source: frontend/node_modules/webpack/lib/dependencies/ContextDependencyHelpers.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 11 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 8.2 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const { parseResource } = require("../util/identifier");
9
10/** @typedef {import("estree").Expression} Expression */
11/** @typedef {import("../../declarations/WebpackOptions").JavascriptParserOptions} JavascriptParserOptions */
12/** @typedef {import("../Dependency").DependencyLocation} DependencyLocation */
13/** @typedef {import("../javascript/BasicEvaluatedExpression")} BasicEvaluatedExpression */
14/** @typedef {import("../javascript/JavascriptParser")} JavascriptParser */
15/** @typedef {import("../javascript/JavascriptParser").Range} Range */
16/** @typedef {import("./ContextDependency")} ContextDependency */
17/** @typedef {import("./ContextDependency").ContextDependencyOptions} ContextDependencyOptions */
18/** @typedef {import("./ContextDependency").Replaces} Replaces */
19
20/**
21 * Escapes regular expression metacharacters
22 * @param {string} str String to quote
23 * @returns {string} Escaped string
24 */
25const quoteMeta = (str) => str.replace(/[-[\]\\/{}()*+?.^$|]/g, "\\$&");
26
27/**
28 * Split context from prefix.
29 * @param {string} prefix prefix
30 * @returns {{ prefix: string, context: string }} result
31 */
32const splitContextFromPrefix = (prefix) => {
33 const idx = prefix.lastIndexOf("/");
34 let context = ".";
35 if (idx >= 0) {
36 context = prefix.slice(0, idx);
37 prefix = `.${prefix.slice(idx)}`;
38 }
39 return {
40 context,
41 prefix
42 };
43};
44
45/** @typedef {Partial<Omit<ContextDependencyOptions, "resource">>} PartialContextDependencyOptions */
46/** @typedef {{ new (options: ContextDependencyOptions, range: Range, valueRange: Range, ...args: EXPECTED_ANY[]): ContextDependency }} ContextDependencyConstructor */
47
48/**
49 * Defines the get additional dep args type used by this module.
50 * @template T
51 * @typedef {T extends new (options: ContextDependencyOptions, range: Range, valueRange: Range, ...remains: infer R) => ContextDependency ? R : []} GetAdditionalDepArgs
52 */
53
54/**
55 * Returns the created Dependency.
56 * @template {ContextDependencyConstructor} T
57 * @param {T} Dep the Dependency class
58 * @param {Range} range source range
59 * @param {BasicEvaluatedExpression} param context param
60 * @param {Expression} expr expr
61 * @param {Pick<JavascriptParserOptions, `${"expr" | "wrapped"}Context${"Critical" | "Recursive" | "RegExp"}` | "exprContextRequest">} options options for context creation
62 * @param {PartialContextDependencyOptions} contextOptions options for the ContextModule
63 * @param {JavascriptParser} parser the parser
64 * @param {GetAdditionalDepArgs<T>} depArgs depArgs
65 * @returns {ContextDependency} the created Dependency
66 */
67module.exports.create = (
68 Dep,
69 range,
70 param,
71 expr,
72 options,
73 contextOptions,
74 parser,
75 ...depArgs
76) => {
77 if (param.isTemplateString()) {
78 const quasis = /** @type {BasicEvaluatedExpression[]} */ (param.quasis);
79 const prefixRaw = /** @type {string} */ (quasis[0].string);
80 const postfixRaw =
81 /** @type {string} */
82 (quasis.length > 1 ? quasis[quasis.length - 1].string : "");
83
84 const valueRange = /** @type {Range} */ (param.range);
85 const { context, prefix } = splitContextFromPrefix(prefixRaw);
86 const {
87 path: postfix,
88 query,
89 fragment
90 } = parseResource(postfixRaw, parser);
91
92 // When there are more than two quasis, the generated RegExp can be more precise
93 // We join the quasis with the expression regexp
94 const innerQuasis = quasis.slice(1, -1);
95 const innerRegExp =
96 /** @type {RegExp} */ (options.wrappedContextRegExp).source +
97 innerQuasis
98 .map(
99 (q) =>
100 quoteMeta(/** @type {string} */ (q.string)) +
101 /** @type {RegExp} */ (options.wrappedContextRegExp).source
102 )
103 .join("");
104
105 // Example: `./context/pre${e}inner${e}inner2${e}post?query#frag`
106 // context: "./context"
107 // prefix: "./pre"
108 // innerQuasis: [BEE("inner"), BEE("inner2")]
109 // (BEE = BasicEvaluatedExpression)
110 // postfix: "post"
111 // query: "?query"
112 // fragment: "#frag"
113 // regExp: /^\.\/pre.*inner.*inner2.*post$/
114 const regExp = new RegExp(
115 `^${quoteMeta(prefix)}${innerRegExp}${quoteMeta(postfix)}$`
116 );
117 const dep = new Dep(
118 {
119 request: context + query + fragment,
120 recursive: /** @type {boolean} */ (options.wrappedContextRecursive),
121 regExp,
122 mode: "sync",
123 ...contextOptions
124 },
125 range,
126 valueRange,
127 ...depArgs
128 );
129 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
130
131 /** @type {Replaces} */
132 const replaces = [];
133 const parts = /** @type {BasicEvaluatedExpression[]} */ (param.parts);
134
135 for (const [i, part] of parts.entries()) {
136 if (i % 2 === 0) {
137 // Quasis or merged quasi
138 let range = /** @type {Range} */ (part.range);
139 let value = /** @type {string} */ (part.string);
140 if (param.templateStringKind === "cooked") {
141 value = JSON.stringify(value);
142 value = value.slice(1, -1);
143 }
144 if (i === 0) {
145 // prefix
146 value = prefix;
147 range = [
148 /** @type {Range} */ (param.range)[0],
149 /** @type {Range} */ (part.range)[1]
150 ];
151 value =
152 (param.templateStringKind === "cooked" ? "`" : "String.raw`") +
153 value;
154 } else if (i === parts.length - 1) {
155 // postfix
156 value = postfix;
157 range = [
158 /** @type {Range} */ (part.range)[0],
159 /** @type {Range} */ (param.range)[1]
160 ];
161 value = `${value}\``;
162 } else if (
163 part.expression &&
164 part.expression.type === "TemplateElement" &&
165 part.expression.value.raw === value
166 ) {
167 // Shortcut when it's a single quasi and doesn't need to be replaced
168 continue;
169 }
170 replaces.push({
171 range,
172 value
173 });
174 } else {
175 // Expression
176 parser.walkExpression(
177 /** @type {Expression} */
178 (part.expression)
179 );
180 }
181 }
182
183 dep.replaces = replaces;
184 dep.critical =
185 options.wrappedContextCritical &&
186 "a part of the request of a dependency is an expression";
187 return dep;
188 } else if (
189 param.isWrapped() &&
190 ((param.prefix && param.prefix.isString()) ||
191 (param.postfix && param.postfix.isString()))
192 ) {
193 const prefixRaw =
194 /** @type {string} */
195 (param.prefix && param.prefix.isString() ? param.prefix.string : "");
196 const postfixRaw =
197 /** @type {string} */
198 (param.postfix && param.postfix.isString() ? param.postfix.string : "");
199 const prefixRange =
200 param.prefix && param.prefix.isString() ? param.prefix.range : null;
201 const postfixRange =
202 param.postfix && param.postfix.isString() ? param.postfix.range : null;
203 const valueRange = /** @type {Range} */ (param.range);
204 const { context, prefix } = splitContextFromPrefix(prefixRaw);
205 const {
206 path: postfix,
207 query,
208 fragment
209 } = parseResource(postfixRaw, parser);
210 const regExp = new RegExp(
211 `^${quoteMeta(prefix)}${
212 /** @type {RegExp} */ (options.wrappedContextRegExp).source
213 }${quoteMeta(postfix)}$`
214 );
215 const dep = new Dep(
216 {
217 request: context + query + fragment,
218 recursive: /** @type {boolean} */ (options.wrappedContextRecursive),
219 regExp,
220 mode: "sync",
221 ...contextOptions
222 },
223 range,
224 valueRange,
225 ...depArgs
226 );
227 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
228 /** @type {Replaces} */
229 const replaces = [];
230 if (prefixRange) {
231 replaces.push({
232 range: prefixRange,
233 value: JSON.stringify(prefix)
234 });
235 }
236 if (postfixRange) {
237 replaces.push({
238 range: postfixRange,
239 value: JSON.stringify(postfix)
240 });
241 }
242 dep.replaces = replaces;
243 dep.critical =
244 options.wrappedContextCritical &&
245 "a part of the request of a dependency is an expression";
246
247 if (parser && param.wrappedInnerExpressions) {
248 for (const part of param.wrappedInnerExpressions) {
249 if (part.expression) {
250 parser.walkExpression(
251 /** @type {Expression} */
252 (part.expression)
253 );
254 }
255 }
256 }
257
258 return dep;
259 }
260 const dep = new Dep(
261 {
262 request: /** @type {string} */ (options.exprContextRequest),
263 recursive: /** @type {boolean} */ (options.exprContextRecursive),
264 regExp: /** @type {RegExp} */ (options.exprContextRegExp),
265 mode: "sync",
266 ...contextOptions
267 },
268 range,
269 /** @type {Range} */ (param.range),
270 ...depArgs
271 );
272 dep.loc = /** @type {DependencyLocation} */ (expr.loc);
273 dep.critical =
274 options.exprContextCritical &&
275 "the request of a dependency is an expression";
276
277 parser.walkExpression(/** @type {Expression} */ (param.expression));
278
279 return dep;
280};
Note: See TracBrowser for help on using the repository browser.