@semacode/cli 1.5.9 → 1.5.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/SEMA_BRIEF.curto.txt +3 -3
- package/SEMA_BRIEF.md +5 -5
- package/SEMA_BRIEF.micro.txt +2 -2
- package/SEMA_INDEX.json +50 -32
- package/dist/drift.d.ts +3 -3
- package/dist/drift.js +111 -5
- package/dist/drift.js.map +1 -1
- package/dist/importador.d.ts +1 -1
- package/dist/importador.js +200 -1
- package/dist/importador.js.map +1 -1
- package/dist/index.js +13 -5
- package/dist/index.js.map +1 -1
- package/dist/lua-symbols.d.ts +6 -4
- package/dist/lua-symbols.js +74 -54
- package/dist/lua-symbols.js.map +1 -1
- package/dist/php-symbols.d.ts +24 -0
- package/dist/php-symbols.js +375 -0
- package/dist/php-symbols.js.map +1 -0
- package/dist/projeto.js +20 -0
- package/dist/projeto.js.map +1 -1
- package/dist/tipos.d.ts +1 -1
- package/docs/AGENT_STARTER.md +3 -3
- package/docs/cli.md +5 -1
- package/docs/env.md +3 -3
- package/docs/fluxo-pratico-ia-sema.md +1 -1
- package/docs/integracao-com-ia.md +2 -0
- package/docs/mcp.md +2 -0
- package/docs/sintaxe.md +65 -0
- package/node_modules/@sema/gerador-css/package.json +1 -1
- package/node_modules/@sema/gerador-dart/package.json +1 -1
- package/node_modules/@sema/gerador-html/package.json +1 -1
- package/node_modules/@sema/gerador-javascript/package.json +1 -1
- package/node_modules/@sema/gerador-lua/package.json +1 -1
- package/node_modules/@sema/gerador-python/package.json +1 -1
- package/node_modules/@sema/gerador-typescript/package.json +1 -1
- package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +8 -0
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +3 -3
- package/node_modules/@sema/nucleo/dist/parser/parser.js +4 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +2 -2
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +5 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
- package/node_modules/@sema/nucleo/package.json +1 -1
- package/node_modules/@sema/padroes/package.json +1 -1
- package/package.json +10 -10
package/dist/importador.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type Diagnostico } from "@sema/nucleo";
|
|
2
|
-
export type FonteImportacao = "nestjs" | "fastapi" | "flask" | "nextjs" | "nextjs-consumer" | "react-vite-consumer" | "angular-consumer" | "flutter-consumer" | "firebase" | "typescript" | "python" | "dart" | "dotnet" | "java" | "go" | "rust" | "cpp";
|
|
2
|
+
export type FonteImportacao = "nestjs" | "fastapi" | "flask" | "nextjs" | "nextjs-consumer" | "react-vite-consumer" | "angular-consumer" | "flutter-consumer" | "firebase" | "typescript" | "python" | "dart" | "lua" | "php" | "dotnet" | "java" | "go" | "rust" | "cpp";
|
|
3
3
|
export interface ArquivoImportado {
|
|
4
4
|
caminhoRelativo: string;
|
|
5
5
|
conteudo: string;
|
package/dist/importador.js
CHANGED
|
@@ -7,6 +7,8 @@ import { extrairSimbolosCpp } from "./cpp-symbols.js";
|
|
|
7
7
|
import { extrairRotasDotnet, extrairSimbolosDotnet } from "./dotnet-http.js";
|
|
8
8
|
import { extrairRotasGo, extrairSimbolosGo } from "./go-http.js";
|
|
9
9
|
import { extrairRotasJava, extrairSimbolosJava } from "./java-http.js";
|
|
10
|
+
import { extrairSimbolosLua } from "./lua-symbols.js";
|
|
11
|
+
import { extrairRotasPhp, extrairSimbolosPhp } from "./php-symbols.js";
|
|
10
12
|
import { extrairParametrosCaminhoFlask, extrairRotasFlaskDecoradas } from "./python-http.js";
|
|
11
13
|
import { extrairRotasRust, extrairSimbolosRust } from "./rust-http.js";
|
|
12
14
|
import { extrairRotasTypeScriptHttp, inferirSemanticaHandlerTypeScriptHttp, localizarExportacaoTypeScriptHttp, } from "./typescript-http.js";
|
|
@@ -245,6 +247,7 @@ function limparTipoBackend(tipo) {
|
|
|
245
247
|
}
|
|
246
248
|
return tipo
|
|
247
249
|
.trim()
|
|
250
|
+
.replace(/^\?/, "")
|
|
248
251
|
.replace(/^Task<(.+)>$/i, "$1")
|
|
249
252
|
.replace(/^ActionResult<(.+)>$/i, "$1")
|
|
250
253
|
.replace(/^IActionResult$/i, "Json")
|
|
@@ -258,7 +261,10 @@ function limparTipoBackend(tipo) {
|
|
|
258
261
|
.replace(/^Vec<(.+)>$/i, "Json")
|
|
259
262
|
.replace(/^List<(.+)>$/i, "Json")
|
|
260
263
|
.replace(/^Map<(.+)>$/i, "Json")
|
|
261
|
-
.replace(/^Dictionary<(.+)>$/i, "Json")
|
|
264
|
+
.replace(/^Dictionary<(.+)>$/i, "Json")
|
|
265
|
+
.replace(/\|null$/i, "")
|
|
266
|
+
.replace(/^null\|/i, "")
|
|
267
|
+
.replace(/^(array|mixed|object)$/i, "Json");
|
|
262
268
|
}
|
|
263
269
|
function mapearTipoBackendParaSema(tipo) {
|
|
264
270
|
const limpo = limparTipoBackend(tipo);
|
|
@@ -1464,6 +1470,8 @@ function renderizarImpl(impl, indentacao = " ") {
|
|
|
1464
1470
|
...(impl.ts ? [`${indentacao} ts: ${impl.ts}`] : []),
|
|
1465
1471
|
...(impl.py ? [`${indentacao} py: ${impl.py}`] : []),
|
|
1466
1472
|
...(impl.dart ? [`${indentacao} dart: ${impl.dart}`] : []),
|
|
1473
|
+
...(impl.lua ? [`${indentacao} lua: ${impl.lua}`] : []),
|
|
1474
|
+
...(impl.php ? [`${indentacao} php: ${impl.php}`] : []),
|
|
1467
1475
|
...(impl.cs ? [`${indentacao} cs: ${impl.cs}`] : []),
|
|
1468
1476
|
...(impl.java ? [`${indentacao} java: ${impl.java}`] : []),
|
|
1469
1477
|
...(impl.go ? [`${indentacao} go: ${impl.go}`] : []),
|
|
@@ -2183,6 +2191,27 @@ function extrairErrosPython(texto) {
|
|
|
2183
2191
|
}
|
|
2184
2192
|
return [...erros.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
2185
2193
|
}
|
|
2194
|
+
function extrairErrosLua(texto) {
|
|
2195
|
+
const erros = new Map();
|
|
2196
|
+
for (const match of texto.matchAll(/\berror\s*\(\s*(?:(["'])(.*?)\1|([A-Za-z_]\w*))/g)) {
|
|
2197
|
+
const mensagem = match[2] ?? `Erro importado automaticamente de ${match[3] ?? "error"}.`;
|
|
2198
|
+
erros.set(normalizarNomeErroBruto(mensagem), mensagem);
|
|
2199
|
+
}
|
|
2200
|
+
return [...erros.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
2201
|
+
}
|
|
2202
|
+
function extrairErrosPhp(texto) {
|
|
2203
|
+
const erros = new Map();
|
|
2204
|
+
for (const match of texto.matchAll(/\bthrow\s+new\s+([A-Za-z_\\][A-Za-z0-9_\\]*)\s*\(([^)]*)\)/g)) {
|
|
2205
|
+
const nomeBruto = match[1].split("\\").at(-1) ?? match[1];
|
|
2206
|
+
const mensagem = (match[2] ?? "").match(/["']([^"']+)["']/)?.[1] ?? `Erro importado automaticamente de ${nomeBruto}.`;
|
|
2207
|
+
erros.set(normalizarNomeErroBruto(nomeBruto), mensagem);
|
|
2208
|
+
}
|
|
2209
|
+
for (const match of texto.matchAll(/\babort\s*\(\s*(\d{3})(?:\s*,\s*["']([^"']+)["'])?/g)) {
|
|
2210
|
+
const mensagem = match[2] ?? `Abort HTTP ${match[1]}.`;
|
|
2211
|
+
erros.set(`http_${match[1]}`, mensagem);
|
|
2212
|
+
}
|
|
2213
|
+
return [...erros.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
2214
|
+
}
|
|
2186
2215
|
function caminhoImplGenerico(diretorioBase, arquivo, simbolo, opcoes) {
|
|
2187
2216
|
const relativo = path.relative(diretorioBase, arquivo).replace(/\.[^.]+$/, "");
|
|
2188
2217
|
const segmentos = relativo.split(path.sep).map((segmento, indice, lista) => opcoes?.snakeCaseUltimoArquivo && indice === lista.length - 1
|
|
@@ -2197,6 +2226,62 @@ function caminhoImplPython(diretorioBase, arquivo, simbolo) {
|
|
|
2197
2226
|
function caminhoImplDart(diretorioBase, arquivo, simbolo) {
|
|
2198
2227
|
return caminhoImplGenerico(diretorioBase, arquivo, simbolo);
|
|
2199
2228
|
}
|
|
2229
|
+
function caminhoImplPhp(diretorioBase, arquivo, simbolo) {
|
|
2230
|
+
return simbolo.includes(".")
|
|
2231
|
+
? simbolo
|
|
2232
|
+
: caminhoImplGenerico(diretorioBase, arquivo, simbolo);
|
|
2233
|
+
}
|
|
2234
|
+
const NOMES_RESERVADOS_TASK_IMPORTADA = new Set([
|
|
2235
|
+
"database",
|
|
2236
|
+
"table",
|
|
2237
|
+
"view",
|
|
2238
|
+
"query",
|
|
2239
|
+
"transaction",
|
|
2240
|
+
"index",
|
|
2241
|
+
"constraint",
|
|
2242
|
+
"relationship",
|
|
2243
|
+
"collection",
|
|
2244
|
+
"document",
|
|
2245
|
+
"keyspace",
|
|
2246
|
+
"stream",
|
|
2247
|
+
"lock",
|
|
2248
|
+
"retention",
|
|
2249
|
+
"replication",
|
|
2250
|
+
"input",
|
|
2251
|
+
"output",
|
|
2252
|
+
"rules",
|
|
2253
|
+
"effects",
|
|
2254
|
+
"impl",
|
|
2255
|
+
"vinculos",
|
|
2256
|
+
"execucao",
|
|
2257
|
+
"auth",
|
|
2258
|
+
"authz",
|
|
2259
|
+
"dados",
|
|
2260
|
+
"audit",
|
|
2261
|
+
"segredos",
|
|
2262
|
+
"forbidden",
|
|
2263
|
+
"guarantees",
|
|
2264
|
+
"state",
|
|
2265
|
+
"tests",
|
|
2266
|
+
"error",
|
|
2267
|
+
"flow",
|
|
2268
|
+
"route",
|
|
2269
|
+
"worker",
|
|
2270
|
+
"evento",
|
|
2271
|
+
"fila",
|
|
2272
|
+
"cron",
|
|
2273
|
+
"webhook",
|
|
2274
|
+
"cache",
|
|
2275
|
+
"storage",
|
|
2276
|
+
"policy",
|
|
2277
|
+
"when",
|
|
2278
|
+
"given",
|
|
2279
|
+
"expect",
|
|
2280
|
+
]);
|
|
2281
|
+
function normalizarNomeTaskImportada(valor) {
|
|
2282
|
+
const nome = paraSnakeCase(valor) || "task_importada";
|
|
2283
|
+
return NOMES_RESERVADOS_TASK_IMPORTADA.has(nome) ? `${nome}_task` : nome;
|
|
2284
|
+
}
|
|
2200
2285
|
function dividirParametrosPython(parametros) {
|
|
2201
2286
|
const partes = [];
|
|
2202
2287
|
let atual = "";
|
|
@@ -2500,6 +2585,114 @@ async function importarDartBase(diretorio, namespaceBase) {
|
|
|
2500
2585
|
}
|
|
2501
2586
|
return modulos;
|
|
2502
2587
|
}
|
|
2588
|
+
async function importarLuaBase(diretorio, namespaceBase) {
|
|
2589
|
+
const arquivos = (await listarArquivosRecursivos(diretorio, [".lua"]))
|
|
2590
|
+
.filter((arquivo) => !/(^|[\\/])tests?([\\/]|$)|(?:^|[\\/])spec([\\/]|$)|(?:_spec|_test)\.lua$/i.test(arquivo));
|
|
2591
|
+
const modulos = [];
|
|
2592
|
+
for (const arquivo of arquivos) {
|
|
2593
|
+
const texto = await readFile(arquivo, "utf8");
|
|
2594
|
+
const relacao = path.relative(diretorio, arquivo);
|
|
2595
|
+
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2596
|
+
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2597
|
+
const tasks = [];
|
|
2598
|
+
for (const simbolo of selecionarSimbolosPreferidos(extrairSimbolosLua(texto))) {
|
|
2599
|
+
const nomeBase = simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo;
|
|
2600
|
+
tasks.push({
|
|
2601
|
+
nome: paraSnakeCase(nomeBase),
|
|
2602
|
+
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2603
|
+
input: simbolo.parametros.map((parametro) => ({
|
|
2604
|
+
nome: normalizarNomeCampoImportado(parametro.nome),
|
|
2605
|
+
tipo: mapearTipoPrimitivo(parametro.tipoTexto ?? "Json"),
|
|
2606
|
+
obrigatorio: parametro.obrigatorio,
|
|
2607
|
+
})),
|
|
2608
|
+
output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
|
|
2609
|
+
errors: extrairErrosLua(texto),
|
|
2610
|
+
effects: descreverEfeitosPorHeuristica(texto),
|
|
2611
|
+
impl: { lua: caminhoImplGenerico(diretorio, arquivo, simbolo.simbolo) },
|
|
2612
|
+
origemArquivo: relacao,
|
|
2613
|
+
origemSimbolo: simbolo.simbolo,
|
|
2614
|
+
});
|
|
2615
|
+
}
|
|
2616
|
+
if (tasks.length === 0) {
|
|
2617
|
+
continue;
|
|
2618
|
+
}
|
|
2619
|
+
modulos.push({
|
|
2620
|
+
nome: nomeModulo,
|
|
2621
|
+
resumo: `Rascunho Sema importado automaticamente de ${relacao}.`,
|
|
2622
|
+
tasks: deduplicarTarefas(tasks),
|
|
2623
|
+
routes: [],
|
|
2624
|
+
entities: [],
|
|
2625
|
+
enums: [],
|
|
2626
|
+
databases: inferirDatabasesPorHeuristica(texto, relacao),
|
|
2627
|
+
});
|
|
2628
|
+
}
|
|
2629
|
+
return modulos;
|
|
2630
|
+
}
|
|
2631
|
+
async function importarPhpBase(diretorio, namespaceBase) {
|
|
2632
|
+
const arquivos = (await listarArquivosRecursivos(diretorio, [".php"]))
|
|
2633
|
+
.filter((arquivo) => !/(^|[\\/])tests?([\\/]|$)|(?:^|[\\/])spec([\\/]|$)|(?:Test|Spec)\.php$/i.test(arquivo));
|
|
2634
|
+
const modulos = new Map();
|
|
2635
|
+
for (const arquivo of arquivos) {
|
|
2636
|
+
const texto = await readFile(arquivo, "utf8");
|
|
2637
|
+
const relacao = path.relative(diretorio, arquivo);
|
|
2638
|
+
const contextoSegmentos = inferirContextoPorArquivo(relacao);
|
|
2639
|
+
const nomeModulo = [namespaceBase, ...contextoSegmentos].join(".");
|
|
2640
|
+
const tasks = [];
|
|
2641
|
+
const routes = [];
|
|
2642
|
+
for (const simbolo of selecionarSimbolosPreferidos(extrairSimbolosPhp(texto))) {
|
|
2643
|
+
const nomeBase = simbolo.simbolo.split(".").at(-1) ?? simbolo.simbolo;
|
|
2644
|
+
tasks.push({
|
|
2645
|
+
nome: normalizarNomeTaskImportada(nomeBase),
|
|
2646
|
+
resumo: `Task importada automaticamente de ${relacao}#${simbolo.simbolo}.`,
|
|
2647
|
+
input: simbolo.parametros.map((parametro) => ({
|
|
2648
|
+
nome: normalizarNomeCampoImportado(parametro.nome),
|
|
2649
|
+
tipo: mapearTipoBackendParaSema(parametro.tipoTexto),
|
|
2650
|
+
obrigatorio: parametro.obrigatorio,
|
|
2651
|
+
})),
|
|
2652
|
+
output: criarCampoResultadoBackend(simbolo.retorno),
|
|
2653
|
+
errors: extrairErrosPhp(texto),
|
|
2654
|
+
effects: descreverEfeitosPorHeuristica(texto),
|
|
2655
|
+
impl: { php: caminhoImplPhp(diretorio, arquivo, simbolo.simbolo) },
|
|
2656
|
+
origemArquivo: relacao,
|
|
2657
|
+
origemSimbolo: simbolo.simbolo,
|
|
2658
|
+
});
|
|
2659
|
+
}
|
|
2660
|
+
for (const rota of extrairRotasPhp(texto)) {
|
|
2661
|
+
const taskNome = normalizarNomeTaskImportada(rota.simbolo.split(".").at(-1) ?? rota.simbolo);
|
|
2662
|
+
const output = rota.retorno ? criarCampoResultadoBackend(rota.retorno) : [{ nome: "resultado", tipo: "Json", obrigatorio: false }];
|
|
2663
|
+
const nomeBase = `${taskNome}_publico`;
|
|
2664
|
+
const nome = routes.some((route) => route.nome === nomeBase)
|
|
2665
|
+
? `${taskNome}_${rota.metodo.toLowerCase()}_publico`
|
|
2666
|
+
: nomeBase;
|
|
2667
|
+
tasks.push({
|
|
2668
|
+
nome: taskNome,
|
|
2669
|
+
resumo: `Task HTTP PHP importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2670
|
+
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2671
|
+
output,
|
|
2672
|
+
errors: extrairErrosPhp(texto),
|
|
2673
|
+
effects: [{ categoria: "consulta", alvo: "http", criticidade: "media" }],
|
|
2674
|
+
impl: { php: caminhoImplPhp(diretorio, arquivo, rota.simbolo) },
|
|
2675
|
+
origemArquivo: relacao,
|
|
2676
|
+
origemSimbolo: rota.simbolo,
|
|
2677
|
+
});
|
|
2678
|
+
routes.push({
|
|
2679
|
+
nome,
|
|
2680
|
+
resumo: `Rota PHP importada automaticamente de ${relacao}#${rota.simbolo}.`,
|
|
2681
|
+
metodo: rota.metodo,
|
|
2682
|
+
caminho: rota.caminho,
|
|
2683
|
+
task: taskNome,
|
|
2684
|
+
input: camposDeParametrosRotaBackend(rota.parametros),
|
|
2685
|
+
output,
|
|
2686
|
+
errors: [],
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
if (tasks.length === 0 && routes.length === 0) {
|
|
2690
|
+
continue;
|
|
2691
|
+
}
|
|
2692
|
+
acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
|
|
2693
|
+
}
|
|
2694
|
+
return [...modulos.values()];
|
|
2695
|
+
}
|
|
2503
2696
|
function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = [], databases = []) {
|
|
2504
2697
|
sincronizarRotasComTasks(routes, tasks);
|
|
2505
2698
|
return {
|
|
@@ -2891,6 +3084,12 @@ export async function importarProjetoLegado(fonte, diretorio, namespaceBase) {
|
|
|
2891
3084
|
else if (fonte === "dart") {
|
|
2892
3085
|
modulos = await importarDartBase(base, namespace);
|
|
2893
3086
|
}
|
|
3087
|
+
else if (fonte === "lua") {
|
|
3088
|
+
modulos = await importarLuaBase(base, namespace);
|
|
3089
|
+
}
|
|
3090
|
+
else if (fonte === "php") {
|
|
3091
|
+
modulos = await importarPhpBase(base, namespace);
|
|
3092
|
+
}
|
|
2894
3093
|
else if (fonte === "dotnet") {
|
|
2895
3094
|
modulos = await importarDotnetBase(base, namespace);
|
|
2896
3095
|
}
|