Skip to content

Commit 8429cd8

Browse files
committed
add factory functions for typenodes, update visitEachChild to dive into typenodes
add tests, fix linter issues
1 parent 7b73e8f commit 8429cd8

File tree

5 files changed

+301
-28
lines changed

5 files changed

+301
-28
lines changed

src/compiler/factory.ts

Lines changed: 206 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,212 @@ namespace ts {
185185
return <BooleanLiteral>createSynthesizedNode(SyntaxKind.FalseKeyword);
186186
}
187187

188+
// Types
189+
190+
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode, type: TypeNode): TypePredicateNode {
191+
const node = <TypePredicateNode>createSynthesizedNode(SyntaxKind.TypePredicate);
192+
node.parameterName = parameterName;
193+
node.type = type;
194+
return node;
195+
}
196+
197+
export function updateTypePredicate(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode): TypePredicateNode {
198+
return node.parameterName !== parameterName
199+
|| node.type !== type
200+
? updateNode(createTypePredicateNode(parameterName, type), node)
201+
: node;
202+
}
203+
204+
export function createTypeReferenceNode(typeName: EntityName, typeArguments?: TypeNode[]): TypeReferenceNode {
205+
const node = <TypeReferenceNode>createSynthesizedNode(SyntaxKind.TypeReference);
206+
node.typeName = typeName;
207+
node.typeArguments = asNodeArray(typeArguments);
208+
return node;
209+
}
210+
211+
export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments?: TypeNode[]) {
212+
return node.typeName !== typeName
213+
|| node.typeArguments !== typeArguments
214+
? updateNode(createTypeReferenceNode(typeName, typeArguments), node)
215+
: node;
216+
}
217+
218+
export function createFunctionTypeNode(name?: PropertyName, typeParameters?: TypeParameterDeclaration[], parameters?: ParameterDeclaration[], type?: TypeNode) {
219+
const node = <FunctionTypeNode>createSynthesizedNode(SyntaxKind.FunctionType);
220+
node.name = asName(name);
221+
node.typeParameters = asNodeArray(typeParameters);
222+
node.parameters = asNodeArray(parameters);
223+
node.type = type;
224+
return node;
225+
}
226+
227+
export function updateFunctionTypeNode(node: FunctionTypeNode, name?: PropertyName, typeParameters?: TypeParameterDeclaration[], parameters?: ParameterDeclaration[], type?: TypeNode): FunctionTypeNode {
228+
return node.name !== name
229+
|| node.typeParameters !== typeParameters
230+
|| node.parameters !== parameters
231+
|| node.type == type
232+
? updateNode(createFunctionTypeNode(name, typeParameters, parameters, type), node)
233+
: node;
234+
}
235+
236+
export function createConstructorTypeNode(name?: PropertyName, typeParameters?: TypeParameterDeclaration[], parameters?: ParameterDeclaration[], type?: TypeNode) {
237+
const node = <ConstructorTypeNode>createSynthesizedNode(SyntaxKind.ConstructorType);
238+
node.name = asName(name);
239+
node.typeParameters = asNodeArray(typeParameters);
240+
node.parameters = asNodeArray(parameters);
241+
node.type = type;
242+
return node;
243+
}
244+
245+
export function updateConstructorTypeNode(node: ConstructorTypeNode, name?: PropertyName, typeParameters?: TypeParameterDeclaration[], parameters?: ParameterDeclaration[], type?: TypeNode): ConstructorTypeNode {
246+
return node.name !== name
247+
|| node.typeParameters !== typeParameters
248+
|| node.parameters !== parameters
249+
|| node.type == type
250+
? updateNode(createConstructorTypeNode(name, typeParameters, parameters, type), node)
251+
: node;
252+
}
253+
254+
export function createTypeQueryNode(exprName: EntityName): TypeQueryNode {
255+
const node = <TypeQueryNode>createSynthesizedNode(SyntaxKind.TypeQuery);
256+
node.exprName = exprName;
257+
return node;
258+
}
259+
260+
export function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName): TypeQueryNode {
261+
return node.exprName !== exprName
262+
? updateNode(createTypeQueryNode(exprName), node)
263+
: node;
264+
}
265+
266+
export function createTypeLiteralNode(members: TypeElement[]): TypeLiteralNode {
267+
const node = <TypeLiteralNode>createSynthesizedNode(SyntaxKind.TypeLiteral);
268+
node.members = asNodeArray(members);
269+
return node;
270+
}
271+
272+
export function updateTypeLiteralNode(node: TypeLiteralNode, members: TypeElement[]): TypeLiteralNode {
273+
return node.members !== members
274+
? updateNode(createTypeLiteralNode(members), node)
275+
: node;
276+
}
277+
278+
export function createArrayTypeNode(elementType: TypeNode): ArrayTypeNode {
279+
const node = <ArrayTypeNode>createSynthesizedNode(SyntaxKind.ArrayType);
280+
node.elementType = elementType;
281+
return node;
282+
}
283+
284+
export function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode {
285+
return node.elementType !== elementType
286+
? updateNode(createArrayTypeNode(elementType), node)
287+
: node;
288+
}
289+
290+
export function createTupleTypeNode(elementTypes: TypeNode[]): TupleTypeNode {
291+
const node = <TupleTypeNode>createSynthesizedNode(SyntaxKind.TupleType);
292+
node.elementTypes = asNodeArray(elementTypes);
293+
return node;
294+
}
295+
296+
export function updateTupleTypeNode(node: TupleTypeNode, elementTypes: TypeNode[]): TupleTypeNode {
297+
return node.elementTypes !== elementTypes
298+
? updateNode(createTupleTypeNode(elementTypes), node)
299+
: node;
300+
}
301+
302+
export function createUnionOrIntersectionTypeNode(kind: UnionOrIntersectionTypeNode["kind"], types: TypeNode[]): UnionOrIntersectionTypeNode {
303+
const node = <UnionOrIntersectionTypeNode>createSynthesizedNode(kind);
304+
node.types = asNodeArray(types);
305+
return node;
306+
}
307+
308+
export function updateUnionOrIntersectionTypeNode(node: UnionOrIntersectionTypeNode, types: TypeNode[]): UnionOrIntersectionTypeNode {
309+
return node.types !== types
310+
? updateNode(createUnionOrIntersectionTypeNode(node.kind, types), node)
311+
: node;
312+
}
313+
314+
export function createUnionTypeNode(types: TypeNode[]): UnionOrIntersectionTypeNode {
315+
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, types);
316+
}
317+
318+
export function createIntersectionTypeNode(types: TypeNode[]): UnionOrIntersectionTypeNode {
319+
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, types);
320+
}
321+
322+
export function createParenthesizedTypeNode(type: TypeNode): ParenthesizedTypeNode {
323+
const node = <ParenthesizedTypeNode>createSynthesizedNode(SyntaxKind.ParenthesizedType);
324+
node.type = type;
325+
return node;
326+
}
327+
328+
export function updateParenthesizedTypeNode(node: ParenthesizedTypeNode, type: TypeNode): ParenthesizedTypeNode {
329+
return node.type !== type
330+
? updateNode(createParenthesizedTypeNode(type), node)
331+
: node;
332+
}
333+
334+
export function createThisTypeNode(): ThisTypeNode {
335+
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
336+
}
337+
338+
export function createTypeOperatorNode(type: TypeNode): TypeOperatorNode {
339+
const node = <TypeOperatorNode>createSynthesizedNode(SyntaxKind.TypeOperator);
340+
node.type = type;
341+
return node;
342+
}
343+
344+
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode): TypeOperatorNode {
345+
return node.type !== type
346+
? updateNode(createTypeOperatorNode(type), node)
347+
: node;
348+
}
349+
350+
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode {
351+
const node = <IndexedAccessTypeNode>createSynthesizedNode(SyntaxKind.IndexedAccessType);
352+
node.objectType = objectType;
353+
node.indexType = indexType;
354+
return node;
355+
}
356+
357+
export function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode): IndexedAccessTypeNode {
358+
return node.objectType !== objectType
359+
|| node.indexType !== indexType
360+
? updateNode(createIndexedAccessTypeNode(objectType, indexType), node)
361+
: node;
362+
}
363+
364+
export function createMappedTypeNode(readonlyToken?: ReadonlyToken, typeParameter?: TypeParameterDeclaration, questionToken?: QuestionToken, type?: TypeNode): MappedTypeNode {
365+
const node = <MappedTypeNode>createSynthesizedNode(SyntaxKind.MappedType);
366+
node.readonlyToken = readonlyToken;
367+
node.typeParameter = typeParameter;
368+
node.questionToken = questionToken;
369+
node.type = type;
370+
return node;
371+
}
372+
373+
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken?: ReadonlyToken, typeParameter?: TypeParameterDeclaration, questionToken?: QuestionToken, type?: TypeNode): MappedTypeNode {
374+
return node.readonlyToken !== readonlyToken
375+
|| node.typeParameter !== typeParameter
376+
|| node.questionToken !== questionToken
377+
|| node.type !== type
378+
? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node)
379+
: node;
380+
}
381+
382+
export function createLiteralTypeNode(literal: Expression): LiteralTypeNode {
383+
const node = <LiteralTypeNode>createSynthesizedNode(SyntaxKind.LiteralType);
384+
node.literal = literal;
385+
return node;
386+
}
387+
388+
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression): LiteralTypeNode {
389+
return node.literal !== literal
390+
? updateNode(createLiteralTypeNode(literal), node)
391+
: node;
392+
}
393+
188394
// Names
189395

