codify-plugin-lib 1.0.51 → 1.0.53

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.
@@ -58,39 +58,40 @@ export class Plan {
58
58
  Object.entries(defaultValues)
59
59
  .forEach(([key, defaultValue]) => {
60
60
  const configValueExists = data
61
- ?.parameters
62
- .find((p) => p.name === key) !== undefined;
63
- if (!configValueExists) {
64
- switch (data?.operation) {
65
- case ResourceOperation.CREATE: {
66
- data?.parameters.push({
67
- name: key,
68
- operation: ParameterOperation.ADD,
69
- previousValue: null,
70
- newValue: defaultValue,
71
- });
72
- break;
73
- }
74
- case ResourceOperation.DESTROY: {
75
- data?.parameters.push({
76
- name: key,
77
- operation: ParameterOperation.REMOVE,
78
- previousValue: defaultValue,
79
- newValue: null,
80
- });
81
- break;
82
- }
83
- case ResourceOperation.MODIFY:
84
- case ResourceOperation.RECREATE:
85
- case ResourceOperation.NOOP: {
86
- data?.parameters.push({
87
- name: key,
88
- operation: ParameterOperation.NOOP,
89
- previousValue: defaultValue,
90
- newValue: defaultValue,
91
- });
92
- break;
93
- }
61
+ .parameters
62
+ .some((p) => p.name === key);
63
+ if (configValueExists) {
64
+ return;
65
+ }
66
+ switch (data.operation) {
67
+ case ResourceOperation.CREATE: {
68
+ data.parameters.push({
69
+ name: key,
70
+ operation: ParameterOperation.ADD,
71
+ previousValue: null,
72
+ newValue: defaultValue,
73
+ });
74
+ break;
75
+ }
76
+ case ResourceOperation.DESTROY: {
77
+ data.parameters.push({
78
+ name: key,
79
+ operation: ParameterOperation.REMOVE,
80
+ previousValue: defaultValue,
81
+ newValue: null,
82
+ });
83
+ break;
84
+ }
85
+ case ResourceOperation.MODIFY:
86
+ case ResourceOperation.RECREATE:
87
+ case ResourceOperation.NOOP: {
88
+ data.parameters.push({
89
+ name: key,
90
+ operation: ParameterOperation.NOOP,
91
+ previousValue: defaultValue,
92
+ newValue: defaultValue,
93
+ });
94
+ break;
94
95
  }
95
96
  }
96
97
  });
@@ -66,10 +66,10 @@ export class Plugin {
66
66
  return this.planStorage.get(planId);
67
67
  }
68
68
  if (!planRequest?.resourceType || !this.resources.has(planRequest.resourceType)) {
69
- throw new Error('Malformed plan. Resource type must be supplied');
69
+ throw new Error('Malformed plan. Resource type must be supplied or resource type was not found');
70
70
  }
71
71
  const resource = this.resources.get(planRequest.resourceType);
72
- return Plan.fromResponse(data.plan, resource?.defaultValues);
72
+ return Plan.fromResponse(data.plan, resource.defaultValues);
73
73
  }
74
74
  async crossValidateResources(configs) { }
75
75
  }
@@ -46,8 +46,8 @@ export class ResourceOptionsParser {
46
46
  return {};
47
47
  }
48
48
  return Object.fromEntries([...this.resourceParameters.entries()]
49
- .filter(([, rp]) => rp.defaultValue !== undefined)
50
- .map(([name, rp]) => [name, rp.defaultValue]));
49
+ .filter(([, rp]) => rp.default !== undefined)
50
+ .map(([name, rp]) => [name, rp.default]));
51
51
  }
