codify-plugin-lib 1.0.141 → 1.0.143
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/messages/handlers.js +1 -1
- package/dist/plan/plan.js +1 -1
- package/dist/plugin/plugin.js +2 -2
- package/dist/resource/resource-controller.d.ts +1 -0
- package/dist/resource/resource-controller.js +14 -0
- package/dist/resource/resource-settings.d.ts +1 -1
- package/dist/resource/resource-settings.js +4 -0
- package/package.json +2 -2
- package/src/messages/handlers.ts +1 -1
- package/src/plan/plan.test.ts +1 -1
- package/src/plan/plan.ts +1 -1
- package/src/plugin/plugin.test.ts +42 -0
- package/src/plugin/plugin.ts +2 -2
- package/src/resource/resource-controller.test.ts +35 -0
- package/src/resource/resource-controller.ts +19 -0
- package/src/resource/resource-settings.ts +5 -1
|
@@ -71,7 +71,7 @@ export class MessageHandler {
|
|
|
71
71
|
const result = await SupportedRequests[message.cmd].handler(this.plugin, message.data);
|
|
72
72
|
const responseValidator = this.responseValidators.get(message.cmd);
|
|
73
73
|
if (responseValidator && !responseValidator(result)) {
|
|
74
|
-
throw new Error(`Plugin: ${this.plugin}. Malformed response data: ${JSON.stringify(responseValidator.errors, null, 2)}`);
|
|
74
|
+
throw new Error(`Plugin: ${this.plugin.name}. Malformed response data: ${JSON.stringify(responseValidator.errors, null, 2)}. Received ${JSON.stringify(result, null, 2)}`);
|
|
75
75
|
}
|
|
76
76
|
process.send({
|
|
77
77
|
cmd: message.cmd + '_Response',
|
package/dist/plan/plan.js
CHANGED
|
@@ -159,7 +159,7 @@ export class Plan {
|
|
|
159
159
|
const matcher = typeof settings.allowMultiple === 'boolean' || !settings.allowMultiple.matcher
|
|
160
160
|
? ((desired, currentArr) => {
|
|
161
161
|
const requiredParameters = typeof settings.allowMultiple === 'object'
|
|
162
|
-
? settings.allowMultiple?.
|
|
162
|
+
? settings.allowMultiple?.identifyingParameters ?? settings.schema?.required ?? []
|
|
163
163
|
: settings.schema?.required ?? [];
|
|
164
164
|
const matched = currentArr.filter((c) => requiredParameters.every((key) => {
|
|
165
165
|
const currentParameter = c[key];
|
package/dist/plugin/plugin.js
CHANGED
|
@@ -43,8 +43,8 @@ export class Plugin {
|
|
|
43
43
|
?? null);
|
|
44
44
|
const allowMultiple = resource.settings.allowMultiple !== undefined
|
|
45
45
|
? (typeof resource.settings.allowMultiple === 'boolean'
|
|
46
|
-
? {
|
|
47
|
-
: {
|
|
46
|
+
? { identifyingParameters: schema?.required ?? [] }
|
|
47
|
+
: { identifyingParameters: resource.settings.allowMultiple.identifyingParameters ?? schema?.required ?? [] }) : undefined;
|
|
48
48
|
return {
|
|
49
49
|
plugin: this.name,
|
|
50
50
|
type: data.type,
|
|
@@ -25,6 +25,7 @@ export declare class ResourceController<T extends StringIndexedObject> {
|
|
|
25
25
|
private validateRefreshResults;
|
|
26
26
|
private applyTransformParameters;
|
|
27
27
|
private addDefaultValues;
|
|
28
|
+
private removeDefaultValues;
|
|
28
29
|
private refreshNonStatefulParameters;
|
|
29
30
|
private refreshStatefulParameters;
|
|
30
31
|
private validatePlanInputs;
|
|
@@ -147,6 +147,9 @@ export class ResourceController {
|
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
async import(core, parameters) {
|
|
150
|
+
if (this.settings.importAndDestroy?.preventImport) {
|
|
151
|
+
throw new Error(`Type: ${this.typeId} cannot be imported`);
|
|
152
|
+
}
|
|
150
153
|
this.addDefaultValues(parameters);
|
|
151
154
|
await this.applyTransformParameters(parameters);
|
|
152
155
|
// Use refresh parameters if specified, otherwise try to refresh as many parameters as possible here
|
|
@@ -176,6 +179,7 @@ export class ResourceController {
|
|
|
176
179
|
const statefulCurrentParameters = await this.refreshStatefulParameters(allStatefulParameters, parametersToRefresh);
|
|
177
180
|
const resultParameters = { ...currentParametersArray[0], ...statefulCurrentParameters };
|
|
178
181
|
await this.applyTransformParameters(resultParameters, true);
|
|
182
|
+
this.removeDefaultValues(resultParameters, parameters);
|
|
179
183
|
return [{ core, parameters: resultParameters }];
|
|
180
184
|
}
|
|
181
185
|
async applyCreate(plan) {
|
|
@@ -268,6 +272,16 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
268
272
|
}
|
|
269
273
|
}
|
|
270
274
|
}
|
|
275
|
+
removeDefaultValues(newConfig, originalConfig) {
|
|
276
|
+
if (!newConfig) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
for (const [key, defaultValue] of Object.entries(this.parsedSettings.defaultValues)) {
|
|
280
|
+
if (defaultValue !== undefined && (newConfig[key] === defaultValue || originalConfig[key] === undefined || originalConfig[key] === null)) {
|
|
281
|
+
delete newConfig[key];
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
271
285
|
async refreshNonStatefulParameters(resourceParameters) {
|
|
272
286
|
const result = await this.resource.refresh(resourceParameters);
|
|
273
287
|
const currentParametersArray = Array.isArray(result) || result === null
|
|
@@ -32,7 +32,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
32
32
|
* If paramA is required, then if resource1.paramA === resource2.paramA then are the same resource.
|
|
33
33
|
* If resource1.paramA !== resource1.paramA, then they are different.
|
|
34
34
|
*/
|
|
35
|
-
|
|
35
|
+
identifyingParameters?: string[];
|
|
36
36
|
/**
|
|
37
37
|
* If multiple copies are allowed then a matcher must be defined to match the desired
|
|
38
38
|
* config with one of the resources currently existing on the system. Return null if there is no match.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "codify-plugin-lib",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.143",
|
|
4
4
|
"description": "Library plugin library",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"typings": "dist/index.d.ts",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"ajv": "^8.12.0",
|
|
18
18
|
"ajv-formats": "^2.1.1",
|
|
19
|
-
"codify-schemas": "1.0.
|
|
19
|
+
"codify-schemas": "1.0.70",
|
|
20
20
|
"@npmcli/promise-spawn": "^7.0.1",
|
|
21
21
|
"@homebridge/node-pty-prebuilt-multiarch": "^0.12.0-beta.5",
|
|
22
22
|
"uuid": "^10.0.0",
|
package/src/messages/handlers.ts
CHANGED
|
@@ -106,7 +106,7 @@ export class MessageHandler {
|
|
|
106
106
|
|
|
107
107
|
const responseValidator = this.responseValidators.get(message.cmd);
|
|
108
108
|
if (responseValidator && !responseValidator(result)) {
|
|
109
|
-
throw new Error(`Plugin: ${this.plugin}. Malformed response data: ${JSON.stringify(responseValidator.errors, null, 2)}`)
|
|
109
|
+
throw new Error(`Plugin: ${this.plugin.name}. Malformed response data: ${JSON.stringify(responseValidator.errors, null, 2)}. Received ${JSON.stringify(result, null, 2)}`);
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
process.send!({
|
package/src/plan/plan.test.ts
CHANGED
package/src/plan/plan.ts
CHANGED
|
@@ -263,7 +263,7 @@ export class Plan<T extends StringIndexedObject> {
|
|
|
263
263
|
const matcher = typeof settings.allowMultiple === 'boolean' || !settings.allowMultiple.matcher
|
|
264
264
|
? ((desired: Partial<T>, currentArr: Array<Partial<T>>) => {
|
|
265
265
|
const requiredParameters = typeof settings.allowMultiple === 'object'
|
|
266
|
-
? settings.allowMultiple?.
|
|
266
|
+
? settings.allowMultiple?.identifyingParameters ?? (settings.schema?.required as string[]) ?? []
|
|
267
267
|
: (settings.schema?.required as string[]) ?? []
|
|
268
268
|
|
|
269
269
|
const matched = currentArr.filter((c) => requiredParameters.every((key) => {
|
|
@@ -324,4 +324,46 @@ describe('Plugin tests', () => {
|
|
|
324
324
|
|
|
325
325
|
console.log(result);
|
|
326
326
|
})
|
|
327
|
+
|
|
328
|
+
it('Returns allowMultiple for getResourceInfo', async () => {
|
|
329
|
+
const resource = spy(new class extends TestResource {
|
|
330
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
331
|
+
return {
|
|
332
|
+
...super.getSettings(),
|
|
333
|
+
allowMultiple: {
|
|
334
|
+
identifyingParameters: ['path', 'paths']
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
const testPlugin = Plugin.create('testPlugin', [resource as any]);
|
|
341
|
+
|
|
342
|
+
const resourceInfo = await testPlugin.getResourceInfo({
|
|
343
|
+
type: 'testResource',
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
expect(resourceInfo.allowMultiple?.requiredParameters).toMatchObject([
|
|
347
|
+
'path', 'paths'
|
|
348
|
+
])
|
|
349
|
+
})
|
|
350
|
+
|
|
351
|
+
it('Returns an empty array by default for allowMultiple for getResourceInfo', async () => {
|
|
352
|
+
const resource = spy(new class extends TestResource {
|
|
353
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
354
|
+
return {
|
|
355
|
+
...super.getSettings(),
|
|
356
|
+
allowMultiple: true
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
})
|
|
360
|
+
|
|
361
|
+
const testPlugin = Plugin.create('testPlugin', [resource as any]);
|
|
362
|
+
|
|
363
|
+
const resourceInfo = await testPlugin.getResourceInfo({
|
|
364
|
+
type: 'testResource',
|
|
365
|
+
})
|
|
366
|
+
|
|
367
|
+
expect(resourceInfo.allowMultiple?.requiredParameters).toMatchObject([])
|
|
368
|
+
})
|
|
327
369
|
});
|
package/src/plugin/plugin.ts
CHANGED
|
@@ -74,8 +74,8 @@ export class Plugin {
|
|
|
74
74
|
|
|
75
75
|
const allowMultiple = resource.settings.allowMultiple !== undefined
|
|
76
76
|
? (typeof resource.settings.allowMultiple === 'boolean'
|
|
77
|
-
? {
|
|
78
|
-
: {
|
|
77
|
+
? { identifyingParameters: schema?.required ?? [] }
|
|
78
|
+
: { identifyingParameters: resource.settings.allowMultiple.identifyingParameters ?? schema?.required ?? [] }
|
|
79
79
|
) : undefined
|
|
80
80
|
|
|
81
81
|
return {
|
|
@@ -711,4 +711,39 @@ describe('Resource tests', () => {
|
|
|
711
711
|
}
|
|
712
712
|
})
|
|
713
713
|
})
|
|
714
|
+
|
|
715
|
+
it('Applies removes default values if they remain default for imports', async () => {
|
|
716
|
+
const resource = new class extends TestResource {
|
|
717
|
+
getSettings(): ResourceSettings<TestConfig> {
|
|
718
|
+
return {
|
|
719
|
+
id: 'resourceType',
|
|
720
|
+
parameterSettings: {
|
|
721
|
+
propA: { type: 'string', default: 'defaultValue' },
|
|
722
|
+
propB: { type: 'boolean', default: true }
|
|
723
|
+
},
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
async refresh(parameters: Partial<TestConfig>): Promise<Partial<TestConfig> | null> {
|
|
728
|
+
return {
|
|
729
|
+
propA: 'defaultValue',
|
|
730
|
+
propB: false,
|
|
731
|
+
propC: 'newPropC'
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const controller = new ResourceController(resource);
|
|
737
|
+
const plan = await controller.import({ type: 'resourceType' }, {});
|
|
738
|
+
|
|
739
|
+
expect(plan![0]).toMatchObject({
|
|
740
|
+
'core': {
|
|
741
|
+
'type': 'resourceType'
|
|
742
|
+
},
|
|
743
|
+
'parameters': {
|
|
744
|
+
propB: false,
|
|
745
|
+
propC: 'newPropC'
|
|
746
|
+
}
|
|
747
|
+
})
|
|
748
|
+
})
|
|
714
749
|
});
|
|
@@ -214,6 +214,10 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
214
214
|
core: ResourceConfig,
|
|
215
215
|
parameters: Partial<T>
|
|
216
216
|
): Promise<Array<ResourceJson> | null> {
|
|
217
|
+
if (this.settings.importAndDestroy?.preventImport) {
|
|
218
|
+
throw new Error(`Type: ${this.typeId} cannot be imported`);
|
|
219
|
+
}
|
|
220
|
+
|
|
217
221
|
this.addDefaultValues(parameters);
|
|
218
222
|
await this.applyTransformParameters(parameters);
|
|
219
223
|
|
|
@@ -257,6 +261,8 @@ export class ResourceController<T extends StringIndexedObject> {
|
|
|
257
261
|
const resultParameters = { ...currentParametersArray[0], ...statefulCurrentParameters };
|
|
258
262
|
|
|
259
263
|
await this.applyTransformParameters(resultParameters, true);
|
|
264
|
+
this.removeDefaultValues(resultParameters, parameters)
|
|
265
|
+
|
|
260
266
|
return [{ core, parameters: resultParameters }];
|
|
261
267
|
}
|
|
262
268
|
|
|
@@ -373,6 +379,19 @@ ${JSON.stringify(refresh, null, 2)}
|
|
|
373
379
|
}
|
|
374
380
|
}
|
|
375
381
|
|
|
382
|
+
private removeDefaultValues(newConfig: Partial<T> | null, originalConfig: Partial<T>): void {
|
|
383
|
+
if (!newConfig) {
|
|
384
|
+
return;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
for (const [key, defaultValue] of Object.entries(this.parsedSettings.defaultValues)) {
|
|
388
|
+
if (defaultValue !== undefined && (newConfig[key] === defaultValue || originalConfig[key] === undefined || originalConfig[key] === null)) {
|
|
389
|
+
delete newConfig[key];
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
}
|
|
394
|
+
|
|
376
395
|
private async refreshNonStatefulParameters(resourceParameters: Partial<T>): Promise<Array<Partial<T>> | null> {
|
|
377
396
|
const result = await this.resource.refresh(resourceParameters);
|
|
378
397
|
|
|
@@ -42,7 +42,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
|
|
|
42
42
|
* If paramA is required, then if resource1.paramA === resource2.paramA then are the same resource.
|
|
43
43
|
* If resource1.paramA !== resource1.paramA, then they are different.
|
|
44
44
|
*/
|
|
45
|
-
|
|
45
|
+
identifyingParameters?: string[]
|
|
46
46
|
|
|
47
47
|
/**
|
|
48
48
|
* If multiple copies are allowed then a matcher must be defined to match the desired
|
|
@@ -368,6 +368,10 @@ const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, Inpu
|
|
|
368
368
|
'string': {
|
|
369
369
|
to: String,
|
|
370
370
|
from: String,
|
|
371
|
+
},
|
|
372
|
+
'boolean': {
|
|
373
|
+
to: Boolean,
|
|
374
|
+
from: Boolean,
|
|
371
375
|
}
|
|
372
376
|
}
|
|
373
377
|
|