mirror of
https://github.com/zoriya/v10.git
synced 2026-08-07 22:56:34 +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
@@ -21,6 +21,45 @@ function unwrapObjectLiteral(node: ts.Expression): ts.ObjectLiteralExpression |
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function extractSatisfiesExpression(node: ts.Expression): ts.TypeNode | undefined {
|
||||
if (ts.isSatisfiesExpression(node)) return node.type;
|
||||
if (ts.isParenthesizedExpression(node)) return extractSatisfiesExpression(node.expression);
|
||||
if (ts.isAsExpression(node)) return extractSatisfiesExpression(node.expression);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function inferStateTypes(satisfiesType: ts.TypeNode, program: ts.Program): Map<string, string> | undefined {
|
||||
if (!ts.isTypeReferenceNode(satisfiesType) || !satisfiesType.typeArguments?.length) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const stateTypeArg = satisfiesType.typeArguments[0]!;
|
||||
const checker = program.getTypeChecker();
|
||||
const resolvedType = checker.getTypeAtLocation(stateTypeArg);
|
||||
const properties = resolvedType.getProperties();
|
||||
|
||||
if (properties.length === 0) return undefined;
|
||||
|
||||
const result = new Map<string, string>();
|
||||
|
||||
for (const prop of properties) {
|
||||
const propType = checker.getTypeOfSymbol(prop);
|
||||
|
||||
// Expand union types to avoid showing alias names (e.g., VolumeLevel → 'off' | 'low')
|
||||
let typeStr: string;
|
||||
if (propType.isUnion()) {
|
||||
typeStr = propType.types.map((t) => checker.typeToString(t)).join(' | ');
|
||||
} else {
|
||||
typeStr = checker.typeToString(propType);
|
||||
}
|
||||
|
||||
if (typeStr === 'boolean' || typeStr === 'false | true') continue;
|
||||
result.set(prop.name, typeStr.replace(/"/g, "'"));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract data attributes from a data-attrs file.
|
||||
*
|
||||
@@ -60,6 +99,10 @@ export function extractDataAttrs(
|
||||
const objLiteral = unwrapObjectLiteral(decl.initializer);
|
||||
if (!objLiteral) continue;
|
||||
|
||||
// Infer types from satisfies StateAttrMap<State>
|
||||
const satisfiesType = extractSatisfiesExpression(decl.initializer);
|
||||
const stateTypes = satisfiesType ? inferStateTypes(satisfiesType, program) : undefined;
|
||||
|
||||
// Extract properties with their JSDoc comments
|
||||
for (const prop of objLiteral.properties) {
|
||||
if (ts.isPropertyAssignment(prop) && ts.isIdentifier(prop.name)) {
|
||||
@@ -71,13 +114,22 @@ export function extractDataAttrs(
|
||||
dataAttrValue = prop.initializer.text;
|
||||
}
|
||||
|
||||
// Get JSDoc comment for this property
|
||||
const jsDocComment = getJsDocComment(prop, sourceFile);
|
||||
// Get JSDoc comment and optional @type for this property
|
||||
const { description: jsDocComment, type: jsDocType } = parseJsDoc(prop, sourceFile);
|
||||
|
||||
attrs.push({
|
||||
const attrEntry: { name: string; description: string; type?: string } = {
|
||||
name: dataAttrValue || `data-${propName}`,
|
||||
description: jsDocComment || '',
|
||||
});
|
||||
};
|
||||
|
||||
// JSDoc @type takes priority, then inferred type from satisfies
|
||||
if (jsDocType) {
|
||||
attrEntry.type = jsDocType;
|
||||
} else if (stateTypes?.has(propName)) {
|
||||
attrEntry.type = stateTypes.get(propName)!;
|
||||
}
|
||||
|
||||
attrs.push(attrEntry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,6 +147,27 @@ export function extractDataAttrs(
|
||||
return { attrs };
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse JSDoc comment, extracting description and optional `@type` tag.
|
||||
*/
|
||||
export function parseJsDoc(
|
||||
node: ts.PropertyAssignment,
|
||||
sourceFile: ts.SourceFile
|
||||
): { description: string; type?: string } {
|
||||
const raw = getJsDocComment(node, sourceFile);
|
||||
if (!raw) return { description: '' };
|
||||
|
||||
// Extract @type {value} tag
|
||||
const typeMatch = raw.match(/@type\s*\{([^}]+)\}/);
|
||||
if (!typeMatch) return { description: raw };
|
||||
|
||||
const type = typeMatch[1]!.trim();
|
||||
// Remove the @type line from description
|
||||
const description = raw.replace(/@type\s*\{[^}]+\}/, '').trim();
|
||||
|
||||
return { description, type };
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract JSDoc comment from a property assignment.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user