-
-
Notifications
You must be signed in to change notification settings - Fork 75
New: Add some parserServices #415
Changes from all commits
b92dfa7
437f5c1
e779847
3298aec
300f1ca
6b2777f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -98,6 +98,12 @@ TOKEN_TO_TEXT[SyntaxKind.CaretEqualsToken] = "^="; | |
TOKEN_TO_TEXT[SyntaxKind.AtToken] = "@"; | ||
TOKEN_TO_TEXT[SyntaxKind.InKeyword] = "in"; | ||
|
||
// ASTNode => TSNode | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We refer to them as |
||
const map = new WeakMap(); | ||
|
||
// TSNode => ASTNode | ||
const reverseMap = new WeakMap(); | ||
|
||
/** | ||
* Find the first matching child based on the given sourceFile and predicate function. | ||
* @param {TSNode} node The current TSNode | ||
|
@@ -155,6 +161,8 @@ module.exports = { | |
* Expose the enum of possible TSNode `kind`s. | ||
*/ | ||
SyntaxKind, | ||
map, | ||
reverseMap, | ||
isAssignmentOperator, | ||
isLogicalOperator, | ||
getTextForTokenKind, | ||
|
@@ -553,6 +561,9 @@ function fixExports(node, result, ast) { | |
loc: getLocFor(exportKeyword.getStart(), result.range[1], ast) | ||
}; | ||
|
||
map.set(newResult, node); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per comment above I don't think these Maps need to be in node-utils at all |
||
reverseMap.set(node, newResult); | ||
|
||
if (!declarationIsDefault) { | ||
newResult.specifiers = []; | ||
newResult.source = null; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -11,7 +11,8 @@ | |
const astNodeTypes = require("./lib/ast-node-types"), | ||
ts = require("typescript"), | ||
convert = require("./lib/ast-converter"), | ||
semver = require("semver"); | ||
semver = require("semver"), | ||
nodeUtils = require("./lib/node-utils"); | ||
|
||
const SUPPORTED_TYPESCRIPT_VERSIONS = require("./package.json").devDependencies.typescript; | ||
const ACTIVE_TYPESCRIPT_VERSION = ts.version; | ||
|
@@ -44,12 +45,14 @@ function resetExtra() { | |
// Parser | ||
//------------------------------------------------------------------------------ | ||
|
||
/** @typedef {{ ast: Program, program: ts.Program }} Result */ | ||
|
||
/** | ||
* Parses the given source code to produce a valid AST | ||
* @param {mixed} code TypeScript code | ||
* @param {Object} options configuration object for the parser | ||
* @param {Object} additionalParsingContext additional internal configuration | ||
* @returns {Object} the AST | ||
* @returns {Result} the result | ||
*/ | ||
function generateAST(code, options, additionalParsingContext) { | ||
additionalParsingContext = additionalParsingContext || {}; | ||
|
@@ -176,7 +179,28 @@ function generateAST(code, options, additionalParsingContext) { | |
const ast = program.getSourceFile(FILENAME); | ||
|
||
extra.code = code; | ||
return convert(ast, extra); | ||
return { | ||
ast: convert(ast, extra), | ||
program | ||
}; | ||
} | ||
|
||
/** | ||
* Generate the `parserServices` object for a parse result | ||
* @param {Result} result The return value of `generateAST` | ||
* @returns {Object} The `parserServices` object | ||
*/ | ||
function getServices(result) { | ||
const typeChecker = result.program.getTypeChecker(); | ||
return { | ||
program: result.program, | ||
getTSNode: node => nodeUtils.map.get(node), | ||
getESNode: tsNode => nodeUtils.reverseMap.get(tsNode), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I'm a little unsure about the use-case for |
||
typeChecker, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As per my comment above about minimal API surface - why do we need a reference to the typeChecker, if we are already exposing the created Program? |
||
getType(node) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Helper functions like this could always be added later if we found that the demand is high, but again, we have already exposed everything you would need to get this yourself There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I found it really useful when I was writing a rule using this — otherwise you have to do context.parserServices.program.getTypeChecker().getTypeAtLocation(context.parserServices.getTSNode(node)) just to get the type of a node. It’s also arguably the most common use of the parser services. |
||
return typeChecker.getTypeAtLocation(nodeUtils.map.get(node)); | ||
} | ||
}; | ||
} | ||
|
||
//------------------------------------------------------------------------------ | ||
|
@@ -186,12 +210,15 @@ function generateAST(code, options, additionalParsingContext) { | |
exports.version = require("./package.json").version; | ||
|
||
exports.parse = function parse(code, options) { | ||
return generateAST(code, options, { isParseForESLint: false }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The name |
||
return generateAST(code, options, { isParseForESLint: false }).ast; | ||
}; | ||
|
||
exports.parseForESLint = function parseForESLint(code, options) { | ||
const ast = generateAST(code, options, { isParseForESLint: true }); | ||
return { ast }; | ||
const result = generateAST(code, options, { isParseForESLint: true }); | ||
return { | ||
ast: result.ast, | ||
services: getServices(result) | ||
}; | ||
}; | ||
|
||
// Deep copy. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these should come right before we return the result, that way you don't need to have two lots of them (i.e. there is no need to have them again in node-utils)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
map
andreverseMap
are not clear names IMOThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I set them when the nodes are created so that in e.g.
the
ClassDeclaration
andExportNamedDeclaration
have a TS AST node attached to them (ClassDeclaration
).