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

Commit 55cd784

Browse files
authored
Merge pull request #27 from nd-02110114/feature/convert-partial-json
Support string includes double quoto and array expression
2 parents d1916ab + b79412c commit 55cd784

File tree

12 files changed

+1334
-941
lines changed

12 files changed

+1334
-941
lines changed

.eslintrc.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@ module.exports = {
1111
// cwdからのpath
1212
project: "./tsconfig.json",
1313
},
14-
rules: {},
14+
rules: {
15+
"@typescript-eslint/ban-ts-ignore": "warn",
16+
},
1517
env: {
1618
node: true,
1719
},

example/input.js

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,30 @@ const data = { foo: 42, bar: 1337 }
33

44
/* valid */
55
const valid1 = { foo: 'foo' };
6-
const valid2 = { foo: "fo'o" }
7-
const valid3 = { foo: "fo\'o" }
6+
const valid2 = { foo: "foo" };
87

9-
const valid4 = { foo: 10 };
8+
const valid3 = { foo: "fo'o" };
9+
const valid4 = { foo: "fo\'o" };
10+
const valid5 = { foo: "fo\"o" };
1011

11-
const valid5 = { foo: true };
12+
const valid6 = { foo: 'fo"o' };
13+
const valid7 = { foo: 'fo\"o' };
14+
const valid8 = { foo: 'fo\'o' };
1215

13-
const valid6 = { foo: null };
16+
const valid9 = { foo: 10 };
1417

15-
const valid7 = { foo: [null, 10, 'foo'] };
18+
const valid10 = { foo: true };
1619

17-
const valid8 = { foo: [null, [10, 2], [{ foo: 'foo' }]] };
20+
const valid11 = { foo: null };
1821

19-
const valid9 = { foo: { bar: 1337 } };
20-
const valid10 = { 1: "123", 23: 45, b: "b_val" };
22+
const valid12 = { foo: [null, 10, 'foo'] };
23+
24+
const valid13 = { foo: [null, [10, 2], [{ foo: 'foo' }]] };
25+
26+
const valid14 = { foo: { bar: 1337 } };
27+
const valid15 = { 1: "123", 23: 45, b: "b_val" };
28+
29+
const valid16 = [1, "two", {three: 3}];
2130

2231

