eslint-plugin-promise
Advanced tools
Comparing version 6.0.1 to 6.1.0
@@ -0,1 +1,5 @@ | ||
## 6.0.2 | ||
- Added tests for @typescript-eslint/parser support | ||
## 6.0.1 | ||
@@ -24,3 +28,3 @@ | ||
- Exempted array methods in prefer-await-to-callbacks | ||
([#212](https://github.com/xjamundx/eslint-plugin-promise/issues/212)) | ||
([#212](https://github.com/eslint-community/eslint-plugin-promise/issues/212)) | ||
@@ -37,4 +41,4 @@ ## 5.0.0 | ||
- https://github.com/xjamundx/eslint-plugin-promise/pull/202 | ||
- Udpated jest | ||
- https://github.com/eslint-community/eslint-plugin-promise/pull/202 | ||
- Updated jest | ||
@@ -53,3 +57,3 @@ ## 4.2.2 | ||
- Remove `promise/param-names` fixer | ||
([#146](https://github.com/xjamundx/eslint-plugin-promise/pull/146)) | ||
([#146](https://github.com/eslint-community/eslint-plugin-promise/pull/146)) | ||
@@ -59,5 +63,5 @@ ## 4.0.0 | ||
- Added fixer for `promise/no-new-statics` rule | ||
([#133](https://github.com/xjamundx/eslint-plugin-promise/pull/133)) | ||
([#133](https://github.com/eslint-community/eslint-plugin-promise/pull/133)) | ||
- Support ESLint v5 | ||
([#144](https://github.com/xjamundx/eslint-plugin-promise/pull/144)) | ||
([#144](https://github.com/eslint-community/eslint-plugin-promise/pull/144)) | ||
@@ -70,10 +74,10 @@ This is a breaking change that drops support for Node v4. In order to use ESLint | ||
- Removed `promise/avoid-new` from recommended configuration | ||
([#119](https://github.com/xjamundx/eslint-plugin-promise/pull/119)) | ||
([#119](https://github.com/eslint-community/eslint-plugin-promise/pull/119)) | ||
- Ignored event listener callbacks in `promise/prefer-await-to-callbacks` | ||
([#117](https://github.com/xjamundx/eslint-plugin-promise/pull/117)) | ||
([#117](https://github.com/eslint-community/eslint-plugin-promise/pull/117)) | ||
- Ignored top-level awaits in `promise/prefer-await-to-then` | ||
([#126](https://github.com/xjamundx/eslint-plugin-promise/pull/126)) | ||
([#126](https://github.com/eslint-community/eslint-plugin-promise/pull/126)) | ||
- Added docs for `promise/no-nesting` and `promise/prefer-await-to-then` | ||
([#120](https://github.com/xjamundx/eslint-plugin-promise/pull/120)) | ||
([#121](https://github.com/xjamundx/eslint-plugin-promise/pull/121)) | ||
([#120](https://github.com/eslint-community/eslint-plugin-promise/pull/120)) | ||
([#121](https://github.com/eslint-community/eslint-plugin-promise/pull/121)) | ||
@@ -83,9 +87,9 @@ ## 3.7.0 | ||
- Added `promise/valid-params` rule | ||
([#85](https://github.com/xjamundx/eslint-plugin-promise/pull/85)) | ||
([#85](https://github.com/eslint-community/eslint-plugin-promise/pull/85)) | ||
- Added `promise/no-new-statics` rule | ||
([#82](https://github.com/xjamundx/eslint-plugin-promise/pull/82)) | ||
([#82](https://github.com/eslint-community/eslint-plugin-promise/pull/82)) | ||
- Added fixer for `promise/param-names` rule | ||
([#99](https://github.com/xjamundx/eslint-plugin-promise/pull/99)) | ||
([#99](https://github.com/eslint-community/eslint-plugin-promise/pull/99)) | ||
- Added rule documentation to each rule | ||
([#91](https://github.com/xjamundx/eslint-plugin-promise/pull/91)) | ||
([#91](https://github.com/eslint-community/eslint-plugin-promise/pull/91)) | ||
@@ -92,0 +96,0 @@ ## 3.6.0 |
@@ -19,2 +19,3 @@ 'use strict' | ||
'valid-params': require('./rules/valid-params'), | ||
'no-multiple-resolved': require('./rules/no-multiple-resolved'), | ||
}, | ||
@@ -21,0 +22,0 @@ rulesConfig: { |
{ | ||
"name": "eslint-plugin-promise", | ||
"version": "6.0.1", | ||
"version": "6.1.0", | ||
"description": "Enforce best practices for JavaScript promises", | ||
@@ -17,8 +17,11 @@ "keywords": [ | ||
], | ||
"repository": "https://github.com/xjamundx/eslint-plugin-promise", | ||
"homepage": "https://github.com/xjamundx/eslint-plugin-promise", | ||
"bugs": "https://github.com/xjamundx/eslint-plugin-promise/issues", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/eslint-community/eslint-plugin-promise" | ||
}, | ||
"homepage": "https://github.com/eslint-community/eslint-plugin-promise", | ||
"bugs": "https://github.com/eslint-community/eslint-plugin-promise/issues", | ||
"scripts": { | ||
"format": "prettier --write .", | ||
"lint": "eslint .", | ||
"lint": "eslint --report-unused-disable-directives .", | ||
"prepare": "husky install", | ||
@@ -28,14 +31,15 @@ "test": "jest --coverage" | ||
"devDependencies": { | ||
"doctoc": "^2.1.0", | ||
"eslint": "^8.5.0", | ||
"eslint-config-prettier": "^8.3.0", | ||
"eslint-plugin-eslint-plugin": "^4.1.0", | ||
"eslint-plugin-jest": "^25.3.0", | ||
"@typescript-eslint/parser": "^5.40.0", | ||
"doctoc": "^2.2.1", | ||
"eslint": "^8.24.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-plugin-eslint-plugin": "^4.4.1", | ||
"eslint-plugin-jest": "^26.9.0", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"eslint-plugin-prettier": "^4.2.1", | ||
"husky": "^7.0.4", | ||
"jest": "^27.4.5", | ||
"jest-runner-eslint": "^1.0.0", | ||
"lint-staged": "^12.1.2", | ||
"prettier": "^2.5.1" | ||
"jest": "^28.1.3", | ||
"lint-staged": "^12.5.0", | ||
"prettier": "^2.7.1", | ||
"typescript": "^4.8.4" | ||
}, | ||
@@ -55,3 +59,3 @@ "peerDependencies": { | ||
"prettier --write", | ||
"eslint --fix" | ||
"eslint --report-unused-disable-directives --fix" | ||
], | ||
@@ -75,19 +79,4 @@ "*.+(json|md)": [ | ||
} | ||
}, | ||
"projects": [ | ||
{ | ||
"displayName": "test", | ||
"testEnvironment": "node" | ||
}, | ||
{ | ||
"runner": "jest-runner-eslint", | ||
"displayName": "lint", | ||
"testMatch": [ | ||
"<rootDir>/rules/**/*.js", | ||
"<rootDir>/__tests__/**/*.js", | ||
"<rootDir>/index.js" | ||
] | ||
} | ||
] | ||
} | ||
} | ||
} |
@@ -5,3 +5,3 @@ # eslint-plugin-promise | ||
[![travis-ci](https://travis-ci.org/xjamundx/eslint-plugin-promise.svg)](https://travis-ci.org/xjamundx/eslint-plugin-promise) | ||
[![CI](https://github.com/eslint-community/eslint-plugin-promise/actions/workflows/CI.yml/badge.svg)](https://github.com/eslint-community/eslint-plugin-promise/actions/workflows/CI.yml) | ||
[![npm version](https://badge.fury.io/js/eslint-plugin-promise.svg)](https://www.npmjs.com/package/eslint-plugin-promise) | ||
@@ -96,2 +96,3 @@ [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) | ||
| [`prefer-await-to-callbacks`][prefer-await-to-callbacks] | Prefer async/await to the callback pattern | :seven: | | | ||
| [`no-multiple-resolved`][no-multiple-resolved] | Disallow creating new promises with paths that resolve multiple times | | | | ||
@@ -132,2 +133,3 @@ **Key** | ||
[prefer-await-to-callbacks]: docs/rules/prefer-await-to-callbacks.md | ||
[no-multiple-resolved]: docs/rules/no-multiple-resolved.md | ||
[nodeify]: https://www.npmjs.com/package/nodeify | ||
@@ -134,0 +136,0 @@ [pify]: https://www.npmjs.com/package/pify |
@@ -5,2 +5,16 @@ 'use strict' | ||
/** | ||
* @typedef {import('estree').Node} Node | ||
* @typedef {import('estree').SimpleCallExpression} CallExpression | ||
* @typedef {import('estree').FunctionExpression} FunctionExpression | ||
* @typedef {import('estree').ArrowFunctionExpression} ArrowFunctionExpression | ||
* @typedef {import('eslint').Rule.CodePath} CodePath | ||
* @typedef {import('eslint').Rule.CodePathSegment} CodePathSegment | ||
*/ | ||
/** | ||
* @typedef { (FunctionExpression | ArrowFunctionExpression) & { parent: CallExpression }} InlineThenFunctionExpression | ||
*/ | ||
/** @param {Node} node */ | ||
function isFunctionWithBlockStatement(node) { | ||
@@ -16,12 +30,20 @@ if (node.type === 'FunctionExpression') { | ||
function isThenCallExpression(node) { | ||
/** | ||
* @param {string} memberName | ||
* @param {Node} node | ||
* @returns {node is CallExpression} | ||
*/ | ||
function isMemberCall(memberName, node) { | ||
return ( | ||
node.type === 'CallExpression' && | ||
node.callee.type === 'MemberExpression' && | ||
node.callee.property.name === 'then' | ||
!node.callee.computed && | ||
node.callee.property.type === 'Identifier' && | ||
node.callee.property.name === memberName | ||
) | ||
} | ||
/** @param {Node} node */ | ||
function isFirstArgument(node) { | ||
return ( | ||
return Boolean( | ||
node.parent && node.parent.arguments && node.parent.arguments[0] === node | ||
@@ -31,6 +53,10 @@ ) | ||
/** | ||
* @param {Node} node | ||
* @returns {node is InlineThenFunctionExpression} | ||
*/ | ||
function isInlineThenFunctionExpression(node) { | ||
return ( | ||
isFunctionWithBlockStatement(node) && | ||
isThenCallExpression(node.parent) && | ||
isMemberCall('then', node.parent) && | ||
isFirstArgument(node) | ||
@@ -40,20 +66,62 @@ ) | ||
function hasParentReturnStatement(node) { | ||
// istanbul ignore else -- not reachable given not checking `Program` | ||
if (node && node.parent && node.parent.type) { | ||
// if the parent is a then, and we haven't returned anything, fail | ||
if (isThenCallExpression(node.parent)) { | ||
return false | ||
} | ||
if (node.parent.type === 'ReturnStatement') { | ||
/** | ||
* Checks whether the given node is the last `then()` callback in a promise chain. | ||
* @param {InlineThenFunctionExpression} node | ||
*/ | ||
function isLastCallback(node) { | ||
/** @type {Node} */ | ||
let target = node.parent | ||
/** @type {Node | undefined} */ | ||
let parent = target.parent | ||
while (parent) { | ||
if (parent.type === 'ExpressionStatement') { | ||
// e.g. { promise.then(() => value) } | ||
return true | ||
} | ||
return hasParentReturnStatement(node.parent) | ||
if (parent.type === 'UnaryExpression') { | ||
// e.g. void promise.then(() => value) | ||
return parent.operator === 'void' | ||
} | ||
/** @type {Node | null} */ | ||
let nextTarget = null | ||
if (parent.type === 'SequenceExpression') { | ||
if (peek(parent.expressions) !== target) { | ||
// e.g. (promise?.then(() => value), expr) | ||
return true | ||
} | ||
nextTarget = parent | ||
} else if ( | ||
// e.g. promise?.then(() => value) | ||
parent.type === 'ChainExpression' || | ||
// e.g. await promise.then(() => value) | ||
parent.type === 'AwaitExpression' | ||
) { | ||
nextTarget = parent | ||
} else if (parent.type === 'MemberExpression') { | ||
if ( | ||
parent.parent && | ||
(isMemberCall('catch', parent.parent) || | ||
isMemberCall('finally', parent.parent)) | ||
) { | ||
// e.g. promise.then(() => value).catch(e => {}) | ||
nextTarget = parent.parent | ||
} | ||
} | ||
if (nextTarget) { | ||
target = nextTarget | ||
parent = target.parent | ||
continue | ||
} | ||
return false | ||
} | ||
// istanbul ignore next -- not reachable given not checking `Program` | ||
// istanbul ignore next | ||
return false | ||
} | ||
/** | ||
* @template T | ||
* @param {T[]} arr | ||
* @returns {T} | ||
*/ | ||
function peek(arr) { | ||
@@ -69,34 +137,55 @@ return arr[arr.length - 1] | ||
}, | ||
schema: [], | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
ignoreLastCallback: { | ||
type: 'boolean', | ||
}, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
}, | ||
create(context) { | ||
// funcInfoStack is a stack representing the stack of currently executing | ||
// functions | ||
// funcInfoStack[i].branchIDStack is a stack representing the currently | ||
// executing branches ("codePathSegment"s) within the given function | ||
// funcInfoStack[i].branchInfoMap is an object representing information | ||
// about all branches within the given function | ||
// funcInfoStack[i].branchInfoMap[j].good is a boolean representing whether | ||
// the given branch explicitly `return`s or `throw`s. It starts as `false` | ||
// for every branch and is updated to `true` if a `return` or `throw` | ||
// statement is found | ||
// funcInfoStack[i].branchInfoMap[j].loc is a eslint SourceLocation object | ||
// for the given branch | ||
// example: | ||
// funcInfoStack = [ { branchIDStack: [ 's1_1' ], | ||
// branchInfoMap: | ||
// { s1_1: | ||
// { good: false, | ||
// loc: <loc> } } }, | ||
// { branchIDStack: ['s2_1', 's2_4'], | ||
// branchInfoMap: | ||
// { s2_1: | ||
// { good: false, | ||
// loc: <loc> }, | ||
// s2_2: | ||
// { good: true, | ||
// loc: <loc> }, | ||
// s2_4: | ||
// { good: false, | ||
// loc: <loc> } } } ] | ||
const options = context.options[0] || {} | ||
const ignoreLastCallback = !!options.ignoreLastCallback | ||
/** | ||
* @typedef {object} FuncInfo | ||
* @property {string[]} branchIDStack This is a stack representing the currently | ||
* executing branches ("codePathSegment"s) within the given function | ||
* @property {Record<string, BranchInfo | undefined>} branchInfoMap This is an object representing information | ||
* about all branches within the given function | ||
* | ||
* @typedef {object} BranchInfo | ||
* @property {boolean} good This is a boolean representing whether | ||
* the given branch explicitly `return`s or `throw`s. It starts as `false` | ||
* for every branch and is updated to `true` if a `return` or `throw` | ||
* statement is found | ||
* @property {Node} node This is a estree Node object | ||
* for the given branch | ||
*/ | ||
/** | ||
* funcInfoStack is a stack representing the stack of currently executing | ||
* functions | ||
* example: | ||
* funcInfoStack = [ { branchIDStack: [ 's1_1' ], | ||
* branchInfoMap: | ||
* { s1_1: | ||
* { good: false, | ||
* loc: <loc> } } }, | ||
* { branchIDStack: ['s2_1', 's2_4'], | ||
* branchInfoMap: | ||
* { s2_1: | ||
* { good: false, | ||
* loc: <loc> }, | ||
* s2_2: | ||
* { good: true, | ||
* loc: <loc> }, | ||
* s2_4: | ||
* { good: false, | ||
* loc: <loc> } } } ] | ||
* @type {FuncInfo[]} | ||
*/ | ||
const funcInfoStack = [] | ||
@@ -114,5 +203,9 @@ | ||
return { | ||
ReturnStatement: markCurrentBranchAsGood, | ||
ThrowStatement: markCurrentBranchAsGood, | ||
'ReturnStatement:exit': markCurrentBranchAsGood, | ||
'ThrowStatement:exit': markCurrentBranchAsGood, | ||
/** | ||
* @param {CodePathSegment} segment | ||
* @param {Node} node | ||
*/ | ||
onCodePathSegmentStart(segment, node) { | ||
@@ -136,2 +229,6 @@ const funcInfo = peek(funcInfoStack) | ||
/** | ||
* @param {CodePath} path | ||
* @param {Node} node | ||
*/ | ||
onCodePathEnd(path, node) { | ||
@@ -144,2 +241,6 @@ const funcInfo = funcInfoStack.pop() | ||
if (ignoreLastCallback && isLastCallback(node)) { | ||
return | ||
} | ||
path.finalSegments.forEach((segment) => { | ||
@@ -149,6 +250,2 @@ const id = segment.id | ||
if (!branch.good) { | ||
if (hasParentReturnStatement(branch.node)) { | ||
return | ||
} | ||
context.report({ | ||
@@ -155,0 +252,0 @@ message: 'Each then() should return a value or throw', |
'use strict' | ||
const REPO_URL = 'https://github.com/xjamundx/eslint-plugin-promise' | ||
const REPO_URL = 'https://github.com/eslint-community/eslint-plugin-promise' | ||
@@ -5,0 +5,0 @@ /** |
@@ -9,2 +9,22 @@ /** | ||
/** | ||
* @typedef {import('estree').SimpleCallExpression} CallExpression | ||
* @typedef {import('estree').MemberExpression} MemberExpression | ||
* @typedef {import('estree').Identifier} Identifier | ||
* | ||
* @typedef {object} NameIsThenOrCatch | ||
* @property {'then' | 'catch'} name | ||
* | ||
* @typedef {object} PropertyIsThenOrCatch | ||
* @property {Identifier & NameIsThenOrCatch} property | ||
* | ||
* @typedef {object} CalleeIsPromiseCallback | ||
* @property {MemberExpression & PropertyIsThenOrCatch} callee | ||
* | ||
* @typedef {CallExpression & CalleeIsPromiseCallback} HasPromiseCallback | ||
*/ | ||
/** | ||
* @param {import('estree').Node} node | ||
* @returns {node is HasPromiseCallback} | ||
*/ | ||
function hasPromiseCallback(node) { | ||
@@ -11,0 +31,0 @@ // istanbul ignore if -- only being called within `CallExpression` |
@@ -5,2 +5,4 @@ 'use strict' | ||
all: true, | ||
allSettled: true, | ||
any: true, | ||
race: true, | ||
@@ -7,0 +9,0 @@ reject: true, |
@@ -41,3 +41,3 @@ // Borrowed from here: | ||
* | ||
* @param {Scope} scope - an escope Scope object | ||
* @param {Scope} scope - an eslint-scope Scope object | ||
* @returns {void} | ||
@@ -51,4 +51,4 @@ * @private | ||
scope.implicit.left || | ||
/* istanbul ignore next | ||
* Fixes https://github.com/xjamundx/eslint-plugin-promise/issues/205. | ||
/** | ||
* Fixes https://github.com/eslint-community/eslint-plugin-promise/issues/205. | ||
* The problem was that @typescript-eslint has a scope manager | ||
@@ -55,0 +55,0 @@ * which has `leftToBeResolved` instead of the default `left`. |
@@ -21,8 +21,96 @@ /** | ||
create(context) { | ||
/** | ||
* Array of callback function scopes. | ||
* Scopes are in order closest to the current node. | ||
* @type {import('eslint').Scope.Scope[]} | ||
*/ | ||
const callbackScopes = [] | ||
/** | ||
* @param {import('eslint').Scope.Scope} scope | ||
* @returns {Iterable<import('eslint').Scope.Reference>} | ||
*/ | ||
function* iterateDefinedReferences(scope) { | ||
for (const variable of scope.variables) { | ||
for (const reference of variable.references) { | ||
yield reference | ||
} | ||
} | ||
} | ||
return { | ||
':function'(node) { | ||
if (isInsidePromise(node)) { | ||
callbackScopes.unshift(context.getScope()) | ||
} | ||
}, | ||
':function:exit'(node) { | ||
if (isInsidePromise(node)) { | ||
callbackScopes.shift() | ||
} | ||
}, | ||
CallExpression(node) { | ||
if (!hasPromiseCallback(node)) return | ||
if (context.getAncestors().some(isInsidePromise)) { | ||
context.report({ node, message: 'Avoid nesting promises.' }) | ||
if (!callbackScopes.length) { | ||
// The node is not in the callback function. | ||
return | ||
} | ||
// Checks if the argument callback uses variables defined in the closest callback function scope. | ||
// | ||
// e.g. | ||
// ``` | ||
// doThing() | ||
// .then(a => getB(a) | ||
// .then(b => getC(a, b)) | ||
// ) | ||
// ``` | ||
// | ||
// In the above case, Since the variables it references are undef, | ||
// we cannot refactor the nesting like following: | ||
// ``` | ||
// doThing() | ||
// .then(a => getB(a)) | ||
// .then(b => getC(a, b)) | ||
// ``` | ||
// | ||
// However, `getD` can be refactored in the following: | ||
// ``` | ||
// doThing() | ||
// .then(a => getB(a) | ||
// .then(b => getC(a, b) | ||
// .then(c => getD(a, c)) | ||
// ) | ||
// ) | ||
// ``` | ||
// ↓ | ||
// ``` | ||
// doThing() | ||
// .then(a => getB(a) | ||
// .then(b => getC(a, b)) | ||
// .then(c => getD(a, c)) | ||
// ) | ||
// ``` | ||
// This is why we only check the closest callback function scope. | ||
// | ||
const closestCallbackScope = callbackScopes[0] | ||
for (const reference of iterateDefinedReferences( | ||
closestCallbackScope | ||
)) { | ||
if ( | ||
node.arguments.some( | ||
(arg) => | ||
arg.range[0] <= reference.identifier.range[0] && | ||
reference.identifier.range[1] <= arg.range[1] | ||
) | ||
) { | ||
// Argument callbacks refer to variables defined in the callback function. | ||
return | ||
} | ||
} | ||
context.report({ | ||
node: node.callee.property, | ||
message: 'Avoid nesting promises.', | ||
}) | ||
}, | ||
@@ -29,0 +117,0 @@ } |
'use strict' | ||
const getDocsUrl = require('./lib/get-docs-url') | ||
const { | ||
isPromiseConstructorWithInlineExecutor, | ||
} = require('./lib/is-promise-constructor') | ||
@@ -11,8 +14,24 @@ module.exports = { | ||
}, | ||
schema: [], | ||
schema: [ | ||
{ | ||
type: 'object', | ||
properties: { | ||
resolvePattern: { type: 'string' }, | ||
rejectPattern: { type: 'string' }, | ||
}, | ||
additionalProperties: false, | ||
}, | ||
], | ||
}, | ||
create(context) { | ||
const options = context.options[0] || {} | ||
const resolvePattern = new RegExp( | ||
options.resolvePattern || '^_?resolve$', | ||
'u' | ||
) | ||
const rejectPattern = new RegExp(options.rejectPattern || '^_?reject$', 'u') | ||
return { | ||
NewExpression(node) { | ||
if (node.callee.name === 'Promise' && node.arguments.length === 1) { | ||
if (isPromiseConstructorWithInlineExecutor(node)) { | ||
const params = node.arguments[0].params | ||
@@ -24,14 +43,24 @@ | ||
if ( | ||
(params[0].name !== 'resolve' && params[0].name !== '_resolve') || | ||
(params[1] && | ||
params[1].name !== 'reject' && | ||
params[1].name !== '_reject') | ||
) { | ||
const resolveParamName = params[0] && params[0].name | ||
if (resolveParamName && !resolvePattern.test(resolveParamName)) { | ||
context.report({ | ||
node, | ||
node: params[0], | ||
message: | ||
'Promise constructor parameters must be named resolve, reject', | ||
'Promise constructor parameters must be named to match "{{ resolvePattern }}"', | ||
data: { | ||
resolvePattern: resolvePattern.source, | ||
}, | ||
}) | ||
} | ||
const rejectParamName = params[1] && params[1].name | ||
if (rejectParamName && !rejectPattern.test(rejectParamName)) { | ||
context.report({ | ||
node: params[1], | ||
message: | ||
'Promise constructor parameters must be named to match "{{ rejectPattern }}"', | ||
data: { | ||
rejectPattern: rejectPattern.source, | ||
}, | ||
}) | ||
} | ||
} | ||
@@ -38,0 +67,0 @@ }, |
@@ -38,3 +38,3 @@ /** | ||
return { | ||
MemberExpression(node) { | ||
'CallExpression > MemberExpression.callee'(node) { | ||
if (isTopLevelScoped() || isInsideYieldOrAwait()) { | ||
@@ -41,0 +41,0 @@ return |
@@ -51,2 +51,4 @@ 'use strict' | ||
case 'all': | ||
case 'allSettled': | ||
case 'any': | ||
case 'catch': | ||
@@ -53,0 +55,0 @@ case 'finally': |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No repository
Supply chain riskPackage does not have a linked source code repository. Without this field, a package will have no reference to the location of the source code use to generate the package.
Found 1 instance in 1 package
64268
1694
137
0
13
29
1