const fs = require('fs') const path = require('path') const root = path.resolve(__dirname, '..') function parseCsv(text) { const source = text.replace(/^\uFEFF/, '').trim() const records = [] let record = [] let value = '' let quoted = false for (let i = 0; i < source.length; i++) { const c = source[i] if (c === '"') { if (quoted && source[i + 1] === '"') { value += '"'; i++ } else quoted = !quoted } else if (c === ',' && !quoted) { record.push(value); value = '' } else if ((c === '\r' || c === '\n') && !quoted) { if (c === '\r' && source[i + 1] === '\n') i++ record.push(value); records.push(record); record = []; value = '' } else value += c } record.push(value) records.push(record) const headers = records.shift() return records.filter(row => row.some(Boolean)).map(row => Object.fromEntries(headers.map((h, i) => [h, row[i] || '']))) } function csv(value) { return `"${String(value == null ? '' : value).replace(/"/g, '""')}"` } function read(name) { return parseCsv(fs.readFileSync(path.join(root, 'work', name), 'utf8')) } const frontend = read('frontend_procedure_call_inventory_20260725.csv') const database = read('database_procedure_inventory_20260725.csv') const normalizeName = value => String(value || '').toLocaleLowerCase() const frontendNames = new Set(frontend.map(row => normalizeName(row.Procedure))) const databaseNames = new Set(database.map(row => normalizeName(row.name))) const missing = frontend .filter(row => !databaseNames.has(normalizeName(row.Procedure))) .sort((a, b) => a.Procedure.localeCompare(b.Procedure, 'zh-CN')) const unused = database .filter(row => !frontendNames.has(normalizeName(row.name))) .sort((a, b) => a.name.localeCompare(b.name, 'zh-CN')) const write = (name, headers, rows) => { const text = [headers, ...rows].map(row => row.map(csv).join(',')).join('\n') + '\n' fs.writeFileSync(path.join(root, 'work', name), text, 'utf8') } write('frontend_calls_missing_db_procedure_20260725.csv', ['Procedure', 'CallCount', 'CreateDataTypes', 'SourceFiles'], missing.map(row => [row.Procedure, row.CallCount, row.CreateDataTypes, row.SourceFiles])) write('database_procedures_unused_by_static_frontend_20260725.csv', ['name', 'ParameterCount', 'HasWriteKeyword', 'HasExternalDependency', 'DefinitionBytes'], unused.map(row => [row.name, row.ParameterCount, row.HasWriteKeyword, row.HasExternalDependency, row.DefinitionBytes])) console.log(JSON.stringify({ frontendProcedures: frontend.length, databaseProcedures: database.length, missing: missing.length, unused: unused.length }))