@semacode/cli 1.3.7 → 1.4.0

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 (46) hide show
  1. package/README.md +61 -41
  2. package/dist/drift.d.ts +5 -3
  3. package/dist/drift.js +532 -27
  4. package/dist/drift.js.map +1 -1
  5. package/dist/importador.d.ts +2 -0
  6. package/dist/importador.js +166 -7
  7. package/dist/importador.js.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/projeto.d.ts +6 -1
  11. package/dist/projeto.js.map +1 -1
  12. package/docs/cli.md +101 -0
  13. package/docs/instalacao-e-primeiro-uso.md +108 -196
  14. package/docs/integracao-com-ia.md +43 -200
  15. package/docs/persistencia-vendor-first.md +145 -0
  16. package/docs/sintaxe.md +67 -251
  17. package/exemplos/persistencia_vendor_first.sema +86 -0
  18. package/node_modules/@sema/gerador-css/package.json +1 -1
  19. package/node_modules/@sema/gerador-dart/package.json +1 -1
  20. package/node_modules/@sema/gerador-html/package.json +1 -1
  21. package/node_modules/@sema/gerador-javascript/package.json +1 -1
  22. package/node_modules/@sema/gerador-lua/package.json +1 -1
  23. package/node_modules/@sema/gerador-python/package.json +1 -1
  24. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  25. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +2 -1
  26. package/node_modules/@sema/nucleo/dist/formatador/index.js +32 -17
  27. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
  28. package/node_modules/@sema/nucleo/dist/index.d.ts +1 -0
  29. package/node_modules/@sema/nucleo/dist/index.js +1 -0
  30. package/node_modules/@sema/nucleo/dist/index.js.map +1 -1
  31. package/node_modules/@sema/nucleo/dist/ir/conversor.js +94 -0
  32. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  33. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +60 -0
  34. package/node_modules/@sema/nucleo/dist/lexer/tokens.js +15 -0
  35. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
  36. package/node_modules/@sema/nucleo/dist/parser/parser.js +98 -3
  37. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  38. package/node_modules/@sema/nucleo/dist/persistencia/contratos.d.ts +39 -0
  39. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js +294 -0
  40. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +1 -0
  41. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +1 -1
  42. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +118 -2
  43. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  44. package/node_modules/@sema/nucleo/package.json +1 -1
  45. package/node_modules/@sema/padroes/package.json +1 -1
  46. package/package.json +11 -11
package/docs/sintaxe.md CHANGED
@@ -1,20 +1,20 @@
1
1
  # Sintaxe Canonica
2
2
 
3
- A Sema usa blocos declarativos com chaves e forma previsivel. A regra aqui nao e "ficar bonitinho para humano"; e reduzir ambiguidade para parser, IR, drift e contexto de IA.
3
+ A Sema usa blocos declarativos previsiveis para reduzir ambiguidade no parser, na IR, no drift e no contexto de IA.
4
4
 
5
5
  ## Regras basicas
6
6
 
7
7
  - um arquivo `.sema` contem um `module` principal
8
8
  - cada bloco abre com palavra-chave e fecha com `}`
9
9
  - campos usam `nome: valor`
10
- - linhas declarativas continuam validas para regra, efeito, garantia, transicao e etapa de flow
11
- - `tests` contem blocos `caso`
12
- - quando uma palavra reservada aparece seguida de `:`, ela continua sendo campo, nao bloco
10
+ - blocos declarativos podem aparecer aninhados quando o contrato exigir
11
+ - `tests` usa blocos `caso`
13
12
 
14
13
  ## Blocos de primeira classe
15
14
 
16
15
  - `module`
17
16
  - `use`
17
+ - `database`
18
18
  - `type`
19
19
  - `entity`
20
20
  - `enum`
@@ -34,7 +34,7 @@ A Sema usa blocos declarativos com chaves e forma previsivel. A regra aqui nao e
34
34
  - `docs`
