lint-suite 1.6.2 → 2.0.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 +262 -18
- package/eslint.cjs +4027 -467
- package/eslint.cjs.map +4 -4
- package/eslint.js +3972 -350
- package/eslint.js.map +4 -4
- package/lib/angular-template.d.ts.map +1 -1
- package/lib/angular.d.ts +0 -1
- package/lib/angular.d.ts.map +1 -1
- package/lib/base-limits.d.ts.map +1 -1
- package/lib/base-practices.d.ts.map +1 -1
- package/lib/line-length.const.d.ts +2 -0
- package/lib/line-length.const.d.ts.map +1 -0
- package/lib/rules/arrow-body-fits-line/arrow-body-fits-line.d.ts +6 -0
- package/lib/rules/arrow-body-fits-line/arrow-body-fits-line.d.ts.map +1 -0
- package/lib/rules/chain-fits-line/chain-fits-line.d.ts +6 -0
- package/lib/rules/chain-fits-line/chain-fits-line.d.ts.map +1 -0
- package/lib/rules/chain-receiver-is-name/chain-receiver-is-name.d.ts +7 -0
- package/lib/rules/chain-receiver-is-name/chain-receiver-is-name.d.ts.map +1 -0
- package/lib/rules/common/class-usage.type.d.ts +26 -0
- package/lib/rules/common/class-usage.type.d.ts.map +1 -0
- package/lib/rules/common/file-cache.type.d.ts +11 -0
- package/lib/rules/common/file-cache.type.d.ts.map +1 -0
- package/lib/rules/common/glob-matcher.type.d.ts +2 -0
- package/lib/rules/common/glob-matcher.type.d.ts.map +1 -0
- package/lib/rules/component-metadata.d.ts +3 -0
- package/lib/rules/component-metadata.d.ts.map +1 -0
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts +1 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.const.d.ts.map +1 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts +4 -1
- package/lib/rules/explicit-accessibility/common/explicit-accessibility.type.d.ts.map +1 -1
- package/lib/rules/file-cache.d.ts +14 -0
- package/lib/rules/file-cache.d.ts.map +1 -0
- package/lib/rules/max-condition-operands/max-condition-operands.d.ts +10 -0
- package/lib/rules/max-condition-operands/max-condition-operands.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.const.d.ts +6 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.const.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.type.d.ts +21 -0
- package/lib/rules/no-call-in-condition/common/no-call-in-condition.type.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/no-call-in-condition.d.ts +7 -0
- package/lib/rules/no-call-in-condition/no-call-in-condition.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/utils/call-exemptions.util.d.ts +4 -0
- package/lib/rules/no-call-in-condition/utils/call-exemptions.util.d.ts.map +1 -0
- package/lib/rules/no-call-in-condition/utils/condition-calls.util.d.ts +7 -0
- package/lib/rules/no-call-in-condition/utils/condition-calls.util.d.ts.map +1 -0
- package/lib/rules/no-grouped-condition/no-grouped-condition.d.ts +7 -0
- package/lib/rules/no-grouped-condition/no-grouped-condition.d.ts.map +1 -0
- package/lib/rules/no-inline-object-types/no-inline-object-types.d.ts.map +1 -1
- package/lib/rules/no-inline-return-object/no-inline-return-object.d.ts +6 -0
- package/lib/rules/no-inline-return-object/no-inline-return-object.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.const.d.ts +5 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.const.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.type.d.ts +7 -0
- package/lib/rules/no-nested-object-value/common/no-nested-object-value.type.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/no-nested-object-value.d.ts +7 -0
- package/lib/rules/no-nested-object-value/no-nested-object-value.d.ts.map +1 -0
- package/lib/rules/no-nested-object-value/utils/decorator-config.util.d.ts +3 -0
- package/lib/rules/no-nested-object-value/utils/decorator-config.util.d.ts.map +1 -0
- package/lib/rules/no-spread-expression/no-spread-expression.d.ts +6 -0
- package/lib/rules/no-spread-expression/no-spread-expression.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/common/no-unstyled-classes.type.d.ts +33 -0
- package/lib/rules/no-unstyled-classes/common/no-unstyled-classes.type.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/no-unstyled-classes.d.ts +8 -0
- package/lib/rules/no-unstyled-classes/no-unstyled-classes.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/component-stylesheets.d.ts +4 -0
- package/lib/rules/no-unstyled-classes/styles/component-stylesheets.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/linked-stylesheets.d.ts +3 -0
- package/lib/rules/no-unstyled-classes/styles/linked-stylesheets.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-classes.d.ts +3 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-classes.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-collection.d.ts +4 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-collection.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-imports.d.ts +2 -0
- package/lib/rules/no-unstyled-classes/styles/stylesheet-imports.d.ts.map +1 -0
- package/lib/rules/no-unstyled-classes/styles/template-stylesheets.d.ts +3 -0
- package/lib/rules/no-unstyled-classes/styles/template-stylesheets.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts +5 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-directive-index.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-resolved-path.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts +0 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-read-resolution.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/angular/angular-template-references.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts +6 -8
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-index.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts +3 -14
- package/lib/rules/no-unused-angular-instance-fields/project-usage/common/project-usage.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-file-entry.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts +3 -2
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-classes.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-reconciliation.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts +8 -4
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-index-staleness.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts +3 -2
- package/lib/rules/no-unused-angular-instance-fields/project-usage/project-usage.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-destructuring-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/typescript/typescript-reads.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/class-members.util.d.ts +10 -0
- package/lib/rules/no-unused-angular-instance-fields/project-usage/utils/class-members.util.d.ts.map +1 -0
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-class-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-imports.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-managed-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/angular/angular-metadata-literals.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts +2 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/common/no-unused-angular-instance-fields.type.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/no-unused-angular-instance-fields.d.ts.map +1 -1
- package/lib/rules/no-unused-angular-instance-fields/rule/typescript/typescript-class-read-visitor.d.ts.map +1 -1
- package/lib/rules/no-unused-classes/common/no-unused-classes.type.d.ts +24 -0
- package/lib/rules/no-unused-classes/common/no-unused-classes.type.d.ts.map +1 -0
- package/lib/rules/no-unused-classes/no-unused-classes.d.ts +8 -0
- package/lib/rules/no-unused-classes/no-unused-classes.d.ts.map +1 -0
- package/lib/rules/no-unused-classes/styles/linked-templates.d.ts +9 -0
- package/lib/rules/no-unused-classes/styles/linked-templates.d.ts.map +1 -0
- package/lib/rules/no-unused-classes/styles/stylesheet-components.d.ts +3 -0
- package/lib/rules/no-unused-classes/styles/stylesheet-components.d.ts.map +1 -0
- package/lib/rules/no-unused-classes/template/template-usage.d.ts +3 -0
- package/lib/rules/no-unused-classes/template/template-usage.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.const.d.ts +7 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.const.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts +70 -0
- package/lib/rules/no-unused-exports/common/no-unused-exports.type.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/export-index.d.ts +6 -0
- package/lib/rules/no-unused-exports/export-index.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/no-unused-exports.d.ts +7 -0
- package/lib/rules/no-unused-exports/no-unused-exports.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/report-unused-exports.d.ts +12 -0
- package/lib/rules/no-unused-exports/report-unused-exports.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/aggregate-update.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/aggregate-update.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-edges.util.d.ts +5 -0
- package/lib/rules/no-unused-exports/utils/export-edges.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-nodes.util.d.ts +5 -0
- package/lib/rules/no-unused-exports/utils/export-nodes.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/export-usage.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/export-usage.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/exported-names.util.d.ts +3 -0
- package/lib/rules/no-unused-exports/utils/exported-names.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/file-changes.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/file-changes.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/module-edges.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/module-target.util.d.ts +4 -0
- package/lib/rules/no-unused-exports/utils/module-target.util.d.ts.map +1 -0
- package/lib/rules/no-unused-exports/utils/public-exports.util.d.ts +3 -0
- package/lib/rules/no-unused-exports/utils/public-exports.util.d.ts.map +1 -0
- package/lib/rules/one-line-guard/one-line-guard.d.ts +10 -0
- package/lib/rules/one-line-guard/one-line-guard.d.ts.map +1 -0
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts +2 -1
- package/lib/rules/readonly-type-properties/readonly-type-properties.d.ts.map +1 -1
- package/lib/rules/selector-classes.d.ts +7 -0
- package/lib/rules/selector-classes.d.ts.map +1 -0
- package/lib/rules/ternary-branch-shape/ternary-branch-shape.d.ts +6 -0
- package/lib/rules/ternary-branch-shape/ternary-branch-shape.d.ts.map +1 -0
- package/lib/rules/test-file-shape/common/test-file-shape.const.d.ts +14 -0
- package/lib/rules/test-file-shape/common/test-file-shape.const.d.ts.map +1 -0
- package/lib/rules/test-file-shape/common/test-file-shape.type.d.ts +7 -0
- package/lib/rules/test-file-shape/common/test-file-shape.type.d.ts.map +1 -0
- package/lib/rules/test-file-shape/mock-exports.d.ts +7 -0
- package/lib/rules/test-file-shape/mock-exports.d.ts.map +1 -0
- package/lib/rules/test-file-shape/stub-exports.d.ts +7 -0
- package/lib/rules/test-file-shape/stub-exports.d.ts.map +1 -0
- package/lib/rules/test-file-shape/test-file-shape.d.ts +7 -0
- package/lib/rules/test-file-shape/test-file-shape.d.ts.map +1 -0
- package/lib/rules/type-placement/common/type-placement.const.d.ts +5 -0
- package/lib/rules/type-placement/common/type-placement.const.d.ts.map +1 -0
- package/lib/rules/type-placement/common/type-placement.type.d.ts +7 -0
- package/lib/rules/type-placement/common/type-placement.type.d.ts.map +1 -0
- package/lib/rules/type-placement/type-placement.d.ts +7 -0
- package/lib/rules/type-placement/type-placement.d.ts.map +1 -0
- package/lib/rules/util-purity/common/util-purity.const.d.ts +10 -0
- package/lib/rules/util-purity/common/util-purity.const.d.ts.map +1 -0
- package/lib/rules/util-purity/common/util-purity.type.d.ts +7 -0
- package/lib/rules/util-purity/common/util-purity.type.d.ts.map +1 -0
- package/lib/rules/util-purity/util-purity.d.ts +7 -0
- package/lib/rules/util-purity/util-purity.d.ts.map +1 -0
- package/lib/rules/utils/class-expression-literals.util.d.ts +4 -0
- package/lib/rules/utils/class-expression-literals.util.d.ts.map +1 -0
- package/lib/rules/utils/enclosing-statement.util.d.ts +3 -0
- package/lib/rules/utils/enclosing-statement.util.d.ts.map +1 -0
- package/lib/rules/utils/glob-matcher.util.d.ts +3 -0
- package/lib/rules/utils/glob-matcher.util.d.ts.map +1 -0
- package/lib/rules/utils/indent-of.util.d.ts +3 -0
- package/lib/rules/utils/indent-of.util.d.ts.map +1 -0
- package/lib/rules/utils/resolved-rules.util.d.ts +5 -0
- package/lib/rules/utils/resolved-rules.util.d.ts.map +1 -0
- package/lib/rules/utils/template-classes.util.d.ts +3 -0
- package/lib/rules/utils/template-classes.util.d.ts.map +1 -0
- package/lib/rules/utils/template-links.util.d.ts +2 -0
- package/lib/rules/utils/template-links.util.d.ts.map +1 -0
- package/lib/rules/utils/to-regexp.util.d.ts +2 -0
- package/lib/rules/utils/to-regexp.util.d.ts.map +1 -0
- package/lib/typescript-local-plugin.d.ts.map +1 -1
- package/lib/typescript-safety.d.ts.map +1 -1
- package/lib/typescript.d.ts +0 -1
- package/lib/typescript.d.ts.map +1 -1
- package/lib/vitest.d.ts.map +1 -1
- package/package.json +4 -1
- package/prettier.cjs +6 -1
- package/prettier.cjs.map +3 -3
- package/prettier.d.ts.map +1 -1
- package/prettier.js +4 -1
- package/prettier.js.map +3 -3
- package/stylelint.cjs +884 -4
- package/stylelint.cjs.map +4 -4
- package/stylelint.d.ts.map +1 -1
- package/stylelint.js +918 -4
- package/stylelint.js.map +4 -4
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ A comprehensive collection of ESLint Flat configurations for modern web applicat
|
|
|
12
12
|
- **Testing**: Vitest and Playwright configurations with best-practice rules
|
|
13
13
|
- **Prettier**: Automatic disabling of formatting rules that conflict with Prettier (`eslint-config-prettier`)
|
|
14
14
|
- **Prettier config**: Standalone formatting preset (subpath `lint-suite/prettier`) with the suite's house defaults and Angular/HTML overrides
|
|
15
|
-
- **Stylelint**: Standalone SCSS/CSS preset (subpath `lint-suite/stylelint`) with standard + recess-order + BEM selector enforcement
|
|
15
|
+
- **Stylelint**: Standalone SCSS/CSS preset (subpath `lint-suite/stylelint`) with standard + recess-order + BEM selector enforcement and `lint-suite/no-unused-classes`
|
|
16
16
|
- **Architecture**: Module boundary enforcement with `eslint-plugin-boundaries`
|
|
17
17
|
- **Additional Support**: JSON (with comment support for tsconfig), Storybook CSF enforcement
|
|
18
18
|
|
|
@@ -89,7 +89,7 @@ export default [
|
|
|
89
89
|
| `javascript` | JavaScript-specific rules via `@nx/eslint-plugin` |
|
|
90
90
|
| `typescript` | TypeScript strict typing, imports, and naming conventions |
|
|
91
91
|
| `angular` | Angular component best practices with Signal support |
|
|
92
|
-
| `angularTemplate` | HTML template rules with accessibility and
|
|
92
|
+
| `angularTemplate` | HTML template rules with accessibility, performance, and `lint-suite-angular-template/no-unstyled-classes` |
|
|
93
93
|
| `rxjs` | Observable patterns, operator safety, and subscriptions |
|
|
94
94
|
| `vitest` | Vitest testing rules and matcher improvements |
|
|
95
95
|
| `playwright` | Playwright e2e locator and matcher best practices |
|
|
@@ -106,6 +106,18 @@ export default [
|
|
|
106
106
|
| changes, do not use ESLint `--cache` for correctness gates; run a full non-cached lint (for example, |
|
|
107
107
|
| `eslint --no-cache`). |
|
|
108
108
|
|
|
109
|
+
## Disk cache
|
|
110
|
+
|
|
111
|
+
`no-unstyled-classes`, `no-unused-classes`, and `no-unused-instance-fields`
|
|
112
|
+
parse component metadata, stylesheets, and templates once per file and keep
|
|
113
|
+
the result in memory for the life of the process, keyed by the file's mtime
|
|
114
|
+
and size. The same entries are mirrored to
|
|
115
|
+
`node_modules/.cache/lint-suite/*.json` under the current working directory
|
|
116
|
+
at process exit, so the next ESLint or stylelint process (a CI run, or an
|
|
117
|
+
editor's first lint) skips every parse of a file that did not change. Set
|
|
118
|
+
`LINT_SUITE_CACHE_DIR` to move the directory, or `LINT_SUITE_CACHE=0` to
|
|
119
|
+
keep everything in memory only.
|
|
120
|
+
|
|
109
121
|
## Customization
|
|
110
122
|
|
|
111
123
|
You can override any rules by adding a `rules` section to your ESLint config:
|
|
@@ -152,6 +164,13 @@ templates can read a component or directive member:
|
|
|
152
164
|
}
|
|
153
165
|
```
|
|
154
166
|
|
|
167
|
+
- In an editor session the index is updated incrementally: a save re-indexes
|
|
168
|
+
only the saved file and the files whose resolutions depended on it. The
|
|
169
|
+
saved file's own templates, and the templates of every component in its
|
|
170
|
+
folder, are re-read on every lint; edits to templates in other folders are
|
|
171
|
+
picked up on a throttled schedule (at most every 100× the duration of the
|
|
172
|
+
last check), so a cross-folder template edit can take a moment to show up
|
|
173
|
+
in another file's diagnostics.
|
|
155
174
|
- `analysis` defaults to `'local'`. Project mode excludes spec-file reads. A
|
|
156
175
|
file it cannot index exactly (a template that does not parse, metadata it
|
|
157
176
|
cannot evaluate, a read it cannot type) falls back to name matching for
|
|
@@ -177,6 +196,128 @@ templates can read a component or directive member:
|
|
|
177
196
|
every matching component or directive in the Program is a candidate. Extra
|
|
178
197
|
candidates can only add reads. Metadata strings may be constants.
|
|
179
198
|
|
|
199
|
+
### No unstyled classes
|
|
200
|
+
|
|
201
|
+
The `angularTemplate` config enables
|
|
202
|
+
`lint-suite-angular-template/no-unstyled-classes`, which reports a class name
|
|
203
|
+
used in an Angular HTML template that no stylesheet of that component selects.
|
|
204
|
+
It reads three sources in the template: the static `class="a b"` attribute
|
|
205
|
+
(each token reported at its own column), `[class.name]` bindings, and the
|
|
206
|
+
literal class names inside `[class]="..."` expressions and `class="a {{ b }}"`
|
|
207
|
+
interpolations. String literals, object-literal keys, array elements, and both
|
|
208
|
+
branches of a ternary contribute names; identifiers, calls, pipes, and `+`
|
|
209
|
+
concatenations contribute nothing, so a class the rule cannot see is never
|
|
210
|
+
reported. `[ngClass]` is deliberately not analysed.
|
|
211
|
+
|
|
212
|
+
Stylesheets come from the component beside the template: `styleUrl`,
|
|
213
|
+
`styleUrls`, and inline `styles` read as string or template literals from the
|
|
214
|
+
`@Component` metadata, falling back to a sibling `.scss` or `.css` file when
|
|
215
|
+
the metadata declares none. A `<link rel="stylesheet" href="...">` in the
|
|
216
|
+
template itself is read too, resolved against the template's directory, so a
|
|
217
|
+
plain HTML page without a component is judged against the stylesheets it
|
|
218
|
+
links; root-relative (`/x.css`) and absolute (`https://...`) links are
|
|
219
|
+
skipped. Each stylesheet is parsed with `postcss-scss`, so
|
|
220
|
+
`&__element`, `&--modifier`, `&.other`, `& > .child`, `.wrapper &`, and rules
|
|
221
|
+
nested inside `@media` all resolve against their parent selector, and a
|
|
222
|
+
selector list such as `.a, .b { &__x {} }` yields both `.a__x` and `.b__x`.
|
|
223
|
+
`@use`, `@import`, and `@forward` are followed to their partials
|
|
224
|
+
(`_name.scss`, `name/index.scss`, `name/_index.scss`). A selector built with
|
|
225
|
+
interpolation (`.icon-#{$size}`) becomes a pattern, so `icon-lg` counts as
|
|
226
|
+
styled and bare `icon` does not.
|
|
227
|
+
|
|
228
|
+
```js
|
|
229
|
+
{
|
|
230
|
+
files: ['**/*.html'],
|
|
231
|
+
rules: {
|
|
232
|
+
'lint-suite-angular-template/no-unstyled-classes': [
|
|
233
|
+
'error',
|
|
234
|
+
{
|
|
235
|
+
ignoreClassPatterns: ['^(js|qa|mat|cdk|mdc)-', '^u-'],
|
|
236
|
+
globalStyles: ['src/styles.scss']
|
|
237
|
+
}
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
- `ignoreClassPatterns` defaults to `['^(js|qa|mat|cdk|mdc)-']`. Each entry is
|
|
244
|
+
compiled with `new RegExp(pattern, 'u')`, and a class matching any of them is
|
|
245
|
+
never reported. A configured list replaces the default one instead of
|
|
246
|
+
extending it.
|
|
247
|
+
- `globalStyles` defaults to `[]`. Paths are resolved against the ESLint
|
|
248
|
+
working directory and merged into the known classes of every template. A path
|
|
249
|
+
that does not exist is ignored.
|
|
250
|
+
- Elements whose tag name contains a dash are skipped: the classes on a child
|
|
251
|
+
component, `ng-container`, or `ng-template` may be styled by that component's
|
|
252
|
+
own `:host(.x)`, which this rule cannot see.
|
|
253
|
+
- A template with no stylesheet reports nothing. The same holds when the only
|
|
254
|
+
stylesheet found fails to parse: with nothing to compare against, the rule has
|
|
255
|
+
no opinion.
|
|
256
|
+
|
|
257
|
+
### No unused classes
|
|
258
|
+
|
|
259
|
+
The `stylelint` preset enables `lint-suite/no-unused-classes`, the dual of the
|
|
260
|
+
rule above: it reports a class selector in a component stylesheet that no
|
|
261
|
+
template of that component uses.
|
|
262
|
+
|
|
263
|
+
Templates are found from the stylesheet. Every `.ts` file beside it is read for
|
|
264
|
+
`@Component` metadata whose `styleUrl` or `styleUrls` resolves to the linted
|
|
265
|
+
file; each matching component contributes its `templateUrl` file or its inline
|
|
266
|
+
`template` literal, and their classes are merged, so a stylesheet shared by two
|
|
267
|
+
components is judged against both templates. When no component declares the
|
|
268
|
+
stylesheet, a sibling template of the same name (`card.component.scss` →
|
|
269
|
+
`card.component.html`) and every `.html` file in the same directory whose
|
|
270
|
+
`<link rel="stylesheet" href="...">` resolves to it are used instead, plus
|
|
271
|
+
every template anywhere under the working directory whose link resolves to
|
|
272
|
+
it (`node_modules`, `dist`, `coverage`, and dot-folders are skipped), so a
|
|
273
|
+
plain `styles.css` beside an `index.html` and a shared stylesheet linked from
|
|
274
|
+
other folders are both checked. A partial (`_tokens.scss`) or a global
|
|
275
|
+
`styles.scss` that nothing links has no template, and the rule stays silent.
|
|
276
|
+
|
|
277
|
+
Selectors resolve through the same parser as the ESLint rule, so `&__element`,
|
|
278
|
+
`&--modifier`, `&.other`, `& > .child`, `.wrapper &`, `@media` blocks, and
|
|
279
|
+
selector lists all report the resolved name on the rule that declares it: in
|
|
280
|
+
`.panel { .inner {} }` only `inner` is checked on the inner rule, never `panel`
|
|
281
|
+
twice. Arguments of `:host(.dark)` and `:host-context(.rtl)` are skipped, and
|
|
282
|
+
everything after `::ng-deep`, `/deep/`, or `>>>` is skipped too, because those
|
|
283
|
+
classes live in other templates. A selector built with interpolation
|
|
284
|
+
(`.icon-#{$size}`) is never reported, and `@extend .base` counts `base` as
|
|
285
|
+
used.
|
|
286
|
+
|
|
287
|
+
The template side reads the same sources as `no-unstyled-classes` plus
|
|
288
|
+
`[ngClass]`, and it does not skip custom elements: a class on
|
|
289
|
+
`<app-child class="foo">` is written by this template, so `.foo` counts as
|
|
290
|
+
used. When any template of the stylesheet holds a class source the rule cannot
|
|
291
|
+
read — `[class]="classes()"`, `[ngClass]="map"`, a whole token that is
|
|
292
|
+
`{{ expr }}`, an unparseable template — the rule reports nothing for that
|
|
293
|
+
stylesheet rather than guessing.
|
|
294
|
+
|
|
295
|
+
```js
|
|
296
|
+
// stylelint.config.mjs
|
|
297
|
+
import { stylelint } from 'lint-suite/stylelint';
|
|
298
|
+
|
|
299
|
+
export default {
|
|
300
|
+
...stylelint,
|
|
301
|
+
overrides: [
|
|
302
|
+
...stylelint.overrides,
|
|
303
|
+
{
|
|
304
|
+
files: ['**/*.scss', '**/*.css'],
|
|
305
|
+
rules: {
|
|
306
|
+
'lint-suite/no-unused-classes': [
|
|
307
|
+
true,
|
|
308
|
+
{ ignoreClassPatterns: ['^(js|qa|mat|cdk|mdc)-', '^u-'] }
|
|
309
|
+
]
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
]
|
|
313
|
+
};
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
- `ignoreClassPatterns` defaults to `['^(js|qa|mat|cdk|mdc)-']`. Each entry is
|
|
317
|
+
compiled with `new RegExp(pattern, 'u')`, and a class matching any of them is
|
|
318
|
+
never reported. A configured list replaces the default one instead of
|
|
319
|
+
extending it.
|
|
320
|
+
|
|
180
321
|
### Explicit accessibility
|
|
181
322
|
|
|
182
323
|
The `typescript` preset enables `local/explicit-accessibility`, which reports
|
|
@@ -225,6 +366,9 @@ type User = { readonly name: string; roles: string[]; profile: Profile };
|
|
|
225
366
|
- Arrays, object types, type references (including string-union aliases
|
|
226
367
|
like `Status`), functions, and tuples are left untouched because the
|
|
227
368
|
rule is syntactic and does not resolve types.
|
|
369
|
+
- The same rule reports and fixes `readonly T[]` and `ReadonlyArray<T>` to
|
|
370
|
+
`T[]`: the property reference is readonly, the array contents stay
|
|
371
|
+
mutable.
|
|
228
372
|
- Index signatures, mapped types, and method signatures are out of scope.
|
|
229
373
|
- Use `// eslint-disable-next-line local/readonly-type-properties` when a
|
|
230
374
|
property genuinely needs to stay mutable.
|
|
@@ -232,29 +376,128 @@ type User = { readonly name: string; roles: string[]; profile: Profile };
|
|
|
232
376
|
### No inline object types
|
|
233
377
|
|
|
234
378
|
The `typescript` preset enables `local/no-inline-object-types`, which
|
|
235
|
-
reports object type
|
|
236
|
-
|
|
237
|
-
intersection members,
|
|
238
|
-
|
|
239
|
-
|
|
379
|
+
reports every object type literal that is not the direct body of a
|
|
380
|
+
`type NAME = ...` alias: nested properties, array element types, union and
|
|
381
|
+
intersection members, generic arguments such as `Readonly<{...}>`, function
|
|
382
|
+
parameter and return types, `satisfies` targets, interface and class
|
|
383
|
+
members, and members of a `declare module` block. It is not auto-fixable:
|
|
384
|
+
extracting an inline object type requires choosing a name.
|
|
240
385
|
|
|
241
386
|
```ts
|
|
242
387
|
// Before
|
|
243
|
-
|
|
388
|
+
const describe = (field: { readonly name: string }): { readonly label: string } => ...
|
|
389
|
+
|
|
390
|
+
// After
|
|
391
|
+
type Field = { readonly name: string };
|
|
392
|
+
type FieldSummary = { readonly label: string };
|
|
393
|
+
const describe = (field: Field): FieldSummary => ...
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
- The direct body of a `type X = {...}` alias is the only allowed position.
|
|
397
|
+
- Mapped types (`{ [K in Keys]: T }`) are a different node and stay valid.
|
|
398
|
+
|
|
399
|
+
### One-line guard
|
|
400
|
+
|
|
401
|
+
The `typescript` preset enables `local/one-line-guard` (with
|
|
402
|
+
`maxLineLength` set to the preset print width, 135), which reports an
|
|
403
|
+
`if` statement whose braced body is a lone `return`, `throw`, `continue`,
|
|
404
|
+
or `break` when the whole statement would fit on one line. It is
|
|
405
|
+
auto-fixable: the fix drops the braces and joins the guard onto the `if`
|
|
406
|
+
line.
|
|
407
|
+
|
|
408
|
+
```ts
|
|
409
|
+
// Before
|
|
410
|
+
if (!user) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
244
413
|
|
|
245
414
|
// After
|
|
246
|
-
|
|
247
|
-
type LineItem = { readonly name: string; readonly item: Item };
|
|
415
|
+
if (!user) return null;
|
|
248
416
|
```
|
|
249
417
|
|
|
250
|
-
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
418
|
+
- Only a block body containing exactly one `return`, `throw`, `continue`,
|
|
419
|
+
or `break` statement is considered a guard; any other body is left
|
|
420
|
+
alone.
|
|
421
|
+
- The rule bails out (no report, no fix) when the `if` has an `else`,
|
|
422
|
+
the block holds a comment, the condition spans multiple lines, the
|
|
423
|
+
guard statement spans multiple lines, or the collapsed line would
|
|
424
|
+
exceed `maxLineLength`.
|
|
425
|
+
- Pass a different width with the rule's options:
|
|
426
|
+
`'local/one-line-guard': ['error', { maxLineLength: 80 }]`.
|
|
427
|
+
- Complements `curly: multi-line`: that rule tolerates a brace-less
|
|
428
|
+
single-line guard once it exists, while `local/one-line-guard` is what
|
|
429
|
+
collapses a braced guard down to one line in the first place.
|
|
430
|
+
|
|
431
|
+
### Statement shape rules
|
|
432
|
+
|
|
433
|
+
The `typescript` preset enables a family of small syntactic rules that make
|
|
434
|
+
control flow and data shape visible by reading the code's outline. None of
|
|
435
|
+
them reads type information or the filesystem; each listens to one node
|
|
436
|
+
type and reports in microseconds per file. Where a fix needs a name the rule
|
|
437
|
+
offers an IDE suggestion with a placeholder name instead of an auto-fix.
|
|
438
|
+
|
|
439
|
+
| Rule | Reports | Fix |
|
|
440
|
+
|---|---|---|
|
|
441
|
+
| `local/no-call-in-condition` | A function call inside an `if` condition, or inside a boolean `const` that an `if` tests. Zero-argument `this.x()` calls (Angular signal reads) and type-predicate calls are exempt; predicates are found through scope in the same file, or through the type checker when a program is available. Option `allowPredicates` (regex sources, default `['^(is\|has)[A-Z]']`) applies when there is no program. | Suggestion: hoist to a `const` |
|
|
442
|
+
| `local/max-condition-operands` | An `if` condition with more than `max` (default 3) operands joined by `&&` / `\|\|`. | none |
|
|
443
|
+
| `local/no-grouped-condition` | A parenthesised group with a different operator inside an `if` condition or a boolean `const` (`a && (b \|\| c)`). | Suggestion: hoist the group |
|
|
444
|
+
| `local/ternary-branch-shape` | A ternary branch that is not a name, literal, template literal, or plain member access. | none |
|
|
445
|
+
| `local/chain-receiver-is-name` | A member chain starting on an inline expression: `(a ?? b).x`, `{...}.x`, `[...].x`, `(await p).x`. | Suggestion: name the receiver |
|
|
446
|
+
| `local/chain-fits-line` | A chain of two or more calls whose `.method(` parts sit on different lines. A multi-line callback argument does not count. | none |
|
|
447
|
+
| `local/arrow-body-fits-line` | An expression-bodied arrow whose body wraps onto more lines. | Fix: block body with `return` |
|
|
448
|
+
| `local/no-nested-object-value` | A property value that is a non-empty object literal, an array holding object literals, a ternary, or a call chain. Decorator arguments (`@Component({...})`) and files matching `configFiles` (default `**/*.config.*`, `**/eslint.config.*`, `**/*.schema.ts`) are exempt. | Suggestion: hoist to a `const` |
|
|
449
|
+
| `local/no-spread-expression` | `...(expr)` where the argument is not a name or member access. | Suggestion: hoist to a `const` |
|
|
450
|
+
| `local/no-inline-return-object` | `return {...}` and `=> ({...})`. | Suggestion: `const result = {...}; return result;` |
|
|
451
|
+
|
|
452
|
+
### Project layout rules
|
|
453
|
+
|
|
454
|
+
Also in the `typescript` preset. These read only the file's own path and
|
|
455
|
+
return no listeners for files they do not cover, so they cost one regex
|
|
456
|
+
per file.
|
|
457
|
+
|
|
458
|
+
| Rule | Reports | Options |
|
|
459
|
+
|---|---|---|
|
|
460
|
+
| `local/type-placement` | An exported `type` outside a `common/*.type.ts` or `test/common/*.type.ts` file; a value exported from a `*.type.ts` file; a non-`const` export from a `*.const.ts` file; an `import type` from a relative or internal path that is neither a `*.type.ts` file nor a `common` barrel (`../common`, `./common/index.ts`, `@shared/common`). `.spec.ts`, `.stub.ts`, `.d.ts`, `state.type.ts` (any prefix), and fixtures are exempt; a `.spec.util.ts` file is not, so an exported type in one is reported. Never resolves imports. | `internalPatterns`: regex sources for alias prefixes that must resolve to a `*.type.ts` file. Default empty: a workspace alias (`@shared/common`) resolves to a library entry point, and module boundaries forbid deep imports, so alias type imports pass. |
|
|
461
|
+
| `local/util-purity` | Inside `utils/*.util.ts` (excluding paths under `test/` or `testing/`): imports of `node:fs`, `child_process`, `os`, `process`, `http`, `net`, `worker_threads`; a module-level `let`; a module-level `new Map/Set/WeakMap/WeakSet`; `process.*`, `globalThis`, `window`, `document`, `localStorage`, `console`; `Date.now`, `Math.random`, `performance.now`, `crypto.randomUUID`; `setTimeout`, `setInterval`, `fetch`, `inject`, `require`. | `bannedModules` |
|
|
462
|
+
| `local/test-file-shape` | A file named `*.spec-support.ts`, `*.spec-helper.ts`, `*.test-utils.ts`, `*-fixture.ts`, or under `__mocks__/` / `helpers/` / `common/stubs/`; a `.stub.ts` outside `test/stubs/`, a `.mock.ts` outside `test/mocks/`, a `.spec.util.ts` outside `test/utils/`, or any `fixtures/` directory outside `test/fixtures/` (a dedicated `testing/` library is exempt from all of these); a `test/stubs/*.stub.ts` export not named `UPPER_SNAKE_STUB` or without a type annotation; a `test/mocks/*.mock.ts` export that is not a camelCase `...Mock` function with an explicit return type. | none |
|
|
463
|
+
|
|
464
|
+
### No unused exports
|
|
465
|
+
|
|
466
|
+
The `typescript` preset enables `local/no-unused-exports`, which reports an
|
|
467
|
+
export (values and types) that no other file in the TypeScript program
|
|
468
|
+
imports, and a module that exports names but is never imported at all.
|
|
469
|
+
|
|
470
|
+
- Source of truth is the program typescript-eslint already built for the
|
|
471
|
+
type-aware rules: no extra parse, no file enumeration, no filesystem.
|
|
472
|
+
- Per file the rule walks top-level statements, plus every node of a file
|
|
473
|
+
whose text contains `import(`, and caches the result
|
|
474
|
+
on the `ts.SourceFile` object; the project-wide usage map is cached per
|
|
475
|
+
`ts.Program`, and an edit that only touches a few files patches that map
|
|
476
|
+
in place instead of rebuilding it. The patch is scoped per project
|
|
477
|
+
(`tsconfig`): programs from different projects never share an aggregate,
|
|
478
|
+
even when ESLint alternates between them in the same process. Editing one
|
|
479
|
+
file re-walks that file and rebuilds the map once. At 10k files the warm
|
|
480
|
+
cost is map lookups.
|
|
481
|
+
- Re-exports are followed: `export { x } from`, `export * from`, and
|
|
482
|
+
`export * as ns from` count usage at the file that declares `x`, so a
|
|
483
|
+
barrel does not hide a dead export. `import * as ns`, default imports,
|
|
484
|
+
and dynamic `import('./x')` anywhere in the file (a lazy route's
|
|
485
|
+
`loadComponent: () => import('./x')` included) count every export of the
|
|
486
|
+
target as used.
|
|
487
|
+
- Files matching `entryPoints` are never reported (default `**/main.ts`,
|
|
488
|
+
`**/main.*.ts`, `**/public-api.ts`, `**/index.ts`, `**/*.config.ts`,
|
|
489
|
+
`**/*.config.mts`, `**/*.config.cts`, `**/*.spec.ts`, `**/*.spec.util.ts`,
|
|
490
|
+
`**/*.stub.ts`, `**/*.mock.ts`, `**/*.d.ts`, `**/*.stories.ts`,
|
|
491
|
+
`**/environment*.ts`).
|
|
492
|
+
Files with `export =` or a `declare module` block are skipped.
|
|
493
|
+
- Names an entry point re-exports (`export { x } from`, `export * from`)
|
|
494
|
+
are public API and never reported: an Nx library's `index.ts` protects
|
|
495
|
+
the exports other projects consume, even though those projects sit
|
|
496
|
+
outside the library's own TypeScript program.
|
|
497
|
+
- The project is the linted file's tsconfig program. An export used only
|
|
498
|
+
from a file outside that program (for example a spec excluded by
|
|
499
|
+
`tsconfig.lib.json`) reports as unused; that is the same boundary `tsc`
|
|
500
|
+
draws.
|
|
258
501
|
|
|
259
502
|
## Stylelint and Prettier presets
|
|
260
503
|
|
|
@@ -344,6 +587,7 @@ The Prettier preset is published with `prettier` as a peer dependency. The Style
|
|
|
344
587
|
- Extends `stylelint-config-standard`, `stylelint-config-standard-scss`, and `stylelint-config-recess-order`
|
|
345
588
|
- `selector-class-pattern`: BEM-aware class names with ITCSS-style namespace prefixes (`o-`, `c-`, `u-`, `is-`, `has-`, `js-`, `qa-`, etc.)
|
|
346
589
|
- `plugin/selector-bem-pattern`: enforces BEM selectors, treats `*.component.scss`/`*.component.css` as implicit components, ignores `--mdc`/`--sys` custom properties
|
|
590
|
+
- `lint-suite/no-unused-classes`: reports a class selector no template of the component uses (see [No unused classes](#no-unused-classes))
|
|
347
591
|
- `no-descending-specificity`: disabled
|
|
348
592
|
|
|
349
593
|
### prettier (format config)
|