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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 | 25x 25x 25x 25x 25x 25x 25x 2x 22x 22x 22x 22x 22x 22x 22x 22x 3x 3x 3x 516x 516x 516x 516x 516x 3x 25x 25x | /**
* Static Generator
*
* Main entry point for generating static usage of UIF components. Orchestrates
* the analyzer, the target serializer, the class resolver, and the variant
* matrix.
*
* Output is shaped by two orthogonal options:
* - `target` — output language. Today only `'html'` is supported.
* - `compose` — composition strategy. `'reference'` (default) emits external
* component library tags wherever a child UIF declares a
* mapping (Pure LBC / LBC Recipe for the HTML target);
* `'expand'` recursively inlines child UIFs into a
* self-contained snapshot (Pure Blueprint).
*
* Two render modes:
* - Default: a single output snapshot for the component's default state.
* - Variant matrix (`variants: true`): every permutation of modifiers and
* variants, each annotated with its active configuration.
*/
import {
analyzeUif,
formatGeneratedCode,
type ResolvedUIF,
type ComponentMetadata,
} from '@fds-uif/generator-base/browser';
import type {
StaticGeneratorOptions,
StaticGeneratedCode,
StaticGenerationContext,
VariantPermutation,
PermutationState,
} from './types.js';
import { DEFAULT_OPTIONS } from './types.js';
import { buildHtmlFragment, buildLbcRootElement, buildLbcSlotChildren } from './html-builder.js';
import { buildDefaultState, generatePermutations, buildPermutationLabel } from './variant-matrix.js';
/**
* Generate static usage for a single UIF component.
*/
export async function generateStaticComponent(
uif: ResolvedUIF,
options: StaticGeneratorOptions = {},
): Promise<StaticGeneratedCode> {
const opts: StaticGeneratorOptions = { ...DEFAULT_OPTIONS, ...options };
const metadata = analyzeUif(uif);
const { code, permutations } = opts.variants
? buildVariantMatrix(metadata, opts, uif)
: { code: buildSingleState(metadata, opts, uif), permutations: undefined };
const fileContent = assembleFile(metadata.name, metadata.description, code);
const result: StaticGeneratedCode = {
files: [
{
path: `${metadata.name}.html`,
content: fileContent,
type: 'html',
},
],
metadata,
artifacts: {
code: fileContent,
permutations,
},
};
Eif (opts.skipFormat) {
return result;
}
return (await formatGeneratedCode(result)) as StaticGeneratedCode;
}
/**
* Generate static usage for multiple UIF components.
*/
export async function generateStaticComponents(
uifs: ResolvedUIF[],
options: StaticGeneratorOptions = {},
): Promise<StaticGeneratedCode[]> {
return Promise.all(uifs.map((uif) => generateStaticComponent(uif, options)));
}
// ---------------------------------------------------------------------------
// Internal
// ---------------------------------------------------------------------------
/**
* Build output for the component's default state, optionally overriding
* individual variant selections supplied by the caller.
*/
function buildSingleState(
metadata: ComponentMetadata,
options: StaticGeneratorOptions,
uif: ResolvedUIF,
): string {
const defaultState = buildDefaultState(metadata);
// Grouped (enum) modifier overrides are string values → go into state.variants.
// Boolean modifier overrides stay in state.modifiers.
const variants = { ...defaultState.variants, ...options.variantOverrides };
const modifiers = { ...defaultState.modifiers };
for (const [key, val] of Object.entries(options.modifierOverrides ?? {})) {
if (typeof val === 'string') {
variants[key] = val;
} else {
modifiers[key] = val;
}
}
const state: PermutationState = { variants, modifiers };
const context: StaticGenerationContext = { metadata, options, indent: 0, state, depth: 0 };
Iif (options.compose === 'reference' && uif.structure?.component) {
return buildLbcRootElement(uif, context, buildHtmlFragment, buildLbcSlotChildren);
}
return buildHtmlFragment(metadata.structure, context);
}
/**
* Build the full variant matrix: one output snapshot per permutation,
* each prefixed with a comment describing the active configuration.
*/
function buildVariantMatrix(
metadata: ComponentMetadata,
options: StaticGeneratorOptions,
uif: ResolvedUIF,
): { code: string; permutations: VariantPermutation[] } {
const states = generatePermutations(metadata);
const permutations: VariantPermutation[] = [];
for (const state of states) {
const context: StaticGenerationContext = { metadata, options, indent: 0, state, depth: 0 };
const code =
options.compose === 'reference' && uif.structure?.component
? buildLbcRootElement(uif, context, buildHtmlFragment, buildLbcSlotChildren)
: buildHtmlFragment(metadata.structure, context);
const label = buildPermutationLabel(state);
permutations.push({ label, state, code });
}
const sections = permutations.map((p) => `<!-- ${p.label} -->\n${p.code}`);
return {
code: sections.join('\n\n'),
permutations,
};
}
/**
* Assemble the final file content with header comments.
*/
function assembleFile(name: string, description: string, body: string): string {
const header = description
? [`<!-- ${name} -->`, `<!-- ${description} -->`, '<!-- @generated from UIF -->']
: [`<!-- ${name} -->`, '<!-- @generated from UIF -->'];
return [...header, '', body].join('\n');
}
|