|
1 |
| -/** @import { AssignmentExpression, Expression, Identifier, Pattern, PrivateIdentifier, Super, UpdateExpression, VariableDeclarator } from 'estree' */ |
| 1 | +/** @import { AssignmentExpression, Expression, Literal, Pattern, PrivateIdentifier, Super, UpdateExpression, VariableDeclarator } from 'estree' */ |
2 | 2 | /** @import { AST, Binding } from '#compiler' */
|
3 | 3 | /** @import { AnalysisState, Context } from '../../types' */
|
4 | 4 | /** @import { Scope } from '../../../scope' */
|
@@ -176,25 +176,42 @@ export function is_safe_identifier(expression, scope) {
|
176 | 176 | }
|
177 | 177 |
|
178 | 178 | /**
|
179 |
| - * @param {Expression | Super} node |
| 179 | + * @param {Expression | Literal | Super} node |
180 | 180 | * @param {Context} context
|
181 | 181 | * @returns {boolean}
|
182 | 182 | */
|
183 | 183 | export function is_pure(node, context) {
|
| 184 | + if (node.type === 'Literal') { |
| 185 | + return true; |
| 186 | + } |
| 187 | + if (node.type === 'CallExpression') { |
| 188 | + if (!is_pure(node.callee, context)) { |
| 189 | + return false; |
| 190 | + } |
| 191 | + for (let arg of node.arguments) { |
| 192 | + if (!is_pure(arg.type === 'SpreadElement' ? arg.argument : arg, context)) { |
| 193 | + return false; |
| 194 | + } |
| 195 | + } |
| 196 | + return true; |
| 197 | + } |
184 | 198 | if (node.type !== 'Identifier' && node.type !== 'MemberExpression') {
|
185 | 199 | return false;
|
186 | 200 | }
|
187 | 201 |
|
188 |
| - if (node.type === 'MemberExpression' && node.object.type === 'Literal') { |
189 |
| - return true; |
| 202 | + /** @type {Expression | Super | null} */ |
| 203 | + let left = node; |
| 204 | + while (left.type === 'MemberExpression' && !left.computed) { |
| 205 | + left = left.object; |
190 | 206 | }
|
191 | 207 |
|
192 |
| - const left = object(node); |
193 | 208 | if (!left) return false;
|
194 | 209 |
|
195 | 210 | if (left.type === 'Identifier') {
|
196 | 211 | const binding = context.state.scope.get(left.name);
|
197 | 212 | if (binding === null) return true; // globals are assumed to be safe
|
| 213 | + } else if (is_pure(left, context)) { |
| 214 | + return true; |
198 | 215 | }
|
199 | 216 |
|
200 | 217 | // TODO add more cases (safe Svelte imports, etc)
|
|
0 commit comments