@open-mercato/cli 0.6.8-develop.6891.1.4dca3f1ad3 → 0.6.8-develop.6892.1.f179677788
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/.turbo/turbo-build.log +3 -3
- package/AGENTS.md +6 -1
- package/dist/agentic/guides/module-facts.json +113 -113
- package/dist/agentic/guides/modules/ai_assistant.md +1 -1
- package/dist/agentic/guides/modules/api_docs.md +1 -1
- package/dist/agentic/guides/modules/api_keys.md +1 -1
- package/dist/agentic/guides/modules/attachments.md +1 -1
- package/dist/agentic/guides/modules/audit_logs.md +1 -1
- package/dist/agentic/guides/modules/auth.md +1 -1
- package/dist/agentic/guides/modules/business_rules.md +1 -1
- package/dist/agentic/guides/modules/catalog.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail.md +1 -1
- package/dist/agentic/guides/modules/channel_imap.md +1 -1
- package/dist/agentic/guides/modules/checkout.md +1 -1
- package/dist/agentic/guides/modules/communication_channels.md +3 -3
- package/dist/agentic/guides/modules/configs.md +1 -1
- package/dist/agentic/guides/modules/content.md +1 -1
- package/dist/agentic/guides/modules/currencies.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts.md +1 -1
- package/dist/agentic/guides/modules/customers.md +1 -1
- package/dist/agentic/guides/modules/dashboards.md +1 -1
- package/dist/agentic/guides/modules/data_sync.md +1 -1
- package/dist/agentic/guides/modules/design_system.md +1 -1
- package/dist/agentic/guides/modules/dictionaries.md +1 -1
- package/dist/agentic/guides/modules/directory.md +1 -1
- package/dist/agentic/guides/modules/entities.md +1 -1
- package/dist/agentic/guides/modules/events.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe.md +1 -1
- package/dist/agentic/guides/modules/generators.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops.md +1 -1
- package/dist/agentic/guides/modules/integrations.md +1 -1
- package/dist/agentic/guides/modules/messages.md +1 -1
- package/dist/agentic/guides/modules/notifications.md +1 -1
- package/dist/agentic/guides/modules/onboarding.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways.md +1 -1
- package/dist/agentic/guides/modules/perspectives.md +1 -1
- package/dist/agentic/guides/modules/planner.md +1 -1
- package/dist/agentic/guides/modules/portal.md +1 -1
- package/dist/agentic/guides/modules/progress.md +1 -1
- package/dist/agentic/guides/modules/query_index.md +1 -1
- package/dist/agentic/guides/modules/record_locks.md +1 -1
- package/dist/agentic/guides/modules/resources.md +1 -1
- package/dist/agentic/guides/modules/sales.md +1 -1
- package/dist/agentic/guides/modules/scheduler.md +1 -1
- package/dist/agentic/guides/modules/search.md +1 -1
- package/dist/agentic/guides/modules/security.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers.md +1 -1
- package/dist/agentic/guides/modules/sso.md +1 -1
- package/dist/agentic/guides/modules/staff.md +1 -1
- package/dist/agentic/guides/modules/storage_s3.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo.md +1 -1
- package/dist/agentic/guides/modules/sync_excel.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays.md +1 -1
- package/dist/agentic/guides/modules/translations.md +1 -1
- package/dist/agentic/guides/modules/webhooks.md +1 -1
- package/dist/agentic/guides/modules/wms.md +1 -1
- package/dist/agentic/guides/modules/workflows.md +1 -1
- package/dist/agentic/guides/upstream/manifest.json +1 -1
- package/dist/bin.js +20 -34
- package/dist/bin.js.map +2 -2
- package/dist/lib/cli-bootstrap-mode.js +32 -0
- package/dist/lib/cli-bootstrap-mode.js.map +7 -0
- package/dist/lib/dev-supervisor-manifest.js +105 -0
- package/dist/lib/dev-supervisor-manifest.js.map +7 -0
- package/dist/lib/generators/entity-ids.js +11 -24
- package/dist/lib/generators/entity-ids.js.map +2 -2
- package/dist/lib/generators/module-di.js +10 -23
- package/dist/lib/generators/module-di.js.map +2 -2
- package/dist/lib/generators/module-entities.js +10 -23
- package/dist/lib/generators/module-entities.js.map +2 -2
- package/dist/lib/generators/module-registry.js +394 -31
- package/dist/lib/generators/module-registry.js.map +2 -2
- package/dist/lib/generators/route-manifest-shards.js +170 -0
- package/dist/lib/generators/route-manifest-shards.js.map +7 -0
- package/dist/lib/queue-worker-supervisor.js.map +2 -2
- package/dist/lib/resolver.js +26 -3
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/utils.js +15 -8
- package/dist/lib/utils.js.map +2 -2
- package/dist/mercato.js +9 -6
- package/dist/mercato.js.map +2 -2
- package/package.json +6 -6
- package/src/__tests__/mercato.test.ts +144 -0
- package/src/bin.ts +28 -42
- package/src/lib/__tests__/cli-bootstrap-mode.test.ts +22 -0
- package/src/lib/__tests__/content-stable-writes.test.ts +74 -0
- package/src/lib/__tests__/dev-supervisor-manifest.test.ts +131 -0
- package/src/lib/__tests__/queue-worker-supervisor.test.ts +33 -0
- package/src/lib/__tests__/resolver.enterprise.test.ts +50 -0
- package/src/lib/cli-bootstrap-mode.ts +31 -0
- package/src/lib/dev-supervisor-manifest.ts +142 -0
- package/src/lib/generators/__tests__/entity-ids.test.ts +32 -0
- package/src/lib/generators/__tests__/module-subset.test.ts +248 -0
- package/src/lib/generators/__tests__/output-snapshots.test.ts +3 -3
- package/src/lib/generators/__tests__/route-manifest-shards.test.ts +62 -0
- package/src/lib/generators/entity-ids.ts +10 -26
- package/src/lib/generators/module-di.ts +9 -25
- package/src/lib/generators/module-entities.ts +9 -25
- package/src/lib/generators/module-registry.ts +432 -29
- package/src/lib/generators/route-manifest-shards.ts +146 -0
- package/src/lib/queue-worker-supervisor.ts +7 -2
- package/src/lib/resolver.ts +31 -3
- package/src/lib/utils.ts +24 -16
- package/src/mercato.ts +15 -6
|
@@ -4,6 +4,12 @@ import { pathToFileURL } from 'node:url'
|
|
|
4
4
|
import { VariableDeclarationKind, type WriterFunction } from 'ts-morph'
|
|
5
5
|
import ts from 'typescript-js'
|
|
6
6
|
import type { ModuleEntry, PackageResolver } from '../resolver'
|
|
7
|
+
import {
|
|
8
|
+
DEV_SUPERVISOR_MANIFEST_FILE,
|
|
9
|
+
DEV_SUPERVISOR_MANIFEST_VERSION,
|
|
10
|
+
type DevSupervisorSchedulerStartStatus,
|
|
11
|
+
type DevSupervisorWorkerDescriptor,
|
|
12
|
+
} from '../dev-supervisor-manifest'
|
|
7
13
|
import {
|
|
8
14
|
calculateStructureChecksum,
|
|
9
15
|
toVar,
|
|
@@ -67,6 +73,12 @@ import {
|
|
|
67
73
|
} from './scanner'
|
|
68
74
|
import { loadGeneratorExtensions } from './extensions'
|
|
69
75
|
import type { ModuleScanContext, StandaloneConfigOptions } from './extension'
|
|
76
|
+
import {
|
|
77
|
+
renderRouteManifestShardOutputs,
|
|
78
|
+
renderRouteMetadataOutput,
|
|
79
|
+
routeManifestShardFilePattern,
|
|
80
|
+
type RouteManifestShardEntry,
|
|
81
|
+
} from './route-manifest-shards'
|
|
70
82
|
|
|
71
83
|
type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE'
|
|
72
84
|
|
|
@@ -128,6 +140,10 @@ type CommandLoaderGenerationEntry = {
|
|
|
128
140
|
ids: string[]
|
|
129
141
|
}
|
|
130
142
|
|
|
143
|
+
type WorkerGenerationEntry = DevSupervisorWorkerDescriptor & {
|
|
144
|
+
importPath: string
|
|
145
|
+
}
|
|
146
|
+
|
|
131
147
|
type RuntimeApiMethodMetadata = {
|
|
132
148
|
requireAuth?: boolean
|
|
133
149
|
requireRoles?: string[]
|
|
@@ -144,6 +160,8 @@ type PageRouteGenerationResult = {
|
|
|
144
160
|
eagerRoutes: string[]
|
|
145
161
|
runtimeRoutes: string[]
|
|
146
162
|
manifestRoutes: string[]
|
|
163
|
+
manifestShardRoutes: RouteManifestShardEntry[]
|
|
164
|
+
metadataRoutes: RouteManifestShardEntry[]
|
|
147
165
|
routePatterns: string[]
|
|
148
166
|
}
|
|
149
167
|
|
|
@@ -173,6 +191,8 @@ type ApiRouteGenerationResult = {
|
|
|
173
191
|
eagerApis: string[]
|
|
174
192
|
runtimeApis: string[]
|
|
175
193
|
manifestApis: string[]
|
|
194
|
+
manifestShardApis: RouteManifestShardEntry[]
|
|
195
|
+
metadataApis: RouteManifestShardEntry[]
|
|
176
196
|
}
|
|
177
197
|
|
|
178
198
|
type SerializablePageMetadata = {
|
|
@@ -1631,12 +1651,16 @@ function discoverTranslations(roots: ModuleRoots): DiscoveredTranslation[] {
|
|
|
1631
1651
|
const locales = new Set<string>()
|
|
1632
1652
|
if (fs.existsSync(i18nCore)) {
|
|
1633
1653
|
for (const entry of fs.readdirSync(i18nCore, { withFileTypes: true })) {
|
|
1634
|
-
if (entry.isFile() &&
|
|
1654
|
+
if (entry.isFile() && /^[a-zA-Z0-9][a-zA-Z0-9_-]*\.json$/.test(entry.name)) {
|
|
1655
|
+
locales.add(entry.name.replace(/\.json$/, ''))
|
|
1656
|
+
}
|
|
1635
1657
|
}
|
|
1636
1658
|
}
|
|
1637
1659
|
if (fs.existsSync(i18nApp)) {
|
|
1638
1660
|
for (const entry of fs.readdirSync(i18nApp, { withFileTypes: true })) {
|
|
1639
|
-
if (entry.isFile() &&
|
|
1661
|
+
if (entry.isFile() && /^[a-zA-Z0-9][a-zA-Z0-9_-]*\.json$/.test(entry.name)) {
|
|
1662
|
+
locales.add(entry.name.replace(/\.json$/, ''))
|
|
1663
|
+
}
|
|
1640
1664
|
}
|
|
1641
1665
|
}
|
|
1642
1666
|
return Array.from(locales, (locale) => ({
|
|
@@ -1748,6 +1772,8 @@ async function processPageFiles(options: {
|
|
|
1748
1772
|
const eagerRoutes: string[] = []
|
|
1749
1773
|
const runtimeRoutes: string[] = []
|
|
1750
1774
|
const manifestRoutes: string[] = []
|
|
1775
|
+
const manifestShardRoutes: RouteManifestShardEntry[] = []
|
|
1776
|
+
const metadataRoutes: RouteManifestShardEntry[] = []
|
|
1751
1777
|
const routePatterns: string[] = []
|
|
1752
1778
|
|
|
1753
1779
|
// Next-style page.* files
|
|
@@ -1819,7 +1845,19 @@ async function processPageFiles(options: {
|
|
|
1819
1845
|
const manifestBaseProps = buildPageRouteManifestSpread(manifestMetaExpr, routePath)
|
|
1820
1846
|
eagerRoutes.push(`{ ${baseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`)
|
|
1821
1847
|
runtimeRoutes.push(`{ ${runtimeBaseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`)
|
|
1822
|
-
|
|
1848
|
+
const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps} }`
|
|
1849
|
+
const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`
|
|
1850
|
+
manifestRoutes.push(manifestDeclaration)
|
|
1851
|
+
manifestShardRoutes.push({
|
|
1852
|
+
path: routePath,
|
|
1853
|
+
declaration: manifestDeclaration,
|
|
1854
|
+
imports: manifestImportStatement ? [manifestImportStatement] : [],
|
|
1855
|
+
})
|
|
1856
|
+
metadataRoutes.push({
|
|
1857
|
+
path: routePath,
|
|
1858
|
+
declaration: metadataDeclaration,
|
|
1859
|
+
imports: manifestImportStatement ? [manifestImportStatement] : [],
|
|
1860
|
+
})
|
|
1823
1861
|
routePatterns.push(routePath)
|
|
1824
1862
|
}
|
|
1825
1863
|
|
|
@@ -1898,7 +1936,19 @@ async function processPageFiles(options: {
|
|
|
1898
1936
|
const manifestBaseProps = buildPageRouteManifestSpread(manifestMetaExpr, routePath)
|
|
1899
1937
|
eagerRoutes.push(`{ ${baseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`)
|
|
1900
1938
|
runtimeRoutes.push(`{ ${runtimeBaseProps}, Component: ${buildLazyRouteComponentExpression(importPath)} }`)
|
|
1901
|
-
|
|
1939
|
+
const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps} }`
|
|
1940
|
+
const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, ${manifestBaseProps}, load: async () => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod.default ?? mod) as any } }`
|
|
1941
|
+
manifestRoutes.push(manifestDeclaration)
|
|
1942
|
+
manifestShardRoutes.push({
|
|
1943
|
+
path: routePath,
|
|
1944
|
+
declaration: manifestDeclaration,
|
|
1945
|
+
imports: manifestImportStatement ? [manifestImportStatement] : [],
|
|
1946
|
+
})
|
|
1947
|
+
metadataRoutes.push({
|
|
1948
|
+
path: routePath,
|
|
1949
|
+
declaration: metadataDeclaration,
|
|
1950
|
+
imports: manifestImportStatement ? [manifestImportStatement] : [],
|
|
1951
|
+
})
|
|
1902
1952
|
routePatterns.push(routePath)
|
|
1903
1953
|
}
|
|
1904
1954
|
|
|
@@ -1906,6 +1956,8 @@ async function processPageFiles(options: {
|
|
|
1906
1956
|
eagerRoutes,
|
|
1907
1957
|
runtimeRoutes,
|
|
1908
1958
|
manifestRoutes,
|
|
1959
|
+
manifestShardRoutes,
|
|
1960
|
+
metadataRoutes,
|
|
1909
1961
|
routePatterns,
|
|
1910
1962
|
}
|
|
1911
1963
|
}
|
|
@@ -1922,12 +1974,14 @@ async function processApiRoutes(options: {
|
|
|
1922
1974
|
const apiApp = path.join(roots.appBase, 'api')
|
|
1923
1975
|
const apiPkg = path.join(roots.pkgBase, 'api')
|
|
1924
1976
|
if (!fs.existsSync(apiApp) && !fs.existsSync(apiPkg)) {
|
|
1925
|
-
return { eagerApis: [], runtimeApis: [], manifestApis: [] }
|
|
1977
|
+
return { eagerApis: [], runtimeApis: [], manifestApis: [], manifestShardApis: [], metadataApis: [] }
|
|
1926
1978
|
}
|
|
1927
1979
|
|
|
1928
1980
|
const eagerApis: string[] = []
|
|
1929
1981
|
const runtimeApis: string[] = []
|
|
1930
1982
|
const manifestApis: string[] = []
|
|
1983
|
+
const manifestShardApis: RouteManifestShardEntry[] = []
|
|
1984
|
+
const metadataApis: RouteManifestShardEntry[] = []
|
|
1931
1985
|
|
|
1932
1986
|
// route.* aggregations
|
|
1933
1987
|
const routeFiles = scanModuleDir(roots, SCAN_CONFIGS.apiRoutes)
|
|
@@ -1958,7 +2012,11 @@ async function processApiRoutes(options: {
|
|
|
1958
2012
|
eagerImports.push(buildImportStatement(`* as ${importName}`, importPath))
|
|
1959
2013
|
eagerApis.push(`{ path: ((${importName} as any).metadata?.path ?? ${toLiteral(routePath)}), metadata: (${importName} as any).metadata, handlers: ${importName} as any${docsPart} }`)
|
|
1960
2014
|
runtimeApis.push(`{ path: ${toLiteral(resolvedPath)}, metadata: ${metadataLiteral}, handlers: { ${exportedMethods.map((method) => `${method}: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod as any).${method}(req, ctx) }`).join(', ')} } }`)
|
|
1961
|
-
|
|
2015
|
+
const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('route-file')}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((method) => toLiteral(method)).join(', ')}] }`
|
|
2016
|
+
const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('route-file')}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((method) => toLiteral(method)).join(', ')}], load: async () => ${buildDynamicImportExpression(importPath)} }`
|
|
2017
|
+
manifestApis.push(manifestDeclaration)
|
|
2018
|
+
manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration })
|
|
2019
|
+
metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration })
|
|
1962
2020
|
}
|
|
1963
2021
|
|
|
1964
2022
|
// Single files (plain scripts, not route.*, not tests, skip method dirs)
|
|
@@ -1990,7 +2048,11 @@ async function processApiRoutes(options: {
|
|
|
1990
2048
|
eagerImports.push(buildImportStatement(`* as ${importName}`, importPath))
|
|
1991
2049
|
eagerApis.push(`{ path: ((${importName} as any).metadata?.path ?? ${toLiteral(routePath)}), metadata: (${importName} as any).metadata, handlers: ${importName} as any${docsPart} }`)
|
|
1992
2050
|
runtimeApis.push(`{ path: ${toLiteral(resolvedPath)}, metadata: ${metadataLiteral}, handlers: { ${exportedMethods.map((entryMethod) => `${entryMethod}: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; return (mod as any).${entryMethod}(req, ctx) }`).join(', ')} } }`)
|
|
1993
|
-
|
|
2051
|
+
const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('route-file')}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((entryMethod) => toLiteral(entryMethod)).join(', ')}] }`
|
|
2052
|
+
const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('route-file')}, path: ${toLiteral(resolvedPath)}, methods: [${exportedMethods.map((entryMethod) => toLiteral(entryMethod)).join(', ')}], load: async () => ${buildDynamicImportExpression(importPath)} }`
|
|
2053
|
+
manifestApis.push(manifestDeclaration)
|
|
2054
|
+
manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration })
|
|
2055
|
+
metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration })
|
|
1994
2056
|
}
|
|
1995
2057
|
|
|
1996
2058
|
// Legacy per-method
|
|
@@ -2032,7 +2094,11 @@ async function processApiRoutes(options: {
|
|
|
2032
2094
|
eagerImports.push(buildImportStatement(`${importName}, * as ${metaName}`, importPath))
|
|
2033
2095
|
eagerApis.push(`{ method: ${toLiteral(method)}, path: (${metaName}.metadata?.path ?? ${toLiteral(routePath)}), handler: ${importName}, metadata: ${metaName}.metadata${docsPart} }`)
|
|
2034
2096
|
runtimeApis.push(`{ method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, handler: async (req: Request, ctx?: any) => { const mod = await ${buildDynamicImportExpression(importPath)}; const handler = ((mod as any).default ?? (mod as any).${method} ?? (mod as any).handler) as any; return handler(req, ctx) }, metadata: ${metadataLiteral} }`)
|
|
2035
|
-
|
|
2097
|
+
const metadataDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('legacy')}, method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, methods: [${toLiteral(method)}] }`
|
|
2098
|
+
const manifestDeclaration = `{ moduleId: ${toLiteral(modId)}, kind: ${toLiteral('legacy')}, method: ${toLiteral(method)}, path: ${toLiteral(resolvedPath)}, methods: [${toLiteral(method)}], load: async () => ${buildDynamicImportExpression(importPath)} }`
|
|
2099
|
+
manifestApis.push(manifestDeclaration)
|
|
2100
|
+
manifestShardApis.push({ path: resolvedPath, declaration: manifestDeclaration })
|
|
2101
|
+
metadataApis.push({ path: resolvedPath, declaration: metadataDeclaration })
|
|
2036
2102
|
}
|
|
2037
2103
|
}
|
|
2038
2104
|
|
|
@@ -2040,6 +2106,8 @@ async function processApiRoutes(options: {
|
|
|
2040
2106
|
eagerApis,
|
|
2041
2107
|
runtimeApis,
|
|
2042
2108
|
manifestApis,
|
|
2109
|
+
manifestShardApis,
|
|
2110
|
+
metadataApis,
|
|
2043
2111
|
}
|
|
2044
2112
|
}
|
|
2045
2113
|
|
|
@@ -2751,6 +2819,24 @@ function processWorkersAst(discovered: DiscoveredWorker[]): WriterFunction[] {
|
|
|
2751
2819
|
return workers
|
|
2752
2820
|
}
|
|
2753
2821
|
|
|
2822
|
+
function collectWorkerGenerationEntries(
|
|
2823
|
+
discovered: DiscoveredWorker[],
|
|
2824
|
+
moduleId: string,
|
|
2825
|
+
): WorkerGenerationEntry[] {
|
|
2826
|
+
const workers: WorkerGenerationEntry[] = []
|
|
2827
|
+
for (const { id, importPath, metadata } of discovered) {
|
|
2828
|
+
if (!metadata.queue) continue
|
|
2829
|
+
workers.push({
|
|
2830
|
+
id: metadata.id ?? id,
|
|
2831
|
+
moduleId,
|
|
2832
|
+
queue: metadata.queue,
|
|
2833
|
+
concurrency: metadata.concurrency ?? 1,
|
|
2834
|
+
importPath,
|
|
2835
|
+
})
|
|
2836
|
+
}
|
|
2837
|
+
return workers
|
|
2838
|
+
}
|
|
2839
|
+
|
|
2754
2840
|
function processTranslationsAst(options: {
|
|
2755
2841
|
discovered: DiscoveredTranslation[]
|
|
2756
2842
|
modId: string
|
|
@@ -2758,8 +2844,9 @@ function processTranslationsAst(options: {
|
|
|
2758
2844
|
pkgImportBase: string
|
|
2759
2845
|
imports: string[]
|
|
2760
2846
|
extraImports?: string[]
|
|
2847
|
+
localeOutputs?: Map<string, { imports: string[]; value: WriterFunction }>
|
|
2761
2848
|
}): GeneratedObjectEntry[] {
|
|
2762
|
-
const { discovered, modId, appImportBase, pkgImportBase, imports, extraImports } = options
|
|
2849
|
+
const { discovered, modId, appImportBase, pkgImportBase, imports, extraImports, localeOutputs } = options
|
|
2763
2850
|
|
|
2764
2851
|
const translations: GeneratedObjectEntry[] = []
|
|
2765
2852
|
|
|
@@ -2768,45 +2855,236 @@ function processTranslationsAst(options: {
|
|
|
2768
2855
|
if (coreHas && appHas) {
|
|
2769
2856
|
const coreName = `T_${toVar(modId)}_${toVar(locale)}_C`
|
|
2770
2857
|
const appName = `T_${toVar(modId)}_${toVar(locale)}_A`
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2858
|
+
const localeImports = [
|
|
2859
|
+
buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`),
|
|
2860
|
+
buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`),
|
|
2861
|
+
]
|
|
2862
|
+
imports.push(...localeImports)
|
|
2863
|
+
extraImports?.push(...localeImports)
|
|
2864
|
+
const value = objectLiteral([
|
|
2865
|
+
{ kind: 'spread', value: asExpression(identifier(coreName), 'unknown as Record<string, string>') },
|
|
2866
|
+
{ kind: 'spread', value: asExpression(identifier(appName), 'unknown as Record<string, string>') },
|
|
2867
|
+
])
|
|
2775
2868
|
translations.push({
|
|
2776
2869
|
name: JSON.stringify(locale),
|
|
2777
|
-
value
|
|
2778
|
-
{ kind: 'spread', value: asExpression(identifier(coreName), 'unknown as Record<string, string>') },
|
|
2779
|
-
{ kind: 'spread', value: asExpression(identifier(appName), 'unknown as Record<string, string>') },
|
|
2780
|
-
]),
|
|
2870
|
+
value,
|
|
2781
2871
|
})
|
|
2872
|
+
localeOutputs?.set(locale, { imports: localeImports, value })
|
|
2782
2873
|
continue
|
|
2783
2874
|
}
|
|
2784
2875
|
|
|
2785
2876
|
if (appHas) {
|
|
2786
2877
|
const appName = `T_${toVar(modId)}_${toVar(locale)}_A`
|
|
2787
|
-
|
|
2788
|
-
|
|
2878
|
+
const localeImports = [buildImportStatement(appName, `${appImportBase}/i18n/${locale}.json`)]
|
|
2879
|
+
imports.push(...localeImports)
|
|
2880
|
+
extraImports?.push(...localeImports)
|
|
2881
|
+
const value = asExpression(identifier(appName), 'unknown as Record<string, string>')
|
|
2789
2882
|
translations.push({
|
|
2790
2883
|
name: JSON.stringify(locale),
|
|
2791
|
-
value
|
|
2884
|
+
value,
|
|
2792
2885
|
})
|
|
2886
|
+
localeOutputs?.set(locale, { imports: localeImports, value })
|
|
2793
2887
|
continue
|
|
2794
2888
|
}
|
|
2795
2889
|
|
|
2796
2890
|
if (coreHas) {
|
|
2797
2891
|
const coreName = `T_${toVar(modId)}_${toVar(locale)}_C`
|
|
2798
|
-
|
|
2799
|
-
|
|
2892
|
+
const localeImports = [buildImportStatement(coreName, `${pkgImportBase}/i18n/${locale}.json`)]
|
|
2893
|
+
imports.push(...localeImports)
|
|
2894
|
+
extraImports?.push(...localeImports)
|
|
2895
|
+
const value = asExpression(identifier(coreName), 'unknown as Record<string, string>')
|
|
2800
2896
|
translations.push({
|
|
2801
2897
|
name: JSON.stringify(locale),
|
|
2802
|
-
value
|
|
2898
|
+
value,
|
|
2803
2899
|
})
|
|
2900
|
+
localeOutputs?.set(locale, { imports: localeImports, value })
|
|
2804
2901
|
}
|
|
2805
2902
|
}
|
|
2806
2903
|
|
|
2807
2904
|
return translations
|
|
2808
2905
|
}
|
|
2809
2906
|
|
|
2907
|
+
function sourceDeclaresCliCommand(filePath: string, commandName: string): boolean {
|
|
2908
|
+
let sourceText: string
|
|
2909
|
+
try {
|
|
2910
|
+
sourceText = fs.readFileSync(filePath, 'utf8')
|
|
2911
|
+
} catch {
|
|
2912
|
+
return false
|
|
2913
|
+
}
|
|
2914
|
+
const sourceFile = ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true)
|
|
2915
|
+
const declarations = new Map<string, ts.Expression>()
|
|
2916
|
+
for (const statement of sourceFile.statements) {
|
|
2917
|
+
if (!ts.isVariableStatement(statement)) continue
|
|
2918
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
2919
|
+
if (ts.isIdentifier(declaration.name) && declaration.initializer) {
|
|
2920
|
+
declarations.set(declaration.name.text, declaration.initializer)
|
|
2921
|
+
}
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
|
|
2925
|
+
const expressionDeclaresCommand = (expression: ts.Expression, seen = new Set<string>()): boolean => {
|
|
2926
|
+
if (ts.isParenthesizedExpression(expression) || ts.isAsExpression(expression) || ts.isSatisfiesExpression(expression)) {
|
|
2927
|
+
return expressionDeclaresCommand(expression.expression, seen)
|
|
2928
|
+
}
|
|
2929
|
+
if (ts.isIdentifier(expression)) {
|
|
2930
|
+
if (seen.has(expression.text)) return false
|
|
2931
|
+
const initializer = declarations.get(expression.text)
|
|
2932
|
+
if (!initializer) return false
|
|
2933
|
+
const nextSeen = new Set(seen)
|
|
2934
|
+
nextSeen.add(expression.text)
|
|
2935
|
+
return expressionDeclaresCommand(initializer, nextSeen)
|
|
2936
|
+
}
|
|
2937
|
+
if (ts.isArrayLiteralExpression(expression)) {
|
|
2938
|
+
return expression.elements.some((element) => (
|
|
2939
|
+
ts.isSpreadElement(element)
|
|
2940
|
+
? expressionDeclaresCommand(element.expression, seen)
|
|
2941
|
+
: expressionDeclaresCommand(element, seen)
|
|
2942
|
+
))
|
|
2943
|
+
}
|
|
2944
|
+
if (!ts.isObjectLiteralExpression(expression)) return false
|
|
2945
|
+
return expression.properties.some((property) => {
|
|
2946
|
+
if (!ts.isPropertyAssignment(property)) return false
|
|
2947
|
+
const propertyName = ts.isIdentifier(property.name) || ts.isStringLiteralLike(property.name)
|
|
2948
|
+
? property.name.text
|
|
2949
|
+
: null
|
|
2950
|
+
return propertyName === 'command'
|
|
2951
|
+
&& (ts.isStringLiteralLike(property.initializer) || ts.isNoSubstitutionTemplateLiteral(property.initializer))
|
|
2952
|
+
&& property.initializer.text === commandName
|
|
2953
|
+
})
|
|
2954
|
+
}
|
|
2955
|
+
|
|
2956
|
+
return sourceFile.statements.some((statement) => (
|
|
2957
|
+
ts.isExportAssignment(statement)
|
|
2958
|
+
&& !statement.isExportEquals
|
|
2959
|
+
&& expressionDeclaresCommand(statement.expression)
|
|
2960
|
+
))
|
|
2961
|
+
}
|
|
2962
|
+
|
|
2963
|
+
function appDeclaresProgrammaticDevSupervisorOverrides(appDir: string): boolean {
|
|
2964
|
+
const srcDir = path.join(appDir, 'src')
|
|
2965
|
+
const pending = [srcDir]
|
|
2966
|
+
while (pending.length > 0) {
|
|
2967
|
+
const current = pending.pop()!
|
|
2968
|
+
let entries: fs.Dirent[]
|
|
2969
|
+
try {
|
|
2970
|
+
entries = fs.readdirSync(current, { withFileTypes: true })
|
|
2971
|
+
} catch {
|
|
2972
|
+
continue
|
|
2973
|
+
}
|
|
2974
|
+
for (const entry of entries) {
|
|
2975
|
+
const entryPath = path.join(current, entry.name)
|
|
2976
|
+
if (entry.isDirectory()) {
|
|
2977
|
+
if (entry.name !== '__tests__' && entry.name !== 'node_modules') pending.push(entryPath)
|
|
2978
|
+
continue
|
|
2979
|
+
}
|
|
2980
|
+
if (!/\.[cm]?tsx?$/.test(entry.name) || /(?:^|\.)test\.[cm]?tsx?$/.test(entry.name)) continue
|
|
2981
|
+
|
|
2982
|
+
let sourceText: string
|
|
2983
|
+
try {
|
|
2984
|
+
sourceText = fs.readFileSync(entryPath, 'utf8')
|
|
2985
|
+
} catch {
|
|
2986
|
+
continue
|
|
2987
|
+
}
|
|
2988
|
+
const sourceFile = ts.createSourceFile(entryPath, sourceText, ts.ScriptTarget.Latest, true)
|
|
2989
|
+
const directImports = new Set<string>()
|
|
2990
|
+
const namespaceImports = new Set<string>()
|
|
2991
|
+
for (const statement of sourceFile.statements) {
|
|
2992
|
+
if (
|
|
2993
|
+
!ts.isImportDeclaration(statement)
|
|
2994
|
+
|| !ts.isStringLiteralLike(statement.moduleSpecifier)
|
|
2995
|
+
|| statement.moduleSpecifier.text !== '@open-mercato/shared/modules/overrides'
|
|
2996
|
+
) continue
|
|
2997
|
+
const bindings = statement.importClause?.namedBindings
|
|
2998
|
+
if (bindings && ts.isNamespaceImport(bindings)) namespaceImports.add(bindings.name.text)
|
|
2999
|
+
if (bindings && ts.isNamedImports(bindings)) {
|
|
3000
|
+
for (const element of bindings.elements) {
|
|
3001
|
+
const importedName = element.propertyName?.text ?? element.name.text
|
|
3002
|
+
if (importedName === 'applyWorkerOverrides' || importedName === 'applyCliOverrides') {
|
|
3003
|
+
directImports.add(element.name.text)
|
|
3004
|
+
}
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
let found = false
|
|
3009
|
+
const visit = (node: ts.Node): void => {
|
|
3010
|
+
if (found) return
|
|
3011
|
+
if (ts.isCallExpression(node)) {
|
|
3012
|
+
if (ts.isIdentifier(node.expression) && directImports.has(node.expression.text)) {
|
|
3013
|
+
found = true
|
|
3014
|
+
return
|
|
3015
|
+
}
|
|
3016
|
+
if (
|
|
3017
|
+
ts.isPropertyAccessExpression(node.expression)
|
|
3018
|
+
&& ts.isIdentifier(node.expression.expression)
|
|
3019
|
+
&& namespaceImports.has(node.expression.expression.text)
|
|
3020
|
+
&& ['applyWorkerOverrides', 'applyCliOverrides'].includes(node.expression.name.text)
|
|
3021
|
+
) {
|
|
3022
|
+
found = true
|
|
3023
|
+
return
|
|
3024
|
+
}
|
|
3025
|
+
}
|
|
3026
|
+
ts.forEachChild(node, visit)
|
|
3027
|
+
}
|
|
3028
|
+
visit(sourceFile)
|
|
3029
|
+
if (found) return true
|
|
3030
|
+
}
|
|
3031
|
+
}
|
|
3032
|
+
return false
|
|
3033
|
+
}
|
|
3034
|
+
|
|
3035
|
+
function renderAstI18nLocaleRegistryFile(options: {
|
|
3036
|
+
fileName: string
|
|
3037
|
+
imports: string[]
|
|
3038
|
+
moduleEntries: WriterFunction[]
|
|
3039
|
+
}): string {
|
|
3040
|
+
const sourceFile = createGeneratedSourceFile(options.fileName)
|
|
3041
|
+
addAutoGeneratedComment(sourceFile, 'registry (locale-specific i18n version)')
|
|
3042
|
+
addImportSpec(sourceFile, {
|
|
3043
|
+
moduleSpecifier: '@open-mercato/shared/modules/registry',
|
|
3044
|
+
namedImports: [{ name: 'Module', isTypeOnly: true }],
|
|
3045
|
+
})
|
|
3046
|
+
addImportStatements(sourceFile, options.imports)
|
|
3047
|
+
sourceFile.addVariableStatement({
|
|
3048
|
+
declarationKind: VariableDeclarationKind.Const,
|
|
3049
|
+
isExported: true,
|
|
3050
|
+
declarations: [{
|
|
3051
|
+
name: 'modules',
|
|
3052
|
+
type: 'Module[]',
|
|
3053
|
+
initializer: arrayLiteral(options.moduleEntries, writeValue),
|
|
3054
|
+
}],
|
|
3055
|
+
})
|
|
3056
|
+
sourceFile.addExportAssignment({
|
|
3057
|
+
isExportEquals: false,
|
|
3058
|
+
expression: 'modules',
|
|
3059
|
+
})
|
|
3060
|
+
return getSourceText(sourceFile)
|
|
3061
|
+
}
|
|
3062
|
+
|
|
3063
|
+
function buildI18nLocaleShardFileName(locale: string): string {
|
|
3064
|
+
const safeLocale = locale.replace(/[^a-zA-Z0-9_-]/g, '_')
|
|
3065
|
+
return `modules.i18n.${safeLocale}.generated.ts`
|
|
3066
|
+
}
|
|
3067
|
+
|
|
3068
|
+
function renderI18nLocaleLoadersFile(locales: string[]): string {
|
|
3069
|
+
const cases = locales.map((locale) => {
|
|
3070
|
+
const moduleSpecifier = `./${buildI18nLocaleShardFileName(locale).replace(/\.ts$/, '')}`
|
|
3071
|
+
return ` case ${JSON.stringify(locale)}:\n return import(${JSON.stringify(moduleSpecifier)}).then((entry) => entry.modules)`
|
|
3072
|
+
}).join('\n')
|
|
3073
|
+
|
|
3074
|
+
return `// AUTO-GENERATED by mercato generate registry (locale-specific i18n loaders)\nimport type { Module } from '@open-mercato/shared/modules/registry'\n\nexport async function loadI18nModules(locale: string): Promise<Module[]> {\n switch (locale) {\n${cases ? `${cases}\n` : ''} default:\n return []\n }\n}\n`
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
function removeStaleI18nLocaleShards(outputDir: string, expectedFileNames: Set<string>): void {
|
|
3078
|
+
if (!fs.existsSync(outputDir)) return
|
|
3079
|
+
for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) {
|
|
3080
|
+
if (!entry.isFile()) continue
|
|
3081
|
+
if (!/^modules\.i18n\..+\.generated\.(?:ts|checksum)$/.test(entry.name)) continue
|
|
3082
|
+
if (entry.name.startsWith('modules.i18n.loaders.generated.')) continue
|
|
3083
|
+
if (expectedFileNames.has(entry.name)) continue
|
|
3084
|
+
fs.unlinkSync(path.join(outputDir, entry.name))
|
|
3085
|
+
}
|
|
3086
|
+
}
|
|
3087
|
+
|
|
2810
3088
|
function resolveConventionFile(
|
|
2811
3089
|
resolved: ResolvedFile | null,
|
|
2812
3090
|
prefix: string,
|
|
@@ -2887,6 +3165,10 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
2887
3165
|
const frontendRouteManifestDecls: string[] = []
|
|
2888
3166
|
const backendRouteManifestDecls: string[] = []
|
|
2889
3167
|
const apiRouteManifestDecls: string[] = []
|
|
3168
|
+
const backendRouteShardEntries: RouteManifestShardEntry[] = []
|
|
3169
|
+
const backendRouteMetadataEntries: RouteManifestShardEntry[] = []
|
|
3170
|
+
const apiRouteShardEntries: RouteManifestShardEntry[] = []
|
|
3171
|
+
const apiRouteMetadataEntries: RouteManifestShardEntry[] = []
|
|
2890
3172
|
// Mutable ref so extracted helper functions can increment the shared counter
|
|
2891
3173
|
const importIdRef = { value: 0 }
|
|
2892
3174
|
const requiresByModule = new Map<string, string[]>()
|
|
@@ -3091,6 +3373,8 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
3091
3373
|
backendRoutes.push(...generatedBackendRoutes.eagerRoutes)
|
|
3092
3374
|
runtimeBackendRoutes.push(...generatedBackendRoutes.runtimeRoutes)
|
|
3093
3375
|
backendRouteManifestDecls.push(...generatedBackendRoutes.manifestRoutes)
|
|
3376
|
+
backendRouteShardEntries.push(...generatedBackendRoutes.manifestShardRoutes)
|
|
3377
|
+
backendRouteMetadataEntries.push(...generatedBackendRoutes.metadataRoutes)
|
|
3094
3378
|
for (const pattern of generatedBackendRoutes.routePatterns) {
|
|
3095
3379
|
assertUniqueBackendRoutePattern(seenBackendRoutePatterns, modId, pattern)
|
|
3096
3380
|
}
|
|
@@ -3111,6 +3395,8 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
3111
3395
|
apis.push(...generatedApis.eagerApis)
|
|
3112
3396
|
runtimeApis.push(...generatedApis.runtimeApis)
|
|
3113
3397
|
apiRouteManifestDecls.push(...generatedApis.manifestApis)
|
|
3398
|
+
apiRouteShardEntries.push(...generatedApis.manifestShardApis)
|
|
3399
|
+
apiRouteMetadataEntries.push(...generatedApis.metadataApis)
|
|
3114
3400
|
}
|
|
3115
3401
|
|
|
3116
3402
|
// 15. CLI
|
|
@@ -3330,6 +3616,12 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
3330
3616
|
exportName: 'apiRoutes',
|
|
3331
3617
|
entries: apiRouteManifestDecls,
|
|
3332
3618
|
})
|
|
3619
|
+
const routeManifestOutputs = [
|
|
3620
|
+
...renderRouteManifestShardOutputs('backend', backendRouteShardEntries),
|
|
3621
|
+
...renderRouteManifestShardOutputs('api', apiRouteShardEntries),
|
|
3622
|
+
renderRouteMetadataOutput('backend', backendRouteMetadataEntries),
|
|
3623
|
+
renderRouteMetadataOutput('api', apiRouteMetadataEntries),
|
|
3624
|
+
]
|
|
3333
3625
|
const legacySubscribersOutput = renderAstLegacyAliasFile({
|
|
3334
3626
|
fileName: 'subscribers.generated.ts',
|
|
3335
3627
|
exportName: 'moduleSubscribers',
|
|
@@ -3377,6 +3669,29 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
3377
3669
|
writeGeneratedFile({ outFile: frontendRoutesOutFile, checksumFile: frontendRoutesChecksumFile, content: frontendRoutesOutput, structureChecksum, result, quiet })
|
|
3378
3670
|
writeGeneratedFile({ outFile: backendRoutesOutFile, checksumFile: backendRoutesChecksumFile, content: backendRoutesOutput, structureChecksum, result, quiet })
|
|
3379
3671
|
writeGeneratedFile({ outFile: apiRoutesOutFile, checksumFile: apiRoutesChecksumFile, content: apiRoutesOutput, structureChecksum, result, quiet })
|
|
3672
|
+
const expectedRouteManifestFiles = new Set(routeManifestOutputs.flatMap(({ fileName }) => [
|
|
3673
|
+
fileName,
|
|
3674
|
+
fileName.replace(/\.ts$/, '.checksum'),
|
|
3675
|
+
]))
|
|
3676
|
+
if (fs.existsSync(outputDir)) {
|
|
3677
|
+
for (const entry of fs.readdirSync(outputDir, { withFileTypes: true })) {
|
|
3678
|
+
if (!entry.isFile() || !routeManifestShardFilePattern.test(entry.name)) continue
|
|
3679
|
+
if (expectedRouteManifestFiles.has(entry.name)) continue
|
|
3680
|
+
const stalePath = path.join(outputDir, entry.name)
|
|
3681
|
+
fs.unlinkSync(stalePath)
|
|
3682
|
+
result.filesWritten.push(stalePath)
|
|
3683
|
+
}
|
|
3684
|
+
}
|
|
3685
|
+
for (const routeOutput of routeManifestOutputs) {
|
|
3686
|
+
writeGeneratedFile({
|
|
3687
|
+
outFile: path.join(outputDir, routeOutput.fileName),
|
|
3688
|
+
checksumFile: path.join(outputDir, routeOutput.fileName.replace(/\.ts$/, '.checksum')),
|
|
3689
|
+
content: routeOutput.content,
|
|
3690
|
+
structureChecksum,
|
|
3691
|
+
result,
|
|
3692
|
+
quiet,
|
|
3693
|
+
})
|
|
3694
|
+
}
|
|
3380
3695
|
writeGeneratedFile({ outFile: legacySubscribersOutFile, checksumFile: legacySubscribersChecksumFile, content: legacySubscribersOutput, structureChecksum, result, quiet })
|
|
3381
3696
|
const commandLoadersOutput = renderCommandLoadersFile(commandLoaderEntries)
|
|
3382
3697
|
writeGeneratedFile({ outFile: commandLoadersOutFile, checksumFile: commandLoadersChecksumFile, content: commandLoadersOutput, structureChecksum, result, quiet })
|
|
@@ -3413,14 +3728,14 @@ async function generateModuleRegistryFromDiscovery(options: ModuleRegistryRender
|
|
|
3413
3728
|
{
|
|
3414
3729
|
const bootstrapPlugins = [...pluginRegistry.values()].filter((p) => p.bootstrapRegistration)
|
|
3415
3730
|
const allEntryImports: string[] = [
|
|
3416
|
-
buildImportStatement(`{
|
|
3731
|
+
buildImportStatement(`{ backendRouteFacades }`, `./backend-route-shards.generated`),
|
|
3417
3732
|
buildImportStatement(`{ frontendRoutes }`, `./frontend-routes.generated`),
|
|
3418
3733
|
]
|
|
3419
3734
|
const allRegImports: string[] = [
|
|
3420
3735
|
`import { registerBackendRouteManifests, registerFrontendRouteManifests } from '@open-mercato/shared/modules/registry'`,
|
|
3421
3736
|
]
|
|
3422
3737
|
const allCalls: string[] = [
|
|
3423
|
-
`registerBackendRouteManifests(
|
|
3738
|
+
`registerBackendRouteManifests(backendRouteFacades)`,
|
|
3424
3739
|
`registerFrontendRouteManifests(frontendRoutes)`,
|
|
3425
3740
|
]
|
|
3426
3741
|
for (const plugin of bootstrapPlugins) {
|
|
@@ -3457,6 +3772,8 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3457
3772
|
const bootstrapChecksumFile = path.join(outputDir, 'modules.bootstrap.generated.checksum')
|
|
3458
3773
|
const i18nOutFile = path.join(outputDir, 'modules.i18n.generated.ts')
|
|
3459
3774
|
const i18nChecksumFile = path.join(outputDir, 'modules.i18n.generated.checksum')
|
|
3775
|
+
const i18nLoadersOutFile = path.join(outputDir, 'modules.i18n.loaders.generated.ts')
|
|
3776
|
+
const i18nLoadersChecksumFile = path.join(outputDir, 'modules.i18n.loaders.generated.checksum')
|
|
3460
3777
|
const legacyOutFile = path.join(outputDir, 'bootstrap-modules.generated.ts')
|
|
3461
3778
|
const legacyChecksumFile = path.join(outputDir, 'bootstrap-modules.generated.checksum')
|
|
3462
3779
|
const enabledIdsOutFile = path.join(outputDir, 'enabled-module-ids.generated.ts')
|
|
@@ -3471,6 +3788,7 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3471
3788
|
const moduleDecls: WriterFunction[] = []
|
|
3472
3789
|
const bootstrapModuleDecls: WriterFunction[] = []
|
|
3473
3790
|
const i18nModuleDecls: WriterFunction[] = []
|
|
3791
|
+
const i18nLocaleShards = new Map<string, { imports: string[]; moduleDecls: WriterFunction[] }>()
|
|
3474
3792
|
const importIdRef = { value: 0 }
|
|
3475
3793
|
const requiresByModule = new Map<string, string[]>()
|
|
3476
3794
|
const commandLoaderEntries: CommandLoaderGenerationEntry[] = []
|
|
@@ -3484,6 +3802,7 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3484
3802
|
const frontendRoutes: WriterFunction[] = []
|
|
3485
3803
|
const backendRoutes: WriterFunction[] = []
|
|
3486
3804
|
const translations: GeneratedObjectEntry[] = []
|
|
3805
|
+
const localeTranslations = new Map<string, { imports: string[]; value: WriterFunction }>()
|
|
3487
3806
|
const subscribers: WriterFunction[] = []
|
|
3488
3807
|
const workers: WriterFunction[] = []
|
|
3489
3808
|
let infoImportName: string | null = null
|
|
@@ -3612,9 +3931,24 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3612
3931
|
pkgImportBase: imps.pkgBase,
|
|
3613
3932
|
imports,
|
|
3614
3933
|
extraImports: translationImports,
|
|
3934
|
+
localeOutputs: localeTranslations,
|
|
3615
3935
|
}))
|
|
3616
|
-
bootstrapImports.push(...translationImports)
|
|
3617
3936
|
i18nImports.push(...translationImports)
|
|
3937
|
+
for (const [locale, localeTranslation] of localeTranslations) {
|
|
3938
|
+
const shard = i18nLocaleShards.get(locale) ?? { imports: [], moduleDecls: [] }
|
|
3939
|
+
shard.imports.push(...localeTranslation.imports)
|
|
3940
|
+
shard.moduleDecls.push(objectLiteral([
|
|
3941
|
+
{ name: 'id', value: modId },
|
|
3942
|
+
{
|
|
3943
|
+
name: 'translations',
|
|
3944
|
+
value: objectLiteral([{
|
|
3945
|
+
name: JSON.stringify(locale),
|
|
3946
|
+
value: localeTranslation.value,
|
|
3947
|
+
}]),
|
|
3948
|
+
},
|
|
3949
|
+
]))
|
|
3950
|
+
i18nLocaleShards.set(locale, shard)
|
|
3951
|
+
}
|
|
3618
3952
|
|
|
3619
3953
|
subscribers.push(...processSubscribersAst(await discovered.getSubscribers()))
|
|
3620
3954
|
|
|
@@ -3730,7 +4064,9 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3730
4064
|
}
|
|
3731
4065
|
|
|
3732
4066
|
moduleDecls.push(objectLiteral(routeAwareModuleEntries))
|
|
3733
|
-
bootstrapModuleDecls.push(objectLiteral(moduleEntries
|
|
4067
|
+
bootstrapModuleDecls.push(objectLiteral(moduleEntries.filter(
|
|
4068
|
+
(entry) => entry.kind === 'spread' || entry.name !== 'translations',
|
|
4069
|
+
)))
|
|
3734
4070
|
i18nModuleDecls.push(objectLiteral(i18nModuleEntries))
|
|
3735
4071
|
}
|
|
3736
4072
|
|
|
@@ -3787,6 +4123,41 @@ async function generateModuleRegistryAppFromDiscovery(options: ModuleRegistryRen
|
|
|
3787
4123
|
writeGeneratedFile({ outFile, checksumFile, content: output, structureChecksum, result, quiet })
|
|
3788
4124
|
writeGeneratedFile({ outFile: bootstrapOutFile, checksumFile: bootstrapChecksumFile, content: bootstrapOutput, structureChecksum, result, quiet })
|
|
3789
4125
|
writeGeneratedFile({ outFile: i18nOutFile, checksumFile: i18nChecksumFile, content: i18nOutput, structureChecksum, result, quiet })
|
|
4126
|
+
const i18nLocales = [...i18nLocaleShards.keys()].sort((a, b) => a.localeCompare(b))
|
|
4127
|
+
const shardFileNames = new Set<string>()
|
|
4128
|
+
const expectedShardArtifacts = new Set<string>()
|
|
4129
|
+
for (const locale of i18nLocales) {
|
|
4130
|
+
const fileName = buildI18nLocaleShardFileName(locale)
|
|
4131
|
+
if (shardFileNames.has(fileName)) {
|
|
4132
|
+
throw new Error(`Locale names produce the same generated i18n shard file: ${locale}`)
|
|
4133
|
+
}
|
|
4134
|
+
shardFileNames.add(fileName)
|
|
4135
|
+
expectedShardArtifacts.add(fileName)
|
|
4136
|
+
expectedShardArtifacts.add(fileName.replace(/\.ts$/, '.checksum'))
|
|
4137
|
+
const shard = i18nLocaleShards.get(locale)!
|
|
4138
|
+
const content = renderAstI18nLocaleRegistryFile({
|
|
4139
|
+
fileName,
|
|
4140
|
+
imports: shard.imports,
|
|
4141
|
+
moduleEntries: shard.moduleDecls,
|
|
4142
|
+
})
|
|
4143
|
+
writeGeneratedFile({
|
|
4144
|
+
outFile: path.join(outputDir, fileName),
|
|
4145
|
+
checksumFile: path.join(outputDir, fileName.replace(/\.ts$/, '.checksum')),
|
|
4146
|
+
content,
|
|
4147
|
+
structureChecksum,
|
|
4148
|
+
result,
|
|
4149
|
+
quiet,
|
|
4150
|
+
})
|
|
4151
|
+
}
|
|
4152
|
+
removeStaleI18nLocaleShards(outputDir, expectedShardArtifacts)
|
|
4153
|
+
writeGeneratedFile({
|
|
4154
|
+
outFile: i18nLoadersOutFile,
|
|
4155
|
+
checksumFile: i18nLoadersChecksumFile,
|
|
4156
|
+
content: renderI18nLocaleLoadersFile(i18nLocales),
|
|
4157
|
+
structureChecksum,
|
|
4158
|
+
result,
|
|
4159
|
+
quiet,
|
|
4160
|
+
})
|
|
3790
4161
|
writeGeneratedFile({ outFile: legacyOutFile, checksumFile: legacyChecksumFile, content: legacyOutput, structureChecksum, result, quiet })
|
|
3791
4162
|
|
|
3792
4163
|
const enabledIdsOutput = renderEnabledModuleIdsFile(enabled.map((entry) => entry.id))
|
|
@@ -3818,6 +4189,8 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
|
|
|
3818
4189
|
const legacyChecksumFile = path.join(outputDir, 'cli-modules.generated.checksum')
|
|
3819
4190
|
const commandLoadersOutFile = path.join(outputDir, 'command-loaders.generated.ts')
|
|
3820
4191
|
const commandLoadersChecksumFile = path.join(outputDir, 'command-loaders.generated.checksum')
|
|
4192
|
+
const devSupervisorOutFile = path.join(outputDir, DEV_SUPERVISOR_MANIFEST_FILE)
|
|
4193
|
+
const devSupervisorChecksumFile = path.join(outputDir, 'dev-supervisor.generated.checksum')
|
|
3821
4194
|
|
|
3822
4195
|
const enabled = discovery.enabled
|
|
3823
4196
|
const imports: string[] = []
|
|
@@ -3826,9 +4199,13 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
|
|
|
3826
4199
|
const importIdRef = { value: 0 }
|
|
3827
4200
|
const requiresByModule = new Map<string, string[]>()
|
|
3828
4201
|
const commandLoaderEntries: CommandLoaderGenerationEntry[] = []
|
|
4202
|
+
const devSupervisorWorkers: DevSupervisorWorkerDescriptor[] = []
|
|
4203
|
+
let schedulerStartStatus: DevSupervisorSchedulerStartStatus = 'missing-module'
|
|
4204
|
+
let requiresFullBootstrap = enabled.some((entry) => entry.devSupervisorRequiresFullBootstrap === true)
|
|
4205
|
+
|| appDeclaresProgrammaticDevSupervisorOverrides(resolver.getAppDir())
|
|
3829
4206
|
|
|
3830
4207
|
for (const discovered of discovery.modules) {
|
|
3831
|
-
const { modId,
|
|
4208
|
+
const { modId, imps, appImportBase } = discovered
|
|
3832
4209
|
commandLoaderEntries.push(...discovered.commandLoaderEntries)
|
|
3833
4210
|
|
|
3834
4211
|
let cliImportName: string | null = null
|
|
@@ -3920,11 +4297,20 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
|
|
|
3920
4297
|
|
|
3921
4298
|
// CLI
|
|
3922
4299
|
{
|
|
4300
|
+
if (modId === 'scheduler') schedulerStartStatus = 'missing-cli'
|
|
3923
4301
|
const cliResolved = discovered.resolve('cli.ts')
|
|
3924
4302
|
if (cliResolved) {
|
|
3925
4303
|
const importName = `CLI_${toVar(modId)}`
|
|
3926
4304
|
imports.push(buildImportStatement(importName, sanitizeGeneratedModuleSpecifier(cliResolved.importPath)))
|
|
3927
4305
|
cliImportName = importName
|
|
4306
|
+
if (modId === 'scheduler') {
|
|
4307
|
+
if (sourceDeclaresCliCommand(cliResolved.absolutePath, 'start')) {
|
|
4308
|
+
schedulerStartStatus = 'ok'
|
|
4309
|
+
} else {
|
|
4310
|
+
schedulerStartStatus = 'missing-command'
|
|
4311
|
+
requiresFullBootstrap = true
|
|
4312
|
+
}
|
|
4313
|
+
}
|
|
3928
4314
|
}
|
|
3929
4315
|
}
|
|
3930
4316
|
|
|
@@ -3941,7 +4327,10 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
|
|
|
3941
4327
|
subscribers.push(...processSubscribersAst(await discovered.getSubscribers()))
|
|
3942
4328
|
|
|
3943
4329
|
// Workers
|
|
3944
|
-
|
|
4330
|
+
const discoveredWorkers = await discovered.getWorkers()
|
|
4331
|
+
const workerGenerationEntries = collectWorkerGenerationEntries(discoveredWorkers, modId)
|
|
4332
|
+
workers.push(...processWorkersAst(discoveredWorkers))
|
|
4333
|
+
devSupervisorWorkers.push(...workerGenerationEntries.map(({ importPath: _importPath, ...worker }) => worker))
|
|
3945
4334
|
|
|
3946
4335
|
// Dashboard widgets
|
|
3947
4336
|
{
|
|
@@ -4106,6 +4495,20 @@ async function generateModuleRegistryCliFromDiscovery(options: ModuleRegistryRen
|
|
|
4106
4495
|
const structureChecksum = discovery.getStructureChecksum()
|
|
4107
4496
|
writeGeneratedFile({ outFile, checksumFile, content: output, structureChecksum, result, quiet })
|
|
4108
4497
|
writeGeneratedFile({ outFile: legacyOutFile, checksumFile: legacyChecksumFile, content: legacyOutput, structureChecksum, result, quiet })
|
|
4498
|
+
const devSupervisorOutput = `${JSON.stringify({
|
|
4499
|
+
version: DEV_SUPERVISOR_MANIFEST_VERSION,
|
|
4500
|
+
workers: devSupervisorWorkers,
|
|
4501
|
+
schedulerStartStatus,
|
|
4502
|
+
requiresFullBootstrap,
|
|
4503
|
+
}, null, 2)}\n`
|
|
4504
|
+
writeGeneratedFile({
|
|
4505
|
+
outFile: devSupervisorOutFile,
|
|
4506
|
+
checksumFile: devSupervisorChecksumFile,
|
|
4507
|
+
content: devSupervisorOutput,
|
|
4508
|
+
structureChecksum,
|
|
4509
|
+
result,
|
|
4510
|
+
quiet,
|
|
4511
|
+
})
|
|
4109
4512
|
const commandLoadersOutput = renderCommandLoadersFile(commandLoaderEntries)
|
|
4110
4513
|
writeGeneratedFile({ outFile: commandLoadersOutFile, checksumFile: commandLoadersChecksumFile, content: commandLoadersOutput, structureChecksum, result, quiet })
|
|
4111
4514
|
|