UNPKG

13.2 kBJavaScriptView Raw
1"use strict";
2
3Object.defineProperty(exports, "__esModule", {
4 value: true
5});
6exports.default = void 0;
7
8var _helperPluginUtils = require("@babel/helper-plugin-utils");
9
10var _pluginSyntaxTypescript = _interopRequireDefault(require("@babel/plugin-syntax-typescript"));
11
12var _core = require("@babel/core");
13
14var _helperCreateClassFeaturesPlugin = require("@babel/helper-create-class-features-plugin");
15
16var _enum = _interopRequireDefault(require("./enum"));
17
18var _namespace = _interopRequireDefault(require("./namespace"));
19
20function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
22function isInType(path) {
23 switch (path.parent.type) {
24 case "TSTypeReference":
25 case "TSQualifiedName":
26 case "TSExpressionWithTypeArguments":
27 case "TSTypeQuery":
28 return true;
29
30 case "ExportSpecifier":
31 return path.parentPath.parent.exportKind === "type";
32
33 default:
34 return false;
35 }
36}
37
38const PARSED_PARAMS = new WeakSet();
39const GLOBAL_TYPES = new WeakMap();
40
41function isGlobalType(path, name) {
42 const program = path.find(path => path.isProgram()).node;
43 if (path.scope.hasOwnBinding(name)) return false;
44 if (GLOBAL_TYPES.get(program).has(name)) return true;
45 console.warn(`The exported identifier "${name}" is not declared in Babel's scope tracker\n` + `as a JavaScript value binding, and "@babel/plugin-transform-typescript"\n` + `never encountered it as a TypeScript type declaration.\n` + `It will be treated as a JavaScript value.\n\n` + `This problem is likely caused by another plugin injecting\n` + `"${name}" without registering it in the scope tracker. If you are the author\n` + ` of that plugin, please use "scope.registerDeclaration(declarationPath)".`);
46 return false;
47}
48
49function registerGlobalType(programScope, name) {
50 GLOBAL_TYPES.get(programScope.path.node).add(name);
51}
52
53var _default = (0, _helperPluginUtils.declare)((api, opts) => {
54 api.assertVersion(7);
55 const JSX_PRAGMA_REGEX = /\*?\s*@jsx((?:Frag)?)\s+([^\s]+)/;
56 const {
57 jsxPragma = "React.createElement",
58 jsxPragmaFrag = "React.Fragment",
59 allowNamespaces = false,
60 onlyRemoveTypeImports = false
61 } = opts;
62 {
63 var {
64 allowDeclareFields = false
65 } = opts;
66 }
67 const classMemberVisitors = {
68 field(path) {
69 const {
70 node
71 } = path;
72 {
73 if (!allowDeclareFields && node.declare) {
74 throw path.buildCodeFrameError(`The 'declare' modifier is only allowed when the 'allowDeclareFields' option of ` + `@babel/plugin-transform-typescript or @babel/preset-typescript is enabled.`);
75 }
76 }
77
78 if (node.declare) {
79 if (node.value) {
80 throw path.buildCodeFrameError(`Fields with the 'declare' modifier cannot be initialized here, but only in the constructor`);
81 }
82
83 if (!node.decorators) {
84 path.remove();
85 }
86 } else if (node.definite) {
87 if (node.value) {
88 throw path.buildCodeFrameError(`Definitely assigned fields cannot be initialized here, but only in the constructor`);
89 }
90
91 {
92 if (!allowDeclareFields && !node.decorators) {
93 path.remove();
94 }
95 }
96 } else {
97 if (!allowDeclareFields && !node.value && !node.decorators && !_core.types.isClassPrivateProperty(node)) {
98 path.remove();
99 }
100 }
101
102 if (node.accessibility) node.accessibility = null;
103 if (node.abstract) node.abstract = null;
104 if (node.readonly) node.readonly = null;
105 if (node.optional) node.optional = null;
106 if (node.typeAnnotation) node.typeAnnotation = null;
107 if (node.definite) node.definite = null;
108 if (node.declare) node.declare = null;
109 },
110
111 method({
112 node
113 }) {
114 if (node.accessibility) node.accessibility = null;
115 if (node.abstract) node.abstract = null;
116 if (node.optional) node.optional = null;
117 },
118
119 constructor(path, classPath) {
120 if (path.node.accessibility) path.node.accessibility = null;
121 const parameterProperties = [];
122
123 for (const param of path.node.params) {
124 if (param.type === "TSParameterProperty" && !PARSED_PARAMS.has(param.parameter)) {
125 PARSED_PARAMS.add(param.parameter);
126 parameterProperties.push(param.parameter);
127 }
128 }
129
130 if (parameterProperties.length) {
131 const assigns = parameterProperties.map(p => {
132 let id;
133
134 if (_core.types.isIdentifier(p)) {
135 id = p;
136 } else if (_core.types.isAssignmentPattern(p) && _core.types.isIdentifier(p.left)) {
137 id = p.left;
138 } else {
139 throw path.buildCodeFrameError("Parameter properties can not be destructuring patterns.");
140 }
141
142 return _core.template.statement.ast`
143 this.${_core.types.cloneNode(id)} = ${_core.types.cloneNode(id)}`;
144 });
145 (0, _helperCreateClassFeaturesPlugin.injectInitialization)(classPath, path, assigns);
146 }
147 }
148
149 };
150 return {
151 name: "transform-typescript",
152 inherits: _pluginSyntaxTypescript.default,
153 visitor: {
154 Pattern: visitPattern,
155 Identifier: visitPattern,
156 RestElement: visitPattern,
157
158 Program(path, state) {
159 const {
160 file
161 } = state;
162 let fileJsxPragma = null;
163 let fileJsxPragmaFrag = null;
164
165 if (!GLOBAL_TYPES.has(path.node)) {
166 GLOBAL_TYPES.set(path.node, new Set());
167 }
168
169 if (file.ast.comments) {
170 for (const comment of file.ast.comments) {
171 const jsxMatches = JSX_PRAGMA_REGEX.exec(comment.value);
172
173 if (jsxMatches) {
174 if (jsxMatches[1]) {
175 fileJsxPragmaFrag = jsxMatches[2];
176 } else {
177 fileJsxPragma = jsxMatches[2];
178 }
179 }
180 }
181 }
182
183 let pragmaImportName = fileJsxPragma || jsxPragma;
184
185 if (pragmaImportName) {
186 [pragmaImportName] = pragmaImportName.split(".");
187 }
188
189 let pragmaFragImportName = fileJsxPragmaFrag || jsxPragmaFrag;
190
191 if (pragmaFragImportName) {
192 [pragmaFragImportName] = pragmaFragImportName.split(".");
193 }
194
195 for (let stmt of path.get("body")) {
196 if (_core.types.isImportDeclaration(stmt)) {
197 if (stmt.node.importKind === "type") {
198 stmt.remove();
199 continue;
200 }
201
202 if (!onlyRemoveTypeImports) {
203 if (stmt.node.specifiers.length === 0) {
204 continue;
205 }
206
207 let allElided = true;
208 const importsToRemove = [];
209
210 for (const specifier of stmt.node.specifiers) {
211 const binding = stmt.scope.getBinding(specifier.local.name);
212
213 if (binding && isImportTypeOnly({
214 binding,
215 programPath: path,
216 pragmaImportName,
217 pragmaFragImportName
218 })) {
219 importsToRemove.push(binding.path);
220 } else {
221 allElided = false;
222 }
223 }
224
225 if (allElided) {
226 stmt.remove();
227 } else {
228 for (const importPath of importsToRemove) {
229 importPath.remove();
230 }
231 }
232 }
233
234 continue;
235 }
236
237 if (stmt.isExportDeclaration()) {
238 stmt = stmt.get("declaration");
239 }
240
241 if (stmt.isVariableDeclaration({
242 declare: true
243 })) {
244 for (const name of Object.keys(stmt.getBindingIdentifiers())) {
245 registerGlobalType(path.scope, name);
246 }
247 } else if (stmt.isTSTypeAliasDeclaration() || stmt.isTSDeclareFunction() || stmt.isTSInterfaceDeclaration() || stmt.isClassDeclaration({
248 declare: true
249 }) || stmt.isTSEnumDeclaration({
250 declare: true
251 }) || stmt.isTSModuleDeclaration({
252 declare: true
253 }) && stmt.get("id").isIdentifier()) {
254 registerGlobalType(path.scope, stmt.node.id.name);
255 }
256 }
257 },
258
259 ExportNamedDeclaration(path) {
260 if (path.node.exportKind === "type") {
261 path.remove();
262 return;
263 }
264
265 if (!path.node.source && path.node.specifiers.length > 0 && path.node.specifiers.every(({
266 local
267 }) => isGlobalType(path, local.name))) {
268 path.remove();
269 }
270 },
271
272 ExportSpecifier(path) {
273 if (!path.parent.source && isGlobalType(path, path.node.local.name)) {
274 path.remove();
275 }
276 },
277
278 ExportDefaultDeclaration(path) {
279 if (_core.types.isIdentifier(path.node.declaration) && isGlobalType(path, path.node.declaration.name)) {
280 path.remove();
281 }
282 },
283
284 TSDeclareFunction(path) {
285 path.remove();
286 },
287
288 TSDeclareMethod(path) {
289 path.remove();
290 },
291
292 VariableDeclaration(path) {
293 if (path.node.declare) {
294 path.remove();
295 }
296 },
297
298 VariableDeclarator({
299 node
300 }) {
301 if (node.definite) node.definite = null;
302 },
303
304 TSIndexSignature(path) {
305 path.remove();
306 },
307
308 ClassDeclaration(path) {
309 const {
310 node
311 } = path;
312
313 if (node.declare) {
314 path.remove();
315 return;
316 }
317 },
318
319 Class(path) {
320 const {
321 node
322 } = path;
323 if (node.typeParameters) node.typeParameters = null;
324 if (node.superTypeParameters) node.superTypeParameters = null;
325 if (node.implements) node.implements = null;
326 if (node.abstract) node.abstract = null;
327 path.get("body.body").forEach(child => {
328 if (child.isClassMethod() || child.isClassPrivateMethod()) {
329 if (child.node.kind === "constructor") {
330 classMemberVisitors.constructor(child, path);
331 } else {
332 classMemberVisitors.method(child, path);
333 }
334 } else if (child.isClassProperty() || child.isClassPrivateProperty()) {
335 classMemberVisitors.field(child, path);
336 }
337 });
338 },
339
340 Function({
341 node
342 }) {
343 if (node.typeParameters) node.typeParameters = null;
344 if (node.returnType) node.returnType = null;
345 const p0 = node.params[0];
346
347 if (p0 && _core.types.isIdentifier(p0) && p0.name === "this") {
348 node.params.shift();
349 }
350
351 node.params = node.params.map(p => {
352 return p.type === "TSParameterProperty" ? p.parameter : p;
353 });
354 },
355
356 TSModuleDeclaration(path) {
357 (0, _namespace.default)(path, _core.types, allowNamespaces);
358 },
359
360 TSInterfaceDeclaration(path) {
361 path.remove();
362 },
363
364 TSTypeAliasDeclaration(path) {
365 path.remove();
366 },
367
368 TSEnumDeclaration(path) {
369 (0, _enum.default)(path, _core.types);
370 },
371
372 TSImportEqualsDeclaration(path) {
373 throw path.buildCodeFrameError("`import =` is not supported by @babel/plugin-transform-typescript\n" + "Please consider using " + "`import <moduleName> from '<moduleName>';` alongside " + "Typescript's --allowSyntheticDefaultImports option.");
374 },
375
376 TSExportAssignment(path) {
377 throw path.buildCodeFrameError("`export =` is not supported by @babel/plugin-transform-typescript\n" + "Please consider using `export <value>;`.");
378 },
379
380 TSTypeAssertion(path) {
381 path.replaceWith(path.node.expression);
382 },
383
384 TSAsExpression(path) {
385 let {
386 node
387 } = path;
388
389 do {
390 node = node.expression;
391 } while (_core.types.isTSAsExpression(node));
392
393 path.replaceWith(node);
394 },
395
396 TSNonNullExpression(path) {
397 path.replaceWith(path.node.expression);
398 },
399
400 CallExpression(path) {
401 path.node.typeParameters = null;
402 },
403
404 OptionalCallExpression(path) {
405 path.node.typeParameters = null;
406 },
407
408 NewExpression(path) {
409 path.node.typeParameters = null;
410 },
411
412 JSXOpeningElement(path) {
413 path.node.typeParameters = null;
414 },
415
416 TaggedTemplateExpression(path) {
417 path.node.typeParameters = null;
418 }
419
420 }
421 };
422
423 function visitPattern({
424 node
425 }) {
426 if (node.typeAnnotation) node.typeAnnotation = null;
427 if (_core.types.isIdentifier(node) && node.optional) node.optional = null;
428 }
429
430 function isImportTypeOnly({
431 binding,
432 programPath,
433 pragmaImportName,
434 pragmaFragImportName
435 }) {
436 for (const path of binding.referencePaths) {
437 if (!isInType(path)) {
438 return false;
439 }
440 }
441
442 if (binding.identifier.name !== pragmaImportName && binding.identifier.name !== pragmaFragImportName) {
443 return true;
444 }
445
446 let sourceFileHasJsx = false;
447 programPath.traverse({
448 "JSXElement|JSXFragment"(path) {
449 sourceFileHasJsx = true;
450 path.stop();
451 }
452
453 });
454 return !sourceFileHasJsx;
455 }
456});
457
458exports.default = _default;
\No newline at end of file