@konvert7/klint 1.4.0 → 1.5.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
@@ -745,8 +745,8 @@ doc-comments alongside `/** */`.
745
745
  | `no-string-match` | `String#match()` usage better expressed with clearer APIs |
746
746
  | `blank-line-before-control-flow` | Blank line above a control-flow statement that follows another statement; autofix |
747
747
  | `blank-line-after-block` | Blank line below a block statement when another statement follows; autofix |
748
- | `cognitive-complexity` | Function whose cognitive complexity (Biome / SonarSource model) is above `max`, in all five languages; opt-in, no autofix |
749
- | `function-length` | Function whose body has more lines than `max` (counted like Biome's `noExcessiveLinesPerFunction`), in all five languages; opt-in, no autofix |
748
+ | `cognitive-complexity` | Function whose cognitive complexity (SonarJS / SonarSource model) is above its `warn`/`error` limits, in all five languages; opt-in, no autofix |
749
+ | `function-length` | Function whose body has more lines than its `warn`/`error` limits (counted like Biome's `noExcessiveLinesPerFunction`), in all five languages; opt-in, no autofix |
750
750
 
751
751
  Rules that needed TypeScript's type checker were removed in 1.0; see [Upgrading from klint 0.x](#upgrading-from-klint-0x).
752
752
 
@@ -800,7 +800,7 @@ rules:
800
800
 
801
801
  ### Cognitive complexity
802
802
 
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 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 its `warn` or `error` limit, 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.
804
804
 
805
805
  ```yaml
806
806
  rules:
@@ -808,50 +808,69 @@ rules:
808
808
  cognitive-complexity: error
809
809
  ```
810
810
 
811
+ ```yaml
812
+ rules:
813
+ core:
814
+ cognitive-complexity: {warn: 10, error: 20}
815
+ ```
816
+
811
817
  ```yaml
812
818
  rules:
813
819
  core:
814
820
  cognitive-complexity:
815
- severity: warn
816
- include: ["src/**", "!src/generated/**"]
817
- max: 14
821
+ - {error: 15}
822
+ - {warn: 10, error: 20, include: ["scripts/**"]}
818
823
  ```
819
824
 
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.
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.
825
+ - `warn` and `error` are integers of at least 1; set either or both. A bare `error` or `warn` uses the default, 15. A function is reported when its score is **greater than** the limit. Any other value (0, a negative number, a fraction, a string) gives one `klint/config` warning naming the rule and the value, and that entry is ignored.
826
+ - One diagnostic per function, at the highest level it exceeds (a function exactly at a limit does not exceed it). `error` below `warn` gives one `klint/config` warning on the rule line and the rule runs with `error` only; `error` equal to `warn` is valid and does the same.
827
+ - A list sets limits per glob. Each entry takes `warn`, `error` and `include`. The last entry whose `include` matches a file wins; entries do not merge; a file no entry matches is not checked; an empty list turns the rule off.
828
+ - The old `{max, severity}` form is still read with today's behaviour. In a v2 config it gives one `klint/config` warning on the rule line: ``max` and `severity` on cognitive-complexity are the old form — run `klint migrate` to upgrade it in place.`` Mixing old and new keys in one object gives one warning, and the new keys apply.
829
+ - The message has the form ``Function `big` has cognitive complexity 16 (max 15) — split it into smaller functions.``, where `max` is the limit exceeded. 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.
822
830
  - Each function starts at 0. Top-level code is not scored.
823
831
 
824
- **Scoring.** "Nesting" is how deep a construct sits: each enclosing `if`, loop, `switch`, `catch`, `guard`, `let … else` body and each enclosing function adds one.
832
+ **Migrating the old form.** `klint migrate` (and `klint --fix`) rewrites the old form as follows, and `klint migrate --check` exits 1 while any of it is left:
833
+
834
+ | old | new |
835
+ |---|---|
836
+ | `{max: M}` or `{max: M, severity: error}` | `{error: M}` |
837
+ | `{max: M, severity: warn}` | `{warn: M}` |
838
+ | `{max: M, severity: off}` | `off` |
839
+ | `{severity: S}` (no `max`) | `{S: <default>}`, i.e. `{error: 15}` / `{warn: 50}`; `off` → `off` |
840
+ | `include`, `skipBlankLines` | kept unchanged in the same object |
841
+
842
+ **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.
825
843
 
826
844
  | Increment | TypeScript / JavaScript | Python | Swift | Rust | C# |
827
845
  |---|---|---|---|---|---|
828
- | +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` |
846
+ | +1 plus nesting: `if` | `if` | `if` | `if`, `if let` | `if` |
847
+ | +1, no nesting: `else if` (its body is nested like the `if` body) | `else if` | `elif` | `else if` | `else if` | `else if` |
829
848
  | +1 plus nesting: ternary | `?:` | `x if c else y` | `?:` | — | `?:` |
830
849
  | +1 plus nesting: switch / match | `switch` | `match` | `switch` | `match` | `switch` statement, `switch` expression |
831
850
  | +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` |
832
851
  | +1 plus nesting: `catch` | `catch` | `except` | `catch` | — | `catch` |
833
852
  | +1 plus nesting: `guard`, `let … else` (its `else` body is nested) | — | — | `guard` | `let … else` | — |
834
- | +1, no nesting: `finally` (its body is not nested) | `finally` | `finally` | — | — | `finally` |
835
- | 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 |
853
+ | 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 |
836
854
  | +1, no nesting: plain `else` (not `else if`/`elif`) | `else` | `else` of `if`, `try`, `for`, `while` | `else` | `else` | `else` |
837
855
  | +1: labeled `break` / `continue`, `goto` | `break label`, `continue label` | — | `break label`, `continue label` | `break 'label`, `continue 'label` | `goto` |
838
- | +1 per logical operator, unless its direct parent is the same operator | `&&`, `\|\|`, `??` | `and`, `or` | `&&`, `\|\|`, `??` | `&&`, `\|\|` | `&&`, `\|\|`, `??`, pattern `and`, `or` |
856
+ | +1 per run of `&&` (see below); `\|\|`, `or`, `??` add nothing | `&&` | `and` | `&&` | `&&` | `&&`, pattern `and` |
839
857
  | +1: comprehension `if` | — | comprehension `if` | — | — | — |
840
858
  | +1: guard on a case or arm | — | — | `case … where` | match-arm guard | `when` clause |
841
859
 
842
- 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.
860
+ 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.
861
+
862
+ 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`.
843
863
 
844
- 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`.
864
+ **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.
845
865
 
846
- **Differences from the Sonar paper.** This rule follows Biome, which differs from the paper in these places:
866
+ **Differences from Biome 2.6.5.** Biome's `noExcessiveCognitiveComplexity` differs from SonarJS in four ways, and klint follows SonarJS:
847
867
 
848
- - `else if` gets the nesting increment.
849
- - `finally` adds one and does not nest its body.
850
- - `??` counts as a boolean operator.
851
- - A logical operator is scored unless its direct parent is the same operator, so `a && (b && c)` is 2, not 1.
852
- - Recursion adds nothing.
853
- - 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.
854
- - 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.
868
+ - `else if` gets no nesting increment (Biome adds it).
869
+ - `??` adds nothing (Biome counts it).
870
+ - `||` adds nothing (Biome counts it).
871
+ - 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.
872
+
873
+ A nested function (closure, lambda, arrow, local function) is scored and reported on its own and does not add to the outer function.
855
874
 
856
875
  **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.
857
876
 
@@ -859,7 +878,7 @@ It adds nothing for `try` itself, `return`, `throw`, recursion, Rust `?`, Python
859
878
 
860
879
  ### Function length
861
880
 
862
- `function-length` reports every function whose body has more than `max` lines, in TypeScript/JavaScript, Python, Swift, Rust and C#. It is opt-in and has no fix. It counts with Biome 2.6.5's `noExcessiveLinesPerFunction` algorithm in every language, so a TypeScript function gets the same count as in Biome.
881
+ `function-length` reports every function whose body has more lines than its `warn` or `error` limit, in TypeScript/JavaScript, Python, Swift, Rust and C#. It is opt-in and has no fix. It counts with Biome 2.6.5's `noExcessiveLinesPerFunction` algorithm in every language, so a TypeScript function gets the same count as in Biome.
863
882
 
864
883
  ```yaml
865
884
  rules:
@@ -867,19 +886,36 @@ rules:
867
886
  function-length: error
868
887
  ```
869
888
 
889
+ ```yaml
890
+ rules:
891
+ core:
892
+ function-length: {warn: 60, error: 80, skipBlankLines: true}
893
+ ```
894
+
870
895
  ```yaml
871
896
  rules:
872
897
  core:
873
898
  function-length:
874
- severity: warn
875
- include: ["src/**", "!src/generated/**"]
876
- max: 40
877
- skipBlankLines: true
899
+ - {error: 50}
900
+ - {warn: 60, error: 80, include: ["scripts/**"]}
878
901
  ```
879
902
 
880
- - `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.
903
+ - `warn` and `error` are integers of at least 1; set either or both. A bare `error` or `warn` uses the default, 50. A function is reported when its count is **greater than** the limit. Any other value (0, a negative number, a fraction, a string) gives one `klint/config` warning naming the rule and the value, and that entry is ignored.
904
+ - One diagnostic per function, at the highest level it exceeds (a function exactly at a limit does not exceed it). `error` below `warn` gives one `klint/config` warning on the rule line and the rule runs with `error` only; `error` equal to `warn` is valid and does the same.
905
+ - A list sets limits per glob. Each entry takes `warn`, `error`, `include` and `skipBlankLines`. The last entry whose `include` matches a file wins; entries do not merge; a file no entry matches is not checked; an empty list turns the rule off.
906
+ - The old `{max, severity}` form is still read with today's behaviour. In a v2 config it gives one `klint/config` warning on the rule line: ``max` and `severity` on function-length are the old form — run `klint migrate` to upgrade it in place.`` Mixing old and new keys in one object gives one warning, and the new keys apply.
881
907
  - `skipBlankLines` is a boolean, default `false`. Any other value gives one `klint/config` warning naming the rule and the value, and the rule uses `false`.
882
- - The message has the form ``Function `big` has 51 lines (max 50) — split it into smaller functions.``. The name is the declared name, the same rule as `cognitive-complexity`. The line is the function's first line.
908
+ - The message has the form ``Function `big` has 51 lines (max 50) — split it into smaller functions.``, where `max` is the limit exceeded. The name is the declared name, the same rule as `cognitive-complexity`. The line is the function's first line.
909
+
910
+ **Migrating the old form.** `klint migrate` (and `klint --fix`) rewrites the old form as follows, and `klint migrate --check` exits 1 while any of it is left:
911
+
912
+ | old | new |
913
+ |---|---|
914
+ | `{max: M}` or `{max: M, severity: error}` | `{error: M}` |
915
+ | `{max: M, severity: warn}` | `{warn: M}` |
916
+ | `{max: M, severity: off}` | `off` |
917
+ | `{severity: S}` (no `max`) | `{S: <default>}`, i.e. `{error: 15}` / `{warn: 50}`; `off` → `off` |
918
+ | `include`, `skipBlankLines` | kept unchanged in the same object |
883
919
 
884
920
  **Counting.** Only the body counts, not the signature line, decorators or attributes. Every line break before a token in the body counts, except a break before `{` or `}`, so lines that hold only braces (and `};`) do not count. Comment lines and blank lines count. With `skipBlankLines`, a run of blank lines adds nothing beyond the line it leads to. A multi-line string or template counts once. Blank lines before the closing brace do not count. A nested function's lines count toward its parent, and the nested function is also checked on its own. Python counts each statement's line (there are no braces), and docstrings count.
885
921
 
package/klint.schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.4.0/klint.schema.json",
2
+ "$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.5.0/klint.schema.json",
3
3
  "$schema": "http://json-schema.org/draft-07/schema#",
4
4
  "additionalProperties": false,
5
5
  "description": "klint configuration. Lives at klint.yaml (or klint.config.json) next to biome.json and knip.json.",
@@ -744,8 +744,30 @@
744
744
  },
745
745
  {
746
746
  "additionalProperties": false,
747
- "description": "Rule options object. Omit severity to default to \"error\". Add include to scope the rule to specific files.",
747
+ "allOf": [
748
+ {
749
+ "anyOf": [
750
+ {
751
+ "required": [
752
+ "warn"
753
+ ]
754
+ },
755
+ {
756
+ "required": [
757
+ "error"
758
+ ]
759
+ }
760
+ ]
761
+ }
762
+ ],
763
+ "description": "warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.",
748
764
  "properties": {
765
+ "error": {
766
+ "description": "Report a function above this limit as an error. If error is below warn, only error applies.",
767
+ "format": "uint32",
768
+ "minimum": 1,
769
+ "type": "integer"
770
+ },
749
771
  "include": {
750
772
  "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
751
773
  "items": {
@@ -753,31 +775,67 @@
753
775
  },
754
776
  "type": "array"
755
777
  },
756
- "max": {
757
- "default": 15,
758
- "description": "Highest cognitive complexity a function may have; a function scoring above it is reported. An integer of at least 1. Defaults to 15.",
778
+ "warn": {
779
+ "description": "Report a function above this limit as a warning.",
759
780
  "format": "uint32",
760
781
  "minimum": 1,
761
782
  "type": "integer"
762
- },
763
- "severity": {
764
- "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
765
- "enum": [
766
- "error",
767
- "warn",
768
- "off",
769
- null
770
- ],
771
- "type": "string"
772
783
  }
773
784
  },
774
785
  "type": "object"
786
+ },
787
+ {
788
+ "description": "Per-glob limits: the last entry whose include matches a file wins; entries do not merge. An empty list turns the rule off.",
789
+ "items": {
790
+ "additionalProperties": false,
791
+ "allOf": [
792
+ {
793
+ "anyOf": [
794
+ {
795
+ "required": [
796
+ "warn"
797
+ ]
798
+ },
799
+ {
800
+ "required": [
801
+ "error"
802
+ ]
803
+ }
804
+ ]
805
+ }
806
+ ],
807
+ "description": "warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.",
808
+ "properties": {
809
+ "error": {
810
+ "description": "Report a function above this limit as an error. If error is below warn, only error applies.",
811
+ "format": "uint32",
812
+ "minimum": 1,
813
+ "type": "integer"
814
+ },
815
+ "include": {
816
+ "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
817
+ "items": {
818
+ "type": "string"
819
+ },
820
+ "type": "array"
821
+ },
822
+ "warn": {
823
+ "description": "Report a function above this limit as a warning.",
824
+ "format": "uint32",
825
+ "minimum": 1,
826
+ "type": "integer"
827
+ }
828
+ },
829
+ "type": "object"
830
+ },
831
+ "type": "array"
775
832
  }
776
833
  ],
777
- "description": "Reports every function whose cognitive complexity is above `max` (default 15), scored like Biome 2.6.5's `noExcessiveCognitiveComplexity` (the SonarSource Cognitive Complexity model). Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
834
+ "description": "Reports every function whose cognitive complexity is above a limit, scored like `eslint-plugin-sonarjs` 3.0.5's `cognitive-complexity` (SonarSource rule S3776). Set `warn` and/or `error` limits (bare `error`/`warn` uses 15); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include}` entries sets limits per glob, and the last entry whose include matches a file wins. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
778
835
  "examples": [
779
836
  "cognitive-complexity: error",
780
- "cognitive-complexity:\n severity: warn\n include: [\"src/**\", \"!src/generated/**\"]\n max: 14"
837
+ "cognitive-complexity: {warn: 10, error: 20}",
838
+ "cognitive-complexity:\n - {error: 15}\n - {warn: 10, error: 20, include: [\"scripts/**\"]}"
781
839
  ]
782
840
  },
