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
13 changes: 13 additions & 0 deletions .changeset/5928-classname-style-props-rename.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
---
'@object-ui/types': minor
---

`@object-ui/types/zod`: the zod const `StylePropsSchema` is renamed to `ClassNameStylePropsSchema` (objectui#5928). **The old name is gone** — there is no deprecated alias and no second spelling. Import `ClassNameStylePropsSchema`.

**What moves on the published surface.** `StylePropsSchema` is removed from `@object-ui/types/zod`; the same object is exported under the new name with the same accept set, so nothing that parsed before parses differently and nothing refused before is accepted now. The break is the name alone: an import of `StylePropsSchema` no longer resolves.

**Why the name had to move.** The const declares exactly two keys — `className` and `style`, the CSS passthrough attributes a node exposes. The TypeScript `StyleProps` (`base.ts`) is the Tailwind-SCALE vocabulary: `padding`, `margin`, `gap`, `backgroundColor`, `textColor`, `borderWidth`, `borderColor`, `borderRadius`. Measured on this branch's base with an AST read of both files: 2 keys against 8, sharing ZERO keys. In this package the `…Schema` suffix otherwise means "runtime mirror of the like-named declaration", so the shared name asserted a mirror relationship that does not exist — and building objectui#5684's parity registry by name pairing duly put the two together and reported drift on a pair that has no counterpart at all.

**Where the non-pair is recorded now.** `zod-mirror-parity.test.ts` keys its existing `EXCLUSIONS` entry — the mechanism that accounts for every exported const with no TypeScript declaration to mirror, each with its stated reason — to `ClassNameStylePropsSchema`. Named for its own two keys, the const leaves no like-named declaration for a name-derived pairing to reach for.

**No deprecation window, deliberately.** No consumer of the old name exists in this repository. Measured on this branch's base: `StylePropsSchema` had exactly three references — the definition, the barrel line, and the guard's own exclusion key — all three inside `packages/types` (lit control on the same query shape: `BaseSchema` matches 251 tracked files). A staged retirement would need named external-consumer evidence, and there is none.
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* ObjectUI
* Copyright (c) 2024-present ObjectStack Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

/**
* `StylePropsSchema` is RENAMED to `ClassNameStylePropsSchema` on the published
* `@object-ui/types/zod` surface — outright, with no deprecated alias standing in
* for the old name (objectui#5928).
*
* ## What this file exists to prove
*
* The rename moves a name on a PUBLISHED surface, so the new name has to be
* checked the way a published export is checked — by IMPORTING it through the
* published barrel and USING it. Nothing else in this package imports the barrel's
* copy of this name, so without this file the barrel line is load-bearing for
* nobody and can be dropped in silence. Measured on this branch by deleting
* `ClassNameStylePropsSchema` from `../zod/index.zod.ts`: this suite fails at
* module load, and `tsc -p tsconfig.test.json` fails with TS2305 at the import
* below — both of them only because this file names the export.
*
* The import is a VALUE import rather than a type-only one, because the type level
* cannot see the half that matters: a type import erases, while the `safeParse`
* pair below proves the published name still resolves to a LIVE zod schema at
* runtime and not to something that lost its identity in the rename.
*
* Both faces of the rename are pinned here:
* - the barrel publishes the new name and it VALIDATES — a live zod schema that
* also REFUSES, with the issue addressed to the offending key, so the export is
* the schema and not an inert re-export of something that lost its identity in
* the rename — and the retired name is no longer among the barrel's exports;
* - the object carries exactly the two keys the new name claims, so the name
* cannot outlive what it describes.
*
* ## What is NOT pinned here, and where it lives instead
*
* That the retired name cannot come back as a DEFINITION is already a ratchet in
* `zod-mirror-parity.test.ts`: its census reads every `export const` in `../zod/`
* and fails on one that is neither a registered pair nor an excluded one, so
* re-declaring `StylePropsSchema` there reddens that suite with no help from this
* file. What that census cannot see — it matches `export const` declarations — is
* the same name returning as a re-export alias (`export { X as Y }`), which is why
* the absence below is read off the barrel's own export list rather than restated
* against the source.
*
* The other half of the card — that the old name never was a mirror of the
* like-named TS `StyleProps`, the Tailwind-scale vocabulary it shares no key with —
* is recorded with its reason in that same file's `EXCLUSIONS`, now keyed to the
* name this const actually carries.
*/

import { describe, it, expect } from 'vitest';

// The PUBLISHED path (`@object-ui/types/zod` resolves to this barrel), deliberately
// not `../zod/base.zod.js`: a const that survives in the source file but never
// reaches the barrel is exactly the regression this import must catch, and a
// missing named export fails this module at link time.
import { ClassNameStylePropsSchema } from '../zod/index.zod.js';

describe('ClassNameStylePropsSchema (objectui#5928)', () => {
it('the published barrel exports it as a live schema — and no longer carries the retired name', async () => {
const ok = ClassNameStylePropsSchema.safeParse({ className: 'p-4 text-sm', style: { color: 'red', zIndex: 10 } });
expect(ok.success).toBe(true);

// A refusal addressed to the key that is wrong — the accept set is this
// schema's, not a passthrough of anything.
const bad = ClassNameStylePropsSchema.safeParse({ className: 42 });
expect(bad.success).toBe(false);
if (!bad.success) expect(bad.error.issues[0]?.path).toEqual(['className']);

// The rename is a removal too: `StylePropsSchema` left the published surface
// with it, under no spelling — no alias, no re-export.
const zodBarrel = await import('../zod/index.zod.js');
expect(
'StylePropsSchema' in zodBarrel,
'`StylePropsSchema` is back on the published ./zod surface — the rename was outright, no alias',
).toBe(false);
// Positive control on the same barrel object, same run: the surviving name IS
// exported, so the refusal above measures the removal and not a broken import.
expect('ClassNameStylePropsSchema' in zodBarrel).toBe(true);
});

it('it carries exactly the two keys its name claims', () => {
// The rename was justified by a measurement (2 keys, both CSS passthrough
// attributes). Pinned so the name cannot outlive what it describes: a third key
// arriving here makes `ClassNameStyleProps…` a lie and must be a decision.
expect(Object.keys(ClassNameStylePropsSchema.shape).sort()).toEqual(['className', 'style']);
});
});
13 changes: 7 additions & 6 deletions packages/types/src/__tests__/zod-mirror-parity.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1512,12 +1512,13 @@ export type assertionBaseSchemaKeysResolve = Expect<
* in neither map.
*/
const EXCLUSIONS: Readonly<Record<string, string>> = {
// A NAME COLLISION, not a mirror. The like-named `StyleProps` in `../base.ts` is a
// Tailwind-scale vocabulary (`padding`, `margin`, `gap`, `backgroundColor`, …) and
// shares ZERO keys with this `{ className, style }` object. A name-derived pairing
// put them together; `assertionEveryPairOverlaps` rejected it.
'base.zod.ts#StylePropsSchema':
'no TS declaration in this package restates it — `StyleProps` (../base.ts) is an unrelated Tailwind style vocabulary that shares no key with it',
// Renamed from `StylePropsSchema` by objectui#5928. Under the old name the
// like-named `StyleProps` (../base.ts) — the Tailwind-scale vocabulary, sharing
// ZERO keys with this `{ className, style }` object — read as its declaration, and
// a name-derived pairing duly compared two unrelated key sets. Named for its own
// two keys, it has no like-named declaration left to be paired with.
'base.zod.ts#ClassNameStylePropsSchema':
'no TS declaration in this package restates it — the `{ className, style }` passthrough attributes are declared inline on each schema, never as one shared interface',
'app.zod.ts#NavigationItemTypeSchema':
"a bare vocabulary with no `.shape`; it is checked where a mirrored KEY declares it",
'app.zod.ts#NavigationItemSchema':
Expand Down
14 changes: 12 additions & 2 deletions packages/types/src/zod/base.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,19 @@ export const HTMLAttributesSchema = z.record(z.string(), z.any()).describe('HTML
export const EventHandlersSchema = z.record(z.string(), z.function()).describe('Event handlers');

/**
* Style Props
* The two CSS passthrough attributes a node exposes: a Tailwind class string and
* an inline style record.
*
* ⚠️ NOT a mirror of `StyleProps` in `../base.ts` (objectui#5928). That
* declaration is the Tailwind-SCALE vocabulary (`padding`, `margin`, `gap`,
* `backgroundColor`, …) and shares ZERO keys with this object — the two only ever
* shared a name, and pairing them by that name reported drift on a mirror
* relationship that does not exist. The old name is gone: with this const named
* for its own keys there is no like-named declaration left to pair it with, and
* the reason it mirrors nothing is recorded against this name in
* `../__tests__/zod-mirror-parity.test.ts`'s `EXCLUSIONS`.
*/
export const StylePropsSchema = z.object({
export const ClassNameStylePropsSchema = z.object({
className: z.string().optional(),
style: z.record(z.string(), z.union([z.string(), z.number()])).optional(),
}).describe('Style properties');
2 changes: 1 addition & 1 deletion packages/types/src/zod/index.zod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export {
ComponentConfigSchema,
HTMLAttributesSchema,
EventHandlersSchema,
StylePropsSchema,
ClassNameStylePropsSchema,
} from './base.zod.js';

// ============================================================================
Expand Down
Loading