@semacode/cli 1.3.7 → 1.4.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 (46) hide show
  1. package/README.md +61 -41
  2. package/dist/drift.d.ts +5 -3
  3. package/dist/drift.js +532 -27
  4. package/dist/drift.js.map +1 -1
  5. package/dist/importador.d.ts +2 -0
  6. package/dist/importador.js +166 -7
  7. package/dist/importador.js.map +1 -1
  8. package/dist/index.js +2 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/projeto.d.ts +6 -1
  11. package/dist/projeto.js.map +1 -1
  12. package/docs/cli.md +101 -0
  13. package/docs/instalacao-e-primeiro-uso.md +108 -196
  14. package/docs/integracao-com-ia.md +43 -200
  15. package/docs/persistencia-vendor-first.md +145 -0
  16. package/docs/sintaxe.md +67 -251
  17. package/exemplos/persistencia_vendor_first.sema +86 -0
  18. package/node_modules/@sema/gerador-css/package.json +1 -1
  19. package/node_modules/@sema/gerador-dart/package.json +1 -1
  20. package/node_modules/@sema/gerador-html/package.json +1 -1
  21. package/node_modules/@sema/gerador-javascript/package.json +1 -1
  22. package/node_modules/@sema/gerador-lua/package.json +1 -1
  23. package/node_modules/@sema/gerador-python/package.json +1 -1
  24. package/node_modules/@sema/gerador-typescript/package.json +1 -1
  25. package/node_modules/@sema/nucleo/dist/ast/tipos.d.ts +2 -1
  26. package/node_modules/@sema/nucleo/dist/formatador/index.js +32 -17
  27. package/node_modules/@sema/nucleo/dist/formatador/index.js.map +1 -1
  28. package/node_modules/@sema/nucleo/dist/index.d.ts +1 -0
  29. package/node_modules/@sema/nucleo/dist/index.js +1 -0
  30. package/node_modules/@sema/nucleo/dist/index.js.map +1 -1
  31. package/node_modules/@sema/nucleo/dist/ir/conversor.js +94 -0
  32. package/node_modules/@sema/nucleo/dist/ir/conversor.js.map +1 -1
  33. package/node_modules/@sema/nucleo/dist/ir/modelos.d.ts +60 -0
  34. package/node_modules/@sema/nucleo/dist/lexer/tokens.js +15 -0
  35. package/node_modules/@sema/nucleo/dist/lexer/tokens.js.map +1 -1
  36. package/node_modules/@sema/nucleo/dist/parser/parser.js +98 -3
  37. package/node_modules/@sema/nucleo/dist/parser/parser.js.map +1 -1
  38. package/node_modules/@sema/nucleo/dist/persistencia/contratos.d.ts +39 -0
  39. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js +294 -0
  40. package/node_modules/@sema/nucleo/dist/persistencia/contratos.js.map +1 -0
  41. package/node_modules/@sema/nucleo/dist/semantico/analisador.d.ts +1 -1
  42. package/node_modules/@sema/nucleo/dist/semantico/analisador.js +118 -2
  43. package/node_modules/@sema/nucleo/dist/semantico/analisador.js.map +1 -1
  44. package/node_modules/@sema/nucleo/package.json +1 -1
  45. package/node_modules/@sema/padroes/package.json +1 -1
  46. package/package.json +11 -11
@@ -320,6 +320,106 @@ function descreverEfeitosPorHeuristica(codigo) {
320
320
  }
321
321
  return efeitos;
322
322
  }
