@semacode/cli 1.0.0 → 1.2.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.
Files changed (48) hide show
  1. package/AGENTS.md +50 -0
  2. package/README.md +15 -2
  3. package/SEMA_BRIEF.curto.txt +9 -0
  4. package/SEMA_BRIEF.md +49 -0
  5. package/SEMA_BRIEF.micro.txt +7 -0
  6. package/SEMA_INDEX.json +546 -0
  7. package/dist/drift.d.ts +17 -2
  8. package/dist/drift.js +516 -5
  9. package/dist/drift.js.map +1 -1
  10. package/dist/importador.d.ts +1 -1
  11. package/dist/importador.js +741 -3
  12. package/dist/importador.js.map +1 -1
  13. package/dist/index.js +962 -86
  14. package/dist/index.js.map +1 -1
  15. package/dist/lua-symbols.d.ts +8 -0
  16. package/dist/lua-symbols.js +68 -0
  17. package/dist/lua-symbols.js.map +1 -0
  18. package/dist/projeto.js +56 -2
  19. package/dist/projeto.js.map +1 -1
  20. package/dist/tipos.d.ts +1 -1
  21. package/docs/AGENT_STARTER.md +34 -6
  22. package/docs/instalacao-e-primeiro-uso.md +18 -9
  23. package/llms-full.txt +34 -0
  24. package/llms.txt +17 -0
  25. package/node_modules/@sema/gerador-dart/package.json +1 -1
  26. package/node_modules/@sema/gerador-lua/dist/index.d.ts +3 -0
  27. package/node_modules/@sema/gerador-lua/dist/index.js +360 -0
  28. package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -0
  29. package/node_modules/@sema/gerador-lua/package.json +7 -0
  30. package/node_modules/@sema/gerador-python/dist/index.js +92 -10
  31. package/node_modules/@sema/gerador-python/dist/index.js.map +1 -1
  32. package/node_modules/@sema/gerador-python/package.json +1 -1
  33. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  34. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +1 -1
  35. package/node_modules/@sema/nucleo/dist/ir/conversor.js +4 -0
  36. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  37. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +3 -3
  38. package/node_modules/@sema/nucleo/dist/parser/parser.js +2 -0
  39. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  40. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +2 -2
  41. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +3 -1
  42. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  43. package/node_modules/@sema/nucleo/package.json +1 -1
  44. package/node_modules/@sema/padroes/dist/index.d.ts +2 -1
  45. package/node_modules/@sema/padroes/dist/index.js +64 -1
  46. package/node_modules/@sema/padroes/dist/index.js.map +1 -1
  47. package/node_modules/@sema/padroes/package.json +1 -1
  48. package/package.json +16 -7
package/dist/drift.js CHANGED
@@ -5,6 +5,7 @@ import { extrairSimbolosCpp } from "./cpp-symbols.js";
5
5
  import { extrairRotasDotnet, extrairSimbolosDotnet } from "./dotnet-http.js";
6
6
  import { extrairRotasGo, extrairSimbolosGo } from "./go-http.js";
7
7
  import { extrairRotasJava, extrairSimbolosJava } from "./java-http.js";
8
+ import { extrairSimbolosLua } from "./lua-symbols.js";
8
9
  import { contarIndentacaoPython, extrairRotasFlaskDecoradas, normalizarCaminhoFlask } from "./python-http.js";
9
10
  import { extrairRotasRust, extrairSimbolosRust } from "./rust-http.js";
10
11
  import { extrairRotasTypeScriptHttp } from "./typescript-http.js";
@@ -291,6 +292,335 @@ function registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, nome, no
291
292
  });
292
293
  }
293
294
  }
