Skip to content

Commit c0bed7b

Browse files
author
Alexey Litvinov
committed
not what I expected
1 parent 05a834d commit c0bed7b

File tree

4 files changed

+139
-18
lines changed

4 files changed

+139
-18
lines changed

index.js

Lines changed: 114 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,130 @@
1+
const dirname = require('path').dirname;
2+
const forEach = require('lodash');
13
const plugin = require('postcss').plugin;
4+
const postcss = require('postcss');
5+
const readFile = require('fs').readFile;
6+
const readFileSync = require('fs').readFileSync;
7+
const resolve = require('path').resolve;
28

39
const importRegexp = /^:import\((.+)\)$/;
10+
const nameOfTheCurrentPlugin = 'postcss-modules-resolve-imports';
411

512
/**
613
* @param {object} [opts]
714
* @param {boolean} opts.sync
815
* @return {function}
916
*/
10-
module.exports = plugin('postcss-modules-resolve-imports', function postcssModulesResolveImports(opts) {
11-
return function resolveImports(css, result) {
17+
module.exports = plugin(nameOfTheCurrentPlugin, function postcssModulesResolveImports(opts) {
18+
return function resolveImports(tree, result) {
1219
// https://github.com/postcss/postcss/blob/master/docs/api.md#inputfile
13-
const filepath = css.source.input.file;
14-
const plugins = result.processor.plugins;
20+
// const filepath = tree.source.input.file;
21+
const plugins = getPluginsForParse(result.processor.plugins);
22+
const runner = postcss(plugins);
1523

16-
css.walkRules(importRegexp, rule => {
17-
const dependency = RegExp.$1.replace(/^["']|["']$/g, '');
24+
const cache = {};
25+
const queue = [];
26+
const traces = {};
1827

19-
// Шаги -> Резолвим путь -> Загружаем содержимое -> Прогоняем через postcss -> Достаем Root
20-
// -> Резолвим зависимости -> Вставляем ноды в исходное дерево (желательно использовать tracesort)
21-
// Получается, нужен кэш с файлами и конечный резолвер на случай, когда файлы загружены.
22-
//
23-
// По сути можно хранить список файлов и их контент + отдельно помечать глубину загрузки
28+
traverseImports(tree, dependency =>
29+
loadDependency(dependency, {cache, queue, runner}));
2430

25-
// path RegExp.$1
26-
});
31+
return Promise.all(queue)
32+
.then(_ => combineTrees(tree, cache));
2733

28-
return css;
34+
// -> traceKeySorter
2935
};
3036
});
37+
38+
/**
39+
* @param {array} plugins
40+
* @return {array}
41+
*/
42+
function getPluginsForParse(plugins) {
43+
const pluginsForParse = plugins.slice();
44+
let ln = pluginsForParse.length;
45+
46+
while (pluginsForParse[--ln].postcssPlugin !== nameOfTheCurrentPlugin) {
47+
pluginsForParse.pop();
48+
}
49+
50+
return pluginsForParse;
51+
}
52+
53+
/**
54+
* @param {root} tree
55+
* @param {function} iterator
56+
*/
57+
function traverseImports(tree, iterator) {
58+
// https://github.com/postcss/postcss/blob/master/docs/api.md#inputfile
59+
const source = tree.source.input.file;
60+
// https://github.com/postcss/postcss/blob/master/docs/api.md#containerwalkrulesselectorfilter-callback
61+
tree.walkRules(importRegexp, rule => {
62+
iterator(getDepsPath(RegExp.$1, source), source);
63+
tree.removeChild(rule);
64+
});
65+
}
66+
67+
/**
68+
* @param {string} to
69+
* @param {string} from
70+
* @return {string}
71+
*/
72+
function getDepsPath(to, from) {
73+
// @todo support non-relative imports
74+
// const filepath = /\w/i.test(to[0])
75+
// ? require.resolve(to)
76+
// : resolve(dirname(from), to);
77+
return resolve(dirname(from), to.replace(/^["']|["']$/g, ''));
78+
}
79+
80+
/**
81+
* @param {string} dependency
82+
* @param {object} options.cache
83+
* @param {array} options.queue
84+
*/
85+
function loadDependency(dependency, {cache, queue, runner}) {
86+
const pending = new Promise((resolve, reject) =>
87+
readFile(dependency, 'utf8', (er, source) => {
88+
if (er) {
89+
return void reject(er);
90+
}
91+
92+
runner
93+
.process(source, {from: dependency})
94+
.then(result => {
95+
cache[dependency] = result.root;
96+
97+
traverseImports(result.root, deps =>
98+
loadDependency(deps, {cache, queue, runner}));
99+
100+
resolve(result.root);
101+
})
102+
.catch(reject);
103+
}));
104+
105+
queue.push(pending);
106+
return pending;
107+
}
108+
109+
function combineTrees(root, cache) {
110+
forEach(cache, tree => root.prepend.apply(root, tree.nodes));
111+
console.log('test', root)
112+
return root;
113+
}
114+
115+
// Sorts dependencies in the following way:
116+
// AAA comes before AA and A
117+
// AB comes after AA and before A
118+
// All Bs come after all As
119+
// This ensures that the files are always returned in the following order:
120+
// - In the order they were required, except
121+
// - After all their dependencies
122+
function traceKeySorter(a, b) {
123+
if (a.length < b.length) {
124+
return a < b.substring(0, a.length) ? -1 : 1;
125+
} else if (a.length > b.length) {
126+
return a.substring(0, b.length) <= b ? -1 : 1;
127+
} else {
128+
return a < b ? -1 : 1;
129+
}
130+
};

package.json

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
"description": "Resolves ICSS imports",
55
"main": "index.js",
66
"scripts": {
7-
"test": "npm run test:unit",
8-
"test:unit": "mocha --require test/setup.js --ui tdd test/index.js"
7+
"test": "npm run test:node",
8+
"test:node": "$npm_package_scripts_test_unit --use_strict",
9+
"test:unit": "mocha --require test/setup.js --ui tdd test/index.js --harmony_destructuring"
910
},
1011
"repository": {
1112
"type": "git",
@@ -21,6 +22,7 @@
2122
},
2223
"homepage": "https://github.com/sullenor/postcss-modules-resolve-imports#readme",
2324
"dependencies": {
25+
"lodash": "^4.6.1",
2426
"postcss": "^5.0.17"
2527
},
2628
"devDependencies": {

removeExports.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
const plugin = require('postcss').plugin;
2+
3+
const exportRegexp = /^:export$/;
4+
5+
module.exports = plugin('remove-exports', function removeExports() {
6+
return css => {
7+
css.walkRules(exportRegexp, rule => css.removeChild(rule));
8+
return css;
9+
};
10+
});

test/index.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,23 @@ const LocalByDefault = require('postcss-modules-local-by-default');
44
const ExtractImports = require('postcss-modules-extract-imports');
55
const Scope = require('postcss-modules-scope');
66
const ResolveImports = require('../index.js');
7+
const RemoveExports = require('../removeExports');
78

89
const readFileSync = require('fs').readFileSync;
910
const resolve = require('path').resolve;
1011

1112
const css = readFileSync(resolve('test/source.css'), 'utf8');
1213

13-
const result = postcss([LocalByDefault, ExtractImports, Scope, ResolveImports])
14+
const result = postcss([
15+
LocalByDefault,
16+
ExtractImports,
17+
Scope,
18+
ResolveImports,
19+
RemoveExports,
20+
])
1421
.process(css, {from: resolve('test/source.css')})
15-
.css;
22+
.then(result => {
23+
// console.log(result.root);
24+
});
1625

1726
console.log(result);

0 commit comments

Comments
 (0)