Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix(eslint-plugin): [unbound-method] blacklist a few unbound natives (#…
  • Loading branch information
bradzacher committed Feb 3, 2020
1 parent bec59ff commit 4670aab
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 14 deletions.
74 changes: 60 additions & 14 deletions packages/eslint-plugin/src/rules/unbound-method.ts
Expand Up @@ -18,8 +18,53 @@ export type Options = [Config];

export type MessageIds = 'unbound';

const nativelyBoundMembers = ([
'Promise',
/**
* The following is a list of exceptions to the rule
* Generated via the following script.
* This is statically defined to save making purposely invalid calls every lint run
* ```
SUPPORTED_GLOBALS.flatMap(namespace => {
const object = window[namespace];
return Object.getOwnPropertyNames(object)
.filter(
name =>
!name.startsWith('_') &&
typeof object[name] === 'function',
)
.map(name => {
try {
const x = object[name];
x();
} catch (e) {
if (e.message.includes("called on non-object")) {
return `${namespace}.${name}`;
}
}
});
}).filter(Boolean);
* ```
*/
const nativelyNotBoundMembers = new Set([
'Promise.all',
'Promise.race',
'Promise.resolve',
'Promise.reject',
'Promise.allSettled',
'Object.defineProperties',
'Object.defineProperty',
'Reflect.defineProperty',
'Reflect.deleteProperty',
'Reflect.get',
'Reflect.getOwnPropertyDescriptor',
'Reflect.getPrototypeOf',
'Reflect.has',
'Reflect.isExtensible',
'Reflect.ownKeys',
'Reflect.preventExtensions',
'Reflect.set',
'Reflect.setPrototypeOf',
]);
const SUPPORTED_GLOBALS = [
'Number',
'Object',
'String', // eslint-disable-line @typescript-eslint/internal/prefer-ast-types-enum
Expand All @@ -35,18 +80,19 @@ const nativelyBoundMembers = ([
'Math',
'JSON',
'Intl',
] as const)
.map(namespace => {
const object = global[namespace];
return Object.getOwnPropertyNames(object)
.filter(
name =>
!name.startsWith('_') &&
typeof (object as Record<string, unknown>)[name] === 'function',
)
.map(name => `${namespace}.${name}`);
})
.reduce((arr, names) => arr.concat(names), []);
] as const;
const nativelyBoundMembers = SUPPORTED_GLOBALS.map(namespace => {
const object = global[namespace];
return Object.getOwnPropertyNames(object)
.filter(
name =>
!name.startsWith('_') &&
typeof (object as Record<string, unknown>)[name] === 'function',
)
.map(name => `${namespace}.${name}`);
})
.reduce((arr, names) => arr.concat(names), [])
.filter(name => !nativelyNotBoundMembers.has(name));

const isMemberNotImported = (
symbol: ts.Symbol,
Expand Down
10 changes: 10 additions & 0 deletions packages/eslint-plugin/tests/rules/unbound-method.test.ts
Expand Up @@ -324,5 +324,15 @@ const x = CommunicationError.prototype.foo;
},
],
},
{
// Promise.all is not auto-bound to Promise
code: 'const x = Promise.all',
errors: [
{
line: 1,
messageId: 'unbound',
},
],
},
],
});

0 comments on commit 4670aab

Please sign in to comment.