@semacode/cli 0.8.8 → 0.9.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/README.md +2 -2
- package/dist/drift.d.ts +30 -1
- package/dist/drift.js +373 -17
- package/dist/drift.js.map +1 -1
- package/dist/index.js +139 -15
- package/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-dart/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/dist/ast/tipos.d.ts +14 -1
- package/node_modules/@sema/nucleo/dist/formatador/index.js +131 -22
- package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +546 -102
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +83 -5
- package/node_modules/@sema/nucleo/dist/lexer/lexer.js +1 -1
- package/node_modules/@sema/nucleo/dist/lexer/lexer.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js +10 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/parser/parser.js +230 -19
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +6 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +269 -10
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
- package/node_modules/@sema/nucleo/package.json +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ sema --help
|
|
|
20
20
|
## Instalacao via tarball da release
|
|
21
21
|
|
|
22
22
|
```bash
|
|
23
|
-
npm install -g ./sema-cli-0.
|
|
23
|
+
npm install -g ./sema-cli-0.9.0.tgz
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
Ou direto da GitHub Release:
|
|
@@ -39,7 +39,7 @@ npx sema --help
|
|
|
39
39
|
Ou, se voce estiver testando um tarball local:
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
npm install ./sema-cli-0.
|
|
42
|
+
npm install ./sema-cli-0.9.0.tgz
|
|
43
43
|
npx sema --help
|
|
44
44
|
```
|
|
45
45
|
|
package/dist/drift.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import type { NivelConfiancaSemantica, NivelRiscoSemantico } from "@sema/nucleo";
|
|
1
2
|
import type { ContextoProjetoCarregado } from "./projeto.js";
|
|
2
3
|
export interface DiagnosticoDrift {
|
|
3
|
-
tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente";
|
|
4
|
+
tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado";
|
|
4
5
|
modulo: string;
|
|
5
6
|
task?: string;
|
|
6
7
|
route?: string;
|
|
@@ -49,9 +50,26 @@ interface ResumoTaskDrift {
|
|
|
49
50
|
implsValidos: number;
|
|
50
51
|
implsQuebrados: number;
|
|
51
52
|
semImplementacao: boolean;
|
|
53
|
+
scoreSemantico: number;
|
|
54
|
+
confiancaVinculo: NivelConfiancaSemantica;
|
|
55
|
+
riscoOperacional: NivelRiscoSemantico;
|
|
56
|
+
lacunas: string[];
|
|
52
57
|
arquivosReferenciados: string[];
|
|
58
|
+
arquivosProvaveisEditar: string[];
|
|
53
59
|
simbolosReferenciados: string[];
|
|
54
60
|
candidatosImpl: SimboloCandidatoDrift[];
|
|
61
|
+
checksSugeridos: string[];
|
|
62
|
+
}
|
|
63
|
+
interface RegistroVinculoDrift {
|
|
64
|
+
modulo: string;
|
|
65
|
+
donoTipo: "modulo" | "task" | "flow" | "route" | "superficie";
|
|
66
|
+
dono: string;
|
|
67
|
+
tipo: string;
|
|
68
|
+
valor: string;
|
|
69
|
+
arquivo?: string;
|
|
70
|
+
simbolo?: string;
|
|
71
|
+
status: "resolvido" | "parcial" | "nao_encontrado";
|
|
72
|
+
confianca: NivelConfiancaSemantica;
|
|
55
73
|
}
|
|
56
74
|
export interface ResultadoDrift {
|
|
57
75
|
comando: "drift";
|
|
@@ -65,9 +83,20 @@ export interface ResultadoDrift {
|
|
|
65
83
|
tasks: ResumoTaskDrift[];
|
|
66
84
|
impls_validos: RegistroImplDrift[];
|
|
67
85
|
impls_quebrados: RegistroImplDrift[];
|
|
86
|
+
vinculos_validos: RegistroVinculoDrift[];
|
|
87
|
+
vinculos_quebrados: RegistroVinculoDrift[];
|
|
68
88
|
rotas_divergentes: RegistroRotaDivergente[];
|
|
69
89
|
recursos_validos: RegistroRecursoDrift[];
|
|
70
90
|
recursos_divergentes: RegistroRecursoDrift[];
|
|
91
|
+
resumo_operacional: {
|
|
92
|
+
scoreMedio: number;
|
|
93
|
+
confiancaGeral: NivelConfiancaSemantica;
|
|
94
|
+
riscosPrincipais: string[];
|
|
95
|
+
oQueTocar: string[];
|
|
96
|
+
oQueValidar: string[];
|
|
97
|
+
oQueEstaFrouxo: string[];
|
|
98
|
+
oQueFoiInferido: string[];
|
|
99
|
+
};
|
|
71
100
|
diagnosticos: DiagnosticoDrift[];
|
|
72
101
|
}
|
|
73
102
|
export declare function analisarDriftLegado(contexto: ContextoProjetoCarregado): Promise<ResultadoDrift>;
|
package/dist/drift.js
CHANGED
|
@@ -25,6 +25,178 @@ const DIRETORIOS_IGNORADOS = new Set([
|
|
|
25
25
|
".tmp",
|
|
26
26
|
"generated",
|
|
27
27
|
]);
|
|
28
|
+
function normalizarFragmentoArquivo(valor) {
|
|
29
|
+
return valor.replace(/\\/g, "/").replace(/^\.?\//, "").trim().toLowerCase();
|
|
30
|
+
}
|
|
31
|
+
function escolherArquivoPorVinculo(arquivos, valor) {
|
|
32
|
+
const normalizado = normalizarFragmentoArquivo(valor);
|
|
33
|
+
const exato = arquivos.find((arquivo) => normalizarFragmentoArquivo(arquivo) === normalizado);
|
|
34
|
+
if (exato) {
|
|
35
|
+
return { arquivo: exato, confianca: "alta", status: "resolvido" };
|
|
36
|
+
}
|
|
37
|
+
const porSufixo = arquivos.find((arquivo) => normalizarFragmentoArquivo(arquivo).endsWith(normalizado));
|
|
38
|
+
if (porSufixo) {
|
|
39
|
+
return { arquivo: porSufixo, confianca: "media", status: "parcial" };
|
|
40
|
+
}
|
|
41
|
+
return { confianca: "baixa", status: "nao_encontrado" };
|
|
42
|
+
}
|
|
43
|
+
function escolherSimboloPorVinculo(simbolos, mapaImpl, valor) {
|
|
44
|
+
const exato = mapaImpl.get(valor);
|
|
45
|
+
if (exato) {
|
|
46
|
+
return { simbolo: exato, confianca: "alta", status: "resolvido" };
|
|
47
|
+
}
|
|
48
|
+
const ultimoSegmento = valor.split(".").at(-1)?.toLowerCase();
|
|
49
|
+
const aproximado = simbolos.find((simbolo) => simbolo.caminho.toLowerCase() === valor.toLowerCase()
|
|
50
|
+
|| simbolo.simbolo.toLowerCase() === ultimoSegmento
|
|
51
|
+
|| simbolo.caminho.toLowerCase().endsWith(`.${ultimoSegmento}`));
|
|
52
|
+
if (aproximado) {
|
|
53
|
+
return { simbolo: aproximado, confianca: "media", status: "parcial" };
|
|
54
|
+
}
|
|
55
|
+
return { confianca: "baixa", status: "nao_encontrado" };
|
|
56
|
+
}
|
|
57
|
+
function resolverArquivoOuSimboloAncora(vinculos, simbolos, mapaImpl, arquivos) {
|
|
58
|
+
for (const vinculo of vinculos) {
|
|
59
|
+
if (vinculo.simbolo) {
|
|
60
|
+
const resolucaoSimbolo = escolherSimboloPorVinculo(simbolos, mapaImpl, vinculo.simbolo);
|
|
61
|
+
if (resolucaoSimbolo.status !== "nao_encontrado") {
|
|
62
|
+
return {
|
|
63
|
+
arquivo: resolucaoSimbolo.simbolo?.arquivo,
|
|
64
|
+
simbolo: resolucaoSimbolo.simbolo?.simbolo,
|
|
65
|
+
confianca: resolucaoSimbolo.confianca,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (vinculo.arquivo) {
|
|
70
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(arquivos, vinculo.arquivo);
|
|
71
|
+
if (resolucaoArquivo.status !== "nao_encontrado") {
|
|
72
|
+
return {
|
|
73
|
+
arquivo: resolucaoArquivo.arquivo,
|
|
74
|
+
confianca: resolucaoArquivo.confianca,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return undefined;
|
|
80
|
+
}
|
|
81
|
+
function encontrarAncoraSuperficie(ir, superficie, simbolos, mapaImpl, arquivos) {
|
|
82
|
+
const ancoraDireta = resolverArquivoOuSimboloAncora(superficie.vinculos, simbolos, mapaImpl, arquivos);
|
|
83
|
+
if (ancoraDireta) {
|
|
84
|
+
return ancoraDireta;
|
|
85
|
+
}
|
|
86
|
+
for (const impl of superficie.implementacoesExternas) {
|
|
87
|
+
const resolvido = mapaImpl.get(impl.caminho);
|
|
88
|
+
if (resolvido) {
|
|
89
|
+
return {
|
|
90
|
+
arquivo: resolvido.arquivo,
|
|
91
|
+
simbolo: resolvido.simbolo,
|
|
92
|
+
confianca: "alta",
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
if (!superficie.task) {
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
const taskAssociada = ir.tasks.find((task) => task.nome === superficie.task);
|
|
100
|
+
if (!taskAssociada) {
|
|
101
|
+
return undefined;
|
|
102
|
+
}
|
|
103
|
+
const ancoraTask = resolverArquivoOuSimboloAncora(taskAssociada.vinculos, simbolos, mapaImpl, arquivos);
|
|
104
|
+
if (ancoraTask) {
|
|
105
|
+
return ancoraTask;
|
|
106
|
+
}
|
|
107
|
+
for (const impl of taskAssociada.implementacoesExternas) {
|
|
108
|
+
const resolvido = mapaImpl.get(impl.caminho);
|
|
109
|
+
if (resolvido) {
|
|
110
|
+
return {
|
|
111
|
+
arquivo: resolvido.arquivo,
|
|
112
|
+
simbolo: resolvido.simbolo,
|
|
113
|
+
confianca: "alta",
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return undefined;
|
|
118
|
+
}
|
|
119
|
+
function calcularRiscoOperacional(task) {
|
|
120
|
+
if (task.execucao.criticidadeOperacional === "alta"
|
|
121
|
+
|| task.execucao.criticidadeOperacional === "critica"
|
|
122
|
+
|| task.efeitosEstruturados.some((efeito) => efeito.categoria === "persistencia" || efeito.criticidade === "critica")) {
|
|
123
|
+
return "alto";
|
|
124
|
+
}
|
|
125
|
+
if (task.efeitosEstruturados.length > 0 || task.vinculos.length > 0 || task.errosDetalhados.length > 0) {
|
|
126
|
+
return "medio";
|
|
127
|
+
}
|
|
128
|
+
return "baixo";
|
|
129
|
+
}
|
|
130
|
+
function calcularConfiancaTask(task, implsValidos, implsQuebrados, vinculosValidos, vinculosQuebrados) {
|
|
131
|
+
if ((implsValidos > 0 || vinculosValidos > 0) && implsQuebrados === 0 && vinculosQuebrados === 0) {
|
|
132
|
+
return "alta";
|
|
133
|
+
}
|
|
134
|
+
if (implsValidos > 0 || vinculosValidos > 0 || task.implementacoesExternas.length > 0 || task.vinculos.length > 0) {
|
|
135
|
+
return "media";
|
|
136
|
+
}
|
|
137
|
+
return "baixa";
|
|
138
|
+
}
|
|
139
|
+
function calcularScoreTask(task, implsValidos, implsQuebrados, vinculosValidos, vinculosQuebrados, semImplementacao) {
|
|
140
|
+
let score = 45;
|
|
141
|
+
if (!semImplementacao && task.implementacoesExternas.length > 0) {
|
|
142
|
+
score += 15;
|
|
143
|
+
}
|
|
144
|
+
score += Math.min(implsValidos * 10, 20);
|
|
145
|
+
score -= Math.min(implsQuebrados * 20, 30);
|
|
146
|
+
score += Math.min(vinculosValidos * 5, 15);
|
|
147
|
+
score -= Math.min(vinculosQuebrados * 10, 20);
|
|
148
|
+
if (task.guarantees.length > 0) {
|
|
149
|
+
score += 5;
|
|
150
|
+
}
|
|
151
|
+
if (task.execucao.explicita) {
|
|
152
|
+
score += 5;
|
|
153
|
+
}
|
|
154
|
+
return Math.max(0, Math.min(100, score));
|
|
155
|
+
}
|
|
156
|
+
function resumirLacunasTask(task, semImplementacao, implsQuebrados, vinculosQuebrados) {
|
|
157
|
+
const lacunas = [];
|
|
158
|
+
if (semImplementacao) {
|
|
159
|
+
lacunas.push("sem_impl");
|
|
160
|
+
}
|
|
161
|
+
if (implsQuebrados > 0) {
|
|
162
|
+
lacunas.push("impl_quebrado");
|
|
163
|
+
}
|
|
164
|
+
if (task.vinculos.length === 0) {
|
|
165
|
+
lacunas.push("sem_vinculos");
|
|
166
|
+
}
|
|
167
|
+
if (vinculosQuebrados > 0) {
|
|
168
|
+
lacunas.push("vinculo_quebrado");
|
|
169
|
+
}
|
|
170
|
+
if (!task.execucao.explicita) {
|
|
171
|
+
lacunas.push("execucao_implicita");
|
|
172
|
+
}
|
|
173
|
+
return lacunas;
|
|
174
|
+
}
|
|
175
|
+
function resumirOperacional(resultado) {
|
|
176
|
+
const scoreMedio = resultado.tasks.length > 0
|
|
177
|
+
? Math.round(resultado.tasks.reduce((total, task) => total + task.scoreSemantico, 0) / resultado.tasks.length)
|
|
178
|
+
: 0;
|
|
179
|
+
const confiancaGeral = scoreMedio >= 80 ? "alta" : scoreMedio >= 55 ? "media" : "baixa";
|
|
180
|
+
const riscosPrincipais = [...new Set(resultado.tasks.filter((task) => task.riscoOperacional !== "baixo").map((task) => `${task.task}:${task.riscoOperacional}`))];
|
|
181
|
+
const oQueTocar = [...new Set(resultado.tasks.flatMap((task) => task.arquivosProvaveisEditar))].slice(0, 20);
|
|
182
|
+
const oQueValidar = [...new Set(resultado.tasks.flatMap((task) => task.checksSugeridos))];
|
|
183
|
+
const oQueEstaFrouxo = [...new Set(resultado.tasks.flatMap((task) => task.lacunas))];
|
|
184
|
+
const oQueFoiInferido = [
|
|
185
|
+
...new Set([
|
|
186
|
+
...resultado.impls_quebrados.flatMap((impl) => impl.candidatos?.map((candidato) => candidato.caminho) ?? []),
|
|
187
|
+
...resultado.vinculos_quebrados.filter((vinculo) => vinculo.status === "parcial").map((vinculo) => `${vinculo.dono}:${vinculo.valor}`),
|
|
188
|
+
]),
|
|
189
|
+
];
|
|
190
|
+
return {
|
|
191
|
+
scoreMedio,
|
|
192
|
+
confiancaGeral,
|
|
193
|
+
riscosPrincipais,
|
|
194
|
+
oQueTocar,
|
|
195
|
+
oQueValidar,
|
|
196
|
+
oQueEstaFrouxo,
|
|
197
|
+
oQueFoiInferido,
|
|
198
|
+
};
|
|
199
|
+
}
|
|
28
200
|
function paraIdentificadorModulo(valor) {
|
|
29
201
|
return valor
|
|
30
202
|
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
@@ -174,10 +346,10 @@ async function indexarTypeScript(diretorios) {
|
|
|
174
346
|
});
|
|
175
347
|
}
|
|
176
348
|
for (const node of sourceFile.statements) {
|
|
177
|
-
if (ts.isFunctionDeclaration(node) && node.name
|
|
349
|
+
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
178
350
|
registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, node.name.text);
|
|
179
351
|
}
|
|
180
|
-
if (ts.isVariableStatement(node)
|
|
352
|
+
if (ts.isVariableStatement(node)) {
|
|
181
353
|
for (const declaracao of node.declarationList.declarations) {
|
|
182
354
|
if (!ts.isIdentifier(declaracao.name) || !declaracao.initializer) {
|
|
183
355
|
continue;
|
|
@@ -196,21 +368,19 @@ async function indexarTypeScript(diretorios) {
|
|
|
196
368
|
if (!ts.isMethodDeclaration(member) || !member.name) {
|
|
197
369
|
continue;
|
|
198
370
|
}
|
|
199
|
-
if (member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
200
|
-
continue;
|
|
201
|
-
}
|
|
202
371
|
const nomeMetodo = member.name.getText(sourceFile);
|
|
203
372
|
if (nomeMetodo === "constructor") {
|
|
204
373
|
continue;
|
|
205
374
|
}
|
|
206
375
|
registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, nomeMetodo, node.name.text);
|
|
376
|
+
const metodoEhInterno = member.modifiers?.some((m) => m.kind === ts.SyntaxKind.PrivateKeyword || m.kind === ts.SyntaxKind.ProtectedKeyword);
|
|
207
377
|
for (const baseSimbolica of basesSimbolicas) {
|
|
208
378
|
const caminhoMetodoDireto = `${baseSimbolica}.${nomeMetodo}`;
|
|
209
379
|
if (!simbolos.has(caminhoMetodoDireto)) {
|
|
210
380
|
simbolos.set(caminhoMetodoDireto, { origem: "ts", caminho: caminhoMetodoDireto, arquivo, simbolo: nomeMetodo });
|
|
211
381
|
}
|
|
212
382
|
}
|
|
213
|
-
if (controllerDecorator) {
|
|
383
|
+
if (controllerDecorator && !metodoEhInterno) {
|
|
214
384
|
const httpDecorator = lerDecorator(member, ["Get", "Post", "Put", "Patch", "Delete"]);
|
|
215
385
|
if (httpDecorator) {
|
|
216
386
|
rotas.push({
|
|
@@ -483,7 +653,7 @@ function normalizarCaminhoRota(caminho) {
|
|
|
483
653
|
if (!caminho) {
|
|
484
654
|
return "/";
|
|
485
655
|
}
|
|
486
|
-
const limpo = normalizarCaminhoFlask(caminho.trim());
|
|
656
|
+
const limpo = normalizarCaminhoFlask(caminho.trim().replace(/\s*\/\s*/g, "/"));
|
|
487
657
|
const comBarra = limpo.startsWith("/") ? limpo : `/${limpo}`;
|
|
488
658
|
const normalizado = comBarra.replace(/\/+/g, "/");
|
|
489
659
|
return normalizado.endsWith("/") && normalizado !== "/" ? normalizado.slice(0, -1) : normalizado;
|
|
@@ -680,6 +850,15 @@ function extrairRecursosEsperados(task) {
|
|
|
680
850
|
alvo: efeito.alvo,
|
|
681
851
|
}));
|
|
682
852
|
}
|
|
853
|
+
function coletarVinculosIr(ir) {
|
|
854
|
+
return [
|
|
855
|
+
...ir.vinculos.map((vinculo) => ({ donoTipo: "modulo", dono: ir.nome, vinculo })),
|
|
856
|
+
...ir.tasks.flatMap((task) => task.vinculos.map((vinculo) => ({ donoTipo: "task", dono: task.nome, vinculo }))),
|
|
857
|
+
...ir.flows.flatMap((flow) => flow.vinculos.map((vinculo) => ({ donoTipo: "flow", dono: flow.nome, vinculo }))),
|
|
858
|
+
...ir.routes.flatMap((route) => route.vinculos.map((vinculo) => ({ donoTipo: "route", dono: route.nome, vinculo }))),
|
|
859
|
+
...ir.superficies.flatMap((superficie) => superficie.vinculos.map((vinculo) => ({ donoTipo: "superficie", dono: `${superficie.tipo}:${superficie.nome}`, vinculo }))),
|
|
860
|
+
];
|
|
861
|
+
}
|
|
683
862
|
export async function analisarDriftLegado(contexto) {
|
|
684
863
|
const indexTs = await indexarTypeScript(contexto.diretoriosCodigo);
|
|
685
864
|
const indexPy = await indexarPython(contexto.diretoriosCodigo);
|
|
@@ -710,19 +889,38 @@ export async function analisarDriftLegado(contexto) {
|
|
|
710
889
|
...indexCpp.map((item) => [item.caminho, item]),
|
|
711
890
|
]);
|
|
712
891
|
const mapaRecursos = new Map(indexTs.recursos.map((item) => [item.nome, item]));
|
|
892
|
+
const todasRotasIndexadas = [
|
|
893
|
+
...indexTs.rotas,
|
|
894
|
+
...indexPy.rotas,
|
|
895
|
+
...indexDotnet.rotas,
|
|
896
|
+
...indexJava.rotas,
|
|
897
|
+
...indexGo.rotas,
|
|
898
|
+
...indexRust.rotas,
|
|
899
|
+
];
|
|
900
|
+
const todosArquivosConhecidos = [...new Set([
|
|
901
|
+
...todosSimbolos.map((item) => item.arquivo),
|
|
902
|
+
...todasRotasIndexadas.map((item) => item.arquivo),
|
|
903
|
+
...indexTs.recursos.map((item) => item.arquivo),
|
|
904
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
713
905
|
const implsValidos = [];
|
|
714
906
|
const implsQuebrados = [];
|
|
907
|
+
const vinculosValidos = [];
|
|
908
|
+
const vinculosQuebrados = [];
|
|
715
909
|
const rotasDivergentes = [];
|
|
716
910
|
const recursosValidos = [];
|
|
717
911
|
const recursosDivergentes = [];
|
|
718
912
|
const diagnosticos = [];
|
|
719
913
|
const tasksResumo = [];
|
|
914
|
+
const taskPorChave = new Map();
|
|
915
|
+
const resumoVinculosPorTask = new Map();
|
|
720
916
|
for (const item of contexto.modulosSelecionados) {
|
|
721
917
|
const ir = item.resultado.ir;
|
|
722
918
|
if (!ir) {
|
|
723
919
|
continue;
|
|
724
920
|
}
|
|
921
|
+
const superficiesPorChave = new Map(ir.superficies.map((superficie) => [`${superficie.tipo}:${superficie.nome}`, superficie]));
|
|
725
922
|
for (const task of ir.tasks) {
|
|
923
|
+
taskPorChave.set(`${ir.nome}:${task.nome}`, task);
|
|
726
924
|
let validos = 0;
|
|
727
925
|
let quebrados = 0;
|
|
728
926
|
const arquivosReferenciados = new Set();
|
|
@@ -779,9 +977,15 @@ export async function analisarDriftLegado(contexto) {
|
|
|
779
977
|
implsValidos: validos,
|
|
780
978
|
implsQuebrados: quebrados,
|
|
781
979
|
semImplementacao: task.implementacoesExternas.length === 0,
|
|
980
|
+
scoreSemantico: 0,
|
|
981
|
+
confiancaVinculo: "baixa",
|
|
982
|
+
riscoOperacional: "baixo",
|
|
983
|
+
lacunas: [],
|
|
782
984
|
arquivosReferenciados: [...arquivosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
985
|
+
arquivosProvaveisEditar: [],
|
|
783
986
|
simbolosReferenciados: [...simbolosReferenciados].sort((a, b) => a.localeCompare(b, "pt-BR")),
|
|
784
987
|
candidatosImpl: ordenarCandidatos([...candidatosTask.values()]).slice(0, 5),
|
|
988
|
+
checksSugeridos: [],
|
|
785
989
|
});
|
|
786
990
|
for (const recursoEsperado of extrairRecursosEsperados(task)) {
|
|
787
991
|
const resolvido = mapaRecursos.get(recursoEsperado.alvo);
|
|
@@ -821,22 +1025,33 @@ export async function analisarDriftLegado(contexto) {
|
|
|
821
1025
|
effects: [],
|
|
822
1026
|
efeitosEstruturados: [],
|
|
823
1027
|
implementacoesExternas: [],
|
|
1028
|
+
vinculos: [],
|
|
1029
|
+
execucao: {
|
|
1030
|
+
idempotencia: false,
|
|
1031
|
+
timeout: "padrao",
|
|
1032
|
+
retry: "nenhum",
|
|
1033
|
+
compensacao: "nenhuma",
|
|
1034
|
+
criticidadeOperacional: "media",
|
|
1035
|
+
explicita: false,
|
|
1036
|
+
},
|
|
824
1037
|
guarantees: [],
|
|
825
1038
|
garantiasEstruturadas: [],
|
|
826
1039
|
errors: {},
|
|
1040
|
+
errosDetalhados: [],
|
|
1041
|
+
perfilCompatibilidade: "interno",
|
|
1042
|
+
resumoAgente: {
|
|
1043
|
+
riscos: [],
|
|
1044
|
+
checks: [],
|
|
1045
|
+
entidadesAfetadas: [],
|
|
1046
|
+
superficiesPublicas: [],
|
|
1047
|
+
mutacoesPrevistas: [],
|
|
1048
|
+
},
|
|
827
1049
|
tests: [],
|
|
828
1050
|
}, contexto.fontesLegado);
|
|
829
1051
|
if (!esperadas.length || !route.metodo || !route.caminho) {
|
|
830
1052
|
continue;
|
|
831
1053
|
}
|
|
832
|
-
const encontradas =
|
|
833
|
-
...indexTs.rotas,
|
|
834
|
-
...indexPy.rotas,
|
|
835
|
-
...indexDotnet.rotas,
|
|
836
|
-
...indexJava.rotas,
|
|
837
|
-
...indexGo.rotas,
|
|
838
|
-
...indexRust.rotas,
|
|
839
|
-
].filter((rotaResolvida) => esperadas.includes(rotaResolvida.origem));
|
|
1054
|
+
const encontradas = todasRotasIndexadas.filter((rotaResolvida) => esperadas.includes(rotaResolvida.origem));
|
|
840
1055
|
const combina = encontradas.some((rotaResolvida) => rotaResolvida.metodo === route.metodo
|
|
841
1056
|
&& normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(route.caminho));
|
|
842
1057
|
if (!combina) {
|
|
@@ -856,10 +1071,135 @@ export async function analisarDriftLegado(contexto) {
|
|
|
856
1071
|
});
|
|
857
1072
|
}
|
|
858
1073
|
}
|
|
1074
|
+
for (const itemVinculo of coletarVinculosIr(ir)) {
|
|
1075
|
+
const registro = {
|
|
1076
|
+
modulo: ir.nome,
|
|
1077
|
+
donoTipo: itemVinculo.donoTipo,
|
|
1078
|
+
dono: itemVinculo.dono,
|
|
1079
|
+
tipo: itemVinculo.vinculo.tipo,
|
|
1080
|
+
valor: itemVinculo.vinculo.valor,
|
|
1081
|
+
status: "nao_encontrado",
|
|
1082
|
+
confianca: "baixa",
|
|
1083
|
+
};
|
|
1084
|
+
const arquivoDeclarado = itemVinculo.vinculo.arquivo ?? (itemVinculo.vinculo.tipo === "arquivo" ? itemVinculo.vinculo.valor : undefined);
|
|
1085
|
+
const simboloDeclarado = itemVinculo.vinculo.simbolo ?? (itemVinculo.vinculo.tipo === "simbolo" ? itemVinculo.vinculo.valor : undefined);
|
|
1086
|
+
const recursoDeclarado = itemVinculo.vinculo.recurso ?? (["recurso", "tabela", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
1087
|
+
const superficieDeclarada = itemVinculo.vinculo.superficie ?? (["superficie", "rota", "worker", "cron", "webhook", "evento", "policy", "fila", "cache", "storage"].includes(itemVinculo.vinculo.tipo) ? itemVinculo.vinculo.valor : undefined);
|
|
1088
|
+
if (simboloDeclarado) {
|
|
1089
|
+
const resolucaoSimbolo = escolherSimboloPorVinculo(todosSimbolos, mapaImpl, simboloDeclarado);
|
|
1090
|
+
registro.status = resolucaoSimbolo.status;
|
|
1091
|
+
registro.confianca = resolucaoSimbolo.confianca;
|
|
1092
|
+
registro.arquivo = resolucaoSimbolo.simbolo?.arquivo;
|
|
1093
|
+
registro.simbolo = resolucaoSimbolo.simbolo?.simbolo;
|
|
1094
|
+
}
|
|
1095
|
+
else if (arquivoDeclarado) {
|
|
1096
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, arquivoDeclarado);
|
|
1097
|
+
registro.status = resolucaoArquivo.status;
|
|
1098
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
1099
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
1100
|
+
}
|
|
1101
|
+
else if (recursoDeclarado) {
|
|
1102
|
+
const recurso = mapaRecursos.get(recursoDeclarado);
|
|
1103
|
+
if (recurso) {
|
|
1104
|
+
registro.status = "resolvido";
|
|
1105
|
+
registro.confianca = "alta";
|
|
1106
|
+
registro.arquivo = recurso.arquivo;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
else if (superficieDeclarada) {
|
|
1110
|
+
const rota = todasRotasIndexadas.find((rotaResolvida) => normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(superficieDeclarada));
|
|
1111
|
+
if (rota) {
|
|
1112
|
+
registro.status = "resolvido";
|
|
1113
|
+
registro.confianca = "alta";
|
|
1114
|
+
registro.arquivo = rota.arquivo;
|
|
1115
|
+
registro.simbolo = rota.simbolo;
|
|
1116
|
+
}
|
|
1117
|
+
else {
|
|
1118
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, superficieDeclarada);
|
|
1119
|
+
registro.status = resolucaoArquivo.status;
|
|
1120
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
1121
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
else {
|
|
1125
|
+
const resolucaoArquivo = escolherArquivoPorVinculo(todosArquivosConhecidos, itemVinculo.vinculo.valor);
|
|
1126
|
+
registro.status = resolucaoArquivo.status;
|
|
1127
|
+
registro.confianca = resolucaoArquivo.confianca;
|
|
1128
|
+
registro.arquivo = resolucaoArquivo.arquivo;
|
|
1129
|
+
}
|
|
1130
|
+
if (registro.status === "nao_encontrado" && itemVinculo.donoTipo === "superficie") {
|
|
1131
|
+
const superficie = superficiesPorChave.get(itemVinculo.dono);
|
|
1132
|
+
const ancora = superficie
|
|
1133
|
+
? encontrarAncoraSuperficie(ir, superficie, todosSimbolos, mapaImpl, todosArquivosConhecidos)
|
|
1134
|
+
: undefined;
|
|
1135
|
+
if (ancora) {
|
|
1136
|
+
registro.status = "parcial";
|
|
1137
|
+
registro.confianca = ancora.confianca === "alta" ? "media" : ancora.confianca;
|
|
1138
|
+
registro.arquivo = registro.arquivo ?? ancora.arquivo;
|
|
1139
|
+
registro.simbolo = registro.simbolo ?? ancora.simbolo;
|
|
1140
|
+
}
|
|
1141
|
+
}
|
|
1142
|
+
if (registro.status === "nao_encontrado") {
|
|
1143
|
+
vinculosQuebrados.push(registro);
|
|
1144
|
+
diagnosticos.push({
|
|
1145
|
+
tipo: "vinculo_quebrado",
|
|
1146
|
+
modulo: ir.nome,
|
|
1147
|
+
mensagem: `Vinculo ${registro.tipo}="${registro.valor}" de ${registro.donoTipo} "${registro.dono}" nao foi resolvido no codigo vivo.`,
|
|
1148
|
+
...(itemVinculo.donoTipo === "task" ? { task: itemVinculo.dono } : itemVinculo.donoTipo === "route" ? { route: itemVinculo.dono } : {}),
|
|
1149
|
+
});
|
|
1150
|
+
}
|
|
1151
|
+
else {
|
|
1152
|
+
vinculosValidos.push(registro);
|
|
1153
|
+
}
|
|
1154
|
+
if (itemVinculo.donoTipo === "task") {
|
|
1155
|
+
const chaveTask = `${ir.nome}:${itemVinculo.dono}`;
|
|
1156
|
+
const resumo = resumoVinculosPorTask.get(chaveTask) ?? {
|
|
1157
|
+
validos: 0,
|
|
1158
|
+
quebrados: 0,
|
|
1159
|
+
arquivos: new Set(),
|
|
1160
|
+
};
|
|
1161
|
+
if (registro.status === "nao_encontrado") {
|
|
1162
|
+
resumo.quebrados += 1;
|
|
1163
|
+
}
|
|
1164
|
+
else {
|
|
1165
|
+
resumo.validos += 1;
|
|
1166
|
+
}
|
|
1167
|
+
if (registro.arquivo) {
|
|
1168
|
+
resumo.arquivos.add(registro.arquivo);
|
|
1169
|
+
}
|
|
1170
|
+
resumoVinculosPorTask.set(chaveTask, resumo);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
859
1173
|
}
|
|
860
|
-
|
|
1174
|
+
for (const resumo of tasksResumo) {
|
|
1175
|
+
const chaveTask = `${resumo.modulo}:${resumo.task}`;
|
|
1176
|
+
const task = taskPorChave.get(chaveTask);
|
|
1177
|
+
const resumoVinculos = resumoVinculosPorTask.get(chaveTask) ?? {
|
|
1178
|
+
validos: 0,
|
|
1179
|
+
quebrados: 0,
|
|
1180
|
+
arquivos: new Set(),
|
|
1181
|
+
};
|
|
1182
|
+
if (!task) {
|
|
1183
|
+
continue;
|
|
1184
|
+
}
|
|
1185
|
+
resumo.confiancaVinculo = calcularConfiancaTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados);
|
|
1186
|
+
resumo.riscoOperacional = calcularRiscoOperacional(task);
|
|
1187
|
+
resumo.lacunas = resumirLacunasTask(task, resumo.semImplementacao, resumo.implsQuebrados, resumoVinculos.quebrados);
|
|
1188
|
+
resumo.scoreSemantico = calcularScoreTask(task, resumo.implsValidos, resumo.implsQuebrados, resumoVinculos.validos, resumoVinculos.quebrados, resumo.semImplementacao);
|
|
1189
|
+
resumo.arquivosProvaveisEditar = [...new Set([
|
|
1190
|
+
...resumo.arquivosReferenciados,
|
|
1191
|
+
...resumo.candidatosImpl.map((candidato) => candidato.arquivo),
|
|
1192
|
+
...resumoVinculos.arquivos,
|
|
1193
|
+
])].sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
1194
|
+
resumo.checksSugeridos = [...new Set([
|
|
1195
|
+
...task.resumoAgente.checks,
|
|
1196
|
+
resumo.riscoOperacional !== "baixo" ? "revisar efeitos operacionais" : "",
|
|
1197
|
+
resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
|
|
1198
|
+
].filter(Boolean))];
|
|
1199
|
+
}
|
|
1200
|
+
const payloadBase = {
|
|
861
1201
|
comando: "drift",
|
|
862
|
-
sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0,
|
|
1202
|
+
sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0 && vinculosQuebrados.length === 0,
|
|
863
1203
|
modulos: contexto.modulosSelecionados.map((item) => ({
|
|
864
1204
|
caminho: item.caminho,
|
|
865
1205
|
modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,
|
|
@@ -869,10 +1209,26 @@ export async function analisarDriftLegado(contexto) {
|
|
|
869
1209
|
tasks: tasksResumo,
|
|
870
1210
|
impls_validos: implsValidos,
|
|
871
1211
|
impls_quebrados: implsQuebrados,
|
|
1212
|
+
vinculos_validos: vinculosValidos,
|
|
1213
|
+
vinculos_quebrados: vinculosQuebrados,
|
|
872
1214
|
rotas_divergentes: rotasDivergentes,
|
|
873
1215
|
recursos_validos: recursosValidos,
|
|
874
1216
|
recursos_divergentes: recursosDivergentes,
|
|
875
1217
|
diagnosticos,
|
|
1218
|
+
resumo_operacional: {
|
|
1219
|
+
scoreMedio: 0,
|
|
1220
|
+
confiancaGeral: "baixa",
|
|
1221
|
+
riscosPrincipais: [],
|
|
1222
|
+
oQueTocar: [],
|
|
1223
|
+
oQueValidar: [],
|
|
1224
|
+
oQueEstaFrouxo: [],
|
|
1225
|
+
oQueFoiInferido: [],
|
|
1226
|
+
},
|
|
1227
|
+
};
|
|
1228
|
+
const resumoOperacional = resumirOperacional(payloadBase);
|
|
1229
|
+
return {
|
|
1230
|
+
...payloadBase,
|
|
1231
|
+
resumo_operacional: resumoOperacional,
|
|
876
1232
|
};
|
|
877
1233
|
}
|
|
878
1234
|
//# sourceMappingURL=drift.js.map
|