Skip to content

feat(lint): <ListView searchableFields> on a react page resolves against the bound object's fields (#4329) - #4338

Merged
os-zhuang merged 1 commit into
mainfrom
claude/quirky-gauss-t5il47
Jul 31, 2026
Merged

feat(lint): <ListView searchableFields> on a react page resolves against the bound object's fields (#4329)#4338
os-zhuang merged 1 commit into
mainfrom
claude/quirky-gauss-t5il47

Conversation

@os-zhuang

@os-zhuang os-zhuang commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Closes #4329.

What

#4328's searchable-field-unknown gates a stale searchableFields entry on the metadata surfaces — an object's own ADR-0061 declaration, its built-in named list views, and a defineView aggregate's default list / named listViews — but not the react page surface. ListView declares searchableFields as a dataProp, so a kind:'react' page could write <ListView searchableFields={['renamed_field']}> and nothing resolved the name: the engine's resolveSearchFields silently 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 $searchFields override (#4254), the prop objectui echoes verbatim becomes a 400 INVALID_FIELD on that list.

How

  • validate-searchable-fields.ts exports its core instead of keeping it closure-private: indexObjectSearchTargets (object name → declared field names, null preserving the "no authored field map" distinction) and checkSearchableFieldList (the per-entry loop: three skips, dotted-path strictness, message/hint). validateSearchableFields behavior 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> whose objectName and searchableFields resolve as static literals. Same rule id, same error severity 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.
  • JSX-specific seams follow the gate's existing rules: a value from a variable, a call, or behind a spread is not knowable at build time and skips silently — an unresolvable binding is not a wrong one (ADR-0072 D1).

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']} on showcase_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.
  • ESLint on the three changed files — clean.

Changeset included (@objectstack/lint minor).

Follow-ups

🤖 Generated with Claude Code

https://claude.ai/code/session_01FwLRwsSQP9gNHkr4dCdQUd

…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
@vercel

vercel Bot commented Jul 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 31, 2026 6:46am

Request Review

@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation tests tooling labels Jul 31, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/lint.

2 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/automation/hook-bodies.mdx (via @objectstack/lint)
  • content/docs/permissions/authorization.mdx (via @objectstack/lint)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

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

Labels

documentation Improvements or additions to documentation size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

lint: <ListView searchableFields> on a React page is not checked against the object's fields

2 participants