@semacode/cli 1.5.53 → 1.5.55

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 (51) hide show
  1. package/README.md +1 -0
  2. package/dist/agentEntryPoints.js +3 -3
  3. package/dist/drift.part01.d.ts +2 -2
  4. package/dist/drift.part03.js +1 -1
  5. package/dist/drift.part04.js +1 -1
  6. package/dist/drift.part07.d.ts +5 -0
  7. package/dist/drift.part07.js +43 -1
  8. package/dist/drift.part08.js +1 -1
  9. package/dist/drift.part09.d.ts +2 -2
  10. package/dist/drift.part09.js +5 -1
  11. package/dist/drift.part12.js +1 -1
  12. package/dist/drift.part13.js +6 -1
  13. package/dist/geracaoCore.js +53 -2
  14. package/dist/iaPrompts.d.ts +1 -1
  15. package/dist/iaPrompts.js +3 -3
  16. package/dist/importador.part01.d.ts +2 -2
  17. package/dist/importador.part05.js +10 -0
  18. package/dist/importador.part08.js +5 -3
  19. package/dist/importador.part09.d.ts +1 -0
  20. package/dist/importador.part09.js +65 -0
  21. package/dist/index.part01.js +4 -4
  22. package/dist/index.part06.js +1 -1
  23. package/dist/index.part08.js +1 -1
  24. package/dist/initTemplatesBase.js +1 -1
  25. package/dist/php-http.d.ts +24 -0
  26. package/dist/php-http.js +252 -0
  27. package/dist/projetoBusca.js +1 -0
  28. package/dist/projetoConfig.js +3 -2
  29. package/dist/projetoLegado.js +11 -0
  30. package/dist/tipos.d.ts +1 -1
  31. package/docs/ai-workflow.md +1 -1
  32. package/docs/commands.md +2 -2
  33. package/docs/syntax.md +3 -2
  34. package/node_modules/@sema/gerador-php/dist/index.d.ts +3 -0
  35. package/node_modules/@sema/gerador-php/dist/index.js +538 -0
  36. package/node_modules/@sema/gerador-php/dist/index.js.map +1 -0
  37. package/node_modules/@sema/gerador-php/package.json +7 -0
  38. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +1 -1
  39. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js +4 -0
  40. package/node_modules/@sema/nucleo/dist/ir/conversor.part01.js.map +1 -1
  41. package/node_modules/@sema/nucleo/dist/ir/conversor.part02.d.ts +1 -1
  42. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +3 -3
  43. package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js +2 -0
  44. package/node_modules/@sema/nucleo/dist/parser/parser.declaracoes.js.map +1 -1
  45. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.d.ts +2 -2
  46. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js +3 -1
  47. package/node_modules/@sema/nucleo/dist/semantico/analisador.part01.js.map +1 -1
  48. package/node_modules/@sema/padroes/dist/index.d.ts +2 -1
  49. package/node_modules/@sema/padroes/dist/index.js +31 -0
  50. package/node_modules/@sema/padroes/dist/index.js.map +1 -1
  51. package/package.json +12 -10
@@ -206,7 +206,7 @@ export async function comandoAjudaIa() {
206
206
  "Use `sema docs-impacto --intencao <acao>` para ler ou criar docs obrigatorias antes de agir.",
207
207
  "Use `sema finalizar-mudanca --intencao <acao>` para bloquear conclusao sem leitura documental comprovada.",
208
208
  "Use `sema contexto-ia <arquivo.sema>` para gerar AST, IR, drift, `briefing.json` e `briefing.min.json`.",
209
- "Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart|lua|javascript|html|css> --saida <diretorio>` quando a tarefa pedir codigo derivado.",
209
+ "Use `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|php|dart|lua|javascript|html|css> --saida <diretorio>` quando a tarefa pedir codigo derivado.",
210
210
  ]));
211
211
  console.log("");
