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
40 changes: 40 additions & 0 deletions .changeset/componentinput-reexport-4972.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
'@object-ui/core': minor
'@object-ui/types': minor
---

`ComponentInput` is now declared once and re-exported, instead of restated in three
places (objectui#4972).

`@object-ui/core`'s `ComponentInput` (`registry/Registry.ts`) and `@object-ui/types`'
plugin-scoped `ComponentInput` (`plugin-scope.ts`, published as `PluginComponentInput`)
were structural copies of the interface in `@object-ui/types`' `base.ts`. Both are now
re-exports of that one declaration, which is the disposition objectui#4580 ruled for the
identical shape — *a structural copy would reproduce the defect the moment either side
moved* — and the way `core/src/types/index.ts` already handles `SchemaNode`.

Either side had already moved. `base.ts` declared thirteen keys; both copies declared
nine, so `min` / `max` / `step` / `placeholder` were missing from **the copy every
component registration actually imports**. Those four keys were unwritable at any real
registration — a plain TypeScript error at the call site — while `ComponentInputSchema`
(the zod schema) and `ComponentMeta.inputs` both accepted them. The publication face
advertised four keys the authoring face rejected. Measured over the repository, no
registration had tried to write one yet, so nothing a user hits was broken today; what
changes is that the four keys become writable, and there is no longer a second
declaration for the next widening to miss.

`ComponentInput`'s arm vocabulary (`ComponentInputControlType`) was already a single
declaration imported by all three sites (objectui#3832); this converges the rest of the
interface.

Measured, not assumed: `@object-ui/core`'s published entry `dist/index.d.ts` is
byte-identical across the change (sha256 `f6494f80…`, both legs). That gauge is reported
here only with its control — a probe that added a *required* key to `ComponentInput` left
the same file byte-identical, because `dist/index.d.ts` is a 63-line barrel of
`export *` lines that names `ComponentInput` zero times. The gauge that can actually fail
is the emitted declaration file: `dist/registry/Registry.d.ts` changes, as does
`@object-ui/types`' `dist/plugin-scope.d.ts`, and those two files are the *only* emitted
declarations that change in either package.

`WidgetInput`'s union-arm capability is deliberately untouched — a different gate path
and a separate judgment.
41 changes: 18 additions & 23 deletions packages/core/src/registry/Registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
* LICENSE file in the root directory of this source tree.
*/

import type { ComponentInputControlType } from '@object-ui/types';
import type { ComponentInput } from '@object-ui/types';
import { PUBLIC_BLOCKS } from './public-blocks.js';

export type ComponentRenderer<T = any> = T;
Expand All @@ -15,29 +15,24 @@ export type ComponentRenderer<T = any> = T;
* What a registration DECLARES about one authorable prop.
*
* This is the declaration the component registrations themselves import, so it
* is the one an author's manifest is ultimately built from. It is structurally
* the third copy of `ComponentInput` (the others live in the types package's
* `base.ts` and `plugin-scope.ts`); the arm vocabulary of `type` is imported
* from there rather than re-spelled, so the union widening of objectui#3832
* cannot land on two of the three and drift.
* is the one an author's manifest is ultimately built from — and it is now
* RE-EXPORTED from `@object-ui/types` rather than restated here
* (objectui#4972), the disposition objectui#4580 ruled for the identical
* shape: *a structural copy would reproduce the defect the moment either side
* moved.* This package already depends on `@object-ui/types`, so the edge
* exists and adds no cycle, and `src/types/index.ts` re-exports `SchemaNode`
* from there the same way.
*
* The copy this replaces had ALREADY moved, which is why the card is not
* hypothetical: it carried nine keys while `base.ts` carried thirteen, so
* `min` / `max` / `step` / `placeholder` were missing from *the copy every
* registration actually imports*. Those four keys were therefore unwritable at
* any real registration — a plain TS error — while `ComponentInputSchema` (the
* zod schema) and `ComponentMeta.inputs` both accepted them. The publication
* face advertised four keys the authoring face rejected; the divergence was
* dormant only because no registration had tried to write one yet.
*/
export type ComponentInput = {
name: string;
/**
* Input control type — one coarse kind, or an array of them when the key's
* contract is a union (objectui#3832). A value passes the manifest gate when
* ANY declared arm accepts it; a value matching none is still reported. Full
* semantics: `ComponentInput.type` in the types package's `base.ts`.
*/
type: ComponentInputControlType | ComponentInputControlType[];
label?: string;
defaultValue?: any;
required?: boolean;
enum?: string[] | { label: string; value: any }[];
description?: string;
advanced?: boolean;
inputType?: string;
};
export type { ComponentInput } from '@object-ui/types';

export type ComponentMeta = {
label?: string; // Display name in designer
Expand Down
31 changes: 9 additions & 22 deletions packages/types/src/plugin-scope.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
* @packageDocumentation
*/

import type { ComponentInputControlType } from './base.js';
import type { ComponentInput } from './base.js';

/**
* Plugin Scope Interface
Expand Down Expand Up @@ -168,28 +168,15 @@ export interface ComponentMeta {
/**
* Component input definition
*
* The plugin-scoped twin of `base.ts`' {@link ComponentInput}. The arm
* vocabulary is IMPORTED from there rather than re-spelled (objectui#3832):
* the two interfaces already have to move together, and a second copy of the
* eleven literals is the copy that drifts — the hazard objectui#4580's ruling
* settled by re-exporting one declaration instead of restating it.
* The plugin-scoped twin of `base.ts`' {@link ComponentInput} is no longer a
* twin: it is the SAME declaration, RE-EXPORTED rather than restated
* (objectui#4972). Only the arm vocabulary was shared before (objectui#3832);
* this finishes the job for the rest of the interface, per objectui#4580's
* ruling — *a structural copy would reproduce the defect the moment either
* side moved.* Re-exported under this name so that `index.ts`' public
* `ComponentInput as PluginComponentInput` alias keeps naming a real export.
*/
export interface ComponentInput {
name: string;
/**
* Input control type — one coarse kind, or an array of them for a union key.
* Semantics, the array form's rules and why it exists: see
* `ComponentInput.type` in `base.ts`.
*/
type: ComponentInputControlType | ComponentInputControlType[];
label?: string;
defaultValue?: any;
required?: boolean;
enum?: string[] | { label: string; value: any }[];
description?: string;
advanced?: boolean;
inputType?: string;
}
export type { ComponentInput } from './base.js';

/**
* Event handler type
Expand Down
Loading