@dirwell/cli 0.0.2 → 0.0.3
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 +13 -3
- package/dist/bin.mjs +1 -1
- package/dist/index.d.mts +3 -2
- package/dist/index.mjs +1 -1
- package/dist/{src-BadHyOPx.mjs → src-CFuBl9jc.mjs} +14 -14
- package/dist/src-CFuBl9jc.mjs.map +1 -0
- package/package.json +4 -4
- package/dist/src-BadHyOPx.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -11,8 +11,8 @@ The CLI supports short theme names and automatic `dirwell.config.mjs` discovery.
|
|
|
11
11
|
## Open or publish a folder
|
|
12
12
|
|
|
13
13
|
```sh
|
|
14
|
-
npx @dirwell/cli@0.0.
|
|
15
|
-
npx @dirwell/cli@0.0.
|
|
14
|
+
npx @dirwell/cli@0.0.3 server ./files
|
|
15
|
+
npx @dirwell/cli@0.0.3 build ./files --out ./generated
|
|
16
16
|
```
|
|
17
17
|
|
|
18
18
|
No project, configuration file or global installation is required. Open the URL
|
|
@@ -42,7 +42,7 @@ Builds replace missing, empty or Dirwell-marked output directories. A nonempty u
|
|
|
42
42
|
For repeated project use, install the CLI and the theme you want:
|
|
43
43
|
|
|
44
44
|
```sh
|
|
45
|
-
npm install --save-dev @dirwell/cli@0.0.
|
|
45
|
+
npm install --save-dev @dirwell/cli@0.0.3 @dirwell/theme-ledger@0.0.3
|
|
46
46
|
npx dirwell server ./files --theme ledger
|
|
47
47
|
```
|
|
48
48
|
|
|
@@ -89,3 +89,13 @@ Mode-specific flags fail when used with the other mode. Legacy dev/daemon
|
|
|
89
89
|
commands are unsupported; the CLI does not silently translate them.
|
|
90
90
|
|
|
91
91
|
The 0.0.x API may evolve. Pin your qualified version and upgrade the official family together. See [support and verification](https://vp-tw.github.io/dirwell/support/) for host, browser and device boundaries.
|
|
92
|
+
|
|
93
|
+
## Directory URLs
|
|
94
|
+
|
|
95
|
+
Version 0.0.3 uses Core `routing: { directoryUrls: "explicit" }` by default
|
|
96
|
+
for every theme. Choose `slash` for directory-index hosts or `clean` for a
|
|
97
|
+
qualified extensionless host. Themes do not rewrite links. Existing source
|
|
98
|
+
homepages and download names are preserved; output conflicts fail. CLI config
|
|
99
|
+
puts routing at the top level, and `--directory-urls` overrides it.
|
|
100
|
+
See [directory URL guidance](https://vp-tw.github.io/dirwell/urls/) for output
|
|
101
|
+
placement, host requirements, native Plain file navigation and migration.
|
package/dist/bin.mjs
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -6,11 +6,12 @@ export declare function defineConfig<const T extends CliConfig>(config: T): T;
|
|
|
6
6
|
//#endregion
|
|
7
7
|
//#region src/index.d.ts
|
|
8
8
|
export interface CliConfig {
|
|
9
|
+
readonly routing?: GenerateOptions["routing"];
|
|
9
10
|
readonly ignoreFiles?: GenerateOptions["ignoreFiles"];
|
|
10
|
-
readonly build?: Omit<GenerateOptions, "sourceDir" | "outputDir" | "theme" | "listing">;
|
|
11
|
+
readonly build?: Omit<GenerateOptions, "sourceDir" | "outputDir" | "theme" | "listing" | "routing">;
|
|
11
12
|
readonly theme?: ExplorerTheme;
|
|
12
13
|
readonly listing?: ListingPolicy;
|
|
13
|
-
readonly server?: Omit<Parameters<typeof startExplorerServer>[0], "root" | "theme" | "listing">;
|
|
14
|
+
readonly server?: Omit<Parameters<typeof startExplorerServer>[0], "root" | "theme" | "listing" | "routing">;
|
|
14
15
|
}
|
|
15
16
|
/** Parse explicit commands; return server ownership to the caller for graceful shutdown. */
|
|
16
17
|
export declare function runCli(args: readonly string[], cwd?: string, log?: (value: string) => void): Promise<{
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as defineConfig, t as runCli } from "./src-
|
|
1
|
+
import { n as defineConfig, t as runCli } from "./src-CFuBl9jc.mjs";
|
|
2
2
|
export { defineConfig, runCli };
|
|
@@ -3,7 +3,7 @@ import { access, stat } from "node:fs/promises";
|
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
4
|
import { resolve } from "import-meta-resolve";
|
|
5
5
|
import { parseArgs } from "node:util";
|
|
6
|
-
import { generateExplorer, resolveIgnoreFiles } from "@dirwell/core";
|
|
6
|
+
import { directoryRoute, encodeLogicalPath, generateExplorer, resolveDirectoryUrls, resolveIgnoreFiles } from "@dirwell/core";
|
|
7
7
|
import { createPlainTheme } from "@dirwell/theme-plain";
|
|
8
8
|
import { startExplorerServer } from "@dirwell/server/node";
|
|
9
9
|
//#region src/config.ts
|
|
@@ -123,8 +123,10 @@ function validateCliConfig(value) {
|
|
|
123
123
|
"listing",
|
|
124
124
|
"build",
|
|
125
125
|
"server",
|
|
126
|
-
"ignoreFiles"
|
|
127
|
-
|
|
126
|
+
"ignoreFiles",
|
|
127
|
+
"routing"
|
|
128
|
+
].includes(key)) throw new TypeError(`Unsupported config key "${key}". Use { theme, routing, listing, build, server }; selection rules belong in build/server.`);
|
|
129
|
+
resolveDirectoryUrls(config.routing);
|
|
128
130
|
listing(config.listing, "listing");
|
|
129
131
|
resolveIgnoreFiles(config.ignoreFiles);
|
|
130
132
|
for (const mode of ["build", "server"]) {
|
|
@@ -223,7 +225,7 @@ Build options: --mode ssg|mpa, --urls relative|base|html-base, --base <path>
|
|
|
223
225
|
Build safety: --dry-run, --force (-f) replaces an unowned nonempty output.
|
|
224
226
|
Selection: --ignore-file <path> (repeatable), --no-ignore disables ignore files.
|
|
225
227
|
Server options: --host <host>, --port <port>, --mount <path>, --live
|
|
226
|
-
Both modes: --page-size <n>, --block-size <n>
|
|
228
|
+
Both modes: --directory-urls explicit|slash|clean, --page-size <n>, --block-size <n>
|
|
227
229
|
Live server reads on request. It does not build an output tree or require watch mode.
|
|
228
230
|
`;
|
|
229
231
|
const positive = (value, name) => {
|
|
@@ -288,6 +290,7 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
288
290
|
out: { type: "string" },
|
|
289
291
|
mode: { type: "string" },
|
|
290
292
|
urls: { type: "string" },
|
|
293
|
+
"directory-urls": { type: "string" },
|
|
291
294
|
base: { type: "string" },
|
|
292
295
|
host: { type: "string" },
|
|
293
296
|
port: { type: "string" },
|
|
@@ -342,19 +345,14 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
342
345
|
if (hasConfig) {
|
|
343
346
|
const module = await import(pathToFileURL(configPath).href);
|
|
344
347
|
if (typeof module.default !== "object" || module.default === null || Array.isArray(module.default)) throw new TypeError("Config must export an object");
|
|
345
|
-
for (const key of Object.keys(module.default)) if (![
|
|
346
|
-
"theme",
|
|
347
|
-
"listing",
|
|
348
|
-
"build",
|
|
349
|
-
"server",
|
|
350
|
-
"ignoreFiles"
|
|
351
|
-
].includes(key)) throw new TypeError(`Unsupported config key "${key}". Use { theme, listing, build, server }; selection rules belong in build/server.`);
|
|
352
348
|
if (typeof module.default.then === "function") throw new TypeError("Config must export a resolved object; use top-level await for async setup");
|
|
353
349
|
validateCliConfig(module.default);
|
|
354
350
|
config = module.default;
|
|
355
351
|
}
|
|
356
352
|
const theme = parsed.values.theme !== void 0 ? await loadTheme(parsed.values.theme, cwd) : config.theme === void 0 ? createPlainTheme() : config.theme;
|
|
357
353
|
assertTheme(theme);
|
|
354
|
+
const directoryUrls = resolveDirectoryUrls(parsed.values["directory-urls"] === void 0 ? config.routing : { directoryUrls: parsed.values["directory-urls"] });
|
|
355
|
+
const routing = { directoryUrls };
|
|
358
356
|
const pageSize = positive(parsed.values["page-size"], "page-size"), blockSize = positive(parsed.values["block-size"], "block-size");
|
|
359
357
|
const listing = pageSize !== void 0 || blockSize !== void 0 ? {
|
|
360
358
|
html: pageSize === void 0 ? { strategy: "all" } : {
|
|
@@ -385,6 +383,7 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
385
383
|
].includes(urlStrategy)) throw new TypeError("Unknown URL strategy");
|
|
386
384
|
const report = await generateExplorer({
|
|
387
385
|
...config.build,
|
|
386
|
+
routing,
|
|
388
387
|
sourceDir: root,
|
|
389
388
|
outputDir: path.resolve(cwd, parsed.values.out),
|
|
390
389
|
theme,
|
|
@@ -400,7 +399,7 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
400
399
|
else {
|
|
401
400
|
log(`Built ${parsed.values.out}`);
|
|
402
401
|
log(`${report.selectedPaths.length} selected paths; ${report.pages.filter((page) => page.outputName !== null).length} directory pages; ${report.pages.filter((page) => page.outputName === null).length} skipped pages.`);
|
|
403
|
-
for (const page of report.pages) if (page.directory === "" || page.outputName === null) log(page.outputName === null ? `Skipped explorer page: ${page.directory || "/"}` : `Explorer entry: ${path.join(report.outputDir, page.
|
|
402
|
+
for (const page of report.pages) if (page.directory === "" || page.outputName === null) log(page.outputName === null ? `Skipped explorer page: ${page.directory || "/"}` : `Explorer entry: ${path.join(report.outputDir, page.outputPath)} (public: ${page.publicPath || "/"})`);
|
|
404
403
|
}
|
|
405
404
|
return null;
|
|
406
405
|
}
|
|
@@ -408,6 +407,7 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
408
407
|
if (!Number.isSafeInteger(port) || port < 0 || port > 65535) throw new TypeError("port must be between 0 and 65535");
|
|
409
408
|
const server = await startExplorerServer({
|
|
410
409
|
...config.server,
|
|
410
|
+
routing,
|
|
411
411
|
...parsed.values.live ? { live: config.server?.live || {} } : {},
|
|
412
412
|
root,
|
|
413
413
|
theme,
|
|
@@ -419,10 +419,10 @@ async function runCli(args, cwd = process.cwd(), log = console.log) {
|
|
|
419
419
|
...parsed.values.host === void 0 ? {} : { host: parsed.values.host },
|
|
420
420
|
...parsed.values.mount === void 0 ? {} : { mountPath: parsed.values.mount }
|
|
421
421
|
});
|
|
422
|
-
log(`Dirwell server: ${server.url}${parsed.values.mount ?? config.server?.mountPath ?? ""}/browse
|
|
422
|
+
log(`Dirwell server: ${server.url}${parsed.values.mount ?? config.server?.mountPath ?? ""}/browse${directoryUrls === "clean" ? "" : "/"}${encodeLogicalPath(directoryRoute("", "index.html", directoryUrls).publicPath)}`);
|
|
423
423
|
return server;
|
|
424
424
|
}
|
|
425
425
|
//#endregion
|
|
426
426
|
export { defineConfig as n, runCli as t };
|
|
427
427
|
|
|
428
|
-
//# sourceMappingURL=src-
|
|
428
|
+
//# sourceMappingURL=src-CFuBl9jc.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"src-CFuBl9jc.mjs","names":["resolveModule"],"sources":["../src/config.ts","../src/index.ts"],"sourcesContent":["import type { CliConfig } from \"./index.ts\";\nimport { resolveIgnoreFiles, resolveDirectoryUrls } from \"@dirwell/core\";\n\ntype RecordValue = Record<string, unknown>;\nfunction object(value: unknown, name: string): RecordValue {\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n throw new TypeError(`${name} must be an object`);\n return value as RecordValue;\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}\nfunction keys(value: RecordValue, 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 config key \"${name}.${key}\".${suggestion ? ` Did you mean \"${name}.${suggestion}\"?` : ` Supported keys: ${allowed.join(\", \")}.`}`,\n );\n }\n}\nfunction scalar(value: unknown, type: \"string\" | \"boolean\" | \"number\" | \"function\", name: string) {\n if (\n value !== undefined &&\n (typeof value !== type || (type === \"number\" && !Number.isFinite(value)))\n )\n throw new TypeError(`${name} must be a ${type}`);\n}\nfunction patterns(value: unknown, name: string): void {\n if (\n value !== undefined &&\n typeof value !== \"string\" &&\n (!Array.isArray(value) || value.some((item) => typeof item !== \"string\"))\n )\n throw new TypeError(`${name} must be a string or an array of strings`);\n}\nfunction sort(value: unknown, name: string): void {\n if (value === undefined) return;\n const options = object(value, name);\n keys(options, [\"direction\", \"directoriesFirst\", \"field\", \"nameMode\"], name);\n scalar(options.directoriesFirst, \"boolean\", `${name}.directoriesFirst`);\n for (const [key, allowed] of Object.entries({\n direction: [\"asc\", \"desc\"],\n field: [\"name\", \"size\", \"modified\"],\n nameMode: [\"natural\", \"unicode\", \"locale\"],\n }))\n if (options[key] !== undefined && !allowed.includes(String(options[key])))\n throw new TypeError(`${name}.${key} must be one of ${allowed.join(\", \")}`);\n}\nfunction listing(value: unknown, name: string): void {\n if (value === undefined || typeof value === \"function\") return;\n const plan = object(value, name);\n keys(plan, [\"html\", \"data\"], name);\n for (const [key, sizedStrategy, sizeKey] of [\n [\"html\", \"paged\", \"pageSize\"],\n [\"data\", \"blocks\", \"blockSize\"],\n ] as const) {\n const strategy = object(plan[key], `${name}.${key}`);\n keys(\n strategy,\n strategy.strategy === sizedStrategy ? [\"strategy\", sizeKey] : [\"strategy\"],\n `${name}.${key}`,\n );\n if (strategy.strategy !== \"all\" && strategy.strategy !== sizedStrategy)\n throw new TypeError(`${name}.${key}.strategy must be all or ${sizedStrategy}`);\n if (\n strategy.strategy === sizedStrategy &&\n (!Number.isSafeInteger(strategy[sizeKey]) || Number(strategy[sizeKey]) < 1)\n )\n throw new TypeError(`${name}.${key}.${sizeKey} must be a positive integer`);\n }\n}\nconst buildKeys = {\n fileHref: true,\n entryData: true,\n dryRun: true,\n outputPolicy: true,\n ignoreFiles: true,\n metadata: true,\n base: true,\n include: true,\n exclude: true,\n mode: true,\n mirror: true,\n outputName: true,\n urlStrategy: true,\n symlinks: true,\n sort: true,\n} satisfies Record<keyof NonNullable<CliConfig[\"build\"]>, true>;\nconst serverKeys = {\n entryData: true,\n ignoreFiles: true,\n live: true,\n search: true,\n blockSize: true,\n mountPath: true,\n files: true,\n pageSize: true,\n maxPageSize: true,\n fileHref: true,\n headers: true,\n authorize: true,\n include: true,\n exclude: true,\n sort: true,\n host: true,\n port: true,\n} satisfies Record<keyof NonNullable<CliConfig[\"server\"]>, true>;\n\n/** Validate both modes before filesystem publication or server startup. */\nexport function validateCliConfig(value: unknown): asserts value is CliConfig {\n const config = object(value, \"Config\");\n // Preserve the top-level diagnostic used by CLI consumers.\n for (const key of Object.keys(config))\n if (![\"theme\", \"listing\", \"build\", \"server\", \"ignoreFiles\", \"routing\"].includes(key))\n throw new TypeError(\n `Unsupported config key \"${key}\". Use { theme, routing, listing, build, server }; selection rules belong in build/server.`,\n );\n resolveDirectoryUrls(config.routing);\n listing(config.listing, \"listing\");\n resolveIgnoreFiles(config.ignoreFiles as CliConfig[\"ignoreFiles\"]);\n for (const mode of [\"build\", \"server\"] as const) {\n if (config[mode] === undefined) continue;\n const options = object(config[mode], mode);\n keys(options, Object.keys(mode === \"build\" ? buildKeys : serverKeys), mode);\n patterns(options.include, `${mode}.include`);\n patterns(options.exclude, `${mode}.exclude`);\n resolveIgnoreFiles(options.ignoreFiles as CliConfig[\"ignoreFiles\"]);\n sort(options.sort, `${mode}.sort`);\n scalar(options.entryData, \"function\", `${mode}.entryData`);\n if (mode === \"build\") {\n scalar(options.fileHref, \"function\", \"build.fileHref\");\n for (const key of [\"base\", \"mode\", \"urlStrategy\"])\n scalar(options[key], \"string\", `${mode}.${key}`);\n scalar(options.mirror, \"boolean\", \"build.mirror\");\n scalar(options.dryRun, \"boolean\", \"build.dryRun\");\n if (\n options.outputPolicy !== undefined &&\n options.outputPolicy !== \"owned\" &&\n options.outputPolicy !== \"replace\"\n )\n throw new TypeError(\"build.outputPolicy must be owned or replace\");\n scalar(options.metadata, \"function\", \"build.metadata\");\n if (\n options.outputName !== undefined &&\n typeof options.outputName !== \"string\" &&\n typeof options.outputName !== \"function\"\n )\n throw new TypeError(\"build.outputName must be a string or function\");\n if (options.symlinks !== undefined) {\n const links = object(options.symlinks, \"build.symlinks\");\n keys(links, [\"follow\", \"boundary\", \"onCycle\"], \"build.symlinks\");\n scalar(links.follow, \"boolean\", \"build.symlinks.follow\");\n for (const [key, allowed] of Object.entries({\n boundary: [\"root\", \"anywhere\"],\n onCycle: [\"error\", \"skip\"],\n }))\n if (links[key] !== undefined && !allowed.includes(String(links[key])))\n throw new TypeError(`build.symlinks.${key} must be one of ${allowed.join(\", \")}`);\n }\n } else {\n for (const key of [\"host\", \"mountPath\"]) scalar(options[key], \"string\", `server.${key}`);\n for (const key of [\"port\", \"pageSize\", \"maxPageSize\", \"blockSize\"])\n scalar(options[key], \"number\", `server.${key}`);\n for (const key of [\"fileHref\", \"headers\", \"authorize\"])\n scalar(options[key], \"function\", `server.${key}`);\n if (\n options.files !== undefined &&\n options.files !== false &&\n ![\"media\", \"attachment\", \"inline\"].includes(String(options.files))\n )\n throw new TypeError(\"server.files must be false, media, attachment or inline\");\n if (options.live !== undefined && options.live !== false) {\n const live = object(options.live, \"server.live\");\n keys(live, [\"intervalMs\", \"maxClients\"], \"server.live\");\n for (const key of [\"intervalMs\", \"maxClients\"])\n scalar(live[key], \"number\", `server.live.${key}`);\n }\n if (options.search !== undefined && options.search !== false) {\n const search = object(options.search, \"server.search\");\n keys(\n search,\n [\n \"maxEntries\",\n \"maxDirectories\",\n \"maxConcurrent\",\n \"maxResults\",\n \"timeoutMs\",\n \"refreshIntervalMs\",\n ],\n \"server.search\",\n );\n if (typeof search.maxResults === \"number\" && search.maxResults > 10000)\n throw new TypeError(\"server.search.maxResults must not exceed 10000\");\n for (const key of Object.keys(search)) {\n scalar(search[key], \"number\", `server.search.${key}`);\n if (\n !Number.isSafeInteger(search[key]) ||\n Number(search[key]) < (key === \"refreshIntervalMs\" ? 1000 : 1)\n )\n throw new TypeError(`server.search.${key} must be a positive safe integer`);\n }\n }\n }\n }\n}\n\n/** Preserve literal types and validate JavaScript configuration at definition time. */\nexport function defineConfig<const T extends CliConfig>(config: T): T {\n validateCliConfig(config);\n return config;\n}\n","import path from \"node:path\";\nimport { access, stat } from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { resolve as resolveModule } from \"import-meta-resolve\";\nimport { parseArgs } from \"node:util\";\nimport {\n generateExplorer,\n resolveIgnoreFiles,\n resolveDirectoryUrls,\n directoryRoute,\n encodeLogicalPath,\n} from \"@dirwell/core\";\nimport type { ExplorerTheme, ListingPolicy, GenerateOptions } from \"@dirwell/core\";\nimport { createPlainTheme } from \"@dirwell/theme-plain\";\nimport { startExplorerServer } from \"@dirwell/server/node\";\nimport { validateCliConfig } from \"./config.ts\";\nexport { defineConfig } from \"./config.ts\";\n\nexport interface CliConfig {\n readonly routing?: GenerateOptions[\"routing\"];\n readonly ignoreFiles?: GenerateOptions[\"ignoreFiles\"];\n readonly build?: Omit<\n GenerateOptions,\n \"sourceDir\" | \"outputDir\" | \"theme\" | \"listing\" | \"routing\"\n >;\n readonly theme?: ExplorerTheme;\n readonly listing?: ListingPolicy;\n readonly server?: Omit<\n Parameters<typeof startExplorerServer>[0],\n \"root\" | \"theme\" | \"listing\" | \"routing\"\n >;\n}\nconst help = `Usage:\n dirwell build <source> --out <output>\n dirwell server <source> [--port 3000]\n\nPlain is included and selected by default. Install other themes separately.\nOfficial themes: --theme plain|ledger|crosswave\nCustom themes: --theme <module>#<factory>, or a module's default export.\nReads dirwell.config.mjs in the working folder; --config <file.mjs> selects another file.\nConfig exports theme, listing, build options, and server hooks.\nBuild options: --mode ssg|mpa, --urls relative|base|html-base, --base <path>\nBuild safety: --dry-run, --force (-f) replaces an unowned nonempty output.\nSelection: --ignore-file <path> (repeatable), --no-ignore disables ignore files.\nServer options: --host <host>, --port <port>, --mount <path>, --live\nBoth modes: --directory-urls explicit|slash|clean, --page-size <n>, --block-size <n>\nLive server reads on request. It does not build an output tree or require watch mode.\n`;\nconst positive = (value: string | undefined, name: string): number | undefined => {\n if (value === undefined) return undefined;\n const number = Number(value);\n if (!Number.isSafeInteger(number) || number < 1)\n throw new TypeError(`${name} must be a positive integer`);\n return number;\n};\nfunction assertTheme(candidate: unknown): asserts candidate is ExplorerTheme {\n if (\n typeof candidate !== \"object\" ||\n candidate === null ||\n !(\"name\" in candidate) ||\n typeof candidate.name !== \"string\" ||\n !(\"render\" in candidate) ||\n typeof candidate.render !== \"function\"\n )\n throw new TypeError(\"Theme must be an object with name and render(context)\");\n}\nasync function loadTheme(specifier: string, cwd: string): Promise<ExplorerTheme> {\n const official: Record<string, string> = {\n plain: \"@dirwell/theme-plain#createPlainTheme\",\n ledger: \"@dirwell/theme-ledger#createLedgerTheme\",\n crosswave: \"@dirwell/theme-crosswave#createCrosswaveTheme\",\n };\n if (Object.hasOwn(official, specifier)) specifier = official[specifier]!;\n const delimiter = specifier.lastIndexOf(\"#\"),\n name = delimiter < 0 ? specifier : specifier.slice(0, delimiter),\n exported = delimiter < 0 ? \"default\" : specifier.slice(delimiter + 1);\n if (!name || !exported) throw new TypeError(\"Theme needs a module and export name\");\n let moduleUrl: string;\n if (name.startsWith(\".\") || path.isAbsolute(name)) {\n moduleUrl = pathToFileURL(path.resolve(cwd, name)).href;\n } else {\n try {\n moduleUrl = resolveModule(name, pathToFileURL(path.join(cwd, \"package.json\")).href);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ERR_MODULE_NOT_FOUND\"))\n throw error;\n // npm exec installs explicit --package entries beside the CLI, outside the user's folder.\n try {\n moduleUrl = resolveModule(name, import.meta.url);\n } catch (fallbackError) {\n if (\n fallbackError instanceof Error &&\n \"code\" in fallbackError &&\n fallbackError.code === \"ERR_MODULE_NOT_FOUND\"\n )\n throw new TypeError(\n `Theme package \"${name}\" was not found. Install it in your project or include it with npm exec --package=${name}.`,\n );\n throw fallbackError;\n }\n }\n }\n const module: Record<string, unknown> = await import(moduleUrl);\n const candidate =\n typeof module[exported] === \"function\" ? await module[exported]() : module[exported];\n assertTheme(candidate);\n return candidate;\n}\n/** Parse explicit commands; return server ownership to the caller for graceful shutdown. */\nexport async function runCli(\n args: readonly string[],\n cwd = process.cwd(),\n log: (value: string) => void = console.log,\n) {\n const parsed = parseArgs({\n args: [...args],\n allowPositionals: true,\n options: {\n help: { type: \"boolean\", short: \"h\" },\n force: { type: \"boolean\", short: \"f\" },\n \"dry-run\": { type: \"boolean\" },\n \"ignore-file\": { type: \"string\", multiple: true },\n \"no-ignore\": { type: \"boolean\" },\n live: { type: \"boolean\" },\n theme: { type: \"string\" },\n config: { type: \"string\" },\n out: { type: \"string\" },\n mode: { type: \"string\" },\n urls: { type: \"string\" },\n \"directory-urls\": { type: \"string\" },\n base: { type: \"string\" },\n host: { type: \"string\" },\n port: { type: \"string\" },\n mount: { type: \"string\" },\n \"page-size\": { type: \"string\" },\n \"block-size\": { type: \"string\" },\n },\n });\n if (parsed.values.help) {\n log(help);\n return null;\n }\n const [command, source] = parsed.positionals;\n if (\n ![\"build\", \"server\"].includes(command ?? \"\") ||\n source === undefined ||\n source === \"\" ||\n parsed.positionals.length !== 2\n )\n throw new TypeError(help);\n const otherModeOptions =\n command === \"build\"\n ? [\"host\", \"port\", \"mount\", \"live\"]\n : [\"out\", \"mode\", \"urls\", \"base\", \"force\", \"dry-run\"];\n for (const option of otherModeOptions)\n if (Object.hasOwn(parsed.values, option))\n throw new TypeError(`--${option} is not supported in ${command} mode`);\n let config: CliConfig = {};\n const configPath = path.resolve(cwd, parsed.values.config ?? \"dirwell.config.mjs\");\n let hasConfig = parsed.values.config !== undefined;\n if (!hasConfig) {\n try {\n await access(configPath);\n hasConfig = true;\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n if (!hasConfig) {\n for (const filename of [\n \"dirwell.config.ts\",\n \"dirwell.config.js\",\n \"dirwell.config.mts\",\n \"dirwell.config.cjs\",\n ]) {\n try {\n await access(path.resolve(cwd, filename));\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") continue;\n throw error;\n }\n throw new TypeError(\n `Found ${filename}. This CLI discovers dirwell.config.mjs only. Migrate the config or select a native JavaScript module with --config; existing rules will not be silently ignored.`,\n );\n }\n }\n if (hasConfig) {\n const module = await import(pathToFileURL(configPath).href);\n if (\n typeof module.default !== \"object\" ||\n module.default === null ||\n Array.isArray(module.default)\n )\n throw new TypeError(\"Config must export an object\");\n if (typeof module.default.then === \"function\")\n throw new TypeError(\n \"Config must export a resolved object; use top-level await for async setup\",\n );\n validateCliConfig(module.default);\n config = module.default;\n }\n const theme =\n parsed.values.theme !== undefined\n ? await loadTheme(parsed.values.theme, cwd)\n : config.theme === undefined\n ? createPlainTheme()\n : config.theme;\n assertTheme(theme);\n const directoryUrls = resolveDirectoryUrls(\n parsed.values[\"directory-urls\"] === undefined\n ? config.routing\n : { directoryUrls: parsed.values[\"directory-urls\"] },\n );\n const routing = { directoryUrls };\n const pageSize = positive(parsed.values[\"page-size\"], \"page-size\"),\n blockSize = positive(parsed.values[\"block-size\"], \"block-size\");\n const listing: ListingPolicy | undefined =\n pageSize !== undefined || blockSize !== undefined\n ? {\n html: pageSize === undefined ? { strategy: \"all\" } : { strategy: \"paged\", pageSize },\n data: blockSize === undefined ? { strategy: \"all\" } : { strategy: \"blocks\", blockSize },\n }\n : config.listing;\n const root = path.resolve(cwd, source);\n if (!(await stat(root)).isDirectory())\n throw new TypeError(\"Source must be an existing directory\");\n if (parsed.values[\"no-ignore\"] && parsed.values[\"ignore-file\"])\n throw new TypeError(\"--no-ignore cannot be combined with --ignore-file\");\n const modeOptions = command === \"build\" ? config.build : config.server;\n const ignoreFiles = resolveIgnoreFiles(\n parsed.values[\"no-ignore\"]\n ? []\n : (parsed.values[\"ignore-file\"] ??\n modeOptions?.ignoreFiles ??\n config.ignoreFiles ?? [{ path: \".gitignore\", optional: true }]),\n cwd,\n );\n if (command === \"build\") {\n if (parsed.values.out === undefined)\n throw new TypeError(\"Build requires --out pointing to a dedicated generated output tree\");\n const mode = parsed.values.mode ?? config.build?.mode ?? \"ssg\",\n urlStrategy = parsed.values.urls ?? config.build?.urlStrategy ?? \"relative\";\n if (mode !== \"ssg\" && mode !== \"mpa\") throw new TypeError(\"mode must be ssg or mpa\");\n if (![\"relative\", \"base\", \"html-base\"].includes(urlStrategy))\n throw new TypeError(\"Unknown URL strategy\");\n const report = await generateExplorer({\n ...config.build,\n routing,\n sourceDir: root,\n outputDir: path.resolve(cwd, parsed.values.out),\n theme,\n ignoreFiles,\n ...(parsed.values.force ? { outputPolicy: \"replace\" } : {}),\n ...(parsed.values[\"dry-run\"] ? { dryRun: true } : {}),\n mode,\n urlStrategy: urlStrategy as \"relative\" | \"base\" | \"html-base\",\n ...(parsed.values.base === undefined ? {} : { base: parsed.values.base }),\n ...(listing === undefined ? {} : { listing }),\n });\n if (report.dryRun) log(JSON.stringify(report, null, 2));\n else {\n log(`Built ${parsed.values.out}`);\n log(\n `${report.selectedPaths.length} selected paths; ${report.pages.filter((page) => page.outputName !== null).length} directory pages; ${report.pages.filter((page) => page.outputName === null).length} skipped pages.`,\n );\n for (const page of report.pages)\n if (page.directory === \"\" || page.outputName === null)\n log(\n page.outputName === null\n ? `Skipped explorer page: ${page.directory || \"/\"}`\n : `Explorer entry: ${path.join(report.outputDir, page.outputPath!)} (public: ${page.publicPath || \"/\"})`,\n );\n }\n return null;\n }\n const port = Number(parsed.values.port ?? process.env.PORT ?? config.server?.port ?? 0);\n if (!Number.isSafeInteger(port) || port < 0 || port > 65535)\n throw new TypeError(\"port must be between 0 and 65535\");\n const server = await startExplorerServer({\n ...config.server,\n routing,\n ...(parsed.values.live ? { live: config.server?.live || {} } : {}),\n root,\n theme,\n ignoreFiles,\n port,\n ...(listing === undefined ? {} : { listing }),\n ...(pageSize === undefined ? {} : { pageSize }),\n ...(blockSize === undefined ? {} : { blockSize }),\n ...(parsed.values.host === undefined ? {} : { host: parsed.values.host }),\n ...(parsed.values.mount === undefined ? {} : { mountPath: parsed.values.mount }),\n });\n log(\n `Dirwell server: ${server.url}${parsed.values.mount ?? config.server?.mountPath ?? \"\"}/browse${directoryUrls === \"clean\" ? \"\" : \"/\"}${encodeLogicalPath(directoryRoute(\"\", \"index.html\", directoryUrls).publicPath)}`,\n );\n return server;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dirwell/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"description": "Minimal file explorer build and live-server commands with Plain included.",
|
|
5
5
|
"homepage": "https://vp-tw.github.io/dirwell/getting-started/",
|
|
6
6
|
"bugs": {
|
|
@@ -33,9 +33,9 @@
|
|
|
33
33
|
"tag": "latest"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@dirwell/core": "0.0.
|
|
37
|
-
"@dirwell/server": "0.0.
|
|
38
|
-
"@dirwell/theme-plain": "0.0.
|
|
36
|
+
"@dirwell/core": "0.0.3",
|
|
37
|
+
"@dirwell/server": "0.0.3",
|
|
38
|
+
"@dirwell/theme-plain": "0.0.3",
|
|
39
39
|
"import-meta-resolve": "4.2.0"
|
|
40
40
|
},
|
|
41
41
|
"engines": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"src-BadHyOPx.mjs","names":["resolveModule"],"sources":["../src/config.ts","../src/index.ts"],"sourcesContent":["import type { CliConfig } from \"./index.ts\";\nimport { resolveIgnoreFiles } from \"@dirwell/core\";\n\ntype RecordValue = Record<string, unknown>;\nfunction object(value: unknown, name: string): RecordValue {\n if (typeof value !== \"object\" || value === null || Array.isArray(value))\n throw new TypeError(`${name} must be an object`);\n return value as RecordValue;\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}\nfunction keys(value: RecordValue, 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 config key \"${name}.${key}\".${suggestion ? ` Did you mean \"${name}.${suggestion}\"?` : ` Supported keys: ${allowed.join(\", \")}.`}`,\n );\n }\n}\nfunction scalar(value: unknown, type: \"string\" | \"boolean\" | \"number\" | \"function\", name: string) {\n if (\n value !== undefined &&\n (typeof value !== type || (type === \"number\" && !Number.isFinite(value)))\n )\n throw new TypeError(`${name} must be a ${type}`);\n}\nfunction patterns(value: unknown, name: string): void {\n if (\n value !== undefined &&\n typeof value !== \"string\" &&\n (!Array.isArray(value) || value.some((item) => typeof item !== \"string\"))\n )\n throw new TypeError(`${name} must be a string or an array of strings`);\n}\nfunction sort(value: unknown, name: string): void {\n if (value === undefined) return;\n const options = object(value, name);\n keys(options, [\"direction\", \"directoriesFirst\", \"field\", \"nameMode\"], name);\n scalar(options.directoriesFirst, \"boolean\", `${name}.directoriesFirst`);\n for (const [key, allowed] of Object.entries({\n direction: [\"asc\", \"desc\"],\n field: [\"name\", \"size\", \"modified\"],\n nameMode: [\"natural\", \"unicode\", \"locale\"],\n }))\n if (options[key] !== undefined && !allowed.includes(String(options[key])))\n throw new TypeError(`${name}.${key} must be one of ${allowed.join(\", \")}`);\n}\nfunction listing(value: unknown, name: string): void {\n if (value === undefined || typeof value === \"function\") return;\n const plan = object(value, name);\n keys(plan, [\"html\", \"data\"], name);\n for (const [key, sizedStrategy, sizeKey] of [\n [\"html\", \"paged\", \"pageSize\"],\n [\"data\", \"blocks\", \"blockSize\"],\n ] as const) {\n const strategy = object(plan[key], `${name}.${key}`);\n keys(\n strategy,\n strategy.strategy === sizedStrategy ? [\"strategy\", sizeKey] : [\"strategy\"],\n `${name}.${key}`,\n );\n if (strategy.strategy !== \"all\" && strategy.strategy !== sizedStrategy)\n throw new TypeError(`${name}.${key}.strategy must be all or ${sizedStrategy}`);\n if (\n strategy.strategy === sizedStrategy &&\n (!Number.isSafeInteger(strategy[sizeKey]) || Number(strategy[sizeKey]) < 1)\n )\n throw new TypeError(`${name}.${key}.${sizeKey} must be a positive integer`);\n }\n}\nconst buildKeys = {\n fileHref: true,\n entryData: true,\n dryRun: true,\n outputPolicy: true,\n ignoreFiles: true,\n metadata: true,\n base: true,\n include: true,\n exclude: true,\n mode: true,\n mirror: true,\n outputName: true,\n urlStrategy: true,\n symlinks: true,\n sort: true,\n} satisfies Record<keyof NonNullable<CliConfig[\"build\"]>, true>;\nconst serverKeys = {\n entryData: true,\n ignoreFiles: true,\n live: true,\n search: true,\n blockSize: true,\n mountPath: true,\n files: true,\n pageSize: true,\n maxPageSize: true,\n fileHref: true,\n headers: true,\n authorize: true,\n include: true,\n exclude: true,\n sort: true,\n host: true,\n port: true,\n} satisfies Record<keyof NonNullable<CliConfig[\"server\"]>, true>;\n\n/** Validate both modes before filesystem publication or server startup. */\nexport function validateCliConfig(value: unknown): asserts value is CliConfig {\n const config = object(value, \"Config\");\n // Preserve the top-level diagnostic used by CLI consumers.\n for (const key of Object.keys(config))\n if (![\"theme\", \"listing\", \"build\", \"server\", \"ignoreFiles\"].includes(key))\n throw new TypeError(\n `Unsupported config key \"${key}\". Use { theme, listing, build, server }; selection rules belong in build/server.`,\n );\n listing(config.listing, \"listing\");\n resolveIgnoreFiles(config.ignoreFiles as CliConfig[\"ignoreFiles\"]);\n for (const mode of [\"build\", \"server\"] as const) {\n if (config[mode] === undefined) continue;\n const options = object(config[mode], mode);\n keys(options, Object.keys(mode === \"build\" ? buildKeys : serverKeys), mode);\n patterns(options.include, `${mode}.include`);\n patterns(options.exclude, `${mode}.exclude`);\n resolveIgnoreFiles(options.ignoreFiles as CliConfig[\"ignoreFiles\"]);\n sort(options.sort, `${mode}.sort`);\n scalar(options.entryData, \"function\", `${mode}.entryData`);\n if (mode === \"build\") {\n scalar(options.fileHref, \"function\", \"build.fileHref\");\n for (const key of [\"base\", \"mode\", \"urlStrategy\"])\n scalar(options[key], \"string\", `${mode}.${key}`);\n scalar(options.mirror, \"boolean\", \"build.mirror\");\n scalar(options.dryRun, \"boolean\", \"build.dryRun\");\n if (\n options.outputPolicy !== undefined &&\n options.outputPolicy !== \"owned\" &&\n options.outputPolicy !== \"replace\"\n )\n throw new TypeError(\"build.outputPolicy must be owned or replace\");\n scalar(options.metadata, \"function\", \"build.metadata\");\n if (\n options.outputName !== undefined &&\n typeof options.outputName !== \"string\" &&\n typeof options.outputName !== \"function\"\n )\n throw new TypeError(\"build.outputName must be a string or function\");\n if (options.symlinks !== undefined) {\n const links = object(options.symlinks, \"build.symlinks\");\n keys(links, [\"follow\", \"boundary\", \"onCycle\"], \"build.symlinks\");\n scalar(links.follow, \"boolean\", \"build.symlinks.follow\");\n for (const [key, allowed] of Object.entries({\n boundary: [\"root\", \"anywhere\"],\n onCycle: [\"error\", \"skip\"],\n }))\n if (links[key] !== undefined && !allowed.includes(String(links[key])))\n throw new TypeError(`build.symlinks.${key} must be one of ${allowed.join(\", \")}`);\n }\n } else {\n for (const key of [\"host\", \"mountPath\"]) scalar(options[key], \"string\", `server.${key}`);\n for (const key of [\"port\", \"pageSize\", \"maxPageSize\", \"blockSize\"])\n scalar(options[key], \"number\", `server.${key}`);\n for (const key of [\"fileHref\", \"headers\", \"authorize\"])\n scalar(options[key], \"function\", `server.${key}`);\n if (\n options.files !== undefined &&\n options.files !== false &&\n ![\"media\", \"attachment\", \"inline\"].includes(String(options.files))\n )\n throw new TypeError(\"server.files must be false, media, attachment or inline\");\n if (options.live !== undefined && options.live !== false) {\n const live = object(options.live, \"server.live\");\n keys(live, [\"intervalMs\", \"maxClients\"], \"server.live\");\n for (const key of [\"intervalMs\", \"maxClients\"])\n scalar(live[key], \"number\", `server.live.${key}`);\n }\n if (options.search !== undefined && options.search !== false) {\n const search = object(options.search, \"server.search\");\n keys(\n search,\n [\n \"maxEntries\",\n \"maxDirectories\",\n \"maxConcurrent\",\n \"maxResults\",\n \"timeoutMs\",\n \"refreshIntervalMs\",\n ],\n \"server.search\",\n );\n if (typeof search.maxResults === \"number\" && search.maxResults > 10000)\n throw new TypeError(\"server.search.maxResults must not exceed 10000\");\n for (const key of Object.keys(search)) {\n scalar(search[key], \"number\", `server.search.${key}`);\n if (\n !Number.isSafeInteger(search[key]) ||\n Number(search[key]) < (key === \"refreshIntervalMs\" ? 1000 : 1)\n )\n throw new TypeError(`server.search.${key} must be a positive safe integer`);\n }\n }\n }\n }\n}\n\n/** Preserve literal types and validate JavaScript configuration at definition time. */\nexport function defineConfig<const T extends CliConfig>(config: T): T {\n validateCliConfig(config);\n return config;\n}\n","import path from \"node:path\";\nimport { access, stat } from \"node:fs/promises\";\nimport { pathToFileURL } from \"node:url\";\nimport { resolve as resolveModule } from \"import-meta-resolve\";\nimport { parseArgs } from \"node:util\";\nimport { generateExplorer, resolveIgnoreFiles } from \"@dirwell/core\";\nimport type { ExplorerTheme, ListingPolicy, GenerateOptions } from \"@dirwell/core\";\nimport { createPlainTheme } from \"@dirwell/theme-plain\";\nimport { startExplorerServer } from \"@dirwell/server/node\";\nimport { validateCliConfig } from \"./config.ts\";\nexport { defineConfig } from \"./config.ts\";\n\nexport interface CliConfig {\n readonly ignoreFiles?: GenerateOptions[\"ignoreFiles\"];\n readonly build?: Omit<GenerateOptions, \"sourceDir\" | \"outputDir\" | \"theme\" | \"listing\">;\n readonly theme?: ExplorerTheme;\n readonly listing?: ListingPolicy;\n readonly server?: Omit<Parameters<typeof startExplorerServer>[0], \"root\" | \"theme\" | \"listing\">;\n}\nconst help = `Usage:\n dirwell build <source> --out <output>\n dirwell server <source> [--port 3000]\n\nPlain is included and selected by default. Install other themes separately.\nOfficial themes: --theme plain|ledger|crosswave\nCustom themes: --theme <module>#<factory>, or a module's default export.\nReads dirwell.config.mjs in the working folder; --config <file.mjs> selects another file.\nConfig exports theme, listing, build options, and server hooks.\nBuild options: --mode ssg|mpa, --urls relative|base|html-base, --base <path>\nBuild safety: --dry-run, --force (-f) replaces an unowned nonempty output.\nSelection: --ignore-file <path> (repeatable), --no-ignore disables ignore files.\nServer options: --host <host>, --port <port>, --mount <path>, --live\nBoth modes: --page-size <n>, --block-size <n>\nLive server reads on request. It does not build an output tree or require watch mode.\n`;\nconst positive = (value: string | undefined, name: string): number | undefined => {\n if (value === undefined) return undefined;\n const number = Number(value);\n if (!Number.isSafeInteger(number) || number < 1)\n throw new TypeError(`${name} must be a positive integer`);\n return number;\n};\nfunction assertTheme(candidate: unknown): asserts candidate is ExplorerTheme {\n if (\n typeof candidate !== \"object\" ||\n candidate === null ||\n !(\"name\" in candidate) ||\n typeof candidate.name !== \"string\" ||\n !(\"render\" in candidate) ||\n typeof candidate.render !== \"function\"\n )\n throw new TypeError(\"Theme must be an object with name and render(context)\");\n}\nasync function loadTheme(specifier: string, cwd: string): Promise<ExplorerTheme> {\n const official: Record<string, string> = {\n plain: \"@dirwell/theme-plain#createPlainTheme\",\n ledger: \"@dirwell/theme-ledger#createLedgerTheme\",\n crosswave: \"@dirwell/theme-crosswave#createCrosswaveTheme\",\n };\n if (Object.hasOwn(official, specifier)) specifier = official[specifier]!;\n const delimiter = specifier.lastIndexOf(\"#\"),\n name = delimiter < 0 ? specifier : specifier.slice(0, delimiter),\n exported = delimiter < 0 ? \"default\" : specifier.slice(delimiter + 1);\n if (!name || !exported) throw new TypeError(\"Theme needs a module and export name\");\n let moduleUrl: string;\n if (name.startsWith(\".\") || path.isAbsolute(name)) {\n moduleUrl = pathToFileURL(path.resolve(cwd, name)).href;\n } else {\n try {\n moduleUrl = resolveModule(name, pathToFileURL(path.join(cwd, \"package.json\")).href);\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ERR_MODULE_NOT_FOUND\"))\n throw error;\n // npm exec installs explicit --package entries beside the CLI, outside the user's folder.\n try {\n moduleUrl = resolveModule(name, import.meta.url);\n } catch (fallbackError) {\n if (\n fallbackError instanceof Error &&\n \"code\" in fallbackError &&\n fallbackError.code === \"ERR_MODULE_NOT_FOUND\"\n )\n throw new TypeError(\n `Theme package \"${name}\" was not found. Install it in your project or include it with npm exec --package=${name}.`,\n );\n throw fallbackError;\n }\n }\n }\n const module: Record<string, unknown> = await import(moduleUrl);\n const candidate =\n typeof module[exported] === \"function\" ? await module[exported]() : module[exported];\n assertTheme(candidate);\n return candidate;\n}\n/** Parse explicit commands; return server ownership to the caller for graceful shutdown. */\nexport async function runCli(\n args: readonly string[],\n cwd = process.cwd(),\n log: (value: string) => void = console.log,\n) {\n const parsed = parseArgs({\n args: [...args],\n allowPositionals: true,\n options: {\n help: { type: \"boolean\", short: \"h\" },\n force: { type: \"boolean\", short: \"f\" },\n \"dry-run\": { type: \"boolean\" },\n \"ignore-file\": { type: \"string\", multiple: true },\n \"no-ignore\": { type: \"boolean\" },\n live: { type: \"boolean\" },\n theme: { type: \"string\" },\n config: { type: \"string\" },\n out: { type: \"string\" },\n mode: { type: \"string\" },\n urls: { type: \"string\" },\n base: { type: \"string\" },\n host: { type: \"string\" },\n port: { type: \"string\" },\n mount: { type: \"string\" },\n \"page-size\": { type: \"string\" },\n \"block-size\": { type: \"string\" },\n },\n });\n if (parsed.values.help) {\n log(help);\n return null;\n }\n const [command, source] = parsed.positionals;\n if (\n ![\"build\", \"server\"].includes(command ?? \"\") ||\n source === undefined ||\n source === \"\" ||\n parsed.positionals.length !== 2\n )\n throw new TypeError(help);\n const otherModeOptions =\n command === \"build\"\n ? [\"host\", \"port\", \"mount\", \"live\"]\n : [\"out\", \"mode\", \"urls\", \"base\", \"force\", \"dry-run\"];\n for (const option of otherModeOptions)\n if (Object.hasOwn(parsed.values, option))\n throw new TypeError(`--${option} is not supported in ${command} mode`);\n let config: CliConfig = {};\n const configPath = path.resolve(cwd, parsed.values.config ?? \"dirwell.config.mjs\");\n let hasConfig = parsed.values.config !== undefined;\n if (!hasConfig) {\n try {\n await access(configPath);\n hasConfig = true;\n } catch (error) {\n if (!(error instanceof Error && \"code\" in error && error.code === \"ENOENT\")) throw error;\n }\n }\n if (!hasConfig) {\n for (const filename of [\n \"dirwell.config.ts\",\n \"dirwell.config.js\",\n \"dirwell.config.mts\",\n \"dirwell.config.cjs\",\n ]) {\n try {\n await access(path.resolve(cwd, filename));\n } catch (error) {\n if (error instanceof Error && \"code\" in error && error.code === \"ENOENT\") continue;\n throw error;\n }\n throw new TypeError(\n `Found ${filename}. This CLI discovers dirwell.config.mjs only. Migrate the config or select a native JavaScript module with --config; existing rules will not be silently ignored.`,\n );\n }\n }\n if (hasConfig) {\n const module = await import(pathToFileURL(configPath).href);\n if (\n typeof module.default !== \"object\" ||\n module.default === null ||\n Array.isArray(module.default)\n )\n throw new TypeError(\"Config must export an object\");\n for (const key of Object.keys(module.default))\n if (![\"theme\", \"listing\", \"build\", \"server\", \"ignoreFiles\"].includes(key))\n throw new TypeError(\n `Unsupported config key \"${key}\". Use { theme, listing, build, server }; selection rules belong in build/server.`,\n );\n if (typeof module.default.then === \"function\")\n throw new TypeError(\n \"Config must export a resolved object; use top-level await for async setup\",\n );\n validateCliConfig(module.default);\n config = module.default;\n }\n const theme =\n parsed.values.theme !== undefined\n ? await loadTheme(parsed.values.theme, cwd)\n : config.theme === undefined\n ? createPlainTheme()\n : config.theme;\n assertTheme(theme);\n const pageSize = positive(parsed.values[\"page-size\"], \"page-size\"),\n blockSize = positive(parsed.values[\"block-size\"], \"block-size\");\n const listing: ListingPolicy | undefined =\n pageSize !== undefined || blockSize !== undefined\n ? {\n html: pageSize === undefined ? { strategy: \"all\" } : { strategy: \"paged\", pageSize },\n data: blockSize === undefined ? { strategy: \"all\" } : { strategy: \"blocks\", blockSize },\n }\n : config.listing;\n const root = path.resolve(cwd, source);\n if (!(await stat(root)).isDirectory())\n throw new TypeError(\"Source must be an existing directory\");\n if (parsed.values[\"no-ignore\"] && parsed.values[\"ignore-file\"])\n throw new TypeError(\"--no-ignore cannot be combined with --ignore-file\");\n const modeOptions = command === \"build\" ? config.build : config.server;\n const ignoreFiles = resolveIgnoreFiles(\n parsed.values[\"no-ignore\"]\n ? []\n : (parsed.values[\"ignore-file\"] ??\n modeOptions?.ignoreFiles ??\n config.ignoreFiles ?? [{ path: \".gitignore\", optional: true }]),\n cwd,\n );\n if (command === \"build\") {\n if (parsed.values.out === undefined)\n throw new TypeError(\"Build requires --out pointing to a dedicated generated output tree\");\n const mode = parsed.values.mode ?? config.build?.mode ?? \"ssg\",\n urlStrategy = parsed.values.urls ?? config.build?.urlStrategy ?? \"relative\";\n if (mode !== \"ssg\" && mode !== \"mpa\") throw new TypeError(\"mode must be ssg or mpa\");\n if (![\"relative\", \"base\", \"html-base\"].includes(urlStrategy))\n throw new TypeError(\"Unknown URL strategy\");\n const report = await generateExplorer({\n ...config.build,\n sourceDir: root,\n outputDir: path.resolve(cwd, parsed.values.out),\n theme,\n ignoreFiles,\n ...(parsed.values.force ? { outputPolicy: \"replace\" } : {}),\n ...(parsed.values[\"dry-run\"] ? { dryRun: true } : {}),\n mode,\n urlStrategy: urlStrategy as \"relative\" | \"base\" | \"html-base\",\n ...(parsed.values.base === undefined ? {} : { base: parsed.values.base }),\n ...(listing === undefined ? {} : { listing }),\n });\n if (report.dryRun) log(JSON.stringify(report, null, 2));\n else {\n log(`Built ${parsed.values.out}`);\n log(\n `${report.selectedPaths.length} selected paths; ${report.pages.filter((page) => page.outputName !== null).length} directory pages; ${report.pages.filter((page) => page.outputName === null).length} skipped pages.`,\n );\n for (const page of report.pages)\n if (page.directory === \"\" || page.outputName === null)\n log(\n page.outputName === null\n ? `Skipped explorer page: ${page.directory || \"/\"}`\n : `Explorer entry: ${path.join(report.outputDir, page.outputName)}`,\n );\n }\n return null;\n }\n const port = Number(parsed.values.port ?? process.env.PORT ?? config.server?.port ?? 0);\n if (!Number.isSafeInteger(port) || port < 0 || port > 65535)\n throw new TypeError(\"port must be between 0 and 65535\");\n const server = await startExplorerServer({\n ...config.server,\n ...(parsed.values.live ? { live: config.server?.live || {} } : {}),\n root,\n theme,\n ignoreFiles,\n port,\n ...(listing === undefined ? {} : { listing }),\n ...(pageSize === undefined ? {} : { pageSize }),\n ...(blockSize === undefined ? {} : { blockSize }),\n ...(parsed.values.host === undefined ? {} : { host: parsed.values.host }),\n ...(parsed.values.mount === undefined ? {} : { mountPath: parsed.values.mount }),\n });\n log(\n `Dirwell server: ${server.url}${parsed.values.mount ?? config.server?.mountPath ?? \"\"}/browse/`,\n );\n return server;\n}\n"],"mappings":"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"}
|