Skip to content

Commit

Permalink
feat: create new package type-utils
Browse files Browse the repository at this point in the history
move isTypeReadonly into it
  • Loading branch information
RebeccaStevens committed Nov 11, 2021
1 parent 49d6444 commit 58ec395
Show file tree
Hide file tree
Showing 30 changed files with 403 additions and 40 deletions.
1 change: 1 addition & 0 deletions .github/ISSUE_TEMPLATE.md
Expand Up @@ -73,6 +73,7 @@ i.e. eslint --ext ".ts,.js" src --debug
| `@typescript-eslint/parser` | `X.Y.Z` |
| `@typescript-eslint/typescript-estree` | `X.Y.Z` |
| `@typescript-eslint/experimental-utils` | `X.Y.Z` |
| `@typescript-eslint/type-utils` | `X.Y.Z` |
| `TypeScript` | `X.Y.Z` |
| `node` | `X.Y.Z` |
| `npm` | `X.Y.Z` |
72 changes: 72 additions & 0 deletions .github/ISSUE_TEMPLATE/typescript-eslint-type-utils.md
@@ -0,0 +1,72 @@
---
name: '@typescript-eslint/type-utils'
about: Report an issue with the '@typescript-eslint/type-utils' package
title: ''
labels: 'package: type-utils, triage'
assignees: ''
---

<!--
Please don't ignore this template.
If you ignore it, we're just going to respond asking you to fill it out, which wastes everyone's time.
The more relevant information you can include, the faster we can find the issue and fix it without asking you for more info.
-->

<!--
🚨 STOP 🚨 𝗦𝗧𝗢𝗣 🚨 𝑺𝑻𝑶𝑷 🚨
This issue template is only for problems specifically with the `@typescript-eslint/type-utils` package.
If you have a problem with a specific lint rule, please back out and select the `@typescript-eslint/eslint-plugin` template.
If you have a problem with the parser, please back out and select the `@typescript-eslint/parser` template.
-->

