@axinom/mosaic-cli 0.14.2-rc.8 → 0.15.0-rc.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 (76) hide show
  1. package/package.json +6 -5
  2. package/src/cli/README.md +60 -0
  3. package/src/cli/index.ts +47 -0
  4. package/src/commands/apply-templates/apply-templates.spec.ts +623 -0
  5. package/src/commands/apply-templates/apply-templates.ts +494 -0
  6. package/src/commands/apply-templates/bitwarden-vault.ts +130 -0
  7. package/src/commands/apply-templates/index.ts +1 -0
  8. package/src/commands/create-extension-config/create-extension-config.ts +92 -0
  9. package/src/commands/create-extension-config/index.ts +23 -0
  10. package/src/commands/get-access-token/get-access-token-options.ts +9 -0
  11. package/src/commands/get-access-token/get-dev-access-token.ts +32 -0
  12. package/src/commands/get-access-token/index.ts +66 -0
  13. package/src/commands/graphql-diff.ts +143 -0
  14. package/src/commands/msg-codegen/codegen.ts +891 -0
  15. package/src/commands/msg-codegen/index.ts +48 -0
  16. package/src/commands/msg-codegen/lint.ts +84 -0
  17. package/src/commands/msg-codegen/message-codegen-options.ts +7 -0
  18. package/src/commands/msg-diff/asyncapi-override.ts +31 -0
  19. package/src/commands/msg-diff/git-checkout-tmp.ts +73 -0
  20. package/src/commands/msg-diff/index.ts +53 -0
  21. package/src/commands/msg-diff/message-diff-options.ts +7 -0
  22. package/src/commands/msg-diff/msg-diff.spec.ts +412 -0
  23. package/src/commands/msg-diff/msg-diff.ts +364 -0
  24. package/src/commands/msg-diff/test-resources/0/1-asyncapi.yml +38 -0
  25. package/src/commands/msg-diff/test-resources/0/2-asyncapi.yml +36 -0
  26. package/src/commands/msg-diff/test-resources/0/command.json +74 -0
  27. package/src/commands/msg-diff/test-resources/0/event.json +25 -0
  28. package/src/commands/msg-diff/test-resources/1/1-asyncapi.yml +25 -0
  29. package/src/commands/msg-diff/test-resources/1/moved-event.json +25 -0
  30. package/src/commands/msg-diff/test-resources/common.json +20 -0
  31. package/src/commands/pg-dump/README.md +21 -0
  32. package/src/commands/pg-dump/generate.ts +146 -0
  33. package/src/commands/pg-dump/index.ts +39 -0
  34. package/src/commands/pg-dump/pg-dump-options.ts +6 -0
  35. package/src/commands/publish-schema-to-db/README.md +130 -0
  36. package/src/commands/publish-schema-to-db/abstractions/base-smart-tags.ts +6 -0
  37. package/src/commands/publish-schema-to-db/abstractions/index.ts +5 -0
  38. package/src/commands/publish-schema-to-db/abstractions/pg-column.ts +31 -0
  39. package/src/commands/publish-schema-to-db/abstractions/pg-fk-column.ts +6 -0
  40. package/src/commands/publish-schema-to-db/abstractions/pg-table.ts +55 -0
  41. package/src/commands/publish-schema-to-db/abstractions/pg-type.ts +8 -0
  42. package/src/commands/publish-schema-to-db/content-entity-model.ts +93 -0
  43. package/src/commands/publish-schema-to-db/generate.ts +82 -0
  44. package/src/commands/publish-schema-to-db/index.ts +49 -0
  45. package/src/commands/publish-schema-to-db/jest.config.js +9 -0
  46. package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.spec.ts +42 -0
  47. package/src/commands/publish-schema-to-db/pg-models/columns/fk-column.ts +41 -0
  48. package/src/commands/publish-schema-to-db/pg-models/columns/index.ts +4 -0
  49. package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.spec.ts +47 -0
  50. package/src/commands/publish-schema-to-db/pg-models/columns/pk-column.ts +34 -0
  51. package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.spec.ts +65 -0
  52. package/src/commands/publish-schema-to-db/pg-models/columns/primitive-column.ts +62 -0
  53. package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.spec.ts +24 -0
  54. package/src/commands/publish-schema-to-db/pg-models/columns/virtual-fk-column.ts +34 -0
  55. package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.spec.ts +182 -0
  56. package/src/commands/publish-schema-to-db/pg-models/json-schema-parse-utils.ts +166 -0
  57. package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.spec.ts +19 -0
  58. package/src/commands/publish-schema-to-db/pg-models/pg-sql-gen-utils.ts +237 -0
  59. package/src/commands/publish-schema-to-db/pg-models/pgl-utils.spec.ts +19 -0
  60. package/src/commands/publish-schema-to-db/pg-models/pgl-utils.ts +115 -0
  61. package/src/commands/publish-schema-to-db/pg-models/tables/content-entity-table.ts +104 -0
  62. package/src/commands/publish-schema-to-db/pg-models/tables/index.ts +3 -0
  63. package/src/commands/publish-schema-to-db/pg-models/tables/object-property-table.ts +113 -0
  64. package/src/commands/publish-schema-to-db/pg-models/tables/relations-table.ts +115 -0
  65. package/src/commands/publish-schema-to-db/postprocessors/collection-postprocessor.ts +33 -0
  66. package/src/commands/publish-schema-to-db/postprocessors/content-entity-model-postprocessor.ts +13 -0
  67. package/src/commands/publish-schema-to-db/postprocessors/episode-postprocessor.ts +37 -0
  68. package/src/commands/publish-schema-to-db/postprocessors/index.ts +6 -0
  69. package/src/commands/publish-schema-to-db/postprocessors/movie-postprocessor.ts +30 -0
  70. package/src/commands/publish-schema-to-db/postprocessors/postprocessing-utils.ts +21 -0
  71. package/src/commands/publish-schema-to-db/postprocessors/season-postprocessor.ts +37 -0
  72. package/src/commands/publish-schema-to-db/postprocessors/tvshow-postprocessor.ts +30 -0
  73. package/src/commands/publish-schema-to-db/publish-schema-to-db-options.ts +15 -0
  74. package/src/commands/publish-schema-to-db/types/sql-formatter.d.ts +10 -0
  75. package/src/exports.ts +2 -0
  76. package/src/index.ts +1 -0
