-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.js
126 lines (108 loc) · 2.11 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const tokenTypes = [
{
regexp: /^\s+/,
create: (value, position) => ({
type: 'whitespace',
position,
raw: value,
value
})
},
{
regexp: /^"(?:[^"\\]|\\.)*"/,
create: (value, position) => ({
type: 'string',
position,
raw: value,
value: value
.slice(1, -1)
.replace(/\\"/g, '"')
})
},
{
regexp: /^(true|false|null)/,
create: (value, position) => ({
type: 'literal',
position,
raw: value,
value: value === 'null'
? null
: value === 'true'
})
},
{
regexp: /^(-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?)/,
create: (value, position) => ({
type: 'number',
position,
raw: value,
value: +value
})
},
{
regexp: /^({|}|\[|]|:|,)/,
create: (value, position) => ({
type: 'punctuation',
position,
raw: value,
value
})
}
]
const tokenize = (
json,
tokens = [],
position = { lineno: 1, column: 1 }
) => {
let char = json[0]
if (!char) {
return tokens
}
const [createToken, str] = tokenTypes.reduce((acc, type) => {
if (acc) return acc
const str = match(type.regexp)
if (!str) return acc
return [
type.create,
str
]
}, null)
const token = createToken(
str,
str.length === 1
? position
: { start: position, end: updateColumn(str.length - 1) }
)
const lines = str.match(/^\n+/g)
if (lines) {
return tokenize(
advance(lines),
tokens,
{ lineno: position.lineno + lines.length, column: 1 }
)
}
return next(token)
function updateColumn (column) {
return {
lineno: position.lineno,
column: position.column + column
}
}
function next (token, nextPosition) {
return tokenize(
advance(token.raw),
tokens.concat([token]),
nextPosition || updateColumn(token.raw.length)
)
}
function match (re) {
const m = re.exec(json)
if (!m) return
const str = m[0]
return str
}
function advance (str) {
return json.slice(str.length)
}
}
module.exports = tokenize