@codifycli/plugin-core 1.0.0-beta1

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.
Files changed (152) hide show
  1. package/.eslintignore +2 -0
  2. package/.eslintrc.json +30 -0
  3. package/.github/workflows/release.yaml +19 -0
  4. package/.github/workflows/unit-test-ci.yaml +18 -0
  5. package/.prettierrc.json +1 -0
  6. package/bin/build.js +189 -0
  7. package/dist/bin/build.d.ts +1 -0
  8. package/dist/bin/build.js +80 -0
  9. package/dist/bin/deploy-plugin.d.ts +2 -0
  10. package/dist/bin/deploy-plugin.js +8 -0
  11. package/dist/common/errors.d.ts +8 -0
  12. package/dist/common/errors.js +24 -0
  13. package/dist/entities/change-set.d.ts +24 -0
  14. package/dist/entities/change-set.js +152 -0
  15. package/dist/entities/errors.d.ts +4 -0
  16. package/dist/entities/errors.js +7 -0
  17. package/dist/entities/plan-types.d.ts +25 -0
  18. package/dist/entities/plan-types.js +1 -0
  19. package/dist/entities/plan.d.ts +15 -0
  20. package/dist/entities/plan.js +127 -0
  21. package/dist/entities/plugin.d.ts +16 -0
  22. package/dist/entities/plugin.js +80 -0
  23. package/dist/entities/resource-options.d.ts +31 -0
  24. package/dist/entities/resource-options.js +76 -0
  25. package/dist/entities/resource-types.d.ts +11 -0
  26. package/dist/entities/resource-types.js +1 -0
  27. package/dist/entities/resource.d.ts +42 -0
  28. package/dist/entities/resource.js +303 -0
  29. package/dist/entities/stateful-parameter.d.ts +29 -0
  30. package/dist/entities/stateful-parameter.js +46 -0
  31. package/dist/entities/transform-parameter.d.ts +4 -0
  32. package/dist/entities/transform-parameter.js +2 -0
  33. package/dist/errors.d.ts +4 -0
  34. package/dist/errors.js +7 -0
  35. package/dist/index.d.ts +20 -0
  36. package/dist/index.js +26 -0
  37. package/dist/messages/handlers.d.ts +14 -0
  38. package/dist/messages/handlers.js +134 -0
  39. package/dist/messages/sender.d.ts +11 -0
  40. package/dist/messages/sender.js +57 -0
  41. package/dist/plan/change-set.d.ts +53 -0
  42. package/dist/plan/change-set.js +153 -0
  43. package/dist/plan/plan-types.d.ts +23 -0
  44. package/dist/plan/plan-types.js +1 -0
  45. package/dist/plan/plan.d.ts +66 -0
  46. package/dist/plan/plan.js +328 -0
  47. package/dist/plugin/plugin.d.ts +24 -0
  48. package/dist/plugin/plugin.js +200 -0
  49. package/dist/pty/background-pty.d.ts +21 -0
  50. package/dist/pty/background-pty.js +127 -0
  51. package/dist/pty/index.d.ts +50 -0
  52. package/dist/pty/index.js +20 -0
  53. package/dist/pty/promise-queue.d.ts +5 -0
  54. package/dist/pty/promise-queue.js +26 -0
  55. package/dist/pty/seqeuntial-pty.d.ts +17 -0
  56. package/dist/pty/seqeuntial-pty.js +119 -0
  57. package/dist/pty/vitest.config.d.ts +2 -0
  58. package/dist/pty/vitest.config.js +11 -0
  59. package/dist/resource/config-parser.d.ts +11 -0
  60. package/dist/resource/config-parser.js +21 -0
  61. package/dist/resource/parsed-resource-settings.d.ts +47 -0
  62. package/dist/resource/parsed-resource-settings.js +196 -0
  63. package/dist/resource/resource-controller.d.ts +36 -0
  64. package/dist/resource/resource-controller.js +402 -0
  65. package/dist/resource/resource-settings.d.ts +303 -0
  66. package/dist/resource/resource-settings.js +147 -0
  67. package/dist/resource/resource.d.ts +144 -0
  68. package/dist/resource/resource.js +44 -0
  69. package/dist/resource/stateful-parameter.d.ts +165 -0
  70. package/dist/resource/stateful-parameter.js +94 -0
  71. package/dist/scripts/deploy.d.ts +1 -0
  72. package/dist/scripts/deploy.js +2 -0
  73. package/dist/stateful-parameter/stateful-parameter-controller.d.ts +21 -0
  74. package/dist/stateful-parameter/stateful-parameter-controller.js +81 -0
  75. package/dist/stateful-parameter/stateful-parameter.d.ts +144 -0
  76. package/dist/stateful-parameter/stateful-parameter.js +43 -0
  77. package/dist/test.d.ts +1 -0
  78. package/dist/test.js +5 -0
  79. package/dist/utils/codify-spawn.d.ts +29 -0
  80. package/dist/utils/codify-spawn.js +136 -0
  81. package/dist/utils/debug.d.ts +2 -0
  82. package/dist/utils/debug.js +10 -0
  83. package/dist/utils/file-utils.d.ts +23 -0
  84. package/dist/utils/file-utils.js +186 -0
  85. package/dist/utils/functions.d.ts +12 -0
  86. package/dist/utils/functions.js +74 -0
  87. package/dist/utils/index.d.ts +46 -0
  88. package/dist/utils/index.js +271 -0
  89. package/dist/utils/internal-utils.d.ts +12 -0
  90. package/dist/utils/internal-utils.js +74 -0
  91. package/dist/utils/load-resources.d.ts +1 -0
  92. package/dist/utils/load-resources.js +46 -0
  93. package/dist/utils/package-json-utils.d.ts +12 -0
  94. package/dist/utils/package-json-utils.js +34 -0
  95. package/dist/utils/pty-local-storage.d.ts +2 -0
  96. package/dist/utils/pty-local-storage.js +2 -0
  97. package/dist/utils/spawn-2.d.ts +5 -0
  98. package/dist/utils/spawn-2.js +7 -0
  99. package/dist/utils/spawn.d.ts +29 -0
  100. package/dist/utils/spawn.js +124 -0
  101. package/dist/utils/utils.d.ts +18 -0
  102. package/dist/utils/utils.js +86 -0
  103. package/dist/utils/verbosity-level.d.ts +5 -0
  104. package/dist/utils/verbosity-level.js +9 -0
  105. package/package.json +59 -0
  106. package/rollup.config.js +24 -0
  107. package/src/common/errors.test.ts +43 -0
  108. package/src/common/errors.ts +31 -0
  109. package/src/errors.ts +8 -0
  110. package/src/index.test.ts +6 -0
  111. package/src/index.ts +30 -0
  112. package/src/messages/handlers.test.ts +329 -0
  113. package/src/messages/handlers.ts +181 -0
  114. package/src/messages/sender.ts +69 -0
  115. package/src/plan/change-set.test.ts +280 -0
  116. package/src/plan/change-set.ts +236 -0
  117. package/src/plan/plan-types.ts +27 -0
  118. package/src/plan/plan.test.ts +413 -0
  119. package/src/plan/plan.ts +499 -0
  120. package/src/plugin/plugin.test.ts +533 -0
  121. package/src/plugin/plugin.ts +291 -0
  122. package/src/pty/background-pty.test.ts +69 -0
  123. package/src/pty/background-pty.ts +154 -0
  124. package/src/pty/index.test.ts +129 -0
  125. package/src/pty/index.ts +66 -0
  126. package/src/pty/promise-queue.ts +33 -0
  127. package/src/pty/seqeuntial-pty.ts +151 -0
  128. package/src/pty/sequential-pty.test.ts +194 -0
  129. package/src/resource/config-parser.ts +42 -0
  130. package/src/resource/parsed-resource-settings.test.ts +186 -0
  131. package/src/resource/parsed-resource-settings.ts +307 -0
  132. package/src/resource/resource-controller-stateful-mode.test.ts +253 -0
  133. package/src/resource/resource-controller.test.ts +1081 -0
  134. package/src/resource/resource-controller.ts +563 -0
  135. package/src/resource/resource-settings.test.ts +1213 -0
  136. package/src/resource/resource-settings.ts +545 -0
  137. package/src/resource/resource.ts +157 -0
  138. package/src/stateful-parameter/stateful-parameter-controller.test.ts +244 -0
  139. package/src/stateful-parameter/stateful-parameter-controller.ts +111 -0
  140. package/src/stateful-parameter/stateful-parameter.ts +160 -0
  141. package/src/utils/debug.ts +11 -0
  142. package/src/utils/file-utils.test.ts +7 -0
  143. package/src/utils/file-utils.ts +231 -0
  144. package/src/utils/functions.ts +103 -0
  145. package/src/utils/index.ts +340 -0
  146. package/src/utils/internal-utils.test.ts +52 -0
  147. package/src/utils/pty-local-storage.ts +3 -0
  148. package/src/utils/test-utils.test.ts +96 -0
  149. package/src/utils/verbosity-level.ts +11 -0
  150. package/tsconfig.json +26 -0
  151. package/tsconfig.test.json +9 -0
  152. package/vitest.config.ts +10 -0
