UNPKG

13.4 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(path) {
341 const {
342 node,
343 scope
344 } = path;
345 if (node.typeParameters) node.typeParameters = null;
346 if (node.returnType) node.returnType = null;
347 const params = node.params;
348
349 if (params.length > 0 && _core.types.isIdentifier(params[0], {
350 name: "this"
351 })) {
352 params.shift();
353 }
354
355 const paramsPath = path.get("params");
356
357 for (const p of paramsPath) {
358 if (p.type === "TSParameterProperty") {
359 p.replaceWith(p.get("parameter"));
360 scope.registerBinding("param", p);
361 }
362 }
363 },
364
365 TSModuleDeclaration(path) {
366 (0, _namespace.default)(path, _core.types, allowNamespaces);
367 },
368
369 TSInterfaceDeclaration(path) {
370 path.remove();
371 },
372
373 TSTypeAliasDeclaration(path) {
374 path.remove();
375 },
376
377 TSEnumDeclaration(path) {
378 (0, _enum.default)(path, _core.types);
379 },
380
381 TSImportEqualsDeclaration(path) {
382 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.");
383 },
384
385 TSExportAssignment(path) {
386 throw path.buildCodeFrameError("`export =` is not supported by @babel/plugin-transform-typescript\n" + "Please consider using `export <value>;`.");
387 },
388
389 TSTypeAssertion(path) {
390 path.replaceWith(path.node.expression);
391 },
392
393 TSAsExpression(path) {
394 let {
395 node
396 } = path;
397
398 do {
399 node = node.expression;
400 } while (_core.types.isTSAsExpression(node));
401
402 path.replaceWith(node);
403 },
404
405 TSNonNullExpression(path) {
406 path.replaceWith(path.node.expression);
407 },
408
409 CallExpression(path) {
410 path.node.typeParameters = null;
411 },
412
413 OptionalCallExpression(path) {
414 path.node.typeParameters = null;
415 },
416
417 NewExpression(path) {
418 path.node.typeParameters = null;
419 },
420
421 JSXOpeningElement(path) {
422 path.node.typeParameters = null;
423 },
424
425 TaggedTemplateExpression(path) {
426 path.node.typeParameters = null;
427 }
428
429 }
430 };
431
432 function visitPattern({
433 node
434 }) {
435 if (node.typeAnnotation) node.typeAnnotation = null;
436 if (_core.types.isIdentifier(node) && node.optional) node.optional = null;
437 }
438
439 function isImportTypeOnly({
440 binding,
441 programPath,
442 pragmaImportName,
443 pragmaFragImportName
444 }) {
445 for (const path of binding.referencePaths) {
446 if (!isInType(path)) {
447 return false;
448 }
449 }
450
451 if (binding.identifier.name !== pragmaImportName && binding.identifier.name !== pragmaFragImportName) {
452 return true;
453 }
454
455 let sourceFileHasJsx = false;
456 programPath.traverse({
457 "JSXElement|JSXFragment"(path) {
458 sourceFileHasJsx = true;
459 path.stop();
460 }
461
462 });
463 return !sourceFileHasJsx;
464 }
465});
466
467exports.default = _default;
\No newline at end of file