783
841
  "function-length": {
@@ -793,8 +851,30 @@
793
851
  },
794
852
  {
795
853
  "additionalProperties": false,
796
- "description": "Rule options object. Omit severity to default to \"error\". Add include to scope the rule to specific files.",
854
+ "allOf": [
855
+ {
856
+ "anyOf": [
857
+ {
858
+ "required": [
859
+ "warn"
860
+ ]
861
+ },
862
+ {
863
+ "required": [
864
+ "error"
865
+ ]
866
+ }
867
+ ]
868
+ }
869
+ ],
870
+ "description": "warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.",
797
871
  "properties": {
872
+ "error": {
873
+ "description": "Report a function above this limit as an error. If error is below warn, only error applies.",
874
+ "format": "uint32",
875
+ "minimum": 1,
876
+ "type": "integer"
877
+ },
798
878
  "include": {
799
879
  "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
800
880
  "items": {
@@ -802,36 +882,77 @@
802
882
  },
803
883
  "type": "array"
804
884
  },
805
- "max": {
806
- "default": 50,
807
- "description": "Highest number of lines a function body may have; a function counting more is reported. An integer of at least 1. Defaults to 50.",
808
- "format": "uint32",
809
- "minimum": 1,
810
- "type": "integer"
811
- },
812
- "severity": {
813
- "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
814
- "enum": [
815
- "error",
816
- "warn",
817
- "off",
818
- null
819
- ],
820
- "type": "string"
821
- },
822
885
  "skipBlankLines": {
823
886
  "default": false,
824
887
  "description": "Leave blank lines out of the count. Defaults to false.",
825
888
  "type": "boolean"
889
+ },
890
+ "warn": {
891
+ "description": "Report a function above this limit as a warning.",
892
+ "format": "uint32",
893
+ "minimum": 1,
894
+ "type": "integer"
826
895
  }
827
896
  },
828
897
  "type": "object"
898
+ },
899
+ {
900
+ "description": "Per-glob limits: the last entry whose include matches a file wins; entries do not merge. An empty list turns the rule off.",
901
+ "items": {
902
+ "additionalProperties": false,
903
+ "allOf": [
904
+ {
905
+ "anyOf": [
906
+ {
907
+ "required": [
908
+ "warn"
909
+ ]
910
+ },
911
+ {
912
+ "required": [
913
+ "error"
914
+ ]
915
+ }
916
+ ]
917
+ }
918
+ ],
919
+ "description": "warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.",
920
+ "properties": {
921
+ "error": {
922
+ "description": "Report a function above this limit as an error. If error is below warn, only error applies.",
923
+ "format": "uint32",
924
+ "minimum": 1,
925
+ "type": "integer"
926
+ },
927
+ "include": {
928
+ "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
929
+ "items": {
930
+ "type": "string"
931
+ },
932
+ "type": "array"
933
+ },
934
+ "skipBlankLines": {
935
+ "default": false,
936
+ "description": "Leave blank lines out of the count. Defaults to false.",
937
+ "type": "boolean"
938
+ },
939
+ "warn": {
940
+ "description": "Report a function above this limit as a warning.",
941
+ "format": "uint32",
942
+ "minimum": 1,
943
+ "type": "integer"
944
+ }
945
+ },
946
+ "type": "object"
947
+ },
948
+ "type": "array"
829
949
  }
