pathprobe 0.1.0 → 0.2.0
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/index.mjs
CHANGED
|
@@ -145,30 +145,32 @@ function pathKey$2(value) {
|
|
|
145
145
|
function isKnownFileError(error) {
|
|
146
146
|
return error instanceof Error && "code" in error && typeof error.code === "string" && knownFileErrors.has(error.code);
|
|
147
147
|
}
|
|
148
|
-
async function
|
|
148
|
+
async function classifyPath(filePath) {
|
|
149
149
|
try {
|
|
150
150
|
const pathStats = await stat(filePath);
|
|
151
|
-
|
|
151
|
+
if (pathStats.isFile()) return "file";
|
|
152
|
+
return pathStats.isDirectory() ? "directory" : void 0;
|
|
152
153
|
} catch (error) {
|
|
153
|
-
if (isKnownFileError(error)) return
|
|
154
|
+
if (isKnownFileError(error)) return;
|
|
154
155
|
throw error;
|
|
155
156
|
}
|
|
156
157
|
}
|
|
157
|
-
async function
|
|
158
|
-
const
|
|
158
|
+
async function classifyAndAdd(found, filePath) {
|
|
159
|
+
const kind = await classifyPath(filePath);
|
|
160
|
+
if (kind !== void 0) found.set(filePath, kind);
|
|
161
|
+
}
|
|
162
|
+
async function classifyExistingPaths(paths, roots) {
|
|
163
|
+
const found = /* @__PURE__ */ new Map();
|
|
159
164
|
const limit = pLimit(settings.validationConcurrency);
|
|
160
|
-
if (
|
|
161
|
-
await Promise.all(
|
|
162
|
-
if (await isExistingPath(filePath)) found.add(filePath);
|
|
163
|
-
})));
|
|
165
|
+
if (paths.length < settings.batchValidationThreshold) {
|
|
166
|
+
await Promise.all(paths.map((filePath) => limit(() => classifyAndAdd(found, filePath))));
|
|
164
167
|
return found;
|
|
165
168
|
}
|
|
166
169
|
const rootKeys = new Set(roots.map(pathKey$2));
|
|
167
170
|
const pathsByParent = /* @__PURE__ */ new Map();
|
|
168
|
-
for (const
|
|
169
|
-
const filePath = indexedPath[0];
|
|
171
|
+
for (const filePath of paths) {
|
|
170
172
|
if (rootKeys.has(pathKey$2(filePath))) {
|
|
171
|
-
found.
|
|
173
|
+
found.set(filePath, "directory");
|
|
172
174
|
continue;
|
|
173
175
|
}
|
|
174
176
|
const parent = nodePath.dirname(filePath);
|
|
@@ -177,16 +179,14 @@ async function locateExistingPaths(indexedPaths, roots) {
|
|
|
177
179
|
parent,
|
|
178
180
|
paths: []
|
|
179
181
|
};
|
|
180
|
-
group.paths.push(
|
|
182
|
+
group.paths.push(filePath);
|
|
181
183
|
pathsByParent.set(key, group);
|
|
182
184
|
}
|
|
183
185
|
const directPaths = [];
|
|
184
186
|
const scannedGroups = [];
|
|
185
187
|
for (const group of pathsByParent.values()) if (group.paths.length < settings.directoryScanThreshold) directPaths.push(...group.paths);
|
|
186
188
|
else scannedGroups.push(group);
|
|
187
|
-
await Promise.all([...directPaths.map((
|
|
188
|
-
if (await isExistingPath(filePath)) found.add(filePath);
|
|
189
|
-
})), ...scannedGroups.map(({ parent, paths }) => limit(async () => {
|
|
189
|
+
await Promise.all([...directPaths.map((filePath) => limit(() => classifyAndAdd(found, filePath))), ...scannedGroups.map(({ parent, paths: groupPaths }) => limit(async () => {
|
|
190
190
|
let entries;
|
|
191
191
|
try {
|
|
192
192
|
entries = await readdir(parent, { withFileTypes: true });
|
|
@@ -195,13 +195,12 @@ async function locateExistingPaths(indexedPaths, roots) {
|
|
|
195
195
|
throw error;
|
|
196
196
|
}
|
|
197
197
|
const entriesByName = new Map(entries.map((entry) => [pathKey$2(entry.name), entry]));
|
|
198
|
-
await Promise.all(
|
|
198
|
+
await Promise.all(groupPaths.map(async (filePath) => {
|
|
199
199
|
const name = nodePath.basename(filePath);
|
|
200
200
|
const entry = entriesByName.get(pathKey$2(name));
|
|
201
|
-
if (entry?.isFile()
|
|
202
|
-
else if (entry
|
|
203
|
-
|
|
204
|
-
}
|
|
201
|
+
if (entry?.isFile()) found.set(filePath, "file");
|
|
202
|
+
else if (entry?.isDirectory()) found.set(filePath, "directory");
|
|
203
|
+
else if (entry !== void 0 || process.platform === "win32" && name.includes(":")) await classifyAndAdd(found, filePath);
|
|
205
204
|
}));
|
|
206
205
|
}))]);
|
|
207
206
|
return found;
|
|
@@ -324,23 +323,33 @@ function toPaths(value, roots, variables, preserveSyntax = false) {
|
|
|
324
323
|
});
|
|
325
324
|
}
|
|
326
325
|
async function validateCandidates(candidates, roots, variables, respectIgnore, searchHidden) {
|
|
327
|
-
const
|
|
328
|
-
|
|
326
|
+
const resolvedCandidates = [];
|
|
327
|
+
const validationPaths = /* @__PURE__ */ new Map();
|
|
328
|
+
for (const candidate of candidates) {
|
|
329
329
|
const paths = toPaths(candidate.value, roots, variables, candidate.kind === "inventory" || candidate.kind === "quoted");
|
|
330
330
|
for (const filePath of paths) {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
331
|
+
resolvedCandidates.push({
|
|
332
|
+
candidate,
|
|
333
|
+
path: filePath
|
|
334
|
+
});
|
|
335
|
+
validationPaths.set(pathKey(filePath), filePath);
|
|
334
336
|
}
|
|
335
337
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
338
|
+
let searchablePaths = [...validationPaths.values()];
|
|
339
|
+
if (respectIgnore || !searchHidden) searchablePaths = [...await filterSearchablePaths(searchablePaths, roots, respectIgnore, searchHidden)];
|
|
340
|
+
const classifiedPaths = await classifyExistingPaths(searchablePaths, roots);
|
|
341
|
+
const kindsByPath = new Map([...classifiedPaths].map(([filePath, kind]) => [pathKey(filePath), kind]));
|
|
342
|
+
return resolvedCandidates.flatMap(({ candidate, path }) => {
|
|
343
|
+
const kind = kindsByPath.get(pathKey(path));
|
|
344
|
+
return kind === void 0 ? [] : [{
|
|
345
|
+
kind,
|
|
346
|
+
path,
|
|
347
|
+
position: {
|
|
348
|
+
end: candidate.end,
|
|
349
|
+
start: candidate.start
|
|
350
|
+
}
|
|
351
|
+
}];
|
|
352
|
+
});
|
|
344
353
|
}
|
|
345
354
|
//#endregion
|
|
346
355
|
//#region src/inventory.ts
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["pathKey","pathKey"],"sources":["../config/settings.ts","../src/variables.ts","../src/candidates.ts","../src/existence.ts","../src/policy.ts","../src/filesystem.ts","../src/inventory.ts","../src/index.ts"],"sourcesContent":["import type { SearchSettings } from \"../src/types.js\";\n\nexport const settings: SearchSettings = {\n batchValidationThreshold: 48,\n directoryScanThreshold: 2,\n ignoreFilePatterns: [\"**/.ignore\", \"**/.rgignore\"],\n locationSuffixPattern: /(?::\\d+){1,2}$/u,\n respectIgnoreByDefault: true,\n searchHiddenByDefault: false,\n spanWordLimits: [3, 8, 24],\n trailingPunctuation: \".,;:!?,。;:!?、\",\n validationConcurrency: 32,\n};\n","import type { Variables } from \"./types.js\";\n\nconst nameSource = String.raw`[A-Za-z_][A-Za-z0-9_.-]*`;\nexport const variableReferenceSource = String.raw`(?:\\$\\{\\{\\s*(?:(?:env|vars|variables)[.:])?${nameSource}\\s*\\}\\}|\\{\\{\\s*${nameSource}\\s*\\}\\}|\\$\\{(?:env[.:])?${nameSource}\\}|\\$env:${nameSource}|\\$[A-Za-z_][A-Za-z0-9_]*|%${nameSource}%|!${nameSource}!|\\$\\(\\s*${nameSource}\\s*\\)|@${nameSource}@)`;\nconst expressionPatterns = [\n new RegExp(String.raw`\\$\\{\\{\\s*(?:(?:env|vars|variables)[.:])?(${nameSource})\\s*\\}\\}`, \"giu\"),\n new RegExp(String.raw`\\{\\{\\s*(${nameSource})\\s*\\}\\}`, \"gu\"),\n new RegExp(String.raw`\\$\\{(?:env[.:])?(${nameSource})\\}`, \"giu\"),\n new RegExp(String.raw`\\$env:(${nameSource})`, \"giu\"),\n new RegExp(String.raw`\\$(?!env:)([A-Za-z_][A-Za-z0-9_]*)`, \"giu\"),\n new RegExp(String.raw`%(${nameSource})%`, \"gu\"),\n new RegExp(String.raw`!(${nameSource})!`, \"gu\"),\n new RegExp(String.raw`\\$\\(\\s*(${nameSource})\\s*\\)`, \"gu\"),\n new RegExp(String.raw`@(${nameSource})@`, \"gu\"),\n];\nfunction resolveVariable(name: string, variables: Variables): string | undefined {\n const direct = variables[name] ?? process.env[name];\n if (direct !== undefined) {\n return direct;\n }\n const unscoped = /^(?:env|vars|variables)[.:](.+)$/iu.exec(name)?.[1];\n return unscoped === undefined ? undefined : (variables[unscoped] ?? process.env[unscoped]);\n}\nexport function expandVariables(value: string, variables: Variables): string {\n let result = value;\n for (const pattern of expressionPatterns) {\n result = result.replace(pattern, (match, name: string) => {\n const replacement = resolveVariable(name, variables);\n return replacement === undefined ? match : replacement;\n });\n }\n return result;\n}\n","import type { Candidate, SearchLevel } from \"./types.js\";\nimport { settings } from \"../config/settings.js\";\nimport { variableReferenceSource } from \"./variables.js\";\n\nconst explicitPattern =\n /(?:file:\\/\\/\\/?|[A-Za-z]:[\\\\/]|\\\\\\\\|\\/|(?:\\.{1,2}|~)[\\\\/])[^\"'`<>()[\\]{}\\s]+/gu;\nconst quotedPattern = /([\"'`])(?<value>[^\"'`\\r\\n]+)\\1/gu;\nconst tokenPattern = /[^\\s]+/gu;\nconst pathTokenPattern =\n /(?:[\\p{L}\\p{N}_@%$+~.#[\\],-]+[\\\\/])+(?:[\\p{L}\\p{N}_@%$+~.#[\\],-]+)|[\\p{L}\\p{N}_@%$+~.#[\\],-]+\\.[\\p{L}\\p{N}_@%$-]{1,16}(?::\\d+){0,2}/gu;\nconst unquotedPathCharacterSource = \"[^\\\"'`<>()[\\\\]{}\\\\s]\";\nconst variablePathPattern = new RegExp(\n `${variableReferenceSource}(?:[\\\\\\\\/]${unquotedPathCharacterSource}+)+`,\n \"giu\",\n);\nconst clausePattern = /[^\\r\\n!?!?;;。]+/gu;\nconst pathHintPattern =\n /[\\\\/]|(?:^|[\\s\"'`])(?:\\.{1,2}|~|%[A-Za-z_][A-Za-z0-9_]*%|\\$\\{?[A-Za-z_][A-Za-z0-9_]*\\}?)(?:[\\\\/]|$)|\\.[\\p{L}\\p{N}]{1,16}(?::\\d+){0,2}(?:$|[\\s,.;:!?,。;:!?、])/u;\nconst variableHintPattern = new RegExp(String.raw`${variableReferenceSource}(?:[\\\\/]|$)`, \"iu\");\nfunction add(\n result: Candidate[],\n seen: Set<string>,\n value: string,\n start: number,\n end: number,\n kind: Candidate[\"kind\"],\n): void {\n if (value.length === 0) {\n return;\n }\n const key = `${start}:${end}:${value}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push({ end, kind, start, value });\n }\n}\nfunction addMatches(\n result: Candidate[],\n seen: Set<string>,\n text: string,\n pattern: RegExp,\n kind: Candidate[\"kind\"],\n): void {\n for (const match of text.matchAll(pattern)) {\n const value = match[0];\n const start = match.index ?? 0;\n add(result, seen, value, start, start + value.length, kind);\n }\n}\nfunction addQuotedMatches(result: Candidate[], seen: Set<string>, text: string): void {\n for (const match of text.matchAll(quotedPattern)) {\n const value = match.groups?.value;\n if (value === undefined) {\n continue;\n }\n const start = (match.index ?? 0) + match[0].indexOf(value);\n add(result, seen, value, start, start + value.length, \"quoted\");\n }\n}\nfunction addSpanMatches(\n result: Candidate[],\n seen: Set<string>,\n text: string,\n maximumWords: number,\n): void {\n for (const clause of text.matchAll(clausePattern)) {\n const clauseStart = clause.index ?? 0;\n const clauseText = clause[0];\n const tokens = [...clauseText.matchAll(tokenPattern)].map((token) => ({\n end: clauseStart + (token.index ?? 0) + token[0].length,\n hint: Number(pathHintPattern.test(token[0]) || variableHintPattern.test(token[0])),\n start: clauseStart + (token.index ?? 0),\n value: token[0],\n }));\n const hintCounts = [0];\n for (const token of tokens) {\n hintCounts.push((hintCounts.at(-1) ?? 0) + token.hint);\n }\n for (let start = 0; start < tokens.length; start += 1) {\n const last = Math.min(tokens.length, start + maximumWords);\n for (let end = start + 1; end <= last; end += 1) {\n const firstToken = tokens[start];\n const lastToken = tokens[end - 1];\n const hintsBefore = hintCounts[start];\n const hintsAfter = hintCounts[end];\n if (\n firstToken === undefined ||\n lastToken === undefined ||\n hintsBefore === undefined ||\n hintsAfter === undefined ||\n hintsBefore === hintsAfter\n ) {\n continue;\n }\n const value = text.slice(firstToken.start, lastToken.end);\n if (pathHintPattern.test(value)) {\n add(result, seen, value, firstToken.start, lastToken.end, \"span\");\n }\n }\n }\n }\n}\nexport function extractCandidates(text: string, level: SearchLevel): Candidate[] {\n const result: Candidate[] = [];\n const seen = new Set<string>();\n addQuotedMatches(result, seen, text);\n addMatches(result, seen, text, explicitPattern, \"explicit\");\n if (level >= 2) {\n addMatches(result, seen, text, variablePathPattern, \"heuristic\");\n addMatches(result, seen, text, pathTokenPattern, \"heuristic\");\n }\n if (level >= 3) {\n const maximumWords =\n settings.spanWordLimits[Math.min(level - 3, settings.spanWordLimits.length - 1)];\n if (maximumWords === undefined) {\n throw new RangeError(\"No text-span level is configured\");\n }\n addSpanMatches(result, seen, text, maximumWords);\n }\n return result;\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport nodePath from \"node:path\";\nimport pLimit from \"p-limit\";\nimport { settings } from \"../config/settings.js\";\n\nconst knownFileErrors = new Set([\n \"EACCES\",\n \"ELOOP\",\n \"ENAMETOOLONG\",\n \"ENOTDIR\",\n \"ENOENT\",\n \"EPERM\",\n \"EINVAL\",\n]);\ntype IndexedPath = [filePath: string, candidateIndex: number];\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nfunction isKnownFileError(error: unknown): boolean {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n knownFileErrors.has(error.code)\n );\n}\nasync function isExistingPath(filePath: string): Promise<boolean> {\n try {\n const pathStats = await stat(filePath);\n return pathStats.isFile() || pathStats.isDirectory();\n } catch (error) {\n if (isKnownFileError(error)) {\n return false;\n }\n throw error;\n }\n}\nexport async function locateExistingPaths(\n indexedPaths: readonly IndexedPath[],\n roots: readonly string[],\n): Promise<Set<string>> {\n const found = new Set<string>();\n const limit = pLimit(settings.validationConcurrency);\n if (indexedPaths.length < settings.batchValidationThreshold) {\n await Promise.all(\n indexedPaths.map(([filePath]) =>\n limit(async () => {\n if (await isExistingPath(filePath)) {\n found.add(filePath);\n }\n }),\n ),\n );\n return found;\n }\n const rootKeys = new Set(roots.map(pathKey));\n const pathsByParent = new Map<string, { parent: string; paths: IndexedPath[] }>();\n for (const indexedPath of indexedPaths) {\n const filePath = indexedPath[0];\n if (rootKeys.has(pathKey(filePath))) {\n found.add(filePath);\n continue;\n }\n const parent = nodePath.dirname(filePath);\n const key = pathKey(parent);\n const group = pathsByParent.get(key) ?? { parent, paths: [] };\n group.paths.push(indexedPath);\n pathsByParent.set(key, group);\n }\n const directPaths: IndexedPath[] = [];\n const scannedGroups: { parent: string; paths: IndexedPath[] }[] = [];\n for (const group of pathsByParent.values()) {\n if (group.paths.length < settings.directoryScanThreshold) {\n directPaths.push(...group.paths);\n } else {\n scannedGroups.push(group);\n }\n }\n await Promise.all([\n ...directPaths.map(([filePath]) =>\n limit(async () => {\n if (await isExistingPath(filePath)) {\n found.add(filePath);\n }\n }),\n ),\n ...scannedGroups.map(({ parent, paths }) =>\n limit(async () => {\n let entries;\n try {\n entries = await readdir(parent, { withFileTypes: true });\n } catch (error) {\n if (isKnownFileError(error)) {\n return;\n }\n throw error;\n }\n const entriesByName = new Map(entries.map((entry) => [pathKey(entry.name), entry]));\n await Promise.all(\n paths.map(async ([filePath]) => {\n const name = nodePath.basename(filePath);\n const entry = entriesByName.get(pathKey(name));\n if (entry?.isFile() || entry?.isDirectory()) {\n found.add(filePath);\n } else if (\n entry !== undefined ||\n (process.platform === \"win32\" && name.includes(\":\"))\n ) {\n if (await isExistingPath(filePath)) {\n found.add(filePath);\n }\n }\n }),\n );\n }),\n ),\n ]);\n return found;\n}\n","import { stat } from \"node:fs/promises\";\nimport nodePath from \"node:path\";\nimport fastGlob from \"fast-glob\";\nimport { convertPathToPattern, globby } from \"globby\";\nimport { settings } from \"../config/settings.js\";\n\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nexport function isWithinRoot(filePath: string, root: string): boolean {\n const relative = nodePath.relative(root, filePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" &&\n !relative.startsWith(`..${nodePath.sep}`) &&\n !nodePath.isAbsolute(relative))\n );\n}\nfunction isHidden(relativePath: string): boolean {\n return relativePath.split(/[\\\\/]/u).some((part) => part.length > 1 && part.startsWith(\".\"));\n}\nfunction traversalOptions(root: string, searchHidden: boolean) {\n return {\n caseSensitiveMatch: process.platform !== \"win32\",\n cwd: root,\n dot: searchHidden,\n followSymbolicLinks: false,\n onlyFiles: false,\n unique: true,\n } as const;\n}\nfunction globbyOptions(root: string, respectIgnore: boolean, searchHidden: boolean) {\n return {\n ...traversalOptions(root, searchHidden),\n expandDirectories: false,\n gitignore: respectIgnore,\n globalGitignore: respectIgnore,\n ...(respectIgnore ? { ignoreFiles: settings.ignoreFilePatterns } : {}),\n } as const;\n}\nexport async function resolveSearchDirectories(directories: readonly string[]): Promise<string[]> {\n if (!Array.isArray(directories)) {\n throw new TypeError(\"directories must be an array\");\n }\n if (directories.length === 0) {\n throw new RangeError(\"directories must not be empty\");\n }\n const unique = new Map<string, string>();\n for (const directory of directories) {\n if (typeof directory !== \"string\" || directory.length === 0) {\n throw new TypeError(\"every directory must be a non-empty string\");\n }\n const resolved = nodePath.resolve(directory);\n unique.set(pathKey(resolved), resolved);\n }\n await Promise.all(\n [...unique.values()].map(async (directory) => {\n if (!(await stat(directory)).isDirectory()) {\n throw new TypeError(`${directory} is not a directory`);\n }\n }),\n );\n return [...unique.values()];\n}\nexport async function listSearchEntries(\n root: string,\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<string[]> {\n if (!respectIgnore) {\n return fastGlob(\"**/*\", traversalOptions(root, searchHidden));\n }\n return globby(\"**/*\", globbyOptions(root, respectIgnore, searchHidden));\n}\nexport async function filterSearchablePaths(\n paths: readonly string[],\n roots: readonly string[],\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<Set<string>> {\n const allowed = new Set<string>();\n const pathsByRoot = new Map<string, string[]>();\n for (const filePath of paths) {\n for (const root of roots) {\n if (!isWithinRoot(filePath, root)) {\n continue;\n }\n const relative = nodePath.relative(root, filePath);\n if (!searchHidden && isHidden(relative)) {\n continue;\n }\n if (relative === \"\" || !respectIgnore) {\n allowed.add(filePath);\n } else {\n const grouped = pathsByRoot.get(root) ?? [];\n grouped.push(relative);\n pathsByRoot.set(root, grouped);\n }\n }\n }\n await Promise.all(\n [...pathsByRoot].map(async ([root, relativePaths]) => {\n const patterns = relativePaths.map(convertPathToPattern);\n const matches = await globby(patterns, {\n ...globbyOptions(root, true, true),\n absolute: true,\n });\n for (const match of matches) {\n allowed.add(nodePath.normalize(match));\n }\n }),\n );\n return allowed;\n}\n","import { fileURLToPath } from \"node:url\";\nimport nodePath from \"node:path\";\nimport { locateExistingPaths } from \"./existence.js\";\nimport { filterSearchablePaths, isWithinRoot } from \"./policy.js\";\nimport { expandVariables } from \"./variables.js\";\nimport { settings } from \"../config/settings.js\";\nimport type { Candidate, Variables } from \"./types.js\";\n\nconst driveRelativePattern = /^[A-Za-z]:/u;\nconst parentSegmentPattern = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/u;\ntype IndexedPath = [filePath: string, candidateIndex: number];\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nfunction trimCandidate(value: string, preserveSyntax: boolean): string {\n let result = preserveSyntax ? value : value.trim();\n if (\n result.length >= 2 &&\n ((result[0] === '\"' && result.at(-1) === '\"') ||\n (result[0] === \"'\" && result.at(-1) === \"'\") ||\n (result[0] === \"`\" && result.at(-1) === \"`\"))\n ) {\n result = result.slice(1, -1);\n }\n if (!preserveSyntax) {\n while (result.length > 0 && settings.trailingPunctuation.includes(result.at(-1) ?? \"\")) {\n result = result.slice(0, -1);\n }\n\n result = result.replace(settings.locationSuffixPattern, \"\");\n }\n return result;\n}\nfunction unescape(value: string): string {\n if (value.startsWith(\"\\\\\\\\\") && !value.startsWith(\"\\\\\\\\\\\\\\\\\")) {\n return value;\n }\n return value.replace(/\\\\([\"'`\\\\])/gu, \"$1\").replace(/\\\\\\\\/gu, \"\\\\\");\n}\nfunction toPaths(\n value: string,\n roots: readonly string[],\n variables: Variables,\n preserveSyntax = false,\n): string[] {\n let expanded = expandVariables(trimCandidate(value, preserveSyntax), variables);\n if (expanded.startsWith(\"file://\")) {\n try {\n expanded = fileURLToPath(expanded);\n } catch (error) {\n if (error instanceof TypeError) {\n return [];\n }\n throw error;\n }\n } else {\n expanded = unescape(expanded);\n if (expanded === \"~\" || /^~[\\\\/]/u.test(expanded)) {\n expanded = nodePath.join(\n variables.HOME ??\n variables.USERPROFILE ??\n process.env.HOME ??\n process.env.USERPROFILE ??\n \"\",\n expanded.slice(2),\n );\n }\n }\n if (expanded.length === 0) {\n return [];\n }\n if (nodePath.isAbsolute(expanded)) {\n const absolute = nodePath.normalize(expanded);\n return roots.some((root) => isWithinRoot(absolute, root)) ? [absolute] : [];\n }\n const paths = roots.map((root) => nodePath.resolve(root, expanded));\n if (\n !parentSegmentPattern.test(expanded) &&\n !(process.platform === \"win32\" && driveRelativePattern.test(expanded))\n ) {\n return paths;\n }\n return paths.filter((filePath, index) => {\n const root = roots[index];\n return root !== undefined && isWithinRoot(filePath, root);\n });\n}\nexport async function validateCandidates(\n candidates: Candidate[],\n roots: readonly string[],\n variables: Variables,\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<string[]> {\n const indexedPaths = new Map<string, IndexedPath>();\n for (const [index, candidate] of candidates.entries()) {\n const paths = toPaths(\n candidate.value,\n roots,\n variables,\n candidate.kind === \"inventory\" || candidate.kind === \"quoted\",\n );\n for (const filePath of paths) {\n const key = pathKey(filePath);\n const previous = indexedPaths.get(key);\n const previousIndex = previous?.[1];\n if (previousIndex === undefined || index < previousIndex) {\n indexedPaths.set(key, [filePath, index]);\n }\n }\n }\n const orderedPaths = [...indexedPaths.values()];\n let allowed: Set<string>;\n if (respectIgnore) {\n allowed = await filterSearchablePaths(\n orderedPaths.map(([filePath]) => filePath),\n roots,\n true,\n searchHidden,\n );\n } else {\n allowed = await locateExistingPaths(orderedPaths, roots);\n if (!searchHidden) {\n allowed = await filterSearchablePaths([...allowed], roots, false, false);\n }\n }\n return orderedPaths\n .toSorted((left, right) => left[1] - right[1])\n .map(([filePath]) => filePath)\n .filter((filePath) => allowed.has(filePath));\n}\n","import nodePath from \"node:path\";\nimport { listSearchEntries } from \"./policy.js\";\nimport type { Candidate } from \"./types.js\";\n\nfunction isBoundary(value: string | undefined, following: string | undefined): boolean {\n if (value === \".\") {\n return following === undefined || !/[\\p{L}\\p{N}_-]/u.test(following);\n }\n return value === undefined || !/[\\p{L}\\p{N}_/\\\\-]/u.test(value);\n}\nfunction addOccurrences(\n result: Candidate[],\n seen: Set<string>,\n source: string,\n text: string,\n value: string,\n): void {\n const target = process.platform === \"win32\" ? value.toLowerCase() : value;\n let offset = source.indexOf(target);\n while (offset !== -1) {\n const end = offset + target.length;\n if (isBoundary(text[offset - 1], text[offset]) && isBoundary(text[end], text[end + 1])) {\n const key = `${offset}:${end}:${text.slice(offset, end)}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push({\n end,\n kind: \"inventory\",\n start: offset,\n value,\n });\n }\n }\n offset = source.indexOf(target, offset + 1);\n }\n}\nexport async function inventoryCandidates(\n text: string,\n roots: readonly string[],\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<Candidate[]> {\n const entries = await Promise.all(\n roots.map((root) => listSearchEntries(root, respectIgnore, searchHidden)),\n );\n const result: Candidate[] = [];\n const seen = new Set<string>();\n const scanned = new Set<string>();\n const source = process.platform === \"win32\" ? text.toLowerCase() : text;\n for (const [rootIndex, relativeEntries] of entries.entries()) {\n const root = roots[rootIndex];\n if (root === undefined) {\n continue;\n }\n for (const relativeEntry of relativeEntries) {\n const absoluteEntry = nodePath.resolve(root, relativeEntry);\n const variants = [\n relativeEntry,\n relativeEntry.replaceAll(\"/\", nodePath.sep),\n absoluteEntry,\n absoluteEntry.replaceAll(nodePath.sep, \"/\"),\n ];\n for (const value of variants) {\n const key = process.platform === \"win32\" ? value.toLowerCase() : value;\n if (!scanned.has(key)) {\n scanned.add(key);\n addOccurrences(result, seen, source, text, value);\n }\n }\n }\n }\n return result;\n}\n","import { extractCandidates } from \"./candidates.js\";\nimport { validateCandidates } from \"./filesystem.js\";\nimport { inventoryCandidates } from \"./inventory.js\";\nimport { resolveSearchDirectories } from \"./policy.js\";\nimport { settings } from \"../config/settings.js\";\nimport type { SearchLevel, Variables } from \"./types.js\";\n\nexport const MAX_LEVEL = settings.spanWordLimits.length + 3;\nfunction validateVariables(value: unknown): asserts value is Variables {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value) ||\n Object.values(value).some((item) => typeof item !== \"string\")\n ) {\n throw new TypeError(\"variables must be an object of string values\");\n }\n}\nexport async function findExistingPaths(\n text: string,\n level: SearchLevel,\n directories: readonly string[],\n variables: Variables = {},\n respectIgnore: boolean = settings.respectIgnoreByDefault,\n searchHidden: boolean = settings.searchHiddenByDefault,\n): Promise<string[]> {\n if (typeof text !== \"string\") {\n throw new TypeError(\"text must be a string\");\n }\n if (!Number.isInteger(level) || level < 1 || level > MAX_LEVEL) {\n throw new RangeError(`level must be an integer from 1 to ${MAX_LEVEL}`);\n }\n validateVariables(variables);\n if (typeof respectIgnore !== \"boolean\") {\n throw new TypeError(\"respectIgnore must be a boolean\");\n }\n if (typeof searchHidden !== \"boolean\") {\n throw new TypeError(\"searchHidden must be a boolean\");\n }\n const roots = await resolveSearchDirectories(directories);\n const candidates = extractCandidates(text, level);\n if (level === MAX_LEVEL) {\n candidates.push(...(await inventoryCandidates(text, roots, respectIgnore, searchHidden)));\n }\n return validateCandidates(candidates, roots, variables, respectIgnore, searchHidden);\n}\nexport type { SearchLevel, Variables };\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["pathKey","pathKey"],"sources":["../config/settings.ts","../src/variables.ts","../src/candidates.ts","../src/existence.ts","../src/policy.ts","../src/filesystem.ts","../src/inventory.ts","../src/index.ts"],"sourcesContent":["import type { SearchSettings } from \"../src/types.js\";\n\nexport const settings: SearchSettings = {\n batchValidationThreshold: 48,\n directoryScanThreshold: 2,\n ignoreFilePatterns: [\"**/.ignore\", \"**/.rgignore\"],\n locationSuffixPattern: /(?::\\d+){1,2}$/u,\n respectIgnoreByDefault: true,\n searchHiddenByDefault: false,\n spanWordLimits: [3, 8, 24],\n trailingPunctuation: \".,;:!?,。;:!?、\",\n validationConcurrency: 32,\n};\n","import type { Variables } from \"./types.js\";\n\nconst nameSource = String.raw`[A-Za-z_][A-Za-z0-9_.-]*`;\nexport const variableReferenceSource = String.raw`(?:\\$\\{\\{\\s*(?:(?:env|vars|variables)[.:])?${nameSource}\\s*\\}\\}|\\{\\{\\s*${nameSource}\\s*\\}\\}|\\$\\{(?:env[.:])?${nameSource}\\}|\\$env:${nameSource}|\\$[A-Za-z_][A-Za-z0-9_]*|%${nameSource}%|!${nameSource}!|\\$\\(\\s*${nameSource}\\s*\\)|@${nameSource}@)`;\nconst expressionPatterns = [\n new RegExp(String.raw`\\$\\{\\{\\s*(?:(?:env|vars|variables)[.:])?(${nameSource})\\s*\\}\\}`, \"giu\"),\n new RegExp(String.raw`\\{\\{\\s*(${nameSource})\\s*\\}\\}`, \"gu\"),\n new RegExp(String.raw`\\$\\{(?:env[.:])?(${nameSource})\\}`, \"giu\"),\n new RegExp(String.raw`\\$env:(${nameSource})`, \"giu\"),\n new RegExp(String.raw`\\$(?!env:)([A-Za-z_][A-Za-z0-9_]*)`, \"giu\"),\n new RegExp(String.raw`%(${nameSource})%`, \"gu\"),\n new RegExp(String.raw`!(${nameSource})!`, \"gu\"),\n new RegExp(String.raw`\\$\\(\\s*(${nameSource})\\s*\\)`, \"gu\"),\n new RegExp(String.raw`@(${nameSource})@`, \"gu\"),\n];\nfunction resolveVariable(name: string, variables: Variables): string | undefined {\n const direct = variables[name] ?? process.env[name];\n if (direct !== undefined) {\n return direct;\n }\n const unscoped = /^(?:env|vars|variables)[.:](.+)$/iu.exec(name)?.[1];\n return unscoped === undefined ? undefined : (variables[unscoped] ?? process.env[unscoped]);\n}\nexport function expandVariables(value: string, variables: Variables): string {\n let result = value;\n for (const pattern of expressionPatterns) {\n result = result.replace(pattern, (match, name: string) => {\n const replacement = resolveVariable(name, variables);\n return replacement === undefined ? match : replacement;\n });\n }\n return result;\n}\n","import type { Candidate, SearchLevel } from \"./types.js\";\nimport { settings } from \"../config/settings.js\";\nimport { variableReferenceSource } from \"./variables.js\";\n\nconst explicitPattern =\n /(?:file:\\/\\/\\/?|[A-Za-z]:[\\\\/]|\\\\\\\\|\\/|(?:\\.{1,2}|~)[\\\\/])[^\"'`<>()[\\]{}\\s]+/gu;\nconst quotedPattern = /([\"'`])(?<value>[^\"'`\\r\\n]+)\\1/gu;\nconst tokenPattern = /[^\\s]+/gu;\nconst pathTokenPattern =\n /(?:[\\p{L}\\p{N}_@%$+~.#[\\],-]+[\\\\/])+(?:[\\p{L}\\p{N}_@%$+~.#[\\],-]+)|[\\p{L}\\p{N}_@%$+~.#[\\],-]+\\.[\\p{L}\\p{N}_@%$-]{1,16}(?::\\d+){0,2}/gu;\nconst unquotedPathCharacterSource = \"[^\\\"'`<>()[\\\\]{}\\\\s]\";\nconst variablePathPattern = new RegExp(\n `${variableReferenceSource}(?:[\\\\\\\\/]${unquotedPathCharacterSource}+)+`,\n \"giu\",\n);\nconst clausePattern = /[^\\r\\n!?!?;;。]+/gu;\nconst pathHintPattern =\n /[\\\\/]|(?:^|[\\s\"'`])(?:\\.{1,2}|~|%[A-Za-z_][A-Za-z0-9_]*%|\\$\\{?[A-Za-z_][A-Za-z0-9_]*\\}?)(?:[\\\\/]|$)|\\.[\\p{L}\\p{N}]{1,16}(?::\\d+){0,2}(?:$|[\\s,.;:!?,。;:!?、])/u;\nconst variableHintPattern = new RegExp(String.raw`${variableReferenceSource}(?:[\\\\/]|$)`, \"iu\");\nfunction add(\n result: Candidate[],\n seen: Set<string>,\n value: string,\n start: number,\n end: number,\n kind: Candidate[\"kind\"],\n): void {\n if (value.length === 0) {\n return;\n }\n const key = `${start}:${end}:${value}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push({ end, kind, start, value });\n }\n}\nfunction addMatches(\n result: Candidate[],\n seen: Set<string>,\n text: string,\n pattern: RegExp,\n kind: Candidate[\"kind\"],\n): void {\n for (const match of text.matchAll(pattern)) {\n const value = match[0];\n const start = match.index ?? 0;\n add(result, seen, value, start, start + value.length, kind);\n }\n}\nfunction addQuotedMatches(result: Candidate[], seen: Set<string>, text: string): void {\n for (const match of text.matchAll(quotedPattern)) {\n const value = match.groups?.value;\n if (value === undefined) {\n continue;\n }\n const start = (match.index ?? 0) + match[0].indexOf(value);\n add(result, seen, value, start, start + value.length, \"quoted\");\n }\n}\nfunction addSpanMatches(\n result: Candidate[],\n seen: Set<string>,\n text: string,\n maximumWords: number,\n): void {\n for (const clause of text.matchAll(clausePattern)) {\n const clauseStart = clause.index ?? 0;\n const clauseText = clause[0];\n const tokens = [...clauseText.matchAll(tokenPattern)].map((token) => ({\n end: clauseStart + (token.index ?? 0) + token[0].length,\n hint: Number(pathHintPattern.test(token[0]) || variableHintPattern.test(token[0])),\n start: clauseStart + (token.index ?? 0),\n value: token[0],\n }));\n const hintCounts = [0];\n for (const token of tokens) {\n hintCounts.push((hintCounts.at(-1) ?? 0) + token.hint);\n }\n for (let start = 0; start < tokens.length; start += 1) {\n const last = Math.min(tokens.length, start + maximumWords);\n for (let end = start + 1; end <= last; end += 1) {\n const firstToken = tokens[start];\n const lastToken = tokens[end - 1];\n const hintsBefore = hintCounts[start];\n const hintsAfter = hintCounts[end];\n if (\n firstToken === undefined ||\n lastToken === undefined ||\n hintsBefore === undefined ||\n hintsAfter === undefined ||\n hintsBefore === hintsAfter\n ) {\n continue;\n }\n const value = text.slice(firstToken.start, lastToken.end);\n if (pathHintPattern.test(value)) {\n add(result, seen, value, firstToken.start, lastToken.end, \"span\");\n }\n }\n }\n }\n}\nexport function extractCandidates(text: string, level: SearchLevel): Candidate[] {\n const result: Candidate[] = [];\n const seen = new Set<string>();\n addQuotedMatches(result, seen, text);\n addMatches(result, seen, text, explicitPattern, \"explicit\");\n if (level >= 2) {\n addMatches(result, seen, text, variablePathPattern, \"heuristic\");\n addMatches(result, seen, text, pathTokenPattern, \"heuristic\");\n }\n if (level >= 3) {\n const maximumWords =\n settings.spanWordLimits[Math.min(level - 3, settings.spanWordLimits.length - 1)];\n if (maximumWords === undefined) {\n throw new RangeError(\"No text-span level is configured\");\n }\n addSpanMatches(result, seen, text, maximumWords);\n }\n return result;\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport nodePath from \"node:path\";\nimport pLimit from \"p-limit\";\nimport { settings } from \"../config/settings.js\";\nimport type { PathKind } from \"./types.js\";\n\nconst knownFileErrors = new Set([\n \"EACCES\",\n \"ELOOP\",\n \"ENAMETOOLONG\",\n \"ENOTDIR\",\n \"ENOENT\",\n \"EPERM\",\n \"EINVAL\",\n]);\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nfunction isKnownFileError(error: unknown): boolean {\n return (\n error instanceof Error &&\n \"code\" in error &&\n typeof error.code === \"string\" &&\n knownFileErrors.has(error.code)\n );\n}\nasync function classifyPath(filePath: string): Promise<PathKind | undefined> {\n try {\n const pathStats = await stat(filePath);\n if (pathStats.isFile()) {\n return \"file\";\n }\n return pathStats.isDirectory() ? \"directory\" : undefined;\n } catch (error) {\n if (isKnownFileError(error)) {\n return undefined;\n }\n throw error;\n }\n}\nasync function classifyAndAdd(found: Map<string, PathKind>, filePath: string): Promise<void> {\n const kind = await classifyPath(filePath);\n if (kind !== undefined) {\n found.set(filePath, kind);\n }\n}\nexport async function classifyExistingPaths(\n paths: readonly string[],\n roots: readonly string[],\n): Promise<Map<string, PathKind>> {\n const found = new Map<string, PathKind>();\n const limit = pLimit(settings.validationConcurrency);\n if (paths.length < settings.batchValidationThreshold) {\n await Promise.all(paths.map((filePath) => limit(() => classifyAndAdd(found, filePath))));\n return found;\n }\n const rootKeys = new Set(roots.map(pathKey));\n const pathsByParent = new Map<string, { parent: string; paths: string[] }>();\n for (const filePath of paths) {\n if (rootKeys.has(pathKey(filePath))) {\n found.set(filePath, \"directory\");\n continue;\n }\n const parent = nodePath.dirname(filePath);\n const key = pathKey(parent);\n const group = pathsByParent.get(key) ?? { parent, paths: [] };\n group.paths.push(filePath);\n pathsByParent.set(key, group);\n }\n const directPaths: string[] = [];\n const scannedGroups: { parent: string; paths: string[] }[] = [];\n for (const group of pathsByParent.values()) {\n if (group.paths.length < settings.directoryScanThreshold) {\n directPaths.push(...group.paths);\n } else {\n scannedGroups.push(group);\n }\n }\n await Promise.all([\n ...directPaths.map((filePath) => limit(() => classifyAndAdd(found, filePath))),\n ...scannedGroups.map(({ parent, paths: groupPaths }) =>\n limit(async () => {\n let entries;\n try {\n entries = await readdir(parent, { withFileTypes: true });\n } catch (error) {\n if (isKnownFileError(error)) {\n return;\n }\n throw error;\n }\n const entriesByName = new Map(entries.map((entry) => [pathKey(entry.name), entry]));\n await Promise.all(\n groupPaths.map(async (filePath) => {\n const name = nodePath.basename(filePath);\n const entry = entriesByName.get(pathKey(name));\n if (entry?.isFile()) {\n found.set(filePath, \"file\");\n } else if (entry?.isDirectory()) {\n found.set(filePath, \"directory\");\n } else if (\n entry !== undefined ||\n (process.platform === \"win32\" && name.includes(\":\"))\n ) {\n await classifyAndAdd(found, filePath);\n }\n }),\n );\n }),\n ),\n ]);\n return found;\n}\n","import { stat } from \"node:fs/promises\";\nimport nodePath from \"node:path\";\nimport fastGlob from \"fast-glob\";\nimport { convertPathToPattern, globby } from \"globby\";\nimport { settings } from \"../config/settings.js\";\n\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nexport function isWithinRoot(filePath: string, root: string): boolean {\n const relative = nodePath.relative(root, filePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" &&\n !relative.startsWith(`..${nodePath.sep}`) &&\n !nodePath.isAbsolute(relative))\n );\n}\nfunction isHidden(relativePath: string): boolean {\n return relativePath.split(/[\\\\/]/u).some((part) => part.length > 1 && part.startsWith(\".\"));\n}\nfunction traversalOptions(root: string, searchHidden: boolean) {\n return {\n caseSensitiveMatch: process.platform !== \"win32\",\n cwd: root,\n dot: searchHidden,\n followSymbolicLinks: false,\n onlyFiles: false,\n unique: true,\n } as const;\n}\nfunction globbyOptions(root: string, respectIgnore: boolean, searchHidden: boolean) {\n return {\n ...traversalOptions(root, searchHidden),\n expandDirectories: false,\n gitignore: respectIgnore,\n globalGitignore: respectIgnore,\n ...(respectIgnore ? { ignoreFiles: settings.ignoreFilePatterns } : {}),\n } as const;\n}\nexport async function resolveSearchDirectories(directories: readonly string[]): Promise<string[]> {\n if (!Array.isArray(directories)) {\n throw new TypeError(\"directories must be an array\");\n }\n if (directories.length === 0) {\n throw new RangeError(\"directories must not be empty\");\n }\n const unique = new Map<string, string>();\n for (const directory of directories) {\n if (typeof directory !== \"string\" || directory.length === 0) {\n throw new TypeError(\"every directory must be a non-empty string\");\n }\n const resolved = nodePath.resolve(directory);\n unique.set(pathKey(resolved), resolved);\n }\n await Promise.all(\n [...unique.values()].map(async (directory) => {\n if (!(await stat(directory)).isDirectory()) {\n throw new TypeError(`${directory} is not a directory`);\n }\n }),\n );\n return [...unique.values()];\n}\nexport async function listSearchEntries(\n root: string,\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<string[]> {\n if (!respectIgnore) {\n return fastGlob(\"**/*\", traversalOptions(root, searchHidden));\n }\n return globby(\"**/*\", globbyOptions(root, respectIgnore, searchHidden));\n}\nexport async function filterSearchablePaths(\n paths: readonly string[],\n roots: readonly string[],\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<Set<string>> {\n const allowed = new Set<string>();\n const pathsByRoot = new Map<string, string[]>();\n for (const filePath of paths) {\n for (const root of roots) {\n if (!isWithinRoot(filePath, root)) {\n continue;\n }\n const relative = nodePath.relative(root, filePath);\n if (!searchHidden && isHidden(relative)) {\n continue;\n }\n if (relative === \"\" || !respectIgnore) {\n allowed.add(filePath);\n } else {\n const grouped = pathsByRoot.get(root) ?? [];\n grouped.push(relative);\n pathsByRoot.set(root, grouped);\n }\n }\n }\n await Promise.all(\n [...pathsByRoot].map(async ([root, relativePaths]) => {\n const patterns = relativePaths.map(convertPathToPattern);\n const matches = await globby(patterns, {\n ...globbyOptions(root, true, true),\n absolute: true,\n });\n for (const match of matches) {\n allowed.add(nodePath.normalize(match));\n }\n }),\n );\n return allowed;\n}\n","import { fileURLToPath } from \"node:url\";\nimport nodePath from \"node:path\";\nimport { classifyExistingPaths } from \"./existence.js\";\nimport { filterSearchablePaths, isWithinRoot } from \"./policy.js\";\nimport { expandVariables } from \"./variables.js\";\nimport { settings } from \"../config/settings.js\";\nimport type { Candidate, PathMatch, Variables } from \"./types.js\";\n\nconst driveRelativePattern = /^[A-Za-z]:/u;\nconst parentSegmentPattern = /(?:^|[\\\\/])\\.\\.(?:[\\\\/]|$)/u;\ninterface ResolvedCandidate {\n candidate: Candidate;\n path: string;\n}\nfunction pathKey(value: string): string {\n return process.platform === \"win32\" ? value.toLowerCase() : value;\n}\nfunction trimCandidate(value: string, preserveSyntax: boolean): string {\n let result = preserveSyntax ? value : value.trim();\n if (\n result.length >= 2 &&\n ((result[0] === '\"' && result.at(-1) === '\"') ||\n (result[0] === \"'\" && result.at(-1) === \"'\") ||\n (result[0] === \"`\" && result.at(-1) === \"`\"))\n ) {\n result = result.slice(1, -1);\n }\n if (!preserveSyntax) {\n while (result.length > 0 && settings.trailingPunctuation.includes(result.at(-1) ?? \"\")) {\n result = result.slice(0, -1);\n }\n\n result = result.replace(settings.locationSuffixPattern, \"\");\n }\n return result;\n}\nfunction unescape(value: string): string {\n if (value.startsWith(\"\\\\\\\\\") && !value.startsWith(\"\\\\\\\\\\\\\\\\\")) {\n return value;\n }\n return value.replace(/\\\\([\"'`\\\\])/gu, \"$1\").replace(/\\\\\\\\/gu, \"\\\\\");\n}\nfunction toPaths(\n value: string,\n roots: readonly string[],\n variables: Variables,\n preserveSyntax = false,\n): string[] {\n let expanded = expandVariables(trimCandidate(value, preserveSyntax), variables);\n if (expanded.startsWith(\"file://\")) {\n try {\n expanded = fileURLToPath(expanded);\n } catch (error) {\n if (error instanceof TypeError) {\n return [];\n }\n throw error;\n }\n } else {\n expanded = unescape(expanded);\n if (expanded === \"~\" || /^~[\\\\/]/u.test(expanded)) {\n expanded = nodePath.join(\n variables.HOME ??\n variables.USERPROFILE ??\n process.env.HOME ??\n process.env.USERPROFILE ??\n \"\",\n expanded.slice(2),\n );\n }\n }\n if (expanded.length === 0) {\n return [];\n }\n if (nodePath.isAbsolute(expanded)) {\n const absolute = nodePath.normalize(expanded);\n return roots.some((root) => isWithinRoot(absolute, root)) ? [absolute] : [];\n }\n const paths = roots.map((root) => nodePath.resolve(root, expanded));\n if (\n !parentSegmentPattern.test(expanded) &&\n !(process.platform === \"win32\" && driveRelativePattern.test(expanded))\n ) {\n return paths;\n }\n return paths.filter((filePath, index) => {\n const root = roots[index];\n return root !== undefined && isWithinRoot(filePath, root);\n });\n}\nexport async function validateCandidates(\n candidates: Candidate[],\n roots: readonly string[],\n variables: Variables,\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<PathMatch[]> {\n const resolvedCandidates: ResolvedCandidate[] = [];\n const validationPaths = new Map<string, string>();\n for (const candidate of candidates) {\n const paths = toPaths(\n candidate.value,\n roots,\n variables,\n candidate.kind === \"inventory\" || candidate.kind === \"quoted\",\n );\n for (const filePath of paths) {\n resolvedCandidates.push({ candidate, path: filePath });\n validationPaths.set(pathKey(filePath), filePath);\n }\n }\n let searchablePaths = [...validationPaths.values()];\n if (respectIgnore || !searchHidden) {\n searchablePaths = [\n ...(await filterSearchablePaths(searchablePaths, roots, respectIgnore, searchHidden)),\n ];\n }\n const classifiedPaths = await classifyExistingPaths(searchablePaths, roots);\n const kindsByPath = new Map(\n [...classifiedPaths].map(([filePath, kind]) => [pathKey(filePath), kind]),\n );\n return resolvedCandidates.flatMap(({ candidate, path }) => {\n const kind = kindsByPath.get(pathKey(path));\n return kind === undefined\n ? []\n : [\n {\n kind,\n path,\n position: {\n end: candidate.end,\n start: candidate.start,\n },\n },\n ];\n });\n}\n","import nodePath from \"node:path\";\nimport { listSearchEntries } from \"./policy.js\";\nimport type { Candidate } from \"./types.js\";\n\nfunction isBoundary(value: string | undefined, following: string | undefined): boolean {\n if (value === \".\") {\n return following === undefined || !/[\\p{L}\\p{N}_-]/u.test(following);\n }\n return value === undefined || !/[\\p{L}\\p{N}_/\\\\-]/u.test(value);\n}\nfunction addOccurrences(\n result: Candidate[],\n seen: Set<string>,\n source: string,\n text: string,\n value: string,\n): void {\n const target = process.platform === \"win32\" ? value.toLowerCase() : value;\n let offset = source.indexOf(target);\n while (offset !== -1) {\n const end = offset + target.length;\n if (isBoundary(text[offset - 1], text[offset]) && isBoundary(text[end], text[end + 1])) {\n const key = `${offset}:${end}:${text.slice(offset, end)}`;\n if (!seen.has(key)) {\n seen.add(key);\n result.push({\n end,\n kind: \"inventory\",\n start: offset,\n value,\n });\n }\n }\n offset = source.indexOf(target, offset + 1);\n }\n}\nexport async function inventoryCandidates(\n text: string,\n roots: readonly string[],\n respectIgnore: boolean,\n searchHidden: boolean,\n): Promise<Candidate[]> {\n const entries = await Promise.all(\n roots.map((root) => listSearchEntries(root, respectIgnore, searchHidden)),\n );\n const result: Candidate[] = [];\n const seen = new Set<string>();\n const scanned = new Set<string>();\n const source = process.platform === \"win32\" ? text.toLowerCase() : text;\n for (const [rootIndex, relativeEntries] of entries.entries()) {\n const root = roots[rootIndex];\n if (root === undefined) {\n continue;\n }\n for (const relativeEntry of relativeEntries) {\n const absoluteEntry = nodePath.resolve(root, relativeEntry);\n const variants = [\n relativeEntry,\n relativeEntry.replaceAll(\"/\", nodePath.sep),\n absoluteEntry,\n absoluteEntry.replaceAll(nodePath.sep, \"/\"),\n ];\n for (const value of variants) {\n const key = process.platform === \"win32\" ? value.toLowerCase() : value;\n if (!scanned.has(key)) {\n scanned.add(key);\n addOccurrences(result, seen, source, text, value);\n }\n }\n }\n }\n return result;\n}\n","import { extractCandidates } from \"./candidates.js\";\nimport { validateCandidates } from \"./filesystem.js\";\nimport { inventoryCandidates } from \"./inventory.js\";\nimport { resolveSearchDirectories } from \"./policy.js\";\nimport { settings } from \"../config/settings.js\";\nimport type { PathMatch, SearchLevel, Variables } from \"./types.js\";\n\nexport const MAX_LEVEL = settings.spanWordLimits.length + 3;\nfunction validateVariables(value: unknown): asserts value is Variables {\n if (\n typeof value !== \"object\" ||\n value === null ||\n Array.isArray(value) ||\n Object.values(value).some((item) => typeof item !== \"string\")\n ) {\n throw new TypeError(\"variables must be an object of string values\");\n }\n}\nexport async function findExistingPaths(\n text: string,\n level: SearchLevel,\n directories: readonly string[],\n variables: Variables = {},\n respectIgnore: boolean = settings.respectIgnoreByDefault,\n searchHidden: boolean = settings.searchHiddenByDefault,\n): Promise<PathMatch[]> {\n if (typeof text !== \"string\") {\n throw new TypeError(\"text must be a string\");\n }\n if (!Number.isInteger(level) || level < 1 || level > MAX_LEVEL) {\n throw new RangeError(`level must be an integer from 1 to ${MAX_LEVEL}`);\n }\n validateVariables(variables);\n if (typeof respectIgnore !== \"boolean\") {\n throw new TypeError(\"respectIgnore must be a boolean\");\n }\n if (typeof searchHidden !== \"boolean\") {\n throw new TypeError(\"searchHidden must be a boolean\");\n }\n const roots = await resolveSearchDirectories(directories);\n const candidates = extractCandidates(text, level);\n if (level === MAX_LEVEL) {\n candidates.push(...(await inventoryCandidates(text, roots, respectIgnore, searchHidden)));\n }\n return validateCandidates(candidates, roots, variables, respectIgnore, searchHidden);\n}\nexport type { PathKind, PathMatch, PathPosition, SearchLevel, Variables } from \"./types.js\";\n"],"mappings":"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"}
|
|
@@ -1,3 +1,2 @@
|
|
|
1
|
-
type
|
|
2
|
-
export declare function
|
|
3
|
-
export {};
|
|
1
|
+
import type { PathKind } from "./types.js";
|
|
2
|
+
export declare function classifyExistingPaths(paths: readonly string[], roots: readonly string[]): Promise<Map<string, PathKind>>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import type { Candidate, Variables } from "./types.js";
|
|
2
|
-
export declare function validateCandidates(candidates: Candidate[], roots: readonly string[], variables: Variables, respectIgnore: boolean, searchHidden: boolean): Promise<
|
|
1
|
+
import type { Candidate, PathMatch, Variables } from "./types.js";
|
|
2
|
+
export declare function validateCandidates(candidates: Candidate[], roots: readonly string[], variables: Variables, respectIgnore: boolean, searchHidden: boolean): Promise<PathMatch[]>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { SearchLevel, Variables } from "./types.js";
|
|
1
|
+
import type { PathMatch, SearchLevel, Variables } from "./types.js";
|
|
2
2
|
export declare const MAX_LEVEL: number;
|
|
3
|
-
export declare function findExistingPaths(text: string, level: SearchLevel, directories: readonly string[], variables?: Variables, respectIgnore?: boolean, searchHidden?: boolean): Promise<
|
|
4
|
-
export type { SearchLevel, Variables };
|
|
3
|
+
export declare function findExistingPaths(text: string, level: SearchLevel, directories: readonly string[], variables?: Variables, respectIgnore?: boolean, searchHidden?: boolean): Promise<PathMatch[]>;
|
|
4
|
+
export type { PathKind, PathMatch, PathPosition, SearchLevel, Variables } from "./types.js";
|
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
export type SearchLevel = number;
|
|
2
|
+
export type PathKind = "directory" | "file";
|
|
3
|
+
export interface PathPosition {
|
|
4
|
+
end: number;
|
|
5
|
+
start: number;
|
|
6
|
+
}
|
|
7
|
+
export interface PathMatch {
|
|
8
|
+
kind: PathKind;
|
|
9
|
+
path: string;
|
|
10
|
+
position: PathPosition;
|
|
11
|
+
}
|
|
2
12
|
export type CandidateKind = "explicit" | "heuristic" | "inventory" | "quoted" | "span";
|
|
3
13
|
export interface Candidate {
|
|
4
14
|
end: number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pathprobe",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Extract, resolve, and validate file and directory paths mentioned in text, with variable expansion, ignore rules, hidden-file control, and configurable search roots.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|