UNPKG

9 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7var _postcssValueParser = _interopRequireDefault(require("postcss-value-parser"));
8var _utils = require("../utils");
9function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
10function parseNode(atRule, key, options) {
11 // Convert only top-level @import
12 if (atRule.parent.type !== "root") {
13 return;
14 }
15 if (atRule.raws && atRule.raws.afterName && atRule.raws.afterName.trim().length > 0) {
16 const lastCommentIndex = atRule.raws.afterName.lastIndexOf("/*");
17 const matched = atRule.raws.afterName.slice(lastCommentIndex).match(_utils.WEBPACK_IGNORE_COMMENT_REGEXP);
18 if (matched && matched[2] === "true") {
19 return;
20 }
21 }
22 const prevNode = atRule.prev();
23 if (prevNode && prevNode.type === "comment") {
24 const matched = prevNode.text.match(_utils.WEBPACK_IGNORE_COMMENT_REGEXP);
25 if (matched && matched[2] === "true") {
26 return;
27 }
28 }
29
30 // Nodes do not exists - `@import url('http://') :root {}`
31 if (atRule.nodes) {
32 const error = new Error("It looks like you didn't end your @import statement correctly. Child nodes are attached to it.");
33 error.node = atRule;
34 throw error;
35 }
36 const rawParams = atRule.raws && atRule.raws[key] && typeof atRule.raws[key].raw !== "undefined" ? atRule.raws[key].raw : atRule[key];
37 const {
38 nodes: paramsNodes
39 } = (0, _postcssValueParser.default)(rawParams);
40
41 // No nodes - `@import ;`
42 // Invalid type - `@import foo-bar;`
43 if (paramsNodes.length === 0 || paramsNodes[0].type !== "string" && paramsNodes[0].type !== "function") {
44 const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
45 error.node = atRule;
46 throw error;
47 }
48 let isStringValue;
49 let url;
50 if (paramsNodes[0].type === "string") {
51 isStringValue = true;
52 url = paramsNodes[0].value;
53 } else {
54 // Invalid function - `@import nourl(test.css);`
55 if (paramsNodes[0].value.toLowerCase() !== "url") {
56 const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
57 error.node = atRule;
58 throw error;
59 }
60 isStringValue = paramsNodes[0].nodes.length !== 0 && paramsNodes[0].nodes[0].type === "string";
61 url = isStringValue ? paramsNodes[0].nodes[0].value : _postcssValueParser.default.stringify(paramsNodes[0].nodes);
62 }
63 url = (0, _utils.normalizeUrl)(url, isStringValue);
64 const {
65 requestable,
66 needResolve
67 } = (0, _utils.isURLRequestable)(url, options);
68 let prefix;
69 if (requestable && needResolve) {
70 const queryParts = url.split("!");
71 if (queryParts.length > 1) {
72 url = queryParts.pop();
73 prefix = queryParts.join("!");
74 }
75 }
76
77 // Empty url - `@import "";` or `@import url();`
78 if (url.trim().length === 0) {
79 const error = new Error(`Unable to find uri in "${atRule.toString()}"`);
80 error.node = atRule;
81 throw error;
82 }
83 const additionalNodes = paramsNodes.slice(1);
84 let supports;
85 let layer;
86 let media;
87 if (additionalNodes.length > 0) {
88 let nodes = [];
89 for (const node of additionalNodes) {
90 nodes.push(node);
91 const isLayerFunction = node.type === "function" && node.value.toLowerCase() === "layer";
92 const isLayerWord = node.type === "word" && node.value.toLowerCase() === "layer";
93 if (isLayerFunction || isLayerWord) {
94 if (isLayerFunction) {
95 nodes.splice(nodes.length - 1, 1, ...node.nodes);
96 } else {
97 nodes.splice(nodes.length - 1, 1, {
98 type: "string",
99 value: "",
100 unclosed: false
101 });
102 }
103 layer = _postcssValueParser.default.stringify(nodes).trim().toLowerCase();
104 nodes = [];
105 } else if (node.type === "function" && node.value.toLowerCase() === "supports") {
106 nodes.splice(nodes.length - 1, 1, ...node.nodes);
107 supports = _postcssValueParser.default.stringify(nodes).trim().toLowerCase();
108 nodes = [];
109 }
110 }
111 if (nodes.length > 0) {
112 media = _postcssValueParser.default.stringify(nodes).trim().toLowerCase();
113 }
114 }
115
116 // eslint-disable-next-line consistent-return
117 return {
118 atRule,
119 prefix,
120 url,
121 layer,
122 supports,
123 media,
124 requestable,
125 needResolve
126 };
127}
128const plugin = (options = {}) => {
129 return {
130 postcssPlugin: "postcss-import-parser",
131 prepare(result) {
132 const parsedAtRules = [];
133 return {
134 AtRule: {
135 import(atRule) {
136 if (options.isCSSStyleSheet) {
137 options.loaderContext.emitError(new Error(atRule.error("'@import' rules are not allowed here and will not be processed").message));
138 return;
139 }
140 const {
141 isSupportDataURL,
142 isSupportAbsoluteURL
143 } = options;
144 let parsedAtRule;
145 try {
146 parsedAtRule = parseNode(atRule, "params", {
147 isSupportAbsoluteURL,
148 isSupportDataURL
149 });
150 } catch (error) {
151 result.warn(error.message, {
152 node: error.node
153 });
154 }
155 if (!parsedAtRule) {
156 return;
157 }
158 parsedAtRules.push(parsedAtRule);
159 }
160 },
161 async OnceExit() {
162 if (parsedAtRules.length === 0) {
163 return;
164 }
165 const {
166 loaderContext
167 } = options;
168 const resolver = loaderContext.getResolve({
169 dependencyType: "css",
170 conditionNames: ["style"],
171 mainFields: ["css", "style", "main", "..."],
172 mainFiles: ["index", "..."],
173 extensions: [".css", "..."],
174 preferRelative: true
175 });
176 const resolvedAtRules = await Promise.all(parsedAtRules.map(async parsedAtRule => {
177 const {
178 atRule,
179 requestable,
180 needResolve,
181 prefix,
182 url,
183 layer,
184 supports,
185 media
186 } = parsedAtRule;
187 if (options.filter) {
188 const needKeep = await options.filter(url, media, loaderContext.resourcePath, supports, layer);
189 if (!needKeep) {
190 return;
191 }
192 }
193 if (needResolve) {
194 const request = (0, _utils.requestify)(url, loaderContext.rootContext);
195 const resolvedUrl = await (0, _utils.resolveRequests)(resolver, loaderContext.context, [...new Set([request, url])]);
196 if (!resolvedUrl) {
197 return;
198 }
199 if (resolvedUrl === loaderContext.resourcePath) {
200 atRule.remove();
201 return;
202 }
203 atRule.remove();
204
205 // eslint-disable-next-line consistent-return
206 return {
207 url: resolvedUrl,
208 layer,
209 supports,
210 media,
211 prefix,
212 requestable
213 };
214 }
215 atRule.remove();
216
217 // eslint-disable-next-line consistent-return
218 return {
219 url,
220 layer,
221 supports,
222 media,
223 prefix,
224 requestable
225 };
226 }));
227 const urlToNameMap = new Map();
228 for (let index = 0; index <= resolvedAtRules.length - 1; index++) {
229 const resolvedAtRule = resolvedAtRules[index];
230 if (!resolvedAtRule) {
231 // eslint-disable-next-line no-continue
232 continue;
233 }
234 const {
235 url,
236 requestable,
237 layer,
238 supports,
239 media
240 } = resolvedAtRule;
241 if (!requestable) {
242 options.api.push({
243 url,
244 layer,
245 supports,
246 media,
247 index
248 });
249
250 // eslint-disable-next-line no-continue
251 continue;
252 }
253 const {
254 prefix
255 } = resolvedAtRule;
256 const newUrl = prefix ? `${prefix}!${url}` : url;
257 let importName = urlToNameMap.get(newUrl);
258 if (!importName) {
259 importName = `___CSS_LOADER_AT_RULE_IMPORT_${urlToNameMap.size}___`;
260 urlToNameMap.set(newUrl, importName);
261 options.imports.push({
262 type: "rule_import",
263 importName,
264 url: options.urlHandler(newUrl),
265 index
266 });
267 }
268 options.api.push({
269 importName,
270 layer,
271 supports,
272 media,
273 index
274 });
275 }
276 }
277 };
278 }
279 };
280};
281plugin.postcss = true;
282var _default = plugin;
283exports.default = _default;
\No newline at end of file