@semacode/cli 1.5.36 → 1.5.37
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/AGENT_CONTEXT_PACK.json +76 -8
- package/LICENSE +1 -2
- package/SEMA_BRIEF.curto.txt +8 -6
- package/SEMA_BRIEF.md +240 -204
- package/SEMA_BRIEF.micro.txt +9 -6
- package/SEMA_INDEX.json +2079 -1907
- package/dist/agentContext.d.ts +19 -0
- package/dist/agentContext.js +26 -0
- package/dist/agentContext.js.map +1 -0
- package/dist/agentContextPack.d.ts +3 -0
- package/dist/agentContextPack.js +403 -0
- package/dist/agentContextPack.js.map +1 -0
- package/dist/agentContextTipos.d.ts +96 -0
- package/dist/agentContextTipos.js +55 -0
- package/dist/agentContextTipos.js.map +1 -0
- package/dist/agentEntryPoints.d.ts +13 -0
- package/dist/agentEntryPoints.js +422 -0
- package/dist/agentEntryPoints.js.map +1 -0
- package/dist/authorAnalise.d.ts +15 -0
- package/dist/authorAnalise.js +210 -0
- package/dist/authorAnalise.js.map +1 -0
- package/dist/authorPoliticas.d.ts +37 -0
- package/dist/authorPoliticas.js +340 -0
- package/dist/authorPoliticas.js.map +1 -0
- package/dist/billing/index.d.ts +1 -1
- package/dist/billing/index.js +6 -2
- package/dist/billing/index.js.map +1 -1
- package/dist/bridge.js +2 -0
- package/dist/bridge.js.map +1 -1
- package/dist/carregarModulos.d.ts +2 -0
- package/dist/carregarModulos.js +9 -0
- package/dist/carregarModulos.js.map +1 -0
- package/dist/cliArgs.d.ts +6 -0
- package/dist/cliArgs.js +70 -0
- package/dist/cliArgs.js.map +1 -0
- package/dist/contexto.js +2 -0
- package/dist/contexto.js.map +1 -1
- package/dist/controleComercialSupabase.js.map +1 -1
- package/dist/controleComercialSupabaseAdmin.js.map +1 -1
- package/dist/controleComercialSupabaseCadastro.js.map +1 -1
- package/dist/controleComercialSupabaseConsumo.js.map +1 -1
- package/dist/controleComercialSupabaseConta.js.map +1 -1
- package/dist/controleComercialSupabaseProfiles.js.map +1 -1
- package/dist/dev/index.js +2 -0
- package/dist/dev/index.js.map +1 -1
- package/dist/dev/watcher.d.ts +1 -0
- package/dist/dev/watcher.js +4 -0
- package/dist/dev/watcher.js.map +1 -0
- package/dist/docs/resolver.d.ts +1 -0
- package/dist/docs/resolver.js +4 -0
- package/dist/docs/resolver.js.map +1 -0
- package/dist/docs.d.ts +2 -56
- package/dist/docs.js +5 -502
- package/dist/docs.js.map +1 -1
- package/dist/docs.part01.d.ts +78 -0
- package/dist/docs.part01.js +347 -0
- package/dist/docs.part01.js.map +1 -0
- package/dist/docs.part02.d.ts +20 -0
- package/dist/docs.part02.js +181 -0
- package/dist/docs.part02.js.map +1 -0
- package/dist/doctorCommand.d.ts +27 -0
- package/dist/doctorCommand.js +160 -0
- package/dist/doctorCommand.js.map +1 -0
- package/dist/drift.contrato.d.ts +23 -0
- package/dist/drift.contrato.js +33 -0
- package/dist/drift.contrato.js.map +1 -0
- package/dist/drift.d.ts +13 -227
- package/dist/drift.js +16 -3924
- package/dist/drift.js.map +1 -1
- package/dist/drift.part01.d.ts +252 -0
- package/dist/drift.part01.js +183 -0
- package/dist/drift.part01.js.map +1 -0
- package/dist/drift.part02.d.ts +30 -0
- package/dist/drift.part02.js +342 -0
- package/dist/drift.part02.js.map +1 -0
- package/dist/drift.part03.d.ts +26 -0
- package/dist/drift.part03.js +343 -0
- package/dist/drift.part03.js.map +1 -0
- package/dist/drift.part04.d.ts +46 -0
- package/dist/drift.part04.js +354 -0
- package/dist/drift.part04.js.map +1 -0
- package/dist/drift.part05.d.ts +47 -0
- package/dist/drift.part05.js +353 -0
- package/dist/drift.part05.js.map +1 -0
- package/dist/drift.part06.d.ts +17 -0
- package/dist/drift.part06.js +381 -0
- package/dist/drift.part06.js.map +1 -0
- package/dist/drift.part07.d.ts +48 -0
- package/dist/drift.part07.js +377 -0
- package/dist/drift.part07.js.map +1 -0
- package/dist/drift.part08.d.ts +26 -0
- package/dist/drift.part08.js +333 -0
- package/dist/drift.part08.js.map +1 -0
- package/dist/drift.part09.d.ts +22 -0
- package/dist/drift.part09.js +322 -0
- package/dist/drift.part09.js.map +1 -0
- package/dist/drift.part10.d.ts +11 -0
- package/dist/drift.part10.js +116 -0
- package/dist/drift.part10.js.map +1 -0
- package/dist/drift.part11.d.ts +3 -0
- package/dist/drift.part11.js +320 -0
- package/dist/drift.part11.js.map +1 -0
- package/dist/drift.part12.d.ts +17 -0
- package/dist/drift.part12.js +289 -0
- package/dist/drift.part12.js.map +1 -0
- package/dist/drift.part13.d.ts +17 -0
- package/dist/drift.part13.js +86 -0
- package/dist/drift.part13.js.map +1 -0
- package/dist/drift.part14.d.ts +44 -0
- package/dist/drift.part14.js +402 -0
- package/dist/drift.part14.js.map +1 -0
- package/dist/driftOrcamento.d.ts +69 -0
- package/dist/driftOrcamento.js +280 -0
- package/dist/driftOrcamento.js.map +1 -0
- package/dist/execucoesExternas.d.ts +10 -0
- package/dist/execucoesExternas.js +51 -0
- package/dist/execucoesExternas.js.map +1 -0
- package/dist/exemplosOficiais.d.ts +10 -0
- package/dist/exemplosOficiais.js +63 -0
- package/dist/exemplosOficiais.js.map +1 -0
- package/dist/fsGovernado.d.ts +10 -0
- package/dist/fsGovernado.js +50 -0
- package/dist/fsGovernado.js.map +1 -0
- package/dist/geracaoCore.d.ts +64 -0
- package/dist/geracaoCore.js +381 -0
- package/dist/geracaoCore.js.map +1 -0
- package/dist/iaPrompts.d.ts +6 -0
- package/dist/iaPrompts.js +318 -0
- package/dist/iaPrompts.js.map +1 -0
- package/dist/importador.d.ts +9 -31
- package/dist/importador.js +11 -2938
- package/dist/importador.js.map +1 -1
- package/dist/importador.part01.d.ts +150 -0
- package/dist/importador.part01.js +256 -0
- package/dist/importador.part01.js.map +1 -0
- package/dist/importador.part02.d.ts +25 -0
- package/dist/importador.part02.js +359 -0
- package/dist/importador.part02.js.map +1 -0
- package/dist/importador.part03.d.ts +53 -0
- package/dist/importador.part03.js +366 -0
- package/dist/importador.part03.js.map +1 -0
- package/dist/importador.part04.d.ts +26 -0
- package/dist/importador.part04.js +374 -0
- package/dist/importador.part04.js.map +1 -0
- package/dist/importador.part05.d.ts +28 -0
- package/dist/importador.part05.js +340 -0
- package/dist/importador.part05.js.map +1 -0
- package/dist/importador.part06.d.ts +8 -0
- package/dist/importador.part06.js +327 -0
- package/dist/importador.part06.js.map +1 -0
- package/dist/importador.part07.d.ts +23 -0
- package/dist/importador.part07.js +300 -0
- package/dist/importador.part07.js.map +1 -0
- package/dist/importador.part08.d.ts +12 -0
- package/dist/importador.part08.js +378 -0
- package/dist/importador.part08.js.map +1 -0
- package/dist/importador.part09.d.ts +16 -0
- package/dist/importador.part09.js +319 -0
- package/dist/importador.part09.js.map +1 -0
- package/dist/index.d.ts +12 -1
- package/dist/index.js +16 -7945
- package/dist/index.js.map +1 -1
- package/dist/index.part01.d.ts +148 -0
- package/dist/index.part01.js +252 -0
- package/dist/index.part01.js.map +1 -0
- package/dist/index.part02.d.ts +17 -0
- package/dist/index.part02.js +344 -0
- package/dist/index.part02.js.map +1 -0
- package/dist/index.part03.d.ts +59 -0
- package/dist/index.part03.js +352 -0
- package/dist/index.part03.js.map +1 -0
- package/dist/index.part04.d.ts +20 -0
- package/dist/index.part04.js +358 -0
- package/dist/index.part04.js.map +1 -0
- package/dist/index.part05.d.ts +10 -0
- package/dist/index.part05.js +370 -0
- package/dist/index.part05.js.map +1 -0
- package/dist/index.part06.d.ts +14 -0
- package/dist/index.part06.js +336 -0
- package/dist/index.part06.js.map +1 -0
- package/dist/index.part07.d.ts +9 -0
- package/dist/index.part07.js +287 -0
- package/dist/index.part07.js.map +1 -0
- package/dist/index.part08.d.ts +1 -0
- package/dist/index.part08.js +206 -0
- package/dist/index.part08.js.map +1 -0
- package/dist/init/index.js +2 -0
- package/dist/init/index.js.map +1 -1
- package/dist/init/templates.d.ts +2 -11
- package/dist/init/templates.js +4 -659
- package/dist/init/templates.js.map +1 -1
- package/dist/init/templates.part01.d.ts +11 -0
- package/dist/init/templates.part01.js +399 -0
- package/dist/init/templates.part01.js.map +1 -0
- package/dist/init/templates.part02.d.ts +8 -0
- package/dist/init/templates.part02.js +265 -0
- package/dist/init/templates.part02.js.map +1 -0
- package/dist/initCommand.d.ts +3 -0
- package/dist/initCommand.js +41 -0
- package/dist/initCommand.js.map +1 -0
- package/dist/initTemplatesBackend.d.ts +2 -0
- package/dist/initTemplatesBackend.js +127 -0
- package/dist/initTemplatesBackend.js.map +1 -0
- package/dist/initTemplatesBase.d.ts +9 -0
- package/dist/initTemplatesBase.js +79 -0
- package/dist/initTemplatesBase.js.map +1 -0
- package/dist/initTemplatesFlutter.d.ts +2 -0
- package/dist/initTemplatesFlutter.js +185 -0
- package/dist/initTemplatesFlutter.js.map +1 -0
- package/dist/initTemplatesRuntime.d.ts +2 -0
- package/dist/initTemplatesRuntime.js +494 -0
- package/dist/initTemplatesRuntime.js.map +1 -0
- package/dist/initTemplatesWeb.d.ts +2 -0
- package/dist/initTemplatesWeb.js +429 -0
- package/dist/initTemplatesWeb.js.map +1 -0
- package/dist/mcpInstalarChaveCommand.d.ts +1 -0
- package/dist/mcpInstalarChaveCommand.js +141 -0
- package/dist/mcpInstalarChaveCommand.js.map +1 -0
- package/dist/mcpRemoto.js.map +1 -1
- package/dist/mcp_chave.d.ts +1 -0
- package/dist/mcp_chave.js +4 -0
- package/dist/mcp_chave.js.map +1 -0
- package/dist/profileArtefatoBase.d.ts +30 -0
- package/dist/profileArtefatoBase.js +129 -0
- package/dist/profileArtefatoBase.js.map +1 -0
- package/dist/profileArtefatoValidadores.d.ts +9 -0
- package/dist/profileArtefatoValidadores.js +287 -0
- package/dist/profileArtefatoValidadores.js.map +1 -0
- package/dist/profileAuthorCommand.d.ts +6 -0
- package/dist/profileAuthorCommand.js +442 -0
- package/dist/profileAuthorCommand.js.map +1 -0
- package/dist/profileAuthorTipos.d.ts +225 -0
- package/dist/profileAuthorTipos.js +6 -0
- package/dist/profileAuthorTipos.js.map +1 -0
- package/dist/profileCatalogo.d.ts +8 -0
- package/dist/profileCatalogo.js +235 -0
- package/dist/profileCatalogo.js.map +1 -0
- package/dist/profileCommand.d.ts +33 -0
- package/dist/profileCommand.js +256 -0
- package/dist/profileCommand.js.map +1 -0
- package/dist/profileOrquestracao.d.ts +33 -0
- package/dist/profileOrquestracao.js +53 -0
- package/dist/profileOrquestracao.js.map +1 -0
- package/dist/profileRegras.d.ts +19 -0
- package/dist/profileRegras.js +219 -0
- package/dist/profileRegras.js.map +1 -0
- package/dist/profileRulePacks.d.ts +3 -0
- package/dist/profileRulePacks.js +334 -0
- package/dist/profileRulePacks.js.map +1 -0
- package/dist/profiles/validate.d.ts +1 -0
- package/dist/profiles/validate.js +4 -0
- package/dist/profiles/validate.js.map +1 -0
- package/dist/projeto.d.ts +4 -53
- package/dist/projeto.js +5 -649
- package/dist/projeto.js.map +1 -1
- package/dist/projetoBusca.d.ts +7 -0
- package/dist/projetoBusca.js +142 -0
- package/dist/projetoBusca.js.map +1 -0
- package/dist/projetoCarregar.d.ts +2 -0
- package/dist/projetoCarregar.js +50 -0
- package/dist/projetoCarregar.js.map +1 -0
- package/dist/projetoConfig.d.ts +10 -0
- package/dist/projetoConfig.js +89 -0
- package/dist/projetoConfig.js.map +1 -0
- package/dist/projetoLegado.d.ts +3 -0
- package/dist/projetoLegado.js +175 -0
- package/dist/projetoLegado.js.map +1 -0
- package/dist/projetoOrigens.d.ts +6 -0
- package/dist/projetoOrigens.js +185 -0
- package/dist/projetoOrigens.js.map +1 -0
- package/dist/projetoResolucao.d.ts +8 -0
- package/dist/projetoResolucao.js +43 -0
- package/dist/projetoResolucao.js.map +1 -0
- package/dist/projetoTipos.d.ts +43 -0
- package/dist/projetoTipos.js +4 -0
- package/dist/projetoTipos.js.map +1 -0
- package/dist/runnerValidacaoRemota.js.map +1 -1
- package/dist/runnerValidacaoRemotaBateria.js +2 -0
- package/dist/runnerValidacaoRemotaBateria.js.map +1 -1
- package/dist/runnerValidacaoRemotaExecucao.js +2 -0
- package/dist/runnerValidacaoRemotaExecucao.js.map +1 -1
- package/dist/runnerValidacaoRemotaRelatorio.js +2 -0
- package/dist/runnerValidacaoRemotaRelatorio.js.map +1 -1
- package/dist/runnerValidacaoRemotaSnapshot.js +2 -0
- package/dist/runnerValidacaoRemotaSnapshot.js.map +1 -1
- package/dist/runnerValidacaoRemotaWorkspace.js +2 -0
- package/dist/runnerValidacaoRemotaWorkspace.js.map +1 -1
- package/dist/sync/index.js +2 -0
- package/dist/sync/index.js.map +1 -1
- package/dist/textoListas.d.ts +4 -0
- package/dist/textoListas.js +22 -0
- package/dist/textoListas.js.map +1 -0
- package/dist/typescript-http-body.d.ts +12 -0
- package/dist/typescript-http-body.js +145 -0
- package/dist/typescript-http-body.js.map +1 -0
- package/dist/typescript-http-expressoes.d.ts +17 -0
- package/dist/typescript-http-expressoes.js +194 -0
- package/dist/typescript-http-expressoes.js.map +1 -0
- package/dist/typescript-http-modelos.d.ts +45 -0
- package/dist/typescript-http-modelos.js +82 -0
- package/dist/typescript-http-modelos.js.map +1 -0
- package/dist/typescript-http-rotas.d.ts +9 -0
- package/dist/typescript-http-rotas.js +129 -0
- package/dist/typescript-http-rotas.js.map +1 -0
- package/dist/typescript-http-semantica.d.ts +11 -0
- package/dist/typescript-http-semantica.js +329 -0
- package/dist/typescript-http-semantica.js.map +1 -0
- package/dist/typescript-http.d.ts +3 -35
- package/dist/typescript-http.js +4 -853
- package/dist/typescript-http.js.map +1 -1
- package/docs/AGENT_STARTER.md +1 -1
- package/docs/agentes-por-capacidade.md +46 -3
- package/docs/documentacao.md +1 -1
- package/docs/fluxo-pratico-ia-sema.md +1 -1
- package/docs/mcp.md +12 -0
- package/docs/pagamento-ponta-a-ponta.md +1 -1
- package/docs/persistencia-vendor-first.md +1 -1
- package/docs/prompt-base-ia-sema.md +1 -1
- package/docs/repositories.md +2 -2
- package/docs/seguranca.md +1 -1
- package/docs/sintaxe.md +1 -1
- package/exemplos/agendamento.sema +1 -1
- package/exemplos/assinatura.sema +1 -1
- package/exemplos/auditoria.sema +1 -1
- package/exemplos/autenticacao.sema +1 -1
- package/exemplos/author_obra_comum.sema +1 -1
- package/exemplos/author_tema_sensivel.sema +1 -1
- package/exemplos/automacao.sema +1 -1
- package/exemplos/cadastro_usuario.sema +1 -1
- package/exemplos/calculadora.sema +1 -1
- package/exemplos/crud_simples.sema +1 -1
- package/exemplos/estoque.sema +1 -1
- package/exemplos/exportacao.sema +1 -1
- package/exemplos/fila.sema +1 -1
- package/exemplos/integracao_externa.sema +1 -1
- package/exemplos/multi_tenant.sema +1 -1
- package/exemplos/notificacao.sema +1 -1
- package/exemplos/operacao_estrategia.sema +132 -633
- package/exemplos/operacao_estrategia_discovery.sema +220 -0
- package/exemplos/operacao_estrategia_fluxo.sema +114 -0
- package/exemplos/operacao_estrategia_gates.sema +106 -0
- package/exemplos/operacao_estrategia_quarentena.sema +133 -0
- package/exemplos/operacao_estrategia_rollout.sema +124 -0
- package/exemplos/pagamento.sema +1 -1
- package/exemplos/pagamento_dominio.sema +1 -1
- package/exemplos/pedido.sema +1 -1
- package/exemplos/permissao.sema +1 -1
- package/exemplos/persistencia_vendor_first.sema +1 -1
- package/exemplos/profile_game.sema +1 -1
- package/exemplos/profile_legal.sema +1 -1
- package/exemplos/profile_ops.sema +1 -1
- package/exemplos/profile_research.sema +1 -1
- package/exemplos/profile_software.sema +1 -1
- package/exemplos/profile_workflow_n8n.sema +1 -1
- package/exemplos/relatorio.sema +1 -1
- package/exemplos/replica_analitica_erp.sema +1 -1
- package/exemplos/testes_embutidos.sema +1 -1
- package/exemplos/tratamento_erro.sema +1 -1
- package/exemplos/upload_arquivo.sema +1 -1
- package/exemplos/webhook.sema +1 -1
- package/llms-full.txt +13 -8
- package/llms.txt +12 -7
- package/node_modules/@sema/gerador-css/dist/index.d.ts +2 -3
- package/node_modules/@sema/gerador-css/dist/index.js +4 -599
- package/node_modules/@sema/gerador-css/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-css/dist/index.part01.d.ts +6 -0
- package/node_modules/@sema/gerador-css/dist/index.part01.js +49 -0
- package/node_modules/@sema/gerador-css/dist/index.part01.js.map +1 -0
- package/node_modules/@sema/gerador-css/dist/index.part02.d.ts +3 -0
- package/node_modules/@sema/gerador-css/dist/index.part02.js +471 -0
- package/node_modules/@sema/gerador-css/dist/index.part02.js.map +1 -0
- package/node_modules/@sema/gerador-python/dist/index.d.ts +2 -6
- package/node_modules/@sema/gerador-python/dist/index.js +4 -771
- package/node_modules/@sema/gerador-python/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-python/dist/index.part01.d.ts +28 -0
- package/node_modules/@sema/gerador-python/dist/index.part01.js +383 -0
- package/node_modules/@sema/gerador-python/dist/index.part01.js.map +1 -0
- package/node_modules/@sema/gerador-python/dist/index.part02.d.ts +20 -0
- package/node_modules/@sema/gerador-python/dist/index.part02.js +396 -0
- package/node_modules/@sema/gerador-python/dist/index.part02.js.map +1 -0
- package/node_modules/@sema/gerador-typescript/dist/index.d.ts +3 -6
- package/node_modules/@sema/gerador-typescript/dist/index.js +5 -810
- package/node_modules/@sema/gerador-typescript/dist/index.js.map +1 -1
- package/node_modules/@sema/gerador-typescript/dist/index.part01.d.ts +25 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part01.js +358 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part01.js.map +1 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part02.d.ts +14 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part02.js +405 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part02.js.map +1 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part03.d.ts +5 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part03.js +60 -0
- package/node_modules/@sema/gerador-typescript/dist/index.part03.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +2 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.d.ts +6 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.js +40 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/snippets.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.d.ts +2 -9
- package/node_modules/@sema/nucleo/dist/formatador/index.js +4 -467
- package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/formatador/index.part01.d.ts +38 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.part01.js +382 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.part01.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.part02.d.ts +4 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.part02.js +92 -0
- package/node_modules/@sema/nucleo/dist/formatador/index.part02.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/index.d.ts +2 -0
- package/node_modules/@sema/nucleo/dist/index.js +6 -0
- package/node_modules/@sema/nucleo/dist/index.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.d.ts +3 -5
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +5 -880
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.part01.d.ts +30 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js +398 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part02.d.ts +41 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part02.js +184 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part02.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part03.d.ts +5 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js +310 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.d.ts +3 -9
- package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.d.ts +11 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js +150 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js +5 -768
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/parser/parser.modulo.d.ts +3 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js +222 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part01.d.ts +9 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part01.js +61 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part01.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part02.d.ts +40 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part02.js +373 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part02.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part03.d.ts +4 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part03.js +9 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part03.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/persistencia/contratos.js +2 -0
- package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +3 -59
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +2 -1682
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.d.ts +89 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js +292 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.d.ts +29 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.js +168 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part02.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.d.ts +11 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.js +185 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part03.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.d.ts +30 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.js +200 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part04.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.d.ts +6 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.js +193 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part05.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.d.ts +11 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.js +208 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part06.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.d.ts +11 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.js +247 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part07.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.d.ts +3 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js +249 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.d.ts +2 -106
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.js +4 -474
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.d.ts +109 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.js +259 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part01.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.d.ts +9 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.js +223 -0
- package/node_modules/@sema/nucleo/dist/semantico/estruturas.part02.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.d.ts +21 -0
- package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.js +40 -0
- package/node_modules/@sema/nucleo/dist/semantico/orcamentoSemantico.js.map +1 -0
- package/package.json +10 -10
package/dist/importador.js
CHANGED
|
@@ -1,2939 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
import { extrairRotasTypeScriptHttp, inferirSemanticaHandlerTypeScriptHttp, localizarExportacaoTypeScriptHttp, } from "./typescript-http.js";
|
|
13
|
-
import { coletarSuperficiesAngularStandaloneConsumer } from "./angular-consumer-standalone.js";
|
|
14
|
-
const DIRETORIOS_IGNORADOS = new Set([
|
|
15
|
-
".git",
|
|
16
|
-
".hg",
|
|
17
|
-
".svn",
|
|
18
|
-
".gradle",
|
|
19
|
-
".cargo",
|
|
20
|
-
"node_modules",
|
|
21
|
-
"dist",
|
|
22
|
-
"build",
|
|
23
|
-
"bin",
|
|
24
|
-
"obj",
|
|
25
|
-
".next",
|
|
26
|
-
".nuxt",
|
|
27
|
-
".dart_tool",
|
|
28
|
-
"__pycache__",
|
|
29
|
-
".venv",
|
|
30
|
-
"venv",
|
|
31
|
-
"coverage",
|
|
32
|
-
".tmp",
|
|
33
|
-
"generated",
|
|
34
|
-
"vendor",
|
|
35
|
-
"ephemeral",
|
|
36
|
-
]);
|
|
37
|
-
const SUFIXOS_WRAPPER = ["Entrada", "Saida", "Dto", "Request", "Response", "Payload", "Body", "Input", "Output"];
|
|
38
|
-
const NOMES_RESERVADOS_CAMPO = new Set([
|
|
39
|
-
"module",
|
|
40
|
-
"use",
|
|
41
|
-
"type",
|
|
42
|
-
"entity",
|
|
43
|
-
"enum",
|
|
44
|
-
"task",
|
|
45
|
-
"input",
|
|
46
|
-
"output",
|
|
47
|
-
"rules",
|
|
48
|
-
"effects",
|
|
49
|
-
"impl",
|
|
50
|
-
"guarantees",
|
|
51
|
-
"state",
|
|
52
|
-
"flow",
|
|
53
|
-
"route",
|
|
54
|
-
"tests",
|
|
55
|
-
"error",
|
|
56
|
-
"docs",
|
|
57
|
-
"comments",
|
|
58
|
-
"fields",
|
|
59
|
-
"invariants",
|
|
60
|
-
"transitions",
|
|
61
|
-
"given",
|
|
62
|
-
"when",
|
|
63
|
-
"expect",
|
|
64
|
-
"caso",
|
|
65
|
-
"required",
|
|
66
|
-
]);
|
|
67
|
-
function escaparTexto(texto) {
|
|
68
|
-
return texto.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
69
|
-
}
|
|
70
|
-
function paraSnakeCase(valor) {
|
|
71
|
-
return valor
|
|
72
|
-
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
73
|
-
.replace(/[^A-Za-z0-9_]+/g, "_")
|
|
74
|
-
.replace(/_{2,}/g, "_")
|
|
75
|
-
.replace(/^_+|_+$/g, "")
|
|
76
|
-
.toLowerCase();
|
|
77
|
-
}
|
|
78
|
-
function paraIdentificadorModulo(valor) {
|
|
79
|
-
return normalizarSegmentoModulo(valor).replace(/_+/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
80
|
-
}
|
|
81
|
-
function normalizarNomeCampoImportado(valor) {
|
|
82
|
-
const normalizado = paraSnakeCase(valor);
|
|
83
|
-
return NOMES_RESERVADOS_CAMPO.has(normalizado)
|
|
84
|
-
? `${normalizado}_campo`
|
|
85
|
-
: normalizado;
|
|
86
|
-
}
|
|
87
|
-
function nomeProjetoPadrao(diretorio) {
|
|
88
|
-
const base = path.basename(diretorio);
|
|
89
|
-
if (["src", "app", "api", "backend", "server"].includes(base.toLowerCase())) {
|
|
90
|
-
return `${path.basename(path.dirname(diretorio))}.${base}`;
|
|
91
|
-
}
|
|
92
|
-
return base;
|
|
93
|
-
}
|
|
94
|
-
export function inferirNamespaceBase(diretorio, namespaceExplicito) {
|
|
95
|
-
if (namespaceExplicito) {
|
|
96
|
-
return namespaceExplicito
|
|
97
|
-
.split(".")
|
|
98
|
-
.map((segmento) => paraIdentificadorModulo(segmento))
|
|
99
|
-
.filter(Boolean)
|
|
100
|
-
.join(".");
|
|
101
|
-
}
|
|
102
|
-
return ["legado", ...nomeProjetoPadrao(diretorio).split(/[\\/._-]+/g)]
|
|
103
|
-
.map((segmento) => paraIdentificadorModulo(segmento))
|
|
104
|
-
.filter(Boolean)
|
|
105
|
-
.join(".");
|
|
106
|
-
}
|
|
107
|
-
async function listarArquivosRecursivos(diretorio, extensoes) {
|
|
108
|
-
const entradas = await readdir(diretorio, { withFileTypes: true });
|
|
109
|
-
const encontrados = [];
|
|
110
|
-
for (const entrada of entradas) {
|
|
111
|
-
if (DIRETORIOS_IGNORADOS.has(entrada.name)) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const caminhoAtual = path.join(diretorio, entrada.name);
|
|
115
|
-
if (entrada.isDirectory()) {
|
|
116
|
-
encontrados.push(...await listarArquivosRecursivos(caminhoAtual, extensoes));
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
if (extensoes.some((extensao) => entrada.name.endsWith(extensao))) {
|
|
120
|
-
encontrados.push(caminhoAtual);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
return encontrados.sort((a, b) => a.localeCompare(b, "pt-BR"));
|
|
124
|
-
}
|
|
125
|
-
function inferirContextoPorArquivo(relacao, opcoes) {
|
|
126
|
-
const semExtensao = relacao.replace(/\.[^.]+$/, "");
|
|
127
|
-
const segmentosOriginais = semExtensao.split(path.sep).filter(Boolean);
|
|
128
|
-
const segmentos = segmentosOriginais.map((segmento) => paraIdentificadorModulo(segmento)).filter(Boolean);
|
|
129
|
-
if (segmentos[0] === "src" || segmentos[0] === "app") {
|
|
130
|
-
segmentos.shift();
|
|
131
|
-
segmentosOriginais.shift();
|
|
132
|
-
}
|
|
133
|
-
const ultimo = segmentos.at(-1) ?? "";
|
|
134
|
-
const semSufixo = ultimo
|
|
135
|
-
.replace(/(\.controller|\.service|\.module|_router|_service|_schemas|_contract)$/g, "")
|
|
136
|
-
.replace(/(controller|service|module|router|schemas|contract)$/g, "")
|
|
137
|
-
.replace(/_+$/g, "");
|
|
138
|
-
if (segmentos.length === 0) {
|
|
139
|
-
return ["importado"];
|
|
140
|
-
}
|
|
141
|
-
if (!opcoes?.preservarUltimo && semSufixo && semSufixo !== ultimo) {
|
|
142
|
-
segmentos[segmentos.length - 1] = semSufixo;
|
|
143
|
-
}
|
|
144
|
-
if (opcoes?.snakeCaseUltimo && segmentos.length > 0) {
|
|
145
|
-
segmentos[segmentos.length - 1] = paraSnakeCase(segmentosOriginais[segmentosOriginais.length - 1] ?? ultimo);
|
|
146
|
-
}
|
|
147
|
-
if (segmentos.length > 1 && segmentos[segmentos.length - 1] === segmentos[segmentos.length - 2]) {
|
|
148
|
-
segmentos.pop();
|
|
149
|
-
}
|
|
150
|
-
return segmentos;
|
|
151
|
-
}
|
|
152
|
-
function juntarCaminhoHttp(base, sufixo) {
|
|
153
|
-
const partes = [base ?? "", sufixo ?? ""]
|
|
154
|
-
.map((item) => item.trim())
|
|
155
|
-
.filter(Boolean)
|
|
156
|
-
.map((item) => item.replace(/^\/+|\/+$/g, ""));
|
|
157
|
-
const caminho = `/${partes.join("/")}`.replace(/\/+/g, "/");
|
|
158
|
-
return caminho === "//" ? "/" : caminho;
|
|
159
|
-
}
|
|
160
|
-
function extrairTextoLiteral(expr) {
|
|
161
|
-
if (!expr) {
|
|
162
|
-
return undefined;
|
|
163
|
-
}
|
|
164
|
-
if (ts.isStringLiteralLike(expr) || ts.isNoSubstitutionTemplateLiteral(expr)) {
|
|
165
|
-
return expr.text;
|
|
166
|
-
}
|
|
167
|
-
if (ts.isNumericLiteral(expr)) {
|
|
168
|
-
return expr.text;
|
|
169
|
-
}
|
|
170
|
-
return undefined;
|
|
171
|
-
}
|
|
172
|
-
function listarDecoradores(node) {
|
|
173
|
-
return ts.canHaveDecorators(node) ? ts.getDecorators(node) ?? [] : [];
|
|
174
|
-
}
|
|
175
|
-
function lerDecorator(node, nomes) {
|
|
176
|
-
for (const decorator of listarDecoradores(node)) {
|
|
177
|
-
const expressao = decorator.expression;
|
|
178
|
-
if (ts.isCallExpression(expressao)) {
|
|
179
|
-
const alvo = expressao.expression;
|
|
180
|
-
if (ts.isIdentifier(alvo) && nomes.includes(alvo.text)) {
|
|
181
|
-
return { nome: alvo.text, argumentos: expressao.arguments };
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
else if (ts.isIdentifier(expressao) && nomes.includes(expressao.text)) {
|
|
185
|
-
return { nome: expressao.text, argumentos: ts.factory.createNodeArray() };
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
return undefined;
|
|
189
|
-
}
|
|
190
|
-
function mapearTipoPrimitivo(tipo) {
|
|
191
|
-
const limpo = tipo.trim().replace(/\s+/g, "");
|
|
192
|
-
const base = limpo
|
|
193
|
-
.replace(/^Promise<(.*)>$/, "$1")
|
|
194
|
-
.replace(/^Future<(.*)>$/, "$1")
|
|
195
|
-
.replace(/\|undefined/g, "")
|
|
196
|
-
.replace(/\|null/g, "")
|
|
197
|
-
.replace(/\bundefined\|/g, "")
|
|
198
|
-
.replace(/\bnull\|/g, "")
|
|
199
|
-
.trim();
|
|
200
|
-
const minusculo = base.toLowerCase();
|
|
201
|
-
if (minusculo === "string" || minusculo === "texto") {
|
|
202
|
-
return "Texto";
|
|
203
|
-
}
|
|
204
|
-
if (minusculo === "number" || minusculo === "float" || minusculo === "double") {
|
|
205
|
-
return "Decimal";
|
|
206
|
-
}
|
|
207
|
-
if (minusculo === "int" || minusculo === "integer" || minusculo === "inteiro") {
|
|
208
|
-
return "Inteiro";
|
|
209
|
-
}
|
|
210
|
-
if (minusculo === "boolean" || minusculo === "bool") {
|
|
211
|
-
return "Booleano";
|
|
212
|
-
}
|
|
213
|
-
if (minusculo === "date") {
|
|
214
|
-
return "Data";
|
|
215
|
-
}
|
|
216
|
-
if (minusculo === "datetime" || minusculo === "timestamp") {
|
|
217
|
-
return "DataHora";
|
|
218
|
-
}
|
|
219
|
-
if (minusculo === "id" || minusculo.endsWith("id")) {
|
|
220
|
-
return "Id";
|
|
221
|
-
}
|
|
222
|
-
if (minusculo.includes("[]")
|
|
223
|
-
|| minusculo.startsWith("array<")
|
|
224
|
-
|| minusculo.startsWith("record<")
|
|
225
|
-
|| minusculo.startsWith("map<")
|
|
226
|
-
|| minusculo.startsWith("list<")
|
|
227
|
-
|| minusculo.startsWith("list[")
|
|
228
|
-
|| minusculo.startsWith("dict[")) {
|
|
229
|
-
return "Json";
|
|
230
|
-
}
|
|
231
|
-
if (minusculo === "json"
|
|
232
|
-
|| minusculo === "object"
|
|
233
|
-
|| minusculo === "unknown"
|
|
234
|
-
|| minusculo === "any"
|
|
235
|
-
|| minusculo === "dynamic"
|
|
236
|
-
|| minusculo === "void"
|
|
237
|
-
|| minusculo === "none") {
|
|
238
|
-
return minusculo === "void" || minusculo === "none" ? "Vazio" : "Json";
|
|
239
|
-
}
|
|
240
|
-
return tipo.trim();
|
|
241
|
-
}
|
|
242
|
-
function limparTipoBackend(tipo) {
|
|
243
|
-
if (!tipo) {
|
|
244
|
-
return undefined;
|
|
245
|
-
}
|
|
246
|
-
return tipo
|
|
247
|
-
.trim()
|
|
248
|
-
.replace(/^Task<(.+)>$/i, "$1")
|
|
249
|
-
.replace(/^ActionResult<(.+)>$/i, "$1")
|
|
250
|
-
.replace(/^IActionResult$/i, "Json")
|
|
251
|
-
.replace(/^Results<(.+)>$/i, "$1")
|
|
252
|
-
.replace(/^ResponseEntity<(.+)>$/i, "$1")
|
|
253
|
-
.replace(/^Optional<(.+)>$/i, "$1")
|
|
254
|
-
.replace(/^Result<(.+)>$/i, "$1")
|
|
255
|
-
.replace(/^impl\s+IntoResponse$/i, "Json")
|
|
256
|
-
.replace(/^Json<(.+)>$/i, "$1")
|
|
257
|
-
.replace(/^Option<(.+)>$/i, "$1")
|
|
258
|
-
.replace(/^Vec<(.+)>$/i, "Json")
|
|
259
|
-
.replace(/^List<(.+)>$/i, "Json")
|
|
260
|
-
.replace(/^Map<(.+)>$/i, "Json")
|
|
261
|
-
.replace(/^Dictionary<(.+)>$/i, "Json");
|
|
262
|
-
}
|
|
263
|
-
function mapearTipoBackendParaSema(tipo) {
|
|
264
|
-
const limpo = limparTipoBackend(tipo);
|
|
265
|
-
if (!limpo) {
|
|
266
|
-
return "Json";
|
|
267
|
-
}
|
|
268
|
-
const basico = mapearTipoPrimitivo(limpo);
|
|
269
|
-
if (basico !== limpo) {
|
|
270
|
-
return basico;
|
|
271
|
-
}
|
|
272
|
-
if (/\[\]$/.test(limpo) || /^(IEnumerable|IReadOnlyList|List|Vec|HashMap|Map|Dictionary)</.test(limpo)) {
|
|
273
|
-
return "Json";
|
|
274
|
-
}
|
|
275
|
-
if (/^(void|unit|\(\)|nil)$/i.test(limpo)) {
|
|
276
|
-
return "Vazio";
|
|
277
|
-
}
|
|
278
|
-
if (/\b(uuid|guid)\b/i.test(limpo)) {
|
|
279
|
-
return "Id";
|
|
280
|
-
}
|
|
281
|
-
return "Json";
|
|
282
|
-
}
|
|
283
|
-
function criarCampoResultadoBackend(tipo) {
|
|
284
|
-
const tipoSema = mapearTipoBackendParaSema(tipo);
|
|
285
|
-
return tipoSema === "Vazio"
|
|
286
|
-
? []
|
|
287
|
-
: [{ nome: "resultado", tipo: tipoSema, obrigatorio: false }];
|
|
288
|
-
}
|
|
289
|
-
function camposDeParametrosRotaBackend(parametros) {
|
|
290
|
-
return parametros.map((parametro) => ({
|
|
291
|
-
nome: normalizarNomeCampoImportado(parametro.nome),
|
|
292
|
-
tipo: parametro.tipoSema,
|
|
293
|
-
obrigatorio: true,
|
|
294
|
-
}));
|
|
295
|
-
}
|
|
296
|
-
function pareceWrapperTipo(nome) {
|
|
297
|
-
return SUFIXOS_WRAPPER.some((sufixo) => nome.endsWith(sufixo)) || /(entrada|saida|dto|request|response|payload|body|input|output)/i.test(nome);
|
|
298
|
-
}
|
|
299
|
-
function descreverEfeitosPorHeuristica(codigo) {
|
|
300
|
-
const texto = codigo.toLowerCase();
|
|
301
|
-
const efeitos = [];
|
|
302
|
-
const adicionar = (categoria, alvo, criticidade) => {
|
|
303
|
-
if (!efeitos.some((efeito) => efeito.categoria === categoria && efeito.alvo === alvo)) {
|
|
304
|
-
efeitos.push({ categoria, alvo, criticidade });
|
|
305
|
-
}
|
|
306
|
-
};
|
|
307
|
-
if (/(prisma\.|repository\.|\.create\(|\.update\(|\.delete\(|\.save\()/i.test(codigo)) {
|
|
308
|
-
adicionar("persistencia", "banco", "alta");
|
|
309
|
-
}
|
|
310
|
-
if (/(findmany|findunique|findfirst|\.find\(|\.select\(|\.query\(|\.get\()/i.test(texto)) {
|
|
311
|
-
adicionar("consulta", "dados", "media");
|
|
312
|
-
}
|
|
313
|
-
if (/(emit\(|publish\(|dispatch\(|eventbus|event_emitter)/i.test(texto)) {
|
|
314
|
-
adicionar("evento", "dominio", "media");
|
|
315
|
-
}
|
|
316
|
-
if (/(notify|notification|sendmessage|send_email|telegram|smtp|mail)/i.test(texto)) {
|
|
317
|
-
adicionar("notificacao", "usuarios", "media");
|
|
318
|
-
}
|
|
319
|
-
if (/(audit|logger|logging|log\.|trace|observability)/i.test(texto)) {
|
|
320
|
-
adicionar("auditoria", "operacao", "baixa");
|
|
321
|
-
}
|
|
322
|
-
return efeitos;
|
|
323
|
-
}
|
|
324
|
-
function deduplicarDatabases(databases) {
|
|
325
|
-
const mapa = new Map();
|
|
326
|
-
for (const database of databases) {
|
|
327
|
-
const chave = `${database.engine}:${database.nome}`;
|
|
328
|
-
const existente = mapa.get(chave);
|
|
329
|
-
if (!existente) {
|
|
330
|
-
mapa.set(chave, {
|
|
331
|
-
...database,
|
|
332
|
-
resources: [...database.resources],
|
|
333
|
-
diagnostics: [...(database.diagnostics ?? [])],
|
|
334
|
-
});
|
|
335
|
-
continue;
|
|
336
|
-
}
|
|
337
|
-
const recursos = new Map();
|
|
338
|
-
for (const recurso of [...existente.resources, ...database.resources]) {
|
|
339
|
-
recursos.set(`${recurso.tipo}:${recurso.nome}`, recurso);
|
|
340
|
-
}
|
|
341
|
-
existente.resources = [...recursos.values()];
|
|
342
|
-
existente.diagnostics = [...new Set([...(existente.diagnostics ?? []), ...(database.diagnostics ?? [])])];
|
|
343
|
-
}
|
|
344
|
-
return [...mapa.values()];
|
|
345
|
-
}
|
|
346
|
-
function inferirDatabasesPorHeuristica(codigo, relacao) {
|
|
347
|
-
const databases = [];
|
|
348
|
-
const adicionar = (database) => {
|
|
349
|
-
databases.push(database);
|
|
350
|
-
};
|
|
351
|
-
const texto = codigo.toLowerCase();
|
|
352
|
-
if (/(postgresql|postgres\b|node-postgres|pg\.pool|pgclient|typeorm.+postgres|sequelize.+postgres|provider\s*=\s*["']postgresql["'])/i.test(codigo)) {
|
|
353
|
-
adicionar({
|
|
354
|
-
nome: "principal_postgres",
|
|
355
|
-
resumo: `Persistencia PostgreSQL inferida automaticamente de ${relacao}.`,
|
|
356
|
-
engine: "postgres",
|
|
357
|
-
queryModel: "sql",
|
|
358
|
-
transactionModel: "mvcc",
|
|
359
|
-
resources: [
|
|
360
|
-
{ tipo: "table", nome: "tabelas_relacionais", table: "legado_principal" },
|
|
361
|
-
{ tipo: "query", nome: "consultas_sql", mode: "sql" },
|
|
362
|
-
],
|
|
363
|
-
diagnostics: ["inferido_por_heuristica"],
|
|
364
|
-
});
|
|
365
|
-
}
|
|
366
|
-
if (/(mysql\b|mariadb|mysql2|typeorm.+mysql|sequelize.+mysql|provider\s*=\s*["']mysql["'])/i.test(codigo)) {
|
|
367
|
-
adicionar({
|
|
368
|
-
nome: "principal_mysql",
|
|
369
|
-
resumo: `Persistencia MySQL inferida automaticamente de ${relacao}.`,
|
|
370
|
-
engine: "mysql",
|
|
371
|
-
queryModel: "sql",
|
|
372
|
-
transactionModel: "bloqueio",
|
|
373
|
-
resources: [
|
|
374
|
-
{ tipo: "table", nome: "tabelas_relacionais", table: "legado_principal" },
|
|
375
|
-
{ tipo: "query", nome: "consultas_sql", mode: "sql" },
|
|
376
|
-
],
|
|
377
|
-
diagnostics: ["inferido_por_heuristica"],
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
if (/(sqlite\b|better-sqlite3|provider\s*=\s*["']sqlite["'])/i.test(codigo)) {
|
|
381
|
-
adicionar({
|
|
382
|
-
nome: "principal_sqlite",
|
|
383
|
-
resumo: `Persistencia SQLite inferida automaticamente de ${relacao}.`,
|
|
384
|
-
engine: "sqlite",
|
|
385
|
-
queryModel: "sql",
|
|
386
|
-
transactionModel: "single_thread",
|
|
387
|
-
resources: [
|
|
388
|
-
{ tipo: "table", nome: "tabelas_locais", table: "legado_local" },
|
|
389
|
-
{ tipo: "query", nome: "consultas_locais", mode: "sql" },
|
|
390
|
-
],
|
|
391
|
-
diagnostics: ["inferido_por_heuristica"],
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
if (/(mongodb|mongoose|mongo\.collection|mongoclient|prisma.+mongodb|provider\s*=\s*["']mongodb["'])/i.test(codigo)) {
|
|
395
|
-
adicionar({
|
|
396
|
-
nome: "principal_mongodb",
|
|
397
|
-
resumo: `Persistencia MongoDB inferida automaticamente de ${relacao}.`,
|
|
398
|
-
engine: "mongodb",
|
|
399
|
-
queryModel: "documento",
|
|
400
|
-
transactionModel: "documento",
|
|
401
|
-
resources: [
|
|
402
|
-
{ tipo: "collection", nome: "colecoes_documentais", collection: "documentos" },
|
|
403
|
-
{ tipo: "document", nome: "documentos_agregados", mode: /aggregate|\$match|\$group/i.test(codigo) ? "pipeline" : "documento" },
|
|
404
|
-
],
|
|
405
|
-
diagnostics: ["inferido_por_heuristica"],
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
if (/(redis\b|ioredis|upstash|bullmq|xadd|xreadgroup)/i.test(codigo)) {
|
|
409
|
-
adicionar({
|
|
410
|
-
nome: "principal_redis",
|
|
411
|
-
resumo: `Persistencia Redis inferida automaticamente de ${relacao}.`,
|
|
412
|
-
engine: "redis",
|
|
413
|
-
queryModel: "chave_valor",
|
|
414
|
-
transactionModel: "single_thread",
|
|
415
|
-
resources: [
|
|
416
|
-
{ tipo: "keyspace", nome: "estado_chaves", ttl: /\bttl\b|expire\(/i.test(codigo) ? "300s" : undefined },
|
|
417
|
-
{ tipo: "stream", nome: "eventos_stream", surface: /bullmq|queue|worker/i.test(codigo) ? "fila" : "evento" },
|
|
418
|
-
],
|
|
419
|
-
diagnostics: ["inferido_por_heuristica"],
|
|
420
|
-
});
|
|
421
|
-
}
|
|
422
|
-
return deduplicarDatabases(databases);
|
|
423
|
-
}
|
|
424
|
-
function normalizarNomeErroBruto(nome) {
|
|
425
|
-
return paraSnakeCase(nome.replace(/(Error|Erro|Exception)$/i, "")) || "erro_importado";
|
|
426
|
-
}
|
|
427
|
-
function extrairErrosTs(node, sourceFile) {
|
|
428
|
-
const encontrados = new Map();
|
|
429
|
-
const visitar = (atual) => {
|
|
430
|
-
if (ts.isThrowStatement(atual) && atual.expression) {
|
|
431
|
-
const expressao = atual.expression;
|
|
432
|
-
if (ts.isNewExpression(expressao)) {
|
|
433
|
-
const nomeErro = expressao.expression.getText(sourceFile);
|
|
434
|
-
const mensagem = extrairTextoLiteral(expressao.arguments?.[0]) ?? `Erro importado automaticamente de ${nomeErro}.`;
|
|
435
|
-
encontrados.set(normalizarNomeErroBruto(nomeErro), mensagem);
|
|
436
|
-
}
|
|
437
|
-
}
|
|
438
|
-
atual.forEachChild(visitar);
|
|
439
|
-
};
|
|
440
|
-
node.forEachChild(visitar);
|
|
441
|
-
return [...encontrados.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
442
|
-
}
|
|
443
|
-
function extrairTiposTs(sourceFile) {
|
|
444
|
-
const tipos = new Map();
|
|
445
|
-
const adicionarObjeto = (nome, campos) => {
|
|
446
|
-
if (!campos.length || tipos.has(nome)) {
|
|
447
|
-
return;
|
|
448
|
-
}
|
|
449
|
-
tipos.set(nome, { tipo: "objeto", nome, campos });
|
|
450
|
-
};
|
|
451
|
-
const adicionarEnum = (nome, valores) => {
|
|
452
|
-
if (!valores.length || tipos.has(nome)) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
tipos.set(nome, { tipo: "enum", nome, valores });
|
|
456
|
-
};
|
|
457
|
-
sourceFile.forEachChild((node) => {
|
|
458
|
-
if (ts.isInterfaceDeclaration(node) && node.name) {
|
|
459
|
-
const campos = node.members
|
|
460
|
-
.filter(ts.isPropertySignature)
|
|
461
|
-
.map((member) => ({
|
|
462
|
-
nome: member.name.getText(sourceFile),
|
|
463
|
-
tipoTexto: member.type?.getText(sourceFile),
|
|
464
|
-
obrigatorio: !member.questionToken,
|
|
465
|
-
}));
|
|
466
|
-
adicionarObjeto(node.name.text, campos);
|
|
467
|
-
return;
|
|
468
|
-
}
|
|
469
|
-
if (ts.isClassDeclaration(node) && node.name) {
|
|
470
|
-
const campos = node.members
|
|
471
|
-
.filter((member) => ts.isPropertyDeclaration(member) && Boolean(member.name))
|
|
472
|
-
.map((member) => ({
|
|
473
|
-
nome: member.name.getText(sourceFile),
|
|
474
|
-
tipoTexto: member.type?.getText(sourceFile),
|
|
475
|
-
obrigatorio: !member.questionToken,
|
|
476
|
-
}));
|
|
477
|
-
adicionarObjeto(node.name.text, campos);
|
|
478
|
-
return;
|
|
479
|
-
}
|
|
480
|
-
if (ts.isTypeAliasDeclaration(node) && node.name) {
|
|
481
|
-
if (ts.isUnionTypeNode(node.type) && node.type.types.every((tipo) => ts.isLiteralTypeNode(tipo) && ts.isStringLiteralLike(tipo.literal))) {
|
|
482
|
-
adicionarEnum(node.name.text, node.type.types
|
|
483
|
-
.map((tipo) => ts.isLiteralTypeNode(tipo) && ts.isStringLiteralLike(tipo.literal) ? tipo.literal.text : undefined)
|
|
484
|
-
.filter((valor) => Boolean(valor)));
|
|
485
|
-
return;
|
|
486
|
-
}
|
|
487
|
-
if (ts.isTypeLiteralNode(node.type)) {
|
|
488
|
-
const campos = node.type.members
|
|
489
|
-
.filter(ts.isPropertySignature)
|
|
490
|
-
.map((member) => ({
|
|
491
|
-
nome: member.name.getText(sourceFile),
|
|
492
|
-
tipoTexto: member.type?.getText(sourceFile),
|
|
493
|
-
obrigatorio: !member.questionToken,
|
|
494
|
-
}));
|
|
495
|
-
adicionarObjeto(node.name.text, campos);
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
});
|
|
499
|
-
return tipos;
|
|
500
|
-
}
|
|
501
|
-
function mapearTipoTsParaSema(tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
502
|
-
if (!tipoTexto) {
|
|
503
|
-
return "Json";
|
|
504
|
-
}
|
|
505
|
-
const basico = mapearTipoPrimitivo(tipoTexto);
|
|
506
|
-
if (basico !== tipoTexto.trim()) {
|
|
507
|
-
return basico;
|
|
508
|
-
}
|
|
509
|
-
const limpo = tipoTexto
|
|
510
|
-
.trim()
|
|
511
|
-
.replace(/^Promise<(.*)>$/, "$1")
|
|
512
|
-
.replace(/\| undefined/g, "")
|
|
513
|
-
.replace(/\| null/g, "")
|
|
514
|
-
.replace(/Readonly<(.+)>/, "$1")
|
|
515
|
-
.replace(/Partial<(.+)>/, "$1")
|
|
516
|
-
.trim();
|
|
517
|
-
if (tipos.has(limpo)) {
|
|
518
|
-
const encontrado = tipos.get(limpo);
|
|
519
|
-
if (encontrado.tipo === "enum") {
|
|
520
|
-
enumsReferenciados.add(encontrado.nome);
|
|
521
|
-
return encontrado.nome;
|
|
522
|
-
}
|
|
523
|
-
if (!pareceWrapperTipo(encontrado.nome)) {
|
|
524
|
-
entidadesReferenciadas.add(encontrado.nome);
|
|
525
|
-
return encontrado.nome;
|
|
526
|
-
}
|
|
527
|
-
}
|
|
528
|
-
return "Json";
|
|
529
|
-
}
|
|
530
|
-
function expandirCamposTs(nomeParametro, tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados, obrigatorio) {
|
|
531
|
-
if (!tipoTexto) {
|
|
532
|
-
return [{ nome: normalizarNomeCampoImportado(nomeParametro), tipo: "Json", obrigatorio }];
|
|
533
|
-
}
|
|
534
|
-
const limpo = tipoTexto
|
|
535
|
-
.trim()
|
|
536
|
-
.replace(/^Promise<(.*)>$/, "$1")
|
|
537
|
-
.replace(/\| undefined/g, "")
|
|
538
|
-
.replace(/\| null/g, "")
|
|
539
|
-
.replace(/Readonly<(.+)>/, "$1")
|
|
540
|
-
.replace(/Partial<(.+)>/, "$1")
|
|
541
|
-
.trim();
|
|
542
|
-
const descoberto = tipos.get(limpo);
|
|
543
|
-
if (descoberto?.tipo === "objeto" && pareceWrapperTipo(descoberto.nome)) {
|
|
544
|
-
return descoberto.campos.map((campo) => ({
|
|
545
|
-
nome: normalizarNomeCampoImportado(campo.nome),
|
|
546
|
-
tipo: mapearTipoTsParaSema(campo.tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
547
|
-
obrigatorio: campo.obrigatorio,
|
|
548
|
-
}));
|
|
549
|
-
}
|
|
550
|
-
return [{
|
|
551
|
-
nome: normalizarNomeCampoImportado(nomeParametro),
|
|
552
|
-
tipo: mapearTipoTsParaSema(tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
553
|
-
obrigatorio,
|
|
554
|
-
}];
|
|
555
|
-
}
|
|
556
|
-
function criarEntidadesReferenciadas(tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
557
|
-
const fila = [...entidadesReferenciadas];
|
|
558
|
-
const processadas = new Set();
|
|
559
|
-
const entities = [];
|
|
560
|
-
while (fila.length > 0) {
|
|
561
|
-
const nomeAtual = fila.shift();
|
|
562
|
-
if (processadas.has(nomeAtual)) {
|
|
563
|
-
continue;
|
|
564
|
-
}
|
|
565
|
-
processadas.add(nomeAtual);
|
|
566
|
-
const tipo = tipos.get(nomeAtual);
|
|
567
|
-
if (!tipo || tipo.tipo !== "objeto") {
|
|
568
|
-
continue;
|
|
569
|
-
}
|
|
570
|
-
const entidade = {
|
|
571
|
-
nome: tipo.nome,
|
|
572
|
-
campos: tipo.campos.map((campo) => ({
|
|
573
|
-
nome: normalizarNomeCampoImportado(campo.nome),
|
|
574
|
-
tipo: mapearTipoTsParaSema(campo.tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
575
|
-
obrigatorio: campo.obrigatorio,
|
|
576
|
-
})),
|
|
577
|
-
};
|
|
578
|
-
entities.push(entidade);
|
|
579
|
-
for (const referenciado of entidadesReferenciadas) {
|
|
580
|
-
if (!processadas.has(referenciado) && !fila.includes(referenciado)) {
|
|
581
|
-
fila.push(referenciado);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
const enums = [...enumsReferenciados]
|
|
586
|
-
.map((nome) => tipos.get(nome))
|
|
587
|
-
.filter((item) => Boolean(item && item.tipo === "enum"))
|
|
588
|
-
.map((tipo) => ({
|
|
589
|
-
nome: tipo.nome,
|
|
590
|
-
valores: tipo.valores,
|
|
591
|
-
}))
|
|
592
|
-
.filter((enumItem, indice, lista) => lista.findIndex((item) => item.nome === enumItem.nome) === indice);
|
|
593
|
-
return { entities: deduplicarEntidades(entities), enums };
|
|
594
|
-
}
|
|
595
|
-
function caminhoImplTs(diretorioBase, arquivo, simbolo) {
|
|
596
|
-
const relativo = path.relative(diretorioBase, arquivo).replace(/\.[^.]+$/, "");
|
|
597
|
-
const segmentos = relativo.split(path.sep).map((segmento) => paraIdentificadorModulo(segmento)).filter(Boolean);
|
|
598
|
-
return [...segmentos, simbolo].join(".");
|
|
599
|
-
}
|
|
600
|
-
function mapearCampoInferidoTypeScriptHttp(campo, tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
601
|
-
const tipoBasico = campo.tipoTexto ? mapearTipoPrimitivo(campo.tipoTexto) : "Json";
|
|
602
|
-
return {
|
|
603
|
-
nome: paraSnakeCase(campo.nome),
|
|
604
|
-
tipo: ["Texto", "Decimal", "Inteiro", "Booleano", "Data", "DataHora", "Id", "Json", "Vazio"].includes(tipoBasico)
|
|
605
|
-
? tipoBasico
|
|
606
|
-
: campo.tipoTexto
|
|
607
|
-
? mapearTipoTsParaSema(campo.tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados)
|
|
608
|
-
: "Json",
|
|
609
|
-
obrigatorio: campo.obrigatorio,
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
function camposDeSemanticaTypeScriptHttp(campos, tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
613
|
-
return campos.map((campo) => mapearCampoInferidoTypeScriptHttp(campo, tipos, entidadesReferenciadas, enumsReferenciados));
|
|
614
|
-
}
|
|
615
|
-
function camposEstruturadosTypeScriptHttp(nomeParametro, tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
616
|
-
const campos = expandirCamposTs(nomeParametro, tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados, false);
|
|
617
|
-
const nomeWrapper = normalizarNomeCampoImportado(nomeParametro);
|
|
618
|
-
if (campos.length === 1 && campos[0]?.nome === nomeWrapper && campos[0]?.tipo === "Json") {
|
|
619
|
-
return [];
|
|
620
|
-
}
|
|
621
|
-
return campos;
|
|
622
|
-
}
|
|
623
|
-
function errosPorStatusHttp(statuses) {
|
|
624
|
-
return [...new Set(statuses)].map((status) => {
|
|
625
|
-
switch (status) {
|
|
626
|
-
case 401:
|
|
627
|
-
return { nome: "nao_autorizado", mensagem: "Falha HTTP importada automaticamente com status 401." };
|
|
628
|
-
case 403:
|
|
629
|
-
return { nome: "acesso_negado", mensagem: "Falha HTTP importada automaticamente com status 403." };
|
|
630
|
-
case 404:
|
|
631
|
-
return { nome: "nao_encontrado", mensagem: "Falha HTTP importada automaticamente com status 404." };
|
|
632
|
-
case 409:
|
|
633
|
-
return { nome: "conflito", mensagem: "Falha HTTP importada automaticamente com status 409." };
|
|
634
|
-
case 422:
|
|
635
|
-
return { nome: "entrada_invalida", mensagem: "Falha HTTP importada automaticamente com status 422." };
|
|
636
|
-
case 500:
|
|
637
|
-
return { nome: "erro_interno", mensagem: "Falha HTTP importada automaticamente com status 500." };
|
|
638
|
-
default:
|
|
639
|
-
return { nome: `erro_http_${status}`, mensagem: `Falha HTTP importada automaticamente com status ${status}.` };
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
function resolverEscopoImportacaoNextJs(diretorioEntrada) {
|
|
644
|
-
const resolvido = path.resolve(diretorioEntrada);
|
|
645
|
-
const partes = path.parse(resolvido);
|
|
646
|
-
const relativoSemRaiz = resolvido.slice(partes.root.length);
|
|
647
|
-
const segmentos = relativoSemRaiz.split(path.sep).filter(Boolean);
|
|
648
|
-
const procurarSequencia = (sequencia) => segmentos.findIndex((segmento, indice) => sequencia.every((item, deslocamento) => segmentos[indice + deslocamento]?.toLowerCase() === item));
|
|
649
|
-
const montarBase = (indice) => indice <= 0
|
|
650
|
-
? partes.root
|
|
651
|
-
: path.join(partes.root, ...segmentos.slice(0, indice));
|
|
652
|
-
const indiceSrcAppApi = procurarSequencia(["src", "app", "api"]);
|
|
653
|
-
if (indiceSrcAppApi >= 0) {
|
|
654
|
-
return {
|
|
655
|
-
baseProjeto: montarBase(indiceSrcAppApi),
|
|
656
|
-
diretorioEscopo: resolvido,
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
const indiceAppApi = procurarSequencia(["app", "api"]);
|
|
660
|
-
if (indiceAppApi >= 0) {
|
|
661
|
-
return {
|
|
662
|
-
baseProjeto: montarBase(indiceAppApi),
|
|
663
|
-
diretorioEscopo: resolvido,
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
const indiceSrcApp = procurarSequencia(["src", "app"]);
|
|
667
|
-
if (indiceSrcApp >= 0) {
|
|
668
|
-
return {
|
|
669
|
-
baseProjeto: montarBase(indiceSrcApp),
|
|
670
|
-
diretorioEscopo: resolvido,
|
|
671
|
-
};
|
|
672
|
-
}
|
|
673
|
-
const indiceApp = procurarSequencia(["app"]);
|
|
674
|
-
if (indiceApp >= 0) {
|
|
675
|
-
return {
|
|
676
|
-
baseProjeto: montarBase(indiceApp),
|
|
677
|
-
diretorioEscopo: resolvido,
|
|
678
|
-
};
|
|
679
|
-
}
|
|
680
|
-
return {
|
|
681
|
-
baseProjeto: resolvido,
|
|
682
|
-
diretorioEscopo: resolvido,
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
function normalizarCaminhoImportado(caminhoArquivo) {
|
|
686
|
-
return caminhoArquivo.replace(/\\/g, "/");
|
|
687
|
-
}
|
|
688
|
-
function normalizarSegmentoRotaConsumer(segmento) {
|
|
689
|
-
const opcionalCatchAll = segmento.match(/^\[\[\.\.\.([A-Za-z_]\w*)\]\]$/);
|
|
690
|
-
if (opcionalCatchAll) {
|
|
691
|
-
return `{${opcionalCatchAll[1]}}`;
|
|
692
|
-
}
|
|
693
|
-
const catchAll = segmento.match(/^\[\.\.\.([A-Za-z_]\w*)\]$/);
|
|
694
|
-
if (catchAll) {
|
|
695
|
-
return `{${catchAll[1]}}`;
|
|
696
|
-
}
|
|
697
|
-
const dinamico = segmento.match(/^\[([A-Za-z_]\w*)\]$/);
|
|
698
|
-
if (dinamico) {
|
|
699
|
-
return `{${dinamico[1]}}`;
|
|
700
|
-
}
|
|
701
|
-
return segmento;
|
|
702
|
-
}
|
|
703
|
-
function montarCaminhoRotaConsumer(partes) {
|
|
704
|
-
const filtradas = partes
|
|
705
|
-
.filter((segmento) => segmento && segmento !== "index" && !/^\(.*\)$/.test(segmento) && !segmento.startsWith("@"))
|
|
706
|
-
.map(normalizarSegmentoRotaConsumer);
|
|
707
|
-
return filtradas.length > 0 ? `/${filtradas.join("/")}`.replace(/\/+/g, "/") : "/";
|
|
708
|
-
}
|
|
709
|
-
function resolverEscopoImportacaoFrontendConsumer(diretorioEntrada) {
|
|
710
|
-
const resolvido = path.resolve(diretorioEntrada);
|
|
711
|
-
const partes = path.parse(resolvido);
|
|
712
|
-
const segmentos = resolvido.slice(partes.root.length).split(path.sep).filter(Boolean);
|
|
713
|
-
const procurarSequencia = (sequencia) => segmentos.findIndex((segmento, indice) => sequencia.every((item, deslocamento) => segmentos[indice + deslocamento]?.toLowerCase() === item));
|
|
714
|
-
const montarBase = (indice) => indice <= 0
|
|
715
|
-
? partes.root
|
|
716
|
-
: path.join(partes.root, ...segmentos.slice(0, indice));
|
|
717
|
-
for (const sequencia of [
|
|
718
|
-
["src", "pages"],
|
|
719
|
-
["pages"],
|
|
720
|
-
["src", "app", "api"],
|
|
721
|
-
["app", "api"],
|
|
722
|
-
["src", "app"],
|
|
723
|
-
["app"],
|
|
724
|
-
["src", "lib"],
|
|
725
|
-
["lib"],
|
|
726
|
-
]) {
|
|
727
|
-
const indice = procurarSequencia(sequencia);
|
|
728
|
-
if (indice >= 0) {
|
|
729
|
-
return {
|
|
730
|
-
baseProjeto: montarBase(indice),
|
|
731
|
-
diretorioEscopo: resolvido,
|
|
732
|
-
};
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
return {
|
|
736
|
-
baseProjeto: resolvido,
|
|
737
|
-
diretorioEscopo: resolvido,
|
|
738
|
-
};
|
|
739
|
-
}
|
|
740
|
-
function arquivoEhBridgeNextJsConsumer(relacaoArquivo) {
|
|
741
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
742
|
-
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
743
|
-
}
|
|
744
|
-
function arquivoEhBridgeReactViteConsumer(relacaoArquivo) {
|
|
745
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
746
|
-
return /(?:^|\/)(?:src\/)?lib\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
747
|
-
}
|
|
748
|
-
function arquivoEhBridgeAngularConsumer(relacaoArquivo) {
|
|
749
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
750
|
-
return /(?:^|\/)(?:src\/)?app\/(?:sema_consumer_bridge|sema\/.+)\.(?:ts|js)$/i.test(relacao);
|
|
751
|
-
}
|
|
752
|
-
function arquivoEhSuperficieNextJsConsumer(relacaoArquivo) {
|
|
753
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
754
|
-
return /(?:^|\/)(?:src\/)?app\/(?:(?!api\/).)*?(?:page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
755
|
-
}
|
|
756
|
-
function arquivoEhSuperficieReactViteConsumer(relacaoArquivo) {
|
|
757
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
758
|
-
return /^(?:src\/)?pages\/.+\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
759
|
-
|| /^(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao);
|
|
760
|
-
}
|
|
761
|
-
function arquivoEhRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
762
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
763
|
-
return /(?:^|\/)(?:src\/)?(?:app\/)?(?:router|routes)\.(?:ts|tsx|js|jsx)$/i.test(relacao)
|
|
764
|
-
|| /from\s+["']react-router-dom["']|createBrowserRouter|RouterProvider|useRoutes\s*\(|<Routes\b|<Route\b/.test(codigo ?? "");
|
|
765
|
-
}
|
|
766
|
-
function arquivoEhRotasAngularConsumer(relacaoArquivo) {
|
|
767
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
768
|
-
return /(?:^|\/)(?:src\/)?app(?:\/.+)?\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
769
|
-
}
|
|
770
|
-
function arquivoEhRotasAngularConsumerRaiz(relacaoArquivo) {
|
|
771
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
772
|
-
return /(?:^|\/)(?:src\/)?app\/[^/]+\.routes\.(?:ts|js)$/i.test(relacao);
|
|
773
|
-
}
|
|
774
|
-
function arquivoEhBridgeFlutterConsumer(relacaoArquivo) {
|
|
775
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
776
|
-
return /(?:^|\/)(?:lib\/)?(?:sema_consumer_bridge|api\/sema_contract_bridge|sema\/.+)\.dart$/i.test(relacao);
|
|
777
|
-
}
|
|
778
|
-
function arquivoEhSuperficieFlutterConsumer(relacaoArquivo) {
|
|
779
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
780
|
-
return /(?:^|\/)(?:lib\/)?(?:screens|pages)\/.+\.dart$/i.test(relacao)
|
|
781
|
-
|| /(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao);
|
|
782
|
-
}
|
|
783
|
-
function arquivoEhRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
784
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
785
|
-
return /(?:^|\/)(?:lib\/)?(?:router|app_router|routes)\.dart$/i.test(relacao)
|
|
786
|
-
|| /MaterialApp(?:\.router)?\s*\(|CupertinoApp(?:\.router)?\s*\(|GoRouter\s*\(/.test(codigo ?? "");
|
|
787
|
-
}
|
|
788
|
-
function inferirCaminhoNextJsConsumer(relacaoArquivo) {
|
|
789
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
790
|
-
const segmentos = relacao.split("/");
|
|
791
|
-
const indiceSrcApp = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "app");
|
|
792
|
-
const indiceApp = segmentos.findIndex((segmento) => segmento === "app");
|
|
793
|
-
const inicioApp = indiceSrcApp >= 0 ? indiceSrcApp + 2 : indiceApp >= 0 ? indiceApp + 1 : -1;
|
|
794
|
-
if (inicioApp < 0) {
|
|
795
|
-
return undefined;
|
|
796
|
-
}
|
|
797
|
-
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
798
|
-
const tipoArquivo = arquivoFinal.match(/^(page|layout|loading|error)\.(?:ts|tsx|js|jsx)$/)?.[1];
|
|
799
|
-
if (!tipoArquivo) {
|
|
800
|
-
return undefined;
|
|
801
|
-
}
|
|
802
|
-
const caminhoAteArquivo = segmentos.slice(inicioApp, -1);
|
|
803
|
-
if (caminhoAteArquivo[0] === "api") {
|
|
804
|
-
return undefined;
|
|
805
|
-
}
|
|
806
|
-
const partes = caminhoAteArquivo
|
|
807
|
-
.filter((segmento) => segmento);
|
|
808
|
-
const caminho = montarCaminhoRotaConsumer(partes);
|
|
809
|
-
return {
|
|
810
|
-
caminho,
|
|
811
|
-
arquivo: relacao,
|
|
812
|
-
tipoArquivo,
|
|
813
|
-
};
|
|
814
|
-
}
|
|
815
|
-
function inferirCaminhoReactViteConsumer(relacaoArquivo) {
|
|
816
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
817
|
-
if (!arquivoEhSuperficieReactViteConsumer(relacao)) {
|
|
818
|
-
return undefined;
|
|
819
|
-
}
|
|
820
|
-
if (/(?:^|\/)(?:src\/)?App\.(?:ts|tsx|js|jsx)$/i.test(relacao)) {
|
|
821
|
-
return {
|
|
822
|
-
caminho: "/",
|
|
823
|
-
arquivo: relacao,
|
|
824
|
-
tipoArquivo: "app",
|
|
825
|
-
};
|
|
826
|
-
}
|
|
827
|
-
const segmentos = relacao.split("/");
|
|
828
|
-
const indiceSrcPages = segmentos.findIndex((segmento, indice) => segmento === "src" && segmentos[indice + 1] === "pages");
|
|
829
|
-
const indicePages = segmentos.findIndex((segmento) => segmento === "pages");
|
|
830
|
-
const inicioPages = indiceSrcPages >= 0 ? indiceSrcPages + 2 : indicePages >= 0 ? indicePages + 1 : -1;
|
|
831
|
-
if (inicioPages < 0) {
|
|
832
|
-
return undefined;
|
|
833
|
-
}
|
|
834
|
-
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
835
|
-
const nomeBase = arquivoFinal.replace(/\.(?:ts|tsx|js|jsx)$/i, "");
|
|
836
|
-
const caminho = montarCaminhoRotaConsumer([...segmentos.slice(inicioPages, -1), nomeBase]);
|
|
837
|
-
return {
|
|
838
|
-
caminho,
|
|
839
|
-
arquivo: relacao,
|
|
840
|
-
tipoArquivo: "page",
|
|
841
|
-
};
|
|
842
|
-
}
|
|
843
|
-
function inferirCaminhoFlutterConsumer(relacaoArquivo) {
|
|
844
|
-
const relacao = normalizarCaminhoImportado(relacaoArquivo);
|
|
845
|
-
if (!arquivoEhSuperficieFlutterConsumer(relacao)) {
|
|
846
|
-
return undefined;
|
|
847
|
-
}
|
|
848
|
-
if (/(?:^|\/)(?:lib\/)?main\.dart$/i.test(relacao)) {
|
|
849
|
-
return {
|
|
850
|
-
caminho: "/",
|
|
851
|
-
arquivo: relacao,
|
|
852
|
-
tipoArquivo: "app",
|
|
853
|
-
};
|
|
854
|
-
}
|
|
855
|
-
const segmentos = relacao.split("/");
|
|
856
|
-
const indiceLibScreens = segmentos.findIndex((segmento, indice) => segmento === "lib" && ["screens", "pages"].includes(segmentos[indice + 1] ?? ""));
|
|
857
|
-
const indiceScreens = segmentos.findIndex((segmento) => segmento === "screens" || segmento === "pages");
|
|
858
|
-
const inicio = indiceLibScreens >= 0 ? indiceLibScreens + 2 : indiceScreens >= 0 ? indiceScreens + 1 : -1;
|
|
859
|
-
if (inicio < 0) {
|
|
860
|
-
return undefined;
|
|
861
|
-
}
|
|
862
|
-
const arquivoFinal = segmentos.at(-1) ?? "";
|
|
863
|
-
const nomeBase = arquivoFinal
|
|
864
|
-
.replace(/\.(?:dart)$/i, "")
|
|
865
|
-
.replace(/_(screen|page)$/i, "");
|
|
866
|
-
return {
|
|
867
|
-
caminho: montarCaminhoRotaConsumer([...segmentos.slice(inicio, -1), nomeBase]),
|
|
868
|
-
arquivo: relacao,
|
|
869
|
-
tipoArquivo: "screen",
|
|
870
|
-
};
|
|
871
|
-
}
|
|
872
|
-
function normalizarRotaDeclaradaConsumer(caminhoCru, prefixo = "/") {
|
|
873
|
-
const partesPrefixo = prefixo.replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
874
|
-
const partesCaminho = (caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean);
|
|
875
|
-
return montarCaminhoRotaConsumer([...partesPrefixo, ...partesCaminho]);
|
|
876
|
-
}
|
|
877
|
-
function resolverImportRelativoTypeScript(relacaoArquivoBase, especificador) {
|
|
878
|
-
if (!especificador.startsWith(".")) {
|
|
879
|
-
return undefined;
|
|
880
|
-
}
|
|
881
|
-
const baseDir = path.posix.dirname(normalizarCaminhoImportado(relacaoArquivoBase));
|
|
882
|
-
for (const sufixo of ["", ".ts", ".tsx", ".js", ".jsx", "/index.ts", "/index.tsx", "/index.js", "/index.jsx"]) {
|
|
883
|
-
const candidato = path.posix.normalize(path.posix.join(baseDir, `${especificador}${sufixo}`));
|
|
884
|
-
if (!/\.(?:ts|tsx|js|jsx)$/i.test(candidato)) {
|
|
885
|
-
continue;
|
|
886
|
-
}
|
|
887
|
-
return candidato;
|
|
888
|
-
}
|
|
889
|
-
return undefined;
|
|
890
|
-
}
|
|
891
|
-
function extrairImportsTypeScriptConsumer(relacaoArquivo, codigo) {
|
|
892
|
-
const imports = new Map();
|
|
893
|
-
for (const match of codigo.matchAll(/import\s*\{\s*([^}]+)\s*\}\s*from\s*["']([^"']+)["']/g)) {
|
|
894
|
-
const moduloImportado = match[2];
|
|
895
|
-
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, moduloImportado);
|
|
896
|
-
if (!relacaoImportada) {
|
|
897
|
-
continue;
|
|
898
|
-
}
|
|
899
|
-
for (const bruto of match[1].split(",")) {
|
|
900
|
-
const normalizado = bruto.trim();
|
|
901
|
-
if (!normalizado) {
|
|
902
|
-
continue;
|
|
903
|
-
}
|
|
904
|
-
const local = normalizado.split(/\s+as\s+/i).at(-1)?.trim();
|
|
905
|
-
if (local) {
|
|
906
|
-
imports.set(local, relacaoImportada);
|
|
907
|
-
}
|
|
908
|
-
}
|
|
909
|
-
}
|
|
910
|
-
for (const match of codigo.matchAll(/import\s+([A-Za-z_]\w*)\s+from\s*["']([^"']+)["']/g)) {
|
|
911
|
-
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2]);
|
|
912
|
-
const local = match[1]?.trim();
|
|
913
|
-
if (relacaoImportada && local) {
|
|
914
|
-
imports.set(local, relacaoImportada);
|
|
915
|
-
}
|
|
916
|
-
}
|
|
917
|
-
return imports;
|
|
918
|
-
}
|
|
919
|
-
function extrairRotasReactViteConsumer(relacaoArquivo, codigo) {
|
|
920
|
-
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
921
|
-
const rotas = new Map();
|
|
922
|
-
const registrar = (caminhoCru, componente) => {
|
|
923
|
-
const caminho = normalizarRotaDeclaradaConsumer(caminhoCru);
|
|
924
|
-
const chave = `${caminho}:${normalizarCaminhoImportado(relacaoArquivo)}:${componente ?? "router"}`;
|
|
925
|
-
rotas.set(chave, {
|
|
926
|
-
caminho,
|
|
927
|
-
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
928
|
-
arquivoComponente: componente ? imports.get(componente) : undefined,
|
|
929
|
-
});
|
|
930
|
-
};
|
|
931
|
-
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)) {
|
|
932
|
-
const caminhoCru = match[1] ?? "";
|
|
933
|
-
const componente = match[2] ?? match[3];
|
|
934
|
-
registrar(caminhoCru, componente);
|
|
935
|
-
}
|
|
936
|
-
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)) {
|
|
937
|
-
const caminhoCru = match[2] ? "" : (match[1] ?? "");
|
|
938
|
-
const componente = match[3] ?? match[4];
|
|
939
|
-
registrar(caminhoCru, componente);
|
|
940
|
-
}
|
|
941
|
-
return [...rotas.values()];
|
|
942
|
-
}
|
|
943
|
-
function extrairRotasAngularConsumerDiretas(relacaoArquivo, codigo, prefixo = "/") {
|
|
944
|
-
const imports = extrairImportsTypeScriptConsumer(relacaoArquivo, codigo);
|
|
945
|
-
const rotas = [];
|
|
946
|
-
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?component\s*:\s*([A-Za-z_]\w*)/g)) {
|
|
947
|
-
const caminhoCru = (match[1] ?? "").trim();
|
|
948
|
-
const componente = match[2];
|
|
949
|
-
rotas.push({
|
|
950
|
-
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
951
|
-
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
952
|
-
arquivoComponente: imports.get(componente),
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
|
-
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,320}?loadComponent\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
956
|
-
const caminhoCru = (match[1] ?? "").trim();
|
|
957
|
-
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2] ?? "");
|
|
958
|
-
rotas.push({
|
|
959
|
-
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
960
|
-
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
961
|
-
arquivoComponente: relacaoImportada,
|
|
962
|
-
});
|
|
963
|
-
}
|
|
964
|
-
for (const match of codigo.matchAll(/path\s*:\s*["'`]([^"'`]*)["'`][\s\S]{0,360}?loadChildren\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*["'`]([^"'`]+)["'`]\s*\)/g)) {
|
|
965
|
-
const caminhoCru = (match[1] ?? "").trim();
|
|
966
|
-
const relacaoImportada = resolverImportRelativoTypeScript(relacaoArquivo, match[2] ?? "");
|
|
967
|
-
rotas.push({
|
|
968
|
-
caminho: normalizarRotaDeclaradaConsumer(caminhoCru, prefixo),
|
|
969
|
-
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
970
|
-
arquivoRotasFilhas: relacaoImportada,
|
|
971
|
-
});
|
|
972
|
-
}
|
|
973
|
-
return rotas;
|
|
974
|
-
}
|
|
975
|
-
async function extrairRotasAngularConsumer(baseProjeto, relacaoArquivo, prefixo = "/", visitados = new Set()) {
|
|
976
|
-
const relacaoNormalizada = normalizarCaminhoImportado(relacaoArquivo);
|
|
977
|
-
if (visitados.has(relacaoNormalizada)) {
|
|
978
|
-
return [];
|
|
979
|
-
}
|
|
980
|
-
visitados.add(relacaoNormalizada);
|
|
981
|
-
const caminhoAbsoluto = path.join(baseProjeto, relacaoNormalizada);
|
|
982
|
-
let codigo = "";
|
|
983
|
-
try {
|
|
984
|
-
codigo = await readFile(caminhoAbsoluto, "utf8");
|
|
985
|
-
}
|
|
986
|
-
catch {
|
|
987
|
-
return [];
|
|
988
|
-
}
|
|
989
|
-
const diretas = extrairRotasAngularConsumerDiretas(relacaoNormalizada, codigo, prefixo);
|
|
990
|
-
const agregadas = [...diretas];
|
|
991
|
-
for (const rota of diretas) {
|
|
992
|
-
if (!rota.arquivoRotasFilhas) {
|
|
993
|
-
continue;
|
|
994
|
-
}
|
|
995
|
-
agregadas.push(...await extrairRotasAngularConsumer(baseProjeto, rota.arquivoRotasFilhas, rota.caminho, visitados));
|
|
996
|
-
}
|
|
997
|
-
return agregadas;
|
|
998
|
-
}
|
|
999
|
-
function normalizarRotaDeclaradaFlutter(caminhoCru) {
|
|
1000
|
-
return montarCaminhoRotaConsumer((caminhoCru ?? "").trim().replace(/^\/+|\/+$/g, "").split("/").filter(Boolean));
|
|
1001
|
-
}
|
|
1002
|
-
function extrairRotasFlutterConsumer(relacaoArquivo, codigo) {
|
|
1003
|
-
const rotas = new Map();
|
|
1004
|
-
const registrar = (caminhoCru) => {
|
|
1005
|
-
const caminho = normalizarRotaDeclaradaFlutter(caminhoCru);
|
|
1006
|
-
rotas.set(`${caminho}:${normalizarCaminhoImportado(relacaoArquivo)}`, {
|
|
1007
|
-
caminho,
|
|
1008
|
-
arquivoRotas: normalizarCaminhoImportado(relacaoArquivo),
|
|
1009
|
-
});
|
|
1010
|
-
};
|
|
1011
|
-
for (const match of codigo.matchAll(/GoRoute\s*\([\s\S]{0,220}?path\s*:\s*["'`]([^"'`]+)["'`]/g)) {
|
|
1012
|
-
registrar(match[1] ?? "");
|
|
1013
|
-
}
|
|
1014
|
-
for (const match of codigo.matchAll(/["'`]([^"'`]+)["'`]\s*:\s*\([^)]*\)\s*=>/g)) {
|
|
1015
|
-
registrar(match[1] ?? "");
|
|
1016
|
-
}
|
|
1017
|
-
if (/home\s*:\s*(?:const\s+)?[A-Za-z_]\w*\(/.test(codigo)) {
|
|
1018
|
-
registrar("/");
|
|
1019
|
-
}
|
|
1020
|
-
return [...rotas.values()];
|
|
1021
|
-
}
|
|
1022
|
-
async function carregarContextosBridgeConsumer(baseProjeto, arquivosBridge) {
|
|
1023
|
-
return Promise.all(arquivosBridge.map(async (arquivo) => {
|
|
1024
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1025
|
-
const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
1026
|
-
return {
|
|
1027
|
-
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, scriptKind),
|
|
1028
|
-
texto,
|
|
1029
|
-
relacao: path.relative(baseProjeto, arquivo),
|
|
1030
|
-
};
|
|
1031
|
-
}));
|
|
1032
|
-
}
|
|
1033
|
-
function extrairTasksBridgeConsumer(baseProjeto, contextosBridge) {
|
|
1034
|
-
const tiposGlobais = consolidarTiposTs(contextosBridge);
|
|
1035
|
-
const entitiesRef = new Set();
|
|
1036
|
-
const enumsRef = new Set();
|
|
1037
|
-
const tasks = [];
|
|
1038
|
-
for (const contexto of contextosBridge) {
|
|
1039
|
-
contexto.sourceFile.forEachChild((node) => {
|
|
1040
|
-
if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
1041
|
-
const nome = node.name.text;
|
|
1042
|
-
const input = node.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1043
|
-
const output = node.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(node.type.getText(contexto.sourceFile)) === "Vazio"
|
|
1044
|
-
? []
|
|
1045
|
-
: deduplicarCampos(expandirCamposTs("resultado", node.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
1046
|
-
tasks.push({
|
|
1047
|
-
nome: nomeTaskBridgeConsumer(nome),
|
|
1048
|
-
resumo: `Task consumer importada automaticamente de ${contexto.relacao}#${nome}.`,
|
|
1049
|
-
input: deduplicarCampos(input),
|
|
1050
|
-
output,
|
|
1051
|
-
errors: node.body ? extrairErrosTs(node.body, contexto.sourceFile) : [],
|
|
1052
|
-
effects: node.body ? descreverEfeitosPorHeuristica(node.body.getText(contexto.sourceFile)) : [],
|
|
1053
|
-
impl: { ts: caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), nome) },
|
|
1054
|
-
vinculos: deduplicarVinculos([
|
|
1055
|
-
{ tipo: "arquivo", valor: normalizarCaminhoImportado(contexto.relacao) },
|
|
1056
|
-
{ tipo: "simbolo", valor: caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), nome) },
|
|
1057
|
-
]),
|
|
1058
|
-
origemArquivo: contexto.relacao,
|
|
1059
|
-
origemSimbolo: nome,
|
|
1060
|
-
});
|
|
1061
|
-
}
|
|
1062
|
-
if (ts.isClassDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
1063
|
-
const nomeClasse = node.name.text;
|
|
1064
|
-
for (const member of node.members) {
|
|
1065
|
-
if (!ts.isMethodDeclaration(member) || !member.name || !member.body) {
|
|
1066
|
-
continue;
|
|
1067
|
-
}
|
|
1068
|
-
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.PrivateKeyword || modifier.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
1069
|
-
continue;
|
|
1070
|
-
}
|
|
1071
|
-
const nomeMetodo = member.name.getText(contexto.sourceFile);
|
|
1072
|
-
if (nomeMetodo === "constructor") {
|
|
1073
|
-
continue;
|
|
1074
|
-
}
|
|
1075
|
-
const input = member.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1076
|
-
const output = member.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(member.type.getText(contexto.sourceFile)) === "Vazio"
|
|
1077
|
-
? []
|
|
1078
|
-
: deduplicarCampos(expandirCamposTs("resultado", member.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
1079
|
-
const caminhoSimbolo = caminhoImplTs(baseProjeto, path.join(baseProjeto, contexto.relacao), `${nomeClasse}.${nomeMetodo}`);
|
|
1080
|
-
tasks.push({
|
|
1081
|
-
nome: nomeTaskBridgeConsumer(nomeMetodo),
|
|
1082
|
-
resumo: `Task consumer importada automaticamente de ${contexto.relacao}#${nomeClasse}.${nomeMetodo}.`,
|
|
1083
|
-
input: deduplicarCampos(input),
|
|
1084
|
-
output,
|
|
1085
|
-
errors: extrairErrosTs(member.body, contexto.sourceFile),
|
|
1086
|
-
effects: descreverEfeitosPorHeuristica(member.body.getText(contexto.sourceFile)),
|
|
1087
|
-
impl: { ts: caminhoSimbolo },
|
|
1088
|
-
vinculos: deduplicarVinculos([
|
|
1089
|
-
{ tipo: "arquivo", valor: normalizarCaminhoImportado(contexto.relacao) },
|
|
1090
|
-
{ tipo: "simbolo", valor: caminhoSimbolo },
|
|
1091
|
-
]),
|
|
1092
|
-
origemArquivo: contexto.relacao,
|
|
1093
|
-
origemSimbolo: `${nomeClasse}.${nomeMetodo}`,
|
|
1094
|
-
});
|
|
1095
|
-
}
|
|
1096
|
-
}
|
|
1097
|
-
});
|
|
1098
|
-
}
|
|
1099
|
-
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
1100
|
-
return {
|
|
1101
|
-
tasks,
|
|
1102
|
-
entities,
|
|
1103
|
-
enums,
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
function montarVinculosSuperficiesConsumer(superficies) {
|
|
1107
|
-
return deduplicarVinculos(superficies.flatMap((superficie) => [
|
|
1108
|
-
{ tipo: "superficie", valor: superficie.caminho },
|
|
1109
|
-
{ tipo: "arquivo", valor: normalizarCaminhoImportado(superficie.arquivo) },
|
|
1110
|
-
]));
|
|
1111
|
-
}
|
|
1112
|
-
async function importarConsumerBase(diretorio, namespaceBase, descricaoFramework, ehBridge, coletarSuperficies) {
|
|
1113
|
-
const escopo = resolverEscopoImportacaoFrontendConsumer(diretorio);
|
|
1114
|
-
const arquivos = await listarArquivosRecursivos(escopo.baseProjeto, [".ts", ".tsx", ".js", ".jsx"]);
|
|
1115
|
-
const arquivosBridge = arquivos.filter((arquivo) => ehBridge(path.relative(escopo.baseProjeto, arquivo)));
|
|
1116
|
-
const contextosBridge = await carregarContextosBridgeConsumer(escopo.baseProjeto, arquivosBridge);
|
|
1117
|
-
const { tasks, entities, enums } = extrairTasksBridgeConsumer(escopo.baseProjeto, contextosBridge);
|
|
1118
|
-
const superficiesImportadas = await coletarSuperficies(escopo.baseProjeto, arquivos);
|
|
1119
|
-
const superficies = montarVinculosSuperficiesConsumer(superficiesImportadas);
|
|
1120
|
-
if (tasks.length === 0 && superficies.length === 0) {
|
|
1121
|
-
return [];
|
|
1122
|
-
}
|
|
1123
|
-
const nomeModulo = namespaceBase.endsWith(".consumer")
|
|
1124
|
-
? namespaceBase
|
|
1125
|
-
: `${namespaceBase}.consumer`;
|
|
1126
|
-
return [{
|
|
1127
|
-
nome: nomeModulo,
|
|
1128
|
-
resumo: `Rascunho Sema importado automaticamente do consumer ${descricaoFramework} em ${escopo.baseProjeto}.`,
|
|
1129
|
-
tasks: deduplicarTarefas(tasks),
|
|
1130
|
-
routes: [],
|
|
1131
|
-
entities,
|
|
1132
|
-
enums,
|
|
1133
|
-
vinculos: superficies,
|
|
1134
|
-
}];
|
|
1135
|
-
}
|
|
1136
|
-
async function coletarSuperficiesNextJsConsumer(baseProjeto, arquivos) {
|
|
1137
|
-
return arquivos
|
|
1138
|
-
.map((arquivo) => inferirCaminhoNextJsConsumer(path.relative(baseProjeto, arquivo)))
|
|
1139
|
-
.filter((item) => Boolean(item));
|
|
1140
|
-
}
|
|
1141
|
-
async function coletarSuperficiesReactViteConsumer(baseProjeto, arquivos) {
|
|
1142
|
-
const superficies = [];
|
|
1143
|
-
for (const arquivo of arquivos) {
|
|
1144
|
-
const relacao = path.relative(baseProjeto, arquivo);
|
|
1145
|
-
const codigo = await readFile(arquivo, "utf8");
|
|
1146
|
-
if (arquivoEhRotasReactViteConsumer(relacao, codigo)) {
|
|
1147
|
-
for (const rota of extrairRotasReactViteConsumer(relacao, codigo)) {
|
|
1148
|
-
superficies.push({
|
|
1149
|
-
caminho: rota.caminho,
|
|
1150
|
-
arquivo: rota.arquivoRotas,
|
|
1151
|
-
tipoArquivo: "router",
|
|
1152
|
-
});
|
|
1153
|
-
if (rota.arquivoComponente) {
|
|
1154
|
-
superficies.push({
|
|
1155
|
-
caminho: rota.caminho,
|
|
1156
|
-
arquivo: rota.arquivoComponente,
|
|
1157
|
-
tipoArquivo: "page",
|
|
1158
|
-
});
|
|
1159
|
-
}
|
|
1160
|
-
}
|
|
1161
|
-
}
|
|
1162
|
-
}
|
|
1163
|
-
for (const arquivo of arquivos) {
|
|
1164
|
-
const superficie = inferirCaminhoReactViteConsumer(path.relative(baseProjeto, arquivo));
|
|
1165
|
-
if (superficie) {
|
|
1166
|
-
superficies.push(superficie);
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
return superficies;
|
|
1170
|
-
}
|
|
1171
|
-
async function coletarSuperficiesAngularConsumer(baseProjeto, arquivos) {
|
|
1172
|
-
const superficies = [];
|
|
1173
|
-
const arquivosRotas = arquivos.filter((arquivo) => arquivoEhRotasAngularConsumer(path.relative(baseProjeto, arquivo)));
|
|
1174
|
-
const arquivosRaiz = arquivosRotas.filter((arquivo) => arquivoEhRotasAngularConsumerRaiz(path.relative(baseProjeto, arquivo)));
|
|
1175
|
-
const pontosEntrada = arquivosRaiz.length > 0 ? arquivosRaiz : arquivosRotas;
|
|
1176
|
-
for (const arquivoRotas of pontosEntrada) {
|
|
1177
|
-
const relacao = path.relative(baseProjeto, arquivoRotas);
|
|
1178
|
-
for (const rota of await extrairRotasAngularConsumer(baseProjeto, relacao)) {
|
|
1179
|
-
superficies.push({
|
|
1180
|
-
caminho: rota.caminho,
|
|
1181
|
-
arquivo: rota.arquivoRotas,
|
|
1182
|
-
tipoArquivo: "routes",
|
|
1183
|
-
});
|
|
1184
|
-
if (rota.arquivoComponente) {
|
|
1185
|
-
superficies.push({
|
|
1186
|
-
caminho: rota.caminho,
|
|
1187
|
-
arquivo: rota.arquivoComponente,
|
|
1188
|
-
tipoArquivo: "component",
|
|
1189
|
-
});
|
|
1190
|
-
}
|
|
1191
|
-
}
|
|
1192
|
-
}
|
|
1193
|
-
if (superficies.length > 0) {
|
|
1194
|
-
return superficies;
|
|
1195
|
-
}
|
|
1196
|
-
return (await coletarSuperficiesAngularStandaloneConsumer(baseProjeto, arquivos)).map((superficie) => ({
|
|
1197
|
-
caminho: superficie.rota,
|
|
1198
|
-
arquivo: superficie.arquivo,
|
|
1199
|
-
tipoArquivo: superficie.tipoArquivo,
|
|
1200
|
-
}));
|
|
1201
|
-
}
|
|
1202
|
-
async function importarNextJsConsumerBase(diretorio, namespaceBase) {
|
|
1203
|
-
return importarConsumerBase(diretorio, namespaceBase, "Next.js", arquivoEhBridgeNextJsConsumer, coletarSuperficiesNextJsConsumer);
|
|
1204
|
-
}
|
|
1205
|
-
async function importarReactViteConsumerBase(diretorio, namespaceBase) {
|
|
1206
|
-
return importarConsumerBase(diretorio, namespaceBase, "React/Vite", arquivoEhBridgeReactViteConsumer, coletarSuperficiesReactViteConsumer);
|
|
1207
|
-
}
|
|
1208
|
-
async function importarAngularConsumerBase(diretorio, namespaceBase) {
|
|
1209
|
-
return importarConsumerBase(diretorio, namespaceBase, "Angular", arquivoEhBridgeAngularConsumer, coletarSuperficiesAngularConsumer);
|
|
1210
|
-
}
|
|
1211
|
-
async function extrairTasksBridgeFlutterConsumer(baseProjeto, arquivosBridge) {
|
|
1212
|
-
const tasks = [];
|
|
1213
|
-
for (const arquivo of arquivosBridge) {
|
|
1214
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1215
|
-
const relacao = path.relative(baseProjeto, arquivo);
|
|
1216
|
-
for (const match of texto.matchAll(/(?:Future<([^\n]+)>|([\w?<>.,\s]+))\s+(\w+)\(([^)]*)\)\s*(?:async\s*)?\{/g)) {
|
|
1217
|
-
const retorno = (match[1] ?? match[2] ?? "").trim();
|
|
1218
|
-
const nome = match[3];
|
|
1219
|
-
if (["build", "toString", "hashCode"].includes(nome)) {
|
|
1220
|
-
continue;
|
|
1221
|
-
}
|
|
1222
|
-
const parametros = match[4];
|
|
1223
|
-
const input = parametros
|
|
1224
|
-
.split(",")
|
|
1225
|
-
.map((item) => item.trim())
|
|
1226
|
-
.filter(Boolean)
|
|
1227
|
-
.map((item) => item.replace(/^(required|final)\s+/g, ""))
|
|
1228
|
-
.map((item) => {
|
|
1229
|
-
const partes = item.split(/\s+/).filter(Boolean);
|
|
1230
|
-
const nomeParametro = partes.at(-1) ?? "arg";
|
|
1231
|
-
const tipoParametro = partes.slice(0, -1).join(" ");
|
|
1232
|
-
return {
|
|
1233
|
-
nome: paraSnakeCase(nomeParametro),
|
|
1234
|
-
tipo: mapearTipoPrimitivo(tipoParametro || "Json"),
|
|
1235
|
-
obrigatorio: !/\?/.test(tipoParametro),
|
|
1236
|
-
};
|
|
1237
|
-
});
|
|
1238
|
-
const caminhoSimbolo = caminhoImplDart(baseProjeto, arquivo, nome);
|
|
1239
|
-
tasks.push({
|
|
1240
|
-
nome: nomeTaskBridgeConsumer(nome),
|
|
1241
|
-
resumo: `Task consumer importada automaticamente de ${relacao}#${nome}.`,
|
|
1242
|
-
input,
|
|
1243
|
-
output: retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
1244
|
-
? []
|
|
1245
|
-
: [{ nome: "resultado", tipo: mapearTipoPrimitivo(retorno || "Json"), obrigatorio: false }],
|
|
1246
|
-
errors: [],
|
|
1247
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
1248
|
-
impl: { dart: caminhoSimbolo },
|
|
1249
|
-
vinculos: deduplicarVinculos([
|
|
1250
|
-
{ tipo: "arquivo", valor: normalizarCaminhoImportado(relacao) },
|
|
1251
|
-
{ tipo: "simbolo", valor: caminhoSimbolo },
|
|
1252
|
-
]),
|
|
1253
|
-
origemArquivo: relacao,
|
|
1254
|
-
origemSimbolo: nome,
|
|
1255
|
-
});
|
|
1256
|
-
}
|
|
1257
|
-
}
|
|
1258
|
-
return tasks;
|
|
1259
|
-
}
|
|
1260
|
-
async function coletarSuperficiesFlutterConsumer(baseProjeto, arquivos) {
|
|
1261
|
-
const superficies = [];
|
|
1262
|
-
for (const arquivo of arquivos) {
|
|
1263
|
-
const relacao = path.relative(baseProjeto, arquivo);
|
|
1264
|
-
const codigo = await readFile(arquivo, "utf8");
|
|
1265
|
-
if (arquivoEhRotasFlutterConsumer(relacao, codigo)) {
|
|
1266
|
-
for (const rota of extrairRotasFlutterConsumer(relacao, codigo)) {
|
|
1267
|
-
superficies.push({
|
|
1268
|
-
caminho: rota.caminho,
|
|
1269
|
-
arquivo: rota.arquivoRotas,
|
|
1270
|
-
tipoArquivo: "router",
|
|
1271
|
-
});
|
|
1272
|
-
}
|
|
1273
|
-
}
|
|
1274
|
-
}
|
|
1275
|
-
for (const arquivo of arquivos) {
|
|
1276
|
-
const superficie = inferirCaminhoFlutterConsumer(path.relative(baseProjeto, arquivo));
|
|
1277
|
-
if (superficie) {
|
|
1278
|
-
superficies.push(superficie);
|
|
1279
|
-
}
|
|
1280
|
-
}
|
|
1281
|
-
return superficies;
|
|
1282
|
-
}
|
|
1283
|
-
async function importarFlutterConsumerBase(diretorio, namespaceBase) {
|
|
1284
|
-
const escopo = resolverEscopoImportacaoFrontendConsumer(diretorio);
|
|
1285
|
-
const arquivos = (await listarArquivosRecursivos(escopo.baseProjeto, [".dart"]))
|
|
1286
|
-
.filter((arquivo) => !arquivo.endsWith(".g.dart") && !arquivo.endsWith(".freezed.dart"));
|
|
1287
|
-
const arquivosBridge = arquivos.filter((arquivo) => arquivoEhBridgeFlutterConsumer(path.relative(escopo.baseProjeto, arquivo)));
|
|
1288
|
-
const tasks = await extrairTasksBridgeFlutterConsumer(escopo.baseProjeto, arquivosBridge);
|
|
1289
|
-
const superficiesImportadas = await coletarSuperficiesFlutterConsumer(escopo.baseProjeto, arquivos);
|
|
1290
|
-
const superficies = montarVinculosSuperficiesConsumer(superficiesImportadas);
|
|
1291
|
-
if (tasks.length === 0 && superficies.length === 0) {
|
|
1292
|
-
return [];
|
|
1293
|
-
}
|
|
1294
|
-
const nomeModulo = namespaceBase.endsWith(".consumer")
|
|
1295
|
-
? namespaceBase
|
|
1296
|
-
: `${namespaceBase}.consumer`;
|
|
1297
|
-
return [{
|
|
1298
|
-
nome: nomeModulo,
|
|
1299
|
-
resumo: `Rascunho Sema importado automaticamente do consumer Flutter em ${escopo.baseProjeto}.`,
|
|
1300
|
-
tasks: deduplicarTarefas(tasks),
|
|
1301
|
-
routes: [],
|
|
1302
|
-
entities: [],
|
|
1303
|
-
enums: [],
|
|
1304
|
-
vinculos: superficies,
|
|
1305
|
-
}];
|
|
1306
|
-
}
|
|
1307
|
-
function nomeTaskBridgeConsumer(nome) {
|
|
1308
|
-
return paraSnakeCase(nome.replace(/^sema/, "")) || paraSnakeCase(nome) || "task_consumer";
|
|
1309
|
-
}
|
|
1310
|
-
function extrairChamadaServiceTs(node) {
|
|
1311
|
-
let encontrado;
|
|
1312
|
-
const visitar = (atual) => {
|
|
1313
|
-
if (encontrado) {
|
|
1314
|
-
return;
|
|
1315
|
-
}
|
|
1316
|
-
if (ts.isCallExpression(atual) && ts.isPropertyAccessExpression(atual.expression)) {
|
|
1317
|
-
const alvo = atual.expression.expression;
|
|
1318
|
-
if (ts.isPropertyAccessExpression(alvo) && alvo.expression.kind === ts.SyntaxKind.ThisKeyword && alvo.name.text.endsWith("Service")) {
|
|
1319
|
-
encontrado = atual.expression.name.text;
|
|
1320
|
-
return;
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1323
|
-
atual.forEachChild(visitar);
|
|
1324
|
-
};
|
|
1325
|
-
node.forEachChild(visitar);
|
|
1326
|
-
return encontrado;
|
|
1327
|
-
}
|
|
1328
|
-
function deduplicarCampos(campos) {
|
|
1329
|
-
const mapa = new Map();
|
|
1330
|
-
for (const campo of campos) {
|
|
1331
|
-
if (!mapa.has(campo.nome)) {
|
|
1332
|
-
mapa.set(campo.nome, campo);
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
return [...mapa.values()];
|
|
1336
|
-
}
|
|
1337
|
-
function deduplicarErros(errors) {
|
|
1338
|
-
const mapa = new Map();
|
|
1339
|
-
for (const erro of errors) {
|
|
1340
|
-
if (!mapa.has(erro.nome)) {
|
|
1341
|
-
mapa.set(erro.nome, erro);
|
|
1342
|
-
}
|
|
1343
|
-
}
|
|
1344
|
-
return [...mapa.values()];
|
|
1345
|
-
}
|
|
1346
|
-
function deduplicarEfeitos(effects) {
|
|
1347
|
-
const mapa = new Map();
|
|
1348
|
-
for (const effect of effects) {
|
|
1349
|
-
const chave = `${effect.categoria}:${effect.alvo}`;
|
|
1350
|
-
if (!mapa.has(chave)) {
|
|
1351
|
-
mapa.set(chave, effect);
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
return [...mapa.values()];
|
|
1355
|
-
}
|
|
1356
|
-
function deduplicarVinculos(vinculos) {
|
|
1357
|
-
const mapa = new Map();
|
|
1358
|
-
for (const vinculo of vinculos) {
|
|
1359
|
-
const chave = `${vinculo.tipo}:${vinculo.valor}`;
|
|
1360
|
-
if (!mapa.has(chave)) {
|
|
1361
|
-
mapa.set(chave, vinculo);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
return [...mapa.values()];
|
|
1365
|
-
}
|
|
1366
|
-
function deduplicarEntidades(entities) {
|
|
1367
|
-
const mapa = new Map();
|
|
1368
|
-
for (const entity of entities) {
|
|
1369
|
-
if (!mapa.has(entity.nome)) {
|
|
1370
|
-
mapa.set(entity.nome, entity);
|
|
1371
|
-
}
|
|
1372
|
-
}
|
|
1373
|
-
return [...mapa.values()];
|
|
1374
|
-
}
|
|
1375
|
-
function deduplicarEnums(enums) {
|
|
1376
|
-
const mapa = new Map();
|
|
1377
|
-
for (const enumItem of enums) {
|
|
1378
|
-
if (!mapa.has(enumItem.nome)) {
|
|
1379
|
-
mapa.set(enumItem.nome, enumItem);
|
|
1380
|
-
}
|
|
1381
|
-
}
|
|
1382
|
-
return [...mapa.values()];
|
|
1383
|
-
}
|
|
1384
|
-
function deduplicarTarefas(tasks) {
|
|
1385
|
-
const mapa = new Map();
|
|
1386
|
-
for (const task of tasks) {
|
|
1387
|
-
if (!mapa.has(task.nome)) {
|
|
1388
|
-
mapa.set(task.nome, task);
|
|
1389
|
-
continue;
|
|
1390
|
-
}
|
|
1391
|
-
const existente = mapa.get(task.nome);
|
|
1392
|
-
existente.input = deduplicarCampos([...existente.input, ...task.input]);
|
|
1393
|
-
existente.output = deduplicarCampos([...existente.output, ...task.output]);
|
|
1394
|
-
existente.errors = deduplicarErros([...existente.errors, ...task.errors]);
|
|
1395
|
-
existente.effects = deduplicarEfeitos([...existente.effects, ...task.effects]);
|
|
1396
|
-
existente.vinculos = deduplicarVinculos([...(existente.vinculos ?? []), ...(task.vinculos ?? [])]);
|
|
1397
|
-
}
|
|
1398
|
-
return [...mapa.values()];
|
|
1399
|
-
}
|
|
1400
|
-
function deduplicarRotas(routes) {
|
|
1401
|
-
const mapa = new Map();
|
|
1402
|
-
for (const route of routes) {
|
|
1403
|
-
const chave = `${route.metodo}:${route.caminho}`;
|
|
1404
|
-
if (!mapa.has(chave)) {
|
|
1405
|
-
mapa.set(chave, route);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
return [...mapa.values()];
|
|
1409
|
-
}
|
|
1410
|
-
function sincronizarRotasComTasks(routes, tasks) {
|
|
1411
|
-
const mapaTasks = new Map(tasks.map((task) => [task.nome, task]));
|
|
1412
|
-
for (const route of routes) {
|
|
1413
|
-
const task = mapaTasks.get(route.task);
|
|
1414
|
-
if (!task) {
|
|
1415
|
-
continue;
|
|
1416
|
-
}
|
|
1417
|
-
if (route.output.length === 0) {
|
|
1418
|
-
route.output = task.output.map((campo) => ({ ...campo, obrigatorio: true }));
|
|
1419
|
-
}
|
|
1420
|
-
if (route.errors.length === 0) {
|
|
1421
|
-
route.errors = task.errors;
|
|
1422
|
-
}
|
|
1423
|
-
}
|
|
1424
|
-
}
|
|
1425
|
-
function renderizarCampos(bloco, campos, indentacao = " ", sempre = false) {
|
|
1426
|
-
if (campos.length === 0 && !sempre) {
|
|
1427
|
-
return [];
|
|
1428
|
-
}
|
|
1429
|
-
return [
|
|
1430
|
-
`${indentacao}${bloco} {`,
|
|
1431
|
-
...campos.map((campo) => `${indentacao} ${normalizarNomeCampoImportado(campo.nome)}: ${campo.tipo}${campo.obrigatorio ? " required" : ""}`),
|
|
1432
|
-
`${indentacao}}`,
|
|
1433
|
-
"",
|
|
1434
|
-
];
|
|
1435
|
-
}
|
|
1436
|
-
function renderizarErrors(erros, indentacao = " ") {
|
|
1437
|
-
if (erros.length === 0) {
|
|
1438
|
-
return [];
|
|
1439
|
-
}
|
|
1440
|
-
return [
|
|
1441
|
-
`${indentacao}error {`,
|
|
1442
|
-
...erros.map((erro) => `${indentacao} ${erro.nome}: "${escaparTexto(erro.mensagem)}"`),
|
|
1443
|
-
`${indentacao}}`,
|
|
1444
|
-
"",
|
|
1445
|
-
];
|
|
1446
|
-
}
|
|
1447
|
-
function renderizarEffects(effects, indentacao = " ") {
|
|
1448
|
-
if (effects.length === 0) {
|
|
1449
|
-
return [];
|
|
1450
|
-
}
|
|
1451
|
-
return [
|
|
1452
|
-
`${indentacao}effects {`,
|
|
1453
|
-
...effects.map((effect) => `${indentacao} ${effect.categoria} ${effect.alvo}${effect.criticidade ? ` criticidade = ${effect.criticidade}` : ""}`),
|
|
1454
|
-
`${indentacao}}`,
|
|
1455
|
-
"",
|
|
1456
|
-
];
|
|
1457
|
-
}
|
|
1458
|
-
function renderizarImpl(impl, indentacao = " ") {
|
|
1459
|
-
if (!impl || Object.keys(impl).length === 0) {
|
|
1460
|
-
return [];
|
|
1461
|
-
}
|
|
1462
|
-
return [
|
|
1463
|
-
`${indentacao}impl {`,
|
|
1464
|
-
...(impl.ts ? [`${indentacao} ts: ${impl.ts}`] : []),
|
|
1465
|
-
...(impl.py ? [`${indentacao} py: ${impl.py}`] : []),
|
|
1466
|
-
...(impl.dart ? [`${indentacao} dart: ${impl.dart}`] : []),
|
|
1467
|
-
...(impl.cs ? [`${indentacao} cs: ${impl.cs}`] : []),
|
|
1468
|
-
...(impl.java ? [`${indentacao} java: ${impl.java}`] : []),
|
|
1469
|
-
...(impl.go ? [`${indentacao} go: ${impl.go}`] : []),
|
|
1470
|
-
...(impl.rust ? [`${indentacao} rust: ${impl.rust}`] : []),
|
|
1471
|
-
...(impl.cpp ? [`${indentacao} cpp: ${impl.cpp}`] : []),
|
|
1472
|
-
`${indentacao}}`,
|
|
1473
|
-
"",
|
|
1474
|
-
];
|
|
1475
|
-
}
|
|
1476
|
-
function renderizarValorVinculo(vinculo) {
|
|
1477
|
-
if (vinculo.tipo === "simbolo") {
|
|
1478
|
-
return vinculo.valor;
|
|
1479
|
-
}
|
|
1480
|
-
if (vinculo.tipo === "arquivo" || vinculo.valor.includes("/") || vinculo.valor.includes("\\") || vinculo.valor.includes("{")) {
|
|
1481
|
-
return `"${escaparTexto(vinculo.valor)}"`;
|
|
1482
|
-
}
|
|
1483
|
-
return vinculo.valor;
|
|
1484
|
-
}
|
|
1485
|
-
function renderizarVinculos(vinculos, indentacao = " ") {
|
|
1486
|
-
if (!vinculos || vinculos.length === 0) {
|
|
1487
|
-
return [];
|
|
1488
|
-
}
|
|
1489
|
-
return [
|
|
1490
|
-
`${indentacao}vinculos {`,
|
|
1491
|
-
...vinculos.map((vinculo) => `${indentacao} ${vinculo.tipo}: ${renderizarValorVinculo(vinculo)}`),
|
|
1492
|
-
`${indentacao}}`,
|
|
1493
|
-
"",
|
|
1494
|
-
];
|
|
1495
|
-
}
|
|
1496
|
-
function renderizarTask(task) {
|
|
1497
|
-
const linhas = [
|
|
1498
|
-
` task ${task.nome} {`,
|
|
1499
|
-
" docs {",
|
|
1500
|
-
` resumo: "${escaparTexto(task.resumo)}"`,
|
|
1501
|
-
" }",
|
|
1502
|
-
"",
|
|
1503
|
-
...renderizarCampos("input", task.input, " ", true),
|
|
1504
|
-
...renderizarCampos("output", task.output, " ", true),
|
|
1505
|
-
...renderizarEffects(task.effects, " "),
|
|
1506
|
-
...renderizarImpl(task.impl, " "),
|
|
1507
|
-
...renderizarVinculos(task.vinculos, " "),
|
|
1508
|
-
...renderizarErrors(task.errors, " "),
|
|
1509
|
-
];
|
|
1510
|
-
linhas.push(" guarantees {");
|
|
1511
|
-
for (const campo of task.output) {
|
|
1512
|
-
linhas.push(` ${normalizarNomeCampoImportado(campo.nome)} existe`);
|
|
1513
|
-
}
|
|
1514
|
-
linhas.push(" }");
|
|
1515
|
-
linhas.push("");
|
|
1516
|
-
linhas.push(" }");
|
|
1517
|
-
linhas.push("");
|
|
1518
|
-
return linhas;
|
|
1519
|
-
}
|
|
1520
|
-
function renderizarRoute(route) {
|
|
1521
|
-
const caminhoRenderizado = /[{}]/.test(route.caminho)
|
|
1522
|
-
? `"${escaparTexto(route.caminho)}"`
|
|
1523
|
-
: route.caminho;
|
|
1524
|
-
return [
|
|
1525
|
-
` route ${route.nome} {`,
|
|
1526
|
-
" docs {",
|
|
1527
|
-
` resumo: "${escaparTexto(route.resumo)}"`,
|
|
1528
|
-
" }",
|
|
1529
|
-
"",
|
|
1530
|
-
` metodo: ${route.metodo}`,
|
|
1531
|
-
` caminho: ${caminhoRenderizado}`,
|
|
1532
|
-
` task: ${route.task}`,
|
|
1533
|
-
...renderizarCampos("input", route.input, " "),
|
|
1534
|
-
...renderizarCampos("output", route.output, " "),
|
|
1535
|
-
...renderizarErrors(route.errors, " "),
|
|
1536
|
-
" }",
|
|
1537
|
-
"",
|
|
1538
|
-
];
|
|
1539
|
-
}
|
|
1540
|
-
function renderizarEnum(enumItem) {
|
|
1541
|
-
return [
|
|
1542
|
-
` enum ${enumItem.nome} {`,
|
|
1543
|
-
` ${enumItem.valores.join(",\n ")}`,
|
|
1544
|
-
" }",
|
|
1545
|
-
"",
|
|
1546
|
-
];
|
|
1547
|
-
}
|
|
1548
|
-
function renderizarEntidade(entity) {
|
|
1549
|
-
return [
|
|
1550
|
-
` entity ${entity.nome} {`,
|
|
1551
|
-
" fields {",
|
|
1552
|
-
...entity.campos.map((campo) => ` ${normalizarNomeCampoImportado(campo.nome)}: ${campo.tipo}`),
|
|
1553
|
-
" }",
|
|
1554
|
-
" }",
|
|
1555
|
-
"",
|
|
1556
|
-
];
|
|
1557
|
-
}
|
|
1558
|
-
function renderizarValorDatabase(valor) {
|
|
1559
|
-
if (!valor) {
|
|
1560
|
-
return undefined;
|
|
1561
|
-
}
|
|
1562
|
-
return /[\s/{}"]/u.test(valor)
|
|
1563
|
-
? `"${escaparTexto(valor)}"`
|
|
1564
|
-
: valor;
|
|
1565
|
-
}
|
|
1566
|
-
function renderizarRecursoDatabase(recurso) {
|
|
1567
|
-
const linhas = [` ${recurso.tipo} ${recurso.nome} {`];
|
|
1568
|
-
const mode = renderizarValorDatabase(recurso.mode);
|
|
1569
|
-
const table = renderizarValorDatabase(recurso.table);
|
|
1570
|
-
const collection = renderizarValorDatabase(recurso.collection);
|
|
1571
|
-
const ttl = renderizarValorDatabase(recurso.ttl);
|
|
1572
|
-
const surface = renderizarValorDatabase(recurso.surface);
|
|
1573
|
-
if (mode) {
|
|
1574
|
-
linhas.push(` mode: ${mode}`);
|
|
1575
|
-
}
|
|
1576
|
-
if (table) {
|
|
1577
|
-
linhas.push(` table: ${table}`);
|
|
1578
|
-
}
|
|
1579
|
-
if (collection) {
|
|
1580
|
-
linhas.push(` collection: ${collection}`);
|
|
1581
|
-
}
|
|
1582
|
-
if (ttl) {
|
|
1583
|
-
linhas.push(` ttl: ${ttl}`);
|
|
1584
|
-
}
|
|
1585
|
-
if (surface) {
|
|
1586
|
-
linhas.push(` surface: ${surface}`);
|
|
1587
|
-
}
|
|
1588
|
-
linhas.push(" }");
|
|
1589
|
-
linhas.push("");
|
|
1590
|
-
return linhas;
|
|
1591
|
-
}
|
|
1592
|
-
function renderizarDatabase(database) {
|
|
1593
|
-
const queryModel = renderizarValorDatabase(database.queryModel);
|
|
1594
|
-
const transactionModel = renderizarValorDatabase(database.transactionModel);
|
|
1595
|
-
return [
|
|
1596
|
-
` database ${database.nome} {`,
|
|
1597
|
-
` engine: ${database.engine}`,
|
|
1598
|
-
...(queryModel ? [` query_model: ${queryModel}`] : []),
|
|
1599
|
-
...(transactionModel ? [` transaction_model: ${transactionModel}`] : []),
|
|
1600
|
-
...(database.diagnostics?.length
|
|
1601
|
-
? [
|
|
1602
|
-
" diagnostics {",
|
|
1603
|
-
...database.diagnostics.map((diagnostico) => ` ${diagnostico}`),
|
|
1604
|
-
" }",
|
|
1605
|
-
]
|
|
1606
|
-
: []),
|
|
1607
|
-
...database.resources.flatMap(renderizarRecursoDatabase),
|
|
1608
|
-
" }",
|
|
1609
|
-
"",
|
|
1610
|
-
];
|
|
1611
|
-
}
|
|
1612
|
-
function moduloParaCodigo(modulo) {
|
|
1613
|
-
const linhas = [
|
|
1614
|
-
`module ${modulo.nome} {`,
|
|
1615
|
-
" docs {",
|
|
1616
|
-
` resumo: "${escaparTexto(modulo.resumo)}"`,
|
|
1617
|
-
" }",
|
|
1618
|
-
"",
|
|
1619
|
-
...renderizarVinculos(modulo.vinculos, " "),
|
|
1620
|
-
...(modulo.databases ?? []).flatMap(renderizarDatabase),
|
|
1621
|
-
...modulo.enums.flatMap(renderizarEnum),
|
|
1622
|
-
...modulo.entities.flatMap(renderizarEntidade),
|
|
1623
|
-
...modulo.tasks.flatMap(renderizarTask),
|
|
1624
|
-
...modulo.routes.flatMap(renderizarRoute),
|
|
1625
|
-
"}",
|
|
1626
|
-
"",
|
|
1627
|
-
];
|
|
1628
|
-
return linhas.join("\n");
|
|
1629
|
-
}
|
|
1630
|
-
async function formatarModuloImportado(codigo, caminhoVirtual) {
|
|
1631
|
-
const formatado = formatarCodigo(codigo, caminhoVirtual);
|
|
1632
|
-
return formatado.codigoFormatado ?? codigo;
|
|
1633
|
-
}
|
|
1634
|
-
function nomeArquivoModulo(modulo) {
|
|
1635
|
-
const segmentos = modulo.split(".");
|
|
1636
|
-
return `${segmentos.at(-1) ?? "modulo"}.sema`;
|
|
1637
|
-
}
|
|
1638
|
-
function contextoArquivoModulo(modulo, namespaceBase) {
|
|
1639
|
-
const prefixo = namespaceBase.split(".");
|
|
1640
|
-
const segmentos = modulo.split(".");
|
|
1641
|
-
const relativos = segmentos.slice(prefixo.length, -1);
|
|
1642
|
-
return relativos.length ? path.join(...relativos) : "";
|
|
1643
|
-
}
|
|
1644
|
-
function montarArquivoImportado(modulo, namespaceBase, conteudo) {
|
|
1645
|
-
const pasta = contextoArquivoModulo(modulo.nome, namespaceBase);
|
|
1646
|
-
const caminhoRelativo = pasta ? path.join(pasta, nomeArquivoModulo(modulo.nome)) : nomeArquivoModulo(modulo.nome);
|
|
1647
|
-
return {
|
|
1648
|
-
caminhoRelativo,
|
|
1649
|
-
conteudo,
|
|
1650
|
-
modulo: modulo.nome,
|
|
1651
|
-
tarefas: modulo.tasks.length,
|
|
1652
|
-
rotas: modulo.routes.length,
|
|
1653
|
-
entidades: modulo.entities.length,
|
|
1654
|
-
enums: modulo.enums.length,
|
|
1655
|
-
databases: modulo.databases?.length ?? 0,
|
|
1656
|
-
};
|
|
1657
|
-
}
|
|
1658
|
-
function consolidarTiposTs(contextos) {
|
|
1659
|
-
const tipos = new Map();
|
|
1660
|
-
for (const contexto of contextos) {
|
|
1661
|
-
for (const [nome, tipo] of extrairTiposTs(contexto.sourceFile)) {
|
|
1662
|
-
if (!tipos.has(nome)) {
|
|
1663
|
-
tipos.set(nome, tipo);
|
|
1664
|
-
}
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
return tipos;
|
|
1668
|
-
}
|
|
1669
|
-
function importarNestJsDeArquivo(diretorioBase, arquivo, namespaceBase, tiposGlobais) {
|
|
1670
|
-
const relacao = path.relative(diretorioBase, arquivo);
|
|
1671
|
-
const codigo = ts.sys.readFile(arquivo, "utf8") ?? "";
|
|
1672
|
-
const sourceFile = ts.createSourceFile(arquivo, codigo, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
1673
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
1674
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
1675
|
-
const entitiesRef = new Set();
|
|
1676
|
-
const enumsRef = new Set();
|
|
1677
|
-
const tasks = [];
|
|
1678
|
-
const routes = [];
|
|
1679
|
-
for (const node of sourceFile.statements) {
|
|
1680
|
-
if (!ts.isClassDeclaration(node)) {
|
|
1681
|
-
continue;
|
|
1682
|
-
}
|
|
1683
|
-
const controllerDecorator = lerDecorator(node, ["Controller"]);
|
|
1684
|
-
if (controllerDecorator) {
|
|
1685
|
-
const basePath = extrairTextoLiteral(controllerDecorator.argumentos[0]);
|
|
1686
|
-
for (const member of node.members) {
|
|
1687
|
-
if (!ts.isMethodDeclaration(member) || !member.body) {
|
|
1688
|
-
continue;
|
|
1689
|
-
}
|
|
1690
|
-
const httpDecorator = lerDecorator(member, ["Get", "Post", "Put", "Patch", "Delete"]);
|
|
1691
|
-
if (!httpDecorator) {
|
|
1692
|
-
continue;
|
|
1693
|
-
}
|
|
1694
|
-
const taskOriginal = extrairChamadaServiceTs(member.body) ?? member.name.getText(sourceFile);
|
|
1695
|
-
const taskNome = paraSnakeCase(taskOriginal);
|
|
1696
|
-
const routeInput = member.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(sourceFile), parametro.type?.getText(sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1697
|
-
const routeOutputTipo = member.type?.getText(sourceFile);
|
|
1698
|
-
const routeOutput = !routeOutputTipo || mapearTipoPrimitivo(routeOutputTipo) === "Vazio"
|
|
1699
|
-
? []
|
|
1700
|
-
: deduplicarCampos(expandirCamposTs("resultado", routeOutputTipo, tiposGlobais, entitiesRef, enumsRef, false));
|
|
1701
|
-
routes.push({
|
|
1702
|
-
nome: `${taskNome}_publico`,
|
|
1703
|
-
resumo: `Rota importada automaticamente de ${relacao}#${member.name.getText(sourceFile)}.`,
|
|
1704
|
-
metodo: httpDecorator.nome.toUpperCase(),
|
|
1705
|
-
caminho: juntarCaminhoHttp(basePath, extrairTextoLiteral(httpDecorator.argumentos[0])),
|
|
1706
|
-
task: taskNome,
|
|
1707
|
-
input: deduplicarCampos(routeInput),
|
|
1708
|
-
output: routeOutput,
|
|
1709
|
-
errors: [],
|
|
1710
|
-
});
|
|
1711
|
-
}
|
|
1712
|
-
}
|
|
1713
|
-
if (!node.name?.text.endsWith("Service")) {
|
|
1714
|
-
continue;
|
|
1715
|
-
}
|
|
1716
|
-
for (const member of node.members) {
|
|
1717
|
-
if (!ts.isMethodDeclaration(member) || !member.body || !member.name) {
|
|
1718
|
-
continue;
|
|
1719
|
-
}
|
|
1720
|
-
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.PrivateKeyword || modifier.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
1721
|
-
continue;
|
|
1722
|
-
}
|
|
1723
|
-
const nomeMetodo = member.name.getText(sourceFile);
|
|
1724
|
-
if (nomeMetodo === "constructor") {
|
|
1725
|
-
continue;
|
|
1726
|
-
}
|
|
1727
|
-
const input = member.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(sourceFile), parametro.type?.getText(sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1728
|
-
const output = member.type?.getText(sourceFile) && mapearTipoPrimitivo(member.type.getText(sourceFile)) === "Vazio"
|
|
1729
|
-
? []
|
|
1730
|
-
: deduplicarCampos(expandirCamposTs("resultado", member.type?.getText(sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
1731
|
-
tasks.push({
|
|
1732
|
-
nome: paraSnakeCase(nomeMetodo),
|
|
1733
|
-
resumo: `Task importada automaticamente de ${relacao}#${nomeMetodo}.`,
|
|
1734
|
-
input: deduplicarCampos(input),
|
|
1735
|
-
output,
|
|
1736
|
-
errors: extrairErrosTs(member.body, sourceFile),
|
|
1737
|
-
effects: descreverEfeitosPorHeuristica(member.body.getText(sourceFile)),
|
|
1738
|
-
impl: { ts: caminhoImplTs(diretorioBase, arquivo, nomeMetodo) },
|
|
1739
|
-
origemArquivo: relacao,
|
|
1740
|
-
origemSimbolo: nomeMetodo,
|
|
1741
|
-
});
|
|
1742
|
-
}
|
|
1743
|
-
}
|
|
1744
|
-
if (!tasks.length && !routes.length) {
|
|
1745
|
-
return [];
|
|
1746
|
-
}
|
|
1747
|
-
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
1748
|
-
sincronizarRotasComTasks(routes, tasks);
|
|
1749
|
-
return [{
|
|
1750
|
-
nome: nomeModulo,
|
|
1751
|
-
resumo: `Rascunho Sema importado de um contexto NestJS legado em ${contextoSegmentos.join("/")}.`,
|
|
1752
|
-
entities,
|
|
1753
|
-
enums,
|
|
1754
|
-
tasks: deduplicarTarefas(tasks),
|
|
1755
|
-
routes: deduplicarRotas(routes),
|
|
1756
|
-
}];
|
|
1757
|
-
}
|
|
1758
|
-
async function importarTypeScriptBase(diretorio, namespaceBase, modoNestjs = false) {
|
|
1759
|
-
const arquivos = await listarArquivosRecursivos(diretorio, [".ts"]);
|
|
1760
|
-
const uteis = arquivos.filter((arquivo) => !arquivo.endsWith(".spec.ts")
|
|
1761
|
-
&& !arquivo.endsWith(".test.ts")
|
|
1762
|
-
&& !arquivo.endsWith(".d.ts")
|
|
1763
|
-
&& !(modoNestjs && !arquivo.endsWith(".controller.ts") && !arquivo.endsWith(".service.ts")));
|
|
1764
|
-
const contextosTodos = await Promise.all(arquivos
|
|
1765
|
-
.filter((arquivo) => !arquivo.endsWith(".spec.ts") && !arquivo.endsWith(".test.ts") && !arquivo.endsWith(".d.ts"))
|
|
1766
|
-
.map(async (arquivo) => {
|
|
1767
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1768
|
-
return {
|
|
1769
|
-
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS),
|
|
1770
|
-
texto,
|
|
1771
|
-
relacao: path.relative(diretorio, arquivo),
|
|
1772
|
-
};
|
|
1773
|
-
}));
|
|
1774
|
-
const contextos = await Promise.all(uteis.map(async (arquivo) => {
|
|
1775
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1776
|
-
return {
|
|
1777
|
-
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS),
|
|
1778
|
-
texto,
|
|
1779
|
-
relacao: path.relative(diretorio, arquivo),
|
|
1780
|
-
};
|
|
1781
|
-
}));
|
|
1782
|
-
const tiposGlobais = consolidarTiposTs(contextosTodos);
|
|
1783
|
-
const modulos = new Map();
|
|
1784
|
-
if (modoNestjs) {
|
|
1785
|
-
for (const contexto of contextos) {
|
|
1786
|
-
for (const modulo of importarNestJsDeArquivo(diretorio, path.join(diretorio, contexto.relacao), namespaceBase, tiposGlobais)) {
|
|
1787
|
-
const existente = modulos.get(modulo.nome);
|
|
1788
|
-
if (!existente) {
|
|
1789
|
-
modulos.set(modulo.nome, modulo);
|
|
1790
|
-
continue;
|
|
1791
|
-
}
|
|
1792
|
-
existente.tasks = deduplicarTarefas([...existente.tasks, ...modulo.tasks]);
|
|
1793
|
-
existente.routes = deduplicarRotas([...existente.routes, ...modulo.routes]);
|
|
1794
|
-
existente.entities = deduplicarEntidades([...existente.entities, ...modulo.entities]);
|
|
1795
|
-
existente.enums = deduplicarEnums([...existente.enums, ...modulo.enums]);
|
|
1796
|
-
}
|
|
1797
|
-
}
|
|
1798
|
-
return [...modulos.values()];
|
|
1799
|
-
}
|
|
1800
|
-
for (const contexto of contextos) {
|
|
1801
|
-
const entitiesRef = new Set();
|
|
1802
|
-
const enumsRef = new Set();
|
|
1803
|
-
const contextoSegmentos = inferirContextoPorArquivo(contexto.relacao);
|
|
1804
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
1805
|
-
const tasks = [];
|
|
1806
|
-
contexto.sourceFile.forEachChild((node) => {
|
|
1807
|
-
if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
1808
|
-
const nome = node.name.text;
|
|
1809
|
-
const input = node.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1810
|
-
const output = node.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(node.type.getText(contexto.sourceFile)) === "Vazio"
|
|
1811
|
-
? []
|
|
1812
|
-
: deduplicarCampos(expandirCamposTs("resultado", node.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
1813
|
-
const errors = node.body ? extrairErrosTs(node.body, contexto.sourceFile) : [];
|
|
1814
|
-
const effects = node.body ? descreverEfeitosPorHeuristica(node.body.getText(contexto.sourceFile)) : [];
|
|
1815
|
-
tasks.push({
|
|
1816
|
-
nome: paraSnakeCase(nome),
|
|
1817
|
-
resumo: `Task importada automaticamente de ${contexto.relacao}#${nome}.`,
|
|
1818
|
-
input: deduplicarCampos(input),
|
|
1819
|
-
output,
|
|
1820
|
-
errors,
|
|
1821
|
-
effects,
|
|
1822
|
-
impl: { ts: caminhoImplTs(diretorio, path.join(diretorio, contexto.relacao), nome) },
|
|
1823
|
-
origemArquivo: contexto.relacao,
|
|
1824
|
-
origemSimbolo: nome,
|
|
1825
|
-
});
|
|
1826
|
-
}
|
|
1827
|
-
if (ts.isClassDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
1828
|
-
const nomeClasse = node.name.text;
|
|
1829
|
-
for (const member of node.members) {
|
|
1830
|
-
if (!ts.isMethodDeclaration(member) || !member.name || !member.body) {
|
|
1831
|
-
continue;
|
|
1832
|
-
}
|
|
1833
|
-
if (member.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.PrivateKeyword || modifier.kind === ts.SyntaxKind.ProtectedKeyword)) {
|
|
1834
|
-
continue;
|
|
1835
|
-
}
|
|
1836
|
-
const nomeMetodo = member.name.getText(contexto.sourceFile);
|
|
1837
|
-
if (nomeMetodo === "constructor") {
|
|
1838
|
-
continue;
|
|
1839
|
-
}
|
|
1840
|
-
const input = member.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
1841
|
-
const output = member.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(member.type.getText(contexto.sourceFile)) === "Vazio"
|
|
1842
|
-
? []
|
|
1843
|
-
: deduplicarCampos(expandirCamposTs("resultado", member.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
1844
|
-
tasks.push({
|
|
1845
|
-
nome: paraSnakeCase(nomeMetodo),
|
|
1846
|
-
resumo: `Task importada automaticamente de ${contexto.relacao}#${nomeClasse}.${nomeMetodo}.`,
|
|
1847
|
-
input: deduplicarCampos(input),
|
|
1848
|
-
output,
|
|
1849
|
-
errors: extrairErrosTs(member.body, contexto.sourceFile),
|
|
1850
|
-
effects: descreverEfeitosPorHeuristica(member.body.getText(contexto.sourceFile)),
|
|
1851
|
-
impl: { ts: caminhoImplTs(diretorio, path.join(diretorio, contexto.relacao), `${nomeClasse}.${nomeMetodo}`) },
|
|
1852
|
-
origemArquivo: contexto.relacao,
|
|
1853
|
-
origemSimbolo: `${nomeClasse}.${nomeMetodo}`,
|
|
1854
|
-
});
|
|
1855
|
-
}
|
|
1856
|
-
}
|
|
1857
|
-
});
|
|
1858
|
-
if (tasks.length === 0) {
|
|
1859
|
-
continue;
|
|
1860
|
-
}
|
|
1861
|
-
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
1862
|
-
modulos.set(nomeModulo, {
|
|
1863
|
-
nome: nomeModulo,
|
|
1864
|
-
resumo: `Rascunho Sema importado automaticamente de ${contexto.relacao}.`,
|
|
1865
|
-
tasks: deduplicarTarefas(tasks),
|
|
1866
|
-
routes: [],
|
|
1867
|
-
entities,
|
|
1868
|
-
enums,
|
|
1869
|
-
});
|
|
1870
|
-
}
|
|
1871
|
-
return [...modulos.values()];
|
|
1872
|
-
}
|
|
1873
|
-
function nomeTaskParaRotaTypeScript(caminho, metodo) {
|
|
1874
|
-
const segmentos = caminho
|
|
1875
|
-
.replace(/^\/+|\/+$/g, "")
|
|
1876
|
-
.split("/")
|
|
1877
|
-
.filter(Boolean)
|
|
1878
|
-
.map((segmento) => segmento.replace(/[{}]/g, ""));
|
|
1879
|
-
return paraSnakeCase([...segmentos, metodo.toLowerCase()].join("_")) || `rota_${metodo.toLowerCase()}`;
|
|
1880
|
-
}
|
|
1881
|
-
function camposDeParametrosRotaTypeScript(parametros) {
|
|
1882
|
-
return parametros.map((parametro) => ({
|
|
1883
|
-
nome: paraSnakeCase(parametro.nome),
|
|
1884
|
-
tipo: parametro.tipoSema,
|
|
1885
|
-
obrigatorio: true,
|
|
1886
|
-
}));
|
|
1887
|
-
}
|
|
1888
|
-
function extrairColecoesFirebaseImportacao(texto) {
|
|
1889
|
-
const encontrados = new Set();
|
|
1890
|
-
for (const match of texto.matchAll(/\b(?:export\s+)?const\s+\w*COLLECTIONS?\w*\s*=\s*\{([\s\S]*?)\n\}/g)) {
|
|
1891
|
-
const corpo = match[1] ?? "";
|
|
1892
|
-
for (const valor of corpo.matchAll(/:\s*["'`]([^"'`]+)["'`]/g)) {
|
|
1893
|
-
encontrados.add(valor[1]);
|
|
1894
|
-
}
|
|
1895
|
-
}
|
|
1896
|
-
return [...encontrados];
|
|
1897
|
-
}
|
|
1898
|
-
async function importarNextJsBase(diretorio, namespaceBase) {
|
|
1899
|
-
const escopo = resolverEscopoImportacaoNextJs(diretorio);
|
|
1900
|
-
const arquivos = await listarArquivosRecursivos(escopo.diretorioEscopo, [".ts", ".tsx", ".js", ".jsx"]);
|
|
1901
|
-
const uteis = arquivos.filter((arquivo) => !arquivo.endsWith(".spec.ts")
|
|
1902
|
-
&& !arquivo.endsWith(".test.ts")
|
|
1903
|
-
&& !arquivo.endsWith(".d.ts")
|
|
1904
|
-
&& /(\\|\/)(?:src\\|src\/)?app(\\|\/)api(\\|\/).+(\\|\/)route\.(ts|tsx|js|jsx)$/i.test(arquivo));
|
|
1905
|
-
const contextos = await Promise.all(uteis.map(async (arquivo) => {
|
|
1906
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1907
|
-
const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
1908
|
-
return {
|
|
1909
|
-
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, scriptKind),
|
|
1910
|
-
texto,
|
|
1911
|
-
relacao: path.relative(escopo.baseProjeto, arquivo),
|
|
1912
|
-
};
|
|
1913
|
-
}));
|
|
1914
|
-
const tiposGlobais = consolidarTiposTs(contextos);
|
|
1915
|
-
const modulos = new Map();
|
|
1916
|
-
for (const contexto of contextos) {
|
|
1917
|
-
const entitiesRef = new Set();
|
|
1918
|
-
const enumsRef = new Set();
|
|
1919
|
-
const contextoSegmentos = inferirContextoPorArquivo(contexto.relacao.replace(/[\\/]route\.(?:ts|tsx|js|jsx)$/i, "")).filter((segmento, indice) => !(indice === 0 && segmento === "app"));
|
|
1920
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
1921
|
-
const tasks = [];
|
|
1922
|
-
const routes = [];
|
|
1923
|
-
for (const rota of extrairRotasTypeScriptHttp(contexto.sourceFile, contexto.relacao).filter((item) => item.origem === "nextjs")) {
|
|
1924
|
-
const taskNome = nomeTaskParaRotaTypeScript(rota.caminho, rota.metodo);
|
|
1925
|
-
const exportacao = localizarExportacaoTypeScriptHttp(contexto.sourceFile, rota.simbolo);
|
|
1926
|
-
const semantica = inferirSemanticaHandlerTypeScriptHttp(contexto.sourceFile, rota.simbolo);
|
|
1927
|
-
const input = deduplicarCampos([
|
|
1928
|
-
...camposDeParametrosRotaTypeScript(rota.parametros),
|
|
1929
|
-
...camposDeSemanticaTypeScriptHttp(semantica?.query ?? [], tiposGlobais, entitiesRef, enumsRef),
|
|
1930
|
-
...camposEstruturadosTypeScriptHttp("body", semantica?.bodyTipoTexto, tiposGlobais, entitiesRef, enumsRef),
|
|
1931
|
-
...camposDeSemanticaTypeScriptHttp(semantica?.body ?? [], tiposGlobais, entitiesRef, enumsRef),
|
|
1932
|
-
]);
|
|
1933
|
-
const output = semantica && semantica.response.length > 0
|
|
1934
|
-
? deduplicarCampos(camposDeSemanticaTypeScriptHttp(semantica.response, tiposGlobais, entitiesRef, enumsRef))
|
|
1935
|
-
: semantica?.responseTipoTexto
|
|
1936
|
-
? deduplicarCampos(expandirCamposTs("resultado", semantica.responseTipoTexto, tiposGlobais, entitiesRef, enumsRef, false))
|
|
1937
|
-
: exportacao?.retorno && mapearTipoPrimitivo(exportacao.retorno) === "Vazio"
|
|
1938
|
-
? []
|
|
1939
|
-
: deduplicarCampos(expandirCamposTs("resultado", exportacao?.retorno, tiposGlobais, entitiesRef, enumsRef, false));
|
|
1940
|
-
const taskOutput = output.length > 0 ? output : [{ nome: "resultado", tipo: "Json", obrigatorio: false }];
|
|
1941
|
-
const resumoBase = `Rota Next.js App Router importada automaticamente de ${contexto.relacao}#${rota.simbolo}.`;
|
|
1942
|
-
const errors = deduplicarErros([
|
|
1943
|
-
...(exportacao?.corpo ? extrairErrosTs(exportacao.corpo, contexto.sourceFile) : []),
|
|
1944
|
-
...errosPorStatusHttp(semantica?.errorStatuses ?? []),
|
|
1945
|
-
]);
|
|
1946
|
-
tasks.push({
|
|
1947
|
-
nome: taskNome,
|
|
1948
|
-
resumo: `Task derivada automaticamente de ${contexto.relacao}#${rota.simbolo}.`,
|
|
1949
|
-
input,
|
|
1950
|
-
output: taskOutput,
|
|
1951
|
-
errors,
|
|
1952
|
-
effects: exportacao?.corpo ? descreverEfeitosPorHeuristica(exportacao.corpo.getText(contexto.sourceFile)) : descreverEfeitosPorHeuristica(contexto.texto),
|
|
1953
|
-
impl: { ts: caminhoImplTs(escopo.baseProjeto, path.join(escopo.baseProjeto, contexto.relacao), rota.simbolo) },
|
|
1954
|
-
origemArquivo: contexto.relacao,
|
|
1955
|
-
origemSimbolo: rota.simbolo,
|
|
1956
|
-
});
|
|
1957
|
-
routes.push({
|
|
1958
|
-
nome: `${taskNome}_publico`,
|
|
1959
|
-
resumo: resumoBase,
|
|
1960
|
-
metodo: rota.metodo,
|
|
1961
|
-
caminho: rota.caminho,
|
|
1962
|
-
task: taskNome,
|
|
1963
|
-
input,
|
|
1964
|
-
output: taskOutput,
|
|
1965
|
-
errors,
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
if (!tasks.length && !routes.length) {
|
|
1969
|
-
continue;
|
|
1970
|
-
}
|
|
1971
|
-
sincronizarRotasComTasks(routes, tasks);
|
|
1972
|
-
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
1973
|
-
modulos.set(nomeModulo, {
|
|
1974
|
-
nome: nomeModulo,
|
|
1975
|
-
resumo: `Rascunho Sema importado automaticamente de ${contexto.relacao}.`,
|
|
1976
|
-
tasks: deduplicarTarefas(tasks),
|
|
1977
|
-
routes: deduplicarRotas(routes),
|
|
1978
|
-
entities,
|
|
1979
|
-
enums,
|
|
1980
|
-
});
|
|
1981
|
-
}
|
|
1982
|
-
return [...modulos.values()];
|
|
1983
|
-
}
|
|
1984
|
-
async function importarFirebaseBase(diretorio, namespaceBase) {
|
|
1985
|
-
const arquivos = await listarArquivosRecursivos(diretorio, [".ts", ".tsx", ".js", ".jsx"]);
|
|
1986
|
-
const uteis = arquivos.filter((arquivo) => !arquivo.endsWith(".spec.ts")
|
|
1987
|
-
&& !arquivo.endsWith(".test.ts")
|
|
1988
|
-
&& !arquivo.endsWith(".d.ts")
|
|
1989
|
-
&& /(sema_contract_bridge|health-check|collections?|firestore)/i.test(arquivo));
|
|
1990
|
-
const contextos = await Promise.all(uteis.map(async (arquivo) => {
|
|
1991
|
-
const texto = await readFile(arquivo, "utf8");
|
|
1992
|
-
const scriptKind = arquivo.endsWith(".tsx") ? ts.ScriptKind.TSX : ts.ScriptKind.TS;
|
|
1993
|
-
return {
|
|
1994
|
-
sourceFile: ts.createSourceFile(arquivo, texto, ts.ScriptTarget.Latest, true, scriptKind),
|
|
1995
|
-
texto,
|
|
1996
|
-
relacao: path.relative(diretorio, arquivo),
|
|
1997
|
-
};
|
|
1998
|
-
}));
|
|
1999
|
-
const tiposGlobais = consolidarTiposTs(contextos);
|
|
2000
|
-
const modulos = new Map();
|
|
2001
|
-
for (const contexto of contextos) {
|
|
2002
|
-
const entitiesRef = new Set();
|
|
2003
|
-
const enumsRef = new Set();
|
|
2004
|
-
const contextoSegmentos = inferirContextoPorArquivo(contexto.relacao);
|
|
2005
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2006
|
-
const tasks = [];
|
|
2007
|
-
const routes = [];
|
|
2008
|
-
for (const node of contexto.sourceFile.statements) {
|
|
2009
|
-
if (ts.isFunctionDeclaration(node) && node.name && node.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
|
|
2010
|
-
const nome = node.name.text;
|
|
2011
|
-
const input = node.parameters.flatMap((parametro) => expandirCamposTs(parametro.name.getText(contexto.sourceFile), parametro.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, !parametro.questionToken));
|
|
2012
|
-
const output = node.type?.getText(contexto.sourceFile) && mapearTipoPrimitivo(node.type.getText(contexto.sourceFile)) === "Vazio"
|
|
2013
|
-
? []
|
|
2014
|
-
: deduplicarCampos(expandirCamposTs("resultado", node.type?.getText(contexto.sourceFile), tiposGlobais, entitiesRef, enumsRef, false));
|
|
2015
|
-
tasks.push({
|
|
2016
|
-
nome: paraSnakeCase(nome.replace(/^sema/, "")) || paraSnakeCase(nome),
|
|
2017
|
-
resumo: `Task Firebase/worker importada automaticamente de ${contexto.relacao}#${nome}.`,
|
|
2018
|
-
input: deduplicarCampos(input),
|
|
2019
|
-
output: output.length > 0 ? output : [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2020
|
-
errors: node.body ? extrairErrosTs(node.body, contexto.sourceFile) : [],
|
|
2021
|
-
effects: node.body ? descreverEfeitosPorHeuristica(node.body.getText(contexto.sourceFile)) : descreverEfeitosPorHeuristica(contexto.texto),
|
|
2022
|
-
impl: { ts: caminhoImplTs(diretorio, path.join(diretorio, contexto.relacao), nome) },
|
|
2023
|
-
origemArquivo: contexto.relacao,
|
|
2024
|
-
origemSimbolo: nome,
|
|
2025
|
-
});
|
|
2026
|
-
}
|
|
2027
|
-
}
|
|
2028
|
-
for (const rota of extrairRotasTypeScriptHttp(contexto.sourceFile, contexto.relacao).filter((item) => item.origem === "firebase")) {
|
|
2029
|
-
const taskNome = nomeTaskParaRotaTypeScript(rota.caminho, rota.metodo);
|
|
2030
|
-
const exportacao = localizarExportacaoTypeScriptHttp(contexto.sourceFile, rota.simbolo);
|
|
2031
|
-
const input = deduplicarCampos(camposDeParametrosRotaTypeScript(rota.parametros));
|
|
2032
|
-
const output = exportacao?.retorno && mapearTipoPrimitivo(exportacao.retorno) === "Vazio"
|
|
2033
|
-
? []
|
|
2034
|
-
: deduplicarCampos(expandirCamposTs("resultado", exportacao?.retorno, tiposGlobais, entitiesRef, enumsRef, false));
|
|
2035
|
-
const taskOutput = output.length > 0 ? output : [{ nome: "resultado", tipo: "Json", obrigatorio: false }];
|
|
2036
|
-
tasks.push({
|
|
2037
|
-
nome: taskNome,
|
|
2038
|
-
resumo: `Task HTTP do worker importada automaticamente de ${contexto.relacao}#${rota.simbolo}.`,
|
|
2039
|
-
input,
|
|
2040
|
-
output: taskOutput,
|
|
2041
|
-
errors: exportacao?.corpo ? extrairErrosTs(exportacao.corpo, contexto.sourceFile) : [],
|
|
2042
|
-
effects: exportacao?.corpo ? descreverEfeitosPorHeuristica(exportacao.corpo.getText(contexto.sourceFile)) : descreverEfeitosPorHeuristica(contexto.texto),
|
|
2043
|
-
impl: { ts: caminhoImplTs(diretorio, path.join(diretorio, contexto.relacao), rota.simbolo) },
|
|
2044
|
-
origemArquivo: contexto.relacao,
|
|
2045
|
-
origemSimbolo: rota.simbolo,
|
|
2046
|
-
});
|
|
2047
|
-
routes.push({
|
|
2048
|
-
nome: `${taskNome}_publico`,
|
|
2049
|
-
resumo: `Rota do worker importada automaticamente de ${contexto.relacao}#${rota.simbolo}.`,
|
|
2050
|
-
metodo: rota.metodo,
|
|
2051
|
-
caminho: rota.caminho,
|
|
2052
|
-
task: taskNome,
|
|
2053
|
-
input,
|
|
2054
|
-
output: taskOutput,
|
|
2055
|
-
errors: exportacao?.corpo ? extrairErrosTs(exportacao.corpo, contexto.sourceFile) : [],
|
|
2056
|
-
});
|
|
2057
|
-
}
|
|
2058
|
-
for (const colecao of extrairColecoesFirebaseImportacao(contexto.texto)) {
|
|
2059
|
-
tasks.push({
|
|
2060
|
-
nome: paraSnakeCase(`inventariar_${colecao}`),
|
|
2061
|
-
resumo: `Task sintetica para registrar o recurso persistido ${colecao} descoberto em ${contexto.relacao}.`,
|
|
2062
|
-
input: [],
|
|
2063
|
-
output: [{ nome: "colecao", tipo: "Texto", obrigatorio: false }],
|
|
2064
|
-
errors: [],
|
|
2065
|
-
effects: [{ categoria: "persistencia", alvo: colecao, criticidade: "media" }],
|
|
2066
|
-
origemArquivo: contexto.relacao,
|
|
2067
|
-
origemSimbolo: colecao,
|
|
2068
|
-
});
|
|
2069
|
-
}
|
|
2070
|
-
if (!tasks.length && !routes.length) {
|
|
2071
|
-
continue;
|
|
2072
|
-
}
|
|
2073
|
-
sincronizarRotasComTasks(routes, tasks);
|
|
2074
|
-
const { entities, enums } = criarEntidadesReferenciadas(tiposGlobais, entitiesRef, enumsRef);
|
|
2075
|
-
modulos.set(nomeModulo, {
|
|
2076
|
-
nome: nomeModulo,
|
|
2077
|
-
resumo: `Rascunho Sema importado automaticamente de ${contexto.relacao}.`,
|
|
2078
|
-
tasks: deduplicarTarefas(tasks),
|
|
2079
|
-
routes: deduplicarRotas(routes),
|
|
2080
|
-
entities,
|
|
2081
|
-
enums,
|
|
2082
|
-
});
|
|
2083
|
-
}
|
|
2084
|
-
return [...modulos.values()];
|
|
2085
|
-
}
|
|
2086
|
-
function extrairTiposPython(texto) {
|
|
2087
|
-
const encontrados = new Map();
|
|
2088
|
-
const regexBaseModel = /^class\s+(\w+)(?:\(([^)]*)\))?:\n((?:^[ \t].*(?:\n|$))*)/gm;
|
|
2089
|
-
for (const match of texto.matchAll(regexBaseModel)) {
|
|
2090
|
-
const [, nome, bases = "", corpo] = match;
|
|
2091
|
-
if (!bases.includes("BaseModel")) {
|
|
2092
|
-
continue;
|
|
2093
|
-
}
|
|
2094
|
-
const campos = [...corpo.matchAll(/^\s{4}(\w+)\s*:\s*([^\n=]+)(?:\s*=.+)?$/gm)].map((campo) => ({
|
|
2095
|
-
nome: campo[1],
|
|
2096
|
-
tipoTexto: campo[2].trim(),
|
|
2097
|
-
obrigatorio: !/=/.test(campo[0]),
|
|
2098
|
-
}));
|
|
2099
|
-
encontrados.set(nome, { tipo: "objeto", nome: nome, campos });
|
|
2100
|
-
}
|
|
2101
|
-
const regexEnum = /^class\s+(\w+)(?:\(([^)]*)\))?:\n((?:^[ \t].*(?:\n|$))*)/gm;
|
|
2102
|
-
for (const match of texto.matchAll(regexEnum)) {
|
|
2103
|
-
const [, nome, bases = "", corpo] = match;
|
|
2104
|
-
if (!/(Enum|StrEnum)/.test(bases)) {
|
|
2105
|
-
continue;
|
|
2106
|
-
}
|
|
2107
|
-
const valores = [...corpo.matchAll(/^\s{4}(\w+)\s*=\s*["']([^"']+)["']$/gm)].map((valor) => valor[1]).filter(Boolean);
|
|
2108
|
-
if (valores.length) {
|
|
2109
|
-
encontrados.set(nome, { tipo: "enum", nome: nome, valores });
|
|
2110
|
-
}
|
|
2111
|
-
}
|
|
2112
|
-
return encontrados;
|
|
2113
|
-
}
|
|
2114
|
-
function mapearTipoPythonParaSema(tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
2115
|
-
if (!tipoTexto) {
|
|
2116
|
-
return "Json";
|
|
2117
|
-
}
|
|
2118
|
-
const limpo = tipoTexto.replace(/\s+/g, "");
|
|
2119
|
-
const basico = mapearTipoPrimitivo(limpo);
|
|
2120
|
-
if (basico !== limpo) {
|
|
2121
|
-
return basico;
|
|
2122
|
-
}
|
|
2123
|
-
const simples = limpo.replace(/Optional\[(.+)\]/, "$1").replace(/list\[(.+)\]/i, "Json").replace(/dict\[(.+)\]/i, "Json");
|
|
2124
|
-
if (tipos.has(simples)) {
|
|
2125
|
-
const encontrado = tipos.get(simples);
|
|
2126
|
-
if (encontrado.tipo === "enum") {
|
|
2127
|
-
enumsReferenciados.add(encontrado.nome);
|
|
2128
|
-
return encontrado.nome;
|
|
2129
|
-
}
|
|
2130
|
-
if (!pareceWrapperTipo(encontrado.nome)) {
|
|
2131
|
-
entidadesReferenciadas.add(encontrado.nome);
|
|
2132
|
-
return encontrado.nome;
|
|
2133
|
-
}
|
|
2134
|
-
}
|
|
2135
|
-
return "Json";
|
|
2136
|
-
}
|
|
2137
|
-
function expandirCamposPython(nomeParametro, tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados, obrigatorio) {
|
|
2138
|
-
if (!tipoTexto) {
|
|
2139
|
-
return [{ nome: paraSnakeCase(nomeParametro), tipo: "Json", obrigatorio }];
|
|
2140
|
-
}
|
|
2141
|
-
const limpo = tipoTexto.replace(/\s+/g, "").replace(/Optional\[(.+)\]/, "$1");
|
|
2142
|
-
const descoberto = tipos.get(limpo);
|
|
2143
|
-
if (descoberto?.tipo === "objeto" && pareceWrapperTipo(descoberto.nome) && descoberto.campos) {
|
|
2144
|
-
return descoberto.campos.map((campo) => ({
|
|
2145
|
-
nome: paraSnakeCase(campo.nome),
|
|
2146
|
-
tipo: mapearTipoPythonParaSema(campo.tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
2147
|
-
obrigatorio: campo.obrigatorio,
|
|
2148
|
-
}));
|
|
2149
|
-
}
|
|
2150
|
-
return [{
|
|
2151
|
-
nome: paraSnakeCase(nomeParametro),
|
|
2152
|
-
tipo: mapearTipoPythonParaSema(tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
2153
|
-
obrigatorio,
|
|
2154
|
-
}];
|
|
2155
|
-
}
|
|
2156
|
-
function criarEntidadesPython(tipos, entidadesReferenciadas, enumsReferenciados) {
|
|
2157
|
-
const entities = [...entidadesReferenciadas]
|
|
2158
|
-
.map((nome) => tipos.get(nome))
|
|
2159
|
-
.filter((item) => Boolean(item?.tipo === "objeto" && item.campos))
|
|
2160
|
-
.map((item) => ({
|
|
2161
|
-
nome: item.nome,
|
|
2162
|
-
campos: item.campos.map((campo) => ({
|
|
2163
|
-
nome: paraSnakeCase(campo.nome),
|
|
2164
|
-
tipo: mapearTipoPythonParaSema(campo.tipoTexto, tipos, entidadesReferenciadas, enumsReferenciados),
|
|
2165
|
-
obrigatorio: campo.obrigatorio,
|
|
2166
|
-
})),
|
|
2167
|
-
}));
|
|
2168
|
-
const enums = [...enumsReferenciados]
|
|
2169
|
-
.map((nome) => tipos.get(nome))
|
|
2170
|
-
.filter((item) => Boolean(item?.tipo === "enum" && item.valores))
|
|
2171
|
-
.map((item) => ({
|
|
2172
|
-
nome: item.nome,
|
|
2173
|
-
valores: item.valores,
|
|
2174
|
-
}));
|
|
2175
|
-
return { entities: deduplicarEntidades(entities), enums: deduplicarEnums(enums) };
|
|
2176
|
-
}
|
|
2177
|
-
function extrairErrosPython(texto) {
|
|
2178
|
-
const erros = new Map();
|
|
2179
|
-
for (const match of texto.matchAll(/raise\s+(\w+)(?:\(([^)]*)\))?/g)) {
|
|
2180
|
-
const nomeBruto = match[1];
|
|
2181
|
-
const mensagem = (match[2] ?? "").match(/["']([^"']+)["']/)?.[1] ?? `Erro importado automaticamente de ${nomeBruto}.`;
|
|
2182
|
-
erros.set(normalizarNomeErroBruto(nomeBruto), mensagem);
|
|
2183
|
-
}
|
|
2184
|
-
return [...erros.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
2185
|
-
}
|
|
2186
|
-
function caminhoImplGenerico(diretorioBase, arquivo, simbolo, opcoes) {
|
|
2187
|
-
const relativo = path.relative(diretorioBase, arquivo).replace(/\.[^.]+$/, "");
|
|
2188
|
-
const segmentos = relativo.split(path.sep).map((segmento, indice, lista) => opcoes?.snakeCaseUltimoArquivo && indice === lista.length - 1
|
|
2189
|
-
? paraSnakeCase(segmento)
|
|
2190
|
-
: paraIdentificadorModulo(segmento))
|
|
2191
|
-
.filter(Boolean);
|
|
2192
|
-
return [...segmentos, simbolo].join(".");
|
|
2193
|
-
}
|
|
2194
|
-
function caminhoImplPython(diretorioBase, arquivo, simbolo) {
|
|
2195
|
-
return caminhoImplGenerico(diretorioBase, arquivo, simbolo);
|
|
2196
|
-
}
|
|
2197
|
-
function caminhoImplDart(diretorioBase, arquivo, simbolo) {
|
|
2198
|
-
return caminhoImplGenerico(diretorioBase, arquivo, simbolo);
|
|
2199
|
-
}
|
|
2200
|
-
function dividirParametrosPython(parametros) {
|
|
2201
|
-
const partes = [];
|
|
2202
|
-
let atual = "";
|
|
2203
|
-
let profundidade = 0;
|
|
2204
|
-
for (const caractere of parametros) {
|
|
2205
|
-
if (caractere === "," && profundidade === 0) {
|
|
2206
|
-
if (atual.trim()) {
|
|
2207
|
-
partes.push(atual.trim());
|
|
2208
|
-
}
|
|
2209
|
-
atual = "";
|
|
2210
|
-
continue;
|
|
2211
|
-
}
|
|
2212
|
-
if (["[", "(", "{", "<"].includes(caractere)) {
|
|
2213
|
-
profundidade += 1;
|
|
2214
|
-
}
|
|
2215
|
-
else if (["]", ")", "}", ">"].includes(caractere) && profundidade > 0) {
|
|
2216
|
-
profundidade -= 1;
|
|
2217
|
-
}
|
|
2218
|
-
atual += caractere;
|
|
2219
|
-
}
|
|
2220
|
-
if (atual.trim()) {
|
|
2221
|
-
partes.push(atual.trim());
|
|
2222
|
-
}
|
|
2223
|
-
return partes;
|
|
2224
|
-
}
|
|
2225
|
-
function extrairAssinaturaParametrosPython(parametros) {
|
|
2226
|
-
const assinatura = new Map();
|
|
2227
|
-
for (const item of dividirParametrosPython(parametros)) {
|
|
2228
|
-
if (!item || item.startsWith("self") || item.startsWith("cls") || item.startsWith("*")) {
|
|
2229
|
-
continue;
|
|
2230
|
-
}
|
|
2231
|
-
const obrigatorio = !item.includes("=");
|
|
2232
|
-
const semValorPadrao = item.split("=")[0]?.trim() ?? item.trim();
|
|
2233
|
-
const [nomeBruto, tipo] = semValorPadrao.split(":").map((parte) => parte.trim());
|
|
2234
|
-
const nome = nomeBruto?.replace(/^\*{1,2}/, "").trim();
|
|
2235
|
-
if (!nome) {
|
|
2236
|
-
continue;
|
|
2237
|
-
}
|
|
2238
|
-
assinatura.set(nome, {
|
|
2239
|
-
tipoTexto: tipo || undefined,
|
|
2240
|
-
obrigatorio,
|
|
2241
|
-
});
|
|
2242
|
-
}
|
|
2243
|
-
return assinatura;
|
|
2244
|
-
}
|
|
2245
|
-
function mapearConversorFlaskParaSema(conversor) {
|
|
2246
|
-
switch ((conversor ?? "").toLowerCase()) {
|
|
2247
|
-
case "int":
|
|
2248
|
-
return "Inteiro";
|
|
2249
|
-
case "float":
|
|
2250
|
-
return "Decimal";
|
|
2251
|
-
case "uuid":
|
|
2252
|
-
return "Id";
|
|
2253
|
-
case "path":
|
|
2254
|
-
default:
|
|
2255
|
-
return "Texto";
|
|
2256
|
-
}
|
|
2257
|
-
}
|
|
2258
|
-
function criarInputRotaFlask(caminho, parametros, tiposGlobais, entitiesRef, enumsRef) {
|
|
2259
|
-
const assinatura = extrairAssinaturaParametrosPython(parametros);
|
|
2260
|
-
return extrairParametrosCaminhoFlask(caminho).map((parametro) => {
|
|
2261
|
-
const correspondente = assinatura.get(parametro.nome);
|
|
2262
|
-
return {
|
|
2263
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2264
|
-
tipo: correspondente?.tipoTexto
|
|
2265
|
-
? mapearTipoPythonParaSema(correspondente.tipoTexto, tiposGlobais, entitiesRef, enumsRef)
|
|
2266
|
-
: mapearConversorFlaskParaSema(parametro.conversor),
|
|
2267
|
-
obrigatorio: correspondente?.obrigatorio ?? true,
|
|
2268
|
-
};
|
|
2269
|
-
});
|
|
2270
|
-
}
|
|
2271
|
-
async function importarPythonBase(diretorio, namespaceBase, modoHttp = "nenhum") {
|
|
2272
|
-
const arquivos = (await listarArquivosRecursivos(diretorio, [".py"]))
|
|
2273
|
-
.filter((arquivo) => !arquivo.endsWith("__init__.py") && !/tests?[\\/]/i.test(arquivo));
|
|
2274
|
-
const textos = new Map();
|
|
2275
|
-
const tiposGlobais = new Map();
|
|
2276
|
-
for (const arquivo of arquivos) {
|
|
2277
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2278
|
-
textos.set(arquivo, texto);
|
|
2279
|
-
for (const [nome, tipo] of extrairTiposPython(texto)) {
|
|
2280
|
-
if (!tiposGlobais.has(nome)) {
|
|
2281
|
-
tiposGlobais.set(nome, tipo);
|
|
2282
|
-
}
|
|
2283
|
-
}
|
|
2284
|
-
}
|
|
2285
|
-
const modulos = new Map();
|
|
2286
|
-
for (const arquivo of arquivos) {
|
|
2287
|
-
const texto = textos.get(arquivo);
|
|
2288
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2289
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2290
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2291
|
-
const entitiesRef = new Set();
|
|
2292
|
-
const enumsRef = new Set();
|
|
2293
|
-
const tasks = [];
|
|
2294
|
-
const routes = [];
|
|
2295
|
-
if (modoHttp === "fastapi") {
|
|
2296
|
-
const prefixo = texto.match(/APIRouter\s*\(\s*prefix\s*=\s*["']([^"']+)["']/)?.[1];
|
|
2297
|
-
const routeRegex = /@(?:router|app)\.(get|post|put|patch|delete)\(([^)]*)\)\s*\n(?:async\s+)?def\s+(\w+)\(([^)]*)\)(?:\s*->\s*([^:]+))?:/g;
|
|
2298
|
-
for (const match of texto.matchAll(routeRegex)) {
|
|
2299
|
-
const metodo = match[1].toUpperCase();
|
|
2300
|
-
const argumentoDecorator = match[2] ?? "";
|
|
2301
|
-
const sufixo = argumentoDecorator.match(/["']([^"']+)["']/)?.[1];
|
|
2302
|
-
const nomeFuncao = match[3];
|
|
2303
|
-
const parametros = match[4];
|
|
2304
|
-
const retorno = match[5]?.trim();
|
|
2305
|
-
const routeInput = parametros
|
|
2306
|
-
.split(",")
|
|
2307
|
-
.map((item) => item.trim())
|
|
2308
|
-
.filter(Boolean)
|
|
2309
|
-
.filter((item) => !item.startsWith("self") && !item.startsWith("cls"))
|
|
2310
|
-
.flatMap((item) => {
|
|
2311
|
-
const [nome, tipo] = item.split(":").map((parte) => parte.trim());
|
|
2312
|
-
const obrigatorio = !item.includes("=");
|
|
2313
|
-
return expandirCamposPython(nome, tipo, tiposGlobais, entitiesRef, enumsRef, obrigatorio);
|
|
2314
|
-
});
|
|
2315
|
-
const routeOutput = retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
2316
|
-
? []
|
|
2317
|
-
: deduplicarCampos(expandirCamposPython("resultado", retorno, tiposGlobais, entitiesRef, enumsRef, false));
|
|
2318
|
-
const taskNome = paraSnakeCase(nomeFuncao);
|
|
2319
|
-
routes.push({
|
|
2320
|
-
nome: `${taskNome}_publico`,
|
|
2321
|
-
resumo: `Rota FastAPI importada automaticamente de ${relacao}#${nomeFuncao}.`,
|
|
2322
|
-
metodo,
|
|
2323
|
-
caminho: juntarCaminhoHttp(prefixo, sufixo),
|
|
2324
|
-
task: taskNome,
|
|
2325
|
-
input: deduplicarCampos(routeInput),
|
|
2326
|
-
output: routeOutput,
|
|
2327
|
-
errors: [],
|
|
2328
|
-
});
|
|
2329
|
-
}
|
|
2330
|
-
}
|
|
2331
|
-
else if (modoHttp === "flask") {
|
|
2332
|
-
for (const rota of extrairRotasFlaskDecoradas(texto)) {
|
|
2333
|
-
const taskNome = paraSnakeCase(rota.nomeFuncao);
|
|
2334
|
-
const nomeBase = `${taskNome}_publico`;
|
|
2335
|
-
const nome = routes.some((route) => route.nome === nomeBase)
|
|
2336
|
-
? `${taskNome}_${rota.metodo.toLowerCase()}_publico`
|
|
2337
|
-
: nomeBase;
|
|
2338
|
-
routes.push({
|
|
2339
|
-
nome,
|
|
2340
|
-
resumo: `Rota Flask importada automaticamente de ${relacao}#${rota.nomeFuncao}.`,
|
|
2341
|
-
metodo: rota.metodo,
|
|
2342
|
-
caminho: rota.caminho,
|
|
2343
|
-
task: taskNome,
|
|
2344
|
-
input: deduplicarCampos(criarInputRotaFlask(rota.caminho, rota.parametros, tiposGlobais, entitiesRef, enumsRef)),
|
|
2345
|
-
output: [],
|
|
2346
|
-
errors: [],
|
|
2347
|
-
});
|
|
2348
|
-
}
|
|
2349
|
-
}
|
|
2350
|
-
const funcRegex = /^(async\s+def|def)\s+(\w+)\(([^)]*)\)(?:\s*->\s*([^:]+))?:/gm;
|
|
2351
|
-
for (const match of texto.matchAll(funcRegex)) {
|
|
2352
|
-
const nomeFuncao = match[2];
|
|
2353
|
-
if (nomeFuncao.startsWith("_")) {
|
|
2354
|
-
continue;
|
|
2355
|
-
}
|
|
2356
|
-
const parametros = match[3];
|
|
2357
|
-
const retorno = match[4]?.trim();
|
|
2358
|
-
const inicioCorpo = match.index ?? 0;
|
|
2359
|
-
const trecho = texto.slice(inicioCorpo, Math.min(texto.length, inicioCorpo + 1500));
|
|
2360
|
-
const input = parametros
|
|
2361
|
-
.split(",")
|
|
2362
|
-
.map((item) => item.trim())
|
|
2363
|
-
.filter(Boolean)
|
|
2364
|
-
.filter((item) => !item.startsWith("self") && !item.startsWith("cls"))
|
|
2365
|
-
.flatMap((item) => {
|
|
2366
|
-
const [nome, tipo] = item.split(":").map((parte) => parte.trim());
|
|
2367
|
-
const obrigatorio = !item.includes("=");
|
|
2368
|
-
return expandirCamposPython(nome, tipo, tiposGlobais, entitiesRef, enumsRef, obrigatorio);
|
|
2369
|
-
});
|
|
2370
|
-
const output = retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
2371
|
-
? []
|
|
2372
|
-
: deduplicarCampos(expandirCamposPython("resultado", retorno, tiposGlobais, entitiesRef, enumsRef, false));
|
|
2373
|
-
tasks.push({
|
|
2374
|
-
nome: paraSnakeCase(nomeFuncao),
|
|
2375
|
-
resumo: `Task importada automaticamente de ${relacao}#${nomeFuncao}.`,
|
|
2376
|
-
input: deduplicarCampos(input),
|
|
2377
|
-
output,
|
|
2378
|
-
errors: extrairErrosPython(trecho),
|
|
2379
|
-
effects: descreverEfeitosPorHeuristica(trecho),
|
|
2380
|
-
impl: { py: caminhoImplPython(diretorio, arquivo, nomeFuncao) },
|
|
2381
|
-
origemArquivo: relacao,
|
|
2382
|
-
origemSimbolo: nomeFuncao,
|
|
2383
|
-
});
|
|
2384
|
-
}
|
|
2385
|
-
const classRegex = /^class\s+(\w+)(?:\(([^)]*)\))?:\n((?:^[ \t].*(?:\n|$))*)/gm;
|
|
2386
|
-
for (const match of texto.matchAll(classRegex)) {
|
|
2387
|
-
const nomeClasse = match[1];
|
|
2388
|
-
const bases = match[2] ?? "";
|
|
2389
|
-
const corpo = match[3];
|
|
2390
|
-
if (/(BaseModel|Enum|StrEnum)/.test(bases)) {
|
|
2391
|
-
continue;
|
|
2392
|
-
}
|
|
2393
|
-
for (const metodo of corpo.matchAll(/^\s{4}(?:async\s+def|def)\s+(\w+)\(([^)]*)\)(?:\s*->\s*([^:]+))?:/gm)) {
|
|
2394
|
-
const nomeMetodo = metodo[1];
|
|
2395
|
-
if (nomeMetodo.startsWith("_")) {
|
|
2396
|
-
continue;
|
|
2397
|
-
}
|
|
2398
|
-
const parametros = metodo[2];
|
|
2399
|
-
const retorno = metodo[3]?.trim();
|
|
2400
|
-
const input = parametros
|
|
2401
|
-
.split(",")
|
|
2402
|
-
.map((item) => item.trim())
|
|
2403
|
-
.filter(Boolean)
|
|
2404
|
-
.filter((item) => !item.startsWith("self") && !item.startsWith("cls"))
|
|
2405
|
-
.flatMap((item) => {
|
|
2406
|
-
const [nome, tipo] = item.split(":").map((parte) => parte.trim());
|
|
2407
|
-
const obrigatorio = !item.includes("=");
|
|
2408
|
-
return expandirCamposPython(nome, tipo, tiposGlobais, entitiesRef, enumsRef, obrigatorio);
|
|
2409
|
-
});
|
|
2410
|
-
const output = retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
2411
|
-
? []
|
|
2412
|
-
: deduplicarCampos(expandirCamposPython("resultado", retorno, tiposGlobais, entitiesRef, enumsRef, false));
|
|
2413
|
-
tasks.push({
|
|
2414
|
-
nome: paraSnakeCase(nomeMetodo),
|
|
2415
|
-
resumo: `Task importada automaticamente de ${relacao}#${nomeClasse}.${nomeMetodo}.`,
|
|
2416
|
-
input: deduplicarCampos(input),
|
|
2417
|
-
output,
|
|
2418
|
-
errors: extrairErrosPython(corpo),
|
|
2419
|
-
effects: descreverEfeitosPorHeuristica(corpo),
|
|
2420
|
-
impl: { py: caminhoImplPython(diretorio, arquivo, `${nomeClasse}.${nomeMetodo}`) },
|
|
2421
|
-
origemArquivo: relacao,
|
|
2422
|
-
origemSimbolo: `${nomeClasse}.${nomeMetodo}`,
|
|
2423
|
-
});
|
|
2424
|
-
}
|
|
2425
|
-
}
|
|
2426
|
-
if (!tasks.length && !routes.length) {
|
|
2427
|
-
continue;
|
|
2428
|
-
}
|
|
2429
|
-
const { entities, enums } = criarEntidadesPython(tiposGlobais, entitiesRef, enumsRef);
|
|
2430
|
-
sincronizarRotasComTasks(routes, tasks);
|
|
2431
|
-
modulos.set(nomeModulo, {
|
|
2432
|
-
nome: nomeModulo,
|
|
2433
|
-
resumo: `Rascunho Sema importado automaticamente de ${relacao}.`,
|
|
2434
|
-
tasks: deduplicarTarefas(tasks),
|
|
2435
|
-
routes: deduplicarRotas(routes),
|
|
2436
|
-
entities,
|
|
2437
|
-
enums,
|
|
2438
|
-
});
|
|
2439
|
-
}
|
|
2440
|
-
return [...modulos.values()];
|
|
2441
|
-
}
|
|
2442
|
-
async function importarDartBase(diretorio, namespaceBase) {
|
|
2443
|
-
const arquivos = (await listarArquivosRecursivos(diretorio, [".dart"]))
|
|
2444
|
-
.filter((arquivo) => !arquivo.endsWith(".g.dart") && !arquivo.endsWith(".freezed.dart"));
|
|
2445
|
-
const modulos = [];
|
|
2446
|
-
for (const arquivo of arquivos) {
|
|
2447
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2448
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2449
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2450
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2451
|
-
const tasks = [];
|
|
2452
|
-
for (const match of texto.matchAll(/(?:Future<([^\n]+)>|([\w?<>.,\s]+))\s+(\w+)\(([^)]*)\)\s*(?:async\s*)?\{/g)) {
|
|
2453
|
-
const retorno = (match[1] ?? match[2] ?? "").trim();
|
|
2454
|
-
const nome = match[3];
|
|
2455
|
-
if (["build", "toString", "hashCode"].includes(nome)) {
|
|
2456
|
-
continue;
|
|
2457
|
-
}
|
|
2458
|
-
const parametros = match[4];
|
|
2459
|
-
const input = parametros
|
|
2460
|
-
.split(",")
|
|
2461
|
-
.map((item) => item.trim())
|
|
2462
|
-
.filter(Boolean)
|
|
2463
|
-
.map((item) => item.replace(/^(required|final)\s+/g, ""))
|
|
2464
|
-
.map((item) => {
|
|
2465
|
-
const partes = item.split(/\s+/);
|
|
2466
|
-
const nomeParametro = partes.at(-1) ?? "param";
|
|
2467
|
-
const tipoParametro = partes.length > 1 ? partes.slice(0, -1).join(" ") : undefined;
|
|
2468
|
-
return {
|
|
2469
|
-
nome: paraSnakeCase(nomeParametro),
|
|
2470
|
-
tipo: mapearTipoPrimitivo(tipoParametro ?? "Json"),
|
|
2471
|
-
obrigatorio: item.includes("required"),
|
|
2472
|
-
};
|
|
2473
|
-
});
|
|
2474
|
-
const output = retorno && mapearTipoPrimitivo(retorno) === "Vazio"
|
|
2475
|
-
? []
|
|
2476
|
-
: [{ nome: "resultado", tipo: mapearTipoPrimitivo(retorno || "Json"), obrigatorio: false }];
|
|
2477
|
-
tasks.push({
|
|
2478
|
-
nome: paraSnakeCase(nome),
|
|
2479
|
-
resumo: `Task importada automaticamente de ${relacao}#${nome}.`,
|
|
2480
|
-
input,
|
|
2481
|
-
output,
|
|
2482
|
-
errors: [],
|
|
2483
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2484
|
-
impl: { dart: caminhoImplDart(diretorio, arquivo, nome) },
|
|
2485
|
-
origemArquivo: relacao,
|
|
2486
|
-
origemSimbolo: nome,
|
|
2487
|
-
});
|
|
2488
|
-
}
|
|
2489
|
-
if (tasks.length === 0) {
|
|
2490
|
-
continue;
|
|
2491
|
-
}
|
|
2492
|
-
modulos.push({
|
|
2493
|
-
nome: nomeModulo,
|
|
2494
|
-
resumo: `Rascunho Sema importado automaticamente de ${relacao}.`,
|
|
2495
|
-
tasks: deduplicarTarefas(tasks),
|
|
2496
|
-
routes: [],
|
|
2497
|
-
entities: [],
|
|
2498
|
-
enums: [],
|
|
2499
|
-
});
|
|
2500
|
-
}
|
|
2501
|
-
return modulos;
|
|
2502
|
-
}
|
|
2503
|
-
function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = [], databases = []) {
|
|
2504
|
-
sincronizarRotasComTasks(routes, tasks);
|
|
2505
|
-
return {
|
|
2506
|
-
nome,
|
|
2507
|
-
resumo,
|
|
2508
|
-
tasks: deduplicarTarefas(tasks),
|
|
2509
|
-
routes: deduplicarRotas(routes),
|
|
2510
|
-
entities: [],
|
|
2511
|
-
enums: [],
|
|
2512
|
-
databases: deduplicarDatabases(databases),
|
|
2513
|
-
vinculos: deduplicarVinculos(vinculos),
|
|
2514
|
-
};
|
|
2515
|
-
}
|
|
2516
|
-
function acumularModuloImportado(modulos, modulo) {
|
|
2517
|
-
const existente = modulos.get(modulo.nome);
|
|
2518
|
-
if (!existente) {
|
|
2519
|
-
modulos.set(modulo.nome, modulo);
|
|
2520
|
-
return;
|
|
2521
|
-
}
|
|
2522
|
-
existente.tasks = deduplicarTarefas([...existente.tasks, ...modulo.tasks]);
|
|
2523
|
-
existente.routes = deduplicarRotas([...existente.routes, ...modulo.routes]);
|
|
2524
|
-
existente.entities = deduplicarEntidades([...existente.entities, ...modulo.entities]);
|
|
2525
|
-
existente.enums = deduplicarEnums([...existente.enums, ...modulo.enums]);
|
|
2526
|
-
existente.databases = deduplicarDatabases([...(existente.databases ?? []), ...(modulo.databases ?? [])]);
|
|
2527
|
-
existente.vinculos = deduplicarVinculos([...(existente.vinculos ?? []), ...(modulo.vinculos ?? [])]);
|
|
2528
|
-
}
|
|
2529
|
-
function selecionarSimbolosPreferidos(simbolos) {
|
|
2530
|
-
const mapa = new Map();
|
|
2531
|
-
for (const simbolo of simbolos) {
|
|
2532
|
-
const chave = simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo;
|
|
2533
|
-
const existente = mapa.get(chave);
|
|
2534
|
-
if (!existente) {
|
|
2535
|
-
mapa.set(chave, simbolo);
|
|
2536
|
-
continue;
|
|
2537
|
-
}
|
|
2538
|
-
const pontuacaoAtual = simbolo.simbolo.split(".").length;
|
|
2539
|
-
const pontuacaoExistente = existente.simbolo.split(".").length;
|
|
2540
|
-
if (pontuacaoAtual > pontuacaoExistente) {
|
|
2541
|
-
mapa.set(chave, simbolo);
|
|
2542
|
-
}
|
|
2543
|
-
}
|
|
2544
|
-
return [...mapa.values()];
|
|
2545
|
-
}
|
|
2546
|
-
async function existeArquivo(caminho) {
|
|
2547
|
-
try {
|
|
2548
|
-
await access(caminho);
|
|
2549
|
-
return true;
|
|
2550
|
-
}
|
|
2551
|
-
catch {
|
|
2552
|
-
return false;
|
|
2553
|
-
}
|
|
2554
|
-
}
|
|
2555
|
-
async function resolverArquivoRustParaSimbolo(diretorio, relacaoFonte, simbolo) {
|
|
2556
|
-
const partes = simbolo.split(".").filter(Boolean);
|
|
2557
|
-
if (partes.length <= 1) {
|
|
2558
|
-
return path.join(diretorio, relacaoFonte);
|
|
2559
|
-
}
|
|
2560
|
-
const moduloPartes = partes.slice(0, -1);
|
|
2561
|
-
const baseAtual = path.dirname(relacaoFonte);
|
|
2562
|
-
const candidatos = [
|
|
2563
|
-
path.join(baseAtual, ...moduloPartes) + ".rs",
|
|
2564
|
-
path.join(baseAtual, ...moduloPartes, "mod.rs"),
|
|
2565
|
-
path.join("src", ...moduloPartes) + ".rs",
|
|
2566
|
-
path.join("src", ...moduloPartes, "mod.rs"),
|
|
2567
|
-
];
|
|
2568
|
-
for (const candidato of candidatos) {
|
|
2569
|
-
const absoluto = path.join(diretorio, candidato);
|
|
2570
|
-
if (await existeArquivo(absoluto)) {
|
|
2571
|
-
return absoluto;
|
|
2572
|
-
}
|
|
2573
|
-
}
|
|
2574
|
-
return path.join(diretorio, relacaoFonte);
|
|
2575
|
-
}
|
|
2576
|
-
async function importarDotnetBase(diretorio, namespaceBase) {
|
|
2577
|
-
const arquivos = (await listarArquivosRecursivos(diretorio, [".cs"]))
|
|
2578
|
-
.filter((arquivo) => !/(^|[\\/])(bin|obj|Test[s]?)([\\/]|$)/i.test(arquivo));
|
|
2579
|
-
const modulos = new Map();
|
|
2580
|
-
for (const arquivo of arquivos) {
|
|
2581
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2582
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2583
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao, { preservarUltimo: true, snakeCaseUltimo: true });
|
|
2584
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2585
|
-
const tasks = [];
|
|
2586
|
-
const routes = [];
|
|
2587
|
-
for (const simbolo of extrairSimbolosDotnet(texto)) {
|
|
2588
|
-
const taskNome = paraSnakeCase(simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo);
|
|
2589
|
-
tasks.push({
|
|
2590
|
-
nome: taskNome,
|
|
2591
|
-
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2592
|
-
input: simbolo.parametros.map((parametro) => ({
|
|
2593
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2594
|
-
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2595
|
-
obrigatorio: parametro.obrigatorio,
|
|
2596
|
-
})),
|
|
2597
|
-
output: criarCampoResultadoBackend(simbolo.retorno),
|
|
2598
|
-
errors: [],
|
|
2599
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2600
|
-
impl: { cs: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo, { snakeCaseUltimoArquivo: true }) },
|
|
2601
|
-
origemArquivo: relacao,
|
|
2602
|
-
origemSimbolo: simbolo.simbolo,
|
|
2603
|
-
});
|
|
2604
|
-
}
|
|
2605
|
-
for (const rota of extrairRotasDotnet(texto)) {
|
|
2606
|
-
const taskNome = paraSnakeCase(rota.simbolo.split(".").at(-1) ?? rota.simbolo);
|
|
2607
|
-
const output = criarCampoResultadoBackend(rota.retorno);
|
|
2608
|
-
tasks.push({
|
|
2609
|
-
nome: taskNome,
|
|
2610
|
-
resumo: `Task HTTP ASP.NET Core importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2611
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2612
|
-
output,
|
|
2613
|
-
errors: [],
|
|
2614
|
-
effects: [{ categoria: "consulta", alvo: "http", criticidade: "media" }],
|
|
2615
|
-
impl: { cs: caminhoImplGenerico(diretorio, arquivo, rota.simbolo, { snakeCaseUltimoArquivo: true }) },
|
|
2616
|
-
origemArquivo: relacao,
|
|
2617
|
-
origemSimbolo: rota.simbolo,
|
|
2618
|
-
});
|
|
2619
|
-
routes.push({
|
|
2620
|
-
nome: `${taskNome}_publico`,
|
|
2621
|
-
resumo: `Rota ASP.NET Core importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2622
|
-
metodo: rota.metodo,
|
|
2623
|
-
caminho: rota.caminho,
|
|
2624
|
-
task: taskNome,
|
|
2625
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2626
|
-
output,
|
|
2627
|
-
errors: [],
|
|
2628
|
-
});
|
|
2629
|
-
}
|
|
2630
|
-
if (tasks.length === 0 && routes.length === 0) {
|
|
2631
|
-
continue;
|
|
2632
|
-
}
|
|
2633
|
-
acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2634
|
-
}
|
|
2635
|
-
return [...modulos.values()];
|
|
2636
|
-
}
|
|
2637
|
-
async function importarJavaBase(diretorio, namespaceBase) {
|
|
2638
|
-
const arquivos = (await listarArquivosRecursivos(diretorio, [".java"]))
|
|
2639
|
-
.filter((arquivo) => !/(^|[\\/])(target|build|out|Test[s]?)([\\/]|$)/i.test(arquivo));
|
|
2640
|
-
const modulos = new Map();
|
|
2641
|
-
for (const arquivo of arquivos) {
|
|
2642
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2643
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2644
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao, { preservarUltimo: true, snakeCaseUltimo: true });
|
|
2645
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2646
|
-
const tasks = [];
|
|
2647
|
-
const routes = [];
|
|
2648
|
-
for (const simbolo of extrairSimbolosJava(texto)) {
|
|
2649
|
-
const taskNome = paraSnakeCase(simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo);
|
|
2650
|
-
tasks.push({
|
|
2651
|
-
nome: taskNome,
|
|
2652
|
-
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2653
|
-
input: simbolo.parametros.map((parametro) => ({
|
|
2654
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2655
|
-
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2656
|
-
obrigatorio: parametro.obrigatorio,
|
|
2657
|
-
})),
|
|
2658
|
-
output: criarCampoResultadoBackend(simbolo.retorno),
|
|
2659
|
-
errors: [],
|
|
2660
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2661
|
-
impl: { java: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo, { snakeCaseUltimoArquivo: true }) },
|
|
2662
|
-
origemArquivo: relacao,
|
|
2663
|
-
origemSimbolo: simbolo.simbolo,
|
|
2664
|
-
});
|
|
2665
|
-
}
|
|
2666
|
-
for (const rota of extrairRotasJava(texto)) {
|
|
2667
|
-
const taskNome = paraSnakeCase(rota.simbolo.split(".").at(-1) ?? rota.simbolo);
|
|
2668
|
-
const output = criarCampoResultadoBackend(rota.retorno);
|
|
2669
|
-
tasks.push({
|
|
2670
|
-
nome: taskNome,
|
|
2671
|
-
resumo: `Task HTTP Spring Boot importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2672
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2673
|
-
output,
|
|
2674
|
-
errors: [],
|
|
2675
|
-
effects: [{ categoria: "consulta", alvo: "http", criticidade: "media" }],
|
|
2676
|
-
impl: { java: caminhoImplGenerico(diretorio, arquivo, rota.simbolo, { snakeCaseUltimoArquivo: true }) },
|
|
2677
|
-
origemArquivo: relacao,
|
|
2678
|
-
origemSimbolo: rota.simbolo,
|
|
2679
|
-
});
|
|
2680
|
-
routes.push({
|
|
2681
|
-
nome: `${taskNome}_publico`,
|
|
2682
|
-
resumo: `Rota Spring Boot importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2683
|
-
metodo: rota.metodo,
|
|
2684
|
-
caminho: rota.caminho,
|
|
2685
|
-
task: taskNome,
|
|
2686
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2687
|
-
output,
|
|
2688
|
-
errors: [],
|
|
2689
|
-
});
|
|
2690
|
-
}
|
|
2691
|
-
if (tasks.length === 0 && routes.length === 0) {
|
|
2692
|
-
continue;
|
|
2693
|
-
}
|
|
2694
|
-
acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2695
|
-
}
|
|
2696
|
-
return [...modulos.values()];
|
|
2697
|
-
}
|
|
2698
|
-
async function importarGoBase(diretorio, namespaceBase) {
|
|
2699
|
-
const arquivos = await listarArquivosRecursivos(diretorio, [".go"]);
|
|
2700
|
-
const modulos = new Map();
|
|
2701
|
-
for (const arquivo of arquivos) {
|
|
2702
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2703
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2704
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2705
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2706
|
-
const tasks = [];
|
|
2707
|
-
const routes = [];
|
|
2708
|
-
for (const simbolo of extrairSimbolosGo(texto)) {
|
|
2709
|
-
const taskNome = paraSnakeCase(simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo);
|
|
2710
|
-
tasks.push({
|
|
2711
|
-
nome: taskNome,
|
|
2712
|
-
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2713
|
-
input: simbolo.parametros.map((parametro) => ({
|
|
2714
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2715
|
-
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2716
|
-
obrigatorio: parametro.obrigatorio,
|
|
2717
|
-
})),
|
|
2718
|
-
output: criarCampoResultadoBackend(simbolo.retorno),
|
|
2719
|
-
errors: [],
|
|
2720
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2721
|
-
impl: { go: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo) },
|
|
2722
|
-
origemArquivo: relacao,
|
|
2723
|
-
origemSimbolo: simbolo.simbolo,
|
|
2724
|
-
});
|
|
2725
|
-
}
|
|
2726
|
-
for (const rota of extrairRotasGo(texto)) {
|
|
2727
|
-
const taskNome = paraSnakeCase(rota.simbolo.split(".").at(-1) ?? rota.simbolo);
|
|
2728
|
-
tasks.push({
|
|
2729
|
-
nome: taskNome,
|
|
2730
|
-
resumo: `Task HTTP Go importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2731
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2732
|
-
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2733
|
-
errors: [],
|
|
2734
|
-
effects: [{ categoria: "consulta", alvo: "http", criticidade: "media" }],
|
|
2735
|
-
impl: { go: caminhoImplGenerico(diretorio, arquivo, rota.simbolo) },
|
|
2736
|
-
origemArquivo: relacao,
|
|
2737
|
-
origemSimbolo: rota.simbolo,
|
|
2738
|
-
});
|
|
2739
|
-
routes.push({
|
|
2740
|
-
nome: `${taskNome}_publico`,
|
|
2741
|
-
resumo: `Rota Go importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2742
|
-
metodo: rota.metodo,
|
|
2743
|
-
caminho: rota.caminho,
|
|
2744
|
-
task: taskNome,
|
|
2745
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2746
|
-
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2747
|
-
errors: [],
|
|
2748
|
-
});
|
|
2749
|
-
}
|
|
2750
|
-
if (tasks.length === 0 && routes.length === 0) {
|
|
2751
|
-
continue;
|
|
2752
|
-
}
|
|
2753
|
-
modulos.set(nomeModulo, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2754
|
-
}
|
|
2755
|
-
return [...modulos.values()];
|
|
2756
|
-
}
|
|
2757
|
-
async function importarRustBase(diretorio, namespaceBase) {
|
|
2758
|
-
const arquivos = await listarArquivosRecursivos(diretorio, [".rs"]);
|
|
2759
|
-
const modulos = new Map();
|
|
2760
|
-
for (const arquivo of arquivos) {
|
|
2761
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2762
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2763
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2764
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2765
|
-
const tasks = [];
|
|
2766
|
-
const routes = [];
|
|
2767
|
-
for (const simbolo of extrairSimbolosRust(texto)) {
|
|
2768
|
-
const taskNome = paraSnakeCase(simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo);
|
|
2769
|
-
tasks.push({
|
|
2770
|
-
nome: taskNome,
|
|
2771
|
-
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2772
|
-
input: simbolo.parametros.map((parametro) => ({
|
|
2773
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2774
|
-
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2775
|
-
obrigatorio: parametro.obrigatorio,
|
|
2776
|
-
})),
|
|
2777
|
-
output: criarCampoResultadoBackend(simbolo.retorno),
|
|
2778
|
-
errors: [],
|
|
2779
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2780
|
-
impl: { rust: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo) },
|
|
2781
|
-
origemArquivo: relacao,
|
|
2782
|
-
origemSimbolo: simbolo.simbolo,
|
|
2783
|
-
});
|
|
2784
|
-
}
|
|
2785
|
-
acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2786
|
-
for (const rota of extrairRotasRust(texto)) {
|
|
2787
|
-
const simboloLimpo = rota.simbolo.replace(/::/g, ".");
|
|
2788
|
-
const nomeSimbolo = simboloLimpo.split(".").at(-1) ?? simboloLimpo;
|
|
2789
|
-
const arquivoAlvo = await resolverArquivoRustParaSimbolo(diretorio, relacao, simboloLimpo);
|
|
2790
|
-
const relacaoAlvo = path.relative(diretorio, arquivoAlvo);
|
|
2791
|
-
const moduloAlvo = [namespaceBase, ...inferirContextoPorArquivo(relacaoAlvo)].join(".");
|
|
2792
|
-
const taskNome = paraSnakeCase(rota.simbolo.split(".").at(-1) ?? rota.simbolo);
|
|
2793
|
-
const task = {
|
|
2794
|
-
nome: taskNome,
|
|
2795
|
-
resumo: `Task HTTP Axum importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2796
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2797
|
-
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2798
|
-
errors: [],
|
|
2799
|
-
effects: [{ categoria: "consulta", alvo: "http", criticidade: "media" }],
|
|
2800
|
-
impl: { rust: caminhoImplGenerico(diretorio, arquivoAlvo, nomeSimbolo) },
|
|
2801
|
-
origemArquivo: relacaoAlvo,
|
|
2802
|
-
origemSimbolo: nomeSimbolo,
|
|
2803
|
-
};
|
|
2804
|
-
const route = {
|
|
2805
|
-
nome: `${taskNome}_publico`,
|
|
2806
|
-
resumo: `Rota Axum importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2807
|
-
metodo: rota.metodo,
|
|
2808
|
-
caminho: rota.caminho,
|
|
2809
|
-
task: taskNome,
|
|
2810
|
-
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2811
|
-
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2812
|
-
errors: [],
|
|
2813
|
-
};
|
|
2814
|
-
acumularModuloImportado(modulos, criarModuloImportadoSimples(moduloAlvo, `Rascunho Sema importado automaticamente de ${relacaoAlvo}.`, [task], [route], [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2815
|
-
}
|
|
2816
|
-
}
|
|
2817
|
-
return [...modulos.values()];
|
|
2818
|
-
}
|
|
2819
|
-
async function importarCppBase(diretorio, namespaceBase) {
|
|
2820
|
-
const arquivos = (await listarArquivosRecursivos(diretorio, [".cpp", ".cc", ".cxx", ".hpp", ".h"]))
|
|
2821
|
-
.filter((arquivo) => !/(^|[\\/])(windows|linux|macos|runner|flutter|ephemeral|build|vendor)([\\/]|$)/i.test(arquivo));
|
|
2822
|
-
const modulos = new Map();
|
|
2823
|
-
for (const arquivo of arquivos) {
|
|
2824
|
-
const texto = await readFile(arquivo, "utf8");
|
|
2825
|
-
const relacao = path.relative(diretorio, arquivo);
|
|
2826
|
-
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2827
|
-
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2828
|
-
const tasks = [];
|
|
2829
|
-
for (const simbolo of selecionarSimbolosPreferidos(extrairSimbolosCpp(texto))) {
|
|
2830
|
-
const taskNome = paraSnakeCase(simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo);
|
|
2831
|
-
tasks.push({
|
|
2832
|
-
nome: taskNome,
|
|
2833
|
-
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2834
|
-
input: simbolo.parametros.map((parametro) => ({
|
|
2835
|
-
nome: paraSnakeCase(parametro.nome),
|
|
2836
|
-
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2837
|
-
obrigatorio: parametro.obrigatorio,
|
|
2838
|
-
})),
|
|
2839
|
-
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2840
|
-
errors: [],
|
|
2841
|
-
effects: descreverEfeitosPorHeuristica(texto),
|
|
2842
|
-
impl: { cpp: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo) },
|
|
2843
|
-
origemArquivo: relacao,
|
|
2844
|
-
origemSimbolo: simbolo.simbolo,
|
|
2845
|
-
});
|
|
2846
|
-
}
|
|
2847
|
-
if (tasks.length === 0) {
|
|
2848
|
-
continue;
|
|
2849
|
-
}
|
|
2850
|
-
acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, [], [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2851
|
-
}
|
|
2852
|
-
return [...modulos.values()];
|
|
2853
|
-
}
|
|
2854
|
-
export async function importarProjetoLegado(fonte, diretorio, namespaceBase) {
|
|
2855
|
-
const base = path.resolve(diretorio);
|
|
2856
|
-
const namespace = inferirNamespaceBase(base, namespaceBase);
|
|
2857
|
-
let modulos = [];
|
|
2858
|
-
if (fonte === "nestjs") {
|
|
2859
|
-
modulos = await importarTypeScriptBase(base, namespace, true);
|
|
2860
|
-
}
|
|
2861
|
-
else if (fonte === "nextjs") {
|
|
2862
|
-
modulos = await importarNextJsBase(base, namespace);
|
|
2863
|
-
}
|
|
2864
|
-
else if (fonte === "nextjs-consumer") {
|
|
2865
|
-
modulos = await importarNextJsConsumerBase(base, namespace);
|
|
2866
|
-
}
|
|
2867
|
-
else if (fonte === "react-vite-consumer") {
|
|
2868
|
-
modulos = await importarReactViteConsumerBase(base, namespace);
|
|
2869
|
-
}
|
|
2870
|
-
else if (fonte === "angular-consumer") {
|
|
2871
|
-
modulos = await importarAngularConsumerBase(base, namespace);
|
|
2872
|
-
}
|
|
2873
|
-
else if (fonte === "flutter-consumer") {
|
|
2874
|
-
modulos = await importarFlutterConsumerBase(base, namespace);
|
|
2875
|
-
}
|
|
2876
|
-
else if (fonte === "firebase") {
|
|
2877
|
-
modulos = await importarFirebaseBase(base, namespace);
|
|
2878
|
-
}
|
|
2879
|
-
else if (fonte === "typescript") {
|
|
2880
|
-
modulos = await importarTypeScriptBase(base, namespace, false);
|
|
2881
|
-
}
|
|
2882
|
-
else if (fonte === "fastapi") {
|
|
2883
|
-
modulos = await importarPythonBase(base, namespace, "fastapi");
|
|
2884
|
-
}
|
|
2885
|
-
else if (fonte === "flask") {
|
|
2886
|
-
modulos = await importarPythonBase(base, namespace, "flask");
|
|
2887
|
-
}
|
|
2888
|
-
else if (fonte === "python") {
|
|
2889
|
-
modulos = await importarPythonBase(base, namespace, "nenhum");
|
|
2890
|
-
}
|
|
2891
|
-
else if (fonte === "dart") {
|
|
2892
|
-
modulos = await importarDartBase(base, namespace);
|
|
2893
|
-
}
|
|
2894
|
-
else if (fonte === "dotnet") {
|
|
2895
|
-
modulos = await importarDotnetBase(base, namespace);
|
|
2896
|
-
}
|
|
2897
|
-
else if (fonte === "java") {
|
|
2898
|
-
modulos = await importarJavaBase(base, namespace);
|
|
2899
|
-
}
|
|
2900
|
-
else if (fonte === "go") {
|
|
2901
|
-
modulos = await importarGoBase(base, namespace);
|
|
2902
|
-
}
|
|
2903
|
-
else if (fonte === "rust") {
|
|
2904
|
-
modulos = await importarRustBase(base, namespace);
|
|
2905
|
-
}
|
|
2906
|
-
else if (fonte === "cpp") {
|
|
2907
|
-
modulos = await importarCppBase(base, namespace);
|
|
2908
|
-
}
|
|
2909
|
-
const arquivos = [];
|
|
2910
|
-
for (const modulo of modulos) {
|
|
2911
|
-
const bruto = moduloParaCodigo(modulo);
|
|
2912
|
-
const formatado = await formatarModuloImportado(bruto, `${modulo.nome}.sema`);
|
|
2913
|
-
arquivos.push(montarArquivoImportado(modulo, namespace, formatado));
|
|
2914
|
-
}
|
|
2915
|
-
const diagnosticos = compilarProjeto(arquivos.map((arquivo) => ({
|
|
2916
|
-
caminho: path.join(base, ".tmp", "importado", arquivo.caminhoRelativo),
|
|
2917
|
-
codigo: arquivo.conteudo,
|
|
2918
|
-
}))).diagnosticos;
|
|
2919
|
-
return {
|
|
2920
|
-
fonte,
|
|
2921
|
-
diretorio: base,
|
|
2922
|
-
namespaceBase: namespace,
|
|
2923
|
-
arquivos,
|
|
2924
|
-
diagnosticos,
|
|
2925
|
-
};
|
|
2926
|
-
}
|
|
2927
|
-
export function resumoImportacao(resultado) {
|
|
2928
|
-
return {
|
|
2929
|
-
modulos: resultado.arquivos.length,
|
|
2930
|
-
tarefas: resultado.arquivos.reduce((total, arquivo) => total + arquivo.tarefas, 0),
|
|
2931
|
-
rotas: resultado.arquivos.reduce((total, arquivo) => total + arquivo.rotas, 0),
|
|
2932
|
-
entidades: resultado.arquivos.reduce((total, arquivo) => total + arquivo.entidades, 0),
|
|
2933
|
-
enums: resultado.arquivos.reduce((total, arquivo) => total + arquivo.enums, 0),
|
|
2934
|
-
databases: resultado.arquivos.reduce((total, arquivo) => total + arquivo.databases, 0),
|
|
2935
|
-
diagnosticos: resultado.diagnosticos.length,
|
|
2936
|
-
sucesso: !temErros(resultado.diagnosticos),
|
|
2937
|
-
};
|
|
2938
|
-
}
|
|
1
|
+
// SEMA-GOVERNED: sema.governanca_ia_contexto
|
|
2
|
+
// Descricao: CLI particionada; consulte contratos/sema/governanca_ia_contexto.sema antes de editar.
|
|
3
|
+
export * from "./importador.part01.js";
|
|
4
|
+
export * from "./importador.part02.js";
|
|
5
|
+
export * from "./importador.part03.js";
|
|
6
|
+
export * from "./importador.part04.js";
|
|
7
|
+
export * from "./importador.part05.js";
|
|
8
|
+
export * from "./importador.part06.js";
|
|
9
|
+
export * from "./importador.part07.js";
|
|
10
|
+
export * from "./importador.part08.js";
|
|
11
|
+
export * from "./importador.part09.js";
|
|
2939
12
|
//# sourceMappingURL=importador.js.map
|