@mmnto/totem 1.14.8 → 1.14.9
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/dist/ast-grep-query.d.ts +22 -2
- package/dist/ast-grep-query.d.ts.map +1 -1
- package/dist/ast-grep-query.js +34 -5
- package/dist/ast-grep-query.js.map +1 -1
- package/dist/ast-grep-query.test.js +45 -1
- package/dist/ast-grep-query.test.js.map +1 -1
- package/dist/compile-lesson.d.ts +24 -1
- package/dist/compile-lesson.d.ts.map +1 -1
- package/dist/compile-lesson.js +112 -58
- package/dist/compile-lesson.js.map +1 -1
- package/dist/compile-lesson.test.js +283 -14
- package/dist/compile-lesson.test.js.map +1 -1
- package/dist/compile-manifest.d.ts +14 -1
- package/dist/compile-manifest.d.ts.map +1 -1
- package/dist/compile-manifest.js +107 -3
- package/dist/compile-manifest.js.map +1 -1
- package/dist/compile-manifest.test.js +123 -1
- package/dist/compile-manifest.test.js.map +1 -1
- package/dist/compile-smoke-gate.d.ts +42 -0
- package/dist/compile-smoke-gate.d.ts.map +1 -0
- package/dist/compile-smoke-gate.js +135 -0
- package/dist/compile-smoke-gate.js.map +1 -0
- package/dist/compile-smoke-gate.test.d.ts +2 -0
- package/dist/compile-smoke-gate.test.d.ts.map +1 -0
- package/dist/compile-smoke-gate.test.js +202 -0
- package/dist/compile-smoke-gate.test.js.map +1 -0
- package/dist/compiler-schema.d.ts +286 -24
- package/dist/compiler-schema.d.ts.map +1 -1
- package/dist/compiler-schema.js +128 -5
- package/dist/compiler-schema.js.map +1 -1
- package/dist/compiler-schema.test.d.ts +2 -0
- package/dist/compiler-schema.test.d.ts.map +1 -0
- package/dist/compiler-schema.test.js +263 -0
- package/dist/compiler-schema.test.js.map +1 -0
- package/dist/compiler.d.ts +22 -5
- package/dist/compiler.d.ts.map +1 -1
- package/dist/compiler.js +9 -3
- package/dist/compiler.js.map +1 -1
- package/dist/compiler.test.js +17 -2
- package/dist/compiler.test.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +1 -1
- package/dist/lesson-pattern.d.ts +26 -0
- package/dist/lesson-pattern.d.ts.map +1 -1
- package/dist/lesson-pattern.js +35 -1
- package/dist/lesson-pattern.js.map +1 -1
- package/dist/lesson-pattern.test.js +72 -0
- package/dist/lesson-pattern.test.js.map +1 -1
- package/dist/rule-engine.d.ts.map +1 -1
- package/dist/rule-engine.js +25 -7
- package/dist/rule-engine.js.map +1 -1
- package/dist/rule-engine.test.js +98 -4
- package/dist/rule-engine.test.js.map +1 -1
- package/dist/rule-tester.d.ts.map +1 -1
- package/dist/rule-tester.js +9 -2
- package/dist/rule-tester.js.map +1 -1
- package/dist/rule-tester.test.js +41 -0
- package/dist/rule-tester.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { matchAstGrepPattern } from './ast-grep-query.js';
|
|
3
|
+
import { runSmokeGate } from './compile-smoke-gate.js';
|
|
4
|
+
// ─── Helpers ────────────────────────────────────────
|
|
5
|
+
function makeRegexRule(overrides = {}) {
|
|
6
|
+
return {
|
|
7
|
+
lessonHash: 'deadbeef1234',
|
|
8
|
+
lessonHeading: 'No console.log',
|
|
9
|
+
pattern: 'console\\.log',
|
|
10
|
+
message: 'Do not use console.log',
|
|
11
|
+
engine: 'regex',
|
|
12
|
+
compiledAt: '2026-04-13T12:00:00Z',
|
|
13
|
+
...overrides,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function makeAstGrepStringRule(overrides = {}) {
|
|
17
|
+
return {
|
|
18
|
+
lessonHash: 'cafeface5678',
|
|
19
|
+
lessonHeading: 'No debugger',
|
|
20
|
+
pattern: '',
|
|
21
|
+
message: 'Do not commit debugger statements',
|
|
22
|
+
engine: 'ast-grep',
|
|
23
|
+
astGrepPattern: 'debugger',
|
|
24
|
+
compiledAt: '2026-04-13T12:00:00Z',
|
|
25
|
+
...overrides,
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
function makeCompoundRule(overrides = {}) {
|
|
29
|
+
return {
|
|
30
|
+
lessonHash: 'beefcafe9abc',
|
|
31
|
+
lessonHeading: 'Empty catch',
|
|
32
|
+
pattern: '',
|
|
33
|
+
message: 'Empty catch swallows errors',
|
|
34
|
+
engine: 'ast-grep',
|
|
35
|
+
astGrepYamlRule: {
|
|
36
|
+
rule: {
|
|
37
|
+
kind: 'catch_clause',
|
|
38
|
+
not: {
|
|
39
|
+
has: {
|
|
40
|
+
kind: 'statement_block',
|
|
41
|
+
has: {
|
|
42
|
+
any: [
|
|
43
|
+
{ kind: 'expression_statement' },
|
|
44
|
+
{ kind: 'variable_declaration' },
|
|
45
|
+
{ kind: 'if_statement' },
|
|
46
|
+
{ kind: 'return_statement' },
|
|
47
|
+
{ kind: 'throw_statement' },
|
|
48
|
+
],
|
|
49
|
+
stopBy: 'end',
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
compiledAt: '2026-04-13T12:00:00Z',
|
|
56
|
+
...overrides,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
// ─── runSmokeGate: regex rules ───────────────────────
|
|
60
|
+
describe('runSmokeGate — regex engine', () => {
|
|
61
|
+
it('matches when the badExample contains the pattern', () => {
|
|
62
|
+
const rule = makeRegexRule();
|
|
63
|
+
const result = runSmokeGate(rule, 'console.log("debug")');
|
|
64
|
+
expect(result.matched).toBe(true);
|
|
65
|
+
expect(result.matchCount).toBeGreaterThanOrEqual(1);
|
|
66
|
+
});
|
|
67
|
+
it('does not match when the badExample is clean', () => {
|
|
68
|
+
const rule = makeRegexRule();
|
|
69
|
+
const result = runSmokeGate(rule, 'const x = 1;');
|
|
70
|
+
expect(result.matched).toBe(false);
|
|
71
|
+
expect(result.matchCount).toBe(0);
|
|
72
|
+
});
|
|
73
|
+
it('returns matched false for an empty badExample', () => {
|
|
74
|
+
const rule = makeRegexRule();
|
|
75
|
+
const result = runSmokeGate(rule, '');
|
|
76
|
+
expect(result.matched).toBe(false);
|
|
77
|
+
expect(result.matchCount).toBe(0);
|
|
78
|
+
});
|
|
79
|
+
it('returns matched false when the regex itself is invalid', () => {
|
|
80
|
+
const rule = makeRegexRule({ pattern: '(unclosed' });
|
|
81
|
+
const result = runSmokeGate(rule, 'console.log(1)');
|
|
82
|
+
expect(result.matched).toBe(false);
|
|
83
|
+
expect(result.matchCount).toBe(0);
|
|
84
|
+
expect(result.reason).toContain('invalid');
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
// ─── runSmokeGate: flat ast-grep rules ───────────────
|
|
88
|
+
describe('runSmokeGate — ast-grep flat pattern', () => {
|
|
89
|
+
it('matches when the pattern hits the badExample', () => {
|
|
90
|
+
const rule = makeAstGrepStringRule();
|
|
91
|
+
const result = runSmokeGate(rule, 'debugger;\n');
|
|
92
|
+
expect(result.matched).toBe(true);
|
|
93
|
+
expect(result.matchCount).toBeGreaterThanOrEqual(1);
|
|
94
|
+
});
|
|
95
|
+
it('does not match when the pattern misses the badExample', () => {
|
|
96
|
+
const rule = makeAstGrepStringRule();
|
|
97
|
+
const result = runSmokeGate(rule, 'const x = 1;\n');
|
|
98
|
+
expect(result.matched).toBe(false);
|
|
99
|
+
expect(result.matchCount).toBe(0);
|
|
100
|
+
});
|
|
101
|
+
it('returns matched false when the pattern itself throws at runtime', () => {
|
|
102
|
+
// Invalid kind — the ast-grep engine throws. The gate must surface
|
|
103
|
+
// this as a non-match with a reason rather than propagating.
|
|
104
|
+
const rule = makeAstGrepStringRule({ astGrepPattern: undefined });
|
|
105
|
+
const invalid = makeAstGrepStringRule({ astGrepPattern: 'catch ($E) { $$$ }' });
|
|
106
|
+
// Force an invalid string pattern so findAll throws.
|
|
107
|
+
const result = runSmokeGate(invalid, 'try { work() } catch (err) {}');
|
|
108
|
+
// A bare catch string pattern is multi-root and throws; the gate
|
|
109
|
+
// swallows the throw and reports no match with a reason.
|
|
110
|
+
expect(result.matched).toBe(false);
|
|
111
|
+
expect(rule).toBeDefined(); // silence unused
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
// ─── runSmokeGate: compound ast-grep rules ───────────
|
|
115
|
+
describe('runSmokeGate — ast-grep compound (astGrepYamlRule)', () => {
|
|
116
|
+
it('matches when the compound rule fires on the badExample', () => {
|
|
117
|
+
const rule = makeCompoundRule();
|
|
118
|
+
const result = runSmokeGate(rule, 'try {\n work();\n} catch (err) {\n}\n');
|
|
119
|
+
expect(result.matched).toBe(true);
|
|
120
|
+
});
|
|
121
|
+
it('does not match when the compound rule misses the badExample', () => {
|
|
122
|
+
const rule = makeCompoundRule();
|
|
123
|
+
const result = runSmokeGate(rule, 'try {\n work();\n} catch (err) {\n log(err);\n}\n');
|
|
124
|
+
expect(result.matched).toBe(false);
|
|
125
|
+
expect(result.matchCount).toBe(0);
|
|
126
|
+
});
|
|
127
|
+
it('returns matched false with a reason when the compound rule throws', () => {
|
|
128
|
+
const rule = makeCompoundRule({
|
|
129
|
+
astGrepYamlRule: { rule: { kind: '!!!INVALID_KIND!!!' } },
|
|
130
|
+
});
|
|
131
|
+
const result = runSmokeGate(rule, 'const x = 1;\n');
|
|
132
|
+
expect(result.matched).toBe(false);
|
|
133
|
+
expect(result.reason).toBeDefined();
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
// ─── extension inference (GCA WARN on design review) ─
|
|
137
|
+
describe('runSmokeGate badExample extension inference', () => {
|
|
138
|
+
it('defaults to a TSX parser so JSX-flavored bad examples still parse', () => {
|
|
139
|
+
const rule = makeAstGrepStringRule({
|
|
140
|
+
astGrepPattern: 'console.log($$$)',
|
|
141
|
+
});
|
|
142
|
+
const jsxSnippet = 'const page = <div>{console.log("hi")}</div>;\n';
|
|
143
|
+
const result = runSmokeGate(rule, jsxSnippet);
|
|
144
|
+
expect(result.matched).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
it('honors a concrete extension from the rule fileGlobs when present', () => {
|
|
147
|
+
const rule = makeAstGrepStringRule({
|
|
148
|
+
fileGlobs: ['**/*.ts'],
|
|
149
|
+
astGrepPattern: 'debugger',
|
|
150
|
+
});
|
|
151
|
+
const tsSnippet = 'debugger;\n';
|
|
152
|
+
const result = runSmokeGate(rule, tsSnippet);
|
|
153
|
+
expect(result.matched).toBe(true);
|
|
154
|
+
});
|
|
155
|
+
// Regression for CR finding on PR #1415: multi-extension fileGlobs must
|
|
156
|
+
// try every declared extension, not just the first match. Otherwise
|
|
157
|
+
// a rule scoped to both `.js` and `.jsx` would gate on JavaScript only
|
|
158
|
+
// and false-reject JSX-flavored bad examples, breaking parity with
|
|
159
|
+
// runtime (which picks Lang.Tsx for `.jsx` files).
|
|
160
|
+
it('tries every positive extension in fileGlobs, not just the first match', () => {
|
|
161
|
+
const rule = makeAstGrepStringRule({
|
|
162
|
+
fileGlobs: ['**/*.js', '**/*.jsx'],
|
|
163
|
+
astGrepPattern: 'console.log($$$)',
|
|
164
|
+
});
|
|
165
|
+
// JSX-flavored snippet: would fail under JavaScript parser but matches
|
|
166
|
+
// under Tsx. Runtime would also use Tsx for a real `.jsx` file.
|
|
167
|
+
const jsxSnippet = 'const el = <div>{console.log("hi")}</div>;\n';
|
|
168
|
+
const result = runSmokeGate(rule, jsxSnippet);
|
|
169
|
+
expect(result.matched).toBe(true);
|
|
170
|
+
});
|
|
171
|
+
// Regression for CR finding on PR #1415: an unscoped rule with a TS
|
|
172
|
+
// angle-bracket cast must not be false-rejected by a TSX-only fallback.
|
|
173
|
+
// TS allows `<Foo>bar` as a type cast; TSX rejects it as an ambiguous
|
|
174
|
+
// JSX tag open. The gate tries `.ts` before `.tsx` in the fallback set.
|
|
175
|
+
it('accepts TS angle-bracket cast syntax on unscoped rules (not just TSX)', () => {
|
|
176
|
+
const rule = makeAstGrepStringRule({
|
|
177
|
+
fileGlobs: undefined, // unscoped
|
|
178
|
+
astGrepPattern: '<$TYPE>$EXPR',
|
|
179
|
+
});
|
|
180
|
+
const tsSnippet = 'const x = <Foo>bar;\n';
|
|
181
|
+
const result = runSmokeGate(rule, tsSnippet);
|
|
182
|
+
expect(result.matched).toBe(true);
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
// ─── runtime-parity invariant ────────────────────────
|
|
186
|
+
describe('runSmokeGate runtime parity invariant', () => {
|
|
187
|
+
it('uses the same engine entry points as the runtime — gate-pass implies runtime-match', () => {
|
|
188
|
+
// If runSmokeGate reports matched === true with a non-zero matchCount,
|
|
189
|
+
// matchAstGrepPattern (the runtime entry point) invoked on the same
|
|
190
|
+
// snippet must also produce at least one match. The gate is a thin
|
|
191
|
+
// wrapper around that exact function, so this is a structural
|
|
192
|
+
// guarantee - the test locks in the guarantee against drift.
|
|
193
|
+
const rule = makeAstGrepStringRule();
|
|
194
|
+
const snippet = 'debugger;\nconst x = 1;\n';
|
|
195
|
+
const result = runSmokeGate(rule, snippet);
|
|
196
|
+
expect(result.matched).toBe(true);
|
|
197
|
+
// Reuse the same engine entry point to verify runtime parity.
|
|
198
|
+
const matches = matchAstGrepPattern(snippet, '.ts', 'debugger', snippet.split('\n').map((_, i) => i + 1));
|
|
199
|
+
expect(matches.length).toBeGreaterThanOrEqual(1);
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
//# sourceMappingURL=compile-smoke-gate.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compile-smoke-gate.test.js","sourceRoot":"","sources":["../src/compile-smoke-gate.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,42 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Schema mirroring `@ast-grep/napi`'s `NapiConfig` interface for compound
|
|
4
|
+
* structural rules. The `rule` key is required at the Zod layer so the
|
|
5
|
+
* parse-time failure is loud and readable; the inner tree shape is handed
|
|
6
|
+
* off to `@ast-grep/napi` at the engine boundary for the authoritative
|
|
7
|
+
* validity check (see `validateAstGrepPattern`). `passthrough()` lets
|
|
8
|
+
* future napi fields (e.g. `constraints`, `transform`) survive a parse
|
|
9
|
+
* without a schema bump.
|
|
10
|
+
*
|
|
11
|
+
* The rule body is a recursive structural tree (combinators like `all`,
|
|
12
|
+
* `any`, `not`, `inside`, `has`, `precedes`, `follows`). Rather than
|
|
13
|
+
* modelling the full recursive schema with `z.lazy()`, we accept any
|
|
14
|
+
* object shape here and lean on napi to reject malformed trees. That
|
|
15
|
+
* keeps the Zod layer cheap and the authoritative check centralized.
|
|
16
|
+
*/
|
|
17
|
+
export declare const NapiConfigSchema: z.ZodObject<{
|
|
18
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
19
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
20
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
21
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
22
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
23
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
24
|
+
export type NapiConfig = z.infer<typeof NapiConfigSchema>;
|
|
25
|
+
/**
|
|
26
|
+
* Named alias of `NapiConfigSchema` for grep-ability. The field on
|
|
27
|
+
* `CompiledRule` is named `astGrepYamlRule` (see ADR-087); the alias
|
|
28
|
+
* lets a reader search for `AstGrepYamlRuleSchema` and land on the
|
|
29
|
+
* right definition without first knowing it's a napi config.
|
|
30
|
+
*/
|
|
31
|
+
export declare const AstGrepYamlRuleSchema: z.ZodObject<{
|
|
32
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
33
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
34
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
35
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
36
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
37
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
38
|
+
export type AstGrepYamlRule = NapiConfig;
|
|
39
|
+
export declare const CompiledRuleSchema: z.ZodEffects<z.ZodObject<{
|
|
3
40
|
/** SHA-256 hash (first 16 hex chars) of heading + body — detects edits */
|
|
4
41
|
lessonHash: z.ZodString;
|
|
5
42
|
/** Human-readable heading from the lesson (for diagnostics) */
|
|
@@ -12,8 +49,33 @@ export declare const CompiledRuleSchema: z.ZodObject<{
|
|
|
12
49
|
engine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
|
|
13
50
|
/** Tree-sitter S-expression query (required when engine is 'ast') */
|
|
14
51
|
astQuery: z.ZodOptional<z.ZodString>;
|
|
15
|
-
/**
|
|
16
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Flat ast-grep pattern source (a single JS/TS expression). Mutually
|
|
54
|
+
* exclusive with `astGrepYamlRule` when `engine === 'ast-grep'`; the
|
|
55
|
+
* superRefine below enforces that.
|
|
56
|
+
*/
|
|
57
|
+
astGrepPattern: z.ZodOptional<z.ZodString>;
|
|
58
|
+
/**
|
|
59
|
+
* Compound ast-grep rule (NapiConfig shape). Holds structural trees
|
|
60
|
+
* that cannot be expressed as a single source snippet (all / any /
|
|
61
|
+
* not / inside / has / precedes / follows combinators). Mutually
|
|
62
|
+
* exclusive with `astGrepPattern`; see the superRefine on this
|
|
63
|
+
* schema. Smoke-test wiring lands in mmnto/totem#1408.
|
|
64
|
+
*/
|
|
65
|
+
astGrepYamlRule: z.ZodOptional<z.ZodObject<{
|
|
66
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
67
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
68
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
69
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
70
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
71
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
72
|
+
/**
|
|
73
|
+
* Optional code snippet the rule is expected to match. Stored from
|
|
74
|
+
* compiler output so the smoke-test runner (wired in
|
|
75
|
+
* mmnto/totem#1408) can re-validate the rule offline. Optional in
|
|
76
|
+
* 1.14.9; flips to required when #1408 turns on the gate.
|
|
77
|
+
*/
|
|
78
|
+
badExample: z.ZodOptional<z.ZodString>;
|
|
17
79
|
/** ISO timestamp of when this rule was compiled */
|
|
18
80
|
compiledAt: z.ZodString;
|
|
19
81
|
/** ISO timestamp of when this rule was first created (survives recompilation) */
|
|
@@ -42,15 +104,19 @@ export declare const CompiledRuleSchema: z.ZodObject<{
|
|
|
42
104
|
*/
|
|
43
105
|
manual: z.ZodOptional<z.ZodBoolean>;
|
|
44
106
|
}, "strip", z.ZodTypeAny, {
|
|
107
|
+
message: string;
|
|
45
108
|
lessonHash: string;
|
|
46
109
|
lessonHeading: string;
|
|
47
110
|
pattern: string;
|
|
48
|
-
message: string;
|
|
49
111
|
engine: "regex" | "ast" | "ast-grep";
|
|
50
112
|
compiledAt: string;
|
|
51
113
|
status?: "active" | "archived" | undefined;
|
|
52
114
|
astQuery?: string | undefined;
|
|
53
|
-
astGrepPattern?: string |
|
|
115
|
+
astGrepPattern?: string | undefined;
|
|
116
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
117
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
118
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
119
|
+
badExample?: string | undefined;
|
|
54
120
|
createdAt?: string | undefined;
|
|
55
121
|
fileGlobs?: string[] | undefined;
|
|
56
122
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -58,15 +124,59 @@ export declare const CompiledRuleSchema: z.ZodObject<{
|
|
|
58
124
|
archivedReason?: string | undefined;
|
|
59
125
|
manual?: boolean | undefined;
|
|
60
126
|
}, {
|
|
127
|
+
message: string;
|
|
128
|
+
lessonHash: string;
|
|
129
|
+
lessonHeading: string;
|
|
130
|
+
pattern: string;
|
|
131
|
+
engine: "regex" | "ast" | "ast-grep";
|
|
132
|
+
compiledAt: string;
|
|
133
|
+
status?: "active" | "archived" | undefined;
|
|
134
|
+
astQuery?: string | undefined;
|
|
135
|
+
astGrepPattern?: string | undefined;
|
|
136
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
137
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
138
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
139
|
+
badExample?: string | undefined;
|
|
140
|
+
createdAt?: string | undefined;
|
|
141
|
+
fileGlobs?: string[] | undefined;
|
|
142
|
+
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
143
|
+
severity?: "error" | "warning" | undefined;
|
|
144
|
+
archivedReason?: string | undefined;
|
|
145
|
+
manual?: boolean | undefined;
|
|
146
|
+
}>, {
|
|
147
|
+
message: string;
|
|
61
148
|
lessonHash: string;
|
|
62
149
|
lessonHeading: string;
|
|
63
150
|
pattern: string;
|
|
151
|
+
engine: "regex" | "ast" | "ast-grep";
|
|
152
|
+
compiledAt: string;
|
|
153
|
+
status?: "active" | "archived" | undefined;
|
|
154
|
+
astQuery?: string | undefined;
|
|
155
|
+
astGrepPattern?: string | undefined;
|
|
156
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
157
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
158
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
159
|
+
badExample?: string | undefined;
|
|
160
|
+
createdAt?: string | undefined;
|
|
161
|
+
fileGlobs?: string[] | undefined;
|
|
162
|
+
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
163
|
+
severity?: "error" | "warning" | undefined;
|
|
164
|
+
archivedReason?: string | undefined;
|
|
165
|
+
manual?: boolean | undefined;
|
|
166
|
+
}, {
|
|
64
167
|
message: string;
|
|
168
|
+
lessonHash: string;
|
|
169
|
+
lessonHeading: string;
|
|
170
|
+
pattern: string;
|
|
65
171
|
engine: "regex" | "ast" | "ast-grep";
|
|
66
172
|
compiledAt: string;
|
|
67
173
|
status?: "active" | "archived" | undefined;
|
|
68
174
|
astQuery?: string | undefined;
|
|
69
|
-
astGrepPattern?: string |
|
|
175
|
+
astGrepPattern?: string | undefined;
|
|
176
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
177
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
178
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
179
|
+
badExample?: string | undefined;
|
|
70
180
|
createdAt?: string | undefined;
|
|
71
181
|
fileGlobs?: string[] | undefined;
|
|
72
182
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -100,7 +210,7 @@ export declare const NonCompilableEntrySchema: z.ZodEffects<z.ZodUnion<[z.ZodStr
|
|
|
100
210
|
export type NonCompilableEntry = z.infer<typeof NonCompilableEntrySchema>;
|
|
101
211
|
export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
102
212
|
version: z.ZodLiteral<1>;
|
|
103
|
-
rules: z.ZodArray<z.ZodObject<{
|
|
213
|
+
rules: z.ZodArray<z.ZodEffects<z.ZodObject<{
|
|
104
214
|
/** SHA-256 hash (first 16 hex chars) of heading + body — detects edits */
|
|
105
215
|
lessonHash: z.ZodString;
|
|
106
216
|
/** Human-readable heading from the lesson (for diagnostics) */
|
|
@@ -113,8 +223,33 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
113
223
|
engine: z.ZodEnum<["regex", "ast", "ast-grep"]>;
|
|
114
224
|
/** Tree-sitter S-expression query (required when engine is 'ast') */
|
|
115
225
|
astQuery: z.ZodOptional<z.ZodString>;
|
|
116
|
-
/**
|
|
117
|
-
|
|
226
|
+
/**
|
|
227
|
+
* Flat ast-grep pattern source (a single JS/TS expression). Mutually
|
|
228
|
+
* exclusive with `astGrepYamlRule` when `engine === 'ast-grep'`; the
|
|
229
|
+
* superRefine below enforces that.
|
|
230
|
+
*/
|
|
231
|
+
astGrepPattern: z.ZodOptional<z.ZodString>;
|
|
232
|
+
/**
|
|
233
|
+
* Compound ast-grep rule (NapiConfig shape). Holds structural trees
|
|
234
|
+
* that cannot be expressed as a single source snippet (all / any /
|
|
235
|
+
* not / inside / has / precedes / follows combinators). Mutually
|
|
236
|
+
* exclusive with `astGrepPattern`; see the superRefine on this
|
|
237
|
+
* schema. Smoke-test wiring lands in mmnto/totem#1408.
|
|
238
|
+
*/
|
|
239
|
+
astGrepYamlRule: z.ZodOptional<z.ZodObject<{
|
|
240
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
241
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
242
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
243
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
244
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
245
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
246
|
+
/**
|
|
247
|
+
* Optional code snippet the rule is expected to match. Stored from
|
|
248
|
+
* compiler output so the smoke-test runner (wired in
|
|
249
|
+
* mmnto/totem#1408) can re-validate the rule offline. Optional in
|
|
250
|
+
* 1.14.9; flips to required when #1408 turns on the gate.
|
|
251
|
+
*/
|
|
252
|
+
badExample: z.ZodOptional<z.ZodString>;
|
|
118
253
|
/** ISO timestamp of when this rule was compiled */
|
|
119
254
|
compiledAt: z.ZodString;
|
|
120
255
|
/** ISO timestamp of when this rule was first created (survives recompilation) */
|
|
@@ -143,15 +278,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
143
278
|
*/
|
|
144
279
|
manual: z.ZodOptional<z.ZodBoolean>;
|
|
145
280
|
}, "strip", z.ZodTypeAny, {
|
|
281
|
+
message: string;
|
|
146
282
|
lessonHash: string;
|
|
147
283
|
lessonHeading: string;
|
|
148
284
|
pattern: string;
|
|
149
|
-
message: string;
|
|
150
285
|
engine: "regex" | "ast" | "ast-grep";
|
|
151
286
|
compiledAt: string;
|
|
152
287
|
status?: "active" | "archived" | undefined;
|
|
153
288
|
astQuery?: string | undefined;
|
|
154
|
-
astGrepPattern?: string |
|
|
289
|
+
astGrepPattern?: string | undefined;
|
|
290
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
291
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
292
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
293
|
+
badExample?: string | undefined;
|
|
155
294
|
createdAt?: string | undefined;
|
|
156
295
|
fileGlobs?: string[] | undefined;
|
|
157
296
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -159,15 +298,59 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
159
298
|
archivedReason?: string | undefined;
|
|
160
299
|
manual?: boolean | undefined;
|
|
161
300
|
}, {
|
|
301
|
+
message: string;
|
|
162
302
|
lessonHash: string;
|
|
163
303
|
lessonHeading: string;
|
|
164
304
|
pattern: string;
|
|
305
|
+
engine: "regex" | "ast" | "ast-grep";
|
|
306
|
+
compiledAt: string;
|
|
307
|
+
status?: "active" | "archived" | undefined;
|
|
308
|
+
astQuery?: string | undefined;
|
|
309
|
+
astGrepPattern?: string | undefined;
|
|
310
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
311
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
312
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
313
|
+
badExample?: string | undefined;
|
|
314
|
+
createdAt?: string | undefined;
|
|
315
|
+
fileGlobs?: string[] | undefined;
|
|
316
|
+
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
317
|
+
severity?: "error" | "warning" | undefined;
|
|
318
|
+
archivedReason?: string | undefined;
|
|
319
|
+
manual?: boolean | undefined;
|
|
320
|
+
}>, {
|
|
165
321
|
message: string;
|
|
322
|
+
lessonHash: string;
|
|
323
|
+
lessonHeading: string;
|
|
324
|
+
pattern: string;
|
|
166
325
|
engine: "regex" | "ast" | "ast-grep";
|
|
167
326
|
compiledAt: string;
|
|
168
327
|
status?: "active" | "archived" | undefined;
|
|
169
328
|
astQuery?: string | undefined;
|
|
170
|
-
astGrepPattern?: string |
|
|
329
|
+
astGrepPattern?: string | undefined;
|
|
330
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
331
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
332
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
333
|
+
badExample?: string | undefined;
|
|
334
|
+
createdAt?: string | undefined;
|
|
335
|
+
fileGlobs?: string[] | undefined;
|
|
336
|
+
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
337
|
+
severity?: "error" | "warning" | undefined;
|
|
338
|
+
archivedReason?: string | undefined;
|
|
339
|
+
manual?: boolean | undefined;
|
|
340
|
+
}, {
|
|
341
|
+
message: string;
|
|
342
|
+
lessonHash: string;
|
|
343
|
+
lessonHeading: string;
|
|
344
|
+
pattern: string;
|
|
345
|
+
engine: "regex" | "ast" | "ast-grep";
|
|
346
|
+
compiledAt: string;
|
|
347
|
+
status?: "active" | "archived" | undefined;
|
|
348
|
+
astQuery?: string | undefined;
|
|
349
|
+
astGrepPattern?: string | undefined;
|
|
350
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
351
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
352
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
353
|
+
badExample?: string | undefined;
|
|
171
354
|
createdAt?: string | undefined;
|
|
172
355
|
fileGlobs?: string[] | undefined;
|
|
173
356
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -199,15 +382,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
199
382
|
}, "strip", z.ZodTypeAny, {
|
|
200
383
|
version: 1;
|
|
201
384
|
rules: {
|
|
385
|
+
message: string;
|
|
202
386
|
lessonHash: string;
|
|
203
387
|
lessonHeading: string;
|
|
204
388
|
pattern: string;
|
|
205
|
-
message: string;
|
|
206
389
|
engine: "regex" | "ast" | "ast-grep";
|
|
207
390
|
compiledAt: string;
|
|
208
391
|
status?: "active" | "archived" | undefined;
|
|
209
392
|
astQuery?: string | undefined;
|
|
210
|
-
astGrepPattern?: string |
|
|
393
|
+
astGrepPattern?: string | undefined;
|
|
394
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
395
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
396
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
397
|
+
badExample?: string | undefined;
|
|
211
398
|
createdAt?: string | undefined;
|
|
212
399
|
fileGlobs?: string[] | undefined;
|
|
213
400
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -222,15 +409,19 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
222
409
|
}, {
|
|
223
410
|
version: 1;
|
|
224
411
|
rules: {
|
|
412
|
+
message: string;
|
|
225
413
|
lessonHash: string;
|
|
226
414
|
lessonHeading: string;
|
|
227
415
|
pattern: string;
|
|
228
|
-
message: string;
|
|
229
416
|
engine: "regex" | "ast" | "ast-grep";
|
|
230
417
|
compiledAt: string;
|
|
231
418
|
status?: "active" | "archived" | undefined;
|
|
232
419
|
astQuery?: string | undefined;
|
|
233
|
-
astGrepPattern?: string |
|
|
420
|
+
astGrepPattern?: string | undefined;
|
|
421
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
422
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
423
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
424
|
+
badExample?: string | undefined;
|
|
234
425
|
createdAt?: string | undefined;
|
|
235
426
|
fileGlobs?: string[] | undefined;
|
|
236
427
|
category?: "security" | "architecture" | "style" | "performance" | undefined;
|
|
@@ -244,35 +435,90 @@ export declare const CompiledRulesFileSchema: z.ZodObject<{
|
|
|
244
435
|
})[] | undefined;
|
|
245
436
|
}>;
|
|
246
437
|
export type CompiledRulesFile = z.infer<typeof CompiledRulesFileSchema>;
|
|
247
|
-
|
|
248
|
-
export declare const CompilerOutputSchema: z.ZodObject<{
|
|
438
|
+
export declare const CompilerOutputSchema: z.ZodEffects<z.ZodObject<{
|
|
249
439
|
compilable: z.ZodBoolean;
|
|
250
440
|
pattern: z.ZodOptional<z.ZodString>;
|
|
251
441
|
message: z.ZodOptional<z.ZodString>;
|
|
252
442
|
fileGlobs: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
253
443
|
engine: z.ZodOptional<z.ZodEnum<["regex", "ast", "ast-grep"]>>;
|
|
254
444
|
astQuery: z.ZodOptional<z.ZodString>;
|
|
255
|
-
|
|
445
|
+
/** Flat ast-grep pattern source. Mutually exclusive with `astGrepYamlRule`. */
|
|
446
|
+
astGrepPattern: z.ZodOptional<z.ZodString>;
|
|
447
|
+
/** Compound ast-grep rule (NapiConfig). Mutually exclusive with `astGrepPattern`. */
|
|
448
|
+
astGrepYamlRule: z.ZodOptional<z.ZodObject<{
|
|
449
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
450
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
451
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
452
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
453
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
454
|
+
}, z.ZodTypeAny, "passthrough">>>;
|
|
455
|
+
/**
|
|
456
|
+
* Code snippet the rule is expected to match. Flipped from optional to
|
|
457
|
+
* engine-conditional required in mmnto-ai/totem#1409 - regex and
|
|
458
|
+
* ast-grep rules must carry a non-empty snippet so the compile-time
|
|
459
|
+
* smoke gate (#1408) can execute the rule against known-bad code
|
|
460
|
+
* before it lands in compiled-rules.json. The Zod field stays
|
|
461
|
+
* optional here; the `refineBadExampleRequired` superRefine below
|
|
462
|
+
* enforces the engine-conditional requirement so the error message
|
|
463
|
+
* can name the engine and cite the ticket.
|
|
464
|
+
*/
|
|
465
|
+
badExample: z.ZodOptional<z.ZodString>;
|
|
256
466
|
severity: z.ZodOptional<z.ZodEnum<["error", "warning"]>>;
|
|
257
467
|
/** LLM explanation for why a lesson was marked non-compilable */
|
|
258
468
|
reason: z.ZodOptional<z.ZodString>;
|
|
259
469
|
}, "strip", z.ZodTypeAny, {
|
|
260
470
|
compilable: boolean;
|
|
261
|
-
pattern?: string | undefined;
|
|
262
471
|
message?: string | undefined;
|
|
472
|
+
pattern?: string | undefined;
|
|
263
473
|
engine?: "regex" | "ast" | "ast-grep" | undefined;
|
|
264
474
|
astQuery?: string | undefined;
|
|
265
|
-
astGrepPattern?: string |
|
|
475
|
+
astGrepPattern?: string | undefined;
|
|
476
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
477
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
478
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
479
|
+
badExample?: string | undefined;
|
|
266
480
|
fileGlobs?: string[] | undefined;
|
|
267
481
|
severity?: "error" | "warning" | undefined;
|
|
268
482
|
reason?: string | undefined;
|
|
269
483
|
}, {
|
|
270
484
|
compilable: boolean;
|
|
485
|
+
message?: string | undefined;
|
|
486
|
+
pattern?: string | undefined;
|
|
487
|
+
engine?: "regex" | "ast" | "ast-grep" | undefined;
|
|
488
|
+
astQuery?: string | undefined;
|
|
489
|
+
astGrepPattern?: string | undefined;
|
|
490
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
491
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
492
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
493
|
+
badExample?: string | undefined;
|
|
494
|
+
fileGlobs?: string[] | undefined;
|
|
495
|
+
severity?: "error" | "warning" | undefined;
|
|
496
|
+
reason?: string | undefined;
|
|
497
|
+
}>, {
|
|
498
|
+
compilable: boolean;
|
|
499
|
+
message?: string | undefined;
|
|
271
500
|
pattern?: string | undefined;
|
|
501
|
+
engine?: "regex" | "ast" | "ast-grep" | undefined;
|
|
502
|
+
astQuery?: string | undefined;
|
|
503
|
+
astGrepPattern?: string | undefined;
|
|
504
|
+
astGrepYamlRule?: z.objectOutputType<{
|
|
505
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
506
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
507
|
+
badExample?: string | undefined;
|
|
508
|
+
fileGlobs?: string[] | undefined;
|
|
509
|
+
severity?: "error" | "warning" | undefined;
|
|
510
|
+
reason?: string | undefined;
|
|
511
|
+
}, {
|
|
512
|
+
compilable: boolean;
|
|
272
513
|
message?: string | undefined;
|
|
514
|
+
pattern?: string | undefined;
|
|
273
515
|
engine?: "regex" | "ast" | "ast-grep" | undefined;
|
|
274
516
|
astQuery?: string | undefined;
|
|
275
|
-
astGrepPattern?: string |
|
|
517
|
+
astGrepPattern?: string | undefined;
|
|
518
|
+
astGrepYamlRule?: z.objectInputType<{
|
|
519
|
+
rule: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
520
|
+
}, z.ZodTypeAny, "passthrough"> | undefined;
|
|
521
|
+
badExample?: string | undefined;
|
|
276
522
|
fileGlobs?: string[] | undefined;
|
|
277
523
|
severity?: "error" | "warning" | undefined;
|
|
278
524
|
reason?: string | undefined;
|
|
@@ -310,7 +556,23 @@ export interface RuleEventContext {
|
|
|
310
556
|
justification?: string;
|
|
311
557
|
/** AST context where the rule fired (code, string, comment, regex). */
|
|
312
558
|
astContext?: AstContext;
|
|
559
|
+
/**
|
|
560
|
+
* Populated on `'failure'` events only. Holds the error message surfaced by
|
|
561
|
+
* the runtime engine (ast-grep `findAll`, regex `exec`, etc.) so `totem
|
|
562
|
+
* doctor` telemetry can aggregate rules that fail at execution time. Not
|
|
563
|
+
* used by `'trigger'` or `'suppress'` events. Kept as a string rather than
|
|
564
|
+
* the raw `unknown` so the callback interface stays cheap to consume.
|
|
565
|
+
*/
|
|
566
|
+
failureReason?: string;
|
|
313
567
|
}
|
|
314
|
-
/**
|
|
315
|
-
|
|
568
|
+
/**
|
|
569
|
+
* Callback for observability - invoked when a rule is suppressed, triggered,
|
|
570
|
+
* or fails at runtime. The `'failure'` variant was added in mmnto/totem#1408
|
|
571
|
+
* alongside per-rule try/catch in `executeQuery`. It is intentionally distinct
|
|
572
|
+
* from `'suppress'`: suppression is a user-initiated directive (totem-ignore /
|
|
573
|
+
* totem-context), while failure is a runtime engine error on a rule that
|
|
574
|
+
* otherwise compiled. The #1412 postmerge GCA fix established this boundary,
|
|
575
|
+
* so the two values must NEVER be conflated in the Trap Ledger.
|
|
576
|
+
*/
|
|
577
|
+
export type RuleEventCallback = (event: 'trigger' | 'suppress' | 'failure', lessonHash: string, context?: RuleEventContext) => void;
|
|
316
578
|
//# sourceMappingURL=compiler-schema.d.ts.map
|