Skip to content

Commit e65a6ed

Browse files
committed
Use NodeFactory to create and update nodes
Most ts.create* and ts.update* functions are deprecated as of TypeScript 4.0. The current plan is to emit noiser and noisier warnings with each version until the deprecated functions are removed in 4.3. See this pull request for more details: microsoft/TypeScript#35282 Some method signatures and names have changed slightly. The easy way to update is to use the global ts.factory object. TypeScript transformations also have access to a NodeFactory in their transformation contexts. Note that we still use the deprecate getMutableClone function because its replacement is not included in the TypeScript declarations. See microsoft/TypeScript#40507
1 parent 11a4379 commit e65a6ed

11 files changed

+227
-185
lines changed

packages/ts-migrate-example/src/example-plugin-ts.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,24 +29,24 @@ const examplePluginTs: Plugin<Options> = {
2929

3030
if (options.shouldReplaceText && hasTwoParams && multiplierReturn) {
3131
// create a new function declaration with a new type
32-
const newFunctionDeclaration = ts.createFunctionDeclaration(
32+
const newFunctionDeclaration = ts.factory.createFunctionDeclaration(
3333
functionDeclaration.decorators,
3434
functionDeclaration.modifiers,
3535
functionDeclaration.asteriskToken,
3636
functionDeclaration.name,
3737
functionDeclaration.typeParameters,
3838
functionDeclaration.parameters.map((x) =>
39-
ts.createParameter(
39+
ts.factory.createParameterDeclaration(
4040
x.decorators,
4141
x.modifiers,
4242
x.dotDotDotToken,
4343
x.name,
4444
x.questionToken,
45-
ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
45+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
4646
x.initializer,
4747
),
4848
),
49-
ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
49+
ts.factory.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword),
5050
functionDeclaration.body,
5151
);
5252

packages/ts-migrate-plugins/src/plugins/hoist-class-statics.ts

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ type Options = {
1515

1616
const hoistClassStaticsPlugin: Plugin<Options> = {
1717
name: 'hoist-class-statics',
18-
run({ fileName, text, options }) {
19-
return hoistStaticClassProperties(fileName, text, options);
18+
run({ sourceFile, text, options }) {
19+
return hoistStaticClassProperties(sourceFile, text, options);
2020
},
2121
};
2222

@@ -90,11 +90,10 @@ function isAlreadyHoisted(
9090
}
9191

9292
function hoistStaticClassProperties(
93-
fileName: string,
93+
sourceFile: ts.SourceFile,
9494
sourceText: string,
9595
options: Options,
9696
): string {
97-
const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true);
9897
const printer = ts.createPrinter();
9998
const updates: SourceTextUpdate[] = [];
10099

@@ -126,9 +125,9 @@ function hoistStaticClassProperties(
126125
canHoistExpression(statement.expression.right, classDeclaration.pos, knownDefinitions)
127126
) {
128127
properties.push(
129-
ts.createProperty(
128+
ts.factory.createPropertyDeclaration(
130129
undefined,
131-
[ts.createModifier(ts.SyntaxKind.StaticKeyword)],
130+
[ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)],
132131
statement.expression.left.name.text,
133132
undefined,
134133
undefined,
@@ -143,14 +142,14 @@ function hoistStaticClassProperties(
143142
} else {
144143
// otherwise add a static type annotation for this expression
145144
properties.push(
146-
ts.createProperty(
145+
ts.factory.createPropertyDeclaration(
147146
undefined,
148-
[ts.createModifier(ts.SyntaxKind.StaticKeyword)],
147+
[ts.factory.createModifier(ts.SyntaxKind.StaticKeyword)],
149148
statement.expression.left.name.text,
150149
undefined,
151150
options.anyAlias != null
152-
? ts.createTypeReferenceNode(options.anyAlias, undefined)
153-
: ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
151+
? ts.factory.createTypeReferenceNode(options.anyAlias, undefined)
152+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
154153
undefined,
155154
),
156155
);
@@ -160,14 +159,14 @@ function hoistStaticClassProperties(
160159

161160
if (properties.length > 0) {
162161
if (classDeclaration.members.length === 0) {
163-
const updatedClassDeclaration = ts.updateClassDeclaration(
162+
const updatedClassDeclaration = ts.factory.updateClassDeclaration(
164163
classDeclaration,
165164
classDeclaration.decorators,
166165
classDeclaration.modifiers,
167166
classDeclaration.name,
168167
classDeclaration.typeParameters,
169168
classDeclaration.heritageClauses,
170-
ts.createNodeArray(properties),
169+
ts.factory.createNodeArray(properties),
171170
);
172171

173172
let index = classDeclaration.pos;

packages/ts-migrate-plugins/src/plugins/jsdoc.ts

Lines changed: 35 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,10 @@ const jsDocTransformerFactory = ({
6363
anyAlias,
6464
typeMap: optionsTypeMap,
6565
}: Options) => (context: ts.TransformationContext) => {
66+
const { factory } = context;
6667
const anyType = anyAlias
67-
? ts.createTypeReferenceNode(anyAlias, undefined)
68-
: ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
68+
? factory.createTypeReferenceNode(anyAlias, undefined)
69+
: factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
6970
const typeMap: TypeMap = { ...defaultTypeMap, ...optionsTypeMap };
7071

7172
function visit<T extends ts.Node>(origNode: T): T {
@@ -78,7 +79,9 @@ const jsDocTransformerFactory = ({
7879

7980
function visitFunctionLike<T extends ts.SignatureDeclaration>(node: T, insideClass: boolean): T {
8081
const modifiers =
81-
ts.isMethodDeclaration(node) && insideClass ? modifiersFromJSDoc(node) : node.modifiers;
82+
ts.isMethodDeclaration(node) && insideClass
83+
? modifiersFromJSDoc(node, factory)
84+
: node.modifiers;
8285
const parameters = visitParameters(node);
8386
const returnType = annotateReturns ? visitReturnType(node) : node.type;
8487
if (
@@ -90,8 +93,8 @@ const jsDocTransformerFactory = ({
9093
}
9194

9295
const newNode = ts.getMutableClone(node) as any;
93-
newNode.modifiers = ts.createNodeArray(modifiers);
94-
newNode.parameters = ts.createNodeArray(parameters);
96+
newNode.modifiers = factory.createNodeArray(modifiers);
97+
newNode.parameters = factory.createNodeArray(parameters);
9598
newNode.type = returnType;
9699
return newNode;
97100
}
@@ -121,10 +124,10 @@ const jsDocTransformerFactory = ({
121124
!param.initializer &&
122125
ts.isIdentifier(param.name) &&
123126
(paramNode.isBracketed || ts.isJSDocOptionalType(typeNode))
124-
? ts.createToken(ts.SyntaxKind.QuestionToken)
127+
? factory.createToken(ts.SyntaxKind.QuestionToken)
125128
: param.questionToken;
126129

127-
const newParam = ts.createParameter(
130+
const newParam = factory.createParameterDeclaration(
128131
param.decorators,
129132
param.modifiers,
130133
param.dotDotDotToken,
@@ -192,25 +195,25 @@ const jsDocTransformerFactory = ({
192195
}
193196

194197
function visitJSDocOptionalType(node: ts.JSDocOptionalType) {
195-
return ts.createUnionTypeNode([
198+
return factory.createUnionTypeNode([
196199
ts.visitNode(node.type, visitJSDocType),
197-
ts.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
200+
factory.createKeywordTypeNode(ts.SyntaxKind.UndefinedKeyword),
198201
]);
199202
}
200203

201204
function visitJSDocNullableType(node: ts.JSDocNullableType) {
202-
return ts.createUnionTypeNode([
205+
return factory.createUnionTypeNode([
203206
ts.visitNode(node.type, visitJSDocType),
204-
ts.createKeywordTypeNode(ts.SyntaxKind.NullKeyword as any),
207+
factory.createKeywordTypeNode(ts.SyntaxKind.NullKeyword as any),
205208
]);
206209
}
207210

208211
function visitJSDocVariadicType(node: ts.JSDocVariadicType) {
209-
return ts.createArrayTypeNode(ts.visitNode(node.type, visitJSDocType));
212+
return factory.createArrayTypeNode(ts.visitNode(node.type, visitJSDocType));
210213
}
211214

212215
function visitJSDocFunctionType(node: ts.JSDocFunctionType) {
213-
return ts.createFunctionTypeNode(
216+
return factory.createFunctionTypeNode(
214217
undefined,
215218
node.parameters.map(visitJSDocParameter),
216219
node.type ?? anyType,
@@ -227,7 +230,7 @@ const jsDocTransformerFactory = ({
227230
}
228231
});
229232
}
230-
return ts.createTypeLiteralNode(propertySignatures);
233+
return factory.createTypeLiteralNode(propertySignatures);
231234
}
232235

233236
function visitJSDocPropertyLikeTag(node: ts.JSDocPropertyLikeTag) {
@@ -240,12 +243,14 @@ const jsDocTransformerFactory = ({
240243
type = anyType;
241244
}
242245
const questionToken =
243-
node.isBracketed || optionalType ? ts.createToken(ts.SyntaxKind.QuestionToken) : undefined;
246+
node.isBracketed || optionalType
247+
? factory.createToken(ts.SyntaxKind.QuestionToken)
248+
: undefined;
244249
if (ts.isIdentifier(node.name)) {
245-
return ts.createPropertySignature(undefined, node.name, questionToken, type, undefined);
250+
return factory.createPropertySignature(undefined, node.name, questionToken, type);
246251
}
247252
// Assumption: the leaf field on the QualifiedName belongs directly to the parent object type.
248-
return ts.createPropertySignature(undefined, node.name.right, questionToken, type, undefined);
253+
return factory.createPropertySignature(undefined, node.name.right, questionToken, type);
249254
}
250255

251256
function visitJSDocParameter(node: ts.ParameterDeclaration) {
@@ -257,8 +262,10 @@ const jsDocTransformerFactory = ({
257262
node.type.kind === ts.SyntaxKind.JSDocVariadicType &&
258263
index === node.parent.parameters.length - 1;
259264
const name = node.name || (isRest ? 'rest' : `arg${index}`);
260-
const dotdotdot = isRest ? ts.createToken(ts.SyntaxKind.DotDotDotToken) : node.dotDotDotToken;
261-
return ts.createParameter(
265+
const dotdotdot = isRest
266+
? factory.createToken(ts.SyntaxKind.DotDotDotToken)
267+
: node.dotDotDotToken;
268+
return factory.createParameterDeclaration(
262269
node.decorators,
263270
node.modifiers,
264271
dotdotdot,
@@ -290,35 +297,35 @@ const jsDocTransformerFactory = ({
290297
}
291298
}
292299

293-
name = ts.createIdentifier(text);
300+
name = factory.createIdentifier(text);
294301
if ((text === 'Array' || text === 'Promise') && !node.typeArguments) {
295-
args = ts.createNodeArray([anyType]);
302+
args = factory.createNodeArray([anyType]);
296303
} else if (acceptsTypeParameters) {
297304
args = ts.visitNodes(node.typeArguments, visitJSDocType);
298305
}
299306
if (!acceptsTypeParameters) {
300307
args = undefined;
301308
}
302309
}
303-
return ts.createTypeReferenceNode(name, args);
310+
return factory.createTypeReferenceNode(name, args);
304311
}
305312

306313
function visitJSDocIndexSignature(node: ts.TypeReferenceNode) {
307314
const typeArguments = node.typeArguments!;
308-
const index = ts.createParameter(
315+
const index = factory.createParameterDeclaration(
309316
/* decorators */ undefined,
310317
/* modifiers */ undefined,
311318
/* dotDotDotToken */ undefined,
312319
typeArguments[0].kind === ts.SyntaxKind.NumberKeyword ? 'n' : 's',
313320
/* questionToken */ undefined,
314-
ts.createTypeReferenceNode(
321+
factory.createTypeReferenceNode(
315322
typeArguments[0].kind === ts.SyntaxKind.NumberKeyword ? 'number' : 'string',
316323
[],
317324
),
318325
/* initializer */ undefined,
319326
);
320-
const indexSignature = ts.createTypeLiteralNode([
321-
ts.createIndexSignature(
327+
const indexSignature = factory.createTypeLiteralNode([
328+
factory.createIndexSignature(
322329
/* decorators */ undefined,
323330
/* modifiers */ undefined,
324331
[index],
@@ -337,6 +344,7 @@ const accessibilityMask =
337344

338345
function modifiersFromJSDoc(
339346
methodDeclaration: ts.MethodDeclaration,
347+
factory: ts.NodeFactory,
340348
): ReadonlyArray<ts.Modifier> | undefined {
341349
let modifierFlags = ts.getCombinedModifierFlags(methodDeclaration);
342350
if ((modifierFlags & accessibilityMask) !== 0) {
@@ -354,7 +362,7 @@ function modifiersFromJSDoc(
354362
return methodDeclaration.modifiers;
355363
}
356364

357-
return ts.createModifiersFromModifierFlags(modifierFlags);
365+
return factory.createModifiersFromModifierFlags(modifierFlags);
358366
}
359367

360368
// Copied from: https://github.com/microsoft/TypeScript/blob/v4.0.2/src/compiler/utilities.ts#L1879

packages/ts-migrate-plugins/src/plugins/member-accessibility.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ const accessibilityMask =
3232
const memberAccessibilityTransformerFactory = (options: Options) => (
3333
context: ts.TransformationContext,
3434
) => {
35+
const { factory } = context;
3536
let defaultAccessibility: ts.ModifierFlags;
3637
switch (options.defaultAccessibility) {
3738
case 'private':
@@ -77,8 +78,8 @@ const memberAccessibilityTransformerFactory = (options: Options) => (
7778
}
7879

7980
const newNode = ts.getMutableClone(node) as any;
80-
newNode.modifiers = ts.createNodeArray(
81-
ts.createModifiersFromModifierFlags(modifierFlags | accessibilityFlag),
81+
newNode.modifiers = factory.createNodeArray(
82+
factory.createModifiersFromModifierFlags(modifierFlags | accessibilityFlag),
8283
);
8384
return newNode;
8485
}

packages/ts-migrate-plugins/src/plugins/react-class-lifecycle-methods.ts

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ type Options = { force?: boolean };
77

88
const reactClassLifecycleMethodsPlugin: Plugin<Options> = {
99
name: 'react-class-lifecycle-methods',
10-
run({ fileName, text, options }) {
10+
run({ fileName, sourceFile, text, options }) {
1111
return /\.tsx$/.test(fileName)
12-
? annotateReactComponentLifecycleMethods(fileName, text, options.force)
12+
? annotateReactComponentLifecycleMethods(sourceFile, text, options.force)
1313
: undefined;
1414
},
1515
};
@@ -37,7 +37,7 @@ const reactLifecycleMethodAnnotations: { [method: string]: AnnotationKind[] } =
3737
};
3838

3939
function updateParameterType(parameter: ts.ParameterDeclaration, type: ts.TypeNode | undefined) {
40-
return ts.updateParameter(
40+
return ts.factory.updateParameterDeclaration(
4141
parameter,
4242
parameter.decorators,
4343
parameter.modifiers,
@@ -50,24 +50,25 @@ function updateParameterType(parameter: ts.ParameterDeclaration, type: ts.TypeNo
5050
}
5151

5252
function annotateReactComponentLifecycleMethods(
53-
fileName: string,
53+
sourceFile: ts.SourceFile,
5454
sourceText: string,
5555
force = false,
5656
) {
57-
const sourceFile = ts.createSourceFile(fileName, sourceText, ts.ScriptTarget.Latest, true);
5857
const printer = ts.createPrinter();
5958
const updates: SourceTextUpdate[] = [];
6059

6160
sourceFile.statements.forEach((statement) => {
6261
if (ts.isClassDeclaration(statement) && isReactClassComponent(statement)) {
6362
const heritageType = getReactComponentHeritageType(statement)!;
6463
const heritageTypeArgs = heritageType.typeArguments || [];
65-
const propsType = heritageTypeArgs[0] || ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
66-
const stateType = heritageTypeArgs[1] || ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
64+
const propsType =
65+
heritageTypeArgs[0] || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
66+
const stateType =
67+
heritageTypeArgs[1] || ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
6768
const annotationToType = {
6869
[AnnotationKind.Props]: propsType,
6970
[AnnotationKind.State]: stateType,
70-
[AnnotationKind.Context]: ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
71+
[AnnotationKind.Context]: ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword),
7172
};
7273

7374
statement.members.forEach((member) => {
@@ -110,7 +111,7 @@ function annotateReactComponentLifecycleMethods(
110111

111112
let text = printer.printList(
112113
ts.ListFormat.Parameters,
113-
ts.createNodeArray(parametersToPrint),
114+
ts.factory.createNodeArray(parametersToPrint),
114115
sourceFile,
115116
);
116117
// Remove surrounding parentheses

packages/ts-migrate-plugins/src/plugins/react-class-state.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,9 @@ const reactClassStatePlugin: Plugin<Options> = {
5959
const stateTypeName = getStateTypeName();
6060
const anyType =
6161
options.anyAlias != null
62-
? ts.createTypeReferenceNode(options.anyAlias, undefined)
63-
: ts.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
64-
const newStateType = ts.createTypeAliasDeclaration(
62+
? ts.factory.createTypeReferenceNode(options.anyAlias, undefined)
63+
: ts.factory.createKeywordTypeNode(ts.SyntaxKind.AnyKeyword);
64+
const newStateType = ts.factory.createTypeAliasDeclaration(
6565
undefined,
6666
undefined,
6767
stateTypeName,
@@ -81,14 +81,10 @@ const reactClassStatePlugin: Plugin<Options> = {
8181
length: heritageType.end - heritageType.pos,
8282
text: ` ${printer.printNode(
8383
ts.EmitHint.Unspecified,
84-
ts.updateExpressionWithTypeArguments(
85-
heritageType,
86-
[
87-
propsType || ts.createTypeLiteralNode([]),
88-
ts.createTypeReferenceNode(stateTypeName, undefined),
89-
],
90-
heritageType.expression,
91-
),
84+
ts.factory.updateExpressionWithTypeArguments(heritageType, heritageType.expression, [
85+
propsType || ts.factory.createTypeLiteralNode([]),
86+
ts.factory.createTypeReferenceNode(stateTypeName, undefined),
87+
]),
9288
sourceFile,
9389
)}`,
9490
});

0 commit comments

Comments
 (0)