Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .changeset/upgrade-jsondiffpatch.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@commercetools/sync-actions': minor
---

Upgrade the `jsondiffpatch` dependency from `0.5.0` to `^0.7.6`, moving off an unmaintained release onto the current maintained version.

A customer security report referenced `jsonpath-plus` (which is not, and never was, a dependency of this package). The reported version facts — pinned `0.5.0`, fixed in `0.7.6`, not backwards compatible — instead correspond to `jsondiffpatch`, a direct dependency used by the diff/patch utility behind update-action generation. This change adopts `jsondiffpatch@0.7.6`.

The public API and observable behavior of `@commercetools/sync-actions` are unchanged. Internally: `jsondiffpatch` 0.7 is ESM-only, so imports were updated to the package root and the dependency is bundled into the published CommonJS, ESM, and UMD artifacts (CommonJS consumers are unaffected). Fine-grained text diffing remains disabled, so a changed string is still reported as a whole-value replacement.
2 changes: 2 additions & 0 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ module.exports = {
'^.+\\.js$': 'babel-jest',
'^.+\\.ts?$': 'ts-jest',
},
// Transpile the ESM-only jsondiffpatch package (Jest skips node_modules by default).
transformIgnorePatterns: ['/node_modules/(?!(jsondiffpatch)/)'],
testRegex: '\\.(test|spec)\\.[t]s?$',
moduleFileExtensions: ['ts', 'js', 'json'],
coverageDirectory: 'coverage',
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"tmp": "^0.2.3",
"ts-jest": "^29.3.2",
"ts-node": "^10.9.2",
"typescript": "^4.6.2",
"typescript": "^5.8.2",
"typescript-eslint": "^8.32.1"
},
"workspaces": ["packages/*"],
Expand Down
5 changes: 4 additions & 1 deletion packages/sync-actions/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,12 @@ module.exports = {
testTimeout: 15000,
testEnvironment: 'node',
transform: {
'^.+\\.js$': 'babel-jest',
// rootMode 'upward' finds the repo-root babel.config.js from this package dir
'^.+\\.js$': ['babel-jest', { rootMode: 'upward' }],
'^.+\\.ts?$': 'ts-jest',
},
// transpile ESM-only jsondiffpatch (jest ignores node_modules by default)
transformIgnorePatterns: ['/node_modules/(?!(jsondiffpatch)/)'],
testRegex: '\\.(test|spec)\\.[t]s?$',
moduleFileExtensions: ['ts', 'js', 'json'],
coverageDirectory: 'coverage',
Expand Down
2 changes: 1 addition & 1 deletion packages/sync-actions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
"esbuild": "^0.25.4",
"fast-equals": "^2.0.0",
"jest": "^29.7.0",
"jsondiffpatch": "0.5.0",
"jsondiffpatch": "^0.7.6",
"lodash.foreach": "^4.5.0",
"lodash.intersection": "^4.4.0",
"lodash.isequal": "^4.5.0",
Expand Down
16 changes: 3 additions & 13 deletions packages/sync-actions/src/utils/diffpatcher.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DiffPatcher } from 'jsondiffpatch/dist/jsondiffpatch.cjs';
import { DiffPatcher } from 'jsondiffpatch';
import { Delta } from './types';

type U = { id: string; name: string; url: string };
Expand All @@ -22,24 +22,14 @@ const diffpatcher = new DiffPatcher({
// value of items moved is not included in deltas
includeValueOnMove: false,
},
textDiff: {
/**
* jsondiffpatch uses a very fine-grained diffing algorithm for long strings to easily identify
* what changed between strings. However, we don't actually care about what changed, just
* if the string changed at all. So we set the minimum length to diff to a very large number to avoid
* using the very slow algorithm.
* See https://github.com/benjamine/jsondiffpatch/blob/master/docs/deltas.md#text-diffs.
*/
minLength: Number.MAX_SAFE_INTEGER,
},
});

export function diff<T>(oldObj: T, newObj: T): Delta {
return diffpatcher.diff(oldObj, newObj);
}

