Press n or j to go to the next uncovered block, b, p or k for the previous block.
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 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 1753x 1753x 1753x 1753x 1753x 1753x 1753x 1753x 2x 2x 2x 2x 2x 2x 2x 2x 1802x 1802x 1802x 1802x 1802x 221x 1802x 35x 14x 14x 14x 12x 12x 12x 12x 12x 12x 8x 8x 8x 8x 8x 8x 12x 12x 7x 12x 4x 4x 12x 14x 35x 1791x 1791x 1791x 1802x 583x 583x 583x 1791x 1802x 43x 43x 1748x 1748x 1802x 1743x 1743x 1802x 1802x 1802x 1802x 1802x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 1158x 306x 1158x 137x 137x 1158x 1158x 1158x 585x 585x 1802x 244x 244x 244x 244x 244x 244x 244x 244x 244x 341x 341x 341x | /** @import { AssignmentExpression, AssignmentOperator, Expression, Pattern } from 'estree' */ /** @import { Context } from '../types.js' */ import * as b from '../../../../utils/builders.js'; import { build_assignment_value } from '../../../../utils/ast.js'; import { is_ignored } from '../../../../state.js'; import { build_proxy_reassignment, should_proxy } from '../utils.js'; import { visit_assignment_expression } from '../../shared/assignments.js'; /** * @param {AssignmentExpression} node * @param {Context} context */ export function AssignmentExpression(node, context) { const expression = /** @type {Expression} */ ( visit_assignment_expression(node, context, build_assignment) ?? context.next() ); return is_ignored(node, 'ownership_invalid_mutation') ? b.call('$.skip_ownership_validation', b.thunk(expression)) : expression; } /** * @param {AssignmentOperator} operator * @param {Pattern} left * @param {Expression} right * @param {Context} context * @returns {Expression | null} */ function build_assignment(operator, left, right, context) { // Handle class private/public state assignment cases if ( context.state.analysis.runes && left.type === 'MemberExpression' && left.object.type === 'ThisExpression' ) { if (left.property.type === 'PrivateIdentifier') { const private_state = context.state.private_state.get(left.property.name); if (private_state !== undefined) { let transformed = false; let value = /** @type {Expression} */ ( context.visit(build_assignment_value(operator, left, right)) ); if (should_proxy(value, context.state.scope)) { transformed = true; value = private_state.kind === 'raw_state' ? value : build_proxy_reassignment(value, b.member(b.this, private_state.id)); } if (!context.state.in_constructor) { return b.call('$.set', left, value); } else if (transformed) { return b.assignment(operator, /** @type {Pattern} */ (context.visit(left)), value); } } } } let object = left; while (object.type === 'MemberExpression') { // @ts-expect-error object = object.object; } if (object.type !== 'Identifier') { return null; } const binding = context.state.scope.get(object.name); if (!binding) return null; const transform = Object.hasOwn(context.state.transform, object.name) ? context.state.transform[object.name] : null; // reassignment if (object === left && transform?.assign) { let value = /** @type {Expression} */ ( context.visit(build_assignment_value(operator, left, right)) ); // special case — if an element binding, we know it's a primitive const path = context.path.map((node) => node.type); const is_primitive = path.at(-1) === 'BindDirective' && path.at(-2) === 'RegularElement'; if ( !is_primitive && binding.kind !== 'prop' && binding.kind !== 'bindable_prop' && context.state.analysis.runes && should_proxy(value, context.state.scope) ) { value = binding.kind === 'raw_state' ? value : build_proxy_reassignment(value, object); } return transform.assign(object, value); } // mutation if (transform?.mutate) { return transform.mutate( object, b.assignment( operator, /** @type {Pattern} */ (context.visit(left)), /** @type {Expression} */ (context.visit(right)) ) ); } return null; } |