@konvert7/klint 0.31.0 → 0.32.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 +71 -24
- package/core/config.schema.ts +2 -2
- package/klint.schema.json +4 -4
- package/klint.schema.yaml +17 -15
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -446,7 +446,7 @@ arch:
|
|
|
446
446
|
in: ["src/**"]
|
|
447
447
|
```
|
|
448
448
|
|
|
449
|
-
Set `countDocComments: true` on either rule to count doc-comments toward the limit as well. Both rules run in the TS and Rust engines; Python (`#`) and
|
|
449
|
+
Set `countDocComments: true` on either rule to count doc-comments toward the limit as well. Both rules run in the TS and Rust engines; Python (`#`), Swift (`//`, `/* */`), and C# (`//`, `/* */`) files are enforced by the Rust engine.
|
|
450
450
|
|
|
451
451
|
Some comments are machinery rather than prose — markers a build or codegen step reads, region pragmas — and counting them makes both limits measure the wrong thing. `ignore` exempts them, on either rule:
|
|
452
452
|
|
|
@@ -462,33 +462,33 @@ An ignored line still counts in the density denominator — it is a physical lin
|
|
|
462
462
|
|
|
463
463
|
### Language Support
|
|
464
464
|
|
|
465
|
-
klint scans TypeScript/JavaScript, Python, Swift, and
|
|
466
|
-
|
|
467
|
-
| | TypeScript / JavaScript | Python | Swift | Rust |
|
|
468
|
-
|
|
469
|
-
| **Engines** | `ts`, `rust` | `rust` | `rust` | `rust` |
|
|
470
|
-
| **Parser** | TypeScript compiler API (TS engine), tree-sitter (Rust engine) | tree-sitter | tree-sitter | tree-sitter |
|
|
471
|
-
| `arch.imports` — static | ✅ | ✅ | ✅ | ✅ `use` |
|
|
472
|
-
| `arch.imports` — dynamic | ✅ `import()` | ✅ `importlib.import_module`, `__import__` | — | — |
|
|
473
|
-
| `arch.imports` — re-exports | ✅ `export … from` | — | ✅ `@_exported import` | ✅ `pub use` |
|
|
474
|
-
| `arch.imports` — multi-target | — | ✅ `import a, b` | — | ✅ `use a::{b, c}` |
|
|
475
|
-
| `type-only: allow` | ✅ `import type` | ✅ `if TYPE_CHECKING:` | — | — |
|
|
476
|
-
| Path aliases | ✅ `tsconfig.json` `paths` | — | — | — |
|
|
477
|
-
| Module resolution | relative paths + alias chains | relative, absolute, and PEP 420 namespace packages | module name against project dirs and file stems | `crate::`/`self::`/`super::` against the directory tree |
|
|
478
|
-
| `deny-packages` | ✅ `/` segments | ✅ `.` segments | ✅ `.` segments, module granularity | ✅ `::` segments |
|
|
479
|
-
| `arch.forbidden` / `singleton` — `pattern` | ✅ | ✅ | ✅ | ✅ |
|
|
480
|
-
| `arch.forbidden` / `singleton` — `jsx-element` | ✅ | — | — | — |
|
|
481
|
-
| `arch.maxLines` | ✅ | ✅ | ✅ | ✅ |
|
|
482
|
-
| `arch.maxCommentDensity` / `maxCommentBlock` | ✅ `//`, `/* */`, `/** */` docs | ✅ `#` | ✅ `//`, `/* */`, `///` and `/** */` docs | ✅ `//`, `/* */`, `///` and `//!` docs |
|
|
483
|
-
| Built-in rules and plugins | ✅ | ✗ | ✗ | ✗ |
|
|
484
|
-
| Custom rules (`klint.rules.ts`) | ✅ | ✗ | ✗ | ✗ |
|
|
485
|
-
| Type-aware rules | ✅ | ✗ | ✗ | ✗ |
|
|
465
|
+
klint scans TypeScript/JavaScript, Python, Swift, Rust, and C#. Every architecture rule is enforced from the same `klint.yaml`, but what a rule can *see* depends on what the language actually has.
|
|
466
|
+
|
|
467
|
+
| | TypeScript / JavaScript | Python | Swift | Rust | C# |
|
|
468
|
+
|---|---|---|---|---|---|
|
|
469
|
+
| **Engines** | `ts`, `rust` | `rust` | `rust` | `rust` | `rust` |
|
|
470
|
+
| **Parser** | TypeScript compiler API (TS engine), tree-sitter (Rust engine) | tree-sitter | tree-sitter | tree-sitter | tree-sitter |
|
|
471
|
+
| `arch.imports` — static | ✅ | ✅ | ✅ | ✅ `use` | ✅ `using` |
|
|
472
|
+
| `arch.imports` — dynamic | ✅ `import()` | ✅ `importlib.import_module`, `__import__` | — | — | — |
|
|
473
|
+
| `arch.imports` — re-exports | ✅ `export … from` | — | ✅ `@_exported import` | ✅ `pub use` | — |
|
|
474
|
+
| `arch.imports` — multi-target | — | ✅ `import a, b` | — | ✅ `use a::{b, c}` | — |
|
|
475
|
+
| `type-only: allow` | ✅ `import type` | ✅ `if TYPE_CHECKING:` | — | — | — |
|
|
476
|
+
| Path aliases | ✅ `tsconfig.json` `paths` | — | — | — | — |
|
|
477
|
+
| Module resolution | relative paths + alias chains | relative, absolute, and PEP 420 namespace packages | module name against project dirs and file stems | `crate::`/`self::`/`super::` against the directory tree | `using` namespace against project namespace declarations |
|
|
478
|
+
| `deny-packages` | ✅ `/` segments | ✅ `.` segments | ✅ `.` segments, module granularity | ✅ `::` segments | ✅ `.` segments |
|
|
479
|
+
| `arch.forbidden` / `singleton` — `pattern` | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
480
|
+
| `arch.forbidden` / `singleton` — `jsx-element` | ✅ | — | — | — | — |
|
|
481
|
+
| `arch.maxLines` | ✅ | ✅ | ✅ | ✅ | ✅ |
|
|
482
|
+
| `arch.maxCommentDensity` / `maxCommentBlock` | ✅ `//`, `/* */`, `/** */` docs | ✅ `#` | ✅ `//`, `/* */`, `///` and `/** */` docs | ✅ `//`, `/* */`, `///` and `//!` docs | ✅ `//`, `/* */`, `///` and `/** */` docs |
|
|
483
|
+
| Built-in rules and plugins | ✅ | ✗ | ✗ | ✗ | ✗ |
|
|
484
|
+
| Custom rules (`klint.rules.ts`) | ✅ | ✗ | ✗ | ✗ | ✗ |
|
|
485
|
+
| Type-aware rules | ✅ | ✗ | ✗ | ✗ | ✗ |
|
|
486
486
|
|
|
487
487
|
**✅** supported · **—** the language has no equivalent construct · **✗** not supported yet
|
|
488
488
|
|
|
489
|
-
A dash is not a gap. Swift has no dynamic import expression, no `import type`, and one module per declaration; Rust has no dynamic import and no type-only import
|
|
489
|
+
A dash is not a gap. Swift has no dynamic import expression, no `import type`, and one module per declaration; Rust has no dynamic import and no type-only import; C# has no dynamic `using`, no type-only import, and one namespace per `using`. Those rows can never be filled. The `✗` rows are real limits: the rule set and custom rules are written against the TypeScript AST, and type-aware rules need a type checker that only the TS engine has.
|
|
490
490
|
|
|
491
|
-
Imports are read off the AST in every language, so a specifier written inside a comment or a string is never an import — including nested Swift block comments. Only file discovery differs: the TS engine walks `.ts`/`.tsx`/`.js`/`.jsx`/`.mts`/`.cts`, so Python, Swift, and
|
|
491
|
+
Imports are read off the AST in every language, so a specifier written inside a comment or a string is never an import — including nested Swift block comments. Only file discovery differs: the TS engine walks `.ts`/`.tsx`/`.js`/`.jsx`/`.mts`/`.cts`, so Python, Swift, Rust, and C# files reach klint through the Rust engine, which `auto` mode selects for them automatically.
|
|
492
492
|
|
|
493
493
|
### Python Architecture Checks
|
|
494
494
|
|
|
@@ -629,6 +629,53 @@ not a Cargo build graph or `#[path]` attribute resolver.
|
|
|
629
629
|
Comment budget rules apply to Rust too, where both `///` and `//!` count as
|
|
630
630
|
doc-comments.
|
|
631
631
|
|
|
632
|
+
### C# Architecture Checks
|
|
633
|
+
|
|
634
|
+
The Rust engine can apply architecture rules to C# projects:
|
|
635
|
+
|
|
636
|
+
```yaml
|
|
637
|
+
include: ["src"]
|
|
638
|
+
|
|
639
|
+
rules: {}
|
|
640
|
+
|
|
641
|
+
arch:
|
|
642
|
+
layers:
|
|
643
|
+
web: ["src/Web/**"]
|
|
644
|
+
data: ["src/Data/**"]
|
|
645
|
+
config: ["src/Config/**"]
|
|
646
|
+
|
|
647
|
+
imports:
|
|
648
|
+
- from: web
|
|
649
|
+
deny: data
|
|
650
|
+
message: "Web must use app services, not import the data layer directly"
|
|
651
|
+
- from: web
|
|
652
|
+
deny-packages: ["Newtonsoft"]
|
|
653
|
+
message: "Use System.Text.Json instead of Newtonsoft"
|
|
654
|
+
|
|
655
|
+
forbidden:
|
|
656
|
+
- pattern: "Console.WriteLine("
|
|
657
|
+
in: web
|
|
658
|
+
message: "Use the logger"
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
C# import checks read `using` declarations off the AST, covering `using System;`,
|
|
662
|
+
qualified namespaces such as `using System.Collections.Generic;`, `using static
|
|
663
|
+
System.Math;`, `global using System.Linq;`, and aliases such as `using Json =
|
|
664
|
+
Newtonsoft.Json;` — an alias resolves to its target namespace, not the alias
|
|
665
|
+
name. Because the specifier comes from the parse tree, a `using` written inside a
|
|
666
|
+
`//` or `/* */` comment is not an import.
|
|
667
|
+
|
|
668
|
+
C# namespaces are decoupled from disk layout, so klint indexes the `namespace`
|
|
669
|
+
declarations across the project — block and file-scoped alike — and resolves a
|
|
670
|
+
`using` against that index. Namespaces that no project file declares, such as
|
|
671
|
+
`System`, are ignored by `deny`/`allow` and are the target of `deny-packages`
|
|
672
|
+
instead, which matches on `.` segments so `Newtonsoft` denies `Newtonsoft.Json`
|
|
673
|
+
but never `NewtonsoftShim`. This is architecture enforcement, not a full MSBuild
|
|
674
|
+
or NuGet restore graph.
|
|
675
|
+
|
|
676
|
+
Comment budget rules apply to C# too, where `///` XML doc comments count as
|
|
677
|
+
doc-comments alongside `/** */`.
|
|
678
|
+
|
|
632
679
|
## Built-in Rules
|
|
633
680
|
|
|
634
681
|
| Rule | Type-aware | Description |
|
package/core/config.schema.ts
CHANGED
|
@@ -86,7 +86,7 @@ const ArchImportRuleSchema = z
|
|
|
86
86
|
"Allowlist of layer name(s) / glob(s) the source may import from. Anything not matching `allow` is denied."
|
|
87
87
|
),
|
|
88
88
|
"deny-packages": StringOrStringArray.optional().describe(
|
|
89
|
-
"Package specifier(s) the source is not allowed to import — npm packages, `node:` builtins, Python pip packages and stdlib modules, Swift system frameworks,
|
|
89
|
+
"Package specifier(s) the source is not allowed to import — npm packages, `node:` builtins, Python pip packages and stdlib modules, Swift system frameworks, external Rust crates, and C# namespaces or NuGet packages, which `deny`/`allow` cannot reach because they never resolve to a project file. Matching is per segment: `/` in TypeScript/JavaScript, so `next` also covers `next/headers` while `nextra` is unaffected; `.` in Python, Swift, and C#, so `os` also covers `os.path` while `oscrypto` is unaffected; and `::` in Rust, so `tokio` also covers `tokio::sync::Mutex` while `tokio_util` is unaffected. Python, Swift, Rust, and C# sources are checked by the Rust engine."
|
|
90
90
|
),
|
|
91
91
|
"type-only": z
|
|
92
92
|
.literal("allow")
|
|
@@ -244,7 +244,7 @@ const CountDocCommentsSchema = z
|
|
|
244
244
|
.boolean()
|
|
245
245
|
.optional()
|
|
246
246
|
.describe(
|
|
247
|
-
"Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit."
|
|
247
|
+
"Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift and C#), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit."
|
|
248
248
|
);
|
|
249
249
|
|
|
250
250
|
const CommentIgnoreSchema = StringOrStringArray.optional().describe(
|
package/klint.schema.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
-
"$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v0.
|
|
3
|
+
"$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v0.32.0/klint.schema.json",
|
|
4
4
|
"type": "object",
|
|
5
5
|
"properties": {
|
|
6
6
|
"$schema": {
|
|
@@ -819,7 +819,7 @@
|
|
|
819
819
|
]
|
|
820
820
|
},
|
|
821
821
|
"deny-packages": {
|
|
822
|
-
"description": "Package specifier(s) the source is not allowed to import — npm packages, `node:` builtins, Python pip packages and stdlib modules, Swift system frameworks,
|
|
822
|
+
"description": "Package specifier(s) the source is not allowed to import — npm packages, `node:` builtins, Python pip packages and stdlib modules, Swift system frameworks, external Rust crates, and C# namespaces or NuGet packages, which `deny`/`allow` cannot reach because they never resolve to a project file. Matching is per segment: `/` in TypeScript/JavaScript, so `next` also covers `next/headers` while `nextra` is unaffected; `.` in Python, Swift, and C#, so `os` also covers `os.path` while `oscrypto` is unaffected; and `::` in Rust, so `tokio` also covers `tokio::sync::Mutex` while `tokio_util` is unaffected. Python, Swift, Rust, and C# sources are checked by the Rust engine.",
|
|
823
823
|
"anyOf": [
|
|
824
824
|
{
|
|
825
825
|
"type": "string"
|
|
@@ -1141,7 +1141,7 @@
|
|
|
1141
1141
|
"description": "Maximum percentage of a file's physical lines that may be comment lines. Denominator is total physical lines (code + comments + blanks), the same count `maxLines` uses. A file above this ratio is a violation."
|
|
1142
1142
|
},
|
|
1143
1143
|
"countDocComments": {
|
|
1144
|
-
"description": "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit.",
|
|
1144
|
+
"description": "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift and C#), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit.",
|
|
1145
1145
|
"type": "boolean"
|
|
1146
1146
|
},
|
|
1147
1147
|
"ignore": {
|
|
@@ -1210,7 +1210,7 @@
|
|
|
1210
1210
|
"description": "Maximum number of consecutive comment lines allowed in a single block. A run of more comment lines than this — e.g. a tall comment stacked above a statement — is a violation, reported at the first offending line."
|
|
1211
1211
|
},
|
|
1212
1212
|
"countDocComments": {
|
|
1213
|
-
"description": "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit.",
|
|
1213
|
+
"description": "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift and C#), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on Python: docstrings are string expressions rather than comments, so they never count toward either limit.",
|
|
1214
1214
|
"type": "boolean"
|
|
1215
1215
|
},
|
|
1216
1216
|
"ignore": {
|
package/klint.schema.yaml
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
$schema: http://json-schema.org/draft-07/schema#
|
|
2
|
-
$id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v0.
|
|
2
|
+
$id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v0.32.0/klint.schema.json
|
|
3
3
|
type: object
|
|
4
4
|
properties:
|
|
5
5
|
$schema:
|
|
@@ -596,12 +596,12 @@ properties:
|
|
|
596
596
|
type: string
|
|
597
597
|
deny-packages:
|
|
598
598
|
description: "Package specifier(s) the source is not allowed to import — npm packages, `node:` builtins, Python pip
|
|
599
|
-
packages and stdlib modules, Swift system frameworks,
|
|
600
|
-
cannot reach because they never resolve to a project file. Matching is
|
|
601
|
-
TypeScript/JavaScript, so `next` also covers `next/headers` while `nextra` is
|
|
602
|
-
|
|
603
|
-
also covers `tokio::sync::Mutex` while `tokio_util` is unaffected. Python,
|
|
604
|
-
checked by the Rust engine."
|
|
599
|
+
packages and stdlib modules, Swift system frameworks, external Rust crates, and C# namespaces or NuGet
|
|
600
|
+
packages, which `deny`/`allow` cannot reach because they never resolve to a project file. Matching is
|
|
601
|
+
per segment: `/` in TypeScript/JavaScript, so `next` also covers `next/headers` while `nextra` is
|
|
602
|
+
unaffected; `.` in Python, Swift, and C#, so `os` also covers `os.path` while `oscrypto` is unaffected;
|
|
603
|
+
and `::` in Rust, so `tokio` also covers `tokio::sync::Mutex` while `tokio_util` is unaffected. Python,
|
|
604
|
+
Swift, Rust, and C# sources are checked by the Rust engine."
|
|
605
605
|
anyOf:
|
|
606
606
|
- type: string
|
|
607
607
|
- type: array
|
|
@@ -880,10 +880,11 @@ properties:
|
|
|
880
880
|
lines (code + comments + blanks), the same count `maxLines` uses. A file above this ratio is a
|
|
881
881
|
violation.
|
|
882
882
|
countDocComments:
|
|
883
|
-
description: "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift
|
|
884
|
-
`///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to
|
|
885
|
-
so documentation is exempt and only explanatory/inline comments are capped. Has no effect on
|
|
886
|
-
docstrings are string expressions rather than comments, so they never count toward either
|
|
883
|
+
description: "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift and
|
|
884
|
+
C#), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to
|
|
885
|
+
false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on
|
|
886
|
+
Python: docstrings are string expressions rather than comments, so they never count toward either
|
|
887
|
+
limit."
|
|
887
888
|
type: boolean
|
|
888
889
|
ignore:
|
|
889
890
|
description: Comment lines matching these patterns are structural, not prose — marker comments a build or codegen step
|
|
@@ -947,10 +948,11 @@ properties:
|
|
|
947
948
|
this — e.g. a tall comment stacked above a statement — is a violation, reported at the first offending
|
|
948
949
|
line.
|
|
949
950
|
countDocComments:
|
|
950
|
-
description: "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift
|
|
951
|
-
`///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to
|
|
952
|
-
so documentation is exempt and only explanatory/inline comments are capped. Has no effect on
|
|
953
|
-
docstrings are string expressions rather than comments, so they never count toward either
|
|
951
|
+
description: "Count doc-comments toward the limit. Doc-comments are `/** … */` JSDoc blocks (TS/JS), `///` (Swift and
|
|
952
|
+
C#), and `///` or `//!` (Rust); ordinary `//`, `/* */`, and `#` comments are always counted. Defaults to
|
|
953
|
+
false, so documentation is exempt and only explanatory/inline comments are capped. Has no effect on
|
|
954
|
+
Python: docstrings are string expressions rather than comments, so they never count toward either
|
|
955
|
+
limit."
|
|
954
956
|
type: boolean
|
|
955
957
|
ignore:
|
|
956
958
|
description: Comment lines matching these patterns are structural, not prose — marker comments a build or codegen step
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@konvert7/klint",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.32.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": {
|
|
@@ -67,10 +67,10 @@
|
|
|
67
67
|
"zod": "^4.4.3"
|
|
68
68
|
},
|
|
69
69
|
"optionalDependencies": {
|
|
70
|
-
"@konvert7/klint-darwin-arm64": "0.
|
|
71
|
-
"@konvert7/klint-darwin-x64": "0.
|
|
72
|
-
"@konvert7/klint-linux-x64": "0.
|
|
73
|
-
"@konvert7/klint-win32-x64": "0.
|
|
70
|
+
"@konvert7/klint-darwin-arm64": "0.32.0",
|
|
71
|
+
"@konvert7/klint-darwin-x64": "0.32.0",
|
|
72
|
+
"@konvert7/klint-linux-x64": "0.32.0",
|
|
73
|
+
"@konvert7/klint-win32-x64": "0.32.0"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"@biomejs/biome": "2.4.7",
|