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.
- package/dist/entities/change-set.d.ts +3 -3
- package/dist/entities/change-set.js +11 -11
- package/dist/entities/plan-types.d.ts +3 -3
- package/dist/entities/plan.d.ts +2 -2
- package/dist/entities/plan.js +6 -6
- package/dist/entities/plugin.js +1 -1
- package/dist/entities/resource-options.d.ts +31 -0
- package/dist/entities/resource-options.js +78 -0
- package/dist/entities/resource-types.d.ts +2 -10
- package/dist/entities/resource.d.ts +20 -9
- package/dist/entities/resource.js +149 -82
- package/dist/entities/stateful-parameter.d.ts +6 -6
- package/dist/entities/stateful-parameter.js +13 -13
- package/dist/entities/transform-parameter.d.ts +4 -0
- package/dist/entities/transform-parameter.js +2 -0
- package/package.json +1 -1
- package/src/entities/change-set.ts +13 -13
- package/src/entities/plan-types.ts +3 -3
- package/src/entities/plan.test.ts +1 -1
- package/src/entities/plan.ts +7 -7
- package/src/entities/plugin.ts +1 -1
- package/src/entities/resource-options.ts +156 -0
- package/src/entities/resource-parameters.test.ts +265 -10
- package/src/entities/resource-types.ts +2 -14
- package/src/entities/resource.test.ts +16 -20
- package/src/entities/resource.ts +206 -117
- package/src/entities/stateful-parameter.test.ts +5 -5
- package/src/entities/stateful-parameter.ts +15 -15
- package/src/entities/transform-parameter.ts +7 -0
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { Plan } from './plan.js';
|
|
2
2
|
import { StringIndexedObject } from 'codify-schemas';
|
|
3
|
-
export interface
|
|
3
|
+
export interface StatefulParameterOptions<T> {
|
|
4
4
|
name: keyof T;
|
|
5
5
|
isEqual?: (desired: any, current: any) => boolean;
|
|
6
6
|
disableStatelessModeArrayFiltering?: boolean;
|
|
7
7
|
}
|
|
8
|
-
export interface
|
|
8
|
+
export interface ArrayStatefulParameterOptions<T> extends StatefulParameterOptions<T> {
|
|
9
9
|
isEqual?: (desired: any[], current: any[]) => boolean;
|
|
10
10
|
isElementEqual?: (desired: any, current: any) => boolean;
|
|
11
11
|
}
|
|
12
12
|
export declare abstract class StatefulParameter<T extends StringIndexedObject, V extends T[keyof T]> {
|
|
13
13
|
readonly name: keyof T;
|
|
14
|
-
readonly
|
|
15
|
-
protected constructor(
|
|
14
|
+
readonly options: StatefulParameterOptions<T>;
|
|
15
|
+
protected constructor(options: StatefulParameterOptions<T>);
|
|
16
16
|
abstract refresh(desired: V | null): Promise<V | null>;
|
|
17
17
|
abstract applyAdd(valueToAdd: V, plan: Plan<T>): Promise<void>;
|
|
18
18
|
abstract applyModify(newValue: V, previousValue: V, allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
19
19
|
abstract applyRemove(valueToRemove: V, plan: Plan<T>): Promise<void>;
|
|
20
20
|
}
|
|
21
21
|
export declare abstract class ArrayStatefulParameter<T extends StringIndexedObject, V> extends StatefulParameter<T, any> {
|
|
22
|
-
|
|
23
|
-
constructor(
|
|
22
|
+
options: ArrayStatefulParameterOptions<T>;
|
|
23
|
+
constructor(options: ArrayStatefulParameterOptions<T>);
|
|
24
24
|
applyAdd(valuesToAdd: V[], plan: Plan<T>): Promise<void>;
|
|
25
25
|
applyModify(newValues: V[], previousValues: V[], allowDeletes: boolean, plan: Plan<T>): Promise<void>;
|
|
26
26
|
applyRemove(valuesToRemove: V[], plan: Plan<T>): Promise<void>;
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
export class StatefulParameter {
|
|
2
2
|
name;
|
|
3
|
-
|
|
4
|
-
constructor(
|
|
5
|
-
this.name =
|
|
6
|
-
this.
|
|
3
|
+
options;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.name = options.name;
|
|
6
|
+
this.options = options;
|
|
7
7
|
}
|
|
8
8
|
}
|
|
9
9
|
export class ArrayStatefulParameter extends StatefulParameter {
|
|
10
|
-
|
|
11
|
-
constructor(
|
|
12
|
-
super(
|
|
13
|
-
this.
|
|
10
|
+
options;
|
|
11
|
+
constructor(options) {
|
|
12
|
+
super(options);
|
|
13
|
+
this.options = options;
|
|
14
14
|
}
|
|
15
15
|
async applyAdd(valuesToAdd, plan) {
|
|
16
16
|
for (const value of valuesToAdd) {
|
|
@@ -18,16 +18,16 @@ export class ArrayStatefulParameter extends StatefulParameter {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
async applyModify(newValues, previousValues, allowDeletes, plan) {
|
|
21
|
-
const
|
|
21
|
+
const options = this.options;
|
|
22
22
|
const valuesToAdd = newValues.filter((n) => !previousValues.some((p) => {
|
|
23
|
-
if (
|
|
24
|
-
return
|
|
23
|
+
if (options.isElementEqual) {
|
|
24
|
+
return options.isElementEqual(n, p);
|
|
25
25
|
}
|
|
26
26
|
return n === p;
|
|
27
27
|
}));
|
|
28
28
|
const valuesToRemove = previousValues.filter((p) => !newValues.some((n) => {
|
|
29
|
-
if (
|
|
30
|
-
return
|
|
29
|
+
if (options.isElementEqual) {
|
|
30
|
+
return options.isElementEqual(n, p);
|
|
31
31
|
}
|
|
32
32
|
return n === p;
|
|
33
33
|
}));
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ParameterOperation, ResourceOperation, StringIndexedObject } from 'codify-schemas';
|
|
2
|
-
import {
|
|
2
|
+
import { ParameterOptions } from './plan-types.js';
|
|
3
3
|
|
|
4
4
|
export interface ParameterChange<T extends StringIndexedObject> {
|
|
5
5
|
name: keyof T & string;
|
|
@@ -61,12 +61,12 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
61
61
|
static calculateParameterChangeSet<T extends StringIndexedObject>(
|
|
62
62
|
desired: T | null,
|
|
63
63
|
current: T | null,
|
|
64
|
-
options: { statefulMode: boolean,
|
|
64
|
+
options: { statefulMode: boolean, parameterOptions?: Record<keyof T, ParameterOptions> },
|
|
65
65
|
): ParameterChange<T>[] {
|
|
66
66
|
if (options.statefulMode) {
|
|
67
|
-
return ChangeSet.calculateStatefulModeChangeSet(desired, current, options.
|
|
67
|
+
return ChangeSet.calculateStatefulModeChangeSet(desired, current, options.parameterOptions);
|
|
68
68
|
} else {
|
|
69
|
-
return ChangeSet.calculateStatelessModeChangeSet(desired, current, options.
|
|
69
|
+
return ChangeSet.calculateStatelessModeChangeSet(desired, current, options.parameterOptions);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
@@ -88,10 +88,10 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
88
88
|
static isSame(
|
|
89
89
|
desired: unknown,
|
|
90
90
|
current: unknown,
|
|
91
|
-
|
|
91
|
+
options?: ParameterOptions,
|
|
92
92
|
): boolean {
|
|
93
|
-
if (
|
|
94
|
-
return
|
|
93
|
+
if (options?.isEqual) {
|
|
94
|
+
return options.isEqual(desired, current);
|
|
95
95
|
}
|
|
96
96
|
|
|
97
97
|
if (Array.isArray(desired) && Array.isArray(current)) {
|
|
@@ -102,9 +102,9 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
102
102
|
return false;
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
-
if (
|
|
105
|
+
if (options?.isElementEqual) {
|
|
106
106
|
return sortedDesired.every((value, index) =>
|
|
107
|
-
|
|
107
|
+
options.isElementEqual!(value, sortedCurrent[index])
|
|
108
108
|
);
|
|
109
109
|
}
|
|
110
110
|
|
|
@@ -119,7 +119,7 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
119
119
|
private static calculateStatefulModeChangeSet<T extends StringIndexedObject>(
|
|
120
120
|
desired: T | null,
|
|
121
121
|
current: T | null,
|
|
122
|
-
|
|
122
|
+
parameterOptions?: Record<keyof T, ParameterOptions>,
|
|
123
123
|
): ParameterChange<T>[] {
|
|
124
124
|
const parameterChangeSet = new Array<ParameterChange<T>>();
|
|
125
125
|
|
|
@@ -139,7 +139,7 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
139
139
|
continue;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
if (!ChangeSet.isSame(_desired[k], _current[k],
|
|
142
|
+
if (!ChangeSet.isSame(_desired[k], _current[k], parameterOptions?.[k])) {
|
|
143
143
|
parameterChangeSet.push({
|
|
144
144
|
name: k,
|
|
145
145
|
previousValue: v,
|
|
@@ -184,7 +184,7 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
184
184
|
private static calculateStatelessModeChangeSet<T extends StringIndexedObject>(
|
|
185
185
|
desired: T | null,
|
|
186
186
|
current: T | null,
|
|
187
|
-
|
|
187
|
+
parameterOptions?: Record<keyof T, ParameterOptions>,
|
|
188
188
|
): ParameterChange<T>[] {
|
|
189
189
|
const parameterChangeSet = new Array<ParameterChange<T>>();
|
|
190
190
|
|
|
@@ -203,7 +203,7 @@ export class ChangeSet<T extends StringIndexedObject> {
|
|
|
203
203
|
continue;
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
if (!ChangeSet.isSame(_desired[k], _current[k],
|
|
206
|
+
if (!ChangeSet.isSame(_desired[k], _current[k], parameterOptions?.[k])) {
|
|
207
207
|
parameterChangeSet.push({
|
|
208
208
|
name: k,
|
|
209
209
|
previousValue: _current[k],
|
|
@@ -3,7 +3,7 @@ import { ResourceOperation } from 'codify-schemas';
|
|
|
3
3
|
/**
|
|
4
4
|
* Customize properties for specific parameters. This will alter the way the library process changes to the parameter.
|
|
5
5
|
*/
|
|
6
|
-
export interface
|
|
6
|
+
export interface ParameterOptions {
|
|
7
7
|
/**
|
|
8
8
|
* Chose if the resource should be re-created or modified if this parameter is changed. Defaults to re-create.
|
|
9
9
|
*/
|
|
@@ -20,7 +20,7 @@ export interface ParameterConfiguration {
|
|
|
20
20
|
isStatefulParameter?: boolean;
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export interface
|
|
23
|
+
export interface PlanOptions<T> {
|
|
24
24
|
statefulMode: boolean;
|
|
25
|
-
|
|
25
|
+
parameterOptions?: Record<keyof T, ParameterOptions>;
|
|
26
26
|
}
|
package/src/entities/plan.ts
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
StringIndexedObject,
|
|
9
9
|
} from 'codify-schemas';
|
|
10
10
|
import { randomUUID } from 'crypto';
|
|
11
|
-
import {
|
|
11
|
+
import { ParameterOptions, PlanOptions } from './plan-types.js';
|
|
12
12
|
|
|
13
13
|
export class Plan<T extends StringIndexedObject> {
|
|
14
14
|
id: string;
|
|
@@ -25,11 +25,11 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
25
25
|
desiredParameters: Partial<T> | null,
|
|
26
26
|
currentParameters: Partial<T> | null,
|
|
27
27
|
resourceMetadata: ResourceConfig,
|
|
28
|
-
|
|
28
|
+
options: PlanOptions<T>
|
|
29
29
|
): Plan<T> {
|
|
30
|
-
const
|
|
30
|
+
const parameterOptions = options.parameterOptions ?? {} as Record<keyof T, ParameterOptions>;
|
|
31
31
|
const statefulParameterNames = new Set(
|
|
32
|
-
[...Object.entries(
|
|
32
|
+
[...Object.entries(parameterOptions)]
|
|
33
33
|
.filter(([k, v]) => v.isStatefulParameter)
|
|
34
34
|
.map(([k, v]) => k)
|
|
35
35
|
);
|
|
@@ -40,7 +40,7 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
40
40
|
const parameterChangeSet = ChangeSet.calculateParameterChangeSet(
|
|
41
41
|
desiredParameters,
|
|
42
42
|
currentParameters,
|
|
43
|
-
{ statefulMode:
|
|
43
|
+
{ statefulMode: options.statefulMode, parameterOptions }
|
|
44
44
|
);
|
|
45
45
|
|
|
46
46
|
let resourceOperation: ResourceOperation;
|
|
@@ -55,8 +55,8 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
55
55
|
let newOperation: ResourceOperation;
|
|
56
56
|
if (statefulParameterNames.has(curr.name)) {
|
|
57
57
|
newOperation = ResourceOperation.MODIFY // All stateful parameters are modify only
|
|
58
|
-
} else if (
|
|
59
|
-
newOperation =
|
|
58
|
+
} else if (parameterOptions[curr.name]?.planOperation) {
|
|
59
|
+
newOperation = parameterOptions[curr.name].planOperation!;
|
|
60
60
|
} else {
|
|
61
61
|
newOperation = ResourceOperation.RECREATE; // Default to Re-create. Should handle the majority of use cases
|
|
62
62
|
}
|
package/src/entities/plugin.ts
CHANGED
|
@@ -42,7 +42,7 @@ export class Plugin {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const { parameters } = splitUserConfig(config);
|
|
45
|
-
const validateResult = await this.resources.get(config.type)!.
|
|
45
|
+
const validateResult = await this.resources.get(config.type)!.validateResource(parameters);
|
|
46
46
|
|
|
47
47
|
validationResults.push({
|
|
48
48
|
...validateResult,
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import { StringIndexedObject } from 'codify-schemas';
|
|
2
|
+
import { StatefulParameter } from './stateful-parameter.js';
|
|
3
|
+
import { TransformParameter } from './transform-parameter.js';
|
|
4
|
+
import { ResourceParameterOptions } from './resource-types.js';
|
|
5
|
+
import { ParameterOptions } from './plan-types.js';
|
|
6
|
+
|
|
7
|
+
export interface ResourceOptions<T extends StringIndexedObject> {
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The id of the resource.
|
|
11
|
+
*/
|
|
12
|
+
type: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Schema to validate user configs with. Must be in the format JSON Schema 2020-12
|
|
16
|
+
*/
|
|
17
|
+
schema?: unknown
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* If true, statefulParameter.applyRemove() will be called before resource destruction.
|
|
21
|
+
* Defaults to false.
|
|
22
|
+
*/
|
|
23
|
+
callStatefulParameterRemoveOnDestroy?: boolean,
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* An array of type ids of resources that this resource depends on. This affects the order in which the resources are
|
|
27
|
+
* planned and applied.
|
|
28
|
+
*/
|
|
29
|
+
dependencies?: string[];
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Additional options for configuring parameters.
|
|
33
|
+
*/
|
|
34
|
+
parameterOptions?: Partial<Record<keyof T,
|
|
35
|
+
ResourceParameterOptions
|
|
36
|
+
| ResourceStatefulParameterOptions<T>
|
|
37
|
+
| ResourceTransformParameterOptions<T>
|
|
38
|
+
>>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface ResourceStatefulParameterOptions<T extends StringIndexedObject> {
|
|
42
|
+
statefulParameter: StatefulParameter<T, T[keyof T]>;
|
|
43
|
+
order?: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface ResourceTransformParameterOptions<T extends StringIndexedObject> {
|
|
47
|
+
transformParameter: TransformParameter<T>;
|
|
48
|
+
order?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export class ResourceOptionsParser<T extends StringIndexedObject> {
|
|
52
|
+
private options: ResourceOptions<T>;
|
|
53
|
+
|
|
54
|
+
constructor(options: ResourceOptions<T>) {
|
|
55
|
+
this.options = options;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
get statefulParameters(): Map<keyof T, StatefulParameter<T, T[keyof T]>> {
|
|
59
|
+
const statefulParameters = Object.entries(this.options.parameterOptions ?? {})
|
|
60
|
+
.filter(([, p]) => p?.hasOwnProperty('statefulParameter'))
|
|
61
|
+
.map(([k, v]) => [k, v as ResourceStatefulParameterOptions<T>] as const)
|
|
62
|
+
.map(([k, v]) => [k, v.statefulParameter] as const)
|
|
63
|
+
|
|
64
|
+
return new Map(statefulParameters);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
get transformParameters(): Map<keyof T, TransformParameter<T>> {
|
|
68
|
+
const transformParameters =
|
|
69
|
+
Object.entries(this.options.parameterOptions ?? {})
|
|
70
|
+
.filter(([, p]) => p?.hasOwnProperty('transformParameter'))
|
|
71
|
+
.map(([k, v]) => [k, v as ResourceTransformParameterOptions<T>] as const)
|
|
72
|
+
.map(([k, v]) => [k, v.transformParameter] as const)
|
|
73
|
+
|
|
74
|
+
return new Map(transformParameters);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
get resourceParameters(): Map<keyof T, ResourceParameterOptions> {
|
|
78
|
+
const resourceParameters =
|
|
79
|
+
Object.entries(this.options.parameterOptions ?? {})
|
|
80
|
+
.filter(([, p]) => !(p?.hasOwnProperty('statefulParameter') || p?.hasOwnProperty('transformParameter')))
|
|
81
|
+
.map(([k, v]) => [k, v as ResourceParameterOptions] as const)
|
|
82
|
+
|
|
83
|
+
return new Map(resourceParameters);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
get changeSetParameterOptions(): Record<keyof T, ParameterOptions> {
|
|
87
|
+
const resourceParameters = Object.fromEntries(
|
|
88
|
+
[...this.resourceParameters.entries()]
|
|
89
|
+
.map(([name, value]) => ([name, { ...value, isStatefulParameter: false }]))
|
|
90
|
+
);
|
|
91
|
+
|
|
92
|
+
const statefulParameters = [...this.statefulParameters.entries()]
|
|
93
|
+
?.reduce((obj, sp) => {
|
|
94
|
+
return {
|
|
95
|
+
...obj,
|
|
96
|
+
[sp[0]]: {
|
|
97
|
+
...sp[1].options,
|
|
98
|
+
isStatefulParameter: true,
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}, {} as Record<keyof T, ParameterOptions>)
|
|
102
|
+
|
|
103
|
+
return {
|
|
104
|
+
...resourceParameters,
|
|
105
|
+
...statefulParameters,
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
get defaultValues(): Partial<Record<keyof T, unknown>> {
|
|
110
|
+
if (!this.options.parameterOptions) {
|
|
111
|
+
return {};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return Object.fromEntries(
|
|
115
|
+
[...this.resourceParameters.entries()]
|
|
116
|
+
.filter(([, rp]) => rp.defaultValue !== undefined)
|
|
117
|
+
.map(([name, rp]) => [name, rp.defaultValue])
|
|
118
|
+
) as Partial<Record<keyof T, unknown>>;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
get statefulParameterOrder(): Map<keyof T, number> {
|
|
122
|
+
const entries = Object.entries(this.options.parameterOptions ?? {})
|
|
123
|
+
.filter(([, v]) => v?.hasOwnProperty('statefulParameter'))
|
|
124
|
+
.map(([k, v]) => [k, v as ResourceStatefulParameterOptions<T>] as const)
|
|
125
|
+
|
|
126
|
+
const orderedEntries = entries.filter(([, v]) => v.order !== undefined)
|
|
127
|
+
const unorderedEntries = entries.filter(([, v]) => v.order === undefined)
|
|
128
|
+
|
|
129
|
+
orderedEntries.sort((a, b) => a[1].order! - b[1].order!);
|
|
130
|
+
|
|
131
|
+
const resultArray = [
|
|
132
|
+
...orderedEntries.map(([k]) => k),
|
|
133
|
+
...unorderedEntries.map(([k]) => k)
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
return new Map(resultArray.map((key, idx) => [key, idx]));
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
get transformParameterOrder(): Map<keyof T, number> {
|
|
140
|
+
const entries = Object.entries(this.options.parameterOptions ?? {})
|
|
141
|
+
.filter(([, v]) => v?.hasOwnProperty('transformParameter'))
|
|
142
|
+
.map(([k, v]) => [k, v as ResourceTransformParameterOptions<T>] as const)
|
|
143
|
+
|
|
144
|
+
const orderedEntries = entries.filter(([, v]) => v.order !== undefined)
|
|
145
|
+
const unorderedEntries = entries.filter(([, v]) => v.order === undefined)
|
|
146
|
+
|
|
147
|
+
orderedEntries.sort((a, b) => a[1].order! - b[1].order!);
|
|
148
|
+
|
|
149
|
+
const resultArray = [
|
|
150
|
+
...orderedEntries.map(([k]) => k),
|
|
151
|
+
...unorderedEntries.map(([k]) => k)
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
return new Map(resultArray.map((key, idx) => [key, idx]));
|
|
155
|
+
}
|
|
156
|
+
}
|