Thanks to visit codestin.com
Credit goes to github.com

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

Add no-unchecked-define rule #28

Merged
merged 1 commit into from
Apr 12, 2021
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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ JSON ESLint config example:
- [No DOM Traversal in Connectedcallback](./docs/rules/no-dom-traversal-in-connectedcallback.md)
- [No Exports with Element](./docs/rules/no-exports-with-element.md)
- [No Method Prefixed with on](./docs/rules/no-method-prefixed-with-on.md)
- [No Unchecked Define](./docs/rules/no-unchecked-define.md)
- [One Element Per File](./docs/rules/one-element-per-file.md)
- [Tag Name Matches Class](./docs/rules/tag-name-matches-class.md)
- [Valid Tag Name](./docs/rules/valid-tag-name.md)
31 changes: 31 additions & 0 deletions docs/rules/no-unchecked-define.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# No Unchecked Define

Registering a custom element under the same tag as another defined custom element will cause a runtime exception in browsers.

Some JavaScript might be inadvertently loaded twice on the same page in a web application, causing run time errors when the same element is registered twice.

## Rule Details

This rule ensures that all custom element definition calls are wrapped in guards if that element is already defined.

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

```js
window.customElements.define('foo-bar', class extends HTMLElement {})
```

👍 Examples of **correct** code for this rule:

```js
if (!window.customElements.get('foo-bar')) {
window.customElements.define('foo-bar', class extends HTMLElement {})
}
```

## When Not To Use It

If you are comfortable with the trade-offs of not checking if a custom element exists before defining it.

## Version

This rule was introduced in v0.0.1
1 change: 1 addition & 0 deletions lib/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = {
'no-dom-traversal-in-connectedcallback': require('./rules/no-dom-traversal-in-connectedcallback'),
'no-exports-with-element': require('./rules/no-exports-with-element'),
'no-method-prefixed-with-on': require('./rules/no-method-prefixed-with-on'),
'no-unchecked-define': require('./rules/no-unchecked-define'),
'one-element-per-file': require('./rules/one-element-per-file'),
'tag-name-matches-class': require('./rules/tag-name-matches-class'),
'valid-tag-name': require('./rules/valid-tag-name')
Expand Down
41 changes: 41 additions & 0 deletions lib/rules/no-unchecked-define.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
const s = require('../custom-selectors')

let definedCustomElements = new Map()

module.exports = {
meta: {
type: 'layout',
docs: {description: '', url: require('../url')(module)}
},
schema: [],
create(context) {
definedCustomElements = new Map()
return {
[`IfStatement:matches([test.type=UnaryExpression],[test.type=BinaryExpression]) ${s.customElements.get}`](node) {
if (node.parent.type === 'UnaryExpression') {
let unaryCounter = 0
let parent = node.parent
while (parent.type === 'UnaryExpression') {
unaryCounter++
parent = parent.parent
}
if (unaryCounter % 2 !== 0) {
definedCustomElements.set(node.arguments[0].value, node)
}
} else {
definedCustomElements.set(node.arguments[0].value, node)
}
},
[s.customElements.define](node) {
if (definedCustomElements.has(node.arguments[0].value)) {
definedCustomElements.delete(node.arguments[0].value)
} else {
context.report(
node,
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined'
)
}
}
}
}
}
83 changes: 83 additions & 0 deletions test/no-unchecked-define.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const rule = require('../lib/rules/no-unchecked-define')
const RuleTester = require('eslint').RuleTester

const ruleTester = new RuleTester({env: {es2020: true}})
ruleTester.run('no-unchecked-define', rule, {
valid: [
{
code:
'if (!window.customElements.get("foo-bar")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } '
},
{
code:
'if (!customElements.get("foo-bar")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } '
},
{
code:
'if (customElements.get("foo-bar") == null) { window.customElements.define("foo-bar", class extends HTMLElement {}) } '
},
{
code:
'if (customElements.get("foo-bar") == undefined) { window.customElements.define("foo-bar", class extends HTMLElement {}) } '
},
{
code:
'if (!!!customElements.get("foo-bar")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } '
}
],
invalid: [
{
code: 'window.customElements.define("foo-bar", class extends HTMLElement {})',
errors: [
{
message:
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined',
type: 'CallExpression'
}
]
},
{
code:
'if (customElements.get("foo-bar")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } ',
errors: [
{
message:
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined',
type: 'CallExpression'
}
]
},
{
code:
'if (!customElements.get("bar-foo")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } ',
errors: [
{
message:
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined',
type: 'CallExpression'
}
]
},
{
code: 'customElements.define("foo-bar", class extends HTMLElement {})',
errors: [
{
message:
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined',
type: 'CallExpression'
}
]
},
{
code:
'if (!!customElements.get("foo-bar")) { window.customElements.define("foo-bar", class extends HTMLElement {}) } ',
errors: [
{
message:
'Make sure to wrap customElements.define calls in checks to see if the element has already been defined',
type: 'CallExpression'
}
]
}
]
})