Skip to content

Commit f4b3cc0

Browse files
committed
Added transform parameters
1 parent ef53319 commit f4b3cc0

5 files changed

Lines changed: 76 additions & 2 deletions

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codify-plugin-lib",
3-
"version": "1.0.49",
3+
"version": "1.0.50",
44
"description": "",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",

src/entities/resource-parameters.test.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Plan } from './plan.js';
44
import { spy } from 'sinon';
55
import { ResourceOperation } from 'codify-schemas';
66
import { TestConfig, TestResource } from './resource.test.js';
7+
import { TransformParameter } from './transform-parameter.js';
78

89
class TestParameter extends StatefulParameter<TestConfig, string> {
910
constructor(configuration?: StatefulParameterConfiguration<TestConfig>) {
@@ -198,4 +199,46 @@ describe('Resource parameters tests', () => {
198199
}
199200
})
200201
})
202+
203+
it('Supports transform parameters', async () => {
204+
const transformParameter = new class extends TransformParameter<TestConfig> {
205+
async transform(value: any): Promise<Partial<TestConfig>> {
206+
return {
207+
propA: 'propA',
208+
propB: 10,
209+
}
210+
}
211+
}
212+
213+
const resource = spy(new class extends TestResource {
214+
constructor() {
215+
super({
216+
type: 'resourceType',
217+
transformParameters: {
218+
propC: transformParameter
219+
},
220+
});
221+
}
222+
223+
async refresh(): Promise<Partial<TestConfig> | null> {
224+
return {
225+
propA: 'propA',
226+
propB: 10,
227+
}
228+
}
229+
});
230+
231+
const plan = await resource.plan({ type: 'resourceType', propC: 'abc' } as any);
232+
233+
expect(resource.refresh.called).to.be.true;
234+
expect(resource.refresh.getCall(0).firstArg.has('propA')).to.be.true;
235+
expect(resource.refresh.getCall(0).firstArg.has('propB')).to.be.true;
236+
expect(resource.refresh.getCall(0).firstArg.has('propC')).to.be.false;
237+
238+
expect(plan.desiredConfig.propA).to.eq('propA');
239+
expect(plan.desiredConfig.propB).to.eq(10);
240+
expect(plan.desiredConfig.propC).to.be.undefined;
241+
242+
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
243+
})
201244
})

src/entities/resource-types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { StatefulParameter } from './stateful-parameter.js';
22
import { ResourceOperation, StringIndexedObject } from 'codify-schemas';
3+
import { TransformParameter } from './transform-parameter.js';
34

45
export type ErrorMessage = string;
56

@@ -35,6 +36,7 @@ export interface ResourceConfiguration<T extends StringIndexedObject> {
3536
callStatefulParameterRemoveOnDestroy?: boolean,
3637
dependencies?: string[];
3738
statefulParameters?: Array<StatefulParameter<T, T[keyof T]>>;
39+
transformParameters?: Partial<Record<keyof T, TransformParameter<T>>>
3840
parameterConfigurations?: Partial<Record<keyof T, ResourceParameterConfiguration>>
3941
}
4042

src/entities/resource.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { StatefulParameter } from './stateful-parameter.js';
55
import { ResourceConfiguration, ValidationResult } from './resource-types.js';
66
import { setsEqual, splitUserConfig } from '../utils/utils.js';
77
import { ParameterConfiguration, PlanConfiguration } from './plan-types.js';
8+
import { TransformParameter } from './transform-parameter.js';
89

910
/**
1011
* Description of resource here
@@ -17,6 +18,7 @@ export abstract class Resource<T extends StringIndexedObject> {
1718

1819
readonly typeId: string;
1920
readonly statefulParameters: Map<keyof T, StatefulParameter<T, T[keyof T]>>;
21+
readonly transformParameters: Map<keyof T, TransformParameter<T>>
2022
readonly dependencies: string[]; // TODO: Change this to a string
2123
readonly parameterConfigurations: Record<keyof T, ParameterConfiguration>
2224
readonly configuration: ResourceConfiguration<T>;
@@ -27,6 +29,7 @@ export abstract class Resource<T extends StringIndexedObject> {
2729

2830
this.typeId = configuration.type;
2931
this.statefulParameters = new Map(configuration.statefulParameters?.map((sp) => [sp.name, sp]));
32+
this.transformParameters = new Map(Object.entries(configuration.transformParameters ?? {})) as Map<keyof T, TransformParameter<T>>;
3033
this.parameterConfigurations = this.initializeParameterConfigurations(configuration);
3134
this.defaultValues = this.initializeDefaultValues(configuration);
3235

@@ -50,6 +53,7 @@ export abstract class Resource<T extends StringIndexedObject> {
5053
const { resourceMetadata, parameters: desiredParameters } = splitUserConfig(desiredConfig);
5154

5255
this.addDefaultValues(desiredParameters);
56+
await this.applyTransformParameters(desiredParameters);
5357

5458
const resourceParameters = Object.fromEntries([
5559
...Object.entries(desiredParameters).filter(([key]) => !this.statefulParameters.has(key)),
@@ -210,7 +214,6 @@ export abstract class Resource<T extends StringIndexedObject> {
210214
...resourceParameters,
211215
...statefulParameters,
212216
}
213-
214217
}
215218

216219
private initializeDefaultValues(
@@ -258,6 +261,25 @@ Additional: ${[...refreshKeys].filter(k => !desiredKeys.has(k))};`
258261
}
259262
}
260263

264+
private async applyTransformParameters(desired: Partial<T>): Promise<void> {
265+
for (const [key, tp] of this.transformParameters.entries()) {
266+
if (desired[key] !== null) {
267+
const transformedValue = await tp.transform(desired[key]);
268+
269+
if (Object.keys(transformedValue).some((k) => desired[k] !== undefined)) {
270+
throw new Error(`Transform parameter ${key as string} is attempting to override existing value ${desired[key]}`);
271+
}
272+
273+
Object.entries(transformedValue).forEach(([tvKey, tvValue]) => {
274+
// @ts-ignore
275+
desired[tvKey] = tvValue;
276+
})
277+
278+
delete desired[key];
279+
}
280+
}
281+
}
282+
261283
private addDefaultValues(desired: Partial<T>): void {
262284
Object.entries(this.defaultValues)
263285
.forEach(([key, defaultValue]) => {
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { StringIndexedObject } from 'codify-schemas';
2+
3+
export abstract class TransformParameter<T extends StringIndexedObject> {
4+
5+
abstract transform(value: any): Promise<Partial<T>>
6+
7+
}

0 commit comments

Comments
 (0)