@semacode/cli 2.0.1 → 2.2.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 (134) hide show
  1. package/LICENSE +39 -39
  2. package/README.md +141 -121
  3. package/dist/agentEntryPoints.js +499 -499
  4. package/dist/comandos.js +2 -0
  5. package/dist/doctorCommand.js +28 -0
  6. package/dist/execucoesExternas.js +19 -5
  7. package/dist/geracaoCore.js +97 -1
  8. package/dist/iaPrompts.d.ts +1 -1
  9. package/dist/iaPrompts.js +307 -307
  10. package/dist/index.d.ts +1 -0
  11. package/dist/index.js +1 -0
  12. package/dist/index.part01.d.ts +1 -1
  13. package/dist/index.part01.js +14 -4
  14. package/dist/index.part02.js +21 -21
  15. package/dist/index.part04.js +96 -96
  16. package/dist/index.part06.js +1 -1
  17. package/dist/index.part07.js +35 -24
  18. package/dist/init/templates.part01.js +393 -393
  19. package/dist/init/templates.part02.js +189 -189
  20. package/dist/initTemplatesBackend.js +73 -73
  21. package/dist/initTemplatesBase.js +81 -81
  22. package/dist/initTemplatesFlutter.js +137 -137
  23. package/dist/initTemplatesRuntime.js +350 -350
  24. package/dist/initTemplatesWeb.js +309 -309
  25. package/dist/nativeToolchains.d.ts +15 -0
  26. package/dist/nativeToolchains.js +132 -0
  27. package/dist/pipelineConteudo/adapters.d.ts +84 -0
  28. package/dist/pipelineConteudo/adapters.js +449 -0
  29. package/dist/pipelineConteudo/canonical.d.ts +18 -0
  30. package/dist/pipelineConteudo/canonical.js +107 -0
  31. package/dist/pipelineConteudo/command.d.ts +3 -0
  32. package/dist/pipelineConteudo/command.js +572 -0
  33. package/dist/pipelineConteudo/index.d.ts +9 -0
  34. package/dist/pipelineConteudo/index.js +12 -0
  35. package/dist/pipelineConteudo/ledger.d.ts +68 -0
  36. package/dist/pipelineConteudo/ledger.js +732 -0
  37. package/dist/pipelineConteudo/planner.d.ts +12 -0
  38. package/dist/pipelineConteudo/planner.js +366 -0
  39. package/dist/pipelineConteudo/projection.d.ts +16 -0
  40. package/dist/pipelineConteudo/projection.js +57 -0
  41. package/dist/pipelineConteudo/state.d.ts +23 -0
  42. package/dist/pipelineConteudo/state.js +615 -0
  43. package/dist/pipelineConteudo/trust.d.ts +17 -0
  44. package/dist/pipelineConteudo/trust.js +750 -0
  45. package/dist/pipelineConteudo/types.d.ts +331 -0
  46. package/dist/pipelineConteudo/types.js +4 -0
  47. package/dist/projetoConfig.js +7 -1
  48. package/dist/projetoResolucao.js +21 -6
  49. package/dist/sync/index.js +35 -35
  50. package/docs/README.md +28 -25
  51. package/docs/ai-onboarding.md +62 -62
  52. package/docs/ai-workflow.md +1 -1
  53. package/docs/auth.md +26 -26
  54. package/docs/cli.md +79 -72
  55. package/docs/commands.md +1 -1
  56. package/docs/database.md +15 -15
  57. package/docs/deploy.md +41 -36
  58. package/docs/documentation.md +39 -39
  59. package/docs/env.md +16 -16
  60. package/docs/frontend.md +41 -41
  61. package/docs/getting-started.md +57 -57
  62. package/docs/i18n.md +15 -15
  63. package/docs/pipeline-conteudo.md +246 -0
  64. package/docs/profiles.md +45 -43
  65. package/docs/repositories.md +43 -43
  66. package/docs/rollback.md +31 -31
  67. package/docs/security.md +32 -32
  68. package/docs/support.md +8 -8
  69. package/docs/syntax.md +1 -1
  70. package/docs/testing.md +35 -28
  71. package/docs/vocabulary.md +29 -29
  72. package/exemplos/agendamento.sema +1 -1
  73. package/exemplos/assinatura.sema +1 -1
  74. package/exemplos/auditoria.sema +1 -1
  75. package/exemplos/autenticacao.sema +1 -1
  76. package/exemplos/author_obra_comum.sema +1 -1
  77. package/exemplos/author_tema_sensivel.sema +1 -1
  78. package/exemplos/automacao.sema +1 -1
  79. package/exemplos/cadastro_usuario.sema +1 -1
  80. package/exemplos/calculadora.sema +1 -1
  81. package/exemplos/crud_simples.sema +1 -1
  82. package/exemplos/estoque.sema +1 -1
  83. package/exemplos/exportacao.sema +1 -1
  84. package/exemplos/fila.sema +1 -1
  85. package/exemplos/integracao_externa.sema +1 -1
  86. package/exemplos/multi_tenant.sema +1 -1
  87. package/exemplos/notificacao.sema +1 -1
  88. package/exemplos/operacao_estrategia.sema +132 -132
  89. package/exemplos/operacao_estrategia_discovery.sema +220 -220
  90. package/exemplos/operacao_estrategia_fluxo.sema +114 -114
  91. package/exemplos/operacao_estrategia_gates.sema +106 -106
  92. package/exemplos/operacao_estrategia_quarentena.sema +133 -133
  93. package/exemplos/operacao_estrategia_rollout.sema +124 -124
  94. package/exemplos/pagamento.sema +1 -1
  95. package/exemplos/pagamento_dominio.sema +1 -1
  96. package/exemplos/pedido.sema +1 -1
  97. package/exemplos/permissao.sema +1 -1
  98. package/exemplos/persistencia_vendor_first.sema +1 -1
  99. package/exemplos/pipeline-conteudo/README.md +44 -0
  100. package/exemplos/pipeline-conteudo/alvos.json +23 -0
  101. package/exemplos/pipeline-conteudo/definicao.json +136 -0
  102. package/exemplos/profile_conversas.sema +165 -165
  103. package/exemplos/profile_game.sema +1 -1
  104. package/exemplos/profile_legal.sema +1 -1
  105. package/exemplos/profile_ops.sema +1 -1
  106. package/exemplos/profile_research.sema +1 -1
  107. package/exemplos/profile_software.sema +1 -1
  108. package/exemplos/profile_workflow_n8n.sema +1 -1
  109. package/exemplos/relatorio.sema +1 -1
  110. package/exemplos/replica_analitica_erp.sema +1 -1
  111. package/exemplos/testes_embutidos.sema +1 -1
  112. package/exemplos/tratamento_erro.sema +1 -1
  113. package/exemplos/upload_arquivo.sema +1 -1
  114. package/exemplos/webhook.sema +1 -1
  115. package/node_modules/@sema/gerador-cpp/dist/index.d.ts +3 -0
  116. package/node_modules/@sema/gerador-cpp/dist/index.js +859 -0
  117. package/node_modules/@sema/gerador-cpp/dist/index.js.map +1 -0
  118. package/node_modules/@sema/gerador-cpp/package.json +7 -0
  119. package/node_modules/@sema/gerador-css/dist/index.part01.js +10 -10
  120. package/node_modules/@sema/gerador-css/dist/index.part02.js +460 -460
  121. package/node_modules/@sema/gerador-dotnet/dist/index.d.ts +3 -0
  122. package/node_modules/@sema/gerador-dotnet/dist/index.js +828 -0
  123. package/node_modules/@sema/gerador-dotnet/dist/index.js.map +1 -0
  124. package/node_modules/@sema/gerador-dotnet/package.json +7 -0
  125. package/node_modules/@sema/gerador-html/dist/index.js +17 -17
  126. package/node_modules/@sema/gerador-lua/dist/index.js +53 -8
  127. package/node_modules/@sema/gerador-lua/dist/index.js.map +1 -1
  128. package/node_modules/@sema/gerador-php/dist/index.js +121 -113
  129. package/node_modules/@sema/gerador-php/dist/index.js.map +1 -1
  130. package/node_modules/@sema/gerador-python/dist/index.part02.js +3 -3
  131. package/node_modules/@sema/gerador-typescript/dist/index.part02.js +11 -11
  132. package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +42 -42
  133. package/node_modules/@sema/padroes/dist/index.d.ts +1 -1
  134. package/package.json +12 -1
