UNPKG

@xtrek/ts-migrate-plugins

Version:

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

262 lines 12.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.createPropsTypeNameGetter = void 0; /* eslint-disable no-use-before-define, @typescript-eslint/no-use-before-define, no-restricted-syntax */ const typescript_1 = __importDefault(require("typescript")); const react_1 = require("./react"); const identifiers_1 = require("./identifiers"); function getTypeFromPropTypesObjectLiteral(objectLiteral, sourceFile, params) { const members = []; const intersectionTypes = []; const unhandledProperties = []; const comments = []; for (const property of objectLiteral.properties) { let handled = false; if (typescript_1.default.isPropertyAssignment(property)) { if (params.implicitChildren && property.name.getText(sourceFile) === 'children') { handled = true; } else { const prop = convertPropertyAssignment(property, sourceFile, params); if (prop) { members.push(prop); handled = true; } } } else if (typescript_1.default.isSpreadAssignment(property) && typescript_1.default.isIdentifier(property.expression)) { const spreadId = property.expression.text; const replacement = params.spreadReplacements.find((cur) => cur.spreadId === spreadId); if (replacement) { intersectionTypes.push(replacement.typeRef); handled = true; } } if (!handled) { unhandledProperties.push(property); comments.push(property.getText(sourceFile)); } } let node = typescript_1.default.factory.createTypeLiteralNode(members); if (intersectionTypes.length > 0) { node = typescript_1.default.factory.createIntersectionTypeNode([node, ...intersectionTypes]); } if (comments.length > 0) { node = typescript_1.default.addSyntheticLeadingComment(node, typescript_1.default.SyntaxKind.MultiLineCommentTrivia, ` (ts-migrate) TODO: Migrate the remaining prop types ${comments.join('\n')} `, true); } return node; } exports.default = getTypeFromPropTypesObjectLiteral; function convertPropertyAssignment(propertyAssignment, sourceFile, params) { const name = propertyAssignment.name.getText(sourceFile); const { initializer } = propertyAssignment; let typeExpression; let isRequired; if (typescript_1.default.isPropertyAccessExpression(initializer) && /\.isRequired/.test(initializer.getText(sourceFile))) { typeExpression = initializer.expression; isRequired = true; } else { typeExpression = initializer; isRequired = false; } const typeNode = getTypeFromPropTypeExpression(typeExpression, sourceFile, params); let propertySignature = typescript_1.default.factory.createPropertySignature(undefined, name, isRequired ? undefined : typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.QuestionToken), typeNode); propertySignature = typescript_1.default.moveSyntheticComments(propertySignature, typeNode); return propertySignature; } function getTypeFromPropTypeExpression(node, sourceFile, params) { const { anyAlias, anyFunctionAlias } = params; let text = node.getText(sourceFile).replace(/React\.PropTypes\./, ''); const isDestructuredProptypeImport = params.propTypeIdentifiers && typescript_1.default.isIdentifier(node) && params.propTypeIdentifiers[text]; let result = null; if (typescript_1.default.isPropertyAccessExpression(node) || isDestructuredProptypeImport) { if (isDestructuredProptypeImport && params.propTypeIdentifiers) { text = params.propTypeIdentifiers[text]; } /** * PropTypes.array, * PropTypes.bool, * PropTypes.func, * PropTypes.number, * PropTypes.object, * PropTypes.string, * PropTypes.symbol, (ignore) * PropTypes.node, * PropTypes.element, * PropTypes.any, */ if (/string/.test(text)) { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.StringKeyword); } else if (/any/.test(text)) { if (anyAlias) { result = typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined); } else { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); } } else if (/array/.test(text)) { if (anyAlias) { result = typescript_1.default.factory.createArrayTypeNode(typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined)); } else { result = typescript_1.default.factory.createArrayTypeNode(typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword)); } } else if (/bool/.test(text)) { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.BooleanKeyword); } else if (/number/.test(text)) { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.NumberKeyword); } else if (/object/.test(text)) { if (anyAlias) { result = typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined); } else { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); } } else if (/node/.test(text)) { result = typescript_1.default.factory.createTypeReferenceNode('React.ReactNode', undefined); } else if (/element/.test(text)) { result = typescript_1.default.factory.createTypeReferenceNode('React.ReactElement', undefined); } else if (/func/.test(text)) { if (anyFunctionAlias) { result = typescript_1.default.factory.createTypeReferenceNode(anyFunctionAlias, undefined); } else if (anyAlias) { result = typescript_1.default.factory.createFunctionTypeNode(undefined, [ typescript_1.default.factory.createParameterDeclaration(undefined, undefined, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.DotDotDotToken), 'args', undefined, typescript_1.default.factory.createArrayTypeNode(typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined)), undefined), ], typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined)); } else { result = typescript_1.default.factory.createFunctionTypeNode(undefined, [ typescript_1.default.factory.createParameterDeclaration(undefined, undefined, typescript_1.default.factory.createToken(typescript_1.default.SyntaxKind.DotDotDotToken), 'args', undefined, typescript_1.default.factory.createArrayTypeNode(typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword)), undefined), ], typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword)); } } } else if (typescript_1.default.isCallExpression(node)) { /** * PropTypes.instanceOf(), (ignore) * PropTypes.oneOf(), // only support oneOf([1, 2]), oneOf(['a', 'b']) * PropTypes.oneOfType(), * PropTypes.arrayOf(), * PropTypes.objectOf(), * PropTypes.shape(), */ const expressionText = node.expression.getText(sourceFile); if (/oneOf$/.test(expressionText)) { const argument = node.arguments[0]; if (typescript_1.default.isArrayLiteralExpression(argument)) { if (argument.elements.every((elm) => typescript_1.default.isStringLiteral(elm) || typescript_1.default.isNumericLiteral(elm))) { result = typescript_1.default.factory.createUnionTypeNode(argument.elements.map((elm) => typescript_1.default.factory.createLiteralTypeNode(elm))); } } } else if (/oneOfType$/.test(expressionText)) { const argument = node.arguments[0]; if (typescript_1.default.isArrayLiteralExpression(argument)) { const children = []; result = typescript_1.default.factory.createUnionTypeNode(argument.elements.map((elm) => { const child = getTypeFromPropTypeExpression(elm, sourceFile, params); children.push(child); return child; })); for (const child of children) { result = typescript_1.default.moveSyntheticComments(result, child); } } } else if (/arrayOf$/.test(expressionText)) { const argument = node.arguments[0]; if (argument) { const child = getTypeFromPropTypeExpression(argument, sourceFile, params); result = typescript_1.default.factory.createArrayTypeNode(child); result = typescript_1.default.moveSyntheticComments(result, child); } } else if (/objectOf$/.test(expressionText)) { const argument = node.arguments[0]; if (argument) { const child = getTypeFromPropTypeExpression(argument, sourceFile, params); result = typescript_1.default.factory.createTypeLiteralNode([ typescript_1.default.factory.createIndexSignature(undefined, undefined, [ typescript_1.default.factory.createParameterDeclaration(undefined, undefined, undefined, 'key', undefined, typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.StringKeyword)), ], child), ]); result = typescript_1.default.moveSyntheticComments(result, child); } } else if (/shape$/.test(expressionText)) { const argument = node.arguments[0]; if (argument && typescript_1.default.isObjectLiteralExpression(argument)) { return getTypeFromPropTypesObjectLiteral(argument, sourceFile, params); } } } else if (typescript_1.default.isIdentifier(node) && node.text === 'textlike') { result = typescript_1.default.factory.createUnionTypeNode([ typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.StringKeyword), typescript_1.default.factory.createTypeReferenceNode('React.ReactNode', undefined), ]); } else if (typescript_1.default.isIdentifier(node)) { result = typescript_1.default.factory.createTypeReferenceNode(node.text, undefined); } /** * customProp, * anything others */ if (!result) { if (anyAlias) { result = typescript_1.default.factory.createTypeReferenceNode(anyAlias, undefined); } else { result = typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword); } // Add comment about what the original proptype was. result = typescript_1.default.addSyntheticTrailingComment(result, typescript_1.default.SyntaxKind.SingleLineCommentTrivia, ` TODO: ${text .split('\n') .map((line) => line.trim()) .join(' ')}`, true); } return result; } function createPropsTypeNameGetter(sourceFile) { const numComponentsInFile = react_1.getNumComponentsInSourceFile(sourceFile); const usedIdentifiers = identifiers_1.collectIdentifiers(sourceFile); const getPropsTypeName = (componentName) => { let name = ''; if (componentName && numComponentsInFile > 1) { name = `${componentName}Props`; } else { name = 'Props'; } if (!usedIdentifiers.has(name)) { return name; } // Ensure name is unused. let i = 1; while (usedIdentifiers.has(name + i)) { i += 1; } return name + i; }; return getPropsTypeName; } exports.createPropsTypeNameGetter = createPropsTypeNameGetter; //# sourceMappingURL=react-props.js.map