@@ -0,0 +1,499 @@
1
+ import {
2
+ ApplyRequestData,
3
+ ParameterOperation,
4
+ PlanResponseData,
5
+ ResourceConfig,
6
+ ResourceOperation,
7
+ StringIndexedObject,
8
+ } from 'codify-schemas';
9
+ import { v4 as uuidV4 } from 'uuid';
10
+
11
+ import {
12
+ ParsedArrayParameterSetting,
13
+ ParsedResourceSettings,
14
+ ParsedStatefulParameterSetting
15
+ } from '../resource/parsed-resource-settings.js';
16
+ import { ArrayParameterSetting, ResourceSettings } from '../resource/resource-settings.js';
17
+ import { ChangeSet } from './change-set.js';
18
+
19
+ /**
20
+ * A plan represents a set of actions that after taken will turn the current resource into the desired one.
21
+ * A plan consists of list of parameter level changes (ADD, REMOVE, MODIFY or NO-OP) as well as a resource level
22
+ * operation (CREATE, DESTROY, MODIFY, RE-CREATE, NO-OP).
23
+ */
24
+ export class Plan<T extends StringIndexedObject> {
25
+ id: string;
26
+
27
+ /**
28
+ * List of changes to make
29
+ */
30
+ changeSet: ChangeSet<T>;
31
+
32
+ /**
33
+ * Ex: name, type, dependsOn etc. Metadata parameters
34
+ */
35
+ coreParameters: ResourceConfig;
36
+
37
+ isStateful: boolean;
38
+
39
+ constructor(id: string, changeSet: ChangeSet<T>, coreParameters: ResourceConfig, isStateful: boolean) {
40
+ this.id = id;
41
+ this.changeSet = changeSet;
42
+ this.coreParameters = coreParameters;
43
+ this.isStateful = isStateful;
44
+ }
45
+
46
+ /**
47
+ * The desired config that a plan will achieve after executing all the actions.
48
+ */
49
+ get desiredConfig(): T | null {
50
+ if (this.changeSet.operation === ResourceOperation.DESTROY) {
51
+ return null;
52
+ }
53
+
54
+ return this.changeSet.desiredParameters;
55
+ }
56
+
57
+ /**
58
+ * The current config that the plan is changing.
59
+ */
60
+ get currentConfig(): T | null {
61
+ if (this.changeSet.operation === ResourceOperation.CREATE) {
62
+ return null;
63
+ }
64
+
65
+ return this.changeSet.currentParameters;
66
+ }
67
+
68
+ get resourceId(): string {
69
+ return this.coreParameters.name
70
+ ? `${this.coreParameters.type}.${this.coreParameters.name}`
71
+ : this.coreParameters.type;
72
+ }
73
+
74
+ static calculate<T extends StringIndexedObject>(params: {
75
+ desired: Partial<T> | null,
76
+ currentArray: Partial<T>[] | null,
77
+ state: Partial<T> | null,
78
+ core: ResourceConfig,
79
+ settings: ParsedResourceSettings<T>,
80
+ isStateful: boolean,
81
+ }): Plan<T> {
82
+ const {
83
+ desired,
84
+ currentArray,
85
+ state,
86
+ core,
87
+ settings,
88
+ isStateful
89
+ } = params
90
+
91
+ const current = Plan.matchCurrentParameters<T>({
92
+ desired,
93
+ currentArray,
94
+ state,
95
+ settings,
96
+ isStateful
97
+ });
98
+
99
+ const filteredCurrentParameters = Plan.filterCurrentParams<T>({
100
+ desired,
101
+ current,
102
+ state,
103
+ settings,
104
+ isStateful
105
+ });
106
+
107
+ // Empty
108
+ if (!filteredCurrentParameters && !desired) {
109
+ return new Plan(
110
+ uuidV4(),
111
+ ChangeSet.empty<T>(),
112
+ core,
113
+ isStateful,
114
+ )
115
+ }
116
+
117
+ // CREATE
118
+ if (!filteredCurrentParameters && desired) {
119
+ return new Plan(
120
+ uuidV4(),
121
+ ChangeSet.create(desired, settings),
122
+ core,
123
+ isStateful,
124
+ )
125
+ }
126
+
127
+ // DESTROY
128
+ if (filteredCurrentParameters && !desired) {
129
+ // We can manually override destroys. If a resource cannot be destroyed (for instance the npm resource relies on NodeJS being created and destroyed)
130
+ if (!settings.canDestroy) {
131
+ return new Plan(
132
+ uuidV4(),
133
+ ChangeSet.noop(filteredCurrentParameters, settings),
134
+ core,
135
+ isStateful,
136
+ )
137
+ }
138
+
139
+ return new Plan(
140
+ uuidV4(),
141
+ ChangeSet.destroy(filteredCurrentParameters, settings),
142
+ core,
143
+ isStateful,
144
+ )
145
+ }
146
+
147
+ // NO-OP, MODIFY or RE-CREATE
148
+ const changeSet = ChangeSet.calculateModification(
149
+ desired!,
150
+ filteredCurrentParameters!,
151
+ settings.parameterSettings,
152
+ );
153
+
154
+ return new Plan(
155
+ uuidV4(),
156
+ changeSet,
157
+ core,
158
+ isStateful,
159
+ );
160
+ }
161
+
162
+ // 2. Even if there was (maybe for testing reasons), the plan values should not be adjusted
163
+ static fromResponse<T extends ResourceConfig>(data: ApplyRequestData['plan'], defaultValues?: Partial<Record<keyof T, unknown>>): Plan<T> {
164
+ if (!data) {
165
+ throw new Error('Data is empty');
166
+ }
167
+
168
+ addDefaultValues();
169
+
170
+ return new Plan(
171
+ uuidV4(),
172
+ new ChangeSet<T>(
173
+ data.operation,
174
+ data.parameters.map((p) => ({
175
+ ...p,
176
+ isSensitive: p.isSensitive ?? false,
177
+ })),
178
+ ),
179
+ {
180
+ type: data.resourceType,
181
+ name: data.resourceName,
182
+ },
183
+ data.isStateful
184
+ );
185
+
186
+ function addDefaultValues(): void {
187
+ Object.entries(defaultValues ?? {})
188
+ .forEach(([key, defaultValue]) => {
189
+ const configValueExists = data!
190
+ .parameters
191
+ .some((p) => p.name === key);
192
+
193
+ // Only set default values if the value does not exist in the config
194
+ if (configValueExists) {
195
+ return;
196
+ }
197
+
198
+ switch (data!.operation) {
199
+ case ResourceOperation.CREATE: {
200
+ data!.parameters.push({
201
+ name: key,
202
+ operation: ParameterOperation.ADD,
203
+ previousValue: null,
204
+ newValue: defaultValue,
205
+ });
206
+ break;
207
+ }
208
+
209
+ case ResourceOperation.DESTROY: {
210
+ data!.parameters.push({
211
+ name: key,
212
+ operation: ParameterOperation.REMOVE,
213
+ previousValue: defaultValue,
214
+ newValue: null,
215
+ });
216
+ break;
217
+ }
218
+
219
+ case ResourceOperation.MODIFY:
220
+ case ResourceOperation.RECREATE:
221
+ case ResourceOperation.NOOP: {
222
+ data!.parameters.push({
223
+ name: key,
224
+ operation: ParameterOperation.NOOP,
225
+ previousValue: defaultValue,
226
+ newValue: defaultValue,
227
+ });
228
+ break;
229
+ }
230
+ }
231
+ });
232
+ }
233
+
234
+ }
235
+
236
+ /**
237
+ * The type (id) of the resource
238
+ *
239
+ * @return string
240
+ */
241
+ getResourceType(): string {
242
+ return this.coreParameters.type
243
+ }
244
+
245
+ /**
246
+ * When multiples of the same resource are allowed, this matching function will match a given config with one of the
247
+ * existing configs on the system. For example if there are multiple versions of Android Studios installed, we can use
248
+ * the application name and location to match it to our desired configs name and location.
249
+ *
250
+ * @param params
251
+ * @private
252
+ */
253
+ private static matchCurrentParameters<T extends StringIndexedObject>(params: {
254
+ desired: Partial<T> | null,
255
+ currentArray: Partial<T>[] | null,
256
+ state: Partial<T> | null,
257
+ settings: ParsedResourceSettings<T>,
258
+ isStateful: boolean,
259
+ }): Partial<T> | null {
260
+ const {
261
+ desired,
262
+ currentArray,
263
+ state,
264
+ settings,
265
+ isStateful
266
+ } = params;
267
+
268
+ if (!settings.allowMultiple) {
269
+ return currentArray?.[0] ?? null;
270
+ }
271
+
272
+ if (!currentArray) {
273
+ return null;
274
+ }
275
+
276
+ const { matcher: parameterMatcher, id } = settings;
277
+ const matcher = (desired: Partial<T>, currentArray: Partial<T>[]): Partial<T> | undefined => {
278
+ const matched = currentArray.filter((c) => parameterMatcher(desired, c))
279
+ if (matched.length > 1) {
280
+ console.log(`Resource: ${id} did not uniquely match resources when allow multiple is set to true`)
281
+ }
282
+
283
+ return matched[0];
284
+ }
285
+
286
+ if (isStateful) {
287
+ return state
288
+ ? matcher(state, currentArray) ?? null
289
+ : null
290
+ }
291
+
292
+ return matcher(desired!, currentArray) ?? null;
293
+ }
294
+
295
+ /**
296
+ * Only keep relevant params for the plan. We don't want to change settings that were not already
297
+ * defined.
298
+ *
299
+ * 1. In stateless mode, filter current by desired. We only want to know about settings that the user has specified
300
+ * 2. In stateful mode, filter current by state and desired. We only know about the settings the user has previously set
301
+ * or wants to set. If a parameter is not specified then it's not managed by Codify.
302
+ */
303
+ private static filterCurrentParams<T extends StringIndexedObject>(params: {
304
+ desired: Partial<T> | null,
305
+ current: Partial<T> | null,
306
+ state: Partial<T> | null,
307
+ settings: ResourceSettings<T>,
308
+ isStateful: boolean,
309
+ }): Partial<T> | null {
310
+ const {
311
+ desired,
312
+ current,
313
+ state,
314
+ settings,
315
+ isStateful
316
+ } = params;
317
+
318
+ if (!current) {
319
+ return null;
320
+ }
321
+
322
+ const filteredCurrent = filterCurrent()
323
+ if (!filteredCurrent) {
324
+ return null
325
+ }
326
+
327
+ // For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
328
+ // requires additional filtering for stateful parameter arrays and objects.
329
+ if (isStateful && desired) {
330
+ return filteredCurrent;
331
+ }
332
+
333
+ // We also want to filter parameters when in delete mode. We don't want to delete parameters that
334
+ // are not specified in the original config.
335
+ if (isStateful && !desired) {
336
+ const arrayStatefulParameters = Object.fromEntries(
337
+ Object.entries(filteredCurrent)
338
+ .filter(([k, v]) => isArrayParameterWithFiltering(k, v))
339
+ .map(([k, v]) => [k, filterArrayParameterForDeletes(k, v)])
340
+ )
341
+
342
+ return { ...filteredCurrent, ...arrayStatefulParameters }
343
+ }
344
+
345
+ // TODO: Add object handling here in addition to arrays in the future
346
+ const arrayStatefulParameters = Object.fromEntries(
347
+ Object.entries(filteredCurrent)
348
+ .filter(([k, v]) => isArrayParameterWithFiltering(k, v))
349
+ .map(([k, v]) => [k, filterArrayParameterForStatelessMode(k, v)])
350
+ )
351
+
352
+ return { ...filteredCurrent, ...arrayStatefulParameters }
353
+
354
+ function filterCurrent(): Partial<T> | null {
355
+ if (!current) {
356
+ return null;
357
+ }
358
+
359
+ if (isStateful) {
360
+ const keys = new Set([...Object.keys(state ?? {}), ...Object.keys(desired ?? {})]);
361
+ return Object.fromEntries(
362
+ Object.entries(current)
363
+ .filter(([k]) => keys.has(k))
364
+ ) as Partial<T>;
365
+ }
366
+
367
+ // Stateless mode
368
+ const keys = new Set(Object.keys(desired ?? {}));
369
+ return Object.fromEntries(
370
+ Object.entries(current)
371
+ .filter(([k]) => keys.has(k))
372
+ ) as Partial<T>;
373
+ }
374
+
375
+ function getFilterParameter(k: string): ((desired: any[], current: any[]) => any[]) | boolean | undefined {
376
+ if (settings.parameterSettings?.[k]?.type === 'stateful') {
377
+ const statefulSetting = settings.parameterSettings[k] as ParsedStatefulParameterSetting;
378
+
379
+ if (statefulSetting.nestedSettings.type === 'array') {
380
+ return (statefulSetting.nestedSettings as ArrayParameterSetting).filterInStatelessMode
381
+ }
382
+ }
383
+
384
+ if (settings.parameterSettings?.[k]?.type === 'array') {
385
+ return (settings.parameterSettings?.[k] as ArrayParameterSetting).filterInStatelessMode;
386
+ }
387
+
388
+ return undefined;
389
+ }
390
+
391
+ function isArrayParameterWithFiltering(k: string, v: T[keyof T]): boolean {
392
+ const filterParameter = getFilterParameter(k);
393
+
394
+ if (settings.parameterSettings?.[k]?.type === 'stateful') {
395
+ const statefulSetting = settings.parameterSettings[k] as ParsedStatefulParameterSetting;
396
+ return statefulSetting.nestedSettings.type === 'array' &&
397
+ (filterParameter ?? true)
398
+ && Array.isArray(v);
399
+ }
400
+
401
+ return settings.parameterSettings?.[k]?.type === 'array'
402
+ && (filterParameter ?? true)
403
+ && Array.isArray(v);
404
+ }
405
+
406
+ // For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
407
+ function filterArrayParameterForStatelessMode(k: string, v: unknown[]): unknown[] {
408
+ const desiredArray = desired![k] as unknown[];
409
+ const matcher = settings.parameterSettings![k]!.type === 'stateful'
410
+ ? ((settings.parameterSettings![k] as ParsedStatefulParameterSetting)
411
+ .nestedSettings as ParsedArrayParameterSetting)
412
+ .isElementEqual
413
+ : (settings.parameterSettings![k] as ParsedArrayParameterSetting)
414
+ .isElementEqual
415
+
416
+ const desiredCopy = [...desiredArray];
417
+ const currentCopy = [...v];
418
+
419
+ const defaultFilterMethod = ((desired: any[], current: any[]) => {
420
+ const result = [];
421
+
422
+ for (let counter = desired.length - 1; counter >= 0; counter--) {
423
+ const idx = currentCopy.findIndex((e2) => matcher(desired[counter], e2))
424
+
425
+ if (idx === -1) {
426
+ continue;
427
+ }
428
+
429
+ desired.splice(counter, 1)
430
+ const [element] = current.splice(idx, 1)
431
+ result.push(element)
432
+ }
433
+
434
+ return result;
435
+ })
436
+
437
+ const filterParameter = getFilterParameter(k);
438
+ return typeof filterParameter === 'function'
439
+ ? filterParameter(desiredCopy, currentCopy)
440
+ : defaultFilterMethod(desiredCopy, currentCopy);
441
+ }
442
+
443
+ function filterArrayParameterForDeletes(k: string, v: unknown[]): unknown[] {
444
+ const stateArray = state![k] as unknown[];
445
+ const matcher = settings.parameterSettings![k]!.type === 'stateful'
446
+ ? ((settings.parameterSettings![k] as ParsedStatefulParameterSetting)
447
+ .nestedSettings as ParsedArrayParameterSetting)
448
+ .isElementEqual
449
+ : (settings.parameterSettings![k] as ParsedArrayParameterSetting)
450
+ .isElementEqual
451
+
452
+ const stateCopy = [...stateArray];
453
+ const currentCopy = [...v];
454
+
455
+ const defaultFilterMethod = ((state: any[], current: any[]) => {
456
+ const result = [];
457
+
458
+ for (let counter = state.length - 1; counter >= 0; counter--) {
459
+ const idx = currentCopy.findIndex((e2) => matcher(state[counter], e2))
460
+
461
+ if (idx === -1) {
462
+ continue;
463
+ }
464
+
465
+ state.splice(counter, 1)
466
+ const [element] = current.splice(idx, 1)
467
+ result.push(element)
468
+ }
469
+
470
+ return result;
471
+ })
472
+
473
+
474
+ const filterParameter = getFilterParameter(k);
475
+ return typeof filterParameter === 'function'
476
+ ? filterParameter(stateCopy, currentCopy)
477
+ : defaultFilterMethod(stateCopy, currentCopy);
478
+ }
479
+ }
480
+
481
+ // TODO: This needs to be revisited. I don't think this is valid anymore.
482
+ // 1. For all scenarios, there shouldn't be an apply without a plan beforehand
483
+
484
+ requiresChanges(): boolean {
485
+ return this.changeSet.operation !== ResourceOperation.NOOP;
486
+ }
487
+
488
+ /** Convert the plan to a JSON response object */
489
+ toResponse(): PlanResponseData {
490
+ return {
491
+ planId: this.id,
492
+ operation: this.changeSet.operation,
493
+ isStateful: this.isStateful,
494
+ resourceName: this.coreParameters.name,
495
+ resourceType: this.coreParameters.type,
496
+ parameters: this.changeSet.parameterChanges,
497
+ }
498
+ }
499
+ }