Skip to content

Commit

Permalink
Async rule changes (#156)
Browse files Browse the repository at this point in the history
# Rationale

Resolves #151. This makes it so a promise must be awaited (or otherwise
handled, just not ignored) in Angular tests, making them match other
code.

Resolves #115. This makes it so a function marked `async` must `await`
something, not contain only synchronous code and not return a promise.

# Implementation

1. Stop disabling `no-floating-promises` in Angular tests. See PR
comment for rationale for keeping `no-unbound-method: 'off'` here.
- this repo even had some Angular tests that violated this rule because
they were using stale `jasminewd2` types. I fixed those by using
`jasmine` types instead (and fixing a playwright test that was
incorrectly referencing jasmine types)
- this required adding an `.npmrc` since my dev machine is configured to
use Artifactory
3. Set `no-return-await: 'off'` in the JS ruleset. This [rule is now
deprecated by
ESLint](https://eslint.org/docs/latest/rules/no-return-await) because
returning an awaited promise is no longer a performance concern.
- the related `@typescript-eslint/return-await': 'error'` was already
enabled and is still useful because [it enforces the
inverse](https://typescript-eslint.io/rules/return-await/), that you
should await promises rather than just return them because you get
better stack traces
4. Set `'require-await': 'error'` in the JS ruleset and
`'@typescript-eslint/require-await': 'error'` in the
TS-with-typechecking ruleset.
5. Change files for beachball marked `minor` in accordance with
CONTRIBUTING.md guidance for rule changes and include package-specific
descriptions of the changes

# Testing

[A draft
PR](https://dev.azure.com/ni/DevCentral/_git/Skyline/pullrequest/761645)
into `systemlink-lib-angular` shows the impact of some of these changes.
It requires mostly mechanical changes and catches lots of legitimate
issues.

I also updated a couple test files in this repo to include more async
cases and played around with those implementations locally to verify the
rules were working.

---------

Co-authored-by: Milan Raj <rajsite@users.noreply.github.com>
  • Loading branch information
jattasNI and rajsite authored Sep 26, 2024
1 parent c2cd58d commit 2fbb47b
Show file tree
Hide file tree
Showing 13 changed files with 52 additions and 20 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,5 @@ node_modules
.DS_Store
*.tgz
.vscode
.npmrc
./rules.txt
./rules-diff.txt
1 change: 1 addition & 0 deletions .npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
registry=https://registry.npmjs.org/
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Rule changes for asynchronous code:\\n 1. Functions marked `async` must now include an `await`. The rule `'@typescript-eslint/require-await'` changed from `'off'` to `'error'`.\\n 2. Test code must now correctly handle promises. The rule `'@typescript-eslint/no-floating-promises'` changed from `'off'` to `'error'`.",
"packageName": "@ni/eslint-config-angular",
"email": "jattasNI@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Rule changes for asynchronous code:\\n 1. Functions marked `async` must now include an `await`. The rule `'require-await'` changed from `'off'` to `'error'`.\\n 2. It is now acceptable for a function to return an awaited promise. The rule `'no-return-await'` changed from `'error'` to `'off'`.",
"packageName": "@ni/eslint-config-javascript",
"email": "jattasNI@users.noreply.github.com",
"dependentChangeType": "patch"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "minor",
"comment": "Rule changes for asynchronous code:\\n 1. Functions marked `async` must now include an `await`. The rule `'@typescript-eslint/require-await'` changed from `'off'` to `'error'`.",
"packageName": "@ni/eslint-config-typescript",
"email": "jattasNI@users.noreply.github.com",
"dependentChangeType": "patch"
}
12 changes: 2 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions packages/eslint-config-angular/requiring-type-checking.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,9 @@ module.exports = {
files: ['*.spec.ts'],
rules: {
/*
The jasminewd2 library used by Angular applications results in a significant number of
floating promises and unbound methods so these rules are disabled for test specs in Angular projects.
Spies used by Angular application tests result in a significant number of
unbound methods so this rule is disabled for test specs in Angular projects.
*/
'@typescript-eslint/no-floating-promises': 'off',
'@typescript-eslint/unbound-method': 'off',
}
},
Expand Down
10 changes: 10 additions & 0 deletions packages/eslint-config-javascript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,11 @@ module.exports = {
selector: 'CallExpression[callee.object.name=\'console\'][callee.property.name=/^(debug|info|time|timeEnd|trace)$/]',
message: 'Unexpected property on console object was called'
}],
/*
This rule is deprecated since ESLint 8.46.0 because returning an awaited value no longer generates an extra microtask.
https://eslint.org/docs/latest/rules/no-return-await
*/
'no-return-await': 'off',

/*
Disallow returning values from setters.
Expand Down Expand Up @@ -424,6 +429,11 @@ module.exports = {
*/
'prefer-regex-literals': 'error',

/*
Asynchronous functions that don’t use await might not need to be asynchronous functions and could be the unintentional result of refactoring.
*/
'require-await': 'error',

/*
This configuration already supports the JSDoc syntax. Add additional syntax as line or
block exceptions or markers when necessary.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,12 @@ module.exports = {
'no-throw-literal': 'off',
'@typescript-eslint/no-throw-literal': 'error',

// Defined by Airbnb
// Defined by NI
'require-await': 'off',
'@typescript-eslint/require-await': 'off',
'@typescript-eslint/require-await': 'error',

// Defined by Airbnb
'no-return-await': 'off',
'@typescript-eslint/return-await': 'error',
'@typescript-eslint/return-await': ['error', 'always'],
}
};
4 changes: 2 additions & 2 deletions tests/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,6 @@
"@angular/core": "^17.3.12"
},
"devDependencies": {
"@types/jasminewd2": "^2.0.13"
"@types/jasmine": "^5.1.4"
}
}
}
4 changes: 4 additions & 0 deletions tests/javascript/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,8 @@ export class NI {
makeAwesomer() {
this._awesomeLevel += 1;
}

async asyncAwesomeness() {
await Promise.resolve(42);
}
}
2 changes: 1 addition & 1 deletion tests/playwright-requiring-type-checking/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { test, expect } from '@playwright/test';

describe('AssetDisplayPropertiesSidenavWrapperComponent', () => {
test.describe('AssetDisplayPropertiesSidenavWrapperComponent', () => {
test('has title', async ({ page }) => {
await page.goto('https://playwright.dev/');

Expand Down
6 changes: 6 additions & 0 deletions tests/typescript-requiring-type-checking/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,10 @@ export class NI {
public makeAwesomer(): void {
this._awesomeLevel += 1;
}

public async slowAdd(a: number, b: number, timeMs: number): Promise<number> {
return await new Promise(resolve => {
setTimeout(() => resolve(a + b), timeMs);
});
}
}

0 comments on commit 2fbb47b

Please sign in to comment.