Skip to content

Commit 727baca

Browse files
committed
feat: Added filtering for array parameters in deletes
1 parent a7c637e commit 727baca

File tree

5 files changed

+103
-8
lines changed

5 files changed

+103
-8
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "codify-plugin-lib",
3-
"version": "1.0.182-beta66",
3+
"version": "1.0.182-beta77",
44
"description": "Library plugin library",
55
"main": "dist/index.js",
66
"typings": "dist/index.d.ts",

src/plan/plan.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,52 @@ describe('Plan entity tests', () => {
180180
expect(plan.changeSet.operation).to.eq(ResourceOperation.NOOP);
181181
})
182182

183+
it('Filters array parameters in delete mode (when desired is null)', async () => {
184+
const resource = new class extends TestResource {
185+
getSettings(): ResourceSettings<any> {
186+
return {
187+
id: 'type',
188+
operatingSystems: [OS.Darwin],
189+
parameterSettings: {
190+
propZ: { type: 'array', isElementEqual: (a, b) => b.includes(a) }
191+
}
192+
}
193+
}
194+
195+
async refresh(): Promise<Partial<any> | null> {
196+
return {
197+
propZ: [
198+
'20.15.0',
199+
'20.15.1'
200+
]
201+
}
202+
}
203+
}
204+
205+
const controller = new ResourceController(resource);
206+
const plan = await controller.plan(
207+
{ type: 'type' },
208+
null,
209+
{ propZ: ['20.15.0'], } as any,
210+
true
211+
)
212+
213+
console.log(JSON.stringify(plan, null, 2));
214+
expect(plan).toMatchObject({
215+
id: expect.any(String),
216+
changeSet: expect.objectContaining({
217+
operation: ResourceOperation.DESTROY,
218+
parameterChanges: [
219+
expect.objectContaining({ operation: 'remove', name: 'propZ', previousValue: ['20.15.0'], newValue: null }),
220+
],
221+
}),
222+
coreParameters: expect.objectContaining({
223+
type: 'type',
224+
}),
225+
isStateful: true,
226+
})
227+
})
228+
183229
it('Doesn\'t filters array parameters if filtering is disabled', async () => {
184230
const resource = new class extends TestResource {
185231
getSettings(): ResourceSettings<any> {

src/plan/plan.ts

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,15 +326,27 @@ export class Plan<T extends StringIndexedObject> {
326326

327327
// For stateful mode, we're done after filtering by the keys of desired + state. Stateless mode
328328
// requires additional filtering for stateful parameter arrays and objects.
329-
if (isStateful) {
329+
if (isStateful && desired) {
330330
return filteredCurrent;
331331
}
332332

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+
333345
// TODO: Add object handling here in addition to arrays in the future
334346
const arrayStatefulParameters = Object.fromEntries(
335347
Object.entries(filteredCurrent)
336348
.filter(([k, v]) => isArrayParameterWithFiltering(k, v))
337-
.map(([k, v]) => [k, filterArrayStatefulParameter(k, v)])
349+
.map(([k, v]) => [k, filterArrayParameterForStatelessMode(k, v)])
338350
)
339351

340352
return { ...filteredCurrent, ...arrayStatefulParameters }
@@ -378,7 +390,7 @@ export class Plan<T extends StringIndexedObject> {
378390

379391
function isArrayParameterWithFiltering(k: string, v: T[keyof T]): boolean {
380392
const filterParameter = getFilterParameter(k);
381-
393+
382394
if (settings.parameterSettings?.[k]?.type === 'stateful') {
383395
const statefulSetting = settings.parameterSettings[k] as ParsedStatefulParameterSetting;
384396
return statefulSetting.nestedSettings.type === 'array' &&
@@ -392,7 +404,7 @@ export class Plan<T extends StringIndexedObject> {
392404
}
393405

394406
// For stateless mode, we must filter the current array so that the diff algorithm will not detect any deletes
395-
function filterArrayStatefulParameter(k: string, v: unknown[]): unknown[] {
407+
function filterArrayParameterForStatelessMode(k: string, v: unknown[]): unknown[] {
396408
const desiredArray = desired![k] as unknown[];
397409
const matcher = settings.parameterSettings![k]!.type === 'stateful'
398410
? ((settings.parameterSettings![k] as ParsedStatefulParameterSetting)
@@ -427,6 +439,43 @@ export class Plan<T extends StringIndexedObject> {
427439
? filterParameter(desiredCopy, currentCopy)
428440
: defaultFilterMethod(desiredCopy, currentCopy);
429441
}
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+
}
430479
}
431480

432481
// TODO: This needs to be revisited. I don't think this is valid anymore.

src/pty/sequential-pty.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ describe('SequentialPty tests', () => {
6666
});
6767

6868

69-
it('It can launch a command in interactive mode', async () => {
69+
it('It can launch a command in interactive mode', { timeout: 30_000 }, async () => {
7070
const originalSend = process.send;
7171
process.send = (req: IpcMessageV2) => {
7272
expect(req).toMatchObject({

0 commit comments

Comments
 (0)