Skip to content

Commit c454228

Browse files
committed
small update
1 parent 847bc76 commit c454228

File tree

4 files changed

+119
-15
lines changed

4 files changed

+119
-15
lines changed

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
dist
22
coverage
33
node_modules
4+
5+
generate-tests.js
46
test/common-test-cases.js

src/fn.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* @param {*} a
3+
* @return {*}
4+
*/
5+
export function identity(a) {
6+
return a;
7+
}
8+
9+
/**
10+
* @param {string} str
11+
* @return {string}
12+
*/
13+
export function removeQuotes(str) {
14+
return str.replace(/^["']|["']$/g, '');
15+
}

src/index.js

Lines changed: 101 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,125 @@
11
import hook from './hook';
22
import { readFileSync } from 'fs';
33
import { dirname, sep, relative, resolve } from 'path';
4+
import { identity, removeQuotes } from './fn';
45
import postcss from 'postcss';
56

67
import ExtractImports from 'postcss-modules-extract-imports';
78
import LocalByDefault from 'postcss-modules-local-by-default';
89
import Scope from 'postcss-modules-scope';
910
import Parser from './parser';
1011

12+
// cache
1113
let importNr = 0;
12-
let plugins = [ExtractImports, LocalByDefault, Scope];
14+
let tokensByFile = {};
15+
// processing functions
16+
const preProcess = identity;
17+
let postProcess;
18+
// defaults
19+
let plugins = [LocalByDefault, ExtractImports, Scope];
1320
let rootDir = process.cwd();
1421

15-
export default function (opts = {}) {
16-
plugins = opts.use ? opts.use : [ExtractImports, LocalByDefault, Scope];
17-
rootDir = opts.rootDir ? opts.rootDir : process.cwd();
22+
/**
23+
* @param {object} opts
24+
* @param {function} opts.createImportedName
25+
* @param {function} opts.generateScopedName
26+
* @param {function} opts.processCss
27+
* @param {string} opts.rootDir
28+
* @param {array} opts.use
29+
*/
30+
export default function setup(opts = {}) {
31+
// clearing cache
32+
importNr = 0;
33+
tokensByFile = {};
34+
35+
if (opts.processCss && typeof opts.processCss !== 'function') {
36+
throw new Error('should specify function for processCss');
37+
}
38+
39+
postProcess = opts.processCss || null;
40+
41+
if (opts.rootDir && typeof opts.rootDir !== 'string') {
42+
throw new Error('should specify string for rootDir');
43+
}
44+
45+
rootDir = opts.rootDir || process.cwd();
46+
47+
if (opts.use) {
48+
if (!Array.isArray(opts.use)) {
49+
throw new Error('should specify array for use');
50+
}
51+
52+
return void (plugins = opts.use);
53+
}
54+
55+
plugins = [];
56+
57+
if (opts.mode) {
58+
if (typeof opts.mode !== 'string') {
59+
throw new Error('should specify string for mode');
60+
}
61+
62+
plugins.push(new LocalByDefault({mode: opts.mode}));
63+
} else {
64+
plugins.push(LocalByDefault);
65+
}
66+
67+
if (opts.createImportedName) {
68+
if (typeof opts.createImportedName !== 'function') {
69+
throw new Error('should specify function for createImportedName');
70+
}
71+
72+
plugins.push(new ExtractImports({createImportedName: opts.createImportedName}));
73+
} else {
74+
plugins.push(ExtractImports);
75+
}
76+
77+
if (opts.generateScopedName) {
78+
if (typeof opts.generateScopedName !== 'function') {
79+
throw new Error('should specify function for generateScopedName');
80+
}
81+
82+
plugins.push(new Scope({generateScopedName: opts.generateScopedName}));
83+
} else {
84+
plugins.push(Scope);
85+
}
1886
}
1987

20-
function pathFetcher(_newPath, sourcePath, _trace) {
88+
/**
89+
* @param {string} _newPath Absolute or relative path. Also can be path to the Node.JS module.
90+
* @param {string} _sourcePath Absolute path (relative to root).
91+
* @param {string} _trace
92+
* @return {object}
93+
*/
94+
function fetch(_newPath, _sourcePath, _trace) {
2195
const trace = _trace || String.fromCharCode(importNr++);
22-
const newPath = _newPath.replace(/^["']|["']$/g, '');
96+
const newPath = removeQuotes(_newPath);
97+
// getting absolute path to the processing file
2398
const filename = /\w/.test(newPath[0])
2499
? require.resolve(newPath)
25-
: resolve(rootDir + dirname(sourcePath), newPath);
100+
: resolve(rootDir + dirname(_sourcePath), newPath);
101+
102+
// checking cache
103+
let tokens = tokensByFile[filename];
104+
if (tokens) {
105+
return tokens;
106+
}
107+
26108
const rootRelativePath = sep + relative(rootDir, filename);
27-
const source = readFileSync(filename, 'utf8');
109+
const CSSSource = preProcess(readFileSync(filename, 'utf8'));
28110

29-
const result = postcss(plugins.concat(new Parser({ pathFetcher, trace })))
30-
// preprocess
31-
.process(source, {from: rootRelativePath})
111+
const result = postcss(plugins.concat(new Parser({ fetch, trace })))
112+
.process(CSSSource, {from: rootRelativePath})
32113
.root;
33-
// postprocess
34114

35-
return result.tokens;
115+
tokens = result.tokens;
116+
tokensByFile[filename] = tokens;
117+
118+
if (postProcess) {
119+
postProcess(result.toResult().css);
120+
}
121+
122+
return tokens;
36123
}
37124

38-
hook(filename => pathFetcher(filename, sep + relative(rootDir, filename)));
125+
hook(filename => fetch(filename, sep + relative(rootDir, filename)));

src/parser.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ export default plugin('parser', function parser(opts = {}) {
99
const fetchImport = (importNode, relativeTo, depNr) => {
1010
const file = importNode.selector.match(importRegexp)[1];
1111
const depTrace = opts.trace + String.fromCharCode(depNr);
12-
const exports = opts.pathFetcher(file, relativeTo, depTrace);
12+
const exports = opts.fetch(file, relativeTo, depTrace);
1313

1414
importNode.each(decl => {
1515
if (decl.type === 'decl') {

0 commit comments

Comments
 (0)