export function patch<T>(obj: T, delta: Delta) {
return diffpatcher.patch(obj, delta);
export function patch<T>(obj: T, delta: Delta): T {
return diffpatcher.patch(obj, delta) as T;
}

export function getDeltaValue<T extends object = object>(
Expand Down
5 changes: 2 additions & 3 deletions packages/sync-actions/src/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Delta as DiffDelta } from 'jsondiffpatch/dist/jsondiffpatch.cjs';

export * from '@commercetools/platform-sdk';
export type Delta = DiffDelta | undefined;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export type Delta = Record<string | number, any> | undefined;

export type SyncActionConfig = {
shouldOmitEmptyString?: boolean;
Expand Down
56 changes: 56 additions & 0 deletions packages/sync-actions/test/utils/diffpatcher.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { diff, getDeltaValue, objectHash } from '../../src/utils/diffpatcher';

describe('diffpatcher (jsondiffpatch 0.7)', () => {
describe('long-string diffing', () => {
test('a changed long string is a whole-value replacement, not a text diff', () => {
const long = 'x'.repeat(5000);
const delta = diff({ desc: long }, { desc: `${long}CHANGED` }) as Record<
string,
unknown[]
>;
const stringDelta = delta.desc;
expect(stringDelta).toHaveLength(2);
expect(stringDelta[0]).toBe(long);
expect(stringDelta[1]).toBe(`${long}CHANGED`);
});
});

describe('objectHash', () => {
test('prefers id, then name, then url, then falls back to index key', () => {
expect(objectHash({ id: 'a', name: 'n', url: 'u' }, 0)).toBe('a');
expect(objectHash({ name: 'n', url: 'u' } as never, 1)).toBe('n');
expect(objectHash({ url: 'u' } as never, 2)).toBe('u');
expect(objectHash(null as never, 3)).toBe('$$index:3');
});
});

describe('getDeltaValue', () => {
test('length 1 returns the added value', () => {
expect(getDeltaValue([{ a: 1 }])).toEqual({ a: 1 });
});

test('length 2 returns the updated value', () => {
expect(getDeltaValue([{ a: 1 }, { a: 2 }])).toEqual({ a: 2 });
});

test('length 3 ending in 0 is a delete and returns undefined', () => {
expect(getDeltaValue([{ a: 1 }, 0, 0])).toBeUndefined();
});

test('text diff (trailing 2) without an original object throws', () => {
expect(() => getDeltaValue(['@@ -1 +1 @@', 0, 2])).toThrow(
/Missing original object/
);
});

test('array move (trailing 3) throws because includeValueOnMove is false', () => {
expect(() => getDeltaValue(['', 1, 3])).toThrow(/array move/);
});

test('a non-array delta throws', () => {
expect(() => getDeltaValue('not-an-array')).toThrow(
/Expected array to extract delta value/
);
});
});
});
57 changes: 23 additions & 34 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@ __metadata:
esbuild: "npm:^0.25.4"
fast-equals: "npm:^2.0.0"
jest: "npm:^29.7.0"
jsondiffpatch: "npm:0.5.0"
jsondiffpatch: "npm:^0.7.6"
lodash.foreach: "npm:^4.5.0"
lodash.intersection: "npm:^4.4.0"
lodash.isequal: "npm:^4.5.0"
Expand Down Expand Up @@ -1873,6 +1873,13 @@ __metadata:
languageName: node
linkType: hard

"@dmsnell/diff-match-patch@npm:^1.1.0":
version: 1.1.0
resolution: "@dmsnell/diff-match-patch@npm:1.1.0"
checksum: 10c0/8547bf4a62dfca0a61b9c6490ea0ea468ec108879892f2e1ebe14dc12e9e6c50ad91b184a186ab5119f47baf631ab4f1f152372b8b89ba4d8d42a8ae5dcb6e44
languageName: node
linkType: hard

"@esbuild/aix-ppc64@npm:0.25.10":
version: 0.25.10
resolution: "@esbuild/aix-ppc64@npm:0.25.10"
Expand Down Expand Up @@ -3903,16 +3910,6 @@ __metadata:
languageName: node
linkType: hard

"chalk@npm:^3.0.0":
version: 3.0.0
resolution: "chalk@npm:3.0.0"
dependencies:
ansi-styles: "npm:^4.1.0"
supports-color: "npm:^7.1.0"
checksum: 10c0/ee650b0a065b3d7a6fda258e75d3a86fc8e4effa55871da730a9e42ccb035bf5fd203525e5a1ef45ec2582ecc4f65b47eb11357c526b84dd29a14fb162c414d2
languageName: node
linkType: hard

"chalk@npm:^4.0.0":
version: 4.1.2
resolution: "chalk@npm:4.1.2"
Expand Down Expand Up @@ -4415,13 +4412,6 @@ __metadata:
languageName: node
linkType: hard

"diff-match-patch@npm:^1.0.0":
version: 1.0.5
resolution: "diff-match-patch@npm:1.0.5"
checksum: 10c0/142b6fad627b9ef309d11bd935e82b84c814165a02500f046e2773f4ea894d10ed3017ac20454900d79d4a0322079f5b713cf0986aaf15fce0ec4a2479980c86
languageName: node
linkType: hard

"diff-sequences@npm:^29.6.3":
version: 29.6.3
resolution: "diff-sequences@npm:29.6.3"
Expand Down Expand Up @@ -6382,15 +6372,14 @@ __metadata:
languageName: node
linkType: hard

"jsondiffpatch@npm:0.5.0":
version: 0.5.0
resolution: "jsondiffpatch@npm:0.5.0"
"jsondiffpatch@npm:^0.7.6":
version: 0.7.6
resolution: "jsondiffpatch@npm:0.7.6"
dependencies:
chalk: "npm:^3.0.0"
diff-match-patch: "npm:^1.0.0"
"@dmsnell/diff-match-patch": "npm:^1.1.0"
bin:
jsondiffpatch: bin/jsondiffpatch
checksum: 10c0/272271b92b20ebd303c002b4ffad6bcbf52dadb667c338509296b3c25e954535e5aa86c3675df5ae1525edad9ea7f7191c8beb921f0ee87569a58b4810299d87
jsondiffpatch: bin/jsondiffpatch.js
checksum: 10c0/c82ea96bcce309fa6d399ad27d773bcfc8a99c817e78fbd6be5d8149e60f13016a777acca3aa93e073a8bb06eca905fda8f9ea3f846188b0914251a7b3d417a5
languageName: node
linkType: hard

Expand Down Expand Up @@ -9185,7 +9174,7 @@ __metadata:
tmp: "npm:^0.2.3"
ts-jest: "npm:^29.3.2"
ts-node: "npm:^10.9.2"
typescript: "npm:^4.6.2"
typescript: "npm:^5.8.2"
typescript-eslint: "npm:^8.32.1"
languageName: unknown
linkType: soft
Expand All @@ -9205,23 +9194,23 @@ __metadata:
languageName: node
linkType: hard

"typescript@npm:^4.6.2":
version: 4.9.5
resolution: "typescript@npm:4.9.5"
"typescript@npm:^5.8.2":
version: 5.9.3
resolution: "typescript@npm:5.9.3"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10c0/5f6cad2e728a8a063521328e612d7876e12f0d8a8390d3b3aaa452a6a65e24e9ac8ea22beb72a924fd96ea0a49ea63bb4e251fb922b12eedfb7f7a26475e5c56
checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5
languageName: node
linkType: hard

"typescript@patch:typescript@npm%3A^4.6.2#optional!builtin<compat/typescript>":
version: 4.9.5
resolution: "typescript@patch:typescript@npm%3A4.9.5#optional!builtin<compat/typescript>::version=4.9.5&hash=289587"
"typescript@patch:typescript@npm%3A^5.8.2#optional!builtin<compat/typescript>":
version: 5.9.3
resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin<compat/typescript>::version=5.9.3&hash=5786d5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10c0/e3333f887c6829dfe0ab6c1dbe0dd1e3e2aeb56c66460cb85c5440c566f900c833d370ca34eb47558c0c69e78ced4bfe09b8f4f98b6de7afed9b84b8d1dd06a1
checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430
languageName: node
linkType: hard

Expand Down
Loading