codify-plugin-lib 1.0.151 → 1.0.153
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/plugin/plugin.js +2 -16
- package/dist/resource/resource-controller.d.ts +1 -0
- package/dist/resource/resource-controller.js +31 -0
- package/dist/resource/resource-settings.d.ts +1 -1
- package/dist/resource/resource-settings.js +8 -3
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +3 -0
- package/package.json +1 -1
- package/src/plugin/plugin.ts +2 -21
- package/src/resource/resource-controller.ts +42 -0
- package/src/resource/resource-settings.ts +10 -4
- package/src/utils/utils.ts +4 -0
package/dist/plugin/plugin.js
CHANGED
|
@@ -39,6 +39,7 @@ export class Plugin {
|
|
|
39
39
|
const resource = this.resourceControllers.get(data.type);
|
|
40
40
|
const schema = resource.settings.schema;
|
|
41
41
|
const requiredPropertyNames = (resource.settings.importAndDestroy?.requiredParameters
|
|
42
|
+
?? (typeof resource.settings.allowMultiple === 'object' ? resource.settings.allowMultiple.identifyingParameters : null)
|
|
42
43
|
?? schema?.required
|
|
43
44
|
?? undefined);
|
|
44
45
|
const allowMultiple = resource.settings.allowMultiple !== undefined
|
|
@@ -64,22 +65,7 @@ export class Plugin {
|
|
|
64
65
|
if (!resource) {
|
|
65
66
|
throw new Error(`Resource of type ${resourceConfig.core.type} could not be found for match`);
|
|
66
67
|
}
|
|
67
|
-
|
|
68
|
-
return { match: array.find((r) => r.core.type === resourceConfig.core.type) };
|
|
69
|
-
}
|
|
70
|
-
const parameterMatcher = resource?.parsedSettings.matcher;
|
|
71
|
-
const match = array.find((r) => {
|
|
72
|
-
if (resourceConfig.core.type !== r.core.type) {
|
|
73
|
-
return false;
|
|
74
|
-
}
|
|
75
|
-
// If the user specifies the same name for the resource and it's not auto-generated (a number) then it's the same resource
|
|
76
|
-
if (resourceConfig.core.name === r.core.name
|
|
77
|
-
&& resourceConfig.core.name
|
|
78
|
-
&& Number.isInteger(Number.parseInt(resourceConfig.core.name, 10))) {
|
|
79
|
-
return true;
|
|
80
|
-
}
|
|
81
|
-
return parameterMatcher(resourceConfig.parameters, r.parameters);
|
|
82
|
-
});
|
|
68
|
+
const match = await resource.match(resourceConfig, array);
|
|
83
69
|
return { match };
|
|
84
70
|
}
|
|
85
71
|
async import(data) {
|
|
@@ -15,6 +15,7 @@ export declare class ResourceController<T extends StringIndexedObject> {
|
|
|
15
15
|
constructor(resource: Resource<T>);
|
|
16
16
|
initialize(): Promise<void>;
|
|
17
17
|
validate(core: ResourceConfig, parameters: Partial<T>): Promise<ValidateResponseData['resourceValidations'][0]>;
|
|
18
|
+
match(resource: ResourceJson, array: Array<ResourceJson>): Promise<ResourceJson | undefined>;
|
|
18
19
|
plan(core: ResourceConfig, desired: Partial<T> | null, state: Partial<T> | null, isStateful?: boolean): Promise<Plan<T>>;
|
|
19
20
|
planDestroy(core: ResourceConfig, parameters: Partial<T>): Promise<Plan<T>>;
|
|
20
21
|
apply(plan: Plan<T>): Promise<void>;
|
|
@@ -71,6 +71,37 @@ export class ResourceController {
|
|
|
71
71
|
schemaValidationErrors: [],
|
|
72
72
|
};
|
|
73
73
|
}
|
|
74
|
+
async match(resource, array) {
|
|
75
|
+
if (resource.core.type !== this.typeId) {
|
|
76
|
+
throw new Error(`Unknown type passed into match method: ${resource.core.type} for ${this.typeId}`);
|
|
77
|
+
}
|
|
78
|
+
if (!this.parsedSettings.allowMultiple) {
|
|
79
|
+
return array.find((r) => r.core.type === resource.core.type);
|
|
80
|
+
}
|
|
81
|
+
const { name, type } = resource.core;
|
|
82
|
+
const parameterMatcher = this.parsedSettings.matcher;
|
|
83
|
+
for (const resourceToMatch of array) {
|
|
84
|
+
if (type !== resourceToMatch.core.type) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
// If the user specifies the same name for the resource and it's not auto-generated (a number) then it's the same resource
|
|
88
|
+
if (name === resourceToMatch.core.name
|
|
89
|
+
&& name
|
|
90
|
+
&& Number.isInteger(Number.parseInt(name, 10))) {
|
|
91
|
+
return resourceToMatch;
|
|
92
|
+
}
|
|
93
|
+
const originalParams = structuredClone(resource.parameters);
|
|
94
|
+
const paramsToMatch = structuredClone(resourceToMatch.parameters);
|
|
95
|
+
this.addDefaultValues(originalParams);
|
|
96
|
+
await this.applyTransformParameters(originalParams);
|
|
97
|
+
this.addDefaultValues(paramsToMatch);
|
|
98
|
+
await this.applyTransformParameters(paramsToMatch);
|
|
99
|
+
const match = parameterMatcher(originalParams, paramsToMatch);
|
|
100
|
+
if (match) {
|
|
101
|
+
return resourceToMatch;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
74
105
|
async plan(core, desired, state, isStateful = false) {
|
|
75
106
|
this.validatePlanInputs(core, desired, state, isStateful);
|
|
76
107
|
this.addDefaultValues(desired);
|
|
@@ -96,7 +96,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
96
96
|
preventImport?: boolean;
|
|
97
97
|
/**
|
|
98
98
|
* Customize the required parameters needed to import this resource. By default, the `requiredParameters` are taken
|
|
99
|
-
* from the
|
|
99
|
+
* from the identifyingParameters for allowMultiple. The `requiredParameters` parameter must be declared if a complex required is declared in
|
|
100
100
|
* the schema (contains `oneOf`, `anyOf`, `allOf`, `if`, `then`, `else`).
|
|
101
101
|
* <br>
|
|
102
102
|
* The user will be prompted for the required parameters before the import starts. This is done because for most resources
|
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import isObjectsEqual from 'lodash.isequal';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import { areArraysEqual, tildify, untildify } from '../utils/utils.js';
|
|
3
|
+
import { areArraysEqual, tildify, unhome, untildify } from '../utils/utils.js';
|
|
4
4
|
const ParameterEqualsDefaults = {
|
|
5
5
|
'boolean': (a, b) => Boolean(a) === Boolean(b),
|
|
6
|
-
'directory': (a, b) =>
|
|
6
|
+
'directory': (a, b) => {
|
|
7
|
+
const notCaseSensitive = process.platform === 'darwin';
|
|
8
|
+
const transformedA = path.resolve(unhome(untildify(notCaseSensitive ? String(a).toLowerCase() : String(a))));
|
|
9
|
+
const transformedB = path.resolve(unhome(untildify(notCaseSensitive ? String(b).toLowerCase() : String(b))));
|
|
10
|
+
return transformedA === transformedB;
|
|
11
|
+
},
|
|
7
12
|
'number': (a, b) => Number(a) === Number(b),
|
|
8
13
|
'string': (a, b) => String(a) === String(b),
|
|
9
14
|
'version': (desired, current) => String(current).includes(String(desired)),
|
|
@@ -48,7 +53,7 @@ export function resolveFnFromEqualsFnOrString(fnOrString) {
|
|
|
48
53
|
}
|
|
49
54
|
const ParameterTransformationDefaults = {
|
|
50
55
|
'directory': {
|
|
51
|
-
to: (a) => path.resolve(untildify(String(a))),
|
|
56
|
+
to: (a) => path.resolve(unhome(untildify(String(a)))),
|
|
52
57
|
from: (a) => tildify(String(a)),
|
|
53
58
|
},
|
|
54
59
|
'string': {
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export declare function splitUserConfig<T extends StringIndexedObject>(config: R
|
|
|
7
7
|
export declare function setsEqual(set1: Set<unknown>, set2: Set<unknown>): boolean;
|
|
8
8
|
export declare function untildify(pathWithTilde: string): string;
|
|
9
9
|
export declare function tildify(pathWithTilde: string): string;
|
|
10
|
+
export declare function unhome(pathWithHome: string): string;
|
|
10
11
|
export declare function areArraysEqual(isElementEqual: ((desired: unknown, current: unknown) => boolean) | undefined, desired: unknown, current: unknown): boolean;
|
package/dist/utils/utils.js
CHANGED
|
@@ -25,6 +25,9 @@ export function untildify(pathWithTilde) {
|
|
|
25
25
|
export function tildify(pathWithTilde) {
|
|
26
26
|
return homeDirectory ? pathWithTilde.replace(homeDirectory, '~') : pathWithTilde;
|
|
27
27
|
}
|
|
28
|
+
export function unhome(pathWithHome) {
|
|
29
|
+
return pathWithHome.includes('$HOME') ? pathWithHome.replaceAll('$HOME', os.homedir()) : pathWithHome;
|
|
30
|
+
}
|
|
28
31
|
export function areArraysEqual(isElementEqual, desired, current) {
|
|
29
32
|
if (!desired || !current) {
|
|
30
33
|
return false;
|
package/package.json
CHANGED
package/src/plugin/plugin.ts
CHANGED
|
@@ -70,6 +70,7 @@ export class Plugin {
|
|
|
70
70
|
const schema = resource.settings.schema as JSONSchemaType<any> | undefined;
|
|
71
71
|
const requiredPropertyNames = (
|
|
72
72
|
resource.settings.importAndDestroy?.requiredParameters
|
|
73
|
+
?? (typeof resource.settings.allowMultiple === 'object' ? resource.settings.allowMultiple.identifyingParameters : null)
|
|
73
74
|
?? schema?.required
|
|
74
75
|
?? undefined
|
|
75
76
|
) as any;
|
|
@@ -101,27 +102,7 @@ export class Plugin {
|
|
|
101
102
|
throw new Error(`Resource of type ${resourceConfig.core.type} could not be found for match`);
|
|
102
103
|
}
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
return { match: array.find((r) => r.core.type === resourceConfig.core.type) }
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const parameterMatcher = resource?.parsedSettings.matcher;
|
|
109
|
-
const match = array.find((r) => {
|
|
110
|
-
if (resourceConfig.core.type !== r.core.type) {
|
|
111
|
-
return false;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
// If the user specifies the same name for the resource and it's not auto-generated (a number) then it's the same resource
|
|
115
|
-
if (resourceConfig.core.name === r.core.name
|
|
116
|
-
&& resourceConfig.core.name
|
|
117
|
-
&& Number.isInteger(Number.parseInt(resourceConfig.core.name, 10))
|
|
118
|
-
) {
|
|
119
|
-
return true;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
return parameterMatcher(resourceConfig.parameters, r.parameters);
|
|
123
|
-
});
|
|
124
|
-
|
|
105
|
+
const match = await resource.match(resourceConfig, array);
|
|
125
106
|
return { match }
|
|
126
107
|
}
|
|
127
108
|
|
|
@@ -102,6 +102,48 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
102
102
|
}
|
|
103
103
|
}
|
|
104
104
|
|
|
105
|
+
async match(resource: ResourceJson, array: Array<ResourceJson>): Promise<ResourceJson | undefined> {
|
|
106
|
+
if (resource.core.type !== this.typeId) {
|
|
107
|
+
throw new Error(`Unknown type passed into match method: ${resource.core.type} for ${this.typeId}`);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (!this.parsedSettings.allowMultiple) {
|
|
111
|
+
return array.find((r) => r.core.type === resource.core.type)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
const { name, type } = resource.core;
|
|
116
|
+
const parameterMatcher = this.parsedSettings.matcher;
|
|
117
|
+
|
|
118
|
+
for (const resourceToMatch of array) {
|
|
119
|
+
if (type !== resourceToMatch.core.type) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// If the user specifies the same name for the resource and it's not auto-generated (a number) then it's the same resource
|
|
124
|
+
if (name === resourceToMatch.core.name
|
|
125
|
+
&& name
|
|
126
|
+
&& Number.isInteger(Number.parseInt(name, 10))
|
|
127
|
+
) {
|
|
128
|
+
return resourceToMatch;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
const originalParams = structuredClone(resource.parameters) as Partial<T>;
|
|
132
|
+
const paramsToMatch = structuredClone(resourceToMatch.parameters) as Partial<T>;
|
|
133
|
+
|
|
134
|
+
this.addDefaultValues(originalParams);
|
|
135
|
+
await this.applyTransformParameters(originalParams);
|
|
136
|
+
|
|
137
|
+
this.addDefaultValues(paramsToMatch);
|
|
138
|
+
await this.applyTransformParameters(paramsToMatch);
|
|
139
|
+
|
|
140
|
+
const match = parameterMatcher(originalParams, paramsToMatch);
|
|
141
|
+
if (match) {
|
|
142
|
+
return resourceToMatch;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
105
147
|
async plan(
|
|
106
148
|
core: ResourceConfig,
|
|
107
149
|
desired: Partial<T> | null,
|
|
@@ -4,7 +4,7 @@ import isObjectsEqual from 'lodash.isequal'
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
|
|
6
6
|
import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
|
|
7
|
-
import { areArraysEqual, tildify, untildify } from '../utils/utils.js';
|
|
7
|
+
import { areArraysEqual, tildify, unhome, untildify } from '../utils/utils.js';
|
|
8
8
|
|
|
9
9
|
export interface InputTransformation {
|
|
10
10
|
to: (input: any) => Promise<any> | any;
|
|
@@ -113,7 +113,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
113
113
|
|
|
114
114
|
/**
|
|
115
115
|
* Customize the required parameters needed to import this resource. By default, the `requiredParameters` are taken
|
|
116
|
-
* from the
|
|
116
|
+
* from the identifyingParameters for allowMultiple. The `requiredParameters` parameter must be declared if a complex required is declared in
|
|
117
117
|
* the schema (contains `oneOf`, `anyOf`, `allOf`, `if`, `then`, `else`).
|
|
118
118
|
* <br>
|
|
119
119
|
* The user will be prompted for the required parameters before the import starts. This is done because for most resources
|
|
@@ -302,7 +302,13 @@ export interface StatefulParameterSetting extends DefaultParameterSetting {
|
|
|
302
302
|
|
|
303
303
|
const ParameterEqualsDefaults: Partial<Record<ParameterSettingType, (a: unknown, b: unknown) => boolean>> = {
|
|
304
304
|
'boolean': (a: unknown, b: unknown) => Boolean(a) === Boolean(b),
|
|
305
|
-
'directory': (a: unknown, b: unknown) =>
|
|
305
|
+
'directory': (a: unknown, b: unknown) => {
|
|
306
|
+
const notCaseSensitive = process.platform === 'darwin';
|
|
307
|
+
const transformedA = path.resolve(unhome(untildify(notCaseSensitive ? String(a).toLowerCase() : String(a))))
|
|
308
|
+
const transformedB = path.resolve(unhome(untildify(notCaseSensitive ? String(b).toLowerCase() : String(b))))
|
|
309
|
+
|
|
310
|
+
return transformedA === transformedB;
|
|
311
|
+
},
|
|
306
312
|
'number': (a: unknown, b: unknown) => Number(a) === Number(b),
|
|
307
313
|
'string': (a: unknown, b: unknown) => String(a) === String(b),
|
|
308
314
|
'version': (desired: unknown, current: unknown) => String(current).includes(String(desired)),
|
|
@@ -362,7 +368,7 @@ export function resolveFnFromEqualsFnOrString(
|
|
|
362
368
|
|
|
363
369
|
const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, InputTransformation>> = {
|
|
364
370
|
'directory': {
|
|
365
|
-
to: (a: unknown) => path.resolve(untildify(String(a))),
|
|
371
|
+
to: (a: unknown) => path.resolve(unhome(untildify(String(a)))),
|
|
366
372
|
from: (a: unknown) => tildify(String(a)),
|
|
367
373
|
},
|
|
368
374
|
'string': {
|
package/src/utils/utils.ts
CHANGED
|
@@ -37,6 +37,10 @@ export function tildify(pathWithTilde: string) {
|
|
|
37
37
|
return homeDirectory ? pathWithTilde.replace(homeDirectory, '~') : pathWithTilde;
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
export function unhome(pathWithHome: string): string {
|
|
41
|
+
return pathWithHome.includes('$HOME') ? pathWithHome.replaceAll('$HOME', os.homedir()) : pathWithHome;
|
|
42
|
+
}
|
|
43
|
+
|
|
40
44
|
export function areArraysEqual(
|
|
41
45
|
isElementEqual: ((desired: unknown, current: unknown) => boolean) | undefined,
|
|
42
46
|
desired: unknown,
|