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

Commit

Permalink
Merge pull request #50 from github/allow-exporting-of-event-sublcasse…
Browse files Browse the repository at this point in the history
…s-alongside-custom-elements

allow exporting of Event sublcasses alongside custom elements
  • Loading branch information
keithamus authored Jan 3, 2023
2 parents bc5734f + afcdf55 commit 3dea2fb
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 6 deletions.
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

0 comments on commit 3dea2fb

Please sign in to comment.