import fs from 'node:fs' import path from 'node:path' const source = JSON.parse(fs.readFileSync('contracts/fields/kbx.fields.json', 'utf8')) const known = new Set(source.fields.map(x => x.key)) const deprecated = new Map(source.fields.filter(x => x.deprecated).map(x => [x.key, x.replacementKey])) const files = [] function walk(dir) { if (!fs.existsSync(dir)) return for (const entry of fs.readdirSync(dir, { withFileTypes: true })) { const full = path.join(dir, entry.name) if (entry.isDirectory()) walk(full) else if (/\.(ts|vue)$/.test(entry.name)) files.push(full) } } walk('apps/web/src') const occurrences = [] const patterns = [ /\bfield\s*:\s*['"]([A-Za-z][A-Za-z0-9]*)['"]/g, /kbxImportField\(\s*['"]([A-Za-z][A-Za-z0-9]*)['"]\s*\)/g, ] for (const file of files) { const text = fs.readFileSync(file, 'utf8') for (const pattern of patterns) { for (const match of text.matchAll(pattern)) { const key = match[1] occurrences.push({ file, key, canonical: known.has(key), deprecated: deprecated.has(key), replacementKey: deprecated.get(key) ?? null }) } } } const counts = new Map() for (const x of occurrences) counts.set(x.key, (counts.get(x.key) ?? 0) + 1) const unique = [...counts.keys()].sort() const canonical = unique.filter(x => known.has(x)) const unknown = unique.filter(x => !known.has(x)) const candidates = unknown .map(key => ({ key, occurrences: counts.get(key) ?? 0 })) .filter(x => x.occurrences >= 2) .sort((a,b) => b.occurrences-a.occurrences || a.key.localeCompare(b.key)) const deprecatedUses = occurrences.filter(x => x.deprecated) const report = { dictionaryVersion: source.version, canonicalFieldCount: known.size, scannedFiles: files.length, fieldOccurrences: occurrences.length, uniqueFieldKeysObserved: unique.length, canonicalKeysUsed: canonical, localOrUnknownKeys: unknown, promotionCandidates: candidates, deprecatedUses, note: 'Unknown keys are not automatically errors: local read-model fields may remain local. Repeated business concepts are promotion candidates for the canonical dictionary.', } fs.writeFileSync('generated/field-adoption-report.json', JSON.stringify(report, null, 2) + '\n') console.log(`field adoption report: canonical-used=${canonical.length}, local/unknown=${unknown.length}, promotion-candidates=${candidates.length}, deprecated-uses=${deprecatedUses.length}`)