830
950
  ],
831
- "description": "Reports every function whose body has more than `max` lines (default 50), counted like Biome 2.6.5's `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function's lines count toward its parent. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
951
+ "description": "Reports every function whose body has more lines than a limit, counted like Biome 2.6.5's `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function's lines count toward its parent. Set `warn` and/or `error` limits (bare `error`/`warn` uses 50); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include, skipBlankLines}` entries sets limits per glob, and the last entry whose include matches a file wins. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
832
952
  "examples": [
833
953
  "function-length: error",
834
- "function-length:\n severity: warn\n include: [\"src/**\", \"!src/generated/**\"]\n max: 40\n skipBlankLines: true"
954
+ "function-length: {warn: 60, error: 80, skipBlankLines: true}",
955
+ "function-length:\n - {error: 50}\n - {warn: 60, error: 80, include: [\"scripts/**\"]}"
835
956
  ]
836
957
  },
837
958
  "no-async-predicate": {
@@ -1591,10 +1712,11 @@
1591
1712
  "type": "object"
1592
1713
  }
1593
1714
  ],
1594
- "description": "Reports every function whose cognitive complexity is above `max` (default 15), scored like Biome 2.6.5's `noExcessiveCognitiveComplexity` (the SonarSource Cognitive Complexity model). Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
1715
+ "description": "Reports every function whose cognitive complexity is above a limit, scored like `eslint-plugin-sonarjs` 3.0.5's `cognitive-complexity` (SonarSource rule S3776). Set `warn` and/or `error` limits (bare `error`/`warn` uses 15); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include}` entries sets limits per glob, and the last entry whose include matches a file wins. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
1595
1716
  "examples": [
1596
1717
  "cognitive-complexity: error",
1597
- "cognitive-complexity:\n severity: warn\n include: [\"src/**\", \"!src/generated/**\"]\n max: 14"
1718
+ "cognitive-complexity: {warn: 10, error: 20}",
1719
+ "cognitive-complexity:\n - {error: 15}\n - {warn: 10, error: 20, include: [\"scripts/**\"]}"
1598
1720
  ]
