gitea push
This commit is contained in:
+64
-17
@@ -89,6 +89,8 @@ const _withResolvers =
|
||||
/** @type {WeakMap<FileSystem, PathCacheFunctions>} */
|
||||
const _pathCacheByFs = new WeakMap();
|
||||
|
||||
const HASH_ESCAPE_RE = /#/g;
|
||||
|
||||
/** @typedef {import("./ResolverFactory").ResolveOptions} ResolveOptions */
|
||||
|
||||
/**
|
||||
@@ -450,6 +452,16 @@ class StackEntry {
|
||||
/**
|
||||
* Walk the linked list looking for an entry with the same request shape.
|
||||
* Set-compatible: callers that used `stack.has(entry)` keep working.
|
||||
*
|
||||
* NOTE: kept monomorphic on purpose. An earlier draft accepted a string
|
||||
* query too (so pre-5.21 plugins keeping their own `Set<string>` of
|
||||
* seen entries could probe the live stack with the formatted form),
|
||||
* but adding the second shape regressed `doResolve`'s heap profile by
|
||||
* ~1 MiB / 200 resolves on stack-churn — V8 keeps a polymorphic
|
||||
* call-site state for `parent.has(stackEntry)` once `has` has two
|
||||
* argument shapes. Plugins that need string membership can reach for
|
||||
* `[...stack].find(e => e.includes(formattedString))` via the
|
||||
* `String`-method proxies on `StackEntry` instead.
|
||||
* @param {StackEntry} query entry to look for
|
||||
* @returns {boolean} whether the stack already contains an equivalent entry
|
||||
*/
|
||||
@@ -493,7 +505,15 @@ class StackEntry {
|
||||
* `Set` that was populated in insertion order would iterate. Pre-seeded
|
||||
* legacy `Set<string>` entries come first so error-message output stays
|
||||
* ordered oldest-to-newest.
|
||||
* @returns {IterableIterator<StackEntry | string>} iterator
|
||||
*
|
||||
* Yields each entry as its formatted `toString()` form. Plugins written
|
||||
* against the pre-5.21 `Set<string>` shape — e.g.
|
||||
* `[...resolveContext.stack].find(a => a.includes("module:"))` — keep
|
||||
* working unchanged because each yielded value is a plain string with
|
||||
* all of `String.prototype` available natively. Resolves that never
|
||||
* iterate the stack pay nothing; iteration costs one `toString()`
|
||||
* allocation per stack frame.
|
||||
* @returns {IterableIterator<string>} iterator
|
||||
*/
|
||||
*[Symbol.iterator]() {
|
||||
if (this.preSeeded !== undefined) {
|
||||
@@ -507,12 +527,14 @@ class StackEntry {
|
||||
entries.push(node);
|
||||
node = node.parent;
|
||||
}
|
||||
for (let i = entries.length - 1; i >= 0; i--) yield entries[i];
|
||||
for (let i = entries.length - 1; i >= 0; i--) yield entries[i].toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Human-readable form used in recursion error messages and logs.
|
||||
* Matches the historical string format so existing log parsers stay valid.
|
||||
* Human-readable form used in recursion error messages, logs, and the
|
||||
* iterator above. Not memoized: caching would require an extra slot on
|
||||
* every `StackEntry`, which costs heap even on resolves that never look
|
||||
* at the formatted form.
|
||||
* @returns {string} formatted entry
|
||||
*/
|
||||
toString() {
|
||||
@@ -887,16 +909,27 @@ class Resolver {
|
||||
* @param {ResolveRequest} result result
|
||||
* @returns {void}
|
||||
*/
|
||||
const finishResolved = (result) =>
|
||||
callback(
|
||||
const finishResolved = (result) => {
|
||||
const resultPath = result.path;
|
||||
if (resultPath === false) return callback(null, false, result);
|
||||
const escapedPath = resultPath.includes("#")
|
||||
? resultPath.replace(HASH_ESCAPE_RE, "\0#")
|
||||
: resultPath;
|
||||
const resultQuery = result.query;
|
||||
let escapedQuery;
|
||||
if (resultQuery) {
|
||||
escapedQuery = resultQuery.includes("#")
|
||||
? resultQuery.replace(HASH_ESCAPE_RE, "\0#")
|
||||
: resultQuery;
|
||||
} else {
|
||||
escapedQuery = "";
|
||||
}
|
||||
return callback(
|
||||
null,
|
||||
result.path === false
|
||||
? false
|
||||
: `${result.path.replace(/#/g, "\0#")}${
|
||||
result.query ? result.query.replace(/#/g, "\0#") : ""
|
||||
}${result.fragment || ""}`,
|
||||
`${escapedPath}${escapedQuery}${result.fragment || ""}`,
|
||||
result,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string[]} log logs
|
||||
@@ -1051,9 +1084,7 @@ class Resolver {
|
||||
* @type {Error & { recursion?: boolean }}
|
||||
*/
|
||||
const recursionError = new Error(
|
||||
`Recursion in resolving\nStack:\n ${[...stackEntry]
|
||||
.map((entry) => entry.toString())
|
||||
.join("\n ")}`,
|
||||
`Recursion in resolving\nStack:\n ${[...stackEntry].join("\n ")}`,
|
||||
);
|
||||
recursionError.recursion = true;
|
||||
if (resolveContext.log) {
|
||||
@@ -1106,9 +1137,25 @@ class Resolver {
|
||||
[part.request, part.query, part.fragment] = parsedIdentifier;
|
||||
|
||||
if (part.request.length > 0) {
|
||||
part.internal = this.isPrivate(identifier);
|
||||
part.module = this.isModule(part.request);
|
||||
part.directory = this.isDirectory(part.request);
|
||||
// `getType` looks at the prefix of its input and the prefix is
|
||||
// identical between `identifier` and `part.request` in every
|
||||
// non-`\0`-escape case (slicing off `?query` / `#fragment` doesn't
|
||||
// touch the head). `parseIdentifier`'s common fast path returns
|
||||
// the same `identifier` reference as `parsedIdentifier[0]`, so a
|
||||
// pointer-equality check detects the case where we can compute
|
||||
// `getType` once and use it for both `module` and `internal`. The
|
||||
// `\0#…` escape path produces a fresh `part.request` and falls
|
||||
// through to the second `getType(identifier)` call to preserve
|
||||
// the original `internal` flag.
|
||||
const requestType = getType(part.request);
|
||||
part.module = requestType === PathType.Normal;
|
||||
part.internal =
|
||||
identifier === part.request
|
||||
? requestType === PathType.Internal
|
||||
: getType(identifier) === PathType.Internal;
|
||||
// `isDirectory` is just `endsWith("/")` — inline so `parse()`
|
||||
// doesn't pay for the extra method dispatch on every resolve.
|
||||
part.directory = part.request.endsWith("/");
|
||||
if (part.directory) {
|
||||
part.request = part.request.slice(0, -1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user