fix(site): resolve aliased part descriptions in api docs (#518)

This commit is contained in:
Darius Cepulis
2026-02-12 10:16:34 -06:00
committed by GitHub
parent 4d62a1ff7d
commit 82944041f9
6 changed files with 49 additions and 9 deletions
+5 -1
View File
@@ -265,6 +265,7 @@ function discoverParts(source: ComponentSource, program: ts.Program): PartSource
const part: PartSource = {
name: partExport.name,
localName: partExport.localName,
kebab,
isPrimary,
htmlPath: hasSubPartElement ? subPartElementFile : isPrimary ? source.htmlPath : undefined,
@@ -310,7 +311,10 @@ function buildMultiPartApiReference(
for (const part of parts) {
// Extract JSDoc description from React component file
const description = part.reactPath ? extractPartDescription(part.reactPath, program, part.name) : undefined;
const description = part.reactPath
? (extractPartDescription(part.reactPath, program, part.localName) ??
extractPartDescription(part.reactPath, program, part.name))
: undefined;
if (part.isPrimary) {
// Primary part: extract from shared core and data-attrs
@@ -2,8 +2,10 @@ import * as ts from 'typescript';
import * as tae from 'typescript-api-extractor';
export interface PartExport {
/** PascalCase export name (e.g., "Value", "Group", "Separator"). */
/** PascalCase exported part name (e.g., "Value", "Group", "Separator"). */
name: string;
/** Local symbol name in the source module before aliasing. */
localName: string;
/** Source path (e.g., "./time-value", "./time-group"). */
source: string;
}
@@ -39,8 +41,10 @@ export function extractParts(filePath: string, program: ts.Program): PartExport[
// Skip type-only specifiers (e.g., `type GroupProps`)
if (element.isTypeOnly) continue;
const localName = element.propertyName?.text ?? element.name.text;
parts.push({
name: element.name.text,
localName,
source,
});
}
@@ -24,9 +24,9 @@ describe('extractParts', () => {
const result = extractParts('test.ts', program);
expect(result).toEqual([
{ name: 'Group', source: './time-group' },
{ name: 'Separator', source: './time-separator' },
{ name: 'Value', source: './time-value' },
{ name: 'Group', localName: 'Group', source: './time-group' },
{ name: 'Separator', localName: 'Separator', source: './time-separator' },
{ name: 'Value', localName: 'Value', source: './time-value' },
]);
});
@@ -38,7 +38,7 @@ describe('extractParts', () => {
const program = createTestProgram(code);
const result = extractParts('test.ts', program);
expect(result).toEqual([{ name: 'Group', source: './time-group' }]);
expect(result).toEqual([{ name: 'Group', localName: 'Group', source: './time-group' }]);
});
it('returns empty array for file with no exports', () => {
@@ -57,8 +57,8 @@ describe('extractParts', () => {
const result = extractParts('test.ts', program);
expect(result).toEqual([
{ name: 'Foo', source: './source' },
{ name: 'Bar', source: './source' },
{ name: 'Foo', localName: 'Foo', source: './source' },
{ name: 'Bar', localName: 'Bar', source: './source' },
]);
});
@@ -69,7 +69,17 @@ describe('extractParts', () => {
const program = createTestProgram(code);
const result = extractParts('test.ts', program);
expect(result).toEqual([{ name: 'Value', source: './time-value' }]);
expect(result).toEqual([{ name: 'Value', localName: 'Value', source: './time-value' }]);
});
it('captures local symbol name for aliased exports', () => {
const code = `
export { ControlsRoot as Root, type ControlsRootProps as RootProps } from './controls-root';
`;
const program = createTestProgram(code);
const result = extractParts('test.ts', program);
expect(result).toEqual([{ name: 'Root', localName: 'ControlsRoot', source: './controls-root' }]);
});
});
@@ -110,6 +120,24 @@ describe('extractPartDescription', () => {
expect(result).toBe('Container for composed time displays.');
});
it('extracts JSDoc description from a local (non-aliased) symbol name', () => {
const program = createTestProgram('');
mockParseFromProgram.mockReturnValue({
exports: [
{
name: 'ControlsRoot',
documentation: {
description: 'Root container for player controls.',
},
},
],
});
const result = extractPartDescription('test.tsx', program, 'ControlsRoot');
expect(result).toBe('Root container for player controls.');
});
it('returns undefined when export is not found', () => {
const program = createTestProgram('');
mockParseFromProgram.mockReturnValue({
@@ -18,6 +18,8 @@ export { ComponentApiReferenceSchema, PartApiReferenceSchema } from '../../../sr
export interface PartSource {
/** PascalCase name (e.g., "Value", "Group", "Separator"). */
name: string;
/** Local symbol name in the source module (before any aliasing). */
localName: string;
/** Kebab-case segment (e.g., "value", "group", "separator"). */
kebab: string;
/** True if this part gets the shared core/data-attrs. */