Files
alla-allaos-fullstack/scripts/audit-pdf-mapping-coverage.ts
phaichayon fd01ebf7c7 pdf task-h
2026-06-19 15:09:58 +07:00

126 lines
3.6 KiB
TypeScript

import {
createSqlClient,
extractTemplateFields,
getActiveTemplateVersions,
getEffectiveMappedKeys,
getMappingsForVersion,
summarizeIssues
} from './pdf-audit-utils.ts';
function classifyToken(token: string, mappedKeys: Set<string>) {
if (token === 'topic' || token === 'data_topic') {
return 'dynamic_topic_field';
}
if (token === 'item_topic') {
return 'dynamic_topic_field';
}
if (token.startsWith('topic_') || token.startsWith('item_topic_')) {
return 'dynamic_runtime_field';
}
if (mappedKeys.has(token)) {
return 'mapped_field';
}
return 'unmapped_field';
}
async function main() {
const sql = createSqlClient();
try {
const templates = await getActiveTemplateVersions(sql);
const results = [];
for (const template of templates) {
const fields = extractTemplateFields(template.schemaJson);
const { mappings, columns } = await getMappingsForVersion(sql, template.versionId);
const mappedKeys = getEffectiveMappedKeys(fields, mappings);
const fieldNames = new Set(fields.map((field) => field.name).filter(Boolean));
const schemaTokens = [...new Set(fields.flatMap((field) => field.tokens))].sort();
const coverage = schemaTokens.map((token) => {
const mapping =
mappings.find((candidate) => candidate.placeholderKey === token) ??
mappings.find(
(candidate) =>
fields.some(
(field) =>
field.name === candidate.placeholderKey &&
field.tokens.length === 1 &&
field.tokens[0] === token
)
) ??
null;
return {
token,
classification: classifyToken(token, mappedKeys),
sourcePath: mapping?.sourcePath ?? null,
dataType: mapping?.dataType ?? null
};
});
const unmappedFields = coverage.filter((item) => item.classification === 'unmapped_field');
const orphanMappings = mappings
.filter(
(mapping) =>
!schemaTokens.includes(mapping.placeholderKey) &&
!fieldNames.has(mapping.placeholderKey) &&
mapping.placeholderKey !== 'items_table'
)
.map((mapping) => ({
placeholderKey: mapping.placeholderKey,
sourcePath: mapping.sourcePath
}));
const tableMapping = mappings.find((mapping) => mapping.placeholderKey === 'items_table') ?? null;
const tableColumns = tableMapping
? columns
.filter((column) => column.mappingId === tableMapping.id)
.map((column) => ({
columnName: column.columnName,
sourceField: column.sourceField
}))
: [];
const status = summarizeIssues([
unmappedFields.length ? 'FAIL' : 'PASS',
orphanMappings.length ? 'WARNING' : 'PASS'
]);
results.push({
templateName: template.templateName,
version: template.version,
organizationId: template.organizationId,
tokenCount: schemaTokens.length,
coverage,
unmappedFields,
orphanMappings,
tableColumns,
status
});
}
const overallStatus = summarizeIssues(
results.map((result) => result.status) as Array<'PASS' | 'WARNING' | 'FAIL'>
);
console.log(
JSON.stringify(
{
audit: 'mapping-coverage',
overallStatus,
results
},
null,
2
)
);
} finally {
await sql.end({ timeout: 5 });
}
}
main().catch((error) => {
console.error(`[audit-pdf-mapping-coverage] ${error.message}`);
process.exit(1);
});