@semacode/cli 4.1.1 → 4.1.2
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/node_modules/@sema/gerador-typescript/dist/index.part01.d.ts +2 -2
- package/node_modules/@sema/gerador-typescript/dist/index.part01.js +118 -16
- package/node_modules/@sema/gerador-typescript/dist/index.part02.d.ts +1 -1
- package/node_modules/@sema/gerador-typescript/dist/index.part02.js +10 -3
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ export declare function gerarComentarioInvariantesTypeScript(invariantes: Expres
|
|
|
8
8
|
export declare function gerarLiteralCamposTypeScript(campos: IrCampo[]): string;
|
|
9
9
|
export declare function coletarTiposExternos(modulo: IrModulo): string[];
|
|
10
10
|
export declare function gerarLiteralErrosTypeScript(erros: Record<string, string>): string;
|
|
11
|
-
export declare function formatarValorTypeScript(valor: string, camposConhecidos: Set<string>, variavel: string): string;
|
|
11
|
+
export declare function formatarValorTypeScript(valor: string, camposConhecidos: Set<string>, variavel: string, literal?: boolean): string;
|
|
12
12
|
export declare function resolverReferenciaTypeScript(referencia: string, variavel: string): string;
|
|
13
13
|
export declare function gerarExpressaoTypeScript(expressao: ExpressaoSemantica, camposConhecidos: Set<string>, variavel: string): string;
|
|
14
14
|
export declare function valorPadraoTypeScript(tipo: string, nomeCampo: string): string;
|
|
@@ -17,7 +17,7 @@ export declare function dividirLiteralNoNivelRaiz(valor: string, separador: ","
|
|
|
17
17
|
export declare function resolverTipoItemTeste(tipoDeclarado?: string): string | undefined;
|
|
18
18
|
export declare function formatarLiteralTesteTypeScript(valor: string, tipoDeclarado?: string): unknown;
|
|
19
19
|
export declare function converterBlocoTesteParaValorTypeScript(bloco: IrBlocoDeclarativo, tiposDeclarados?: Map<string, string>): Record<string, unknown>;
|
|
20
|
-
export declare function gerarPreparacaoSaida(task: IrTask): string;
|
|
20
|
+
export declare function gerarPreparacaoSaida(task: IrTask, tiposDeclarados?: Map<string, Map<string, string>>): string;
|
|
21
21
|
export declare function gerarValidacoes(task: IrTask): string;
|
|
22
22
|
export declare function gerarGarantias(task: IrTask): string;
|
|
23
23
|
export declare function gerarFuncaoGarantias(task: IrTask): string;
|
|
@@ -48,7 +48,7 @@ export function gerarLiteralErrosTypeScript(erros) {
|
|
|
48
48
|
}
|
|
49
49
|
return `{\n${entradas.map(([nome, mensagem]) => ` ${JSON.stringify(nome)}: ${JSON.stringify(mensagem)},`).join("\n")}\n}`;
|
|
50
50
|
}
|
|
51
|
-
export function formatarValorTypeScript(valor, camposConhecidos, variavel) {
|
|
51
|
+
export function formatarValorTypeScript(valor, camposConhecidos, variavel, literal = false) {
|
|
52
52
|
const texto = valor.trim();
|
|
53
53
|
if (/^-?\d+(?:\.\d+)?$/.test(texto)) {
|
|
54
54
|
return texto;
|
|
@@ -62,7 +62,7 @@ export function formatarValorTypeScript(valor, camposConhecidos, variavel) {
|
|
|
62
62
|
if (texto === "nulo") {
|
|
63
63
|
return "null";
|
|
64
64
|
}
|
|
65
|
-
if (camposConhecidos.has(texto.split(".")[0] ?? texto)) {
|
|
65
|
+
if (!literal && camposConhecidos.has(texto.split(".")[0] ?? texto)) {
|
|
66
66
|
return `${variavel}.${texto}`;
|
|
67
67
|
}
|
|
68
68
|
return JSON.stringify(texto);
|
|
@@ -260,29 +260,131 @@ export function converterBlocoTesteParaValorTypeScript(bloco, tiposDeclarados) {
|
|
|
260
260
|
}
|
|
261
261
|
return literal;
|
|
262
262
|
}
|
|
263
|
-
|
|
263
|
+
function achatarGarantiasConjuntivasTypeScript(expressao) {
|
|
264
|
+
return expressao.tipo === "composta" && expressao.operadorLogico === "e"
|
|
265
|
+
? expressao.termos.flatMap(achatarGarantiasConjuntivasTypeScript)
|
|
266
|
+
: [expressao];
|
|
267
|
+
}
|
|
268
|
+
function sugerirValoresTypeScript(tipo, tiposDeclarados) {
|
|
269
|
+
if (["Numero", "Inteiro", "Decimal"].includes(tipo))
|
|
270
|
+
return "[1, 0, -1]";
|
|
271
|
+
if (tipo === "Booleano")
|
|
272
|
+
return "[false, true]";
|
|
273
|
+
if (["Texto", "Id", "Email", "Url", "Data", "DataHora", "Timestamp"].includes(tipo)) {
|
|
274
|
+
return '["valor_garantido", "outro_valor"]';
|
|
275
|
+
}
|
|
276
|
+
if (/^Lista</u.test(tipo) || /\[\]$/u.test(tipo))
|
|
277
|
+
return "[[]]";
|
|
278
|
+
if (/^Mapa</u.test(tipo) || ["Json", "Objeto"].includes(tipo) || tiposDeclarados.has(tipo))
|
|
279
|
+
return "[{}]";
|
|
280
|
+
return "[1, 0, -1, true, false, \"valor_garantido\", \"outro_valor\", {}]";
|
|
281
|
+
}
|
|
282
|
+
export function gerarPreparacaoSaida(task, tiposDeclarados = new Map()) {
|
|
264
283
|
const camposSaida = new Set(task.output.map((campo) => campo.nome));
|
|
265
284
|
const linhas = [];
|
|
266
285
|
for (const campo of task.output) {
|
|
267
286
|
linhas.push(` ${campo.nome}: ${valorPadraoTypeScript(campo.tipo, campo.nome)},`);
|
|
268
287
|
}
|
|
269
|
-
const
|
|
270
|
-
for (const garantia of task.garantiasEstruturadas) {
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
ajustes.push(` ${resolverReferenciaTypeScript(garantia.alvo, "saida")} = ${formatarValorTypeScript(garantia.valor, camposSaida, "saida")} as any;`);
|
|
288
|
+
const grupos = new Map();
|
|
289
|
+
for (const garantia of task.garantiasEstruturadas.flatMap(achatarGarantiasConjuntivasTypeScript)) {
|
|
290
|
+
if (!("alvo" in garantia) || !camposSaida.has(garantia.alvo.split(".")[0] ?? garantia.alvo))
|
|
291
|
+
continue;
|
|
292
|
+
if (garantia.tipo === "comparacao" || garantia.tipo === "pertencimento" || garantia.tipo === "existe") {
|
|
293
|
+
grupos.set(garantia.alvo, [...(grupos.get(garantia.alvo) ?? []), garantia]);
|
|
276
294
|
}
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
295
|
+
}
|
|
296
|
+
const referencias = new Set();
|
|
297
|
+
for (const regras of grupos.values()) {
|
|
298
|
+
for (const regra of regras) {
|
|
299
|
+
if (regra.tipo === "comparacao" && !regra.valorLiteral && camposSaida.has(regra.valor.split(".")[0] ?? regra.valor)) {
|
|
300
|
+
referencias.add(regra.valor);
|
|
282
301
|
}
|
|
283
302
|
}
|
|
284
303
|
}
|
|
285
|
-
|
|
304
|
+
for (const referencia of referencias) {
|
|
305
|
+
if (!grupos.has(referencia)) {
|
|
306
|
+
grupos.set(referencia, [{ tipo: "existe", alvo: referencia, textoOriginal: `${referencia} existe` }]);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
const caminhos = [...grupos.keys()].sort((a, b) => Number(referencias.has(b)) - Number(referencias.has(a)) || a.split(".").length - b.split(".").length);
|
|
310
|
+
const ajustes = [];
|
|
311
|
+
for (const caminho of caminhos) {
|
|
312
|
+
const regras = grupos.get(caminho);
|
|
313
|
+
let tipo = task.output.find((campo) => campo.nome === caminho.split(".")[0])?.tipo ?? "Json";
|
|
314
|
+
for (const segmento of caminho.split(".").slice(1)) {
|
|
315
|
+
tipo = tiposDeclarados.get(tipo)?.get(segmento) ?? "Json";
|
|
316
|
+
}
|
|
317
|
+
const restricoes = regras.map((regra) => {
|
|
318
|
+
if (regra.tipo === "comparacao") {
|
|
319
|
+
return `[${JSON.stringify(regra.operador)}, ${formatarValorTypeScript(regra.valor, camposSaida, "saida", regra.valorLiteral)}]`;
|
|
320
|
+
}
|
|
321
|
+
if (regra.tipo === "pertencimento") {
|
|
322
|
+
const valores = (regra.valores ?? []).map((valor) => formatarValorTypeScript(valor, camposSaida, "saida", true));
|
|
323
|
+
return `["in", [${valores.join(", ")}]]`;
|
|
324
|
+
}
|
|
325
|
+
return '["existe", null]';
|
|
326
|
+
});
|
|
327
|
+
const caminhoLiteral = JSON.stringify(caminho.split("."));
|
|
328
|
+
const somenteExistencia = regras.every((regra) => regra.tipo === "existe");
|
|
329
|
+
const temDescendente = caminhos.some((outro) => outro.startsWith(`${caminho}.`));
|
|
330
|
+
if (somenteExistencia && temDescendente) {
|
|
331
|
+
ajustes.push(` if (semaLerSaida(saida, ${caminhoLiteral}) == null) semaDefinirSaida(saida, ${caminhoLiteral}, {});`);
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
const inteiro = tipo === "Inteiro" ? "true" : "false";
|
|
335
|
+
ajustes.push(` semaDefinirSaida(saida, ${caminhoLiteral}, semaSintetizarSaida(semaLerSaida(saida, ${caminhoLiteral}), [${restricoes.join(", ")}], ${inteiro}, ${sugerirValoresTypeScript(tipo, tiposDeclarados)}));`);
|
|
336
|
+
}
|
|
337
|
+
const helpers = grupos.size === 0 ? "" : `
|
|
338
|
+
const semaLerSaida = (objeto: any, caminho: string[]): any => caminho.reduce((atual, campo) => atual == null ? undefined : atual[campo], objeto);
|
|
339
|
+
const semaDefinirSaida = (objeto: any, caminho: string[], valor: any): void => {
|
|
340
|
+
let atual = objeto;
|
|
341
|
+
for (const campo of caminho.slice(0, -1)) {
|
|
342
|
+
if (atual[campo] === null || typeof atual[campo] !== "object") atual[campo] = {};
|
|
343
|
+
atual = atual[campo];
|
|
344
|
+
}
|
|
345
|
+
const ultimo = caminho[caminho.length - 1];
|
|
346
|
+
if (ultimo !== undefined) atual[ultimo] = valor;
|
|
347
|
+
};
|
|
348
|
+
const semaSintetizarSaida = (atual: any, restricoes: Array<[string, any]>, inteiro: boolean, sementes: any[]): any => {
|
|
349
|
+
const aceita = (valor: any): boolean => restricoes.every(([operador, limite]) => {
|
|
350
|
+
if (operador === "existe") return valor !== undefined && valor !== null;
|
|
351
|
+
if (operador === "in") return Array.isArray(limite) && limite.some((item: any) => Object.is(item, valor));
|
|
352
|
+
if (operador === "==") return valor === limite;
|
|
353
|
+
if (operador === "!=") return valor !== limite;
|
|
354
|
+
const esquerda: any = valor;
|
|
355
|
+
const direita: any = limite;
|
|
356
|
+
if (operador === ">") return esquerda > direita;
|
|
357
|
+
if (operador === ">=") return esquerda >= direita;
|
|
358
|
+
if (operador === "<") return esquerda < direita;
|
|
359
|
+
if (operador === "<=") return esquerda <= direita;
|
|
360
|
+
return false;
|
|
361
|
+
});
|
|
362
|
+
const candidatos: any[] = [atual, ...sementes];
|
|
363
|
+
const numeros: number[] = [];
|
|
364
|
+
for (const [operador, limite] of restricoes) {
|
|
365
|
+
if (operador === "in" && Array.isArray(limite)) candidatos.push(...limite);
|
|
366
|
+
else if (operador !== "existe") {
|
|
367
|
+
candidatos.push(limite);
|
|
368
|
+
if (typeof limite === "number" && Number.isFinite(limite)) {
|
|
369
|
+
numeros.push(limite);
|
|
370
|
+
candidatos.push(limite - 1, limite + 1, Math.floor(limite), Math.ceil(limite));
|
|
371
|
+
} else if (typeof limite === "string") {
|
|
372
|
+
candidatos.push(limite + "\\u0000", limite.slice(0, -1), "");
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
numeros.sort((a, b) => a - b);
|
|
377
|
+
for (let indice = 0; indice < numeros.length - 1; indice += 1) {
|
|
378
|
+
candidatos.push((numeros[indice]! + numeros[indice + 1]!) / 2);
|
|
379
|
+
}
|
|
380
|
+
for (const candidato of candidatos) {
|
|
381
|
+
if (inteiro && (typeof candidato !== "number" || !Number.isInteger(candidato))) continue;
|
|
382
|
+
if (aceita(candidato)) return candidato;
|
|
383
|
+
}
|
|
384
|
+
throw new Error("Nao foi possivel sintetizar uma saida demonstrativa compativel com as garantias.");
|
|
385
|
+
};
|
|
386
|
+
`;
|
|
387
|
+
return ` const saida = {\n${linhas.join("\n")}\n } as ${task.nome}Saida;${helpers}\n${ajustes.join("\n")}`;
|
|
286
388
|
}
|
|
287
389
|
export function gerarValidacoes(task) {
|
|
288
390
|
const linhas = [];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { IrModulo, IrTask } from "@sema/nucleo";
|
|
2
2
|
import { type ArquivoGerado } from "@sema/padroes";
|
|
3
3
|
export declare function gerarRotas(modulo: IrModulo): string;
|
|
4
|
-
export declare function gerarTask(task: IrTask): string;
|
|
4
|
+
export declare function gerarTask(task: IrTask, tiposDeclarados?: Map<string, Map<string, string>>): string;
|
|
5
5
|
export declare function gerarTestes(modulo: IrModulo): string;
|
|
6
6
|
export type TipoCabecalhoSemaTypeScript = "contrato" | "teste" | "dto" | "service" | "controller" | "spec";
|
|
7
7
|
export declare function gerarCabecalhoSemaTypeScript(modulo: IrModulo, tipo?: TipoCabecalhoSemaTypeScript): string;
|
|
@@ -68,7 +68,7 @@ ${verificacoesErro || " throw erro;"}
|
|
|
68
68
|
`;
|
|
69
69
|
}).join("\n");
|
|
70
70
|
}
|
|
71
|
-
export function gerarTask(task) {
|
|
71
|
+
export function gerarTask(task, tiposDeclarados = new Map()) {
|
|
72
72
|
const nomeSimbolo = normalizarNomeParaSimbolo(task.nome);
|
|
73
73
|
const entradaNome = `${nomeSimbolo}_entrada`;
|
|
74
74
|
const saidaNome = `${nomeSimbolo}_saida`;
|
|
@@ -130,7 +130,7 @@ ${task.stateContract ? ` // Vinculo de estado: ${task.stateContract.nomeEstado
|
|
|
130
130
|
${task.implementacoesExternas.length > 0 ? ` // Implementacoes externas vinculadas:\n${task.implementacoesExternas.map((impl) => ` // - ${impl.origem}: ${impl.caminho} [${impl.statusImpl ?? "nao_verificado"}]`).join("\n")}` : ""}
|
|
131
131
|
// Efeitos declarados:
|
|
132
132
|
${task.efeitosEstruturados.map((efeito) => ` // - categoria=${efeito.categoria} alvo=${efeito.alvo}${efeito.detalhe ? ` detalhe=${efeito.detalhe}` : ""}${efeito.criticidade ? ` criticidade=${efeito.criticidade}` : ""}`).join("\n") || task.effects.map((efeito) => ` // - ${efeito}`).join("\n") || " // - Nenhum efeito declarado."}
|
|
133
|
-
${gerarPreparacaoSaida(task)}
|
|
133
|
+
${gerarPreparacaoSaida(task, tiposDeclarados)}
|
|
134
134
|
${gerarGarantias(task)}
|
|
135
135
|
}
|
|
136
136
|
|
|
@@ -211,6 +211,13 @@ export function gerarCabecalhoSemaTypeScript(modulo, tipo = "contrato") {
|
|
|
211
211
|
}
|
|
212
212
|
export function gerarTypeScriptBase(modulo) {
|
|
213
213
|
const nomeBase = normalizarNomeModulo(modulo.nome).replace(/\./g, "_");
|
|
214
|
+
const mapaTiposDeclarados = new Map();
|
|
215
|
+
for (const entidade of modulo.entities) {
|
|
216
|
+
mapaTiposDeclarados.set(entidade.nome, new Map(entidade.campos.map((campo) => [campo.nome, campo.tipo])));
|
|
217
|
+
}
|
|
218
|
+
for (const tipo of modulo.types) {
|
|
219
|
+
mapaTiposDeclarados.set(tipo.nome, new Map(tipo.definicao.campos.map((campo) => [campo.nome, campo.tipo])));
|
|
220
|
+
}
|
|
214
221
|
const interoperabilidades = modulo.interoperabilidades
|
|
215
222
|
.map((interop) => `// Interop externo ${interop.origem}: ${interop.caminho}`)
|
|
216
223
|
.join("\n");
|
|
@@ -235,7 +242,7 @@ export function gerarTypeScriptBase(modulo) {
|
|
|
235
242
|
const routes = modulo.routes
|
|
236
243
|
.map((route) => `// Route ${route.nome}: metodo=${route.metodo ?? "nao_definido"} caminho=${route.caminho ?? "nao_definido"} task=${route.task ?? "nao_definida"} input_publico=${route.inputPublico.map((campo) => campo.nome).join(", ") || "padrao_task"} output_publico=${route.outputPublico.map((campo) => campo.nome).join(", ") || "padrao_task"} erros_publicos=${route.errosPublicos.map((erro) => erro.nome).join(", ") || "padrao_task"} effects_publicos=${route.efeitosPublicos.map((efeito) => `${efeito.categoria}:${efeito.alvo}`).join(", ") || "nenhum"} garantias_publicas=${route.garantiasPublicasMinimas.length}`)
|
|
237
244
|
.join("\n");
|
|
238
|
-
const tasks = modulo.tasks.map(gerarTask).join("\n");
|
|
245
|
+
const tasks = modulo.tasks.map((task) => gerarTask(task, mapaTiposDeclarados)).join("\n");
|
|
239
246
|
const contratosPublicos = gerarRotas(modulo);
|
|
240
247
|
const codigo = `${gerarCabecalhoSemaTypeScript(modulo)}${interoperabilidades ? `${interoperabilidades}\n` : ""}\n${tiposExternos}\n${tipos}\n${entidades}\n${enums}\n${states}\n${flows}\n${routes}\n${tasks}\n${contratosPublicos}\n`;
|
|
241
248
|
const testes = `${gerarCabecalhoSemaTypeScript(modulo, "teste")}${gerarTestes(modulo)}`;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semacode/cli",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.2",
|
|
4
4
|
"description": "Local-first semantic governance CLI for AI agents, proven with Claude, Codex, zCode (GLM) and Kimi: contracts, drift, impact, docs gates, and code generation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "logo.png",
|