diff --git a/packages/jsondiffpatch/src/formatters/jsonpatch.ts b/packages/jsondiffpatch/src/formatters/jsonpatch.ts index e156cd4..9f1cf01 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,13 +91,23 @@ 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'); }; } diff --git a/packages/jsondiffpatch/test/index.spec.ts b/packages/jsondiffpatch/test/index.spec.ts index 8f10f97..48a704b 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', () => {