* Utility used to determine if an expression includes object getters or proxies. * * Example: given `obj.foo`, the function lets you know if `foo` has a getter function * associated to it, or if `obj` is a proxy * @param {any} expr The expression, in AST format to analyze * @param {string} expr
(expr, exprStr, evalFn, ctx, callback)
| 658 | * @returns {void} |
| 659 | */ |
| 660 | function includesProxiesOrGetters(expr, exprStr, evalFn, ctx, callback) { |
| 661 | if (expr?.type !== 'MemberExpression') { |
| 662 | // If the expression is not a member one for obvious reasons no getters are involved |
| 663 | return callback(false); |
| 664 | } |
| 665 | |
| 666 | if (expr.object.type === 'MemberExpression') { |
| 667 | // The object itself is a member expression, so we need to recurse (e.g. the expression is `obj.foo.bar`) |
| 668 | return includesProxiesOrGetters( |
| 669 | expr.object, |
| 670 | exprStr.slice(0, expr.object.end), |
| 671 | evalFn, |
| 672 | ctx, |
| 673 | (includes, lastEvaledObj) => { |
| 674 | if (includes) { |
| 675 | // If the recurred call found a getter we can also terminate |
| 676 | return callback(includes); |
| 677 | } |
| 678 | |
| 679 | if (isProxy(lastEvaledObj)) { |
| 680 | return callback(true); |
| 681 | } |
| 682 | |
| 683 | // If a getter/proxy hasn't been found by the recursion call we need to check if maybe a getter/proxy |
| 684 | // is present here (e.g. in `obj.foo.bar` we found that `obj.foo` doesn't involve any getters so we now |
| 685 | // need to check if `bar` on `obj.foo` (i.e. `lastEvaledObj`) has a getter or if `obj.foo.bar` is a proxy) |
| 686 | return hasGetterOrIsProxy(lastEvaledObj, expr.property, (doesHaveGetterOrIsProxy) => { |
| 687 | return callback(doesHaveGetterOrIsProxy); |
| 688 | }); |
| 689 | }, |
| 690 | ); |
| 691 | } |
| 692 | |
| 693 | // This is the base of the recursion we have an identifier for the object and an identifier or literal |
| 694 | // for the property (e.g. we have `obj.foo` or `obj['foo']`, `obj` is the object identifier and `foo` |
| 695 | // is the property identifier/literal) |
| 696 | if (expr.object.type === 'Identifier') { |
| 697 | return evalFn(`try { ${expr.object.name} } catch {}`, ctx, getREPLResourceName(), (err, obj) => { |
| 698 | if (err) { |
| 699 | return callback(false); |
| 700 | } |
| 701 | |
| 702 | if (isProxy(obj)) { |
| 703 | return callback(true); |
| 704 | } |
| 705 | |
| 706 | return hasGetterOrIsProxy(obj, expr.property, (doesHaveGetterOrIsProxy) => { |
| 707 | if (doesHaveGetterOrIsProxy) { |
| 708 | return callback(true); |
| 709 | } |
| 710 | |
| 711 | return evalFn( |
| 712 | `try { ${exprStr} } catch {} `, ctx, getREPLResourceName(), (err, obj) => { |
| 713 | if (err) { |
| 714 | return callback(false); |
| 715 | } |
| 716 | return callback(false, obj); |
| 717 | }); |
no test coverage detected
searching dependent graphs…