@xtrek/ts-migrate-plugins
Version:
Set of codemods, which are doing transformation of js/jsx to ts/tsx
98 lines • 5.83 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const typescript_1 = __importDefault(require("typescript"));
const react_1 = require("./utils/react");
const updateSourceText_1 = __importDefault(require("../utils/updateSourceText"));
const validateOptions_1 = require("../utils/validateOptions");
const optionProperties = {
force: { type: 'boolean' },
};
const reactClassLifecycleMethodsPlugin = {
name: 'react-class-lifecycle-methods',
run({ fileName, sourceFile, text, options }) {
return /\.tsx$/.test(fileName)
? annotateReactComponentLifecycleMethods(sourceFile, text, options.force)
: undefined;
},
validate: validateOptions_1.createValidate(optionProperties),
};
exports.default = reactClassLifecycleMethodsPlugin;
var AnnotationKind;
(function (AnnotationKind) {
AnnotationKind["Props"] = "Props";
AnnotationKind["State"] = "State";
AnnotationKind["Context"] = "Context";
})(AnnotationKind || (AnnotationKind = {}));
const reactLifecycleMethodAnnotations = {
// shouldComponentUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): boolean;
shouldComponentUpdate: [AnnotationKind.Props, AnnotationKind.State, AnnotationKind.Context],
// componentDidUpdate?(prevProps: Readonly<P>, prevState: Readonly<S>, snapshot?: SS): void;
componentDidUpdate: [AnnotationKind.Props, AnnotationKind.State],
// componentWillReceiveProps?(nextProps: Readonly<P>, nextContext: any): void;
componentWillReceiveProps: [AnnotationKind.Props, AnnotationKind.Context],
// componentWillUpdate?(nextProps: Readonly<P>, nextState: Readonly<S>, nextContext: any): void;
componentWillUpdate: [AnnotationKind.Props, AnnotationKind.State, AnnotationKind.Context],
};
function updateParameterType(parameter, type) {
return typescript_1.default.factory.updateParameterDeclaration(parameter, parameter.decorators, parameter.modifiers, parameter.dotDotDotToken, parameter.name, parameter.questionToken, type, parameter.initializer);
}
function annotateReactComponentLifecycleMethods(sourceFile, sourceText, force = false) {
const printer = typescript_1.default.createPrinter();
const updates = [];
sourceFile.statements.forEach((statement) => {
if (typescript_1.default.isClassDeclaration(statement) && react_1.isReactClassComponent(statement)) {
const heritageType = react_1.getReactComponentHeritageType(statement);
const heritageTypeArgs = heritageType.typeArguments || [];
const propsType = heritageTypeArgs[0] || typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword);
const stateType = heritageTypeArgs[1] || typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword);
const annotationToType = {
[AnnotationKind.Props]: propsType,
[AnnotationKind.State]: stateType,
[AnnotationKind.Context]: typescript_1.default.factory.createKeywordTypeNode(typescript_1.default.SyntaxKind.AnyKeyword),
};
statement.members.forEach((member) => {
if (typescript_1.default.isConstructorDeclaration(member) &&
member.parameters.length === 1 &&
(member.parameters[0].type == null || force)) {
const parameter = member.parameters[0];
const updatedParameter = updateParameterType(parameter, propsType);
updates.push({
kind: 'replace',
index: parameter.pos,
length: parameter.end - parameter.pos,
text: printer.printNode(typescript_1.default.EmitHint.Unspecified, updatedParameter, sourceFile),
});
}
else if (typescript_1.default.isMethodDeclaration(member) &&
typescript_1.default.isIdentifier(member.name) &&
reactLifecycleMethodAnnotations[member.name.text] != null) {
const annotations = reactLifecycleMethodAnnotations[member.name.text];
let didUpdateParameters = false;
const parametersToPrint = [...member.parameters];
for (let i = 0; i < member.parameters.length; i += 1) {
const parameter = member.parameters[i];
const annotation = annotationToType[annotations[i]];
if (annotation != null && (parameter.type == null || force)) {
const updatedParameter = updateParameterType(parameter, annotation);
parametersToPrint[i] = updatedParameter;
didUpdateParameters = true;
}
}
if (didUpdateParameters) {
const start = member.parameters[0].pos;
const { end } = member.parameters[member.parameters.length - 1];
let text = printer.printList(typescript_1.default.ListFormat.Parameters, typescript_1.default.factory.createNodeArray(parametersToPrint), sourceFile);
// Remove surrounding parentheses
text = text.slice(1, text.length - 1);
updates.push({ kind: 'replace', index: start, length: end - start, text });
}
}
});
}
});
return updateSourceText_1.default(sourceText, updates);
}
//# sourceMappingURL=react-class-lifecycle-methods.js.map