1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | 1 1 1 1 1 1 1 1 10 10 10 10 10 10 10 3 7 7 7 7 7 7 7 1 22 22 22 22 22 1 21 21 21 21 21 21 21 21 1 | import hook from './hook'; import { readFileSync } from 'fs'; import { dirname, sep, relative, resolve } from 'path'; import { get, removeQuotes } from './utility'; import assign from 'lodash.assign'; import identity from 'lodash.identity'; import pick from 'lodash.pick'; import postcss from 'postcss'; import ExtractImports from 'postcss-modules-extract-imports'; import LocalByDefault from 'postcss-modules-local-by-default'; import Scope from 'postcss-modules-scope'; import Parser from './parser'; // cache let importNr = 0; let tokensByFile = {}; // processing functions const preProcess = identity; let postProcess; // defaults let lazyResultOpts = {}; let plugins = [LocalByDefault, ExtractImports, Scope]; let rootDir = process.cwd(); /** * @param {object} opts * @param {function} opts.createImportedName * @param {function} opts.generateScopedName * @param {function} opts.processCss * @param {string} opts.rootDir * @param {string} opts.to * @param {array} opts.use */ export default function setup(opts = {}) { // clearing cache importNr = 0; tokensByFile = {}; postProcess = get('processCss', null, 'function', opts) || null; rootDir = get('rootDir', ['root', 'd'], 'string', opts) || process.cwd(); // https://github.com/postcss/postcss/blob/master/docs/api.md#processorprocesscss-opts lazyResultOpts = pick(opts, ['to']); const customPlugins = get('use', ['u'], 'array', opts); if (customPlugins) { return void (plugins = customPlugins); } plugins = []; const mode = get('mode', null, 'string', opts); plugins.push(mode ? new LocalByDefault({mode: opts.mode}) : LocalByDefault); const createImportedName = get('createImportedName', null, 'function', opts); plugins.push(createImportedName ? new ExtractImports({createImportedName: opts.createImportedName}) : ExtractImports); const generateScopedName = get('generateScopedName', null, 'function', opts); plugins.push(generateScopedName ? new Scope({generateScopedName: opts.generateScopedName}) : Scope); } /** * @param {string} _to Absolute or relative path. Also can be path to the Node.JS module. * @param {string} _from Absolute path (relative to root). * @param {string} _trace * @return {object} */ function fetch(_to, _from, _trace) { const trace = _trace || String.fromCharCode(importNr++); const newPath = removeQuotes(_to); // getting absolute path to the processing file const filename = /\w/.test(newPath[0]) ? require.resolve(newPath) : resolve(dirname(_from), newPath); // checking cache let tokens = tokensByFile[filename]; if (tokens) { return tokens; } const rootRelativePath = sep + relative(rootDir, filename); const CSSSource = preProcess(readFileSync(filename, 'utf8')); const lazyResult = postcss(plugins.concat(new Parser({ fetch, filename, trace }))) .process(CSSSource, assign(lazyResultOpts, {from: rootRelativePath})); lazyResult.warnings().forEach(message => console.warn(message.text)); tokens = lazyResult.root.tokens; // updating cache tokensByFile[filename] = tokens; Iif (postProcess) { postProcess(lazyResult.css); } return tokens; } hook(filename => fetch(filename, filename)); |