diff --git a/src/__tests__/decodePointer.ts b/src/__tests__/decodePointer.ts index 6a01823..c56c532 100644 --- a/src/__tests__/decodePointer.ts +++ b/src/__tests__/decodePointer.ts @@ -7,4 +7,7 @@ test('decodePointer', () => { expect(decodePointer('paths/~1users')).toEqual('paths//users'); expect(decodePointer('paths/foo~0users')).toEqual('paths/foo~users'); expect(decodePointer('#/foo')).toEqual('#/foo'); + expect(decodePointer('#/foo%20%5E%20bar')).toEqual('#/foo ^ bar'); + expect(decodePointer('#/users% ')).toEqual('#/users% '); + expect(decodePointer('#/users%%20%5E%')).toEqual('#/users% ^%'); }); diff --git a/src/__tests__/pointerToPath.ts b/src/__tests__/pointerToPath.ts index 41a004e..34631ee 100644 --- a/src/__tests__/pointerToPath.ts +++ b/src/__tests__/pointerToPath.ts @@ -8,4 +8,6 @@ test('pointerToPath', () => { expect(pointerToPath('#/paths/foo~0users')).toEqual(['paths', 'foo~users']); expect(pointerToPath('#')).toEqual([]); expect(pointerToPath('#/')).toEqual(['']); + expect(pointerToPath('#/foo%20%5E%20bar')).toEqual(['foo ^ bar']); + expect(pointerToPath('#/users% ')).toEqual(['users% ']); }); diff --git a/src/decodePointer.ts b/src/decodePointer.ts index b052a09..b23d163 100644 --- a/src/decodePointer.ts +++ b/src/decodePointer.ts @@ -1,10 +1,27 @@ import { replaceInString } from './_utils'; +function safeDecodeURIComponent(value: string): string { + try { + return decodeURIComponent(value); + } catch { + return value; + } +} + +const PERCENT_ENCODING_OCTET = /%[0-9a-f]+/gi; + /** * Removes special json pointer characters in a value. Example: * * decodePointer('#/paths/~1users) => '#/paths//users' */ export const decodePointer = (value: string): string => { - return replaceInString(replaceInString(decodeURIComponent('' + value), '~1', '/'), '~0', '~'); + let decoded; + try { + decoded = decodeURIComponent(value); + } catch { + decoded = value.replace(PERCENT_ENCODING_OCTET, safeDecodeURIComponent); + } + + return replaceInString(replaceInString(decoded, '~1', '/'), '~0', '~'); };