56 lines
2.3 KiB
JavaScript
56 lines
2.3 KiB
JavaScript
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}`)
|