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: 7 additions & 0 deletions .changeset/theme-zod-retired-spec-reexports.md
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
---
'@object-ui/types': minor
---

Remove the six retired `@objectstack/spec/ui` theme-schema re-exports from `@object-ui/types/zod` — `ColorPaletteSchema`, `TypographySchema`, `BorderRadiusSchema`, `ShadowSchema`, `ThemeModeSchema`, `ThemeDefinitionSchema` (the spec's `ThemeSchema`) — plus their `…SchemaType` inference helpers, and the `theme` / `mode` props of `ThemePreviewSchema` (zod and interface) that consumed them.

objectstack#10485 (ADR-0049 enforce-or-remove, PR objectstack#10695) retired the spec's whole `ui/theme.zod.ts` module, and the maintainer's ruling on objectstack#10856 (Options A + C) has objectui remove the dangling imports first so the Console Pin Gate can build objectui against the framework tree; restoring the spec exports (Option B) was explicitly not taken. Breaking in effect for anyone importing those six names from `@object-ui/types/zod`: there is no replacement — the validators retired upstream with no successor. The theme TYPE surface (`Theme`, `ThemeMode`, `ColorPalette`, … re-exported from `@object-ui/types`) and the ThemeEngine/ThemeProvider runtime are unchanged.
24 changes: 10 additions & 14 deletions packages/types/src/__tests__/p2-spec-exports.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -67,8 +67,11 @@ import {
UserActionsConfigSchema as UserActionsConfigZod,
ViewTabSchema as ViewTabZod,
ViewFilterRuleSchema as ViewFilterRuleZod,
ThemeModeSchema as ThemeModeZod,
} from '@objectstack/spec/ui';
// `ThemeModeSchema` no longer imported: objectstack#10485 (PR objectstack#10695)
// retired the spec's whole `ui/theme.zod.ts` module, and the objectstack#10856
// ruling had objectui drop its dangling imports (objectui#5710) — its
// spec-liveness `describe` block left with it.

// ============================================================================
// P2.3 Sharing & Embedding
Expand DownExpand Up@@ -243,19 +246,12 @@ describe('v3.0.10 Spec Protocol New Types', () => {
});
});