212
212
  console.log(renderizarSecaoAscii("Regras praticas", [
@@ -121,7 +121,7 @@ export async function principal() {
121
121
  {
122
122
  const fonte = normalizarFonteImportacao(posicionais[0]);
123
123
  if (!fonte || !posicionais[1]) {
124
- console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|firebase|dotnet|java|go|rust|cpp|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
124
+ console.error("Uso: sema importar <nestjs|fastapi|flask|nextjs|nextjs-consumer|react-vite-consumer|angular-consumer|flutter-consumer|firebase|dotnet|java|go|rust|cpp|php|typescript|python|dart> <diretorio> [--saida <diretorio>] [--namespace <base>] [--json]");
125
125
  codigoSaida = 1;
126
126
  break;
127
127
  }
@@ -118,7 +118,7 @@ export function arquivosTemplateIniciar(template) {
118
118
  ?? [
119
119
  {
120
120
  caminhoRelativo: "sema.config.json",
121
- conteudo: "{\n \"origens\": [\"./contratos\"],\n \"saida\": \"./generated\",\n \"alvos\": [\"typescript\", \"javascript\", \"python\", \"dart\", \"lua\", \"html\", \"css\"],\n \"alvoPadrao\": \"typescript\",\n \"estruturaSaida\": \"modulos\",\n \"framework\": \"base\",\n \"modoEstrito\": true,\n \"diretoriosSaidaPorAlvo\": {\n \"typescript\": \"./generated/typescript\",\n \"javascript\": \"./generated/javascript\",\n \"python\": \"./generated/python\",\n \"dart\": \"./generated/dart\",\n \"lua\": \"./generated/lua\",\n \"html\": \"./generated/html\",\n \"css\": \"./generated/css\"\n },\n \"convencoesGeracaoPorProjeto\": \"base\"\n}\n",
121
+ conteudo: "{\n \"origens\": [\"./contratos\"],\n \"saida\": \"./generated\",\n \"alvos\": [\"typescript\", \"javascript\", \"python\", \"php\", \"dart\", \"lua\", \"html\", \"css\"],\n \"alvoPadrao\": \"typescript\",\n \"estruturaSaida\": \"modulos\",\n \"framework\": \"base\",\n \"modoEstrito\": true,\n \"diretoriosSaidaPorAlvo\": {\n \"typescript\": \"./generated/typescript\",\n \"javascript\": \"./generated/javascript\",\n \"python\": \"./generated/python\",\n \"php\": \"./generated/php\",\n \"dart\": \"./generated/dart\",\n \"lua\": \"./generated/lua\",\n \"html\": \"./generated/html\",\n \"css\": \"./generated/css\"\n },\n \"convencoesGeracaoPorProjeto\": \"base\"\n}\n",
122
122
  },
123
123
  ...arquivosBase,
124
124
  ];
@@ -0,0 +1,24 @@
1
+ export interface ParametroRotaPhp {
2
+ nome: string;
3
+ tipoSema: "Texto" | "Inteiro" | "Decimal" | "Id";
4
+ }
5
+ export interface SimboloPhpExtraido {
6
+ simbolo: string;
7
+ aliases?: string[];
8
+ retorno?: string;
9
+ parametros: Array<{
10
+ nome: string;
11
+ tipoTexto?: string;
12
+ obrigatorio: boolean;
13
+ }>;
14
+ }
15
+ export interface RotaPhpExtraida {
16
+ origem: "php";
17
+ metodo: string;
18
+ caminho: string;
19
+ simbolo: string;
20
+ parametros: ParametroRotaPhp[];
21
+ retorno?: string;
22
+ }
23
+ export declare function extrairSimbolosPhp(codigo: string): SimboloPhpExtraido[];
24
+ export declare function extrairRotasPhp(codigo: string): RotaPhpExtraida[];
@@ -0,0 +1,252 @@
1
+ // SEMA-GOVERNED: sema.governanca_ia_contexto
2
+ // Descricao: extracao PHP para drift/importacao; consulte contratos/sema/governanca_ia_contexto.sema antes de editar.
3
+ const METODOS_HTTP = new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
4
+ function contarChar(texto, alvo) {
5
+ return [...texto].filter((char) => char === alvo).length;
6
+ }
7
+ function limparStringPhp(valor) {
8
+ const limpo = (valor ?? "").trim();
9
+ if (!limpo) {
10
+ return undefined;
11
+ }
12
+ if ((limpo.startsWith("\"") && limpo.endsWith("\"")) || (limpo.startsWith("'") && limpo.endsWith("'"))) {
13
+ return limpo.slice(1, -1);
14
+ }
15
+ return limpo;
16
+ }
17
+ function normalizarCaminhoPhp(caminho) {
18
+ const limpo = caminho
19
+ .trim()
20
+ .replace(/^\/+|\/+$/g, "")
21
+ .replace(/:([A-Za-z_]\w*)/g, "{$1}")
22
+ .replace(/\{([^}:?]+)\??(?::[^}]+)?\}/g, "{$1}");
23
+ return `/${limpo}`.replace(/\/+/g, "/");
24
+ }
25
+ function juntarCaminhoPhp(base, sufixo) {
26
+ const partes = [base, sufixo]
27
+ .map((parte) => (parte ?? "").trim())
28
+ .filter(Boolean)
29
+ .map((parte) => parte.replace(/^\/+|\/+$/g, ""));
30
+ return normalizarCaminhoPhp(partes.join("/"));
31
+ }
32
+ function mapearTipoPhp(tipo) {
33
+ const normalizado = (tipo ?? "").toLowerCase().replace(/^[?\\]+/, "");
34
+ if (/^(int|integer)$/.test(normalizado)) {
35
+ return "Inteiro";
36
+ }
37
+ if (/^(float|double|decimal)$/.test(normalizado)) {
38
+ return "Decimal";
39
+ }
40
+ if (/uuid|id$/.test(normalizado)) {
41
+ return "Id";
42
+ }
43
+ return "Texto";
44
+ }
45
+ function extrairParametrosPhp(assinatura) {
46
+ return assinatura.split(",").map((parametroBruto) => {
47
+ const parametro = parametroBruto.trim();
48
+ if (!parametro) {
49
+ return undefined;
50
+ }
51
+ const semPadrao = parametro.split("=")[0]?.trim() ?? parametro;
52
+ const nome = semPadrao.match(/\$([A-Za-z_]\w*)/)?.[1];
53
+ if (!nome) {
54
+ return undefined;
55
+ }
56
+ const tipoTexto = semPadrao
57
+ .slice(0, semPadrao.indexOf(`$${nome}`))
58
+ .replace(/\b(?:public|protected|private|readonly|static)\b/g, "")
59
+ .replace(/[&.]{1,3}/g, "")
60
+ .trim() || undefined;
61
+ return {
62
+ nome,
63
+ tipoTexto,
64
+ obrigatorio: !parametro.includes("=") && !tipoTexto?.startsWith("?"),
65
+ };
66
+ }).filter((item) => Boolean(item));
67
+ }
68
+ function extrairParametrosRotaPhp(caminho, assinatura) {
69
+ const assinaturaMap = new Map();
70
+ for (const parametro of extrairParametrosPhp(assinatura)) {
71
+ assinaturaMap.set(parametro.nome, parametro.tipoTexto ?? "");
72
+ }
73
+ return [...normalizarCaminhoPhp(caminho).matchAll(/\{([^}]+)\}/g)].map((match) => {
74
+ const nome = match[1];
75
+ return {
76
+ nome,
77
+ tipoSema: mapearTipoPhp(assinaturaMap.get(nome)),
78
+ };
79
+ });
80
+ }
81
+ function removerComentariosBloco(codigo) {
82
+ return codigo.replace(/\/\*[\s\S]*?\*\//g, "");
83
+ }
84
+ function extrairAtributoRoutePhp(linha) {
85
+ const match = linha.match(/#\[\s*Route\s*\(([\s\S]+)\)\s*\]/i);
86
+ if (!match) {
87
+ return undefined;
88
+ }
89
+ const corpo = match[1];
90
+ const caminho = limparStringPhp(corpo.match(/(?:path\s*:\s*)?(['"][^'"]+['"])/i)?.[1]);
91
+ if (!caminho) {
92
+ return undefined;
93
+ }
94
+ const metodos = [...corpo.matchAll(/['"](GET|POST|PUT|PATCH|DELETE|HEAD|OPTIONS)['"]/gi)]
95
+ .map((item) => item[1].toUpperCase())
96
+ .filter((metodo) => METODOS_HTTP.has(metodo));
97
+ return {
98
+ caminho,
99
+ metodos: metodos.length > 0 ? [...new Set(metodos)] : ["GET"],
100
+ };
101
+ }
102
+ function extrairTargetLaravel(bloco) {
103
+ const arrayController = bloco.match(/([A-Za-z_][\\A-Za-z0-9_]*)::class\s*,\s*['"]([A-Za-z_]\w*)['"]/);
104
+ if (arrayController) {
105
+ const classe = arrayController[1].split("\\").at(-1);
106
+ return `${classe}.${arrayController[2]}`;
107
+ }
108
+ const stringController = bloco.match(/['"]([A-Za-z_][\\A-Za-z0-9_]*)@([A-Za-z_]\w*)['"]/);
109
+ if (stringController) {
110
+ const classe = stringController[1].split("\\").at(-1);
111
+ return `${classe}.${stringController[2]}`;
112
+ }
113
+ const invokable = bloco.match(/([A-Za-z_][\\A-Za-z0-9_]*)::class/);
114
+ if (invokable) {
115
+ const classe = invokable[1].split("\\").at(-1);
116
+ return `${classe}.__invoke`;
117
+ }
118
+ const closure = bloco.match(/function\s*\(/);
119
+ if (closure) {
120
+ return "closure";
121
+ }
122
+ return undefined;
123
+ }
124
+ function assinaturaFuncaoPhp(linha) {
125
+ return linha.match(/^(?:(?:public|protected|private|static|final|abstract|readonly)\s+)*function\s+&?\s*([A-Za-z_]\w*)\s*\(([^)]*)\)\s*(?::\s*([?\\A-Za-z_][\\A-Za-z0-9_|?]*))?/);
126
+ }
127
+ function namespaceParaCaminhoPhp(namespace) {
128
+ const limpo = namespace?.trim().replace(/\\+/g, ".");
129
+ return limpo || undefined;
130
+ }
131
+ function variantesNamespacePhp(namespace, classe, metodo) {
132
+ const base = namespaceParaCaminhoPhp(namespace);
133
+ if (!base) {
134
+ return [];
135
+ }
136
+ const caminho = `${base}.${classe}.${metodo}`;
137
+ const partes = caminho.split(".");
138
+ const primeiroMinusculo = partes.length > 0
139
+ ? [partes[0].toLowerCase(), ...partes.slice(1)].join(".")
140
+ : caminho;
141
+ return [...new Set([caminho, primeiroMinusculo])];
142
+ }
143
+ export function extrairSimbolosPhp(codigo) {
144
+ const simbolos = new Map();
145
+ const linhas = removerComentariosBloco(codigo).split(/\r?\n/);
146
+ const pilhaClasses = [];
147
+ let profundidade = 0;
148
+ let namespaceAtual;
149
+ for (const linhaOriginal of linhas) {
150
+ const linha = linhaOriginal.trim();
151
+ if (!linha || linha.startsWith("//") || linha.startsWith("#")) {
152
+ profundidade += contarChar(linhaOriginal, "{") - contarChar(linhaOriginal, "}");
153
+ continue;
154
+ }
155
+ const namespace = linha.match(/^namespace\s+([^;{]+)\s*[;{]/);
156
+ if (namespace) {
157
+ namespaceAtual = namespace[1].trim();
158
+ }
159
+ const classe = linha.match(/\b(?:class|trait)\s+([A-Za-z_]\w*)/);
160
+ const classeSemChaveNaLinha = Boolean(classe && !linhaOriginal.includes("{"));
161
+ if (classe) {
162
+ pilhaClasses.push({ nome: classe[1], profundidade: profundidade + 1 });
163
+ }
164
+ const funcao = assinaturaFuncaoPhp(linha);
165
+ if (funcao) {
166
+ const nome = funcao[1];
167
+ if (!["__construct", "__destruct"].includes(nome)) {
168
+ const classeAtual = pilhaClasses[pilhaClasses.length - 1];
169
+ const simbolo = classeAtual ? `${classeAtual.nome}.${nome}` : nome;
170
+ simbolos.set(simbolo, {
171
+ simbolo,
172
+ aliases: classeAtual ? variantesNamespacePhp(namespaceAtual, classeAtual.nome, nome) : [],
173
+ retorno: funcao[3]?.trim(),
174
+ parametros: extrairParametrosPhp(funcao[2] ?? ""),
175
+ });
176
+ }
177
+ }
178
+ profundidade += contarChar(linhaOriginal, "{") - contarChar(linhaOriginal, "}");
179
+ while (!classeSemChaveNaLinha && pilhaClasses.length > 0 && profundidade < pilhaClasses[pilhaClasses.length - 1].profundidade) {
180
+ pilhaClasses.pop();
181
+ }
182
+ }
183
+ return [...simbolos.values()];
184
+ }
185
+ export function extrairRotasPhp(codigo) {
186
+ const rotas = new Map();
187
+ const texto = removerComentariosBloco(codigo);
188
+ for (const match of texto.matchAll(/\b(?:Route::|\$?[A-Za-z_]\w*->)(get|post|put|patch|delete|head|options)\s*\(\s*(['"][^'"]+['"])\s*,\s*([\s\S]*?)\)\s*;/gi)) {
189
+ const metodo = match[1].toUpperCase();
190
+ if (!METODOS_HTTP.has(metodo)) {
191
+ continue;
192
+ }
193
+ const caminho = normalizarCaminhoPhp(limparStringPhp(match[2]) ?? "/");
194
+ const simbolo = extrairTargetLaravel(match[3] ?? "") ?? metodo.toLowerCase();
195
+ rotas.set(`${metodo}:${caminho}:${simbolo}`, {
196
+ origem: "php",
197
+ metodo,
198
+ caminho,
199
+ simbolo,
200
+ parametros: extrairParametrosRotaPhp(caminho, ""),
201
+ });
202
+ }
203
+ const linhas = texto.split(/\r?\n/);
204
+ const pilhaClasses = [];
205
+ let atributoPendente;
206
+ let profundidade = 0;
207
+ for (const linhaOriginal of linhas) {
208
+ const linha = linhaOriginal.trim();
209
+ const atributo = extrairAtributoRoutePhp(linha);
210
+ if (atributo) {
211
+ atributoPendente = atributo;
212
+ continue;
213
+ }
214
+ const classe = linha.match(/\b(?:class|trait)\s+([A-Za-z_]\w*)/);
215
+ const classeSemChaveNaLinha = Boolean(classe && !linhaOriginal.includes("{"));
216
+ if (classe) {
217
+ pilhaClasses.push({
218
+ nome: classe[1],
219
+ profundidade: profundidade + 1,
220
+ rotaBase: atributoPendente?.caminho,
221
+ });
222
+ atributoPendente = undefined;
223
+ }
224
+ const funcao = assinaturaFuncaoPhp(linha);
225
+ if (funcao && atributoPendente) {
226
+ const classeAtual = pilhaClasses[pilhaClasses.length - 1];
227
+ const nome = funcao[1];
228
+ const simbolo = classeAtual ? `${classeAtual.nome}.${nome}` : nome;
229
+ const caminho = juntarCaminhoPhp(classeAtual?.rotaBase, atributoPendente.caminho);
230
+ for (const metodo of atributoPendente.metodos) {
231
+ rotas.set(`${metodo}:${caminho}:${simbolo}`, {
232
+ origem: "php",
233
+ metodo,
234
+ caminho,
235
+ simbolo,
236
+ parametros: extrairParametrosRotaPhp(caminho, funcao[2] ?? ""),
237
+ retorno: funcao[3]?.trim(),
238
+ });
239
+ }
240
+ atributoPendente = undefined;
241
+ }
242
+ else if (funcao) {
243
+ atributoPendente = undefined;
244
+ }
245
+ profundidade += contarChar(linhaOriginal, "{") - contarChar(linhaOriginal, "}");
246
+ while (!classeSemChaveNaLinha && pilhaClasses.length > 0 && profundidade < pilhaClasses[pilhaClasses.length - 1].profundidade) {
247
+ pilhaClasses.pop();
248
+ }
249
+ }
250
+ return [...rotas.values()];
251
+ }
252
+ //# sourceMappingURL=php-http.js.map
@@ -54,6 +54,7 @@ export const EXTENSOES_CODIGO = [
54
54
  ".cxx",
55
55
  ".hpp",
56
56
  ".h",
57
+ ".php",
57
58
  ".html",
58
59
  ".htm",
59
60
  ".css",
@@ -52,7 +52,7 @@ export function normalizarFrameworkGeracao(valor) {
52
52
  return "base";
53
53
  }
54
54
  export function normalizarAlvo(valor) {
55
- if (valor === "typescript" || valor === "python" || valor === "dart" || valor === "lua" || valor === "javascript" || valor === "html" || valor === "css") {
55
+ if (valor === "typescript" || valor === "python" || valor === "dart" || valor === "lua" || valor === "javascript" || valor === "html" || valor === "css" || valor === "php") {
56
56
  return valor;
57
57
  }
58
58
  if (valor === "js") {
@@ -85,7 +85,8 @@ export function normalizarFonteLegado(valor) {
85
85
  || valor === "java"
86
86
  || valor === "go"
87
87
  || valor === "rust"
88
- || valor === "cpp") {
88
+ || valor === "cpp"
89
+ || valor === "php") {
89
90
  return valor;
90
91
  }
91
92
  return undefined;
@@ -45,6 +45,8 @@ export async function inferirFontesLegado(diretoriosCodigo, baseProjeto, configC
45
45
  const arquivosRust = await listarArquivosRecursivosLimitado(diretorio, [".rs"], 5, 20);
46
46
  const arquivosCppBrutos = await listarArquivosRecursivosLimitado(diretorio, [".cpp", ".cc", ".cxx", ".hpp", ".h"], 5, 30);
47
47
  const arquivosCpp = arquivosCppBrutos.filter((arquivo) => !/(^|[\\/])(windows|linux|macos|runner|flutter|ephemeral|build|vendor)([\\/]|$)/i.test(arquivo));
48
+ const arquivosPhp = (await listarArquivosRecursivosLimitado(diretorio, [".php"], 5, 30))
49
+ .filter((arquivo) => !/(^|[\\/])(vendor|storage|bootstrap[\\/]cache|cache|tests?)([\\/]|$)/i.test(arquivo));
48
50
  if (arquivosTs.length > 0) {
49
51
  encontrados.add("typescript");
50
52
  }
@@ -176,6 +178,15 @@ export async function inferirFontesLegado(diretoriosCodigo, baseProjeto, configC
176
178
  if (arquivosCpp.length > 0) {
177
179
  encontrados.add("cpp");
178
180
  }
181
+ if (arquivosPhp.length > 0) {
182
+ encontrados.add("php");
183
+ const composer = await procurarArquivosPorNome(diretorio, ["composer.json"], 4);
184
+ const amostrasPhp = await Promise.all(arquivosPhp.slice(0, 8).map((arquivo) => lerConteudoSeExistir(arquivo)));
185
+ if (composer.length > 0
186
+ || amostrasPhp.some((texto) => /Route::(?:get|post|put|patch|delete)|#\[\s*Route\s*\(|namespace\s+App\\|use\s+Illuminate\\|use\s+Symfony\\/i.test(texto ?? ""))) {
187
+ encontrados.add("php");
188
+ }
189
+ }
179
190
  }
180
191
  return [...encontrados].sort((a, b) => a.localeCompare(b, "pt-BR"));
181
192
  }
package/dist/tipos.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export type EstruturaSaida = "flat" | "modulos" | "backend";
2
- export type FonteLegado = "nestjs" | "fastapi" | "flask" | "nextjs" | "nextjs-consumer" | "react-vite-consumer" | "angular-consumer" | "flutter-consumer" | "firebase" | "typescript" | "javascript" | "python" | "dart" | "lua" | "dotnet" | "java" | "go" | "rust" | "cpp";
2
+ export type FonteLegado = "nestjs" | "fastapi" | "flask" | "nextjs" | "nextjs-consumer" | "react-vite-consumer" | "angular-consumer" | "flutter-consumer" | "firebase" | "typescript" | "javascript" | "python" | "dart" | "lua" | "dotnet" | "java" | "go" | "rust" | "cpp" | "php";
3
3
  export type ModoAdocao = "incremental";
@@ -35,7 +35,7 @@ If the delivery includes code derived from a contract, run `sema compilar`.
35
35
  sema compilar contratos/orders.sema --alvo javascript --saida ./generated/javascript
36
36
  ```
37
37
 
38
- Replace `javascript` with `typescript`, `python`, `dart`, `lua`, `html`, or `css` when appropriate.
38
+ Replace `javascript` with `typescript`, `python`, `php`, `dart`, `lua`, `html`, or `css` when appropriate.
39
39
 
40
40
  ## Fail Closed
41
41
 
package/docs/commands.md CHANGED
@@ -36,7 +36,7 @@ Honest closure: treat drift JSON as the source of truth. `sucesso:false`, `vincu
36
36
 
37
37
  ## Sema Code
38
38
 
39
- - `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|dart|lua|javascript|html|css> --saida <diretorio>`: generates starter/support artifacts from the contract.
39
+ - `sema compilar <arquivo-ou-pasta> --alvo <typescript|python|php|dart|lua|javascript|html|css> --saida <diretorio>`: generates starter/support artifacts from the contract.
40
40
  - `sema testar <arquivo.sema> --alvo <alvo> --saida <diretorio-temporario>`: generates and runs local tests when the target supports it.
41
41
  - `sema importar <fonte> <diretorio> --saida <diretorio> --json`: imports a legacy project into initial contracts.
42
42
  - `sema renomear-semantico <arquivo-ou-pasta> --de <nome> --para <nome> --json`: helps rename symbols semantically.
@@ -49,7 +49,7 @@ Ready UI rule: if the task generates an app, site, dashboard, form, or static HT
49
49
 
50
50
  ## Canonical Syntax Lists
51
51
 
52
- - Origins for `use` and `impl`: `ts/typescript`, `js/javascript`, `py/python`, `dart`, `lua`, `cs/dotnet`, `java`, `go`, `rust`, `cpp`.
52
+ - Origins for `use` and `impl`: `ts/typescript`, `js/javascript`, `py/python`, `dart`, `lua`, `cs/dotnet`, `java`, `go`, `rust`, `cpp`, `php`.
53
53
  - Frequent `effects` categories: `persistencia`, `consulta`, `evento`, `auditoria`, `db.write`, `queue.publish`, `fs.write`, `network.egress`, `secret.read`, `shell.exec`.
54
54
  - Accepted `audit.motivo` values: `obrigatorio`, `opcional`, `dispensado`.
55
55
 
package/docs/syntax.md CHANGED
@@ -74,6 +74,7 @@ Use these origins before inventing a new one:
74
74
  - `go`
75
75
  - `rust`
76
76
  - `cpp`
77
+ - `php`
77
78
 
78
79
  Examples:
79
80
 
@@ -104,13 +105,13 @@ impl {
104
105
 
105
106
  ## JavaScript Is Supported
106
107
 
107
- The CLI supports JavaScript generation:
108
+ The CLI supports JavaScript and PHP generation:
108
109
 
109
110
  ```bash
110
111
  sema compilar contratos/orders.sema --alvo javascript --saida ./generated/javascript
111
112
  ```
112
113
 
113
- The project can also generate TypeScript, Python, Dart, Lua, HTML, and CSS when those targets are enabled in `sema.config.json`.
114
+ The project can also generate TypeScript, Python, PHP, Dart, Lua, HTML, and CSS when those targets are enabled in `sema.config.json`.
114
115
 
115
116
  ## Support Files
116
117
 
@@ -0,0 +1,3 @@
1
+ import type { IrModulo } from "@sema/nucleo";
2
+ import { type ArquivoGerado } from "@sema/padroes";
3
+ export declare function gerarPhp(modulo: IrModulo): ArquivoGerado[];