@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.
Files changed (105) hide show
  1. package/dist/comandos.js +69 -0
  2. package/dist/comandos.js.map +1 -1
  3. package/dist/dev/index.d.ts +18 -0
  4. package/dist/dev/index.js +143 -0
  5. package/dist/dev/index.js.map +1 -0
  6. package/dist/guard.d.ts +35 -0
  7. package/dist/guard.js +164 -0
  8. package/dist/guard.js.map +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/init/index.d.ts +23 -0
  11. package/dist/init/index.js +112 -0
  12. package/dist/init/index.js.map +1 -0
  13. package/dist/init/templates.d.ts +11 -0
  14. package/dist/init/templates.js +660 -0
  15. package/dist/init/templates.js.map +1 -0
  16. package/dist/sync/index.d.ts +24 -0
  17. package/dist/sync/index.js +174 -0
  18. package/dist/sync/index.js.map +1 -0
  19. package/exemplos/.prepack-generated +1 -0
  20. package/node_modules/@sema/gerador-css/package.json +14 -7
  21. package/node_modules/@sema/gerador-css/src/index.ts +605 -0
  22. package/node_modules/@sema/gerador-css/tsconfig.json +13 -0
  23. package/node_modules/@sema/gerador-css/tsconfig.tsbuildinfo +1 -0
  24. package/node_modules/@sema/gerador-dart/package.json +14 -7
  25. package/node_modules/@sema/gerador-dart/src/index.ts +52 -0
  26. package/node_modules/@sema/gerador-dart/tsconfig.json +13 -0
  27. package/node_modules/@sema/gerador-dart/tsconfig.tsbuildinfo +1 -0
  28. package/node_modules/@sema/gerador-html/package.json +14 -7
  29. package/node_modules/@sema/gerador-html/src/index.ts +185 -0
  30. package/node_modules/@sema/gerador-html/tsconfig.json +13 -0
  31. package/node_modules/@sema/gerador-html/tsconfig.tsbuildinfo +1 -0
  32. package/node_modules/@sema/gerador-javascript/package.json +14 -7
  33. package/node_modules/@sema/gerador-javascript/src/index.ts +461 -0
  34. package/node_modules/@sema/gerador-javascript/tsconfig.json +13 -0
  35. package/node_modules/@sema/gerador-javascript/tsconfig.tsbuildinfo +1 -0
  36. package/node_modules/@sema/gerador-lua/package.json +14 -7
  37. package/node_modules/@sema/gerador-lua/src/index.ts +359 -0
  38. package/node_modules/@sema/gerador-lua/tsconfig.json +13 -0
  39. package/node_modules/@sema/gerador-lua/tsconfig.tsbuildinfo +1 -0
  40. package/node_modules/@sema/gerador-python/package.json +14 -7
  41. package/node_modules/@sema/gerador-python/src/index.ts +850 -0
  42. package/node_modules/@sema/gerador-python/tsconfig.json +13 -0
  43. package/node_modules/@sema/gerador-python/tsconfig.tsbuildinfo +1 -0
  44. package/node_modules/@sema/gerador-typescript/package.json +14 -7
  45. package/node_modules/@sema/gerador-typescript/src/index.ts +876 -0
  46. package/node_modules/@sema/gerador-typescript/tsconfig.json +13 -0
  47. package/node_modules/@sema/gerador-typescript/tsconfig.tsbuildinfo +1 -0
  48. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.d.ts +22 -0
  49. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +97 -0
  50. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js.map +1 -0
  51. package/node_modules/@sema/nucleo/dist/index.d.ts +1 -0
  52. package/node_modules/@sema/nucleo/dist/index.js +1 -0
  53. package/node_modules/@sema/nucleo/dist/index.js.map +1 -1
  54. package/node_modules/@sema/nucleo/package.json +10 -7
  55. package/node_modules/@sema/nucleo/src/ast/tipos.ts +207 -0
  56. package/node_modules/@sema/nucleo/src/diagnosticos/index.ts +43 -0
  57. package/node_modules/@sema/nucleo/src/diagnosticos/melhorador.ts +130 -0
  58. package/node_modules/@sema/nucleo/src/formatador/index.ts +530 -0
  59. package/node_modules/@sema/nucleo/src/index.ts +184 -0
  60. package/node_modules/@sema/nucleo/src/ir/conversor.ts +1037 -0
  61. package/node_modules/@sema/nucleo/src/ir/modelos.ts +403 -0
  62. package/node_modules/@sema/nucleo/src/lexer/lexer.ts +166 -0
  63. package/node_modules/@sema/nucleo/src/lexer/tokens.ts +79 -0
  64. package/node_modules/@sema/nucleo/src/parser/gramatica.ebnf +41 -0
  65. package/node_modules/@sema/nucleo/src/parser/parser.ts +936 -0
  66. package/node_modules/@sema/nucleo/src/persistencia/contratos.ts +379 -0
  67. package/node_modules/@sema/nucleo/src/semantico/analisador.ts +3126 -0
  68. package/node_modules/@sema/nucleo/src/semantico/estruturas.ts +665 -0
  69. package/node_modules/@sema/nucleo/src/semantico/seguranca.ts +362 -0
  70. package/node_modules/@sema/nucleo/src/util/arquivos.ts +28 -0
  71. package/node_modules/@sema/nucleo/tsconfig.json +9 -0
  72. package/node_modules/@sema/nucleo/tsconfig.tsbuildinfo +1 -0
  73. package/node_modules/@sema/padroes/package.json +10 -7
  74. package/node_modules/@sema/padroes/src/index.ts +382 -0
  75. package/node_modules/@sema/padroes/tsconfig.json +9 -0
  76. package/node_modules/@sema/padroes/tsconfig.tsbuildinfo +1 -0
  77. package/package.json +74 -75
  78. package/AGENTS.md +0 -294
  79. package/AGENT_CONTEXT_PACK.json +0 -164
  80. package/LICENSE +0 -22
  81. package/SEMA_BRIEF.curto.txt +0 -11
  82. package/SEMA_BRIEF.md +0 -511
  83. package/SEMA_BRIEF.micro.txt +0 -9
  84. package/SEMA_INDEX.json +0 -7588
  85. package/docs/AGENT_STARTER.md +0 -109
  86. package/docs/api.md +0 -82
  87. package/docs/cli.md +0 -175
  88. package/docs/como-ensinar-a-sema-para-ia.md +0 -155
  89. package/docs/deploy.md +0 -93
  90. package/docs/documentacao.md +0 -88
  91. package/docs/env.md +0 -105
  92. package/docs/extensao-vscode.md +0 -53
  93. package/docs/fluxo-pratico-ia-sema.md +0 -187
  94. package/docs/instalacao-e-primeiro-uso.md +0 -134
  95. package/docs/integracao-com-ia.md +0 -110
  96. package/docs/mcp.md +0 -292
  97. package/docs/pagamento-ponta-a-ponta.md +0 -171
  98. package/docs/persistencia-vendor-first.md +0 -151
  99. package/docs/prompt-base-ia-sema.md +0 -111
  100. package/docs/repositories.md +0 -54
  101. package/docs/rollback.md +0 -49
  102. package/docs/seguranca.md +0 -126
  103. package/docs/sintaxe.md +0 -218
  104. package/llms-full.txt +0 -35
  105. 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
+ }