@open-mercato/cli 0.10.1-develop.7809.1.ea24461aeb → 0.10.1-develop.7813.1.83931e7add

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 (100) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/dist/agentic/guides/module-facts.json +162 -162
  3. package/dist/agentic/guides/module-facts.v2.json +162 -162
  4. package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
  5. package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
  6. package/dist/agentic/guides/modules/api_docs/index.md +1 -1
  7. package/dist/agentic/guides/modules/api_keys/index.md +1 -1
  8. package/dist/agentic/guides/modules/attachments/index.md +1 -1
  9. package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
  10. package/dist/agentic/guides/modules/auth/index.md +1 -1
  11. package/dist/agentic/guides/modules/availability/index.md +1 -1
  12. package/dist/agentic/guides/modules/business_rules/index.md +1 -1
  13. package/dist/agentic/guides/modules/carrier_inpost/index.md +1 -1
  14. package/dist/agentic/guides/modules/cart/index.md +1 -1
  15. package/dist/agentic/guides/modules/catalog/index.md +1 -1
  16. package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
  17. package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
  18. package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
  19. package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
  20. package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
  21. package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
  22. package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
  23. package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
  24. package/dist/agentic/guides/modules/channel_smtp/index.md +1 -1
  25. package/dist/agentic/guides/modules/checkout/index.md +1 -1
  26. package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
  27. package/dist/agentic/guides/modules/configs/index.md +1 -1
  28. package/dist/agentic/guides/modules/content/index.md +1 -1
  29. package/dist/agentic/guides/modules/currencies/index.md +1 -1
  30. package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
  31. package/dist/agentic/guides/modules/customer_groups/index.md +1 -1
  32. package/dist/agentic/guides/modules/customers/index.md +1 -1
  33. package/dist/agentic/guides/modules/dashboards/index.md +1 -1
  34. package/dist/agentic/guides/modules/data_sync/index.md +1 -1
  35. package/dist/agentic/guides/modules/design_system/index.md +1 -1
  36. package/dist/agentic/guides/modules/devices/index.md +1 -1
  37. package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
  38. package/dist/agentic/guides/modules/directory/index.md +1 -1
  39. package/dist/agentic/guides/modules/documents/index.md +1 -1
  40. package/dist/agentic/guides/modules/ecommerce/index.md +1 -1
  41. package/dist/agentic/guides/modules/entities/index.md +1 -1
  42. package/dist/agentic/guides/modules/eudr/index.md +1 -1
  43. package/dist/agentic/guides/modules/events/index.md +1 -1
  44. package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
  45. package/dist/agentic/guides/modules/forms/index.md +1 -1
  46. package/dist/agentic/guides/modules/gateway_autopay/index.md +1 -1
  47. package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
  48. package/dist/agentic/guides/modules/gateway_tpay/index.md +1 -1
  49. package/dist/agentic/guides/modules/generators/index.md +1 -1
  50. package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
  51. package/dist/agentic/guides/modules/integrations/index.md +1 -1
  52. package/dist/agentic/guides/modules/messages/index.md +1 -1
  53. package/dist/agentic/guides/modules/notifications/index.md +1 -1
  54. package/dist/agentic/guides/modules/onboarding/index.md +1 -1
  55. package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
  56. package/dist/agentic/guides/modules/perspectives/index.md +1 -1
  57. package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
  58. package/dist/agentic/guides/modules/planner/index.md +1 -1
  59. package/dist/agentic/guides/modules/portal/index.md +1 -1
  60. package/dist/agentic/guides/modules/progress/index.md +1 -1
  61. package/dist/agentic/guides/modules/promotions/index.md +1 -1
  62. package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
  63. package/dist/agentic/guides/modules/query_index/index.md +1 -1
  64. package/dist/agentic/guides/modules/record_locks/index.md +1 -1
  65. package/dist/agentic/guides/modules/resources/index.md +1 -1
  66. package/dist/agentic/guides/modules/sales/index.md +1 -1
  67. package/dist/agentic/guides/modules/scheduler/index.md +1 -1
  68. package/dist/agentic/guides/modules/search/index.md +1 -1
  69. package/dist/agentic/guides/modules/security/index.md +1 -1
  70. package/dist/agentic/guides/modules/seeds/index.md +1 -1
  71. package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
  72. package/dist/agentic/guides/modules/sso/index.md +1 -1
  73. package/dist/agentic/guides/modules/staff/index.md +1 -1
  74. package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
  75. package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
  76. package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
  77. package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
  78. package/dist/agentic/guides/modules/telemetry/index.md +1 -1
  79. package/dist/agentic/guides/modules/tillio/index.md +1 -1
  80. package/dist/agentic/guides/modules/translations/index.md +1 -1
  81. package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
  82. package/dist/agentic/guides/modules/webhooks/index.md +1 -1
  83. package/dist/agentic/guides/modules/wms/index.md +1 -1
  84. package/dist/agentic/guides/modules/workflows/index.md +1 -1
  85. package/dist/agentic/guides/reference-module-facts.json +1 -1
  86. package/dist/agentic/guides/upstream/BACKWARD_COMPATIBILITY.md +40 -38
  87. package/dist/agentic/guides/upstream/manifest.json +2 -2
  88. package/dist/lib/generators/ast/imports.js +9 -4
  89. package/dist/lib/generators/ast/imports.js.map +2 -2
  90. package/dist/lib/generators/entity-ids.js +10 -12
  91. package/dist/lib/generators/entity-ids.js.map +2 -2
  92. package/dist/lib/generators/module-di.js +6 -9
  93. package/dist/lib/generators/module-di.js.map +2 -2
  94. package/dist/lib/generators/module-entities.js +6 -9
  95. package/dist/lib/generators/module-entities.js.map +2 -2
  96. package/package.json +7 -7
  97. package/src/lib/generators/ast/imports.ts +14 -4
  98. package/src/lib/generators/entity-ids.ts +10 -12
  99. package/src/lib/generators/module-di.ts +6 -9
  100. package/src/lib/generators/module-entities.ts +6 -9
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/generators/module-di.ts"],
4
- "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { StructureKind, VariableDeclarationKind } from 'ts-morph'\nimport type { PackageResolver } from '../resolver'\nimport { MODULE_CODE_EXTENSIONS } from './scanner'\nimport {\n toVar,\n type GeneratorResult,\n createGeneratorResult,\n writeGeneratedFile,\n} from '../utils'\nimport {\n addAutoGeneratedComment,\n addImportSpec,\n arrayLiteral,\n createGeneratedSourceFile,\n getSourceText,\n identifier,\n methodCall,\n parenthesized,\n} from './ast'\n\nexport interface ModuleDiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\nexport async function generateModuleDi(options: ModuleDiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'di.generated.ts')\n const checksumFile = path.join(outputDir, 'di.generated.checksum')\n\n const mods = resolver.loadEnabledModules()\n const imports: Array<{ name: string; moduleSpecifier: string }> = []\n const registrars: string[] = []\n let i = 0\n\n for (const entry of mods) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n const imp = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n\n const useApp = resolveModuleConventionFile(roots.appBase, 'di')\n const usePkg = resolveModuleConventionFile(roots.pkgBase, 'di')\n const importName = `D_${toVar(modId)}_${i++}`\n\n if (useApp) {\n warnIfDiMissingRegisterExport(findModuleConventionFilePath(roots.appBase, 'di'), quiet)\n // For @app modules, use relative path to work in both Next.js and Node.js CLI context\n // From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/\n const importPath = isAppModule ? `../../src/modules/${modId}/di` : `${imp.appBase}/di`\n imports.push({ name: importName, moduleSpecifier: importPath })\n registrars.push(`${importName}.register`)\n } else if (usePkg) {\n warnIfDiMissingRegisterExport(findModuleConventionFilePath(roots.pkgBase, 'di'), quiet)\n imports.push({ name: importName, moduleSpecifier: `${imp.pkgBase}/di` })\n registrars.push(`${importName}.register`)\n }\n }\n\n const sourceFile = createGeneratedSourceFile('di.generated.ts')\n addAutoGeneratedComment(sourceFile, 'di')\n imports.forEach((entry) => {\n addImportSpec(sourceFile, {\n kind: StructureKind.ImportDeclaration,\n namespaceImport: entry.name,\n moduleSpecifier: entry.moduleSpecifier,\n })\n })\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'diRegistrars',\n type: '(((c: any) => void) | undefined)[]',\n initializer: methodCall(\n parenthesized(arrayLiteral(registrars, (currentWriter, registrar) => identifier(registrar)(currentWriter))),\n 'filter',\n [identifier('Boolean')],\n ),\n },\n ],\n })\n sourceFile.addExportDeclaration({\n namedExports: ['diRegistrars'],\n })\n sourceFile.addExportAssignment({\n isExportEquals: false,\n expression: 'diRegistrars',\n })\n const output = getSourceText(sourceFile)\n\n writeGeneratedFile({\n outFile,\n checksumFile,\n content: output,\n structureChecksum: '',\n result,\n quiet,\n })\n\n return result\n}\n\nfunction resolveModuleConventionFile(baseDir: string, basename: string): boolean {\n return MODULE_CODE_EXTENSIONS.some((extension) => fs.existsSync(path.join(baseDir, `${basename}${extension}`)))\n}\n\nfunction findModuleConventionFilePath(baseDir: string, basename: string): string | null {\n for (const extension of MODULE_CODE_EXTENSIONS) {\n const candidate = path.join(baseDir, `${basename}${extension}`)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Warns when a discovered `di.ts` exports no `register`.\n *\n * The generated registrar list is built from `<import>.register` for every module that has a\n * `di` file. A differently named export makes that entry `undefined`, so the module's DI\n * registrations silently never run and its services surface as missing at request time\n * instead of at generation time.\n */\nexport function warnIfDiMissingRegisterExport(diPath: string | null, quiet = false): void {\n if (!diPath || quiet) return\n let source = ''\n try {\n source = fs.readFileSync(diPath, 'utf8')\n } catch {\n return\n }\n const exportsRegister = /export\\s+(async\\s+)?function\\s+register\\b/.test(source)\n || /export\\s+(const|let|var)\\s+register\\b/.test(source)\n || /export\\s*\\{[^}]*\\bregister\\b[^}]*\\}/.test(source)\n if (exportsRegister) return\n console.warn(\n `[generate] \u26A0 di.ts exports no 'register' \u2014 this module's DI registrations will never run: ${diPath}`,\n )\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { VariableDeclarationKind } from 'ts-morph'\nimport type { PackageResolver } from '../resolver'\nimport { MODULE_CODE_EXTENSIONS } from './scanner'\nimport {\n toVar,\n type GeneratorResult,\n createGeneratorResult,\n writeGeneratedFile,\n} from '../utils'\nimport {\n addAutoGeneratedComment,\n addImportSpecs,\n arrayLiteral,\n createGeneratedSourceFile,\n getSourceText,\n identifier,\n methodCall,\n parenthesized,\n} from './ast'\n\nexport interface ModuleDiOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\nexport async function generateModuleDi(options: ModuleDiOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'di.generated.ts')\n const checksumFile = path.join(outputDir, 'di.generated.checksum')\n\n const mods = resolver.loadEnabledModules()\n const imports: Array<{ name: string; moduleSpecifier: string }> = []\n const registrars: string[] = []\n let i = 0\n\n for (const entry of mods) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n const imp = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n\n const useApp = resolveModuleConventionFile(roots.appBase, 'di')\n const usePkg = resolveModuleConventionFile(roots.pkgBase, 'di')\n const importName = `D_${toVar(modId)}_${i++}`\n\n if (useApp) {\n warnIfDiMissingRegisterExport(findModuleConventionFilePath(roots.appBase, 'di'), quiet)\n // For @app modules, use relative path to work in both Next.js and Node.js CLI context\n // From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/\n const importPath = isAppModule ? `../../src/modules/${modId}/di` : `${imp.appBase}/di`\n imports.push({ name: importName, moduleSpecifier: importPath })\n registrars.push(`${importName}.register`)\n } else if (usePkg) {\n warnIfDiMissingRegisterExport(findModuleConventionFilePath(roots.pkgBase, 'di'), quiet)\n imports.push({ name: importName, moduleSpecifier: `${imp.pkgBase}/di` })\n registrars.push(`${importName}.register`)\n }\n }\n\n const sourceFile = createGeneratedSourceFile('di.generated.ts')\n addAutoGeneratedComment(sourceFile, 'di')\n addImportSpecs(sourceFile, imports.map((entry) => ({\n namespaceImport: entry.name,\n moduleSpecifier: entry.moduleSpecifier,\n })))\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n declarations: [\n {\n name: 'diRegistrars',\n type: '(((c: any) => void) | undefined)[]',\n initializer: methodCall(\n parenthesized(arrayLiteral(registrars, (currentWriter, registrar) => identifier(registrar)(currentWriter))),\n 'filter',\n [identifier('Boolean')],\n ),\n },\n ],\n })\n sourceFile.addExportDeclaration({\n namedExports: ['diRegistrars'],\n })\n sourceFile.addExportAssignment({\n isExportEquals: false,\n expression: 'diRegistrars',\n })\n const output = getSourceText(sourceFile)\n\n writeGeneratedFile({\n outFile,\n checksumFile,\n content: output,\n structureChecksum: '',\n result,\n quiet,\n })\n\n return result\n}\n\nfunction resolveModuleConventionFile(baseDir: string, basename: string): boolean {\n return MODULE_CODE_EXTENSIONS.some((extension) => fs.existsSync(path.join(baseDir, `${basename}${extension}`)))\n}\n\nfunction findModuleConventionFilePath(baseDir: string, basename: string): string | null {\n for (const extension of MODULE_CODE_EXTENSIONS) {\n const candidate = path.join(baseDir, `${basename}${extension}`)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n\n/**\n * Warns when a discovered `di.ts` exports no `register`.\n *\n * The generated registrar list is built from `<import>.register` for every module that has a\n * `di` file. A differently named export makes that entry `undefined`, so the module's DI\n * registrations silently never run and its services surface as missing at request time\n * instead of at generation time.\n */\nexport function warnIfDiMissingRegisterExport(diPath: string | null, quiet = false): void {\n if (!diPath || quiet) return\n let source = ''\n try {\n source = fs.readFileSync(diPath, 'utf8')\n } catch {\n return\n }\n const exportsRegister = /export\\s+(async\\s+)?function\\s+register\\b/.test(source)\n || /export\\s+(const|let|var)\\s+register\\b/.test(source)\n || /export\\s*\\{[^}]*\\bregister\\b[^}]*\\}/.test(source)\n if (exportsRegister) return\n console.warn(\n `[generate] \u26A0 di.ts exports no 'register' \u2014 this module's DI registrations will never run: ${diPath}`,\n )\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import fs from "node:fs";
2
2
  import path from "node:path";
