@xtrek/ts-migrate-plugins
Version:
Set of codemods, which are doing transformation of js/jsx to ts/tsx
262 lines • 12.7 kB
JavaScript
;
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