From 086c36b5aceb1f8fd75de1e1e80ca76c78cbac2c Mon Sep 17 00:00:00 2001 From: Nathan Gobinet Date: Tue, 30 Jul 2024 14:18:06 +0200 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=90=9B=20Fix=20JsonPatch=20Formatter:?= =?UTF-8?q?=20Properly=20escape=20property=20name?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jsondiffpatch/src/formatters/jsonpatch.ts | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/jsondiffpatch/src/formatters/jsonpatch.ts b/packages/jsondiffpatch/src/formatters/jsonpatch.ts index e156cd42..ec710f3c 100644 --- a/packages/jsondiffpatch/src/formatters/jsonpatch.ts +++ b/packages/jsondiffpatch/src/formatters/jsonpatch.ts @@ -53,6 +53,8 @@ interface JSONFormatterContext extends BaseFormatterContext { pushMoveOp: (to: number) => void; currentPath: () => string; toPath: (to: number) => string; + buildPath: (path: (string | number)[]) => string; + escapePath: (path: string | number) => string; } class JSONFormatter extends BaseFormatter { @@ -89,14 +91,24 @@ class JSONFormatter extends BaseFormatter { }; context.currentPath = function () { - return `/${this.path!.join('/')}`; + return `/${this.buildPath!(this.path!)}`; }; context.toPath = function (toPath) { const to = this.path!.slice(); to[to.length - 1] = toPath; - return `/${to.join('/')}`; + return `/${this.buildPath!(to)}`; }; + + context.buildPath = function (path: (string | number)[]) { + return path.map((path) => this.escapePath!(path)).join('/') + } + + context.escapePath = function (path: string | number) { + if (typeof path !== 'string') return path.toString(); + if (path.indexOf('/') === -1 && path.indexOf('~') === -1) return path; + return path.replace(/~/g, '~0').replace(/\//g, '~1'); + } } typeFormattterErrorFormatter(context: JSONFormatterContext, err: unknown) { From f15ec8ecec175677c5bab3e5ac3de6de0280f5ec Mon Sep 17 00:00:00 2001 From: Nathan Gobinet Date: Tue, 30 Jul 2024 14:21:09 +0200 Subject: [PATCH 2/3] Fix semi --- packages/jsondiffpatch/src/formatters/jsonpatch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/jsondiffpatch/src/formatters/jsonpatch.ts b/packages/jsondiffpatch/src/formatters/jsonpatch.ts index ec710f3c..fad6be0f 100644 --- a/packages/jsondiffpatch/src/formatters/jsonpatch.ts +++ b/packages/jsondiffpatch/src/formatters/jsonpatch.ts @@ -101,7 +101,7 @@ class JSONFormatter extends BaseFormatter { }; context.buildPath = function (path: (string | number)[]) { - return path.map((path) => this.escapePath!(path)).join('/') + return path.map((path) => this.escapePath!(path)).join('/'); } context.escapePath = function (path: string | number) { From 4752181cc3f4456b4b8792469fb89ea9b7b52a09 Mon Sep 17 00:00:00 2001 From: Nathan Gobinet Date: Tue, 30 Jul 2024 14:31:15 +0200 Subject: [PATCH 3/3] Add test and prettier --- packages/jsondiffpatch/src/formatters/jsonpatch.ts | 6 +++--- packages/jsondiffpatch/test/index.spec.ts | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/jsondiffpatch/src/formatters/jsonpatch.ts b/packages/jsondiffpatch/src/formatters/jsonpatch.ts index fad6be0f..9f1cf014 100644 --- a/packages/jsondiffpatch/src/formatters/jsonpatch.ts +++ b/packages/jsondiffpatch/src/formatters/jsonpatch.ts @@ -102,13 +102,13 @@ class JSONFormatter extends BaseFormatter { context.buildPath = function (path: (string | number)[]) { return path.map((path) => this.escapePath!(path)).join('/'); - } - + }; + context.escapePath = function (path: string | number) { if (typeof path !== 'string') return path.toString(); if (path.indexOf('/') === -1 && path.indexOf('~') === -1) return path; return path.replace(/~/g, '~0').replace(/\//g, '~1'); - } + }; } typeFormattterErrorFormatter(context: JSONFormatterContext, err: unknown) { diff --git a/packages/jsondiffpatch/test/index.spec.ts b/packages/jsondiffpatch/test/index.spec.ts index 8f10f972..48a704ba 100644 --- a/packages/jsondiffpatch/test/index.spec.ts +++ b/packages/jsondiffpatch/test/index.spec.ts @@ -606,6 +606,12 @@ describe('DiffPatcher', () => { }); expectFormat(before, after, diff); }); + + it('should escape the property name', () => { + expectFormat({ 'tree/item': 1 }, { 'tree/item': 2 }, [ + replaceOp('/tree~1item', 2), + ]); + }); }); describe('html', () => {