@codelaw/rules-stencil 0.1.0 → 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/README.md CHANGED
@@ -12,11 +12,15 @@ preview = true # every rule is `preview` until a corpus run promotes it
12
12
 
13
13
  ## Presets
14
14
 
15
+ <!-- docs-sync:presets -->
16
+
15
17
  | preset | rules | ported from |
16
18
  |---|---|---|
17
- | `stencil/recommended` | 15 | @stencil/eslint-plugin 1.4.0 `recommended` — 15 of its 21 rules |
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`) |
18
20
  | `stencil/conventions` | 1 | codelaw's starter catalogue: `stencil/tag-prefix` — opt in |
19
21
 
22
+ <!-- /docs-sync:presets -->
23
+
20
24
  Every rule is **reimplemented**, not vendored: the matchers, messages and docs
21
25
  are written fresh, and each rule's `ported_from:` names the source rule.
22
26
 
package/codelaw-pack.toml CHANGED
@@ -1,5 +1,5 @@
1
1
  name = "@codelaw/rules-stencil"
2
- version = "0.1.0"
2
+ version = "0.2.0"
3
3
  min_codelaw = "0.1.0"
4
4
  languages = ["typescript", "tsx"]
5
5
  presets = ["stencil/recommended", "stencil/conventions"]
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,6 @@
1
1
  {
2
2
  "name": "@codelaw/rules-stencil",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "codelaw's Stencil rules, from @stencil/eslint-plugin; npm only (SR-RULE-PACKS)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -4,7 +4,9 @@ description = "@stencil/eslint-plugin 1.4.0 recommended without its type-checked
4
4
  "stencil/ban-default-true" = "error"
5
5
  "stencil/ban-exported-const-enums" = "error"
6
6
  "stencil/ban-prefix" = "error"
7
+ "stencil/ban-side-effects" = "error"
7
8
  "stencil/decorators-context" = "error"
9
+ "stencil/enforce-slot-jsdoc" = "error"
8
10
  "stencil/host-data-deprecated" = "error"
9
11
  "stencil/methods-must-be-public" = "error"
10
12
  "stencil/no-unused-watch" = "error"
@@ -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,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.