@konvert7/klint 1.3.1 → 1.4.1
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 +74 -55
- package/klint.schema.json +1434 -607
- package/klint.schema.yaml +1100 -505
- package/package.json +10 -7
package/README.md
CHANGED
|
@@ -53,11 +53,12 @@ Then create `klint.yaml` in your project root.
|
|
|
53
53
|
include: ["src", "!**/node_modules/**"]
|
|
54
54
|
|
|
55
55
|
rules:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
56
|
+
core:
|
|
57
|
+
no-async-predicate: error
|
|
58
|
+
no-unguarded-json-parse: error
|
|
59
|
+
no-sync-in-async:
|
|
60
|
+
severity: error
|
|
61
|
+
include: ["src/hooks/**"]
|
|
61
62
|
|
|
62
63
|
arch:
|
|
63
64
|
layers:
|
|
@@ -121,6 +122,7 @@ Rules give agents room to move quickly because the unsafe moves are blocked stru
|
|
|
121
122
|
```sh
|
|
122
123
|
klint [--config <dir>] [--fix] [--json] [--hook]
|
|
123
124
|
klint stats [--config <dir>]
|
|
125
|
+
klint migrate [--config <dir>] [--check]
|
|
124
126
|
klint install-skill [--agents <list>] [--symlink | --copy] [--force]
|
|
125
127
|
```
|
|
126
128
|
|
|
@@ -130,6 +132,8 @@ klint install-skill [--agents <list>] [--symlink | --copy] [--force]
|
|
|
130
132
|
| `--fix` | Apply auto-fixes for fixable violations in-place |
|
|
131
133
|
| `--json` | Emit structured JSON to stdout for agents and CI |
|
|
132
134
|
| `--hook` | Count this run as an agent hook run in `klint stats` |
|
|
135
|
+
| `migrate` | Rewrite a v1 config to the v2 rule groups in place, keeping comments and blank lines |
|
|
136
|
+
| `migrate --check` | Exit 1 when the config is v1 and 0 when it is v2; never writes |
|
|
133
137
|
|
|
134
138
|
`klint install-skill` installs the bundled rule-authoring skill for agent environments:
|
|
135
139
|
|
|
@@ -224,15 +228,17 @@ The npm package needs Node.js 18+ and no longer installs `typescript`, `zod`, `y
|
|
|
224
228
|
# yaml-language-server: $schema=./klint.schema.yaml
|
|
225
229
|
|
|
226
230
|
include: ["src", "!**/node_modules/**"]
|
|
227
|
-
plugins: [sonar]
|
|
228
231
|
|
|
229
232
|
rules:
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
233
|
+
recommended: true
|
|
234
|
+
core:
|
|
235
|
+
no-unguarded-json-parse: error
|
|
236
|
+
no-async-predicate: error
|
|
237
|
+
no-sync-in-async:
|
|
238
|
+
severity: error
|
|
239
|
+
include: ["src/server/**"]
|
|
240
|
+
sonar:
|
|
241
|
+
prefer-string-replaceall: warn
|
|
236
242
|
|
|
237
243
|
arch:
|
|
238
244
|
layers:
|
|
@@ -247,9 +253,15 @@ arch:
|
|
|
247
253
|
|
|
248
254
|
`include` selects source files to lint. Patterns support `**` globs and `!` negation.
|
|
249
255
|
|
|
250
|
-
`
|
|
256
|
+
`rules` has three parts. Each rule is `"error"`, `"warn"`, `"off"`, or an options object with `severity` and/or `include`.
|
|
257
|
+
|
|
258
|
+
- `recommended: true` enables the six sonar rules at `error`.
|
|
259
|
+
- `core` holds the built-in rules, by name.
|
|
260
|
+
- `sonar` holds the sonar rules, by name without the `sonar/` prefix. An entry here overrides `recommended`.
|
|
261
|
+
|
|
262
|
+
The rule ids in the output stay `sonar/…`, for example `sonar/prefer-at`.
|
|
251
263
|
|
|
252
|
-
`rules`
|
|
264
|
+
**v1 still works.** The flat map under `rules` (with `sonar/` prefixes) and `plugins: [sonar]` are still read. A v1 config gets one `klint/config` warning. `klint migrate` or `klint --fix` upgrades it in place and keeps comments, blank lines and key order. It refuses, naming the line, when it cannot do that safely: YAML anchors, aliases, tags, a flow-map `rules`, duplicate keys, or a config that mixes v1 and v2 keys. A mixed config is read as v2 and the v1 entries are ignored, with one warning.
|
|
253
265
|
|
|
254
266
|
`arch` declares architecture constraints without writing a custom rule.
|
|
255
267
|
|
|
@@ -733,7 +745,7 @@ doc-comments alongside `/** */`.
|
|
|
733
745
|
| `no-string-match` | `String#match()` usage better expressed with clearer APIs |
|
|
734
746
|
| `blank-line-before-control-flow` | Blank line above a control-flow statement that follows another statement; autofix |
|
|
735
747
|
| `blank-line-after-block` | Blank line below a block statement when another statement follows; autofix |
|
|
736
|
-
| `cognitive-complexity` | Function whose cognitive complexity (
|
|
748
|
+
| `cognitive-complexity` | Function whose cognitive complexity (SonarJS / SonarSource model) is above `max`, in all five languages; opt-in, no autofix |
|
|
737
749
|
| `function-length` | Function whose body has more lines than `max` (counted like Biome's `noExcessiveLinesPerFunction`), in all five languages; opt-in, no autofix |
|
|
738
750
|
|
|
739
751
|
Rules that needed TypeScript's type checker were removed in 1.0; see [Upgrading from klint 0.x](#upgrading-from-klint-0x).
|
|
@@ -744,21 +756,23 @@ Rules that needed TypeScript's type checker were removed in 1.0; see [Upgrading
|
|
|
744
756
|
|
|
745
757
|
```yaml
|
|
746
758
|
rules:
|
|
747
|
-
|
|
748
|
-
|
|
759
|
+
core:
|
|
760
|
+
blank-line-before-control-flow: error
|
|
761
|
+
blank-line-after-block: warn
|
|
749
762
|
```
|
|
750
763
|
|
|
751
764
|
```yaml
|
|
752
765
|
rules:
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
766
|
+
core:
|
|
767
|
+
blank-line-before-control-flow:
|
|
768
|
+
severity: error
|
|
769
|
+
include: ["src/**", "!src/generated/**"]
|
|
770
|
+
statements: [if, for, while, switch, try, return, guard, loop, with]
|
|
771
|
+
allowSetup: true
|
|
772
|
+
blank-line-after-block:
|
|
773
|
+
severity: warn
|
|
774
|
+
include: ["src/**"]
|
|
775
|
+
statements: [if, for, while, switch, try, guard, loop, with]
|
|
762
776
|
```
|
|
763
777
|
|
|
764
778
|
- `statements` lists the statement kinds a rule targets. The default is every kind the rule supports. `statements: []` turns the rule off. `match` is an alias of `switch`. `return` is valid only for `blank-line-before-control-flow`. An unknown keyword, or `return` on the after rule, produces one `klint/config` warning, and the remaining keywords still apply.
|
|
@@ -786,56 +800,59 @@ rules:
|
|
|
786
800
|
|
|
787
801
|
### Cognitive complexity
|
|
788
802
|
|
|
789
|
-
`cognitive-complexity` reports every function whose cognitive complexity is above `max`, in TypeScript/JavaScript, Python, Swift, Rust and C#. It is opt-in and has no fix. It
|
|
803
|
+
`cognitive-complexity` reports every function whose cognitive complexity is above `max`, in TypeScript/JavaScript, Python, Swift, Rust and C#. It is opt-in and has no fix. It scores like SonarSource's own implementation, `eslint-plugin-sonarjs` 3.0.5 rule S3776 (the SonarSource Cognitive Complexity model, G. Ann Campbell 2017), for every language, so a TypeScript function gets the same score as in SonarJS.
|
|
790
804
|
|
|
791
805
|
```yaml
|
|
792
806
|
rules:
|
|
793
|
-
|
|
807
|
+
core:
|
|
808
|
+
cognitive-complexity: error
|
|
794
809
|
```
|
|
795
810
|
|
|
796
811
|
```yaml
|
|
797
812
|
rules:
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
813
|
+
core:
|
|
814
|
+
cognitive-complexity:
|
|
815
|
+
severity: warn
|
|
816
|
+
include: ["src/**", "!src/generated/**"]
|
|
817
|
+
max: 14
|
|
802
818
|
```
|
|
803
819
|
|
|
804
820
|
- `max` is an integer of at least 1, default 15. A function is reported when its score is **greater than** `max`. Any other value (0, a negative number, a fraction, a string) gives one `klint/config` warning naming the rule and the value, and the rule uses 15.
|
|
805
821
|
- The message has the form ``Function `big` has cognitive complexity 16 (max 15) — split it into smaller functions.``. The name is the declared name. For an anonymous function assigned to a variable or property it is that name. Otherwise it is `<anonymous>`. The line is the function's first line.
|
|
806
822
|
- Each function starts at 0. Top-level code is not scored.
|
|
807
823
|
|
|
808
|
-
**Scoring.** "Nesting" is how deep a construct sits: each enclosing `if`, loop, `switch`, `catch`, `guard
|
|
824
|
+
**Scoring.** "Nesting" is how deep a construct sits: nesting is added by each enclosing `if`, loop, `switch`, `catch`, `guard` and `let … else` body; a nested function starts again at 0. Only a construct's body is nested: its condition, loop head, `switch` value or ternary test sits at the construct's own nesting. For example, in `if (a ? b : c) {}` the ternary adds 1, not 2.
|
|
809
825
|
|
|
810
826
|
| Increment | TypeScript / JavaScript | Python | Swift | Rust | C# |
|
|
811
827
|
|---|---|---|---|---|---|
|
|
812
|
-
| +1 plus nesting: `if
|
|
828
|
+
| +1 plus nesting: `if` | `if` | `if` | `if`, `if let` | `if` |
|
|
829
|
+
| +1, no nesting: `else if` (its body is nested like the `if` body) | `else if` | `elif` | `else if` | `else if` | `else if` |
|
|
813
830
|
| +1 plus nesting: ternary | `?:` | `x if c else y` | `?:` | — | `?:` |
|
|
814
831
|
| +1 plus nesting: switch / match | `switch` | `match` | `switch` | `match` | `switch` statement, `switch` expression |
|
|
815
832
|
| +1 plus nesting: loops | `for`, `for…in`, `for…of`, `while`, `do…while` | `for`, `while` | `for`, `while`, `repeat…while` | `for`, `while`, `while let`, `loop` | `for`, `foreach`, `while`, `do` |
|
|
816
833
|
| +1 plus nesting: `catch` | `catch` | `except` | `catch` | — | `catch` |
|
|
817
834
|
| +1 plus nesting: `guard`, `let … else` (its `else` body is nested) | — | — | `guard` | `let … else` | — |
|
|
818
|
-
|
|
|
819
|
-
| nesting only: nested function (scored on its own, see below) | arrow, function expression, function declaration, method | `lambda`, `def` | closure | closure | lambda, local function, anonymous method |
|
|
835
|
+
| no increment: nested function (scored on its own, starting at nesting 0) | arrow, function expression, function declaration, method | `lambda`, `def` | closure | closure | lambda, local function, anonymous method |
|
|
820
836
|
| +1, no nesting: plain `else` (not `else if`/`elif`) | `else` | `else` of `if`, `try`, `for`, `while` | `else` | `else` | `else` |
|
|
821
837
|
| +1: labeled `break` / `continue`, `goto` | `break label`, `continue label` | — | `break label`, `continue label` | `break 'label`, `continue 'label` | `goto` |
|
|
822
|
-
| +1 per
|
|
838
|
+
| +1 per run of `&&` (see below); `\|\|`, `or`, `??` add nothing | `&&` | `and` | `&&` | `&&` | `&&`, pattern `and` |
|
|
823
839
|
| +1: comprehension `if` | — | comprehension `if` | — | — | — |
|
|
824
840
|
| +1: guard on a case or arm | — | — | `case … where` | match-arm guard | `when` clause |
|
|
825
841
|
|
|
826
|
-
Each
|
|
842
|
+
Logical operators form one sequence per expression, read in source order through parentheses; negation, calls and other expressions start a new sequence. Each `&&` (`and`) scores +1 unless the operator before it in the sequence is also `&&`. `||`, `or`, `??` and pattern `or` add nothing but end a run: `a && b || c` is 1, `a && (b || c) && a` is 2, `a && (b && c)` is 1, and `a ?? b ?? c` is 0. Negation (`!`, `not`) adds nothing. In TypeScript/JavaScript, a short-circuit directly inside a JSX expression that uses one operator and has no ternary operand (`{a && <X/>}`, `{a && b && <X/>}`) adds nothing; a mixed one (`{a && b || <X/>}`) is counted as usual. A function used as a branch of a conditional expression (`a ? () => {…} : b` in TypeScript/JavaScript and C#, a Swift closure in a ternary, `(lambda: …) if a else b` in Python) is scored on its own from nesting 0 like any nested function, and every later construct in the enclosing function that adds "plus nesting" in the table above scores one more.
|
|
843
|
+
|
|
844
|
+
It adds nothing for `try` itself, `finally`, `return`, `throw`, recursion, Rust `?`, Python `with`, Swift `do` without `catch`, an `if let` or `while let` beyond the `if` or `while`, optional chaining `?.`, assignment operators `||=`, `&&=`, `??=`, and a Rust `let` without `else`.
|
|
845
|
+
|
|
846
|
+
**Differences from the Sonar paper.** SonarJS, and so klint, departs from the 2017 paper in one place: `||` (Python `or`, C# pattern `or`) adds nothing; the paper counts it.
|
|
827
847
|
|
|
828
|
-
|
|
848
|
+
**Differences from Biome 2.6.5.** Biome's `noExcessiveCognitiveComplexity` differs from SonarJS in four ways, and klint follows SonarJS:
|
|
829
849
|
|
|
830
|
-
|
|
850
|
+
- `else if` gets no nesting increment (Biome adds it).
|
|
851
|
+
- `??` adds nothing (Biome counts it).
|
|
852
|
+
- `||` adds nothing (Biome counts it).
|
|
853
|
+
- Biome 2.6.5 lowers the nesting level of the code after a plain `else` (an unbalanced decrement). That is a Biome bug; klint keeps the nesting.
|
|
831
854
|
|
|
832
|
-
|
|
833
|
-
- `finally` adds one and does not nest its body.
|
|
834
|
-
- `??` counts as a boolean operator.
|
|
835
|
-
- A logical operator is scored unless its direct parent is the same operator, so `a && (b && c)` is 2, not 1.
|
|
836
|
-
- Recursion adds nothing.
|
|
837
|
-
- Biome 2.6.5 lowers the nesting level of the code after a plain `else` (an unbalanced decrement), so it can score such functions lower; klint keeps the nesting.
|
|
838
|
-
- A nested function (closure, lambda, arrow, local function) is scored and reported on its own. It starts at its enclosing nesting level plus one and does not add to the outer function.
|
|
855
|
+
A nested function (closure, lambda, arrow, local function) is scored and reported on its own and does not add to the outer function.
|
|
839
856
|
|
|
840
857
|
**What counts as a function.** TypeScript/JavaScript: `function` declarations and expressions, arrow functions, methods (including getters and setters), generator functions. Python: `def` and `lambda`. Swift: `func`, `init`, `deinit`, closures, computed getters and setters. Rust: `fn` items and closures. C#: methods, constructors, destructors, local functions, lambdas, anonymous methods, property and indexer accessors, operators and conversion operators.
|
|
841
858
|
|
|
@@ -847,16 +864,18 @@ It adds nothing for `try` itself, `return`, `throw`, recursion, Rust `?`, Python
|
|
|
847
864
|
|
|
848
865
|
```yaml
|
|
849
866
|
rules:
|
|
850
|
-
|
|
867
|
+
core:
|
|
868
|
+
function-length: error
|
|
851
869
|
```
|
|
852
870
|
|
|
853
871
|
```yaml
|
|
854
872
|
rules:
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
873
|
+
core:
|
|
874
|
+
function-length:
|
|
875
|
+
severity: warn
|
|
876
|
+
include: ["src/**", "!src/generated/**"]
|
|
877
|
+
max: 40
|
|
878
|
+
skipBlankLines: true
|
|
860
879
|
```
|
|
861
880
|
|
|
862
881
|
- `max` is an integer of at least 1, default 50. A function is reported when its count is **greater than** `max`. Any other value (0, a negative number, a fraction, a string) gives one `klint/config` warning naming the rule and the value, and the rule uses 50.
|
|
@@ -869,9 +888,9 @@ rules:
|
|
|
869
888
|
|
|
870
889
|
**Not checked.** Bodyless declarations, and files with a syntax error.
|
|
871
890
|
|
|
872
|
-
##
|
|
891
|
+
## Sonar rules (`rules.sonar`)
|
|
873
892
|
|
|
874
|
-
|
|
893
|
+
`recommended: true` enables these rules. Override each one under `rules.sonar` by its name without the prefix.
|
|
875
894
|
|
|
876
895
|
| Rule | Description |
|
|
877
896
|
|------|-------------|
|