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 | 27x 22x 6x 22x 22x 7x 7x 7x 17x 15x 15x 15x 3x 3x 4x 3x 3x 1x 1x 3x 5x 5x 5x 5x 5x 3x 3x 3x 3x 1x 2x 2x | /**
* @fds-uif/core - UIF Manifest Utilities
*
* Utilities for creating and managing UIF distribution manifests.
* These manifests enable UIF source packages to vend a catalog of available
* UIF files for consumer discovery.
*
* @see RFC: uif-gen-components-overview.md
*/
import { access, readFile, writeFile, mkdir } from 'node:fs/promises';
import { dirname } from 'node:path';
import type { SourceManifest, ComponentEntry, BuildResult } from './types.js';
/**
* Create an empty manifest
*/
export function createManifest(system: string): SourceManifest {
return {
uifManifest: '1.0.0',
generatedAt: new Date().toISOString(),
system,
foundations: {},
systems: {},
};
}
/**
* Add a component entry to the manifest
*/
export function addComponent(
manifest: SourceManifest,
component: ComponentEntry,
componentName: string,
type: 'foundation' | 'system',
): void {
const entry: ComponentEntry = {
source: component.source,
output: component.output,
};
if (type === 'system') {
entry.resolvedAt = new Date().toISOString();
}
manifest[type === 'foundation' ? 'foundations' : 'systems'][componentName] = entry;
manifest.generatedAt = new Date().toISOString();
}
/**
* Remove a component from the manifest
*/
export function removeComponent(manifest: SourceManifest, componentName: string): void {
delete manifest.foundations[componentName];
delete manifest.systems[componentName];
manifest.generatedAt = new Date().toISOString();
}
/**
* Read manifest from file
*/
export async function readManifest(path: string): Promise<SourceManifest> {
const content = await readFile(path, 'utf-8');
return JSON.parse(content) as SourceManifest;
}
/**
* Write manifest to file
*/
export async function writeManifest(manifest: SourceManifest, path: string): Promise<void> {
await mkdir(dirname(path), { recursive: true });
await writeFile(path, JSON.stringify(manifest, null, 2) + '\n', 'utf-8');
}
/**
* Generate manifest from build results
*/
export function generateManifest(
foundationResults: BuildResult[],
systemResults: BuildResult[],
system: string,
): SourceManifest {
const manifest = createManifest(system);
foundationResults
.filter((r) => r.success)
.forEach((r) => {
addComponent(manifest, { source: r.inputPath, output: r.outputPath }, r.componentName, 'foundation');
});
systemResults
.filter((r) => r.success)
.forEach((r) => {
addComponent(manifest, { source: r.inputPath, output: r.outputPath }, r.componentName, 'system');
});
return manifest;
}
/**
* Helper: Read manifest, apply updater function, write back
* Centralizes read-modify-write pattern for DRY code
*/
async function updateManifestFile(
manifestPath: string,
system: string,
updater: (manifest: SourceManifest) => void | null,
): Promise<void> {
const manifest = await readManifest(manifestPath).catch(() => createManifest(system));
const result = updater(manifest);
Iif (result === null) return; // Updater can return null to skip write
await writeManifest(manifest, manifestPath);
}
/**
* Update manifest for a single component (incremental build)
*/
export async function updateManifestForComponent(
result: BuildResult,
manifestPath: string,
system: string,
): Promise<void> {
if (!result.success || !result.type) return;
const componentType = result.type; // Capture for type narrowing
await updateManifestFile(manifestPath, system, (manifest) => {
addComponent(
manifest,
{ source: result.inputPath, output: result.outputPath },
result.componentName,
componentType,
);
});
}
/**
* Remove component from manifest (file deletion)
*/
export async function removeFromManifest(
componentName: string,
manifestPath: string,
system: string,
): Promise<void> {
// If manifest doesn't exist, nothing to remove
try {
await access(manifestPath);
} catch {
return;
}
await updateManifestFile(manifestPath, system, (manifest) => {
removeComponent(manifest, componentName);
});
}
|