feat: add phone frequency controls and modularize codebase
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
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.`,
|
||||
);
|
||||
Reference in New Issue
Block a user