@semacode/cli 1.5.29 → 1.5.31
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/dist/comandos.js +69 -0
- package/dist/comandos.js.map +1 -1
- package/dist/dev/index.d.ts +18 -0
- package/dist/dev/index.js +143 -0
- package/dist/dev/index.js.map +1 -0
- package/dist/guard.d.ts +35 -0
- package/dist/guard.js +164 -0
- package/dist/guard.js.map +1 -0
- package/dist/index.js.map +1 -1
- package/dist/init/index.d.ts +23 -0
- package/dist/init/index.js +112 -0
- package/dist/init/index.js.map +1 -0
- package/dist/init/templates.d.ts +11 -0
- package/dist/init/templates.js +660 -0
- package/dist/init/templates.js.map +1 -0
- package/dist/sync/index.d.ts +24 -0
- package/dist/sync/index.js +174 -0
- package/dist/sync/index.js.map +1 -0
- package/exemplos/.prepack-generated +1 -0
- package/node_modules/@sema/gerador-css/package.json +14 -7
- package/node_modules/@sema/gerador-css/src/index.ts +605 -0
- package/node_modules/@sema/gerador-css/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-css/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-dart/package.json +14 -7
- package/node_modules/@sema/gerador-dart/src/index.ts +52 -0
- package/node_modules/@sema/gerador-dart/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-dart/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-html/package.json +14 -7
- package/node_modules/@sema/gerador-html/src/index.ts +185 -0
- package/node_modules/@sema/gerador-html/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-html/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-javascript/package.json +14 -7
- package/node_modules/@sema/gerador-javascript/src/index.ts +461 -0
- package/node_modules/@sema/gerador-javascript/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-javascript/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-lua/package.json +14 -7
- package/node_modules/@sema/gerador-lua/src/index.ts +359 -0
- package/node_modules/@sema/gerador-lua/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-lua/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-python/package.json +14 -7
- package/node_modules/@sema/gerador-python/src/index.ts +850 -0
- package/node_modules/@sema/gerador-python/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-python/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/gerador-typescript/package.json +14 -7
- package/node_modules/@sema/gerador-typescript/src/index.ts +876 -0
- package/node_modules/@sema/gerador-typescript/tsconfig.json +13 -0
- package/node_modules/@sema/gerador-typescript/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.d.ts +22 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +97 -0
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +1 -0
- package/node_modules/@sema/nucleo/dist/index.d.ts +1 -0
- package/node_modules/@sema/nucleo/dist/index.js +1 -0
- package/node_modules/@sema/nucleo/dist/index.js.map +1 -1
- package/node_modules/@sema/nucleo/package.json +10 -7
- package/node_modules/@sema/nucleo/src/ast/tipos.ts +207 -0
- package/node_modules/@sema/nucleo/src/diagnosticos/index.ts +43 -0
- package/node_modules/@sema/nucleo/src/diagnosticos/melhorador.ts +130 -0
- package/node_modules/@sema/nucleo/src/formatador/index.ts +530 -0
- package/node_modules/@sema/nucleo/src/index.ts +184 -0
- package/node_modules/@sema/nucleo/src/ir/conversor.ts +1037 -0
- package/node_modules/@sema/nucleo/src/ir/modelos.ts +403 -0
- package/node_modules/@sema/nucleo/src/lexer/lexer.ts +166 -0
- package/node_modules/@sema/nucleo/src/lexer/tokens.ts +79 -0
- package/node_modules/@sema/nucleo/src/parser/gramatica.ebnf +41 -0
- package/node_modules/@sema/nucleo/src/parser/parser.ts +936 -0
- package/node_modules/@sema/nucleo/src/persistencia/contratos.ts +379 -0
- package/node_modules/@sema/nucleo/src/semantico/analisador.ts +3126 -0
- package/node_modules/@sema/nucleo/src/semantico/estruturas.ts +665 -0
- package/node_modules/@sema/nucleo/src/semantico/seguranca.ts +362 -0
- package/node_modules/@sema/nucleo/src/util/arquivos.ts +28 -0
- package/node_modules/@sema/nucleo/tsconfig.json +9 -0
- package/node_modules/@sema/nucleo/tsconfig.tsbuildinfo +1 -0
- package/node_modules/@sema/padroes/package.json +10 -7
- package/node_modules/@sema/padroes/src/index.ts +382 -0
- package/node_modules/@sema/padroes/tsconfig.json +9 -0
- package/node_modules/@sema/padroes/tsconfig.tsbuildinfo +1 -0
- package/package.json +74 -75
- package/AGENTS.md +0 -294
- package/AGENT_CONTEXT_PACK.json +0 -164
- package/LICENSE +0 -22
- package/SEMA_BRIEF.curto.txt +0 -11
- package/SEMA_BRIEF.md +0 -511
- package/SEMA_BRIEF.micro.txt +0 -9
- package/SEMA_INDEX.json +0 -7588
- package/docs/AGENT_STARTER.md +0 -109
- package/docs/api.md +0 -82
- package/docs/cli.md +0 -175
- package/docs/como-ensinar-a-sema-para-ia.md +0 -155
- package/docs/deploy.md +0 -93
- package/docs/documentacao.md +0 -88
- package/docs/env.md +0 -105
- package/docs/extensao-vscode.md +0 -53
- package/docs/fluxo-pratico-ia-sema.md +0 -187
- package/docs/instalacao-e-primeiro-uso.md +0 -134
- package/docs/integracao-com-ia.md +0 -110
- package/docs/mcp.md +0 -292
- package/docs/pagamento-ponta-a-ponta.md +0 -171
- package/docs/persistencia-vendor-first.md +0 -151
- package/docs/prompt-base-ia-sema.md +0 -111
- package/docs/repositories.md +0 -54
- package/docs/rollback.md +0 -49
- package/docs/seguranca.md +0 -126
- package/docs/sintaxe.md +0 -218
- package/llms-full.txt +0 -35
- package/llms.txt +0 -18
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
// Melhoria de mensagens de erro SEM0xx
|
|
2
|
+
// Contrato: cli_melhoria_erros.sema
|
|
3
|
+
|
|
4
|
+
export interface ErroSemantico {
|
|
5
|
+
codigo: string;
|
|
6
|
+
mensagem: string;
|
|
7
|
+
dica?: string;
|
|
8
|
+
arquivo?: string;
|
|
9
|
+
linha?: number;
|
|
10
|
+
coluna?: number;
|
|
11
|
+
localizacao?: {
|
|
12
|
+
arquivo?: string;
|
|
13
|
+
linha?: number;
|
|
14
|
+
coluna?: number;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface MensagemMelhorada {
|
|
19
|
+
mensagemMelhorada: string;
|
|
20
|
+
snippetCorrecao: string;
|
|
21
|
+
explicacao: string;
|
|
22
|
+
documentacaoLink: string;
|
|
23
|
+
gravidade: "alta" | "media" | "baixa";
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SNIPPETS_CORRECAO: Record<string, (nomeElemento: string) => string> = {
|
|
27
|
+
SEM094: (nome) => ` auth {
|
|
28
|
+
modo: obrigatorio // ou: anonimo, opcional
|
|
29
|
+
}`,
|
|
30
|
+
|
|
31
|
+
SEM095: (nome) => ` authz {
|
|
32
|
+
escopo: ${nome.toLowerCase().replace(/_/g, '.')}.executar
|
|
33
|
+
papeis: [admin, editor] // ajuste conforme necessario
|
|
34
|
+
}`,
|
|
35
|
+
|
|
36
|
+
SEM096: (nome) => ` dados {
|
|
37
|
+
classificacao_padrao: interno // ou: publico, pii, financeiro, segredo
|
|
38
|
+
input {
|
|
39
|
+
campo1: interno
|
|
40
|
+
campo2: publico
|
|
41
|
+
}
|
|
42
|
+
output {
|
|
43
|
+
resultado: publico
|
|
44
|
+
}
|
|
45
|
+
}`,
|
|
46
|
+
|
|
47
|
+
SEM097: (nome) => ` audit {
|
|
48
|
+
evento: ${nome.toLowerCase().replace(/_/g, '.')}.executado
|
|
49
|
+
ator: auth.usuario
|
|
50
|
+
correlacao: request_id
|
|
51
|
+
retencao: "90d"
|
|
52
|
+
motivo: obrigatorio
|
|
53
|
+
}`,
|
|
54
|
+
|
|
55
|
+
SEM071: (nome) => ` execucao {
|
|
56
|
+
idempotencia: verdadeiro // ou: falso
|
|
57
|
+
timeout: "30s" // ajuste conforme necessidade
|
|
58
|
+
retry: "ate 3 tentativas com backoff"
|
|
59
|
+
compensacao: "descricao do rollback"
|
|
60
|
+
criticidade_operacional: alta // ou: media, baixa
|
|
61
|
+
}`,
|
|
62
|
+
|
|
63
|
+
SEM072: (nome) => ` impl {
|
|
64
|
+
ts: pacote.src.modulo.${nome} // ajuste o caminho
|
|
65
|
+
}
|
|
66
|
+
vinculos {
|
|
67
|
+
arquivo: "src/modulo/arquivo.ts"
|
|
68
|
+
simbolo: pacote.src.modulo.${nome}
|
|
69
|
+
}`
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
const EXPLICACOES: Record<string, string> = {
|
|
73
|
+
SEM094: "O bloco auth define se a task/route requer autenticacao. Isso e obrigatorio para endpoints publicos.",
|
|
74
|
+
SEM095: "O bloco authz define quem pode acessar (escopos, papeis). Sem isso, a autorizacao fica ambigua.",
|
|
75
|
+
SEM096: "O bloco dados classifica a sensibilidade dos dados (PII, financeiro, etc) para compliance.",
|
|
76
|
+
SEM097: "O bloco audit cria trilha de auditoria para rastrear quem fez o que e quando.",
|
|
77
|
+
SEM071: "O bloco execucao define timeout, retry, idempotencia - essencial para producao.",
|
|
78
|
+
SEM072: "Os vinculos ligam o contrato ao codigo real (arquivo, simbolo), permitindo drift detection."
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
export function melhorarMensagemErro(
|
|
82
|
+
erroOriginal: ErroSemantico,
|
|
83
|
+
nomeElemento: string,
|
|
84
|
+
tipoElemento: string
|
|
85
|
+
): MensagemMelhorada {
|
|
86
|
+
const codigo = erroOriginal.codigo;
|
|
87
|
+
|
|
88
|
+
// Gerar snippet de correcao
|
|
89
|
+
const geradorSnippet = SNIPPETS_CORRECAO[codigo];
|
|
90
|
+
const snippet = geradorSnippet ? geradorSnippet(nomeElemento) : "// Consulte a documentacao para corrigir";
|
|
91
|
+
|
|
92
|
+
// Construir mensagem melhorada
|
|
93
|
+
let mensagemMelhorada = erroOriginal.mensagem;
|
|
94
|
+
|
|
95
|
+
if (codigo === "SEM094") {
|
|
96
|
+
mensagemMelhorada = `Task/Route "${nomeElemento}" exposta publicamente nao declara auth { ... }.\n\nAdicione o bloco auth para definir se requer autenticacao:`;
|
|
97
|
+
} else if (codigo === "SEM095") {
|
|
98
|
+
mensagemMelhorada = `Task/Route "${nomeElemento}" exposta publicamente nao declara authz { ... }.\n\nAdicione o bloco authz para definir permissoes:`;
|
|
99
|
+
} else if (codigo === "SEM096") {
|
|
100
|
+
mensagemMelhorada = `Task/Route "${nomeElemento}" nao classifica dados em dados { ... }.\n\nAdicione classificacao para compliance:`;
|
|
101
|
+
} else if (codigo === "SEM097") {
|
|
102
|
+
mensagemMelhorada = `Task/Route "${nomeElemento}" nao declara audit { ... }.\n\nAdicione trilha de auditoria:`;
|
|
103
|
+
} else if (codigo === "SEM071") {
|
|
104
|
+
mensagemMelhorada = `Task "${nomeElemento}" exposta publicamente requer execucao { ... } explicita.\n\nAdicione configuracao de execucao:`;
|
|
105
|
+
} else if (codigo === "SEM072") {
|
|
106
|
+
mensagemMelhorada = `Task "${nomeElemento}" exposta publicamente requer impl/vinculos { ... }.\n\nAdicione rastreabilidade ao codigo:`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
mensagemMelhorada,
|
|
111
|
+
snippetCorrecao: snippet,
|
|
112
|
+
explicacao: EXPLICACOES[codigo] || erroOriginal.dica || "Consulte a documentacao.",
|
|
113
|
+
documentacaoLink: `https://sema.otimitare.online/docs/erros/${codigo}`,
|
|
114
|
+
gravidade: codigo.startsWith("SEM09") ? "alta" : "media"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
export function formatarErroMelhorado(erro: ErroSemantico, mensagemMelhorada: MensagemMelhorada): string {
|
|
119
|
+
return `
|
|
120
|
+
❌ ${erro.codigo}: ${mensagemMelhorada.mensagemMelhorada}
|
|
121
|
+
|
|
122
|
+
📝 Snippet de correcao:
|
|
123
|
+
${mensagemMelhorada.snippetCorrecao}
|
|
124
|
+
|
|
125
|
+
💡 ${mensagemMelhorada.explicacao}
|
|
126
|
+
|
|
127
|
+
📖 Documentacao: ${mensagemMelhorada.documentacaoLink}
|
|
128
|
+
📍 ${erro.localizacao?.arquivo ?? erro.arquivo}:${erro.localizacao?.linha ?? erro.linha}:${erro.localizacao?.coluna ?? erro.coluna}
|
|
129
|
+
`;
|
|
130
|
+
}
|
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BlocoAst,
|
|
3
|
+
BlocoCasoTesteAst,
|
|
4
|
+
BlocoGenericoAst,
|
|
5
|
+
CampoAst,
|
|
6
|
+
EntityAst,
|
|
7
|
+
EnumAst,
|
|
8
|
+
FlowAst,
|
|
9
|
+
ModuloAst,
|
|
10
|
+
RouteAst,
|
|
11
|
+
StateAst,
|
|
12
|
+
TaskAst,
|
|
13
|
+
TypeAst,
|
|
14
|
+
UseAst,
|
|
15
|
+
} from "../ast/tipos.js";
|
|
16
|
+
import type { Diagnostico } from "../diagnosticos/index.js";
|
|
17
|
+
import { parsear } from "../parser/parser.js";
|
|
18
|
+
import { tokenizar } from "../lexer/lexer.js";
|
|
19
|
+
|
|
20
|
+
const ORDEM_BLOCOS_MODULO = new Map<string, number>([
|
|
21
|
+
["docs", 0],
|
|
22
|
+
["comments", 1],
|
|
23
|
+
["use", 2],
|
|
24
|
+
["vinculos", 3],
|
|
25
|
+
["database", 4],
|
|
26
|
+
["type", 5],
|
|
27
|
+
["entity", 6],
|
|
28
|
+
["enum", 7],
|
|
29
|
+
["state", 8],
|
|
30
|
+
["task", 9],
|
|
31
|
+
["flow", 10],
|
|
32
|
+
["route", 11],
|
|
33
|
+
["worker", 12],
|
|
34
|
+
["evento", 13],
|
|
35
|
+
["fila", 14],
|
|
36
|
+
["cron", 15],
|
|
37
|
+
["webhook", 16],
|
|
38
|
+
["cache", 17],
|
|
39
|
+
["storage", 18],
|
|
40
|
+
["policy", 19],
|
|
41
|
+
["tests", 20],
|
|
42
|
+
["desconhecido", 21],
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const ORDEM_SUBBLOCOS_TASK = new Map<string, number>([
|
|
46
|
+
["docs", 0],
|
|
47
|
+
["comments", 1],
|
|
48
|
+
["input", 2],
|
|
49
|
+
["output", 3],
|
|
50
|
+
["rules", 4],
|
|
51
|
+
["effects", 5],
|
|
52
|
+
["auth", 6],
|
|
53
|
+
["authz", 7],
|
|
54
|
+
["dados", 8],
|
|
55
|
+
["audit", 9],
|
|
56
|
+
["segredos", 10],
|
|
57
|
+
["forbidden", 11],
|
|
58
|
+
["impl", 12],
|
|
59
|
+
["vinculos", 13],
|
|
60
|
+
["execucao", 14],
|
|
61
|
+
["state", 15],
|
|
62
|
+
["guarantees", 16],
|
|
63
|
+
["error", 17],
|
|
64
|
+
["tests", 18],
|
|
65
|
+
["desconhecido", 19],
|
|
66
|
+
]);
|
|
67
|
+
|
|
68
|
+
const ORDEM_SUBBLOCOS_ROUTE = new Map<string, number>([
|
|
69
|
+
["input", 0],
|
|
70
|
+
["output", 1],
|
|
71
|
+
["effects", 2],
|
|
72
|
+
["auth", 3],
|
|
73
|
+
["authz", 4],
|
|
74
|
+
["dados", 5],
|
|
75
|
+
["audit", 6],
|
|
76
|
+
["segredos", 7],
|
|
77
|
+
["forbidden", 8],
|
|
78
|
+
["vinculos", 9],
|
|
79
|
+
["error", 10],
|
|
80
|
+
["docs", 11],
|
|
81
|
+
["comments", 12],
|
|
82
|
+
["desconhecido", 13],
|
|
83
|
+
]);
|
|
84
|
+
|
|
85
|
+
const ORDEM_SUBBLOCOS_FLOW = new Map<string, number>([
|
|
86
|
+
["effects", 0],
|
|
87
|
+
["vinculos", 1],
|
|
88
|
+
["docs", 2],
|
|
89
|
+
["comments", 3],
|
|
90
|
+
["desconhecido", 4],
|
|
91
|
+
]);
|
|
92
|
+
|
|
93
|
+
const ORDEM_SUBBLOCOS_SUPERFICIE = new Map<string, number>([
|
|
94
|
+
["input", 0],
|
|
95
|
+
["output", 1],
|
|
96
|
+
["effects", 2],
|
|
97
|
+
["auth", 3],
|
|
98
|
+
["authz", 4],
|
|
99
|
+
["dados", 5],
|
|
100
|
+
["audit", 6],
|
|
101
|
+
["segredos", 7],
|
|
102
|
+
["forbidden", 8],
|
|
103
|
+
["impl", 9],
|
|
104
|
+
["vinculos", 10],
|
|
105
|
+
["execucao", 11],
|
|
106
|
+
["error", 12],
|
|
107
|
+
["docs", 13],
|
|
108
|
+
["comments", 14],
|
|
109
|
+
["desconhecido", 15],
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const ORDEM_SUBBLOCOS_STATE = new Map<string, number>([
|
|
113
|
+
["fields", 0],
|
|
114
|
+
["invariants", 1],
|
|
115
|
+
["transitions", 2],
|
|
116
|
+
["docs", 3],
|
|
117
|
+
["comments", 4],
|
|
118
|
+
["desconhecido", 5],
|
|
119
|
+
]);
|
|
120
|
+
|
|
121
|
+
const ORDEM_SUBBLOCOS_TESTE = new Map<string, number>([
|
|
122
|
+
["given", 0],
|
|
123
|
+
["when", 1],
|
|
124
|
+
["expect", 2],
|
|
125
|
+
["error", 3],
|
|
126
|
+
["docs", 4],
|
|
127
|
+
["comments", 5],
|
|
128
|
+
["desconhecido", 6],
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
const ORDEM_CAMPOS_POR_BLOCO = new Map<string, Map<string, number>>([
|
|
132
|
+
["vinculos", new Map<string, number>([
|
|
133
|
+
["arquivo", 0],
|
|
134
|
+
["simbolo", 1],
|
|
135
|
+
["rota", 2],
|
|
136
|
+
["superficie", 3],
|
|
137
|
+
["recurso", 4],
|
|
138
|
+
["tabela", 5],
|
|
139
|
+
["fila", 6],
|
|
140
|
+
["worker", 7],
|
|
141
|
+
["evento", 8],
|
|
142
|
+
["cron", 9],
|
|
143
|
+
["webhook", 10],
|
|
144
|
+
["cache", 11],
|
|
145
|
+
["storage", 12],
|
|
146
|
+
["policy", 13],
|
|
147
|
+
["teste", 14],
|
|
148
|
+
])],
|
|
149
|
+
["execucao", new Map<string, number>([
|
|
150
|
+
["idempotencia", 0],
|
|
151
|
+
["timeout", 1],
|
|
152
|
+
["retry", 2],
|
|
153
|
+
["compensacao", 3],
|
|
154
|
+
["criticidade_operacional", 4],
|
|
155
|
+
])],
|
|
156
|
+
["auth", new Map<string, number>([
|
|
157
|
+
["modo", 0],
|
|
158
|
+
["estrategia", 1],
|
|
159
|
+
["principal", 2],
|
|
160
|
+
["origem", 3],
|
|
161
|
+
])],
|
|
162
|
+
["authz", new Map<string, number>([
|
|
163
|
+
["papeis", 0],
|
|
164
|
+
["papel", 1],
|
|
165
|
+
["escopos", 2],
|
|
166
|
+
["escopo", 3],
|
|
167
|
+
["politica", 4],
|
|
168
|
+
["tenant", 5],
|
|
169
|
+
])],
|
|
170
|
+
["dados", new Map<string, number>([
|
|
171
|
+
["classificacao_padrao", 0],
|
|
172
|
+
["redacao_log", 1],
|
|
173
|
+
["retencao", 2],
|
|
174
|
+
])],
|
|
175
|
+
["audit", new Map<string, number>([
|
|
176
|
+
["evento", 0],
|
|
177
|
+
["ator", 1],
|
|
178
|
+
["correlacao", 2],
|
|
179
|
+
["retencao", 3],
|
|
180
|
+
["motivo", 4],
|
|
181
|
+
])],
|
|
182
|
+
["database", new Map<string, number>([
|
|
183
|
+
["engine", 0],
|
|
184
|
+
["schema", 1],
|
|
185
|
+
["database", 2],
|
|
186
|
+
["consistency", 3],
|
|
187
|
+
["durability", 4],
|
|
188
|
+
["transaction_model", 5],
|
|
189
|
+
["query_model", 6],
|
|
190
|
+
["portavel", 7],
|
|
191
|
+
["adapter", 8],
|
|
192
|
+
])],
|
|
193
|
+
]);
|
|
194
|
+
|
|
195
|
+
export interface ResultadoFormatacao {
|
|
196
|
+
modulo?: ModuloAst;
|
|
197
|
+
codigoFormatado?: string;
|
|
198
|
+
diagnosticos: Diagnostico[];
|
|
199
|
+
alterado: boolean;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function indentacao(nivel: number): string {
|
|
203
|
+
return " ".repeat(nivel);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function ordenarPorMapa<T>(itens: T[], extrairChave: (item: T) => string, ordem: Map<string, number>): T[] {
|
|
207
|
+
return [...itens].sort((a, b) => {
|
|
208
|
+
const ordemA = ordem.get(extrairChave(a)) ?? Number.MAX_SAFE_INTEGER;
|
|
209
|
+
const ordemB = ordem.get(extrairChave(b)) ?? Number.MAX_SAFE_INTEGER;
|
|
210
|
+
if (ordemA !== ordemB) {
|
|
211
|
+
return ordemA - ordemB;
|
|
212
|
+
}
|
|
213
|
+
return extrairChave(a).localeCompare(extrairChave(b), "pt-BR");
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
function normalizarEspacos(texto: string): string {
|
|
218
|
+
const marcadorSeta = "__SEMA_SETA__";
|
|
219
|
+
const marcadorMaiorIgual = "__SEMA_MAIOR_IGUAL__";
|
|
220
|
+
const marcadorMenorIgual = "__SEMA_MENOR_IGUAL__";
|
|
221
|
+
const marcadorIgual = "__SEMA_IGUAL__";
|
|
222
|
+
const marcadorDiferente = "__SEMA_DIFERENTE__";
|
|
223
|
+
return texto
|
|
224
|
+
.trim()
|
|
225
|
+
.replace(/\s*->\s*/g, ` ${marcadorSeta} `)
|
|
226
|
+
.replace(/\s*-\s*>\s*/g, ` ${marcadorSeta} `)
|
|
227
|
+
.replace(/\s+/g, " ")
|
|
228
|
+
.replace(/\s*,\s*/g, ", ")
|
|
229
|
+
.replace(/\(\s+/g, "(")
|
|
230
|
+
.replace(/\s+\)/g, ")")
|
|
231
|
+
.replace(/\[\s+/g, "[")
|
|
232
|
+
.replace(/\s+\]/g, "]")
|
|
233
|
+
.replace(/\s*>=\s*/g, ` ${marcadorMaiorIgual} `)
|
|
234
|
+
.replace(/\s*<=\s*/g, ` ${marcadorMenorIgual} `)
|
|
235
|
+
.replace(/\s*==\s*/g, ` ${marcadorIgual} `)
|
|
236
|
+
.replace(/\s*!=\s*/g, ` ${marcadorDiferente} `)
|
|
237
|
+
.replace(/\s*>\s*/g, " > ")
|
|
238
|
+
.replace(/\s*<\s*/g, " < ")
|
|
239
|
+
.replace(new RegExp(`\\s*${marcadorMaiorIgual}\\s*`, "g"), " >= ")
|
|
240
|
+
.replace(new RegExp(`\\s*${marcadorMenorIgual}\\s*`, "g"), " <= ")
|
|
241
|
+
.replace(new RegExp(`\\s*${marcadorIgual}\\s*`, "g"), " == ")
|
|
242
|
+
.replace(new RegExp(`\\s*${marcadorDiferente}\\s*`, "g"), " != ")
|
|
243
|
+
.replace(new RegExp(`\\s*${marcadorSeta}\\s*`, "g"), " -> ");
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function normalizarCaminho(texto: string): string {
|
|
247
|
+
return texto
|
|
248
|
+
.trim()
|
|
249
|
+
.replace(/\s*\/\s*/g, "/")
|
|
250
|
+
.replace(/\s+/g, "");
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function eLiteralEscalar(texto: string): boolean {
|
|
254
|
+
const normalizado = texto.trim();
|
|
255
|
+
return /^-?\d+(?:\.\d+)?$/.test(normalizado) || ["verdadeiro", "falso", "nulo"].includes(normalizado);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function deveColocarAspas(contexto: string, campo: CampoAst, combinado: string): boolean {
|
|
259
|
+
if (campo.nome === "metodo") {
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
if (campo.nome === "caminho") {
|
|
263
|
+
return /[{}]/.test(combinado);
|
|
264
|
+
}
|
|
265
|
+
if (contexto === "vinculos" && ["arquivo", "webhook"].includes(campo.nome)) {
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
if (["timeout", "retry", "compensacao", "retencao", "rotacao"].includes(campo.nome)) {
|
|
269
|
+
return true;
|
|
270
|
+
}
|
|
271
|
+
if (contexto === "docs" || contexto === "comments") {
|
|
272
|
+
return true;
|
|
273
|
+
}
|
|
274
|
+
if (contexto === "error") {
|
|
275
|
+
return !eLiteralEscalar(combinado);
|
|
276
|
+
}
|
|
277
|
+
if (contexto === "given" || contexto === "when" || contexto === "expect") {
|
|
278
|
+
return !eLiteralEscalar(combinado);
|
|
279
|
+
}
|
|
280
|
+
return false;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
function normalizarValorCampo(campo: CampoAst): string {
|
|
284
|
+
return [campo.valor, ...campo.modificadores]
|
|
285
|
+
.filter(Boolean)
|
|
286
|
+
.join(" ")
|
|
287
|
+
.replace(/\s+/g, " ")
|
|
288
|
+
.trim();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
function ordenarCampos(bloco: BlocoGenericoAst): CampoAst[] {
|
|
292
|
+
const ordem = ORDEM_CAMPOS_POR_BLOCO.get(bloco.palavraChave);
|
|
293
|
+
if (!ordem) {
|
|
294
|
+
return bloco.campos;
|
|
295
|
+
}
|
|
296
|
+
return ordenarPorMapa(bloco.campos, (campo) => campo.nome, ordem);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function renderizarCampo(campo: CampoAst, nivel: number, contexto: string): string {
|
|
300
|
+
let combinado = normalizarValorCampo(campo);
|
|
301
|
+
|
|
302
|
+
if (campo.nome === "caminho") {
|
|
303
|
+
combinado = normalizarCaminho(combinado);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (deveColocarAspas(contexto, campo, combinado)) {
|
|
307
|
+
combinado = JSON.stringify(combinado);
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
return `${indentacao(nivel)}${campo.nome}: ${combinado}`;
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function renderizarLinha(linha: string, nivel: number): string {
|
|
314
|
+
return `${indentacao(nivel)}${normalizarEspacos(linha)}`;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
function renderizarCasoTeste(caso: BlocoCasoTesteAst, nivel: number): string {
|
|
318
|
+
const partes: string[] = [];
|
|
319
|
+
if (caso.given) {
|
|
320
|
+
partes.push(renderizarBlocoGenerico(caso.given, nivel + 1));
|
|
321
|
+
}
|
|
322
|
+
if (caso.when) {
|
|
323
|
+
partes.push(renderizarBlocoGenerico(caso.when, nivel + 1));
|
|
324
|
+
}
|
|
325
|
+
if (caso.expect) {
|
|
326
|
+
partes.push(renderizarBlocoGenerico(caso.expect, nivel + 1));
|
|
327
|
+
}
|
|
328
|
+
if (caso.error) {
|
|
329
|
+
partes.push(renderizarBlocoGenerico(caso.error, nivel + 1));
|
|
330
|
+
}
|
|
331
|
+
if (caso.docs) {
|
|
332
|
+
partes.push(renderizarBlocoGenerico(caso.docs, nivel + 1));
|
|
333
|
+
}
|
|
334
|
+
if (caso.comments) {
|
|
335
|
+
partes.push(renderizarBlocoGenerico(caso.comments, nivel + 1));
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return `${indentacao(nivel)}caso ${JSON.stringify(caso.nome)} {\n${partes.join("\n\n")}\n${indentacao(nivel)}}`;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function renderizarBlocoAst(bloco: BlocoAst, nivel: number): string {
|
|
342
|
+
switch (bloco.tipo) {
|
|
343
|
+
case "caso_teste":
|
|
344
|
+
return renderizarCasoTeste(bloco, nivel);
|
|
345
|
+
case "bloco_generico":
|
|
346
|
+
return renderizarBlocoGenerico(bloco, nivel);
|
|
347
|
+
case "use":
|
|
348
|
+
return `${indentacao(nivel)}use ${bloco.origem === "sema" ? "" : `${bloco.origem} `}${bloco.caminho}`.trimEnd();
|
|
349
|
+
case "enum":
|
|
350
|
+
return renderizarEnum(bloco, nivel);
|
|
351
|
+
case "type":
|
|
352
|
+
return renderizarTipo(bloco, nivel);
|
|
353
|
+
case "entity":
|
|
354
|
+
return renderizarEntity(bloco, nivel);
|
|
355
|
+
case "task":
|
|
356
|
+
return renderizarTask(bloco, nivel);
|
|
357
|
+
case "flow":
|
|
358
|
+
return renderizarFlow(bloco, nivel);
|
|
359
|
+
case "route":
|
|
360
|
+
return renderizarRoute(bloco, nivel);
|
|
361
|
+
case "state":
|
|
362
|
+
return renderizarState(bloco, nivel);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
function ordenarSubblocos(bloco: BlocoGenericoAst): BlocoAst[] {
|
|
367
|
+
if (bloco.palavraChave === "task") {
|
|
368
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_TASK);
|
|
369
|
+
}
|
|
370
|
+
if (bloco.palavraChave === "route") {
|
|
371
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_ROUTE);
|
|
372
|
+
}
|
|
373
|
+
if (bloco.palavraChave === "flow") {
|
|
374
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_FLOW);
|
|
375
|
+
}
|
|
376
|
+
if (["worker", "evento", "fila", "cron", "webhook", "cache", "storage", "policy"].includes(bloco.palavraChave)) {
|
|
377
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_SUPERFICIE);
|
|
378
|
+
}
|
|
379
|
+
if (bloco.palavraChave === "state") {
|
|
380
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_STATE);
|
|
381
|
+
}
|
|
382
|
+
if (bloco.palavraChave === "tests") {
|
|
383
|
+
return ordenarPorMapa(bloco.blocos, (item) => item.tipo === "caso_teste" ? "case" : item.tipo === "bloco_generico" ? item.palavraChave : item.tipo, ORDEM_SUBBLOCOS_TESTE);
|
|
384
|
+
}
|
|
385
|
+
return bloco.blocos;
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function renderizarBlocoGenerico(bloco: BlocoGenericoAst, nivel: number): string {
|
|
389
|
+
const identificadorBloco = bloco.palavraChave === "desconhecido" && bloco.nome
|
|
390
|
+
? bloco.nome
|
|
391
|
+
: `${bloco.palavraChave}${bloco.nome ? ` ${bloco.nome}` : ""}`;
|
|
392
|
+
const cabecalho = `${indentacao(nivel)}${identificadorBloco} {`;
|
|
393
|
+
const linhasCampos = ordenarCampos(bloco).map((campo) => renderizarCampo(campo, nivel + 1, bloco.palavraChave));
|
|
394
|
+
const linhasDeclarativas = bloco.linhas.map((linha) => renderizarLinha(linha.conteudo, nivel + 1));
|
|
395
|
+
const blocosInternos = ordenarSubblocos(bloco).map((subbloco) => renderizarBlocoAst(subbloco, nivel + 1));
|
|
396
|
+
const corpo = [...linhasCampos, ...linhasDeclarativas, ...blocosInternos];
|
|
397
|
+
if (corpo.length === 0) {
|
|
398
|
+
return `${cabecalho}\n${indentacao(nivel)}}`;
|
|
399
|
+
}
|
|
400
|
+
return `${cabecalho}\n${corpo.join("\n")}\n${indentacao(nivel)}}`;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function renderizarEnum(enumeracao: EnumAst, nivel: number): string {
|
|
404
|
+
const corpo = enumeracao.valores.map((valor, indice) => `${indentacao(nivel + 1)}${valor}${indice < enumeracao.valores.length - 1 ? "," : ""}`);
|
|
405
|
+
return `${indentacao(nivel)}enum ${enumeracao.nome} {\n${corpo.join("\n")}\n${indentacao(nivel)}}`;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
function renderizarTipo(type: TypeAst, nivel: number): string {
|
|
409
|
+
return `${indentacao(nivel)}type ${type.nome} {\n${renderizarCorpoSimples(type.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function renderizarEntity(entity: EntityAst, nivel: number): string {
|
|
413
|
+
return `${indentacao(nivel)}entity ${entity.nome} {\n${renderizarCorpoSimples(entity.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
function renderizarTask(task: TaskAst, nivel: number): string {
|
|
417
|
+
return `${indentacao(nivel)}task ${task.nome} {\n${renderizarCorpoSimples(task.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function renderizarFlow(flow: FlowAst, nivel: number): string {
|
|
421
|
+
return `${indentacao(nivel)}flow ${flow.nome} {\n${renderizarCorpoSimples(flow.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
function renderizarRoute(route: RouteAst, nivel: number): string {
|
|
425
|
+
return `${indentacao(nivel)}route ${route.nome} {\n${renderizarCorpoSimples(route.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function renderizarState(state: StateAst, nivel: number): string {
|
|
429
|
+
return `${indentacao(nivel)}state${state.nome ? ` ${state.nome}` : ""} {\n${renderizarCorpoSimples(state.corpo, nivel + 1)}\n${indentacao(nivel)}}`;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function renderizarCorpoSimples(bloco: BlocoGenericoAst, nivel: number): string {
|
|
433
|
+
const conteudo = ordenarSubblocos(bloco).map((subbloco) => renderizarBlocoAst(subbloco, nivel));
|
|
434
|
+
const campos = ordenarCampos(bloco).map((campo) => renderizarCampo(campo, nivel, bloco.palavraChave));
|
|
435
|
+
const linhas = bloco.linhas.map((linha) => renderizarLinha(linha.conteudo, nivel));
|
|
436
|
+
const corpo = [...campos, ...linhas, ...conteudo];
|
|
437
|
+
return corpo.join("\n");
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function renderizarModulo(modulo: ModuloAst): string {
|
|
441
|
+
const blocos: Array<{ chave: string; conteudo: string }> = [];
|
|
442
|
+
|
|
443
|
+
if (modulo.docs) {
|
|
444
|
+
blocos.push({ chave: "docs", conteudo: renderizarBlocoGenerico(modulo.docs, 1) });
|
|
445
|
+
}
|
|
446
|
+
if (modulo.comments) {
|
|
447
|
+
blocos.push({ chave: "comments", conteudo: renderizarBlocoGenerico(modulo.comments, 1) });
|
|
448
|
+
}
|
|
449
|
+
for (const use of modulo.uses) {
|
|
450
|
+
blocos.push({ chave: "use", conteudo: renderizarBlocoAst(use, 1) });
|
|
451
|
+
}
|
|
452
|
+
if (modulo.vinculos) {
|
|
453
|
+
blocos.push({ chave: "vinculos", conteudo: renderizarBlocoGenerico(modulo.vinculos, 1) });
|
|
454
|
+
}
|
|
455
|
+
for (const database of modulo.databases) {
|
|
456
|
+
blocos.push({ chave: "database", conteudo: renderizarBlocoGenerico(database, 1) });
|
|
457
|
+
}
|
|
458
|
+
for (const type of modulo.types) {
|
|
459
|
+
blocos.push({ chave: "type", conteudo: renderizarBlocoAst(type, 1) });
|
|
460
|
+
}
|
|
461
|
+
for (const entity of modulo.entities) {
|
|
462
|
+
blocos.push({ chave: "entity", conteudo: renderizarBlocoAst(entity, 1) });
|
|
463
|
+
}
|
|
464
|
+
for (const enumeracao of modulo.enums) {
|
|
465
|
+
blocos.push({ chave: "enum", conteudo: renderizarBlocoAst(enumeracao, 1) });
|
|
466
|
+
}
|
|
467
|
+
for (const state of modulo.states) {
|
|
468
|
+
blocos.push({ chave: "state", conteudo: renderizarBlocoAst(state, 1) });
|
|
469
|
+
}
|
|
470
|
+
for (const task of modulo.tasks) {
|
|
471
|
+
blocos.push({ chave: "task", conteudo: renderizarBlocoAst(task, 1) });
|
|
472
|
+
}
|
|
473
|
+
for (const flow of modulo.flows) {
|
|
474
|
+
blocos.push({ chave: "flow", conteudo: renderizarBlocoAst(flow, 1) });
|
|
475
|
+
}
|
|
476
|
+
for (const route of modulo.routes) {
|
|
477
|
+
blocos.push({ chave: "route", conteudo: renderizarBlocoAst(route, 1) });
|
|
478
|
+
}
|
|
479
|
+
for (const worker of modulo.workers) {
|
|
480
|
+
blocos.push({ chave: "worker", conteudo: renderizarBlocoGenerico(worker, 1) });
|
|
481
|
+
}
|
|
482
|
+
for (const evento of modulo.eventos) {
|
|
483
|
+
blocos.push({ chave: "evento", conteudo: renderizarBlocoGenerico(evento, 1) });
|
|
484
|
+
}
|
|
485
|
+
for (const fila of modulo.filas) {
|
|
486
|
+
blocos.push({ chave: "fila", conteudo: renderizarBlocoGenerico(fila, 1) });
|
|
487
|
+
}
|
|
488
|
+
for (const cron of modulo.crons) {
|
|
489
|
+
blocos.push({ chave: "cron", conteudo: renderizarBlocoGenerico(cron, 1) });
|
|
490
|
+
}
|
|
491
|
+
for (const webhook of modulo.webhooks) {
|
|
492
|
+
blocos.push({ chave: "webhook", conteudo: renderizarBlocoGenerico(webhook, 1) });
|
|
493
|
+
}
|
|
494
|
+
for (const cache of modulo.caches) {
|
|
495
|
+
blocos.push({ chave: "cache", conteudo: renderizarBlocoGenerico(cache, 1) });
|
|
496
|
+
}
|
|
497
|
+
for (const storage of modulo.storages) {
|
|
498
|
+
blocos.push({ chave: "storage", conteudo: renderizarBlocoGenerico(storage, 1) });
|
|
499
|
+
}
|
|
500
|
+
for (const policy of modulo.policies) {
|
|
501
|
+
blocos.push({ chave: "policy", conteudo: renderizarBlocoGenerico(policy, 1) });
|
|
502
|
+
}
|
|
503
|
+
if (modulo.tests) {
|
|
504
|
+
blocos.push({ chave: "tests", conteudo: renderizarBlocoGenerico(modulo.tests, 1) });
|
|
505
|
+
}
|
|
506
|
+
for (const extra of modulo.extras) {
|
|
507
|
+
blocos.push({ chave: "desconhecido", conteudo: renderizarBlocoGenerico(extra, 1) });
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
const ordenados = ordenarPorMapa(blocos, (item) => item.chave, ORDEM_BLOCOS_MODULO);
|
|
511
|
+
return `module ${modulo.nome} {\n${ordenados.map((item) => item.conteudo).join("\n\n")}\n}\n`;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export function formatarCodigo(codigo: string, arquivo?: string): ResultadoFormatacao {
|
|
515
|
+
const resultadoLexer = tokenizar(codigo, arquivo);
|
|
516
|
+
const resultadoParser = parsear(resultadoLexer.tokens);
|
|
517
|
+
const diagnosticos = [...resultadoLexer.diagnosticos, ...resultadoParser.diagnosticos];
|
|
518
|
+
|
|
519
|
+
if (!resultadoParser.modulo) {
|
|
520
|
+
return { diagnosticos, alterado: false };
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
const codigoFormatado = renderizarModulo(resultadoParser.modulo);
|
|
524
|
+
return {
|
|
525
|
+
modulo: resultadoParser.modulo,
|
|
526
|
+
codigoFormatado,
|
|
527
|
+
diagnosticos,
|
|
528
|
+
alterado: codigoFormatado !== codigo,
|
|
529
|
+
};
|
|
530
|
+
}
|