@kernlang/review 3.1.9 → 3.3.4

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.
Files changed (94) hide show
  1. package/dist/cache.js +143 -2
  2. package/dist/cache.js.map +1 -1
  3. package/dist/call-graph.d.ts +4 -1
  4. package/dist/call-graph.js +290 -25
  5. package/dist/call-graph.js.map +1 -1
  6. package/dist/external-tools.d.ts +23 -4
  7. package/dist/external-tools.js +68 -12
  8. package/dist/external-tools.js.map +1 -1
  9. package/dist/file-context.d.ts +6 -0
  10. package/dist/file-context.js +6 -1
  11. package/dist/file-context.js.map +1 -1
  12. package/dist/graph.js +149 -39
  13. package/dist/graph.js.map +1 -1
  14. package/dist/index.d.ts +27 -3
  15. package/dist/index.js +254 -41
  16. package/dist/index.js.map +1 -1
  17. package/dist/inferrer.d.ts +5 -0
  18. package/dist/inferrer.js +1 -1
  19. package/dist/inferrer.js.map +1 -1
  20. package/dist/mappers/ts-concepts.js +31 -6
  21. package/dist/mappers/ts-concepts.js.map +1 -1
  22. package/dist/public-api.d.ts +73 -0
  23. package/dist/public-api.js +351 -0
  24. package/dist/public-api.js.map +1 -0
  25. package/dist/reporter.d.ts +5 -0
  26. package/dist/reporter.js +119 -84
  27. package/dist/reporter.js.map +1 -1
  28. package/dist/review-health.d.ts +38 -0
  29. package/dist/review-health.js +60 -0
  30. package/dist/review-health.js.map +1 -0
  31. package/dist/rules/a11y.d.ts +10 -0
  32. package/dist/rules/a11y.js +294 -0
  33. package/dist/rules/a11y.js.map +1 -0
  34. package/dist/rules/async.d.ts +8 -0
  35. package/dist/rules/async.js +142 -0
  36. package/dist/rules/async.js.map +1 -0
  37. package/dist/rules/base.js +112 -87
  38. package/dist/rules/base.js.map +1 -1
  39. package/dist/rules/confidence.d.ts +2 -2
  40. package/dist/rules/confidence.js +32 -15
  41. package/dist/rules/confidence.js.map +1 -1
  42. package/dist/rules/dead-code.d.ts +2 -1
  43. package/dist/rules/dead-code.js +49 -3
  44. package/dist/rules/dead-code.js.map +1 -1
  45. package/dist/rules/index.d.ts +12 -0
  46. package/dist/rules/index.js +414 -4
  47. package/dist/rules/index.js.map +1 -1
  48. package/dist/rules/ink.js +41 -0
  49. package/dist/rules/ink.js.map +1 -1
  50. package/dist/rules/kern-source-cross-file.d.ts +2 -0
  51. package/dist/rules/kern-source-cross-file.js +102 -0
  52. package/dist/rules/kern-source-cross-file.js.map +1 -0
  53. package/dist/rules/kern-source.js +145 -18
  54. package/dist/rules/kern-source.js.map +1 -1
  55. package/dist/rules/nextjs-app-router.d.ts +11 -0
  56. package/dist/rules/nextjs-app-router.js +1182 -0
  57. package/dist/rules/nextjs-app-router.js.map +1 -0
  58. package/dist/rules/nextjs.js +266 -7
  59. package/dist/rules/nextjs.js.map +1 -1
  60. package/dist/rules/perf.d.ts +11 -0
  61. package/dist/rules/perf.js +131 -0
  62. package/dist/rules/perf.js.map +1 -0
  63. package/dist/rules/react-composition.d.ts +12 -0
  64. package/dist/rules/react-composition.js +741 -0
  65. package/dist/rules/react-composition.js.map +1 -0
  66. package/dist/rules/react-hooks.d.ts +11 -0
  67. package/dist/rules/react-hooks.js +429 -0
  68. package/dist/rules/react-hooks.js.map +1 -0
  69. package/dist/rules/react.js +265 -49
  70. package/dist/rules/react.js.map +1 -1
  71. package/dist/rules/security-v5.d.ts +11 -0
  72. package/dist/rules/security-v5.js +200 -0
  73. package/dist/rules/security-v5.js.map +1 -0
  74. package/dist/rules/utils.d.ts +52 -1
  75. package/dist/rules/utils.js +159 -0
  76. package/dist/rules/utils.js.map +1 -1
  77. package/dist/semantic-diff.js +1 -1
  78. package/dist/semantic-diff.js.map +1 -1
  79. package/dist/taint-ast.js +260 -10
  80. package/dist/taint-ast.js.map +1 -1
  81. package/dist/taint-crossfile.d.ts +30 -2
  82. package/dist/taint-crossfile.js +280 -59
  83. package/dist/taint-crossfile.js.map +1 -1
  84. package/dist/taint-findings.js +3 -0
  85. package/dist/taint-findings.js.map +1 -1
  86. package/dist/taint-types.d.ts +4 -3
  87. package/dist/taint-types.js +70 -6
  88. package/dist/taint-types.js.map +1 -1
  89. package/dist/taint.d.ts +1 -1
  90. package/dist/taint.js +1 -1
  91. package/dist/taint.js.map +1 -1
  92. package/dist/types.d.ts +98 -0
  93. package/dist/types.js.map +1 -1
  94. package/package.json +3 -3