- [ ] I have tried restarting my IDE and the issue persists.
- [ ] I have updated to the latest version of the packages.
- [ ] I have [read the FAQ](https://github.com/typescript-eslint/typescript-eslint/blob/master/docs/getting-started/linting/FAQ.md) and my problem is not listed.

**Repro**

<!--
Include a ***minimal*** reproduction case.
The more irrelevant code/config you give, the harder it is for us to investigate.
Please consider creating an isolated reproduction repo to make it easy for the volunteer maintainers debug your issue.
-->

```TS
// your repro code case
```

**Expected Result**

<!--
What did you expect to happen?
Please be specific here - list the exact lines and messages you expect.
-->

**Actual Result**

<!--
What actually happened?
Please be specific here - list the exact lines and messages that caused errors
-->

**Additional Info**

<!--
Did eslint throw an exception?
Please run your lint again with the --debug flag, and dump the output below.
i.e. eslint --ext ".ts,.js" src --debug
-->

**Versions**

| package | version |
| ------------------------------- | ------- |
| `@typescript-eslint/type-utils` | `X.Y.Z` |
| `@typescript-eslint/type-utils` | `X.Y.Z` |
| `TypeScript` | `X.Y.Z` |
| `node` | `X.Y.Z` |
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Expand Up @@ -116,6 +116,11 @@ jobs:
env:
CI: true

- name: Run unit tests for type-utils
run: npx nx test @typescript-eslint/type-utils
env:
CI: true

- name: Run unit tests for parser
run: npx nx test @typescript-eslint/parser
env:
Expand Down Expand Up @@ -282,6 +287,11 @@ jobs:
env:
CI: true

- name: Run unit tests for type-utils
run: npx nx test @typescript-eslint/type-utils
env:
CI: true

- name: Run unit tests for parser
run: npx nx test @typescript-eslint/parser
env:
Expand Down
46 changes: 46 additions & 0 deletions .vscode/launch.json
Expand Up @@ -24,6 +24,8 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down Expand Up @@ -56,6 +58,8 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down Expand Up @@ -88,6 +92,8 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/type-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down Expand Up @@ -120,6 +126,8 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down Expand Up @@ -152,6 +160,42 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${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",
"${workspaceFolder}/packages/visitor-keys/src/index.ts",
"${workspaceFolder}/packages/visitor-keys/dist/index.js",
"${workspaceFolder}/packages/scope-manager/dist/index.js",
"${workspaceFolder}/packages/scope-manager/dist/index.js",
],
},
{
"type": "node",
"request": "launch",
"name": "Run currently opened type-utils test",
"cwd": "${workspaceFolder}/packages/type-utils/",
"program": "${workspaceFolder}/node_modules/jest/bin/jest.js",
"args": [
"--runInBand",
"--no-cache",
"--no-coverage",
"${fileBasenameNoExtension}"
],
"sourceMaps": true,
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",
"skipFiles": [
"${workspaceFolder}/packages/experimental-utils/src/index.ts",
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down Expand Up @@ -184,6 +228,8 @@
"${workspaceFolder}/packages/experimental-utils/dist/index.js",
"${workspaceFolder}/packages/experimental-utils/src/ts-estree.ts",
"${workspaceFolder}/packages/experimental-utils/dist/ts-estree.js",
"${workspaceFolder}/packages/type-utils/src/index.ts",
"${workspaceFolder}/packages/type-utils/dist/index.js",
"${workspaceFolder}/packages/parser/src/index.ts",
"${workspaceFolder}/packages/parser/dist/index.js",
"${workspaceFolder}/packages/typescript-estree/src/index.ts",
Expand Down
2 changes: 1 addition & 1 deletion docs/getting-started/plugin-development/README.md
Expand Up @@ -7,7 +7,7 @@ sidebar_label: Writing an ESLint Plugin in TypeScript
TODO:

- talk about how to setup the folder structure
- talk about how to consume `experimental-utils` to create an empty rule
- talk about how to consume `experimental-utils`/`type-utils` to create an empty rule
- talk about https://eslint.org/docs/developer-guide/selectors and how to use the strict types
- talk about how to write tests

Expand Down
2 changes: 1 addition & 1 deletion packages/ast-spec/README.md
Expand Up @@ -16,7 +16,7 @@ It includes:

**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 building an ESLint plugin, consider using [`@typescript-eslint/experimental-utils`](../experimental-utils) and [`@typescript-eslint/type-utils`](../type-utils).
If you're parsing TypeScript code, consider using [`@typescript-eslint/typescript-estree`](../typescript-estree).

## Contributing
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/package.json
Expand Up @@ -46,6 +46,7 @@
"dependencies": {
"@typescript-eslint/experimental-utils": "5.3.1",
"@typescript-eslint/scope-manager": "5.3.1",
"@typescript-eslint/type-utils": "5.3.1",
"debug": "^4.3.2",
"functional-red-black-tree": "^1.0.1",
"ignore": "^5.1.8",
Expand Down
Expand Up @@ -2,13 +2,14 @@ import {
AST_NODE_TYPES,
TSESTree,
} from '@typescript-eslint/experimental-utils';
import { ESLintTypeUtils } from '@typescript-eslint/type-utils';
import * as util from '../util';

type Options = [
{
checkParameterProperties?: boolean;
ignoreInferredTypes?: boolean;
} & util.ReadonlynessOptions,
} & ESLintTypeUtils.ReadonlynessOptions,
];
type MessageIds = 'shouldBeReadonly';

Expand All @@ -33,7 +34,7 @@ export default util.createRule<Options, MessageIds>({
ignoreInferredTypes: {
type: 'boolean',
},
...util.readonlynessOptionsSchema.properties,
...ESLintTypeUtils.readonlynessOptionsSchema.properties,
},
},
],
Expand All @@ -45,7 +46,7 @@ export default util.createRule<Options, MessageIds>({
{
checkParameterProperties: true,
ignoreInferredTypes: false,
...util.readonlynessOptionsDefaults,
...ESLintTypeUtils.readonlynessOptionsDefaults,
},
],
create(
Expand Down Expand Up @@ -97,7 +98,7 @@ export default util.createRule<Options, MessageIds>({

const tsNode = esTreeNodeToTSNodeMap.get(actualParam);
const type = checker.getTypeAtLocation(tsNode);
const isReadOnly = util.isTypeReadonly(checker, type, {
const isReadOnly = ESLintTypeUtils.isTypeReadonly(checker, type, {
treatMethodsAsReadonly: treatMethodsAsReadonly!,
});

Expand Down
12 changes: 9 additions & 3 deletions packages/eslint-plugin/src/util/explicitReturnTypeUtils.ts
@@ -1,11 +1,11 @@
import {
TSESTree,
AST_NODE_TYPES,
ESLintUtils,
TSESLint,
} from '@typescript-eslint/experimental-utils';
import { isTypeAssertion, isConstructor, isSetter } from './astUtils';
import { getFunctionHeadLoc } from './getFunctionHeadLoc';
import { nullThrows, NullThrowsReasons } from './nullThrows';

type FunctionExpression =
| TSESTree.ArrowFunctionExpression
Expand Down Expand Up @@ -187,7 +187,10 @@ function isTypedFunctionExpression(
node: FunctionExpression,
options: Options,
): boolean {
const parent = nullThrows(node.parent, NullThrowsReasons.MissingParent);
const parent = ESLintUtils.nullThrows(
node.parent,
ESLintUtils.NullThrowsReasons.MissingParent,
);

if (!options.allowTypedFunctionExpressions) {
return false;
Expand Down Expand Up @@ -215,7 +218,10 @@ function isValidFunctionExpressionReturnType(
return true;
}

const parent = nullThrows(node.parent, NullThrowsReasons.MissingParent);
const parent = ESLintUtils.nullThrows(
node.parent,
ESLintUtils.NullThrowsReasons.MissingParent,
);
if (
options.allowExpressions &&
parent.type !== AST_NODE_TYPES.VariableDeclarator &&
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/util/getESLintCoreRule.ts
@@ -1,6 +1,6 @@
import { ESLintUtils } from '@typescript-eslint/experimental-utils';
import { version } from 'eslint/package.json';
import * as semver from 'semver';
import { nullThrows } from './nullThrows';

const isESLintV8 = semver.major(version) >= 8;

Expand Down Expand Up @@ -42,7 +42,7 @@ type RuleId = keyof RuleMap;
export const getESLintCoreRule: <R extends RuleId>(ruleId: R) => RuleMap[R] =
isESLintV8
? <R extends RuleId>(ruleId: R): RuleMap[R] =>
nullThrows(
ESLintUtils.nullThrows(
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
require('eslint/use-at-your-own-risk').builtinRules.get(
ruleId,
Expand Down
29 changes: 24 additions & 5 deletions packages/eslint-plugin/src/util/index.ts
@@ -1,31 +1,50 @@
import { ESLintUtils } from '@typescript-eslint/experimental-utils';
import { ESLintTypeUtils } from '@typescript-eslint/type-utils';

export * from './astUtils';
export * from './collectUnusedVariables';
export * from './createRule';
export * from './getFunctionHeadLoc';
export * from './getThisExpression';
export * from './getWrappingFixer';
export * from './isTypeReadonly';
export * from './misc';
export * from './nullThrows';
export * from './objectIterators';
export * from './propertyTypes';
export * from './requiresQuoting';
export * from './types';

// this is done for convenience - saves migrating all of the old rules
const { applyDefault, deepMerge, isObjectNotArray, getParserServices } =
ESLintUtils;
const {
applyDefault,
deepMerge,
isObjectNotArray,
getParserServices,
nullThrows,
NullThrowsReasons,
} = ESLintUtils;
type InferMessageIdsTypeFromRule<T> =
ESLintUtils.InferMessageIdsTypeFromRule<T>;
type InferOptionsTypeFromRule<T> = ESLintUtils.InferOptionsTypeFromRule<T>;

const {
getTypeOfPropertyOfName,
isTypeReadonly,
readonlynessOptionsSchema,
readonlynessOptionsDefaults,
} = ESLintTypeUtils;
type ReadonlynessOptions = ESLintTypeUtils.ReadonlynessOptions;

export {
applyDefault,
deepMerge,
isObjectNotArray,
getParserServices,
getTypeOfPropertyOfName,
isTypeReadonly,
nullThrows,
readonlynessOptionsDefaults,
readonlynessOptionsSchema,
InferMessageIdsTypeFromRule,
InferOptionsTypeFromRule,
NullThrowsReasons,
ReadonlynessOptions,
};
3 changes: 2 additions & 1 deletion packages/eslint-plugin/tsconfig.build.json
Expand Up @@ -12,6 +12,7 @@
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../parser/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" }
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../type-utils/tsconfig.build.json" }
]
}
3 changes: 2 additions & 1 deletion packages/eslint-plugin/tsconfig.json
Expand Up @@ -8,6 +8,7 @@
"references": [
{ "path": "../experimental-utils/tsconfig.build.json" },
{ "path": "../parser/tsconfig.build.json" },
{ "path": "../scope-manager/tsconfig.build.json" }
{ "path": "../scope-manager/tsconfig.build.json" },
{ "path": "../type-utils/tsconfig.build.json" }
]
}
1 change: 1 addition & 0 deletions packages/experimental-utils/src/eslint-utils/index.ts
Expand Up @@ -5,3 +5,4 @@ export * from './InferTypesFromRule';
export * from './RuleCreator';
export * from './RuleTester';
export * from './deepMerge';
export * from './nullThrows';
4 changes: 4 additions & 0 deletions packages/type-utils/CHANGELOG.md
@@ -0,0 +1,4 @@
# Change Log

All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.

0 comments on commit 58ec395

Please sign in to comment.