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
35 changes: 35 additions & 0 deletions .changeset/6349-name-authority-batch-3.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
'@object-ui/components': minor
'@object-ui/plugin-grid': patch
'@object-ui/app-shell': patch
---

One authority per exported type name, batch 3 of objectui#6349: `ComboboxOption`,
`NamedActionDef`, `OrgTranslate`.

**`@object-ui/components` — `ComboboxOption` now IS `@object-ui/types`' declaration.**
The component declared its own `{ value, label }`, a strict subset of the
`ComboboxOption` that `@object-ui/types` declares for `ComboboxSchema.options` and
mirrors in `form.zod.ts` (`{ value, label, disabled? }`). The component now re-exports
the types declaration (through the `@object-ui/types/form` subpath — the root barrel
does not publish the name), so the name `ComboboxOption` exported from
`@object-ui/components` gains the optional `disabled?: boolean` member. Every value
that type-checked before still does — nothing narrows and no key changes type; the
one thing that moves is `keyof ComboboxOption`, so a consumer that EXHAUSTS the type
(a `Record` over its keys) will need the new key. Note that the `Combobox` component
itself does not read `option.disabled` — that member was already declared on the
`@object-ui/types` face and is now visible on this one too; it is recorded as a
separate finding, not changed here.

**`@object-ui/plugin-grid` / `@object-ui/app-shell` — internal, surface unchanged.**
`NamedActionDef` was declared identically in `resolveBulkActions.ts` and
`resolveLegacyRowActions.ts`; the latter is now the one authority and the former
re-exports it. `OrgTranslate` was declared identically in `orgErrorMessage.ts` and
`orgRoleLabel.ts`; the former is now the one authority and the latter re-exports it.
Neither name is on its package's public entry, and every deep-`dist` module still
exports the same name with the same shape.

`FilterBuilderCondition` / `FilterGroup` (the other two names this batch was sized
with) are deliberately NOT converged: their shapes disagree on `id`, `value` and on
`operator`, and the only dependency-legal re-point would retype `operator` — the
vocabulary objectui#7561 is asking a maintainer to rule on.
11 changes: 6 additions & 5 deletions packages/app-shell/src/console/organizations/orgRoleLabel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,13 @@

import { ORG_ROLE_LABELS } from '@object-ui/auth';
import type { OrgRole } from '@object-ui/auth';
// One authority for `OrgTranslate` (objectui#6349): `orgErrorMessage.ts`
// declares the translate-function shape both organization helpers take, and
// this module re-exports it so an import from `./orgRoleLabel.js` keeps
// resolving to the same type. A re-export, not a second declaration.
import type { OrgTranslate } from './orgErrorMessage.js';

/**
* The translate function shape this module needs — structurally what
* `useObjectTranslation().t` and `createSafeTranslation()` both provide.
*/
export type OrgTranslate = (key: string, options?: Record<string, unknown>) => string;
export type { OrgTranslate } from './orgErrorMessage.js';