35
35
  - `comments`
36
36
 
37
- ## Subblocos mais usados
37
+ ## Subblocos comuns
38
38
 
39
39
  - `input`
40
40
  - `output`
@@ -60,8 +60,6 @@ A Sema usa blocos declarativos com chaves e forma previsivel. A regra aqui nao e
60
60
 
61
61
  ## Tipos compostos
62
62
 
63
- A Sema agora aceita formas canonicas para payload mais denso sem empurrar tudo para `Json`.
64
-
65
63
  ```sema
66
64
  input {
67
65
  ids: Lista<Id> required
@@ -79,283 +77,101 @@ Formas suportadas:
79
77
  - `T1|T2`
80
78
  - `T?`
81
79
 
82
- ## Task com contrato operacional
83
-
84
- ```sema
85
- task processar_pedido {
86
- input {
87
- pedido_id: Id required
88
- itens: Lista<Texto> required
89
- }
90
- output {
91
- protocolo: Id
92
- status: Texto
93
- }
94
- impl {
95
- ts: app.pedidos.processar
96
- }
97
- vinculos {
98
- arquivo: "src/pedidos/processar.ts"
99
- simbolo: app.pedidos.processar
100
- fila: pedidos_processamento
101
- }
102
- execucao {
103
- idempotencia: verdadeiro
104
- timeout: "30s"
105
- retry: "3x exponencial"
106
- compensacao: "reverter_reserva"
107
- criticidade_operacional: alta
108
- }
109
- effects {
110
- persistencia pedidos criticidade = alta
111
- auditoria pedidos criticidade = media
112
- }
113
- guarantees {
114
- protocolo existe
115
- status existe
116
- }
117
- error {
118
- pedido_invalido {
119
- mensagem: "payload invalido"
120
- categoria: dominio
121
- recuperabilidade: permanente
122
- acao_chamador: corrigir_input
123
- impacta_estado: falso
124
- requer_compensacao: falso
125
- }
126
- }
127
- tests {
128
- caso "processa pedido valido" {
129
- given {
130
- pedido_id: "ped_1"
131
- }
132
- expect {
133
- sucesso: verdadeiro
134
- }
135
- }
136
- }
137
- }
138
- ```
80
+ ## Persistencia vendor-first
139
81
 
140
- ## `impl`
82
+ O bloco `database` modela banco e recursos persistidos sem apagar as diferencas entre engines.
141
83
 
142
- `impl` liga a task ou a superficie ao simbolo real do runtime.
84
+ Estrutura base:
143
85
 
144
86
  ```sema
