@nekostack/schema 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 +422 -0
- package/LICENSE +202 -0
- package/README.md +656 -0
- package/dist/src/builders/array.d.ts +12 -0
- package/dist/src/builders/array.d.ts.map +1 -0
- package/dist/src/builders/array.js +29 -0
- package/dist/src/builders/array.js.map +1 -0
- package/dist/src/builders/object.d.ts +62 -0
- package/dist/src/builders/object.d.ts.map +1 -0
- package/dist/src/builders/object.js +263 -0
- package/dist/src/builders/object.js.map +1 -0
- package/dist/src/builders/primitives.d.ts +37 -0
- package/dist/src/builders/primitives.d.ts.map +1 -0
- package/dist/src/builders/primitives.js +125 -0
- package/dist/src/builders/primitives.js.map +1 -0
- package/dist/src/builders/s.d.ts +27 -0
- package/dist/src/builders/s.d.ts.map +1 -0
- package/dist/src/builders/s.js +39 -0
- package/dist/src/builders/s.js.map +1 -0
- package/dist/src/builders/schema.d.ts +70 -0
- package/dist/src/builders/schema.d.ts.map +1 -0
- package/dist/src/builders/schema.js +98 -0
- package/dist/src/builders/schema.js.map +1 -0
- package/dist/src/cli-integration.d.ts +43 -0
- package/dist/src/cli-integration.d.ts.map +1 -0
- package/dist/src/cli-integration.js +48 -0
- package/dist/src/cli-integration.js.map +1 -0
- package/dist/src/errors/issue.d.ts +34 -0
- package/dist/src/errors/issue.d.ts.map +1 -0
- package/dist/src/errors/issue.js +89 -0
- package/dist/src/errors/issue.js.map +1 -0
- package/dist/src/generators/errors.d.ts +31 -0
- package/dist/src/generators/errors.d.ts.map +1 -0
- package/dist/src/generators/errors.js +34 -0
- package/dist/src/generators/errors.js.map +1 -0
- package/dist/src/generators/header.d.ts +42 -0
- package/dist/src/generators/header.d.ts.map +1 -0
- package/dist/src/generators/header.js +43 -0
- package/dist/src/generators/header.js.map +1 -0
- package/dist/src/generators/json-schema-meta.d.ts +36 -0
- package/dist/src/generators/json-schema-meta.d.ts.map +1 -0
- package/dist/src/generators/json-schema-meta.js +35 -0
- package/dist/src/generators/json-schema-meta.js.map +1 -0
- package/dist/src/generators/json-schema.d.ts +26 -0
- package/dist/src/generators/json-schema.d.ts.map +1 -0
- package/dist/src/generators/json-schema.js +88 -0
- package/dist/src/generators/json-schema.js.map +1 -0
- package/dist/src/generators/openapi.d.ts +33 -0
- package/dist/src/generators/openapi.d.ts.map +1 -0
- package/dist/src/generators/openapi.js +61 -0
- package/dist/src/generators/openapi.js.map +1 -0
- package/dist/src/generators/schema-fragment.d.ts +55 -0
- package/dist/src/generators/schema-fragment.d.ts.map +1 -0
- package/dist/src/generators/schema-fragment.js +253 -0
- package/dist/src/generators/schema-fragment.js.map +1 -0
- package/dist/src/generators/ts.d.ts +19 -0
- package/dist/src/generators/ts.d.ts.map +1 -0
- package/dist/src/generators/ts.js +252 -0
- package/dist/src/generators/ts.js.map +1 -0
- package/dist/src/generators/types.d.ts +96 -0
- package/dist/src/generators/types.d.ts.map +1 -0
- package/dist/src/generators/types.js +10 -0
- package/dist/src/generators/types.js.map +1 -0
- package/dist/src/generators/version.d.ts +11 -0
- package/dist/src/generators/version.d.ts.map +1 -0
- package/dist/src/generators/version.js +11 -0
- package/dist/src/generators/version.js.map +1 -0
- package/dist/src/generators/zod-mapping.d.ts +90 -0
- package/dist/src/generators/zod-mapping.d.ts.map +1 -0
- package/dist/src/generators/zod-mapping.js +174 -0
- package/dist/src/generators/zod-mapping.js.map +1 -0
- package/dist/src/generators/zod.d.ts +17 -0
- package/dist/src/generators/zod.d.ts.map +1 -0
- package/dist/src/generators/zod.js +118 -0
- package/dist/src/generators/zod.js.map +1 -0
- package/dist/src/index.d.ts +21 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +43 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/ir/hash.d.ts +19 -0
- package/dist/src/ir/hash.d.ts.map +1 -0
- package/dist/src/ir/hash.js +22 -0
- package/dist/src/ir/hash.js.map +1 -0
- package/dist/src/ir/nodes.d.ts +121 -0
- package/dist/src/ir/nodes.d.ts.map +1 -0
- package/dist/src/ir/nodes.js +14 -0
- package/dist/src/ir/nodes.js.map +1 -0
- package/dist/src/ir/serialize.d.ts +8 -0
- package/dist/src/ir/serialize.d.ts.map +1 -0
- package/dist/src/ir/serialize.js +23 -0
- package/dist/src/ir/serialize.js.map +1 -0
- package/dist/src/migrations/build-migration-registry.d.ts +46 -0
- package/dist/src/migrations/build-migration-registry.d.ts.map +1 -0
- package/dist/src/migrations/build-migration-registry.js +134 -0
- package/dist/src/migrations/build-migration-registry.js.map +1 -0
- package/dist/src/migrations/handlers/list.d.ts +35 -0
- package/dist/src/migrations/handlers/list.d.ts.map +1 -0
- package/dist/src/migrations/handlers/list.js +55 -0
- package/dist/src/migrations/handlers/list.js.map +1 -0
- package/dist/src/migrations/handlers/plan.d.ts +26 -0
- package/dist/src/migrations/handlers/plan.d.ts.map +1 -0
- package/dist/src/migrations/handlers/plan.js +28 -0
- package/dist/src/migrations/handlers/plan.js.map +1 -0
- package/dist/src/migrations/handlers/stub.d.ts +22 -0
- package/dist/src/migrations/handlers/stub.d.ts.map +1 -0
- package/dist/src/migrations/handlers/stub.js +24 -0
- package/dist/src/migrations/handlers/stub.js.map +1 -0
- package/dist/src/migrations/handlers/verify.d.ts +25 -0
- package/dist/src/migrations/handlers/verify.d.ts.map +1 -0
- package/dist/src/migrations/handlers/verify.js +27 -0
- package/dist/src/migrations/handlers/verify.js.map +1 -0
- package/dist/src/migrations/parse-provenance.d.ts +78 -0
- package/dist/src/migrations/parse-provenance.d.ts.map +1 -0
- package/dist/src/migrations/parse-provenance.js +157 -0
- package/dist/src/migrations/parse-provenance.js.map +1 -0
- package/dist/src/migrations/plan-migration.d.ts +50 -0
- package/dist/src/migrations/plan-migration.d.ts.map +1 -0
- package/dist/src/migrations/plan-migration.js +256 -0
- package/dist/src/migrations/plan-migration.js.map +1 -0
- package/dist/src/migrations/stub.d.ts +55 -0
- package/dist/src/migrations/stub.d.ts.map +1 -0
- package/dist/src/migrations/stub.js +201 -0
- package/dist/src/migrations/stub.js.map +1 -0
- package/dist/src/migrations/types.d.ts +297 -0
- package/dist/src/migrations/types.d.ts.map +1 -0
- package/dist/src/migrations/types.js +28 -0
- package/dist/src/migrations/types.js.map +1 -0
- package/dist/src/migrations/verify-provenance.d.ts +46 -0
- package/dist/src/migrations/verify-provenance.d.ts.map +1 -0
- package/dist/src/migrations/verify-provenance.js +158 -0
- package/dist/src/migrations/verify-provenance.js.map +1 -0
- package/dist/src/registry/build-registry.d.ts +65 -0
- package/dist/src/registry/build-registry.d.ts.map +1 -0
- package/dist/src/registry/build-registry.js +172 -0
- package/dist/src/registry/build-registry.js.map +1 -0
- package/dist/src/registry/diff.d.ts +25 -0
- package/dist/src/registry/diff.d.ts.map +1 -0
- package/dist/src/registry/diff.js +497 -0
- package/dist/src/registry/diff.js.map +1 -0
- package/dist/src/registry/handlers/check.d.ts +57 -0
- package/dist/src/registry/handlers/check.d.ts.map +1 -0
- package/dist/src/registry/handlers/check.js +181 -0
- package/dist/src/registry/handlers/check.js.map +1 -0
- package/dist/src/registry/handlers/diff.d.ts +33 -0
- package/dist/src/registry/handlers/diff.d.ts.map +1 -0
- package/dist/src/registry/handlers/diff.js +61 -0
- package/dist/src/registry/handlers/diff.js.map +1 -0
- package/dist/src/registry/handlers/generate.d.ts +87 -0
- package/dist/src/registry/handlers/generate.d.ts.map +1 -0
- package/dist/src/registry/handlers/generate.js +223 -0
- package/dist/src/registry/handlers/generate.js.map +1 -0
- package/dist/src/registry/handlers/list.d.ts +36 -0
- package/dist/src/registry/handlers/list.d.ts.map +1 -0
- package/dist/src/registry/handlers/list.js +84 -0
- package/dist/src/registry/handlers/list.js.map +1 -0
- package/dist/src/registry/parse-provenance.d.ts +63 -0
- package/dist/src/registry/parse-provenance.d.ts.map +1 -0
- package/dist/src/registry/parse-provenance.js +182 -0
- package/dist/src/registry/parse-provenance.js.map +1 -0
- package/dist/src/registry/source-hash.d.ts +28 -0
- package/dist/src/registry/source-hash.d.ts.map +1 -0
- package/dist/src/registry/source-hash.js +32 -0
- package/dist/src/registry/source-hash.js.map +1 -0
- package/dist/src/registry/types.d.ts +185 -0
- package/dist/src/registry/types.d.ts.map +1 -0
- package/dist/src/registry/types.js +22 -0
- package/dist/src/registry/types.js.map +1 -0
- package/dist/src/runtime/compile.d.ts +38 -0
- package/dist/src/runtime/compile.d.ts.map +1 -0
- package/dist/src/runtime/compile.js +45 -0
- package/dist/src/runtime/compile.js.map +1 -0
- package/dist/src/runtime/errors.d.ts +25 -0
- package/dist/src/runtime/errors.d.ts.map +1 -0
- package/dist/src/runtime/errors.js +43 -0
- package/dist/src/runtime/errors.js.map +1 -0
- package/dist/src/runtime/normalize-issues.d.ts +65 -0
- package/dist/src/runtime/normalize-issues.d.ts.map +1 -0
- package/dist/src/runtime/normalize-issues.js +208 -0
- package/dist/src/runtime/normalize-issues.js.map +1 -0
- package/dist/src/runtime/parse.d.ts +62 -0
- package/dist/src/runtime/parse.d.ts.map +1 -0
- package/dist/src/runtime/parse.js +107 -0
- package/dist/src/runtime/parse.js.map +1 -0
- package/dist/src/runtime/strip-defaults.d.ts +51 -0
- package/dist/src/runtime/strip-defaults.d.ts.map +1 -0
- package/dist/src/runtime/strip-defaults.js +81 -0
- package/dist/src/runtime/strip-defaults.js.map +1 -0
- package/dist/src/runtime/zod-compile.d.ts +27 -0
- package/dist/src/runtime/zod-compile.d.ts.map +1 -0
- package/dist/src/runtime/zod-compile.js +92 -0
- package/dist/src/runtime/zod-compile.js.map +1 -0
- package/dist/src/types.d.ts +116 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +2 -0
- package/dist/src/types.js.map +1 -0
- package/docs/ABSENCE_SEMANTICS.md +37 -0
- package/docs/BENCHMARKS.md +64 -0
- package/docs/COMPOSITION.md +206 -0
- package/docs/DIFF_CLASSIFICATION.md +137 -0
- package/docs/EXAMPLES.md +221 -0
- package/docs/HEADER_FORMAT.md +66 -0
- package/docs/INVARIANTS.md +58 -0
- package/docs/IR_CONTRACT.md +67 -0
- package/docs/ISSUE_CODES.md +99 -0
- package/docs/JSON_SCHEMA_MAPPING.md +149 -0
- package/docs/MIGRATIONS.md +406 -0
- package/docs/MIGRATION_GUIDE.md +150 -0
- package/docs/OPENAPI_MAPPING.md +66 -0
- package/docs/REGISTRY.md +336 -0
- package/docs/RUNTIME.md +279 -0
- package/docs/SCOPE.md +119 -0
- package/docs/USAGE.md +376 -0
- package/docs/ZOD_MODIFIER_ORDERING.md +77 -0
- package/package.json +45 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `checkHandler({ registry, committedArtifacts })` — freshness check
|
|
3
|
+
* via the two-hash matrix from Master plan §"Freshness verdict —
|
|
4
|
+
* two-hash discipline".
|
|
5
|
+
*
|
|
6
|
+
* Pure. No filesystem, no `import()`, no `process.*`, no `console.*`.
|
|
7
|
+
* The CLI reads each artifact's bytes from disk and hands them in;
|
|
8
|
+
* this function parses provenance, looks up the matching
|
|
9
|
+
* `RegistryEntry`, and produces one `FreshnessVerdict` per artifact.
|
|
10
|
+
* Master plan Decision #1 boundary.
|
|
11
|
+
*
|
|
12
|
+
* ## Two-hash matrix
|
|
13
|
+
*
|
|
14
|
+
* | artifact irHash | artifact sourceHash | verdict |
|
|
15
|
+
* |---|---|---|
|
|
16
|
+
* | matches registry | matches registry | `clean` |
|
|
17
|
+
* | matches registry | **differs** | `cosmetic_drift` |
|
|
18
|
+
* | **differs** | **differs** | `stale` |
|
|
19
|
+
* | **differs** | matches registry | `integrity_error` (the impossible row — should never happen unless the artifact was hand-edited or the recorded sourceHash was tampered with) |
|
|
20
|
+
*
|
|
21
|
+
* ## v0.6 backward compatibility (Master plan Decision #8)
|
|
22
|
+
*
|
|
23
|
+
* Artifacts emitted before Step 4 (`@nekostack/schema@0.6.0` and
|
|
24
|
+
* earlier) have no `sourceHash` field/line. `parseProvenanceFromText`
|
|
25
|
+
* returns `sourceHash: undefined` for those. Treat as:
|
|
26
|
+
*
|
|
27
|
+
* - `irHash` matches registry → `clean`
|
|
28
|
+
* - `irHash` differs from registry → `stale`
|
|
29
|
+
*
|
|
30
|
+
* Absent `sourceHash` is **never** an integrity error by itself — the
|
|
31
|
+
* artifact simply predates the two-hash discipline. Once the user
|
|
32
|
+
* regenerates the artifact at v0.7+, full matrix participation
|
|
33
|
+
* resumes.
|
|
34
|
+
*
|
|
35
|
+
* ## Failure paths (Result<...> failure)
|
|
36
|
+
*
|
|
37
|
+
* - **Malformed provenance** — `parseProvenanceFromText` already
|
|
38
|
+
* returns an `integrity_error` Issue; this handler forwards those
|
|
39
|
+
* issues with the artifact path attached.
|
|
40
|
+
* - **Anonymous artifact** (provenance `schemaId === null`) —
|
|
41
|
+
* `schema_not_found` with `metadata.reason = "anonymous_artifact"`.
|
|
42
|
+
* The registry never indexes anonymous schemas (Master plan
|
|
43
|
+
* Decision #5), so there's nothing to validate against.
|
|
44
|
+
* - **schemaId not in registry** — `schema_not_found`. The user
|
|
45
|
+
* likely deleted a schema source file but forgot to delete the
|
|
46
|
+
* generated artifacts.
|
|
47
|
+
* - **schemaId present but version not in registry** —
|
|
48
|
+
* `version_not_found`. Distinct code so the CLI can format
|
|
49
|
+
* orphan-by-id vs. orphan-by-version differently.
|
|
50
|
+
*
|
|
51
|
+
* Any artifact failure surfaces as `Result.failure` for the whole
|
|
52
|
+
* check call. Per-artifact verdicts are returned only when EVERY
|
|
53
|
+
* artifact parses + resolves cleanly.
|
|
54
|
+
*/
|
|
55
|
+
import { findSchema } from "../build-registry.js";
|
|
56
|
+
import { parseProvenanceFromText } from "../parse-provenance.js";
|
|
57
|
+
export function checkHandler(opts) {
|
|
58
|
+
const verdicts = [];
|
|
59
|
+
const issues = [];
|
|
60
|
+
for (const artifact of opts.committedArtifacts) {
|
|
61
|
+
const r = classifyArtifact(artifact, opts.registry);
|
|
62
|
+
if (r.kind === "verdict") {
|
|
63
|
+
verdicts.push(r.verdict);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
issues.push(...r.issues);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (issues.length > 0) {
|
|
70
|
+
return { success: false, issues };
|
|
71
|
+
}
|
|
72
|
+
return { success: true, data: { verdicts } };
|
|
73
|
+
}
|
|
74
|
+
function classifyArtifact(artifact, registry) {
|
|
75
|
+
// 1. Parse provenance. Forward failures with the artifact path.
|
|
76
|
+
const parsed = parseProvenanceFromText(artifact.content);
|
|
77
|
+
if (!parsed.success) {
|
|
78
|
+
return {
|
|
79
|
+
kind: "issues",
|
|
80
|
+
issues: parsed.issues.map((i) => ({
|
|
81
|
+
...i,
|
|
82
|
+
path: [artifact.path],
|
|
83
|
+
metadata: { ...(i.metadata ?? {}), artifactPath: artifact.path },
|
|
84
|
+
})),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
const { schemaId, schemaVersion, irHash, sourceHash } = parsed.data;
|
|
88
|
+
// 2. Anonymous artifact — registry never indexes anonymous schemas.
|
|
89
|
+
if (schemaId === null) {
|
|
90
|
+
return {
|
|
91
|
+
kind: "issues",
|
|
92
|
+
issues: [
|
|
93
|
+
{
|
|
94
|
+
code: "schema_not_found",
|
|
95
|
+
path: [artifact.path],
|
|
96
|
+
message: `Anonymous artifact \`${artifact.path}\` cannot be validated; registry does not index anonymous schemas.`,
|
|
97
|
+
severity: "error",
|
|
98
|
+
metadata: {
|
|
99
|
+
reason: "anonymous_artifact",
|
|
100
|
+
artifactPath: artifact.path,
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
],
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
// 3. Look up the (schemaId, schemaVersion) pair in the registry.
|
|
107
|
+
// Pass the version explicitly so `findSchema` does exact-match
|
|
108
|
+
// rather than highest-semver fallback.
|
|
109
|
+
const versionKey = schemaVersion ?? "";
|
|
110
|
+
const entry = findSchema(registry, schemaId, versionKey);
|
|
111
|
+
if (entry === undefined) {
|
|
112
|
+
const idKnown = registry.has(schemaId);
|
|
113
|
+
return {
|
|
114
|
+
kind: "issues",
|
|
115
|
+
issues: [
|
|
116
|
+
idKnown
|
|
117
|
+
? versionNotFoundIssue(artifact, schemaId, schemaVersion)
|
|
118
|
+
: schemaNotFoundIssue(artifact, schemaId, schemaVersion),
|
|
119
|
+
],
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// 4. Apply the two-hash matrix.
|
|
123
|
+
return { kind: "verdict", verdict: verdictFor(artifact, irHash, sourceHash, entry) };
|
|
124
|
+
}
|
|
125
|
+
function verdictFor(artifact, artifactIrHash, artifactSourceHash, entry) {
|
|
126
|
+
const irMatch = artifactIrHash === entry.irHash;
|
|
127
|
+
// v0.6-era artifact: no sourceHash recorded.
|
|
128
|
+
// - irHash match → clean
|
|
129
|
+
// - irHash differ → stale
|
|
130
|
+
// Never integrity_error.
|
|
131
|
+
if (artifactSourceHash === undefined) {
|
|
132
|
+
return {
|
|
133
|
+
status: irMatch ? "clean" : "stale",
|
|
134
|
+
artifactPath: artifact.path,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
const sourceMatch = artifactSourceHash === entry.sourceHash;
|
|
138
|
+
let status;
|
|
139
|
+
if (irMatch && sourceMatch)
|
|
140
|
+
status = "clean";
|
|
141
|
+
else if (irMatch && !sourceMatch)
|
|
142
|
+
status = "cosmetic_drift";
|
|
143
|
+
else if (!irMatch && !sourceMatch)
|
|
144
|
+
status = "stale";
|
|
145
|
+
else
|
|
146
|
+
status = "integrity_error";
|
|
147
|
+
return { status, artifactPath: artifact.path };
|
|
148
|
+
}
|
|
149
|
+
// =============================================================================
|
|
150
|
+
// Issue constructors
|
|
151
|
+
// =============================================================================
|
|
152
|
+
function schemaNotFoundIssue(artifact, schemaId, schemaVersion) {
|
|
153
|
+
return {
|
|
154
|
+
code: "schema_not_found",
|
|
155
|
+
path: [artifact.path],
|
|
156
|
+
message: `Schema \`${schemaId}\` referenced by artifact \`${artifact.path}\` is not in the registry. ` +
|
|
157
|
+
`The schema source may have been deleted; remove the generated artifact or restore the source.`,
|
|
158
|
+
severity: "error",
|
|
159
|
+
metadata: {
|
|
160
|
+
artifactPath: artifact.path,
|
|
161
|
+
schemaId,
|
|
162
|
+
schemaVersion: schemaVersion ?? null,
|
|
163
|
+
},
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function versionNotFoundIssue(artifact, schemaId, schemaVersion) {
|
|
167
|
+
const versionLabel = schemaVersion === null ? "(unversioned)" : `v${schemaVersion}`;
|
|
168
|
+
return {
|
|
169
|
+
code: "version_not_found",
|
|
170
|
+
path: [artifact.path],
|
|
171
|
+
message: `Schema \`${schemaId}\` exists in the registry but version \`${versionLabel}\` (referenced by \`${artifact.path}\`) does not. ` +
|
|
172
|
+
`Regenerate the artifact against the current schema versions.`,
|
|
173
|
+
severity: "error",
|
|
174
|
+
metadata: {
|
|
175
|
+
artifactPath: artifact.path,
|
|
176
|
+
schemaId,
|
|
177
|
+
schemaVersion: schemaVersion ?? null,
|
|
178
|
+
},
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../../src/registry/handlers/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `diffHandler({ before, after })` — wraps Step 7's `diffNodes` and
|
|
3
|
+
* adds the `worstSeverity` aggregation that Master plan Decision #13
|
|
4
|
+
* relies on for CLI exit-code mapping.
|
|
5
|
+
*
|
|
6
|
+
* Pure. No filesystem, no `import()`, no `process.*`, no `console.*`.
|
|
7
|
+
* Master plan Decision #1 boundary.
|
|
8
|
+
*
|
|
9
|
+
* **Severity precedence**: `breaking` > `additive` > `cosmetic`. The
|
|
10
|
+
* `worstSeverity` field is `null` exactly when `changes.length === 0`.
|
|
11
|
+
* Per Decision #13: a `schemaVersion`-only change paired with
|
|
12
|
+
* structural changes inherits the worst structural severity — that
|
|
13
|
+
* rule is realized naturally here because every change keeps its own
|
|
14
|
+
* severity (set by `diffNodes`); `worstSeverity` is the max over the
|
|
15
|
+
* full list.
|
|
16
|
+
*
|
|
17
|
+
* **`UnsupportedNodeKindError` propagates.** When `diffNodes` throws
|
|
18
|
+
* for an unsupported IR kind (`date`, `union`, `recursiveRef`,
|
|
19
|
+
* `transform`), this handler does NOT catch — it lets the throw
|
|
20
|
+
* propagate to the CLI dispatcher (Step 28+), where it maps to a
|
|
21
|
+
* non-zero exit code at the CLI boundary. This matches Master plan
|
|
22
|
+
* Decision #14's "throw at the boundary" language and the v0.6
|
|
23
|
+
* convention (`runtime/parse.ts` also propagates rather than
|
|
24
|
+
* normalizing into `Result`). Treating an unsupported IR kind as an
|
|
25
|
+
* `integrity_error` (the closest existing v0.7 code) would be
|
|
26
|
+
* semantically wrong — the IR is well-formed; v0.7 just doesn't
|
|
27
|
+
* know how to diff it. Inventing a new code (`schema_diff_failed`)
|
|
28
|
+
* without it being in the locked plan would expand the v0.7 vocabulary
|
|
29
|
+
* casually.
|
|
30
|
+
*/
|
|
31
|
+
import type { DiffOpts, DiffResult } from "../types.js";
|
|
32
|
+
export declare function diffHandler(opts: DiffOpts): DiffResult;
|
|
33
|
+
//# sourceMappingURL=diff.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.ts","sourceRoot":"","sources":["../../../../src/registry/handlers/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAGH,OAAO,KAAK,EAEV,QAAQ,EACR,UAAU,EAEX,MAAM,aAAa,CAAC;AAErB,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAStD"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `diffHandler({ before, after })` — wraps Step 7's `diffNodes` and
|
|
3
|
+
* adds the `worstSeverity` aggregation that Master plan Decision #13
|
|
4
|
+
* relies on for CLI exit-code mapping.
|
|
5
|
+
*
|
|
6
|
+
* Pure. No filesystem, no `import()`, no `process.*`, no `console.*`.
|
|
7
|
+
* Master plan Decision #1 boundary.
|
|
8
|
+
*
|
|
9
|
+
* **Severity precedence**: `breaking` > `additive` > `cosmetic`. The
|
|
10
|
+
* `worstSeverity` field is `null` exactly when `changes.length === 0`.
|
|
11
|
+
* Per Decision #13: a `schemaVersion`-only change paired with
|
|
12
|
+
* structural changes inherits the worst structural severity — that
|
|
13
|
+
* rule is realized naturally here because every change keeps its own
|
|
14
|
+
* severity (set by `diffNodes`); `worstSeverity` is the max over the
|
|
15
|
+
* full list.
|
|
16
|
+
*
|
|
17
|
+
* **`UnsupportedNodeKindError` propagates.** When `diffNodes` throws
|
|
18
|
+
* for an unsupported IR kind (`date`, `union`, `recursiveRef`,
|
|
19
|
+
* `transform`), this handler does NOT catch — it lets the throw
|
|
20
|
+
* propagate to the CLI dispatcher (Step 28+), where it maps to a
|
|
21
|
+
* non-zero exit code at the CLI boundary. This matches Master plan
|
|
22
|
+
* Decision #14's "throw at the boundary" language and the v0.6
|
|
23
|
+
* convention (`runtime/parse.ts` also propagates rather than
|
|
24
|
+
* normalizing into `Result`). Treating an unsupported IR kind as an
|
|
25
|
+
* `integrity_error` (the closest existing v0.7 code) would be
|
|
26
|
+
* semantically wrong — the IR is well-formed; v0.7 just doesn't
|
|
27
|
+
* know how to diff it. Inventing a new code (`schema_diff_failed`)
|
|
28
|
+
* without it being in the locked plan would expand the v0.7 vocabulary
|
|
29
|
+
* casually.
|
|
30
|
+
*/
|
|
31
|
+
import { diffNodes } from "../diff.js";
|
|
32
|
+
export function diffHandler(opts) {
|
|
33
|
+
const changes = diffNodes(opts.before, opts.after);
|
|
34
|
+
return {
|
|
35
|
+
success: true,
|
|
36
|
+
data: {
|
|
37
|
+
changes,
|
|
38
|
+
worstSeverity: computeWorstSeverity(changes),
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
// =============================================================================
|
|
43
|
+
// worstSeverity aggregation (Master plan Decision #13)
|
|
44
|
+
// =============================================================================
|
|
45
|
+
const SEVERITY_RANK = {
|
|
46
|
+
cosmetic: 0,
|
|
47
|
+
additive: 1,
|
|
48
|
+
breaking: 2,
|
|
49
|
+
};
|
|
50
|
+
function computeWorstSeverity(changes) {
|
|
51
|
+
if (changes.length === 0)
|
|
52
|
+
return null;
|
|
53
|
+
let worst = "cosmetic";
|
|
54
|
+
for (const c of changes) {
|
|
55
|
+
if (SEVERITY_RANK[c.severity] > SEVERITY_RANK[worst]) {
|
|
56
|
+
worst = c.severity;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return worst;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=diff.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.js","sourceRoot":"","sources":["../../../../src/registry/handlers/diff.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAQvC,MAAM,UAAU,WAAW,CAAC,IAAc;IACxC,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;IACnD,OAAO;QACL,OAAO,EAAE,IAAI;QACb,IAAI,EAAE;YACJ,OAAO;YACP,aAAa,EAAE,oBAAoB,CAAC,OAAO,CAAC;SAC7C;KACF,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,uDAAuD;AACvD,gFAAgF;AAEhF,MAAM,aAAa,GAAiC;IAClD,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;IACX,QAAQ,EAAE,CAAC;CACZ,CAAC;AAEF,SAAS,oBAAoB,CAC3B,OAA8B;IAE9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACtC,IAAI,KAAK,GAAiB,UAAU,CAAC;IACrC,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACxB,IAAI,aAAa,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,aAAa,CAAC,KAAK,CAAC,EAAE,CAAC;YACrD,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC;QACrB,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `generateHandler({ entries })` — pure generation planner.
|
|
3
|
+
*
|
|
4
|
+
* For every **named** schema in every `RegistrySourceEntry`, emits
|
|
5
|
+
* all four artifact kinds (TypeScript / Zod / JSON Schema / OpenAPI)
|
|
6
|
+
* as `GeneratedArtifact` payloads with `suggestedPath`s relative to
|
|
7
|
+
* the schema's source location. The CLI is responsible for writing
|
|
8
|
+
* each payload to its suggested path; this handler never touches
|
|
9
|
+
* the filesystem.
|
|
10
|
+
*
|
|
11
|
+
* Master plan Decision #1 boundary: pure, data-in / data-out. No
|
|
12
|
+
* `fs.*`, no `import()`, no `process.*`, no `console.*`. The
|
|
13
|
+
* `sourceText` is hashed once per entry via `sourceHashFromText`
|
|
14
|
+
* (Step 2). `sourceHash` is passed through to each generator's
|
|
15
|
+
* `ProvenanceOptions` (Step 3 + Step 4) so the emitted artifact
|
|
16
|
+
* bytes carry provenance; `irHash(schema.node)` is recorded
|
|
17
|
+
* separately on each `GeneratedArtifact` and independently emitted
|
|
18
|
+
* by the generators from `schema.node` — the irHash field is NOT
|
|
19
|
+
* part of `ProvenanceOptions`.
|
|
20
|
+
*
|
|
21
|
+
* **Anonymous schemas (no `.id()`)** are silently skipped — they
|
|
22
|
+
* cannot participate in registry lookup downstream, so emitting
|
|
23
|
+
* artifacts for them is meaningless. The CLI warns; this handler
|
|
24
|
+
* is silent (Master plan Decision #5).
|
|
25
|
+
*
|
|
26
|
+
* **Partial generation is not supported in v0.7** (Master plan
|
|
27
|
+
* Decision #6). `GenerateOpts` carries no `kinds` filter; every
|
|
28
|
+
* named schema produces exactly 4 artifacts. The CLI's `check`
|
|
29
|
+
* verb expects all 4 to be present on disk.
|
|
30
|
+
*
|
|
31
|
+
* ## Suggested path convention (Master plan Decision #6 locked)
|
|
32
|
+
*
|
|
33
|
+
* **Single named schema in a source file:**
|
|
34
|
+
*
|
|
35
|
+
* <schema-dir>/<basename>.schema.{ts,js}
|
|
36
|
+
* ↓
|
|
37
|
+
* <schema-dir>/generated/<basename>.types.ts
|
|
38
|
+
* <schema-dir>/generated/<basename>.zod.ts
|
|
39
|
+
* <schema-dir>/generated/<basename>.json.schema.json
|
|
40
|
+
* <schema-dir>/generated/<basename>.openapi.json
|
|
41
|
+
*
|
|
42
|
+
* **Multiple named schemas in one source file** — paths gain a
|
|
43
|
+
* schemaId-derived discriminator slug so the four-artifact set per
|
|
44
|
+
* schema doesn't collide on disk:
|
|
45
|
+
*
|
|
46
|
+
* <schema-dir>/<basename>.schema.ts
|
|
47
|
+
* export const Tenant = s.object(...).id("com.x.Tenant");
|
|
48
|
+
* export const Audit = s.object(...).id("com.x.AuditEvent");
|
|
49
|
+
* ↓
|
|
50
|
+
* <schema-dir>/generated/<basename>.com-x-tenant.types.ts
|
|
51
|
+
* <schema-dir>/generated/<basename>.com-x-auditevent.types.ts
|
|
52
|
+
* <schema-dir>/generated/<basename>.com-x-tenant.zod.ts
|
|
53
|
+
* ... and so on for json/openapi.
|
|
54
|
+
*
|
|
55
|
+
* Slug rule: lowercase, non-alphanumeric runs collapse to `-`, with
|
|
56
|
+
* leading/trailing `-` trimmed. If a source file declares the same
|
|
57
|
+
* `schemaId` at multiple versions (rare; v0.7 doesn't endorse but
|
|
58
|
+
* does tolerate), the discriminator additionally includes a slugged
|
|
59
|
+
* version (`com-x-tenant-1-0-0`) so per-schema paths stay unique.
|
|
60
|
+
*
|
|
61
|
+
* The basename strips a `.schema.{ts,js,mts,cts}` suffix when
|
|
62
|
+
* present; falls back to "filename minus last extension" otherwise.
|
|
63
|
+
* Source-path parsing is plain string manipulation — no `node:path`
|
|
64
|
+
* import — to keep the handler trivially platform-agnostic.
|
|
65
|
+
*/
|
|
66
|
+
import type { GenerateOpts, GenerateResult, GeneratorKind, RegistrySourceEntry } from "../types.js";
|
|
67
|
+
declare const GENERATOR_KINDS: readonly GeneratorKind[];
|
|
68
|
+
export declare function generateHandler(opts: GenerateOpts): GenerateResult;
|
|
69
|
+
/**
|
|
70
|
+
* `<schema-dir>/<basename>.schema.ts` → `<schema-dir>/generated/<basename>[.<discriminator>].<ext>`.
|
|
71
|
+
*
|
|
72
|
+
* Pure string manipulation; no `node:path` import. Forward slashes
|
|
73
|
+
* are the canonical separator in the suggested path even on Windows
|
|
74
|
+
* — the CLI normalizes back to platform separators on write
|
|
75
|
+
* (separate concern; Step 31).
|
|
76
|
+
*
|
|
77
|
+
* The optional `discriminator` is inserted between the basename and
|
|
78
|
+
* the artifact extension. The handler computes it per-entry via
|
|
79
|
+
* `discriminatorsFor` (see above); callers that know they have a
|
|
80
|
+
* single-schema source file may omit the option entirely.
|
|
81
|
+
*/
|
|
82
|
+
export declare function suggestedPathFor(sourcePath: string, kind: GeneratorKind, options?: {
|
|
83
|
+
readonly discriminator?: string;
|
|
84
|
+
}): string;
|
|
85
|
+
export { GENERATOR_KINDS };
|
|
86
|
+
export type { RegistrySourceEntry };
|
|
87
|
+
//# sourceMappingURL=generate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.d.ts","sourceRoot":"","sources":["../../../../src/registry/handlers/generate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AAQH,OAAO,KAAK,EAEV,YAAY,EACZ,cAAc,EACd,aAAa,EACb,mBAAmB,EACpB,MAAM,aAAa,CAAC;AAIrB,QAAA,MAAM,eAAe,EAAE,SAAS,aAAa,EAK5C,CAAC;AAEF,wBAAgB,eAAe,CAAC,IAAI,EAAE,YAAY,GAAG,cAAc,CA6BlE;AAqGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE;IAAE,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAA;CAAO,GAChD,MAAM,CAaR;AAaD,OAAO,EAAE,eAAe,EAAE,CAAC;AAG3B,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `generateHandler({ entries })` — pure generation planner.
|
|
3
|
+
*
|
|
4
|
+
* For every **named** schema in every `RegistrySourceEntry`, emits
|
|
5
|
+
* all four artifact kinds (TypeScript / Zod / JSON Schema / OpenAPI)
|
|
6
|
+
* as `GeneratedArtifact` payloads with `suggestedPath`s relative to
|
|
7
|
+
* the schema's source location. The CLI is responsible for writing
|
|
8
|
+
* each payload to its suggested path; this handler never touches
|
|
9
|
+
* the filesystem.
|
|
10
|
+
*
|
|
11
|
+
* Master plan Decision #1 boundary: pure, data-in / data-out. No
|
|
12
|
+
* `fs.*`, no `import()`, no `process.*`, no `console.*`. The
|
|
13
|
+
* `sourceText` is hashed once per entry via `sourceHashFromText`
|
|
14
|
+
* (Step 2). `sourceHash` is passed through to each generator's
|
|
15
|
+
* `ProvenanceOptions` (Step 3 + Step 4) so the emitted artifact
|
|
16
|
+
* bytes carry provenance; `irHash(schema.node)` is recorded
|
|
17
|
+
* separately on each `GeneratedArtifact` and independently emitted
|
|
18
|
+
* by the generators from `schema.node` — the irHash field is NOT
|
|
19
|
+
* part of `ProvenanceOptions`.
|
|
20
|
+
*
|
|
21
|
+
* **Anonymous schemas (no `.id()`)** are silently skipped — they
|
|
22
|
+
* cannot participate in registry lookup downstream, so emitting
|
|
23
|
+
* artifacts for them is meaningless. The CLI warns; this handler
|
|
24
|
+
* is silent (Master plan Decision #5).
|
|
25
|
+
*
|
|
26
|
+
* **Partial generation is not supported in v0.7** (Master plan
|
|
27
|
+
* Decision #6). `GenerateOpts` carries no `kinds` filter; every
|
|
28
|
+
* named schema produces exactly 4 artifacts. The CLI's `check`
|
|
29
|
+
* verb expects all 4 to be present on disk.
|
|
30
|
+
*
|
|
31
|
+
* ## Suggested path convention (Master plan Decision #6 locked)
|
|
32
|
+
*
|
|
33
|
+
* **Single named schema in a source file:**
|
|
34
|
+
*
|
|
35
|
+
* <schema-dir>/<basename>.schema.{ts,js}
|
|
36
|
+
* ↓
|
|
37
|
+
* <schema-dir>/generated/<basename>.types.ts
|
|
38
|
+
* <schema-dir>/generated/<basename>.zod.ts
|
|
39
|
+
* <schema-dir>/generated/<basename>.json.schema.json
|
|
40
|
+
* <schema-dir>/generated/<basename>.openapi.json
|
|
41
|
+
*
|
|
42
|
+
* **Multiple named schemas in one source file** — paths gain a
|
|
43
|
+
* schemaId-derived discriminator slug so the four-artifact set per
|
|
44
|
+
* schema doesn't collide on disk:
|
|
45
|
+
*
|
|
46
|
+
* <schema-dir>/<basename>.schema.ts
|
|
47
|
+
* export const Tenant = s.object(...).id("com.x.Tenant");
|
|
48
|
+
* export const Audit = s.object(...).id("com.x.AuditEvent");
|
|
49
|
+
* ↓
|
|
50
|
+
* <schema-dir>/generated/<basename>.com-x-tenant.types.ts
|
|
51
|
+
* <schema-dir>/generated/<basename>.com-x-auditevent.types.ts
|
|
52
|
+
* <schema-dir>/generated/<basename>.com-x-tenant.zod.ts
|
|
53
|
+
* ... and so on for json/openapi.
|
|
54
|
+
*
|
|
55
|
+
* Slug rule: lowercase, non-alphanumeric runs collapse to `-`, with
|
|
56
|
+
* leading/trailing `-` trimmed. If a source file declares the same
|
|
57
|
+
* `schemaId` at multiple versions (rare; v0.7 doesn't endorse but
|
|
58
|
+
* does tolerate), the discriminator additionally includes a slugged
|
|
59
|
+
* version (`com-x-tenant-1-0-0`) so per-schema paths stay unique.
|
|
60
|
+
*
|
|
61
|
+
* The basename strips a `.schema.{ts,js,mts,cts}` suffix when
|
|
62
|
+
* present; falls back to "filename minus last extension" otherwise.
|
|
63
|
+
* Source-path parsing is plain string manipulation — no `node:path`
|
|
64
|
+
* import — to keep the handler trivially platform-agnostic.
|
|
65
|
+
*/
|
|
66
|
+
import { irHash } from "../../ir/hash.js";
|
|
67
|
+
import { generateTypeScript } from "../../generators/ts.js";
|
|
68
|
+
import { generateZod } from "../../generators/zod.js";
|
|
69
|
+
import { generateJsonSchema } from "../../generators/json-schema.js";
|
|
70
|
+
import { generateOpenApiSchemaComponent } from "../../generators/openapi.js";
|
|
71
|
+
import { sourceHashFromText } from "../source-hash.js";
|
|
72
|
+
const GENERATOR_KINDS = [
|
|
73
|
+
"typescript",
|
|
74
|
+
"zod",
|
|
75
|
+
"jsonSchema",
|
|
76
|
+
"openApi",
|
|
77
|
+
];
|
|
78
|
+
export function generateHandler(opts) {
|
|
79
|
+
const artifacts = [];
|
|
80
|
+
for (const entry of opts.entries) {
|
|
81
|
+
const entrySourceHash = sourceHashFromText(entry.sourceText);
|
|
82
|
+
const discriminators = discriminatorsFor(entry);
|
|
83
|
+
for (const schema of entry.schemas) {
|
|
84
|
+
const schemaId = schema.node.metadata?.id;
|
|
85
|
+
if (schemaId === undefined)
|
|
86
|
+
continue; // anonymous → skip
|
|
87
|
+
const schemaIrHash = `sha256:${irHash(schema.node)}`;
|
|
88
|
+
const discriminator = discriminators.get(schema);
|
|
89
|
+
for (const kind of GENERATOR_KINDS) {
|
|
90
|
+
artifacts.push({
|
|
91
|
+
schemaId,
|
|
92
|
+
kind,
|
|
93
|
+
suggestedPath: suggestedPathFor(entry.sourcePath, kind, {
|
|
94
|
+
...(discriminator !== undefined ? { discriminator } : {}),
|
|
95
|
+
}),
|
|
96
|
+
content: renderArtifact(kind, schema, entrySourceHash),
|
|
97
|
+
irHash: schemaIrHash,
|
|
98
|
+
sourceHash: entrySourceHash,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return { success: true, data: { artifacts } };
|
|
104
|
+
}
|
|
105
|
+
// =============================================================================
|
|
106
|
+
// Per-entry discriminator slugs (Master plan Decision #6 multi-schema rule)
|
|
107
|
+
// =============================================================================
|
|
108
|
+
/**
|
|
109
|
+
* For one `RegistrySourceEntry`, decide the discriminator slug each
|
|
110
|
+
* named schema needs on its `suggestedPath`:
|
|
111
|
+
*
|
|
112
|
+
* - Entry contains exactly 0 or 1 named schemas → no discriminator.
|
|
113
|
+
* - Entry contains 2+ named schemas with **distinct ids** →
|
|
114
|
+
* discriminator = `slugify(schemaId)`.
|
|
115
|
+
* - Entry contains 2+ named schemas where **at least one id appears
|
|
116
|
+
* more than once** (different versions of the same id in one
|
|
117
|
+
* source file — rare) → for the IDs that repeat, the discriminator
|
|
118
|
+
* additionally embeds the slugged version so per-schema paths
|
|
119
|
+
* stay unique. IDs that appear only once still use the id-only
|
|
120
|
+
* slug.
|
|
121
|
+
*
|
|
122
|
+
* Returned `Map` is keyed by the original `AnySchema` instance so
|
|
123
|
+
* the handler loop can look up each schema's discriminator without
|
|
124
|
+
* re-deriving it. Anonymous schemas are not represented in the map.
|
|
125
|
+
*/
|
|
126
|
+
function discriminatorsFor(entry) {
|
|
127
|
+
const result = new Map();
|
|
128
|
+
const named = entry.schemas.filter((s) => s.node.metadata?.id !== undefined);
|
|
129
|
+
if (named.length <= 1) {
|
|
130
|
+
for (const s of named)
|
|
131
|
+
result.set(s, undefined);
|
|
132
|
+
return result;
|
|
133
|
+
}
|
|
134
|
+
// Multiple named schemas — disambiguation needed. Count id
|
|
135
|
+
// occurrences; if any id appears more than once, those entries
|
|
136
|
+
// get the version-suffixed slug to stay unique.
|
|
137
|
+
const idCounts = new Map();
|
|
138
|
+
for (const s of named) {
|
|
139
|
+
const id = s.node.metadata.id;
|
|
140
|
+
idCounts.set(id, (idCounts.get(id) ?? 0) + 1);
|
|
141
|
+
}
|
|
142
|
+
for (const s of named) {
|
|
143
|
+
const id = s.node.metadata.id;
|
|
144
|
+
const version = s.node.metadata?.version;
|
|
145
|
+
const idSlug = slugify(id);
|
|
146
|
+
const sameIdElsewhere = (idCounts.get(id) ?? 0) > 1;
|
|
147
|
+
const slug = sameIdElsewhere && version !== undefined
|
|
148
|
+
? `${idSlug}-${slugify(version)}`
|
|
149
|
+
: idSlug;
|
|
150
|
+
result.set(s, slug);
|
|
151
|
+
}
|
|
152
|
+
return result;
|
|
153
|
+
}
|
|
154
|
+
/** Lowercase, non-alphanumeric runs → `-`, trim leading/trailing `-`. */
|
|
155
|
+
function slugify(s) {
|
|
156
|
+
return s
|
|
157
|
+
.toLowerCase()
|
|
158
|
+
.replace(/[^a-z0-9]+/g, "-")
|
|
159
|
+
.replace(/^-+|-+$/g, "");
|
|
160
|
+
}
|
|
161
|
+
// =============================================================================
|
|
162
|
+
// Per-kind dispatch
|
|
163
|
+
// =============================================================================
|
|
164
|
+
function renderArtifact(kind, schema, sourceHash) {
|
|
165
|
+
const node = schema.node;
|
|
166
|
+
switch (kind) {
|
|
167
|
+
case "typescript":
|
|
168
|
+
return generateTypeScript(node, { sourceHash });
|
|
169
|
+
case "zod":
|
|
170
|
+
return generateZod(node, { sourceHash });
|
|
171
|
+
case "jsonSchema":
|
|
172
|
+
return generateJsonSchema(node, { sourceHash });
|
|
173
|
+
case "openApi":
|
|
174
|
+
return generateOpenApiSchemaComponent(node, { sourceHash });
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// =============================================================================
|
|
178
|
+
// Path convention
|
|
179
|
+
// =============================================================================
|
|
180
|
+
const KIND_TO_EXT = {
|
|
181
|
+
typescript: ".types.ts",
|
|
182
|
+
zod: ".zod.ts",
|
|
183
|
+
jsonSchema: ".json.schema.json",
|
|
184
|
+
openApi: ".openapi.json",
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* `<schema-dir>/<basename>.schema.ts` → `<schema-dir>/generated/<basename>[.<discriminator>].<ext>`.
|
|
188
|
+
*
|
|
189
|
+
* Pure string manipulation; no `node:path` import. Forward slashes
|
|
190
|
+
* are the canonical separator in the suggested path even on Windows
|
|
191
|
+
* — the CLI normalizes back to platform separators on write
|
|
192
|
+
* (separate concern; Step 31).
|
|
193
|
+
*
|
|
194
|
+
* The optional `discriminator` is inserted between the basename and
|
|
195
|
+
* the artifact extension. The handler computes it per-entry via
|
|
196
|
+
* `discriminatorsFor` (see above); callers that know they have a
|
|
197
|
+
* single-schema source file may omit the option entirely.
|
|
198
|
+
*/
|
|
199
|
+
export function suggestedPathFor(sourcePath, kind, options = {}) {
|
|
200
|
+
const normalized = sourcePath.replace(/\\/g, "/");
|
|
201
|
+
const lastSlash = normalized.lastIndexOf("/");
|
|
202
|
+
const dir = lastSlash >= 0 ? normalized.slice(0, lastSlash) : "";
|
|
203
|
+
const filename = lastSlash >= 0 ? normalized.slice(lastSlash + 1) : normalized;
|
|
204
|
+
const basename = basenameOf(filename);
|
|
205
|
+
const stem = options.discriminator !== undefined
|
|
206
|
+
? `${basename}.${options.discriminator}`
|
|
207
|
+
: basename;
|
|
208
|
+
const prefix = dir ? `${dir}/generated/${stem}` : `generated/${stem}`;
|
|
209
|
+
return `${prefix}${KIND_TO_EXT[kind]}`;
|
|
210
|
+
}
|
|
211
|
+
function basenameOf(filename) {
|
|
212
|
+
// Preferred: strip the `.schema.{ts,js,mts,cts}` suffix.
|
|
213
|
+
const schemaMatch = filename.match(/^(.+?)\.schema\.(ts|js|mts|cts)$/);
|
|
214
|
+
if (schemaMatch)
|
|
215
|
+
return schemaMatch[1];
|
|
216
|
+
// Fallback for non-conventional input: drop the last extension.
|
|
217
|
+
const lastDot = filename.lastIndexOf(".");
|
|
218
|
+
return lastDot > 0 ? filename.slice(0, lastDot) : filename;
|
|
219
|
+
}
|
|
220
|
+
// Exported so the CLI can advertise the same path convention for
|
|
221
|
+
// `check`'s artifact-lookup, without re-deriving the rule.
|
|
222
|
+
export { GENERATOR_KINDS };
|
|
223
|
+
//# sourceMappingURL=generate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../../../src/registry/handlers/generate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `listHandler({ registry })` — enumerate every `RegistryEntry` in a
|
|
3
|
+
* `Registry`, in a stable order, as a `Result<{ entries }>`.
|
|
4
|
+
*
|
|
5
|
+
* The simplest of the four v0.7 handlers; landing this commit first
|
|
6
|
+
* pins the handler shape and the `Result<T>` discriminated-union
|
|
7
|
+
* contract before `diff` / `check` / `generate` add per-handler
|
|
8
|
+
* complexity (Master plan sequencing step 8).
|
|
9
|
+
*
|
|
10
|
+
* **Pure.** No filesystem, no `import()`, no `process.*`, no
|
|
11
|
+
* `console.*`. Takes an already-built `Registry` (Step 6's
|
|
12
|
+
* `buildRegistry` output) and returns a `Result` over a flat array.
|
|
13
|
+
* Master plan Decision #1 boundary.
|
|
14
|
+
*
|
|
15
|
+
* Ordering (deterministic; documented in tests):
|
|
16
|
+
*
|
|
17
|
+
* 1. **Across `schemaId`**: alphabetical ascending.
|
|
18
|
+
* 2. **Within one `schemaId`**: versioned entries first, ascending
|
|
19
|
+
* by numeric major.minor.patch semver (so `1.0.0` < `2.0.0` <
|
|
20
|
+
* `10.0.0`, never lexicographic `10.0.0` < `2.0.0`). Unversioned
|
|
21
|
+
* entries (the empty-string inner key from Step 6) come **last**.
|
|
22
|
+
*
|
|
23
|
+
* Rationale for "unversioned last":
|
|
24
|
+
* - Putting unversioned first would sort empty-string `""` before
|
|
25
|
+
* any semver — visually surprising in CLI output.
|
|
26
|
+
* - Unversioned schemas are the v0.7 fallback for `.id()`-without-
|
|
27
|
+
* `.version()`. Most workspaces won't have any. Sorting them at
|
|
28
|
+
* the tail makes them visually distinct from the canonical
|
|
29
|
+
* versioned list.
|
|
30
|
+
*
|
|
31
|
+
* Empty registry: returns `{ success: true, data: { entries: [] } }`.
|
|
32
|
+
* Never returns failure — list is read-only, has no failure mode.
|
|
33
|
+
*/
|
|
34
|
+
import type { ListOpts, ListResult } from "../types.js";
|
|
35
|
+
export declare function listHandler(opts: ListOpts): ListResult;
|
|
36
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../src/registry/handlers/list.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EAEX,MAAM,aAAa,CAAC;AAErB,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,UAAU,CAyBtD"}
|