refactor(types)!: authoring types are input types — ActionParam takes the spec's declaration forms, ListViewSchema stops promising phantom defaults (objectstack#4074) - #3020
Merged
Conversation
… the spec's declaration forms, ListViewSchema stops promising phantom defaults (objectstack#4074) Three public types said something different from what the platform accepts, found by making packages/types' tests compile (#3009) and resolving the declared p1-spec-alignment.test.ts debt site-by-site. ActionParam is now the AUTHORING shape, aligned with the spec's input: name/label/type optional, field/objectOverride added. The spec's primary declaration form — a bare field reference inheriting label/type/validation/ options from an object field — was unrepresentable while all three were required. The RESOLVED shape the dialog consumes (after app-shell's resolveActionParams() inlines the reference) remains core's ActionParamDef, all three required: authoring and resolved are different types on purpose. label is the spec's I18nLabel by import — which the new compile-time guard promptly revealed to be aliased to plain string in the current spec, so no behavioural widening today; importing the alias means objectui tracks any future widening automatically. ListViewInferred is z.input, not z.infer. The spec sub-schemas flowing into the list-view surface (userActions, tabs→ViewTab, sharing) carry .default()s, so the inferred output type made userActions.refresh or a tab's pinned/visible REQUIRED — but nothing on the render path runs .parse(): normalizeListViewSchema deliberately applies no defaults ("an absent flag stays absent", its own suite). The output type rejected valid authored metadata while promising renderers defaults that never arrive; input matches both author and runtime. FormField.dependsOn is DependsOnInput. The runtime reader (resolveCascadingOptions) has always accepted a bare name, a list of names, or {field, param} entries; the public property said string, so array-authored metadata type-errored while working and the form renderer read the key through (f as any).dependsOn to get past its own type. The shape now lives in @object-ui/types next to FormField; core imports and re-exports it; the two as-any reads in components are typed. The p1-spec-alignment.test.ts exclusion is gone — its 14 errors resolved: the "sharing in ObjectUI format" and legacy-ARIA fixtures are re-seated as normalizer-input dialects (folded by normalizeListViewSchema; asserted branch-by-branch in core's normalize-list-view.test.ts, the seam where the fold runs), and the one fixture no surface ever admitted (an ObjectQL triplet as a spec ViewTab.filter) is corrected to the rule-object form. Every test file in @object-ui/types is compiled, no exclusions. Discrimination-checked: reverting ListViewInferred to z.infer, dependsOn to string, or ActionParam.name to required each fails compile in the now-compiled tests (TS2739 / TS2322 / TS2741); restored, all projects clean. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014DBMo8gnFduzgpuSHd5Eje
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes the remaining scope of objectstack-ai/objectstack#4074 (steps 2–3) and retires the
p1-spec-alignment.test.tsdebt #3009 declared. Three public types said something different from what the platform accepts; each fix below carries its runtime evidence.1.
ActionParamis the authoring shape, aligned with the spec's inputname/label/typebecome optional andfield/objectOverrideappear. The spec's primary way to declare a param — a bare field reference that inherits label/type/validation/options from an object field — was unrepresentable while all three were required:{ field: 'status' }was a type error in the very package that claims spec alignment.The resolved shape the dialog consumes — after app-shell's
resolveActionParams()inlines the reference — remains@object-ui/core'sActionParamDef, with all three required. Authoring and resolved are different types on purpose; that separation is the whole point (and is spec's own: it exportsResolvedActionParamdistinct from the schema input).The new guard caught me in the act. I typed
labelas the spec'sI18nLabeland wrote a per-locale-record fixture, matching what I'd claimed in the issue — the now-compiled annotation immediately failed: in the current spec,I18nLabelSchemaisz.ZodString(the record form is the separateI18nObject). The fixture was corrected, and sincelabelimports the alias rather than restating it, objectui tracks any future widening automatically. Guards that run beat claims that don't — the PR's thesis, demonstrated against its own author mid-PR.2.
ListViewInferredisz.input, notz.inferThe spec sub-schemas flowing into the list-view surface (
userActions,tabs→ViewTab,sharing) carry.default()s, so the inferred output type madeuserActions.refreshor a tab'spinned/visiblerequired. But nothing on the render path ever runs.parse():normalizeListViewSchemadeliberately applies no defaults — "an absent flag stays absent" is one of its own test names. So the output type simultaneouslyuserActions: { sort: true }, a tab withoutpinned), andz.inputmatches both the author and the actual runtime object. Code that trusted the phantom defaults now gets an optionality error — a latent bug surfacing, not a regression.3.
FormField.dependsOnmatches its runtime readerresolveCascadingOptions(@object-ui/core) has always accepted a bare name, a list of names, or lookup-parameter entries{ field, param }— its parameter typeDependsOnInputsays so. The publicFormField.dependsOnsaidstring, so array-authored metadata type-errored while working, and the components form renderer read the key through(f as any).dependsOnto get past its own type — theas anywas the confession.DependsOnInputnow lives in@object-ui/typesnext toFormField(single source of truth; the dependency direction types → core is the correct one), core imports and re-exports it for its existing consumers (@object-ui/fields'useCascadingOptionskeeps working untouched), and bothas anyreads are typed.form.tsxlint warnings drop 87 → 85.The p1 exclusion is gone
tsconfig.test.jsonno longer excludes anything. The 14 errors resolved site-by-site rather than papered over:userActions/tabsminimal fixturesdependsOn: ['industry']DependsOnInput(fix #3){ visibility, enabled }" + legacy-ARIA spellingsnormalizeListViewSchemaand already asserted branch-by-branch in core'snormalize-list-view.test.ts(visibility→type collapse, bare-enabledmapping,lockedBypreservation, explicit-typeprecedence). Asserting a fold's input dialect on the canonical type is the wrong seam, and only ever "passed" because nothing compiled the file. Widening the canonical type to advertise a dialect that already has a fold would invite new metadata to author it.filter: ['owner', '=', 'current_user']ViewTab.filterhas never been admitted by any type on this surface; the fixture now uses the rule-object formVerification
ListViewInferredtoz.infer→TS2739on the exact fixtures; revertdependsOntostring→TS2322; revertActionParam.nameto required →TS2741on the field-backed annotation. Restored: clean.pnpm type-check— 76/76 tasks.pnpm vitest run— 731 files / 8516 tests passed, 1 file / 24 skipped.eslinton changed files: 0 errors, no new warnings (form.tsx count drops by 2).node scripts/check-changeset-fixed.mjs— clean.Changeset:
@object-ui/typesmajor (theActionParamoptionality andListViewInferredinput-typing are breaking for consumers that destructured required fields), core/components patch.Also fixes a wrong reference merged in #3009: the guard file's header said the test project landed in "#3005".
Refs objectstack#4074, #3009, #3003, #2231, #2890, objectstack#4115, objectstack#4118
Generated by Claude Code