Skip to content

Commit

Permalink
Merge 2848e24 into 6fd5284
Browse files Browse the repository at this point in the history
  • Loading branch information
43081j committed May 9, 2021
2 parents 6fd5284 + 2848e24 commit d168141
Show file tree
Hide file tree
Showing 4 changed files with 200 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,4 @@ to be custom elements.
| [wc/guard-super-call](docs/rules/guard-super-call.md) | Requires a guard before calling a super method inside a Custom Element Lifecycle hook |
| [wc/no-closed-shadow-root](docs/rules/no-closed-shadow-root.md) | Disallows closed shadow roots |
| [wc/no-typos](docs/rules/no-typos.md) | Prevents common typos |
| [wc/no-constructor-params](docs/rules/no-constructor-params.md) | Disallows constructor parameters of custom elements |
30 changes: 30 additions & 0 deletions docs/rules/no-constructor-params.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Disallows constructor parameters in custom elements (no-constructor-params)

Ensures that custom element constructors have no parameters as they
are never constructed directly but are rather constructed automatically when
appended to the DOM (or via `createElement` etc).

## Rule Details

This rule disallows constructor parameters in custom element classes.

The following patterns are considered warnings:

```ts
class Foo extends HTMLElement {
constructor(p1, p2) {}
}
```

The following patterns are not warnings:

```ts
class Foo extends HTMLElement {
constructor() {}
}
```

## When Not To Use It

If you wish to allow parameters to custom element constructors, you should not
use this rule.
71 changes: 71 additions & 0 deletions src/rules/no-constructor-params.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
/**
* @fileoverview Disallows constructor parameters in custom elements
* @author James Garbutt <https://github.com/43081j>
*/

import {Rule} from 'eslint';
import * as ESTree from 'estree';
import {isCustomElement} from '../util';

//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

const rule: Rule.RuleModule = {
meta: {
docs: {
description: 'Disallows constructor parameters in custom elements',
url:
'https://github.com/43081j/eslint-plugin-wc/blob/master/docs/rules/no-constructor-params.md'
},
messages: {
noParams:
'Constructors must be parameterless as they are created indirectly ' +
'when appended to DOM.'
}
},

create(context): Rule.RuleListener {
// variables should be defined here
const constructorQuery =
'ClassBody > MethodDefinition[kind="constructor"]' +
'[value.params.length > 0]';
let insideElement = false;
const source = context.getSourceCode();

//----------------------------------------------------------------------
// Helpers
//----------------------------------------------------------------------
const visitConstructor = (node: ESTree.MethodDefinition): void => {
if (insideElement) {
context.report({
node,
messageId: 'noParams'
});
}
};

//----------------------------------------------------------------------
// Public
//----------------------------------------------------------------------

return {
[`ClassExpression > ${constructorQuery}`]: visitConstructor,
[`ClassDeclaration > ${constructorQuery}`]: visitConstructor,
'ClassDeclaration,ClassExpression': (node: ESTree.Node): void => {
if (
(node.type === 'ClassExpression' ||
node.type === 'ClassDeclaration') &&
isCustomElement(context, node, source.getJSDocComment(node))
) {
insideElement = true;
}
},
'ClassDeclaration,ClassExpression:exit': (): void => {
insideElement = false;
}
};
}
};

export default rule;
98 changes: 98 additions & 0 deletions src/test/rules/no-constructor-params_test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/**
* @fileoverview Disallows constructor parameters in custom elements
* @author James Garbutt <https://github.com/43081j>
*/

//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------

import rule from '../../rules/no-constructor-params';
import {RuleTester} from 'eslint';

//------------------------------------------------------------------------------
// Tests
//------------------------------------------------------------------------------

const ruleTester = new RuleTester({
parserOptions: {
sourceType: 'module',
ecmaVersion: 2015
}
});

const parser = require.resolve('@typescript-eslint/parser');

ruleTester.run('no-constructor-params', rule, {
valid: [
{
code: `class Foo {}`
},
{
code: `class Foo extends Unknown {
constructor(arg1) {}
}`
},
{
code: `class Foo extends HTMLElement {
constructor() {}
}`
},
{
code: `
/** @customElement */
class Foo extends Bar {
constructor() {}
}`
},
{
code: `@customElement('x-foo')
class Foo extends Bar {
constructor() {}
}`,
parser
}
],

invalid: [
{
code: `class Foo extends HTMLElement {
constructor(param1) {}
}`,
errors: [
{
messageId: 'noParams',
line: 2,
column: 9
}
]
},
{
code: `/** @customElement */
class Foo extends Bar {
constructor(param1) {}
}`,
errors: [
{
messageId: 'noParams',
line: 3,
column: 9
}
]
},
{
code: `@customElement('x-foo')
class Foo extends Bar {
constructor(param1) {}
}`,
parser,
errors: [
{
messageId: 'noParams',
line: 3,
column: 9
}
]
}
]
});

0 comments on commit d168141

Please sign in to comment.