@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,859 @@
1
+ // SEMA-GOVERNED: sema.produto.geradores_nativos, sema.produto.geradores_codigo_governado
2
+ // Descrição: gera projetos C++/CMake autocontidos e testes locais sem framework externo a partir do IR Sema.
3
+ import path from "node:path";
4
+ import { descreverEstruturaModulo, dividirTipoNoNivelRaiz, extrairTiposNomeados, normalizarNomeModulo, normalizarNomeParaSimbolo, } from "@sema/padroes";
5
+ const TIPOS_PRIMITIVOS_SEMA = new Set([
6
+ "Texto",
7
+ "Numero",
8
+ "Inteiro",
9
+ "Decimal",
10
+ "Booleano",
11
+ "Data",
12
+ "DataHora",
13
+ "Id",
14
+ "Email",
15
+ "Url",
16
+ "Json",
17
+ "Objeto",
18
+ "Lista",
19
+ "Mapa",
20
+ "Vazio",
21
+ ]);
22
+ const PALAVRAS_RESERVADAS_CPP = new Set([
23
+ "alignas", "alignof", "and", "and_eq", "asm", "auto", "bitand", "bitor", "bool", "break",
24
+ "case", "catch", "char", "char16_t", "char32_t", "class", "compl", "concept", "const",
25
+ "consteval", "constexpr", "constinit", "const_cast", "continue", "co_await", "co_return", "co_yield",
26
+ "decltype", "default", "delete", "do", "double", "dynamic_cast", "else", "enum", "explicit",
27
+ "export", "extern", "false", "float", "for", "friend", "goto", "if", "inline", "int", "long",
28
+ "mutable", "namespace", "new", "noexcept", "not", "not_eq", "nullptr", "operator", "or", "or_eq",
29
+ "private", "protected", "public", "register", "reinterpret_cast", "requires", "return", "short",
30
+ "signed", "sizeof", "static", "static_assert", "static_cast", "struct", "switch", "template", "this",
31
+ "thread_local", "throw", "true", "try", "typedef", "typeid", "typename", "union", "unsigned", "using",
32
+ "virtual", "void", "volatile", "wchar_t", "while", "xor", "xor_eq",
33
+ ]);
34
+ function identificadorCpp(valor, fallback = "valor") {
35
+ let simbolo = normalizarNomeParaSimbolo(valor) || fallback;
36
+ if (/^\d/.test(simbolo)) {
37
+ simbolo = `valor_${simbolo}`;
38
+ }
39
+ if (PALAVRAS_RESERVADAS_CPP.has(simbolo)) {
40
+ simbolo = `${simbolo}_sema`;
41
+ }
42
+ return simbolo;
43
+ }
44
+ function paraPascalCase(valor) {
45
+ const partes = identificadorCpp(valor, "Contrato").split(/_+/).filter(Boolean);
46
+ const nome = partes.map((parte) => parte[0].toUpperCase() + parte.slice(1)).join("");
47
+ const seguro = nome || "Contrato";
48
+ return /^\d/.test(seguro) ? `Tipo${seguro}` : seguro;
49
+ }
50
+ function paraConstanteCpp(valor) {
51
+ const simbolo = identificadorCpp(valor, "VAZIO").toUpperCase();
52
+ return /^\d/.test(simbolo) ? `VALOR_${simbolo}` : simbolo;
53
+ }
54
+ function comentarioCpp(valor) {
55
+ return valor.replace(/[\r\n]+/g, " ").replace(/\s+/g, " ").trim();
56
+ }
57
+ function literalStringCpp(valor) {
58
+ return JSON.stringify(valor);
59
+ }
60
+ function removerAspas(valor) {
61
+ return valor.trim().replace(/^["']|["']$/g, "");
62
+ }
63
+ function nomeNamespace(modulo) {
64
+ const segmentos = modulo.nome.split(".").map((item) => identificadorCpp(item.toLowerCase())).filter(Boolean);
65
+ return ["sema_generated", ...segmentos].join("::");
66
+ }
67
+ function mapearTipoCpp(tipo) {
68
+ const limpo = tipo.trim();
69
+ const uniao = dividirTipoNoNivelRaiz(limpo, "|");
70
+ if (uniao.length > 1) {
71
+ const alternativas = [...new Set(uniao.map(mapearTipoCpp))];
72
+ return `std::variant<${alternativas.join(", ")}>`;
73
+ }
74
+ if (/^Opcional<.+>$/.test(limpo)) {
75
+ return `std::optional<${mapearTipoCpp(limpo.slice("Opcional<".length, -1))}>`;
76
+ }
77
+ if (limpo.endsWith("[]")) {
78
+ return `std::vector<${mapearTipoCpp(limpo.slice(0, -2))}>`;
79
+ }
80
+ if (/^Lista<.+>$/.test(limpo)) {
81
+ return `std::vector<${mapearTipoCpp(limpo.slice("Lista<".length, -1))}>`;
82
+ }
83
+ if (/^Mapa<.+>$/.test(limpo)) {
84
+ const partes = dividirTipoNoNivelRaiz(limpo.slice("Mapa<".length, -1), ",");
85
+ return `std::map<${mapearTipoCpp(partes[0] ?? "Texto")}, ${mapearTipoCpp(partes[1] ?? "Json")}>`;
86
+ }
87
+ switch (limpo) {
88
+ case "Texto":
89
+ case "Id":
90
+ case "Email":
91
+ case "Url":
92
+ case "Data":
93
+ case "DataHora":
94
+ return "std::string";
95
+ case "Numero":
96
+ case "Decimal":
97
+ return "double";
98
+ case "Inteiro":
99
+ return "std::int64_t";
100
+ case "Booleano":
101
+ return "bool";
102
+ case "Json":
103
+ return "JsonValue";
104
+ case "Objeto":
105
+ return "std::map<std::string, JsonValue>";
106
+ case "Lista":
107
+ return "std::vector<JsonValue>";
108
+ case "Mapa":
109
+ return "std::map<std::string, JsonValue>";
110
+ case "Vazio":
111
+ return "std::monostate";
112
+ default:
113
+ return paraPascalCase(limpo);
114
+ }
115
+ }
116
+ function tipoCampoCpp(campo) {
117
+ let tipo;
118
+ if (campo.cardinalidade === "lista") {
119
+ tipo = `std::vector<${mapearTipoCpp(campo.tipoItem ?? campo.tipoBase)}>`;
120
+ }
121
+ else if (campo.cardinalidade === "mapa") {
122
+ tipo = `std::map<${mapearTipoCpp(campo.chaveMapa ?? "Texto")}, ${mapearTipoCpp(campo.valorMapa ?? "Json")}>`;
123
+ }
124
+ else if (campo.cardinalidade === "uniao") {
125
+ const alternativas = [...new Set(campo.tiposAlternativos.map(mapearTipoCpp))];
126
+ tipo = alternativas.length > 0 ? `std::variant<${alternativas.join(", ")}>` : "JsonValue";
127
+ }
128
+ else {
129
+ tipo = mapearTipoCpp(campo.tipoBase || campo.tipo);
130
+ }
131
+ if (campo.opcional && !tipo.startsWith("std::optional<")) {
132
+ return `std::optional<${tipo}>`;
133
+ }
134
+ return tipo;
135
+ }
136
+ function enumDoCampo(campo, modulo) {
137
+ return modulo.enums.find((item) => item.nome === campo.tipoBase || item.nome === campo.tipo);
138
+ }
139
+ function valorInicialCpp(campo, modulo, modo) {
140
+ if (campo.opcional) {
141
+ return "std::nullopt";
142
+ }
143
+ if (campo.cardinalidade === "lista" || campo.cardinalidade === "mapa") {
144
+ return "{}";
145
+ }
146
+ if (campo.cardinalidade === "uniao") {
147
+ const primeiro = campo.tiposAlternativos[0];
148
+ return primeiro ? `${mapearTipoCpp(primeiro)}{}` : "JsonValue{}";
149
+ }
150
+ const enumeracao = enumDoCampo(campo, modulo);
151
+ if (enumeracao) {
152
+ return `${paraPascalCase(enumeracao.nome)}::${paraConstanteCpp(enumeracao.valores[0] ?? "VAZIO")}`;
153
+ }
154
+ switch (campo.tipoBase) {
155
+ case "Texto":
156
+ case "Id":
157
+ case "Email":
158
+ case "Url":
159
+ case "Data":
160
+ case "DataHora":
161
+ return modo === "saida" ? literalStringCpp(`${campo.nome}_exemplo`) : "{}";
162
+ case "Numero":
163
+ case "Decimal":
164
+ return modo === "saida" ? "1.0" : "0.0";
165
+ case "Inteiro":
166
+ return modo === "saida" ? "1" : "0";
167
+ case "Booleano":
168
+ return "false";
169
+ case "Json":
170
+ return modo === "saida" ? literalStringCpp("{}") : "{}";
171
+ case "Vazio":
172
+ return "{}";
173
+ default:
174
+ return "{}";
175
+ }
176
+ }
177
+ function literalCpp(valor, campo, modulo) {
178
+ const texto = removerAspas(valor);
179
+ if (!campo) {
180
+ if (texto === "verdadeiro")
181
+ return "true";
182
+ if (texto === "falso")
183
+ return "false";
184
+ if (texto === "nulo")
185
+ return "{}";
186
+ if (/^-?\d+(?:\.\d+)?$/.test(texto))
187
+ return texto;
188
+ return literalStringCpp(texto);
189
+ }
190
+ const ehLista = campo.cardinalidade === "lista" || campo.tipoBase === "Lista";
191
+ const ehMapa = campo.cardinalidade === "mapa" || ["Mapa", "Objeto"].includes(campo.tipoBase);
192
+ if (ehLista) {
193
+ const tipoItem = campo.tipoItem ?? "Json";
194
+ const campoItem = {
195
+ ...campo,
196
+ tipo: tipoItem,
197
+ tipoOriginal: tipoItem,
198
+ tipoBase: tipoItem,
199
+ cardinalidade: "unitario",
200
+ opcional: false,
201
+ tiposAlternativos: [],
202
+ refinamentos: [],
203
+ };
204
+ const itens = dividirTipoNoNivelRaiz(texto.replace(/^\[|\]$/g, ""), ",")
205
+ .filter(Boolean)
206
+ .map((item) => literalCpp(item, campoItem, modulo));
207
+ const tipo = tipoCampoCpp(campo).replace(/^std::optional<(.+)>$/, "$1");
208
+ return `${tipo}{${itens.join(", ")}}`;
209
+ }
210
+ if (ehMapa) {
211
+ const tipo = tipoCampoCpp(campo).replace(/^std::optional<(.+)>$/, "$1");
212
+ return `${tipo}{}`;
213
+ }
214
+ const enumeracao = enumDoCampo(campo, modulo);
215
+ if (enumeracao) {
216
+ return `${paraPascalCase(enumeracao.nome)}::${paraConstanteCpp(texto)}`;
217
+ }
218
+ switch (campo.tipoBase) {
219
+ case "Booleano":
220
+ return texto === "verdadeiro" || texto === "true" ? "true" : "false";
221
+ case "Numero":
222
+ case "Decimal":
223
+ case "Inteiro":
224
+ return /^-?\d+(?:\.\d+)?$/.test(texto) ? texto : valorInicialCpp(campo, modulo, "modelo");
225
+ case "Texto":
226
+ case "Id":
227
+ case "Email":
228
+ case "Url":
229
+ case "Data":
230
+ case "DataHora":
231
+ case "Json":
232
+ return literalStringCpp(texto);
233
+ case "Vazio":
234
+ return "{}";
235
+ default:
236
+ return `${tipoCampoCpp(campo)}{}`;
237
+ }
238
+ }
239
+ function coletarTiposExternos(modulo) {
240
+ const locais = new Set([
241
+ ...modulo.types.map((item) => item.nome),
242
+ ...modulo.entities.map((item) => item.nome),
243
+ ...modulo.enums.map((item) => item.nome),
244
+ ]);
245
+ const campos = [
246
+ ...modulo.types.flatMap((item) => item.definicao.campos),
247
+ ...modulo.entities.flatMap((item) => item.campos),
248
+ ...modulo.tasks.flatMap((item) => [...item.input, ...item.output]),
249
+ ...modulo.routes.flatMap((item) => [...item.inputPublico, ...item.outputPublico]),
250
+ ...modulo.states.flatMap((item) => item.campos),
251
+ ];
252
+ const externos = new Set();
253
+ for (const campo of campos) {
254
+ for (const tipo of extrairTiposNomeados(campo.tipo)) {
255
+ if (!locais.has(tipo) && !TIPOS_PRIMITIVOS_SEMA.has(tipo)) {
256
+ externos.add(tipo);
257
+ }
258
+ }
259
+ }
260
+ return [...externos].sort((a, b) => a.localeCompare(b, "pt-BR"));
261
+ }
262
+ function ordenarModelos(modulo) {
263
+ const modelos = [
264
+ ...modulo.types.map((item) => ({ nome: item.nome, campos: item.definicao.campos, origem: "type" })),
265
+ ...modulo.entities.map((item) => ({ nome: item.nome, campos: item.campos, origem: "entity" })),
266
+ ];
267
+ const nomes = new Set(modelos.map((item) => item.nome));
268
+ const pendentes = [...modelos];
269
+ const emitidos = new Set();
270
+ const ordenados = [];
271
+ while (pendentes.length > 0) {
272
+ const indice = pendentes.findIndex((modelo) => modelo.campos.every((campo) => extrairTiposNomeados(campo.tipo).every((tipo) => !nomes.has(tipo) || tipo === modelo.nome || emitidos.has(tipo))));
273
+ const escolhido = pendentes.splice(indice >= 0 ? indice : 0, 1)[0];
274
+ ordenados.push(escolhido);
275
+ emitidos.add(escolhido.nome);
276
+ }
277
+ return ordenados;
278
+ }
279
+ function gerarStruct(nome, campos, modulo, modo) {
280
+ const linhas = campos.map((campo) => ` ${tipoCampoCpp(campo)} ${identificadorCpp(campo.nome)} = ${valorInicialCpp(campo, modulo, modo)};`);
281
+ return `struct ${paraPascalCase(nome)} final {
282
+ ${linhas.length > 0 ? linhas.join("\n") : " // Estrutura intencionalmente vazia."}
283
+ bool operator==(const ${paraPascalCase(nome)}&) const = default;
284
+ };`;
285
+ }
286
+ function gerarEnum(nome, valores) {
287
+ const itens = (valores.length > 0 ? valores : ["VAZIO"]).map((valor) => ` ${paraConstanteCpp(valor)}`).join(",\n");
288
+ return `enum class ${paraPascalCase(nome)} {
289
+ ${itens}
290
+ };`;
291
+ }
292
+ function camposPorNome(campos) {
293
+ return new Map(campos.map((campo) => [campo.nome, campo]));
294
+ }
295
+ function resolverReferenciaCpp(referencia, campos, variavel, modulo) {
296
+ const partes = referencia.split(".").filter(Boolean);
297
+ let campo = campos.get(partes[0] ?? "");
298
+ if (!campo)
299
+ return undefined;
300
+ let codigo = `${variavel}.${identificadorCpp(campo.nome)}`;
301
+ for (const parte of partes.slice(1)) {
302
+ const modelo = [...modulo.types.map((item) => ({ nome: item.nome, campos: item.definicao.campos })), ...modulo.entities]
303
+ .find((item) => item.nome === campo?.tipoBase);
304
+ const filho = modelo?.campos.find((item) => item.nome === parte);
305
+ if (!filho)
306
+ return undefined;
307
+ codigo += `${campo.opcional ? "->" : "."}${identificadorCpp(filho.nome)}`;
308
+ campo = filho;
309
+ }
310
+ return { codigo, campo };
311
+ }
312
+ function formatarValorExpressaoCpp(valor, alvo, campos, variavel, modulo) {
313
+ const referenciaValor = resolverReferenciaCpp(valor, campos, variavel, modulo);
314
+ if (referenciaValor)
315
+ return referenciaValor.codigo;
316
+ return literalCpp(valor, resolverReferenciaCpp(alvo, campos, variavel, modulo)?.campo, modulo);
317
+ }
318
+ function expressaoExisteCpp(alvo, campos, variavel, modulo) {
319
+ const referencia = resolverReferenciaCpp(alvo, campos, variavel, modulo);
320
+ if (!referencia)
321
+ return undefined;
322
+ if (referencia.campo.opcional)
323
+ return `${referencia.codigo}.has_value()`;
324
+ if (referencia.campo.cardinalidade === "lista"
325
+ || referencia.campo.cardinalidade === "mapa"
326
+ || ["Texto", "Id", "Email", "Url", "Data", "DataHora", "Json", "Lista", "Mapa", "Objeto"].includes(referencia.campo.tipoBase)) {
327
+ return `!${referencia.codigo}.empty()`;
328
+ }
329
+ return "true";
330
+ }
331
+ function resolverPredicadoCpp(expressao, campos, variavel, modulo) {
332
+ const referencia = resolverReferenciaCpp(expressao.alvo, campos, variavel, modulo);
333
+ if (!referencia)
334
+ return undefined;
335
+ const predicado = expressao.predicadoCanonico ?? expressao.predicado;
336
+ if (["preenchido", "nao_vazio", "valido"].includes(predicado)) {
337
+ return expressaoExisteCpp(expressao.alvo, campos, variavel, modulo);
338
+ }
339
+ if (predicado === "positivo" && ["Numero", "Inteiro", "Decimal"].includes(referencia.campo.tipoBase)) {
340
+ return `${referencia.codigo} > 0`;
341
+ }
342
+ if (predicado === "diferente_de_zero" && ["Numero", "Inteiro", "Decimal"].includes(referencia.campo.tipoBase)) {
343
+ return `${referencia.codigo} != 0`;
344
+ }
345
+ if (predicado === "numero_valido" && ["Numero", "Decimal"].includes(referencia.campo.tipoBase)) {
346
+ return `std::isfinite(${referencia.codigo})`;
347
+ }
348
+ if (predicado === "email_valido" && ["Texto", "Email"].includes(referencia.campo.tipoBase)) {
349
+ return `${referencia.codigo}.find('@') != std::string::npos`;
350
+ }
351
+ if (["em", "um_de"].includes(predicado) && expressao.argumentos) {
352
+ const valores = dividirTipoNoNivelRaiz(expressao.argumentos.replace(/^\[|\]$/g, ""), ",").filter(Boolean);
353
+ return valores.length > 0
354
+ ? `(${valores.map((valor) => `${referencia.codigo} == ${literalCpp(valor, referencia.campo, modulo)}`).join(" || ")})`
355
+ : undefined;
356
+ }
357
+ if (predicado === "booleano")
358
+ return referencia.campo.tipoBase === "Booleano" ? "true" : undefined;
359
+ if (predicado === "verdadeiro" && referencia.campo.tipoBase === "Booleano")
360
+ return referencia.codigo;
361
+ return undefined;
362
+ }
363
+ function resolverExpressaoCpp(expressao, campos, variavel, modulo) {
364
+ switch (expressao.tipo) {
365
+ case "existe":
366
+ return expressaoExisteCpp(expressao.alvo, campos, variavel, modulo);
367
+ case "comparacao": {
368
+ if (/\squando\s/u.test(expressao.valor))
369
+ return undefined;
370
+ const alvo = resolverReferenciaCpp(expressao.alvo, campos, variavel, modulo);
371
+ if (!alvo)
372
+ return undefined;
373
+ const valor = expressao.valorLiteral === false
374
+ ? resolverReferenciaCpp(expressao.valor, campos, variavel, modulo)?.codigo
375
+ : formatarValorExpressaoCpp(expressao.valor, expressao.alvo, campos, variavel, modulo);
376
+ if (!valor)
377
+ return undefined;
378
+ if (!["==", "!="].includes(expressao.operador)
379
+ && !["Texto", "Id", "Email", "Url", "Data", "DataHora", "Numero", "Inteiro", "Decimal"].includes(alvo.campo.tipoBase)
380
+ && !enumDoCampo(alvo.campo, modulo))
381
+ return undefined;
382
+ return `${alvo.codigo} ${expressao.operador} ${valor}`;
383
+ }
384
+ case "pertencimento": {
385
+ const alvo = resolverReferenciaCpp(expressao.alvo, campos, variavel, modulo);
386
+ if (!alvo)
387
+ return undefined;
388
+ const opcoes = expressao.valores.map((valor) => `${alvo.codigo} == ${literalCpp(valor, alvo.campo, modulo)}`);
389
+ return opcoes.length > 0 ? `(${opcoes.join(" || ")})` : "false";
390
+ }
391
+ case "predicado":
392
+ return resolverPredicadoCpp(expressao, campos, variavel, modulo);
393
+ case "composta": {
394
+ const termos = expressao.termos.map((termo) => resolverExpressaoCpp(termo, campos, variavel, modulo));
395
+ return termos.some((termo) => !termo)
396
+ ? undefined
397
+ : `(${termos.join(expressao.operadorLogico === "e" ? " && " : " || ")})`;
398
+ }
399
+ case "negacao": {
400
+ const termo = resolverExpressaoCpp(expressao.termo, campos, variavel, modulo);
401
+ return termo ? `!(${termo})` : undefined;
402
+ }
403
+ }
404
+ }
405
+ function gerarValidacoes(task, modulo) {
406
+ const campos = camposPorNome(task.input);
407
+ const linhas = [" (void)entrada;"];
408
+ for (const campo of task.input.filter((item) => item.modificadores.includes("required"))) {
409
+ const referencia = `entrada.${identificadorCpp(campo.nome)}`;
410
+ if (campo.opcional) {
411
+ linhas.push(` if (!${referencia}.has_value()) throw std::invalid_argument(${literalStringCpp(`Campo obrigatório ausente: ${campo.nome}`)});`);
412
+ }
413
+ else if (["Texto", "Id", "Email", "Url", "Data", "DataHora"].includes(campo.tipoBase)) {
414
+ linhas.push(` if (${referencia}.empty()) throw std::invalid_argument(${literalStringCpp(`Campo obrigatório vazio: ${campo.nome}`)});`);
415
+ }
416
+ }
417
+ for (const regra of task.regrasEstruturadas) {
418
+ const condicao = resolverExpressaoCpp(regra, campos, "entrada", modulo);
419
+ linhas.push(condicao
420
+ ? ` if (!(${condicao})) throw std::invalid_argument(${literalStringCpp(`Regra violada: ${regra.textoOriginal}`)});`
421
+ : ` // SEMA-UNENFORCED: regra exige implementação de domínio: ${comentarioCpp(regra.textoOriginal)}`);
422
+ }
423
+ for (const regra of task.rules.filter((item) => !task.regrasEstruturadas.some((estruturada) => estruturada.textoOriginal === item))) {
424
+ linhas.push(` // Regra declarada em Sema: ${comentarioCpp(regra)}`);
425
+ }
426
+ return linhas.join("\n");
427
+ }
428
+ function gerarGarantias(task, modulo) {
429
+ const campos = camposPorNome(task.output);
430
+ const linhas = [" (void)saida;"];
431
+ for (const garantia of task.garantiasEstruturadas) {
432
+ const condicao = resolverExpressaoCpp(garantia, campos, "saida", modulo);
433
+ linhas.push(condicao
434
+ ? ` if (!(${condicao})) throw std::runtime_error(${literalStringCpp(`Garantia violada: ${garantia.textoOriginal}`)});`
435
+ : ` // SEMA-UNENFORCED: garantia exige implementação de domínio: ${comentarioCpp(garantia.textoOriginal)}`);
436
+ }
437
+ for (const garantia of task.guarantees.filter((item) => !task.garantiasEstruturadas.some((estruturada) => estruturada.textoOriginal === item))) {
438
+ linhas.push(` // Garantia declarada em Sema: ${comentarioCpp(garantia)}`);
439
+ }
440
+ return linhas.join("\n");
441
+ }
442
+ function coletarErrosTask(task) {
443
+ const erros = new Map(Object.entries(task.errors));
444
+ for (const caso of task.tests) {
445
+ const tipo = caso.error?.campos.find((campo) => campo.nome === "tipo")?.tipo ?? caso.error?.campos[0]?.tipo;
446
+ if (tipo && !erros.has(tipo)) {
447
+ erros.set(tipo, `Erro sintético gerado a partir do caso de teste "${caso.nome}".`);
448
+ }
449
+ }
450
+ return erros;
451
+ }
452
+ function nomeClasseErro(task, codigo) {
453
+ return `${paraPascalCase(task.nome)}${paraPascalCase(codigo)}Erro`;
454
+ }
455
+ function gerarErrosTask(task) {
456
+ return [...coletarErrosTask(task).entries()].map(([codigo, mensagem]) => `class ${nomeClasseErro(task, codigo)} final : public std::runtime_error {
457
+ public:
458
+ inline static constexpr std::string_view codigo = ${literalStringCpp(codigo)};
459
+ ${nomeClasseErro(task, codigo)}() : std::runtime_error(${literalStringCpp(mensagem)}) {}
460
+ };`).join("\n\n");
461
+ }
462
+ function literalCamposContrato(campos) {
463
+ return campos.length > 0
464
+ ? `{\n${campos.map((campo) => ` {${literalStringCpp(campo.nome)}, ${literalStringCpp(campo.tipo)}, ${campo.modificadores.includes("required") ? "true" : "false"}}`).join(",\n")}\n }`
465
+ : "{}";
466
+ }
467
+ function literalStringsCpp(valores) {
468
+ return valores.length > 0 ? `{${valores.map((item) => literalStringCpp(item)).join(", ")}}` : "{}";
469
+ }
470
+ function gerarDeclaracoesTask(task, modulo) {
471
+ const nome = identificadorCpp(task.nome);
472
+ const entrada = paraPascalCase(`${task.nome}_entrada`);
473
+ const saida = paraPascalCase(`${task.nome}_saida`);
474
+ return `${gerarStruct(`${task.nome}_entrada`, task.input, modulo, "entrada")}
475
+
476
+ ${gerarStruct(`${task.nome}_saida`, task.output, modulo, "saida")}
477
+
478
+ ${gerarErrosTask(task)}${coletarErrosTask(task).size > 0 ? "\n\n" : ""}TaskContract contrato_${nome}();
479
+ void validar_${nome}(const ${entrada}& entrada);
480
+ void verificar_garantias_${nome}(const ${saida}& saida);
481
+ ${saida} executar_${nome}(const ${entrada}& entrada, const ExecutionContext& contexto = {});`;
482
+ }
483
+ function valorExistenteCpp(campo, modulo) {
484
+ if (campo.cardinalidade === "lista" || campo.tipoBase === "Lista") {
485
+ return literalCpp("valor_garantido", campo, modulo);
486
+ }
487
+ if (campo.cardinalidade === "mapa" || ["Mapa", "Objeto"].includes(campo.tipoBase)) {
488
+ const tipo = tipoCampoCpp(campo).replace(/^std::optional<(.+)>$/, "$1");
489
+ const tipoChave = mapearTipoCpp(campo.chaveMapa ?? "Texto");
490
+ const tipoValor = mapearTipoCpp(campo.valorMapa ?? "Json");
491
+ const chave = tipoChave === "std::string" ? literalStringCpp("chave") : `${tipoChave}{}`;
492
+ const valor = tipoValor === "std::string" ? literalStringCpp("valor") : `${tipoValor}{}`;
493
+ return `${tipo}{{${chave}, ${valor}}}`;
494
+ }
495
+ if (["Texto", "Id", "Email", "Url", "Data", "DataHora", "Json"].includes(campo.tipoBase)) {
496
+ return literalCpp("valor_garantido", campo, modulo);
497
+ }
498
+ if (campo.opcional) {
499
+ return tipoCampoCpp(campo).replace(/^std::optional<(.+)>$/, "$1") + "{}";
500
+ }
501
+ return undefined;
502
+ }
503
+ function valorParaComparacaoCpp(garantia, campo, modulo) {
504
+ if (garantia.valorLiteral === false)
505
+ return undefined;
506
+ if (garantia.operador === "==")
507
+ return literalCpp(garantia.valor, campo, modulo);
508
+ const texto = removerAspas(garantia.valor);
509
+ if (campo.tipoBase === "Booleano" && garantia.operador === "!=") {
510
+ return ["verdadeiro", "true"].includes(texto) ? "false" : "true";
511
+ }
512
+ const numero = Number(texto);
513
+ if (["Numero", "Inteiro", "Decimal"].includes(campo.tipoBase) && Number.isFinite(numero)) {
514
+ const delta = garantia.operador === ">" || garantia.operador === "!=" ? 1 : garantia.operador === "<" ? -1 : 0;
515
+ return String(numero + delta);
516
+ }
517
+ if (garantia.operador === "!=" && ["Texto", "Id", "Email", "Url"].includes(campo.tipoBase)) {
518
+ return literalStringCpp(`${texto}_alternativo`);
519
+ }
520
+ return undefined;
521
+ }
522
+ function gerarAjustesSaida(task, modulo) {
523
+ const campos = camposPorNome(task.output);
524
+ const ajustes = [];
525
+ const ajustar = (garantia) => {
526
+ if (garantia.tipo === "composta") {
527
+ const termos = garantia.operadorLogico === "e" ? garantia.termos : garantia.termos.slice(0, 1);
528
+ termos.forEach(ajustar);
529
+ return;
530
+ }
531
+ if (garantia.tipo === "negacao")
532
+ return;
533
+ const referencia = "alvo" in garantia
534
+ ? resolverReferenciaCpp(garantia.alvo, campos, "saida", modulo)
535
+ : undefined;
536
+ if (!referencia)
537
+ return;
538
+ const campo = referencia.campo;
539
+ const destino = referencia.codigo;
540
+ if (garantia.tipo === "pertencimento" && garantia.valores[0] !== undefined) {
541
+ ajustes.push(` ${destino} = ${literalCpp(garantia.valores[0], campo, modulo)};`);
542
+ }
543
+ if (garantia.tipo === "predicado" && ["em", "um_de"].includes(garantia.predicadoCanonico ?? garantia.predicado)
544
+ && garantia.argumentos) {
545
+ const primeiro = dividirTipoNoNivelRaiz(garantia.argumentos.replace(/^\[|\]$/g, ""), ",")[0];
546
+ if (primeiro)
547
+ ajustes.push(` ${destino} = ${literalCpp(primeiro, campo, modulo)};`);
548
+ }
549
+ if (garantia.tipo === "comparacao") {
550
+ const valor = valorParaComparacaoCpp(garantia, campo, modulo);
551
+ if (valor)
552
+ ajustes.push(` ${destino} = ${valor};`);
553
+ }
554
+ if (garantia.tipo === "existe" || (garantia.tipo === "predicado"
555
+ && ["preenchido", "nao_vazio", "valido"].includes(garantia.predicadoCanonico ?? garantia.predicado))) {
556
+ const valor = valorExistenteCpp(campo, modulo);
557
+ if (valor)
558
+ ajustes.push(` ${destino} = ${valor};`);
559
+ }
560
+ if (garantia.tipo === "predicado" && garantia.predicadoCanonico === "positivo"
561
+ && ["Numero", "Inteiro", "Decimal"].includes(campo.tipoBase)) {
562
+ ajustes.push(` ${destino} = 1;`);
563
+ }
564
+ };
565
+ task.garantiasEstruturadas.forEach(ajustar);
566
+ return ajustes;
567
+ }
568
+ function gerarImplementacaoTask(task, modulo) {
569
+ const nome = identificadorCpp(task.nome);
570
+ const entrada = paraPascalCase(`${task.nome}_entrada`);
571
+ const saida = paraPascalCase(`${task.nome}_saida`);
572
+ const erros = [...coletarErrosTask(task).keys()];
573
+ const falhas = erros.map((codigo) => ` if (contexto.erro_esperado == ${literalStringCpp(codigo)}) throw ${nomeClasseErro(task, codigo)}{};`).join("\n");
574
+ const efeitos = task.efeitosEstruturados.length > 0
575
+ ? task.efeitosEstruturados.map((efeito) => ` // Efeito estruturado: categoria=${comentarioCpp(efeito.categoria)} alvo=${comentarioCpp(efeito.alvo)}${efeito.detalhe ? ` detalhe=${comentarioCpp(efeito.detalhe)}` : ""}${efeito.criticidade ? ` criticidade=${efeito.criticidade}` : ""}`).join("\n")
576
+ : task.effects.map((efeito) => ` // Efeito declarado: ${comentarioCpp(efeito)}`).join("\n");
577
+ const metadadosEfeitos = task.efeitosEstruturados.map((efeito) => `${efeito.categoria}:${efeito.alvo}${efeito.detalhe ? `:${efeito.detalhe}` : ""}`);
578
+ return `TaskContract contrato_${nome}() {
579
+ return TaskContract{
580
+ ${literalStringCpp(task.nome)},
581
+ ${literalCamposContrato(task.input)},
582
+ ${literalCamposContrato(task.output)},
583
+ ${literalStringsCpp(task.rules)},
584
+ ${literalStringsCpp(task.guarantees)},
585
+ ${literalStringsCpp(metadadosEfeitos.length > 0 ? metadadosEfeitos : task.effects)}
586
+ };
587
+ }
588
+
589
+ void validar_${nome}(const ${entrada}& entrada) {
590
+ ${gerarValidacoes(task, modulo)}
591
+ }
592
+
593
+ void verificar_garantias_${nome}(const ${saida}& saida) {
594
+ ${gerarGarantias(task, modulo)}
595
+ }
596
+
597
+ ${saida} executar_${nome}(const ${entrada}& entrada, const ExecutionContext& contexto) {
598
+ (void)contexto;
599
+ ${falhas ? `${falhas}\n` : ""} validar_${nome}(entrada);
600
+ ${task.stateContract ? ` // Vínculo de estado: ${comentarioCpp(task.stateContract.nomeEstado ?? "não definido")}\n // Transições: ${comentarioCpp(task.stateContract.transicoes.map((item) => `${item.origem}->${item.destino}`).join(", ") || "nenhuma")}\n` : ""}${task.implementacoesExternas.map((item) => ` // Implementação externa: origem=${item.origem} caminho=${comentarioCpp(item.caminho)} status=${item.statusImpl ?? "não verificado"}`).join("\n")}${task.implementacoesExternas.length > 0 ? "\n" : ""}${efeitos || " // Nenhum efeito declarado."}
601
+ ${saida} saida{};
602
+ ${gerarAjustesSaida(task, modulo).join("\n")}${gerarAjustesSaida(task, modulo).length > 0 ? "\n" : ""} verificar_garantias_${nome}(saida);
603
+ return saida;
604
+ }`;
605
+ }
606
+ function formatarValorTesteCpp(valor, campo, modulo) {
607
+ return literalCpp(valor, campo, modulo);
608
+ }
609
+ function gerarAtribuicoesGiven(task, given, modulo) {
610
+ const campos = camposPorNome(task.input);
611
+ return given.campos.flatMap((item) => {
612
+ const campo = campos.get(item.nome);
613
+ if (!campo)
614
+ return [];
615
+ return [` entrada.${identificadorCpp(campo.nome)} = ${formatarValorTesteCpp(item.tipo, campo, modulo)};`];
616
+ }).join("\n");
617
+ }
618
+ function gerarAssercoesExpect(task, expect, modulo) {
619
+ const campos = camposPorNome(task.output);
620
+ return expect.campos.flatMap((item) => {
621
+ if (item.nome === "sucesso")
622
+ return [];
623
+ const campo = campos.get(item.nome);
624
+ if (!campo)
625
+ return [];
626
+ return [` assert_sema(resultado.${identificadorCpp(campo.nome)} == ${formatarValorTesteCpp(item.tipo, campo, modulo)}, ${literalStringCpp(`Saída inesperada para ${item.nome}`)});`];
627
+ }).join("\n");
628
+ }
629
+ function gerarFuncaoTeste(task, indice, modulo) {
630
+ const caso = task.tests[indice];
631
+ const nome = `test_${identificadorCpp(task.nome)}_${indice + 1}`;
632
+ const entrada = paraPascalCase(`${task.nome}_entrada`);
633
+ const atribuicoes = gerarAtribuicoesGiven(task, caso.given, modulo);
634
+ const tipoErro = caso.error?.campos.find((campo) => campo.nome === "tipo")?.tipo ?? caso.error?.campos[0]?.tipo;
635
+ if (tipoErro) {
636
+ return {
637
+ nome,
638
+ rotulo: caso.nome,
639
+ conteudo: `// SEMA-TEST: ${comentarioCpp(task.nome)} :: ${comentarioCpp(caso.nome)}
640
+ void ${nome}() {
641
+ ${entrada} entrada{};
642
+ ${atribuicoes ? `${atribuicoes}\n` : ""} ExecutionContext contexto{};
643
+ contexto.erro_esperado = ${literalStringCpp(tipoErro)};
644
+ try {
645
+ (void)executar_${identificadorCpp(task.nome)}(entrada, contexto);
646
+ } catch (const ${nomeClasseErro(task, tipoErro)}& erro) {
647
+ assert_sema(erro.codigo == ${literalStringCpp(tipoErro)}, "Código de erro inesperado");
648
+ return;
649
+ }
650
+ throw std::runtime_error(${literalStringCpp(`Caso ${caso.nome} deveria falhar com ${tipoErro}`)});
651
+ }`,
652
+ };
653
+ }
654
+ const assercoes = gerarAssercoesExpect(task, caso.expect, modulo);
655
+ const esperaFalha = caso.expect.campos.some((campo) => campo.nome === "sucesso" && ["falso", "false"].includes(removerAspas(campo.tipo).toLowerCase()));
656
+ if (esperaFalha) {
657
+ return {
658
+ nome,
659
+ rotulo: caso.nome,
660
+ conteudo: `// SEMA-TEST: ${comentarioCpp(task.nome)} :: ${comentarioCpp(caso.nome)}
661
+ void ${nome}() {
662
+ ${entrada} entrada{};
663
+ ${atribuicoes ? `${atribuicoes}\n` : ""} try {
664
+ (void)executar_${identificadorCpp(task.nome)}(entrada);
665
+ } catch (const std::exception&) {
666
+ return;
667
+ }
668
+ throw std::runtime_error(${literalStringCpp(`Caso ${caso.nome} esperava sucesso falso`)});
669
+ }`,
670
+ };
671
+ }
672
+ return {
673
+ nome,
674
+ rotulo: caso.nome,
675
+ conteudo: `// SEMA-TEST: ${comentarioCpp(task.nome)} :: ${comentarioCpp(caso.nome)}
676
+ void ${nome}() {
677
+ ${entrada} entrada{};
678
+ ${atribuicoes ? `${atribuicoes}\n` : ""} const auto resultado = executar_${identificadorCpp(task.nome)}(entrada);
679
+ (void)resultado;
680
+ ${assercoes || ` assert_sema(true, ${literalStringCpp(`Caso ${caso.nome} executado`)});`}
681
+ }`,
682
+ };
683
+ }
684
+ function gerarCabecalhoSemaCpp(modulo, tipo) {
685
+ const descricoes = {
686
+ cabecalho: "tipos, entidades, enums e contratos de tasks C++ derivados do IR Sema.",
687
+ implementacao: "implementação C++ das regras, garantias e tasks declaradas no contrato Sema.",
688
+ teste: "runner C++ autocontido gerado a partir dos casos de teste do contrato Sema.",
689
+ cmake: "build CMake autocontido do módulo e de seu runner de testes C++.",
690
+ };
691
+ const prefixo = tipo === "cmake" ? "#" : "//";
692
+ return [
693
+ `${prefixo} SEMA-GOVERNED`,
694
+ `${prefixo} Módulo de origem: ${modulo.nome}`,
695
+ `${prefixo} Consulte o contrato .sema aplicável antes de editar este arquivo.`,
696
+ `${prefixo} Rastreabilidade: outros contratos .sema podem governar este mesmo arquivo via vínculos.`,
697
+ `${prefixo} Para IA fraca/média/forte: chame Sema, rode docs-impacto e drift antes de alterar código.`,
698
+ `${prefixo} Descrição: ${descricoes[tipo]}`,
699
+ "",
700
+ ].join("\n");
701
+ }
702
+ function gerarHeader(modulo) {
703
+ const namespace = nomeNamespace(modulo);
704
+ const enums = modulo.enums.map((item) => gerarEnum(item.nome, item.valores));
705
+ const externos = coletarTiposExternos(modulo).map((item) => `struct ${paraPascalCase(item)} final {
706
+ bool operator==(const ${paraPascalCase(item)}&) const = default;
707
+ };`);
708
+ const modelos = ordenarModelos(modulo).map((item) => `${gerarStruct(item.nome, item.campos, modulo, "modelo")}\n// Origem Sema: ${item.origem} ${comentarioCpp(item.nome)}`);
709
+ const tasks = modulo.tasks.map((task) => gerarDeclaracoesTask(task, modulo));
710
+ const interops = modulo.interoperabilidades.map((item) => `// Interop externo ${item.origem}: ${comentarioCpp(item.caminho)}`);
711
+ const estados = modulo.states.map((item) => `// State${item.nome ? ` ${comentarioCpp(item.nome)}` : ""}: campos=${item.campos.length} invariantes=${item.invariantes.length} transições=${item.transicoes.length}`);
712
+ const flows = modulo.flows.map((item) => `// Flow ${comentarioCpp(item.nome)}: etapas=${item.etapasEstruturadas.length} tasks=${comentarioCpp(item.tasksReferenciadas.join(", ") || "nenhuma")}`);
713
+ const routes = modulo.routes.map((item) => `// Route ${comentarioCpp(item.nome)}: método=${item.metodo ?? "não definido"} caminho=${comentarioCpp(item.caminho ?? "não definido")} task=${comentarioCpp(item.task ?? "não definida")}`);
714
+ const secoes = [...interops, ...enums, ...externos, ...modelos, ...tasks, ...estados, ...flows, ...routes].filter(Boolean).join("\n\n");
715
+ return `${gerarCabecalhoSemaCpp(modulo, "cabecalho")}#pragma once
716
+
717
+ #include <cmath>
718
+ #include <cstdint>
719
+ #include <map>
720
+ #include <optional>
721
+ #include <stdexcept>
722
+ #include <string>
723
+ #include <string_view>
724
+ #include <variant>
725
+ #include <vector>
726
+
727
+ namespace ${namespace} {
728
+
729
+ using JsonValue = std::string;
730
+
731
+ struct CampoContrato final {
732
+ std::string_view nome;
733
+ std::string_view tipo;
734
+ bool obrigatorio;
735
+ };
736
+
737
+ struct TaskContract final {
738
+ std::string_view nome;
739
+ std::vector<CampoContrato> input;
740
+ std::vector<CampoContrato> output;
741
+ std::vector<std::string_view> regras;
742
+ std::vector<std::string_view> garantias;
743
+ std::vector<std::string_view> efeitos;
744
+ };
745
+
746
+ struct ExecutionContext final {
747
+ std::string erro_esperado{};
748
+ };
749
+
750
+ ${secoes}
751
+
752
+ } // namespace ${namespace}
753
+ `;
754
+ }
755
+ function gerarSource(modulo, arquivoHeader) {
756
+ const namespace = nomeNamespace(modulo);
757
+ const implementacoes = modulo.tasks.map((task) => gerarImplementacaoTask(task, modulo)).join("\n\n");
758
+ return `${gerarCabecalhoSemaCpp(modulo, "implementacao")}#include ${literalStringCpp(path.posix.basename(arquivoHeader))}
759
+
760
+ namespace ${namespace} {
761
+
762
+ ${implementacoes || "// Nenhuma task declarada no módulo."}
763
+
764
+ } // namespace ${namespace}
765
+ `;
766
+ }
767
+ function gerarTestes(modulo, arquivoHeader) {
768
+ const namespace = nomeNamespace(modulo);
769
+ const testes = modulo.tasks.flatMap((task) => task.tests.map((_, indice) => ({ task, indice })));
770
+ const funcoesDeclaradas = testes.map(({ task, indice }) => gerarFuncaoTeste(task, indice, modulo));
771
+ const funcoes = funcoesDeclaradas.length > 0 ? funcoesDeclaradas : [{
772
+ nome: "test_smoke_modulo",
773
+ rotulo: "smoke do módulo sem casos declarados",
774
+ conteudo: `// SEMA-TEST: smoke :: módulo sem casos declarados
775
+ void test_smoke_modulo() {
776
+ assert_sema(true, "Runner C++ autocontido disponível");
777
+ }`,
778
+ }];
779
+ const registros = funcoes.map((item) => ` {${literalStringCpp(item.rotulo)}, &${item.nome}}`).join(",\n");
780
+ return `${gerarCabecalhoSemaCpp(modulo, "teste")}#include ${literalStringCpp(path.posix.basename(arquivoHeader))}
781
+
782
+ #include <iostream>
783
+ #include <stdexcept>
784
+ #include <string_view>
785
+ #include <utility>
786
+ #include <vector>
787
+
788
+ using namespace ${namespace};
789
+
790
+ namespace {
791
+
792
+ void assert_sema(bool condicao, std::string_view mensagem) {
793
+ if (!condicao) throw std::runtime_error(std::string{mensagem});
794
+ }
795
+
796
+ ${funcoes.map((item) => item.conteudo).join("\n\n")}
797
+
798
+ } // namespace
799
+
800
+ int main() {
801
+ const std::vector<std::pair<std::string_view, void (*)()>> testes{
802
+ ${registros}
803
+ };
804
+ for (const auto& [nome, executar] : testes) {
805
+ std::cout << "test " << nome << '\\n';
806
+ executar();
807
+ }
808
+ std::cout << "ok " << testes.size() << " testes\\n";
809
+ return 0;
810
+ }
811
+ `;
812
+ }
813
+ function gerarCmake(modulo, arquivoSource, arquivoTeste) {
814
+ const nomeProjeto = `sema_${identificadorCpp(normalizarNomeModulo(modulo.nome).replace(/\./g, "_").toLowerCase())}`;
815
+ const alvoBiblioteca = `${nomeProjeto}_lib`;
816
+ const alvoTeste = `test_${nomeProjeto}`;
817
+ return `${gerarCabecalhoSemaCpp(modulo, "cmake")}cmake_minimum_required(VERSION 3.16)
818
+ project(${nomeProjeto} LANGUAGES CXX)
819
+
820
+ set(CMAKE_CXX_STANDARD 20)
821
+ set(CMAKE_CXX_STANDARD_REQUIRED ON)
822
+ set(CMAKE_CXX_EXTENSIONS OFF)
823
+
824
+ add_library(${alvoBiblioteca} STATIC ${path.posix.basename(arquivoSource)})
825
+ target_include_directories(${alvoBiblioteca} PUBLIC "\${CMAKE_CURRENT_SOURCE_DIR}")
826
+ target_compile_features(${alvoBiblioteca} PUBLIC cxx_std_20)
827
+
828
+ add_executable(${alvoTeste} ${path.posix.basename(arquivoTeste)})
829
+ target_link_libraries(${alvoTeste} PRIVATE ${alvoBiblioteca})
830
+
831
+ if(MSVC)
832
+ target_compile_options(${alvoBiblioteca} PRIVATE /W4 /permissive-)
833
+ target_compile_options(${alvoTeste} PRIVATE /W4 /permissive-)
834
+ else()
835
+ target_compile_options(${alvoBiblioteca} PRIVATE -Wall -Wextra -Wpedantic)
836
+ target_compile_options(${alvoTeste} PRIVATE -Wall -Wextra -Wpedantic)
837
+ endif()
838
+
839
+ include(CTest)
840
+ if(BUILD_TESTING)
841
+ add_test(NAME ${alvoTeste} COMMAND ${alvoTeste})
842
+ endif()
843
+ `;
844
+ }
845
+ export function gerarCpp(modulo) {
846
+ const estrutura = descreverEstruturaModulo(modulo.nome);
847
+ const nomeBase = estrutura.nomeArquivo || normalizarNomeModulo(modulo.nome).replace(/\./g, "_");
848
+ const arquivoHeader = `${nomeBase}.hpp`;
849
+ const arquivoSource = `${nomeBase}.cpp`;
850
+ const arquivoTeste = `test_${nomeBase}.cpp`;
851
+ const arquivoCmake = "CMakeLists.txt";
852
+ return [
853
+ { caminhoRelativo: arquivoHeader, conteudo: gerarHeader(modulo) },
854
+ { caminhoRelativo: arquivoSource, conteudo: gerarSource(modulo, arquivoHeader) },
855
+ { caminhoRelativo: arquivoTeste, conteudo: gerarTestes(modulo, arquivoHeader) },
856
+ { caminhoRelativo: arquivoCmake, conteudo: gerarCmake(modulo, arquivoSource, arquivoTeste) },
857
+ ];
858
+ }
859
+ //# sourceMappingURL=index.js.map