@semacode/cli 1.4.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +2 -2
- package/README.md +1 -1
- package/dist/drift.d.ts +93 -1
- package/dist/drift.js +1376 -546
- package/dist/drift.js.map +1 -1
- package/dist/index.js +106 -9
- package/dist/index.js.map +1 -1
- package/docs/cli.md +1 -1
- package/docs/instalacao-e-primeiro-uso.md +7 -6
- package/docs/integracao-com-ia.md +6 -0
- package/docs/persistencia-vendor-first.md +1 -1
- package/node_modules/@sema/gerador-css/package.json +1 -1
- package/node_modules/@sema/gerador-dart/package.json +1 -1
- package/node_modules/@sema/gerador-html/package.json +1 -1
- package/node_modules/@sema/gerador-javascript/package.json +1 -1
- package/node_modules/@sema/gerador-lua/package.json +1 -1
- package/node_modules/@sema/gerador-python/package.json +1 -1
- package/node_modules/@sema/gerador-typescript/package.json +1 -1
- package/node_modules/@sema/nucleo/package.json +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- package/package.json +10 -10
package/dist/drift.js
CHANGED
|
@@ -8,7 +8,7 @@ import { extrairRotasJava, extrairSimbolosJava } from "./java-http.js";
|
|
|
8
8
|
import { contarIndentacaoPython, extrairRotasFlaskDecoradas, normalizarCaminhoFlask } from "./python-http.js";
|
|
9
9
|
import { extrairRotasRust, extrairSimbolosRust } from "./rust-http.js";
|
|
10
10
|
import { extrairRotasTypeScriptHttp } from "./typescript-http.js";
|
|
11
|
-
const
|
|
11
|
+
const DIRETORIOS_IGNORADOS_BASE = new Set([
|
|
12
12
|
".git",
|
|
13
13
|
".hg",
|
|
14
14
|
".svn",
|
|
@@ -25,9 +25,229 @@ const DIRETORIOS_IGNORADOS = new Set([
|
|
|
25
25
|
".tmp",
|
|
26
26
|
"generated",
|
|
27
27
|
]);
|
|
28
|
+
const DIRETORIOS_WORKTREE = [
|
|
29
|
+
".claude",
|
|
30
|
+
"worktrees",
|
|
31
|
+
];
|
|
32
|
+
const DIRETORIOS_CONSUMIDOR_LATERAL = [
|
|
33
|
+
"showcase",
|
|
34
|
+
"showcases",
|
|
35
|
+
"storybook",
|
|
36
|
+
"stories",
|
|
37
|
+
"playground",
|
|
38
|
+
"sandbox",
|
|
39
|
+
"fixture",
|
|
40
|
+
"fixtures",
|
|
41
|
+
"demo",
|
|
42
|
+
"demos",
|
|
43
|
+
"sample",
|
|
44
|
+
"samples",
|
|
45
|
+
"mini-web",
|
|
46
|
+
];
|
|
47
|
+
const TERMOS_ESCopo_IGNORADOS = new Set([
|
|
48
|
+
"api",
|
|
49
|
+
"app",
|
|
50
|
+
"apps",
|
|
51
|
+
"base",
|
|
52
|
+
"codigo",
|
|
53
|
+
"config",
|
|
54
|
+
"controller",
|
|
55
|
+
"controllers",
|
|
56
|
+
"data",
|
|
57
|
+
"drift",
|
|
58
|
+
"flow",
|
|
59
|
+
"module",
|
|
60
|
+
"modulo",
|
|
61
|
+
"publico",
|
|
62
|
+
"route",
|
|
63
|
+
"routes",
|
|
64
|
+
"schema",
|
|
65
|
+
"sema",
|
|
66
|
+
"service",
|
|
67
|
+
"services",
|
|
68
|
+
"src",
|
|
69
|
+
"task",
|
|
70
|
+
"tasks",
|
|
71
|
+
"tests",
|
|
72
|
+
"ui",
|
|
73
|
+
"web",
|
|
74
|
+
]);
|
|
75
|
+
let diretoriosIgnoradosAtivos = new Set(DIRETORIOS_IGNORADOS_BASE);
|
|
28
76
|
function normalizarFragmentoArquivo(valor) {
|
|
29
77
|
return valor.replace(/\\/g, "/").replace(/^\.?\//, "").trim().toLowerCase();
|
|
30
78
|
}
|
|
79
|
+
function normalizarEscopoDrift(valor) {
|
|
80
|
+
if (valor === "arquivo" || valor === "modulo" || valor === "projeto") {
|
|
81
|
+
return valor;
|
|
82
|
+
}
|
|
83
|
+
return "modulo";
|
|
84
|
+
}
|
|
85
|
+
function resolverOpcoesDrift(opcoes) {
|
|
86
|
+
return {
|
|
87
|
+
escopo: normalizarEscopoDrift(opcoes?.escopo),
|
|
88
|
+
ignorarWorktrees: opcoes?.ignorarWorktrees !== false,
|
|
89
|
+
ignorarConsumidoresLaterais: opcoes?.ignorarConsumidoresLaterais !== false,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function resolverDiretoriosIgnoradosAtivos(opcoes) {
|
|
93
|
+
const resolvidas = resolverOpcoesDrift(opcoes);
|
|
94
|
+
const diretorios = new Set(DIRETORIOS_IGNORADOS_BASE);
|
|
95
|
+
if (resolvidas.ignorarWorktrees) {
|
|
96
|
+
for (const diretorio of DIRETORIOS_WORKTREE) {
|
|
97
|
+
diretorios.add(diretorio);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
if (resolvidas.ignorarConsumidoresLaterais) {
|
|
101
|
+
for (const diretorio of DIRETORIOS_CONSUMIDOR_LATERAL) {
|
|
102
|
+
diretorios.add(diretorio);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return diretorios;
|
|
106
|
+
}
|
|
107
|
+
function quebrarTermosEscopo(valor) {
|
|
108
|
+
return paraIdentificadorModulo(valor)
|
|
109
|
+
.split("_")
|
|
110
|
+
.map((item) => item.trim())
|
|
111
|
+
.filter((item) => item.length >= 3 && !TERMOS_ESCopo_IGNORADOS.has(item));
|
|
112
|
+
}
|
|
113
|
+
function extrairTermosEscopoDrift(contexto, escopo) {
|
|
114
|
+
if (escopo === "projeto") {
|
|
115
|
+
return [];
|
|
116
|
+
}
|
|
117
|
+
const termos = new Set();
|
|
118
|
+
termos.add(paraIdentificadorModulo(path.basename(contexto.entradaResolvida, path.extname(contexto.entradaResolvida))));
|
|
119
|
+
for (const modulo of contexto.modulosSelecionados) {
|
|
120
|
+
const ir = modulo.resultado.ir;
|
|
121
|
+
if (!ir) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
for (const termo of quebrarTermosEscopo(ir.nome)) {
|
|
125
|
+
termos.add(termo);
|
|
126
|
+
}
|
|
127
|
+
for (const task of ir.tasks) {
|
|
128
|
+
for (const termo of quebrarTermosEscopo(task.nome)) {
|
|
129
|
+
termos.add(termo);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
for (const route of ir.routes) {
|
|
133
|
+
for (const termo of quebrarTermosEscopo(route.nome)) {
|
|
134
|
+
termos.add(termo);
|
|
135
|
+
}
|
|
136
|
+
if (route.caminho) {
|
|
137
|
+
for (const termo of quebrarTermosEscopo(route.caminho)) {
|
|
138
|
+
termos.add(termo);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return [...termos].filter(Boolean).sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
144
|
+
}
|
|
145
|
+
function caminhoTemSegmentoIgnorado(arquivo, segmentos) {
|
|
146
|
+
const partes = normalizarFragmentoArquivo(arquivo).split("/").filter(Boolean);
|
|
147
|
+
return partes.some((parte) => segmentos.includes(parte));
|
|
148
|
+
}
|
|
149
|
+
function normalizarCaminhoComparacao(caminhoArquivo) {
|
|
150
|
+
return path.resolve(caminhoArquivo).replace(/\\/g, "/").replace(/\/+$/, "").toLowerCase();
|
|
151
|
+
}
|
|
152
|
+
function caminhoEstaDentroDe(base, alvo) {
|
|
153
|
+
const baseNormalizada = normalizarCaminhoComparacao(base);
|
|
154
|
+
const alvoNormalizado = normalizarCaminhoComparacao(alvo);
|
|
155
|
+
return alvoNormalizado === baseNormalizada || alvoNormalizado.startsWith(`${baseNormalizada}/`);
|
|
156
|
+
}
|
|
157
|
+
function resolverRaizEscopoReal(contexto) {
|
|
158
|
+
const entrada = path.resolve(contexto.entradaResolvida);
|
|
159
|
+
return path.extname(entrada) ? path.dirname(entrada) : entrada;
|
|
160
|
+
}
|
|
161
|
+
function resolverRaizesExplicitasConfiguradas(contexto) {
|
|
162
|
+
const configCarregada = contexto.configCarregada;
|
|
163
|
+
if (!configCarregada) {
|
|
164
|
+
return [];
|
|
165
|
+
}
|
|
166
|
+
const origensDeclaradas = configCarregada.config.origens ?? (configCarregada.config.origem ? [configCarregada.config.origem] : []);
|
|
167
|
+
return [...new Set([
|
|
168
|
+
...(configCarregada.config.diretoriosCodigo ?? []).map((diretorio) => path.resolve(configCarregada.baseDiretorio, diretorio)),
|
|
169
|
+
...origensDeclaradas.map((origem) => path.resolve(configCarregada.baseDiretorio, origem)),
|
|
170
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
171
|
+
}
|
|
172
|
+
function resolverRaizesIgnoradasPermitidas(contexto, segmentosIgnorados) {
|
|
173
|
+
return [...new Set([
|
|
174
|
+
resolverRaizEscopoReal(contexto),
|
|
175
|
+
...resolverRaizesExplicitasConfiguradas(contexto),
|
|
176
|
+
])]
|
|
177
|
+
.filter((raiz) => caminhoTemSegmentoIgnorado(raiz, segmentosIgnorados))
|
|
178
|
+
.sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
179
|
+
}
|
|
180
|
+
function caminhoIgnoradoForaDoEscopoReal(caminhoArquivo, segmentosIgnorados, raizesPermitidas) {
|
|
181
|
+
if (!caminhoTemSegmentoIgnorado(caminhoArquivo, segmentosIgnorados)) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
184
|
+
if (raizesPermitidas.length === 0) {
|
|
185
|
+
return true;
|
|
186
|
+
}
|
|
187
|
+
return !raizesPermitidas.some((raiz) => caminhoEstaDentroDe(raiz, caminhoArquivo));
|
|
188
|
+
}
|
|
189
|
+
function filtrarCaminhosEscopoReal(caminhos, contexto, configuracao) {
|
|
190
|
+
const raizesWorktreePermitidas = resolverRaizesIgnoradasPermitidas(contexto, DIRETORIOS_WORKTREE);
|
|
191
|
+
const raizesConsumidorPermitidas = resolverRaizesIgnoradasPermitidas(contexto, DIRETORIOS_CONSUMIDOR_LATERAL);
|
|
192
|
+
return caminhos.filter((caminho) => {
|
|
193
|
+
if (configuracao.ignorarWorktrees && caminhoIgnoradoForaDoEscopoReal(caminho, DIRETORIOS_WORKTREE, raizesWorktreePermitidas)) {
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
if (configuracao.ignorarConsumidoresLaterais
|
|
197
|
+
&& caminhoIgnoradoForaDoEscopoReal(caminho, DIRETORIOS_CONSUMIDOR_LATERAL, raizesConsumidorPermitidas)) {
|
|
198
|
+
return false;
|
|
199
|
+
}
|
|
200
|
+
return true;
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
function resolverDiretoriosCodigoEscopoReal(contexto, configuracao) {
|
|
204
|
+
return filtrarCaminhosEscopoReal(contexto.diretoriosCodigo, contexto, configuracao);
|
|
205
|
+
}
|
|
206
|
+
function textoCombinaEscopo(texto, termos) {
|
|
207
|
+
if (termos.length === 0) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
const normalizado = paraIdentificadorModulo(texto);
|
|
211
|
+
return termos.some((termo) => normalizado.includes(termo));
|
|
212
|
+
}
|
|
213
|
+
function filtrarConsumerSurfacesPorEscopo(consumerSurfaces, consumerBridges, contexto, configuracao) {
|
|
214
|
+
const raizesWorktreePermitidas = resolverRaizesIgnoradasPermitidas(contexto, DIRETORIOS_WORKTREE);
|
|
215
|
+
const raizesConsumidorPermitidas = resolverRaizesIgnoradasPermitidas(contexto, DIRETORIOS_CONSUMIDOR_LATERAL);
|
|
216
|
+
const manterSurface = (surface) => {
|
|
217
|
+
if (configuracao.ignorarWorktrees
|
|
218
|
+
&& caminhoIgnoradoForaDoEscopoReal(surface.arquivo, DIRETORIOS_WORKTREE, raizesWorktreePermitidas)) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
if (configuracao.ignorarConsumidoresLaterais
|
|
222
|
+
&& caminhoIgnoradoForaDoEscopoReal(surface.arquivo, DIRETORIOS_CONSUMIDOR_LATERAL, raizesConsumidorPermitidas)) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
const combinaEscopo = textoCombinaEscopo(`${surface.rota} ${surface.arquivo} ${surface.tipoArquivo}`, configuracao.termosEscopo);
|
|
226
|
+
if (!configuracao.ignorarConsumidoresLaterais) {
|
|
227
|
+
return combinaEscopo || configuracao.escopo === "projeto";
|
|
228
|
+
}
|
|
229
|
+
return configuracao.escopo === "projeto" ? true : combinaEscopo;
|
|
230
|
+
};
|
|
231
|
+
const manterBridge = (bridge) => {
|
|
232
|
+
if (configuracao.ignorarWorktrees
|
|
233
|
+
&& caminhoIgnoradoForaDoEscopoReal(bridge.arquivo, DIRETORIOS_WORKTREE, raizesWorktreePermitidas)) {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
if (configuracao.ignorarConsumidoresLaterais
|
|
237
|
+
&& caminhoIgnoradoForaDoEscopoReal(bridge.arquivo, DIRETORIOS_CONSUMIDOR_LATERAL, raizesConsumidorPermitidas)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
const combinaEscopo = textoCombinaEscopo(`${bridge.caminho} ${bridge.arquivo} ${bridge.simbolo}`, configuracao.termosEscopo);
|
|
241
|
+
if (!configuracao.ignorarConsumidoresLaterais) {
|
|
242
|
+
return combinaEscopo || configuracao.escopo === "projeto";
|
|
243
|
+
}
|
|
244
|
+
return configuracao.escopo === "projeto" ? true : combinaEscopo;
|
|
245
|
+
};
|
|
246
|
+
return {
|
|
247
|
+
consumerSurfaces: consumerSurfaces.filter(manterSurface),
|
|
248
|
+
consumerBridges: consumerBridges.filter(manterBridge),
|
|
249
|
+
};
|
|
250
|
+
}
|
|
31
251
|
const NOMES_RECURSO_IGNORADOS = new Set([
|
|
32
252
|
"all",
|
|
33
253
|
"and",
|
|
@@ -544,14 +764,35 @@ function resumirOperacional(resultado) {
|
|
|
544
764
|
? Math.round(resultado.tasks.reduce((total, task) => total + task.scoreSemantico, 0) / resultado.tasks.length)
|
|
545
765
|
: 0;
|
|
546
766
|
const confiancaGeral = scoreMedio >= 80 ? "alta" : scoreMedio >= 55 ? "media" : "baixa";
|
|
547
|
-
const riscosPrincipais = [...new Set(
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
767
|
+
const riscosPrincipais = [...new Set([
|
|
768
|
+
...resultado.tasks.filter((task) => task.riscoOperacional !== "baixo").map((task) => `${task.task}:${task.riscoOperacional}`),
|
|
769
|
+
...resultado.persistencia_real
|
|
770
|
+
.filter((item) => item.status !== "materializado")
|
|
771
|
+
.map((item) => `${item.task}:${item.alvo}:persistencia_${item.status}`),
|
|
772
|
+
])];
|
|
773
|
+
const oQueTocar = [...new Set([
|
|
774
|
+
...resultado.tasks.flatMap((task) => task.arquivosProvaveisEditar),
|
|
775
|
+
...resultado.persistencia_real.flatMap((item) => [...item.arquivos, ...item.repositorios]),
|
|
776
|
+
])].slice(0, 20);
|
|
777
|
+
const oQueValidar = [...new Set([
|
|
778
|
+
...resultado.tasks.flatMap((task) => task.checksSugeridos),
|
|
779
|
+
...resultado.persistencia_real
|
|
780
|
+
.filter((item) => item.status !== "materializado")
|
|
781
|
+
.map((item) => `validar persistencia real de ${item.task} em ${item.alvo}`),
|
|
782
|
+
])];
|
|
783
|
+
const oQueEstaFrouxo = [...new Set([
|
|
784
|
+
...resultado.tasks.flatMap((task) => task.lacunas),
|
|
785
|
+
...resultado.persistencia_real
|
|
786
|
+
.filter((item) => item.status !== "materializado" || item.compatibilidade === "desconhecida" || item.compatibilidade === "invalido")
|
|
787
|
+
.map((item) => `persistencia:${item.alvo}:${item.status}:${item.compatibilidade}`),
|
|
788
|
+
])];
|
|
551
789
|
const oQueFoiInferido = [
|
|
552
790
|
...new Set([
|
|
553
791
|
...resultado.impls_quebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.caminho) ?? []),
|
|
554
792
|
...resultado.vinculos_quebrados.filter((vinculo) => vinculo.status === "parcial").map((vinculo) => `${vinculo.dono}:${vinculo.valor}`),
|
|
793
|
+
...resultado.persistencia_real
|
|
794
|
+
.filter((item) => item.compatibilidade === "desconhecida")
|
|
795
|
+
.map((item) => `${item.task}:${item.alvo}:compatibilidade_nao_confirmada`),
|
|
555
796
|
]),
|
|
556
797
|
];
|
|
557
798
|
return {
|
|
@@ -620,7 +861,7 @@ async function listarArquivosRecursivos(diretorio, extensoes) {
|
|
|
620
861
|
}
|
|
621
862
|
const encontrados = [];
|
|
622
863
|
for (const entrada of entradas) {
|
|
623
|
-
if (
|
|
864
|
+
if (diretoriosIgnoradosAtivos.has(entrada.name.toLowerCase())) {
|
|
624
865
|
continue;
|
|
625
866
|
}
|
|
626
867
|
const caminhoAtual = path.join(diretorio, entrada.name);
|
|
@@ -1529,6 +1770,273 @@ async function indexarPersistenciaDeclarativa(diretorios) {
|
|
|
1529
1770
|
}
|
|
1530
1771
|
return { recursos: [...recursos.values()] };
|
|
1531
1772
|
}
|
|
1773
|
+
function normalizarOrigemParaEngine(origem) {
|
|
1774
|
+
return origem && origem !== "firebase" ? origem : undefined;
|
|
1775
|
+
}
|
|
1776
|
+
function registrarColunaPersistenciaDrift(colunas, engine, recurso, coluna, arquivo) {
|
|
1777
|
+
const recursoNormalizado = fecharPrefixoRecurso(limparLiteralRecurso(recurso));
|
|
1778
|
+
const colunaNormalizada = fecharPrefixoRecurso(limparLiteralRecurso(coluna));
|
|
1779
|
+
if (!recursoNormalizado || !colunaNormalizada || recursoEhIgnorado(colunaNormalizada)) {
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
const chave = `${engine}:${normalizarNomeRecursoDrift(recursoNormalizado)}:${normalizarNomeRecursoDrift(colunaNormalizada)}:${arquivo}`;
|
|
1783
|
+
if (!colunas.has(chave)) {
|
|
1784
|
+
colunas.set(chave, {
|
|
1785
|
+
engine,
|
|
1786
|
+
recurso: recursoNormalizado,
|
|
1787
|
+
coluna: colunaNormalizada,
|
|
1788
|
+
arquivo,
|
|
1789
|
+
});
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
function registrarRepositorioPersistenciaDrift(repositorios, engine, recurso, arquivo) {
|
|
1793
|
+
const recursoNormalizado = fecharPrefixoRecurso(limparLiteralRecurso(recurso));
|
|
1794
|
+
if (!recursoNormalizado) {
|
|
1795
|
+
return;
|
|
1796
|
+
}
|
|
1797
|
+
const chave = `${engine}:${normalizarNomeRecursoDrift(recursoNormalizado)}:${arquivo}`;
|
|
1798
|
+
if (!repositorios.has(chave)) {
|
|
1799
|
+
repositorios.set(chave, {
|
|
1800
|
+
engine,
|
|
1801
|
+
recurso: recursoNormalizado,
|
|
1802
|
+
arquivo,
|
|
1803
|
+
});
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
function extrairColunasSqlDetalhadas(arquivo, codigo) {
|
|
1807
|
+
const colunas = new Map();
|
|
1808
|
+
const motores = inferirMotoresRelacionais(codigo, arquivo);
|
|
1809
|
+
if (motores.length === 0) {
|
|
1810
|
+
return [];
|
|
1811
|
+
}
|
|
1812
|
+
const registrarParaMotores = (recurso, coluna) => {
|
|
1813
|
+
for (const motor of motores) {
|
|
1814
|
+
registrarColunaPersistenciaDrift(colunas, motor, recurso, coluna, arquivo);
|
|
1815
|
+
}
|
|
1816
|
+
};
|
|
1817
|
+
for (const match of codigo.matchAll(/\bcreate\s+table\s+(?:if\s+not\s+exists\s+)?["'`]?([A-Za-z_][\w$.-]*)["'`]?\s*\(([\s\S]*?)\)\s*;?/gi)) {
|
|
1818
|
+
const tabela = match[1];
|
|
1819
|
+
const corpo = match[2] ?? "";
|
|
1820
|
+
for (const linha of corpo.split(/\r?\n|,/)) {
|
|
1821
|
+
const trecho = linha.trim();
|
|
1822
|
+
if (!trecho || /^(?:constraint|primary|foreign|unique|check|key|index)\b/i.test(trecho)) {
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
const coluna = trecho.match(/^["'`]?([A-Za-z_][\w$.-]*)["'`]?/i)?.[1];
|
|
1826
|
+
if (coluna) {
|
|
1827
|
+
registrarParaMotores(tabela, coluna);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
for (const match of codigo.matchAll(/\binsert\s+into\s+["'`]?([A-Za-z_][\w$.-]*)["'`]?\s*\(([^)]+)\)/gi)) {
|
|
1832
|
+
for (const coluna of (match[2] ?? "").split(",").map((item) => item.trim())) {
|
|
1833
|
+
registrarParaMotores(match[1], coluna);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
for (const match of codigo.matchAll(/\bupdate\s+["'`]?([A-Za-z_][\w$.-]*)["'`]?\s+set\s+([\s\S]*?)(?:\bwhere\b|;|$)/gi)) {
|
|
1837
|
+
for (const coluna of (match[2] ?? "").split(",").map((item) => item.split("=")[0]?.trim() ?? "")) {
|
|
1838
|
+
registrarParaMotores(match[1], coluna);
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
for (const match of codigo.matchAll(/\bselect\s+([\s\S]*?)\s+from\s+["'`]?([A-Za-z_][\w$.-]*)["'`]?/gi)) {
|
|
1842
|
+
const tabela = match[2];
|
|
1843
|
+
const lista = (match[1] ?? "").trim();
|
|
1844
|
+
if (!lista || lista === "*") {
|
|
1845
|
+
continue;
|
|
1846
|
+
}
|
|
1847
|
+
for (const coluna of lista.split(",").map((item) => item.trim().split(/\s+as\s+/i)[0] ?? "")) {
|
|
1848
|
+
const nome = coluna.split(".").at(-1) ?? coluna;
|
|
1849
|
+
registrarParaMotores(tabela, nome);
|
|
1850
|
+
}
|
|
1851
|
+
}
|
|
1852
|
+
return [...colunas.values()];
|
|
1853
|
+
}
|
|
1854
|
+
function extrairColunasPrismaDetalhadas(arquivo, codigo) {
|
|
1855
|
+
const colunas = new Map();
|
|
1856
|
+
const provider = codigo.match(/\bprovider\s*=\s*["'`](postgresql|mysql|sqlite)["'`]/i)?.[1]?.toLowerCase();
|
|
1857
|
+
const engine = provider === "postgresql"
|
|
1858
|
+
? "postgres"
|
|
1859
|
+
: provider === "mysql"
|
|
1860
|
+
? "mysql"
|
|
1861
|
+
: provider === "sqlite"
|
|
1862
|
+
? "sqlite"
|
|
1863
|
+
: undefined;
|
|
1864
|
+
if (!engine) {
|
|
1865
|
+
return [];
|
|
1866
|
+
}
|
|
1867
|
+
for (const match of codigo.matchAll(/\bmodel\s+([A-Za-z_]\w*)\s*\{([\s\S]*?)\n\}/g)) {
|
|
1868
|
+
const nomeModelo = match[1];
|
|
1869
|
+
const corpo = match[2] ?? "";
|
|
1870
|
+
const tabela = corpo.match(/@@map\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/)?.[1] ?? nomeModelo;
|
|
1871
|
+
for (const linha of corpo.split(/\r?\n/)) {
|
|
1872
|
+
const limpa = linha.trim();
|
|
1873
|
+
if (!limpa || limpa.startsWith("@@") || limpa.startsWith("//")) {
|
|
1874
|
+
continue;
|
|
1875
|
+
}
|
|
1876
|
+
const coluna = limpa.match(/^([A-Za-z_]\w*)\s+/)?.[1];
|
|
1877
|
+
const colunaMapeada = limpa.match(/@map\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/)?.[1];
|
|
1878
|
+
if (coluna) {
|
|
1879
|
+
registrarColunaPersistenciaDrift(colunas, engine, tabela, colunaMapeada ?? coluna, arquivo);
|
|
1880
|
+
}
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
return [...colunas.values()];
|
|
1884
|
+
}
|
|
1885
|
+
function extrairCamposMongoDetalhados(arquivo, codigo) {
|
|
1886
|
+
const colunas = new Map();
|
|
1887
|
+
const colecoes = extrairRecursosMongoDb(arquivo, codigo).filter((item) => item.tipo === "collection");
|
|
1888
|
+
if (colecoes.length === 0) {
|
|
1889
|
+
return [];
|
|
1890
|
+
}
|
|
1891
|
+
const registrarCampoMongo = (colecao, trecho) => {
|
|
1892
|
+
for (const match of trecho.matchAll(/([A-Za-z_][\w$]*)\s*:/g)) {
|
|
1893
|
+
registrarColunaPersistenciaDrift(colunas, "mongodb", colecao, match[1], arquivo);
|
|
1894
|
+
}
|
|
1895
|
+
};
|
|
1896
|
+
for (const schema of codigo.matchAll(/\bnew\s+Schema\s*\(\s*\{([\s\S]*?)\}\s*\)/g)) {
|
|
1897
|
+
for (const colecao of colecoes) {
|
|
1898
|
+
registrarCampoMongo(colecao.nome, schema[1] ?? "");
|
|
1899
|
+
}
|
|
1900
|
+
}
|
|
1901
|
+
for (const trecho of codigo.matchAll(/\b(?:find(?:One)?|update(?:One|Many)?|insertOne|insertMany)\s*\(\s*\{([\s\S]*?)\}\s*(?:,|\))/g)) {
|
|
1902
|
+
for (const colecao of colecoes) {
|
|
1903
|
+
registrarCampoMongo(colecao.nome, trecho[1] ?? "");
|
|
1904
|
+
}
|
|
1905
|
+
}
|
|
1906
|
+
return [...colunas.values()];
|
|
1907
|
+
}
|
|
1908
|
+
function extrairCamposRedisDetalhados(arquivo, codigo) {
|
|
1909
|
+
const colunas = new Map();
|
|
1910
|
+
for (const match of codigo.matchAll(/\bh(?:set|get|del|exists)\s*\(\s*["'`]([^"'`]+)["'`]\s*,\s*["'`]([^"'`]+)["'`]/gi)) {
|
|
1911
|
+
registrarColunaPersistenciaDrift(colunas, "redis", match[1], match[2], arquivo);
|
|
1912
|
+
}
|
|
1913
|
+
return [...colunas.values()];
|
|
1914
|
+
}
|
|
1915
|
+
function registrarRepositoriosPorRecursos(repositorios, arquivo, codigo, recursos) {
|
|
1916
|
+
const contextoRepositorio = /(?:repository|repositories|repositorio|repositorios|repo|dao|store|queries|persistence|persistencia)/i.test(arquivo)
|
|
1917
|
+
|| /\b(?:Repository|Repositories|Dao|Store)\b/.test(codigo);
|
|
1918
|
+
const contextoAcesso = /\b(?:select|insert|update|delete|aggregate|findOne|findMany|findUnique|findFirst|prisma\.|db\.collection|createClient|hset|hget|xadd|xread)\b/i.test(codigo);
|
|
1919
|
+
if (!contextoRepositorio && !contextoAcesso) {
|
|
1920
|
+
return;
|
|
1921
|
+
}
|
|
1922
|
+
for (const recurso of recursos) {
|
|
1923
|
+
const engine = normalizarOrigemParaEngine(recurso.origem);
|
|
1924
|
+
if (!engine) {
|
|
1925
|
+
continue;
|
|
1926
|
+
}
|
|
1927
|
+
registrarRepositorioPersistenciaDrift(repositorios, engine, recurso.nome, arquivo);
|
|
1928
|
+
}
|
|
1929
|
+
}
|
|
1930
|
+
async function indexarPersistenciaDetalhada(diretorios) {
|
|
1931
|
+
const colunas = new Map();
|
|
1932
|
+
const repositorios = new Map();
|
|
1933
|
+
for (const diretorio of diretorios) {
|
|
1934
|
+
const arquivos = await listarArquivosRecursivos(diretorio, [
|
|
1935
|
+
".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
|
|
1936
|
+
".py", ".dart", ".cs", ".java", ".go", ".rs", ".cpp", ".cc", ".cxx", ".hpp", ".h",
|
|
1937
|
+
".sql", ".psql", ".ddl", ".prisma",
|
|
1938
|
+
]);
|
|
1939
|
+
for (const arquivo of arquivos) {
|
|
1940
|
+
const codigo = await readFile(arquivo, "utf8");
|
|
1941
|
+
const recursos = arquivo.endsWith(".prisma")
|
|
1942
|
+
? extrairRecursosPrisma(arquivo, codigo)
|
|
1943
|
+
: extrairRecursosPersistenciaCodigoVivo(arquivo, codigo);
|
|
1944
|
+
for (const coluna of extrairColunasSqlDetalhadas(arquivo, codigo)) {
|
|
1945
|
+
registrarColunaPersistenciaDrift(colunas, coluna.engine, coluna.recurso, coluna.coluna, coluna.arquivo);
|
|
1946
|
+
}
|
|
1947
|
+
for (const coluna of extrairColunasPrismaDetalhadas(arquivo, codigo)) {
|
|
1948
|
+
registrarColunaPersistenciaDrift(colunas, coluna.engine, coluna.recurso, coluna.coluna, coluna.arquivo);
|
|
1949
|
+
}
|
|
1950
|
+
for (const coluna of extrairCamposMongoDetalhados(arquivo, codigo)) {
|
|
1951
|
+
registrarColunaPersistenciaDrift(colunas, coluna.engine, coluna.recurso, coluna.coluna, coluna.arquivo);
|
|
1952
|
+
}
|
|
1953
|
+
for (const coluna of extrairCamposRedisDetalhados(arquivo, codigo)) {
|
|
1954
|
+
registrarColunaPersistenciaDrift(colunas, coluna.engine, coluna.recurso, coluna.coluna, coluna.arquivo);
|
|
1955
|
+
}
|
|
1956
|
+
registrarRepositoriosPorRecursos(repositorios, arquivo, codigo, recursos);
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
return {
|
|
1960
|
+
colunas: [...colunas.values()],
|
|
1961
|
+
repositorios: [...repositorios.values()],
|
|
1962
|
+
};
|
|
1963
|
+
}
|
|
1964
|
+
function recursoDetalhadoCombina(recurso, esperado) {
|
|
1965
|
+
return variantesNomeRecursoDrift(recurso).some((variante) => esperado.nomes.some((nome) => variantesNomeRecursoDrift(nome).includes(variante)));
|
|
1966
|
+
}
|
|
1967
|
+
function localizarCompatibilidadePersistencia(bancos, esperado, recursoReal) {
|
|
1968
|
+
for (const banco of bancos) {
|
|
1969
|
+
for (const recurso of banco.resources) {
|
|
1970
|
+
if (!recursoPersistenciaCombinaAlvo(recurso, esperado.alvo)) {
|
|
1971
|
+
continue;
|
|
1972
|
+
}
|
|
1973
|
+
const engine = banco.engine ?? normalizarOrigemParaEngine(recursoReal?.origem);
|
|
1974
|
+
const compatibilidade = engine
|
|
1975
|
+
? recurso.compatibilidade.find((item) => item.engine === engine) ?? recurso.compatibilidade[0]
|
|
1976
|
+
: recurso.compatibilidade[0];
|
|
1977
|
+
return {
|
|
1978
|
+
engine: (engine ?? recursoReal?.origem ?? "desconhecido"),
|
|
1979
|
+
compatibilidade: compatibilidade?.status ?? "desconhecida",
|
|
1980
|
+
motivoCompatibilidade: compatibilidade?.motivo,
|
|
1981
|
+
tipo: recurso.resourceKind ?? recursoReal?.tipo ?? esperado.tiposAceitos[0] ?? "query",
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
}
|
|
1985
|
+
return {
|
|
1986
|
+
engine: recursoReal?.origem ?? esperado.origem ?? "desconhecido",
|
|
1987
|
+
compatibilidade: "desconhecida",
|
|
1988
|
+
tipo: recursoReal?.tipo ?? esperado.tiposAceitos[0] ?? "query",
|
|
1989
|
+
};
|
|
1990
|
+
}
|
|
1991
|
+
export async function analisarPersistenciaReal(contexto, mapaRecursos, detalhesPersistencia, opcoes) {
|
|
1992
|
+
const opcoesResolvidas = resolverOpcoesDrift(opcoes);
|
|
1993
|
+
const diretoriosCodigoAtivos = resolverDiretoriosCodigoEscopoReal(contexto, opcoesResolvidas);
|
|
1994
|
+
const mapa = mapaRecursos ?? construirMapaRecursos((await indexarPersistenciaDeclarativa(diretoriosCodigoAtivos)).recursos);
|
|
1995
|
+
const detalhes = detalhesPersistencia ?? await indexarPersistenciaDetalhada(diretoriosCodigoAtivos);
|
|
1996
|
+
const registros = [];
|
|
1997
|
+
for (const item of contexto.modulosSelecionados) {
|
|
1998
|
+
const ir = item.resultado.ir;
|
|
1999
|
+
if (!ir) {
|
|
2000
|
+
continue;
|
|
2001
|
+
}
|
|
2002
|
+
for (const task of ir.tasks) {
|
|
2003
|
+
for (const esperado of extrairRecursosEsperados(task, ir)) {
|
|
2004
|
+
const correspondencias = esperado.nomes.flatMap((nome) => variantesNomeRecursoDrift(nome).flatMap((variante) => (mapa.get(variante) ?? []).filter((recurso) => recursoResolvidoCombinaEsperado(recurso, esperado))));
|
|
2005
|
+
const recursosReais = [...new Map(correspondencias.map((recurso) => [`${recurso.origem}:${recurso.tipo}:${recurso.nome}:${recurso.arquivo}`, recurso])).values()];
|
|
2006
|
+
const compatibilidade = localizarCompatibilidadePersistencia(ir.databases, esperado, recursosReais[0]);
|
|
2007
|
+
const colunas = [...new Set(detalhes.colunas
|
|
2008
|
+
.filter((coluna) => (!normalizarOrigemParaEngine(recursosReais[0]?.origem) || coluna.engine === normalizarOrigemParaEngine(recursosReais[0]?.origem))
|
|
2009
|
+
&& recursoDetalhadoCombina(coluna.recurso, esperado))
|
|
2010
|
+
.map((coluna) => coluna.coluna))].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2011
|
+
const repositorios = [...new Set(detalhes.repositorios
|
|
2012
|
+
.filter((repositorio) => (!normalizarOrigemParaEngine(recursosReais[0]?.origem) || repositorio.engine === normalizarOrigemParaEngine(recursosReais[0]?.origem))
|
|
2013
|
+
&& recursoDetalhadoCombina(repositorio.recurso, esperado))
|
|
2014
|
+
.map((repositorio) => repositorio.arquivo))].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2015
|
+
const arquivos = [...new Set(recursosReais.map((recurso) => recurso.arquivo))].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2016
|
+
registros.push({
|
|
2017
|
+
modulo: ir.nome,
|
|
2018
|
+
task: task.nome,
|
|
2019
|
+
alvo: esperado.alvo,
|
|
2020
|
+
engine: compatibilidade.engine,
|
|
2021
|
+
tipo: compatibilidade.tipo,
|
|
2022
|
+
status: recursosReais.length === 0
|
|
2023
|
+
? "divergente"
|
|
2024
|
+
: colunas.length > 0 || repositorios.length > 0
|
|
2025
|
+
? "materializado"
|
|
2026
|
+
: "parcial",
|
|
2027
|
+
arquivos,
|
|
2028
|
+
colunas,
|
|
2029
|
+
repositorios,
|
|
2030
|
+
compatibilidade: compatibilidade.compatibilidade,
|
|
2031
|
+
motivoCompatibilidade: compatibilidade.motivoCompatibilidade,
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
}
|
|
2035
|
+
}
|
|
2036
|
+
return registros.sort((a, b) => a.modulo.localeCompare(b.modulo, "pt-BR")
|
|
2037
|
+
|| a.task.localeCompare(b.task, "pt-BR")
|
|
2038
|
+
|| a.alvo.localeCompare(b.alvo, "pt-BR"));
|
|
2039
|
+
}
|
|
1532
2040
|
function normalizarCaminhoRota(caminho) {
|
|
1533
2041
|
if (!caminho) {
|
|
1534
2042
|
return "/";
|
|
@@ -1844,598 +2352,920 @@ function coletarVinculosIr(ir) {
|
|
|
1844
2352
|
...ir.superficies.flatMap((superficie) => superficie.vinculos.map((vinculo) => ({ donoTipo: "superficie", dono: `${superficie.tipo}:${superficie.nome}`, vinculo }))),
|
|
1845
2353
|
];
|
|
1846
2354
|
}
|
|
1847
|
-
export async function analisarDriftLegado(contexto) {
|
|
1848
|
-
const
|
|
1849
|
-
const
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
const
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
const
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
const
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
forbidden: task.forbidden.explicita,
|
|
1931
|
-
dadosSensiveis: Boolean(task.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(task.dados.classificacaoPadrao)
|
|
1932
|
-
|| task.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao))),
|
|
1933
|
-
efeitoPrivilegiado: task.efeitosEstruturados.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
|
|
1934
|
-
|| ["alta", "critica"].includes(efeito.criticidade ?? "")),
|
|
1935
|
-
exigeSegredos: task.efeitosEstruturados.some((efeito) => efeito.categoria === "secret.read")
|
|
1936
|
-
|| Boolean(task.dados.classificacaoPadrao && ["credencial", "segredo"].includes(task.dados.classificacaoPadrao)
|
|
1937
|
-
|| task.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao))),
|
|
1938
|
-
});
|
|
1939
|
-
}
|
|
1940
|
-
for (const route of ir.routes) {
|
|
1941
|
-
if (!route.task || route.perfilCompatibilidade !== "publico") {
|
|
2355
|
+
export async function analisarDriftLegado(contexto, opcoes) {
|
|
2356
|
+
const opcoesResolvidas = resolverOpcoesDrift(opcoes);
|
|
2357
|
+
const configuracaoEscopo = {
|
|
2358
|
+
escopo: opcoesResolvidas.escopo,
|
|
2359
|
+
ignorarWorktrees: opcoesResolvidas.ignorarWorktrees,
|
|
2360
|
+
ignorarConsumidoresLaterais: opcoesResolvidas.ignorarConsumidoresLaterais,
|
|
2361
|
+
termosEscopo: extrairTermosEscopoDrift(contexto, opcoesResolvidas.escopo),
|
|
2362
|
+
};
|
|
2363
|
+
const diretoriosIgnoradosAnteriores = diretoriosIgnoradosAtivos;
|
|
2364
|
+
diretoriosIgnoradosAtivos = resolverDiretoriosIgnoradosAtivos(opcoesResolvidas);
|
|
2365
|
+
try {
|
|
2366
|
+
const diretoriosCodigoAtivos = resolverDiretoriosCodigoEscopoReal(contexto, configuracaoEscopo);
|
|
2367
|
+
const indexTs = await indexarTypeScript(diretoriosCodigoAtivos);
|
|
2368
|
+
const indexPy = await indexarPython(diretoriosCodigoAtivos);
|
|
2369
|
+
const indexDart = await indexarDart(diretoriosCodigoAtivos);
|
|
2370
|
+
const indexDotnet = await indexarDotnet(diretoriosCodigoAtivos);
|
|
2371
|
+
const indexJava = await indexarJava(diretoriosCodigoAtivos);
|
|
2372
|
+
const indexGo = await indexarGo(diretoriosCodigoAtivos);
|
|
2373
|
+
const indexRust = await indexarRust(diretoriosCodigoAtivos);
|
|
2374
|
+
const indexPersistencia = await indexarPersistenciaDeclarativa(diretoriosCodigoAtivos);
|
|
2375
|
+
const detalhesPersistencia = await indexarPersistenciaDetalhada(diretoriosCodigoAtivos);
|
|
2376
|
+
const indexCpp = await indexarCpp(diretoriosCodigoAtivos);
|
|
2377
|
+
const todosSimbolos = [
|
|
2378
|
+
...indexTs.simbolos,
|
|
2379
|
+
...indexPy.simbolos,
|
|
2380
|
+
...indexDart.simbolos,
|
|
2381
|
+
...indexDotnet.simbolos,
|
|
2382
|
+
...indexJava.simbolos,
|
|
2383
|
+
...indexGo.simbolos,
|
|
2384
|
+
...indexRust.simbolos,
|
|
2385
|
+
...indexCpp.simbolos,
|
|
2386
|
+
];
|
|
2387
|
+
const mapaImpl = new Map([
|
|
2388
|
+
...indexTs.simbolos.map((item) => [item.caminho, item]),
|
|
2389
|
+
...indexPy.simbolos.map((item) => [item.caminho, item]),
|
|
2390
|
+
...indexDart.simbolos.map((item) => [item.caminho, item]),
|
|
2391
|
+
...indexDotnet.simbolos.map((item) => [item.caminho, item]),
|
|
2392
|
+
...indexJava.simbolos.map((item) => [item.caminho, item]),
|
|
2393
|
+
...indexGo.simbolos.map((item) => [item.caminho, item]),
|
|
2394
|
+
...indexRust.simbolos.map((item) => [item.caminho, item]),
|
|
2395
|
+
...indexCpp.simbolos.map((item) => [item.caminho, item]),
|
|
2396
|
+
]);
|
|
2397
|
+
const todosRecursos = [
|
|
2398
|
+
...indexTs.recursos,
|
|
2399
|
+
...indexPy.recursos,
|
|
2400
|
+
...indexDart.recursos,
|
|
2401
|
+
...indexDotnet.recursos,
|
|
2402
|
+
...indexJava.recursos,
|
|
2403
|
+
...indexGo.recursos,
|
|
2404
|
+
...indexRust.recursos,
|
|
2405
|
+
...indexCpp.recursos,
|
|
2406
|
+
...indexPersistencia.recursos,
|
|
2407
|
+
];
|
|
2408
|
+
const mapaRecursos = construirMapaRecursos(todosRecursos);
|
|
2409
|
+
const todasRotasIndexadas = [
|
|
2410
|
+
...indexTs.rotas,
|
|
2411
|
+
...indexPy.rotas,
|
|
2412
|
+
...indexDart.rotas,
|
|
2413
|
+
...indexDotnet.rotas,
|
|
2414
|
+
...indexJava.rotas,
|
|
2415
|
+
...indexGo.rotas,
|
|
2416
|
+
...indexRust.rotas,
|
|
2417
|
+
];
|
|
2418
|
+
const todosArquivosConhecidos = [...new Set([
|
|
2419
|
+
...todosSimbolos.map((item) => item.arquivo),
|
|
2420
|
+
...todasRotasIndexadas.map((item) => item.arquivo),
|
|
2421
|
+
...todosRecursos.map((item) => item.arquivo),
|
|
2422
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2423
|
+
const implsValidos = [];
|
|
2424
|
+
const implsQuebrados = [];
|
|
2425
|
+
const vinculosValidos = [];
|
|
2426
|
+
const vinculosQuebrados = [];
|
|
2427
|
+
const rotasDivergentes = [];
|
|
2428
|
+
const recursosValidos = [];
|
|
2429
|
+
const recursosDivergentes = [];
|
|
2430
|
+
const diagnosticos = [];
|
|
2431
|
+
const tasksResumo = [];
|
|
2432
|
+
const taskPorChave = new Map();
|
|
2433
|
+
const guardrailsPorTask = new Map();
|
|
2434
|
+
const resumoVinculosPorTask = new Map();
|
|
2435
|
+
for (const item of contexto.modulosSelecionados) {
|
|
2436
|
+
const ir = item.resultado.ir;
|
|
2437
|
+
if (!ir) {
|
|
1942
2438
|
continue;
|
|
1943
2439
|
}
|
|
1944
|
-
const
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
if (!superficie.task || superficie.perfilCompatibilidade !== "publico") {
|
|
1964
|
-
continue;
|
|
2440
|
+
const superficiesPorChave = new Map(ir.superficies.map((superficie) => [`${superficie.tipo}:${superficie.nome}`, superficie]));
|
|
2441
|
+
for (const task of ir.tasks) {
|
|
2442
|
+
guardrailsPorTask.set(`${ir.nome}:${task.nome}`, {
|
|
2443
|
+
publica: false,
|
|
2444
|
+
sensivel: calcularRiscoOperacional(task) === "alto",
|
|
2445
|
+
auth: task.auth.explicita,
|
|
2446
|
+
authz: task.authz.explicita,
|
|
2447
|
+
dados: task.dados.explicita,
|
|
2448
|
+
audit: task.audit.explicita,
|
|
2449
|
+
segredos: task.segredos.explicita,
|
|
2450
|
+
forbidden: task.forbidden.explicita,
|
|
2451
|
+
dadosSensiveis: Boolean(task.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(task.dados.classificacaoPadrao)
|
|
2452
|
+
|| task.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao))),
|
|
2453
|
+
efeitoPrivilegiado: task.efeitosEstruturados.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
|
|
2454
|
+
|| ["alta", "critica"].includes(efeito.criticidade ?? "")),
|
|
2455
|
+
exigeSegredos: task.efeitosEstruturados.some((efeito) => efeito.categoria === "secret.read")
|
|
2456
|
+
|| Boolean(task.dados.classificacaoPadrao && ["credencial", "segredo"].includes(task.dados.classificacaoPadrao)
|
|
2457
|
+
|| task.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao))),
|
|
2458
|
+
});
|
|
1965
2459
|
}
|
|
1966
|
-
const
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
guardrails
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
2460
|
+
for (const route of ir.routes) {
|
|
2461
|
+
if (!route.task || route.perfilCompatibilidade !== "publico") {
|
|
2462
|
+
continue;
|
|
2463
|
+
}
|
|
2464
|
+
const guardrails = guardrailsPorTask.get(`${ir.nome}:${route.task}`);
|
|
2465
|
+
if (guardrails) {
|
|
2466
|
+
guardrails.publica = true;
|
|
2467
|
+
guardrails.auth = guardrails.auth || route.auth.explicita;
|
|
2468
|
+
guardrails.authz = guardrails.authz || route.authz.explicita;
|
|
2469
|
+
guardrails.dados = guardrails.dados || route.dados.explicita;
|
|
2470
|
+
guardrails.audit = guardrails.audit || route.audit.explicita;
|
|
2471
|
+
guardrails.segredos = guardrails.segredos || route.segredos.explicita;
|
|
2472
|
+
guardrails.forbidden = guardrails.forbidden || route.forbidden.explicita;
|
|
2473
|
+
guardrails.dadosSensiveis = guardrails.dadosSensiveis || Boolean(route.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(route.dados.classificacaoPadrao)
|
|
2474
|
+
|| route.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao)));
|
|
2475
|
+
guardrails.efeitoPrivilegiado = guardrails.efeitoPrivilegiado || route.efeitosPublicos.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
|
|
2476
|
+
|| ["alta", "critica"].includes(efeito.criticidade ?? ""));
|
|
2477
|
+
guardrails.exigeSegredos = guardrails.exigeSegredos || route.efeitosPublicos.some((efeito) => efeito.categoria === "secret.read")
|
|
2478
|
+
|| Boolean(route.dados.classificacaoPadrao && ["credencial", "segredo"].includes(route.dados.classificacaoPadrao)
|
|
2479
|
+
|| route.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao)));
|
|
2480
|
+
}
|
|
1982
2481
|
}
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
let validos = 0;
|
|
1987
|
-
let quebrados = 0;
|
|
1988
|
-
const arquivosReferenciados = new Set();
|
|
1989
|
-
const simbolosReferenciados = new Set();
|
|
1990
|
-
const candidatosTask = new Map();
|
|
1991
|
-
if (task.implementacoesExternas.length === 0) {
|
|
1992
|
-
for (const candidato of sugerirCandidatosParaTaskSemImpl(todosSimbolos, task.nome)) {
|
|
1993
|
-
candidatosTask.set(`${candidato.origem}:${candidato.caminho}:${candidato.arquivo}:${candidato.simbolo}`, candidato);
|
|
2482
|
+
for (const superficie of ir.superficies) {
|
|
2483
|
+
if (!superficie.task || superficie.perfilCompatibilidade !== "publico") {
|
|
2484
|
+
continue;
|
|
1994
2485
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
2486
|
+
const guardrails = guardrailsPorTask.get(`${ir.nome}:${superficie.task}`);
|
|
2487
|
+
if (guardrails) {
|
|
2488
|
+
guardrails.publica = true;
|
|
2489
|
+
guardrails.auth = guardrails.auth || superficie.auth.explicita;
|
|
2490
|
+
guardrails.authz = guardrails.authz || superficie.authz.explicita;
|
|
2491
|
+
guardrails.dados = guardrails.dados || superficie.dados.explicita;
|
|
2492
|
+
guardrails.audit = guardrails.audit || superficie.audit.explicita;
|
|
2493
|
+
guardrails.segredos = guardrails.segredos || superficie.segredos.explicita;
|
|
2494
|
+
guardrails.forbidden = guardrails.forbidden || superficie.forbidden.explicita;
|
|
2495
|
+
guardrails.dadosSensiveis = guardrails.dadosSensiveis || Boolean(superficie.dados.classificacaoPadrao && ["pii", "financeiro", "credencial", "segredo"].includes(superficie.dados.classificacaoPadrao)
|
|
2496
|
+
|| superficie.dados.campos.some((campo) => ["pii", "financeiro", "credencial", "segredo"].includes(campo.classificacao)));
|
|
2497
|
+
guardrails.efeitoPrivilegiado = guardrails.efeitoPrivilegiado || superficie.effects.some((efeito) => ["db.read", "db.write", "queue.publish", "queue.consume", "fs.read", "fs.write", "network.egress", "secret.read", "shell.exec"].includes(efeito.categoria)
|
|
2498
|
+
|| ["alta", "critica"].includes(efeito.criticidade ?? ""));
|
|
2499
|
+
guardrails.exigeSegredos = guardrails.exigeSegredos || superficie.effects.some((efeito) => efeito.categoria === "secret.read")
|
|
2500
|
+
|| Boolean(superficie.dados.classificacaoPadrao && ["credencial", "segredo"].includes(superficie.dados.classificacaoPadrao)
|
|
2501
|
+
|| superficie.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao)));
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
for (const task of ir.tasks) {
|
|
2505
|
+
taskPorChave.set(`${ir.nome}:${task.nome}`, task);
|
|
2506
|
+
let validos = 0;
|
|
2507
|
+
let quebrados = 0;
|
|
2508
|
+
const arquivosReferenciados = new Set();
|
|
2509
|
+
const simbolosReferenciados = new Set();
|
|
2510
|
+
const candidatosTask = new Map();
|
|
2511
|
+
if (task.implementacoesExternas.length === 0) {
|
|
2512
|
+
for (const candidato of sugerirCandidatosParaTaskSemImpl(todosSimbolos, task.nome)) {
|
|
2513
|
+
candidatosTask.set(`${candidato.origem}:${candidato.caminho}:${candidato.arquivo}:${candidato.simbolo}`, candidato);
|
|
2514
|
+
}
|
|
2515
|
+
diagnosticos.push({
|
|
2516
|
+
tipo: "task_sem_impl",
|
|
2517
|
+
modulo: ir.nome,
|
|
2518
|
+
task: task.nome,
|
|
2519
|
+
mensagem: `Task "${task.nome}" ainda nao foi ligada a nenhuma implementacao externa.`,
|
|
2520
|
+
});
|
|
2521
|
+
}
|
|
2522
|
+
for (const impl of task.implementacoesExternas) {
|
|
2523
|
+
const resolvido = mapaImpl.get(impl.caminho);
|
|
2524
|
+
const registro = {
|
|
2525
|
+
modulo: ir.nome,
|
|
2526
|
+
task: task.nome,
|
|
2527
|
+
origem: impl.origem,
|
|
2528
|
+
caminho: impl.caminho,
|
|
2529
|
+
arquivo: resolvido?.arquivo,
|
|
2530
|
+
simbolo: resolvido?.simbolo,
|
|
2531
|
+
caminhoResolvido: resolvido?.caminho,
|
|
2532
|
+
status: resolvido ? "resolvido" : "quebrado",
|
|
2533
|
+
};
|
|
2534
|
+
if (resolvido) {
|
|
2535
|
+
arquivosReferenciados.add(resolvido.arquivo);
|
|
2536
|
+
simbolosReferenciados.add(resolvido.simbolo);
|
|
2537
|
+
implsValidos.push(registro);
|
|
2538
|
+
validos += 1;
|
|
2539
|
+
}
|
|
2540
|
+
else {
|
|
2541
|
+
registro.candidatos = sugerirCandidatosParaImpl(todosSimbolos, impl.origem, impl.caminho);
|
|
2542
|
+
for (const candidato of registro.candidatos) {
|
|
2543
|
+
candidatosTask.set(`${candidato.origem}:${candidato.caminho}:${candidato.arquivo}:${candidato.simbolo}`, candidato);
|
|
2544
|
+
}
|
|
2545
|
+
implsQuebrados.push(registro);
|
|
2546
|
+
quebrados += 1;
|
|
2547
|
+
diagnosticos.push({
|
|
2548
|
+
tipo: "impl_quebrado",
|
|
2549
|
+
modulo: ir.nome,
|
|
2550
|
+
task: task.nome,
|
|
2551
|
+
mensagem: `Implementacao externa "${impl.origem}:${impl.caminho}" nao foi encontrada nos diretorios de codigo vivos.`,
|
|
2552
|
+
});
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
tasksResumo.push({
|
|
1997
2556
|
modulo: ir.nome,
|
|
1998
2557
|
task: task.nome,
|
|
1999
|
-
|
|
2558
|
+
impls: task.implementacoesExternas.length,
|
|
2559
|
+
implsValidos: validos,
|
|
2560
|
+
implsQuebrados: quebrados,
|
|
2561
|
+
semImplementacao: task.implementacoesExternas.length === 0,
|
|
2562
|
+
scoreSemantico: 0,
|
|
2563
|
+
confiancaVinculo: "baixa",
|
|
2564
|
+
riscoOperacional: "baixo",
|
|
2565
|
+
lacunas: [],
|
|
2566
|
+
arquivosReferenciados: [...arquivosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
2567
|
+
arquivosProvaveisEditar: [],
|
|
2568
|
+
simbolosReferenciados: [...simbolosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
2569
|
+
candidatosImpl: ordenarCandidatos([...candidatosTask.values()]).slice(0, 5),
|
|
2570
|
+
checksSugeridos: [],
|
|
2000
2571
|
});
|
|
2572
|
+
for (const recursoEsperado of extrairRecursosEsperados(task, ir)) {
|
|
2573
|
+
const resolvido = resolverRecursoEsperado(mapaRecursos, recursoEsperado, arquivosReferenciados);
|
|
2574
|
+
const registro = {
|
|
2575
|
+
modulo: ir.nome,
|
|
2576
|
+
task: task.nome,
|
|
2577
|
+
categoria: recursoEsperado.categoria,
|
|
2578
|
+
alvo: recursoEsperado.alvo,
|
|
2579
|
+
arquivo: resolvido?.arquivo ?? "",
|
|
2580
|
+
origem: resolvido?.origem ?? recursoEsperado.origem ?? "firebase",
|
|
2581
|
+
tipo: resolvido?.tipo ?? recursoEsperado.tiposAceitos[0] ?? "query",
|
|
2582
|
+
status: resolvido ? "resolvido" : "divergente",
|
|
2583
|
+
};
|
|
2584
|
+
if (resolvido) {
|
|
2585
|
+
registro.arquivo = resolvido.arquivo;
|
|
2586
|
+
recursosValidos.push(registro);
|
|
2587
|
+
}
|
|
2588
|
+
else {
|
|
2589
|
+
recursosDivergentes.push(registro);
|
|
2590
|
+
const escopo = recursoEsperado.origem ? `${recursoEsperado.origem}` : "persistencia declarada";
|
|
2591
|
+
diagnosticos.push({
|
|
2592
|
+
tipo: "recurso_divergente",
|
|
2593
|
+
modulo: ir.nome,
|
|
2594
|
+
task: task.nome,
|
|
2595
|
+
mensagem: `Recurso vivo "${recursoEsperado.alvo}" nao foi encontrado no codigo legado para ${escopo}.`,
|
|
2596
|
+
});
|
|
2597
|
+
}
|
|
2598
|
+
}
|
|
2001
2599
|
}
|
|
2002
|
-
for (const
|
|
2003
|
-
const
|
|
2004
|
-
const
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2600
|
+
for (const route of ir.routes) {
|
|
2601
|
+
const taskAssociada = ir.tasks.find((task) => task.nome === route.task);
|
|
2602
|
+
const esperadas = escolherRotasEsperadas(taskAssociada ?? {
|
|
2603
|
+
nome: "",
|
|
2604
|
+
input: [],
|
|
2605
|
+
output: [],
|
|
2606
|
+
rules: [],
|
|
2607
|
+
regrasEstruturadas: [],
|
|
2608
|
+
effects: [],
|
|
2609
|
+
efeitosEstruturados: [],
|
|
2610
|
+
implementacoesExternas: [],
|
|
2611
|
+
vinculos: [],
|
|
2612
|
+
execucao: {
|
|
2613
|
+
idempotencia: false,
|
|
2614
|
+
timeout: "padrao",
|
|
2615
|
+
retry: "nenhum",
|
|
2616
|
+
compensacao: "nenhuma",
|
|
2617
|
+
criticidadeOperacional: "media",
|
|
2618
|
+
explicita: false,
|
|
2619
|
+
},
|
|
2620
|
+
auth: {
|
|
2621
|
+
explicita: false,
|
|
2622
|
+
},
|
|
2623
|
+
authz: {
|
|
2624
|
+
explicita: false,
|
|
2625
|
+
papeis: [],
|
|
2626
|
+
escopos: [],
|
|
2627
|
+
},
|
|
2628
|
+
dados: {
|
|
2629
|
+
explicita: false,
|
|
2630
|
+
campos: [],
|
|
2631
|
+
},
|
|
2632
|
+
audit: {
|
|
2633
|
+
explicita: false,
|
|
2634
|
+
},
|
|
2635
|
+
segredos: {
|
|
2636
|
+
explicita: false,
|
|
2637
|
+
itens: [],
|
|
2638
|
+
},
|
|
2639
|
+
forbidden: {
|
|
2640
|
+
explicita: false,
|
|
2641
|
+
regras: [],
|
|
2642
|
+
},
|
|
2643
|
+
guarantees: [],
|
|
2644
|
+
garantiasEstruturadas: [],
|
|
2645
|
+
errors: {},
|
|
2646
|
+
errosDetalhados: [],
|
|
2647
|
+
perfilCompatibilidade: "interno",
|
|
2648
|
+
resumoAgente: {
|
|
2649
|
+
riscos: [],
|
|
2650
|
+
checks: [],
|
|
2651
|
+
entidadesAfetadas: [],
|
|
2652
|
+
superficiesPublicas: [],
|
|
2653
|
+
mutacoesPrevistas: [],
|
|
2654
|
+
},
|
|
2655
|
+
tests: [],
|
|
2656
|
+
}, contexto.fontesLegado);
|
|
2657
|
+
if (!esperadas.length || !route.metodo || !route.caminho) {
|
|
2658
|
+
continue;
|
|
2019
2659
|
}
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2660
|
+
const encontradas = todasRotasIndexadas.filter((rotaResolvida) => rotaResolvida.origem !== "nextjs-consumer"
|
|
2661
|
+
&& rotaResolvida.origem !== "react-vite-consumer"
|
|
2662
|
+
&& rotaResolvida.origem !== "angular-consumer"
|
|
2663
|
+
&& rotaResolvida.origem !== "flutter-consumer"
|
|
2664
|
+
&& esperadas.includes(rotaResolvida.origem));
|
|
2665
|
+
const combina = encontradas.some((rotaResolvida) => rotaResolvida.metodo === route.metodo
|
|
2666
|
+
&& normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(route.caminho));
|
|
2667
|
+
if (!combina) {
|
|
2668
|
+
const registro = {
|
|
2669
|
+
modulo: ir.nome,
|
|
2670
|
+
route: route.nome,
|
|
2671
|
+
metodo: route.metodo,
|
|
2672
|
+
caminho: route.caminho,
|
|
2673
|
+
motivo: `Nenhuma rota publica ${route.metodo} ${route.caminho} foi encontrada no codigo legado para o framework esperado.`,
|
|
2674
|
+
};
|
|
2675
|
+
rotasDivergentes.push(registro);
|
|
2027
2676
|
diagnosticos.push({
|
|
2028
|
-
tipo: "
|
|
2677
|
+
tipo: "rota_divergente",
|
|
2029
2678
|
modulo: ir.nome,
|
|
2030
|
-
|
|
2031
|
-
mensagem:
|
|
2679
|
+
route: route.nome,
|
|
2680
|
+
mensagem: registro.motivo,
|
|
2032
2681
|
});
|
|
2033
2682
|
}
|
|
2034
2683
|
}
|
|
2035
|
-
|
|
2036
|
-
modulo: ir.nome,
|
|
2037
|
-
task: task.nome,
|
|
2038
|
-
impls: task.implementacoesExternas.length,
|
|
2039
|
-
implsValidos: validos,
|
|
2040
|
-
implsQuebrados: quebrados,
|
|
2041
|
-
semImplementacao: task.implementacoesExternas.length === 0,
|
|
2042
|
-
scoreSemantico: 0,
|
|
2043
|
-
confiancaVinculo: "baixa",
|
|
2044
|
-
riscoOperacional: "baixo",
|
|
2045
|
-
lacunas: [],
|
|
2046
|
-
arquivosReferenciados: [...arquivosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
2047
|
-
arquivosProvaveisEditar: [],
|
|
2048
|
-
simbolosReferenciados: [...simbolosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
2049
|
-
candidatosImpl: ordenarCandidatos([...candidatosTask.values()]).slice(0, 5),
|
|
2050
|
-
checksSugeridos: [],
|
|
2051
|
-
});
|
|
2052
|
-
for (const recursoEsperado of extrairRecursosEsperados(task, ir)) {
|
|
2053
|
-
const resolvido = resolverRecursoEsperado(mapaRecursos, recursoEsperado, arquivosReferenciados);
|
|
2684
|
+
for (const itemVinculo of coletarVinculosIr(ir)) {
|
|
2054
2685
|
const registro = {
|
|
2055
2686
|
modulo: ir.nome,
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
status: resolvido ? "resolvido" : "divergente",
|
|
2687
|
+
donoTipo: itemVinculo.donoTipo,
|
|
2688
|
+
dono: itemVinculo.dono,
|
|
2689
|
+
tipo: itemVinculo.vinculo.tipo,
|
|
2690
|
+
valor: itemVinculo.vinculo.valor,
|
|
2691
|
+
status: "nao_encontrado",
|
|
2692
|
+
confianca: "baixa",
|
|
2063
2693
|
};
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2694
|
+
const arquivoDeclarado = itemVinculo.vinculo.arquivo ?? (itemVinculo.vinculo.tipo === "arquivo" ? itemVinculo.vinculo.valor : undefined);
|
|
2695
|
+
const simboloDeclarado = itemVinculo.vinculo.simbolo ?? (itemVinculo.vinculo.tipo === "simbolo" ? itemVinculo.vinculo.valor : undefined);
|
|
2696
|
+
const recursoDeclarado = itemVinculo.vinculo.recurso ?? (["recurso", "tabela", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
2697
|
+
const superficieDeclarada = itemVinculo.vinculo.superficie ?? (["superficie", "rota", "worker", "cron", "webhook", "evento", "policy", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
2698
|
+
if (simboloDeclarado) {
|
|
2699
|
+
const resolucaoSimbolo = escolherSimboloPorVinculo(todosSimbolos, mapaImpl, simboloDeclarado);
|
|
2700
|
+
registro.status = resolucaoSimbolo.status;
|
|
2701
|
+
registro.confianca = resolucaoSimbolo.confianca;
|
|
2702
|
+
registro.arquivo = resolucaoSimbolo.simbolo?.arquivo;
|
|
2703
|
+
registro.simbolo = resolucaoSimbolo.simbolo?.simbolo;
|
|
2704
|
+
}
|
|
2705
|
+
else if (arquivoDeclarado) {
|
|
2706
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, arquivoDeclarado);
|
|
2707
|
+
registro.status = resolucaoArquivo.status;
|
|
2708
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
2709
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
2710
|
+
}
|
|
2711
|
+
else if (recursoDeclarado) {
|
|
2712
|
+
const recurso = resolverRecursoEsperado(mapaRecursos, {
|
|
2713
|
+
categoria: "persistencia",
|
|
2714
|
+
alvo: recursoDeclarado,
|
|
2715
|
+
tiposAceitos: [],
|
|
2716
|
+
nomes: [recursoDeclarado],
|
|
2717
|
+
});
|
|
2718
|
+
if (recurso) {
|
|
2719
|
+
registro.status = "resolvido";
|
|
2720
|
+
registro.confianca = "alta";
|
|
2721
|
+
registro.arquivo = recurso.arquivo;
|
|
2722
|
+
}
|
|
2723
|
+
}
|
|
2724
|
+
else if (superficieDeclarada) {
|
|
2725
|
+
const rota = todasRotasIndexadas.find((rotaResolvida) => normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(superficieDeclarada));
|
|
2726
|
+
if (rota) {
|
|
2727
|
+
registro.status = "resolvido";
|
|
2728
|
+
registro.confianca = "alta";
|
|
2729
|
+
registro.arquivo = rota.arquivo;
|
|
2730
|
+
registro.simbolo = rota.simbolo;
|
|
2731
|
+
}
|
|
2732
|
+
else {
|
|
2733
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, superficieDeclarada);
|
|
2734
|
+
registro.status = resolucaoArquivo.status;
|
|
2735
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
2736
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
2737
|
+
}
|
|
2067
2738
|
}
|
|
2068
2739
|
else {
|
|
2069
|
-
|
|
2070
|
-
|
|
2740
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, itemVinculo.vinculo.valor);
|
|
2741
|
+
registro.status = resolucaoArquivo.status;
|
|
2742
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
2743
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
2744
|
+
}
|
|
2745
|
+
if (registro.status === "nao_encontrado" && itemVinculo.donoTipo === "superficie") {
|
|
2746
|
+
const superficie = superficiesPorChave.get(itemVinculo.dono);
|
|
2747
|
+
const ancora = superficie
|
|
2748
|
+
? encontrarAncoraSuperficie(ir, superficie, todosSimbolos, mapaImpl, todosArquivosConhecidos)
|
|
2749
|
+
: undefined;
|
|
2750
|
+
if (ancora) {
|
|
2751
|
+
registro.status = "parcial";
|
|
2752
|
+
registro.confianca = ancora.confianca === "alta" ? "media" : ancora.confianca;
|
|
2753
|
+
registro.arquivo = registro.arquivo ?? ancora.arquivo;
|
|
2754
|
+
registro.simbolo = registro.simbolo ?? ancora.simbolo;
|
|
2755
|
+
}
|
|
2756
|
+
}
|
|
2757
|
+
if (registro.status === "nao_encontrado") {
|
|
2758
|
+
vinculosQuebrados.push(registro);
|
|
2071
2759
|
diagnosticos.push({
|
|
2072
|
-
tipo: "
|
|
2760
|
+
tipo: "vinculo_quebrado",
|
|
2073
2761
|
modulo: ir.nome,
|
|
2074
|
-
|
|
2075
|
-
|
|
2762
|
+
mensagem: `Vinculo ${registro.tipo}="${registro.valor}" de ${registro.donoTipo} "${registro.dono}" nao foi resolvido no codigo vivo.`,
|
|
2763
|
+
...(itemVinculo.donoTipo === "task" ? { task: itemVinculo.dono } : itemVinculo.donoTipo === "route" ? { route: itemVinculo.dono } : {}),
|
|
2076
2764
|
});
|
|
2077
2765
|
}
|
|
2766
|
+
else {
|
|
2767
|
+
vinculosValidos.push(registro);
|
|
2768
|
+
}
|
|
2769
|
+
if (itemVinculo.donoTipo === "task") {
|
|
2770
|
+
const chaveTask = `${ir.nome}:${itemVinculo.dono}`;
|
|
2771
|
+
const resumo = resumoVinculosPorTask.get(chaveTask) ?? {
|
|
2772
|
+
validos: 0,
|
|
2773
|
+
quebrados: 0,
|
|
2774
|
+
arquivos: new Set(),
|
|
2775
|
+
};
|
|
2776
|
+
if (registro.status === "nao_encontrado") {
|
|
2777
|
+
resumo.quebrados += 1;
|
|
2778
|
+
}
|
|
2779
|
+
else {
|
|
2780
|
+
resumo.validos += 1;
|
|
2781
|
+
}
|
|
2782
|
+
if (registro.arquivo) {
|
|
2783
|
+
resumo.arquivos.add(registro.arquivo);
|
|
2784
|
+
}
|
|
2785
|
+
resumoVinculosPorTask.set(chaveTask, resumo);
|
|
2786
|
+
}
|
|
2078
2787
|
}
|
|
2079
2788
|
}
|
|
2080
|
-
for (const
|
|
2081
|
-
const
|
|
2082
|
-
const
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
|
|
2102
|
-
},
|
|
2103
|
-
authz: {
|
|
2104
|
-
explicita: false,
|
|
2105
|
-
papeis: [],
|
|
2106
|
-
escopos: [],
|
|
2107
|
-
},
|
|
2108
|
-
dados: {
|
|
2109
|
-
explicita: false,
|
|
2110
|
-
campos: [],
|
|
2111
|
-
},
|
|
2112
|
-
audit: {
|
|
2113
|
-
explicita: false,
|
|
2114
|
-
},
|
|
2115
|
-
segredos: {
|
|
2116
|
-
explicita: false,
|
|
2117
|
-
itens: [],
|
|
2118
|
-
},
|
|
2119
|
-
forbidden: {
|
|
2120
|
-
explicita: false,
|
|
2121
|
-
regras: [],
|
|
2122
|
-
},
|
|
2123
|
-
guarantees: [],
|
|
2124
|
-
garantiasEstruturadas: [],
|
|
2125
|
-
errors: {},
|
|
2126
|
-
errosDetalhados: [],
|
|
2127
|
-
perfilCompatibilidade: "interno",
|
|
2128
|
-
resumoAgente: {
|
|
2129
|
-
riscos: [],
|
|
2130
|
-
checks: [],
|
|
2131
|
-
entidadesAfetadas: [],
|
|
2132
|
-
superficiesPublicas: [],
|
|
2133
|
-
mutacoesPrevistas: [],
|
|
2134
|
-
},
|
|
2135
|
-
tests: [],
|
|
2136
|
-
}, contexto.fontesLegado);
|
|
2137
|
-
if (!esperadas.length || !route.metodo || !route.caminho) {
|
|
2789
|
+
for (const resumo of tasksResumo) {
|
|
2790
|
+
const chaveTask = `${resumo.modulo}:${resumo.task}`;
|
|
2791
|
+
const task = taskPorChave.get(chaveTask);
|
|
2792
|
+
const guardrails = guardrailsPorTask.get(chaveTask) ?? {
|
|
2793
|
+
publica: false,
|
|
2794
|
+
sensivel: false,
|
|
2795
|
+
auth: false,
|
|
2796
|
+
authz: false,
|
|
2797
|
+
dados: false,
|
|
2798
|
+
audit: false,
|
|
2799
|
+
segredos: false,
|
|
2800
|
+
forbidden: false,
|
|
2801
|
+
dadosSensiveis: false,
|
|
2802
|
+
efeitoPrivilegiado: false,
|
|
2803
|
+
exigeSegredos: false,
|
|
2804
|
+
};
|
|
2805
|
+
const resumoVinculos = resumoVinculosPorTask.get(chaveTask) ?? {
|
|
2806
|
+
validos: 0,
|
|
2807
|
+
quebrados: 0,
|
|
2808
|
+
arquivos: new Set(),
|
|
2809
|
+
};
|
|
2810
|
+
if (!task) {
|
|
2138
2811
|
continue;
|
|
2139
2812
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2813
|
+
resumo.confiancaVinculo = calcularConfiancaTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados);
|
|
2814
|
+
resumo.riscoOperacional = calcularRiscoOperacional(task);
|
|
2815
|
+
resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados, guardrails);
|
|
2816
|
+
resumo.scoreSemantico = calcularScoreTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados, resumo.semImplementacao);
|
|
2817
|
+
resumo.arquivosProvaveisEditar = [...new Set([
|
|
2818
|
+
...resumo.arquivosReferenciados,
|
|
2819
|
+
...resumo.candidatosImpl.map((candidato) => candidato.arquivo),
|
|
2820
|
+
...resumoVinculos.arquivos,
|
|
2821
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2822
|
+
resumo.checksSugeridos = [...new Set([
|
|
2823
|
+
...task.resumoAgente.checks,
|
|
2824
|
+
resumo.riscoOperacional !== "baixo" ? "revisar efeitos operacionais" : "",
|
|
2825
|
+
resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
|
|
2826
|
+
resumo.lacunas.some((lacuna) => ["superficie_publica_sem_execucao", "execucao_critica_sem_bloco", "rastreabilidade_fraca"].includes(lacuna))
|
|
2827
|
+
? "endurecer execucao e rastreabilidade para producao"
|
|
2828
|
+
: "",
|
|
2829
|
+
resumo.lacunas.some((lacuna) => ["auth_ausente", "authz_frouxa", "dados_nao_classificados", "audit_ausente", "segredo_sem_governanca", "proibicoes_ausentes"].includes(lacuna))
|
|
2830
|
+
? "explicitar contratos de seguranca semantica"
|
|
2831
|
+
: "",
|
|
2832
|
+
].filter(Boolean))];
|
|
2833
|
+
if (resumo.lacunas.includes("superficie_publica_sem_execucao")) {
|
|
2156
2834
|
diagnosticos.push({
|
|
2157
|
-
tipo: "
|
|
2158
|
-
modulo:
|
|
2159
|
-
|
|
2160
|
-
mensagem:
|
|
2835
|
+
tipo: "seguranca_frouxa",
|
|
2836
|
+
modulo: resumo.modulo,
|
|
2837
|
+
task: resumo.task,
|
|
2838
|
+
mensagem: `Task "${resumo.task}" alimenta superficie publica, mas ainda depende de execucao implicita.`,
|
|
2161
2839
|
});
|
|
2162
2840
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
tipo: itemVinculo.vinculo.tipo,
|
|
2170
|
-
valor: itemVinculo.vinculo.valor,
|
|
2171
|
-
status: "nao_encontrado",
|
|
2172
|
-
confianca: "baixa",
|
|
2173
|
-
};
|
|
2174
|
-
const arquivoDeclarado = itemVinculo.vinculo.arquivo ?? (itemVinculo.vinculo.tipo === "arquivo" ? itemVinculo.vinculo.valor : undefined);
|
|
2175
|
-
const simboloDeclarado = itemVinculo.vinculo.simbolo ?? (itemVinculo.vinculo.tipo === "simbolo" ? itemVinculo.vinculo.valor : undefined);
|
|
2176
|
-
const recursoDeclarado = itemVinculo.vinculo.recurso ?? (["recurso", "tabela", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
2177
|
-
const superficieDeclarada = itemVinculo.vinculo.superficie ?? (["superficie", "rota", "worker", "cron", "webhook", "evento", "policy", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
2178
|
-
if (simboloDeclarado) {
|
|
2179
|
-
const resolucaoSimbolo = escolherSimboloPorVinculo(todosSimbolos, mapaImpl, simboloDeclarado);
|
|
2180
|
-
registro.status = resolucaoSimbolo.status;
|
|
2181
|
-
registro.confianca = resolucaoSimbolo.confianca;
|
|
2182
|
-
registro.arquivo = resolucaoSimbolo.simbolo?.arquivo;
|
|
2183
|
-
registro.simbolo = resolucaoSimbolo.simbolo?.simbolo;
|
|
2184
|
-
}
|
|
2185
|
-
else if (arquivoDeclarado) {
|
|
2186
|
-
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, arquivoDeclarado);
|
|
2187
|
-
registro.status = resolucaoArquivo.status;
|
|
2188
|
-
registro.confianca = resolucaoArquivo.confianca;
|
|
2189
|
-
registro.arquivo = resolucaoArquivo.arquivo;
|
|
2190
|
-
}
|
|
2191
|
-
else if (recursoDeclarado) {
|
|
2192
|
-
const recurso = resolverRecursoEsperado(mapaRecursos, {
|
|
2193
|
-
categoria: "persistencia",
|
|
2194
|
-
alvo: recursoDeclarado,
|
|
2195
|
-
tiposAceitos: [],
|
|
2196
|
-
nomes: [recursoDeclarado],
|
|
2841
|
+
if (resumo.lacunas.includes("execucao_critica_sem_bloco")) {
|
|
2842
|
+
diagnosticos.push({
|
|
2843
|
+
tipo: "seguranca_frouxa",
|
|
2844
|
+
modulo: resumo.modulo,
|
|
2845
|
+
task: resumo.task,
|
|
2846
|
+
mensagem: `Task "${resumo.task}" opera com risco alto, mas ainda nao declarou execucao explicita.`,
|
|
2197
2847
|
});
|
|
2198
|
-
if (recurso) {
|
|
2199
|
-
registro.status = "resolvido";
|
|
2200
|
-
registro.confianca = "alta";
|
|
2201
|
-
registro.arquivo = recurso.arquivo;
|
|
2202
|
-
}
|
|
2203
2848
|
}
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
}
|
|
2212
|
-
else {
|
|
2213
|
-
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, superficieDeclarada);
|
|
2214
|
-
registro.status = resolucaoArquivo.status;
|
|
2215
|
-
registro.confianca = resolucaoArquivo.confianca;
|
|
2216
|
-
registro.arquivo = resolucaoArquivo.arquivo;
|
|
2217
|
-
}
|
|
2849
|
+
if (resumo.lacunas.includes("rastreabilidade_fraca")) {
|
|
2850
|
+
diagnosticos.push({
|
|
2851
|
+
tipo: "seguranca_frouxa",
|
|
2852
|
+
modulo: resumo.modulo,
|
|
2853
|
+
task: resumo.task,
|
|
2854
|
+
mensagem: `Task "${resumo.task}" exige producao mais rastreavel, mas ainda nao declara impl nem vinculos.`,
|
|
2855
|
+
});
|
|
2218
2856
|
}
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
const superficie = superficiesPorChave.get(itemVinculo.dono);
|
|
2227
|
-
const ancora = superficie
|
|
2228
|
-
? encontrarAncoraSuperficie(ir, superficie, todosSimbolos, mapaImpl, todosArquivosConhecidos)
|
|
2229
|
-
: undefined;
|
|
2230
|
-
if (ancora) {
|
|
2231
|
-
registro.status = "parcial";
|
|
2232
|
-
registro.confianca = ancora.confianca === "alta" ? "media" : ancora.confianca;
|
|
2233
|
-
registro.arquivo = registro.arquivo ?? ancora.arquivo;
|
|
2234
|
-
registro.simbolo = registro.simbolo ?? ancora.simbolo;
|
|
2235
|
-
}
|
|
2857
|
+
if (resumo.lacunas.includes("auth_ausente")) {
|
|
2858
|
+
diagnosticos.push({
|
|
2859
|
+
tipo: "seguranca_frouxa",
|
|
2860
|
+
modulo: resumo.modulo,
|
|
2861
|
+
task: resumo.task,
|
|
2862
|
+
mensagem: `Task "${resumo.task}" chega em superficie publica sem auth explicita em task, route ou superficie associada.`,
|
|
2863
|
+
});
|
|
2236
2864
|
}
|
|
2237
|
-
if (
|
|
2238
|
-
vinculosQuebrados.push(registro);
|
|
2865
|
+
if (resumo.lacunas.includes("authz_frouxa")) {
|
|
2239
2866
|
diagnosticos.push({
|
|
2240
|
-
tipo: "
|
|
2241
|
-
modulo:
|
|
2242
|
-
|
|
2243
|
-
|
|
2867
|
+
tipo: "seguranca_frouxa",
|
|
2868
|
+
modulo: resumo.modulo,
|
|
2869
|
+
task: resumo.task,
|
|
2870
|
+
mensagem: `Task "${resumo.task}" opera com risco ou exposicao, mas ainda nao explicita authz suficiente.`,
|
|
2244
2871
|
});
|
|
2245
2872
|
}
|
|
2246
|
-
|
|
2247
|
-
|
|
2873
|
+
if (resumo.lacunas.includes("dados_nao_classificados")) {
|
|
2874
|
+
diagnosticos.push({
|
|
2875
|
+
tipo: "seguranca_frouxa",
|
|
2876
|
+
modulo: resumo.modulo,
|
|
2877
|
+
task: resumo.task,
|
|
2878
|
+
mensagem: `Task "${resumo.task}" ainda nao classifica dados de entrada/saida de forma semantica.`,
|
|
2879
|
+
});
|
|
2248
2880
|
}
|
|
2249
|
-
if (
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
};
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
resumo.
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2881
|
+
if (resumo.lacunas.includes("audit_ausente")) {
|
|
2882
|
+
diagnosticos.push({
|
|
2883
|
+
tipo: "seguranca_frouxa",
|
|
2884
|
+
modulo: resumo.modulo,
|
|
2885
|
+
task: resumo.task,
|
|
2886
|
+
mensagem: `Task "${resumo.task}" ainda nao declara audit explicita para operacao sensivel ou publica.`,
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
if (resumo.lacunas.includes("segredo_sem_governanca")) {
|
|
2890
|
+
diagnosticos.push({
|
|
2891
|
+
tipo: "seguranca_frouxa",
|
|
2892
|
+
modulo: resumo.modulo,
|
|
2893
|
+
task: resumo.task,
|
|
2894
|
+
mensagem: `Task "${resumo.task}" toca segredo ou credencial sem bloco segredos governando origem, escopo e rotacao.`,
|
|
2895
|
+
});
|
|
2896
|
+
}
|
|
2897
|
+
if (resumo.lacunas.includes("proibicoes_ausentes")) {
|
|
2898
|
+
diagnosticos.push({
|
|
2899
|
+
tipo: "seguranca_frouxa",
|
|
2900
|
+
modulo: resumo.modulo,
|
|
2901
|
+
task: resumo.task,
|
|
2902
|
+
mensagem: `Task "${resumo.task}" opera com efeito privilegiado ou dado sensivel sem forbidden explicito para conter abuso e vazamento.`,
|
|
2903
|
+
});
|
|
2904
|
+
}
|
|
2905
|
+
}
|
|
2906
|
+
const consumersFiltrados = filtrarConsumerSurfacesPorEscopo([...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
|
|
2907
|
+
|| a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
|
|
2908
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR")), [...new Map([...indexTs.simbolos, ...indexDart.simbolos]
|
|
2909
|
+
.filter((simbolo) => simboloEhBridgeConsumer(simbolo.caminho, simbolo.arquivo))
|
|
2910
|
+
.map((simbolo) => [
|
|
2911
|
+
`${simbolo.caminho}:${simbolo.arquivo}:${simbolo.simbolo}`,
|
|
2912
|
+
{
|
|
2913
|
+
caminho: simbolo.caminho,
|
|
2914
|
+
arquivo: simbolo.arquivo,
|
|
2915
|
+
simbolo: simbolo.simbolo,
|
|
2916
|
+
},
|
|
2917
|
+
])).values()].sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR")
|
|
2918
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR")), contexto, configuracaoEscopo);
|
|
2919
|
+
const consumerSurfaces = consumersFiltrados.consumerSurfaces;
|
|
2920
|
+
const consumerBridges = consumersFiltrados.consumerBridges;
|
|
2921
|
+
const appRoutes = [...new Set(consumerSurfaces.map((surface) => surface.rota))]
|
|
2922
|
+
.sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2923
|
+
const consumerFramework = inferirConsumerFrameworkPrincipal(contexto.fontesLegado, consumerSurfaces, consumerBridges);
|
|
2924
|
+
const persistenciaReal = await analisarPersistenciaReal(contexto, mapaRecursos, detalhesPersistencia, opcoesResolvidas);
|
|
2925
|
+
for (const item of persistenciaReal) {
|
|
2926
|
+
if (item.status === "divergente") {
|
|
2927
|
+
diagnosticos.push({
|
|
2928
|
+
tipo: "recurso_divergente",
|
|
2929
|
+
modulo: item.modulo,
|
|
2930
|
+
task: item.task,
|
|
2931
|
+
mensagem: `Persistencia real para "${item.alvo}" ainda nao foi materializada no codigo vivo.`,
|
|
2932
|
+
});
|
|
2933
|
+
}
|
|
2934
|
+
else if (item.compatibilidade === "invalido") {
|
|
2935
|
+
diagnosticos.push({
|
|
2936
|
+
tipo: "recurso_divergente",
|
|
2937
|
+
modulo: item.modulo,
|
|
2938
|
+
task: item.task,
|
|
2939
|
+
mensagem: `Persistencia real para "${item.alvo}" conflita com a compatibilidade declarada do engine ${item.engine}.`,
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
const payloadBase = {
|
|
2944
|
+
comando: "drift",
|
|
2945
|
+
sucesso: implsQuebrados.length === 0
|
|
2946
|
+
&& rotasDivergentes.length === 0
|
|
2947
|
+
&& recursosDivergentes.length === 0
|
|
2948
|
+
&& vinculosQuebrados.length === 0
|
|
2949
|
+
&& persistenciaReal.every((item) => item.status !== "divergente" && item.compatibilidade !== "invalido"),
|
|
2950
|
+
escopo_aplicado: configuracaoEscopo,
|
|
2951
|
+
consumerFramework,
|
|
2952
|
+
appRoutes,
|
|
2953
|
+
consumerSurfaces,
|
|
2954
|
+
consumerBridges,
|
|
2955
|
+
modulos: contexto.modulosSelecionados.map((item) => ({
|
|
2956
|
+
caminho: item.caminho,
|
|
2957
|
+
modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,
|
|
2958
|
+
tasks: item.resultado.ir?.tasks.length ?? 0,
|
|
2959
|
+
routes: item.resultado.ir?.routes.length ?? 0,
|
|
2960
|
+
})),
|
|
2961
|
+
tasks: tasksResumo,
|
|
2962
|
+
impls_validos: implsValidos,
|
|
2963
|
+
impls_quebrados: implsQuebrados,
|
|
2964
|
+
vinculos_validos: vinculosValidos,
|
|
2965
|
+
vinculos_quebrados: vinculosQuebrados,
|
|
2966
|
+
rotas_divergentes: rotasDivergentes,
|
|
2967
|
+
recursos_validos: recursosValidos,
|
|
2968
|
+
recursos_divergentes: recursosDivergentes,
|
|
2969
|
+
persistencia_real: persistenciaReal,
|
|
2970
|
+
diagnosticos,
|
|
2971
|
+
resumo_operacional: {
|
|
2972
|
+
scoreMedio: 0,
|
|
2973
|
+
confiancaGeral: "baixa",
|
|
2974
|
+
riscosPrincipais: [],
|
|
2975
|
+
oQueTocar: [],
|
|
2976
|
+
oQueValidar: [],
|
|
2977
|
+
oQueEstaFrouxo: [],
|
|
2978
|
+
oQueFoiInferido: [],
|
|
2979
|
+
},
|
|
2284
2980
|
};
|
|
2285
|
-
const
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2981
|
+
const resumoOperacional = resumirOperacional(payloadBase);
|
|
2982
|
+
return {
|
|
2983
|
+
...payloadBase,
|
|
2984
|
+
resumo_operacional: resumoOperacional,
|
|
2289
2985
|
};
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2986
|
+
}
|
|
2987
|
+
finally {
|
|
2988
|
+
diretoriosIgnoradosAtivos = diretoriosIgnoradosAnteriores;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
const EXTENSOES_BUSCA_IMPACTO = [
|
|
2992
|
+
".sema",
|
|
2993
|
+
".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs",
|
|
2994
|
+
".py", ".dart", ".cs", ".java", ".go", ".rs", ".cpp", ".cc", ".cxx", ".hpp", ".h",
|
|
2995
|
+
".sql", ".psql", ".ddl", ".prisma", ".json",
|
|
2996
|
+
];
|
|
2997
|
+
function construirVariantesSemanticas(valor) {
|
|
2998
|
+
const bruto = valor.trim();
|
|
2999
|
+
const partes = paraIdentificadorModulo(valor).split("_").filter(Boolean);
|
|
3000
|
+
if (!bruto && partes.length === 0) {
|
|
3001
|
+
return [];
|
|
3002
|
+
}
|
|
3003
|
+
const camel = partes.length > 0
|
|
3004
|
+
? `${partes[0]}${partes.slice(1).map((item) => item[0]?.toUpperCase() + item.slice(1)).join("")}`
|
|
3005
|
+
: bruto;
|
|
3006
|
+
const pascal = partes.length > 0
|
|
3007
|
+
? partes.map((item) => item[0]?.toUpperCase() + item.slice(1)).join("")
|
|
3008
|
+
: bruto;
|
|
3009
|
+
return [...new Set([
|
|
3010
|
+
bruto,
|
|
3011
|
+
partes.join("_"),
|
|
3012
|
+
partes.join("-"),
|
|
3013
|
+
partes.join("."),
|
|
3014
|
+
camel,
|
|
3015
|
+
pascal,
|
|
3016
|
+
].filter(Boolean))];
|
|
3017
|
+
}
|
|
3018
|
+
function classificarArquivoImpacto(arquivo) {
|
|
3019
|
+
const normalizado = normalizarFragmentoArquivo(arquivo);
|
|
3020
|
+
if (normalizado.endsWith(".sema")) {
|
|
3021
|
+
return "contrato";
|
|
3022
|
+
}
|
|
3023
|
+
if (/\.(sql|psql|ddl|prisma)$/i.test(normalizado) || /(?:^|\/)(?:db|database|migrations?|schemas?)\//i.test(normalizado)) {
|
|
3024
|
+
return "persistencia";
|
|
3025
|
+
}
|
|
3026
|
+
if (/(?:^|\/)(?:repositorio|repositorios|repository|repositories|repo|dao|store)\//i.test(normalizado) || /(repository|repositorio|dao|store)/i.test(path.basename(normalizado))) {
|
|
3027
|
+
return "repositorio";
|
|
3028
|
+
}
|
|
3029
|
+
if (/(?:^|\/)(?:routes?|controllers?|api)\//i.test(normalizado) || /(controller|route)/i.test(path.basename(normalizado))) {
|
|
3030
|
+
return "rota";
|
|
3031
|
+
}
|
|
3032
|
+
if (/(?:^|\/)(?:workers?|jobs?|queues?|cron)\//i.test(normalizado) || /(worker|job|queue|cron)/i.test(path.basename(normalizado))) {
|
|
3033
|
+
return "worker";
|
|
3034
|
+
}
|
|
3035
|
+
if (/(?:^|\/)(?:pages|screens|components|views|app)\//i.test(normalizado)) {
|
|
3036
|
+
return "ui";
|
|
3037
|
+
}
|
|
3038
|
+
if (/(?:^|\/)(?:tests?|specs?|__tests__)\//i.test(normalizado) || /\.(spec|test)\./i.test(normalizado)) {
|
|
3039
|
+
return "teste";
|
|
3040
|
+
}
|
|
3041
|
+
return "codigo";
|
|
3042
|
+
}
|
|
3043
|
+
function prioridadeArquivoImpacto(tipo) {
|
|
3044
|
+
switch (tipo) {
|
|
3045
|
+
case "contrato":
|
|
3046
|
+
case "persistencia":
|
|
3047
|
+
case "repositorio":
|
|
3048
|
+
case "rota":
|
|
3049
|
+
return "alta";
|
|
3050
|
+
case "worker":
|
|
3051
|
+
case "codigo":
|
|
3052
|
+
return "media";
|
|
3053
|
+
default:
|
|
3054
|
+
return "baixa";
|
|
3055
|
+
}
|
|
3056
|
+
}
|
|
3057
|
+
function textoIrCombinaTermos(texto, termos) {
|
|
3058
|
+
return textoCombinaEscopo(texto, termos);
|
|
3059
|
+
}
|
|
3060
|
+
function registrarArquivoImpactado(mapa, arquivo, linhas, motivos) {
|
|
3061
|
+
const tipo = classificarArquivoImpacto(arquivo);
|
|
3062
|
+
const atual = mapa.get(arquivo);
|
|
3063
|
+
if (atual) {
|
|
3064
|
+
atual.linhas = [...new Set([...atual.linhas, ...linhas])].sort((a, b) => a - b);
|
|
3065
|
+
atual.motivos = [...new Set([...atual.motivos, ...motivos])];
|
|
3066
|
+
if (prioridadeArquivoImpacto(tipo) === "alta") {
|
|
3067
|
+
atual.prioridade = "alta";
|
|
2320
3068
|
}
|
|
2321
|
-
if (
|
|
2322
|
-
|
|
2323
|
-
tipo: "seguranca_frouxa",
|
|
2324
|
-
modulo: resumo.modulo,
|
|
2325
|
-
task: resumo.task,
|
|
2326
|
-
mensagem: `Task "${resumo.task}" opera com risco alto, mas ainda nao declarou execucao explicita.`,
|
|
2327
|
-
});
|
|
3069
|
+
else if (prioridadeArquivoImpacto(tipo) === "media" && atual.prioridade === "baixa") {
|
|
3070
|
+
atual.prioridade = "media";
|
|
2328
3071
|
}
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
mapa.set(arquivo, {
|
|
3075
|
+
arquivo,
|
|
3076
|
+
tipo,
|
|
3077
|
+
prioridade: prioridadeArquivoImpacto(tipo),
|
|
3078
|
+
linhas: [...new Set(linhas)].sort((a, b) => a - b),
|
|
3079
|
+
motivos: [...new Set(motivos)],
|
|
3080
|
+
});
|
|
3081
|
+
}
|
|
3082
|
+
async function listarArquivosImpacto(contexto, opcoes) {
|
|
3083
|
+
const opcoesResolvidas = resolverOpcoesDrift(opcoes);
|
|
3084
|
+
const arquivos = new Set(filtrarCaminhosEscopoReal(contexto.arquivosProjeto, contexto, opcoesResolvidas));
|
|
3085
|
+
for (const diretorio of resolverDiretoriosCodigoEscopoReal(contexto, opcoesResolvidas)) {
|
|
3086
|
+
for (const arquivo of await listarArquivosRecursivos(diretorio, EXTENSOES_BUSCA_IMPACTO)) {
|
|
3087
|
+
arquivos.add(arquivo);
|
|
2336
3088
|
}
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
3089
|
+
}
|
|
3090
|
+
return [...arquivos].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
3091
|
+
}
|
|
3092
|
+
function extrairLinhasComVariantes(codigo, variantes) {
|
|
3093
|
+
const linhas = [];
|
|
3094
|
+
const texto = codigo.split(/\r?\n/);
|
|
3095
|
+
for (let indice = 0; indice < texto.length; indice += 1) {
|
|
3096
|
+
if (variantes.some((variante) => variante && texto[indice].includes(variante))) {
|
|
3097
|
+
linhas.push(indice + 1);
|
|
2344
3098
|
}
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
3099
|
+
}
|
|
3100
|
+
return linhas;
|
|
3101
|
+
}
|
|
3102
|
+
function serializarTaskParaImpacto(task) {
|
|
3103
|
+
return JSON.stringify({
|
|
3104
|
+
nome: task.nome,
|
|
3105
|
+
input: task.input.map((campo) => campo.nome),
|
|
3106
|
+
output: task.output.map((campo) => campo.nome),
|
|
3107
|
+
effects: task.effects,
|
|
3108
|
+
guarantees: task.guarantees,
|
|
3109
|
+
errors: task.errors,
|
|
3110
|
+
resumo: task.resumoAgente,
|
|
3111
|
+
});
|
|
3112
|
+
}
|
|
3113
|
+
function serializarRouteParaImpacto(route) {
|
|
3114
|
+
return JSON.stringify({
|
|
3115
|
+
nome: route.nome,
|
|
3116
|
+
caminho: route.caminho,
|
|
3117
|
+
metodo: route.metodo,
|
|
3118
|
+
task: route.task,
|
|
3119
|
+
input: route.inputPublico.map((campo) => campo.nome),
|
|
3120
|
+
output: route.outputPublico.map((campo) => campo.nome),
|
|
3121
|
+
});
|
|
3122
|
+
}
|
|
3123
|
+
function serializarSuperficieParaImpacto(superficie) {
|
|
3124
|
+
return JSON.stringify({
|
|
3125
|
+
tipo: superficie.tipo,
|
|
3126
|
+
nome: superficie.nome,
|
|
3127
|
+
task: superficie.task,
|
|
3128
|
+
input: superficie.input.map((campo) => campo.nome),
|
|
3129
|
+
output: superficie.output.map((campo) => campo.nome),
|
|
3130
|
+
});
|
|
3131
|
+
}
|
|
3132
|
+
function ordenarArquivosImpacto(arquivos) {
|
|
3133
|
+
const ordemPrioridade = { alta: 0, media: 1, baixa: 2 };
|
|
3134
|
+
return [...arquivos].sort((a, b) => ordemPrioridade[a.prioridade] - ordemPrioridade[b.prioridade]
|
|
3135
|
+
|| a.tipo.localeCompare(b.tipo, "pt-BR")
|
|
3136
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR"));
|
|
3137
|
+
}
|
|
3138
|
+
export async function gerarMapaImpactoSemantico(contexto, alvoSemantico, mudancaProposta, opcoes) {
|
|
3139
|
+
const opcoesResolvidas = resolverOpcoesDrift(opcoes);
|
|
3140
|
+
const diretoriosIgnoradosAnteriores = diretoriosIgnoradosAtivos;
|
|
3141
|
+
diretoriosIgnoradosAtivos = resolverDiretoriosIgnoradosAtivos(opcoesResolvidas);
|
|
3142
|
+
try {
|
|
3143
|
+
const drift = await analisarDriftLegado(contexto, opcoesResolvidas);
|
|
3144
|
+
const variantes = construirVariantesSemanticas(alvoSemantico);
|
|
3145
|
+
const termos = [...new Set([...quebrarTermosEscopo(alvoSemantico), ...drift.escopo_aplicado.termosEscopo])];
|
|
3146
|
+
const arquivosImpactados = new Map();
|
|
3147
|
+
const arquivosBusca = await listarArquivosImpacto(contexto, opcoesResolvidas);
|
|
3148
|
+
for (const arquivo of arquivosBusca) {
|
|
3149
|
+
const codigo = await readFile(arquivo, "utf8");
|
|
3150
|
+
const linhas = extrairLinhasComVariantes(codigo, variantes);
|
|
3151
|
+
if (linhas.length > 0) {
|
|
3152
|
+
registrarArquivoImpactado(arquivosImpactados, arquivo, linhas, ["token_semantico_encontrado"]);
|
|
3153
|
+
}
|
|
2352
3154
|
}
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
3155
|
+
const tasksAfetadas = new Set();
|
|
3156
|
+
const routesAfetadas = new Set();
|
|
3157
|
+
const superficiesAfetadas = new Set();
|
|
3158
|
+
const persistenciaAfetada = new Set();
|
|
3159
|
+
for (const item of contexto.modulosSelecionados) {
|
|
3160
|
+
const ir = item.resultado.ir;
|
|
3161
|
+
if (!ir) {
|
|
3162
|
+
continue;
|
|
3163
|
+
}
|
|
3164
|
+
for (const task of ir.tasks) {
|
|
3165
|
+
if (textoIrCombinaTermos(serializarTaskParaImpacto(task), termos)) {
|
|
3166
|
+
tasksAfetadas.add(`${ir.nome}.${task.nome}`);
|
|
3167
|
+
}
|
|
3168
|
+
}
|
|
3169
|
+
for (const route of ir.routes) {
|
|
3170
|
+
if (textoIrCombinaTermos(serializarRouteParaImpacto(route), termos)) {
|
|
3171
|
+
routesAfetadas.add(`${ir.nome}.${route.nome}`);
|
|
3172
|
+
}
|
|
3173
|
+
}
|
|
3174
|
+
for (const superficie of ir.superficies) {
|
|
3175
|
+
if (textoIrCombinaTermos(serializarSuperficieParaImpacto(superficie), termos)) {
|
|
3176
|
+
superficiesAfetadas.add(`${ir.nome}.${superficie.tipo}.${superficie.nome}`);
|
|
3177
|
+
}
|
|
3178
|
+
}
|
|
2360
3179
|
}
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
task: resumo.task,
|
|
2366
|
-
mensagem: `Task "${resumo.task}" ainda nao declara audit explicita para operacao sensivel ou publica.`,
|
|
2367
|
-
});
|
|
3180
|
+
for (const task of drift.tasks.filter((item) => tasksAfetadas.has(`${item.modulo}.${item.task}`))) {
|
|
3181
|
+
for (const arquivo of task.arquivosProvaveisEditar) {
|
|
3182
|
+
registrarArquivoImpactado(arquivosImpactados, arquivo, [], ["arquivo_relacionado_por_drift"]);
|
|
3183
|
+
}
|
|
2368
3184
|
}
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
}
|
|
3185
|
+
for (const item of drift.persistencia_real) {
|
|
3186
|
+
if (textoIrCombinaTermos(`${item.alvo} ${item.task} ${item.colunas.join(" ")}`, termos)) {
|
|
3187
|
+
persistenciaAfetada.add(`${item.task}:${item.alvo}`);
|
|
3188
|
+
for (const arquivo of [...item.arquivos, ...item.repositorios]) {
|
|
3189
|
+
registrarArquivoImpactado(arquivosImpactados, arquivo, [], ["persistencia_relacionada"]);
|
|
3190
|
+
}
|
|
3191
|
+
}
|
|
2376
3192
|
}
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2383
|
-
|
|
3193
|
+
const contratosAfetados = ordenarArquivosImpacto([...arquivosImpactados.values()].filter((arquivo) => arquivo.tipo === "contrato")).map((arquivo) => arquivo.arquivo);
|
|
3194
|
+
return {
|
|
3195
|
+
comando: "impacto",
|
|
3196
|
+
sucesso: arquivosImpactados.size > 0 || tasksAfetadas.size > 0 || persistenciaAfetada.size > 0,
|
|
3197
|
+
escopo: drift.escopo_aplicado.escopo,
|
|
3198
|
+
alvoSemantico,
|
|
3199
|
+
mudancaProposta,
|
|
3200
|
+
contratosAfetados,
|
|
3201
|
+
tasksAfetadas: [...tasksAfetadas].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
3202
|
+
routesAfetadas: [...routesAfetadas].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
3203
|
+
superficiesAfetadas: [...superficiesAfetadas].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
3204
|
+
persistenciaAfetada: [...persistenciaAfetada].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
3205
|
+
arquivos: ordenarArquivosImpacto([...arquivosImpactados.values()]),
|
|
3206
|
+
ordemOperacional: [
|
|
3207
|
+
"Atualizar contrato .sema e revisar garantias publicas primeiro.",
|
|
3208
|
+
"Ajustar persistencia e repositorios concretos antes de materializacao externa.",
|
|
3209
|
+
"Revisar rotas, workers e bridges depois que o contrato e o storage estiverem coerentes.",
|
|
3210
|
+
"Fechar com UI/consumidores e testes alinhados ao payload final.",
|
|
3211
|
+
],
|
|
3212
|
+
validacoes: [
|
|
3213
|
+
"Rodar sema validar no contrato alterado.",
|
|
3214
|
+
"Rodar sema drift com o mesmo escopo apos a mudanca.",
|
|
3215
|
+
"Revalidar testes de payload, persistencia e superficies publicas.",
|
|
3216
|
+
],
|
|
3217
|
+
};
|
|
3218
|
+
}
|
|
3219
|
+
finally {
|
|
3220
|
+
diretoriosIgnoradosAtivos = diretoriosIgnoradosAnteriores;
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
export async function assistirRenomeacaoSemantica(contexto, nomeAtual, nomeNovo, opcoes) {
|
|
3224
|
+
const impacto = await gerarMapaImpactoSemantico(contexto, nomeAtual, `renomear ${nomeAtual} para ${nomeNovo}`, opcoes);
|
|
3225
|
+
const variantesAntigas = construirVariantesSemanticas(nomeAtual);
|
|
3226
|
+
const variantesNovas = construirVariantesSemanticas(nomeNovo);
|
|
3227
|
+
const mapaSubstituicao = new Map();
|
|
3228
|
+
variantesAntigas.forEach((antiga, indice) => {
|
|
3229
|
+
mapaSubstituicao.set(antiga, variantesNovas[indice] ?? nomeNovo);
|
|
3230
|
+
});
|
|
3231
|
+
const sugestoes = [];
|
|
3232
|
+
for (const arquivo of impacto.arquivos) {
|
|
3233
|
+
const codigo = await readFile(arquivo.arquivo, "utf8");
|
|
3234
|
+
const linhas = codigo.split(/\r?\n/);
|
|
3235
|
+
for (let indice = 0; indice < linhas.length; indice += 1) {
|
|
3236
|
+
const linha = linhas[indice];
|
|
3237
|
+
for (const antiga of variantesAntigas) {
|
|
3238
|
+
if (!antiga || !linha.includes(antiga)) {
|
|
3239
|
+
continue;
|
|
3240
|
+
}
|
|
3241
|
+
sugestoes.push({
|
|
3242
|
+
arquivo: arquivo.arquivo,
|
|
3243
|
+
linha: indice + 1,
|
|
3244
|
+
atual: antiga,
|
|
3245
|
+
sugerido: mapaSubstituicao.get(antiga) ?? nomeNovo,
|
|
3246
|
+
contexto: linha.trim().slice(0, 180),
|
|
3247
|
+
});
|
|
3248
|
+
}
|
|
2384
3249
|
}
|
|
2385
3250
|
}
|
|
2386
|
-
const consumerSurfaces = [...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
|
|
2387
|
-
|| a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
|
|
2388
|
-
|| a.arquivo.localeCompare(b.arquivo, "pt-BR"));
|
|
2389
|
-
const consumerBridges = [...new Map([...indexTs.simbolos, ...indexDart.simbolos]
|
|
2390
|
-
.filter((simbolo) => simboloEhBridgeConsumer(simbolo.caminho, simbolo.arquivo))
|
|
2391
|
-
.map((simbolo) => [
|
|
2392
|
-
`${simbolo.caminho}:${simbolo.arquivo}:${simbolo.simbolo}`,
|
|
2393
|
-
{
|
|
2394
|
-
caminho: simbolo.caminho,
|
|
2395
|
-
arquivo: simbolo.arquivo,
|
|
2396
|
-
simbolo: simbolo.simbolo,
|
|
2397
|
-
},
|
|
2398
|
-
])).values()].sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR")
|
|
2399
|
-
|| a.arquivo.localeCompare(b.arquivo, "pt-BR"));
|
|
2400
|
-
const appRoutes = [...new Set(consumerSurfaces.map((surface) => surface.rota))]
|
|
2401
|
-
.sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
2402
|
-
const consumerFramework = inferirConsumerFrameworkPrincipal(contexto.fontesLegado, consumerSurfaces, consumerBridges);
|
|
2403
|
-
const payloadBase = {
|
|
2404
|
-
comando: "drift",
|
|
2405
|
-
sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0 && vinculosQuebrados.length === 0,
|
|
2406
|
-
consumerFramework,
|
|
2407
|
-
appRoutes,
|
|
2408
|
-
consumerSurfaces,
|
|
2409
|
-
consumerBridges,
|
|
2410
|
-
modulos: contexto.modulosSelecionados.map((item) => ({
|
|
2411
|
-
caminho: item.caminho,
|
|
2412
|
-
modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,
|
|
2413
|
-
tasks: item.resultado.ir?.tasks.length ?? 0,
|
|
2414
|
-
routes: item.resultado.ir?.routes.length ?? 0,
|
|
2415
|
-
})),
|
|
2416
|
-
tasks: tasksResumo,
|
|
2417
|
-
impls_validos: implsValidos,
|
|
2418
|
-
impls_quebrados: implsQuebrados,
|
|
2419
|
-
vinculos_validos: vinculosValidos,
|
|
2420
|
-
vinculos_quebrados: vinculosQuebrados,
|
|
2421
|
-
rotas_divergentes: rotasDivergentes,
|
|
2422
|
-
recursos_validos: recursosValidos,
|
|
2423
|
-
recursos_divergentes: recursosDivergentes,
|
|
2424
|
-
diagnosticos,
|
|
2425
|
-
resumo_operacional: {
|
|
2426
|
-
scoreMedio: 0,
|
|
2427
|
-
confiancaGeral: "baixa",
|
|
2428
|
-
riscosPrincipais: [],
|
|
2429
|
-
oQueTocar: [],
|
|
2430
|
-
oQueValidar: [],
|
|
2431
|
-
oQueEstaFrouxo: [],
|
|
2432
|
-
oQueFoiInferido: [],
|
|
2433
|
-
},
|
|
2434
|
-
};
|
|
2435
|
-
const resumoOperacional = resumirOperacional(payloadBase);
|
|
2436
3251
|
return {
|
|
2437
|
-
|
|
2438
|
-
|
|
3252
|
+
comando: "renomear-semantico",
|
|
3253
|
+
sucesso: sugestoes.length > 0,
|
|
3254
|
+
escopo: impacto.escopo,
|
|
3255
|
+
de: nomeAtual,
|
|
3256
|
+
para: nomeNovo,
|
|
3257
|
+
arquivos: impacto.arquivos,
|
|
3258
|
+
sugestoes,
|
|
3259
|
+
ordemOperacional: [
|
|
3260
|
+
"Renomear primeiro no contrato .sema e nos campos publicos derivados.",
|
|
3261
|
+
"Ajustar repositorios, payloads e bridges que materializam o nome antigo.",
|
|
3262
|
+
"Rodar sema drift e revisar sugestoes restantes antes de fechar a troca.",
|
|
3263
|
+
],
|
|
3264
|
+
validacoes: [
|
|
3265
|
+
"Rodar sema validar no contrato renomeado.",
|
|
3266
|
+
"Rodar sema drift para confirmar que payload e superficie nao ficaram misturados.",
|
|
3267
|
+
"Reexecutar testes e checar snapshots ou fixtures afetados.",
|
|
3268
|
+
],
|
|
2439
3269
|
};
|
|
2440
3270
|
}
|
|
2441
3271
|
//# sourceMappingURL=drift.js.map
|