Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 36c8a52

Browse files
committed
feat: refactor to split AST specification out as its own module
Fixes typescript-eslint#2726 Fixes typescript-eslint#2912 This PR is the basis for a big cleanup and reorganisation of the AST. This first step takes the file `types/src/ts-estree.ts` and splits it up in its entirety. This file was a monolith at 1700 lines - meaning it was a pain to organise and manage, and there was no way to isolate/restrict certain things (aside from adding comments). This PR should ultimately be a no-op - there should be no breaking changes here. I did fix up a number of types which I found when organising files into their folders. Whilst this PR ultimately creates more LOC, the isolation enables a few things: - By splitting the AST into its own module, it's isolated so easier to manage / govern - By splitting each AST node into its own folder we can cleanly document and link to individual node specs - By grouping nodes decls by folder, it's easier to inspect the types to validate unions are correct. - I found a number of invalid nodes in unions in this PR which have been fixed. - In a future PR we can: - Add lint rule(s) to validate unions are correct (eg ensure all `Expression` types are included in the `Expression` union). - Easily add documentation about the node without cluttering things up - Colocate fixtures/snapshots with the node specs to document the cases that we expect a node to show up - Colocate the conversion logic here so that it's easier to validate that the spec and the conversion logic are in sync - This will make it much easier to implement and maintain typescript-eslint#1852
1 parent 9092c04 commit 36c8a52

File tree

275 files changed

+3551
-2002
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

275 files changed

+3551
-2002
lines changed

.eslintrc.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module.exports = {
77
'import',
88
'eslint-comments',
99
'@typescript-eslint/internal',
10+
'simple-import-sort',
1011
],
1112
env: {
1213
es6: true,
@@ -251,5 +252,21 @@ module.exports = {
251252
'@typescript-eslint/internal/prefer-ast-types-enum': 'off',
252253
},
253254
},
255+
// ast spec specific standardization
256+
{
257+
files: ['packages/ast-spec/src/**/*.ts'],
258+
rules: {
259+
'@typescript-eslint/consistent-type-imports': [
260+
'error',
261+
{ prefer: 'type-imports', disallowTypeAnnotations: true },
262+
],
263+
'@typescript-eslint/no-unused-vars': 'error',
264+
'@typescript-eslint/sort-type-union-intersection-members': 'error',
265+
'import/first': 'error',
266+
'import/newline-after-import': 'error',
267+
'import/no-duplicates': 'error',
268+
'simple-import-sort/imports': 'error',
269+
},
270+
},
254271
],
255272
};

.vscode/settings.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
// typescript auto-format settings
1515
"typescript.tsdk": "node_modules/typescript/lib",
16-
"javascript.preferences.importModuleSpecifier": "auto",
17-
"typescript.preferences.importModuleSpecifier": "auto",
16+
"javascript.preferences.importModuleSpecifier": "project-relative",
17+
"typescript.preferences.importModuleSpecifier": "project-relative",
1818
"javascript.preferences.quoteStyle": "single",
1919
"typescript.preferences.quoteStyle": "single",
2020
"editor.defaultFormatter": "esbenp.prettier-vscode",

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@
9292
"eslint-plugin-eslint-plugin": "^2.3.0",
9393
"eslint-plugin-import": "^2.22.0",
9494
"eslint-plugin-jest": "^23.20.0",
95+
"eslint-plugin-simple-import-sort": "^7.0.0",
9596
"glob": "^7.1.6",
9697
"husky": "^4.2.5",
9798
"isomorphic-fetch": "^2.2.1",

packages/ast-spec/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2019 TypeScript ESLint and other contributors
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

