@hubspot/ui-extensions-dev-server 0.10.2 → 1.0.0

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 (95) hide show
  1. package/README.md +23 -4
  2. package/dist/index.d.ts +3 -3
  3. package/dist/index.js +4 -45
  4. package/dist/lib/DevModeInterface.d.ts +2 -2
  5. package/dist/lib/DevModeInterface.js +12 -28
  6. package/dist/lib/DevModeParentInterface.d.ts +2 -2
  7. package/dist/lib/DevModeParentInterface.js +138 -154
  8. package/dist/lib/DevModeUnifiedInterface.d.ts +2 -2
  9. package/dist/lib/DevModeUnifiedInterface.js +28 -49
  10. package/dist/lib/DevServerState.d.ts +9 -5
  11. package/dist/lib/DevServerState.js +37 -18
  12. package/dist/lib/ExtensionsWebSocket.d.ts +25 -0
  13. package/dist/lib/ExtensionsWebSocket.js +110 -0
  14. package/dist/lib/__mocks__/config.d.ts +2 -0
  15. package/dist/lib/__mocks__/config.js +5 -0
  16. package/dist/lib/__mocks__/isExtensionFile.d.ts +5 -0
  17. package/dist/lib/__mocks__/isExtensionFile.js +11 -0
  18. package/dist/lib/__tests__/DevModeInterface.spec.d.ts +1 -0
  19. package/dist/lib/__tests__/DevModeInterface.spec.js +155 -0
  20. package/dist/lib/__tests__/DevModeParentInterface.spec.d.ts +1 -0
  21. package/dist/lib/__tests__/DevModeParentInterface.spec.js +179 -0
  22. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.d.ts +1 -0
  23. package/dist/lib/__tests__/DevModeUnifiedInterface.spec.js +236 -0
  24. package/dist/lib/__tests__/ExtensionsWebSocket.spec.d.ts +1 -0
  25. package/dist/lib/__tests__/ExtensionsWebSocket.spec.js +304 -0
  26. package/dist/lib/__tests__/ast.spec.d.ts +1 -0
  27. package/dist/lib/__tests__/ast.spec.js +737 -0
  28. package/dist/lib/__tests__/build.spec.d.ts +1 -0
  29. package/dist/lib/__tests__/build.spec.js +159 -0
  30. package/dist/lib/__tests__/config.spec.d.ts +1 -0
  31. package/dist/lib/__tests__/config.spec.js +291 -0
  32. package/dist/lib/__tests__/dev.spec.d.ts +1 -0
  33. package/dist/lib/__tests__/dev.spec.js +80 -0
  34. package/dist/lib/__tests__/extensionsService.spec.d.ts +1 -0
  35. package/dist/lib/__tests__/extensionsService.spec.js +150 -0
  36. package/dist/lib/__tests__/factories.d.ts +48 -0
  37. package/dist/lib/__tests__/factories.js +32 -0
  38. package/dist/lib/__tests__/fixtures/extensionConfig.d.ts +182 -0
  39. package/dist/lib/__tests__/fixtures/extensionConfig.js +304 -0
  40. package/dist/lib/__tests__/fixtures/urls.d.ts +4 -0
  41. package/dist/lib/__tests__/fixtures/urls.js +4 -0
  42. package/dist/lib/__tests__/parsing-utils.spec.d.ts +1 -0
  43. package/dist/lib/__tests__/parsing-utils.spec.js +467 -0
  44. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.d.ts +1 -0
  45. package/dist/lib/__tests__/plugins/codeBlockingPlugin.spec.js +112 -0
  46. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.d.ts +1 -0
  47. package/dist/lib/__tests__/plugins/codeCheckingPlugin.spec.js +73 -0
  48. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.d.ts +1 -0
  49. package/dist/lib/__tests__/plugins/devBuildPlugin.spec.js +256 -0
  50. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.d.ts +1 -0
  51. package/dist/lib/__tests__/plugins/friendlyLoggingPlugin.spec.js +65 -0
  52. package/dist/lib/__tests__/plugins/manifestPlugin.spec.d.ts +1 -0
  53. package/dist/lib/__tests__/plugins/manifestPlugin.spec.js +455 -0
  54. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.d.ts +1 -0
  55. package/dist/lib/__tests__/plugins/relevantModulesPlugin.spec.js +81 -0
  56. package/dist/lib/__tests__/server.spec.d.ts +1 -0
  57. package/dist/lib/__tests__/server.spec.js +152 -0
  58. package/dist/lib/__tests__/test-utils/ast.d.ts +1 -0
  59. package/dist/lib/__tests__/test-utils/ast.js +4 -0
  60. package/dist/lib/__tests__/utils.spec.d.ts +1 -0
  61. package/dist/lib/__tests__/utils.spec.js +176 -0
  62. package/dist/lib/ast.d.ts +1 -1
  63. package/dist/lib/ast.js +22 -29
  64. package/dist/lib/bin/cli.js +52 -72
  65. package/dist/lib/build.d.ts +1 -1
  66. package/dist/lib/build.js +60 -78
  67. package/dist/lib/config.d.ts +1 -1
  68. package/dist/lib/config.js +31 -34
  69. package/dist/lib/constants.d.ts +0 -2
  70. package/dist/lib/constants.js +20 -27
  71. package/dist/lib/dev.d.ts +1 -1
  72. package/dist/lib/dev.js +52 -69
  73. package/dist/lib/extensionsService.d.ts +1 -1
  74. package/dist/lib/extensionsService.js +21 -15
  75. package/dist/lib/parsing-utils.d.ts +1 -1
  76. package/dist/lib/parsing-utils.js +7 -11
  77. package/dist/lib/plugins/codeBlockingPlugin.d.ts +1 -1
  78. package/dist/lib/plugins/codeBlockingPlugin.js +5 -8
  79. package/dist/lib/plugins/codeCheckingPlugin.d.ts +1 -1
  80. package/dist/lib/plugins/codeCheckingPlugin.js +4 -9
  81. package/dist/lib/plugins/devBuildPlugin.d.ts +2 -2
  82. package/dist/lib/plugins/devBuildPlugin.js +74 -99
  83. package/dist/lib/plugins/friendlyLoggingPlugin.d.ts +2 -2
  84. package/dist/lib/plugins/friendlyLoggingPlugin.js +4 -12
  85. package/dist/lib/plugins/manifestPlugin.d.ts +1 -1
  86. package/dist/lib/plugins/manifestPlugin.js +46 -26
  87. package/dist/lib/plugins/relevantModulesPlugin.d.ts +2 -2
  88. package/dist/lib/plugins/relevantModulesPlugin.js +4 -7
  89. package/dist/lib/server.d.ts +7 -2
  90. package/dist/lib/server.js +85 -84
  91. package/dist/lib/types.d.ts +1 -1
  92. package/dist/lib/types.js +4 -7
  93. package/dist/lib/utils.d.ts +1 -1
  94. package/dist/lib/utils.js +23 -40
  95. package/package.json +44 -31
