/
replacements.js
123 lines (119 loc) · 3.42 KB
/
replacements.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
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
119
120
121
122
123
const FALLBACK_HANDLER = Symbol("fallback handler");
module.exports = ({ types: t }) => {
const undef = t.unaryExpression("void", t.numericLiteral(0));
function isUndef(ob) {
return (
ob === undefined ||
t.isIdentifier(ob, { name: "undefined" }) ||
t.isUnaryExpression(ob, { operator: "void" })
);
}
function defaultZero(cb) {
return function(i = t.numericLiteral(0), ...args) {
if (t.isNumericLiteral(i)) {
return cb.call(this, this, i.value, ...args);
}
};
}
return {
ArrayExpression: {
members: {
length() {
return t.numericLiteral(this.elements.length);
},
[FALLBACK_HANDLER](i) {
if (typeof i === "number" || i.match(/^\d+$/)) {
return this.elements[i] || undef;
}
}
},
calls: {
join(sep = t.stringLiteral(",")) {
if (!t.isStringLiteral(sep)) return;
let bad = false;
const str = this.elements
.map(el => {
if (!t.isLiteral(el)) {
bad = true;
return;
}
return el.value;
})
.join(sep.value);
return bad ? undefined : t.stringLiteral(str);
},
push(...args) {
return t.numericLiteral(this.elements.length + args.length);
},
shift() {
if (this.elements.length === 0) {
return undef;
}
return t.numericLiteral(this.elements.length - 1);
},
slice(start = t.numericLiteral(0), end) {
if (!t.isNumericLiteral(start) || (end && !t.isNumericLiteral(end))) {
return;
}
return t.arrayExpression(
this.elements.slice(start.value, end && end.value)
);
},
pop() {
return this.elements[this.elements.length - 1] || undef;
},
reverse() {
return t.arrayExpression(this.elements.reverse());
},
splice(start, end, ...args) {
if (!t.isNumericLiteral(start) || (end && !t.isNumericLiteral(end))) {
return;
}
if (end) {
args.unshift(end.value);
}
return t.arrayExpression(
this.elements.slice().splice(start.value, ...args)
);
}
}
},
StringLiteral: {
members: {
length() {
return t.numericLiteral(this.value.length);
},
[FALLBACK_HANDLER](i) {
if (typeof i === "number" || i.match(/^\d+$/)) {
const ch = this.value[i];
return ch ? t.stringLiteral(ch) : undef;
}
}
},
calls: {
split(sep = undef) {
let realSep = null;
if (t.isStringLiteral(sep)) {
realSep = sep.value;
}
if (isUndef(sep)) {
realSep = sep;
}
if (realSep !== null) {
return t.arrayExpression(
this.value.split(realSep).map(str => t.stringLiteral(str))
);
}
},
charAt: defaultZero(({ value }, i) => t.stringLiteral(value.charAt(i))),
charCodeAt: defaultZero(({ value }, i) =>
t.numericLiteral(value.charCodeAt(i))
),
codePointAt: defaultZero(({ value }, i) =>
t.numericLiteral(value.codePointAt(i))
)
}
}
};
};
module.exports.FALLBACK_HANDLER = FALLBACK_HANDLER;