@procedures/mark 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/CHANGELOG.md +5 -0
- package/LICENSE +21 -0
- package/README.md +799 -2
- package/dist/.tsbuildinfo +1 -0
- package/dist/args.d.ts +77 -0
- package/dist/args.d.ts.map +1 -0
- package/dist/args.js +351 -0
- package/dist/args.js.map +1 -0
- package/dist/ask.d.ts +48 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +91 -0
- package/dist/ask.js.map +1 -0
- package/dist/bin.d.ts +9 -0
- package/dist/bin.d.ts.map +1 -0
- package/dist/bin.js +10 -0
- package/dist/bin.js.map +1 -0
- package/dist/cli.d.ts +61 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +530 -0
- package/dist/cli.js.map +1 -0
- package/dist/client-mode.d.ts +21 -0
- package/dist/client-mode.d.ts.map +1 -0
- package/dist/client-mode.js +75 -0
- package/dist/client-mode.js.map +1 -0
- package/dist/ecosystem.d.ts +66 -0
- package/dist/ecosystem.d.ts.map +1 -0
- package/dist/ecosystem.js +211 -0
- package/dist/ecosystem.js.map +1 -0
- package/dist/failure.d.ts +16 -0
- package/dist/failure.d.ts.map +1 -0
- package/dist/failure.js +47 -0
- package/dist/failure.js.map +1 -0
- package/dist/format.d.ts +30 -0
- package/dist/format.d.ts.map +1 -0
- package/dist/format.js +125 -0
- package/dist/format.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -0
- package/dist/lockfile.d.ts +26 -0
- package/dist/lockfile.d.ts.map +1 -0
- package/dist/lockfile.js +68 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/manifest-build.d.ts +7 -0
- package/dist/manifest-build.d.ts.map +1 -0
- package/dist/manifest-build.js +11 -0
- package/dist/manifest-build.js.map +1 -0
- package/dist/manifest.d.ts +57 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +140 -0
- package/dist/manifest.js.map +1 -0
- package/dist/manifest.json +20885 -0
- package/dist/parse.d.ts +143 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +509 -0
- package/dist/parse.js.map +1 -0
- package/dist/print.d.ts +42 -0
- package/dist/print.d.ts.map +1 -0
- package/dist/print.js +80 -0
- package/dist/print.js.map +1 -0
- package/dist/prompts.d.ts +58 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +124 -0
- package/dist/prompts.js.map +1 -0
- package/dist/repl.d.ts +34 -0
- package/dist/repl.d.ts.map +1 -0
- package/dist/repl.js +101 -0
- package/dist/repl.js.map +1 -0
- package/dist/server-mode.d.ts +37 -0
- package/dist/server-mode.d.ts.map +1 -0
- package/dist/server-mode.js +167 -0
- package/dist/server-mode.js.map +1 -0
- package/package.json +97 -3
- package/src/args.ts +440 -0
- package/src/ask.ts +119 -0
- package/src/bin.ts +11 -0
- package/src/cli.ts +596 -0
- package/src/client-mode.ts +90 -0
- package/src/ecosystem.ts +258 -0
- package/src/failure.ts +47 -0
- package/src/format.ts +177 -0
- package/src/index.ts +31 -0
- package/src/lockfile.ts +85 -0
- package/src/manifest-build.ts +12 -0
- package/src/manifest.ts +162 -0
- package/src/parse.ts +670 -0
- package/src/print.ts +108 -0
- package/src/prompts.ts +181 -0
- package/src/repl.ts +121 -0
- package/src/server-mode.ts +205 -0
package/dist/lockfile.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lockfiles of the CLI server: `mark` uses the shared module of `client-server`, so `mark` and the
|
|
3
|
+
* `server.*` procedures read and write the same files the same way (deep dive CLI-4). This module
|
|
4
|
+
* adds what only `mark` needs: the log file and the build id.
|
|
5
|
+
*/
|
|
6
|
+
import * as fs from "node:fs";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import { fileURLToPath } from "node:url";
|
|
9
|
+
import { checkServer, findServer, getMarkDir, getServersDir, readAllLockfiles, readLockfileForPort, removeLockfileForPort, writeLockfile as writeSharedLockfile, } from "@procedures/peer/lockfile";
|
|
10
|
+
export { checkServer, findServer, readAllLockfiles, readLockfileForPort, removeLockfileForPort };
|
|
11
|
+
const LOG_PATH = path.join(getMarkDir(), "server.log");
|
|
12
|
+
const LOG_PREV_PATH = path.join(getMarkDir(), "server.log.1");
|
|
13
|
+
/**
|
|
14
|
+
* The build of this `mark`: its file and the time of its last build. A warm server runs only the
|
|
15
|
+
* commands of the same build (deep dive CLI-14): after `pnpm build`, or from another checkout,
|
|
16
|
+
* the CLI runs the command itself.
|
|
17
|
+
*/
|
|
18
|
+
export function currentBuild() {
|
|
19
|
+
const file = fileURLToPath(import.meta.url);
|
|
20
|
+
try {
|
|
21
|
+
return `${file}@${fs.statSync(file).mtimeMs}`;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return file;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export async function writeLockfile(data) {
|
|
28
|
+
writeSharedLockfile(data);
|
|
29
|
+
}
|
|
30
|
+
/** The first lockfile whose server answers as its peer (any folder, any build). */
|
|
31
|
+
export async function readLockfile() {
|
|
32
|
+
for (const data of readAllLockfiles()) {
|
|
33
|
+
if (await isServerAlive(data))
|
|
34
|
+
return data;
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
/** True when the lockfile's server answers as its peer. A dead server's lockfile is removed. */
|
|
39
|
+
export async function isServerAlive(lockfile) {
|
|
40
|
+
const state = await checkServer(lockfile);
|
|
41
|
+
if (state === "dead")
|
|
42
|
+
removeLockfileForPort(lockfile.port);
|
|
43
|
+
return state === "alive";
|
|
44
|
+
}
|
|
45
|
+
/** This function removes the lockfile of the default port (3000). */
|
|
46
|
+
export async function removeLockfile() {
|
|
47
|
+
removeLockfileForPort(3000);
|
|
48
|
+
}
|
|
49
|
+
export function getLockfileDir() {
|
|
50
|
+
return getMarkDir();
|
|
51
|
+
}
|
|
52
|
+
export function getLockfilePath() {
|
|
53
|
+
return getServersDir();
|
|
54
|
+
}
|
|
55
|
+
export function getLogPath() {
|
|
56
|
+
return LOG_PATH;
|
|
57
|
+
}
|
|
58
|
+
export async function rotateLogFile() {
|
|
59
|
+
try {
|
|
60
|
+
fs.mkdirSync(getMarkDir(), { recursive: true });
|
|
61
|
+
if (fs.existsSync(LOG_PATH))
|
|
62
|
+
fs.renameSync(LOG_PATH, LOG_PREV_PATH);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
// Ignore rotation errors
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=lockfile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lockfile.js","sourceRoot":"","sources":["../src/lockfile.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EACL,WAAW,EACX,UAAU,EACV,UAAU,EACV,aAAa,EACb,gBAAgB,EAChB,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,IAAI,mBAAmB,GAErC,MAAM,2BAA2B,CAAC;AAGnC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,CAAC;AAEjG,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,YAAY,CAAC,CAAC;AACvD,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,cAAc,CAAC,CAAC;AAE9D;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC;IAC5C,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,IAAI,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,CAAC;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAkB;IACpD,mBAAmB,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,KAAK,MAAM,IAAI,IAAI,gBAAgB,EAAE,EAAE,CAAC;QACtC,IAAI,MAAM,aAAa,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gGAAgG;AAChG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAsB;IACxD,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;IAC1C,IAAI,KAAK,KAAK,MAAM;QAAE,qBAAqB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC3D,OAAO,KAAK,KAAK,OAAO,CAAC;AAC3B,CAAC;AAED,qEAAqE;AACrE,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,qBAAqB,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,cAAc;IAC5B,OAAO,UAAU,EAAE,CAAC;AACtB,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,EAAE,CAAC;AACzB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,IAAI,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;YAAE,EAAE,CAAC,UAAU,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC;IACtE,CAAC;IAAC,MAAM,CAAC;QACP,yBAAyB;IAC3B,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build of mark runs this module after `tsc -b`: it builds the registry of the workspace
|
|
3
|
+
* (the module of each package, roadmap 3.1) and writes `dist/manifest.json` (see manifest.ts).
|
|
4
|
+
* mark depends on each package that has procedures, so they are built before it.
|
|
5
|
+
*/
|
|
6
|
+
export {};
|
|
7
|
+
//# sourceMappingURL=manifest-build.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-build.d.ts","sourceRoot":"","sources":["../src/manifest-build.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The build of mark runs this module after `tsc -b`: it builds the registry of the workspace
|
|
3
|
+
* (the module of each package, roadmap 3.1) and writes `dist/manifest.json` (see manifest.ts).
|
|
4
|
+
* mark depends on each package that has procedures, so they are built before it.
|
|
5
|
+
*/
|
|
6
|
+
import { loadEcosystemRegistry } from "./ecosystem.js";
|
|
7
|
+
import { manifestPath, writeManifest } from "./manifest.js";
|
|
8
|
+
const { registry, loaded } = await loadEcosystemRegistry(false, false);
|
|
9
|
+
const manifest = await writeManifest(registry.getAll());
|
|
10
|
+
console.log(`mark: ${manifestPath()} has ${manifest.commands.length} commands from ${loaded.length} packages`);
|
|
11
|
+
//# sourceMappingURL=manifest-build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest-build.js","sourceRoot":"","sources":["../src/manifest-build.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAE5D,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,qBAAqB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;AACvE,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;AACxD,OAAO,CAAC,GAAG,CAAC,SAAS,YAAY,EAAE,QAAQ,QAAQ,CAAC,QAAQ,CAAC,MAAM,kBAAkB,MAAM,CAAC,MAAM,WAAW,CAAC,CAAC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command manifest of mark (architecture review 3.6, roadmap 1.3).
|
|
3
|
+
*
|
|
4
|
+
* Before, each run of mark imported the procedure modules of every package (about 4 s), also to
|
|
5
|
+
* show the help or to send a command to the CLI server. The manifest holds what the command line
|
|
6
|
+
* needs without the procedures: the path, the CLI metadata, the fields of the input (with the
|
|
7
|
+
* types that the flag parser converts to) and the JSON Schema of the input. mark reads it first.
|
|
8
|
+
* It imports the procedures only to run a command in this process.
|
|
9
|
+
*
|
|
10
|
+
* The build of mark writes `dist/manifest.json`. A run checks the fingerprint of the manifest:
|
|
11
|
+
* the packages that declare `client.procedures` and the build information of each one, of the
|
|
12
|
+
* core, and of mark. When a package was built again, or added, or removed, the fingerprint
|
|
13
|
+
* changes: mark then loads the procedures as before and writes the manifest again.
|
|
14
|
+
*/
|
|
15
|
+
import { type AnyProcedure } from "@procedures/client";
|
|
16
|
+
import { type CLIMeta, type SchemaFieldInfo } from "./parse.js";
|
|
17
|
+
/**
|
|
18
|
+
* The format of the manifest. A change of the format makes old manifests stale.
|
|
19
|
+
* Version 2 adds `resultFields`.
|
|
20
|
+
*/
|
|
21
|
+
export declare const MANIFEST_VERSION = 2;
|
|
22
|
+
/** One command of the manifest */
|
|
23
|
+
export interface ManifestCommand {
|
|
24
|
+
path: string[];
|
|
25
|
+
/** The CLI metadata of the procedure (description, args, shorts, output, interactive) */
|
|
26
|
+
metadata: CLIMeta;
|
|
27
|
+
/** The fields of the input, as the flag parser and the help read them */
|
|
28
|
+
fields: SchemaFieldInfo[];
|
|
29
|
+
/** The JSON Schema of the input */
|
|
30
|
+
inputSchema: unknown;
|
|
31
|
+
/** The fields of the result, for the help (none when the result is not an object) */
|
|
32
|
+
resultFields: SchemaFieldInfo[];
|
|
33
|
+
}
|
|
34
|
+
export interface Manifest {
|
|
35
|
+
version: number;
|
|
36
|
+
/** The state of the builds that the manifest describes (see `computeFingerprint`) */
|
|
37
|
+
fingerprint: string;
|
|
38
|
+
generatedAt: string;
|
|
39
|
+
commands: ManifestCommand[];
|
|
40
|
+
}
|
|
41
|
+
/** The path of the manifest: in the dist folder of mark (also when this module runs from src) */
|
|
42
|
+
export declare function manifestPath(): string;
|
|
43
|
+
/**
|
|
44
|
+
* The fingerprint of the builds that the manifest depends on. `tsc -b` writes
|
|
45
|
+
* `dist/.tsbuildinfo` each time it builds a package, so a new build of any package changes it.
|
|
46
|
+
* For a package without that file, the procedures file counts. `tsc --noEmit` (the typecheck
|
|
47
|
+
* script) also writes that file when the sources changed after the last build: the manifest is
|
|
48
|
+
* then stale, and the next run of mark loads the procedures and writes it again.
|
|
49
|
+
*/
|
|
50
|
+
export declare function computeFingerprint(root?: string | null, markDir?: string): string;
|
|
51
|
+
/** The commands of the manifest, from the procedures of the registry */
|
|
52
|
+
export declare function commandsOf(procedures: readonly AnyProcedure[]): Promise<ManifestCommand[]>;
|
|
53
|
+
/** Write the manifest of these procedures for the current fingerprint (a temporary file, then a rename) */
|
|
54
|
+
export declare function writeManifest(procedures: readonly AnyProcedure[], file?: string): Promise<Manifest>;
|
|
55
|
+
/** The manifest when it exists and matches the current builds, or null */
|
|
56
|
+
export declare function readFreshManifest(file?: string): Manifest | null;
|
|
57
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAMH,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAErE,OAAO,EAA6C,KAAK,OAAO,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE3G;;;GAGG;AACH,eAAO,MAAM,gBAAgB,IAAI,CAAC;AAElC,kCAAkC;AAClC,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,yFAAyF;IACzF,QAAQ,EAAE,OAAO,CAAC;IAClB,yEAAyE;IACzE,MAAM,EAAE,eAAe,EAAE,CAAC;IAC1B,mCAAmC;IACnC,WAAW,EAAE,OAAO,CAAC;IACrB,qFAAqF;IACrF,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,QAAQ;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,qFAAqF;IACrF,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,eAAe,EAAE,CAAC;CAC7B;AAaD,iGAAiG;AACjG,wBAAgB,YAAY,IAAI,MAAM,CAErC;AAYD;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,GAAE,MAAM,GAAG,IAA0B,EAAE,OAAO,GAAE,MAAmB,GAAG,MAAM,CAalH;AAcD,wEAAwE;AACxE,wBAAsB,UAAU,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC,CAYhG;AAOD,2GAA2G;AAC3G,wBAAsB,aAAa,CAAC,UAAU,EAAE,SAAS,YAAY,EAAE,EAAE,IAAI,GAAE,MAAuB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAgBzH;AAED,0EAA0E;AAC1E,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,MAAuB,GAAG,QAAQ,GAAG,IAAI,CAWhF"}
|
package/dist/manifest.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The command manifest of mark (architecture review 3.6, roadmap 1.3).
|
|
3
|
+
*
|
|
4
|
+
* Before, each run of mark imported the procedure modules of every package (about 4 s), also to
|
|
5
|
+
* show the help or to send a command to the CLI server. The manifest holds what the command line
|
|
6
|
+
* needs without the procedures: the path, the CLI metadata, the fields of the input (with the
|
|
7
|
+
* types that the flag parser converts to) and the JSON Schema of the input. mark reads it first.
|
|
8
|
+
* It imports the procedures only to run a command in this process.
|
|
9
|
+
*
|
|
10
|
+
* The build of mark writes `dist/manifest.json`. A run checks the fingerprint of the manifest:
|
|
11
|
+
* the packages that declare `client.procedures` and the build information of each one, of the
|
|
12
|
+
* core, and of mark. When a package was built again, or added, or removed, the fingerprint
|
|
13
|
+
* changes: mark then loads the procedures as before and writes the manifest again.
|
|
14
|
+
*/
|
|
15
|
+
import { createHash } from "node:crypto";
|
|
16
|
+
import * as fs from "node:fs";
|
|
17
|
+
import * as path from "node:path";
|
|
18
|
+
import { fileURLToPath } from "node:url";
|
|
19
|
+
import { jsonSchemaOf } from "@procedures/client";
|
|
20
|
+
import { discoverFromEcosystem, findWorkspaceRoot } from "./ecosystem.js";
|
|
21
|
+
import { extractSchemaFields, resultFieldsOfSchema } from "./parse.js";
|
|
22
|
+
/**
|
|
23
|
+
* The format of the manifest. A change of the format makes old manifests stale.
|
|
24
|
+
* Version 2 adds `resultFields`.
|
|
25
|
+
*/
|
|
26
|
+
export const MANIFEST_VERSION = 2;
|
|
27
|
+
/** The folder of the mark package: the nearest folder above this module with a package.json */
|
|
28
|
+
function markRoot() {
|
|
29
|
+
let dir = path.dirname(fileURLToPath(import.meta.url));
|
|
30
|
+
while (!fs.existsSync(path.join(dir, "package.json"))) {
|
|
31
|
+
const parent = path.dirname(dir);
|
|
32
|
+
if (parent === dir)
|
|
33
|
+
break;
|
|
34
|
+
dir = parent;
|
|
35
|
+
}
|
|
36
|
+
return dir;
|
|
37
|
+
}
|
|
38
|
+
/** The path of the manifest: in the dist folder of mark (also when this module runs from src) */
|
|
39
|
+
export function manifestPath() {
|
|
40
|
+
return path.join(markRoot(), "dist", "manifest.json");
|
|
41
|
+
}
|
|
42
|
+
/** The size and the modification time of a file, or "-" when it does not exist */
|
|
43
|
+
function stamp(file) {
|
|
44
|
+
try {
|
|
45
|
+
const stat = fs.statSync(file);
|
|
46
|
+
return `${stat.size}:${Math.round(stat.mtimeMs)}`;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return "-";
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* The fingerprint of the builds that the manifest depends on. `tsc -b` writes
|
|
54
|
+
* `dist/.tsbuildinfo` each time it builds a package, so a new build of any package changes it.
|
|
55
|
+
* For a package without that file, the procedures file counts. `tsc --noEmit` (the typecheck
|
|
56
|
+
* script) also writes that file when the sources changed after the last build: the manifest is
|
|
57
|
+
* then stale, and the next run of mark loads the procedures and writes it again.
|
|
58
|
+
*/
|
|
59
|
+
export function computeFingerprint(root = findWorkspaceRoot(), markDir = markRoot()) {
|
|
60
|
+
const parts = [`v${MANIFEST_VERSION}`];
|
|
61
|
+
if (root) {
|
|
62
|
+
parts.push(`client:${stamp(path.join(root, "packages", "client", "dist", ".tsbuildinfo"))}`);
|
|
63
|
+
}
|
|
64
|
+
// The field extraction is code of mark: a new build of mark can read the schemas differently
|
|
65
|
+
parts.push(`mark:${stamp(path.join(markDir, "dist", ".tsbuildinfo"))}`);
|
|
66
|
+
for (const pkg of root ? discoverFromEcosystem(root) : []) {
|
|
67
|
+
const info = stamp(path.join(pkg.path, "dist", ".tsbuildinfo"));
|
|
68
|
+
const procedures = info === "-" ? stamp(path.join(pkg.path, pkg.proceduresPath)) : info;
|
|
69
|
+
parts.push(`${pkg.name}:${pkg.proceduresPath}:${procedures}`);
|
|
70
|
+
}
|
|
71
|
+
return createHash("sha256").update(parts.join("\n")).digest("hex");
|
|
72
|
+
}
|
|
73
|
+
/** The CLI metadata of a procedure: only the fields that mark reads, so the manifest is plain JSON */
|
|
74
|
+
function cliMetadata(procedure) {
|
|
75
|
+
const meta = (procedure.metadata ?? {});
|
|
76
|
+
const result = {};
|
|
77
|
+
if (typeof meta["description"] === "string")
|
|
78
|
+
result.description = meta["description"];
|
|
79
|
+
if (Array.isArray(meta["args"]))
|
|
80
|
+
result.args = meta["args"].filter((arg) => typeof arg === "string");
|
|
81
|
+
if (meta["shorts"] && typeof meta["shorts"] === "object")
|
|
82
|
+
result.shorts = { ...meta["shorts"] };
|
|
83
|
+
if (typeof meta["output"] === "string")
|
|
84
|
+
result.output = meta["output"];
|
|
85
|
+
if (typeof meta["interactive"] === "boolean")
|
|
86
|
+
result.interactive = meta["interactive"];
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/** The commands of the manifest, from the procedures of the registry */
|
|
90
|
+
export async function commandsOf(procedures) {
|
|
91
|
+
return procedures.map((procedure) => {
|
|
92
|
+
// One JSON Schema for each command: the fields come from it too (roadmap 2.1)
|
|
93
|
+
const inputSchema = jsonSchemaOf(procedure.input) ?? {};
|
|
94
|
+
return {
|
|
95
|
+
path: [...procedure.path],
|
|
96
|
+
metadata: cliMetadata(procedure),
|
|
97
|
+
fields: extractSchemaFields(inputSchema),
|
|
98
|
+
inputSchema,
|
|
99
|
+
resultFields: resultFieldsOfSchema(procedure.output),
|
|
100
|
+
};
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
/** JSON of a manifest: a bigint (a default or a literal) becomes its text */
|
|
104
|
+
function toJson(manifest) {
|
|
105
|
+
return JSON.stringify(manifest, (_key, value) => (typeof value === "bigint" ? value.toString() : value), 1);
|
|
106
|
+
}
|
|
107
|
+
/** Write the manifest of these procedures for the current fingerprint (a temporary file, then a rename) */
|
|
108
|
+
export async function writeManifest(procedures, file = manifestPath()) {
|
|
109
|
+
const manifest = {
|
|
110
|
+
version: MANIFEST_VERSION,
|
|
111
|
+
fingerprint: computeFingerprint(),
|
|
112
|
+
generatedAt: new Date().toISOString(),
|
|
113
|
+
commands: await commandsOf(procedures),
|
|
114
|
+
};
|
|
115
|
+
const temporary = `${file}.${process.pid}.tmp`;
|
|
116
|
+
fs.writeFileSync(temporary, toJson(manifest));
|
|
117
|
+
try {
|
|
118
|
+
fs.renameSync(temporary, file);
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
fs.rmSync(temporary, { force: true });
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
return manifest;
|
|
125
|
+
}
|
|
126
|
+
/** The manifest when it exists and matches the current builds, or null */
|
|
127
|
+
export function readFreshManifest(file = manifestPath()) {
|
|
128
|
+
let manifest;
|
|
129
|
+
try {
|
|
130
|
+
manifest = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
if (manifest.version !== MANIFEST_VERSION || !Array.isArray(manifest.commands)) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
return manifest.fingerprint === computeFingerprint() ? manifest : null;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
|