@equinor/echo-cli 2.0.1 → 2.1.0-beta-1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +381 -357
  2. package/lib/echo-dev-host/README.md +121 -121
  3. package/lib/echo-dev-host/babel.config.js +10 -10
  4. package/lib/echo-dev-host/jest.config.js +21 -21
  5. package/lib/echo-dev-host/package-lock.json +13124 -13124
  6. package/lib/echo-dev-host/public/env-config.js +17 -17
  7. package/lib/echo-dev-host/public/index.html +21 -21
  8. package/lib/echo-dev-host/tsconfig.json +21 -21
  9. package/lib/echo-dev-host/webpack.config.js +145 -145
  10. package/lib/sync-dev-host-to-app.d.ts +26 -0
  11. package/lib/sync-dev-host-to-app.js +63 -0
  12. package/lib/sync-dev-host-to-app.js.map +1 -0
  13. package/lib/sync-echo-dev-versions.d.ts +6 -0
  14. package/lib/sync-echo-dev-versions.js +43 -0
  15. package/lib/sync-echo-dev-versions.js.map +1 -0
  16. package/lib/tools/buildScripts/buildAndCopyDevHost.d.ts +38 -1
  17. package/lib/tools/buildScripts/buildAndCopyDevHost.js +73 -10
  18. package/lib/tools/buildScripts/buildAndCopyDevHost.js.map +1 -1
  19. package/lib/tools/buildScripts/buildAndCopyDevHost.test.js +502 -0
  20. package/lib/tools/buildScripts/buildAndCopyDevHost.test.js.map +1 -0
  21. package/lib/utils/merge.test.d.ts +1 -0
  22. package/lib/{__test__/utils/merg.test.js → utils/merge.test.js} +2 -2
  23. package/lib/utils/merge.test.js.map +1 -0
  24. package/package.json +111 -110
  25. package/templates/echoAppTemplate/.gitattributes +3 -3
  26. package/templates/echoAppTemplate/package.json +35 -35
  27. package/templates/echoAppTemplate/readme.md +41 -41
  28. package/templates/echoAppTemplate/tsconfig.json +25 -25
  29. package/templates/echoAppTemplateTutorial/.gitattributes +3 -3
  30. package/templates/echoAppTemplateTutorial/package.json +36 -36
  31. package/templates/echoAppTemplateTutorial/readme.md +41 -41
  32. package/templates/echoAppTemplateTutorial/tsconfig.json +25 -25
  33. package/templates/echoLibraryTemplate/package.json +35 -35
  34. package/templates/echoLibraryTemplate/public/index.html +21 -21
  35. package/templates/echoLibraryTemplate/readme.md +1 -1
  36. package/templates/echoPluginTemplate/package.json +35 -35
  37. package/templates/echoPluginTemplate/public/index.html +21 -21
  38. package/templates/echoPluginTemplate/readme.md +1 -1
  39. package/lib/__test__/utils/merg.test.js.map +0 -1
  40. /package/lib/{__test__/utils/merg.test.d.ts → tools/buildScripts/buildAndCopyDevHost.test.d.ts} +0 -0
@@ -30,7 +30,7 @@ import { printEchoLibsVersions } from '../../utils/printEchoLibsVersions.js';
30
30
  * @remarks
31
31
  * - Exits the process if a suitable consumer app package.json cannot be found.
32
32
  */
