@konvert7/klint 1.5.3 → 1.7.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
@@ -936,6 +936,75 @@ rules:
936
936
  | `sonar/no-single-char-class` | Avoid regex character classes with a single character |
937
937
  | `sonar/prefer-at` | Prefer `.at()` for relative index access |
938
938
 
939
+ ## Experimental rules (`rules.experimental`)
940
+
941
+ Rules under trial live under `rules.experimental`:
942
+
943
+ ```yaml
944
+ rules:
945
+ recommended: true
946
+ experimental:
947
+ no-date-equality: error
948
+ no-floating-promise: warn
949
+ ```
950
+
951
+ - **Opt-in.** A rule runs only when it is listed under `rules.experimental` with `error`, `warn`, or `{severity, include}`. `recommended: true` never enables one.
952
+ - **Wrong group.** An experimental rule listed under `rules.core` or `rules.sonar`, or a core or sonar rule listed under `rules.experimental`, gives one `klint/config` warning and is ignored.
953
+ - **Plain ids.** Ids have no `experimental/` prefix in output, `--json`, `.klint/stats.json` and `klint stats`. Ids and suppressions stay the same when a rule is promoted to `core`.
954
+ - **Same-file checks.** These rules use no type information. They stay silent unless the file proves the case, and they have no autofix.
955
+
956
+ ### `no-date-equality`
957
+
958
+ Reports `==`, `===`, `!=` and `!==` when both operands are provably `Date` objects, because these compare identity, not time.
959
+
960
+ Reported:
961
+
962
+ ```ts
963
+ const a = new Date(1);
964
+ const b = new Date(2);
965
+ a === b;
966
+ new Date(1) !== new Date(2);
967
+ ```
968
+
969
+ Not reported:
970
+
971
+ ```ts
972
+ let c = new Date(1);
973
+ c === a; // let binding
974
+ function f(d: Date) { return d === a; } // parameter
975
+ x.created === y.created; // property
976
+ a < b; // relational operator
977
+ a === null; // null comparison
978
+ ```
979
+
980
+ ### `no-floating-promise`
981
+
982
+ Reports an expression statement that drops a promise the file provably created.
983
+
984
+ Reported:
985
+
986
+ ```ts
987
+ async function f() {}
988
+ f();
989
+ new Promise((resolve) => resolve(1));
990
+ Promise.all([]);
991
+ Promise.resolve(1).then((x) => x);
992
+ Promise.resolve(1).finally(() => {});
993
+ ```
994
+
995
+ Not reported:
996
+
997
+ ```ts
998
+ await f();
999
+ return f();
1000
+ void f();
1001
+ const p = f();
1002
+ g(f());
1003
+ f().catch(() => {});
1004
+ f().then((x) => x, () => {});
1005
+ obj.f();
1006
+ ```
1007
+
939
1008
  ## Agent and CI Integration
940
1009
 
941
1010
  Agent hooks should run klint with `--json` so violations are machine-readable, and with `--hook` so [`klint stats`](#stats) can tell hook runs apart from direct ones.
package/klint.schema.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.5.3/klint.schema.json",
2
+ "$id": "https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.7.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.",
@@ -1205,6 +1205,133 @@
1205
1205
  },
1206
1206
  "type": "object"
1207
1207
  },
