codify-plugin-lib 1.0.140 → 1.0.142

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/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?.requiredParameters ?? settings.schema?.required ?? []
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];
@@ -43,14 +43,15 @@ export class Plugin {
43
43
  ?? null);
44
44
  const allowMultiple = resource.settings.allowMultiple !== undefined
45
45
  ? (typeof resource.settings.allowMultiple === 'boolean'
46
- ? { requiredParameters: schema?.required ?? [] }
47
- : { requiredParameters: resource.settings.allowMultiple.requiredParameters ?? schema?.required ?? [] }) : undefined;
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,
51
51
  dependencies: resource.dependencies,
52
52
  schema: schema,
53
53
  importAndDestroy: {
54
+ preventImport: resource.settings.importAndDestroy?.preventImport,
54
55
  requiredParameters: requiredPropertyNames,
55
56
  },
56
57
  import: {
@@ -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
- requiredParameters?: string[];
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.
@@ -87,6 +87,13 @@ export interface ResourceSettings<T extends StringIndexedObject> {
87
87
  * ```
88
88
  */
89
89
  importAndDestroy?: {
90
+ /**
91
+ * Can this resources be imported? If set to false then the codifyCLI will skip over/not consider this
92
+ * resource valid for imports. Defaults to true.
93
+ *
94
+ * Resources that can't be imported in the core library for example are: action resources
95
+ */
96
+ preventImport?: boolean;
90
97
  /**
91
98
  * Customize the required parameters needed to import this resource. By default, the `requiredParameters` are taken
92
99
  * from the JSON schema. The `requiredParameters` parameter must be declared if a complex required is declared in
@@ -54,6 +54,10 @@ const ParameterTransformationDefaults = {
54
54
  'string': {
55
55
  to: String,
56
56
  from: String,
57
+ },
58
+ 'boolean': {
59
+ to: Boolean,
60
+ from: Boolean,
57
61
  }
58
62
  };
59
63
  export function resolveParameterTransformFn(parameter) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.140",
3
+ "version": "1.0.142",
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.66",
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",
@@ -241,7 +241,7 @@ describe('Plan entity tests', () => {
241
241
  propB: { type: 'string', canModify: true },
242
242
  },
243
243
  allowMultiple: {
244
- requiredParameters: ['propA']
244
+ identifyingParameters: ['propA']
245
245
  }
246
246
  }
247
247
  }
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?.requiredParameters ?? (settings.schema?.required as string[]) ?? []
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
  });
@@ -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
- ? { requiredParameters: schema?.required ?? [] }
78
- : { requiredParameters: resource.settings.allowMultiple.requiredParameters ?? schema?.required ?? [] }
77
+ ? { identifyingParameters: schema?.required ?? [] }
78
+ : { identifyingParameters: resource.settings.allowMultiple.identifyingParameters ?? schema?.required ?? [] }
79
79
  ) : undefined
80
80
 
81
81
  return {
@@ -84,6 +84,7 @@ export class Plugin {
84
84
  dependencies: resource.dependencies,
85
85
  schema: schema as Record<string, unknown> | undefined,
86
86
  importAndDestroy: {
87
+ preventImport: resource.settings.importAndDestroy?.preventImport,
87
88
  requiredParameters: requiredPropertyNames,
88
89
  },
89
90
  import: {
@@ -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
- requiredParameters?: string[]
45
+ identifyingParameters?: string[]
46
46
 
47
47
  /**
48
48
  * If multiple copies are allowed then a matcher must be defined to match the desired
@@ -103,6 +103,13 @@ export interface ResourceSettings<T extends StringIndexedObject> {
103
103
  * ```
104
104
  */
105
105
  importAndDestroy?: {
106
+ /**
107
+ * Can this resources be imported? If set to false then the codifyCLI will skip over/not consider this
108
+ * resource valid for imports. Defaults to true.
109
+ *
110
+ * Resources that can't be imported in the core library for example are: action resources
111
+ */
112
+ preventImport?: boolean;
106
113
 
107
114
  /**
108
115
  * Customize the required parameters needed to import this resource. By default, the `requiredParameters` are taken
@@ -133,7 +140,7 @@ export interface ResourceSettings<T extends StringIndexedObject> {
133
140
  *
134
141
  * See {@link importAndDestroy} for more information on how importing works.
135
142
  */
136
- defaultRefreshValues?: Partial<T>
143
+ defaultRefreshValues?: Partial<T>;
137
144
  }
138
145
  }
139
146
 
@@ -361,6 +368,10 @@ const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, Inpu
361
368
  'string': {
362
369
  to: String,
363
370
  from: String,
371
+ },
372
+ 'boolean': {
373
+ to: Boolean,
374
+ from: Boolean,
364
375
  }
365
376
  }
366
377