3
- import { StructureKind, VariableDeclarationKind } from "ts-morph";
3
+ import { VariableDeclarationKind } from "ts-morph";
4
4
  import {
5
5
  findDuplicateEntityClassNames,
6
6
  formatDuplicateEntityClassNamesWarning
@@ -14,7 +14,7 @@ import {
14
14
  } from "../utils.js";
15
15
  import {
16
16
  addAutoGeneratedComment,
17
- addImportSpec,
17
+ addImportSpecs,
18
18
  asExpression,
19
19
  arrayLiteral,
20
20
  arrowFunction,
@@ -89,13 +89,10 @@ async function generateModuleEntities(options) {
89
89
  }
90
90
  const sourceFile = createGeneratedSourceFile("entities.generated.ts");
91
91
  addAutoGeneratedComment(sourceFile, "entities");
92
- imports.forEach((entry) => {
93
- addImportSpec(sourceFile, {
94
- kind: StructureKind.ImportDeclaration,
95
- namespaceImport: entry.name,
96
- moduleSpecifier: entry.moduleSpecifier
97
- });
98
- });
92
+ addImportSpecs(sourceFile, imports.map((entry) => ({
93
+ namespaceImport: entry.name,
94
+ moduleSpecifier: entry.moduleSpecifier
95
+ })));
99
96
  sourceFile.addFunction({
100
97
  name: "enhanceEntities",
101
98
  parameters: [
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/generators/module-entities.ts"],
4
- "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { StructureKind, VariableDeclarationKind } from 'ts-morph'\nimport {\n findDuplicateEntityClassNames,\n formatDuplicateEntityClassNamesWarning,\n type EntityClassNameEntry,\n} from '@open-mercato/shared/lib/db/duplicateEntityClassNames'\nimport type { ModuleEntry, PackageResolver } from '../resolver'\nimport { parseEntityClassNames } from './entity-class-declarations'\nimport { MODULE_CODE_EXTENSIONS, stripModuleCodeExtension } from './scanner'\nimport {\n toVar,\n type GeneratorResult,\n createGeneratorResult,\n writeGeneratedFile,\n} from '../utils'\nimport {\n addAutoGeneratedComment,\n addImportSpec,\n asExpression,\n arrayLiteral,\n arrowFunction,\n binaryExpression,\n callExpression,\n createGeneratedSourceFile,\n expressionStatement,\n getSourceText,\n identifier,\n ifStatement,\n logicalAnd,\n methodCall,\n objectEntries,\n objectLiteral,\n prefixExpression,\n propertyAccess,\n returnStatement,\n spreadExpression,\n templateLiteral,\n variableStatement,\n} from './ast'\n\nexport interface ModuleEntitiesOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\nexport async function generateModuleEntities(options: ModuleEntitiesOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'entities.generated.ts')\n const checksumFile = path.join(outputDir, 'entities.generated.checksum')\n\n const mods = resolver.loadEnabledModules()\n const imports: Array<{ name: string; moduleSpecifier: string }> = []\n const entitySources: Array<{ importName: string; moduleId: string }> = []\n const classNameEntries: EntityClassNameEntry[] = []\n let n = 0\n\n for (const entry of mods) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n const imp = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n\n // prefer app override data/, fallback to core data/, then legacy db/\n const appData = path.join(roots.appBase, 'data')\n const pkgData = path.join(roots.pkgBase, 'data')\n const appDb = path.join(roots.appBase, 'db')\n const pkgDb = path.join(roots.pkgBase, 'db')\n const bases = [appData, pkgData, appDb, pkgDb]\n const candidates = ['entities.override', 'entities', 'schema']\n\n let found: { base: string; file: string } | null = null\n for (const base of bases) {\n for (const f of candidates) {\n const p = resolveConventionFile(base, f)\n if (p) {\n found = { base, file: path.basename(p) }\n break\n }\n }\n if (found) break\n }\n if (!found) continue\n\n const importName = `E_${toVar(modId)}_${n++}`\n const sub = path.basename(found.base) // 'data' or 'db'\n const fromApp = found.base.startsWith(roots.appBase)\n // For @app modules, use relative path to ensure it works both in Next.js and Node.js CLI context\n // From .mercato/generated/, the relative path to src/modules/ is ../src/modules/\n let relImport: string\n if (isAppModule && fromApp) {\n // From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/\n relImport = `../../src/modules/${modId}/${sub}/${stripModuleCodeExtension(found.file)}`\n } else {\n const baseImport = fromApp ? imp.appBase : imp.pkgBase\n relImport = `${baseImport}/${sub}/${stripModuleCodeExtension(found.file)}`\n }\n imports.push({ name: importName, moduleSpecifier: relImport })\n entitySources.push({ importName, moduleId: modId })\n\n const entityFilePath = resolveEntitySourceFile(resolver, entry, found, fromApp)\n for (const className of parseEntityClassNames(entityFilePath)) {\n classNameEntries.push({ className, moduleId: modId, sourcePath: entityFilePath })\n }\n }\n\n const sourceFile = createGeneratedSourceFile('entities.generated.ts')\n addAutoGeneratedComment(sourceFile, 'entities')\n imports.forEach((entry) => {\n addImportSpec(sourceFile, {\n kind: StructureKind.ImportDeclaration,\n namespaceImport: entry.name,\n moduleSpecifier: entry.moduleSpecifier,\n })\n })\n sourceFile.addFunction({\n name: 'enhanceEntities',\n parameters: [\n { name: 'namespace', type: 'Record<string, unknown>' },\n { name: 'moduleId', type: 'string' },\n ],\n returnType: 'any[]',\n statements: [\n returnStatement(\n methodCall(\n methodCall(objectEntries(identifier('namespace')), 'filter', [\n arrowFunction({\n parameters: ['[, value]'],\n body: binaryExpression(\n prefixExpression('typeof ', identifier('value')),\n '===',\n 'function',\n ),\n }),\n ]),\n 'map',\n [\n arrowFunction({\n parameters: ['[exportName, value]'],\n body: (writer) => {\n writer.block(() => {\n variableStatement({\n name: 'entity',\n initializer: asExpression(identifier('value'), '{ entityName?: string }'),\n })(writer)\n writer.newLine()\n ifStatement({\n condition: logicalAnd([\n identifier('entity'),\n binaryExpression(\n prefixExpression('typeof ', identifier('entity')),\n '===',\n 'function',\n ),\n binaryExpression(\n methodCall(\n propertyAccess(\n propertyAccess(identifier('Object'), 'prototype'),\n 'hasOwnProperty',\n ),\n 'call',\n [identifier('entity'), 'entityName'],\n ),\n '===',\n false,\n ),\n ]),\n thenStatements: [\n expressionStatement(\n callExpression(propertyAccess(identifier('Object'), 'defineProperty'), [\n identifier('entity'),\n 'entityName',\n objectLiteral([\n {\n name: 'value',\n value: templateLiteral([\n identifier('moduleId'),\n '.',\n identifier('exportName'),\n ]),\n },\n { name: 'configurable', value: true },\n { name: 'enumerable', value: false },\n { name: 'writable', value: false },\n ]),\n ]),\n ),\n ],\n })(writer)\n writer.newLine()\n returnStatement(identifier('entity'))(writer)\n })\n },\n }),\n ],\n ),\n ),\n ],\n })\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n declarations: [\n {\n name: 'entities',\n initializer: arrayLiteral(entitySources, (writer, entry) =>\n spreadExpression(callExpression(identifier('enhanceEntities'), [identifier(entry.importName), entry.moduleId]))(writer)),\n },\n ],\n })\n const output = getSourceText(sourceFile)\n\n writeGeneratedFile({\n outFile,\n checksumFile,\n content: output,\n structureChecksum: '',\n result,\n quiet,\n })\n\n warnOnDuplicateEntityClassNames(classNameEntries)\n\n return result\n}\n\n/**\n * A duplicate entity class name across modules silently corrupts entity resolution at\n * runtime and no build step otherwise catches it, so surface it here \u2014 where the\n * colliding registry is produced. Reported as a warning; generation still succeeds.\n */\nfunction warnOnDuplicateEntityClassNames(entries: readonly EntityClassNameEntry[]): void {\n try {\n const duplicates = findDuplicateEntityClassNames(entries)\n if (duplicates.length === 0) return\n console.warn(`\\x1b[33m[Entities Warning]\\x1b[0m ${formatDuplicateEntityClassNamesWarning(duplicates)}`)\n } catch {\n // This check is a diagnostic. It must never be the reason generation fails.\n }\n}\n\n/**\n * The file to read class names out of, which is not always the file the runtime imports.\n * A standalone install resolves a package module to its compiled `dist/modules` tree, and\n * published packages ship `src/modules` alongside it \u2014 so prefer the shipped source, the\n * way `eject` already does, and leave the runtime import pointing at `dist`. A package\n * that ships compiled output only falls back to the resolved base, which the parser also\n * understands. An app override wins over the package tree entirely: the registry imports\n * the app file, so that is the file whose class names are registered.\n */\nfunction resolveEntitySourceFile(\n resolver: PackageResolver,\n entry: ModuleEntry,\n found: { base: string; file: string },\n fromApp: boolean,\n): string {\n const resolved = path.join(found.base, found.file)\n const from = entry.from\n if (fromApp || !from || from === '@app') return resolved\n const sourceBase = path.join(resolver.getPackageRoot(from), 'src', 'modules', entry.id, path.basename(found.base))\n if (path.resolve(sourceBase) === path.resolve(found.base)) return resolved\n const sourceFile = resolveConventionFile(sourceBase, stripModuleCodeExtension(found.file))\n return sourceFile ?? resolved\n}\n\nfunction resolveConventionFile(baseDir: string, basename: string): string | null {\n for (const extension of MODULE_CODE_EXTENSIONS) {\n const candidate = path.join(baseDir, `${basename}${extension}`)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { VariableDeclarationKind } from 'ts-morph'\nimport {\n findDuplicateEntityClassNames,\n formatDuplicateEntityClassNamesWarning,\n type EntityClassNameEntry,\n} from '@open-mercato/shared/lib/db/duplicateEntityClassNames'\nimport type { ModuleEntry, PackageResolver } from '../resolver'\nimport { parseEntityClassNames } from './entity-class-declarations'\nimport { MODULE_CODE_EXTENSIONS, stripModuleCodeExtension } from './scanner'\nimport {\n toVar,\n type GeneratorResult,\n createGeneratorResult,\n writeGeneratedFile,\n} from '../utils'\nimport {\n addAutoGeneratedComment,\n addImportSpecs,\n asExpression,\n arrayLiteral,\n arrowFunction,\n binaryExpression,\n callExpression,\n createGeneratedSourceFile,\n expressionStatement,\n getSourceText,\n identifier,\n ifStatement,\n logicalAnd,\n methodCall,\n objectEntries,\n objectLiteral,\n prefixExpression,\n propertyAccess,\n returnStatement,\n spreadExpression,\n templateLiteral,\n variableStatement,\n} from './ast'\n\nexport interface ModuleEntitiesOptions {\n resolver: PackageResolver\n quiet?: boolean\n}\n\nexport async function generateModuleEntities(options: ModuleEntitiesOptions): Promise<GeneratorResult> {\n const { resolver, quiet = false } = options\n const result = createGeneratorResult()\n\n const outputDir = resolver.getOutputDir()\n const outFile = path.join(outputDir, 'entities.generated.ts')\n const checksumFile = path.join(outputDir, 'entities.generated.checksum')\n\n const mods = resolver.loadEnabledModules()\n const imports: Array<{ name: string; moduleSpecifier: string }> = []\n const entitySources: Array<{ importName: string; moduleId: string }> = []\n const classNameEntries: EntityClassNameEntry[] = []\n let n = 0\n\n for (const entry of mods) {\n const modId = entry.id\n const roots = resolver.getModulePaths(entry)\n const imp = resolver.getModuleImportBase(entry)\n const isAppModule = entry.from === '@app'\n\n // prefer app override data/, fallback to core data/, then legacy db/\n const appData = path.join(roots.appBase, 'data')\n const pkgData = path.join(roots.pkgBase, 'data')\n const appDb = path.join(roots.appBase, 'db')\n const pkgDb = path.join(roots.pkgBase, 'db')\n const bases = [appData, pkgData, appDb, pkgDb]\n const candidates = ['entities.override', 'entities', 'schema']\n\n let found: { base: string; file: string } | null = null\n for (const base of bases) {\n for (const f of candidates) {\n const p = resolveConventionFile(base, f)\n if (p) {\n found = { base, file: path.basename(p) }\n break\n }\n }\n if (found) break\n }\n if (!found) continue\n\n const importName = `E_${toVar(modId)}_${n++}`\n const sub = path.basename(found.base) // 'data' or 'db'\n const fromApp = found.base.startsWith(roots.appBase)\n // For @app modules, use relative path to ensure it works both in Next.js and Node.js CLI context\n // From .mercato/generated/, the relative path to src/modules/ is ../src/modules/\n let relImport: string\n if (isAppModule && fromApp) {\n // From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/\n relImport = `../../src/modules/${modId}/${sub}/${stripModuleCodeExtension(found.file)}`\n } else {\n const baseImport = fromApp ? imp.appBase : imp.pkgBase\n relImport = `${baseImport}/${sub}/${stripModuleCodeExtension(found.file)}`\n }\n imports.push({ name: importName, moduleSpecifier: relImport })\n entitySources.push({ importName, moduleId: modId })\n\n const entityFilePath = resolveEntitySourceFile(resolver, entry, found, fromApp)\n for (const className of parseEntityClassNames(entityFilePath)) {\n classNameEntries.push({ className, moduleId: modId, sourcePath: entityFilePath })\n }\n }\n\n const sourceFile = createGeneratedSourceFile('entities.generated.ts')\n addAutoGeneratedComment(sourceFile, 'entities')\n addImportSpecs(sourceFile, imports.map((entry) => ({\n namespaceImport: entry.name,\n moduleSpecifier: entry.moduleSpecifier,\n })))\n sourceFile.addFunction({\n name: 'enhanceEntities',\n parameters: [\n { name: 'namespace', type: 'Record<string, unknown>' },\n { name: 'moduleId', type: 'string' },\n ],\n returnType: 'any[]',\n statements: [\n returnStatement(\n methodCall(\n methodCall(objectEntries(identifier('namespace')), 'filter', [\n arrowFunction({\n parameters: ['[, value]'],\n body: binaryExpression(\n prefixExpression('typeof ', identifier('value')),\n '===',\n 'function',\n ),\n }),\n ]),\n 'map',\n [\n arrowFunction({\n parameters: ['[exportName, value]'],\n body: (writer) => {\n writer.block(() => {\n variableStatement({\n name: 'entity',\n initializer: asExpression(identifier('value'), '{ entityName?: string }'),\n })(writer)\n writer.newLine()\n ifStatement({\n condition: logicalAnd([\n identifier('entity'),\n binaryExpression(\n prefixExpression('typeof ', identifier('entity')),\n '===',\n 'function',\n ),\n binaryExpression(\n methodCall(\n propertyAccess(\n propertyAccess(identifier('Object'), 'prototype'),\n 'hasOwnProperty',\n ),\n 'call',\n [identifier('entity'), 'entityName'],\n ),\n '===',\n false,\n ),\n ]),\n thenStatements: [\n expressionStatement(\n callExpression(propertyAccess(identifier('Object'), 'defineProperty'), [\n identifier('entity'),\n 'entityName',\n objectLiteral([\n {\n name: 'value',\n value: templateLiteral([\n identifier('moduleId'),\n '.',\n identifier('exportName'),\n ]),\n },\n { name: 'configurable', value: true },\n { name: 'enumerable', value: false },\n { name: 'writable', value: false },\n ]),\n ]),\n ),\n ],\n })(writer)\n writer.newLine()\n returnStatement(identifier('entity'))(writer)\n })\n },\n }),\n ],\n ),\n ),\n ],\n })\n sourceFile.addVariableStatement({\n declarationKind: VariableDeclarationKind.Const,\n isExported: true,\n declarations: [\n {\n name: 'entities',\n initializer: arrayLiteral(entitySources, (writer, entry) =>\n spreadExpression(callExpression(identifier('enhanceEntities'), [identifier(entry.importName), entry.moduleId]))(writer)),\n },\n ],\n })\n const output = getSourceText(sourceFile)\n\n writeGeneratedFile({\n outFile,\n checksumFile,\n content: output,\n structureChecksum: '',\n result,\n quiet,\n })\n\n warnOnDuplicateEntityClassNames(classNameEntries)\n\n return result\n}\n\n/**\n * A duplicate entity class name across modules silently corrupts entity resolution at\n * runtime and no build step otherwise catches it, so surface it here \u2014 where the\n * colliding registry is produced. Reported as a warning; generation still succeeds.\n */\nfunction warnOnDuplicateEntityClassNames(entries: readonly EntityClassNameEntry[]): void {\n try {\n const duplicates = findDuplicateEntityClassNames(entries)\n if (duplicates.length === 0) return\n console.warn(`\\x1b[33m[Entities Warning]\\x1b[0m ${formatDuplicateEntityClassNamesWarning(duplicates)}`)\n } catch {\n // This check is a diagnostic. It must never be the reason generation fails.\n }\n}\n\n/**\n * The file to read class names out of, which is not always the file the runtime imports.\n * A standalone install resolves a package module to its compiled `dist/modules` tree, and\n * published packages ship `src/modules` alongside it \u2014 so prefer the shipped source, the\n * way `eject` already does, and leave the runtime import pointing at `dist`. A package\n * that ships compiled output only falls back to the resolved base, which the parser also\n * understands. An app override wins over the package tree entirely: the registry imports\n * the app file, so that is the file whose class names are registered.\n */\nfunction resolveEntitySourceFile(\n resolver: PackageResolver,\n entry: ModuleEntry,\n found: { base: string; file: string },\n fromApp: boolean,\n): string {\n const resolved = path.join(found.base, found.file)\n const from = entry.from\n if (fromApp || !from || from === '@app') return resolved\n const sourceBase = path.join(resolver.getPackageRoot(from), 'src', 'modules', entry.id, path.basename(found.base))\n if (path.resolve(sourceBase) === path.resolve(found.base)) return resolved\n const sourceFile = resolveConventionFile(sourceBase, stripModuleCodeExtension(found.file))\n return sourceFile ?? resolved\n}\n\nfunction resolveConventionFile(baseDir: string, basename: string): string | null {\n for (const extension of MODULE_CODE_EXTENSIONS) {\n const candidate = path.join(baseDir, `${basename}${extension}`)\n if (fs.existsSync(candidate)) return candidate\n }\n return null\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/cli",
3
- "version": "0.10.1-develop.7809.1.ea24461aeb",
3
+ "version": "0.10.1-develop.7813.1.83931e7add",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -60,10 +60,10 @@
60
60
  "@mikro-orm/decorators": "^7.1.14",
61
61
  "@mikro-orm/migrations": "^7.1.14",
62
62
  "@mikro-orm/postgresql": "^7.1.14",
63
- "@open-mercato/events": "0.10.1-develop.7809.1.ea24461aeb",
64
- "@open-mercato/queue": "0.10.1-develop.7809.1.ea24461aeb",
65
- "@open-mercato/shared": "0.10.1-develop.7809.1.ea24461aeb",
66
- "@open-mercato/telemetry": "0.10.1-develop.7809.1.ea24461aeb",
63
+ "@open-mercato/events": "0.10.1-develop.7813.1.83931e7add",
64
+ "@open-mercato/queue": "0.10.1-develop.7813.1.83931e7add",
65
+ "@open-mercato/shared": "0.10.1-develop.7813.1.83931e7add",
66
+ "@open-mercato/telemetry": "0.10.1-develop.7813.1.83931e7add",
67
67
  "cross-spawn": "^7.0.6",
68
68
  "minisearch": "7.2.0",
69
69
  "pg": "8.23.0",
@@ -75,10 +75,10 @@
75
75
  "typescript-js": "npm:typescript@6.0.3"
76
76
  },
77
77
  "peerDependencies": {
78
- "@open-mercato/shared": "0.10.1-develop.7809.1.ea24461aeb"
78
+ "@open-mercato/shared": "0.10.1-develop.7813.1.83931e7add"
79
79
  },
80
80
  "devDependencies": {
81
- "@open-mercato/shared": "0.10.1-develop.7809.1.ea24461aeb",
81
+ "@open-mercato/shared": "0.10.1-develop.7813.1.83931e7add",
82
82
  "@types/jest": "^30.0.0",
83
83
  "jest": "^30.4.2",
84
84
  "ts-jest": "^29.4.12"
@@ -60,10 +60,17 @@ export function addImportSpec(sourceFile: SourceFile, spec: GeneratedImportSpec)
60
60
  })
61
61
  }
62
62
 
63
+ /**
64
+ * Inserts every import in one ts-morph manipulation. Each `addImportDeclaration` call
65
+ * re-prints and re-parses the whole source file, so adding registry imports one by one is
66
+ * quadratic in the import count and dominated `mercato generate` peak memory.
67
+ */
63
68
  export function addImportSpecs(sourceFile: SourceFile, specs: GeneratedImportSpec[]): void {
64
- for (const spec of specs) {
65
- addImportSpec(sourceFile, spec)
66
- }
69
+ if (specs.length === 0) return
70
+ sourceFile.addImportDeclarations(specs.map((spec) => ({
71
+ kind: StructureKind.ImportDeclaration,
72
+ ...spec,
73
+ })))
67
74
  }
68
75
 
69
76
  export function addImportStatement(sourceFile: SourceFile, statement: string): void {
@@ -73,7 +80,10 @@ export function addImportStatement(sourceFile: SourceFile, statement: string): v
73
80
  }
74
81
 
75
82
  export function addImportStatements(sourceFile: SourceFile, statements: string[]): void {
83
+ const specs: GeneratedImportSpec[] = []
76
84
  for (const statement of statements) {
77
- addImportStatement(sourceFile, statement)
85
+ const trimmed = statement.trim()
86
+ if (trimmed) specs.push(toImportSpec(trimmed))
78
87
  }
88
+ addImportSpecs(sourceFile, specs)
79
89
  }
@@ -260,18 +260,16 @@ function writePerEntityFieldFiles(
260
260
  const entDir = path.join(outRoot, entity)
261
261
  fs.mkdirSync(entDir, { recursive: true })
262
262
  const sourceFile = createGeneratedSourceFile(`${entity}/index.ts`)
263
- for (const field of fields) {
264
- sourceFile.addVariableStatement({
265
- declarationKind: VariableDeclarationKind.Const,
266
- isExported: true,
267
- declarations: [
268
- {
269
- name: toVar(field),
270
- initializer: JSON.stringify(field),
271
- },
272
- ],
273
- })
274
- }
263
+ sourceFile.addVariableStatements(fields.map((field) => ({
264
+ declarationKind: VariableDeclarationKind.Const,
265
+ isExported: true,
266
+ declarations: [
267
+ {
268
+ name: toVar(field),
269
+ initializer: JSON.stringify(field),
270
+ },
271
+ ],
272
+ })))
275
273
  writeTrackedFile(path.join(entDir, 'index.ts'), getSourceText(sourceFile), result)
276
274
  }
277
275
 
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { StructureKind, VariableDeclarationKind } from 'ts-morph'
3
+ import { VariableDeclarationKind } from 'ts-morph'
4
4
  import type { PackageResolver } from '../resolver'
5
5
  import { MODULE_CODE_EXTENSIONS } from './scanner'
6
6
  import {
@@ -11,7 +11,7 @@ import {
11
11
  } from '../utils'
12
12
  import {
13
13
  addAutoGeneratedComment,
14
- addImportSpec,
14
+ addImportSpecs,
15
15
  arrayLiteral,
16
16
  createGeneratedSourceFile,
17
17
  getSourceText,
@@ -64,13 +64,10 @@ export async function generateModuleDi(options: ModuleDiOptions): Promise<Genera
64
64
 
65
65
  const sourceFile = createGeneratedSourceFile('di.generated.ts')
66
66
  addAutoGeneratedComment(sourceFile, 'di')
67
- imports.forEach((entry) => {
68
- addImportSpec(sourceFile, {
69
- kind: StructureKind.ImportDeclaration,
70
- namespaceImport: entry.name,
71
- moduleSpecifier: entry.moduleSpecifier,
72
- })
73
- })
67
+ addImportSpecs(sourceFile, imports.map((entry) => ({
68
+ namespaceImport: entry.name,
69
+ moduleSpecifier: entry.moduleSpecifier,
70
+ })))
74
71
  sourceFile.addVariableStatement({
75
72
  declarationKind: VariableDeclarationKind.Const,
76
73
  declarations: [
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs'
2
2
  import path from 'node:path'
3
- import { StructureKind, VariableDeclarationKind } from 'ts-morph'
3
+ import { VariableDeclarationKind } from 'ts-morph'
4
4
  import {
5
5
  findDuplicateEntityClassNames,
6
6
  formatDuplicateEntityClassNamesWarning,
@@ -17,7 +17,7 @@ import {
17
17
  } from '../utils'
18
18
  import {
19
19
  addAutoGeneratedComment,
20
- addImportSpec,
20
+ addImportSpecs,
21
21
  asExpression,
22
22
  arrayLiteral,
23
23
  arrowFunction,
@@ -110,13 +110,10 @@ export async function generateModuleEntities(options: ModuleEntitiesOptions): Pr
110
110
 
111
111
  const sourceFile = createGeneratedSourceFile('entities.generated.ts')
112
112
  addAutoGeneratedComment(sourceFile, 'entities')
113
- imports.forEach((entry) => {
114
- addImportSpec(sourceFile, {
115
- kind: StructureKind.ImportDeclaration,
116
- namespaceImport: entry.name,
117
- moduleSpecifier: entry.moduleSpecifier,
118
- })
119
- })
113
+ addImportSpecs(sourceFile, imports.map((entry) => ({
114
+ namespaceImport: entry.name,
115
+ moduleSpecifier: entry.moduleSpecifier,
116
+ })))
120
117
  sourceFile.addFunction({
121
118
  name: 'enhanceEntities',
122
119
  parameters: [