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 | 39x 8x 9x 3x 18x 51x 10x 39x 8x 6x 4x 1x 8x 9x 9x 3x 12x 3x 12x 18x | /**
* Props Building
*
* Transforms UIF states, modifiers, variants, slots, and bound attributes into PropMetadata.
*/
import type { ResolvedState, ResolvedModifier, ResolvedVariant, ResolvedSlot } from '@fds-uif/schema';
import type { PropMetadata } from '../types/index.js';
import { sanitizeIdentifier } from '../types/index.js';
/**
* Build props from extracted UIF data
*/
export function buildProps(
states: ResolvedState[],
modifiers: ResolvedModifier[],
variants: ResolvedVariant[],
slots: ResolvedSlot[],
boundAttrs: Array<{ attribute: string; prop: string; required: boolean }>,
inferDescriptions: boolean,
): PropMetadata[] {
const props: PropMetadata[] = [];
// States → props
for (const state of states) {
props.push(stateToProps(state, inferDescriptions));
}
// Modifiers → props
for (const modifier of modifiers) {
props.push(modifierToProps(modifier, inferDescriptions));
}
// Variants → props
for (const variant of variants) {
props.push(variantToProps(variant, inferDescriptions));
}
// Slots → props
for (const slot of slots) {
props.push(slotToProps(slot, inferDescriptions));
}
// Bound attributes → props (avoid duplicates)
for (const attr of boundAttrs) {
if (!props.some((p) => p.name === attr.prop)) {
props.push({
name: attr.prop,
type: 'string',
required: attr.required,
description: inferDescriptions ? `Bound attribute: ${attr.attribute}` : undefined,
source: 'attribute',
});
}
}
return props;
}
function stateToProps(state: ResolvedState, inferDescriptions: boolean): PropMetadata {
// Sanitize state name to be a valid JS identifier
const safeName = sanitizeIdentifier(state.name);
let type: string;
if (state.type === 'boolean') {
type = 'boolean';
} else if (state.type === 'enum' && state.options) {
type = state.options.map((v) => `'${v}'`).join(' | ');
} else {
type = 'string';
}
return {
name: safeName,
type,
required: false,
default: state.default,
description: inferDescriptions ? (state.description ?? `State: ${state.name}`) : undefined,
source: 'state',
};
}
function modifierToProps(modifier: ResolvedModifier, inferDescriptions: boolean): PropMetadata {
// Sanitize modifier name to be a valid JS identifier (e.g., 'outline-brand' → 'outlineBrand')
const safeName = sanitizeIdentifier(modifier.name);
return {
name: safeName,
type: 'boolean',
required: false,
description: inferDescriptions ? (modifier.description ?? `Modifier: ${modifier.name}`) : undefined,
source: 'modifier',
};
}
function variantToProps(variant: ResolvedVariant, inferDescriptions: boolean): PropMetadata {
// Sanitize variant name to be a valid JS identifier
const safeName = sanitizeIdentifier(variant.name);
const values = variant.options.map((o) => o.value);
return {
name: safeName,
type: values.map((v) => `'${v}'`).join(' | '),
required: false,
default: variant.default ?? values[0],
description: inferDescriptions ? (variant.description ?? `Variant: ${variant.name}`) : undefined,
source: 'variant',
};
}
function slotToProps(slot: ResolvedSlot, inferDescriptions: boolean): PropMetadata {
return {
name: slot.name === 'default' ? 'children' : slot.name,
type: 'ReactNode', // Library-specific generators may override
required: slot.required ?? false,
description: inferDescriptions ? `Slot: ${slot.name}` : undefined,
source: 'slot',
};
}
|