@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/importador.js
CHANGED
|
@@ -190,6 +190,7 @@ function mapearTipoPrimitivo(tipo) {
|
|
|
190
190
|
const limpo = tipo.trim().replace(/\s+/g, "");
|
|
191
191
|
const base = limpo
|
|
192
192
|
.replace(/^Promise<(.*)>$/, "$1")
|
|
193
|
+
.replace(/^Future<(.*)>$/, "$1")
|
|
193
194
|
.replace(/\|undefined/g, "")
|
|
194
195
|
.replace(/\|null/g, "")
|
|
195
196
|
.replace(/\bundefined\|/g, "")
|
|
@@ -217,10 +218,22 @@ function mapearTipoPrimitivo(tipo) {
|
|
|
217
218
|
if (minusculo === "id" || minusculo.endsWith("id")) {
|
|
218
219
|
return "Id";
|
|
219
220
|
}
|
|
220
|
-
if (minusculo.includes("[]")
|
|
221
|
+
if (minusculo.includes("[]")
|
|
222
|
+
|| minusculo.startsWith("array<")
|
|
223
|
+
|| minusculo.startsWith("record<")
|
|
224
|
+
|| minusculo.startsWith("map<")
|
|
225
|
+
|| minusculo.startsWith("list<")
|
|
226
|
+
|| minusculo.startsWith("list[")
|
|
227
|
+
|| minusculo.startsWith("dict[")) {
|
|
221
228
|
return "Json";
|
|
222
229
|
}
|
|
223
|
-
if (minusculo === "json"
|
|
230
|
+
if (minusculo === "json"
|
|
231
|
+
|| minusculo === "object"
|
|
232
|
+
|| minusculo === "unknown"
|
|
233
|
+
|| minusculo === "any"
|
|
234
|
+
|| minusculo === "dynamic"
|
|
235
|
+
|| minusculo === "void"
|
|
236
|
+
|| minusculo === "none") {
|
|
224
237
|
return minusculo === "void" || minusculo === "none" ? "Vazio" : "Json";
|
|
225
238
|
}
|
|
226
239
|
return tipo.trim();
|
|
@@ -568,6 +581,624 @@ function resolverEscopoImportacaoNextJs(diretorioEntrada) {
|
|
|
568
581
|
diretorioEscopo: resolvido,
|
|
569
582
|
};
|
|
570
583
|
}
|
|
584
|
+
function normalizarCaminhoImportado(caminhoArquivo) {
|
|
585
|
+
return caminhoArquivo.replace(/\\/g, "/");
|
|
586
|
+
}
|
|
587
|
+
function normalizarSegmentoRotaConsumer(segmento) {
|
|
588
|
+
const opcionalCatchAll = segmento.match(/^\[\[\.\.\.([A-Za-z_]\w*)\]\]$/);
|
|
589
|
+
if (opcionalCatchAll) {
|
|
590
|
+
return `{${opcionalCatchAll[1]}}`;
|
|
591
|
+
}
|
|
592
|
+
const catchAll = segmento.match(/^\[\.\.\.([A-Za-z_]\w*)\]$/);
|
|
593
|
+
if (catchAll) {
|
|
594
|
+
return `{${catchAll[1]}}`;
|
|
595
|
+
}
|
|
596
|
+
const dinamico = segmento.match(/^\[([A-Za-z_]\w*)\]$/);
|
|
597
|
+
if (dinamico) {
|
|
598
|
+
return `{${dinamico[1]}}`;
|
|
599
|
+
}
|
|
600
|
+
return segmento;
|
|
601
|
+
}
|
|
602
|
+
function montarCaminhoRotaConsumer(partes) {
|
|
603
|
+
const filtradas = partes
|
|
604
|
+
.filter((segmento) => segmento && segmento !== "index" && !/^\(.*\)$/.test(segmento) && !segmento.startsWith("@"))
|
|
605
|
+
.map(normalizarSegmentoRotaConsumer);
|
|
606
|
+
return filtradas.length > 0 ? `/${filtradas.join("/")}`.replace(/\/+/g, "/") : "/";
|
|
607
|
+
}
|
|
608
|
+
function resolverEscopoImportacaoFrontendConsumer(diretorioEntrada) {
|
|
609
|
+
const resolvido = path.resolve(diretorioEntrada);
|
|
610
|
+
const partes = path.parse(resolvido);
|
|
611
|
+
const segmentos = resolvido.slice(partes.root.length).split(path.sep).filter(Boolean);
|
|
612
|
+
const procurarSequencia = (sequencia) => segmentos.findIndex((segmento, indice) => sequencia.every((item, deslocamento) => segmentos[indice + deslocamento]?.toLowerCase() === item));
|
|
613
|
+
const montarBase = (indice) => indice <= 0
|
|
614
|
+
? partes.root
|
|
615
|
+
: path.join(partes.root, ...segmentos.slice(0, indice));
|
|
616
|
+
for (const sequencia of [
|
|
617
|
+
["src", "pages"],
|
|
618
|
+
["pages"],
|
|
619
|
+
["src", "app", "api"],
|
|
620
|
+
["app", "api"],
|
|
621
|
+
["src", "app"],
|
|
622
|
+
["app"],
|
|
623
|
+
["src", "lib"],
|
|
624
|
+
["lib"],
|
|
625
|
+
]) {
|
|
626
|
+
const indice = procurarSequencia(sequencia);
|
|
627
|
+
if (indice >= 0) {
|
|
628
|
+
return {
|
|
629
|
+
baseProjeto: montarBase(indice),
|
|
630
|
+
diretorioEscopo: resolvido,
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
return {
|
|
635
|
+
baseProjeto: resolvido,
|
|
636
|
+
diretorioEscopo: resolvido,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function arquivoEhBridgeNextJsConsumer(relacaoArquivo) {
|
|
640
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
641
|
+
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
642
|
+
}
|
|
643
|
+
function arquivoEhBridgeReactViteConsumer(relacaoArquivo) {
|
|
644
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
645
|
+
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
646
|
+
}
|
|
647
|
+
function arquivoEhBridgeAngularConsumer(relacaoArquivo) {
|
|
648
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
649
|
+
return /(?:^|\/)(?:src\/)?app\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|js)$/i.test(relacao);
|
|
650
|
+
}
|
|
651
|
+
function arquivoEhSuperficieNextJsConsumer(relacaoArquivo) {
|
|
652
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
653
|
+
return /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
654
|
+
}
|
|
655
|
+
function arquivoEhSuperficieReactViteConsumer(relacaoArquivo) {
|
|
656
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
657
|
+
return /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
658
|
+
|| /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
659
|
+
}
|
|
660
|
+
function arquivoEhRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
661
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
662
|
+
return /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
663
|
+
|| /from\s+["']react-router-dom["']|createBrowserRouter|RouterProvider|useRoutes\s*\(|<Routes\b|<Route\b/.test(codigo ?? "");
|
|
664
|
+
}
|
|
665
|
+
function arquivoEhRotasAngularConsumer(relacaoArquivo) {
|
|
666
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
667
|
+
return /(?:^|\/)(?:src\/)?app(?:\/.+)?\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
668
|
+
}
|
|
669
|
+
function arquivoEhRotasAngularConsumerRaiz(relacaoArquivo) {
|
|
670
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
671
|
+
return /(?:^|\/)(?:src\/)?app\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
672
|
+
}
|
|
673
|
+
function arquivoEhBridgeFlutterConsumer(relacaoArquivo) {
|
|
674
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
675
|
+
return /(?:^|\/)(?:lib\/)?(?:sema_consumer_bridge|api\/sema_contract_bridge|sema\/.+)\.dart$/i.test(relacao);
|
|
676
|
+
}
|
|
677
|
+
function arquivoEhSuperficieFlutterConsumer(relacaoArquivo) {
|
|
678
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
679
|
+
return /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(relacao)
|
|
680
|
+
|| /(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao);
|
|
681
|
+
}
|
|
682
|
+
function arquivoEhRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
683
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
684
|
+
return /(?:^|\/)(?:lib\/)?(?:router|app_router|routes)\.dart$/i.test(relacao)
|
|
685
|
+
|| /MaterialApp(?:\.router)?\s*\(|CupertinoApp(?:\.router)?\s*\(|GoRouter\s*\(/.test(codigo ?? "");
|
|
686
|
+
}
|
|
687
|
+
function inferirCaminhoNextJsConsumer(relacaoArquivo) {
|
|
688
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
689
|
+
const segmentos = relacao.split("/");
|
|
690
|
+
const indiceSrcApp = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "app");
|
|
691
|
+
const indiceApp = segmentos.findIndex((segmento) => segmento === "app");
|
|
692
|
+
const inicioApp = indiceSrcApp >= 0 ? indiceSrcApp + 2 : indiceApp >= 0 ? indiceApp + 1 : -1;
|
|
693
|
+
if (inicioApp < 0) {
|
|
694
|
+
return undefined;
|
|
695
|
+
}
|
|
696
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
697
|
+
const tipoArquivo = arquivoFinal.match(/^(page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/)?.[1];
|
|
698
|
+
if (!tipoArquivo) {
|
|
699
|
+
return undefined;
|
|
700
|
+
}
|
|
701
|
+
const caminhoAteArquivo = segmentos.slice(inicioApp, -1);
|
|
702
|
+
if (caminhoAteArquivo[0] === "api") {
|
|
703
|
+
return undefined;
|
|
704
|
+
}
|
|
705
|
+
const partes = caminhoAteArquivo
|
|
706
|
+
.filter((segmento) => segmento);
|
|
707
|
+
const caminho = montarCaminhoRotaConsumer(partes);
|
|
708
|
+
return {
|
|
709
|
+
caminho,
|
|
710
|
+
arquivo: relacao,
|
|
711
|
+
tipoArquivo,
|
|
712
|
+
};
|
|
713
|
+
}
|
|
714
|
+
function inferirCaminhoReactViteConsumer(relacaoArquivo) {
|
|
715
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
716
|
+
if (!arquivoEhSuperficieReactViteConsumer(relacao)) {
|
|
717
|
+
return undefined;
|
|
718
|
+
}
|
|
719
|
+
if (/(?:^|\/)(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao)) {
|
|
720
|
+
return {
|
|
721
|
+
caminho: "/",
|
|
722
|
+
arquivo: relacao,
|
|
723
|
+
tipoArquivo: "app",
|
|
724
|
+
};
|
|
725
|
+
}
|
|
726
|
+
const segmentos = relacao.split("/");
|
|
727
|
+
const indiceSrcPages = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "pages");
|
|
728
|
+
const indicePages = segmentos.findIndex((segmento) => segmento === "pages");
|
|
729
|
+
const inicioPages = indiceSrcPages >= 0 ? indiceSrcPages + 2 : indicePages >= 0 ? indicePages + 1 : -1;
|
|
730
|
+
if (inicioPages < 0) {
|
|
731
|
+
return undefined;
|
|
732
|
+
}
|
|
733
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
734
|
+
const nomeBase = arquivoFinal.replace(/\.(?:ts|tsx|js|jsx)$/i, "");
|
|
735
|
+
const caminho = montarCaminhoRotaConsumer([...segmentos.slice(inicioPages, -1), nomeBase]);
|
|
736
|
+
return {
|
|
737
|
+
caminho,
|
|
738
|
+
arquivo: relacao,
|
|
739
|
+
tipoArquivo: "page",
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
function inferirCaminhoFlutterConsumer(relacaoArquivo) {
|
|
743
|
+
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
744
|
+
if (!arquivoEhSuperficieFlutterConsumer(relacao)) {
|
|
745
|
+
return undefined;
|
|
746
|
+
}
|
|
747
|
+
if (/(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao)) {
|
|
748
|
+
return {
|
|
749
|
+
caminho: "/",
|
|
750
|
+
arquivo: relacao,
|
|
751
|
+
tipoArquivo: "app",
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
const segmentos = relacao.split("/");
|
|
755
|
+
const indiceLibScreens = segmentos.findIndex((segmento, indice) => segmento === "lib" && ["screens", "pages"].includes(segmentos[indice + 1] ?? ""));
|
|
756
|
+
const indiceScreens = segmentos.findIndex((segmento) => segmento === "screens" || segmento === "pages");
|
|
757
|
+
const inicio = indiceLibScreens >= 0 ? indiceLibScreens + 2 : indiceScreens >= 0 ? indiceScreens + 1 : -1;
|
|
758
|
+
if (inicio < 0) {
|
|
759
|
+
return undefined;
|
|
760
|
+
}
|
|
761
|
+
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
762
|
+
const nomeBase = arquivoFinal
|
|
763
|
+
.replace(/\.(?:dart)$/i, "")
|
|
764
|
+
.replace(/_(screen|page)$/i, "");
|
|
765
|
+
return {
|
|
766
|
+
caminho: montarCaminhoRotaConsumer([...segmentos.slice(inicio, -1), nomeBase]),
|
|
767
|
+
arquivo: relacao,
|
|
768
|
+
tipoArquivo: "screen",
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
function normalizarRotaDeclaradaConsumer(caminhoCru, prefixo = "/") {
|
|
772
|
+
const partesPrefixo = prefixo.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
773
|
+
const partesCaminho = (caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
774
|
+
return montarCaminhoRotaConsumer([...partesPrefixo, ...partesCaminho]);
|
|
775
|
+
}
|
|
776
|
+
function resolverImportRelativoTypeScript(relacaoArquivoBase, especificador) {
|
|
777
|
+
if (!especificador.startsWith(".")) {
|
|
778
|
+
return undefined;
|
|
779
|
+
}
|
|
780
|
+
const baseDir = path.posix.dirname(normalizarCaminhoImportado(relacaoArquivoBase));
|
|
781
|
+
for (const sufixo of ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx", "/index.js", "/index.jsx"]) {
|
|
782
|
+
const candidato = path.posix.normalize(path.posix.join(baseDir, `${especificador}${sufixo}`));
|
|
783
|
+
if (!/\.(?:ts|tsx|js|jsx)$/i.test(candidato)) {
|
|
784
|
+
continue;
|
|
785
|
+
}
|
|
786
|
+
return candidato;
|
|
787
|
+
}
|
|
788
|
+
return undefined;
|
|
789
|
+
}
|
|
790
|
+
function extrairImportsTypeScriptConsumer(relacaoArquivo, codigo) {
|
|
791
|
+
const imports = new Map();
|
|
792
|
+
for (const match of codigo.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*["']([^"']+)["']/g)) {
|
|
793
|
+
const moduloImportado = match[2];
|
|
794
|
+
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, moduloImportado);
|
|
795
|
+
if (!relacaoImportada) {
|
|
796
|
+
continue;
|
|
797
|
+
}
|
|
798
|
+
for (const bruto of match[1].split(",")) {
|
|
799
|
+
const normalizado = bruto.trim();
|
|
800
|
+
if (!normalizado) {
|
|
801
|
+
continue;
|
|
802
|
+
}
|
|
803
|
+
const local = normalizado.split(/\s+as\s+/i).at(-1)?.trim();
|
|
804
|
+
if (local) {
|
|
805
|
+
imports.set(local, relacaoImportada);
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
for (const match of codigo.matchAll(/import\s+([A-Za-z_]\w*)\s+from\s*["']([^"']+)["']/g)) {
|
|
810
|
+
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2]);
|
|
811
|
+
const local = match[1]?.trim();
|
|
812
|
+
if (relacaoImportada && local) {
|
|
813
|
+
imports.set(local, relacaoImportada);
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
return imports;
|
|
817
|
+
}
|
|
818
|
+
function extrairRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
819
|
+
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
820
|
+
const rotas = new Map();
|
|
821
|
+
const registrar = (caminhoCru, componente) => {
|
|
822
|
+
const caminho = normalizarRotaDeclaradaConsumer(caminhoCru);
|
|
823
|
+
const chave = `${caminho}:${normalizarCaminhoImportado(relacaoArquivo)}:${componente ?? "router"}`;
|
|
824
|
+
rotas.set(chave, {
|
|
825
|
+
caminho,
|
|
826
|
+
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
827
|
+
arquivoComponente: componente ? imports.get(componente) : undefined,
|
|
828
|
+
});
|
|
829
|
+
};
|
|
830
|
+
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)) {
|
|
831
|
+
const caminhoCru = match[1] ?? "";
|
|
832
|
+
const componente = match[2] ?? match[3];
|
|
833
|
+
registrar(caminhoCru, componente);
|
|
834
|
+
}
|
|
835
|
+
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)) {
|
|
836
|
+
const caminhoCru = match[2] ? "" : (match[1] ?? "");
|
|
837
|
+
const componente = match[3] ?? match[4];
|
|
838
|
+
registrar(caminhoCru, componente);
|
|
839
|
+
}
|
|
840
|
+
return [...rotas.values()];
|
|
841
|
+
}
|
|
842
|
+
function extrairRotasAngularConsumerDiretas(relacaoArquivo, codigo, prefixo = "/") {
|
|
843
|
+
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
844
|
+
const rotas = [];
|
|
845
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?component\s*:\s*([A-Za-z_]\w*)/g)) {
|
|
846
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
847
|
+
const componente = match[2];
|
|
848
|
+
rotas.push({
|
|
849
|
+
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
850
|
+
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
851
|
+
arquivoComponente: imports.get(componente),
|
|
852
|
+
});
|
|
853
|
+
}
|
|
854
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?loadComponent\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
855
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
856
|
+
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2] ?? "");
|
|
857
|
+
rotas.push({
|
|
858
|
+
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
859
|
+
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
860
|
+
arquivoComponente: relacaoImportada,
|
|
861
|
+
});
|
|
862
|
+
}
|
|
863
|
+
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,360}?loadChildren\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
864
|
+
const caminhoCru = (match[1] ?? "").trim();
|
|
865
|
+
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2] ?? "");
|
|
866
|
+
rotas.push({
|
|
867
|
+
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
868
|
+
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
869
|
+
arquivoRotasFilhas: relacaoImportada,
|
|
870
|
+
});
|
|
871
|
+
}
|
|
872
|
+
return rotas;
|
|
873
|
+
}
|
|
874
|
+
async function extrairRotasAngularConsumer(baseProjeto, relacaoArquivo, prefixo = "/", visitados = new Set()) {
|
|
875
|
+
const relacaoNormalizada = normalizarCaminhoImportado(relacaoArquivo);
|
|
876
|
+
if (visitados.has(relacaoNormalizada)) {
|
|
877
|
+
return [];
|
|
878
|
+
}
|
|
879
|
+
visitados.add(relacaoNormalizada);
|
|
880
|
+
const caminhoAbsoluto = path.join(baseProjeto, relacaoNormalizada);
|
|
881
|
+
let codigo = "";
|
|
882
|
+
try {
|
|
883
|
+
codigo = await readFile(caminhoAbsoluto, "utf8");
|
|
884
|
+
}
|
|
885
|
+
catch {
|
|
886
|
+
return [];
|
|
887
|
+
}
|
|
888
|
+
const diretas = extrairRotasAngularConsumerDiretas(relacaoNormalizada, codigo, prefixo);
|
|
889
|
+
const agregadas = [...diretas];
|
|
890
|
+
for (const rota of diretas) {
|
|
891
|
+
if (!rota.arquivoRotasFilhas) {
|
|
892
|
+
continue;
|
|
893
|
+
}
|
|
894
|
+
agregadas.push(...await extrairRotasAngularConsumer(baseProjeto, rota.arquivoRotasFilhas, rota.caminho, visitados));
|
|
895
|
+
}
|
|
896
|
+
return agregadas;
|
|
897
|
+
}
|
|
898
|
+
function normalizarRotaDeclaradaFlutter(caminhoCru) {
|
|
899
|
+
return montarCaminhoRotaConsumer((caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean));
|
|
900
|
+
}
|
|
901
|
+
function extrairRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
902
|
+
const rotas = new Map();
|
|
903
|
+
const registrar = (caminhoCru) => {
|
|
904
|
+
const caminho = normalizarRotaDeclaradaFlutter(caminhoCru);
|
|
905
|
+
rotas.set(`${caminho}:${normalizarCaminhoImportado(relacaoArquivo)}`, {
|
|
906
|
+
caminho,
|
|
907
|
+
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
908
|
+
});
|
|
909
|
+
};
|
|
910
|
+
for (const match of codigo.matchAll(/GoRoute\s*\([\s\S]{0,220}?path\s*:\s*["'`]([^"'`]+)["'`]/g)) {
|
|
911
|
+
registrar(match[1] ?? "");
|
|
912
|
+
}
|
|
913
|
+
for (const match of codigo.matchAll(/["'`]([^"'`]+)["'`]\s*:\s*\([^)]*\)\s*=>/g)) {
|
|
914
|
+
registrar(match[1] ?? "");
|
|
915
|
+
}
|
|
916
|
+
if (/home\s*:\s*(?:const\s+)?[A-Za-z_]\w*\(/.test(codigo)) {
|
|
917
|
+
registrar("/");
|
|
918
|
+
}
|
|
919
|
+
return [...rotas.values()];
|
|
920
|
+
}
|
|
921
|
+
async function carregarContextosBridgeConsumer(baseProjeto, arquivosBridge) {
|
|
922
|
+
return Promise.all(arquivosBridge.map(async (arquivo) => {
|
|
923
|
+
const texto = await readFile(arquivo, "utf8");
|
|
924
|
+
const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
925
|
+
return {
|
|
926
|
+
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, scriptKind),
|
|
927
|
+
texto,
|
|
928
|
+
relacao: path.relative(baseProjeto, arquivo),
|
|
929
|
+
};
|
|
930
|
+
}));
|
|
931
|
+
}
|
|
932
|
+
function extrairTasksBridgeConsumer(baseProjeto, contextosBridge) {
|
|
933
|
+
const tiposGlobais = consolidarTiposTs(contextosBridge);
|
|
934
|
+
const entitiesRef = new Set();
|
|
935
|
+
const enumsRef = new Set();
|
|
936
|
+
const tasks = [];
|
|
937
|
+
for (const contexto of contextosBridge) {
|
|
938
|
+
contexto.sourceFile.forEachChild((node) => {
|
|
939
|
+
if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
940
|
+
const nome = node.name.text;
|
|
941
|
+
const input = node.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
942
|
+
const output = node.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(node.type.getText(contexto.sourceFile)) === "Vazio"
|
|
943
|
+
? []
|
|
944
|
+
: deduplicarCampos(expandirCamposTs("resultado", node.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
945
|
+
tasks.push({
|
|
946
|
+
nome: nomeTaskBridgeConsumer(nome),
|
|
947
|
+
resumo: `Task consumer importada automaticamente de ${contexto.relacao}#${nome}.`,
|
|
948
|
+
input: deduplicarCampos(input),
|
|
949
|
+
output,
|
|
950
|
+
errors: node.body ? extrairErrosTs(node.body, contexto.sourceFile) : [],
|
|
951
|
+
effects: node.body ? descreverEfeitosPorHeuristica(node.body.getText(contexto.sourceFile)) : [],
|
|
952
|
+
impl: { ts: caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), nome) },
|
|
953
|
+
vinculos: deduplicarVinculos([
|
|
954
|
+
{ tipo: "arquivo", valor: normalizarCaminhoImportado(contexto.relacao) },
|
|
955
|
+
{ tipo: "simbolo", valor: caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), nome) },
|
|
956
|
+
]),
|
|
957
|
+
origemArquivo: contexto.relacao,
|
|
958
|
+
origemSimbolo: nome,
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
if (ts.isClassDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
962
|
+
const nomeClasse = node.name.text;
|
|
963
|
+
for (const member of node.members) {
|
|
964
|
+
if (!ts.isMethodDeclaration(member) || !member.name || !member.body) {
|
|
965
|
+
continue;
|
|
966
|
+
}
|
|
967
|
+
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.PrivateKeyword || modifier.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
968
|
+
continue;
|
|
969
|
+
}
|
|
970
|
+
const nomeMetodo = member.name.getText(contexto.sourceFile);
|
|
971
|
+
if (nomeMetodo === "constructor") {
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
const input = member.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
975
|
+
const output = member.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(member.type.getText(contexto.sourceFile)) === "Vazio"
|
|
976
|
+
? []
|
|
977
|
+
: deduplicarCampos(expandirCamposTs("resultado", member.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
978
|
+
const caminhoSimbolo = caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), `${nomeClasse}.${nomeMetodo}`);
|
|
979
|
+
tasks.push({
|
|
980
|
+
nome: nomeTaskBridgeConsumer(nomeMetodo),
|
|
981
|
+
resumo: `Task consumer importada automaticamente de ${contexto.relacao}#${nomeClasse}.${nomeMetodo}.`,
|
|
982
|
+
input: deduplicarCampos(input),
|
|
983
|
+
output,
|
|
984
|
+
errors: extrairErrosTs(member.body, contexto.sourceFile),
|
|
985
|
+
effects: descreverEfeitosPorHeuristica(member.body.getText(contexto.sourceFile)),
|
|
986
|
+
impl: { ts: caminhoSimbolo },
|
|
987
|
+
vinculos: deduplicarVinculos([
|
|
988
|
+
{ tipo: "arquivo", valor: normalizarCaminhoImportado(contexto.relacao) },
|
|
989
|
+
{ tipo: "simbolo", valor: caminhoSimbolo },
|
|
990
|
+
]),
|
|
991
|
+
origemArquivo: contexto.relacao,
|
|
992
|
+
origemSimbolo: `${nomeClasse}.${nomeMetodo}`,
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
}
|
|
998
|
+
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
999
|
+
return {
|
|
1000
|
+
tasks,
|
|
1001
|
+
entities,
|
|
1002
|
+
enums,
|
|
1003
|
+
};
|
|
1004
|
+
}
|
|
1005
|
+
function montarVinculosSuperficiesConsumer(superficies) {
|
|
1006
|
+
return deduplicarVinculos(superficies.flatMap((superficie) => [
|
|
1007
|
+
{ tipo: "superficie", valor: superficie.caminho },
|
|
1008
|
+
{ tipo: "arquivo", valor: normalizarCaminhoImportado(superficie.arquivo) },
|
|
1009
|
+
]));
|
|
1010
|
+
}
|
|
1011
|
+
async function importarConsumerBase(diretorio, namespaceBase, descricaoFramework, ehBridge, coletarSuperficies) {
|
|
1012
|
+
const escopo = resolverEscopoImportacaoFrontendConsumer(diretorio);
|
|
1013
|
+
const arquivos = await listarArquivosRecursivos(escopo.baseProjeto, [".ts", ".tsx", ".js", ".jsx"]);
|
|
1014
|
+
const arquivosBridge = arquivos.filter((arquivo) => ehBridge(path.relative(escopo.baseProjeto, arquivo)));
|
|
1015
|
+
const contextosBridge = await carregarContextosBridgeConsumer(escopo.baseProjeto, arquivosBridge);
|
|
1016
|
+
const { tasks, entities, enums } = extrairTasksBridgeConsumer(escopo.baseProjeto, contextosBridge);
|
|
1017
|
+
const superficiesImportadas = await coletarSuperficies(escopo.baseProjeto, arquivos);
|
|
1018
|
+
const superficies = montarVinculosSuperficiesConsumer(superficiesImportadas);
|
|
1019
|
+
if (tasks.length === 0 && superficies.length === 0) {
|
|
1020
|
+
return [];
|
|
1021
|
+
}
|
|
1022
|
+
const nomeModulo = namespaceBase.endsWith(".consumer")
|
|
1023
|
+
? namespaceBase
|
|
1024
|
+
: `${namespaceBase}.consumer`;
|
|
1025
|
+
return [{
|
|
1026
|
+
nome: nomeModulo,
|
|
1027
|
+
resumo: `Rascunho Sema importado automaticamente do consumer ${descricaoFramework} em ${escopo.baseProjeto}.`,
|
|
1028
|
+
tasks: deduplicarTarefas(tasks),
|
|
1029
|
+
routes: [],
|
|
1030
|
+
entities,
|
|
1031
|
+
enums,
|
|
1032
|
+
vinculos: superficies,
|
|
1033
|
+
}];
|
|
1034
|
+
}
|
|
1035
|
+
async function coletarSuperficiesNextJsConsumer(baseProjeto, arquivos) {
|
|
1036
|
+
return arquivos
|
|
1037
|
+
.map((arquivo) => inferirCaminhoNextJsConsumer(path.relative(baseProjeto, arquivo)))
|
|
1038
|
+
.filter((item) => Boolean(item));
|
|
1039
|
+
}
|
|
1040
|
+
async function coletarSuperficiesReactViteConsumer(baseProjeto, arquivos) {
|
|
1041
|
+
const superficies = [];
|
|
1042
|
+
for (const arquivo of arquivos) {
|
|
1043
|
+
const relacao = path.relative(baseProjeto, arquivo);
|
|
1044
|
+
const codigo = await readFile(arquivo, "utf8");
|
|
1045
|
+
if (arquivoEhRotasReactViteConsumer(relacao, codigo)) {
|
|
1046
|
+
for (const rota of extrairRotasReactViteConsumer(relacao, codigo)) {
|
|
1047
|
+
superficies.push({
|
|
1048
|
+
caminho: rota.caminho,
|
|
1049
|
+
arquivo: rota.arquivoRotas,
|
|
1050
|
+
tipoArquivo: "router",
|
|
1051
|
+
});
|
|
1052
|
+
if (rota.arquivoComponente) {
|
|
1053
|
+
superficies.push({
|
|
1054
|
+
caminho: rota.caminho,
|
|
1055
|
+
arquivo: rota.arquivoComponente,
|
|
1056
|
+
tipoArquivo: "page",
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
for (const arquivo of arquivos) {
|
|
1063
|
+
const superficie = inferirCaminhoReactViteConsumer(path.relative(baseProjeto, arquivo));
|
|
1064
|
+
if (superficie) {
|
|
1065
|
+
superficies.push(superficie);
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
return superficies;
|
|
1069
|
+
}
|
|
1070
|
+
async function coletarSuperficiesAngularConsumer(baseProjeto, arquivos) {
|
|
1071
|
+
const superficies = [];
|
|
1072
|
+
const arquivosRotas = arquivos.filter((arquivo) => arquivoEhRotasAngularConsumer(path.relative(baseProjeto, arquivo)));
|
|
1073
|
+
const arquivosRaiz = arquivosRotas.filter((arquivo) => arquivoEhRotasAngularConsumerRaiz(path.relative(baseProjeto, arquivo)));
|
|
1074
|
+
const pontosEntrada = arquivosRaiz.length > 0 ? arquivosRaiz : arquivosRotas;
|
|
1075
|
+
for (const arquivoRotas of pontosEntrada) {
|
|
1076
|
+
const relacao = path.relative(baseProjeto, arquivoRotas);
|
|
1077
|
+
for (const rota of await extrairRotasAngularConsumer(baseProjeto, relacao)) {
|
|
1078
|
+
superficies.push({
|
|
1079
|
+
caminho: rota.caminho,
|
|
1080
|
+
arquivo: rota.arquivoRotas,
|
|
1081
|
+
tipoArquivo: "routes",
|
|
1082
|
+
});
|
|
1083
|
+
if (rota.arquivoComponente) {
|
|
1084
|
+
superficies.push({
|
|
1085
|
+
caminho: rota.caminho,
|
|
1086
|
+
arquivo: rota.arquivoComponente,
|
|
1087
|
+
tipoArquivo: "component",
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
return superficies;
|
|
1093
|
+
}
|
|
1094
|
+
async function importarNextJsConsumerBase(diretorio, namespaceBase) {
|
|
1095
|
+
return importarConsumerBase(diretorio, namespaceBase, "Next.js", arquivoEhBridgeNextJsConsumer, coletarSuperficiesNextJsConsumer);
|
|
1096
|
+
}
|
|
1097
|
+
async function importarReactViteConsumerBase(diretorio, namespaceBase) {
|
|
1098
|
+
return importarConsumerBase(diretorio, namespaceBase, "React/Vite", arquivoEhBridgeReactViteConsumer, coletarSuperficiesReactViteConsumer);
|
|
1099
|
+
}
|
|
1100
|
+
async function importarAngularConsumerBase(diretorio, namespaceBase) {
|
|
1101
|
+
return importarConsumerBase(diretorio, namespaceBase, "Angular", arquivoEhBridgeAngularConsumer, coletarSuperficiesAngularConsumer);
|
|
1102
|
+
}
|
|
1103
|
+
async function extrairTasksBridgeFlutterConsumer(baseProjeto, arquivosBridge) {
|
|
1104
|
+
const tasks = [];
|
|
1105
|
+
for (const arquivo of arquivosBridge) {
|
|
1106
|
+
const texto = await readFile(arquivo, "utf8");
|
|
1107
|
+
const relacao = path.relative(baseProjeto, arquivo);
|
|
1108
|
+
for (const match of texto.matchAll(/(?:Future<([^\n]+)>|([\w?<>.,\s]+))\s+(\w+)\(([^)]*)\)\s*(?:async\s*)?\{/g)) {
|
|
1109
|
+
const retorno = (match[1] ?? match[2] ?? "").trim();
|
|
1110
|
+
const nome = match[3];
|
|
1111
|
+
if (["build", "toString", "hashCode"].includes(nome)) {
|
|
1112
|
+
continue;
|
|
1113
|
+
}
|
|
1114
|
+
const parametros = match[4];
|
|
1115
|
+
const input = parametros
|
|
1116
|
+
.split(",")
|
|
1117
|
+
.map((item) => item.trim())
|
|
1118
|
+
.filter(Boolean)
|
|
1119
|
+
.map((item) => item.replace(/^(required|final)\s+/g, ""))
|
|
1120
|
+
.map((item) => {
|
|
1121
|
+
const partes = item.split(/\s+/).filter(Boolean);
|
|
1122
|
+
const nomeParametro = partes.at(-1) ?? "arg";
|
|
1123
|
+
const tipoParametro = partes.slice(0, -1).join(" ");
|
|
1124
|
+
return {
|
|
1125
|
+
nome: paraSnakeCase(nomeParametro),
|
|
1126
|
+
tipo: mapearTipoPrimitivo(tipoParametro || "Json"),
|
|
1127
|
+
obrigatorio: !/\?/.test(tipoParametro),
|
|
1128
|
+
};
|
|
1129
|
+
});
|
|
1130
|
+
const caminhoSimbolo = caminhoImplDart(baseProjeto, arquivo, nome);
|
|
1131
|
+
tasks.push({
|
|
1132
|
+
nome: nomeTaskBridgeConsumer(nome),
|
|
1133
|
+
resumo: `Task consumer importada automaticamente de ${relacao}#${nome}.`,
|
|
1134
|
+
input,
|
|
1135
|
+
output: retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
1136
|
+
? []
|
|
1137
|
+
: [{ nome: "resultado", tipo: mapearTipoPrimitivo(retorno || "Json"), obrigatorio: false }],
|
|
1138
|
+
errors: [],
|
|
1139
|
+
effects: descreverEfeitosPorHeuristica(texto),
|
|
1140
|
+
impl: { dart: caminhoSimbolo },
|
|
1141
|
+
vinculos: deduplicarVinculos([
|
|
1142
|
+
{ tipo: "arquivo", valor: normalizarCaminhoImportado(relacao) },
|
|
1143
|
+
{ tipo: "simbolo", valor: caminhoSimbolo },
|
|
1144
|
+
]),
|
|
1145
|
+
origemArquivo: relacao,
|
|
1146
|
+
origemSimbolo: nome,
|
|
1147
|
+
});
|
|
1148
|
+
}
|
|
1149
|
+
}
|
|
1150
|
+
return tasks;
|
|
1151
|
+
}
|
|
1152
|
+
async function coletarSuperficiesFlutterConsumer(baseProjeto, arquivos) {
|
|
1153
|
+
const superficies = [];
|
|
1154
|
+
for (const arquivo of arquivos) {
|
|
1155
|
+
const relacao = path.relative(baseProjeto, arquivo);
|
|
1156
|
+
const codigo = await readFile(arquivo, "utf8");
|
|
1157
|
+
if (arquivoEhRotasFlutterConsumer(relacao, codigo)) {
|
|
1158
|
+
for (const rota of extrairRotasFlutterConsumer(relacao, codigo)) {
|
|
1159
|
+
superficies.push({
|
|
1160
|
+
caminho: rota.caminho,
|
|
1161
|
+
arquivo: rota.arquivoRotas,
|
|
1162
|
+
tipoArquivo: "router",
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
for (const arquivo of arquivos) {
|
|
1168
|
+
const superficie = inferirCaminhoFlutterConsumer(path.relative(baseProjeto, arquivo));
|
|
1169
|
+
if (superficie) {
|
|
1170
|
+
superficies.push(superficie);
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
return superficies;
|
|
1174
|
+
}
|
|
1175
|
+
async function importarFlutterConsumerBase(diretorio, namespaceBase) {
|
|
1176
|
+
const escopo = resolverEscopoImportacaoFrontendConsumer(diretorio);
|
|
1177
|
+
const arquivos = (await listarArquivosRecursivos(escopo.baseProjeto, [".dart"]))
|
|
1178
|
+
.filter((arquivo) => !arquivo.endsWith(".g.dart") && !arquivo.endsWith(".freezed.dart"));
|
|
1179
|
+
const arquivosBridge = arquivos.filter((arquivo) => arquivoEhBridgeFlutterConsumer(path.relative(escopo.baseProjeto, arquivo)));
|
|
1180
|
+
const tasks = await extrairTasksBridgeFlutterConsumer(escopo.baseProjeto, arquivosBridge);
|
|
1181
|
+
const superficiesImportadas = await coletarSuperficiesFlutterConsumer(escopo.baseProjeto, arquivos);
|
|
1182
|
+
const superficies = montarVinculosSuperficiesConsumer(superficiesImportadas);
|
|
1183
|
+
if (tasks.length === 0 && superficies.length === 0) {
|
|
1184
|
+
return [];
|
|
1185
|
+
}
|
|
1186
|
+
const nomeModulo = namespaceBase.endsWith(".consumer")
|
|
1187
|
+
? namespaceBase
|
|
1188
|
+
: `${namespaceBase}.consumer`;
|
|
1189
|
+
return [{
|
|
1190
|
+
nome: nomeModulo,
|
|
1191
|
+
resumo: `Rascunho Sema importado automaticamente do consumer Flutter em ${escopo.baseProjeto}.`,
|
|
1192
|
+
tasks: deduplicarTarefas(tasks),
|
|
1193
|
+
routes: [],
|
|
1194
|
+
entities: [],
|
|
1195
|
+
enums: [],
|
|
1196
|
+
vinculos: superficies,
|
|
1197
|
+
}];
|
|
1198
|
+
}
|
|
1199
|
+
function nomeTaskBridgeConsumer(nome) {
|
|
1200
|
+
return paraSnakeCase(nome.replace(/^sema/, "")) || paraSnakeCase(nome) || "task_consumer";
|
|
1201
|
+
}
|
|
571
1202
|
function extrairChamadaServiceTs(node) {
|
|
572
1203
|
let encontrado;
|
|
573
1204
|
const visitar = (atual) => {
|
|
@@ -614,6 +1245,16 @@ function deduplicarEfeitos(effects) {
|
|
|
614
1245
|
}
|
|
615
1246
|
return [...mapa.values()];
|
|
616
1247
|
}
|
|
1248
|
+
function deduplicarVinculos(vinculos) {
|
|
1249
|
+
const mapa = new Map();
|
|
1250
|
+
for (const vinculo of vinculos) {
|
|
1251
|
+
const chave = `${vinculo.tipo}:${vinculo.valor}`;
|
|
1252
|
+
if (!mapa.has(chave)) {
|
|
1253
|
+
mapa.set(chave, vinculo);
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
return [...mapa.values()];
|
|
1257
|
+
}
|
|
617
1258
|
function deduplicarEntidades(entities) {
|
|
618
1259
|
const mapa = new Map();
|
|
619
1260
|
for (const entity of entities) {
|
|
@@ -644,6 +1285,7 @@ function deduplicarTarefas(tasks) {
|
|
|
644
1285
|
existente.output = deduplicarCampos([...existente.output, ...task.output]);
|
|
645
1286
|
existente.errors = deduplicarErros([...existente.errors, ...task.errors]);
|
|
646
1287
|
existente.effects = deduplicarEfeitos([...existente.effects, ...task.effects]);
|
|
1288
|
+
existente.vinculos = deduplicarVinculos([...(existente.vinculos ?? []), ...(task.vinculos ?? [])]);
|
|
647
1289
|
}
|
|
648
1290
|
return [...mapa.values()];
|
|
649
1291
|
}
|
|
@@ -723,6 +1365,26 @@ function renderizarImpl(impl, indentacao = " ") {
|
|
|
723
1365
|
"",
|
|
724
1366
|
];
|
|
725
1367
|
}
|
|
1368
|
+
function renderizarValorVinculo(vinculo) {
|
|
1369
|
+
if (vinculo.tipo === "simbolo") {
|
|
1370
|
+
return vinculo.valor;
|
|
1371
|
+
}
|
|
1372
|
+
if (vinculo.tipo === "arquivo" || vinculo.valor.includes("/") || vinculo.valor.includes("\\") || vinculo.valor.includes("{")) {
|
|
1373
|
+
return `"${escaparTexto(vinculo.valor)}"`;
|
|
1374
|
+
}
|
|
1375
|
+
return vinculo.valor;
|
|
1376
|
+
}
|
|
1377
|
+
function renderizarVinculos(vinculos, indentacao = " ") {
|
|
1378
|
+
if (!vinculos || vinculos.length === 0) {
|
|
1379
|
+
return [];
|
|
1380
|
+
}
|
|
1381
|
+
return [
|
|
1382
|
+
`${indentacao}vinculos {`,
|
|
1383
|
+
...vinculos.map((vinculo) => `${indentacao} ${vinculo.tipo}: ${renderizarValorVinculo(vinculo)}`),
|
|
1384
|
+
`${indentacao}}`,
|
|
1385
|
+
"",
|
|
1386
|
+
];
|
|
1387
|
+
}
|
|
726
1388
|
function renderizarTask(task) {
|
|
727
1389
|
const linhas = [
|
|
728
1390
|
` task ${task.nome} {`,
|
|
@@ -734,6 +1396,7 @@ function renderizarTask(task) {
|
|
|
734
1396
|
...renderizarCampos("output", task.output, " ", true),
|
|
735
1397
|
...renderizarEffects(task.effects, " "),
|
|
736
1398
|
...renderizarImpl(task.impl, " "),
|
|
1399
|
+
...renderizarVinculos(task.vinculos, " "),
|
|
737
1400
|
...renderizarErrors(task.errors, " "),
|
|
738
1401
|
];
|
|
739
1402
|
linhas.push(" guarantees {");
|
|
@@ -791,6 +1454,7 @@ function moduloParaCodigo(modulo) {
|
|
|
791
1454
|
` resumo: "${escaparTexto(modulo.resumo)}"`,
|
|
792
1455
|
" }",
|
|
793
1456
|
"",
|
|
1457
|
+
...renderizarVinculos(modulo.vinculos, " "),
|
|
794
1458
|
...modulo.enums.flatMap(renderizarEnum),
|
|
795
1459
|
...modulo.entities.flatMap(renderizarEntidade),
|
|
796
1460
|
...modulo.tasks.flatMap(renderizarTask),
|
|
@@ -1672,7 +2336,7 @@ async function importarDartBase(diretorio, namespaceBase) {
|
|
|
1672
2336
|
}
|
|
1673
2337
|
return modulos;
|
|
1674
2338
|
}
|
|
1675
|
-
function criarModuloImportadoSimples(nome, resumo, tasks, routes = []) {
|
|
2339
|
+
function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = []) {
|
|
1676
2340
|
sincronizarRotasComTasks(routes, tasks);
|
|
1677
2341
|
return {
|
|
1678
2342
|
nome,
|
|
@@ -1681,6 +2345,7 @@ function criarModuloImportadoSimples(nome, resumo, tasks, routes = []) {
|
|
|
1681
2345
|
routes: deduplicarRotas(routes),
|
|
1682
2346
|
entities: [],
|
|
1683
2347
|
enums: [],
|
|
2348
|
+
vinculos: deduplicarVinculos(vinculos),
|
|
1684
2349
|
};
|
|
1685
2350
|
}
|
|
1686
2351
|
function acumularModuloImportado(modulos, modulo) {
|
|
@@ -1693,6 +2358,7 @@ function acumularModuloImportado(modulos, modulo) {
|
|
|
1693
2358
|
existente.routes = deduplicarRotas([...existente.routes, ...modulo.routes]);
|
|
1694
2359
|
existente.entities = deduplicarEntidades([...existente.entities, ...modulo.entities]);
|
|
1695
2360
|
existente.enums = deduplicarEnums([...existente.enums, ...modulo.enums]);
|
|
2361
|
+
existente.vinculos = deduplicarVinculos([...(existente.vinculos ?? []), ...(modulo.vinculos ?? [])]);
|
|
1696
2362
|
}
|
|
1697
2363
|
function selecionarSimbolosPreferidos(simbolos) {
|
|
1698
2364
|
const mapa = new Map();
|
|
@@ -2029,6 +2695,18 @@ export async function importarProjetoLegado(fonte, diretorio, namespaceBase) {
|
|
|
2029
2695
|
else if (fonte === "nextjs") {
|
|
2030
2696
|
modulos = await importarNextJsBase(base, namespace);
|
|
2031
2697
|
}
|
|
2698
|
+
else if (fonte === "nextjs-consumer") {
|
|
2699
|
+
modulos = await importarNextJsConsumerBase(base, namespace);
|
|
2700
|
+
}
|
|
2701
|
+
else if (fonte === "react-vite-consumer") {
|
|
2702
|
+
modulos = await importarReactViteConsumerBase(base, namespace);
|
|
2703
|
+
}
|
|
2704
|
+
else if (fonte === "angular-consumer") {
|
|
2705
|
+
modulos = await importarAngularConsumerBase(base, namespace);
|
|
2706
|
+
}
|
|
2707
|
+
else if (fonte === "flutter-consumer") {
|
|
2708
|
+
modulos = await importarFlutterConsumerBase(base, namespace);
|
|
2709
|
+
}
|
|
2032
2710
|
else if (fonte === "firebase") {
|
|
2033
2711
|
modulos = await importarFirebaseBase(base, namespace);
|
|
2034
2712
|
}
|