33
- export async function buildAndCopyDevHost({ cliNodeModules, tmpDevHostFolder, finalOutputDir, isProdBuild = false }) {
33
+ export async function buildAndCopyDevHost({ cliNodeModules, tmpDevHostFolder, finalOutputDir, isProdBuild = false, syncMode = false }) {
34
34
  console.log(`${chalk.cyan.bold('echo-dev-host')} - by Echo Core Team`);
35
35
  console.log('Minimalistic host application for local development of Echo applications.\n');
36
36
  console.log(figlet.textSync('Echo Dev Host', {
@@ -66,6 +66,12 @@ export async function buildAndCopyDevHost({ cliNodeModules, tmpDevHostFolder, fi
66
66
  tmpDevHostFolder
67
67
  });
68
68
  }
69
+ else if (syncMode) {
70
+ echoLibVersionsToUse = await syncDevHostToConsumerVersions({
71
+ appPkgPath,
72
+ tmpDevHostFolder
73
+ });
74
+ }
69
75
  await printEchoLibsVersions({
70
76
  devHostPkgPath: srcPkgJson,
71
77
  appPkgPath: appPkgPath,
@@ -100,8 +106,9 @@ export async function buildAndCopyDevHost({ cliNodeModules, tmpDevHostFolder, fi
100
106
  * @param appPkgPath - The file path to the consumer application's package.json.
101
107
  * @param tmpDevHostFolder - The folder path containing the dev host's package.json.
102
108
  * @returns A promise that resolves to a record mapping each Echo library name to the version that will be used for the build.
109
+ * @internal - Exported for testing purposes only
103
110
  */
104
- async function determineEchoLibVersionsForProdBuild({ appPkgPath, tmpDevHostFolder }) {
111
+ export async function determineEchoLibVersionsForProdBuild({ appPkgPath, tmpDevHostFolder }) {
105
112
  const consumerPkg = fs.readJsonSync(appPkgPath);
106
113
  const consumerAppName = consumerPkg.name || 'the consumer app';
107
114
  console.log(chalk.magentaBright.bold(`\n[echo-dev-host] Prod build - Using latest echo lib versions from "${consumerAppName}" or echo dev host.\n`));
@@ -113,17 +120,28 @@ async function determineEchoLibVersionsForProdBuild({ appPkgPath, tmpDevHostFold
113
120
  for (const [lib, consumerVersion] of echoDeps) {
114
121
  const devHostVersion = devHostPkg.dependencies?.[lib];
115
122
  let source = consumerAppName;
116
- let finalVersion = consumerVersion;
117
- if (devHostVersion &&
118
- semver.valid(devHostVersion) &&
119
- semver.valid(consumerVersion) &&
120
- semver.gt(devHostVersion, consumerVersion)) {
121
- source = 'echo dev host';
122
- devHostPkg.dependencies[lib] = devHostVersion;
123
+ let finalVersion = consumerVersion; // Default to consumer version
124
+ if (devHostVersion && semver.valid(devHostVersion) && semver.valid(consumerVersion)) {
125
+ // Use whichever version is higher
126
+ if (semver.gt(devHostVersion, consumerVersion)) {
127
+ // Dev host version is higher, keep it
128
+ source = 'echo dev host';
129
+ finalVersion = devHostVersion;
130
+ }
131
+ else if (semver.gt(consumerVersion, devHostVersion)) {
132
+ // Consumer version is higher, update dev host package.json
133
+ devHostPkg.dependencies[lib] = consumerVersion;
134
+ updated = true;
135
+ }
136
+ // If versions are equal, finalVersion stays as consumerVersion
137
+ }
138
+ else if (!devHostVersion) {
139
+ // Dev host doesn't have this library, add it from consumer
140
+ devHostPkg.dependencies[lib] = consumerVersion;
123
141
  updated = true;
124
142
  }
125
143
  // Track the version that will be used for the build
126
- echoLibVersionsToUse[lib] = devHostPkg.dependencies?.[lib] || consumerVersion;
144
+ echoLibVersionsToUse[lib] = finalVersion;
127
145
  // Log the decision
128
146
  console.log(`${chalk.cyan(lib)}: ${chalk.yellow(finalVersion)} (from ${source})`);
129
147
  }
@@ -132,4 +150,49 @@ async function determineEchoLibVersionsForProdBuild({ appPkgPath, tmpDevHostFold
132
150
  }
133
151
  return echoLibVersionsToUse;
134
152
  }
153
+ /**
154
+ * Forces the dev host to use the exact echo library versions from the consumer app's package.json.
155
+ * This is useful for developers switching between git branches with different echo lib versions.
156
+ *
157
+ * Unlike production builds which use max(consumer, devHost), this function always uses the consumer's
158
+ * version regardless of whether it's higher or lower than the dev host's current version.
159
+ *
160
+ * @param appPkgPath - The file path to the consumer application's package.json.
161
+ * @param tmpDevHostFolder - The folder path containing the dev host's package.json.
162
+ * @returns A promise that resolves to a record mapping each Echo library name to the version from the consumer app.
163
+ * @internal - Exported for testing purposes only
164
+ */
165
+ export async function syncDevHostToConsumerVersions({ appPkgPath, tmpDevHostFolder }) {
166
+ const consumerPkg = fs.readJsonSync(appPkgPath);
167
+ const consumerAppName = consumerPkg.name || 'your app';
168
+ console.log(chalk.magentaBright.bold(`\n[echo-dev-host] Syncing to exact echo lib versions from "${consumerAppName}".\n`));
169
+ const devHostPkgPath = path.join(tmpDevHostFolder, 'package.json');
170
+ const devHostPkg = fs.readJsonSync(devHostPkgPath);
171
+ const echoDeps = getEchoDeps(consumerPkg);
172
+ let updated = false;
173
+ const echoLibVersionsToUse = {};
174
+ for (const [lib, consumerVersion] of echoDeps) {
175
+ const devHostVersion = devHostPkg.dependencies?.[lib];
176
+ // Always use consumer version (force sync)
177
+ echoLibVersionsToUse[lib] = consumerVersion;
178
+ if (devHostVersion === consumerVersion) {
179
+ console.log(`${chalk.cyan(lib)}: ${chalk.yellow(consumerVersion)} ${chalk.gray('(already synced)')}`);
180
+ }
181
+ else {
182
+ devHostPkg.dependencies[lib] = consumerVersion;
183
+ updated = true;
184
+ const previousVersion = devHostVersion || 'not installed';
185
+ const wasMessage = chalk.gray(`(was ${previousVersion})`);
186
+ console.log(`${chalk.cyan(lib)}: ${chalk.yellow(consumerVersion)} ${wasMessage}`);
187
+ }
188
+ }
189
+ if (updated) {
190
+ fs.writeJsonSync(devHostPkgPath, devHostPkg, { spaces: 4 });
191
+ console.log(chalk.green('\n✓ Updated dev host package.json'));
192
+ }
193
+ else {
194
+ console.log(chalk.gray('\n✓ All versions already synced'));
195
+ }
196
+ return echoLibVersionsToUse;
197
+ }
135
198
  //# sourceMappingURL=buildAndCopyDevHost.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"buildAndCopyDevHost.js","sourceRoot":"","sources":["../../../src/tools/buildScripts/buildAndCopyDevHost.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"buildAndCopyDevHost.js","sourceRoot":"","sources":["../../../src/tools/buildScripts/buildAndCopyDevHost.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,502 @@
1
+ // Mock all dependencies BEFORE any imports
2
+ jest.mock('fs-extra');
3
+ jest.mock('../../utils/printEchoLibsVersions.js', () => ({
4
+ printEchoLibsVersions: jest.fn()
5
+ }));
6
+ jest.mock('chalk', () => {
7
+ const mockFn = jest.fn((str) => str);
8
+ const chalkMock = {
9
+ cyan: mockFn,
10
+ yellow: mockFn,
11
+ gray: mockFn,
12
+ green: mockFn,
13
+ magentaBright: { bold: mockFn },
14
+ blueBright: { bold: mockFn },
15
+ yellowBright: { bold: mockFn },
16
+ greenBright: { bold: mockFn }
17
+ };
18
+ // Also add nested bold methods for green
19
+ chalkMock.green.bold = mockFn;
20
+ // Return both default export and named export pattern
21
+ chalkMock.default = chalkMock;
22
+ return chalkMock;
23
+ });
24
+ jest.mock('figlet', () => ({
25
+ default: {
26
+ textSync: jest.fn(() => 'ECHO DEV HOST')
27
+ }
28
+ }));
29
+ jest.mock('child_process', () => ({
30
+ execSync: jest.fn()
31
+ }));
32
+ import fs from 'fs-extra';
33
+ import path from 'node:path';
34
+ import { determineEchoLibVersionsForProdBuild, syncDevHostToConsumerVersions } from './buildAndCopyDevHost';
35
+ const mockedFs = fs;
36
+ // Mock console.log to suppress output during tests
37
+ const originalConsoleLog = console.log;
38
+ beforeAll(() => {
39
+ console.log = jest.fn();
40
+ });
41
+ afterAll(() => {
42
+ console.log = originalConsoleLog;
43
+ });
44
+ describe('determineEchoLibVersionsForProdBuild', () => {
45
+ const tmpDevHostFolder = '/tmp/dev-host';
46
+ const devHostPkgPath = path.join(tmpDevHostFolder, 'package.json');
47
+ beforeEach(() => {
48
+ jest.clearAllMocks();
49
+ });
50
+ describe('Consumer version is higher than dev host version', () => {
51
+ it('should update dev host package.json with consumer versions when consumer has higher versions', async () => {
52
+ // Arrange
53
+ const consumerPkg = {
54
+ name: 'test-consumer-app',
55
+ dependencies: {
56
+ '@equinor/echo-base': '2.2.1',
57
+ '@equinor/echo-core': '2.2.1',
58
+ '@equinor/echo-framework': '2.2.1'
59
+ }
60
+ };
61
+ const devHostPkg = {
62
+ name: 'echo-dev-host',
63
+ dependencies: {
64
+ '@equinor/echo-base': '2.0.1',
65
+ '@equinor/echo-core': '2.0.1',
66
+ '@equinor/echo-framework': '2.0.1'
67
+ }
68
+ };
69
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
70
+ if (filePath.includes('consumer'))
71
+ return consumerPkg;
72
+ if (filePath === devHostPkgPath)
73
+ return devHostPkg;
74
+ throw new Error(`Unexpected file path: ${filePath}`);
75
+ });
76
+ // Act
77
+ const result = await determineEchoLibVersionsForProdBuild({
78
+ appPkgPath: '/path/to/consumer/package.json',
79
+ tmpDevHostFolder
80
+ });
81
+ // Assert
82
+ expect(result).toEqual({
83
+ '@equinor/echo-base': '2.2.1',
84
+ '@equinor/echo-core': '2.2.1',
85
+ '@equinor/echo-framework': '2.2.1'
86
+ });
87
+ // Verify dev host package.json was updated
88
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
89
+ dependencies: {
90
+ '@equinor/echo-base': '2.2.1',
91
+ '@equinor/echo-core': '2.2.1',
92
+ '@equinor/echo-framework': '2.2.1'
93
+ }
94
+ }), { spaces: 4 });
95
+ });
96
+ });
97
+ describe('Dev host version is higher than consumer version', () => {
98
+ it('should keep dev host versions when dev host has higher versions', async () => {
99
+ // Arrange
100
+ const consumerPkg = {
101
+ name: 'test-consumer-app',
102
+ dependencies: {
103
+ '@equinor/echo-base': '2.0.1',
104
+ '@equinor/echo-core': '2.0.1'
105
+ }
106
+ };
107
+ const devHostPkg = {
108
+ name: 'echo-dev-host',
109
+ dependencies: {
110
+ '@equinor/echo-base': '2.2.1',
111
+ '@equinor/echo-core': '2.2.1'
112
+ }
113
+ };
114
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
115
+ if (filePath.includes('consumer'))
116
+ return consumerPkg;
117
+ if (filePath === devHostPkgPath)
118
+ return devHostPkg;
119
+ throw new Error(`Unexpected file path: ${filePath}`);
120
+ });
121
+ // Act
122
+ const result = await determineEchoLibVersionsForProdBuild({
123
+ appPkgPath: '/path/to/consumer/package.json',
124
+ tmpDevHostFolder
125
+ });
126
+ // Assert
127
+ expect(result).toEqual({
128
+ '@equinor/echo-base': '2.2.1',
129
+ '@equinor/echo-core': '2.2.1'
130
+ });
131
+ // Verify dev host package.json was NOT updated (no changes needed)
132
+ expect(mockedFs.writeJsonSync).not.toHaveBeenCalled();
133
+ });
134
+ });
135
+ describe('Mixed version scenarios', () => {
136
+ it('should use max version for each library independently', async () => {
137
+ // Arrange
138
+ const consumerPkg = {
139
+ name: 'test-consumer-app',
140
+ dependencies: {
141
+ '@equinor/echo-base': '2.2.1', // Consumer higher
142
+ '@equinor/echo-core': '2.0.1', // Dev host higher
143
+ '@equinor/echo-framework': '2.1.0' // Equal
144
+ }
145
+ };
146
+ const devHostPkg = {
147
+ name: 'echo-dev-host',
148
+ dependencies: {
149
+ '@equinor/echo-base': '2.0.1',
150
+ '@equinor/echo-core': '2.2.1',
151
+ '@equinor/echo-framework': '2.1.0'
152
+ }
153
+ };
154
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
155
+ if (filePath.includes('consumer'))
156
+ return consumerPkg;
157
+ if (filePath === devHostPkgPath)
158
+ return devHostPkg;
159
+ throw new Error(`Unexpected file path: ${filePath}`);
160
+ });
161
+ // Act
162
+ const result = await determineEchoLibVersionsForProdBuild({
163
+ appPkgPath: '/path/to/consumer/package.json',
164
+ tmpDevHostFolder
165
+ });
166
+ // Assert
167
+ expect(result).toEqual({
168
+ '@equinor/echo-base': '2.2.1', // Consumer version used
169
+ '@equinor/echo-core': '2.2.1', // Dev host version used
170
+ '@equinor/echo-framework': '2.1.0' // Equal, consumer used
171
+ });
172
+ // Verify only echo-base was updated in dev host package.json
173
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
174
+ dependencies: {
175
+ '@equinor/echo-base': '2.2.1', // Updated
176
+ '@equinor/echo-core': '2.2.1', // Unchanged
177
+ '@equinor/echo-framework': '2.1.0' // Unchanged
178
+ }
179
+ }), { spaces: 4 });
180
+ });
181
+ });
182
+ describe('Missing dependencies in dev host', () => {
183
+ it('should add missing libraries from consumer to dev host', async () => {
184
+ // Arrange
185
+ const consumerPkg = {
186
+ name: 'test-consumer-app',
187
+ dependencies: {
188
+ '@equinor/echo-base': '2.2.1',
189
+ '@equinor/echo-core': '2.2.1',
190
+ '@equinor/echo-utils': '2.0.2' // Missing in dev host
191
+ }
192
+ };
193
+ const devHostPkg = {
194
+ name: 'echo-dev-host',
195
+ dependencies: {
196
+ '@equinor/echo-base': '2.0.1',
197
+ '@equinor/echo-core': '2.0.1'
198
+ // echo-utils is missing
199
+ }
200
+ };
201
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
202
+ if (filePath.includes('consumer'))
203
+ return consumerPkg;
204
+ if (filePath === devHostPkgPath)
205
+ return devHostPkg;
206
+ throw new Error(`Unexpected file path: ${filePath}`);
207
+ });
208
+ // Act
209
+ const result = await determineEchoLibVersionsForProdBuild({
210
+ appPkgPath: '/path/to/consumer/package.json',
211
+ tmpDevHostFolder
212
+ });
213
+ // Assert
214
+ expect(result).toEqual({
215
+ '@equinor/echo-base': '2.2.1',
216
+ '@equinor/echo-core': '2.2.1',
217
+ '@equinor/echo-utils': '2.0.2'
218
+ });
219
+ // Verify dev host package.json was updated with all three libraries
220
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
221
+ dependencies: {
222
+ '@equinor/echo-base': '2.2.1',
223
+ '@equinor/echo-core': '2.2.1',
224
+ '@equinor/echo-utils': '2.0.2' // Added
225
+ }
226
+ }), { spaces: 4 });
227
+ });
228
+ });
229
+ describe('Real-world bug scenario from issue report', () => {
230
+ it('should reproduce and fix the reported bug where consumer 2.2.1 was ignored and dev host 2.0.1 was used', async () => {
231
+ // This is the exact scenario from the user's bug report
232
+ const consumerPkg = {
233
+ name: 'echo-3d-web',
234
+ dependencies: {
235
+ '@equinor/echo-base': '2.2.1',
236
+ '@equinor/echo-components': '2.2.1',
237
+ '@equinor/echo-core': '2.2.1',
238
+ '@equinor/echo-framework': '2.2.1',
239
+ '@equinor/echo-search': '2.2.1',
240
+ '@equinor/echo-utils': '2.2.1',
241
+ '@equinor/echo-cli': '2.0.0'
242
+ }
243
+ };
244
+ const devHostPkg = {
245
+ name: 'echo-dev-host',
246
+ dependencies: {
247
+ '@equinor/echo-base': '2.0.1',
248
+ '@equinor/echo-components': '2.0.1',
249
+ '@equinor/echo-core': '2.0.1',
250
+ '@equinor/echo-framework': '2.0.1',
251
+ '@equinor/echo-search': '2.0.1',
252
+ '@equinor/echo-utils': '2.0.2'
253
+ }
254
+ };
255
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
256
+ if (filePath.includes('consumer') || filePath.includes('echo-3d-web'))
257
+ return consumerPkg;
258
+ if (filePath === devHostPkgPath)
259
+ return devHostPkg;
260
+ throw new Error(`Unexpected file path: ${filePath}`);
261
+ });
262
+ // Act
263
+ const result = await determineEchoLibVersionsForProdBuild({
264
+ appPkgPath: '/path/to/echo-3d-web/package.json',
265
+ tmpDevHostFolder
266
+ });
267
+ // Assert - All should use the consumer's 2.2.1 versions (except echo-utils which is higher in dev host)
268
+ expect(result).toEqual({
269
+ '@equinor/echo-base': '2.2.1',
270
+ '@equinor/echo-components': '2.2.1',
271
+ '@equinor/echo-core': '2.2.1',
272
+ '@equinor/echo-framework': '2.2.1',
273
+ '@equinor/echo-search': '2.2.1',
274
+ '@equinor/echo-utils': '2.2.1', // Consumer version is higher than 2.0.2
275
+ '@equinor/echo-cli': '2.0.0'
276
+ });
277
+ // Verify dev host package.json was updated with the higher consumer versions
278
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
279
+ dependencies: expect.objectContaining({
280
+ '@equinor/echo-base': '2.2.1',
281
+ '@equinor/echo-components': '2.2.1',
282
+ '@equinor/echo-core': '2.2.1',
283
+ '@equinor/echo-framework': '2.2.1',
284
+ '@equinor/echo-search': '2.2.1',
285
+ '@equinor/echo-utils': '2.2.1',
286
+ '@equinor/echo-cli': '2.0.0'
287
+ })
288
+ }), { spaces: 4 });
289
+ });
290
+ });
291
+ });
292
+ describe('syncDevHostToConsumerVersions', () => {
293
+ const tmpDevHostFolder = '/tmp/dev-host';
294
+ const devHostPkgPath = path.join(tmpDevHostFolder, 'package.json');
295
+ beforeEach(() => {
296
+ jest.clearAllMocks();
297
+ });
298
+ describe('Force sync behavior', () => {
299
+ it('should downgrade dev host versions to match lower consumer versions', async () => {
300
+ // Arrange
301
+ const consumerPkg = {
302
+ name: 'my-echo-app',
303
+ dependencies: {
304
+ '@equinor/echo-core': '2.0.1',
305
+ '@equinor/echo-framework': '2.0.1'
306
+ }
307
+ };
308
+ const devHostPkg = {
309
+ name: 'echo-dev-host',
310
+ dependencies: {
311
+ '@equinor/echo-core': '2.3.0', // Higher than consumer
312
+ '@equinor/echo-framework': '2.3.0' // Higher than consumer
313
+ }
314
+ };
315
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
316
+ if (filePath.includes('my-echo-app'))
317
+ return consumerPkg;
318
+ if (filePath === devHostPkgPath)
319
+ return devHostPkg;
320
+ throw new Error(`Unexpected file path: ${filePath}`);
321
+ });
322
+ // Act
323
+ const result = await syncDevHostToConsumerVersions({
324
+ appPkgPath: '/path/to/my-echo-app/package.json',
325
+ tmpDevHostFolder
326
+ });
327
+ // Assert - Should force downgrade to consumer versions
328
+ expect(result).toEqual({
329
+ '@equinor/echo-core': '2.0.1',
330
+ '@equinor/echo-framework': '2.0.1'
331
+ });
332
+ // Verify dev host was downgraded
333
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
334
+ dependencies: {
335
+ '@equinor/echo-core': '2.0.1',
336
+ '@equinor/echo-framework': '2.0.1'
337
+ }
338
+ }), { spaces: 4 });
339
+ });
340
+ it('should upgrade dev host versions to match higher consumer versions', async () => {
341
+ // Arrange
342
+ const consumerPkg = {
343
+ name: 'my-echo-app',
344
+ dependencies: {
345
+ '@equinor/echo-core': '2.5.0',
346
+ '@equinor/echo-framework': '2.5.0'
347
+ }
348
+ };
349
+ const devHostPkg = {
350
+ name: 'echo-dev-host',
351
+ dependencies: {
352
+ '@equinor/echo-core': '2.0.1', // Lower than consumer
353
+ '@equinor/echo-framework': '2.0.1' // Lower than consumer
354
+ }
355
+ };
356
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
357
+ if (filePath.includes('my-echo-app'))
358
+ return consumerPkg;
359
+ if (filePath === devHostPkgPath)
360
+ return devHostPkg;
361
+ throw new Error(`Unexpected file path: ${filePath}`);
362
+ });
363
+ // Act
364
+ const result = await syncDevHostToConsumerVersions({
365
+ appPkgPath: '/path/to/my-echo-app/package.json',
366
+ tmpDevHostFolder
367
+ });
368
+ // Assert - Should upgrade to consumer versions
369
+ expect(result).toEqual({
370
+ '@equinor/echo-core': '2.5.0',
371
+ '@equinor/echo-framework': '2.5.0'
372
+ });
373
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
374
+ dependencies: {
375
+ '@equinor/echo-core': '2.5.0',
376
+ '@equinor/echo-framework': '2.5.0'
377
+ }
378
+ }), { spaces: 4 });
379
+ });
380
+ it('should not update package.json if versions already match', async () => {
381
+ // Arrange
382
+ const consumerPkg = {
383
+ name: 'my-echo-app',
384
+ dependencies: {
385
+ '@equinor/echo-core': '2.2.1',
386
+ '@equinor/echo-framework': '2.2.1'
387
+ }
388
+ };
389
+ const devHostPkg = {
390
+ name: 'echo-dev-host',
391
+ dependencies: {
392
+ '@equinor/echo-core': '2.2.1', // Same as consumer
393
+ '@equinor/echo-framework': '2.2.1' // Same as consumer
394
+ }
395
+ };
396
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
397
+ if (filePath.includes('my-echo-app'))
398
+ return consumerPkg;
399
+ if (filePath === devHostPkgPath)
400
+ return devHostPkg;
401
+ throw new Error(`Unexpected file path: ${filePath}`);
402
+ });
403
+ // Act
404
+ const result = await syncDevHostToConsumerVersions({
405
+ appPkgPath: '/path/to/my-echo-app/package.json',
406
+ tmpDevHostFolder
407
+ });
408
+ // Assert
409
+ expect(result).toEqual({
410
+ '@equinor/echo-core': '2.2.1',
411
+ '@equinor/echo-framework': '2.2.1'
412
+ });
413
+ // Should NOT write to package.json if already synced
414
+ expect(mockedFs.writeJsonSync).not.toHaveBeenCalled();
415
+ });
416
+ it('should handle mixed versions (some up, some down, some same)', async () => {
417
+ // Arrange
418
+ const consumerPkg = {
419
+ name: 'my-echo-app',
420
+ dependencies: {
421
+ '@equinor/echo-core': '2.0.1', // Lower than dev host
422
+ '@equinor/echo-framework': '2.5.0', // Higher than dev host
423
+ '@equinor/echo-search': '2.2.1' // Same as dev host
424
+ }
425
+ };
426
+ const devHostPkg = {
427
+ name: 'echo-dev-host',
428
+ dependencies: {
429
+ '@equinor/echo-core': '2.3.0',
430
+ '@equinor/echo-framework': '2.0.1',
431
+ '@equinor/echo-search': '2.2.1'
432
+ }
433
+ };
434
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
435
+ if (filePath.includes('my-echo-app'))
436
+ return consumerPkg;
437
+ if (filePath === devHostPkgPath)
438
+ return devHostPkg;
439
+ throw new Error(`Unexpected file path: ${filePath}`);
440
+ });
441
+ // Act
442
+ const result = await syncDevHostToConsumerVersions({
443
+ appPkgPath: '/path/to/my-echo-app/package.json',
444
+ tmpDevHostFolder
445
+ });
446
+ // Assert - All should match consumer, regardless of direction
447
+ expect(result).toEqual({
448
+ '@equinor/echo-core': '2.0.1',
449
+ '@equinor/echo-framework': '2.5.0',
450
+ '@equinor/echo-search': '2.2.1'
451
+ });
452
+ // Only echo-core and echo-framework should be updated (echo-search already synced)
453
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
454
+ dependencies: {
455
+ '@equinor/echo-core': '2.0.1',
456
+ '@equinor/echo-framework': '2.5.0',
457
+ '@equinor/echo-search': '2.2.1'
458
+ }
459
+ }), { spaces: 4 });
460
+ });
461
+ it('should add missing libraries from consumer app', async () => {
462
+ // Arrange
463
+ const consumerPkg = {
464
+ name: 'my-echo-app',
465
+ dependencies: {
466
+ '@equinor/echo-core': '2.2.1',
467
+ '@equinor/echo-search': '2.2.1' // Not in dev host
468
+ }
469
+ };
470
+ const devHostPkg = {
471
+ name: 'echo-dev-host',
472
+ dependencies: {
473
+ '@equinor/echo-core': '2.0.1'
474
+ }
475
+ };
476
+ mockedFs.readJsonSync.mockImplementation((filePath) => {
477
+ if (filePath.includes('my-echo-app'))
478
+ return consumerPkg;
479
+ if (filePath === devHostPkgPath)
480
+ return devHostPkg;
481
+ throw new Error(`Unexpected file path: ${filePath}`);
482
+ });
483
+ // Act
484
+ const result = await syncDevHostToConsumerVersions({
485
+ appPkgPath: '/path/to/my-echo-app/package.json',
486
+ tmpDevHostFolder
487
+ });
488
+ // Assert
489
+ expect(result).toEqual({
490
+ '@equinor/echo-core': '2.2.1',
491
+ '@equinor/echo-search': '2.2.1'
492
+ });
493
+ expect(mockedFs.writeJsonSync).toHaveBeenCalledWith(devHostPkgPath, expect.objectContaining({
494
+ dependencies: {
495
+ '@equinor/echo-core': '2.2.1',
496
+ '@equinor/echo-search': '2.2.1'
497
+ }
498
+ }), { spaces: 4 });
499
+ });
500
+ });
501
+ });
502
+ //# sourceMappingURL=buildAndCopyDevHost.test.js.map