Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/scripts/generate-field-contracts.mjs
T

89 lines
3.7 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
import crypto from 'node:crypto'
const sourcePath = 'contracts/fields/kbx.fields.json'
const source = JSON.parse(fs.readFileSync(sourcePath, 'utf8'))
const fields = [...source.fields].sort((a, b) => a.key.localeCompare(b.key))
const hash = crypto.createHash('sha256').update(JSON.stringify(source)).digest('hex')
const tsDir = 'packages/kbx-contracts/src/generated'
const csDir = 'backend/Shared/Contracts/Generated'
fs.mkdirSync(tsDir, { recursive: true })
fs.mkdirSync(csDir, { recursive: true })
fs.mkdirSync('generated', { recursive: true })
const q = value => JSON.stringify(value)
const ts = [
'// GENERATED FILE. DO NOT EDIT.',
`// Source: ${sourcePath}`,
`// Source SHA256: ${hash}`,
'',
`export const kbxFieldDictionaryVersion = ${q(source.version)} as const`,
'',
'export const kbxFieldCatalog = {',
...fields.map(f => ` ${q(f.key)}: ${JSON.stringify(f)},`),
'} as const',
'',
'export type KbxKnownFieldKey = keyof typeof kbxFieldCatalog',
'export type KbxKnownFieldDefinition = (typeof kbxFieldCatalog)[KbxKnownFieldKey]',
'',
'export function getKbxField<K extends KbxKnownFieldKey>(key: K): (typeof kbxFieldCatalog)[K] {',
' return kbxFieldCatalog[key]',
'}',
'',
].join('\n')
fs.writeFileSync(path.join(tsDir, 'fieldCatalog.ts'), ts)
const csString = value => value == null ? 'null' : `"${String(value).replaceAll('\\','\\\\').replaceAll('"','\\"')}"`
const csBool = value => value ? 'true' : 'false'
const pascal = s => s[0].toUpperCase() + s.slice(1)
const cs = [
'// <auto-generated />',
`// Source: ${sourcePath}`,
`// Source SHA256: ${hash}`,
'namespace Kbx.Contracts.Generated;',
'',
'public sealed record KbxFieldMetadata(',
' string Key, string Label, string DataType, IReadOnlyList<string> Aliases,',
' bool Required, int? MaxLength, int? Precision, int? Scale, string? LookupEntity,',
' bool Readonly, bool Importable, bool Exportable, bool Sensitive, string? Masking);',
'',
'public static class KbxFieldKeys',
'{',
...fields.map(f => ` public const string ${pascal(f.key)} = "${f.key}";`),
'}',
'',
'public static class KbxFieldCatalog',
'{',
` public const string Version = "${source.version}";`,
' private static readonly IReadOnlyDictionary<string, KbxFieldMetadata> Items =',
' new Dictionary<string, KbxFieldMetadata>(StringComparer.Ordinal)',
' {',
...fields.map(f => {
const aliases = (f.aliases ?? []).map(csString).join(', ')
return ` ["${f.key}"] = new("${f.key}", ${csString(f.label)}, "${f.dataType}", new[] { ${aliases} }, ${csBool(Boolean(f.required))}, ${f.maxLength ?? 'null'}, ${f.precision ?? 'null'}, ${f.scale ?? 'null'}, ${csString(f.lookupEntity)}, ${csBool(Boolean(f.readonly))}, ${csBool(Boolean(f.importable))}, ${csBool(Boolean(f.exportable))}, ${csBool(Boolean(f.sensitive))}, ${csString(f.masking)}),`
}),
' };',
'',
' public static KbxFieldMetadata Get(string key) => Items.TryGetValue(key, out var value)',
' ? value',
' : throw new KeyNotFoundException($"Unknown KBX field key: {key}");',
'',
' public static bool TryGet(string key, out KbxFieldMetadata? value) => Items.TryGetValue(key, out value);',
' public static IReadOnlyCollection<KbxFieldMetadata> All => Items.Values;',
'}',
'',
].join('\n')
fs.writeFileSync(path.join(csDir, 'KbxFieldCatalog.g.cs'), cs)
const manifest = {
version: source.version,
source: sourcePath,
sourceSha256: hash,
count: fields.length,
fields,
}
fs.writeFileSync('generated/field-manifest.json', JSON.stringify(manifest, null, 2) + '\n')
console.log(`field contracts generated: ${fields.length} fields, version ${source.version}`)