@nekostack/cli 1.0.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 +42 -0
- package/LICENSE +202 -0
- package/README.md +89 -0
- package/bin/neko +6 -0
- package/dist/.build.tsbuildinfo +1 -0
- package/dist/.tsbuildinfo +1 -0
- package/dist/cli.d.ts +60 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +355 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +11 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/schema/check.d.ts +55 -0
- package/dist/commands/schema/check.d.ts.map +1 -0
- package/dist/commands/schema/check.js +197 -0
- package/dist/commands/schema/check.js.map +1 -0
- package/dist/commands/schema/diff.d.ts +48 -0
- package/dist/commands/schema/diff.d.ts.map +1 -0
- package/dist/commands/schema/diff.js +245 -0
- package/dist/commands/schema/diff.js.map +1 -0
- package/dist/commands/schema/generate.d.ts +59 -0
- package/dist/commands/schema/generate.d.ts.map +1 -0
- package/dist/commands/schema/generate.js +135 -0
- package/dist/commands/schema/generate.js.map +1 -0
- package/dist/commands/schema/list.d.ts +50 -0
- package/dist/commands/schema/list.d.ts.map +1 -0
- package/dist/commands/schema/list.js +115 -0
- package/dist/commands/schema/list.js.map +1 -0
- package/dist/commands/schema/migrate/list.d.ts +65 -0
- package/dist/commands/schema/migrate/list.d.ts.map +1 -0
- package/dist/commands/schema/migrate/list.js +148 -0
- package/dist/commands/schema/migrate/list.js.map +1 -0
- package/dist/commands/schema/migrate/plan.d.ts +79 -0
- package/dist/commands/schema/migrate/plan.d.ts.map +1 -0
- package/dist/commands/schema/migrate/plan.js +255 -0
- package/dist/commands/schema/migrate/plan.js.map +1 -0
- package/dist/commands/schema/migrate/stub.d.ts +59 -0
- package/dist/commands/schema/migrate/stub.d.ts.map +1 -0
- package/dist/commands/schema/migrate/stub.js +195 -0
- package/dist/commands/schema/migrate/stub.js.map +1 -0
- package/dist/commands/schema/migrate/verify.d.ts +59 -0
- package/dist/commands/schema/migrate/verify.d.ts.map +1 -0
- package/dist/commands/schema/migrate/verify.js +268 -0
- package/dist/commands/schema/migrate/verify.js.map +1 -0
- package/dist/exit-codes.d.ts +47 -0
- package/dist/exit-codes.d.ts.map +1 -0
- package/dist/exit-codes.js +46 -0
- package/dist/exit-codes.js.map +1 -0
- package/dist/formatters/json.d.ts +25 -0
- package/dist/formatters/json.d.ts.map +1 -0
- package/dist/formatters/json.js +27 -0
- package/dist/formatters/json.js.map +1 -0
- package/dist/formatters/pretty.d.ts +131 -0
- package/dist/formatters/pretty.d.ts.map +1 -0
- package/dist/formatters/pretty.js +229 -0
- package/dist/formatters/pretty.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/loaders/read-artifacts.d.ts +55 -0
- package/dist/loaders/read-artifacts.d.ts.map +1 -0
- package/dist/loaders/read-artifacts.js +99 -0
- package/dist/loaders/read-artifacts.js.map +1 -0
- package/dist/loaders/read-migrations.d.ts +70 -0
- package/dist/loaders/read-migrations.d.ts.map +1 -0
- package/dist/loaders/read-migrations.js +206 -0
- package/dist/loaders/read-migrations.js.map +1 -0
- package/dist/loaders/tsx-loader.d.ts +116 -0
- package/dist/loaders/tsx-loader.d.ts.map +1 -0
- package/dist/loaders/tsx-loader.js +250 -0
- package/dist/loaders/tsx-loader.js.map +1 -0
- package/dist/loaders/walk-workspace.d.ts +62 -0
- package/dist/loaders/walk-workspace.d.ts.map +1 -0
- package/dist/loaders/walk-workspace.js +133 -0
- package/dist/loaders/walk-workspace.js.map +1 -0
- package/docs/SCOPE.md +42 -0
- package/package.json +39 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neko schema diff <a> <b>` command implementation (v0.7 Step 30).
|
|
3
|
+
*
|
|
4
|
+
* Second real schema verb. Replaces the Step 25 placeholder.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Walk the workspace + build the registry (same prelude as
|
|
8
|
+
* `runList`).
|
|
9
|
+
* 2. Resolve each operand `<a>` / `<b>` to a `SchemaNode`. An
|
|
10
|
+
* operand is one of:
|
|
11
|
+
* - `schemaId` — highest-semver entry for that id
|
|
12
|
+
* - `schemaId@version` — exact id+version
|
|
13
|
+
* - file path (`/`, `\`, or `.ts` / `.js` / `.mts` / `.cts`
|
|
14
|
+
* suffix) — find the workspace
|
|
15
|
+
* entry whose `sourcePath` matches,
|
|
16
|
+
* take its first schema.
|
|
17
|
+
* 3. Hand the pair to `diffHandler({ before, after })`.
|
|
18
|
+
* 4. Format the `DiffResult.data` payload (`{ changes,
|
|
19
|
+
* worstSeverity }`):
|
|
20
|
+
* - `--json` → one-line JSON of the payload
|
|
21
|
+
* - default → `formatDiffPretty(payload)`
|
|
22
|
+
* 5. Pick the exit code from `worstSeverity`:
|
|
23
|
+
* - `"breaking"` → `LOGICAL_FAILURE`
|
|
24
|
+
* - `"additive"` / `"cosmetic"` / `null` → `SUCCESS`
|
|
25
|
+
*
|
|
26
|
+
* `UnsupportedNodeKindError` from `diffNodes` (date / union /
|
|
27
|
+
* recursiveRef / transform IR) propagates out per the schema-side
|
|
28
|
+
* convention. The CLI dispatch layer will gain explicit
|
|
29
|
+
* unsupported-IR mapping when a real verb introduces a surface that
|
|
30
|
+
* could throw beyond `Issue`s; v0.7 lets the throw fall through so
|
|
31
|
+
* the failure is loud during development.
|
|
32
|
+
*
|
|
33
|
+
* Pure: no `process.exit`, no `console.*`, no direct `process.stdout`
|
|
34
|
+
* / `process.stderr` writes. Writers are injected by the caller.
|
|
35
|
+
*/
|
|
36
|
+
import { type ExitCode } from "../../exit-codes.js";
|
|
37
|
+
export interface RunDiffOptions {
|
|
38
|
+
readonly root: string;
|
|
39
|
+
/** Left operand — `schemaId`, `schemaId@version`, or file path. */
|
|
40
|
+
readonly a: string;
|
|
41
|
+
/** Right operand — same forms as `a`. */
|
|
42
|
+
readonly b: string;
|
|
43
|
+
readonly json: boolean;
|
|
44
|
+
readonly stdout: (s: string) => void;
|
|
45
|
+
readonly stderr: (s: string) => void;
|
|
46
|
+
}
|
|
47
|
+
export declare function runDiff(opts: RunDiffOptions): Promise<ExitCode>;
|
|
48
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../src/commands/schema/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAWH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAehE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,mEAAmE;IACnE,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,yCAAyC;IACzC,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiDrE"}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neko schema diff <a> <b>` command implementation (v0.7 Step 30).
|
|
3
|
+
*
|
|
4
|
+
* Second real schema verb. Replaces the Step 25 placeholder.
|
|
5
|
+
*
|
|
6
|
+
* Flow:
|
|
7
|
+
* 1. Walk the workspace + build the registry (same prelude as
|
|
8
|
+
* `runList`).
|
|
9
|
+
* 2. Resolve each operand `<a>` / `<b>` to a `SchemaNode`. An
|
|
10
|
+
* operand is one of:
|
|
11
|
+
* - `schemaId` — highest-semver entry for that id
|
|
12
|
+
* - `schemaId@version` — exact id+version
|
|
13
|
+
* - file path (`/`, `\`, or `.ts` / `.js` / `.mts` / `.cts`
|
|
14
|
+
* suffix) — find the workspace
|
|
15
|
+
* entry whose `sourcePath` matches,
|
|
16
|
+
* take its first schema.
|
|
17
|
+
* 3. Hand the pair to `diffHandler({ before, after })`.
|
|
18
|
+
* 4. Format the `DiffResult.data` payload (`{ changes,
|
|
19
|
+
* worstSeverity }`):
|
|
20
|
+
* - `--json` → one-line JSON of the payload
|
|
21
|
+
* - default → `formatDiffPretty(payload)`
|
|
22
|
+
* 5. Pick the exit code from `worstSeverity`:
|
|
23
|
+
* - `"breaking"` → `LOGICAL_FAILURE`
|
|
24
|
+
* - `"additive"` / `"cosmetic"` / `null` → `SUCCESS`
|
|
25
|
+
*
|
|
26
|
+
* `UnsupportedNodeKindError` from `diffNodes` (date / union /
|
|
27
|
+
* recursiveRef / transform IR) propagates out per the schema-side
|
|
28
|
+
* convention. The CLI dispatch layer will gain explicit
|
|
29
|
+
* unsupported-IR mapping when a real verb introduces a surface that
|
|
30
|
+
* could throw beyond `Issue`s; v0.7 lets the throw fall through so
|
|
31
|
+
* the failure is loud during development.
|
|
32
|
+
*
|
|
33
|
+
* Pure: no `process.exit`, no `console.*`, no direct `process.stdout`
|
|
34
|
+
* / `process.stderr` writes. Writers are injected by the caller.
|
|
35
|
+
*/
|
|
36
|
+
import { isAbsolute, resolve, sep } from "node:path";
|
|
37
|
+
import { buildRegistry, diffHandler, findSchema, } from "@nekostack/schema/cli";
|
|
38
|
+
import { EXIT_CODES } from "../../exit-codes.js";
|
|
39
|
+
import { formatJson } from "../../formatters/json.js";
|
|
40
|
+
import { formatDiffPretty, formatIssuesPretty, formatLoadFailuresPretty, } from "../../formatters/pretty.js";
|
|
41
|
+
import { walkWorkspace } from "../../loaders/walk-workspace.js";
|
|
42
|
+
export async function runDiff(opts) {
|
|
43
|
+
// 1. Walk + build registry (shared prelude with `runList`).
|
|
44
|
+
const walk = await walkWorkspace({ root: opts.root });
|
|
45
|
+
if (walk.failures.length > 0) {
|
|
46
|
+
writeLoadFailures(opts, walk.failures);
|
|
47
|
+
return EXIT_CODES.IO_ERROR;
|
|
48
|
+
}
|
|
49
|
+
const reg = buildRegistry(walk.entries);
|
|
50
|
+
if (!reg.success) {
|
|
51
|
+
writeIssues(opts, reg.issues);
|
|
52
|
+
return EXIT_CODES.LOGICAL_FAILURE;
|
|
53
|
+
}
|
|
54
|
+
// 2. Resolve each operand to a SchemaNode.
|
|
55
|
+
const rootAbs = isAbsolute(opts.root) ? opts.root : resolve(opts.root);
|
|
56
|
+
const a = resolveOperand(opts.a, rootAbs, walk.entries, reg.data);
|
|
57
|
+
const b = resolveOperand(opts.b, rootAbs, walk.entries, reg.data);
|
|
58
|
+
if (!a.ok || !b.ok) {
|
|
59
|
+
const issues = [];
|
|
60
|
+
if (!a.ok)
|
|
61
|
+
issues.push(a.issue);
|
|
62
|
+
if (!b.ok)
|
|
63
|
+
issues.push(b.issue);
|
|
64
|
+
writeIssues(opts, issues);
|
|
65
|
+
return EXIT_CODES.LOGICAL_FAILURE;
|
|
66
|
+
}
|
|
67
|
+
// 3. Diff.
|
|
68
|
+
const result = diffHandler({ before: a.node, after: b.node });
|
|
69
|
+
if (!result.success) {
|
|
70
|
+
writeIssues(opts, result.issues);
|
|
71
|
+
return EXIT_CODES.LOGICAL_FAILURE;
|
|
72
|
+
}
|
|
73
|
+
// 4. Format.
|
|
74
|
+
if (opts.json) {
|
|
75
|
+
opts.stdout(formatJson({
|
|
76
|
+
changes: result.data.changes,
|
|
77
|
+
worstSeverity: result.data.worstSeverity,
|
|
78
|
+
}));
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
opts.stdout(formatDiffPretty(result.data));
|
|
82
|
+
}
|
|
83
|
+
// 5. Exit code from worstSeverity. Breaking is the only failure;
|
|
84
|
+
// additive / cosmetic / null (no-change) are all SUCCESS.
|
|
85
|
+
return result.data.worstSeverity === "breaking"
|
|
86
|
+
? EXIT_CODES.LOGICAL_FAILURE
|
|
87
|
+
: EXIT_CODES.SUCCESS;
|
|
88
|
+
}
|
|
89
|
+
function resolveOperand(operand, rootAbs, entries, registry) {
|
|
90
|
+
const parsed = parseOperand(operand);
|
|
91
|
+
if (parsed.kind === "file") {
|
|
92
|
+
const entry = findEntryByFile(parsed.path, rootAbs, entries);
|
|
93
|
+
if (entry === undefined) {
|
|
94
|
+
return {
|
|
95
|
+
ok: false,
|
|
96
|
+
issue: {
|
|
97
|
+
code: "schema_not_found",
|
|
98
|
+
path: [],
|
|
99
|
+
message: `File operand \`${operand}\` does not match any loaded schema file under \`${opts_root_display(rootAbs)}\`.`,
|
|
100
|
+
severity: "error",
|
|
101
|
+
metadata: { operand, kind: "file", root: rootAbs },
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
if (entry.schemas.length === 0) {
|
|
106
|
+
return {
|
|
107
|
+
ok: false,
|
|
108
|
+
issue: {
|
|
109
|
+
code: "schema_not_found",
|
|
110
|
+
path: [],
|
|
111
|
+
message: `File operand \`${operand}\` matched a workspace file but exported no schemas.`,
|
|
112
|
+
severity: "error",
|
|
113
|
+
metadata: { operand, kind: "file" },
|
|
114
|
+
},
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (entry.schemas.length > 1) {
|
|
118
|
+
// v0.7 supports multi-schema source files (Master plan Decision
|
|
119
|
+
// #6 disambiguates the generated artifact paths). The diff
|
|
120
|
+
// verb has no such per-schema disambiguator on its operands —
|
|
121
|
+
// silently picking `schemas[0]` would produce a possibly-wrong
|
|
122
|
+
// diff with no signal to the user. Reject the operand and
|
|
123
|
+
// tell them to address one schema explicitly.
|
|
124
|
+
return {
|
|
125
|
+
ok: false,
|
|
126
|
+
issue: {
|
|
127
|
+
code: "schema_not_found",
|
|
128
|
+
path: [],
|
|
129
|
+
message: `File operand \`${operand}\` matched multiple schemas; use schemaId or schemaId@version instead.`,
|
|
130
|
+
severity: "error",
|
|
131
|
+
metadata: {
|
|
132
|
+
operand,
|
|
133
|
+
kind: "file",
|
|
134
|
+
reason: "ambiguous_file_operand",
|
|
135
|
+
schemaIds: entry.schemas.map((s) => s.node.metadata?.id ?? null),
|
|
136
|
+
},
|
|
137
|
+
},
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
return { ok: true, node: entry.schemas[0].node };
|
|
141
|
+
}
|
|
142
|
+
// schemaId or schemaId@version.
|
|
143
|
+
const entry = findSchema(registry, parsed.id, parsed.version);
|
|
144
|
+
if (entry === undefined) {
|
|
145
|
+
const idKnown = registry.has(parsed.id);
|
|
146
|
+
if (parsed.version !== undefined && idKnown) {
|
|
147
|
+
return {
|
|
148
|
+
ok: false,
|
|
149
|
+
issue: {
|
|
150
|
+
code: "version_not_found",
|
|
151
|
+
path: [],
|
|
152
|
+
message: `Schema \`${parsed.id}\` exists but version \`${parsed.version}\` is not in the registry.`,
|
|
153
|
+
severity: "error",
|
|
154
|
+
metadata: {
|
|
155
|
+
operand,
|
|
156
|
+
kind: "id",
|
|
157
|
+
schemaId: parsed.id,
|
|
158
|
+
schemaVersion: parsed.version,
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
return {
|
|
164
|
+
ok: false,
|
|
165
|
+
issue: {
|
|
166
|
+
code: "schema_not_found",
|
|
167
|
+
path: [],
|
|
168
|
+
message: `Schema \`${parsed.id}\`${parsed.version === undefined ? "" : `@${parsed.version}`} is not in the registry.`,
|
|
169
|
+
severity: "error",
|
|
170
|
+
metadata: {
|
|
171
|
+
operand,
|
|
172
|
+
kind: "id",
|
|
173
|
+
schemaId: parsed.id,
|
|
174
|
+
schemaVersion: parsed.version ?? null,
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
return { ok: true, node: entry.schema.node };
|
|
180
|
+
}
|
|
181
|
+
function parseOperand(op) {
|
|
182
|
+
// File detection: contains a path separator or ends in a recognized
|
|
183
|
+
// source-file extension.
|
|
184
|
+
if (/[/\\]/.test(op) || /\.(ts|js|mts|cts)$/i.test(op)) {
|
|
185
|
+
return { kind: "file", path: op };
|
|
186
|
+
}
|
|
187
|
+
// `id@version` — split at the first `@`. Reverse-DNS schemaIds
|
|
188
|
+
// (`com.x.User`) do not contain `@`, so this is unambiguous.
|
|
189
|
+
const at = op.indexOf("@");
|
|
190
|
+
if (at > 0 && at < op.length - 1) {
|
|
191
|
+
return {
|
|
192
|
+
kind: "id",
|
|
193
|
+
id: op.slice(0, at),
|
|
194
|
+
version: op.slice(at + 1),
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
return { kind: "id", id: op };
|
|
198
|
+
}
|
|
199
|
+
function findEntryByFile(filePath, rootAbs, entries) {
|
|
200
|
+
// Resolve the user's input against the workspace root. Absolute
|
|
201
|
+
// paths pass through; relative paths anchor on `--root` so the
|
|
202
|
+
// command behaves the same whether the user shelled in from
|
|
203
|
+
// cwd === root or from somewhere else.
|
|
204
|
+
const target = isAbsolute(filePath)
|
|
205
|
+
? resolve(filePath)
|
|
206
|
+
: resolve(rootAbs, filePath);
|
|
207
|
+
for (const entry of entries) {
|
|
208
|
+
// entry.sourcePath is workspace-relative forward-slash. Rebuild
|
|
209
|
+
// the absolute form by joining against rootAbs and normalizing
|
|
210
|
+
// separators.
|
|
211
|
+
const entryAbs = resolve(rootAbs, entry.sourcePath.split("/").join(sep));
|
|
212
|
+
if (entryAbs === target)
|
|
213
|
+
return entry;
|
|
214
|
+
}
|
|
215
|
+
return undefined;
|
|
216
|
+
}
|
|
217
|
+
function opts_root_display(rootAbs) {
|
|
218
|
+
return rootAbs;
|
|
219
|
+
}
|
|
220
|
+
// =============================================================================
|
|
221
|
+
// Failure output helpers (mirror runList)
|
|
222
|
+
// =============================================================================
|
|
223
|
+
function writeLoadFailures(opts, failures) {
|
|
224
|
+
if (opts.json) {
|
|
225
|
+
opts.stdout(formatJson({
|
|
226
|
+
failures: failures.map((f) => ({
|
|
227
|
+
path: f.path,
|
|
228
|
+
reason: f.reason,
|
|
229
|
+
message: f.message,
|
|
230
|
+
})),
|
|
231
|
+
}));
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
opts.stderr(formatLoadFailuresPretty(failures));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
function writeIssues(opts, issues) {
|
|
238
|
+
if (opts.json) {
|
|
239
|
+
opts.stdout(formatJson({ issues }));
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
opts.stderr(formatIssuesPretty(issues));
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../src/commands/schema/diff.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neko schema generate [pattern]` command implementation (v0.7 Step 32).
|
|
3
|
+
*
|
|
4
|
+
* Fourth and final schema verb. Replaces the Step 25 placeholder.
|
|
5
|
+
*
|
|
6
|
+
* `generate` is the only v0.7 verb that writes files. The schema-side
|
|
7
|
+
* `generateHandler` is pure — it returns a list of `GeneratedArtifact`
|
|
8
|
+
* payloads with `suggestedPath` values; this command is responsible
|
|
9
|
+
* for actually persisting them. Master plan Decision #1 keeps the
|
|
10
|
+
* filesystem on the CLI side.
|
|
11
|
+
*
|
|
12
|
+
* Flow:
|
|
13
|
+
* 1. `walkWorkspace({ root, pattern })`.
|
|
14
|
+
* 2. Per-file load failures → `IO_ERROR`.
|
|
15
|
+
* 3. `buildRegistry(entries)` runs purely for duplicate-id
|
|
16
|
+
* detection. The `generateHandler` itself doesn't use the
|
|
17
|
+
* registry, but two schemas sharing a `(schemaId, version)`
|
|
18
|
+
* would emit artifacts to the same `suggestedPath` and the
|
|
19
|
+
* second write would silently overwrite the first. Surfacing
|
|
20
|
+
* that as `duplicate_schema_id` keeps the failure mode loud.
|
|
21
|
+
* 4. `generateHandler({ entries })` plans every artifact for every
|
|
22
|
+
* named schema. Anonymous schemas are silently skipped per
|
|
23
|
+
* schema-side Decision #5 — the CLI warns nothing here (the
|
|
24
|
+
* audit-noticeable surface is the count of generated artifacts).
|
|
25
|
+
* 5. Write each artifact's `content` to `<root>/<suggestedPath>`.
|
|
26
|
+
* Parent directories are created as needed; existing files are
|
|
27
|
+
* overwritten. Partial-generation (a subset of artifact kinds)
|
|
28
|
+
* is not supported in v0.7 — Master plan Decision #6.
|
|
29
|
+
* 6. Format + return `SUCCESS`. The empty-artifacts case (anonymous-
|
|
30
|
+
* only workspace, or empty workspace) is still `SUCCESS`.
|
|
31
|
+
*
|
|
32
|
+
* JSON output excludes the artifact `content` — that's potentially
|
|
33
|
+
* many kilobytes per artifact and is not what a CI consumer needs:
|
|
34
|
+
*
|
|
35
|
+
* {
|
|
36
|
+
* "artifacts": [
|
|
37
|
+
* { "schemaId": "com.x.User", "kind": "typescript",
|
|
38
|
+
* "suggestedPath": "schemas/generated/user.types.ts",
|
|
39
|
+
* "irHash": "sha256:…", "sourceHash": "sha256:…" },
|
|
40
|
+
* …
|
|
41
|
+
* ]
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* Pure with one exception — filesystem writes via `node:fs/promises`
|
|
45
|
+
* are deliberately allowed here. `process.exit` / `console.*` /
|
|
46
|
+
* direct stdout-stderr writes remain forbidden and are statically
|
|
47
|
+
* scanned in tests.
|
|
48
|
+
*/
|
|
49
|
+
import { type ExitCode } from "../../exit-codes.js";
|
|
50
|
+
export interface RunGenerateOptions {
|
|
51
|
+
readonly root: string;
|
|
52
|
+
readonly pattern?: string;
|
|
53
|
+
readonly json: boolean;
|
|
54
|
+
readonly quiet: boolean;
|
|
55
|
+
readonly stdout: (s: string) => void;
|
|
56
|
+
readonly stderr: (s: string) => void;
|
|
57
|
+
}
|
|
58
|
+
export declare function runGenerate(opts: RunGenerateOptions): Promise<ExitCode>;
|
|
59
|
+
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../src/commands/schema/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAUH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAUhE,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,QAAQ,CAAC,CA8CnB"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neko schema generate [pattern]` command implementation (v0.7 Step 32).
|
|
3
|
+
*
|
|
4
|
+
* Fourth and final schema verb. Replaces the Step 25 placeholder.
|
|
5
|
+
*
|
|
6
|
+
* `generate` is the only v0.7 verb that writes files. The schema-side
|
|
7
|
+
* `generateHandler` is pure — it returns a list of `GeneratedArtifact`
|
|
8
|
+
* payloads with `suggestedPath` values; this command is responsible
|
|
9
|
+
* for actually persisting them. Master plan Decision #1 keeps the
|
|
10
|
+
* filesystem on the CLI side.
|
|
11
|
+
*
|
|
12
|
+
* Flow:
|
|
13
|
+
* 1. `walkWorkspace({ root, pattern })`.
|
|
14
|
+
* 2. Per-file load failures → `IO_ERROR`.
|
|
15
|
+
* 3. `buildRegistry(entries)` runs purely for duplicate-id
|
|
16
|
+
* detection. The `generateHandler` itself doesn't use the
|
|
17
|
+
* registry, but two schemas sharing a `(schemaId, version)`
|
|
18
|
+
* would emit artifacts to the same `suggestedPath` and the
|
|
19
|
+
* second write would silently overwrite the first. Surfacing
|
|
20
|
+
* that as `duplicate_schema_id` keeps the failure mode loud.
|
|
21
|
+
* 4. `generateHandler({ entries })` plans every artifact for every
|
|
22
|
+
* named schema. Anonymous schemas are silently skipped per
|
|
23
|
+
* schema-side Decision #5 — the CLI warns nothing here (the
|
|
24
|
+
* audit-noticeable surface is the count of generated artifacts).
|
|
25
|
+
* 5. Write each artifact's `content` to `<root>/<suggestedPath>`.
|
|
26
|
+
* Parent directories are created as needed; existing files are
|
|
27
|
+
* overwritten. Partial-generation (a subset of artifact kinds)
|
|
28
|
+
* is not supported in v0.7 — Master plan Decision #6.
|
|
29
|
+
* 6. Format + return `SUCCESS`. The empty-artifacts case (anonymous-
|
|
30
|
+
* only workspace, or empty workspace) is still `SUCCESS`.
|
|
31
|
+
*
|
|
32
|
+
* JSON output excludes the artifact `content` — that's potentially
|
|
33
|
+
* many kilobytes per artifact and is not what a CI consumer needs:
|
|
34
|
+
*
|
|
35
|
+
* {
|
|
36
|
+
* "artifacts": [
|
|
37
|
+
* { "schemaId": "com.x.User", "kind": "typescript",
|
|
38
|
+
* "suggestedPath": "schemas/generated/user.types.ts",
|
|
39
|
+
* "irHash": "sha256:…", "sourceHash": "sha256:…" },
|
|
40
|
+
* …
|
|
41
|
+
* ]
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* Pure with one exception — filesystem writes via `node:fs/promises`
|
|
45
|
+
* are deliberately allowed here. `process.exit` / `console.*` /
|
|
46
|
+
* direct stdout-stderr writes remain forbidden and are statically
|
|
47
|
+
* scanned in tests.
|
|
48
|
+
*/
|
|
49
|
+
import { dirname, isAbsolute, resolve, sep } from "node:path";
|
|
50
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
51
|
+
import { buildRegistry, generateHandler, } from "@nekostack/schema/cli";
|
|
52
|
+
import { EXIT_CODES } from "../../exit-codes.js";
|
|
53
|
+
import { formatJson } from "../../formatters/json.js";
|
|
54
|
+
import { formatGeneratePretty, formatIssuesPretty, formatLoadFailuresPretty, } from "../../formatters/pretty.js";
|
|
55
|
+
import { walkWorkspace } from "../../loaders/walk-workspace.js";
|
|
56
|
+
export async function runGenerate(opts) {
|
|
57
|
+
// 1. Walk.
|
|
58
|
+
const walk = await walkWorkspace({
|
|
59
|
+
root: opts.root,
|
|
60
|
+
...(opts.pattern !== undefined ? { pattern: opts.pattern } : {}),
|
|
61
|
+
});
|
|
62
|
+
if (walk.failures.length > 0) {
|
|
63
|
+
writeLoadFailures(opts, walk.failures);
|
|
64
|
+
return EXIT_CODES.IO_ERROR;
|
|
65
|
+
}
|
|
66
|
+
// 2. Duplicate-id safety check. `buildRegistry` doesn't feed
|
|
67
|
+
// `generateHandler` but it's the existing surface that catches
|
|
68
|
+
// `(schemaId, version)` collisions across files.
|
|
69
|
+
const reg = buildRegistry(walk.entries);
|
|
70
|
+
if (!reg.success) {
|
|
71
|
+
writeIssues(opts, reg.issues);
|
|
72
|
+
return EXIT_CODES.LOGICAL_FAILURE;
|
|
73
|
+
}
|
|
74
|
+
// 3. Plan artifacts.
|
|
75
|
+
const result = generateHandler({ entries: walk.entries });
|
|
76
|
+
if (!result.success) {
|
|
77
|
+
writeIssues(opts, result.issues);
|
|
78
|
+
return EXIT_CODES.LOGICAL_FAILURE;
|
|
79
|
+
}
|
|
80
|
+
// 4. Persist each artifact.
|
|
81
|
+
const rootAbs = isAbsolute(opts.root) ? opts.root : resolve(opts.root);
|
|
82
|
+
for (const a of result.data.artifacts) {
|
|
83
|
+
const abs = resolve(rootAbs, a.suggestedPath.split("/").join(sep));
|
|
84
|
+
await mkdir(dirname(abs), { recursive: true });
|
|
85
|
+
await writeFile(abs, a.content, "utf8");
|
|
86
|
+
}
|
|
87
|
+
// 5. Format + return.
|
|
88
|
+
if (opts.json) {
|
|
89
|
+
opts.stdout(formatJson({
|
|
90
|
+
artifacts: result.data.artifacts.map(toSerializableArtifact),
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
opts.stdout(formatGeneratePretty(result.data.artifacts));
|
|
95
|
+
}
|
|
96
|
+
return EXIT_CODES.SUCCESS;
|
|
97
|
+
}
|
|
98
|
+
// =============================================================================
|
|
99
|
+
// JSON projection — omit `content` from machine-readable output
|
|
100
|
+
// =============================================================================
|
|
101
|
+
function toSerializableArtifact(a) {
|
|
102
|
+
return {
|
|
103
|
+
schemaId: a.schemaId,
|
|
104
|
+
kind: a.kind,
|
|
105
|
+
suggestedPath: a.suggestedPath,
|
|
106
|
+
irHash: a.irHash,
|
|
107
|
+
sourceHash: a.sourceHash,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// =============================================================================
|
|
111
|
+
// Failure output helpers (mirror the other verbs)
|
|
112
|
+
// =============================================================================
|
|
113
|
+
function writeLoadFailures(opts, failures) {
|
|
114
|
+
if (opts.json) {
|
|
115
|
+
opts.stdout(formatJson({
|
|
116
|
+
failures: failures.map((f) => ({
|
|
117
|
+
path: f.path,
|
|
118
|
+
reason: f.reason,
|
|
119
|
+
message: f.message,
|
|
120
|
+
})),
|
|
121
|
+
}));
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
opts.stderr(formatLoadFailuresPretty(failures));
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function writeIssues(opts, issues) {
|
|
128
|
+
if (opts.json) {
|
|
129
|
+
opts.stdout(formatJson({ issues }));
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
opts.stderr(formatIssuesPretty(issues));
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../src/commands/schema/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `neko schema list` command implementation (v0.7 Step 29).
|
|
3
|
+
*
|
|
4
|
+
* First fully-wired schema verb. Replaces the Step 25 placeholder.
|
|
5
|
+
* Flow:
|
|
6
|
+
*
|
|
7
|
+
* 1. `walkWorkspace({ root })` discovers and loads every
|
|
8
|
+
* `*.schema.{ts,js}` file under `root`.
|
|
9
|
+
* 2. If any file failed to load → render failures, exit IO_ERROR.
|
|
10
|
+
* 3. `buildRegistry(entries)` indexes the loaded schemas.
|
|
11
|
+
* 4. If the build returned `duplicate_schema_id` Issues → render
|
|
12
|
+
* issues, exit LOGICAL_FAILURE.
|
|
13
|
+
* 5. `listHandler({ registry })` enumerates entries in
|
|
14
|
+
* schemaId-ascending order (unversioned last).
|
|
15
|
+
* 6. Format and write:
|
|
16
|
+
* - `--json` → one-line JSON `{ schemas: [...] }` to stdout
|
|
17
|
+
* - default → padded table to stdout via `formatListPretty`
|
|
18
|
+
* 7. Return SUCCESS.
|
|
19
|
+
*
|
|
20
|
+
* Pure: no `process.exit`, no `console.*`, no direct `process.stdout`
|
|
21
|
+
* / `process.stderr` writes. The caller (the commander action wired
|
|
22
|
+
* up in `cli.ts`) injects writers; tests pass collector functions.
|
|
23
|
+
*
|
|
24
|
+
* JSON output shape is locked here so machine consumers have a
|
|
25
|
+
* stable contract. The `schema` field of `RegistryEntry` (the live
|
|
26
|
+
* `Schema` instance) is deliberately NOT included — it's not
|
|
27
|
+
* JSON-serializable and not a useful identifier downstream.
|
|
28
|
+
*
|
|
29
|
+
* {
|
|
30
|
+
* "schemas": [
|
|
31
|
+
* { "schemaId": "com.x.User", "schemaVersion": "1.0.0",
|
|
32
|
+
* "sourcePath": "schemas/user.schema.ts",
|
|
33
|
+
* "irHash": "sha256:...", "sourceHash": "sha256:..." },
|
|
34
|
+
* …
|
|
35
|
+
* ]
|
|
36
|
+
* }
|
|
37
|
+
*
|
|
38
|
+
* Unversioned entries surface as `"schemaVersion": null` so the
|
|
39
|
+
* JSON shape stays uniform.
|
|
40
|
+
*/
|
|
41
|
+
import { type ExitCode } from "../../exit-codes.js";
|
|
42
|
+
export interface RunListOptions {
|
|
43
|
+
readonly root: string;
|
|
44
|
+
readonly json: boolean;
|
|
45
|
+
readonly quiet: boolean;
|
|
46
|
+
readonly stdout: (s: string) => void;
|
|
47
|
+
readonly stderr: (s: string) => void;
|
|
48
|
+
}
|
|
49
|
+
export declare function runList(opts: RunListOptions): Promise<ExitCode>;
|
|
50
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/schema/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAGH,OAAO,EAAc,KAAK,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAuBhE,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC;AAED,wBAAsB,OAAO,CAAC,IAAI,EAAE,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,CA8DrE"}
|