/** True when `role` is one of the four framework-owned membership roles. */
function isKnownRole(role: string): role is OrgRole {
Expand Down
11 changes: 7 additions & 4 deletions packages/components/src/custom/combobox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,13 @@ import {
PopoverTrigger,
} from "../ui/popover"

export interface ComboboxOption {
value: string
label: string
}
// One authority for `ComboboxOption` (objectui#6349): `@object-ui/types`
// declares it (`packages/types/src/form.ts` — the shape `ComboboxSchema.options`
// carries and `form.zod.ts` mirrors), and this component read a strict SUBSET
// of it, `value` and `label`. The `./form` subpath is the door because the
// root barrel does not publish the name. A re-export, not a second declaration.
import type { ComboboxOption } from "@object-ui/types/form"
export type { ComboboxOption } from "@object-ui/types/form"

/**
* Beyond its own named props, the combobox accepts standard button attributes
Expand Down
12 changes: 6 additions & 6 deletions packages/plugin-grid/src/resolveBulkActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,12 @@
*/

import type { BulkActionDef, BulkActionParam } from '@object-ui/types';

/** The subset of an `ActionDef` this fold reads; everything else is carried. */
export interface NamedActionDef {
name?: string;
[key: string]: unknown;
}
// One authority for `NamedActionDef` (objectui#6349): `resolveLegacyRowActions.ts`
// declares the `ActionDef` subset both folds read, and this module re-exports
// it so the name stays reachable from here exactly as before. A re-export, not
// a second declaration — the one-authority gate counts declarations only.
import type { NamedActionDef } from './resolveLegacyRowActions';
export type { NamedActionDef } from './resolveLegacyRowActions';

/**
* Concurrency for a promoted action's per-record fan-out. Well below the
Expand Down
23 changes: 20 additions & 3 deletions scripts/__tests__/one-authority-per-exported-name-6273.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,7 +364,12 @@ const KNOWN_COLLISIONS: ReadonlyMap<string, readonly string[]> = new Map([
['CalendarSchema', ['packages/plugin-calendar/src/ObjectCalendar.tsx', 'packages/types/src/form.ts']],
['ChatMessage', ['packages/plugin-chatbot/src/ChatbotEnhanced.tsx', 'packages/types/src/complex.ts']],
['ChatToolInvocation', ['packages/plugin-chatbot/src/ChatbotEnhanced.tsx', 'packages/types/src/complex.ts']],
['ComboboxOption', ['packages/components/src/custom/combobox.tsx', 'packages/types/src/form.ts']],
// `ComboboxOption` sat here, colliding between
// `packages/components/src/custom/combobox.tsx` and `packages/types/src/form.ts`.
// The component's copy was a strict SUBSET (`value`, `label`; the types copy
// adds `disabled?`), so the component re-points at the one authority in
// `@object-ui/types` — through the `./form` subpath, since the root barrel
// does not publish the name (objectui#6349).
// `ComponentConfig` sat here, colliding between
// `packages/core/src/registry/Registry.ts` and `packages/types/src/base.ts`.
// objectui#6298 made `@object-ui/types` the one authority — it gained the
Expand All @@ -385,6 +390,14 @@ const KNOWN_COLLISIONS: ReadonlyMap<string, readonly string[]> = new Map([
['Diagnostic', ['packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts', 'packages/cli/src/commands/doctor.ts', 'packages/sdui-parser/src/types.ts']],
['DiagnosticLevel', ['packages/app-shell/src/views/metadata-admin/previews/simulator/flow-sim-types.ts', 'packages/cli/src/commands/doctor.ts']],
['DomProps', ['packages/core/src/utils/dom-props.ts', 'packages/fields/src/widgets/toDomProps.ts']],
// ⚠️ `FilterBuilderCondition` / `FilterGroup` are NOT one shape declared twice:
// the component's condition carries a required `id`, a required narrow `value`
// and `operator: string` (the dropdown's camelCase ids); the types copy has no
// `id`, `value?: any` and `operator: FilterBuilderOperator` (the snake_case
// union). Both headers claim ONE concept, so the remedy is a re-point, and the
// only dependency-legal direction (components -> types) retypes `operator` —
// the vocabulary objectui#7561 is asking a maintainer to rule on. Both rows
// wait for that ruling (objectui#6349, batch 3, stop-and-report).
['FilterBuilderCondition', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']],
['FilterBuilderOperator', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']],
['FilterGroup', ['packages/components/src/custom/filter-builder.tsx', 'packages/types/src/complex.ts']],
Expand Down Expand Up @@ -428,8 +441,12 @@ const KNOWN_COLLISIONS: ReadonlyMap<string, readonly string[]> = new Map([
// the RENAME branch: app's declaration now spells `AppMenuItem`, the name
// `src/index.ts` always published it under (objectui#6349).
['MetadataTypeStatus', ['packages/app-shell/src/providers/MetadataProvider.tsx', 'packages/react/src/context/AppShellContext.tsx']],
['NamedActionDef', ['packages/plugin-grid/src/resolveBulkActions.ts', 'packages/plugin-grid/src/resolveLegacyRowActions.ts']],
['OrgTranslate', ['packages/app-shell/src/console/organizations/orgErrorMessage.ts', 'packages/app-shell/src/console/organizations/orgRoleLabel.ts']],
// `NamedActionDef` sat here — two IDENTICAL declarations inside plugin-grid.
// `resolveLegacyRowActions.ts` is the one authority; `resolveBulkActions.ts`
// re-exports it (objectui#6349).
// `OrgTranslate` sat here — two IDENTICAL declarations inside app-shell's
// organizations console. `orgErrorMessage.ts` is the one authority;
// `orgRoleLabel.ts` re-exports it (objectui#6349).
['PageHeaderComponentProps', ['packages/app-shell/src/layout/PageHeader.tsx', 'packages/layout/src/PageHeader.tsx']],
['RecordDetailDrawerProps', ['packages/plugin-dashboard/src/RecordDetailDrawer.tsx', 'packages/plugin-detail/src/RecordDetailDrawer.tsx']],
['SchemaNode', ['packages/sdui-parser/src/types.ts', 'packages/types/src/base.ts']],
Expand Down
Loading