Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(eslint-plugin): added new rule promise-function-async#194

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
13 commits
Select commitHold shift + click to select a range
e132cac
feat: (eslint-plugin) added new rule await-promise
Feb 3, 2019
34d72fd
Merge branch 'master' into typescript-eslint-promise-function-async
Feb 3, 2019
336d231
Merge branch master; moved util to its own file
Feb 3, 2019
eed1310
Corrected containsTypeByName to be able to reference itself
Feb 3, 2019
64788ca
Merge branch 'master'
Feb 3, 2019
0d85213
Fixed more merge conflicts...
Feb 3, 2019
c2fe169
Merge branch 'master'
Feb 3, 2019
c45499e
Update packages/eslint-plugin/lib/rules/promise-function-async.js
bradzacherFeb 5, 2019
1a4d17d
Fixed formatting post-suggestion
Feb 5, 2019
a1f4554
Simplified explanations
Feb 5, 2019
d362386
Merge branch 'master' into typescript-eslint-promise-function-async
Feb 5, 2019
ea0dd69
Merge branch 'master' into typescript-eslint-promise-function-async
JamesHenryFeb 7, 2019
131a158
Merge branch 'master' into typescript-eslint-promise-function-async
bradzacherFeb 7, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletionspackages/eslint-plugin/README.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -145,6 +145,7 @@ Then you should add `airbnb` (or `airbnb-base`) to your `extends` section of `.e
| [`@typescript-eslint/no-var-requires`](./docs/rules/no-var-requires.md) | Disallows the use of require statements except in import statements (`no-var-requires` from TSLint) | :heavy_check_mark: | |
| [`@typescript-eslint/prefer-interface`](./docs/rules/prefer-interface.md) | Prefer an interface declaration over a type literal (type T = { ... }) (`interface-over-type-literal` from TSLint) | :heavy_check_mark: | :wrench: |
| [`@typescript-eslint/prefer-namespace-keyword`](./docs/rules/prefer-namespace-keyword.md) | Require the use of the `namespace` keyword instead of the `module` keyword to declare custom TypeScript modules. (`no-internal-module` from TSLint) | :heavy_check_mark: | :wrench: |
| [`@typescript-eslint/promise-function-async`](./docs/rules/promise-function-async.md) | Requires any function or method that returns a Promise to be marked async. (`promise-function-async` from TSLint) | :heavy_check_mark: | |
| [`@typescript-eslint/restrict-plus-operands`](./docs/rules/restrict-plus-operands.md) | When adding two variables, operands must both be of type number or of type string. (`restrict-plus-operands` from TSLint) | | |
| [`@typescript-eslint/type-annotation-spacing`](./docs/rules/type-annotation-spacing.md) | Require consistent spacing around type annotations (`typedef-whitespace` from TSLint) | :heavy_check_mark: | :wrench: |

Expand Down
2 changes: 1 addition & 1 deletionpackages/eslint-plugin/ROADMAP.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,7 +30,7 @@
| [`no-var-requires`] | ✅ | [`@typescript-eslint/no-var-requires`] |
| [`only-arrow-functions`] | 🔌 | [`prefer-arrow/prefer-arrow-functions`] |
| [`prefer-for-of`] | 🛑 | N/A |
| [`promise-function-async`] |🛑 |N/A ([relevant plugin][plugin:promise]) |
| [`promise-function-async`] | |[`@typescript-eslint/promise-function-async`] |
| [`typedef`] | 🛑 | N/A |
| [`typedef-whitespace`] | ✅ | [`@typescript-eslint/type-annotation-spacing`] |
| [`unified-signatures`] | 🛑 | N/A |
Expand Down
65 changes: 65 additions & 0 deletionspackages/eslint-plugin/docs/rules/promise-function-async.md
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
# Functions that return promises must be async (promise-function-async)

Requires any function or method that returns a Promise to be marked async.
Ensures that each function is only capable of:

- returning a rejected promise, or
- throwing an Error object.

In contrast, non-`async` `Promise`-returning functions are technically capable of either.
Code that handles the results of those functions will often need to handle both cases, which can get complex.
This rule's practice removes a requirement for creating code to handle both cases.

## Rule Details

Examples of **incorrect** code for this rule

```ts
const arrowFunctionReturnsPromise = () => Promise.resolve('value');

function functionDeturnsPromise() {
return Math.random() > 0.5 ? Promise.resolve('value') : false;
}
```

Examples of **correct** code for this rule

```ts
const arrowFunctionReturnsPromise = async () => 'value';

