css-loader 3.4.1 → 3.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -17,112 +17,120 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
17
17
 
18
18
  const pluginName = 'postcss-import-parser';
19
19
 
20
- function getParsedValue(node) {
21
- if (node.type === 'function' && node.value.toLowerCase() === 'url') {
22
- const {
23
- nodes
24
- } = node;
25
- const isStringValue = nodes.length !== 0 && nodes[0].type === 'string';
26
- const url = isStringValue ? nodes[0].value : _postcssValueParser.default.stringify(nodes);
27
- return {
28
- url,
29
- isStringValue
30
- };
31
- }
32
-
33
- if (node.type === 'string') {
34
- const url = node.value;
35
- return {
36
- url,
37
- isStringValue: true
38
- };
39
- }
40
-
41
- return null;
42
- }
43
-
44
- function parseImport(params) {
45
- const {
46
- nodes
47
- } = (0, _postcssValueParser.default)(params);
48
-
49
- if (nodes.length === 0) {
50
- return null;
51
- }
52
-
53
- const value = getParsedValue(nodes[0]);
54
-
55
- if (!value) {
56
- return null;
57
- }
58
-
59
- let {
60
- url
61
- } = value;
62
-
63
- if (url.trim().length === 0) {
64
- return null;
65
- }
66
-
67
- if ((0, _loaderUtils.isUrlRequest)(url)) {
68
- const {
69
- isStringValue
70
- } = value;
71
- url = (0, _utils.normalizeUrl)(url, isStringValue);
72
- }
73
-
74
- return {
75
- url,
76
- media: _postcssValueParser.default.stringify(nodes.slice(1)).trim().toLowerCase()
77
- };
78
- }
79
-
80
- function walkAtRules(css, result, filter) {
81
- const items = [];
20
+ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
21
+ const importsMap = new Map();
82
22
  css.walkAtRules(/^import$/i, atRule => {
83
23
  // Convert only top-level @import
84
24
  if (atRule.parent.type !== 'root') {
85
25
  return;
86
- }
26
+ } // Nodes do not exists - `@import url('http://') :root {}`
27
+
87
28
 
88
29
  if (atRule.nodes) {
89
- result.warn("It looks like you didn't end your @import statement correctly. " + 'Child nodes are attached to it.', {
30
+ result.warn("It looks like you didn't end your @import statement correctly. Child nodes are attached to it.", {
90
31
  node: atRule
91
32
  });
92
33
  return;
93
34
  }
94
35
 
95
- const parsed = parseImport(atRule.params);
36
+ const {
37
+ nodes
38
+ } = (0, _postcssValueParser.default)(atRule.params); // No nodes - `@import ;`
39
+ // Invalid type - `@import foo-bar;`
96
40
 
97
- if (!parsed) {
98
- // eslint-disable-next-line consistent-return
99
- return result.warn(`Unable to find uri in '${atRule.toString()}'`, {
41
+ if (nodes.length === 0 || nodes[0].type !== 'string' && nodes[0].type !== 'function') {
42
+ result.warn(`Unable to find uri in "${atRule.toString()}"`, {
100
43
  node: atRule
101
44
  });
45
+ return;
102
46
  }
103
47
 
104
- if (filter && !filter(parsed)) {
48
+ let isStringValue;
49
+ let url;
50
+
51
+ if (nodes[0].type === 'string') {
52
+ isStringValue = true;
53
+ url = nodes[0].value;
54
+ } else if (nodes[0].type === 'function') {
55
+ // Invalid function - `@import nourl(test.css);`
56
+ if (nodes[0].value.toLowerCase() !== 'url') {
57
+ result.warn(`Unable to find uri in "${atRule.toString()}"`, {
58
+ node: atRule
59
+ });
60
+ return;
61
+ }
62
+
63
+ isStringValue = nodes[0].nodes.length !== 0 && nodes[0].nodes[0].type === 'string';
64
+ url = isStringValue ? nodes[0].nodes[0].value : _postcssValueParser.default.stringify(nodes[0].nodes);
65
+ } // Empty url - `@import "";` or `@import url();`
66
+
67
+
68
+ if (url.trim().length === 0) {
69
+ result.warn(`Unable to find uri in "${atRule.toString()}"`, {
70
+ node: atRule
71
+ });
105
72
  return;
106
73
  }
107
74
 
108
- atRule.remove();
109
- items.push(parsed);
110
- });
111
- return items;
112
- }
75
+ const isRequestable = (0, _loaderUtils.isUrlRequest)(url);
113
76
 
114
- var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
115
- const items = walkAtRules(css, result, options.filter);
116
- items.forEach(item => {
117
- const {
77
+ if (isRequestable) {
78
+ url = (0, _utils.normalizeUrl)(url, isStringValue); // Empty url after normalize - `@import '\
79
+ // \
80
+ // \
81
+ // ';
82
+
83
+ if (url.trim().length === 0) {
84
+ result.warn(`Unable to find uri in "${atRule.toString()}"`, {
85
+ node: atRule
86
+ });
87
+ return;
88
+ }
89
+ }
90
+
91
+ const media = _postcssValueParser.default.stringify(nodes.slice(1)).trim().toLowerCase();
92
+
93
+ if (options.filter && !options.filter({
118
94
  url,
119
95
  media
120
- } = item;
96
+ })) {
97
+ return;
98
+ }
99
+
100
+ atRule.remove();
101
+
102
+ if (isRequestable) {
103
+ const importKey = url;
104
+ let importName = importsMap.get(importKey);
105
+
106
+ if (!importName) {
107
+ importName = `___CSS_LOADER_AT_RULE_IMPORT_${importsMap.size}___`;
108
+ importsMap.set(importKey, importName);
109
+ result.messages.push({
110
+ type: 'import',
111
+ value: {
112
+ importName,
113
+ url: options.urlHandler ? options.urlHandler(url) : url
114
+ }
115
+ });
116
+ }
117
+
118
+ result.messages.push({
119
+ type: 'api-import',
120
+ value: {
121
+ type: 'internal',
122
+ importName,
123
+ media
124
+ }
125
+ });
126
+ return;
127
+ }
128
+
121
129
  result.messages.push({
122
130
  pluginName,
123
- type: 'import',
131
+ type: 'api-import',
124
132
  value: {
125
- type: '@import',
133
+ type: 'external',
126
134
  url,
127
135
  media
128
136
  }
@@ -41,7 +41,7 @@ function walkUrls(parsed, callback) {
41
41
  }
42
42
 
43
43
  if (isImageSetFunc.test(node.value)) {
44
- node.nodes.forEach(nNode => {
44
+ for (const nNode of node.nodes) {
45
45
  const {
46
46
  type,
47
47
  value
@@ -59,139 +59,93 @@ function walkUrls(parsed, callback) {
59
59
  if (type === 'string') {
60
60
  callback(nNode, value, true, true);
61
61
  }
62
- }); // Do not traverse inside `image-set`
62
+ } // Do not traverse inside `image-set`
63
63
  // eslint-disable-next-line consistent-return
64
64
 
65
+
65
66
  return false;
66
67
  }
67
68
  });
68
69
  }
69
70
 
70
- function getUrlsFromValue(value, result, filter, decl) {
71
- if (!needParseDecl.test(value)) {
72
- return;
73
- }
74
-
75
- const parsed = (0, _postcssValueParser.default)(value);
76
- const urls = [];
77
- walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
78
- if (url.trim().replace(/\\[\r\n]/g, '').length === 0) {
79
- result.warn(`Unable to find uri in '${decl ? decl.toString() : value}'`, {
80
- node: decl
81
- });
82
- return;
83
- }
84
-
85
- if (filter && !filter(url)) {
71
+ var _default = _postcss.default.plugin(pluginName, options => (css, result) => {
72
+ const importsMap = new Map();
73
+ const replacementsMap = new Map();
74
+ let hasHelper = false;
75
+ css.walkDecls(decl => {
76
+ if (!needParseDecl.test(decl.value)) {
86
77
  return;
87
78
  }
88
79
 
89
- const splittedUrl = url.split(/(\?)?#/);
90
- const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
91
- const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
92
- const normalizedUrl = (0, _utils.normalizeUrl)(urlWithoutHash, isStringValue);
93
- urls.push({
94
- node,
95
- url: normalizedUrl,
96
- hash,
97
- needQuotes
98
- });
99
- }); // eslint-disable-next-line consistent-return
100
-
101
- return {
102
- parsed,
103
- urls
104
- };
105
- }
106
-
107
- function walkDecls(css, result, filter) {
108
- const items = [];
109
- css.walkDecls(decl => {
110
- const item = getUrlsFromValue(decl.value, result, filter, decl);
80
+ const parsed = (0, _postcssValueParser.default)(decl.value);
81
+ walkUrls(parsed, (node, url, needQuotes, isStringValue) => {
82
+ // https://www.w3.org/TR/css-syntax-3/#typedef-url-token
83
+ if (url.replace(/^[\s]+|[\s]+$/g, '').length === 0) {
84
+ result.warn(`Unable to find uri in '${decl ? decl.toString() : decl.value}'`, {
85
+ node: decl
86
+ });
87
+ return;
88
+ }
111
89
 
112
- if (!item || item.urls.length === 0) {
113
- return;
114
- }
90
+ if (options.filter && !options.filter(url)) {
91
+ return;
92
+ }
115
93
 
116
- items.push({
117
- decl,
118
- parsed: item.parsed,
119
- urls: item.urls
120
- });
121
- });
122
- return items;
123
- }
94
+ const splittedUrl = url.split(/(\?)?#/);
95
+ const [urlWithoutHash, singleQuery, hashValue] = splittedUrl;
96
+ const hash = singleQuery || hashValue ? `${singleQuery ? '?' : ''}${hashValue ? `#${hashValue}` : ''}` : '';
97
+ const normalizedUrl = (0, _utils.normalizeUrl)(urlWithoutHash, isStringValue);
98
+ const importKey = normalizedUrl;
99
+ let importName = importsMap.get(importKey);
100
+
101
+ if (!importName) {
102
+ importName = `___CSS_LOADER_URL_IMPORT_${importsMap.size}___`;
103
+ importsMap.set(importKey, importName);
104
+
105
+ if (!hasHelper) {
106
+ const urlToHelper = require.resolve('../runtime/getUrl.js');
107
+
108
+ result.messages.push({
109
+ pluginName,
110
+ type: 'import',
111
+ value: {
112
+ importName: '___CSS_LOADER_GET_URL_IMPORT___',
113
+ url: options.urlHandler ? options.urlHandler(urlToHelper) : urlToHelper
114
+ }
115
+ });
116
+ hasHelper = true;
117
+ }
124
118
 
125
- function flatten(array) {
126
- return array.reduce((a, b) => a.concat(b), []);
127
- }
119
+ result.messages.push({
120
+ pluginName,
121
+ type: 'import',
122
+ value: {
123
+ importName,
124
+ url: options.urlHandler ? options.urlHandler(normalizedUrl) : normalizedUrl
125
+ }
126
+ });
127
+ }
128
128
 
129
- function collectUniqueUrlsWithNodes(array) {
130
- return array.reduce((accumulator, currentValue) => {
131
- const {
132
- url,
133
- needQuotes,
134
- hash,
135
- node
136
- } = currentValue;
137
- const found = accumulator.find(item => url === item.url && needQuotes === item.needQuotes && hash === item.hash);
138
-
139
- if (!found) {
140
- accumulator.push({
141
- url,
129
+ const replacementKey = JSON.stringify({
130
+ importKey,
142
131
  hash,
143
- needQuotes,
144
- nodes: [node]
132
+ needQuotes
145
133
  });
146
- } else {
147
- found.nodes.push(node);
148
- }
149
-
150
- return accumulator;
151
- }, []);
152
- }
153
-
154
- var _default = _postcss.default.plugin(pluginName, options => function process(css, result) {
155
- const traversed = walkDecls(css, result, options.filter);
156
- const flattenTraversed = flatten(traversed.map(item => item.urls));
157
- const urlsWithNodes = collectUniqueUrlsWithNodes(flattenTraversed);
158
- const replacers = new Map();
159
- urlsWithNodes.forEach((urlWithNodes, index) => {
160
- const {
161
- url,
162
- hash,
163
- needQuotes,
164
- nodes
165
- } = urlWithNodes;
166
- const replacementName = `___CSS_LOADER_URL_REPLACEMENT_${index}___`;
167
- result.messages.push({
168
- pluginName,
169
- type: 'import',
170
- value: {
171
- type: 'url',
172
- replacementName,
173
- url,
174
- needQuotes,
175
- hash
176
- }
177
- }, {
178
- pluginName,
179
- type: 'replacer',
180
- value: {
181
- type: 'url',
182
- replacementName
183
- }
184
- });
185
- nodes.forEach(node => {
186
- replacers.set(node, replacementName);
187
- });
188
- });
189
- traversed.forEach(item => {
190
- walkUrls(item.parsed, node => {
191
- const replacementName = replacers.get(node);
134
+ let replacementName = replacementsMap.get(replacementKey);
192
135
 
193
136
  if (!replacementName) {
194
- return;
137
+ replacementName = `___CSS_LOADER_URL_REPLACEMENT_${replacementsMap.size}___`;
138
+ replacementsMap.set(replacementKey, replacementName);
139
+ result.messages.push({
140
+ pluginName,
141
+ type: 'url-replacement',
142
+ value: {
143
+ replacementName,
144
+ importName,
145
+ hash,
146
+ needQuotes
147
+ }
148
+ });
195
149
  } // eslint-disable-next-line no-param-reassign
196
150
 
197
151
 
@@ -200,7 +154,7 @@ var _default = _postcss.default.plugin(pluginName, options => function process(c
200
154
  node.value = replacementName;
201
155
  }); // eslint-disable-next-line no-param-reassign
202
156
 
203
- item.decl.value = item.parsed.toString();
157
+ decl.value = parsed.toString();
204
158
  });
205
159
  });
206
160
 
@@ -23,14 +23,32 @@ module.exports = function (useSourceMap) {
23
23
  // eslint-disable-next-line func-names
24
24
 
25
25
 
26
- list.i = function (modules, mediaQuery) {
26
+ list.i = function (modules, mediaQuery, dedupe) {
27
27
  if (typeof modules === 'string') {
28
28
  // eslint-disable-next-line no-param-reassign
29
29
  modules = [[null, modules, '']];
30
30
  }
31
31
 
32
- for (var i = 0; i < modules.length; i++) {
33
- var item = [].concat(modules[i]);
32
+ var alreadyImportedModules = {};
33
+
34
+ if (dedupe) {
35
+ for (var i = 0; i < this.length; i++) {
36
+ // eslint-disable-next-line prefer-destructuring
37
+ var id = this[i][0];
38
+
39
+ if (id != null) {
40
+ alreadyImportedModules[id] = true;
41
+ }
42
+ }
43
+ }
44
+
45
+ for (var _i = 0; _i < modules.length; _i++) {
46
+ var item = [].concat(modules[_i]);
47
+
48
+ if (dedupe && alreadyImportedModules[item[0]]) {
49
+ // eslint-disable-next-line no-continue
50
+ continue;
51
+ }
34
52
 
35
53
  if (mediaQuery) {
36
54
  if (!item[2]) {