Skip to content

chore: add generated AI component index for /next - #5079

Merged
pomfrida merged 4 commits into
mainfrom
chore/ai-component-index
Jul 20, 2026
Merged

chore: add generated AI component index for /next#5079
pomfrida merged 4 commits into
mainfrom
chore/ai-component-index

Conversation

@pomfrida

@pomfrida pomfrida commented Jun 19, 2026

Copy link
Copy Markdown
Collaborator

Summary

Generates documentation/AI-COMPONENT-INDEX.md — a single-file ground-truth reference listing every /next component (name, JSDoc description, EDS-defined props, compound sub-components, asChild support, status). AI coding assistants can consult one file instead of re-walking packages/eds-core-react/src/components/next/ every session.

Closes #4890.

What's in the change

  • scripts/generate-component-index.js — Node script (uses ts-morph, promoted to direct devDep) that parses the top-level next/index.ts barrel and extracts metadata from each component's .tsx + .types.ts. Supports --check, which regenerates in memory and exits 1 if the committed file is stale, naming the affected components.
  • documentation/AI-COMPONENT-INDEX.md — generated output (committed, like a snapshot). 23 components today.
  • package.json — adds pnpm run generate:component-index; chains into prebuild so a root pnpm run build keeps it fresh.
  • .github/workflows/checks.yaml — runs generate:component-index --check before the build step (prebuild would mask a stale committed file), on both PRs and pushes to main. documentation added to the sparse checkout_paths so the committed file is visible in CI.
  • AGENTS.md — one-paragraph pointer in the EDS 2.0 overview block.
  • Point-of-use references: BUILDING_EDS_2_COMPONENTS.md, .claude/rules/eds-component.md, and the three scaffolding entry points (/new-component, Copilot new-component prompt, OpenCode eds-component agent) now direct agents to check the index before scaffolding.

Design notes

  • Location: documentation/AI-COMPONENT-INDEX.md (matches existing docs structure; AGENTS.md links to it from the root).
  • Extraction: ts-morph AST. Skips intersected HTML attributes and React-conventional props (children, className, style, ref, key) so the props list shows the EDS API surface only. Known limitation (documented in the file): props from referenced local type aliases or union types are not expanded — no component uses those patterns today.
  • Freshness: CI-gated. The --check step in the Checks workflow fails any PR that changes the /next API surface without regenerating the index. Note: pnpm run build:core-react does NOT regenerate (pre-hooks only fire for the exact script name build) — the CI gate is the enforcement, not the prebuild hook.
  • Sub-components: compound API (Field.Label, Dialog.Header) detected via the Compound<Name> type alias pattern. Standalone exports like MenuItem get their own row (not folded under Menu).
  • Description: JSDoc above the component's forwardRef declaration (also tries <Name>Component / <Name>Root for compound components), with <Name>Props as fallback. Only Icon has a JSDoc today; the rest fall back to . Future improvement: add JSDoc to more component files.

Review follow-up (Claude review, 24 June)

  • Suggestion 1 (AGENTS.md diff noise) — resolved by rebase; the diff is now the pointer paragraph only.
  • Suggestions 2–3 (base-type aliases, union types) — closed as documented limitations; no component uses these patterns.
  • Suggestion 4 (Slot row) — kept deliberately: agents should know the polymorphism utility exists.
  • Suggestion 5 (staleness) — resolved with the CI --check gate; drift was demonstrated in practice (Dialog merged to main without an index update).

Test plan

  • pnpm run generate:component-index produces documentation/AI-COMPONENT-INDEX.md with 23 components
  • Running it twice in a row produces zero diff (idempotent)
  • --check exits 0 when fresh; exits 1 naming affected components when a row is removed or tampered with
  • pnpm run lint scripts/generate-component-index.js passes
  • Spot-check: Dialog has compound Dialog.Header, Dialog.Title, Dialog.Content, Dialog.Actions; MenuItem is its own row; Button and Link show asChild ✓
  • The Check AI component index freshness step passes in the Checks workflow on this PR

Comment thread scripts/generate-component-index.js Fixed
@pomfrida pomfrida self-assigned this Jun 19, 2026
@pomfrida

Copy link
Copy Markdown
Collaborator Author

@claude review

@claude

claude Bot commented Jun 24, 2026

Copy link
Copy Markdown

Claude finished @pomfrida's task in 1m 42s —— View job


Code Review — AI Component Index

  • Read the diff (5 files)
  • Review scripts/generate-component-index.js
  • Verify the CodeQL escaping finding
  • Review package.json, AGENTS.md, generated output
  • Post review

