@semacode/cli 1.5.10 → 1.5.14
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 +6 -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 +67 -4
- package/dist/drift.js.map +1 -1
- package/dist/importador.d.ts +1 -1
- package/dist/importador.js +144 -1
- package/dist/importador.js.map +1 -1
- package/dist/index.js +388 -3
- package/dist/index.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 +14 -0
- package/dist/projeto.js.map +1 -1
- package/dist/tipos.d.ts +1 -1
- package/docs/cli.md +10 -1
- package/docs/sintaxe.md +192 -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 +4 -2
- package/node_modules/@sema/nucleo/dist/formatador/index.js +40 -13
- package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.js +182 -3
- package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +35 -3
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js +21 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/parser/parser.js +38 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
- package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +4 -3
- package/node_modules/@sema/nucleo/dist/semantico/analisador.js +310 -13
- 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 +14 -14
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" | "lua" | "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
|
@@ -8,6 +8,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
10
|
import { extrairSimbolosLua } from "./lua-symbols.js";
|
|
11
|
+
import { extrairRotasPhp, extrairSimbolosPhp } from "./php-symbols.js";
|
|
11
12
|
import { extrairParametrosCaminhoFlask, extrairRotasFlaskDecoradas } from "./python-http.js";
|
|
12
13
|
import { extrairRotasRust, extrairSimbolosRust } from "./rust-http.js";
|
|
13
14
|
import { extrairRotasTypeScriptHttp, inferirSemanticaHandlerTypeScriptHttp, localizarExportacaoTypeScriptHttp, } from "./typescript-http.js";
|
|
@@ -246,6 +247,7 @@ function limparTipoBackend(tipo) {
|
|
|
246
247
|
}
|
|
247
248
|
return tipo
|
|
248
249
|
.trim()
|
|
250
|
+
.replace(/^\?/, "")
|
|
249
251
|
.replace(/^Task<(.+)>$/i, "$1")
|
|
250
252
|
.replace(/^ActionResult<(.+)>$/i, "$1")
|
|
251
253
|
.replace(/^IActionResult$/i, "Json")
|
|
@@ -259,7 +261,10 @@ function limparTipoBackend(tipo) {
|
|
|
259
261
|
.replace(/^Vec<(.+)>$/i, "Json")
|
|
260
262
|
.replace(/^List<(.+)>$/i, "Json")
|
|
261
263
|
.replace(/^Map<(.+)>$/i, "Json")
|
|
262
|
-
.replace(/^Dictionary<(.+)>$/i, "Json")
|
|
264
|
+
.replace(/^Dictionary<(.+)>$/i, "Json")
|
|
265
|
+
.replace(/\|null$/i, "")
|
|
266
|
+
.replace(/^null\|/i, "")
|
|
267
|
+
.replace(/^(array|mixed|object)$/i, "Json");
|
|
263
268
|
}
|
|
264
269
|
function mapearTipoBackendParaSema(tipo) {
|
|
265
270
|
const limpo = limparTipoBackend(tipo);
|
|
@@ -1466,6 +1471,7 @@ function renderizarImpl(impl, indentacao = " ") {
|
|
|
1466
1471
|
...(impl.py ? [`${indentacao} py: ${impl.py}`] : []),
|
|
1467
1472
|
...(impl.dart ? [`${indentacao} dart: ${impl.dart}`] : []),
|
|
1468
1473
|
...(impl.lua ? [`${indentacao} lua: ${impl.lua}`] : []),
|
|
1474
|
+
...(impl.php ? [`${indentacao} php: ${impl.php}`] : []),
|
|
1469
1475
|
...(impl.cs ? [`${indentacao} cs: ${impl.cs}`] : []),
|
|
1470
1476
|
...(impl.java ? [`${indentacao} java: ${impl.java}`] : []),
|
|
1471
1477
|
...(impl.go ? [`${indentacao} go: ${impl.go}`] : []),
|
|
@@ -2193,6 +2199,19 @@ function extrairErrosLua(texto) {
|
|
|
2193
2199
|
}
|
|
2194
2200
|
return [...erros.entries()].map(([nome, mensagem]) => ({ nome, mensagem }));
|
|
2195
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
|
+
}
|
|
2196
2215
|
function caminhoImplGenerico(diretorioBase, arquivo, simbolo, opcoes) {
|
|
2197
2216
|
const relativo = path.relative(diretorioBase, arquivo).replace(/\.[^.]+$/, "");
|
|
2198
2217
|
const segmentos = relativo.split(path.sep).map((segmento, indice, lista) => opcoes?.snakeCaseUltimoArquivo && indice === lista.length - 1
|
|
@@ -2207,6 +2226,62 @@ function caminhoImplPython(diretorioBase, arquivo, simbolo) {
|
|
|
2207
2226
|
function caminhoImplDart(diretorioBase, arquivo, simbolo) {
|
|
2208
2227
|
return caminhoImplGenerico(diretorioBase, arquivo, simbolo);
|
|
2209
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
|
+
}
|
|
2210
2285
|
function dividirParametrosPython(parametros) {
|
|
2211
2286
|
const partes = [];
|
|
2212
2287
|
let atual = "";
|
|
@@ -2553,6 +2628,71 @@ async function importarLuaBase(diretorio, namespaceBase) {
|
|
|
2553
2628
|
}
|
|
2554
2629
|
return modulos;
|
|
2555
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
|
+
}
|
|
2556
2696
|
function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = [], databases = []) {
|
|
2557
2697
|
sincronizarRotasComTasks(routes, tasks);
|
|
2558
2698
|
return {
|
|
@@ -2947,6 +3087,9 @@ export async function importarProjetoLegado(fonte, diretorio, namespaceBase) {
|
|
|
2947
3087
|
else if (fonte === "lua") {
|
|
2948
3088
|
modulos = await importarLuaBase(base, namespace);
|
|
2949
3089
|
}
|
|
3090
|
+
else if (fonte === "php") {
|
|
3091
|
+
modulos = await importarPhpBase(base, namespace);
|
|
3092
|
+
}
|
|
2950
3093
|
else if (fonte === "dotnet") {
|
|
2951
3094
|
modulos = await importarDotnetBase(base, namespace);
|
|
2952
3095
|
}
|