@dirwell/core 0.0.1 → 0.0.2
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/README.md +1 -1
- package/dist/client.d.mts +1 -1
- package/dist/index.d.mts +17 -6
- package/dist/index.mjs +37 -4
- package/dist/index.mjs.map +1 -1
- package/dist/{listing-B_6TbWuz.d.mts → listing-CG4b6tOt.d.mts} +3 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @dirwell/core
|
|
2
2
|
|
|
3
|
-
Framework-neutral filesystem, listing and static-publication SDK. Requires Node.js 22.12 or newer. For this quick start, install `npm install @dirwell/core@0.0.
|
|
3
|
+
Framework-neutral filesystem, listing and static-publication SDK. Requires Node.js 22.12 or newer. For this quick start, install `npm install @dirwell/core@0.0.2 @dirwell/theme-plain@0.0.2`.
|
|
4
4
|
|
|
5
5
|
Core owns filesystem selection, safe navigation, public listing projection and static publication. It requires an explicit theme and does not load a default theme, image renderer, frontend framework, config loader or watcher. Runtime matching uses picomatch for globs and ignore for Git-style ignore files.
|
|
6
6
|
|
package/dist/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as ListingManifest, r as ListingEntry, t as ListingBlock } from "./listing-
|
|
1
|
+
import { i as ListingManifest, r as ListingEntry, t as ListingBlock } from "./listing-CG4b6tOt.mjs";
|
|
2
2
|
//#region src/client.d.ts
|
|
3
3
|
export declare class ListingDataError extends Error {
|
|
4
4
|
readonly name = "ListingDataError";
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
|
-
import { A as SymlinkMetadata, B as ResolvedMetadataContext, C as MetadataProviderFactory, D as SortDirection, E as RenderedPage, F as MetadataImage, H as JsonObject, I as MetadataImageValue, L as MetadataOptions, M as ContentCounts, N as ImageSource, O as SortField, P as MetadataContext, R as MetadataValue, S as MetadataProvider, T as OutputNameResolver, U as JsonValue, V as ThemeMetadataDefaults, W as copyJsonObject, _ as FileMetadata, a as ListingPage, b as GenerateOptions, c as ListingPolicyContext, d as projectListingEntry, f as BuildReport, g as ExplorerTheme, h as EntryKind, i as ListingManifest, j as ThemeContext, k as SortOptions, l as entryDataFacts, m as EntryDataProvider, n as ListingContext, o as ListingPlan, p as DirectoryData, r as ListingEntry, s as ListingPolicy, t as ListingBlock, u as listingRevision, v as FileSystemEntry, w as NameSortMode, x as IgnoreFile, y as FileTimes, z as PageMetadata } from "./listing-
|
|
1
|
+
import { A as SymlinkMetadata, B as ResolvedMetadataContext, C as MetadataProviderFactory, D as SortDirection, E as RenderedPage, F as MetadataImage, H as JsonObject, I as MetadataImageValue, L as MetadataOptions, M as ContentCounts, N as ImageSource, O as SortField, P as MetadataContext, R as MetadataValue, S as MetadataProvider, T as OutputNameResolver, U as JsonValue, V as ThemeMetadataDefaults, W as copyJsonObject, _ as FileMetadata, a as ListingPage, b as GenerateOptions, c as ListingPolicyContext, d as projectListingEntry, f as BuildReport, g as ExplorerTheme, h as EntryKind, i as ListingManifest, j as ThemeContext, k as SortOptions, l as entryDataFacts, m as EntryDataProvider, n as ListingContext, o as ListingPlan, p as DirectoryData, r as ListingEntry, s as ListingPolicy, t as ListingBlock, u as listingRevision, v as FileSystemEntry, w as NameSortMode, x as IgnoreFile, y as FileTimes, z as PageMetadata } from "./listing-CG4b6tOt.mjs";
|
|
2
2
|
import { FileHandle } from "node:fs/promises";
|
|
3
|
+
//#region src/filters.d.ts
|
|
4
|
+
/** Resolve configuration paths once, before a host changes working directories. */
|
|
5
|
+
export declare function resolveIgnoreFiles(value?: unknown, cwd?: string): readonly Exclude<IgnoreFile, string>[];
|
|
6
|
+
interface SelectionBudget {
|
|
7
|
+
readonly maxEntries: number;
|
|
8
|
+
readonly maxDirectories: number;
|
|
9
|
+
readonly signal: AbortSignal;
|
|
10
|
+
readonly allowPath: (logicalPath: string) => Promise<boolean>;
|
|
11
|
+
}
|
|
12
|
+
export declare class SelectionBudgetError extends Error {
|
|
13
|
+
readonly name = "SelectionBudgetError";
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
3
16
|
//#region src/service.d.ts
|
|
4
17
|
interface DirectoryServiceOptions {
|
|
5
18
|
readonly entryData?: EntryDataProvider;
|
|
@@ -10,6 +23,8 @@ interface DirectoryServiceOptions {
|
|
|
10
23
|
readonly sort?: SortOptions;
|
|
11
24
|
}
|
|
12
25
|
interface DirectoryService {
|
|
26
|
+
/** Bounded fresh enumeration; authorization runs before directory traversal. */
|
|
27
|
+
readonly scan: (budget: SelectionBudget) => Promise<readonly FileSystemEntry[]>;
|
|
13
28
|
readonly resolvePath: (logicalPath: string) => Promise<string>;
|
|
14
29
|
readonly openFile: (logicalPath: string) => Promise<{
|
|
15
30
|
readonly entry: FileSystemEntry;
|
|
@@ -40,9 +55,5 @@ export declare function readGeneratedPage(filePath: string): Promise<string>;
|
|
|
40
55
|
/** Escape untrusted text for HTML/XML text nodes and double-quoted attributes. */
|
|
41
56
|
export declare function escapeHtml(value: string): string;
|
|
42
57
|
//#endregion
|
|
43
|
-
|
|
44
|
-
/** Resolve configuration paths once, before a host changes working directories. */
|
|
45
|
-
export declare function resolveIgnoreFiles(value?: unknown, cwd?: string): readonly Exclude<IgnoreFile, string>[];
|
|
46
|
-
//#endregion
|
|
47
|
-
export { type BuildReport, type ContentCounts, type DirectoryData, type DirectoryService, type DirectoryServiceOptions, type EntryDataProvider, type EntryKind, type ExplorerTheme, type FileMetadata, type FileSystemEntry, type FileTimes, type GenerateOptions, type IgnoreFile, type ImageSource, type JsonObject, type JsonValue, type ListingBlock, type ListingContext, type ListingEntry, type ListingManifest, type ListingPage, type ListingPlan, type ListingPolicy, type ListingPolicyContext, type MetadataContext, type MetadataImage, type MetadataImageValue, type MetadataOptions, type MetadataProvider, type MetadataProviderFactory, type MetadataValue, type NameSortMode, type OutputNameResolver, type PageMetadata, type RenderedPage, type ResolvedMetadataContext, type SortDirection, type SortField, type SortOptions, type SymlinkMetadata, type ThemeContext, type ThemeMetadataDefaults, copyJsonObject, type entryDataFacts, listingRevision, projectListingEntry };
|
|
58
|
+
export { type BuildReport, type ContentCounts, type DirectoryData, type DirectoryService, type DirectoryServiceOptions, type EntryDataProvider, type EntryKind, type ExplorerTheme, type FileMetadata, type FileSystemEntry, type FileTimes, type GenerateOptions, type IgnoreFile, type ImageSource, type JsonObject, type JsonValue, type ListingBlock, type ListingContext, type ListingEntry, type ListingManifest, type ListingPage, type ListingPlan, type ListingPolicy, type ListingPolicyContext, type MetadataContext, type MetadataImage, type MetadataImageValue, type MetadataOptions, type MetadataProvider, type MetadataProviderFactory, type MetadataValue, type NameSortMode, type OutputNameResolver, type PageMetadata, type RenderedPage, type ResolvedMetadataContext, type SelectionBudget, type SortDirection, type SortField, type SortOptions, type SymlinkMetadata, type ThemeContext, type ThemeMetadataDefaults, copyJsonObject, type entryDataFacts, listingRevision, projectListingEntry };
|
|
48
59
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { t as copyJsonObject } from "./json-Bvj6xQLq.mjs";
|
|
2
|
-
import { cp, lstat, mkdir, mkdtemp, open, readFile, readdir, readlink, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
2
|
+
import { cp, lstat, mkdir, mkdtemp, open, opendir, readFile, readdir, readlink, realpath, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import picomatch from "picomatch";
|
|
5
5
|
import ignore from "ignore";
|
|
@@ -77,8 +77,11 @@ function isWithin(parent, candidate) {
|
|
|
77
77
|
const relative = path.relative(parent, candidate);
|
|
78
78
|
return relative === "" || relative !== ".." && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative);
|
|
79
79
|
}
|
|
80
|
+
var SelectionBudgetError = class extends Error {
|
|
81
|
+
name = "SelectionBudgetError";
|
|
82
|
+
};
|
|
80
83
|
/** Select physical source paths; parent directories remain when a descendant matches. */
|
|
81
|
-
async function selectSourcePaths(sourceDir, outputDir, include, exclude, ignoredPaths = [], ignoreFiles = [], preparedIgnore) {
|
|
84
|
+
async function selectSourcePaths(sourceDir, outputDir, include, exclude, ignoredPaths = [], ignoreFiles = [], preparedIgnore, budget) {
|
|
82
85
|
const isIgnored = preparedIgnore ?? await createIgnoreMatcher(ignoreFiles);
|
|
83
86
|
const canonicalRoot = await realpath(sourceDir);
|
|
84
87
|
const ignored = ignoredPaths.map((value) => path.resolve(value));
|
|
@@ -92,12 +95,25 @@ async function selectSourcePaths(sourceDir, outputDir, include, exclude, ignored
|
|
|
92
95
|
}));
|
|
93
96
|
const selected = /* @__PURE__ */ new Set([""]);
|
|
94
97
|
const symlinks = /* @__PURE__ */ new Map();
|
|
98
|
+
let entries = 0;
|
|
99
|
+
let directories = 0;
|
|
95
100
|
async function visit(directory, relativeDir, inheritedInclude) {
|
|
101
|
+
budget?.signal.throwIfAborted();
|
|
102
|
+
if (budget) {
|
|
103
|
+
const physical = await realpath(directory);
|
|
104
|
+
if (!isWithin(canonicalRoot, physical)) return false;
|
|
105
|
+
if (path.relative(canonicalRoot, physical).split(path.sep).join("/") !== relativeDir) return false;
|
|
106
|
+
}
|
|
107
|
+
if (budget && !await budget.allowPath(relativeDir)) return false;
|
|
108
|
+
if (budget && ++directories > budget.maxDirectories) throw new SelectionBudgetError("Directory scan budget exceeded");
|
|
96
109
|
let hasSelected = false;
|
|
97
|
-
for (const entry of await
|
|
110
|
+
for await (const entry of await opendir(directory)) {
|
|
111
|
+
budget?.signal.throwIfAborted();
|
|
112
|
+
if (budget && ++entries > budget.maxEntries) throw new SelectionBudgetError("Entry scan budget exceeded");
|
|
98
113
|
const absolutePath = path.join(directory, entry.name);
|
|
99
114
|
if (isWithin(outputDir, absolutePath) || ignored.some((value) => isWithin(value, absolutePath))) continue;
|
|
100
115
|
const relativePath = path.posix.join(relativeDir, entry.name);
|
|
116
|
+
if (budget && !await budget.allowPath(relativePath)) continue;
|
|
101
117
|
const directoryLike = entry.isDirectory();
|
|
102
118
|
const matches = (matcher) => matcher(relativePath) || directoryLike && matcher(`${relativePath}/`);
|
|
103
119
|
if (excluded.some(matches) || isIgnored(path.join(canonicalRoot, relativePath), directoryLike)) continue;
|
|
@@ -1078,6 +1094,23 @@ async function createDirectoryService(options) {
|
|
|
1078
1094
|
});
|
|
1079
1095
|
}
|
|
1080
1096
|
return {
|
|
1097
|
+
async scan(budget) {
|
|
1098
|
+
if (!budget || !Number.isSafeInteger(budget.maxEntries) || budget.maxEntries < 1 || !Number.isSafeInteger(budget.maxDirectories) || budget.maxDirectories < 1 || !(budget.signal instanceof AbortSignal) || typeof budget.allowPath !== "function") throw new TypeError("scan requires positive entry/directory limits, an AbortSignal and allowPath");
|
|
1099
|
+
const selection = (await selectSourcePaths(root, path.join(root, "__dirwell"), options.include, options.exclude, [], ignoreFiles, void 0, budget)).selected;
|
|
1100
|
+
const entries = [];
|
|
1101
|
+
for (const logical of [...selection].sort()) {
|
|
1102
|
+
budget.signal.throwIfAborted();
|
|
1103
|
+
if (!logical) continue;
|
|
1104
|
+
try {
|
|
1105
|
+
const entry = await describe(logical, selection);
|
|
1106
|
+
if (entry.kind === "file" || entry.kind === "directory") entries.push(entry);
|
|
1107
|
+
} catch (error) {
|
|
1108
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") continue;
|
|
1109
|
+
throw error;
|
|
1110
|
+
}
|
|
1111
|
+
}
|
|
1112
|
+
return entries;
|
|
1113
|
+
},
|
|
1081
1114
|
async resolvePath(logicalPath) {
|
|
1082
1115
|
const selection = await selected();
|
|
1083
1116
|
const entry = await describe(logicalPath, selection);
|
|
@@ -1155,6 +1188,6 @@ async function createDirectoryService(options) {
|
|
|
1155
1188
|
};
|
|
1156
1189
|
}
|
|
1157
1190
|
//#endregion
|
|
1158
|
-
export { DirectoryAccessError, compareEntries, copyJsonObject, createDirectoryService, defaultOutputName, escapeHtml, generateExplorer, generateExplorerSkippingPaths, listingRevision, projectListingEntry, readGeneratedPage, resolveIgnoreFiles, validateListingPlan };
|
|
1191
|
+
export { DirectoryAccessError, SelectionBudgetError, compareEntries, copyJsonObject, createDirectoryService, defaultOutputName, escapeHtml, generateExplorer, generateExplorerSkippingPaths, listingRevision, projectListingEntry, readGeneratedPage, resolveIgnoreFiles, validateListingPlan };
|
|
1159
1192
|
|
|
1160
1193
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/filters.ts","../src/validation.ts","../src/filesystem.ts","../src/listing.ts","../src/publication.ts","../src/generator.ts","../src/html.ts","../src/file-identity.ts","../src/service.ts"],"sourcesContent":["import { readdir, readlink, readFile, realpath } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport picomatch from \"picomatch\";\nimport ignore from \"ignore\";\nimport type { IgnoreFile } from \"./model.ts\";\n\n/** Resolve configuration paths once, before a host changes working directories. */\nexport function resolveIgnoreFiles(\n value: unknown = [],\n cwd = process.cwd(),\n): readonly Exclude<IgnoreFile, string>[] {\n if (!Array.isArray(value)) throw new TypeError(\"ignoreFiles must be an array\");\n return value.map((input) => {\n const file = typeof input === \"string\" ? { path: input } : input;\n if (typeof file !== \"object\" || file === null || Array.isArray(file))\n throw new TypeError(\"ignoreFiles entries must be paths or objects\");\n for (const key of Object.keys(file))\n if (![\"path\", \"baseDir\", \"optional\"].includes(key))\n throw new TypeError(`Unsupported ignoreFiles key \"${key}\"`);\n for (const key of [\"path\", \"baseDir\"] as const)\n if (\n (key === \"path\" || file[key] !== undefined) &&\n (typeof file[key] !== \"string\" || file[key].length === 0)\n )\n throw new TypeError(`ignoreFiles.${key} must be a non-empty string`);\n if (file.optional !== undefined && typeof file.optional !== \"boolean\")\n throw new TypeError(\"ignoreFiles.optional must be a boolean\");\n const filename = path.resolve(cwd, file.path);\n return {\n path: filename,\n baseDir: path.resolve(cwd, file.baseDir ?? path.dirname(filename)),\n optional: file.optional ?? false,\n };\n });\n}\n\nexport async function createIgnoreMatcher(files: readonly IgnoreFile[]) {\n const rules: { base: string; matcher: ReturnType<typeof ignore> }[] = [];\n const scopes = new Map<string, ReturnType<typeof ignore>>();\n let hasRules = false;\n for (const file of resolveIgnoreFiles(files)) {\n let contents: string;\n try {\n contents = await readFile(file.path, \"utf8\");\n } catch (error) {\n if (file.optional && error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n continue;\n throw error;\n }\n const base = await realpath(file.baseDir!);\n if (contents.split(/\\r?\\n/).some((line) => line.trim() !== \"\" && !line.startsWith(\"#\")))\n hasRules = true;\n let matcher = scopes.get(base);\n if (matcher === undefined) {\n matcher = ignore();\n scopes.set(base, matcher);\n rules.push({ base, matcher });\n }\n matcher.add(contents);\n }\n // Preserve Git's parent-directory negation behavior across files in one scope.\n // Explicit deeper scopes override applicable parent-scope rules.\n rules.sort((left, right) => left.base.split(path.sep).length - right.base.split(path.sep).length);\n const matches = (filename: string, directory: boolean): boolean => {\n let ignored = false;\n for (const rule of rules) {\n if (!isWithin(rule.base, filename)) continue;\n const relative = path.relative(rule.base, filename).split(path.sep).join(\"/\");\n if (relative === \"\") continue;\n const result = rule.matcher.test(relative + (directory ? \"/\" : \"\"));\n if (result.ignored) ignored = true;\n else if (result.unignored) ignored = false;\n }\n return ignored;\n };\n return Object.assign(matches, { hasRules });\n}\n\nexport function normalizePathPatterns(value: unknown, name: string): readonly string[] {\n if (value === undefined) return [];\n const patterns = typeof value === \"string\" ? [value] : value;\n if (\n !Array.isArray(patterns) ||\n patterns.some(\n (pattern) =>\n typeof pattern !== \"string\" ||\n pattern.length === 0 ||\n pattern.startsWith(\"/\") ||\n /^[A-Za-z]:/.test(pattern) ||\n pattern.startsWith(\"!\") ||\n pattern.includes(\"\\\\\") ||\n pattern.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n )\n ) {\n throw new TypeError(`${name} must contain root-relative glob patterns using forward slashes`);\n }\n return patterns as readonly string[];\n}\n\nfunction isWithin(parent: string, candidate: string): boolean {\n const relative = path.relative(parent, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport interface SourceSelection {\n readonly selected: ReadonlySet<string>;\n readonly symlinks: ReadonlySet<string>;\n readonly mirroredSymlinks: ReadonlySet<string>;\n}\n\n/** Select physical source paths; parent directories remain when a descendant matches. */\nexport async function selectSourcePaths(\n sourceDir: string,\n outputDir: string,\n include: unknown,\n exclude: unknown,\n ignoredPaths: readonly string[] = [],\n ignoreFiles: readonly IgnoreFile[] = [],\n preparedIgnore?: Awaited<ReturnType<typeof createIgnoreMatcher>>,\n): Promise<SourceSelection> {\n const isIgnored = preparedIgnore ?? (await createIgnoreMatcher(ignoreFiles));\n const canonicalRoot = await realpath(sourceDir);\n const ignored = ignoredPaths.map((value) => path.resolve(value));\n const included = normalizePathPatterns(include, \"include\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const excluded = normalizePathPatterns(exclude, \"exclude\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const selected = new Set<string>([\"\"]);\n const symlinks = new Map<string, string>();\n\n async function visit(\n directory: string,\n relativeDir: string,\n inheritedInclude: boolean,\n ): Promise<boolean> {\n let hasSelected = false;\n for (const entry of await readdir(directory, { withFileTypes: true })) {\n const absolutePath = path.join(directory, entry.name);\n if (\n isWithin(outputDir, absolutePath) ||\n ignored.some((value) => isWithin(value, absolutePath))\n )\n continue;\n const relativePath = path.posix.join(relativeDir, entry.name);\n const directoryLike = entry.isDirectory();\n const matches = (matcher: (value: string) => boolean) =>\n matcher(relativePath) || (directoryLike && matcher(`${relativePath}/`));\n if (\n excluded.some(matches) ||\n isIgnored(path.join(canonicalRoot, relativePath), directoryLike)\n )\n continue;\n const includedHere = inheritedInclude || included.some(matches);\n if (directoryLike) {\n const hasSelectedChild = await visit(absolutePath, relativePath, includedHere);\n if (included.length === 0 || includedHere || hasSelectedChild) {\n selected.add(relativePath);\n hasSelected = true;\n }\n } else if (included.length === 0 || includedHere) {\n selected.add(relativePath);\n hasSelected = true;\n if (entry.isSymbolicLink()) symlinks.set(relativePath, await readlink(absolutePath));\n }\n }\n return hasSelected;\n }\n\n if (!isIgnored(canonicalRoot, true)) await visit(sourceDir, \"\", false);\n // Absolute, escaping, and filtered targets cannot remain valid inside the copied tree.\n const mirroredSymlinks = new Set<string>();\n for (const [relativePath, target] of symlinks) {\n if (path.isAbsolute(target)) continue;\n const targetPath = path.resolve(sourceDir, path.dirname(relativePath), target);\n if (!isWithin(sourceDir, targetPath)) continue;\n const targetRelativePath = path.relative(sourceDir, targetPath).split(path.sep).join(\"/\");\n if (selected.has(targetRelativePath)) mirroredSymlinks.add(relativePath);\n }\n return { selected, symlinks: new Set(symlinks.keys()), mirroredSymlinks };\n}\n","import type { GenerateOptions, ExplorerTheme } from \"./model.ts\";\nimport type { DirectoryServiceOptions } from \"./service.ts\";\nimport type { ListingPlan } from \"./listing.ts\";\nimport { resolveIgnoreFiles } from \"./filters.ts\";\n\ntype Options = Record<string, unknown>;\nexport function optionObject(value: unknown, name: string): Options {\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n throw new TypeError(`${name} must be an object`);\n return value as Options;\n}\nfunction distance(left: string, right: string): number {\n let previous = Array.from({ length: right.length + 1 }, (_, index) => index);\n for (let i = 1; i <= left.length; i++) {\n const current = [i];\n for (let j = 1; j <= right.length; j++)\n current[j] = Math.min(\n current[j - 1]! + 1,\n previous[j]! + 1,\n previous[j - 1]! + (left[i - 1] === right[j - 1] ? 0 : 1),\n );\n previous = current;\n }\n return previous[right.length]!;\n}\nexport function optionKeys(value: Options, allowed: readonly string[], name: string): void {\n for (const key of Object.keys(value)) {\n if (allowed.includes(key)) continue;\n const suggestion = allowed\n .map((candidate) => ({ candidate, distance: distance(key, candidate) }))\n .sort((left, right) => left.distance - right.distance)\n .find((item) => item.distance <= 2)?.candidate;\n throw new TypeError(\n `Unsupported option \"${name}.${key}\".${suggestion ? ` Did you mean \"${name}.${suggestion}\"?` : ` Supported keys: ${allowed.join(\", \")}.`}`,\n );\n }\n}\nfunction scalar(value: unknown, type: \"boolean\" | \"string\" | \"function\", name: string): void {\n if (value !== undefined && typeof value !== type)\n throw new TypeError(`${name} must be a ${type}`);\n}\nfunction choice(value: unknown, allowed: readonly unknown[], name: string): void {\n if (value !== undefined && !allowed.includes(value))\n throw new TypeError(`${name} must be one of ${allowed.join(\", \")}`);\n}\nfunction positiveInteger(value: unknown, name: string): void {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1)\n throw new TypeError(`${name} must be a positive safe integer`);\n}\nexport function validateListingPlan(value: unknown): asserts value is ListingPlan {\n const plan = optionObject(value, \"listing\");\n optionKeys(plan, [\"html\", \"data\"], \"listing\");\n for (const [key, strategy, size] of [\n [\"html\", \"paged\", \"pageSize\"],\n [\"data\", \"blocks\", \"blockSize\"],\n ] as const) {\n const section = optionObject(plan[key], `listing.${key}`);\n optionKeys(\n section,\n section.strategy === strategy ? [\"strategy\", size] : [\"strategy\"],\n `listing.${key}`,\n );\n if (section.strategy !== \"all\" && section.strategy !== strategy)\n throw new TypeError(`listing.${key}.strategy must be all or ${strategy}`);\n if (section.strategy === strategy) positiveInteger(section[size], `listing.${key}.${size}`);\n }\n}\nfunction selection(value: Options, name: string): void {\n for (const key of [\"include\", \"exclude\"])\n if (\n value[key] !== undefined &&\n typeof value[key] !== \"string\" &&\n (!Array.isArray(value[key]) || value[key].some((item: unknown) => typeof item !== \"string\"))\n )\n throw new TypeError(`${name}.${key} must be a string or array of strings`);\n resolveIgnoreFiles(value.ignoreFiles);\n scalar(value.entryData, \"function\", `${name}.entryData`);\n if (value.sort !== undefined) {\n const sort = optionObject(value.sort, `${name}.sort`);\n optionKeys(sort, [\"field\", \"direction\", \"directoriesFirst\", \"nameMode\"], `${name}.sort`);\n scalar(sort.directoriesFirst, \"boolean\", `${name}.sort.directoriesFirst`);\n choice(sort.field, [\"name\", \"size\", \"modified\"], `${name}.sort.field`);\n choice(sort.direction, [\"asc\", \"desc\"], `${name}.sort.direction`);\n choice(sort.nameMode, [\"natural\", \"locale\", \"unicode\"], `${name}.sort.nameMode`);\n }\n}\nfunction requiredString(value: unknown, name: string): void {\n if (typeof value !== \"string\" || !value.length)\n throw new TypeError(`${name} must be a non-empty string`);\n}\nexport function validateTheme(\n value: unknown,\n name = \"options.theme\",\n): asserts value is ExplorerTheme {\n if (value === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const theme = optionObject(value, name);\n requiredString(theme.name, `${name}.name`);\n if (typeof theme.render !== \"function\") throw new TypeError(`${name}.render must be a function`);\n scalar(theme.entryData, \"function\", `${name}.entryData`);\n scalar(theme.searchIndex, \"boolean\", `${name}.searchIndex`);\n if (theme.listing !== undefined) {\n const listing = optionObject(theme.listing, `${name}.listing`);\n optionKeys(listing, [\"pagination\"], `${name}.listing`);\n if (typeof listing.pagination !== \"boolean\")\n throw new TypeError(`${name}.listing.pagination must be a boolean`);\n }\n}\nconst generateKeys = {\n sourceDir: true,\n outputDir: true,\n theme: true,\n include: true,\n exclude: true,\n ignoreFiles: true,\n sort: true,\n entryData: true,\n fileHref: true,\n dryRun: true,\n outputPolicy: true,\n listing: true,\n metadata: true,\n base: true,\n mode: true,\n mirror: true,\n outputName: true,\n urlStrategy: true,\n symlinks: true,\n} satisfies Record<keyof GenerateOptions, true>;\nexport function validateGenerateOptions(value: unknown): asserts value is GenerateOptions {\n const options = optionObject(value, \"options\");\n optionKeys(options, Object.keys(generateKeys), \"options\");\n requiredString(options.sourceDir, \"options.sourceDir\");\n requiredString(options.outputDir, \"options.outputDir\");\n validateTheme(options.theme);\n selection(options, \"options\");\n for (const key of [\"fileHref\", \"metadata\"]) scalar(options[key], \"function\", `options.${key}`);\n for (const key of [\"dryRun\", \"mirror\"]) scalar(options[key], \"boolean\", `options.${key}`);\n scalar(options.base, \"string\", \"options.base\");\n choice(options.mode, [\"ssg\", \"mpa\"], \"options.mode\");\n choice(\n options.urlStrategy,\n Object.keys({\n base: true,\n \"html-base\": true,\n relative: true,\n } satisfies Record<NonNullable<GenerateOptions[\"urlStrategy\"]>, true>),\n \"options.urlStrategy\",\n );\n choice(options.outputPolicy, [\"owned\", \"replace\"], \"options.outputPolicy\");\n if (\n options.outputName !== undefined &&\n typeof options.outputName !== \"string\" &&\n typeof options.outputName !== \"function\"\n )\n throw new TypeError(\"options.outputName must be a string or function\");\n if (options.listing !== undefined && typeof options.listing !== \"function\")\n validateListingPlan(options.listing);\n if (options.symlinks !== undefined) {\n const links = optionObject(options.symlinks, \"options.symlinks\");\n optionKeys(links, [\"follow\", \"boundary\", \"onCycle\"], \"options.symlinks\");\n scalar(links.follow, \"boolean\", \"options.symlinks.follow\");\n choice(links.boundary, [\"root\", \"anywhere\"], \"options.symlinks.boundary\");\n choice(links.onCycle, [\"error\", \"skip\"], \"options.symlinks.onCycle\");\n }\n}\nconst serviceKeys = {\n root: true,\n include: true,\n exclude: true,\n ignoreFiles: true,\n sort: true,\n entryData: true,\n} satisfies Record<keyof DirectoryServiceOptions, true>;\nexport function validateDirectoryOptions(value: unknown): asserts value is DirectoryServiceOptions {\n const options = optionObject(value, \"options\");\n optionKeys(options, Object.keys(serviceKeys), \"options\");\n requiredString(options.root, \"options.root\");\n selection(options, \"options\");\n}\n","import { lstat, readlink, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Stats } from \"node:fs\";\nimport type { EntryKind, FileMetadata, FileSystemEntry, SymlinkMetadata } from \"./model.ts\";\nfunction entryKind(stats: Stats): EntryKind {\n if (stats.isDirectory()) return \"directory\";\n if (stats.isFile()) return \"file\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"other\";\n}\n\nfunction metadata(stats: Stats): FileMetadata {\n return {\n device: stats.dev,\n groupId: stats.gid,\n hardLinkCount: stats.nlink,\n inode: stats.ino,\n mode: stats.mode,\n ownerId: stats.uid,\n size: stats.size,\n times: {\n accessedAt: stats.atime.toISOString(),\n changedAt: stats.ctime.toISOString(),\n createdAt: stats.birthtime.toISOString(),\n modifiedAt: stats.mtime.toISOString(),\n },\n };\n}\n\nexport function isInsideRoot(rootPath: string, candidatePath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport async function describeEntry({\n absolutePath,\n relativePath,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths,\n}: {\n absolutePath: string;\n relativePath: string;\n rootRealPath: string;\n ancestors: ReadonlySet<string>;\n followSymlinks: boolean;\n selectedPaths: ReadonlySet<string> | null;\n}): Promise<FileSystemEntry> {\n const linkStats = await lstat(absolutePath);\n const kind = entryKind(linkStats);\n let symlink: SymlinkMetadata | null = null;\n\n if (kind === \"symlink\") {\n const target = await readlink(absolutePath);\n let resolvedPath: string | null = null;\n let targetKind: Exclude<EntryKind, \"symlink\"> | null = null;\n let targetSize: number | null = null;\n try {\n resolvedPath = await realpath(absolutePath);\n const targetStats = await stat(absolutePath);\n targetKind = entryKind(targetStats) as Exclude<EntryKind, \"symlink\">;\n targetSize = targetStats.size;\n } catch {\n // Broken and inaccessible links are represented as data.\n }\n const isOutsideRoot = resolvedPath === null || !isInsideRoot(rootRealPath, resolvedPath);\n const isCycle = resolvedPath !== null && ancestors.has(resolvedPath);\n const targetRelativePath =\n resolvedPath !== null && !isOutsideRoot\n ? path.relative(rootRealPath, resolvedPath).split(path.sep).join(\"/\")\n : null;\n const isTargetExcluded =\n targetRelativePath !== null &&\n selectedPaths !== null &&\n !selectedPaths.has(targetRelativePath);\n symlink = {\n target,\n resolvedPath,\n targetRelativePath,\n targetKind,\n targetSize:\n isOutsideRoot || isTargetExcluded || targetKind === \"directory\" ? null : targetSize,\n isBroken: resolvedPath === null,\n isCycle,\n isOutsideRoot,\n isTargetExcluded,\n wasFollowed:\n followSymlinks &&\n targetKind === \"directory\" &&\n !isCycle &&\n !isOutsideRoot &&\n !isTargetExcluded,\n };\n }\n\n return {\n name: path.basename(absolutePath),\n absolutePath,\n relativePath,\n kind,\n metadata: metadata(linkStats),\n symlink,\n };\n}\n","import type { JsonObject } from \"./json.ts\";\nimport { createHash } from \"node:crypto\";\nimport type { EntryKind, FileSystemEntry, ThemeContext, SortOptions } from \"./model.ts\";\nimport { copyJsonObject } from \"./json.ts\";\n\n/** Public transport fields only. Internal filesystem metadata must never be spread here. */\nexport interface ListingEntry {\n readonly data?: JsonObject;\n readonly presentation?: JsonObject;\n readonly id: string;\n readonly name: string;\n readonly kind: EntryKind;\n readonly href: string | null;\n readonly exitsExplorer: boolean;\n readonly size: number;\n readonly modifiedAt: string;\n readonly link: null | {\n readonly target: string;\n readonly targetKind: Exclude<EntryKind, \"symlink\"> | null;\n readonly targetSize: number | null;\n readonly unavailable: boolean;\n readonly cycle: boolean;\n };\n}\nexport interface ListingPlan {\n readonly html:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"paged\"; readonly pageSize: number };\n readonly data:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"blocks\"; readonly blockSize: number };\n}\nexport interface ListingPolicyContext {\n readonly operation?: \"build\" | \"server\";\n readonly directoryPath: string;\n readonly visibleCount: number;\n readonly dataBytes: number;\n readonly mode: \"ssg\" | \"mpa\";\n readonly supportsPagination: boolean;\n}\nexport type ListingPolicy = ListingPlan | ((context: ListingPolicyContext) => ListingPlan);\nexport interface ListingPage {\n readonly number: number;\n readonly count: number;\n readonly offset: number;\n readonly total: number;\n readonly href: string;\n readonly previousHref: string | null;\n readonly nextHref: string | null;\n}\nexport interface ListingContext {\n readonly revision: string;\n readonly manifestHref: string;\n readonly page: ListingPage;\n}\nexport interface ListingBlock {\n readonly version: 1;\n readonly revision: string;\n readonly offset: number;\n readonly total: number;\n readonly entries: readonly ListingEntry[];\n}\nexport interface ListingManifest {\n readonly version: 1;\n readonly revision: string;\n readonly directory: string;\n /** Resolve entry hrefs against this URL, resolved relative to the manifest URL. */\n readonly hrefBase: string;\n readonly total: number;\n readonly sort: Required<SortOptions>;\n /** Block hrefs are relative to the manifest URL. */\n readonly blocks: readonly {\n readonly href: string;\n readonly offset: number;\n readonly count: number;\n }[];\n}\n\nexport function projectListingEntry(\n entry: FileSystemEntry,\n context: Pick<ThemeContext, \"hrefFor\" | \"exitsExplorerFor\">,\n): ListingEntry {\n const link = entry.symlink;\n return {\n ...(entry.publicData === undefined ? {} : { data: copyJsonObject(entry.publicData) }),\n id: entry.relativePath,\n name: entry.name,\n kind: entry.kind,\n href: context.hrefFor(entry),\n exitsExplorer: context.exitsExplorerFor(entry),\n size: entry.metadata.size,\n modifiedAt: entry.metadata.times.modifiedAt,\n link:\n link === null\n ? null\n : {\n target: link.target,\n targetKind: link.targetKind,\n targetSize: link.targetSize ?? null,\n unavailable: link.isBroken || link.isOutsideRoot || Boolean(link.isTargetExcluded),\n cycle: link.isCycle,\n },\n };\n}\n\n/** Annotation providers receive public facts, not transport URLs or raw stat objects. */\nexport function entryDataFacts(\n entry: FileSystemEntry,\n): Omit<ListingEntry, \"href\" | \"exitsExplorer\" | \"presentation\" | \"data\"> {\n const {\n href: _href,\n exitsExplorer: _exits,\n data: _data,\n ...facts\n } = projectListingEntry(entry, { hrefFor: () => null, exitsExplorerFor: () => false });\n return facts;\n}\nexport { validateListingPlan } from \"./validation.ts\";\nexport function listingRevision(\n entries: readonly ListingEntry[],\n sort: Required<SortOptions>,\n hrefBase: string,\n blockSize: number,\n): string {\n return createHash(\"sha256\")\n .update(JSON.stringify({ version: 1, entries, sort, hrefBase, blockSize }))\n .digest(\"hex\");\n}\n","import { lstat, readdir, readFile, realpath, rename, rm, mkdir, open } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { isInsideRoot } from \"./filesystem.ts\";\n\nexport const outputMarker = \"__dirwell/ownership.json\";\nexport const outputMarkerContents = '{\"type\":\"dirwell-output\",\"version\":1}\\n';\n\nexport async function lockOutput(output: string) {\n const canonical = await canonicalPath(output);\n const lockPath = path.join(path.dirname(canonical), `.${path.basename(canonical)}-dirwell.lock`);\n await mkdir(path.dirname(lockPath), { recursive: true });\n let handle;\n try {\n handle = await open(lockPath, \"wx\");\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"EEXIST\")\n throw new Error(\n `Output is locked by another build: ${lockPath}. Wait for it to finish. Remove a stale lock only after confirming its owner has stopped; --force does not bypass locks.`,\n );\n throw error;\n }\n try {\n await handle.writeFile(JSON.stringify({ pid: process.pid }));\n } catch (error) {\n await handle.close();\n await rm(lockPath);\n throw error;\n }\n return {\n lockPath,\n async release() {\n await handle.close();\n await rm(lockPath);\n },\n };\n}\n\nexport async function canonicalPath(filename: string): Promise<string> {\n try {\n return await realpath(filename);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n const parent = path.dirname(filename);\n if (parent === filename) throw error;\n return path.join(await canonicalPath(parent), path.basename(filename));\n }\n}\n\n/** Force permits output ownership replacement, never source containment violations. */\nexport async function checkOutput(\n source: string,\n output: string,\n policy: \"owned\" | \"replace\" = \"owned\",\n): Promise<boolean> {\n if (policy !== \"owned\" && policy !== \"replace\")\n throw new TypeError(\"outputPolicy must be owned or replace\");\n if (isInsideRoot(await canonicalPath(output), await realpath(source)))\n throw new Error(\"outputDir must not contain the sourceDir\");\n let stat;\n try {\n stat = await lstat(output);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return false;\n throw error;\n }\n if (stat.isSymbolicLink() || !stat.isDirectory())\n throw new Error(\"outputDir must be a directory, not a file or symlink\");\n if ((await readdir(output)).length === 0 || policy === \"replace\") return true;\n try {\n const marker = path.join(output, outputMarker);\n if (\n !(await lstat(path.dirname(marker))).isSymbolicLink() &&\n !(await lstat(marker)).isSymbolicLink() &&\n (await readFile(marker, \"utf8\")) === outputMarkerContents\n )\n return true;\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n throw new Error(\n \"Output is nonempty and not owned by Dirwell. Choose another directory or explicitly replace it with --force (-f) / outputPolicy: 'replace'.\",\n );\n}\n\n/** Keep a recoverable previous tree until the new tree is installed. */\nexport async function publishOutput(\n staged: string,\n output: string,\n source: string,\n policy: \"owned\" | \"replace\" = \"owned\",\n): Promise<void> {\n const exists = await checkOutput(source, output, policy);\n await mkdir(path.dirname(output), { recursive: true });\n const backup = path.join(\n path.dirname(output),\n `.${path.basename(output)}-previous-${randomUUID()}`,\n );\n if (exists) await rename(output, backup);\n try {\n await rename(staged, output);\n } catch (error) {\n if (exists) {\n try {\n await rename(backup, output);\n } catch (restoreError) {\n throw new AggregateError(\n [error, restoreError],\n `Publication failed; previous output is retained at ${backup}`,\n );\n }\n }\n throw error;\n }\n if (exists) await rm(backup, { recursive: true, force: true });\n}\n","import { validateGenerateOptions } from \"./validation.ts\";\nimport { copyJsonObject } from \"./json.ts\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n listingRevision,\n projectListingEntry,\n entryDataFacts,\n validateListingPlan,\n type ListingManifest,\n} from \"./listing.ts\";\nimport {\n cp,\n lstat,\n mkdtemp,\n mkdir,\n readFile,\n readdir,\n realpath,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n DirectoryData,\n EntryKind,\n ExplorerTheme,\n FileSystemEntry,\n GenerateOptions,\n NameSortMode,\n OutputNameResolver,\n SortOptions,\n ThemeContext,\n} from \"./model.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\nimport {\n checkOutput,\n publishOutput,\n outputMarker,\n outputMarkerContents,\n lockOutput,\n canonicalPath,\n} from \"./publication.ts\";\nimport type { BuildReport } from \"./model.ts\";\n\nconst indexPattern = /^index\\.html?$/i;\n\nconst defaultSort = {\n direction: \"asc\",\n directoriesFirst: true,\n field: \"name\",\n nameMode: \"natural\",\n} as const satisfies Required<SortOptions>;\n\nexport const defaultOutputName: OutputNameResolver = ({ entries }) =>\n entries.some((entry) => entry.kind === \"file\" && indexPattern.test(entry.name))\n ? entries.some((entry) => entry.name.toLowerCase() === \"_dirwell.html\")\n ? null\n : \"_dirwell.html\"\n : \"index.html\";\n\nfunction assertSafeOutputName(name: string): void {\n if (name.length === 0 || path.basename(name) !== name || name === \".\" || name === \"..\") {\n throw new Error(`Output name must be a single safe filename: ${name}`);\n }\n}\n\nfunction normalizeBase(value: string): string {\n if (value.includes(\"?\") || value.includes(\"#\")) {\n throw new TypeError(\"base must not contain a query string or fragment\");\n }\n if (/^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/`;\n return url.href;\n }\n if (!value.startsWith(\"/\")) {\n throw new TypeError('base must start with \"/\" or be an absolute HTTP(S) URL');\n }\n return `${value.replace(/\\/+$/, \"\")}/`;\n}\n\nfunction encodeLogicalPath(value: string): string {\n return value\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n\nfunction isDirectoryLike(entry: FileSystemEntry): boolean {\n return entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n}\n\nfunction isUnavailableSymlink(entry: FileSystemEntry): boolean {\n return Boolean(\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded,\n );\n}\n\nfunction compareUnicode(left: string, right: string): number {\n const leftPoints = [...left];\n const rightPoints = [...right];\n const length = Math.min(leftPoints.length, rightPoints.length);\n for (let index = 0; index < length; index += 1) {\n const difference =\n (leftPoints[index]?.codePointAt(0) ?? 0) - (rightPoints[index]?.codePointAt(0) ?? 0);\n if (difference !== 0) return difference;\n }\n return leftPoints.length - rightPoints.length;\n}\n\nfunction compareNames(left: string, right: string, mode: NameSortMode): number {\n if (mode === \"unicode\") return compareUnicode(left, right);\n return left.localeCompare(right, undefined, {\n numeric: mode === \"natural\",\n sensitivity: \"base\",\n });\n}\n\nexport function compareEntries(\n left: FileSystemEntry,\n right: FileSystemEntry,\n options: SortOptions = {},\n): number {\n const resolved = { ...defaultSort, ...options };\n if (resolved.directoriesFirst && isDirectoryLike(left) !== isDirectoryLike(right)) {\n return isDirectoryLike(left) ? -1 : 1;\n }\n let result: number;\n if (resolved.field === \"modified\") {\n result = left.metadata.times.modifiedAt.localeCompare(right.metadata.times.modifiedAt);\n } else if (resolved.field === \"size\") {\n result =\n (left.kind === \"directory\" ? 0 : left.metadata.size) -\n (right.kind === \"directory\" ? 0 : right.metadata.size);\n } else {\n result = compareNames(left.name, right.name, resolved.nameMode);\n }\n if (result === 0) result = compareNames(left.name, right.name, resolved.nameMode);\n return resolved.direction === \"asc\" ? result : -result;\n}\n\nfunction rawLinkFilename(entry: FileSystemEntry): string {\n return `${createHash(\"sha256\")\n .update(entry.relativePath)\n .update(\"\\0\")\n .update(entry.symlink?.target ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)}.txt`;\n}\n\nexport async function generateExplorer(options: GenerateOptions): Promise<BuildReport> {\n return generateExplorerSkippingPaths(options, []);\n}\n\n/** Internal entry point for hosts that stage previews outside their published output. */\nexport async function generateExplorerSkippingPaths(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<BuildReport> {\n validateGenerateOptions(options);\n const source = path.resolve(options.sourceDir),\n output = path.resolve(options.outputDir);\n await checkOutput(source, output, options.outputPolicy);\n if (options.dryRun) return generateExplorerUnlocked(options, ignoredPaths);\n const lock = await lockOutput(output);\n const lexicalLock = path.join(path.dirname(output), path.basename(lock.lockPath));\n try {\n return await generateExplorerUnlocked(options, [...ignoredPaths, lock.lockPath, lexicalLock]);\n } finally {\n await lock.release();\n }\n}\n\nasync function generateExplorerUnlocked(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<BuildReport> {\n const sourceDir = await realpath(path.resolve(options.sourceDir));\n const outputDir = await canonicalPath(path.resolve(options.outputDir));\n const ignoredSourcePaths = ignoredPaths.map((value) => path.resolve(value));\n const rootRealPath = await realpath(sourceDir);\n const replacesOutput = await checkOutput(sourceDir, outputDir, options.outputPolicy);\n const outputName = options.outputName ?? defaultOutputName;\n const resolveOutputName: OutputNameResolver =\n typeof outputName === \"string\" ? () => outputName : outputName;\n const theme: ExplorerTheme = options.theme;\n if (theme === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const mode = options.mode ?? \"ssg\";\n const urlStrategy = options.urlStrategy ?? \"relative\";\n const base = normalizeBase(options.base ?? \"/\");\n const followSymlinks = options.symlinks?.follow ?? false;\n const boundary = options.symlinks?.boundary ?? \"root\";\n const onCycle = options.symlinks?.onCycle ?? \"skip\";\n const filtersActive =\n options.include !== undefined ||\n options.exclude !== undefined ||\n (options.ignoreFiles?.length ?? 0) > 0 ||\n ignoredSourcePaths.length > 0;\n const plans: Array<{\n readonly directory: DirectoryData;\n readonly logicalDir: string;\n readonly outputName: string | null;\n }> = [];\n if (isInsideRoot(outputDir, sourceDir)) {\n throw new Error(\"outputDir must not contain the sourceDir\");\n }\n try {\n await lstat(path.join(sourceDir, \"__dirwell\"));\n throw new Error('Dirwell reserves the source-root path \"__dirwell\"');\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n // The reserved asset path is available.\n } else {\n throw error;\n }\n }\n const outputIsWithinSource = isInsideRoot(sourceDir, outputDir);\n const selection = await selectSourcePaths(\n sourceDir,\n outputDir,\n options.include,\n options.exclude,\n ignoredSourcePaths,\n options.ignoreFiles,\n );\n const stageParent = outputIsWithinSource ? path.dirname(sourceDir) : path.dirname(outputDir);\n if (!options.dryRun) await mkdir(stageParent, { recursive: true });\n const stagedOutputDir = options.dryRun\n ? null\n : await mkdtemp(path.join(stageParent, `.${path.basename(outputDir)}-dirwell-`));\n const buildOutputDir = stagedOutputDir!;\n\n try {\n if (!options.dryRun && (options.mirror ?? true)) {\n await rm(buildOutputDir, { recursive: true, force: true });\n await mkdir(buildOutputDir, { recursive: true });\n await cp(sourceDir, buildOutputDir, {\n recursive: true,\n dereference: false,\n preserveTimestamps: true,\n filter: (sourcePath) => {\n const relativePath = path.relative(sourceDir, sourcePath).split(path.sep).join(\"/\");\n return (\n selection.selected.has(relativePath) &&\n (!selection.symlinks.has(relativePath) || selection.mirroredSymlinks.has(relativePath))\n );\n },\n });\n }\n } catch (error) {\n if (stagedOutputDir !== null) await rm(stagedOutputDir, { recursive: true, force: true });\n throw error;\n }\n\n async function visit(\n logicalDir: string,\n physicalDir: string,\n ancestors: ReadonlySet<string>,\n ): Promise<void> {\n const physicalRealPath = await realpath(physicalDir);\n if (ancestors.has(physicalRealPath)) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${logicalDir}`);\n return;\n }\n\n const nextAncestors = new Set(ancestors).add(physicalRealPath);\n const names = (await readdir(physicalDir)).filter((name) => {\n if (outputIsWithinSource && isInsideRoot(outputDir, path.join(physicalDir, name)))\n return false;\n if (ignoredSourcePaths.some((value) => isInsideRoot(value, path.join(physicalDir, name))))\n return false;\n if (!filtersActive) return true;\n const relativePath = path.relative(rootRealPath, path.join(physicalRealPath, name));\n return selection.selected.has(relativePath.split(path.sep).join(\"/\"));\n });\n const entries = await Promise.all(\n names.map(async (name) => {\n const entry = await describeEntry({\n absolutePath: path.join(physicalDir, name),\n relativePath: path.posix.join(logicalDir, name),\n rootRealPath,\n ancestors: nextAncestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n return options.entryData === undefined\n ? entry\n : {\n ...entry,\n publicData: copyJsonObject(\n await options.entryData(entryDataFacts(entry), {\n operation: \"build\",\n directoryPath: logicalDir,\n }),\n ),\n };\n }),\n );\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (options.listing === undefined ? 0 : compareUnicode(left.relativePath, right.relativePath)),\n );\n\n const describedCurrent = await describeEntry({\n absolutePath: physicalDir,\n relativePath: logicalDir,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n if (describedCurrent.kind !== \"directory\") {\n throw new Error(`${physicalDir} is not a directory`);\n }\n const current: DirectoryData[\"current\"] = {\n ...describedCurrent,\n kind: \"directory\",\n };\n\n const root = await describeEntry({\n absolutePath: sourceDir,\n relativePath: \"\",\n rootRealPath,\n ancestors: new Set(),\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const parent =\n logicalDir === \"\"\n ? null\n : await describeEntry({\n absolutePath: path.dirname(physicalDir),\n relativePath:\n path.posix.dirname(logicalDir) === \".\" ? \"\" : path.posix.dirname(logicalDir),\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const directory: DirectoryData = {\n root,\n current,\n parent,\n depth: logicalDir === \"\" ? 0 : logicalDir.split(\"/\").length,\n entries,\n };\n\n const name = await resolveOutputName(directory);\n if (name !== null) assertSafeOutputName(name);\n plans.push({ directory, logicalDir, outputName: name });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n await visit(path.posix.join(logicalDir, entry.name), entry.absolutePath, nextAncestors);\n continue;\n }\n if (!followSymlinks || entry.symlink?.targetKind !== \"directory\") continue;\n const physicalLinkPath = path\n .relative(rootRealPath, path.join(physicalRealPath, entry.name))\n .split(path.sep)\n .join(\"/\");\n if ((options.mirror ?? true) && !selection.mirroredSymlinks.has(physicalLinkPath)) continue;\n if (entry.symlink.isCycle) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${entry.relativePath}`);\n continue;\n }\n if (entry.symlink.resolvedPath === null) continue;\n if (boundary === \"root\" && entry.symlink.isOutsideRoot) continue;\n if (\n filtersActive &&\n (entry.symlink.targetRelativePath === null ||\n !selection.selected.has(entry.symlink.targetRelativePath))\n )\n continue;\n // Mirrored internal aliases already resolve to the target's generated page.\n // Writing an alias page through the copied symlink would overwrite that page.\n if (\n (options.mirror ?? true) &&\n entry.symlink.targetRelativePath !== null &&\n !entry.symlink.isOutsideRoot\n )\n continue;\n await visit(\n path.posix.join(logicalDir, entry.name),\n entry.symlink.resolvedPath,\n nextAncestors,\n );\n }\n }\n\n try {\n await visit(\"\", sourceDir, new Set());\n\n const report: BuildReport = {\n sourceDir,\n outputDir,\n theme: theme.name,\n dryRun: options.dryRun ?? false,\n mirror: options.mirror ?? true,\n replacesOutput,\n selectedPaths: [...selection.selected].filter(Boolean).sort(),\n pages: plans.map((plan) => ({ directory: plan.logicalDir, outputName: plan.outputName })),\n };\n if (options.dryRun) return report;\n\n const generatedPages = new Map(\n plans\n .filter(\n (plan): plan is typeof plan & { readonly outputName: string } => plan.outputName !== null,\n )\n .map((plan) => [plan.logicalDir, plan.outputName]),\n );\n const generatedDirectories = new Set(generatedPages.keys());\n const pagePathForDirectory = (logicalPath: string): string => {\n const pageName = generatedPages.get(logicalPath);\n return pageName === undefined || pageName === \"index.html\"\n ? logicalPath\n : path.posix.join(logicalPath, pageName);\n };\n const sourceKinds = new Map<string, string>();\n for (const { directory } of plans)\n for (const entry of directory.entries) {\n const sourcePath = path.relative(sourceDir, entry.absolutePath).split(path.sep).join(\"/\");\n if (selection.selected.has(sourcePath)) sourceKinds.set(sourcePath, entry.kind);\n }\n const metadataResolver = await options.metadata?.({ sourceDir, sourceKinds });\n const sharedAssets = new Map<string, string | Uint8Array>();\n const rawLinkFiles = new Map<string, string>();\n const searchEntries = new Map<\n string,\n {\n href: string | null;\n exitsExplorer: boolean;\n isLink: boolean;\n kind: EntryKind;\n modifiedAt: string;\n name: string;\n path: string;\n size: number;\n target: string | null;\n targetKind: Exclude<EntryKind, \"symlink\"> | null;\n targetSize: number | null;\n isTargetUnavailable: boolean;\n isCycle: boolean;\n }\n >();\n\n const fileHrefs = new Map<string, string | null>();\n const mappedFileHref = (logicalPath: string): string | null => {\n if (!fileHrefs.has(logicalPath)) {\n const href = options.fileHref!(logicalPath);\n if (\n href !== null &&\n (typeof href !== \"string\" ||\n href.length === 0 ||\n href.includes(\"\\\\\") ||\n Array.from(href).some((character) => character.charCodeAt(0) < 32) ||\n ![\"http:\", \"https:\"].includes(new URL(href, \"https://dirwell.invalid/\").protocol))\n )\n throw new TypeError(\n \"fileHref must return a synchronous HTTP(S), root-relative or relative URL, or null\",\n );\n fileHrefs.set(logicalPath, href);\n }\n return fileHrefs.get(logicalPath)!;\n };\n\n for (const { directory, logicalDir } of theme.searchIndex === false ? [] : plans) {\n for (const entry of directory.entries) {\n if (searchEntries.has(entry.relativePath)) continue;\n const targetLogicalPath = isUnavailableSymlink(entry)\n ? null\n : entry.symlink?.targetRelativePath !== null && entry.symlink !== null\n ? entry.symlink.targetRelativePath\n : path.posix.join(logicalDir, entry.name);\n const directoryLike = isDirectoryLike(entry);\n const linkedPath =\n directoryLike && targetLogicalPath !== null\n ? pagePathForDirectory(targetLogicalPath)\n : targetLogicalPath;\n let href: string | null = null;\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n href = `raw-links/${filename}`;\n } else if (linkedPath !== null) {\n href =\n linkedPath === \"\"\n ? \"../\"\n : `../${encodeLogicalPath(linkedPath)}${directoryLike && linkedPath === targetLogicalPath ? \"/\" : \"\"}`;\n if (!directoryLike && options.fileHref !== undefined) href = mappedFileHref(linkedPath);\n }\n searchEntries.set(entry.relativePath, {\n exitsExplorer:\n isUnavailableSymlink(entry) ||\n (targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))),\n href,\n isLink: entry.kind === \"symlink\",\n kind: entry.kind,\n modifiedAt: entry.metadata.times.modifiedAt,\n name: entry.name,\n path: entry.relativePath,\n size: entry.metadata.size,\n target: entry.symlink?.target ?? null,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n isTargetUnavailable: isUnavailableSymlink(entry),\n isCycle: entry.symlink?.isCycle ?? false,\n });\n }\n }\n\n for (const plan of plans) {\n const { directory, logicalDir, outputName: name } = plan;\n const sourceEntryNames = new Set(directory.entries.map((entry) => entry.name.toLowerCase()));\n if (name === null) continue;\n\n const targetLogicalPathFor = (entry: FileSystemEntry): string | null => {\n if (isUnavailableSymlink(entry)) return null;\n if (entry.symlink?.targetRelativePath !== null && entry.symlink !== null) {\n return entry.symlink.targetRelativePath;\n }\n return path.posix.join(logicalDir, entry.name);\n };\n const hrefForLogicalPath = (targetPath: string, directoryLike: boolean): string => {\n const linkedPath = directoryLike ? pagePathForDirectory(targetPath) : targetPath;\n const linkToDirectory = directoryLike && linkedPath === targetPath;\n if (urlStrategy === \"relative\") {\n const relativeTarget = path.posix.relative(\n logicalDir === \"\" ? \".\" : logicalDir,\n linkedPath === \"\" ? \".\" : linkedPath,\n );\n const encodedTarget = relativeTarget\n .split(\"/\")\n .map((segment) =>\n segment === \".\" || segment === \"..\" ? segment : encodeURIComponent(segment),\n )\n .join(\"/\");\n return `${encodedTarget || \".\"}${linkToDirectory ? \"/\" : \"\"}`;\n }\n const encodedTarget = encodeLogicalPath(linkedPath);\n if (encodedTarget === \"\") {\n return urlStrategy === \"base\" ? base : \"./\";\n }\n const suffix = `${encodedTarget}${linkToDirectory ? \"/\" : \"\"}`;\n return urlStrategy === \"base\" ? `${base}${suffix}` : suffix;\n };\n const hrefFor = (entry: FileSystemEntry): string | null => {\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n return hrefForLogicalPath(path.posix.join(\"__dirwell\", \"raw-links\", filename), false);\n }\n const targetLogicalPath = targetLogicalPathFor(entry);\n if (targetLogicalPath === null) return null;\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n if (!directoryLike && options.fileHref !== undefined)\n return mappedFileHref(targetLogicalPath);\n return hrefForLogicalPath(targetLogicalPath, directoryLike);\n };\n const baseContext: ThemeContext = {\n operation: \"build\",\n directory,\n documentBaseHref: urlStrategy === \"html-base\" ? base : null,\n outputName: name,\n mode,\n searchIndexHref: hrefForLogicalPath(\n path.posix.join(\"__dirwell\", \"search-index.json\"),\n false,\n ),\n sort: { ...defaultSort, ...options.sort },\n assetHref: (assetName) => {\n assertSafeOutputName(assetName);\n return hrefForLogicalPath(\n mode === \"ssg\"\n ? path.posix.join(logicalDir, assetName)\n : path.posix.join(\"__dirwell\", assetName),\n false,\n );\n },\n hrefFor,\n hrefForDirectory: (relativePath) => hrefForLogicalPath(relativePath, true),\n hasPageForDirectory: (relativePath) => generatedDirectories.has(relativePath),\n exitsExplorerFor: (entry) => {\n if (isUnavailableSymlink(entry)) return true;\n const targetLogicalPath = targetLogicalPathFor(entry);\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return (\n targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))\n );\n },\n };\n const targetDir = path.join(buildOutputDir, logicalDir);\n await mkdir(targetDir, { recursive: true });\n const sort = baseContext.sort;\n let revision = \"\";\n let manifestHref = \"\";\n let pageSize = Math.max(1, directory.entries.length);\n if (options.listing !== undefined) {\n const records = directory.entries.map((entry) => {\n const projected = projectListingEntry(entry, baseContext);\n return theme.entryData === undefined\n ? projected\n : {\n ...projected,\n presentation: copyJsonObject(\n theme.entryData(projected, {\n mode: baseContext.mode,\n outputName: baseContext.outputName,\n assetHref: baseContext.assetHref,\n hrefForDirectory: baseContext.hrefForDirectory,\n documentBaseHref: baseContext.documentBaseHref,\n directoryPath: logicalDir,\n }),\n ),\n };\n });\n const candidate =\n typeof options.listing === \"function\"\n ? options.listing({\n directoryPath: logicalDir,\n visibleCount: records.length,\n dataBytes: Buffer.byteLength(JSON.stringify(records)),\n mode,\n operation: \"build\",\n supportsPagination: theme.listing?.pagination === true,\n })\n : options.listing;\n validateListingPlan(candidate);\n if (candidate.html.strategy === \"paged\") {\n if (theme.listing?.pagination !== true)\n throw new Error(`Theme ${theme.name} does not support listing pagination`);\n pageSize = candidate.html.pageSize;\n }\n const directoryId = createHash(\"sha256\").update(logicalDir).digest(\"hex\");\n const manifestDirectory = path.posix.join(\"__dirwell\", \"listing\", directoryId);\n // Relative records belong to the document directory, not to the JSON asset directory.\n const hrefBase =\n urlStrategy === \"relative\"\n ? `../../../${encodeLogicalPath(logicalDir)}${logicalDir ? \"/\" : \"\"}`\n : base;\n const manifestPath = path.posix.join(manifestDirectory, \"manifest.json\");\n manifestHref = hrefForLogicalPath(manifestPath, false);\n const blocks: Array<ListingManifest[\"blocks\"][number]> = [];\n const blockSize =\n candidate.data.strategy === \"blocks\"\n ? candidate.data.blockSize\n : Math.max(1, records.length);\n revision = listingRevision(records, sort, hrefBase, blockSize);\n const outputListingDir = path.join(buildOutputDir, manifestDirectory);\n await mkdir(outputListingDir, { recursive: true });\n for (let offset = 0; offset < records.length || offset === 0; offset += blockSize) {\n const entries = records.slice(offset, offset + blockSize);\n const filename = `${revision}-${blocks.length}.json`;\n blocks.push({ href: filename, offset, count: entries.length });\n await writeFile(\n path.join(outputListingDir, filename),\n JSON.stringify({ version: 1, revision, offset, total: records.length, entries }),\n );\n }\n const manifest: ListingManifest = {\n version: 1,\n revision,\n directory: logicalDir,\n hrefBase,\n total: records.length,\n sort,\n blocks,\n };\n await writeFile(path.join(outputListingDir, \"manifest.json\"), JSON.stringify(manifest));\n }\n const pageCount = Math.max(1, Math.ceil(directory.entries.length / pageSize));\n const pagePrefix = `__dirwell-page-${createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 16)}`;\n const pageNames = Array.from({ length: pageCount }, (_, index) =>\n index === 0 ? name : `${pagePrefix}-${index + 1}.html`,\n );\n for (const pageName of pageNames.slice(1)) {\n if (directory.entries.some((entry) => entry.name.toLowerCase() === pageName.toLowerCase()))\n throw new Error(\n `Listing page conflicts with source entry: ${path.posix.join(logicalDir, pageName)}`,\n );\n }\n const pagedAssets = new Map<string, Buffer>();\n for (const [index, pageName] of pageNames.entries()) {\n const pagePath = path.posix.join(logicalDir, pageName);\n const metadata = await metadataResolver?.resolve(\n directory,\n (outputPath) => hrefForLogicalPath(outputPath, false),\n pageName === \"index.html\" ? (logicalDir ? `${logicalDir}/` : \"\") : pagePath,\n );\n const pageHref = (number: number): string =>\n hrefForLogicalPath(path.posix.join(logicalDir, pageNames[number] ?? name), false);\n const page = await theme.render({\n ...baseContext,\n ...(metadata === undefined ? {} : { metadata }),\n outputName: pageName,\n directory:\n options.listing === undefined\n ? directory\n : {\n ...directory,\n entries: directory.entries.slice(index * pageSize, (index + 1) * pageSize),\n },\n ...(options.listing === undefined\n ? {}\n : {\n listing: {\n revision,\n manifestHref,\n page: {\n number: index + 1,\n count: pageCount,\n offset: index * pageSize,\n total: directory.entries.length,\n href: pageHref(index),\n previousHref: index === 0 ? null : pageHref(index - 1),\n nextHref: index + 1 === pageCount ? null : pageHref(index + 1),\n },\n },\n }),\n });\n await writeFile(path.join(targetDir, pageName), page.html);\n for (const [assetName, contents] of Object.entries(page.assets ?? {})) {\n assertSafeOutputName(assetName);\n if (\n (options.listing !== undefined || theme.listing?.pagination === true) &&\n mode === \"ssg\" &&\n sourceEntryNames.has(assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with source entry: ${assetName}`);\n if (\n options.listing !== undefined &&\n pageNames.some((pageName) => pageName.toLowerCase() === assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with listing page: ${assetName}`);\n if (options.listing !== undefined && pageCount > 1) {\n const bytes = Buffer.from(contents);\n const existing = pagedAssets.get(assetName);\n if (existing !== undefined && !existing.equals(bytes))\n throw new Error(`Theme emitted conflicting paginated asset: ${assetName}`);\n pagedAssets.set(assetName, bytes);\n }\n if (mode === \"ssg\") {\n await writeFile(path.join(targetDir, assetName), contents);\n } else {\n const bytes = Buffer.from(contents);\n const existing = sharedAssets.get(assetName);\n if (existing !== undefined && !Buffer.from(existing).equals(bytes)) {\n throw new Error(`Theme emitted conflicting shared asset: ${assetName}`);\n }\n sharedAssets.set(assetName, bytes);\n }\n }\n }\n }\n\n if (mode === \"mpa\" && sharedAssets.size > 0) {\n const assetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(assetDirectory, { recursive: true });\n for (const [assetName, contents] of sharedAssets) {\n await writeFile(path.join(assetDirectory, assetName), contents);\n }\n }\n\n for (const [filename, bytes] of metadataResolver?.assets ?? []) {\n const parts = filename.split(\"/\");\n for (let index = 1; index <= parts.length; index++) {\n const prefix = parts.slice(0, index).join(\"/\");\n if (selection.selected.has(prefix))\n throw new Error(`Metadata image conflicts with source entry: ${filename}`);\n const candidate = path.join(buildOutputDir, prefix);\n try {\n const info = await lstat(candidate);\n if (info.isSymbolicLink() || index === parts.length || !info.isDirectory())\n throw new Error(`Metadata image conflicts with generated output: ${filename}`);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n const destination = path.join(buildOutputDir, filename);\n await mkdir(path.dirname(destination), { recursive: true });\n await writeFile(destination, bytes);\n }\n\n if (rawLinkFiles.size > 0) {\n const rawLinkDirectory = path.join(buildOutputDir, \"__dirwell\", \"raw-links\");\n await mkdir(rawLinkDirectory, { recursive: true });\n for (const [filename, target] of rawLinkFiles) {\n await writeFile(path.join(rawLinkDirectory, filename), target);\n }\n }\n if (theme.searchIndex !== false) {\n const generatedAssetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(generatedAssetDirectory, { recursive: true });\n const indexedEntries = [...searchEntries.values()];\n const shards: string[] = [];\n for (let offset = 0; offset < indexedEntries.length; offset += 512) {\n const filename = `search-${String(shards.length).padStart(5, \"0\")}.json`;\n shards.push(filename);\n await writeFile(\n path.join(generatedAssetDirectory, filename),\n JSON.stringify({ entries: indexedEntries.slice(offset, offset + 512) }),\n );\n }\n await writeFile(\n path.join(generatedAssetDirectory, \"search-index.json\"),\n JSON.stringify({ count: indexedEntries.length, shards, version: 3 }),\n );\n }\n\n await mkdir(path.join(buildOutputDir, \"__dirwell\"), { recursive: true });\n await writeFile(path.join(buildOutputDir, outputMarker), outputMarkerContents);\n await publishOutput(buildOutputDir, outputDir, sourceDir, options.outputPolicy);\n return report;\n } finally {\n if (stagedOutputDir !== null) await rm(stagedOutputDir, { recursive: true, force: true });\n }\n}\n\nexport async function readGeneratedPage(filePath: string): Promise<string> {\n return readFile(filePath, \"utf8\");\n}\n","/** Escape untrusted text for HTML/XML text nodes and double-quoted attributes. */\nexport function escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n","/** Some Windows Node/libuv versions omit the path-stat device ID but retain the file ID. */\nexport function fileIdentityMatches(\n before: { readonly device: number; readonly inode: number },\n descriptor: { readonly dev: number; readonly ino: number },\n platform = process.platform,\n): boolean {\n if (before.inode !== descriptor.ino) return false;\n if (before.device === descriptor.dev) return true;\n return platform === \"win32\" && before.device === 0 && before.inode !== 0;\n}\n","import { validateDirectoryOptions } from \"./validation.ts\";\nimport { readdir, realpath, open, type FileHandle } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { fileIdentityMatches } from \"./file-identity.ts\";\nimport path from \"node:path\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n selectSourcePaths,\n resolveIgnoreFiles,\n createIgnoreMatcher,\n normalizePathPatterns,\n} from \"./filters.ts\";\nimport { compareEntries } from \"./generator.ts\";\nimport { entryDataFacts } from \"./listing.ts\";\nimport { copyJsonObject } from \"./json.ts\";\nimport type {\n DirectoryData,\n FileSystemEntry,\n SortOptions,\n IgnoreFile,\n EntryDataProvider,\n} from \"./model.ts\";\n\nexport interface DirectoryServiceOptions {\n readonly entryData?: EntryDataProvider;\n readonly root: string;\n readonly include?: string | readonly string[];\n readonly exclude?: string | readonly string[];\n readonly ignoreFiles?: readonly IgnoreFile[];\n readonly sort?: SortOptions;\n}\nexport interface DirectoryService {\n readonly resolvePath: (logicalPath: string) => Promise<string>;\n readonly openFile: (logicalPath: string) => Promise<{\n readonly entry: FileSystemEntry;\n readonly handle: FileHandle;\n readonly canonicalPath: string;\n }>;\n readonly getEntry: (logicalPath: string) => Promise<FileSystemEntry>;\n readonly listDirectory: (logicalPath: string) => Promise<DirectoryData>;\n}\nexport class DirectoryAccessError extends Error {\n override readonly name = \"DirectoryAccessError\";\n}\nfunction assertLogicalPath(value: string): void {\n if (\n value.startsWith(\"/\") ||\n value.includes(\"\\\\\") ||\n value.includes(\"\\0\") ||\n value\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\" || (segment === \"\" && value !== \"\")) ||\n /^[a-z]:/i.test(value) ||\n value === \"__dirwell\" ||\n value.startsWith(\"__dirwell/\")\n )\n throw new DirectoryAccessError(\"Unavailable path\");\n}\n/** Live reads; no watcher, recursive stat snapshot, output tree or implicit cache. */\nexport async function createDirectoryService(\n options: DirectoryServiceOptions,\n): Promise<DirectoryService> {\n validateDirectoryOptions(options);\n const root = await realpath(options.root);\n const ignoreFiles = resolveIgnoreFiles(options.ignoreFiles);\n // Validate explicit sources before an HTTP host starts accepting requests.\n await createIgnoreMatcher(ignoreFiles);\n normalizePathPatterns(options.include, \"include\");\n normalizePathPatterns(options.exclude, \"exclude\");\n const selected = async () => {\n const matcher = await createIgnoreMatcher(ignoreFiles);\n if (\n normalizePathPatterns(options.include, \"include\").length === 0 &&\n normalizePathPatterns(options.exclude, \"exclude\").length === 0 &&\n !matcher.hasRules\n )\n return null;\n return (\n await selectSourcePaths(\n root,\n path.join(root, \"__dirwell\"),\n options.include,\n options.exclude,\n [],\n ignoreFiles,\n matcher,\n )\n ).selected;\n };\n async function describe(\n logicalPath: string,\n selection: ReadonlySet<string> | null,\n ): Promise<FileSystemEntry> {\n assertLogicalPath(logicalPath);\n if (selection !== null && !selection.has(logicalPath))\n throw new DirectoryAccessError(\"Unavailable path\");\n const absolutePath = path.join(root, logicalPath);\n const parent = logicalPath === \"\" ? root : await realpath(path.dirname(absolutePath));\n if (!isInsideRoot(root, parent)) throw new DirectoryAccessError(\"Unavailable path\");\n const ancestors = new Set<string>([root]);\n if (logicalPath !== \"\") {\n const segments = logicalPath.split(\"/\").slice(0, -1);\n for (let length = 1; length <= segments.length; length++)\n ancestors.add(await realpath(path.join(root, ...segments.slice(0, length))));\n }\n return describeEntry({\n absolutePath,\n relativePath: logicalPath,\n rootRealPath: root,\n ancestors,\n followSymlinks: false,\n selectedPaths: selection,\n });\n }\n return {\n async resolvePath(logicalPath) {\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (\n entry.symlink &&\n (entry.symlink.isBroken || entry.symlink.isOutsideRoot || entry.symlink.isTargetExcluded)\n )\n throw new DirectoryAccessError(\"Unavailable target\");\n const resolved = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, resolved)) throw new DirectoryAccessError(\"Unavailable target\");\n const canonical = path.relative(root, resolved).split(path.sep).join(\"/\");\n if (selection !== null && !selection.has(canonical))\n throw new DirectoryAccessError(\"Unavailable target\");\n return canonical;\n },\n async openFile(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n let entry = await describe(logicalPath, selection);\n if (entry.symlink !== null) {\n if (\n entry.symlink.isBroken ||\n entry.symlink.isOutsideRoot ||\n entry.symlink.isTargetExcluded ||\n entry.symlink.targetRelativePath === null\n )\n throw new DirectoryAccessError(\"Unavailable file\");\n entry = await describe(entry.symlink.targetRelativePath, selection);\n }\n if (entry.kind !== \"file\") throw new DirectoryAccessError(\"Unavailable file\");\n const handle = await open(\n entry.absolutePath,\n constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),\n );\n try {\n const stats = await handle.stat();\n const resolved = await realpath(entry.absolutePath);\n if (\n !stats.isFile() ||\n !isInsideRoot(root, resolved) ||\n !fileIdentityMatches(entry.metadata, stats)\n )\n throw new DirectoryAccessError(\"File changed before opening\");\n return {\n entry,\n handle,\n canonicalPath: path.relative(root, resolved).split(path.sep).join(\"/\"),\n };\n } catch (error) {\n await handle.close();\n throw error;\n }\n },\n async getEntry(logicalPath) {\n assertLogicalPath(logicalPath);\n return describe(logicalPath, await selected());\n },\n async listDirectory(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (entry.kind !== \"directory\") throw new DirectoryAccessError(\"Unavailable directory\");\n const physical = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, physical)) throw new DirectoryAccessError(\"Unavailable directory\");\n const names = (await readdir(physical)).filter(\n (name) => logicalPath !== \"\" || name !== \"__dirwell\",\n );\n const described = await Promise.all(\n names\n .filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name)))\n .map(async (name) => {\n let entry: FileSystemEntry;\n try {\n entry = await describe(path.posix.join(logicalPath, name), selection);\n } catch (error) {\n // An enumerated child may disappear before stat; the directory is still available.\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return null;\n throw error;\n }\n return options.entryData === undefined\n ? entry\n : {\n ...entry,\n publicData: copyJsonObject(\n await options.entryData(entryDataFacts(entry), {\n operation: \"server\",\n directoryPath: logicalPath,\n }),\n ),\n };\n }),\n );\n const entries = described.filter((entry): entry is FileSystemEntry => entry !== null);\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (left.relativePath < right.relativePath\n ? -1\n : left.relativePath > right.relativePath\n ? 1\n : 0),\n );\n return {\n root: await describe(\"\", selection),\n current: { ...entry, kind: \"directory\" },\n parent:\n logicalPath === \"\"\n ? null\n : await describe(\n path.posix.dirname(logicalPath) === \".\" ? \"\" : path.posix.dirname(logicalPath),\n selection,\n ),\n depth: logicalPath === \"\" ? 0 : logicalPath.split(\"/\").length,\n entries,\n };\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/filters.ts","../src/validation.ts","../src/filesystem.ts","../src/listing.ts","../src/publication.ts","../src/generator.ts","../src/html.ts","../src/file-identity.ts","../src/service.ts"],"sourcesContent":["import { opendir, readlink, readFile, realpath } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport picomatch from \"picomatch\";\nimport ignore from \"ignore\";\nimport type { IgnoreFile } from \"./model.ts\";\n\n/** Resolve configuration paths once, before a host changes working directories. */\nexport function resolveIgnoreFiles(\n value: unknown = [],\n cwd = process.cwd(),\n): readonly Exclude<IgnoreFile, string>[] {\n if (!Array.isArray(value)) throw new TypeError(\"ignoreFiles must be an array\");\n return value.map((input) => {\n const file = typeof input === \"string\" ? { path: input } : input;\n if (typeof file !== \"object\" || file === null || Array.isArray(file))\n throw new TypeError(\"ignoreFiles entries must be paths or objects\");\n for (const key of Object.keys(file))\n if (![\"path\", \"baseDir\", \"optional\"].includes(key))\n throw new TypeError(`Unsupported ignoreFiles key \"${key}\"`);\n for (const key of [\"path\", \"baseDir\"] as const)\n if (\n (key === \"path\" || file[key] !== undefined) &&\n (typeof file[key] !== \"string\" || file[key].length === 0)\n )\n throw new TypeError(`ignoreFiles.${key} must be a non-empty string`);\n if (file.optional !== undefined && typeof file.optional !== \"boolean\")\n throw new TypeError(\"ignoreFiles.optional must be a boolean\");\n const filename = path.resolve(cwd, file.path);\n return {\n path: filename,\n baseDir: path.resolve(cwd, file.baseDir ?? path.dirname(filename)),\n optional: file.optional ?? false,\n };\n });\n}\n\nexport async function createIgnoreMatcher(files: readonly IgnoreFile[]) {\n const rules: { base: string; matcher: ReturnType<typeof ignore> }[] = [];\n const scopes = new Map<string, ReturnType<typeof ignore>>();\n let hasRules = false;\n for (const file of resolveIgnoreFiles(files)) {\n let contents: string;\n try {\n contents = await readFile(file.path, \"utf8\");\n } catch (error) {\n if (file.optional && error instanceof Error && \"code\" in error && error.code === \"ENOENT\")\n continue;\n throw error;\n }\n const base = await realpath(file.baseDir!);\n if (contents.split(/\\r?\\n/).some((line) => line.trim() !== \"\" && !line.startsWith(\"#\")))\n hasRules = true;\n let matcher = scopes.get(base);\n if (matcher === undefined) {\n matcher = ignore();\n scopes.set(base, matcher);\n rules.push({ base, matcher });\n }\n matcher.add(contents);\n }\n // Preserve Git's parent-directory negation behavior across files in one scope.\n // Explicit deeper scopes override applicable parent-scope rules.\n rules.sort((left, right) => left.base.split(path.sep).length - right.base.split(path.sep).length);\n const matches = (filename: string, directory: boolean): boolean => {\n let ignored = false;\n for (const rule of rules) {\n if (!isWithin(rule.base, filename)) continue;\n const relative = path.relative(rule.base, filename).split(path.sep).join(\"/\");\n if (relative === \"\") continue;\n const result = rule.matcher.test(relative + (directory ? \"/\" : \"\"));\n if (result.ignored) ignored = true;\n else if (result.unignored) ignored = false;\n }\n return ignored;\n };\n return Object.assign(matches, { hasRules });\n}\n\nexport function normalizePathPatterns(value: unknown, name: string): readonly string[] {\n if (value === undefined) return [];\n const patterns = typeof value === \"string\" ? [value] : value;\n if (\n !Array.isArray(patterns) ||\n patterns.some(\n (pattern) =>\n typeof pattern !== \"string\" ||\n pattern.length === 0 ||\n pattern.startsWith(\"/\") ||\n /^[A-Za-z]:/.test(pattern) ||\n pattern.startsWith(\"!\") ||\n pattern.includes(\"\\\\\") ||\n pattern.split(\"/\").some((segment) => segment === \".\" || segment === \"..\"),\n )\n ) {\n throw new TypeError(`${name} must contain root-relative glob patterns using forward slashes`);\n }\n return patterns as readonly string[];\n}\n\nfunction isWithin(parent: string, candidate: string): boolean {\n const relative = path.relative(parent, candidate);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport interface SourceSelection {\n readonly selected: ReadonlySet<string>;\n readonly symlinks: ReadonlySet<string>;\n readonly mirroredSymlinks: ReadonlySet<string>;\n}\nexport interface SelectionBudget {\n readonly maxEntries: number;\n readonly maxDirectories: number;\n readonly signal: AbortSignal;\n readonly allowPath: (logicalPath: string) => Promise<boolean>;\n}\nexport class SelectionBudgetError extends Error {\n override readonly name = \"SelectionBudgetError\";\n}\n\n/** Select physical source paths; parent directories remain when a descendant matches. */\nexport async function selectSourcePaths(\n sourceDir: string,\n outputDir: string,\n include: unknown,\n exclude: unknown,\n ignoredPaths: readonly string[] = [],\n ignoreFiles: readonly IgnoreFile[] = [],\n preparedIgnore?: Awaited<ReturnType<typeof createIgnoreMatcher>>,\n budget?: SelectionBudget,\n): Promise<SourceSelection> {\n const isIgnored = preparedIgnore ?? (await createIgnoreMatcher(ignoreFiles));\n const canonicalRoot = await realpath(sourceDir);\n const ignored = ignoredPaths.map((value) => path.resolve(value));\n const included = normalizePathPatterns(include, \"include\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const excluded = normalizePathPatterns(exclude, \"exclude\").map((pattern) =>\n picomatch(pattern, { dot: true, nonegate: true }),\n );\n const selected = new Set<string>([\"\"]);\n const symlinks = new Map<string, string>();\n let entries = 0;\n let directories = 0;\n\n async function visit(\n directory: string,\n relativeDir: string,\n inheritedInclude: boolean,\n ): Promise<boolean> {\n budget?.signal.throwIfAborted();\n if (budget) {\n const physical = await realpath(directory);\n if (!isWithin(canonicalRoot, physical)) return false;\n if (path.relative(canonicalRoot, physical).split(path.sep).join(\"/\") !== relativeDir)\n return false;\n }\n if (budget && !(await budget.allowPath(relativeDir))) return false;\n if (budget && ++directories > budget.maxDirectories)\n throw new SelectionBudgetError(\"Directory scan budget exceeded\");\n let hasSelected = false;\n for await (const entry of await opendir(directory)) {\n budget?.signal.throwIfAborted();\n if (budget && ++entries > budget.maxEntries)\n throw new SelectionBudgetError(\"Entry scan budget exceeded\");\n const absolutePath = path.join(directory, entry.name);\n if (\n isWithin(outputDir, absolutePath) ||\n ignored.some((value) => isWithin(value, absolutePath))\n )\n continue;\n const relativePath = path.posix.join(relativeDir, entry.name);\n if (budget && !(await budget.allowPath(relativePath))) continue;\n const directoryLike = entry.isDirectory();\n const matches = (matcher: (value: string) => boolean) =>\n matcher(relativePath) || (directoryLike && matcher(`${relativePath}/`));\n if (\n excluded.some(matches) ||\n isIgnored(path.join(canonicalRoot, relativePath), directoryLike)\n )\n continue;\n const includedHere = inheritedInclude || included.some(matches);\n if (directoryLike) {\n const hasSelectedChild = await visit(absolutePath, relativePath, includedHere);\n if (included.length === 0 || includedHere || hasSelectedChild) {\n selected.add(relativePath);\n hasSelected = true;\n }\n } else if (included.length === 0 || includedHere) {\n selected.add(relativePath);\n hasSelected = true;\n if (entry.isSymbolicLink()) symlinks.set(relativePath, await readlink(absolutePath));\n }\n }\n return hasSelected;\n }\n\n if (!isIgnored(canonicalRoot, true)) await visit(sourceDir, \"\", false);\n // Absolute, escaping, and filtered targets cannot remain valid inside the copied tree.\n const mirroredSymlinks = new Set<string>();\n for (const [relativePath, target] of symlinks) {\n if (path.isAbsolute(target)) continue;\n const targetPath = path.resolve(sourceDir, path.dirname(relativePath), target);\n if (!isWithin(sourceDir, targetPath)) continue;\n const targetRelativePath = path.relative(sourceDir, targetPath).split(path.sep).join(\"/\");\n if (selected.has(targetRelativePath)) mirroredSymlinks.add(relativePath);\n }\n return { selected, symlinks: new Set(symlinks.keys()), mirroredSymlinks };\n}\n","import type { GenerateOptions, ExplorerTheme } from \"./model.ts\";\nimport type { DirectoryServiceOptions } from \"./service.ts\";\nimport type { ListingPlan } from \"./listing.ts\";\nimport { resolveIgnoreFiles } from \"./filters.ts\";\n\ntype Options = Record<string, unknown>;\nexport function optionObject(value: unknown, name: string): Options {\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n throw new TypeError(`${name} must be an object`);\n return value as Options;\n}\nfunction distance(left: string, right: string): number {\n let previous = Array.from({ length: right.length + 1 }, (_, index) => index);\n for (let i = 1; i <= left.length; i++) {\n const current = [i];\n for (let j = 1; j <= right.length; j++)\n current[j] = Math.min(\n current[j - 1]! + 1,\n previous[j]! + 1,\n previous[j - 1]! + (left[i - 1] === right[j - 1] ? 0 : 1),\n );\n previous = current;\n }\n return previous[right.length]!;\n}\nexport function optionKeys(value: Options, allowed: readonly string[], name: string): void {\n for (const key of Object.keys(value)) {\n if (allowed.includes(key)) continue;\n const suggestion = allowed\n .map((candidate) => ({ candidate, distance: distance(key, candidate) }))\n .sort((left, right) => left.distance - right.distance)\n .find((item) => item.distance <= 2)?.candidate;\n throw new TypeError(\n `Unsupported option \"${name}.${key}\".${suggestion ? ` Did you mean \"${name}.${suggestion}\"?` : ` Supported keys: ${allowed.join(\", \")}.`}`,\n );\n }\n}\nfunction scalar(value: unknown, type: \"boolean\" | \"string\" | \"function\", name: string): void {\n if (value !== undefined && typeof value !== type)\n throw new TypeError(`${name} must be a ${type}`);\n}\nfunction choice(value: unknown, allowed: readonly unknown[], name: string): void {\n if (value !== undefined && !allowed.includes(value))\n throw new TypeError(`${name} must be one of ${allowed.join(\", \")}`);\n}\nfunction positiveInteger(value: unknown, name: string): void {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1)\n throw new TypeError(`${name} must be a positive safe integer`);\n}\nexport function validateListingPlan(value: unknown): asserts value is ListingPlan {\n const plan = optionObject(value, \"listing\");\n optionKeys(plan, [\"html\", \"data\"], \"listing\");\n for (const [key, strategy, size] of [\n [\"html\", \"paged\", \"pageSize\"],\n [\"data\", \"blocks\", \"blockSize\"],\n ] as const) {\n const section = optionObject(plan[key], `listing.${key}`);\n optionKeys(\n section,\n section.strategy === strategy ? [\"strategy\", size] : [\"strategy\"],\n `listing.${key}`,\n );\n if (section.strategy !== \"all\" && section.strategy !== strategy)\n throw new TypeError(`listing.${key}.strategy must be all or ${strategy}`);\n if (section.strategy === strategy) positiveInteger(section[size], `listing.${key}.${size}`);\n }\n}\nfunction selection(value: Options, name: string): void {\n for (const key of [\"include\", \"exclude\"])\n if (\n value[key] !== undefined &&\n typeof value[key] !== \"string\" &&\n (!Array.isArray(value[key]) || value[key].some((item: unknown) => typeof item !== \"string\"))\n )\n throw new TypeError(`${name}.${key} must be a string or array of strings`);\n resolveIgnoreFiles(value.ignoreFiles);\n scalar(value.entryData, \"function\", `${name}.entryData`);\n if (value.sort !== undefined) {\n const sort = optionObject(value.sort, `${name}.sort`);\n optionKeys(sort, [\"field\", \"direction\", \"directoriesFirst\", \"nameMode\"], `${name}.sort`);\n scalar(sort.directoriesFirst, \"boolean\", `${name}.sort.directoriesFirst`);\n choice(sort.field, [\"name\", \"size\", \"modified\"], `${name}.sort.field`);\n choice(sort.direction, [\"asc\", \"desc\"], `${name}.sort.direction`);\n choice(sort.nameMode, [\"natural\", \"locale\", \"unicode\"], `${name}.sort.nameMode`);\n }\n}\nfunction requiredString(value: unknown, name: string): void {\n if (typeof value !== \"string\" || !value.length)\n throw new TypeError(`${name} must be a non-empty string`);\n}\nexport function validateTheme(\n value: unknown,\n name = \"options.theme\",\n): asserts value is ExplorerTheme {\n if (value === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const theme = optionObject(value, name);\n requiredString(theme.name, `${name}.name`);\n if (typeof theme.render !== \"function\") throw new TypeError(`${name}.render must be a function`);\n scalar(theme.entryData, \"function\", `${name}.entryData`);\n scalar(theme.searchIndex, \"boolean\", `${name}.searchIndex`);\n if (theme.listing !== undefined) {\n const listing = optionObject(theme.listing, `${name}.listing`);\n optionKeys(listing, [\"pagination\"], `${name}.listing`);\n if (typeof listing.pagination !== \"boolean\")\n throw new TypeError(`${name}.listing.pagination must be a boolean`);\n }\n}\nconst generateKeys = {\n sourceDir: true,\n outputDir: true,\n theme: true,\n include: true,\n exclude: true,\n ignoreFiles: true,\n sort: true,\n entryData: true,\n fileHref: true,\n dryRun: true,\n outputPolicy: true,\n listing: true,\n metadata: true,\n base: true,\n mode: true,\n mirror: true,\n outputName: true,\n urlStrategy: true,\n symlinks: true,\n} satisfies Record<keyof GenerateOptions, true>;\nexport function validateGenerateOptions(value: unknown): asserts value is GenerateOptions {\n const options = optionObject(value, \"options\");\n optionKeys(options, Object.keys(generateKeys), \"options\");\n requiredString(options.sourceDir, \"options.sourceDir\");\n requiredString(options.outputDir, \"options.outputDir\");\n validateTheme(options.theme);\n selection(options, \"options\");\n for (const key of [\"fileHref\", \"metadata\"]) scalar(options[key], \"function\", `options.${key}`);\n for (const key of [\"dryRun\", \"mirror\"]) scalar(options[key], \"boolean\", `options.${key}`);\n scalar(options.base, \"string\", \"options.base\");\n choice(options.mode, [\"ssg\", \"mpa\"], \"options.mode\");\n choice(\n options.urlStrategy,\n Object.keys({\n base: true,\n \"html-base\": true,\n relative: true,\n } satisfies Record<NonNullable<GenerateOptions[\"urlStrategy\"]>, true>),\n \"options.urlStrategy\",\n );\n choice(options.outputPolicy, [\"owned\", \"replace\"], \"options.outputPolicy\");\n if (\n options.outputName !== undefined &&\n typeof options.outputName !== \"string\" &&\n typeof options.outputName !== \"function\"\n )\n throw new TypeError(\"options.outputName must be a string or function\");\n if (options.listing !== undefined && typeof options.listing !== \"function\")\n validateListingPlan(options.listing);\n if (options.symlinks !== undefined) {\n const links = optionObject(options.symlinks, \"options.symlinks\");\n optionKeys(links, [\"follow\", \"boundary\", \"onCycle\"], \"options.symlinks\");\n scalar(links.follow, \"boolean\", \"options.symlinks.follow\");\n choice(links.boundary, [\"root\", \"anywhere\"], \"options.symlinks.boundary\");\n choice(links.onCycle, [\"error\", \"skip\"], \"options.symlinks.onCycle\");\n }\n}\nconst serviceKeys = {\n root: true,\n include: true,\n exclude: true,\n ignoreFiles: true,\n sort: true,\n entryData: true,\n} satisfies Record<keyof DirectoryServiceOptions, true>;\nexport function validateDirectoryOptions(value: unknown): asserts value is DirectoryServiceOptions {\n const options = optionObject(value, \"options\");\n optionKeys(options, Object.keys(serviceKeys), \"options\");\n requiredString(options.root, \"options.root\");\n selection(options, \"options\");\n}\n","import { lstat, readlink, realpath, stat } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport type { Stats } from \"node:fs\";\nimport type { EntryKind, FileMetadata, FileSystemEntry, SymlinkMetadata } from \"./model.ts\";\nfunction entryKind(stats: Stats): EntryKind {\n if (stats.isDirectory()) return \"directory\";\n if (stats.isFile()) return \"file\";\n if (stats.isSymbolicLink()) return \"symlink\";\n return \"other\";\n}\n\nfunction metadata(stats: Stats): FileMetadata {\n return {\n device: stats.dev,\n groupId: stats.gid,\n hardLinkCount: stats.nlink,\n inode: stats.ino,\n mode: stats.mode,\n ownerId: stats.uid,\n size: stats.size,\n times: {\n accessedAt: stats.atime.toISOString(),\n changedAt: stats.ctime.toISOString(),\n createdAt: stats.birthtime.toISOString(),\n modifiedAt: stats.mtime.toISOString(),\n },\n };\n}\n\nexport function isInsideRoot(rootPath: string, candidatePath: string): boolean {\n const relative = path.relative(rootPath, candidatePath);\n return (\n relative === \"\" ||\n (relative !== \"..\" && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative))\n );\n}\n\nexport async function describeEntry({\n absolutePath,\n relativePath,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths,\n}: {\n absolutePath: string;\n relativePath: string;\n rootRealPath: string;\n ancestors: ReadonlySet<string>;\n followSymlinks: boolean;\n selectedPaths: ReadonlySet<string> | null;\n}): Promise<FileSystemEntry> {\n const linkStats = await lstat(absolutePath);\n const kind = entryKind(linkStats);\n let symlink: SymlinkMetadata | null = null;\n\n if (kind === \"symlink\") {\n const target = await readlink(absolutePath);\n let resolvedPath: string | null = null;\n let targetKind: Exclude<EntryKind, \"symlink\"> | null = null;\n let targetSize: number | null = null;\n try {\n resolvedPath = await realpath(absolutePath);\n const targetStats = await stat(absolutePath);\n targetKind = entryKind(targetStats) as Exclude<EntryKind, \"symlink\">;\n targetSize = targetStats.size;\n } catch {\n // Broken and inaccessible links are represented as data.\n }\n const isOutsideRoot = resolvedPath === null || !isInsideRoot(rootRealPath, resolvedPath);\n const isCycle = resolvedPath !== null && ancestors.has(resolvedPath);\n const targetRelativePath =\n resolvedPath !== null && !isOutsideRoot\n ? path.relative(rootRealPath, resolvedPath).split(path.sep).join(\"/\")\n : null;\n const isTargetExcluded =\n targetRelativePath !== null &&\n selectedPaths !== null &&\n !selectedPaths.has(targetRelativePath);\n symlink = {\n target,\n resolvedPath,\n targetRelativePath,\n targetKind,\n targetSize:\n isOutsideRoot || isTargetExcluded || targetKind === \"directory\" ? null : targetSize,\n isBroken: resolvedPath === null,\n isCycle,\n isOutsideRoot,\n isTargetExcluded,\n wasFollowed:\n followSymlinks &&\n targetKind === \"directory\" &&\n !isCycle &&\n !isOutsideRoot &&\n !isTargetExcluded,\n };\n }\n\n return {\n name: path.basename(absolutePath),\n absolutePath,\n relativePath,\n kind,\n metadata: metadata(linkStats),\n symlink,\n };\n}\n","import type { JsonObject } from \"./json.ts\";\nimport { createHash } from \"node:crypto\";\nimport type { EntryKind, FileSystemEntry, ThemeContext, SortOptions } from \"./model.ts\";\nimport { copyJsonObject } from \"./json.ts\";\n\n/** Public transport fields only. Internal filesystem metadata must never be spread here. */\nexport interface ListingEntry {\n readonly data?: JsonObject;\n readonly presentation?: JsonObject;\n readonly id: string;\n readonly name: string;\n readonly kind: EntryKind;\n readonly href: string | null;\n readonly exitsExplorer: boolean;\n readonly size: number;\n readonly modifiedAt: string;\n readonly link: null | {\n readonly target: string;\n readonly targetKind: Exclude<EntryKind, \"symlink\"> | null;\n readonly targetSize: number | null;\n readonly unavailable: boolean;\n readonly cycle: boolean;\n };\n}\nexport interface ListingPlan {\n readonly html:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"paged\"; readonly pageSize: number };\n readonly data:\n | { readonly strategy: \"all\" }\n | { readonly strategy: \"blocks\"; readonly blockSize: number };\n}\nexport interface ListingPolicyContext {\n readonly operation?: \"build\" | \"server\";\n readonly directoryPath: string;\n readonly visibleCount: number;\n readonly dataBytes: number;\n readonly mode: \"ssg\" | \"mpa\";\n readonly supportsPagination: boolean;\n}\nexport type ListingPolicy = ListingPlan | ((context: ListingPolicyContext) => ListingPlan);\nexport interface ListingPage {\n readonly number: number;\n readonly count: number;\n readonly offset: number;\n readonly total: number;\n readonly href: string;\n readonly previousHref: string | null;\n readonly nextHref: string | null;\n}\nexport interface ListingContext {\n readonly revision: string;\n readonly manifestHref: string;\n readonly page: ListingPage;\n}\nexport interface ListingBlock {\n readonly version: 1;\n readonly revision: string;\n readonly offset: number;\n readonly total: number;\n readonly entries: readonly ListingEntry[];\n}\nexport interface ListingManifest {\n readonly version: 1;\n readonly revision: string;\n readonly directory: string;\n /** Resolve entry hrefs against this URL, resolved relative to the manifest URL. */\n readonly hrefBase: string;\n readonly total: number;\n readonly sort: Required<SortOptions>;\n /** Block hrefs are relative to the manifest URL. */\n readonly blocks: readonly {\n readonly href: string;\n readonly offset: number;\n readonly count: number;\n }[];\n}\n\nexport function projectListingEntry(\n entry: FileSystemEntry,\n context: Pick<ThemeContext, \"hrefFor\" | \"exitsExplorerFor\">,\n): ListingEntry {\n const link = entry.symlink;\n return {\n ...(entry.publicData === undefined ? {} : { data: copyJsonObject(entry.publicData) }),\n id: entry.relativePath,\n name: entry.name,\n kind: entry.kind,\n href: context.hrefFor(entry),\n exitsExplorer: context.exitsExplorerFor(entry),\n size: entry.metadata.size,\n modifiedAt: entry.metadata.times.modifiedAt,\n link:\n link === null\n ? null\n : {\n target: link.target,\n targetKind: link.targetKind,\n targetSize: link.targetSize ?? null,\n unavailable: link.isBroken || link.isOutsideRoot || Boolean(link.isTargetExcluded),\n cycle: link.isCycle,\n },\n };\n}\n\n/** Annotation providers receive public facts, not transport URLs or raw stat objects. */\nexport function entryDataFacts(\n entry: FileSystemEntry,\n): Omit<ListingEntry, \"href\" | \"exitsExplorer\" | \"presentation\" | \"data\"> {\n const {\n href: _href,\n exitsExplorer: _exits,\n data: _data,\n ...facts\n } = projectListingEntry(entry, { hrefFor: () => null, exitsExplorerFor: () => false });\n return facts;\n}\nexport { validateListingPlan } from \"./validation.ts\";\nexport function listingRevision(\n entries: readonly ListingEntry[],\n sort: Required<SortOptions>,\n hrefBase: string,\n blockSize: number,\n): string {\n return createHash(\"sha256\")\n .update(JSON.stringify({ version: 1, entries, sort, hrefBase, blockSize }))\n .digest(\"hex\");\n}\n","import { lstat, readdir, readFile, realpath, rename, rm, mkdir, open } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { randomUUID } from \"node:crypto\";\nimport { isInsideRoot } from \"./filesystem.ts\";\n\nexport const outputMarker = \"__dirwell/ownership.json\";\nexport const outputMarkerContents = '{\"type\":\"dirwell-output\",\"version\":1}\\n';\n\nexport async function lockOutput(output: string) {\n const canonical = await canonicalPath(output);\n const lockPath = path.join(path.dirname(canonical), `.${path.basename(canonical)}-dirwell.lock`);\n await mkdir(path.dirname(lockPath), { recursive: true });\n let handle;\n try {\n handle = await open(lockPath, \"wx\");\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"EEXIST\")\n throw new Error(\n `Output is locked by another build: ${lockPath}. Wait for it to finish. Remove a stale lock only after confirming its owner has stopped; --force does not bypass locks.`,\n );\n throw error;\n }\n try {\n await handle.writeFile(JSON.stringify({ pid: process.pid }));\n } catch (error) {\n await handle.close();\n await rm(lockPath);\n throw error;\n }\n return {\n lockPath,\n async release() {\n await handle.close();\n await rm(lockPath);\n },\n };\n}\n\nexport async function canonicalPath(filename: string): Promise<string> {\n try {\n return await realpath(filename);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n const parent = path.dirname(filename);\n if (parent === filename) throw error;\n return path.join(await canonicalPath(parent), path.basename(filename));\n }\n}\n\n/** Force permits output ownership replacement, never source containment violations. */\nexport async function checkOutput(\n source: string,\n output: string,\n policy: \"owned\" | \"replace\" = \"owned\",\n): Promise<boolean> {\n if (policy !== \"owned\" && policy !== \"replace\")\n throw new TypeError(\"outputPolicy must be owned or replace\");\n if (isInsideRoot(await canonicalPath(output), await realpath(source)))\n throw new Error(\"outputDir must not contain the sourceDir\");\n let stat;\n try {\n stat = await lstat(output);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return false;\n throw error;\n }\n if (stat.isSymbolicLink() || !stat.isDirectory())\n throw new Error(\"outputDir must be a directory, not a file or symlink\");\n if ((await readdir(output)).length === 0 || policy === \"replace\") return true;\n try {\n const marker = path.join(output, outputMarker);\n if (\n !(await lstat(path.dirname(marker))).isSymbolicLink() &&\n !(await lstat(marker)).isSymbolicLink() &&\n (await readFile(marker, \"utf8\")) === outputMarkerContents\n )\n return true;\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n throw new Error(\n \"Output is nonempty and not owned by Dirwell. Choose another directory or explicitly replace it with --force (-f) / outputPolicy: 'replace'.\",\n );\n}\n\n/** Keep a recoverable previous tree until the new tree is installed. */\nexport async function publishOutput(\n staged: string,\n output: string,\n source: string,\n policy: \"owned\" | \"replace\" = \"owned\",\n): Promise<void> {\n const exists = await checkOutput(source, output, policy);\n await mkdir(path.dirname(output), { recursive: true });\n const backup = path.join(\n path.dirname(output),\n `.${path.basename(output)}-previous-${randomUUID()}`,\n );\n if (exists) await rename(output, backup);\n try {\n await rename(staged, output);\n } catch (error) {\n if (exists) {\n try {\n await rename(backup, output);\n } catch (restoreError) {\n throw new AggregateError(\n [error, restoreError],\n `Publication failed; previous output is retained at ${backup}`,\n );\n }\n }\n throw error;\n }\n if (exists) await rm(backup, { recursive: true, force: true });\n}\n","import { validateGenerateOptions } from \"./validation.ts\";\nimport { copyJsonObject } from \"./json.ts\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n listingRevision,\n projectListingEntry,\n entryDataFacts,\n validateListingPlan,\n type ListingManifest,\n} from \"./listing.ts\";\nimport {\n cp,\n lstat,\n mkdtemp,\n mkdir,\n readFile,\n readdir,\n realpath,\n rm,\n writeFile,\n} from \"node:fs/promises\";\nimport { createHash } from \"node:crypto\";\nimport path from \"node:path\";\nimport type {\n DirectoryData,\n EntryKind,\n ExplorerTheme,\n FileSystemEntry,\n GenerateOptions,\n NameSortMode,\n OutputNameResolver,\n SortOptions,\n ThemeContext,\n} from \"./model.ts\";\nimport { selectSourcePaths } from \"./filters.ts\";\nimport {\n checkOutput,\n publishOutput,\n outputMarker,\n outputMarkerContents,\n lockOutput,\n canonicalPath,\n} from \"./publication.ts\";\nimport type { BuildReport } from \"./model.ts\";\n\nconst indexPattern = /^index\\.html?$/i;\n\nconst defaultSort = {\n direction: \"asc\",\n directoriesFirst: true,\n field: \"name\",\n nameMode: \"natural\",\n} as const satisfies Required<SortOptions>;\n\nexport const defaultOutputName: OutputNameResolver = ({ entries }) =>\n entries.some((entry) => entry.kind === \"file\" && indexPattern.test(entry.name))\n ? entries.some((entry) => entry.name.toLowerCase() === \"_dirwell.html\")\n ? null\n : \"_dirwell.html\"\n : \"index.html\";\n\nfunction assertSafeOutputName(name: string): void {\n if (name.length === 0 || path.basename(name) !== name || name === \".\" || name === \"..\") {\n throw new Error(`Output name must be a single safe filename: ${name}`);\n }\n}\n\nfunction normalizeBase(value: string): string {\n if (value.includes(\"?\") || value.includes(\"#\")) {\n throw new TypeError(\"base must not contain a query string or fragment\");\n }\n if (/^https?:\\/\\//i.test(value)) {\n const url = new URL(value);\n url.pathname = `${url.pathname.replace(/\\/+$/, \"\")}/`;\n return url.href;\n }\n if (!value.startsWith(\"/\")) {\n throw new TypeError('base must start with \"/\" or be an absolute HTTP(S) URL');\n }\n return `${value.replace(/\\/+$/, \"\")}/`;\n}\n\nfunction encodeLogicalPath(value: string): string {\n return value\n .split(\"/\")\n .filter((segment) => segment.length > 0)\n .map((segment) => encodeURIComponent(segment))\n .join(\"/\");\n}\n\nfunction isDirectoryLike(entry: FileSystemEntry): boolean {\n return entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n}\n\nfunction isUnavailableSymlink(entry: FileSystemEntry): boolean {\n return Boolean(\n entry.symlink?.isBroken || entry.symlink?.isOutsideRoot || entry.symlink?.isTargetExcluded,\n );\n}\n\nfunction compareUnicode(left: string, right: string): number {\n const leftPoints = [...left];\n const rightPoints = [...right];\n const length = Math.min(leftPoints.length, rightPoints.length);\n for (let index = 0; index < length; index += 1) {\n const difference =\n (leftPoints[index]?.codePointAt(0) ?? 0) - (rightPoints[index]?.codePointAt(0) ?? 0);\n if (difference !== 0) return difference;\n }\n return leftPoints.length - rightPoints.length;\n}\n\nfunction compareNames(left: string, right: string, mode: NameSortMode): number {\n if (mode === \"unicode\") return compareUnicode(left, right);\n return left.localeCompare(right, undefined, {\n numeric: mode === \"natural\",\n sensitivity: \"base\",\n });\n}\n\nexport function compareEntries(\n left: FileSystemEntry,\n right: FileSystemEntry,\n options: SortOptions = {},\n): number {\n const resolved = { ...defaultSort, ...options };\n if (resolved.directoriesFirst && isDirectoryLike(left) !== isDirectoryLike(right)) {\n return isDirectoryLike(left) ? -1 : 1;\n }\n let result: number;\n if (resolved.field === \"modified\") {\n result = left.metadata.times.modifiedAt.localeCompare(right.metadata.times.modifiedAt);\n } else if (resolved.field === \"size\") {\n result =\n (left.kind === \"directory\" ? 0 : left.metadata.size) -\n (right.kind === \"directory\" ? 0 : right.metadata.size);\n } else {\n result = compareNames(left.name, right.name, resolved.nameMode);\n }\n if (result === 0) result = compareNames(left.name, right.name, resolved.nameMode);\n return resolved.direction === \"asc\" ? result : -result;\n}\n\nfunction rawLinkFilename(entry: FileSystemEntry): string {\n return `${createHash(\"sha256\")\n .update(entry.relativePath)\n .update(\"\\0\")\n .update(entry.symlink?.target ?? \"\")\n .digest(\"hex\")\n .slice(0, 16)}.txt`;\n}\n\nexport async function generateExplorer(options: GenerateOptions): Promise<BuildReport> {\n return generateExplorerSkippingPaths(options, []);\n}\n\n/** Internal entry point for hosts that stage previews outside their published output. */\nexport async function generateExplorerSkippingPaths(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<BuildReport> {\n validateGenerateOptions(options);\n const source = path.resolve(options.sourceDir),\n output = path.resolve(options.outputDir);\n await checkOutput(source, output, options.outputPolicy);\n if (options.dryRun) return generateExplorerUnlocked(options, ignoredPaths);\n const lock = await lockOutput(output);\n const lexicalLock = path.join(path.dirname(output), path.basename(lock.lockPath));\n try {\n return await generateExplorerUnlocked(options, [...ignoredPaths, lock.lockPath, lexicalLock]);\n } finally {\n await lock.release();\n }\n}\n\nasync function generateExplorerUnlocked(\n options: GenerateOptions,\n ignoredPaths: readonly string[],\n): Promise<BuildReport> {\n const sourceDir = await realpath(path.resolve(options.sourceDir));\n const outputDir = await canonicalPath(path.resolve(options.outputDir));\n const ignoredSourcePaths = ignoredPaths.map((value) => path.resolve(value));\n const rootRealPath = await realpath(sourceDir);\n const replacesOutput = await checkOutput(sourceDir, outputDir, options.outputPolicy);\n const outputName = options.outputName ?? defaultOutputName;\n const resolveOutputName: OutputNameResolver =\n typeof outputName === \"string\" ? () => outputName : outputName;\n const theme: ExplorerTheme = options.theme;\n if (theme === undefined) throw new TypeError(\"Core requires an explicit theme\");\n const mode = options.mode ?? \"ssg\";\n const urlStrategy = options.urlStrategy ?? \"relative\";\n const base = normalizeBase(options.base ?? \"/\");\n const followSymlinks = options.symlinks?.follow ?? false;\n const boundary = options.symlinks?.boundary ?? \"root\";\n const onCycle = options.symlinks?.onCycle ?? \"skip\";\n const filtersActive =\n options.include !== undefined ||\n options.exclude !== undefined ||\n (options.ignoreFiles?.length ?? 0) > 0 ||\n ignoredSourcePaths.length > 0;\n const plans: Array<{\n readonly directory: DirectoryData;\n readonly logicalDir: string;\n readonly outputName: string | null;\n }> = [];\n if (isInsideRoot(outputDir, sourceDir)) {\n throw new Error(\"outputDir must not contain the sourceDir\");\n }\n try {\n await lstat(path.join(sourceDir, \"__dirwell\"));\n throw new Error('Dirwell reserves the source-root path \"__dirwell\"');\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") {\n // The reserved asset path is available.\n } else {\n throw error;\n }\n }\n const outputIsWithinSource = isInsideRoot(sourceDir, outputDir);\n const selection = await selectSourcePaths(\n sourceDir,\n outputDir,\n options.include,\n options.exclude,\n ignoredSourcePaths,\n options.ignoreFiles,\n );\n const stageParent = outputIsWithinSource ? path.dirname(sourceDir) : path.dirname(outputDir);\n if (!options.dryRun) await mkdir(stageParent, { recursive: true });\n const stagedOutputDir = options.dryRun\n ? null\n : await mkdtemp(path.join(stageParent, `.${path.basename(outputDir)}-dirwell-`));\n const buildOutputDir = stagedOutputDir!;\n\n try {\n if (!options.dryRun && (options.mirror ?? true)) {\n await rm(buildOutputDir, { recursive: true, force: true });\n await mkdir(buildOutputDir, { recursive: true });\n await cp(sourceDir, buildOutputDir, {\n recursive: true,\n dereference: false,\n preserveTimestamps: true,\n filter: (sourcePath) => {\n const relativePath = path.relative(sourceDir, sourcePath).split(path.sep).join(\"/\");\n return (\n selection.selected.has(relativePath) &&\n (!selection.symlinks.has(relativePath) || selection.mirroredSymlinks.has(relativePath))\n );\n },\n });\n }\n } catch (error) {\n if (stagedOutputDir !== null) await rm(stagedOutputDir, { recursive: true, force: true });\n throw error;\n }\n\n async function visit(\n logicalDir: string,\n physicalDir: string,\n ancestors: ReadonlySet<string>,\n ): Promise<void> {\n const physicalRealPath = await realpath(physicalDir);\n if (ancestors.has(physicalRealPath)) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${logicalDir}`);\n return;\n }\n\n const nextAncestors = new Set(ancestors).add(physicalRealPath);\n const names = (await readdir(physicalDir)).filter((name) => {\n if (outputIsWithinSource && isInsideRoot(outputDir, path.join(physicalDir, name)))\n return false;\n if (ignoredSourcePaths.some((value) => isInsideRoot(value, path.join(physicalDir, name))))\n return false;\n if (!filtersActive) return true;\n const relativePath = path.relative(rootRealPath, path.join(physicalRealPath, name));\n return selection.selected.has(relativePath.split(path.sep).join(\"/\"));\n });\n const entries = await Promise.all(\n names.map(async (name) => {\n const entry = await describeEntry({\n absolutePath: path.join(physicalDir, name),\n relativePath: path.posix.join(logicalDir, name),\n rootRealPath,\n ancestors: nextAncestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n return options.entryData === undefined\n ? entry\n : {\n ...entry,\n publicData: copyJsonObject(\n await options.entryData(entryDataFacts(entry), {\n operation: \"build\",\n directoryPath: logicalDir,\n }),\n ),\n };\n }),\n );\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (options.listing === undefined ? 0 : compareUnicode(left.relativePath, right.relativePath)),\n );\n\n const describedCurrent = await describeEntry({\n absolutePath: physicalDir,\n relativePath: logicalDir,\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n if (describedCurrent.kind !== \"directory\") {\n throw new Error(`${physicalDir} is not a directory`);\n }\n const current: DirectoryData[\"current\"] = {\n ...describedCurrent,\n kind: \"directory\",\n };\n\n const root = await describeEntry({\n absolutePath: sourceDir,\n relativePath: \"\",\n rootRealPath,\n ancestors: new Set(),\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const parent =\n logicalDir === \"\"\n ? null\n : await describeEntry({\n absolutePath: path.dirname(physicalDir),\n relativePath:\n path.posix.dirname(logicalDir) === \".\" ? \"\" : path.posix.dirname(logicalDir),\n rootRealPath,\n ancestors,\n followSymlinks,\n selectedPaths: filtersActive ? selection.selected : null,\n });\n const directory: DirectoryData = {\n root,\n current,\n parent,\n depth: logicalDir === \"\" ? 0 : logicalDir.split(\"/\").length,\n entries,\n };\n\n const name = await resolveOutputName(directory);\n if (name !== null) assertSafeOutputName(name);\n plans.push({ directory, logicalDir, outputName: name });\n\n for (const entry of entries) {\n if (entry.kind === \"directory\") {\n await visit(path.posix.join(logicalDir, entry.name), entry.absolutePath, nextAncestors);\n continue;\n }\n if (!followSymlinks || entry.symlink?.targetKind !== \"directory\") continue;\n const physicalLinkPath = path\n .relative(rootRealPath, path.join(physicalRealPath, entry.name))\n .split(path.sep)\n .join(\"/\");\n if ((options.mirror ?? true) && !selection.mirroredSymlinks.has(physicalLinkPath)) continue;\n if (entry.symlink.isCycle) {\n if (onCycle === \"error\") throw new Error(`Symlink cycle at ${entry.relativePath}`);\n continue;\n }\n if (entry.symlink.resolvedPath === null) continue;\n if (boundary === \"root\" && entry.symlink.isOutsideRoot) continue;\n if (\n filtersActive &&\n (entry.symlink.targetRelativePath === null ||\n !selection.selected.has(entry.symlink.targetRelativePath))\n )\n continue;\n // Mirrored internal aliases already resolve to the target's generated page.\n // Writing an alias page through the copied symlink would overwrite that page.\n if (\n (options.mirror ?? true) &&\n entry.symlink.targetRelativePath !== null &&\n !entry.symlink.isOutsideRoot\n )\n continue;\n await visit(\n path.posix.join(logicalDir, entry.name),\n entry.symlink.resolvedPath,\n nextAncestors,\n );\n }\n }\n\n try {\n await visit(\"\", sourceDir, new Set());\n\n const report: BuildReport = {\n sourceDir,\n outputDir,\n theme: theme.name,\n dryRun: options.dryRun ?? false,\n mirror: options.mirror ?? true,\n replacesOutput,\n selectedPaths: [...selection.selected].filter(Boolean).sort(),\n pages: plans.map((plan) => ({ directory: plan.logicalDir, outputName: plan.outputName })),\n };\n if (options.dryRun) return report;\n\n const generatedPages = new Map(\n plans\n .filter(\n (plan): plan is typeof plan & { readonly outputName: string } => plan.outputName !== null,\n )\n .map((plan) => [plan.logicalDir, plan.outputName]),\n );\n const generatedDirectories = new Set(generatedPages.keys());\n const pagePathForDirectory = (logicalPath: string): string => {\n const pageName = generatedPages.get(logicalPath);\n return pageName === undefined || pageName === \"index.html\"\n ? logicalPath\n : path.posix.join(logicalPath, pageName);\n };\n const sourceKinds = new Map<string, string>();\n for (const { directory } of plans)\n for (const entry of directory.entries) {\n const sourcePath = path.relative(sourceDir, entry.absolutePath).split(path.sep).join(\"/\");\n if (selection.selected.has(sourcePath)) sourceKinds.set(sourcePath, entry.kind);\n }\n const metadataResolver = await options.metadata?.({ sourceDir, sourceKinds });\n const sharedAssets = new Map<string, string | Uint8Array>();\n const rawLinkFiles = new Map<string, string>();\n const searchEntries = new Map<\n string,\n {\n href: string | null;\n exitsExplorer: boolean;\n isLink: boolean;\n kind: EntryKind;\n modifiedAt: string;\n name: string;\n path: string;\n size: number;\n target: string | null;\n targetKind: Exclude<EntryKind, \"symlink\"> | null;\n targetSize: number | null;\n isTargetUnavailable: boolean;\n isCycle: boolean;\n }\n >();\n\n const fileHrefs = new Map<string, string | null>();\n const mappedFileHref = (logicalPath: string): string | null => {\n if (!fileHrefs.has(logicalPath)) {\n const href = options.fileHref!(logicalPath);\n if (\n href !== null &&\n (typeof href !== \"string\" ||\n href.length === 0 ||\n href.includes(\"\\\\\") ||\n Array.from(href).some((character) => character.charCodeAt(0) < 32) ||\n ![\"http:\", \"https:\"].includes(new URL(href, \"https://dirwell.invalid/\").protocol))\n )\n throw new TypeError(\n \"fileHref must return a synchronous HTTP(S), root-relative or relative URL, or null\",\n );\n fileHrefs.set(logicalPath, href);\n }\n return fileHrefs.get(logicalPath)!;\n };\n\n for (const { directory, logicalDir } of theme.searchIndex === false ? [] : plans) {\n for (const entry of directory.entries) {\n if (searchEntries.has(entry.relativePath)) continue;\n const targetLogicalPath = isUnavailableSymlink(entry)\n ? null\n : entry.symlink?.targetRelativePath !== null && entry.symlink !== null\n ? entry.symlink.targetRelativePath\n : path.posix.join(logicalDir, entry.name);\n const directoryLike = isDirectoryLike(entry);\n const linkedPath =\n directoryLike && targetLogicalPath !== null\n ? pagePathForDirectory(targetLogicalPath)\n : targetLogicalPath;\n let href: string | null = null;\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n href = `raw-links/${filename}`;\n } else if (linkedPath !== null) {\n href =\n linkedPath === \"\"\n ? \"../\"\n : `../${encodeLogicalPath(linkedPath)}${directoryLike && linkedPath === targetLogicalPath ? \"/\" : \"\"}`;\n if (!directoryLike && options.fileHref !== undefined) href = mappedFileHref(linkedPath);\n }\n searchEntries.set(entry.relativePath, {\n exitsExplorer:\n isUnavailableSymlink(entry) ||\n (targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))),\n href,\n isLink: entry.kind === \"symlink\",\n kind: entry.kind,\n modifiedAt: entry.metadata.times.modifiedAt,\n name: entry.name,\n path: entry.relativePath,\n size: entry.metadata.size,\n target: entry.symlink?.target ?? null,\n targetKind: entry.symlink?.targetKind ?? null,\n targetSize: entry.symlink?.targetSize ?? null,\n isTargetUnavailable: isUnavailableSymlink(entry),\n isCycle: entry.symlink?.isCycle ?? false,\n });\n }\n }\n\n for (const plan of plans) {\n const { directory, logicalDir, outputName: name } = plan;\n const sourceEntryNames = new Set(directory.entries.map((entry) => entry.name.toLowerCase()));\n if (name === null) continue;\n\n const targetLogicalPathFor = (entry: FileSystemEntry): string | null => {\n if (isUnavailableSymlink(entry)) return null;\n if (entry.symlink?.targetRelativePath !== null && entry.symlink !== null) {\n return entry.symlink.targetRelativePath;\n }\n return path.posix.join(logicalDir, entry.name);\n };\n const hrefForLogicalPath = (targetPath: string, directoryLike: boolean): string => {\n const linkedPath = directoryLike ? pagePathForDirectory(targetPath) : targetPath;\n const linkToDirectory = directoryLike && linkedPath === targetPath;\n if (urlStrategy === \"relative\") {\n const relativeTarget = path.posix.relative(\n logicalDir === \"\" ? \".\" : logicalDir,\n linkedPath === \"\" ? \".\" : linkedPath,\n );\n const encodedTarget = relativeTarget\n .split(\"/\")\n .map((segment) =>\n segment === \".\" || segment === \"..\" ? segment : encodeURIComponent(segment),\n )\n .join(\"/\");\n return `${encodedTarget || \".\"}${linkToDirectory ? \"/\" : \"\"}`;\n }\n const encodedTarget = encodeLogicalPath(linkedPath);\n if (encodedTarget === \"\") {\n return urlStrategy === \"base\" ? base : \"./\";\n }\n const suffix = `${encodedTarget}${linkToDirectory ? \"/\" : \"\"}`;\n return urlStrategy === \"base\" ? `${base}${suffix}` : suffix;\n };\n const hrefFor = (entry: FileSystemEntry): string | null => {\n if (entry.symlink !== null && isUnavailableSymlink(entry)) {\n const filename = rawLinkFilename(entry);\n rawLinkFiles.set(filename, entry.symlink.target);\n return hrefForLogicalPath(path.posix.join(\"__dirwell\", \"raw-links\", filename), false);\n }\n const targetLogicalPath = targetLogicalPathFor(entry);\n if (targetLogicalPath === null) return null;\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n if (!directoryLike && options.fileHref !== undefined)\n return mappedFileHref(targetLogicalPath);\n return hrefForLogicalPath(targetLogicalPath, directoryLike);\n };\n const baseContext: ThemeContext = {\n operation: \"build\",\n directory,\n documentBaseHref: urlStrategy === \"html-base\" ? base : null,\n outputName: name,\n mode,\n searchIndexHref: hrefForLogicalPath(\n path.posix.join(\"__dirwell\", \"search-index.json\"),\n false,\n ),\n sort: { ...defaultSort, ...options.sort },\n assetHref: (assetName) => {\n assertSafeOutputName(assetName);\n return hrefForLogicalPath(\n mode === \"ssg\"\n ? path.posix.join(logicalDir, assetName)\n : path.posix.join(\"__dirwell\", assetName),\n false,\n );\n },\n hrefFor,\n hrefForDirectory: (relativePath) => hrefForLogicalPath(relativePath, true),\n hasPageForDirectory: (relativePath) => generatedDirectories.has(relativePath),\n exitsExplorerFor: (entry) => {\n if (isUnavailableSymlink(entry)) return true;\n const targetLogicalPath = targetLogicalPathFor(entry);\n const directoryLike =\n entry.kind === \"directory\" || entry.symlink?.targetKind === \"directory\";\n return (\n targetLogicalPath !== null &&\n (!directoryLike || !generatedDirectories.has(targetLogicalPath))\n );\n },\n };\n const targetDir = path.join(buildOutputDir, logicalDir);\n await mkdir(targetDir, { recursive: true });\n const sort = baseContext.sort;\n let revision = \"\";\n let manifestHref = \"\";\n let pageSize = Math.max(1, directory.entries.length);\n if (options.listing !== undefined) {\n const records = directory.entries.map((entry) => {\n const projected = projectListingEntry(entry, baseContext);\n return theme.entryData === undefined\n ? projected\n : {\n ...projected,\n presentation: copyJsonObject(\n theme.entryData(projected, {\n mode: baseContext.mode,\n outputName: baseContext.outputName,\n assetHref: baseContext.assetHref,\n hrefForDirectory: baseContext.hrefForDirectory,\n documentBaseHref: baseContext.documentBaseHref,\n directoryPath: logicalDir,\n }),\n ),\n };\n });\n const candidate =\n typeof options.listing === \"function\"\n ? options.listing({\n directoryPath: logicalDir,\n visibleCount: records.length,\n dataBytes: Buffer.byteLength(JSON.stringify(records)),\n mode,\n operation: \"build\",\n supportsPagination: theme.listing?.pagination === true,\n })\n : options.listing;\n validateListingPlan(candidate);\n if (candidate.html.strategy === \"paged\") {\n if (theme.listing?.pagination !== true)\n throw new Error(`Theme ${theme.name} does not support listing pagination`);\n pageSize = candidate.html.pageSize;\n }\n const directoryId = createHash(\"sha256\").update(logicalDir).digest(\"hex\");\n const manifestDirectory = path.posix.join(\"__dirwell\", \"listing\", directoryId);\n // Relative records belong to the document directory, not to the JSON asset directory.\n const hrefBase =\n urlStrategy === \"relative\"\n ? `../../../${encodeLogicalPath(logicalDir)}${logicalDir ? \"/\" : \"\"}`\n : base;\n const manifestPath = path.posix.join(manifestDirectory, \"manifest.json\");\n manifestHref = hrefForLogicalPath(manifestPath, false);\n const blocks: Array<ListingManifest[\"blocks\"][number]> = [];\n const blockSize =\n candidate.data.strategy === \"blocks\"\n ? candidate.data.blockSize\n : Math.max(1, records.length);\n revision = listingRevision(records, sort, hrefBase, blockSize);\n const outputListingDir = path.join(buildOutputDir, manifestDirectory);\n await mkdir(outputListingDir, { recursive: true });\n for (let offset = 0; offset < records.length || offset === 0; offset += blockSize) {\n const entries = records.slice(offset, offset + blockSize);\n const filename = `${revision}-${blocks.length}.json`;\n blocks.push({ href: filename, offset, count: entries.length });\n await writeFile(\n path.join(outputListingDir, filename),\n JSON.stringify({ version: 1, revision, offset, total: records.length, entries }),\n );\n }\n const manifest: ListingManifest = {\n version: 1,\n revision,\n directory: logicalDir,\n hrefBase,\n total: records.length,\n sort,\n blocks,\n };\n await writeFile(path.join(outputListingDir, \"manifest.json\"), JSON.stringify(manifest));\n }\n const pageCount = Math.max(1, Math.ceil(directory.entries.length / pageSize));\n const pagePrefix = `__dirwell-page-${createHash(\"sha256\").update(name).digest(\"hex\").slice(0, 16)}`;\n const pageNames = Array.from({ length: pageCount }, (_, index) =>\n index === 0 ? name : `${pagePrefix}-${index + 1}.html`,\n );\n for (const pageName of pageNames.slice(1)) {\n if (directory.entries.some((entry) => entry.name.toLowerCase() === pageName.toLowerCase()))\n throw new Error(\n `Listing page conflicts with source entry: ${path.posix.join(logicalDir, pageName)}`,\n );\n }\n const pagedAssets = new Map<string, Buffer>();\n for (const [index, pageName] of pageNames.entries()) {\n const pagePath = path.posix.join(logicalDir, pageName);\n const metadata = await metadataResolver?.resolve(\n directory,\n (outputPath) => hrefForLogicalPath(outputPath, false),\n pageName === \"index.html\" ? (logicalDir ? `${logicalDir}/` : \"\") : pagePath,\n );\n const pageHref = (number: number): string =>\n hrefForLogicalPath(path.posix.join(logicalDir, pageNames[number] ?? name), false);\n const page = await theme.render({\n ...baseContext,\n ...(metadata === undefined ? {} : { metadata }),\n outputName: pageName,\n directory:\n options.listing === undefined\n ? directory\n : {\n ...directory,\n entries: directory.entries.slice(index * pageSize, (index + 1) * pageSize),\n },\n ...(options.listing === undefined\n ? {}\n : {\n listing: {\n revision,\n manifestHref,\n page: {\n number: index + 1,\n count: pageCount,\n offset: index * pageSize,\n total: directory.entries.length,\n href: pageHref(index),\n previousHref: index === 0 ? null : pageHref(index - 1),\n nextHref: index + 1 === pageCount ? null : pageHref(index + 1),\n },\n },\n }),\n });\n await writeFile(path.join(targetDir, pageName), page.html);\n for (const [assetName, contents] of Object.entries(page.assets ?? {})) {\n assertSafeOutputName(assetName);\n if (\n (options.listing !== undefined || theme.listing?.pagination === true) &&\n mode === \"ssg\" &&\n sourceEntryNames.has(assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with source entry: ${assetName}`);\n if (\n options.listing !== undefined &&\n pageNames.some((pageName) => pageName.toLowerCase() === assetName.toLowerCase())\n )\n throw new Error(`Theme asset conflicts with listing page: ${assetName}`);\n if (options.listing !== undefined && pageCount > 1) {\n const bytes = Buffer.from(contents);\n const existing = pagedAssets.get(assetName);\n if (existing !== undefined && !existing.equals(bytes))\n throw new Error(`Theme emitted conflicting paginated asset: ${assetName}`);\n pagedAssets.set(assetName, bytes);\n }\n if (mode === \"ssg\") {\n await writeFile(path.join(targetDir, assetName), contents);\n } else {\n const bytes = Buffer.from(contents);\n const existing = sharedAssets.get(assetName);\n if (existing !== undefined && !Buffer.from(existing).equals(bytes)) {\n throw new Error(`Theme emitted conflicting shared asset: ${assetName}`);\n }\n sharedAssets.set(assetName, bytes);\n }\n }\n }\n }\n\n if (mode === \"mpa\" && sharedAssets.size > 0) {\n const assetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(assetDirectory, { recursive: true });\n for (const [assetName, contents] of sharedAssets) {\n await writeFile(path.join(assetDirectory, assetName), contents);\n }\n }\n\n for (const [filename, bytes] of metadataResolver?.assets ?? []) {\n const parts = filename.split(\"/\");\n for (let index = 1; index <= parts.length; index++) {\n const prefix = parts.slice(0, index).join(\"/\");\n if (selection.selected.has(prefix))\n throw new Error(`Metadata image conflicts with source entry: ${filename}`);\n const candidate = path.join(buildOutputDir, prefix);\n try {\n const info = await lstat(candidate);\n if (info.isSymbolicLink() || index === parts.length || !info.isDirectory())\n throw new Error(`Metadata image conflicts with generated output: ${filename}`);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n const destination = path.join(buildOutputDir, filename);\n await mkdir(path.dirname(destination), { recursive: true });\n await writeFile(destination, bytes);\n }\n\n if (rawLinkFiles.size > 0) {\n const rawLinkDirectory = path.join(buildOutputDir, \"__dirwell\", \"raw-links\");\n await mkdir(rawLinkDirectory, { recursive: true });\n for (const [filename, target] of rawLinkFiles) {\n await writeFile(path.join(rawLinkDirectory, filename), target);\n }\n }\n if (theme.searchIndex !== false) {\n const generatedAssetDirectory = path.join(buildOutputDir, \"__dirwell\");\n await mkdir(generatedAssetDirectory, { recursive: true });\n const indexedEntries = [...searchEntries.values()];\n const shards: string[] = [];\n for (let offset = 0; offset < indexedEntries.length; offset += 512) {\n const filename = `search-${String(shards.length).padStart(5, \"0\")}.json`;\n shards.push(filename);\n await writeFile(\n path.join(generatedAssetDirectory, filename),\n JSON.stringify({ entries: indexedEntries.slice(offset, offset + 512) }),\n );\n }\n await writeFile(\n path.join(generatedAssetDirectory, \"search-index.json\"),\n JSON.stringify({ count: indexedEntries.length, shards, version: 3 }),\n );\n }\n\n await mkdir(path.join(buildOutputDir, \"__dirwell\"), { recursive: true });\n await writeFile(path.join(buildOutputDir, outputMarker), outputMarkerContents);\n await publishOutput(buildOutputDir, outputDir, sourceDir, options.outputPolicy);\n return report;\n } finally {\n if (stagedOutputDir !== null) await rm(stagedOutputDir, { recursive: true, force: true });\n }\n}\n\nexport async function readGeneratedPage(filePath: string): Promise<string> {\n return readFile(filePath, \"utf8\");\n}\n","/** Escape untrusted text for HTML/XML text nodes and double-quoted attributes. */\nexport function escapeHtml(value: string): string {\n return value\n .replaceAll(\"&\", \"&\")\n .replaceAll(\"<\", \"<\")\n .replaceAll(\">\", \">\")\n .replaceAll('\"', \""\");\n}\n","/** Some Windows Node/libuv versions omit the path-stat device ID but retain the file ID. */\nexport function fileIdentityMatches(\n before: { readonly device: number; readonly inode: number },\n descriptor: { readonly dev: number; readonly ino: number },\n platform = process.platform,\n): boolean {\n if (before.inode !== descriptor.ino) return false;\n if (before.device === descriptor.dev) return true;\n return platform === \"win32\" && before.device === 0 && before.inode !== 0;\n}\n","import { validateDirectoryOptions } from \"./validation.ts\";\nimport { readdir, realpath, open, type FileHandle } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { fileIdentityMatches } from \"./file-identity.ts\";\nimport path from \"node:path\";\nimport { describeEntry, isInsideRoot } from \"./filesystem.ts\";\nimport {\n selectSourcePaths,\n resolveIgnoreFiles,\n createIgnoreMatcher,\n normalizePathPatterns,\n type SelectionBudget,\n} from \"./filters.ts\";\nimport { compareEntries } from \"./generator.ts\";\nimport { entryDataFacts } from \"./listing.ts\";\nimport { copyJsonObject } from \"./json.ts\";\nimport type {\n DirectoryData,\n FileSystemEntry,\n SortOptions,\n IgnoreFile,\n EntryDataProvider,\n} from \"./model.ts\";\n\nexport interface DirectoryServiceOptions {\n readonly entryData?: EntryDataProvider;\n readonly root: string;\n readonly include?: string | readonly string[];\n readonly exclude?: string | readonly string[];\n readonly ignoreFiles?: readonly IgnoreFile[];\n readonly sort?: SortOptions;\n}\nexport interface DirectoryService {\n /** Bounded fresh enumeration; authorization runs before directory traversal. */\n readonly scan: (budget: SelectionBudget) => Promise<readonly FileSystemEntry[]>;\n readonly resolvePath: (logicalPath: string) => Promise<string>;\n readonly openFile: (logicalPath: string) => Promise<{\n readonly entry: FileSystemEntry;\n readonly handle: FileHandle;\n readonly canonicalPath: string;\n }>;\n readonly getEntry: (logicalPath: string) => Promise<FileSystemEntry>;\n readonly listDirectory: (logicalPath: string) => Promise<DirectoryData>;\n}\nexport class DirectoryAccessError extends Error {\n override readonly name = \"DirectoryAccessError\";\n}\nfunction assertLogicalPath(value: string): void {\n if (\n value.startsWith(\"/\") ||\n value.includes(\"\\\\\") ||\n value.includes(\"\\0\") ||\n value\n .split(\"/\")\n .some((segment) => segment === \".\" || segment === \"..\" || (segment === \"\" && value !== \"\")) ||\n /^[a-z]:/i.test(value) ||\n value === \"__dirwell\" ||\n value.startsWith(\"__dirwell/\")\n )\n throw new DirectoryAccessError(\"Unavailable path\");\n}\n/** Live reads; no watcher, recursive stat snapshot, output tree or implicit cache. */\nexport async function createDirectoryService(\n options: DirectoryServiceOptions,\n): Promise<DirectoryService> {\n validateDirectoryOptions(options);\n const root = await realpath(options.root);\n const ignoreFiles = resolveIgnoreFiles(options.ignoreFiles);\n // Validate explicit sources before an HTTP host starts accepting requests.\n await createIgnoreMatcher(ignoreFiles);\n normalizePathPatterns(options.include, \"include\");\n normalizePathPatterns(options.exclude, \"exclude\");\n const selected = async () => {\n const matcher = await createIgnoreMatcher(ignoreFiles);\n if (\n normalizePathPatterns(options.include, \"include\").length === 0 &&\n normalizePathPatterns(options.exclude, \"exclude\").length === 0 &&\n !matcher.hasRules\n )\n return null;\n return (\n await selectSourcePaths(\n root,\n path.join(root, \"__dirwell\"),\n options.include,\n options.exclude,\n [],\n ignoreFiles,\n matcher,\n )\n ).selected;\n };\n async function describe(\n logicalPath: string,\n selection: ReadonlySet<string> | null,\n ): Promise<FileSystemEntry> {\n assertLogicalPath(logicalPath);\n if (selection !== null && !selection.has(logicalPath))\n throw new DirectoryAccessError(\"Unavailable path\");\n const absolutePath = path.join(root, logicalPath);\n const parent = logicalPath === \"\" ? root : await realpath(path.dirname(absolutePath));\n if (!isInsideRoot(root, parent)) throw new DirectoryAccessError(\"Unavailable path\");\n const ancestors = new Set<string>([root]);\n if (logicalPath !== \"\") {\n const segments = logicalPath.split(\"/\").slice(0, -1);\n for (let length = 1; length <= segments.length; length++)\n ancestors.add(await realpath(path.join(root, ...segments.slice(0, length))));\n }\n return describeEntry({\n absolutePath,\n relativePath: logicalPath,\n rootRealPath: root,\n ancestors,\n followSymlinks: false,\n selectedPaths: selection,\n });\n }\n return {\n async scan(budget) {\n if (\n !budget ||\n !Number.isSafeInteger(budget.maxEntries) ||\n budget.maxEntries < 1 ||\n !Number.isSafeInteger(budget.maxDirectories) ||\n budget.maxDirectories < 1 ||\n !(budget.signal instanceof AbortSignal) ||\n typeof budget.allowPath !== \"function\"\n )\n throw new TypeError(\n \"scan requires positive entry/directory limits, an AbortSignal and allowPath\",\n );\n const selection = (\n await selectSourcePaths(\n root,\n path.join(root, \"__dirwell\"),\n options.include,\n options.exclude,\n [],\n ignoreFiles,\n undefined,\n budget,\n )\n ).selected;\n const entries: FileSystemEntry[] = [];\n for (const logical of [...selection].sort()) {\n budget.signal.throwIfAborted();\n if (!logical) continue;\n try {\n const entry = await describe(logical, selection);\n // Canonical physical entries cover safe aliases once, without following cycles.\n if (entry.kind === \"file\" || entry.kind === \"directory\") entries.push(entry);\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") continue;\n throw error;\n }\n }\n return entries;\n },\n async resolvePath(logicalPath) {\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (\n entry.symlink &&\n (entry.symlink.isBroken || entry.symlink.isOutsideRoot || entry.symlink.isTargetExcluded)\n )\n throw new DirectoryAccessError(\"Unavailable target\");\n const resolved = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, resolved)) throw new DirectoryAccessError(\"Unavailable target\");\n const canonical = path.relative(root, resolved).split(path.sep).join(\"/\");\n if (selection !== null && !selection.has(canonical))\n throw new DirectoryAccessError(\"Unavailable target\");\n return canonical;\n },\n async openFile(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n let entry = await describe(logicalPath, selection);\n if (entry.symlink !== null) {\n if (\n entry.symlink.isBroken ||\n entry.symlink.isOutsideRoot ||\n entry.symlink.isTargetExcluded ||\n entry.symlink.targetRelativePath === null\n )\n throw new DirectoryAccessError(\"Unavailable file\");\n entry = await describe(entry.symlink.targetRelativePath, selection);\n }\n if (entry.kind !== \"file\") throw new DirectoryAccessError(\"Unavailable file\");\n const handle = await open(\n entry.absolutePath,\n constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0),\n );\n try {\n const stats = await handle.stat();\n const resolved = await realpath(entry.absolutePath);\n if (\n !stats.isFile() ||\n !isInsideRoot(root, resolved) ||\n !fileIdentityMatches(entry.metadata, stats)\n )\n throw new DirectoryAccessError(\"File changed before opening\");\n return {\n entry,\n handle,\n canonicalPath: path.relative(root, resolved).split(path.sep).join(\"/\"),\n };\n } catch (error) {\n await handle.close();\n throw error;\n }\n },\n async getEntry(logicalPath) {\n assertLogicalPath(logicalPath);\n return describe(logicalPath, await selected());\n },\n async listDirectory(logicalPath) {\n assertLogicalPath(logicalPath);\n const selection = await selected();\n const entry = await describe(logicalPath, selection);\n if (entry.kind !== \"directory\") throw new DirectoryAccessError(\"Unavailable directory\");\n const physical = await realpath(entry.absolutePath);\n if (!isInsideRoot(root, physical)) throw new DirectoryAccessError(\"Unavailable directory\");\n const names = (await readdir(physical)).filter(\n (name) => logicalPath !== \"\" || name !== \"__dirwell\",\n );\n const described = await Promise.all(\n names\n .filter((name) => selection === null || selection.has(path.posix.join(logicalPath, name)))\n .map(async (name) => {\n let entry: FileSystemEntry;\n try {\n entry = await describe(path.posix.join(logicalPath, name), selection);\n } catch (error) {\n // An enumerated child may disappear before stat; the directory is still available.\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") return null;\n throw error;\n }\n return options.entryData === undefined\n ? entry\n : {\n ...entry,\n publicData: copyJsonObject(\n await options.entryData(entryDataFacts(entry), {\n operation: \"server\",\n directoryPath: logicalPath,\n }),\n ),\n };\n }),\n );\n const entries = described.filter((entry): entry is FileSystemEntry => entry !== null);\n entries.sort(\n (left, right) =>\n compareEntries(left, right, options.sort) ||\n (left.relativePath < right.relativePath\n ? -1\n : left.relativePath > right.relativePath\n ? 1\n : 0),\n );\n return {\n root: await describe(\"\", selection),\n current: { ...entry, kind: \"directory\" },\n parent:\n logicalPath === \"\"\n ? null\n : await describe(\n path.posix.dirname(logicalPath) === \".\" ? \"\" : path.posix.dirname(logicalPath),\n selection,\n ),\n depth: logicalPath === \"\" ? 0 : logicalPath.split(\"/\").length,\n entries,\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;AAOA,SAAgB,mBACd,QAAiB,CAAC,GAClB,MAAM,QAAQ,IAAI,GACsB;CACxC,IAAI,CAAC,MAAM,QAAQ,KAAK,GAAG,MAAM,IAAI,UAAU,8BAA8B;CAC7E,OAAO,MAAM,KAAK,UAAU;EAC1B,MAAM,OAAO,OAAO,UAAU,WAAW,EAAE,MAAM,MAAM,IAAI;EAC3D,IAAI,OAAO,SAAS,YAAY,SAAS,QAAQ,MAAM,QAAQ,IAAI,GACjE,MAAM,IAAI,UAAU,8CAA8C;EACpE,KAAK,MAAM,OAAO,OAAO,KAAK,IAAI,GAChC,IAAI,CAAC;GAAC;GAAQ;GAAW;EAAU,CAAC,CAAC,SAAS,GAAG,GAC/C,MAAM,IAAI,UAAU,gCAAgC,IAAI,EAAE;EAC9D,KAAK,MAAM,OAAO,CAAC,QAAQ,SAAS,GAClC,KACG,QAAQ,UAAU,KAAK,SAAS,KAAA,OAChC,OAAO,KAAK,SAAS,YAAY,KAAK,IAAI,CAAC,WAAW,IAEvD,MAAM,IAAI,UAAU,eAAe,IAAI,4BAA4B;EACvE,IAAI,KAAK,aAAa,KAAA,KAAa,OAAO,KAAK,aAAa,WAC1D,MAAM,IAAI,UAAU,wCAAwC;EAC9D,MAAM,WAAW,KAAK,QAAQ,KAAK,KAAK,IAAI;EAC5C,OAAO;GACL,MAAM;GACN,SAAS,KAAK,QAAQ,KAAK,KAAK,WAAW,KAAK,QAAQ,QAAQ,CAAC;GACjE,UAAU,KAAK,YAAY;EAC7B;CACF,CAAC;AACH;AAEA,eAAsB,oBAAoB,OAA8B;CACtE,MAAM,QAAgE,CAAC;CACvE,MAAM,yBAAS,IAAI,IAAuC;CAC1D,IAAI,WAAW;CACf,KAAK,MAAM,QAAQ,mBAAmB,KAAK,GAAG;EAC5C,IAAI;EACJ,IAAI;GACF,WAAW,MAAM,SAAS,KAAK,MAAM,MAAM;EAC7C,SAAS,OAAO;GACd,IAAI,KAAK,YAAY,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAC/E;GACF,MAAM;EACR;EACA,MAAM,OAAO,MAAM,SAAS,KAAK,OAAQ;EACzC,IAAI,SAAS,MAAM,OAAO,CAAC,CAAC,MAAM,SAAS,KAAK,KAAK,MAAM,MAAM,CAAC,KAAK,WAAW,GAAG,CAAC,GACpF,WAAW;EACb,IAAI,UAAU,OAAO,IAAI,IAAI;EAC7B,IAAI,YAAY,KAAA,GAAW;GACzB,UAAU,OAAO;GACjB,OAAO,IAAI,MAAM,OAAO;GACxB,MAAM,KAAK;IAAE;IAAM;GAAQ,CAAC;EAC9B;EACA,QAAQ,IAAI,QAAQ;CACtB;CAGA,MAAM,MAAM,MAAM,UAAU,KAAK,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,SAAS,MAAM,KAAK,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM;CAChG,MAAM,WAAW,UAAkB,cAAgC;EACjE,IAAI,UAAU;EACd,KAAK,MAAM,QAAQ,OAAO;GACxB,IAAI,CAAC,SAAS,KAAK,MAAM,QAAQ,GAAG;GACpC,MAAM,WAAW,KAAK,SAAS,KAAK,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;GAC5E,IAAI,aAAa,IAAI;GACrB,MAAM,SAAS,KAAK,QAAQ,KAAK,YAAY,YAAY,MAAM,GAAG;GAClE,IAAI,OAAO,SAAS,UAAU;QACzB,IAAI,OAAO,WAAW,UAAU;EACvC;EACA,OAAO;CACT;CACA,OAAO,OAAO,OAAO,SAAS,EAAE,SAAS,CAAC;AAC5C;AAEA,SAAgB,sBAAsB,OAAgB,MAAiC;CACrF,IAAI,UAAU,KAAA,GAAW,OAAO,CAAC;CACjC,MAAM,WAAW,OAAO,UAAU,WAAW,CAAC,KAAK,IAAI;CACvD,IACE,CAAC,MAAM,QAAQ,QAAQ,KACvB,SAAS,MACN,YACC,OAAO,YAAY,YACnB,QAAQ,WAAW,KACnB,QAAQ,WAAW,GAAG,KACtB,aAAa,KAAK,OAAO,KACzB,QAAQ,WAAW,GAAG,KACtB,QAAQ,SAAS,IAAI,KACrB,QAAQ,MAAM,GAAG,CAAC,CAAC,MAAM,YAAY,YAAY,OAAO,YAAY,IAAI,CAC5E,GAEA,MAAM,IAAI,UAAU,GAAG,KAAK,gEAAgE;CAE9F,OAAO;AACT;AAEA,SAAS,SAAS,QAAgB,WAA4B;CAC5D,MAAM,WAAW,KAAK,SAAS,QAAQ,SAAS;CAChD,OACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,KAAK,KAAK,KAAK,KAAK,CAAC,KAAK,WAAW,QAAQ;AAE5F;AAaA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;AAC3B;;AAGA,eAAsB,kBACpB,WACA,WACA,SACA,SACA,eAAkC,CAAC,GACnC,cAAqC,CAAC,GACtC,gBACA,QAC0B;CAC1B,MAAM,YAAY,kBAAmB,MAAM,oBAAoB,WAAW;CAC1E,MAAM,gBAAgB,MAAM,SAAS,SAAS;CAC9C,MAAM,UAAU,aAAa,KAAK,UAAU,KAAK,QAAQ,KAAK,CAAC;CAC/D,MAAM,WAAW,sBAAsB,SAAS,SAAS,CAAC,CAAC,KAAK,YAC9D,UAAU,SAAS;EAAE,KAAK;EAAM,UAAU;CAAK,CAAC,CAClD;CACA,MAAM,WAAW,sBAAsB,SAAS,SAAS,CAAC,CAAC,KAAK,YAC9D,UAAU,SAAS;EAAE,KAAK;EAAM,UAAU;CAAK,CAAC,CAClD;CACA,MAAM,2BAAW,IAAI,IAAY,CAAC,EAAE,CAAC;CACrC,MAAM,2BAAW,IAAI,IAAoB;CACzC,IAAI,UAAU;CACd,IAAI,cAAc;CAElB,eAAe,MACb,WACA,aACA,kBACkB;EAClB,QAAQ,OAAO,eAAe;EAC9B,IAAI,QAAQ;GACV,MAAM,WAAW,MAAM,SAAS,SAAS;GACzC,IAAI,CAAC,SAAS,eAAe,QAAQ,GAAG,OAAO;GAC/C,IAAI,KAAK,SAAS,eAAe,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,MAAM,aACvE,OAAO;EACX;EACA,IAAI,UAAU,CAAE,MAAM,OAAO,UAAU,WAAW,GAAI,OAAO;EAC7D,IAAI,UAAU,EAAE,cAAc,OAAO,gBACnC,MAAM,IAAI,qBAAqB,gCAAgC;EACjE,IAAI,cAAc;EAClB,WAAW,MAAM,SAAS,MAAM,QAAQ,SAAS,GAAG;GAClD,QAAQ,OAAO,eAAe;GAC9B,IAAI,UAAU,EAAE,UAAU,OAAO,YAC/B,MAAM,IAAI,qBAAqB,4BAA4B;GAC7D,MAAM,eAAe,KAAK,KAAK,WAAW,MAAM,IAAI;GACpD,IACE,SAAS,WAAW,YAAY,KAChC,QAAQ,MAAM,UAAU,SAAS,OAAO,YAAY,CAAC,GAErD;GACF,MAAM,eAAe,KAAK,MAAM,KAAK,aAAa,MAAM,IAAI;GAC5D,IAAI,UAAU,CAAE,MAAM,OAAO,UAAU,YAAY,GAAI;GACvD,MAAM,gBAAgB,MAAM,YAAY;GACxC,MAAM,WAAW,YACf,QAAQ,YAAY,KAAM,iBAAiB,QAAQ,GAAG,aAAa,EAAE;GACvE,IACE,SAAS,KAAK,OAAO,KACrB,UAAU,KAAK,KAAK,eAAe,YAAY,GAAG,aAAa,GAE/D;GACF,MAAM,eAAe,oBAAoB,SAAS,KAAK,OAAO;GAC9D,IAAI,eAAe;IACjB,MAAM,mBAAmB,MAAM,MAAM,cAAc,cAAc,YAAY;IAC7E,IAAI,SAAS,WAAW,KAAK,gBAAgB,kBAAkB;KAC7D,SAAS,IAAI,YAAY;KACzB,cAAc;IAChB;GACF,OAAO,IAAI,SAAS,WAAW,KAAK,cAAc;IAChD,SAAS,IAAI,YAAY;IACzB,cAAc;IACd,IAAI,MAAM,eAAe,GAAG,SAAS,IAAI,cAAc,MAAM,SAAS,YAAY,CAAC;GACrF;EACF;EACA,OAAO;CACT;CAEA,IAAI,CAAC,UAAU,eAAe,IAAI,GAAG,MAAM,MAAM,WAAW,IAAI,KAAK;CAErE,MAAM,mCAAmB,IAAI,IAAY;CACzC,KAAK,MAAM,CAAC,cAAc,WAAW,UAAU;EAC7C,IAAI,KAAK,WAAW,MAAM,GAAG;EAC7B,MAAM,aAAa,KAAK,QAAQ,WAAW,KAAK,QAAQ,YAAY,GAAG,MAAM;EAC7E,IAAI,CAAC,SAAS,WAAW,UAAU,GAAG;EACtC,MAAM,qBAAqB,KAAK,SAAS,WAAW,UAAU,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;EACxF,IAAI,SAAS,IAAI,kBAAkB,GAAG,iBAAiB,IAAI,YAAY;CACzE;CACA,OAAO;EAAE;EAAU,UAAU,IAAI,IAAI,SAAS,KAAK,CAAC;EAAG;CAAiB;AAC1E;;;AC5MA,SAAgB,aAAa,OAAgB,MAAuB;CAClE,IAAI,OAAO,UAAU,YAAY,UAAU,QAAQ,MAAM,QAAQ,KAAK,GACpE,MAAM,IAAI,UAAU,GAAG,KAAK,mBAAmB;CACjD,OAAO;AACT;AACA,SAAS,SAAS,MAAc,OAAuB;CACrD,IAAI,WAAW,MAAM,KAAK,EAAE,QAAQ,MAAM,SAAS,EAAE,IAAI,GAAG,UAAU,KAAK;CAC3E,KAAK,IAAI,IAAI,GAAG,KAAK,KAAK,QAAQ,KAAK;EACrC,MAAM,UAAU,CAAC,CAAC;EAClB,KAAK,IAAI,IAAI,GAAG,KAAK,MAAM,QAAQ,KACjC,QAAQ,KAAK,KAAK,IAChB,QAAQ,IAAI,KAAM,GAClB,SAAS,KAAM,GACf,SAAS,IAAI,MAAO,KAAK,IAAI,OAAO,MAAM,IAAI,KAAK,IAAI,EACzD;EACF,WAAW;CACb;CACA,OAAO,SAAS,MAAM;AACxB;AACA,SAAgB,WAAW,OAAgB,SAA4B,MAAoB;CACzF,KAAK,MAAM,OAAO,OAAO,KAAK,KAAK,GAAG;EACpC,IAAI,QAAQ,SAAS,GAAG,GAAG;EAC3B,MAAM,aAAa,QAChB,KAAK,eAAe;GAAE;GAAW,UAAU,SAAS,KAAK,SAAS;EAAE,EAAE,CAAC,CACvE,MAAM,MAAM,UAAU,KAAK,WAAW,MAAM,QAAQ,CAAC,CACrD,MAAM,SAAS,KAAK,YAAY,CAAC,CAAC,EAAE;EACvC,MAAM,IAAI,UACR,uBAAuB,KAAK,GAAG,IAAI,IAAI,aAAa,kBAAkB,KAAK,GAAG,WAAW,MAAM,oBAAoB,QAAQ,KAAK,IAAI,EAAE,IACxI;CACF;AACF;AACA,SAAS,OAAO,OAAgB,MAAyC,MAAoB;CAC3F,IAAI,UAAU,KAAA,KAAa,OAAO,UAAU,MAC1C,MAAM,IAAI,UAAU,GAAG,KAAK,aAAa,MAAM;AACnD;AACA,SAAS,OAAO,OAAgB,SAA6B,MAAoB;CAC/E,IAAI,UAAU,KAAA,KAAa,CAAC,QAAQ,SAAS,KAAK,GAChD,MAAM,IAAI,UAAU,GAAG,KAAK,kBAAkB,QAAQ,KAAK,IAAI,GAAG;AACtE;AACA,SAAS,gBAAgB,OAAgB,MAAoB;CAC3D,IAAI,OAAO,UAAU,YAAY,CAAC,OAAO,cAAc,KAAK,KAAK,QAAQ,GACvE,MAAM,IAAI,UAAU,GAAG,KAAK,iCAAiC;AACjE;AACA,SAAgB,oBAAoB,OAA8C;CAChF,MAAM,OAAO,aAAa,OAAO,SAAS;CAC1C,WAAW,MAAM,CAAC,QAAQ,MAAM,GAAG,SAAS;CAC5C,KAAK,MAAM,CAAC,KAAK,UAAU,SAAS,CAClC;EAAC;EAAQ;EAAS;CAAU,GAC5B;EAAC;EAAQ;EAAU;CAAW,CAChC,GAAY;EACV,MAAM,UAAU,aAAa,KAAK,MAAM,WAAW,KAAK;EACxD,WACE,SACA,QAAQ,aAAa,WAAW,CAAC,YAAY,IAAI,IAAI,CAAC,UAAU,GAChE,WAAW,KACb;EACA,IAAI,QAAQ,aAAa,SAAS,QAAQ,aAAa,UACrD,MAAM,IAAI,UAAU,WAAW,IAAI,2BAA2B,UAAU;EAC1E,IAAI,QAAQ,aAAa,UAAU,gBAAgB,QAAQ,OAAO,WAAW,IAAI,GAAG,MAAM;CAC5F;AACF;AACA,SAAS,UAAU,OAAgB,MAAoB;CACrD,KAAK,MAAM,OAAO,CAAC,WAAW,SAAS,GACrC,IACE,MAAM,SAAS,KAAA,KACf,OAAO,MAAM,SAAS,aACrB,CAAC,MAAM,QAAQ,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC,MAAM,SAAkB,OAAO,SAAS,QAAQ,IAE1F,MAAM,IAAI,UAAU,GAAG,KAAK,GAAG,IAAI,sCAAsC;CAC7E,mBAAmB,MAAM,WAAW;CACpC,OAAO,MAAM,WAAW,YAAY,GAAG,KAAK,WAAW;CACvD,IAAI,MAAM,SAAS,KAAA,GAAW;EAC5B,MAAM,OAAO,aAAa,MAAM,MAAM,GAAG,KAAK,MAAM;EACpD,WAAW,MAAM;GAAC;GAAS;GAAa;GAAoB;EAAU,GAAG,GAAG,KAAK,MAAM;EACvF,OAAO,KAAK,kBAAkB,WAAW,GAAG,KAAK,uBAAuB;EACxE,OAAO,KAAK,OAAO;GAAC;GAAQ;GAAQ;EAAU,GAAG,GAAG,KAAK,YAAY;EACrE,OAAO,KAAK,WAAW,CAAC,OAAO,MAAM,GAAG,GAAG,KAAK,gBAAgB;EAChE,OAAO,KAAK,UAAU;GAAC;GAAW;GAAU;EAAS,GAAG,GAAG,KAAK,eAAe;CACjF;AACF;AACA,SAAS,eAAe,OAAgB,MAAoB;CAC1D,IAAI,OAAO,UAAU,YAAY,CAAC,MAAM,QACtC,MAAM,IAAI,UAAU,GAAG,KAAK,4BAA4B;AAC5D;AACA,SAAgB,cACd,OACA,OAAO,iBACyB;CAChC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,UAAU,iCAAiC;CAC9E,MAAM,QAAQ,aAAa,OAAO,IAAI;CACtC,eAAe,MAAM,MAAM,GAAG,KAAK,MAAM;CACzC,IAAI,OAAO,MAAM,WAAW,YAAY,MAAM,IAAI,UAAU,GAAG,KAAK,2BAA2B;CAC/F,OAAO,MAAM,WAAW,YAAY,GAAG,KAAK,WAAW;CACvD,OAAO,MAAM,aAAa,WAAW,GAAG,KAAK,aAAa;CAC1D,IAAI,MAAM,YAAY,KAAA,GAAW;EAC/B,MAAM,UAAU,aAAa,MAAM,SAAS,GAAG,KAAK,SAAS;EAC7D,WAAW,SAAS,CAAC,YAAY,GAAG,GAAG,KAAK,SAAS;EACrD,IAAI,OAAO,QAAQ,eAAe,WAChC,MAAM,IAAI,UAAU,GAAG,KAAK,sCAAsC;CACtE;AACF;AACA,MAAM,eAAe;CACnB,WAAW;CACX,WAAW;CACX,OAAO;CACP,SAAS;CACT,SAAS;CACT,aAAa;CACb,MAAM;CACN,WAAW;CACX,UAAU;CACV,QAAQ;CACR,cAAc;CACd,SAAS;CACT,UAAU;CACV,MAAM;CACN,MAAM;CACN,QAAQ;CACR,YAAY;CACZ,aAAa;CACb,UAAU;AACZ;AACA,SAAgB,wBAAwB,OAAkD;CACxF,MAAM,UAAU,aAAa,OAAO,SAAS;CAC7C,WAAW,SAAS,OAAO,KAAK,YAAY,GAAG,SAAS;CACxD,eAAe,QAAQ,WAAW,mBAAmB;CACrD,eAAe,QAAQ,WAAW,mBAAmB;CACrD,cAAc,QAAQ,KAAK;CAC3B,UAAU,SAAS,SAAS;CAC5B,KAAK,MAAM,OAAO,CAAC,YAAY,UAAU,GAAG,OAAO,QAAQ,MAAM,YAAY,WAAW,KAAK;CAC7F,KAAK,MAAM,OAAO,CAAC,UAAU,QAAQ,GAAG,OAAO,QAAQ,MAAM,WAAW,WAAW,KAAK;CACxF,OAAO,QAAQ,MAAM,UAAU,cAAc;CAC7C,OAAO,QAAQ,MAAM,CAAC,OAAO,KAAK,GAAG,cAAc;CACnD,OACE,QAAQ,aACR,OAAO,KAAK;EACV,MAAM;EACN,aAAa;EACb,UAAU;CACZ,CAAqE,GACrE,qBACF;CACA,OAAO,QAAQ,cAAc,CAAC,SAAS,SAAS,GAAG,sBAAsB;CACzE,IACE,QAAQ,eAAe,KAAA,KACvB,OAAO,QAAQ,eAAe,YAC9B,OAAO,QAAQ,eAAe,YAE9B,MAAM,IAAI,UAAU,iDAAiD;CACvE,IAAI,QAAQ,YAAY,KAAA,KAAa,OAAO,QAAQ,YAAY,YAC9D,oBAAoB,QAAQ,OAAO;CACrC,IAAI,QAAQ,aAAa,KAAA,GAAW;EAClC,MAAM,QAAQ,aAAa,QAAQ,UAAU,kBAAkB;EAC/D,WAAW,OAAO;GAAC;GAAU;GAAY;EAAS,GAAG,kBAAkB;EACvE,OAAO,MAAM,QAAQ,WAAW,yBAAyB;EACzD,OAAO,MAAM,UAAU,CAAC,QAAQ,UAAU,GAAG,2BAA2B;EACxE,OAAO,MAAM,SAAS,CAAC,SAAS,MAAM,GAAG,0BAA0B;CACrE;AACF;AACA,MAAM,cAAc;CAClB,MAAM;CACN,SAAS;CACT,SAAS;CACT,aAAa;CACb,MAAM;CACN,WAAW;AACb;AACA,SAAgB,yBAAyB,OAA0D;CACjG,MAAM,UAAU,aAAa,OAAO,SAAS;CAC7C,WAAW,SAAS,OAAO,KAAK,WAAW,GAAG,SAAS;CACvD,eAAe,QAAQ,MAAM,cAAc;CAC3C,UAAU,SAAS,SAAS;AAC9B;;;AC9KA,SAAS,UAAU,OAAyB;CAC1C,IAAI,MAAM,YAAY,GAAG,OAAO;CAChC,IAAI,MAAM,OAAO,GAAG,OAAO;CAC3B,IAAI,MAAM,eAAe,GAAG,OAAO;CACnC,OAAO;AACT;AAEA,SAAS,SAAS,OAA4B;CAC5C,OAAO;EACL,QAAQ,MAAM;EACd,SAAS,MAAM;EACf,eAAe,MAAM;EACrB,OAAO,MAAM;EACb,MAAM,MAAM;EACZ,SAAS,MAAM;EACf,MAAM,MAAM;EACZ,OAAO;GACL,YAAY,MAAM,MAAM,YAAY;GACpC,WAAW,MAAM,MAAM,YAAY;GACnC,WAAW,MAAM,UAAU,YAAY;GACvC,YAAY,MAAM,MAAM,YAAY;EACtC;CACF;AACF;AAEA,SAAgB,aAAa,UAAkB,eAAgC;CAC7E,MAAM,WAAW,KAAK,SAAS,UAAU,aAAa;CACtD,OACE,aAAa,MACZ,aAAa,QAAQ,CAAC,SAAS,WAAW,KAAK,KAAK,KAAK,KAAK,CAAC,KAAK,WAAW,QAAQ;AAE5F;AAEA,eAAsB,cAAc,EAClC,cACA,cACA,cACA,WACA,gBACA,iBAQ2B;CAC3B,MAAM,YAAY,MAAM,MAAM,YAAY;CAC1C,MAAM,OAAO,UAAU,SAAS;CAChC,IAAI,UAAkC;CAEtC,IAAI,SAAS,WAAW;EACtB,MAAM,SAAS,MAAM,SAAS,YAAY;EAC1C,IAAI,eAA8B;EAClC,IAAI,aAAmD;EACvD,IAAI,aAA4B;EAChC,IAAI;GACF,eAAe,MAAM,SAAS,YAAY;GAC1C,MAAM,cAAc,MAAM,KAAK,YAAY;GAC3C,aAAa,UAAU,WAAW;GAClC,aAAa,YAAY;EAC3B,QAAQ,CAER;EACA,MAAM,gBAAgB,iBAAiB,QAAQ,CAAC,aAAa,cAAc,YAAY;EACvF,MAAM,UAAU,iBAAiB,QAAQ,UAAU,IAAI,YAAY;EACnE,MAAM,qBACJ,iBAAiB,QAAQ,CAAC,gBACtB,KAAK,SAAS,cAAc,YAAY,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,IAClE;EACN,MAAM,mBACJ,uBAAuB,QACvB,kBAAkB,QAClB,CAAC,cAAc,IAAI,kBAAkB;EACvC,UAAU;GACR;GACA;GACA;GACA;GACA,YACE,iBAAiB,oBAAoB,eAAe,cAAc,OAAO;GAC3E,UAAU,iBAAiB;GAC3B;GACA;GACA;GACA,aACE,kBACA,eAAe,eACf,CAAC,WACD,CAAC,iBACD,CAAC;EACL;CACF;CAEA,OAAO;EACL,MAAM,KAAK,SAAS,YAAY;EAChC;EACA;EACA;EACA,UAAU,SAAS,SAAS;EAC5B;CACF;AACF;;;AC7BA,SAAgB,oBACd,OACA,SACc;CACd,MAAM,OAAO,MAAM;CACnB,OAAO;EACL,GAAI,MAAM,eAAe,KAAA,IAAY,CAAC,IAAI,EAAE,MAAM,eAAe,MAAM,UAAU,EAAE;EACnF,IAAI,MAAM;EACV,MAAM,MAAM;EACZ,MAAM,MAAM;EACZ,MAAM,QAAQ,QAAQ,KAAK;EAC3B,eAAe,QAAQ,iBAAiB,KAAK;EAC7C,MAAM,MAAM,SAAS;EACrB,YAAY,MAAM,SAAS,MAAM;EACjC,MACE,SAAS,OACL,OACA;GACE,QAAQ,KAAK;GACb,YAAY,KAAK;GACjB,YAAY,KAAK,cAAc;GAC/B,aAAa,KAAK,YAAY,KAAK,iBAAiB,QAAQ,KAAK,gBAAgB;GACjF,OAAO,KAAK;EACd;CACR;AACF;;AAGA,SAAgB,eACd,OACwE;CACxE,MAAM,EACJ,MAAM,OACN,eAAe,QACf,MAAM,OACN,GAAG,UACD,oBAAoB,OAAO;EAAE,eAAe;EAAM,wBAAwB;CAAM,CAAC;CACrF,OAAO;AACT;AAEA,SAAgB,gBACd,SACA,MACA,UACA,WACQ;CACR,OAAO,WAAW,QAAQ,CAAC,CACxB,OAAO,KAAK,UAAU;EAAE,SAAS;EAAG;EAAS;EAAM;EAAU;CAAU,CAAC,CAAC,CAAC,CAC1E,OAAO,KAAK;AACjB;;;AC1HA,MAAa,eAAe;AAC5B,MAAa,uBAAuB;AAEpC,eAAsB,WAAW,QAAgB;CAC/C,MAAM,YAAY,MAAM,cAAc,MAAM;CAC5C,MAAM,WAAW,KAAK,KAAK,KAAK,QAAQ,SAAS,GAAG,IAAI,KAAK,SAAS,SAAS,EAAE,cAAc;CAC/F,MAAM,MAAM,KAAK,QAAQ,QAAQ,GAAG,EAAE,WAAW,KAAK,CAAC;CACvD,IAAI;CACJ,IAAI;EACF,SAAS,MAAM,KAAK,UAAU,IAAI;CACpC,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAC9D,MAAM,IAAI,MACR,sCAAsC,SAAS,yHACjD;EACF,MAAM;CACR;CACA,IAAI;EACF,MAAM,OAAO,UAAU,KAAK,UAAU,EAAE,KAAK,QAAQ,IAAI,CAAC,CAAC;CAC7D,SAAS,OAAO;EACd,MAAM,OAAO,MAAM;EACnB,MAAM,GAAG,QAAQ;EACjB,MAAM;CACR;CACA,OAAO;EACL;EACA,MAAM,UAAU;GACd,MAAM,OAAO,MAAM;GACnB,MAAM,GAAG,QAAQ;EACnB;CACF;AACF;AAEA,eAAsB,cAAc,UAAmC;CACrE,IAAI;EACF,OAAO,MAAM,SAAS,QAAQ;CAChC,SAAS,OAAO;EACd,IAAI,EAAE,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,WAAW,MAAM;EACnF,MAAM,SAAS,KAAK,QAAQ,QAAQ;EACpC,IAAI,WAAW,UAAU,MAAM;EAC/B,OAAO,KAAK,KAAK,MAAM,cAAc,MAAM,GAAG,KAAK,SAAS,QAAQ,CAAC;CACvE;AACF;;AAGA,eAAsB,YACpB,QACA,QACA,SAA8B,SACZ;CAClB,IAAI,WAAW,WAAW,WAAW,WACnC,MAAM,IAAI,UAAU,uCAAuC;CAC7D,IAAI,aAAa,MAAM,cAAc,MAAM,GAAG,MAAM,SAAS,MAAM,CAAC,GAClE,MAAM,IAAI,MAAM,0CAA0C;CAC5D,IAAI;CACJ,IAAI;EACF,OAAO,MAAM,MAAM,MAAM;CAC3B,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAAU,OAAO;EACjF,MAAM;CACR;CACA,IAAI,KAAK,eAAe,KAAK,CAAC,KAAK,YAAY,GAC7C,MAAM,IAAI,MAAM,sDAAsD;CACxE,KAAK,MAAM,QAAQ,MAAM,EAAA,CAAG,WAAW,KAAK,WAAW,WAAW,OAAO;CACzE,IAAI;EACF,MAAM,SAAS,KAAK,KAAK,QAAQ,YAAY;EAC7C,IACE,EAAE,MAAM,MAAM,KAAK,QAAQ,MAAM,CAAC,EAAA,CAAG,eAAe,KACpD,EAAE,MAAM,MAAM,MAAM,EAAA,CAAG,eAAe,KACrC,MAAM,SAAS,QAAQ,MAAM,MAAA,iDAE9B,OAAO;CACX,SAAS,OAAO;EACd,IAAI,EAAE,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,WAAW,MAAM;CACrF;CACA,MAAM,IAAI,MACR,6IACF;AACF;;AAGA,eAAsB,cACpB,QACA,QACA,QACA,SAA8B,SACf;CACf,MAAM,SAAS,MAAM,YAAY,QAAQ,QAAQ,MAAM;CACvD,MAAM,MAAM,KAAK,QAAQ,MAAM,GAAG,EAAE,WAAW,KAAK,CAAC;CACrD,MAAM,SAAS,KAAK,KAClB,KAAK,QAAQ,MAAM,GACnB,IAAI,KAAK,SAAS,MAAM,EAAE,YAAY,WAAW,GACnD;CACA,IAAI,QAAQ,MAAM,OAAO,QAAQ,MAAM;CACvC,IAAI;EACF,MAAM,OAAO,QAAQ,MAAM;CAC7B,SAAS,OAAO;EACd,IAAI,QACF,IAAI;GACF,MAAM,OAAO,QAAQ,MAAM;EAC7B,SAAS,cAAc;GACrB,MAAM,IAAI,eACR,CAAC,OAAO,YAAY,GACpB,sDAAsD,QACxD;EACF;EAEF,MAAM;CACR;CACA,IAAI,QAAQ,MAAM,GAAG,QAAQ;EAAE,WAAW;EAAM,OAAO;CAAK,CAAC;AAC/D;;;ACtEA,MAAM,eAAe;AAErB,MAAM,cAAc;CAClB,WAAW;CACX,kBAAkB;CAClB,OAAO;CACP,UAAU;AACZ;AAEA,MAAa,qBAAyC,EAAE,cACtD,QAAQ,MAAM,UAAU,MAAM,SAAS,UAAU,aAAa,KAAK,MAAM,IAAI,CAAC,IAC1E,QAAQ,MAAM,UAAU,MAAM,KAAK,YAAY,MAAM,eAAe,IAClE,OACA,kBACF;AAEN,SAAS,qBAAqB,MAAoB;CAChD,IAAI,KAAK,WAAW,KAAK,KAAK,SAAS,IAAI,MAAM,QAAQ,SAAS,OAAO,SAAS,MAChF,MAAM,IAAI,MAAM,+CAA+C,MAAM;AAEzE;AAEA,SAAS,cAAc,OAAuB;CAC5C,IAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,GAAG,GAC3C,MAAM,IAAI,UAAU,kDAAkD;CAExE,IAAI,gBAAgB,KAAK,KAAK,GAAG;EAC/B,MAAM,MAAM,IAAI,IAAI,KAAK;EACzB,IAAI,WAAW,GAAG,IAAI,SAAS,QAAQ,QAAQ,EAAE,EAAE;EACnD,OAAO,IAAI;CACb;CACA,IAAI,CAAC,MAAM,WAAW,GAAG,GACvB,MAAM,IAAI,UAAU,0DAAwD;CAE9E,OAAO,GAAG,MAAM,QAAQ,QAAQ,EAAE,EAAE;AACtC;AAEA,SAAS,kBAAkB,OAAuB;CAChD,OAAO,MACJ,MAAM,GAAG,CAAC,CACV,QAAQ,YAAY,QAAQ,SAAS,CAAC,CAAC,CACvC,KAAK,YAAY,mBAAmB,OAAO,CAAC,CAAC,CAC7C,KAAK,GAAG;AACb;AAEA,SAAS,gBAAgB,OAAiC;CACxD,OAAO,MAAM,SAAS,eAAe,MAAM,SAAS,eAAe;AACrE;AAEA,SAAS,qBAAqB,OAAiC;CAC7D,OAAO,QACL,MAAM,SAAS,YAAY,MAAM,SAAS,iBAAiB,MAAM,SAAS,gBAC5E;AACF;AAEA,SAAS,eAAe,MAAc,OAAuB;CAC3D,MAAM,aAAa,CAAC,GAAG,IAAI;CAC3B,MAAM,cAAc,CAAC,GAAG,KAAK;CAC7B,MAAM,SAAS,KAAK,IAAI,WAAW,QAAQ,YAAY,MAAM;CAC7D,KAAK,IAAI,QAAQ,GAAG,QAAQ,QAAQ,SAAS,GAAG;EAC9C,MAAM,cACH,WAAW,MAAM,EAAE,YAAY,CAAC,KAAK,MAAM,YAAY,MAAM,EAAE,YAAY,CAAC,KAAK;EACpF,IAAI,eAAe,GAAG,OAAO;CAC/B;CACA,OAAO,WAAW,SAAS,YAAY;AACzC;AAEA,SAAS,aAAa,MAAc,OAAe,MAA4B;CAC7E,IAAI,SAAS,WAAW,OAAO,eAAe,MAAM,KAAK;CACzD,OAAO,KAAK,cAAc,OAAO,KAAA,GAAW;EAC1C,SAAS,SAAS;EAClB,aAAa;CACf,CAAC;AACH;AAEA,SAAgB,eACd,MACA,OACA,UAAuB,CAAC,GAChB;CACR,MAAM,WAAW;EAAE,GAAG;EAAa,GAAG;CAAQ;CAC9C,IAAI,SAAS,oBAAoB,gBAAgB,IAAI,MAAM,gBAAgB,KAAK,GAC9E,OAAO,gBAAgB,IAAI,IAAI,KAAK;CAEtC,IAAI;CACJ,IAAI,SAAS,UAAU,YACrB,SAAS,KAAK,SAAS,MAAM,WAAW,cAAc,MAAM,SAAS,MAAM,UAAU;MAChF,IAAI,SAAS,UAAU,QAC5B,UACG,KAAK,SAAS,cAAc,IAAI,KAAK,SAAS,SAC9C,MAAM,SAAS,cAAc,IAAI,MAAM,SAAS;MAEnD,SAAS,aAAa,KAAK,MAAM,MAAM,MAAM,SAAS,QAAQ;CAEhE,IAAI,WAAW,GAAG,SAAS,aAAa,KAAK,MAAM,MAAM,MAAM,SAAS,QAAQ;CAChF,OAAO,SAAS,cAAc,QAAQ,SAAS,CAAC;AAClD;AAEA,SAAS,gBAAgB,OAAgC;CACvD,OAAO,GAAG,WAAW,QAAQ,CAAC,CAC3B,OAAO,MAAM,YAAY,CAAC,CAC1B,OAAO,IAAI,CAAC,CACZ,OAAO,MAAM,SAAS,UAAU,EAAE,CAAC,CACnC,OAAO,KAAK,CAAC,CACb,MAAM,GAAG,EAAE,EAAE;AAClB;AAEA,eAAsB,iBAAiB,SAAgD;CACrF,OAAO,8BAA8B,SAAS,CAAC,CAAC;AAClD;;AAGA,eAAsB,8BACpB,SACA,cACsB;CACtB,wBAAwB,OAAO;CAC/B,MAAM,SAAS,KAAK,QAAQ,QAAQ,SAAS,GAC3C,SAAS,KAAK,QAAQ,QAAQ,SAAS;CACzC,MAAM,YAAY,QAAQ,QAAQ,QAAQ,YAAY;CACtD,IAAI,QAAQ,QAAQ,OAAO,yBAAyB,SAAS,YAAY;CACzE,MAAM,OAAO,MAAM,WAAW,MAAM;CACpC,MAAM,cAAc,KAAK,KAAK,KAAK,QAAQ,MAAM,GAAG,KAAK,SAAS,KAAK,QAAQ,CAAC;CAChF,IAAI;EACF,OAAO,MAAM,yBAAyB,SAAS;GAAC,GAAG;GAAc,KAAK;GAAU;EAAW,CAAC;CAC9F,UAAU;EACR,MAAM,KAAK,QAAQ;CACrB;AACF;AAEA,eAAe,yBACb,SACA,cACsB;CACtB,MAAM,YAAY,MAAM,SAAS,KAAK,QAAQ,QAAQ,SAAS,CAAC;CAChE,MAAM,YAAY,MAAM,cAAc,KAAK,QAAQ,QAAQ,SAAS,CAAC;CACrE,MAAM,qBAAqB,aAAa,KAAK,UAAU,KAAK,QAAQ,KAAK,CAAC;CAC1E,MAAM,eAAe,MAAM,SAAS,SAAS;CAC7C,MAAM,iBAAiB,MAAM,YAAY,WAAW,WAAW,QAAQ,YAAY;CACnF,MAAM,aAAa,QAAQ,cAAc;CACzC,MAAM,oBACJ,OAAO,eAAe,iBAAiB,aAAa;CACtD,MAAM,QAAuB,QAAQ;CACrC,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,UAAU,iCAAiC;CAC9E,MAAM,OAAO,QAAQ,QAAQ;CAC7B,MAAM,cAAc,QAAQ,eAAe;CAC3C,MAAM,OAAO,cAAc,QAAQ,QAAQ,GAAG;CAC9C,MAAM,iBAAiB,QAAQ,UAAU,UAAU;CACnD,MAAM,WAAW,QAAQ,UAAU,YAAY;CAC/C,MAAM,UAAU,QAAQ,UAAU,WAAW;CAC7C,MAAM,gBACJ,QAAQ,YAAY,KAAA,KACpB,QAAQ,YAAY,KAAA,MACnB,QAAQ,aAAa,UAAU,KAAK,KACrC,mBAAmB,SAAS;CAC9B,MAAM,QAID,CAAC;CACN,IAAI,aAAa,WAAW,SAAS,GACnC,MAAM,IAAI,MAAM,0CAA0C;CAE5D,IAAI;EACF,MAAM,MAAM,KAAK,KAAK,WAAW,WAAW,CAAC;EAC7C,MAAM,IAAI,MAAM,qDAAmD;CACrE,SAAS,OAAO;EACd,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAAU,CAE1E,OACE,MAAM;CAEV;CACA,MAAM,uBAAuB,aAAa,WAAW,SAAS;CAC9D,MAAM,YAAY,MAAM,kBACtB,WACA,WACA,QAAQ,SACR,QAAQ,SACR,oBACA,QAAQ,WACV;CACA,MAAM,cAAc,uBAAuB,KAAK,QAAQ,SAAS,IAAI,KAAK,QAAQ,SAAS;CAC3F,IAAI,CAAC,QAAQ,QAAQ,MAAM,MAAM,aAAa,EAAE,WAAW,KAAK,CAAC;CACjE,MAAM,kBAAkB,QAAQ,SAC5B,OACA,MAAM,QAAQ,KAAK,KAAK,aAAa,IAAI,KAAK,SAAS,SAAS,EAAE,UAAU,CAAC;CACjF,MAAM,iBAAiB;CAEvB,IAAI;EACF,IAAI,CAAC,QAAQ,WAAW,QAAQ,UAAU,OAAO;GAC/C,MAAM,GAAG,gBAAgB;IAAE,WAAW;IAAM,OAAO;GAAK,CAAC;GACzD,MAAM,MAAM,gBAAgB,EAAE,WAAW,KAAK,CAAC;GAC/C,MAAM,GAAG,WAAW,gBAAgB;IAClC,WAAW;IACX,aAAa;IACb,oBAAoB;IACpB,SAAS,eAAe;KACtB,MAAM,eAAe,KAAK,SAAS,WAAW,UAAU,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;KAClF,OACE,UAAU,SAAS,IAAI,YAAY,MAClC,CAAC,UAAU,SAAS,IAAI,YAAY,KAAK,UAAU,iBAAiB,IAAI,YAAY;IAEzF;GACF,CAAC;EACH;CACF,SAAS,OAAO;EACd,IAAI,oBAAoB,MAAM,MAAM,GAAG,iBAAiB;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;EACxF,MAAM;CACR;CAEA,eAAe,MACb,YACA,aACA,WACe;EACf,MAAM,mBAAmB,MAAM,SAAS,WAAW;EACnD,IAAI,UAAU,IAAI,gBAAgB,GAAG;GACnC,IAAI,YAAY,SAAS,MAAM,IAAI,MAAM,oBAAoB,YAAY;GACzE;EACF;EAEA,MAAM,gBAAgB,IAAI,IAAI,SAAS,CAAC,CAAC,IAAI,gBAAgB;EAC7D,MAAM,SAAS,MAAM,QAAQ,WAAW,EAAA,CAAG,QAAQ,SAAS;GAC1D,IAAI,wBAAwB,aAAa,WAAW,KAAK,KAAK,aAAa,IAAI,CAAC,GAC9E,OAAO;GACT,IAAI,mBAAmB,MAAM,UAAU,aAAa,OAAO,KAAK,KAAK,aAAa,IAAI,CAAC,CAAC,GACtF,OAAO;GACT,IAAI,CAAC,eAAe,OAAO;GAC3B,MAAM,eAAe,KAAK,SAAS,cAAc,KAAK,KAAK,kBAAkB,IAAI,CAAC;GAClF,OAAO,UAAU,SAAS,IAAI,aAAa,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG,CAAC;EACtE,CAAC;EACD,MAAM,UAAU,MAAM,QAAQ,IAC5B,MAAM,IAAI,OAAO,SAAS;GACxB,MAAM,QAAQ,MAAM,cAAc;IAChC,cAAc,KAAK,KAAK,aAAa,IAAI;IACzC,cAAc,KAAK,MAAM,KAAK,YAAY,IAAI;IAC9C;IACA,WAAW;IACX;IACA,eAAe,gBAAgB,UAAU,WAAW;GACtD,CAAC;GACD,OAAO,QAAQ,cAAc,KAAA,IACzB,QACA;IACE,GAAG;IACH,YAAY,eACV,MAAM,QAAQ,UAAU,eAAe,KAAK,GAAG;KAC7C,WAAW;KACX,eAAe;IACjB,CAAC,CACH;GACF;EACN,CAAC,CACH;EACA,QAAQ,MACL,MAAM,UACL,eAAe,MAAM,OAAO,QAAQ,IAAI,MACvC,QAAQ,YAAY,KAAA,IAAY,IAAI,eAAe,KAAK,cAAc,MAAM,YAAY,EAC7F;EAEA,MAAM,mBAAmB,MAAM,cAAc;GAC3C,cAAc;GACd,cAAc;GACd;GACA;GACA;GACA,eAAe,gBAAgB,UAAU,WAAW;EACtD,CAAC;EACD,IAAI,iBAAiB,SAAS,aAC5B,MAAM,IAAI,MAAM,GAAG,YAAY,oBAAoB;EAErD,MAAM,UAAoC;GACxC,GAAG;GACH,MAAM;EACR;EAsBA,MAAM,YAA2B;GAC/B,MAAA,MArBiB,cAAc;IAC/B,cAAc;IACd,cAAc;IACd;IACA,2BAAW,IAAI,IAAI;IACnB;IACA,eAAe,gBAAgB,UAAU,WAAW;GACtD,CAAC;GAeC;GACA,QAdA,eAAe,KACX,OACA,MAAM,cAAc;IAClB,cAAc,KAAK,QAAQ,WAAW;IACtC,cACE,KAAK,MAAM,QAAQ,UAAU,MAAM,MAAM,KAAK,KAAK,MAAM,QAAQ,UAAU;IAC7E;IACA;IACA;IACA,eAAe,gBAAgB,UAAU,WAAW;GACtD,CAAC;GAKL,OAAO,eAAe,KAAK,IAAI,WAAW,MAAM,GAAG,CAAC,CAAC;GACrD;EACF;EAEA,MAAM,OAAO,MAAM,kBAAkB,SAAS;EAC9C,IAAI,SAAS,MAAM,qBAAqB,IAAI;EAC5C,MAAM,KAAK;GAAE;GAAW;GAAY,YAAY;EAAK,CAAC;EAEtD,KAAK,MAAM,SAAS,SAAS;GAC3B,IAAI,MAAM,SAAS,aAAa;IAC9B,MAAM,MAAM,KAAK,MAAM,KAAK,YAAY,MAAM,IAAI,GAAG,MAAM,cAAc,aAAa;IACtF;GACF;GACA,IAAI,CAAC,kBAAkB,MAAM,SAAS,eAAe,aAAa;GAClE,MAAM,mBAAmB,KACtB,SAAS,cAAc,KAAK,KAAK,kBAAkB,MAAM,IAAI,CAAC,CAAC,CAC/D,MAAM,KAAK,GAAG,CAAC,CACf,KAAK,GAAG;GACX,KAAK,QAAQ,UAAU,SAAS,CAAC,UAAU,iBAAiB,IAAI,gBAAgB,GAAG;GACnF,IAAI,MAAM,QAAQ,SAAS;IACzB,IAAI,YAAY,SAAS,MAAM,IAAI,MAAM,oBAAoB,MAAM,cAAc;IACjF;GACF;GACA,IAAI,MAAM,QAAQ,iBAAiB,MAAM;GACzC,IAAI,aAAa,UAAU,MAAM,QAAQ,eAAe;GACxD,IACE,kBACC,MAAM,QAAQ,uBAAuB,QACpC,CAAC,UAAU,SAAS,IAAI,MAAM,QAAQ,kBAAkB,IAE1D;GAGF,KACG,QAAQ,UAAU,SACnB,MAAM,QAAQ,uBAAuB,QACrC,CAAC,MAAM,QAAQ,eAEf;GACF,MAAM,MACJ,KAAK,MAAM,KAAK,YAAY,MAAM,IAAI,GACtC,MAAM,QAAQ,cACd,aACF;EACF;CACF;CAEA,IAAI;EACF,MAAM,MAAM,IAAI,2BAAW,IAAI,IAAI,CAAC;EAEpC,MAAM,SAAsB;GAC1B;GACA;GACA,OAAO,MAAM;GACb,QAAQ,QAAQ,UAAU;GAC1B,QAAQ,QAAQ,UAAU;GAC1B;GACA,eAAe,CAAC,GAAG,UAAU,QAAQ,CAAC,CAAC,OAAO,OAAO,CAAC,CAAC,KAAK;GAC5D,OAAO,MAAM,KAAK,UAAU;IAAE,WAAW,KAAK;IAAY,YAAY,KAAK;GAAW,EAAE;EAC1F;EACA,IAAI,QAAQ,QAAQ,OAAO;EAE3B,MAAM,iBAAiB,IAAI,IACzB,MACG,QACE,SAAgE,KAAK,eAAe,IACvF,CAAC,CACA,KAAK,SAAS,CAAC,KAAK,YAAY,KAAK,UAAU,CAAC,CACrD;EACA,MAAM,uBAAuB,IAAI,IAAI,eAAe,KAAK,CAAC;EAC1D,MAAM,wBAAwB,gBAAgC;GAC5D,MAAM,WAAW,eAAe,IAAI,WAAW;GAC/C,OAAO,aAAa,KAAA,KAAa,aAAa,eAC1C,cACA,KAAK,MAAM,KAAK,aAAa,QAAQ;EAC3C;EACA,MAAM,8BAAc,IAAI,IAAoB;EAC5C,KAAK,MAAM,EAAE,eAAe,OAC1B,KAAK,MAAM,SAAS,UAAU,SAAS;GACrC,MAAM,aAAa,KAAK,SAAS,WAAW,MAAM,YAAY,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;GACxF,IAAI,UAAU,SAAS,IAAI,UAAU,GAAG,YAAY,IAAI,YAAY,MAAM,IAAI;EAChF;EACF,MAAM,mBAAmB,MAAM,QAAQ,WAAW;GAAE;GAAW;EAAY,CAAC;EAC5E,MAAM,+BAAe,IAAI,IAAiC;EAC1D,MAAM,+BAAe,IAAI,IAAoB;EAC7C,MAAM,gCAAgB,IAAI,IAiBxB;EAEF,MAAM,4BAAY,IAAI,IAA2B;EACjD,MAAM,kBAAkB,gBAAuC;GAC7D,IAAI,CAAC,UAAU,IAAI,WAAW,GAAG;IAC/B,MAAM,OAAO,QAAQ,SAAU,WAAW;IAC1C,IACE,SAAS,SACR,OAAO,SAAS,YACf,KAAK,WAAW,KAChB,KAAK,SAAS,IAAI,KAClB,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,cAAc,UAAU,WAAW,CAAC,IAAI,EAAE,KACjE,CAAC,CAAC,SAAS,QAAQ,CAAC,CAAC,SAAS,IAAI,IAAI,MAAM,0BAA0B,CAAC,CAAC,QAAQ,IAElF,MAAM,IAAI,UACR,oFACF;IACF,UAAU,IAAI,aAAa,IAAI;GACjC;GACA,OAAO,UAAU,IAAI,WAAW;EAClC;EAEA,KAAK,MAAM,EAAE,WAAW,gBAAgB,MAAM,gBAAgB,QAAQ,CAAC,IAAI,OACzE,KAAK,MAAM,SAAS,UAAU,SAAS;GACrC,IAAI,cAAc,IAAI,MAAM,YAAY,GAAG;GAC3C,MAAM,oBAAoB,qBAAqB,KAAK,IAChD,OACA,MAAM,SAAS,uBAAuB,QAAQ,MAAM,YAAY,OAC9D,MAAM,QAAQ,qBACd,KAAK,MAAM,KAAK,YAAY,MAAM,IAAI;GAC5C,MAAM,gBAAgB,gBAAgB,KAAK;GAC3C,MAAM,aACJ,iBAAiB,sBAAsB,OACnC,qBAAqB,iBAAiB,IACtC;GACN,IAAI,OAAsB;GAC1B,IAAI,MAAM,YAAY,QAAQ,qBAAqB,KAAK,GAAG;IACzD,MAAM,WAAW,gBAAgB,KAAK;IACtC,aAAa,IAAI,UAAU,MAAM,QAAQ,MAAM;IAC/C,OAAO,aAAa;GACtB,OAAO,IAAI,eAAe,MAAM;IAC9B,OACE,eAAe,KACX,QACA,MAAM,kBAAkB,UAAU,IAAI,iBAAiB,eAAe,oBAAoB,MAAM;IACtG,IAAI,CAAC,iBAAiB,QAAQ,aAAa,KAAA,GAAW,OAAO,eAAe,UAAU;GACxF;GACA,cAAc,IAAI,MAAM,cAAc;IACpC,eACE,qBAAqB,KAAK,KACzB,sBAAsB,SACpB,CAAC,iBAAiB,CAAC,qBAAqB,IAAI,iBAAiB;IAClE;IACA,QAAQ,MAAM,SAAS;IACvB,MAAM,MAAM;IACZ,YAAY,MAAM,SAAS,MAAM;IACjC,MAAM,MAAM;IACZ,MAAM,MAAM;IACZ,MAAM,MAAM,SAAS;IACrB,QAAQ,MAAM,SAAS,UAAU;IACjC,YAAY,MAAM,SAAS,cAAc;IACzC,YAAY,MAAM,SAAS,cAAc;IACzC,qBAAqB,qBAAqB,KAAK;IAC/C,SAAS,MAAM,SAAS,WAAW;GACrC,CAAC;EACH;EAGF,KAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,EAAE,WAAW,YAAY,YAAY,SAAS;GACpD,MAAM,mBAAmB,IAAI,IAAI,UAAU,QAAQ,KAAK,UAAU,MAAM,KAAK,YAAY,CAAC,CAAC;GAC3F,IAAI,SAAS,MAAM;GAEnB,MAAM,wBAAwB,UAA0C;IACtE,IAAI,qBAAqB,KAAK,GAAG,OAAO;IACxC,IAAI,MAAM,SAAS,uBAAuB,QAAQ,MAAM,YAAY,MAClE,OAAO,MAAM,QAAQ;IAEvB,OAAO,KAAK,MAAM,KAAK,YAAY,MAAM,IAAI;GAC/C;GACA,MAAM,sBAAsB,YAAoB,kBAAmC;IACjF,MAAM,aAAa,gBAAgB,qBAAqB,UAAU,IAAI;IACtE,MAAM,kBAAkB,iBAAiB,eAAe;IACxD,IAAI,gBAAgB,YAWlB,OAAO,GAVgB,KAAK,MAAM,SAChC,eAAe,KAAK,MAAM,YAC1B,eAAe,KAAK,MAAM,UAEO,CAAC,CACjC,MAAM,GAAG,CAAC,CACV,KAAK,YACJ,YAAY,OAAO,YAAY,OAAO,UAAU,mBAAmB,OAAO,CAC5E,CAAC,CACA,KAAK,GACc,KAAK,MAAM,kBAAkB,MAAM;IAE3D,MAAM,gBAAgB,kBAAkB,UAAU;IAClD,IAAI,kBAAkB,IACpB,OAAO,gBAAgB,SAAS,OAAO;IAEzC,MAAM,SAAS,GAAG,gBAAgB,kBAAkB,MAAM;IAC1D,OAAO,gBAAgB,SAAS,GAAG,OAAO,WAAW;GACvD;GACA,MAAM,WAAW,UAA0C;IACzD,IAAI,MAAM,YAAY,QAAQ,qBAAqB,KAAK,GAAG;KACzD,MAAM,WAAW,gBAAgB,KAAK;KACtC,aAAa,IAAI,UAAU,MAAM,QAAQ,MAAM;KAC/C,OAAO,mBAAmB,KAAK,MAAM,KAAK,aAAa,aAAa,QAAQ,GAAG,KAAK;IACtF;IACA,MAAM,oBAAoB,qBAAqB,KAAK;IACpD,IAAI,sBAAsB,MAAM,OAAO;IACvC,MAAM,gBACJ,MAAM,SAAS,eAAe,MAAM,SAAS,eAAe;IAC9D,IAAI,CAAC,iBAAiB,QAAQ,aAAa,KAAA,GACzC,OAAO,eAAe,iBAAiB;IACzC,OAAO,mBAAmB,mBAAmB,aAAa;GAC5D;GACA,MAAM,cAA4B;IAChC,WAAW;IACX;IACA,kBAAkB,gBAAgB,cAAc,OAAO;IACvD,YAAY;IACZ;IACA,iBAAiB,mBACf,KAAK,MAAM,KAAK,aAAa,mBAAmB,GAChD,KACF;IACA,MAAM;KAAE,GAAG;KAAa,GAAG,QAAQ;IAAK;IACxC,YAAY,cAAc;KACxB,qBAAqB,SAAS;KAC9B,OAAO,mBACL,SAAS,QACL,KAAK,MAAM,KAAK,YAAY,SAAS,IACrC,KAAK,MAAM,KAAK,aAAa,SAAS,GAC1C,KACF;IACF;IACA;IACA,mBAAmB,iBAAiB,mBAAmB,cAAc,IAAI;IACzE,sBAAsB,iBAAiB,qBAAqB,IAAI,YAAY;IAC5E,mBAAmB,UAAU;KAC3B,IAAI,qBAAqB,KAAK,GAAG,OAAO;KACxC,MAAM,oBAAoB,qBAAqB,KAAK;KACpD,MAAM,gBACJ,MAAM,SAAS,eAAe,MAAM,SAAS,eAAe;KAC9D,OACE,sBAAsB,SACrB,CAAC,iBAAiB,CAAC,qBAAqB,IAAI,iBAAiB;IAElE;GACF;GACA,MAAM,YAAY,KAAK,KAAK,gBAAgB,UAAU;GACtD,MAAM,MAAM,WAAW,EAAE,WAAW,KAAK,CAAC;GAC1C,MAAM,OAAO,YAAY;GACzB,IAAI,WAAW;GACf,IAAI,eAAe;GACnB,IAAI,WAAW,KAAK,IAAI,GAAG,UAAU,QAAQ,MAAM;GACnD,IAAI,QAAQ,YAAY,KAAA,GAAW;IACjC,MAAM,UAAU,UAAU,QAAQ,KAAK,UAAU;KAC/C,MAAM,YAAY,oBAAoB,OAAO,WAAW;KACxD,OAAO,MAAM,cAAc,KAAA,IACvB,YACA;MACE,GAAG;MACH,cAAc,eACZ,MAAM,UAAU,WAAW;OACzB,MAAM,YAAY;OAClB,YAAY,YAAY;OACxB,WAAW,YAAY;OACvB,kBAAkB,YAAY;OAC9B,kBAAkB,YAAY;OAC9B,eAAe;MACjB,CAAC,CACH;KACF;IACN,CAAC;IACD,MAAM,YACJ,OAAO,QAAQ,YAAY,aACvB,QAAQ,QAAQ;KACd,eAAe;KACf,cAAc,QAAQ;KACtB,WAAW,OAAO,WAAW,KAAK,UAAU,OAAO,CAAC;KACpD;KACA,WAAW;KACX,oBAAoB,MAAM,SAAS,eAAe;IACpD,CAAC,IACD,QAAQ;IACd,oBAAoB,SAAS;IAC7B,IAAI,UAAU,KAAK,aAAa,SAAS;KACvC,IAAI,MAAM,SAAS,eAAe,MAChC,MAAM,IAAI,MAAM,SAAS,MAAM,KAAK,qCAAqC;KAC3E,WAAW,UAAU,KAAK;IAC5B;IACA,MAAM,cAAc,WAAW,QAAQ,CAAC,CAAC,OAAO,UAAU,CAAC,CAAC,OAAO,KAAK;IACxE,MAAM,oBAAoB,KAAK,MAAM,KAAK,aAAa,WAAW,WAAW;IAE7E,MAAM,WACJ,gBAAgB,aACZ,YAAY,kBAAkB,UAAU,IAAI,aAAa,MAAM,OAC/D;IAEN,eAAe,mBADM,KAAK,MAAM,KAAK,mBAAmB,eACX,GAAG,KAAK;IACrD,MAAM,SAAmD,CAAC;IAC1D,MAAM,YACJ,UAAU,KAAK,aAAa,WACxB,UAAU,KAAK,YACf,KAAK,IAAI,GAAG,QAAQ,MAAM;IAChC,WAAW,gBAAgB,SAAS,MAAM,UAAU,SAAS;IAC7D,MAAM,mBAAmB,KAAK,KAAK,gBAAgB,iBAAiB;IACpE,MAAM,MAAM,kBAAkB,EAAE,WAAW,KAAK,CAAC;IACjD,KAAK,IAAI,SAAS,GAAG,SAAS,QAAQ,UAAU,WAAW,GAAG,UAAU,WAAW;KACjF,MAAM,UAAU,QAAQ,MAAM,QAAQ,SAAS,SAAS;KACxD,MAAM,WAAW,GAAG,SAAS,GAAG,OAAO,OAAO;KAC9C,OAAO,KAAK;MAAE,MAAM;MAAU;MAAQ,OAAO,QAAQ;KAAO,CAAC;KAC7D,MAAM,UACJ,KAAK,KAAK,kBAAkB,QAAQ,GACpC,KAAK,UAAU;MAAE,SAAS;MAAG;MAAU;MAAQ,OAAO,QAAQ;MAAQ;KAAQ,CAAC,CACjF;IACF;IACA,MAAM,WAA4B;KAChC,SAAS;KACT;KACA,WAAW;KACX;KACA,OAAO,QAAQ;KACf;KACA;IACF;IACA,MAAM,UAAU,KAAK,KAAK,kBAAkB,eAAe,GAAG,KAAK,UAAU,QAAQ,CAAC;GACxF;GACA,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,KAAK,UAAU,QAAQ,SAAS,QAAQ,CAAC;GAC5E,MAAM,aAAa,kBAAkB,WAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,GAAG,EAAE;GAChG,MAAM,YAAY,MAAM,KAAK,EAAE,QAAQ,UAAU,IAAI,GAAG,UACtD,UAAU,IAAI,OAAO,GAAG,WAAW,GAAG,QAAQ,EAAE,MAClD;GACA,KAAK,MAAM,YAAY,UAAU,MAAM,CAAC,GACtC,IAAI,UAAU,QAAQ,MAAM,UAAU,MAAM,KAAK,YAAY,MAAM,SAAS,YAAY,CAAC,GACvF,MAAM,IAAI,MACR,6CAA6C,KAAK,MAAM,KAAK,YAAY,QAAQ,GACnF;GAEJ,MAAM,8BAAc,IAAI,IAAoB;GAC5C,KAAK,MAAM,CAAC,OAAO,aAAa,UAAU,QAAQ,GAAG;IACnD,MAAM,WAAW,KAAK,MAAM,KAAK,YAAY,QAAQ;IACrD,MAAM,WAAW,MAAM,kBAAkB,QACvC,YACC,eAAe,mBAAmB,YAAY,KAAK,GACpD,aAAa,eAAgB,aAAa,GAAG,WAAW,KAAK,KAAM,QACrE;IACA,MAAM,YAAY,WAChB,mBAAmB,KAAK,MAAM,KAAK,YAAY,UAAU,WAAW,IAAI,GAAG,KAAK;IAClF,MAAM,OAAO,MAAM,MAAM,OAAO;KAC9B,GAAG;KACH,GAAI,aAAa,KAAA,IAAY,CAAC,IAAI,EAAE,SAAS;KAC7C,YAAY;KACZ,WACE,QAAQ,YAAY,KAAA,IAChB,YACA;MACE,GAAG;MACH,SAAS,UAAU,QAAQ,MAAM,QAAQ,WAAW,QAAQ,KAAK,QAAQ;KAC3E;KACN,GAAI,QAAQ,YAAY,KAAA,IACpB,CAAC,IACD,EACE,SAAS;MACP;MACA;MACA,MAAM;OACJ,QAAQ,QAAQ;OAChB,OAAO;OACP,QAAQ,QAAQ;OAChB,OAAO,UAAU,QAAQ;OACzB,MAAM,SAAS,KAAK;OACpB,cAAc,UAAU,IAAI,OAAO,SAAS,QAAQ,CAAC;OACrD,UAAU,QAAQ,MAAM,YAAY,OAAO,SAAS,QAAQ,CAAC;MAC/D;KACF,EACF;IACN,CAAC;IACD,MAAM,UAAU,KAAK,KAAK,WAAW,QAAQ,GAAG,KAAK,IAAI;IACzD,KAAK,MAAM,CAAC,WAAW,aAAa,OAAO,QAAQ,KAAK,UAAU,CAAC,CAAC,GAAG;KACrE,qBAAqB,SAAS;KAC9B,KACG,QAAQ,YAAY,KAAA,KAAa,MAAM,SAAS,eAAe,SAChE,SAAS,SACT,iBAAiB,IAAI,UAAU,YAAY,CAAC,GAE5C,MAAM,IAAI,MAAM,4CAA4C,WAAW;KACzE,IACE,QAAQ,YAAY,KAAA,KACpB,UAAU,MAAM,aAAa,SAAS,YAAY,MAAM,UAAU,YAAY,CAAC,GAE/E,MAAM,IAAI,MAAM,4CAA4C,WAAW;KACzE,IAAI,QAAQ,YAAY,KAAA,KAAa,YAAY,GAAG;MAClD,MAAM,QAAQ,OAAO,KAAK,QAAQ;MAClC,MAAM,WAAW,YAAY,IAAI,SAAS;MAC1C,IAAI,aAAa,KAAA,KAAa,CAAC,SAAS,OAAO,KAAK,GAClD,MAAM,IAAI,MAAM,8CAA8C,WAAW;MAC3E,YAAY,IAAI,WAAW,KAAK;KAClC;KACA,IAAI,SAAS,OACX,MAAM,UAAU,KAAK,KAAK,WAAW,SAAS,GAAG,QAAQ;UACpD;MACL,MAAM,QAAQ,OAAO,KAAK,QAAQ;MAClC,MAAM,WAAW,aAAa,IAAI,SAAS;MAC3C,IAAI,aAAa,KAAA,KAAa,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,OAAO,KAAK,GAC/D,MAAM,IAAI,MAAM,2CAA2C,WAAW;MAExE,aAAa,IAAI,WAAW,KAAK;KACnC;IACF;GACF;EACF;EAEA,IAAI,SAAS,SAAS,aAAa,OAAO,GAAG;GAC3C,MAAM,iBAAiB,KAAK,KAAK,gBAAgB,WAAW;GAC5D,MAAM,MAAM,gBAAgB,EAAE,WAAW,KAAK,CAAC;GAC/C,KAAK,MAAM,CAAC,WAAW,aAAa,cAClC,MAAM,UAAU,KAAK,KAAK,gBAAgB,SAAS,GAAG,QAAQ;EAElE;EAEA,KAAK,MAAM,CAAC,UAAU,UAAU,kBAAkB,UAAU,CAAC,GAAG;GAC9D,MAAM,QAAQ,SAAS,MAAM,GAAG;GAChC,KAAK,IAAI,QAAQ,GAAG,SAAS,MAAM,QAAQ,SAAS;IAClD,MAAM,SAAS,MAAM,MAAM,GAAG,KAAK,CAAC,CAAC,KAAK,GAAG;IAC7C,IAAI,UAAU,SAAS,IAAI,MAAM,GAC/B,MAAM,IAAI,MAAM,+CAA+C,UAAU;IAC3E,MAAM,YAAY,KAAK,KAAK,gBAAgB,MAAM;IAClD,IAAI;KACF,MAAM,OAAO,MAAM,MAAM,SAAS;KAClC,IAAI,KAAK,eAAe,KAAK,UAAU,MAAM,UAAU,CAAC,KAAK,YAAY,GACvE,MAAM,IAAI,MAAM,mDAAmD,UAAU;IACjF,SAAS,OAAO;KACd,IAAI,EAAE,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,WAAW,MAAM;IACrF;GACF;GACA,MAAM,cAAc,KAAK,KAAK,gBAAgB,QAAQ;GACtD,MAAM,MAAM,KAAK,QAAQ,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;GAC1D,MAAM,UAAU,aAAa,KAAK;EACpC;EAEA,IAAI,aAAa,OAAO,GAAG;GACzB,MAAM,mBAAmB,KAAK,KAAK,gBAAgB,aAAa,WAAW;GAC3E,MAAM,MAAM,kBAAkB,EAAE,WAAW,KAAK,CAAC;GACjD,KAAK,MAAM,CAAC,UAAU,WAAW,cAC/B,MAAM,UAAU,KAAK,KAAK,kBAAkB,QAAQ,GAAG,MAAM;EAEjE;EACA,IAAI,MAAM,gBAAgB,OAAO;GAC/B,MAAM,0BAA0B,KAAK,KAAK,gBAAgB,WAAW;GACrE,MAAM,MAAM,yBAAyB,EAAE,WAAW,KAAK,CAAC;GACxD,MAAM,iBAAiB,CAAC,GAAG,cAAc,OAAO,CAAC;GACjD,MAAM,SAAmB,CAAC;GAC1B,KAAK,IAAI,SAAS,GAAG,SAAS,eAAe,QAAQ,UAAU,KAAK;IAClE,MAAM,WAAW,UAAU,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,GAAG,GAAG,EAAE;IAClE,OAAO,KAAK,QAAQ;IACpB,MAAM,UACJ,KAAK,KAAK,yBAAyB,QAAQ,GAC3C,KAAK,UAAU,EAAE,SAAS,eAAe,MAAM,QAAQ,SAAS,GAAG,EAAE,CAAC,CACxE;GACF;GACA,MAAM,UACJ,KAAK,KAAK,yBAAyB,mBAAmB,GACtD,KAAK,UAAU;IAAE,OAAO,eAAe;IAAQ;IAAQ,SAAS;GAAE,CAAC,CACrE;EACF;EAEA,MAAM,MAAM,KAAK,KAAK,gBAAgB,WAAW,GAAG,EAAE,WAAW,KAAK,CAAC;EACvE,MAAM,UAAU,KAAK,KAAK,gBAAgB,YAAY,GAAG,oBAAoB;EAC7E,MAAM,cAAc,gBAAgB,WAAW,WAAW,QAAQ,YAAY;EAC9E,OAAO;CACT,UAAU;EACR,IAAI,oBAAoB,MAAM,MAAM,GAAG,iBAAiB;GAAE,WAAW;GAAM,OAAO;EAAK,CAAC;CAC1F;AACF;AAEA,eAAsB,kBAAkB,UAAmC;CACzE,OAAO,SAAS,UAAU,MAAM;AAClC;;;;AC3zBA,SAAgB,WAAW,OAAuB;CAChD,OAAO,MACJ,WAAW,KAAK,OAAO,CAAC,CACxB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,KAAK,MAAM,CAAC,CACvB,WAAW,MAAK,QAAQ;AAC7B;;;;ACNA,SAAgB,oBACd,QACA,YACA,WAAW,QAAQ,UACV;CACT,IAAI,OAAO,UAAU,WAAW,KAAK,OAAO;CAC5C,IAAI,OAAO,WAAW,WAAW,KAAK,OAAO;CAC7C,OAAO,aAAa,WAAW,OAAO,WAAW,KAAK,OAAO,UAAU;AACzE;;;ACmCA,IAAa,uBAAb,cAA0C,MAAM;CAC9C,OAAyB;AAC3B;AACA,SAAS,kBAAkB,OAAqB;CAC9C,IACE,MAAM,WAAW,GAAG,KACpB,MAAM,SAAS,IAAI,KACnB,MAAM,SAAS,IAAI,KACnB,MACG,MAAM,GAAG,CAAC,CACV,MAAM,YAAY,YAAY,OAAO,YAAY,QAAS,YAAY,MAAM,UAAU,EAAG,KAC5F,WAAW,KAAK,KAAK,KACrB,UAAU,eACV,MAAM,WAAW,YAAY,GAE7B,MAAM,IAAI,qBAAqB,kBAAkB;AACrD;;AAEA,eAAsB,uBACpB,SAC2B;CAC3B,yBAAyB,OAAO;CAChC,MAAM,OAAO,MAAM,SAAS,QAAQ,IAAI;CACxC,MAAM,cAAc,mBAAmB,QAAQ,WAAW;CAE1D,MAAM,oBAAoB,WAAW;CACrC,sBAAsB,QAAQ,SAAS,SAAS;CAChD,sBAAsB,QAAQ,SAAS,SAAS;CAChD,MAAM,WAAW,YAAY;EAC3B,MAAM,UAAU,MAAM,oBAAoB,WAAW;EACrD,IACE,sBAAsB,QAAQ,SAAS,SAAS,CAAC,CAAC,WAAW,KAC7D,sBAAsB,QAAQ,SAAS,SAAS,CAAC,CAAC,WAAW,KAC7D,CAAC,QAAQ,UAET,OAAO;EACT,QACE,MAAM,kBACJ,MACA,KAAK,KAAK,MAAM,WAAW,GAC3B,QAAQ,SACR,QAAQ,SACR,CAAC,GACD,aACA,OACF,EAAA,CACA;CACJ;CACA,eAAe,SACb,aACA,WAC0B;EAC1B,kBAAkB,WAAW;EAC7B,IAAI,cAAc,QAAQ,CAAC,UAAU,IAAI,WAAW,GAClD,MAAM,IAAI,qBAAqB,kBAAkB;EACnD,MAAM,eAAe,KAAK,KAAK,MAAM,WAAW;EAChD,MAAM,SAAS,gBAAgB,KAAK,OAAO,MAAM,SAAS,KAAK,QAAQ,YAAY,CAAC;EACpF,IAAI,CAAC,aAAa,MAAM,MAAM,GAAG,MAAM,IAAI,qBAAqB,kBAAkB;EAClF,MAAM,4BAAY,IAAI,IAAY,CAAC,IAAI,CAAC;EACxC,IAAI,gBAAgB,IAAI;GACtB,MAAM,WAAW,YAAY,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,EAAE;GACnD,KAAK,IAAI,SAAS,GAAG,UAAU,SAAS,QAAQ,UAC9C,UAAU,IAAI,MAAM,SAAS,KAAK,KAAK,MAAM,GAAG,SAAS,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC;EAC/E;EACA,OAAO,cAAc;GACnB;GACA,cAAc;GACd,cAAc;GACd;GACA,gBAAgB;GAChB,eAAe;EACjB,CAAC;CACH;CACA,OAAO;EACL,MAAM,KAAK,QAAQ;GACjB,IACE,CAAC,UACD,CAAC,OAAO,cAAc,OAAO,UAAU,KACvC,OAAO,aAAa,KACpB,CAAC,OAAO,cAAc,OAAO,cAAc,KAC3C,OAAO,iBAAiB,KACxB,EAAE,OAAO,kBAAkB,gBAC3B,OAAO,OAAO,cAAc,YAE5B,MAAM,IAAI,UACR,6EACF;GACF,MAAM,aACJ,MAAM,kBACJ,MACA,KAAK,KAAK,MAAM,WAAW,GAC3B,QAAQ,SACR,QAAQ,SACR,CAAC,GACD,aACA,KAAA,GACA,MACF,EAAA,CACA;GACF,MAAM,UAA6B,CAAC;GACpC,KAAK,MAAM,WAAW,CAAC,GAAG,SAAS,CAAC,CAAC,KAAK,GAAG;IAC3C,OAAO,OAAO,eAAe;IAC7B,IAAI,CAAC,SAAS;IACd,IAAI;KACF,MAAM,QAAQ,MAAM,SAAS,SAAS,SAAS;KAE/C,IAAI,MAAM,SAAS,UAAU,MAAM,SAAS,aAAa,QAAQ,KAAK,KAAK;IAC7E,SAAS,OAAO;KACd,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAAU;KAC1E,MAAM;IACR;GACF;GACA,OAAO;EACT;EACA,MAAM,YAAY,aAAa;GAC7B,MAAM,YAAY,MAAM,SAAS;GACjC,MAAM,QAAQ,MAAM,SAAS,aAAa,SAAS;GACnD,IACE,MAAM,YACL,MAAM,QAAQ,YAAY,MAAM,QAAQ,iBAAiB,MAAM,QAAQ,mBAExE,MAAM,IAAI,qBAAqB,oBAAoB;GACrD,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY;GAClD,IAAI,CAAC,aAAa,MAAM,QAAQ,GAAG,MAAM,IAAI,qBAAqB,oBAAoB;GACtF,MAAM,YAAY,KAAK,SAAS,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;GACxE,IAAI,cAAc,QAAQ,CAAC,UAAU,IAAI,SAAS,GAChD,MAAM,IAAI,qBAAqB,oBAAoB;GACrD,OAAO;EACT;EACA,MAAM,SAAS,aAAa;GAC1B,kBAAkB,WAAW;GAC7B,MAAM,YAAY,MAAM,SAAS;GACjC,IAAI,QAAQ,MAAM,SAAS,aAAa,SAAS;GACjD,IAAI,MAAM,YAAY,MAAM;IAC1B,IACE,MAAM,QAAQ,YACd,MAAM,QAAQ,iBACd,MAAM,QAAQ,oBACd,MAAM,QAAQ,uBAAuB,MAErC,MAAM,IAAI,qBAAqB,kBAAkB;IACnD,QAAQ,MAAM,SAAS,MAAM,QAAQ,oBAAoB,SAAS;GACpE;GACA,IAAI,MAAM,SAAS,QAAQ,MAAM,IAAI,qBAAqB,kBAAkB;GAC5E,MAAM,SAAS,MAAM,KACnB,MAAM,cACN,UAAU,YAAY,UAAU,cAAc,EAChD;GACA,IAAI;IACF,MAAM,QAAQ,MAAM,OAAO,KAAK;IAChC,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY;IAClD,IACE,CAAC,MAAM,OAAO,KACd,CAAC,aAAa,MAAM,QAAQ,KAC5B,CAAC,oBAAoB,MAAM,UAAU,KAAK,GAE1C,MAAM,IAAI,qBAAqB,6BAA6B;IAC9D,OAAO;KACL;KACA;KACA,eAAe,KAAK,SAAS,MAAM,QAAQ,CAAC,CAAC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,GAAG;IACvE;GACF,SAAS,OAAO;IACd,MAAM,OAAO,MAAM;IACnB,MAAM;GACR;EACF;EACA,MAAM,SAAS,aAAa;GAC1B,kBAAkB,WAAW;GAC7B,OAAO,SAAS,aAAa,MAAM,SAAS,CAAC;EAC/C;EACA,MAAM,cAAc,aAAa;GAC/B,kBAAkB,WAAW;GAC7B,MAAM,YAAY,MAAM,SAAS;GACjC,MAAM,QAAQ,MAAM,SAAS,aAAa,SAAS;GACnD,IAAI,MAAM,SAAS,aAAa,MAAM,IAAI,qBAAqB,uBAAuB;GACtF,MAAM,WAAW,MAAM,SAAS,MAAM,YAAY;GAClD,IAAI,CAAC,aAAa,MAAM,QAAQ,GAAG,MAAM,IAAI,qBAAqB,uBAAuB;GACzF,MAAM,SAAS,MAAM,QAAQ,QAAQ,EAAA,CAAG,QACrC,SAAS,gBAAgB,MAAM,SAAS,WAC3C;GA0BA,MAAM,WAAU,MAzBQ,QAAQ,IAC9B,MACG,QAAQ,SAAS,cAAc,QAAQ,UAAU,IAAI,KAAK,MAAM,KAAK,aAAa,IAAI,CAAC,CAAC,CAAC,CACzF,IAAI,OAAO,SAAS;IACnB,IAAI;IACJ,IAAI;KACF,QAAQ,MAAM,SAAS,KAAK,MAAM,KAAK,aAAa,IAAI,GAAG,SAAS;IACtE,SAAS,OAAO;KAEd,IAAI,iBAAiB,SAAS,UAAU,SAAS,MAAM,SAAS,UAAU,OAAO;KACjF,MAAM;IACR;IACA,OAAO,QAAQ,cAAc,KAAA,IACzB,QACA;KACE,GAAG;KACH,YAAY,eACV,MAAM,QAAQ,UAAU,eAAe,KAAK,GAAG;MAC7C,WAAW;MACX,eAAe;KACjB,CAAC,CACH;IACF;GACN,CAAC,CACL,EAAA,CAC0B,QAAQ,UAAoC,UAAU,IAAI;GACpF,QAAQ,MACL,MAAM,UACL,eAAe,MAAM,OAAO,QAAQ,IAAI,MACvC,KAAK,eAAe,MAAM,eACvB,KACA,KAAK,eAAe,MAAM,eACxB,IACA,EACV;GACA,OAAO;IACL,MAAM,MAAM,SAAS,IAAI,SAAS;IAClC,SAAS;KAAE,GAAG;KAAO,MAAM;IAAY;IACvC,QACE,gBAAgB,KACZ,OACA,MAAM,SACJ,KAAK,MAAM,QAAQ,WAAW,MAAM,MAAM,KAAK,KAAK,MAAM,QAAQ,WAAW,GAC7E,SACF;IACN,OAAO,gBAAgB,KAAK,IAAI,YAAY,MAAM,GAAG,CAAC,CAAC;IACvD;GACF;EACF;CACF;AACF"}
|
|
@@ -144,6 +144,8 @@ interface SortOptions {
|
|
|
144
144
|
interface ThemeContext {
|
|
145
145
|
readonly operation?: "build" | "server";
|
|
146
146
|
readonly updatesHref?: string;
|
|
147
|
+
readonly searchQueryHref?: string;
|
|
148
|
+
readonly searchRefreshIntervalMs?: number;
|
|
147
149
|
/** Optional host route for live framework page snapshots. */
|
|
148
150
|
readonly pageDataHref?: (theme: string, directoryPath: string, page: number) => string;
|
|
149
151
|
/** Present only when core listing publication is enabled. Entries are the current HTML slice. */
|
|
@@ -317,4 +319,4 @@ declare function entryDataFacts(entry: FileSystemEntry): Omit<ListingEntry, "hre
|
|
|
317
319
|
declare function listingRevision(entries: readonly ListingEntry[], sort: Required<SortOptions>, hrefBase: string, blockSize: number): string;
|
|
318
320
|
//#endregion
|
|
319
321
|
export { SymlinkMetadata as A, ResolvedMetadataContext as B, MetadataProviderFactory as C, SortDirection as D, RenderedPage as E, MetadataImage as F, JsonObject as H, MetadataImageValue as I, MetadataOptions as L, ContentCounts as M, ImageSource as N, SortField as O, MetadataContext as P, MetadataValue as R, MetadataProvider as S, OutputNameResolver as T, JsonValue as U, ThemeMetadataDefaults as V, copyJsonObject as W, FileMetadata as _, ListingPage as a, GenerateOptions as b, ListingPolicyContext as c, projectListingEntry as d, BuildReport as f, ExplorerTheme as g, EntryKind as h, ListingManifest as i, ThemeContext as j, SortOptions as k, entryDataFacts as l, EntryDataProvider as m, ListingContext as n, ListingPlan as o, DirectoryData as p, ListingEntry as r, ListingPolicy as s, ListingBlock as t, listingRevision as u, FileSystemEntry as v, NameSortMode as w, IgnoreFile as x, FileTimes as y, PageMetadata as z };
|
|
320
|
-
//# sourceMappingURL=listing-
|
|
322
|
+
//# sourceMappingURL=listing-CG4b6tOt.d.mts.map
|