1 | <h1 align="center">TypeScript ESTree</h1>
|
2 |
|
3 | <p align="center">A parser that converts TypeScript source code into an <a href="https://github.com/estree/estree">ESTree</a>-compatible form</p>
|
4 |
|
5 | <p align="center">
|
6 | <img src="https://github.com/typescript-eslint/typescript-eslint/workflows/CI/badge.svg" alt="CI" />
|
7 | <a href="https://www.npmjs.com/package/@typescript-eslint/typescript-estree"><img src="https://img.shields.io/npm/v/@typescript-eslint/typescript-estree.svg?style=flat-square" alt="NPM Version" /></a>
|
8 | <a href="https://www.npmjs.com/package/@typescript-eslint/typescript-estree"><img src="https://img.shields.io/npm/dm/@typescript-eslint/typescript-estree.svg?style=flat-square" alt="NPM Downloads" /></a>
|
9 | </p>
|
10 |
|
11 | ## Getting Started
|
12 |
|
13 | **[You can find our Getting Started docs here](../../docs/getting-started/linting/README.md)**
|
14 |
|
15 | ## About
|
16 |
|
17 | This parser is somewhat generic and robust, and could be used to power any use-case which requires taking TypeScript source code and producing an ESTree-compatible AST.
|
18 |
|
19 | In fact, it is already used within these hyper-popular open-source projects to power their TypeScript support:
|
20 |
|
21 | - [ESLint](https://eslint.org), the pluggable linting utility for JavaScript and JSX
|
22 | - [Prettier](https://prettier.io), an opinionated code formatter
|
23 |
|
24 | ## Installation
|
25 |
|
26 | ```sh
|
27 | yarn add -D @typescript-eslint/typescript-estree
|
28 | ```
|
29 |
|
30 | ## API
|
31 |
|
32 | ### Parsing
|
33 |
|
34 | #### `parse(code, options)`
|
35 |
|
36 | Parses the given string of code with the options provided and returns an ESTree-compatible AST.
|
37 |
|
38 | ```ts
|
39 | interface ParseOptions {
|
40 | /**
|
41 | * create a top-level comments array containing all comments
|
42 | */
|
43 | comment?: boolean;
|
44 |
|
45 | /**
|
46 | * An array of modules to turn explicit debugging on for.
|
47 | * - 'typescript-eslint' is the same as setting the env var `DEBUG=typescript-eslint:*`
|
48 | * - 'eslint' is the same as setting the env var `DEBUG=eslint:*`
|
49 | * - 'typescript' is the same as setting `extendedDiagnostics: true` in your tsconfig compilerOptions
|
50 | *
|
51 | * For convenience, also supports a boolean:
|
52 | * - true === ['typescript-eslint']
|
53 | * - false === []
|
54 | */
|
55 | debugLevel?: boolean | ('typescript-eslint' | 'eslint' | 'typescript')[];
|
56 |
|
57 | /**
|
58 | * Cause the parser to error if it encounters an unknown AST node type (useful for testing).
|
59 | * This case only usually occurs when TypeScript releases new features.
|
60 | */
|
61 | errorOnUnknownASTType?: boolean;
|
62 |
|
63 | /**
|
64 | * Absolute (or relative to `cwd`) path to the file being parsed.
|
65 | */
|
66 | filePath?: string;
|
67 |
|
68 | /**
|
69 | * Enable parsing of JSX.
|
70 | * For more details, see https://www.typescriptlang.org/docs/handbook/jsx.html
|
71 | *
|
72 | * NOTE: this setting does not effect known file types (.js, .jsx, .ts, .tsx, .json) because the
|
73 | * TypeScript compiler has its own internal handling for known file extensions.
|
74 | *
|
75 | * For the exact behavior, see https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/parser#parseroptionsecmafeaturesjsx
|
76 | */
|
77 | jsx?: boolean;
|
78 |
|
79 | /**
|
80 | * Controls whether the `loc` information to each node.
|
81 | * The `loc` property is an object which contains the exact line/column the node starts/ends on.
|
82 | * This is similar to the `range` property, except it is line/column relative.
|
83 | */
|
84 | loc?: boolean;
|
85 |
|
86 | /*
|
87 | * Allows overriding of function used for logging.
|
88 | * When value is `false`, no logging will occur.
|
89 | * When value is not provided, `console.log()` will be used.
|
90 | */
|
91 | loggerFn?: Function | false;
|
92 |
|
93 | /**
|
94 | * Controls whether the `range` property is included on AST nodes.
|
95 | * The `range` property is a [number, number] which indicates the start/end index of the node in the file contents.
|
96 | * This is similar to the `loc` property, except this is the absolute index.
|
97 | */
|
98 | range?: boolean;
|
99 |
|
100 | /**
|
101 | * Set to true to create a top-level array containing all tokens from the file.
|
102 | */
|
103 | tokens?: boolean;
|
104 | }
|
105 |
|
106 | const PARSE_DEFAULT_OPTIONS: ParseOptions = {
|
107 | comment: false,
|
108 | errorOnUnknownASTType: false,
|
109 | filePath: 'estree.ts', // or 'estree.tsx', if you pass jsx: true
|
110 | jsx: false,
|
111 | loc: false,
|
112 | loggerFn: undefined,
|
113 | range: false,
|
114 | tokens: false,
|
115 | };
|
116 |
|
117 | declare function parse(
|
118 | code: string,
|
119 | options: ParseOptions = PARSE_DEFAULT_OPTIONS,
|
120 | ): TSESTree.Program;
|
121 | ```
|
122 |
|
123 | Example usage:
|
124 |
|
125 | ```js
|
126 | import { parse } from '@typescript-eslint/typescript-estree';
|
127 |
|
128 | const code = `const hello: string = 'world';`;
|
129 | const ast = parse(code, {
|
130 | loc: true,
|
131 | range: true,
|
132 | });
|
133 | ```
|
134 |
|
135 | #### `parseAndGenerateServices(code, options)`
|
136 |
|
137 | Parses the given string of code with the options provided and returns an ESTree-compatible AST. Accepts additional options which can be used to generate type information along with the AST.
|
138 |
|
139 | ```ts
|
140 | interface ParseAndGenerateServicesOptions extends ParseOptions {
|
141 | /**
|
142 | * Causes the parser to error if the TypeScript compiler returns any unexpected syntax/semantic errors.
|
143 | */
|
144 | errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;
|
145 |
|
146 | /**
|
147 | * ***EXPERIMENTAL FLAG*** - Use this at your own risk.
|
148 | *
|
149 | * Causes TS to use the source files for referenced projects instead of the compiled .d.ts files.
|
150 | * This feature is not yet optimized, and is likely to cause OOMs for medium to large projects.
|
151 | *
|
152 | * This flag REQUIRES at least TS v3.9, otherwise it does nothing.
|
153 | *
|
154 | * See: https://github.com/typescript-eslint/typescript-eslint/issues/2094
|
155 | */
|
156 | EXPERIMENTAL_useSourceOfProjectReferenceRedirect?: boolean;
|
157 |
|
158 | /**
|
159 | * When `project` is provided, this controls the non-standard file extensions which will be parsed.
|
160 | * It accepts an array of file extensions, each preceded by a `.`.
|
161 | */
|
162 | extraFileExtensions?: string[];
|
163 |
|
164 | /**
|
165 | * Absolute (or relative to `tsconfigRootDir`) path to the file being parsed.
|
166 | * When `project` is provided, this is required, as it is used to fetch the file from the TypeScript compiler's cache.
|
167 | */
|
168 | filePath?: string;
|
169 |
|
170 | /**
|
171 | * Allows the user to control whether or not two-way AST node maps are preserved
|
172 | * during the AST conversion process.
|
173 | *
|
174 | * By default: the AST node maps are NOT preserved, unless `project` has been specified,
|
175 | * in which case the maps are made available on the returned `parserServices`.
|
176 | *
|
177 | * NOTE: If `preserveNodeMaps` is explicitly set by the user, it will be respected,
|
178 | * regardless of whether or not `project` is in use.
|
179 | */
|
180 | preserveNodeMaps?: boolean;
|
181 |
|
182 | /**
|
183 | * Absolute (or relative to `tsconfigRootDir`) paths to the tsconfig(s).
|
184 | * If this is provided, type information will be returned.
|
185 | */
|
186 | project?: string | string[];
|
187 |
|
188 | /**
|
189 | * If you provide a glob (or globs) to the project option, you can use this option to ignore certain folders from
|
190 | * being matched by the globs.
|
191 | * This accepts an array of globs to ignore.
|
192 | *
|
193 | * By default, this is set to ["/node_modules/"]
|
194 | */
|
195 | projectFolderIgnoreList?: string[];
|
196 |
|
197 | /**
|
198 | * The absolute path to the root directory for all provided `project`s.
|
199 | */
|
200 | tsconfigRootDir?: string;
|
201 |
|
202 | /**
|
203 | * An array of one or more instances of TypeScript Program objects to be used for type information.
|
204 | * This overrides any program or programs that would have been computed from the `project` option.
|
205 | * All linted files must be part of the provided program(s).
|
206 | */
|
207 | programs?: Program[];
|
208 |
|
209 | /**
|
210 | ***************************************************************************************
|
211 | * IT IS RECOMMENDED THAT YOU DO NOT USE THIS OPTION, AS IT CAUSES PERFORMANCE ISSUES. *
|
212 | ***************************************************************************************
|
213 | *
|
214 | * When passed with `project`, this allows the parser to create a catch-all, default program.
|
215 | * This means that if the parser encounters a file not included in any of the provided `project`s,
|
216 | * it will not error, but will instead parse the file and its dependencies in a new program.
|
217 | */
|
218 | createDefaultProgram?: boolean;
|
219 |
|
220 | /**
|
221 | * ESLint (and therefore typescript-eslint) is used in both "single run"/one-time contexts,
|
222 | * such as an ESLint CLI invocation, and long-running sessions (such as continuous feedback
|
223 | * on a file in an IDE).
|
224 | *
|
225 | * When typescript-eslint handles TypeScript Program management behind the scenes, this distinction
|
226 | * is important because there is significant overhead to managing the so called Watch Programs
|
227 | * needed for the long-running use-case.
|
228 | *
|
229 | * When allowAutomaticSingleRunInference is enabled, we will use common heuristics to infer
|
230 | * whether or not ESLint is being used as part of a single run.
|
231 | */
|
232 | allowAutomaticSingleRunInference?: boolean;
|
233 |
|
234 | /**
|
235 | * Path to a file exporting a custom ModuleResolver.
|
236 | */
|
237 | moduleResolver?: string;
|
238 | }
|
239 |
|
240 | interface ParserServices {
|
241 | program: ts.Program;
|
242 | esTreeNodeToTSNodeMap: WeakMap<TSESTree.Node, ts.Node | ts.Token>;
|
243 | tsNodeToESTreeNodeMap: WeakMap<ts.Node | ts.Token, TSESTree.Node>;
|
244 | hasFullTypeInformation: boolean;
|
245 | }
|
246 |
|
247 | interface ParseAndGenerateServicesResult<T extends TSESTreeOptions> {
|
248 | ast: TSESTree.Program;
|
249 | services: ParserServices;
|
250 | }
|
251 |
|
252 | const PARSE_AND_GENERATE_SERVICES_DEFAULT_OPTIONS: ParseOptions = {
|
253 | ...PARSE_DEFAULT_OPTIONS,
|
254 | errorOnTypeScriptSyntacticAndSemanticIssues: false,
|
255 | extraFileExtensions: [],
|
256 | preserveNodeMaps: false, // or true, if you do not set this, but pass `project`
|
257 | project: undefined,
|
258 | projectFolderIgnoreList: ['/node_modules/'],
|
259 | tsconfigRootDir: process.cwd(),
|
260 | };
|
261 |
|
262 | declare function parseAndGenerateServices(
|
263 | code: string,
|
264 | options: ParseOptions = PARSE_DEFAULT_OPTIONS,
|
265 | ): ParseAndGenerateServicesResult;
|
266 | ```
|
267 |
|
268 | Example usage:
|
269 |
|
270 | ```js
|
271 | import { parseAndGenerateServices } from '@typescript-eslint/typescript-estree';
|
272 |
|
273 | const code = `const hello: string = 'world';`;
|
274 | const { ast, services } = parseAndGenerateServices(code, {
|
275 | filePath: '/some/path/to/file/foo.ts',
|
276 | loc: true,
|
277 | project: './tsconfig.json',
|
278 | range: true,
|
279 | });
|
280 | ```
|
281 |
|
282 | #### `parseWithNodeMaps(code, options)`
|
283 |
|
284 | Parses the given string of code with the options provided and returns both the ESTree-compatible AST as well as the node maps.
|
285 | This allows you to work with both ASTs without the overhead of types that may come with `parseAndGenerateServices`.
|
286 |
|
287 | ```ts
|
288 | interface ParseWithNodeMapsResult<T extends TSESTreeOptions> {
|
289 | ast: TSESTree.Program;
|
290 | esTreeNodeToTSNodeMap: ParserServices['esTreeNodeToTSNodeMap'];
|
291 | tsNodeToESTreeNodeMap: ParserServices['tsNodeToESTreeNodeMap'];
|
292 | }
|
293 |
|
294 | declare function parseWithNodeMaps(
|
295 | code: string,
|
296 | options: ParseOptions = PARSE_DEFAULT_OPTIONS,
|
297 | ): ParseWithNodeMapsResult;
|
298 | ```
|
299 |
|
300 | Example usage:
|
301 |
|
302 | ```js
|
303 | import { parseWithNodeMaps } from '@typescript-eslint/typescript-estree';
|
304 |
|
305 | const code = `const hello: string = 'world';`;
|
306 | const { ast, esTreeNodeToTSNodeMap, tsNodeToESTreeNodeMap } = parseWithNodeMaps(
|
307 | code,
|
308 | {
|
309 | loc: true,
|
310 | range: true,
|
311 | },
|
312 | );
|
313 | ```
|
314 |
|
315 | ### `TSESTree`, `AST_NODE_TYPES` and `AST_TOKEN_TYPES`
|
316 |
|
317 | Types for the AST produced by the parse functions.
|
318 |
|
319 | - `TSESTree` is a namespace which contains object types representing all of the AST Nodes produced by the parser.
|
320 | - `AST_NODE_TYPES` is an enum which provides the values for every single AST node's `type` property.
|
321 | - `AST_TOKEN_TYPES` is an enum which provides the values for every single AST token's `type` property.
|
322 |
|
323 | ### Utilities
|
324 |
|
325 | #### `createProgram(configFile, projectDirectory)`
|
326 |
|
327 | This serves as a utility method for users of the `ParseOptions.programs` feature to create a TypeScript program instance from a config file.
|
328 |
|
329 | ```ts
|
330 | declare function createProgram(
|
331 | configFile: string,
|
332 | projectDirectory: string = process.cwd(),
|
333 | ): import('typescript').Program;
|
334 | ```
|
335 |
|
336 | Example usage:
|
337 |
|
338 | ```js
|
339 | const tsESTree = require('@typescript-eslint/typescript-estree');
|
340 |
|
341 | const program = tsESTree.createProgram('tsconfig.json');
|
342 | const code = `const hello: string = 'world';`;
|
343 | const { ast, services } = parseAndGenerateServices(code, {
|
344 | filePath: '/some/path/to/file/foo.ts',
|
345 | loc: true,
|
346 | program,
|
347 | range: true,
|
348 | });
|
349 | ```
|
350 |
|
351 | ## Supported TypeScript Version
|
352 |
|
353 | See the [Supported TypeScript Version](../../README.md#supported-typescript-version) section in the project root.
|
354 |
|
355 | If you use a non-supported version of TypeScript, the parser will log a warning to the console.
|
356 |
|
357 | **Please ensure that you are using a supported version before submitting any issues/bug reports.**
|
358 |
|
359 | ## Reporting Issues
|
360 |
|
361 | Please check the current list of open and known issues and ensure the issue has not been reported before. When creating a new issue provide as much information about your environment as possible. This includes:
|
362 |
|
363 | - TypeScript version
|
364 | - The `typescript-estree` version
|
365 |
|
366 | ## AST Alignment Tests
|
367 |
|
368 | A couple of years after work on this parser began, the TypeScript Team at Microsoft began [officially supporting TypeScript parsing via Babel](https://blogs.msdn.microsoft.com/typescript/2018/08/27/typescript-and-babel-7/).
|
369 |
|
370 | I work closely with the TypeScript Team and we are gradually aligning the AST of this project with the one produced by Babel's parser. To that end, I have created a full test harness to compare the ASTs of the two projects which runs on every PR, please see [the code](https://github.com/typescript-eslint/typescript-eslint/tree/master/packages/typescript-estree/tests/ast-alignment) for more details.
|
371 |
|
372 | ## Debugging
|
373 |
|
374 | If you encounter a bug with the parser that you want to investigate, you can turn on the debug logging via setting the environment variable: `DEBUG=typescript-eslint:*`.
|
375 | I.e. in this repo you can run: `DEBUG=typescript-eslint:* yarn lint`.
|
376 |
|
377 | ## License
|
378 |
|
379 | TypeScript ESTree inherits from the the original TypeScript ESLint Parser license, as the majority of the work began there. It is licensed under a permissive BSD 2-clause license.
|
380 |
|
381 | ## Contributing
|
382 |
|
383 | [See the contributing guide here](../../CONTRIBUTING.md)
|