@@ -0,0 +1,412 @@
1
+ import { AsyncAPIDocument, parse } from '@asyncapi/parser';
2
+ import * as fs from 'fs';
3
+ import 'jest-extended';
4
+ import { MessageDiffOptions } from './message-diff-options';
5
+ import { MessageDiff } from './msg-diff';
6
+
7
+ const resources = `${__dirname}/test-resources`;
8
+
9
+ describe('sanity', () => {
10
+ const options: MessageDiffOptions = {
11
+ inputDir: resources,
12
+ filePattern: '.*(-asyncapi).(json|yaml|yml)',
13
+ excludePattern: undefined,
14
+ branch: 'xxx',
15
+ verbose: false,
16
+ };
17
+ let msgDiff: MessageDiff;
18
+ let consoleSpy: jest.SpyInstance<
19
+ void,
20
+ [message?: any, ...optionalParams: any[]]
21
+ >;
22
+
23
+ const loadDocument = async (
24
+ file: string,
25
+ editJson?: (any) => void,
26
+ ): Promise<AsyncAPIDocument> => {
27
+ const doc = await parse((await fs.promises.readFile(file)).toString(), {
28
+ path: file,
29
+ });
30
+ if (!editJson) {
31
+ return doc;
32
+ }
33
+ const json = doc.json();
34
+ editJson(json);
35
+ return parse(json);
36
+ };
37
+
38
+ beforeEach(async () => {
39
+ consoleSpy = jest.spyOn(console, 'log');
40
+ msgDiff = new MessageDiff(options);
41
+ });
42
+
43
+ afterEach(async () => {
44
+ jest.restoreAllMocks();
45
+ });
46
+
47
+ describe('walk', () => {
48
+ it('resources sanity', async () => {
49
+ console.log({ resources });
50
+
51
+ // Assert
52
+ expect(fs.existsSync(`${resources}/0/1-asyncapi.yml`)).toBeTrue();
53
+ expect(fs.existsSync(`${resources}/0/event.json`)).toBeTrue();
54
+ });
55
+
56
+ it('compare with self -> same', async () => {
57
+ // Act
58
+ await msgDiff.walk(`${resources}/0`, `${resources}/0`);
59
+
60
+ // Assert
61
+ expect(msgDiff.results).toEqual({
62
+ skipped: 0,
63
+ same: 6,
64
+ changed: 0,
65
+ breaking: 0,
66
+ });
67
+ });
68
+
69
+ it('remove file -> breaking', async () => {
70
+ // Act
71
+ await msgDiff.walk(`${resources}/0`, `${resources}/1`);
72
+
73
+ // Assert
74
+ expect(msgDiff.results).toEqual({
75
+ skipped: 0,
76
+ same: 1,
77
+ changed: 0,
78
+ breaking: 2,
79
+ });
80
+ expect(consoleSpy).toHaveBeenCalledWith(
81
+ expect.stringContaining(
82
+ '❌ File not found. This document may have been removed. Assuming this is a breaking change.',
83
+ ),
84
+ );
85
+ expect(consoleSpy).toHaveBeenCalledWith(
86
+ expect.stringContaining(' ✖ remove /channels/cmd-channel'),
87
+ );
88
+ });
89
+
90
+ it('add file -> ignored', async () => {
91
+ // Act
92
+ await msgDiff.walk(`${resources}/1`, `${resources}/0`);
93
+
94
+ // Assert
95
+ expect(msgDiff.results).toEqual({
96
+ skipped: 0,
97
+ same: 1,
98
+ changed: 1,
99
+ breaking: 0,
100
+ });
101
+ });
102
+ });
103
+
104
+ describe('documentDiff', () => {
105
+ it('remove channel -> breaking', async () => {
106
+ // Arrange
107
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
108
+ const document2 = await loadDocument(
109
+ `${resources}/0/1-asyncapi.yml`,
110
+ (json) => {
111
+ // remove a channel
112
+ delete json.channels['evt-channel'];
113
+ },
114
+ );
115
+
116
+ // Act
117
+ const result = await msgDiff.documentDiff(document1, document2);
118
+
119
+ // Assert
120
+ expect(result).toEqual('breaking');
121
+ });
122
+
123
+ it('remove event -> breaking', async () => {
124
+ // Arrange
125
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
126
+ const document2 = await loadDocument(
127
+ `${resources}/0/1-asyncapi.yml`,
128
+ (json) => {
129
+ // remove an event
130
+ delete json.channels['evt-channel'].publish.message;
131
+ },
132
+ );
133
+
134
+ // Act
135
+ const result = await msgDiff.documentDiff(document1, document2);
136
+
137
+ // Assert
138
+ expect(result).toEqual('breaking');
139
+ });
140
+
141
+ it('rename channel -> breaking', async () => {
142
+ // Arrange
143
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
144
+ const document2 = await loadDocument(
145
+ `${resources}/0/1-asyncapi.yml`,
146
+ (json) => {
147
+ // rename a channel
148
+ json.channels['evt-channel-CHANGE'] = json.channels['evt-channel'];
149
+ delete json.channels['evt-channel'];
150
+ },
151
+ );
152
+
153
+ // Act
154
+ const result = await msgDiff.documentDiff(document1, document2);
155
+
156
+ // Assert
157
+ expect(result).toEqual('breaking');
158
+ });
159
+
160
+ it('rename queue -> breaking', async () => {
161
+ // Arrange
162
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
163
+ const document2 = await loadDocument(
164
+ `${resources}/0/1-asyncapi.yml`,
165
+ (json) => {
166
+ // rename a queue
167
+ json.channels['evt-channel'].bindings.amqp.queue.name =
168
+ 'differentqueue';
169
+ },
170
+ );
171
+
172
+ // Act
173
+ const result = await msgDiff.documentDiff(document1, document2);
174
+
175
+ // Assert
176
+ expect(result).toEqual('breaking');
177
+ });
178
+
179
+ it('add channel -> changed', async () => {
180
+ // Arrange
181
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
182
+ const document2 = await loadDocument(
183
+ `${resources}/0/1-asyncapi.yml`,
184
+ (json) => {
185
+ // create a new
186
+ json.channels['evt-channel-NEW'] = json.channels['evt-channel'];
187
+ },
188
+ );
189
+
190
+ // Act
191
+ const result = await msgDiff.documentDiff(document1, document2);
192
+
193
+ // Assert
194
+ expect(result).toEqual('changed');
195
+ });
196
+
197
+ it('change info -> changed', async () => {
198
+ // Arrange
199
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
200
+ const document2 = await loadDocument(
201
+ `${resources}/0/1-asyncapi.yml`,
202
+ (json) => {
203
+ // non breaking changes
204
+ json.info.title = 'My new title';
205
+ json.info.description = 'My new description';
206
+ },
207
+ );
208
+
209
+ // Act
210
+ const result = await msgDiff.documentDiff(document1, document2);
211
+
212
+ // Assert
213
+ expect(result).toEqual('changed');
214
+ });
215
+
216
+ it('change x-service-id -> breaking', async () => {
217
+ // Arrange
218
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
219
+ const document2 = await loadDocument(
220
+ `${resources}/0/1-asyncapi.yml`,
221
+ (json) => {
222
+ // breaking change
223
+ json['x-service-id'] = 'my-new-service-id';
224
+ },
225
+ );
226
+
227
+ // Act
228
+ const result = await msgDiff.documentDiff(document1, document2);
229
+
230
+ // Assert
231
+ expect(result).toEqual('breaking');
232
+ });
233
+ });
234
+
235
+ describe('payloadDiff', () => {
236
+ it('unsupported schema version -> skipped', async () => {
237
+ // Arrange
238
+ const document1 = await loadDocument(
239
+ `${resources}/0/1-asyncapi.yml`,
240
+ (json) => {
241
+ const schema = json.channels['evt-channel'].publish.message.payload;
242
+ schema.$schema = 'http://json-schema.org/draft-04/schema#';
243
+ },
244
+ );
245
+ const document2 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
246
+
247
+ // Act
248
+ const result = await msgDiff.payloadDiff(
249
+ document1.channels()['evt-channel'],
250
+ document2.channels()['evt-channel'],
251
+ );
252
+
253
+ // Assert
254
+ expect(result).toEqual('skipped');
255
+ expect(consoleSpy).toHaveBeenCalledWith(
256
+ expect.stringContaining(
257
+ 'WARNING: Unsupported JsonSchema version. This payload will be skipped.',
258
+ ),
259
+ );
260
+ });
261
+
262
+ it('add required to a field -> breaking', async () => {
263
+ // Arrange
264
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
265
+ const document2 = await loadDocument(
266
+ `${resources}/0/1-asyncapi.yml`,
267
+ (json) => {
268
+ const schema = json.channels['evt-channel'].publish.message.payload;
269
+ schema.required.push('is_public');
270
+ },
271
+ );
272
+
273
+ // Act
274
+ const result = await msgDiff.payloadDiff(
275
+ document1.channels()['evt-channel'],
276
+ document2.channels()['evt-channel'],
277
+ );
278
+
279
+ // Assert
280
+ expect(result).toEqual('breaking');
281
+ });
282
+
283
+ it('remove required from a field -> changed', async () => {
284
+ // Arrange
285
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
286
+ const document2 = await loadDocument(
287
+ `${resources}/0/1-asyncapi.yml`,
288
+ (json) => {
289
+ const schema = json.channels['evt-channel'].publish.message.payload;
290
+ schema.required = [];
291
+ },
292
+ );
293
+
294
+ // Act
295
+ const result = await msgDiff.payloadDiff(
296
+ document1.channels()['evt-channel'],
297
+ document2.channels()['evt-channel'],
298
+ );
299
+
300
+ // Assert
301
+ expect(result).toEqual('changed');
302
+ });
303
+
304
+ it('remove a non required field -> breaking', async () => {
305
+ // Arrange
306
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
307
+ const document2 = await loadDocument(
308
+ `${resources}/0/1-asyncapi.yml`,
309
+ (json) => {
310
+ const schema = json.channels['evt-channel'].publish.message.payload;
311
+ delete schema.properties.is_public;
312
+ },
313
+ );
314
+
315
+ // Act
316
+ const result = await msgDiff.payloadDiff(
317
+ document1.channels()['evt-channel'],
318
+ document2.channels()['evt-channel'],
319
+ );
320
+
321
+ // Assert
322
+ expect(result).toEqual('breaking');
323
+ });
324
+
325
+ it('add a non required field -> changed', async () => {
326
+ // Arrange
327
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
328
+ const document2 = await loadDocument(
329
+ `${resources}/0/1-asyncapi.yml`,
330
+ (json) => {
331
+ const schema = json.channels['evt-channel'].publish.message.payload;
332
+ schema.properties.new_field = {
333
+ description: 'blah',
334
+ type: 'boolean',
335
+ };
336
+ },
337
+ );
338
+
339
+ // Act
340
+ const result = await msgDiff.payloadDiff(
341
+ document1.channels()['evt-channel'],
342
+ document2.channels()['evt-channel'],
343
+ );
344
+
345
+ // Assert
346
+ expect(result).toEqual('changed');
347
+ });
348
+
349
+ it('extending type of a field -> changed', async () => {
350
+ // Arrange
351
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
352
+ const document2 = await loadDocument(
353
+ `${resources}/0/1-asyncapi.yml`,
354
+ (json) => {
355
+ const schema = json.channels['evt-channel'].publish.message.payload;
356
+ schema.properties.is_public.type = ['boolean', 'string'];
357
+ },
358
+ );
359
+
360
+ // Act
361
+ const result = await msgDiff.payloadDiff(
362
+ document1.channels()['evt-channel'],
363
+ document2.channels()['evt-channel'],
364
+ );
365
+
366
+ // Assert
367
+ expect(result).toEqual('changed');
368
+ });
369
+
370
+ it('reducing type of a field -> breaking', async () => {
371
+ // Arrange
372
+ const document1 = await loadDocument(
373
+ `${resources}/0/1-asyncapi.yml`,
374
+ (json) => {
375
+ const schema = json.channels['evt-channel'].publish.message.payload;
376
+ schema.properties.is_public.type = ['boolean', 'string'];
377
+ },
378
+ );
379
+ const document2 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
380
+
381
+ // Act
382
+ const result = await msgDiff.payloadDiff(
383
+ document1.channels()['evt-channel'],
384
+ document2.channels()['evt-channel'],
385
+ );
386
+
387
+ // Assert
388
+ expect(result).toEqual('breaking');
389
+ });
390
+
391
+ it('changing field description -> same', async () => {
392
+ // Arrange
393
+ const document1 = await loadDocument(`${resources}/0/1-asyncapi.yml`);
394
+ const document2 = await loadDocument(
395
+ `${resources}/0/1-asyncapi.yml`,
396
+ (json) => {
397
+ const schema = json.channels['evt-channel'].publish.message.payload;
398
+ schema.properties.is_public.description = 'My new description';
399
+ },
400
+ );
401
+
402
+ // Act
403
+ const result = await msgDiff.payloadDiff(
404
+ document1.channels()['evt-channel'],
405
+ document2.channels()['evt-channel'],
406
+ );
407
+
408
+ // Assert
409
+ expect(result).toEqual('same');
410
+ });
411
+ });
412
+ });