feat(lint): <ListView searchableFields> on a react page resolves against the bound object's fields (#4329) - #4338
Merged
Conversation
…nst the bound object's fields (#4329) #4328's searchable-field-unknown gates the metadata surfaces (an object's own ADR-0061 declaration, its built-in named list views, defineView list/listViews) but not the react page surface: ListView declares searchableFields as a dataProp, so a kind:'react' page could ship a stale name nothing resolves — the engine silently narrows the search (or widens it to the auto-default once every entry is stale), and #4254 turns the echoed $searchFields override into a 400 INVALID_FIELD. validate-searchable-fields now exports its core (indexObjectSearchTargets + checkSearchableFieldList) and validate-react-page-props — the gate that already parses the page's real JSX — runs it on <ListView> usages with static objectName + searchableFields, under the same rule id and severity. The two surfaces agree by construction: same three skips (cross-package object, no authored field map, spec-derived system columns), same dotted-path strictness. Non-static values and spreads skip silently (ADR-0072 D1). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FwLRwsSQP9gNHkr4dCdQUd
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
Contributor
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:
|
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 #4329.
What
#4328's
searchable-field-unknowngates a stalesearchableFieldsentry on the metadata surfaces — an object's own ADR-0061 declaration, its built-in named list views, and adefineViewaggregate's defaultlist/ namedlistViews— but not the react page surface.ListViewdeclaressearchableFieldsas a dataProp, so akind:'react'page could write<ListView searchableFields={['renamed_field']}>and nothing resolved the name: the engine'sresolveSearchFieldssilently drops it (narrower search than the page asked for, or the auto-default — wider — once every entry is stale), and once the REST read path validates the$searchFieldsoverride (#4254), the prop objectui echoes verbatim becomes a400 INVALID_FIELDon that list.How
validate-searchable-fields.tsexports its core instead of keeping it closure-private:indexObjectSearchTargets(object name → declared field names,nullpreserving the "no authored field map" distinction) andcheckSearchableFieldList(the per-entry loop: three skips, dotted-path strictness, message/hint).validateSearchableFieldsbehavior is unchanged — its existing tests pass untouched.validate-react-page-props.ts— the gate that already parses a react page's real JSX and owns React block dataProps — runs that core on every<ListView>whoseobjectNameandsearchableFieldsresolve as static literals. Same rule id, sameerrorseverity as the metadata surfaces, so the two agree on what counts as a field by construction: cross-package objects, objects with no authored field map, and spec-derived system columns skip; a dotted entry (owner_id.name) is flagged, since search matches the field map by exact string.The finding's path carries the entry index (
pages[0].source › searchableFields[1]) so the author can go straight to the stale name.Corpus
The one live instance (
examples/app-showcase/src/ui/pages/renewals-pipeline.page.ts:97,searchableFields={['name']}onshowcase_account) resolves — this closes the gap before it bites, flagging nothing today.Testing
pnpm --filter @objectstack/lint test— 594 passed (39 files), including 9 new tests pinning the JSX seams: static resolution, spread/variable skips, system columns, cross-package + no-field-map skips, dotted paths, did-you-mean, where/path shape.pnpm --filter @objectstack/lint typecheck— clean.Changeset included (
@objectstack/lintminor).Follow-ups
ListView fields/columns/sort/filters/userFilters,ObjectForm fields,RecordHighlights/Details/Path,RecordRelatedList,<Block>) that is still unchecked against the bound object — including theRecordRelatedListobjectNamecontract conflict that blocks linting that block, and unifying the hand-copiedSYSTEM_FIELDSsets onto the spec-derived one.🤖 Generated with Claude Code
https://claude.ai/code/session_01FwLRwsSQP9gNHkr4dCdQUd