Skip to content
This repository was archived by the owner on Jan 1, 2023. It is now read-only.

Commit d2aa2f1

Browse files
committed
🐛 fix key includes backslash and negative value
1 parent 729ae64 commit d2aa2f1

File tree

13 files changed

+1135
-25
lines changed

13 files changed

+1135
-25
lines changed

src/utils.ts

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
isObjectExpression,
55
isNullLiteral,
66
isNumericLiteral,
7+
isUnaryExpression,
78
isStringLiteral,
89
ObjectExpression,
910
ObjectProperty,
@@ -60,30 +61,43 @@ const isConvertibleObjectProperty = (properties: ObjectProperty[]) => {
6061
return properties.every(node => !node.computed)
6162
}
6263

63-
export function converter(node: object | null | undefined): unknown {
64-
if (!isValidJsonValue(node)) {
65-
throw new Error('Invalid value is included.')
64+
const createSafeStringForJsonParse = (value: string) => {
65+
if (/\\/.test(value)) {
66+
value = value.replace(/\\/g, '\\\\')
6667
}
6768

68-
if (isStringLiteral(node)) {
69-
let { value } = node
70-
if (/\\/.test(value)) {
71-
value = value.replace(/\\/g, '\\\\')
72-
}
69+
if (/"/.test(value)) {
70+
value = value.replace(/"/g, '\\"')
71+
}
7372

74-
if (/"/.test(value)) {
75-
value = value.replace(/"/g, '\\"')
73+
if (/[\t\f\r\n\b]/g.test(value)) {
74+
const codes = ['\f', '\r', '\n', '\t', '\b']
75+
const replaceCodes = ['\\f', '\\r', '\\n', '\\t', '\\b']
76+
for (let i = 0; i < codes.length; i++) {
77+
value = value.replace(new RegExp(codes[i]), replaceCodes[i])
7678
}
79+
}
7780

78-
if (/[\t\f\r\n\b]/g.test(value)) {
79-
const codes = ['\f', '\r', '\n', '\t', '\b']
80-
const replaceCodes = ['\\f', '\\r', '\\n', '\\t', '\\b']
81-
for (let i = 0; i < codes.length; i++) {
82-
value = value.replace(new RegExp(codes[i]), replaceCodes[i])
83-
}
81+
return value
82+
}
83+
84+
export function converter(node: object | null | undefined): unknown {
85+
// for negative number, ex) -10
86+
if (isUnaryExpression(node)) {
87+
const { operator, argument } = node
88+
if (operator === '-' && isNumericLiteral(argument)) {
89+
return -argument.value
8490
}
91+
}
8592

86-
return value
93+
if (!isValidJsonValue(node)) {
94+
throw new Error('Invalid value is included.')
95+
}
96+
97+
if (isStringLiteral(node)) {
98+
const { value } = node
99+
const safeValue = createSafeStringForJsonParse(value)
100+
return safeValue
87101
}
88102

89103
if (isNullLiteral(node)) {
@@ -106,7 +120,10 @@ export function converter(node: object | null | undefined): unknown {
106120
}
107121

108122
return properties.reduce((acc, cur) => {
109-
const key = cur.key.name || cur.key.value
123+
let key = cur.key.name || cur.key.value
124+
if (typeof key === 'string') {
125+
key = createSafeStringForJsonParse(key)
126+
}
110127
// see issues#10
111128
if (typeof key === 'number' && !Number.isSafeInteger(key)) {
112129
throw new Error('Invalid syntax is included.')

test/__fixtures__/object/backslash/input.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ const test12 = { foo: 'fo\\o' }
1313
const test13 = { foo: 'fo\\\o' }
1414
const test14 = { foo: 'fo\\\\o' }
1515
const test15 = { foo: '\\\\' }
16+
const test16 = { "fo\'o": "foo" }
17+
const test17 = { "fo\"o": "foo" }
18+
const test18 = { 'fo\"o': "foo" }
19+
const test19 = { 'fo\'o': "foo" }
20+
const test20 = { 'fo\no': "foo" }
21+
const test21 = { 'fo\r\no': "foo" }
22+
const test22 = { 'fo\\o': "foo" }
23+
const test23 = { 'fo\\\o': "foo" }
24+
const test24 = { 'fo\\\\o': "foo" }
1625
const res = [
1726
test1,
1827
test2,
@@ -28,5 +37,14 @@ const res = [
2837
test12,
2938
test13,
3039
test14,
31-
test15
40+
test15,
41+
test16,
42+
test17,
43+
test18,
44+
test19,
45+
test20,
46+
test21,
47+
test22,
48+
test23,
49+
test24
3250
]

test/__fixtures__/object/backslash/output.js

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,15 @@ const test12 = JSON.parse('{"foo":"fo\\\\o"}')
1313
const test13 = JSON.parse('{"foo":"fo\\\\o"}')
1414
const test14 = JSON.parse('{"foo":"fo\\\\\\\\o"}')
1515
const test15 = JSON.parse('{"foo":"\\\\\\\\"}')
16+
const test16 = JSON.parse('{"fo\'o":"foo"}')
17+
const test17 = JSON.parse('{"fo\\"o":"foo"}')
18+
const test18 = JSON.parse('{"fo\\"o":"foo"}')
19+
const test19 = JSON.parse('{"fo\'o":"foo"}')
20+
const test20 = JSON.parse('{"fo\\no":"foo"}')
21+
const test21 = JSON.parse('{"fo\\r\\no":"foo"}')
22+
const test22 = JSON.parse('{"fo\\\\o":"foo"}')
23+
const test23 = JSON.parse('{"fo\\\\o":"foo"}')
24+
const test24 = JSON.parse('{"fo\\\\\\\\o":"foo"}')
1625
const res = [
1726
test1,
1827
test2,
@@ -28,5 +37,14 @@ const res = [
2837
test12,
2938
test13,
3039
test14,
31-
test15
40+
test15,
41+
test16,
42+
test17,
43+
test18,
44+
test19,
45+
test20,
46+
test21,
47+
test22,
48+
test23,
49+
test24
3250
]

0 commit comments

Comments
 (0)