@semacode/cli 3.13.1 → 4.1.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.
- package/dist/cliGrammar.js +16 -5
- package/dist/cliHelpTexto.js +4 -3
- package/dist/contextPack.d.ts +75 -0
- package/dist/contextPack.js +133 -0
- package/dist/driftPack.d.ts +65 -0
- package/dist/driftPack.js +96 -0
- package/dist/entrypointPack.d.ts +47 -0
- package/dist/entrypointPack.js +79 -0
- package/dist/index.part05.js +7 -1
- package/dist/index.part06.js +48 -17
- package/dist/index.part07.d.ts +1 -1
- package/dist/index.part07.js +16 -2
- package/dist/index.part08.js +1 -1
- package/dist/indexPack.d.ts +54 -0
- package/dist/indexPack.js +146 -0
- package/dist/init/templates.part01.js +393 -393
- package/dist/init/templates.part02.js +189 -189
- package/dist/initTemplatesBackend.js +73 -73
- package/dist/initTemplatesFlutter.js +137 -137
- package/dist/initTemplatesRuntime.js +350 -350
- package/dist/initTemplatesWeb.js +309 -309
- package/dist/sync/index.js +35 -35
- package/docs/auth.md +26 -26
- package/docs/database.md +15 -15
- package/docs/env.md +16 -16
- package/docs/frontend.md +41 -41
- package/docs/i18n.md +15 -15
- package/exemplos/agendamento.sema +1 -1
- package/exemplos/assinatura.sema +1 -1
- package/exemplos/auditoria.sema +1 -1
- package/exemplos/autenticacao.sema +1 -1
- package/exemplos/author_obra_comum.sema +1 -1
- package/exemplos/author_tema_sensivel.sema +1 -1
- package/exemplos/automacao.sema +1 -1
- package/exemplos/cadastro_usuario.sema +1 -1
- package/exemplos/calculadora.sema +1 -1
- package/exemplos/crud_simples.sema +1 -1
- package/exemplos/estoque.sema +1 -1
- package/exemplos/exportacao.sema +1 -1
- package/exemplos/fila.sema +1 -1
- package/exemplos/integracao_externa.sema +1 -1
- package/exemplos/multi_tenant.sema +1 -1
- package/exemplos/notificacao.sema +1 -1
- package/exemplos/operacao_estrategia.sema +132 -132
- package/exemplos/operacao_estrategia_discovery.sema +220 -220
- package/exemplos/operacao_estrategia_fluxo.sema +114 -114
- package/exemplos/operacao_estrategia_gates.sema +106 -106
- package/exemplos/operacao_estrategia_quarentena.sema +133 -133
- package/exemplos/operacao_estrategia_rollout.sema +124 -124
- package/exemplos/pagamento.sema +1 -1
- package/exemplos/pagamento_dominio.sema +1 -1
- package/exemplos/pedido.sema +1 -1
- package/exemplos/permissao.sema +1 -1
- package/exemplos/persistencia_vendor_first.sema +1 -1
- package/exemplos/php_crud.sema +170 -170
- package/exemplos/profile_conversas.sema +165 -165
- package/exemplos/profile_game.sema +1 -1
- package/exemplos/profile_legal.sema +1 -1
- package/exemplos/profile_ops.sema +1 -1
- package/exemplos/profile_research.sema +1 -1
- package/exemplos/profile_software.sema +1 -1
- package/exemplos/profile_workflow_n8n.sema +1 -1
- package/exemplos/relatorio.sema +1 -1
- package/exemplos/replica_analitica_erp.sema +1 -1
- package/exemplos/testes_embutidos.sema +1 -1
- package/exemplos/tratamento_erro.sema +1 -1
- package/exemplos/upload_arquivo.sema +1 -1
- package/exemplos/webhook.sema +1 -1
- package/node_modules/@sema/gerador-cpp/dist/index.js +176 -176
- package/node_modules/@sema/gerador-css/dist/index.part01.js +10 -10
- package/node_modules/@sema/gerador-dotnet/dist/index.js +169 -169
- package/node_modules/@sema/gerador-html/dist/index.js +17 -17
- package/node_modules/@sema/gerador-python/dist/index.part02.js +3 -3
- package/node_modules/@sema/gerador-typescript/dist/index.part02.js +11 -11
- package/node_modules/@sema/nucleo/dist/diagnosticos/melhorador.js +42 -42
- package/package.json +1 -1
|
@@ -509,54 +509,54 @@ function gerarTask(task, contexto) {
|
|
|
509
509
|
const erros = Object.entries(task.errors)
|
|
510
510
|
.map(([codigo, mensagem]) => ` [${literalString(codigo)}] = ${literalString(mensagem)},`)
|
|
511
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
|
-
}
|
|
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
560
|
}`;
|
|
561
561
|
}
|
|
562
562
|
function removerAspas(valor) {
|
|
@@ -636,27 +636,27 @@ function gerarMetodoTeste(task, caso, indice, contexto) {
|
|
|
636
636
|
.join(", ");
|
|
637
637
|
const assercoesEsperadas = gerarAssercoesEsperadas(task, caso, contexto);
|
|
638
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.
|
|
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
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);
|
|
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
651
|
${assercoesEsperadas || " // O caso não declarou campos de saída verificáveis."}`;
|
|
652
652
|
return {
|
|
653
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}
|
|
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
660
|
}`,
|
|
661
661
|
};
|
|
662
662
|
}
|
|
@@ -671,30 +671,30 @@ function gerarCodigoFonte(modulo, contexto) {
|
|
|
671
671
|
const flows = modulo.flows.map((item) => `// SEMA-FLOW: ${escaparComentario(item.nome)} tasks=${escaparComentario(item.tasksReferenciadas.join(", ") || "nenhuma")}`).join("\n");
|
|
672
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
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}` : ""}
|
|
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
698
|
`;
|
|
699
699
|
}
|
|
700
700
|
function gerarCodigoTestes(modulo, contexto) {
|
|
@@ -703,96 +703,96 @@ function gerarCodigoTestes(modulo, contexto) {
|
|
|
703
703
|
if (metodos.length === 0) {
|
|
704
704
|
metodos.push({
|
|
705
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.");
|
|
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
710
|
}`,
|
|
711
711
|
});
|
|
712
712
|
}
|
|
713
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
|
-
}
|
|
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
758
|
`;
|
|
759
759
|
}
|
|
760
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>
|
|
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
776
|
`;
|
|
777
777
|
}
|
|
778
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>
|
|
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
796
|
`;
|
|
797
797
|
}
|
|
798
798
|
export function gerarDotNet(modulo) {
|
|
@@ -112,7 +112,7 @@ ${etapas || ' <li>Nenhuma etapa estruturada.</li>'}
|
|
|
112
112
|
</section>`;
|
|
113
113
|
}
|
|
114
114
|
function gerarRoute(route) {
|
|
115
|
-
return ` <section class="sema-route" data-route="${route.nome}">
|
|
115
|
+
return ` <section class="sema-route" data-route="${route.nome}">
|
|
116
116
|
<h3>Route: ${route.nome}</h3>
|
|
117
117
|
<div class="sema-route-detalhe">
|
|
118
118
|
<span class="sema-route-metodo">${route.metodo ?? "POST"}</span>
|
|
@@ -124,13 +124,13 @@ function gerarRoute(route) {
|
|
|
124
124
|
</section>`;
|
|
125
125
|
}
|
|
126
126
|
function gerarCabecalhoSemaHtml(modulo) {
|
|
127
|
-
return `<!--
|
|
128
|
-
SEMA-GOVERNED
|
|
129
|
-
Módulo de origem: ${escaparHtml(modulo.nome)}
|
|
130
|
-
Consulte o contrato .sema aplicável antes de editar este arquivo.
|
|
131
|
-
Rastreabilidade: outros contratos .sema podem governar este mesmo arquivo via vinculos.
|
|
132
|
-
Para IA fraca/média/forte: chame Sema, rode docs-impacto e drift antes de alterar código.
|
|
133
|
-
Descrição: página HTML gerada para humanos e IAs entenderem rapidamente a intenção do contrato.
|
|
127
|
+
return `<!--
|
|
128
|
+
SEMA-GOVERNED
|
|
129
|
+
Módulo de origem: ${escaparHtml(modulo.nome)}
|
|
130
|
+
Consulte o contrato .sema aplicável antes de editar este arquivo.
|
|
131
|
+
Rastreabilidade: outros contratos .sema podem governar este mesmo arquivo via vinculos.
|
|
132
|
+
Para IA fraca/média/forte: chame Sema, rode docs-impacto e drift antes de alterar código.
|
|
133
|
+
Descrição: página HTML gerada para humanos e IAs entenderem rapidamente a intenção do contrato.
|
|
134
134
|
-->`;
|
|
135
135
|
}
|
|
136
136
|
export function gerarHtml(modulo) {
|
|
@@ -142,15 +142,15 @@ export function gerarHtml(modulo) {
|
|
|
142
142
|
const tasks = modulo.tasks.map(gerarFormularioTask).join("\n\n");
|
|
143
143
|
const flows = modulo.flows.map(gerarFlow).join("\n\n");
|
|
144
144
|
const routes = modulo.routes.map(gerarRoute).join("\n\n");
|
|
145
|
-
const html = `<!DOCTYPE html>
|
|
146
|
-
${gerarCabecalhoSemaHtml(modulo)}
|
|
147
|
-
<html lang="pt-BR">
|
|
148
|
-
<head>
|
|
149
|
-
<meta charset="UTF-8">
|
|
150
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
151
|
-
<meta name="description" content="Contrato Sema: ${escaparHtml(modulo.nome)}">
|
|
152
|
-
<meta name="sema-governed" content="true">
|
|
153
|
-
<meta name="sema-module" content="${escaparHtml(modulo.nome)}">
|
|
145
|
+
const html = `<!DOCTYPE html>
|
|
146
|
+
${gerarCabecalhoSemaHtml(modulo)}
|
|
147
|
+
<html lang="pt-BR">
|
|
148
|
+
<head>
|
|
149
|
+
<meta charset="UTF-8">
|
|
150
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
151
|
+
<meta name="description" content="Contrato Sema: ${escaparHtml(modulo.nome)}">
|
|
152
|
+
<meta name="sema-governed" content="true">
|
|
153
|
+
<meta name="sema-module" content="${escaparHtml(modulo.nome)}">
|
|
154
154
|
<title>${escaparHtml(titulo)} — Sema</title>
|
|
155
155
|
<link rel="stylesheet" href="${nomeBase}.css">
|
|
156
156
|
</head>
|
|
@@ -333,9 +333,9 @@ def ${normalizarNomeParaSimbolo(route.nome)}(entrada: ${schemaEntrada}):
|
|
|
333
333
|
return `${gerarCabecalhoSemaPython(modulo, "router")}${imports.join("\n")}${rotas}\n`;
|
|
334
334
|
}
|
|
335
335
|
export function gerarFastApiTests(modulo, caminhoRouter) {
|
|
336
|
-
return `${gerarCabecalhoSemaPython(modulo, "teste")}from fastapi.testclient import TestClient
|
|
337
|
-
from ${caminhoRouter} import router
|
|
338
|
-
from fastapi import FastAPI
|
|
336
|
+
return `${gerarCabecalhoSemaPython(modulo, "teste")}from fastapi.testclient import TestClient
|
|
337
|
+
from ${caminhoRouter} import router
|
|
338
|
+
from fastapi import FastAPI
|
|
339
339
|
|
|
340
340
|
app = FastAPI()
|
|
341
341
|
app.include_router(router)
|
|
@@ -321,10 +321,10 @@ ${task.implementacoesExternas.length > 0 ? task.implementacoesExternas.map((impl
|
|
|
321
321
|
.map((route) => ` async ${normalizarNomeParaSimbolo(route.nome)}(entrada: ${route.nome}EntradaPublica): Promise<${route.nome}RespostaPublica> {
|
|
322
322
|
return adaptar_${normalizarNomeParaSimbolo(route.nome)}(entrada);
|
|
323
323
|
}`).join("\n\n");
|
|
324
|
-
return `${gerarCabecalhoSemaTypeScript(modulo, "service")}${imports.join("\n")}
|
|
325
|
-
|
|
326
|
-
@Injectable()
|
|
327
|
-
export class ${nomeClasse} {
|
|
324
|
+
return `${gerarCabecalhoSemaTypeScript(modulo, "service")}${imports.join("\n")}
|
|
325
|
+
|
|
326
|
+
@Injectable()
|
|
327
|
+
export class ${nomeClasse} {
|
|
328
328
|
${metodosTask}${metodosTask && metodosRota ? "\n\n" : ""}${metodosRota}
|
|
329
329
|
}
|
|
330
330
|
`;
|
|
@@ -373,10 +373,10 @@ export function gerarNestJsController(modulo, caminhoDto, caminhoService) {
|
|
|
373
373
|
const contratosImportados = [...new Set(modulo.routes
|
|
374
374
|
.filter((route) => route.task)
|
|
375
375
|
.map((route) => `type ${route.nome}RespostaPublica`))];
|
|
376
|
-
return `${gerarCabecalhoSemaTypeScript(modulo, "controller")}import { ${[...decoratorsImport].join(", ")} } from "@nestjs/common";
|
|
377
|
-
import { ${nomeService} } from "${caminhoService}";
|
|
378
|
-
${dtosImportados.length > 0 ? `import { ${dtosImportados.join(", ")} } from "${caminhoDto}";` : ""}
|
|
379
|
-
${contratosImportados.length > 0 ? `import { ${contratosImportados.join(", ")} } from "./${descreverEstruturaModulo(modulo.nome).nomeArquivo}.contract";` : ""}
|
|
376
|
+
return `${gerarCabecalhoSemaTypeScript(modulo, "controller")}import { ${[...decoratorsImport].join(", ")} } from "@nestjs/common";
|
|
377
|
+
import { ${nomeService} } from "${caminhoService}";
|
|
378
|
+
${dtosImportados.length > 0 ? `import { ${dtosImportados.join(", ")} } from "${caminhoDto}";` : ""}
|
|
379
|
+
${contratosImportados.length > 0 ? `import { ${contratosImportados.join(", ")} } from "./${descreverEstruturaModulo(modulo.nome).nomeArquivo}.contract";` : ""}
|
|
380
380
|
|
|
381
381
|
@Controller()
|
|
382
382
|
export class ${nomeClasse} {
|
|
@@ -390,9 +390,9 @@ export function gerarNestJsSpec(modulo, caminhoService, caminhoController) {
|
|
|
390
390
|
const nomeArquivo = descreverEstruturaModulo(modulo.nome).nomeArquivo;
|
|
391
391
|
const nomeService = `${paraPascalCase(nomeArquivo)}Service`;
|
|
392
392
|
const nomeController = `${paraPascalCase(nomeArquivo)}Controller`;
|
|
393
|
-
return `${gerarCabecalhoSemaTypeScript(modulo, "spec")}import { describe, it } from "@jest/globals";
|
|
394
|
-
import { ${nomeService} } from "${caminhoService}";
|
|
395
|
-
import { ${nomeController} } from "${caminhoController}";
|
|
393
|
+
return `${gerarCabecalhoSemaTypeScript(modulo, "spec")}import { describe, it } from "@jest/globals";
|
|
394
|
+
import { ${nomeService} } from "${caminhoService}";
|
|
395
|
+
import { ${nomeController} } from "${caminhoController}";
|
|
396
396
|
|
|
397
397
|
describe("${nomeController}", () => {
|
|
398
398
|
it("mantem o scaffold inicial em pe", () => {
|
|
@@ -3,43 +3,43 @@
|
|
|
3
3
|
// Melhoria de mensagens de erro SEM0xx
|
|
4
4
|
// Contrato: cli_melhoria_erros.sema
|
|
5
5
|
const SNIPPETS_CORRECAO = {
|
|
6
|
-
SEM094: (nome) => ` auth {
|
|
7
|
-
modo: obrigatorio // ou: anonimo, opcional
|
|
6
|
+
SEM094: (nome) => ` auth {
|
|
7
|
+
modo: obrigatorio // ou: anonimo, opcional
|
|
8
8
|
}`,
|
|
9
|
-
SEM095: (nome) => ` authz {
|
|
10
|
-
escopo: ${nome.toLowerCase().replace(/_/g, '.')}.executar
|
|
11
|
-
papeis: [admin, editor] // ajuste conforme necessario
|
|
9
|
+
SEM095: (nome) => ` authz {
|
|
10
|
+
escopo: ${nome.toLowerCase().replace(/_/g, '.')}.executar
|
|
11
|
+
papeis: [admin, editor] // ajuste conforme necessario
|
|
12
12
|
}`,
|
|
13
|
-
SEM096: (nome) => ` dados {
|
|
14
|
-
classificacao_padrao: interno // ou: publico, pii, financeiro, segredo
|
|
15
|
-
input {
|
|
16
|
-
campo1: interno
|
|
17
|
-
campo2: publico
|
|
18
|
-
}
|
|
19
|
-
output {
|
|
20
|
-
resultado: publico
|
|
21
|
-
}
|
|
13
|
+
SEM096: (nome) => ` dados {
|
|
14
|
+
classificacao_padrao: interno // ou: publico, pii, financeiro, segredo
|
|
15
|
+
input {
|
|
16
|
+
campo1: interno
|
|
17
|
+
campo2: publico
|
|
18
|
+
}
|
|
19
|
+
output {
|
|
20
|
+
resultado: publico
|
|
21
|
+
}
|
|
22
22
|
}`,
|
|
23
|
-
SEM097: (nome) => ` audit {
|
|
24
|
-
evento: ${nome.toLowerCase().replace(/_/g, '.')}.executado
|
|
25
|
-
ator: auth.usuario
|
|
26
|
-
correlacao: request_id
|
|
27
|
-
retencao: "90d"
|
|
28
|
-
motivo: obrigatorio
|
|
23
|
+
SEM097: (nome) => ` audit {
|
|
24
|
+
evento: ${nome.toLowerCase().replace(/_/g, '.')}.executado
|
|
25
|
+
ator: auth.usuario
|
|
26
|
+
correlacao: request_id
|
|
27
|
+
retencao: "90d"
|
|
28
|
+
motivo: obrigatorio
|
|
29
29
|
}`,
|
|
30
|
-
SEM071: (nome) => ` execucao {
|
|
31
|
-
idempotencia: verdadeiro // ou: falso
|
|
32
|
-
timeout: "30s" // ajuste conforme necessidade
|
|
33
|
-
retry: "ate 3 tentativas com backoff"
|
|
34
|
-
compensacao: "descricao do rollback"
|
|
35
|
-
criticidade_operacional: alta // ou: media, baixa
|
|
30
|
+
SEM071: (nome) => ` execucao {
|
|
31
|
+
idempotencia: verdadeiro // ou: falso
|
|
32
|
+
timeout: "30s" // ajuste conforme necessidade
|
|
33
|
+
retry: "ate 3 tentativas com backoff"
|
|
34
|
+
compensacao: "descricao do rollback"
|
|
35
|
+
criticidade_operacional: alta // ou: media, baixa
|
|
36
36
|
}`,
|
|
37
|
-
SEM072: (nome) => ` impl {
|
|
38
|
-
ts: pacote.src.modulo.${nome} // ajuste o caminho
|
|
39
|
-
}
|
|
40
|
-
vinculos {
|
|
41
|
-
arquivo: "src/modulo/arquivo.ts"
|
|
42
|
-
simbolo: pacote.src.modulo.${nome}
|
|
37
|
+
SEM072: (nome) => ` impl {
|
|
38
|
+
ts: pacote.src.modulo.${nome} // ajuste o caminho
|
|
39
|
+
}
|
|
40
|
+
vinculos {
|
|
41
|
+
arquivo: "src/modulo/arquivo.ts"
|
|
42
|
+
simbolo: pacote.src.modulo.${nome}
|
|
43
43
|
}`
|
|
44
44
|
};
|
|
45
45
|
const EXPLICACOES = {
|
|
@@ -84,16 +84,16 @@ export function melhorarMensagemErro(erroOriginal, nomeElemento, tipoElemento) {
|
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
export function formatarErroMelhorado(erro, mensagemMelhorada) {
|
|
87
|
-
return `
|
|
88
|
-
❌ ${erro.codigo}: ${mensagemMelhorada.mensagemMelhorada}
|
|
89
|
-
|
|
90
|
-
📝 Snippet de correcao:
|
|
91
|
-
${mensagemMelhorada.snippetCorrecao}
|
|
92
|
-
|
|
93
|
-
💡 ${mensagemMelhorada.explicacao}
|
|
94
|
-
|
|
95
|
-
📖 Documentacao: ${mensagemMelhorada.documentacaoLink}
|
|
96
|
-
📍 ${erro.localizacao?.arquivo ?? erro.arquivo}:${erro.localizacao?.linha ?? erro.linha}:${erro.localizacao?.coluna ?? erro.coluna}
|
|
87
|
+
return `
|
|
88
|
+
❌ ${erro.codigo}: ${mensagemMelhorada.mensagemMelhorada}
|
|
89
|
+
|
|
90
|
+
📝 Snippet de correcao:
|
|
91
|
+
${mensagemMelhorada.snippetCorrecao}
|
|
92
|
+
|
|
93
|
+
💡 ${mensagemMelhorada.explicacao}
|
|
94
|
+
|
|
95
|
+
📖 Documentacao: ${mensagemMelhorada.documentacaoLink}
|
|
96
|
+
📍 ${erro.localizacao?.arquivo ?? erro.arquivo}:${erro.localizacao?.linha ?? erro.linha}:${erro.localizacao?.coluna ?? erro.coluna}
|
|
97
97
|
`;
|
|
98
98
|
}
|
|
99
99
|
//# sourceMappingURL=melhorador.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@semacode/cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "4.1.0",
|
|
4
4
|
"description": "Local-first semantic governance CLI for AI agents, proven with Claude, Codex, zCode (GLM) and Kimi: contracts, drift, impact, docs gates, and code generation.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"icon": "logo.png",
|