UNPKG

@xtrek/ts-migrate-plugins

Version:

Set of codemods, which are doing transformation of js/jsx to ts/tsx

213 lines 10.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const jscodeshift_1 = __importDefault(require("jscodeshift")); const typescript_1 = __importDefault(require("typescript")); const type_guards_1 = require("../utils/type-guards"); const validateOptions_1 = require("../utils/validateOptions"); const explicitAnyPlugin = { name: 'explicit-any', run({ options, fileName, text, getLanguageService }) { const semanticDiagnostics = getLanguageService().getSemanticDiagnostics(fileName); const diagnostics = semanticDiagnostics .filter(type_guards_1.isDiagnosticWithLinePosition) .filter((d) => d.category === typescript_1.default.DiagnosticCategory.Error); return withExplicitAny(text, diagnostics, options.anyAlias); }, validate: validateOptions_1.validateAnyAliasOptions, }; exports.default = explicitAnyPlugin; const j = jscodeshift_1.default.withParser('tsx'); function withExplicitAny(text, diagnostics, anyAlias) { const root = j(text); const anyType = anyAlias != null ? j.tsTypeReference(j.identifier(anyAlias)) : j.tsAnyKeyword(); const typeAnnotation = j.tsTypeAnnotation(anyType); replaceTS2683(root, diagnostics.filter((diagnostic) => diagnostic.code === 2683), typeAnnotation); replaceTS7006AndTS7008(root, diagnostics.filter((diagnostic) => diagnostic.code === 7006 || diagnostic.code === 7008), typeAnnotation); replaceTS7019(root, diagnostics.filter((diagnostic) => diagnostic.code === 7019), j.tsTypeAnnotation(j.tsArrayType(anyType))); replaceTS7031(root, diagnostics.filter((diagnostic) => diagnostic.code === 7031), typeAnnotation); replaceTS7034(root, diagnostics.filter((diagnostic) => diagnostic.code === 7034), typeAnnotation); replaceTS2459(root, diagnostics.filter((diagnostic) => diagnostic.code === 2459), typeAnnotation); replaceTS2525(root, diagnostics.filter((diagnostic) => diagnostic.code === 2525), typeAnnotation); return root.toSource(); } // TS2683: "'this' implicitly has type 'any' because it does not have a type annotation." function replaceTS2683(root, diagnostics, typeAnnotation) { const annotated = new Set(); diagnostics.forEach((diagnostic) => { root .find(j.ThisExpression, (node) => node.start === diagnostic.start && node.end === diagnostic.start + diagnostic.length) .forEach((path) => { let newNode = path.parentPath; // Find the containing function declaration/expression. while (newNode.parentPath && !j.FunctionDeclaration.check(newNode.node) && !j.FunctionExpression.check(newNode.node)) { newNode = newNode.parentPath; } // Add annotation only if we haven't already added one to this function. if (!annotated.has(newNode)) { newNode.get('params').unshift(j.identifier.from({ name: 'this', typeAnnotation })); annotated.add(newNode); } }); }); } // TS7006: "Parameter '{0}' implicitly has an '{1}' type." // TS7008: "Member '{0}' implicitly has an '{1}' type." function replaceTS7006AndTS7008(root, diagnostics, typeAnnotation) { diagnostics.forEach((diagnostic) => { root .find(j.Identifier, (node) => node.start === diagnostic.start && node.end === diagnostic.start + diagnostic.length && node.typeAnnotation == null) .forEach((path) => { let replaceArrow = false; const parentNode = path.parent.node; if (j.ArrowFunctionExpression.check(parentNode)) { // Special casing to work around jscodeshift bugs. let { body, params } = parentNode; // Object literals used as arrow function returns do not have // parentheses added. // https://github.com/benjamn/recast/issues/743 if (j.ObjectExpression.check(body)) { replaceArrow = true; body = j.objectExpression.from(Object.assign({}, body)); } // Make sure to add parentheses around single parameters. if (params.length === 1) { replaceArrow = true; params = [ j.identifier.from(Object.assign(Object.assign({}, parentNode.params[0]), { typeAnnotation })), ]; } if (replaceArrow) { path.parent.replace(j.arrowFunctionExpression.from(Object.assign(Object.assign({}, parentNode), { params, body }))); } } if (!replaceArrow) { path.get('typeAnnotation').replace(typeAnnotation); } }); }); } // TS7019: "Rest parameter '{0}' implicitly has an 'any[]' type." function replaceTS7019(root, diagnostics, typeAnnotation) { diagnostics.forEach((diagnostic) => { root .find(j.RestElement, (node) => node.start === diagnostic.start && node.end === diagnostic.start + diagnostic.length && node.typeAnnotation == null) .forEach((path) => { path.get('typeAnnotation').replace(typeAnnotation); }); }); } // TS7031: "Binding element '{0}' implicitly has an '{1}' type." function replaceTS7031(root, diagnostics, typeAnnotation) { const getParentObjectPattern = (path) => { let res = path; while (res.parent && j.ObjectProperty.check(res.parent.value) && res.parent.parent && j.ObjectPattern.check(res.parent.parent.value)) { res = res.parent.parent; } return res; }; diagnostics.forEach((diagnostic) => { root.find(j.ObjectPattern).forEach((path) => { if (path.node.typeAnnotation == null) { const propertyIndex = path.node.properties.findIndex((property) => property.start === diagnostic.start && property.end === diagnostic.start + diagnostic.length && j.ObjectProperty.check(property)); if (propertyIndex !== -1) { const objectPattern = getParentObjectPattern(path); if (objectPattern.node.typeAnnotation == null) { objectPattern.get('typeAnnotation').replace(typeAnnotation); } } } }); }); } // TS7034: Variable '{0}' implicitly has type '{1}' in some locations where its type cannot be determined. function replaceTS7034(root, diagnostics, typeAnnotation) { diagnostics.forEach((diagnostic) => { root .find(j.Identifier) .filter((path) => path.node.start === diagnostic.start && path.node.end === diagnostic.start + diagnostic.length && path.node.typeAnnotation == null) .forEach((path) => { if (!j.ImportSpecifier.check(path.parent.node) && !j.ImportDefaultSpecifier.check(path.parent.node) && !j.ImportNamespaceSpecifier.check(path.parent.node)) { path.get('typeAnnotation').replace(typeAnnotation); } }); }); } // TS2459: Type '{0}' has no property '{1}' and no string index signature. function replaceTS2459(root, diagnostics, typeAnnotation) { diagnostics.forEach((diagnostic) => { root .find(j.Identifier) .filter((path) => path.node.start === diagnostic.start && path.node.end === diagnostic.start + diagnostic.length && path.node.typeAnnotation == null) .forEach((path) => { let newNode = path.parentPath; // The error will only provide the location of the left hand side identifier // so we have to find the variable declarator by traveling back up while (newNode.parentPath && !j.VariableDeclarator.check(newNode.node)) { newNode = newNode.parentPath; } if (newNode.get('init')) { // init returns the right hand side identifier const rightHandSideNodePath = newNode.get('init'); const name = rightHandSideNodePath.getValueProperty('name'); let { scope } = rightHandSideNodePath; // we check if the current scope declares the identifier // if not we move up to the parent scope while (scope && scope.parent && !scope.declares(name)) { scope = scope.parent; } if (scope && scope.getBindings()[name]) { const binding = scope.getBindings()[name][0]; if (j.AssignmentPattern.check(binding.parentPath.node) && j.ObjectExpression.check(binding.parentPath.node.right) && binding.parentPath.node.right.properties.length === 0 && binding.node.typeAnnotation == null) { binding.get('typeAnnotation').replace(typeAnnotation); } } } }); }); } // TS2525: Initializer provides no value for this binding element and the binding element has no default value. function replaceTS2525(root, diagnostics, typeAnnotation) { diagnostics.forEach((diagnostic) => { root .find(j.Identifier) .filter((path) => path.node.start === diagnostic.start && path.node.end === diagnostic.start + diagnostic.length && path.node.typeAnnotation == null) .forEach((path) => { const potentialObjDestructionNode = path.parentPath.parentPath.parentPath; if (j.ObjectPattern.check(potentialObjDestructionNode.node) && (j.AssignmentPattern.check(potentialObjDestructionNode.parentPath.node) || j.VariableDeclarator.check(potentialObjDestructionNode.parentPath.node)) && // to prevent adding a type to the obj destruction inside of the destruction !j.ObjectProperty.check(potentialObjDestructionNode.parentPath.parentPath.node) && potentialObjDestructionNode.node.typeAnnotation == null) { potentialObjDestructionNode.get('typeAnnotation').replace(typeAnnotation); } }); }); } //# sourceMappingURL=explicit-any.js.map