(path, data, assetInfo)
| 339 | * @returns {string} the interpolated path |
| 340 | */ |
| 341 | const interpolate = (path, data, assetInfo) => { |
| 342 | if (typeof path === "function") { |
| 343 | path = path(data, assetInfo); |
| 344 | } |
| 345 | |
| 346 | // Literal paths carry no `[placeholder]`, so the whole replacement table |
| 347 | // and regex pass are pure overhead — building replacers has no side effects |
| 348 | // (those only fire when a replacer is invoked), so the output is identical. |
| 349 | if (!path.includes("[")) { |
| 350 | return path; |
| 351 | } |
| 352 | |
| 353 | // Only build replacers for placeholders the template actually uses — most |
| 354 | // templates reference a handful, so building the whole table per call is |
| 355 | // wasted work. Replacer construction has no side effects (those fire only |
| 356 | // when a replacer is invoked, which happens for present kinds), so this is |
| 357 | // output-identical. |
| 358 | const presentKinds = getPresentKinds(path); |
| 359 | |
| 360 | const chunkGraph = data.chunkGraph; |
| 361 | // Digest the stored hashes are encoded in, so `[hash:<digest>]` can re-encode. |
| 362 | const sourceDigest = data.hashDigest || "hex"; |
| 363 | |
| 364 | /** @type {Map<string, Replacer>} */ |
| 365 | const replacements = new Map(); |
| 366 | |
| 367 | // Filename context |
| 368 | // |
| 369 | // Placeholders |
| 370 | // |
| 371 | // for /some/path/file.js?query#fragment: |
| 372 | // [file] - /some/path/file.js |
| 373 | // [query] - ?query |
| 374 | // [fragment] - #fragment |
| 375 | // [base] - file.js |
| 376 | // [path] - /some/path/ |
| 377 | // [name] - file |
| 378 | // [ext] - .js |
| 379 | if ( |
| 380 | typeof data.filename === "string" && |
| 381 | (presentKinds.has("file") || |
| 382 | presentKinds.has("query") || |
| 383 | presentKinds.has("fragment") || |
| 384 | presentKinds.has("path") || |
| 385 | presentKinds.has("base") || |
| 386 | presentKinds.has("name") || |
| 387 | presentKinds.has("ext") || |
| 388 | presentKinds.has("filebase")) |
| 389 | ) { |
| 390 | // check that filename is data uri |
| 391 | const match = data.filename.match(/^data:([^;,]+)/); |
| 392 | if (match) { |
| 393 | const ext = getMimeTypes().extension(match[1]); |
| 394 | const emptyReplacer = replacer("", true); |
| 395 | // "XXXX" used for `updateHash`, so we don't need it here |
| 396 | const contentHash = |
| 397 | data.contentHash && !/X+/.test(data.contentHash) |
| 398 | ? data.contentHash |
no test coverage detected