Skip to content

Commit 5248868

Browse files
authored
fix: $ref value encoding and decoding (#1322)
* add failing tests * use querystring escaping for $ref value parsing * use querystring-browser for consistent cross-platform escaping * re-sort dependencies
1 parent a635e37 commit 5248868

File tree

3 files changed

+68
-3
lines changed

3 files changed

+68
-3
lines changed

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@
6767
"xmock": "^0.3.0"
6868
},
6969
"dependencies": {
70+
"@kyleshockey/object-assign-deep": "^0.4.0",
7071
"babel-runtime": "^6.23.0",
7172
"btoa": "1.1.2",
7273
"cookie": "^0.3.1",
@@ -77,8 +78,8 @@
7778
"isomorphic-form-data": "0.0.1",
7879
"js-yaml": "^3.8.1",
7980
"lodash": "^4.16.2",
80-
"@kyleshockey/object-assign-deep": "^0.4.0",
8181
"qs": "^6.3.0",
82+
"querystring-browser": "^1.0.4",
8283
"url": "^0.11.0",
8384
"utf8-bytes": "0.0.1",
8485
"utfstring": "^2.0.0"

src/specmap/lib/refs.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {fetch} from 'cross-fetch'
2+
import qs from 'querystring-browser'
23
import url from 'url'
34
import lib from '../lib'
45
import createError from '../lib/create-error'
@@ -303,15 +304,15 @@ function unescapeJsonPointerToken(token) {
303304
if (typeof token !== 'string') {
304305
return token
305306
}
306-
return token.replace(/~1/g, '/').replace(/~0/g, '~')
307+
return qs.unescape(token.replace(/~1/g, '/').replace(/~0/g, '~'))
307308
}
308309

309310
/**
310311
* Escapes a JSON pointer.
311312
* @api public
312313
*/
313314
function escapeJsonPointerToken(token) {
314-
return token.replace(/~/g, '~0').replace(/\//g, '~1')
315+
return qs.escape(token.replace(/~/g, '~0').replace(/\//g, '~1'))
315316
}
316317

317318
function arrayToJsonPointer(arr) {

test/resolver.js

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,69 @@ describe('resolver', () => {
4848
}
4949
})
5050

51+
it('should be able to resolve $refs with percent-encoded values', () => {
52+
// Given
53+
const spec = {
54+
one: {
55+
uno: 1,
56+
$ref: '#/value%20two'
57+
},
58+
'value two': {
59+
duos: 2
60+
}
61+
}
62+
63+
// When
64+
return Swagger.resolve({spec, allowMetaPatches: false})
65+
.then(handleResponse)
66+
67+
// Then
68+
function handleResponse(obj) {
69+
expect(obj.errors).toEqual([])
70+
expect(obj.spec).toEqual({
71+
one: {
72+
duos: 2
73+
},
74+
'value two': {
75+
duos: 2
76+
}
77+
})
78+
}
79+
})
80+
81+
it('should tolerate $refs with raw values that should be percent-encoded', () => {
82+
// NOTE: this is for compatibility and can be removed in the next major
83+
// REVIEW for v4
84+
85+
// Given
86+
const spec = {
87+
one: {
88+
uno: 1,
89+
$ref: '#/value two'
90+
},
91+
'value two': {
92+
duos: 2
93+
}
94+
}
95+
96+
// When
97+
return Swagger.resolve({spec, allowMetaPatches: false})
98+
.then(handleResponse)
99+
100+
// Then
101+
function handleResponse(obj) {
102+
expect(obj.errors).toEqual([])
103+
expect(obj.spec).toEqual({
104+
one: {
105+
duos: 2
106+
},
107+
'value two': {
108+
duos: 2
109+
}
110+
})
111+
}
112+
})
113+
51114
it('should be able to resolve circular $refs when a baseDoc is provided', () => {
52115
// Given
53116
const spec = {

0 commit comments

Comments
 (0)