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
127
128
129 | 1×
1×
1×
1×
1×
1×
| import Fs from 'fs'
import Espree from 'espree'
const EspreeConfig = {
// attach range information to each node
range: true,
// attach line/column location information to each node
loc: true,
// create a top-level comments array containing all comments
comment: true,
// attach comments to the closest relevant node as leadingComments and
// trailingComments
attachComment: true,
// create a top-level tokens array containing all tokens
tokens: true,
// specify the language version (3, 5, 6, or 7, default is 5)
ecmaVersion: 5,
// specify which type of script you're parsing (script or module, default is script)
sourceType: 'module',
// specify additional language features
ecmaFeatures: {
// enable JSX parsing
jsx: true,
// enable return in global scope
globalReturn: true,
// enable implied strict mode (if ecmaVersion >= 5)
impliedStrict: true,
// allow experimental object rest/spread
experimentalObjectRestSpread: true,
// allow let and const declarations
blockBindings: true
}
}
// Leaving this code here in case support for assignment variables are needed.
// Since we are only supporting "const" for now, this isn't needed.
const ExtractAssignmentConstants = (node, store) => {
if (!node) {
throw new Error('Something went wrong!')
}
if (node.type !== 'AssignmentExpression') {
return node.end
}
const { name, start, end } = node.left
store.push({ name, start, end })
ExtractAssignmentConstants(node.right, store)
}
const ExtractGlobals = (astBody) => {
const globals = {
imports: {
start: null,
end: null,
nodes: []
},
constants: {
start: null,
end: null,
nodes: []
},
exports: {
start: null,
end: null,
nodes: []
}
}
astBody.forEach(node => {
if (node.type === 'ImportDeclaration') { // handle imports
const { start, end, specifiers } = node
if (globals.imports.start === null) {
globals.imports.start = start
}
globals.imports.end = end
specifiers.forEach(node => {
const { name, start, end } = node.local
globals.imports.nodes.push({ name, start, end })
})
} else if (node.type === 'ExportAllDeclaration' || // handle exports
node.type === 'ExportDefaultDeclaration' ||
node.type === 'ExportNamedDeclaration') {
if (globals.exports.start === null) {
globals.exports.start = node.start
}
if (node.type === 'ExportDefaultDeclaration') {
const { name, start, end } = node.declaration
globals.exports.nodes.push({ name, start, end })
} else if (node.type === 'ExportNamedDeclaration') {
if (node.declaration && node.declaration.declarations[0]) {
const { id, init } = node.declaration.declarations[0]
const { name, start, end } = id
globals.exports.nodes.push({ name, start, end })
ExtractAssignmentConstants(init, globals.exports.nodes)
} else {
node.specifiers.forEach(node => {
const { name, start, end } = node.local
globals.exports.nodes.push({ name, start, end })
})
}
}
globals.exports.end = node.end
} else if (node.type === 'VariableDeclaration' && // handle constants
node.kind === 'const') {
if (globals.constants.start === null) {
globals.constants.start = node.start
}
node.declarations.forEach(node => {
const { id, init } = node
const { name, start, end } = id
const constantNodes = globals.constants.nodes
const terminal = ExtractAssignmentConstants(init, constantNodes)
constantNodes.push({ name, start, end, terminal })
})
globals.constants.end = node.end
}
})
return globals
}
const Parse = (code) => {
if (typeof code !== 'string') {
throw new Error('Please pass in a valid code string!')
}
const ast = Espree.parse(code, EspreeConfig)
return ExtractGlobals(ast.body)
}
export default Parse
|