323
+ function deduplicarDatabases(databases) {
324
+ const mapa = new Map();
325
+ for (const database of databases) {
326
+ const chave = `${database.engine}:${database.nome}`;
327
+ const existente = mapa.get(chave);
328
+ if (!existente) {
329
+ mapa.set(chave, {
330
+ ...database,
331
+ resources: [...database.resources],
332
+ diagnostics: [...(database.diagnostics ?? [])],
333
+ });
334
+ continue;
335
+ }
336
+ const recursos = new Map();
337
+ for (const recurso of [...existente.resources, ...database.resources]) {
338
+ recursos.set(`${recurso.tipo}:${recurso.nome}`, recurso);
339
+ }
340
+ existente.resources = [...recursos.values()];
341
+ existente.diagnostics = [...new Set([...(existente.diagnostics ?? []), ...(database.diagnostics ?? [])])];
342
+ }
343
+ return [...mapa.values()];
344
+ }
345
+ function inferirDatabasesPorHeuristica(codigo, relacao) {
346
+ const databases = [];
347
+ const adicionar = (database) => {
348
+ databases.push(database);
349
+ };
350
+ const texto = codigo.toLowerCase();
351
+ if (/(postgresql|postgres\b|node-postgres|pg\.pool|pgclient|typeorm.+postgres|sequelize.+postgres|provider\s*=\s*["']postgresql["'])/i.test(codigo)) {
352
+ adicionar({
353
+ nome: "principal_postgres",
354
+ resumo: `Persistencia PostgreSQL inferida automaticamente de ${relacao}.`,
355
+ engine: "postgres",
356
+ queryModel: "sql",
357
+ transactionModel: "mvcc",
358
+ resources: [
359
+ { tipo: "table", nome: "tabelas_relacionais", table: "legado_principal" },
360
+ { tipo: "query", nome: "consultas_sql", mode: "sql" },
361
+ ],
362
+ diagnostics: ["inferido_por_heuristica"],
363
+ });
364
+ }
365
+ if (/(mysql\b|mariadb|mysql2|typeorm.+mysql|sequelize.+mysql|provider\s*=\s*["']mysql["'])/i.test(codigo)) {
366
+ adicionar({
367
+ nome: "principal_mysql",
368
+ resumo: `Persistencia MySQL inferida automaticamente de ${relacao}.`,
369
+ engine: "mysql",
370
+ queryModel: "sql",
371
+ transactionModel: "bloqueio",
372
+ resources: [
373
+ { tipo: "table", nome: "tabelas_relacionais", table: "legado_principal" },
374
+ { tipo: "query", nome: "consultas_sql", mode: "sql" },
375
+ ],
376
+ diagnostics: ["inferido_por_heuristica"],
377
+ });
378
+ }
379
+ if (/(sqlite\b|better-sqlite3|provider\s*=\s*["']sqlite["'])/i.test(codigo)) {
380
+ adicionar({
381
+ nome: "principal_sqlite",
382
+ resumo: `Persistencia SQLite inferida automaticamente de ${relacao}.`,
383
+ engine: "sqlite",
384
+ queryModel: "sql",
385
+ transactionModel: "single_thread",
386
+ resources: [
387
+ { tipo: "table", nome: "tabelas_locais", table: "legado_local" },
388
+ { tipo: "query", nome: "consultas_locais", mode: "sql" },
389
+ ],
390
+ diagnostics: ["inferido_por_heuristica"],
391
+ });
392
+ }
393
+ if (/(mongodb|mongoose|mongo\.collection|mongoclient|prisma.+mongodb|provider\s*=\s*["']mongodb["'])/i.test(codigo)) {
394
+ adicionar({
395
+ nome: "principal_mongodb",
396
+ resumo: `Persistencia MongoDB inferida automaticamente de ${relacao}.`,
397
+ engine: "mongodb",
398
+ queryModel: "documento",
399
+ transactionModel: "documento",
400
+ resources: [
401
+ { tipo: "collection", nome: "colecoes_documentais", collection: "documentos" },
402
+ { tipo: "document", nome: "documentos_agregados", mode: /aggregate|\$match|\$group/i.test(codigo) ? "pipeline" : "documento" },
403
+ ],
404
+ diagnostics: ["inferido_por_heuristica"],
405
+ });
406
+ }
407
+ if (/(redis\b|ioredis|upstash|bullmq|xadd|xreadgroup)/i.test(codigo)) {
408
+ adicionar({
409
+ nome: "principal_redis",
410
+ resumo: `Persistencia Redis inferida automaticamente de ${relacao}.`,
411
+ engine: "redis",
412
+ queryModel: "chave_valor",
413
+ transactionModel: "single_thread",
414
+ resources: [
415
+ { tipo: "keyspace", nome: "estado_chaves", ttl: /\bttl\b|expire\(/i.test(codigo) ? "300s" : undefined },
416
+ { tipo: "stream", nome: "eventos_stream", surface: /bullmq|queue|worker/i.test(codigo) ? "fila" : "evento" },
417
+ ],
418
+ diagnostics: ["inferido_por_heuristica"],
419
+ });
420
+ }
421
+ return deduplicarDatabases(databases);
422
+ }
323
423
  function normalizarNomeErroBruto(nome) {
324
424
  return paraSnakeCase(nome.replace(/(Error|Erro|Exception)$/i, "")) || "erro_importado";
325
425
  }
@@ -1447,6 +1547,60 @@ function renderizarEntidade(entity) {
1447
1547
  "",
1448
1548
  ];
1449
1549
  }
1550
+ function renderizarValorDatabase(valor) {
1551
+ if (!valor) {
1552
+ return undefined;
1553
+ }
1554
+ return /[\s/{}"]/u.test(valor)
1555
+ ? `"${escaparTexto(valor)}"`
1556
+ : valor;
1557
+ }
1558
+ function renderizarRecursoDatabase(recurso) {
1559
+ const linhas = [` ${recurso.tipo} ${recurso.nome} {`];
1560
+ const mode = renderizarValorDatabase(recurso.mode);
1561
+ const table = renderizarValorDatabase(recurso.table);
1562
+ const collection = renderizarValorDatabase(recurso.collection);
1563
+ const ttl = renderizarValorDatabase(recurso.ttl);
1564
+ const surface = renderizarValorDatabase(recurso.surface);
1565
+ if (mode) {
1566
+ linhas.push(` mode: ${mode}`);
1567
+ }
1568
+ if (table) {
1569
+ linhas.push(` table: ${table}`);
1570
+ }
1571
+ if (collection) {
1572
+ linhas.push(` collection: ${collection}`);
1573
+ }
1574
+ if (ttl) {
1575
+ linhas.push(` ttl: ${ttl}`);
1576
+ }
1577
+ if (surface) {
1578
+ linhas.push(` surface: ${surface}`);
1579
+ }
1580
+ linhas.push(" }");
1581
+ linhas.push("");
1582
+ return linhas;
1583
+ }
1584
+ function renderizarDatabase(database) {
1585
+ const queryModel = renderizarValorDatabase(database.queryModel);
1586
+ const transactionModel = renderizarValorDatabase(database.transactionModel);
1587
+ return [
1588
+ ` database ${database.nome} {`,
1589
+ ` engine: ${database.engine}`,
1590
+ ...(queryModel ? [` query_model: ${queryModel}`] : []),
1591
+ ...(transactionModel ? [` transaction_model: ${transactionModel}`] : []),
1592
+ ...(database.diagnostics?.length
1593
+ ? [
1594
+ " diagnostics {",
1595
+ ...database.diagnostics.map((diagnostico) => ` ${diagnostico}`),
1596
+ " }",
1597
+ ]
1598
+ : []),
1599
+ ...database.resources.flatMap(renderizarRecursoDatabase),
1600
+ " }",
1601
+ "",
1602
+ ];
1603
+ }
1450
1604
  function moduloParaCodigo(modulo) {
1451
1605
  const linhas = [
1452
1606
  `module ${modulo.nome} {`,
@@ -1455,6 +1609,7 @@ function moduloParaCodigo(modulo) {
1455
1609
  " }",
1456
1610
  "",
1457
1611
  ...renderizarVinculos(modulo.vinculos, " "),
1612
+ ...(modulo.databases ?? []).flatMap(renderizarDatabase),
1458
1613
  ...modulo.enums.flatMap(renderizarEnum),
1459
1614
  ...modulo.entities.flatMap(renderizarEntidade),
1460
1615
  ...modulo.tasks.flatMap(renderizarTask),
@@ -1489,6 +1644,7 @@ function montarArquivoImportado(modulo, namespaceBase, conteudo) {
1489
1644
  rotas: modulo.routes.length,
1490
1645
  entidades: modulo.entities.length,
1491
1646
  enums: modulo.enums.length,
1647
+ databases: modulo.databases?.length ?? 0,
1492
1648
  };
1493
1649
  }
1494
1650
  function consolidarTiposTs(contextos) {
@@ -2336,7 +2492,7 @@ async function importarDartBase(diretorio, namespaceBase) {
2336
2492
  }
2337
2493
  return modulos;
2338
2494
  }
2339
- function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = []) {
2495
+ function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos = [], databases = []) {
2340
2496
  sincronizarRotasComTasks(routes, tasks);
2341
2497
  return {
2342
2498
  nome,
@@ -2345,6 +2501,7 @@ function criarModuloImportadoSimples(nome, resumo, tasks, routes = [], vinculos
2345
2501
  routes: deduplicarRotas(routes),
2346
2502
  entities: [],
2347
2503
  enums: [],
2504
+ databases: deduplicarDatabases(databases),
2348
2505
  vinculos: deduplicarVinculos(vinculos),
2349
2506
  };
2350
2507
  }
@@ -2358,6 +2515,7 @@ function acumularModuloImportado(modulos, modulo) {
2358
2515
  existente.routes = deduplicarRotas([...existente.routes, ...modulo.routes]);
2359
2516
  existente.entities = deduplicarEntidades([...existente.entities, ...modulo.entities]);
2360
2517
  existente.enums = deduplicarEnums([...existente.enums, ...modulo.enums]);
2518
+ existente.databases = deduplicarDatabases([...(existente.databases ?? []), ...(modulo.databases ?? [])]);
2361
2519
  existente.vinculos = deduplicarVinculos([...(existente.vinculos ?? []), ...(modulo.vinculos ?? [])]);
2362
2520
  }
2363
2521
  function selecionarSimbolosPreferidos(simbolos) {
@@ -2464,7 +2622,7 @@ async function importarDotnetBase(diretorio, namespaceBase) {
2464
2622
  if (tasks.length === 0 && routes.length === 0) {
2465
2623
  continue;
2466
2624
  }
2467
- acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes));
2625
+ acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
2468
2626
  }
2469
2627
  return [...modulos.values()];
2470
2628
  }
@@ -2525,7 +2683,7 @@ async function importarJavaBase(diretorio, namespaceBase) {
2525
2683
  if (tasks.length === 0 && routes.length === 0) {
2526
2684
  continue;
2527
2685
  }
2528
- acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes));
2686
+ acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
2529
2687
  }
2530
2688
  return [...modulos.values()];
2531
2689
  }
@@ -2584,7 +2742,7 @@ async function importarGoBase(diretorio, namespaceBase) {
2584
2742
  if (tasks.length === 0 && routes.length === 0) {
2585
2743
  continue;
2586
2744
  }
2587
- modulos.set(nomeModulo, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes));
2745
+ modulos.set(nomeModulo, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
2588
2746
  }
2589
2747
  return [...modulos.values()];
2590
2748
  }
@@ -2616,7 +2774,7 @@ async function importarRustBase(diretorio, namespaceBase) {
2616
2774
  origemSimbolo: simbolo.simbolo,
2617
2775
  });
2618
2776
  }
2619
- acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes));
2777
+ acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, routes, [], inferirDatabasesPorHeuristica(texto, relacao)));
2620
2778
  for (const rota of extrairRotasRust(texto)) {
2621
2779
  const simboloLimpo = rota.simbolo.replace(/::/g, ".");
2622
2780
  const nomeSimbolo = simboloLimpo.split(".").at(-1) ?? simboloLimpo;
@@ -2645,7 +2803,7 @@ async function importarRustBase(diretorio, namespaceBase) {
2645
2803
  output: [{ nome: "resultado", tipo: "Json", obrigatorio: false }],
2646
2804
  errors: [],
2647
2805
  };
2648
- acumularModuloImportado(modulos, criarModuloImportadoSimples(moduloAlvo, `Rascunho Sema importado automaticamente de ${relacaoAlvo}.`, [task], [route]));
2806
+ acumularModuloImportado(modulos, criarModuloImportadoSimples(moduloAlvo, `Rascunho Sema importado automaticamente de ${relacaoAlvo}.`, [task], [route], [], inferirDatabasesPorHeuristica(texto, relacao)));
2649
2807
  }
