const PLUS_CODE = 43; // + const MINUS_CODE = 45; // - const plugin = { name: 'assignment', assignmentOperators: new Set([ '=', '*=', '**=', '/=', '%=', '+=', '-=', '<<=', '>>=', '>>>=', '&=', '^=', '|=', '||=', '&&=', '??=', ]), updateOperators: [PLUS_CODE, MINUS_CODE], assignmentPrecedence: 0.9, init(jsep) { const updateNodeTypes = [jsep.IDENTIFIER, jsep.MEMBER_EXP]; plugin.assignmentOperators.forEach(op => jsep.addBinaryOp(op, plugin.assignmentPrecedence, true)); jsep.hooks.add('gobble-token', function gobbleUpdatePrefix(env) { const code = this.code; if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) { this.index += 2; env.node = { type: 'UpdateExpression', operator: code === PLUS_CODE ? '++' : '--', argument: this.gobbleTokenProperty(this.gobbleIdentifier()), prefix: true, }; if (!env.node.argument || !updateNodeTypes.includes(env.node.argument.type)) { this.throwError(`Unexpected ${env.node.operator}`); } } }); jsep.hooks.add('after-token', function gobbleUpdatePostfix(env) { if (env.node) { const code = this.code; if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) { if (!updateNodeTypes.includes(env.node.type)) { this.throwError(`Unexpected ${env.node.operator}`); } this.index += 2; env.node = { type: 'UpdateExpression', operator: code === PLUS_CODE ? '++' : '--', argument: env.node, prefix: false, }; } } }); jsep.hooks.add('after-expression', function gobbleAssignment(env) { if (env.node) { // Note: Binaries can be chained in a single expression to respect // operator precedence (i.e. a = b = 1 + 2 + 3) // Update all binary assignment nodes in the tree updateBinariesToAssignments(env.node); } }); function updateBinariesToAssignments(node) { if (plugin.assignmentOperators.has(node.operator)) { node.type = 'AssignmentExpression'; updateBinariesToAssignments(node.left); updateBinariesToAssignments(node.right); } else if (!node.operator) { Object.values(node).forEach((val) => { if (val && typeof val === 'object') { updateBinariesToAssignments(val); } }); } } }, }; export { plugin as default };