@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.
- package/LICENSE +23 -0
- package/NOTICE +6 -0
- package/README.md +44 -2
- package/codelaw-pack.toml +6 -0
- package/corpus.toml +22 -0
- package/package.json +14 -4
- package/presets/stencil/conventions.toml +4 -0
- package/presets/stencil/recommended.toml +20 -0
- package/rules/stencil/ban-default-true.md +70 -0
- package/rules/stencil/ban-exported-const-enums.md +60 -0
- package/rules/stencil/ban-prefix.md +76 -0
- package/rules/stencil/ban-side-effects.md +81 -0
- package/rules/stencil/decorators-context.md +61 -0
- package/rules/stencil/enforce-slot-jsdoc.md +68 -0
- package/rules/stencil/host-data-deprecated.md +73 -0
- package/rules/stencil/methods-must-be-public.md +69 -0
- package/rules/stencil/no-unused-watch.md +68 -0
- package/rules/stencil/own-methods-must-be-private.md +68 -0
- package/rules/stencil/own-props-must-be-private.md +60 -0
- package/rules/stencil/prefer-vdom-listener.md +67 -0
- package/rules/stencil/prop-readonly.md +63 -0
- package/rules/stencil/props-must-be-public.md +68 -0
- package/rules/stencil/required-jsdoc.md +66 -0
- package/rules/stencil/reserved-member-names.md +70 -0
- package/rules/stencil/strict-mutable.md +75 -0
- package/rules/stencil/tag-prefix.md +75 -0
|
@@ -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
|
+
```
|