-
Notifications
You must be signed in to change notification settings - Fork 119
/
ConditionalPatcher.js
82 lines (71 loc) · 2.22 KB
/
ConditionalPatcher.js
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
import NodePatcher from '../../../patchers/NodePatcher.js';
import type { Node, ParseContext, Editor } from './../../../patchers/types.js';
import type { SourceTokenListIndex } from 'coffee-lex';
import { IF } from 'coffee-lex';
/**
* Normalizes conditionals by rewriting post-`if` into standard `if`, e.g.
*
* return [] unless list?
*
* becomes
*
* unless list? then return []
*/
export default class ConditionalPatcher extends NodePatcher {
condition: NodePatcher;
consequent: ?NodePatcher;
alternate: ?NodePatcher;
constructor(node: Node, context: ParseContext, editor: Editor, condition: NodePatcher, consequent: NodePatcher, alternate: ?NodePatcher) {
super(node, context, editor);
this.condition = condition;
this.consequent = consequent;
this.alternate = alternate;
}
patchAsExpression() {
if (this.isPostIf()) {
this.patchPostIf();
} else {
this.condition.patch();
if (this.consequent !== null) {
this.consequent.patch();
}
if (this.alternate !== null) {
this.alternate.patch();
}
}
}
/**
* `CONSEQUENT 'if' CONDITION` → `if CONDITION then CONSEQUENT`
* `CONSEQUENT 'unless' CONDITION` → `unless CONDITION then CONSEQUENT`
*/
patchPostIf() {
this.condition.patch();
this.consequent.patch();
let ifTokenIndex = this.getIfTokenIndex();
let ifToken = this.sourceTokenAtIndex(ifTokenIndex);
if (ifToken) {
let consequentCode = this.slice(this.consequent.outerStart, this.consequent.outerEnd);
this.remove(this.consequent.outerStart, ifToken.start);
this.insert(this.condition.outerEnd, ` then ${consequentCode}`);
}
}
isPostIf(): boolean {
return this.consequent !== null
&& this.condition.contentStart > this.consequent.contentStart;
}
getIfTokenIndex(): SourceTokenListIndex {
let start = this.contentStartTokenIndex;
let index = this.condition.outerStartTokenIndex;
while (index !== start) {
let token = this.sourceTokenAtIndex(index);
if (token && token.type === IF) {
break;
}
index = index.previous();
}
if (!index) {
throw this.error('unable to find `if` token in conditional');
}
return index;
}
}