@codelaw/rules-stencil 0.0.0-stage → 0.1.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 +40 -2
- package/codelaw-pack.toml +6 -0
- package/package.json +14 -4
- package/presets/stencil/conventions.toml +4 -0
- package/presets/stencil/recommended.toml +18 -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/decorators-context.md +61 -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
package/LICENSE
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Arpit Arya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
SPDX-License-Identifier: MIT
|
package/NOTICE
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
@codelaw/rules-stencil
|
|
2
|
+
|
|
3
|
+
The rules are reimplementations written for codelaw. Their `ported_from:`
|
|
4
|
+
fields name the @stencil/eslint-plugin rules (MIT License) whose documented
|
|
5
|
+
behaviour they reproduce; no @stencil/eslint-plugin code or documentation text
|
|
6
|
+
is included.
|
package/README.md
CHANGED
|
@@ -1,3 +1,41 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @codelaw/rules-stencil
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
codelaw's Stencil rules — one of codelaw's first-party rule packs
|
|
4
|
+
([SR-RULE-PACKS](../../records/0101_rule-packs.md)). It ships on
|
|
5
|
+
npm only, as `@codelaw/rules-stencil`; PyPI has no copy (L6 decision 11).
|
|
6
|
+
|
|
7
|
+
```toml
|
|
8
|
+
# codelaw.toml
|
|
9
|
+
extends = ["codelaw:js/recommended", "codelaw:stencil/recommended"]
|
|
10
|
+
preview = true # every rule is `preview` until a corpus run promotes it
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Presets
|
|
14
|
+
|
|
15
|
+
| preset | rules | ported from |
|
|
16
|
+
|---|---|---|
|
|
17
|
+
| `stencil/recommended` | 15 | @stencil/eslint-plugin 1.4.0 `recommended` — 15 of its 21 rules |
|
|
18
|
+
| `stencil/conventions` | 1 | codelaw's starter catalogue: `stencil/tag-prefix` — opt in |
|
|
19
|
+
|
|
20
|
+
Every rule is **reimplemented**, not vendored: the matchers, messages and docs
|
|
21
|
+
are written fresh, and each rule's `ported_from:` names the source rule.
|
|
22
|
+
|
|
23
|
+
## How the ports differ
|
|
24
|
+
|
|
25
|
+
Every rule matches its source's documented behaviour on the source's own
|
|
26
|
+
examples. Where codelaw differs, the rule's `## Differences from the source`
|
|
27
|
+
section says so. The larger ones:
|
|
28
|
+
|
|
29
|
+
| rule | difference |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `stencil/tag-prefix` | with no `prefix` option set, a tag only needs some prefix |
|
|
32
|
+
| `stencil/prop-readonly` | the starter id for upstream `props-must-be-readonly` |
|
|
33
|
+
|
|
34
|
+
## Not ported, and why
|
|
35
|
+
|
|
36
|
+
| rule | why |
|
|
37
|
+
|---|---|
|
|
38
|
+
| `stencil/async-methods`, `stencil/render-returns-host`, `stencil/single-export`, `stencil/strict-boolean-conditions` | need type information |
|
|
39
|
+
| `stencil/element-type` | needs the component's tag mapped to its element type name |
|
|
40
|
+
| `stencil/decorators-style` | layout: the formatter owns it |
|
|
41
|
+
| `stencil/dependency-suggestions` | advisory, with no fixed check to port |
|
package/package.json
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codelaw/rules-stencil",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "codelaw's Stencil rules, from @stencil/eslint-plugin; npm only (SR-RULE-PACKS)",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/arpitarya/codelaw.git"
|
|
9
|
+
},
|
|
10
|
+
"homepage": "https://github.com/arpitarya/codelaw",
|
|
11
|
+
"keywords": [
|
|
12
|
+
"codelaw",
|
|
13
|
+
"codelaw-pack",
|
|
14
|
+
"lint-rules"
|
|
15
|
+
]
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
description = "@stencil/eslint-plugin 1.4.0 recommended without its type-checked rules, reimplemented"
|
|
2
|
+
|
|
3
|
+
[rules]
|
|
4
|
+
"stencil/ban-default-true" = "error"
|
|
5
|
+
"stencil/ban-exported-const-enums" = "error"
|
|
6
|
+
"stencil/ban-prefix" = "error"
|
|
7
|
+
"stencil/decorators-context" = "error"
|
|
8
|
+
"stencil/host-data-deprecated" = "error"
|
|
9
|
+
"stencil/methods-must-be-public" = "error"
|
|
10
|
+
"stencil/no-unused-watch" = "error"
|
|
11
|
+
"stencil/own-methods-must-be-private" = "error"
|
|
12
|
+
"stencil/own-props-must-be-private" = "error"
|
|
13
|
+
"stencil/prefer-vdom-listener" = "error"
|
|
14
|
+
"stencil/prop-readonly" = "error"
|
|
15
|
+
"stencil/props-must-be-public" = "error"
|
|
16
|
+
"stencil/required-jsdoc" = "error"
|
|
17
|
+
"stencil/reserved-member-names" = "error"
|
|
18
|
+
"stencil/strict-mutable" = "error"
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/ban-default-true
|
|
3
|
+
title: "A boolean @Prop defaults to false"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "inverting the prop renames it for every user"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stencil/ban-default-true]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A `@Prop()` of a Stencil component doesn't default to `true`.
|
|
13
|
+
|
|
14
|
+
**Why:** An HTML boolean attribute can only switch something on; a prop that starts `true` can't be
|
|
15
|
+
turned off from markup.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
native: stencil/ban-default-true
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to fix
|
|
22
|
+
|
|
23
|
+
1. Invert the prop's meaning so it defaults to `false` (e.g. `closable` → `hideClose`).
|
|
24
|
+
2. Update the component's markup users.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
### TypeScript
|
|
29
|
+
|
|
30
|
+
#### Don't
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
@Component({ tag: 'my-card' })
|
|
34
|
+
export class Card {
|
|
35
|
+
/** Shows the close button. */
|
|
36
|
+
@Prop() readonly closable = true;
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Do
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
@Component({ tag: 'my-card' })
|
|
44
|
+
export class Card {
|
|
45
|
+
/** Hides the close button. */
|
|
46
|
+
@Prop() readonly hideClose = false;
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### TSX
|
|
51
|
+
|
|
52
|
+
#### Don't
|
|
53
|
+
|
|
54
|
+
```tsx
|
|
55
|
+
@Component({ tag: 'my-card' })
|
|
56
|
+
export class Card {
|
|
57
|
+
/** Shows the close button. */
|
|
58
|
+
@Prop() readonly closable = true;
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
#### Do
|
|
63
|
+
|
|
64
|
+
```tsx
|
|
65
|
+
@Component({ tag: 'my-card' })
|
|
66
|
+
export class Card {
|
|
67
|
+
/** Hides the close button. */
|
|
68
|
+
@Prop() readonly hideClose = false;
|
|
69
|
+
}
|
|
70
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/ban-exported-const-enums
|
|
3
|
+
title: "No exported const enums"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: auto
|
|
6
|
+
stability: preview
|
|
7
|
+
ported_from: [stencil/ban-exported-const-enums]
|
|
8
|
+
since: 0.1.0
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
An exported enum is a plain `enum`, not a `const enum`.
|
|
12
|
+
|
|
13
|
+
**Why:** A `const enum` is erased at compile time, so code that imports it from the built bundle
|
|
14
|
+
finds nothing.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: stencil/ban-exported-const-enums
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Examples
|
|
21
|
+
|
|
22
|
+
### TypeScript
|
|
23
|
+
|
|
24
|
+
#### Don't
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
export const enum Size {
|
|
28
|
+
Small,
|
|
29
|
+
Large,
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
#### Do
|
|
34
|
+
|
|
35
|
+
```ts
|
|
36
|
+
export enum Size {
|
|
37
|
+
Small,
|
|
38
|
+
Large,
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### TSX
|
|
43
|
+
|
|
44
|
+
#### Don't
|
|
45
|
+
|
|
46
|
+
```tsx
|
|
47
|
+
export const enum Size {
|
|
48
|
+
Small,
|
|
49
|
+
Large,
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
#### Do
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
export enum Size {
|
|
57
|
+
Small,
|
|
58
|
+
Large,
|
|
59
|
+
}
|
|
60
|
+
```
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/ban-prefix
|
|
3
|
+
title: "A component tag doesn't use a reserved prefix"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "renaming a tag changes every page that uses it"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
prefixes: { type: "string[]", default: ["stencil", "stnl", "st"] }
|
|
10
|
+
ported_from: [stencil/ban-prefix]
|
|
11
|
+
since: 0.1.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
A component's `tag` doesn't start with a prefix Stencil reserves (`stencil-`, `stnl-`, `st-` by
|
|
15
|
+
default; the `prefixes` option changes the list).
|
|
16
|
+
|
|
17
|
+
**Why:** Reserved prefixes may clash with Stencil's own elements.
|
|
18
|
+
|
|
19
|
+
```codelaw
|
|
20
|
+
native: stencil/ban-prefix
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## How to fix
|
|
24
|
+
|
|
25
|
+
1. Choose a prefix of your own and rename the tag.
|
|
26
|
+
2. Update every usage of the element.
|
|
27
|
+
|
|
28
|
+
## Examples
|
|
29
|
+
|
|
30
|
+
### TypeScript
|
|
31
|
+
|
|
32
|
+
#### Don't
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
@Component({ tag: 'stencil-card' })
|
|
36
|
+
export class Card {
|
|
37
|
+
render() {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
#### Do
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
@Component({ tag: 'acme-card' })
|
|
47
|
+
export class Card {
|
|
48
|
+
render() {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### TSX
|
|
55
|
+
|
|
56
|
+
#### Don't
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
@Component({ tag: 'stencil-card' })
|
|
60
|
+
export class Card {
|
|
61
|
+
render() {
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
#### Do
|
|
68
|
+
|
|
69
|
+
```tsx
|
|
70
|
+
@Component({ tag: 'acme-card' })
|
|
71
|
+
export class Card {
|
|
72
|
+
render() {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
```
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/decorators-context
|
|
3
|
+
title: "Stencil decorators only inside @Component classes"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "whether the class should be a component needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stencil/decorators-context]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
`@Prop`, `@State`, `@Element`, `@Method`, `@Watch`, `@Listen`, `@Event` and `@AttachInternals`
|
|
13
|
+
appear only in a class decorated with `@Component`.
|
|
14
|
+
|
|
15
|
+
**Why:** Outside a component Stencil ignores them, so the code silently does nothing.
|
|
16
|
+
|
|
17
|
+
```codelaw
|
|
18
|
+
native: stencil/decorators-context
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## How to fix
|
|
22
|
+
|
|
23
|
+
1. Make the class a `@Component`, or remove the Stencil decorators.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### TypeScript
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
export class Store {
|
|
33
|
+
@State() count = 0;
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
#### Do
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
export class Store {
|
|
41
|
+
count = 0;
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### TSX
|
|
46
|
+
|
|
47
|
+
#### Don't
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
export class Store {
|
|
51
|
+
@State() count = 0;
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
#### Do
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
export class Store {
|
|
59
|
+
count = 0;
|
|
60
|
+
}
|
|
61
|
+
```
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/host-data-deprecated
|
|
3
|
+
title: "No hostData()"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the attributes move into `render()` by hand"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stencil/host-data-deprecated]
|
|
9
|
+
since: 0.1.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A component doesn't define `hostData()`.
|
|
13
|
+
|
|
14
|
+
**Why:** `hostData()` is deprecated; the host element's attributes are set by rendering `<Host>`.
|
|
15
|
+
|
|
16
|
+
```codelaw
|
|
17
|
+
native: stencil/host-data-deprecated
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## How to fix
|
|
21
|
+
|
|
22
|
+
1. Render a `<Host>` element in `render()` with the attributes `hostData()` returned.
|
|
23
|
+
2. Remove `hostData()`.
|
|
24
|
+
|
|
25
|
+
## Examples
|
|
26
|
+
|
|
27
|
+
### TypeScript
|
|
28
|
+
|
|
29
|
+
#### Don't
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
@Component({ tag: 'my-card' })
|
|
33
|
+
export class Card {
|
|
34
|
+
hostData() {
|
|
35
|
+
return { class: 'card' };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
#### Do
|
|
41
|
+
|
|
42
|
+
```ts
|
|
43
|
+
@Component({ tag: 'my-card' })
|
|
44
|
+
export class Card {
|
|
45
|
+
render() {
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### TSX
|
|
52
|
+
|
|
53
|
+
#### Don't
|
|
54
|
+
|
|
55
|
+
```tsx
|
|
56
|
+
@Component({ tag: 'my-card' })
|
|
57
|
+
export class Card {
|
|
58
|
+
hostData() {
|
|
59
|
+
return { class: 'card' };
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
#### Do
|
|
65
|
+
|
|
66
|
+
```tsx
|
|
67
|
+
@Component({ tag: 'my-card' })
|
|
68
|
+
export class Card {
|
|
69
|
+
render() {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
@@ -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
|
+
```
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/tag-prefix
|
|
3
|
+
title: "Component tags start with the project's prefix"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "renaming a tag changes every page that uses it"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
prefix: { type: string, default: "", description: "the prefix every tag must start with" }
|
|
10
|
+
since: 0.1.0
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
Every component's `tag` starts with the project's prefix (the `prefix` option); with no prefix set,
|
|
14
|
+
a tag still needs one.
|
|
15
|
+
|
|
16
|
+
**Why:** One prefix keeps a project's elements apart from other libraries'.
|
|
17
|
+
|
|
18
|
+
```codelaw
|
|
19
|
+
native: stencil/tag-prefix
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## How to fix
|
|
23
|
+
|
|
24
|
+
1. Rename the tag to start with the project's prefix.
|
|
25
|
+
2. Update every usage of the element.
|
|
26
|
+
|
|
27
|
+
## Examples
|
|
28
|
+
|
|
29
|
+
### TypeScript
|
|
30
|
+
|
|
31
|
+
#### Don't
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
@Component({ tag: 'card' })
|
|
35
|
+
export class Card {
|
|
36
|
+
render() {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
#### Do
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
@Component({ tag: 'acme-card' })
|
|
46
|
+
export class Card {
|
|
47
|
+
render() {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### TSX
|
|
54
|
+
|
|
55
|
+
#### Don't
|
|
56
|
+
|
|
57
|
+
```tsx
|
|
58
|
+
@Component({ tag: 'card' })
|
|
59
|
+
export class Card {
|
|
60
|
+
render() {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
#### Do
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
@Component({ tag: 'acme-card' })
|
|
70
|
+
export class Card {
|
|
71
|
+
render() {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
```
|