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 1177x 1177x 1177x 1177x 1177x 1177x 1177x 1177x 2x 2x 2x 2x 2x 2x 2x 2x 1214x 1214x 1214x 1214x 1214x 5x 1214x 2x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 2x 1214x 1214x 1214x 1214x 341x 341x 341x 1214x 1214x 15x 15x 1199x 1199x 1214x 1194x 1194x 1214x 1214x 1214x 1214x 1214x 820x 820x 820x 820x 820x 820x 820x 820x 820x 820x 820x 820x 820x 10x 820x 4x 4x 820x 820x 820x 374x 374x 1214x 189x 189x 189x 189x 189x 189x 189x 189x 189x 185x 185x 185x | /** @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; } |