Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/spec/scripts/def-key-collisions.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -323,8 +323,11 @@ describe('build-schemas.ts refuses a second write of one def key (#5832)', () =>
expect(res.status).toBe(1);
expect(output).toContain('JSON Schema def key(s) are claimed by two or more different schemas');
expect(output).toContain('json-schema/shared/HttpMethod.json <- HttpMethod, HttpMethodSchema');
// Exactly one collision: the fourteen `export const X = XSchema` self-aliases
// this package really does carry must stay green, or the guard is unusable.
// Exactly one collision: the self-aliases this package really does carry —
// the `Object.assign(XSchema, { … })` exports under `api/` and `system/` —
// must all stay green, or the guard is unusable. Their number is deliberately
// not pinned here: it moves, and a count asserted in a comment only drifts
// (#12608). The generator reports the live population every run (#12588).
expect(output).toContain('1 JSON Schema def key(s) are claimed');
// It stops BEFORE the ratchets, which would otherwise adjudicate a build
// whose output already depends on export iteration order. The name here
Expand Down
22 changes: 17 additions & 5 deletions packages/spec/scripts/lib/def-key-collisions.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -35,9 +35,19 @@
* > same schema instance.
*
* Identity, not today's byte-equality. The permitted shape is the package's
* self-alias convention — `export const ThemeMode = ThemeModeSchema`, and
* fourteen more across `api`, `system` and `ui` — where the second write is the
* same object and therefore cannot change what is published. Anything else is
* self-alias convention: a second export name bound to the very same schema
* object, as `src/api/endpoint.zod.ts` does with
* `export const ApiEndpoint = Object.assign(ApiEndpointSchema, { create })` —
* `Object.assign` returns its target, so `ApiEndpoint` and `ApiEndpointSchema`
* are one object and the second write cannot change what is published. A plain
* re-export (`export const Foo = FooSchema`) is the same shape by the same test.
*
* How many of these the package carries, and which def keys they land on, is
* deliberately NOT restated here: the population moves, and nothing checks a
* comment. `build-schemas.ts` prints it on every run instead (#12588 — the
* `N emit(s) collapsed into M existing def key(s) — all self-aliases` line,
* built from `findSelfAliasedDefKeys` below, which lists each def key and the
* export keys that reach it). Read that run, not this paragraph. Anything else is
* two independent declarations under one published name: even if their JSON
* happens to match today, the next edit to either one makes the artifact
* depend on export order again, silently. So the guard refuses at the point
Expand DownExpand Up@@ -183,7 +193,9 @@ export function formatDefKeyCollisions(collisions: readonly DefKeyCollision[]):
` one name meaning one thing. Record the rename in scripts/lib/renamed-defs.ts when the OLD\n` +
` def key stops being emitted;\n` +
` - a duplicate DECLARATION of one schema: delete it and re-export the survivor, so both\n` +
` names resolve to a single object (\`export const ThemeMode = ThemeModeSchema\` — that\n` +
` shape is allowed here precisely because it cannot change what is published).\n`
` names resolve to a single object — \`export const Foo = FooSchema\`, or the\n` +
` \`Object.assign(FooSchema, { … })\` form src/api/endpoint.zod.ts uses for \`ApiEndpoint\`.\n` +
` Either shape is allowed here precisely because it cannot change what is published;\n` +
` a build's own summary lists the self-aliases it already carries.\n`
);
}
Loading