@kernlang/review 2.0.0 → 3.1.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.
Files changed (118) hide show
  1. package/dist/concept-rules/boundary-mutation.d.ts +13 -0
  2. package/dist/concept-rules/boundary-mutation.js +40 -0
  3. package/dist/concept-rules/boundary-mutation.js.map +1 -0
  4. package/dist/concept-rules/ignored-error.d.ts +13 -0
  5. package/dist/concept-rules/ignored-error.js +40 -0
  6. package/dist/concept-rules/ignored-error.js.map +1 -0
  7. package/dist/concept-rules/illegal-dependency.d.ts +13 -0
  8. package/dist/concept-rules/illegal-dependency.js +49 -0
  9. package/dist/concept-rules/illegal-dependency.js.map +1 -0
  10. package/dist/concept-rules/index.d.ts +15 -0
  11. package/dist/concept-rules/index.js +27 -0
  12. package/dist/concept-rules/index.js.map +1 -0
  13. package/dist/concept-rules/unguarded-effect.d.ts +13 -0
  14. package/dist/concept-rules/unguarded-effect.js +58 -0
  15. package/dist/concept-rules/unguarded-effect.js.map +1 -0
  16. package/dist/concept-rules/unrecovered-effect.d.ts +13 -0
  17. package/dist/concept-rules/unrecovered-effect.js +61 -0
  18. package/dist/concept-rules/unrecovered-effect.js.map +1 -0
  19. package/dist/confidence.d.ts +92 -0
  20. package/dist/confidence.js +263 -0
  21. package/dist/confidence.js.map +1 -0
  22. package/dist/differ.js +4 -2
  23. package/dist/differ.js.map +1 -1
  24. package/dist/external-tools.js +7 -3
  25. package/dist/external-tools.js.map +1 -1
  26. package/dist/file-role.d.ts +10 -0
  27. package/dist/file-role.js +80 -0
  28. package/dist/file-role.js.map +1 -0
  29. package/dist/graph.d.ts +11 -0
  30. package/dist/graph.js +152 -0
  31. package/dist/graph.js.map +1 -0
  32. package/dist/index.d.ts +46 -3
  33. package/dist/index.js +313 -27
  34. package/dist/index.js.map +1 -1
  35. package/dist/inferrer.js +123 -25
  36. package/dist/inferrer.js.map +1 -1
  37. package/dist/kern-lint.d.ts +18 -0
  38. package/dist/kern-lint.js +24 -0
  39. package/dist/kern-lint.js.map +1 -0
  40. package/dist/llm-bridge.d.ts +42 -0
  41. package/dist/llm-bridge.js +176 -0
  42. package/dist/llm-bridge.js.map +1 -0
  43. package/dist/llm-review.d.ts +8 -1
  44. package/dist/llm-review.js +20 -7
  45. package/dist/llm-review.js.map +1 -1
  46. package/dist/mappers/ts-concepts.d.ts +9 -0
  47. package/dist/mappers/ts-concepts.js +518 -0
  48. package/dist/mappers/ts-concepts.js.map +1 -0
  49. package/dist/quality-rules.d.ts +3 -3
  50. package/dist/quality-rules.js +3 -11
  51. package/dist/quality-rules.js.map +1 -1
  52. package/dist/reporter.d.ts +19 -3
  53. package/dist/reporter.js +232 -20
  54. package/dist/reporter.js.map +1 -1
  55. package/dist/rules/base.js +167 -15
  56. package/dist/rules/base.js.map +1 -1
  57. package/dist/rules/confidence.d.ts +37 -0
  58. package/dist/rules/confidence.js +159 -0
  59. package/dist/rules/confidence.js.map +1 -0
  60. package/dist/rules/dead-logic.d.ts +13 -0
  61. package/dist/rules/dead-logic.js +393 -0
  62. package/dist/rules/dead-logic.js.map +1 -0
  63. package/dist/rules/express.js +69 -2
  64. package/dist/rules/express.js.map +1 -1
  65. package/dist/rules/ground-layer.d.ts +23 -0
  66. package/dist/rules/ground-layer.js +132 -0
  67. package/dist/rules/ground-layer.js.map +1 -0
  68. package/dist/rules/index.d.ts +1 -1
  69. package/dist/rules/index.js +8 -2
  70. package/dist/rules/index.js.map +1 -1
  71. package/dist/rules/kern-source.d.ts +16 -0
  72. package/dist/rules/kern-source.js +726 -0
  73. package/dist/rules/kern-source.js.map +1 -0
  74. package/dist/rules/nextjs.js +38 -10
  75. package/dist/rules/nextjs.js.map +1 -1
  76. package/dist/rules/null-safety.d.ts +12 -0
  77. package/dist/rules/null-safety.js +123 -0
  78. package/dist/rules/null-safety.js.map +1 -0
  79. package/dist/rules/react.js +64 -1
  80. package/dist/rules/react.js.map +1 -1
  81. package/dist/rules/security-v2.d.ts +12 -0
  82. package/dist/rules/security-v2.js +415 -0
  83. package/dist/rules/security-v2.js.map +1 -0
  84. package/dist/rules/security-v3.d.ts +12 -0
  85. package/dist/rules/security-v3.js +397 -0
  86. package/dist/rules/security-v3.js.map +1 -0
  87. package/dist/rules/security-v4.d.ts +22 -0
  88. package/dist/rules/security-v4.js +688 -0
  89. package/dist/rules/security-v4.js.map +1 -0
  90. package/dist/rules/security.d.ts +12 -0
  91. package/dist/rules/security.js +286 -0
  92. package/dist/rules/security.js.map +1 -0
  93. package/dist/rules/utils.d.ts +7 -0
  94. package/dist/rules/utils.js +21 -0
  95. package/dist/rules/utils.js.map +1 -0
  96. package/dist/rules/vue.js +1 -1
  97. package/dist/rules/vue.js.map +1 -1
  98. package/dist/spec-checker.d.ts +83 -0
  99. package/dist/spec-checker.js +405 -0
  100. package/dist/spec-checker.js.map +1 -0
  101. package/dist/suppression/apply-suppression.d.ts +17 -0
  102. package/dist/suppression/apply-suppression.js +94 -0
  103. package/dist/suppression/apply-suppression.js.map +1 -0
  104. package/dist/suppression/index.d.ts +6 -0
  105. package/dist/suppression/index.js +6 -0
  106. package/dist/suppression/index.js.map +1 -0
  107. package/dist/suppression/parse-directives.d.ts +25 -0
  108. package/dist/suppression/parse-directives.js +161 -0
  109. package/dist/suppression/parse-directives.js.map +1 -0
  110. package/dist/suppression/types.d.ts +32 -0
  111. package/dist/suppression/types.js +5 -0
  112. package/dist/suppression/types.js.map +1 -0
  113. package/dist/taint.d.ts +115 -0
  114. package/dist/taint.js +1052 -0
  115. package/dist/taint.js.map +1 -0
  116. package/dist/types.d.ts +71 -0
  117. package/dist/types.js.map +1 -1
  118. package/package.json +7 -4
