Skip to content

Commit

Permalink
Add prefer-event-target rule (#1792)
Browse files Browse the repository at this point in the history
Co-authored-by: fisker Cheung <lionkay@gmail.com>
Co-authored-by: Sindre Sorhus <sindresorhus@gmail.com>
  • Loading branch information
3 people committed May 8, 2022
1 parent 6f5ecf5 commit 166524a
Show file tree
Hide file tree
Showing 7 changed files with 194 additions and 0 deletions.
1 change: 1 addition & 0 deletions configs/recommended.js
Expand Up @@ -78,6 +78,7 @@ module.exports = {
'unicorn/prefer-dom-node-dataset': 'error',
'unicorn/prefer-dom-node-remove': 'error',
'unicorn/prefer-dom-node-text-content': 'error',
'unicorn/prefer-event-target': 'error',
'unicorn/prefer-export-from': 'error',
'unicorn/prefer-includes': 'error',
'unicorn/prefer-json-parse-buffer': 'off',
Expand Down
34 changes: 34 additions & 0 deletions docs/rules/prefer-event-target.md
@@ -0,0 +1,34 @@
# Prefer `EventTarget` over `EventEmitter`

<!-- Do not manually modify RULE_NOTICE part. Run: `npm run generate-rule-notices` -->
<!-- RULE_NOTICE -->
*This rule is part of the [recommended](https://github.com/sindresorhus/eslint-plugin-unicorn#recommended-config) config.*
<!-- /RULE_NOTICE -->

While [`EventEmitter`](https://nodejs.org/api/events.html#class-eventemitter) is only available in Node.js, [`EventTarget`](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget) is also available in *Deno* and browsers.

This rule reduces the bundle size and makes your code more cross-platform friendly.

See the [differences](https://nodejs.org/api/events.html#eventtarget-and-event-api) between `EventEmitter` and `EventTarget`.

## Fail

```js
import {EventEmitter} from 'node:event';

class Foo extends EventEmitter {}
```

```js
const emitter = new EventEmitter();
```

## Pass

```js
class Foo extends EventTarget {}
```

```js
const target = new EventTarget();
```
1 change: 1 addition & 0 deletions readme.md
Expand Up @@ -118,6 +118,7 @@ Each rule has emojis denoting:
| [prefer-dom-node-dataset](docs/rules/prefer-dom-node-dataset.md) | Prefer using `.dataset` on DOM elements over calling attribute methods. || 🔧 | |
| [prefer-dom-node-remove](docs/rules/prefer-dom-node-remove.md) | Prefer `childNode.remove()` over `parentNode.removeChild(childNode)`. || 🔧 | 💡 |
| [prefer-dom-node-text-content](docs/rules/prefer-dom-node-text-content.md) | Prefer `.textContent` over `.innerText`. || | 💡 |
| [prefer-event-target](docs/rules/prefer-event-target.md) | Prefer `EventTarget` over `EventEmitter`. || | |
| [prefer-export-from](docs/rules/prefer-export-from.md) | Prefer `export…from` when re-exporting. || 🔧 | 💡 |
| [prefer-includes](docs/rules/prefer-includes.md) | Prefer `.includes()` over `.indexOf()` and `Array#some()` when checking for existence or non-existence. || 🔧 | 💡 |
| [prefer-json-parse-buffer](docs/rules/prefer-json-parse-buffer.md) | Prefer reading a JSON file as a buffer. | | 🔧 | |
Expand Down
39 changes: 39 additions & 0 deletions rules/prefer-event-target.js
@@ -0,0 +1,39 @@
'use strict';
const {matches} = require('./selectors/index.js');

const MESSAGE_ID = 'prefer-event-target';
const messages = {
[MESSAGE_ID]: 'Prefer `EventTarget` over `EventEmitter`.',
};

const selector = [
'Identifier',
'[name="EventEmitter"]',
matches([
'ClassDeclaration > .superClass',
'ClassExpression > .superClass',
'NewExpression > .callee',
]),
].join('');

/** @param {import('eslint').Rule.RuleContext} context */
const create = () => ({
[selector](node) {
return {
node,
messageId: MESSAGE_ID,
};
},
});

/** @type {import('eslint').Rule.RuleModule} */
module.exports = {
create,
meta: {
type: 'suggestion',
docs: {
description: 'Prefer `EventTarget` over `EventEmitter`.',
},
messages,
},
};
48 changes: 48 additions & 0 deletions test/prefer-event-target.mjs
@@ -0,0 +1,48 @@
import outdent from 'outdent';
import {getTester} from './utils/test.mjs';

const {test} = getTester(import.meta);

test.snapshot({
valid: [
'class Foo {}',
'class Foo extends OtherClass {}',
'class Foo extends EventTarget {}',
'const Foo = class extends EventTarget {}',
'const Foo = class extends foo.EventTarget {}',
'const Foo = class extends foo.bar.EventTarget {}',
'class Foo extends foo.EventEmitter {}',
'class Foo extends foo.bar.EventEmitter {}',
'class EventEmitter extends Foo {}',
'const Foo = class EventEmitter extends Foo {}',
'new Foo(EventEmitter)',
'new foo.EventEmitter()',
],
invalid: [
'class Foo extends EventEmitter {}',
'class Foo extends EventEmitter { someMethod() {} }',
'const Foo = class extends EventEmitter {}',
outdent`
class Foo extends EventEmitter {
addListener() {}
removeListener() {}
}
`,
],
});

test.snapshot({
valid: [
'EventTarget()',
'new EventTarget',
'const target = new EventTarget;',
'const target = EventTarget()',
'const target = new Foo(EventEmitter);',
'EventEmitter()',
'const emitter = EventEmitter()',
],
invalid: [
'new EventEmitter',
'const emitter = new EventEmitter;',
],
});
71 changes: 71 additions & 0 deletions test/snapshots/prefer-event-target.mjs.md
@@ -0,0 +1,71 @@
# Snapshot report for `test/prefer-event-target.mjs`

The actual snapshot is saved in `prefer-event-target.mjs.snap`.

Generated by [AVA](https://avajs.dev).

## Invalid #1
1 | class Foo extends EventEmitter {}

> Error 1/1
`␊
> 1 | class Foo extends EventEmitter {}␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
`

## Invalid #2
1 | class Foo extends EventEmitter { someMethod() {} }

> Error 1/1
`␊
> 1 | class Foo extends EventEmitter { someMethod() {} }␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
`

## Invalid #3
1 | const Foo = class extends EventEmitter {}

> Error 1/1
`␊
> 1 | const Foo = class extends EventEmitter {}␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
`

## Invalid #4
1 | class Foo extends EventEmitter {
2 | addListener() {}
3 | removeListener() {}
4 | }

> Error 1/1
`␊
> 1 | class Foo extends EventEmitter {␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
2 | addListener() {}␊
3 | removeListener() {}␊
4 | }␊
`

## Invalid #1
1 | new EventEmitter

> Error 1/1
`␊
> 1 | new EventEmitter␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
`

## Invalid #2
1 | const emitter = new EventEmitter;

> Error 1/1
`␊
> 1 | const emitter = new EventEmitter;␊
| ^^^^^^^^^^^^ Prefer \`EventTarget\` over \`EventEmitter\`.␊
`
Binary file added test/snapshots/prefer-event-target.mjs.snap
Binary file not shown.

0 comments on commit 166524a

Please sign in to comment.