@open-mercato/cli 0.4.2-canary-eb5f87d5f9 → 0.4.2-canary-5035717565
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/lib/db/commands.js +17 -8
- package/dist/lib/db/commands.js.map +2 -2
- package/dist/lib/generators/entity-ids.js +2 -3
- package/dist/lib/generators/entity-ids.js.map +2 -2
- package/dist/lib/generators/module-di.js +4 -6
- package/dist/lib/generators/module-di.js.map +2 -2
- package/dist/lib/generators/module-entities.js +3 -4
- package/dist/lib/generators/module-entities.js.map +2 -2
- package/dist/lib/generators/module-registry.js +92 -118
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/resolver.js +2 -2
- package/dist/lib/resolver.js.map +2 -2
- package/dist/mercato.js +21 -33
- package/dist/mercato.js.map +2 -2
- package/package.json +2 -2
- package/src/lib/db/commands.ts +19 -12
- package/src/lib/generators/entity-ids.ts +2 -4
- package/src/lib/generators/module-di.ts +4 -7
- package/src/lib/generators/module-entities.ts +3 -4
- package/src/lib/generators/module-registry.ts +99 -135
- package/src/lib/resolver.ts +5 -4
- package/src/mercato.ts +21 -40
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.4.2-canary-
|
|
3
|
+
"version": "0.4.2-canary-5035717565",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"exports": {
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
"@mikro-orm/core": "^6.6.2",
|
|
56
56
|
"@mikro-orm/migrations": "^6.6.2",
|
|
57
57
|
"@mikro-orm/postgresql": "^6.6.2",
|
|
58
|
-
"@open-mercato/shared": "0.4.2-canary-
|
|
58
|
+
"@open-mercato/shared": "0.4.2-canary-5035717565",
|
|
59
59
|
"pg": "^8.16.3",
|
|
60
60
|
"typescript": "^5.9.3"
|
|
61
61
|
},
|
package/src/lib/db/commands.ts
CHANGED
|
@@ -77,8 +77,7 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
|
|
|
77
77
|
path.join(roots.appBase, 'db'),
|
|
78
78
|
path.join(roots.pkgBase, 'db'),
|
|
79
79
|
]
|
|
80
|
-
|
|
81
|
-
const candidates = ['entities.ts', 'entities.js', 'schema.ts', 'schema.js']
|
|
80
|
+
const candidates = ['entities.ts', 'schema.ts']
|
|
82
81
|
|
|
83
82
|
for (const base of bases) {
|
|
84
83
|
for (const f of candidates) {
|
|
@@ -86,12 +85,10 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
|
|
|
86
85
|
if (fs.existsSync(p)) {
|
|
87
86
|
const sub = path.basename(base)
|
|
88
87
|
const fromApp = base.startsWith(roots.appBase)
|
|
89
|
-
const ext = path.extname(f)
|
|
90
|
-
const baseName = f.replace(ext, '')
|
|
91
88
|
// For @app modules, use file:// URL since @/ alias doesn't work in Node.js runtime
|
|
92
89
|
const importPath = (isAppModule && fromApp)
|
|
93
90
|
? `file://${p.replace(/\.ts$/, '.js')}`
|
|
94
|
-
: `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${
|
|
91
|
+
: `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${f.replace(/\.ts$/, '')}`
|
|
95
92
|
try {
|
|
96
93
|
const mod = await import(importPath)
|
|
97
94
|
const entities = Object.values(mod).filter((v) => typeof v === 'function')
|
|
@@ -110,15 +107,25 @@ async function loadModuleEntities(entry: ModuleEntry, resolver: PackageResolver)
|
|
|
110
107
|
|
|
111
108
|
function getMigrationsPath(entry: ModuleEntry, resolver: PackageResolver): string {
|
|
112
109
|
const from = entry.from || '@open-mercato/core'
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
110
|
+
let pkgModRoot: string
|
|
111
|
+
|
|
112
|
+
if (from === '@open-mercato/core') {
|
|
113
|
+
pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
|
|
114
|
+
} else if (/^@open-mercato\//.test(from)) {
|
|
115
|
+
const segs = from.split('/')
|
|
116
|
+
if (segs.length > 1 && segs[1]) {
|
|
117
|
+
pkgModRoot = path.join(resolver.getRootDir(), `packages/${segs[1]}/src/modules`, entry.id)
|
|
118
|
+
} else {
|
|
119
|
+
pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
|
|
120
|
+
}
|
|
121
|
+
} else if (from === '@app') {
|
|
122
|
+
// For @app modules, use the app directory not the monorepo root
|
|
123
|
+
pkgModRoot = path.join(resolver.getAppDir(), 'src/modules', entry.id)
|
|
124
|
+
} else {
|
|
125
|
+
pkgModRoot = path.join(resolver.getRootDir(), 'packages/core/src/modules', entry.id)
|
|
117
126
|
}
|
|
118
127
|
|
|
119
|
-
|
|
120
|
-
const { pkgBase } = resolver.getModulePaths(entry)
|
|
121
|
-
return path.join(pkgBase, 'migrations')
|
|
128
|
+
return path.join(pkgModRoot, 'migrations')
|
|
122
129
|
}
|
|
123
130
|
|
|
124
131
|
export interface DbOptions {
|
|
@@ -179,8 +179,7 @@ export async function generateEntityIds(options: EntityIdsOptions): Promise<Gene
|
|
|
179
179
|
const appDb = path.join(roots.appBase, 'db')
|
|
180
180
|
const pkgDb = path.join(roots.pkgBase, 'db')
|
|
181
181
|
const bases = [appData, pkgData, appDb, pkgDb]
|
|
182
|
-
|
|
183
|
-
const candidates = ['entities.override.ts', 'entities.override.js', 'entities.ts', 'entities.js', 'schema.ts', 'schema.js']
|
|
182
|
+
const candidates = ['entities.override.ts', 'entities.ts', 'schema.ts']
|
|
184
183
|
let importPath: string | null = null
|
|
185
184
|
let filePath: string | null = null
|
|
186
185
|
|
|
@@ -190,8 +189,7 @@ export async function generateEntityIds(options: EntityIdsOptions): Promise<Gene
|
|
|
190
189
|
if (fs.existsSync(p)) {
|
|
191
190
|
const fromApp = base.startsWith(roots.appBase)
|
|
192
191
|
const sub = path.basename(base) // 'data' | 'db'
|
|
193
|
-
|
|
194
|
-
importPath = `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${fileBaseName}`
|
|
192
|
+
importPath = `${fromApp ? imps.appBase : imps.pkgBase}/${sub}/${f.replace(/\.ts$/, '')}`
|
|
195
193
|
filePath = p
|
|
196
194
|
break
|
|
197
195
|
}
|
|
@@ -34,13 +34,10 @@ export async function generateModuleDi(options: ModuleDiOptions): Promise<Genera
|
|
|
34
34
|
const modId = entry.id
|
|
35
35
|
const roots = resolver.getModulePaths(entry)
|
|
36
36
|
const imp = resolver.getModuleImportBase(entry)
|
|
37
|
-
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
const
|
|
41
|
-
const pkgDiJs = path.join(roots.pkgBase, 'di.js')
|
|
42
|
-
const useApp = fs.existsSync(appDiTs) || fs.existsSync(appDiJs)
|
|
43
|
-
const usePkg = fs.existsSync(pkgDiTs) || fs.existsSync(pkgDiJs)
|
|
37
|
+
const appDi = path.join(roots.appBase, 'di.ts')
|
|
38
|
+
const pkgDi = path.join(roots.pkgBase, 'di.ts')
|
|
39
|
+
const useApp = fs.existsSync(appDi)
|
|
40
|
+
const usePkg = fs.existsSync(pkgDi)
|
|
44
41
|
const importName = `D_${toVar(modId)}_${i++}`
|
|
45
42
|
|
|
46
43
|
if (useApp) {
|
|
@@ -41,7 +41,7 @@ export async function generateModuleEntities(options: ModuleEntitiesOptions): Pr
|
|
|
41
41
|
const appDb = path.join(roots.appBase, 'db')
|
|
42
42
|
const pkgDb = path.join(roots.pkgBase, 'db')
|
|
43
43
|
const bases = [appData, pkgData, appDb, pkgDb]
|
|
44
|
-
const candidates = ['entities.override.ts', 'entities.
|
|
44
|
+
const candidates = ['entities.override.ts', 'entities.ts', 'schema.ts']
|
|
45
45
|
|
|
46
46
|
let found: { base: string; file: string } | null = null
|
|
47
47
|
for (const base of bases) {
|
|
@@ -63,13 +63,12 @@ export async function generateModuleEntities(options: ModuleEntitiesOptions): Pr
|
|
|
63
63
|
// For @app modules, use relative path to ensure it works both in Next.js and Node.js CLI context
|
|
64
64
|
// From .mercato/generated/, the relative path to src/modules/ is ../src/modules/
|
|
65
65
|
let relImport: string
|
|
66
|
-
const fileBaseName = found.file.replace(/\.(ts|js)$/, '')
|
|
67
66
|
if (isAppModule && fromApp) {
|
|
68
67
|
// From .mercato/generated/, go up two levels (../..) to reach the app root, then into src/modules/
|
|
69
|
-
relImport = `../../src/modules/${modId}/${sub}/${
|
|
68
|
+
relImport = `../../src/modules/${modId}/${sub}/${found.file.replace(/\.ts$/, '')}`
|
|
70
69
|
} else {
|
|
71
70
|
const baseImport = fromApp ? imp.appBase : imp.pkgBase
|
|
72
|
-
relImport = `${baseImport}/${sub}/${
|
|
71
|
+
relImport = `${baseImport}/${sub}/${found.file.replace(/\.ts$/, '')}`
|
|
73
72
|
}
|
|
74
73
|
imports.push(`import * as ${importName} from '${relImport}'`)
|
|
75
74
|
entitySources.push({ importName, moduleId: modId })
|
|
@@ -15,21 +15,6 @@ import {
|
|
|
15
15
|
|
|
16
16
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
17
17
|
|
|
18
|
-
/**
|
|
19
|
-
* Find a module file, checking for both .ts (src) and .js (dist) extensions.
|
|
20
|
-
* Supports both simple names (e.g., 'cli') and nested paths (e.g., 'data/extensions').
|
|
21
|
-
* Returns the path if found, null otherwise.
|
|
22
|
-
*/
|
|
23
|
-
function findModuleFile(basePath: string, ...segments: string[]): string | null {
|
|
24
|
-
const name = segments.pop()!
|
|
25
|
-
const dir = segments.length ? path.join(basePath, ...segments) : basePath
|
|
26
|
-
const tsPath = path.join(dir, `${name}.ts`)
|
|
27
|
-
if (fs.existsSync(tsPath)) return tsPath
|
|
28
|
-
const jsPath = path.join(dir, `${name}.js`)
|
|
29
|
-
if (fs.existsSync(jsPath)) return jsPath
|
|
30
|
-
return null
|
|
31
|
-
}
|
|
32
|
-
|
|
33
18
|
export interface ModuleRegistryOptions {
|
|
34
19
|
resolver: PackageResolver
|
|
35
20
|
quiet?: boolean
|
|
@@ -94,9 +79,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
94
79
|
let injectionTableImportName: string | null = null
|
|
95
80
|
|
|
96
81
|
// Module metadata: index.ts (overrideable)
|
|
97
|
-
const appIndex =
|
|
98
|
-
const pkgIndex =
|
|
99
|
-
const indexTs = appIndex
|
|
82
|
+
const appIndex = path.join(roots.appBase, 'index.ts')
|
|
83
|
+
const pkgIndex = path.join(roots.pkgBase, 'index.ts')
|
|
84
|
+
const indexTs = fs.existsSync(appIndex) ? appIndex : fs.existsSync(pkgIndex) ? pkgIndex : null
|
|
100
85
|
if (indexTs) {
|
|
101
86
|
infoImportName = `I${importId++}_${toVar(modId)}`
|
|
102
87
|
const importPath = indexTs.startsWith(roots.appBase) ? `${appImportBase}/index` : `${imps.pkgBase}/index`
|
|
@@ -205,10 +190,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
205
190
|
|
|
206
191
|
// Entity extensions: src/modules/<module>/data/extensions.ts
|
|
207
192
|
{
|
|
208
|
-
const appFile =
|
|
209
|
-
const pkgFile =
|
|
210
|
-
const hasApp =
|
|
211
|
-
const hasPkg =
|
|
193
|
+
const appFile = path.join(roots.appBase, 'data', 'extensions.ts')
|
|
194
|
+
const pkgFile = path.join(roots.pkgBase, 'data', 'extensions.ts')
|
|
195
|
+
const hasApp = fs.existsSync(appFile)
|
|
196
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
212
197
|
if (hasApp || hasPkg) {
|
|
213
198
|
const importName = `X_${toVar(modId)}_${importId++}`
|
|
214
199
|
const importPath = hasApp ? `${appImportBase}/data/extensions` : `${imps.pkgBase}/data/extensions`
|
|
@@ -219,12 +204,12 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
219
204
|
|
|
220
205
|
// RBAC feature declarations: module root acl.ts
|
|
221
206
|
{
|
|
222
|
-
const rootApp =
|
|
223
|
-
const rootPkg =
|
|
224
|
-
const hasRoot = rootApp || rootPkg
|
|
207
|
+
const rootApp = path.join(roots.appBase, 'acl.ts')
|
|
208
|
+
const rootPkg = path.join(roots.pkgBase, 'acl.ts')
|
|
209
|
+
const hasRoot = fs.existsSync(rootApp) || fs.existsSync(rootPkg)
|
|
225
210
|
if (hasRoot) {
|
|
226
211
|
const importName = `ACL_${toVar(modId)}_${importId++}`
|
|
227
|
-
const useApp = rootApp
|
|
212
|
+
const useApp = fs.existsSync(rootApp) ? rootApp : rootPkg
|
|
228
213
|
const importPath = useApp.startsWith(roots.appBase) ? `${appImportBase}/acl` : `${imps.pkgBase}/acl`
|
|
229
214
|
imports.push(`import * as ${importName} from '${importPath}'`)
|
|
230
215
|
featuresImportName = importName
|
|
@@ -233,10 +218,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
233
218
|
|
|
234
219
|
// Custom entities declarations: module root ce.ts
|
|
235
220
|
{
|
|
236
|
-
const appFile =
|
|
237
|
-
const pkgFile =
|
|
238
|
-
const hasApp =
|
|
239
|
-
const hasPkg =
|
|
221
|
+
const appFile = path.join(roots.appBase, 'ce.ts')
|
|
222
|
+
const pkgFile = path.join(roots.pkgBase, 'ce.ts')
|
|
223
|
+
const hasApp = fs.existsSync(appFile)
|
|
224
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
240
225
|
if (hasApp || hasPkg) {
|
|
241
226
|
const importName = `CE_${toVar(modId)}_${importId++}`
|
|
242
227
|
const importPath = hasApp ? `${appImportBase}/ce` : `${imps.pkgBase}/ce`
|
|
@@ -247,10 +232,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
247
232
|
|
|
248
233
|
// Search module configuration: module root search.ts
|
|
249
234
|
{
|
|
250
|
-
const appFile =
|
|
251
|
-
const pkgFile =
|
|
252
|
-
const hasApp =
|
|
253
|
-
const hasPkg =
|
|
235
|
+
const appFile = path.join(roots.appBase, 'search.ts')
|
|
236
|
+
const pkgFile = path.join(roots.pkgBase, 'search.ts')
|
|
237
|
+
const hasApp = fs.existsSync(appFile)
|
|
238
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
254
239
|
if (hasApp || hasPkg) {
|
|
255
240
|
const importName = `SEARCH_${toVar(modId)}_${importId++}`
|
|
256
241
|
const importPath = hasApp ? `${appImportBase}/search` : `${imps.pkgBase}/search`
|
|
@@ -263,10 +248,10 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
263
248
|
|
|
264
249
|
// Custom field declarations: src/modules/<module>/data/fields.ts
|
|
265
250
|
{
|
|
266
|
-
const appFile =
|
|
267
|
-
const pkgFile =
|
|
268
|
-
const hasApp =
|
|
269
|
-
const hasPkg =
|
|
251
|
+
const appFile = path.join(roots.appBase, 'data', 'fields.ts')
|
|
252
|
+
const pkgFile = path.join(roots.pkgBase, 'data', 'fields.ts')
|
|
253
|
+
const hasApp = fs.existsSync(appFile)
|
|
254
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
270
255
|
if (hasApp || hasPkg) {
|
|
271
256
|
const importName = `F_${toVar(modId)}_${importId++}`
|
|
272
257
|
const importPath = hasApp ? `${appImportBase}/data/fields` : `${imps.pkgBase}/data/fields`
|
|
@@ -369,21 +354,19 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
369
354
|
const apiApp = path.join(roots.appBase, 'api')
|
|
370
355
|
const apiPkg = path.join(roots.pkgBase, 'api')
|
|
371
356
|
if (fs.existsSync(apiApp) || fs.existsSync(apiPkg)) {
|
|
372
|
-
// route.ts
|
|
357
|
+
// route.ts aggregations
|
|
373
358
|
const routeFiles: string[] = []
|
|
374
359
|
const walk = (dir: string, rel: string[] = []) => {
|
|
375
360
|
for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
376
361
|
if (e.isDirectory()) {
|
|
377
362
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
378
363
|
walk(path.join(dir, e.name), [...rel, e.name])
|
|
379
|
-
} else if (e.isFile() &&
|
|
380
|
-
routeFiles.push([...rel, e.name].join('/'))
|
|
381
|
-
}
|
|
364
|
+
} else if (e.isFile() && e.name === 'route.ts') routeFiles.push([...rel, e.name].join('/'))
|
|
382
365
|
}
|
|
383
366
|
}
|
|
384
367
|
if (fs.existsSync(apiPkg)) walk(apiPkg)
|
|
385
368
|
if (fs.existsSync(apiApp)) walk(apiApp)
|
|
386
|
-
const routeList = Array.from(new Set(routeFiles
|
|
369
|
+
const routeList = Array.from(new Set(routeFiles))
|
|
387
370
|
const isDynamicRoute = (p: string) => p.split('/').some((seg) => /\[|\[\[\.\.\./.test(seg))
|
|
388
371
|
routeList.sort((a, b) => {
|
|
389
372
|
const ad = isDynamicRoute(a) ? 1 : 0
|
|
@@ -393,27 +376,22 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
393
376
|
})
|
|
394
377
|
for (const rel of routeList) {
|
|
395
378
|
const segs = rel.split('/')
|
|
396
|
-
segs.pop()
|
|
379
|
+
segs.pop()
|
|
397
380
|
const reqSegs = [modId, ...segs]
|
|
398
381
|
const importName = `R${importId++}_${toVar(modId)}_${toVar(segs.join('_') || 'index')}`
|
|
399
|
-
const
|
|
400
|
-
const
|
|
401
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
382
|
+
const appFile = path.join(apiApp, ...segs, 'route.ts')
|
|
383
|
+
const fromApp = fs.existsSync(appFile)
|
|
402
384
|
const apiSegPath = segs.join('/')
|
|
403
385
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/api${apiSegPath ? `/${apiSegPath}` : ''}/route`
|
|
404
386
|
const routePath = '/' + reqSegs.filter(Boolean).join('/')
|
|
405
|
-
const
|
|
406
|
-
const pkgFileJs = path.join(apiPkg, ...segs, 'route.js')
|
|
407
|
-
const sourceFile = fromApp
|
|
408
|
-
? (fs.existsSync(appFileTs) ? appFileTs : appFileJs)
|
|
409
|
-
: (fs.existsSync(pkgFileTs) ? pkgFileTs : pkgFileJs)
|
|
387
|
+
const sourceFile = fromApp ? appFile : path.join(apiPkg, ...segs, 'route.ts')
|
|
410
388
|
const hasOpenApi = await moduleHasExport(sourceFile, 'openApi')
|
|
411
389
|
const docsPart = hasOpenApi ? `, docs: ${importName}.openApi` : ''
|
|
412
390
|
imports.push(`import * as ${importName} from '${importPath}'`)
|
|
413
391
|
apis.push(`{ path: '${routePath}', metadata: (${importName} as any).metadata, handlers: ${importName} as any${docsPart} }`)
|
|
414
392
|
}
|
|
415
393
|
|
|
416
|
-
// Single files
|
|
394
|
+
// Single files
|
|
417
395
|
const plainFiles: string[] = []
|
|
418
396
|
const methodNames = new Set(['get', 'post', 'put', 'patch', 'delete'])
|
|
419
397
|
const walkPlain = (dir: string, rel: string[] = []) => {
|
|
@@ -422,32 +400,28 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
422
400
|
if (methodNames.has(e.name.toLowerCase())) continue
|
|
423
401
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
424
402
|
walkPlain(path.join(dir, e.name), [...rel, e.name])
|
|
425
|
-
} else if (e.isFile() &&
|
|
426
|
-
if (/\.(test|spec)\.
|
|
427
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
403
|
+
} else if (e.isFile() && e.name.endsWith('.ts') && e.name !== 'route.ts') {
|
|
404
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
428
405
|
plainFiles.push([...rel, e.name].join('/'))
|
|
429
406
|
}
|
|
430
407
|
}
|
|
431
408
|
}
|
|
432
409
|
if (fs.existsSync(apiPkg)) walkPlain(apiPkg)
|
|
433
410
|
if (fs.existsSync(apiApp)) walkPlain(apiApp)
|
|
434
|
-
const plainList = Array.from(new Set(plainFiles
|
|
411
|
+
const plainList = Array.from(new Set(plainFiles))
|
|
435
412
|
for (const rel of plainList) {
|
|
436
413
|
const segs = rel.split('/')
|
|
437
|
-
const
|
|
414
|
+
const file = segs.pop()!
|
|
415
|
+
const pathWithoutExt = file.replace(/\.ts$/, '')
|
|
438
416
|
const fullSegs = [...segs, pathWithoutExt]
|
|
439
417
|
const routePath = '/' + [modId, ...fullSegs].filter(Boolean).join('/')
|
|
440
418
|
const importName = `R${importId++}_${toVar(modId)}_${toVar(fullSegs.join('_') || 'index')}`
|
|
441
|
-
const
|
|
442
|
-
const
|
|
443
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
419
|
+
const appFile = path.join(apiApp, ...fullSegs) + '.ts'
|
|
420
|
+
const fromApp = fs.existsSync(appFile)
|
|
444
421
|
const plainSegPath = fullSegs.join('/')
|
|
445
422
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/api${plainSegPath ? `/${plainSegPath}` : ''}`
|
|
446
|
-
const
|
|
447
|
-
const
|
|
448
|
-
const sourceFile = fromApp
|
|
449
|
-
? (fs.existsSync(appFileTs) ? appFileTs : appFileJs)
|
|
450
|
-
: (fs.existsSync(pkgFileTs) ? pkgFileTs : pkgFileJs)
|
|
423
|
+
const pkgFile = path.join(apiPkg, ...fullSegs) + '.ts'
|
|
424
|
+
const sourceFile = fromApp ? appFile : pkgFile
|
|
451
425
|
const hasOpenApi = await moduleHasExport(sourceFile, 'openApi')
|
|
452
426
|
const docsPart = hasOpenApi ? `, docs: ${importName}.openApi` : ''
|
|
453
427
|
imports.push(`import * as ${importName} from '${importPath}'`)
|
|
@@ -466,27 +440,25 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
466
440
|
if (e.isDirectory()) {
|
|
467
441
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
468
442
|
walk2(path.join(dir, e.name), [...rel, e.name])
|
|
469
|
-
} else if (e.isFile() &&
|
|
470
|
-
if (/\.(test|spec)\.
|
|
471
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
443
|
+
} else if (e.isFile() && e.name.endsWith('.ts')) {
|
|
444
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
472
445
|
apiFiles.push([...rel, e.name].join('/'))
|
|
473
446
|
}
|
|
474
447
|
}
|
|
475
448
|
}
|
|
476
449
|
walk2(methodDir)
|
|
477
|
-
const methodList = Array.from(new Set(apiFiles
|
|
450
|
+
const methodList = Array.from(new Set(apiFiles))
|
|
478
451
|
for (const rel of methodList) {
|
|
479
452
|
const segs = rel.split('/')
|
|
480
|
-
const
|
|
453
|
+
const file = segs.pop()!
|
|
454
|
+
const pathWithoutExt = file.replace(/\.ts$/, '')
|
|
481
455
|
const fullSegs = [...segs, pathWithoutExt]
|
|
482
456
|
const routePath = '/' + [modId, ...fullSegs].filter(Boolean).join('/')
|
|
483
457
|
const importName = `H${importId++}_${toVar(modId)}_${toVar(method)}_${toVar(fullSegs.join('_'))}`
|
|
484
458
|
const fromApp = methodDir === appMethodDir
|
|
485
459
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/api/${method.toLowerCase()}/${fullSegs.join('/')}`
|
|
486
460
|
const metaName = `RM${importId++}_${toVar(modId)}_${toVar(method)}_${toVar(fullSegs.join('_'))}`
|
|
487
|
-
const
|
|
488
|
-
const sourceFileJs = path.join(methodDir, ...segs, `${pathWithoutExt}.js`)
|
|
489
|
-
const sourceFile = fs.existsSync(sourceFileTs) ? sourceFileTs : sourceFileJs
|
|
461
|
+
const sourceFile = path.join(methodDir, ...segs, file)
|
|
490
462
|
const hasOpenApi = await moduleHasExport(sourceFile, 'openApi')
|
|
491
463
|
const docsPart = hasOpenApi ? `, docs: ${metaName}.openApi` : ''
|
|
492
464
|
imports.push(`import ${importName}, * as ${metaName} from '${importPath}'`)
|
|
@@ -496,9 +468,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
496
468
|
}
|
|
497
469
|
|
|
498
470
|
// CLI
|
|
499
|
-
const cliApp =
|
|
500
|
-
const cliPkg =
|
|
501
|
-
const cliPath = cliApp
|
|
471
|
+
const cliApp = path.join(roots.appBase, 'cli.ts')
|
|
472
|
+
const cliPkg = path.join(roots.pkgBase, 'cli.ts')
|
|
473
|
+
const cliPath = fs.existsSync(cliApp) ? cliApp : fs.existsSync(cliPkg) ? cliPkg : null
|
|
502
474
|
if (cliPath) {
|
|
503
475
|
const importName = `CLI_${toVar(modId)}`
|
|
504
476
|
const importPath = cliPath.startsWith(roots.appBase) ? `${appImportBase}/cli` : `${imps.pkgBase}/cli`
|
|
@@ -538,7 +510,7 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
538
510
|
}
|
|
539
511
|
}
|
|
540
512
|
|
|
541
|
-
// Subscribers: src/modules/<module>/subscribers/*.ts
|
|
513
|
+
// Subscribers: src/modules/<module>/subscribers/*.ts
|
|
542
514
|
const subApp = path.join(roots.appBase, 'subscribers')
|
|
543
515
|
const subPkg = path.join(roots.pkgBase, 'subscribers')
|
|
544
516
|
if (fs.existsSync(subApp) || fs.existsSync(subPkg)) {
|
|
@@ -548,9 +520,8 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
548
520
|
if (e.isDirectory()) {
|
|
549
521
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
550
522
|
walk(path.join(dir, e.name), [...rel, e.name])
|
|
551
|
-
} else if (e.isFile() &&
|
|
552
|
-
if (/\.(test|spec)\.
|
|
553
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
523
|
+
} else if (e.isFile() && e.name.endsWith('.ts')) {
|
|
524
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
554
525
|
found.push([...rel, e.name].join('/'))
|
|
555
526
|
}
|
|
556
527
|
}
|
|
@@ -561,12 +532,11 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
561
532
|
for (const rel of files) {
|
|
562
533
|
const segs = rel.split('/')
|
|
563
534
|
const file = segs.pop()!
|
|
564
|
-
const name = file.replace(/\.
|
|
535
|
+
const name = file.replace(/\.ts$/, '')
|
|
565
536
|
const importName = `Subscriber${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
|
|
566
537
|
const metaName = `SubscriberMeta${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
|
|
567
|
-
const
|
|
568
|
-
const
|
|
569
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
538
|
+
const appFile = path.join(subApp, ...segs, `${name}.ts`)
|
|
539
|
+
const fromApp = fs.existsSync(appFile)
|
|
570
540
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/subscribers/${[...segs, name].join('/')}`
|
|
571
541
|
imports.push(`import ${importName}, * as ${metaName} from '${importPath}'`)
|
|
572
542
|
const sid = [modId, ...segs, name].filter(Boolean).join(':')
|
|
@@ -576,7 +546,7 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
576
546
|
}
|
|
577
547
|
}
|
|
578
548
|
|
|
579
|
-
// Workers: src/modules/<module>/workers/*.ts
|
|
549
|
+
// Workers: src/modules/<module>/workers/*.ts
|
|
580
550
|
// Only includes files that export `metadata` with a `queue` property
|
|
581
551
|
{
|
|
582
552
|
const wrkApp = path.join(roots.appBase, 'workers')
|
|
@@ -588,9 +558,8 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
588
558
|
if (e.isDirectory()) {
|
|
589
559
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
590
560
|
walk(path.join(dir, e.name), [...rel, e.name])
|
|
591
|
-
} else if (e.isFile() &&
|
|
592
|
-
if (/\.(test|spec)\.
|
|
593
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
561
|
+
} else if (e.isFile() && e.name.endsWith('.ts')) {
|
|
562
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
594
563
|
found.push([...rel, e.name].join('/'))
|
|
595
564
|
}
|
|
596
565
|
}
|
|
@@ -601,10 +570,9 @@ export async function generateModuleRegistry(options: ModuleRegistryOptions): Pr
|
|
|
601
570
|
for (const rel of files) {
|
|
602
571
|
const segs = rel.split('/')
|
|
603
572
|
const file = segs.pop()!
|
|
604
|
-
const name = file.replace(/\.
|
|
605
|
-
const
|
|
606
|
-
const
|
|
607
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
573
|
+
const name = file.replace(/\.ts$/, '')
|
|
574
|
+
const appFile = path.join(wrkApp, ...segs, `${name}.ts`)
|
|
575
|
+
const fromApp = fs.existsSync(appFile)
|
|
608
576
|
// Use package import path for checking exports (file path fails due to relative imports)
|
|
609
577
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/workers/${[...segs, name].join('/')}`
|
|
610
578
|
// Only include files that export metadata with a queue property
|
|
@@ -962,9 +930,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
962
930
|
let customFieldSetsExpr: string = '[]'
|
|
963
931
|
|
|
964
932
|
// Module metadata: index.ts (overrideable)
|
|
965
|
-
const appIndex =
|
|
966
|
-
const pkgIndex =
|
|
967
|
-
const indexTs = appIndex
|
|
933
|
+
const appIndex = path.join(roots.appBase, 'index.ts')
|
|
934
|
+
const pkgIndex = path.join(roots.pkgBase, 'index.ts')
|
|
935
|
+
const indexTs = fs.existsSync(appIndex) ? appIndex : fs.existsSync(pkgIndex) ? pkgIndex : null
|
|
968
936
|
if (indexTs) {
|
|
969
937
|
infoImportName = `I${importId++}_${toVar(modId)}`
|
|
970
938
|
const importPath = indexTs.startsWith(roots.appBase) ? `${appImportBase}/index` : `${imps.pkgBase}/index`
|
|
@@ -981,10 +949,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
981
949
|
|
|
982
950
|
// Entity extensions: src/modules/<module>/data/extensions.ts
|
|
983
951
|
{
|
|
984
|
-
const appFile =
|
|
985
|
-
const pkgFile =
|
|
986
|
-
const hasApp =
|
|
987
|
-
const hasPkg =
|
|
952
|
+
const appFile = path.join(roots.appBase, 'data', 'extensions.ts')
|
|
953
|
+
const pkgFile = path.join(roots.pkgBase, 'data', 'extensions.ts')
|
|
954
|
+
const hasApp = fs.existsSync(appFile)
|
|
955
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
988
956
|
if (hasApp || hasPkg) {
|
|
989
957
|
const importName = `X_${toVar(modId)}_${importId++}`
|
|
990
958
|
const importPath = hasApp ? `${appImportBase}/data/extensions` : `${imps.pkgBase}/data/extensions`
|
|
@@ -995,12 +963,12 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
995
963
|
|
|
996
964
|
// RBAC feature declarations: module root acl.ts
|
|
997
965
|
{
|
|
998
|
-
const rootApp =
|
|
999
|
-
const rootPkg =
|
|
1000
|
-
const hasRoot = rootApp || rootPkg
|
|
966
|
+
const rootApp = path.join(roots.appBase, 'acl.ts')
|
|
967
|
+
const rootPkg = path.join(roots.pkgBase, 'acl.ts')
|
|
968
|
+
const hasRoot = fs.existsSync(rootApp) || fs.existsSync(rootPkg)
|
|
1001
969
|
if (hasRoot) {
|
|
1002
970
|
const importName = `ACL_${toVar(modId)}_${importId++}`
|
|
1003
|
-
const useApp = rootApp
|
|
971
|
+
const useApp = fs.existsSync(rootApp) ? rootApp : rootPkg
|
|
1004
972
|
const importPath = useApp.startsWith(roots.appBase) ? `${appImportBase}/acl` : `${imps.pkgBase}/acl`
|
|
1005
973
|
imports.push(`import * as ${importName} from '${importPath}'`)
|
|
1006
974
|
featuresImportName = importName
|
|
@@ -1009,10 +977,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1009
977
|
|
|
1010
978
|
// Custom entities declarations: module root ce.ts
|
|
1011
979
|
{
|
|
1012
|
-
const appFile =
|
|
1013
|
-
const pkgFile =
|
|
1014
|
-
const hasApp =
|
|
1015
|
-
const hasPkg =
|
|
980
|
+
const appFile = path.join(roots.appBase, 'ce.ts')
|
|
981
|
+
const pkgFile = path.join(roots.pkgBase, 'ce.ts')
|
|
982
|
+
const hasApp = fs.existsSync(appFile)
|
|
983
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
1016
984
|
if (hasApp || hasPkg) {
|
|
1017
985
|
const importName = `CE_${toVar(modId)}_${importId++}`
|
|
1018
986
|
const importPath = hasApp ? `${appImportBase}/ce` : `${imps.pkgBase}/ce`
|
|
@@ -1023,10 +991,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1023
991
|
|
|
1024
992
|
// Vector search configuration: module root vector.ts
|
|
1025
993
|
{
|
|
1026
|
-
const appFile =
|
|
1027
|
-
const pkgFile =
|
|
1028
|
-
const hasApp =
|
|
1029
|
-
const hasPkg =
|
|
994
|
+
const appFile = path.join(roots.appBase, 'vector.ts')
|
|
995
|
+
const pkgFile = path.join(roots.pkgBase, 'vector.ts')
|
|
996
|
+
const hasApp = fs.existsSync(appFile)
|
|
997
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
1030
998
|
if (hasApp || hasPkg) {
|
|
1031
999
|
const importName = `VECTOR_${toVar(modId)}_${importId++}`
|
|
1032
1000
|
const importPath = hasApp ? `${appImportBase}/vector` : `${imps.pkgBase}/vector`
|
|
@@ -1037,10 +1005,10 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1037
1005
|
|
|
1038
1006
|
// Custom field declarations: src/modules/<module>/data/fields.ts
|
|
1039
1007
|
{
|
|
1040
|
-
const appFile =
|
|
1041
|
-
const pkgFile =
|
|
1042
|
-
const hasApp =
|
|
1043
|
-
const hasPkg =
|
|
1008
|
+
const appFile = path.join(roots.appBase, 'data', 'fields.ts')
|
|
1009
|
+
const pkgFile = path.join(roots.pkgBase, 'data', 'fields.ts')
|
|
1010
|
+
const hasApp = fs.existsSync(appFile)
|
|
1011
|
+
const hasPkg = fs.existsSync(pkgFile)
|
|
1044
1012
|
if (hasApp || hasPkg) {
|
|
1045
1013
|
const importName = `F_${toVar(modId)}_${importId++}`
|
|
1046
1014
|
const importPath = hasApp ? `${appImportBase}/data/fields` : `${imps.pkgBase}/data/fields`
|
|
@@ -1050,9 +1018,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1050
1018
|
}
|
|
1051
1019
|
|
|
1052
1020
|
// CLI
|
|
1053
|
-
const cliApp =
|
|
1054
|
-
const cliPkg =
|
|
1055
|
-
const cliPath = cliApp
|
|
1021
|
+
const cliApp = path.join(roots.appBase, 'cli.ts')
|
|
1022
|
+
const cliPkg = path.join(roots.pkgBase, 'cli.ts')
|
|
1023
|
+
const cliPath = fs.existsSync(cliApp) ? cliApp : fs.existsSync(cliPkg) ? cliPkg : null
|
|
1056
1024
|
if (cliPath) {
|
|
1057
1025
|
const importName = `CLI_${toVar(modId)}`
|
|
1058
1026
|
const importPath = cliPath.startsWith(roots.appBase) ? `${appImportBase}/cli` : `${imps.pkgBase}/cli`
|
|
@@ -1092,7 +1060,7 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1092
1060
|
}
|
|
1093
1061
|
}
|
|
1094
1062
|
|
|
1095
|
-
// Subscribers: src/modules/<module>/subscribers/*.ts
|
|
1063
|
+
// Subscribers: src/modules/<module>/subscribers/*.ts
|
|
1096
1064
|
const subApp = path.join(roots.appBase, 'subscribers')
|
|
1097
1065
|
const subPkg = path.join(roots.pkgBase, 'subscribers')
|
|
1098
1066
|
if (fs.existsSync(subApp) || fs.existsSync(subPkg)) {
|
|
@@ -1102,9 +1070,8 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1102
1070
|
if (e.isDirectory()) {
|
|
1103
1071
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
1104
1072
|
walk(path.join(dir, e.name), [...rel, e.name])
|
|
1105
|
-
} else if (e.isFile() &&
|
|
1106
|
-
if (/\.(test|spec)\.
|
|
1107
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
1073
|
+
} else if (e.isFile() && e.name.endsWith('.ts')) {
|
|
1074
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
1108
1075
|
found.push([...rel, e.name].join('/'))
|
|
1109
1076
|
}
|
|
1110
1077
|
}
|
|
@@ -1115,12 +1082,11 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1115
1082
|
for (const rel of files) {
|
|
1116
1083
|
const segs = rel.split('/')
|
|
1117
1084
|
const file = segs.pop()!
|
|
1118
|
-
const name = file.replace(/\.
|
|
1085
|
+
const name = file.replace(/\.ts$/, '')
|
|
1119
1086
|
const importName = `Subscriber${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
|
|
1120
1087
|
const metaName = `SubscriberMeta${importId++}_${toVar(modId)}_${toVar([...segs, name].join('_') || 'index')}`
|
|
1121
|
-
const
|
|
1122
|
-
const
|
|
1123
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
1088
|
+
const appFile = path.join(subApp, ...segs, `${name}.ts`)
|
|
1089
|
+
const fromApp = fs.existsSync(appFile)
|
|
1124
1090
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/subscribers/${[...segs, name].join('/')}`
|
|
1125
1091
|
imports.push(`import ${importName}, * as ${metaName} from '${importPath}'`)
|
|
1126
1092
|
const sid = [modId, ...segs, name].filter(Boolean).join(':')
|
|
@@ -1130,7 +1096,7 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1130
1096
|
}
|
|
1131
1097
|
}
|
|
1132
1098
|
|
|
1133
|
-
// Workers: src/modules/<module>/workers/*.ts
|
|
1099
|
+
// Workers: src/modules/<module>/workers/*.ts
|
|
1134
1100
|
// Only includes files that export `metadata` with a `queue` property
|
|
1135
1101
|
{
|
|
1136
1102
|
const wrkApp = path.join(roots.appBase, 'workers')
|
|
@@ -1142,9 +1108,8 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1142
1108
|
if (e.isDirectory()) {
|
|
1143
1109
|
if (e.name === '__tests__' || e.name === '__mocks__') continue
|
|
1144
1110
|
walk(path.join(dir, e.name), [...rel, e.name])
|
|
1145
|
-
} else if (e.isFile() &&
|
|
1146
|
-
if (/\.(test|spec)\.
|
|
1147
|
-
if (e.name.endsWith('.d.ts')) continue
|
|
1111
|
+
} else if (e.isFile() && e.name.endsWith('.ts')) {
|
|
1112
|
+
if (/\.(test|spec)\.ts$/.test(e.name)) continue
|
|
1148
1113
|
found.push([...rel, e.name].join('/'))
|
|
1149
1114
|
}
|
|
1150
1115
|
}
|
|
@@ -1155,10 +1120,9 @@ export async function generateModuleRegistryCli(options: ModuleRegistryOptions):
|
|
|
1155
1120
|
for (const rel of files) {
|
|
1156
1121
|
const segs = rel.split('/')
|
|
1157
1122
|
const file = segs.pop()!
|
|
1158
|
-
const name = file.replace(/\.
|
|
1159
|
-
const
|
|
1160
|
-
const
|
|
1161
|
-
const fromApp = fs.existsSync(appFileTs) || fs.existsSync(appFileJs)
|
|
1123
|
+
const name = file.replace(/\.ts$/, '')
|
|
1124
|
+
const appFile = path.join(wrkApp, ...segs, `${name}.ts`)
|
|
1125
|
+
const fromApp = fs.existsSync(appFile)
|
|
1162
1126
|
// Use package import path for checking exports (file path fails due to relative imports)
|
|
1163
1127
|
const importPath = `${fromApp ? appImportBase : imps.pkgBase}/workers/${[...segs, name].join('/')}`
|
|
1164
1128
|
// Only include files that export metadata with a queue property
|