mirror of
https://github.com/zoriya/v10.git
synced 2026-08-13 09:30:38 +00:00
71 lines
2.4 KiB
TypeScript
71 lines
2.4 KiB
TypeScript
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;
|
|
}
|