89 lines
3.7 KiB
JavaScript
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}`)
|