@semacode/cli 3.8.4 → 3.9.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/agentContextPack.js +1 -0
- package/dist/docs.part01.d.ts +4 -0
- package/dist/docs.part02.js +10 -5
- package/dist/drift.part01.d.ts +1 -1
- package/dist/drift.part14.js +8 -0
- package/dist/geracaoCore.d.ts +4 -0
- package/dist/geracaoCore.js +112 -29
- package/exemplos/painel_agro.sema +68 -0
- package/node_modules/@sema/gerador-css/dist/index.part02.js +462 -461
- package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +2 -1
- package/node_modules/@sema/nucleo/dist/ir/conversor.part03.js +17 -0
- package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +14 -0
- package/node_modules/@sema/nucleo/dist/lexer/tokens.js +2 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.modulo.js +9 -0
- package/node_modules/@sema/nucleo/dist/parser/parser.part01.d.ts +1 -1
- package/node_modules/@sema/nucleo/dist/parser/parser.part02.js +2 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.d.ts +8 -0
- package/node_modules/@sema/nucleo/dist/semantico/analisador.part08.js +45 -1
- package/node_modules/@sema/padroes/dist/design.d.ts +54 -0
- package/node_modules/@sema/padroes/dist/design.js +131 -0
- package/node_modules/@sema/padroes/dist/index.d.ts +1 -0
- package/node_modules/@sema/padroes/dist/index.js +1 -0
- package/package.json +1 -1
package/dist/agentContextPack.js
CHANGED
|
@@ -130,6 +130,7 @@ function criarPoliticaDesignVisualAgentContext() {
|
|
|
130
130
|
criteriosMinimos: [
|
|
131
131
|
"não parecer template de 2010",
|
|
132
132
|
"não reciclar a mesma estética para domínios diferentes",
|
|
133
|
+
"declarar bloco design no contrato antes de construir UI",
|
|
133
134
|
"domínio e público moldam layout, linguagem, componentes e interação",
|
|
134
135
|
"hierarquia visual clara",
|
|
135
136
|
"paleta com contraste e identidade do domínio",
|
package/dist/docs.part01.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ export interface DocumentoPlanejado {
|
|
|
5
5
|
tipo: TipoDocumentoMudanca;
|
|
6
6
|
motivo: string;
|
|
7
7
|
permitirCriacao: boolean;
|
|
8
|
+
obrigatoriedade?: "bloqueante" | "recomendada";
|
|
8
9
|
}
|
|
9
10
|
export interface DocumentoObrigatorioMudanca {
|
|
10
11
|
caminho: string;
|
|
@@ -20,6 +21,7 @@ export interface DocumentoObrigatorioMudanca {
|
|
|
20
21
|
template?: string;
|
|
21
22
|
templatePendente?: boolean;
|
|
22
23
|
substancia?: boolean;
|
|
24
|
+
obrigatoriedade: "bloqueante" | "recomendada";
|
|
23
25
|
}
|
|
24
26
|
export interface BloqueioDocumentacaoMudanca {
|
|
25
27
|
tipo: "documentacao_ausente" | "leitura_obrigatoria_nao_comprovada" | "documentacao_template_cru" | "documentacao_sem_substancia" | "arquivo_monolitico" | "codigo_governado_sem_cabecalho";
|
|
@@ -38,6 +40,7 @@ export interface ResultadoDocumentacaoObrigatoria {
|
|
|
38
40
|
leituraObrigatoria: DocumentoObrigatorioMudanca[];
|
|
39
41
|
docsAusentes: DocumentoObrigatorioMudanca[];
|
|
40
42
|
docsCriadas: DocumentoObrigatorioMudanca[];
|
|
43
|
+
leituraRecomendada: DocumentoObrigatorioMudanca[];
|
|
41
44
|
bloqueios: BloqueioDocumentacaoMudanca[];
|
|
42
45
|
instrucoes: string[];
|
|
43
46
|
}
|
|
@@ -45,6 +48,7 @@ export interface ResultadoVerificacaoDocumentacaoMudanca {
|
|
|
45
48
|
sucesso: boolean;
|
|
46
49
|
baseProjeto: string;
|
|
47
50
|
intencao: string;
|
|
51
|
+
leituraRecomendada: DocumentoObrigatorioMudanca[];
|
|
48
52
|
categorias: string[];
|
|
49
53
|
docsLidas: string[];
|
|
50
54
|
leituraObrigatoria: DocumentoObrigatorioMudanca[];
|
package/dist/docs.part02.js
CHANGED
|
@@ -51,7 +51,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
51
51
|
await adicionarDocsRaizExistentes(baseProjeto, registrar);
|
|
52
52
|
for (const regra of REGRAS_DOCUMENTACAO.filter((item) => categorias.includes(item.categoria))) {
|
|
53
53
|
for (const doc of regra.docs) {
|
|
54
|
-
registrar(doc);
|
|
54
|
+
registrar({ ...doc, obrigatoriedade: "recomendada" });
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
await adicionarReadmesDeArquivos(baseProjeto, arquivosAlvo, registrar);
|
|
@@ -87,6 +87,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
87
87
|
criado,
|
|
88
88
|
criacaoAutomatica: doc.permitirCriacao,
|
|
89
89
|
obrigatorio: true,
|
|
90
|
+
obrigatoriedade: doc.obrigatoriedade ?? "bloqueante",
|
|
90
91
|
template: existe ? undefined : template,
|
|
91
92
|
};
|
|
92
93
|
if (existe) {
|
|
@@ -101,7 +102,7 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
101
102
|
}
|
|
102
103
|
const docsAusentes = leituraObrigatoria.filter((doc) => !doc.existe);
|
|
103
104
|
const docsCriadas = leituraObrigatoria.filter((doc) => doc.criado);
|
|
104
|
-
const bloqueios = docsAusentes.map((doc) => ({
|
|
105
|
+
const bloqueios = docsAusentes.filter((doc) => doc.obrigatoriedade !== "recomendada").map((doc) => ({
|
|
105
106
|
tipo: "documentacao_ausente",
|
|
106
107
|
severidade: 4,
|
|
107
108
|
caminho: doc.relativo,
|
|
@@ -118,6 +119,9 @@ export async function resolverDocumentacaoObrigatoria(opcoes) {
|
|
|
118
119
|
leituraObrigatoria,
|
|
119
120
|
docsAusentes,
|
|
120
121
|
docsCriadas,
|
|
122
|
+
leituraRecomendada: leituraObrigatoria
|
|
123
|
+
.filter((doc) => doc.obrigatoriedade === "recomendada")
|
|
124
|
+
.map(compactarDocumentoObrigatorio),
|
|
121
125
|
bloqueios,
|
|
122
126
|
instrucoes: [
|
|
123
127
|
"A IA deve ler todos os itens de leituraObrigatoria antes de executar a mudanca.",
|
|
@@ -149,9 +153,9 @@ export async function verificarDocumentacaoMudanca(opcoes) {
|
|
|
149
153
|
});
|
|
150
154
|
const docsLidas = [...new Set((opcoes.docsLidas ?? []).map((doc) => normalizarDocLida(baseProjeto, doc)).filter(Boolean))];
|
|
151
155
|
const setDocsLidas = new Set(docsLidas);
|
|
152
|
-
const docsNaoLidas = impacto.leituraObrigatoria.filter((doc) => doc.existe && !setDocsLidas.has(doc.relativo));
|
|
153
|
-
const docsTemplatePendentes = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.templatePendente && setDocsLidas.has(doc.relativo)));
|
|
154
|
-
const docsSemSubstancia = impacto.leituraObrigatoria.filter((doc) => (doc.existe && !doc.templatePendente && doc.substancia === false));
|
|
156
|
+
const docsNaoLidas = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && !setDocsLidas.has(doc.relativo)));
|
|
157
|
+
const docsTemplatePendentes = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && doc.templatePendente && setDocsLidas.has(doc.relativo)));
|
|
158
|
+
const docsSemSubstancia = impacto.leituraObrigatoria.filter((doc) => (doc.existe && doc.obrigatoriedade !== "recomendada" && !doc.templatePendente && doc.substancia === false));
|
|
155
159
|
const diagnosticosOrcamento = await emitirDiagnosticosArquivosOrcamento({
|
|
156
160
|
baseProjeto,
|
|
157
161
|
arquivos: opcoes.arquivosAlvo ?? [],
|
|
@@ -201,6 +205,7 @@ export async function verificarDocumentacaoMudanca(opcoes) {
|
|
|
201
205
|
intencao: opcoes.intencao,
|
|
202
206
|
categorias: impacto.categorias,
|
|
203
207
|
docsLidas,
|
|
208
|
+
leituraRecomendada: impacto.leituraRecomendada,
|
|
204
209
|
leituraObrigatoria: impacto.leituraObrigatoria.map(compactarDocumentoObrigatorio),
|
|
205
210
|
docsNaoLidas: docsNaoLidas.map(compactarDocumentoObrigatorio),
|
|
206
211
|
docsAusentes: impacto.docsAusentes.map(compactarDocumentoObrigatorio),
|
package/dist/drift.part01.d.ts
CHANGED
|
@@ -39,7 +39,7 @@ export interface OpcoesDriftLegado {
|
|
|
39
39
|
observador?: ObservadorOperacaoDrift | undefined;
|
|
40
40
|
}
|
|
41
41
|
export interface DiagnosticoDrift {
|
|
42
|
-
tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado" | "seguranca_frouxa" | "pontuacao_semantica_insuficiente" | "contrato_monolitico" | "codigo_monolitico" | "codigo_governado_sem_cabecalho" | "escopo_estreito_sem_vinculos" | "escopo_estreito_ambiguo";
|
|
42
|
+
tipo: "impl_quebrado" | "task_sem_impl" | "rota_divergente" | "recurso_divergente" | "vinculo_quebrado" | "seguranca_frouxa" | "pontuacao_semantica_insuficiente" | "contrato_monolitico" | "codigo_monolitico" | "codigo_governado_sem_cabecalho" | "escopo_estreito_sem_vinculos" | "escopo_estreito_ambiguo" | "design_nao_declarado";
|
|
43
43
|
modulo: string;
|
|
44
44
|
task?: string;
|
|
45
45
|
route?: string;
|
package/dist/drift.part14.js
CHANGED
|
@@ -68,6 +68,14 @@ export function analisarModulosSelecionadosDrift(estado) {
|
|
|
68
68
|
|| task.dados.campos.some((campo) => ["credencial", "segredo"].includes(campo.classificacao))),
|
|
69
69
|
});
|
|
70
70
|
}
|
|
71
|
+
if (ir.routes.length > 0 && !ir.design) {
|
|
72
|
+
diagnosticos.push({
|
|
73
|
+
tipo: "design_nao_declarado",
|
|
74
|
+
modulo: ir.nome,
|
|
75
|
+
severidade: "aviso",
|
|
76
|
+
mensagem: `Modulo "${ir.nome}" expoe rotas de UI sem bloco design; declare identidade e tokens para a interface nao regredir ao padrao.`,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
71
79
|
for (const route of ir.routes) {
|
|
72
80
|
if (!route.task || route.perfilCompatibilidade !== "publico") {
|
|
73
81
|
continue;
|
package/dist/geracaoCore.d.ts
CHANGED
|
@@ -34,6 +34,10 @@ export declare function validarCompatibilidadeFramework(alvo: AlvoGeracao, frame
|
|
|
34
34
|
export declare function normalizarFonteImportacao(valor: string | undefined): FonteImportacao | undefined;
|
|
35
35
|
export declare function normalizarTemplateIniciar(valor?: string): TemplateIniciar;
|
|
36
36
|
export declare function garantirIr(resultado: ReturnType<typeof compilarCodigo>, caminho: string): IrModulo;
|
|
37
|
+
export declare function gerarDesignTokensArquivos(ir: IrModulo, alvo: AlvoGeracao): Array<{
|
|
38
|
+
caminhoRelativo: string;
|
|
39
|
+
conteudo: string;
|
|
40
|
+
}>;
|
|
37
41
|
export declare function gerarArquivosPorAlvo(ir: IrModulo, alvo: AlvoGeracao, framework: FrameworkGeracao): import("@sema/padroes").ArquivoGerado[];
|
|
38
42
|
export declare function aplicarEstruturaSaida(arquivos: Array<{
|
|
39
43
|
caminhoRelativo: string;
|
package/dist/geracaoCore.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { formatarDiagnosticos } from "@sema/nucleo";
|
|
6
|
-
import { descreverEstruturaModulo } from "@sema/padroes";
|
|
6
|
+
import { descreverEstruturaModulo, resolverDesignTokens } from "@sema/padroes";
|
|
7
7
|
import { gerarDart } from "@sema/gerador-dart";
|
|
8
8
|
import { gerarLua } from "@sema/gerador-lua";
|
|
9
9
|
import { gerarPython } from "@sema/gerador-python";
|
|
@@ -135,35 +135,118 @@ export function garantirIr(resultado, caminho) {
|
|
|
135
135
|
}
|
|
136
136
|
return resultado.ir;
|
|
137
137
|
}
|
|
138
|
+
export function gerarDesignTokensArquivos(ir, alvo) {
|
|
139
|
+
if (!ir.design || !["css", "html", "typescript", "javascript"].includes(alvo)) {
|
|
140
|
+
return [];
|
|
141
|
+
}
|
|
142
|
+
const design = resolverDesignTokens(ir.design);
|
|
143
|
+
const cabecalho = `/* SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo. */\n`;
|
|
144
|
+
const css = `${cabecalho}:root {
|
|
145
|
+
--sema-cor-primaria: ${design.cores.primaria};
|
|
146
|
+
--sema-cor-primaria-hover: ${design.cores.primariaHover};
|
|
147
|
+
--sema-cor-primaria-suave: ${design.cores.primariaSuave};
|
|
148
|
+
--sema-cor-fundo: ${design.cores.fundo};
|
|
149
|
+
--sema-cor-superficie: ${design.cores.superficie};
|
|
150
|
+
--sema-cor-texto: ${design.cores.texto};
|
|
151
|
+
--sema-cor-texto-secundario: ${design.cores.textoSecundario};
|
|
152
|
+
--sema-cor-borda: ${design.cores.borda};
|
|
153
|
+
--sema-cor-borda-foco: ${design.cores.bordaFoco};
|
|
154
|
+
--sema-fonte: ${design.tipografia.fonte};
|
|
155
|
+
--sema-fonte-titulo: ${design.tipografia.fonteTitulo};
|
|
156
|
+
--sema-fonte-mono: ${design.tipografia.fonteMono};
|
|
157
|
+
--sema-raio: ${design.forma.raio};
|
|
158
|
+
--sema-movimento-duracao: ${design.movimentoDuracao};
|
|
159
|
+
}
|
|
160
|
+
`;
|
|
161
|
+
const objetoTokens = JSON.stringify({
|
|
162
|
+
colors: design.cores,
|
|
163
|
+
typography: { ...design.tipografia, scale: design.escala },
|
|
164
|
+
shape: design.forma,
|
|
165
|
+
motion: { duration: design.movimentoDuracao },
|
|
166
|
+
domain: ir.design.dominio ?? null,
|
|
167
|
+
identity: ir.design.identidade ?? null,
|
|
168
|
+
}, null, 2);
|
|
169
|
+
const ts = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
|
|
170
|
+
export const designTokens = ${objetoTokens} as const;
|
|
171
|
+
export type DesignTokens = typeof designTokens;
|
|
172
|
+
`;
|
|
173
|
+
const js = `// SEMA-GOVERNED — design tokens de ${ir.nome}; edite o bloco design do contrato, nao este arquivo.
|
|
174
|
+
export const designTokens = ${objetoTokens};
|
|
175
|
+
`;
|
|
176
|
+
const scss = `${cabecalho}$sema-cor-primaria: ${design.cores.primaria};
|
|
177
|
+
$sema-cor-primaria-hover: ${design.cores.primariaHover};
|
|
178
|
+
$sema-cor-fundo: ${design.cores.fundo};
|
|
179
|
+
$sema-cor-superficie: ${design.cores.superficie};
|
|
180
|
+
$sema-cor-texto: ${design.cores.texto};
|
|
181
|
+
$sema-cor-texto-secundario: ${design.cores.textoSecundario};
|
|
182
|
+
$sema-cor-borda: ${design.cores.borda};
|
|
183
|
+
$sema-fonte: ${design.tipografia.fonte};
|
|
184
|
+
$sema-fonte-titulo: ${design.tipografia.fonteTitulo};
|
|
185
|
+
$sema-raio: ${design.forma.raio};
|
|
186
|
+
`;
|
|
187
|
+
const tailwind = `// SEMA-GOVERNED — tema Tailwind derivado do bloco design de ${ir.nome}.
|
|
188
|
+
export const theme = {
|
|
189
|
+
extend: {
|
|
190
|
+
colors: {
|
|
191
|
+
sema: {
|
|
192
|
+
primary: "${design.cores.primaria}",
|
|
193
|
+
"primary-hover": "${design.cores.primariaHover}",
|
|
194
|
+
"primary-soft": "${design.cores.primariaSuave}",
|
|
195
|
+
background: "${design.cores.fundo}",
|
|
196
|
+
surface: "${design.cores.superficie}",
|
|
197
|
+
text: "${design.cores.texto}",
|
|
198
|
+
"text-muted": "${design.cores.textoSecundario}",
|
|
199
|
+
border: "${design.cores.borda}",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
borderRadius: { sema: "${design.forma.raio}" },
|
|
203
|
+
transitionDuration: { sema: "${design.movimentoDuracao}" },
|
|
204
|
+
},
|
|
205
|
+
};
|
|
206
|
+
`;
|
|
207
|
+
const tui = `{\n "comentario": "SEMA-GOVERNED — tema de terminal derivado do bloco design de ${ir.nome}",\n "cores": ${JSON.stringify(design.cores, null, 2)},\n "movimento": "${design.movimentoDuracao}"\n}\n`;
|
|
208
|
+
return [
|
|
209
|
+
{ caminhoRelativo: `design/design-tokens.css`, conteudo: css },
|
|
210
|
+
{ caminhoRelativo: `design/tokens.ts`, conteudo: ts },
|
|
211
|
+
{ caminhoRelativo: `design/tokens.js`, conteudo: js },
|
|
212
|
+
{ caminhoRelativo: `design/_tokens.scss`, conteudo: scss },
|
|
213
|
+
{ caminhoRelativo: `design/tailwind.theme.js`, conteudo: tailwind },
|
|
214
|
+
{ caminhoRelativo: `design/theme-tui.json`, conteudo: tui },
|
|
215
|
+
];
|
|
216
|
+
}
|
|
138
217
|
export function gerarArquivosPorAlvo(ir, alvo, framework) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
218
|
+
const extras = gerarDesignTokensArquivos(ir, alvo);
|
|
219
|
+
const base = (() => {
|
|
220
|
+
if (alvo === "python") {
|
|
221
|
+
return gerarPython(ir, { framework });
|
|
222
|
+
}
|
|
223
|
+
if (alvo === "dart") {
|
|
224
|
+
return gerarDart(ir);
|
|
225
|
+
}
|
|
226
|
+
if (alvo === "lua") {
|
|
227
|
+
return gerarLua(ir);
|
|
228
|
+
}
|
|
229
|
+
if (alvo === "javascript") {
|
|
230
|
+
return gerarJavaScript(ir);
|
|
231
|
+
}
|
|
232
|
+
if (alvo === "html") {
|
|
233
|
+
return gerarHtml(ir);
|
|
234
|
+
}
|
|
235
|
+
if (alvo === "css") {
|
|
236
|
+
return gerarCss(ir);
|
|
237
|
+
}
|
|
238
|
+
if (alvo === "php") {
|
|
239
|
+
return gerarPhp(ir);
|
|
240
|
+
}
|
|
241
|
+
if (alvo === "dotnet") {
|
|
242
|
+
return gerarDotNet(ir);
|
|
243
|
+
}
|
|
244
|
+
if (alvo === "cpp") {
|
|
245
|
+
return gerarCpp(ir);
|
|
246
|
+
}
|
|
247
|
+
return gerarTypeScript(ir, { framework });
|
|
248
|
+
})();
|
|
249
|
+
return extras.length > 0 ? [...base, ...extras] : base;
|
|
167
250
|
}
|
|
168
251
|
export function aplicarEstruturaSaida(arquivos, ir, estrutura) {
|
|
169
252
|
if (estrutura === "flat" || estrutura === "backend") {
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
module exemplos.painel.agro {
|
|
2
|
+
design {
|
|
3
|
+
dominio: agro
|
|
4
|
+
identidade: rustico_moderno
|
|
5
|
+
tokens {
|
|
6
|
+
paleta: terra
|
|
7
|
+
tipografia: display
|
|
8
|
+
densidade: confortavel
|
|
9
|
+
forma: arredondada
|
|
10
|
+
movimento: suave
|
|
11
|
+
cor_primaria: "#7c2d12"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
entity Safra {
|
|
16
|
+
fields {
|
|
17
|
+
id: Id
|
|
18
|
+
cultura: Texto
|
|
19
|
+
hectares: Decimal
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
task registrar_safra {
|
|
24
|
+
input {
|
|
25
|
+
cultura: Texto required
|
|
26
|
+
hectares: Decimal required
|
|
27
|
+
}
|
|
28
|
+
output {
|
|
29
|
+
safra: Safra
|
|
30
|
+
}
|
|
31
|
+
rules {
|
|
32
|
+
hectares deve_ser positivo
|
|
33
|
+
}
|
|
34
|
+
effects {
|
|
35
|
+
persistencia Safra
|
|
36
|
+
auditoria safra_registrada
|
|
37
|
+
}
|
|
38
|
+
guarantees {
|
|
39
|
+
safra existe
|
|
40
|
+
}
|
|
41
|
+
tests {
|
|
42
|
+
caso "registra safra" {
|
|
43
|
+
given {
|
|
44
|
+
cultura: "Cafe"
|
|
45
|
+
hectares: 12.5
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
expect {
|
|
49
|
+
sucesso: verdadeiro
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
route safras_criar {
|
|
56
|
+
metodo: POST
|
|
57
|
+
caminho: /safras
|
|
58
|
+
task: registrar_safra
|
|
59
|
+
finalidade: cadastro_safra
|
|
60
|
+
input {
|
|
61
|
+
cultura: Texto
|
|
62
|
+
hectares: Decimal
|
|
63
|
+
}
|
|
64
|
+
output {
|
|
65
|
+
safra: Safra
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|