1599
1721
  },
1600
1722
  "function-length": {
@@ -1645,10 +1767,11 @@
1645
1767
  "type": "object"
1646
1768
  }
1647
1769
  ],
1648
- "description": "Reports every function whose body has more than `max` lines (default 50), counted like Biome 2.6.5's `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function's lines count toward its parent. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
1770
+ "description": "Reports every function whose body has more lines than a limit, counted like Biome 2.6.5's `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function's lines count toward its parent. Set `warn` and/or `error` limits (bare `error`/`warn` uses 50); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include, skipBlankLines}` entries sets limits per glob, and the last entry whose include matches a file wins. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.",
1649
1771
  "examples": [
1650
1772
  "function-length: error",
1651
- "function-length:\n severity: warn\n include: [\"src/**\", \"!src/generated/**\"]\n max: 40\n skipBlankLines: true"
1773
+ "function-length: {warn: 60, error: 80, skipBlankLines: true}",
1774
+ "function-length:\n - {error: 50}\n - {warn: 60, error: 80, include: [\"scripts/**\"]}"
1652
1775
  ]
1653
1776
  },
1654
1777
  "no-async-predicate": {
package/klint.schema.yaml CHANGED
@@ -1,4 +1,4 @@
1
- $id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.4.0/klint.schema.json
1
+ $id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.5.0/klint.schema.json
2
2
  $schema: http://json-schema.org/draft-07/schema#
3
3
  additionalProperties: false
4
4
  description: klint configuration. Lives at klint.yaml (or klint.config.json) next to biome.json and knip.json.
@@ -566,36 +566,66 @@ properties:
566
566
  - off
567
567
  type: string
568
568
  - additionalProperties: false
569
- description: Rule options object. Omit severity to default to "error". Add include to scope the rule to specific files.
569
+ allOf:
570
+ - anyOf:
571
+ - required:
572
+ - warn
573
+ - required:
574
+ - error
575
+ description: warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.
570
576
  properties:
577
+ error:
578
+ description: Report a function above this limit as an error. If error is below warn, only error applies.
579
+ format: uint32
580
+ minimum: 1
581
+ type: integer
571
582
  include:
572
583
  description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
573
584
  items:
574
585
  type: string
575
586
  type: array
576
- max:
577
- default: 15
578
- description: Highest cognitive complexity a function may have; a function scoring above it is reported. An integer of at least 1. Defaults to 15.
587
+ warn:
588
+ description: Report a function above this limit as a warning.
579
589
  format: uint32
580
590
  minimum: 1
581
591
  type: integer
582
- severity:
583
- description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
584
- enum:
585
- - error
586
- - warn
587
- - off
588
- - null
589
- type: string
590
592
  type: object
591
- description: Reports every function whose cognitive complexity is above `max` (default 15), scored like Biome 2.6.5's `noExcessiveCognitiveComplexity` (the SonarSource Cognitive Complexity model). Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.
593
+ - description: 'Per-glob limits: the last entry whose include matches a file wins; entries do not merge. An empty list turns the rule off.'
594
+ items:
595
+ additionalProperties: false
596
+ allOf:
597
+ - anyOf:
598
+ - required:
599
+ - warn
600
+ - required:
601
+ - error
602
+ description: warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.
603
+ properties:
604
+ error:
605
+ description: Report a function above this limit as an error. If error is below warn, only error applies.
606
+ format: uint32
607
+ minimum: 1
608
+ type: integer
609
+ include:
610
+ description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
611
+ items:
612
+ type: string
613
+ type: array
614
+ warn:
615
+ description: Report a function above this limit as a warning.
616
+ format: uint32
617
+ minimum: 1
618
+ type: integer
619
+ type: object
620
+ type: array
621
+ description: Reports every function whose cognitive complexity is above a limit, scored like `eslint-plugin-sonarjs` 3.0.5's `cognitive-complexity` (SonarSource rule S3776). Set `warn` and/or `error` limits (bare `error`/`warn` uses 15); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include}` entries sets limits per glob, and the last entry whose include matches a file wins. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.
592
622
  examples:
593
623
  - 'cognitive-complexity: error'
624
+ - 'cognitive-complexity: {warn: 10, error: 20}'
594
625
  - |-
595
626
  cognitive-complexity:
596
- severity: warn
597
- include: ["src/**", "!src/generated/**"]
598
- max: 14
627
+ - {error: 15}
628
+ - {warn: 10, error: 20, include: ["scripts/**"]}
599
629
  function-length:
600
630
  anyOf:
601
631
  - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
@@ -605,41 +635,74 @@ properties:
605
635
  - off
606
636
  type: string
607
637
  - additionalProperties: false
608
- description: Rule options object. Omit severity to default to "error". Add include to scope the rule to specific files.
638
+ allOf:
639
+ - anyOf:
640
+ - required:
641
+ - warn
642
+ - required:
643
+ - error
644
+ description: warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.
609
645
  properties:
646
+ error:
647
+ description: Report a function above this limit as an error. If error is below warn, only error applies.
648
+ format: uint32
649
+ minimum: 1
650
+ type: integer
610
651
  include:
611
652
  description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
612
653
  items:
613
654
  type: string
614
655
  type: array
615
- max:
616
- default: 50
617
- description: Highest number of lines a function body may have; a function counting more is reported. An integer of at least 1. Defaults to 50.
618
- format: uint32
619
- minimum: 1
620
- type: integer
621
- severity:
622
- description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
623
- enum:
624
- - error
625
- - warn
626
- - off
627
- - null
628
- type: string
629
656
  skipBlankLines:
630
657
  default: false
631
658
  description: Leave blank lines out of the count. Defaults to false.
632
659
  type: boolean
660
+ warn:
661
+ description: Report a function above this limit as a warning.
662
+ format: uint32
663
+ minimum: 1
664
+ type: integer
633
665
  type: object
634
- description: 'Reports every function whose body has more than `max` lines (default 50), counted like Biome 2.6.5''s `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function''s lines count toward its parent. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.'
666
+ - description: 'Per-glob limits: the last entry whose include matches a file wins; entries do not merge. An empty list turns the rule off.'
667
+ items:
668
+ additionalProperties: false
669
+ allOf:
670
+ - anyOf:
671
+ - required:
672
+ - warn
673
+ - required:
674
+ - error
675
+ description: warn and/or error limits. A function gets one diagnostic, at the highest level it exceeds.
676
+ properties:
677
+ error:
678
+ description: Report a function above this limit as an error. If error is below warn, only error applies.
679
+ format: uint32
680
+ minimum: 1
681
+ type: integer
682
+ include:
683
+ description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
684
+ items:
685
+ type: string
686
+ type: array
687
+ skipBlankLines:
688
+ default: false
689
+ description: Leave blank lines out of the count. Defaults to false.
690
+ type: boolean
691
+ warn:
692
+ description: Report a function above this limit as a warning.
693
+ format: uint32
694
+ minimum: 1
695
+ type: integer
696
+ type: object
697
+ type: array
698
+ description: 'Reports every function whose body has more lines than a limit, counted like Biome 2.6.5''s `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function''s lines count toward its parent. Set `warn` and/or `error` limits (bare `error`/`warn` uses 50); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include, skipBlankLines}` entries sets limits per glob, and the last entry whose include matches a file wins. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.'
635
699
  examples:
636
700
  - 'function-length: error'
701
+ - 'function-length: {warn: 60, error: 80, skipBlankLines: true}'
637
702
  - |-
638
703
  function-length:
639
- severity: warn
640
- include: ["src/**", "!src/generated/**"]
641
- max: 40
642
- skipBlankLines: true
704
+ - {error: 50}
705
+ - {warn: 60, error: 80, include: ["scripts/**"]}
643
706
  no-async-predicate:
644
707
  anyOf:
645
708
  - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
@@ -1176,14 +1239,14 @@ properties:
1176
1239
  - null
1177
1240
  type: string
1178
1241
  type: object
1179
- description: Reports every function whose cognitive complexity is above `max` (default 15), scored like Biome 2.6.5's `noExcessiveCognitiveComplexity` (the SonarSource Cognitive Complexity model). Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.
1242
+ description: Reports every function whose cognitive complexity is above a limit, scored like `eslint-plugin-sonarjs` 3.0.5's `cognitive-complexity` (SonarSource rule S3776). Set `warn` and/or `error` limits (bare `error`/`warn` uses 15); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include}` entries sets limits per glob, and the last entry whose include matches a file wins. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.
1180
1243
  examples:
1181
1244
  - 'cognitive-complexity: error'
1245
+ - 'cognitive-complexity: {warn: 10, error: 20}'
1182
1246
  - |-
1183
1247
  cognitive-complexity:
1184
- severity: warn
1185
- include: ["src/**", "!src/generated/**"]
1186
- max: 14
1248
+ - {error: 15}
1249
+ - {warn: 10, error: 20, include: ["scripts/**"]}
1187
1250
  function-length:
1188
1251
  anyOf:
1189
1252
  - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
@@ -1219,15 +1282,14 @@ properties:
1219
1282
  description: Leave blank lines out of the count. Defaults to false.
1220
1283
  type: boolean
1221
1284
  type: object
1222
- description: 'Reports every function whose body has more than `max` lines (default 50), counted like Biome 2.6.5''s `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function''s lines count toward its parent. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.'
1285
+ description: 'Reports every function whose body has more lines than a limit, counted like Biome 2.6.5''s `noExcessiveLinesPerFunction`: brace lines do not count, comment and blank lines do (blank lines not with `skipBlankLines`), and a nested function''s lines count toward its parent. Set `warn` and/or `error` limits (bare `error`/`warn` uses 50); a function gets one diagnostic, at the highest level it exceeds. A list of `{warn, error, include, skipBlankLines}` entries sets limits per glob, and the last entry whose include matches a file wins. Getters and setters are not checked. Works on TypeScript/JavaScript, Python, Swift, Rust and C#. Opt-in; no autofix.'
1223
1286
  examples:
1224
1287
  - 'function-length: error'
1288
+ - 'function-length: {warn: 60, error: 80, skipBlankLines: true}'
1225
1289
  - |-
1226
1290
  function-length:
1227
- severity: warn
1228
- include: ["src/**", "!src/generated/**"]
1229
- max: 40
1230
- skipBlankLines: true
1291
+ - {error: 50}
1292
+ - {warn: 60, error: 80, include: ["scripts/**"]}
1231
1293
  no-async-predicate:
1232
1294
  anyOf:
1233
1295
  - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konvert7/klint",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Architecture-as-Code linter for TypeScript. Enforce layer boundaries, import rules, and singleton patterns in YAML.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -56,12 +56,12 @@
56
56
  ]
