Skip to content

Commit db44073

Browse files
armano2JamesHenry
authored andcommitted
feat: updates to constructor method node (typescript-eslint#124)
1 parent 6aa4286 commit db44073

File tree

6 files changed

+1313
-384
lines changed

6 files changed

+1313
-384
lines changed

packages/typescript-estree/src/convert.ts

+68-87
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ import {
2525
isOptional,
2626
findFirstMatchingToken,
2727
unescapeStringLiteralText,
28-
getDeclarationKind
28+
getDeclarationKind,
29+
getLastModifier
2930
} from './node-utils';
3031
import { AST_NODE_TYPES } from './ast-node-types';
3132
import { ESTreeNode } from './temp-types-based-on-js-source';
@@ -923,11 +924,11 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
923924
(openingParen as any).getStart(ast)
924925
),
925926
nodeIsMethod = node.kind === SyntaxKind.MethodDeclaration,
926-
method = {
927+
method: ESTreeNode = {
927928
type: AST_NODE_TYPES.FunctionExpression,
928929
id: null,
929930
generator: !!node.asteriskToken,
930-
expression: false,
931+
expression: false, // ESTreeNode as ESTreeNode here
931932
async: hasModifier(SyntaxKind.AsyncKeyword, node),
932933
body: convertChild(node.body),
933934
range: [node.parameters.pos - 1, result.range[1]],
@@ -938,7 +939,7 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
938939
},
939940
end: result.loc.end
940941
}
941-
};
942+
} as any;
942943

943944
if (node.type) {
944945
(method as any).returnType = convertTypeAnnotation(node.type);
@@ -1007,112 +1008,92 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
10071008
} else if (
10081009
!(result as any).static &&
10091010
node.name.kind === SyntaxKind.StringLiteral &&
1010-
node.name.text === 'constructor'
1011+
node.name.text === 'constructor' &&
1012+
result.type !== AST_NODE_TYPES.Property
10111013
) {
10121014
(result as any).kind = 'constructor';
10131015
}
10141016

10151017
// Process typeParameters
10161018
if (node.typeParameters && node.typeParameters.length) {
1017-
(method as any).typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
1018-
node.typeParameters
1019-
);
1019+
if (result.type !== AST_NODE_TYPES.Property) {
1020+
method.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
1021+
node.typeParameters
1022+
);
1023+
} else {
1024+
result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
1025+
node.typeParameters
1026+
);
1027+
}
10201028
}
10211029

10221030
break;
10231031
}
10241032

10251033
// TypeScript uses this even for static methods named "constructor"
10261034
case SyntaxKind.Constructor: {
1027-
const constructorIsStatic = hasModifier(SyntaxKind.StaticKeyword, node),
1028-
constructorIsAbstract = hasModifier(SyntaxKind.AbstractKeyword, node),
1029-
firstConstructorToken = constructorIsStatic
1030-
? findNextToken(node.getFirstToken()!, ast, ast)
1031-
: node.getFirstToken(),
1032-
constructorLoc = ast.getLineAndCharacterOfPosition(
1033-
node.parameters.pos - 1
1034-
),
1035-
constructor = {
1036-
type: AST_NODE_TYPES.FunctionExpression,
1037-
id: null,
1038-
params: convertParameters(node.parameters),
1039-
generator: false,
1040-
expression: false,
1041-
async: false,
1042-
body: convertChild(node.body),
1043-
range: [node.parameters.pos - 1, result.range[1]],
1044-
loc: {
1045-
start: {
1046-
line: constructorLoc.line + 1,
1047-
column: constructorLoc.character
1048-
},
1049-
end: result.loc.end
1050-
}
1051-
};
1035+
const lastModifier = getLastModifier(node);
1036+
const constructorToken =
1037+
(lastModifier && findNextToken(lastModifier, node, ast)) ||
1038+
node.getFirstToken()!;
1039+
1040+
const constructorTokenRange = [
1041+
constructorToken.getStart(ast),
1042+
constructorToken.end
1043+
];
1044+
1045+
const constructorLoc = ast.getLineAndCharacterOfPosition(
1046+
node.parameters.pos - 1
1047+
);
10521048

1053-
const constructorIdentifierLocStart = ast.getLineAndCharacterOfPosition(
1054-
(firstConstructorToken as any).getStart(ast)
1055-
),
1056-
constructorIdentifierLocEnd = ast.getLineAndCharacterOfPosition(
1057-
(firstConstructorToken as any).getEnd(ast)
1058-
),
1059-
constructorIsComputed = !!node.name && isComputedProperty(node.name);
1049+
const constructor: ESTreeNode = {
1050+
type: AST_NODE_TYPES.FunctionExpression,
1051+
id: null,
1052+
params: convertParameters(node.parameters),
1053+
generator: false,
1054+
expression: false, // is not present in ESTreeNode
1055+
async: false,
1056+
body: convertChild(node.body),
1057+
range: [node.parameters.pos - 1, result.range[1]],
1058+
loc: {
1059+
start: {
1060+
line: constructorLoc.line + 1,
1061+
column: constructorLoc.character
1062+
},
1063+
end: result.loc.end
1064+
}
1065+
} as any;
10601066

1061-
let constructorKey;
1067+
// Process typeParameters
1068+
if (node.typeParameters && node.typeParameters.length) {
1069+
constructor.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
1070+
node.typeParameters
1071+
);
1072+
}
10621073

