@xsynaptic/astro-scripts 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +30 -2
- package/dist/astro.d.mts +20 -0
- package/dist/astro.mjs +56 -0
- package/dist/astro.mjs.map +1 -0
- package/dist/index.d.mts +101 -0
- package/dist/index.mjs +756 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +65 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Alexander Synaptic
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @xsynaptic/astro-scripts
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Plumbing for an Astro project's `scripts` package: a command runner, output through interchangeable reporters, workspace root discovery, and a bridge for reading `astro:content` outside the Astro runtime. Early prototype; the API will move.
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pnpm add @xsynaptic/astro-scripts
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { createCommandRunner, log } from '@xsynaptic/astro-scripts';
|
|
11
|
+
import { getCollectionEntries, withAstroContent } from '@xsynaptic/astro-scripts/astro';
|
|
12
|
+
|
|
13
|
+
const { runCommand } = createCommandRunner();
|
|
14
|
+
|
|
15
|
+
await runCommand({
|
|
16
|
+
name: 'count-posts',
|
|
17
|
+
run: async () => {
|
|
18
|
+
const posts = await withAstroContent((content) => getCollectionEntries(content, ['posts']));
|
|
19
|
+
|
|
20
|
+
log.data(posts.length);
|
|
21
|
+
},
|
|
22
|
+
summary: 'Count published posts',
|
|
23
|
+
title: 'Posts',
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Output renders `pretty` on a TTY, `plain` elsewhere, and NDJSON with `--json`; `SCRIPTS_OUTPUT` overrides the choice. The `/astro` entry needs `astro` and `vite` installed and a content store written by `astro sync`.
|
|
28
|
+
|
|
29
|
+
## License
|
|
30
|
+
|
|
31
|
+
MIT
|
package/dist/astro.d.mts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import * as AstroContentModule from "astro:content";
|
|
2
|
+
import { CollectionEntry, CollectionKey } from "astro:content";
|
|
3
|
+
import { ModuleRunner } from "vite/module-runner";
|
|
4
|
+
//#region src/astro.d.ts
|
|
5
|
+
type AstroContent = typeof AstroContentModule;
|
|
6
|
+
export interface ContentEntry {
|
|
7
|
+
body?: string | undefined;
|
|
8
|
+
collection: string;
|
|
9
|
+
data: Record<string, unknown>;
|
|
10
|
+
digest?: number | string | undefined;
|
|
11
|
+
filePath?: string | undefined;
|
|
12
|
+
id: string;
|
|
13
|
+
}
|
|
14
|
+
export declare function findAstroRoot(startDir?: string): string;
|
|
15
|
+
export declare function getCollectionEntries<C extends CollectionKey>({ getCollection }: AstroContent, collections: Array<C>): Promise<Array<CollectionEntry<C>>>;
|
|
16
|
+
export declare function withAstroModules<T>(callback: (runner: ModuleRunner) => Promise<T>): Promise<T>;
|
|
17
|
+
export declare function withAstroContent<T>(callback: (content: AstroContent) => Promise<T>): Promise<T>;
|
|
18
|
+
//#endregion
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=astro.d.mts.map
|
package/dist/astro.mjs
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { getViteConfig } from "astro/config";
|
|
4
|
+
import { createLogger, createServer, createServerModuleRunner } from "vite";
|
|
5
|
+
//#region src/astro.ts
|
|
6
|
+
const configFilenames = [
|
|
7
|
+
"astro.config.mjs",
|
|
8
|
+
"astro.config.js",
|
|
9
|
+
"astro.config.ts",
|
|
10
|
+
"astro.config.mts"
|
|
11
|
+
];
|
|
12
|
+
function findAstroRoot(startDir = process.cwd()) {
|
|
13
|
+
let current = path.resolve(startDir);
|
|
14
|
+
while (current !== path.dirname(current)) {
|
|
15
|
+
if (configFilenames.some((filename) => existsSync(path.join(current, filename)))) return current;
|
|
16
|
+
current = path.dirname(current);
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`Could not locate an Astro config above ${startDir}`);
|
|
19
|
+
}
|
|
20
|
+
async function getCollectionEntries({ getCollection }, collections) {
|
|
21
|
+
const flattened = (await Promise.all(collections.map((collection) => getCollection(collection)))).flat();
|
|
22
|
+
if (flattened.length === 0) throw new Error(`No entries found in: ${collections.join(", ")}. Run \`astro sync\` to write the content store.`);
|
|
23
|
+
return flattened;
|
|
24
|
+
}
|
|
25
|
+
async function withAstroModules(callback) {
|
|
26
|
+
const root = findAstroRoot();
|
|
27
|
+
const config = await getViteConfig({}, {
|
|
28
|
+
logLevel: "silent",
|
|
29
|
+
root
|
|
30
|
+
})({
|
|
31
|
+
command: "serve",
|
|
32
|
+
mode: "development"
|
|
33
|
+
});
|
|
34
|
+
const server = await createServer({
|
|
35
|
+
...config,
|
|
36
|
+
customLogger: createLogger("silent"),
|
|
37
|
+
logLevel: "silent",
|
|
38
|
+
server: {
|
|
39
|
+
hmr: false,
|
|
40
|
+
middlewareMode: true,
|
|
41
|
+
ws: false
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
try {
|
|
45
|
+
return await callback(createServerModuleRunner(server.environments.ssr));
|
|
46
|
+
} finally {
|
|
47
|
+
await server.close();
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
async function withAstroContent(callback) {
|
|
51
|
+
return withAstroModules(async (runner) => callback(await runner.import("astro:content")));
|
|
52
|
+
}
|
|
53
|
+
//#endregion
|
|
54
|
+
export { findAstroRoot, getCollectionEntries, withAstroContent, withAstroModules };
|
|
55
|
+
|
|
56
|
+
//# sourceMappingURL=astro.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"astro.mjs","names":[],"sources":["../src/astro.ts"],"sourcesContent":["import type * as AstroContentModule from 'astro:content';\nimport type { CollectionEntry, CollectionKey } from 'astro:content';\nimport type { ModuleRunner } from 'vite/module-runner';\n\nimport { getViteConfig } from 'astro/config';\nimport { existsSync } from 'node:fs';\nimport path from 'node:path';\nimport { createLogger, createServer, createServerModuleRunner } from 'vite';\n\ntype AstroContent = typeof AstroContentModule;\n\n// Mirrors Astro's own `configPaths`; it does not accept the CommonJS variants\nconst configFilenames = [\n\t'astro.config.mjs',\n\t'astro.config.js',\n\t'astro.config.ts',\n\t'astro.config.mts',\n];\n\n// Every `CollectionEntry` must satisfy this\nexport interface ContentEntry {\n\tbody?: string | undefined;\n\tcollection: string;\n\tdata: Record<string, unknown>;\n\t// Astro widens this to `string | number`; file-based collections only ever write a string\n\tdigest?: number | string | undefined;\n\tfilePath?: string | undefined;\n\tid: string;\n}\n\nexport function findAstroRoot(startDir = process.cwd()) {\n\tlet current = path.resolve(startDir);\n\n\twhile (current !== path.dirname(current)) {\n\t\tconst hasConfig = configFilenames.some((filename) => existsSync(path.join(current, filename)));\n\n\t\tif (hasConfig) return current;\n\n\t\tcurrent = path.dirname(current);\n\t}\n\n\tthrow new Error(`Could not locate an Astro config above ${startDir}`);\n}\n\n// Annotated so the declaration keeps the consumer's `CollectionEntry`; inferred, it bakes in the unsynced `any`\nexport async function getCollectionEntries<C extends CollectionKey>(\n\t{ getCollection }: AstroContent,\n\tcollections: Array<C>,\n): Promise<Array<CollectionEntry<C>>> {\n\tconst entries = await Promise.all(\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return -- unsynced here, `getCollection` is the stub's `any`; a consumer's is typed\n\t\tcollections.map((collection) => getCollection(collection)),\n\t);\n\tconst flattened = entries.flat();\n\n\tif (flattened.length === 0) {\n\t\tthrow new Error(\n\t\t\t`No entries found in: ${collections.join(', ')}. Run \\`astro sync\\` to write the content store.`,\n\t\t);\n\t}\n\n\treturn flattened;\n}\n\nexport async function withAstroModules<T>(callback: (runner: ModuleRunner) => Promise<T>) {\n\t// An unrooted config resolves against `process.cwd()`, finds none, and reads every collection back empty\n\tconst root = findAstroRoot();\n\n\tconst config = await getViteConfig(\n\t\t{},\n\t\t{ logLevel: 'silent', root },\n\t)({\n\t\tcommand: 'serve',\n\t\tmode: 'development',\n\t});\n\n\tconst server = await createServer({\n\t\t...config,\n\t\t// Astro's config sets a `customLogger` that writes to stdout and ignores `logLevel`\n\t\tcustomLogger: createLogger('silent'),\n\t\tlogLevel: 'silent',\n\t\tserver: { hmr: false, middlewareMode: true, ws: false },\n\t});\n\n\ttry {\n\t\treturn await callback(createServerModuleRunner(server.environments.ssr));\n\t} finally {\n\t\t// The process hangs on the open server otherwise\n\t\tawait server.close();\n\t}\n}\n\nexport async function withAstroContent<T>(callback: (content: AstroContent) => Promise<T>) {\n\treturn withAstroModules(async (runner) =>\n\t\tcallback(await runner.import<AstroContent>('astro:content')),\n\t);\n}\n"],"mappings":";;;;;AAYA,MAAM,kBAAkB;CACvB;CACA;CACA;CACA;AACD;AAaA,SAAgB,cAAc,WAAW,QAAQ,IAAI,GAAG;CACvD,IAAI,UAAU,KAAK,QAAQ,QAAQ;CAEnC,OAAO,YAAY,KAAK,QAAQ,OAAO,GAAG;EAGzC,IAFkB,gBAAgB,MAAM,aAAa,WAAW,KAAK,KAAK,SAAS,QAAQ,CAAC,CAEhF,GAAG,OAAO;EAEtB,UAAU,KAAK,QAAQ,OAAO;CAC/B;CAEA,MAAM,IAAI,MAAM,0CAA0C,UAAU;AACrE;AAGA,eAAsB,qBACrB,EAAE,iBACF,aACqC;CAKrC,MAAM,aAAY,MAJI,QAAQ,IAE7B,YAAY,KAAK,eAAe,cAAc,UAAU,CAAC,CAC1D,EAAA,CAC0B,KAAK;CAE/B,IAAI,UAAU,WAAW,GACxB,MAAM,IAAI,MACT,wBAAwB,YAAY,KAAK,IAAI,EAAE,iDAChD;CAGD,OAAO;AACR;AAEA,eAAsB,iBAAoB,UAAgD;CAEzF,MAAM,OAAO,cAAc;CAE3B,MAAM,SAAS,MAAM,cACpB,CAAC,GACD;EAAE,UAAU;EAAU;CAAK,CAC5B,CAAC,CAAC;EACD,SAAS;EACT,MAAM;CACP,CAAC;CAED,MAAM,SAAS,MAAM,aAAa;EACjC,GAAG;EAEH,cAAc,aAAa,QAAQ;EACnC,UAAU;EACV,QAAQ;GAAE,KAAK;GAAO,gBAAgB;GAAM,IAAI;EAAM;CACvD,CAAC;CAED,IAAI;EACH,OAAO,MAAM,SAAS,yBAAyB,OAAO,aAAa,GAAG,CAAC;CACxE,UAAU;EAET,MAAM,OAAO,MAAM;CACpB;AACD;AAEA,eAAsB,iBAAoB,UAAiD;CAC1F,OAAO,iBAAiB,OAAO,WAC9B,SAAS,MAAM,OAAO,OAAqB,eAAe,CAAC,CAC5D;AACD"}
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { ParseArgsOptionDescriptor, parseArgs } from "node:util";
|
|
2
|
+
//#region src/command.d.ts
|
|
3
|
+
type CommandOption = ParseArgsOptionDescriptor & {
|
|
4
|
+
description: string;
|
|
5
|
+
};
|
|
6
|
+
type CommandOptions = Record<string, CommandOption>;
|
|
7
|
+
interface CommandPositional {
|
|
8
|
+
description: string;
|
|
9
|
+
name: string;
|
|
10
|
+
}
|
|
11
|
+
type ParsedValues<Options extends CommandOptions> = ReturnType<typeof parseArgs<{
|
|
12
|
+
allowPositionals: true;
|
|
13
|
+
options: Options;
|
|
14
|
+
strict: true;
|
|
15
|
+
}>>['values'];
|
|
16
|
+
interface CommandDescription {
|
|
17
|
+
name: string;
|
|
18
|
+
options?: CommandOptions;
|
|
19
|
+
positional?: CommandPositional;
|
|
20
|
+
summary: string;
|
|
21
|
+
title: string;
|
|
22
|
+
}
|
|
23
|
+
interface CommandContext<Options extends CommandOptions> {
|
|
24
|
+
positionals: Array<string>;
|
|
25
|
+
rootPath: string;
|
|
26
|
+
signal: AbortSignal;
|
|
27
|
+
values: ParsedValues<Options>;
|
|
28
|
+
}
|
|
29
|
+
interface Command<Options extends CommandOptions, Context> extends CommandDescription {
|
|
30
|
+
interrupted?: string;
|
|
31
|
+
options?: Options;
|
|
32
|
+
run: (context: CommandContext<Options> & Context) => Promise<void> | void;
|
|
33
|
+
}
|
|
34
|
+
interface CommandRunnerOptions<Context> {
|
|
35
|
+
context?: (base: {
|
|
36
|
+
rootPath: string;
|
|
37
|
+
}) => Context | Promise<Context>;
|
|
38
|
+
usagePrefix?: string;
|
|
39
|
+
}
|
|
40
|
+
export declare function parseNumberOption(value: string, name: string): number;
|
|
41
|
+
export declare function createCommandRunner<Context extends object = object>(runnerOptions?: CommandRunnerOptions<Context>): {
|
|
42
|
+
defineCommand: <const Options extends CommandOptions>(command: Command<Options, Context>) => Command<Options, Context>;
|
|
43
|
+
runCommand: <const Options extends CommandOptions>(command: Command<Options, Context>) => Promise<void>;
|
|
44
|
+
};
|
|
45
|
+
//#endregion
|
|
46
|
+
//#region src/output/format.d.ts
|
|
47
|
+
export declare function formatCount(count: number): string;
|
|
48
|
+
export declare function formatBytes(bytes: number): string;
|
|
49
|
+
export declare function formatError(error: unknown): string;
|
|
50
|
+
export declare function formatDuration(milliseconds: number): string;
|
|
51
|
+
//#endregion
|
|
52
|
+
//#region src/output/events.d.ts
|
|
53
|
+
type SummaryRow = [label: string, value: number | string];
|
|
54
|
+
//#endregion
|
|
55
|
+
//#region src/output/output.d.ts
|
|
56
|
+
type OutputMode = 'json' | 'plain' | 'pretty';
|
|
57
|
+
export declare function getOutputMode(): OutputMode;
|
|
58
|
+
export declare const log: {
|
|
59
|
+
data(value: unknown): void;
|
|
60
|
+
detail(text: string): void;
|
|
61
|
+
error(text: string): void;
|
|
62
|
+
info(text: string): void;
|
|
63
|
+
step(text: string): void;
|
|
64
|
+
success(text: string): void;
|
|
65
|
+
summary(rows: Array<SummaryRow>): void;
|
|
66
|
+
title(text: string): void;
|
|
67
|
+
warn(text: string): void;
|
|
68
|
+
};
|
|
69
|
+
export declare function createStatus(text: string): {
|
|
70
|
+
fail(finalText?: string): void;
|
|
71
|
+
stop(): void;
|
|
72
|
+
succeed(finalText?: string): void;
|
|
73
|
+
update(nextText: string): void;
|
|
74
|
+
warn(finalText?: string): void;
|
|
75
|
+
};
|
|
76
|
+
//#endregion
|
|
77
|
+
//#region src/output/progress.d.ts
|
|
78
|
+
interface ProgressOptions {
|
|
79
|
+
label: string;
|
|
80
|
+
note?: () => string;
|
|
81
|
+
total: number;
|
|
82
|
+
}
|
|
83
|
+
export declare function createProgress({ label, note, total }: ProgressOptions): {
|
|
84
|
+
fail(text?: string): void;
|
|
85
|
+
succeed(text?: string): void;
|
|
86
|
+
tick(count?: number): void;
|
|
87
|
+
warn(text?: string): void;
|
|
88
|
+
};
|
|
89
|
+
export declare function withStatus<Result>(text: string, task: () => Promise<Result>): Promise<Result>;
|
|
90
|
+
export declare function withSpinner<Result>(text: string, task: () => Promise<Result>, describe?: (result: Result) => string): Promise<Result>;
|
|
91
|
+
//#endregion
|
|
92
|
+
//#region src/refusal.d.ts
|
|
93
|
+
export declare class Refusal extends Error {
|
|
94
|
+
name: string;
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
//#region src/workspace.d.ts
|
|
98
|
+
export declare function findWorkspaceRoot(startDir?: string): string;
|
|
99
|
+
//#endregion
|
|
100
|
+
export type { Command, CommandContext, OutputMode };
|
|
101
|
+
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,756 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
import { parseArgs, stripVTControlCharacters } from "node:util";
|
|
3
|
+
import ora from "ora";
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
import path from "node:path";
|
|
6
|
+
//#region src/output/reporter-json.ts
|
|
7
|
+
const throttleMs = 1e3;
|
|
8
|
+
function strip(text) {
|
|
9
|
+
return text === void 0 ? void 0 : stripVTControlCharacters(text);
|
|
10
|
+
}
|
|
11
|
+
function stripEvent(event) {
|
|
12
|
+
switch (event.type) {
|
|
13
|
+
case "data": return event;
|
|
14
|
+
case "end": {
|
|
15
|
+
const { detail, message, ...rest } = event;
|
|
16
|
+
return {
|
|
17
|
+
...rest,
|
|
18
|
+
...detail === void 0 ? {} : { detail: strip(detail) },
|
|
19
|
+
...message === void 0 ? {} : { message: strip(message) }
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
case "message":
|
|
23
|
+
case "status": return {
|
|
24
|
+
...event,
|
|
25
|
+
text: strip(event.text)
|
|
26
|
+
};
|
|
27
|
+
case "progress": {
|
|
28
|
+
const { note, ...rest } = event;
|
|
29
|
+
return {
|
|
30
|
+
...rest,
|
|
31
|
+
label: strip(event.label),
|
|
32
|
+
...note ? { note: strip(note) } : {}
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
case "start": return {
|
|
36
|
+
...event,
|
|
37
|
+
title: strip(event.title)
|
|
38
|
+
};
|
|
39
|
+
case "summary": return {
|
|
40
|
+
...event,
|
|
41
|
+
rows: event.rows.map(([label, value]) => [strip(label), typeof value === "string" ? strip(value) : value])
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function createJsonReporter({ stderr, stdout }, { command, now = Date.now } = {}) {
|
|
46
|
+
const progressThrottles = /* @__PURE__ */ new Map();
|
|
47
|
+
const updateThrottles = /* @__PURE__ */ new Map();
|
|
48
|
+
function write(event) {
|
|
49
|
+
const { type, ...payload } = stripEvent(event);
|
|
50
|
+
const envelope = {
|
|
51
|
+
command,
|
|
52
|
+
time: new Date(now()).toISOString()
|
|
53
|
+
};
|
|
54
|
+
stderr.write(`${JSON.stringify({
|
|
55
|
+
type,
|
|
56
|
+
...envelope,
|
|
57
|
+
...payload
|
|
58
|
+
})}\n`);
|
|
59
|
+
}
|
|
60
|
+
function isDue(throttles, id) {
|
|
61
|
+
const time = now();
|
|
62
|
+
const throttle = throttles.get(id);
|
|
63
|
+
if (throttle && time - throttle.lastSent < throttleMs) return false;
|
|
64
|
+
throttles.set(id, { lastSent: time });
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
return { emit(event) {
|
|
68
|
+
if (event.type === "data") {
|
|
69
|
+
stdout.write(`${JSON.stringify(event.value)}\n`);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (event.type === "progress") {
|
|
73
|
+
if (isDue(progressThrottles, event.id)) {
|
|
74
|
+
write(event);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const throttle = progressThrottles.get(event.id);
|
|
78
|
+
if (throttle) throttle.pending = event;
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
if (event.type === "status" && event.state === "update") {
|
|
82
|
+
if (isDue(updateThrottles, event.id)) write(event);
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
if (event.type === "status" && event.state !== "start") {
|
|
86
|
+
const pending = progressThrottles.get(event.id)?.pending;
|
|
87
|
+
if (pending) write(pending);
|
|
88
|
+
progressThrottles.delete(event.id);
|
|
89
|
+
updateThrottles.delete(event.id);
|
|
90
|
+
}
|
|
91
|
+
write(event);
|
|
92
|
+
} };
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
//#region src/output/format.ts
|
|
96
|
+
const countFormat = new Intl.NumberFormat("en-CA");
|
|
97
|
+
const byteUnits = [
|
|
98
|
+
"B",
|
|
99
|
+
"kB",
|
|
100
|
+
"MB",
|
|
101
|
+
"GB",
|
|
102
|
+
"TB"
|
|
103
|
+
];
|
|
104
|
+
function formatCount(count) {
|
|
105
|
+
return countFormat.format(count);
|
|
106
|
+
}
|
|
107
|
+
function formatBytes(bytes) {
|
|
108
|
+
let value = bytes;
|
|
109
|
+
let unitIndex = 0;
|
|
110
|
+
while (value >= 1e3 && unitIndex < byteUnits.length - 1) {
|
|
111
|
+
value /= 1e3;
|
|
112
|
+
unitIndex += 1;
|
|
113
|
+
}
|
|
114
|
+
const unit = byteUnits[unitIndex] ?? "B";
|
|
115
|
+
return unitIndex === 0 ? `${String(value)} ${unit}` : `${value.toFixed(1)} ${unit}`;
|
|
116
|
+
}
|
|
117
|
+
function formatError(error) {
|
|
118
|
+
return error instanceof Error ? error.message : String(error);
|
|
119
|
+
}
|
|
120
|
+
function formatDuration(milliseconds) {
|
|
121
|
+
const seconds = milliseconds / 1e3;
|
|
122
|
+
if (seconds < 60) return `${seconds.toFixed(1)}s`;
|
|
123
|
+
const totalSeconds = Math.round(seconds);
|
|
124
|
+
const minutes = Math.floor(totalSeconds / 60);
|
|
125
|
+
const remainder = totalSeconds % 60;
|
|
126
|
+
return `${String(minutes)}m ${String(remainder).padStart(2, "0")}s`;
|
|
127
|
+
}
|
|
128
|
+
function formatRate(perSecond) {
|
|
129
|
+
return perSecond >= 10 ? formatCount(Math.round(perSecond)) : perSecond.toFixed(1);
|
|
130
|
+
}
|
|
131
|
+
function formatProgressText({ done, label, note, perSecond, total }) {
|
|
132
|
+
const percent = total === 0 ? 100 : Math.floor(done / total * 100);
|
|
133
|
+
const parts = [`${label} ${formatCount(done)} / ${formatCount(total)} (${String(percent)}%)`];
|
|
134
|
+
const remaining = total - done;
|
|
135
|
+
if (perSecond !== void 0 && perSecond > 0) {
|
|
136
|
+
parts.push(`${formatRate(perSecond)}/s`);
|
|
137
|
+
if (remaining > 0) parts.push(`~${formatDuration(remaining / perSecond * 1e3)} left`);
|
|
138
|
+
}
|
|
139
|
+
if (note) parts.push(note);
|
|
140
|
+
return parts.join(" · ");
|
|
141
|
+
}
|
|
142
|
+
//#endregion
|
|
143
|
+
//#region src/output/human-format.ts
|
|
144
|
+
function unpainted(text) {
|
|
145
|
+
return text;
|
|
146
|
+
}
|
|
147
|
+
const plainPalette = {
|
|
148
|
+
blue: unpainted,
|
|
149
|
+
gray: unpainted,
|
|
150
|
+
green: unpainted,
|
|
151
|
+
magenta: unpainted,
|
|
152
|
+
red: unpainted,
|
|
153
|
+
yellow: unpainted
|
|
154
|
+
};
|
|
155
|
+
function getStateSymbol(state, palette) {
|
|
156
|
+
if (state === "succeed") return palette.green("✓");
|
|
157
|
+
if (state === "fail") return palette.red("✗");
|
|
158
|
+
return palette.yellow("⚠");
|
|
159
|
+
}
|
|
160
|
+
function formatMessage(level, text, palette) {
|
|
161
|
+
switch (level) {
|
|
162
|
+
case "detail": return palette.gray(` ${text}`);
|
|
163
|
+
case "error": return `${getStateSymbol("fail", palette)} ${palette.red(text)}`;
|
|
164
|
+
case "info": return text;
|
|
165
|
+
case "step": return palette.blue(text);
|
|
166
|
+
case "success": return `${getStateSymbol("succeed", palette)} ${text}`;
|
|
167
|
+
case "title": return palette.magenta(`=== ${text} ===`);
|
|
168
|
+
case "warn": return `${getStateSymbol("warn", palette)} ${palette.yellow(text)}`;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
function formatSummaryRows(rows, palette) {
|
|
172
|
+
const width = Math.max(...rows.map(([label]) => label.length)) + 2;
|
|
173
|
+
return rows.map(([label, value]) => {
|
|
174
|
+
const formatted = typeof value === "number" ? formatCount(value) : value;
|
|
175
|
+
return ` ${palette.gray(`${label}:`.padEnd(width))}${formatted}`;
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
function formatData(value) {
|
|
179
|
+
return typeof value === "string" ? value : JSON.stringify(value, void 0, 2);
|
|
180
|
+
}
|
|
181
|
+
function formatEnd(event, palette) {
|
|
182
|
+
if (event.status === "ok") return [formatMessage("detail", `Finished in ${formatDuration(event.durationMs)}`, palette)];
|
|
183
|
+
const level = event.status === "failed" || event.forced ? "error" : "warn";
|
|
184
|
+
const lines = event.message === void 0 ? [] : [formatMessage(level, event.message, palette)];
|
|
185
|
+
if (event.detail) lines.push(formatMessage("detail", event.detail, palette));
|
|
186
|
+
return lines;
|
|
187
|
+
}
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/output/reporter-plain.ts
|
|
190
|
+
const progressIntervalMs = 1e4;
|
|
191
|
+
function createPlainReporter({ stderr, stdout }, now = Date.now) {
|
|
192
|
+
const statuses = /* @__PURE__ */ new Map();
|
|
193
|
+
let activeId;
|
|
194
|
+
function writeLine(line) {
|
|
195
|
+
stderr.write(`${stripVTControlCharacters(line)}\n`);
|
|
196
|
+
}
|
|
197
|
+
function closeStatus(id) {
|
|
198
|
+
statuses.delete(id);
|
|
199
|
+
if (activeId === id) activeId = void 0;
|
|
200
|
+
}
|
|
201
|
+
return { emit(event) {
|
|
202
|
+
switch (event.type) {
|
|
203
|
+
case "data":
|
|
204
|
+
stdout.write(`${formatData(event.value)}\n`);
|
|
205
|
+
break;
|
|
206
|
+
case "end": {
|
|
207
|
+
const active = activeId === void 0 ? void 0 : statuses.get(activeId);
|
|
208
|
+
if (active && activeId !== void 0 && event.status !== "ok") {
|
|
209
|
+
writeLine(`${getStateSymbol("fail", plainPalette)} ${active.text}`);
|
|
210
|
+
closeStatus(activeId);
|
|
211
|
+
}
|
|
212
|
+
for (const line of formatEnd(event, plainPalette)) writeLine(line);
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
case "message":
|
|
216
|
+
writeLine(formatMessage(event.level, event.text, plainPalette));
|
|
217
|
+
break;
|
|
218
|
+
case "progress": {
|
|
219
|
+
const status = statuses.get(event.id);
|
|
220
|
+
const time = now();
|
|
221
|
+
if (!status || time - status.lastPrint < progressIntervalMs) break;
|
|
222
|
+
status.lastPrint = time;
|
|
223
|
+
writeLine(formatProgressText(event));
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
case "start":
|
|
227
|
+
writeLine(formatMessage("title", event.title, plainPalette));
|
|
228
|
+
break;
|
|
229
|
+
case "status": {
|
|
230
|
+
const { id, state, text } = event;
|
|
231
|
+
if (state === "start") {
|
|
232
|
+
statuses.set(id, {
|
|
233
|
+
lastPrint: now(),
|
|
234
|
+
text
|
|
235
|
+
});
|
|
236
|
+
activeId = id;
|
|
237
|
+
writeLine(text);
|
|
238
|
+
break;
|
|
239
|
+
}
|
|
240
|
+
const status = statuses.get(id);
|
|
241
|
+
if (!status) break;
|
|
242
|
+
if (state === "update") {
|
|
243
|
+
status.text = text;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
if (state !== "stop") writeLine(`${getStateSymbol(state, plainPalette)} ${text}`);
|
|
247
|
+
closeStatus(id);
|
|
248
|
+
break;
|
|
249
|
+
}
|
|
250
|
+
case "summary": for (const line of formatSummaryRows(event.rows, plainPalette)) writeLine(line);
|
|
251
|
+
}
|
|
252
|
+
} };
|
|
253
|
+
}
|
|
254
|
+
//#endregion
|
|
255
|
+
//#region src/output/reporter-pretty.ts
|
|
256
|
+
function createPrettyReporter({ stderr, stdout }) {
|
|
257
|
+
const spinners = /* @__PURE__ */ new Map();
|
|
258
|
+
let activeId;
|
|
259
|
+
function getActiveSpinner() {
|
|
260
|
+
return activeId === void 0 ? void 0 : spinners.get(activeId);
|
|
261
|
+
}
|
|
262
|
+
function writeLine(line) {
|
|
263
|
+
const active = getActiveSpinner();
|
|
264
|
+
if (!active?.isSpinning) {
|
|
265
|
+
stderr.write(`${line}\n`);
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
active.clear();
|
|
269
|
+
stderr.write(`${line}\n`);
|
|
270
|
+
active.render();
|
|
271
|
+
}
|
|
272
|
+
function endSpinner(id, state, text) {
|
|
273
|
+
const spinner = spinners.get(id);
|
|
274
|
+
if (!spinner) return;
|
|
275
|
+
if (state === "stop") spinner.stop();
|
|
276
|
+
else spinner.stopAndPersist({
|
|
277
|
+
symbol: getStateSymbol(state, chalk),
|
|
278
|
+
text
|
|
279
|
+
});
|
|
280
|
+
spinners.delete(id);
|
|
281
|
+
if (activeId === id) activeId = void 0;
|
|
282
|
+
}
|
|
283
|
+
function onStatus({ id, state, text }) {
|
|
284
|
+
if (state === "start") {
|
|
285
|
+
getActiveSpinner()?.stop();
|
|
286
|
+
spinners.set(id, ora({
|
|
287
|
+
discardStdin: false,
|
|
288
|
+
stream: stderr,
|
|
289
|
+
text
|
|
290
|
+
}).start());
|
|
291
|
+
activeId = id;
|
|
292
|
+
return;
|
|
293
|
+
}
|
|
294
|
+
if (state === "update") {
|
|
295
|
+
const spinner = spinners.get(id);
|
|
296
|
+
if (spinner) spinner.text = text;
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
endSpinner(id, state, text);
|
|
300
|
+
}
|
|
301
|
+
return { emit(event) {
|
|
302
|
+
switch (event.type) {
|
|
303
|
+
case "data":
|
|
304
|
+
stdout.write(`${formatData(event.value)}\n`);
|
|
305
|
+
break;
|
|
306
|
+
case "end": {
|
|
307
|
+
const active = getActiveSpinner();
|
|
308
|
+
if (active && activeId !== void 0 && event.status !== "ok") endSpinner(activeId, "fail", active.text);
|
|
309
|
+
for (const spinner of spinners.values()) spinner.stop();
|
|
310
|
+
spinners.clear();
|
|
311
|
+
activeId = void 0;
|
|
312
|
+
for (const line of formatEnd(event, chalk)) writeLine(line);
|
|
313
|
+
break;
|
|
314
|
+
}
|
|
315
|
+
case "message":
|
|
316
|
+
writeLine(formatMessage(event.level, event.text, chalk));
|
|
317
|
+
break;
|
|
318
|
+
case "progress": {
|
|
319
|
+
const spinner = spinners.get(event.id);
|
|
320
|
+
if (spinner) spinner.text = formatProgressText(event);
|
|
321
|
+
break;
|
|
322
|
+
}
|
|
323
|
+
case "start":
|
|
324
|
+
writeLine(formatMessage("title", event.title, chalk));
|
|
325
|
+
break;
|
|
326
|
+
case "status":
|
|
327
|
+
onStatus(event);
|
|
328
|
+
break;
|
|
329
|
+
case "summary": for (const line of formatSummaryRows(event.rows, chalk)) writeLine(line);
|
|
330
|
+
}
|
|
331
|
+
} };
|
|
332
|
+
}
|
|
333
|
+
//#endregion
|
|
334
|
+
//#region src/output/output.ts
|
|
335
|
+
const outputModes = /* @__PURE__ */ new Set([
|
|
336
|
+
"json",
|
|
337
|
+
"plain",
|
|
338
|
+
"pretty"
|
|
339
|
+
]);
|
|
340
|
+
let currentMode;
|
|
341
|
+
let currentReporter;
|
|
342
|
+
let nextStatusId = 1;
|
|
343
|
+
function isOutputMode(value) {
|
|
344
|
+
return outputModes.has(value);
|
|
345
|
+
}
|
|
346
|
+
function detectOutputMode() {
|
|
347
|
+
const requested = process.env.SCRIPTS_OUTPUT;
|
|
348
|
+
if (isOutputMode(requested)) return requested;
|
|
349
|
+
return process.stderr.isTTY ? "pretty" : "plain";
|
|
350
|
+
}
|
|
351
|
+
function createReporter(mode, command) {
|
|
352
|
+
const streams = {
|
|
353
|
+
stderr: process.stderr,
|
|
354
|
+
stdout: process.stdout
|
|
355
|
+
};
|
|
356
|
+
if (mode === "json") return createJsonReporter(streams, { command });
|
|
357
|
+
if (mode === "plain") return createPlainReporter(streams);
|
|
358
|
+
return createPrettyReporter(streams);
|
|
359
|
+
}
|
|
360
|
+
function configureOutput(mode = detectOutputMode(), command) {
|
|
361
|
+
currentMode = mode;
|
|
362
|
+
currentReporter = createReporter(mode, command);
|
|
363
|
+
}
|
|
364
|
+
function getOutputMode() {
|
|
365
|
+
if (currentMode === void 0) currentMode = detectOutputMode();
|
|
366
|
+
return currentMode;
|
|
367
|
+
}
|
|
368
|
+
function emit(event) {
|
|
369
|
+
if (currentReporter === void 0) currentReporter = createReporter(getOutputMode());
|
|
370
|
+
currentReporter.emit(event);
|
|
371
|
+
}
|
|
372
|
+
function emitMessage(level, text) {
|
|
373
|
+
emit({
|
|
374
|
+
level,
|
|
375
|
+
text,
|
|
376
|
+
type: "message"
|
|
377
|
+
});
|
|
378
|
+
}
|
|
379
|
+
const log = {
|
|
380
|
+
data(value) {
|
|
381
|
+
emit({
|
|
382
|
+
type: "data",
|
|
383
|
+
value
|
|
384
|
+
});
|
|
385
|
+
},
|
|
386
|
+
detail(text) {
|
|
387
|
+
emitMessage("detail", text);
|
|
388
|
+
},
|
|
389
|
+
error(text) {
|
|
390
|
+
emitMessage("error", text);
|
|
391
|
+
},
|
|
392
|
+
info(text) {
|
|
393
|
+
emitMessage("info", text);
|
|
394
|
+
},
|
|
395
|
+
step(text) {
|
|
396
|
+
emitMessage("step", text);
|
|
397
|
+
},
|
|
398
|
+
success(text) {
|
|
399
|
+
emitMessage("success", text);
|
|
400
|
+
},
|
|
401
|
+
summary(rows) {
|
|
402
|
+
emit({
|
|
403
|
+
rows,
|
|
404
|
+
type: "summary"
|
|
405
|
+
});
|
|
406
|
+
},
|
|
407
|
+
title(text) {
|
|
408
|
+
emitMessage("title", text);
|
|
409
|
+
},
|
|
410
|
+
warn(text) {
|
|
411
|
+
emitMessage("warn", text);
|
|
412
|
+
}
|
|
413
|
+
};
|
|
414
|
+
function startStatus(initialText) {
|
|
415
|
+
const id = nextStatusId;
|
|
416
|
+
let text = initialText;
|
|
417
|
+
nextStatusId += 1;
|
|
418
|
+
emit({
|
|
419
|
+
id,
|
|
420
|
+
state: "start",
|
|
421
|
+
text,
|
|
422
|
+
type: "status"
|
|
423
|
+
});
|
|
424
|
+
function finish(state, finalText) {
|
|
425
|
+
text = finalText ?? text;
|
|
426
|
+
emit({
|
|
427
|
+
id,
|
|
428
|
+
state,
|
|
429
|
+
text,
|
|
430
|
+
type: "status"
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
id,
|
|
435
|
+
status: {
|
|
436
|
+
fail(finalText) {
|
|
437
|
+
finish("fail", finalText);
|
|
438
|
+
},
|
|
439
|
+
stop() {
|
|
440
|
+
finish("stop");
|
|
441
|
+
},
|
|
442
|
+
succeed(finalText) {
|
|
443
|
+
finish("succeed", finalText);
|
|
444
|
+
},
|
|
445
|
+
update(nextText) {
|
|
446
|
+
text = nextText;
|
|
447
|
+
emit({
|
|
448
|
+
id,
|
|
449
|
+
state: "update",
|
|
450
|
+
text,
|
|
451
|
+
type: "status"
|
|
452
|
+
});
|
|
453
|
+
},
|
|
454
|
+
warn(finalText) {
|
|
455
|
+
finish("warn", finalText);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function createStatus(text) {
|
|
461
|
+
return startStatus(text).status;
|
|
462
|
+
}
|
|
463
|
+
//#endregion
|
|
464
|
+
//#region src/refusal.ts
|
|
465
|
+
var Refusal = class extends Error {
|
|
466
|
+
name = "Refusal";
|
|
467
|
+
};
|
|
468
|
+
function isRefusal(error) {
|
|
469
|
+
return error instanceof Error && error.name === "Refusal";
|
|
470
|
+
}
|
|
471
|
+
//#endregion
|
|
472
|
+
//#region src/workspace.ts
|
|
473
|
+
function findWorkspaceRoot(startDir = process.cwd()) {
|
|
474
|
+
let current = path.resolve(startDir);
|
|
475
|
+
while (current !== path.dirname(current)) {
|
|
476
|
+
if (existsSync(path.join(current, "pnpm-workspace.yaml"))) return current;
|
|
477
|
+
current = path.dirname(current);
|
|
478
|
+
}
|
|
479
|
+
throw new Error(`Could not locate pnpm-workspace.yaml above ${startDir}`);
|
|
480
|
+
}
|
|
481
|
+
//#endregion
|
|
482
|
+
//#region src/command.ts
|
|
483
|
+
const interruptedExitCode = 130;
|
|
484
|
+
const interruptBurstMs = 1e3;
|
|
485
|
+
const builtInOptions = [["json", {
|
|
486
|
+
description: "Print output as JSON lines",
|
|
487
|
+
type: "boolean"
|
|
488
|
+
}], ["help", {
|
|
489
|
+
description: "Show this help",
|
|
490
|
+
short: "h",
|
|
491
|
+
type: "boolean"
|
|
492
|
+
}]];
|
|
493
|
+
function parseNumberOption(value, name) {
|
|
494
|
+
const parsed = Number(value);
|
|
495
|
+
if (value.trim() === "" || !Number.isFinite(parsed)) throw new Refusal(`--${name} expects a number, got "${value}"`);
|
|
496
|
+
return parsed;
|
|
497
|
+
}
|
|
498
|
+
function getUsage(command, usagePrefix) {
|
|
499
|
+
const positional = command.positional ? ` [${command.positional.name}]` : "";
|
|
500
|
+
return `${usagePrefix} ${command.name}${positional} [options]`;
|
|
501
|
+
}
|
|
502
|
+
function getOptionLabel(name, option) {
|
|
503
|
+
const flag = option.short ? `-${option.short}, --${name}` : ` --${name}`;
|
|
504
|
+
return option.type === "string" ? `${flag} <value>` : flag;
|
|
505
|
+
}
|
|
506
|
+
function getOptionDescription(option) {
|
|
507
|
+
const { default: defaultValue, description } = option;
|
|
508
|
+
if (defaultValue === void 0 || defaultValue === false) return description;
|
|
509
|
+
if (Array.isArray(defaultValue) && defaultValue.length === 0) return description;
|
|
510
|
+
return `${description} (default: ${String(defaultValue)})`;
|
|
511
|
+
}
|
|
512
|
+
function formatHelp(command, usagePrefix = "pnpm") {
|
|
513
|
+
const rows = [...Object.entries(command.options ?? {}), ...builtInOptions].map(([name, option]) => [getOptionLabel(name, option), getOptionDescription(option)]);
|
|
514
|
+
if (command.positional) rows.unshift([command.positional.name, command.positional.description]);
|
|
515
|
+
const width = Math.max(...rows.map(([label]) => label.length)) + 2;
|
|
516
|
+
return [
|
|
517
|
+
chalk.magenta(command.title),
|
|
518
|
+
command.summary,
|
|
519
|
+
"",
|
|
520
|
+
`Usage: ${getUsage(command, usagePrefix)}`,
|
|
521
|
+
"",
|
|
522
|
+
...rows.map(([label, description]) => ` ${label.padEnd(width)}${chalk.gray(description)}`)
|
|
523
|
+
].join("\n");
|
|
524
|
+
}
|
|
525
|
+
function isParseError(error) {
|
|
526
|
+
return error instanceof Error && "code" in error && typeof error.code === "string" && error.code.startsWith("ERR_PARSE_ARGS_");
|
|
527
|
+
}
|
|
528
|
+
function isChildProcessFailure(error) {
|
|
529
|
+
return error instanceof Error && "exitCode" in error && "signal" in error;
|
|
530
|
+
}
|
|
531
|
+
function isInterruption(error, isAborted) {
|
|
532
|
+
if (isAborted) return true;
|
|
533
|
+
return isChildProcessFailure(error) && (error.exitCode === interruptedExitCode || error.signal === "SIGINT");
|
|
534
|
+
}
|
|
535
|
+
function describeError(error) {
|
|
536
|
+
if (isParseError(error)) return {
|
|
537
|
+
detail: "See --help",
|
|
538
|
+
message: error.message
|
|
539
|
+
};
|
|
540
|
+
if (isRefusal(error)) return { message: error.message };
|
|
541
|
+
if (isChildProcessFailure(error)) return { message: `Child process ${error.signal ? `was killed by ${error.signal}` : `exited with code ${String(error.exitCode)}`}` };
|
|
542
|
+
if (!(error instanceof Error)) return { message: String(error) };
|
|
543
|
+
const stack = error.stack?.split("\n").slice(1).join("\n");
|
|
544
|
+
return stack ? {
|
|
545
|
+
detail: stack,
|
|
546
|
+
message: error.message
|
|
547
|
+
} : { message: error.message };
|
|
548
|
+
}
|
|
549
|
+
function getFailureReport(error, { interrupted, isAborted }) {
|
|
550
|
+
if (isInterruption(error, isAborted)) return {
|
|
551
|
+
exitCode: interruptedExitCode,
|
|
552
|
+
isInterrupted: true,
|
|
553
|
+
message: interrupted ? `Interrupted; ${interrupted}` : "Interrupted"
|
|
554
|
+
};
|
|
555
|
+
return {
|
|
556
|
+
exitCode: 1,
|
|
557
|
+
isInterrupted: false,
|
|
558
|
+
...describeError(error)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
function parseCommandArgs(command) {
|
|
562
|
+
const options = [...Object.entries(command.options ?? {}), ...builtInOptions];
|
|
563
|
+
return parseArgs({
|
|
564
|
+
allowPositionals: command.positional !== void 0,
|
|
565
|
+
args: process.argv.slice(2),
|
|
566
|
+
options: Object.fromEntries(options.map(([name, { description: _description, ...descriptor }]) => [name, descriptor])),
|
|
567
|
+
strict: true
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
function selectOutput(isJson) {
|
|
571
|
+
if (isJson) {
|
|
572
|
+
process.env.SCRIPTS_OUTPUT = "json";
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
const requested = process.env.SCRIPTS_OUTPUT;
|
|
576
|
+
if (requested && !isOutputMode(requested)) throw new Refusal(`SCRIPTS_OUTPUT must be pretty, plain or json, got "${requested}"`);
|
|
577
|
+
}
|
|
578
|
+
function createCommandRunner(runnerOptions = {}) {
|
|
579
|
+
const { context: createContext, usagePrefix = "pnpm" } = runnerOptions;
|
|
580
|
+
function defineCommand(command) {
|
|
581
|
+
return command;
|
|
582
|
+
}
|
|
583
|
+
async function runCommand(command) {
|
|
584
|
+
const controller = new AbortController();
|
|
585
|
+
const startTime = Date.now();
|
|
586
|
+
let interruptTime;
|
|
587
|
+
const isJson = process.argv.slice(2).includes("--json");
|
|
588
|
+
configureOutput(isJson ? "json" : void 0, command.name);
|
|
589
|
+
function onInterrupt() {
|
|
590
|
+
if (interruptTime === void 0) {
|
|
591
|
+
interruptTime = Date.now();
|
|
592
|
+
controller.abort();
|
|
593
|
+
log.warn("Stopping; press Ctrl-C again to force quit");
|
|
594
|
+
return;
|
|
595
|
+
}
|
|
596
|
+
if (Date.now() - interruptTime < interruptBurstMs) return;
|
|
597
|
+
emit({
|
|
598
|
+
durationMs: Date.now() - startTime,
|
|
599
|
+
exitCode: interruptedExitCode,
|
|
600
|
+
forced: true,
|
|
601
|
+
message: "Force quit",
|
|
602
|
+
status: "interrupted",
|
|
603
|
+
type: "end"
|
|
604
|
+
});
|
|
605
|
+
process.exit(interruptedExitCode);
|
|
606
|
+
}
|
|
607
|
+
process.on("SIGINT", onInterrupt);
|
|
608
|
+
process.on("SIGTERM", onInterrupt);
|
|
609
|
+
try {
|
|
610
|
+
const { positionals, values } = parseCommandArgs(command);
|
|
611
|
+
if (values.help) {
|
|
612
|
+
process.stdout.write(`${formatHelp(command, usagePrefix)}\n`);
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
selectOutput(isJson);
|
|
616
|
+
emit({
|
|
617
|
+
title: command.title,
|
|
618
|
+
type: "start"
|
|
619
|
+
});
|
|
620
|
+
const rootPath = findWorkspaceRoot();
|
|
621
|
+
const context = createContext ? await createContext({ rootPath }) : {};
|
|
622
|
+
await command.run({
|
|
623
|
+
...context,
|
|
624
|
+
positionals,
|
|
625
|
+
rootPath,
|
|
626
|
+
signal: controller.signal,
|
|
627
|
+
values
|
|
628
|
+
});
|
|
629
|
+
controller.signal.throwIfAborted();
|
|
630
|
+
emit({
|
|
631
|
+
durationMs: Date.now() - startTime,
|
|
632
|
+
exitCode: 0,
|
|
633
|
+
status: "ok",
|
|
634
|
+
type: "end"
|
|
635
|
+
});
|
|
636
|
+
} catch (error) {
|
|
637
|
+
const report = getFailureReport(error, {
|
|
638
|
+
interrupted: command.interrupted,
|
|
639
|
+
isAborted: controller.signal.aborted
|
|
640
|
+
});
|
|
641
|
+
emit({
|
|
642
|
+
...report.detail === void 0 ? {} : { detail: report.detail },
|
|
643
|
+
durationMs: Date.now() - startTime,
|
|
644
|
+
exitCode: report.exitCode,
|
|
645
|
+
message: report.message,
|
|
646
|
+
status: report.isInterrupted ? "interrupted" : "failed",
|
|
647
|
+
type: "end"
|
|
648
|
+
});
|
|
649
|
+
process.exitCode = report.exitCode;
|
|
650
|
+
} finally {
|
|
651
|
+
process.off("SIGINT", onInterrupt);
|
|
652
|
+
process.off("SIGTERM", onInterrupt);
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
return {
|
|
656
|
+
defineCommand,
|
|
657
|
+
runCommand
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
//#endregion
|
|
661
|
+
//#region src/output/progress.ts
|
|
662
|
+
const renderIntervalMs = 100;
|
|
663
|
+
const rateWindowMs = 1e4;
|
|
664
|
+
function createRateWindow(windowMs = rateWindowMs) {
|
|
665
|
+
const samples = [];
|
|
666
|
+
return {
|
|
667
|
+
add(count, time) {
|
|
668
|
+
samples.push({
|
|
669
|
+
count,
|
|
670
|
+
time
|
|
671
|
+
});
|
|
672
|
+
while (samples.length > 2 && time - (samples[0]?.time ?? time) > windowMs) samples.shift();
|
|
673
|
+
},
|
|
674
|
+
perSecond() {
|
|
675
|
+
const first = samples.at(0);
|
|
676
|
+
const last = samples.at(-1);
|
|
677
|
+
if (!first || !last || last.time <= first.time) return;
|
|
678
|
+
return (last.count - first.count) * 1e3 / (last.time - first.time);
|
|
679
|
+
}
|
|
680
|
+
};
|
|
681
|
+
}
|
|
682
|
+
function createProgress({ label, note, total }) {
|
|
683
|
+
const rateWindow = createRateWindow();
|
|
684
|
+
const startTime = Date.now();
|
|
685
|
+
let done = 0;
|
|
686
|
+
let lastRender = 0;
|
|
687
|
+
rateWindow.add(0, startTime);
|
|
688
|
+
function getSnapshot() {
|
|
689
|
+
const noteText = note?.();
|
|
690
|
+
const perSecond = rateWindow.perSecond();
|
|
691
|
+
return {
|
|
692
|
+
done,
|
|
693
|
+
label,
|
|
694
|
+
total,
|
|
695
|
+
...noteText ? { note: noteText } : {},
|
|
696
|
+
...perSecond === void 0 ? {} : { perSecond }
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
const { id, status } = startStatus(formatProgressText(getSnapshot()));
|
|
700
|
+
function render() {
|
|
701
|
+
const now = Date.now();
|
|
702
|
+
if (now - lastRender < renderIntervalMs) return;
|
|
703
|
+
lastRender = now;
|
|
704
|
+
rateWindow.add(done, now);
|
|
705
|
+
emit({
|
|
706
|
+
id,
|
|
707
|
+
type: "progress",
|
|
708
|
+
...getSnapshot()
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
function finish(state, text) {
|
|
712
|
+
const snapshot = getSnapshot();
|
|
713
|
+
emit({
|
|
714
|
+
id,
|
|
715
|
+
type: "progress",
|
|
716
|
+
...snapshot
|
|
717
|
+
});
|
|
718
|
+
status[state](text ?? formatProgressText(snapshot));
|
|
719
|
+
}
|
|
720
|
+
return {
|
|
721
|
+
fail(text) {
|
|
722
|
+
finish("fail", text);
|
|
723
|
+
},
|
|
724
|
+
succeed(text) {
|
|
725
|
+
finish("succeed", text);
|
|
726
|
+
},
|
|
727
|
+
tick(count = 1) {
|
|
728
|
+
done += count;
|
|
729
|
+
render();
|
|
730
|
+
},
|
|
731
|
+
warn(text) {
|
|
732
|
+
finish("warn", text);
|
|
733
|
+
}
|
|
734
|
+
};
|
|
735
|
+
}
|
|
736
|
+
async function withStatus(text, task) {
|
|
737
|
+
const status = createStatus(text);
|
|
738
|
+
const result = await task();
|
|
739
|
+
status.stop();
|
|
740
|
+
return result;
|
|
741
|
+
}
|
|
742
|
+
async function withSpinner(text, task, describe) {
|
|
743
|
+
const status = createStatus(text);
|
|
744
|
+
try {
|
|
745
|
+
const result = await task();
|
|
746
|
+
status.succeed(describe?.(result) ?? text);
|
|
747
|
+
return result;
|
|
748
|
+
} catch (error) {
|
|
749
|
+
status.fail(text);
|
|
750
|
+
throw error;
|
|
751
|
+
}
|
|
752
|
+
}
|
|
753
|
+
//#endregion
|
|
754
|
+
export { Refusal, createCommandRunner, createProgress, createStatus, findWorkspaceRoot, formatBytes, formatCount, formatDuration, formatError, getOutputMode, log, parseNumberOption, withSpinner, withStatus };
|
|
755
|
+
|
|
756
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../src/output/reporter-json.ts","../src/output/format.ts","../src/output/human-format.ts","../src/output/reporter-plain.ts","../src/output/reporter-pretty.ts","../src/output/output.ts","../src/refusal.ts","../src/workspace.ts","../src/command.ts","../src/output/progress.ts"],"sourcesContent":["import { stripVTControlCharacters } from 'node:util';\n\nimport type { OutputEvent, Reporter, ReporterStreams } from './events.js';\n\ntype ProgressEvent = Extract<OutputEvent, { type: 'progress' }>;\n\ninterface JsonReporterOptions {\n\tcommand?: string | undefined;\n\tnow?: () => number;\n}\n\ninterface Throttle {\n\tlastSent: number;\n\tpending?: ProgressEvent;\n}\n\nconst throttleMs = 1000;\n\nfunction strip(text: string): string;\nfunction strip(text: string | undefined): string | undefined;\nfunction strip(text: string | undefined) {\n\treturn text === undefined ? undefined : stripVTControlCharacters(text);\n}\n\nfunction stripEvent(event: OutputEvent): OutputEvent {\n\tswitch (event.type) {\n\t\tcase 'data': {\n\t\t\treturn event;\n\t\t}\n\t\tcase 'end': {\n\t\t\tconst { detail, message, ...rest } = event;\n\n\t\t\treturn {\n\t\t\t\t...rest,\n\t\t\t\t...(detail === undefined ? {} : { detail: strip(detail) }),\n\t\t\t\t...(message === undefined ? {} : { message: strip(message) }),\n\t\t\t};\n\t\t}\n\t\tcase 'message':\n\t\tcase 'status': {\n\t\t\treturn { ...event, text: strip(event.text) };\n\t\t}\n\t\tcase 'progress': {\n\t\t\tconst { note, ...rest } = event;\n\n\t\t\treturn { ...rest, label: strip(event.label), ...(note ? { note: strip(note) } : {}) };\n\t\t}\n\t\tcase 'start': {\n\t\t\treturn { ...event, title: strip(event.title) };\n\t\t}\n\t\tcase 'summary': {\n\t\t\treturn {\n\t\t\t\t...event,\n\t\t\t\trows: event.rows.map(([label, value]) => [\n\t\t\t\t\tstrip(label),\n\t\t\t\t\ttypeof value === 'string' ? strip(value) : value,\n\t\t\t\t]),\n\t\t\t};\n\t\t}\n\t}\n}\n\nexport function createJsonReporter(\n\t{ stderr, stdout }: ReporterStreams,\n\t{ command, now = Date.now }: JsonReporterOptions = {},\n): Reporter {\n\tconst progressThrottles = new Map<number, Throttle>();\n\tconst updateThrottles = new Map<number, Throttle>();\n\n\tfunction write(event: OutputEvent) {\n\t\tconst { type, ...payload } = stripEvent(event);\n\t\tconst envelope = { command, time: new Date(now()).toISOString() };\n\n\t\tstderr.write(`${JSON.stringify({ type, ...envelope, ...payload })}\\n`);\n\t}\n\n\tfunction isDue(throttles: Map<number, Throttle>, id: number) {\n\t\tconst time = now();\n\t\tconst throttle = throttles.get(id);\n\n\t\tif (throttle && time - throttle.lastSent < throttleMs) return false;\n\n\t\tthrottles.set(id, { lastSent: time });\n\n\t\treturn true;\n\t}\n\n\treturn {\n\t\temit(event) {\n\t\t\tif (event.type === 'data') {\n\t\t\t\tstdout.write(`${JSON.stringify(event.value)}\\n`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.type === 'progress') {\n\t\t\t\tif (isDue(progressThrottles, event.id)) {\n\t\t\t\t\twrite(event);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tconst throttle = progressThrottles.get(event.id);\n\n\t\t\t\tif (throttle) throttle.pending = event;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.type === 'status' && event.state === 'update') {\n\t\t\t\tif (isDue(updateThrottles, event.id)) write(event);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (event.type === 'status' && event.state !== 'start') {\n\t\t\t\tconst pending = progressThrottles.get(event.id)?.pending;\n\n\t\t\t\tif (pending) write(pending);\n\n\t\t\t\tprogressThrottles.delete(event.id);\n\t\t\t\tupdateThrottles.delete(event.id);\n\t\t\t}\n\n\t\t\twrite(event);\n\t\t},\n\t};\n}\n","const countFormat = new Intl.NumberFormat('en-CA');\n\nconst byteUnits = ['B', 'kB', 'MB', 'GB', 'TB'] as const;\n\nexport function formatCount(count: number) {\n\treturn countFormat.format(count);\n}\n\nexport function formatBytes(bytes: number) {\n\tlet value = bytes;\n\tlet unitIndex = 0;\n\n\twhile (value >= 1000 && unitIndex < byteUnits.length - 1) {\n\t\tvalue /= 1000;\n\t\tunitIndex += 1;\n\t}\n\n\tconst unit = byteUnits[unitIndex] ?? 'B';\n\n\treturn unitIndex === 0 ? `${String(value)} ${unit}` : `${value.toFixed(1)} ${unit}`;\n}\n\nexport function formatError(error: unknown) {\n\treturn error instanceof Error ? error.message : String(error);\n}\n\nexport function formatDuration(milliseconds: number) {\n\tconst seconds = milliseconds / 1000;\n\n\tif (seconds < 60) return `${seconds.toFixed(1)}s`;\n\n\tconst totalSeconds = Math.round(seconds);\n\tconst minutes = Math.floor(totalSeconds / 60);\n\tconst remainder = totalSeconds % 60;\n\n\treturn `${String(minutes)}m ${String(remainder).padStart(2, '0')}s`;\n}\n\nfunction formatRate(perSecond: number) {\n\treturn perSecond >= 10 ? formatCount(Math.round(perSecond)) : perSecond.toFixed(1);\n}\n\nexport interface ProgressSnapshot {\n\tdone: number;\n\tlabel: string;\n\tnote?: string;\n\tperSecond?: number;\n\ttotal: number;\n}\n\nexport function formatProgressText({ done, label, note, perSecond, total }: ProgressSnapshot) {\n\tconst percent = total === 0 ? 100 : Math.floor((done / total) * 100);\n\tconst parts = [`${label} ${formatCount(done)} / ${formatCount(total)} (${String(percent)}%)`];\n\tconst remaining = total - done;\n\n\tif (perSecond !== undefined && perSecond > 0) {\n\t\tparts.push(`${formatRate(perSecond)}/s`);\n\n\t\tif (remaining > 0) parts.push(`~${formatDuration((remaining / perSecond) * 1000)} left`);\n\t}\n\n\tif (note) parts.push(note);\n\n\treturn parts.join(' · ');\n}\n","import type { MessageLevel, OutputEvent, StatusState, SummaryRow } from './events.js';\n\nimport { formatCount, formatDuration } from './format.js';\n\ntype Paint = (text: string) => string;\n\nexport interface Palette {\n\tblue: Paint;\n\tgray: Paint;\n\tgreen: Paint;\n\tmagenta: Paint;\n\tred: Paint;\n\tyellow: Paint;\n}\n\ntype EndEvent = Extract<OutputEvent, { type: 'end' }>;\n\ntype TerminalState = Exclude<StatusState, 'start' | 'stop' | 'update'>;\n\nfunction unpainted(text: string) {\n\treturn text;\n}\n\nexport const plainPalette: Palette = {\n\tblue: unpainted,\n\tgray: unpainted,\n\tgreen: unpainted,\n\tmagenta: unpainted,\n\tred: unpainted,\n\tyellow: unpainted,\n};\n\nexport function getStateSymbol(state: TerminalState, palette: Palette) {\n\tif (state === 'succeed') return palette.green('✓');\n\tif (state === 'fail') return palette.red('✗');\n\n\treturn palette.yellow('⚠');\n}\n\nexport function formatMessage(level: MessageLevel, text: string, palette: Palette) {\n\tswitch (level) {\n\t\tcase 'detail': {\n\t\t\treturn palette.gray(` ${text}`);\n\t\t}\n\t\tcase 'error': {\n\t\t\treturn `${getStateSymbol('fail', palette)} ${palette.red(text)}`;\n\t\t}\n\t\tcase 'info': {\n\t\t\treturn text;\n\t\t}\n\t\tcase 'step': {\n\t\t\treturn palette.blue(text);\n\t\t}\n\t\tcase 'success': {\n\t\t\treturn `${getStateSymbol('succeed', palette)} ${text}`;\n\t\t}\n\t\tcase 'title': {\n\t\t\treturn palette.magenta(`=== ${text} ===`);\n\t\t}\n\t\tcase 'warn': {\n\t\t\treturn `${getStateSymbol('warn', palette)} ${palette.yellow(text)}`;\n\t\t}\n\t}\n}\n\nexport function formatSummaryRows(rows: Array<SummaryRow>, palette: Palette) {\n\tconst width = Math.max(...rows.map(([label]) => label.length)) + 2;\n\n\treturn rows.map(([label, value]) => {\n\t\tconst formatted = typeof value === 'number' ? formatCount(value) : value;\n\n\t\treturn ` ${palette.gray(`${label}:`.padEnd(width))}${formatted}`;\n\t});\n}\n\nexport function formatData(value: unknown) {\n\treturn typeof value === 'string' ? value : JSON.stringify(value, undefined, 2);\n}\n\nexport function formatEnd(event: EndEvent, palette: Palette) {\n\tif (event.status === 'ok') {\n\t\treturn [formatMessage('detail', `Finished in ${formatDuration(event.durationMs)}`, palette)];\n\t}\n\n\tconst level = event.status === 'failed' || event.forced ? 'error' : 'warn';\n\tconst lines = event.message === undefined ? [] : [formatMessage(level, event.message, palette)];\n\n\tif (event.detail) lines.push(formatMessage('detail', event.detail, palette));\n\n\treturn lines;\n}\n","import { stripVTControlCharacters } from 'node:util';\n\nimport type { Reporter, ReporterStreams } from './events.js';\n\nimport { formatProgressText } from './format.js';\nimport {\n\tformatData,\n\tformatEnd,\n\tformatMessage,\n\tformatSummaryRows,\n\tgetStateSymbol,\n\tplainPalette,\n} from './human-format.js';\n\ninterface OpenStatus {\n\tlastPrint: number;\n\ttext: string;\n}\n\nconst progressIntervalMs = 10_000;\n\nexport function createPlainReporter(\n\t{ stderr, stdout }: ReporterStreams,\n\tnow: () => number = Date.now,\n): Reporter {\n\tconst statuses = new Map<number, OpenStatus>();\n\tlet activeId: number | undefined;\n\n\tfunction writeLine(line: string) {\n\t\tstderr.write(`${stripVTControlCharacters(line)}\\n`);\n\t}\n\n\tfunction closeStatus(id: number) {\n\t\tstatuses.delete(id);\n\n\t\tif (activeId === id) activeId = undefined;\n\t}\n\n\treturn {\n\t\temit(event) {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase 'data': {\n\t\t\t\t\tstdout.write(`${formatData(event.value)}\\n`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'end': {\n\t\t\t\t\tconst active = activeId === undefined ? undefined : statuses.get(activeId);\n\n\t\t\t\t\tif (active && activeId !== undefined && event.status !== 'ok') {\n\t\t\t\t\t\twriteLine(`${getStateSymbol('fail', plainPalette)} ${active.text}`);\n\t\t\t\t\t\tcloseStatus(activeId);\n\t\t\t\t\t}\n\n\t\t\t\t\tfor (const line of formatEnd(event, plainPalette)) writeLine(line);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'message': {\n\t\t\t\t\twriteLine(formatMessage(event.level, event.text, plainPalette));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'progress': {\n\t\t\t\t\tconst status = statuses.get(event.id);\n\t\t\t\t\tconst time = now();\n\n\t\t\t\t\tif (!status || time - status.lastPrint < progressIntervalMs) break;\n\n\t\t\t\t\tstatus.lastPrint = time;\n\t\t\t\t\twriteLine(formatProgressText(event));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'start': {\n\t\t\t\t\twriteLine(formatMessage('title', event.title, plainPalette));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'status': {\n\t\t\t\t\tconst { id, state, text } = event;\n\n\t\t\t\t\tif (state === 'start') {\n\t\t\t\t\t\tstatuses.set(id, { lastPrint: now(), text });\n\t\t\t\t\t\tactiveId = id;\n\t\t\t\t\t\twriteLine(text);\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst status = statuses.get(id);\n\n\t\t\t\t\tif (!status) break;\n\n\t\t\t\t\tif (state === 'update') {\n\t\t\t\t\t\tstatus.text = text;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (state !== 'stop') writeLine(`${getStateSymbol(state, plainPalette)} ${text}`);\n\n\t\t\t\t\tcloseStatus(id);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'summary': {\n\t\t\t\t\tfor (const line of formatSummaryRows(event.rows, plainPalette)) writeLine(line);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n","import type { Ora } from 'ora';\n\nimport chalk from 'chalk';\nimport ora from 'ora';\n\nimport type { OutputEvent, Reporter, ReporterStreams, StatusState } from './events.js';\n\nimport { formatProgressText } from './format.js';\nimport {\n\tformatData,\n\tformatEnd,\n\tformatMessage,\n\tformatSummaryRows,\n\tgetStateSymbol,\n} from './human-format.js';\n\ntype StatusEvent = Extract<OutputEvent, { type: 'status' }>;\n\nexport function createPrettyReporter({ stderr, stdout }: ReporterStreams): Reporter {\n\tconst spinners = new Map<number, Ora>();\n\tlet activeId: number | undefined;\n\n\tfunction getActiveSpinner() {\n\t\treturn activeId === undefined ? undefined : spinners.get(activeId);\n\t}\n\n\tfunction writeLine(line: string) {\n\t\tconst active = getActiveSpinner();\n\n\t\tif (!active?.isSpinning) {\n\t\t\tstderr.write(`${line}\\n`);\n\t\t\treturn;\n\t\t}\n\n\t\tactive.clear();\n\t\tstderr.write(`${line}\\n`);\n\t\tactive.render();\n\t}\n\n\tfunction endSpinner(id: number, state: Exclude<StatusState, 'start' | 'update'>, text: string) {\n\t\tconst spinner = spinners.get(id);\n\n\t\tif (!spinner) return;\n\n\t\tif (state === 'stop') {\n\t\t\tspinner.stop();\n\t\t} else {\n\t\t\tspinner.stopAndPersist({ symbol: getStateSymbol(state, chalk), text });\n\t\t}\n\n\t\tspinners.delete(id);\n\n\t\tif (activeId === id) activeId = undefined;\n\t}\n\n\tfunction onStatus({ id, state, text }: StatusEvent) {\n\t\tif (state === 'start') {\n\t\t\tgetActiveSpinner()?.stop();\n\t\t\t// Stdin stays cooked so the terminal still signals the whole process group on Ctrl-C, child processes included\n\t\t\tspinners.set(id, ora({ discardStdin: false, stream: stderr, text }).start());\n\t\t\tactiveId = id;\n\t\t\treturn;\n\t\t}\n\n\t\tif (state === 'update') {\n\t\t\tconst spinner = spinners.get(id);\n\n\t\t\tif (spinner) spinner.text = text;\n\t\t\treturn;\n\t\t}\n\n\t\tendSpinner(id, state, text);\n\t}\n\n\treturn {\n\t\temit(event) {\n\t\t\tswitch (event.type) {\n\t\t\t\tcase 'data': {\n\t\t\t\t\tstdout.write(`${formatData(event.value)}\\n`);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'end': {\n\t\t\t\t\tconst active = getActiveSpinner();\n\n\t\t\t\t\tif (active && activeId !== undefined && event.status !== 'ok') {\n\t\t\t\t\t\tendSpinner(activeId, 'fail', active.text);\n\t\t\t\t\t}\n\n\t\t\t\t\t// An open spinner's render interval keeps the process alive\n\t\t\t\t\tfor (const spinner of spinners.values()) spinner.stop();\n\n\t\t\t\t\tspinners.clear();\n\t\t\t\t\tactiveId = undefined;\n\n\t\t\t\t\tfor (const line of formatEnd(event, chalk)) writeLine(line);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'message': {\n\t\t\t\t\twriteLine(formatMessage(event.level, event.text, chalk));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'progress': {\n\t\t\t\t\tconst spinner = spinners.get(event.id);\n\n\t\t\t\t\tif (spinner) spinner.text = formatProgressText(event);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'start': {\n\t\t\t\t\twriteLine(formatMessage('title', event.title, chalk));\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'status': {\n\t\t\t\t\tonStatus(event);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tcase 'summary': {\n\t\t\t\t\tfor (const line of formatSummaryRows(event.rows, chalk)) writeLine(line);\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t};\n}\n","import type { MessageLevel, OutputEvent, Reporter, SummaryRow } from './events.js';\n\nimport { createJsonReporter } from './reporter-json.js';\nimport { createPlainReporter } from './reporter-plain.js';\nimport { createPrettyReporter } from './reporter-pretty.js';\n\nexport type OutputMode = 'json' | 'plain' | 'pretty';\n\nconst outputModes = new Set<unknown>(['json', 'plain', 'pretty'] satisfies Array<OutputMode>);\n\nlet currentMode: OutputMode | undefined;\nlet currentReporter: Reporter | undefined;\nlet nextStatusId = 1;\n\nexport function isOutputMode(value: unknown): value is OutputMode {\n\treturn outputModes.has(value);\n}\n\nfunction detectOutputMode(): OutputMode {\n\tconst requested = process.env.SCRIPTS_OUTPUT;\n\n\tif (isOutputMode(requested)) return requested;\n\n\treturn process.stderr.isTTY ? 'pretty' : 'plain';\n}\n\nfunction createReporter(mode: OutputMode, command?: string) {\n\tconst streams = { stderr: process.stderr, stdout: process.stdout };\n\n\tif (mode === 'json') return createJsonReporter(streams, { command });\n\tif (mode === 'plain') return createPlainReporter(streams);\n\n\treturn createPrettyReporter(streams);\n}\n\nexport function configureOutput(mode: OutputMode = detectOutputMode(), command?: string) {\n\tcurrentMode = mode;\n\tcurrentReporter = createReporter(mode, command);\n}\n\nexport function getOutputMode() {\n\tif (currentMode === undefined) currentMode = detectOutputMode();\n\n\treturn currentMode;\n}\n\nexport function emit(event: OutputEvent) {\n\tif (currentReporter === undefined) currentReporter = createReporter(getOutputMode());\n\n\tcurrentReporter.emit(event);\n}\n\nfunction emitMessage(level: MessageLevel, text: string) {\n\temit({ level, text, type: 'message' });\n}\n\nexport const log = {\n\tdata(value: unknown) {\n\t\temit({ type: 'data', value });\n\t},\n\tdetail(text: string) {\n\t\temitMessage('detail', text);\n\t},\n\terror(text: string) {\n\t\temitMessage('error', text);\n\t},\n\tinfo(text: string) {\n\t\temitMessage('info', text);\n\t},\n\tstep(text: string) {\n\t\temitMessage('step', text);\n\t},\n\tsuccess(text: string) {\n\t\temitMessage('success', text);\n\t},\n\tsummary(rows: Array<SummaryRow>) {\n\t\temit({ rows, type: 'summary' });\n\t},\n\ttitle(text: string) {\n\t\temitMessage('title', text);\n\t},\n\twarn(text: string) {\n\t\temitMessage('warn', text);\n\t},\n};\n\nexport function startStatus(initialText: string) {\n\tconst id = nextStatusId;\n\tlet text = initialText;\n\n\tnextStatusId += 1;\n\temit({ id, state: 'start', text, type: 'status' });\n\n\tfunction finish(state: 'fail' | 'stop' | 'succeed' | 'warn', finalText?: string) {\n\t\ttext = finalText ?? text;\n\t\temit({ id, state, text, type: 'status' });\n\t}\n\n\tconst status = {\n\t\tfail(finalText?: string) {\n\t\t\tfinish('fail', finalText);\n\t\t},\n\t\tstop() {\n\t\t\tfinish('stop');\n\t\t},\n\t\tsucceed(finalText?: string) {\n\t\t\tfinish('succeed', finalText);\n\t\t},\n\t\tupdate(nextText: string) {\n\t\t\ttext = nextText;\n\t\t\temit({ id, state: 'update', text, type: 'status' });\n\t\t},\n\t\twarn(finalText?: string) {\n\t\t\tfinish('warn', finalText);\n\t\t},\n\t};\n\n\treturn { id, status };\n}\n\nexport function createStatus(text: string) {\n\treturn startStatus(text).status;\n}\n","// Matched by `name`, so a library's own `Refusal` class reports the same way\nexport class Refusal extends Error {\n\toverride name = 'Refusal';\n}\n\nexport function isRefusal(error: unknown): error is Error {\n\treturn error instanceof Error && error.name === 'Refusal';\n}\n","import { existsSync } from 'node:fs';\nimport path from 'node:path';\n\nexport function findWorkspaceRoot(startDir = process.cwd()) {\n\tlet current = path.resolve(startDir);\n\n\twhile (current !== path.dirname(current)) {\n\t\tif (existsSync(path.join(current, 'pnpm-workspace.yaml'))) return current;\n\n\t\tcurrent = path.dirname(current);\n\t}\n\n\tthrow new Error(`Could not locate pnpm-workspace.yaml above ${startDir}`);\n}\n","import type { ParseArgsOptionDescriptor } from 'node:util';\n\nimport chalk from 'chalk';\nimport { parseArgs } from 'node:util';\n\nimport { configureOutput, emit, isOutputMode, log } from './output/output.js';\nimport { isRefusal, Refusal } from './refusal.js';\nimport { findWorkspaceRoot } from './workspace.js';\n\ntype CommandOption = ParseArgsOptionDescriptor & { description: string };\n\ntype CommandOptions = Record<string, CommandOption>;\n\ninterface CommandPositional {\n\tdescription: string;\n\tname: string;\n}\n\ntype ParsedValues<Options extends CommandOptions> = ReturnType<\n\ttypeof parseArgs<{ allowPositionals: true; options: Options; strict: true }>\n>['values'];\n\ninterface CommandDescription {\n\tname: string;\n\toptions?: CommandOptions;\n\tpositional?: CommandPositional;\n\tsummary: string;\n\ttitle: string;\n}\n\nexport interface CommandContext<Options extends CommandOptions> {\n\tpositionals: Array<string>;\n\trootPath: string;\n\tsignal: AbortSignal;\n\tvalues: ParsedValues<Options>;\n}\n\nexport interface Command<Options extends CommandOptions, Context> extends CommandDescription {\n\tinterrupted?: string;\n\toptions?: Options;\n\trun: (context: CommandContext<Options> & Context) => Promise<void> | void;\n}\n\ninterface CommandRunnerOptions<Context> {\n\tcontext?: (base: { rootPath: string }) => Context | Promise<Context>;\n\tusagePrefix?: string;\n}\n\ninterface ChildProcessFailure extends Error {\n\texitCode: null | number | undefined;\n\tsignal: null | string | undefined;\n}\n\ninterface FailureReport {\n\tdetail?: string;\n\texitCode: number;\n\tisInterrupted: boolean;\n\tmessage: string;\n}\n\nconst interruptedExitCode = 130;\nconst interruptBurstMs = 1000;\n\nconst jsonOption = {\n\tdescription: 'Print output as JSON lines',\n\ttype: 'boolean',\n} as const satisfies CommandOption;\n\nconst helpOption = {\n\tdescription: 'Show this help',\n\tshort: 'h',\n\ttype: 'boolean',\n} as const satisfies CommandOption;\n\nconst builtInOptions: Array<[string, CommandOption]> = [\n\t['json', jsonOption],\n\t['help', helpOption],\n];\n\nexport function parseNumberOption(value: string, name: string) {\n\tconst parsed = Number(value);\n\n\tif (value.trim() === '' || !Number.isFinite(parsed))\n\t\tthrow new Refusal(`--${name} expects a number, got \"${value}\"`);\n\n\treturn parsed;\n}\n\nfunction getUsage(command: CommandDescription, usagePrefix: string) {\n\tconst positional = command.positional ? ` [${command.positional.name}]` : '';\n\n\treturn `${usagePrefix} ${command.name}${positional} [options]`;\n}\n\nfunction getOptionLabel(name: string, option: CommandOption) {\n\tconst flag = option.short ? `-${option.short}, --${name}` : ` --${name}`;\n\n\treturn option.type === 'string' ? `${flag} <value>` : flag;\n}\n\nfunction getOptionDescription(option: CommandOption) {\n\tconst { default: defaultValue, description } = option;\n\n\tif (defaultValue === undefined || defaultValue === false) return description;\n\tif (Array.isArray(defaultValue) && defaultValue.length === 0) return description;\n\n\treturn `${description} (default: ${String(defaultValue)})`;\n}\n\nexport function formatHelp(command: CommandDescription, usagePrefix = 'pnpm') {\n\tconst options = [...Object.entries(command.options ?? {}), ...builtInOptions];\n\tconst rows: Array<[string, string]> = options.map(([name, option]) => [\n\t\tgetOptionLabel(name, option),\n\t\tgetOptionDescription(option),\n\t]);\n\n\tif (command.positional) {\n\t\trows.unshift([command.positional.name, command.positional.description]);\n\t}\n\n\tconst width = Math.max(...rows.map(([label]) => label.length)) + 2;\n\n\treturn [\n\t\tchalk.magenta(command.title),\n\t\tcommand.summary,\n\t\t'',\n\t\t`Usage: ${getUsage(command, usagePrefix)}`,\n\t\t'',\n\t\t...rows.map(([label, description]) => ` ${label.padEnd(width)}${chalk.gray(description)}`),\n\t].join('\\n');\n}\n\nfunction isParseError(error: unknown): error is Error {\n\treturn (\n\t\terror instanceof Error &&\n\t\t'code' in error &&\n\t\ttypeof error.code === 'string' &&\n\t\terror.code.startsWith('ERR_PARSE_ARGS_')\n\t);\n}\n\n// Matched by shape, which covers zx's `ProcessOutput` and execa's `ExecaError` alike\nfunction isChildProcessFailure(error: unknown): error is ChildProcessFailure {\n\treturn error instanceof Error && 'exitCode' in error && 'signal' in error;\n}\n\nfunction isInterruption(error: unknown, isAborted: boolean) {\n\tif (isAborted) return true;\n\n\treturn (\n\t\tisChildProcessFailure(error) &&\n\t\t(error.exitCode === interruptedExitCode || error.signal === 'SIGINT')\n\t);\n}\n\nfunction describeError(error: unknown): Pick<FailureReport, 'detail' | 'message'> {\n\tif (isParseError(error)) return { detail: 'See --help', message: error.message };\n\n\tif (isRefusal(error)) return { message: error.message };\n\n\tif (isChildProcessFailure(error)) {\n\t\tconst reason = error.signal\n\t\t\t? `was killed by ${error.signal}`\n\t\t\t: `exited with code ${String(error.exitCode)}`;\n\n\t\treturn { message: `Child process ${reason}` };\n\t}\n\n\tif (!(error instanceof Error)) return { message: String(error) };\n\n\tconst stack = error.stack?.split('\\n').slice(1).join('\\n');\n\n\treturn stack ? { detail: stack, message: error.message } : { message: error.message };\n}\n\nexport function getFailureReport(\n\terror: unknown,\n\t{ interrupted, isAborted }: { interrupted?: string | undefined; isAborted: boolean },\n): FailureReport {\n\tif (isInterruption(error, isAborted)) {\n\t\treturn {\n\t\t\texitCode: interruptedExitCode,\n\t\t\tisInterrupted: true,\n\t\t\tmessage: interrupted ? `Interrupted; ${interrupted}` : 'Interrupted',\n\t\t};\n\t}\n\n\treturn { exitCode: 1, isInterrupted: false, ...describeError(error) };\n}\n\nfunction parseCommandArgs(command: CommandDescription) {\n\tconst options = [...Object.entries(command.options ?? {}), ...builtInOptions];\n\n\treturn parseArgs({\n\t\tallowPositionals: command.positional !== undefined,\n\t\targs: process.argv.slice(2),\n\t\toptions: Object.fromEntries(\n\t\t\toptions.map(([name, { description: _description, ...descriptor }]) => [name, descriptor]),\n\t\t),\n\t\tstrict: true,\n\t});\n}\n\nfunction selectOutput(isJson: boolean) {\n\tif (isJson) {\n\t\t// Nested commands inherit this and join one stream\n\t\tprocess.env.SCRIPTS_OUTPUT = 'json';\n\t\treturn;\n\t}\n\n\tconst requested = process.env.SCRIPTS_OUTPUT;\n\n\tif (requested && !isOutputMode(requested)) {\n\t\tthrow new Refusal(`SCRIPTS_OUTPUT must be pretty, plain or json, got \"${requested}\"`);\n\t}\n}\n\nexport function createCommandRunner<Context extends object = object>(\n\trunnerOptions: CommandRunnerOptions<Context> = {},\n) {\n\tconst { context: createContext, usagePrefix = 'pnpm' } = runnerOptions;\n\n\tfunction defineCommand<const Options extends CommandOptions>(command: Command<Options, Context>) {\n\t\treturn command;\n\t}\n\n\tasync function runCommand<const Options extends CommandOptions>(\n\t\tcommand: Command<Options, Context>,\n\t) {\n\t\tconst controller = new AbortController();\n\t\tconst startTime = Date.now();\n\t\tlet interruptTime: number | undefined;\n\t\t// Read before parsing, so a parse error in a `--json` run still reports as JSON\n\t\tconst isJson = process.argv.slice(2).includes('--json');\n\n\t\tconfigureOutput(isJson ? 'json' : undefined, command.name);\n\n\t\t// One Ctrl-C arrives as a burst: the terminal's SIGINT, pnpm's forwarded copy, and a SIGTERM per nested pnpm\n\t\tfunction onInterrupt() {\n\t\t\tif (interruptTime === undefined) {\n\t\t\t\tinterruptTime = Date.now();\n\t\t\t\tcontroller.abort();\n\t\t\t\tlog.warn('Stopping; press Ctrl-C again to force quit');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif (Date.now() - interruptTime < interruptBurstMs) return;\n\n\t\t\temit({\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\texitCode: interruptedExitCode,\n\t\t\t\tforced: true,\n\t\t\t\tmessage: 'Force quit',\n\t\t\t\tstatus: 'interrupted',\n\t\t\t\ttype: 'end',\n\t\t\t});\n\t\t\t// eslint-disable-next-line unicorn/no-process-exit -- a second Ctrl-C must quit even while the command still holds the event loop\n\t\t\tprocess.exit(interruptedExitCode);\n\t\t}\n\n\t\tprocess.on('SIGINT', onInterrupt);\n\t\tprocess.on('SIGTERM', onInterrupt);\n\n\t\ttry {\n\t\t\tconst { positionals, values } = parseCommandArgs(command);\n\n\t\t\tif (values.help) {\n\t\t\t\tprocess.stdout.write(`${formatHelp(command, usagePrefix)}\\n`);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tselectOutput(isJson);\n\t\t\temit({ title: command.title, type: 'start' });\n\n\t\t\tconst rootPath = findWorkspaceRoot();\n\t\t\t// `Context` is only left at its empty default when no factory is given\n\t\t\tconst context = createContext ? await createContext({ rootPath }) : ({} as Context);\n\n\t\t\tawait command.run({\n\t\t\t\t...context,\n\t\t\t\tpositionals,\n\t\t\t\trootPath,\n\t\t\t\tsignal: controller.signal,\n\t\t\t\tvalues: values as ParsedValues<Options>,\n\t\t\t});\n\n\t\t\t// A command that honours the signal by returning early was still interrupted\n\t\t\tcontroller.signal.throwIfAborted();\n\n\t\t\temit({ durationMs: Date.now() - startTime, exitCode: 0, status: 'ok', type: 'end' });\n\t\t} catch (error) {\n\t\t\tconst report = getFailureReport(error, {\n\t\t\t\tinterrupted: command.interrupted,\n\t\t\t\tisAborted: controller.signal.aborted,\n\t\t\t});\n\n\t\t\temit({\n\t\t\t\t...(report.detail === undefined ? {} : { detail: report.detail }),\n\t\t\t\tdurationMs: Date.now() - startTime,\n\t\t\t\texitCode: report.exitCode,\n\t\t\t\tmessage: report.message,\n\t\t\t\tstatus: report.isInterrupted ? 'interrupted' : 'failed',\n\t\t\t\ttype: 'end',\n\t\t\t});\n\n\t\t\tprocess.exitCode = report.exitCode;\n\t\t} finally {\n\t\t\tprocess.off('SIGINT', onInterrupt);\n\t\t\tprocess.off('SIGTERM', onInterrupt);\n\t\t}\n\t}\n\n\treturn { defineCommand, runCommand };\n}\n","import type { ProgressSnapshot } from './format.js';\n\nimport { formatProgressText } from './format.js';\nimport { createStatus, emit, startStatus } from './output.js';\n\ninterface ProgressOptions {\n\tlabel: string;\n\tnote?: () => string;\n\ttotal: number;\n}\n\ninterface RateSample {\n\tcount: number;\n\ttime: number;\n}\n\nconst renderIntervalMs = 100;\nconst rateWindowMs = 10_000;\n\nexport function createRateWindow(windowMs = rateWindowMs) {\n\tconst samples: Array<RateSample> = [];\n\n\treturn {\n\t\tadd(count: number, time: number) {\n\t\t\tsamples.push({ count, time });\n\n\t\t\twhile (samples.length > 2 && time - (samples[0]?.time ?? time) > windowMs) samples.shift();\n\t\t},\n\t\tperSecond() {\n\t\t\tconst first = samples.at(0);\n\t\t\tconst last = samples.at(-1);\n\n\t\t\tif (!first || !last || last.time <= first.time) return;\n\n\t\t\treturn ((last.count - first.count) * 1000) / (last.time - first.time);\n\t\t},\n\t};\n}\n\nexport function createProgress({ label, note, total }: ProgressOptions) {\n\tconst rateWindow = createRateWindow();\n\tconst startTime = Date.now();\n\tlet done = 0;\n\tlet lastRender = 0;\n\n\trateWindow.add(0, startTime);\n\n\tfunction getSnapshot(): ProgressSnapshot {\n\t\tconst noteText = note?.();\n\t\tconst perSecond = rateWindow.perSecond();\n\n\t\treturn {\n\t\t\tdone,\n\t\t\tlabel,\n\t\t\ttotal,\n\t\t\t...(noteText ? { note: noteText } : {}),\n\t\t\t...(perSecond === undefined ? {} : { perSecond }),\n\t\t};\n\t}\n\n\tconst { id, status } = startStatus(formatProgressText(getSnapshot()));\n\n\tfunction render() {\n\t\tconst now = Date.now();\n\n\t\tif (now - lastRender < renderIntervalMs) return;\n\n\t\tlastRender = now;\n\t\trateWindow.add(done, now);\n\t\temit({ id, type: 'progress', ...getSnapshot() });\n\t}\n\n\tfunction finish(state: 'fail' | 'succeed' | 'warn', text?: string) {\n\t\tconst snapshot = getSnapshot();\n\n\t\temit({ id, type: 'progress', ...snapshot });\n\t\tstatus[state](text ?? formatProgressText(snapshot));\n\t}\n\n\treturn {\n\t\tfail(text?: string) {\n\t\t\tfinish('fail', text);\n\t\t},\n\t\tsucceed(text?: string) {\n\t\t\tfinish('succeed', text);\n\t\t},\n\t\ttick(count = 1) {\n\t\t\tdone += count;\n\t\t\trender();\n\t\t},\n\t\twarn(text?: string) {\n\t\t\tfinish('warn', text);\n\t\t},\n\t};\n}\n\n// A failure leaves the status open for `runCommand` to mark as failed\nexport async function withStatus<Result>(text: string, task: () => Promise<Result>) {\n\tconst status = createStatus(text);\n\tconst result = await task();\n\n\tstatus.stop();\n\n\treturn result;\n}\n\nexport async function withSpinner<Result>(\n\ttext: string,\n\ttask: () => Promise<Result>,\n\tdescribe?: (result: Result) => string,\n) {\n\tconst status = createStatus(text);\n\n\ttry {\n\t\tconst result = await task();\n\n\t\tstatus.succeed(describe?.(result) ?? text);\n\n\t\treturn result;\n\t} catch (error) {\n\t\tstatus.fail(text);\n\t\tthrow error;\n\t}\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,68 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xsynaptic/astro-scripts",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Plumbing for an Astro project's scripts package: a command runner, output with interchangeable reporters, and a bridge into Astro's content layer",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "Alexander Synaptic <x@synapticism.com>",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/xsynaptic/astro-lab.git",
|
|
11
|
+
"directory": "packages/astro-scripts"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/xsynaptic/astro-lab/tree/main/packages/astro-scripts#readme",
|
|
14
|
+
"bugs": {
|
|
15
|
+
"url": "https://github.com/xsynaptic/astro-lab/issues"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"astro",
|
|
19
|
+
"withastro",
|
|
20
|
+
"cli",
|
|
21
|
+
"scripts",
|
|
22
|
+
"content-collections",
|
|
23
|
+
"vite"
|
|
24
|
+
],
|
|
25
|
+
"main": "./dist/index.mjs",
|
|
26
|
+
"types": "./dist/index.d.mts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./dist/index.d.mts",
|
|
30
|
+
"import": "./dist/index.mjs"
|
|
31
|
+
},
|
|
32
|
+
"./astro": {
|
|
33
|
+
"types": "./dist/astro.d.mts",
|
|
34
|
+
"import": "./dist/astro.mjs"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"files": [
|
|
38
|
+
"dist"
|
|
39
|
+
],
|
|
40
|
+
"sideEffects": false,
|
|
41
|
+
"dependencies": {
|
|
42
|
+
"chalk": "^6.0.1",
|
|
43
|
+
"ora": "^9.4.1"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"astro": "^7.0.0",
|
|
47
|
+
"vite": "^8.0.0"
|
|
48
|
+
},
|
|
49
|
+
"peerDependenciesMeta": {
|
|
50
|
+
"astro": {
|
|
51
|
+
"optional": true
|
|
52
|
+
},
|
|
53
|
+
"vite": {
|
|
54
|
+
"optional": true
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@types/node": "^24.19.2",
|
|
59
|
+
"astro": "^7.4.2",
|
|
60
|
+
"vite": "^8.3.5",
|
|
61
|
+
"zx": "^8.8.5"
|
|
62
|
+
},
|
|
63
|
+
"scripts": {
|
|
64
|
+
"build": "tsdown",
|
|
65
|
+
"dev": "tsdown --watch",
|
|
66
|
+
"check-types": "tsc --noEmit"
|
|
67
|
+
}
|
|
6
68
|
}
|