2332
/* invalidValue */
@@ -32,6 +41,3 @@ const inValid2 = {
3241

3342
const inValid3 = { ...data, foo: 'foo' };
3443
const inValid4 = { bar: data, foo: 'foo' };
35-
36-
const inValid5 = { foo: 'fo\"o' }
37-
const inValid6 = { foo: 'fo"o' }

example/output.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@ const data = JSON.parse('{"foo":42,"bar":1337}');
33
/* valid */
44

55
const valid1 = JSON.parse('{"foo":"foo"}');
6-
const valid2 = JSON.parse('{"foo":"fo\'o"}');
6+
const valid2 = JSON.parse('{"foo":"foo"}');
77
const valid3 = JSON.parse('{"foo":"fo\'o"}');
8-
const valid4 = JSON.parse('{"foo":10}');
9-
const valid5 = JSON.parse('{"foo":true}');
10-
const valid6 = JSON.parse('{"foo":null}');
11-
const valid7 = JSON.parse('{"foo":[null,10,"foo"]}');
12-
const valid8 = JSON.parse('{"foo":[null,[10,2],[{"foo":"foo"}]]}');
13-
const valid9 = JSON.parse('{"foo":{"bar":1337}}');
14-
const valid10 = JSON.parse('{"1":"123","23":45,"b":"b_val"}');
8+
const valid4 = JSON.parse('{"foo":"fo\'o"}');
9+
const valid5 = JSON.parse('{"foo":"fo\\\"o"}');
10+
const valid6 = JSON.parse('{"foo":"fo\\\"o"}');
11+
const valid7 = JSON.parse('{"foo":"fo\\\"o"}');
12+
const valid8 = JSON.parse('{"foo":"fo\'o"}');
13+
const valid9 = JSON.parse('{"foo":10}');
14+
const valid10 = JSON.parse('{"foo":true}');
15+
const valid11 = JSON.parse('{"foo":null}');
16+
const valid12 = JSON.parse('{"foo":[null,10,"foo"]}');
17+
const valid13 = JSON.parse('{"foo":[null,[10,2],[{"foo":"foo"}]]}');
18+
const valid14 = JSON.parse('{"foo":{"bar":1337}}');
19+
const valid15 = JSON.parse('{"1":"123","23":45,"b":"b_val"}');
20+
const valid16 = JSON.parse('[1,"two",{"three":3}]');
1521
/* invalidValue */
1622

1723
const inValid1 = {
@@ -31,9 +37,3 @@ const inValid4 = {
3137
bar: data,
3238
foo: 'foo'
3339
};
34-
const inValid5 = {
35-
foo: 'fo\"o'
36-
};
37-
const inValid6 = {
38-
foo: 'fo"o'
39-
};

package.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,31 @@
44
"main": "dist/index.js",
55
"scripts": {
66
"build": "rm -rf dist/** && tsc",
7-
"example": "babel ./example/input.js -o ./example/output.js",
7+
"example": "babel example/input.js -o example/output.js && node example/output.js",
88
"fmt": "prettier --write \"src/**/*.ts\"",
99
"lint": "eslint 'src/**/*.ts' --fix",
1010
"test": "jest"
1111
},
1212
"dependencies": {
13-
"@babel/core": "^7.4.5",
14-
"@babel/types": "^7.4.4"
13+
"@babel/core": "^7.7.7",
14+
"@babel/types": "^7.7.4"
1515
},
1616
"devDependencies": {
17-
"@babel/cli": "^7.4.4",
17+
"@babel/cli": "^7.7.7",
1818
"@types/babel-core": "^6.25.6",
1919
"@types/babel-types": "^7.0.7",
20-
"@types/jest": "^24.0.15",
21-
"@typescript-eslint/eslint-plugin": "^1.11.0",
22-
"@typescript-eslint/parser": "^1.11.0",
23-
"babel-plugin-tester": "^6.4.0",
24-
"eslint": "^6.0.1",
25-
"eslint-config-prettier": "^6.0.0",
26-
"husky": "^2.7.0",
27-
"jest": "^24.8.0",
28-
"lint-staged": "^8.2.1",
29-
"prettier": "^1.18.2",
30-
"ts-jest": "^24.0.2",
31-
"typescript": "^3.5.2"
20+
"@types/jest": "^24.0.25",
21+
"@typescript-eslint/eslint-plugin": "^2.14.0",
22+
"@typescript-eslint/parser": "^2.14.0",
23+
"babel-plugin-tester": "^8.0.1",
24+
"eslint": "^6.8.0",
25+
"eslint-config-prettier": "^6.9.0",
26+
"husky": "^3.1.0",
27+
"jest": "^24.9.0",
28+
"lint-staged": "^9.5.0",
29+
"prettier": "^1.19.1",
30+
"ts-jest": "^24.2.0",
31+
"typescript": "^3.7.4"
3232
},
3333
"jest": {
3434
"transform": {

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { buildPlugin } from './plugin'
22
import { ObjectExpression } from './visitors/object_expression'
3+
import { ArrayExpression } from './visitors/array_expression'
34

4-
export = buildPlugin([ObjectExpression])
5+
export = buildPlugin([ObjectExpression, ArrayExpression])

src/plugin.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
export function buildPlugin(visitors: Function[]) {
22
const visitorMap: { [name: string]: Function } = {}
33
for (const visitor of visitors) {
4-
// @ts-ignore
54
visitorMap[visitor.name] = visitor
65
}
76

src/utils.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ export function converter(node: object | null | undefined): unknown {
6868
if (isStringLiteral(node)) {
6969
const { value } = node
7070
if (/"/.test(value)) {
71-
throw new Error('Invalid value is included.')
71+
return value.replace(/"/g, '\\"')
7272
}
7373

7474
return value

src/visitors/array_expression.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { ArrayExpression } from '@babel/types'
2+
import { NodePath } from '@babel/traverse'
3+
import { converter } from '../utils'
4+
5+
interface PluginState {
6+
opts: {
7+
minJSONStringSize: number
8+
}
9+
}
10+
11+
const DEFAULT_THRESHOLD = 1024
12+
13+
/* eslint-disable no-redeclare */
14+
export function ArrayExpression(
15+
path: NodePath<ArrayExpression>,
16+
state: PluginState
17+
): void {
18+
try {
19+
const obj = converter(path.node)
20+
const json = JSON.stringify(obj)
21+
// escaping for single quotes
22+
const escapedJson = json.replace(/'/g, "\\'")
23+
// it simply isn't worth it to convert into the AST objects that are too small.
24+
// so, this plugin only convert large objects by default.
25+
const { minJSONStringSize } = state.opts
26+
const threshold = minJSONStringSize ?? DEFAULT_THRESHOLD
27+
if (escapedJson.length < threshold) {
28+
return
29+
}
30+
path.replaceWithSourceString(`JSON.parse('${escapedJson}')`)
31+
} catch (e) {
32+
// disable error message
33+
// const { loc } = path.parent
34+
// const line = loc && loc.start.line
35+
// console.error(
36+
// `At ${line} line (start) : The object wasn't converted (${e.message})`
37+
// )
38+
}
39+
}

src/visitors/object_expression.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ const DEFAULT_THRESHOLD = 1024
1414
export function ObjectExpression(
1515
path: NodePath<ObjectExpression>,
1616
state: PluginState
17-
) {
17+
): void {
1818
try {
1919
const obj = converter(path.node)
2020
const json = JSON.stringify(obj)
@@ -23,8 +23,7 @@ export function ObjectExpression(
2323
// it simply isn't worth it to convert into the AST objects that are too small.
2424
// so, this plugin only convert large objects by default.
2525
const { minJSONStringSize } = state.opts
26-
const threshold =
27-
minJSONStringSize !== undefined ? minJSONStringSize : DEFAULT_THRESHOLD
26+
const threshold = minJSONStringSize ?? DEFAULT_THRESHOLD
2827
if (escapedJson.length < threshold) {
2928
return
3029
}
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import pluginTester from 'babel-plugin-tester'
2+
import { buildPlugin } from '../../src/plugin'
3+
import { ArrayExpression } from '../../src/visitors/array_expression'
4+
5+
pluginTester({
6+
plugin: buildPlugin([ArrayExpression]),
7+
tests: [{
8+
title: 'Array',
9+
pluginOptions: {
10+
minJSONStringSize: 0
11+
},
12+
code: `const a = [1, "two", {three: 3}]`,
13+
output: `const a = JSON.parse('[1,"two",{"three":3}]')`
14+
}, {
15+
title: 'Array',
16+
pluginOptions: {
17+
minJSONStringSize: 0
18+
},
19+
code: `const a = [{one: 1}, {two: 2}, {three: 3}]`,
20+
output: `const a = JSON.parse('[{"one":1},{"two":2},{"three":3}]')`
21+
},]
22+
})

0 commit comments

Comments
 (0)