Skip to content

Commit 259ac17

Browse files
refactor: move value parser plugin to own file (#800)
1 parent bd0fff1 commit 259ac17

File tree

2 files changed

+142
-135
lines changed

2 files changed

+142
-135
lines changed

lib/postcss-css-loader-parser.js

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
const postcss = require('postcss');
2+
const valueParser = require('postcss-value-parser');
3+
const icssUtils = require('icss-utils');
4+
const Tokenizer = require('css-selector-tokenizer');
5+
const loaderUtils = require('loader-utils');
6+
7+
module.exports = postcss.plugin(
8+
'postcss-css-loader-parser',
9+
(options) => (css) => {
10+
const imports = {};
11+
let exports = {};
12+
const importItems = [];
13+
const urlItems = [];
14+
15+
function replaceImportsInString(str) {
16+
if (options.import) {
17+
const tokens = valueParser(str);
18+
tokens.walk((node) => {
19+
if (node.type !== 'word') {
20+
return;
21+
}
22+
const token = node.value;
23+
const importIndex = imports[`$${token}`];
24+
if (typeof importIndex === 'number') {
25+
// eslint-disable-next-line no-param-reassign
26+
node.value = `___CSS_LOADER_IMPORT___${importIndex}___`;
27+
}
28+
});
29+
return tokens.toString();
30+
}
31+
return str;
32+
}
33+
34+
if (options.import) {
35+
css.walkAtRules(/^import$/i, (rule) => {
36+
const values = Tokenizer.parseValues(rule.params);
37+
let [url] = values.nodes[0].nodes;
38+
if (url && url.type === 'url') {
39+
({ url } = url);
40+
} else if (url && url.type === 'string') {
41+
url = url.value;
42+
} else throw rule.error(`Unexpected format ${rule.params}`);
43+
if (!url.replace(/\s/g, '').length) {
44+
return;
45+
}
46+
values.nodes[0].nodes.shift();
47+
const mediaQuery = Tokenizer.stringifyValues(values);
48+
49+
if (loaderUtils.isUrlRequest(url)) {
50+
url = loaderUtils.urlToRequest(url);
51+
}
52+
53+
importItems.push({
54+
url,
55+
mediaQuery,
56+
});
57+
rule.remove();
58+
});
59+
}
60+
61+
const icss = icssUtils.extractICSS(css);
62+
exports = icss.icssExports;
63+
Object.keys(icss.icssImports).forEach((key) => {
64+
const url = loaderUtils.parseString(key);
65+
Object.keys(icss.icssImports[key]).forEach((prop) => {
66+
imports[`$${prop}`] = importItems.length;
67+
importItems.push({
68+
url,
69+
export: icss.icssImports[key][prop],
70+
});
71+
});
72+
});
73+
74+
Object.keys(exports).forEach((exportName) => {
75+
exports[exportName] = replaceImportsInString(exports[exportName]);
76+
});
77+
78+
function processNode(item) {
79+
switch (item.type) {
80+
case 'value':
81+
item.nodes.forEach(processNode);
82+
break;
83+
case 'nested-item':
84+
item.nodes.forEach(processNode);
85+
break;
86+
case 'item': {
87+
const importIndex = imports[`$${item.name}`];
88+
if (typeof importIndex === 'number') {
89+
// eslint-disable-next-line no-param-reassign
90+
item.name = `___CSS_LOADER_IMPORT___${importIndex}___`;
91+
}
92+
break;
93+
}
94+
case 'url':
95+
if (
96+
options.url &&
97+
item.url.replace(/\s/g, '').length &&
98+
!/^#/.test(item.url) &&
99+
loaderUtils.isUrlRequest(item.url)
100+
) {
101+
// Strip quotes, they will be re-added if the module needs them
102+
/* eslint-disable no-param-reassign */
103+
item.stringType = '';
104+
delete item.innerSpacingBefore;
105+
delete item.innerSpacingAfter;
106+
const { url } = item;
107+
item.url = `___CSS_LOADER_URL___${urlItems.length}___`;
108+
/* eslint-enable no-param-reassign */
109+
urlItems.push({
110+
url,
111+
});
112+
}
113+
break;
114+
// no default
115+
}
116+
}
117+
118+
css.walkDecls((decl) => {
119+
const values = Tokenizer.parseValues(decl.value);
120+
values.nodes.forEach((value) => {
121+
value.nodes.forEach(processNode);
122+
});
123+
// eslint-disable-next-line no-param-reassign
124+
decl.value = Tokenizer.stringifyValues(values);
125+
});
126+
css.walkAtRules((atrule) => {
127+
if (typeof atrule.params === 'string') {
128+
// eslint-disable-next-line no-param-reassign
129+
atrule.params = replaceImportsInString(atrule.params);
130+
}
131+
});
132+
133+
/* eslint-disable no-param-reassign */
134+
options.importItems = importItems;
135+
options.urlItems = urlItems;
136+
options.exports = exports;
137+
/* eslint-enable no-param-reassign */
138+
}
139+
);

lib/processCss.js

Lines changed: 3 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -2,151 +2,19 @@
22
MIT License http://www.opensource.org/licenses/mit-license.php
33
Author Tobias Koppers @sokra
44
*/
5-
const Tokenizer = require('css-selector-tokenizer');
65
const postcss = require('postcss');
76
const loaderUtils = require('loader-utils');
87

9-
const icssUtils = require('icss-utils');
108
const localByDefault = require('postcss-modules-local-by-default');
119
const extractImports = require('postcss-modules-extract-imports');
1210
const modulesScope = require('postcss-modules-scope');
1311
const modulesValues = require('postcss-modules-values');
14-
const valueParser = require('postcss-value-parser');
12+
13+
const cssLoaderParser = require('./postcss-css-loader-parser');
1514

1615
const CssSyntaxError = require('./CssSyntaxError');
1716
const getLocalIdent = require('./getLocalIdent');
1817

19-
const parserPlugin = postcss.plugin('css-loader-parser', (options) => (css) => {
20-
const imports = {};
21-
let exports = {};
22-
const importItems = [];
23-
const urlItems = [];
24-
25-
function replaceImportsInString(str) {
26-
if (options.import) {
27-
const tokens = valueParser(str);
28-
tokens.walk((node) => {
29-
if (node.type !== 'word') {
30-
return;
31-
}
32-
const token = node.value;
33-
const importIndex = imports[`$${token}`];
34-
if (typeof importIndex === 'number') {
35-
// eslint-disable-next-line no-param-reassign
36-
node.value = `___CSS_LOADER_IMPORT___${importIndex}___`;
37-
}
38-
});
39-
return tokens.toString();
40-
}
41-
return str;
42-
}
43-
44-
if (options.import) {
45-
css.walkAtRules(/^import$/i, (rule) => {
46-
const values = Tokenizer.parseValues(rule.params);
47-
let [url] = values.nodes[0].nodes;
48-
if (url && url.type === 'url') {
49-
({ url } = url);
50-
} else if (url && url.type === 'string') {
51-
url = url.value;
52-
} else throw rule.error(`Unexpected format ${rule.params}`);
53-
if (!url.replace(/\s/g, '').length) {
54-
return;
55-
}
56-
values.nodes[0].nodes.shift();
57-
const mediaQuery = Tokenizer.stringifyValues(values);
58-
59-
if (loaderUtils.isUrlRequest(url)) {
60-
url = loaderUtils.urlToRequest(url);
61-
}
62-
63-
importItems.push({
64-
url,
65-
mediaQuery,
66-
});
67-
rule.remove();
68-
});
69-
}
70-
71-
const icss = icssUtils.extractICSS(css);
72-
exports = icss.icssExports;
73-
Object.keys(icss.icssImports).forEach((key) => {
74-
const url = loaderUtils.parseString(key);
75-
Object.keys(icss.icssImports[key]).forEach((prop) => {
76-
imports[`$${prop}`] = importItems.length;
77-
importItems.push({
78-
url,
79-
export: icss.icssImports[key][prop],
80-
});
81-
});
82-
});
83-
84-
Object.keys(exports).forEach((exportName) => {
85-
exports[exportName] = replaceImportsInString(exports[exportName]);
86-
});
87-
88-
function processNode(item) {
89-
switch (item.type) {
90-
case 'value':
91-
item.nodes.forEach(processNode);
92-
break;
93-
case 'nested-item':
94-
item.nodes.forEach(processNode);
95-
break;
96-
case 'item': {
97-
const importIndex = imports[`$${item.name}`];
98-
if (typeof importIndex === 'number') {
99-
// eslint-disable-next-line no-param-reassign
100-
item.name = `___CSS_LOADER_IMPORT___${importIndex}___`;
101-
}
102-
break;
103-
}
104-
case 'url':
105-
if (
106-
options.url &&
107-
item.url.replace(/\s/g, '').length &&
108-
!/^#/.test(item.url) &&
109-
loaderUtils.isUrlRequest(item.url)
110-
) {
111-
// Strip quotes, they will be re-added if the module needs them
112-
/* eslint-disable no-param-reassign */
113-
item.stringType = '';
114-
delete item.innerSpacingBefore;
115-
delete item.innerSpacingAfter;
116-
const { url } = item;
117-
item.url = `___CSS_LOADER_URL___${urlItems.length}___`;
118-
/* eslint-enable no-param-reassign */
119-
urlItems.push({
120-
url,
121-
});
122-
}
123-
break;
124-
// no default
125-
}
126-
}
127-
128-
css.walkDecls((decl) => {
129-
const values = Tokenizer.parseValues(decl.value);
130-
values.nodes.forEach((value) => {
131-
value.nodes.forEach(processNode);
132-
});
133-
// eslint-disable-next-line no-param-reassign
134-
decl.value = Tokenizer.stringifyValues(values);
135-
});
136-
css.walkAtRules((atrule) => {
137-
if (typeof atrule.params === 'string') {
138-
// eslint-disable-next-line no-param-reassign
139-
atrule.params = replaceImportsInString(atrule.params);
140-
}
141-
});
142-
143-
/* eslint-disable no-param-reassign */
144-
options.importItems = importItems;
145-
options.urlItems = urlItems;
146-
options.exports = exports;
147-
/* eslint-enable no-param-reassign */
148-
});
149-
15018
module.exports = function processCss(inputSource, inputMap, options, callback) {
15119
const { query } = options;
15220
const { context, localIdentRegExp } = query;
@@ -197,7 +65,7 @@ module.exports = function processCss(inputSource, inputMap, options, callback) {
19765
);
19866
},
19967
}),
200-
parserPlugin(parserOptions),
68+
cssLoaderParser(parserOptions),
20169
]);
20270

20371
pipeline

0 commit comments

Comments
 (0)