diff --git a/package.json b/package.json index d7a6477..caa0206 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@codifycli/plugin-core", - "version": "1.2.0", + "version": "1.2.1", "description": "TypeScript library for building Codify plugins to manage system resources (applications, CLI tools, settings) through infrastructure-as-code", "main": "dist/index.js", "typings": "dist/index.d.ts", diff --git a/src/plan/change-set.test.ts b/src/plan/change-set.test.ts index 5e386ca..f5a4f5d 100644 --- a/src/plan/change-set.test.ts +++ b/src/plan/change-set.test.ts @@ -304,6 +304,33 @@ describe('Change set tests', () => { expect(cs.operation).to.eq(ResourceOperation.DESTROY); }) + it('treats empty objects {} as no-op', () => { + const desired = { + keyboard: {}, + dock: {}, + } + + const current = { + keyboard: {}, + dock: {}, + } + + const cs = ChangeSet.calculateModification(desired, current); + expect(cs.parameterChanges.length).to.eq(0); + expect(cs.operation).to.eq(ResourceOperation.NOOP); + }) + + it('treats empty object {} as absent when current has no value', () => { + const desired = { + keyboard: {}, + dock: {}, + } + + const cs = ChangeSet.calculateModification(desired, {}); + expect(cs.parameterChanges.length).to.eq(0); + expect(cs.operation).to.eq(ResourceOperation.NOOP); + }) + it('correctly determines array equality 5', () => { const arrA = [{ key1: 'b' }, { key1: 'a' }, { key1: 'a' }]; const arrB = [{ key1: 'a' }, { key1: 'a' }, { key1: 'b' }]; diff --git a/src/plan/change-set.ts b/src/plan/change-set.ts index aa7b979..98f1619 100644 --- a/src/plan/change-set.ts +++ b/src/plan/change-set.ts @@ -154,13 +154,13 @@ export class ChangeSet { ): ParameterChange[] { const parameterChangeSet = new Array>(); - // Filter out null and undefined values or else the diff below will not work + // Filter out null, undefined, [], and {} — all treated as "no value" const desired = Object.fromEntries( - Object.entries(desiredParameters).filter(([, v]) => v !== null && v !== undefined) + Object.entries(desiredParameters).filter(([, v]) => !ChangeSet.isAbsent(v)) ) as Partial const current = Object.fromEntries( - Object.entries(currentParameters).filter(([, v]) => v !== null && v !== undefined) + Object.entries(currentParameters).filter(([, v]) => !ChangeSet.isAbsent(v)) ) as Partial for (const k of new Set([...Object.keys(current), ...Object.keys(desired)])) { @@ -227,6 +227,13 @@ export class ChangeSet { return orderOfOperations[Math.max(indexPrev, indexNext)]; } + private static isAbsent(v: unknown): boolean { + if (v === null || v === undefined) return true; + if (Array.isArray(v)) return v.length === 0; + if (typeof v === 'object') return Object.keys(v as object).length === 0; + return false; + } + private static isSame( desired: unknown, current: unknown, diff --git a/src/utils/functions.ts b/src/utils/functions.ts index 16011b0..e9eb685 100644 --- a/src/utils/functions.ts +++ b/src/utils/functions.ts @@ -43,7 +43,7 @@ export function resolvePathWithVariables(pathWithVariables: string) { export function addVariablesToPath(pathWithoutVariables: string) { let result = pathWithoutVariables; for (const [key, value] of Object.entries(process.env)) { - if (!value || !path.isAbsolute(value) || value === '/' || key === 'HOME' || key === 'PATH' || key === 'SHELL' || key === 'PWD') { + if (!value || !path.isAbsolute(value) || value === '/' || value === homeDirectory || key === 'HOME' || key === 'PATH' || key === 'SHELL' || key === 'PWD') { continue; }