diff --git a/.changeset/25921-types-spec-report-bridge.md b/.changeset/25921-types-spec-report-bridge.md new file mode 100644 index 00000000000..67c99db865f --- /dev/null +++ b/.changeset/25921-types-spec-report-bridge.md @@ -0,0 +1,23 @@ +--- +'@object-ui/types': patch +--- + +refactor(types)!: delete nine Spec Report Bridge names nothing reads + +Clause-②: no (narrowing) +Metadata-protocol: none + + + +**BREAKING** for a host that imports any of these nine names from `@object-ui/types`. None had an importer anywhere in the workspace or in hotcrm, so the Console and every `@object-ui/*` package are unaffected. + +They are **gone from the package, not only from the entry**: `src/spec-report.ts` no longer declares them. Two of them, `mapAggregateToQL` and `isJoinedSpecReport`, are runtime values, so the built `dist` loses them too. The rest of the Spec Report Bridge stays: `SpecReport`, `SpecReportInput`, `SpecReportTypeName`, `SpecReportDateGranularity`, `SpecReportSchema`, `LegacyReportPresentationLike`, `specReportToPresentation`, `isSpecReport` and `JoinedReportBlock`. + +What leaves, and what to write instead: + +- FROM `SpecReportChart` TO `ReportChartParsed` from `@objectstack/spec/ui`. +- FROM `SpecReportChartInput` TO `ReportChart` from `@objectstack/spec/ui`. +- FROM `SpecReportChartSchema` TO `ReportChartSchema` from `@objectstack/spec/ui`. +- FROM `SpecReportTypeEnum` TO `ReportType` from `@objectstack/spec/ui`. +- FROM `SpecReportAggregate`, `QLAggregationFunction`, `mapAggregateToQL` TO no replacement. A spec report is dataset-bound: its `values` name measures whose aggregation the dataset declares, so there is no per-column aggregate left to translate. +- FROM `JoinedSpecReport`, `isJoinedSpecReport` TO no replacement in this package. Test `isSpecReport(value) && value.type === 'joined'` and read `value.blocks`, each a `JoinedReportBlock`. diff --git a/ui/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts b/ui/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts index 5c07db60105..fe106a40c5e 100644 --- a/ui/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts +++ b/ui/packages/types/src/__tests__/report-chart-query-spec-parity.test.ts @@ -42,11 +42,8 @@ import { ChartTypeSchema as SpecChartTypeSchema, DashboardWidgetSchema as SpecDashboardWidgetSchema, } from '@objectstack/spec/ui'; -import type { - JoinedReportBlock as SpecJoinedReportBlock, - JoinedReportBlockParsed as SpecJoinedReportBlockParsed, -} from '@objectstack/spec/ui'; -import type { JoinedReportBlock as PublishedJoinedReportBlock, JoinedSpecReport } from '../spec-report.js'; +import type { JoinedReportBlock as SpecJoinedReportBlock } from '@objectstack/spec/ui'; +import type { JoinedReportBlock as PublishedJoinedReportBlock } from '../spec-report.js'; import { AppContextSelectorSchema } from '../zod/app.zod.js'; import { DashboardWidgetSchema, DashboardWidgetTypeSchema, GlobalFilterSchema } from '../zod/complex.zod.js'; import { DASHBOARD_COMPONENT_WIDGET_TYPES, DASHBOARD_WIDGET_TYPE_EXTENSIONS } from '../complex.js'; @@ -790,10 +787,10 @@ describe('renamed local dialects do not collide with a spec export (objectui#307 * `groupingsAcross`, `filter`, `chart` — plus an index signature; the spec's * schema refuses all five of those keys, `chart` by name since objectstack#20161. * - * objectui#10940 REPLACED the published `JoinedReportBlock` with the spec's type, - * and `JoinedSpecReport.blocks` with the spec's own `Report.blocks`: a - * published-type change, narrowing and widening, stated member by member in its - * changeset. The divergence probes that stood here — local interface against + * objectui#10940 REPLACED the published `JoinedReportBlock` with the spec's type: + * a published-type change, narrowing and widening, stated member by member in + * its changeset. (The joined-report wrapper type it also re-derived left the + * package with objectstack#25921, read by nothing; its pins went with it.) The divergence probes that stood here — local interface against * spec, each written to stop compiling the day its difference moved — are * answered by that replacement and are deleted with the interface. * @@ -807,8 +804,7 @@ describe('renamed local dialects do not collide with a spec export (objectui#307 * probe on an erased spec is deleted, so every probe below is asked on every * compile and an erasure, on either spec, stops compiling. `any` is refused * as before. - * - THE DERIVATION PINS: the published block IS the spec's block, and the - * published joined report's `blocks` ARE the spec's report blocks. Re-forking + * - THE DERIVATION PIN: the published block IS the spec's block. Re-forking * the block by hand under the spec's name is also refused by * `check:spec-symbols`, whose ALLOW row for this symbol retired with the * burn-down. @@ -861,27 +857,6 @@ const _publishedBlockIsTheSpecBlock = true satisfies ( ? SameType, DeclaredBlockKeys> : false ); -// …and a published joined report's `blocks` are the spec's own report blocks, -// on the PARSED tier of `SpecReport`: required, each element the spec's parsed -// block, assignable to the authoring-tier block but not the other way round -// (`type` and `order[].direction` are defaulted on the parsed side). -type PublishedJoinedBlocks = BlockMember; -const _joinedReportBlocksAreTheSpecReportBlocks = true satisfies ( - [PublishedJoinedBlocks] extends [never] - ? false - : undefined extends PublishedJoinedBlocks - ? false - : SameType -); -const _joinedReportBlocksAreParsedTier = true satisfies ( - [PublishedJoinedBlocks] extends [never] - ? false - : [SpecJoinedReportBlockParsed] extends [PublishedJoinedReportBlock] - ? [PublishedJoinedReportBlock] extends [SpecJoinedReportBlockParsed] - ? false - : true - : false -); // 1. NARROWED: the legacy inline-query keys are gone from the published block, // and so is the index signature that let any other key through. @@ -958,8 +933,6 @@ void _specJoinedReportBlockTyping; void _specJoinedReportBlockIsNotEvenAny; void _publishedBlockTyping; void _publishedBlockIsTheSpecBlock; -void _joinedReportBlocksAreTheSpecReportBlocks; -void _joinedReportBlocksAreParsedTier; void _legacyBlockKeysAreGone; void _publishedBlockHasNoIndexSignature; void _datasetBoundBlockKeysArrived; diff --git a/ui/packages/types/src/__tests__/spec-report.test.ts b/ui/packages/types/src/__tests__/spec-report.test.ts index 0ead2093b1d..72a10eba882 100644 --- a/ui/packages/types/src/__tests__/spec-report.test.ts +++ b/ui/packages/types/src/__tests__/spec-report.test.ts @@ -4,7 +4,6 @@ * * Tests for the Spec Report bridge (spec 9.0, dataset-bound — ADR-0021): * - Re-exports compile and match the spec shape. - * - Aggregate mapping handles the `unique → count_distinct` translation. * - The presentation adapter maps the dataset `rows` / `values` names through. */ @@ -12,27 +11,12 @@ import { describe, it, expect } from 'vitest'; import { SpecReport, SpecReportSchema, - mapAggregateToQL, specReportToPresentation, isSpecReport, } from '../spec-report'; import type { SpecReportInput } from '../spec-report'; describe('SpecReport bridge', () => { - describe('mapAggregateToQL', () => { - it('translates unique to count_distinct', () => { - expect(mapAggregateToQL('unique')).toBe('count_distinct'); - }); - - it('passes through standard aggregates', () => { - expect(mapAggregateToQL('sum')).toBe('sum'); - expect(mapAggregateToQL('avg')).toBe('avg'); - expect(mapAggregateToQL('min')).toBe('min'); - expect(mapAggregateToQL('max')).toBe('max'); - expect(mapAggregateToQL('count')).toBe('count'); - }); - }); - describe('SpecReportSchema parsing', () => { it('accepts a minimal tabular report (dataset + values)', () => { const input: SpecReportInput = { diff --git a/ui/packages/types/src/__tests__/spec-ui-schema-reexports.test.ts b/ui/packages/types/src/__tests__/spec-ui-schema-reexports.test.ts index 58f710db109..d214cbfdd43 100644 --- a/ui/packages/types/src/__tests__/spec-ui-schema-reexports.test.ts +++ b/ui/packages/types/src/__tests__/spec-ui-schema-reexports.test.ts @@ -184,7 +184,6 @@ describe('spec/ui …Schema re-exports (#2561, decision (a))', () => { expect(typeof Types.defineStack).toBe('function'); expect(Types.ObjectStackSchema).toBeDefined(); expect(Types.SpecReportSchema).toBeDefined(); - expect(Types.SpecReportTypeEnum).toBeDefined(); expect(Types.ACTION_LOCATIONS).toBeDefined(); expect(Types.ActionLocationSchema).toBeDefined(); }); diff --git a/ui/packages/types/src/index.ts b/ui/packages/types/src/index.ts index 1b2e5a7ebc1..9c034456f94 100644 --- a/ui/packages/types/src/index.ts +++ b/ui/packages/types/src/index.ts @@ -960,29 +960,28 @@ export type { // Authoritative report protocol from @objectstack/spec, re-exported under // `Spec*` names so they coexist with the legacy presentation `ReportComponentSchema`. // See `./spec-report.ts` for the layering rationale. +// +// #25921 (batch 10): nine names of this block are DELETED, nothing in this +// workspace or in hotcrm read them: `SpecReportChart`, `SpecReportChartInput`, +// `SpecReportChartSchema` and `SpecReportTypeEnum` (import `ReportChartParsed`, +// `ReportChart`, `ReportChartSchema` and `ReportType` from `@objectstack/spec/ui`), +// and `SpecReportAggregate`, `QLAggregationFunction`, `mapAggregateToQL`, +// `JoinedSpecReport` and `isJoinedSpecReport` (no replacement). The changeset +// carries the FROM/TO. // --------------------------------------------------------------------------- export type { SpecReportInput, - SpecReportChart, - SpecReportChartInput, SpecReportTypeName, - SpecReportAggregate, SpecReportDateGranularity, - QLAggregationFunction, LegacyReportPresentationLike, JoinedReportBlock, - JoinedSpecReport, } from './spec-report.js'; export { SpecReportSchema, - SpecReportChartSchema, - SpecReportTypeEnum, SpecReport, - mapAggregateToQL, specReportToPresentation, isSpecReport, - isJoinedSpecReport, } from './spec-report.js'; // Workflow / Flow Designer schemas removed in 9.0 — they backed the retired diff --git a/ui/packages/types/src/spec-report.ts b/ui/packages/types/src/spec-report.ts index 6973ada87df..a99b6b9ca36 100644 --- a/ui/packages/types/src/spec-report.ts +++ b/ui/packages/types/src/spec-report.ts @@ -32,34 +32,24 @@ * without polluting the protocol. * - A converter (`specReportToPresentation`) lets the legacy renderer keep * working while we migrate to spec-native rendering. - * - * ## Aggregation naming - * - * The UI spec uses `aggregate: 'unique'` while the data layer (ObjectQL, - * `@objectstack/spec/data`) uses `count_distinct`. Use {@link mapAggregateToQL} - * when translating a Report column into an ObjectQL `AggregationNode`. */ // `@objectstack/spec` 17.0.0-rc.6 retired every `…Input` alias and moved the // bare name onto the `z.input` side: `Report`/`ReportChart` are now // `z.input` and `ReportParsed`/`ReportChartParsed` carry the -// `z.infer` shape these bindings used to read under the bare name. Both pairs -// below are therefore re-pointed so that each local alias keeps the meaning it -// had at rc.5 — `SpecReport`/`SpecReportChart` stay PARSED, `SpecReportInput`/ -// `SpecReportChartInput` stay INPUT. Following the rename by name alone (`X` → -// `X`) would have silently swapped the two. +// `z.infer` shape these bindings used to read under the bare name. The pair +// below is therefore re-pointed so that each local alias keeps the meaning it +// had at rc.5 — `SpecReport` stays PARSED, `SpecReportInput` stays INPUT. +// Following the rename by name alone (`X` → `X`) would have silently swapped +// the two. import type { ReportParsed as SpecReportType_, Report as SpecReportInputType_, - ReportChartParsed as SpecReportChartType_, - ReportChart as SpecReportChartInputType_, JoinedReportBlock as SpecJoinedReportBlockType_, } from '@objectstack/spec/ui'; import { ReportSchema as SpecReportSchema_, - ReportChartSchema as SpecReportChartSchema_, - ReportType as SpecReportTypeEnum_, Report as SpecReportFactory_, } from '@objectstack/spec/ui'; @@ -69,8 +59,6 @@ import { export type SpecReport = SpecReportType_; export type SpecReportInput = SpecReportInputType_; -export type SpecReportChart = SpecReportChartType_; -export type SpecReportChartInput = SpecReportChartInputType_; /** * The four report types defined by the UI Protocol. @@ -82,15 +70,6 @@ export type SpecReportChartInput = SpecReportChartInputType_; */ export type SpecReportTypeName = 'tabular' | 'summary' | 'matrix' | 'joined'; -/** - * Aggregation enum as it appears in the *UI* Report spec - * (`@objectstack/spec/ui` Report.columns[].aggregate). - * - * Note that this intentionally differs from the data-layer `AggregationFunction` - * enum used in ObjectQL — see {@link mapAggregateToQL}. - */ -export type SpecReportAggregate = 'sum' | 'avg' | 'max' | 'min' | 'count' | 'unique'; - /** * Date granularity for time-based grouping * (`Report.groupingsDown[].dateGranularity`). @@ -102,8 +81,6 @@ export type SpecReportDateGranularity = 'day' | 'week' | 'month' | 'quarter' | ' // --------------------------------------------------------------------------- export const SpecReportSchema = SpecReportSchema_; -export const SpecReportChartSchema = SpecReportChartSchema_; -export const SpecReportTypeEnum = SpecReportTypeEnum_; /** * Spec factory helper (`Report.create`). @@ -111,52 +88,6 @@ export const SpecReportTypeEnum = SpecReportTypeEnum_; */ export const SpecReport = SpecReportFactory_; -// --------------------------------------------------------------------------- -// Aggregate mapping: UI spec → data layer (ObjectQL) -// --------------------------------------------------------------------------- - -/** - * The aggregation enum used by the ObjectQL data layer. - * Kept as a string union (rather than importing the value from - * `@objectstack/spec/data`) so this types-only package stays - * runtime-dependency-free. - */ -export type QLAggregationFunction = - | 'count' - | 'sum' - | 'avg' - | 'min' - | 'max' - | 'count_distinct' - | 'array_agg' - | 'string_agg'; - -/** - * Translate a UI-layer aggregate name into the corresponding ObjectQL - * `AggregationFunction`. The only non-trivial mapping is `unique → count_distinct`. - * - * @example - * mapAggregateToQL('unique') // 'count_distinct' - * mapAggregateToQL('sum') // 'sum' - */ -export function mapAggregateToQL(aggregate: SpecReportAggregate): QLAggregationFunction { - switch (aggregate) { - case 'unique': return 'count_distinct'; - case 'sum': - case 'avg': - case 'min': - case 'max': - case 'count': - return aggregate; - default: { - // Exhaustiveness check - const _exhaustive: never = aggregate; - void _exhaustive; - return 'count'; - } - } -} - // --------------------------------------------------------------------------- // Adapter: spec Report → legacy presentation ReportComponentSchema // --------------------------------------------------------------------------- @@ -282,25 +213,3 @@ export function isSpecReport(value: unknown): value is SpecReport { * rather than kept beside it. */ export type JoinedReportBlock = SpecJoinedReportBlockType_; - -/** - * A `SpecReport` of `type: 'joined'` carrying its constituent blocks. - * Use this as the schema input to `ReportRenderer` (dataset-bound blocks render - * through `DatasetReportRenderer`). - * - * `blocks` is the spec's own `Report.blocks`, made required. It is on the - * PARSED tier, like `SpecReport` itself (`type` and each `order[].direction` - * are defaulted), so each element is assignable to the authoring-tier - * {@link JoinedReportBlock}, but not the other way round. - */ -export type JoinedSpecReport = SpecReport & { - type: 'joined'; - blocks: NonNullable; -}; - -/** Type guard for joined reports with a `blocks` array. */ -export function isJoinedSpecReport(value: unknown): value is JoinedSpecReport { - if (!isSpecReport(value)) return false; - const v = value as Record; - return v.type === 'joined' && Array.isArray((v as { blocks?: unknown }).blocks); -}