@semacode/cli 0.9.0 → 1.1.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 +50 -0
- package/README.md +24 -3
- package/SEMA_BRIEF.curto.txt +9 -0
- package/SEMA_BRIEF.md +49 -0
- package/SEMA_BRIEF.micro.txt +7 -0
- package/SEMA_INDEX.json +501 -0
- package/dist/drift.d.ts +15 -0
- package/dist/drift.js +496 -5
- package/dist/drift.js.map +1 -1
- package/dist/importador.d.ts +1 -1
- package/dist/importador.js +681 -3
- package/dist/importador.js.map +1 -1
- package/dist/index.js +1578 -123
- package/dist/index.js.map +1 -1
- package/dist/projeto.js +49 -1
- package/dist/projeto.js.map +1 -1
- package/dist/tipos.d.ts +1 -1
- package/docs/AGENT_STARTER.md +40 -8
- package/docs/como-ensinar-a-sema-para-ia.md +17 -11
- package/docs/fluxo-pratico-ia-sema.md +42 -38
- package/docs/instalacao-e-primeiro-uso.md +196 -0
- package/docs/integracao-com-ia.md +228 -0
- package/docs/pagamento-ponta-a-ponta.md +155 -0
- package/docs/prompt-base-ia-sema.md +10 -3
- package/docs/sintaxe.md +267 -0
- package/exemplos/automacao.sema +107 -0
- package/exemplos/cadastro_usuario.sema +54 -0
- package/exemplos/calculadora.sema +78 -0
- package/exemplos/crud_simples.sema +89 -0
- package/exemplos/operacao_estrategia.sema +402 -0
- package/exemplos/pagamento.sema +222 -0
- package/exemplos/pagamento_dominio.sema +35 -0
- package/exemplos/testes_embutidos.sema +45 -0
- package/exemplos/tratamento_erro.sema +157 -0
- package/llms-full.txt +34 -0
- package/llms.txt +17 -0
- package/node_modules/@sema/gerador-dart/package.json +1 -1
- package/node_modules/@sema/gerador-python/dist/index.js +92 -10
- package/node_modules/@sema/gerador-python/dist/index.js.map +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/dist/index.js +47 -1
- package/node_modules/@sema/padroes/dist/index.js.map +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- package/package.json +15 -7
package/dist/drift.d.ts
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import type { NivelConfiancaSemantica, NivelRiscoSemantico } from "@sema/nucleo";
|
|
2
2
|
import type { ContextoProjetoCarregado } from "./projeto.js";
|
|
3
|
+
type ConsumerFramework = "nextjs-consumer" | "react-vite-consumer" | "angular-consumer" | "flutter-consumer";
|
|
4
|
+
interface RegistroConsumerSurfaceDrift {
|
|
5
|
+
rota: string;
|
|
6
|
+
arquivo: string;
|
|
7
|
+
tipoArquivo: string;
|
|
8
|
+
}
|
|
9
|
+
interface RegistroConsumerBridgeDrift {
|
|
10
|
+
caminho: string;
|
|
11
|
+
arquivo: string;
|
|
12
|
+
simbolo: string;
|
|
13
|
+
}
|
|
3
14
|
export interface DiagnosticoDrift {
|
|
4
15
|
tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado";
|
|
5
16
|
modulo: string;
|
|
@@ -74,6 +85,10 @@ interface RegistroVinculoDrift {
|
|
|
74
85
|
export interface ResultadoDrift {
|
|
75
86
|
comando: "drift";
|
|
76
87
|
sucesso: boolean;
|
|
88
|
+
consumerFramework: ConsumerFramework | null;
|
|
89
|
+
appRoutes: string[];
|
|
90
|
+
consumerSurfaces: RegistroConsumerSurfaceDrift[];
|
|
91
|
+
consumerBridges: RegistroConsumerBridgeDrift[];
|
|
77
92
|
modulos: Array<{
|
|
78
93
|
caminho: string;
|
|
79
94
|
modulo: string | null;
|
package/dist/drift.js
CHANGED
|
@@ -291,6 +291,335 @@ function registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, nome, no
|
|
|
291
291
|
});
|
|
292
292
|
}
|
|
293
293
|
}
|
|
294
|
+
function normalizarRelacaoConsumer(relacaoArquivo) {
|
|
295
|
+
return relacaoArquivo.replace(/\\/g, "/");
|
|
296
|
+
}
|
|
297
|
+
function normalizarSegmentoRotaConsumer(segmento) {
|
|
298
|
+
const opcionalCatchAll = segmento.match(/^\[\[\.\.\.([A-Za-z_]\w*)\]\]$/);
|
|
299
|
+
if (opcionalCatchAll) {
|
|
300
|
+
return `{${opcionalCatchAll[1]}}`;
|
|
301
|
+
}
|
|
302
|
+
const catchAll = segmento.match(/^\[\.\.\.([A-Za-z_]\w*)\]$/);
|
|
303
|
+
if (catchAll) {
|
|
304
|
+
return `{${catchAll[1]}}`;
|
|
305
|
+
}
|
|
306
|
+
const dinamico = segmento.match(/^\[([A-Za-z_]\w*)\]$/);
|
|
307
|
+
if (dinamico) {
|
|
308
|
+
return `{${dinamico[1]}}`;
|
|
309
|
+
}
|
|
310
|
+
return segmento;
|
|
311
|
+
}
|
|
312
|
+
function montarRotaConsumer(partes) {
|
|
313
|
+
const filtradas = partes
|
|
314
|
+
.filter((segmento) => segmento && segmento !== "index" && !/^\(.*\)$/.test(segmento) && !segmento.startsWith("@"))
|
|
315
|
+
.map(normalizarSegmentoRotaConsumer);
|
|
316
|
+
return filtradas.length > 0 ? `/${filtradas.join("/")}`.replace(/\/+/g, "/") : "/";
|
|
317
|
+
}
|
|
318
|
+
function arquivoEhBridgeNextJsConsumer(relacaoArquivo) {
|
|
319
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
320
|
+
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
321
|
+
}
|
|
322
|
+
function arquivoEhBridgeReactViteConsumer(relacaoArquivo) {
|
|
323
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
324
|
+
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
325
|
+
}
|
|
326
|
+
function arquivoEhBridgeAngularConsumer(relacaoArquivo) {
|
|
327
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
328
|
+
return /(?:^|\/)(?:src\/)?app\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|js)$/i.test(relacao);
|
|
329
|
+
}
|
|
330
|
+
function arquivoEhSuperficieNextJsConsumer(relacaoArquivo) {
|
|
331
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
332
|
+
return /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
333
|
+
}
|
|
334
|
+
function arquivoEhSuperficieReactViteConsumer(relacaoArquivo) {
|
|
335
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
336
|
+
return /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
337
|
+
|| /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
338
|
+
}
|
|
339
|
+
function arquivoEhRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
340
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
341
|
+
return /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
342
|
+
|| /from\s+["']react-router-dom["']|createBrowserRouter|RouterProvider|useRoutes\s*\(|<Routes\b|<Route\b/.test(codigo ?? "");
|
|
343
|
+
}
|
|
344
|
+
function arquivoEhRotasAngularConsumer(relacaoArquivo) {
|
|
345
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
346
|
+
return /(?:^|\/)(?:src\/)?app(?:\/.+)?\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
347
|
+
}
|
|
348
|
+
function arquivoEhRotasAngularConsumerRaiz(relacaoArquivo) {
|
|
349
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
350
|
+
return /(?:^|\/)(?:src\/)?app\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
351
|
+
}
|
|
352
|
+
function arquivoEhBridgeFlutterConsumer(relacaoArquivo) {
|
|
353
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
354
|
+
return /(?:^|\/)(?:lib\/)?(?:sema_consumer_bridge|api\/sema_contract_bridge|sema\/.+)\.dart$/i.test(relacao);
|
|
355
|
+
}
|
|
356
|
+
function arquivoEhSuperficieFlutterConsumer(relacaoArquivo) {
|
|
357
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
358
|
+
return /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(relacao)
|
|
359
|
+
|| /(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao);
|
|
360
|
+
}
|
|
361
|
+
function arquivoEhRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
362
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
363
|
+
return /(?:^|\/)(?:lib\/)?(?:router|app_router|routes)\.dart$/i.test(relacao)
|
|
364
|
+
|| /MaterialApp(?:\.router)?\s*\(|CupertinoApp(?:\.router)?\s*\(|GoRouter\s*\(/.test(codigo ?? "");
|
|
365
|
+
}
|
|
366
|
+
function inferirRotaNextJsConsumer(relacaoArquivo) {
|
|
367
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
368
|
+
const segmentos = relacao.split("/");
|
|
369
|
+
const indiceSrcApp = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "app");
|
|
370
|
+
const indiceApp = segmentos.findIndex((segmento) => segmento === "app");
|
|
371
|
+
const inicioApp = indiceSrcApp >= 0 ? indiceSrcApp + 2 : indiceApp >= 0 ? indiceApp + 1 : -1;
|
|
372
|
+
if (inicioApp < 0) {
|
|
373
|
+
return undefined;
|
|
374
|
+
}
|
|
375
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
376
|
+
const tipoArquivo = arquivoFinal.match(/^(page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/)?.[1];
|
|
377
|
+
if (!tipoArquivo) {
|
|
378
|
+
return undefined;
|
|
379
|
+
}
|
|
380
|
+
const caminhoAteArquivo = segmentos.slice(inicioApp, -1);
|
|
381
|
+
if (caminhoAteArquivo[0] === "api") {
|
|
382
|
+
return undefined;
|
|
383
|
+
}
|
|
384
|
+
return {
|
|
385
|
+
rota: montarRotaConsumer(caminhoAteArquivo),
|
|
386
|
+
arquivo: relacaoArquivo,
|
|
387
|
+
tipoArquivo,
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
function inferirRotaReactViteConsumer(relacaoArquivo) {
|
|
391
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
392
|
+
if (/(?:^|\/)(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao)) {
|
|
393
|
+
return {
|
|
394
|
+
rota: "/",
|
|
395
|
+
arquivo: relacaoArquivo,
|
|
396
|
+
tipoArquivo: "app",
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
const segmentos = relacao.split("/");
|
|
400
|
+
const indiceSrcPages = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "pages");
|
|
401
|
+
const indicePages = segmentos.findIndex((segmento) => segmento === "pages");
|
|
402
|
+
const inicioPages = indiceSrcPages >= 0 ? indiceSrcPages + 2 : indicePages >= 0 ? indicePages + 1 : -1;
|
|
403
|
+
if (inicioPages < 0) {
|
|
404
|
+
return undefined;
|
|
405
|
+
}
|
|
406
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
407
|
+
const nomeBase = arquivoFinal.replace(/\.(?:ts|tsx|js|jsx)$/i, "");
|
|
408
|
+
return {
|
|
409
|
+
rota: montarRotaConsumer([...segmentos.slice(inicioPages, -1), nomeBase]),
|
|
410
|
+
arquivo: relacaoArquivo,
|
|
411
|
+
tipoArquivo: "page",
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
function inferirRotaFlutterConsumer(relacaoArquivo) {
|
|
415
|
+
const relacao = normalizarRelacaoConsumer(relacaoArquivo);
|
|
416
|
+
if (!arquivoEhSuperficieFlutterConsumer(relacao)) {
|
|
417
|
+
return undefined;
|
|
418
|
+
}
|
|
419
|
+
if (/(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao)) {
|
|
420
|
+
return {
|
|
421
|
+
rota: "/",
|
|
422
|
+
arquivo: relacaoArquivo,
|
|
423
|
+
tipoArquivo: "app",
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
const segmentos = relacao.split("/");
|
|
427
|
+
const indiceLibScreens = segmentos.findIndex((segmento, indice) => segmento === "lib" && ["screens", "pages"].includes(segmentos[indice + 1] ?? ""));
|
|
428
|
+
const indiceScreens = segmentos.findIndex((segmento) => segmento === "screens" || segmento === "pages");
|
|
429
|
+
const inicio = indiceLibScreens >= 0 ? indiceLibScreens + 2 : indiceScreens >= 0 ? indiceScreens + 1 : -1;
|
|
430
|
+
if (inicio < 0) {
|
|
431
|
+
return undefined;
|
|
432
|
+
}
|
|
433
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
434
|
+
const nomeBase = arquivoFinal
|
|
435
|
+
.replace(/\.(?:dart)$/i, "")
|
|
436
|
+
.replace(/_(screen|page)$/i, "");
|
|
437
|
+
return {
|
|
438
|
+
rota: montarRotaConsumer([...segmentos.slice(inicio, -1), nomeBase]),
|
|
439
|
+
arquivo: relacaoArquivo,
|
|
440
|
+
tipoArquivo: "screen",
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function normalizarRotaDeclaradaConsumer(caminhoCru, prefixo = "/") {
|
|
444
|
+
const partesPrefixo = prefixo.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
445
|
+
const partesCaminho = (caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
446
|
+
return montarRotaConsumer([...partesPrefixo, ...partesCaminho]);
|
|
447
|
+
}
|
|
448
|
+
function resolverImportRelativoConsumer(relacaoArquivoBase, especificador) {
|
|
449
|
+
if (!especificador.startsWith(".")) {
|
|
450
|
+
return undefined;
|
|
451
|
+
}
|
|
452
|
+
const baseDir = path.posix.dirname(normalizarRelacaoConsumer(relacaoArquivoBase));
|
|
453
|
+
for (const sufixo of ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"]) {
|
|
454
|
+
const candidato = path.posix.normalize(path.posix.join(baseDir, `${especificador}${sufixo}`));
|
|
455
|
+
if (/\.(?:ts|tsx|js|jsx)$/i.test(candidato)) {
|
|
456
|
+
return candidato;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
return undefined;
|
|
460
|
+
}
|
|
461
|
+
function extrairImportsTypeScriptConsumer(relacaoArquivo, codigo) {
|
|
462
|
+
const imports = new Map();
|
|
463
|
+
for (const match of codigo.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*["']([^"']+)["']/g)) {
|
|
464
|
+
const arquivoImportado = resolverImportRelativoConsumer(relacaoArquivo, match[2]);
|
|
465
|
+
if (!arquivoImportado) {
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
for (const bruto of match[1].split(",")) {
|
|
469
|
+
const local = bruto.trim().split(/\s+as\s+/i).at(-1)?.trim();
|
|
470
|
+
if (local) {
|
|
471
|
+
imports.set(local, arquivoImportado);
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
for (const match of codigo.matchAll(/import\s+([A-Za-z_]\w*)\s+from\s*["']([^"']+)["']/g)) {
|
|
476
|
+
const arquivoImportado = resolverImportRelativoConsumer(relacaoArquivo, match[2]);
|
|
477
|
+
const local = match[1]?.trim();
|
|
478
|
+
if (arquivoImportado && local) {
|
|
479
|
+
imports.set(local, arquivoImportado);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
return imports;
|
|
483
|
+
}
|
|
484
|
+
function extrairRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
485
|
+
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
486
|
+
const rotas = new Map();
|
|
487
|
+
const registrar = (caminhoCru, componente) => {
|
|
488
|
+
const rota = normalizarRotaDeclaradaConsumer(caminhoCru);
|
|
489
|
+
const chave = `${rota}:${normalizarRelacaoConsumer(relacaoArquivo)}:${componente ?? "router"}`;
|
|
490
|
+
rotas.set(chave, {
|
|
491
|
+
rota,
|
|
492
|
+
arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
|
|
493
|
+
arquivoComponente: componente ? imports.get(componente) : undefined,
|
|
494
|
+
});
|
|
495
|
+
};
|
|
496
|
+
for (const match of codigo.matchAll(/(?:path\s*:\s*["'`]([^"'`]*)["'`]|index\s*:\s*true)[\s\S]{0,260}?(?:element\s*:\s*<\s*([A-Za-z_]\w*)|Component\s*:\s*([A-Za-z_]\w*))/g)) {
|
|
497
|
+
const caminhoCru = match[1] ?? "";
|
|
498
|
+
const componente = match[2] ?? match[3];
|
|
499
|
+
registrar(caminhoCru, componente);
|
|
500
|
+
}
|
|
501
|
+
for (const match of codigo.matchAll(/<Route\b[^>]*?(?:path=["'`]([^"'`]*)["'`][^>]*?)?(index\b)?[^>]*?(?:element=\{\s*<\s*([A-Za-z_]\w*)|Component=\{\s*([A-Za-z_]\w*))/g)) {
|
|
502
|
+
const caminhoCru = match[2] ? "" : (match[1] ?? "");
|
|
503
|
+
const componente = match[3] ?? match[4];
|
|
504
|
+
registrar(caminhoCru, componente);
|
|
505
|
+
}
|
|
506
|
+
return [...rotas.values()];
|
|
507
|
+
}
|
|
508
|
+
function normalizarRotaDeclaradaFlutter(caminhoCru) {
|
|
509
|
+
return montarRotaConsumer((caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean));
|
|
510
|
+
}
|
|
511
|
+
function extrairRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
512
|
+
const rotas = new Map();
|
|
513
|
+
const registrar = (caminhoCru) => {
|
|
514
|
+
const rota = normalizarRotaDeclaradaFlutter(caminhoCru);
|
|
515
|
+
rotas.set(`${rota}:${normalizarRelacaoConsumer(relacaoArquivo)}`, {
|
|
516
|
+
rota,
|
|
517
|
+
arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
|
|
518
|
+
});
|
|
519
|
+
};
|
|
520
|
+
for (const match of codigo.matchAll(/GoRoute\s*\([\s\S]{0,220}?path\s*:\s*["'`]([^"'`]+)["'`]/g)) {
|
|
521
|
+
registrar(match[1] ?? "");
|
|
522
|
+
}
|
|
523
|
+
for (const match of codigo.matchAll(/["'`]([^"'`]+)["'`]\s*:\s*\([^)]*\)\s*=>/g)) {
|
|
524
|
+
registrar(match[1] ?? "");
|
|
525
|
+
}
|
|
526
|
+
if (/home\s*:\s*(?:const\s+)?[A-Za-z_]\w*\(/.test(codigo)) {
|
|
527
|
+
registrar("/");
|
|
528
|
+
}
|
|
529
|
+
return [...rotas.values()];
|
|
530
|
+
}
|
|
531
|
+
function extrairRotasAngularConsumerDiretas(relacaoArquivo, codigo, prefixo = "/") {
|
|
532
|
+
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
533
|
+
const rotas = [];
|
|
534
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?component\s*:\s*([A-Za-z_]\w*)/g)) {
|
|
535
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
536
|
+
const componente = match[2];
|
|
537
|
+
rotas.push({
|
|
538
|
+
rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
539
|
+
arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
|
|
540
|
+
componente,
|
|
541
|
+
arquivoComponente: imports.get(componente),
|
|
542
|
+
});
|
|
543
|
+
}
|
|
544
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?loadComponent\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
545
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
546
|
+
const arquivoComponente = resolverImportRelativoConsumer(relacaoArquivo, match[2] ?? "");
|
|
547
|
+
rotas.push({
|
|
548
|
+
rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
549
|
+
arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
|
|
550
|
+
arquivoComponente,
|
|
551
|
+
});
|
|
552
|
+
}
|
|
553
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,360}?loadChildren\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
554
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
555
|
+
const arquivoRotasFilhas = resolverImportRelativoConsumer(relacaoArquivo, match[2] ?? "");
|
|
556
|
+
rotas.push({
|
|
557
|
+
rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
558
|
+
arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
|
|
559
|
+
arquivoRotasFilhas,
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
return rotas;
|
|
563
|
+
}
|
|
564
|
+
async function extrairRotasAngularConsumer(diretorioBase, relacaoArquivo, prefixo = "/", visitados = new Set()) {
|
|
565
|
+
const relacaoNormalizada = normalizarRelacaoConsumer(relacaoArquivo);
|
|
566
|
+
if (visitados.has(relacaoNormalizada)) {
|
|
567
|
+
return [];
|
|
568
|
+
}
|
|
569
|
+
visitados.add(relacaoNormalizada);
|
|
570
|
+
let codigo = "";
|
|
571
|
+
try {
|
|
572
|
+
codigo = await readFile(path.join(diretorioBase, relacaoNormalizada), "utf8");
|
|
573
|
+
}
|
|
574
|
+
catch {
|
|
575
|
+
return [];
|
|
576
|
+
}
|
|
577
|
+
const rotas = extrairRotasAngularConsumerDiretas(relacaoNormalizada, codigo, prefixo);
|
|
578
|
+
const filhas = [];
|
|
579
|
+
for (const rota of rotas) {
|
|
580
|
+
if (!rota.arquivoRotasFilhas) {
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
filhas.push(...await extrairRotasAngularConsumer(diretorioBase, rota.arquivoRotasFilhas, rota.rota, visitados));
|
|
584
|
+
}
|
|
585
|
+
return [...rotas, ...filhas];
|
|
586
|
+
}
|
|
587
|
+
function simboloEhBridgeConsumer(caminho, arquivo) {
|
|
588
|
+
return arquivoEhBridgeNextJsConsumer(arquivo)
|
|
589
|
+
|| arquivoEhBridgeReactViteConsumer(arquivo)
|
|
590
|
+
|| arquivoEhBridgeAngularConsumer(arquivo)
|
|
591
|
+
|| arquivoEhBridgeFlutterConsumer(arquivo)
|
|
592
|
+
|| /(?:^|\.)(?:src\.)?lib\.(?:sema_consumer_bridge|sema\.)/i.test(caminho)
|
|
593
|
+
|| /(?:^|\.)(?:src\.)?app\.(?:sema_consumer_bridge|sema\.)/i.test(caminho)
|
|
594
|
+
|| /(?:^|\.)(?:lib\.)?(?:sema_consumer_bridge|api\.sema_contract_bridge|sema\.)/i.test(caminho);
|
|
595
|
+
}
|
|
596
|
+
function inferirConsumerFrameworkPrincipal(fontesLegado, consumerSurfaces, consumerBridges) {
|
|
597
|
+
const arquivos = [
|
|
598
|
+
...consumerSurfaces.map((item) => item.arquivo),
|
|
599
|
+
...consumerBridges.map((item) => item.arquivo),
|
|
600
|
+
].map(normalizarRelacaoConsumer);
|
|
601
|
+
if (arquivos.some((arquivo) => /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(arquivo))) {
|
|
602
|
+
return "nextjs-consumer";
|
|
603
|
+
}
|
|
604
|
+
if (arquivos.some((arquivo) => /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(arquivo)
|
|
605
|
+
|| /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(arquivo)
|
|
606
|
+
|| /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(arquivo))) {
|
|
607
|
+
return "react-vite-consumer";
|
|
608
|
+
}
|
|
609
|
+
if (arquivos.some((arquivo) => /(?:^|\/)(?:src\/)?app\/.+\.component\.(?:ts|js)$/i.test(arquivo) || arquivoEhRotasAngularConsumer(arquivo))) {
|
|
610
|
+
return "angular-consumer";
|
|
611
|
+
}
|
|
612
|
+
if (arquivos.some((arquivo) => /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(arquivo)
|
|
613
|
+
|| /(?:^|\/)(?:lib\/)?(?:router|app_router|routes|main)\.dart$/i.test(arquivo))) {
|
|
614
|
+
return "flutter-consumer";
|
|
615
|
+
}
|
|
616
|
+
for (const framework of ["nextjs-consumer", "react-vite-consumer", "angular-consumer", "flutter-consumer"]) {
|
|
617
|
+
if (fontesLegado.includes(framework)) {
|
|
618
|
+
return framework;
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
return null;
|
|
622
|
+
}
|
|
294
623
|
function extrairColecoesFirebase(arquivo, codigo) {
|
|
295
624
|
const recursos = new Map();
|
|
296
625
|
const registrar = (nome) => {
|
|
@@ -322,11 +651,17 @@ async function indexarTypeScript(diretorios) {
|
|
|
322
651
|
const simbolos = new Map();
|
|
323
652
|
const rotas = [];
|
|
324
653
|
const recursos = new Map();
|
|
654
|
+
const consumerSurfaces = new Map();
|
|
325
655
|
for (const diretorio of diretorios) {
|
|
326
656
|
const arquivos = (await listarArquivosRecursivos(diretorio, [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]))
|
|
327
657
|
.filter((arquivo) => !arquivo.endsWith(".d.ts")
|
|
328
658
|
&& !arquivo.endsWith(".spec.ts")
|
|
329
659
|
&& !arquivo.endsWith(".test.ts"));
|
|
660
|
+
const arquivosRotasAngular = arquivos.filter((arquivo) => arquivoEhRotasAngularConsumer(path.relative(diretorio, arquivo)));
|
|
661
|
+
const arquivosRotasAngularRaiz = new Set(arquivosRotasAngular
|
|
662
|
+
.filter((arquivo) => arquivoEhRotasAngularConsumerRaiz(path.relative(diretorio, arquivo)))
|
|
663
|
+
.map((arquivo) => path.resolve(arquivo)));
|
|
664
|
+
const usarApenasRotasAngularRaiz = arquivosRotasAngularRaiz.size > 0;
|
|
330
665
|
for (const arquivo of arquivos) {
|
|
331
666
|
const codigo = await readFile(arquivo, "utf8");
|
|
332
667
|
const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
@@ -345,6 +680,89 @@ async function indexarTypeScript(diretorios) {
|
|
|
345
680
|
simbolo: rota.simbolo,
|
|
346
681
|
});
|
|
347
682
|
}
|
|
683
|
+
const superficieNextJs = arquivoEhSuperficieNextJsConsumer(relacao)
|
|
684
|
+
? inferirRotaNextJsConsumer(relacao)
|
|
685
|
+
: undefined;
|
|
686
|
+
if (superficieNextJs) {
|
|
687
|
+
consumerSurfaces.set(`${superficieNextJs.rota}:${arquivo}:${superficieNextJs.tipoArquivo}`, {
|
|
688
|
+
rota: superficieNextJs.rota,
|
|
689
|
+
arquivo,
|
|
690
|
+
tipoArquivo: superficieNextJs.tipoArquivo,
|
|
691
|
+
});
|
|
692
|
+
rotas.push({
|
|
693
|
+
origem: "nextjs-consumer",
|
|
694
|
+
metodo: "VIEW",
|
|
695
|
+
caminho: superficieNextJs.rota,
|
|
696
|
+
arquivo,
|
|
697
|
+
simbolo: superficieNextJs.tipoArquivo,
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
const superficieReact = arquivoEhSuperficieReactViteConsumer(relacao)
|
|
701
|
+
? inferirRotaReactViteConsumer(relacao)
|
|
702
|
+
: undefined;
|
|
703
|
+
if (superficieReact) {
|
|
704
|
+
consumerSurfaces.set(`${superficieReact.rota}:${arquivo}:${superficieReact.tipoArquivo}`, {
|
|
705
|
+
rota: superficieReact.rota,
|
|
706
|
+
arquivo,
|
|
707
|
+
tipoArquivo: superficieReact.tipoArquivo,
|
|
708
|
+
});
|
|
709
|
+
rotas.push({
|
|
710
|
+
origem: "react-vite-consumer",
|
|
711
|
+
metodo: "VIEW",
|
|
712
|
+
caminho: superficieReact.rota,
|
|
713
|
+
arquivo,
|
|
714
|
+
simbolo: superficieReact.tipoArquivo,
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
if (arquivoEhRotasReactViteConsumer(relacao, codigo)) {
|
|
718
|
+
for (const rotaReact of extrairRotasReactViteConsumer(relacao, codigo)) {
|
|
719
|
+
consumerSurfaces.set(`${rotaReact.rota}:${arquivo}:router`, {
|
|
720
|
+
rota: rotaReact.rota,
|
|
721
|
+
arquivo,
|
|
722
|
+
tipoArquivo: "router",
|
|
723
|
+
});
|
|
724
|
+
rotas.push({
|
|
725
|
+
origem: "react-vite-consumer",
|
|
726
|
+
metodo: "VIEW",
|
|
727
|
+
caminho: rotaReact.rota,
|
|
728
|
+
arquivo,
|
|
729
|
+
simbolo: "router",
|
|
730
|
+
});
|
|
731
|
+
if (rotaReact.arquivoComponente) {
|
|
732
|
+
const arquivoComponente = path.join(diretorio, rotaReact.arquivoComponente);
|
|
733
|
+
consumerSurfaces.set(`${rotaReact.rota}:${arquivoComponente}:page`, {
|
|
734
|
+
rota: rotaReact.rota,
|
|
735
|
+
arquivo: arquivoComponente,
|
|
736
|
+
tipoArquivo: "page",
|
|
737
|
+
});
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
if (arquivoEhRotasAngularConsumer(relacao) && (!usarApenasRotasAngularRaiz || arquivosRotasAngularRaiz.has(path.resolve(arquivo)))) {
|
|
742
|
+
for (const rotaAngular of await extrairRotasAngularConsumer(diretorio, relacao)) {
|
|
743
|
+
const arquivoRotasAngular = path.join(diretorio, rotaAngular.arquivoRotas);
|
|
744
|
+
consumerSurfaces.set(`${rotaAngular.rota}:${arquivoRotasAngular}:routes`, {
|
|
745
|
+
rota: rotaAngular.rota,
|
|
746
|
+
arquivo: arquivoRotasAngular,
|
|
747
|
+
tipoArquivo: "routes",
|
|
748
|
+
});
|
|
749
|
+
rotas.push({
|
|
750
|
+
origem: "angular-consumer",
|
|
751
|
+
metodo: "VIEW",
|
|
752
|
+
caminho: rotaAngular.rota,
|
|
753
|
+
arquivo: arquivoRotasAngular,
|
|
754
|
+
simbolo: rotaAngular.componente ?? "routes",
|
|
755
|
+
});
|
|
756
|
+
if (rotaAngular.arquivoComponente) {
|
|
757
|
+
const arquivoComponente = path.join(diretorio, rotaAngular.arquivoComponente);
|
|
758
|
+
consumerSurfaces.set(`${rotaAngular.rota}:${arquivoComponente}:component`, {
|
|
759
|
+
rota: rotaAngular.rota,
|
|
760
|
+
arquivo: arquivoComponente,
|
|
761
|
+
tipoArquivo: "component",
|
|
762
|
+
});
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
348
766
|
for (const node of sourceFile.statements) {
|
|
349
767
|
if (ts.isFunctionDeclaration(node) && node.name) {
|
|
350
768
|
registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, node.name.text);
|
|
@@ -396,7 +814,14 @@ async function indexarTypeScript(diretorios) {
|
|
|
396
814
|
}
|
|
397
815
|
}
|
|
398
816
|
}
|
|
399
|
-
return {
|
|
817
|
+
return {
|
|
818
|
+
simbolos: [...simbolos.values()],
|
|
819
|
+
rotas,
|
|
820
|
+
recursos: [...recursos.values()],
|
|
821
|
+
consumerSurfaces: [...consumerSurfaces.values()].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
|
|
822
|
+
|| a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
|
|
823
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR")),
|
|
824
|
+
};
|
|
400
825
|
}
|
|
401
826
|
function registrarSimboloPython(simbolos, basesSimbolicas, arquivo, nome, nomeClasse) {
|
|
402
827
|
for (const baseSimbolica of basesSimbolicas) {
|
|
@@ -493,12 +918,15 @@ async function indexarPython(diretorios) {
|
|
|
493
918
|
}
|
|
494
919
|
async function indexarDart(diretorios) {
|
|
495
920
|
const simbolos = new Map();
|
|
921
|
+
const rotas = [];
|
|
922
|
+
const consumerSurfaces = new Map();
|
|
496
923
|
for (const diretorio of diretorios) {
|
|
497
924
|
const arquivos = (await listarArquivosRecursivos(diretorio, [".dart"]))
|
|
498
925
|
.filter((arquivo) => !arquivo.endsWith(".g.dart") && !arquivo.endsWith(".freezed.dart"));
|
|
499
926
|
for (const arquivo of arquivos) {
|
|
500
927
|
const texto = await readFile(arquivo, "utf8");
|
|
501
928
|
const basesSimbolicas = caminhosSimbolicos(diretorio, arquivo);
|
|
929
|
+
const relacao = path.relative(diretorio, arquivo);
|
|
502
930
|
for (const match of texto.matchAll(/(?:Future<[^\n]+>|[\w?<>.,\s]+)\s+(\w+)\(([^)]*)\)\s*(?:async\s*)?\{/g)) {
|
|
503
931
|
const nome = match[1];
|
|
504
932
|
if (["build", "toString"].includes(nome)) {
|
|
@@ -509,9 +937,46 @@ async function indexarDart(diretorios) {
|
|
|
509
937
|
simbolos.set(caminho, { origem: "dart", caminho, arquivo, simbolo: nome });
|
|
510
938
|
}
|
|
511
939
|
}
|
|
940
|
+
const superficieFlutter = inferirRotaFlutterConsumer(relacao);
|
|
941
|
+
if (superficieFlutter) {
|
|
942
|
+
consumerSurfaces.set(`${superficieFlutter.rota}:${arquivo}:${superficieFlutter.tipoArquivo}`, {
|
|
943
|
+
rota: superficieFlutter.rota,
|
|
944
|
+
arquivo,
|
|
945
|
+
tipoArquivo: superficieFlutter.tipoArquivo,
|
|
946
|
+
});
|
|
947
|
+
rotas.push({
|
|
948
|
+
origem: "flutter-consumer",
|
|
949
|
+
metodo: "VIEW",
|
|
950
|
+
caminho: superficieFlutter.rota,
|
|
951
|
+
arquivo,
|
|
952
|
+
simbolo: superficieFlutter.tipoArquivo,
|
|
953
|
+
});
|
|
954
|
+
}
|
|
955
|
+
if (arquivoEhRotasFlutterConsumer(relacao, texto)) {
|
|
956
|
+
for (const rotaFlutter of extrairRotasFlutterConsumer(relacao, texto)) {
|
|
957
|
+
consumerSurfaces.set(`${rotaFlutter.rota}:${arquivo}:router`, {
|
|
958
|
+
rota: rotaFlutter.rota,
|
|
959
|
+
arquivo,
|
|
960
|
+
tipoArquivo: "router",
|
|
961
|
+
});
|
|
962
|
+
rotas.push({
|
|
963
|
+
origem: "flutter-consumer",
|
|
964
|
+
metodo: "VIEW",
|
|
965
|
+
caminho: rotaFlutter.rota,
|
|
966
|
+
arquivo,
|
|
967
|
+
simbolo: "router",
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
}
|
|
512
971
|
}
|
|
513
972
|
}
|
|
514
|
-
return
|
|
973
|
+
return {
|
|
974
|
+
simbolos: [...simbolos.values()],
|
|
975
|
+
rotas,
|
|
976
|
+
consumerSurfaces: [...consumerSurfaces.values()].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
|
|
977
|
+
|| a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
|
|
978
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR")),
|
|
979
|
+
};
|
|
515
980
|
}
|
|
516
981
|
function registrarSimboloGenerico(simbolos, origem, basesSimbolicas, arquivo, simbolo) {
|
|
517
982
|
for (const baseSimbolica of basesSimbolicas) {
|
|
@@ -871,7 +1336,7 @@ export async function analisarDriftLegado(contexto) {
|
|
|
871
1336
|
const todosSimbolos = [
|
|
872
1337
|
...indexTs.simbolos,
|
|
873
1338
|
...indexPy.simbolos,
|
|
874
|
-
...indexDart,
|
|
1339
|
+
...indexDart.simbolos,
|
|
875
1340
|
...indexDotnet.simbolos,
|
|
876
1341
|
...indexJava.simbolos,
|
|
877
1342
|
...indexGo.simbolos,
|
|
@@ -881,7 +1346,7 @@ export async function analisarDriftLegado(contexto) {
|
|
|
881
1346
|
const mapaImpl = new Map([
|
|
882
1347
|
...indexTs.simbolos.map((item) => [item.caminho, item]),
|
|
883
1348
|
...indexPy.simbolos.map((item) => [item.caminho, item]),
|
|
884
|
-
...indexDart.map((item) => [item.caminho, item]),
|
|
1349
|
+
...indexDart.simbolos.map((item) => [item.caminho, item]),
|
|
885
1350
|
...indexDotnet.simbolos.map((item) => [item.caminho, item]),
|
|
886
1351
|
...indexJava.simbolos.map((item) => [item.caminho, item]),
|
|
887
1352
|
...indexGo.simbolos.map((item) => [item.caminho, item]),
|
|
@@ -892,6 +1357,7 @@ export async function analisarDriftLegado(contexto) {
|
|
|
892
1357
|
const todasRotasIndexadas = [
|
|
893
1358
|
...indexTs.rotas,
|
|
894
1359
|
...indexPy.rotas,
|
|
1360
|
+
...indexDart.rotas,
|
|
895
1361
|
...indexDotnet.rotas,
|
|
896
1362
|
...indexJava.rotas,
|
|
897
1363
|
...indexGo.rotas,
|
|
@@ -1051,7 +1517,11 @@ export async function analisarDriftLegado(contexto) {
|
|
|
1051
1517
|
if (!esperadas.length || !route.metodo || !route.caminho) {
|
|
1052
1518
|
continue;
|
|
1053
1519
|
}
|
|
1054
|
-
const encontradas = todasRotasIndexadas.filter((rotaResolvida) =>
|
|
1520
|
+
const encontradas = todasRotasIndexadas.filter((rotaResolvida) => rotaResolvida.origem !== "nextjs-consumer"
|
|
1521
|
+
&& rotaResolvida.origem !== "react-vite-consumer"
|
|
1522
|
+
&& rotaResolvida.origem !== "angular-consumer"
|
|
1523
|
+
&& rotaResolvida.origem !== "flutter-consumer"
|
|
1524
|
+
&& esperadas.includes(rotaResolvida.origem));
|
|
1055
1525
|
const combina = encontradas.some((rotaResolvida) => rotaResolvida.metodo === route.metodo
|
|
1056
1526
|
&& normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(route.caminho));
|
|
1057
1527
|
if (!combina) {
|
|
@@ -1197,9 +1667,30 @@ export async function analisarDriftLegado(contexto) {
|
|
|
1197
1667
|
resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
|
|
1198
1668
|
].filter(Boolean))];
|
|
1199
1669
|
}
|
|
1670
|
+
const consumerSurfaces = [...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
|
|
1671
|
+
|| a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
|
|
1672
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR"));
|
|
1673
|
+
const consumerBridges = [...new Map([...indexTs.simbolos, ...indexDart.simbolos]
|
|
1674
|
+
.filter((simbolo) => simboloEhBridgeConsumer(simbolo.caminho, simbolo.arquivo))
|
|
1675
|
+
.map((simbolo) => [
|
|
1676
|
+
`${simbolo.caminho}:${simbolo.arquivo}:${simbolo.simbolo}`,
|
|
1677
|
+
{
|
|
1678
|
+
caminho: simbolo.caminho,
|
|
1679
|
+
arquivo: simbolo.arquivo,
|
|
1680
|
+
simbolo: simbolo.simbolo,
|
|
1681
|
+
},
|
|
1682
|
+
])).values()].sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR")
|
|
1683
|
+
|| a.arquivo.localeCompare(b.arquivo, "pt-BR"));
|
|
1684
|
+
const appRoutes = [...new Set(consumerSurfaces.map((surface) => surface.rota))]
|
|
1685
|
+
.sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
1686
|
+
const consumerFramework = inferirConsumerFrameworkPrincipal(contexto.fontesLegado, consumerSurfaces, consumerBridges);
|
|
1200
1687
|
const payloadBase = {
|
|
1201
1688
|
comando: "drift",
|
|
1202
1689
|
sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0 && vinculosQuebrados.length === 0,
|
|
1690
|
+
consumerFramework,
|
|
1691
|
+
appRoutes,
|
|
1692
|
+
consumerSurfaces,
|
|
1693
|
+
consumerBridges,
|
|
1203
1694
|
modulos: contexto.modulosSelecionados.map((item) => ({
|
|
1204
1695
|
caminho: item.caminho,
|
|
1205
1696
|
modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,
|