packages/ast-spec/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<h1 align="center">TypeScript-ESTree AST Specification</h1>
2+
3+
<p align="center">
4+
<img src="https://github.com/typescript-eslint/typescript-eslint/workflows/CI/badge.svg" alt="CI" />
5+
<a href="https://www.npmjs.com/package/@typescript-eslint/ast-spec"><img src="https://img.shields.io/npm/v/@typescript-eslint/ast-spec.svg?style=flat-square" alt="NPM Version" /></a>
6+
<a href="https://www.npmjs.com/package/@typescript-eslint/ast-spec"><img src="https://img.shields.io/npm/dm/@typescript-eslint/ast-spec.svg?style=flat-square" alt="NPM Downloads" /></a>
7+
</p>
8+
9+
This is the complete specification for the TypeScript-ESTree AST.
10+
11+
It includes:
12+
13+
- Node definitions as TypeScript types (the specification)
14+
- Logic for converting from the TypeScript AST to the TypeScript-ESTree AST.
15+
- Tests/Fixtures/Examples for each Node
16+
17+
**You probably don't want to use it directly.**
18+
19+
If you're building an ESLint plugin, consider using [`@typescript-eslint/experimental-utils`](../experimental-utils).
20+
If you're parsing TypeScript code, consider using [`@typescript-eslint/typescript-estree`](../typescript-estree).
21+
22+
## Contributing
23+
24+
[See the contributing guide here](../../CONTRIBUTING.md)

packages/ast-spec/jest.config.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
'use strict';
2+
3+
// @ts-check
4+
/** @type {import('@jest/types').Config.InitialOptions} */
5+
module.exports = {
6+
globals: {
7+
'ts-jest': {
8+
isolatedModules: true,
9+
},
10+
},
11+
testEnvironment: 'node',
12+
transform: {
13+
['^.+\\.tsx?$']: 'ts-jest',
14+
},
15+
testRegex: ['./tests/.+\\.test\\.ts$'],
16+
collectCoverage: false,
17+
collectCoverageFrom: ['src/**/*.{js,jsx,ts,tsx}'],
18+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
19+
coverageReporters: ['text-summary', 'lcov'],
20+
};

