@getfootgun/footgun 0.2.1 → 0.2.2
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/lib/rules.mjs +9 -0
- package/lib/scan.mjs +5 -5
- package/package.json +1 -1
package/lib/rules.mjs
CHANGED
|
@@ -128,6 +128,13 @@ function isSafe(rule) {
|
|
|
128
128
|
return v;
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
// A line whose trimmed start is a comment marker is not matched (`#!` shebangs fall under `#`).
|
|
132
|
+
// Block comments are not parsed: only lines starting with `/*` or `*` are skipped.
|
|
133
|
+
const COMMENT_START = /^(?:\/\/|#|\/\*|\*|<!--|--)/;
|
|
134
|
+
// A rule whose pattern itself targets comment syntax (contains `<!--`, or starts with a comment marker) is not subject to the skip.
|
|
135
|
+
// For ordinary rules, `#[attr]`, `#include` and Markdown `*` bullets are skipped like any other comment-looking line.
|
|
136
|
+
const COMMENT_RULE = /<!--|^\^?(?:\\s\*|\(\?:|\()*(?:--|#|\/\/|\/\\\*|\\\*)/;
|
|
137
|
+
|
|
131
138
|
export function matchRule(rule, relPath, text) {
|
|
132
139
|
if (!isSafe(rule)) return [];
|
|
133
140
|
if (!rule.files.some((g) => globMatch(g, relPath))) return [];
|
|
@@ -139,10 +146,12 @@ export function matchRule(rule, relPath, text) {
|
|
|
139
146
|
return [];
|
|
140
147
|
}
|
|
141
148
|
if (unless && unless.test(text)) return [];
|
|
149
|
+
const skipComments = !COMMENT_RULE.test(rule.pattern);
|
|
142
150
|
const hits = [];
|
|
143
151
|
const lines = text.split(/\r?\n/);
|
|
144
152
|
for (let i = 0; i < lines.length; i++) {
|
|
145
153
|
if (lines[i].length > MAX_LINE) continue;
|
|
154
|
+
if (skipComments && COMMENT_START.test(lines[i].trimStart())) continue;
|
|
146
155
|
if (re.test(lines[i])) hits.push(i + 1);
|
|
147
156
|
}
|
|
148
157
|
return hits;
|
package/lib/scan.mjs
CHANGED
|
@@ -303,16 +303,16 @@ export async function scanProject(root, rules) {
|
|
|
303
303
|
: [];
|
|
304
304
|
|
|
305
305
|
const findings = [];
|
|
306
|
-
|
|
306
|
+
// one finding per trap per file, at its lowest matching line
|
|
307
|
+
const first = new Map();
|
|
307
308
|
const hitRules = new Set();
|
|
308
309
|
for (const { rel, d, line } of hits) {
|
|
309
310
|
const ri = detects[d].ri;
|
|
310
|
-
const key = `${ri}\0${rel}
|
|
311
|
-
if (seen.has(key)) continue;
|
|
312
|
-
seen.add(key);
|
|
311
|
+
const key = `${ri}\0${rel}`;
|
|
313
312
|
hitRules.add(ri);
|
|
314
|
-
|
|
313
|
+
if (!first.has(key) || line < first.get(key).line) first.set(key, { ri, rel, line });
|
|
315
314
|
}
|
|
315
|
+
for (const { ri, rel, line } of first.values()) findings.push(finding(good[ri], rel, line, false));
|
|
316
316
|
findings.sort((a, b) => (a.file < b.file ? -1 : a.file > b.file ? 1 : a.line - b.line));
|
|
317
317
|
// a manual finding and the applicable list both need a ref narrower than "any version": a broad ref
|
|
318
318
|
// only shows the package is present, which is enough to run detect rules but not to say the trap applies
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{ "name": "@getfootgun/footgun", "version": "0.2.
|
|
1
|
+
{ "name": "@getfootgun/footgun", "version": "0.2.2", "description": "Ask Footgun why a third-party API, platform, or AI tool just broke.", "bin": { "footgun": "bin/footgun.mjs" }, "scripts": { "prepublishOnly": "node ../scripts/check-publish.mjs" }, "type": "module", "license": "MIT", "files": ["bin", "lib", "README.md"], "engines": { "node": ">=20" } }
|