1208
+ "experimental": {
1209
+ "additionalProperties": {
1210
+ "anyOf": [
1211
+ {
1212
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1213
+ "enum": [
1214
+ "error",
1215
+ "warn",
1216
+ "off"
1217
+ ],
1218
+ "type": "string"
1219
+ },
1220
+ {
1221
+ "additionalProperties": false,
1222
+ "description": "Rule options object. Omit severity to default to \"error\". Add include to scope the rule to specific files.",
1223
+ "properties": {
1224
+ "include": {
1225
+ "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
1226
+ "items": {
1227
+ "type": "string"
1228
+ },
1229
+ "type": "array"
1230
+ },
1231
+ "severity": {
1232
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1233
+ "enum": [
1234
+ "error",
1235
+ "warn",
1236
+ "off",
1237
+ null
1238
+ ],
1239
+ "type": "string"
1240
+ }
1241
+ },
1242
+ "type": "object"
1243
+ }
1244
+ ]
1245
+ },
1246
+ "description": "Opt-in experimental rules: each runs only when listed here with error, warn or {severity, include}. recommended: true never enables them. Rule ids have no prefix, so they stay the same when a rule is promoted to core.",
1247
+ "properties": {
1248
+ "no-date-equality": {
1249
+ "anyOf": [
1250
+ {
1251
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1252
+ "enum": [
1253
+ "error",
1254
+ "warn",
1255
+ "off"
1256
+ ],
1257
+ "type": "string"
1258
+ },
1259
+ {
1260
+ "additionalProperties": false,
1261
+ "description": "Rule options object. Omit severity to default to \"error\". Add include to scope the rule to specific files.",
1262
+ "properties": {
1263
+ "include": {
1264
+ "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
1265
+ "items": {
1266
+ "type": "string"
1267
+ },
1268
+ "type": "array"
1269
+ },
1270
+ "severity": {
1271
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1272
+ "enum": [
1273
+ "error",
1274
+ "warn",
1275
+ "off",
1276
+ null
1277
+ ],
1278
+ "type": "string"
1279
+ }
1280
+ },
1281
+ "type": "object"
1282
+ }
1283
+ ],
1284
+ "description": "Experimental, opt-in: list it under rules.experimental. Flags ==, ===, != and !== between two values the same file proves are Date objects (a new Date(...) or a const initialised with one) — these compare identity, not time. Stays silent unless the file proves both sides are Dates; no autofix.",
1285
+ "examples": [
1286
+ "no-date-equality: error",
1287
+ "no-date-equality:\n severity: warn\n include: [\"src/**\"]"
1288
+ ]
1289
+ },
1290
+ "no-floating-promise": {
1291
+ "anyOf": [
1292
+ {
1293
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1294
+ "enum": [
1295
+ "error",
1296
+ "warn",
1297
+ "off"
1298
+ ],
1299
+ "type": "string"
1300
+ },
1301
+ {
1302
+ "additionalProperties": false,
1303
+ "description": "Rule options object. Omit severity to default to \"error\". Add include to scope the rule to specific files.",
1304
+ "properties": {
1305
+ "include": {
1306
+ "description": "Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: [\"src/hooks/**\", \"!src/hooks/scripts/**\"]",
1307
+ "items": {
1308
+ "type": "string"
1309
+ },
1310
+ "type": "array"
1311
+ },
1312
+ "severity": {
1313
+ "description": "Rule severity. \"error\" exits with code 2; \"warn\" reports but exits 0; \"off\" silences.",
1314
+ "enum": [
1315
+ "error",
1316
+ "warn",
1317
+ "off",
1318
+ null
1319
+ ],
1320
+ "type": "string"
1321
+ }
1322
+ },
1323
+ "type": "object"
1324
+ }
1325
+ ],
1326
+ "description": "Experimental, opt-in: list it under rules.experimental. Flags an expression statement that drops a promise the same file proves it created: a call to a same-file async function, new Promise(...), or Promise.resolve/reject/all/allSettled/race/any(...), optionally followed by .then(onFulfilled) or .finally(...) with no .catch. Stays silent unless the file proves it; no autofix.",
1327
+ "examples": [
1328
+ "no-floating-promise: error",
1329
+ "no-floating-promise: warn"
1330
+ ]
1331
+ }
1332
+ },
1333
+ "type": "object"
1334
+ },
1208
1335
  "recommended": {
1209
1336
  "default": false,
1210
1337
  "description": "true enables the six sonar rules at error, as plugins: [sonar] did.",
@@ -2272,7 +2399,7 @@
2272
2399
  }
2273
2400
  ],
2274
2401
  "default": null,
2275
- "description": "Rules, in groups: recommended (true enables the six sonar rules at error), core (built-in rules) and sonar (sonar rules, without the sonar/ prefix). Example: { \"recommended\": true, \"core\": { \"no-string-match\": \"error\" }, \"sonar\": { \"prefer-at\": \"warn\" } }. The v1 flat map (rule name → severity or options, sonar/ prefixed) is still read; run `klint migrate` to upgrade it."
2402
+ "description": "Rules, in groups: recommended (true enables the six sonar rules at error), core (built-in rules), sonar (sonar rules, without the sonar/ prefix) and experimental (opt-in rules under trial; never enabled by recommended; ids have no prefix). Example: { \"recommended\": true, \"core\": { \"no-string-match\": \"error\" }, \"sonar\": { \"prefer-at\": \"warn\" } }. The v1 flat map (rule name → severity or options, sonar/ prefixed) is still read; run `klint migrate` to upgrade it."
2276
2403
  }
2277
2404
  },
2278
2405
  "type": "object"
package/klint.schema.yaml CHANGED
@@ -1,4 +1,4 @@
1
- $id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.5.3/klint.schema.json
1
+ $id: https://raw.githubusercontent.com/konvert7/klint/refs/tags/v1.7.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.
@@ -876,6 +876,96 @@ properties:
876
876
  examples:
