substrate-ai 0.20.55 → 0.20.57
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapter-registry-k7ZX3Bz6.js +4 -0
- package/dist/cli/index.js +3846 -20
- package/dist/{decisions-UFV5YFaW.js → decisions-4F91LrVD.js} +1 -1
- package/dist/{dist-VcMmfo2w.js → dist-W2emvN3F.js} +31 -4
- package/dist/{errors-CogpxBUg.js → errors-CKFu8YI9.js} +2 -2
- package/dist/{experimenter-2KGF4bLj.js → experimenter-DxxwicpK.js} +1 -1
- package/dist/{health-BdsvEnfm.js → health-HmyFdWEf.js} +2 -2
- package/dist/{health-PSnpYDAa.js → health-PdI4-96I.js} +129 -11
- package/dist/index.d.ts +61 -8
- package/dist/index.js +2 -2
- package/dist/{routing-BNGNSI0w.js → routing-0ykvBl_4.js} +1 -1
- package/dist/{run-CkFWtcjl.js → run-BF8oeJhG.js} +3 -3
- package/dist/{run-CeaNSnD6.js → run-DcDoaG12.js} +76 -34
- package/dist/{upgrade-Csv0GRft.js → upgrade-C8LAnB6W.js} +2 -2
- package/dist/{upgrade-CF4__LCr.js → upgrade-CAqLkNUP.js} +2 -2
- package/dist/{version-manager-impl-C-mrgne3.js → version-manager-impl-DaA_ALYK.js} +1 -1
- package/package.json +1 -1
- package/dist/adapter-registry-CcahKCG1.js +0 -4
package/dist/cli/index.js
CHANGED
|
@@ -1,31 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-
|
|
2
|
+
import { FileStateStore, RunManifest, SUBSTRATE_OWNED_SETTINGS_KEYS, SupervisorLock, VALID_PHASES, WorkGraphRepository, ZERO_FINDINGS_BY_AUTHOR, ZERO_FINDING_COUNTS, ZERO_PROBE_AUTHOR_METRICS, aggregateProbeAuthorMetrics, buildPipelineStatusOutput, createDatabaseAdapter, createStateStore, findPackageRoot, formatOutput, formatPipelineStatusHuman, formatPipelineSummary, formatTokenTelemetry, getAllDescendantPids, getAutoHealthData, getSubstrateDefaultSettings, inspectProcessTree, parseDbTimestampAsUtc, parseRuntimeProbes, registerHealthCommand, resolveBmadMethodSrcPath, resolveBmadMethodVersion, resolveMainRepoRoot, resolveRunManifest, rollupFindingCounts, rollupFindingsByAuthor, rollupProbeAuthorByClass, rollupProbeAuthorMetrics } from "../health-PdI4-96I.js";
|
|
3
3
|
import { createLogger } from "../logger-KeHncl-f.js";
|
|
4
4
|
import { createEventBus } from "../helpers-CElYrONe.js";
|
|
5
|
-
import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-
|
|
5
|
+
import { AdapterRegistry, BudgetConfigSchema, CURRENT_CONFIG_FORMAT_VERSION, CURRENT_TASK_GRAPH_VERSION, ConfigError, CostTrackerConfigSchema, DEFAULT_CONFIG, DoltClient, DoltNotInstalled, GlobalSettingsSchema, InMemoryDatabaseAdapter, IngestionServer, MonitorDatabaseImpl, OPERATIONAL_FINDING, PartialGlobalSettingsSchema, PartialProviderConfigSchema, ProvidersSchema, RoutingRecommender, STORY_METRICS, TelemetryConfigSchema, addTokenUsage, aggregateTokenUsageForRun, checkDoltInstalled, compareRunMetrics, createAmendmentRun, createConfigSystem, createDecision, createDoltClient, createPipelineRun, getActiveDecisions, getAllCostEntriesFiltered, getBaselineRunMetrics, getDecisionsByCategory, getDecisionsByPhaseForRun, getLatestCompletedRun, getLatestRun, getPipelineRunById, getPlanningCostTotal, getRetryableEscalations, getRunMetrics, getRunningPipelineRuns, getSessionCostSummary, getSessionCostSummaryFiltered, getStoryMetricsForRun, getTokenUsageSummary, incrementRunRestarts, initSchema, initializeDolt, listRunMetrics, loadParentRunDecisions, supersedeDecision, tagRunAsBaseline, updatePipelineRun } from "../dist-W2emvN3F.js";
|
|
6
6
|
import "../adapter-registry-DXLMTmfD.js";
|
|
7
|
-
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GitClient, GrammarLoader, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, validateStopAfterFromConflict } from "../run-
|
|
8
|
-
import "../errors-
|
|
7
|
+
import { AdapterTelemetryPersistence, AppError, DoltRepoMapMetaRepository, DoltSymbolRepository, ERR_REPO_MAP_STORAGE_WRITE, EpicIngester, GLOBSTAR, GitClient, GrammarLoader, Minimatch, Minipass, RepoMapInjector, RepoMapModule, RepoMapQueryEngine, RepoMapStorage, SymbolParser, createContextCompiler, createDispatcher, createEventEmitter, createImplementationOrchestrator, createPackLoader, createPhaseOrchestrator, createStopAfterGate, createTelemetryAdvisor, escape, formatPhaseCompletionSummary, getFactoryRunSummaries, getScenarioResultsForRun, getTwinRunsForRun, listGraphRuns, registerExportCommand, registerFactoryCommand, registerRunCommand, registerScenariosCommand, resolveStoryKeys, runAnalysisPhase, runPlanningPhase, runProbeAuthor, runSolutioningPhase, unescape, validateStopAfterFromConflict } from "../run-DcDoaG12.js";
|
|
8
|
+
import "../errors-CKFu8YI9.js";
|
|
9
9
|
import "../routing-CcBOCuC9.js";
|
|
10
10
|
import "../decisions-C0pz9Clx.js";
|
|
11
11
|
import "../version-manager-impl-BmOWu8ml.js";
|
|
12
|
-
import { registerUpgradeCommand } from "../upgrade-
|
|
12
|
+
import { registerUpgradeCommand } from "../upgrade-CAqLkNUP.js";
|
|
13
13
|
import { Command } from "commander";
|
|
14
14
|
import { fileURLToPath } from "url";
|
|
15
15
|
import { dirname, join, resolve } from "path";
|
|
16
16
|
import { access, mkdir, readFile, writeFile } from "fs/promises";
|
|
17
17
|
import yaml from "js-yaml";
|
|
18
|
-
import
|
|
18
|
+
import * as actualFS from "node:fs";
|
|
19
|
+
import { existsSync, promises, readFileSync, writeFileSync } from "node:fs";
|
|
19
20
|
import { execFile, spawn } from "node:child_process";
|
|
20
21
|
import * as path$3 from "node:path";
|
|
21
22
|
import * as path$2 from "node:path";
|
|
22
23
|
import * as path$1 from "node:path";
|
|
23
|
-
import { basename as basename$1, join as join$1, resolve as resolve$1 } from "node:path";
|
|
24
|
+
import { basename as basename$1, join as join$1, posix, relative, resolve as resolve$1, win32 } from "node:path";
|
|
24
25
|
import { randomUUID } from "node:crypto";
|
|
25
26
|
import { z } from "zod";
|
|
26
27
|
import * as fs from "node:fs/promises";
|
|
27
|
-
import { access as access$1, readFile as readFile$1, readdir as readdir$1 } from "node:fs/promises";
|
|
28
|
-
import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdirSync as readdirSync$1, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
28
|
+
import { access as access$1, lstat, readFile as readFile$1, readdir as readdir$1, readlink, realpath } from "node:fs/promises";
|
|
29
|
+
import { appendFileSync, chmodSync, cpSync, existsSync as existsSync$1, lstatSync, mkdirSync as mkdirSync$1, readFileSync as readFileSync$1, readdir as readdir$2, readdirSync as readdirSync$1, readlinkSync, realpathSync as realpathSync$1, rmSync as rmSync$1, statSync as statSync$1, unlinkSync as unlinkSync$1, writeFileSync as writeFileSync$1 } from "fs";
|
|
29
30
|
import { homedir } from "os";
|
|
30
31
|
import { createRequire } from "node:module";
|
|
31
32
|
import { fileURLToPath as fileURLToPath$1 } from "node:url";
|
|
@@ -3037,10 +3038,3810 @@ function registerConfigCommand(program, _version) {
|
|
|
3037
3038
|
});
|
|
3038
3039
|
}
|
|
3039
3040
|
|
|
3041
|
+
//#endregion
|
|
3042
|
+
//#region node_modules/lru-cache/dist/esm/index.js
|
|
3043
|
+
/**
|
|
3044
|
+
* @module LRUCache
|
|
3045
|
+
*/
|
|
3046
|
+
const perf = typeof performance === "object" && performance && typeof performance.now === "function" ? performance : Date;
|
|
3047
|
+
const warned = new Set();
|
|
3048
|
+
/* c8 ignore start */
|
|
3049
|
+
const PROCESS = typeof process === "object" && !!process ? process : {};
|
|
3050
|
+
/* c8 ignore start */
|
|
3051
|
+
const emitWarning = (msg, type, code, fn) => {
|
|
3052
|
+
typeof PROCESS.emitWarning === "function" ? PROCESS.emitWarning(msg, type, code, fn) : console.error(`[${code}] ${type}: ${msg}`);
|
|
3053
|
+
};
|
|
3054
|
+
let AC = globalThis.AbortController;
|
|
3055
|
+
let AS = globalThis.AbortSignal;
|
|
3056
|
+
/* c8 ignore start */
|
|
3057
|
+
if (typeof AC === "undefined") {
|
|
3058
|
+
AS = class AbortSignal {
|
|
3059
|
+
onabort;
|
|
3060
|
+
_onabort = [];
|
|
3061
|
+
reason;
|
|
3062
|
+
aborted = false;
|
|
3063
|
+
addEventListener(_, fn) {
|
|
3064
|
+
this._onabort.push(fn);
|
|
3065
|
+
}
|
|
3066
|
+
};
|
|
3067
|
+
AC = class AbortController {
|
|
3068
|
+
constructor() {
|
|
3069
|
+
warnACPolyfill();
|
|
3070
|
+
}
|
|
3071
|
+
signal = new AS();
|
|
3072
|
+
abort(reason) {
|
|
3073
|
+
if (this.signal.aborted) return;
|
|
3074
|
+
this.signal.reason = reason;
|
|
3075
|
+
this.signal.aborted = true;
|
|
3076
|
+
for (const fn of this.signal._onabort) fn(reason);
|
|
3077
|
+
this.signal.onabort?.(reason);
|
|
3078
|
+
}
|
|
3079
|
+
};
|
|
3080
|
+
let printACPolyfillWarning = PROCESS.env?.LRU_CACHE_IGNORE_AC_WARNING !== "1";
|
|
3081
|
+
const warnACPolyfill = () => {
|
|
3082
|
+
if (!printACPolyfillWarning) return;
|
|
3083
|
+
printACPolyfillWarning = false;
|
|
3084
|
+
emitWarning("AbortController is not defined. If using lru-cache in node 14, load an AbortController polyfill from the `node-abort-controller` package. A minimal polyfill is provided for use by LRUCache.fetch(), but it should not be relied upon in other contexts (eg, passing it to other APIs that use AbortController/AbortSignal might have undesirable effects). You may disable this with LRU_CACHE_IGNORE_AC_WARNING=1 in the env.", "NO_ABORT_CONTROLLER", "ENOTSUP", warnACPolyfill);
|
|
3085
|
+
};
|
|
3086
|
+
}
|
|
3087
|
+
/* c8 ignore stop */
|
|
3088
|
+
const shouldWarn = (code) => !warned.has(code);
|
|
3089
|
+
const TYPE = Symbol("type");
|
|
3090
|
+
const isPosInt = (n) => n && n === Math.floor(n) && n > 0 && isFinite(n);
|
|
3091
|
+
/* c8 ignore start */
|
|
3092
|
+
const getUintArray = (max) => !isPosInt(max) ? null : max <= Math.pow(2, 8) ? Uint8Array : max <= Math.pow(2, 16) ? Uint16Array : max <= Math.pow(2, 32) ? Uint32Array : max <= Number.MAX_SAFE_INTEGER ? ZeroArray : null;
|
|
3093
|
+
/* c8 ignore stop */
|
|
3094
|
+
var ZeroArray = class extends Array {
|
|
3095
|
+
constructor(size) {
|
|
3096
|
+
super(size);
|
|
3097
|
+
this.fill(0);
|
|
3098
|
+
}
|
|
3099
|
+
};
|
|
3100
|
+
var Stack = class Stack {
|
|
3101
|
+
heap;
|
|
3102
|
+
length;
|
|
3103
|
+
static #constructing = false;
|
|
3104
|
+
static create(max) {
|
|
3105
|
+
const HeapCls = getUintArray(max);
|
|
3106
|
+
if (!HeapCls) return [];
|
|
3107
|
+
Stack.#constructing = true;
|
|
3108
|
+
const s = new Stack(max, HeapCls);
|
|
3109
|
+
Stack.#constructing = false;
|
|
3110
|
+
return s;
|
|
3111
|
+
}
|
|
3112
|
+
constructor(max, HeapCls) {
|
|
3113
|
+
/* c8 ignore start */
|
|
3114
|
+
if (!Stack.#constructing) throw new TypeError("instantiate Stack using Stack.create(n)");
|
|
3115
|
+
/* c8 ignore stop */
|
|
3116
|
+
this.heap = new HeapCls(max);
|
|
3117
|
+
this.length = 0;
|
|
3118
|
+
}
|
|
3119
|
+
push(n) {
|
|
3120
|
+
this.heap[this.length++] = n;
|
|
3121
|
+
}
|
|
3122
|
+
pop() {
|
|
3123
|
+
return this.heap[--this.length];
|
|
3124
|
+
}
|
|
3125
|
+
};
|
|
3126
|
+
/**
|
|
3127
|
+
* Default export, the thing you're using this module to get.
|
|
3128
|
+
*
|
|
3129
|
+
* The `K` and `V` types define the key and value types, respectively. The
|
|
3130
|
+
* optional `FC` type defines the type of the `context` object passed to
|
|
3131
|
+
* `cache.fetch()` and `cache.memo()`.
|
|
3132
|
+
*
|
|
3133
|
+
* Keys and values **must not** be `null` or `undefined`.
|
|
3134
|
+
*
|
|
3135
|
+
* All properties from the options object (with the exception of `max`,
|
|
3136
|
+
* `maxSize`, `fetchMethod`, `memoMethod`, `dispose` and `disposeAfter`) are
|
|
3137
|
+
* added as normal public members. (The listed options are read-only getters.)
|
|
3138
|
+
*
|
|
3139
|
+
* Changing any of these will alter the defaults for subsequent method calls.
|
|
3140
|
+
*/
|
|
3141
|
+
var LRUCache = class LRUCache {
|
|
3142
|
+
#max;
|
|
3143
|
+
#maxSize;
|
|
3144
|
+
#dispose;
|
|
3145
|
+
#disposeAfter;
|
|
3146
|
+
#fetchMethod;
|
|
3147
|
+
#memoMethod;
|
|
3148
|
+
/**
|
|
3149
|
+
* {@link LRUCache.OptionsBase.ttl}
|
|
3150
|
+
*/
|
|
3151
|
+
ttl;
|
|
3152
|
+
/**
|
|
3153
|
+
* {@link LRUCache.OptionsBase.ttlResolution}
|
|
3154
|
+
*/
|
|
3155
|
+
ttlResolution;
|
|
3156
|
+
/**
|
|
3157
|
+
* {@link LRUCache.OptionsBase.ttlAutopurge}
|
|
3158
|
+
*/
|
|
3159
|
+
ttlAutopurge;
|
|
3160
|
+
/**
|
|
3161
|
+
* {@link LRUCache.OptionsBase.updateAgeOnGet}
|
|
3162
|
+
*/
|
|
3163
|
+
updateAgeOnGet;
|
|
3164
|
+
/**
|
|
3165
|
+
* {@link LRUCache.OptionsBase.updateAgeOnHas}
|
|
3166
|
+
*/
|
|
3167
|
+
updateAgeOnHas;
|
|
3168
|
+
/**
|
|
3169
|
+
* {@link LRUCache.OptionsBase.allowStale}
|
|
3170
|
+
*/
|
|
3171
|
+
allowStale;
|
|
3172
|
+
/**
|
|
3173
|
+
* {@link LRUCache.OptionsBase.noDisposeOnSet}
|
|
3174
|
+
*/
|
|
3175
|
+
noDisposeOnSet;
|
|
3176
|
+
/**
|
|
3177
|
+
* {@link LRUCache.OptionsBase.noUpdateTTL}
|
|
3178
|
+
*/
|
|
3179
|
+
noUpdateTTL;
|
|
3180
|
+
/**
|
|
3181
|
+
* {@link LRUCache.OptionsBase.maxEntrySize}
|
|
3182
|
+
*/
|
|
3183
|
+
maxEntrySize;
|
|
3184
|
+
/**
|
|
3185
|
+
* {@link LRUCache.OptionsBase.sizeCalculation}
|
|
3186
|
+
*/
|
|
3187
|
+
sizeCalculation;
|
|
3188
|
+
/**
|
|
3189
|
+
* {@link LRUCache.OptionsBase.noDeleteOnFetchRejection}
|
|
3190
|
+
*/
|
|
3191
|
+
noDeleteOnFetchRejection;
|
|
3192
|
+
/**
|
|
3193
|
+
* {@link LRUCache.OptionsBase.noDeleteOnStaleGet}
|
|
3194
|
+
*/
|
|
3195
|
+
noDeleteOnStaleGet;
|
|
3196
|
+
/**
|
|
3197
|
+
* {@link LRUCache.OptionsBase.allowStaleOnFetchAbort}
|
|
3198
|
+
*/
|
|
3199
|
+
allowStaleOnFetchAbort;
|
|
3200
|
+
/**
|
|
3201
|
+
* {@link LRUCache.OptionsBase.allowStaleOnFetchRejection}
|
|
3202
|
+
*/
|
|
3203
|
+
allowStaleOnFetchRejection;
|
|
3204
|
+
/**
|
|
3205
|
+
* {@link LRUCache.OptionsBase.ignoreFetchAbort}
|
|
3206
|
+
*/
|
|
3207
|
+
ignoreFetchAbort;
|
|
3208
|
+
#size;
|
|
3209
|
+
#calculatedSize;
|
|
3210
|
+
#keyMap;
|
|
3211
|
+
#keyList;
|
|
3212
|
+
#valList;
|
|
3213
|
+
#next;
|
|
3214
|
+
#prev;
|
|
3215
|
+
#head;
|
|
3216
|
+
#tail;
|
|
3217
|
+
#free;
|
|
3218
|
+
#disposed;
|
|
3219
|
+
#sizes;
|
|
3220
|
+
#starts;
|
|
3221
|
+
#ttls;
|
|
3222
|
+
#hasDispose;
|
|
3223
|
+
#hasFetchMethod;
|
|
3224
|
+
#hasDisposeAfter;
|
|
3225
|
+
/**
|
|
3226
|
+
* Do not call this method unless you need to inspect the
|
|
3227
|
+
* inner workings of the cache. If anything returned by this
|
|
3228
|
+
* object is modified in any way, strange breakage may occur.
|
|
3229
|
+
*
|
|
3230
|
+
* These fields are private for a reason!
|
|
3231
|
+
*
|
|
3232
|
+
* @internal
|
|
3233
|
+
*/
|
|
3234
|
+
static unsafeExposeInternals(c) {
|
|
3235
|
+
return {
|
|
3236
|
+
starts: c.#starts,
|
|
3237
|
+
ttls: c.#ttls,
|
|
3238
|
+
sizes: c.#sizes,
|
|
3239
|
+
keyMap: c.#keyMap,
|
|
3240
|
+
keyList: c.#keyList,
|
|
3241
|
+
valList: c.#valList,
|
|
3242
|
+
next: c.#next,
|
|
3243
|
+
prev: c.#prev,
|
|
3244
|
+
get head() {
|
|
3245
|
+
return c.#head;
|
|
3246
|
+
},
|
|
3247
|
+
get tail() {
|
|
3248
|
+
return c.#tail;
|
|
3249
|
+
},
|
|
3250
|
+
free: c.#free,
|
|
3251
|
+
isBackgroundFetch: (p) => c.#isBackgroundFetch(p),
|
|
3252
|
+
backgroundFetch: (k, index, options, context) => c.#backgroundFetch(k, index, options, context),
|
|
3253
|
+
moveToTail: (index) => c.#moveToTail(index),
|
|
3254
|
+
indexes: (options) => c.#indexes(options),
|
|
3255
|
+
rindexes: (options) => c.#rindexes(options),
|
|
3256
|
+
isStale: (index) => c.#isStale(index)
|
|
3257
|
+
};
|
|
3258
|
+
}
|
|
3259
|
+
/**
|
|
3260
|
+
* {@link LRUCache.OptionsBase.max} (read-only)
|
|
3261
|
+
*/
|
|
3262
|
+
get max() {
|
|
3263
|
+
return this.#max;
|
|
3264
|
+
}
|
|
3265
|
+
/**
|
|
3266
|
+
* {@link LRUCache.OptionsBase.maxSize} (read-only)
|
|
3267
|
+
*/
|
|
3268
|
+
get maxSize() {
|
|
3269
|
+
return this.#maxSize;
|
|
3270
|
+
}
|
|
3271
|
+
/**
|
|
3272
|
+
* The total computed size of items in the cache (read-only)
|
|
3273
|
+
*/
|
|
3274
|
+
get calculatedSize() {
|
|
3275
|
+
return this.#calculatedSize;
|
|
3276
|
+
}
|
|
3277
|
+
/**
|
|
3278
|
+
* The number of items stored in the cache (read-only)
|
|
3279
|
+
*/
|
|
3280
|
+
get size() {
|
|
3281
|
+
return this.#size;
|
|
3282
|
+
}
|
|
3283
|
+
/**
|
|
3284
|
+
* {@link LRUCache.OptionsBase.fetchMethod} (read-only)
|
|
3285
|
+
*/
|
|
3286
|
+
get fetchMethod() {
|
|
3287
|
+
return this.#fetchMethod;
|
|
3288
|
+
}
|
|
3289
|
+
get memoMethod() {
|
|
3290
|
+
return this.#memoMethod;
|
|
3291
|
+
}
|
|
3292
|
+
/**
|
|
3293
|
+
* {@link LRUCache.OptionsBase.dispose} (read-only)
|
|
3294
|
+
*/
|
|
3295
|
+
get dispose() {
|
|
3296
|
+
return this.#dispose;
|
|
3297
|
+
}
|
|
3298
|
+
/**
|
|
3299
|
+
* {@link LRUCache.OptionsBase.disposeAfter} (read-only)
|
|
3300
|
+
*/
|
|
3301
|
+
get disposeAfter() {
|
|
3302
|
+
return this.#disposeAfter;
|
|
3303
|
+
}
|
|
3304
|
+
constructor(options) {
|
|
3305
|
+
const { max = 0, ttl, ttlResolution = 1, ttlAutopurge, updateAgeOnGet, updateAgeOnHas, allowStale, dispose, disposeAfter, noDisposeOnSet, noUpdateTTL, maxSize = 0, maxEntrySize = 0, sizeCalculation, fetchMethod, memoMethod, noDeleteOnFetchRejection, noDeleteOnStaleGet, allowStaleOnFetchRejection, allowStaleOnFetchAbort, ignoreFetchAbort } = options;
|
|
3306
|
+
if (max !== 0 && !isPosInt(max)) throw new TypeError("max option must be a nonnegative integer");
|
|
3307
|
+
const UintArray = max ? getUintArray(max) : Array;
|
|
3308
|
+
if (!UintArray) throw new Error("invalid max value: " + max);
|
|
3309
|
+
this.#max = max;
|
|
3310
|
+
this.#maxSize = maxSize;
|
|
3311
|
+
this.maxEntrySize = maxEntrySize || this.#maxSize;
|
|
3312
|
+
this.sizeCalculation = sizeCalculation;
|
|
3313
|
+
if (this.sizeCalculation) {
|
|
3314
|
+
if (!this.#maxSize && !this.maxEntrySize) throw new TypeError("cannot set sizeCalculation without setting maxSize or maxEntrySize");
|
|
3315
|
+
if (typeof this.sizeCalculation !== "function") throw new TypeError("sizeCalculation set to non-function");
|
|
3316
|
+
}
|
|
3317
|
+
if (memoMethod !== void 0 && typeof memoMethod !== "function") throw new TypeError("memoMethod must be a function if defined");
|
|
3318
|
+
this.#memoMethod = memoMethod;
|
|
3319
|
+
if (fetchMethod !== void 0 && typeof fetchMethod !== "function") throw new TypeError("fetchMethod must be a function if specified");
|
|
3320
|
+
this.#fetchMethod = fetchMethod;
|
|
3321
|
+
this.#hasFetchMethod = !!fetchMethod;
|
|
3322
|
+
this.#keyMap = new Map();
|
|
3323
|
+
this.#keyList = new Array(max).fill(void 0);
|
|
3324
|
+
this.#valList = new Array(max).fill(void 0);
|
|
3325
|
+
this.#next = new UintArray(max);
|
|
3326
|
+
this.#prev = new UintArray(max);
|
|
3327
|
+
this.#head = 0;
|
|
3328
|
+
this.#tail = 0;
|
|
3329
|
+
this.#free = Stack.create(max);
|
|
3330
|
+
this.#size = 0;
|
|
3331
|
+
this.#calculatedSize = 0;
|
|
3332
|
+
if (typeof dispose === "function") this.#dispose = dispose;
|
|
3333
|
+
if (typeof disposeAfter === "function") {
|
|
3334
|
+
this.#disposeAfter = disposeAfter;
|
|
3335
|
+
this.#disposed = [];
|
|
3336
|
+
} else {
|
|
3337
|
+
this.#disposeAfter = void 0;
|
|
3338
|
+
this.#disposed = void 0;
|
|
3339
|
+
}
|
|
3340
|
+
this.#hasDispose = !!this.#dispose;
|
|
3341
|
+
this.#hasDisposeAfter = !!this.#disposeAfter;
|
|
3342
|
+
this.noDisposeOnSet = !!noDisposeOnSet;
|
|
3343
|
+
this.noUpdateTTL = !!noUpdateTTL;
|
|
3344
|
+
this.noDeleteOnFetchRejection = !!noDeleteOnFetchRejection;
|
|
3345
|
+
this.allowStaleOnFetchRejection = !!allowStaleOnFetchRejection;
|
|
3346
|
+
this.allowStaleOnFetchAbort = !!allowStaleOnFetchAbort;
|
|
3347
|
+
this.ignoreFetchAbort = !!ignoreFetchAbort;
|
|
3348
|
+
if (this.maxEntrySize !== 0) {
|
|
3349
|
+
if (this.#maxSize !== 0) {
|
|
3350
|
+
if (!isPosInt(this.#maxSize)) throw new TypeError("maxSize must be a positive integer if specified");
|
|
3351
|
+
}
|
|
3352
|
+
if (!isPosInt(this.maxEntrySize)) throw new TypeError("maxEntrySize must be a positive integer if specified");
|
|
3353
|
+
this.#initializeSizeTracking();
|
|
3354
|
+
}
|
|
3355
|
+
this.allowStale = !!allowStale;
|
|
3356
|
+
this.noDeleteOnStaleGet = !!noDeleteOnStaleGet;
|
|
3357
|
+
this.updateAgeOnGet = !!updateAgeOnGet;
|
|
3358
|
+
this.updateAgeOnHas = !!updateAgeOnHas;
|
|
3359
|
+
this.ttlResolution = isPosInt(ttlResolution) || ttlResolution === 0 ? ttlResolution : 1;
|
|
3360
|
+
this.ttlAutopurge = !!ttlAutopurge;
|
|
3361
|
+
this.ttl = ttl || 0;
|
|
3362
|
+
if (this.ttl) {
|
|
3363
|
+
if (!isPosInt(this.ttl)) throw new TypeError("ttl must be a positive integer if specified");
|
|
3364
|
+
this.#initializeTTLTracking();
|
|
3365
|
+
}
|
|
3366
|
+
if (this.#max === 0 && this.ttl === 0 && this.#maxSize === 0) throw new TypeError("At least one of max, maxSize, or ttl is required");
|
|
3367
|
+
if (!this.ttlAutopurge && !this.#max && !this.#maxSize) {
|
|
3368
|
+
const code = "LRU_CACHE_UNBOUNDED";
|
|
3369
|
+
if (shouldWarn(code)) {
|
|
3370
|
+
warned.add(code);
|
|
3371
|
+
const msg = "TTL caching without ttlAutopurge, max, or maxSize can result in unbounded memory consumption.";
|
|
3372
|
+
emitWarning(msg, "UnboundedCacheWarning", code, LRUCache);
|
|
3373
|
+
}
|
|
3374
|
+
}
|
|
3375
|
+
}
|
|
3376
|
+
/**
|
|
3377
|
+
* Return the number of ms left in the item's TTL. If item is not in cache,
|
|
3378
|
+
* returns `0`. Returns `Infinity` if item is in cache without a defined TTL.
|
|
3379
|
+
*/
|
|
3380
|
+
getRemainingTTL(key) {
|
|
3381
|
+
return this.#keyMap.has(key) ? Infinity : 0;
|
|
3382
|
+
}
|
|
3383
|
+
#initializeTTLTracking() {
|
|
3384
|
+
const ttls = new ZeroArray(this.#max);
|
|
3385
|
+
const starts = new ZeroArray(this.#max);
|
|
3386
|
+
this.#ttls = ttls;
|
|
3387
|
+
this.#starts = starts;
|
|
3388
|
+
this.#setItemTTL = (index, ttl, start = perf.now()) => {
|
|
3389
|
+
starts[index] = ttl !== 0 ? start : 0;
|
|
3390
|
+
ttls[index] = ttl;
|
|
3391
|
+
if (ttl !== 0 && this.ttlAutopurge) {
|
|
3392
|
+
const t = setTimeout(() => {
|
|
3393
|
+
if (this.#isStale(index)) this.#delete(this.#keyList[index], "expire");
|
|
3394
|
+
}, ttl + 1);
|
|
3395
|
+
/* c8 ignore start */
|
|
3396
|
+
if (t.unref) t.unref();
|
|
3397
|
+
}
|
|
3398
|
+
};
|
|
3399
|
+
this.#updateItemAge = (index) => {
|
|
3400
|
+
starts[index] = ttls[index] !== 0 ? perf.now() : 0;
|
|
3401
|
+
};
|
|
3402
|
+
this.#statusTTL = (status, index) => {
|
|
3403
|
+
if (ttls[index]) {
|
|
3404
|
+
const ttl = ttls[index];
|
|
3405
|
+
const start = starts[index];
|
|
3406
|
+
/* c8 ignore next */
|
|
3407
|
+
if (!ttl || !start) return;
|
|
3408
|
+
status.ttl = ttl;
|
|
3409
|
+
status.start = start;
|
|
3410
|
+
status.now = cachedNow || getNow();
|
|
3411
|
+
const age = status.now - start;
|
|
3412
|
+
status.remainingTTL = ttl - age;
|
|
3413
|
+
}
|
|
3414
|
+
};
|
|
3415
|
+
let cachedNow = 0;
|
|
3416
|
+
const getNow = () => {
|
|
3417
|
+
const n = perf.now();
|
|
3418
|
+
if (this.ttlResolution > 0) {
|
|
3419
|
+
cachedNow = n;
|
|
3420
|
+
const t = setTimeout(() => cachedNow = 0, this.ttlResolution);
|
|
3421
|
+
/* c8 ignore start */
|
|
3422
|
+
if (t.unref) t.unref();
|
|
3423
|
+
}
|
|
3424
|
+
return n;
|
|
3425
|
+
};
|
|
3426
|
+
this.getRemainingTTL = (key) => {
|
|
3427
|
+
const index = this.#keyMap.get(key);
|
|
3428
|
+
if (index === void 0) return 0;
|
|
3429
|
+
const ttl = ttls[index];
|
|
3430
|
+
const start = starts[index];
|
|
3431
|
+
if (!ttl || !start) return Infinity;
|
|
3432
|
+
const age = (cachedNow || getNow()) - start;
|
|
3433
|
+
return ttl - age;
|
|
3434
|
+
};
|
|
3435
|
+
this.#isStale = (index) => {
|
|
3436
|
+
const s = starts[index];
|
|
3437
|
+
const t = ttls[index];
|
|
3438
|
+
return !!t && !!s && (cachedNow || getNow()) - s > t;
|
|
3439
|
+
};
|
|
3440
|
+
}
|
|
3441
|
+
#updateItemAge = () => {};
|
|
3442
|
+
#statusTTL = () => {};
|
|
3443
|
+
#setItemTTL = () => {};
|
|
3444
|
+
/* c8 ignore stop */
|
|
3445
|
+
#isStale = () => false;
|
|
3446
|
+
#initializeSizeTracking() {
|
|
3447
|
+
const sizes = new ZeroArray(this.#max);
|
|
3448
|
+
this.#calculatedSize = 0;
|
|
3449
|
+
this.#sizes = sizes;
|
|
3450
|
+
this.#removeItemSize = (index) => {
|
|
3451
|
+
this.#calculatedSize -= sizes[index];
|
|
3452
|
+
sizes[index] = 0;
|
|
3453
|
+
};
|
|
3454
|
+
this.#requireSize = (k, v, size, sizeCalculation) => {
|
|
3455
|
+
if (this.#isBackgroundFetch(v)) return 0;
|
|
3456
|
+
if (!isPosInt(size)) if (sizeCalculation) {
|
|
3457
|
+
if (typeof sizeCalculation !== "function") throw new TypeError("sizeCalculation must be a function");
|
|
3458
|
+
size = sizeCalculation(v, k);
|
|
3459
|
+
if (!isPosInt(size)) throw new TypeError("sizeCalculation return invalid (expect positive integer)");
|
|
3460
|
+
} else throw new TypeError("invalid size value (must be positive integer). When maxSize or maxEntrySize is used, sizeCalculation or size must be set.");
|
|
3461
|
+
return size;
|
|
3462
|
+
};
|
|
3463
|
+
this.#addItemSize = (index, size, status) => {
|
|
3464
|
+
sizes[index] = size;
|
|
3465
|
+
if (this.#maxSize) {
|
|
3466
|
+
const maxSize = this.#maxSize - sizes[index];
|
|
3467
|
+
while (this.#calculatedSize > maxSize) this.#evict(true);
|
|
3468
|
+
}
|
|
3469
|
+
this.#calculatedSize += sizes[index];
|
|
3470
|
+
if (status) {
|
|
3471
|
+
status.entrySize = size;
|
|
3472
|
+
status.totalCalculatedSize = this.#calculatedSize;
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3475
|
+
}
|
|
3476
|
+
#removeItemSize = (_i) => {};
|
|
3477
|
+
#addItemSize = (_i, _s, _st) => {};
|
|
3478
|
+
#requireSize = (_k, _v, size, sizeCalculation) => {
|
|
3479
|
+
if (size || sizeCalculation) throw new TypeError("cannot set size without setting maxSize or maxEntrySize on cache");
|
|
3480
|
+
return 0;
|
|
3481
|
+
};
|
|
3482
|
+
*#indexes({ allowStale = this.allowStale } = {}) {
|
|
3483
|
+
if (this.#size) for (let i = this.#tail;;) {
|
|
3484
|
+
if (!this.#isValidIndex(i)) break;
|
|
3485
|
+
if (allowStale || !this.#isStale(i)) yield i;
|
|
3486
|
+
if (i === this.#head) break;
|
|
3487
|
+
else i = this.#prev[i];
|
|
3488
|
+
}
|
|
3489
|
+
}
|
|
3490
|
+
*#rindexes({ allowStale = this.allowStale } = {}) {
|
|
3491
|
+
if (this.#size) for (let i = this.#head;;) {
|
|
3492
|
+
if (!this.#isValidIndex(i)) break;
|
|
3493
|
+
if (allowStale || !this.#isStale(i)) yield i;
|
|
3494
|
+
if (i === this.#tail) break;
|
|
3495
|
+
else i = this.#next[i];
|
|
3496
|
+
}
|
|
3497
|
+
}
|
|
3498
|
+
#isValidIndex(index) {
|
|
3499
|
+
return index !== void 0 && this.#keyMap.get(this.#keyList[index]) === index;
|
|
3500
|
+
}
|
|
3501
|
+
/**
|
|
3502
|
+
* Return a generator yielding `[key, value]` pairs,
|
|
3503
|
+
* in order from most recently used to least recently used.
|
|
3504
|
+
*/
|
|
3505
|
+
*entries() {
|
|
3506
|
+
for (const i of this.#indexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
|
|
3507
|
+
}
|
|
3508
|
+
/**
|
|
3509
|
+
* Inverse order version of {@link LRUCache.entries}
|
|
3510
|
+
*
|
|
3511
|
+
* Return a generator yielding `[key, value]` pairs,
|
|
3512
|
+
* in order from least recently used to most recently used.
|
|
3513
|
+
*/
|
|
3514
|
+
*rentries() {
|
|
3515
|
+
for (const i of this.#rindexes()) if (this.#valList[i] !== void 0 && this.#keyList[i] !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield [this.#keyList[i], this.#valList[i]];
|
|
3516
|
+
}
|
|
3517
|
+
/**
|
|
3518
|
+
* Return a generator yielding the keys in the cache,
|
|
3519
|
+
* in order from most recently used to least recently used.
|
|
3520
|
+
*/
|
|
3521
|
+
*keys() {
|
|
3522
|
+
for (const i of this.#indexes()) {
|
|
3523
|
+
const k = this.#keyList[i];
|
|
3524
|
+
if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
|
|
3525
|
+
}
|
|
3526
|
+
}
|
|
3527
|
+
/**
|
|
3528
|
+
* Inverse order version of {@link LRUCache.keys}
|
|
3529
|
+
*
|
|
3530
|
+
* Return a generator yielding the keys in the cache,
|
|
3531
|
+
* in order from least recently used to most recently used.
|
|
3532
|
+
*/
|
|
3533
|
+
*rkeys() {
|
|
3534
|
+
for (const i of this.#rindexes()) {
|
|
3535
|
+
const k = this.#keyList[i];
|
|
3536
|
+
if (k !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield k;
|
|
3537
|
+
}
|
|
3538
|
+
}
|
|
3539
|
+
/**
|
|
3540
|
+
* Return a generator yielding the values in the cache,
|
|
3541
|
+
* in order from most recently used to least recently used.
|
|
3542
|
+
*/
|
|
3543
|
+
*values() {
|
|
3544
|
+
for (const i of this.#indexes()) {
|
|
3545
|
+
const v = this.#valList[i];
|
|
3546
|
+
if (v !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
/**
|
|
3550
|
+
* Inverse order version of {@link LRUCache.values}
|
|
3551
|
+
*
|
|
3552
|
+
* Return a generator yielding the values in the cache,
|
|
3553
|
+
* in order from least recently used to most recently used.
|
|
3554
|
+
*/
|
|
3555
|
+
*rvalues() {
|
|
3556
|
+
for (const i of this.#rindexes()) {
|
|
3557
|
+
const v = this.#valList[i];
|
|
3558
|
+
if (v !== void 0 && !this.#isBackgroundFetch(this.#valList[i])) yield this.#valList[i];
|
|
3559
|
+
}
|
|
3560
|
+
}
|
|
3561
|
+
/**
|
|
3562
|
+
* Iterating over the cache itself yields the same results as
|
|
3563
|
+
* {@link LRUCache.entries}
|
|
3564
|
+
*/
|
|
3565
|
+
[Symbol.iterator]() {
|
|
3566
|
+
return this.entries();
|
|
3567
|
+
}
|
|
3568
|
+
/**
|
|
3569
|
+
* A String value that is used in the creation of the default string
|
|
3570
|
+
* description of an object. Called by the built-in method
|
|
3571
|
+
* `Object.prototype.toString`.
|
|
3572
|
+
*/
|
|
3573
|
+
[Symbol.toStringTag] = "LRUCache";
|
|
3574
|
+
/**
|
|
3575
|
+
* Find a value for which the supplied fn method returns a truthy value,
|
|
3576
|
+
* similar to `Array.find()`. fn is called as `fn(value, key, cache)`.
|
|
3577
|
+
*/
|
|
3578
|
+
find(fn, getOptions = {}) {
|
|
3579
|
+
for (const i of this.#indexes()) {
|
|
3580
|
+
const v = this.#valList[i];
|
|
3581
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3582
|
+
if (value === void 0) continue;
|
|
3583
|
+
if (fn(value, this.#keyList[i], this)) return this.get(this.#keyList[i], getOptions);
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
/**
|
|
3587
|
+
* Call the supplied function on each item in the cache, in order from most
|
|
3588
|
+
* recently used to least recently used.
|
|
3589
|
+
*
|
|
3590
|
+
* `fn` is called as `fn(value, key, cache)`.
|
|
3591
|
+
*
|
|
3592
|
+
* If `thisp` is provided, function will be called in the `this`-context of
|
|
3593
|
+
* the provided object, or the cache if no `thisp` object is provided.
|
|
3594
|
+
*
|
|
3595
|
+
* Does not update age or recenty of use, or iterate over stale values.
|
|
3596
|
+
*/
|
|
3597
|
+
forEach(fn, thisp = this) {
|
|
3598
|
+
for (const i of this.#indexes()) {
|
|
3599
|
+
const v = this.#valList[i];
|
|
3600
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3601
|
+
if (value === void 0) continue;
|
|
3602
|
+
fn.call(thisp, value, this.#keyList[i], this);
|
|
3603
|
+
}
|
|
3604
|
+
}
|
|
3605
|
+
/**
|
|
3606
|
+
* The same as {@link LRUCache.forEach} but items are iterated over in
|
|
3607
|
+
* reverse order. (ie, less recently used items are iterated over first.)
|
|
3608
|
+
*/
|
|
3609
|
+
rforEach(fn, thisp = this) {
|
|
3610
|
+
for (const i of this.#rindexes()) {
|
|
3611
|
+
const v = this.#valList[i];
|
|
3612
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3613
|
+
if (value === void 0) continue;
|
|
3614
|
+
fn.call(thisp, value, this.#keyList[i], this);
|
|
3615
|
+
}
|
|
3616
|
+
}
|
|
3617
|
+
/**
|
|
3618
|
+
* Delete any stale entries. Returns true if anything was removed,
|
|
3619
|
+
* false otherwise.
|
|
3620
|
+
*/
|
|
3621
|
+
purgeStale() {
|
|
3622
|
+
let deleted = false;
|
|
3623
|
+
for (const i of this.#rindexes({ allowStale: true })) if (this.#isStale(i)) {
|
|
3624
|
+
this.#delete(this.#keyList[i], "expire");
|
|
3625
|
+
deleted = true;
|
|
3626
|
+
}
|
|
3627
|
+
return deleted;
|
|
3628
|
+
}
|
|
3629
|
+
/**
|
|
3630
|
+
* Get the extended info about a given entry, to get its value, size, and
|
|
3631
|
+
* TTL info simultaneously. Returns `undefined` if the key is not present.
|
|
3632
|
+
*
|
|
3633
|
+
* Unlike {@link LRUCache#dump}, which is designed to be portable and survive
|
|
3634
|
+
* serialization, the `start` value is always the current timestamp, and the
|
|
3635
|
+
* `ttl` is a calculated remaining time to live (negative if expired).
|
|
3636
|
+
*
|
|
3637
|
+
* Always returns stale values, if their info is found in the cache, so be
|
|
3638
|
+
* sure to check for expirations (ie, a negative {@link LRUCache.Entry#ttl})
|
|
3639
|
+
* if relevant.
|
|
3640
|
+
*/
|
|
3641
|
+
info(key) {
|
|
3642
|
+
const i = this.#keyMap.get(key);
|
|
3643
|
+
if (i === void 0) return void 0;
|
|
3644
|
+
const v = this.#valList[i];
|
|
3645
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3646
|
+
if (value === void 0) return void 0;
|
|
3647
|
+
const entry = { value };
|
|
3648
|
+
if (this.#ttls && this.#starts) {
|
|
3649
|
+
const ttl = this.#ttls[i];
|
|
3650
|
+
const start = this.#starts[i];
|
|
3651
|
+
if (ttl && start) {
|
|
3652
|
+
const remain = ttl - (perf.now() - start);
|
|
3653
|
+
entry.ttl = remain;
|
|
3654
|
+
entry.start = Date.now();
|
|
3655
|
+
}
|
|
3656
|
+
}
|
|
3657
|
+
if (this.#sizes) entry.size = this.#sizes[i];
|
|
3658
|
+
return entry;
|
|
3659
|
+
}
|
|
3660
|
+
/**
|
|
3661
|
+
* Return an array of [key, {@link LRUCache.Entry}] tuples which can be
|
|
3662
|
+
* passed to {@link LRLUCache#load}.
|
|
3663
|
+
*
|
|
3664
|
+
* The `start` fields are calculated relative to a portable `Date.now()`
|
|
3665
|
+
* timestamp, even if `performance.now()` is available.
|
|
3666
|
+
*
|
|
3667
|
+
* Stale entries are always included in the `dump`, even if
|
|
3668
|
+
* {@link LRUCache.OptionsBase.allowStale} is false.
|
|
3669
|
+
*
|
|
3670
|
+
* Note: this returns an actual array, not a generator, so it can be more
|
|
3671
|
+
* easily passed around.
|
|
3672
|
+
*/
|
|
3673
|
+
dump() {
|
|
3674
|
+
const arr = [];
|
|
3675
|
+
for (const i of this.#indexes({ allowStale: true })) {
|
|
3676
|
+
const key = this.#keyList[i];
|
|
3677
|
+
const v = this.#valList[i];
|
|
3678
|
+
const value = this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3679
|
+
if (value === void 0 || key === void 0) continue;
|
|
3680
|
+
const entry = { value };
|
|
3681
|
+
if (this.#ttls && this.#starts) {
|
|
3682
|
+
entry.ttl = this.#ttls[i];
|
|
3683
|
+
const age = perf.now() - this.#starts[i];
|
|
3684
|
+
entry.start = Math.floor(Date.now() - age);
|
|
3685
|
+
}
|
|
3686
|
+
if (this.#sizes) entry.size = this.#sizes[i];
|
|
3687
|
+
arr.unshift([key, entry]);
|
|
3688
|
+
}
|
|
3689
|
+
return arr;
|
|
3690
|
+
}
|
|
3691
|
+
/**
|
|
3692
|
+
* Reset the cache and load in the items in entries in the order listed.
|
|
3693
|
+
*
|
|
3694
|
+
* The shape of the resulting cache may be different if the same options are
|
|
3695
|
+
* not used in both caches.
|
|
3696
|
+
*
|
|
3697
|
+
* The `start` fields are assumed to be calculated relative to a portable
|
|
3698
|
+
* `Date.now()` timestamp, even if `performance.now()` is available.
|
|
3699
|
+
*/
|
|
3700
|
+
load(arr) {
|
|
3701
|
+
this.clear();
|
|
3702
|
+
for (const [key, entry] of arr) {
|
|
3703
|
+
if (entry.start) {
|
|
3704
|
+
const age = Date.now() - entry.start;
|
|
3705
|
+
entry.start = perf.now() - age;
|
|
3706
|
+
}
|
|
3707
|
+
this.set(key, entry.value, entry);
|
|
3708
|
+
}
|
|
3709
|
+
}
|
|
3710
|
+
/**
|
|
3711
|
+
* Add a value to the cache.
|
|
3712
|
+
*
|
|
3713
|
+
* Note: if `undefined` is specified as a value, this is an alias for
|
|
3714
|
+
* {@link LRUCache#delete}
|
|
3715
|
+
*
|
|
3716
|
+
* Fields on the {@link LRUCache.SetOptions} options param will override
|
|
3717
|
+
* their corresponding values in the constructor options for the scope
|
|
3718
|
+
* of this single `set()` operation.
|
|
3719
|
+
*
|
|
3720
|
+
* If `start` is provided, then that will set the effective start
|
|
3721
|
+
* time for the TTL calculation. Note that this must be a previous
|
|
3722
|
+
* value of `performance.now()` if supported, or a previous value of
|
|
3723
|
+
* `Date.now()` if not.
|
|
3724
|
+
*
|
|
3725
|
+
* Options object may also include `size`, which will prevent
|
|
3726
|
+
* calling the `sizeCalculation` function and just use the specified
|
|
3727
|
+
* number if it is a positive integer, and `noDisposeOnSet` which
|
|
3728
|
+
* will prevent calling a `dispose` function in the case of
|
|
3729
|
+
* overwrites.
|
|
3730
|
+
*
|
|
3731
|
+
* If the `size` (or return value of `sizeCalculation`) for a given
|
|
3732
|
+
* entry is greater than `maxEntrySize`, then the item will not be
|
|
3733
|
+
* added to the cache.
|
|
3734
|
+
*
|
|
3735
|
+
* Will update the recency of the entry.
|
|
3736
|
+
*
|
|
3737
|
+
* If the value is `undefined`, then this is an alias for
|
|
3738
|
+
* `cache.delete(key)`. `undefined` is never stored in the cache.
|
|
3739
|
+
*/
|
|
3740
|
+
set(k, v, setOptions = {}) {
|
|
3741
|
+
if (v === void 0) {
|
|
3742
|
+
this.delete(k);
|
|
3743
|
+
return this;
|
|
3744
|
+
}
|
|
3745
|
+
const { ttl = this.ttl, start, noDisposeOnSet = this.noDisposeOnSet, sizeCalculation = this.sizeCalculation, status } = setOptions;
|
|
3746
|
+
let { noUpdateTTL = this.noUpdateTTL } = setOptions;
|
|
3747
|
+
const size = this.#requireSize(k, v, setOptions.size || 0, sizeCalculation);
|
|
3748
|
+
if (this.maxEntrySize && size > this.maxEntrySize) {
|
|
3749
|
+
if (status) {
|
|
3750
|
+
status.set = "miss";
|
|
3751
|
+
status.maxEntrySizeExceeded = true;
|
|
3752
|
+
}
|
|
3753
|
+
this.#delete(k, "set");
|
|
3754
|
+
return this;
|
|
3755
|
+
}
|
|
3756
|
+
let index = this.#size === 0 ? void 0 : this.#keyMap.get(k);
|
|
3757
|
+
if (index === void 0) {
|
|
3758
|
+
index = this.#size === 0 ? this.#tail : this.#free.length !== 0 ? this.#free.pop() : this.#size === this.#max ? this.#evict(false) : this.#size;
|
|
3759
|
+
this.#keyList[index] = k;
|
|
3760
|
+
this.#valList[index] = v;
|
|
3761
|
+
this.#keyMap.set(k, index);
|
|
3762
|
+
this.#next[this.#tail] = index;
|
|
3763
|
+
this.#prev[index] = this.#tail;
|
|
3764
|
+
this.#tail = index;
|
|
3765
|
+
this.#size++;
|
|
3766
|
+
this.#addItemSize(index, size, status);
|
|
3767
|
+
if (status) status.set = "add";
|
|
3768
|
+
noUpdateTTL = false;
|
|
3769
|
+
} else {
|
|
3770
|
+
this.#moveToTail(index);
|
|
3771
|
+
const oldVal = this.#valList[index];
|
|
3772
|
+
if (v !== oldVal) {
|
|
3773
|
+
if (this.#hasFetchMethod && this.#isBackgroundFetch(oldVal)) {
|
|
3774
|
+
oldVal.__abortController.abort(new Error("replaced"));
|
|
3775
|
+
const { __staleWhileFetching: s } = oldVal;
|
|
3776
|
+
if (s !== void 0 && !noDisposeOnSet) {
|
|
3777
|
+
if (this.#hasDispose) this.#dispose?.(s, k, "set");
|
|
3778
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
3779
|
+
s,
|
|
3780
|
+
k,
|
|
3781
|
+
"set"
|
|
3782
|
+
]);
|
|
3783
|
+
}
|
|
3784
|
+
} else if (!noDisposeOnSet) {
|
|
3785
|
+
if (this.#hasDispose) this.#dispose?.(oldVal, k, "set");
|
|
3786
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
3787
|
+
oldVal,
|
|
3788
|
+
k,
|
|
3789
|
+
"set"
|
|
3790
|
+
]);
|
|
3791
|
+
}
|
|
3792
|
+
this.#removeItemSize(index);
|
|
3793
|
+
this.#addItemSize(index, size, status);
|
|
3794
|
+
this.#valList[index] = v;
|
|
3795
|
+
if (status) {
|
|
3796
|
+
status.set = "replace";
|
|
3797
|
+
const oldValue = oldVal && this.#isBackgroundFetch(oldVal) ? oldVal.__staleWhileFetching : oldVal;
|
|
3798
|
+
if (oldValue !== void 0) status.oldValue = oldValue;
|
|
3799
|
+
}
|
|
3800
|
+
} else if (status) status.set = "update";
|
|
3801
|
+
}
|
|
3802
|
+
if (ttl !== 0 && !this.#ttls) this.#initializeTTLTracking();
|
|
3803
|
+
if (this.#ttls) {
|
|
3804
|
+
if (!noUpdateTTL) this.#setItemTTL(index, ttl, start);
|
|
3805
|
+
if (status) this.#statusTTL(status, index);
|
|
3806
|
+
}
|
|
3807
|
+
if (!noDisposeOnSet && this.#hasDisposeAfter && this.#disposed) {
|
|
3808
|
+
const dt = this.#disposed;
|
|
3809
|
+
let task;
|
|
3810
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
3811
|
+
}
|
|
3812
|
+
return this;
|
|
3813
|
+
}
|
|
3814
|
+
/**
|
|
3815
|
+
* Evict the least recently used item, returning its value or
|
|
3816
|
+
* `undefined` if cache is empty.
|
|
3817
|
+
*/
|
|
3818
|
+
pop() {
|
|
3819
|
+
try {
|
|
3820
|
+
while (this.#size) {
|
|
3821
|
+
const val = this.#valList[this.#head];
|
|
3822
|
+
this.#evict(true);
|
|
3823
|
+
if (this.#isBackgroundFetch(val)) {
|
|
3824
|
+
if (val.__staleWhileFetching) return val.__staleWhileFetching;
|
|
3825
|
+
} else if (val !== void 0) return val;
|
|
3826
|
+
}
|
|
3827
|
+
} finally {
|
|
3828
|
+
if (this.#hasDisposeAfter && this.#disposed) {
|
|
3829
|
+
const dt = this.#disposed;
|
|
3830
|
+
let task;
|
|
3831
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
3832
|
+
}
|
|
3833
|
+
}
|
|
3834
|
+
}
|
|
3835
|
+
#evict(free) {
|
|
3836
|
+
const head = this.#head;
|
|
3837
|
+
const k = this.#keyList[head];
|
|
3838
|
+
const v = this.#valList[head];
|
|
3839
|
+
if (this.#hasFetchMethod && this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("evicted"));
|
|
3840
|
+
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
|
3841
|
+
if (this.#hasDispose) this.#dispose?.(v, k, "evict");
|
|
3842
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
3843
|
+
v,
|
|
3844
|
+
k,
|
|
3845
|
+
"evict"
|
|
3846
|
+
]);
|
|
3847
|
+
}
|
|
3848
|
+
this.#removeItemSize(head);
|
|
3849
|
+
if (free) {
|
|
3850
|
+
this.#keyList[head] = void 0;
|
|
3851
|
+
this.#valList[head] = void 0;
|
|
3852
|
+
this.#free.push(head);
|
|
3853
|
+
}
|
|
3854
|
+
if (this.#size === 1) {
|
|
3855
|
+
this.#head = this.#tail = 0;
|
|
3856
|
+
this.#free.length = 0;
|
|
3857
|
+
} else this.#head = this.#next[head];
|
|
3858
|
+
this.#keyMap.delete(k);
|
|
3859
|
+
this.#size--;
|
|
3860
|
+
return head;
|
|
3861
|
+
}
|
|
3862
|
+
/**
|
|
3863
|
+
* Check if a key is in the cache, without updating the recency of use.
|
|
3864
|
+
* Will return false if the item is stale, even though it is technically
|
|
3865
|
+
* in the cache.
|
|
3866
|
+
*
|
|
3867
|
+
* Check if a key is in the cache, without updating the recency of
|
|
3868
|
+
* use. Age is updated if {@link LRUCache.OptionsBase.updateAgeOnHas} is set
|
|
3869
|
+
* to `true` in either the options or the constructor.
|
|
3870
|
+
*
|
|
3871
|
+
* Will return `false` if the item is stale, even though it is technically in
|
|
3872
|
+
* the cache. The difference can be determined (if it matters) by using a
|
|
3873
|
+
* `status` argument, and inspecting the `has` field.
|
|
3874
|
+
*
|
|
3875
|
+
* Will not update item age unless
|
|
3876
|
+
* {@link LRUCache.OptionsBase.updateAgeOnHas} is set.
|
|
3877
|
+
*/
|
|
3878
|
+
has(k, hasOptions = {}) {
|
|
3879
|
+
const { updateAgeOnHas = this.updateAgeOnHas, status } = hasOptions;
|
|
3880
|
+
const index = this.#keyMap.get(k);
|
|
3881
|
+
if (index !== void 0) {
|
|
3882
|
+
const v = this.#valList[index];
|
|
3883
|
+
if (this.#isBackgroundFetch(v) && v.__staleWhileFetching === void 0) return false;
|
|
3884
|
+
if (!this.#isStale(index)) {
|
|
3885
|
+
if (updateAgeOnHas) this.#updateItemAge(index);
|
|
3886
|
+
if (status) {
|
|
3887
|
+
status.has = "hit";
|
|
3888
|
+
this.#statusTTL(status, index);
|
|
3889
|
+
}
|
|
3890
|
+
return true;
|
|
3891
|
+
} else if (status) {
|
|
3892
|
+
status.has = "stale";
|
|
3893
|
+
this.#statusTTL(status, index);
|
|
3894
|
+
}
|
|
3895
|
+
} else if (status) status.has = "miss";
|
|
3896
|
+
return false;
|
|
3897
|
+
}
|
|
3898
|
+
/**
|
|
3899
|
+
* Like {@link LRUCache#get} but doesn't update recency or delete stale
|
|
3900
|
+
* items.
|
|
3901
|
+
*
|
|
3902
|
+
* Returns `undefined` if the item is stale, unless
|
|
3903
|
+
* {@link LRUCache.OptionsBase.allowStale} is set.
|
|
3904
|
+
*/
|
|
3905
|
+
peek(k, peekOptions = {}) {
|
|
3906
|
+
const { allowStale = this.allowStale } = peekOptions;
|
|
3907
|
+
const index = this.#keyMap.get(k);
|
|
3908
|
+
if (index === void 0 || !allowStale && this.#isStale(index)) return;
|
|
3909
|
+
const v = this.#valList[index];
|
|
3910
|
+
return this.#isBackgroundFetch(v) ? v.__staleWhileFetching : v;
|
|
3911
|
+
}
|
|
3912
|
+
#backgroundFetch(k, index, options, context) {
|
|
3913
|
+
const v = index === void 0 ? void 0 : this.#valList[index];
|
|
3914
|
+
if (this.#isBackgroundFetch(v)) return v;
|
|
3915
|
+
const ac = new AC();
|
|
3916
|
+
const { signal } = options;
|
|
3917
|
+
signal?.addEventListener("abort", () => ac.abort(signal.reason), { signal: ac.signal });
|
|
3918
|
+
const fetchOpts = {
|
|
3919
|
+
signal: ac.signal,
|
|
3920
|
+
options,
|
|
3921
|
+
context
|
|
3922
|
+
};
|
|
3923
|
+
const cb = (v$1, updateCache = false) => {
|
|
3924
|
+
const { aborted } = ac.signal;
|
|
3925
|
+
const ignoreAbort = options.ignoreFetchAbort && v$1 !== void 0;
|
|
3926
|
+
if (options.status) if (aborted && !updateCache) {
|
|
3927
|
+
options.status.fetchAborted = true;
|
|
3928
|
+
options.status.fetchError = ac.signal.reason;
|
|
3929
|
+
if (ignoreAbort) options.status.fetchAbortIgnored = true;
|
|
3930
|
+
} else options.status.fetchResolved = true;
|
|
3931
|
+
if (aborted && !ignoreAbort && !updateCache) return fetchFail(ac.signal.reason);
|
|
3932
|
+
const bf$1 = p;
|
|
3933
|
+
if (this.#valList[index] === p) if (v$1 === void 0) if (bf$1.__staleWhileFetching) this.#valList[index] = bf$1.__staleWhileFetching;
|
|
3934
|
+
else this.#delete(k, "fetch");
|
|
3935
|
+
else {
|
|
3936
|
+
if (options.status) options.status.fetchUpdated = true;
|
|
3937
|
+
this.set(k, v$1, fetchOpts.options);
|
|
3938
|
+
}
|
|
3939
|
+
return v$1;
|
|
3940
|
+
};
|
|
3941
|
+
const eb = (er) => {
|
|
3942
|
+
if (options.status) {
|
|
3943
|
+
options.status.fetchRejected = true;
|
|
3944
|
+
options.status.fetchError = er;
|
|
3945
|
+
}
|
|
3946
|
+
return fetchFail(er);
|
|
3947
|
+
};
|
|
3948
|
+
const fetchFail = (er) => {
|
|
3949
|
+
const { aborted } = ac.signal;
|
|
3950
|
+
const allowStaleAborted = aborted && options.allowStaleOnFetchAbort;
|
|
3951
|
+
const allowStale = allowStaleAborted || options.allowStaleOnFetchRejection;
|
|
3952
|
+
const noDelete = allowStale || options.noDeleteOnFetchRejection;
|
|
3953
|
+
const bf$1 = p;
|
|
3954
|
+
if (this.#valList[index] === p) {
|
|
3955
|
+
const del = !noDelete || bf$1.__staleWhileFetching === void 0;
|
|
3956
|
+
if (del) this.#delete(k, "fetch");
|
|
3957
|
+
else if (!allowStaleAborted) this.#valList[index] = bf$1.__staleWhileFetching;
|
|
3958
|
+
}
|
|
3959
|
+
if (allowStale) {
|
|
3960
|
+
if (options.status && bf$1.__staleWhileFetching !== void 0) options.status.returnedStale = true;
|
|
3961
|
+
return bf$1.__staleWhileFetching;
|
|
3962
|
+
} else if (bf$1.__returned === bf$1) throw er;
|
|
3963
|
+
};
|
|
3964
|
+
const pcall = (res, rej) => {
|
|
3965
|
+
const fmp = this.#fetchMethod?.(k, v, fetchOpts);
|
|
3966
|
+
if (fmp && fmp instanceof Promise) fmp.then((v$1) => res(v$1 === void 0 ? void 0 : v$1), rej);
|
|
3967
|
+
ac.signal.addEventListener("abort", () => {
|
|
3968
|
+
if (!options.ignoreFetchAbort || options.allowStaleOnFetchAbort) {
|
|
3969
|
+
res(void 0);
|
|
3970
|
+
if (options.allowStaleOnFetchAbort) res = (v$1) => cb(v$1, true);
|
|
3971
|
+
}
|
|
3972
|
+
});
|
|
3973
|
+
};
|
|
3974
|
+
if (options.status) options.status.fetchDispatched = true;
|
|
3975
|
+
const p = new Promise(pcall).then(cb, eb);
|
|
3976
|
+
const bf = Object.assign(p, {
|
|
3977
|
+
__abortController: ac,
|
|
3978
|
+
__staleWhileFetching: v,
|
|
3979
|
+
__returned: void 0
|
|
3980
|
+
});
|
|
3981
|
+
if (index === void 0) {
|
|
3982
|
+
this.set(k, bf, {
|
|
3983
|
+
...fetchOpts.options,
|
|
3984
|
+
status: void 0
|
|
3985
|
+
});
|
|
3986
|
+
index = this.#keyMap.get(k);
|
|
3987
|
+
} else this.#valList[index] = bf;
|
|
3988
|
+
return bf;
|
|
3989
|
+
}
|
|
3990
|
+
#isBackgroundFetch(p) {
|
|
3991
|
+
if (!this.#hasFetchMethod) return false;
|
|
3992
|
+
const b = p;
|
|
3993
|
+
return !!b && b instanceof Promise && b.hasOwnProperty("__staleWhileFetching") && b.__abortController instanceof AC;
|
|
3994
|
+
}
|
|
3995
|
+
async fetch(k, fetchOptions = {}) {
|
|
3996
|
+
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, ttl = this.ttl, noDisposeOnSet = this.noDisposeOnSet, size = 0, sizeCalculation = this.sizeCalculation, noUpdateTTL = this.noUpdateTTL, noDeleteOnFetchRejection = this.noDeleteOnFetchRejection, allowStaleOnFetchRejection = this.allowStaleOnFetchRejection, ignoreFetchAbort = this.ignoreFetchAbort, allowStaleOnFetchAbort = this.allowStaleOnFetchAbort, context, forceRefresh = false, status, signal } = fetchOptions;
|
|
3997
|
+
if (!this.#hasFetchMethod) {
|
|
3998
|
+
if (status) status.fetch = "get";
|
|
3999
|
+
return this.get(k, {
|
|
4000
|
+
allowStale,
|
|
4001
|
+
updateAgeOnGet,
|
|
4002
|
+
noDeleteOnStaleGet,
|
|
4003
|
+
status
|
|
4004
|
+
});
|
|
4005
|
+
}
|
|
4006
|
+
const options = {
|
|
4007
|
+
allowStale,
|
|
4008
|
+
updateAgeOnGet,
|
|
4009
|
+
noDeleteOnStaleGet,
|
|
4010
|
+
ttl,
|
|
4011
|
+
noDisposeOnSet,
|
|
4012
|
+
size,
|
|
4013
|
+
sizeCalculation,
|
|
4014
|
+
noUpdateTTL,
|
|
4015
|
+
noDeleteOnFetchRejection,
|
|
4016
|
+
allowStaleOnFetchRejection,
|
|
4017
|
+
allowStaleOnFetchAbort,
|
|
4018
|
+
ignoreFetchAbort,
|
|
4019
|
+
status,
|
|
4020
|
+
signal
|
|
4021
|
+
};
|
|
4022
|
+
let index = this.#keyMap.get(k);
|
|
4023
|
+
if (index === void 0) {
|
|
4024
|
+
if (status) status.fetch = "miss";
|
|
4025
|
+
const p = this.#backgroundFetch(k, index, options, context);
|
|
4026
|
+
return p.__returned = p;
|
|
4027
|
+
} else {
|
|
4028
|
+
const v = this.#valList[index];
|
|
4029
|
+
if (this.#isBackgroundFetch(v)) {
|
|
4030
|
+
const stale = allowStale && v.__staleWhileFetching !== void 0;
|
|
4031
|
+
if (status) {
|
|
4032
|
+
status.fetch = "inflight";
|
|
4033
|
+
if (stale) status.returnedStale = true;
|
|
4034
|
+
}
|
|
4035
|
+
return stale ? v.__staleWhileFetching : v.__returned = v;
|
|
4036
|
+
}
|
|
4037
|
+
const isStale = this.#isStale(index);
|
|
4038
|
+
if (!forceRefresh && !isStale) {
|
|
4039
|
+
if (status) status.fetch = "hit";
|
|
4040
|
+
this.#moveToTail(index);
|
|
4041
|
+
if (updateAgeOnGet) this.#updateItemAge(index);
|
|
4042
|
+
if (status) this.#statusTTL(status, index);
|
|
4043
|
+
return v;
|
|
4044
|
+
}
|
|
4045
|
+
const p = this.#backgroundFetch(k, index, options, context);
|
|
4046
|
+
const hasStale = p.__staleWhileFetching !== void 0;
|
|
4047
|
+
const staleVal = hasStale && allowStale;
|
|
4048
|
+
if (status) {
|
|
4049
|
+
status.fetch = isStale ? "stale" : "refresh";
|
|
4050
|
+
if (staleVal && isStale) status.returnedStale = true;
|
|
4051
|
+
}
|
|
4052
|
+
return staleVal ? p.__staleWhileFetching : p.__returned = p;
|
|
4053
|
+
}
|
|
4054
|
+
}
|
|
4055
|
+
async forceFetch(k, fetchOptions = {}) {
|
|
4056
|
+
const v = await this.fetch(k, fetchOptions);
|
|
4057
|
+
if (v === void 0) throw new Error("fetch() returned undefined");
|
|
4058
|
+
return v;
|
|
4059
|
+
}
|
|
4060
|
+
memo(k, memoOptions = {}) {
|
|
4061
|
+
const memoMethod = this.#memoMethod;
|
|
4062
|
+
if (!memoMethod) throw new Error("no memoMethod provided to constructor");
|
|
4063
|
+
const { context, forceRefresh,...options } = memoOptions;
|
|
4064
|
+
const v = this.get(k, options);
|
|
4065
|
+
if (!forceRefresh && v !== void 0) return v;
|
|
4066
|
+
const vv = memoMethod(k, v, {
|
|
4067
|
+
options,
|
|
4068
|
+
context
|
|
4069
|
+
});
|
|
4070
|
+
this.set(k, vv, options);
|
|
4071
|
+
return vv;
|
|
4072
|
+
}
|
|
4073
|
+
/**
|
|
4074
|
+
* Return a value from the cache. Will update the recency of the cache
|
|
4075
|
+
* entry found.
|
|
4076
|
+
*
|
|
4077
|
+
* If the key is not found, get() will return `undefined`.
|
|
4078
|
+
*/
|
|
4079
|
+
get(k, getOptions = {}) {
|
|
4080
|
+
const { allowStale = this.allowStale, updateAgeOnGet = this.updateAgeOnGet, noDeleteOnStaleGet = this.noDeleteOnStaleGet, status } = getOptions;
|
|
4081
|
+
const index = this.#keyMap.get(k);
|
|
4082
|
+
if (index !== void 0) {
|
|
4083
|
+
const value = this.#valList[index];
|
|
4084
|
+
const fetching = this.#isBackgroundFetch(value);
|
|
4085
|
+
if (status) this.#statusTTL(status, index);
|
|
4086
|
+
if (this.#isStale(index)) {
|
|
4087
|
+
if (status) status.get = "stale";
|
|
4088
|
+
if (!fetching) {
|
|
4089
|
+
if (!noDeleteOnStaleGet) this.#delete(k, "expire");
|
|
4090
|
+
if (status && allowStale) status.returnedStale = true;
|
|
4091
|
+
return allowStale ? value : void 0;
|
|
4092
|
+
} else {
|
|
4093
|
+
if (status && allowStale && value.__staleWhileFetching !== void 0) status.returnedStale = true;
|
|
4094
|
+
return allowStale ? value.__staleWhileFetching : void 0;
|
|
4095
|
+
}
|
|
4096
|
+
} else {
|
|
4097
|
+
if (status) status.get = "hit";
|
|
4098
|
+
if (fetching) return value.__staleWhileFetching;
|
|
4099
|
+
this.#moveToTail(index);
|
|
4100
|
+
if (updateAgeOnGet) this.#updateItemAge(index);
|
|
4101
|
+
return value;
|
|
4102
|
+
}
|
|
4103
|
+
} else if (status) status.get = "miss";
|
|
4104
|
+
}
|
|
4105
|
+
#connect(p, n) {
|
|
4106
|
+
this.#prev[n] = p;
|
|
4107
|
+
this.#next[p] = n;
|
|
4108
|
+
}
|
|
4109
|
+
#moveToTail(index) {
|
|
4110
|
+
if (index !== this.#tail) {
|
|
4111
|
+
if (index === this.#head) this.#head = this.#next[index];
|
|
4112
|
+
else this.#connect(this.#prev[index], this.#next[index]);
|
|
4113
|
+
this.#connect(this.#tail, index);
|
|
4114
|
+
this.#tail = index;
|
|
4115
|
+
}
|
|
4116
|
+
}
|
|
4117
|
+
/**
|
|
4118
|
+
* Deletes a key out of the cache.
|
|
4119
|
+
*
|
|
4120
|
+
* Returns true if the key was deleted, false otherwise.
|
|
4121
|
+
*/
|
|
4122
|
+
delete(k) {
|
|
4123
|
+
return this.#delete(k, "delete");
|
|
4124
|
+
}
|
|
4125
|
+
#delete(k, reason) {
|
|
4126
|
+
let deleted = false;
|
|
4127
|
+
if (this.#size !== 0) {
|
|
4128
|
+
const index = this.#keyMap.get(k);
|
|
4129
|
+
if (index !== void 0) {
|
|
4130
|
+
deleted = true;
|
|
4131
|
+
if (this.#size === 1) this.#clear(reason);
|
|
4132
|
+
else {
|
|
4133
|
+
this.#removeItemSize(index);
|
|
4134
|
+
const v = this.#valList[index];
|
|
4135
|
+
if (this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("deleted"));
|
|
4136
|
+
else if (this.#hasDispose || this.#hasDisposeAfter) {
|
|
4137
|
+
if (this.#hasDispose) this.#dispose?.(v, k, reason);
|
|
4138
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
4139
|
+
v,
|
|
4140
|
+
k,
|
|
4141
|
+
reason
|
|
4142
|
+
]);
|
|
4143
|
+
}
|
|
4144
|
+
this.#keyMap.delete(k);
|
|
4145
|
+
this.#keyList[index] = void 0;
|
|
4146
|
+
this.#valList[index] = void 0;
|
|
4147
|
+
if (index === this.#tail) this.#tail = this.#prev[index];
|
|
4148
|
+
else if (index === this.#head) this.#head = this.#next[index];
|
|
4149
|
+
else {
|
|
4150
|
+
const pi = this.#prev[index];
|
|
4151
|
+
this.#next[pi] = this.#next[index];
|
|
4152
|
+
const ni = this.#next[index];
|
|
4153
|
+
this.#prev[ni] = this.#prev[index];
|
|
4154
|
+
}
|
|
4155
|
+
this.#size--;
|
|
4156
|
+
this.#free.push(index);
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
}
|
|
4160
|
+
if (this.#hasDisposeAfter && this.#disposed?.length) {
|
|
4161
|
+
const dt = this.#disposed;
|
|
4162
|
+
let task;
|
|
4163
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
4164
|
+
}
|
|
4165
|
+
return deleted;
|
|
4166
|
+
}
|
|
4167
|
+
/**
|
|
4168
|
+
* Clear the cache entirely, throwing away all values.
|
|
4169
|
+
*/
|
|
4170
|
+
clear() {
|
|
4171
|
+
return this.#clear("delete");
|
|
4172
|
+
}
|
|
4173
|
+
#clear(reason) {
|
|
4174
|
+
for (const index of this.#rindexes({ allowStale: true })) {
|
|
4175
|
+
const v = this.#valList[index];
|
|
4176
|
+
if (this.#isBackgroundFetch(v)) v.__abortController.abort(new Error("deleted"));
|
|
4177
|
+
else {
|
|
4178
|
+
const k = this.#keyList[index];
|
|
4179
|
+
if (this.#hasDispose) this.#dispose?.(v, k, reason);
|
|
4180
|
+
if (this.#hasDisposeAfter) this.#disposed?.push([
|
|
4181
|
+
v,
|
|
4182
|
+
k,
|
|
4183
|
+
reason
|
|
4184
|
+
]);
|
|
4185
|
+
}
|
|
4186
|
+
}
|
|
4187
|
+
this.#keyMap.clear();
|
|
4188
|
+
this.#valList.fill(void 0);
|
|
4189
|
+
this.#keyList.fill(void 0);
|
|
4190
|
+
if (this.#ttls && this.#starts) {
|
|
4191
|
+
this.#ttls.fill(0);
|
|
4192
|
+
this.#starts.fill(0);
|
|
4193
|
+
}
|
|
4194
|
+
if (this.#sizes) this.#sizes.fill(0);
|
|
4195
|
+
this.#head = 0;
|
|
4196
|
+
this.#tail = 0;
|
|
4197
|
+
this.#free.length = 0;
|
|
4198
|
+
this.#calculatedSize = 0;
|
|
4199
|
+
this.#size = 0;
|
|
4200
|
+
if (this.#hasDisposeAfter && this.#disposed) {
|
|
4201
|
+
const dt = this.#disposed;
|
|
4202
|
+
let task;
|
|
4203
|
+
while (task = dt?.shift()) this.#disposeAfter?.(...task);
|
|
4204
|
+
}
|
|
4205
|
+
}
|
|
4206
|
+
};
|
|
4207
|
+
|
|
4208
|
+
//#endregion
|
|
4209
|
+
//#region node_modules/path-scurry/dist/esm/index.js
|
|
4210
|
+
const realpathSync$2 = realpathSync$1.native;
|
|
4211
|
+
const defaultFS = {
|
|
4212
|
+
lstatSync,
|
|
4213
|
+
readdir: readdir$2,
|
|
4214
|
+
readdirSync: readdirSync$1,
|
|
4215
|
+
readlinkSync,
|
|
4216
|
+
realpathSync: realpathSync$2,
|
|
4217
|
+
promises: {
|
|
4218
|
+
lstat,
|
|
4219
|
+
readdir: readdir$1,
|
|
4220
|
+
readlink,
|
|
4221
|
+
realpath
|
|
4222
|
+
}
|
|
4223
|
+
};
|
|
4224
|
+
const fsFromOption = (fsOption) => !fsOption || fsOption === defaultFS || fsOption === actualFS ? defaultFS : {
|
|
4225
|
+
...defaultFS,
|
|
4226
|
+
...fsOption,
|
|
4227
|
+
promises: {
|
|
4228
|
+
...defaultFS.promises,
|
|
4229
|
+
...fsOption.promises || {}
|
|
4230
|
+
}
|
|
4231
|
+
};
|
|
4232
|
+
const uncDriveRegexp = /^\\\\\?\\([a-z]:)\\?$/i;
|
|
4233
|
+
const uncToDrive = (rootPath) => rootPath.replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
|
|
4234
|
+
const eitherSep = /[\\\/]/;
|
|
4235
|
+
const UNKNOWN = 0;
|
|
4236
|
+
const IFIFO = 1;
|
|
4237
|
+
const IFCHR = 2;
|
|
4238
|
+
const IFDIR = 4;
|
|
4239
|
+
const IFBLK = 6;
|
|
4240
|
+
const IFREG = 8;
|
|
4241
|
+
const IFLNK = 10;
|
|
4242
|
+
const IFSOCK = 12;
|
|
4243
|
+
const IFMT = 15;
|
|
4244
|
+
const IFMT_UNKNOWN = ~IFMT;
|
|
4245
|
+
const READDIR_CALLED = 16;
|
|
4246
|
+
const LSTAT_CALLED = 32;
|
|
4247
|
+
const ENOTDIR = 64;
|
|
4248
|
+
const ENOENT = 128;
|
|
4249
|
+
const ENOREADLINK = 256;
|
|
4250
|
+
const ENOREALPATH = 512;
|
|
4251
|
+
const ENOCHILD = ENOTDIR | ENOENT | ENOREALPATH;
|
|
4252
|
+
const TYPEMASK = 1023;
|
|
4253
|
+
const entToType = (s) => s.isFile() ? IFREG : s.isDirectory() ? IFDIR : s.isSymbolicLink() ? IFLNK : s.isCharacterDevice() ? IFCHR : s.isBlockDevice() ? IFBLK : s.isSocket() ? IFSOCK : s.isFIFO() ? IFIFO : UNKNOWN;
|
|
4254
|
+
const normalizeCache = new Map();
|
|
4255
|
+
const normalize = (s) => {
|
|
4256
|
+
const c = normalizeCache.get(s);
|
|
4257
|
+
if (c) return c;
|
|
4258
|
+
const n = s.normalize("NFKD");
|
|
4259
|
+
normalizeCache.set(s, n);
|
|
4260
|
+
return n;
|
|
4261
|
+
};
|
|
4262
|
+
const normalizeNocaseCache = new Map();
|
|
4263
|
+
const normalizeNocase = (s) => {
|
|
4264
|
+
const c = normalizeNocaseCache.get(s);
|
|
4265
|
+
if (c) return c;
|
|
4266
|
+
const n = normalize(s.toLowerCase());
|
|
4267
|
+
normalizeNocaseCache.set(s, n);
|
|
4268
|
+
return n;
|
|
4269
|
+
};
|
|
4270
|
+
/**
|
|
4271
|
+
* An LRUCache for storing resolved path strings or Path objects.
|
|
4272
|
+
* @internal
|
|
4273
|
+
*/
|
|
4274
|
+
var ResolveCache = class extends LRUCache {
|
|
4275
|
+
constructor() {
|
|
4276
|
+
super({ max: 256 });
|
|
4277
|
+
}
|
|
4278
|
+
};
|
|
4279
|
+
/**
|
|
4280
|
+
* an LRUCache for storing child entries.
|
|
4281
|
+
* @internal
|
|
4282
|
+
*/
|
|
4283
|
+
var ChildrenCache = class extends LRUCache {
|
|
4284
|
+
constructor(maxSize = 16 * 1024) {
|
|
4285
|
+
super({
|
|
4286
|
+
maxSize,
|
|
4287
|
+
sizeCalculation: (a) => a.length + 1
|
|
4288
|
+
});
|
|
4289
|
+
}
|
|
4290
|
+
};
|
|
4291
|
+
const setAsCwd = Symbol("PathScurry setAsCwd");
|
|
4292
|
+
/**
|
|
4293
|
+
* Path objects are sort of like a super-powered
|
|
4294
|
+
* {@link https://nodejs.org/docs/latest/api/fs.html#class-fsdirent fs.Dirent}
|
|
4295
|
+
*
|
|
4296
|
+
* Each one represents a single filesystem entry on disk, which may or may not
|
|
4297
|
+
* exist. It includes methods for reading various types of information via
|
|
4298
|
+
* lstat, readlink, and readdir, and caches all information to the greatest
|
|
4299
|
+
* degree possible.
|
|
4300
|
+
*
|
|
4301
|
+
* Note that fs operations that would normally throw will instead return an
|
|
4302
|
+
* "empty" value. This is in order to prevent excessive overhead from error
|
|
4303
|
+
* stack traces.
|
|
4304
|
+
*/
|
|
4305
|
+
var PathBase = class {
|
|
4306
|
+
/**
|
|
4307
|
+
* the basename of this path
|
|
4308
|
+
*
|
|
4309
|
+
* **Important**: *always* test the path name against any test string
|
|
4310
|
+
* usingthe {@link isNamed} method, and not by directly comparing this
|
|
4311
|
+
* string. Otherwise, unicode path strings that the system sees as identical
|
|
4312
|
+
* will not be properly treated as the same path, leading to incorrect
|
|
4313
|
+
* behavior and possible security issues.
|
|
4314
|
+
*/
|
|
4315
|
+
name;
|
|
4316
|
+
/**
|
|
4317
|
+
* the Path entry corresponding to the path root.
|
|
4318
|
+
*
|
|
4319
|
+
* @internal
|
|
4320
|
+
*/
|
|
4321
|
+
root;
|
|
4322
|
+
/**
|
|
4323
|
+
* All roots found within the current PathScurry family
|
|
4324
|
+
*
|
|
4325
|
+
* @internal
|
|
4326
|
+
*/
|
|
4327
|
+
roots;
|
|
4328
|
+
/**
|
|
4329
|
+
* a reference to the parent path, or undefined in the case of root entries
|
|
4330
|
+
*
|
|
4331
|
+
* @internal
|
|
4332
|
+
*/
|
|
4333
|
+
parent;
|
|
4334
|
+
/**
|
|
4335
|
+
* boolean indicating whether paths are compared case-insensitively
|
|
4336
|
+
* @internal
|
|
4337
|
+
*/
|
|
4338
|
+
nocase;
|
|
4339
|
+
/**
|
|
4340
|
+
* boolean indicating that this path is the current working directory
|
|
4341
|
+
* of the PathScurry collection that contains it.
|
|
4342
|
+
*/
|
|
4343
|
+
isCWD = false;
|
|
4344
|
+
#fs;
|
|
4345
|
+
#dev;
|
|
4346
|
+
get dev() {
|
|
4347
|
+
return this.#dev;
|
|
4348
|
+
}
|
|
4349
|
+
#mode;
|
|
4350
|
+
get mode() {
|
|
4351
|
+
return this.#mode;
|
|
4352
|
+
}
|
|
4353
|
+
#nlink;
|
|
4354
|
+
get nlink() {
|
|
4355
|
+
return this.#nlink;
|
|
4356
|
+
}
|
|
4357
|
+
#uid;
|
|
4358
|
+
get uid() {
|
|
4359
|
+
return this.#uid;
|
|
4360
|
+
}
|
|
4361
|
+
#gid;
|
|
4362
|
+
get gid() {
|
|
4363
|
+
return this.#gid;
|
|
4364
|
+
}
|
|
4365
|
+
#rdev;
|
|
4366
|
+
get rdev() {
|
|
4367
|
+
return this.#rdev;
|
|
4368
|
+
}
|
|
4369
|
+
#blksize;
|
|
4370
|
+
get blksize() {
|
|
4371
|
+
return this.#blksize;
|
|
4372
|
+
}
|
|
4373
|
+
#ino;
|
|
4374
|
+
get ino() {
|
|
4375
|
+
return this.#ino;
|
|
4376
|
+
}
|
|
4377
|
+
#size;
|
|
4378
|
+
get size() {
|
|
4379
|
+
return this.#size;
|
|
4380
|
+
}
|
|
4381
|
+
#blocks;
|
|
4382
|
+
get blocks() {
|
|
4383
|
+
return this.#blocks;
|
|
4384
|
+
}
|
|
4385
|
+
#atimeMs;
|
|
4386
|
+
get atimeMs() {
|
|
4387
|
+
return this.#atimeMs;
|
|
4388
|
+
}
|
|
4389
|
+
#mtimeMs;
|
|
4390
|
+
get mtimeMs() {
|
|
4391
|
+
return this.#mtimeMs;
|
|
4392
|
+
}
|
|
4393
|
+
#ctimeMs;
|
|
4394
|
+
get ctimeMs() {
|
|
4395
|
+
return this.#ctimeMs;
|
|
4396
|
+
}
|
|
4397
|
+
#birthtimeMs;
|
|
4398
|
+
get birthtimeMs() {
|
|
4399
|
+
return this.#birthtimeMs;
|
|
4400
|
+
}
|
|
4401
|
+
#atime;
|
|
4402
|
+
get atime() {
|
|
4403
|
+
return this.#atime;
|
|
4404
|
+
}
|
|
4405
|
+
#mtime;
|
|
4406
|
+
get mtime() {
|
|
4407
|
+
return this.#mtime;
|
|
4408
|
+
}
|
|
4409
|
+
#ctime;
|
|
4410
|
+
get ctime() {
|
|
4411
|
+
return this.#ctime;
|
|
4412
|
+
}
|
|
4413
|
+
#birthtime;
|
|
4414
|
+
get birthtime() {
|
|
4415
|
+
return this.#birthtime;
|
|
4416
|
+
}
|
|
4417
|
+
#matchName;
|
|
4418
|
+
#depth;
|
|
4419
|
+
#fullpath;
|
|
4420
|
+
#fullpathPosix;
|
|
4421
|
+
#relative;
|
|
4422
|
+
#relativePosix;
|
|
4423
|
+
#type;
|
|
4424
|
+
#children;
|
|
4425
|
+
#linkTarget;
|
|
4426
|
+
#realpath;
|
|
4427
|
+
/**
|
|
4428
|
+
* This property is for compatibility with the Dirent class as of
|
|
4429
|
+
* Node v20, where Dirent['parentPath'] refers to the path of the
|
|
4430
|
+
* directory that was passed to readdir. For root entries, it's the path
|
|
4431
|
+
* to the entry itself.
|
|
4432
|
+
*/
|
|
4433
|
+
get parentPath() {
|
|
4434
|
+
return (this.parent || this).fullpath();
|
|
4435
|
+
}
|
|
4436
|
+
/**
|
|
4437
|
+
* Deprecated alias for Dirent['parentPath'] Somewhat counterintuitively,
|
|
4438
|
+
* this property refers to the *parent* path, not the path object itself.
|
|
4439
|
+
*/
|
|
4440
|
+
get path() {
|
|
4441
|
+
return this.parentPath;
|
|
4442
|
+
}
|
|
4443
|
+
/**
|
|
4444
|
+
* Do not create new Path objects directly. They should always be accessed
|
|
4445
|
+
* via the PathScurry class or other methods on the Path class.
|
|
4446
|
+
*
|
|
4447
|
+
* @internal
|
|
4448
|
+
*/
|
|
4449
|
+
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
|
4450
|
+
this.name = name;
|
|
4451
|
+
this.#matchName = nocase ? normalizeNocase(name) : normalize(name);
|
|
4452
|
+
this.#type = type & TYPEMASK;
|
|
4453
|
+
this.nocase = nocase;
|
|
4454
|
+
this.roots = roots;
|
|
4455
|
+
this.root = root || this;
|
|
4456
|
+
this.#children = children;
|
|
4457
|
+
this.#fullpath = opts.fullpath;
|
|
4458
|
+
this.#relative = opts.relative;
|
|
4459
|
+
this.#relativePosix = opts.relativePosix;
|
|
4460
|
+
this.parent = opts.parent;
|
|
4461
|
+
if (this.parent) this.#fs = this.parent.#fs;
|
|
4462
|
+
else this.#fs = fsFromOption(opts.fs);
|
|
4463
|
+
}
|
|
4464
|
+
/**
|
|
4465
|
+
* Returns the depth of the Path object from its root.
|
|
4466
|
+
*
|
|
4467
|
+
* For example, a path at `/foo/bar` would have a depth of 2.
|
|
4468
|
+
*/
|
|
4469
|
+
depth() {
|
|
4470
|
+
if (this.#depth !== void 0) return this.#depth;
|
|
4471
|
+
if (!this.parent) return this.#depth = 0;
|
|
4472
|
+
return this.#depth = this.parent.depth() + 1;
|
|
4473
|
+
}
|
|
4474
|
+
/**
|
|
4475
|
+
* @internal
|
|
4476
|
+
*/
|
|
4477
|
+
childrenCache() {
|
|
4478
|
+
return this.#children;
|
|
4479
|
+
}
|
|
4480
|
+
/**
|
|
4481
|
+
* Get the Path object referenced by the string path, resolved from this Path
|
|
4482
|
+
*/
|
|
4483
|
+
resolve(path$4) {
|
|
4484
|
+
if (!path$4) return this;
|
|
4485
|
+
const rootPath = this.getRootString(path$4);
|
|
4486
|
+
const dir = path$4.substring(rootPath.length);
|
|
4487
|
+
const dirParts = dir.split(this.splitSep);
|
|
4488
|
+
const result = rootPath ? this.getRoot(rootPath).#resolveParts(dirParts) : this.#resolveParts(dirParts);
|
|
4489
|
+
return result;
|
|
4490
|
+
}
|
|
4491
|
+
#resolveParts(dirParts) {
|
|
4492
|
+
let p = this;
|
|
4493
|
+
for (const part of dirParts) p = p.child(part);
|
|
4494
|
+
return p;
|
|
4495
|
+
}
|
|
4496
|
+
/**
|
|
4497
|
+
* Returns the cached children Path objects, if still available. If they
|
|
4498
|
+
* have fallen out of the cache, then returns an empty array, and resets the
|
|
4499
|
+
* READDIR_CALLED bit, so that future calls to readdir() will require an fs
|
|
4500
|
+
* lookup.
|
|
4501
|
+
*
|
|
4502
|
+
* @internal
|
|
4503
|
+
*/
|
|
4504
|
+
children() {
|
|
4505
|
+
const cached = this.#children.get(this);
|
|
4506
|
+
if (cached) return cached;
|
|
4507
|
+
const children = Object.assign([], { provisional: 0 });
|
|
4508
|
+
this.#children.set(this, children);
|
|
4509
|
+
this.#type &= ~READDIR_CALLED;
|
|
4510
|
+
return children;
|
|
4511
|
+
}
|
|
4512
|
+
/**
|
|
4513
|
+
* Resolves a path portion and returns or creates the child Path.
|
|
4514
|
+
*
|
|
4515
|
+
* Returns `this` if pathPart is `''` or `'.'`, or `parent` if pathPart is
|
|
4516
|
+
* `'..'`.
|
|
4517
|
+
*
|
|
4518
|
+
* This should not be called directly. If `pathPart` contains any path
|
|
4519
|
+
* separators, it will lead to unsafe undefined behavior.
|
|
4520
|
+
*
|
|
4521
|
+
* Use `Path.resolve()` instead.
|
|
4522
|
+
*
|
|
4523
|
+
* @internal
|
|
4524
|
+
*/
|
|
4525
|
+
child(pathPart, opts) {
|
|
4526
|
+
if (pathPart === "" || pathPart === ".") return this;
|
|
4527
|
+
if (pathPart === "..") return this.parent || this;
|
|
4528
|
+
const children = this.children();
|
|
4529
|
+
const name = this.nocase ? normalizeNocase(pathPart) : normalize(pathPart);
|
|
4530
|
+
for (const p of children) if (p.#matchName === name) return p;
|
|
4531
|
+
const s = this.parent ? this.sep : "";
|
|
4532
|
+
const fullpath = this.#fullpath ? this.#fullpath + s + pathPart : void 0;
|
|
4533
|
+
const pchild = this.newChild(pathPart, UNKNOWN, {
|
|
4534
|
+
...opts,
|
|
4535
|
+
parent: this,
|
|
4536
|
+
fullpath
|
|
4537
|
+
});
|
|
4538
|
+
if (!this.canReaddir()) pchild.#type |= ENOENT;
|
|
4539
|
+
children.push(pchild);
|
|
4540
|
+
return pchild;
|
|
4541
|
+
}
|
|
4542
|
+
/**
|
|
4543
|
+
* The relative path from the cwd. If it does not share an ancestor with
|
|
4544
|
+
* the cwd, then this ends up being equivalent to the fullpath()
|
|
4545
|
+
*/
|
|
4546
|
+
relative() {
|
|
4547
|
+
if (this.isCWD) return "";
|
|
4548
|
+
if (this.#relative !== void 0) return this.#relative;
|
|
4549
|
+
const name = this.name;
|
|
4550
|
+
const p = this.parent;
|
|
4551
|
+
if (!p) return this.#relative = this.name;
|
|
4552
|
+
const pv = p.relative();
|
|
4553
|
+
return pv + (!pv || !p.parent ? "" : this.sep) + name;
|
|
4554
|
+
}
|
|
4555
|
+
/**
|
|
4556
|
+
* The relative path from the cwd, using / as the path separator.
|
|
4557
|
+
* If it does not share an ancestor with
|
|
4558
|
+
* the cwd, then this ends up being equivalent to the fullpathPosix()
|
|
4559
|
+
* On posix systems, this is identical to relative().
|
|
4560
|
+
*/
|
|
4561
|
+
relativePosix() {
|
|
4562
|
+
if (this.sep === "/") return this.relative();
|
|
4563
|
+
if (this.isCWD) return "";
|
|
4564
|
+
if (this.#relativePosix !== void 0) return this.#relativePosix;
|
|
4565
|
+
const name = this.name;
|
|
4566
|
+
const p = this.parent;
|
|
4567
|
+
if (!p) return this.#relativePosix = this.fullpathPosix();
|
|
4568
|
+
const pv = p.relativePosix();
|
|
4569
|
+
return pv + (!pv || !p.parent ? "" : "/") + name;
|
|
4570
|
+
}
|
|
4571
|
+
/**
|
|
4572
|
+
* The fully resolved path string for this Path entry
|
|
4573
|
+
*/
|
|
4574
|
+
fullpath() {
|
|
4575
|
+
if (this.#fullpath !== void 0) return this.#fullpath;
|
|
4576
|
+
const name = this.name;
|
|
4577
|
+
const p = this.parent;
|
|
4578
|
+
if (!p) return this.#fullpath = this.name;
|
|
4579
|
+
const pv = p.fullpath();
|
|
4580
|
+
const fp = pv + (!p.parent ? "" : this.sep) + name;
|
|
4581
|
+
return this.#fullpath = fp;
|
|
4582
|
+
}
|
|
4583
|
+
/**
|
|
4584
|
+
* On platforms other than windows, this is identical to fullpath.
|
|
4585
|
+
*
|
|
4586
|
+
* On windows, this is overridden to return the forward-slash form of the
|
|
4587
|
+
* full UNC path.
|
|
4588
|
+
*/
|
|
4589
|
+
fullpathPosix() {
|
|
4590
|
+
if (this.#fullpathPosix !== void 0) return this.#fullpathPosix;
|
|
4591
|
+
if (this.sep === "/") return this.#fullpathPosix = this.fullpath();
|
|
4592
|
+
if (!this.parent) {
|
|
4593
|
+
const p$1 = this.fullpath().replace(/\\/g, "/");
|
|
4594
|
+
if (/^[a-z]:\//i.test(p$1)) return this.#fullpathPosix = `//?/${p$1}`;
|
|
4595
|
+
else return this.#fullpathPosix = p$1;
|
|
4596
|
+
}
|
|
4597
|
+
const p = this.parent;
|
|
4598
|
+
const pfpp = p.fullpathPosix();
|
|
4599
|
+
const fpp = pfpp + (!pfpp || !p.parent ? "" : "/") + this.name;
|
|
4600
|
+
return this.#fullpathPosix = fpp;
|
|
4601
|
+
}
|
|
4602
|
+
/**
|
|
4603
|
+
* Is the Path of an unknown type?
|
|
4604
|
+
*
|
|
4605
|
+
* Note that we might know *something* about it if there has been a previous
|
|
4606
|
+
* filesystem operation, for example that it does not exist, or is not a
|
|
4607
|
+
* link, or whether it has child entries.
|
|
4608
|
+
*/
|
|
4609
|
+
isUnknown() {
|
|
4610
|
+
return (this.#type & IFMT) === UNKNOWN;
|
|
4611
|
+
}
|
|
4612
|
+
isType(type) {
|
|
4613
|
+
return this[`is${type}`]();
|
|
4614
|
+
}
|
|
4615
|
+
getType() {
|
|
4616
|
+
return this.isUnknown() ? "Unknown" : this.isDirectory() ? "Directory" : this.isFile() ? "File" : this.isSymbolicLink() ? "SymbolicLink" : this.isFIFO() ? "FIFO" : this.isCharacterDevice() ? "CharacterDevice" : this.isBlockDevice() ? "BlockDevice" : this.isSocket() ? "Socket" : "Unknown";
|
|
4617
|
+
/* c8 ignore stop */
|
|
4618
|
+
}
|
|
4619
|
+
/**
|
|
4620
|
+
* Is the Path a regular file?
|
|
4621
|
+
*/
|
|
4622
|
+
isFile() {
|
|
4623
|
+
return (this.#type & IFMT) === IFREG;
|
|
4624
|
+
}
|
|
4625
|
+
/**
|
|
4626
|
+
* Is the Path a directory?
|
|
4627
|
+
*/
|
|
4628
|
+
isDirectory() {
|
|
4629
|
+
return (this.#type & IFMT) === IFDIR;
|
|
4630
|
+
}
|
|
4631
|
+
/**
|
|
4632
|
+
* Is the path a character device?
|
|
4633
|
+
*/
|
|
4634
|
+
isCharacterDevice() {
|
|
4635
|
+
return (this.#type & IFMT) === IFCHR;
|
|
4636
|
+
}
|
|
4637
|
+
/**
|
|
4638
|
+
* Is the path a block device?
|
|
4639
|
+
*/
|
|
4640
|
+
isBlockDevice() {
|
|
4641
|
+
return (this.#type & IFMT) === IFBLK;
|
|
4642
|
+
}
|
|
4643
|
+
/**
|
|
4644
|
+
* Is the path a FIFO pipe?
|
|
4645
|
+
*/
|
|
4646
|
+
isFIFO() {
|
|
4647
|
+
return (this.#type & IFMT) === IFIFO;
|
|
4648
|
+
}
|
|
4649
|
+
/**
|
|
4650
|
+
* Is the path a socket?
|
|
4651
|
+
*/
|
|
4652
|
+
isSocket() {
|
|
4653
|
+
return (this.#type & IFMT) === IFSOCK;
|
|
4654
|
+
}
|
|
4655
|
+
/**
|
|
4656
|
+
* Is the path a symbolic link?
|
|
4657
|
+
*/
|
|
4658
|
+
isSymbolicLink() {
|
|
4659
|
+
return (this.#type & IFLNK) === IFLNK;
|
|
4660
|
+
}
|
|
4661
|
+
/**
|
|
4662
|
+
* Return the entry if it has been subject of a successful lstat, or
|
|
4663
|
+
* undefined otherwise.
|
|
4664
|
+
*
|
|
4665
|
+
* Does not read the filesystem, so an undefined result *could* simply
|
|
4666
|
+
* mean that we haven't called lstat on it.
|
|
4667
|
+
*/
|
|
4668
|
+
lstatCached() {
|
|
4669
|
+
return this.#type & LSTAT_CALLED ? this : void 0;
|
|
4670
|
+
}
|
|
4671
|
+
/**
|
|
4672
|
+
* Return the cached link target if the entry has been the subject of a
|
|
4673
|
+
* successful readlink, or undefined otherwise.
|
|
4674
|
+
*
|
|
4675
|
+
* Does not read the filesystem, so an undefined result *could* just mean we
|
|
4676
|
+
* don't have any cached data. Only use it if you are very sure that a
|
|
4677
|
+
* readlink() has been called at some point.
|
|
4678
|
+
*/
|
|
4679
|
+
readlinkCached() {
|
|
4680
|
+
return this.#linkTarget;
|
|
4681
|
+
}
|
|
4682
|
+
/**
|
|
4683
|
+
* Returns the cached realpath target if the entry has been the subject
|
|
4684
|
+
* of a successful realpath, or undefined otherwise.
|
|
4685
|
+
*
|
|
4686
|
+
* Does not read the filesystem, so an undefined result *could* just mean we
|
|
4687
|
+
* don't have any cached data. Only use it if you are very sure that a
|
|
4688
|
+
* realpath() has been called at some point.
|
|
4689
|
+
*/
|
|
4690
|
+
realpathCached() {
|
|
4691
|
+
return this.#realpath;
|
|
4692
|
+
}
|
|
4693
|
+
/**
|
|
4694
|
+
* Returns the cached child Path entries array if the entry has been the
|
|
4695
|
+
* subject of a successful readdir(), or [] otherwise.
|
|
4696
|
+
*
|
|
4697
|
+
* Does not read the filesystem, so an empty array *could* just mean we
|
|
4698
|
+
* don't have any cached data. Only use it if you are very sure that a
|
|
4699
|
+
* readdir() has been called recently enough to still be valid.
|
|
4700
|
+
*/
|
|
4701
|
+
readdirCached() {
|
|
4702
|
+
const children = this.children();
|
|
4703
|
+
return children.slice(0, children.provisional);
|
|
4704
|
+
}
|
|
4705
|
+
/**
|
|
4706
|
+
* Return true if it's worth trying to readlink. Ie, we don't (yet) have
|
|
4707
|
+
* any indication that readlink will definitely fail.
|
|
4708
|
+
*
|
|
4709
|
+
* Returns false if the path is known to not be a symlink, if a previous
|
|
4710
|
+
* readlink failed, or if the entry does not exist.
|
|
4711
|
+
*/
|
|
4712
|
+
canReadlink() {
|
|
4713
|
+
if (this.#linkTarget) return true;
|
|
4714
|
+
if (!this.parent) return false;
|
|
4715
|
+
const ifmt = this.#type & IFMT;
|
|
4716
|
+
return !(ifmt !== UNKNOWN && ifmt !== IFLNK || this.#type & ENOREADLINK || this.#type & ENOENT);
|
|
4717
|
+
}
|
|
4718
|
+
/**
|
|
4719
|
+
* Return true if readdir has previously been successfully called on this
|
|
4720
|
+
* path, indicating that cachedReaddir() is likely valid.
|
|
4721
|
+
*/
|
|
4722
|
+
calledReaddir() {
|
|
4723
|
+
return !!(this.#type & READDIR_CALLED);
|
|
4724
|
+
}
|
|
4725
|
+
/**
|
|
4726
|
+
* Returns true if the path is known to not exist. That is, a previous lstat
|
|
4727
|
+
* or readdir failed to verify its existence when that would have been
|
|
4728
|
+
* expected, or a parent entry was marked either enoent or enotdir.
|
|
4729
|
+
*/
|
|
4730
|
+
isENOENT() {
|
|
4731
|
+
return !!(this.#type & ENOENT);
|
|
4732
|
+
}
|
|
4733
|
+
/**
|
|
4734
|
+
* Return true if the path is a match for the given path name. This handles
|
|
4735
|
+
* case sensitivity and unicode normalization.
|
|
4736
|
+
*
|
|
4737
|
+
* Note: even on case-sensitive systems, it is **not** safe to test the
|
|
4738
|
+
* equality of the `.name` property to determine whether a given pathname
|
|
4739
|
+
* matches, due to unicode normalization mismatches.
|
|
4740
|
+
*
|
|
4741
|
+
* Always use this method instead of testing the `path.name` property
|
|
4742
|
+
* directly.
|
|
4743
|
+
*/
|
|
4744
|
+
isNamed(n) {
|
|
4745
|
+
return !this.nocase ? this.#matchName === normalize(n) : this.#matchName === normalizeNocase(n);
|
|
4746
|
+
}
|
|
4747
|
+
/**
|
|
4748
|
+
* Return the Path object corresponding to the target of a symbolic link.
|
|
4749
|
+
*
|
|
4750
|
+
* If the Path is not a symbolic link, or if the readlink call fails for any
|
|
4751
|
+
* reason, `undefined` is returned.
|
|
4752
|
+
*
|
|
4753
|
+
* Result is cached, and thus may be outdated if the filesystem is mutated.
|
|
4754
|
+
*/
|
|
4755
|
+
async readlink() {
|
|
4756
|
+
const target = this.#linkTarget;
|
|
4757
|
+
if (target) return target;
|
|
4758
|
+
if (!this.canReadlink()) return void 0;
|
|
4759
|
+
/* c8 ignore start */
|
|
4760
|
+
if (!this.parent) return void 0;
|
|
4761
|
+
/* c8 ignore stop */
|
|
4762
|
+
try {
|
|
4763
|
+
const read = await this.#fs.promises.readlink(this.fullpath());
|
|
4764
|
+
const linkTarget = (await this.parent.realpath())?.resolve(read);
|
|
4765
|
+
if (linkTarget) return this.#linkTarget = linkTarget;
|
|
4766
|
+
} catch (er) {
|
|
4767
|
+
this.#readlinkFail(er.code);
|
|
4768
|
+
return void 0;
|
|
4769
|
+
}
|
|
4770
|
+
}
|
|
4771
|
+
/**
|
|
4772
|
+
* Synchronous {@link PathBase.readlink}
|
|
4773
|
+
*/
|
|
4774
|
+
readlinkSync() {
|
|
4775
|
+
const target = this.#linkTarget;
|
|
4776
|
+
if (target) return target;
|
|
4777
|
+
if (!this.canReadlink()) return void 0;
|
|
4778
|
+
/* c8 ignore start */
|
|
4779
|
+
if (!this.parent) return void 0;
|
|
4780
|
+
/* c8 ignore stop */
|
|
4781
|
+
try {
|
|
4782
|
+
const read = this.#fs.readlinkSync(this.fullpath());
|
|
4783
|
+
const linkTarget = this.parent.realpathSync()?.resolve(read);
|
|
4784
|
+
if (linkTarget) return this.#linkTarget = linkTarget;
|
|
4785
|
+
} catch (er) {
|
|
4786
|
+
this.#readlinkFail(er.code);
|
|
4787
|
+
return void 0;
|
|
4788
|
+
}
|
|
4789
|
+
}
|
|
4790
|
+
#readdirSuccess(children) {
|
|
4791
|
+
this.#type |= READDIR_CALLED;
|
|
4792
|
+
for (let p = children.provisional; p < children.length; p++) {
|
|
4793
|
+
const c = children[p];
|
|
4794
|
+
if (c) c.#markENOENT();
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
#markENOENT() {
|
|
4798
|
+
if (this.#type & ENOENT) return;
|
|
4799
|
+
this.#type = (this.#type | ENOENT) & IFMT_UNKNOWN;
|
|
4800
|
+
this.#markChildrenENOENT();
|
|
4801
|
+
}
|
|
4802
|
+
#markChildrenENOENT() {
|
|
4803
|
+
const children = this.children();
|
|
4804
|
+
children.provisional = 0;
|
|
4805
|
+
for (const p of children) p.#markENOENT();
|
|
4806
|
+
}
|
|
4807
|
+
#markENOREALPATH() {
|
|
4808
|
+
this.#type |= ENOREALPATH;
|
|
4809
|
+
this.#markENOTDIR();
|
|
4810
|
+
}
|
|
4811
|
+
#markENOTDIR() {
|
|
4812
|
+
/* c8 ignore start */
|
|
4813
|
+
if (this.#type & ENOTDIR) return;
|
|
4814
|
+
/* c8 ignore stop */
|
|
4815
|
+
let t = this.#type;
|
|
4816
|
+
if ((t & IFMT) === IFDIR) t &= IFMT_UNKNOWN;
|
|
4817
|
+
this.#type = t | ENOTDIR;
|
|
4818
|
+
this.#markChildrenENOENT();
|
|
4819
|
+
}
|
|
4820
|
+
#readdirFail(code = "") {
|
|
4821
|
+
if (code === "ENOTDIR" || code === "EPERM") this.#markENOTDIR();
|
|
4822
|
+
else if (code === "ENOENT") this.#markENOENT();
|
|
4823
|
+
else this.children().provisional = 0;
|
|
4824
|
+
}
|
|
4825
|
+
#lstatFail(code = "") {
|
|
4826
|
+
/* c8 ignore start */
|
|
4827
|
+
if (code === "ENOTDIR") {
|
|
4828
|
+
const p = this.parent;
|
|
4829
|
+
p.#markENOTDIR();
|
|
4830
|
+
} else if (code === "ENOENT")
|
|
4831
|
+
/* c8 ignore stop */
|
|
4832
|
+
this.#markENOENT();
|
|
4833
|
+
}
|
|
4834
|
+
#readlinkFail(code = "") {
|
|
4835
|
+
let ter = this.#type;
|
|
4836
|
+
ter |= ENOREADLINK;
|
|
4837
|
+
if (code === "ENOENT") ter |= ENOENT;
|
|
4838
|
+
if (code === "EINVAL" || code === "UNKNOWN") ter &= IFMT_UNKNOWN;
|
|
4839
|
+
this.#type = ter;
|
|
4840
|
+
/* c8 ignore start */
|
|
4841
|
+
if (code === "ENOTDIR" && this.parent) this.parent.#markENOTDIR();
|
|
4842
|
+
/* c8 ignore stop */
|
|
4843
|
+
}
|
|
4844
|
+
#readdirAddChild(e, c) {
|
|
4845
|
+
return this.#readdirMaybePromoteChild(e, c) || this.#readdirAddNewChild(e, c);
|
|
4846
|
+
}
|
|
4847
|
+
#readdirAddNewChild(e, c) {
|
|
4848
|
+
const type = entToType(e);
|
|
4849
|
+
const child = this.newChild(e.name, type, { parent: this });
|
|
4850
|
+
const ifmt = child.#type & IFMT;
|
|
4851
|
+
if (ifmt !== IFDIR && ifmt !== IFLNK && ifmt !== UNKNOWN) child.#type |= ENOTDIR;
|
|
4852
|
+
c.unshift(child);
|
|
4853
|
+
c.provisional++;
|
|
4854
|
+
return child;
|
|
4855
|
+
}
|
|
4856
|
+
#readdirMaybePromoteChild(e, c) {
|
|
4857
|
+
for (let p = c.provisional; p < c.length; p++) {
|
|
4858
|
+
const pchild = c[p];
|
|
4859
|
+
const name = this.nocase ? normalizeNocase(e.name) : normalize(e.name);
|
|
4860
|
+
if (name !== pchild.#matchName) continue;
|
|
4861
|
+
return this.#readdirPromoteChild(e, pchild, p, c);
|
|
4862
|
+
}
|
|
4863
|
+
}
|
|
4864
|
+
#readdirPromoteChild(e, p, index, c) {
|
|
4865
|
+
const v = p.name;
|
|
4866
|
+
p.#type = p.#type & IFMT_UNKNOWN | entToType(e);
|
|
4867
|
+
if (v !== e.name) p.name = e.name;
|
|
4868
|
+
if (index !== c.provisional) {
|
|
4869
|
+
if (index === c.length - 1) c.pop();
|
|
4870
|
+
else c.splice(index, 1);
|
|
4871
|
+
c.unshift(p);
|
|
4872
|
+
}
|
|
4873
|
+
c.provisional++;
|
|
4874
|
+
return p;
|
|
4875
|
+
}
|
|
4876
|
+
/**
|
|
4877
|
+
* Call lstat() on this Path, and update all known information that can be
|
|
4878
|
+
* determined.
|
|
4879
|
+
*
|
|
4880
|
+
* Note that unlike `fs.lstat()`, the returned value does not contain some
|
|
4881
|
+
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
|
|
4882
|
+
* information is required, you will need to call `fs.lstat` yourself.
|
|
4883
|
+
*
|
|
4884
|
+
* If the Path refers to a nonexistent file, or if the lstat call fails for
|
|
4885
|
+
* any reason, `undefined` is returned. Otherwise the updated Path object is
|
|
4886
|
+
* returned.
|
|
4887
|
+
*
|
|
4888
|
+
* Results are cached, and thus may be out of date if the filesystem is
|
|
4889
|
+
* mutated.
|
|
4890
|
+
*/
|
|
4891
|
+
async lstat() {
|
|
4892
|
+
if ((this.#type & ENOENT) === 0) try {
|
|
4893
|
+
this.#applyStat(await this.#fs.promises.lstat(this.fullpath()));
|
|
4894
|
+
return this;
|
|
4895
|
+
} catch (er) {
|
|
4896
|
+
this.#lstatFail(er.code);
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
/**
|
|
4900
|
+
* synchronous {@link PathBase.lstat}
|
|
4901
|
+
*/
|
|
4902
|
+
lstatSync() {
|
|
4903
|
+
if ((this.#type & ENOENT) === 0) try {
|
|
4904
|
+
this.#applyStat(this.#fs.lstatSync(this.fullpath()));
|
|
4905
|
+
return this;
|
|
4906
|
+
} catch (er) {
|
|
4907
|
+
this.#lstatFail(er.code);
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
#applyStat(st) {
|
|
4911
|
+
const { atime, atimeMs, birthtime, birthtimeMs, blksize, blocks, ctime, ctimeMs, dev, gid, ino, mode, mtime, mtimeMs, nlink, rdev, size, uid } = st;
|
|
4912
|
+
this.#atime = atime;
|
|
4913
|
+
this.#atimeMs = atimeMs;
|
|
4914
|
+
this.#birthtime = birthtime;
|
|
4915
|
+
this.#birthtimeMs = birthtimeMs;
|
|
4916
|
+
this.#blksize = blksize;
|
|
4917
|
+
this.#blocks = blocks;
|
|
4918
|
+
this.#ctime = ctime;
|
|
4919
|
+
this.#ctimeMs = ctimeMs;
|
|
4920
|
+
this.#dev = dev;
|
|
4921
|
+
this.#gid = gid;
|
|
4922
|
+
this.#ino = ino;
|
|
4923
|
+
this.#mode = mode;
|
|
4924
|
+
this.#mtime = mtime;
|
|
4925
|
+
this.#mtimeMs = mtimeMs;
|
|
4926
|
+
this.#nlink = nlink;
|
|
4927
|
+
this.#rdev = rdev;
|
|
4928
|
+
this.#size = size;
|
|
4929
|
+
this.#uid = uid;
|
|
4930
|
+
const ifmt = entToType(st);
|
|
4931
|
+
this.#type = this.#type & IFMT_UNKNOWN | ifmt | LSTAT_CALLED;
|
|
4932
|
+
if (ifmt !== UNKNOWN && ifmt !== IFDIR && ifmt !== IFLNK) this.#type |= ENOTDIR;
|
|
4933
|
+
}
|
|
4934
|
+
#onReaddirCB = [];
|
|
4935
|
+
#readdirCBInFlight = false;
|
|
4936
|
+
#callOnReaddirCB(children) {
|
|
4937
|
+
this.#readdirCBInFlight = false;
|
|
4938
|
+
const cbs = this.#onReaddirCB.slice();
|
|
4939
|
+
this.#onReaddirCB.length = 0;
|
|
4940
|
+
cbs.forEach((cb) => cb(null, children));
|
|
4941
|
+
}
|
|
4942
|
+
/**
|
|
4943
|
+
* Standard node-style callback interface to get list of directory entries.
|
|
4944
|
+
*
|
|
4945
|
+
* If the Path cannot or does not contain any children, then an empty array
|
|
4946
|
+
* is returned.
|
|
4947
|
+
*
|
|
4948
|
+
* Results are cached, and thus may be out of date if the filesystem is
|
|
4949
|
+
* mutated.
|
|
4950
|
+
*
|
|
4951
|
+
* @param cb The callback called with (er, entries). Note that the `er`
|
|
4952
|
+
* param is somewhat extraneous, as all readdir() errors are handled and
|
|
4953
|
+
* simply result in an empty set of entries being returned.
|
|
4954
|
+
* @param allowZalgo Boolean indicating that immediately known results should
|
|
4955
|
+
* *not* be deferred with `queueMicrotask`. Defaults to `false`. Release
|
|
4956
|
+
* zalgo at your peril, the dark pony lord is devious and unforgiving.
|
|
4957
|
+
*/
|
|
4958
|
+
readdirCB(cb, allowZalgo = false) {
|
|
4959
|
+
if (!this.canReaddir()) {
|
|
4960
|
+
if (allowZalgo) cb(null, []);
|
|
4961
|
+
else queueMicrotask(() => cb(null, []));
|
|
4962
|
+
return;
|
|
4963
|
+
}
|
|
4964
|
+
const children = this.children();
|
|
4965
|
+
if (this.calledReaddir()) {
|
|
4966
|
+
const c = children.slice(0, children.provisional);
|
|
4967
|
+
if (allowZalgo) cb(null, c);
|
|
4968
|
+
else queueMicrotask(() => cb(null, c));
|
|
4969
|
+
return;
|
|
4970
|
+
}
|
|
4971
|
+
this.#onReaddirCB.push(cb);
|
|
4972
|
+
if (this.#readdirCBInFlight) return;
|
|
4973
|
+
this.#readdirCBInFlight = true;
|
|
4974
|
+
const fullpath = this.fullpath();
|
|
4975
|
+
this.#fs.readdir(fullpath, { withFileTypes: true }, (er, entries) => {
|
|
4976
|
+
if (er) {
|
|
4977
|
+
this.#readdirFail(er.code);
|
|
4978
|
+
children.provisional = 0;
|
|
4979
|
+
} else {
|
|
4980
|
+
for (const e of entries) this.#readdirAddChild(e, children);
|
|
4981
|
+
this.#readdirSuccess(children);
|
|
4982
|
+
}
|
|
4983
|
+
this.#callOnReaddirCB(children.slice(0, children.provisional));
|
|
4984
|
+
return;
|
|
4985
|
+
});
|
|
4986
|
+
}
|
|
4987
|
+
#asyncReaddirInFlight;
|
|
4988
|
+
/**
|
|
4989
|
+
* Return an array of known child entries.
|
|
4990
|
+
*
|
|
4991
|
+
* If the Path cannot or does not contain any children, then an empty array
|
|
4992
|
+
* is returned.
|
|
4993
|
+
*
|
|
4994
|
+
* Results are cached, and thus may be out of date if the filesystem is
|
|
4995
|
+
* mutated.
|
|
4996
|
+
*/
|
|
4997
|
+
async readdir() {
|
|
4998
|
+
if (!this.canReaddir()) return [];
|
|
4999
|
+
const children = this.children();
|
|
5000
|
+
if (this.calledReaddir()) return children.slice(0, children.provisional);
|
|
5001
|
+
const fullpath = this.fullpath();
|
|
5002
|
+
if (this.#asyncReaddirInFlight) await this.#asyncReaddirInFlight;
|
|
5003
|
+
else {
|
|
5004
|
+
/* c8 ignore start */
|
|
5005
|
+
let resolve$2 = () => {};
|
|
5006
|
+
/* c8 ignore stop */
|
|
5007
|
+
this.#asyncReaddirInFlight = new Promise((res) => resolve$2 = res);
|
|
5008
|
+
try {
|
|
5009
|
+
for (const e of await this.#fs.promises.readdir(fullpath, { withFileTypes: true })) this.#readdirAddChild(e, children);
|
|
5010
|
+
this.#readdirSuccess(children);
|
|
5011
|
+
} catch (er) {
|
|
5012
|
+
this.#readdirFail(er.code);
|
|
5013
|
+
children.provisional = 0;
|
|
5014
|
+
}
|
|
5015
|
+
this.#asyncReaddirInFlight = void 0;
|
|
5016
|
+
resolve$2();
|
|
5017
|
+
}
|
|
5018
|
+
return children.slice(0, children.provisional);
|
|
5019
|
+
}
|
|
5020
|
+
/**
|
|
5021
|
+
* synchronous {@link PathBase.readdir}
|
|
5022
|
+
*/
|
|
5023
|
+
readdirSync() {
|
|
5024
|
+
if (!this.canReaddir()) return [];
|
|
5025
|
+
const children = this.children();
|
|
5026
|
+
if (this.calledReaddir()) return children.slice(0, children.provisional);
|
|
5027
|
+
const fullpath = this.fullpath();
|
|
5028
|
+
try {
|
|
5029
|
+
for (const e of this.#fs.readdirSync(fullpath, { withFileTypes: true })) this.#readdirAddChild(e, children);
|
|
5030
|
+
this.#readdirSuccess(children);
|
|
5031
|
+
} catch (er) {
|
|
5032
|
+
this.#readdirFail(er.code);
|
|
5033
|
+
children.provisional = 0;
|
|
5034
|
+
}
|
|
5035
|
+
return children.slice(0, children.provisional);
|
|
5036
|
+
}
|
|
5037
|
+
canReaddir() {
|
|
5038
|
+
if (this.#type & ENOCHILD) return false;
|
|
5039
|
+
const ifmt = IFMT & this.#type;
|
|
5040
|
+
/* c8 ignore start */
|
|
5041
|
+
if (!(ifmt === UNKNOWN || ifmt === IFDIR || ifmt === IFLNK)) return false;
|
|
5042
|
+
/* c8 ignore stop */
|
|
5043
|
+
return true;
|
|
5044
|
+
}
|
|
5045
|
+
shouldWalk(dirs, walkFilter) {
|
|
5046
|
+
return (this.#type & IFDIR) === IFDIR && !(this.#type & ENOCHILD) && !dirs.has(this) && (!walkFilter || walkFilter(this));
|
|
5047
|
+
}
|
|
5048
|
+
/**
|
|
5049
|
+
* Return the Path object corresponding to path as resolved
|
|
5050
|
+
* by realpath(3).
|
|
5051
|
+
*
|
|
5052
|
+
* If the realpath call fails for any reason, `undefined` is returned.
|
|
5053
|
+
*
|
|
5054
|
+
* Result is cached, and thus may be outdated if the filesystem is mutated.
|
|
5055
|
+
* On success, returns a Path object.
|
|
5056
|
+
*/
|
|
5057
|
+
async realpath() {
|
|
5058
|
+
if (this.#realpath) return this.#realpath;
|
|
5059
|
+
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return void 0;
|
|
5060
|
+
try {
|
|
5061
|
+
const rp = await this.#fs.promises.realpath(this.fullpath());
|
|
5062
|
+
return this.#realpath = this.resolve(rp);
|
|
5063
|
+
} catch (_) {
|
|
5064
|
+
this.#markENOREALPATH();
|
|
5065
|
+
}
|
|
5066
|
+
}
|
|
5067
|
+
/**
|
|
5068
|
+
* Synchronous {@link realpath}
|
|
5069
|
+
*/
|
|
5070
|
+
realpathSync() {
|
|
5071
|
+
if (this.#realpath) return this.#realpath;
|
|
5072
|
+
if ((ENOREALPATH | ENOREADLINK | ENOENT) & this.#type) return void 0;
|
|
5073
|
+
try {
|
|
5074
|
+
const rp = this.#fs.realpathSync(this.fullpath());
|
|
5075
|
+
return this.#realpath = this.resolve(rp);
|
|
5076
|
+
} catch (_) {
|
|
5077
|
+
this.#markENOREALPATH();
|
|
5078
|
+
}
|
|
5079
|
+
}
|
|
5080
|
+
/**
|
|
5081
|
+
* Internal method to mark this Path object as the scurry cwd,
|
|
5082
|
+
* called by {@link PathScurry#chdir}
|
|
5083
|
+
*
|
|
5084
|
+
* @internal
|
|
5085
|
+
*/
|
|
5086
|
+
[setAsCwd](oldCwd) {
|
|
5087
|
+
if (oldCwd === this) return;
|
|
5088
|
+
oldCwd.isCWD = false;
|
|
5089
|
+
this.isCWD = true;
|
|
5090
|
+
const changed = new Set([]);
|
|
5091
|
+
let rp = [];
|
|
5092
|
+
let p = this;
|
|
5093
|
+
while (p && p.parent) {
|
|
5094
|
+
changed.add(p);
|
|
5095
|
+
p.#relative = rp.join(this.sep);
|
|
5096
|
+
p.#relativePosix = rp.join("/");
|
|
5097
|
+
p = p.parent;
|
|
5098
|
+
rp.push("..");
|
|
5099
|
+
}
|
|
5100
|
+
p = oldCwd;
|
|
5101
|
+
while (p && p.parent && !changed.has(p)) {
|
|
5102
|
+
p.#relative = void 0;
|
|
5103
|
+
p.#relativePosix = void 0;
|
|
5104
|
+
p = p.parent;
|
|
5105
|
+
}
|
|
5106
|
+
}
|
|
5107
|
+
};
|
|
5108
|
+
/**
|
|
5109
|
+
* Path class used on win32 systems
|
|
5110
|
+
*
|
|
5111
|
+
* Uses `'\\'` as the path separator for returned paths, either `'\\'` or `'/'`
|
|
5112
|
+
* as the path separator for parsing paths.
|
|
5113
|
+
*/
|
|
5114
|
+
var PathWin32 = class PathWin32 extends PathBase {
|
|
5115
|
+
/**
|
|
5116
|
+
* Separator for generating path strings.
|
|
5117
|
+
*/
|
|
5118
|
+
sep = "\\";
|
|
5119
|
+
/**
|
|
5120
|
+
* Separator for parsing path strings.
|
|
5121
|
+
*/
|
|
5122
|
+
splitSep = eitherSep;
|
|
5123
|
+
/**
|
|
5124
|
+
* Do not create new Path objects directly. They should always be accessed
|
|
5125
|
+
* via the PathScurry class or other methods on the Path class.
|
|
5126
|
+
*
|
|
5127
|
+
* @internal
|
|
5128
|
+
*/
|
|
5129
|
+
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
|
5130
|
+
super(name, type, root, roots, nocase, children, opts);
|
|
5131
|
+
}
|
|
5132
|
+
/**
|
|
5133
|
+
* @internal
|
|
5134
|
+
*/
|
|
5135
|
+
newChild(name, type = UNKNOWN, opts = {}) {
|
|
5136
|
+
return new PathWin32(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
|
|
5137
|
+
}
|
|
5138
|
+
/**
|
|
5139
|
+
* @internal
|
|
5140
|
+
*/
|
|
5141
|
+
getRootString(path$4) {
|
|
5142
|
+
return win32.parse(path$4).root;
|
|
5143
|
+
}
|
|
5144
|
+
/**
|
|
5145
|
+
* @internal
|
|
5146
|
+
*/
|
|
5147
|
+
getRoot(rootPath) {
|
|
5148
|
+
rootPath = uncToDrive(rootPath.toUpperCase());
|
|
5149
|
+
if (rootPath === this.root.name) return this.root;
|
|
5150
|
+
for (const [compare, root] of Object.entries(this.roots)) if (this.sameRoot(rootPath, compare)) return this.roots[rootPath] = root;
|
|
5151
|
+
return this.roots[rootPath] = new PathScurryWin32(rootPath, this).root;
|
|
5152
|
+
}
|
|
5153
|
+
/**
|
|
5154
|
+
* @internal
|
|
5155
|
+
*/
|
|
5156
|
+
sameRoot(rootPath, compare = this.root.name) {
|
|
5157
|
+
rootPath = rootPath.toUpperCase().replace(/\//g, "\\").replace(uncDriveRegexp, "$1\\");
|
|
5158
|
+
return rootPath === compare;
|
|
5159
|
+
}
|
|
5160
|
+
};
|
|
5161
|
+
/**
|
|
5162
|
+
* Path class used on all posix systems.
|
|
5163
|
+
*
|
|
5164
|
+
* Uses `'/'` as the path separator.
|
|
5165
|
+
*/
|
|
5166
|
+
var PathPosix = class PathPosix extends PathBase {
|
|
5167
|
+
/**
|
|
5168
|
+
* separator for parsing path strings
|
|
5169
|
+
*/
|
|
5170
|
+
splitSep = "/";
|
|
5171
|
+
/**
|
|
5172
|
+
* separator for generating path strings
|
|
5173
|
+
*/
|
|
5174
|
+
sep = "/";
|
|
5175
|
+
/**
|
|
5176
|
+
* Do not create new Path objects directly. They should always be accessed
|
|
5177
|
+
* via the PathScurry class or other methods on the Path class.
|
|
5178
|
+
*
|
|
5179
|
+
* @internal
|
|
5180
|
+
*/
|
|
5181
|
+
constructor(name, type = UNKNOWN, root, roots, nocase, children, opts) {
|
|
5182
|
+
super(name, type, root, roots, nocase, children, opts);
|
|
5183
|
+
}
|
|
5184
|
+
/**
|
|
5185
|
+
* @internal
|
|
5186
|
+
*/
|
|
5187
|
+
getRootString(path$4) {
|
|
5188
|
+
return path$4.startsWith("/") ? "/" : "";
|
|
5189
|
+
}
|
|
5190
|
+
/**
|
|
5191
|
+
* @internal
|
|
5192
|
+
*/
|
|
5193
|
+
getRoot(_rootPath) {
|
|
5194
|
+
return this.root;
|
|
5195
|
+
}
|
|
5196
|
+
/**
|
|
5197
|
+
* @internal
|
|
5198
|
+
*/
|
|
5199
|
+
newChild(name, type = UNKNOWN, opts = {}) {
|
|
5200
|
+
return new PathPosix(name, type, this.root, this.roots, this.nocase, this.childrenCache(), opts);
|
|
5201
|
+
}
|
|
5202
|
+
};
|
|
5203
|
+
/**
|
|
5204
|
+
* The base class for all PathScurry classes, providing the interface for path
|
|
5205
|
+
* resolution and filesystem operations.
|
|
5206
|
+
*
|
|
5207
|
+
* Typically, you should *not* instantiate this class directly, but rather one
|
|
5208
|
+
* of the platform-specific classes, or the exported {@link PathScurry} which
|
|
5209
|
+
* defaults to the current platform.
|
|
5210
|
+
*/
|
|
5211
|
+
var PathScurryBase = class {
|
|
5212
|
+
/**
|
|
5213
|
+
* The root Path entry for the current working directory of this Scurry
|
|
5214
|
+
*/
|
|
5215
|
+
root;
|
|
5216
|
+
/**
|
|
5217
|
+
* The string path for the root of this Scurry's current working directory
|
|
5218
|
+
*/
|
|
5219
|
+
rootPath;
|
|
5220
|
+
/**
|
|
5221
|
+
* A collection of all roots encountered, referenced by rootPath
|
|
5222
|
+
*/
|
|
5223
|
+
roots;
|
|
5224
|
+
/**
|
|
5225
|
+
* The Path entry corresponding to this PathScurry's current working directory.
|
|
5226
|
+
*/
|
|
5227
|
+
cwd;
|
|
5228
|
+
#resolveCache;
|
|
5229
|
+
#resolvePosixCache;
|
|
5230
|
+
#children;
|
|
5231
|
+
/**
|
|
5232
|
+
* Perform path comparisons case-insensitively.
|
|
5233
|
+
*
|
|
5234
|
+
* Defaults true on Darwin and Windows systems, false elsewhere.
|
|
5235
|
+
*/
|
|
5236
|
+
nocase;
|
|
5237
|
+
#fs;
|
|
5238
|
+
/**
|
|
5239
|
+
* This class should not be instantiated directly.
|
|
5240
|
+
*
|
|
5241
|
+
* Use PathScurryWin32, PathScurryDarwin, PathScurryPosix, or PathScurry
|
|
5242
|
+
*
|
|
5243
|
+
* @internal
|
|
5244
|
+
*/
|
|
5245
|
+
constructor(cwd = process.cwd(), pathImpl, sep, { nocase, childrenCacheSize = 16 * 1024, fs: fs$1 = defaultFS } = {}) {
|
|
5246
|
+
this.#fs = fsFromOption(fs$1);
|
|
5247
|
+
if (cwd instanceof URL || cwd.startsWith("file://")) cwd = fileURLToPath$1(cwd);
|
|
5248
|
+
const cwdPath = pathImpl.resolve(cwd);
|
|
5249
|
+
this.roots = Object.create(null);
|
|
5250
|
+
this.rootPath = this.parseRootPath(cwdPath);
|
|
5251
|
+
this.#resolveCache = new ResolveCache();
|
|
5252
|
+
this.#resolvePosixCache = new ResolveCache();
|
|
5253
|
+
this.#children = new ChildrenCache(childrenCacheSize);
|
|
5254
|
+
const split = cwdPath.substring(this.rootPath.length).split(sep);
|
|
5255
|
+
if (split.length === 1 && !split[0]) split.pop();
|
|
5256
|
+
/* c8 ignore start */
|
|
5257
|
+
if (nocase === void 0) throw new TypeError("must provide nocase setting to PathScurryBase ctor");
|
|
5258
|
+
/* c8 ignore stop */
|
|
5259
|
+
this.nocase = nocase;
|
|
5260
|
+
this.root = this.newRoot(this.#fs);
|
|
5261
|
+
this.roots[this.rootPath] = this.root;
|
|
5262
|
+
let prev = this.root;
|
|
5263
|
+
let len = split.length - 1;
|
|
5264
|
+
const joinSep = pathImpl.sep;
|
|
5265
|
+
let abs = this.rootPath;
|
|
5266
|
+
let sawFirst = false;
|
|
5267
|
+
for (const part of split) {
|
|
5268
|
+
const l = len--;
|
|
5269
|
+
prev = prev.child(part, {
|
|
5270
|
+
relative: new Array(l).fill("..").join(joinSep),
|
|
5271
|
+
relativePosix: new Array(l).fill("..").join("/"),
|
|
5272
|
+
fullpath: abs += (sawFirst ? "" : joinSep) + part
|
|
5273
|
+
});
|
|
5274
|
+
sawFirst = true;
|
|
5275
|
+
}
|
|
5276
|
+
this.cwd = prev;
|
|
5277
|
+
}
|
|
5278
|
+
/**
|
|
5279
|
+
* Get the depth of a provided path, string, or the cwd
|
|
5280
|
+
*/
|
|
5281
|
+
depth(path$4 = this.cwd) {
|
|
5282
|
+
if (typeof path$4 === "string") path$4 = this.cwd.resolve(path$4);
|
|
5283
|
+
return path$4.depth();
|
|
5284
|
+
}
|
|
5285
|
+
/**
|
|
5286
|
+
* Return the cache of child entries. Exposed so subclasses can create
|
|
5287
|
+
* child Path objects in a platform-specific way.
|
|
5288
|
+
*
|
|
5289
|
+
* @internal
|
|
5290
|
+
*/
|
|
5291
|
+
childrenCache() {
|
|
5292
|
+
return this.#children;
|
|
5293
|
+
}
|
|
5294
|
+
/**
|
|
5295
|
+
* Resolve one or more path strings to a resolved string
|
|
5296
|
+
*
|
|
5297
|
+
* Same interface as require('path').resolve.
|
|
5298
|
+
*
|
|
5299
|
+
* Much faster than path.resolve() when called multiple times for the same
|
|
5300
|
+
* path, because the resolved Path objects are cached. Much slower
|
|
5301
|
+
* otherwise.
|
|
5302
|
+
*/
|
|
5303
|
+
resolve(...paths) {
|
|
5304
|
+
let r = "";
|
|
5305
|
+
for (let i = paths.length - 1; i >= 0; i--) {
|
|
5306
|
+
const p = paths[i];
|
|
5307
|
+
if (!p || p === ".") continue;
|
|
5308
|
+
r = r ? `${p}/${r}` : p;
|
|
5309
|
+
if (this.isAbsolute(p)) break;
|
|
5310
|
+
}
|
|
5311
|
+
const cached = this.#resolveCache.get(r);
|
|
5312
|
+
if (cached !== void 0) return cached;
|
|
5313
|
+
const result = this.cwd.resolve(r).fullpath();
|
|
5314
|
+
this.#resolveCache.set(r, result);
|
|
5315
|
+
return result;
|
|
5316
|
+
}
|
|
5317
|
+
/**
|
|
5318
|
+
* Resolve one or more path strings to a resolved string, returning
|
|
5319
|
+
* the posix path. Identical to .resolve() on posix systems, but on
|
|
5320
|
+
* windows will return a forward-slash separated UNC path.
|
|
5321
|
+
*
|
|
5322
|
+
* Same interface as require('path').resolve.
|
|
5323
|
+
*
|
|
5324
|
+
* Much faster than path.resolve() when called multiple times for the same
|
|
5325
|
+
* path, because the resolved Path objects are cached. Much slower
|
|
5326
|
+
* otherwise.
|
|
5327
|
+
*/
|
|
5328
|
+
resolvePosix(...paths) {
|
|
5329
|
+
let r = "";
|
|
5330
|
+
for (let i = paths.length - 1; i >= 0; i--) {
|
|
5331
|
+
const p = paths[i];
|
|
5332
|
+
if (!p || p === ".") continue;
|
|
5333
|
+
r = r ? `${p}/${r}` : p;
|
|
5334
|
+
if (this.isAbsolute(p)) break;
|
|
5335
|
+
}
|
|
5336
|
+
const cached = this.#resolvePosixCache.get(r);
|
|
5337
|
+
if (cached !== void 0) return cached;
|
|
5338
|
+
const result = this.cwd.resolve(r).fullpathPosix();
|
|
5339
|
+
this.#resolvePosixCache.set(r, result);
|
|
5340
|
+
return result;
|
|
5341
|
+
}
|
|
5342
|
+
/**
|
|
5343
|
+
* find the relative path from the cwd to the supplied path string or entry
|
|
5344
|
+
*/
|
|
5345
|
+
relative(entry = this.cwd) {
|
|
5346
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5347
|
+
return entry.relative();
|
|
5348
|
+
}
|
|
5349
|
+
/**
|
|
5350
|
+
* find the relative path from the cwd to the supplied path string or
|
|
5351
|
+
* entry, using / as the path delimiter, even on Windows.
|
|
5352
|
+
*/
|
|
5353
|
+
relativePosix(entry = this.cwd) {
|
|
5354
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5355
|
+
return entry.relativePosix();
|
|
5356
|
+
}
|
|
5357
|
+
/**
|
|
5358
|
+
* Return the basename for the provided string or Path object
|
|
5359
|
+
*/
|
|
5360
|
+
basename(entry = this.cwd) {
|
|
5361
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5362
|
+
return entry.name;
|
|
5363
|
+
}
|
|
5364
|
+
/**
|
|
5365
|
+
* Return the dirname for the provided string or Path object
|
|
5366
|
+
*/
|
|
5367
|
+
dirname(entry = this.cwd) {
|
|
5368
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5369
|
+
return (entry.parent || entry).fullpath();
|
|
5370
|
+
}
|
|
5371
|
+
async readdir(entry = this.cwd, opts = { withFileTypes: true }) {
|
|
5372
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5373
|
+
else if (!(entry instanceof PathBase)) {
|
|
5374
|
+
opts = entry;
|
|
5375
|
+
entry = this.cwd;
|
|
5376
|
+
}
|
|
5377
|
+
const { withFileTypes } = opts;
|
|
5378
|
+
if (!entry.canReaddir()) return [];
|
|
5379
|
+
else {
|
|
5380
|
+
const p = await entry.readdir();
|
|
5381
|
+
return withFileTypes ? p : p.map((e) => e.name);
|
|
5382
|
+
}
|
|
5383
|
+
}
|
|
5384
|
+
readdirSync(entry = this.cwd, opts = { withFileTypes: true }) {
|
|
5385
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5386
|
+
else if (!(entry instanceof PathBase)) {
|
|
5387
|
+
opts = entry;
|
|
5388
|
+
entry = this.cwd;
|
|
5389
|
+
}
|
|
5390
|
+
const { withFileTypes = true } = opts;
|
|
5391
|
+
if (!entry.canReaddir()) return [];
|
|
5392
|
+
else if (withFileTypes) return entry.readdirSync();
|
|
5393
|
+
else return entry.readdirSync().map((e) => e.name);
|
|
5394
|
+
}
|
|
5395
|
+
/**
|
|
5396
|
+
* Call lstat() on the string or Path object, and update all known
|
|
5397
|
+
* information that can be determined.
|
|
5398
|
+
*
|
|
5399
|
+
* Note that unlike `fs.lstat()`, the returned value does not contain some
|
|
5400
|
+
* information, such as `mode`, `dev`, `nlink`, and `ino`. If that
|
|
5401
|
+
* information is required, you will need to call `fs.lstat` yourself.
|
|
5402
|
+
*
|
|
5403
|
+
* If the Path refers to a nonexistent file, or if the lstat call fails for
|
|
5404
|
+
* any reason, `undefined` is returned. Otherwise the updated Path object is
|
|
5405
|
+
* returned.
|
|
5406
|
+
*
|
|
5407
|
+
* Results are cached, and thus may be out of date if the filesystem is
|
|
5408
|
+
* mutated.
|
|
5409
|
+
*/
|
|
5410
|
+
async lstat(entry = this.cwd) {
|
|
5411
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5412
|
+
return entry.lstat();
|
|
5413
|
+
}
|
|
5414
|
+
/**
|
|
5415
|
+
* synchronous {@link PathScurryBase.lstat}
|
|
5416
|
+
*/
|
|
5417
|
+
lstatSync(entry = this.cwd) {
|
|
5418
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5419
|
+
return entry.lstatSync();
|
|
5420
|
+
}
|
|
5421
|
+
async readlink(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
|
|
5422
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5423
|
+
else if (!(entry instanceof PathBase)) {
|
|
5424
|
+
withFileTypes = entry.withFileTypes;
|
|
5425
|
+
entry = this.cwd;
|
|
5426
|
+
}
|
|
5427
|
+
const e = await entry.readlink();
|
|
5428
|
+
return withFileTypes ? e : e?.fullpath();
|
|
5429
|
+
}
|
|
5430
|
+
readlinkSync(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
|
|
5431
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5432
|
+
else if (!(entry instanceof PathBase)) {
|
|
5433
|
+
withFileTypes = entry.withFileTypes;
|
|
5434
|
+
entry = this.cwd;
|
|
5435
|
+
}
|
|
5436
|
+
const e = entry.readlinkSync();
|
|
5437
|
+
return withFileTypes ? e : e?.fullpath();
|
|
5438
|
+
}
|
|
5439
|
+
async realpath(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
|
|
5440
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5441
|
+
else if (!(entry instanceof PathBase)) {
|
|
5442
|
+
withFileTypes = entry.withFileTypes;
|
|
5443
|
+
entry = this.cwd;
|
|
5444
|
+
}
|
|
5445
|
+
const e = await entry.realpath();
|
|
5446
|
+
return withFileTypes ? e : e?.fullpath();
|
|
5447
|
+
}
|
|
5448
|
+
realpathSync(entry = this.cwd, { withFileTypes } = { withFileTypes: false }) {
|
|
5449
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5450
|
+
else if (!(entry instanceof PathBase)) {
|
|
5451
|
+
withFileTypes = entry.withFileTypes;
|
|
5452
|
+
entry = this.cwd;
|
|
5453
|
+
}
|
|
5454
|
+
const e = entry.realpathSync();
|
|
5455
|
+
return withFileTypes ? e : e?.fullpath();
|
|
5456
|
+
}
|
|
5457
|
+
async walk(entry = this.cwd, opts = {}) {
|
|
5458
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5459
|
+
else if (!(entry instanceof PathBase)) {
|
|
5460
|
+
opts = entry;
|
|
5461
|
+
entry = this.cwd;
|
|
5462
|
+
}
|
|
5463
|
+
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
|
|
5464
|
+
const results = [];
|
|
5465
|
+
if (!filter || filter(entry)) results.push(withFileTypes ? entry : entry.fullpath());
|
|
5466
|
+
const dirs = new Set();
|
|
5467
|
+
const walk = (dir, cb) => {
|
|
5468
|
+
dirs.add(dir);
|
|
5469
|
+
dir.readdirCB((er, entries) => {
|
|
5470
|
+
/* c8 ignore start */
|
|
5471
|
+
if (er) return cb(er);
|
|
5472
|
+
/* c8 ignore stop */
|
|
5473
|
+
let len = entries.length;
|
|
5474
|
+
if (!len) return cb();
|
|
5475
|
+
const next = () => {
|
|
5476
|
+
if (--len === 0) cb();
|
|
5477
|
+
};
|
|
5478
|
+
for (const e of entries) {
|
|
5479
|
+
if (!filter || filter(e)) results.push(withFileTypes ? e : e.fullpath());
|
|
5480
|
+
if (follow && e.isSymbolicLink()) e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r).then((r) => r?.shouldWalk(dirs, walkFilter) ? walk(r, next) : next());
|
|
5481
|
+
else if (e.shouldWalk(dirs, walkFilter)) walk(e, next);
|
|
5482
|
+
else next();
|
|
5483
|
+
}
|
|
5484
|
+
}, true);
|
|
5485
|
+
};
|
|
5486
|
+
const start = entry;
|
|
5487
|
+
return new Promise((res, rej) => {
|
|
5488
|
+
walk(start, (er) => {
|
|
5489
|
+
/* c8 ignore start */
|
|
5490
|
+
if (er) return rej(er);
|
|
5491
|
+
/* c8 ignore stop */
|
|
5492
|
+
res(results);
|
|
5493
|
+
});
|
|
5494
|
+
});
|
|
5495
|
+
}
|
|
5496
|
+
walkSync(entry = this.cwd, opts = {}) {
|
|
5497
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5498
|
+
else if (!(entry instanceof PathBase)) {
|
|
5499
|
+
opts = entry;
|
|
5500
|
+
entry = this.cwd;
|
|
5501
|
+
}
|
|
5502
|
+
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
|
|
5503
|
+
const results = [];
|
|
5504
|
+
if (!filter || filter(entry)) results.push(withFileTypes ? entry : entry.fullpath());
|
|
5505
|
+
const dirs = new Set([entry]);
|
|
5506
|
+
for (const dir of dirs) {
|
|
5507
|
+
const entries = dir.readdirSync();
|
|
5508
|
+
for (const e of entries) {
|
|
5509
|
+
if (!filter || filter(e)) results.push(withFileTypes ? e : e.fullpath());
|
|
5510
|
+
let r = e;
|
|
5511
|
+
if (e.isSymbolicLink()) {
|
|
5512
|
+
if (!(follow && (r = e.realpathSync()))) continue;
|
|
5513
|
+
if (r.isUnknown()) r.lstatSync();
|
|
5514
|
+
}
|
|
5515
|
+
if (r.shouldWalk(dirs, walkFilter)) dirs.add(r);
|
|
5516
|
+
}
|
|
5517
|
+
}
|
|
5518
|
+
return results;
|
|
5519
|
+
}
|
|
5520
|
+
/**
|
|
5521
|
+
* Support for `for await`
|
|
5522
|
+
*
|
|
5523
|
+
* Alias for {@link PathScurryBase.iterate}
|
|
5524
|
+
*
|
|
5525
|
+
* Note: As of Node 19, this is very slow, compared to other methods of
|
|
5526
|
+
* walking. Consider using {@link PathScurryBase.stream} if memory overhead
|
|
5527
|
+
* and backpressure are concerns, or {@link PathScurryBase.walk} if not.
|
|
5528
|
+
*/
|
|
5529
|
+
[Symbol.asyncIterator]() {
|
|
5530
|
+
return this.iterate();
|
|
5531
|
+
}
|
|
5532
|
+
iterate(entry = this.cwd, options = {}) {
|
|
5533
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5534
|
+
else if (!(entry instanceof PathBase)) {
|
|
5535
|
+
options = entry;
|
|
5536
|
+
entry = this.cwd;
|
|
5537
|
+
}
|
|
5538
|
+
return this.stream(entry, options)[Symbol.asyncIterator]();
|
|
5539
|
+
}
|
|
5540
|
+
/**
|
|
5541
|
+
* Iterating over a PathScurry performs a synchronous walk.
|
|
5542
|
+
*
|
|
5543
|
+
* Alias for {@link PathScurryBase.iterateSync}
|
|
5544
|
+
*/
|
|
5545
|
+
[Symbol.iterator]() {
|
|
5546
|
+
return this.iterateSync();
|
|
5547
|
+
}
|
|
5548
|
+
*iterateSync(entry = this.cwd, opts = {}) {
|
|
5549
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5550
|
+
else if (!(entry instanceof PathBase)) {
|
|
5551
|
+
opts = entry;
|
|
5552
|
+
entry = this.cwd;
|
|
5553
|
+
}
|
|
5554
|
+
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
|
|
5555
|
+
if (!filter || filter(entry)) yield withFileTypes ? entry : entry.fullpath();
|
|
5556
|
+
const dirs = new Set([entry]);
|
|
5557
|
+
for (const dir of dirs) {
|
|
5558
|
+
const entries = dir.readdirSync();
|
|
5559
|
+
for (const e of entries) {
|
|
5560
|
+
if (!filter || filter(e)) yield withFileTypes ? e : e.fullpath();
|
|
5561
|
+
let r = e;
|
|
5562
|
+
if (e.isSymbolicLink()) {
|
|
5563
|
+
if (!(follow && (r = e.realpathSync()))) continue;
|
|
5564
|
+
if (r.isUnknown()) r.lstatSync();
|
|
5565
|
+
}
|
|
5566
|
+
if (r.shouldWalk(dirs, walkFilter)) dirs.add(r);
|
|
5567
|
+
}
|
|
5568
|
+
}
|
|
5569
|
+
}
|
|
5570
|
+
stream(entry = this.cwd, opts = {}) {
|
|
5571
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5572
|
+
else if (!(entry instanceof PathBase)) {
|
|
5573
|
+
opts = entry;
|
|
5574
|
+
entry = this.cwd;
|
|
5575
|
+
}
|
|
5576
|
+
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
|
|
5577
|
+
const results = new Minipass({ objectMode: true });
|
|
5578
|
+
if (!filter || filter(entry)) results.write(withFileTypes ? entry : entry.fullpath());
|
|
5579
|
+
const dirs = new Set();
|
|
5580
|
+
const queue = [entry];
|
|
5581
|
+
let processing = 0;
|
|
5582
|
+
const process$1 = () => {
|
|
5583
|
+
let paused = false;
|
|
5584
|
+
while (!paused) {
|
|
5585
|
+
const dir = queue.shift();
|
|
5586
|
+
if (!dir) {
|
|
5587
|
+
if (processing === 0) results.end();
|
|
5588
|
+
return;
|
|
5589
|
+
}
|
|
5590
|
+
processing++;
|
|
5591
|
+
dirs.add(dir);
|
|
5592
|
+
const onReaddir = (er, entries, didRealpaths = false) => {
|
|
5593
|
+
/* c8 ignore start */
|
|
5594
|
+
if (er) return results.emit("error", er);
|
|
5595
|
+
/* c8 ignore stop */
|
|
5596
|
+
if (follow && !didRealpaths) {
|
|
5597
|
+
const promises$1 = [];
|
|
5598
|
+
for (const e of entries) if (e.isSymbolicLink()) promises$1.push(e.realpath().then((r) => r?.isUnknown() ? r.lstat() : r));
|
|
5599
|
+
if (promises$1.length) {
|
|
5600
|
+
Promise.all(promises$1).then(() => onReaddir(null, entries, true));
|
|
5601
|
+
return;
|
|
5602
|
+
}
|
|
5603
|
+
}
|
|
5604
|
+
for (const e of entries) if (e && (!filter || filter(e))) {
|
|
5605
|
+
if (!results.write(withFileTypes ? e : e.fullpath())) paused = true;
|
|
5606
|
+
}
|
|
5607
|
+
processing--;
|
|
5608
|
+
for (const e of entries) {
|
|
5609
|
+
const r = e.realpathCached() || e;
|
|
5610
|
+
if (r.shouldWalk(dirs, walkFilter)) queue.push(r);
|
|
5611
|
+
}
|
|
5612
|
+
if (paused && !results.flowing) results.once("drain", process$1);
|
|
5613
|
+
else if (!sync$1) process$1();
|
|
5614
|
+
};
|
|
5615
|
+
let sync$1 = true;
|
|
5616
|
+
dir.readdirCB(onReaddir, true);
|
|
5617
|
+
sync$1 = false;
|
|
5618
|
+
}
|
|
5619
|
+
};
|
|
5620
|
+
process$1();
|
|
5621
|
+
return results;
|
|
5622
|
+
}
|
|
5623
|
+
streamSync(entry = this.cwd, opts = {}) {
|
|
5624
|
+
if (typeof entry === "string") entry = this.cwd.resolve(entry);
|
|
5625
|
+
else if (!(entry instanceof PathBase)) {
|
|
5626
|
+
opts = entry;
|
|
5627
|
+
entry = this.cwd;
|
|
5628
|
+
}
|
|
5629
|
+
const { withFileTypes = true, follow = false, filter, walkFilter } = opts;
|
|
5630
|
+
const results = new Minipass({ objectMode: true });
|
|
5631
|
+
const dirs = new Set();
|
|
5632
|
+
if (!filter || filter(entry)) results.write(withFileTypes ? entry : entry.fullpath());
|
|
5633
|
+
const queue = [entry];
|
|
5634
|
+
let processing = 0;
|
|
5635
|
+
const process$1 = () => {
|
|
5636
|
+
let paused = false;
|
|
5637
|
+
while (!paused) {
|
|
5638
|
+
const dir = queue.shift();
|
|
5639
|
+
if (!dir) {
|
|
5640
|
+
if (processing === 0) results.end();
|
|
5641
|
+
return;
|
|
5642
|
+
}
|
|
5643
|
+
processing++;
|
|
5644
|
+
dirs.add(dir);
|
|
5645
|
+
const entries = dir.readdirSync();
|
|
5646
|
+
for (const e of entries) if (!filter || filter(e)) {
|
|
5647
|
+
if (!results.write(withFileTypes ? e : e.fullpath())) paused = true;
|
|
5648
|
+
}
|
|
5649
|
+
processing--;
|
|
5650
|
+
for (const e of entries) {
|
|
5651
|
+
let r = e;
|
|
5652
|
+
if (e.isSymbolicLink()) {
|
|
5653
|
+
if (!(follow && (r = e.realpathSync()))) continue;
|
|
5654
|
+
if (r.isUnknown()) r.lstatSync();
|
|
5655
|
+
}
|
|
5656
|
+
if (r.shouldWalk(dirs, walkFilter)) queue.push(r);
|
|
5657
|
+
}
|
|
5658
|
+
}
|
|
5659
|
+
if (paused && !results.flowing) results.once("drain", process$1);
|
|
5660
|
+
};
|
|
5661
|
+
process$1();
|
|
5662
|
+
return results;
|
|
5663
|
+
}
|
|
5664
|
+
chdir(path$4 = this.cwd) {
|
|
5665
|
+
const oldCwd = this.cwd;
|
|
5666
|
+
this.cwd = typeof path$4 === "string" ? this.cwd.resolve(path$4) : path$4;
|
|
5667
|
+
this.cwd[setAsCwd](oldCwd);
|
|
5668
|
+
}
|
|
5669
|
+
};
|
|
5670
|
+
/**
|
|
5671
|
+
* Windows implementation of {@link PathScurryBase}
|
|
5672
|
+
*
|
|
5673
|
+
* Defaults to case insensitve, uses `'\\'` to generate path strings. Uses
|
|
5674
|
+
* {@link PathWin32} for Path objects.
|
|
5675
|
+
*/
|
|
5676
|
+
var PathScurryWin32 = class extends PathScurryBase {
|
|
5677
|
+
/**
|
|
5678
|
+
* separator for generating path strings
|
|
5679
|
+
*/
|
|
5680
|
+
sep = "\\";
|
|
5681
|
+
constructor(cwd = process.cwd(), opts = {}) {
|
|
5682
|
+
const { nocase = true } = opts;
|
|
5683
|
+
super(cwd, win32, "\\", {
|
|
5684
|
+
...opts,
|
|
5685
|
+
nocase
|
|
5686
|
+
});
|
|
5687
|
+
this.nocase = nocase;
|
|
5688
|
+
for (let p = this.cwd; p; p = p.parent) p.nocase = this.nocase;
|
|
5689
|
+
}
|
|
5690
|
+
/**
|
|
5691
|
+
* @internal
|
|
5692
|
+
*/
|
|
5693
|
+
parseRootPath(dir) {
|
|
5694
|
+
return win32.parse(dir).root.toUpperCase();
|
|
5695
|
+
}
|
|
5696
|
+
/**
|
|
5697
|
+
* @internal
|
|
5698
|
+
*/
|
|
5699
|
+
newRoot(fs$1) {
|
|
5700
|
+
return new PathWin32(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs$1 });
|
|
5701
|
+
}
|
|
5702
|
+
/**
|
|
5703
|
+
* Return true if the provided path string is an absolute path
|
|
5704
|
+
*/
|
|
5705
|
+
isAbsolute(p) {
|
|
5706
|
+
return p.startsWith("/") || p.startsWith("\\") || /^[a-z]:(\/|\\)/i.test(p);
|
|
5707
|
+
}
|
|
5708
|
+
};
|
|
5709
|
+
/**
|
|
5710
|
+
* {@link PathScurryBase} implementation for all posix systems other than Darwin.
|
|
5711
|
+
*
|
|
5712
|
+
* Defaults to case-sensitive matching, uses `'/'` to generate path strings.
|
|
5713
|
+
*
|
|
5714
|
+
* Uses {@link PathPosix} for Path objects.
|
|
5715
|
+
*/
|
|
5716
|
+
var PathScurryPosix = class extends PathScurryBase {
|
|
5717
|
+
/**
|
|
5718
|
+
* separator for generating path strings
|
|
5719
|
+
*/
|
|
5720
|
+
sep = "/";
|
|
5721
|
+
constructor(cwd = process.cwd(), opts = {}) {
|
|
5722
|
+
const { nocase = false } = opts;
|
|
5723
|
+
super(cwd, posix, "/", {
|
|
5724
|
+
...opts,
|
|
5725
|
+
nocase
|
|
5726
|
+
});
|
|
5727
|
+
this.nocase = nocase;
|
|
5728
|
+
}
|
|
5729
|
+
/**
|
|
5730
|
+
* @internal
|
|
5731
|
+
*/
|
|
5732
|
+
parseRootPath(_dir) {
|
|
5733
|
+
return "/";
|
|
5734
|
+
}
|
|
5735
|
+
/**
|
|
5736
|
+
* @internal
|
|
5737
|
+
*/
|
|
5738
|
+
newRoot(fs$1) {
|
|
5739
|
+
return new PathPosix(this.rootPath, IFDIR, void 0, this.roots, this.nocase, this.childrenCache(), { fs: fs$1 });
|
|
5740
|
+
}
|
|
5741
|
+
/**
|
|
5742
|
+
* Return true if the provided path string is an absolute path
|
|
5743
|
+
*/
|
|
5744
|
+
isAbsolute(p) {
|
|
5745
|
+
return p.startsWith("/");
|
|
5746
|
+
}
|
|
5747
|
+
};
|
|
5748
|
+
/**
|
|
5749
|
+
* {@link PathScurryBase} implementation for Darwin (macOS) systems.
|
|
5750
|
+
*
|
|
5751
|
+
* Defaults to case-insensitive matching, uses `'/'` for generating path
|
|
5752
|
+
* strings.
|
|
5753
|
+
*
|
|
5754
|
+
* Uses {@link PathPosix} for Path objects.
|
|
5755
|
+
*/
|
|
5756
|
+
var PathScurryDarwin = class extends PathScurryPosix {
|
|
5757
|
+
constructor(cwd = process.cwd(), opts = {}) {
|
|
5758
|
+
const { nocase = true } = opts;
|
|
5759
|
+
super(cwd, {
|
|
5760
|
+
...opts,
|
|
5761
|
+
nocase
|
|
5762
|
+
});
|
|
5763
|
+
}
|
|
5764
|
+
};
|
|
5765
|
+
/**
|
|
5766
|
+
* Default {@link PathBase} implementation for the current platform.
|
|
5767
|
+
*
|
|
5768
|
+
* {@link PathWin32} on Windows systems, {@link PathPosix} on all others.
|
|
5769
|
+
*/
|
|
5770
|
+
const Path = process.platform === "win32" ? PathWin32 : PathPosix;
|
|
5771
|
+
/**
|
|
5772
|
+
* Default {@link PathScurryBase} implementation for the current platform.
|
|
5773
|
+
*
|
|
5774
|
+
* {@link PathScurryWin32} on Windows systems, {@link PathScurryDarwin} on
|
|
5775
|
+
* Darwin (macOS) systems, {@link PathScurryPosix} on all others.
|
|
5776
|
+
*/
|
|
5777
|
+
const PathScurry = process.platform === "win32" ? PathScurryWin32 : process.platform === "darwin" ? PathScurryDarwin : PathScurryPosix;
|
|
5778
|
+
|
|
5779
|
+
//#endregion
|
|
5780
|
+
//#region node_modules/glob/dist/esm/pattern.js
|
|
5781
|
+
const isPatternList = (pl) => pl.length >= 1;
|
|
5782
|
+
const isGlobList = (gl) => gl.length >= 1;
|
|
5783
|
+
/**
|
|
5784
|
+
* An immutable-ish view on an array of glob parts and their parsed
|
|
5785
|
+
* results
|
|
5786
|
+
*/
|
|
5787
|
+
var Pattern = class Pattern {
|
|
5788
|
+
#patternList;
|
|
5789
|
+
#globList;
|
|
5790
|
+
#index;
|
|
5791
|
+
length;
|
|
5792
|
+
#platform;
|
|
5793
|
+
#rest;
|
|
5794
|
+
#globString;
|
|
5795
|
+
#isDrive;
|
|
5796
|
+
#isUNC;
|
|
5797
|
+
#isAbsolute;
|
|
5798
|
+
#followGlobstar = true;
|
|
5799
|
+
constructor(patternList, globList, index, platform) {
|
|
5800
|
+
if (!isPatternList(patternList)) throw new TypeError("empty pattern list");
|
|
5801
|
+
if (!isGlobList(globList)) throw new TypeError("empty glob list");
|
|
5802
|
+
if (globList.length !== patternList.length) throw new TypeError("mismatched pattern list and glob list lengths");
|
|
5803
|
+
this.length = patternList.length;
|
|
5804
|
+
if (index < 0 || index >= this.length) throw new TypeError("index out of range");
|
|
5805
|
+
this.#patternList = patternList;
|
|
5806
|
+
this.#globList = globList;
|
|
5807
|
+
this.#index = index;
|
|
5808
|
+
this.#platform = platform;
|
|
5809
|
+
if (this.#index === 0) {
|
|
5810
|
+
if (this.isUNC()) {
|
|
5811
|
+
const [p0, p1, p2, p3, ...prest] = this.#patternList;
|
|
5812
|
+
const [g0, g1, g2, g3, ...grest] = this.#globList;
|
|
5813
|
+
if (prest[0] === "") {
|
|
5814
|
+
prest.shift();
|
|
5815
|
+
grest.shift();
|
|
5816
|
+
}
|
|
5817
|
+
const p = [
|
|
5818
|
+
p0,
|
|
5819
|
+
p1,
|
|
5820
|
+
p2,
|
|
5821
|
+
p3,
|
|
5822
|
+
""
|
|
5823
|
+
].join("/");
|
|
5824
|
+
const g = [
|
|
5825
|
+
g0,
|
|
5826
|
+
g1,
|
|
5827
|
+
g2,
|
|
5828
|
+
g3,
|
|
5829
|
+
""
|
|
5830
|
+
].join("/");
|
|
5831
|
+
this.#patternList = [p, ...prest];
|
|
5832
|
+
this.#globList = [g, ...grest];
|
|
5833
|
+
this.length = this.#patternList.length;
|
|
5834
|
+
} else if (this.isDrive() || this.isAbsolute()) {
|
|
5835
|
+
const [p1, ...prest] = this.#patternList;
|
|
5836
|
+
const [g1, ...grest] = this.#globList;
|
|
5837
|
+
if (prest[0] === "") {
|
|
5838
|
+
prest.shift();
|
|
5839
|
+
grest.shift();
|
|
5840
|
+
}
|
|
5841
|
+
const p = p1 + "/";
|
|
5842
|
+
const g = g1 + "/";
|
|
5843
|
+
this.#patternList = [p, ...prest];
|
|
5844
|
+
this.#globList = [g, ...grest];
|
|
5845
|
+
this.length = this.#patternList.length;
|
|
5846
|
+
}
|
|
5847
|
+
}
|
|
5848
|
+
}
|
|
5849
|
+
/**
|
|
5850
|
+
* The first entry in the parsed list of patterns
|
|
5851
|
+
*/
|
|
5852
|
+
pattern() {
|
|
5853
|
+
return this.#patternList[this.#index];
|
|
5854
|
+
}
|
|
5855
|
+
/**
|
|
5856
|
+
* true of if pattern() returns a string
|
|
5857
|
+
*/
|
|
5858
|
+
isString() {
|
|
5859
|
+
return typeof this.#patternList[this.#index] === "string";
|
|
5860
|
+
}
|
|
5861
|
+
/**
|
|
5862
|
+
* true of if pattern() returns GLOBSTAR
|
|
5863
|
+
*/
|
|
5864
|
+
isGlobstar() {
|
|
5865
|
+
return this.#patternList[this.#index] === GLOBSTAR;
|
|
5866
|
+
}
|
|
5867
|
+
/**
|
|
5868
|
+
* true if pattern() returns a regexp
|
|
5869
|
+
*/
|
|
5870
|
+
isRegExp() {
|
|
5871
|
+
return this.#patternList[this.#index] instanceof RegExp;
|
|
5872
|
+
}
|
|
5873
|
+
/**
|
|
5874
|
+
* The /-joined set of glob parts that make up this pattern
|
|
5875
|
+
*/
|
|
5876
|
+
globString() {
|
|
5877
|
+
return this.#globString = this.#globString || (this.#index === 0 ? this.isAbsolute() ? this.#globList[0] + this.#globList.slice(1).join("/") : this.#globList.join("/") : this.#globList.slice(this.#index).join("/"));
|
|
5878
|
+
}
|
|
5879
|
+
/**
|
|
5880
|
+
* true if there are more pattern parts after this one
|
|
5881
|
+
*/
|
|
5882
|
+
hasMore() {
|
|
5883
|
+
return this.length > this.#index + 1;
|
|
5884
|
+
}
|
|
5885
|
+
/**
|
|
5886
|
+
* The rest of the pattern after this part, or null if this is the end
|
|
5887
|
+
*/
|
|
5888
|
+
rest() {
|
|
5889
|
+
if (this.#rest !== void 0) return this.#rest;
|
|
5890
|
+
if (!this.hasMore()) return this.#rest = null;
|
|
5891
|
+
this.#rest = new Pattern(this.#patternList, this.#globList, this.#index + 1, this.#platform);
|
|
5892
|
+
this.#rest.#isAbsolute = this.#isAbsolute;
|
|
5893
|
+
this.#rest.#isUNC = this.#isUNC;
|
|
5894
|
+
this.#rest.#isDrive = this.#isDrive;
|
|
5895
|
+
return this.#rest;
|
|
5896
|
+
}
|
|
5897
|
+
/**
|
|
5898
|
+
* true if the pattern represents a //unc/path/ on windows
|
|
5899
|
+
*/
|
|
5900
|
+
isUNC() {
|
|
5901
|
+
const pl = this.#patternList;
|
|
5902
|
+
return this.#isUNC !== void 0 ? this.#isUNC : this.#isUNC = this.#platform === "win32" && this.#index === 0 && pl[0] === "" && pl[1] === "" && typeof pl[2] === "string" && !!pl[2] && typeof pl[3] === "string" && !!pl[3];
|
|
5903
|
+
}
|
|
5904
|
+
/**
|
|
5905
|
+
* True if the pattern starts with a drive letter on Windows
|
|
5906
|
+
*/
|
|
5907
|
+
isDrive() {
|
|
5908
|
+
const pl = this.#patternList;
|
|
5909
|
+
return this.#isDrive !== void 0 ? this.#isDrive : this.#isDrive = this.#platform === "win32" && this.#index === 0 && this.length > 1 && typeof pl[0] === "string" && /^[a-z]:$/i.test(pl[0]);
|
|
5910
|
+
}
|
|
5911
|
+
/**
|
|
5912
|
+
* True if the pattern is rooted on an absolute path
|
|
5913
|
+
*/
|
|
5914
|
+
isAbsolute() {
|
|
5915
|
+
const pl = this.#patternList;
|
|
5916
|
+
return this.#isAbsolute !== void 0 ? this.#isAbsolute : this.#isAbsolute = pl[0] === "" && pl.length > 1 || this.isDrive() || this.isUNC();
|
|
5917
|
+
}
|
|
5918
|
+
/**
|
|
5919
|
+
* consume the root of the pattern, and return it
|
|
5920
|
+
*/
|
|
5921
|
+
root() {
|
|
5922
|
+
const p = this.#patternList[0];
|
|
5923
|
+
return typeof p === "string" && this.isAbsolute() && this.#index === 0 ? p : "";
|
|
5924
|
+
}
|
|
5925
|
+
/**
|
|
5926
|
+
* Check to see if the current globstar pattern is allowed to follow
|
|
5927
|
+
* a symbolic link.
|
|
5928
|
+
*/
|
|
5929
|
+
checkFollowGlobstar() {
|
|
5930
|
+
return !(this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar);
|
|
5931
|
+
}
|
|
5932
|
+
/**
|
|
5933
|
+
* Mark that the current globstar pattern is following a symbolic link
|
|
5934
|
+
*/
|
|
5935
|
+
markFollowGlobstar() {
|
|
5936
|
+
if (this.#index === 0 || !this.isGlobstar() || !this.#followGlobstar) return false;
|
|
5937
|
+
this.#followGlobstar = false;
|
|
5938
|
+
return true;
|
|
5939
|
+
}
|
|
5940
|
+
};
|
|
5941
|
+
|
|
5942
|
+
//#endregion
|
|
5943
|
+
//#region node_modules/glob/dist/esm/ignore.js
|
|
5944
|
+
const defaultPlatform$1 = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
5945
|
+
/**
|
|
5946
|
+
* Class used to process ignored patterns
|
|
5947
|
+
*/
|
|
5948
|
+
var Ignore = class {
|
|
5949
|
+
relative;
|
|
5950
|
+
relativeChildren;
|
|
5951
|
+
absolute;
|
|
5952
|
+
absoluteChildren;
|
|
5953
|
+
platform;
|
|
5954
|
+
mmopts;
|
|
5955
|
+
constructor(ignored, { nobrace, nocase, noext, noglobstar, platform = defaultPlatform$1 }) {
|
|
5956
|
+
this.relative = [];
|
|
5957
|
+
this.absolute = [];
|
|
5958
|
+
this.relativeChildren = [];
|
|
5959
|
+
this.absoluteChildren = [];
|
|
5960
|
+
this.platform = platform;
|
|
5961
|
+
this.mmopts = {
|
|
5962
|
+
dot: true,
|
|
5963
|
+
nobrace,
|
|
5964
|
+
nocase,
|
|
5965
|
+
noext,
|
|
5966
|
+
noglobstar,
|
|
5967
|
+
optimizationLevel: 2,
|
|
5968
|
+
platform,
|
|
5969
|
+
nocomment: true,
|
|
5970
|
+
nonegate: true
|
|
5971
|
+
};
|
|
5972
|
+
for (const ign of ignored) this.add(ign);
|
|
5973
|
+
}
|
|
5974
|
+
add(ign) {
|
|
5975
|
+
const mm = new Minimatch(ign, this.mmopts);
|
|
5976
|
+
for (let i = 0; i < mm.set.length; i++) {
|
|
5977
|
+
const parsed = mm.set[i];
|
|
5978
|
+
const globParts = mm.globParts[i];
|
|
5979
|
+
/* c8 ignore start */
|
|
5980
|
+
if (!parsed || !globParts) throw new Error("invalid pattern object");
|
|
5981
|
+
while (parsed[0] === "." && globParts[0] === ".") {
|
|
5982
|
+
parsed.shift();
|
|
5983
|
+
globParts.shift();
|
|
5984
|
+
}
|
|
5985
|
+
/* c8 ignore stop */
|
|
5986
|
+
const p = new Pattern(parsed, globParts, 0, this.platform);
|
|
5987
|
+
const m = new Minimatch(p.globString(), this.mmopts);
|
|
5988
|
+
const children = globParts[globParts.length - 1] === "**";
|
|
5989
|
+
const absolute = p.isAbsolute();
|
|
5990
|
+
if (absolute) this.absolute.push(m);
|
|
5991
|
+
else this.relative.push(m);
|
|
5992
|
+
if (children) if (absolute) this.absoluteChildren.push(m);
|
|
5993
|
+
else this.relativeChildren.push(m);
|
|
5994
|
+
}
|
|
5995
|
+
}
|
|
5996
|
+
ignored(p) {
|
|
5997
|
+
const fullpath = p.fullpath();
|
|
5998
|
+
const fullpaths = `${fullpath}/`;
|
|
5999
|
+
const relative$1 = p.relative() || ".";
|
|
6000
|
+
const relatives = `${relative$1}/`;
|
|
6001
|
+
for (const m of this.relative) if (m.match(relative$1) || m.match(relatives)) return true;
|
|
6002
|
+
for (const m of this.absolute) if (m.match(fullpath) || m.match(fullpaths)) return true;
|
|
6003
|
+
return false;
|
|
6004
|
+
}
|
|
6005
|
+
childrenIgnored(p) {
|
|
6006
|
+
const fullpath = p.fullpath() + "/";
|
|
6007
|
+
const relative$1 = (p.relative() || ".") + "/";
|
|
6008
|
+
for (const m of this.relativeChildren) if (m.match(relative$1)) return true;
|
|
6009
|
+
for (const m of this.absoluteChildren) if (m.match(fullpath)) return true;
|
|
6010
|
+
return false;
|
|
6011
|
+
}
|
|
6012
|
+
};
|
|
6013
|
+
|
|
6014
|
+
//#endregion
|
|
6015
|
+
//#region node_modules/glob/dist/esm/processor.js
|
|
6016
|
+
/**
|
|
6017
|
+
* A cache of which patterns have been processed for a given Path
|
|
6018
|
+
*/
|
|
6019
|
+
var HasWalkedCache = class HasWalkedCache {
|
|
6020
|
+
store;
|
|
6021
|
+
constructor(store = new Map()) {
|
|
6022
|
+
this.store = store;
|
|
6023
|
+
}
|
|
6024
|
+
copy() {
|
|
6025
|
+
return new HasWalkedCache(new Map(this.store));
|
|
6026
|
+
}
|
|
6027
|
+
hasWalked(target, pattern) {
|
|
6028
|
+
return this.store.get(target.fullpath())?.has(pattern.globString());
|
|
6029
|
+
}
|
|
6030
|
+
storeWalked(target, pattern) {
|
|
6031
|
+
const fullpath = target.fullpath();
|
|
6032
|
+
const cached = this.store.get(fullpath);
|
|
6033
|
+
if (cached) cached.add(pattern.globString());
|
|
6034
|
+
else this.store.set(fullpath, new Set([pattern.globString()]));
|
|
6035
|
+
}
|
|
6036
|
+
};
|
|
6037
|
+
/**
|
|
6038
|
+
* A record of which paths have been matched in a given walk step,
|
|
6039
|
+
* and whether they only are considered a match if they are a directory,
|
|
6040
|
+
* and whether their absolute or relative path should be returned.
|
|
6041
|
+
*/
|
|
6042
|
+
var MatchRecord = class {
|
|
6043
|
+
store = new Map();
|
|
6044
|
+
add(target, absolute, ifDir) {
|
|
6045
|
+
const n = (absolute ? 2 : 0) | (ifDir ? 1 : 0);
|
|
6046
|
+
const current = this.store.get(target);
|
|
6047
|
+
this.store.set(target, current === void 0 ? n : n & current);
|
|
6048
|
+
}
|
|
6049
|
+
entries() {
|
|
6050
|
+
return [...this.store.entries()].map(([path$4, n]) => [
|
|
6051
|
+
path$4,
|
|
6052
|
+
!!(n & 2),
|
|
6053
|
+
!!(n & 1)
|
|
6054
|
+
]);
|
|
6055
|
+
}
|
|
6056
|
+
};
|
|
6057
|
+
/**
|
|
6058
|
+
* A collection of patterns that must be processed in a subsequent step
|
|
6059
|
+
* for a given path.
|
|
6060
|
+
*/
|
|
6061
|
+
var SubWalks = class {
|
|
6062
|
+
store = new Map();
|
|
6063
|
+
add(target, pattern) {
|
|
6064
|
+
if (!target.canReaddir()) return;
|
|
6065
|
+
const subs = this.store.get(target);
|
|
6066
|
+
if (subs) {
|
|
6067
|
+
if (!subs.find((p) => p.globString() === pattern.globString())) subs.push(pattern);
|
|
6068
|
+
} else this.store.set(target, [pattern]);
|
|
6069
|
+
}
|
|
6070
|
+
get(target) {
|
|
6071
|
+
const subs = this.store.get(target);
|
|
6072
|
+
/* c8 ignore start */
|
|
6073
|
+
if (!subs) throw new Error("attempting to walk unknown path");
|
|
6074
|
+
/* c8 ignore stop */
|
|
6075
|
+
return subs;
|
|
6076
|
+
}
|
|
6077
|
+
entries() {
|
|
6078
|
+
return this.keys().map((k) => [k, this.store.get(k)]);
|
|
6079
|
+
}
|
|
6080
|
+
keys() {
|
|
6081
|
+
return [...this.store.keys()].filter((t) => t.canReaddir());
|
|
6082
|
+
}
|
|
6083
|
+
};
|
|
6084
|
+
/**
|
|
6085
|
+
* The class that processes patterns for a given path.
|
|
6086
|
+
*
|
|
6087
|
+
* Handles child entry filtering, and determining whether a path's
|
|
6088
|
+
* directory contents must be read.
|
|
6089
|
+
*/
|
|
6090
|
+
var Processor = class Processor {
|
|
6091
|
+
hasWalkedCache;
|
|
6092
|
+
matches = new MatchRecord();
|
|
6093
|
+
subwalks = new SubWalks();
|
|
6094
|
+
patterns;
|
|
6095
|
+
follow;
|
|
6096
|
+
dot;
|
|
6097
|
+
opts;
|
|
6098
|
+
constructor(opts, hasWalkedCache) {
|
|
6099
|
+
this.opts = opts;
|
|
6100
|
+
this.follow = !!opts.follow;
|
|
6101
|
+
this.dot = !!opts.dot;
|
|
6102
|
+
this.hasWalkedCache = hasWalkedCache ? hasWalkedCache.copy() : new HasWalkedCache();
|
|
6103
|
+
}
|
|
6104
|
+
processPatterns(target, patterns) {
|
|
6105
|
+
this.patterns = patterns;
|
|
6106
|
+
const processingSet = patterns.map((p) => [target, p]);
|
|
6107
|
+
for (let [t, pattern] of processingSet) {
|
|
6108
|
+
this.hasWalkedCache.storeWalked(t, pattern);
|
|
6109
|
+
const root = pattern.root();
|
|
6110
|
+
const absolute = pattern.isAbsolute() && this.opts.absolute !== false;
|
|
6111
|
+
if (root) {
|
|
6112
|
+
t = t.resolve(root === "/" && this.opts.root !== void 0 ? this.opts.root : root);
|
|
6113
|
+
const rest$1 = pattern.rest();
|
|
6114
|
+
if (!rest$1) {
|
|
6115
|
+
this.matches.add(t, true, false);
|
|
6116
|
+
continue;
|
|
6117
|
+
} else pattern = rest$1;
|
|
6118
|
+
}
|
|
6119
|
+
if (t.isENOENT()) continue;
|
|
6120
|
+
let p;
|
|
6121
|
+
let rest;
|
|
6122
|
+
let changed = false;
|
|
6123
|
+
while (typeof (p = pattern.pattern()) === "string" && (rest = pattern.rest())) {
|
|
6124
|
+
const c = t.resolve(p);
|
|
6125
|
+
t = c;
|
|
6126
|
+
pattern = rest;
|
|
6127
|
+
changed = true;
|
|
6128
|
+
}
|
|
6129
|
+
p = pattern.pattern();
|
|
6130
|
+
rest = pattern.rest();
|
|
6131
|
+
if (changed) {
|
|
6132
|
+
if (this.hasWalkedCache.hasWalked(t, pattern)) continue;
|
|
6133
|
+
this.hasWalkedCache.storeWalked(t, pattern);
|
|
6134
|
+
}
|
|
6135
|
+
if (typeof p === "string") {
|
|
6136
|
+
const ifDir = p === ".." || p === "" || p === ".";
|
|
6137
|
+
this.matches.add(t.resolve(p), absolute, ifDir);
|
|
6138
|
+
continue;
|
|
6139
|
+
} else if (p === GLOBSTAR) {
|
|
6140
|
+
if (!t.isSymbolicLink() || this.follow || pattern.checkFollowGlobstar()) this.subwalks.add(t, pattern);
|
|
6141
|
+
const rp = rest?.pattern();
|
|
6142
|
+
const rrest = rest?.rest();
|
|
6143
|
+
if (!rest || (rp === "" || rp === ".") && !rrest) this.matches.add(t, absolute, rp === "" || rp === ".");
|
|
6144
|
+
else if (rp === "..") {
|
|
6145
|
+
/* c8 ignore start */
|
|
6146
|
+
const tp = t.parent || t;
|
|
6147
|
+
/* c8 ignore stop */
|
|
6148
|
+
if (!rrest) this.matches.add(tp, absolute, true);
|
|
6149
|
+
else if (!this.hasWalkedCache.hasWalked(tp, rrest)) this.subwalks.add(tp, rrest);
|
|
6150
|
+
}
|
|
6151
|
+
} else if (p instanceof RegExp) this.subwalks.add(t, pattern);
|
|
6152
|
+
}
|
|
6153
|
+
return this;
|
|
6154
|
+
}
|
|
6155
|
+
subwalkTargets() {
|
|
6156
|
+
return this.subwalks.keys();
|
|
6157
|
+
}
|
|
6158
|
+
child() {
|
|
6159
|
+
return new Processor(this.opts, this.hasWalkedCache);
|
|
6160
|
+
}
|
|
6161
|
+
filterEntries(parent, entries) {
|
|
6162
|
+
const patterns = this.subwalks.get(parent);
|
|
6163
|
+
const results = this.child();
|
|
6164
|
+
for (const e of entries) for (const pattern of patterns) {
|
|
6165
|
+
const absolute = pattern.isAbsolute();
|
|
6166
|
+
const p = pattern.pattern();
|
|
6167
|
+
const rest = pattern.rest();
|
|
6168
|
+
if (p === GLOBSTAR) results.testGlobstar(e, pattern, rest, absolute);
|
|
6169
|
+
else if (p instanceof RegExp) results.testRegExp(e, p, rest, absolute);
|
|
6170
|
+
else results.testString(e, p, rest, absolute);
|
|
6171
|
+
}
|
|
6172
|
+
return results;
|
|
6173
|
+
}
|
|
6174
|
+
testGlobstar(e, pattern, rest, absolute) {
|
|
6175
|
+
if (this.dot || !e.name.startsWith(".")) {
|
|
6176
|
+
if (!pattern.hasMore()) this.matches.add(e, absolute, false);
|
|
6177
|
+
if (e.canReaddir()) {
|
|
6178
|
+
if (this.follow || !e.isSymbolicLink()) this.subwalks.add(e, pattern);
|
|
6179
|
+
else if (e.isSymbolicLink()) {
|
|
6180
|
+
if (rest && pattern.checkFollowGlobstar()) this.subwalks.add(e, rest);
|
|
6181
|
+
else if (pattern.markFollowGlobstar()) this.subwalks.add(e, pattern);
|
|
6182
|
+
}
|
|
6183
|
+
}
|
|
6184
|
+
}
|
|
6185
|
+
if (rest) {
|
|
6186
|
+
const rp = rest.pattern();
|
|
6187
|
+
if (typeof rp === "string" && rp !== ".." && rp !== "" && rp !== ".") this.testString(e, rp, rest.rest(), absolute);
|
|
6188
|
+
else if (rp === "..") {
|
|
6189
|
+
/* c8 ignore start */
|
|
6190
|
+
const ep = e.parent || e;
|
|
6191
|
+
/* c8 ignore stop */
|
|
6192
|
+
this.subwalks.add(ep, rest);
|
|
6193
|
+
} else if (rp instanceof RegExp) this.testRegExp(e, rp, rest.rest(), absolute);
|
|
6194
|
+
}
|
|
6195
|
+
}
|
|
6196
|
+
testRegExp(e, p, rest, absolute) {
|
|
6197
|
+
if (!p.test(e.name)) return;
|
|
6198
|
+
if (!rest) this.matches.add(e, absolute, false);
|
|
6199
|
+
else this.subwalks.add(e, rest);
|
|
6200
|
+
}
|
|
6201
|
+
testString(e, p, rest, absolute) {
|
|
6202
|
+
if (!e.isNamed(p)) return;
|
|
6203
|
+
if (!rest) this.matches.add(e, absolute, false);
|
|
6204
|
+
else this.subwalks.add(e, rest);
|
|
6205
|
+
}
|
|
6206
|
+
};
|
|
6207
|
+
|
|
6208
|
+
//#endregion
|
|
6209
|
+
//#region node_modules/glob/dist/esm/walker.js
|
|
6210
|
+
const makeIgnore = (ignore, opts) => typeof ignore === "string" ? new Ignore([ignore], opts) : Array.isArray(ignore) ? new Ignore(ignore, opts) : ignore;
|
|
6211
|
+
/**
|
|
6212
|
+
* basic walking utilities that all the glob walker types use
|
|
6213
|
+
*/
|
|
6214
|
+
var GlobUtil = class {
|
|
6215
|
+
path;
|
|
6216
|
+
patterns;
|
|
6217
|
+
opts;
|
|
6218
|
+
seen = new Set();
|
|
6219
|
+
paused = false;
|
|
6220
|
+
aborted = false;
|
|
6221
|
+
#onResume = [];
|
|
6222
|
+
#ignore;
|
|
6223
|
+
#sep;
|
|
6224
|
+
signal;
|
|
6225
|
+
maxDepth;
|
|
6226
|
+
includeChildMatches;
|
|
6227
|
+
constructor(patterns, path$4, opts) {
|
|
6228
|
+
this.patterns = patterns;
|
|
6229
|
+
this.path = path$4;
|
|
6230
|
+
this.opts = opts;
|
|
6231
|
+
this.#sep = !opts.posix && opts.platform === "win32" ? "\\" : "/";
|
|
6232
|
+
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
6233
|
+
if (opts.ignore || !this.includeChildMatches) {
|
|
6234
|
+
this.#ignore = makeIgnore(opts.ignore ?? [], opts);
|
|
6235
|
+
if (!this.includeChildMatches && typeof this.#ignore.add !== "function") {
|
|
6236
|
+
const m = "cannot ignore child matches, ignore lacks add() method.";
|
|
6237
|
+
throw new Error(m);
|
|
6238
|
+
}
|
|
6239
|
+
}
|
|
6240
|
+
/* c8 ignore start */
|
|
6241
|
+
this.maxDepth = opts.maxDepth || Infinity;
|
|
6242
|
+
/* c8 ignore stop */
|
|
6243
|
+
if (opts.signal) {
|
|
6244
|
+
this.signal = opts.signal;
|
|
6245
|
+
this.signal.addEventListener("abort", () => {
|
|
6246
|
+
this.#onResume.length = 0;
|
|
6247
|
+
});
|
|
6248
|
+
}
|
|
6249
|
+
}
|
|
6250
|
+
#ignored(path$4) {
|
|
6251
|
+
return this.seen.has(path$4) || !!this.#ignore?.ignored?.(path$4);
|
|
6252
|
+
}
|
|
6253
|
+
#childrenIgnored(path$4) {
|
|
6254
|
+
return !!this.#ignore?.childrenIgnored?.(path$4);
|
|
6255
|
+
}
|
|
6256
|
+
pause() {
|
|
6257
|
+
this.paused = true;
|
|
6258
|
+
}
|
|
6259
|
+
resume() {
|
|
6260
|
+
/* c8 ignore start */
|
|
6261
|
+
if (this.signal?.aborted) return;
|
|
6262
|
+
/* c8 ignore stop */
|
|
6263
|
+
this.paused = false;
|
|
6264
|
+
let fn = void 0;
|
|
6265
|
+
while (!this.paused && (fn = this.#onResume.shift())) fn();
|
|
6266
|
+
}
|
|
6267
|
+
onResume(fn) {
|
|
6268
|
+
if (this.signal?.aborted) return;
|
|
6269
|
+
/* c8 ignore start */
|
|
6270
|
+
if (!this.paused) fn();
|
|
6271
|
+
else
|
|
6272
|
+
/* c8 ignore stop */
|
|
6273
|
+
this.#onResume.push(fn);
|
|
6274
|
+
}
|
|
6275
|
+
async matchCheck(e, ifDir) {
|
|
6276
|
+
if (ifDir && this.opts.nodir) return void 0;
|
|
6277
|
+
let rpc;
|
|
6278
|
+
if (this.opts.realpath) {
|
|
6279
|
+
rpc = e.realpathCached() || await e.realpath();
|
|
6280
|
+
if (!rpc) return void 0;
|
|
6281
|
+
e = rpc;
|
|
6282
|
+
}
|
|
6283
|
+
const needStat = e.isUnknown() || this.opts.stat;
|
|
6284
|
+
const s = needStat ? await e.lstat() : e;
|
|
6285
|
+
if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
|
|
6286
|
+
const target = await s.realpath();
|
|
6287
|
+
/* c8 ignore start */
|
|
6288
|
+
if (target && (target.isUnknown() || this.opts.stat)) await target.lstat();
|
|
6289
|
+
}
|
|
6290
|
+
return this.matchCheckTest(s, ifDir);
|
|
6291
|
+
}
|
|
6292
|
+
matchCheckTest(e, ifDir) {
|
|
6293
|
+
return e && (this.maxDepth === Infinity || e.depth() <= this.maxDepth) && (!ifDir || e.canReaddir()) && (!this.opts.nodir || !e.isDirectory()) && (!this.opts.nodir || !this.opts.follow || !e.isSymbolicLink() || !e.realpathCached()?.isDirectory()) && !this.#ignored(e) ? e : void 0;
|
|
6294
|
+
}
|
|
6295
|
+
matchCheckSync(e, ifDir) {
|
|
6296
|
+
if (ifDir && this.opts.nodir) return void 0;
|
|
6297
|
+
let rpc;
|
|
6298
|
+
if (this.opts.realpath) {
|
|
6299
|
+
rpc = e.realpathCached() || e.realpathSync();
|
|
6300
|
+
if (!rpc) return void 0;
|
|
6301
|
+
e = rpc;
|
|
6302
|
+
}
|
|
6303
|
+
const needStat = e.isUnknown() || this.opts.stat;
|
|
6304
|
+
const s = needStat ? e.lstatSync() : e;
|
|
6305
|
+
if (this.opts.follow && this.opts.nodir && s?.isSymbolicLink()) {
|
|
6306
|
+
const target = s.realpathSync();
|
|
6307
|
+
if (target && (target?.isUnknown() || this.opts.stat)) target.lstatSync();
|
|
6308
|
+
}
|
|
6309
|
+
return this.matchCheckTest(s, ifDir);
|
|
6310
|
+
}
|
|
6311
|
+
matchFinish(e, absolute) {
|
|
6312
|
+
if (this.#ignored(e)) return;
|
|
6313
|
+
if (!this.includeChildMatches && this.#ignore?.add) {
|
|
6314
|
+
const ign = `${e.relativePosix()}/**`;
|
|
6315
|
+
this.#ignore.add(ign);
|
|
6316
|
+
}
|
|
6317
|
+
const abs = this.opts.absolute === void 0 ? absolute : this.opts.absolute;
|
|
6318
|
+
this.seen.add(e);
|
|
6319
|
+
const mark = this.opts.mark && e.isDirectory() ? this.#sep : "";
|
|
6320
|
+
if (this.opts.withFileTypes) this.matchEmit(e);
|
|
6321
|
+
else if (abs) {
|
|
6322
|
+
const abs$1 = this.opts.posix ? e.fullpathPosix() : e.fullpath();
|
|
6323
|
+
this.matchEmit(abs$1 + mark);
|
|
6324
|
+
} else {
|
|
6325
|
+
const rel = this.opts.posix ? e.relativePosix() : e.relative();
|
|
6326
|
+
const pre = this.opts.dotRelative && !rel.startsWith(".." + this.#sep) ? "." + this.#sep : "";
|
|
6327
|
+
this.matchEmit(!rel ? "." + mark : pre + rel + mark);
|
|
6328
|
+
}
|
|
6329
|
+
}
|
|
6330
|
+
async match(e, absolute, ifDir) {
|
|
6331
|
+
const p = await this.matchCheck(e, ifDir);
|
|
6332
|
+
if (p) this.matchFinish(p, absolute);
|
|
6333
|
+
}
|
|
6334
|
+
matchSync(e, absolute, ifDir) {
|
|
6335
|
+
const p = this.matchCheckSync(e, ifDir);
|
|
6336
|
+
if (p) this.matchFinish(p, absolute);
|
|
6337
|
+
}
|
|
6338
|
+
walkCB(target, patterns, cb) {
|
|
6339
|
+
/* c8 ignore start */
|
|
6340
|
+
if (this.signal?.aborted) cb();
|
|
6341
|
+
/* c8 ignore stop */
|
|
6342
|
+
this.walkCB2(target, patterns, new Processor(this.opts), cb);
|
|
6343
|
+
}
|
|
6344
|
+
walkCB2(target, patterns, processor, cb) {
|
|
6345
|
+
if (this.#childrenIgnored(target)) return cb();
|
|
6346
|
+
if (this.signal?.aborted) cb();
|
|
6347
|
+
if (this.paused) {
|
|
6348
|
+
this.onResume(() => this.walkCB2(target, patterns, processor, cb));
|
|
6349
|
+
return;
|
|
6350
|
+
}
|
|
6351
|
+
processor.processPatterns(target, patterns);
|
|
6352
|
+
let tasks = 1;
|
|
6353
|
+
const next = () => {
|
|
6354
|
+
if (--tasks === 0) cb();
|
|
6355
|
+
};
|
|
6356
|
+
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
|
6357
|
+
if (this.#ignored(m)) continue;
|
|
6358
|
+
tasks++;
|
|
6359
|
+
this.match(m, absolute, ifDir).then(() => next());
|
|
6360
|
+
}
|
|
6361
|
+
for (const t of processor.subwalkTargets()) {
|
|
6362
|
+
if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) continue;
|
|
6363
|
+
tasks++;
|
|
6364
|
+
const childrenCached = t.readdirCached();
|
|
6365
|
+
if (t.calledReaddir()) this.walkCB3(t, childrenCached, processor, next);
|
|
6366
|
+
else t.readdirCB((_, entries) => this.walkCB3(t, entries, processor, next), true);
|
|
6367
|
+
}
|
|
6368
|
+
next();
|
|
6369
|
+
}
|
|
6370
|
+
walkCB3(target, entries, processor, cb) {
|
|
6371
|
+
processor = processor.filterEntries(target, entries);
|
|
6372
|
+
let tasks = 1;
|
|
6373
|
+
const next = () => {
|
|
6374
|
+
if (--tasks === 0) cb();
|
|
6375
|
+
};
|
|
6376
|
+
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
|
6377
|
+
if (this.#ignored(m)) continue;
|
|
6378
|
+
tasks++;
|
|
6379
|
+
this.match(m, absolute, ifDir).then(() => next());
|
|
6380
|
+
}
|
|
6381
|
+
for (const [target$1, patterns] of processor.subwalks.entries()) {
|
|
6382
|
+
tasks++;
|
|
6383
|
+
this.walkCB2(target$1, patterns, processor.child(), next);
|
|
6384
|
+
}
|
|
6385
|
+
next();
|
|
6386
|
+
}
|
|
6387
|
+
walkCBSync(target, patterns, cb) {
|
|
6388
|
+
/* c8 ignore start */
|
|
6389
|
+
if (this.signal?.aborted) cb();
|
|
6390
|
+
/* c8 ignore stop */
|
|
6391
|
+
this.walkCB2Sync(target, patterns, new Processor(this.opts), cb);
|
|
6392
|
+
}
|
|
6393
|
+
walkCB2Sync(target, patterns, processor, cb) {
|
|
6394
|
+
if (this.#childrenIgnored(target)) return cb();
|
|
6395
|
+
if (this.signal?.aborted) cb();
|
|
6396
|
+
if (this.paused) {
|
|
6397
|
+
this.onResume(() => this.walkCB2Sync(target, patterns, processor, cb));
|
|
6398
|
+
return;
|
|
6399
|
+
}
|
|
6400
|
+
processor.processPatterns(target, patterns);
|
|
6401
|
+
let tasks = 1;
|
|
6402
|
+
const next = () => {
|
|
6403
|
+
if (--tasks === 0) cb();
|
|
6404
|
+
};
|
|
6405
|
+
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
|
6406
|
+
if (this.#ignored(m)) continue;
|
|
6407
|
+
this.matchSync(m, absolute, ifDir);
|
|
6408
|
+
}
|
|
6409
|
+
for (const t of processor.subwalkTargets()) {
|
|
6410
|
+
if (this.maxDepth !== Infinity && t.depth() >= this.maxDepth) continue;
|
|
6411
|
+
tasks++;
|
|
6412
|
+
const children = t.readdirSync();
|
|
6413
|
+
this.walkCB3Sync(t, children, processor, next);
|
|
6414
|
+
}
|
|
6415
|
+
next();
|
|
6416
|
+
}
|
|
6417
|
+
walkCB3Sync(target, entries, processor, cb) {
|
|
6418
|
+
processor = processor.filterEntries(target, entries);
|
|
6419
|
+
let tasks = 1;
|
|
6420
|
+
const next = () => {
|
|
6421
|
+
if (--tasks === 0) cb();
|
|
6422
|
+
};
|
|
6423
|
+
for (const [m, absolute, ifDir] of processor.matches.entries()) {
|
|
6424
|
+
if (this.#ignored(m)) continue;
|
|
6425
|
+
this.matchSync(m, absolute, ifDir);
|
|
6426
|
+
}
|
|
6427
|
+
for (const [target$1, patterns] of processor.subwalks.entries()) {
|
|
6428
|
+
tasks++;
|
|
6429
|
+
this.walkCB2Sync(target$1, patterns, processor.child(), next);
|
|
6430
|
+
}
|
|
6431
|
+
next();
|
|
6432
|
+
}
|
|
6433
|
+
};
|
|
6434
|
+
var GlobWalker = class extends GlobUtil {
|
|
6435
|
+
matches = new Set();
|
|
6436
|
+
constructor(patterns, path$4, opts) {
|
|
6437
|
+
super(patterns, path$4, opts);
|
|
6438
|
+
}
|
|
6439
|
+
matchEmit(e) {
|
|
6440
|
+
this.matches.add(e);
|
|
6441
|
+
}
|
|
6442
|
+
async walk() {
|
|
6443
|
+
if (this.signal?.aborted) throw this.signal.reason;
|
|
6444
|
+
if (this.path.isUnknown()) await this.path.lstat();
|
|
6445
|
+
await new Promise((res, rej) => {
|
|
6446
|
+
this.walkCB(this.path, this.patterns, () => {
|
|
6447
|
+
if (this.signal?.aborted) rej(this.signal.reason);
|
|
6448
|
+
else res(this.matches);
|
|
6449
|
+
});
|
|
6450
|
+
});
|
|
6451
|
+
return this.matches;
|
|
6452
|
+
}
|
|
6453
|
+
walkSync() {
|
|
6454
|
+
if (this.signal?.aborted) throw this.signal.reason;
|
|
6455
|
+
if (this.path.isUnknown()) this.path.lstatSync();
|
|
6456
|
+
this.walkCBSync(this.path, this.patterns, () => {
|
|
6457
|
+
if (this.signal?.aborted) throw this.signal.reason;
|
|
6458
|
+
});
|
|
6459
|
+
return this.matches;
|
|
6460
|
+
}
|
|
6461
|
+
};
|
|
6462
|
+
var GlobStream = class extends GlobUtil {
|
|
6463
|
+
results;
|
|
6464
|
+
constructor(patterns, path$4, opts) {
|
|
6465
|
+
super(patterns, path$4, opts);
|
|
6466
|
+
this.results = new Minipass({
|
|
6467
|
+
signal: this.signal,
|
|
6468
|
+
objectMode: true
|
|
6469
|
+
});
|
|
6470
|
+
this.results.on("drain", () => this.resume());
|
|
6471
|
+
this.results.on("resume", () => this.resume());
|
|
6472
|
+
}
|
|
6473
|
+
matchEmit(e) {
|
|
6474
|
+
this.results.write(e);
|
|
6475
|
+
if (!this.results.flowing) this.pause();
|
|
6476
|
+
}
|
|
6477
|
+
stream() {
|
|
6478
|
+
const target = this.path;
|
|
6479
|
+
if (target.isUnknown()) target.lstat().then(() => {
|
|
6480
|
+
this.walkCB(target, this.patterns, () => this.results.end());
|
|
6481
|
+
});
|
|
6482
|
+
else this.walkCB(target, this.patterns, () => this.results.end());
|
|
6483
|
+
return this.results;
|
|
6484
|
+
}
|
|
6485
|
+
streamSync() {
|
|
6486
|
+
if (this.path.isUnknown()) this.path.lstatSync();
|
|
6487
|
+
this.walkCBSync(this.path, this.patterns, () => this.results.end());
|
|
6488
|
+
return this.results;
|
|
6489
|
+
}
|
|
6490
|
+
};
|
|
6491
|
+
|
|
6492
|
+
//#endregion
|
|
6493
|
+
//#region node_modules/glob/dist/esm/glob.js
|
|
6494
|
+
const defaultPlatform = typeof process === "object" && process && typeof process.platform === "string" ? process.platform : "linux";
|
|
6495
|
+
/**
|
|
6496
|
+
* An object that can perform glob pattern traversals.
|
|
6497
|
+
*/
|
|
6498
|
+
var Glob = class {
|
|
6499
|
+
absolute;
|
|
6500
|
+
cwd;
|
|
6501
|
+
root;
|
|
6502
|
+
dot;
|
|
6503
|
+
dotRelative;
|
|
6504
|
+
follow;
|
|
6505
|
+
ignore;
|
|
6506
|
+
magicalBraces;
|
|
6507
|
+
mark;
|
|
6508
|
+
matchBase;
|
|
6509
|
+
maxDepth;
|
|
6510
|
+
nobrace;
|
|
6511
|
+
nocase;
|
|
6512
|
+
nodir;
|
|
6513
|
+
noext;
|
|
6514
|
+
noglobstar;
|
|
6515
|
+
pattern;
|
|
6516
|
+
platform;
|
|
6517
|
+
realpath;
|
|
6518
|
+
scurry;
|
|
6519
|
+
stat;
|
|
6520
|
+
signal;
|
|
6521
|
+
windowsPathsNoEscape;
|
|
6522
|
+
withFileTypes;
|
|
6523
|
+
includeChildMatches;
|
|
6524
|
+
/**
|
|
6525
|
+
* The options provided to the constructor.
|
|
6526
|
+
*/
|
|
6527
|
+
opts;
|
|
6528
|
+
/**
|
|
6529
|
+
* An array of parsed immutable {@link Pattern} objects.
|
|
6530
|
+
*/
|
|
6531
|
+
patterns;
|
|
6532
|
+
/**
|
|
6533
|
+
* All options are stored as properties on the `Glob` object.
|
|
6534
|
+
*
|
|
6535
|
+
* See {@link GlobOptions} for full options descriptions.
|
|
6536
|
+
*
|
|
6537
|
+
* Note that a previous `Glob` object can be passed as the
|
|
6538
|
+
* `GlobOptions` to another `Glob` instantiation to re-use settings
|
|
6539
|
+
* and caches with a new pattern.
|
|
6540
|
+
*
|
|
6541
|
+
* Traversal functions can be called multiple times to run the walk
|
|
6542
|
+
* again.
|
|
6543
|
+
*/
|
|
6544
|
+
constructor(pattern, opts) {
|
|
6545
|
+
/* c8 ignore start */
|
|
6546
|
+
if (!opts) throw new TypeError("glob options required");
|
|
6547
|
+
/* c8 ignore stop */
|
|
6548
|
+
this.withFileTypes = !!opts.withFileTypes;
|
|
6549
|
+
this.signal = opts.signal;
|
|
6550
|
+
this.follow = !!opts.follow;
|
|
6551
|
+
this.dot = !!opts.dot;
|
|
6552
|
+
this.dotRelative = !!opts.dotRelative;
|
|
6553
|
+
this.nodir = !!opts.nodir;
|
|
6554
|
+
this.mark = !!opts.mark;
|
|
6555
|
+
if (!opts.cwd) this.cwd = "";
|
|
6556
|
+
else if (opts.cwd instanceof URL || opts.cwd.startsWith("file://")) opts.cwd = fileURLToPath$1(opts.cwd);
|
|
6557
|
+
this.cwd = opts.cwd || "";
|
|
6558
|
+
this.root = opts.root;
|
|
6559
|
+
this.magicalBraces = !!opts.magicalBraces;
|
|
6560
|
+
this.nobrace = !!opts.nobrace;
|
|
6561
|
+
this.noext = !!opts.noext;
|
|
6562
|
+
this.realpath = !!opts.realpath;
|
|
6563
|
+
this.absolute = opts.absolute;
|
|
6564
|
+
this.includeChildMatches = opts.includeChildMatches !== false;
|
|
6565
|
+
this.noglobstar = !!opts.noglobstar;
|
|
6566
|
+
this.matchBase = !!opts.matchBase;
|
|
6567
|
+
this.maxDepth = typeof opts.maxDepth === "number" ? opts.maxDepth : Infinity;
|
|
6568
|
+
this.stat = !!opts.stat;
|
|
6569
|
+
this.ignore = opts.ignore;
|
|
6570
|
+
if (this.withFileTypes && this.absolute !== void 0) throw new Error("cannot set absolute and withFileTypes:true");
|
|
6571
|
+
if (typeof pattern === "string") pattern = [pattern];
|
|
6572
|
+
this.windowsPathsNoEscape = !!opts.windowsPathsNoEscape || opts.allowWindowsEscape === false;
|
|
6573
|
+
if (this.windowsPathsNoEscape) pattern = pattern.map((p) => p.replace(/\\/g, "/"));
|
|
6574
|
+
if (this.matchBase) {
|
|
6575
|
+
if (opts.noglobstar) throw new TypeError("base matching requires globstar");
|
|
6576
|
+
pattern = pattern.map((p) => p.includes("/") ? p : `./**/${p}`);
|
|
6577
|
+
}
|
|
6578
|
+
this.pattern = pattern;
|
|
6579
|
+
this.platform = opts.platform || defaultPlatform;
|
|
6580
|
+
this.opts = {
|
|
6581
|
+
...opts,
|
|
6582
|
+
platform: this.platform
|
|
6583
|
+
};
|
|
6584
|
+
if (opts.scurry) {
|
|
6585
|
+
this.scurry = opts.scurry;
|
|
6586
|
+
if (opts.nocase !== void 0 && opts.nocase !== opts.scurry.nocase) throw new Error("nocase option contradicts provided scurry option");
|
|
6587
|
+
} else {
|
|
6588
|
+
const Scurry = opts.platform === "win32" ? PathScurryWin32 : opts.platform === "darwin" ? PathScurryDarwin : opts.platform ? PathScurryPosix : PathScurry;
|
|
6589
|
+
this.scurry = new Scurry(this.cwd, {
|
|
6590
|
+
nocase: opts.nocase,
|
|
6591
|
+
fs: opts.fs
|
|
6592
|
+
});
|
|
6593
|
+
}
|
|
6594
|
+
this.nocase = this.scurry.nocase;
|
|
6595
|
+
const nocaseMagicOnly = this.platform === "darwin" || this.platform === "win32";
|
|
6596
|
+
const mmo = {
|
|
6597
|
+
...opts,
|
|
6598
|
+
dot: this.dot,
|
|
6599
|
+
matchBase: this.matchBase,
|
|
6600
|
+
nobrace: this.nobrace,
|
|
6601
|
+
nocase: this.nocase,
|
|
6602
|
+
nocaseMagicOnly,
|
|
6603
|
+
nocomment: true,
|
|
6604
|
+
noext: this.noext,
|
|
6605
|
+
nonegate: true,
|
|
6606
|
+
optimizationLevel: 2,
|
|
6607
|
+
platform: this.platform,
|
|
6608
|
+
windowsPathsNoEscape: this.windowsPathsNoEscape,
|
|
6609
|
+
debug: !!this.opts.debug
|
|
6610
|
+
};
|
|
6611
|
+
const mms = this.pattern.map((p) => new Minimatch(p, mmo));
|
|
6612
|
+
const [matchSet, globParts] = mms.reduce((set, m) => {
|
|
6613
|
+
set[0].push(...m.set);
|
|
6614
|
+
set[1].push(...m.globParts);
|
|
6615
|
+
return set;
|
|
6616
|
+
}, [[], []]);
|
|
6617
|
+
this.patterns = matchSet.map((set, i) => {
|
|
6618
|
+
const g = globParts[i];
|
|
6619
|
+
/* c8 ignore start */
|
|
6620
|
+
if (!g) throw new Error("invalid pattern object");
|
|
6621
|
+
/* c8 ignore stop */
|
|
6622
|
+
return new Pattern(set, g, 0, this.platform);
|
|
6623
|
+
});
|
|
6624
|
+
}
|
|
6625
|
+
async walk() {
|
|
6626
|
+
return [...await new GlobWalker(this.patterns, this.scurry.cwd, {
|
|
6627
|
+
...this.opts,
|
|
6628
|
+
maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
|
|
6629
|
+
platform: this.platform,
|
|
6630
|
+
nocase: this.nocase,
|
|
6631
|
+
includeChildMatches: this.includeChildMatches
|
|
6632
|
+
}).walk()];
|
|
6633
|
+
}
|
|
6634
|
+
walkSync() {
|
|
6635
|
+
return [...new GlobWalker(this.patterns, this.scurry.cwd, {
|
|
6636
|
+
...this.opts,
|
|
6637
|
+
maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
|
|
6638
|
+
platform: this.platform,
|
|
6639
|
+
nocase: this.nocase,
|
|
6640
|
+
includeChildMatches: this.includeChildMatches
|
|
6641
|
+
}).walkSync()];
|
|
6642
|
+
}
|
|
6643
|
+
stream() {
|
|
6644
|
+
return new GlobStream(this.patterns, this.scurry.cwd, {
|
|
6645
|
+
...this.opts,
|
|
6646
|
+
maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
|
|
6647
|
+
platform: this.platform,
|
|
6648
|
+
nocase: this.nocase,
|
|
6649
|
+
includeChildMatches: this.includeChildMatches
|
|
6650
|
+
}).stream();
|
|
6651
|
+
}
|
|
6652
|
+
streamSync() {
|
|
6653
|
+
return new GlobStream(this.patterns, this.scurry.cwd, {
|
|
6654
|
+
...this.opts,
|
|
6655
|
+
maxDepth: this.maxDepth !== Infinity ? this.maxDepth + this.scurry.cwd.depth() : Infinity,
|
|
6656
|
+
platform: this.platform,
|
|
6657
|
+
nocase: this.nocase,
|
|
6658
|
+
includeChildMatches: this.includeChildMatches
|
|
6659
|
+
}).streamSync();
|
|
6660
|
+
}
|
|
6661
|
+
/**
|
|
6662
|
+
* Default sync iteration function. Returns a Generator that
|
|
6663
|
+
* iterates over the results.
|
|
6664
|
+
*/
|
|
6665
|
+
iterateSync() {
|
|
6666
|
+
return this.streamSync()[Symbol.iterator]();
|
|
6667
|
+
}
|
|
6668
|
+
[Symbol.iterator]() {
|
|
6669
|
+
return this.iterateSync();
|
|
6670
|
+
}
|
|
6671
|
+
/**
|
|
6672
|
+
* Default async iteration function. Returns an AsyncGenerator that
|
|
6673
|
+
* iterates over the results.
|
|
6674
|
+
*/
|
|
6675
|
+
iterate() {
|
|
6676
|
+
return this.stream()[Symbol.asyncIterator]();
|
|
6677
|
+
}
|
|
6678
|
+
[Symbol.asyncIterator]() {
|
|
6679
|
+
return this.iterate();
|
|
6680
|
+
}
|
|
6681
|
+
};
|
|
6682
|
+
|
|
6683
|
+
//#endregion
|
|
6684
|
+
//#region node_modules/glob/dist/esm/has-magic.js
|
|
6685
|
+
/**
|
|
6686
|
+
* Return true if the patterns provided contain any magic glob characters,
|
|
6687
|
+
* given the options provided.
|
|
6688
|
+
*
|
|
6689
|
+
* Brace expansion is not considered "magic" unless the `magicalBraces` option
|
|
6690
|
+
* is set, as brace expansion just turns one string into an array of strings.
|
|
6691
|
+
* So a pattern like `'x{a,b}y'` would return `false`, because `'xay'` and
|
|
6692
|
+
* `'xby'` both do not contain any magic glob characters, and it's treated the
|
|
6693
|
+
* same as if you had called it on `['xay', 'xby']`. When `magicalBraces:true`
|
|
6694
|
+
* is in the options, brace expansion _is_ treated as a pattern having magic.
|
|
6695
|
+
*/
|
|
6696
|
+
const hasMagic = (pattern, options = {}) => {
|
|
6697
|
+
if (!Array.isArray(pattern)) pattern = [pattern];
|
|
6698
|
+
for (const p of pattern) if (new Minimatch(p, options).hasMagic()) return true;
|
|
6699
|
+
return false;
|
|
6700
|
+
};
|
|
6701
|
+
|
|
6702
|
+
//#endregion
|
|
6703
|
+
//#region node_modules/glob/dist/esm/index.js
|
|
6704
|
+
function globStreamSync(pattern, options = {}) {
|
|
6705
|
+
return new Glob(pattern, options).streamSync();
|
|
6706
|
+
}
|
|
6707
|
+
function globStream(pattern, options = {}) {
|
|
6708
|
+
return new Glob(pattern, options).stream();
|
|
6709
|
+
}
|
|
6710
|
+
function globSync(pattern, options = {}) {
|
|
6711
|
+
return new Glob(pattern, options).walkSync();
|
|
6712
|
+
}
|
|
6713
|
+
async function glob_(pattern, options = {}) {
|
|
6714
|
+
return new Glob(pattern, options).walk();
|
|
6715
|
+
}
|
|
6716
|
+
function globIterateSync(pattern, options = {}) {
|
|
6717
|
+
return new Glob(pattern, options).iterateSync();
|
|
6718
|
+
}
|
|
6719
|
+
function globIterate(pattern, options = {}) {
|
|
6720
|
+
return new Glob(pattern, options).iterate();
|
|
6721
|
+
}
|
|
6722
|
+
const streamSync = globStreamSync;
|
|
6723
|
+
const stream = Object.assign(globStream, { sync: globStreamSync });
|
|
6724
|
+
const iterateSync = globIterateSync;
|
|
6725
|
+
const iterate = Object.assign(globIterate, { sync: globIterateSync });
|
|
6726
|
+
const sync = Object.assign(globSync, {
|
|
6727
|
+
stream: globStreamSync,
|
|
6728
|
+
iterate: globIterateSync
|
|
6729
|
+
});
|
|
6730
|
+
const glob = Object.assign(glob_, {
|
|
6731
|
+
glob: glob_,
|
|
6732
|
+
globSync,
|
|
6733
|
+
sync,
|
|
6734
|
+
globStream,
|
|
6735
|
+
stream,
|
|
6736
|
+
globStreamSync,
|
|
6737
|
+
streamSync,
|
|
6738
|
+
globIterate,
|
|
6739
|
+
iterate,
|
|
6740
|
+
globIterateSync,
|
|
6741
|
+
iterateSync,
|
|
6742
|
+
Glob,
|
|
6743
|
+
hasMagic,
|
|
6744
|
+
escape,
|
|
6745
|
+
unescape
|
|
6746
|
+
});
|
|
6747
|
+
glob.glob = glob;
|
|
6748
|
+
|
|
6749
|
+
//#endregion
|
|
6750
|
+
//#region src/cli/commands/resume-drift-detector.ts
|
|
6751
|
+
const DEFAULT_SCAN_GLOBS = ["packages/*/src/**/*.ts", "src/**/*.ts"];
|
|
6752
|
+
/**
|
|
6753
|
+
* Detect manifest-vs-working-tree drift for `substrate resume`.
|
|
6754
|
+
*
|
|
6755
|
+
* Scans files matching the configured glob patterns using the `glob` library.
|
|
6756
|
+
* For each story entry in `manifest.per_story_state` where
|
|
6757
|
+
* `phase === 'IN_STORY_CREATION'` AND `status === 'dispatched'`, checks whether
|
|
6758
|
+
* any scanned file has an mtime newer than the story's `started_at` timestamp.
|
|
6759
|
+
* If so, the manifest is considered drifted.
|
|
6760
|
+
*
|
|
6761
|
+
* Scan globs are read from the `SUBSTRATE_RESUME_DRIFT_SCAN_GLOBS` environment
|
|
6762
|
+
* variable (comma-separated), falling back to the defaults:
|
|
6763
|
+
* "packages/*/src/**/*.ts" and "src/**/*.ts"
|
|
6764
|
+
*
|
|
6765
|
+
* @param manifest - The run manifest data (parsed and validated from disk)
|
|
6766
|
+
* @param projectRoot - Absolute path to the project root for glob scanning
|
|
6767
|
+
* @returns `{ drifted, evidence }` where `evidence` contains up to 3 sample
|
|
6768
|
+
* newer files per drifted story entry.
|
|
6769
|
+
*/
|
|
6770
|
+
async function detectManifestDriftAgainstWorkingTree(manifest, projectRoot) {
|
|
6771
|
+
const envGlobs = process.env["SUBSTRATE_RESUME_DRIFT_SCAN_GLOBS"];
|
|
6772
|
+
const scanGlobs = envGlobs !== void 0 && envGlobs.trim() !== "" ? envGlobs.split(",").map((g) => g.trim()).filter(Boolean) : DEFAULT_SCAN_GLOBS;
|
|
6773
|
+
const qualifying = Object.entries(manifest.per_story_state).filter(([, s]) => s.phase === "IN_STORY_CREATION" && s.status === "dispatched");
|
|
6774
|
+
if (qualifying.length === 0) return {
|
|
6775
|
+
drifted: false,
|
|
6776
|
+
evidence: []
|
|
6777
|
+
};
|
|
6778
|
+
const scannedAbsPaths = await glob(scanGlobs, {
|
|
6779
|
+
cwd: projectRoot,
|
|
6780
|
+
absolute: true,
|
|
6781
|
+
nodir: true
|
|
6782
|
+
});
|
|
6783
|
+
if (scannedAbsPaths.length === 0) return {
|
|
6784
|
+
drifted: false,
|
|
6785
|
+
evidence: []
|
|
6786
|
+
};
|
|
6787
|
+
const evidence = [];
|
|
6788
|
+
for (const [storyKey, storyState] of qualifying) {
|
|
6789
|
+
const storyTimestampMs = new Date(storyState.started_at).getTime();
|
|
6790
|
+
const newerFiles = [];
|
|
6791
|
+
for (const absPath of scannedAbsPaths) try {
|
|
6792
|
+
const { mtimeMs } = await promises.stat(absPath);
|
|
6793
|
+
if (mtimeMs > storyTimestampMs) newerFiles.push(relative(projectRoot, absPath).replace(/\\/g, "/"));
|
|
6794
|
+
} catch {}
|
|
6795
|
+
if (newerFiles.length > 0) evidence.push({
|
|
6796
|
+
storyKey,
|
|
6797
|
+
sampleFiles: newerFiles.slice(0, 3),
|
|
6798
|
+
totalNewerFiles: newerFiles.length
|
|
6799
|
+
});
|
|
6800
|
+
}
|
|
6801
|
+
return {
|
|
6802
|
+
drifted: evidence.length > 0,
|
|
6803
|
+
evidence
|
|
6804
|
+
};
|
|
6805
|
+
}
|
|
6806
|
+
|
|
3040
6807
|
//#endregion
|
|
3041
6808
|
//#region src/cli/commands/resume.ts
|
|
3042
6809
|
const logger$14 = createLogger("resume-cmd");
|
|
3043
6810
|
/**
|
|
6811
|
+
* Format a human-readable duration from an ISO-8601 timestamp to "now".
|
|
6812
|
+
*/
|
|
6813
|
+
function formatAgo(isoTimestamp) {
|
|
6814
|
+
const diffMs = Date.now() - new Date(isoTimestamp).getTime();
|
|
6815
|
+
const totalSeconds = Math.max(0, Math.floor(diffMs / 1e3));
|
|
6816
|
+
if (totalSeconds < 60) return `${totalSeconds} second${totalSeconds === 1 ? "" : "s"} ago`;
|
|
6817
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
6818
|
+
if (minutes < 60) return `${minutes} minute${minutes === 1 ? "" : "s"} ago`;
|
|
6819
|
+
const hours = Math.floor(minutes / 60);
|
|
6820
|
+
if (hours < 24) return `${hours} hour${hours === 1 ? "" : "s"} ago`;
|
|
6821
|
+
const days = Math.floor(hours / 24);
|
|
6822
|
+
return `${days} day${days === 1 ? "" : "s"} ago`;
|
|
6823
|
+
}
|
|
6824
|
+
/**
|
|
6825
|
+
* Format the drift error message shown to the operator when drift is detected.
|
|
6826
|
+
* The output must contain the substring "manifest drift detected" (checked by AC5 test).
|
|
6827
|
+
*/
|
|
6828
|
+
function formatDriftError(result, manifest) {
|
|
6829
|
+
const lines = [];
|
|
6830
|
+
for (const ev of result.evidence) {
|
|
6831
|
+
const storyState = manifest.per_story_state[ev.storyKey];
|
|
6832
|
+
const recordedAt = storyState?.started_at ?? "unknown";
|
|
6833
|
+
const ago = formatAgo(recordedAt);
|
|
6834
|
+
const sampleList = ev.sampleFiles.join(", ");
|
|
6835
|
+
const fileCount = ev.totalNewerFiles;
|
|
6836
|
+
lines.push(`substrate resume: manifest drift detected for story ${ev.storyKey}`);
|
|
6837
|
+
lines.push(` manifest phase: IN_STORY_CREATION dispatched (recorded ${ago})`);
|
|
6838
|
+
lines.push(` working tree: ${fileCount} file${fileCount === 1 ? "" : "s"} newer than manifest (sample: ${sampleList})`);
|
|
6839
|
+
lines.push("");
|
|
6840
|
+
}
|
|
6841
|
+
lines.push("This usually means the orchestrator died after writing dev-story output but", "before persisting the phase advancement (obs_2026-05-03_022 class).", "Re-dispatching from IN_STORY_CREATION would clobber that work.", "", "Recovery options:", " 1. Inspect the working tree, validate dev-story output, then commit it", " as if the pipeline had shipped LGTM — see obs_022 recovery runbook.", " 2. To proceed with re-dispatch anyway (clobbering disk state),", " re-run with --force-from-manifest.");
|
|
6842
|
+
return lines.join("\n");
|
|
6843
|
+
}
|
|
6844
|
+
/**
|
|
3044
6845
|
* Map internal orchestrator phase names to pipeline event protocol phase names.
|
|
3045
6846
|
*/
|
|
3046
6847
|
function mapInternalPhaseToEventPhase(internalPhase) {
|
|
@@ -3064,6 +6865,20 @@ async function runResumeAction(options) {
|
|
|
3064
6865
|
const dbRoot = await resolveMainRepoRoot(projectRoot);
|
|
3065
6866
|
const packPath = join(dbRoot, "packs", packName);
|
|
3066
6867
|
const dbPath = join(dbRoot, ".substrate", "substrate.db");
|
|
6868
|
+
if (!options.forceFromManifest) {
|
|
6869
|
+
const { manifest: runManifest } = await resolveRunManifest(dbRoot, specifiedRunId ?? void 0);
|
|
6870
|
+
if (runManifest !== null) try {
|
|
6871
|
+
const manifestData = await runManifest.read();
|
|
6872
|
+
const driftResult = await detectManifestDriftAgainstWorkingTree(manifestData, projectRoot);
|
|
6873
|
+
if (driftResult.drifted) {
|
|
6874
|
+
const errMsg = formatDriftError(driftResult, manifestData);
|
|
6875
|
+
process.stderr.write(errMsg + "\n");
|
|
6876
|
+
return 1;
|
|
6877
|
+
}
|
|
6878
|
+
} catch (driftErr) {
|
|
6879
|
+
logger$14.debug({ err: driftErr }, "manifest drift check failed — proceeding with resume");
|
|
6880
|
+
}
|
|
6881
|
+
}
|
|
3067
6882
|
const doltDir = join(dbRoot, ".substrate", "state", ".dolt");
|
|
3068
6883
|
if (!existsSync$1(dbPath) && !existsSync$1(doltDir)) {
|
|
3069
6884
|
const errorMsg = `Decision store not initialized. Run 'substrate init' first.`;
|
|
@@ -3394,7 +7209,8 @@ async function runFullPipelineFromPhase(options) {
|
|
|
3394
7209
|
run_id: payload.runId,
|
|
3395
7210
|
active_dispatches: payload.activeDispatches,
|
|
3396
7211
|
completed_dispatches: payload.completedDispatches,
|
|
3397
|
-
queued_dispatches: payload.queuedDispatches
|
|
7212
|
+
queued_dispatches: payload.queuedDispatches,
|
|
7213
|
+
...payload.perStoryState !== void 0 ? { per_story_state: payload.perStoryState } : {}
|
|
3398
7214
|
});
|
|
3399
7215
|
});
|
|
3400
7216
|
}
|
|
@@ -3493,7 +7309,7 @@ async function runFullPipelineFromPhase(options) {
|
|
|
3493
7309
|
}
|
|
3494
7310
|
}
|
|
3495
7311
|
function registerResumeCommand(program, _version = "0.0.0", projectRoot = process.cwd(), registry) {
|
|
3496
|
-
program.command("resume").description("Resume a previously interrupted pipeline run").option("--run-id <id>", "Pipeline run ID to resume (defaults to latest)").option("--pack <name>", "Methodology pack name", "bmad").option("--stop-after <phase>", "Stop pipeline after this phase completes (overrides saved state)").option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").action(async (opts) => {
|
|
7312
|
+
program.command("resume").description("Resume a previously interrupted pipeline run").option("--run-id <id>", "Pipeline run ID to resume (defaults to latest)").option("--pack <name>", "Methodology pack name", "bmad").option("--stop-after <phase>", "Stop pipeline after this phase completes (overrides saved state)").option("--concurrency <n>", "Maximum parallel conflict groups", (v) => parseInt(v, 10), 3).option("--project-root <path>", "Project root directory", projectRoot).option("--output-format <format>", "Output format: human (default) or json", "human").option("--events", "Emit structured NDJSON events on stdout for programmatic consumption").option("--max-review-cycles <n>", "Maximum review cycles per story (default: 2)", (v) => parseInt(v, 10), 2).option("--agent <id>", "Agent backend: claude-code (default), codex, or gemini").option("--force-from-manifest", "Bypass manifest drift check and proceed with re-dispatch (Story 66-3 / obs_2026-05-03_022 fix #3)").action(async (opts) => {
|
|
3497
7313
|
const outputFormat = opts.outputFormat === "json" ? "json" : "human";
|
|
3498
7314
|
const exitCode = await runResumeAction({
|
|
3499
7315
|
runId: opts.runId,
|
|
@@ -3505,6 +7321,7 @@ function registerResumeCommand(program, _version = "0.0.0", projectRoot = proces
|
|
|
3505
7321
|
events: opts.events,
|
|
3506
7322
|
maxReviewCycles: opts.maxReviewCycles,
|
|
3507
7323
|
agent: opts.agent,
|
|
7324
|
+
forceFromManifest: opts.forceFromManifest,
|
|
3508
7325
|
registry
|
|
3509
7326
|
});
|
|
3510
7327
|
process.exitCode = exitCode;
|
|
@@ -3667,7 +7484,7 @@ async function runStatusAction(options) {
|
|
|
3667
7484
|
logger$13.debug({ err }, "Work graph query failed, continuing without work graph data");
|
|
3668
7485
|
}
|
|
3669
7486
|
if (run === void 0) {
|
|
3670
|
-
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-
|
|
7487
|
+
const { inspectProcessTree: inspectProcessTree$1 } = await import("../health-HmyFdWEf.js");
|
|
3671
7488
|
const substrateDirPath = join(projectRoot, ".substrate");
|
|
3672
7489
|
const processInfo = inspectProcessTree$1({
|
|
3673
7490
|
projectRoot,
|
|
@@ -3746,6 +7563,14 @@ async function runStatusAction(options) {
|
|
|
3746
7563
|
const completedCount = storyMetricsRows.filter((r) => r.result === "success").length;
|
|
3747
7564
|
const storiesPerHour = pipelineWallClockMs > 0 ? Math.round(completedCount / (pipelineWallClockMs / 36e5) * 100) / 100 : 0;
|
|
3748
7565
|
const totalCostUsd = storyMetricsRows.reduce((sum, r) => sum + (r.cost_usd ?? 0), 0);
|
|
7566
|
+
let latestHeartbeatPerStoryState;
|
|
7567
|
+
const heartbeatSnapshotPath = join(dbRoot, ".substrate", "latest-heartbeat-per-story-state.json");
|
|
7568
|
+
try {
|
|
7569
|
+
if (existsSync$1(heartbeatSnapshotPath)) {
|
|
7570
|
+
const raw = readFileSync$1(heartbeatSnapshotPath, "utf-8");
|
|
7571
|
+
latestHeartbeatPerStoryState = JSON.parse(raw);
|
|
7572
|
+
}
|
|
7573
|
+
} catch {}
|
|
3749
7574
|
const enhancedOutput = {
|
|
3750
7575
|
...statusOutput,
|
|
3751
7576
|
story_metrics: storyMetricsV2,
|
|
@@ -3758,7 +7583,8 @@ async function runStatusAction(options) {
|
|
|
3758
7583
|
cost_usd: totalCostUsd
|
|
3759
7584
|
},
|
|
3760
7585
|
story_states: storeStories,
|
|
3761
|
-
workGraph: workGraph ?? null
|
|
7586
|
+
workGraph: workGraph ?? null,
|
|
7587
|
+
latest_heartbeat_per_story_state: latestHeartbeatPerStoryState ?? {}
|
|
3762
7588
|
};
|
|
3763
7589
|
process.stdout.write(formatOutput(enhancedOutput, "json", true) + "\n");
|
|
3764
7590
|
} else {
|
|
@@ -4623,7 +8449,7 @@ function defaultSupervisorDeps() {
|
|
|
4623
8449
|
if (cached === null) {
|
|
4624
8450
|
const { AdapterRegistry: AR } = await import(
|
|
4625
8451
|
/* @vite-ignore */
|
|
4626
|
-
"../adapter-registry-
|
|
8452
|
+
"../adapter-registry-k7ZX3Bz6.js"
|
|
4627
8453
|
);
|
|
4628
8454
|
cached = new AR();
|
|
4629
8455
|
await cached.discoverAndRegister();
|
|
@@ -5190,11 +9016,11 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
5190
9016
|
try {
|
|
5191
9017
|
const { createExperimenter } = await import(
|
|
5192
9018
|
/* @vite-ignore */
|
|
5193
|
-
"../experimenter-
|
|
9019
|
+
"../experimenter-DxxwicpK.js"
|
|
5194
9020
|
);
|
|
5195
9021
|
const { getLatestRun: getLatest } = await import(
|
|
5196
9022
|
/* @vite-ignore */
|
|
5197
|
-
"../decisions-
|
|
9023
|
+
"../decisions-4F91LrVD.js"
|
|
5198
9024
|
);
|
|
5199
9025
|
const expAdapter = createDatabaseAdapter({
|
|
5200
9026
|
backend: "auto",
|
|
@@ -5204,7 +9030,7 @@ async function runSupervisorAction(options, deps = {}) {
|
|
|
5204
9030
|
await initSchema(expAdapter);
|
|
5205
9031
|
const { runRunAction: runPipeline } = await import(
|
|
5206
9032
|
/* @vite-ignore */
|
|
5207
|
-
"../run-
|
|
9033
|
+
"../run-BF8oeJhG.js"
|
|
5208
9034
|
);
|
|
5209
9035
|
const runStoryFn = async (opts) => {
|
|
5210
9036
|
const exitCode = await runPipeline({
|
|
@@ -5736,7 +9562,7 @@ async function runMetricsAction(options) {
|
|
|
5736
9562
|
const routingConfigPath = join(dbDir, "routing.yml");
|
|
5737
9563
|
let routingConfig = null;
|
|
5738
9564
|
if (existsSync$1(routingConfigPath)) try {
|
|
5739
|
-
const { loadModelRoutingConfig } = await import("../routing-
|
|
9565
|
+
const { loadModelRoutingConfig } = await import("../routing-0ykvBl_4.js");
|
|
5740
9566
|
routingConfig = loadModelRoutingConfig(routingConfigPath);
|
|
5741
9567
|
} catch {}
|
|
5742
9568
|
if (routingConfig === null) routingConfig = {
|
|
@@ -9372,8 +13198,8 @@ async function createProgram() {
|
|
|
9372
13198
|
/** Fire-and-forget startup version check (story 8.3, AC3/AC5) */
|
|
9373
13199
|
function checkForUpdatesInBackground(currentVersion) {
|
|
9374
13200
|
if (process.env.SUBSTRATE_NO_UPDATE_CHECK === "1") return;
|
|
9375
|
-
import("../upgrade-
|
|
9376
|
-
const { createVersionManager } = await import("../version-manager-impl-
|
|
13201
|
+
import("../upgrade-C8LAnB6W.js").then(async () => {
|
|
13202
|
+
const { createVersionManager } = await import("../version-manager-impl-DaA_ALYK.js");
|
|
9377
13203
|
const vm = createVersionManager();
|
|
9378
13204
|
const result = await vm.checkForUpdates();
|
|
9379
13205
|
if (result.updateAvailable) {
|