@urbicon-ui/docs-gen 6.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +92 -0
- package/dist/cli/CLI.d.ts +10 -0
- package/dist/cli/CLI.d.ts.map +1 -0
- package/dist/cli/CLI.js +340 -0
- package/dist/cli/CLI.js.map +1 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/core/discovery/ComponentFinder.d.ts +43 -0
- package/dist/core/discovery/ComponentFinder.d.ts.map +1 -0
- package/dist/core/discovery/ComponentFinder.js +421 -0
- package/dist/core/discovery/ComponentFinder.js.map +1 -0
- package/dist/core/discovery/FileStructureAnalyzer.d.ts +15 -0
- package/dist/core/discovery/FileStructureAnalyzer.d.ts.map +1 -0
- package/dist/core/discovery/FileStructureAnalyzer.js +35 -0
- package/dist/core/discovery/FileStructureAnalyzer.js.map +1 -0
- package/dist/core/discovery/MetadataExtractor.d.ts +15 -0
- package/dist/core/discovery/MetadataExtractor.d.ts.map +1 -0
- package/dist/core/discovery/MetadataExtractor.js +47 -0
- package/dist/core/discovery/MetadataExtractor.js.map +1 -0
- package/dist/core/discovery/index.d.ts +2 -0
- package/dist/core/discovery/index.d.ts.map +1 -0
- package/dist/core/discovery/index.js +2 -0
- package/dist/core/discovery/index.js.map +1 -0
- package/dist/core/enrichment/APIDataGenerator.d.ts +77 -0
- package/dist/core/enrichment/APIDataGenerator.d.ts.map +1 -0
- package/dist/core/enrichment/APIDataGenerator.js +663 -0
- package/dist/core/enrichment/APIDataGenerator.js.map +1 -0
- package/dist/core/enrichment/index.d.ts +2 -0
- package/dist/core/enrichment/index.d.ts.map +1 -0
- package/dist/core/enrichment/index.js +6 -0
- package/dist/core/enrichment/index.js.map +1 -0
- package/dist/core/extraction/ExtractionCoordinator.d.ts +53 -0
- package/dist/core/extraction/ExtractionCoordinator.d.ts.map +1 -0
- package/dist/core/extraction/ExtractionCoordinator.js +352 -0
- package/dist/core/extraction/ExtractionCoordinator.js.map +1 -0
- package/dist/core/extraction/index.d.ts +2 -0
- package/dist/core/extraction/index.d.ts.map +1 -0
- package/dist/core/extraction/index.js +2 -0
- package/dist/core/extraction/index.js.map +1 -0
- package/dist/core/generation/GenerationCoordinator.d.ts +51 -0
- package/dist/core/generation/GenerationCoordinator.d.ts.map +1 -0
- package/dist/core/generation/GenerationCoordinator.js +206 -0
- package/dist/core/generation/GenerationCoordinator.js.map +1 -0
- package/dist/core/generation/index.d.ts +2 -0
- package/dist/core/generation/index.d.ts.map +1 -0
- package/dist/core/generation/index.js +2 -0
- package/dist/core/generation/index.js.map +1 -0
- package/dist/core/index.d.ts +7 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +16 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/pipeline/ErrorHandler.d.ts +129 -0
- package/dist/core/pipeline/ErrorHandler.d.ts.map +1 -0
- package/dist/core/pipeline/ErrorHandler.js +321 -0
- package/dist/core/pipeline/ErrorHandler.js.map +1 -0
- package/dist/core/pipeline/PipelineOrchestrator.d.ts +45 -0
- package/dist/core/pipeline/PipelineOrchestrator.d.ts.map +1 -0
- package/dist/core/pipeline/PipelineOrchestrator.js +216 -0
- package/dist/core/pipeline/PipelineOrchestrator.js.map +1 -0
- package/dist/core/pipeline/index.d.ts +1 -0
- package/dist/core/pipeline/index.d.ts.map +1 -0
- package/dist/core/pipeline/index.js +2 -0
- package/dist/core/pipeline/index.js.map +1 -0
- package/dist/extractors/BaseExtractor.d.ts +33 -0
- package/dist/extractors/BaseExtractor.d.ts.map +1 -0
- package/dist/extractors/BaseExtractor.js +68 -0
- package/dist/extractors/BaseExtractor.js.map +1 -0
- package/dist/extractors/ExtractorFactory.d.ts +35 -0
- package/dist/extractors/ExtractorFactory.d.ts.map +1 -0
- package/dist/extractors/ExtractorFactory.js +88 -0
- package/dist/extractors/ExtractorFactory.js.map +1 -0
- package/dist/extractors/documentation/index.d.ts +1 -0
- package/dist/extractors/documentation/index.d.ts.map +1 -0
- package/dist/extractors/documentation/index.js +2 -0
- package/dist/extractors/documentation/index.js.map +1 -0
- package/dist/extractors/index.d.ts +1 -0
- package/dist/extractors/index.d.ts.map +1 -0
- package/dist/extractors/index.js +2 -0
- package/dist/extractors/index.js.map +1 -0
- package/dist/extractors/typescript/ExamplesExtractor.d.ts +32 -0
- package/dist/extractors/typescript/ExamplesExtractor.d.ts.map +1 -0
- package/dist/extractors/typescript/ExamplesExtractor.js +209 -0
- package/dist/extractors/typescript/ExamplesExtractor.js.map +1 -0
- package/dist/extractors/typescript/InheritanceExtractor.d.ts +45 -0
- package/dist/extractors/typescript/InheritanceExtractor.d.ts.map +1 -0
- package/dist/extractors/typescript/InheritanceExtractor.js +368 -0
- package/dist/extractors/typescript/InheritanceExtractor.js.map +1 -0
- package/dist/extractors/typescript/LocalTypesExtractor.d.ts +20 -0
- package/dist/extractors/typescript/LocalTypesExtractor.d.ts.map +1 -0
- package/dist/extractors/typescript/LocalTypesExtractor.js +100 -0
- package/dist/extractors/typescript/LocalTypesExtractor.js.map +1 -0
- package/dist/extractors/typescript/PropsExtractor.d.ts +142 -0
- package/dist/extractors/typescript/PropsExtractor.d.ts.map +1 -0
- package/dist/extractors/typescript/PropsExtractor.js +709 -0
- package/dist/extractors/typescript/PropsExtractor.js.map +1 -0
- package/dist/extractors/typescript/TypeScriptBaseExtractor.d.ts +74 -0
- package/dist/extractors/typescript/TypeScriptBaseExtractor.d.ts.map +1 -0
- package/dist/extractors/typescript/TypeScriptBaseExtractor.js +249 -0
- package/dist/extractors/typescript/TypeScriptBaseExtractor.js.map +1 -0
- package/dist/extractors/typescript/index.d.ts +1 -0
- package/dist/extractors/typescript/index.d.ts.map +1 -0
- package/dist/extractors/typescript/index.js +2 -0
- package/dist/extractors/typescript/index.js.map +1 -0
- package/dist/extractors/variants/TailwindVariantsParser.d.ts +16 -0
- package/dist/extractors/variants/TailwindVariantsParser.d.ts.map +1 -0
- package/dist/extractors/variants/TailwindVariantsParser.js +53 -0
- package/dist/extractors/variants/TailwindVariantsParser.js.map +1 -0
- package/dist/extractors/variants/VariantsExtractor.d.ts +45 -0
- package/dist/extractors/variants/VariantsExtractor.d.ts.map +1 -0
- package/dist/extractors/variants/VariantsExtractor.js +340 -0
- package/dist/extractors/variants/VariantsExtractor.js.map +1 -0
- package/dist/extractors/variants/index.d.ts +2 -0
- package/dist/extractors/variants/index.d.ts.map +1 -0
- package/dist/extractors/variants/index.js +2 -0
- package/dist/extractors/variants/index.js.map +1 -0
- package/dist/generators/api/APIFileGenerator.d.ts +32 -0
- package/dist/generators/api/APIFileGenerator.d.ts.map +1 -0
- package/dist/generators/api/APIFileGenerator.js +450 -0
- package/dist/generators/api/APIFileGenerator.js.map +1 -0
- package/dist/generators/api/TypeDefinitionGenerator.d.ts +1 -0
- package/dist/generators/api/TypeDefinitionGenerator.d.ts.map +1 -0
- package/dist/generators/api/TypeDefinitionGenerator.js +2 -0
- package/dist/generators/api/TypeDefinitionGenerator.js.map +1 -0
- package/dist/generators/api/index.d.ts +2 -0
- package/dist/generators/api/index.d.ts.map +1 -0
- package/dist/generators/api/index.js +2 -0
- package/dist/generators/api/index.js.map +1 -0
- package/dist/generators/index.d.ts +5 -0
- package/dist/generators/index.d.ts.map +1 -0
- package/dist/generators/index.js +4 -0
- package/dist/generators/index.js.map +1 -0
- package/dist/generators/llm/LLMDocumentationGenerator.d.ts +34 -0
- package/dist/generators/llm/LLMDocumentationGenerator.d.ts.map +1 -0
- package/dist/generators/llm/LLMDocumentationGenerator.js +480 -0
- package/dist/generators/llm/LLMDocumentationGenerator.js.map +1 -0
- package/dist/generators/llm/LLMFormatter.d.ts +4 -0
- package/dist/generators/llm/LLMFormatter.d.ts.map +1 -0
- package/dist/generators/llm/LLMFormatter.js +8 -0
- package/dist/generators/llm/LLMFormatter.js.map +1 -0
- package/dist/generators/llm/LlmsFullAssembler.d.ts +20 -0
- package/dist/generators/llm/LlmsFullAssembler.d.ts.map +1 -0
- package/dist/generators/llm/LlmsFullAssembler.js +63 -0
- package/dist/generators/llm/LlmsFullAssembler.js.map +1 -0
- package/dist/generators/llm/index.d.ts +1 -0
- package/dist/generators/llm/index.d.ts.map +1 -0
- package/dist/generators/llm/index.js +2 -0
- package/dist/generators/llm/index.js.map +1 -0
- package/dist/generators/mcp/MCPCatalogAssembler.d.ts +27 -0
- package/dist/generators/mcp/MCPCatalogAssembler.d.ts.map +1 -0
- package/dist/generators/mcp/MCPCatalogAssembler.js +147 -0
- package/dist/generators/mcp/MCPCatalogAssembler.js.map +1 -0
- package/dist/generators/mcp/MCPCatalogGenerator.d.ts +55 -0
- package/dist/generators/mcp/MCPCatalogGenerator.d.ts.map +1 -0
- package/dist/generators/mcp/MCPCatalogGenerator.js +153 -0
- package/dist/generators/mcp/MCPCatalogGenerator.js.map +1 -0
- package/dist/generators/svelte/PageGenerator.d.ts +82 -0
- package/dist/generators/svelte/PageGenerator.d.ts.map +1 -0
- package/dist/generators/svelte/PageGenerator.js +557 -0
- package/dist/generators/svelte/PageGenerator.js.map +1 -0
- package/dist/generators/svelte/PlaygroundPresets.d.ts +2 -0
- package/dist/generators/svelte/PlaygroundPresets.d.ts.map +1 -0
- package/dist/generators/svelte/PlaygroundPresets.js +4 -0
- package/dist/generators/svelte/PlaygroundPresets.js.map +1 -0
- package/dist/generators/svelte/SectionMerger.d.ts +38 -0
- package/dist/generators/svelte/SectionMerger.d.ts.map +1 -0
- package/dist/generators/svelte/SectionMerger.js +154 -0
- package/dist/generators/svelte/SectionMerger.js.map +1 -0
- package/dist/generators/svelte/TemplateEngine.d.ts +91 -0
- package/dist/generators/svelte/TemplateEngine.d.ts.map +1 -0
- package/dist/generators/svelte/TemplateEngine.js +500 -0
- package/dist/generators/svelte/TemplateEngine.js.map +1 -0
- package/dist/generators/svelte/index.d.ts +8 -0
- package/dist/generators/svelte/index.d.ts.map +1 -0
- package/dist/generators/svelte/index.js +11 -0
- package/dist/generators/svelte/index.js.map +1 -0
- package/dist/generators/svelte/renderers/ApiRenderer.d.ts +17 -0
- package/dist/generators/svelte/renderers/ApiRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/ApiRenderer.js +44 -0
- package/dist/generators/svelte/renderers/ApiRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/ExampleRenderer.d.ts +33 -0
- package/dist/generators/svelte/renderers/ExampleRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/ExampleRenderer.js +137 -0
- package/dist/generators/svelte/renderers/ExampleRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/OverviewRenderer.d.ts +9 -0
- package/dist/generators/svelte/renderers/OverviewRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/OverviewRenderer.js +45 -0
- package/dist/generators/svelte/renderers/OverviewRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/PlaygroundRenderer.d.ts +35 -0
- package/dist/generators/svelte/renderers/PlaygroundRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/PlaygroundRenderer.js +319 -0
- package/dist/generators/svelte/renderers/PlaygroundRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/TypesRenderer.d.ts +9 -0
- package/dist/generators/svelte/renderers/TypesRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/TypesRenderer.js +23 -0
- package/dist/generators/svelte/renderers/TypesRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/UsageRenderer.d.ts +14 -0
- package/dist/generators/svelte/renderers/UsageRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/UsageRenderer.js +91 -0
- package/dist/generators/svelte/renderers/UsageRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/VariantsRenderer.d.ts +43 -0
- package/dist/generators/svelte/renderers/VariantsRenderer.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/VariantsRenderer.js +277 -0
- package/dist/generators/svelte/renderers/VariantsRenderer.js.map +1 -0
- package/dist/generators/svelte/renderers/index.d.ts +8 -0
- package/dist/generators/svelte/renderers/index.d.ts.map +1 -0
- package/dist/generators/svelte/renderers/index.js +8 -0
- package/dist/generators/svelte/renderers/index.js.map +1 -0
- package/dist/generators/svelte/types.d.ts +13 -0
- package/dist/generators/svelte/types.d.ts.map +1 -0
- package/dist/generators/svelte/types.js +2 -0
- package/dist/generators/svelte/types.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/parsers/SvelteDocsParser.d.ts +44 -0
- package/dist/parsers/SvelteDocsParser.d.ts.map +1 -0
- package/dist/parsers/SvelteDocsParser.js +141 -0
- package/dist/parsers/SvelteDocsParser.js.map +1 -0
- package/dist/parsers/index.d.ts +2 -0
- package/dist/parsers/index.d.ts.map +1 -0
- package/dist/parsers/index.js +6 -0
- package/dist/parsers/index.js.map +1 -0
- package/dist/schema/ConfigurationBuilder.d.ts +55 -0
- package/dist/schema/ConfigurationBuilder.d.ts.map +1 -0
- package/dist/schema/ConfigurationBuilder.js +447 -0
- package/dist/schema/ConfigurationBuilder.js.map +1 -0
- package/dist/schema/index.d.ts +1 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/dist/types/configuration.d.ts +255 -0
- package/dist/types/configuration.d.ts.map +1 -0
- package/dist/types/configuration.js +2 -0
- package/dist/types/configuration.js.map +1 -0
- package/dist/types/core.d.ts +96 -0
- package/dist/types/core.d.ts.map +1 -0
- package/dist/types/core.js +2 -0
- package/dist/types/core.js.map +1 -0
- package/dist/types/docs-config.d.ts +5 -0
- package/dist/types/docs-config.d.ts.map +1 -0
- package/dist/types/docs-config.js +51 -0
- package/dist/types/docs-config.js.map +1 -0
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +9 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/validation.d.ts +321 -0
- package/dist/types/validation.d.ts.map +1 -0
- package/dist/types/validation.js +2 -0
- package/dist/types/validation.js.map +1 -0
- package/dist/utils/DeploymentManager.d.ts +80 -0
- package/dist/utils/DeploymentManager.d.ts.map +1 -0
- package/dist/utils/DeploymentManager.js +360 -0
- package/dist/utils/DeploymentManager.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/package.json +74 -0
|
@@ -0,0 +1,663 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generates structured API data from enriched component information
|
|
3
|
+
* This is the core of the enrichment phase - converts extraction results to API format
|
|
4
|
+
*/
|
|
5
|
+
export class APIDataGenerator {
|
|
6
|
+
/**
|
|
7
|
+
* Codeberg (Gitea) source base URL for `sourceHref` construction.
|
|
8
|
+
* Hardcoded rather than derived from a `package.json` repository
|
|
9
|
+
* field because the root-level package has no `repository` entry
|
|
10
|
+
* and only two sub-packages do (`shared-types`, `docs-gen`);
|
|
11
|
+
* deriving from those would couple the link to whichever package
|
|
12
|
+
* happened to be checked first.
|
|
13
|
+
*
|
|
14
|
+
* Gitea/Codeberg URL pattern is `<repo>/src/branch/<branch>/<path>`
|
|
15
|
+
* for source view. We pin to `main` rather than `HEAD` because
|
|
16
|
+
* Codeberg's path resolver does not currently accept `HEAD` as a
|
|
17
|
+
* branch placeholder — if the default branch is ever renamed, this
|
|
18
|
+
* constant has to move with it.
|
|
19
|
+
*
|
|
20
|
+
* If the repo ever moves, change this constant.
|
|
21
|
+
*/
|
|
22
|
+
static SOURCE_BASE_URL = 'https://codeberg.org/urbicon/ui/src/branch/main';
|
|
23
|
+
generatedTypes = new Set();
|
|
24
|
+
typeDefinitions = [];
|
|
25
|
+
componentSlugs = new Map();
|
|
26
|
+
routeBasePath = '/components';
|
|
27
|
+
/**
|
|
28
|
+
* Generate complete API data structure from rich components
|
|
29
|
+
*/
|
|
30
|
+
async generate(richComponents, options) {
|
|
31
|
+
console.log(`📊 Generating API data for ${richComponents.length} components`);
|
|
32
|
+
const startTime = Date.now();
|
|
33
|
+
const components = {};
|
|
34
|
+
// Reset state for new generation
|
|
35
|
+
this.generatedTypes.clear();
|
|
36
|
+
this.typeDefinitions = [];
|
|
37
|
+
this.componentSlugs.clear();
|
|
38
|
+
this.routeBasePath = options?.routeBasePath || '/components';
|
|
39
|
+
// Prepare component slugs for linking
|
|
40
|
+
for (const c of richComponents) {
|
|
41
|
+
this.componentSlugs.set(c.name, this.toSlug(c.name));
|
|
42
|
+
}
|
|
43
|
+
// Process each component
|
|
44
|
+
for (const component of richComponents) {
|
|
45
|
+
try {
|
|
46
|
+
console.log(` 🔍 Processing ${component.name}...`);
|
|
47
|
+
const apiData = await this.generateComponentAPIData(component);
|
|
48
|
+
components[component.name] = apiData;
|
|
49
|
+
console.log(` ✅ ${component.name}: ${apiData.props.length} props, ${apiData.variants.length} variants`);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
console.error(` ❌ Failed to process ${component.name}:`, error);
|
|
53
|
+
// Continue with other components - create minimal API data
|
|
54
|
+
components[component.name] = this.createFallbackAPIData(component);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Generate metadata
|
|
58
|
+
const metadata = {
|
|
59
|
+
generated: new Date().toISOString(),
|
|
60
|
+
version: '2.0.0',
|
|
61
|
+
totalComponents: Object.keys(components).length,
|
|
62
|
+
totalProps: Object.values(components).reduce((sum, comp) => sum + comp.props.length, 0),
|
|
63
|
+
generator: 'docs-gen'
|
|
64
|
+
};
|
|
65
|
+
const duration = Date.now() - startTime;
|
|
66
|
+
console.log(`📊 API data generation complete in ${duration}ms`);
|
|
67
|
+
console.log(` 📈 ${metadata.totalComponents} components, ${metadata.totalProps} total props, ${this.typeDefinitions.length} type definitions`);
|
|
68
|
+
return {
|
|
69
|
+
components,
|
|
70
|
+
types: this.typeDefinitions,
|
|
71
|
+
metadata
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
// ==========================================
|
|
75
|
+
// COMPONENT API DATA GENERATION
|
|
76
|
+
// ==========================================
|
|
77
|
+
async generateComponentAPIData(component) {
|
|
78
|
+
// Process props with cross-references and categorization
|
|
79
|
+
const processedProps = await this.processProps(component.props, component);
|
|
80
|
+
// Surface `Omit<XVariants, 'a' | 'b'>` decisions from PropsExtractor.
|
|
81
|
+
// Marker props with name `__OMIT_VARIANT__<key>` are extracted from
|
|
82
|
+
// the props list here and used to filter the variants pass below, so
|
|
83
|
+
// the keys never enter the public API surface (they're also stripped
|
|
84
|
+
// from the merged output).
|
|
85
|
+
const omittedVariantKeys = new Set();
|
|
86
|
+
for (let i = processedProps.length - 1; i >= 0; i--) {
|
|
87
|
+
const prop = processedProps[i];
|
|
88
|
+
if (prop?.name.startsWith('__OMIT_VARIANT__')) {
|
|
89
|
+
omittedVariantKeys.add(prop.name.slice('__OMIT_VARIANT__'.length));
|
|
90
|
+
processedProps.splice(i, 1);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Process variants with examples and categorization, then drop those
|
|
94
|
+
// explicitly omitted via `extends Omit<XVariants, '...' | '...'>`.
|
|
95
|
+
const allProcessedVariants = await this.processVariants(component.variants, component);
|
|
96
|
+
const processedVariants = allProcessedVariants.filter((v) => !omittedVariantKeys.has(v.name));
|
|
97
|
+
// Expose variants as API props (so API table shows available variant options)
|
|
98
|
+
// Deduplicate: only add variant props that don't already exist from TypeScript extraction
|
|
99
|
+
const variantPropsAsProps = this.createVariantPropsForAPI(processedVariants, component);
|
|
100
|
+
const existingPropNames = new Set(processedProps.map((p) => p.name));
|
|
101
|
+
const newVariantProps = variantPropsAsProps.filter((p) => !existingPropNames.has(p.name));
|
|
102
|
+
processedProps.push(...newVariantProps);
|
|
103
|
+
// Process inheritance with resolution and flattening
|
|
104
|
+
const processedInheritance = await this.processInheritance(component.inheritance, component);
|
|
105
|
+
// Integrate and enrich local types if present on component (produced by extraction)
|
|
106
|
+
const compWithLocalTypes = component;
|
|
107
|
+
const localTypeDefs = Array.isArray(compWithLocalTypes.localTypes)
|
|
108
|
+
? compWithLocalTypes.localTypes
|
|
109
|
+
: [];
|
|
110
|
+
if (localTypeDefs.length > 0) {
|
|
111
|
+
// Reverse index: which props reference which local types
|
|
112
|
+
const usedByMap = new Map();
|
|
113
|
+
const considerProps = [
|
|
114
|
+
...processedProps,
|
|
115
|
+
...processedInheritance.flatMap((inh) => inh.props || [])
|
|
116
|
+
];
|
|
117
|
+
for (const p of considerProps) {
|
|
118
|
+
const base = this.getBaseType(p.type || '');
|
|
119
|
+
if (!base)
|
|
120
|
+
continue;
|
|
121
|
+
if (localTypeDefs.some((t) => t.name === base)) {
|
|
122
|
+
const list = usedByMap.get(base) || [];
|
|
123
|
+
list.push({
|
|
124
|
+
component: component.name,
|
|
125
|
+
propName: p.name,
|
|
126
|
+
source: p?.source?.type || 'direct'
|
|
127
|
+
});
|
|
128
|
+
usedByMap.set(base, list);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
for (const td of localTypeDefs) {
|
|
132
|
+
// annotate scope/category and usedBy
|
|
133
|
+
td.scope = 'local';
|
|
134
|
+
td.usedByProps = usedByMap.get(td.name) || [];
|
|
135
|
+
td.usedByCount = Array.isArray(td.usedByProps) ? td.usedByProps.length : 0;
|
|
136
|
+
const defStr = String(td.definition || '');
|
|
137
|
+
const looksLikeVariant = defStr.includes('VariantProps<') || /Variants?$/.test(td.name);
|
|
138
|
+
const looksLikeProps = td.type === 'interface' && /Props$/.test(td.name);
|
|
139
|
+
td.category = looksLikeProps ? 'props' : looksLikeVariant ? 'variant' : 'helper';
|
|
140
|
+
if (!this.generatedTypes.has(td.name)) {
|
|
141
|
+
this.typeDefinitions.push(td);
|
|
142
|
+
this.generatedTypes.add(td.name);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
// Generate examples list exclusively from extraction phase (no fallbacks)
|
|
147
|
+
const componentWithExamples = component;
|
|
148
|
+
const examplesFromExtractor = Array.isArray(componentWithExamples.interfaceExamples)
|
|
149
|
+
? componentWithExamples.interfaceExamples
|
|
150
|
+
: [];
|
|
151
|
+
const examples = this.dedupeExamples(examplesFromExtractor.map((ex) => this.sanitizeExampleCode(ex)));
|
|
152
|
+
// Calculate component statistics
|
|
153
|
+
const stats = this.calculateComponentStats(processedProps, processedVariants, processedInheritance);
|
|
154
|
+
// Pull through Editorial-doc-page metadata from the rich
|
|
155
|
+
// ComponentInfo. Stability defaults to 'stable' so the badge can
|
|
156
|
+
// render unconditionally without each component needing a JSDoc
|
|
157
|
+
// tag; `sourceHref` and `relatedComponents` stay optional because
|
|
158
|
+
// missing data should be silently invisible rather than show a
|
|
159
|
+
// stub link / empty RELATED block.
|
|
160
|
+
const stability = component.stability ?? 'stable';
|
|
161
|
+
const sourceHref = this.buildSourceHref(component.filePath || '');
|
|
162
|
+
const relatedComponents = Array.isArray(component.relatedComponents)
|
|
163
|
+
? component.relatedComponents.filter((name) => name && name !== component.name)
|
|
164
|
+
: [];
|
|
165
|
+
return {
|
|
166
|
+
name: component.name,
|
|
167
|
+
props: processedProps,
|
|
168
|
+
variants: processedVariants,
|
|
169
|
+
inheritance: processedInheritance,
|
|
170
|
+
examples,
|
|
171
|
+
stats,
|
|
172
|
+
group: this.inferGroupFromPath(component.filePath || ''),
|
|
173
|
+
stability,
|
|
174
|
+
...(sourceHref ? { sourceHref } : {}),
|
|
175
|
+
...(relatedComponents.length > 0 ? { relatedComponents } : {}),
|
|
176
|
+
// @ts-expect-error not part of shared type, but used by docs app
|
|
177
|
+
types: localTypeDefs
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Builds a GitHub blob URL for the component's source file.
|
|
182
|
+
* Walks back from the absolute filesystem path to the first
|
|
183
|
+
* `packages/...` segment, then appends that to the repo base URL.
|
|
184
|
+
* Returns undefined when no `packages/` segment is present (e.g.
|
|
185
|
+
* an app-level component or a synthetic test fixture).
|
|
186
|
+
*
|
|
187
|
+
* Paths that traverse `node_modules` are rejected outright so a
|
|
188
|
+
* hoisted-dependency fixture (or a future glob that accidentally
|
|
189
|
+
* pulls in a vendored copy) doesn't render as a 404 link to a
|
|
190
|
+
* non-existent file in the upstream repo.
|
|
191
|
+
*/
|
|
192
|
+
buildSourceHref(filePath) {
|
|
193
|
+
if (!filePath)
|
|
194
|
+
return undefined;
|
|
195
|
+
const normalized = filePath.replace(/\\/g, '/');
|
|
196
|
+
if (normalized.includes('/node_modules/'))
|
|
197
|
+
return undefined;
|
|
198
|
+
const match = normalized.match(/(packages\/.+)$/);
|
|
199
|
+
if (!match)
|
|
200
|
+
return undefined;
|
|
201
|
+
return `${APIDataGenerator.SOURCE_BASE_URL}/${match[1]}`;
|
|
202
|
+
}
|
|
203
|
+
// ==========================================
|
|
204
|
+
// PROPS PROCESSING
|
|
205
|
+
// ==========================================
|
|
206
|
+
async processProps(props, component) {
|
|
207
|
+
const processedProps = [];
|
|
208
|
+
for (const prop of props) {
|
|
209
|
+
const processedProp = await this.processProp(prop, component);
|
|
210
|
+
processedProps.push(processedProp);
|
|
211
|
+
// Extract type definitions from complex props
|
|
212
|
+
this.extractTypeDefinitions(prop, component);
|
|
213
|
+
}
|
|
214
|
+
// Sort props by category and importance
|
|
215
|
+
return this.sortPropsForAPI(processedProps);
|
|
216
|
+
}
|
|
217
|
+
async processProp(prop, component) {
|
|
218
|
+
const processedProp = { ...prop };
|
|
219
|
+
// Ensure source.name is set (required by ApiReference)
|
|
220
|
+
if (!processedProp.source.name) {
|
|
221
|
+
processedProp.source.name = `${component.name}Props`;
|
|
222
|
+
}
|
|
223
|
+
// Enhance description with context if needed
|
|
224
|
+
if (prop.description.length < 20) {
|
|
225
|
+
processedProp.description = this.enhancePropertyDescription(prop, component);
|
|
226
|
+
}
|
|
227
|
+
// Add seeAlso for known types/components if not provided via JSDoc
|
|
228
|
+
if (!processedProp.seeAlso) {
|
|
229
|
+
const link = this.resolveTypeLink(prop.type, component);
|
|
230
|
+
if (link)
|
|
231
|
+
processedProp.seeAlso = link;
|
|
232
|
+
}
|
|
233
|
+
// Link placeholder/inherited variant aggregates to the Variants section
|
|
234
|
+
if ((processedProp.name?.startsWith('...') && processedProp.source?.type === 'variant') ||
|
|
235
|
+
processedProp.type === 'VariantProps') {
|
|
236
|
+
const slug = this.componentSlugs.get(component.name) || this.toSlug(component.name);
|
|
237
|
+
processedProp.seeAlso = `${this.routeBasePath.replace(/\/$/, '')}/${slug}#variants`;
|
|
238
|
+
}
|
|
239
|
+
// If local type is referenced, add a direct anchor for UI (TypeCell will prefer seeAlso, then typeAnchor)
|
|
240
|
+
try {
|
|
241
|
+
const base = this.getBaseType(prop.type || '');
|
|
242
|
+
if (base) {
|
|
243
|
+
const componentWithLocalTypes = component;
|
|
244
|
+
const localTypeNames = new Set(Array.isArray(componentWithLocalTypes.localTypes)
|
|
245
|
+
? componentWithLocalTypes.localTypes.map((t) => t.name)
|
|
246
|
+
: []);
|
|
247
|
+
if (localTypeNames.has(base)) {
|
|
248
|
+
const slug = this.componentSlugs.get(component.name) || this.toSlug(component.name);
|
|
249
|
+
processedProp.typeAnchor =
|
|
250
|
+
`${this.routeBasePath.replace(/\/$/, '')}/${slug}#type-${base}`;
|
|
251
|
+
const td = componentWithLocalTypes.localTypes?.find((t) => t?.name === base);
|
|
252
|
+
if (td?.definition) {
|
|
253
|
+
// Keep preview compact (first ~15 lines)
|
|
254
|
+
const raw = String(td.definition);
|
|
255
|
+
const lines = raw.split(/\r?\n/).slice(0, 15).join('\n');
|
|
256
|
+
processedProp.typePreview = lines;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
// ignore resolution failures
|
|
263
|
+
}
|
|
264
|
+
// Add usage examples if missing
|
|
265
|
+
const examples = this.generatePropExamples(prop, component);
|
|
266
|
+
if (examples && examples.length > 0) {
|
|
267
|
+
processedProp.examples = examples;
|
|
268
|
+
}
|
|
269
|
+
return processedProp;
|
|
270
|
+
}
|
|
271
|
+
enhancePropertyDescription(prop, component) {
|
|
272
|
+
const descriptions = {
|
|
273
|
+
class: `Additional CSS classes to apply to the ${component.name} component`,
|
|
274
|
+
children: `Content to render inside the ${component.name} component`,
|
|
275
|
+
variant: `Visual style variant for the ${component.name} component`,
|
|
276
|
+
size: `Size variant that controls dimensions and spacing of the ${component.name}`,
|
|
277
|
+
intent: `Color and semantic meaning variant for the ${component.name}`,
|
|
278
|
+
disabled: `Whether the ${component.name} is disabled and non-interactive`,
|
|
279
|
+
loading: `Whether the ${component.name} is in a loading state`,
|
|
280
|
+
mint: `Micro-interaction configuration for enhanced user experience`
|
|
281
|
+
};
|
|
282
|
+
return (descriptions[prop.name] ||
|
|
283
|
+
`${prop.name.charAt(0).toUpperCase() + prop.name.slice(1)} property for the ${component.name} component`);
|
|
284
|
+
}
|
|
285
|
+
resolveTypeLink(type, component) {
|
|
286
|
+
const base = this.getBaseType(type);
|
|
287
|
+
if (!base)
|
|
288
|
+
return undefined;
|
|
289
|
+
// Local type definitions for this component
|
|
290
|
+
const componentWithLocalTypes = component;
|
|
291
|
+
const localTypeNames = new Set(Array.isArray(componentWithLocalTypes.localTypes)
|
|
292
|
+
? componentWithLocalTypes.localTypes.map((t) => t.name)
|
|
293
|
+
: []);
|
|
294
|
+
if (localTypeNames.has(base)) {
|
|
295
|
+
const slug = this.componentSlugs.get(component.name) || this.toSlug(component.name);
|
|
296
|
+
return `${this.routeBasePath.replace(/\/$/, '')}/${slug}#type-${base}`;
|
|
297
|
+
}
|
|
298
|
+
// Component name or *Props → component page
|
|
299
|
+
const compName = base.endsWith('Props') ? base.slice(0, -'Props'.length) : base;
|
|
300
|
+
if (this.componentSlugs.has(compName)) {
|
|
301
|
+
const slug = this.componentSlugs.get(compName);
|
|
302
|
+
return `${this.routeBasePath.replace(/\/$/, '')}/${slug}#api`;
|
|
303
|
+
}
|
|
304
|
+
// External types
|
|
305
|
+
const external = this.getExternalTypeLink(base);
|
|
306
|
+
if (external)
|
|
307
|
+
return external;
|
|
308
|
+
// Urbicon tokens
|
|
309
|
+
const urbicon = this.getUrbiconTypeLink(base);
|
|
310
|
+
if (urbicon)
|
|
311
|
+
return urbicon;
|
|
312
|
+
return undefined;
|
|
313
|
+
}
|
|
314
|
+
getBaseType(type) {
|
|
315
|
+
if (!type)
|
|
316
|
+
return null;
|
|
317
|
+
const first = (type.split('|')[0] || '').trim();
|
|
318
|
+
const noGenerics = first.replace(/<.*>/, '').replace(/\[\]$/, '').trim();
|
|
319
|
+
const primitives = [
|
|
320
|
+
'string',
|
|
321
|
+
'number',
|
|
322
|
+
'boolean',
|
|
323
|
+
'undefined',
|
|
324
|
+
'null',
|
|
325
|
+
'void',
|
|
326
|
+
'any',
|
|
327
|
+
'never',
|
|
328
|
+
'unknown'
|
|
329
|
+
];
|
|
330
|
+
if (!noGenerics || primitives.includes(noGenerics) || /^['"]/.test(noGenerics))
|
|
331
|
+
return null;
|
|
332
|
+
return noGenerics;
|
|
333
|
+
}
|
|
334
|
+
toSlug(input) {
|
|
335
|
+
return input
|
|
336
|
+
.replace(/([a-z0-9])(\p{Lu})/gu, '$1-$2')
|
|
337
|
+
.replace(/[\s_]+/g, '-')
|
|
338
|
+
.toLowerCase();
|
|
339
|
+
}
|
|
340
|
+
inferGroupFromPath(filePath) {
|
|
341
|
+
try {
|
|
342
|
+
const lower = String(filePath || '').toLowerCase();
|
|
343
|
+
if (lower.includes('/primitives/'))
|
|
344
|
+
return 'primitives';
|
|
345
|
+
if (lower.includes('/components/'))
|
|
346
|
+
return 'components';
|
|
347
|
+
return undefined;
|
|
348
|
+
}
|
|
349
|
+
catch {
|
|
350
|
+
return undefined;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
getExternalTypeLink(typeName) {
|
|
354
|
+
const svelteMap = {
|
|
355
|
+
Snippet: 'https://svelte.dev/docs/svelte/snippet',
|
|
356
|
+
ComponentEvents: 'https://svelte.dev/docs/svelte/component-events'
|
|
357
|
+
};
|
|
358
|
+
if (svelteMap[typeName])
|
|
359
|
+
return svelteMap[typeName];
|
|
360
|
+
if (/^HTML\w+Attributes$/.test(typeName)) {
|
|
361
|
+
const el = typeName
|
|
362
|
+
.replace(/^HTML/, '')
|
|
363
|
+
.replace(/Attributes$/, '')
|
|
364
|
+
.toLowerCase();
|
|
365
|
+
return `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/${el}`;
|
|
366
|
+
}
|
|
367
|
+
const mdnMap = {
|
|
368
|
+
// DOM core
|
|
369
|
+
Event: 'https://developer.mozilla.org/en-US/docs/Web/API/Event',
|
|
370
|
+
HTMLElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement',
|
|
371
|
+
Element: 'https://developer.mozilla.org/en-US/docs/Web/API/Element',
|
|
372
|
+
Node: 'https://developer.mozilla.org/en-US/docs/Web/API/Node',
|
|
373
|
+
Document: 'https://developer.mozilla.org/en-US/docs/Web/API/Document',
|
|
374
|
+
// Events
|
|
375
|
+
MouseEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent',
|
|
376
|
+
KeyboardEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent',
|
|
377
|
+
FocusEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent',
|
|
378
|
+
PointerEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent',
|
|
379
|
+
InputEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/InputEvent',
|
|
380
|
+
WheelEvent: 'https://developer.mozilla.org/en-US/docs/Web/API/WheelEvent',
|
|
381
|
+
// HTML elements (common)
|
|
382
|
+
HTMLButtonElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement',
|
|
383
|
+
HTMLInputElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement',
|
|
384
|
+
HTMLDivElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLDivElement',
|
|
385
|
+
HTMLAnchorElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLAnchorElement',
|
|
386
|
+
HTMLSpanElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLSpanElement',
|
|
387
|
+
HTMLUListElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLUListElement',
|
|
388
|
+
HTMLLIElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLLIElement',
|
|
389
|
+
HTMLTextAreaElement: 'https://developer.mozilla.org/en-US/docs/Web/API/HTMLTextAreaElement'
|
|
390
|
+
};
|
|
391
|
+
if (mdnMap[typeName])
|
|
392
|
+
return mdnMap[typeName];
|
|
393
|
+
return undefined;
|
|
394
|
+
}
|
|
395
|
+
getUrbiconTypeLink(typeName) {
|
|
396
|
+
const map = {
|
|
397
|
+
ComponentIntent: '/docs/design-tokens#intent',
|
|
398
|
+
ComponentSize: '/docs/design-tokens#size',
|
|
399
|
+
MintProp: '/docs/mint-system'
|
|
400
|
+
};
|
|
401
|
+
return map[typeName];
|
|
402
|
+
}
|
|
403
|
+
generatePropExamples(prop, component) {
|
|
404
|
+
const examples = [];
|
|
405
|
+
// Generate basic usage example
|
|
406
|
+
if (prop.type.includes('boolean')) {
|
|
407
|
+
examples.push({
|
|
408
|
+
title: `Enable ${prop.name}`,
|
|
409
|
+
code: `<${component.name} ${prop.name} />`,
|
|
410
|
+
description: `Enable the ${prop.name} property`
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
else if (prop.type.includes('string')) {
|
|
414
|
+
const exampleValue = this.generateExampleValue(prop.name, prop.type);
|
|
415
|
+
examples.push({
|
|
416
|
+
title: `Set ${prop.name}`,
|
|
417
|
+
code: `<${component.name} ${prop.name}="${exampleValue}" />`,
|
|
418
|
+
description: `Set the ${prop.name} property`
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
return examples.length > 0 ? examples : undefined;
|
|
422
|
+
}
|
|
423
|
+
generateExampleValue(propName, propType) {
|
|
424
|
+
// Extract union values if available
|
|
425
|
+
const unionMatch = propType.match(/'([^']+)'/g);
|
|
426
|
+
if (unionMatch && unionMatch.length > 0) {
|
|
427
|
+
return unionMatch[0].replace(/'/g, '');
|
|
428
|
+
}
|
|
429
|
+
// Default values based on prop name
|
|
430
|
+
const defaultValues = {
|
|
431
|
+
variant: 'filled',
|
|
432
|
+
size: 'md',
|
|
433
|
+
intent: 'primary',
|
|
434
|
+
class: 'custom-class',
|
|
435
|
+
href: '/example',
|
|
436
|
+
type: 'button',
|
|
437
|
+
placeholder: 'Enter text...'
|
|
438
|
+
};
|
|
439
|
+
return defaultValues[propName] || 'example';
|
|
440
|
+
}
|
|
441
|
+
// ==========================================
|
|
442
|
+
// VARIANTS PROCESSING
|
|
443
|
+
// ==========================================
|
|
444
|
+
async processVariants(variants, component) {
|
|
445
|
+
const processedVariants = [];
|
|
446
|
+
for (const variant of variants) {
|
|
447
|
+
const processedVariant = await this.processVariant(variant, component);
|
|
448
|
+
processedVariants.push(processedVariant);
|
|
449
|
+
}
|
|
450
|
+
return processedVariants.sort((a, b) => {
|
|
451
|
+
// Sort by importance: intent > variant > size > others
|
|
452
|
+
const order = ['intent', 'variant', 'size'];
|
|
453
|
+
const aIndex = order.indexOf(a.name);
|
|
454
|
+
const bIndex = order.indexOf(b.name);
|
|
455
|
+
if (aIndex !== -1 && bIndex !== -1)
|
|
456
|
+
return aIndex - bIndex;
|
|
457
|
+
if (aIndex !== -1)
|
|
458
|
+
return -1;
|
|
459
|
+
if (bIndex !== -1)
|
|
460
|
+
return 1;
|
|
461
|
+
return a.name.localeCompare(b.name);
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
async processVariant(variant, component) {
|
|
465
|
+
const processedVariant = { ...variant };
|
|
466
|
+
// Generate examples if missing
|
|
467
|
+
const examples = this.generateVariantExamples(variant, component);
|
|
468
|
+
if (examples && examples.length > 0) {
|
|
469
|
+
processedVariant.examples = examples;
|
|
470
|
+
}
|
|
471
|
+
// Ensure default value is set only if explicitly provided upstream
|
|
472
|
+
if (!variant.defaultValue) {
|
|
473
|
+
// No heuristic defaults here. Respect tv() defaultVariants only.
|
|
474
|
+
}
|
|
475
|
+
return processedVariant;
|
|
476
|
+
}
|
|
477
|
+
enhanceVariantDescription(variant, component) {
|
|
478
|
+
const descriptions = {
|
|
479
|
+
intent: `Controls the color theme and semantic meaning of the ${component.name}. Affects the overall appearance and user perception.`,
|
|
480
|
+
variant: `Controls the visual style and presentation of the ${component.name}. Determines the component's visual treatment.`,
|
|
481
|
+
size: `Controls the dimensions, padding, and text size of the ${component.name}. Affects the component's physical footprint.`,
|
|
482
|
+
placement: `Controls the positioning and alignment of the ${component.name} relative to its container or trigger element.`,
|
|
483
|
+
state: `Controls the visual state representation of the ${component.name} to communicate status to users.`
|
|
484
|
+
};
|
|
485
|
+
const baseDescription = descriptions[variant.name] ||
|
|
486
|
+
`Controls the ${variant.name} behavior and appearance of the ${component.name} component.`;
|
|
487
|
+
const valuesList = variant.values.length <= 4
|
|
488
|
+
? variant.values.join(', ')
|
|
489
|
+
: `${variant.values.slice(0, 3).join(', ')}, and ${variant.values.length - 3} more`;
|
|
490
|
+
return `${baseDescription} Available options: ${valuesList}.`;
|
|
491
|
+
}
|
|
492
|
+
generateVariantExamples(variant, component) {
|
|
493
|
+
return variant.values.slice(0, 3).map((value) => ({
|
|
494
|
+
value,
|
|
495
|
+
label: value.charAt(0).toUpperCase() + value.slice(1), // Add required label property
|
|
496
|
+
description: `${component.name} with ${variant.name} set to "${value}"`,
|
|
497
|
+
code: `<${component.name} ${variant.name}="${value}">${component.name} content</${component.name}>`
|
|
498
|
+
}));
|
|
499
|
+
}
|
|
500
|
+
// ==========================================
|
|
501
|
+
// VARIANTS AS API PROPS (FLATTENED VIEW)
|
|
502
|
+
// ==========================================
|
|
503
|
+
createVariantPropsForAPI(variants, component) {
|
|
504
|
+
const props = [];
|
|
505
|
+
for (const v of variants) {
|
|
506
|
+
// Build a union type from values
|
|
507
|
+
const unionType = v.values && v.values.length > 0
|
|
508
|
+
? v.values.map((val) => `'${val}'`).join(' | ')
|
|
509
|
+
: 'string';
|
|
510
|
+
const description = this.enhanceVariantDescription(v, component);
|
|
511
|
+
const prop = {
|
|
512
|
+
name: v.name,
|
|
513
|
+
type: unionType,
|
|
514
|
+
required: false,
|
|
515
|
+
description,
|
|
516
|
+
...(v.defaultValue !== undefined && v.defaultValue !== ''
|
|
517
|
+
? { defaultValue: v.defaultValue }
|
|
518
|
+
: {}),
|
|
519
|
+
// expose raw values for UI rendering (e.g., tooltip/second line)
|
|
520
|
+
...(Array.isArray(v.values) && v.values.length > 0 ? { values: v.values } : {}),
|
|
521
|
+
source: {
|
|
522
|
+
type: 'variant',
|
|
523
|
+
name: `${component.name}Variants`
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
props.push(prop);
|
|
527
|
+
}
|
|
528
|
+
return props;
|
|
529
|
+
}
|
|
530
|
+
// Removed heuristic default inference
|
|
531
|
+
// ==========================================
|
|
532
|
+
// INHERITANCE PROCESSING
|
|
533
|
+
// ==========================================
|
|
534
|
+
async processInheritance(inheritance, component) {
|
|
535
|
+
const processedInheritance = [];
|
|
536
|
+
for (const inheritanceItem of inheritance) {
|
|
537
|
+
const processedItem = await this.processInheritanceItem(inheritanceItem, component);
|
|
538
|
+
processedInheritance.push(processedItem);
|
|
539
|
+
}
|
|
540
|
+
return processedInheritance;
|
|
541
|
+
}
|
|
542
|
+
async processInheritanceItem(inheritance, component) {
|
|
543
|
+
const processedItem = { ...inheritance };
|
|
544
|
+
// Resolve URLs for better documentation
|
|
545
|
+
if (!inheritance.url && this.canResolveURL(inheritance.typeName)) {
|
|
546
|
+
processedItem.url = this.resolveInheritanceURL(inheritance.typeName);
|
|
547
|
+
}
|
|
548
|
+
// Process inherited props
|
|
549
|
+
processedItem.props = await Promise.all(inheritance.props.map((prop) => this.processProp(prop, component)));
|
|
550
|
+
return processedItem;
|
|
551
|
+
}
|
|
552
|
+
canResolveURL(typeName) {
|
|
553
|
+
return (typeName.includes('HTML') || typeName.includes('Svelte') || typeName.includes('@urbicon-ui'));
|
|
554
|
+
}
|
|
555
|
+
resolveInheritanceURL(typeName) {
|
|
556
|
+
const urlMap = {
|
|
557
|
+
HTMLButtonAttributes: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button',
|
|
558
|
+
HTMLInputAttributes: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input',
|
|
559
|
+
HTMLDivAttributes: 'https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div',
|
|
560
|
+
Snippet: 'https://svelte.dev/docs/svelte/snippet',
|
|
561
|
+
ComponentEvents: 'https://svelte.dev/docs/svelte/component-events'
|
|
562
|
+
};
|
|
563
|
+
return urlMap[typeName] || '#';
|
|
564
|
+
}
|
|
565
|
+
// ==========================================
|
|
566
|
+
// STATISTICS & METADATA
|
|
567
|
+
// ==========================================
|
|
568
|
+
calculateComponentStats(props, variants, _inheritance) {
|
|
569
|
+
const directProps = props.filter((p) => p.source.type === 'direct');
|
|
570
|
+
const variantProps = props.filter((p) => p.source.type === 'variant');
|
|
571
|
+
const inheritedProps = props.filter((p) => p.source.type === 'inherited');
|
|
572
|
+
return {
|
|
573
|
+
totalProps: props.length,
|
|
574
|
+
directProps: directProps.length,
|
|
575
|
+
variantProps: variantProps.length + variants.length,
|
|
576
|
+
inheritedProps: inheritedProps.length
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
// ==========================================
|
|
580
|
+
// UTILITY METHODS
|
|
581
|
+
// ==========================================
|
|
582
|
+
sanitizeExampleCode(code) {
|
|
583
|
+
if (!code)
|
|
584
|
+
return '';
|
|
585
|
+
const lines = String(code)
|
|
586
|
+
.split(/\r?\n/)
|
|
587
|
+
.map((l) => l.replace(/^\s*\*\s?/, ''));
|
|
588
|
+
while (lines.length > 0 && lines[0]?.trim() === '')
|
|
589
|
+
lines.shift();
|
|
590
|
+
while (lines.length > 0 && lines[lines.length - 1]?.trim() === '')
|
|
591
|
+
lines.pop();
|
|
592
|
+
return lines.join('\n');
|
|
593
|
+
}
|
|
594
|
+
dedupeExamples(examples) {
|
|
595
|
+
const seen = new Set();
|
|
596
|
+
const out = [];
|
|
597
|
+
for (const ex of examples) {
|
|
598
|
+
const key = ex.replace(/\s+/g, '').toLowerCase();
|
|
599
|
+
if (!seen.has(key)) {
|
|
600
|
+
seen.add(key);
|
|
601
|
+
out.push(ex);
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
return out;
|
|
605
|
+
}
|
|
606
|
+
sortPropsForAPI(props) {
|
|
607
|
+
return props.sort((a, b) => {
|
|
608
|
+
// Required props first
|
|
609
|
+
if (a.required && !b.required)
|
|
610
|
+
return -1;
|
|
611
|
+
if (!a.required && b.required)
|
|
612
|
+
return 1;
|
|
613
|
+
// Alphabetical within same requirement
|
|
614
|
+
return a.name.localeCompare(b.name);
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
isComplexType(type) {
|
|
618
|
+
return (type.includes('<') ||
|
|
619
|
+
type.includes('=>') ||
|
|
620
|
+
type.includes('|') ||
|
|
621
|
+
type.includes('&') ||
|
|
622
|
+
type.includes('[]'));
|
|
623
|
+
}
|
|
624
|
+
extractTypeDefinitions(prop, component) {
|
|
625
|
+
// Extract complex type definitions for the types array
|
|
626
|
+
if (!this.isComplexType(prop.type))
|
|
627
|
+
return;
|
|
628
|
+
// Create a safe alias name for the complex type, e.g. ButtonLoadingPlacement
|
|
629
|
+
const toPascalCase = (input) => input
|
|
630
|
+
.replace(/[^a-zA-Z0-9]+/g, ' ')
|
|
631
|
+
.trim()
|
|
632
|
+
.split(/\s+/)
|
|
633
|
+
.map((w) => w.charAt(0).toUpperCase() + w.slice(1))
|
|
634
|
+
.join('');
|
|
635
|
+
const aliasName = `${component.name}${toPascalCase(prop.name)}`;
|
|
636
|
+
if (this.generatedTypes.has(aliasName))
|
|
637
|
+
return;
|
|
638
|
+
this.typeDefinitions.push({
|
|
639
|
+
name: aliasName,
|
|
640
|
+
type: 'type',
|
|
641
|
+
definition: prop.type,
|
|
642
|
+
package: component.packageName,
|
|
643
|
+
documentation: `Type definition for ${prop.name} property`
|
|
644
|
+
});
|
|
645
|
+
this.generatedTypes.add(aliasName);
|
|
646
|
+
}
|
|
647
|
+
createFallbackAPIData(component) {
|
|
648
|
+
return {
|
|
649
|
+
name: component.name,
|
|
650
|
+
props: [],
|
|
651
|
+
variants: [],
|
|
652
|
+
inheritance: [],
|
|
653
|
+
examples: [],
|
|
654
|
+
stats: {
|
|
655
|
+
totalProps: 0,
|
|
656
|
+
directProps: 0,
|
|
657
|
+
variantProps: 0,
|
|
658
|
+
inheritedProps: 0
|
|
659
|
+
}
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
//# sourceMappingURL=APIDataGenerator.js.map
|