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('= 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.`, );