295
+ function normalizarRelacaoConsumer(relacaoArquivo) {
296
+ return relacaoArquivo.replace(/\\/g, "/");
297
+ }
298
+ function normalizarSegmentoRotaConsumer(segmento) {
299
+ const opcionalCatchAll = segmento.match(/^\[\[\.\.\.([A-Za-z_]\w*)\]\]$/);
300
+ if (opcionalCatchAll) {
301
+ return `{${opcionalCatchAll[1]}}`;
302
+ }
303
+ const catchAll = segmento.match(/^\[\.\.\.([A-Za-z_]\w*)\]$/);
304
+ if (catchAll) {
305
+ return `{${catchAll[1]}}`;
306
+ }
307
+ const dinamico = segmento.match(/^\[([A-Za-z_]\w*)\]$/);
308
+ if (dinamico) {
309
+ return `{${dinamico[1]}}`;
310
+ }
311
+ return segmento;
312
+ }
313
+ function montarRotaConsumer(partes) {
314
+ const filtradas = partes
315
+ .filter((segmento) => segmento && segmento !== "index" && !/^\(.*\)$/.test(segmento) && !segmento.startsWith("@"))
316
+ .map(normalizarSegmentoRotaConsumer);
317
+ return filtradas.length > 0 ? `/${filtradas.join("/")}`.replace(/\/+/g, "/") : "/";
318
+ }
319
+ function arquivoEhBridgeNextJsConsumer(relacaoArquivo) {
320
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
321
+ return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
322
+ }
323
+ function arquivoEhBridgeReactViteConsumer(relacaoArquivo) {
324
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
325
+ return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
326
+ }
327
+ function arquivoEhBridgeAngularConsumer(relacaoArquivo) {
328
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
329
+ return /(?:^|\/)(?:src\/)?app\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|js)$/i.test(relacao);
330
+ }
331
+ function arquivoEhSuperficieNextJsConsumer(relacaoArquivo) {
332
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
333
+ return /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
334
+ }
335
+ function arquivoEhSuperficieReactViteConsumer(relacaoArquivo) {
336
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
337
+ return /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(relacao)
338
+ || /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao);
339
+ }
340
+ function arquivoEhRotasReactViteConsumer(relacaoArquivo, codigo) {
341
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
342
+ return /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(relacao)
343
+ || /from\s+["']react-router-dom["']|createBrowserRouter|RouterProvider|useRoutes\s*\(|<Routes\b|<Route\b/.test(codigo ?? "");
344
+ }
345
+ function arquivoEhRotasAngularConsumer(relacaoArquivo) {
346
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
347
+ return /(?:^|\/)(?:src\/)?app(?:\/.+)?\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
348
+ }
349
+ function arquivoEhRotasAngularConsumerRaiz(relacaoArquivo) {
350
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
351
+ return /(?:^|\/)(?:src\/)?app\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
352
+ }
353
+ function arquivoEhBridgeFlutterConsumer(relacaoArquivo) {
354
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
355
+ return /(?:^|\/)(?:lib\/)?(?:sema_consumer_bridge|api\/sema_contract_bridge|sema\/.+)\.dart$/i.test(relacao);
356
+ }
357
+ function arquivoEhSuperficieFlutterConsumer(relacaoArquivo) {
358
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
359
+ return /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(relacao)
360
+ || /(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao);
361
+ }
362
+ function arquivoEhRotasFlutterConsumer(relacaoArquivo, codigo) {
363
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
364
+ return /(?:^|\/)(?:lib\/)?(?:router|app_router|routes)\.dart$/i.test(relacao)
365
+ || /MaterialApp(?:\.router)?\s*\(|CupertinoApp(?:\.router)?\s*\(|GoRouter\s*\(/.test(codigo ?? "");
366
+ }
367
+ function inferirRotaNextJsConsumer(relacaoArquivo) {
368
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
369
+ const segmentos = relacao.split("/");
370
+ const indiceSrcApp = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "app");
371
+ const indiceApp = segmentos.findIndex((segmento) => segmento === "app");
372
+ const inicioApp = indiceSrcApp >= 0 ? indiceSrcApp + 2 : indiceApp >= 0 ? indiceApp + 1 : -1;
373
+ if (inicioApp < 0) {
374
+ return undefined;
375
+ }
376
+ const arquivoFinal = segmentos.at(-1) ?? "";
377
+ const tipoArquivo = arquivoFinal.match(/^(page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/)?.[1];
378
+ if (!tipoArquivo) {
379
+ return undefined;
380
+ }
381
+ const caminhoAteArquivo = segmentos.slice(inicioApp, -1);
382
+ if (caminhoAteArquivo[0] === "api") {
383
+ return undefined;
384
+ }
385
+ return {
386
+ rota: montarRotaConsumer(caminhoAteArquivo),
387
+ arquivo: relacaoArquivo,
388
+ tipoArquivo,
389
+ };
390
+ }
391
+ function inferirRotaReactViteConsumer(relacaoArquivo) {
392
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
393
+ if (/(?:^|\/)(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao)) {
394
+ return {
395
+ rota: "/",
396
+ arquivo: relacaoArquivo,
397
+ tipoArquivo: "app",
398
+ };
399
+ }
400
+ const segmentos = relacao.split("/");
401
+ const indiceSrcPages = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "pages");
402
+ const indicePages = segmentos.findIndex((segmento) => segmento === "pages");
403
+ const inicioPages = indiceSrcPages >= 0 ? indiceSrcPages + 2 : indicePages >= 0 ? indicePages + 1 : -1;
404
+ if (inicioPages < 0) {
405
+ return undefined;
406
+ }
407
+ const arquivoFinal = segmentos.at(-1) ?? "";
408
+ const nomeBase = arquivoFinal.replace(/\.(?:ts|tsx|js|jsx)$/i, "");
409
+ return {
410
+ rota: montarRotaConsumer([...segmentos.slice(inicioPages, -1), nomeBase]),
411
+ arquivo: relacaoArquivo,
412
+ tipoArquivo: "page",
413
+ };
414
+ }
415
+ function inferirRotaFlutterConsumer(relacaoArquivo) {
416
+ const relacao = normalizarRelacaoConsumer(relacaoArquivo);
417
+ if (!arquivoEhSuperficieFlutterConsumer(relacao)) {
418
+ return undefined;
419
+ }
420
+ if (/(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao)) {
421
+ return {
422
+ rota: "/",
423
+ arquivo: relacaoArquivo,
424
+ tipoArquivo: "app",
425
+ };
426
+ }
427
+ const segmentos = relacao.split("/");
428
+ const indiceLibScreens = segmentos.findIndex((segmento, indice) => segmento === "lib" && ["screens", "pages"].includes(segmentos[indice + 1] ?? ""));
429
+ const indiceScreens = segmentos.findIndex((segmento) => segmento === "screens" || segmento === "pages");
430
+ const inicio = indiceLibScreens >= 0 ? indiceLibScreens + 2 : indiceScreens >= 0 ? indiceScreens + 1 : -1;
431
+ if (inicio < 0) {
432
+ return undefined;
433
+ }
434
+ const arquivoFinal = segmentos.at(-1) ?? "";
435
+ const nomeBase = arquivoFinal
436
+ .replace(/\.(?:dart)$/i, "")
437
+ .replace(/_(screen|page)$/i, "");
438
+ return {
439
+ rota: montarRotaConsumer([...segmentos.slice(inicio, -1), nomeBase]),
440
+ arquivo: relacaoArquivo,
441
+ tipoArquivo: "screen",
442
+ };
443
+ }
444
+ function normalizarRotaDeclaradaConsumer(caminhoCru, prefixo = "/") {
445
+ const partesPrefixo = prefixo.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
446
+ const partesCaminho = (caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
447
+ return montarRotaConsumer([...partesPrefixo, ...partesCaminho]);
448
+ }
449
+ function resolverImportRelativoConsumer(relacaoArquivoBase, especificador) {
450
+ if (!especificador.startsWith(".")) {
451
+ return undefined;
452
+ }
453
+ const baseDir = path.posix.dirname(normalizarRelacaoConsumer(relacaoArquivoBase));
454
+ for (const sufixo of ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.js"]) {
455
+ const candidato = path.posix.normalize(path.posix.join(baseDir, `${especificador}${sufixo}`));
456
+ if (/\.(?:ts|tsx|js|jsx)$/i.test(candidato)) {
457
+ return candidato;
458
+ }
459
+ }
460
+ return undefined;
461
+ }
462
+ function extrairImportsTypeScriptConsumer(relacaoArquivo, codigo) {
463
+ const imports = new Map();
464
+ for (const match of codigo.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*["']([^"']+)["']/g)) {
465
+ const arquivoImportado = resolverImportRelativoConsumer(relacaoArquivo, match[2]);
466
+ if (!arquivoImportado) {
467
+ continue;
468
+ }
469
+ for (const bruto of match[1].split(",")) {
470
+ const local = bruto.trim().split(/\s+as\s+/i).at(-1)?.trim();
471
+ if (local) {
472
+ imports.set(local, arquivoImportado);
473
+ }
474
+ }
475
+ }
476
+ for (const match of codigo.matchAll(/import\s+([A-Za-z_]\w*)\s+from\s*["']([^"']+)["']/g)) {
477
+ const arquivoImportado = resolverImportRelativoConsumer(relacaoArquivo, match[2]);
478
+ const local = match[1]?.trim();
479
+ if (arquivoImportado && local) {
480
+ imports.set(local, arquivoImportado);
481
+ }
482
+ }
483
+ return imports;
484
+ }
485
+ function extrairRotasReactViteConsumer(relacaoArquivo, codigo) {
486
+ const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
487
+ const rotas = new Map();
488
+ const registrar = (caminhoCru, componente) => {
489
+ const rota = normalizarRotaDeclaradaConsumer(caminhoCru);
490
+ const chave = `${rota}:${normalizarRelacaoConsumer(relacaoArquivo)}:${componente ?? "router"}`;
491
+ rotas.set(chave, {
492
+ rota,
493
+ arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
494
+ arquivoComponente: componente ? imports.get(componente) : undefined,
495
+ });
496
+ };
497
+ 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)) {
498
+ const caminhoCru = match[1] ?? "";
499
+ const componente = match[2] ?? match[3];
500
+ registrar(caminhoCru, componente);
501
+ }
502
+ 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)) {
503
+ const caminhoCru = match[2] ? "" : (match[1] ?? "");
504
+ const componente = match[3] ?? match[4];
505
+ registrar(caminhoCru, componente);
506
+ }
507
+ return [...rotas.values()];
508
+ }
509
+ function normalizarRotaDeclaradaFlutter(caminhoCru) {
510
+ return montarRotaConsumer((caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean));
511
+ }
512
+ function extrairRotasFlutterConsumer(relacaoArquivo, codigo) {
513
+ const rotas = new Map();
514
+ const registrar = (caminhoCru) => {
515
+ const rota = normalizarRotaDeclaradaFlutter(caminhoCru);
516
+ rotas.set(`${rota}:${normalizarRelacaoConsumer(relacaoArquivo)}`, {
517
+ rota,
518
+ arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
519
+ });
520
+ };
521
+ for (const match of codigo.matchAll(/GoRoute\s*\([\s\S]{0,220}?path\s*:\s*["'`]([^"'`]+)["'`]/g)) {
522
+ registrar(match[1] ?? "");
523
+ }
524
+ for (const match of codigo.matchAll(/["'`]([^"'`]+)["'`]\s*:\s*\([^)]*\)\s*=>/g)) {
525
+ registrar(match[1] ?? "");
526
+ }
527
+ if (/home\s*:\s*(?:const\s+)?[A-Za-z_]\w*\(/.test(codigo)) {
528
+ registrar("/");
529
+ }
530
+ return [...rotas.values()];
531
+ }
532
+ function extrairRotasAngularConsumerDiretas(relacaoArquivo, codigo, prefixo = "/") {
533
+ const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
534
+ const rotas = [];
535
+ for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?component\s*:\s*([A-Za-z_]\w*)/g)) {
536
+ const caminhoCru = (match[1] ?? "").trim();
537
+ const componente = match[2];
538
+ rotas.push({
539
+ rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
540
+ arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
541
+ componente,
542
+ arquivoComponente: imports.get(componente),
543
+ });
544
+ }
545
+ for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?loadComponent\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
546
+ const caminhoCru = (match[1] ?? "").trim();
547
+ const arquivoComponente = resolverImportRelativoConsumer(relacaoArquivo, match[2] ?? "");
548
+ rotas.push({
549
+ rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
550
+ arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
551
+ arquivoComponente,
552
+ });
553
+ }
554
+ for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,360}?loadChildren\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
555
+ const caminhoCru = (match[1] ?? "").trim();
556
+ const arquivoRotasFilhas = resolverImportRelativoConsumer(relacaoArquivo, match[2] ?? "");
557
+ rotas.push({
558
+ rota: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
559
+ arquivoRotas: normalizarRelacaoConsumer(relacaoArquivo),
560
+ arquivoRotasFilhas,
561
+ });
562
+ }
563
+ return rotas;
564
+ }
565
+ async function extrairRotasAngularConsumer(diretorioBase, relacaoArquivo, prefixo = "/", visitados = new Set()) {
566
+ const relacaoNormalizada = normalizarRelacaoConsumer(relacaoArquivo);
567
+ if (visitados.has(relacaoNormalizada)) {
568
+ return [];
569
+ }
570
+ visitados.add(relacaoNormalizada);
571
+ let codigo = "";
572
+ try {
573
+ codigo = await readFile(path.join(diretorioBase, relacaoNormalizada), "utf8");
574
+ }
575
+ catch {
576
+ return [];
577
+ }
578
+ const rotas = extrairRotasAngularConsumerDiretas(relacaoNormalizada, codigo, prefixo);
579
+ const filhas = [];
580
+ for (const rota of rotas) {
581
+ if (!rota.arquivoRotasFilhas) {
582
+ continue;
583
+ }
584
+ filhas.push(...await extrairRotasAngularConsumer(diretorioBase, rota.arquivoRotasFilhas, rota.rota, visitados));
585
+ }
586
+ return [...rotas, ...filhas];
587
+ }
588
+ function simboloEhBridgeConsumer(caminho, arquivo) {
589
+ return arquivoEhBridgeNextJsConsumer(arquivo)
590
+ || arquivoEhBridgeReactViteConsumer(arquivo)
591
+ || arquivoEhBridgeAngularConsumer(arquivo)
592
+ || arquivoEhBridgeFlutterConsumer(arquivo)
593
+ || /(?:^|\.)(?:src\.)?lib\.(?:sema_consumer_bridge|sema\.)/i.test(caminho)
594
+ || /(?:^|\.)(?:src\.)?app\.(?:sema_consumer_bridge|sema\.)/i.test(caminho)
595
+ || /(?:^|\.)(?:lib\.)?(?:sema_consumer_bridge|api\.sema_contract_bridge|sema\.)/i.test(caminho);
596
+ }
597
+ function inferirConsumerFrameworkPrincipal(fontesLegado, consumerSurfaces, consumerBridges) {
598
+ const arquivos = [
599
+ ...consumerSurfaces.map((item) => item.arquivo),
600
+ ...consumerBridges.map((item) => item.arquivo),
601
+ ].map(normalizarRelacaoConsumer);
602
+ if (arquivos.some((arquivo) => /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(arquivo))) {
603
+ return "nextjs-consumer";
604
+ }
605
+ if (arquivos.some((arquivo) => /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(arquivo)
606
+ || /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(arquivo)
607
+ || /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(arquivo))) {
608
+ return "react-vite-consumer";
609
+ }
610
+ if (arquivos.some((arquivo) => /(?:^|\/)(?:src\/)?app\/.+\.component\.(?:ts|js)$/i.test(arquivo) || arquivoEhRotasAngularConsumer(arquivo))) {
611
+ return "angular-consumer";
612
+ }
613
+ if (arquivos.some((arquivo) => /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(arquivo)
614
+ || /(?:^|\/)(?:lib\/)?(?:router|app_router|routes|main)\.dart$/i.test(arquivo))) {
615
+ return "flutter-consumer";
616
+ }
617
+ for (const framework of ["nextjs-consumer", "react-vite-consumer", "angular-consumer", "flutter-consumer"]) {
618
+ if (fontesLegado.includes(framework)) {
619
+ return framework;
620
+ }
621
+ }
622
+ return null;
623
+ }
294
624
  function extrairColecoesFirebase(arquivo, codigo) {
295
625
  const recursos = new Map();
296
626
  const registrar = (nome) => {
@@ -322,11 +652,17 @@ async function indexarTypeScript(diretorios) {
322
652
  const simbolos = new Map();
323
653
  const rotas = [];
324
654
  const recursos = new Map();
655
+ const consumerSurfaces = new Map();
325
656
  for (const diretorio of diretorios) {
326
657
  const arquivos = (await listarArquivosRecursivos(diretorio, [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]))
327
658
  .filter((arquivo) => !arquivo.endsWith(".d.ts")
328
659
  && !arquivo.endsWith(".spec.ts")
329
660
  && !arquivo.endsWith(".test.ts"));
661
+ const arquivosRotasAngular = arquivos.filter((arquivo) => arquivoEhRotasAngularConsumer(path.relative(diretorio, arquivo)));
662
+ const arquivosRotasAngularRaiz = new Set(arquivosRotasAngular
663
+ .filter((arquivo) => arquivoEhRotasAngularConsumerRaiz(path.relative(diretorio, arquivo)))
664
+ .map((arquivo) => path.resolve(arquivo)));
665
+ const usarApenasRotasAngularRaiz = arquivosRotasAngularRaiz.size > 0;
330
666
  for (const arquivo of arquivos) {
331
667
  const codigo = await readFile(arquivo, "utf8");
332
668
  const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
@@ -345,6 +681,89 @@ async function indexarTypeScript(diretorios) {
345
681
  simbolo: rota.simbolo,
346
682
  });
347
683
  }
684
+ const superficieNextJs = arquivoEhSuperficieNextJsConsumer(relacao)
685
+ ? inferirRotaNextJsConsumer(relacao)
686
+ : undefined;
687
+ if (superficieNextJs) {
688
+ consumerSurfaces.set(`${superficieNextJs.rota}:${arquivo}:${superficieNextJs.tipoArquivo}`, {
689
+ rota: superficieNextJs.rota,
690
+ arquivo,
691
+ tipoArquivo: superficieNextJs.tipoArquivo,
692
+ });
693
+ rotas.push({
694
+ origem: "nextjs-consumer",
695
+ metodo: "VIEW",
696
+ caminho: superficieNextJs.rota,
697
+ arquivo,
698
+ simbolo: superficieNextJs.tipoArquivo,
699
+ });
700
+ }
701
+ const superficieReact = arquivoEhSuperficieReactViteConsumer(relacao)
702
+ ? inferirRotaReactViteConsumer(relacao)
703
+ : undefined;
704
+ if (superficieReact) {
705
+ consumerSurfaces.set(`${superficieReact.rota}:${arquivo}:${superficieReact.tipoArquivo}`, {
706
+ rota: superficieReact.rota,
707
+ arquivo,
708
+ tipoArquivo: superficieReact.tipoArquivo,
709
+ });
710
+ rotas.push({
711
+ origem: "react-vite-consumer",
712
+ metodo: "VIEW",
713
+ caminho: superficieReact.rota,
714
+ arquivo,
715
+ simbolo: superficieReact.tipoArquivo,
716
+ });
717
+ }
718
+ if (arquivoEhRotasReactViteConsumer(relacao, codigo)) {
719
+ for (const rotaReact of extrairRotasReactViteConsumer(relacao, codigo)) {
720
+ consumerSurfaces.set(`${rotaReact.rota}:${arquivo}:router`, {
721
+ rota: rotaReact.rota,
722
+ arquivo,
723
+ tipoArquivo: "router",
724
+ });
725
+ rotas.push({
726
+ origem: "react-vite-consumer",
727
+ metodo: "VIEW",
728
+ caminho: rotaReact.rota,
729
+ arquivo,
730
+ simbolo: "router",
731
+ });
732
+ if (rotaReact.arquivoComponente) {
733
+ const arquivoComponente = path.join(diretorio, rotaReact.arquivoComponente);
734
+ consumerSurfaces.set(`${rotaReact.rota}:${arquivoComponente}:page`, {
735
+ rota: rotaReact.rota,
736
+ arquivo: arquivoComponente,
737
+ tipoArquivo: "page",
738
+ });
739
+ }
740
+ }
741
+ }
742
+ if (arquivoEhRotasAngularConsumer(relacao) && (!usarApenasRotasAngularRaiz || arquivosRotasAngularRaiz.has(path.resolve(arquivo)))) {
743
+ for (const rotaAngular of await extrairRotasAngularConsumer(diretorio, relacao)) {
744
+ const arquivoRotasAngular = path.join(diretorio, rotaAngular.arquivoRotas);
745
+ consumerSurfaces.set(`${rotaAngular.rota}:${arquivoRotasAngular}:routes`, {
746
+ rota: rotaAngular.rota,
747
+ arquivo: arquivoRotasAngular,
748
+ tipoArquivo: "routes",
749
+ });
750
+ rotas.push({
751
+ origem: "angular-consumer",
752
+ metodo: "VIEW",
753
+ caminho: rotaAngular.rota,
754
+ arquivo: arquivoRotasAngular,
755
+ simbolo: rotaAngular.componente ?? "routes",
756
+ });
757
+ if (rotaAngular.arquivoComponente) {
758
+ const arquivoComponente = path.join(diretorio, rotaAngular.arquivoComponente);
759
+ consumerSurfaces.set(`${rotaAngular.rota}:${arquivoComponente}:component`, {
760
+ rota: rotaAngular.rota,
761
+ arquivo: arquivoComponente,
762
+ tipoArquivo: "component",
763
+ });
764
+ }
765
+ }
766
+ }
348
767
  for (const node of sourceFile.statements) {
349
768
  if (ts.isFunctionDeclaration(node) && node.name) {
350
769
  registrarSimboloTypeScript(simbolos, basesSimbolicas, arquivo, node.name.text);
@@ -396,7 +815,14 @@ async function indexarTypeScript(diretorios) {
396
815
  }
397
816
  }
398
817
  }
399
- return { simbolos: [...simbolos.values()], rotas, recursos: [...recursos.values()] };
818
+ return {
819
+ simbolos: [...simbolos.values()],
820
+ rotas,
821
+ recursos: [...recursos.values()],
822
+ consumerSurfaces: [...consumerSurfaces.values()].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
823
+ || a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
824
+ || a.arquivo.localeCompare(b.arquivo, "pt-BR")),
825
+ };
400
826
  }
401
827
  function registrarSimboloPython(simbolos, basesSimbolicas, arquivo, nome, nomeClasse) {
402
828
  for (const baseSimbolica of basesSimbolicas) {
@@ -493,12 +919,15 @@ async function indexarPython(diretorios) {
493
919
  }
494
920
  async function indexarDart(diretorios) {
495
921
  const simbolos = new Map();
922
+ const rotas = [];
923
+ const consumerSurfaces = new Map();
496
924
  for (const diretorio of diretorios) {
497
925
  const arquivos = (await listarArquivosRecursivos(diretorio, [".dart"]))
498
926
  .filter((arquivo) => !arquivo.endsWith(".g.dart") && !arquivo.endsWith(".freezed.dart"));
499
927
  for (const arquivo of arquivos) {
500
928
  const texto = await readFile(arquivo, "utf8");
501
929
  const basesSimbolicas = caminhosSimbolicos(diretorio, arquivo);
930
+ const relacao = path.relative(diretorio, arquivo);
502
931
  for (const match of texto.matchAll(/(?:Future<[^\n]+>|[\w?<>.,\s]+)\s+(\w+)\(([^)]*)\)\s*(?:async\s*)?\{/g)) {
503
932
  const nome = match[1];
504
933
  if (["build", "toString"].includes(nome)) {
@@ -509,9 +938,62 @@ async function indexarDart(diretorios) {
509
938
  simbolos.set(caminho, { origem: "dart", caminho, arquivo, simbolo: nome });
510
939
  }
511
940
  }
941
+ const superficieFlutter = inferirRotaFlutterConsumer(relacao);
942
+ if (superficieFlutter) {
943
+ consumerSurfaces.set(`${superficieFlutter.rota}:${arquivo}:${superficieFlutter.tipoArquivo}`, {
944
+ rota: superficieFlutter.rota,
945
+ arquivo,
946
+ tipoArquivo: superficieFlutter.tipoArquivo,
947
+ });
948
+ rotas.push({
949
+ origem: "flutter-consumer",
950
+ metodo: "VIEW",
951
+ caminho: superficieFlutter.rota,
952
+ arquivo,
953
+ simbolo: superficieFlutter.tipoArquivo,
954
+ });
955
+ }
956
+ if (arquivoEhRotasFlutterConsumer(relacao, texto)) {
957
+ for (const rotaFlutter of extrairRotasFlutterConsumer(relacao, texto)) {
958
+ consumerSurfaces.set(`${rotaFlutter.rota}:${arquivo}:router`, {
959
+ rota: rotaFlutter.rota,
960
+ arquivo,
961
+ tipoArquivo: "router",
962
+ });
963
+ rotas.push({
964
+ origem: "flutter-consumer",
965
+ metodo: "VIEW",
966
+ caminho: rotaFlutter.rota,
967
+ arquivo,
968
+ simbolo: "router",
969
+ });
970
+ }
971
+ }
512
972
  }
513
973
  }
514
- return [...simbolos.values()];
974
+ return {
975
+ simbolos: [...simbolos.values()],
976
+ rotas,
977
+ consumerSurfaces: [...consumerSurfaces.values()].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
978
+ || a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
979
+ || a.arquivo.localeCompare(b.arquivo, "pt-BR")),
980
+ };
981
+ }
982
+ async function indexarLua(diretorios) {
983
+ const simbolos = new Map();
984
+ for (const diretorio of diretorios) {
985
+ const arquivos = (await listarArquivosRecursivos(diretorio, [".lua"]))
986
+ .filter((arquivo) => !/(^|[\\/])(spec|specs|test|tests)([\\/]|$)/i.test(arquivo))
987
+ .filter((arquivo) => !/[_-](spec|test)\.lua$/i.test(arquivo));
988
+ for (const arquivo of arquivos) {
989
+ const texto = await readFile(arquivo, "utf8");
990
+ const basesSimbolicas = caminhosSimbolicos(diretorio, arquivo);
991
+ for (const simbolo of extrairSimbolosLua(texto)) {
992
+ registrarSimboloGenerico(simbolos, "lua", basesSimbolicas, arquivo, simbolo.simbolo);
993
+ }
994
+ }
995
+ }
996
+ return { simbolos: [...simbolos.values()], rotas: [] };
515
997
  }
516
998
  function registrarSimboloGenerico(simbolos, origem, basesSimbolicas, arquivo, simbolo) {
517
999
  for (const baseSimbolica of basesSimbolicas) {
@@ -863,6 +1345,7 @@ export async function analisarDriftLegado(contexto) {
863
1345
  const indexTs = await indexarTypeScript(contexto.diretoriosCodigo);
864
1346
  const indexPy = await indexarPython(contexto.diretoriosCodigo);
865
1347
  const indexDart = await indexarDart(contexto.diretoriosCodigo);
1348
+ const indexLua = await indexarLua(contexto.diretoriosCodigo);
866
1349
  const indexDotnet = await indexarDotnet(contexto.diretoriosCodigo);
867
1350
  const indexJava = await indexarJava(contexto.diretoriosCodigo);
868
1351
  const indexGo = await indexarGo(contexto.diretoriosCodigo);
@@ -871,7 +1354,8 @@ export async function analisarDriftLegado(contexto) {
871
1354
  const todosSimbolos = [
872
1355
  ...indexTs.simbolos,
873
1356
  ...indexPy.simbolos,
874
- ...indexDart,
1357
+ ...indexDart.simbolos,
1358
+ ...indexLua.simbolos,
875
1359
  ...indexDotnet.simbolos,
876
1360
  ...indexJava.simbolos,
877
1361
  ...indexGo.simbolos,
@@ -881,7 +1365,8 @@ export async function analisarDriftLegado(contexto) {
881
1365
  const mapaImpl = new Map([
882
1366
  ...indexTs.simbolos.map((item) => [item.caminho, item]),
883
1367
  ...indexPy.simbolos.map((item) => [item.caminho, item]),
884
- ...indexDart.map((item) => [item.caminho, item]),
1368
+ ...indexDart.simbolos.map((item) => [item.caminho, item]),
1369
+ ...indexLua.simbolos.map((item) => [item.caminho, item]),
885
1370
  ...indexDotnet.simbolos.map((item) => [item.caminho, item]),
886
1371
  ...indexJava.simbolos.map((item) => [item.caminho, item]),
887
1372
  ...indexGo.simbolos.map((item) => [item.caminho, item]),
@@ -892,6 +1377,7 @@ export async function analisarDriftLegado(contexto) {
892
1377
  const todasRotasIndexadas = [
893
1378
  ...indexTs.rotas,
894
1379
  ...indexPy.rotas,
1380
+ ...indexDart.rotas,
895
1381
  ...indexDotnet.rotas,
896
1382
  ...indexJava.rotas,
897
1383
  ...indexGo.rotas,
@@ -1051,7 +1537,11 @@ export async function analisarDriftLegado(contexto) {
1051
1537
  if (!esperadas.length || !route.metodo || !route.caminho) {
1052
1538
  continue;
1053
1539
  }
1054
- const encontradas = todasRotasIndexadas.filter((rotaResolvida) => esperadas.includes(rotaResolvida.origem));
1540
+ const encontradas = todasRotasIndexadas.filter((rotaResolvida) => rotaResolvida.origem !== "nextjs-consumer"
1541
+ && rotaResolvida.origem !== "react-vite-consumer"
1542
+ && rotaResolvida.origem !== "angular-consumer"
1543
+ && rotaResolvida.origem !== "flutter-consumer"
1544
+ && esperadas.includes(rotaResolvida.origem));
1055
1545
  const combina = encontradas.some((rotaResolvida) => rotaResolvida.metodo === route.metodo
1056
1546
  && normalizarCaminhoRota(rotaResolvida.caminho) === normalizarCaminhoRota(route.caminho));
1057
1547
  if (!combina) {
@@ -1197,9 +1687,30 @@ export async function analisarDriftLegado(contexto) {
1197
1687
  resumo.lacunas.includes("vinculo_quebrado") ? "corrigir vinculos rastreaveis" : "",
1198
1688
  ].filter(Boolean))];
1199
1689
  }
1690
+ const consumerSurfaces = [...indexTs.consumerSurfaces, ...indexDart.consumerSurfaces].sort((a, b) => a.rota.localeCompare(b.rota, "pt-BR")
1691
+ || a.tipoArquivo.localeCompare(b.tipoArquivo, "pt-BR")
1692
+ || a.arquivo.localeCompare(b.arquivo, "pt-BR"));
1693
+ const consumerBridges = [...new Map([...indexTs.simbolos, ...indexDart.simbolos]
1694
+ .filter((simbolo) => simboloEhBridgeConsumer(simbolo.caminho, simbolo.arquivo))
1695
+ .map((simbolo) => [
1696
+ `${simbolo.caminho}:${simbolo.arquivo}:${simbolo.simbolo}`,
1697
+ {
1698
+ caminho: simbolo.caminho,
1699
+ arquivo: simbolo.arquivo,
1700
+ simbolo: simbolo.simbolo,
1701
+ },
1702
+ ])).values()].sort((a, b) => a.caminho.localeCompare(b.caminho, "pt-BR")
1703
+ || a.arquivo.localeCompare(b.arquivo, "pt-BR"));
1704
+ const appRoutes = [...new Set(consumerSurfaces.map((surface) => surface.rota))]
1705
+ .sort((a, b) => a.localeCompare(b, "pt-BR"));
1706
+ const consumerFramework = inferirConsumerFrameworkPrincipal(contexto.fontesLegado, consumerSurfaces, consumerBridges);
1200
1707
  const payloadBase = {
1201
1708
  comando: "drift",
1202
1709
  sucesso: implsQuebrados.length === 0 && rotasDivergentes.length === 0 && recursosDivergentes.length === 0 && vinculosQuebrados.length === 0,
1710
+ consumerFramework,
1711
+ appRoutes,
1712
+ consumerSurfaces,
1713
+ consumerBridges,
1203
1714
  modulos: contexto.modulosSelecionados.map((item) => ({
1204
1715
  caminho: item.caminho,
1205
1716
  modulo: item.resultado.ir?.nome ?? item.resultado.modulo?.nome ?? null,