Skip to content
This repository was archived by the owner on Sep 18, 2023. It is now read-only.

allow exporting of Event sublcasses alongside custom elements #50

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion docs/rules/no-exports-with-element.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ It's possible to export multiple functions and classes in a JavaScript file. In

## Rule Details

This rule disallows exports (other than the element class) in a file with a Custom Element.
This rule disallows exports (other than the element class and event subclasses) in a file with a Custom Element.

👎 Examples of **incorrect** code for this rule:

Expand All @@ -29,6 +29,18 @@ export class FooBarElement extends HTMLElement {
}
```

```js
// foo-bar-element.js
import {myHelper} from './helpers.js'
export class FooReadyEvent extends Event {
// ...
}

export class FooBarElement extends HTMLElement {
// ...
}
```

```js
// helpers.js
export function myHelper() {
Expand Down
4 changes: 4 additions & 0 deletions lib/class-ref-tracker.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ class ClassRefTracker {
static customElements(context) {
return new ClassRefTracker(context, superClassRef => superClassRef && /^HTML.*Element$/.test(superClassRef.name))
}

static customEvents(context) {
return new ClassRefTracker(context, superClassRef => superClassRef && superClassRef.name === 'Event')
}
}

module.exports = ClassRefTracker
2 changes: 2 additions & 0 deletions lib/custom-selectors.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const HTMLElementClass = ':matches(ClassDeclaration, ClassExpression)[superClass.name=/HTML.*Element/]'
const EventSubClass = ':matches(ClassDeclaration, ClassExpression)[superClass.name=/^Event$/]'
const customElements = {
_call:
'[callee.object.type=Identifier][callee.object.name=customElements],' +
Expand All @@ -10,4 +11,5 @@ customElements.define = `CallExpression[callee.property.name=define]:matches(${c
module.exports = {
HTMLElementClass,
customElements,
EventSubClass,
}
14 changes: 9 additions & 5 deletions lib/rules/no-exports-with-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ module.exports = {
schema: [],
create(context) {
const classes = ClassRefTracker.customElements(context)
const eventClasses = ClassRefTracker.customEvents(context)
const exports = new Set()
let hasElement = false

Expand All @@ -17,23 +18,26 @@ module.exports = {
hasElement = true
classes.add(node)
},
[s.EventSubClass](node) {
eventClasses.add(node)
},
['ExportNamedDeclaration > VariableDeclaration > VariableDeclarator']: function (node) {
if (!classes.get(node.init)) {
if (!classes.get(node.init) && !eventClasses.get(node.init)) {
exports.add(node.init)
}
},
['ExportNamedDeclaration :matches(ClassDeclaration, ClassExpression, FunctionDeclaration)']: function (node) {
if (!classes.get(node)) {
if (!classes.get(node) && !eventClasses.get(node)) {
exports.add(node)
}
},
['ExportNamedDeclaration > AssignmentExpression']: function (node) {
if (!classes.get(node.right)) {
if (!classes.get(node.right) && !eventClasses.get(node.local)) {
exports.add(node.right)
}
},
['ExportNamedDeclaration ExportSpecifier']: function (node) {
if (!classes.get(node.local)) {
if (!classes.get(node.local) && !eventClasses.get(node.local)) {
exports.add(node.local)
}
},
Expand All @@ -42,7 +46,7 @@ module.exports = {
if (declaration.type === 'AssignmentExpression') {
declaration = declaration.right
}
if (!classes.get(declaration)) {
if (!classes.get(declaration) && !eventClasses.get(declaration)) {
exports.add(declaration)
}
},
Expand Down
4 changes: 4 additions & 0 deletions test/no-exports-with-element.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ ruleTester.run('no-exports-with-element', rule, {
{code: 'class FooBarElement extends HTMLElement { }\nexport {FooBarElement}'},
{code: 'class FooBarElement extends HTMLElement { }\nexport default FooBarElement'},
{code: 'export class a extends HTMLElement { }\nexport class b extends HTMLElement { }'},
{code: 'export class a extends HTMLElement { }\nexport class b extends Event { }'},
{code: 'export class a extends HTMLElement { }\nexport default class b extends Event { }'},
{code: 'class A extends HTMLElement { }\nclass B extends Event { }\nexport {A, B}'},
{code: 'class A extends HTMLElement { }\nclass B extends Event { }\nexport default A\nexport {B}'},
{code: 'export function baz() { const foo = "bar" }'},
{
code: 'export class a extends Map { }\nexport default class extends Map { }\nexport const b = class extends Map {}',
Expand Down