2650
2808
  }
2651
2809
  return [...modulos.values()];
@@ -2681,7 +2839,7 @@ async function importarCppBase(diretorio, namespaceBase) {
2681
2839
  if (tasks.length === 0) {
2682
2840
  continue;
2683
2841
  }
2684
- acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks));
2842
+ acumularModuloImportado(modulos, criarModuloImportadoSimples(nomeModulo, `Rascunho Sema importado automaticamente de ${relacao}.`, tasks, [], [], inferirDatabasesPorHeuristica(texto, relacao)));
2685
2843
  }
2686
2844
  return [...modulos.values()];
2687
2845
  }
@@ -2765,6 +2923,7 @@ export function resumoImportacao(resultado) {
2765
2923
  rotas: resultado.arquivos.reduce((total, arquivo) => total + arquivo.rotas, 0),
2766
2924
  entidades: resultado.arquivos.reduce((total, arquivo) => total + arquivo.entidades, 0),
2767
2925
  enums: resultado.arquivos.reduce((total, arquivo) => total + arquivo.enums, 0),
2926
+ databases: resultado.arquivos.reduce((total, arquivo) => total + arquivo.databases, 0),
2768
2927
  diagnosticos: resultado.diagnosticos.length,
2769
2928
  sucesso: !temErros(resultado.diagnosticos),
2770
2929
  };