@@ -0,0 +1,405 @@
1
+ /**
2
+ * Spec Checker — verifies .kern contracts against TypeScript implementation.
3
+ *
4
+ * The .kern file is a machine-readable security contract. This module
5
+ * cross-checks declared auth, validation, guards, middleware, and error
6
+ * handling against what the TypeScript code actually does.
7
+ *
8
+ * No other tool can do this — .kern IS the spec, and this verifies reality.
9
+ */
10
+ import { readFileSync } from 'fs';
11
+ import { parse } from '@kernlang/core';
12
+ import { createFingerprint } from './types.js';
13
+ // ── Extract spec contracts from .kern ────────────────────────────────────
14
+ export function extractSpecContracts(kernSource, kernFile) {
15
+ const ast = parse(kernSource);
16
+ const contracts = [];
17
+ collectRoutes(ast, contracts, kernFile);
18
+ return contracts;
19
+ }
20
+ function collectRoutes(node, out, kernFile) {
21
+ if (node.type === 'route') {
22
+ const method = String(node.props?.method || 'get').toLowerCase();
23
+ const path = String(node.props?.path || '/');
24
+ const routeKey = `${method.toUpperCase()} ${path}`;
25
+ const contract = {
26
+ method,
27
+ path,
28
+ routeKey,
29
+ guards: [],
30
+ middleware: [],
31
+ errors: [],
32
+ hasHandler: false,
33
+ line: node.loc?.line || 1,
34
+ kernFile,
35
+ };
36
+ // Walk children for auth, validate, guard, middleware, error, handler
37
+ if (node.children) {
38
+ for (const child of node.children) {
39
+ switch (child.type) {
40
+ case 'auth':
41
+ contract.auth = { mode: String(child.props?.mode || 'required') };
42
+ break;
43
+ case 'validate':
44
+ contract.validate = { schema: String(child.props?.schema || '') };
45
+ break;
46
+ case 'guard': {
47
+ const elseVal = child.props?.else;
48
+ contract.guards.push({
49
+ name: String(child.props?.name || 'guard'),
50
+ expr: child.props?.expr ? String(child.props.expr) : undefined,
51
+ elseStatus: typeof elseVal === 'number' ? elseVal : parseInt(String(elseVal || '404'), 10),
52
+ });
53
+ break;
54
+ }
55
+ case 'middleware': {
56
+ const names = [];
57
+ if (child.props?.names && Array.isArray(child.props.names)) {
58
+ names.push(...child.props.names);
59
+ }
60
+ else if (child.props?.name) {
61
+ names.push(String(child.props.name));
62
+ }
63
+ if (names.length > 0) {
64
+ contract.middleware.push({ names });
65
+ }
66
+ break;
67
+ }
68
+ case 'error':
69
+ if (child.props?.status) {
70
+ contract.errors.push({
71
+ status: typeof child.props.status === 'number'
72
+ ? child.props.status
73
+ : parseInt(String(child.props.status), 10),
74
+ message: child.props?.message ? String(child.props.message) : undefined,
75
+ });
76
+ }
77
+ break;
78
+ case 'handler':
79
+ contract.hasHandler = true;
80
+ break;
81
+ }
82
+ }
83
+ }
84
+ out.push(contract);
85
+ }
86
+ // Recurse into ALL children (server, document nodes contain routes)
87
+ if (node.children) {
88
+ for (const child of node.children) {
89
+ collectRoutes(child, out, kernFile);
90
+ }
91
+ }
92
+ }
93
+ // ── Extract implementation routes from .ts ───────────────────────────────
94
+ const ROUTE_REGEX = /\b(app|router|server)\.(get|post|put|delete|patch|head|options)\s*\(\s*(['"`])([^'"`]+)\3/gi;
95
+ export function extractImplRoutes(tsSource, filePath) {
96
+ const routes = [];
97
+ const lines = tsSource.split('\n');
98
+ let match;
99
+ ROUTE_REGEX.lastIndex = 0;
100
+ while ((match = ROUTE_REGEX.exec(tsSource)) !== null) {
101
+ const method = match[2].toLowerCase();
102
+ const path = match[4];
103
+ const routeKey = `${method.toUpperCase()} ${path}`;
104
+ // Find line number
105
+ const beforeMatch = tsSource.slice(0, match.index);
106
+ const startLine = beforeMatch.split('\n').length;
107
+ // Extract middleware args between path and handler
108
+ const afterPath = tsSource.slice(match.index + match[0].length);
109
+ const middlewareArgs = extractMiddlewareArgs(afterPath);
110
+ // Extract handler body
111
+ const handlerBody = extractHandlerBody(afterPath);
112
+ routes.push({
113
+ method,
114
+ path,
115
+ routeKey,
116
+ handlerBody,
117
+ middlewareArgs,
118
+ filePath,
119
+ startLine,
120
+ });
121
+ }
122
+ return routes;
123
+ }
124
+ function extractMiddlewareArgs(afterPath) {
125
+ // After the path string, there are comma-separated middleware names
126
+ // before the final (req, res) => { handler. Extract the identifiers.
127
+ const names = [];
128
+ // Match: , identifier, identifier, ... async? (req
129
+ const argsSection = afterPath.match(/^((?:, ?\w+){0,10}) ?, ?(?:async )?\(/);
130
+ if (!argsSection)
131
+ return names;
132
+ const argsText = argsSection[1];
133
+ const parts = argsText.split(',').map(s => s.trim()).filter(Boolean);
134
+ for (const part of parts) {
135
+ if (/^\w+$/.test(part)) {
136
+ names.push(part);
137
+ }
138
+ }
139
+ return names;
140
+ }
141
+ function extractHandlerBody(afterPath) {
142
+ // Find the handler function body — look for (req, res) => { or function(req, res) {
143
+ const handlerStart = afterPath.search(/(?:async\s*)?\([^)]*\)\s*(?:=>)?\s*\{/);
144
+ if (handlerStart < 0)
145
+ return '';
146
+ const braceStart = afterPath.indexOf('{', handlerStart);
147
+ if (braceStart < 0)
148
+ return '';
149
+ let depth = 1;
150
+ let i = braceStart + 1;
151
+ let inString = null;
152
+ while (i < afterPath.length && depth > 0) {
153
+ const ch = afterPath[i];
154
+ if (inString) {
155
+ if (ch === inString && afterPath[i - 1] !== '\\')
156
+ inString = null;
157
+ else if (ch === '\n' && inString !== '`')
158
+ inString = null; // single/double quotes don't span lines
159
+ }
160
+ else {
161
+ if (ch === '"' || ch === "'" || ch === '`')
162
+ inString = ch;
163
+ else if (ch === '{')
164
+ depth++;
165
+ else if (ch === '}')
166
+ depth--;
167
+ }
168
+ i++;
169
+ }
170
+ return afterPath.slice(braceStart + 1, i - 1).trim();
171
+ }
172
+ // ── Route matching ───────────────────────────────────────────────────────
173
+ function pathsMatch(a, b) {
174
+ const sa = a.split('/').filter(Boolean);
175
+ const sb = b.split('/').filter(Boolean);
176
+ if (sa.length !== sb.length)
177
+ return false;
178
+ return sa.every((seg, i) => {
179
+ const isParamA = seg.startsWith(':');
180
+ const isParamB = sb[i].startsWith(':');
181
+ if (isParamA && isParamB)
182
+ return true;
183
+ if (isParamA || isParamB)
184
+ return false;
185
+ return seg === sb[i];
186
+ });
187
+ }
188
+ export function matchRoutes(specs, impls) {
189
+ const matched = [];
190
+ const usedImpls = new Set();
191
+ for (const spec of specs) {
192
+ // Try exact routeKey match first
193
+ let implIdx = impls.findIndex((impl, i) => !usedImpls.has(i) && impl.routeKey === spec.routeKey);
194
+ // Fallback: fuzzy path match (handles :id vs :userId)
195
+ if (implIdx < 0) {
196
+ implIdx = impls.findIndex((impl, i) => !usedImpls.has(i) &&
197
+ impl.method === spec.method &&
198
+ pathsMatch(impl.path, spec.path));
199
+ }
200
+ if (implIdx >= 0) {
201
+ matched.push({ spec, impl: impls[implIdx] });
202
+ usedImpls.add(implIdx);
203
+ }
204
+ }
205
+ const unmatchedSpecs = specs.filter(s => !matched.some(m => m.spec === s));
206
+ const unmatchedImpls = impls.filter((_, i) => !usedImpls.has(i));
207
+ return { matched, unmatchedSpecs, unmatchedImpls };
208
+ }
209
+ // ── Contract verification ────────────────────────────────────────────────
210
+ const AUTH_MIDDLEWARE = /\b(auth|authenticate|requireAuth|requireLicense|verifyToken|jwtVerify|bearerAuth|isAuthenticated|authMiddleware|passport|requirePro)\b/i;
211
+ const AUTH_BODY = /\breq\.(user|auth)\b|verifyToken\s*\(|authenticate\s*\(|checkAuth\s*\(|requireLicense\b/;
212
+ const VALIDATION_CALL = /\.(parse|safeParse|validate|validateSync)\s?\(/;
213
+ const GUARD_CONDITIONAL = /if\s?\(\s?!?\s?\w+/;
214
+ function checkAuth(spec, impl) {
215
+ if (!spec.auth)
216
+ return null;
217
+ const hasAuthMiddleware = impl.middlewareArgs.some(a => AUTH_MIDDLEWARE.test(a));
218
+ const hasAuthInBody = AUTH_BODY.test(impl.handlerBody);
219
+ if (!hasAuthMiddleware && !hasAuthInBody) {
220
+ return {
221
+ kind: 'spec-auth-missing',
222
+ detail: `.kern declares 'auth ${spec.auth.mode}' on ${spec.routeKey} but no auth middleware or check found in implementation`,
223
+ suggestion: 'Add auth middleware (e.g., requireLicense) to the route handler chain',
224
+ kernFile: spec.kernFile,
225
+ kernLine: spec.line,
226
+ tsFile: impl.filePath,
227
+ tsLine: impl.startLine,
228
+ };
229
+ }
230
+ return null;
231
+ }
232
+ function checkValidate(spec, impl) {
233
+ if (!spec.validate)
234
+ return null;
235
+ const hasValidation = VALIDATION_CALL.test(impl.handlerBody);
236
+ const hasSchemaRef = impl.handlerBody.includes(spec.validate.schema);
237
+ if (!hasValidation) {
238
+ return {
239
+ kind: 'spec-validate-missing',
240
+ detail: `.kern declares 'validate ${spec.validate.schema}' on ${spec.routeKey} but no .parse()/.safeParse() found in handler`,
241
+ suggestion: `Add ${spec.validate.schema}.safeParse(req.body) before processing the request`,
242
+ kernFile: spec.kernFile,
243
+ kernLine: spec.line,
244
+ tsFile: impl.filePath,
245
+ tsLine: impl.startLine,
246
+ };
247
+ }
248
+ return null;
249
+ }
250
+ function checkGuards(spec, impl) {
251
+ const violations = [];
252
+ for (const guard of spec.guards) {
253
+ const hasConditional = GUARD_CONDITIONAL.test(impl.handlerBody);
254
+ const hasStatus = new RegExp(`\\.status\\s*\\(\\s*${guard.elseStatus}\\s*\\)`).test(impl.handlerBody) ||
255
+ new RegExp(`sendStatus\\s*\\(\\s*${guard.elseStatus}\\s*\\)`).test(impl.handlerBody);
256
+ if (!hasConditional || !hasStatus) {
257
+ violations.push({
258
+ kind: 'spec-guard-missing',
259
+ detail: `.kern declares 'guard ${guard.name} else=${guard.elseStatus}' on ${spec.routeKey} but ${!hasConditional ? 'no conditional check' : `no ${guard.elseStatus} response`} found`,
260
+ suggestion: `Add: if (!${guard.name}) return res.status(${guard.elseStatus}).json({ error: '...' })`,
261
+ kernFile: spec.kernFile,
262
+ kernLine: spec.line,
263
+ tsFile: impl.filePath,
264
+ tsLine: impl.startLine,
265
+ });
266
+ }
267
+ }
268
+ return violations;
269
+ }
270
+ function checkMiddleware(spec, impl) {
271
+ const violations = [];
272
+ const implMiddleware = impl.middlewareArgs.join(' ').toLowerCase();
273
+ const bodyLower = impl.handlerBody.toLowerCase();
274
+ for (const mw of spec.middleware) {
275
+ for (const name of mw.names) {
276
+ const nameLower = name.toLowerCase();
277
+ if (!implMiddleware.includes(nameLower) && !bodyLower.includes(nameLower)) {
278
+ violations.push({
279
+ kind: 'spec-middleware-missing',
280
+ detail: `.kern declares 'middleware ${name}' on ${spec.routeKey} but '${name}' not found in route registration or handler`,
281
+ suggestion: `Add ${name} middleware to the route: router.${spec.method}('${spec.path}', ${name}, handler)`,
282
+ kernFile: spec.kernFile,
283
+ kernLine: spec.line,
284
+ tsFile: impl.filePath,
285
+ tsLine: impl.startLine,
286
+ });
287
+ }
288
+ }
289
+ }
290
+ return violations;
291
+ }
292
+ function checkErrors(spec, impl) {
293
+ const violations = [];
294
+ for (const err of spec.errors) {
295
+ // 500 is special — try/catch satisfies it
296
+ if (err.status === 500 && /try\s*\{[\s\S]*?\}\s*catch/.test(impl.handlerBody))
297
+ continue;
298
+ const hasStatus = new RegExp(`\\.status\\s*\\(\\s*${err.status}\\s*\\)`).test(impl.handlerBody) ||
299
+ new RegExp(`sendStatus\\s*\\(\\s*${err.status}\\s*\\)`).test(impl.handlerBody);
300
+ if (!hasStatus) {
301
+ violations.push({
302
+ kind: 'spec-error-unhandled',
303
+ detail: `.kern declares 'error ${err.status}${err.message ? ` "${err.message}"` : ''}' on ${spec.routeKey} but status ${err.status} is never sent`,
304
+ suggestion: `Ensure the handler can respond with res.status(${err.status}).json({ error: '${err.message || 'Error'}' })`,
305
+ kernFile: spec.kernFile,
306
+ kernLine: spec.line,
307
+ tsFile: impl.filePath,
308
+ tsLine: impl.startLine,
309
+ });
310
+ }
311
+ }
312
+ return violations;
313
+ }
314
+ export function verifyRouteContract(spec, impl) {
315
+ return [
316
+ checkAuth(spec, impl),
317
+ checkValidate(spec, impl),
318
+ ...checkGuards(spec, impl),
319
+ ...checkMiddleware(spec, impl),
320
+ ...checkErrors(spec, impl),
321
+ ].filter((v) => v !== null);
322
+ }
323
+ // ── Main entry ───────────────────────────────────────────────────────────
324
+ export function checkSpec(kernSource, kernFile, tsSource, tsFile) {
325
+ const specs = extractSpecContracts(kernSource, kernFile);
326
+ const impls = extractImplRoutes(tsSource, tsFile);
327
+ const { matched, unmatchedSpecs, unmatchedImpls } = matchRoutes(specs, impls);
328
+ const violations = [];
329
+ // Check each matched route
330
+ for (const { spec, impl } of matched) {
331
+ violations.push(...verifyRouteContract(spec, impl));
332
+ }
333
+ // Routes in .kern with no implementation
334
+ for (const spec of unmatchedSpecs) {
335
+ violations.push({
336
+ kind: 'spec-unimplemented',
337
+ detail: `${spec.routeKey} declared in .kern but no matching route handler found in implementation`,
338
+ suggestion: `Implement the ${spec.method.toUpperCase()} ${spec.path} route handler`,
339
+ kernFile: spec.kernFile,
340
+ kernLine: spec.line,
341
+ });
342
+ }
343
+ // Routes in .ts with no .kern declaration
344
+ for (const impl of unmatchedImpls) {
345
+ violations.push({
346
+ kind: 'spec-undeclared',
347
+ detail: `${impl.routeKey} exists in implementation but is not declared in .kern spec — undocumented endpoint`,
348
+ suggestion: `Add to .kern: route ${impl.method.toUpperCase()} ${impl.path}`,
349
+ tsFile: impl.filePath,
350
+ tsLine: impl.startLine,
351
+ });
352
+ }
353
+ return { violations, matched, unmatchedSpecs, unmatchedImpls };
354
+ }
355
+ // ── Finding conversion ───────────────────────────────────────────────────
356
+ const SEVERITY_MAP = {
357
+ 'spec-auth-missing': 'error',
358
+ 'spec-validate-missing': 'warning',
359
+ 'spec-guard-missing': 'warning',
360
+ 'spec-middleware-missing': 'warning',
361
+ 'spec-error-unhandled': 'info',
362
+ 'spec-unimplemented': 'error',
363
+ 'spec-undeclared': 'info',
364
+ };
365
+ export function specViolationsToFindings(result) {
366
+ return result.violations.map(v => {
367
+ const file = v.kernFile || v.tsFile || '';
368
+ const line = v.kernLine || v.tsLine || 1;
369
+ const primarySpan = {
370
+ file,
371
+ startLine: line,
372
+ startCol: 1,
373
+ endLine: line,
374
+ endCol: 1,
375
+ };
376
+ const relatedSpans = [];
377
+ if (v.kernFile && v.tsFile) {
378
+ relatedSpans.push({
379
+ file: v.tsFile,
380
+ startLine: v.tsLine || 1,
381
+ startCol: 1,
382
+ endLine: v.tsLine || 1,
383
+ endCol: 1,
384
+ });
385
+ }
386
+ return {
387
+ source: 'kern',
388
+ ruleId: v.kind,
389
+ severity: SEVERITY_MAP[v.kind],
390
+ category: 'bug',
391
+ message: v.detail,
392
+ primarySpan,
393
+ ...(relatedSpans.length > 0 ? { relatedSpans } : {}),
394
+ suggestion: v.suggestion,
395
+ fingerprint: createFingerprint(v.kind, line, 1),
396
+ };
397
+ });
398
+ }
399
+ // ── File-based entry points ──────────────────────────────────────────────
400
+ export function checkSpecFiles(kernFilePath, tsFilePath) {
401
+ const kernSource = readFileSync(kernFilePath, 'utf-8');
402
+ const tsSource = readFileSync(tsFilePath, 'utf-8');
403
+ return checkSpec(kernSource, kernFilePath, tsSource, tsFilePath);
404
+ }
405
+ //# sourceMappingURL=spec-checker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-checker.js","sourceRoot":"","sources":["../src/spec-checker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Apply suppression directives to findings.
3
+ * Runs after sortAndDedup(), before checkEnforcement().
4
+ */
5
+ import type { ReviewFinding } from '../types.js';
6
+ import type { SuppressionResult, StrictMode } from './types.js';
7
+ import type { ReviewConfig } from '../types.js';
8
+ /**
9
+ * Apply all suppression directives to a set of findings.
10
+ *
11
+ * @param findings - Deduplicated, sorted findings from the pipeline
12
+ * @param source - Source text of the file (for parsing inline directives)
13
+ * @param filePath - File path
14
+ * @param config - ReviewConfig (for disabledRules)
15
+ * @param strict - CI strict mode: false = respect all, 'inline' = ignore inline, 'all' = ignore everything
16
+ */
17
+ export declare function applySuppression(findings: ReviewFinding[], source: string, filePath: string, config?: ReviewConfig, strict?: StrictMode): SuppressionResult;
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Apply suppression directives to findings.
3
+ * Runs after sortAndDedup(), before checkEnforcement().
4
+ */
5
+ import { parseDirectives, configDirectives } from './parse-directives.js';
6
+ function isSuppressed(finding, directive) {
7
+ // Rule ID must match
8
+ if (!directive.ruleIds.includes(finding.ruleId))
9
+ return false;
10
+ // Config-level directives (file='*') apply to all files
11
+ if (directive.file === '*')
12
+ return true;
13
+ // File must match
14
+ if (directive.file !== finding.primarySpan.file)
15
+ return false;
16
+ // File-level: suppress all matching rules in file
17
+ if (directive.type === 'file')
18
+ return true;
19
+ // Line-level: finding must be on the directive's target line
20
+ return finding.primarySpan.startLine === directive.line;
21
+ }
22
+ /**
23
+ * Apply all suppression directives to a set of findings.
24
+ *
25
+ * @param findings - Deduplicated, sorted findings from the pipeline
26
+ * @param source - Source text of the file (for parsing inline directives)
27
+ * @param filePath - File path
28
+ * @param config - ReviewConfig (for disabledRules)
29
+ * @param strict - CI strict mode: false = respect all, 'inline' = ignore inline, 'all' = ignore everything
30
+ */
31
+ export function applySuppression(findings, source, filePath, config, strict = false) {
32
+ // Parse inline directives from source
33
+ const { directives: inlineDirectives, warnings } = parseDirectives(source, filePath);
34
+ // Build config-level directives
35
+ const cfgDirectives = configDirectives(config?.disabledRules ?? []);
36
+ // Determine which directives are active based on strict mode
37
+ let activeDirectives;
38
+ if (strict === 'all') {
39
+ activeDirectives = [];
40
+ }
41
+ else if (strict === 'inline') {
42
+ // Only config-level directives are active
43
+ activeDirectives = cfgDirectives;
44
+ }
45
+ else {
46
+ activeDirectives = [...inlineDirectives, ...cfgDirectives];
47
+ }
48
+ const allDirectives = [...inlineDirectives, ...cfgDirectives];
49
+ // Track which directives matched at least one finding
50
+ const matchedDirectives = new Set();
51
+ const passed = [];
52
+ const suppressed = [];
53
+ for (const finding of findings) {
54
+ const matchingDirective = activeDirectives.find(d => isSuppressed(finding, d));
55
+ if (matchingDirective) {
56
+ matchedDirectives.add(matchingDirective);
57
+ suppressed.push(finding);
58
+ }
59
+ else {
60
+ passed.push(finding);
61
+ }
62
+ }
63
+ // Find unused inline directives (config-level ones are intentionally exempt)
64
+ const unusedDirectives = inlineDirectives.filter(d => !matchedDirectives.has(d));
65
+ // Add warnings from parsing + unused directive warnings
66
+ const allWarnings = [...warnings];
67
+ // Only report unused directives when not in strict mode (in strict, inline directives are intentionally ignored)
68
+ if (!strict) {
69
+ for (const d of unusedDirectives) {
70
+ allWarnings.push({
71
+ source: 'kern',
72
+ ruleId: 'kern-ignore-unused',
73
+ severity: 'warning',
74
+ category: 'style',
75
+ message: `Unused kern-ignore for '${d.ruleIds.join(', ')}' — no matching findings`,
76
+ primarySpan: {
77
+ file: d.file,
78
+ startLine: d.commentLine ?? 1,
79
+ startCol: 1,
80
+ endLine: d.commentLine ?? 1,
81
+ endCol: 1,
82
+ },
83
+ fingerprint: `unused-${d.commentLine}-${d.ruleIds.join(',')}`,
84
+ });
85
+ }
86
+ }
87
+ return {
88
+ findings: [...passed, ...allWarnings],
89
+ suppressed,
90
+ directives: allDirectives,
91
+ unusedDirectives,
92
+ };
93
+ }
94
+ //# sourceMappingURL=apply-suppression.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apply-suppression.js","sourceRoot":"","sources":["../../src/suppression/apply-suppression.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Suppression module — inline comments + config-level rule suppression.
3
+ */
4
+ export type { SuppressionDirective, SuppressionResult, StrictMode } from './types.js';
5
+ export { parseDirectives, configDirectives, isConceptRule } from './parse-directives.js';
6
+ export { applySuppression } from './apply-suppression.js';
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Suppression module — inline comments + config-level rule suppression.
3
+ */
4
+ export { parseDirectives, configDirectives, isConceptRule } from './parse-directives.js';
5
+ export { applySuppression } from './apply-suppression.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/suppression/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Parse kern-ignore directives from source text.
3
+ *
4
+ * Supported syntax:
5
+ * // kern-ignore <rule-id>[, <rule-id>...] — suppress on same or next non-comment line
6
+ * // kern-ignore-file <rule-id>[, <rule-id>...] — suppress for entire file (first 5 lines)
7
+ * # kern-ignore <rule-id>[, <rule-id>...] — Python variant
8
+ * # kern-ignore-file <rule-id>[, <rule-id>...] — Python variant
9
+ */
10
+ import type { SuppressionDirective } from './types.js';
11
+ import type { ReviewFinding } from '../types.js';
12
+ export declare function isConceptRule(ruleId: string): boolean;
13
+ /**
14
+ * Parse all suppression directives from source text.
15
+ * Returns directives + any warnings (e.g., bare kern-ignore, concept rule on line-level).
16
+ */
17
+ export declare function parseDirectives(source: string, filePath: string): {
18
+ directives: SuppressionDirective[];
19
+ warnings: ReviewFinding[];
20
+ };
21
+ /**
22
+ * Create config-level suppression directives from disabledRules.
23
+ * These apply to all files (file field is '*').
24
+ */
25
+ export declare function configDirectives(disabledRules: string[]): SuppressionDirective[];