Files
lislgosms/tools/quality/verify-enterprise-signatures-r4.mjs

89 lines
3.7 KiB
JavaScript

import { createHash } from 'node:crypto';
import { readFileSync } from 'node:fs';
import { resolve } from 'node:path';
import ts from '../../api/node_modules/typescript/lib/typescript.js';
const root = process.cwd();
const manifest = JSON.parse(
readFileSync(resolve(root, 'docs/contracts/admin-enterprise-signatures-r4.json'), 'utf8'),
);
const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed });
const sha256 = (value) => createHash('sha256').update(value).digest('hex');
function load(relativePath) {
const filePath = resolve(root, relativePath);
const source = readFileSync(filePath, 'utf8');
return {
source,
file: ts.createSourceFile(filePath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX),
};
}
const componentDirectory = 'src/apps/admin/enterprise-signatures';
const loadedFiles = manifest.files.map((file) => ({
relativePath: `${componentDirectory}/${file}`,
...load(`${componentDirectory}/${file}`),
}));
const declarations = new Map();
for (const loaded of loadedFiles) {
for (const statement of loaded.file.statements) {
if (!ts.isFunctionDeclaration(statement) || !statement.name) continue;
declarations.set(statement.name.text, { statement, file: loaded.file, relativePath: loaded.relativePath });
}
}
for (const expected of manifest.movedFunctions) {
const actual = declarations.get(expected.name);
if (!actual) throw new Error(`R4 frontend function missing: ${expected.name}`);
const canonical = printer
.printNode(ts.EmitHint.Unspecified, actual.statement, actual.file)
.replace(/^export\s+/, '');
if (sha256(canonical) !== expected.canonicalSha256) {
throw new Error(`${expected.name} changed while moving out of the page`);
}
}
const table = declarations.get('EnterpriseSignaturesTable');
if (!table?.statement.body) throw new Error('EnterpriseSignaturesTable not found');
const tableReturn = table.statement.body.statements.find(ts.isReturnStatement);
if (!tableReturn?.expression) throw new Error('EnterpriseSignaturesTable return expression not found');
if (
sha256(printer.printNode(ts.EmitHint.Unspecified, tableReturn.expression, table.file)) !==
manifest.tableJsxSha256
) {
throw new Error('Enterprise signatures table JSX changed during R4 extraction');
}
const page = load('src/apps/admin/AdminEnterpriseSignaturesPage.tsx');
const pageFunction = page.file.statements.find(
(statement) => ts.isFunctionDeclaration(statement) && statement.name?.text === 'AdminEnterpriseSignaturesPage',
);
if (!pageFunction || !ts.isFunctionDeclaration(pageFunction) || !pageFunction.body) {
throw new Error('AdminEnterpriseSignaturesPage container not found');
}
const pageText = pageFunction.getText(page.file);
for (const apiCall of manifest.apiCalls) {
if (!pageText.includes(`adminApi.${apiCall}`)) {
throw new Error(`R4 page container API coordination missing: ${apiCall}`);
}
}
for (const stateName of manifest.stateNames) {
if (!new RegExp(`\\b${stateName}\\b`).test(pageText)) {
throw new Error(`R4 page container state missing: ${stateName}`);
}
}
if (!pageText.includes('<EnterpriseSignaturesTable')) {
throw new Error('AdminEnterpriseSignaturesPage does not delegate table rendering');
}
if (page.source.split(/\r?\n/).length >= manifest.originalLines) {
throw new Error('AdminEnterpriseSignaturesPage was not reduced by R4 extraction');
}
for (const loaded of loadedFiles) {
if (loaded.source.split(/\r?\n/).length > 360) {
throw new Error(`${loaded.relativePath} exceeds the R4 component size boundary`);
}
}
console.log(
`R4 enterprise-signatures page verified: ${manifest.movedFunctions.length} functions, table JSX, ${manifest.apiCalls.length} real API calls and ${manifest.stateNames.length} page states preserved.`,
);