Skip to content

refactor(plugin-calendar): rename the runtime CalendarEvent to CalendarViewEvent, keep a deprecated alias (#5044) - #5866

Merged
os-zhuang merged 1 commit into
mainfrom
claude/issue-5044-calendarevent-runtime-rename
Aug 23, 2026
Merged

refactor(plugin-calendar): rename the runtime CalendarEvent to CalendarViewEvent, keep a deprecated alias (#5044)#5866
os-zhuang merged 1 commit into
mainfrom
claude/issue-5044-calendarevent-runtime-rename

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Fixes#5044

Executes the 2026-08-19 maintainer ruling (option A, 「全部接受」): the authoring type keeps the canonical name, the runtime type is renamed, and a @deprecated alias is left behind — the same shape #4650 used for ObjectCalendarPropsObjectCalendarComponentProps.

What moved

beforeafter
@object-ui/types — AUTHORING event (id: string, ISO-string start/end with end required, plus description)CalendarEventCalendarEventunchanged, keeps the canonical name
@object-ui/plugin-calendarCalendarView's RUNTIME event (id: string | number, start: Date, end?: Date)CalendarEventCalendarViewEvent, plus CalendarEvent as a @deprecated alias

The published .d.ts carries both, with the deprecation intact:

packages/plugin-calendar/dist/index.d.ts
14: export type { CalendarViewProps, CalendarViewEvent } from './CalendarView';
16: * @deprecated Use `CalendarViewEvent`. Renamed in objectui#5044 because
30: export type { CalendarViewEvent as CalendarEvent } from './CalendarView';
packages/plugin-calendar/dist/CalendarView.d.ts
44: export interface CalendarViewEvent {

grep 'interface CalendarEvent' packages/plugin-calendar/dist/*.d.ts now returns nothing — the old name survives only as a re-export of the new one.

Non-breaking, by construction rather than by assertion. At the package boundary this change is strictly additive: before, the barrel exported CalendarEvent; after, it exports CalendarEvent (aliased) andCalendarViewEvent. No name was removed and no shape changed, so no consumer has a narrowed surface to fail on. That is why option B (stop exporting the runtime type) is not what landed.

Acceptance evidence is about the published NAME SET, not behaviour

Nothing here changes what a calendar renders, and no test claims it does. The new pin is packages/plugin-calendar/src/__tests__/name-collision-5044.test.ts, sibling of spec-symbol-4650.test.ts next door. It is compiled by this package's tsconfig.test.json, which drops the root paths — so @object-ui/types resolves through the workspace dependency's built.d.ts, the surface a consumer actually imports. Proved rather than assumed:

$ pnpm exec tsc -p tsconfig.test.json --listFiles --noEmit | grep -E 'name-collision-5044|types/dist/index.d.ts'
/home/user/objectui-5044/packages/types/dist/index.d.ts
/home/user/objectui-5044/packages/plugin-calendar/src/__tests__/name-collision-5044.test.ts

What it pins:

  1. the two names denote different types, and are incompatible in both directions (id and start each conflict) — the trap itself, not just its symptom;
  2. the deprecated alias denotes the same type as CalendarViewEvent — a type-only stub (= never, a re-declaration) fails here;
  3. an importer of the old name still compiles — the import statement at the top of the test file is that leg;
  4. each side still has the shape that made them incompatible, so (1) cannot go vacuous;
  5. @object-ui/types still declares CalendarEvent — the "which type moved" invariant, so a future edit cannot silently invert this card.

Legs that do not discriminate, named rather than written: rendering a CalendarView is green before and after under either name (it measures the component, not the name set); typeof CalendarEvent at runtime probes nothing, because both are types and are erased before vitest loads the file — which is exactly why the pins are compile-time.

Reverse verification (on the committed tree, mutation confirmed on disk each time)

Ablation 1 — delete the deprecated alias from the barrel (the "Option B by another route" failure). Predicted: type-check red on the old-name import; vitest red on the deprecation-tag test only.

DISK: "CalendarViewEvent as CalendarEvent" occurrences → 0 (was 1); new-name export still 1
$ pnpm --filter @object-ui/plugin-calendar type-check → exit 2
src/__tests__/name-collision-5044.test.ts(76,34): error TS2724: '"../index"' has no exported member named 'CalendarEvent'. Did you mean 'CalendarViewEvent'?
src/__tests__/name-collision-5044.test.ts(112,36): error TS2344: Type 'false' does not satisfy the constraint 'true'. ← _AliasIsSameType
$ pnpm exec vitest run …/name-collision-5044.test.ts → exit 1
× keeps the old name marked deprecated at the export site
Tests 1 failed | 2 passed (3)

Observed exactly as predicted, including the non-discriminating half: the type-level it passed under vitest, because its assertions are erased there.

Ablation 2 — the cross-package leg, mutating the AUTHORING type's id: stringstring | number in packages/types/src/complex.ts. This one exists to prove the pins read the rebuilt.d.ts rather than a cache, so both legs rebuild and both are confirmed in dist:

mutation leg: src id: string | number; → pnpm --filter @object-ui/types build (exit 0)
dist packages/types/dist/complex.d.ts:135 id: string | number;
pnpm --filter @object-ui/plugin-calendar type-check → exit 2
src/__tests__/name-collision-5044.test.ts(118,40): error TS2344: Type 'false' does not
satisfy the constraint 'true'. ← line 118 is _AuthoringIdIsString
restore leg: git checkout HEAD -- … && rebuild
dist packages/types/dist/complex.d.ts:135 id: string;
grep -c 'id: string | number;' packages/types/dist/complex.d.ts → 0
git diff HEAD --stat → empty

Every mutation was confirmed by grepping the text it was meant to change, never by an editor's exit code; both ablation scripts carried a trap … EXIT INT TERM restore.

Also in this diff, and why

  • packages/plugin-calendar/src/ObjectCalendar.tsx — dropped type CalendarEvent from its ./CalendarView import. The identifier appeared exactly once in the file, on the import line itself (grep -cw → 1), so it had no reader; renaming it would have left a name nothing spells. Called out here rather than left silent.
  • README + content/docs/plugins/plugin-calendar.mdx — the docs half of this rename (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2). The README's "two same-name types" note now names both types and records the alias. The docs page's TypeScript Support block was a second live instance of the very defect this card fixes: it annotated a runtime-shaped literal (id: 1, start: new Date(...)) as CalendarEventimported from @object-ui/types, which is the authoring type that rejects both. It now imports CalendarViewEvent from this package. The block is fenced ```plaintext, so check:doc-snippet-types never read it — that is why it outlived plugin-calendar README 教的 calendarComponents 手动注册 API 不存在 —— 照抄即抛 #5010.
  • The README fence that reads onEventClick?: (event: CalendarEvent) => void is left alone: that is CalendarViewSchema's host-only callback, whose payload really is the @object-ui/types authoring type.

Verification — union re-run on the final commit d9d13e7fa

checkresult
pnpm --filter @object-ui/plugin-calendar type-check (tsc --noEmit && tsc -p tsconfig.test.json)exit 0
pnpm exec vitest run --maxWorkers=2 packages/plugin-calendar/src (repo root)Test Files 12 passed (12) / Tests 86 passed (86)
pnpm exec vitest run scripts/__tests__/{doc-version-claims,check-doc-links,vitest-invocation-guard,check-changeset-presence}.test.tsTest Files 4 passed (4) / Tests 166 passed (166)
node scripts/check-changeset-presence.mjs✅ 7 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s)
node scripts/check-doc-snippet-types.mjsSemantic phase: 101 of 101 block(s) judged, 0 failed.
pnpm check:doc-types✅ Every documented component type is registered.
pnpm check:spec-symbols✅ spec symbol derivation: … 13 declared dialects, 3 untriaged collisions in 1 packages. (unchanged — neither name collides with a spec export)
pnpm check:control-bytes✅ check-control-bytes: OK (scanned 4882 tracked text file(s); skipped 85 binary).
pnpm check:self-import / check:phantom-deps /
node scripts/check-type-check-coverage.mjs✅ 45/46 … and ✅ test type-check coverage: 41/41 packages compile their tests
node scripts/check-lint-coverage.mjs✅ lint coverage: 46/46 packages linted, 0 with outstanding errors
node scripts/check-doc-links.mjsLinks are valid across 13 scan roots.

Lint is a declared narrowing, not the repo-wide run — CI runs the farm regardless. Evidence that the narrowing excluded nothing: (1) the population came from eslint's own enumeration, not a guess — eslint --no-inline-config --format json packages/plugin-calendar enumerated 20 files, all seven changed/added source files among them; eslint itself refused content/docs and .changeset with "all of the files matching the glob pattern are ignored", so those two edits are outside the lint population by its configuration; (2) the file count is read from --format json, not counted by hand; (3) type-aware linting is offeslint --print-config on the barrel prints parserOptions: {} (no project / projectService), so this diff cannot move the verdict of any file it does not touch. Result: 0 error-severity messages (106 pre-existing warnings, unchanged in kind).

Nothing was widened, no pin loosened, no assertion weakened, no exemption added.


Generated by Claude Code

…endarViewEvent` (#5044)
Two structurally incompatible public exports were both called `CalendarEvent`:
the AUTHORING event in `@object-ui/types` (`id: string`, ISO-string `start`/`end`
with `end` required, plus `description`) and this package's RUNTIME event
(`id: string | number`, `start: Date`, `end?: Date`). Neither is assignable to
the other, so IDE auto-import picked between them at random and the wrong pick
failed as a remote `TS2322` about `Date`, not as a wrong import.
Per the 2026-08-19 maintainer ruling (option A), the authoring type keeps the
canonical name and the runtime type is renamed, with a `@deprecated`
`CalendarEvent` alias left on the barrel — the same shape objectui#4650 used for
`ObjectCalendarProps` -> `ObjectCalendarComponentProps`. The alias is a working
re-export of the same type, so existing importers keep compiling; no behaviour
changes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EuPCi56cnGyykygi3z9w4m
@github-actionsgithub-actionsBot added documentation Improvements or additions to documentation plugin tests labels Aug 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

✅ Console Performance Budget

MetricValueBudget
Eager closure (gzip, 52 chunks)3228.9 KB3990.2 KB
Main entry chunk (gzip)153.1 KB350 KB
Entry fileindex-BxCTBSjo.js
StatusPASS

The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it.


📦 Bundle Size Report

PackageSizeGzipped
app-shell (consoleActionDispatch.js)0.20KB0.19KB
app-shell (index.js)10.13KB3.77KB
app-shell (runtime-config.js)12.80KB4.47KB
app-shell (types.js)0.01KB0.04KB
app-shell (urlParams.js)10.06KB3.86KB
auth (ActiveOrganizationStorage.js)25.05KB9.16KB
auth (AuthContext.js)0.31KB0.24KB
auth (AuthGuard.js)2.07KB1.00KB
auth (AuthProvider.js)40.18KB10.59KB
auth (AuthShell.js)3.49KB1.40KB
auth (ForgotPasswordForm.js)12.21KB3.45KB
auth (LoginForm.js)18.15KB5.39KB
auth (PreviewBanner.js)0.90KB0.50KB
auth (RegisterForm.js)6.65KB2.22KB
auth (SocialSignInButtons.js)9.61KB3.89KB
auth (UserMenu.js)3.41KB1.23KB
auth (auth-gate-events.js)1.29KB0.66KB
auth (authStyles.js)5.04KB1.72KB
auth (createAuthClient.js)40.21KB10.80KB
auth (createAuthenticatedFetch.js)8.46KB3.43KB
auth (index.js)3.19KB1.44KB
auth (invitation-status.js)1.22KB0.70KB
auth (org-roles.js)6.66KB2.78KB
auth (phone-identifier.js)1.11KB0.66KB
auth (types.js)0.59KB0.35KB
auth (useAuth.js)5.30KB1.02KB
auth (useWorkspaceAdminStatus.js)5.13KB2.35KB
collaboration (CommentThread.js)26.08KB7.56KB
collaboration (LiveCursors.js)3.17KB1.27KB
collaboration (PresenceAvatars.js)6.49KB2.64KB
collaboration (PresenceProvider.js)2.79KB1.13KB
collaboration (index.js)1.68KB0.73KB
collaboration (useCollaborationTranslation.js)6.05KB2.52KB
collaboration (useCommentSearch.js)1.98KB0.88KB
collaboration (useConflictResolution.js)7.75KB1.86KB
collaboration (useMentionNotifications.js)1.81KB0.68KB
collaboration (usePresence.js)6.33KB1.84KB
collaboration (useRealtimeSubscription.js)7.91KB2.01KB
components (index.js)504.16KB114.08KB
core (index.js)4.92KB1.97KB
create-plugin (index.js)10.08KB3.26KB
data-objectstack (index.js)164.55KB45.67KB
fields (index.js)238.40KB59.89KB
i18n (LocalizationContext.js)1.76KB0.96KB
i18n (currency.js)1.22KB0.64KB
i18n (i18n.js)4.28KB1.75KB
i18n (index.js)3.44KB1.39KB
i18n (pickLocalized.js)7.62KB3.26KB
i18n (provider.js)23.13KB7.63KB
i18n (useDisplayLocale.js)2.85KB1.45KB
i18n (useObjectLabel.js)33.40KB8.71KB
i18n (useSafeTranslation.js)7.77KB3.13KB
layout (index.js)38.95KB10.97KB
mobile (MobileProvider.js)0.92KB0.49KB
mobile (ResponsiveContainer.js)0.94KB0.38KB
mobile (breakpoints.js)1.51KB0.70KB
mobile (createOfflineDataSource.js)5.61KB1.75KB
mobile (index.js)1.55KB0.62KB
mobile (offlineQueue.js)3.91KB1.35KB
mobile (pwa.js)0.97KB0.49KB
mobile (serviceWorker.js)1.48KB0.62KB
mobile (serviceWorkerSource.js)3.41KB1.48KB
mobile (useBreakpoint.js)1.54KB0.65KB
mobile (useGesture.js)6.96KB1.98KB
mobile (useOfflineSync.js)1.99KB0.72KB
mobile (usePullToRefresh.js)2.53KB0.85KB
mobile (useResponsive.js)0.72KB0.42KB
mobile (useResponsiveConfig.js)1.37KB0.63KB
mobile (useSpecGesture.js)4.32KB1.64KB
mobile (useTouchTarget.js)1.01KB0.54KB
permissions (MePermissionsProvider.js)9.53KB3.38KB
permissions (PermissionContext.js)0.31KB0.25KB
permissions (PermissionGuard.js)0.89KB0.45KB
permissions (PermissionProvider.js)4.64KB1.50KB
permissions (evaluator.js)5.12KB1.74KB
permissions (index.js)0.93KB0.41KB
permissions (store.js)0.91KB0.42KB
permissions (useFieldPermissions.js)1.28KB0.53KB
permissions (usePermissions.js)1.93KB0.88KB
plugin-ai (index.js)15.75KB3.80KB
plugin-calendar (index.js)46.62KB12.83KB
plugin-charts (index.js)64.66KB18.32KB
plugin-chatbot (index.js)186.91KB44.22KB
plugin-dashboard (index.js)132.44KB34.28KB
plugin-designer (index.js)212.30KB42.80KB
plugin-detail (index.js)242.34KB60.99KB
plugin-editor (index.js)2.46KB1.10KB
plugin-form (index.js)125.63KB30.64KB
plugin-gantt (index.js)164.15KB39.88KB
plugin-grid (index.js)200.79KB54.26KB
plugin-kanban (index.js)52.93KB14.60KB
plugin-list (index.js)111.80KB27.20KB
plugin-map (index.js)20.06KB6.62KB
plugin-markdown (index.js)13.72KB4.69KB
plugin-report (index.js)43.49KB11.93KB
plugin-timeline (index.js)26.49KB7.59KB
plugin-tree (index.js)8.50KB2.88KB
plugin-view (index.js)84.57KB20.74KB
providers (DataSourceProvider.js)0.75KB0.39KB
providers (MetadataProvider.js)1.37KB0.59KB
providers (ThemeProvider.js)1.90KB0.85KB
providers (UploadProvider.js)11.66KB3.50KB
providers (index.js)0.45KB0.23KB
providers (types.js)0.01KB0.04KB
react-runtime (index.js)5.62KB2.34KB
react (LazyPluginLoader.js)3.77KB1.33KB
react (SchemaRenderer.js)52.40KB17.45KB
react (data-invalidation.js)5.05KB2.08KB
react (index.js)1.33KB0.69KB
react (schema-input.js)2.32KB1.24KB
react (spec-input.js)0.20KB0.18KB
sdui-parser (codegen.js)5.41KB2.34KB
sdui-parser (dashboard-widget-options.js)3.08KB1.30KB
sdui-parser (index.js)4.93KB2.24KB
sdui-parser (input-type.js)2.84KB1.40KB
sdui-parser (parse.js)12.13KB3.65KB
sdui-parser (provenance.js)3.66KB1.82KB
sdui-parser (types.js)0.28KB0.23KB
sdui-parser (validate.js)7.54KB2.63KB
types (ai.js)0.20KB0.17KB
types (api-types.js)0.20KB0.18KB
types (app.js)2.87KB0.99KB
types (base.js)0.20KB0.18KB
types (blocks.js)0.20KB0.18KB
types (complex.js)0.20KB0.18KB
types (crud.js)0.20KB0.18KB
types (dashboard-filter-alias.js)6.23KB2.74KB
types (data-display.js)0.20KB0.18KB
types (data-protocol.js)0.20KB0.19KB
types (data.js)0.20KB0.18KB
types (designer.js)1.87KB0.85KB
types (disclosure.js)0.20KB0.18KB
types (error-code.js)1.54KB0.88KB
types (feedback.js)0.20KB0.18KB
types (field-types.js)0.20KB0.18KB
types (form.js)0.20KB0.18KB
types (http-inflight.js)8.87KB3.73KB
types (http-retry.js)4.32KB2.02KB
types (index.js)3.88KB1.85KB
types (layout.js)0.20KB0.18KB
types (managed-by.js)0.19KB0.18KB
types (mobile.js)2.59KB1.31KB
types (navigation.js)0.20KB0.18KB
types (objectql.js)0.20KB0.18KB
types (overlay.js)0.20KB0.18KB
types (permissions.js)0.20KB0.18KB
types (plugin-scope.js)0.20KB0.18KB
types (record-components.js)0.20KB0.19KB
types (record-semantics.js)1.28KB0.67KB
types (registry.js)0.20KB0.18KB
types (reports.js)0.20KB0.18KB
types (spec-report.js)5.05KB1.93KB
types (spec-ui-namespace.js)0.20KB0.19KB
types (system-fields.js)3.33KB1.54KB
types (theme.js)6.28KB2.87KB
types (ui-action.js)3.40KB1.71KB
types (views.js)0.20KB0.18KB
types (widget.js)0.20KB0.18KB

Size Limits

  • ✅ Core packages should be < 50KB gzipped
  • ✅ Component packages should be < 100KB gzipped
  • ⚠️ Plugin packages should be < 150KB gzipped

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationplugintests

Projects

None yet

2 participants

@os-zhuang@os-project-manager