codify-plugin-lib 1.0.75 → 1.0.77
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.
- package/.eslintrc.json +11 -4
- package/.github/workflows/release.yaml +19 -0
- package/.github/workflows/unit-test-ci.yaml +19 -0
- package/dist/entities/plugin.d.ts +1 -1
- package/dist/entities/plugin.js +5 -5
- package/dist/entities/resource-options.d.ts +6 -6
- package/dist/entities/resource-options.js +7 -9
- package/dist/entities/resource.d.ts +2 -3
- package/dist/entities/resource.js +2 -2
- package/dist/errors.d.ts +4 -0
- package/dist/errors.js +7 -0
- package/dist/index.d.ts +10 -10
- package/dist/index.js +9 -9
- package/dist/messages/handlers.d.ts +1 -1
- package/dist/messages/handlers.js +25 -24
- package/dist/plan/change-set.d.ts +37 -0
- package/dist/plan/change-set.js +146 -0
- package/dist/plan/plan-types.d.ts +23 -0
- package/dist/plan/plan-types.js +1 -0
- package/dist/plan/plan.d.ts +59 -0
- package/dist/plan/plan.js +228 -0
- package/dist/plugin/plugin.d.ts +17 -0
- package/dist/plugin/plugin.js +83 -0
- package/dist/resource/config-parser.d.ts +14 -0
- package/dist/resource/config-parser.js +48 -0
- package/dist/resource/parsed-resource-settings.d.ts +26 -0
- package/dist/resource/parsed-resource-settings.js +126 -0
- package/dist/resource/resource-controller.d.ts +30 -0
- package/dist/resource/resource-controller.js +247 -0
- package/dist/resource/resource-settings.d.ts +149 -0
- package/dist/resource/resource-settings.js +9 -0
- package/dist/resource/resource.d.ts +137 -0
- package/dist/resource/resource.js +44 -0
- package/dist/resource/stateful-parameter.d.ts +164 -0
- package/dist/resource/stateful-parameter.js +94 -0
- package/dist/utils/utils.d.ts +19 -3
- package/dist/utils/utils.js +52 -3
- package/package.json +6 -4
- package/src/index.ts +10 -11
- package/src/messages/handlers.test.ts +21 -42
- package/src/messages/handlers.ts +28 -27
- package/src/plan/change-set.test.ts +220 -0
- package/src/plan/change-set.ts +225 -0
- package/src/plan/plan-types.ts +27 -0
- package/src/{entities → plan}/plan.test.ts +35 -29
- package/src/plan/plan.ts +353 -0
- package/src/{entities → plugin}/plugin.test.ts +14 -13
- package/src/{entities → plugin}/plugin.ts +32 -27
- package/src/resource/config-parser.ts +77 -0
- package/src/{entities/resource-options.test.ts → resource/parsed-resource-settings.test.ts} +8 -7
- package/src/resource/parsed-resource-settings.ts +179 -0
- package/src/{entities/resource-stateful-mode.test.ts → resource/resource-controller-stateful-mode.test.ts} +36 -39
- package/src/{entities/resource.test.ts → resource/resource-controller.test.ts} +116 -176
- package/src/resource/resource-controller.ts +340 -0
- package/src/resource/resource-settings.test.ts +494 -0
- package/src/resource/resource-settings.ts +192 -0
- package/src/resource/resource.ts +149 -0
- package/src/resource/stateful-parameter.test.ts +93 -0
- package/src/resource/stateful-parameter.ts +217 -0
- package/src/utils/test-utils.test.ts +87 -0
- package/src/utils/utils.test.ts +2 -2
- package/src/utils/utils.ts +51 -5
- package/tsconfig.json +0 -1
- package/vitest.config.ts +10 -0
- package/src/entities/change-set.test.ts +0 -155
- package/src/entities/change-set.ts +0 -244
- package/src/entities/plan-types.ts +0 -44
- package/src/entities/plan.ts +0 -178
- package/src/entities/resource-options.ts +0 -156
- package/src/entities/resource-parameters.test.ts +0 -604
- package/src/entities/resource-types.ts +0 -31
- package/src/entities/resource.ts +0 -471
- package/src/entities/stateful-parameter.test.ts +0 -114
- package/src/entities/stateful-parameter.ts +0 -92
- package/src/entities/transform-parameter.ts +0 -13
- /package/src/{entities/errors.ts → errors.ts} +0 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { StringIndexedObject } from 'codify-schemas';
|
|
2
|
+
|
|
3
|
+
import { areArraysEqual } from '../utils/utils.js';
|
|
4
|
+
import {
|
|
5
|
+
ArrayParameterSetting,
|
|
6
|
+
ParameterEqualsDefaults,
|
|
7
|
+
ParameterSetting,
|
|
8
|
+
ParameterSettingType,
|
|
9
|
+
ResourceSettings,
|
|
10
|
+
StatefulParameterSetting
|
|
11
|
+
} from './resource-settings.js';
|
|
12
|
+
import { StatefulParameter as StatefulParameterImpl } from './stateful-parameter.js'
|
|
13
|
+
|
|
14
|
+
export class ParsedResourceSettings<T extends StringIndexedObject> implements ResourceSettings<T> {
|
|
15
|
+
private cache = new Map<string, unknown>();
|
|
16
|
+
id!: string;
|
|
17
|
+
schema?: unknown;
|
|
18
|
+
allowMultiple?: { matcher: (desired: Partial<T>, current: Partial<T>[]) => Partial<T>; } | undefined;
|
|
19
|
+
removeStatefulParametersBeforeDestroy?: boolean | undefined;
|
|
20
|
+
dependencies?: string[] | undefined;
|
|
21
|
+
inputTransformation?: ((desired: Partial<T>) => unknown) | undefined;
|
|
22
|
+
private settings: ResourceSettings<T>;
|
|
23
|
+
|
|
24
|
+
constructor(settings: ResourceSettings<T>) {
|
|
25
|
+
this.settings = settings;
|
|
26
|
+
this.id = settings.id;
|
|
27
|
+
this.schema = settings.schema;
|
|
28
|
+
this.allowMultiple = settings.allowMultiple;
|
|
29
|
+
this.removeStatefulParametersBeforeDestroy = settings.removeStatefulParametersBeforeDestroy;
|
|
30
|
+
this.dependencies = settings.dependencies;
|
|
31
|
+
this.inputTransformation = settings.inputTransformation;
|
|
32
|
+
|
|
33
|
+
this.validateSettings();
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get typeId(): string {
|
|
37
|
+
return this.id;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
get statefulParameters(): Map<keyof T, StatefulParameterImpl<T, T[keyof T]>> {
|
|
41
|
+
return this.getFromCacheOrCreate('statefulParameters', () => {
|
|
42
|
+
|
|
43
|
+
const statefulParameters = Object.entries(this.settings.parameterSettings ?? {})
|
|
44
|
+
.filter(([, p]) => p?.type === 'stateful')
|
|
45
|
+
.map(([k, v]) => [k, (v as StatefulParameterSetting).definition] as const)
|
|
46
|
+
|
|
47
|
+
return new Map(statefulParameters) as Map<keyof T, StatefulParameterImpl<T, T[keyof T]>>;
|
|
48
|
+
})
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
get parameterSettings(): Record<keyof T, ParameterSetting> {
|
|
52
|
+
return this.getFromCacheOrCreate('parameterSetting', () => {
|
|
53
|
+
|
|
54
|
+
const settings = Object.entries(this.settings.parameterSettings ?? {})
|
|
55
|
+
.map(([k, v]) => [k, v!] as const)
|
|
56
|
+
.map(([k, v]) => {
|
|
57
|
+
v.isEqual = this.resolveEqualsFn(v, k);
|
|
58
|
+
|
|
59
|
+
return [k, v];
|
|
60
|
+
})
|
|
61
|
+
|
|
62
|
+
return Object.fromEntries(settings);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
get defaultValues(): Partial<Record<keyof T, unknown>> {
|
|
67
|
+
return this.getFromCacheOrCreate('defaultValues', () => {
|
|
68
|
+
|
|
69
|
+
if (!this.settings.parameterSettings) {
|
|
70
|
+
return {};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const defaultValues = Object.fromEntries(
|
|
74
|
+
Object.entries(this.settings.parameterSettings)
|
|
75
|
+
.filter(([, v]) => v!.default !== undefined)
|
|
76
|
+
.map(([k, v]) => [k, v!.default] as const)
|
|
77
|
+
)
|
|
78
|
+
|
|
79
|
+
const statefulParameterDefaultValues = Object.fromEntries(
|
|
80
|
+
Object.entries(this.settings.parameterSettings)
|
|
81
|
+
.filter(([, v]) => v?.type === 'stateful')
|
|
82
|
+
.filter(([, v]) => (v as StatefulParameterSetting).definition.getSettings().default !== undefined)
|
|
83
|
+
.map(([k, v]) => [k, (v as StatefulParameterSetting).definition.getSettings().default] as const)
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
return { ...defaultValues, ...statefulParameterDefaultValues } as Partial<Record<keyof T, unknown>>;
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
get inputTransformations(): Partial<Record<keyof T, (a: unknown) => unknown>> {
|
|
91
|
+
return this.getFromCacheOrCreate('inputTransformations', () => {
|
|
92
|
+
if (!this.settings.parameterSettings) {
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return Object.fromEntries(
|
|
97
|
+
Object.entries(this.settings.parameterSettings)
|
|
98
|
+
.filter(([, v]) => v!.inputTransformation !== undefined)
|
|
99
|
+
.map(([k, v]) => [k, v!.inputTransformation!] as const)
|
|
100
|
+
) as Record<keyof T, (a: unknown) => unknown>;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
get statefulParameterOrder(): Map<keyof T, number> {
|
|
105
|
+
return this.getFromCacheOrCreate('stateParameterOrder', () => {
|
|
106
|
+
|
|
107
|
+
const entries = Object.entries(this.settings.parameterSettings ?? {})
|
|
108
|
+
.filter(([, v]) => v?.type === 'stateful')
|
|
109
|
+
.map(([k, v]) => [k, v as StatefulParameterSetting] as const)
|
|
110
|
+
|
|
111
|
+
const orderedEntries = entries.filter(([, v]) => v.order !== undefined)
|
|
112
|
+
const unorderedEntries = entries.filter(([, v]) => v.order === undefined)
|
|
113
|
+
|
|
114
|
+
orderedEntries.sort((a, b) => a[1].order! - b[1].order!);
|
|
115
|
+
|
|
116
|
+
const resultArray = [
|
|
117
|
+
...orderedEntries.map(([k]) => k),
|
|
118
|
+
...unorderedEntries.map(([k]) => k)
|
|
119
|
+
]
|
|
120
|
+
|
|
121
|
+
return new Map(resultArray.map((key, idx) => [key, idx]));
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private validateSettings(): void {
|
|
126
|
+
// validate parameter settings
|
|
127
|
+
if (this.settings.parameterSettings) {
|
|
128
|
+
for (const [k, v] of Object.entries(this.settings.parameterSettings)) {
|
|
129
|
+
if (!v) {
|
|
130
|
+
throw new Error(`Resource: ${this.id}. Parameter setting ${k} was left undefined`);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
this.validateParameterEqualsFn(v, k);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (this.allowMultiple
|
|
138
|
+
&& Object.values(this.parameterSettings).some((v) => v.type === 'stateful')) {
|
|
139
|
+
throw new Error(`Resource: ${this.id}. Stateful parameters are not allowed if multiples of a resource exist`)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private validateParameterEqualsFn(parameter: ParameterSetting, key: string): void {
|
|
144
|
+
if (parameter.type === 'stateful') {
|
|
145
|
+
const nestedSettings = (parameter as StatefulParameterSetting).definition.getSettings();
|
|
146
|
+
|
|
147
|
+
if (nestedSettings.type === 'stateful') {
|
|
148
|
+
throw new Error(`Nested stateful parameters are not allowed for ${key}`);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
this.validateParameterEqualsFn(nestedSettings, key);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// The rest of the types have defaults set already
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
private resolveEqualsFn(parameter: ParameterSetting, key: string): (desired: unknown, current: unknown) => boolean {
|
|
158
|
+
if (parameter.type === 'array') {
|
|
159
|
+
return parameter.isEqual ?? areArraysEqual.bind(areArraysEqual, parameter as ArrayParameterSetting)
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
if (parameter.type === 'stateful') {
|
|
163
|
+
return this.resolveEqualsFn((parameter as StatefulParameterSetting).definition.getSettings(), key)
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return parameter.isEqual ?? ParameterEqualsDefaults[parameter.type as ParameterSettingType] ?? (((a, b) => a === b));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private getFromCacheOrCreate<T2>(key: string, create: () => T2): T2 {
|
|
170
|
+
if (this.cache.has(key)) {
|
|
171
|
+
return this.cache.get(key) as T2
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const result = create();
|
|
175
|
+
|
|
176
|
+
this.cache.set(key, result)
|
|
177
|
+
return result;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
@@ -1,17 +1,13 @@
|
|
|
1
1
|
import { describe, expect, it } from 'vitest';
|
|
2
|
-
import { TestConfig, TestResource } from './resource.test.js';
|
|
3
2
|
import { ParameterOperation, ResourceOperation } from 'codify-schemas';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { TestConfig, TestResource, TestStatefulParameter } from '../utils/test-utils.test.js';
|
|
4
|
+
import { ResourceSettings } from './resource-settings.js';
|
|
5
|
+
import { ResourceController } from './resource-controller.js';
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
describe('Resource tests for stateful plans', () => {
|
|
9
9
|
it('Supports delete operations ', async () => {
|
|
10
10
|
const resource = new class extends TestResource {
|
|
11
|
-
constructor() {
|
|
12
|
-
super({ type: 'resource' });
|
|
13
|
-
}
|
|
14
|
-
|
|
15
11
|
async refresh(parameters: Partial<TestConfig>): Promise<Partial<TestConfig> | null> {
|
|
16
12
|
return {
|
|
17
13
|
propA: 'propADifferent',
|
|
@@ -21,10 +17,11 @@ describe('Resource tests for stateful plans', () => {
|
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
const
|
|
20
|
+
const controller = new ResourceController(resource);
|
|
21
|
+
const plan = await controller.plan(
|
|
25
22
|
null,
|
|
26
23
|
{
|
|
27
|
-
type: '
|
|
24
|
+
type: 'type',
|
|
28
25
|
propA: 'propA',
|
|
29
26
|
propB: 10,
|
|
30
27
|
propC: 'propC',
|
|
@@ -41,6 +38,12 @@ describe('Resource tests for stateful plans', () => {
|
|
|
41
38
|
newValue: null,
|
|
42
39
|
operation: ParameterOperation.REMOVE
|
|
43
40
|
},
|
|
41
|
+
{
|
|
42
|
+
name: 'propB',
|
|
43
|
+
previousValue: null,
|
|
44
|
+
newValue: null,
|
|
45
|
+
operation: ParameterOperation.REMOVE
|
|
46
|
+
},
|
|
44
47
|
{
|
|
45
48
|
name: "propC",
|
|
46
49
|
previousValue: "propCDifferent",
|
|
@@ -49,24 +52,21 @@ describe('Resource tests for stateful plans', () => {
|
|
|
49
52
|
},
|
|
50
53
|
]
|
|
51
54
|
},
|
|
52
|
-
|
|
53
|
-
type: '
|
|
55
|
+
coreParameters: {
|
|
56
|
+
type: 'type'
|
|
54
57
|
}
|
|
55
58
|
})
|
|
56
59
|
})
|
|
57
60
|
|
|
58
61
|
it('Supports create operations', async () => {
|
|
59
62
|
const resource = new class extends TestResource {
|
|
60
|
-
constructor() {
|
|
61
|
-
super({ type: 'resource' });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
63
|
async refresh(): Promise<Partial<TestConfig> | null> {
|
|
65
64
|
return null;
|
|
66
65
|
}
|
|
67
66
|
}
|
|
68
67
|
|
|
69
|
-
const
|
|
68
|
+
const controller = new ResourceController(resource);
|
|
69
|
+
const plan = await controller.plan(
|
|
70
70
|
{
|
|
71
71
|
type: 'resource',
|
|
72
72
|
propA: 'propA',
|
|
@@ -101,7 +101,7 @@ describe('Resource tests for stateful plans', () => {
|
|
|
101
101
|
},
|
|
102
102
|
]
|
|
103
103
|
},
|
|
104
|
-
|
|
104
|
+
coreParameters: {
|
|
105
105
|
type: 'resource'
|
|
106
106
|
}
|
|
107
107
|
})
|
|
@@ -109,28 +109,24 @@ describe('Resource tests for stateful plans', () => {
|
|
|
109
109
|
|
|
110
110
|
it('Supports re-create operations', async () => {
|
|
111
111
|
const resource = new class extends TestResource {
|
|
112
|
-
constructor() {
|
|
113
|
-
super({ type: 'resource' });
|
|
114
|
-
}
|
|
115
|
-
|
|
116
112
|
async refresh(): Promise<Partial<TestConfig> | null> {
|
|
117
113
|
return {
|
|
118
114
|
propA: 'propA',
|
|
119
115
|
propC: 'propC',
|
|
120
|
-
propB: undefined
|
|
121
116
|
};
|
|
122
117
|
}
|
|
123
118
|
}
|
|
124
119
|
|
|
125
|
-
const
|
|
120
|
+
const controller = new ResourceController(resource)
|
|
121
|
+
const plan = await controller.plan(
|
|
126
122
|
{
|
|
127
|
-
type: '
|
|
123
|
+
type: 'type',
|
|
128
124
|
propA: 'propA',
|
|
129
125
|
propB: 10,
|
|
130
126
|
propC: 'propC',
|
|
131
127
|
},
|
|
132
128
|
{
|
|
133
|
-
type: '
|
|
129
|
+
type: 'type',
|
|
134
130
|
propA: 'propA',
|
|
135
131
|
propC: 'propC'
|
|
136
132
|
},
|
|
@@ -161,27 +157,27 @@ describe('Resource tests for stateful plans', () => {
|
|
|
161
157
|
},
|
|
162
158
|
])
|
|
163
159
|
},
|
|
164
|
-
|
|
165
|
-
type: '
|
|
160
|
+
coreParameters: {
|
|
161
|
+
type: 'type'
|
|
166
162
|
}
|
|
167
163
|
})
|
|
168
164
|
})
|
|
169
165
|
|
|
170
166
|
it('Supports stateful parameters', async () => {
|
|
171
|
-
const statefulParameter = new class extends
|
|
167
|
+
const statefulParameter = new class extends TestStatefulParameter {
|
|
172
168
|
async refresh(): Promise<string | null> {
|
|
173
169
|
return null;
|
|
174
170
|
}
|
|
175
171
|
}
|
|
176
172
|
|
|
177
173
|
const resource = new class extends TestResource {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
propD: {
|
|
174
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
175
|
+
return {
|
|
176
|
+
id: 'type',
|
|
177
|
+
parameterSettings: {
|
|
178
|
+
propD: { type: 'stateful', definition: statefulParameter },
|
|
183
179
|
}
|
|
184
|
-
}
|
|
180
|
+
};
|
|
185
181
|
}
|
|
186
182
|
|
|
187
183
|
async refresh(): Promise<Partial<TestConfig> | null> {
|
|
@@ -193,16 +189,17 @@ describe('Resource tests for stateful plans', () => {
|
|
|
193
189
|
}
|
|
194
190
|
}
|
|
195
191
|
|
|
196
|
-
const
|
|
192
|
+
const controller = new ResourceController(resource);
|
|
193
|
+
const plan = await controller.plan(
|
|
197
194
|
{
|
|
198
|
-
type: '
|
|
195
|
+
type: 'type',
|
|
199
196
|
propA: 'propA',
|
|
200
197
|
propB: 10,
|
|
201
198
|
propC: 'propC',
|
|
202
199
|
propD: 'propD'
|
|
203
200
|
},
|
|
204
201
|
{
|
|
205
|
-
type: '
|
|
202
|
+
type: 'type',
|
|
206
203
|
propA: 'propA',
|
|
207
204
|
propC: 'propC'
|
|
208
205
|
},
|
|
@@ -239,8 +236,8 @@ describe('Resource tests for stateful plans', () => {
|
|
|
239
236
|
},
|
|
240
237
|
])
|
|
241
238
|
},
|
|
242
|
-
|
|
243
|
-
type: '
|
|
239
|
+
coreParameters: {
|
|
240
|
+
type: 'type'
|
|
244
241
|
}
|
|
245
242
|
})
|
|
246
243
|
})
|