Nice, focused utility. The script is well-documented, the extraction logic is sensible, and the generated table is exactly the kind of single-file ground truth that saves an agent from re-walking next/. Overall this is in good shape. Notes below, roughly by importance.

✅ The CodeQL finding is already resolved

The "incomplete string escaping" alert is addressed by commit e3aa9df:

function escapePipe(str) {
  if (!str) return str
  return str.replace(/\\/g, '\\\\').replace(/\|/g, '\\|')
}

The order is correct — backslashes are doubled before pipes are escaped, so an input pipe doesn't get a stray-doubled backslash. Since readJsDoc already collapses all whitespace (\s+ → ' '), newlines can't leak into a cell either. This cell sanitization is solid. The alert can be dismissed/closed.

Suggestions (non-blocking)

1. AGENTS.md change is broader than the PR description suggests. The body says "one-paragraph pointer in the EDS 2.0 overview block," but the diff also rewrites the entire Conventional Commits section (removes the "scope is usually omitted" rationale, restructures the scopes list). That may be an intended sync, or it may be diff noise from the branch lacking a merge base with origin/main (git diff origin/main...HEAD reports no merge base). Worth confirming the commit-convention rewrite is deliberate and belongs in this PR rather than slipping in unannounced. Fix this →

2. Props referenced via a base type are silently dropped. extractPropsFromTypeAlias (lines 149–176) walks TypeLiteral / IntersectionType / ParenthesizedType and intentionally skips every TypeReference. That's right for HTMLAttributes<…> / Omit<…>, but it also drops EDS props that come from a shared base alias, e.g. type FooProps = BaseFieldProps & { … } where BaseFieldProps is a local type alias. Those rows would under-report the API surface with no signal that anything was skipped. The field-reference doc only calls out HTML/React props as excluded. Either resolve local type-reference aliases, or note in the doc that base-type props aren't expanded. (Acceptable as a documented limitation — just make it explicit.)

3. No UnionType handling. A props type expressed as a discriminated union (type FooProps = A | B) yields an empty props list. None of today's 22 components hit this, but it'll fail silently the day one does. A one-line else if (kind === SyntaxKind.UnionType) branch (or at least a comment) would future-proof it.

4. Slot shows up as a component row. It's a polymorphism utility, not a user-facing component, but it's a PascalCase value export so it lands in the table (line 35 of the generated file). Minor noise — consider a small skip-list, or leave it if you'd rather keep the rule "everything the barrel exports."

5. Staleness. A committed generated file can drift when someone adds a component without running build. The PR rightly mirrors the existing extract-prerequisites.js pattern (no CI gate), so this is a conscious trade-off — flagging only so it's on record. A lightweight --check mode runnable in CI later would close the gap cheaply.

Things done well

  • ts-morph promoted from transitive to a direct devDep — correct; relying on a transitive dep would be fragile.
  • Deterministic output: rows sorted by name, props sorted after de-dup via Set → idempotent re-runs, as the test plan claims.
  • Compound${name} matched by exact name so an unrelated CompoundFoo helper can't steal the match (lines 185–203) — nice defensive touch.
  • Graceful handling of missing .tsx / .types.ts via loadSourceIfExists.
  • MenuItem correctly gets its own row rather than being folded under Menu.

No blocking issues. The escaping fix is correct; suggestions 1 (confirm AGENTS.md scope) and 2 (document/handle base-type props) are the ones I'd act on before merge.
chore/ai-component-index

@pomfrida
pomfrida force-pushed the chore/ai-component-index branch from e3aa9df to dd49db7 Compare June 29, 2026 10:14
@pomfrida
pomfrida marked this pull request as ready for review June 29, 2026 10:15
pomfrida and others added 3 commits July 20, 2026 15:55
Generates documentation/AI-COMPONENT-INDEX.md listing every /next
component with props, sub-components, and asChild support. Gives AI
coding assistants a stable ground-truth reference instead of
re-walking the source tree each session.

Wired into `prebuild` so `pnpm run build` keeps it fresh; ad-hoc
regeneration via `pnpm run generate:component-index`.

Closes #4890
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@pomfrida
pomfrida force-pushed the chore/ai-component-index branch from dd49db7 to 39cb71b Compare July 20, 2026 14:09
@pomfrida
pomfrida merged commit bf7c97f into main Jul 20, 2026
10 checks passed
@pomfrida
pomfrida deleted the chore/ai-component-index branch July 20, 2026 15:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate AI component index for /next components

2 participants