source: frontend/node_modules/sucrase/dist/CJSImportProcessor.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 12 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 16.0 KB
Line 
1"use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
2
3
4var _tokenizer = require('./parser/tokenizer');
5var _keywords = require('./parser/tokenizer/keywords');
6var _types = require('./parser/tokenizer/types');
7
8var _getImportExportSpecifierInfo = require('./util/getImportExportSpecifierInfo'); var _getImportExportSpecifierInfo2 = _interopRequireDefault(_getImportExportSpecifierInfo);
9var _getNonTypeIdentifiers = require('./util/getNonTypeIdentifiers');
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26/**
27 * Class responsible for preprocessing and bookkeeping import and export declarations within the
28 * file.
29 *
30 * TypeScript uses a simpler mechanism that does not use functions like interopRequireDefault and
31 * interopRequireWildcard, so we also allow that mode for compatibility.
32 */
33 class CJSImportProcessor {
34 __init() {this.nonTypeIdentifiers = new Set()}
35 __init2() {this.importInfoByPath = new Map()}
36 __init3() {this.importsToReplace = new Map()}
37 __init4() {this.identifierReplacements = new Map()}
38 __init5() {this.exportBindingsByLocalName = new Map()}
39
40 constructor(
41 nameManager,
42 tokens,
43 enableLegacyTypeScriptModuleInterop,
44 options,
45 isTypeScriptTransformEnabled,
46 keepUnusedImports,
47 helperManager,
48 ) {;this.nameManager = nameManager;this.tokens = tokens;this.enableLegacyTypeScriptModuleInterop = enableLegacyTypeScriptModuleInterop;this.options = options;this.isTypeScriptTransformEnabled = isTypeScriptTransformEnabled;this.keepUnusedImports = keepUnusedImports;this.helperManager = helperManager;CJSImportProcessor.prototype.__init.call(this);CJSImportProcessor.prototype.__init2.call(this);CJSImportProcessor.prototype.__init3.call(this);CJSImportProcessor.prototype.__init4.call(this);CJSImportProcessor.prototype.__init5.call(this);}
49
50 preprocessTokens() {
51 for (let i = 0; i < this.tokens.tokens.length; i++) {
52 if (
53 this.tokens.matches1AtIndex(i, _types.TokenType._import) &&
54 !this.tokens.matches3AtIndex(i, _types.TokenType._import, _types.TokenType.name, _types.TokenType.eq)
55 ) {
56 this.preprocessImportAtIndex(i);
57 }
58 if (
59 this.tokens.matches1AtIndex(i, _types.TokenType._export) &&
60 !this.tokens.matches2AtIndex(i, _types.TokenType._export, _types.TokenType.eq)
61 ) {
62 this.preprocessExportAtIndex(i);
63 }
64 }
65 this.generateImportReplacements();
66 }
67
68 /**
69 * In TypeScript, import statements that only import types should be removed.
70 * This includes `import {} from 'foo';`, but not `import 'foo';`.
71 */
72 pruneTypeOnlyImports() {
73 this.nonTypeIdentifiers = _getNonTypeIdentifiers.getNonTypeIdentifiers.call(void 0, this.tokens, this.options);
74 for (const [path, importInfo] of this.importInfoByPath.entries()) {
75 if (
76 importInfo.hasBareImport ||
77 importInfo.hasStarExport ||
78 importInfo.exportStarNames.length > 0 ||
79 importInfo.namedExports.length > 0
80 ) {
81 continue;
82 }
83 const names = [
84 ...importInfo.defaultNames,
85 ...importInfo.wildcardNames,
86 ...importInfo.namedImports.map(({localName}) => localName),
87 ];
88 if (names.every((name) => this.shouldAutomaticallyElideImportedName(name))) {
89 this.importsToReplace.set(path, "");
90 }
91 }
92 }
93
94 shouldAutomaticallyElideImportedName(name) {
95 return (
96 this.isTypeScriptTransformEnabled &&
97 !this.keepUnusedImports &&
98 !this.nonTypeIdentifiers.has(name)
99 );
100 }
101
102 generateImportReplacements() {
103 for (const [path, importInfo] of this.importInfoByPath.entries()) {
104 const {
105 defaultNames,
106 wildcardNames,
107 namedImports,
108 namedExports,
109 exportStarNames,
110 hasStarExport,
111 } = importInfo;
112
113 if (
114 defaultNames.length === 0 &&
115 wildcardNames.length === 0 &&
116 namedImports.length === 0 &&
117 namedExports.length === 0 &&
118 exportStarNames.length === 0 &&
119 !hasStarExport
120 ) {
121 // Import is never used, so don't even assign a name.
122 this.importsToReplace.set(path, `require('${path}');`);
123 continue;
124 }
125
126 const primaryImportName = this.getFreeIdentifierForPath(path);
127 let secondaryImportName;
128 if (this.enableLegacyTypeScriptModuleInterop) {
129 secondaryImportName = primaryImportName;
130 } else {
131 secondaryImportName =
132 wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path);
133 }
134 let requireCode = `var ${primaryImportName} = require('${path}');`;
135 if (wildcardNames.length > 0) {
136 for (const wildcardName of wildcardNames) {
137 const moduleExpr = this.enableLegacyTypeScriptModuleInterop
138 ? primaryImportName
139 : `${this.helperManager.getHelperName("interopRequireWildcard")}(${primaryImportName})`;
140 requireCode += ` var ${wildcardName} = ${moduleExpr};`;
141 }
142 } else if (exportStarNames.length > 0 && secondaryImportName !== primaryImportName) {
143 requireCode += ` var ${secondaryImportName} = ${this.helperManager.getHelperName(
144 "interopRequireWildcard",
145 )}(${primaryImportName});`;
146 } else if (defaultNames.length > 0 && secondaryImportName !== primaryImportName) {
147 requireCode += ` var ${secondaryImportName} = ${this.helperManager.getHelperName(
148 "interopRequireDefault",
149 )}(${primaryImportName});`;
150 }
151
152 for (const {importedName, localName} of namedExports) {
153 requireCode += ` ${this.helperManager.getHelperName(
154 "createNamedExportFrom",
155 )}(${primaryImportName}, '${localName}', '${importedName}');`;
156 }
157 for (const exportStarName of exportStarNames) {
158 requireCode += ` exports.${exportStarName} = ${secondaryImportName};`;
159 }
160 if (hasStarExport) {
161 requireCode += ` ${this.helperManager.getHelperName(
162 "createStarExport",
163 )}(${primaryImportName});`;
164 }
165
166 this.importsToReplace.set(path, requireCode);
167
168 for (const defaultName of defaultNames) {
169 this.identifierReplacements.set(defaultName, `${secondaryImportName}.default`);
170 }
171 for (const {importedName, localName} of namedImports) {
172 this.identifierReplacements.set(localName, `${primaryImportName}.${importedName}`);
173 }
174 }
175 }
176
177 getFreeIdentifierForPath(path) {
178 const components = path.split("/");
179 const lastComponent = components[components.length - 1];
180 const baseName = lastComponent.replace(/\W/g, "");
181 return this.nameManager.claimFreeName(`_${baseName}`);
182 }
183
184 preprocessImportAtIndex(index) {
185 const defaultNames = [];
186 const wildcardNames = [];
187 const namedImports = [];
188
189 index++;
190 if (
191 (this.tokens.matchesContextualAtIndex(index, _keywords.ContextualKeyword._type) ||
192 this.tokens.matches1AtIndex(index, _types.TokenType._typeof)) &&
193 !this.tokens.matches1AtIndex(index + 1, _types.TokenType.comma) &&
194 !this.tokens.matchesContextualAtIndex(index + 1, _keywords.ContextualKeyword._from)
195 ) {
196 // import type declaration, so no need to process anything.
197 return;
198 }
199
200 if (this.tokens.matches1AtIndex(index, _types.TokenType.parenL)) {
201 // Dynamic import, so nothing to do
202 return;
203 }
204
205 if (this.tokens.matches1AtIndex(index, _types.TokenType.name)) {
206 defaultNames.push(this.tokens.identifierNameAtIndex(index));
207 index++;
208 if (this.tokens.matches1AtIndex(index, _types.TokenType.comma)) {
209 index++;
210 }
211 }
212
213 if (this.tokens.matches1AtIndex(index, _types.TokenType.star)) {
214 // * as
215 index += 2;
216 wildcardNames.push(this.tokens.identifierNameAtIndex(index));
217 index++;
218 }
219
220 if (this.tokens.matches1AtIndex(index, _types.TokenType.braceL)) {
221 const result = this.getNamedImports(index + 1);
222 index = result.newIndex;
223
224 for (const namedImport of result.namedImports) {
225 // Treat {default as X} as a default import to ensure usage of require interop helper
226 if (namedImport.importedName === "default") {
227 defaultNames.push(namedImport.localName);
228 } else {
229 namedImports.push(namedImport);
230 }
231 }
232 }
233
234 if (this.tokens.matchesContextualAtIndex(index, _keywords.ContextualKeyword._from)) {
235 index++;
236 }
237
238 if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
239 throw new Error("Expected string token at the end of import statement.");
240 }
241 const path = this.tokens.stringValueAtIndex(index);
242 const importInfo = this.getImportInfo(path);
243 importInfo.defaultNames.push(...defaultNames);
244 importInfo.wildcardNames.push(...wildcardNames);
245 importInfo.namedImports.push(...namedImports);
246 if (defaultNames.length === 0 && wildcardNames.length === 0 && namedImports.length === 0) {
247 importInfo.hasBareImport = true;
248 }
249 }
250
251 preprocessExportAtIndex(index) {
252 if (
253 this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType._var) ||
254 this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType._let) ||
255 this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType._const)
256 ) {
257 this.preprocessVarExportAtIndex(index);
258 } else if (
259 this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType._function) ||
260 this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType._class)
261 ) {
262 const exportName = this.tokens.identifierNameAtIndex(index + 2);
263 this.addExportBinding(exportName, exportName);
264 } else if (this.tokens.matches3AtIndex(index, _types.TokenType._export, _types.TokenType.name, _types.TokenType._function)) {
265 const exportName = this.tokens.identifierNameAtIndex(index + 3);
266 this.addExportBinding(exportName, exportName);
267 } else if (this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType.braceL)) {
268 this.preprocessNamedExportAtIndex(index);
269 } else if (this.tokens.matches2AtIndex(index, _types.TokenType._export, _types.TokenType.star)) {
270 this.preprocessExportStarAtIndex(index);
271 }
272 }
273
274 preprocessVarExportAtIndex(index) {
275 let depth = 0;
276 // Handle cases like `export let {x} = y;`, starting at the open-brace in that case.
277 for (let i = index + 2; ; i++) {
278 if (
279 this.tokens.matches1AtIndex(i, _types.TokenType.braceL) ||
280 this.tokens.matches1AtIndex(i, _types.TokenType.dollarBraceL) ||
281 this.tokens.matches1AtIndex(i, _types.TokenType.bracketL)
282 ) {
283 depth++;
284 } else if (
285 this.tokens.matches1AtIndex(i, _types.TokenType.braceR) ||
286 this.tokens.matches1AtIndex(i, _types.TokenType.bracketR)
287 ) {
288 depth--;
289 } else if (depth === 0 && !this.tokens.matches1AtIndex(i, _types.TokenType.name)) {
290 break;
291 } else if (this.tokens.matches1AtIndex(1, _types.TokenType.eq)) {
292 const endIndex = this.tokens.currentToken().rhsEndIndex;
293 if (endIndex == null) {
294 throw new Error("Expected = token with an end index.");
295 }
296 i = endIndex - 1;
297 } else {
298 const token = this.tokens.tokens[i];
299 if (_tokenizer.isDeclaration.call(void 0, token)) {
300 const exportName = this.tokens.identifierNameAtIndex(i);
301 this.identifierReplacements.set(exportName, `exports.${exportName}`);
302 }
303 }
304 }
305 }
306
307 /**
308 * Walk this export statement just in case it's an export...from statement.
309 * If it is, combine it into the import info for that path. Otherwise, just
310 * bail out; it'll be handled later.
311 */
312 preprocessNamedExportAtIndex(index) {
313 // export {
314 index += 2;
315 const {newIndex, namedImports} = this.getNamedImports(index);
316 index = newIndex;
317
318 if (this.tokens.matchesContextualAtIndex(index, _keywords.ContextualKeyword._from)) {
319 index++;
320 } else {
321 // Reinterpret "a as b" to be local/exported rather than imported/local.
322 for (const {importedName: localName, localName: exportedName} of namedImports) {
323 this.addExportBinding(localName, exportedName);
324 }
325 return;
326 }
327
328 if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
329 throw new Error("Expected string token at the end of import statement.");
330 }
331 const path = this.tokens.stringValueAtIndex(index);
332 const importInfo = this.getImportInfo(path);
333 importInfo.namedExports.push(...namedImports);
334 }
335
336 preprocessExportStarAtIndex(index) {
337 let exportedName = null;
338 if (this.tokens.matches3AtIndex(index, _types.TokenType._export, _types.TokenType.star, _types.TokenType._as)) {
339 // export * as
340 index += 3;
341 exportedName = this.tokens.identifierNameAtIndex(index);
342 // foo from
343 index += 2;
344 } else {
345 // export * from
346 index += 3;
347 }
348 if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
349 throw new Error("Expected string token at the end of star export statement.");
350 }
351 const path = this.tokens.stringValueAtIndex(index);
352 const importInfo = this.getImportInfo(path);
353 if (exportedName !== null) {
354 importInfo.exportStarNames.push(exportedName);
355 } else {
356 importInfo.hasStarExport = true;
357 }
358 }
359
360 getNamedImports(index) {
361 const namedImports = [];
362 while (true) {
363 if (this.tokens.matches1AtIndex(index, _types.TokenType.braceR)) {
364 index++;
365 break;
366 }
367
368 const specifierInfo = _getImportExportSpecifierInfo2.default.call(void 0, this.tokens, index);
369 index = specifierInfo.endIndex;
370 if (!specifierInfo.isType) {
371 namedImports.push({
372 importedName: specifierInfo.leftName,
373 localName: specifierInfo.rightName,
374 });
375 }
376
377 if (this.tokens.matches2AtIndex(index, _types.TokenType.comma, _types.TokenType.braceR)) {
378 index += 2;
379 break;
380 } else if (this.tokens.matches1AtIndex(index, _types.TokenType.braceR)) {
381 index++;
382 break;
383 } else if (this.tokens.matches1AtIndex(index, _types.TokenType.comma)) {
384 index++;
385 } else {
386 throw new Error(`Unexpected token: ${JSON.stringify(this.tokens.tokens[index])}`);
387 }
388 }
389 return {newIndex: index, namedImports};
390 }
391
392 /**
393 * Get a mutable import info object for this path, creating one if it doesn't
394 * exist yet.
395 */
396 getImportInfo(path) {
397 const existingInfo = this.importInfoByPath.get(path);
398 if (existingInfo) {
399 return existingInfo;
400 }
401 const newInfo = {
402 defaultNames: [],
403 wildcardNames: [],
404 namedImports: [],
405 namedExports: [],
406 hasBareImport: false,
407 exportStarNames: [],
408 hasStarExport: false,
409 };
410 this.importInfoByPath.set(path, newInfo);
411 return newInfo;
412 }
413
414 addExportBinding(localName, exportedName) {
415 if (!this.exportBindingsByLocalName.has(localName)) {
416 this.exportBindingsByLocalName.set(localName, []);
417 }
418 this.exportBindingsByLocalName.get(localName).push(exportedName);
419 }
420
421 /**
422 * Return the code to use for the import for this path, or the empty string if
423 * the code has already been "claimed" by a previous import.
424 */
425 claimImportCode(importPath) {
426 const result = this.importsToReplace.get(importPath);
427 this.importsToReplace.set(importPath, "");
428 return result || "";
429 }
430
431 getIdentifierReplacement(identifierName) {
432 return this.identifierReplacements.get(identifierName) || null;
433 }
434
435 /**
436 * Return a string like `exports.foo = exports.bar`.
437 */
438 resolveExportBinding(assignedName) {
439 const exportedNames = this.exportBindingsByLocalName.get(assignedName);
440 if (!exportedNames || exportedNames.length === 0) {
441 return null;
442 }
443 return exportedNames.map((exportedName) => `exports.${exportedName}`).join(" = ");
444 }
445
446 /**
447 * Return all imported/exported names where we might be interested in whether usages of those
448 * names are shadowed.
449 */
450 getGlobalNames() {
451 return new Set([
452 ...this.identifierReplacements.keys(),
453 ...this.exportBindingsByLocalName.keys(),
454 ]);
455 }
456} exports.default = CJSImportProcessor;
Note: See TracBrowser for help on using the repository browser.