codify-plugin-lib 1.0.49 → 1.0.51

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.
@@ -1,13 +1,14 @@
1
1
  import { describe, expect, it } from 'vitest';
2
- import { ArrayStatefulParameter, StatefulParameter, StatefulParameterConfiguration } from './stateful-parameter.js';
2
+ import { ArrayStatefulParameter, StatefulParameter, StatefulParameterOptions } from './stateful-parameter.js';
3
3
  import { Plan } from './plan.js';
4
4
  import { spy } from 'sinon';
5
- import { ResourceOperation } from 'codify-schemas';
5
+ import { ParameterOperation, ResourceOperation } from 'codify-schemas';
6
6
  import { TestConfig, TestResource } from './resource.test.js';
7
+ import { TransformParameter } from './transform-parameter.js';
7
8
 
8
9
  class TestParameter extends StatefulParameter<TestConfig, string> {
9
- constructor(configuration?: StatefulParameterConfiguration<TestConfig>) {
10
- super(configuration ?? {
10
+ constructor(options?: StatefulParameterOptions<TestConfig>) {
11
+ super(options ?? {
11
12
  name: 'propA'
12
13
  })
13
14
  }
@@ -42,7 +43,9 @@ describe('Resource parameters tests', () => {
42
43
  constructor() {
43
44
  super({
44
45
  type: 'resource',
45
- statefulParameters: [statefulParameterSpy],
46
+ parameterOptions: {
47
+ propA: { statefulParameter: statefulParameterSpy }
48
+ },
46
49
  });
47
50
  }
48
51
  }
@@ -75,8 +78,8 @@ describe('Resource parameters tests', () => {
75
78
  constructor() {
76
79
  super({
77
80
  type: 'resource',
78
- statefulParameters: [statefulParameterSpy],
79
- parameterConfigurations: {
81
+ parameterOptions: {
82
+ propA: { statefulParameter: statefulParameterSpy },
80
83
  propB: { planOperation: ResourceOperation.MODIFY },
81
84
  }
82
85
  });
@@ -109,7 +112,9 @@ describe('Resource parameters tests', () => {
109
112
  constructor() {
110
113
  super({
111
114
  type: 'resource',
112
- statefulParameters: [statefulParameterSpy],
115
+ parameterOptions: {
116
+ propA: { statefulParameter: statefulParameterSpy },
117
+ },
113
118
  });
114
119
  }
115
120
 
@@ -140,7 +145,9 @@ describe('Resource parameters tests', () => {
140
145
  constructor() {
141
146
  super({
142
147
  type: 'resource',
143
- statefulParameters: [statefulParameterSpy],
148
+ parameterOptions: {
149
+ propA: { statefulParameter: statefulParameterSpy }
150
+ },
144
151
  });
145
152
  }
146
153
 
@@ -181,7 +188,9 @@ describe('Resource parameters tests', () => {
181
188
  constructor() {
182
189
  super({
183
190
  type: 'resource',
184
- statefulParameters: [statefulParameterSpy],
191
+ parameterOptions: {
192
+ propA: { statefulParameter: statefulParameterSpy }
193
+ },
185
194
  });
186
195
  }
187
196
 
@@ -198,4 +207,250 @@ describe('Resource parameters tests', () => {
198
207
  }
199
208
  })
200
209
  })
210
+
211
+ it('Plans stateful parameters in the order specified', async () => {
212
+ const statefulParameterA = spy(new class extends TestParameter {
213
+ async refresh(): Promise<any | null> {
214
+ return performance.now()
215
+ }
216
+ });
217
+
218
+ const statefulParameterB = spy(new class extends TestParameter {
219
+ async refresh(): Promise<any | null> {
220
+ return performance.now()
221
+ }
222
+ });
223
+
224
+ const statefulParameterC = spy(new class extends TestParameter {
225
+ async refresh(): Promise<any | null> {
226
+ return performance.now()
227
+ }
228
+ });
229
+
230
+ const statefulParameterD = spy(new class extends TestParameter {
231
+ async refresh(): Promise<any | null> {
232
+ return performance.now()
233
+ }
234
+ });
235
+
236
+ const statefulParameterE = spy(new class extends TestParameter {
237
+ async refresh(): Promise<any | null> {
238
+ return performance.now()
239
+ }
240
+ });
241
+
242
+ const resource = spy(new class extends TestResource {
243
+ constructor() {
244
+ super({
245
+ type: 'resourceType',
246
+ parameterOptions: {
247
+ propA: { statefulParameter: statefulParameterA, order: 3},
248
+ propB: { statefulParameter: statefulParameterB, order: 1 },
249
+ propC: { statefulParameter: statefulParameterC, order: 2 },
250
+ propD: { statefulParameter: statefulParameterD },
251
+ propE: { statefulParameter: statefulParameterE }
252
+ },
253
+ });
254
+ }
255
+
256
+ async refresh(): Promise<Partial<TestConfig> | null> {
257
+ return {};
258
+ }
259
+ });
260
+
261
+ const plan = await resource.plan({
262
+ type: 'resourceType',
263
+ propA: 'propA',
264
+ propB: 10,
265
+ propC: 'propC',
266
+ propD: 'propD',
267
+ propE: 'propE',
268
+ });
269
+
270
+ expect(plan.currentConfig.propB).to.be.lessThan(plan.currentConfig.propC as any);
271
+ expect(plan.currentConfig.propC).to.be.lessThan(plan.currentConfig.propA as any);
272
+ expect(plan.currentConfig.propA).to.be.lessThan(plan.currentConfig.propD as any);
273
+ expect(plan.currentConfig.propD).to.be.lessThan(plan.currentConfig.propE as any);
274
+ })
275
+
276
+ it('Applies stateful parameters in the order specified', async () => {
277
+ let timestampA;
278
+ const statefulParameterA = spy(new class extends TestParameter {
279
+ applyAdd = async (): Promise<void> => { timestampA = performance.now(); }
280
+ applyModify = async (): Promise<void> => { timestampA = performance.now(); }
281
+ applyRemove = async (): Promise<void> => { timestampA = performance.now(); }
282
+ });
283
+
284
+ let timestampB
285
+ const statefulParameterB = spy(new class extends TestParameter {
286
+ applyAdd = async (): Promise<void> => { timestampB = performance.now(); }
287
+ applyModify = async (): Promise<void> => { timestampB = performance.now(); }
288
+ applyRemove = async (): Promise<void> => { timestampB = performance.now(); }
289
+ });
290
+
291
+ let timestampC
292
+ const statefulParameterC = spy(new class extends TestParameter {
293
+ applyAdd = async (): Promise<void> => { timestampC = performance.now(); }
294
+ applyModify = async (): Promise<void> => { timestampC = performance.now(); }
295
+ applyRemove = async (): Promise<void> => { timestampC = performance.now(); }
296
+ });
297
+
298
+ const resource = spy(new class extends TestResource {
299
+ constructor() {
300
+ super({
301
+ type: 'resourceType',
302
+ parameterOptions: {
303
+ propA: { statefulParameter: statefulParameterA, order: 3},
304
+ propB: { statefulParameter: statefulParameterB, order: 1 },
305
+ propC: { statefulParameter: statefulParameterC, order: 2 },
306
+ },
307
+ callStatefulParameterRemoveOnDestroy: true,
308
+ });
309
+ }
310
+ });
311
+
312
+ await resource.apply(
313
+ Plan.fromResponse({
314
+ resourceType: 'resourceType',
315
+ operation: ResourceOperation.CREATE,
316
+ parameters: [
317
+ { name: 'propA', operation: ParameterOperation.ADD, previousValue: null, newValue: null },
318
+ { name: 'propB', operation: ParameterOperation.ADD, previousValue: null, newValue: null },
319
+ { name: 'propC', operation: ParameterOperation.ADD, previousValue: null, newValue: null },
320
+ ]
321
+ }, {}) as any
322
+ );
323
+
324
+ expect(timestampB).to.be.lessThan(timestampC as any);
325
+ expect(timestampC).to.be.lessThan(timestampA as any);
326
+ timestampA = 0;
327
+ timestampB = 0;
328
+ timestampC = 0;
329
+
330
+ await resource.apply(
331
+ Plan.fromResponse({
332
+ resourceType: 'resourceType',
333
+ operation: ResourceOperation.MODIFY,
334
+ parameters: [
335
+ { name: 'propA', operation: ParameterOperation.MODIFY, previousValue: null, newValue: null },
336
+ { name: 'propB', operation: ParameterOperation.MODIFY, previousValue: null, newValue: null },
337
+ { name: 'propC', operation: ParameterOperation.MODIFY, previousValue: null, newValue: null },
338
+ ]
339
+ }, {}) as any
340
+ );
341
+
342
+ expect(timestampB).to.be.lessThan(timestampC as any);
343
+ expect(timestampC).to.be.lessThan(timestampA as any);
344
+ timestampA = 0;
345
+ timestampB = 0;
346
+ timestampC = 0;
347
+
348
+ await resource.apply(
349
+ Plan.fromResponse({
350
+ resourceType: 'resourceType',
351
+ operation: ResourceOperation.DESTROY,
352
+ parameters: [
353
+ { name: 'propA', operation: ParameterOperation.REMOVE, previousValue: null, newValue: null },
354
+ { name: 'propB', operation: ParameterOperation.REMOVE, previousValue: null, newValue: null },
355
+ { name: 'propC', operation: ParameterOperation.REMOVE, previousValue: null, newValue: null },
356
+ ]
357
+ }, {}) as any
358
+ );
359
+
360
+ expect(timestampB).to.be.lessThan(timestampC as any);
361
+ expect(timestampC).to.be.lessThan(timestampA as any);
362
+ timestampA = 0;
363
+ timestampB = 0;
364
+ timestampC = 0;
365
+
366
+ })
367
+
368
+ it('Supports transform parameters', async () => {
369
+ const transformParameter = new class extends TransformParameter<TestConfig> {
370
+ async transform(value: any): Promise<Partial<TestConfig>> {
371
+ return {
372
+ propA: 'propA',
373
+ propB: 10,
374
+ }
375
+ }
376
+ }
377
+
378
+ const resource = spy(new class extends TestResource {
379
+ constructor() {
380
+ super({
381
+ type: 'resourceType',
382
+ parameterOptions: {
383
+ propC: { transformParameter }
384
+ },
385
+ });
386
+ }
387
+
388
+ async refresh(): Promise<Partial<TestConfig> | null> {
389
+ return {
390
+ propA: 'propA',
391
+ propB: 10,
392
+ }
393
+ }
394
+ });
395
+
396
+ const plan = await resource.plan({ type: 'resourceType', propC: 'abc' } as any);
397
+
398
+ expect(resource.refresh.called).to.be.true;
399
+ expect(resource.refresh.getCall(0).firstArg.has('propA')).to.be.true;
400
+ expect(resource.refresh.getCall(0).firstArg.has('propB')).to.be.true;
401
+ expect(resource.refresh.getCall(0).firstArg.has('propC')).to.be.false;
402
+
403
+ expect(plan.desiredConfig.propA).to.eq('propA');
404
+ expect(plan.desiredConfig.propB).to.eq(10);
405
+ expect(plan.desiredConfig.propC).to.be.undefined;
406
+
407
+ expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
408
+ })
409
+
410
+ it('Plans transform parameters in the order specified', async () => {
411
+ const transformParameterA = spy(new class extends TransformParameter<TestConfig> {
412
+ async transform(value: any): Promise<Partial<TestConfig>> {
413
+ return { propD: performance.now() as any }
414
+ }
415
+ });
416
+
417
+ const transformParameterB = spy(new class extends TransformParameter<TestConfig> {
418
+ async transform(value: any): Promise<Partial<TestConfig>> {
419
+ return { propE: performance.now() }
420
+ }
421
+ });
422
+
423
+ const transformParameterC = spy(new class extends TransformParameter<TestConfig> {
424
+ async transform(value: any): Promise<Partial<TestConfig>> {
425
+ return { propF: performance.now() as any }
426
+ }
427
+ });
428
+
429
+ const resource = spy(new class extends TestResource {
430
+ constructor() {
431
+ super({
432
+ type: 'resourceType',
433
+ parameterOptions: {
434
+ propA: { transformParameter: transformParameterA, order: 3},
435
+ propB: { transformParameter: transformParameterB, order: 1 },
436
+ propC: { transformParameter: transformParameterC, order: 2 },
437
+ },
438
+ });
439
+ }
440
+
441
+ async refresh(): Promise<Partial<TestConfig> | null> {
442
+ return { propD: 'propD', propE: 10, propF: 'propF' };
443
+ }
444
+ });
445
+
446
+ const plan = await resource.plan({
447
+ type: 'resourceType',
448
+ propA: 'propA',
449
+ propB: 10,
450
+ propC: 'propC',
451
+ });
452
+
453
+ expect(plan.desiredConfig.propE).to.be.lessThan(plan.desiredConfig.propF as any);
454
+ expect(plan.desiredConfig.propF).to.be.lessThan(plan.desiredConfig.propD as any);
455
+ })
201
456
  })
@@ -1,12 +1,11 @@
1
- import { StatefulParameter } from './stateful-parameter.js';
2
- import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
1
+ import { ResourceOperation } from 'codify-schemas';
3
2
 
4
3
  export type ErrorMessage = string;
5
4
 
6
5
  /**
7
6
  * Customize properties for specific parameters. This will alter the way the library process changes to the parameter.
8
7
  */
9
- export interface ResourceParameterConfiguration {
8
+ export interface ResourceParameterOptions {
10
9
  /**
11
10
  * Chose if the resource should be re-created or modified if this parameter is changed. Defaults to re-create.
12
11
  */
@@ -26,17 +25,6 @@ export interface ResourceParameterConfiguration {
26
25
  /**
27
26
  * @param
28
27
  */
29
- export interface ResourceConfiguration<T extends StringIndexedObject> {
30
- type: string;
31
- /**
32
- * If true, statefulParameter.applyRemove() will be called before resource destruction.
33
- * Defaults to false.
34
- */
35
- callStatefulParameterRemoveOnDestroy?: boolean,
36
- dependencies?: string[];
37
- statefulParameters?: Array<StatefulParameter<T, T[keyof T]>>;
38
- parameterConfigurations?: Partial<Record<keyof T, ResourceParameterConfiguration>>
39
- }
40
28
 
41
29
  export interface ResourceDefinition {
42
30
  [x: string]: {
@@ -3,8 +3,9 @@ import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
3
3
  import { spy } from 'sinon';
4
4
  import { Plan } from './plan.js';
5
5
  import { describe, expect, it } from 'vitest'
6
- import { ResourceConfiguration, ValidationResult } from './resource-types.js';
6
+ import { ValidationResult } from './resource-types.js';
7
7
  import { StatefulParameter } from './stateful-parameter.js';
8
+ import { ResourceOptions } from './resource-options.js';
8
9
 
9
10
  export interface TestConfig extends StringIndexedObject {
10
11
  propA: string;
@@ -13,7 +14,7 @@ export interface TestConfig extends StringIndexedObject {
13
14
  }
14
15
 
15
16
  export class TestResource extends Resource<TestConfig> {
16
- constructor(options: ResourceConfiguration<TestConfig>) {
17
+ constructor(options: ResourceOptions<TestConfig>) {
17
18
  super(options);
18
19
  }
19
20
 
@@ -33,7 +34,7 @@ export class TestResource extends Resource<TestConfig> {
33
34
  };
34
35
  }
35
36
 
36
- async validate(config: unknown): Promise<ValidationResult> {
37
+ async validateResource(config: unknown): Promise<ValidationResult> {
37
38
  return {
38
39
  isValid: true
39
40
  }
@@ -193,7 +194,7 @@ describe('Resource tests', () => {
193
194
  constructor() {
194
195
  super({
195
196
  type: 'resource',
196
- parameterConfigurations: {
197
+ parameterOptions: {
197
198
  propA: { planOperation: ResourceOperation.MODIFY },
198
199
  propB: { planOperation: ResourceOperation.MODIFY },
199
200
  }
@@ -215,8 +216,8 @@ describe('Resource tests', () => {
215
216
  expect(resourceSpy.applyModify.calledTwice).to.be.true;
216
217
  })
217
218
 
218
- it('Validates the resource configuration correct (pass)', () => {
219
- const parameter = new class extends StatefulParameter<TestConfig, string> {
219
+ it('Validates the resource options correct (pass)', () => {
220
+ const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
220
221
  constructor() {
221
222
  super({
222
223
  name: 'propC',
@@ -242,11 +243,9 @@ describe('Resource tests', () => {
242
243
  super({
243
244
  type: 'type',
244
245
  dependencies: ['homebrew', 'python'],
245
- statefulParameters: [
246
- parameter
247
- ],
248
- parameterConfigurations: {
246
+ parameterOptions: {
249
247
  propA: { planOperation: ResourceOperation.MODIFY },
248
+ propB: { statefulParameter },
250
249
  propC: { isEqual: (a, b) => true },
251
250
  }
252
251
  });
@@ -254,8 +253,8 @@ describe('Resource tests', () => {
254
253
  }).to.not.throw;
255
254
  })
256
255
 
257
- it('Validates the resource configuration correct (fail)', () => {
258
- const parameter = new class extends StatefulParameter<TestConfig, string> {
256
+ it('Validates the resource options correct (fail)', () => {
257
+ const statefulParameter = new class extends StatefulParameter<TestConfig, string> {
259
258
  constructor() {
260
259
  super({
261
260
  name: 'propC',
@@ -281,11 +280,9 @@ describe('Resource tests', () => {
281
280
  super({
282
281
  type: 'type',
283
282
  dependencies: ['homebrew', 'python'],
284
- statefulParameters: [
285
- parameter
286
- ],
287
- parameterConfigurations: {
283
+ parameterOptions: {
288
284
  propA: { planOperation: ResourceOperation.MODIFY },
285
+ propB: { statefulParameter },
289
286
  propC: { isEqual: (a, b) => true },
290
287
  }
291
288
  });
@@ -298,7 +295,7 @@ describe('Resource tests', () => {
298
295
  constructor() {
299
296
  super({
300
297
  type: 'type',
301
- parameterConfigurations: {
298
+ parameterOptions: {
302
299
  propA: { defaultValue: 'propADefault' }
303
300
  }
304
301
  });
@@ -327,7 +324,7 @@ describe('Resource tests', () => {
327
324
  constructor() {
328
325
  super({
329
326
  type: 'type',
330
- parameterConfigurations: {
327
+ parameterOptions: {
331
328
  propA: { defaultValue: 'propADefault' }
332
329
  }
333
330
  });
@@ -348,6 +345,5 @@ describe('Resource tests', () => {
348
345
  expect(plan.currentConfig.propA).to.eq('propAAfter');
349
346
  expect(plan.desiredConfig.propA).to.eq('propA');
350
347
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
351
-
352
- })
348
+ });
353
349
  });