57
57
  },
58
58
  "optionalDependencies": {
59
- "@konvert7/klint-darwin-arm64": "1.4.0",
60
- "@konvert7/klint-darwin-x64": "1.4.0",
61
- "@konvert7/klint-linux-arm64": "1.4.0",
62
- "@konvert7/klint-linux-x64": "1.4.0",
63
- "@konvert7/klint-linux-x64-musl": "1.4.0",
64
- "@konvert7/klint-win32-x64": "1.4.0"
59
+ "@konvert7/klint-darwin-arm64": "1.5.0",
60
+ "@konvert7/klint-darwin-x64": "1.5.0",
61
+ "@konvert7/klint-linux-arm64": "1.5.0",
62
+ "@konvert7/klint-linux-x64": "1.5.0",
63
+ "@konvert7/klint-linux-x64-musl": "1.5.0",
64
+ "@konvert7/klint-win32-x64": "1.5.0"
65
65
  },
66
66
  "devDependencies": {
67
67
  "@biomejs/biome": "2.6.5",
@@ -72,6 +72,9 @@
72
72
  "@semantic-release/github": "^12.0.6",
73
73
  "@types/bun": "latest",
74
74
  "@types/node": "latest",
75
+ "@typescript-eslint/parser": "8.72.2",
76
+ "eslint": "9.39.5",
77
+ "eslint-plugin-sonarjs": "3.0.5",
75
78
  "husky": "^9.1.7",
76
79
  "jscpd": "4.2.3",
77
80
  "knip": "^6.9.0",