89 lines
3.7 KiB
JavaScript
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.`,
|
|
);
|