2 * Copyright (C) 2022 Nick Downing <nick@ndcode.org>
3 * SPDX-License-Identifier: MIT
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to
7 * deal in the Software without restriction, including without limitation the
8 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
9 * sell copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 let transform = (visitors, node, state) => {
25 let c = (node, st, override) =>
26 visitors[override || node.type](node, st, c)
27 return c(node, state, node.type)
30 // remainder of the file is adapted from acorn-walk/src/index.js
31 // we have changed "base" to "visitors"
32 // we have made tree be reconstructed by replacing each child element with
33 // the return value of its walker (and most walkers will return themselves)
35 let skipThrough = (node, st, c) => c(node, st)
36 let ignore = (node, st, c) => node
43 visitors.BlockStatement =
44 visitors.StaticBlock = (node, st, c) => {
45 for (let i = 0; i < node.body.length; ++i)
46 node.body[i] = c(node.body[i], st, 'Statement')
49 visitors.Statement = skipThrough
50 visitors.EmptyStatement = ignore
51 visitors.ExpressionStatement =
52 visitors.ParenthesizedExpression =
53 visitors.ChainExpression = (node, st, c) => {
54 node.expression = c(node.expression, st, 'Expression')
57 visitors.IfStatement = (node, st, c) => {
58 node.test = c(node.test, st, 'Expression')
59 node.consequent = c(node.consequent, st, 'Statement')
60 if (node.alternate) node.alternate = c(node.alternate, st, 'Statement')
63 visitors.LabeledStatement = (node, st, c) => {
64 node.body = c(node.body, st, 'Statement')
67 visitors.BreakStatement =
68 visitors.ContinueStatement = ignore
69 visitors.WithStatement = (node, st, c) => {
70 node.object = c(node.object, st, 'Expression')
71 node.body = c(node.body, st, 'Statement')
74 visitors.SwitchStatement = (node, st, c) => {
75 node.discriminant = c(node.discriminant, st, 'Expression')
76 for (let cs of node.cases) {
77 if (cs.test) cs.test = c(cs.test, st, 'Expression')
78 for (let i = 0; i < cs.consequent.length; ++i)
79 cs.consequent[i] = c(cs.consequent[i], st, 'Statement')
83 visitors.SwitchCase = (node, st, c) => {
84 if (node.test) node.test = c(node.test, st, 'Expression')
85 for (let i = 0; i < node.consequent.length; ++i)
86 node.consequent[i] = c(node.consequent[i], st, 'Statement')
89 visitors.ReturnStatement =
90 visitors.YieldExpression =
91 visitors.AwaitExpression =
92 visitors.InterpolateExpression = (node, st, c) => {
93 if (node.argument) node.argument = c(node.argument, st, 'Expression')
96 visitors.ThrowStatement =
97 visitors.SpreadElement = (node, st, c) => {
98 node.argument = c(node.argument, st, 'Expression')
101 visitors.TryStatement = (node, st, c) => {
102 node.block = c(node.block, st, 'Statement')
103 if (node.handler) node.handler = c(node.handler, st)
104 if (node.finalizer) node.finalizer = c(node.finalizer, st, 'Statement')
107 visitors.CatchClause = (node, st, c) => {
108 if (node.param) node.param = c(node.param, st, 'Pattern')
109 node.body = c(node.body, st, 'Statement')
112 visitors.WhileStatement =
113 visitors.DoWhileStatement = (node, st, c) => {
114 node.test = c(node.test, st, 'Expression')
115 node.body = c(node.body, st, 'Statement')
118 visitors.ForStatement = (node, st, c) => {
119 if (node.init) node.init = c(node.init, st, 'ForInit')
120 if (node.test) node.test = c(node.test, st, 'Expression')
121 if (node.update) node.update = c(node.update, st, 'Expression')
122 node.body = c(node.body, st, 'Statement')
125 visitors.ForInStatement =
126 visitors.ForOfStatement = (node, st, c) => {
127 node.left = c(node.left, st, 'ForInit')
128 node.right = c(node.right, st, 'Expression')
129 node.body = c(node.body, st, 'Statement')
132 visitors.ForInit = (node, st, c) => {
133 if (node.type === 'VariableDeclaration') return c(node, st)
134 else return c(node, st, 'Expression')
137 visitors.DebuggerStatement = ignore
139 visitors.FunctionDeclaration = (node, st, c) => c(node, st, 'Function')
140 visitors.VariableDeclaration = (node, st, c) => {
141 for (let i = 0; i < node.declarations.length; ++i)
142 node.declarations[i] = c(node.declarations[i], st)
145 visitors.VariableDeclarator = (node, st, c) => {
146 node.id = c(node.id, st, 'Pattern')
147 if (node.init) node.init = c(node.init, st, 'Expression')
151 visitors.Function = (node, st, c) => {
152 if (node.id) node.id = c(node.id, st, 'Pattern')
153 for (let i = 0; i < node.params.length; ++i)
154 node.params[i] = c(node.params[i], st, 'Pattern')
155 node.body = c(node.body, st, node.expression ? 'Expression' : 'Statement')
159 visitors.Pattern = (node, st, c) => {
160 if (node.type === 'Identifier')
161 return c(node, st, 'VariablePattern')
162 else if (node.type === 'MemberExpression')
163 return c(node, st, 'MemberPattern')
168 visitors.VariablePattern = ignore
169 visitors.MemberPattern = skipThrough
170 visitors.RestElement = (node, st, c) => {
171 node.argument = c(node.argument, st, 'Pattern')
174 visitors.ArrayPattern = (node, st, c) => {
175 for (let i = 0; i < node.elements.length; ++i) {
176 let elt = node.elements[i]
177 if (elt) node.elements[i] = c(elt, st, 'Pattern')
181 visitors.ObjectPattern = (node, st, c) => {
182 for (let prop of node.properties) {
183 if (prop.type === 'Property') {
184 if (prop.computed) prop.key = c(prop.key, st, 'Expression')
185 prop.value = c(prop.value, st, 'Pattern')
186 } else if (prop.type === 'RestElement') {
187 prop.argument = c(prop.argument, st, 'Pattern')
193 visitors.Expression = skipThrough
194 visitors.ThisExpression =
196 visitors.MetaProperty = ignore
197 visitors.ArrayExpression = (node, st, c) => {
198 for (let i = 0; i < node.elements.length; ++i) {
199 let elt = node.elements[i]
200 if (elt) node.elements[i] = c(elt, st, 'Expression')
204 visitors.ObjectExpression = (node, st, c) => {
205 for (let i = 0; i < node.properties.length; ++i)
206 node.properties[i] = c(node.properties[i], st)
209 visitors.FunctionExpression =
210 visitors.ArrowFunctionExpression = visitors.FunctionDeclaration
211 visitors.SequenceExpression = (node, st, c) => {
212 for (let i = 0; i < node.expressions.length; ++i)
213 node.expressions[i] = c(node.expressions[i], st, 'Expression')
216 visitors.TemplateLiteral = (node, st, c) => {
217 for (let i = 0; i < node.quasis.length; ++i)
218 node.quasis[i] = c(node.quasis[i], st)
220 for (let i = 0; i < node.expressions.length; ++i)
221 node.expressions[i] = c(node.expressions[i], st, 'Expression')
224 visitors.TemplateElement = ignore
225 visitors.UnaryExpression =
226 visitors.UpdateExpression = (node, st, c) => {
227 node.argument = c(node.argument, st, 'Expression')
230 visitors.BinaryExpression =
231 visitors.LogicalExpression = (node, st, c) => {
232 node.left = c(node.left, st, 'Expression')
233 node.right = c(node.right, st, 'Expression')
236 visitors.AssignmentExpression =
237 visitors.AssignmentPattern = (node, st, c) => {
238 node.left = c(node.left, st, 'Pattern')
239 node.right = c(node.right, st, 'Expression')
242 visitors.ConditionalExpression = (node, st, c) => {
243 node.test = c(node.test, st, 'Expression')
244 node.consequent = c(node.consequent, st, 'Expression')
245 node.alternate = c(node.alternate, st, 'Expression')
248 visitors.NewExpression =
249 visitors.CallExpression = (node, st, c) => {
250 node.callee = c(node.callee, st, 'Expression')
252 for (let i = 0; i < node.arguments.length; ++i)
253 node.arguments[i] = c(node.arguments[i], st, 'Expression')
256 visitors.MemberExpression = (node, st, c) => {
257 node.object = c(node.object, st, 'Expression')
258 if (node.computed) node.property = c(node.property, st, 'Expression')
261 visitors.ExportNamedDeclaration =
262 visitors.ExportDefaultDeclaration = (node, st, c) => {
263 if (node.declaration)
264 node.declaration = c(node.declaration, st, node.type === 'ExportNamedDeclaration' || node.declaration.id ? 'Statement' : 'Expression')
265 if (node.source) node.source = c(node.source, st, 'Expression')
268 visitors.ExportAllDeclaration = (node, st, c) => {
270 node.exported = c(node.exported, st)
271 node.source = c(node.source, st, 'Expression')
274 visitors.ImportDeclaration = (node, st, c) => {
275 for (let i = 0; i < node.specifiers.length; ++i)
276 node.specifiers[i] = c(node.specifiers[i], st)
277 node.source = c(node.source, st, 'Expression')
280 visitors.ImportExpression = (node, st, c) => {
281 node.source = c(node.source, st, "Expression")
284 visitors.ImportSpecifier =
285 visitors.ImportDefaultSpecifier =
286 visitors.ImportNamespaceSpecifier =
287 visitors.Identifier =
288 visitors.PrivateIdentifier =
289 visitors.Literal = ignore
291 visitors.TaggedTemplateExpression = (node, st, c) => {
292 node.tag = c(node.tag, st, 'Expression')
293 node.quasi = c(node.quasi, st, 'Expression')
296 visitors.ClassDeclaration =
297 visitors.ClassExpression = (node, st, c) => c(node, st, 'Class')
298 visitors.Class = (node, st, c) => {
299 if (node.id) node.id = c(node.id, st, 'Pattern')
300 if (node.superClass) node.superClass = c(node.superClass, st, 'Expression')
301 node.body = c(node.body, st)
304 visitors.ClassBody = (node, st, c) => {
305 for (let i = 0; i < node.body.length; ++i)
306 node.body[i] = c(node.body[i], st)
309 visitors.MethodDefinition =
310 visitors.PropertyDefinition =
311 visitors.Property = (node, st, c) => {
312 if (node.computed) node.key = c(node.key, st, 'Expression')
313 if (node.value) node.value = c(node.value, st, 'Expression')
318 visitors.HTMLExpression = (node, st, c) => {
319 node.tag = c(node.tag, st, 'Expression')
320 node.body = c(node.body, st, 'Statement')
324 exports.transform = transform
325 exports.visitors = visitors