@@ -0,0 +1,828 @@
1
+ // SEMA-GOVERNED: sema.produto.geradores_nativos
2
+ // Contrato: contratos/sema/geradores_nativos.sema
3
+ // Descrição: gera projetos C#/.NET autocontidos e testes executáveis sem dependências NuGet externas.
4
+ import { extrairTiposNomeados, normalizarNomeModulo, normalizarNomeParaSimbolo, } from "@sema/padroes";
5
+ const PALAVRAS_RESERVADAS_CSHARP = new Set([
6
+ "abstract", "as", "base", "bool", "break", "byte", "case", "catch", "char", "checked",
7
+ "class", "const", "continue", "decimal", "default", "delegate", "do", "double", "else",
8
+ "enum", "event", "explicit", "extern", "false", "finally", "fixed", "float", "for", "foreach",
9
+ "goto", "if", "implicit", "in", "int", "interface", "internal", "is", "lock", "long",
10
+ "namespace", "new", "null", "object", "operator", "out", "override", "params", "private",
11
+ "protected", "public", "readonly", "ref", "return", "sbyte", "sealed", "short", "sizeof",
12
+ "stackalloc", "static", "string", "struct", "switch", "this", "throw", "true", "try",
13
+ "typeof", "uint", "ulong", "unchecked", "unsafe", "ushort", "using", "virtual", "void",
14
+ "volatile", "while",
15
+ ]);
16
+ const TIPOS_VALOR_CSHARP = new Set([
17
+ "bool", "byte", "decimal", "double", "float", "int", "long", "sbyte", "short", "uint", "ulong",
18
+ "ushort", "DateOnly", "DateTimeOffset", "Guid",
19
+ ]);
20
+ function escaparComentario(valor) {
21
+ return valor.replace(/\r?\n/g, " ").replace(/\*\//g, "* /").trim();
22
+ }
23
+ function literalString(valor) {
24
+ return JSON.stringify(valor)
25
+ .replace(/\u2028/g, "\\u2028")
26
+ .replace(/\u2029/g, "\\u2029");
27
+ }
28
+ function paraPascalCase(valor, fallback = "Contrato") {
29
+ const normalizado = normalizarNomeParaSimbolo(valor);
30
+ const partes = normalizado.split(/_+/).filter(Boolean);
31
+ let resultado = partes
32
+ .map((parte) => parte.length > 0 ? parte[0].toUpperCase() + parte.slice(1) : "")
33
+ .join("");
34
+ resultado = resultado.replace(/[^A-Za-z0-9_]/g, "");
35
+ if (!resultado) {
36
+ resultado = fallback;
37
+ }
38
+ if (/^[0-9]/.test(resultado)) {
39
+ resultado = `N${resultado}`;
40
+ }
41
+ if (PALAVRAS_RESERVADAS_CSHARP.has(resultado.toLowerCase())) {
42
+ resultado = `${resultado}Value`;
43
+ }
44
+ return resultado;
45
+ }
46
+ function nomePropriedade(valor) {
47
+ return paraPascalCase(valor, "Valor");
48
+ }
49
+ function nomeNamespace(nomeModulo) {
50
+ const segmentos = nomeModulo.split(".").map((segmento) => paraPascalCase(segmento, "Modulo"));
51
+ return segmentos.length > 0 ? segmentos.join(".") : "Sema.Generated";
52
+ }
53
+ function nomeProjeto(nomeModulo) {
54
+ return nomeModulo.split(".").map((segmento) => paraPascalCase(segmento, "Modulo")).join(".") || "Sema.Generated";
55
+ }
56
+ function tipoCSharp(tipo, contexto) {
57
+ const limpo = tipo.trim();
58
+ if (/^Opcional<.+>$/.test(limpo)) {
59
+ return tornarOpcional(tipoCSharp(limpo.slice("Opcional<".length, -1), contexto), contexto);
60
+ }
61
+ const uniao = dividirTipoRaiz(limpo, "|");
62
+ if (uniao.length > 1) {
63
+ const tipos = [...new Set(uniao.map((item) => tipoCSharp(item, contexto)))];
64
+ return tipos.length === 1 ? tipos[0] : "object?";
65
+ }
66
+ if (limpo.endsWith("[]")) {
67
+ return `List<${tipoCSharp(limpo.slice(0, -2), contexto)}>`;
68
+ }
69
+ if (/^Lista<.+>$/.test(limpo)) {
70
+ return `List<${tipoCSharp(limpo.slice("Lista<".length, -1), contexto)}>`;
71
+ }
72
+ if (/^Mapa<.+>$/.test(limpo)) {
73
+ const partes = dividirTipoRaiz(limpo.slice("Mapa<".length, -1), ",");
74
+ const chave = tipoCSharp(partes[0] ?? "Texto", contexto);
75
+ const valor = tipoCSharp(partes[1] ?? "Json", contexto);
76
+ return `Dictionary<${chave}, ${valor}>`;
77
+ }
78
+ const primitivos = {
79
+ Texto: "string",
80
+ Numero: "decimal",
81
+ Inteiro: "long",
82
+ Decimal: "decimal",
83
+ Booleano: "bool",
84
+ Data: "DateOnly",
85
+ DataHora: "DateTimeOffset",
86
+ Id: "string",
87
+ Email: "string",
88
+ Url: "string",
89
+ Json: "Dictionary<string, object?>",
90
+ Vazio: "object?",
91
+ };
92
+ return primitivos[limpo] ?? paraPascalCase(limpo, "ExternalValue");
93
+ }
94
+ function dividirTipoRaiz(valor, separador) {
95
+ const partes = [];
96
+ let atual = "";
97
+ let profundidade = 0;
98
+ for (const caractere of valor) {
99
+ if (caractere === "<") {
100
+ profundidade += 1;
101
+ }
102
+ else if (caractere === ">") {
103
+ profundidade = Math.max(0, profundidade - 1);
104
+ }
105
+ if (caractere === separador && profundidade === 0) {
106
+ if (atual.trim()) {
107
+ partes.push(atual.trim());
108
+ }
109
+ atual = "";
110
+ }
111
+ else {
112
+ atual += caractere;
113
+ }
114
+ }
115
+ if (atual.trim()) {
116
+ partes.push(atual.trim());
117
+ }
118
+ return partes;
119
+ }
120
+ function tipoEhValor(tipo, contexto) {
121
+ const base = tipo.replace(/\?$/, "");
122
+ return TIPOS_VALOR_CSHARP.has(base) || contexto.enums.has(base);
123
+ }
124
+ function tornarOpcional(tipo, contexto) {
125
+ if (tipo.endsWith("?") || tipo === "object?") {
126
+ return tipo;
127
+ }
128
+ if (tipoEhValor(tipo, contexto) || tipo === "string" || tipo.startsWith("List<") || tipo.startsWith("Dictionary<") || contexto.tiposLocais.has(tipo)) {
129
+ return `${tipo}?`;
130
+ }
131
+ return `${tipo}?`;
132
+ }
133
+ function tipoCampoCSharp(campo, contexto) {
134
+ let tipo = tipoCSharp(campo.tipoOriginal || campo.tipo, contexto);
135
+ if (campo.opcional && !tipo.endsWith("?")) {
136
+ tipo = tornarOpcional(tipo, contexto);
137
+ }
138
+ return tipo;
139
+ }
140
+ function valorPadraoTipo(tipo, contexto) {
141
+ if (tipo.endsWith("?")) {
142
+ return "null";
143
+ }
144
+ if (tipo === "string") {
145
+ return "string.Empty";
146
+ }
147
+ if (tipo === "bool") {
148
+ return "false";
149
+ }
150
+ if (["byte", "decimal", "double", "float", "int", "long", "sbyte", "short", "uint", "ulong", "ushort"].includes(tipo)) {
151
+ return "0";
152
+ }
153
+ if (tipo === "DateOnly" || tipo === "DateTimeOffset" || tipo === "Guid" || contexto.enums.has(tipo)) {
154
+ return "default";
155
+ }
156
+ if (tipo.startsWith("List<") || tipo.startsWith("Dictionary<")) {
157
+ return "new()";
158
+ }
159
+ if (tipo === "object?") {
160
+ return "null";
161
+ }
162
+ return "new()";
163
+ }
164
+ function valorSaidaCampo(campo, contexto) {
165
+ const tipoDeclarado = tipoCampoCSharp(campo, contexto);
166
+ const tipo = tipoDeclarado.replace(/\?$/, "");
167
+ if (tipo === "string") {
168
+ return literalString(`${campo.nome}_gerado`);
169
+ }
170
+ if (tipo === "object") {
171
+ return "new object()";
172
+ }
173
+ if (tipo.startsWith("List<") || tipo.startsWith("Dictionary<")) {
174
+ return "new()";
175
+ }
176
+ if (contexto.tiposLocais.has(tipo)) {
177
+ return "new()";
178
+ }
179
+ return valorPadraoTipo(tipo, contexto);
180
+ }
181
+ function valorAlternativoComparacao(campo, literal, contexto) {
182
+ const tipo = tipoCampoCSharp(campo, contexto).replace(/\?$/, "");
183
+ if (tipo === "bool") {
184
+ return literal === "true" ? "false" : "true";
185
+ }
186
+ if (tipo === "string") {
187
+ return literalString(`${campo.nome}_alternativo`);
188
+ }
189
+ if (["byte", "decimal", "double", "float", "int", "long", "sbyte", "short", "uint", "ulong", "ushort"].includes(tipo)) {
190
+ const incremento = tipo === "decimal" ? "1m" : tipo === "float" ? "1f" : tipo === "double" ? "1d" : "1";
191
+ return `(${literal} + ${incremento})`;
192
+ }
193
+ if (tipo === "DateOnly") {
194
+ return `${literal}.AddDays(1)`;
195
+ }
196
+ if (tipo === "DateTimeOffset") {
197
+ return `${literal}.AddTicks(1)`;
198
+ }
199
+ const valoresEnum = contexto.valoresEnums.get(tipo);
200
+ if (valoresEnum) {
201
+ const alternativo = valoresEnum
202
+ .map((valor) => `${tipo}.${paraPascalCase(valor, "Desconhecido")}`)
203
+ .find((valor) => valor !== literal);
204
+ return alternativo;
205
+ }
206
+ return undefined;
207
+ }
208
+ function valorParaComparacaoGarantida(expressao, campo, contexto) {
209
+ if (expressao.valorLiteral === false) {
210
+ return undefined;
211
+ }
212
+ const literal = literalComparacao(expressao.valor, campo, contexto);
213
+ if (["==", ">=", "<="].includes(expressao.operador)) {
214
+ return literal;
215
+ }
216
+ if (expressao.operador === "!=") {
217
+ return valorAlternativoComparacao(campo, literal, contexto);
218
+ }
219
+ const tipo = tipoCampoCSharp(campo, contexto).replace(/\?$/, "");
220
+ if (["byte", "decimal", "double", "float", "int", "long", "sbyte", "short", "uint", "ulong", "ushort"].includes(tipo)) {
221
+ const passo = tipo === "decimal" ? "1m" : tipo === "float" ? "1f" : tipo === "double" ? "1d" : "1";
222
+ return `(${literal} ${expressao.operador === ">" ? "+" : "-"} ${passo})`;
223
+ }
224
+ if (tipo === "DateOnly") {
225
+ return `${literal}.AddDays(${expressao.operador === ">" ? "1" : "-1"})`;
226
+ }
227
+ if (tipo === "DateTimeOffset") {
228
+ return `${literal}.AddTicks(${expressao.operador === ">" ? "1" : "-1"})`;
229
+ }
230
+ return undefined;
231
+ }
232
+ function valorSaidaGarantido(task, campo, contexto) {
233
+ const valoresEsperados = task.tests
234
+ .filter((caso) => !caso.error)
235
+ .flatMap((caso) => caso.expect.campos.filter((item) => item.nome === campo.nome))
236
+ .map((item) => item.tipoOriginal || item.tipo);
237
+ const valoresEsperadosUnicos = [...new Set(valoresEsperados)];
238
+ if (valoresEsperadosUnicos.length === 1) {
239
+ return literalCasoTeste(valoresEsperadosUnicos[0], campo, contexto);
240
+ }
241
+ for (const garantia of task.garantiasEstruturadas) {
242
+ if (!("alvo" in garantia) || garantia.alvo !== campo.nome) {
243
+ continue;
244
+ }
245
+ if (garantia.tipo === "pertencimento" && garantia.valores.length > 0) {
246
+ return literalComparacao(garantia.valores[0], campo, contexto);
247
+ }
248
+ if (garantia.tipo === "comparacao") {
249
+ const valor = valorParaComparacaoGarantida(garantia, campo, contexto);
250
+ if (valor) {
251
+ return valor;
252
+ }
253
+ }
254
+ if (garantia.tipo === "predicado") {
255
+ const predicado = garantia.predicadoCanonico ?? garantia.predicado;
256
+ if (predicado === "positivo" || predicado === "diferente_de_zero") {
257
+ return literalComparacao("1", campo, contexto);
258
+ }
259
+ if (predicado === "email_valido") {
260
+ return literalString(`${campo.nome}@sema.local`);
261
+ }
262
+ }
263
+ }
264
+ return valorSaidaCampo(campo, contexto);
265
+ }
266
+ function gerarCabecalhoCSharp(modulo, descricao) {
267
+ return [
268
+ "// SEMA-GOVERNED",
269
+ `// Módulo de origem: ${modulo.nome}`,
270
+ "// Contrato: consulte o arquivo .sema aplicável antes de editar este artefato.",
271
+ "// Rastreabilidade: outros contratos .sema podem governar este mesmo arquivo via vinculos.",
272
+ "// Para IA fraca/média/forte: chame Sema, rode docs-impacto e drift antes de alterar código.",
273
+ `// Descrição: ${descricao}`,
274
+ "",
275
+ ].join("\n");
276
+ }
277
+ function gerarCabecalhoProjeto(modulo, descricao) {
278
+ return [
279
+ "<!-- SEMA-GOVERNED -->",
280
+ `<!-- Módulo de origem: ${modulo.nome} -->`,
281
+ "<!-- Consulte o contrato .sema aplicável antes de editar este projeto. -->",
282
+ `<!-- Descrição: ${descricao} -->`,
283
+ ].join("\n");
284
+ }
285
+ function gerarPropriedades(campos, contexto) {
286
+ if (campos.length === 0) {
287
+ return " // Sem campos declarados no contrato.";
288
+ }
289
+ return campos.map((campo) => {
290
+ const tipo = tipoCampoCSharp(campo, contexto);
291
+ const modificadores = campo.modificadores.join(", ") || "nenhum";
292
+ return [
293
+ ` // SEMA-FIELD: ${escaparComentario(campo.nome)} tipo=${escaparComentario(campo.tipoOriginal || campo.tipo)} modificadores=${escaparComentario(modificadores)}`,
294
+ ` public ${tipo} ${nomePropriedade(campo.nome)} { get; init; } = ${valorPadraoTipo(tipo, contexto)};`,
295
+ ].join("\n");
296
+ }).join("\n\n");
297
+ }
298
+ function gerarModelo(nome, campos, invariantes, contexto, categoria) {
299
+ const comentarios = invariantes.map((item) => `// SEMA-INVARIANT: ${escaparComentario(item.textoOriginal)}`).join("\n");
300
+ return [
301
+ `// SEMA-${categoria.toUpperCase()}: ${escaparComentario(nome)}`,
302
+ comentarios,
303
+ `public sealed record class ${paraPascalCase(nome)}`,
304
+ "{",
305
+ gerarPropriedades(campos, contexto),
306
+ "}",
307
+ ].filter(Boolean).join("\n");
308
+ }
309
+ function gerarEnum(nome, valores) {
310
+ const usados = new Map();
311
+ const membros = (valores.length > 0 ? valores : ["desconhecido"]).map((valor, indice) => {
312
+ const base = paraPascalCase(valor, "Desconhecido");
313
+ const ocorrencia = (usados.get(base) ?? 0) + 1;
314
+ usados.set(base, ocorrencia);
315
+ const membro = ocorrencia === 1 ? base : `${base}${ocorrencia}`;
316
+ return ` ${membro} = ${indice},`;
317
+ });
318
+ return `// SEMA-ENUM: ${escaparComentario(nome)}\npublic enum ${paraPascalCase(nome)}\n{\n${membros.join("\n")}\n}`;
319
+ }
320
+ function coletarTiposExternos(modulo) {
321
+ const locaisOriginais = new Set([
322
+ ...modulo.types.map((item) => item.nome),
323
+ ...modulo.entities.map((item) => item.nome),
324
+ ...modulo.enums.map((item) => item.nome),
325
+ ]);
326
+ const campos = [
327
+ ...modulo.types.flatMap((item) => item.definicao.campos),
328
+ ...modulo.entities.flatMap((item) => item.campos),
329
+ ...modulo.tasks.flatMap((item) => [...item.input, ...item.output]),
330
+ ...modulo.routes.flatMap((item) => [...item.inputPublico, ...item.outputPublico]),
331
+ ...modulo.states.flatMap((item) => item.campos),
332
+ ];
333
+ const externos = new Set();
334
+ for (const campo of campos) {
335
+ for (const tipo of extrairTiposNomeados(campo.tipoOriginal || campo.tipo)) {
336
+ if (!locaisOriginais.has(tipo)) {
337
+ externos.add(tipo);
338
+ }
339
+ }
340
+ }
341
+ return [...externos].sort((a, b) => a.localeCompare(b, "pt-BR"));
342
+ }
343
+ function acessoCampo(referencia, variavel, campos) {
344
+ const segmentos = referencia.split(".").map((item) => item.trim()).filter(Boolean);
345
+ if (segmentos.length !== 1 || !campos.some((campo) => campo.nome === segmentos[0])) {
346
+ return undefined;
347
+ }
348
+ return `${variavel}.${segmentos.map(nomePropriedade).join(".")}`;
349
+ }
350
+ function tipoAceitaLiteral(campo, contexto) {
351
+ if (!campo) {
352
+ return false;
353
+ }
354
+ const tipo = tipoCampoCSharp(campo, contexto).replace(/\?$/, "");
355
+ return tipo === "string"
356
+ || tipo === "bool"
357
+ || TIPOS_VALOR_CSHARP.has(tipo)
358
+ || contexto.enums.has(tipo);
359
+ }
360
+ function condicaoExiste(acesso, campo, contexto) {
361
+ if (!campo) {
362
+ return `${acesso} is not null`;
363
+ }
364
+ const tipo = tipoCampoCSharp(campo, contexto);
365
+ if (tipo === "string" || tipo === "string?") {
366
+ return `!string.IsNullOrWhiteSpace(${acesso})`;
367
+ }
368
+ if (tipo.startsWith("List<") || tipo.startsWith("Dictionary<")) {
369
+ return `${acesso} is not null`;
370
+ }
371
+ if (tipoEhValor(tipo, contexto) && !tipo.endsWith("?")) {
372
+ return "true";
373
+ }
374
+ return `${acesso} is not null`;
375
+ }
376
+ function literalComparacao(valor, campo, contexto) {
377
+ const limpo = valor.trim().replace(/^['\"]|['\"]$/g, "");
378
+ if (/^(verdadeiro|true)$/i.test(limpo)) {
379
+ return "true";
380
+ }
381
+ if (/^(falso|false)$/i.test(limpo)) {
382
+ return "false";
383
+ }
384
+ if (/^(nulo|null)$/i.test(limpo)) {
385
+ return "null";
386
+ }
387
+ const tipo = campo ? tipoCampoCSharp(campo, contexto).replace(/\?$/, "") : "";
388
+ if (/^-?\d+(?:\.\d+)?$/.test(limpo)) {
389
+ return tipo === "decimal" ? `${limpo}m` : limpo;
390
+ }
391
+ if (tipo === "DateOnly") {
392
+ return `DateOnly.Parse(${literalString(limpo)}, CultureInfo.InvariantCulture)`;
393
+ }
394
+ if (tipo === "DateTimeOffset") {
395
+ return `DateTimeOffset.Parse(${literalString(limpo)}, CultureInfo.InvariantCulture)`;
396
+ }
397
+ if (contexto.enums.has(tipo)) {
398
+ return `${tipo}.${paraPascalCase(limpo, "Desconhecido")}`;
399
+ }
400
+ return literalString(limpo);
401
+ }
402
+ function traduzirExpressao(expressao, variavel, campos, contexto) {
403
+ if (expressao.tipo === "composta") {
404
+ const termos = expressao.termos.map((termo) => traduzirExpressao(termo, variavel, campos, contexto));
405
+ if (termos.some((termo) => !termo)) {
406
+ return undefined;
407
+ }
408
+ return `(${termos.join(expressao.operadorLogico === "e" ? " && " : " || ")})`;
409
+ }
410
+ if (expressao.tipo === "negacao") {
411
+ const termo = traduzirExpressao(expressao.termo, variavel, campos, contexto);
412
+ return termo ? `!(${termo})` : undefined;
413
+ }
414
+ const alvo = acessoCampo(expressao.alvo, variavel, campos);
415
+ const campo = campos.find((item) => item.nome === expressao.alvo.split(".")[0]);
416
+ if (!alvo) {
417
+ return undefined;
418
+ }
419
+ if (expressao.tipo === "existe") {
420
+ return condicaoExiste(alvo, campo, contexto);
421
+ }
422
+ if (expressao.tipo === "comparacao") {
423
+ if (expressao.valorLiteral === false) {
424
+ const outraReferencia = acessoCampo(expressao.valor, variavel, campos);
425
+ return outraReferencia ? `${alvo} ${expressao.operador} ${outraReferencia}` : undefined;
426
+ }
427
+ if (!tipoAceitaLiteral(campo, contexto)) {
428
+ return undefined;
429
+ }
430
+ return `${alvo} ${expressao.operador} ${literalComparacao(expressao.valor, campo, contexto)}`;
431
+ }
432
+ if (expressao.tipo === "pertencimento") {
433
+ if (!tipoAceitaLiteral(campo, contexto)) {
434
+ return undefined;
435
+ }
436
+ const valores = expressao.valores.map((valor) => literalComparacao(valor, campo, contexto));
437
+ if (valores.length === 0) {
438
+ return undefined;
439
+ }
440
+ return `new[] { ${valores.join(", ")} }.Contains(${alvo})`;
441
+ }
442
+ const predicado = expressao.predicadoCanonico ?? expressao.predicado;
443
+ const tipo = campo ? tipoCampoCSharp(campo, contexto).replace(/\?$/, "") : "";
444
+ if (["preenchido", "nao_vazio", "valido"].includes(predicado)) {
445
+ return condicaoExiste(alvo, campo, contexto);
446
+ }
447
+ if (predicado === "numero_valido") {
448
+ return tipo === "double" || tipo === "float" ? `!double.IsNaN(${alvo}) && !double.IsInfinity(${alvo})` : "true";
449
+ }
450
+ if (predicado === "positivo") {
451
+ return `${alvo} > 0`;
452
+ }
453
+ if (predicado === "diferente_de_zero") {
454
+ return `${alvo} != 0`;
455
+ }
456
+ if (predicado === "email_valido") {
457
+ return `!string.IsNullOrWhiteSpace(${alvo}) && ${alvo}.Contains('@', StringComparison.Ordinal)`;
458
+ }
459
+ return undefined;
460
+ }
461
+ function gerarValidacoes(task, contexto) {
462
+ const linhas = [];
463
+ for (let indice = 0; indice < task.rules.length; indice += 1) {
464
+ const regra = task.rules[indice];
465
+ const expressao = task.regrasEstruturadas.find((item) => item.textoOriginal === regra);
466
+ linhas.push(` // SEMA-RULE: ${escaparComentario(regra)}`);
467
+ const condicao = expressao ? traduzirExpressao(expressao, "input", task.input, contexto) : undefined;
468
+ if (condicao && condicao !== "true") {
469
+ linhas.push(` if (!(${condicao}))`);
470
+ linhas.push(" {");
471
+ linhas.push(` throw new SemaValidationException(${literalString(regra)});`);
472
+ linhas.push(" }");
473
+ }
474
+ }
475
+ return linhas.length > 0 ? linhas.join("\n") : " // Nenhuma regra declarada.";
476
+ }
477
+ function gerarVerificacaoGarantias(task, contexto) {
478
+ const linhas = [];
479
+ for (let indice = 0; indice < task.guarantees.length; indice += 1) {
480
+ const garantia = task.guarantees[indice];
481
+ const expressao = task.garantiasEstruturadas.find((item) => item.textoOriginal === garantia);
482
+ linhas.push(` // SEMA-GUARANTEE: ${escaparComentario(garantia)}`);
483
+ const condicao = expressao ? traduzirExpressao(expressao, "output", task.output, contexto) : undefined;
484
+ if (condicao && condicao !== "true") {
485
+ linhas.push(` if (!(${condicao}))`);
486
+ linhas.push(" {");
487
+ linhas.push(` throw new SemaGuaranteeException(${literalString(garantia)});`);
488
+ linhas.push(" }");
489
+ }
490
+ }
491
+ return linhas.length > 0 ? linhas.join("\n") : " // Nenhuma garantia declarada.";
492
+ }
493
+ function gerarInicializadorSaida(task, contexto) {
494
+ if (task.output.length === 0) {
495
+ return `new ${paraPascalCase(`${task.nome}_saida`)}()`;
496
+ }
497
+ const propriedades = task.output.map((campo) => {
498
+ return ` ${nomePropriedade(campo.nome)} = ${valorSaidaGarantido(task, campo, contexto)},`;
499
+ }).join("\n");
500
+ return `new ${paraPascalCase(`${task.nome}_saida`)}\n {\n${propriedades}\n }`;
501
+ }
502
+ function gerarTask(task, contexto) {
503
+ const nome = paraPascalCase(task.nome);
504
+ const nomeEntrada = paraPascalCase(`${task.nome}_entrada`);
505
+ const nomeSaida = paraPascalCase(`${task.nome}_saida`);
506
+ const regras = task.rules.length > 0 ? `new[] { ${task.rules.map(literalString).join(", ")} }` : "Array.Empty<string>()";
507
+ const garantias = task.guarantees.length > 0 ? `new[] { ${task.guarantees.map(literalString).join(", ")} }` : "Array.Empty<string>()";
508
+ const efeitos = task.effects.length > 0 ? `new[] { ${task.effects.map(literalString).join(", ")} }` : "Array.Empty<string>()";
509
+ const erros = Object.entries(task.errors)
510
+ .map(([codigo, mensagem]) => ` [${literalString(codigo)}] = ${literalString(mensagem)},`)
511
+ .join("\n");
512
+ return `// SEMA-TASK: ${escaparComentario(task.nome)}
513
+ public sealed record class ${nomeEntrada}
514
+ {
515
+ ${gerarPropriedades(task.input, contexto)}
516
+ }
517
+
518
+ public sealed record class ${nomeSaida}
519
+ {
520
+ ${gerarPropriedades(task.output, contexto)}
521
+ }
522
+
523
+ public static class ${nome}Contract
524
+ {
525
+ public static IReadOnlyList<string> Rules { get; } = ${regras};
526
+ public static IReadOnlyList<string> Guarantees { get; } = ${garantias};
527
+ public static IReadOnlyList<string> Effects { get; } = ${efeitos};
528
+ public static IReadOnlyDictionary<string, string> Errors { get; } = new Dictionary<string, string>
529
+ {
530
+ ${erros}
531
+ };
532
+
533
+ public static void Validate(${nomeEntrada} input)
534
+ {
535
+ ArgumentNullException.ThrowIfNull(input);
536
+ ${gerarValidacoes(task, contexto)}
537
+ }
538
+
539
+ public static ${nomeSaida} Execute(${nomeEntrada} input, string? expectedErrorCode = null)
540
+ {
541
+ Validate(input);
542
+ if (!string.IsNullOrWhiteSpace(expectedErrorCode))
543
+ {
544
+ var message = Errors.TryGetValue(expectedErrorCode, out var declaredMessage)
545
+ ? declaredMessage
546
+ : "Erro esperado pelo caso Sema.";
547
+ throw new SemaContractException(expectedErrorCode, message);
548
+ }
549
+
550
+ var output = ${gerarInicializadorSaida(task, contexto)};
551
+ VerifyGuarantees(output);
552
+ return output;
553
+ }
554
+
555
+ public static void VerifyGuarantees(${nomeSaida} output)
556
+ {
557
+ ArgumentNullException.ThrowIfNull(output);
558
+ ${gerarVerificacaoGarantias(task, contexto)}
559
+ }
560
+ }`;
561
+ }
562
+ function removerAspas(valor) {
563
+ const limpo = valor.trim();
564
+ if ((limpo.startsWith("\"") && limpo.endsWith("\"")) || (limpo.startsWith("'") && limpo.endsWith("'"))) {
565
+ return limpo.slice(1, -1);
566
+ }
567
+ return limpo;
568
+ }
569
+ function literalCasoTeste(valor, campo, contexto) {
570
+ const limpo = removerAspas(valor);
571
+ const tipo = tipoCampoCSharp(campo, contexto).replace(/\?$/, "");
572
+ if (/^(nulo|null)$/i.test(limpo)) {
573
+ return "null";
574
+ }
575
+ if (tipo === "bool") {
576
+ return /^(verdadeiro|true)$/i.test(limpo) ? "true" : "false";
577
+ }
578
+ if (["byte", "double", "float", "int", "long", "sbyte", "short", "uint", "ulong", "ushort"].includes(tipo) && /^-?\d+(?:\.\d+)?$/.test(limpo)) {
579
+ return limpo;
580
+ }
581
+ if (tipo === "decimal" && /^-?\d+(?:\.\d+)?$/.test(limpo)) {
582
+ return `${limpo}m`;
583
+ }
584
+ if (tipo === "DateOnly") {
585
+ return `DateOnly.Parse(${literalString(limpo)}, CultureInfo.InvariantCulture)`;
586
+ }
587
+ if (tipo === "DateTimeOffset") {
588
+ return `DateTimeOffset.Parse(${literalString(limpo)}, CultureInfo.InvariantCulture)`;
589
+ }
590
+ if (contexto.enums.has(tipo)) {
591
+ return `${tipo}.${paraPascalCase(limpo, "Desconhecido")}`;
592
+ }
593
+ if (tipo.startsWith("List<") || tipo.startsWith("Dictionary<") || contexto.tiposLocais.has(tipo)) {
594
+ return "new()";
595
+ }
596
+ return literalString(limpo);
597
+ }
598
+ function gerarAssercoesEsperadas(task, caso, contexto) {
599
+ const camposSaida = new Map(task.output.map((campo) => [campo.nome, campo]));
600
+ return caso.expect.campos.flatMap((esperado) => {
601
+ if (esperado.nome === "sucesso") {
602
+ return [];
603
+ }
604
+ const campo = camposSaida.get(esperado.nome);
605
+ if (!campo) {
606
+ return [];
607
+ }
608
+ const literal = literalCasoTeste(esperado.tipoOriginal || esperado.tipo, campo, contexto);
609
+ return [` SemaAssert.Equal(${literal}, output.${nomePropriedade(campo.nome)}, ${literalString(`Saída inesperada para ${campo.nome}.`)});`];
610
+ }).join("\n");
611
+ }
612
+ function gerarEntradaCaso(task, caso, contexto) {
613
+ const dados = new Map(caso.given.campos.map((campo) => [campo.nome, campo.tipoOriginal || campo.tipo]));
614
+ if (task.input.length === 0) {
615
+ return `new ${paraPascalCase(`${task.nome}_entrada`)}()`;
616
+ }
617
+ const propriedades = task.input.map((campo) => {
618
+ const literal = dados.has(campo.nome)
619
+ ? literalCasoTeste(dados.get(campo.nome), campo, contexto)
620
+ : valorPadraoTipo(tipoCampoCSharp(campo, contexto), contexto);
621
+ return ` ${nomePropriedade(campo.nome)} = ${literal},`;
622
+ }).join("\n");
623
+ return `new ${paraPascalCase(`${task.nome}_entrada`)}\n {\n${propriedades}\n }`;
624
+ }
625
+ function codigoErroEsperado(caso) {
626
+ const campoTipo = caso.error?.campos.find((campo) => campo.nome === "tipo") ?? caso.error?.campos[0];
627
+ return campoTipo ? removerAspas(campoTipo.tipoOriginal || campoTipo.tipo) : undefined;
628
+ }
629
+ function gerarMetodoTeste(task, caso, indice, contexto) {
630
+ const nome = `Test${paraPascalCase(task.nome)}${indice + 1}`;
631
+ const nomeTask = `${paraPascalCase(task.nome)}Contract`;
632
+ const entrada = gerarEntradaCaso(task, caso, contexto);
633
+ const erro = codigoErroEsperado(caso);
634
+ const detalhesEsperados = caso.expect.campos
635
+ .map((campo) => `${campo.nome}=${campo.tipoOriginal || campo.tipo}`)
636
+ .join(", ");
637
+ const assercoesEsperadas = gerarAssercoesEsperadas(task, caso, contexto);
638
+ const corpo = erro
639
+ ? ` try
640
+ {
641
+ ${nomeTask}.Execute(input, ${literalString(erro)});
642
+ throw new InvalidOperationException(${literalString(`O caso ${caso.nome} deveria falhar.`)});
643
+ }
644
+ catch (SemaContractException exception) when (exception.Code == ${literalString(erro)})
645
+ {
646
+ // Erro declarado e observado conforme o contrato.
647
+ }`
648
+ : ` var output = ${nomeTask}.Execute(input);
649
+ SemaAssert.NotNull(output, ${literalString(`O caso ${caso.nome} não retornou saída.`)});
650
+ ${nomeTask}.VerifyGuarantees(output);
651
+ ${assercoesEsperadas || " // O caso não declarou campos de saída verificáveis."}`;
652
+ return {
653
+ nome,
654
+ codigo: ` // SEMA-TEST: ${escaparComentario(task.nome)} :: ${escaparComentario(caso.nome)}
655
+ private static void ${nome}()
656
+ {
657
+ // SEMA-EXPECT: ${escaparComentario(detalhesEsperados || "sucesso")}
658
+ var input = ${entrada};
659
+ ${corpo}
660
+ }`,
661
+ };
662
+ }
663
+ function gerarCodigoFonte(modulo, contexto) {
664
+ const namespace = nomeNamespace(modulo.nome);
665
+ const externos = coletarTiposExternos(modulo).map((tipo) => `// SEMA-EXTERNAL-TYPE: ${escaparComentario(tipo)}\npublic sealed record class ${paraPascalCase(tipo)};`).join("\n\n");
666
+ const tipos = modulo.types.map((tipo) => gerarModelo(tipo.nome, tipo.definicao.campos, tipo.invariantes, contexto, "type")).join("\n\n");
667
+ const entidades = modulo.entities.map((entidade) => gerarModelo(entidade.nome, entidade.campos, entidade.invariantes, contexto, "entity")).join("\n\n");
668
+ const enums = modulo.enums.map((item) => gerarEnum(item.nome, item.valores)).join("\n\n");
669
+ const tasks = modulo.tasks.map((task) => gerarTask(task, contexto)).join("\n\n");
670
+ const interops = modulo.interoperabilidades.map((item) => `// SEMA-INTEROP: ${item.origem}:${escaparComentario(item.caminho)}`).join("\n");
671
+ const flows = modulo.flows.map((item) => `// SEMA-FLOW: ${escaparComentario(item.nome)} tasks=${escaparComentario(item.tasksReferenciadas.join(", ") || "nenhuma")}`).join("\n");
672
+ const routes = modulo.routes.map((item) => `// SEMA-ROUTE: ${escaparComentario(item.nome)} metodo=${escaparComentario(item.metodo ?? "nao_definido")} caminho=${escaparComentario(item.caminho ?? "nao_definido")} task=${escaparComentario(item.task ?? "nao_definida")}`).join("\n");
673
+ const states = modulo.states.map((item) => `// SEMA-STATE: ${escaparComentario(item.nome ?? "anonimo")} campos=${item.campos.length} invariantes=${item.invariantes.length} transicoes=${item.transicoes.length}`).join("\n");
674
+ return `${gerarCabecalhoCSharp(modulo, "código C# gerado a partir do IR Sema, incluindo modelos, regras, garantias e metadados operacionais.")}using System;
675
+ using System.Collections.Generic;
676
+ using System.Globalization;
677
+ using System.Linq;
678
+
679
+ namespace ${namespace};
680
+
681
+ public class SemaContractException : Exception
682
+ {
683
+ public SemaContractException(string code, string message) : base(message) => Code = code;
684
+ public string Code { get; }
685
+ }
686
+
687
+ public sealed class SemaValidationException : SemaContractException
688
+ {
689
+ public SemaValidationException(string rule) : base("regra_invalida", $"Regra Sema violada: {rule}") { }
690
+ }
691
+
692
+ public sealed class SemaGuaranteeException : SemaContractException
693
+ {
694
+ public SemaGuaranteeException(string guarantee) : base("garantia_violada", $"Garantia Sema violada: {guarantee}") { }
695
+ }
696
+
697
+ ${interops ? `${interops}\n\n` : ""}${externos ? `${externos}\n\n` : ""}${enums ? `${enums}\n\n` : ""}${tipos ? `${tipos}\n\n` : ""}${entidades ? `${entidades}\n\n` : ""}${tasks}${states ? `\n\n${states}` : ""}${flows ? `\n${flows}` : ""}${routes ? `\n${routes}` : ""}
698
+ `;
699
+ }
700
+ function gerarCodigoTestes(modulo, contexto) {
701
+ const namespace = nomeNamespace(modulo.nome);
702
+ const metodos = modulo.tasks.flatMap((task) => task.tests.map((caso, indice) => gerarMetodoTeste(task, caso, indice, contexto)));
703
+ if (metodos.length === 0) {
704
+ metodos.push({
705
+ nome: "TestEstruturaGerada",
706
+ codigo: ` // SEMA-TEST: estrutura gerada :: módulo sem casos declarados
707
+ private static void TestEstruturaGerada()
708
+ {
709
+ SemaAssert.True(true, "A estrutura .NET gerada deve ser executavel.");
710
+ }`,
711
+ });
712
+ }
713
+ const registros = metodos.map((metodo) => ` (${literalString(metodo.nome)}, ${metodo.nome}),`).join("\n");
714
+ return `${gerarCabecalhoCSharp(modulo, "runner de testes .NET gerado sem framework ou pacote NuGet externo.")}using System;
715
+ using System.Collections.Generic;
716
+ using System.Globalization;
717
+ using ${namespace};
718
+
719
+ internal static class SemaAssert
720
+ {
721
+ public static void True(bool condition, string message)
722
+ {
723
+ if (!condition) throw new InvalidOperationException(message);
724
+ }
725
+
726
+ public static void NotNull(object? value, string message) => True(value is not null, message);
727
+
728
+ public static void Equal<T>(T expected, T actual, string message)
729
+ {
730
+ if (!EqualityComparer<T>.Default.Equals(expected, actual))
731
+ {
732
+ throw new InvalidOperationException($"{message} Esperado={expected}; Atual={actual}.");
733
+ }
734
+ }
735
+ }
736
+
737
+ internal static class Program
738
+ {
739
+ private static int Main()
740
+ {
741
+ var tests = new (string Name, Action Run)[]
742
+ {
743
+ ${registros}
744
+ };
745
+
746
+ foreach (var test in tests)
747
+ {
748
+ Console.WriteLine($"test {test.Name}");
749
+ test.Run();
750
+ }
751
+
752
+ Console.WriteLine($"ok {tests.Length} testes");
753
+ return 0;
754
+ }
755
+
756
+ ${metodos.map((metodo) => metodo.codigo).join("\n\n")}
757
+ }
758
+ `;
759
+ }
760
+ function gerarProjetoFonte(modulo, base, assemblyName) {
761
+ return `${gerarCabecalhoProjeto(modulo, "biblioteca .NET gerada sem dependências NuGet externas.")}
762
+ <Project Sdk="Microsoft.NET.Sdk">
763
+ <PropertyGroup>
764
+ <TargetFramework>net8.0</TargetFramework>
765
+ <ImplicitUsings>enable</ImplicitUsings>
766
+ <Nullable>enable</Nullable>
767
+ <LangVersion>latest</LangVersion>
768
+ <AssemblyName>${assemblyName}</AssemblyName>
769
+ <RootNamespace>${assemblyName}</RootNamespace>
770
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
771
+ </PropertyGroup>
772
+ <ItemGroup>
773
+ <Compile Include="${base}.cs" />
774
+ </ItemGroup>
775
+ </Project>
776
+ `;
777
+ }
778
+ function gerarProjetoTestes(modulo, base, assemblyName) {
779
+ return `${gerarCabecalhoProjeto(modulo, "executavel de testes .NET autocontido, sem xUnit, MSTest, NUnit ou outro pacote NuGet.")}
780
+ <Project Sdk="Microsoft.NET.Sdk">
781
+ <PropertyGroup>
782
+ <OutputType>Exe</OutputType>
783
+ <TargetFramework>net8.0</TargetFramework>
784
+ <ImplicitUsings>enable</ImplicitUsings>
785
+ <Nullable>enable</Nullable>
786
+ <LangVersion>latest</LangVersion>
787
+ <AssemblyName>${assemblyName}.Tests</AssemblyName>
788
+ <RootNamespace>${assemblyName}.Tests</RootNamespace>
789
+ <EnableDefaultCompileItems>false</EnableDefaultCompileItems>
790
+ </PropertyGroup>
791
+ <ItemGroup>
792
+ <Compile Include="${base}.Tests.cs" />
793
+ <ProjectReference Include="${base}.csproj" />
794
+ </ItemGroup>
795
+ </Project>
796
+ `;
797
+ }
798
+ export function gerarDotNet(modulo) {
799
+ const base = normalizarNomeModulo(modulo.nome).replace(/\./g, "_") || "sema_generated";
800
+ const assemblyName = nomeProjeto(modulo.nome);
801
+ const enums = new Set(modulo.enums.map((item) => paraPascalCase(item.nome)));
802
+ const valoresEnums = new Map(modulo.enums.map((item) => [paraPascalCase(item.nome), item.valores]));
803
+ const tiposLocais = new Set([
804
+ ...modulo.types.map((item) => paraPascalCase(item.nome)),
805
+ ...modulo.entities.map((item) => paraPascalCase(item.nome)),
806
+ ...coletarTiposExternos(modulo).map((item) => paraPascalCase(item)),
807
+ ]);
808
+ const contexto = { enums, valoresEnums, tiposLocais };
809
+ return [
810
+ {
811
+ caminhoRelativo: `${base}.csproj`,
812
+ conteudo: gerarProjetoFonte(modulo, base, assemblyName),
813
+ },
814
+ {
815
+ caminhoRelativo: `${base}.cs`,
816
+ conteudo: gerarCodigoFonte(modulo, contexto),
817
+ },
818
+ {
819
+ caminhoRelativo: `${base}.Tests.csproj`,
820
+ conteudo: gerarProjetoTestes(modulo, base, assemblyName),
821
+ },
822
+ {
823
+ caminhoRelativo: `${base}.Tests.cs`,
824
+ conteudo: gerarCodigoTestes(modulo, contexto),
825
+ },
826
+ ];
827
+ }
828
+ //# sourceMappingURL=index.js.map