@@ -0,0 +1,455 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { isExtensionFileMock } from "../../__mocks__/isExtensionFile.js";
3
+ vi.mock('../../utils', async () => {
4
+ const originalModule = (await vi.importActual('../../utils'));
5
+ return {
6
+ ...originalModule,
7
+ isExtensionFile: isExtensionFileMock,
8
+ };
9
+ });
10
+ vi.mock('fs', () => {
11
+ const readFileSyncMock = vi.fn((filename) => JSON.stringify({
12
+ filename,
13
+ }));
14
+ return {
15
+ default: {
16
+ readFileSync: readFileSyncMock,
17
+ },
18
+ readFileSync: readFileSyncMock,
19
+ };
20
+ });
21
+ import manifestPlugin from "../../plugins/manifestPlugin.js";
22
+ import fs from 'fs';
23
+ import { MANIFEST_FILE } from "../../constants.js";
24
+ import path from 'path';
25
+ const bundleEntry = {
26
+ facadeModuleId: 'facadeModuleId',
27
+ moduleIds: ['foo', 'bar', 'baz', 'node_modules/lodash'],
28
+ modules: {
29
+ foo: {
30
+ renderedExports: ['bar'],
31
+ },
32
+ bar: {
33
+ renderedExports: ['baz'],
34
+ },
35
+ baz: {
36
+ renderedExports: [],
37
+ },
38
+ 'node_modules/lodash': {
39
+ renderedExports: ['get'],
40
+ },
41
+ },
42
+ };
43
+ describe('manifestPlugin', () => {
44
+ let logger;
45
+ let options;
46
+ let bundle;
47
+ describe('metadata', () => {
48
+ beforeEach(() => {
49
+ logger = {
50
+ info: vi.fn(),
51
+ error: vi.fn(),
52
+ debug: vi.fn(),
53
+ warn: vi.fn(),
54
+ };
55
+ options = {
56
+ output: 'SomeFileName.js',
57
+ extensionPath: '/some/path/to/the/project',
58
+ logger,
59
+ };
60
+ bundle = {
61
+ [options.output]: bundleEntry,
62
+ };
63
+ });
64
+ afterEach(() => {
65
+ vi.clearAllMocks();
66
+ });
67
+ it('should return the correct metadata', () => {
68
+ const plugin = manifestPlugin({ output: '', logger });
69
+ expect(plugin).toStrictEqual(expect.objectContaining({
70
+ name: 'ui-extensions-manifest-generation-plugin',
71
+ enforce: 'post',
72
+ generateBundle: expect.any(Function),
73
+ }));
74
+ });
75
+ it('should handle extensionPath without trailing slash', () => {
76
+ const plugin = manifestPlugin({
77
+ ...options,
78
+ extensionPath: '/mock/extension/path',
79
+ });
80
+ // @ts-expect-error TS thinks these aren't functions
81
+ plugin.emitFile = vi.fn();
82
+ // @ts-expect-error TS thinks these aren't functions
83
+ plugin.generateBundle({}, bundle);
84
+ expect(fs.readFileSync).toHaveBeenCalledWith('/mock/extension/path/package-lock.json');
85
+ });
86
+ it('should handle extensionPath with trailing slash', () => {
87
+ const plugin = manifestPlugin({
88
+ ...options,
89
+ extensionPath: '/mock/extension/path/',
90
+ });
91
+ // @ts-expect-error TS thinks these aren't functions
92
+ plugin.emitFile = vi.fn();
93
+ // @ts-expect-error TS thinks these aren't functions
94
+ plugin.generateBundle({}, bundle);
95
+ expect(fs.readFileSync).toHaveBeenCalledWith('/mock/extension/path/package-lock.json');
96
+ });
97
+ });
98
+ describe('generateBundle', () => {
99
+ it('should load the package-lock.json file when no extensionsPath is provided', () => {
100
+ const plugin = manifestPlugin({ ...options, extensionPath: undefined });
101
+ // @ts-expect-error TS thinks these aren't functions
102
+ plugin.emitFile = vi.fn(); // Mock plugin function that gets bound
103
+ // @ts-expect-error TS thinks these aren't functions
104
+ plugin.generateBundle({}, bundle);
105
+ expect(fs.readFileSync).toHaveBeenCalledWith(expect.stringMatching(/.*\/package-lock.json$/));
106
+ expect(fs.readFileSync).not.toHaveBeenCalledWith(expect.stringMatching(/.*\/package.json$/));
107
+ });
108
+ it('should load the package-lock.json file when extensionsPath is provided', () => {
109
+ const plugin = manifestPlugin(options);
110
+ // @ts-expect-error TS thinks these aren't functions
111
+ plugin.emitFile = vi.fn(); // Mock plugin function that gets bound
112
+ // @ts-expect-error TS thinks these aren't functions
113
+ plugin.generateBundle({}, bundle);
114
+ expect(fs.readFileSync).toHaveBeenCalledWith(`${options.extensionPath}/package-lock.json`);
115
+ expect(fs.readFileSync).not.toHaveBeenCalledWith(`${options.extensionPath}/package.json`);
116
+ });
117
+ it('should fallback to loading the package.json file if no lockfile is present', () => {
118
+ const plugin = manifestPlugin(options);
119
+ // @ts-expect-error TS thinks these aren't functions
120
+ plugin.emitFile = vi.fn(); // Mock plugin function that gets bound
121
+ // @ts-expect-error TS thinks mockImplementationOnce doesn't exist on readFileSync
122
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
123
+ if (filename.includes('package-lock.json')) {
124
+ throw new Error('YOU SHALL NOT PASS!');
125
+ }
126
+ return JSON.stringify({ filename });
127
+ });
128
+ // @ts-expect-error TS thinks these aren't functions
129
+ plugin.generateBundle({}, bundle);
130
+ expect(fs.readFileSync).toHaveBeenCalledWith(`${options.extensionPath}/package-lock.json`);
131
+ expect(fs.readFileSync).toHaveBeenCalledWith(`${options.extensionPath}/package.json`);
132
+ });
133
+ it('should call emitFile with the manifest contents', () => {
134
+ const plugin = manifestPlugin(options);
135
+ let actualSource = '';
136
+ // @ts-expect-error TS thinks these aren't functions
137
+ plugin.emitFile = vi.fn(({ source }) => {
138
+ actualSource = source;
139
+ }); // Mock plugin function that gets bound
140
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
141
+ return JSON.stringify({ filename });
142
+ });
143
+ // @ts-expect-error TS thinks these aren't functions
144
+ plugin.generateBundle({}, bundle);
145
+ // @ts-expect-error TS thinks these aren't functions
146
+ expect(plugin.emitFile).toHaveBeenCalledTimes(1);
147
+ // @ts-expect-error TS thinks these aren't functions
148
+ expect(plugin.emitFile).toHaveBeenCalledWith(expect.objectContaining({
149
+ type: 'asset',
150
+ fileName: `${path.parse(options.output).name}-${MANIFEST_FILE}`,
151
+ }));
152
+ expect(JSON.parse(actualSource)).toEqual({
153
+ dataDeps: [],
154
+ entry: bundleEntry.facadeModuleId,
155
+ modules: {
156
+ internal: [
157
+ {
158
+ module: 'foo',
159
+ renderedExports: bundleEntry.modules.foo.renderedExports,
160
+ },
161
+ {
162
+ module: 'bar',
163
+ renderedExports: bundleEntry.modules.bar.renderedExports,
164
+ },
165
+ {
166
+ module: 'baz',
167
+ renderedExports: bundleEntry.modules.baz.renderedExports,
168
+ },
169
+ ],
170
+ external: [
171
+ {
172
+ module: 'node_modules/lodash',
173
+ renderedExports: bundleEntry.modules['node_modules/lodash'].renderedExports,
174
+ },
175
+ ],
176
+ },
177
+ package: {
178
+ filename: expect.stringMatching(/.*\/package-lock.json$/),
179
+ },
180
+ variables: {},
181
+ });
182
+ });
183
+ it('should generate manifest for multiple bundles', () => {
184
+ const plugin = manifestPlugin(options);
185
+ let actualSource = '';
186
+ // @ts-expect-error TS thinks these aren't functions
187
+ plugin.emitFile = vi.fn(({ source }) => {
188
+ actualSource = source;
189
+ }); // Mock plugin function that gets bound
190
+ const multiBundle = {
191
+ 'bundle1.js': bundleEntry,
192
+ 'bundle2.js': {
193
+ facadeModuleId: 'facadeModuleId2',
194
+ moduleIds: ['foo2', 'bar2'],
195
+ modules: {
196
+ foo2: {
197
+ renderedExports: ['bar2'],
198
+ },
199
+ bar2: {
200
+ renderedExports: [],
201
+ },
202
+ },
203
+ },
204
+ };
205
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
206
+ return JSON.stringify({ filename });
207
+ });
208
+ // @ts-expect-error TS thinks these aren't functions
209
+ plugin.generateBundle({}, multiBundle);
210
+ // @ts-expect-error TS thinks these aren't functions
211
+ expect(plugin.emitFile).toHaveBeenCalledTimes(1);
212
+ // @ts-expect-error TS thinks these aren't functions
213
+ expect(plugin.emitFile).toHaveBeenCalledWith(expect.objectContaining({
214
+ type: 'asset',
215
+ fileName: `${path.parse(options.output).name}-${MANIFEST_FILE}`,
216
+ }));
217
+ const expectedManifest = {
218
+ 'bundle1.js': {
219
+ entry: 'facadeModuleId',
220
+ modules: {
221
+ internal: [
222
+ {
223
+ module: 'foo',
224
+ renderedExports: bundleEntry.modules.foo.renderedExports,
225
+ },
226
+ {
227
+ module: 'bar',
228
+ renderedExports: bundleEntry.modules.bar.renderedExports,
229
+ },
230
+ {
231
+ module: 'baz',
232
+ renderedExports: bundleEntry.modules.baz.renderedExports,
233
+ },
234
+ ],
235
+ external: [
236
+ {
237
+ module: 'node_modules/lodash',
238
+ renderedExports: bundleEntry.modules['node_modules/lodash'].renderedExports,
239
+ },
240
+ ],
241
+ },
242
+ },
243
+ 'bundle2.js': {
244
+ entry: 'facadeModuleId2',
245
+ modules: {
246
+ internal: [
247
+ {
248
+ module: 'foo2',
249
+ renderedExports: multiBundle['bundle2.js'].modules.foo2.renderedExports,
250
+ },
251
+ {
252
+ module: 'bar2',
253
+ renderedExports: multiBundle['bundle2.js'].modules.bar2.renderedExports,
254
+ },
255
+ ],
256
+ external: [],
257
+ },
258
+ },
259
+ dataDeps: [],
260
+ package: {
261
+ filename: expect.stringMatching(/.*\/package-lock.json$/),
262
+ },
263
+ variables: {},
264
+ };
265
+ expect(JSON.parse(actualSource)).toEqual(expectedManifest);
266
+ });
267
+ it('should include variables from manifestConfig when provided', () => {
268
+ const manifestConfig = {
269
+ variables: {
270
+ ENV: 'development',
271
+ DEBUG: true,
272
+ },
273
+ };
274
+ const optionsWithManifestConfig = { ...options, manifestConfig };
275
+ const plugin = manifestPlugin(optionsWithManifestConfig);
276
+ let actualSource = '';
277
+ // @ts-expect-error TS thinks these aren't functions
278
+ plugin.emitFile = vi.fn(({ source }) => {
279
+ actualSource = source;
280
+ });
281
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
282
+ return JSON.stringify({ filename });
283
+ });
284
+ // @ts-expect-error TS thinks these aren't functions
285
+ plugin.generateBundle({}, bundle);
286
+ expect(JSON.parse(actualSource)).toEqual({
287
+ dataDeps: [],
288
+ entry: bundleEntry.facadeModuleId,
289
+ modules: {
290
+ internal: [
291
+ {
292
+ module: 'foo',
293
+ renderedExports: bundleEntry.modules.foo.renderedExports,
294
+ },
295
+ {
296
+ module: 'bar',
297
+ renderedExports: bundleEntry.modules.bar.renderedExports,
298
+ },
299
+ {
300
+ module: 'baz',
301
+ renderedExports: bundleEntry.modules.baz.renderedExports,
302
+ },
303
+ ],
304
+ external: [
305
+ {
306
+ module: 'node_modules/lodash',
307
+ renderedExports: bundleEntry.modules['node_modules/lodash'].renderedExports,
308
+ },
309
+ ],
310
+ },
311
+ package: {
312
+ filename: expect.stringMatching(/.*\/package-lock.json$/),
313
+ },
314
+ variables: {
315
+ ENV: 'development',
316
+ DEBUG: true,
317
+ },
318
+ });
319
+ });
320
+ it('should handle null variables in manifestConfig', () => {
321
+ const manifestConfig = {
322
+ variables: null,
323
+ };
324
+ const optionsWithManifestConfig = { ...options, manifestConfig };
325
+ const plugin = manifestPlugin(optionsWithManifestConfig);
326
+ let actualSource = '';
327
+ // @ts-expect-error TS thinks these aren't functions
328
+ plugin.emitFile = vi.fn(({ source }) => {
329
+ actualSource = source;
330
+ });
331
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
332
+ return JSON.stringify({ filename });
333
+ });
334
+ // @ts-expect-error TS thinks these aren't functions
335
+ plugin.generateBundle({}, bundle);
336
+ const manifest = JSON.parse(actualSource);
337
+ expect(manifest.variables).toEqual({});
338
+ });
339
+ it('should handle undefined manifestConfig', () => {
340
+ const optionsWithoutManifestConfig = {
341
+ ...options,
342
+ manifestConfig: undefined,
343
+ };
344
+ const plugin = manifestPlugin(optionsWithoutManifestConfig);
345
+ let actualSource = '';
346
+ // @ts-expect-error TS thinks these aren't functions
347
+ plugin.emitFile = vi.fn(({ source }) => {
348
+ actualSource = source;
349
+ });
350
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
351
+ return JSON.stringify({ filename });
352
+ });
353
+ // @ts-expect-error TS thinks these aren't functions
354
+ plugin.generateBundle({}, bundle);
355
+ const manifest = JSON.parse(actualSource);
356
+ expect(manifest.variables).toEqual({});
357
+ });
358
+ it('should handle empty variables object vs undefined variables', () => {
359
+ const manifestConfigWithEmptyVars = {
360
+ variables: {},
361
+ };
362
+ const plugin1 = manifestPlugin({
363
+ ...options,
364
+ manifestConfig: manifestConfigWithEmptyVars,
365
+ });
366
+ let actualSource1 = '';
367
+ // @ts-expect-error TS thinks these aren't functions
368
+ plugin1.emitFile = vi.fn(({ source }) => {
369
+ actualSource1 = source;
370
+ });
371
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
372
+ return JSON.stringify({ filename });
373
+ });
374
+ // @ts-expect-error TS thinks these aren't functions
375
+ plugin1.generateBundle({}, bundle);
376
+ const manifest1 = JSON.parse(actualSource1);
377
+ expect(manifest1.variables).toEqual({});
378
+ const manifestConfigWithUndefinedVars = {
379
+ variables: undefined,
380
+ };
381
+ const plugin2 = manifestPlugin({
382
+ ...options,
383
+ manifestConfig: manifestConfigWithUndefinedVars,
384
+ });
385
+ let actualSource2 = '';
386
+ // @ts-expect-error TS thinks these aren't functions
387
+ plugin2.emitFile = vi.fn(({ source }) => {
388
+ actualSource2 = source;
389
+ });
390
+ vi.mocked(fs.readFileSync).mockImplementationOnce((filename) => {
391
+ return JSON.stringify({ filename });
392
+ });
393
+ // @ts-expect-error TS thinks these aren't functions
394
+ plugin2.generateBundle({}, bundle);
395
+ const manifest2 = JSON.parse(actualSource2);
396
+ expect(manifest2.variables).toEqual({});
397
+ });
398
+ });
399
+ describe('transform', () => {
400
+ let plugin;
401
+ const extensionPath = '/mock/extension/path';
402
+ beforeEach(() => {
403
+ logger = {
404
+ info: vi.fn(),
405
+ error: vi.fn(),
406
+ debug: vi.fn(),
407
+ warn: vi.fn(),
408
+ };
409
+ plugin = manifestPlugin({ output: 'output.js', extensionPath, logger });
410
+ });
411
+ afterEach(() => {
412
+ vi.clearAllMocks();
413
+ });
414
+ it('should parse extension files and collect data dependencies', () => {
415
+ const code = 'valid code';
416
+ const filename = `${extensionPath}/someFile.ts`;
417
+ // @ts-expect-error It does exist, I promise
418
+ plugin.parse = vi.fn(() => {
419
+ return {};
420
+ });
421
+ // @ts-expect-error Deep breath TS, it's ok
422
+ const result = plugin.transform(code, filename);
423
+ // @ts-expect-error It does exist, I promise
424
+ expect(plugin.parse).toBeCalledTimes(1);
425
+ // @ts-expect-error It does exist, I promise
426
+ expect(plugin.parse).toBeCalledWith(code);
427
+ expect(result.code).toBe(code);
428
+ });
429
+ it('should not parse non-extension files', () => {
430
+ const code = 'valid code';
431
+ const filename = 'node_modules/someFile.ts';
432
+ // @ts-expect-error It does exist, I promise
433
+ plugin.parse = vi.fn(() => {
434
+ return {};
435
+ });
436
+ // @ts-expect-error Deep breath TS, it's ok
437
+ const result = plugin.transform(code, filename);
438
+ // @ts-expect-error It does exist, I promise
439
+ expect(plugin.parse).not.toHaveBeenCalled();
440
+ expect(result.code).toBe(code);
441
+ });
442
+ it('should log an error if parsing fails', () => {
443
+ const code = 'invalid code';
444
+ const filename = `${extensionPath}/someFile.ts`;
445
+ // @ts-expect-error It does exist, I promise
446
+ plugin.parse = vi.fn(() => {
447
+ throw new Error('Parsing error');
448
+ });
449
+ // @ts-expect-error Deep breath TS, it's ok
450
+ const result = plugin.transform(code, filename);
451
+ expect(logger.error).toHaveBeenCalledWith(`Unable to parse source code for ${filename}, Error: Parsing error`);
452
+ expect(result.code).toBe(code);
453
+ });
454
+ });
455
+ });
@@ -0,0 +1,81 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import relevantModulesPlugin, { getRelevantModules, } from "../../plugins/relevantModulesPlugin.js";
3
+ describe('manifestPlugin', () => {
4
+ let logger;
5
+ let options;
6
+ let bundle;
7
+ beforeEach(() => {
8
+ logger = {
9
+ info: vi.fn(),
10
+ debug: vi.fn(),
11
+ warn: vi.fn(),
12
+ error: vi.fn(),
13
+ };
14
+ options = {
15
+ output: 'SomeFileName.js',
16
+ logger,
17
+ };
18
+ bundle = {
19
+ [options.output]: {
20
+ moduleIds: [
21
+ 'A.js',
22
+ 'B.js',
23
+ 'C.js',
24
+ 'node_modules/lodash',
25
+ 'node_modules/react',
26
+ ],
27
+ },
28
+ // @ts-expect-error We don't need all the other fields
29
+ empty: {
30
+ moduleIds: [],
31
+ },
32
+ };
33
+ });
34
+ afterEach(() => {
35
+ vi.clearAllMocks();
36
+ });
37
+ describe('metadata', () => {
38
+ it('should return the correct metadata', () => {
39
+ const plugin = relevantModulesPlugin(options);
40
+ expect(plugin).toStrictEqual(expect.objectContaining({
41
+ name: 'ui-extensions-relevant-modules-plugin',
42
+ generateBundle: expect.any(Function),
43
+ }));
44
+ });
45
+ });
46
+ describe('getRelevantModules', () => {
47
+ it('should return an empty array instead of undefined', () => {
48
+ const actual = getRelevantModules('this property does not exist');
49
+ expect(actual).toStrictEqual([]);
50
+ });
51
+ });
52
+ describe('generateBundle', () => {
53
+ it('should not update the relevantModules when output is not found in the bundle', () => {
54
+ const plugin = relevantModulesPlugin(options);
55
+ // @ts-expect-error TS thinks this isn't a function
56
+ plugin.generateBundle({}, {
57
+ output: 'no modules for this string',
58
+ });
59
+ const actual = getRelevantModules('something wrong');
60
+ expect(actual).toStrictEqual([]);
61
+ expect(logger.error).toBeCalledTimes(1);
62
+ expect(logger.error).toHaveBeenCalledWith('Invalid bundle format, please try saving the extension again. If the problem persists try restarting `hs project dev`');
63
+ });
64
+ it('should not update the relevantModules when moduleIds is not defined', () => {
65
+ const plugin = relevantModulesPlugin({ output: 'empty', logger });
66
+ // @ts-expect-error TS thinks this isn't a function
67
+ plugin.generateBundle({}, bundle);
68
+ const actual = getRelevantModules(options.output);
69
+ expect(actual).toStrictEqual([]);
70
+ expect(logger.error).toBeCalledTimes(1);
71
+ expect(logger.error).toHaveBeenCalledWith('Unable to determine relevant files to watch, please try saving the extension again. If the problem persists try restarting `hs project dev`');
72
+ });
73
+ it('should update the relevantModules when generateBundle is called', () => {
74
+ const plugin = relevantModulesPlugin(options);
75
+ // @ts-expect-error TS thinks this isn't a function
76
+ plugin.generateBundle({}, bundle);
77
+ const actual = getRelevantModules(options.output);
78
+ expect(actual).toStrictEqual(['A.js', 'B.js', 'C.js']);
79
+ });
80
+ });
81
+ });
@@ -0,0 +1 @@
1
+ export {};