190396
export function createQualifiedName(left: EntityName, right: string | Identifier) {

src/compiler/visitor.ts

Lines changed: 74 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,20 +210,87 @@ namespace ts {
210210
if (node === undefined) {
211211
return undefined;
212212
}
213-
noop
214-
215213
const kind = node.kind;
216214
// No need to visit nodes with no children.
217215
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) {
218216
return node;
219217
}
220218

221-
// We do not yet support types.
222-
if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.LiteralType)) {
223-
return node;
224-
}
225-
226219
switch (node.kind) {
220+
// TODO: add tests for visit* operations for type nodes
221+
case SyntaxKind.TypePredicate:
222+
return updateTypePredicate(<TypePredicateNode>node,
223+
visitNode((<TypePredicateNode>node).parameterName, visitor),
224+
visitNode((<TypePredicateNode>node).type, visitor));
225+
226+
case SyntaxKind.TypeReference:
227+
return updateTypeReferenceNode(<TypeReferenceNode>node,
228+
visitNode((<TypeReferenceNode>node).typeName, visitor),
229+
nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor));
230+
231+
case SyntaxKind.FunctionType:
232+
return updateFunctionTypeNode(<FunctionTypeNode>node,
233+
visitNode((<FunctionTypeNode>node).name, visitor),
234+
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor),
235+
nodesVisitor((<FunctionTypeNode>node).parameters, visitor),
236+
visitNode((<FunctionTypeNode>node).type, visitor));
237+
238+
case SyntaxKind.ConstructorType:
239+
return updateConstructorTypeNode(<ConstructorTypeNode>node,
240+
visitNode((<ConstructorTypeNode>node).name, visitor),
241+
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor),
242+
nodesVisitor((<ConstructorTypeNode>node).parameters, visitor),
243+
visitNode((<ConstructorTypeNode>node).type, visitor));
244+
245+
case SyntaxKind.TypeQuery:
246+
return updateTypeQueryNode(<TypeQueryNode>node,
247+
visitNode((<TypeQueryNode>node).exprName, visitor));
248+
249+
case SyntaxKind.TypeLiteral:
250+
return updateTypeLiteralNode(<TypeLiteralNode>node,
251+
nodesVisitor((<TypeLiteralNode>node).members, visitor));
252+
253+
case SyntaxKind.ArrayType:
254+
return updateArrayTypeNode(<ArrayTypeNode>node,
255+
visitNode((<ArrayTypeNode>node).elementType, visitor));
256+
257+
case SyntaxKind.TupleType:
258+
return updateTupleTypeNode(<TupleTypeNode>node,
259+
nodesVisitor((<TupleTypeNode>node).elementTypes, visitor));
260+
261+
case SyntaxKind.UnionType:
262+
case SyntaxKind.IntersectionType:
263+
return updateUnionOrIntersectionTypeNode(<UnionOrIntersectionTypeNode>node,
264+
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor));
265+
266+
case SyntaxKind.ParenthesizedType:
267+
return updateParenthesizedTypeNode(<ParenthesizedTypeNode>node,
268+
visitNode((<ParenthesizedTypeNode>node).type, visitor));
269+
270+
case SyntaxKind.ThisType:
271+
// ThisType does not have child nodes
272+
return node;
273+
274+
case SyntaxKind.TypeOperator:
275+
return updateTypeOperatorNode(<TypeOperatorNode>node,
276+
visitNode((<TypeOperatorNode>node).type, visitor));
277+
278+
case SyntaxKind.IndexedAccessType:
279+
return updateIndexedAccessTypeNode(<IndexedAccessTypeNode>node,
280+
visitNode((<IndexedAccessTypeNode>node).objectType, visitor),
281+
visitNode((<IndexedAccessTypeNode>node).indexType, visitor));
282+
283+
case SyntaxKind.MappedType:
284+
return updateMappedTypeNode(<MappedTypeNode>node,
285+
visitNode((<MappedTypeNode>node).readonlyToken, visitor), // TODO: use tokenVisitor
286+
visitNode((<MappedTypeNode>node).typeParameter, visitor),
287+
visitNode((<MappedTypeNode>node).questionToken, visitor), // TODO: use tokenVisitor
288+
visitNode((<MappedTypeNode>node).type, visitor));
289+
290+
case SyntaxKind.LiteralType:
291+
return updateLiteralTypeNode(<LiteralTypeNode>node,
292+
visitNode((<LiteralTypeNode>node).literal, visitor));
293+
227294
case SyntaxKind.SemicolonClassElement:
228295
case SyntaxKind.EmptyStatement:
229296
case SyntaxKind.OmittedExpression:

src/harness/unittests/extractMethods.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ namespace A {
561561
content: t.source
562562
};
563563
const host = projectSystem.createServerHost([f]);
564-
const projectService = projectSystem.createProjectService(host)
564+
const projectService = projectSystem.createProjectService(host);
565565
projectService.openClientFile(f.path);
566566
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
567567
const sourceFile = program.getSourceFile(f.path);
@@ -574,13 +574,13 @@ namespace A {
574574
sourceFile,
575575
span: undefined,
576576
rulesProvider: getRuleProvider()
577-
}
577+
};
578578
const result = codefix.extractMethod.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
579579
assert.equal(result.errors, undefined, "expect no errors");
580580
const results = codefix.extractMethod.extractRange(result.targetRange, sourceFile, context);
581581
const data: string[] = [];
582582
data.push(`==ORIGINAL==`);
583-
data.push(sourceFile.text)
583+
data.push(sourceFile.text);
584584
for (const r of results) {
585585
data.push(`==SCOPE::${r.scopeDescription}==`);
586586
data.push(textChanges.applyChanges(sourceFile.text, r.changes[0].textChanges));

0 commit comments

Comments
 (0)