@mmnto/cli 1.6.1 → 1.6.3
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/commands/check.js +2 -2
- package/dist/commands/check.test.js +9 -8
- package/dist/commands/check.test.js.map +1 -1
- package/dist/commands/config-drift.test.js +4 -2
- package/dist/commands/config-drift.test.js.map +1 -1
- package/dist/commands/config.d.ts +4 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +39 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/config.test.d.ts +2 -0
- package/dist/commands/config.test.d.ts.map +1 -0
- package/dist/commands/config.test.js +117 -0
- package/dist/commands/config.test.js.map +1 -0
- package/dist/commands/docs.d.ts +1 -1
- package/dist/commands/docs.js +2 -2
- package/dist/commands/eject.d.ts.map +1 -1
- package/dist/commands/eject.js +1 -1
- package/dist/commands/eject.js.map +1 -1
- package/dist/commands/exemption.d.ts +7 -0
- package/dist/commands/exemption.d.ts.map +1 -0
- package/dist/commands/exemption.js +166 -0
- package/dist/commands/exemption.js.map +1 -0
- package/dist/commands/exemption.test.d.ts +2 -0
- package/dist/commands/exemption.test.d.ts.map +1 -0
- package/dist/commands/exemption.test.js +258 -0
- package/dist/commands/exemption.test.js.map +1 -0
- package/dist/commands/init-templates.d.ts +4 -4
- package/dist/commands/init-templates.js +5 -5
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +10 -15
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/install-hooks.d.ts +3 -2
- package/dist/commands/install-hooks.d.ts.map +1 -1
- package/dist/commands/install-hooks.js +24 -51
- package/dist/commands/install-hooks.js.map +1 -1
- package/dist/commands/install-hooks.test.js +144 -78
- package/dist/commands/install-hooks.test.js.map +1 -1
- package/dist/commands/lesson.d.ts +3 -0
- package/dist/commands/lesson.d.ts.map +1 -0
- package/dist/commands/lesson.js +90 -0
- package/dist/commands/lesson.js.map +1 -0
- package/dist/commands/lesson.test.d.ts +2 -0
- package/dist/commands/lesson.test.d.ts.map +1 -0
- package/dist/commands/lesson.test.js +187 -0
- package/dist/commands/lesson.test.js.map +1 -0
- package/dist/commands/review-alias.test.d.ts +2 -0
- package/dist/commands/review-alias.test.d.ts.map +1 -0
- package/dist/commands/review-alias.test.js +49 -0
- package/dist/commands/review-alias.test.js.map +1 -0
- package/dist/commands/rule.d.ts +4 -0
- package/dist/commands/rule.d.ts.map +1 -0
- package/dist/commands/rule.js +154 -0
- package/dist/commands/rule.js.map +1 -0
- package/dist/commands/rule.test.d.ts +2 -0
- package/dist/commands/rule.test.d.ts.map +1 -0
- package/dist/commands/rule.test.js +315 -0
- package/dist/commands/rule.test.js.map +1 -0
- package/dist/commands/shield.d.ts +4 -2
- package/dist/commands/shield.d.ts.map +1 -1
- package/dist/commands/shield.js +42 -20
- package/dist/commands/shield.js.map +1 -1
- package/dist/commands/shield.test.js +15 -13
- package/dist/commands/shield.test.js.map +1 -1
- package/dist/commands/spec-templates.d.ts +1 -1
- package/dist/commands/spec-templates.js +1 -1
- package/dist/index.js +226 -37
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const TAG = 'Rule';
|
|
2
|
+
// ─── Helpers ───────────────────────────────────────────
|
|
3
|
+
function truncate(text, max) {
|
|
4
|
+
return text.length > max ? text.slice(0, max - 1) + '\u2026' : text;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the rules path and load rules, with a user-friendly error
|
|
8
|
+
* when no compiled-rules.json exists.
|
|
9
|
+
*/
|
|
10
|
+
async function loadRulesOrExit() {
|
|
11
|
+
const path = await import('node:path');
|
|
12
|
+
const { loadCompiledRules } = await import('@mmnto/totem');
|
|
13
|
+
const { loadConfig, resolveConfigPath } = await import('../utils.js');
|
|
14
|
+
const cwd = process.cwd();
|
|
15
|
+
const configPath = resolveConfigPath(cwd);
|
|
16
|
+
const config = await loadConfig(configPath);
|
|
17
|
+
const totemDir = path.join(cwd, config.totemDir);
|
|
18
|
+
const rulesPath = path.join(totemDir, 'compiled-rules.json');
|
|
19
|
+
const rules = loadCompiledRules(rulesPath);
|
|
20
|
+
return { rules, totemDir, cwd };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Find rules matching a hash prefix. Returns the match(es) and handles
|
|
24
|
+
* ambiguous / not-found cases with user output.
|
|
25
|
+
*/
|
|
26
|
+
function resolveRuleByPrefix(rules, id, log, bold) {
|
|
27
|
+
const lower = id.toLowerCase();
|
|
28
|
+
const matches = rules.filter((r) => r.lessonHash.toLowerCase().startsWith(lower));
|
|
29
|
+
if (matches.length === 0) {
|
|
30
|
+
log.error('Totem Error', `No rule found matching '${id}'`);
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
if (matches.length > 1) {
|
|
34
|
+
log.warn(TAG, `Ambiguous prefix '${id}' matches ${matches.length} rules:`);
|
|
35
|
+
for (const m of matches) {
|
|
36
|
+
log.info(TAG, ` ${bold(m.lessonHash)} \u2014 ${m.lessonHeading}`);
|
|
37
|
+
}
|
|
38
|
+
log.dim(TAG, 'Provide more characters to disambiguate.');
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
return matches[0];
|
|
42
|
+
}
|
|
43
|
+
// ─── Subcommands ───────────────────────────────────────
|
|
44
|
+
export async function ruleListCommand() {
|
|
45
|
+
const { log, dim, bold } = await import('../ui.js');
|
|
46
|
+
const { rules } = await loadRulesOrExit();
|
|
47
|
+
if (rules.length === 0) {
|
|
48
|
+
log.error('Totem Error', 'No compiled rules found. Run `totem compile` first.');
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
// Table header
|
|
52
|
+
const hashW = 10;
|
|
53
|
+
const engineW = 10;
|
|
54
|
+
const sevW = 9;
|
|
55
|
+
const globW = 7;
|
|
56
|
+
const headingW = 50;
|
|
57
|
+
console.error(dim(` ${'HASH'.padEnd(hashW)}${'ENGINE'.padEnd(engineW)}${'SEVERITY'.padEnd(sevW)}${'GLOBS'.padEnd(globW)}HEADING`));
|
|
58
|
+
console.error(dim(' ' + '\u2500'.repeat(hashW + engineW + sevW + globW + headingW)));
|
|
59
|
+
for (const rule of rules) {
|
|
60
|
+
const hash = rule.lessonHash.slice(0, 8).padEnd(hashW);
|
|
61
|
+
const engine = (rule.engine ?? 'regex').padEnd(engineW);
|
|
62
|
+
const severity = (rule.severity ?? 'warning').padEnd(sevW);
|
|
63
|
+
const globs = String(rule.fileGlobs?.length ?? 0).padEnd(globW);
|
|
64
|
+
const heading = truncate(rule.lessonHeading, headingW);
|
|
65
|
+
console.error(` ${hash}${engine}${severity}${globs}${heading}`);
|
|
66
|
+
}
|
|
67
|
+
console.error('');
|
|
68
|
+
log.info(TAG, `${bold(String(rules.length))} rule(s) total`);
|
|
69
|
+
}
|
|
70
|
+
export async function ruleInspectCommand(id) {
|
|
71
|
+
const { log, bold, dim } = await import('../ui.js');
|
|
72
|
+
const { rules } = await loadRulesOrExit();
|
|
73
|
+
if (rules.length === 0) {
|
|
74
|
+
log.error('Totem Error', 'No compiled rules found. Run `totem compile` first.');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const rule = resolveRuleByPrefix(rules, id, log, bold);
|
|
78
|
+
if (!rule)
|
|
79
|
+
return;
|
|
80
|
+
console.error('');
|
|
81
|
+
log.info(TAG, `${bold('Hash:')} ${rule.lessonHash}`);
|
|
82
|
+
log.info(TAG, `${bold('Heading:')} ${rule.lessonHeading}`);
|
|
83
|
+
log.info(TAG, `${bold('Engine:')} ${rule.engine}`);
|
|
84
|
+
log.info(TAG, `${bold('Severity:')} ${rule.severity ?? 'warning'}`);
|
|
85
|
+
log.info(TAG, `${bold('Message:')} ${rule.message}`);
|
|
86
|
+
if (rule.pattern) {
|
|
87
|
+
log.info(TAG, `${bold('Pattern:')} ${dim(rule.pattern)}`);
|
|
88
|
+
}
|
|
89
|
+
if (rule.astQuery) {
|
|
90
|
+
log.info(TAG, `${bold('AST Query:')} ${dim(rule.astQuery)}`);
|
|
91
|
+
}
|
|
92
|
+
if (rule.astGrepPattern) {
|
|
93
|
+
const display = typeof rule.astGrepPattern === 'string'
|
|
94
|
+
? rule.astGrepPattern
|
|
95
|
+
: JSON.stringify(rule.astGrepPattern);
|
|
96
|
+
log.info(TAG, `${bold('AST Grep:')} ${dim(display)}`);
|
|
97
|
+
}
|
|
98
|
+
if (rule.fileGlobs && rule.fileGlobs.length > 0) {
|
|
99
|
+
log.info(TAG, `${bold('File Globs:')} ${rule.fileGlobs.join(', ')}`);
|
|
100
|
+
}
|
|
101
|
+
if (rule.compiledAt) {
|
|
102
|
+
log.info(TAG, `${bold('Compiled:')} ${rule.compiledAt}`);
|
|
103
|
+
}
|
|
104
|
+
if (rule.createdAt) {
|
|
105
|
+
log.info(TAG, `${bold('Created:')} ${rule.createdAt}`);
|
|
106
|
+
}
|
|
107
|
+
console.error('');
|
|
108
|
+
}
|
|
109
|
+
export async function ruleTestCommand(id) {
|
|
110
|
+
const { log, bold, errorColor, success: successColor } = await import('../ui.js');
|
|
111
|
+
const { hashLesson, readAllLessons, extractRuleExamples, verifyRuleExamples, formatExampleFailure, } = await import('@mmnto/totem');
|
|
112
|
+
const { rules, totemDir } = await loadRulesOrExit();
|
|
113
|
+
if (rules.length === 0) {
|
|
114
|
+
log.error('Totem Error', 'No compiled rules found. Run `totem compile` first.');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const rule = resolveRuleByPrefix(rules, id, log, bold);
|
|
118
|
+
if (!rule)
|
|
119
|
+
return;
|
|
120
|
+
// Find source lesson — search all lessons for one whose hash matches the rule's lessonHash
|
|
121
|
+
const lessons = readAllLessons(totemDir);
|
|
122
|
+
const lesson = lessons.find((l) => hashLesson(l.heading, l.body) === rule.lessonHash);
|
|
123
|
+
if (!lesson) {
|
|
124
|
+
log.warn(TAG, `Source lesson for rule ${bold(rule.lessonHash)} not found in .totem/lessons/`);
|
|
125
|
+
log.dim(TAG, 'The lesson may have been removed or the hash may have changed.');
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// Check for Example Hit/Miss
|
|
129
|
+
const examples = extractRuleExamples(lesson.body);
|
|
130
|
+
if (!examples) {
|
|
131
|
+
log.warn(TAG, 'No Example Hit/Miss found in lesson for this rule. Add examples to test.');
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
// Run verification using the same logic as compile
|
|
135
|
+
const result = verifyRuleExamples(rule, lesson.body);
|
|
136
|
+
if (!result) {
|
|
137
|
+
// verifyRuleExamples returns null for non-regex engines with no examples
|
|
138
|
+
log.warn(TAG, `Engine '${rule.engine}' does not support inline example testing.`);
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
console.error('');
|
|
142
|
+
if (result.passed) {
|
|
143
|
+
const label = successColor(bold('PASS'));
|
|
144
|
+
log.info(TAG, `${label} \u2014 ${rule.lessonHeading}`);
|
|
145
|
+
log.dim(TAG, `${examples.hits.length} hit(s), ${examples.misses.length} miss(es) verified`);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
const label = errorColor(bold('FAIL'));
|
|
149
|
+
log.info(TAG, `${label} \u2014 ${rule.lessonHeading}`);
|
|
150
|
+
log.warn(TAG, formatExampleFailure(result));
|
|
151
|
+
}
|
|
152
|
+
console.error('');
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=rule.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.js","sourceRoot":"","sources":["../../src/commands/rule.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.test.d.ts","sourceRoot":"","sources":["../../src/commands/rule.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import * as fs from 'node:fs';
|
|
2
|
+
import * as os from 'node:os';
|
|
3
|
+
import * as path from 'node:path';
|
|
4
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { cleanTmpDir } from '../test-utils.js';
|
|
6
|
+
// ─── Mock utils to bypass real config loading ───────────
|
|
7
|
+
vi.mock('../utils.js', async () => {
|
|
8
|
+
const actual = await vi.importActual('../utils.js');
|
|
9
|
+
return {
|
|
10
|
+
...actual,
|
|
11
|
+
resolveConfigPath: (cwd) => path.join(cwd, 'totem.config.ts'),
|
|
12
|
+
loadConfig: async () => ({
|
|
13
|
+
targets: [],
|
|
14
|
+
totemDir: '.totem',
|
|
15
|
+
ignorePatterns: [],
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
});
|
|
19
|
+
// ─── Helpers ────────────────────────────────────────────
|
|
20
|
+
/** Strip ANSI escape codes for assertion matching. */
|
|
21
|
+
function stripAnsi(str) {
|
|
22
|
+
return str.replace(/\x1b\[[0-9;]*m/g, ''); // totem-context: ANSI regex — not user input
|
|
23
|
+
}
|
|
24
|
+
function makeTmpDir() {
|
|
25
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), 'totem-rule-'));
|
|
26
|
+
}
|
|
27
|
+
/** Write a minimal compiled-rules.json with the given rules. */
|
|
28
|
+
function writeRules(totemDir, rules) {
|
|
29
|
+
const rulesPath = path.join(totemDir, 'compiled-rules.json');
|
|
30
|
+
fs.writeFileSync(rulesPath, JSON.stringify({ version: 1, rules }), 'utf-8');
|
|
31
|
+
}
|
|
32
|
+
/** Scaffold a .totem directory with config, lessons dir, and optional rules. */
|
|
33
|
+
function scaffold(cwd, rules) {
|
|
34
|
+
const totemDir = path.join(cwd, '.totem');
|
|
35
|
+
const lessonsDir = path.join(totemDir, 'lessons');
|
|
36
|
+
fs.mkdirSync(lessonsDir, { recursive: true });
|
|
37
|
+
fs.writeFileSync(path.join(cwd, 'totem.config.ts'), 'export default {};', 'utf-8');
|
|
38
|
+
if (rules) {
|
|
39
|
+
writeRules(totemDir, rules);
|
|
40
|
+
}
|
|
41
|
+
return { totemDir, lessonsDir };
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Compute the hash a rule would get after parseLessonsFile processes it.
|
|
45
|
+
* parseLessonsFile strips the **Tags:** line from the body before hashing,
|
|
46
|
+
* so we replicate that here to get a matching hash.
|
|
47
|
+
*/
|
|
48
|
+
async function computeLessonHash(heading, bodyAfterTags) {
|
|
49
|
+
const { hashLesson } = await import('@mmnto/totem');
|
|
50
|
+
return hashLesson(heading, bodyAfterTags);
|
|
51
|
+
}
|
|
52
|
+
const SAMPLE_RULES = [
|
|
53
|
+
{
|
|
54
|
+
lessonHash: 'abcd1234abcd1234',
|
|
55
|
+
lessonHeading: 'Always use strict equality',
|
|
56
|
+
pattern: '===?\\s',
|
|
57
|
+
message: 'Use === instead of ==',
|
|
58
|
+
engine: 'regex',
|
|
59
|
+
severity: 'error',
|
|
60
|
+
compiledAt: '2026-01-01T00:00:00.000Z',
|
|
61
|
+
createdAt: '2025-12-01T00:00:00.000Z',
|
|
62
|
+
fileGlobs: ['**/*.ts', '**/*.js'],
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
lessonHash: 'efgh5678efgh5678',
|
|
66
|
+
lessonHeading: 'Avoid console.log in production code that ships to users',
|
|
67
|
+
pattern: 'console\\.log',
|
|
68
|
+
message: 'Remove console.log statements',
|
|
69
|
+
engine: 'regex',
|
|
70
|
+
severity: 'warning',
|
|
71
|
+
compiledAt: '2026-01-02T00:00:00.000Z',
|
|
72
|
+
fileGlobs: ['**/*.ts'],
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
lessonHash: 'abcd9999abcd9999',
|
|
76
|
+
lessonHeading: 'No var declarations',
|
|
77
|
+
pattern: '\\bvar\\b',
|
|
78
|
+
message: 'Use const or let instead of var',
|
|
79
|
+
engine: 'regex',
|
|
80
|
+
severity: 'warning',
|
|
81
|
+
compiledAt: '2026-01-03T00:00:00.000Z',
|
|
82
|
+
},
|
|
83
|
+
];
|
|
84
|
+
// ─── Tests ──────────────────────────────────────────────
|
|
85
|
+
describe('rule list', () => {
|
|
86
|
+
let tmpDir;
|
|
87
|
+
let originalCwd;
|
|
88
|
+
beforeEach(() => {
|
|
89
|
+
tmpDir = makeTmpDir();
|
|
90
|
+
originalCwd = process.cwd();
|
|
91
|
+
process.chdir(tmpDir);
|
|
92
|
+
});
|
|
93
|
+
afterEach(() => {
|
|
94
|
+
process.chdir(originalCwd);
|
|
95
|
+
cleanTmpDir(tmpDir);
|
|
96
|
+
vi.restoreAllMocks();
|
|
97
|
+
});
|
|
98
|
+
it('outputs correct count and table format', async () => {
|
|
99
|
+
scaffold(tmpDir, SAMPLE_RULES);
|
|
100
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
101
|
+
const { ruleListCommand } = await import('./rule.js');
|
|
102
|
+
await ruleListCommand();
|
|
103
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
104
|
+
expect(output).toContain('3 rule(s) total');
|
|
105
|
+
expect(output).toContain('abcd1234');
|
|
106
|
+
expect(output).toContain('efgh5678');
|
|
107
|
+
expect(output).toContain('regex');
|
|
108
|
+
expect(output).toContain('error');
|
|
109
|
+
expect(output).toContain('warning');
|
|
110
|
+
});
|
|
111
|
+
it('truncates long headings', async () => {
|
|
112
|
+
scaffold(tmpDir, [
|
|
113
|
+
{
|
|
114
|
+
...SAMPLE_RULES[0],
|
|
115
|
+
lessonHeading: 'This is a very long heading that exceeds fifty characters and should be truncated properly',
|
|
116
|
+
},
|
|
117
|
+
]);
|
|
118
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
119
|
+
const { ruleListCommand } = await import('./rule.js');
|
|
120
|
+
await ruleListCommand();
|
|
121
|
+
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
122
|
+
// Should be truncated with ellipsis
|
|
123
|
+
expect(output).toContain('\u2026');
|
|
124
|
+
// Should NOT contain the full heading
|
|
125
|
+
expect(output).not.toContain('truncated properly');
|
|
126
|
+
});
|
|
127
|
+
it('shows error when no compiled-rules.json exists', async () => {
|
|
128
|
+
scaffold(tmpDir); // no rules
|
|
129
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
130
|
+
const { ruleListCommand } = await import('./rule.js');
|
|
131
|
+
await ruleListCommand();
|
|
132
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
133
|
+
expect(output).toContain('No compiled rules found');
|
|
134
|
+
expect(output).toContain('totem compile');
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
describe('rule inspect', () => {
|
|
138
|
+
let tmpDir;
|
|
139
|
+
let originalCwd;
|
|
140
|
+
beforeEach(() => {
|
|
141
|
+
tmpDir = makeTmpDir();
|
|
142
|
+
originalCwd = process.cwd();
|
|
143
|
+
process.chdir(tmpDir);
|
|
144
|
+
});
|
|
145
|
+
afterEach(() => {
|
|
146
|
+
process.chdir(originalCwd);
|
|
147
|
+
cleanTmpDir(tmpDir);
|
|
148
|
+
vi.restoreAllMocks();
|
|
149
|
+
});
|
|
150
|
+
it('finds rule by full hash', async () => {
|
|
151
|
+
scaffold(tmpDir, SAMPLE_RULES);
|
|
152
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
153
|
+
const { ruleInspectCommand } = await import('./rule.js');
|
|
154
|
+
await ruleInspectCommand('abcd1234abcd1234');
|
|
155
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
156
|
+
expect(output).toContain('abcd1234abcd1234');
|
|
157
|
+
expect(output).toContain('Always use strict equality');
|
|
158
|
+
expect(output).toContain('regex');
|
|
159
|
+
expect(output).toContain('error');
|
|
160
|
+
expect(output).toContain('**/*.ts');
|
|
161
|
+
});
|
|
162
|
+
it('finds rule by prefix', async () => {
|
|
163
|
+
scaffold(tmpDir, SAMPLE_RULES);
|
|
164
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
165
|
+
const { ruleInspectCommand } = await import('./rule.js');
|
|
166
|
+
await ruleInspectCommand('efgh');
|
|
167
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
168
|
+
expect(output).toContain('efgh5678efgh5678');
|
|
169
|
+
expect(output).toContain('console.log');
|
|
170
|
+
});
|
|
171
|
+
it('errors on no match', async () => {
|
|
172
|
+
scaffold(tmpDir, SAMPLE_RULES);
|
|
173
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
174
|
+
const { ruleInspectCommand } = await import('./rule.js');
|
|
175
|
+
await ruleInspectCommand('zzzz');
|
|
176
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
177
|
+
expect(output).toContain("No rule found matching 'zzzz'");
|
|
178
|
+
});
|
|
179
|
+
it('reports ambiguous prefix', async () => {
|
|
180
|
+
scaffold(tmpDir, SAMPLE_RULES);
|
|
181
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
182
|
+
// 'abcd' matches both abcd1234... and abcd9999...
|
|
183
|
+
const { ruleInspectCommand } = await import('./rule.js');
|
|
184
|
+
await ruleInspectCommand('abcd');
|
|
185
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
186
|
+
expect(output).toContain('Ambiguous prefix');
|
|
187
|
+
expect(output).toContain('abcd1234abcd1234');
|
|
188
|
+
expect(output).toContain('abcd9999abcd9999');
|
|
189
|
+
});
|
|
190
|
+
});
|
|
191
|
+
describe('rule test', () => {
|
|
192
|
+
let tmpDir;
|
|
193
|
+
let originalCwd;
|
|
194
|
+
beforeEach(() => {
|
|
195
|
+
tmpDir = makeTmpDir();
|
|
196
|
+
originalCwd = process.cwd();
|
|
197
|
+
process.chdir(tmpDir);
|
|
198
|
+
});
|
|
199
|
+
afterEach(() => {
|
|
200
|
+
process.chdir(originalCwd);
|
|
201
|
+
cleanTmpDir(tmpDir);
|
|
202
|
+
vi.restoreAllMocks();
|
|
203
|
+
});
|
|
204
|
+
it('passes when examples match correctly', async () => {
|
|
205
|
+
const heading = 'Catch console log usage';
|
|
206
|
+
// Body as parseLessonsFile would produce it (tags stripped)
|
|
207
|
+
const bodyAfterTags = [
|
|
208
|
+
'Do not use console.log in production.',
|
|
209
|
+
'',
|
|
210
|
+
'**Pattern:** `console\\.log`',
|
|
211
|
+
'**Example Hit:** `console.log("debug")`',
|
|
212
|
+
'**Example Miss:** `logger.info("debug")`',
|
|
213
|
+
].join('\n');
|
|
214
|
+
const realHash = await computeLessonHash(heading, bodyAfterTags);
|
|
215
|
+
const rule = {
|
|
216
|
+
lessonHash: realHash,
|
|
217
|
+
lessonHeading: heading,
|
|
218
|
+
pattern: 'console\\.log',
|
|
219
|
+
message: 'Remove console.log statements',
|
|
220
|
+
engine: 'regex',
|
|
221
|
+
severity: 'error',
|
|
222
|
+
compiledAt: '2026-01-01T00:00:00.000Z',
|
|
223
|
+
};
|
|
224
|
+
const { lessonsDir } = scaffold(tmpDir, [rule]);
|
|
225
|
+
// Write the lesson file — parseLessonsFile will extract heading and body
|
|
226
|
+
const lessonContent = [
|
|
227
|
+
`## Lesson \u2014 ${heading}`,
|
|
228
|
+
'',
|
|
229
|
+
'**Tags:** best-practice',
|
|
230
|
+
'',
|
|
231
|
+
bodyAfterTags,
|
|
232
|
+
'',
|
|
233
|
+
].join('\n');
|
|
234
|
+
fs.writeFileSync(path.join(lessonsDir, 'lesson-test.md'), lessonContent, 'utf-8');
|
|
235
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
236
|
+
const { ruleTestCommand } = await import('./rule.js');
|
|
237
|
+
await ruleTestCommand(realHash);
|
|
238
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
239
|
+
expect(output).toContain('PASS');
|
|
240
|
+
});
|
|
241
|
+
it('reports failure when examples do not match', async () => {
|
|
242
|
+
const heading = 'Catch console log';
|
|
243
|
+
const bodyAfterTags = [
|
|
244
|
+
'Remove console.log statements.',
|
|
245
|
+
'',
|
|
246
|
+
'**Pattern:** `console\\.log`',
|
|
247
|
+
'**Example Hit:** `console.log("test")`',
|
|
248
|
+
'**Example Miss:** `logger.info("test")`',
|
|
249
|
+
].join('\n');
|
|
250
|
+
const realHash = await computeLessonHash(heading, bodyAfterTags);
|
|
251
|
+
// Deliberately wrong pattern so the example hit will NOT match
|
|
252
|
+
const rule = {
|
|
253
|
+
lessonHash: realHash,
|
|
254
|
+
lessonHeading: heading,
|
|
255
|
+
pattern: 'NOMATCH_PATTERN_XYZZY',
|
|
256
|
+
message: 'Remove console.log',
|
|
257
|
+
engine: 'regex',
|
|
258
|
+
severity: 'warning',
|
|
259
|
+
compiledAt: '2026-01-01T00:00:00.000Z',
|
|
260
|
+
};
|
|
261
|
+
const { lessonsDir } = scaffold(tmpDir, [rule]);
|
|
262
|
+
const lessonContent = [
|
|
263
|
+
`## Lesson \u2014 ${heading}`,
|
|
264
|
+
'',
|
|
265
|
+
'**Tags:** lint',
|
|
266
|
+
'',
|
|
267
|
+
bodyAfterTags,
|
|
268
|
+
'',
|
|
269
|
+
].join('\n');
|
|
270
|
+
fs.writeFileSync(path.join(lessonsDir, 'lesson-test.md'), lessonContent, 'utf-8');
|
|
271
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
272
|
+
const { ruleTestCommand } = await import('./rule.js');
|
|
273
|
+
await ruleTestCommand(realHash);
|
|
274
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
275
|
+
expect(output).toContain('FAIL');
|
|
276
|
+
});
|
|
277
|
+
it('reports when no examples exist in lesson', async () => {
|
|
278
|
+
const heading = 'No examples lesson';
|
|
279
|
+
const bodyAfterTags = 'This lesson has no Example Hit/Miss lines.';
|
|
280
|
+
const realHash = await computeLessonHash(heading, bodyAfterTags);
|
|
281
|
+
const rule = {
|
|
282
|
+
lessonHash: realHash,
|
|
283
|
+
lessonHeading: heading,
|
|
284
|
+
pattern: 'something',
|
|
285
|
+
message: 'Some rule',
|
|
286
|
+
engine: 'regex',
|
|
287
|
+
severity: 'warning',
|
|
288
|
+
compiledAt: '2026-01-01T00:00:00.000Z',
|
|
289
|
+
};
|
|
290
|
+
const { lessonsDir } = scaffold(tmpDir, [rule]);
|
|
291
|
+
const lessonContent = [
|
|
292
|
+
`## Lesson \u2014 ${heading}`,
|
|
293
|
+
'',
|
|
294
|
+
'**Tags:** misc',
|
|
295
|
+
'',
|
|
296
|
+
bodyAfterTags,
|
|
297
|
+
'',
|
|
298
|
+
].join('\n');
|
|
299
|
+
fs.writeFileSync(path.join(lessonsDir, 'lesson-test.md'), lessonContent, 'utf-8');
|
|
300
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
301
|
+
const { ruleTestCommand } = await import('./rule.js');
|
|
302
|
+
await ruleTestCommand(realHash);
|
|
303
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
304
|
+
expect(output).toContain('No Example Hit/Miss');
|
|
305
|
+
});
|
|
306
|
+
it('shows error when no compiled-rules.json exists', async () => {
|
|
307
|
+
scaffold(tmpDir); // no rules
|
|
308
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
309
|
+
const { ruleTestCommand } = await import('./rule.js');
|
|
310
|
+
await ruleTestCommand('abcd');
|
|
311
|
+
const output = stripAnsi(consoleSpy.mock.calls.map((c) => String(c[0])).join('\n'));
|
|
312
|
+
expect(output).toContain('No compiled rules found');
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
//# sourceMappingURL=rule.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rule.test.js","sourceRoot":"","sources":["../../src/commands/rule.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,9 +34,11 @@ export declare function computeVerdict(verdict: ShieldStructuredVerdict): {
|
|
|
34
34
|
*/
|
|
35
35
|
export declare function formatVerdictForDisplay(verdict: ShieldStructuredVerdict, pass: boolean): string;
|
|
36
36
|
/**
|
|
37
|
-
* Write the .
|
|
37
|
+
* Write the .reviewed-content-hash flag on PASS.
|
|
38
|
+
* Uses a content hash of tracked source files (not Git SHA) so the flag
|
|
39
|
+
* survives commits, amends, and rebases. Only breaks when source files change.
|
|
38
40
|
*/
|
|
39
|
-
export declare function
|
|
41
|
+
export declare function writeReviewedContentHash(cwd: string, totemDir: string, configRoot?: string): Promise<void>;
|
|
40
42
|
export type ShieldFormat = 'text' | 'sarif' | 'json';
|
|
41
43
|
export interface ShieldOptions {
|
|
42
44
|
raw?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shield.d.ts","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA2B,YAAY,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAiBvF,OAAO,EAUL,KAAK,uBAAuB,EAO7B,MAAM,uBAAuB,CAAC;AAK/B,OAAO,EACL,cAAc,EACd,0BAA0B,EAC1B,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAI/B,UAAU,gBAAgB;IACxB,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,QAAQ,EAAE,YAAY,EAAE,CAAC;IACzB,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,OAAO,EAAE,YAAY,EAAE,CAAC;CACzB;AA0BD,wBAAsB,gBAAgB,CACpC,YAAY,EAAE,MAAM,EAAE,EACtB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,CA0CjB;AAID,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EAAE,EACtB,OAAO,EAAE,gBAAgB,EACzB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAsDR;AAID,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,MAAM,EAAE,EACtB,YAAY,EAAE,MAAM,EACpB,UAAU,CAAC,EAAE,MAAM,EAAE,EACrB,WAAW,CAAC,EAAE,MAAM,GACnB,MAAM,CAoCR;AAID,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAItF;AAID;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAuCxF;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,uBAAuB,GAAG;IAChE,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB,CAuBA;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,uBAAuB,EAAE,IAAI,EAAE,OAAO,GAAG,MAAM,CAkC/F;AAED
|
|
1
|
+
{"version":3,"file":"shield.d.ts","sourceRoot":"","sources":["../../src/commands/shield.ts"],"names":[],"mappings":"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"}
|