@codelaw/rules-stencil 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,69 @@
1
+ ---
2
+ id: stencil/methods-must-be-public
3
+ title: "@Method() members are public"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether the method is public API needs the author"
7
+ stability: preview
8
+ ported_from: [stencil/methods-must-be-public]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `@Method()` isn't marked `private` or `protected`.
13
+
14
+ **Why:** A `@Method()` is part of the element's public API; hiding it in TypeScript contradicts
15
+ that.
16
+
17
+ ```codelaw
18
+ native: stencil/methods-must-be-public
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Remove `private`/`protected`, or remove `@Method()` if it isn't public API.
24
+
25
+ ## Examples
26
+
27
+ ### TypeScript
28
+
29
+ #### Don't
30
+
31
+ ```ts
32
+ @Component({ tag: 'my-card' })
33
+ export class Card {
34
+ /** Opens the card. */
35
+ @Method() private async open() {}
36
+ }
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```ts
42
+ @Component({ tag: 'my-card' })
43
+ export class Card {
44
+ /** Opens the card. */
45
+ @Method() async open() {}
46
+ }
47
+ ```
48
+
49
+ ### TSX
50
+
51
+ #### Don't
52
+
53
+ ```tsx
54
+ @Component({ tag: 'my-card' })
55
+ export class Card {
56
+ /** Opens the card. */
57
+ @Method() private async open() {}
58
+ }
59
+ ```
60
+
61
+ #### Do
62
+
63
+ ```tsx
64
+ @Component({ tag: 'my-card' })
65
+ export class Card {
66
+ /** Opens the card. */
67
+ @Method() async open() {}
68
+ }
69
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ id: stencil/no-unused-watch
3
+ title: "@Watch watches a @Prop or @State"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "which member was meant needs the author"
7
+ stability: preview
8
+ ported_from: [stencil/no-unused-watch]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ `@Watch('name')` names a `@Prop` or `@State` of the same component.
13
+
14
+ **Why:** Watching anything else never fires, so the handler is dead code.
15
+
16
+ ```codelaw
17
+ native: stencil/no-unused-watch
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Correct the name to the @Prop or @State it should watch, or remove the watcher.
23
+
24
+ ## Examples
25
+
26
+ ### TypeScript
27
+
28
+ #### Don't
29
+
30
+ ```ts
31
+ @Component({ tag: 'my-card' })
32
+ export class Card {
33
+ @State() open = false;
34
+ @Watch('opened') onOpen() {}
35
+ }
36
+ ```
37
+
38
+ #### Do
39
+
40
+ ```ts
41
+ @Component({ tag: 'my-card' })
42
+ export class Card {
43
+ @State() open = false;
44
+ @Watch('open') onOpen() {}
45
+ }
46
+ ```
47
+
48
+ ### TSX
49
+
50
+ #### Don't
51
+
52
+ ```tsx
53
+ @Component({ tag: 'my-card' })
54
+ export class Card {
55
+ @State() open = false;
56
+ @Watch('opened') onOpen() {}
57
+ }
58
+ ```
59
+
60
+ #### Do
61
+
62
+ ```tsx
63
+ @Component({ tag: 'my-card' })
64
+ export class Card {
65
+ @State() open = false;
66
+ @Watch('open') onOpen() {}
67
+ }
68
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ id: stencil/own-methods-must-be-private
3
+ title: "A component's own methods are private"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [stencil/own-methods-must-be-private]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A method of a component that isn't a `@Method()`, a lifecycle method or `render()` is `private`.
12
+
13
+ **Why:** Only `@Method()` members reach users of the element; a public own method suggests an API
14
+ that isn't there.
15
+
16
+ ```codelaw
17
+ native: stencil/own-methods-must-be-private
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### TypeScript
23
+
24
+ #### Don't
25
+
26
+ ```ts
27
+ @Component({ tag: 'my-card' })
28
+ export class Card {
29
+ helper() {
30
+ return 1;
31
+ }
32
+ }
33
+ ```
34
+
35
+ #### Do
36
+
37
+ ```ts
38
+ @Component({ tag: 'my-card' })
39
+ export class Card {
40
+ private helper() {
41
+ return 1;
42
+ }
43
+ }
44
+ ```
45
+
46
+ ### TSX
47
+
48
+ #### Don't
49
+
50
+ ```tsx
51
+ @Component({ tag: 'my-card' })
52
+ export class Card {
53
+ helper() {
54
+ return 1;
55
+ }
56
+ }
57
+ ```
58
+
59
+ #### Do
60
+
61
+ ```tsx
62
+ @Component({ tag: 'my-card' })
63
+ export class Card {
64
+ private helper() {
65
+ return 1;
66
+ }
67
+ }
68
+ ```
@@ -0,0 +1,60 @@
1
+ ---
2
+ id: stencil/own-props-must-be-private
3
+ title: "A component's own fields are private"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [stencil/own-props-must-be-private]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A class field of a component without a Stencil decorator is `private`.
12
+
13
+ **Why:** Only `@Prop()` fields reach users of the element; a public plain field suggests an API that
14
+ isn't there.
15
+
16
+ ```codelaw
17
+ native: stencil/own-props-must-be-private
18
+ ```
19
+
20
+ ## Examples
21
+
22
+ ### TypeScript
23
+
24
+ #### Don't
25
+
26
+ ```ts
27
+ @Component({ tag: 'my-card' })
28
+ export class Card {
29
+ cache = new Map();
30
+ }
31
+ ```
32
+
33
+ #### Do
34
+
35
+ ```ts
36
+ @Component({ tag: 'my-card' })
37
+ export class Card {
38
+ private cache = new Map();
39
+ }
40
+ ```
41
+
42
+ ### TSX
43
+
44
+ #### Don't
45
+
46
+ ```tsx
47
+ @Component({ tag: 'my-card' })
48
+ export class Card {
49
+ cache = new Map();
50
+ }
51
+ ```
52
+
53
+ #### Do
54
+
55
+ ```tsx
56
+ @Component({ tag: 'my-card' })
57
+ export class Card {
58
+ private cache = new Map();
59
+ }
60
+ ```
@@ -0,0 +1,67 @@
1
+ ---
2
+ id: stencil/prefer-vdom-listener
3
+ title: "DOM events are handled in render(), not with @Listen"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the handler moves into the rendered markup by hand"
7
+ stability: preview
8
+ ported_from: [stencil/prefer-vdom-listener]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A component handles DOM events on itself (`click`, `keydown`, …) with an `on…` handler in
13
+ `render()`, not `@Listen`; `@Listen` with a `target` is fine.
14
+
15
+ **Why:** Handlers in `render()` are scoped to the element they're on and cheaper than a host-wide
16
+ listener.
17
+
18
+ ```codelaw
19
+ native: stencil/prefer-vdom-listener
20
+ ```
21
+
22
+ ## How to fix
23
+
24
+ 1. Attach the handler in `render()` (e.g. `onClick={…}` on `<Host>`).
25
+ 2. Remove the `@Listen`.
26
+
27
+ ## Examples
28
+
29
+ ### TypeScript
30
+
31
+ #### Don't
32
+
33
+ ```ts
34
+ @Component({ tag: 'my-card' })
35
+ export class Card {
36
+ @Listen('click') onClick() {}
37
+ }
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```ts
43
+ @Component({ tag: 'my-card' })
44
+ export class Card {
45
+ @Listen('resize', { target: 'window' }) onResize() {}
46
+ }
47
+ ```
48
+
49
+ ### TSX
50
+
51
+ #### Don't
52
+
53
+ ```tsx
54
+ @Component({ tag: 'my-card' })
55
+ export class Card {
56
+ @Listen('click') onClick() {}
57
+ }
58
+ ```
59
+
60
+ #### Do
61
+
62
+ ```tsx
63
+ @Component({ tag: 'my-card' })
64
+ export class Card {
65
+ @Listen('resize', { target: 'window' }) onResize() {}
66
+ }
67
+ ```
@@ -0,0 +1,63 @@
1
+ ---
2
+ id: stencil/prop-readonly
3
+ title: "@Prop() members are readonly unless mutable"
4
+ languages: [typescript, tsx]
5
+ fix: auto
6
+ stability: preview
7
+ ported_from: [stencil/props-must-be-readonly]
8
+ since: 0.1.0
9
+ ---
10
+
11
+ A `@Prop()` is `readonly`, unless its options say `mutable: true`.
12
+
13
+ **Why:** Props are set from outside; a component that writes one by accident fights its parent.
14
+
15
+ ```codelaw
16
+ native: stencil/prop-readonly
17
+ ```
18
+
19
+ ## Examples
20
+
21
+ ### TypeScript
22
+
23
+ #### Don't
24
+
25
+ ```ts
26
+ @Component({ tag: 'my-card' })
27
+ export class Card {
28
+ /** The heading. */
29
+ @Prop() heading: string;
30
+ }
31
+ ```
32
+
33
+ #### Do
34
+
35
+ ```ts
36
+ @Component({ tag: 'my-card' })
37
+ export class Card {
38
+ /** The heading. */
39
+ @Prop() readonly heading: string;
40
+ }
41
+ ```
42
+
43
+ ### TSX
44
+
45
+ #### Don't
46
+
47
+ ```tsx
48
+ @Component({ tag: 'my-card' })
49
+ export class Card {
50
+ /** The heading. */
51
+ @Prop() heading: string;
52
+ }
53
+ ```
54
+
55
+ #### Do
56
+
57
+ ```tsx
58
+ @Component({ tag: 'my-card' })
59
+ export class Card {
60
+ /** The heading. */
61
+ @Prop() readonly heading: string;
62
+ }
63
+ ```
@@ -0,0 +1,68 @@
1
+ ---
2
+ id: stencil/props-must-be-public
3
+ title: "@Prop() members are public"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether the field is public API needs the author"
7
+ stability: preview
8
+ ported_from: [stencil/props-must-be-public]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `@Prop()` isn't marked `private` or `protected`.
13
+
14
+ **Why:** A prop is set from outside the component; hiding it in TypeScript contradicts that.
15
+
16
+ ```codelaw
17
+ native: stencil/props-must-be-public
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Remove `private`/`protected`, or make it a `@State()` if it is internal.
23
+
24
+ ## Examples
25
+
26
+ ### TypeScript
27
+
28
+ #### Don't
29
+
30
+ ```ts
31
+ @Component({ tag: 'my-card' })
32
+ export class Card {
33
+ /** The heading. */
34
+ @Prop() private readonly heading: string;
35
+ }
36
+ ```
37
+
38
+ #### Do
39
+
40
+ ```ts
41
+ @Component({ tag: 'my-card' })
42
+ export class Card {
43
+ /** The heading. */
44
+ @Prop() readonly heading: string;
45
+ }
46
+ ```
47
+
48
+ ### TSX
49
+
50
+ #### Don't
51
+
52
+ ```tsx
53
+ @Component({ tag: 'my-card' })
54
+ export class Card {
55
+ /** The heading. */
56
+ @Prop() private readonly heading: string;
57
+ }
58
+ ```
59
+
60
+ #### Do
61
+
62
+ ```tsx
63
+ @Component({ tag: 'my-card' })
64
+ export class Card {
65
+ /** The heading. */
66
+ @Prop() readonly heading: string;
67
+ }
68
+ ```
@@ -0,0 +1,66 @@
1
+ ---
2
+ id: stencil/required-jsdoc
3
+ title: "Public members have JSDoc"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "the documentation text needs the author"
7
+ stability: preview
8
+ ported_from: [stencil/required-jsdoc]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ Every `@Prop()`, `@Method()` and `@Event()` has a `/** … */` comment.
13
+
14
+ **Why:** Stencil turns these comments into the component's documentation and editor hints.
15
+
16
+ ```codelaw
17
+ native: stencil/required-jsdoc
18
+ ```
19
+
20
+ ## How to fix
21
+
22
+ 1. Write a `/** … */` comment above the member saying what it is for.
23
+
24
+ ## Examples
25
+
26
+ ### TypeScript
27
+
28
+ #### Don't
29
+
30
+ ```ts
31
+ @Component({ tag: 'my-card' })
32
+ export class Card {
33
+ @Prop() readonly heading: string;
34
+ }
35
+ ```
36
+
37
+ #### Do
38
+
39
+ ```ts
40
+ @Component({ tag: 'my-card' })
41
+ export class Card {
42
+ /** The heading shown at the top. */
43
+ @Prop() readonly heading: string;
44
+ }
45
+ ```
46
+
47
+ ### TSX
48
+
49
+ #### Don't
50
+
51
+ ```tsx
52
+ @Component({ tag: 'my-card' })
53
+ export class Card {
54
+ @Prop() readonly heading: string;
55
+ }
56
+ ```
57
+
58
+ #### Do
59
+
60
+ ```tsx
61
+ @Component({ tag: 'my-card' })
62
+ export class Card {
63
+ /** The heading shown at the top. */
64
+ @Prop() readonly heading: string;
65
+ }
66
+ ```
@@ -0,0 +1,70 @@
1
+ ---
2
+ id: stencil/reserved-member-names
3
+ title: "Public members don't reuse HTML element names"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "renaming a public member changes every user"
7
+ stability: preview
8
+ ported_from: [stencil/reserved-member-names]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `@Prop()` or `@Method()` isn't named after an HTML global attribute or an `HTMLElement` member
13
+ (`title`, `hidden`, `id`, `click`, …).
14
+
15
+ **Why:** The element already has a member of that name, so the component's version clashes with it.
16
+
17
+ ```codelaw
18
+ native: stencil/reserved-member-names
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Rename the member.
24
+ 2. Update its users.
25
+
26
+ ## Examples
27
+
28
+ ### TypeScript
29
+
30
+ #### Don't
31
+
32
+ ```ts
33
+ @Component({ tag: 'my-card' })
34
+ export class Card {
35
+ /** The card's title. */
36
+ @Prop() readonly title: string;
37
+ }
38
+ ```
39
+
40
+ #### Do
41
+
42
+ ```ts
43
+ @Component({ tag: 'my-card' })
44
+ export class Card {
45
+ /** The card's heading. */
46
+ @Prop() readonly heading: string;
47
+ }
48
+ ```
49
+
50
+ ### TSX
51
+
52
+ #### Don't
53
+
54
+ ```tsx
55
+ @Component({ tag: 'my-card' })
56
+ export class Card {
57
+ /** The card's title. */
58
+ @Prop() readonly title: string;
59
+ }
60
+ ```
61
+
62
+ #### Do
63
+
64
+ ```tsx
65
+ @Component({ tag: 'my-card' })
66
+ export class Card {
67
+ /** The card's heading. */
68
+ @Prop() readonly heading: string;
69
+ }
70
+ ```
@@ -0,0 +1,75 @@
1
+ ---
2
+ id: stencil/strict-mutable
3
+ title: "mutable: true only on props the component changes"
4
+ languages: [typescript, tsx]
5
+ fix: manual
6
+ fix_reason: "whether the component should change the prop needs the author"
7
+ stability: preview
8
+ ported_from: [stencil/strict-mutable]
9
+ since: 0.1.0
10
+ ---
11
+
12
+ A `@Prop({ mutable: true })` is assigned somewhere in the component.
13
+
14
+ **Why:** `mutable: true` says the component changes the prop; if it never does, the flag only hides
15
+ that the prop should be `readonly`.
16
+
17
+ ```codelaw
18
+ native: stencil/strict-mutable
19
+ ```
20
+
21
+ ## How to fix
22
+
23
+ 1. Remove `mutable: true` and make the prop `readonly`, or assign it where the component means to.
24
+
25
+ ## Examples
26
+
27
+ ### TypeScript
28
+
29
+ #### Don't
30
+
31
+ ```ts
32
+ @Component({ tag: 'my-card' })
33
+ export class Card {
34
+ /** The count. */
35
+ @Prop({ mutable: true }) count = 0;
36
+ }
37
+ ```
38
+
39
+ #### Do
40
+
41
+ ```ts
42
+ @Component({ tag: 'my-card' })
43
+ export class Card {
44
+ /** The count. */
45
+ @Prop({ mutable: true }) count = 0;
46
+ private inc() {
47
+ this.count++;
48
+ }
49
+ }
50
+ ```
51
+
52
+ ### TSX
53
+
54
+ #### Don't
55
+
56
+ ```tsx
57
+ @Component({ tag: 'my-card' })
58
+ export class Card {
59
+ /** The count. */
60
+ @Prop({ mutable: true }) count = 0;
61
+ }
62
+ ```
63
+
64
+ #### Do
65
+
66
+ ```tsx
67
+ @Component({ tag: 'my-card' })
68
+ export class Card {
69
+ /** The count. */
70
+ @Prop({ mutable: true }) count = 0;
71
+ private inc() {
72
+ this.count++;
73
+ }
74
+ }
75
+ ```