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-zhuangos-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

vercelBot commented Jul 31, 2026

Copy link
Copy Markdown

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

1 Skipped Deployment
ProjectDeploymentActionsUpdated (UTC)
objectstackIgnoredIgnoredJul 31, 2026 6:46am

Request Review

@github-actionsgithub-actionsBot 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.

@os-zhuang
os-zhuang marked this pull request as ready for review July 31, 2026 07:00
@os-zhuang
os-zhuang merged commit 9555b07 into mainJul 31, 2026
17 checks passed
@os-zhuang
os-zhuang deleted the claude/quirky-gauss-t5il47 branch July 31, 2026 07:00
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/mteststooling

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

@os-zhuang@claude