mirror of
https://github.com/zoriya/v10.git
synced 2026-08-16 02:45:09 +00:00
feat(site): generated multipart component api reference (#468)
This commit is contained in:
@@ -0,0 +1,70 @@
|
||||
import * as ts from 'typescript';
|
||||
import * as tae from 'typescript-api-extractor';
|
||||
|
||||
export interface PartExport {
|
||||
/** PascalCase export name (e.g., "Value", "Group", "Separator"). */
|
||||
name: string;
|
||||
/** Source path (e.g., "./time-value", "./time-group"). */
|
||||
source: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract part definitions from a React `index.parts.ts` file.
|
||||
*
|
||||
* Discovery algorithm:
|
||||
* 1. Parses named exports from `index.parts.ts` (filters out type-only exports)
|
||||
* 2. Each value export becomes a part: `export { Group } from './time-group'` -> part "Group"
|
||||
* 3. Source path is preserved for HTML element matching in the main builder
|
||||
*
|
||||
* If a part isn't appearing in the output:
|
||||
* - Ensure it's exported as a value export (not `type`-only) in `index.parts.ts`
|
||||
* - Ensure the source path follows `'./{component}-{part}'` naming
|
||||
*/
|
||||
export function extractParts(filePath: string, program: ts.Program): PartExport[] {
|
||||
const sourceFile = program.getSourceFile(filePath);
|
||||
if (!sourceFile) return [];
|
||||
|
||||
const parts: PartExport[] = [];
|
||||
|
||||
function visit(node: ts.Node) {
|
||||
// Match: export { Name } from './source' or export { Name, type NameProps } from './source'
|
||||
if (ts.isExportDeclaration(node) && node.moduleSpecifier && ts.isStringLiteral(node.moduleSpecifier)) {
|
||||
const source = node.moduleSpecifier.text;
|
||||
|
||||
// Skip type-only export declarations (export type { ... } from '...')
|
||||
if (node.isTypeOnly) return;
|
||||
|
||||
if (node.exportClause && ts.isNamedExports(node.exportClause)) {
|
||||
for (const element of node.exportClause.elements) {
|
||||
// Skip type-only specifiers (e.g., `type GroupProps`)
|
||||
if (element.isTypeOnly) continue;
|
||||
|
||||
parts.push({
|
||||
name: element.name.text,
|
||||
source,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
}
|
||||
|
||||
visit(sourceFile);
|
||||
|
||||
return parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the JSDoc description from a React component export.
|
||||
*
|
||||
* Parses the file with `typescript-api-extractor`, finds the export matching
|
||||
* `partName`, and returns its description (stripping `@example` blocks).
|
||||
*/
|
||||
export function extractPartDescription(filePath: string, program: ts.Program, partName: string): string | undefined {
|
||||
const ast = tae.parseFromProgram(filePath, program);
|
||||
const component = ast.exports.find((exp) => exp.name === partName);
|
||||
let desc = component?.documentation?.description;
|
||||
if (desc) desc = desc.replace(/\n*@example[\s\S]*$/, '').trim();
|
||||
return desc || undefined;
|
||||
}
|
||||
Reference in New Issue
Block a user