async function functionDeturnsPromise() {
return Math.random() > 0.5 ? 'value' : false;
}
```

## Options

Options may be provided as an object with:

- `allowedPromiseNames` to indicate any extra names of classes or interfaces to be considered Promises when returned.

In addition, each of the following properties may be provided, and default to `true`:

- `checkArrowFunctions`
- `checkFunctionDeclarations`
- `checkFunctionExpressions`
- `checkMethodDeclarations`

```json
{
"@typescript-eslint/promise-function-async": [
"error",
{
"allowedPromiseNames": ["Thenable"],
"checkArrowFunctions": true,
"checkFunctionDeclarations": true,
"checkFunctionExpressions": true,
"checkMethodDeclarations": true
}
]
}
```

## Related To

- TSLint: [promise-function-async](https://palantir.github.io/tslint/rules/promise-function-async)
125 changes: 125 additions & 0 deletionspackages/eslint-plugin/lib/rules/promise-function-async.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
/**
* @fileoverview Requires any function or method that returns a Promise to be marked async
* @author Josh Goldberg <https://github.com/joshuakgoldberg>
*/
'use strict';

const util = require('../util');
const types = require('../utils/types');

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

const defaultOptions = [
{
allowedPromiseNames: [],
checkArrowFunctions: true,
checkFunctionDeclarations: true,
checkFunctionExpressions: true,
checkMethodDeclarations: true
}
];

/**
* @type {import("eslint").Rule.RuleModule}
*/
module.exports = {
meta: {
type: 'suggestion',
docs: {
description:
'Requires any function or method that returns a Promise to be marked async.',
extraDescription: [util.tslintRule('promise-function-async')],
category: 'TypeScript',
url: util.metaDocsUrl('promise-function-async'),
recommended: 'error'
},
fixable: null,
messages: {
missingAsync: 'Functions that return promises must be async.'
},
schema: [
{
type: 'object',
properties: {
allowedPromiseNames: {
type: 'array',
items: {
type: 'string'
}
},
checkArrowFunctions: {
type: 'boolean'
},
checkFunctionDeclarations: {
type: 'boolean'
},
checkFunctionExpressions: {
type: 'boolean'
},
checkMethodDeclarations: {
type: 'boolean'
}
},
additionalProperties: false
}
]
},

create(context) {
const {
allowedPromiseNames,
checkArrowFunctions,
checkFunctionDeclarations,
checkFunctionExpressions,
checkMethodDeclarations
} = util.applyDefault(defaultOptions, context.options)[0];

const allAllowedPromiseNames = new Set(['Promise', ...allowedPromiseNames]);
const parserServices = util.getParserServices(context);
const checker = parserServices.program.getTypeChecker();

/**
* @param {import("estree").Function} node
*/
function validateNode(node) {
const originalNode = parserServices.esTreeNodeToTSNodeMap.get(node);
const [callSignature] = checker
.getTypeAtLocation(originalNode)
.getCallSignatures();
const returnType = checker.getReturnTypeOfSignature(callSignature);

if (!types.containsTypeByName(returnType, allAllowedPromiseNames)) {
return;
}

context.report({
messageId: 'missingAsync',
node
});
}

return {
ArrowFunctionExpression(node) {
if (checkArrowFunctions && !node.async) {
validateNode(node);
}
},
FunctionDeclaration(node) {
if (checkFunctionDeclarations && !node.async) {
validateNode(node);
}
},
FunctionExpression(node) {
if (!!node.parent && node.parent.kind === 'method') {
if (checkMethodDeclarations && !node.async) {
validateNode(node.parent);
}
} else if (checkFunctionExpressions && !node.async) {
validateNode(node);
}
}
};
}
};
38 changes: 38 additions & 0 deletionspackages/eslint-plugin/lib/utils/types.js
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
'use strict';

const tsutils = require('tsutils');
const ts = require('typescript');

/**
* @param {string} type Type being checked by name.
* @param {Set<string>} allowedNames Symbol names checking on the type.
* @returns {boolean} Whether the type is, extends, or contains any of the allowed names.
*/
function containsTypeByName(type, allowedNames) {
if (tsutils.isTypeFlagSet(type, ts.TypeFlags.Any | ts.TypeFlags.Unknown)) {
return true;
}

if (tsutils.isTypeReference(type)) {
type = type.target;
}

if (
typeof type.symbol !== 'undefined' &&
allowedNames.has(type.symbol.name)
) {
return true;
}

if (tsutils.isUnionOrIntersectionType(type)) {
return type.types.some(t => containsTypeByName(t, allowedNames));
}

const bases = type.getBaseTypes();
return (
typeof bases !== 'undefined' &&
bases.some(t => containsTypeByName(t, allowedNames))
);
}

exports.containsTypeByName = containsTypeByName;
Loading

[8]ページ先頭

©2009-2025 Movatter.jp