145
- impl {
146
- ts: app.pedidos.processar
147
- py: services.orders.processar
148
- cs: Pedidos.Api.Controllers.PedidosController.Processar
87
+ database principal_postgres {
88
+ engine: postgres
89
+ consistency: forte
90
+ durability: alta
91
+ transaction_model: mvcc
92
+ query_model: sql
149
93
  }
150
94
  ```
151
95
 
152
- Regras:
96
+ Recursos canonicamente suportados:
153
97
 
154
- - cada origem aparece no maximo uma vez por bloco
155
- - o caminho aponta para simbolo, nao para chamada com `()`
156
- - `ts|typescript`, `py|python`, `dart`, `cs|csharp|dotnet`, `java`, `go|golang`, `rust|rs`, `cpp|cxx|cc|c++` sao origens validas
98
+ - `table`
99
+ - `index`
100
+ - `relationship`
101
+ - `query`
102
+ - `retention`
103
+ - `lock`
104
+ - `replication`
105
+ - `collection`
106
+ - `document`
107
+ - `keyspace`
108
+ - `stream`
109
+ - `capabilities`
157
110
 
158
- ## `vinculos`
159
-
160
- `vinculos` nao substitui `impl`. Ele complementa o contrato com rastros operacionais que ajudam IA e drift a mapear o sistema vivo.
161
-
162
- Campos comuns:
163
-
164
- - `arquivo`
165
- - `simbolo`
166
- - `rota`
167
- - `superficie`
168
- - `recurso`
169
- - `tabela`
170
- - `fila`
171
- - `worker`
172
- - `evento`
173
- - `cron`
174
- - `webhook`
175
- - `cache`
176
- - `storage`
177
- - `policy`
178
-
179
- Exemplo:
111
+ Exemplo relacional:
180
112
 
181
113
  ```sema
182
- vinculos {
183
- arquivo: "pacotes/cli/src/index.ts"
184
- simbolo: cli.src.index.gerarContextoIa
185
- webhook: "/interno/contexto-ia"
186
- }
187
- ```
188
-
189
- ## `execucao`
190
-
191
- `execucao` explicita comportamento operacional em vez de deixar isso espalhado pelo codigo ou pela cabeca da IA.
192
-
193
- ```sema
194
- execucao {
195
- idempotencia: verdadeiro
196
- timeout: "15s"
197
- retry: "fila"
198
- compensacao: "nenhuma"
199
- criticidade_operacional: media
200
- }
201
- ```
202
-
203
- Campos canonicos:
204
-
205
- - `idempotencia`
206
- - `timeout`
207
- - `retry`
208
- - `compensacao`
209
- - `criticidade_operacional`
210
-
211
- ## Seguranca semantica
212
-
213
- Em `task`, `route` e superficies modernas, a Sema agora aceita contratos de seguranca explicitos para reduzir adivinhacao em producao.
214
-
215
- - `auth`: como a chamada autentica, com `modo`, `estrategia`, `principal` e `origem`
216
- - `authz`: quem pode executar, com `papel`, `escopo`, `politica` e `tenant`
217
- - `dados`: classificacao de input/output, `redacao_log` e `retencao`
218
- - `audit`: trilha obrigatoria com `evento`, `ator`, `correlacao`, `retencao` e `motivo`
219
- - `segredos`: origem, escopo, rotacao e protecoes de segredo
220
- - `forbidden`: proibicoes explicitas como `shell.exec`, `network.egress`, `log.segredo` e `retorno.credencial`
221
-
222
- Exemplo:
223
-
224
- ```sema
225
- task processar_pagamento {
226
- input {
227
- cliente_id: Id required
228
- token_gateway: Texto required
114
+ database principal_postgres {
115
+ engine: postgres
116
+ schema: public
117
+ capabilities {
118
+ joins
119
+ views
120
+ foreign_keys
229
121
  }
230
- output {
231
- protocolo: Id
232
- status: Texto
122
+ table pedidos {
123
+ entity: Pedido
233
124
  }
234
- effects {
235
- db.write Pagamento criticidade=alta privilegio=escrita isolamento=tenant
236
- secret.read gateway_api_key criticidade=media privilegio=leitura isolamento=processo
125
+ relationship pedido_cliente {
126
+ from: Pedido
127
+ to: Cliente
237
128
  }
238
- auth {
239
- modo: interno
240
- estrategia: jwt
241
- principal: servico
242
- origem: worker
243
- }
244
- authz {
245
- papel: pagamentos_admin
246
- escopo: pagamentos.processar
247
- tenant: isolado
248
- }
249
- dados {
250
- classificacao_padrao: interno
251
- redacao_log: obrigatoria
252
- retencao: "90d"
253
- input {
254
- cliente_id: pii
255
- token_gateway: credencial
256
- }
257
- output {
258
- protocolo: interno
259
- status: interno
260
- }
261
- }
262
- audit {
263
- evento: pagamentos.processado
264
- ator: auth.servico
265
- correlacao: request_id
266
- retencao: "180d"
267
- motivo: obrigatorio
268
- }
269
- segredos {
270
- gateway_api_key {
271
- origem: vault
272
- escopo: runtime
273
- acesso: gateway_pagamento
274
- rotacao: "30d"
275
- nao_logar: verdadeiro
276
- nao_retornar: verdadeiro
277
- mascarar: verdadeiro
278
- }
279
- }
280
- forbidden {
281
- shell.exec
282
- retorno.credencial
283
- log.segredo
284
- }
285
- guarantees {
286
- protocolo existe
287
- status existe
129
+ query buscar_pedidos {
130
+ mode: sql
288
131
  }
289
132
  }
290
133
  ```
291
134
 
292
- Esses blocos nao tentam implementar seguranca magica. Eles tornam a intencao auditavel por parser, IR, `drift`, `contexto-ia` e verificacao semantica.
293
-
294
- ## Superficies modernas
295
-
296
- A Sema nao fica presa em HTTP. As bordas abaixo sao blocos irmaos de `route`, com shape minimo compativel com `task`, `impl`, `vinculos`, `execucao` e `effects`.
135
+ Exemplo documental:
297
136
 
298
137
  ```sema
299
- worker preparar_briefing {
300
- task: medir_drift
301
- vinculos {
302
- arquivo: "pacotes/cli/src/index.ts"
303
- worker: contexto_ia
304
- }
305
- execucao {
306
- retry: "fila_contexto"
307
- criticidade_operacional: alta
138
+ database principal_mongodb {
139
+ engine: mongodb
140
+ query_model: documento
141
+ collection pedidos {
142
+ collection: pedidos
308
143
  }
309
- }
310
-
311
- webhook confirmar_contexto {
312
- task: mapear_projeto
313
- vinculos {
314
- webhook: "/interno/contexto-ia"
144
+ document pedido_snapshot {
145
+ entity: PedidoSnapshot
315
146
  }
316
- execucao {
317
- timeout: "15s"
318
- criticidade_operacional: media
147
+ query pipeline_pedido {
148
+ mode: pipeline
319
149
  }
320
150
  }
321
151
  ```
322
152
 
323
- ## Flow com dependencia explicita
153
+ Exemplo key-value:
324
154
 
325
155
  ```sema
326
- flow operar_contexto_ia {
327
- entrada: Texto
328
- etapa mapear usa mapear_projeto com entrada = entrada
329
- etapa drift usa medir_drift com contrato = entrada depende_de mapear
330
- etapa briefing usa preparar_briefing com entrada = entrada depende_de drift
331
- effects {
332
- auditoria contexto_ia criticidade = alta
156
+ database principal_redis {
157
+ engine: redis
158
+ query_model: chave_valor
159
+ keyspace cache_pedidos {
160
+ ttl: "300s"
333
161
  }
334
- vinculos {
335
- simbolo: cli.src.index.comandoContextoIa
162
+ stream eventos_pedido {
163
+ surface: fila
336
164
  }
337
165
  }
338
166
  ```
339
167
 
340
- ## Forma canonica
341
-
342
- O formatador passa a preferir:
343
-
344
- - `vinculos` com `arquivo` antes de `simbolo`
345
- - `auth` com `modo`, `estrategia`, `principal` e `origem`
346
- - `authz` com `papel|papeis`, `escopo|escopos`, `politica` e `tenant`
347
- - `dados` com `classificacao_padrao`, `redacao_log` e `retencao`
348
- - `audit` com `evento`, `ator`, `correlacao`, `retencao` e `motivo`
349
- - `execucao` com `idempotencia`, `timeout`, `retry`, `compensacao` e `criticidade_operacional`
350
- - strings operacionais como `arquivo`, `timeout`, `retry`, `compensacao`, `retencao` e `rotacao` com aspas
351
- - tipos compostos sem espacos quebrados em `Lista<T>` e `Mapa<K, V>`
168
+ ## Compatibilidade declarada
352
169
 
353
- ## Resumo pratico
170
+ O IR de persistencia calcula compatibilidade por recurso com quatro estados:
354
171
 
355
- Se a duvida for "isso vai ajudar a IA a editar com menos chute?", a sintaxe nova aponta para quatro coisas:
172
+ - `nativo`
173
+ - `adaptado`
174
+ - `parcial`
175
+ - `invalido`
356
176
 
357
- - contrato rico
358
- - seguranca semantica explicita
359
- - vinculo rastreavel
360
- - execucao explicita
361
- - superficie moderna de primeira classe
177
+ Isso existe para deixar explicito quando um contrato esta pedindo de um banco algo que ele nao entrega do mesmo jeito.
@@ -0,0 +1,86 @@
1
+ module exemplos.persistencia.vendor_first {
2
+ database principal_postgres {
3
+ engine: postgres
4
+ schema: public
5
+ consistency: forte
6
+ durability: alta
7
+ transaction_model: mvcc
8
+ query_model: sql
9
+ capabilities {
10
+ joins
11
+ views
12
+ }
13
+ table pedidos {
14
+ entity: Pedido
15
+ }
16
+ relationship pedido_cliente {
17
+ from: Pedido
18
+ to: Cliente
19
+ }
20
+ query buscar_pedidos {
21
+ mode: sql
22
+ }
23
+ }
24
+
25
+ database principal_mysql {
26
+ engine: mysql
27
+ consistency: forte
28
+ durability: alta
29
+ transaction_model: bloqueio
30
+ query_model: sql
31
+ table faturamento {
32
+ table: faturamento
33
+ }
34
+ query buscar_faturas {
35
+ mode: sql
36
+ }
37
+ }
38
+
39
+ database principal_sqlite {
40
+ engine: sqlite
41
+ consistency: snapshot
42
+ durability: media
43
+ transaction_model: single_thread
44
+ query_model: sql
45
+ table cache_local {
46
+ table: cache_local
47
+ }
48
+ retention limpeza_local {
49
+ retention: 7d
50
+ }
51
+ }
52
+
53
+ database principal_mongodb {
54
+ engine: mongodb
55
+ consistency: eventual
56
+ durability: alta
57
+ transaction_model: documento
58
+ query_model: documento
59
+ collection pedidos {
60
+ collection: pedidos
61
+ }
62
+ document pedido_snapshot {
63
+ entity: PedidoSnapshot
64
+ }
65
+ query pipeline_pedido {
66
+ mode: pipeline
67
+ }
68
+ }
69
+
70
+ database principal_redis {
71
+ engine: redis
72
+ consistency: eventual
73
+ durability: media
74
+ transaction_model: single_thread
75
+ query_model: chave_valor
76
+ keyspace cache_pedidos {
77
+ ttl: 300s
78
+ }
79
+ stream eventos_pedido {
80
+ surface: fila
81
+ }
82
+ retention expurgo_cache {
83
+ retention: 300s
84
+ }
85
+ }
86
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-css",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-dart",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-html",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-javascript",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-lua",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-python",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema/gerador-typescript",
3
- "version": "1.3.7",
3
+ "version": "1.4.0",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts"
@@ -1,5 +1,5 @@
1
1
  import type { IntervaloFonte } from "../diagnosticos/index.js";
2
- export type TipoBloco = "module" | "use" | "type" | "entity" | "enum" | "task" | "worker" | "evento" | "fila" | "cron" | "webhook" | "cache" | "storage" | "policy" | "input" | "output" | "rules" | "effects" | "impl" | "vinculos" | "execucao" | "auth" | "authz" | "dados" | "audit" | "segredos" | "forbidden" | "guarantees" | "state" | "flow" | "route" | "tests" | "error" | "docs" | "comments" | "fields" | "invariants" | "transitions" | "given" | "when" | "expect" | "case" | "desconhecido";
2
+ export type TipoBloco = "module" | "use" | "database" | "type" | "entity" | "enum" | "task" | "worker" | "evento" | "fila" | "cron" | "webhook" | "cache" | "storage" | "policy" | "input" | "output" | "rules" | "effects" | "impl" | "vinculos" | "execucao" | "auth" | "authz" | "dados" | "audit" | "segredos" | "forbidden" | "guarantees" | "state" | "flow" | "route" | "tests" | "error" | "docs" | "comments" | "table" | "view" | "query" | "transaction" | "index" | "constraint" | "relationship" | "collection" | "document" | "keyspace" | "stream" | "lock" | "retention" | "replication" | "fields" | "invariants" | "transitions" | "given" | "when" | "expect" | "case" | "desconhecido";
3
3
  export interface NoAstBase {
4
4
  tipo: string;
5
5
  intervalo?: IntervaloFonte;
@@ -101,6 +101,7 @@ export interface ModuloAst extends NoAstBase {
101
101
  vinculos?: BlocoGenericoAst;
102
102
  docs?: BlocoGenericoAst;
103
103
  comments?: BlocoGenericoAst;
104
+ databases: BlocoGenericoAst[];
104
105
  types: TypeAst[];
105
106
  entities: EntityAst[];
106
107
  enums: EnumAst[];
@@ -5,23 +5,24 @@ const ORDEM_BLOCOS_MODULO = new Map([
5
5
  ["comments", 1],
6
6
  ["use", 2],
7
7
  ["vinculos", 3],
8
- ["type", 4],
9
- ["entity", 5],
10
- ["enum", 6],
11
- ["state", 7],
12
- ["task", 8],
13
- ["flow", 9],
14
- ["route", 10],
15
- ["worker", 11],
16
- ["evento", 12],
17
- ["fila", 13],
18
- ["cron", 14],
19
- ["webhook", 15],
20
- ["cache", 16],
21
- ["storage", 17],
22
- ["policy", 18],
23
- ["tests", 19],
24
- ["desconhecido", 20],
8
+ ["database", 4],
9
+ ["type", 5],
10
+ ["entity", 6],
11
+ ["enum", 7],
12
+ ["state", 8],
13
+ ["task", 9],
14
+ ["flow", 10],
15
+ ["route", 11],
16
+ ["worker", 12],
17
+ ["evento", 13],
18
+ ["fila", 14],
19
+ ["cron", 15],
20
+ ["webhook", 16],
21
+ ["cache", 17],
22
+ ["storage", 18],
23
+ ["policy", 19],
24
+ ["tests", 20],
25
+ ["desconhecido", 21],
25
26
  ]);
26
27
  const ORDEM_SUBBLOCOS_TASK = new Map([
27
28
  ["docs", 0],
@@ -154,6 +155,17 @@ const ORDEM_CAMPOS_POR_BLOCO = new Map([
154
155
  ["retencao", 3],
155
156
  ["motivo", 4],
156
157
  ])],
158
+ ["database", new Map([
159
+ ["engine", 0],
160
+ ["schema", 1],
161
+ ["database", 2],
162
+ ["consistency", 3],
163
+ ["durability", 4],
164
+ ["transaction_model", 5],
165
+ ["query_model", 6],
166
+ ["portavel", 7],
167
+ ["adapter", 8],
168
+ ])],
157
169
  ]);
158
170
  function indentacao(nivel) {
159
171
  return " ".repeat(nivel);
@@ -373,6 +385,9 @@ function renderizarModulo(modulo) {
373
385
  if (modulo.vinculos) {
374
386
  blocos.push({ chave: "vinculos", conteudo: renderizarBlocoGenerico(modulo.vinculos, 1) });
375
387
  }
388
+ for (const database of modulo.databases) {
389
+ blocos.push({ chave: "database", conteudo: renderizarBlocoGenerico(database, 1) });
390
+ }
376
391
  for (const type of modulo.types) {
377
392
  blocos.push({ chave: "type", conteudo: renderizarBlocoAst(type, 1) });
378
393
  }