Skip to content

Commit

Permalink
feat: updates to constructor method node (typescript-eslint#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
armano2 authored and JamesHenry committed Jan 13, 2019
1 parent 6aa4286 commit db44073
Show file tree
Hide file tree
Showing 6 changed files with 1,313 additions and 384 deletions.
155 changes: 68 additions & 87 deletions packages/typescript-estree/src/convert.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ import {
isOptional,
findFirstMatchingToken,
unescapeStringLiteralText,
getDeclarationKind
getDeclarationKind,
getLastModifier
} from './node-utils';
import { AST_NODE_TYPES } from './ast-node-types';
import { ESTreeNode } from './temp-types-based-on-js-source';
Expand Down Expand Up @@ -923,11 +924,11 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
(openingParen as any).getStart(ast)
),
nodeIsMethod = node.kind === SyntaxKind.MethodDeclaration,
method = {
method: ESTreeNode = {
type: AST_NODE_TYPES.FunctionExpression,
id: null,
generator: !!node.asteriskToken,
expression: false,
expression: false, // ESTreeNode as ESTreeNode here
async: hasModifier(SyntaxKind.AsyncKeyword, node),
body: convertChild(node.body),
range: [node.parameters.pos - 1, result.range[1]],
Expand All @@ -938,7 +939,7 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
},
end: result.loc.end
}
};
} as any;

if (node.type) {
(method as any).returnType = convertTypeAnnotation(node.type);
Expand Down Expand Up @@ -1007,112 +1008,92 @@ export default function convert(config: ConvertConfig): ESTreeNode | null {
} else if (
!(result as any).static &&
node.name.kind === SyntaxKind.StringLiteral &&
node.name.text === 'constructor'
node.name.text === 'constructor' &&
result.type !== AST_NODE_TYPES.Property
) {
(result as any).kind = 'constructor';
}

// Process typeParameters
if (node.typeParameters && node.typeParameters.length) {
(method as any).typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
node.typeParameters
);
if (result.type !== AST_NODE_TYPES.Property) {
method.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
node.typeParameters
);
} else {
result.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
node.typeParameters
);
}
}

break;
}

