Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | 16x 1x 1x 1x 1x 96x 96x 95x 95x 1x 1x 95x 95x 95x 95x 95x 95x 95x 95x 95x 95x 95x 96x 96x 96x 96x 11x 84x 94x 3x 94x 1x 1x 1x 2x | /**
* UIF Analyzer
*
* Extracts component metadata from resolved UIFs for code generation.
* Uses extraction utilities from @fds-uif/core.
*/
import type { ResolvedUIF } from '@fds-uif/schema';
import {
validateResolved,
UifResolvedValidationError,
getStates,
getModifiers,
getVariants,
getSlots,
getBoundAttributes,
getStateClasses,
} from '@fds-uif/core/browser';
import type { ComponentMetadata, AnalyzerOptions, StructureMetadata } from '../types/index.js';
import { buildProps } from './props.js';
import { analyzeStructure } from './structure.js';
import { buildClassNameRules } from './classNames.js';
import { detectDependencies } from './dependencies.js';
const DEFAULT_ELEMENT = 'div';
/**
* Error thrown during UIF analysis
*/
export class UifAnalyzerError extends Error {
constructor(
message: string,
public readonly componentName?: string,
public readonly details?: Record<string, unknown>,
) {
super(message);
this.name = 'UifAnalyzerError';
}
}
/**
* Analyze a resolved UIF and extract component metadata
*
* @param uif - Resolved UIF (with $extends already merged)
* @param options - Analyzer options
* @returns Component metadata for code generation
*/
export function analyzeUif(uif: unknown, options: AnalyzerOptions = {}): ComponentMetadata {
const { defaultElement = DEFAULT_ELEMENT, inferDescriptions = false, validate = true } = options;
// Validate before analysis
if (validate) {
const validation = validateResolved(uif);
if (!validation.valid) {
const messages = validation.errors?.map((e) => `${e.path}: ${e.message}`).join('; ');
throw new UifResolvedValidationError(`Invalid UIF: ${messages}`, validation.errors);
}
}
const resolvedUif = uif as ResolvedUIF;
try {
// Use schema extraction utilities
const states = getStates(resolvedUif);
const modifiers = getModifiers(resolvedUif); // all modifiers (including child nodes) for props
const variants = getVariants(resolvedUif);
const slots = getSlots(resolvedUif);
const boundAttrs = getBoundAttributes(resolvedUif);
const stateClasses = getStateClasses(resolvedUif);
// Build props from extracted data
const props = buildProps(states, modifiers, variants, slots, boundAttrs, inferDescriptions);
// Analyze structure for rendering (also builds per-node classNames for child modifiers).
// Root structure is always a StructureMetadata (never a bare composed component).
const structure = analyzeStructure(resolvedUif.structure, defaultElement) as StructureMetadata;
// Build ROOT class name rules — only root-level modifiers (not child-node modifiers,
// which are already handled per-node in analyzeStructure above).
const rootModifiers = [...(resolvedUif.modifiers ?? []), ...(resolvedUif.structure?.modifiers ?? [])];
const classNames = buildClassNameRules(resolvedUif, rootModifiers, stateClasses);
// Detect dependencies
const dependencies = detectDependencies(resolvedUif.structure, defaultElement);
const metadata: ComponentMetadata = {
name: resolvedUif.name,
description: resolvedUif.description,
props,
structure,
classNames,
dependencies,
};
if (resolvedUif.accessibility) {
metadata.accessibility = {
role: resolvedUif.accessibility.role,
ariaProps: props.filter((p) => p.name.startsWith('aria')).map((p) => p.name),
landmarks: resolvedUif.accessibility.landmarks,
};
}
if (resolvedUif.behavior) {
metadata.behavior = resolvedUif.behavior;
}
return metadata;
} catch (error) {
Iif (error instanceof UifAnalyzerError) throw error;
Iif (error instanceof UifResolvedValidationError) throw error;
throw new UifAnalyzerError(
`Failed to analyze UIF: ${error instanceof Error ? error.message : String(error)}`,
resolvedUif.name,
);
}
}
/**
* Analyze multiple UIFs
*/
export function analyzeMultipleUifs(uifs: ResolvedUIF[], options: AnalyzerOptions = {}): ComponentMetadata[] {
return uifs.map((uif) => analyzeUif(uif, options));
}
// Re-export sub-modules for advanced usage
export { buildProps } from './props.js';
export { analyzeStructure, extractComponentPropsMetadata } from './structure.js';
export { buildClassNameRules } from './classNames.js';
export { detectDependencies } from './dependencies.js';
|