From ff613e0b541fb039e27b9706b2866976bf6054d6 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 19 Nov 2022 00:52:25 -0500 Subject: [PATCH 1/6] chore: added blog article: 'ASTs and TypeScript-ESLint' --- docs/development/CUSTOM_RULES.md | 2 +- docs/development/architecture/ASTS.md | 57 --------- .../2022-12-01-asts-and-typescript-eslint.md | 118 ++++++++++++++++++ packages/website/sidebars/sidebar.base.js | 5 +- 4 files changed, 120 insertions(+), 62 deletions(-) delete mode 100644 docs/development/architecture/ASTS.md create mode 100644 packages/website/blog/2022-12-01-asts-and-typescript-eslint.md diff --git a/docs/development/CUSTOM_RULES.md b/docs/development/CUSTOM_RULES.md index f04255d00e68..183573b81093 100644 --- a/docs/development/CUSTOM_RULES.md +++ b/docs/development/CUSTOM_RULES.md @@ -5,7 +5,7 @@ title: Custom Rules --- :::important -You should be familiar with [ESLint's developer guide](https://eslint.org/docs/developer-guide) and [Development > Architecture](./architecture/asts) before writing custom rules. +You should be familiar with [ESLint's developer guide](https://eslint.org/docs/developer-guide) and [ASTs](https://typescript-eslint.io/blog/asts-and-typescript-eslint) before writing custom rules. ::: As long as you are using `@typescript-eslint/parser` as the `parser` in your ESLint configuration, custom ESLint rules generally work the same way for JavaScript and TypeScript code. diff --git a/docs/development/architecture/ASTS.md b/docs/development/architecture/ASTS.md deleted file mode 100644 index 26164c8174e1..000000000000 --- a/docs/development/architecture/ASTS.md +++ /dev/null @@ -1,57 +0,0 @@ ---- -id: asts -sidebar_label: ASTs ---- - -# Abstract Syntax Trees (ASTs) - -Parsers such as those in ESLint and TypeScript read in the text of source code and parse it into a standard format they can reason about known as an **Abstract Syntax Tree** (AST). -ASTs are called such because although they might contain information on the location of constructs within source code, they are an abstract representation that cares more about the semantic structure. - -For example, given this line of code: - -```js -1 + 2; -``` - -ESLint would natively understand it as an object like: - -```json -{ - "type": "ExpressionStatement", - "expression": { - "type": "BinaryExpression", - "left": { - "type": "Literal", - "value": 1, - "raw": "1" - }, - "operator": "+", - "right": { - "type": "Literal", - "value": 2, - "raw": "2" - } - } -} -``` - -ESLint uses an AST format known as **[`estree`]**. - -ESTree is more broadly used than just for ESLint -- it is the de facto community standard. -ESLint's built-in parser that outputs an `estree`-shaped AST is also a separate package, called **[`espree`]**. - -## AST Playground - -The [TypeScript ESLint playground](https://typescript-eslint.io/play#showAST=es) contains an AST explorer that generates an interactive AST for any code entered into the playground. -You can activate it under _Options_ > _AST Explorer_ on its left sidebar by selecting _ESTree_. - -:::note - -You can play more with various other ASTs on [astexplorer.net] and read more details on their [Wikipedia article](https://en.wikipedia.org/wiki/Abstract_syntax_tree). - -::: - -[astexplorer.net]: https://astexplorer.net -[`espree`]: https://github.com/eslint/espree -[`estree`]: https://github.com/estree/estree diff --git a/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md b/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md new file mode 100644 index 000000000000..934a21918995 --- /dev/null +++ b/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md @@ -0,0 +1,118 @@ +--- +authors: + - image_url: https://www.joshuakgoldberg.com/img/josh.jpg + name: Josh Goldberg + title: TypeScript ESLint Maintainer + url: https://github.com/JoshuaKGoldberg +description: Describing what an AST (Abstract Syntax Tree) is and why it's useful for ESLint and TypeScript tooling. +slug: asts-and-typescript-eslint +tags: [ast, abstract syntax tree, parser, parsing, prettier] +title: ASTs and TypeScript-ESLint +--- + +Programmers who work with tools like [ESLint](https://eslint.org) and [Prettier](https://prettier.io) often refer to ASTs. +But what is an AST, why is it useful for these kinds of tools, and how does that interact with ESLint and TypeScript tooling? +Let's dig in! + +## What's an AST? + +_Static analysis_ tools are those that look at code without running it. +They typically _parse_ code, or transform it from a string into a standard format they can reason about known as an **Abstract Syntax Tree** (AST). +ASTs are called such because although they might contain information on the location of constructs within source code, they are an abstract representation that cares more about the semantic structure. + +> In other words, an AST is a description of your code's syntax. + +### An Example AST + +Take this single line of code: + +```js +1 + 2; +``` + +ESLint's AST format, **[ESTree]**, would describe that line of code as an object like: + +```json +{ + "type": "ExpressionStatement", + "expression": { + "type": "BinaryExpression", + "left": { + "type": "Literal", + "value": 1, + "raw": "1" + }, + "operator": "+", + "right": { + "type": "Literal", + "value": 2, + "raw": "2" + } + } +} +``` + +Each piece of code described within an AST description is referred to as a **node**, or AST node. +Each node is given a **node type** indicating the type of code syntax it represents +That code snippet includes four nodes of the following types: + +- _ExpressionStatement_: `1 + 2;` +- _BinaryExpression_: `1 + 2` +- _Literal_: `1` +- _Literal_: `2` + +That ESTree object representation of the code is what static analysis tools such as [ESLint](https://eslint.org) and [Prettier](https://prettier.io) work with. + +## AST Formats + +ESTree is more broadly used than just for ESLint -- it is the de facto community standard. +ESLint's built-in parser that outputs an ESTree-shaped AST is also a separate package, called **[Espree]**. + +TypeScript has its own separate AST format, often referred to as the TypeScript AST. +Because TypeScript is developed separately and with different goals from ESLint, ESTree, and Espree, its AST also represents nodes differently in many cases. + +- TS's AST is optimized for its use case of parsing incomplete code and typechecking. +- ESTree is unoptimized and intended for "general purpose" use-cases of traversing the AST. + +ESLint rules are by default only given nodes in the ESTree AST format - which has no knowledge of TypeScript-specific syntax such as interfaces. +On the other hand, TypeScript's type checking APIs require nodes in the TypeScript AST format. + +### Enter TSESTree + +To resolve the incompatibilities between ESTrees and the TypeScript AST typescript-eslint provides its own [`@typescript-eslint/parser` package](https://typescript-eslint.io/architecture/Parser.mdx) which: + +1. First parses TypeScript syntax into a TypeScript AST +1. Creates an ESTree AST based on that TypeScript AST +1. Keeps track of equivalent nodes across each AST + +By creating both an ESTree AST and a TypeScript AST, the typescript-eslint parser allows ESLint rules to work with TypeScript code. +That's why the [Getting Started guide](https://typescript-eslint.io/getting-started) for typescript-eslint has you specify `parser: '@typescript-eslint/parser'` in your ESLint config! + +We commonly refer to the ESTree format that also includes TypeScript-specific syntax as **TSESTree**. + +### AST Playground + +The [TypeScript ESLint playground](https://typescript-eslint.io/play#showAST=es) contains an AST explorer that generates an interactive AST for any code entered into the playground. +You can activate it under _Options_ > _AST Explorer_ on its left sidebar by selecting the value of _AST Viewer_. + +## Further Resources + +You can play more with various other ASTs on [astexplorer.net], including those for other languages such as CSS and HTML. + +The [AST Wikipedia article](https://en.wikipedia.org/wiki/Abstract_syntax_tree) has a great deal more context and history on ASTs. + +### Glossary + +Putting together all the terms introduces in this article: + +- **AST (Abstract Syntax Tree)**: An object representation of your code's syntax. +- **Espree**: ESLint's built-in parser that outputs an ESTree-shaped AST. +- **ESTree**: The AST specification used by ESLint and other common JavaScript tools. +- **Node Type**: What kind of code syntax an AST node refers to, such as _BinaryExpression_ or _Literal_. +- **Node**: A single range of code syntax in an AST. +- **Parser**: A tool that reads in a string and outputs an AST. +- **TSESTree**: Our extension to the ESTree AST format that also includes TypeScript-specific syntax. + +[astexplorer.net]: https://astexplorer.net +[espree]: https://github.com/eslint/espree +[estree]: https://github.com/ESTree/ESTree diff --git a/packages/website/sidebars/sidebar.base.js b/packages/website/sidebars/sidebar.base.js index 81b219c541ce..fbad9c43b0a5 100644 --- a/packages/website/sidebars/sidebar.base.js +++ b/packages/website/sidebars/sidebar.base.js @@ -44,10 +44,7 @@ module.exports = { label: 'Architecture', type: 'category', collapsible: false, - items: [ - 'development/architecture/asts', - 'development/architecture/packages', - ], + items: ['development/architecture/packages'], }, 'development/custom-rules', ], From ca23cd596b0f9ec97c6f8b5660880ca53113eccc Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Sat, 19 Nov 2022 01:00:05 -0500 Subject: [PATCH 2/6] Added netlify.toml redirect --- netlify.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netlify.toml b/netlify.toml index 7ac5b9811484..8a38c2fa7772 100644 --- a/netlify.toml +++ b/netlify.toml @@ -23,3 +23,7 @@ [[redirects]] from = "/docs/linting/tslint" to = "/docs/linting/troubleshooting/tslint" + +[[redirects]] + from = "/docs/development/architecture/asts" + to = "/blog/asts-and-typescript-eslint" From 8060289b260f312d5e766960fe1c4fc07e71d2c1 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Wed, 23 Nov 2022 21:40:10 -0500 Subject: [PATCH 3/6] Update packages/website/blog/2022-12-01-asts-and-typescript-eslint.md Co-authored-by: Brad Zacher --- packages/website/blog/2022-12-01-asts-and-typescript-eslint.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md b/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md index 934a21918995..9360c6d4bb9b 100644 --- a/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md +++ b/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md @@ -65,7 +65,7 @@ That ESTree object representation of the code is what static analysis tools such ## AST Formats -ESTree is more broadly used than just for ESLint -- it is the de facto community standard. +ESTree is more broadly used than just for ESLint -- it is a popular community standard. ESLint's built-in parser that outputs an ESTree-shaped AST is also a separate package, called **[Espree]**. TypeScript has its own separate AST format, often referred to as the TypeScript AST. From 03203281be0c79a6f2e1ac530303738ee66dcc9a Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 28 Nov 2022 19:58:04 -0500 Subject: [PATCH 4/6] Pushed post release date to 12-05 --- ...escript-eslint.md => 2022-12-05-asts-and-typescript-eslint.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename packages/website/blog/{2022-12-01-asts-and-typescript-eslint.md => 2022-12-05-asts-and-typescript-eslint.md} (100%) diff --git a/packages/website/blog/2022-12-01-asts-and-typescript-eslint.md b/packages/website/blog/2022-12-05-asts-and-typescript-eslint.md similarity index 100% rename from packages/website/blog/2022-12-01-asts-and-typescript-eslint.md rename to packages/website/blog/2022-12-05-asts-and-typescript-eslint.md From edd436ee7e19e80c7fdb7ee1b8d529872b37d0b6 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 28 Nov 2022 20:06:24 -0500 Subject: [PATCH 5/6] Added more further resources --- .../website/blog/2022-12-05-asts-and-typescript-eslint.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/packages/website/blog/2022-12-05-asts-and-typescript-eslint.md b/packages/website/blog/2022-12-05-asts-and-typescript-eslint.md index 9360c6d4bb9b..17da83da75d0 100644 --- a/packages/website/blog/2022-12-05-asts-and-typescript-eslint.md +++ b/packages/website/blog/2022-12-05-asts-and-typescript-eslint.md @@ -113,6 +113,12 @@ Putting together all the terms introduces in this article: - **Parser**: A tool that reads in a string and outputs an AST. - **TSESTree**: Our extension to the ESTree AST format that also includes TypeScript-specific syntax. +### TypeScript Lint Rules and ASTs + +Interested in how these ASTs work with ESLint rules? +We collaborated with our friends at Sourcegraph on a [Tour de Source on TypeScript ESLint](https://sourcegraph.com/notebooks/Tm90ZWJvb2s6MTA2OA==). +Read on to learn how ESLint rules use ASTs to analyze code files and, thanks to `@typescript-eslint/parser`, call TypeScript's type checking APIs to analyze code. + [astexplorer.net]: https://astexplorer.net [espree]: https://github.com/eslint/espree [estree]: https://github.com/ESTree/ESTree From 500414011a76eaebd509bb3491f848c26e52b5f0 Mon Sep 17 00:00:00 2001 From: Josh Goldberg Date: Mon, 28 Nov 2022 21:03:00 -0500 Subject: [PATCH 6/6] cspell --- .cspell.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.cspell.json b/.cspell.json index f6bb6c5cd87d..47e1d390de9e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -101,6 +101,7 @@ "ruleset", "rulesets", "serializers", + "Sourcegraph", "superset", "thenables", "transpiled", @@ -108,6 +109,7 @@ "transpiling", "triaging", "tsconfigs", + "tseslint", "tsutils", "tsvfs", "typedef", @@ -116,8 +118,7 @@ "unoptimized", "unprefixed", "upsert", - "Zacher", - "tseslint" + "Zacher" ], "overrides": [ {