Skip to content

Commit

Permalink
feat: split types into their own package (#2229)
Browse files Browse the repository at this point in the history
As part of the scope analysis work, I want to remove its runtime dependency on `typescript-estree`, so it doesn't need to depend on `typescript`.
It only needs a few pieces from the package; AST_NODE_TYPES, and the visitor keys.

This moves the following the to a new package, `@typescript-eslint/types`:
- `AST_NODE_TYPES`
- `AST_TOKEN_TYPES`
- `TSESTree` (aka the types for the typescript-estree AST)
- `ParserOptions` (moved out of `experimental-utils`)

This has the added bonus of getting us very close to removing the need for `parser` to depend on `experimental-utils`, which will reduce its dependency tree significantly.
  • Loading branch information
bradzacher committed Jun 25, 2020
1 parent ba41680 commit 5f45918
Show file tree
Hide file tree
Showing 39 changed files with 319 additions and 121 deletions.
10 changes: 10 additions & 0 deletions .vscode/launch.json
Expand Up @@ -28,6 +28,8 @@
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
"${workspaceFolder}/packages/typescript-estree/dist/index.js",
"${workspaceFolder}/packages/types/src/index.ts",
"${workspaceFolder}/packages/types/dist/index.js",
],
},
{
Expand All @@ -54,6 +56,8 @@
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
"${workspaceFolder}/packages/typescript-estree/dist/index.js",
"${workspaceFolder}/packages/types/src/index.ts",
"${workspaceFolder}/packages/types/dist/index.js",
],
},
{
Expand All @@ -80,6 +84,8 @@
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
"${workspaceFolder}/packages/typescript-estree/dist/index.js",
"${workspaceFolder}/packages/types/src/index.ts",
"${workspaceFolder}/packages/types/dist/index.js",
],
},
{
Expand All @@ -106,6 +112,8 @@
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
"${workspaceFolder}/packages/typescript-estree/dist/index.js",
"${workspaceFolder}/packages/types/src/index.ts",
"${workspaceFolder}/packages/types/dist/index.js",
],
},
{
Expand All @@ -132,6 +140,8 @@
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
"${workspaceFolder}/packages/typescript-estree/dist/index.js",
"${workspaceFolder}/packages/types/src/index.ts",
"${workspaceFolder}/packages/types/dist/index.js",
],
}
]
Expand Down
@@ -1,6 +1,7 @@
import { createRule } from '../util';

const TSESTREE_NAME = '@typescript-eslint/typescript-estree';
const TYPES_NAME = '@typescript-eslint/types';
const UTILS_NAME = '@typescript-eslint/experimental-utils';

