mirror of
https://github.com/zoriya/v10.git
synced 2026-08-13 17:40:12 +00:00
feat(site): add util reference pipeline (#537)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
c11395ece1
commit
78112fbefd
@@ -1,105 +1,27 @@
|
||||
# API Docs Builder
|
||||
|
||||
Generates interactive API documentation from TypeScript sources for Video.js 10 components.
|
||||
Generates API reference JSON from TypeScript sources for Video.js 10 components and utilities.
|
||||
|
||||
> **Spec:** [`internal/design/site/api-docs-builder.md`](../../../internal/design/site/api-docs-builder.md)
|
||||
> is the ground-truth for discovery conventions, extraction rules, JSON schemas, the reference model,
|
||||
> and rendered output. When implementation diverges from the spec, the spec wins.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
TypeScript Sources (core/html/react packages)
|
||||
TypeScript Sources (core/html/react/store packages)
|
||||
↓
|
||||
api-docs-builder (typescript-api-extractor)
|
||||
↓
|
||||
JSON files (site/src/content/generated-api-reference/)
|
||||
JSON files (component + util references)
|
||||
↓
|
||||
<ApiReference /> Astro component
|
||||
Astro components (ComponentReference / UtilReference)
|
||||
↓
|
||||
Interactive tables in MDX pages
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
### 1. Source Discovery
|
||||
|
||||
The builder scans `packages/core/src/core/ui/` for component directories. For each component (e.g., `play-button`), it looks for:
|
||||
|
||||
- **Core file**: `play-button-core.ts` → Extracts `PlayButtonProps`, `PlayButtonState`, and `defaultProps`
|
||||
- **Data attrs file**: `play-button-data-attrs.ts` → Extracts data attributes with JSDoc descriptions
|
||||
- **HTML element file**: `packages/html/src/ui/play-button/play-button-element.ts` → Extracts `tagName`
|
||||
- **Parts index**: `packages/react/src/ui/play-button/index.parts.ts` → Detects multi-part components
|
||||
|
||||
### 2. TypeScript Extraction
|
||||
|
||||
Uses `typescript-api-extractor` to parse TypeScript AST and extract:
|
||||
|
||||
- Interface properties with types and JSDoc descriptions
|
||||
- Default values from `static defaultProps = { ... }`
|
||||
- Data attributes from `const PlayButtonDataAttrs = { ... } as const`
|
||||
- Lit element tag names from `static tagName = 'media-play-button'`
|
||||
|
||||
### 3. JSON Output
|
||||
|
||||
Generates one JSON file per component at `site/src/content/generated-api-reference/{kebab-case-name}.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "PlayButton",
|
||||
"props": {
|
||||
"label": {
|
||||
"type": "string | ((state: PlayButtonState) => string)",
|
||||
"description": "Custom label for the button.",
|
||||
"default": "''"
|
||||
}
|
||||
},
|
||||
"state": {
|
||||
"paused": {
|
||||
"type": "boolean",
|
||||
"description": "Whether playback is paused."
|
||||
}
|
||||
},
|
||||
"dataAttributes": {
|
||||
"data-paused": {
|
||||
"description": "Present when the media is paused."
|
||||
}
|
||||
},
|
||||
"platforms": {
|
||||
"html": {
|
||||
"tagName": "media-play-button"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 4. Astro Components
|
||||
|
||||
The `<ApiReference />` component:
|
||||
|
||||
1. Loads the JSON via Astro Content Collections (`getEntry('apiReference', 'play-button')`)
|
||||
2. For single-part components: renders Props, State, and Data Attributes sections with h3 headings
|
||||
3. For multi-part components: renders each part with a framework-aware h3 heading, part description, and h4 sub-sections
|
||||
4. Renders interactive tables with expandable prop details
|
||||
|
||||
## Usage
|
||||
|
||||
### In MDX
|
||||
|
||||
Use the unified `<ApiReference />` component for both single-part and multi-part components:
|
||||
|
||||
```mdx
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
|
||||
<ApiReference component="PlayButton" />
|
||||
```
|
||||
|
||||
For multi-part components, the same pattern applies — the component automatically renders part headings, descriptions, and sub-sections:
|
||||
|
||||
```mdx
|
||||
import ApiReference from "@/components/docs/api-reference/ApiReference.astro";
|
||||
|
||||
<ApiReference component="Time" />
|
||||
```
|
||||
|
||||
Part descriptions are extracted from JSDoc on the React component exports (e.g., `packages/react/src/ui/time/time-value.tsx`).
|
||||
|
||||
### Building
|
||||
|
||||
The builder runs automatically before dev/build via npm scripts:
|
||||
@@ -113,129 +35,60 @@ pnpm dev # via predev hook
|
||||
pnpm build # via prebuild hook
|
||||
```
|
||||
|
||||
## Multi-Part Components
|
||||
### In MDX
|
||||
|
||||
Some components are composed of multiple parts (e.g., Time has Value, Group, Separator). The builder auto-discovers these via convention.
|
||||
```mdx
|
||||
import ComponentReference from "@/components/docs/api-reference/ComponentReference.astro";
|
||||
import UtilReference from "@/components/docs/api-reference/UtilReference.astro";
|
||||
|
||||
### Detection
|
||||
|
||||
**Trigger**: Presence of `packages/react/src/ui/{name}/index.parts.ts`.
|
||||
|
||||
Single-part components (PlayButton, MuteButton) don't have this file and are unaffected.
|
||||
|
||||
### Discovery Algorithm
|
||||
|
||||
1. **Part name discovery**: Named (non-type-only) exports are parsed from `index.parts.ts`. Each value export becomes a part.
|
||||
2. **Kebab segment derivation**: Source path `./time-group` → strip `./time-` prefix → `group`.
|
||||
3. **HTML element matching**: Each part's kebab segment is used to find `{name}-{kebab}-element.ts` in the HTML directory (e.g., `time-group-element.ts`).
|
||||
4. **Primary part identification**: The part with NO `{name}-{part}-element.ts` match, whose element is just `{name}-element.ts`, is the primary part.
|
||||
5. **Shared resource attribution**: `{name}-core.ts` and `{name}-data-attrs.ts` are attributed to the primary part only.
|
||||
|
||||
### Naming Conventions Required
|
||||
|
||||
- Core interfaces must be `{Name}Props` and `{Name}State` (not `{Name}CoreProps` etc.)
|
||||
- Part exports in `index.parts.ts` must be value exports (not type-only)
|
||||
- HTML element files must follow `{name}-{part}-element.ts` naming
|
||||
- Element classes must be `{Name}{Part}Element` (e.g., `TimeGroupElement`)
|
||||
|
||||
### JSON Output
|
||||
|
||||
Multi-part components have empty top-level `props`/`state`/`dataAttributes`. All data lives in the `parts` record:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Time",
|
||||
"props": {},
|
||||
"state": {},
|
||||
"dataAttributes": {},
|
||||
"platforms": {},
|
||||
"parts": {
|
||||
"value": { "name": "Value", "description": "Displays a formatted time value.", "props": { ... }, ... },
|
||||
"group": { "name": "Group", "description": "Container for composed time displays.", "props": {}, ... },
|
||||
"separator": { "name": "Separator", "description": "Divider between time values.", "props": {}, ... }
|
||||
}
|
||||
}
|
||||
<ComponentReference component="PlayButton" />
|
||||
<UtilReference util="usePlayer" />
|
||||
```
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- **Part not appearing in JSON?** Check `index.parts.ts` exports the part as a value export (not type-only).
|
||||
- **Props/state empty for primary part?** Verify core interfaces are named `{Name}Props`/`{Name}State`.
|
||||
- **HTML tag name missing?** Verify element file follows `{name}-{part}-element.ts` naming and has `static tagName`.
|
||||
- **No primary part warning?** Ensure the primary part's element file is just `{name}-element.ts` (not `{name}-{part}-element.ts`).
|
||||
- **Part description missing?** Add a JSDoc comment to the React component export (e.g., `/** Displays a formatted time value. */` above `export const Value`).
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
site/scripts/api-docs-builder/
|
||||
├── README.md # This file
|
||||
├── README.md # This file
|
||||
└── src/
|
||||
├── index.ts # Main entry point, orchestrates handlers
|
||||
├── types.ts # TypeScript interfaces
|
||||
├── formatter.ts # Type formatting utilities
|
||||
├── utils.ts # Utility functions (naming helpers)
|
||||
├── core-handler.ts # Extracts Props/State from core packages
|
||||
├── index.ts # Main entry point, orchestrates handlers
|
||||
├── types.ts # TypeScript interfaces
|
||||
├── formatter.ts # Type formatting utilities
|
||||
├── utils.ts # Utility functions (naming helpers)
|
||||
├── core-handler.ts # Extracts Props/State from core packages
|
||||
├── data-attrs-handler.ts # Extracts data attributes
|
||||
├── html-handler.ts # Extracts Lit element info
|
||||
├── parts-handler.ts # Parses index.parts.ts for multi-part components
|
||||
├── html-handler.ts # Extracts Lit element info
|
||||
├── parts-handler.ts # Parses index.parts.ts for multi-part components
|
||||
├── util-handler.ts # Extracts util params/return from store/react packages
|
||||
└── tests/
|
||||
├── test-utils.ts
|
||||
├── fixtures/ # Monorepo fixtures for integration tests
|
||||
├── core-handler.test.ts
|
||||
├── data-attrs-handler.test.ts
|
||||
├── formatter.test.ts
|
||||
├── html-handler.test.ts
|
||||
├── parts-handler.test.ts
|
||||
├── util-handler.test.ts
|
||||
└── utils.test.ts
|
||||
|
||||
site/src/
|
||||
├── content/generated-api-reference/ # Generated JSON files (gitignored)
|
||||
│ ├── play-button.json
|
||||
│ ├── mute-button.json
|
||||
│ └── time.json
|
||||
├── content/generated-component-reference/ # Generated component JSON (gitignored)
|
||||
├── content/generated-util-reference/ # Generated util JSON (gitignored)
|
||||
└── components/docs/api-reference/
|
||||
├── ApiReference.astro # Unified component — renders full API reference from JSON
|
||||
├── ApiPropsTable.astro # Props table
|
||||
├── ApiStateTable.astro # State interface table
|
||||
├── ApiDataAttrsTable.astro # Data attributes table
|
||||
└── PropRow.astro # Expandable prop row
|
||||
├── ComponentReference.astro # Renders full component API reference
|
||||
├── UtilReference.astro # Renders full util API reference
|
||||
├── ApiPropsTable.astro # Props table
|
||||
├── ApiStateTable.astro # State interface table
|
||||
├── ApiDataAttrsTable.astro # Data attributes table
|
||||
├── UtilParamsTable.astro # Util parameters table
|
||||
├── UtilReturnTable.astro # Util return type table
|
||||
├── PropRow.astro # Expandable prop row
|
||||
├── StateRow.astro # Expandable state row
|
||||
├── DataAttrRow.astro # Data attribute row
|
||||
├── DetailRow.astro # Shared disclosure row
|
||||
└── InlineMarkdown.astro # Renders inline markdown (backticks → <code>)
|
||||
```
|
||||
|
||||
## Adding a New Component
|
||||
|
||||
### Single-Part Component
|
||||
|
||||
1. Create the component in `packages/core/src/core/ui/{name}/`
|
||||
2. Export `{Name}Props` interface and `{Name}State` interface
|
||||
3. Optionally create `{name}-data-attrs.ts` with data attribute definitions
|
||||
4. Create the HTML element in `packages/html/src/ui/{name}/` with `static tagName`
|
||||
5. Run `pnpm api-docs` to generate JSON
|
||||
6. Use `<ApiReference component="{Name}" />` in MDX
|
||||
|
||||
### Multi-Part Component
|
||||
|
||||
1. Follow the single-part steps above for the primary part's core/data-attrs/element files
|
||||
2. Create `packages/react/src/ui/{name}/index.parts.ts` exporting each part
|
||||
3. Add JSDoc descriptions to each React component export for part descriptions
|
||||
4. Create HTML element files for each non-primary part at `packages/html/src/ui/{name}/{name}-{part}-element.ts`
|
||||
5. Run `pnpm api-docs` to generate JSON
|
||||
6. Use `<ApiReference component="{Name}" />` in MDX
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This builder's architecture and approach were inspired by [Base UI](https://github.com/mui/base-ui)'s
|
||||
`api-docs-builder`, maintained by MUI. Base UI is licensed under the
|
||||
[MIT License](https://github.com/mui/base-ui/blob/master/LICENSE) (Copyright 2019 Material-UI SAS).
|
||||
Thank you to the MUI team for the excellent reference implementation.
|
||||
|
||||
### Key differences from Base UI's builder
|
||||
|
||||
1. **Multi-platform**: One JSON per component containing all platform variants (React/HTML)
|
||||
2. **Core-first**: Props come from core package, not platform-specific components
|
||||
3. **Data attributes**: Extracted from dedicated `*-data-attrs.ts` files
|
||||
4. **HTML elements**: Extracts Lit element `static tagName`
|
||||
5. **No prettier**: Uses biome for formatting (removed prettier dependency)
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `typescript-api-extractor`: AST parsing for TypeScript types
|
||||
@@ -243,3 +96,10 @@ Thank you to the MUI team for the excellent reference implementation.
|
||||
- `tsx`: TypeScript execution
|
||||
|
||||
All dependencies are in `site/package.json` devDependencies.
|
||||
|
||||
## Acknowledgements
|
||||
|
||||
This builder's architecture and approach were inspired by [Base UI](https://github.com/mui/base-ui)'s
|
||||
`api-docs-builder`, maintained by MUI. Base UI is licensed under the
|
||||
[MIT License](https://github.com/mui/base-ui/blob/master/LICENSE) (Copyright 2019 Material-UI SAS).
|
||||
Thank you to the MUI team for the excellent reference implementation.
|
||||
|
||||
Reference in New Issue
Block a user