Skip to content

Comments

feat: cross-renderer component coverage matrix#653

Draft
zeroasterisk wants to merge 4 commits intogoogle:mainfrom
zeroasterisk:feat/coverage-matrix
Draft

feat: cross-renderer component coverage matrix#653
zeroasterisk wants to merge 4 commits intogoogle:mainfrom
zeroasterisk:feat/coverage-matrix

Conversation

@zeroasterisk
Copy link
Collaborator

Cross-Renderer Component Coverage Matrix

Adds a zero-dependency Node.js script (testing/coverage-matrix.mjs) that verifies all A2UI component types are implemented across renderers.

What it does

  1. Reads the v0.10 spec's standard_catalog.json for the canonical component list (18 types)
  2. Introspects the Lit renderer (root.ts case handlers) and Angular renderer (DEFAULT_CATALOG entries)
  3. Outputs a visual matrix showing parity status
  4. Exits with code 1 if any spec component is missing — CI-ready

Demo

coverage-matrix

Current result

Spec (v0.10) Lit (v0.8.1) Angular (v0.8.4)
Components 18 18 18
Parity

Note: Both renderers use the v0.8 name MultipleChoice which was renamed to ChoicePicker in v0.10. The script accounts for this rename.

Usage

node testing/coverage-matrix.mjs

Files

  • testing/coverage-matrix.mjs — the script (zero deps, Node.js builtins only)
  • testing/README.md — documentation and CI integration example

Adds a zero-dependency Node.js script that introspects the v0.10 spec,
Lit renderer, and Angular renderer to verify all component types are
implemented across renderers.

- Reads standard_catalog.json for canonical component list
- Scans Lit root.ts case handlers and Angular DEFAULT_CATALOG entries
- Outputs visual matrix with parity status
- Exits 1 if any spec component is missing (CI-friendly)
- Accounts for v0.8→v0.10 MultipleChoice→ChoicePicker rename

Current result: all 18 components covered in both renderers.
@google-cla
Copy link

google-cla bot commented Feb 23, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

The pull request introduces a new Node.js script to verify component coverage across Lit and Angular renderers against the v0.10 specification. This is a valuable addition for maintaining consistency and quality. The script correctly identifies component parity and handles the MultipleChoice to ChoicePicker rename. The accompanying README.md is clear and provides good usage and CI integration examples. I've identified a few areas for improvement regarding the Angular component extraction logic and the handling of the readdirSync import.

Comment on lines +26 to +28
const angularComponents = [...angularDefault.matchAll(/^\s+(\w+):/gm)]
.map(m => m[1])
.filter(name => !['type', 'bindings', 'https', 'http', 'import', 'return', 'const', 'export'].includes(name) && /^[A-Z]/.test(name))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current regex for extracting Angular components is quite broad and includes common JavaScript keywords. While the filter step attempts to remove some, it's brittle. A more robust approach would be to refine the regex to specifically target property keys within the DEFAULT_CATALOG object, perhaps by looking for key: patterns or by parsing the TypeScript file more intelligently if possible (though that might introduce external dependencies). The current approach might miss valid component names if they happen to be in the exclusion list, or include non-component properties if they are not in the exclusion list. This could lead to incorrect coverage reporting.

const angularComponents = [...angularDefault.matchAll(/(\w+):\s*\{\s*type:/gm)]
  .map(m => m[1])
  .sort();

* compares against v0.10 spec, and outputs a coverage matrix.
*/

import { readFileSync, readdirSync } from 'fs';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The readdirSync import is not used in the script. It's good practice to remove unused imports to keep the code clean and avoid potential confusion.

Suggested change
import { readFileSync, readdirSync } from 'fs';
import { readFileSync } from 'fs';

Comment on lines +60 to +61
if (inSpec && (!inLit || !inAngular) && comp !== 'ChoicePicker') {
failures.push(comp);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The failures array is populated but never used after the loop. This variable can be removed to simplify the code and avoid unnecessary state.

  // let failures = [];

@zeroasterisk
Copy link
Collaborator Author

Live Storybook (Lit renderer, all 18 components): https://a2ui-conformance-storybook.pages.dev/

This Storybook uses @storybook/web-components-vite which avoids the accessor keyword issue that breaks the repo's existing lit-storybook (Rollup/acorn can't parse TC39 decorators — Vite/esbuild handles them fine).

@zeroasterisk
Copy link
Collaborator Author

Update: Conformance Storybook + Generated Matrix

Live Storybook: https://a2ui-conformance-storybook.pages.dev/

81 stories covering all 18 component types:

  • 40 hand-written stories (Components, Integration)
  • 41 auto-generated from v0.10 JSON fixtures (translated to v0.8 at build time)

Architecture

  • Fixtures in v0.10 format as single source of truth (stories/fixtures/*.json)
  • Version adapter translates v0.10 → v0.8 (createSurfacebeginRendering, ChoicePickerMultipleChoice)
  • Build-time generator (scripts/generate-stories.mjs) produces CSF3 story files
  • Adding a scenario = edit a JSON file. Adding a renderer = one translation function

Versions Tested

Package Version
A2UI Spec v0.10
Lit Renderer v0.8.1
Angular Renderer v0.8.4
Storybook 8.6.14

Sidebar

All 18 components organized in three sections:

sidebar

Note: Uses @storybook/web-components-vite which fixes the accessor keyword issue that breaks the repo's existing lit-storybook (Rollup can't parse TC39 decorators — Vite/esbuild handles them).

Zaf added 2 commits February 23, 2026 15:12
…slation

- Fixed theme to include all nested keys (Text.all, CheckBox.container, etc.)
  preventing 'Cannot convert undefined or null to object' in Styles.merge
- Added auto-translation in simpleComponent: v0.10 flat format → v0.8 nested
  (e.g. {component: 'Button', child: 'txt'} → {component: {Button: {child: 'txt'}}})
- Added property renames: variant → usageHint for Text component
- String text/label/hint values auto-wrapped in {literalString: ...}
- Same translation in version-adapter.ts for generated stories
- Components now render: Button, Text, Card confirmed with content
- Theme: added all nested keys (Tabs.controls.all/selected, Modal.backdrop/element)
- StringValue wrapping: name, url, src, title, placeholder, description
- Component-specific: variant→usageHint (Text only), tabs→tabItems,
  value→selections (MultipleChoice), ChoicePicker→MultipleChoice
- Auto-detect v0.10 messages (createSurface/updateComponents) in renderA2UI
- Translate flat component format to nested in both simpleComponent and renderA2UI
- Only Modal (2, hidden by design) and 1 generated Tabs story still fail
@zeroasterisk
Copy link
Collaborator Author

Rendering Fixed: 78/81 Stories Pass (96%)

Automated Playwright audit confirms 78 of 81 stories render correctly with visible A2UI components.

What was wrong:

  1. Theme context needed full nested structure (Text.all, Tabs.controls.all/selected, Modal.backdrop/element)
  2. v0.10 flat component format ({component: "Button", child: "txt"}) needed translation to v0.8 nested ({component: {Button: {child: "txt"}}})
  3. StringValue properties (text, name, url, label) needed {literalString: ...} wrapping
  4. Property renames: variant→usageHint (Text), tabs→tabItems (Tabs), value→selections (MultipleChoice)

3 remaining failures:

  • Modal (2) — hidden by design (<dialog> not visible until click interaction)
  • 1 generated Tabs fixture format edge case

Live: https://a2ui-conformance-storybook.pages.dev/

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

Labels

None yet

Projects

Status: Todo

Development

Successfully merging this pull request may close these issues.

1 participant