| | |
| | | |
| | | const { basename, extname } = require("path"); |
| | | const util = require("util"); |
| | | const mime = require("mime-types"); |
| | | const Chunk = require("./Chunk"); |
| | | const Module = require("./Module"); |
| | | const { parseResource } = require("./util/identifier"); |
| | | const memoize = require("./util/memoize"); |
| | | |
| | | const getMimeTypes = memoize(() => require("./util/mimeTypes")); |
| | | |
| | | /** @typedef {import("./ChunkGraph")} ChunkGraph */ |
| | | /** @typedef {import("./ChunkGraph").ModuleId} ModuleId */ |
| | |
| | | /** @typedef {import("./Compilation").PathData} PathData */ |
| | | /** @typedef {import("./Compiler")} Compiler */ |
| | | |
| | | const REGEXP = /\[\\*([\w:]+)\\*\]/gi; |
| | | const REGEXP = /\[\\*([\w:]+)\\*\]/g; |
| | | |
| | | /** |
| | | * @param {string | number} id id |
| | | * @returns {string | number} result |
| | | */ |
| | | /** @type {PathData["prepareId"]} */ |
| | | const prepareId = (id) => { |
| | | if (typeof id !== "string") return id; |
| | | |
| | |
| | | } + "").replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_") + "`; |
| | | } |
| | | |
| | | return id.replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_"); |
| | | return id.replace(/(^[.-]|[^a-z0-9_-])+/gi, "_"); |
| | | }; |
| | | |
| | | /** |
| | | * Defines the replacer function callback. |
| | | * @callback ReplacerFunction |
| | | * @param {string} match |
| | | * @param {string | undefined} arg |
| | |
| | | */ |
| | | |
| | | /** |
| | | * Returns hash replacer function. |
| | | * @param {ReplacerFunction} replacer replacer |
| | | * @param {((arg0: number) => string) | undefined} handler handler |
| | | * @param {AssetInfo | undefined} assetInfo asset info |
| | |
| | | const hashLength = (replacer, handler, assetInfo, hashName) => { |
| | | /** @type {Replacer} */ |
| | | const fn = (match, arg, input) => { |
| | | /** @type {string} */ |
| | | let result; |
| | | const length = arg && Number.parseInt(arg, 10); |
| | | |
| | |
| | | /** @typedef {(match: string, arg: string | undefined, input: string) => string} Replacer */ |
| | | |
| | | /** |
| | | * Returns replacer. |
| | | * @param {string | number | null | undefined | (() => string | number | null | undefined)} value value |
| | | * @param {boolean=} allowEmpty allow empty |
| | | * @returns {Replacer} replacer |
| | |
| | | return fn; |
| | | }; |
| | | |
| | | /** @type {Map<string, (...args: EXPECTED_ANY[]) => EXPECTED_ANY>} */ |
| | | const deprecationCache = new Map(); |
| | | const deprecatedFunction = (() => () => {})(); |
| | | /** |
| | | * Returns function with deprecation output. |
| | | * @template {(...args: EXPECTED_ANY[]) => EXPECTED_ANY} T |
| | | * @param {T} fn function |
| | | * @param {string} message message |
| | |
| | | /** @typedef {string | TemplatePathFn} TemplatePath */ |
| | | |
| | | /** |
| | | * Returns the interpolated path. |
| | | * @param {TemplatePath} path the raw path |
| | | * @param {PathData} data context data |
| | | * @param {AssetInfo | undefined} assetInfo extra info about the asset (will be written to) |
| | | * @param {AssetInfo=} assetInfo extra info about the asset (will be written to) |
| | | * @returns {string} the interpolated path |
| | | */ |
| | | const replacePathVariables = (path, data, assetInfo) => { |
| | | const interpolate = (path, data, assetInfo) => { |
| | | const chunkGraph = data.chunkGraph; |
| | | |
| | | /** @type {Map<string, Replacer>} */ |
| | |
| | | // check that filename is data uri |
| | | const match = data.filename.match(/^data:([^;,]+)/); |
| | | if (match) { |
| | | const ext = mime.extension(match[1]); |
| | | const ext = getMimeTypes().extension(match[1]); |
| | | const emptyReplacer = replacer("", true); |
| | | // "XXXX" used for `updateHash`, so we don't need it here |
| | | const contentHash = |
| | |
| | | const module = data.module; |
| | | |
| | | const idReplacer = replacer(() => |
| | | prepareId( |
| | | (data.prepareId || prepareId)( |
| | | module instanceof Module |
| | | ? /** @type {ModuleId} */ |
| | | (/** @type {ChunkGraph} */ (chunkGraph).getModuleId(module)) |
| | |
| | | if (typeof data.runtime === "string") { |
| | | replacements.set( |
| | | "runtime", |
| | | replacer(() => prepareId(/** @type {string} */ (data.runtime))) |
| | | replacer(() => |
| | | (data.prepareId || prepareId)(/** @type {string} */ (data.runtime)) |
| | | ) |
| | | ); |
| | | } else { |
| | | replacements.set("runtime", replacer("_")); |
| | |
| | | |
| | | class TemplatedPathPlugin { |
| | | /** |
| | | * Apply the plugin |
| | | * Applies the plugin by registering its hooks on the compiler. |
| | | * @param {Compiler} compiler the compiler instance |
| | | * @returns {void} |
| | | */ |
| | | apply(compiler) { |
| | | compiler.hooks.compilation.tap(plugin, (compilation) => { |
| | | compilation.hooks.assetPath.tap(plugin, replacePathVariables); |
| | | compilation.hooks.assetPath.tap(plugin, interpolate); |
| | | }); |
| | | } |
| | | } |
| | | |
| | | module.exports = TemplatedPathPlugin; |
| | | module.exports.interpolate = interpolate; |