package/dist/taint.js CHANGED
@@ -14,7 +14,7 @@ export { analyzeTaintRegex, buildPaths, classifyParams, detectSanitizers, extrac
14
14
  // ── Finding Generation ──────────────────────────────────────────────────
15
15
  export { crossFileTaintToFindings, taintToFindings } from './taint-findings.js';
16
16
  // ── Cross-File Analysis ─────────────────────────────────────────────────
17
- export { analyzeTaintCrossFile, buildExportMap, buildImportMap } from './taint-crossfile.js';
17
+ export { analyzeTaintCrossFile, buildExportMap, buildExportMapFromGraph, buildImportAliasMap, buildImportMap, buildImportMapFromGraph, } from './taint-crossfile.js';
18
18
  // ── Main Entry Point ────────────────────────────────────────────────────
19
19
  /**
20
20
  * Run taint analysis on all fn nodes in inferred results.
package/dist/taint.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"taint.js","sourceRoot":"","sources":["../src/taint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAiBrD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,2EAA2E;AAE3E,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,2EAA2E;AAE3E,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,2EAA2E;AAE3E,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEhF,2EAA2E;AAE3E,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAE7F,2EAA2E;AAE3E;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB,EAAE,QAAgB,EAAE,UAAuB;IAC7F,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/C,CAAC"}
1
+ {"version":3,"file":"taint.js","sourceRoot":"","sources":["../src/taint.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAiBrD,OAAO,EACL,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,kBAAkB,EAClB,UAAU,EACV,aAAa,EACb,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,2EAA2E;AAE3E,OAAO,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAEvE,2EAA2E;AAE3E,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,cAAc,EACd,gBAAgB,EAChB,qBAAqB,EACrB,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,2EAA2E;AAE3E,OAAO,EAAE,wBAAwB,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEhF,2EAA2E;AAE3E,OAAO,EACL,qBAAqB,EACrB,cAAc,EACd,uBAAuB,EACvB,mBAAmB,EACnB,cAAc,EACd,uBAAuB,GACxB,MAAM,sBAAsB,CAAC;AAE9B,2EAA2E;AAE3E;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,QAAuB,EAAE,QAAgB,EAAE,UAAuB;IAC7F,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,eAAe,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IACzD,CAAC;IACD,OAAO,iBAAiB,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC/C,CAAC"}
package/dist/types.d.ts CHANGED
@@ -32,6 +32,24 @@ export interface FixAction {
32
32
  replacement: string;
33
33
  description: string;
34
34
  }
35
+ /** Single hop in an evidence chain — where a finding came from */
36
+ export interface ProvenanceStep {
37
+ /** What this step represents — source, sanitizer, boundary, sink, etc. */
38
+ kind: 'source' | 'sanitizer' | 'boundary' | 'sink' | 'import' | 'call';
39
+ /** File + location of this step */
40
+ location: SourceSpan;
41
+ /** Short human-readable label (e.g., "req.body", "fetch(url)", "use client") */
42
+ label: string;
43
+ /** Optional longer explanation rendered in the "why this fired" tooltip */
44
+ detail?: string;
45
+ }
46
+ /** Evidence chain: ordered steps from root cause to the reported sink */
47
+ export interface ProvenanceChain {
48
+ /** Ordered steps from source → sink */
49
+ steps: ProvenanceStep[];
50
+ /** Optional one-line summary shown before expanding the chain */
51
+ summary?: string;
52
+ }
35
53
  /** Unified finding from any review layer */
36
54
  export interface ReviewFinding {
37
55
  /** Which layer produced this finding */
@@ -62,6 +80,8 @@ export interface ReviewFinding {
62
80
  origin?: 'changed' | 'upstream';
63
81
  /** Distance from nearest entry file (0 = entry, 1 = direct import, etc.) */
64
82
  distance?: number;
83
+ /** Evidence chain explaining WHY the finding fired (taint path, boundary walk, etc.) */
84
+ provenance?: ProvenanceChain;
65
85
  }
66
86
  /** Confidence level for an inference match */
67
87
  export type Confidence = 'high' | 'medium' | 'low';
@@ -111,6 +131,42 @@ export interface TemplateMatch {
111
131
  /** Original TS tokens covered by this match */
112
132
  tsTokens?: number;
113
133
  }
134
+ /**
135
+ * Which analysis subsystem an entry concerns. Kept stable — reporters and downstream
136
+ * consumers pattern-match on these strings.
137
+ */
138
+ export type ReviewHealthSubsystem = 'eslint' | 'tsc' | 'call-graph' | 'fs-project' | 'rule-loader' | 'concept-extraction';
139
+ /**
140
+ * What happened to a subsystem during the review.
141
+ * skipped — subsystem was not available and was cleanly skipped (e.g. optional peer dep missing)
142
+ * fallback — subsystem partially ran but had to degrade (e.g. fs project fell back to in-memory)
143
+ * error — subsystem failed outright; its findings are missing from this report
144
+ */
145
+ export type ReviewHealthKind = 'skipped' | 'fallback' | 'error';
146
+ /** A single note about a subsystem that didn't run at full fidelity. */
147
+ export interface ReviewHealthEntry {
148
+ subsystem: ReviewHealthSubsystem;
149
+ kind: ReviewHealthKind;
150
+ /** Human-readable note — rendered in the report header */
151
+ message: string;
152
+ /** Error detail; only populated when KERN_DEBUG is set or the caller opts in */
153
+ detail?: string;
154
+ }
155
+ /**
156
+ * Aggregate subsystem status for a review. Present only when something degraded analysis —
157
+ * a clean run leaves this undefined so consumers that check for its presence can treat
158
+ * "no health field" as "all subsystems ran clean." Does NOT affect CI exit codes: `status`
159
+ * is observability, not gatekeeping.
160
+ */
161
+ export interface ReviewHealth {
162
+ /**
163
+ * ok — all subsystems ran clean (this case is normally represented by omitting the field entirely)
164
+ * degraded — one or more subsystems fell back or were skipped; findings are still trustworthy within scope
165
+ * partial — one or more subsystems failed outright; findings may be incomplete
166
+ */
167
+ status: 'ok' | 'degraded' | 'partial';
168
+ entries: ReviewHealthEntry[];
169
+ }
114
170
  /** Full review report for a single file */
115
171
  export interface ReviewReport {
116
172
  /** File path that was reviewed */
@@ -121,6 +177,8 @@ export interface ReviewReport {
121
177
  templateMatches: TemplateMatch[];
122
178
  /** All findings from every review layer (unified) */
123
179
  findings: ReviewFinding[];
180
+ /** Findings removed by inline/config suppression, preserved for SARIF and audit output */
181
+ suppressedFindings?: ReviewFinding[];
124
182
  /** Summary stats */
125
183
  stats: ReviewStats;
126
184
  /** Cross-file taint results (present when graph-aware review detects cross-module taint) */
@@ -133,6 +191,13 @@ export interface ReviewReport {
133
191
  obligations?: import('./obligations.js').ProofObligation[];
134
192
  /** Semantic changes between old and new versions (present in --diff mode) */
135
193
  semanticChanges?: import('./semantic-diff.js').SemanticChange[];
194
+ /** True when the reviewed file is codegen output (path matches /generated/ | /__generated__/ or has @generated header). */
195
+ generated?: boolean;
196
+ /**
197
+ * Subsystem status — present only when something degraded analysis. Does NOT count
198
+ * toward findings-based CI gates; reporters surface it as a banner. See ReviewHealth.
199
+ */
200
+ health?: ReviewHealth;
136
201
  }
137
202
  /** Summary statistics for a review */
138
203
  export interface ReviewStats {
@@ -187,6 +252,8 @@ export interface ReviewConfig {
187
252
  enforceTemplates?: boolean;
188
253
  /** Maximum cognitive complexity allowed (default: 15) */
189
254
  maxComplexity?: number;
255
+ /** Maximum handler-body line count before handler-size fires (default: 30) */
256
+ maxHandlerLines?: number;
190
257
  /** Maximum errors allowed in CI (default: 0) */
191
258
  maxErrors?: number;
192
259
  /** Maximum warnings allowed in CI (default: undefined - no limit) */
@@ -211,6 +278,19 @@ export interface ReviewConfig {
211
278
  noCache?: boolean;
212
279
  /** Pre-computed file context map from import graph (populated by reviewGraph) */
213
280
  fileContextMap?: Map<string, FileContext>;
281
+ /** Pre-computed file graph map from import graph (populated by reviewGraph) */
282
+ graphFileMap?: Map<string, GraphFile>;
283
+ /** Path to host project's tsconfig.json — loaded into the ts-morph Project so jsx/paths/lib/allowJs match the real build. */
284
+ tsConfigFilePath?: string;
285
+ /** Override what dead-export treats as intentional public API. */
286
+ publicApi?: {
287
+ /** Absolute or projectRoot-relative paths whose exports are all public. */
288
+ files?: string[];
289
+ /** Per-symbol overrides in `path#name` form. */
290
+ symbols?: string[];
291
+ /** Root for resolving relative `files`/`symbols`. Defaults to process.cwd(). */
292
+ projectRoot?: string;
293
+ };
214
294
  }
215
295
  /** Runtime boundary determined by position in the import tree */
216
296
  export type RuntimeBoundary = 'server' | 'client' | 'api' | 'middleware' | 'shared' | 'unknown';
@@ -249,12 +329,27 @@ export interface RuleContext {
249
329
  }
250
330
  /** A review rule function */
251
331
  export type ReviewRule = (ctx: RuleContext) => ReviewFinding[];
332
+ export type GraphEdgeKind = 'side-effect-import' | 'default-import' | 'named-import' | 'namespace-import' | 'named-reexport' | 'export-all';
333
+ export interface GraphEdge {
334
+ from: string;
335
+ to: string;
336
+ specifier: string;
337
+ kind: GraphEdgeKind;
338
+ /** Exported symbol name, when known. */
339
+ importedName?: string;
340
+ /** Local bound name in the importing file, when applicable. */
341
+ localName?: string;
342
+ /** How the module resolution succeeded. */
343
+ via: 'ts-morph' | 'extension-fallback';
344
+ }
252
345
  /** A file node in the import graph */
253
346
  export interface GraphFile {
254
347
  path: string;
255
348
  distance: number;
256
349
  imports: string[];
257
350
  importedBy: string[];
351
+ importEdges: GraphEdge[];
352
+ incomingEdges: GraphEdge[];
258
353
  }
259
354
  /** Result of resolving the import graph */
260
355
  export interface GraphResult {
@@ -262,6 +357,9 @@ export interface GraphResult {
262
357
  entryFiles: string[];
263
358
  totalFiles: number;
264
359
  skipped: number;
360
+ /** ts-morph Project used to resolve the graph. Exposed so downstream
361
+ * analyses (call graph, cross-file taint) can reuse it without re-parsing. */
362
+ project?: import('ts-morph').Project;
265
363
  }
266
364
  /** Options for resolveImportGraph */
267
365
  export interface GraphOptions {
package/dist/types.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA8SH,4EAA4E;AAE5E;sEACsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,SAAiB,EAAE,QAAgB;IACnF,OAAO,GAAG,MAAM,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;AAC9C,CAAC"}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAsaH,4EAA4E;AAE5E;sEACsE;AACtE,MAAM,UAAU,iBAAiB,CAAC,MAAc,EAAE,SAAiB,EAAE,QAAgB;IACnF,OAAO,GAAG,MAAM,IAAI,SAAS,IAAI,QAAQ,EAAE,CAAC;AAC9C,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kernlang/review",
3
- "version": "3.1.9",
3
+ "version": "3.3.4",
4
4
  "description": "Kern Review — scan TS, infer .kern IR, roundtrip diff, report",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -25,8 +25,8 @@
25
25
  ],
26
26
  "license": "AGPL-3.0",
27
27
  "dependencies": {
28
- "ts-morph": "^27.0.0",
29
- "@kernlang/core": "3.1.9"
28
+ "ts-morph": "^28.0.0",
29
+ "@kernlang/core": "3.3.4"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "tsc -b",