UNPKG

2.36 kBJavaScriptView Raw
1const PLUS_CODE = 43; // +
2const MINUS_CODE = 45; // -
3
4const plugin = {
5 name: 'assignment',
6
7 assignmentOperators: new Set([
8 '=',
9 '*=',
10 '**=',
11 '/=',
12 '%=',
13 '+=',
14 '-=',
15 '<<=',
16 '>>=',
17 '>>>=',
18 '&=',
19 '^=',
20 '|=',
21 ]),
22 updateOperators: [PLUS_CODE, MINUS_CODE],
23 assignmentPrecedence: 0.9,
24
25 init(jsep) {
26 const updateNodeTypes = [jsep.IDENTIFIER, jsep.MEMBER_EXP];
27 plugin.assignmentOperators.forEach(op => jsep.addBinaryOp(op, plugin.assignmentPrecedence, true));
28
29 jsep.hooks.add('gobble-token', function gobbleUpdatePrefix(env) {
30 const code = this.code;
31 if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) {
32 this.index += 2;
33 env.node = {
34 type: 'UpdateExpression',
35 operator: code === PLUS_CODE ? '++' : '--',
36 argument: this.gobbleTokenProperty(this.gobbleIdentifier()),
37 prefix: true,
38 };
39 if (!env.node.argument || !updateNodeTypes.includes(env.node.argument.type)) {
40 this.throwError(`Unexpected ${env.node.operator}`);
41 }
42 }
43 });
44
45 jsep.hooks.add('after-token', function gobbleUpdatePostfix(env) {
46 if (env.node) {
47 const code = this.code;
48 if (plugin.updateOperators.some(c => c === code && c === this.expr.charCodeAt(this.index + 1))) {
49 if (!updateNodeTypes.includes(env.node.type)) {
50 this.throwError(`Unexpected ${env.node.operator}`);
51 }
52 this.index += 2;
53 env.node = {
54 type: 'UpdateExpression',
55 operator: code === PLUS_CODE ? '++' : '--',
56 argument: env.node,
57 prefix: false,
58 };
59 }
60 }
61 });
62
63 jsep.hooks.add('after-expression', function gobbleAssignment(env) {
64 if (env.node) {
65 // Note: Binaries can be chained in a single expression to respect
66 // operator precedence (i.e. a = b = 1 + 2 + 3)
67 // Update all binary assignment nodes in the tree
68 updateBinariesToAssignments(env.node);
69 }
70 });
71
72 function updateBinariesToAssignments(node) {
73 if (plugin.assignmentOperators.has(node.operator)) {
74 node.type = 'AssignmentExpression';
75 updateBinariesToAssignments(node.left);
76 updateBinariesToAssignments(node.right);
77 }
78 else if (!node.operator) {
79 Object.values(node).forEach((val) => {
80 if (val && typeof val === 'object') {
81 updateBinariesToAssignments(val);
82 }
83 });
84 }
85 }
86 },
87};
88
89export { plugin as default };