diff --git a/packages/typescript-eslint-parser/parser.js b/packages/typescript-eslint-parser/parser.js index dec3cd6e5039..995c1ebe4006 100644 --- a/packages/typescript-eslint-parser/parser.js +++ b/packages/typescript-eslint-parser/parser.js @@ -8,7 +8,7 @@ "use strict"; -const parse = require("typescript-estree").parse; +const parse = require("typescript-estree").parseAndGenerateServices; const astNodeTypes = require("typescript-estree").AST_NODE_TYPES; const traverser = require("eslint/lib/util/traverser"); const analyzeScope = require("./analyze-scope"); @@ -40,7 +40,7 @@ exports.parseForESLint = function parseForESLint(code, options) { options.sourceType = "script"; } - const ast = parse(code, options); + const { ast, services } = parse(code, options); ast.sourceType = options.sourceType; traverser.traverse(ast, { @@ -58,7 +58,7 @@ exports.parseForESLint = function parseForESLint(code, options) { }); const scopeManager = analyzeScope(ast, options); - return { ast, scopeManager, visitorKeys }; + return { ast, services, scopeManager, visitorKeys }; }; exports.parse = function(code, options) { diff --git a/packages/typescript-eslint-parser/tests/fixtures/services/isolated-file.src.ts b/packages/typescript-eslint-parser/tests/fixtures/services/isolated-file.src.ts new file mode 100644 index 000000000000..0f03f0973061 --- /dev/null +++ b/packages/typescript-eslint-parser/tests/fixtures/services/isolated-file.src.ts @@ -0,0 +1 @@ +const x = [3, 4, 5]; diff --git a/packages/typescript-eslint-parser/tests/fixtures/services/tsconfig.json b/packages/typescript-eslint-parser/tests/fixtures/services/tsconfig.json new file mode 100644 index 000000000000..914d17298c56 --- /dev/null +++ b/packages/typescript-eslint-parser/tests/fixtures/services/tsconfig.json @@ -0,0 +1,8 @@ +{ + "compilerOptions": { + "target": "es5", + "module": "commonjs", + "strict": true, + "esModuleInterop": true + } +} diff --git a/packages/typescript-eslint-parser/tests/lib/__snapshots__/services.js.snap b/packages/typescript-eslint-parser/tests/lib/__snapshots__/services.js.snap new file mode 100644 index 000000000000..d7af97b5b5dc --- /dev/null +++ b/packages/typescript-eslint-parser/tests/lib/__snapshots__/services.js.snap @@ -0,0 +1,356 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`services fixtures/isolated-file.src 1`] = ` +Object { + "body": Array [ + Object { + "declarations": Array [ + Object { + "id": Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "name": "x", + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + }, + "init": Object { + "elements": Array [ + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 1, + }, + "start": Object { + "column": 11, + "line": 1, + }, + }, + "range": Array [ + 11, + 12, + ], + "raw": "3", + "type": "Literal", + "value": 3, + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 1, + }, + "start": Object { + "column": 14, + "line": 1, + }, + }, + "range": Array [ + 14, + 15, + ], + "raw": "4", + "type": "Literal", + "value": 4, + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 1, + }, + "start": Object { + "column": 17, + "line": 1, + }, + }, + "range": Array [ + 17, + 18, + ], + "raw": "5", + "type": "Literal", + "value": 5, + }, + ], + "loc": Object { + "end": Object { + "column": 19, + "line": 1, + }, + "start": Object { + "column": 10, + "line": 1, + }, + }, + "range": Array [ + 10, + 19, + ], + "type": "ArrayExpression", + }, + "loc": Object { + "end": Object { + "column": 19, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 19, + ], + "type": "VariableDeclarator", + }, + ], + "kind": "const", + "loc": Object { + "end": Object { + "column": 20, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 20, + ], + "type": "VariableDeclaration", + }, + ], + "comments": Array [], + "loc": Object { + "end": Object { + "column": 0, + "line": 2, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 21, + ], + "sourceType": "module", + "tokens": Array [ + Object { + "loc": Object { + "end": Object { + "column": 5, + "line": 1, + }, + "start": Object { + "column": 0, + "line": 1, + }, + }, + "range": Array [ + 0, + 5, + ], + "type": "Keyword", + "value": "const", + }, + Object { + "loc": Object { + "end": Object { + "column": 7, + "line": 1, + }, + "start": Object { + "column": 6, + "line": 1, + }, + }, + "range": Array [ + 6, + 7, + ], + "type": "Identifier", + "value": "x", + }, + Object { + "loc": Object { + "end": Object { + "column": 9, + "line": 1, + }, + "start": Object { + "column": 8, + "line": 1, + }, + }, + "range": Array [ + 8, + 9, + ], + "type": "Punctuator", + "value": "=", + }, + Object { + "loc": Object { + "end": Object { + "column": 11, + "line": 1, + }, + "start": Object { + "column": 10, + "line": 1, + }, + }, + "range": Array [ + 10, + 11, + ], + "type": "Punctuator", + "value": "[", + }, + Object { + "loc": Object { + "end": Object { + "column": 12, + "line": 1, + }, + "start": Object { + "column": 11, + "line": 1, + }, + }, + "range": Array [ + 11, + 12, + ], + "type": "Numeric", + "value": "3", + }, + Object { + "loc": Object { + "end": Object { + "column": 13, + "line": 1, + }, + "start": Object { + "column": 12, + "line": 1, + }, + }, + "range": Array [ + 12, + 13, + ], + "type": "Punctuator", + "value": ",", + }, + Object { + "loc": Object { + "end": Object { + "column": 15, + "line": 1, + }, + "start": Object { + "column": 14, + "line": 1, + }, + }, + "range": Array [ + 14, + 15, + ], + "type": "Numeric", + "value": "4", + }, + Object { + "loc": Object { + "end": Object { + "column": 16, + "line": 1, + }, + "start": Object { + "column": 15, + "line": 1, + }, + }, + "range": Array [ + 15, + 16, + ], + "type": "Punctuator", + "value": ",", + }, + Object { + "loc": Object { + "end": Object { + "column": 18, + "line": 1, + }, + "start": Object { + "column": 17, + "line": 1, + }, + }, + "range": Array [ + 17, + 18, + ], + "type": "Numeric", + "value": "5", + }, + Object { + "loc": Object { + "end": Object { + "column": 19, + "line": 1, + }, + "start": Object { + "column": 18, + "line": 1, + }, + }, + "range": Array [ + 18, + 19, + ], + "type": "Punctuator", + "value": "]", + }, + Object { + "loc": Object { + "end": Object { + "column": 20, + "line": 1, + }, + "start": Object { + "column": 19, + "line": 1, + }, + }, + "range": Array [ + 19, + 20, + ], + "type": "Punctuator", + "value": ";", + }, + ], + "type": "Program", +} +`; diff --git a/packages/typescript-eslint-parser/tests/lib/services.js b/packages/typescript-eslint-parser/tests/lib/services.js new file mode 100644 index 000000000000..2c0e8b37bde0 --- /dev/null +++ b/packages/typescript-eslint-parser/tests/lib/services.js @@ -0,0 +1,53 @@ +/** + * @fileoverview Tests for TypeScript-specific constructs + * @author Benjamin Lichtman + * @copyright jQuery Foundation and other contributors, https://jquery.org/ + * MIT License + */ + +"use strict"; + +//------------------------------------------------------------------------------ +// Requirements +//------------------------------------------------------------------------------ + +const path = require("path"), + fs = require("fs"), + glob = require('glob'), + testUtils = require("../../tools/test-utils"); + +//------------------------------------------------------------------------------ +// Setup +//------------------------------------------------------------------------------ + +const FIXTURES_DIR = "./tests/fixtures/services"; +const testFiles = glob.sync(`${FIXTURES_DIR}/**/*.src.ts`); + +/** +* @param {string} filename Full path to file being tested +* @returns {Object} Config object +*/ +function createConfig(filename) { + return { + filePath: filename, + generateServices: true, + project: "./tsconfig.json", + tsconfigRootDir: path.resolve(FIXTURES_DIR) + }; +} + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +describe("services", () => { + testFiles.forEach(filename => { + const code = fs.readFileSync(filename, 'utf8'); + const config = createConfig(filename); + test(testUtils.formatSnapshotName(filename, FIXTURES_DIR, '.ts'), testUtils.createSnapshotTestBlock(code, config)); + test(`${testUtils.formatSnapshotName(filename, FIXTURES_DIR, '.ts')} services`, () => { + testUtils.testServices(code, config); + }); + }); + +}); diff --git a/packages/typescript-eslint-parser/tools/test-utils.js b/packages/typescript-eslint-parser/tools/test-utils.js index 11d6fd38008e..2f84b0938aa3 100644 --- a/packages/typescript-eslint-parser/tools/test-utils.js +++ b/packages/typescript-eslint-parser/tools/test-utils.js @@ -20,6 +20,16 @@ const parser = require("../parser"); // Private //-------------------------------------------------------------------------------- +const defaultConfig = { + loc: true, + range: true, + raw: true, + tokens: true, + comment: true, + errorOnUnknownASTType: true, + sourceType: "module" +}; + /** * Returns a raw copy of the given AST * @param {Object} ast the AST object @@ -42,15 +52,6 @@ function getRaw(ast) { * @returns {Function} callback for Jest test() block */ function createSnapshotTestBlock(code, config = {}) { - const defaultConfig = { - loc: true, - range: true, - raw: true, - tokens: true, - comment: true, - errorOnUnknownASTType: true, - sourceType: "module" - }; config = Object.assign({}, defaultConfig, config); /** @@ -79,6 +80,21 @@ function createSnapshotTestBlock(code, config = {}) { } +/** + * @param {string} code The code being parsed + * @param {Object} config The configuration object for the parser + * @returns {void} + */ +function testServices(code, config = {}) { + config = Object.assign({}, defaultConfig, config); + + const services = parser.parseForESLint(code, config).services; + expect(services).toBeDefined(); + expect(services.program).toBeDefined(); + expect(services.esTreeNodeToTSNodeMap).toBeDefined(); + expect(services.tsNodeToESTreeNodeMap).toBeDefined(); +} + function formatSnapshotName(filename, fixturesDir, fileExtension = '.js') { return `fixtures/${filename.replace(fixturesDir + '/', '').replace(fileExtension, '')}`; } @@ -86,5 +102,6 @@ function formatSnapshotName(filename, fixturesDir, fileExtension = '.js') { module.exports = { getRaw, createSnapshotTestBlock, + testServices, formatSnapshotName };