teste_docs / scripts /sync_mesa_documentacao.mjs
gui-sparim's picture
Publica gerador evolutivo e carrega modelos do repositório MESA
55d9355 verified
Raw History Blame Contribute Delete
5.13 kB
// Extrai os conteúdos compartilhados da MESA sem copiar definições manualmente.
import fs from 'node:fs';
import path from 'node:path';
import crypto from 'node:crypto';
import { createRequire } from 'node:module';
import { fileURLToPath } from 'node:url';
const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');
const mesa = path.resolve(process.argv[2] || path.join(root, '..', 'mesa-frame'));
const require = createRequire(path.join(mesa, 'frontend/package.json'));
const { parse } = require('@babel/parser');
const sources = {};
function ast(relative) {
const text = fs.readFileSync(path.join(mesa, relative), 'utf8');
sources[relative] = crypto.createHash('sha256').update(text).digest('hex');
return parse(text, { sourceType: 'module', plugins: ['jsx'] });
}
function walk(node, fn) {
if (!node || typeof node !== 'object') return;
fn(node);
for (const value of Object.values(node)) {
if (Array.isArray(value)) value.forEach((child) => walk(child, fn));
else if (value && typeof value === 'object') walk(value, fn);
}
}
function literal(node) {
if (['StringLiteral', 'NumericLiteral', 'BooleanLiteral'].includes(node?.type)) return node.value;
if (node?.type === 'NullLiteral') return null;
if (node?.type === 'ArrayExpression') return node.elements.map(literal);
if (node?.type === 'ObjectExpression') return Object.fromEntries(node.properties.map((prop) => [prop.key.name || prop.key.value, literal(prop.value)]));
if (node?.type === 'UnaryExpression' && node.operator === '-') return -literal(node.argument);
throw new Error(`Conteúdo não literal: ${node?.type}`);
}
function variable(tree, name) {
let result;
walk(tree, (node) => { if (node.type === 'VariableDeclarator' && node.id.name === name) result = node.init; });
if (!result) throw new Error(`Variável ausente na MESA: ${name}`);
return result;
}
const refs = ast('frontend/src/mqc/data/referenceData.js');
const notes = ast('frontend/src/mqc/wordExportOptions.js');
const norms = ast('frontend/src/components/NormativeReference.jsx');
const reducers = ast('frontend/src/components/RedutoresAvaliacaoModal.jsx');
const dep = ast('frontend/src/mqc/calculations.js');
const models = ast('frontend/src/modelFoundation.js');
const global = ast('frontend/src/globalFoundation.js');
const exports = ast('frontend/src/mqc/exporters.js');
const redutoresTermos = {};
walk(variable(reducers, 'memoriaCompleta'), (node) => {
if (node.type !== 'ObjectExpression') return;
const props = Object.fromEntries(node.properties.filter((p) => p.type === 'ObjectProperty').map((p) => [p.key.name || p.key.value, p.value]));
if (props.nome?.type === 'StringLiteral' && props.descricao?.type === 'StringLiteral') redutoresTermos[props.nome.value] = props.descricao.value;
});
const functions = {};
for (const name of ['calcularDepreciacao', 'calcularKd', 'calcularEnquadramento']) {
walk(dep, (node) => { if (node.type === 'FunctionDeclaration' && node.id.name === name) functions[name] = fs.readFileSync(path.join(mesa, 'frontend/src/mqc/calculations.js'), 'utf8').slice(node.start, node.end); });
}
const annotations = {};
walk(exports, (node) => { if (node.type === 'FunctionDeclaration' && ['wordCubTypeExplanation', 'wordMixExplanation', 'wordLifeAdjustmentExplanation'].includes(node.id.name)) annotations[node.id.name] = fs.readFileSync(path.join(mesa, 'frontend/src/mqc/exporters.js'), 'utf8').slice(node.start, node.end); });
const areaNotes = [];
walk(notes, (node) => {
if (node.type === 'FunctionDeclaration' && node.id.name === 'wordAreaHeaderNote') {
walk(node, (child) => { if (child.type === 'StringLiteral' && child.value.includes(': área')) areaNotes.push(child.value); });
}
});
// As fórmulas e critérios passam a ter a mesma origem do conteúdo da interface.
const catalog = {
versao: 1, fontes: sources,
notas: Object.fromEntries(literal(variable(notes, 'WORD_HEADER_NOTES'))),
notas_area: areaNotes,
referencias: Object.fromEntries(['bdiAdicionais', 'bdiTiposConstrucao', 'estadosConservacao', 'vidaUtilTipos', 'valorResidualReferencias', 'areaEquivalenteCoeficientes', 'siglasCub'].map((name) => [name, literal(variable(refs, name))])),
normas: literal(variable(norms, 'REFERENCES')),
redutores_termos: redutoresTermos,
funcoes_mqc: functions,
anotacoes_mqc: annotations,
criterios_fc: literal(variable(global, 'FC_FOUNDATION_OPTIONS')),
descricoes_modelo: literal(variable(models, 'MODEL_FOUNDATION_MANUAL_DESCRIPTIONS')),
requisitos_modelo: literal(variable(models, 'MODEL_FOUNDATION_REQUIREMENTS')),
};
const encoded = JSON.stringify(catalog);
catalog.identificador = crypto.createHash('sha256').update(encoded).digest('hex').slice(0, 16);
fs.writeFileSync(path.join(root, 'config/mesa_documentacao.json'), JSON.stringify(catalog, null, 2) + '\n');
// O mesmo pacote acompanha as novas exportações EVO para leitura histórica.
fs.writeFileSync(path.join(mesa, 'frontend/src/evolutivo/documentacaoTecnica.json'), JSON.stringify(catalog, null, 2) + '\n');
console.log(`Conteúdo técnico sincronizado da MESA: ${catalog.identificador}`);