@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
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,45 @@
|
|
|
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
|
+
<!-- docs-sync:presets -->
|
|
16
|
+
|
|
17
|
+
| preset | rules | ported from |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `stencil/recommended` | 17 | @stencil/eslint-plugin 1.4.0 `recommended` — 16 of the 23 rules it turns on, and `stencil/prop-readonly` (upstream `props-must-be-readonly`) |
|
|
20
|
+
| `stencil/conventions` | 1 | codelaw's starter catalogue: `stencil/tag-prefix` — opt in |
|
|
21
|
+
|
|
22
|
+
<!-- /docs-sync:presets -->
|
|
23
|
+
|
|
24
|
+
Every rule is **reimplemented**, not vendored: the matchers, messages and docs
|
|
25
|
+
are written fresh, and each rule's `ported_from:` names the source rule.
|
|
26
|
+
|
|
27
|
+
## How the ports differ
|
|
28
|
+
|
|
29
|
+
Every rule matches its source's documented behaviour on the source's own
|
|
30
|
+
examples. Where codelaw differs, the rule's `## Differences from the source`
|
|
31
|
+
section says so. The larger ones:
|
|
32
|
+
|
|
33
|
+
| rule | difference |
|
|
34
|
+
|---|---|
|
|
35
|
+
| `stencil/tag-prefix` | with no `prefix` option set, a tag only needs some prefix |
|
|
36
|
+
| `stencil/prop-readonly` | the starter id for upstream `props-must-be-readonly` |
|
|
37
|
+
|
|
38
|
+
## Not ported, and why
|
|
39
|
+
|
|
40
|
+
| rule | why |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `stencil/async-methods`, `stencil/render-returns-host`, `stencil/single-export`, `stencil/strict-boolean-conditions` | need type information |
|
|
43
|
+
| `stencil/element-type` | needs the component's tag mapped to its element type name |
|
|
44
|
+
| `stencil/decorators-style` | layout: the formatter owns it |
|
|
45
|
+
| `stencil/dependency-suggestions` | advisory, with no fixed check to port |
|
package/corpus.toml
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# `codelaw test --corpus` finding counts (SR-RULE-AUTHORING decision 4).
|
|
2
|
+
# Rewrite with --update-snapshot, and review the change.
|
|
3
|
+
|
|
4
|
+
[findings]
|
|
5
|
+
"stencil/ban-default-true" = 39
|
|
6
|
+
"stencil/ban-exported-const-enums" = 0
|
|
7
|
+
"stencil/ban-prefix" = 0
|
|
8
|
+
"stencil/ban-side-effects" = 141
|
|
9
|
+
"stencil/decorators-context" = 0
|
|
10
|
+
"stencil/enforce-slot-jsdoc" = 50
|
|
11
|
+
"stencil/host-data-deprecated" = 0
|
|
12
|
+
"stencil/methods-must-be-public" = 0
|
|
13
|
+
"stencil/no-unused-watch" = 6
|
|
14
|
+
"stencil/own-methods-must-be-private" = 202
|
|
15
|
+
"stencil/own-props-must-be-private" = 224
|
|
16
|
+
"stencil/prefer-vdom-listener" = 12
|
|
17
|
+
"stencil/prop-readonly" = 589
|
|
18
|
+
"stencil/props-must-be-public" = 0
|
|
19
|
+
"stencil/required-jsdoc" = 3
|
|
20
|
+
"stencil/reserved-member-names" = 9
|
|
21
|
+
"stencil/strict-mutable" = 8
|
|
22
|
+
"stencil/tag-prefix" = 0
|
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.2.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,20 @@
|
|
|
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/ban-side-effects" = "error"
|
|
8
|
+
"stencil/decorators-context" = "error"
|
|
9
|
+
"stencil/enforce-slot-jsdoc" = "error"
|
|
10
|
+
"stencil/host-data-deprecated" = "error"
|
|
11
|
+
"stencil/methods-must-be-public" = "error"
|
|
12
|
+
"stencil/no-unused-watch" = "error"
|
|
13
|
+
"stencil/own-methods-must-be-private" = "error"
|
|
14
|
+
"stencil/own-props-must-be-private" = "error"
|
|
15
|
+
"stencil/prefer-vdom-listener" = "error"
|
|
16
|
+
"stencil/prop-readonly" = "error"
|
|
17
|
+
"stencil/props-must-be-public" = "error"
|
|
18
|
+
"stencil/required-jsdoc" = "error"
|
|
19
|
+
"stencil/reserved-member-names" = "error"
|
|
20
|
+
"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,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/ban-side-effects
|
|
3
|
+
title: "No calls at a module's top level"
|
|
4
|
+
languages: [typescript, tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "where the call should run instead — a function, a lifecycle method — needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
options:
|
|
9
|
+
allow: { type: "string[]", default: ["describe", "test", "bind", "createStore"], description: "functions that may be called at the top level; setting it replaces the default list" }
|
|
10
|
+
ported_from: [stencil/ban-side-effects]
|
|
11
|
+
since: 0.2.0
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
A module makes no calls at its top level: every call sits inside a function, a method or a class, or
|
|
15
|
+
in an `export` declaration. Test files (a name with `spec.`, `e2e.` or `test.` in it) are not
|
|
16
|
+
checked, and `describe`, `test`, `bind` and `createStore` may be called anywhere (the `allow` option
|
|
17
|
+
changes that list).
|
|
18
|
+
|
|
19
|
+
**Why:** Stencil's compiler loads modules to analyse them and bundles them lazily, so a call that runs
|
|
20
|
+
on import runs at a time no one chose, and may not run at all when a bundle is split.
|
|
21
|
+
|
|
22
|
+
```codelaw
|
|
23
|
+
native: stencil/ban-side-effects
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## How to fix
|
|
27
|
+
|
|
28
|
+
1. Move the call into the function, method or lifecycle hook (`componentWillLoad`, `connectedCallback`)
|
|
29
|
+
that needs its effect.
|
|
30
|
+
2. If the call builds a value, export a function that builds it, or keep it in an `export const`.
|
|
31
|
+
3. If the call must run at load time, add the function's name to the `allow` option.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
### TypeScript
|
|
36
|
+
|
|
37
|
+
#### Don't
|
|
38
|
+
|
|
39
|
+
```ts
|
|
40
|
+
import { setupConfig } from './config';
|
|
41
|
+
|
|
42
|
+
setupConfig({ mode: 'md' });
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
#### Do
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { setupConfig } from './config';
|
|
49
|
+
|
|
50
|
+
export function init() {
|
|
51
|
+
setupConfig({ mode: 'md' });
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### TSX
|
|
56
|
+
|
|
57
|
+
#### Don't
|
|
58
|
+
|
|
59
|
+
```tsx
|
|
60
|
+
import { setupConfig } from './config';
|
|
61
|
+
|
|
62
|
+
setupConfig({ mode: 'md' });
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
#### Do
|
|
66
|
+
|
|
67
|
+
```tsx
|
|
68
|
+
import { setupConfig } from './config';
|
|
69
|
+
|
|
70
|
+
export function init() {
|
|
71
|
+
setupConfig({ mode: 'md' });
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## Differences from the source
|
|
76
|
+
|
|
77
|
+
- Every function is a boundary: the source treats arrow functions and function declarations as
|
|
78
|
+
boundaries but reports calls inside a function expression or an object method, which run only
|
|
79
|
+
when called.
|
|
80
|
+
- The option is named `allow`, not the source's unnamed list.
|
|
81
|
+
- A tagged template and a dynamic `import()` are not calls here, as in the source.
|
|
@@ -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,68 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: stencil/enforce-slot-jsdoc
|
|
3
|
+
title: "Every slot a component renders has a @slot tag, and every @slot tag a slot"
|
|
4
|
+
languages: [tsx]
|
|
5
|
+
fix: manual
|
|
6
|
+
fix_reason: "the slot's description, or whether it should exist, needs the author"
|
|
7
|
+
stability: preview
|
|
8
|
+
ported_from: [stencil/enforce-slot-jsdoc]
|
|
9
|
+
since: 0.2.0
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
A `@Component` class's JSDoc has a `@slot` tag for each `<slot>` it renders — `@slot name - what it
|
|
13
|
+
holds` for a named slot, `@slot - what it holds` for the default one — and no `@slot` tag for a slot
|
|
14
|
+
it doesn't render.
|
|
15
|
+
|
|
16
|
+
**Why:** Stencil builds the component's documentation and editor hints from these tags, so a missing
|
|
17
|
+
tag hides a slot from its users, and a stale one promises a slot that isn't there.
|
|
18
|
+
|
|
19
|
+
```codelaw
|
|
20
|
+
native: stencil/enforce-slot-jsdoc
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## How to fix
|
|
24
|
+
|
|
25
|
+
1. For a slot reported as rendered without a tag, add `@slot <name> - <what it holds>` (or
|
|
26
|
+
`@slot - <what it holds>` for the default slot) to the JSDoc above `@Component`.
|
|
27
|
+
2. For a tag reported as never rendered, remove the tag, or render the `<slot>` it describes.
|
|
28
|
+
|
|
29
|
+
## Examples
|
|
30
|
+
|
|
31
|
+
### TSX
|
|
32
|
+
|
|
33
|
+
#### Don't
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
/**
|
|
37
|
+
* A card.
|
|
38
|
+
*/
|
|
39
|
+
@Component({ tag: 'my-card' })
|
|
40
|
+
export class Card {
|
|
41
|
+
render() {
|
|
42
|
+
return <slot name="header" />;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
#### Do
|
|
48
|
+
|
|
49
|
+
```tsx
|
|
50
|
+
/**
|
|
51
|
+
* A card.
|
|
52
|
+
* @slot header - The card's title row.
|
|
53
|
+
*/
|
|
54
|
+
@Component({ tag: 'my-card' })
|
|
55
|
+
export class Card {
|
|
56
|
+
render() {
|
|
57
|
+
return <slot name="header" />;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## Differences from the source
|
|
63
|
+
|
|
64
|
+
- A `<slot>` whose `name` is an expression (`name={this.slot}`) is left out; the source records it as
|
|
65
|
+
a slot named `undefined`.
|
|
66
|
+
- A `@slot` tag's text stops at the end of its line; the source lets a bare `@slot` take its
|
|
67
|
+
description from the next line.
|
|
68
|
+
- TSX only: a `.ts` file has no `<slot>` elements to check.
|
|
@@ -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
|
+
```
|