@rigour-labs/core 6.2.5 → 6.3.1
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 +2 -0
- package/dist/discovery-signals.d.ts +27 -0
- package/dist/discovery-signals.js +96 -0
- package/dist/discovery.d.ts +1 -2
- package/dist/discovery.js +36 -49
- package/dist/discovery.test.js +84 -71
- package/dist/gates/deep-analysis.d.ts +2 -0
- package/dist/gates/deep-analysis.js +5 -1
- package/dist/gates/deep-intent.d.ts +3 -0
- package/dist/gates/deep-intent.js +57 -0
- package/dist/gates/deep-intent.test.d.ts +1 -0
- package/dist/gates/deep-intent.test.js +51 -0
- package/dist/gates/deep-runner.js +1 -0
- package/dist/gates/deprecated-apis-ast.d.ts +8 -0
- package/dist/gates/deprecated-apis-ast.js +25 -0
- package/dist/gates/deprecated-apis-rules-node.js +2 -8
- package/dist/gates/deprecated-apis.js +5 -1
- package/dist/gates/deprecated-apis.test.js +30 -0
- package/dist/gates/frontend-secret-exposure.js +5 -1
- package/dist/gates/frontend-secret-exposure.test.js +20 -0
- package/dist/gates/hallucinated-imports/framework-modules.d.ts +14 -0
- package/dist/gates/hallucinated-imports/framework-modules.js +75 -0
- package/dist/gates/hallucinated-imports/index.js +14 -6
- package/dist/gates/hallucinated-imports/js-resolver.d.ts +16 -12
- package/dist/gates/hallucinated-imports/js-resolver.js +65 -153
- package/dist/gates/hallucinated-imports/ts-path-target.js +16 -0
- package/dist/gates/hallucinated-imports/tsconfig-paths.d.ts +16 -0
- package/dist/gates/hallucinated-imports/tsconfig-paths.js +120 -0
- package/dist/gates/hallucinated-imports-sveltekit.test.d.ts +1 -0
- package/dist/gates/hallucinated-imports-sveltekit.test.js +108 -0
- package/dist/gates/runner.js +5 -0
- package/dist/gates/semantic-bugs.d.ts +23 -0
- package/dist/gates/semantic-bugs.js +48 -0
- package/dist/gates/semantic-bugs.test.d.ts +1 -0
- package/dist/gates/semantic-bugs.test.js +70 -0
- package/dist/gates/side-effect-analysis/index.js +11 -1
- package/dist/gates/side-effect-analysis.test.d.ts +1 -0
- package/dist/gates/side-effect-analysis.test.js +162 -0
- package/dist/gates/side-effect-helpers/pattern-detection.js +35 -7
- package/dist/gates/side-effect-helpers/resource-tracking.js +17 -10
- package/dist/gates/side-effect-helpers/scope-analysis.d.ts +6 -0
- package/dist/gates/side-effect-helpers/scope-analysis.js +20 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.js +4 -1
- package/dist/inference/model-download.test.js +54 -2
- package/dist/inference/model-manager.d.ts +6 -0
- package/dist/inference/model-manager.js +58 -18
- package/dist/inference/sidecar-provider.js +12 -1
- package/dist/inference/types.d.ts +8 -2
- package/dist/inference/types.js +7 -3
- package/dist/semantic/ast.d.ts +29 -0
- package/dist/semantic/ast.js +122 -0
- package/dist/semantic/benchmark.d.ts +16 -0
- package/dist/semantic/benchmark.js +31 -0
- package/dist/semantic/benchmark.test.d.ts +1 -0
- package/dist/semantic/benchmark.test.js +18 -0
- package/dist/semantic/engine.d.ts +8 -0
- package/dist/semantic/engine.js +45 -0
- package/dist/semantic/intent/benchmark.d.ts +31 -0
- package/dist/semantic/intent/benchmark.js +74 -0
- package/dist/semantic/intent/intent-check.d.ts +43 -0
- package/dist/semantic/intent/intent-check.js +72 -0
- package/dist/semantic/intent/intent.test.d.ts +1 -0
- package/dist/semantic/intent/intent.test.js +46 -0
- package/dist/semantic/intent/parallel-reads.d.ts +23 -0
- package/dist/semantic/intent/parallel-reads.js +59 -0
- package/dist/semantic/learn/benchmark.d.ts +20 -0
- package/dist/semantic/learn/benchmark.js +71 -0
- package/dist/semantic/learn/compile.d.ts +4 -0
- package/dist/semantic/learn/compile.js +56 -0
- package/dist/semantic/learn/conditions.d.ts +22 -0
- package/dist/semantic/learn/conditions.js +93 -0
- package/dist/semantic/learn/extract.d.ts +30 -0
- package/dist/semantic/learn/extract.js +122 -0
- package/dist/semantic/learn/git-trees.d.ts +8 -0
- package/dist/semantic/learn/git-trees.js +32 -0
- package/dist/semantic/learn/identity.d.ts +18 -0
- package/dist/semantic/learn/identity.js +97 -0
- package/dist/semantic/learn/learn.d.ts +25 -0
- package/dist/semantic/learn/learn.js +109 -0
- package/dist/semantic/learn/learn.test.d.ts +1 -0
- package/dist/semantic/learn/learn.test.js +67 -0
- package/dist/semantic/learn/store.d.ts +4 -0
- package/dist/semantic/learn/store.js +39 -0
- package/dist/semantic/learn/types.d.ts +468 -0
- package/dist/semantic/learn/types.js +55 -0
- package/dist/semantic/origins.d.ts +42 -0
- package/dist/semantic/origins.js +149 -0
- package/dist/semantic/origins.test.d.ts +1 -0
- package/dist/semantic/origins.test.js +77 -0
- package/dist/semantic/program.d.ts +13 -0
- package/dist/semantic/program.js +62 -0
- package/dist/semantic/rules/credential-redirect.d.ts +2 -0
- package/dist/semantic/rules/credential-redirect.js +209 -0
- package/dist/semantic/rules/degraded-response-cached.d.ts +2 -0
- package/dist/semantic/rules/degraded-response-cached.js +271 -0
- package/dist/semantic/rules/in-memory-aggregation.d.ts +2 -0
- package/dist/semantic/rules/in-memory-aggregation.js +179 -0
- package/dist/semantic/summaries.d.ts +18 -0
- package/dist/semantic/summaries.js +33 -0
- package/dist/semantic/types.d.ts +32 -0
- package/dist/semantic/types.js +1 -0
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.js +1 -0
- package/dist/storage/team-diagnostics.d.ts +22 -0
- package/dist/storage/team-diagnostics.js +58 -0
- package/dist/storage/team-diagnostics.test.d.ts +1 -0
- package/dist/storage/team-diagnostics.test.js +51 -0
- package/dist/storage/team-schema.d.ts +6 -0
- package/dist/storage/team-schema.js +82 -0
- package/dist/storage/team-store.js +25 -72
- package/dist/templates/universal-config.js +4 -0
- package/dist/types/index.d.ts +56 -0
- package/dist/types/index.js +7 -0
- package/package.json +6 -6
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rigour learn`: from a fix (before and after trees) to validated rules.
|
|
3
|
+
*
|
|
4
|
+
* For each supported edit, candidates are tried from most general to most
|
|
5
|
+
* specific. The first one that fires on the code before the fix, is silent on
|
|
6
|
+
* the fixed code, and fires on at most `maxHits` places in the repository is
|
|
7
|
+
* kept. Nothing is kept on a guess: an edit whose candidates all fail is
|
|
8
|
+
* reported with the reason the most specific one failed.
|
|
9
|
+
*/
|
|
10
|
+
import crypto from 'crypto';
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { globby } from 'globby';
|
|
13
|
+
import { analyzeFiles } from '../engine.js';
|
|
14
|
+
import { programBatches, loadProjectConfig } from '../program.js';
|
|
15
|
+
import { compileLearnedRule, LEARNED_PREFIX } from './compile.js';
|
|
16
|
+
import { extractEdits } from './extract.js';
|
|
17
|
+
const DEFAULT_MAX_HITS = 3;
|
|
18
|
+
const SOURCE = /\.(?:[cm]?[jt]s|[jt]sx)$/i;
|
|
19
|
+
const NOT_SOURCE = /\.d\.[cm]?ts$|(?:^|\/)(?:__tests__|__mocks__|tests?)\/|\.(?:test|spec)\.[cm]?[jt]sx?$/;
|
|
20
|
+
export async function learnFromFix(input) {
|
|
21
|
+
const maxHits = input.maxHits ?? DEFAULT_MAX_HITS;
|
|
22
|
+
const files = input.files.filter(f => SOURCE.test(f) && !NOT_SOURCE.test(f));
|
|
23
|
+
const report = { learned: [], rejected: [], unsupported: [] };
|
|
24
|
+
const edits = [];
|
|
25
|
+
for (const file of files) {
|
|
26
|
+
const extraction = extractEdits(file, openTree(input.beforeDir, file), openTree(input.afterDir, file));
|
|
27
|
+
edits.push(...extraction.edits);
|
|
28
|
+
report.unsupported.push(...extraction.unsupported.map(fn => ({ file, fn })));
|
|
29
|
+
}
|
|
30
|
+
if (edits.length === 0)
|
|
31
|
+
return report;
|
|
32
|
+
const candidates = edits.flatMap(edit => edit.candidates.map(pattern => toRule(edit, pattern, input.commit, maxHits)));
|
|
33
|
+
const repoFiles = await sourceFiles(input.repoDir);
|
|
34
|
+
const counts = countFindings(input, candidates, files, repoFiles);
|
|
35
|
+
const seen = new Set();
|
|
36
|
+
for (const edit of edits) {
|
|
37
|
+
const tried = candidates.filter(rule => rule.source.file === edit.file && rule.source.function === edit.fn && edit.candidates.includes(rule.pattern));
|
|
38
|
+
const kept = tried.find(rule => failure(counts.get(rule.id), maxHits) === null);
|
|
39
|
+
if (kept && !seen.has(kept.id)) {
|
|
40
|
+
seen.add(kept.id);
|
|
41
|
+
const { before, after, hits } = counts.get(kept.id);
|
|
42
|
+
report.learned.push({ ...kept, validation: { firesBefore: before, firesAfter: after, maxHits, repoHits: hits } });
|
|
43
|
+
}
|
|
44
|
+
else if (!kept) {
|
|
45
|
+
report.rejected.push({ edit, reason: failure(counts.get(tried[tried.length - 1].id), maxHits) ?? 'no candidate' });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return report;
|
|
49
|
+
}
|
|
50
|
+
function openTree(cwd, file) {
|
|
51
|
+
const root = path.join(cwd, file);
|
|
52
|
+
const [program] = [...programBatches([root], loadProjectConfig(cwd).options)];
|
|
53
|
+
const sourceFile = program.getSourceFile(root);
|
|
54
|
+
if (!sourceFile)
|
|
55
|
+
throw new Error(`Cannot parse ${file} in ${cwd}`);
|
|
56
|
+
return { cwd, checker: program.getTypeChecker(), sourceFile };
|
|
57
|
+
}
|
|
58
|
+
function countFindings(input, rules, files, repoFiles) {
|
|
59
|
+
const compiled = rules.map(compileLearnedRule);
|
|
60
|
+
const tally = (dir, scan) => analyzeFiles(dir, scan, { rules: compiled });
|
|
61
|
+
const byRule = (findings, id) => findings.filter(f => f.rule === `${LEARNED_PREFIX}${id}`);
|
|
62
|
+
const before = tally(input.beforeDir, files);
|
|
63
|
+
const after = tally(input.afterDir, files);
|
|
64
|
+
const repo = tally(input.repoDir, repoFiles);
|
|
65
|
+
return new Map(rules.map(rule => [rule.id, {
|
|
66
|
+
before: byRule(before, rule.id).length,
|
|
67
|
+
after: byRule(after, rule.id).length,
|
|
68
|
+
hits: byRule(repo, rule.id).map(f => `${f.file}:${f.line}`),
|
|
69
|
+
}]));
|
|
70
|
+
}
|
|
71
|
+
function failure(counts, maxHits) {
|
|
72
|
+
if (counts.before === 0)
|
|
73
|
+
return 'does not fire on the code before the fix';
|
|
74
|
+
if (counts.after > 0)
|
|
75
|
+
return `still fires ${counts.after} time(s) on the fixed code`;
|
|
76
|
+
if (counts.hits.length > maxHits)
|
|
77
|
+
return `fires on ${counts.hits.length} places in the repository (max ${maxHits})`;
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
async function sourceFiles(cwd) {
|
|
81
|
+
const files = await globby('**/*.{ts,tsx,js,jsx,mjs,cjs,mts,cts}', {
|
|
82
|
+
cwd, gitignore: true, ignore: ['**/node_modules/**', '**/dist/**', '**/build/**', '**/.next/**', '**/coverage/**'],
|
|
83
|
+
});
|
|
84
|
+
return files.filter(f => !NOT_SOURCE.test(f));
|
|
85
|
+
}
|
|
86
|
+
function toRule(edit, pattern, commit, maxHits) {
|
|
87
|
+
return {
|
|
88
|
+
id: ruleId(pattern),
|
|
89
|
+
version: 1,
|
|
90
|
+
pattern,
|
|
91
|
+
message: messageFor(pattern, edit.file),
|
|
92
|
+
severity: 'medium',
|
|
93
|
+
source: { ...(commit ? { commit } : {}), file: edit.file, function: edit.fn },
|
|
94
|
+
validation: { firesBefore: 0, firesAfter: 0, maxHits, repoHits: [] },
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function messageFor(pattern, file) {
|
|
98
|
+
const callee = pattern.callee.key.split('#').pop();
|
|
99
|
+
if (pattern.template === 'require-option') {
|
|
100
|
+
const value = pattern.value ? ` (e.g. '${pattern.value}')` : '';
|
|
101
|
+
return `${callee}(...) does not set \`${pattern.property}\`${value} in argument ${pattern.argIndex + 1}; a fix in ${file} added it to the same call.`;
|
|
102
|
+
}
|
|
103
|
+
return `\`${pattern.property}\` in ${callee}(...) is not conditional on \`${pattern.guard}\`; a fix in ${file} added that condition.`;
|
|
104
|
+
}
|
|
105
|
+
function ruleId(pattern) {
|
|
106
|
+
const slug = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '').slice(0, 24);
|
|
107
|
+
const hash = crypto.createHash('sha256').update(JSON.stringify(pattern)).digest('hex').slice(0, 8);
|
|
108
|
+
return `${pattern.template}-${slug(pattern.property)}-${hash}`;
|
|
109
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import ts from 'typescript';
|
|
5
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
7
|
+
import { forEachNode } from '../ast.js';
|
|
8
|
+
import { loadLearnCases, runLearnCase } from './benchmark.js';
|
|
9
|
+
import { guardsOf, namesIn, propertiesNamed } from './conditions.js';
|
|
10
|
+
import { functionKeyOf, isInvocation } from './identity.js';
|
|
11
|
+
import { loadLearnedRules, saveLearnedRule } from './store.js';
|
|
12
|
+
const ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '../../../../../benchmarks/learn');
|
|
13
|
+
describe('learn benchmark', () => {
|
|
14
|
+
for (const bench of loadLearnCases(ROOT)) {
|
|
15
|
+
it(`${bench.name}: ${bench.note}`, async () => {
|
|
16
|
+
const result = await runLearnCase(ROOT, bench);
|
|
17
|
+
expect(result.problems).toEqual([]);
|
|
18
|
+
});
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
function parse(text) {
|
|
22
|
+
return ts.createSourceFile('x.ts', text, ts.ScriptTarget.Latest, true);
|
|
23
|
+
}
|
|
24
|
+
function firstCall(sf) {
|
|
25
|
+
let call;
|
|
26
|
+
forEachNode(sf, (n) => { if (!call && isInvocation(n))
|
|
27
|
+
call = n; });
|
|
28
|
+
return call;
|
|
29
|
+
}
|
|
30
|
+
describe('guardsOf', () => {
|
|
31
|
+
it('collects the spread condition and the value condition', () => {
|
|
32
|
+
const sf = parse("h({ ...(ok ? { 'cache-control': fresh ? 'max-age=1' : 'no-store' } : {}) });");
|
|
33
|
+
const [prop] = propertiesNamed(sf, 'cache-control');
|
|
34
|
+
expect(namesIn(guardsOf(prop, firstCall(sf)))).toEqual(['fresh', 'ok']);
|
|
35
|
+
});
|
|
36
|
+
it('lists property names before receivers', () => {
|
|
37
|
+
const sf = parse("h({ c: status === 200 && body.stepsAvailable !== false ? 'a' : 'b' });");
|
|
38
|
+
const [prop] = propertiesNamed(sf, 'c');
|
|
39
|
+
expect(namesIn(guardsOf(prop, firstCall(sf)))[0]).toBe('stepsAvailable');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
42
|
+
describe('functionKeyOf', () => {
|
|
43
|
+
it('names nested arrows, methods and the module level', () => {
|
|
44
|
+
const sf = parse('class A { run() { const inner = () => f(); } }\ng();\n');
|
|
45
|
+
const keys = [];
|
|
46
|
+
forEachNode(sf, (n) => { if (isInvocation(n))
|
|
47
|
+
keys.push(functionKeyOf(n)); });
|
|
48
|
+
expect(keys).toEqual(['A.run>inner', '<module>']);
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
describe('learned rule store', () => {
|
|
52
|
+
let dir;
|
|
53
|
+
afterEach(() => { if (dir)
|
|
54
|
+
fs.rmSync(dir, { recursive: true, force: true }); dir = undefined; });
|
|
55
|
+
it('round-trips a rule and skips files that are not rules', () => {
|
|
56
|
+
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'learned-'));
|
|
57
|
+
const rule = {
|
|
58
|
+
id: 'require-option-redirect-abcd1234', version: 1,
|
|
59
|
+
pattern: { template: 'require-option', callee: { level: 'name', key: 'fetch' }, argIndex: 1, property: 'redirect' },
|
|
60
|
+
message: 'm', severity: 'medium', source: { file: 'http.ts', function: 'post' },
|
|
61
|
+
validation: { firesBefore: 1, firesAfter: 0, maxHits: 3, repoHits: [] },
|
|
62
|
+
};
|
|
63
|
+
saveLearnedRule(dir, rule);
|
|
64
|
+
fs.writeFileSync(path.join(dir, '.rigour', 'rules', 'broken.json'), '{"id": 1}');
|
|
65
|
+
expect(loadLearnedRules(dir)).toEqual([rule]);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Learned rules live in `.rigour/rules/<id>.json`, committed and reviewed
|
|
3
|
+
* like code. A file that does not parse as a rule is skipped with a warning.
|
|
4
|
+
*/
|
|
5
|
+
import fs from 'fs';
|
|
6
|
+
import path from 'path';
|
|
7
|
+
import { Logger } from '../../utils/logger.js';
|
|
8
|
+
import { ZodError } from 'zod';
|
|
9
|
+
import { LearnedRuleSchema } from './types.js';
|
|
10
|
+
export const LEARNED_RULES_DIR = path.join('.rigour', 'rules');
|
|
11
|
+
export function saveLearnedRule(cwd, rule) {
|
|
12
|
+
const dir = path.join(cwd, LEARNED_RULES_DIR);
|
|
13
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
14
|
+
const file = path.join(dir, `${rule.id}.json`);
|
|
15
|
+
fs.writeFileSync(file, `${JSON.stringify(LearnedRuleSchema.parse(rule), null, 2)}\n`);
|
|
16
|
+
return file;
|
|
17
|
+
}
|
|
18
|
+
export function loadLearnedRules(cwd) {
|
|
19
|
+
const dir = path.join(cwd, LEARNED_RULES_DIR);
|
|
20
|
+
if (!fs.existsSync(dir))
|
|
21
|
+
return [];
|
|
22
|
+
const rules = [];
|
|
23
|
+
for (const name of fs.readdirSync(dir).filter(n => n.endsWith('.json')).sort()) {
|
|
24
|
+
try {
|
|
25
|
+
rules.push(LearnedRuleSchema.parse(JSON.parse(fs.readFileSync(path.join(dir, name), 'utf8'))));
|
|
26
|
+
}
|
|
27
|
+
catch (error) {
|
|
28
|
+
Logger.warn(`Skipping ${path.join(LEARNED_RULES_DIR, name)}: not a valid learned rule (${reasonOf(error)})`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return rules;
|
|
32
|
+
}
|
|
33
|
+
function reasonOf(error) {
|
|
34
|
+
if (error instanceof ZodError) {
|
|
35
|
+
const [issue] = error.issues;
|
|
36
|
+
return `${issue.path.join('.') || 'rule'}: ${issue.message}`;
|
|
37
|
+
}
|
|
38
|
+
return error instanceof Error ? error.message : String(error);
|
|
39
|
+
}
|
|
@@ -0,0 +1,468 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rules learned from a fix: a before/after pair turned into a check.
|
|
3
|
+
*
|
|
4
|
+
* A learned rule is data (`.rigour/rules/<id>.json`), reviewed in pull
|
|
5
|
+
* requests like code. It is kept only when it fires on the code before the
|
|
6
|
+
* fix, is silent on the fixed code, and fires on few other places in the
|
|
7
|
+
* repository; the validation that proved this is stored with it.
|
|
8
|
+
*/
|
|
9
|
+
import { z } from 'zod';
|
|
10
|
+
/** How a call is recognised: by its name, the declaration it resolves to, or its exact text. */
|
|
11
|
+
export declare const CalleeMatcherSchema: z.ZodObject<{
|
|
12
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
13
|
+
key: z.ZodString;
|
|
14
|
+
}, "strip", z.ZodTypeAny, {
|
|
15
|
+
key: string;
|
|
16
|
+
level: "name" | "text" | "declaration";
|
|
17
|
+
}, {
|
|
18
|
+
key: string;
|
|
19
|
+
level: "name" | "text" | "declaration";
|
|
20
|
+
}>;
|
|
21
|
+
/** Narrows a rule to one function in one file: a regression guard for the fixed code. */
|
|
22
|
+
export declare const ScopeSchema: z.ZodObject<{
|
|
23
|
+
file: z.ZodString;
|
|
24
|
+
fn: z.ZodString;
|
|
25
|
+
}, "strip", z.ZodTypeAny, {
|
|
26
|
+
file: string;
|
|
27
|
+
fn: string;
|
|
28
|
+
}, {
|
|
29
|
+
file: string;
|
|
30
|
+
fn: string;
|
|
31
|
+
}>;
|
|
32
|
+
export declare const RequireOptionSchema: z.ZodObject<{
|
|
33
|
+
template: z.ZodLiteral<"require-option">;
|
|
34
|
+
callee: z.ZodObject<{
|
|
35
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
36
|
+
key: z.ZodString;
|
|
37
|
+
}, "strip", z.ZodTypeAny, {
|
|
38
|
+
key: string;
|
|
39
|
+
level: "name" | "text" | "declaration";
|
|
40
|
+
}, {
|
|
41
|
+
key: string;
|
|
42
|
+
level: "name" | "text" | "declaration";
|
|
43
|
+
}>;
|
|
44
|
+
argIndex: z.ZodNumber;
|
|
45
|
+
property: z.ZodString;
|
|
46
|
+
value: z.ZodOptional<z.ZodString>;
|
|
47
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
48
|
+
file: z.ZodString;
|
|
49
|
+
fn: z.ZodString;
|
|
50
|
+
}, "strip", z.ZodTypeAny, {
|
|
51
|
+
file: string;
|
|
52
|
+
fn: string;
|
|
53
|
+
}, {
|
|
54
|
+
file: string;
|
|
55
|
+
fn: string;
|
|
56
|
+
}>>;
|
|
57
|
+
}, "strip", z.ZodTypeAny, {
|
|
58
|
+
template: "require-option";
|
|
59
|
+
callee: {
|
|
60
|
+
key: string;
|
|
61
|
+
level: "name" | "text" | "declaration";
|
|
62
|
+
};
|
|
63
|
+
argIndex: number;
|
|
64
|
+
property: string;
|
|
65
|
+
value?: string | undefined;
|
|
66
|
+
scope?: {
|
|
67
|
+
file: string;
|
|
68
|
+
fn: string;
|
|
69
|
+
} | undefined;
|
|
70
|
+
}, {
|
|
71
|
+
template: "require-option";
|
|
72
|
+
callee: {
|
|
73
|
+
key: string;
|
|
74
|
+
level: "name" | "text" | "declaration";
|
|
75
|
+
};
|
|
76
|
+
argIndex: number;
|
|
77
|
+
property: string;
|
|
78
|
+
value?: string | undefined;
|
|
79
|
+
scope?: {
|
|
80
|
+
file: string;
|
|
81
|
+
fn: string;
|
|
82
|
+
} | undefined;
|
|
83
|
+
}>;
|
|
84
|
+
export declare const RequireGuardSchema: z.ZodObject<{
|
|
85
|
+
template: z.ZodLiteral<"require-guard">;
|
|
86
|
+
callee: z.ZodObject<{
|
|
87
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
88
|
+
key: z.ZodString;
|
|
89
|
+
}, "strip", z.ZodTypeAny, {
|
|
90
|
+
key: string;
|
|
91
|
+
level: "name" | "text" | "declaration";
|
|
92
|
+
}, {
|
|
93
|
+
key: string;
|
|
94
|
+
level: "name" | "text" | "declaration";
|
|
95
|
+
}>;
|
|
96
|
+
property: z.ZodString;
|
|
97
|
+
guard: z.ZodString;
|
|
98
|
+
/** Apply only where the call's other arguments mention `guard` (e.g. the body carries it). */
|
|
99
|
+
appliesWhenArgsMention: z.ZodBoolean;
|
|
100
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
101
|
+
file: z.ZodString;
|
|
102
|
+
fn: z.ZodString;
|
|
103
|
+
}, "strip", z.ZodTypeAny, {
|
|
104
|
+
file: string;
|
|
105
|
+
fn: string;
|
|
106
|
+
}, {
|
|
107
|
+
file: string;
|
|
108
|
+
fn: string;
|
|
109
|
+
}>>;
|
|
110
|
+
}, "strip", z.ZodTypeAny, {
|
|
111
|
+
template: "require-guard";
|
|
112
|
+
callee: {
|
|
113
|
+
key: string;
|
|
114
|
+
level: "name" | "text" | "declaration";
|
|
115
|
+
};
|
|
116
|
+
property: string;
|
|
117
|
+
guard: string;
|
|
118
|
+
appliesWhenArgsMention: boolean;
|
|
119
|
+
scope?: {
|
|
120
|
+
file: string;
|
|
121
|
+
fn: string;
|
|
122
|
+
} | undefined;
|
|
123
|
+
}, {
|
|
124
|
+
template: "require-guard";
|
|
125
|
+
callee: {
|
|
126
|
+
key: string;
|
|
127
|
+
level: "name" | "text" | "declaration";
|
|
128
|
+
};
|
|
129
|
+
property: string;
|
|
130
|
+
guard: string;
|
|
131
|
+
appliesWhenArgsMention: boolean;
|
|
132
|
+
scope?: {
|
|
133
|
+
file: string;
|
|
134
|
+
fn: string;
|
|
135
|
+
} | undefined;
|
|
136
|
+
}>;
|
|
137
|
+
export declare const LearnedPatternSchema: z.ZodDiscriminatedUnion<"template", [z.ZodObject<{
|
|
138
|
+
template: z.ZodLiteral<"require-option">;
|
|
139
|
+
callee: z.ZodObject<{
|
|
140
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
141
|
+
key: z.ZodString;
|
|
142
|
+
}, "strip", z.ZodTypeAny, {
|
|
143
|
+
key: string;
|
|
144
|
+
level: "name" | "text" | "declaration";
|
|
145
|
+
}, {
|
|
146
|
+
key: string;
|
|
147
|
+
level: "name" | "text" | "declaration";
|
|
148
|
+
}>;
|
|
149
|
+
argIndex: z.ZodNumber;
|
|
150
|
+
property: z.ZodString;
|
|
151
|
+
value: z.ZodOptional<z.ZodString>;
|
|
152
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
153
|
+
file: z.ZodString;
|
|
154
|
+
fn: z.ZodString;
|
|
155
|
+
}, "strip", z.ZodTypeAny, {
|
|
156
|
+
file: string;
|
|
157
|
+
fn: string;
|
|
158
|
+
}, {
|
|
159
|
+
file: string;
|
|
160
|
+
fn: string;
|
|
161
|
+
}>>;
|
|
162
|
+
}, "strip", z.ZodTypeAny, {
|
|
163
|
+
template: "require-option";
|
|
164
|
+
callee: {
|
|
165
|
+
key: string;
|
|
166
|
+
level: "name" | "text" | "declaration";
|
|
167
|
+
};
|
|
168
|
+
argIndex: number;
|
|
169
|
+
property: string;
|
|
170
|
+
value?: string | undefined;
|
|
171
|
+
scope?: {
|
|
172
|
+
file: string;
|
|
173
|
+
fn: string;
|
|
174
|
+
} | undefined;
|
|
175
|
+
}, {
|
|
176
|
+
template: "require-option";
|
|
177
|
+
callee: {
|
|
178
|
+
key: string;
|
|
179
|
+
level: "name" | "text" | "declaration";
|
|
180
|
+
};
|
|
181
|
+
argIndex: number;
|
|
182
|
+
property: string;
|
|
183
|
+
value?: string | undefined;
|
|
184
|
+
scope?: {
|
|
185
|
+
file: string;
|
|
186
|
+
fn: string;
|
|
187
|
+
} | undefined;
|
|
188
|
+
}>, z.ZodObject<{
|
|
189
|
+
template: z.ZodLiteral<"require-guard">;
|
|
190
|
+
callee: z.ZodObject<{
|
|
191
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
192
|
+
key: z.ZodString;
|
|
193
|
+
}, "strip", z.ZodTypeAny, {
|
|
194
|
+
key: string;
|
|
195
|
+
level: "name" | "text" | "declaration";
|
|
196
|
+
}, {
|
|
197
|
+
key: string;
|
|
198
|
+
level: "name" | "text" | "declaration";
|
|
199
|
+
}>;
|
|
200
|
+
property: z.ZodString;
|
|
201
|
+
guard: z.ZodString;
|
|
202
|
+
/** Apply only where the call's other arguments mention `guard` (e.g. the body carries it). */
|
|
203
|
+
appliesWhenArgsMention: z.ZodBoolean;
|
|
204
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
205
|
+
file: z.ZodString;
|
|
206
|
+
fn: z.ZodString;
|
|
207
|
+
}, "strip", z.ZodTypeAny, {
|
|
208
|
+
file: string;
|
|
209
|
+
fn: string;
|
|
210
|
+
}, {
|
|
211
|
+
file: string;
|
|
212
|
+
fn: string;
|
|
213
|
+
}>>;
|
|
214
|
+
}, "strip", z.ZodTypeAny, {
|
|
215
|
+
template: "require-guard";
|
|
216
|
+
callee: {
|
|
217
|
+
key: string;
|
|
218
|
+
level: "name" | "text" | "declaration";
|
|
219
|
+
};
|
|
220
|
+
property: string;
|
|
221
|
+
guard: string;
|
|
222
|
+
appliesWhenArgsMention: boolean;
|
|
223
|
+
scope?: {
|
|
224
|
+
file: string;
|
|
225
|
+
fn: string;
|
|
226
|
+
} | undefined;
|
|
227
|
+
}, {
|
|
228
|
+
template: "require-guard";
|
|
229
|
+
callee: {
|
|
230
|
+
key: string;
|
|
231
|
+
level: "name" | "text" | "declaration";
|
|
232
|
+
};
|
|
233
|
+
property: string;
|
|
234
|
+
guard: string;
|
|
235
|
+
appliesWhenArgsMention: boolean;
|
|
236
|
+
scope?: {
|
|
237
|
+
file: string;
|
|
238
|
+
fn: string;
|
|
239
|
+
} | undefined;
|
|
240
|
+
}>]>;
|
|
241
|
+
export declare const LearnedRuleSchema: z.ZodObject<{
|
|
242
|
+
id: z.ZodString;
|
|
243
|
+
version: z.ZodLiteral<1>;
|
|
244
|
+
pattern: z.ZodDiscriminatedUnion<"template", [z.ZodObject<{
|
|
245
|
+
template: z.ZodLiteral<"require-option">;
|
|
246
|
+
callee: z.ZodObject<{
|
|
247
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
248
|
+
key: z.ZodString;
|
|
249
|
+
}, "strip", z.ZodTypeAny, {
|
|
250
|
+
key: string;
|
|
251
|
+
level: "name" | "text" | "declaration";
|
|
252
|
+
}, {
|
|
253
|
+
key: string;
|
|
254
|
+
level: "name" | "text" | "declaration";
|
|
255
|
+
}>;
|
|
256
|
+
argIndex: z.ZodNumber;
|
|
257
|
+
property: z.ZodString;
|
|
258
|
+
value: z.ZodOptional<z.ZodString>;
|
|
259
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
260
|
+
file: z.ZodString;
|
|
261
|
+
fn: z.ZodString;
|
|
262
|
+
}, "strip", z.ZodTypeAny, {
|
|
263
|
+
file: string;
|
|
264
|
+
fn: string;
|
|
265
|
+
}, {
|
|
266
|
+
file: string;
|
|
267
|
+
fn: string;
|
|
268
|
+
}>>;
|
|
269
|
+
}, "strip", z.ZodTypeAny, {
|
|
270
|
+
template: "require-option";
|
|
271
|
+
callee: {
|
|
272
|
+
key: string;
|
|
273
|
+
level: "name" | "text" | "declaration";
|
|
274
|
+
};
|
|
275
|
+
argIndex: number;
|
|
276
|
+
property: string;
|
|
277
|
+
value?: string | undefined;
|
|
278
|
+
scope?: {
|
|
279
|
+
file: string;
|
|
280
|
+
fn: string;
|
|
281
|
+
} | undefined;
|
|
282
|
+
}, {
|
|
283
|
+
template: "require-option";
|
|
284
|
+
callee: {
|
|
285
|
+
key: string;
|
|
286
|
+
level: "name" | "text" | "declaration";
|
|
287
|
+
};
|
|
288
|
+
argIndex: number;
|
|
289
|
+
property: string;
|
|
290
|
+
value?: string | undefined;
|
|
291
|
+
scope?: {
|
|
292
|
+
file: string;
|
|
293
|
+
fn: string;
|
|
294
|
+
} | undefined;
|
|
295
|
+
}>, z.ZodObject<{
|
|
296
|
+
template: z.ZodLiteral<"require-guard">;
|
|
297
|
+
callee: z.ZodObject<{
|
|
298
|
+
level: z.ZodEnum<["name", "declaration", "text"]>;
|
|
299
|
+
key: z.ZodString;
|
|
300
|
+
}, "strip", z.ZodTypeAny, {
|
|
301
|
+
key: string;
|
|
302
|
+
level: "name" | "text" | "declaration";
|
|
303
|
+
}, {
|
|
304
|
+
key: string;
|
|
305
|
+
level: "name" | "text" | "declaration";
|
|
306
|
+
}>;
|
|
307
|
+
property: z.ZodString;
|
|
308
|
+
guard: z.ZodString;
|
|
309
|
+
/** Apply only where the call's other arguments mention `guard` (e.g. the body carries it). */
|
|
310
|
+
appliesWhenArgsMention: z.ZodBoolean;
|
|
311
|
+
scope: z.ZodOptional<z.ZodObject<{
|
|
312
|
+
file: z.ZodString;
|
|
313
|
+
fn: z.ZodString;
|
|
314
|
+
}, "strip", z.ZodTypeAny, {
|
|
315
|
+
file: string;
|
|
316
|
+
fn: string;
|
|
317
|
+
}, {
|
|
318
|
+
file: string;
|
|
319
|
+
fn: string;
|
|
320
|
+
}>>;
|
|
321
|
+
}, "strip", z.ZodTypeAny, {
|
|
322
|
+
template: "require-guard";
|
|
323
|
+
callee: {
|
|
324
|
+
key: string;
|
|
325
|
+
level: "name" | "text" | "declaration";
|
|
326
|
+
};
|
|
327
|
+
property: string;
|
|
328
|
+
guard: string;
|
|
329
|
+
appliesWhenArgsMention: boolean;
|
|
330
|
+
scope?: {
|
|
331
|
+
file: string;
|
|
332
|
+
fn: string;
|
|
333
|
+
} | undefined;
|
|
334
|
+
}, {
|
|
335
|
+
template: "require-guard";
|
|
336
|
+
callee: {
|
|
337
|
+
key: string;
|
|
338
|
+
level: "name" | "text" | "declaration";
|
|
339
|
+
};
|
|
340
|
+
property: string;
|
|
341
|
+
guard: string;
|
|
342
|
+
appliesWhenArgsMention: boolean;
|
|
343
|
+
scope?: {
|
|
344
|
+
file: string;
|
|
345
|
+
fn: string;
|
|
346
|
+
} | undefined;
|
|
347
|
+
}>]>;
|
|
348
|
+
message: z.ZodString;
|
|
349
|
+
severity: z.ZodEnum<["low", "medium", "high"]>;
|
|
350
|
+
source: z.ZodObject<{
|
|
351
|
+
commit: z.ZodOptional<z.ZodString>;
|
|
352
|
+
file: z.ZodString;
|
|
353
|
+
function: z.ZodString;
|
|
354
|
+
}, "strip", z.ZodTypeAny, {
|
|
355
|
+
function: string;
|
|
356
|
+
file: string;
|
|
357
|
+
commit?: string | undefined;
|
|
358
|
+
}, {
|
|
359
|
+
function: string;
|
|
360
|
+
file: string;
|
|
361
|
+
commit?: string | undefined;
|
|
362
|
+
}>;
|
|
363
|
+
validation: z.ZodObject<{
|
|
364
|
+
firesBefore: z.ZodNumber;
|
|
365
|
+
firesAfter: z.ZodNumber;
|
|
366
|
+
maxHits: z.ZodNumber;
|
|
367
|
+
repoHits: z.ZodArray<z.ZodString, "many">;
|
|
368
|
+
}, "strip", z.ZodTypeAny, {
|
|
369
|
+
firesBefore: number;
|
|
370
|
+
firesAfter: number;
|
|
371
|
+
maxHits: number;
|
|
372
|
+
repoHits: string[];
|
|
373
|
+
}, {
|
|
374
|
+
firesBefore: number;
|
|
375
|
+
firesAfter: number;
|
|
376
|
+
maxHits: number;
|
|
377
|
+
repoHits: string[];
|
|
378
|
+
}>;
|
|
379
|
+
}, "strip", z.ZodTypeAny, {
|
|
380
|
+
message: string;
|
|
381
|
+
validation: {
|
|
382
|
+
firesBefore: number;
|
|
383
|
+
firesAfter: number;
|
|
384
|
+
maxHits: number;
|
|
385
|
+
repoHits: string[];
|
|
386
|
+
};
|
|
387
|
+
version: 1;
|
|
388
|
+
id: string;
|
|
389
|
+
severity: "high" | "medium" | "low";
|
|
390
|
+
source: {
|
|
391
|
+
function: string;
|
|
392
|
+
file: string;
|
|
393
|
+
commit?: string | undefined;
|
|
394
|
+
};
|
|
395
|
+
pattern: {
|
|
396
|
+
template: "require-option";
|
|
397
|
+
callee: {
|
|
398
|
+
key: string;
|
|
399
|
+
level: "name" | "text" | "declaration";
|
|
400
|
+
};
|
|
401
|
+
argIndex: number;
|
|
402
|
+
property: string;
|
|
403
|
+
value?: string | undefined;
|
|
404
|
+
scope?: {
|
|
405
|
+
file: string;
|
|
406
|
+
fn: string;
|
|
407
|
+
} | undefined;
|
|
408
|
+
} | {
|
|
409
|
+
template: "require-guard";
|
|
410
|
+
callee: {
|
|
411
|
+
key: string;
|
|
412
|
+
level: "name" | "text" | "declaration";
|
|
413
|
+
};
|
|
414
|
+
property: string;
|
|
415
|
+
guard: string;
|
|
416
|
+
appliesWhenArgsMention: boolean;
|
|
417
|
+
scope?: {
|
|
418
|
+
file: string;
|
|
419
|
+
fn: string;
|
|
420
|
+
} | undefined;
|
|
421
|
+
};
|
|
422
|
+
}, {
|
|
423
|
+
message: string;
|
|
424
|
+
validation: {
|
|
425
|
+
firesBefore: number;
|
|
426
|
+
firesAfter: number;
|
|
427
|
+
maxHits: number;
|
|
428
|
+
repoHits: string[];
|
|
429
|
+
};
|
|
430
|
+
version: 1;
|
|
431
|
+
id: string;
|
|
432
|
+
severity: "high" | "medium" | "low";
|
|
433
|
+
source: {
|
|
434
|
+
function: string;
|
|
435
|
+
file: string;
|
|
436
|
+
commit?: string | undefined;
|
|
437
|
+
};
|
|
438
|
+
pattern: {
|
|
439
|
+
template: "require-option";
|
|
440
|
+
callee: {
|
|
441
|
+
key: string;
|
|
442
|
+
level: "name" | "text" | "declaration";
|
|
443
|
+
};
|
|
444
|
+
argIndex: number;
|
|
445
|
+
property: string;
|
|
446
|
+
value?: string | undefined;
|
|
447
|
+
scope?: {
|
|
448
|
+
file: string;
|
|
449
|
+
fn: string;
|
|
450
|
+
} | undefined;
|
|
451
|
+
} | {
|
|
452
|
+
template: "require-guard";
|
|
453
|
+
callee: {
|
|
454
|
+
key: string;
|
|
455
|
+
level: "name" | "text" | "declaration";
|
|
456
|
+
};
|
|
457
|
+
property: string;
|
|
458
|
+
guard: string;
|
|
459
|
+
appliesWhenArgsMention: boolean;
|
|
460
|
+
scope?: {
|
|
461
|
+
file: string;
|
|
462
|
+
fn: string;
|
|
463
|
+
} | undefined;
|
|
464
|
+
};
|
|
465
|
+
}>;
|
|
466
|
+
export type CalleeMatcher = z.infer<typeof CalleeMatcherSchema>;
|
|
467
|
+
export type LearnedPattern = z.infer<typeof LearnedPatternSchema>;
|
|
468
|
+
export type LearnedRule = z.infer<typeof LearnedRuleSchema>;
|