-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit abd5a89
Showing
9 changed files
with
4,177 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
"use strict"; | ||
|
||
module.exports = { | ||
root: true, | ||
extends: [ | ||
"eslint:recommended", | ||
"plugin:eslint-plugin/recommended", | ||
"plugin:node/recommended", | ||
], | ||
env: { | ||
node: true, | ||
}, | ||
overrides: [ | ||
{ | ||
files: ["tests/**/*.js"], | ||
env: { mocha: true }, | ||
}, | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
lerna-debug.log* | ||
.pnpm-debug.log* | ||
|
||
# Diagnostic reports (https://nodejs.org/api/report.html) | ||
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json | ||
|
||
# Runtime data | ||
pids | ||
*.pid | ||
*.seed | ||
*.pid.lock | ||
|
||
# Directory for instrumented libs generated by jscoverage/JSCover | ||
lib-cov | ||
|
||
# Coverage directory used by tools like istanbul | ||
coverage | ||
*.lcov | ||
|
||
# nyc test coverage | ||
.nyc_output | ||
|
||
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) | ||
.grunt | ||
|
||
# Bower dependency directory (https://bower.io/) | ||
bower_components | ||
|
||
# node-waf configuration | ||
.lock-wscript | ||
|
||
# Compiled binary addons (https://nodejs.org/api/addons.html) | ||
build/Release | ||
|
||
# Dependency directories | ||
node_modules/ | ||
jspm_packages/ | ||
|
||
# Snowpack dependency directory (https://snowpack.dev/) | ||
web_modules/ | ||
|
||
# TypeScript cache | ||
*.tsbuildinfo | ||
|
||
# Optional npm cache directory | ||
.npm | ||
|
||
# Optional eslint cache | ||
.eslintcache | ||
|
||
# Optional stylelint cache | ||
.stylelintcache | ||
|
||
# Microbundle cache | ||
.rpt2_cache/ | ||
.rts2_cache_cjs/ | ||
.rts2_cache_es/ | ||
.rts2_cache_umd/ | ||
|
||
# Optional REPL history | ||
.node_repl_history | ||
|
||
# Output of 'npm pack' | ||
*.tgz | ||
|
||
# Yarn Integrity file | ||
.yarn-integrity | ||
|
||
# dotenv environment variable files | ||
.env | ||
.env.development.local | ||
.env.test.local | ||
.env.production.local | ||
.env.local | ||
|
||
# parcel-bundler cache (https://parceljs.org/) | ||
.cache | ||
.parcel-cache | ||
|
||
# Next.js build output | ||
.next | ||
out | ||
|
||
# Nuxt.js build / generate output | ||
.nuxt | ||
dist | ||
|
||
# Gatsby files | ||
.cache/ | ||
# Comment in the public line in if your project uses Gatsby and not Next.js | ||
# https://nextjs.org/blog/next-9-1#public-directory-support | ||
# public | ||
|
||
# vuepress build output | ||
.vuepress/dist | ||
|
||
# vuepress v2.x temp and cache directory | ||
.temp | ||
.cache | ||
|
||
# Docusaurus cache and generated files | ||
.docusaurus | ||
|
||
# Serverless directories | ||
.serverless/ | ||
|
||
# FuseBox cache | ||
.fusebox/ | ||
|
||
# DynamoDB Local files | ||
.dynamodb/ | ||
|
||
# TernJS port file | ||
.tern-port | ||
|
||
# Stores VSCode versions used for testing VSCode extensions | ||
.vscode-test | ||
|
||
# yarn v2 | ||
.yarn/cache | ||
.yarn/unplugged | ||
.yarn/build-state.yml | ||
.yarn/install-state.gz | ||
.pnp.* | ||
.DS_Store |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
# eslint-plugin-no-throw-await | ||
|
||
Forces explicit error handling for promises (Similar to golang) through disallowing unpredictable awaits | ||
|
||
## Why? | ||
|
||
`await` can't be trusted. and try-catching everything is 💩. Explicit error handling is the way. It doesn't clutter your code it makes it better. Take a look at the following code: | ||
```typescript | ||
async function foo() { | ||
await bar() | ||
} | ||
``` | ||
Is `bar` safe to await? does it throw an exception maybe? Just in case let's wrap it in a try-catch | ||
```typescript | ||
async function foo() { | ||
try { | ||
await bar() | ||
} catch (e) { | ||
/* whatever */ | ||
} | ||
} | ||
``` | ||
Now assume you don't know what `foo` does. Or you don't want to read every async function line by line to check if it may throw an exception before using it. So what do you do? Also wrap `foo` in a try-catch just in case | ||
```typescript | ||
try { await foo() } catch (e) { } | ||
``` | ||
When/how do you propgate an error to the caller? or do you silence everything throuh a try catch? What if you have a series of async functions. But you don't want one throw to stop everything. Do you just wrap every single one in a try-catch. Or worse, use `.catch` nesting hell. There are many other examples of how bad this trycatching can get, amongst other issues with throwing in an async func. | ||
|
||
The goal of this plugin is to treat every promise as unsafe, which they are, and only allow awaiting a safe promise. A safe promise in this case means one that will not crash the application if left outside of a try-catch (will never throw). To to that, a linter rule will prevent you from awaiting a promise unless it's wrapped by a `awaitable` function. | ||
|
||
## awaitable | ||
A function that turns unsafe promises into safe promises. One implementation (golang like error handling): | ||
```typescript | ||
/** | ||
* Guarantees that a promise throw will be handled and returned gracefully as an error if any | ||
* The returned promise will never throw an exception | ||
* Result and error type can be specified through awaitable<ResultType, ErrorType> | ||
* @param fn Promise | ||
* @returns Promise<[result, error]> | ||
* - `result`: Returned on success, null on throw (Infered type of `fn`) | ||
* - `error`: Null on success, returned on throw (Default to Error) | ||
*/ | ||
/* Modified version from karanpratapsingh */ | ||
async function awaitable<R, E = Error> ( | ||
fn: Promise<R> | ||
): Promise<[R | null, E | null]> { | ||
// eslint-disable-next-line no-try-catch/no-try-catch | ||
try { | ||
// eslint-disable-next-line no-try-catch/no-direct-await | ||
const data: R = await fn | ||
return [data, null] | ||
} catch (error: any) { | ||
return [null, error] | ||
} | ||
} | ||
``` | ||
|
||
## Example | ||
```typescript | ||
async function foo (): Promise<boolean> { | ||
throw new Error('Some error') | ||
} | ||
|
||
async function testing (): Promise<void> { | ||
const [result, err] = await awaitable(foo()) | ||
if (err != null) { | ||
console.log(err.message) | ||
return | ||
} | ||
|
||
// Do stuff with result | ||
console.log(result) | ||
} | ||
``` | ||
|
||
|
||
## Installation | ||
|
||
You'll first need to install [ESLint](https://eslint.org/): | ||
|
||
```sh | ||
npm i eslint --save-dev | ||
``` | ||
|
||
Next, install `eslint-plugin-no-throw-await`: | ||
|
||
```sh | ||
npm install eslint-plugin-no-throw-await --save-dev | ||
``` | ||
|
||
## Usage | ||
|
||
Add `no-throw-await` to the plugins section of your `.eslintrc` configuration file. You can omit the `eslint-plugin-` prefix: | ||
|
||
```json | ||
{ | ||
"plugins": [ | ||
"no-throw-await" | ||
] | ||
} | ||
``` | ||
|
||
|
||
Then configure the rule under the rules section. | ||
|
||
```json | ||
{ | ||
"rules": { | ||
"no-throw-await/no-direct-await": "error" | ||
} | ||
} | ||
``` | ||
|
||
## Rules | ||
|
||
<!-- begin auto-generated rules list --> | ||
|
||
🔧 Automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/user-guide/command-line-interface#--fix).\ | ||
💡 Manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). | ||
|
||
| Name | Description | 🔧 | 💡 | | ||
| :----------------------------------------------- | :------------------------------------------------- | :- | :- | | ||
| [no-direct-await](docs/rules/no-direct-await.md) | Enforces using an await handler before every await | 🔧 | 💡 | | ||
|
||
<!-- end auto-generated rules list --> | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Enforces using an await handler before every await (`no-throw-await/no-direct-await`) | ||
|
||
🔧💡 This rule is automatically fixable by the [`--fix` CLI option](https://eslint.org/docs/latest/user-guide/command-line-interface#--fix) and manually fixable by [editor suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions). | ||
|
||
<!-- end auto-generated rule header --> | ||
|
||
The goal of this rule is to provide a way of error handling that is similar to golang. [Why?](../../README.md#Why) | ||
|
||
## Rule Details | ||
|
||
This rule aims to enforces using of an await handler before every await | ||
|
||
Examples of **incorrect** code for this rule: | ||
|
||
```js | ||
// 1 | ||
await someAsyncFunc() | ||
// 2 | ||
const aPromise = new Promise() | ||
await aPromise | ||
// 3 | ||
await new Promise() | ||
``` | ||
|
||
Examples of **correct** code for this rule: | ||
|
||
```js | ||
// 1 | ||
await awaitable(someAsyncFunc()) | ||
// 2 | ||
const aPromise = new Promise() | ||
await awaitable(aPromise) | ||
// 3 | ||
await awaitable(new Promise()) | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
/** | ||
* @fileoverview Forces explicit error handling through disallowing try-catch, and regular awaits. | ||
* @author wes4m | ||
*/ | ||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const requireIndex = require("requireindex"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Plugin Definition | ||
//------------------------------------------------------------------------------ | ||
|
||
|
||
// import all rules in lib/rules | ||
module.exports.rules = requireIndex(__dirname + "/rules"); |
Oops, something went wrong.