-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparseHeredoc.js
More file actions
72 lines (72 loc) · 1.8 KB
/
parseHeredoc.js
File metadata and controls
72 lines (72 loc) · 1.8 KB
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
export const parseHeredoc = (str, {
open = '[',
close = ']',
escape = '`',
heredoc = '~',
} = {}) => {
const parents = []
let parent = {subvalues: []},
buffer = [],
chars = '',
mode = 'normal',
delim = '',
line = '',
lines = [];
const flushChars = () => {
if (chars !== '') {
buffer.push({chars})
chars = ''
}
}
for (let i = 0; i < str.length; ++i) {
const c = str[i]
if (mode === 'escape') {
if (c === escape || c === open || c === close) {
flushChars()
buffer.push({escape: c})
mode = 'normal'
} else if (c === heredoc) {
mode = 'heredoc0'
} else throw Error('Invalid escape!')
} else if (mode === 'heredoc0') {
if (c === '\n') mode = 'heredoc1'
else delim += c
} else if (mode === 'heredoc1') {
if (c === '\n') {
if (line === delim) {
flushChars()
buffer.push({lines, delimiter: delim})
delim = ''
line = ''
lines = []
mode = 'normal'
} else {
lines.push(line)
line = ''
}
} else line += c
} else if (c === escape) {mode = 'escape'}
else if (c === open) {
const value = {subvalues: []}
flushChars()
parent.subvalues.push({prefix: buffer, value})
parents.push(parent)
parent = value
buffer = []
} else if (c === close) {
flushChars()
parent.suffix = buffer
buffer = []
if (parents.length < 1) throw Error('Unexpected close!')
parent = parents.pop()
} else {chars += c}
}
if (mode !== 'normal' || parents.length > 0) throw Error('Unexpected end!')
flushChars()
parent.suffix = buffer
parent.open = open
parent.close = close
parent.escape = escape
parent.heredoc = heredoc
return parent
}