@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 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
- no-async-predicate: error
57
- no-unguarded-json-parse: error
58
- no-sync-in-async:
59
- severity: error
60
- include: ["src/hooks/**"]
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
- no-unguarded-json-parse: error
231
- no-async-predicate: error
232
- sonar/prefer-string-replaceall: warn
233
- no-sync-in-async:
234
- severity: error
235
- include: ["src/server/**"]
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
- `plugins` enables bundled rule groups. Today, `sonar` provides focused code-quality rules.
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` maps rule names to `"error"`, `"warn"`, `"off"`, or an options object with `severity` and/or `include`.
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 (Biome / SonarSource model) is above `max`, in all five languages; opt-in, no autofix |
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
- blank-line-before-control-flow: error
748
- blank-line-after-block: warn
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
- blank-line-before-control-flow:
754
- severity: error
755
- include: ["src/**", "!src/generated/**"]
756
- statements: [if, for, while, switch, try, return, guard, loop, with]
757
- allowSetup: true
758
- blank-line-after-block:
759
- severity: warn
760
- include: ["src/**"]
761
- statements: [if, for, while, switch, try, guard, loop, with]
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 uses Biome 2.6.5's `noExcessiveCognitiveComplexity` scoring (the SonarSource Cognitive Complexity model, G. Ann Campbell 2017) for every language, so a TypeScript function gets the same score as in Biome.
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
- cognitive-complexity: error
807
+ core:
808
+ cognitive-complexity: error
794
809
  ```
795
810
 
796
811
  ```yaml
797
812
  rules:
798
- cognitive-complexity:
799
- severity: warn
800
- include: ["src/**", "!src/generated/**"]
801
- max: 14
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`, `let … else` body and each enclosing function adds one.
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`, and `else if` (which also gets the nesting) | `if`, `else if` | `if`, `elif` | `if`, `else if` | `if`, `if let`, `else if` | `if`, `else 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
- | +1, no nesting: `finally` (its body is not nested) | `finally` | `finally` | — | — | `finally` |
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 logical operator, unless its direct parent is the same operator | `&&`, `\|\|`, `??` | `and`, `or` | `&&`, `\|\|`, `??` | `&&`, `\|\|` | `&&`, `\|\|`, `??`, pattern `and`, `or` |
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 logical operator scores +1, unless its direct parent is a logical operator of the same kind. Parentheses break that link, so a parenthesised group scores on its own: `a && b || c` is 2, `a && (b || c) && a` is 2, `a && (b && c)` is 2, and `a ?? b ?? c` is 1. Negation (`!`, `not`) adds nothing.
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
- It adds nothing for `try` itself, `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`.
848
+ **Differences from Biome 2.6.5.** Biome's `noExcessiveCognitiveComplexity` differs from SonarJS in four ways, and klint follows SonarJS:
829
849
 
830
- **Differences from the Sonar paper.** This rule follows Biome, which differs from the paper in these places:
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
- - `else if` gets the nesting increment.
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
- function-length: error
867
+ core:
868
+ function-length: error
851
869
  ```
852
870
 
853
871
  ```yaml
854
872
  rules:
855
- function-length:
856
- severity: warn
857
- include: ["src/**", "!src/generated/**"]
858
- max: 40
859
- skipBlankLines: true
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
- ## Plugins
891
+ ## Sonar rules (`rules.sonar`)
873
892
 
874
- Enable plugin rules with `plugins: [sonar]`, then override individual severities in `rules` when needed.
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
  |------|-------------|