@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,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Terminal-readable formatters for the four `neko schema *` verbs
|
|
3
|
+
* plus the two cross-cutting result kinds (load failures and Issues).
|
|
4
|
+
* v0.7 Step 28.
|
|
5
|
+
*
|
|
6
|
+
* Each function returns a `string` ending in exactly one trailing
|
|
7
|
+
* newline — same shape as `formatJson` (Step 27), so command modules
|
|
8
|
+
* can write either through the same `stdout`/`stderr` writer without
|
|
9
|
+
* remembering to add `\n`.
|
|
10
|
+
*
|
|
11
|
+
* Pure utility. No `console.*`, no `process.*`, no `fs.*`. Static-
|
|
12
|
+
* scan asserted by [`../../tests/formatters/pretty.test.ts`](../../tests/formatters/pretty.test.ts).
|
|
13
|
+
*
|
|
14
|
+
* Color is NOT applied here. CLI plan §"Explicit non-scope" defers
|
|
15
|
+
* richer color to a later phase; v0.7 ships plain ANSI-free output
|
|
16
|
+
* that respects `NO_COLOR` by default (i.e., never emits codes).
|
|
17
|
+
*
|
|
18
|
+
* Output stability — pretty output is **not** a contract across
|
|
19
|
+
* versions (the locked promise is `--json`, see [`./json.ts`](./json.ts)).
|
|
20
|
+
* These functions still aim for a deterministic shape so snapshot
|
|
21
|
+
* tests can compare against known strings; downstream consumers
|
|
22
|
+
* should consume `--json` rather than parsing pretty output.
|
|
23
|
+
*
|
|
24
|
+
* Pure: takes data in, returns a string. Inputs are never mutated;
|
|
25
|
+
* sorted/iterated lazily and the caller's arrays are preserved.
|
|
26
|
+
*/
|
|
27
|
+
// =============================================================================
|
|
28
|
+
// `neko schema list`
|
|
29
|
+
// =============================================================================
|
|
30
|
+
/**
|
|
31
|
+
* Render a registry-listing as a fixed-width table. Format matches
|
|
32
|
+
* the example in the CLI companion plan:
|
|
33
|
+
*
|
|
34
|
+
* 3 schemas in workspace:
|
|
35
|
+
* com.nekostack.tenant.Tenant 1.0.0 path/to/tenant.schema.ts
|
|
36
|
+
* com.nekostack.audit.AuditEvent 1.0.0 path/to/audit-event.schema.ts
|
|
37
|
+
*
|
|
38
|
+
* Empty input produces a single human-readable line. Versions are
|
|
39
|
+
* displayed as `(unversioned)` when the entry's `schemaVersion` is
|
|
40
|
+
* `undefined`. Entries are NOT re-sorted here — `listHandler`
|
|
41
|
+
* already returns them in deterministic schemaId-ascending order.
|
|
42
|
+
*/
|
|
43
|
+
export function formatListPretty(entries) {
|
|
44
|
+
if (entries.length === 0)
|
|
45
|
+
return "No schemas found in workspace.\n";
|
|
46
|
+
const header = `${pluralize(entries.length, "schema", "schemas")} in workspace:`;
|
|
47
|
+
const rows = entries.map((e) => ({
|
|
48
|
+
id: e.schemaId,
|
|
49
|
+
version: e.schemaVersion ?? "(unversioned)",
|
|
50
|
+
path: e.sourcePath,
|
|
51
|
+
}));
|
|
52
|
+
const idWidth = maxWidth(rows.map((r) => r.id));
|
|
53
|
+
const versionWidth = maxWidth(rows.map((r) => r.version));
|
|
54
|
+
const lines = rows.map((r) => ` ${r.id.padEnd(idWidth)} ${r.version.padEnd(versionWidth)} ${r.path}`);
|
|
55
|
+
return [header, ...lines].join("\n") + "\n";
|
|
56
|
+
}
|
|
57
|
+
// =============================================================================
|
|
58
|
+
// `neko schema migrate list`
|
|
59
|
+
// =============================================================================
|
|
60
|
+
/**
|
|
61
|
+
* Render a migration-listing as a fixed-width table. Same shape as
|
|
62
|
+
* `formatListPretty` but with `(schemaId, fromVersion → toVersion,
|
|
63
|
+
* sourcePath)` columns. Entries are NOT re-sorted —
|
|
64
|
+
* `listMigrationsHandler` already returns them in
|
|
65
|
+
* `(schemaId, fromVersion, toVersion)` ascending order.
|
|
66
|
+
*
|
|
67
|
+
* The `migration` field on `MigrationEntry` (the loaded `AnyMigration`)
|
|
68
|
+
* is deliberately NOT rendered: it carries a closure `transform` that
|
|
69
|
+
* the v0.8 boundary forbids touching here, and the pretty output is
|
|
70
|
+
* for human review of the registry shape only.
|
|
71
|
+
*/
|
|
72
|
+
export function formatMigrationListPretty(entries) {
|
|
73
|
+
if (entries.length === 0)
|
|
74
|
+
return "No migrations found in workspace.\n";
|
|
75
|
+
const header = `${pluralize(entries.length, "migration", "migrations")} in workspace:`;
|
|
76
|
+
const rows = entries.map((e) => ({
|
|
77
|
+
id: e.schemaId,
|
|
78
|
+
versions: `${e.fromVersion} → ${e.toVersion}`,
|
|
79
|
+
path: e.sourcePath,
|
|
80
|
+
}));
|
|
81
|
+
const idWidth = maxWidth(rows.map((r) => r.id));
|
|
82
|
+
const versionsWidth = maxWidth(rows.map((r) => r.versions));
|
|
83
|
+
const lines = rows.map((r) => ` ${r.id.padEnd(idWidth)} ${r.versions.padEnd(versionsWidth)} ${r.path}`);
|
|
84
|
+
return [header, ...lines].join("\n") + "\n";
|
|
85
|
+
}
|
|
86
|
+
// =============================================================================
|
|
87
|
+
// `neko schema diff`
|
|
88
|
+
// =============================================================================
|
|
89
|
+
/**
|
|
90
|
+
* Render a `DiffResult.data` payload (the unwrapped success branch).
|
|
91
|
+
* Header carries the count + `worstSeverity`; rows list each change
|
|
92
|
+
* as `[severity] kind at path — message`.
|
|
93
|
+
*
|
|
94
|
+
* Empty change list prints `No changes.` with the worst-severity
|
|
95
|
+
* sentinel `null`. Non-empty lists print the count and severity in
|
|
96
|
+
* a uniform header so machine post-processing (e.g., a CI script
|
|
97
|
+
* grepping the pretty output, even though `--json` is the contract)
|
|
98
|
+
* has a stable single-line summary at the top.
|
|
99
|
+
*/
|
|
100
|
+
export function formatDiffPretty(payload) {
|
|
101
|
+
if (payload.changes.length === 0)
|
|
102
|
+
return "No changes.\n";
|
|
103
|
+
const header = `${pluralize(payload.changes.length, "change", "changes")} (worst severity: ${payload.worstSeverity}):`;
|
|
104
|
+
const lines = payload.changes.map((c) => formatDiffChange(c));
|
|
105
|
+
return [header, ...lines].join("\n") + "\n";
|
|
106
|
+
}
|
|
107
|
+
function formatDiffChange(c) {
|
|
108
|
+
const pathText = formatIssuePath(c.path);
|
|
109
|
+
const where = pathText === "" ? "(root)" : pathText;
|
|
110
|
+
return ` [${c.severity}] ${c.kind} at ${where} — ${c.message}`;
|
|
111
|
+
}
|
|
112
|
+
// =============================================================================
|
|
113
|
+
// `neko schema check`
|
|
114
|
+
// =============================================================================
|
|
115
|
+
/**
|
|
116
|
+
* Render a list of freshness verdicts (`CheckResult.data.verdicts`).
|
|
117
|
+
* Header is a per-status tally:
|
|
118
|
+
*
|
|
119
|
+
* 4 artifacts: 2 clean, 1 cosmetic_drift, 1 stale
|
|
120
|
+
*
|
|
121
|
+
* Body lists each verdict as `[status] artifactPath` in input order
|
|
122
|
+
* (the schema-side handler emits in the order the CLI handed it the
|
|
123
|
+
* artifacts, which is already deterministic — see Step 24).
|
|
124
|
+
*
|
|
125
|
+
* Empty input prints a single human-readable line; the CLI dispatch
|
|
126
|
+
* layer is responsible for deciding what an empty `check` exits as.
|
|
127
|
+
*/
|
|
128
|
+
export function formatCheckPretty(verdicts) {
|
|
129
|
+
if (verdicts.length === 0)
|
|
130
|
+
return "No artifacts to check.\n";
|
|
131
|
+
const counts = {
|
|
132
|
+
clean: 0,
|
|
133
|
+
cosmetic_drift: 0,
|
|
134
|
+
stale: 0,
|
|
135
|
+
integrity_error: 0,
|
|
136
|
+
};
|
|
137
|
+
for (const v of verdicts)
|
|
138
|
+
counts[v.status] += 1;
|
|
139
|
+
const tally = [
|
|
140
|
+
["clean", counts.clean],
|
|
141
|
+
["cosmetic_drift", counts.cosmetic_drift],
|
|
142
|
+
["stale", counts.stale],
|
|
143
|
+
["integrity_error", counts.integrity_error],
|
|
144
|
+
]
|
|
145
|
+
.filter(([, n]) => n > 0)
|
|
146
|
+
.map(([k, n]) => `${n} ${k}`)
|
|
147
|
+
.join(", ");
|
|
148
|
+
const header = `${pluralize(verdicts.length, "artifact", "artifacts")}: ${tally}`;
|
|
149
|
+
const lines = verdicts.map((v) => ` [${v.status}] ${v.artifactPath}`);
|
|
150
|
+
return [header, ...lines].join("\n") + "\n";
|
|
151
|
+
}
|
|
152
|
+
// =============================================================================
|
|
153
|
+
// `neko schema generate`
|
|
154
|
+
// =============================================================================
|
|
155
|
+
/**
|
|
156
|
+
* Render the list of `GeneratedArtifact`s `generateHandler` returned.
|
|
157
|
+
* The CLI dispatch layer is what actually writes each artifact's
|
|
158
|
+
* `content` to its `suggestedPath`; this formatter only summarizes
|
|
159
|
+
* the plan for the user's terminal.
|
|
160
|
+
*
|
|
161
|
+
* Generated 12 artifacts (3 schemas × 4 kinds):
|
|
162
|
+
* com.x.Tenant typescript schemas/generated/tenant.types.ts
|
|
163
|
+
* com.x.Tenant zod schemas/generated/tenant.zod.ts
|
|
164
|
+
* …
|
|
165
|
+
*
|
|
166
|
+
* Empty input prints a single human-readable line. Artifacts are
|
|
167
|
+
* NOT re-sorted — `generateHandler` already emits them in
|
|
168
|
+
* deterministic schemaId-then-kind order.
|
|
169
|
+
*/
|
|
170
|
+
export function formatGeneratePretty(artifacts) {
|
|
171
|
+
if (artifacts.length === 0)
|
|
172
|
+
return "No artifacts generated.\n";
|
|
173
|
+
const schemaIds = new Set(artifacts.map((a) => a.schemaId));
|
|
174
|
+
const header = `Generated ${pluralize(artifacts.length, "artifact", "artifacts")} (${pluralize(schemaIds.size, "schema", "schemas")} × ${Math.round(artifacts.length / Math.max(schemaIds.size, 1))} kinds):`;
|
|
175
|
+
const idWidth = maxWidth(artifacts.map((a) => a.schemaId));
|
|
176
|
+
const kindWidth = maxWidth(artifacts.map((a) => a.kind));
|
|
177
|
+
const lines = artifacts.map((a) => ` ${a.schemaId.padEnd(idWidth)} ${a.kind.padEnd(kindWidth)} ${a.suggestedPath}`);
|
|
178
|
+
return [header, ...lines].join("\n") + "\n";
|
|
179
|
+
}
|
|
180
|
+
export function formatLoadFailuresPretty(failures, opts = {}) {
|
|
181
|
+
if (failures.length === 0)
|
|
182
|
+
return "No load failures.\n";
|
|
183
|
+
const noun = opts.noun ?? { singular: "schema file", plural: "schema files" };
|
|
184
|
+
const header = `${pluralize(failures.length, `${noun.singular} failed`, `${noun.plural} failed`)} to load:`;
|
|
185
|
+
const lines = failures.map((f) => ` [${f.reason}] ${f.path} — ${f.message}`);
|
|
186
|
+
return [header, ...lines].join("\n") + "\n";
|
|
187
|
+
}
|
|
188
|
+
// =============================================================================
|
|
189
|
+
// Schema-side `Issue[]` rendering
|
|
190
|
+
// =============================================================================
|
|
191
|
+
/**
|
|
192
|
+
* Render a list of `Issue`s — used when a schema-side handler returns
|
|
193
|
+
* `Result.failure` and the CLI needs a human-readable digest.
|
|
194
|
+
* Severity prefixes the message; `error` is the only severity v0.7
|
|
195
|
+
* emits, but the formatter handles the full vocabulary for
|
|
196
|
+
* forward compatibility.
|
|
197
|
+
*/
|
|
198
|
+
export function formatIssuesPretty(issues) {
|
|
199
|
+
if (issues.length === 0)
|
|
200
|
+
return "No issues.\n";
|
|
201
|
+
const header = `${pluralize(issues.length, "issue", "issues")}:`;
|
|
202
|
+
const lines = issues.map((i) => {
|
|
203
|
+
const where = formatIssuePath(i.path);
|
|
204
|
+
const pathPart = where === "" ? "" : ` at ${where}`;
|
|
205
|
+
return ` [${i.severity}] ${i.code}${pathPart} — ${i.message}`;
|
|
206
|
+
});
|
|
207
|
+
return [header, ...lines].join("\n") + "\n";
|
|
208
|
+
}
|
|
209
|
+
// =============================================================================
|
|
210
|
+
// Helpers
|
|
211
|
+
// =============================================================================
|
|
212
|
+
function pluralize(n, singular, plural) {
|
|
213
|
+
return `${n} ${n === 1 ? singular : plural}`;
|
|
214
|
+
}
|
|
215
|
+
function maxWidth(values) {
|
|
216
|
+
let max = 0;
|
|
217
|
+
for (const v of values) {
|
|
218
|
+
if (v.length > max)
|
|
219
|
+
max = v.length;
|
|
220
|
+
}
|
|
221
|
+
return max;
|
|
222
|
+
}
|
|
223
|
+
function formatIssuePath(path) {
|
|
224
|
+
return path
|
|
225
|
+
.map((segment) => typeof segment === "number" ? `[${segment}]` : segment)
|
|
226
|
+
.join(".")
|
|
227
|
+
.replace(/\.\[/g, "[");
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=pretty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pretty.js","sourceRoot":"","sources":["../../src/formatters/pretty.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `loadCommittedArtifacts(generatedDir)` — CLI-side committed-artifact
|
|
3
|
+
* reader for the `check` command (v0.7 Step 24).
|
|
4
|
+
*
|
|
5
|
+
* Walks `generatedDir` for the four locked NekoStack artifact-name
|
|
6
|
+
* suffixes (Master plan Decision #6) and reads each one's bytes as
|
|
7
|
+
* UTF-8 text. Returns one {@link CommittedArtifact} per file. The
|
|
8
|
+
* schema-side `checkHandler` then parses each artifact's provenance
|
|
9
|
+
* block and applies the two-hash freshness matrix; this loader only
|
|
10
|
+
* handles the filesystem read.
|
|
11
|
+
*
|
|
12
|
+
* <generatedDir>/<basename>.types.ts ← TS output
|
|
13
|
+
* <generatedDir>/<basename>.zod.ts ← Zod source
|
|
14
|
+
* <generatedDir>/<basename>.json.schema.json ← JSON Schema
|
|
15
|
+
* <generatedDir>/<basename>.openapi.json ← OpenAPI 3.1 component
|
|
16
|
+
*
|
|
17
|
+
* Multi-schema source files add a discriminator slug between the
|
|
18
|
+
* basename and the artifact suffix (e.g. `account.com-x-tenant.types.ts`).
|
|
19
|
+
* The glob patterns below match the full set without re-deriving the
|
|
20
|
+
* discriminator rule — any file whose name ends in one of the four
|
|
21
|
+
* suffixes is treated as a candidate artifact.
|
|
22
|
+
*
|
|
23
|
+
* Behavior:
|
|
24
|
+
*
|
|
25
|
+
* - Default behavior reads every artifact under the dir, recursively.
|
|
26
|
+
* - If the directory does not exist, returns `[]` — the schema-side
|
|
27
|
+
* `checkHandler` treats "no artifacts" as a no-op verdict, which
|
|
28
|
+
* is the right shape for a fresh workspace before its first
|
|
29
|
+
* `neko schema generate` run.
|
|
30
|
+
* - Per-artifact paths returned to the caller are
|
|
31
|
+
* {@link generatedDir}-relative, forward-slash-normalized, for
|
|
32
|
+
* stable display across platforms (same convention as the walker
|
|
33
|
+
* in `walk-workspace.ts`).
|
|
34
|
+
*
|
|
35
|
+
* No `console.*`, no `process.exit`, no stdout/stderr writes — static-
|
|
36
|
+
* scan asserted by [`../../tests/loaders/read-artifacts.test.ts`](../../tests/loaders/read-artifacts.test.ts).
|
|
37
|
+
*
|
|
38
|
+
* This module does NOT:
|
|
39
|
+
* - Parse artifact provenance (schema-side `parseProvenanceFromText`).
|
|
40
|
+
* - Compute freshness verdicts (schema-side `checkHandler`).
|
|
41
|
+
* - Write artifacts to disk (Step 32's `generate.ts` command).
|
|
42
|
+
* - Decide exit codes (Step 25/26).
|
|
43
|
+
*/
|
|
44
|
+
import type { CommittedArtifact } from "@nekostack/schema/cli";
|
|
45
|
+
export type { CommittedArtifact };
|
|
46
|
+
/**
|
|
47
|
+
* Artifact-name suffixes matched by the locked v0.7 path convention.
|
|
48
|
+
* Exported so downstream code (Step 31's `check.ts` dispatch) can
|
|
49
|
+
* advertise the same list without re-deriving it. Listed in the same
|
|
50
|
+
* order as `GENERATOR_KINDS` on the schema side: `typescript`, `zod`,
|
|
51
|
+
* `jsonSchema`, `openApi`.
|
|
52
|
+
*/
|
|
53
|
+
export declare const ARTIFACT_SUFFIXES: readonly [".types.ts", ".zod.ts", ".json.schema.json", ".openapi.json"];
|
|
54
|
+
export declare function loadCommittedArtifacts(generatedDir: string): Promise<readonly CommittedArtifact[]>;
|
|
55
|
+
//# sourceMappingURL=read-artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-artifacts.d.ts","sourceRoot":"","sources":["../../src/loaders/read-artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAKH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAE/D,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,yEAKpB,CAAC;AAIX,wBAAsB,sBAAsB,CAC1C,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,SAAS,iBAAiB,EAAE,CAAC,CA4BvC"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `loadCommittedArtifacts(generatedDir)` — CLI-side committed-artifact
|
|
3
|
+
* reader for the `check` command (v0.7 Step 24).
|
|
4
|
+
*
|
|
5
|
+
* Walks `generatedDir` for the four locked NekoStack artifact-name
|
|
6
|
+
* suffixes (Master plan Decision #6) and reads each one's bytes as
|
|
7
|
+
* UTF-8 text. Returns one {@link CommittedArtifact} per file. The
|
|
8
|
+
* schema-side `checkHandler` then parses each artifact's provenance
|
|
9
|
+
* block and applies the two-hash freshness matrix; this loader only
|
|
10
|
+
* handles the filesystem read.
|
|
11
|
+
*
|
|
12
|
+
* <generatedDir>/<basename>.types.ts ← TS output
|
|
13
|
+
* <generatedDir>/<basename>.zod.ts ← Zod source
|
|
14
|
+
* <generatedDir>/<basename>.json.schema.json ← JSON Schema
|
|
15
|
+
* <generatedDir>/<basename>.openapi.json ← OpenAPI 3.1 component
|
|
16
|
+
*
|
|
17
|
+
* Multi-schema source files add a discriminator slug between the
|
|
18
|
+
* basename and the artifact suffix (e.g. `account.com-x-tenant.types.ts`).
|
|
19
|
+
* The glob patterns below match the full set without re-deriving the
|
|
20
|
+
* discriminator rule — any file whose name ends in one of the four
|
|
21
|
+
* suffixes is treated as a candidate artifact.
|
|
22
|
+
*
|
|
23
|
+
* Behavior:
|
|
24
|
+
*
|
|
25
|
+
* - Default behavior reads every artifact under the dir, recursively.
|
|
26
|
+
* - If the directory does not exist, returns `[]` — the schema-side
|
|
27
|
+
* `checkHandler` treats "no artifacts" as a no-op verdict, which
|
|
28
|
+
* is the right shape for a fresh workspace before its first
|
|
29
|
+
* `neko schema generate` run.
|
|
30
|
+
* - Per-artifact paths returned to the caller are
|
|
31
|
+
* {@link generatedDir}-relative, forward-slash-normalized, for
|
|
32
|
+
* stable display across platforms (same convention as the walker
|
|
33
|
+
* in `walk-workspace.ts`).
|
|
34
|
+
*
|
|
35
|
+
* No `console.*`, no `process.exit`, no stdout/stderr writes — static-
|
|
36
|
+
* scan asserted by [`../../tests/loaders/read-artifacts.test.ts`](../../tests/loaders/read-artifacts.test.ts).
|
|
37
|
+
*
|
|
38
|
+
* This module does NOT:
|
|
39
|
+
* - Parse artifact provenance (schema-side `parseProvenanceFromText`).
|
|
40
|
+
* - Compute freshness verdicts (schema-side `checkHandler`).
|
|
41
|
+
* - Write artifacts to disk (Step 32's `generate.ts` command).
|
|
42
|
+
* - Decide exit codes (Step 25/26).
|
|
43
|
+
*/
|
|
44
|
+
import { readFile, stat } from "node:fs/promises";
|
|
45
|
+
import { glob } from "node:fs/promises";
|
|
46
|
+
import { isAbsolute, resolve, sep } from "node:path";
|
|
47
|
+
/**
|
|
48
|
+
* Artifact-name suffixes matched by the locked v0.7 path convention.
|
|
49
|
+
* Exported so downstream code (Step 31's `check.ts` dispatch) can
|
|
50
|
+
* advertise the same list without re-deriving it. Listed in the same
|
|
51
|
+
* order as `GENERATOR_KINDS` on the schema side: `typescript`, `zod`,
|
|
52
|
+
* `jsonSchema`, `openApi`.
|
|
53
|
+
*/
|
|
54
|
+
export const ARTIFACT_SUFFIXES = [
|
|
55
|
+
".types.ts",
|
|
56
|
+
".zod.ts",
|
|
57
|
+
".json.schema.json",
|
|
58
|
+
".openapi.json",
|
|
59
|
+
];
|
|
60
|
+
const ARTIFACT_GLOB = `**/*{${ARTIFACT_SUFFIXES.join(",")}}`;
|
|
61
|
+
export async function loadCommittedArtifacts(generatedDir) {
|
|
62
|
+
const dirAbs = isAbsolute(generatedDir)
|
|
63
|
+
? generatedDir
|
|
64
|
+
: resolve(generatedDir);
|
|
65
|
+
// Missing-or-not-a-directory → no artifacts. The check verb's right
|
|
66
|
+
// shape on a fresh workspace is "no verdicts, no error" — let the
|
|
67
|
+
// schema-side handler decide whether that means clean or stale.
|
|
68
|
+
if (!(await isDirectory(dirAbs)))
|
|
69
|
+
return [];
|
|
70
|
+
const relativeRaw = [];
|
|
71
|
+
for await (const p of glob(ARTIFACT_GLOB, { cwd: dirAbs })) {
|
|
72
|
+
relativeRaw.push(p);
|
|
73
|
+
}
|
|
74
|
+
// Deterministic ordering — alphabetical on forward-slash-normalized
|
|
75
|
+
// relative paths. Same convention as `walk-workspace.ts`.
|
|
76
|
+
const relative = relativeRaw
|
|
77
|
+
.map((p) => p.split(sep).join("/"))
|
|
78
|
+
.sort((a, b) => (a < b ? -1 : a > b ? 1 : 0));
|
|
79
|
+
const out = [];
|
|
80
|
+
for (const rel of relative) {
|
|
81
|
+
const abs = resolve(dirAbs, rel);
|
|
82
|
+
const content = await readFile(abs, "utf8");
|
|
83
|
+
out.push({ path: rel, content });
|
|
84
|
+
}
|
|
85
|
+
return out;
|
|
86
|
+
}
|
|
87
|
+
// =============================================================================
|
|
88
|
+
// Helpers
|
|
89
|
+
// =============================================================================
|
|
90
|
+
async function isDirectory(path) {
|
|
91
|
+
try {
|
|
92
|
+
const s = await stat(path);
|
|
93
|
+
return s.isDirectory();
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=read-artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-artifacts.js","sourceRoot":"","sources":["../../src/loaders/read-artifacts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CG;AAEH,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACxC,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAKrD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,WAAW;IACX,SAAS;IACT,mBAAmB;IACnB,eAAe;CACP,CAAC;AAEX,MAAM,aAAa,GAAG,QAAQ,iBAAiB,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;AAE7D,MAAM,CAAC,KAAK,UAAU,sBAAsB,CAC1C,YAAoB;IAEpB,MAAM,MAAM,GAAG,UAAU,CAAC,YAAY,CAAC;QACrC,CAAC,CAAC,YAAY;QACd,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IAE1B,oEAAoE;IACpE,kEAAkE;IAClE,gEAAgE;IAChE,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,MAAM,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAE5C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,KAAK,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,aAAa,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;QAC3D,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,CAAC;IAED,oEAAoE;IACpE,0DAA0D;IAC1D,MAAM,QAAQ,GAAG,WAAW;SACzB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;SAClC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAEhD,MAAM,GAAG,GAAwB,EAAE,CAAC;IACpC,KAAK,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;QAC5C,GAAG,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,gFAAgF;AAChF,UAAU;AACV,gFAAgF;AAEhF,KAAK,UAAU,WAAW,CAAC,IAAY;IACrC,IAAI,CAAC;QACH,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `readMigrations({ root, pattern? })` — CLI-side discovery + load of
|
|
3
|
+
* authored `*.migration.ts` files (v0.8 Step 19).
|
|
4
|
+
*
|
|
5
|
+
* The CLI is the only filesystem walker and the only place that
|
|
6
|
+
* dynamic-imports authored migration modules (Master plan Decision #1;
|
|
7
|
+
* v0.8 INVARIANTS — `no apply, no transform execution` stays in force).
|
|
8
|
+
* This function:
|
|
9
|
+
*
|
|
10
|
+
* 1. Glob-walks `pattern` (default `**/*.migration.ts`) under
|
|
11
|
+
* `root` using Node's built-in `fs/promises.glob` — same approach
|
|
12
|
+
* as the v0.7 `walk-workspace.ts`.
|
|
13
|
+
* 2. Reads each match's UTF-8 source text verbatim.
|
|
14
|
+
* 3. Hands the absolute path to a dynamic `import()` routed through
|
|
15
|
+
* the tsx ESM hook registered once by the sibling `tsx-loader.ts`
|
|
16
|
+
* module (importing it for the `register()` side effect is
|
|
17
|
+
* sufficient — no per-call `tsImport()`).
|
|
18
|
+
* 4. Validates the module's default export structurally as an
|
|
19
|
+
* `AnyMigration` (`schemaId` / `from` / `to` strings + `transform`
|
|
20
|
+
* function). Anything else → `no_migration_export` failure.
|
|
21
|
+
* 5. Pairs the load result with its `sourceText` and workspace-
|
|
22
|
+
* relative, forward-slash-normalized `sourcePath` into one
|
|
23
|
+
* `MigrationSourceEntry`.
|
|
24
|
+
* 6. Collects every per-file failure into a separate `failures`
|
|
25
|
+
* array — never short-circuits.
|
|
26
|
+
*
|
|
27
|
+
* **Top-level evaluation nuance.** Authored migration files are
|
|
28
|
+
* TypeScript modules. tsx evaluates their top-level code at import
|
|
29
|
+
* time; this is the CLI side of the v0.8 boundary (the schema package
|
|
30
|
+
* never imports authored migration modules). A top-level throw
|
|
31
|
+
* classifies as `runtime_error` — the rest of the walk continues.
|
|
32
|
+
*
|
|
33
|
+
* **`transform` is NEVER invoked here.** This loader reads, imports,
|
|
34
|
+
* validates the export shape, and stops. A static-scan test asserts
|
|
35
|
+
* the source contains no `.transform(` call.
|
|
36
|
+
*
|
|
37
|
+
* No `console.*`, no `process.exit`, no stdout/stderr writes —
|
|
38
|
+
* static-scan asserted by [`../../tests/loaders/read-migrations.test.ts`](../../tests/loaders/read-migrations.test.ts).
|
|
39
|
+
*
|
|
40
|
+
* This module does NOT:
|
|
41
|
+
* - Build a `MigrationRegistry` (that's `buildMigrationRegistry` on
|
|
42
|
+
* the schema side).
|
|
43
|
+
* - Parse the JSDoc provenance header (that's
|
|
44
|
+
* `parseMigrationProvenanceFromText` on the schema side).
|
|
45
|
+
* - Plan, verify, or stub migrations (Steps 21 / 22 / 23 commands).
|
|
46
|
+
* - Format output (later steps).
|
|
47
|
+
* - Decide exit codes (later steps).
|
|
48
|
+
*/
|
|
49
|
+
import type { MigrationSourceEntry } from "@nekostack/schema/cli";
|
|
50
|
+
import { type LoadFailure } from "./tsx-loader.js";
|
|
51
|
+
export type { MigrationSourceEntry, LoadFailure };
|
|
52
|
+
export declare const DEFAULT_MIGRATION_PATTERN = "**/*.migration.ts";
|
|
53
|
+
export interface ReadMigrationsOpts {
|
|
54
|
+
/** Workspace root. Must be passed explicitly; the loader does not
|
|
55
|
+
* fall back to `process.cwd()`. Dispatch layer resolves `--root`
|
|
56
|
+
* (or its default) and hands the absolute path in. */
|
|
57
|
+
readonly root: string;
|
|
58
|
+
/** Optional glob, **replaces** {@link DEFAULT_MIGRATION_PATTERN}. */
|
|
59
|
+
readonly pattern?: string;
|
|
60
|
+
}
|
|
61
|
+
export interface ReadMigrationsResult {
|
|
62
|
+
/** One entry per successfully loaded migration file, sorted by
|
|
63
|
+
* `sourcePath`. */
|
|
64
|
+
readonly entries: readonly MigrationSourceEntry[];
|
|
65
|
+
/** Per-file failures collected across the walk; ordered the same
|
|
66
|
+
* way as discovery. Empty array when every file loaded cleanly. */
|
|
67
|
+
readonly failures: readonly LoadFailure[];
|
|
68
|
+
}
|
|
69
|
+
export declare function readMigrations(opts: ReadMigrationsOpts): Promise<ReadMigrationsResult>;
|
|
70
|
+
//# sourceMappingURL=read-migrations.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-migrations.d.ts","sourceRoot":"","sources":["../../src/loaders/read-migrations.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+CG;AAOH,OAAO,KAAK,EAAgB,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAMhF,OAAO,EAGL,KAAK,WAAW,EACjB,MAAM,iBAAiB,CAAC;AAEzB,YAAY,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC;AAMlD,eAAO,MAAM,yBAAyB,sBAAsB,CAAC;AAE7D,MAAM,WAAW,kBAAkB;IACjC;;2DAEuD;IACvD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC;wBACoB;IACpB,QAAQ,CAAC,OAAO,EAAE,SAAS,oBAAoB,EAAE,CAAC;IAClD;wEACoE;IACpE,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;CAC3C;AAMD,wBAAsB,cAAc,CAClC,IAAI,EAAE,kBAAkB,GACvB,OAAO,CAAC,oBAAoB,CAAC,CA0F/B"}
|