// TypeScript uses this even for static methods named "constructor"
case SyntaxKind.Constructor: {
const constructorIsStatic = hasModifier(SyntaxKind.StaticKeyword, node),
constructorIsAbstract = hasModifier(SyntaxKind.AbstractKeyword, node),
firstConstructorToken = constructorIsStatic
? findNextToken(node.getFirstToken()!, ast, ast)
: node.getFirstToken(),
constructorLoc = ast.getLineAndCharacterOfPosition(
node.parameters.pos - 1
),
constructor = {
type: AST_NODE_TYPES.FunctionExpression,
id: null,
params: convertParameters(node.parameters),
generator: false,
expression: false,
async: false,
body: convertChild(node.body),
range: [node.parameters.pos - 1, result.range[1]],
loc: {
start: {
line: constructorLoc.line + 1,
column: constructorLoc.character
},
end: result.loc.end
}
};
const lastModifier = getLastModifier(node);
const constructorToken =
(lastModifier && findNextToken(lastModifier, node, ast)) ||
node.getFirstToken()!;

const constructorTokenRange = [
constructorToken.getStart(ast),
constructorToken.end
];

const constructorLoc = ast.getLineAndCharacterOfPosition(
node.parameters.pos - 1
);

const constructorIdentifierLocStart = ast.getLineAndCharacterOfPosition(
(firstConstructorToken as any).getStart(ast)
),
constructorIdentifierLocEnd = ast.getLineAndCharacterOfPosition(
(firstConstructorToken as any).getEnd(ast)
),
constructorIsComputed = !!node.name && isComputedProperty(node.name);
const constructor: ESTreeNode = {
type: AST_NODE_TYPES.FunctionExpression,
id: null,
params: convertParameters(node.parameters),
generator: false,
expression: false, // is not present in ESTreeNode
async: false,
body: convertChild(node.body),
range: [node.parameters.pos - 1, result.range[1]],
loc: {
start: {
line: constructorLoc.line + 1,
column: constructorLoc.character
},
end: result.loc.end
}
} as any;

let constructorKey;
// Process typeParameters
if (node.typeParameters && node.typeParameters.length) {
constructor.typeParameters = convertTSTypeParametersToTypeParametersDeclaration(
node.typeParameters
);
}

if (constructorIsComputed) {
constructorKey = {
type: AST_NODE_TYPES.Literal,
value: 'constructor',
raw: node.name!.getText(),
range: [
(firstConstructorToken as any).getStart(ast),
(firstConstructorToken as any).end
],
loc: {
start: {
line: constructorIdentifierLocStart.line + 1,
column: constructorIdentifierLocStart.character
},
end: {
line: constructorIdentifierLocEnd.line + 1,
column: constructorIdentifierLocEnd.character
}
}
};
} else {
constructorKey = {
type: AST_NODE_TYPES.Identifier,
name: 'constructor',
range: [
(firstConstructorToken as any).getStart(ast),
(firstConstructorToken as any).end
],
loc: {
start: {
line: constructorIdentifierLocStart.line + 1,
column: constructorIdentifierLocStart.character
},
end: {
line: constructorIdentifierLocEnd.line + 1,
column: constructorIdentifierLocEnd.character
}
}
};
// Process returnType
if (node.type) {
constructor.returnType = convertTypeAnnotation(node.type);
}

const constructorKey = {
type: AST_NODE_TYPES.Identifier,
name: 'constructor',
range: constructorTokenRange,
loc: getLocFor(constructorTokenRange[0], constructorTokenRange[1], ast)
};

const isStatic = hasModifier(SyntaxKind.StaticKeyword, node);

Object.assign(result, {
type: constructorIsAbstract
type: hasModifier(SyntaxKind.AbstractKeyword, node)
? AST_NODE_TYPES.TSAbstractMethodDefinition
: AST_NODE_TYPES.MethodDefinition,
key: constructorKey,
value: constructor,
computed: constructorIsComputed,
static: constructorIsStatic,
kind:
constructorIsStatic || constructorIsComputed
? 'method'
: 'constructor'
computed: false,
static: isStatic,
kind: isStatic ? 'method' : 'constructor'
});

const accessibility = getTSNodeAccessibility(node);
Expand Down
14 changes: 14 additions & 0 deletions packages/typescript-estree/src/node-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,20 @@ export function hasModifier(
);
}

/**
* Get last last modifier in ast
* @param node TypeScript AST node
* @returns returns last modifier if present or null
*/
export function getLastModifier(node: ts.Node): ts.Node | null {
return (
(!!node.modifiers &&
!!node.modifiers.length &&
node.modifiers[node.modifiers.length - 1]) ||
null
);
}

/**
* Returns true if the given ts.Token is a comma
* @param {ts.Node} token the TypeScript token
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -386,25 +386,7 @@ tester.addFixturePatternConfig('typescript/basics', {
* https://github.com/babel/babel/issues/9325
*/
'class-multi-line-keyword-declare',
'class-multi-line-keyword-abstract',
/**
* There is difference in range between babel and ts-estree
*/
'class-with-constructor-and-modifier',
/**
* ts-estree: missing returnType in constructor
* babel: parses it correctly
*/
'class-with-constructor-and-return-type',
/**
* ts-estree: missing typeParameters in constructor
* babel: parses it correctly
*/
'class-with-constructor-and-type-parameters',
/**
* There is deference in AST between babel and ts-estree
*/
'object-with-typed-methods'
'class-multi-line-keyword-abstract'
],
ignoreSourceType: [
/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
class Foo {
foo: () => boolean = (): boolean => true;
bar: string = () => test;
}
Original file line number Diff line number Diff line change
Expand Up @@ -1920,6 +1920,8 @@ exports[`Parse all fixtures with "errorOnTypeScriptSyntacticAndSemanticIssues" e

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"`;

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"`;

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"`;

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"`;
Expand Down
Loading

0 comments on commit db44073

Please sign in to comment.