/*
Expand All @@ -14,30 +15,41 @@ export default createRule({
meta: {
type: 'problem',
docs: {
description: `Enforces that eslint-plugin rules don't require anything from ${TSESTREE_NAME}`,
description: `Enforces that eslint-plugin rules don't require anything from ${TSESTREE_NAME} or ${TYPES_NAME}`,
category: 'Possible Errors',
recommended: 'error',
},
fixable: 'code',
schema: [],
messages: {
dontImportTSEStree: [
`Don't import from ${TSESTREE_NAME}. Everything you need should be available in ${UTILS_NAME}.`,
`${TSESTREE_NAME} is an indirect dependency of this package, and thus should not be used directly.`,
dontImportPackage: [
`Don't import from {{packageName}}. Everything you need should be available in ${UTILS_NAME}.`,
`{{packageName}} is an indirect dependency of this package, and thus should not be used directly.`,
].join('\n'),
},
},
defaultOptions: [],
create(context) {
return {
ImportDeclaration(node): void {
if (
typeof node.source.value === 'string' &&
node.source.value.startsWith(TSESTREE_NAME)
) {
if (typeof node.source.value !== 'string') {
return;
}

let packageName: string | null = null;
if (node.source.value.startsWith(TSESTREE_NAME)) {
packageName = TSESTREE_NAME;
} else if (node.source.value.startsWith(TYPES_NAME)) {
packageName = TYPES_NAME;
}

if (packageName != null) {
context.report({
node,
messageId: 'dontImportTSEStree',
messageId: 'dontImportPackage',
data: {
packageName,
},
fix(fixer) {
return fixer.replaceTextRange(
[node.source.range[0] + 1, node.source.range[1] - 1],
Expand Down
Expand Up @@ -19,25 +19,43 @@ ruleTester.run('no-typescript-estree-import', rule, {
import { foo } from '@typescript-eslint/typescript-estree';
import foo from '@typescript-eslint/typescript-estree';
import * as foo from '@typescript-eslint/typescript-estree';
import { foo } from '@typescript-eslint/types';
import foo from '@typescript-eslint/types';
import * as foo from '@typescript-eslint/types';
`,
output: `
import { foo } from '@typescript-eslint/experimental-utils';
import foo from '@typescript-eslint/experimental-utils';
import * as foo from '@typescript-eslint/experimental-utils';
import { foo } from '@typescript-eslint/experimental-utils';
import foo from '@typescript-eslint/experimental-utils';
import * as foo from '@typescript-eslint/experimental-utils';
`,
errors: [
{
messageId: 'dontImportTSEStree',
messageId: 'dontImportPackage',
line: 2,
},
{
messageId: 'dontImportTSEStree',
messageId: 'dontImportPackage',
line: 3,
},
{
messageId: 'dontImportTSEStree',
messageId: 'dontImportPackage',
line: 4,
},
{
messageId: 'dontImportPackage',
line: 5,
},
{
messageId: 'dontImportPackage',
line: 6,
},
{
messageId: 'dontImportPackage',
line: 7,
},
],
}),
});
22 changes: 11 additions & 11 deletions packages/experimental-utils/README.md
Expand Up @@ -20,17 +20,17 @@ Once it is stable, it will be renamed to `@typescript-eslint/util` for a `4.0.0`

## Exports

| Name | Description |
| ------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`ASTUtils`](./src/ast-utils) | Tools for operating on the ESTree AST. Also includes the [`eslint-utils`](https://www.npmjs.com/package/eslint-utils) package, correctly typed to work with the types found in `TSESTree` |
| [`ESLintUtils`](./src/eslint-utils) | Tools for creating ESLint rules with TypeScript. |
| `JSONSchema` | Types from the [`@types/json-schema`](https://www.npmjs.com/package/@types/json-schema) package, re-exported to save you having to manually import them. Also ensures you're using the same version of the types as this package. |
| [`TSESLint`](./src/ts-eslint) | Types for ESLint, correctly typed to work with the types found in `TSESTree`. |
| [`TSESLintScope`](./src/ts-eslint-scope) | The [`eslint-scope`](https://www.npmjs.com/package/eslint-scope) package, correctly typed to work with the types found in both `TSESTree` and `TSESLint` |
| [`TSESTree`](../typescript-estree/src/ts-estree/ts-estree.ts) | Types for the TypeScript flavor of ESTree created by `@typescript-eslint/typescript-estree`. |
| [`AST_NODE_TYPES`](../typescript-estree/src/ts-estree/ast-node-types.ts) | An enum with the names of every single _node_ found in `TSESTree`. |
| [`AST_TOKEN_TYPES`](../typescript-estree/src/ts-estree/ast-node-types.ts) | An enum with the names of every single _token_ found in `TSESTree`. |
| [`ParserServices`](../typescript-estree/src/parser-options.ts) | Typing for the parser services provided when parsing a file using `@typescript-eslint/typescript-estree`. |
| Name | Description |
| -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`ASTUtils`](./src/ast-utils) | Tools for operating on the ESTree AST. Also includes the [`eslint-utils`](https://www.npmjs.com/package/eslint-utils) package, correctly typed to work with the types found in `TSESTree` |
| [`ESLintUtils`](./src/eslint-utils) | Tools for creating ESLint rules with TypeScript. |
| `JSONSchema` | Types from the [`@types/json-schema`](https://www.npmjs.com/package/@types/json-schema) package, re-exported to save you having to manually import them. Also ensures you're using the same version of the types as this package. |
| [`TSESLint`](./src/ts-eslint) | Types for ESLint, correctly typed to work with the types found in `TSESTree`. |
| [`TSESLintScope`](./src/ts-eslint-scope) | The [`eslint-scope`](https://www.npmjs.com/package/eslint-scope) package, correctly typed to work with the types found in both `TSESTree` and `TSESLint` |
| [`TSESTree`](../types/src/ts-estree.ts) | Types for the TypeScript flavor of ESTree created by `@typescript-eslint/typescript-estree`. |
| [`AST_NODE_TYPES`](../types/src/ast-node-types.ts) | An enum with the names of every single _node_ found in `TSESTree`. |
| [`AST_TOKEN_TYPES`](../types/src/ast-token-types.ts) | An enum with the names of every single _token_ found in `TSESTree`. |
| [`ParserServices`](../typescript-estree/src/parser-options.ts) | Typing for the parser services provided when parsing a file using `@typescript-eslint/typescript-estree`. |

## Contributing

Expand Down
1 change: 1 addition & 0 deletions packages/experimental-utils/package.json
Expand Up @@ -40,6 +40,7 @@
},
"dependencies": {
"@types/json-schema": "^7.0.3",
"@typescript-eslint/types": "3.4.0",
"@typescript-eslint/typescript-estree": "3.4.0",
"eslint-scope": "^5.0.0",
"eslint-utils": "^2.0.0"
Expand Down
49 changes: 6 additions & 43 deletions packages/experimental-utils/src/ts-eslint/ParserOptions.ts
@@ -1,43 +1,6 @@
import { TSESTreeOptions } from '@typescript-eslint/typescript-estree';

type EcmaVersion =
| 3
| 5
| 6
| 7
| 8
| 9
| 10
| 11
| 2015
| 2016
| 2017
| 2018
| 2019
| 2020;

interface ParserOptions {
comment?: boolean;
ecmaFeatures?: {
globalReturn?: boolean;
jsx?: boolean;
};
ecmaVersion?: EcmaVersion;
// ts-estree specific
debugLevel?: TSESTreeOptions['debugLevel'];
errorOnTypeScriptSyntacticAndSemanticIssues?: boolean;
errorOnUnknownASTType?: boolean;
extraFileExtensions?: string[];
filePath?: string;
loc?: boolean;
project?: string | string[];
projectFolderIgnoreList?: (string | RegExp)[];
range?: boolean;
sourceType?: 'script' | 'module';
tokens?: boolean;
tsconfigRootDir?: string;
useJSXTextNode?: boolean;
warnOnUnsupportedTypeScriptVersion?: boolean;
}

export { EcmaVersion, ParserOptions };
export {
DebugLevel,
EcmaVersion,
ParserOptions,
SourceType,
} from '@typescript-eslint/types';
9 changes: 5 additions & 4 deletions packages/experimental-utils/src/ts-estree.ts
@@ -1,12 +1,13 @@
// for convenience's sake - export the types directly from here so consumers
// don't need to reference/install both packages in their code

// NOTE - this uses hard links inside ts-estree to avoid initialization of entire package
// via its main file (which imports typescript at runtime).
// Not every eslint-plugin written in typescript requires typescript at runtime.
export {
AST_NODE_TYPES,
AST_TOKEN_TYPES,
TSESTree,
} from '@typescript-eslint/typescript-estree/dist/ts-estree';
} from '@typescript-eslint/types';

// NOTE - this uses hard links inside ts-estree to avoid initialization of entire package
// via its main file (which imports typescript at runtime).
// Not every eslint-plugin written in typescript requires typescript at runtime.
export { ParserServices } from '@typescript-eslint/typescript-estree/dist/parser-options';
5 changes: 4 additions & 1 deletion packages/experimental-utils/tsconfig.build.json
Expand Up @@ -7,5 +7,8 @@
"resolveJsonModule": true
},
"include": ["src", "typings"],
"references": [{ "path": "../typescript-estree/tsconfig.build.json" }]
"references": [
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
}
1 change: 1 addition & 0 deletions packages/parser/package.json
Expand Up @@ -45,6 +45,7 @@
"dependencies": {
"@types/eslint-visitor-keys": "^1.0.0",
"@typescript-eslint/experimental-utils": "3.4.0",
"@typescript-eslint/types": "3.4.0",
"@typescript-eslint/typescript-estree": "3.4.0",
"eslint-visitor-keys": "^1.1.0"
},
Expand Down
9 changes: 3 additions & 6 deletions packages/parser/src/analyze-scope.ts
@@ -1,13 +1,10 @@
import {
TSESTree,
TSESLintScope,
AST_NODE_TYPES,
} from '@typescript-eslint/experimental-utils';
import { TSESLintScope } from '@typescript-eslint/experimental-utils';
import { TSESTree, AST_NODE_TYPES } from '@typescript-eslint/types';
import { visitorKeys as childVisitorKeys } from '@typescript-eslint/typescript-estree';
import { getKeys as fallback } from 'eslint-visitor-keys';

import { ParserOptions } from './parser-options';
import { ScopeManager } from './scope/scope-manager';
import { visitorKeys as childVisitorKeys } from '@typescript-eslint/typescript-estree';

/**
* Define the override function of `Scope#__define` for global augmentation.
Expand Down
4 changes: 1 addition & 3 deletions packages/parser/src/parser-options.ts
@@ -1,3 +1 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';

export type ParserOptions = TSESLint.ParserOptions;
export { ParserOptions } from '@typescript-eslint/types';
5 changes: 1 addition & 4 deletions packages/parser/src/parser.ts
@@ -1,15 +1,12 @@
import { TSESLint } from '@typescript-eslint/experimental-utils';
import { ParserOptions, TSESTree } from '@typescript-eslint/types';
import {
parseAndGenerateServices,
ParserServices,
TSESTreeOptions,
TSESTree,
visitorKeys,
} from '@typescript-eslint/typescript-estree';
import { analyzeScope } from './analyze-scope';

type ParserOptions = TSESLint.ParserOptions;

interface ParseForESLintResult {
ast: TSESTree.Program & {
range?: [number, number];
Expand Down
3 changes: 2 additions & 1 deletion packages/parser/src/scope/scope-manager.ts
@@ -1,4 +1,5 @@
import { TSESTree, TSESLintScope } from '@typescript-eslint/experimental-utils';
import { TSESLintScope } from '@typescript-eslint/experimental-utils';
import { TSESTree } from '@typescript-eslint/types';
import { EmptyFunctionScope, EnumScope } from './scopes';

/**
Expand Down
3 changes: 2 additions & 1 deletion packages/parser/src/scope/scopes.ts
@@ -1,4 +1,5 @@
import { TSESTree, TSESLintScope } from '@typescript-eslint/experimental-utils';
import { TSESLintScope } from '@typescript-eslint/experimental-utils';
import { TSESTree } from '@typescript-eslint/types';
import { ScopeManager } from './scope-manager';

/** The scope class for enum. */
Expand Down
6 changes: 2 additions & 4 deletions packages/parser/tests/lib/basics.ts
@@ -1,7 +1,5 @@
import {
AST_NODE_TYPES,
TSESLint,
} from '@typescript-eslint/experimental-utils';
import { TSESLint } from '@typescript-eslint/experimental-utils';
import { AST_NODE_TYPES } from '@typescript-eslint/types';
import fs from 'fs';
import glob from 'glob';
import * as parser from '../../src/parser';
Expand Down
5 changes: 3 additions & 2 deletions packages/parser/tsconfig.build.json
Expand Up @@ -9,7 +9,8 @@
"include": ["src"],
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" },
{ "path": "../shared-fixtures/tsconfig.build.json" }
{ "path": "../shared-fixtures/tsconfig.build.json" },
{ "path": "../types/tsconfig.build.json" },
{ "path": "../typescript-estree/tsconfig.build.json" }
]
}
21 changes: 21 additions & 0 deletions packages/types/LICENSE
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 TypeScript ESLint and other contributors

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
17 changes: 17 additions & 0 deletions packages/types/README.md
@@ -0,0 +1,17 @@
<h1 align="center">TypeScript-ESTree Types</h1>

<p align="center">
<img src="https://github.com/typescript-eslint/typescript-eslint/workflows/CI/badge.svg" alt="CI" />
<a href="https://www.npmjs.com/package/@typescript-eslint/types"><img src="https://img.shields.io/npm/v/@typescript-eslint/types.svg?style=flat-square" alt="NPM Version" /></a>
<a href="https://www.npmjs.com/package/@typescript-eslint/types"><img src="https://img.shields.io/npm/dm/@typescript-eslint/types.svg?style=flat-square" alt="NPM Downloads" /></a>
</p>

This package exists to help us reduce cycles and provide lighter-weight packages at runtime.
You probably don't want to use it directly.

If you're building an ESLint plugin, consider using [`@typescript-eslint/experimental-utils`](../experimental-utils).
If you're parsing TypeScript code, consider using [`@typescript-eslint/typescript-estree`](../typescript-estree).

## Contributing

[See the contributing guide here](../../CONTRIBUTING.md)

0 comments on commit 5f45918

Please sign in to comment.