codify-plugin-lib 1.0.157 → 1.0.159

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
@@ -189,8 +189,8 @@ export class Plan {
189
189
  return null;
190
190
  }
191
191
  // For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
192
- // requires additional filtering for stateful parameter arrays and objects. Use this for stateful destroys as well.
193
- if (isStateful && desired !== null) {
192
+ // requires additional filtering for stateful parameter arrays and objects.
193
+ if (isStateful) {
194
194
  return filteredCurrent;
195
195
  }
196
196
  // TODO: Add object handling here in addition to arrays in the future
@@ -32,4 +32,5 @@ export declare class ResourceController<T extends StringIndexedObject> {
32
32
  private validatePlanInputs;
33
33
  private getSortedStatefulParameterChanges;
34
34
  private getAllParameterKeys;
35
+ private getParametersToRefreshForImport;
35
36
  }
@@ -193,22 +193,7 @@ export class ResourceController {
193
193
  this.addDefaultValues(parameters);
194
194
  await this.applyTransformParameters(parameters);
195
195
  // Use refresh parameters if specified, otherwise try to refresh as many parameters as possible here
196
- const parametersToRefresh = this.settings.importAndDestroy?.refreshKeys
197
- ? {
198
- ...Object.fromEntries(this.settings.importAndDestroy?.refreshKeys.map((k) => [k, null])),
199
- ...this.settings.importAndDestroy?.defaultRefreshValues,
200
- ...parameters,
201
- ...(Object.fromEntries(// If a default value was used, but it was also declared in the defaultRefreshValues, prefer the defaultRefreshValue instead
202
- Object.entries(parameters).filter(([k, v]) => this.parsedSettings.defaultValues[k] !== undefined
203
- && v === this.parsedSettings.defaultValues[k]
204
- && context.originalDesiredConfig?.[k] === undefined
205
- && this.settings.importAndDestroy?.defaultRefreshValues?.[k] !== undefined).map(([k]) => [k, this.settings.importAndDestroy.defaultRefreshValues[k]])))
206
- }
207
- : {
208
- ...Object.fromEntries(this.getAllParameterKeys().map((k) => [k, null])),
209
- ...this.settings.importAndDestroy?.defaultRefreshValues,
210
- ...parameters,
211
- };
196
+ const parametersToRefresh = this.getParametersToRefreshForImport(parameters, context);
212
197
  // Parse data from the user supplied config
213
198
  const parsedConfig = new ConfigParser(parametersToRefresh, null, this.parsedSettings.statefulParameters);
214
199
  const { allParameters, allNonStatefulParameters, allStatefulParameters, } = parsedConfig;
@@ -222,7 +207,7 @@ export class ResourceController {
222
207
  const resultParametersArray = currentParametersArray
223
208
  ?.map((r, idx) => ({ ...r, ...statefulCurrentParameters[idx] }));
224
209
  for (const result of resultParametersArray) {
225
- await this.applyTransformParameters(result, true);
210
+ await this.applyTransformParameters(result, { original: parameters });
226
211
  this.removeDefaultValues(result, parameters);
227
212
  }
228
213
  return resultParametersArray?.map((r) => ({ core, parameters: r }));
@@ -287,7 +272,7 @@ ${JSON.stringify(refresh, null, 2)}
287
272
  `);
288
273
  }
289
274
  }
290
- async applyTransformParameters(config, reverse = false) {
275
+ async applyTransformParameters(config, reverse) {
291
276
  if (!config) {
292
277
  return;
293
278
  }
@@ -296,12 +281,12 @@ ${JSON.stringify(refresh, null, 2)}
296
281
  continue;
297
282
  }
298
283
  config[key] = reverse
299
- ? await inputTransformation.from(config[key])
284
+ ? await inputTransformation.from(config[key], reverse.original)
300
285
  : await inputTransformation.to(config[key]);
301
286
  }
302
287
  if (this.settings.transformation) {
303
288
  const transformed = reverse
304
- ? await this.settings.transformation.from({ ...config })
289
+ ? await this.settings.transformation.from({ ...config }, reverse.original)
305
290
  : await this.settings.transformation.to({ ...config });
306
291
  Object.keys(config).forEach((k) => delete config[k]);
307
292
  Object.assign(config, transformed);
@@ -373,4 +358,25 @@ ${JSON.stringify(refresh, null, 2)}
373
358
  ? Object.keys(this.settings.schema?.properties)
374
359
  : Object.keys(this.parsedSettings.parameterSettings);
375
360
  }
361
+ getParametersToRefreshForImport(parameters, context) {
362
+ if (this.settings.importAndDestroy?.refreshMapper) {
363
+ return this.settings.importAndDestroy?.refreshMapper(parameters, context);
364
+ }
365
+ return this.settings.importAndDestroy?.refreshKeys
366
+ ? {
367
+ ...Object.fromEntries(this.settings.importAndDestroy?.refreshKeys.map((k) => [k, null])),
368
+ ...this.settings.importAndDestroy?.defaultRefreshValues,
369
+ ...parameters,
370
+ ...(Object.fromEntries(// If a default value was used, but it was also declared in the defaultRefreshValues, prefer the defaultRefreshValue instead
371
+ Object.entries(parameters).filter(([k, v]) => this.parsedSettings.defaultValues[k] !== undefined
372
+ && v === this.parsedSettings.defaultValues[k]
373
+ && context.originalDesiredConfig?.[k] === undefined
374
+ && this.settings.importAndDestroy?.defaultRefreshValues?.[k] !== undefined).map(([k]) => [k, this.settings.importAndDestroy.defaultRefreshValues[k]])))
375
+ }
376
+ : {
377
+ ...Object.fromEntries(this.getAllParameterKeys().map((k) => [k, null])),
378
+ ...this.settings.importAndDestroy?.defaultRefreshValues,
379
+ ...parameters,
380
+ };
381
+ }
376
382
  }
@@ -1,9 +1,10 @@
1
1
  import { JSONSchemaType } from 'ajv';
2
2
  import { StringIndexedObject } from 'codify-schemas';
3
3
  import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
4
+ import { RefreshContext } from './resource.js';
4
5
  export interface InputTransformation {
5
6
  to: (input: any) => Promise<any> | any;
6
- from: (current: any) => Promise<any> | any;
7
+ from: (current: any, original: any) => Promise<any> | any;
7
8
  }
8
9
  /**
9
10
  * The configuration and settings for a resource.
@@ -122,6 +123,14 @@ export interface ResourceSettings<T extends StringIndexedObject> {
122
123
  * See {@link importAndDestroy} for more information on how importing works.
123
124
  */
124
125
  defaultRefreshValues?: Partial<T>;
126
+ /**
127
+ * A custom function that maps the input to what gets passed to refresh for imports. If this is set, then refreshKeys and
128
+ * defaultRefreshValues are ignored.
129
+ *
130
+ * @param input
131
+ * @param context
132
+ */
133
+ refreshMapper?: (input: Partial<T>, context: RefreshContext<T>) => Partial<T>;
125
134
  };
126
135
  }
127
136
  /**
@@ -1,6 +1,6 @@
1
1
  import isObjectsEqual from 'lodash.isequal';
2
2
  import path from 'node:path';
3
- import { addVariablesToPath, areArraysEqual, resolvePathWithVariables, tildify, untildify } from '../utils/utils.js';
3
+ import { addVariablesToPath, areArraysEqual, resolvePathWithVariables, untildify } from '../utils/utils.js';
4
4
  const ParameterEqualsDefaults = {
5
5
  'boolean': (a, b) => Boolean(a) === Boolean(b),
6
6
  'directory': (a, b) => {
@@ -54,7 +54,12 @@ export function resolveFnFromEqualsFnOrString(fnOrString) {
54
54
  const ParameterTransformationDefaults = {
55
55
  'directory': {
56
56
  to: (a) => path.resolve(resolvePathWithVariables((untildify(String(a))))),
57
- from: (a) => addVariablesToPath(tildify(String(a))),
57
+ from: (a, original) => {
58
+ if (ParameterEqualsDefaults.directory(a, original)) {
59
+ return original;
60
+ }
61
+ return addVariablesToPath(String(a));
62
+ },
58
63
  },
59
64
  'string': {
60
65
  to: String,
@@ -83,8 +88,8 @@ export function resolveParameterTransformFn(parameter) {
83
88
  to(input) {
84
89
  return input.map((i) => itemTransformation.to(i));
85
90
  },
86
- from(input) {
87
- return input.map((i) => itemTransformation.from(i));
91
+ from(input, original) {
92
+ return input.map((i) => itemTransformation.from(i, original));
88
93
  }
89
94
  };
90
95
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codify-plugin-lib",
3
- "version": "1.0.157",
3
+ "version": "1.0.159",
4
4
  "description": "Library plugin library",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
package/src/plan/plan.ts CHANGED
@@ -312,8 +312,8 @@ export class Plan<T extends StringIndexedObject> {
312
312
  }
313
313
 
314
314
  // For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
315
- // requires additional filtering for stateful parameter arrays and objects. Use this for stateful destroys as well.
316
- if (isStateful && desired !== null) {
315
+ // requires additional filtering for stateful parameter arrays and objects.
316
+ if (isStateful) {
317
317
  return filteredCurrent;
318
318
  }
319
319
 
@@ -274,29 +274,7 @@ export class ResourceController<T extends StringIndexedObject> {
274
274
  await this.applyTransformParameters(parameters);
275
275
 
276
276
  // Use refresh parameters if specified, otherwise try to refresh as many parameters as possible here
277
- const parametersToRefresh = this.settings.importAndDestroy?.refreshKeys
278
- ? {
279
- ...Object.fromEntries(
280
- this.settings.importAndDestroy?.refreshKeys.map((k) => [k, null])
281
- ),
282
- ...this.settings.importAndDestroy?.defaultRefreshValues,
283
- ...parameters,
284
- ...(Object.fromEntries( // If a default value was used, but it was also declared in the defaultRefreshValues, prefer the defaultRefreshValue instead
285
- Object.entries(parameters).filter(([k, v]) =>
286
- this.parsedSettings.defaultValues[k] !== undefined
287
- && v === this.parsedSettings.defaultValues[k]
288
- && context.originalDesiredConfig?.[k] === undefined
289
- && this.settings.importAndDestroy?.defaultRefreshValues?.[k] !== undefined
290
- ).map(([k]) => [k, this.settings.importAndDestroy!.defaultRefreshValues![k]])
291
- ))
292
- }
293
- : {
294
- ...Object.fromEntries(
295
- this.getAllParameterKeys().map((k) => [k, null])
296
- ),
297
- ...this.settings.importAndDestroy?.defaultRefreshValues,
298
- ...parameters,
299
- };
277
+ const parametersToRefresh = this.getParametersToRefreshForImport(parameters, context);
300
278
 
301
279
  // Parse data from the user supplied config
302
280
  const parsedConfig = new ConfigParser(parametersToRefresh, null, this.parsedSettings.statefulParameters)
@@ -320,11 +298,13 @@ export class ResourceController<T extends StringIndexedObject> {
320
298
  ?.map((r, idx) => ({ ...r, ...statefulCurrentParameters[idx] }))
321
299
 
322
300
  for (const result of resultParametersArray) {
323
- await this.applyTransformParameters(result, true);
301
+ await this.applyTransformParameters(result, { original: parameters });
324
302
  this.removeDefaultValues(result, parameters);
325
303
  }
326
304
 
327
305
  return resultParametersArray?.map((r) => ({ core, parameters: r }))
306
+
307
+
328
308
  }
329
309
 
330
310
  private async applyCreate(plan: Plan<T>): Promise<void> {
@@ -403,7 +383,7 @@ ${JSON.stringify(refresh, null, 2)}
403
383
  }
404
384
  }
405
385
 
406
- private async applyTransformParameters(config: Partial<T> | null, reverse = false): Promise<void> {
386
+ private async applyTransformParameters(config: Partial<T> | null, reverse?: { original: Partial<T> }): Promise<void> {
407
387
  if (!config) {
408
388
  return;
409
389
  }
@@ -414,13 +394,13 @@ ${JSON.stringify(refresh, null, 2)}
414
394
  }
415
395
 
416
396
  (config as Record<string, unknown>)[key] = reverse
417
- ? await inputTransformation.from(config[key])
397
+ ? await inputTransformation.from(config[key], reverse.original)
418
398
  : await inputTransformation.to(config[key]);
419
399
  }
420
400
 
421
401
  if (this.settings.transformation) {
422
402
  const transformed = reverse
423
- ? await this.settings.transformation.from({ ...config })
403
+ ? await this.settings.transformation.from({ ...config }, reverse.original)
424
404
  : await this.settings.transformation.to({ ...config })
425
405
 
426
406
  Object.keys(config).forEach((k) => delete config[k])
@@ -523,5 +503,35 @@ ${JSON.stringify(refresh, null, 2)}
523
503
  ? Object.keys((this.settings.schema as any)?.properties)
524
504
  : Object.keys(this.parsedSettings.parameterSettings);
525
505
  }
506
+
507
+ private getParametersToRefreshForImport(parameters: Partial<T>, context: RefreshContext<T>): Partial<T> {
508
+ if (this.settings.importAndDestroy?.refreshMapper) {
509
+ return this.settings.importAndDestroy?.refreshMapper(parameters, context);
510
+ }
511
+
512
+ return this.settings.importAndDestroy?.refreshKeys
513
+ ? {
514
+ ...Object.fromEntries(
515
+ this.settings.importAndDestroy?.refreshKeys.map((k) => [k, null])
516
+ ),
517
+ ...this.settings.importAndDestroy?.defaultRefreshValues,
518
+ ...parameters,
519
+ ...(Object.fromEntries( // If a default value was used, but it was also declared in the defaultRefreshValues, prefer the defaultRefreshValue instead
520
+ Object.entries(parameters).filter(([k, v]) =>
521
+ this.parsedSettings.defaultValues[k] !== undefined
522
+ && v === this.parsedSettings.defaultValues[k]
523
+ && context.originalDesiredConfig?.[k] === undefined
524
+ && this.settings.importAndDestroy?.defaultRefreshValues?.[k] !== undefined
525
+ ).map(([k]) => [k, this.settings.importAndDestroy!.defaultRefreshValues![k]])
526
+ ))
527
+ }
528
+ : {
529
+ ...Object.fromEntries(
530
+ this.getAllParameterKeys().map((k) => [k, null])
531
+ ),
532
+ ...this.settings.importAndDestroy?.defaultRefreshValues,
533
+ ...parameters,
534
+ };
535
+ }
526
536
  }
527
537
 
@@ -5,10 +5,12 @@ import path from 'node:path';
5
5
 
6
6
  import { ArrayStatefulParameter, StatefulParameter } from '../stateful-parameter/stateful-parameter.js';
7
7
  import { addVariablesToPath, areArraysEqual, resolvePathWithVariables, tildify, untildify } from '../utils/utils.js';
8
+ import { or } from 'ajv/dist/compile/codegen/index.js';
9
+ import { RefreshContext } from './resource.js';
8
10
 
9
11
  export interface InputTransformation {
10
12
  to: (input: any) => Promise<any> | any;
11
- from: (current: any) => Promise<any> | any;
13
+ from: (current: any, original: any) => Promise<any> | any;
12
14
  }
13
15
 
14
16
  /**
@@ -141,6 +143,15 @@ export interface ResourceSettings<T extends StringIndexedObject> {
141
143
  * See {@link importAndDestroy} for more information on how importing works.
142
144
  */
143
145
  defaultRefreshValues?: Partial<T>;
146
+
147
+ /**
148
+ * A custom function that maps the input to what gets passed to refresh for imports. If this is set, then refreshKeys and
149
+ * defaultRefreshValues are ignored.
150
+ *
151
+ * @param input
152
+ * @param context
153
+ */
154
+ refreshMapper?: (input: Partial<T>, context: RefreshContext<T>) => Partial<T>
144
155
  }
145
156
  }
146
157
 
@@ -369,7 +380,13 @@ export function resolveFnFromEqualsFnOrString(
369
380
  const ParameterTransformationDefaults: Partial<Record<ParameterSettingType, InputTransformation>> = {
370
381
  'directory': {
371
382
  to: (a: unknown) => path.resolve(resolvePathWithVariables((untildify(String(a))))),
372
- from: (a: unknown) => addVariablesToPath(tildify(String(a))),
383
+ from: (a: unknown, original) => {
384
+ if (ParameterEqualsDefaults.directory!(a, original)) {
385
+ return original;
386
+ }
387
+
388
+ return addVariablesToPath(String(a))
389
+ },
373
390
  },
374
391
  'string': {
375
392
  to: String,
@@ -406,8 +423,8 @@ export function resolveParameterTransformFn(
406
423
  to(input: unknown[]) {
407
424
  return input.map((i) => itemTransformation.to(i))
408
425
  },
409
- from(input: unknown[]) {
410
- return input.map((i) => itemTransformation.from(i))
426
+ from(input: unknown[], original) {
427
+ return input.map((i) => itemTransformation.from(i, original))
411
428
  }
412
429
  }
413
430
  }