packages/ast-spec/package.json

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
{
2+
"name": "@typescript-eslint/ast-spec",
3+
"version": "4.11.1",
4+
"description": "Types for the TypeScript-ESTree AST spec",
5+
"keywords": [
6+
"eslint",
7+
"typescript",
8+
"estree"
9+
],
10+
"engines": {
11+
"node": "^8.10.0 || ^10.13.0 || >=11.10.1"
12+
},
13+
"files": [
14+
"dist",
15+
"package.json",
16+
"README.md",
17+
"LICENSE"
18+
],
19+
"repository": {
20+
"type": "git",
21+
"url": "https://github.com/typescript-eslint/typescript-eslint.git",
22+
"directory": "packages/ast-spec"
23+
},
24+
"bugs": {
25+
"url": "https://github.com/typescript-eslint/typescript-eslint/issues"
26+
},
27+
"license": "MIT",
28+
"main": "dist/index.js",
29+
"types": "dist/index.d.ts",
30+
"scripts": {
31+
"build": "tsc -b tsconfig.build.json",
32+
"postbuild": "downlevel-dts dist _ts3.4/dist",
33+
"clean": "tsc -b tsconfig.build.json --clean",
34+
"postclean": "rimraf dist && rimraf _ts3.4 && rimraf coverage",
35+
"format": "prettier --write \"./**/*.{ts,js,json,md}\" --ignore-path ../../.prettierignore",
36+
"generate:lib": "../../node_modules/.bin/ts-node --files --transpile-only ../scope-manager/tools/generate-lib.ts",
37+
"lint": "eslint . --ext .js,.ts --ignore-path='../../.eslintignore'",
38+
"typecheck": "tsc -p tsconfig.json --noEmit"
39+
},
40+
"funding": {
41+
"type": "opencollective",
42+
"url": "https://opencollective.com/typescript-eslint"
43+
},
44+
"typesVersions": {
45+
"<3.8": {
46+
"*": [
47+
"_ts3.4/*"
48+
]
49+
}
50+
}
51+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type { AST_NODE_TYPES } from '../ast-node-types';
2+
import type { Node } from '../unions/Node';
3+
4+
type GetKeys<T extends AST_NODE_TYPES> = keyof Extract<Node, { type: T }>;
5+
6+
type AllKeys = {
7+
readonly [T in AST_NODE_TYPES]: GetKeys<T>;
8+
};
9+
10+
type TakesString<T extends Record<string, string>> = T;
11+
12+
// @ts-expect-error: purposely unused
13+
type _Test =
14+
// forcing the test onto a new line so it isn't covered by the expect error
15+
// If there are any enum members that don't have a corresponding TSESTree.Node, then this line will error with "Type 'string | number | symbol' is not assignable to type 'string'."
16+
TakesString<AllKeys> | void;
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
export enum AST_NODE_TYPES {
2+
ArrayExpression = 'ArrayExpression',
3+
ArrayPattern = 'ArrayPattern',
4+
ArrowFunctionExpression = 'ArrowFunctionExpression',
5+
AssignmentExpression = 'AssignmentExpression',
6+
AssignmentPattern = 'AssignmentPattern',
7+
AwaitExpression = 'AwaitExpression',
8+
BinaryExpression = 'BinaryExpression',
9+
BlockStatement = 'BlockStatement',
10+
BreakStatement = 'BreakStatement',
11+
CallExpression = 'CallExpression',
12+
CatchClause = 'CatchClause',
13+
ChainExpression = 'ChainExpression',
14+
ClassBody = 'ClassBody',
15+
ClassDeclaration = 'ClassDeclaration',
16+
ClassExpression = 'ClassExpression',
17+
ClassProperty = 'ClassProperty',
18+
ConditionalExpression = 'ConditionalExpression',
19+
ContinueStatement = 'ContinueStatement',
20+
DebuggerStatement = 'DebuggerStatement',
21+
Decorator = 'Decorator',
22+
DoWhileStatement = 'DoWhileStatement',
23+
EmptyStatement = 'EmptyStatement',
24+
ExportAllDeclaration = 'ExportAllDeclaration',
25+
ExportDefaultDeclaration = 'ExportDefaultDeclaration',
26+
ExportNamedDeclaration = 'ExportNamedDeclaration',
27+
ExportSpecifier = 'ExportSpecifier',
28+
ExpressionStatement = 'ExpressionStatement',
29+
ForInStatement = 'ForInStatement',
30+
ForOfStatement = 'ForOfStatement',
31+
ForStatement = 'ForStatement',
32+
FunctionDeclaration = 'FunctionDeclaration',
33+
FunctionExpression = 'FunctionExpression',
34+
Identifier = 'Identifier',
35+
IfStatement = 'IfStatement',
36+
ImportDeclaration = 'ImportDeclaration',
37+
ImportDefaultSpecifier = 'ImportDefaultSpecifier',
38+
ImportExpression = 'ImportExpression',
39+
ImportNamespaceSpecifier = 'ImportNamespaceSpecifier',
40+
ImportSpecifier = 'ImportSpecifier',
41+
JSXAttribute = 'JSXAttribute',
42+
JSXClosingElement = 'JSXClosingElement',
43+
JSXClosingFragment = 'JSXClosingFragment',
44+
JSXElement = 'JSXElement',
45+
JSXEmptyExpression = 'JSXEmptyExpression',
46+
JSXExpressionContainer = 'JSXExpressionContainer',
47+
JSXFragment = 'JSXFragment',
48+
JSXIdentifier = 'JSXIdentifier',
49+
JSXMemberExpression = 'JSXMemberExpression',
50+
JSXOpeningElement = 'JSXOpeningElement',
51+
JSXOpeningFragment = 'JSXOpeningFragment',
52+
JSXSpreadAttribute = 'JSXSpreadAttribute',
53+
JSXSpreadChild = 'JSXSpreadChild',
54+
JSXText = 'JSXText',
55+
LabeledStatement = 'LabeledStatement',
56+
Literal = 'Literal',
57+
LogicalExpression = 'LogicalExpression',
58+
MemberExpression = 'MemberExpression',
59+
MetaProperty = 'MetaProperty',
60+
MethodDefinition = 'MethodDefinition',
61+
NewExpression = 'NewExpression',
62+
ObjectExpression = 'ObjectExpression',
63+
ObjectPattern = 'ObjectPattern',
64+
Program = 'Program',
65+
Property = 'Property',
66+
RestElement = 'RestElement',
67+
ReturnStatement = 'ReturnStatement',
68+
SequenceExpression = 'SequenceExpression',
69+
SpreadElement = 'SpreadElement',
70+
Super = 'Super',
71+
SwitchCase = 'SwitchCase',
72+
SwitchStatement = 'SwitchStatement',
73+
TaggedTemplateExpression = 'TaggedTemplateExpression',
74+
TemplateElement = 'TemplateElement',
75+
TemplateLiteral = 'TemplateLiteral',
76+
ThisExpression = 'ThisExpression',
77+
ThrowStatement = 'ThrowStatement',
78+
TryStatement = 'TryStatement',
79+
UnaryExpression = 'UnaryExpression',
80+
UpdateExpression = 'UpdateExpression',
81+
VariableDeclaration = 'VariableDeclaration',
82+
VariableDeclarator = 'VariableDeclarator',
83+
WhileStatement = 'WhileStatement',
84+
WithStatement = 'WithStatement',
85+
YieldExpression = 'YieldExpression',
86+
/**
87+
* TS-prefixed nodes
88+
*/
89+
TSAbstractClassProperty = 'TSAbstractClassProperty',
90+
TSAbstractKeyword = 'TSAbstractKeyword',
91+
TSAbstractMethodDefinition = 'TSAbstractMethodDefinition',
92+
TSAnyKeyword = 'TSAnyKeyword',
93+
TSArrayType = 'TSArrayType',
94+
TSAsExpression = 'TSAsExpression',
95+
TSAsyncKeyword = 'TSAsyncKeyword',
96+
TSBigIntKeyword = 'TSBigIntKeyword',
97+
TSBooleanKeyword = 'TSBooleanKeyword',
98+
TSCallSignatureDeclaration = 'TSCallSignatureDeclaration',
99+
TSClassImplements = 'TSClassImplements',
100+
TSConditionalType = 'TSConditionalType',
101+
TSConstructorType = 'TSConstructorType',
102+
TSConstructSignatureDeclaration = 'TSConstructSignatureDeclaration',
103+
TSDeclareFunction = 'TSDeclareFunction',
104+
TSDeclareKeyword = 'TSDeclareKeyword',
105+
TSEmptyBodyFunctionExpression = 'TSEmptyBodyFunctionExpression',
106+
TSEnumDeclaration = 'TSEnumDeclaration',
107+
TSEnumMember = 'TSEnumMember',
108+
TSExportAssignment = 'TSExportAssignment',
109+
TSExportKeyword = 'TSExportKeyword',
110+
TSExternalModuleReference = 'TSExternalModuleReference',
111+
TSFunctionType = 'TSFunctionType',
112+
TSImportEqualsDeclaration = 'TSImportEqualsDeclaration',
113+
TSImportType = 'TSImportType',
114+
TSIndexedAccessType = 'TSIndexedAccessType',
115+
TSIndexSignature = 'TSIndexSignature',
116+
TSInferType = 'TSInferType',
117+
TSInterfaceBody = 'TSInterfaceBody',
118+
TSInterfaceDeclaration = 'TSInterfaceDeclaration',
119+
TSInterfaceHeritage = 'TSInterfaceHeritage',
120+
TSIntersectionType = 'TSIntersectionType',
121+
TSLiteralType = 'TSLiteralType',
122+
TSMappedType = 'TSMappedType',
123+
TSMethodSignature = 'TSMethodSignature',
124+
TSModuleBlock = 'TSModuleBlock',
125+
TSModuleDeclaration = 'TSModuleDeclaration',
126+
TSNamedTupleMember = 'TSNamedTupleMember',
127+
TSNamespaceExportDeclaration = 'TSNamespaceExportDeclaration',
128+
TSNeverKeyword = 'TSNeverKeyword',
129+
TSNonNullExpression = 'TSNonNullExpression',
130+
TSNullKeyword = 'TSNullKeyword',
131+
TSNumberKeyword = 'TSNumberKeyword',
132+
TSObjectKeyword = 'TSObjectKeyword',
133+
TSOptionalType = 'TSOptionalType',
134+
TSParameterProperty = 'TSParameterProperty',
135+
TSParenthesizedType = 'TSParenthesizedType',
136+
TSPrivateKeyword = 'TSPrivateKeyword',
137+
TSPropertySignature = 'TSPropertySignature',
138+
TSProtectedKeyword = 'TSProtectedKeyword',
139+
TSPublicKeyword = 'TSPublicKeyword',
140+
TSQualifiedName = 'TSQualifiedName',
141+
TSReadonlyKeyword = 'TSReadonlyKeyword',
142+
TSRestType = 'TSRestType',
143+
TSStaticKeyword = 'TSStaticKeyword',
144+
TSStringKeyword = 'TSStringKeyword',
145+
TSSymbolKeyword = 'TSSymbolKeyword',
146+
TSTemplateLiteralType = 'TSTemplateLiteralType',
147+
TSThisType = 'TSThisType',
148+
TSTupleType = 'TSTupleType',
149+
TSTypeAliasDeclaration = 'TSTypeAliasDeclaration',
150+
TSTypeAnnotation = 'TSTypeAnnotation',
151+
TSTypeAssertion = 'TSTypeAssertion',
152+
TSTypeLiteral = 'TSTypeLiteral',
153+
TSTypeOperator = 'TSTypeOperator',
154+
TSTypeParameter = 'TSTypeParameter',
155+
TSTypeParameterDeclaration = 'TSTypeParameterDeclaration',
156+
TSTypeParameterInstantiation = 'TSTypeParameterInstantiation',
157+
TSTypePredicate = 'TSTypePredicate',
158+
TSTypeQuery = 'TSTypeQuery',
159+
TSTypeReference = 'TSTypeReference',
160+
TSUndefinedKeyword = 'TSUndefinedKeyword',
161+
TSUnionType = 'TSUnionType',
162+
TSUnknownKeyword = 'TSUnknownKeyword',
163+
TSVoidKeyword = 'TSVoidKeyword',
164+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export enum AST_TOKEN_TYPES {
2+
Boolean = 'Boolean',
3+
Identifier = 'Identifier',
4+
JSXIdentifier = 'JSXIdentifier',
5+
JSXText = 'JSXText',
6+
Keyword = 'Keyword',
7+
Null = 'Null',
8+
Numeric = 'Numeric',
9+
Punctuator = 'Punctuator',
10+
RegularExpression = 'RegularExpression',
11+
String = 'String',
12+
Template = 'Template',
13+
14+
// comment types
15+
Block = 'Block',
16+
Line = 'Line',
17+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export type Accessibility = 'private' | 'protected' | 'public';
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
// import type { Node } from '../unions/Node';
2+
import type { Range } from './Range';
3+
import type { SourceLocation } from './SourceLocation';
4+
5+
export interface BaseNode {
6+
/**
7+
* The source location information of the node.
8+
* @see {SourceLocation}
9+
*/
10+
loc: SourceLocation;
11+
/**
12+
* @see {Range}
13+
*/
14+
range: Range;
15+
/**
16+
* The parent node of the current node
17+
*/
18+
// parent?: Node;
19+
20+
// every node *will* have a type, but let the nodes define their own exact string
21+
// type: string;
22+
}

0 commit comments

Comments
 (0)