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 | 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2x 2842x 2842x 2842x 2728x 2842x 114x 114x 114x 114x 114x 114x 114x 215x 215x 215x 215x 215x 215x 215x 111x 111x 111x 111x 111x 215x 114x 114x 114x 53x 53x 53x 61x 61x 61x 61x 114x 13x 13x 13x 61x 114x 51x 51x 51x 51x 51x 51x 51x 51x 51x 10x 10x 10x 2728x 2842x 2728x 2728x 2728x | /** @import { AssignmentExpression, AssignmentOperator, Expression, Node, Pattern } from 'estree' */ /** @import { Context as ClientContext } from '../client/types.js' */ /** @import { Context as ServerContext } from '../server/types.js' */ import { extract_paths, is_expression_async } from '../../../utils/ast.js'; import * as b from '../../../utils/builders.js'; /** * @template {ClientContext | ServerContext} Context * @param {AssignmentExpression} node * @param {Context} context * @param {(operator: AssignmentOperator, left: Pattern, right: Expression, context: Context) => Expression | null} build_assignment * @returns */ export function visit_assignment_expression(node, context, build_assignment) { if ( node.left.type === 'ArrayPattern' || node.left.type === 'ObjectPattern' || node.left.type === 'RestElement' ) { const value = /** @type {Expression} */ (context.visit(node.right)); const should_cache = value.type !== 'Identifier'; const rhs = should_cache ? b.id('$$value') : value; let changed = false; const assignments = extract_paths(node.left).map((path) => { const value = path.expression?.(rhs); let assignment = build_assignment('=', path.node, value, context); if (assignment !== null) changed = true; return ( assignment ?? b.assignment( '=', /** @type {Pattern} */ (context.visit(path.node)), /** @type {Expression} */ (context.visit(value)) ) ); }); if (!changed) { // No change to output -> nothing to transform -> we can keep the original assignment return null; } const is_standalone = /** @type {Node} */ (context.path.at(-1)).type.endsWith('Statement'); const sequence = b.sequence(assignments); if (!is_standalone) { // this is part of an expression, we need the sequence to end with the value sequence.expressions.push(rhs); } if (should_cache) { // the right hand side is a complex expression, wrap in an IIFE to cache it const iife = b.arrow([rhs], sequence); const iife_is_async = is_expression_async(value) || assignments.some((assignment) => is_expression_async(assignment)); return iife_is_async ? b.await(b.call(b.async(iife), value)) : b.call(iife, value); } return sequence; } if (node.left.type !== 'Identifier' && node.left.type !== 'MemberExpression') { throw new Error(`Unexpected assignment type ${node.left.type}`); } return build_assignment(node.operator, node.left, node.right, context); } |