52
52
  get statefulParameterOrder() {
53
53
  const entries = Object.entries(this.options.parameterOptions ?? {})
@@ -3,7 +3,7 @@ export type ErrorMessage = string;
3
3
  export interface ResourceParameterOptions {
4
4
  planOperation?: ResourceOperation.MODIFY | ResourceOperation.RECREATE;
5
5
  isEqual?: (desired: any, current: any) => boolean;
6
- defaultValue?: unknown;
6
+ default?: unknown;
7
7
  }
8
8
  export interface ResourceDefinition {
9
9
  [x: string]: {
@@ -55,9 +55,9 @@ export class Resource {
55
55
  parameterOptions: this.parameterOptions,
56
56
  };
57
57
  const parsedConfig = new ConfigParser(desiredConfig, this.statefulParameters, this.transformParameters);
58
- const { parameters: desiredParameters, resourceMetadata, resourceParameters, statefulParameters } = parsedConfig;
58
+ const { parameters: desiredParameters, resourceMetadata, resourceParameters, statefulParameters, transformParameters, } = parsedConfig;
59
59
  this.addDefaultValues(resourceParameters);
60
- await this.applyTransformParameters(resourceParameters);
60
+ await this.applyTransformParameters(transformParameters, resourceParameters);
61
61
  const currentParameters = await this.refreshResourceParameters(resourceParameters);
62
62
  if (currentParameters == null) {
63
63
  return Plan.create(desiredParameters, null, resourceMetadata, planOptions);
@@ -151,8 +151,8 @@ Missing: ${[...desiredKeys].filter((k) => !refreshKeys.has(k))};
151
151
  Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`);
152
152
  }
153
153
  }
154
- async applyTransformParameters(desired) {
155
- const orderedEntries = [...this.transformParameters.entries()]
154
+ async applyTransformParameters(transformParameters, desired) {
155
+ const orderedEntries = [...Object.entries(transformParameters)]
156
156
  .sort(([keyA], [keyB]) => this.transformParameterOrder.get(keyA) - this.transformParameterOrder.get(keyB));
157
157
  for (const [key, tp] of orderedEntries) {
158
158
  if (desired[key] !== null) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.51",
3
+ "version": "1.0.53",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -141,9 +141,7 @@ function createResource(): Resource<any> {
141
141
  super({
142
142
  type: 'type',
143
143
  parameterOptions: {
144
- propA: {
145
- defaultValue: 'defaultA'
146
- }
144
+ propA: { default: 'defaultA' }
147
145
  }
148
146
  });
149
147
  }
@@ -97,43 +97,46 @@ export class Plan<T extends StringIndexedObject> {
97
97
  function addDefaultValues(): void {
98
98
  Object.entries(defaultValues)
99
99
  .forEach(([key, defaultValue]) => {
100
- const configValueExists = data
101
- ?.parameters
102
- .find((p) => p.name === key) !== undefined;
103
-
104
- if (!configValueExists) {
105
- switch (data?.operation) {
106
- case ResourceOperation.CREATE: {
107
- data?.parameters.push({
108
- name: key,
109
- operation: ParameterOperation.ADD,
110
- previousValue: null,
111
- newValue: defaultValue,
112
- });
113
- break;
114
- }
115
-
116
- case ResourceOperation.DESTROY: {
117
- data?.parameters.push({
118
- name: key,
119
- operation: ParameterOperation.REMOVE,
120
- previousValue: defaultValue,
121
- newValue: null,
122
- });
123
- break;
124
- }
125
-
126
- case ResourceOperation.MODIFY:
127
- case ResourceOperation.RECREATE:
128
- case ResourceOperation.NOOP: {
129
- data?.parameters.push({
130
- name: key,
131
- operation: ParameterOperation.NOOP,
132
- previousValue: defaultValue,
133
- newValue: defaultValue,
134
- });
135
- break;
136
- }
100
+ const configValueExists = data!
101
+ .parameters
102
+ .some((p) => p.name === key);
103
+
104
+ // Only set default values if the value does not exist in the config
105
+ if (configValueExists) {
106
+ return;
107
+ }
108
+
109
+ switch (data!.operation) {
110
+ case ResourceOperation.CREATE: {
111
+ data!.parameters.push({
112
+ name: key,
113
+ operation: ParameterOperation.ADD,
114
+ previousValue: null,
115
+ newValue: defaultValue,
116
+ });
117
+ break;
118
+ }
119
+
120
+ case ResourceOperation.DESTROY: {
121
+ data!.parameters.push({
122
+ name: key,
123
+ operation: ParameterOperation.REMOVE,
124
+ previousValue: defaultValue,
125
+ newValue: null,
126
+ });
127
+ break;
128
+ }
129
+
130
+ case ResourceOperation.MODIFY:
131
+ case ResourceOperation.RECREATE:
132
+ case ResourceOperation.NOOP: {
133
+ data!.parameters.push({
134
+ name: key,
135
+ operation: ParameterOperation.NOOP,
136
+ previousValue: defaultValue,
137
+ newValue: defaultValue,
138
+ });
139
+ break;
137
140
  }
138
141
  }
139
142
  });
@@ -95,11 +95,11 @@ export class Plugin {
95
95
  }
96
96
 
97
97
  if (!planRequest?.resourceType || !this.resources.has(planRequest.resourceType)) {
98
- throw new Error('Malformed plan. Resource type must be supplied');
98
+ throw new Error('Malformed plan. Resource type must be supplied or resource type was not found');
99
99
  }
100
100
 
101
- const resource = this.resources.get(planRequest.resourceType);
102
- return Plan.fromResponse(data.plan, resource?.defaultValues!);
101
+ const resource = this.resources.get(planRequest.resourceType)!;
102
+ return Plan.fromResponse(data.plan, resource.defaultValues);
103
103
  }
104
104
 
105
105
  protected async crossValidateResources(configs: ResourceConfig[]): Promise<void> {}
@@ -0,0 +1,23 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ResourceOptions, ResourceOptionsParser } from './resource-options.js';
3
+ import { TestConfig } from './resource.test.js';
4
+
5
+ describe('Resource options parser tests', () => {
6
+ it('Parses default values from options', () => {
7
+ const option: ResourceOptions<TestConfig> = {
8
+ type: 'typeId',
9
+ parameterOptions: {
10
+ propA: { default: 'propA' },
11
+ propB: { default: 'propB' },
12
+ propC: { isEqual: () => true },
13
+ propD: { },
14
+ }
15
+ }
16
+
17
+ const result = new ResourceOptionsParser(option);
18
+ expect(result.defaultValues).to.deep.eq({
19
+ propA: 'propA',
20
+ propB: 'propB'
21
+ })
22
+ })
23
+ })
@@ -113,8 +113,8 @@ export class ResourceOptionsParser<T extends StringIndexedObject> {
113
113
 
114
114
  return Object.fromEntries(
115
115
  [...this.resourceParameters.entries()]
116
- .filter(([, rp]) => rp.defaultValue !== undefined)
117
- .map(([name, rp]) => [name, rp.defaultValue])
116
+ .filter(([, rp]) => rp.default !== undefined)
117
+ .map(([name, rp]) => [name, rp.default])
118
118
  ) as Partial<Record<keyof T, unknown>>;
119
119
  }
120
120
 
@@ -407,6 +407,43 @@ describe('Resource parameters tests', () => {
407
407
  expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
408
408
  })
409
409
 
410
+ it('Does not call transform parameters unless they are specified in the user config', async () => {
411
+ const transformParameter = spy(new class extends TransformParameter<TestConfig> {
412
+ async transform(value: any): Promise<Partial<TestConfig>> {
413
+ return {
414
+ propA: 'propA',
415
+ propB: 10,
416
+ }
417
+ }
418
+ })
419
+
420
+ const resource = spy(new class extends TestResource {
421
+ constructor() {
422
+ super({
423
+ type: 'resourceType',
424
+ parameterOptions: {
425
+ propC: { transformParameter }
426
+ },
427
+ });
428
+ }
429
+
430
+ async refresh(): Promise<Partial<TestConfig> | null> {
431
+ return {
432
+ propA: 'propA',
433
+ propB: 10,
434
+ }
435
+ }
436
+ });
437
+
438
+ const plan = await resource.plan({ type: 'resourceType', propA: 'propA', propB: 10 } as any);
439
+
440
+ expect(transformParameter.transform.called).to.be.false;
441
+ expect(resource.refresh.getCall(0).firstArg.has('propA')).to.be.true;
442
+ expect(resource.refresh.getCall(0).firstArg.has('propB')).to.be.true;
443
+
444
+ expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
445
+ })
446
+
410
447
  it('Plans transform parameters in the order specified', async () => {
411
448
  const transformParameterA = spy(new class extends TransformParameter<TestConfig> {
412
449
  async transform(value: any): Promise<Partial<TestConfig>> {
@@ -19,7 +19,7 @@ export interface ResourceParameterOptions {
19
19
  /**
20
20
  * Default value for the parameter. If a value is not provided in the config, the library will use this value.
21
21
  */
22
- defaultValue?: unknown,
22
+ default?: unknown,
23
23
  }
24
24
 
25
25
  /**
@@ -296,7 +296,7 @@ describe('Resource tests', () => {
296
296
  super({
297
297
  type: 'type',
298
298
  parameterOptions: {
299
- propA: { defaultValue: 'propADefault' }
299
+ propA: { default: 'propADefault' }
300
300
  }
301
301
  });
302
302
  }
@@ -325,7 +325,7 @@ describe('Resource tests', () => {
325
325
  super({
326
326
  type: 'type',
327
327
  parameterOptions: {
328
- propA: { defaultValue: 'propADefault' }
328
+ propA: { default: 'propADefault' }
329
329
  }
330
330
  });
331
331
  }
@@ -346,4 +346,21 @@ describe('Resource tests', () => {
346
346
  expect(plan.desiredConfig.propA).to.eq('propA');
347
347
  expect(plan.changeSet.operation).to.eq(ResourceOperation.RECREATE);
348
348
  });
349
+
350
+ it('Sets the default value properly on the resource', () => {
351
+ const resource = new class extends TestResource {
352
+ constructor() {
353
+ super({
354
+ type: 'type',
355
+ parameterOptions: {
356
+ propA: { default: 'propADefault' }
357
+ }
358
+ });
359
+ }
360
+ }
361
+
362
+ expect(resource.defaultValues).to.deep.eq({
363
+ propA: 'propADefault',
364
+ })
365
+ })
349
366
  });
@@ -89,11 +89,12 @@ export abstract class Resource<T extends StringIndexedObject> {
89
89
  parameters: desiredParameters,
90
90
  resourceMetadata,
91
91
  resourceParameters,
92
- statefulParameters
92
+ statefulParameters,
93
+ transformParameters,
93
94
  } = parsedConfig;
94
95
 
95
96
  this.addDefaultValues(resourceParameters);
96
- await this.applyTransformParameters(resourceParameters);
97
+ await this.applyTransformParameters(transformParameters, resourceParameters);
97
98
 
98
99
  // Refresh resource parameters. This refreshes the parameters that configure the resource itself
99
100
  const currentParameters = await this.refreshResourceParameters(resourceParameters);
@@ -223,8 +224,8 @@ Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`
223
224
  }
224
225
  }
225
226
 
226
- private async applyTransformParameters(desired: Partial<T>): Promise<void> {
227
- const orderedEntries = [...this.transformParameters.entries()]
227
+ private async applyTransformParameters(transformParameters: Partial<T>, desired: Partial<T>): Promise<void> {
228
+ const orderedEntries = [...Object.entries(transformParameters)]
228
229
  .sort(([keyA], [keyB]) => this.transformParameterOrder.get(keyA)! - this.transformParameterOrder.get(keyB)!)
229
230
 
230
231
  for (const [key, tp] of orderedEntries) {