source: imaps-frontend/node_modules/webpack/lib/TemplatedPathPlugin.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

  • Property mode set to 100644
File size: 10.1 KB
RevLine 
[79a0317]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Jason Anderson @diurnalist
4*/
5
6"use strict";
7
8const mime = require("mime-types");
9const { basename, extname } = require("path");
10const util = require("util");
11const Chunk = require("./Chunk");
12const Module = require("./Module");
13const { parseResource } = require("./util/identifier");
14
15/** @typedef {import("./ChunkGraph")} ChunkGraph */
16/** @typedef {import("./ChunkGraph").ModuleId} ModuleId */
17/** @typedef {import("./Compilation").AssetInfo} AssetInfo */
18/** @typedef {import("./Compilation").PathData} PathData */
19/** @typedef {import("./Compiler")} Compiler */
20
21const REGEXP = /\[\\*([\w:]+)\\*\]/gi;
22
23/**
24 * @param {string | number} id id
25 * @returns {string | number} result
26 */
27const prepareId = id => {
28 if (typeof id !== "string") return id;
29
30 if (/^"\s\+*.*\+\s*"$/.test(id)) {
31 const match = /^"\s\+*\s*(.*)\s*\+\s*"$/.exec(id);
32
33 return `" + (${
34 /** @type {string[]} */ (match)[1]
35 } + "").replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_") + "`;
36 }
37
38 return id.replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_");
39};
40
41/**
42 * @callback ReplacerFunction
43 * @param {string} match
44 * @param {string | undefined} arg
45 * @param {string} input
46 */
47
48/**
49 * @param {ReplacerFunction} replacer replacer
50 * @param {((arg0: number) => string) | undefined} handler handler
51 * @param {AssetInfo | undefined} assetInfo asset info
52 * @param {string} hashName hash name
53 * @returns {ReplacerFunction} hash replacer function
54 */
55const hashLength = (replacer, handler, assetInfo, hashName) => {
56 /** @type {ReplacerFunction} */
57 const fn = (match, arg, input) => {
58 let result;
59 const length = arg && Number.parseInt(arg, 10);
60
61 if (length && handler) {
62 result = handler(length);
63 } else {
64 const hash = replacer(match, arg, input);
65
66 result = length ? hash.slice(0, length) : hash;
67 }
68 if (assetInfo) {
69 assetInfo.immutable = true;
70 if (Array.isArray(assetInfo[hashName])) {
71 assetInfo[hashName] = [...assetInfo[hashName], result];
72 } else if (assetInfo[hashName]) {
73 assetInfo[hashName] = [assetInfo[hashName], result];
74 } else {
75 assetInfo[hashName] = result;
76 }
77 }
78 return result;
79 };
80
81 return fn;
82};
83
84/** @typedef {(match: string, arg?: string, input?: string) => string} Replacer */
85
86/**
87 * @param {string | number | null | undefined | (() => string | number | null | undefined)} value value
88 * @param {boolean=} allowEmpty allow empty
89 * @returns {Replacer} replacer
90 */
91const replacer = (value, allowEmpty) => {
92 /** @type {Replacer} */
93 const fn = (match, arg, input) => {
94 if (typeof value === "function") {
95 value = value();
96 }
97 if (value === null || value === undefined) {
98 if (!allowEmpty) {
99 throw new Error(
100 `Path variable ${match} not implemented in this context: ${input}`
101 );
102 }
103
104 return "";
105 }
106
107 return `${value}`;
108 };
109
110 return fn;
111};
112
113const deprecationCache = new Map();
114const deprecatedFunction = (() => () => {})();
115/**
116 * @param {Function} fn function
117 * @param {string} message message
118 * @param {string} code code
119 * @returns {function(...any[]): void} function with deprecation output
120 */
121const deprecated = (fn, message, code) => {
122 let d = deprecationCache.get(message);
123 if (d === undefined) {
124 d = util.deprecate(deprecatedFunction, message, code);
125 deprecationCache.set(message, d);
126 }
127 return (...args) => {
128 d();
129 return fn(...args);
130 };
131};
132
133/** @typedef {string | function(PathData, AssetInfo=): string} TemplatePath */
134
135/**
136 * @param {TemplatePath} path the raw path
137 * @param {PathData} data context data
138 * @param {AssetInfo | undefined} assetInfo extra info about the asset (will be written to)
139 * @returns {string} the interpolated path
140 */
141const replacePathVariables = (path, data, assetInfo) => {
142 const chunkGraph = data.chunkGraph;
143
144 /** @type {Map<string, Function>} */
145 const replacements = new Map();
146
147 // Filename context
148 //
149 // Placeholders
150 //
151 // for /some/path/file.js?query#fragment:
152 // [file] - /some/path/file.js
153 // [query] - ?query
154 // [fragment] - #fragment
155 // [base] - file.js
156 // [path] - /some/path/
157 // [name] - file
158 // [ext] - .js
159 if (typeof data.filename === "string") {
160 // check that filename is data uri
161 const match = data.filename.match(/^data:([^;,]+)/);
162 if (match) {
163 const ext = mime.extension(match[1]);
164 const emptyReplacer = replacer("", true);
165 // "XXXX" used for `updateHash`, so we don't need it here
166 const contentHash =
167 data.contentHash && !/X+/.test(data.contentHash)
168 ? data.contentHash
169 : false;
170 const baseReplacer = contentHash ? replacer(contentHash) : emptyReplacer;
171
172 replacements.set("file", emptyReplacer);
173 replacements.set("query", emptyReplacer);
174 replacements.set("fragment", emptyReplacer);
175 replacements.set("path", emptyReplacer);
176 replacements.set("base", baseReplacer);
177 replacements.set("name", baseReplacer);
178 replacements.set("ext", replacer(ext ? `.${ext}` : "", true));
179 // Legacy
180 replacements.set(
181 "filebase",
182 deprecated(
183 baseReplacer,
184 "[filebase] is now [base]",
185 "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_FILENAME"
186 )
187 );
188 } else {
189 const { path: file, query, fragment } = parseResource(data.filename);
190
191 const ext = extname(file);
192 const base = basename(file);
193 const name = base.slice(0, base.length - ext.length);
194 const path = file.slice(0, file.length - base.length);
195
196 replacements.set("file", replacer(file));
197 replacements.set("query", replacer(query, true));
198 replacements.set("fragment", replacer(fragment, true));
199 replacements.set("path", replacer(path, true));
200 replacements.set("base", replacer(base));
201 replacements.set("name", replacer(name));
202 replacements.set("ext", replacer(ext, true));
203 // Legacy
204 replacements.set(
205 "filebase",
206 deprecated(
207 replacer(base),
208 "[filebase] is now [base]",
209 "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_FILENAME"
210 )
211 );
212 }
213 }
214
215 // Compilation context
216 //
217 // Placeholders
218 //
219 // [fullhash] - data.hash (3a4b5c6e7f)
220 //
221 // Legacy Placeholders
222 //
223 // [hash] - data.hash (3a4b5c6e7f)
224 if (data.hash) {
225 const hashReplacer = hashLength(
226 replacer(data.hash),
227 data.hashWithLength,
228 assetInfo,
229 "fullhash"
230 );
231
232 replacements.set("fullhash", hashReplacer);
233
234 // Legacy
235 replacements.set(
236 "hash",
237 deprecated(
238 hashReplacer,
239 "[hash] is now [fullhash] (also consider using [chunkhash] or [contenthash], see documentation for details)",
240 "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_HASH"
241 )
242 );
243 }
244
245 // Chunk Context
246 //
247 // Placeholders
248 //
249 // [id] - chunk.id (0.js)
250 // [name] - chunk.name (app.js)
251 // [chunkhash] - chunk.hash (7823t4t4.js)
252 // [contenthash] - chunk.contentHash[type] (3256u3zg.js)
253 if (data.chunk) {
254 const chunk = data.chunk;
255
256 const contentHashType = data.contentHashType;
257
258 const idReplacer = replacer(chunk.id);
259 const nameReplacer = replacer(chunk.name || chunk.id);
260 const chunkhashReplacer = hashLength(
261 replacer(chunk instanceof Chunk ? chunk.renderedHash : chunk.hash),
262 "hashWithLength" in chunk ? chunk.hashWithLength : undefined,
263 assetInfo,
264 "chunkhash"
265 );
266 const contenthashReplacer = hashLength(
267 replacer(
268 data.contentHash ||
269 (contentHashType &&
270 chunk.contentHash &&
271 chunk.contentHash[contentHashType])
272 ),
273 data.contentHashWithLength ||
274 ("contentHashWithLength" in chunk && chunk.contentHashWithLength
275 ? chunk.contentHashWithLength[/** @type {string} */ (contentHashType)]
276 : undefined),
277 assetInfo,
278 "contenthash"
279 );
280
281 replacements.set("id", idReplacer);
282 replacements.set("name", nameReplacer);
283 replacements.set("chunkhash", chunkhashReplacer);
284 replacements.set("contenthash", contenthashReplacer);
285 }
286
287 // Module Context
288 //
289 // Placeholders
290 //
291 // [id] - module.id (2.png)
292 // [hash] - module.hash (6237543873.png)
293 //
294 // Legacy Placeholders
295 //
296 // [moduleid] - module.id (2.png)
297 // [modulehash] - module.hash (6237543873.png)
298 if (data.module) {
299 const module = data.module;
300
301 const idReplacer = replacer(() =>
302 prepareId(
303 module instanceof Module
304 ? /** @type {ModuleId} */
305 (/** @type {ChunkGraph} */ (chunkGraph).getModuleId(module))
306 : module.id
307 )
308 );
309 const moduleHashReplacer = hashLength(
310 replacer(() =>
311 module instanceof Module
312 ? /** @type {ChunkGraph} */
313 (chunkGraph).getRenderedModuleHash(module, data.runtime)
314 : module.hash
315 ),
316 "hashWithLength" in module ? module.hashWithLength : undefined,
317 assetInfo,
318 "modulehash"
319 );
320 const contentHashReplacer = hashLength(
321 replacer(/** @type {string} */ (data.contentHash)),
322 undefined,
323 assetInfo,
324 "contenthash"
325 );
326
327 replacements.set("id", idReplacer);
328 replacements.set("modulehash", moduleHashReplacer);
329 replacements.set("contenthash", contentHashReplacer);
330 replacements.set(
331 "hash",
332 data.contentHash ? contentHashReplacer : moduleHashReplacer
333 );
334 // Legacy
335 replacements.set(
336 "moduleid",
337 deprecated(
338 idReplacer,
339 "[moduleid] is now [id]",
340 "DEP_WEBPACK_TEMPLATE_PATH_PLUGIN_REPLACE_PATH_VARIABLES_MODULE_ID"
341 )
342 );
343 }
344
345 // Other things
346 if (data.url) {
347 replacements.set("url", replacer(data.url));
348 }
349 if (typeof data.runtime === "string") {
350 replacements.set(
351 "runtime",
352 replacer(() => prepareId(/** @type {string} */ (data.runtime)))
353 );
354 } else {
355 replacements.set("runtime", replacer("_"));
356 }
357
358 if (typeof path === "function") {
359 path = path(data, assetInfo);
360 }
361
362 path = path.replace(REGEXP, (match, content) => {
363 if (content.length + 2 === match.length) {
364 const contentMatch = /^(\w+)(?::(\w+))?$/.exec(content);
365 if (!contentMatch) return match;
366 const [, kind, arg] = contentMatch;
367 const replacer = replacements.get(kind);
368 if (replacer !== undefined) {
369 return replacer(match, arg, path);
370 }
371 } else if (match.startsWith("[\\") && match.endsWith("\\]")) {
372 return `[${match.slice(2, -2)}]`;
373 }
374 return match;
375 });
376
377 return path;
378};
379
380const plugin = "TemplatedPathPlugin";
381
382class TemplatedPathPlugin {
383 /**
384 * Apply the plugin
385 * @param {Compiler} compiler the compiler instance
386 * @returns {void}
387 */
388 apply(compiler) {
389 compiler.hooks.compilation.tap(plugin, compilation => {
390 compilation.hooks.assetPath.tap(plugin, replacePathVariables);
391 });
392 }
393}
394
395module.exports = TemplatedPathPlugin;
Note: See TracBrowser for help on using the repository browser.