877
877
  - 'no-unguarded-json-parse: error'
878
878
  type: object
879
+ experimental:
880
+ additionalProperties:
881
+ anyOf:
882
+ - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
883
+ enum:
884
+ - error
885
+ - warn
886
+ - off
887
+ type: string
888
+ - additionalProperties: false
889
+ description: Rule options object. Omit severity to default to "error". Add include to scope the rule to specific files.
890
+ properties:
891
+ include:
892
+ description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
893
+ items:
894
+ type: string
895
+ type: array
896
+ severity:
897
+ description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
898
+ enum:
899
+ - error
900
+ - warn
901
+ - off
902
+ - null
903
+ type: string
904
+ type: object
905
+ description: 'Opt-in experimental rules: each runs only when listed here with error, warn or {severity, include}. recommended: true never enables them. Rule ids have no prefix, so they stay the same when a rule is promoted to core.'
906
+ properties:
907
+ no-date-equality:
908
+ anyOf:
909
+ - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
910
+ enum:
911
+ - error
912
+ - warn
913
+ - off
914
+ type: string
915
+ - additionalProperties: false
916
+ description: Rule options object. Omit severity to default to "error". Add include to scope the rule to specific files.
917
+ properties:
918
+ include:
919
+ description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
920
+ items:
921
+ type: string
922
+ type: array
923
+ severity:
924
+ description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
925
+ enum:
926
+ - error
927
+ - warn
928
+ - off
929
+ - null
930
+ type: string
931
+ type: object
932
+ description: 'Experimental, opt-in: list it under rules.experimental. Flags ==, ===, != and !== between two values the same file proves are Date objects (a new Date(...) or a const initialised with one) — these compare identity, not time. Stays silent unless the file proves both sides are Dates; no autofix.'
933
+ examples:
934
+ - 'no-date-equality: error'
935
+ - |-
936
+ no-date-equality:
937
+ severity: warn
938
+ include: ["src/**"]
939
+ no-floating-promise:
940
+ anyOf:
941
+ - description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
942
+ enum:
943
+ - error
944
+ - warn
945
+ - off
946
+ type: string
947
+ - additionalProperties: false
948
+ description: Rule options object. Omit severity to default to "error". Add include to scope the rule to specific files.
949
+ properties:
950
+ include:
951
+ description: 'Glob patterns scoping this rule to a subset of files. Prefix with ! to exclude. Example: ["src/hooks/**", "!src/hooks/scripts/**"]'
952
+ items:
953
+ type: string
954
+ type: array
955
+ severity:
956
+ description: Rule severity. "error" exits with code 2; "warn" reports but exits 0; "off" silences.
957
+ enum:
958
+ - error
959
+ - warn
960
+ - off
961
+ - null
962
+ type: string
963
+ type: object
964
+ description: 'Experimental, opt-in: list it under rules.experimental. Flags an expression statement that drops a promise the same file proves it created: a call to a same-file async function, new Promise(...), or Promise.resolve/reject/all/allSettled/race/any(...), optionally followed by .then(onFulfilled) or .finally(...) with no .catch. Stays silent unless the file proves it; no autofix.'
965
+ examples:
966
+ - 'no-floating-promise: error'
967
+ - 'no-floating-promise: warn'
968
+ type: object
879
969
  recommended:
880
970
  default: false
881
971
  description: 'true enables the six sonar rules at error, as plugins: [sonar] did.'
@@ -1632,5 +1722,5 @@ properties:
1632
1722
  - 'sonar/prefer-string-replaceall: error'
1633
1723
  type: object
1634
1724
  default: null
1635
- description: 'Rules, in groups: recommended (true enables the six sonar rules at error), core (built-in rules) and sonar (sonar rules, without the sonar/ prefix). Example: { "recommended": true, "core": { "no-string-match": "error" }, "sonar": { "prefer-at": "warn" } }. The v1 flat map (rule name → severity or options, sonar/ prefixed) is still read; run `klint migrate` to upgrade it.'
1725
+ description: 'Rules, in groups: recommended (true enables the six sonar rules at error), core (built-in rules), sonar (sonar rules, without the sonar/ prefix) and experimental (opt-in rules under trial; never enabled by recommended; ids have no prefix). Example: { "recommended": true, "core": { "no-string-match": "error" }, "sonar": { "prefer-at": "warn" } }. The v1 flat map (rule name → severity or options, sonar/ prefixed) is still read; run `klint migrate` to upgrade it.'
1636
1726
  type: object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@konvert7/klint",
