@open-mercato/cli 0.8.1-develop.7241.1.fad7b2ce2a → 0.8.1-develop.7254.1.ab24f26208
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/agentic/guides/module-facts.json +158 -152
- package/dist/agentic/guides/module-facts.v2.json +158 -152
- package/dist/agentic/guides/modules/agent_orchestrator/index.md +1 -1
- package/dist/agentic/guides/modules/ai_assistant/index.md +1 -1
- package/dist/agentic/guides/modules/api_docs/index.md +1 -1
- package/dist/agentic/guides/modules/api_keys/index.md +1 -1
- package/dist/agentic/guides/modules/attachments/index.md +1 -1
- package/dist/agentic/guides/modules/audit_logs/index.md +1 -1
- package/dist/agentic/guides/modules/auth/di-registrations-rich.md +2 -2
- package/dist/agentic/guides/modules/auth/index.md +1 -1
- package/dist/agentic/guides/modules/availability/index.md +1 -1
- package/dist/agentic/guides/modules/business_rules/index.md +1 -1
- package/dist/agentic/guides/modules/catalog/index.md +1 -1
- package/dist/agentic/guides/modules/channel_apns/index.md +1 -1
- package/dist/agentic/guides/modules/channel_discord/index.md +1 -1
- package/dist/agentic/guides/modules/channel_expo/index.md +1 -1
- package/dist/agentic/guides/modules/channel_fcm/index.md +1 -1
- package/dist/agentic/guides/modules/channel_gmail/index.md +1 -1
- package/dist/agentic/guides/modules/channel_imap/index.md +1 -1
- package/dist/agentic/guides/modules/channel_resend/index.md +1 -1
- package/dist/agentic/guides/modules/channel_ses/index.md +1 -1
- package/dist/agentic/guides/modules/checkout/index.md +1 -1
- package/dist/agentic/guides/modules/communication_channels/index.md +1 -1
- package/dist/agentic/guides/modules/configs/index.md +1 -1
- package/dist/agentic/guides/modules/content/index.md +1 -1
- package/dist/agentic/guides/modules/currencies/index.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/di-registrations-rich.md +1 -1
- package/dist/agentic/guides/modules/customer_accounts/index.md +1 -1
- package/dist/agentic/guides/modules/customers/index.md +1 -1
- package/dist/agentic/guides/modules/dashboards/index.md +1 -1
- package/dist/agentic/guides/modules/data_sync/index.md +1 -1
- package/dist/agentic/guides/modules/design_system/index.md +1 -1
- package/dist/agentic/guides/modules/devices/index.md +1 -1
- package/dist/agentic/guides/modules/dictionaries/index.md +1 -1
- package/dist/agentic/guides/modules/directory/index.md +1 -1
- package/dist/agentic/guides/modules/documents/index.md +1 -1
- package/dist/agentic/guides/modules/entities/index.md +1 -1
- package/dist/agentic/guides/modules/eudr/index.md +1 -1
- package/dist/agentic/guides/modules/events/index.md +1 -1
- package/dist/agentic/guides/modules/feature_toggles/index.md +1 -1
- package/dist/agentic/guides/modules/gateway_stripe/index.md +1 -1
- package/dist/agentic/guides/modules/generators/index.md +1 -1
- package/dist/agentic/guides/modules/inbox_ops/index.md +1 -1
- package/dist/agentic/guides/modules/integrations/index.md +1 -1
- package/dist/agentic/guides/modules/messages/index.md +1 -1
- package/dist/agentic/guides/modules/notifications/index.md +1 -1
- package/dist/agentic/guides/modules/onboarding/index.md +1 -1
- package/dist/agentic/guides/modules/payment_gateways/index.md +1 -1
- package/dist/agentic/guides/modules/perspectives/index.md +1 -1
- package/dist/agentic/guides/modules/phone_calls/index.md +1 -1
- package/dist/agentic/guides/modules/planner/index.md +1 -1
- package/dist/agentic/guides/modules/portal/index.md +1 -1
- package/dist/agentic/guides/modules/progress/index.md +1 -1
- package/dist/agentic/guides/modules/push_notifications/index.md +1 -1
- package/dist/agentic/guides/modules/query_index/index.md +1 -1
- package/dist/agentic/guides/modules/record_locks/di-registrations-rich.md +3 -3
- package/dist/agentic/guides/modules/record_locks/di-service-tokens.md +2 -2
- package/dist/agentic/guides/modules/record_locks/exact-override-targets.md +2 -2
- package/dist/agentic/guides/modules/record_locks/index.md +1 -1
- package/dist/agentic/guides/modules/resources/index.md +1 -1
- package/dist/agentic/guides/modules/sales/index.md +1 -1
- package/dist/agentic/guides/modules/scheduler/index.md +1 -1
- package/dist/agentic/guides/modules/search/index.md +1 -1
- package/dist/agentic/guides/modules/security/index.md +1 -1
- package/dist/agentic/guides/modules/seeds/index.md +1 -1
- package/dist/agentic/guides/modules/shipping_carriers/index.md +1 -1
- package/dist/agentic/guides/modules/sso/index.md +1 -1
- package/dist/agentic/guides/modules/staff/index.md +1 -1
- package/dist/agentic/guides/modules/storage_s3/index.md +1 -1
- package/dist/agentic/guides/modules/sync_akeneo/index.md +1 -1
- package/dist/agentic/guides/modules/sync_excel/index.md +1 -1
- package/dist/agentic/guides/modules/system_status_overlays/index.md +1 -1
- package/dist/agentic/guides/modules/tillio/index.md +1 -1
- package/dist/agentic/guides/modules/translations/index.md +1 -1
- package/dist/agentic/guides/modules/warranty_claims/index.md +1 -1
- package/dist/agentic/guides/modules/webhooks/index.md +1 -1
- package/dist/agentic/guides/modules/wms/index.md +1 -1
- package/dist/agentic/guides/modules/workflows/index.md +1 -1
- package/dist/agentic/guides/reference-module-facts.json +1 -1
- package/dist/agentic/guides/upstream/manifest.json +1 -1
- package/dist/lib/generate-watch-events.js +19 -1
- package/dist/lib/generate-watch-events.js.map +2 -2
- package/dist/lib/generators/module-package-sources.js +17 -4
- package/dist/lib/generators/module-package-sources.js.map +2 -2
- package/dist/mercato.js +11 -16
- package/dist/mercato.js.map +2 -2
- package/package.json +6 -6
- package/src/lib/__tests__/generate-watch-events.test.ts +137 -0
- package/src/lib/generate-watch-events.ts +31 -0
- package/src/lib/generators/__tests__/module-package-sources.test.ts +89 -6
- package/src/lib/generators/module-package-sources.ts +17 -5
- package/src/mercato.ts +16 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/cli",
|
|
3
|
-
"version": "0.8.1-develop.
|
|
3
|
+
"version": "0.8.1-develop.7254.1.ab24f26208",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -60,9 +60,9 @@
|
|
|
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/queue": "0.8.1-develop.
|
|
64
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
65
|
-
"@open-mercato/telemetry": "0.8.1-develop.
|
|
63
|
+
"@open-mercato/queue": "0.8.1-develop.7254.1.ab24f26208",
|
|
64
|
+
"@open-mercato/shared": "0.8.1-develop.7254.1.ab24f26208",
|
|
65
|
+
"@open-mercato/telemetry": "0.8.1-develop.7254.1.ab24f26208",
|
|
66
66
|
"cross-spawn": "^7.0.6",
|
|
67
67
|
"pg": "8.23.0",
|
|
68
68
|
"semver": "^7.8.5",
|
|
@@ -73,10 +73,10 @@
|
|
|
73
73
|
"typescript-js": "npm:typescript@6.0.3"
|
|
74
74
|
},
|
|
75
75
|
"peerDependencies": {
|
|
76
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
76
|
+
"@open-mercato/shared": "0.8.1-develop.7254.1.ab24f26208"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
|
-
"@open-mercato/shared": "0.8.1-develop.
|
|
79
|
+
"@open-mercato/shared": "0.8.1-develop.7254.1.ab24f26208",
|
|
80
80
|
"@types/jest": "^30.0.0",
|
|
81
81
|
"jest": "^30.4.2",
|
|
82
82
|
"ts-jest": "^29.4.12"
|
|
@@ -3,6 +3,7 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import {
|
|
5
5
|
createGenerateWatchChangeSignal,
|
|
6
|
+
resolveGenerateWatchTargets,
|
|
6
7
|
type GenerateWatchTarget,
|
|
7
8
|
} from '../generate-watch-events'
|
|
8
9
|
|
|
@@ -40,6 +41,142 @@ function createWatchHarness(initialTargets: GenerateWatchTarget[]) {
|
|
|
40
41
|
}
|
|
41
42
|
|
|
42
43
|
describe('createGenerateWatchChangeSignal', () => {
|
|
44
|
+
it('keeps app-module watches idle without inventing a node_modules/@app target', async () => {
|
|
45
|
+
const projectRoot = path.resolve('/virtual/standalone-app')
|
|
46
|
+
const modulesFile = path.join(projectRoot, 'src', 'modules.ts')
|
|
47
|
+
const appBase = path.join(projectRoot, 'src', 'modules', 'custom_module')
|
|
48
|
+
const impossiblePackageBase = path.join(
|
|
49
|
+
projectRoot,
|
|
50
|
+
'node_modules',
|
|
51
|
+
'@app',
|
|
52
|
+
'src',
|
|
53
|
+
'modules',
|
|
54
|
+
'custom_module',
|
|
55
|
+
)
|
|
56
|
+
const resolveSourceMirrorBase = jest.fn(() => null)
|
|
57
|
+
const targets = resolveGenerateWatchTargets({
|
|
58
|
+
modulesFile,
|
|
59
|
+
moduleRoots: [{
|
|
60
|
+
appBase,
|
|
61
|
+
pkgBase: impossiblePackageBase,
|
|
62
|
+
watchPackageBase: false,
|
|
63
|
+
}],
|
|
64
|
+
resolveSourceMirrorBase,
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
expect(targets).toEqual([
|
|
68
|
+
{
|
|
69
|
+
directory: path.dirname(modulesFile),
|
|
70
|
+
recursive: false,
|
|
71
|
+
fileName: path.basename(modulesFile),
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
directory: path.dirname(appBase),
|
|
75
|
+
recursive: true,
|
|
76
|
+
},
|
|
77
|
+
])
|
|
78
|
+
expect(resolveSourceMirrorBase).not.toHaveBeenCalled()
|
|
79
|
+
|
|
80
|
+
const signal = createGenerateWatchChangeSignal({
|
|
81
|
+
getWatchTargets: () => targets,
|
|
82
|
+
directoryExists: () => true,
|
|
83
|
+
watchDirectory: () => ({ close: jest.fn() }),
|
|
84
|
+
})
|
|
85
|
+
await signal.refresh()
|
|
86
|
+
expect(signal.hasSkippedTargets?.()).toBe(false)
|
|
87
|
+
await signal.close()
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('retains the real package fallback target for app modules in monorepo mode', () => {
|
|
91
|
+
const projectRoot = path.resolve('/virtual/monorepo')
|
|
92
|
+
const modulesFile = path.join(projectRoot, 'apps', 'mercato', 'src', 'modules.ts')
|
|
93
|
+
const appBase = path.join(
|
|
94
|
+
projectRoot,
|
|
95
|
+
'apps',
|
|
96
|
+
'mercato',
|
|
97
|
+
'src',
|
|
98
|
+
'modules',
|
|
99
|
+
'custom_module',
|
|
100
|
+
)
|
|
101
|
+
const packageBase = path.join(
|
|
102
|
+
projectRoot,
|
|
103
|
+
'packages',
|
|
104
|
+
'core',
|
|
105
|
+
'src',
|
|
106
|
+
'modules',
|
|
107
|
+
'custom_module',
|
|
108
|
+
)
|
|
109
|
+
const resolveSourceMirrorBase = jest.fn(() => null)
|
|
110
|
+
|
|
111
|
+
const targets = resolveGenerateWatchTargets({
|
|
112
|
+
modulesFile,
|
|
113
|
+
moduleRoots: [{
|
|
114
|
+
appBase,
|
|
115
|
+
pkgBase: packageBase,
|
|
116
|
+
watchPackageBase: true,
|
|
117
|
+
}],
|
|
118
|
+
resolveSourceMirrorBase,
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
expect(targets).toContainEqual({
|
|
122
|
+
directory: path.dirname(appBase),
|
|
123
|
+
recursive: true,
|
|
124
|
+
})
|
|
125
|
+
expect(targets).toContainEqual({
|
|
126
|
+
directory: path.dirname(packageBase),
|
|
127
|
+
recursive: true,
|
|
128
|
+
})
|
|
129
|
+
expect(resolveSourceMirrorBase).toHaveBeenCalledWith(packageBase)
|
|
130
|
+
})
|
|
131
|
+
|
|
132
|
+
it('retains missing package-module targets so idle refresh discovers them later', async () => {
|
|
133
|
+
const projectRoot = path.resolve('/virtual/standalone-app')
|
|
134
|
+
const modulesFile = path.join(projectRoot, 'src', 'modules.ts')
|
|
135
|
+
const appBase = path.join(projectRoot, 'src', 'modules', 'official_module')
|
|
136
|
+
const packageBase = path.join(
|
|
137
|
+
projectRoot,
|
|
138
|
+
'node_modules',
|
|
139
|
+
'@open-mercato',
|
|
140
|
+
'official-package',
|
|
141
|
+
'dist',
|
|
142
|
+
'modules',
|
|
143
|
+
'official_module',
|
|
144
|
+
)
|
|
145
|
+
const packageModulesDir = path.dirname(packageBase)
|
|
146
|
+
const targets = resolveGenerateWatchTargets({
|
|
147
|
+
modulesFile,
|
|
148
|
+
moduleRoots: [{
|
|
149
|
+
appBase,
|
|
150
|
+
pkgBase: packageBase,
|
|
151
|
+
watchPackageBase: true,
|
|
152
|
+
}],
|
|
153
|
+
resolveSourceMirrorBase: () => null,
|
|
154
|
+
})
|
|
155
|
+
const existing = new Set([
|
|
156
|
+
path.dirname(modulesFile),
|
|
157
|
+
path.dirname(appBase),
|
|
158
|
+
])
|
|
159
|
+
const registered: string[] = []
|
|
160
|
+
const signal = createGenerateWatchChangeSignal({
|
|
161
|
+
getWatchTargets: () => targets,
|
|
162
|
+
directoryExists: (directory) => existing.has(directory),
|
|
163
|
+
watchDirectory: (target) => {
|
|
164
|
+
registered.push(target.directory)
|
|
165
|
+
return { close: jest.fn() }
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
|
|
169
|
+
await signal.refresh()
|
|
170
|
+
expect(signal.hasSkippedTargets?.()).toBe(true)
|
|
171
|
+
expect(registered).not.toContain(packageModulesDir)
|
|
172
|
+
|
|
173
|
+
existing.add(packageModulesDir)
|
|
174
|
+
await signal.refresh()
|
|
175
|
+
expect(signal.hasSkippedTargets?.()).toBe(false)
|
|
176
|
+
expect(registered).toContain(packageModulesDir)
|
|
177
|
+
await signal.close()
|
|
178
|
+
})
|
|
179
|
+
|
|
43
180
|
it('skips missing directories without falling back and retries them on refresh', async () => {
|
|
44
181
|
const present = path.resolve('./modules-present')
|
|
45
182
|
const delayed = path.resolve('./modules-delayed')
|
|
@@ -25,6 +25,37 @@ export type GenerateWatchChangeSignalOptions = {
|
|
|
25
25
|
onSkippedDirectory?: (directory: string) => void
|
|
26
26
|
}
|
|
27
27
|
|
|
28
|
+
export type GenerateWatchModuleTarget = {
|
|
29
|
+
appBase: string
|
|
30
|
+
pkgBase: string
|
|
31
|
+
watchPackageBase: boolean
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function resolveGenerateWatchTargets(options: {
|
|
35
|
+
modulesFile: string
|
|
36
|
+
moduleRoots: GenerateWatchModuleTarget[]
|
|
37
|
+
resolveSourceMirrorBase: (packageBase: string) => string | null
|
|
38
|
+
}): GenerateWatchTarget[] {
|
|
39
|
+
const targets: GenerateWatchTarget[] = [{
|
|
40
|
+
directory: path.dirname(options.modulesFile),
|
|
41
|
+
recursive: false,
|
|
42
|
+
fileName: path.basename(options.modulesFile),
|
|
43
|
+
}]
|
|
44
|
+
|
|
45
|
+
for (const roots of options.moduleRoots) {
|
|
46
|
+
targets.push({ directory: path.dirname(roots.appBase), recursive: true })
|
|
47
|
+
if (!roots.watchPackageBase) continue
|
|
48
|
+
|
|
49
|
+
targets.push({ directory: path.dirname(roots.pkgBase), recursive: true })
|
|
50
|
+
const sourceMirror = options.resolveSourceMirrorBase(roots.pkgBase)
|
|
51
|
+
if (sourceMirror) {
|
|
52
|
+
targets.push({ directory: path.dirname(sourceMirror), recursive: true })
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return targets
|
|
57
|
+
}
|
|
58
|
+
|
|
28
59
|
function targetKey(target: GenerateWatchTarget): string {
|
|
29
60
|
return JSON.stringify([
|
|
30
61
|
path.resolve(target.directory),
|
|
@@ -3,6 +3,7 @@ import os from 'node:os'
|
|
|
3
3
|
import path from 'node:path'
|
|
4
4
|
import { generateModulePackageSources } from '../module-package-sources'
|
|
5
5
|
import type { PackageResolver } from '../../resolver'
|
|
6
|
+
import { readChecksumRecord } from '../../utils'
|
|
6
7
|
|
|
7
8
|
const fixturePackageRoot = path.resolve(
|
|
8
9
|
__dirname,
|
|
@@ -25,7 +26,7 @@ function copyDir(src: string, dest: string): void {
|
|
|
25
26
|
}
|
|
26
27
|
}
|
|
27
28
|
|
|
28
|
-
function createResolver(tmpDir: string, packageRoot: string, from: string): PackageResolver {
|
|
29
|
+
function createResolver(tmpDir: string, packageRoot: string, from: string, moduleId = 'test_package'): PackageResolver {
|
|
29
30
|
const appDir = path.join(tmpDir, 'app')
|
|
30
31
|
const outputDir = path.join(appDir, '.mercato', 'generated')
|
|
31
32
|
fs.mkdirSync(outputDir, { recursive: true })
|
|
@@ -37,14 +38,14 @@ function createResolver(tmpDir: string, packageRoot: string, from: string): Pack
|
|
|
37
38
|
getOutputDir: () => outputDir,
|
|
38
39
|
getModulesConfigPath: () => path.join(appDir, 'src', 'modules.ts'),
|
|
39
40
|
discoverPackages: () => [],
|
|
40
|
-
loadEnabledModules: () => [{ id:
|
|
41
|
+
loadEnabledModules: () => [{ id: moduleId, from }],
|
|
41
42
|
getModulePaths: () => ({
|
|
42
|
-
appBase: path.join(appDir, 'src', 'modules',
|
|
43
|
-
pkgBase: path.join(packageRoot, 'src', 'modules',
|
|
43
|
+
appBase: path.join(appDir, 'src', 'modules', moduleId),
|
|
44
|
+
pkgBase: path.join(packageRoot, 'src', 'modules', moduleId),
|
|
44
45
|
}),
|
|
45
46
|
getModuleImportBase: () => ({
|
|
46
|
-
appBase:
|
|
47
|
-
pkgBase: `${from}/modules
|
|
47
|
+
appBase: `@/modules/${moduleId}`,
|
|
48
|
+
pkgBase: `${from}/modules/${moduleId}`,
|
|
48
49
|
}),
|
|
49
50
|
getPackageOutputDir: () => outputDir,
|
|
50
51
|
getPackageRoot: () => packageRoot,
|
|
@@ -75,6 +76,88 @@ describe('generateModulePackageSources', () => {
|
|
|
75
76
|
expect(output).toContain('node_modules/@open-mercato/test-package/src/**/*.{ts,tsx}')
|
|
76
77
|
})
|
|
77
78
|
|
|
79
|
+
it('does not checksum unrelated files below the installed package root', async () => {
|
|
80
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@open-mercato', 'test-package')
|
|
81
|
+
copyDir(fixturePackageRoot, packageRoot)
|
|
82
|
+
const resolver = createResolver(tmpDir, packageRoot, '@open-mercato/test-package')
|
|
83
|
+
const outFile = path.join(resolver.getOutputDir(), 'module-package-sources.css')
|
|
84
|
+
const checksumFile = path.join(resolver.getOutputDir(), 'module-package-sources.checksum')
|
|
85
|
+
|
|
86
|
+
await generateModulePackageSources({ resolver, quiet: true })
|
|
87
|
+
const outputBefore = fs.readFileSync(outFile, 'utf8')
|
|
88
|
+
const checksumBefore = readChecksumRecord(checksumFile)
|
|
89
|
+
const pinnedTime = new Date(Date.now() - 60_000)
|
|
90
|
+
fs.utimesSync(outFile, pinnedTime, pinnedTime)
|
|
91
|
+
fs.utimesSync(checksumFile, pinnedTime, pinnedTime)
|
|
92
|
+
|
|
93
|
+
fs.writeFileSync(path.join(packageRoot, 'src', 'unrelated-runtime.ts'), 'export const unrelated = true\n')
|
|
94
|
+
const result = await generateModulePackageSources({ resolver, quiet: true })
|
|
95
|
+
|
|
96
|
+
expect(result.filesWritten).toEqual([])
|
|
97
|
+
expect(result.filesUnchanged).toEqual([outFile])
|
|
98
|
+
expect(fs.readFileSync(outFile, 'utf8')).toBe(outputBefore)
|
|
99
|
+
expect(fs.statSync(outFile).mtimeMs).toBe(pinnedTime.getTime())
|
|
100
|
+
expect(fs.statSync(checksumFile).mtimeMs).toBe(pinnedTime.getTime())
|
|
101
|
+
expect(readChecksumRecord(checksumFile)).toEqual(checksumBefore)
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
it('tracks enabled module and package manifest inputs without touching byte-identical output', async () => {
|
|
105
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@open-mercato', 'test-package')
|
|
106
|
+
copyDir(fixturePackageRoot, packageRoot)
|
|
107
|
+
copyDir(
|
|
108
|
+
path.join(packageRoot, 'src', 'modules', 'test_package'),
|
|
109
|
+
path.join(packageRoot, 'src', 'modules', 'alternate_module'),
|
|
110
|
+
)
|
|
111
|
+
copyDir(
|
|
112
|
+
path.join(packageRoot, 'dist', 'modules', 'test_package'),
|
|
113
|
+
path.join(packageRoot, 'dist', 'modules', 'alternate_module'),
|
|
114
|
+
)
|
|
115
|
+
const packageName = '@open-mercato/test-package'
|
|
116
|
+
const initialResolver = createResolver(tmpDir, packageRoot, packageName)
|
|
117
|
+
const alternateResolver = createResolver(tmpDir, packageRoot, packageName, 'alternate_module')
|
|
118
|
+
const outFile = path.join(initialResolver.getOutputDir(), 'module-package-sources.css')
|
|
119
|
+
const checksumFile = path.join(initialResolver.getOutputDir(), 'module-package-sources.checksum')
|
|
120
|
+
|
|
121
|
+
await generateModulePackageSources({ resolver: initialResolver, quiet: true })
|
|
122
|
+
const outputBefore = fs.readFileSync(outFile, 'utf8')
|
|
123
|
+
const initialStructure = readChecksumRecord(checksumFile)?.structure
|
|
124
|
+
const pinnedTime = new Date(Date.now() - 60_000)
|
|
125
|
+
fs.utimesSync(outFile, pinnedTime, pinnedTime)
|
|
126
|
+
|
|
127
|
+
await generateModulePackageSources({ resolver: alternateResolver, quiet: true })
|
|
128
|
+
const alternateStructure = readChecksumRecord(checksumFile)?.structure
|
|
129
|
+
expect(alternateStructure).not.toBe(initialStructure)
|
|
130
|
+
expect(fs.readFileSync(outFile, 'utf8')).toBe(outputBefore)
|
|
131
|
+
expect(fs.statSync(outFile).mtimeMs).toBe(pinnedTime.getTime())
|
|
132
|
+
|
|
133
|
+
const packageJsonPath = path.join(packageRoot, 'package.json')
|
|
134
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as Record<string, unknown>
|
|
135
|
+
packageJson.version = '0.2.0'
|
|
136
|
+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`)
|
|
137
|
+
const result = await generateModulePackageSources({ resolver: alternateResolver, quiet: true })
|
|
138
|
+
|
|
139
|
+
expect(readChecksumRecord(checksumFile)?.structure).not.toBe(alternateStructure)
|
|
140
|
+
expect(result.filesWritten).toEqual([])
|
|
141
|
+
expect(result.filesUnchanged).toEqual([outFile])
|
|
142
|
+
expect(fs.readFileSync(outFile, 'utf8')).toBe(outputBefore)
|
|
143
|
+
expect(fs.statSync(outFile).mtimeMs).toBe(pinnedTime.getTime())
|
|
144
|
+
})
|
|
145
|
+
|
|
146
|
+
it('keeps official package validation as the source inclusion gate', async () => {
|
|
147
|
+
const packageRoot = path.join(tmpDir, 'node_modules', '@open-mercato', 'test-package')
|
|
148
|
+
copyDir(fixturePackageRoot, packageRoot)
|
|
149
|
+
const packageJsonPath = path.join(packageRoot, 'package.json')
|
|
150
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as Record<string, unknown>
|
|
151
|
+
packageJson.name = '@open-mercato/different-package'
|
|
152
|
+
fs.writeFileSync(packageJsonPath, `${JSON.stringify(packageJson, null, 2)}\n`)
|
|
153
|
+
const resolver = createResolver(tmpDir, packageRoot, '@open-mercato/test-package')
|
|
154
|
+
|
|
155
|
+
await generateModulePackageSources({ resolver, quiet: true })
|
|
156
|
+
|
|
157
|
+
const output = fs.readFileSync(path.join(resolver.getOutputDir(), 'module-package-sources.css'), 'utf8')
|
|
158
|
+
expect(output).toBe('')
|
|
159
|
+
})
|
|
160
|
+
|
|
78
161
|
it('skips app-backed modules', async () => {
|
|
79
162
|
const packageRoot = path.join(tmpDir, 'node_modules', '@open-mercato', 'test-package')
|
|
80
163
|
copyDir(fixturePackageRoot, packageRoot)
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
1
|
import path from 'node:path'
|
|
3
2
|
import { readOfficialModulePackageFromRoot, resolveInstalledPackageRoot } from '../module-package'
|
|
4
3
|
import type { PackageResolver } from '../resolver'
|
|
5
|
-
import {
|
|
4
|
+
import { calculateChecksum, createGeneratorResult, type GeneratorResult, writeGeneratedFile } from '../utils'
|
|
6
5
|
|
|
7
6
|
export interface ModulePackageSourcesOptions {
|
|
8
7
|
resolver: PackageResolver
|
|
@@ -23,13 +22,12 @@ export async function generateModulePackageSources(
|
|
|
23
22
|
const outFile = path.join(outputDir, 'module-package-sources.css')
|
|
24
23
|
const checksumFile = path.join(outputDir, 'module-package-sources.checksum')
|
|
25
24
|
const sourcePaths = new Set<string>()
|
|
26
|
-
const
|
|
25
|
+
const checksumInputs = new Set<string>()
|
|
27
26
|
|
|
28
27
|
for (const entry of resolver.loadEnabledModules()) {
|
|
29
28
|
if (!entry.from || entry.from === '@app' || entry.from === '@open-mercato/core') continue
|
|
30
29
|
|
|
31
30
|
const packageRoot = resolveInstalledPackageRoot(resolver, entry.from)
|
|
32
|
-
checksumTargets.push(packageRoot)
|
|
33
31
|
|
|
34
32
|
let modulePackage
|
|
35
33
|
try {
|
|
@@ -39,12 +37,26 @@ export async function generateModulePackageSources(
|
|
|
39
37
|
}
|
|
40
38
|
|
|
41
39
|
const packageSourceRoot = path.join(modulePackage.packageRoot, 'src')
|
|
40
|
+
checksumInputs.add(JSON.stringify({
|
|
41
|
+
entry: {
|
|
42
|
+
from: entry.from,
|
|
43
|
+
id: entry.id,
|
|
44
|
+
},
|
|
45
|
+
packageName: modulePackage.packageName,
|
|
46
|
+
packageRoot: path.resolve(modulePackage.packageRoot),
|
|
47
|
+
packageJson: modulePackage.packageJson,
|
|
48
|
+
packageSourceRoot,
|
|
49
|
+
sourceModuleDir: path.resolve(modulePackage.sourceModuleDir),
|
|
50
|
+
distModuleDir: path.resolve(modulePackage.distModuleDir),
|
|
51
|
+
}))
|
|
42
52
|
const relativeSourcePath = normalizeCssSourcePath(path.relative(path.dirname(outFile), packageSourceRoot))
|
|
43
53
|
sourcePaths.add(`@source "${relativeSourcePath}/**/*.{ts,tsx}";`)
|
|
44
54
|
}
|
|
45
55
|
|
|
46
56
|
const content = `${Array.from(sourcePaths).sort((left, right) => left.localeCompare(right)).join('\n')}${sourcePaths.size > 0 ? '\n' : ''}`
|
|
47
|
-
const structureChecksum =
|
|
57
|
+
const structureChecksum = calculateChecksum(
|
|
58
|
+
Array.from(checksumInputs).sort((left, right) => left.localeCompare(right)).join('\n'),
|
|
59
|
+
)
|
|
48
60
|
|
|
49
61
|
writeGeneratedFile({
|
|
50
62
|
outFile,
|
package/src/mercato.ts
CHANGED
|
@@ -825,7 +825,7 @@ async function createGenerateWatchRuntime(quiet = false) {
|
|
|
825
825
|
const [
|
|
826
826
|
{ createResolver },
|
|
827
827
|
{ calculateGenerateWatchStructureChecksum },
|
|
828
|
-
{ createGenerateWatchChangeSignal },
|
|
828
|
+
{ createGenerateWatchChangeSignal, resolveGenerateWatchTargets },
|
|
829
829
|
{ resolveStandaloneSourceMirrorBase },
|
|
830
830
|
] = await Promise.all([
|
|
831
831
|
import('./lib/resolver'),
|
|
@@ -836,10 +836,18 @@ async function createGenerateWatchRuntime(quiet = false) {
|
|
|
836
836
|
|
|
837
837
|
const collectWatchState = () => {
|
|
838
838
|
const resolver = createResolver()
|
|
839
|
-
const moduleRoots
|
|
839
|
+
const moduleRoots: Array<{
|
|
840
|
+
appBase: string
|
|
841
|
+
pkgBase: string
|
|
842
|
+
watchPackageBase: boolean
|
|
843
|
+
}> = []
|
|
844
|
+
const watchAppPackageFallbacks = resolver.isMonorepo()
|
|
840
845
|
for (const entry of resolver.loadEnabledModules()) {
|
|
841
846
|
const roots = resolver.getModulePaths(entry)
|
|
842
|
-
moduleRoots.push({
|
|
847
|
+
moduleRoots.push({
|
|
848
|
+
...roots,
|
|
849
|
+
watchPackageBase: entry.from !== '@app' || watchAppPackageFallbacks,
|
|
850
|
+
})
|
|
843
851
|
}
|
|
844
852
|
return {
|
|
845
853
|
modulesFile: resolver.getModulesConfigPath(),
|
|
@@ -857,20 +865,11 @@ async function createGenerateWatchRuntime(quiet = false) {
|
|
|
857
865
|
: (directory) => console.log(`[generate:watch] Skipping missing watch directory: ${directory}`),
|
|
858
866
|
getWatchTargets: () => {
|
|
859
867
|
const state = collectWatchState()
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
}
|
|
865
|
-
for (const roots of state.moduleRoots) {
|
|
866
|
-
targets.push({ directory: path.dirname(roots.appBase), recursive: true })
|
|
867
|
-
targets.push({ directory: path.dirname(roots.pkgBase), recursive: true })
|
|
868
|
-
const sourceMirror = resolveStandaloneSourceMirrorBase(roots.pkgBase)
|
|
869
|
-
if (sourceMirror) {
|
|
870
|
-
targets.push({ directory: path.dirname(sourceMirror), recursive: true })
|
|
871
|
-
}
|
|
872
|
-
}
|
|
873
|
-
return targets
|
|
868
|
+
return resolveGenerateWatchTargets({
|
|
869
|
+
modulesFile: state.modulesFile,
|
|
870
|
+
moduleRoots: state.moduleRoots,
|
|
871
|
+
resolveSourceMirrorBase: resolveStandaloneSourceMirrorBase,
|
|
872
|
+
})
|
|
874
873
|
},
|
|
875
874
|
}),
|
|
876
875
|
}
|