UNPKG

8.82 kBJavaScriptView Raw
1"use strict"; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }Object.defineProperty(exports, "__esModule", {value: true});
2
3var _keywords = require('../parser/tokenizer/keywords');
4var _types = require('../parser/tokenizer/types');
5
6var _getNonTypeIdentifiers = require('../util/getNonTypeIdentifiers');
7
8var _Transformer = require('./Transformer'); var _Transformer2 = _interopRequireDefault(_Transformer);
9
10/**
11 * Class for editing import statements when we are keeping the code as ESM. We still need to remove
12 * type-only imports in TypeScript and Flow.
13 */
14 class ESMImportTransformer extends _Transformer2.default {
15
16
17 constructor(
18 tokens,
19 nameManager,
20 reactHotLoaderTransformer,
21 isTypeScriptTransformEnabled,
22 options,
23 ) {
24 super();this.tokens = tokens;this.nameManager = nameManager;this.reactHotLoaderTransformer = reactHotLoaderTransformer;this.isTypeScriptTransformEnabled = isTypeScriptTransformEnabled;;
25 this.nonTypeIdentifiers = isTypeScriptTransformEnabled
26 ? _getNonTypeIdentifiers.getNonTypeIdentifiers.call(void 0, tokens, options)
27 : new Set();
28 }
29
30 process() {
31 // TypeScript `import foo = require('foo');` should always just be translated to plain require.
32 if (this.tokens.matches3(_types.TokenType._import, _types.TokenType.name, _types.TokenType.eq)) {
33 this.tokens.replaceToken("const");
34 return true;
35 }
36 if (this.tokens.matches2(_types.TokenType._export, _types.TokenType.eq)) {
37 this.tokens.replaceToken("module.exports");
38 return true;
39 }
40 if (this.tokens.matches1(_types.TokenType._import)) {
41 return this.processImport();
42 }
43 if (this.tokens.matches2(_types.TokenType._export, _types.TokenType._default)) {
44 return this.processExportDefault();
45 }
46 return false;
47 }
48
49 processImport() {
50 if (this.tokens.matches2(_types.TokenType._import, _types.TokenType.parenL)) {
51 // Dynamic imports don't need to be transformed.
52 return false;
53 }
54
55 const snapshot = this.tokens.snapshot();
56 const allImportsRemoved = this.removeTypeBindings();
57 if (allImportsRemoved) {
58 this.tokens.restoreToSnapshot(snapshot);
59 while (!this.tokens.matches1(_types.TokenType.string)) {
60 this.tokens.removeToken();
61 }
62 this.tokens.removeToken();
63 if (this.tokens.matches1(_types.TokenType.semi)) {
64 this.tokens.removeToken();
65 }
66 }
67 return true;
68 }
69
70 /**
71 * Remove type bindings from this import, leaving the rest of the import intact.
72 *
73 * Return true if this import was ONLY types, and thus is eligible for removal. This will bail out
74 * of the replacement operation, so we can return early here.
75 */
76 removeTypeBindings() {
77 this.tokens.copyExpectedToken(_types.TokenType._import);
78 if (
79 this.tokens.matchesContextual(_keywords.ContextualKeyword._type) &&
80 !this.tokens.matches1AtIndex(this.tokens.currentIndex() + 1, _types.TokenType.comma) &&
81 !this.tokens.matchesContextualAtIndex(this.tokens.currentIndex() + 1, _keywords.ContextualKeyword._from)
82 ) {
83 // This is an "import type" statement, so exit early.
84 return true;
85 }
86
87 if (this.tokens.matches1(_types.TokenType.string)) {
88 // This is a bare import, so we should proceed with the import.
89 this.tokens.copyToken();
90 return false;
91 }
92
93 let foundNonTypeImport = false;
94
95 if (this.tokens.matches1(_types.TokenType.name)) {
96 if (this.isTypeName(this.tokens.identifierName())) {
97 this.tokens.removeToken();
98 if (this.tokens.matches1(_types.TokenType.comma)) {
99 this.tokens.removeToken();
100 }
101 } else {
102 foundNonTypeImport = true;
103 this.tokens.copyToken();
104 if (this.tokens.matches1(_types.TokenType.comma)) {
105 this.tokens.copyToken();
106 }
107 }
108 }
109
110 if (this.tokens.matches1(_types.TokenType.star)) {
111 if (this.isTypeName(this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 2))) {
112 this.tokens.removeToken();
113 this.tokens.removeToken();
114 this.tokens.removeToken();
115 } else {
116 foundNonTypeImport = true;
117 this.tokens.copyExpectedToken(_types.TokenType.star);
118 this.tokens.copyExpectedToken(_types.TokenType.name);
119 this.tokens.copyExpectedToken(_types.TokenType.name);
120 }
121 } else if (this.tokens.matches1(_types.TokenType.braceL)) {
122 this.tokens.copyToken();
123 while (!this.tokens.matches1(_types.TokenType.braceR)) {
124 if (
125 this.tokens.matches3(_types.TokenType.name, _types.TokenType.name, _types.TokenType.comma) ||
126 this.tokens.matches3(_types.TokenType.name, _types.TokenType.name, _types.TokenType.braceR)
127 ) {
128 // type foo
129 this.tokens.removeToken();
130 this.tokens.removeToken();
131 if (this.tokens.matches1(_types.TokenType.comma)) {
132 this.tokens.removeToken();
133 }
134 } else if (
135 this.tokens.matches5(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.comma) ||
136 this.tokens.matches5(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.braceR)
137 ) {
138 // type foo as bar
139 this.tokens.removeToken();
140 this.tokens.removeToken();
141 this.tokens.removeToken();
142 this.tokens.removeToken();
143 if (this.tokens.matches1(_types.TokenType.comma)) {
144 this.tokens.removeToken();
145 }
146 } else if (
147 this.tokens.matches2(_types.TokenType.name, _types.TokenType.comma) ||
148 this.tokens.matches2(_types.TokenType.name, _types.TokenType.braceR)
149 ) {
150 // foo
151 if (this.isTypeName(this.tokens.identifierName())) {
152 this.tokens.removeToken();
153 if (this.tokens.matches1(_types.TokenType.comma)) {
154 this.tokens.removeToken();
155 }
156 } else {
157 foundNonTypeImport = true;
158 this.tokens.copyToken();
159 if (this.tokens.matches1(_types.TokenType.comma)) {
160 this.tokens.copyToken();
161 }
162 }
163 } else if (
164 this.tokens.matches4(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.comma) ||
165 this.tokens.matches4(_types.TokenType.name, _types.TokenType.name, _types.TokenType.name, _types.TokenType.braceR)
166 ) {
167 // foo as bar
168 if (this.isTypeName(this.tokens.identifierNameAtIndex(this.tokens.currentIndex() + 2))) {
169 this.tokens.removeToken();
170 this.tokens.removeToken();
171 this.tokens.removeToken();
172 if (this.tokens.matches1(_types.TokenType.comma)) {
173 this.tokens.removeToken();
174 }
175 } else {
176 foundNonTypeImport = true;
177 this.tokens.copyToken();
178 this.tokens.copyToken();
179 this.tokens.copyToken();
180 if (this.tokens.matches1(_types.TokenType.comma)) {
181 this.tokens.copyToken();
182 }
183 }
184 } else {
185 throw new Error("Unexpected import form.");
186 }
187 }
188 this.tokens.copyExpectedToken(_types.TokenType.braceR);
189 }
190
191 return !foundNonTypeImport;
192 }
193
194 isTypeName(name) {
195 return this.isTypeScriptTransformEnabled && !this.nonTypeIdentifiers.has(name);
196 }
197
198 processExportDefault() {
199 const alreadyHasName =
200 this.tokens.matches4(_types.TokenType._export, _types.TokenType._default, _types.TokenType._function, _types.TokenType.name) ||
201 // export default async function
202 this.tokens.matches5(_types.TokenType._export, _types.TokenType._default, _types.TokenType.name, _types.TokenType._function, _types.TokenType.name) ||
203 this.tokens.matches4(_types.TokenType._export, _types.TokenType._default, _types.TokenType._class, _types.TokenType.name) ||
204 this.tokens.matches5(_types.TokenType._export, _types.TokenType._default, _types.TokenType._abstract, _types.TokenType._class, _types.TokenType.name);
205
206 if (!alreadyHasName && this.reactHotLoaderTransformer) {
207 // This is a plain "export default E" statement and we need to assign E to a variable.
208 // Change "export default E" to "let _default; export default _default = E"
209 const defaultVarName = this.nameManager.claimFreeName("_default");
210 this.tokens.replaceToken(`let ${defaultVarName}; export`);
211 this.tokens.copyToken();
212 this.tokens.appendCode(` ${defaultVarName} =`);
213 this.reactHotLoaderTransformer.setExtractedDefaultExportName(defaultVarName);
214 return true;
215 }
216 return false;
217 }
218} exports.default = ESMImportTransformer;