1063-
if (constructorIsComputed) {
1064-
constructorKey = {
1065-
type: AST_NODE_TYPES.Literal,
1066-
value: 'constructor',
1067-
raw: node.name!.getText(),
1068-
range: [
1069-
(firstConstructorToken as any).getStart(ast),
1070-
(firstConstructorToken as any).end
1071-
],
1072-
loc: {
1073-
start: {
1074-
line: constructorIdentifierLocStart.line + 1,
1075-
column: constructorIdentifierLocStart.character
1076-
},
1077-
end: {
1078-
line: constructorIdentifierLocEnd.line + 1,
1079-
column: constructorIdentifierLocEnd.character
1080-
}
1081-
}
1082-
};
1083-
} else {
1084-
constructorKey = {
1085-
type: AST_NODE_TYPES.Identifier,
1086-
name: 'constructor',
1087-
range: [
1088-
(firstConstructorToken as any).getStart(ast),
1089-
(firstConstructorToken as any).end
1090-
],
1091-
loc: {
1092-
start: {
1093-
line: constructorIdentifierLocStart.line + 1,
1094-
column: constructorIdentifierLocStart.character
1095-
},
1096-
end: {
1097-
line: constructorIdentifierLocEnd.line + 1,
1098-
column: constructorIdentifierLocEnd.character
1099-
}
1100-
}
1101-
};
1074+
// Process returnType
1075+
if (node.type) {
1076+
constructor.returnType = convertTypeAnnotation(node.type);
11021077
}
11031078

1079+
const constructorKey = {
1080+
type: AST_NODE_TYPES.Identifier,
1081+
name: 'constructor',
1082+
range: constructorTokenRange,
1083+
loc: getLocFor(constructorTokenRange[0], constructorTokenRange[1], ast)
1084+
};
1085+
1086+
const isStatic = hasModifier(SyntaxKind.StaticKeyword, node);
1087+
11041088
Object.assign(result, {
1105-
type: constructorIsAbstract
1089+
type: hasModifier(SyntaxKind.AbstractKeyword, node)
11061090
? AST_NODE_TYPES.TSAbstractMethodDefinition
11071091
: AST_NODE_TYPES.MethodDefinition,
11081092
key: constructorKey,
11091093
value: constructor,
1110-
computed: constructorIsComputed,
1111-
static: constructorIsStatic,
1112-
kind:
1113-
constructorIsStatic || constructorIsComputed
1114-
? 'method'
1115-
: 'constructor'
1094+
computed: false,
1095+
static: isStatic,
1096+
kind: isStatic ? 'method' : 'constructor'
11161097
});
11171098

11181099
const accessibility = getTSNodeAccessibility(node);

packages/typescript-estree/src/node-utils.ts

+14
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,20 @@ export function hasModifier(
156156
);
157157
}
158158

159+
/**
160+
* Get last last modifier in ast
161+
* @param node TypeScript AST node
162+
* @returns returns last modifier if present or null
163+
*/
164+
export function getLastModifier(node: ts.Node): ts.Node | null {
165+
return (
166+
(!!node.modifiers &&
167+
!!node.modifiers.length &&
168+
node.modifiers[node.modifiers.length - 1]) ||
169+
null
170+
);
171+
}
172+
159173
/**
160174
* Returns true if the given ts.Token is a comma
161175
* @param {ts.Node} token the TypeScript token

packages/typescript-estree/tests/ast-alignment/fixtures-to-test.ts

+1-19
Original file line numberDiff line numberDiff line change
@@ -386,25 +386,7 @@ tester.addFixturePatternConfig('typescript/basics', {
386386
* https://github.com/babel/babel/issues/9325
387387
*/
388388
'class-multi-line-keyword-declare',
389-
'class-multi-line-keyword-abstract',
390-
/**
391-
* There is difference in range between babel and ts-estree
392-
*/
393-
'class-with-constructor-and-modifier',
394-
/**
395-
* ts-estree: missing returnType in constructor
396-
* babel: parses it correctly
397-
*/
398-
'class-with-constructor-and-return-type',
399-
/**
400-
* ts-estree: missing typeParameters in constructor
401-
* babel: parses it correctly
402-
*/
403-
'class-with-constructor-and-type-parameters',
404-
/**
405-
* There is deference in AST between babel and ts-estree
406-
*/
407-
'object-with-typed-methods'
389+
'class-multi-line-keyword-abstract'
408390
],
409391
ignoreSourceType: [
410392
/**
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
class Foo {
2+
foo: () => boolean = (): boolean => true;
3+
bar: string = () => test;
4+
}

packages/typescript-estree/tests/lib/__snapshots__/semantic-diagnostics-enabled.ts.snap

+2
Original file line numberDiff line numberDiff line change
@@ -1920,6 +1920,8 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e
19201920

19211921
exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-private-parameter-properties.src.ts.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`;
19221922

1923+
exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-property-function.src.ts.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`;
1924+
19231925
exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-property-values.src.ts.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`;
19241926

19251927
exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" enabled fixtures/typescript/basics/class-with-protected-parameter-properties.src.ts.src 1`] = `"TEST OUTPUT: No semantic or syntactic issues found"`;

0 commit comments

Comments
 (0)