1 |
|
2 | import {TokenType as tt} from "../parser/tokenizer/types";
|
3 |
|
4 | import isIdentifier from "../util/isIdentifier";
|
5 |
|
6 | import Transformer from "./Transformer";
|
7 |
|
8 | export default class TypeScriptTransformer extends Transformer {
|
9 | constructor(
|
10 | rootTransformer,
|
11 | tokens,
|
12 | isImportsTransformEnabled,
|
13 | ) {
|
14 | super();this.rootTransformer = rootTransformer;this.tokens = tokens;this.isImportsTransformEnabled = isImportsTransformEnabled;;
|
15 | }
|
16 |
|
17 | process() {
|
18 | if (
|
19 | this.rootTransformer.processPossibleArrowParamEnd() ||
|
20 | this.rootTransformer.processPossibleAsyncArrowWithTypeParams() ||
|
21 | this.rootTransformer.processPossibleTypeRange()
|
22 | ) {
|
23 | return true;
|
24 | }
|
25 | if (
|
26 | this.tokens.matches1(tt._public) ||
|
27 | this.tokens.matches1(tt._protected) ||
|
28 | this.tokens.matches1(tt._private) ||
|
29 | this.tokens.matches1(tt._abstract) ||
|
30 | this.tokens.matches1(tt._readonly) ||
|
31 | this.tokens.matches1(tt._override) ||
|
32 | this.tokens.matches1(tt.nonNullAssertion)
|
33 | ) {
|
34 | this.tokens.removeInitialToken();
|
35 | return true;
|
36 | }
|
37 | if (this.tokens.matches1(tt._enum) || this.tokens.matches2(tt._const, tt._enum)) {
|
38 | this.processEnum();
|
39 | return true;
|
40 | }
|
41 | if (
|
42 | this.tokens.matches2(tt._export, tt._enum) ||
|
43 | this.tokens.matches3(tt._export, tt._const, tt._enum)
|
44 | ) {
|
45 | this.processEnum(true);
|
46 | return true;
|
47 | }
|
48 | return false;
|
49 | }
|
50 |
|
51 | processEnum(isExport = false) {
|
52 |
|
53 | this.tokens.removeInitialToken();
|
54 | while (this.tokens.matches1(tt._const) || this.tokens.matches1(tt._enum)) {
|
55 | this.tokens.removeToken();
|
56 | }
|
57 | const enumName = this.tokens.identifierName();
|
58 | this.tokens.removeToken();
|
59 | if (isExport && !this.isImportsTransformEnabled) {
|
60 | this.tokens.appendCode("export ");
|
61 | }
|
62 | this.tokens.appendCode(`var ${enumName}; (function (${enumName})`);
|
63 | this.tokens.copyExpectedToken(tt.braceL);
|
64 | this.processEnumBody(enumName);
|
65 | this.tokens.copyExpectedToken(tt.braceR);
|
66 | if (isExport && this.isImportsTransformEnabled) {
|
67 | this.tokens.appendCode(`)(${enumName} || (exports.${enumName} = ${enumName} = {}));`);
|
68 | } else {
|
69 | this.tokens.appendCode(`)(${enumName} || (${enumName} = {}));`);
|
70 | }
|
71 | }
|
72 |
|
73 | |
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | processEnumBody(enumName) {
|
81 |
|
82 |
|
83 | let previousValueCode = null;
|
84 | while (true) {
|
85 | if (this.tokens.matches1(tt.braceR)) {
|
86 | break;
|
87 | }
|
88 | const {nameStringCode, variableName} = this.extractEnumKeyInfo(this.tokens.currentToken());
|
89 | this.tokens.removeInitialToken();
|
90 |
|
91 | if (
|
92 | this.tokens.matches3(tt.eq, tt.string, tt.comma) ||
|
93 | this.tokens.matches3(tt.eq, tt.string, tt.braceR)
|
94 | ) {
|
95 | this.processStringLiteralEnumMember(enumName, nameStringCode, variableName);
|
96 | } else if (this.tokens.matches1(tt.eq)) {
|
97 | this.processExplicitValueEnumMember(enumName, nameStringCode, variableName);
|
98 | } else {
|
99 | this.processImplicitValueEnumMember(
|
100 | enumName,
|
101 | nameStringCode,
|
102 | variableName,
|
103 | previousValueCode,
|
104 | );
|
105 | }
|
106 | if (this.tokens.matches1(tt.comma)) {
|
107 | this.tokens.removeToken();
|
108 | }
|
109 |
|
110 | if (variableName != null) {
|
111 | previousValueCode = variableName;
|
112 | } else {
|
113 | previousValueCode = `${enumName}[${nameStringCode}]`;
|
114 | }
|
115 | }
|
116 | }
|
117 |
|
118 | |
119 |
|
120 |
|
121 |
|
122 |
|
123 |
|
124 |
|
125 |
|
126 |
|
127 |
|
128 |
|
129 |
|
130 |
|
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 |
|
137 |
|
138 | extractEnumKeyInfo(nameToken) {
|
139 | if (nameToken.type === tt.name) {
|
140 | const name = this.tokens.identifierNameForToken(nameToken);
|
141 | return {
|
142 | nameStringCode: `"${name}"`,
|
143 | variableName: isIdentifier(name) ? name : null,
|
144 | };
|
145 | } else if (nameToken.type === tt.string) {
|
146 | const name = this.tokens.stringValueForToken(nameToken);
|
147 | return {
|
148 | nameStringCode: this.tokens.code.slice(nameToken.start, nameToken.end),
|
149 | variableName: isIdentifier(name) ? name : null,
|
150 | };
|
151 | } else {
|
152 | throw new Error("Expected name or string at beginning of enum element.");
|
153 | }
|
154 | }
|
155 |
|
156 | |
157 |
|
158 |
|
159 |
|
160 |
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 |
|
173 | processStringLiteralEnumMember(
|
174 | enumName,
|
175 | nameStringCode,
|
176 | variableName,
|
177 | ) {
|
178 | if (variableName != null) {
|
179 | this.tokens.appendCode(`const ${variableName}`);
|
180 |
|
181 | this.tokens.copyToken();
|
182 |
|
183 | this.tokens.copyToken();
|
184 | this.tokens.appendCode(`; ${enumName}[${nameStringCode}] = ${variableName};`);
|
185 | } else {
|
186 | this.tokens.appendCode(`${enumName}[${nameStringCode}]`);
|
187 |
|
188 | this.tokens.copyToken();
|
189 |
|
190 | this.tokens.copyToken();
|
191 | this.tokens.appendCode(";");
|
192 | }
|
193 | }
|
194 |
|
195 | |
196 |
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 |
|
212 |
|
213 |
|
214 |
|
215 |
|
216 |
|
217 |
|
218 |
|
219 |
|
220 | processExplicitValueEnumMember(
|
221 | enumName,
|
222 | nameStringCode,
|
223 | variableName,
|
224 | ) {
|
225 | const rhsEndIndex = this.tokens.currentToken().rhsEndIndex;
|
226 | if (rhsEndIndex == null) {
|
227 | throw new Error("Expected rhsEndIndex on enum assign.");
|
228 | }
|
229 |
|
230 | if (variableName != null) {
|
231 | this.tokens.appendCode(`const ${variableName}`);
|
232 | this.tokens.copyToken();
|
233 | while (this.tokens.currentIndex() < rhsEndIndex) {
|
234 | this.rootTransformer.processToken();
|
235 | }
|
236 | this.tokens.appendCode(
|
237 | `; ${enumName}[${enumName}[${nameStringCode}] = ${variableName}] = ${nameStringCode};`,
|
238 | );
|
239 | } else {
|
240 | this.tokens.appendCode(`${enumName}[${enumName}[${nameStringCode}]`);
|
241 | this.tokens.copyToken();
|
242 | while (this.tokens.currentIndex() < rhsEndIndex) {
|
243 | this.rootTransformer.processToken();
|
244 | }
|
245 | this.tokens.appendCode(`] = ${nameStringCode};`);
|
246 | }
|
247 | }
|
248 |
|
249 | |
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 |
|
256 |
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 |
|
264 | processImplicitValueEnumMember(
|
265 | enumName,
|
266 | nameStringCode,
|
267 | variableName,
|
268 | previousValueCode,
|
269 | ) {
|
270 | let valueCode = previousValueCode != null ? `${previousValueCode} + 1` : "0";
|
271 | if (variableName != null) {
|
272 | this.tokens.appendCode(`const ${variableName} = ${valueCode}; `);
|
273 | valueCode = variableName;
|
274 | }
|
275 | this.tokens.appendCode(
|
276 | `${enumName}[${enumName}[${nameStringCode}] = ${valueCode}] = ${nameStringCode};`,
|
277 | );
|
278 | }
|
279 | }
|