describe('ThemeModeSchema', () => {
it('should be a valid Zod schema with parse method', () => {
expect(ThemeModeZod).toBeDefined();
expect(typeof ThemeModeZod.parse).toBe('function');
expect(typeof ThemeModeZod.safeParse).toBe('function');
});

it('should validate theme mode values', () => {
expect(ThemeModeZod.safeParse('light').success).toBe(true);
expect(ThemeModeZod.safeParse('dark').success).toBe(true);
expect(ThemeModeZod.safeParse('auto').success).toBe(true);
});
});
// `describe('ThemeModeSchema')` DELETED, not rewritten: its whole point was
// that the spec publishes a live `ThemeModeSchema` validator, and
// objectstack#10485 (PR objectstack#10695) retired the spec's entire theme
// module — there is no upstream referent left to assert against
// (objectui#5710). The provider's own mode handling stays covered by
// `packages/providers/src/__tests__/theme-mode-spec-parity.test.tsx`.
});
describe('Type re-exports from @object-ui/types index', () => {
it('should re-export P2.3 types (compile-time verification)', async () => {
Expand Down
31 changes: 20 additions & 11 deletions packages/types/src/__tests__/phase2-schemas.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -10,7 +10,6 @@ import {
ThemeSwitcherSchema,
ThemePreviewSchema,
ThemeUnionSchema,
ThemeDefinitionSchema,
ReportComponentSchema,
ReportBuilderSchema,
ReportViewerSchema,
Expand DownExpand Up@@ -121,11 +120,15 @@ describe('Phase 2: Theme component kinds — Zod Validation', () => {
// VALID is now proven REFUSED, so a re-added union member fails here rather
// than reappearing silently in the published `@object-ui/types/zod` surface.
//
// The theme SYSTEM is untouched — `ThemeDefinitionSchema` (the theme
// document the engine and the provider consume) is retained, and this
// fixture's `themes[0]` still parses against it, which is what makes the
// refusal below attributable to the retired WRAPPER and not to a bad fixture.
it('refuses the retired `type: \'theme\'` component kind, while the theme document it carried still parses', () => {
// The control leg this pin used to carry — `themes[0]` still parsing against
// `ThemeDefinitionSchema` — left with that validator: objectstack#10485 (PR
// objectstack#10695) retired the spec's whole theme module, and the
// objectstack#10856 ruling had objectui remove its re-exports rather than
// keep a local mirror (objectui#5710). Attribution now reads the refusal
// itself: a discriminated union rejecting an unknown `type` reports the
// DISCRIMINATOR, so asserting every issue sits on `type` proves the refusal
// hit the retired wrapper kind, not the theme document it carried.
it('refuses the retired `type: \'theme\'` component kind at the discriminator', () => {
const retiredWrapper = {
type: 'theme',
mode: 'dark',
Expand DownExpand Up@@ -160,13 +163,19 @@ describe('Phase 2: Theme component kinds — Zod Validation', () => {
};

// The wrapper: gone from every union that used to carry it.
expect(ThemeUnionSchema.safeParse(retiredWrapper).success).toBe(false);
const refusal = ThemeUnionSchema.safeParse(retiredWrapper);
expect(refusal.success).toBe(false);
expect(AnyComponentSchema.safeParse(retiredWrapper).success).toBe(false);

// The control that makes that refusal mean something: the document the
// wrapper carried is retained and still valid on its own. If this leg ever
// fails, the fixture broke — not the retirement.
expect(ThemeDefinitionSchema.safeParse(retiredWrapper.themes[0]).success).toBe(true);
// Attribution control (see the block comment above): the refusal must sit
// on the `type` discriminator — the retired WRAPPER kind — not somewhere
// inside the theme document the fixture carries.
if (!refusal.success) {
expect(refusal.error.issues.length).toBeGreaterThan(0);
for (const issue of refusal.error.issues) {
expect(issue.path, `refusal must be at the discriminator, got ${JSON.stringify(issue)}`).toEqual(['type']);
}
}
});

it('should validate ThemeSwitcherSchema', () => {
Expand Down
108 changes: 50 additions & 58 deletions packages/types/src/__tests__/spec-subschema-parity.test.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -9,10 +9,12 @@
/**
* Sub-schema ↔ @objectstack/spec drift guard (issue #2231, phase 2).
*
* The former hand-written mirrors in `zod/objectql.zod.ts` and `zod/theme.zod.ts`
* are now the spec's schemas **by reference** — re-forking one (replacing the
* re-export with a local copy that can drift) is exactly the failure mode that
* produced the original ListViewSchema divergence. These tests pin:
* The former hand-written mirrors in `zod/objectql.zod.ts` are now the spec's
* schemas **by reference** — re-forking one (replacing the re-export with a
* local copy that can drift) is exactly the failure mode that produced the
* original ListViewSchema divergence. (`zod/theme.zod.ts` carried six such
* re-exports too until the spec retired its whole theme module — see the
* retirement block below.) These tests pin:
*
* 1. Reference identity for every direct re-export. `toBe` — not structural
* equality — so a "faithful copy" fails too: a copy is a fork.
Expand All@@ -34,14 +36,8 @@ import {
ColumnSummarySchema as SpecColumnSummarySchema,
SelectionConfigSchema as SpecSelectionConfigSchema,
PaginationConfigSchema as SpecPaginationConfigSchema,
ColorPaletteSchema as SpecColorPaletteSchema,
TypographySchema as SpecTypographySchema,
BorderRadiusSchema as SpecBorderRadiusSchema,
ShadowSchema as SpecShadowSchema,
ThemeModeSchema as SpecThemeModeSchema,
ChartTypeSchema as SpecChartTypeSchema,
PageTypeSchema as SpecPageTypeSchema,
ThemeSchema as SpecThemeSchema,
} from '@objectstack/spec/ui';
import {
HttpMethodSchema,
Expand All@@ -51,14 +47,6 @@ import {
SelectionConfigSchema,
PaginationConfigSchema,
} from '../zod/objectql.zod.js';
import {
ColorPaletteSchema,
TypographySchema,
BorderRadiusSchema,
ShadowSchema,
ThemeModeSchema,
ThemeDefinitionSchema,
} from '../zod/theme.zod.js';
import { ChartTypeSchema } from '../zod/data-display.zod.js';
import { PageTypeSchema } from '../zod/layout.zod.js';

Expand All@@ -75,17 +63,16 @@ describe('spec sub-schema re-exports are the spec objects (by reference)', () =>
['ViewDataSchema', ViewDataSchema, SpecViewDataSchema],
['SelectionConfigSchema', SelectionConfigSchema, SpecSelectionConfigSchema],
['PaginationConfigSchema', PaginationConfigSchema, SpecPaginationConfigSchema],
['ColorPaletteSchema', ColorPaletteSchema, SpecColorPaletteSchema],
['TypographySchema', TypographySchema, SpecTypographySchema],
['BorderRadiusSchema', BorderRadiusSchema, SpecBorderRadiusSchema],
['ShadowSchema', ShadowSchema, SpecShadowSchema],
// `AnimationSchema` / `ZIndexSchema` pairs REMOVED, not re-pointed: the
// spec deleted both value schemas outright with the `theme.animation` /
// `theme.zIndex` tombstones (objectstack#5021, PR objectstack#5289), and
// this package's re-exports went with them. There is no longer a pair to
// compare on either side — `theme.customVars` is the declared door now.
['ThemeModeSchema', ThemeModeSchema, SpecThemeModeSchema],
['ThemeDefinitionSchema', ThemeDefinitionSchema, SpecThemeSchema],
// The six THEME pairs (`ColorPaletteSchema`, `TypographySchema`,
// `BorderRadiusSchema`, `ShadowSchema`, `ThemeModeSchema`,
// `ThemeDefinitionSchema`↔`ThemeSchema`) REMOVED, not re-pointed — the
// same shape as the earlier `AnimationSchema` / `ZIndexSchema` removal
// (objectstack#5021, PR objectstack#5289): objectstack#10485 (ADR-0049,
// PR objectstack#10695) retired the spec's whole `ui/theme.zod.ts`
// module, and the objectstack#10856 ruling had objectui remove its
// re-exports (objectui#5710). There is no longer a pair to compare on
// either side; the describe block at the bottom pins the names OUT of
// `zod/theme.zod.ts` instead.
// #2944 — these two were forks that had already drifted, re-exported under
// the spec's own symbol name so an importer could not tell them apart.
// `ChartTypeSchema` carried 7 of the spec's 19 values and is why #2901 was
Expand All@@ -102,39 +89,44 @@ describe('spec sub-schema re-exports are the spec objects (by reference)', () =>
});

/**
* spec v17 (#3494) pruned the never-enforced Theme keys. They were re-exported
* here by reference, so they left with the spec rather than surviving as an
* objectui-only mirror — the second de-facto contract AGENTS.md #0.1 forbids.
* This guards both ends: the keys stay gone from the spec schema, and objectui
* does not quietly grow its own replacements.
* The retired theme schemas stay retired. Two waves of the same shape:
* spec v17 (#3494) pruned the never-enforced Theme keys and their sub-schema
* re-exports left with it (`SpacingSchema` and friends); then
* objectstack#10485 (ADR-0049, PR objectstack#10695) retired the spec's whole
* `ui/theme.zod.ts` module, and the maintainer's ruling on objectstack#10856
* had objectui REMOVE its six re-exports rather than localize them
* (objectui#5710) — an objectui-only mirror would be the second de-facto
* contract AGENTS.md #0.1 forbids, one repo over from the compatibility
* surface (Option B) that ruling explicitly declined. The per-key
* `SpecThemeSchema.shape` assertions this block used to carry left with the
* spec schema itself — there is no upstream shape left to read.
*
* If a later ruling (e.g. on objectui#5647's theme component kinds) decides
* to localize a theme document schema DELIBERATELY, update this list in the
* PR that records that ruling.
*/
describe('spec v17 pruned Theme keys stay pruned (#3494)', () => {
const PRUNED = [
'spacing',
'breakpoints',
'logo',
'density',
'wcagContrast',
'rtl',
'touchTarget',
'keyboardNavigation',
];

it.each(PRUNED)('the spec Theme schema has no `%s` key', (key) => {
const shape = (SpecThemeSchema as unknown as { shape: Record<string, unknown> }).shape;
expect(
key in shape,
`spec v17 pruned Theme.${key}; if the spec brought it back, re-export it ` +
`by reference instead of hand-writing a mirror`,
).toBe(false);
});

it('objectui does not re-add a mirror of the pruned sub-schemas', async () => {
describe('retired theme schemas stay retired (#3494, objectstack#10485 / objectui#5710)', () => {
it('objectui does not re-add a local mirror of a retired theme schema', async () => {
const themeZod = await import('../zod/theme.zod.js');
for (const name of ['SpacingSchema', 'SpacingScaleSchema', 'BreakpointsSchema', 'ThemeLogoSchema']) {
for (const name of [
// spec v17 pruning (#3494)
'SpacingSchema',
'SpacingScaleSchema',
'BreakpointsSchema',
'ThemeLogoSchema',
// whole-module retirement (objectstack#10485, removal executed as objectui#5710)
'ColorPaletteSchema',
'TypographySchema',
'BorderRadiusSchema',
'ShadowSchema',
'ThemeModeSchema',
'ThemeDefinitionSchema',
'ThemeSchema',
]) {
expect(
name in themeZod,
`'${name}' is gone from @objectstack/spec/ui — do not reintroduce it as an objectui-local schema`,
`'${name}' is gone from @objectstack/spec/ui — do not reintroduce it as an ` +
`objectui-local schema without a maintainer ruling (objectui#5710)`,
).toBe(false);
}
});
Expand Down
28 changes: 15 additions & 13 deletions packages/types/src/theme.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -68,13 +68,14 @@ export type { Shadow } from '@objectstack/spec/ui';
export type { ThemeMode } from '@objectstack/spec/ui';

// `ThemeModeSchema` (the zod value) is intentionally not re-exported — under
// `export type` it was value-erased (#2561); import it from
// `@objectstack/spec/ui` directly when the runtime validator is needed.

// Import spec types for local use in interfaces below
import type {
ThemeMode,
} from '@objectstack/spec/ui';
// `export type` it was value-erased (#2561). It can no longer be imported from
// `@objectstack/spec/ui` either: objectstack#10485 (PR objectstack#10695)
// retired the spec's whole `ui/theme.zod.ts` module, and the objectstack#10856
// ruling had objectui remove its dangling re-exports (objectui#5710). The
// installed `@objectstack/spec` pin still publishes the type re-exports in
// this file; re-homing the theme TYPE surface once the pin moves past the
// retirement is a separate, un-ruled decision — see the tripwire note in
// `packages/providers/src/__tests__/spec-symbol-batch7.test.ts`.

/**
* Complete Theme Definition — the spec's **authoring** theme shape, re-exported
Expand DownExpand Up@@ -163,16 +164,17 @@ export interface ThemeSwitcherSchema extends BaseSchema {

/**
* Theme Preview Component Schema
*
* The `theme` / `mode` members RETIRED with the spec's theme module
* (objectstack#10485; removal ruled on objectstack#10856, executed as
* objectui#5710): their zod validators no longer exist upstream, so keeping
* the members here while `zod/theme.zod.ts` cannot check them would be
* declared-without-enforcement. The kind itself is unregistered and held for
* triage as objectui#5647.
*/
export interface ThemePreviewSchema extends BaseSchema {
type: 'theme-preview';

/** Theme to preview */
theme?: Theme;

/** Preview mode */
mode?: ThemeMode;

/** Show color palette */
showColors?: boolean;

Expand Down
11 changes: 5 additions & 6 deletions packages/types/src/zod/index.zod.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -284,12 +284,11 @@ export {
// Phase 2 Schemas - Theme, Reports, Blocks, and Views
// ============================================================================
export {
ColorPaletteSchema,
TypographySchema,
BorderRadiusSchema,
ShadowSchema,
ThemeModeSchema,
ThemeDefinitionSchema,
// `ColorPaletteSchema` / `TypographySchema` / `BorderRadiusSchema` /
// `ShadowSchema` / `ThemeModeSchema` / `ThemeDefinitionSchema` RETIRED with
// the spec's whole `ui/theme.zod.ts` module (objectstack#10485, PR
// objectstack#10695; removal ruled on objectstack#10856, executed as
// objectui#5710) — see `./theme.zod`.
// `ThemeComponentSchema` RETIRED in objectui#5489 — see `./theme.zod`.
ThemeUnionSchema,
ThemeSwitcherSchema,
Expand Down
Loading
Loading