3
- "version": "1.5.3",
3
+ "version": "1.7.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": {
@@ -46,6 +46,12 @@
46
46
  "knip": "knip-bun",
47
47
  "klint": "cargo run --quiet -p klint-rs --",
48
48
  "jscpd": "jscpd --noTips",
49
+ "madge": "madge --circular --extensions ts --ts-config tsconfig.json tools tests .agents/hooks",
50
+ "lf": "bun tools/check-lf.ts",
51
+ "lf:fix": "bun tools/check-lf.ts --fix",
52
+ "exact-versions": "bun tools/check-exact-versions.ts",
53
+ "lock:check": "bun tools/check-lock.ts",
54
+ "secretlint": "secretlint \"**/*\"",
49
55
  "schema": "cargo run --quiet -p klint-rs --example generate_schema -- $npm_package_version",
50
56
  "lint-staged": "lint-staged",
51
57
  "prepare": "bun .husky/install.mjs"
@@ -53,35 +59,41 @@
53
59
  "lint-staged": {
54
60
  "*.ts": [
55
61
  "bun run check"
62
+ ],
63
+ "{package.json,bun.lock,bunfig.toml,.npmrc,Cargo.toml,Cargo.lock}": [
64
+ "bun run lock:check"
56
65
  ]
57
66
  },
58
67
  "optionalDependencies": {
59
- "@konvert7/klint-darwin-arm64": "1.5.3",
60
- "@konvert7/klint-darwin-x64": "1.5.3",
61
- "@konvert7/klint-linux-arm64": "1.5.3",
62
- "@konvert7/klint-linux-x64": "1.5.3",
63
- "@konvert7/klint-linux-x64-musl": "1.5.3",
64
- "@konvert7/klint-win32-x64": "1.5.3"
68
+ "@konvert7/klint-darwin-arm64": "1.7.0",
69
+ "@konvert7/klint-darwin-x64": "1.7.0",
70
+ "@konvert7/klint-linux-arm64": "1.7.0",
71
+ "@konvert7/klint-linux-x64": "1.7.0",
72
+ "@konvert7/klint-linux-x64-musl": "1.7.0",
73
+ "@konvert7/klint-win32-x64": "1.7.0"
65
74
  },
66
75
  "devDependencies": {
67
76
  "@biomejs/biome": "2.6.5",
68
- "@commitlint/cli": "^20.5.3",
69
- "@commitlint/config-conventional": "^20.5.3",
70
- "@semantic-release/changelog": "^6.0.3",
71
- "@semantic-release/git": "^10.0.1",
72
- "@semantic-release/github": "^12.0.6",
73
- "@types/bun": "latest",
74
- "@types/node": "latest",
77
+ "@commitlint/cli": "20.5.3",
78
+ "@commitlint/config-conventional": "20.5.3",
79
+ "@secretlint/secretlint-rule-preset-recommend": "13.1.0",
80
+ "@semantic-release/changelog": "6.0.3",
81
+ "@semantic-release/git": "10.0.1",
82
+ "@semantic-release/github": "12.0.8",
83
+ "@types/bun": "1.3.14",
84
+ "@types/node": "25.8.0",
75
85
  "@typescript-eslint/parser": "8.72.2",
76
86
  "eslint": "9.39.5",
77
87
  "eslint-plugin-sonarjs": "3.0.5",
78
- "husky": "^9.1.7",
88
+ "husky": "9.1.7",
79
89
  "jscpd": "4.2.3",
80
- "knip": "^6.9.0",
81
- "lint-staged": "^15.5.2",
82
- "semantic-release": "^25.0.3",
83
- "typescript": "^5.9.3",
84
- "yaml": "^2.9.0"
90
+ "knip": "6.14.1",
91
+ "lint-staged": "15.5.2",
92
+ "madge": "8.0.0",
93
+ "secretlint": "13.1.0",
94
+ "semantic-release": "25.0.3",
95
+ "typescript": "5.9.3",
96
+ "yaml": "2.9.0"
85
97
  },
86
98
  "directories": {
87
99
  "test": "tests"
@@ -90,5 +102,10 @@
90
102
  "bugs": {
91
103
  "url": "https://github.com/konvert7/klint/issues"
92
104
  },
93
- "homepage": "https://github.com/konvert7/klint#readme"
105
+ "homepage": "https://klint.dev",
106
+ "overrides": {
107
+ "eslint-plugin-sonarjs": {
108
+ "minimatch": "9.0.7"
109
+ }
110
+ }
94
111
  }