| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const { isRelativeRequest } = require("./util/path");
- /** @typedef {import("./Resolver")} Resolver */
- /** @typedef {import("./Resolver").ResolveRequest} ResolveRequest */
- /** @typedef {import("./Resolver").ResolveStepHook} ResolveStepHook */
- /** @typedef {import("./Resolver").ResolveContextYield} ResolveContextYield */
- /** @typedef {{ [k: string]: undefined | ResolveRequest | ResolveRequest[] }} Cache */
- /**
- * @param {string} relativePath relative path from package root
- * @param {string} request relative request
- * @param {Resolver} resolver resolver instance
- * @returns {string} normalized request with a preserved leading dot
- */
- function joinRelativePreservingLeadingDot(relativePath, request, resolver) {
- const normalized = resolver.join(relativePath, request);
- return isRelativeRequest(normalized) ? normalized : `./${normalized}`;
- }
- /**
- * @param {ResolveRequest} request request
- * @returns {string | false | undefined} normalized path
- */
- function getCachePath(request) {
- if (request.descriptionFileRoot && !request.module) {
- return request.descriptionFileRoot;
- }
- return request.path;
- }
- /**
- * @param {ResolveRequest} request request
- * @param {Resolver} resolver resolver instance
- * @returns {string | undefined} normalized request string
- */
- function getCacheRequest(request, resolver) {
- const requestString = request.request;
- if (
- !requestString ||
- !request.relativePath ||
- !isRelativeRequest(requestString)
- ) {
- return requestString;
- }
- return joinRelativePreservingLeadingDot(
- request.relativePath,
- requestString,
- resolver,
- );
- }
- // Cache-key separator: `\0` is safe because paths, requests, queries and
- // fragments produced by `parseIdentifier` never contain a raw NUL (the
- // \0-escape in identifier.js is decoded back to the original char), and the
- // context, when included, is passed through `JSON.stringify`, which escapes
- // any NUL to \u0000.
- // const SEP = "\0";
- /**
- * Build the cache id for a request. Called on every `described-resolve`
- * invocation when `unsafeCache` is on, so it's a hot path.
- *
- * Equivalent in meaning to the previous `JSON.stringify({ ... })` form, but
- * ~3–5× faster since we avoid the object allocation and JSON serializer for
- * the fields that are already plain strings.
- * @param {string} type type of cache
- * @param {ResolveRequest} request request
- * @param {boolean} withContext cache with context?
- * @param {Resolver} resolver resolver instance
- * @returns {string} cache id
- */
- function getCacheId(type, request, withContext, resolver) {
- // TODO use it in the next major release, it is faster
- // const contextPart = withContext ? JSON.stringify(request.context) : "";
- // const path = getCachePath(request);
- // const cacheRequest = getCacheRequest(request, resolver);
- // return (
- // type +
- // SEP +
- // contextPart +
- // SEP +
- // (path || "") +
- // SEP +
- // (request.query || "") +
- // SEP +
- // (request.fragment || "") +
- // SEP +
- // (cacheRequest || "")
- // );
- return JSON.stringify({
- type,
- context: withContext ? request.context : "",
- path: getCachePath(request),
- query: request.query,
- fragment: request.fragment,
- request: getCacheRequest(request, resolver),
- });
- }
- module.exports = class UnsafeCachePlugin {
- /**
- * @param {string | ResolveStepHook} source source
- * @param {(request: ResolveRequest) => boolean} filterPredicate filterPredicate
- * @param {Cache} cache cache
- * @param {boolean} withContext withContext
- * @param {string | ResolveStepHook} target target
- */
- constructor(source, filterPredicate, cache, withContext, target) {
- this.source = source;
- this.filterPredicate = filterPredicate;
- this.withContext = withContext;
- this.cache = cache;
- this.target = target;
- }
- /**
- * @param {Resolver} resolver the resolver
- * @returns {void}
- */
- apply(resolver) {
- const target = resolver.ensureHook(this.target);
- resolver
- .getHook(this.source)
- .tapAsync("UnsafeCachePlugin", (request, resolveContext, callback) => {
- if (!this.filterPredicate(request)) {
- return resolver.doResolve(
- target,
- request,
- null,
- resolveContext,
- callback,
- );
- }
- const isYield = typeof resolveContext.yield === "function";
- const cacheId = getCacheId(
- isYield ? "yield" : "default",
- request,
- this.withContext,
- resolver,
- );
- const cacheEntry = this.cache[cacheId];
- if (cacheEntry) {
- if (isYield) {
- const yield_ =
- /** @type {ResolveContextYield} */
- (resolveContext.yield);
- if (Array.isArray(cacheEntry)) {
- for (const result of cacheEntry) yield_(result);
- } else {
- yield_(cacheEntry);
- }
- return callback(null, null);
- }
- return callback(null, /** @type {ResolveRequest} */ (cacheEntry));
- }
- /** @type {ResolveContextYield | undefined} */
- let yieldFn;
- /** @type {ResolveContextYield | undefined} */
- let yield_;
- /** @type {ResolveRequest[]} */
- const yieldResult = [];
- if (isYield) {
- yieldFn = resolveContext.yield;
- yield_ = (result) => {
- yieldResult.push(result);
- };
- }
- resolver.doResolve(
- target,
- request,
- null,
- yield_ ? { ...resolveContext, yield: yield_ } : resolveContext,
- (err, result) => {
- if (err) return callback(err);
- if (isYield) {
- if (result) yieldResult.push(result);
- for (const result of yieldResult) {
- /** @type {ResolveContextYield} */
- (yieldFn)(result);
- }
- this.cache[cacheId] = yieldResult;
- return callback(null, null);
- }
- if (result) return callback(null, (this.cache[cacheId] = result));
- callback();
- },
- );
- });
- }
- };
|