typescript-eslint-parser
Advanced tools
Comparing version 0.1.0-alpha-1 to 0.1.0
/** | ||
* @fileoverview Converts TypeScript AST into ESTree format. | ||
* @author Nicholas C. Zakas | ||
* @copyright 2015 Fred K. Schott. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* @copyright jQuery Foundation and other contributors, https://jquery.org/ | ||
* MIT License | ||
*/ | ||
@@ -34,3 +15,4 @@ | ||
var ts = require("typescript"), | ||
assign = require("object-assign"); | ||
assign = require("object-assign"), | ||
unescape = require("lodash.unescape"); | ||
@@ -41,4 +23,3 @@ //------------------------------------------------------------------------------ | ||
var SyntaxKind = ts.SyntaxKind, | ||
TokenClass = ts.TokenClass; | ||
var SyntaxKind = ts.SyntaxKind; | ||
@@ -120,2 +101,7 @@ var ASSIGNMENT_OPERATORS = [ | ||
/** | ||
* Returns true if the given TSNode is a valid ESTree class member | ||
* @param {TSNode} node TypeScript AST node | ||
* @returns {boolean} is valid ESTree class member | ||
*/ | ||
function isESTreeClassMember(node) { | ||
@@ -125,2 +111,7 @@ return node.kind !== SyntaxKind.PropertyDeclaration && node.kind !== SyntaxKind.SemicolonClassElement; | ||
/** | ||
* Returns true if the given TSToken is a comma | ||
* @param {TSToken} token the TypeScript token | ||
* @returns {boolean} is comma | ||
*/ | ||
function isComma(token) { | ||
@@ -130,2 +121,7 @@ return token.kind === SyntaxKind.CommaToken; | ||
/** | ||
* Returns true if the given TSToken is the assignment operator | ||
* @param {TSToken} operator the operator token | ||
* @returns {boolean} is assignment | ||
*/ | ||
function isAssignmentOperator(operator) { | ||
@@ -135,2 +131,7 @@ return ASSIGNMENT_OPERATORS.indexOf(operator.kind) > -1; | ||
/** | ||
* Returns true if the given TSToken is a logical operator | ||
* @param {TSToken} operator the operator token | ||
* @returns {boolean} is a logical operator | ||
*/ | ||
function isLogicalOperator(operator) { | ||
@@ -140,2 +141,7 @@ return LOGICAL_OPERATORS.indexOf(operator.kind) > -1; | ||
/** | ||
* Returns the binary expression type of the given TSToken | ||
* @param {TSToken} operator the operator token | ||
* @returns {string} the binary expression type | ||
*/ | ||
function getBinaryExpressionType(operator) { | ||
@@ -151,2 +157,10 @@ if (isAssignmentOperator(operator)) { | ||
/** | ||
* Returns line and column data for the given start and end positions, | ||
* for the given AST | ||
* @param {Object} start start data | ||
* @param {Object} end end data | ||
* @param {Object} ast the AST object | ||
* @returns {Object} the loc data | ||
*/ | ||
function getLocFor(start, end, ast) { | ||
@@ -168,2 +182,9 @@ var startLoc = ast.getLineAndCharacterOfPosition(start), | ||
/** | ||
* Returns line and column data for the given ESTreeNode or ESTreeToken, | ||
* for the given AST | ||
* @param {ESTreeToken|ESTreeNode} nodeOrToken the ESTreeNode or ESTreeToken | ||
* @param {Object} ast the AST object | ||
* @returns {Object} the loc data | ||
*/ | ||
function getLoc(nodeOrToken, ast) { | ||
@@ -187,2 +208,9 @@ return getLocFor(nodeOrToken.getStart(), nodeOrToken.end, ast); | ||
/** | ||
* Fixes the exports of the given TSNode | ||
* @param {TSNode} node the TSNode | ||
* @param {Object} result result | ||
* @param {Object} ast the AST | ||
* @returns {TSNode} the TSNode with fixed exports | ||
*/ | ||
function fixExports(node, result, ast) { | ||
@@ -219,2 +247,7 @@ // check for exports | ||
/** | ||
* Extends and formats a given error object | ||
* @param {Object} error the error object | ||
* @returns {Object} converted error object | ||
*/ | ||
function convertError(error) { | ||
@@ -232,5 +265,9 @@ | ||
/** | ||
* Returns the type of a given ESTreeToken | ||
* @param {ESTreeToken} token the ESTreeToken | ||
* @returns {string} the token type | ||
*/ | ||
function getTokenType(token) { | ||
// Need two checks for keywords since some are also identifiers | ||
@@ -245,14 +282,20 @@ if (token.originalKeywordKind) { | ||
case SyntaxKind.SetKeyword: | ||
case SyntaxKind.TypeKeyword: | ||
case SyntaxKind.ModuleKeyword: | ||
return "Identifier"; | ||
default: | ||
return "Keyword" | ||
return "Keyword"; | ||
} | ||
} | ||
if (token.kind >= 68 && token.kind <= 112) { | ||
if (token.kind >= SyntaxKind.FirstKeyword && token.kind <= SyntaxKind.LastFutureReservedWord) { | ||
if (token.kind === SyntaxKind.FalseKeyword || token.kind === SyntaxKind.TrueKeyword) { | ||
return "Boolean"; | ||
} | ||
return "Keyword"; | ||
} | ||
if (token.kind >= 15 && token.kind <= 66) { | ||
if (token.kind >= SyntaxKind.FirstPunctuation && token.kind <= SyntaxKind.LastBinaryOperator) { | ||
return "Punctuator"; | ||
@@ -269,3 +312,12 @@ } | ||
case SyntaxKind.JsxText: | ||
return "JSXText"; | ||
case SyntaxKind.StringLiteral: | ||
// A TypeScript-StringLiteral token with a TypeScript-JsxAttribute or TypeScript-JsxElement parent, | ||
// must actually be an ESTree-JSXText token | ||
if (token.parent && (token.parent.kind === SyntaxKind.JsxAttribute || token.parent.kind === SyntaxKind.JsxElement)) { | ||
return "JSXText"; | ||
} | ||
return "String"; | ||
@@ -281,6 +333,21 @@ | ||
// falls through | ||
default: | ||
} | ||
// Some JSX tokens have to be determined based on their parent | ||
if (token.parent) { | ||
if (token.kind === SyntaxKind.Identifier && token.parent.kind === SyntaxKind.FirstNode) { | ||
return "JSXIdentifier"; | ||
} | ||
if (token.parent.kind >= SyntaxKind.JsxElement && token.parent.kind <= SyntaxKind.JsxAttribute) { | ||
if (token.kind === SyntaxKind.FirstNode) { | ||
return "JSXMemberExpression"; | ||
} | ||
if (token.kind === SyntaxKind.Identifier) { | ||
return "JSXIdentifier"; | ||
} | ||
} | ||
} | ||
@@ -290,2 +357,8 @@ return "Identifier"; | ||
/** | ||
* Extends and formats a given ESTreeToken, for a given AST | ||
* @param {ESTreeToken} token the ESTreeToken | ||
* @param {Object} ast the AST object | ||
* @returns {ESTreeToken} the converted ESTreeToken | ||
*/ | ||
function convertToken(token, ast) { | ||
@@ -295,3 +368,3 @@ | ||
value = ast.text.slice(start, token.end), | ||
newToken = { | ||
newToken = { | ||
type: getTokenType(token), | ||
@@ -313,2 +386,7 @@ value: value, | ||
/** | ||
* Converts all tokens for the given AST | ||
* @param {Object} ast the AST object | ||
* @returns {ESTreeToken[]} the converted ESTreeTokens | ||
*/ | ||
function convertTokens(ast) { | ||
@@ -324,3 +402,2 @@ var token = ast.getFirstToken(), | ||
} | ||
token = ts.findNextToken(token, ast); | ||
@@ -342,2 +419,8 @@ } | ||
/** | ||
* Converts a TypeScript node into an ESTree node | ||
* @param {TSNode} node the TSNode | ||
* @param {TSNode} parent the parent TSNode | ||
* @returns {ESTreeNode} the converted ESTreeNode | ||
*/ | ||
function convert(node, parent) { | ||
@@ -356,2 +439,7 @@ | ||
/** | ||
* Copies the result object into an ESTree node with just a type property. | ||
* This is used only for leaf nodes that have no other properties. | ||
* @returns {void} | ||
*/ | ||
function simplyCopy() { | ||
@@ -363,2 +451,7 @@ assign(result, { | ||
/** | ||
* Converts a TypeScript node into an ESTree node. | ||
* @param {TSNode} child the child TSNode | ||
* @returns {ESTreeNode} the converted ESTree node | ||
*/ | ||
function convertChild(child) { | ||
@@ -368,2 +461,91 @@ return convert(child, node); | ||
/** | ||
* Converts a child into a type annotation. This creates an intermediary | ||
* TypeAnnotation node to match what Flow does. | ||
* @param {TSNode} child The TypeScript AST node to convert. | ||
* @returns {ESTreeNode} The type annotation node. | ||
*/ | ||
function convertTypeAnnotation(child) { | ||
var annotation = convertChild(child); | ||
return { | ||
type: "TypeAnnotation", | ||
loc: annotation.loc, | ||
range: annotation.range, | ||
typeAnnotation: annotation | ||
}; | ||
} | ||
/** | ||
* Converts a child into a class implements node. This creates an intermediary | ||
* ClassImplements node to match what Flow does. | ||
* @param {TSNode} child The TypeScript AST node to convert. | ||
* @returns {ESTreeNode} The type annotation node. | ||
*/ | ||
function convertClassImplements(child) { | ||
var id = convertChild(child.expression); | ||
return { | ||
type: "ClassImplements", | ||
loc: id.loc, | ||
range: id.range, | ||
id: id | ||
}; | ||
} | ||
/** | ||
* For nodes that are copied directly from the TypeScript AST into | ||
* ESTree mostly as-is. The only difference is the addition of a type | ||
* property instead of a kind property. Recursively copies all children. | ||
* @returns {void} | ||
*/ | ||
function deeplyCopy() { | ||
result.type = "TS" + SyntaxKind[node.kind]; | ||
Object.keys(node).filter(function(key) { | ||
return !(/^(?:kind|parent|pos|end)$/.test(key)); | ||
}).forEach(function(key) { | ||
if (key === "type") { | ||
result.typeAnnotation = convertTypeAnnotation(node.type); | ||
} else { | ||
if (Array.isArray(node[key])) { | ||
result[key] = node[key].map(convertChild); | ||
} else if (node[key] && typeof node[key] === "object") { | ||
result[key] = convertChild(node[key]); | ||
} else { | ||
result[key] = node[key]; | ||
} | ||
} | ||
}); | ||
} | ||
/** | ||
* Converts a TypeScript JSX node.tagName into an ESTree node.name | ||
* @param {Object} tagName the tagName object from a JSX TSNode | ||
* @param {Object} ast the AST object | ||
* @returns {Object} the converted ESTree name object | ||
*/ | ||
function convertTypeScriptJSXTagNameToESTreeName(tagName) { | ||
var tagNameToken = convertToken(tagName, ast); | ||
if (tagNameToken.type === "JSXMemberExpression") { | ||
var isNestedMemberExpression = (node.tagName.left.kind === SyntaxKind.FirstNode); | ||
// Convert TSNode left and right objects into ESTreeNode object | ||
// and property objects | ||
tagNameToken.object = convertChild(node.tagName.left); | ||
tagNameToken.property = convertChild(node.tagName.right); | ||
// Assign the appropriate types | ||
tagNameToken.object.type = (isNestedMemberExpression) ? "JSXMemberExpression" : "JSXIdentifier"; | ||
tagNameToken.property.type = "JSXIdentifier"; | ||
} else { | ||
tagNameToken.name = tagNameToken.value; | ||
} | ||
delete tagNameToken.value; | ||
return tagNameToken; | ||
} | ||
switch (node.kind) { | ||
@@ -374,3 +556,3 @@ case SyntaxKind.SourceFile: | ||
body: [], | ||
sourceType: node.externalModuleIndicator ? "module": "script" | ||
sourceType: node.externalModuleIndicator ? "module" : "script" | ||
}); | ||
@@ -543,2 +725,6 @@ | ||
if (node.type) { | ||
result.returnType = convertTypeAnnotation(node.type); | ||
} | ||
// check for exports | ||
@@ -555,2 +741,6 @@ result = fixExports(node, result, ast); | ||
}); | ||
if (node.type) { | ||
result.id.typeAnnotation = convertTypeAnnotation(node.type); | ||
} | ||
break; | ||
@@ -560,6 +750,14 @@ | ||
var varStatementKind; | ||
if (node.declarationList.flags) { | ||
varStatementKind = (node.declarationList.flags === ts.NodeFlags.Let) ? "let" : "const"; | ||
} else { | ||
varStatementKind = "var"; | ||
} | ||
assign(result, { | ||
type: "VariableDeclaration", | ||
declarations: node.declarationList.declarations.map(convertChild), | ||
kind: (node.declarationList.flags ? (node.declarationList.flags === ts.NodeFlags.Let ? "let" : "const") : "var") | ||
kind: varStatementKind | ||
}); | ||
@@ -573,6 +771,15 @@ | ||
case SyntaxKind.VariableDeclarationList: | ||
var varDeclarationListKind; | ||
if (node.flags) { | ||
varDeclarationListKind = (node.flags === ts.NodeFlags.Let) ? "let" : "const"; | ||
} else { | ||
varDeclarationListKind = "var"; | ||
} | ||
assign(result, { | ||
type: "VariableDeclaration", | ||
declarations: node.declarations.map(convertChild), | ||
kind: (node.flags ? (node.flags === ts.NodeFlags.Let ? "let" : "const") : "var") | ||
kind: varDeclarationListKind | ||
}); | ||
@@ -715,2 +922,6 @@ break; | ||
if (node.type) { | ||
method.returnType = convertTypeAnnotation(node.type); | ||
} | ||
if (parent.kind === SyntaxKind.ObjectLiteralExpression) { | ||
@@ -751,3 +962,3 @@ assign(result, { | ||
var constructorIsStatic = Boolean(node.flags & ts.NodeFlags.Static), | ||
var constructorIsStatic = Boolean(node.flags & ts.NodeFlags.Static), | ||
firstConstructorToken = constructorIsStatic ? ts.findNextToken(node.getFirstToken(), ast) : node.getFirstToken(), | ||
@@ -832,2 +1043,6 @@ constructorOffset = 11, | ||
}); | ||
if (node.type) { | ||
result.returnType = convertTypeAnnotation(node.type); | ||
} | ||
break; | ||
@@ -841,9 +1056,2 @@ | ||
case SyntaxKind.SpreadElementExpression: | ||
assign(result, { | ||
type: "SpreadElement", | ||
argument: convertChild(node.expression) | ||
}); | ||
break; | ||
case SyntaxKind.ArrayBindingPattern: | ||
@@ -915,2 +1123,7 @@ assign(result, { | ||
}); | ||
if (node.type) { | ||
result.returnType = convertTypeAnnotation(node.type); | ||
} | ||
break; | ||
@@ -1015,4 +1228,12 @@ | ||
case SyntaxKind.ClassExpression: | ||
var lastClassToken = node.heritageClauses ? node.heritageClauses[node.heritageClauses.length - 1] : node.name; | ||
if (!lastClassToken) { // no name | ||
var heritageClauses = node.heritageClauses || []; | ||
var lastClassToken = heritageClauses.length ? heritageClauses[heritageClauses.length - 1] : node.name; | ||
/** | ||
* We need check for modifiers, and use the last one, as there | ||
* could be multiple before the open brace | ||
*/ | ||
if (node.modifiers && node.modifiers.length) { | ||
var lastModifier = node.modifiers[node.modifiers.length - 1]; | ||
lastClassToken = ts.findNextToken(lastModifier, ast); | ||
} else if (!lastClassToken) { // no name | ||
lastClassToken = node.getFirstToken(); | ||
@@ -1022,3 +1243,12 @@ } | ||
var openBrace = ts.findNextToken(lastClassToken, ast); | ||
var hasExtends = (heritageClauses.length && node.heritageClauses[0].token === SyntaxKind.ExtendsKeyword), | ||
superClass, | ||
hasImplements = false; | ||
if (hasExtends) { | ||
superClass = heritageClauses.shift(); | ||
} | ||
hasImplements = heritageClauses.length > 0; | ||
assign(result, { | ||
@@ -1035,3 +1265,4 @@ type: SyntaxKind[node.kind], | ||
}, | ||
superClass: (node.heritageClauses ? convertChild(node.heritageClauses[0].types[0].expression) : null), | ||
superClass: (superClass ? convertChild(superClass.types[0].expression) : null), | ||
implements: hasImplements ? heritageClauses[0].types.map(convertClassImplements) : [] | ||
}); | ||
@@ -1266,3 +1497,3 @@ | ||
type: "Literal", | ||
value: node.text, | ||
value: unescape(node.text), | ||
raw: ast.text.slice(result.range[0], result.range[1]) | ||
@@ -1295,3 +1526,4 @@ }); | ||
type: "Literal", | ||
value: "true" | ||
value: true, | ||
raw: "true" | ||
}); | ||
@@ -1303,3 +1535,4 @@ break; | ||
type: "Literal", | ||
value: "false" | ||
value: false, | ||
raw: "false" | ||
}); | ||
@@ -1311,3 +1544,4 @@ break; | ||
type: "Literal", | ||
value: "null" | ||
value: null, | ||
raw: "null" | ||
}); | ||
@@ -1321,2 +1555,121 @@ break; | ||
// JSX | ||
case SyntaxKind.JsxElement: | ||
assign(result, { | ||
type: "JSXElement", | ||
openingElement: convertChild(node.openingElement), | ||
closingElement: convertChild(node.closingElement), | ||
children: node.children.map(convertChild) | ||
}); | ||
break; | ||
case SyntaxKind.JsxSelfClosingElement: | ||
// Convert SyntaxKind.JsxSelfClosingElement to SyntaxKind.JsxOpeningElement, | ||
// TypeScript does not seem to have the idea of openingElement when tag is self-closing | ||
node.kind = SyntaxKind.JsxOpeningElement; | ||
assign(result, { | ||
type: "JSXElement", | ||
openingElement: convertChild(node), | ||
closingElement: null, | ||
children: [] | ||
}); | ||
break; | ||
case SyntaxKind.JsxOpeningElement: | ||
var openingTagName = convertTypeScriptJSXTagNameToESTreeName(node.tagName); | ||
assign(result, { | ||
type: "JSXOpeningElement", | ||
selfClosing: !(node.parent && node.parent.closingElement), | ||
name: openingTagName, | ||
attributes: node.attributes.map(convertChild) | ||
}); | ||
break; | ||
case SyntaxKind.JsxClosingElement: | ||
var closingTagName = convertTypeScriptJSXTagNameToESTreeName(node.tagName); | ||
assign(result, { | ||
type: "JSXClosingElement", | ||
name: closingTagName | ||
}); | ||
break; | ||
case SyntaxKind.JsxExpression: | ||
var eloc = ast.getLineAndCharacterOfPosition(result.range[0] + 1); | ||
var expression = (node.expression) ? convertChild(node.expression) : { | ||
type: "JSXEmptyExpression", | ||
loc: { | ||
start: { | ||
line: eloc.line + 1, | ||
column: eloc.character | ||
}, | ||
end: { | ||
line: result.loc.end.line, | ||
column: result.loc.end.column - 1 | ||
} | ||
}, | ||
range: [result.range[0] + 1, result.range[1] - 1] | ||
}; | ||
assign(result, { | ||
type: "JSXExpressionContainer", | ||
expression: expression | ||
}); | ||
break; | ||
case SyntaxKind.JsxAttribute: | ||
var attributeName = convertToken(node.name, ast); | ||
attributeName.name = attributeName.value; | ||
delete attributeName.value; | ||
assign(result, { | ||
type: "JSXAttribute", | ||
name: attributeName, | ||
value: convertChild(node.initializer) | ||
}); | ||
break; | ||
case SyntaxKind.JsxText: | ||
assign(result, { | ||
type: "Literal", | ||
value: ast.text.slice(node.pos, node.end), | ||
raw: ast.text.slice(node.pos, node.end) | ||
}); | ||
result.loc.start.column = node.pos; | ||
result.range[0] = node.pos; | ||
break; | ||
case SyntaxKind.JsxSpreadAttribute: | ||
assign(result, { | ||
type: "JSXSpreadAttribute", | ||
argument: convertChild(node.expression) | ||
}); | ||
break; | ||
case SyntaxKind.FirstNode: | ||
var jsxMemberExpressionObject = convertChild(node.left); | ||
jsxMemberExpressionObject.type = "JSXIdentifier"; | ||
delete jsxMemberExpressionObject.value; | ||
var jsxMemberExpressionProperty = convertChild(node.right); | ||
jsxMemberExpressionProperty.type = "JSXIdentifier"; | ||
delete jsxMemberExpressionObject.value; | ||
assign(result, { | ||
type: "JSXMemberExpression", | ||
object: jsxMemberExpressionObject, | ||
property: jsxMemberExpressionProperty | ||
}); | ||
break; | ||
// TypeScript specific | ||
@@ -1328,4 +1681,3 @@ | ||
default: | ||
console.log(node.kind); | ||
result = null; | ||
deeplyCopy(); | ||
} | ||
@@ -1336,4 +1688,2 @@ | ||
var estree = convert(ast); | ||
@@ -1345,4 +1695,9 @@ | ||
/** | ||
* Add the comment nodes to the AST (that were parsed separately in parser.js) | ||
* TODO: Track the progress of https://github.com/eslint/eslint/issues/6724 | ||
* regarding ESLint itself becoming responsible for attributing comment nodes | ||
*/ | ||
if (extra.comment || extra.attachComment) { | ||
estree.comments = []; | ||
estree.comments = extra.comments || []; | ||
} | ||
@@ -1349,0 +1704,0 @@ |
/** | ||
* @fileoverview The AST node types produced by the parser. | ||
* @author Nicholas C. Zakas | ||
* @copyright 2014 Nicholas C. Zakas. All rights reserved. | ||
* @copyright 2011-2013 Ariya Hidayat <ariya.hidayat@gmail.com> | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* @copyright jQuery Foundation and other contributors, https://jquery.org/ | ||
* MIT License | ||
*/ | ||
@@ -27,0 +7,0 @@ |
@@ -5,24 +5,4 @@ /** | ||
* @author Nicholas C. Zakas | ||
* @copyright 2015 Fred K. Schott. All rights reserved. | ||
* @copyright 2014 Nicholas C. Zakas. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* @copyright jQuery Foundation and other contributors, https://jquery.org/ | ||
* MIT License | ||
*/ | ||
@@ -29,0 +9,0 @@ |
/** | ||
* @fileoverview Translates tokens between Acorn format and Esprima format. | ||
* @author Nicholas C. Zakas | ||
* @copyright 2015 Nicholas C. Zakas. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* @copyright jQuery Foundation and other contributors, https://jquery.org/ | ||
* MIT License | ||
*/ | ||
@@ -26,0 +7,0 @@ /* eslint no-underscore-dangle: 0 */ |
@@ -5,5 +5,5 @@ { | ||
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>", | ||
"homepage": "https://github.com/eslint/espree", | ||
"homepage": "https://github.com/eslint/typescript-eslint-parser", | ||
"main": "parser.js", | ||
"version": "0.1.0-alpha-1", | ||
"version": "0.1.0", | ||
"files": [ | ||
@@ -16,20 +16,13 @@ "lib", | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/eslint/typescript-eslint-parser.git" | ||
}, | ||
"repository": "eslint/typescript-eslint-parser", | ||
"bugs": { | ||
"url": "https://github.com/eslint/typescript-eslint-parser/issues" | ||
}, | ||
"licenses": [ | ||
{ | ||
"type": "BSD", | ||
"url": "http://github.com/nzakas/espree/raw/master/LICENSE" | ||
} | ||
], | ||
"license": "BSD-2-Clause", | ||
"devDependencies": { | ||
"chai": "^1.10.0", | ||
"dateformat": "^1.0.11", | ||
"eslint": "^1.8.0", | ||
"eslint-config-eslint": "^1.0.1", | ||
"eslint": "^2.2.0", | ||
"eslint-config-eslint": "^3.0.0", | ||
"eslint-release": "^0.9.2", | ||
"istanbul": "~0.2.6", | ||
@@ -55,10 +48,15 @@ "leche": "^1.0.1", | ||
"lint": "node Makefile.js lint", | ||
"patch": "node Makefile.js patch", | ||
"minor": "node Makefile.js minor", | ||
"major": "node Makefile.js major" | ||
"release": "eslint-release", | ||
"ci-release": "eslint-ci-release", | ||
"gh-release": "eslint-gh-release", | ||
"alpharelease": "eslint-prerelease alpha", | ||
"betarelease": "eslint-prerelease beta" | ||
}, | ||
"dependencies": { | ||
"object-assign": "^4.0.1", | ||
"typescript": "^1.6.2" | ||
"lodash.unescape": "4.0.0", | ||
"object-assign": "^4.0.1" | ||
}, | ||
"peerDependencies": { | ||
"typescript": "^1.7.3" | ||
} | ||
} |
154
parser.js
/** | ||
* @fileoverview Parser that converts TypeScript into ESTree format. | ||
* Copyright 2015 Nicholas C. Zakas. All rights reserved. | ||
* | ||
* Redistribution and use in source and binary forms, with or without | ||
* modification, are permitted provided that the following conditions are met: | ||
* | ||
* * Redistributions of source code must retain the above copyright | ||
* notice, this list of conditions and the following disclaimer. | ||
* * Redistributions in binary form must reproduce the above copyright | ||
* notice, this list of conditions and the following disclaimer in the | ||
* documentation and/or other materials provided with the distribution. | ||
* | ||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
* ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY | ||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
* @author Nicholas C. Zakas | ||
* @copyright jQuery Foundation and other contributors, https://jquery.org/ | ||
* MIT License | ||
*/ | ||
/*eslint no-undefined:0, no-use-before-define: 0*/ | ||
/* eslint no-undefined:0, no-use-before-define: 0 */ | ||
@@ -30,11 +12,10 @@ "use strict"; | ||
var astNodeTypes = require("./lib/ast-node-types"), | ||
commentAttachment = require("./lib/comment-attachment"), | ||
TokenTranslator = require("./lib/token-translator"), | ||
acornJSX = require("acorn-jsx/inject"), | ||
ts = require("typescript"); | ||
var lookahead, | ||
extra, | ||
lastToken; | ||
var extra; | ||
/** | ||
* Resets the extra config object | ||
* @returns {void} | ||
*/ | ||
function resetExtra() { | ||
@@ -54,4 +35,57 @@ extra = { | ||
/** | ||
* Converts a TypeScript comment to an Esprima comment. | ||
* @param {boolean} block True if it's a block comment, false if not. | ||
* @param {string} text The text of the comment. | ||
* @param {int} start The index at which the comment starts. | ||
* @param {int} end The index at which the comment ends. | ||
* @param {Location} startLoc The location at which the comment starts. | ||
* @param {Location} endLoc The location at which the comment ends. | ||
* @returns {Object} The comment object. | ||
* @private | ||
*/ | ||
function convertTypeScriptCommentToEsprimaComment(block, text, start, end, startLoc, endLoc) { | ||
var comment = { | ||
type: block ? "Block" : "Line", | ||
value: text | ||
}; | ||
if (typeof start === "number") { | ||
comment.range = [start, end]; | ||
} | ||
if (typeof startLoc === "object") { | ||
comment.loc = { | ||
start: startLoc, | ||
end: endLoc | ||
}; | ||
} | ||
return comment; | ||
} | ||
/** | ||
* Returns line and column data for the given start and end positions, | ||
* for the given AST | ||
* @param {Object} start start data | ||
* @param {Object} end end data | ||
* @param {Object} ast the AST object | ||
* @returns {Object} the loc data | ||
*/ | ||
function getLocFor(start, end, ast) { | ||
var startLoc = ast.getLineAndCharacterOfPosition(start), | ||
endLoc = ast.getLineAndCharacterOfPosition(end); | ||
return { | ||
start: { | ||
line: startLoc.line + 1, | ||
column: startLoc.character | ||
}, | ||
end: { | ||
line: endLoc.line + 1, | ||
column: endLoc.character | ||
} | ||
}; | ||
} | ||
//------------------------------------------------------------------------------ | ||
@@ -61,11 +95,12 @@ // Parser | ||
/** | ||
* Parses the given source code to produce a valid AST | ||
* @param {mixed} code TypeScript code | ||
* @param {object} options configuration object for the parser | ||
* @returns {object} the AST | ||
*/ | ||
function parse(code, options) { | ||
var program, | ||
toString = String, | ||
translator, | ||
acornOptions = { | ||
ecmaVersion: 5 | ||
}; | ||
toString = String; | ||
@@ -77,3 +112,2 @@ if (typeof code !== "string" && !(code instanceof String)) { | ||
resetExtra(); | ||
commentAttachment.reset(); | ||
@@ -91,3 +125,2 @@ if (typeof options !== "undefined") { | ||
extra.tokens = []; | ||
// translator = new TokenTranslator(tt, code); | ||
} | ||
@@ -104,7 +137,13 @@ if (typeof options.comment === "boolean" && options.comment) { | ||
extra.comments = []; | ||
commentAttachment.reset(); | ||
} | ||
var FILENAME = "eslint.ts"; | ||
if (options.ecmaFeatures && typeof options.ecmaFeatures === "object") { | ||
// pass through jsx option | ||
extra.ecmaFeatures.jsx = options.ecmaFeatures.jsx; | ||
} | ||
// Even if jsx option is set in typescript compiler, filename still has to | ||
// contain .tsx file extension | ||
var FILENAME = (extra.ecmaFeatures.jsx) ? "eslint.tsx" : "eslint.ts"; | ||
var compilerHost = { | ||
@@ -142,3 +181,3 @@ fileExists: function() { | ||
var program = ts.createProgram([FILENAME], { | ||
program = ts.createProgram([FILENAME], { | ||
noResolve: true, | ||
@@ -152,10 +191,32 @@ target: ts.ScriptTarget.Latest, | ||
if (extra.attachComment || extra.comment) { | ||
acornOptions.onComment = function() { | ||
var comment = convertAcornCommentToEsprimaComment.apply(this, arguments); | ||
extra.comments.push(comment); | ||
/** | ||
* Create a TypeScript Scanner, with skipTrivia set to false so that | ||
* we can parse the comments | ||
*/ | ||
var triviaScanner = ts.createScanner(ast.languageVersion, false, 0, code); | ||
if (extra.attachComment) { | ||
commentAttachment.addComment(comment); | ||
var kind = triviaScanner.scan(); | ||
while (kind !== ts.SyntaxKind.EndOfFileToken) { | ||
if (kind !== ts.SyntaxKind.SingleLineCommentTrivia && kind !== ts.SyntaxKind.MultiLineCommentTrivia) { | ||
kind = triviaScanner.scan(); | ||
continue; | ||
} | ||
}; | ||
var isBlock = (kind === ts.SyntaxKind.MultiLineCommentTrivia); | ||
var range = { | ||
pos: triviaScanner.getTokenPos(), | ||
end: triviaScanner.getTextPos(), | ||
kind: triviaScanner.getToken() | ||
}; | ||
var comment = code.substring(range.pos, range.end); | ||
var text = comment.replace("//", "").replace("/*", "").replace("*/", ""); | ||
var loc = getLocFor(range.pos, range.end, ast); | ||
var esprimaComment = convertTypeScriptCommentToEsprimaComment(isBlock, text, range.pos, range.end, loc.start, loc.end); | ||
extra.comments.push(esprimaComment); | ||
kind = triviaScanner.scan(); | ||
} | ||
} | ||
@@ -166,2 +227,3 @@ | ||
var convert = require("./lib/ast-converter"); | ||
return convert(ast, extra); | ||
@@ -180,3 +242,3 @@ } | ||
/* istanbul ignore next */ | ||
exports.Syntax = (function () { | ||
exports.Syntax = (function() { | ||
var name, types = {}; | ||
@@ -183,0 +245,0 @@ |
# TypeScript ESLint Parser (Experimental) | ||
An parser that converts TypeScript into an [ESTree](https://github.com/estree/estree)-compatible form so it can be used in ESLint. | ||
A parser that converts TypeScript into an [ESTree](https://github.com/estree/estree)-compatible form so it can be used in ESLint. The goal is to allow TypeScript files to be parsed by ESLint (though not necessarily pass all ESLint rules). | ||
@@ -25,2 +25,11 @@ **Important:** This parser is still in the very early stages and is considered experimental. There are likely a lot of bugs. You should not rely on this in a production environment yet. | ||
## Reporting Bugs | ||
**Do not** file bugs about ESLint rule failures. This is expected because ESLint doesn't know anything about TypeScript syntax. It's likely that many ESLint rules will have failures as a result. Longer-term, it's likely we'll need to create a custom set of ESLint rules that are TypeScript-specific. | ||
Bugs should be filed for: | ||
1. TypeScript syntax that fails to parse. | ||
1. TypeScript syntax that produces an unexpected AST. | ||
## Contributing | ||
@@ -30,4 +39,2 @@ | ||
TypeScript ESLint Parser is licensed under a permissive BSD 2-clause license. | ||
## Build Commands | ||
@@ -38,10 +45,5 @@ | ||
## Development Plan | ||
## License | ||
* **Phase 1:** Full ES6 support, stripping out all TypeScript-specific syntax. | ||
* **Phase 2:** Add support for attaching comments. | ||
* **Phase 3:** Add JSX support. | ||
* **Phase 4:** Add support for top-level TypeScript syntax. | ||
* **Phase 5:** Add support for types. | ||
TypeScript ESLint Parser is licensed under a permissive BSD 2-clause license. | ||
The high-level goal is to have output that matches Espree v3.x. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No License Found
License(Experimental) License information could not be found.
Found 1 instance in 1 package
88134
9
0
1990
47
3
12
1
1
+ Addedlodash.unescape@4.0.0
+ Addedlodash.tostring@4.1.4(transitive)
+ Addedlodash.unescape@4.0.0(transitive)
- Removedtypescript@^1.6.2