unguard 0.15.2 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +232 -81
- package/dist/{chunk-WXUUG77Y.js → chunk-3Y76J2K2.js} +215 -100
- package/dist/chunk-3Y76J2K2.js.map +1 -0
- package/dist/chunk-Z34GRD3S.js +5352 -0
- package/dist/chunk-Z34GRD3S.js.map +1 -0
- package/dist/cli.js +211 -40
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +134 -9
- package/dist/index.js +2 -2
- package/dist/worker.js +8 -3
- package/dist/worker.js.map +1 -1
- package/package.json +8 -2
- package/schema.json +23 -1
- package/dist/chunk-BLCVXVLX.js +0 -3850
- package/dist/chunk-BLCVXVLX.js.map +0 -1
- package/dist/chunk-WXUUG77Y.js.map +0 -1
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
allRules,
|
|
3
3
|
analyzeFiles,
|
|
4
4
|
getRuleMetadata
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Z34GRD3S.js";
|
|
6
6
|
|
|
7
7
|
// src/scan/config.ts
|
|
8
8
|
var BUILTIN_IGNORE = [
|
|
@@ -20,20 +20,30 @@ var GENERATED_IGNORE = [
|
|
|
20
20
|
var DEFAULT_FAIL_ON = "info";
|
|
21
21
|
function resolveScanConfig(options) {
|
|
22
22
|
const paths = options.paths.length > 0 ? options.paths : ["."];
|
|
23
|
-
const
|
|
23
|
+
const ignore3 = [...BUILTIN_IGNORE, ...GENERATED_IGNORE, ...options.ignore ?? []];
|
|
24
24
|
return {
|
|
25
25
|
paths,
|
|
26
|
+
mode: options.mode ?? "scan",
|
|
26
27
|
strict: options.strict ?? false,
|
|
27
28
|
rules: options.rules ? [...options.rules] : null,
|
|
28
|
-
ignore:
|
|
29
|
+
ignore: ignore3,
|
|
29
30
|
rulePolicy: toRulePolicyEntries(options.rulePolicy),
|
|
31
|
+
overrides: toResolvedOverrides(options.overrides),
|
|
30
32
|
showSeverities: normalizeSeveritySet(options.showSeverities),
|
|
31
33
|
failOn: options.failOn ?? DEFAULT_FAIL_ON,
|
|
32
34
|
useGitIgnore: options.useGitIgnore ?? true,
|
|
33
35
|
concurrency: options.concurrency,
|
|
34
|
-
cache: options.cache ?? true
|
|
36
|
+
cache: options.cache ?? true,
|
|
37
|
+
baseline: options.baseline ?? null
|
|
35
38
|
};
|
|
36
39
|
}
|
|
40
|
+
function toResolvedOverrides(overrides) {
|
|
41
|
+
if (overrides === void 0) return [];
|
|
42
|
+
return overrides.map((entry) => ({
|
|
43
|
+
files: [...entry.files],
|
|
44
|
+
rulePolicy: toRulePolicyEntries(entry.rules)
|
|
45
|
+
}));
|
|
46
|
+
}
|
|
37
47
|
function toRulePolicyEntries(policy) {
|
|
38
48
|
if (policy === void 0) return [];
|
|
39
49
|
if (Array.isArray(policy)) return [...policy];
|
|
@@ -57,12 +67,193 @@ function isFailOn(value) {
|
|
|
57
67
|
return value === "none" || isSeverity(value);
|
|
58
68
|
}
|
|
59
69
|
|
|
70
|
+
// src/scan/baseline.ts
|
|
71
|
+
import { existsSync, readFileSync, writeFileSync } from "fs";
|
|
72
|
+
import { relative, resolve } from "path";
|
|
73
|
+
var BASELINE_FILENAME = "unguard.baseline.json";
|
|
74
|
+
function buildBaseline(diagnostics, cwd) {
|
|
75
|
+
const rules = {};
|
|
76
|
+
for (const diagnostic of diagnostics) {
|
|
77
|
+
const file = relative(cwd, diagnostic.file);
|
|
78
|
+
rules[file] ??= {};
|
|
79
|
+
const forFile = rules[file];
|
|
80
|
+
forFile[diagnostic.ruleId] = (forFile[diagnostic.ruleId] ?? 0) + 1;
|
|
81
|
+
}
|
|
82
|
+
return { version: 1, rules };
|
|
83
|
+
}
|
|
84
|
+
function writeBaseline(baseline, cwd) {
|
|
85
|
+
const path = resolve(cwd, BASELINE_FILENAME);
|
|
86
|
+
writeFileSync(path, `${JSON.stringify(baseline, null, 2)}
|
|
87
|
+
`, "utf8");
|
|
88
|
+
return path;
|
|
89
|
+
}
|
|
90
|
+
function loadBaseline(cwd) {
|
|
91
|
+
const path = resolve(cwd, BASELINE_FILENAME);
|
|
92
|
+
if (!existsSync(path)) return null;
|
|
93
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
94
|
+
if (!isBaselineData(parsed)) {
|
|
95
|
+
throw new Error(`Invalid baseline in ${BASELINE_FILENAME}: expected {"version": 1, "rules": {<file>: {<ruleId>: count}}}.`);
|
|
96
|
+
}
|
|
97
|
+
return parsed;
|
|
98
|
+
}
|
|
99
|
+
function isBaselineData(value) {
|
|
100
|
+
if (typeof value !== "object" || value === null) return false;
|
|
101
|
+
if (!("version" in value) || value.version !== 1) return false;
|
|
102
|
+
if (!("rules" in value) || typeof value.rules !== "object" || value.rules === null) return false;
|
|
103
|
+
return Object.values(value.rules).every(
|
|
104
|
+
(forFile) => typeof forFile === "object" && forFile !== null && Object.values(forFile).every((count) => typeof count === "number")
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
function applyBaseline(diagnostics, baseline, cwd) {
|
|
108
|
+
const groups = /* @__PURE__ */ new Map();
|
|
109
|
+
for (const diagnostic of diagnostics) {
|
|
110
|
+
const key = `${relative(cwd, diagnostic.file)}\0${diagnostic.ruleId}`;
|
|
111
|
+
let list = groups.get(key);
|
|
112
|
+
if (list === void 0) {
|
|
113
|
+
list = [];
|
|
114
|
+
groups.set(key, list);
|
|
115
|
+
}
|
|
116
|
+
list.push(diagnostic);
|
|
117
|
+
}
|
|
118
|
+
const kept = [];
|
|
119
|
+
for (const [key, group] of groups) {
|
|
120
|
+
const [file, ruleId] = key.split("\0");
|
|
121
|
+
const allowed = baseline.rules[file]?.[ruleId] ?? 0;
|
|
122
|
+
if (group.length <= allowed) continue;
|
|
123
|
+
kept.push(...group);
|
|
124
|
+
}
|
|
125
|
+
return kept;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// src/scan/policy.ts
|
|
129
|
+
import { relative as relative2 } from "path";
|
|
130
|
+
import ignore from "ignore";
|
|
131
|
+
function buildRuleDescriptors(rules) {
|
|
132
|
+
return rules.map((rule) => {
|
|
133
|
+
const metadata = getRuleMetadata(rule.id);
|
|
134
|
+
return {
|
|
135
|
+
rule,
|
|
136
|
+
category: metadata.category,
|
|
137
|
+
tags: metadata.tags,
|
|
138
|
+
confidence: metadata.confidence
|
|
139
|
+
};
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
function resolveActiveRules(descriptors, config) {
|
|
143
|
+
const selectedRules = config.rules ? new Set(config.rules) : null;
|
|
144
|
+
const wantedConfidence = config.mode === "audit" ? "heuristic" : "proven";
|
|
145
|
+
const active = [];
|
|
146
|
+
for (const descriptor of descriptors) {
|
|
147
|
+
if (selectedRules) {
|
|
148
|
+
if (!selectedRules.has(descriptor.rule.id)) continue;
|
|
149
|
+
} else if (descriptor.confidence !== wantedConfidence) {
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
const resolvedSeverity = resolveRuleSeverity(descriptor, config);
|
|
153
|
+
if (resolvedSeverity === "off") continue;
|
|
154
|
+
if (descriptor.rule.severity === resolvedSeverity) {
|
|
155
|
+
active.push(descriptor.rule);
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
active.push({ ...descriptor.rule, severity: resolvedSeverity });
|
|
159
|
+
}
|
|
160
|
+
return active;
|
|
161
|
+
}
|
|
162
|
+
function resolveRuleSeverity(descriptor, config) {
|
|
163
|
+
let severity = descriptor.rule.severity;
|
|
164
|
+
for (const entry of config.rulePolicy) {
|
|
165
|
+
if (!matchesSelector(descriptor, entry.selector)) continue;
|
|
166
|
+
severity = entry.severity;
|
|
167
|
+
}
|
|
168
|
+
if (severity === "off") return "off";
|
|
169
|
+
if (config.strict) return "error";
|
|
170
|
+
return severity;
|
|
171
|
+
}
|
|
172
|
+
function matchesSelector(descriptor, selector) {
|
|
173
|
+
if (selector.startsWith("category:")) {
|
|
174
|
+
return descriptor.category === selector.slice("category:".length);
|
|
175
|
+
}
|
|
176
|
+
if (selector.startsWith("tag:")) {
|
|
177
|
+
return descriptor.tags.includes(selector.slice("tag:".length));
|
|
178
|
+
}
|
|
179
|
+
if (selector.startsWith("confidence:")) {
|
|
180
|
+
return descriptor.confidence === selector.slice("confidence:".length);
|
|
181
|
+
}
|
|
182
|
+
if (selector === descriptor.rule.id) return true;
|
|
183
|
+
if (!selector.includes("*")) return false;
|
|
184
|
+
const regex = new RegExp(`^${escapeRegex(selector).replaceAll("\\*", ".*")}$`);
|
|
185
|
+
return regex.test(descriptor.rule.id);
|
|
186
|
+
}
|
|
187
|
+
function escapeRegex(value) {
|
|
188
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
189
|
+
}
|
|
190
|
+
function finalizeScanResult(diagnostics, fileCount, config) {
|
|
191
|
+
const afterOverrides = applyOverrides(diagnostics, config.overrides, process.cwd());
|
|
192
|
+
const effective = config.baseline ? applyBaseline(afterOverrides, config.baseline, process.cwd()) : afterOverrides;
|
|
193
|
+
const visibleDiagnostics = config.showSeverities ? effective.filter((d) => config.showSeverities?.has(d.severity)) : effective;
|
|
194
|
+
return {
|
|
195
|
+
diagnostics,
|
|
196
|
+
visibleDiagnostics,
|
|
197
|
+
fileCount,
|
|
198
|
+
exitCode: computeExitCode(effective, config.failOn)
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
function applyOverrides(diagnostics, overrides, cwd) {
|
|
202
|
+
if (overrides.length === 0) return diagnostics;
|
|
203
|
+
const matchers = overrides.map((entry) => ({
|
|
204
|
+
matcher: ignore().add(entry.files),
|
|
205
|
+
rulePolicy: entry.rulePolicy
|
|
206
|
+
}));
|
|
207
|
+
const result = [];
|
|
208
|
+
for (const diagnostic of diagnostics) {
|
|
209
|
+
const relPath = relative2(cwd, diagnostic.file).replaceAll("\\", "/");
|
|
210
|
+
const metadata = getRuleMetadata(diagnostic.ruleId);
|
|
211
|
+
const descriptor = {
|
|
212
|
+
rule: { id: diagnostic.ruleId },
|
|
213
|
+
category: metadata.category,
|
|
214
|
+
tags: metadata.tags,
|
|
215
|
+
confidence: metadata.confidence
|
|
216
|
+
};
|
|
217
|
+
let severity = diagnostic.severity;
|
|
218
|
+
for (const { matcher, rulePolicy } of matchers) {
|
|
219
|
+
if (relPath.startsWith("..") || !matcher.ignores(relPath)) continue;
|
|
220
|
+
for (const entry of rulePolicy) {
|
|
221
|
+
if (!matchesSelector(descriptor, entry.selector)) continue;
|
|
222
|
+
severity = entry.severity;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
if (severity === "off") continue;
|
|
226
|
+
result.push(severity === diagnostic.severity ? diagnostic : { ...diagnostic, severity });
|
|
227
|
+
}
|
|
228
|
+
return result;
|
|
229
|
+
}
|
|
230
|
+
function toScanResult(execution) {
|
|
231
|
+
return {
|
|
232
|
+
diagnostics: execution.diagnostics,
|
|
233
|
+
fileCount: execution.fileCount
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
function computeExitCode(diagnostics, failOn) {
|
|
237
|
+
if (failOn === "none") return 0;
|
|
238
|
+
const hasError = diagnostics.some((d) => d.severity === "error");
|
|
239
|
+
const hasWarning = diagnostics.some((d) => d.severity === "warning");
|
|
240
|
+
const hasInfo = diagnostics.some((d) => d.severity === "info");
|
|
241
|
+
if (failOn === "error") return hasError ? 2 : 0;
|
|
242
|
+
if (failOn === "warning") {
|
|
243
|
+
if (hasError) return 2;
|
|
244
|
+
return hasWarning ? 1 : 0;
|
|
245
|
+
}
|
|
246
|
+
if (hasError) return 2;
|
|
247
|
+
if (hasWarning || hasInfo) return 1;
|
|
248
|
+
return 0;
|
|
249
|
+
}
|
|
250
|
+
|
|
60
251
|
// src/engine.ts
|
|
61
252
|
import { availableParallelism } from "os";
|
|
62
253
|
|
|
63
254
|
// src/scan/cache.ts
|
|
64
255
|
import { createHash } from "crypto";
|
|
65
|
-
import { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from "fs";
|
|
256
|
+
import { existsSync as existsSync2, mkdirSync, readFileSync as readFileSync2, statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
66
257
|
import { join } from "path";
|
|
67
258
|
var CACHE_VERSION = 1;
|
|
68
259
|
var CACHE_FILENAME = "scan-cache.json";
|
|
@@ -70,7 +261,7 @@ function resolveCacheDir(startDir) {
|
|
|
70
261
|
let dir = startDir;
|
|
71
262
|
for (; ; ) {
|
|
72
263
|
const nm = join(dir, "node_modules");
|
|
73
|
-
if (
|
|
264
|
+
if (existsSync2(nm)) return join(nm, ".cache", "unguard", `v${CACHE_VERSION}`);
|
|
74
265
|
const parent = join(dir, "..");
|
|
75
266
|
if (parent === dir) return null;
|
|
76
267
|
dir = parent;
|
|
@@ -96,7 +287,7 @@ function hashFile(path, prevFingerprint) {
|
|
|
96
287
|
const prevStat = prevFingerprint.split("@", 1)[0];
|
|
97
288
|
if (prevStat === statTag) return prevFingerprint;
|
|
98
289
|
}
|
|
99
|
-
const buf =
|
|
290
|
+
const buf = readFileSync2(path);
|
|
100
291
|
const contentHash = createHash("sha1").update(buf).digest("hex").slice(0, 16);
|
|
101
292
|
return `${statTag}@${contentHash}`;
|
|
102
293
|
}
|
|
@@ -109,8 +300,8 @@ function hashFiles(paths, prev) {
|
|
|
109
300
|
}
|
|
110
301
|
function readScanCache(dir) {
|
|
111
302
|
const path = join(dir, CACHE_FILENAME);
|
|
112
|
-
if (!
|
|
113
|
-
const text = trySync(() =>
|
|
303
|
+
if (!existsSync2(path)) return null;
|
|
304
|
+
const text = trySync(() => readFileSync2(path, "utf8"), "read failed");
|
|
114
305
|
if (text === null) return null;
|
|
115
306
|
const raw = trySync(() => JSON.parse(text), "parse failed");
|
|
116
307
|
if (raw === null) return null;
|
|
@@ -119,7 +310,7 @@ function readScanCache(dir) {
|
|
|
119
310
|
function writeScanCache(dir, entry) {
|
|
120
311
|
trySync(() => {
|
|
121
312
|
mkdirSync(dir, { recursive: true });
|
|
122
|
-
|
|
313
|
+
writeFileSync2(join(dir, CACHE_FILENAME), JSON.stringify(entry));
|
|
123
314
|
return true;
|
|
124
315
|
}, "write failed");
|
|
125
316
|
}
|
|
@@ -217,9 +408,9 @@ function debugLog(label, err) {
|
|
|
217
408
|
|
|
218
409
|
// src/scan/discover.ts
|
|
219
410
|
import fg from "fast-glob";
|
|
220
|
-
import
|
|
221
|
-
import { existsSync as
|
|
222
|
-
import { relative, resolve, sep } from "path";
|
|
411
|
+
import ignore2 from "ignore";
|
|
412
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
413
|
+
import { relative as relative3, resolve as resolve2, sep } from "path";
|
|
223
414
|
async function discoverFiles(config) {
|
|
224
415
|
const globs = expandGlobs(config.paths);
|
|
225
416
|
const discoveredFiles = await fg(globs, {
|
|
@@ -240,100 +431,19 @@ function expandGlobs(paths) {
|
|
|
240
431
|
});
|
|
241
432
|
}
|
|
242
433
|
function applyGitIgnore(files) {
|
|
243
|
-
const gitIgnorePath =
|
|
244
|
-
if (!
|
|
245
|
-
const matcher =
|
|
434
|
+
const gitIgnorePath = resolve2(process.cwd(), ".gitignore");
|
|
435
|
+
if (!existsSync3(gitIgnorePath)) return files;
|
|
436
|
+
const matcher = ignore2().add(readFileSync3(gitIgnorePath, "utf8"));
|
|
246
437
|
return files.filter((file) => {
|
|
247
|
-
const rel =
|
|
438
|
+
const rel = relative3(process.cwd(), file);
|
|
248
439
|
if (rel.startsWith("..")) return true;
|
|
249
440
|
const normalized = rel.split(sep).join("/");
|
|
250
441
|
return !matcher.ignores(normalized);
|
|
251
442
|
});
|
|
252
443
|
}
|
|
253
444
|
|
|
254
|
-
// src/scan/policy.ts
|
|
255
|
-
function buildRuleDescriptors(rules) {
|
|
256
|
-
return rules.map((rule) => {
|
|
257
|
-
const metadata = getRuleMetadata(rule.id);
|
|
258
|
-
return {
|
|
259
|
-
rule,
|
|
260
|
-
category: metadata.category,
|
|
261
|
-
tags: metadata.tags
|
|
262
|
-
};
|
|
263
|
-
});
|
|
264
|
-
}
|
|
265
|
-
function resolveActiveRules(descriptors, config) {
|
|
266
|
-
const selectedRules = config.rules ? new Set(config.rules) : null;
|
|
267
|
-
const active = [];
|
|
268
|
-
for (const descriptor of descriptors) {
|
|
269
|
-
if (selectedRules && !selectedRules.has(descriptor.rule.id)) continue;
|
|
270
|
-
const resolvedSeverity = resolveRuleSeverity(descriptor, config);
|
|
271
|
-
if (resolvedSeverity === "off") continue;
|
|
272
|
-
if (descriptor.rule.severity === resolvedSeverity) {
|
|
273
|
-
active.push(descriptor.rule);
|
|
274
|
-
continue;
|
|
275
|
-
}
|
|
276
|
-
active.push({ ...descriptor.rule, severity: resolvedSeverity });
|
|
277
|
-
}
|
|
278
|
-
return active;
|
|
279
|
-
}
|
|
280
|
-
function resolveRuleSeverity(descriptor, config) {
|
|
281
|
-
let severity = descriptor.rule.severity;
|
|
282
|
-
for (const entry of config.rulePolicy) {
|
|
283
|
-
if (!matchesSelector(descriptor, entry.selector)) continue;
|
|
284
|
-
severity = entry.severity;
|
|
285
|
-
}
|
|
286
|
-
if (severity === "off") return "off";
|
|
287
|
-
if (config.strict) return "error";
|
|
288
|
-
return severity;
|
|
289
|
-
}
|
|
290
|
-
function matchesSelector(descriptor, selector) {
|
|
291
|
-
if (selector.startsWith("category:")) {
|
|
292
|
-
return descriptor.category === selector.slice("category:".length);
|
|
293
|
-
}
|
|
294
|
-
if (selector.startsWith("tag:")) {
|
|
295
|
-
return descriptor.tags.includes(selector.slice("tag:".length));
|
|
296
|
-
}
|
|
297
|
-
if (selector === descriptor.rule.id) return true;
|
|
298
|
-
if (!selector.includes("*")) return false;
|
|
299
|
-
const regex = new RegExp(`^${escapeRegex(selector).replaceAll("\\*", ".*")}$`);
|
|
300
|
-
return regex.test(descriptor.rule.id);
|
|
301
|
-
}
|
|
302
|
-
function escapeRegex(value) {
|
|
303
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
304
|
-
}
|
|
305
|
-
function finalizeScanResult(diagnostics, fileCount, config) {
|
|
306
|
-
const visibleDiagnostics = config.showSeverities ? diagnostics.filter((d) => config.showSeverities?.has(d.severity)) : diagnostics;
|
|
307
|
-
return {
|
|
308
|
-
diagnostics,
|
|
309
|
-
visibleDiagnostics,
|
|
310
|
-
fileCount,
|
|
311
|
-
exitCode: computeExitCode(diagnostics, config.failOn)
|
|
312
|
-
};
|
|
313
|
-
}
|
|
314
|
-
function toScanResult(execution) {
|
|
315
|
-
return {
|
|
316
|
-
diagnostics: execution.diagnostics,
|
|
317
|
-
fileCount: execution.fileCount
|
|
318
|
-
};
|
|
319
|
-
}
|
|
320
|
-
function computeExitCode(diagnostics, failOn) {
|
|
321
|
-
if (failOn === "none") return 0;
|
|
322
|
-
const hasError = diagnostics.some((d) => d.severity === "error");
|
|
323
|
-
const hasWarning = diagnostics.some((d) => d.severity === "warning");
|
|
324
|
-
const hasInfo = diagnostics.some((d) => d.severity === "info");
|
|
325
|
-
if (failOn === "error") return hasError ? 2 : 0;
|
|
326
|
-
if (failOn === "warning") {
|
|
327
|
-
if (hasError) return 2;
|
|
328
|
-
return hasWarning ? 1 : 0;
|
|
329
|
-
}
|
|
330
|
-
if (hasError) return 2;
|
|
331
|
-
if (hasWarning || hasInfo) return 1;
|
|
332
|
-
return 0;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
445
|
// src/engine.ts
|
|
336
|
-
var UNGUARD_VERSION = "0.
|
|
446
|
+
var UNGUARD_VERSION = "0.16.0";
|
|
337
447
|
async function executeScan(options) {
|
|
338
448
|
const config = resolveScanConfig(options);
|
|
339
449
|
const files = await discoverFiles(config);
|
|
@@ -390,7 +500,12 @@ export {
|
|
|
390
500
|
isRulePolicySeverity,
|
|
391
501
|
isSeverity,
|
|
392
502
|
isFailOn,
|
|
503
|
+
BASELINE_FILENAME,
|
|
504
|
+
buildBaseline,
|
|
505
|
+
writeBaseline,
|
|
506
|
+
loadBaseline,
|
|
507
|
+
computeExitCode,
|
|
393
508
|
executeScan,
|
|
394
509
|
scan
|
|
395
510
|
};
|
|
396
|
-
//# sourceMappingURL=chunk-
|
|
511
|
+
//# sourceMappingURL=chunk-3Y76J2K2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/scan/config.ts","../src/scan/baseline.ts","../src/scan/policy.ts","../src/engine.ts","../src/scan/cache.ts","../src/scan/discover.ts"],"sourcesContent":["import type {\n FailOn,\n ResolvedRuleOverride,\n ResolvedScanConfig,\n RuleOverride,\n RulePolicy,\n RulePolicyEntry,\n RulePolicySeverity,\n ScanOptions,\n Severity,\n} from \"./types.ts\";\n\nconst BUILTIN_IGNORE = [\n \"**/node_modules/**\",\n \"**/dist/**\",\n \"**/.git/**\",\n \"**/*.d.ts\",\n \"**/*.d.cts\",\n \"**/*.d.mts\",\n];\n\nconst GENERATED_IGNORE = [\n \"**/*.gen.*\",\n \"**/*.generated.*\",\n];\n\nconst DEFAULT_FAIL_ON: FailOn = \"info\";\n\nexport function resolveScanConfig(options: ScanOptions): ResolvedScanConfig {\n const paths = options.paths.length > 0 ? options.paths : [\".\"];\n const ignore = [...BUILTIN_IGNORE, ...GENERATED_IGNORE, ...(options.ignore ?? [])];\n return {\n paths,\n mode: options.mode ?? \"scan\",\n strict: options.strict ?? false,\n rules: options.rules ? [...options.rules] : null,\n ignore,\n rulePolicy: toRulePolicyEntries(options.rulePolicy),\n overrides: toResolvedOverrides(options.overrides),\n showSeverities: normalizeSeveritySet(options.showSeverities),\n failOn: options.failOn ?? DEFAULT_FAIL_ON,\n useGitIgnore: options.useGitIgnore ?? true,\n concurrency: options.concurrency,\n cache: options.cache ?? true,\n baseline: options.baseline ?? null,\n };\n}\n\nfunction toResolvedOverrides(overrides: RuleOverride[] | undefined): ResolvedRuleOverride[] {\n if (overrides === undefined) return [];\n return overrides.map((entry) => ({\n files: [...entry.files],\n rulePolicy: toRulePolicyEntries(entry.rules),\n }));\n}\n\nexport function toRulePolicyEntries(policy: RulePolicy | undefined): RulePolicyEntry[] {\n if (policy === undefined) return [];\n if (Array.isArray(policy)) return [...policy];\n\n const entries: RulePolicyEntry[] = [];\n for (const [selector, severity] of Object.entries(policy)) {\n entries.push({ selector, severity });\n }\n return entries;\n}\n\nfunction normalizeSeveritySet(levels: Severity[] | undefined): Set<Severity> | null {\n if (levels === undefined || levels.length === 0) return null;\n return new Set(levels);\n}\n\nexport function isRulePolicySeverity(value: string): value is RulePolicySeverity {\n return value === \"off\" || value === \"info\" || value === \"warning\" || value === \"error\";\n}\n\nexport function isSeverity(value: string): value is Severity {\n return value === \"info\" || value === \"warning\" || value === \"error\";\n}\n\nexport function isFailOn(value: string): value is FailOn {\n return value === \"none\" || isSeverity(value);\n}\n","import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { relative, resolve } from \"node:path\";\nimport type { Diagnostic } from \"../rules/types.ts\";\n\nexport const BASELINE_FILENAME = \"unguard.baseline.json\";\n\n/**\n * Ratchet file: known-issue counts per (file, rule). A scan suppresses a\n * group while its count stays at or below the recorded number; the moment it\n * exceeds the baseline, the whole group surfaces — line numbers shift too\n * easily to pin individual diagnostics, counts only ratchet downward.\n */\nexport interface BaselineData {\n version: 1;\n rules: Record<string, Record<string, number>>;\n}\n\nexport function buildBaseline(diagnostics: Diagnostic[], cwd: string): BaselineData {\n const rules: Record<string, Record<string, number>> = {};\n for (const diagnostic of diagnostics) {\n const file = relative(cwd, diagnostic.file);\n rules[file] ??= {};\n const forFile = rules[file];\n forFile[diagnostic.ruleId] = (forFile[diagnostic.ruleId] ?? 0) + 1;\n }\n return { version: 1, rules };\n}\n\nexport function writeBaseline(baseline: BaselineData, cwd: string): string {\n const path = resolve(cwd, BASELINE_FILENAME);\n writeFileSync(path, `${JSON.stringify(baseline, null, 2)}\\n`, \"utf8\");\n return path;\n}\n\nexport function loadBaseline(cwd: string): BaselineData | null {\n const path = resolve(cwd, BASELINE_FILENAME);\n if (!existsSync(path)) return null;\n const parsed: unknown = JSON.parse(readFileSync(path, \"utf8\"));\n if (!isBaselineData(parsed)) {\n throw new Error(`Invalid baseline in ${BASELINE_FILENAME}: expected {\"version\": 1, \"rules\": {<file>: {<ruleId>: count}}}.`);\n }\n return parsed;\n}\n\nfunction isBaselineData(value: unknown): value is BaselineData {\n if (typeof value !== \"object\" || value === null) return false;\n if (!(\"version\" in value) || value.version !== 1) return false;\n if (!(\"rules\" in value) || typeof value.rules !== \"object\" || value.rules === null) return false;\n return Object.values(value.rules).every(\n (forFile) =>\n typeof forFile === \"object\" &&\n forFile !== null &&\n Object.values(forFile).every((count) => typeof count === \"number\"),\n );\n}\n\n/** Drop diagnostic groups still within their baselined count. */\nexport function applyBaseline(diagnostics: Diagnostic[], baseline: BaselineData, cwd: string): Diagnostic[] {\n const groups = new Map<string, Diagnostic[]>();\n for (const diagnostic of diagnostics) {\n const key = `${relative(cwd, diagnostic.file)}\\0${diagnostic.ruleId}`;\n let list = groups.get(key);\n if (list === undefined) {\n list = [];\n groups.set(key, list);\n }\n list.push(diagnostic);\n }\n\n const kept: Diagnostic[] = [];\n for (const [key, group] of groups) {\n const [file, ruleId] = key.split(\"\\0\") as [string, string];\n const allowed = baseline.rules[file]?.[ruleId] ?? 0;\n if (group.length <= allowed) continue;\n kept.push(...group);\n }\n return kept;\n}\n","import { relative } from \"node:path\";\nimport ignore from \"ignore\";\nimport type { Diagnostic, Rule } from \"../rules/types.ts\";\nimport { getRuleMetadata } from \"../rules/index.ts\";\nimport { applyBaseline } from \"./baseline.ts\";\nimport type {\n ResolvedRuleOverride,\n ResolvedScanConfig,\n RuleDescriptor,\n RulePolicySeverity,\n ScanExecutionResult,\n ScanResult,\n Severity,\n} from \"./types.ts\";\n\nexport function buildRuleDescriptors(rules: Rule[]): RuleDescriptor[] {\n return rules.map((rule) => {\n const metadata = getRuleMetadata(rule.id);\n return {\n rule,\n category: metadata.category,\n tags: metadata.tags,\n confidence: metadata.confidence,\n };\n });\n}\n\nexport function resolveActiveRules(\n descriptors: RuleDescriptor[],\n config: ResolvedScanConfig,\n): Rule[] {\n const selectedRules = config.rules ? new Set(config.rules) : null;\n const wantedConfidence = config.mode === \"audit\" ? \"heuristic\" : \"proven\";\n const active: Rule[] = [];\n\n for (const descriptor of descriptors) {\n if (selectedRules) {\n // An explicit rule filter names what to run; the mode split is moot.\n if (!selectedRules.has(descriptor.rule.id)) continue;\n } else if (descriptor.confidence !== wantedConfidence) {\n continue;\n }\n const resolvedSeverity = resolveRuleSeverity(descriptor, config);\n if (resolvedSeverity === \"off\") continue;\n if (descriptor.rule.severity === resolvedSeverity) {\n active.push(descriptor.rule);\n continue;\n }\n active.push({ ...descriptor.rule, severity: resolvedSeverity });\n }\n\n return active;\n}\n\nfunction resolveRuleSeverity(descriptor: RuleDescriptor, config: ResolvedScanConfig): RulePolicySeverity {\n let severity: RulePolicySeverity = descriptor.rule.severity;\n for (const entry of config.rulePolicy) {\n if (!matchesSelector(descriptor, entry.selector)) continue;\n severity = entry.severity;\n }\n\n if (severity === \"off\") return \"off\";\n if (config.strict) return \"error\";\n return severity;\n}\n\nfunction matchesSelector(\n descriptor: Pick<RuleDescriptor, \"category\" | \"tags\" | \"confidence\"> & { rule: { id: string } },\n selector: string,\n): boolean {\n if (selector.startsWith(\"category:\")) {\n return descriptor.category === selector.slice(\"category:\".length);\n }\n if (selector.startsWith(\"tag:\")) {\n return descriptor.tags.includes(selector.slice(\"tag:\".length));\n }\n if (selector.startsWith(\"confidence:\")) {\n return descriptor.confidence === selector.slice(\"confidence:\".length);\n }\n if (selector === descriptor.rule.id) return true;\n if (!selector.includes(\"*\")) return false;\n const regex = new RegExp(`^${escapeRegex(selector).replaceAll(\"\\\\*\", \".*\")}$`);\n return regex.test(descriptor.rule.id);\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport function finalizeScanResult(\n diagnostics: Diagnostic[],\n fileCount: number,\n config: ResolvedScanConfig,\n): ScanExecutionResult {\n // `diagnostics` stays raw (and cached raw); overrides and the baseline\n // ratchet only shape what is reported and what fails the run.\n const afterOverrides = applyOverrides(diagnostics, config.overrides, process.cwd());\n const effective = config.baseline\n ? applyBaseline(afterOverrides, config.baseline, process.cwd())\n : afterOverrides;\n const visibleDiagnostics = config.showSeverities\n ? effective.filter((d) => config.showSeverities?.has(d.severity))\n : effective;\n\n return {\n diagnostics,\n visibleDiagnostics,\n fileCount,\n exitCode: computeExitCode(effective, config.failOn),\n };\n}\n\n/**\n * Re-resolve severities per file: each override whose globs (gitignore\n * syntax, matched against the cwd-relative path) cover the diagnostic's file\n * applies its rule policy on top of the already-resolved severity. `off`\n * drops the diagnostic.\n */\nexport function applyOverrides(\n diagnostics: Diagnostic[],\n overrides: ResolvedRuleOverride[],\n cwd: string,\n): Diagnostic[] {\n if (overrides.length === 0) return diagnostics;\n const matchers = overrides.map((entry) => ({\n matcher: ignore().add(entry.files),\n rulePolicy: entry.rulePolicy,\n }));\n\n const result: Diagnostic[] = [];\n for (const diagnostic of diagnostics) {\n const relPath = relative(cwd, diagnostic.file).replaceAll(\"\\\\\", \"/\");\n const metadata = getRuleMetadata(diagnostic.ruleId);\n const descriptor = {\n rule: { id: diagnostic.ruleId },\n category: metadata.category,\n tags: metadata.tags,\n confidence: metadata.confidence,\n };\n\n let severity: RulePolicySeverity = diagnostic.severity;\n for (const { matcher, rulePolicy } of matchers) {\n if (relPath.startsWith(\"..\") || !matcher.ignores(relPath)) continue;\n for (const entry of rulePolicy) {\n if (!matchesSelector(descriptor, entry.selector)) continue;\n severity = entry.severity;\n }\n }\n\n if (severity === \"off\") continue;\n result.push(severity === diagnostic.severity ? diagnostic : { ...diagnostic, severity });\n }\n return result;\n}\n\nexport function toScanResult(execution: ScanExecutionResult): ScanResult {\n return {\n diagnostics: execution.diagnostics,\n fileCount: execution.fileCount,\n };\n}\n\nexport function computeExitCode(diagnostics: Diagnostic[], failOn: \"none\" | Severity): number {\n if (failOn === \"none\") return 0;\n\n const hasError = diagnostics.some((d) => d.severity === \"error\");\n const hasWarning = diagnostics.some((d) => d.severity === \"warning\");\n const hasInfo = diagnostics.some((d) => d.severity === \"info\");\n\n if (failOn === \"error\") return hasError ? 2 : 0;\n if (failOn === \"warning\") {\n if (hasError) return 2;\n return hasWarning ? 1 : 0;\n }\n\n if (hasError) return 2;\n if (hasWarning || hasInfo) return 1;\n return 0;\n}\n","import { availableParallelism } from \"node:os\";\nimport { allRules } from \"./rules/index.ts\";\nimport { analyzeFiles } from \"./scan/analyze.ts\";\nimport { cacheCovers, computeScanKey, hashFiles, readScanCache, resolveCacheDir, writeScanCache } from \"./scan/cache.ts\";\nimport { resolveScanConfig } from \"./scan/config.ts\";\nimport { discoverFiles } from \"./scan/discover.ts\";\nimport { buildRuleDescriptors, finalizeScanResult, resolveActiveRules, toScanResult } from \"./scan/policy.ts\";\nimport type { ScanExecutionResult, ScanOptions, ScanResult } from \"./scan/types.ts\";\n\nexport type {\n FailOn,\n RulePolicy,\n RulePolicyEntry,\n RulePolicySeverity,\n ScanExecutionResult,\n ScanOptions,\n ScanResult,\n Severity,\n} from \"./scan/types.ts\";\n\nconst UNGUARD_VERSION = \"0.16.0\";\n\nexport async function executeScan(options: ScanOptions): Promise<ScanExecutionResult> {\n const config = resolveScanConfig(options);\n const files = await discoverFiles(config);\n const descriptors = buildRuleDescriptors(allRules);\n const activeRules = resolveActiveRules(descriptors, config);\n\n const cacheDir = config.cache ? resolveCacheDir(process.cwd()) : null;\n if (cacheDir !== null) {\n const scanKey = computeScanKey({\n unguardVersion: UNGUARD_VERSION,\n rules: activeRules,\n paths: config.paths,\n ignore: config.ignore,\n strict: config.strict,\n failOn: config.failOn,\n showSeverities: config.showSeverities,\n });\n const cached = readScanCache(cacheDir);\n const sortedFiles = [...files].sort();\n const currentHashes = hashFiles(sortedFiles, cached?.fileHashes ?? null);\n\n if (cached !== null && cacheCovers(cached, { unguardVersion: UNGUARD_VERSION, scanKey }, currentHashes)) {\n return finalizeScanResult(cached.diagnostics, cached.fileCount, config);\n }\n\n const concurrency = resolveDefaultConcurrency(config.concurrency);\n const diagnostics = await analyzeFiles(files, activeRules, { concurrency });\n writeScanCache(cacheDir, {\n version: 1,\n unguardVersion: UNGUARD_VERSION,\n scanKey,\n fileHashes: currentHashes,\n diagnostics,\n fileCount: files.length,\n });\n return finalizeScanResult(diagnostics, files.length, config);\n }\n\n const concurrency = resolveDefaultConcurrency(config.concurrency);\n const diagnostics = await analyzeFiles(files, activeRules, { concurrency });\n return finalizeScanResult(diagnostics, files.length, config);\n}\n\nfunction resolveDefaultConcurrency(requested: number | undefined): number {\n if (requested !== undefined) {\n if (!Number.isFinite(requested) || requested < 1) return 1;\n return Math.floor(requested);\n }\n // Each worker holds its own ts.Program; cap at half the CPUs to avoid memory blow-up on shared CI.\n const cores = availableParallelism();\n return Math.min(8, Math.max(1, Math.ceil(cores / 2)));\n}\n\nexport async function scan(options: ScanOptions): Promise<ScanResult> {\n const execution = await executeScan(options);\n return toScanResult(execution);\n}\n","import { createHash } from \"node:crypto\";\nimport { existsSync, mkdirSync, readFileSync, statSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { Diagnostic, Rule } from \"../rules/types.ts\";\nimport type { Severity } from \"./types.ts\";\n\nconst CACHE_VERSION = 1;\nconst CACHE_FILENAME = \"scan-cache.json\";\n\nexport interface ScanCacheEntry {\n version: number;\n unguardVersion: string;\n /** Hash of active rules + ignore globs + paths + severity policy. Mismatch -> cache miss. */\n scanKey: string;\n /** `<size>:<mtimeNs>@<contentHash>` per file. Stat fast-path skips hashing when stat matches. */\n fileHashes: Record<string, string>;\n diagnostics: Diagnostic[];\n fileCount: number;\n}\n\nexport interface ScanKeyInput {\n unguardVersion: string;\n rules: readonly Rule[];\n paths: readonly string[];\n ignore: readonly string[];\n strict: boolean;\n failOn: string;\n showSeverities: ReadonlySet<Severity> | null;\n}\n\nexport interface CacheCheckContext {\n unguardVersion: string;\n scanKey: string;\n}\n\n/** Walk up from `startDir` to the nearest `node_modules`, returning its `.cache/unguard/v<N>` subdir. */\nexport function resolveCacheDir(startDir: string): string | null {\n let dir = startDir;\n for (;;) {\n const nm = join(dir, \"node_modules\");\n if (existsSync(nm)) return join(nm, \".cache\", \"unguard\", `v${CACHE_VERSION}`);\n const parent = join(dir, \"..\");\n if (parent === dir) return null;\n dir = parent;\n }\n}\n\nexport function computeScanKey(input: ScanKeyInput): string {\n const ruleSig = [...input.rules]\n .map((r) => `${r.id}=${r.severity}`)\n .sort()\n .join(\",\");\n const payload = JSON.stringify({\n unguardVersion: input.unguardVersion,\n ruleSig,\n paths: [...input.paths].sort(),\n ignore: [...input.ignore].sort(),\n strict: input.strict,\n failOn: input.failOn,\n showSeverities: input.showSeverities ? [...input.showSeverities].sort() : null,\n });\n return createHash(\"sha256\").update(payload).digest(\"hex\").slice(0, 16);\n}\n\nexport function hashFile(path: string, prevFingerprint: string | undefined): string {\n const s = statSync(path, { bigint: true });\n const statTag = `${s.size}:${s.mtimeNs.toString()}`;\n if (prevFingerprint !== undefined) {\n const prevStat = prevFingerprint.split(\"@\", 1)[0];\n if (prevStat === statTag) return prevFingerprint;\n }\n const buf = readFileSync(path);\n const contentHash = createHash(\"sha1\").update(buf).digest(\"hex\").slice(0, 16);\n return `${statTag}@${contentHash}`;\n}\n\nexport function hashFiles(paths: readonly string[], prev: Record<string, string> | null): Record<string, string> {\n const result: Record<string, string> = {};\n for (const path of paths) {\n result[path] = hashFile(path, prev?.[path]);\n }\n return result;\n}\n\nexport function readScanCache(dir: string): ScanCacheEntry | null {\n const path = join(dir, CACHE_FILENAME);\n if (!existsSync(path)) return null;\n\n const text = trySync(() => readFileSync(path, \"utf8\"), \"read failed\");\n if (text === null) return null;\n\n const raw = trySync(() => JSON.parse(text) as unknown, \"parse failed\");\n if (raw === null) return null;\n\n return validateScanCache(raw);\n}\n\nexport function writeScanCache(dir: string, entry: ScanCacheEntry): void {\n trySync(() => {\n mkdirSync(dir, { recursive: true });\n writeFileSync(join(dir, CACHE_FILENAME), JSON.stringify(entry));\n return true;\n }, \"write failed\");\n}\n\n/** Cache hit iff scan config matches and every file's content hash matches. Ignores stat. */\nexport function cacheCovers(\n cached: ScanCacheEntry,\n context: CacheCheckContext,\n currentHashes: Record<string, string>,\n): boolean {\n if (cached.unguardVersion !== context.unguardVersion) return false;\n if (cached.scanKey !== context.scanKey) return false;\n\n const cachedFiles = Object.keys(cached.fileHashes);\n const currentFiles = Object.keys(currentHashes);\n if (cachedFiles.length !== currentFiles.length) return false;\n\n for (const file of currentFiles) {\n const prev = cached.fileHashes[file];\n const cur = currentHashes[file];\n if (prev === undefined || cur === undefined) return false;\n if (contentHashOf(prev) !== contentHashOf(cur)) return false;\n }\n return true;\n}\n\nfunction contentHashOf(fingerprint: string): string {\n const idx = fingerprint.indexOf(\"@\");\n return idx >= 0 ? fingerprint.slice(idx + 1) : fingerprint;\n}\n\nfunction validateScanCache(raw: unknown): ScanCacheEntry | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const entry = raw as Record<string, unknown>;\n if (entry.version !== CACHE_VERSION) return null;\n if (typeof entry.scanKey !== \"string\") return null;\n if (typeof entry.unguardVersion !== \"string\") return null;\n if (typeof entry.fileCount !== \"number\") return null;\n\n const fileHashes = validateFileHashes(entry.fileHashes);\n if (fileHashes === null) return null;\n\n const diagnostics = validateDiagnostics(entry.diagnostics);\n if (diagnostics === null) return null;\n\n return {\n version: entry.version,\n unguardVersion: entry.unguardVersion,\n scanKey: entry.scanKey,\n fileHashes,\n diagnostics,\n fileCount: entry.fileCount,\n };\n}\n\nfunction validateFileHashes(raw: unknown): Record<string, string> | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const result: Record<string, string> = {};\n for (const [key, value] of Object.entries(raw)) {\n if (typeof value !== \"string\") return null;\n result[key] = value;\n }\n return result;\n}\n\nfunction validateDiagnostics(raw: unknown): Diagnostic[] | null {\n if (!Array.isArray(raw)) return null;\n const list: Diagnostic[] = [];\n for (const item of raw) {\n const diag = validateDiagnostic(item);\n if (diag === null) return null;\n list.push(diag);\n }\n return list;\n}\n\nfunction validateDiagnostic(item: unknown): Diagnostic | null {\n if (typeof item !== \"object\" || item === null) return null;\n if (!(\"file\" in item) || typeof item.file !== \"string\") return null;\n if (!(\"ruleId\" in item) || typeof item.ruleId !== \"string\") return null;\n if (!(\"line\" in item) || typeof item.line !== \"number\") return null;\n if (!(\"column\" in item) || typeof item.column !== \"number\") return null;\n if (!(\"severity\" in item)) return null;\n if (item.severity !== \"error\" && item.severity !== \"warning\" && item.severity !== \"info\") return null;\n if (!(\"message\" in item) || typeof item.message !== \"string\") return null;\n const annotation = \"annotation\" in item ? item.annotation : undefined;\n if (annotation !== undefined && typeof annotation !== \"string\") return null;\n return {\n file: item.file,\n ruleId: item.ruleId,\n line: item.line,\n column: item.column,\n severity: item.severity,\n message: item.message,\n annotation,\n };\n}\n\nfunction trySync<T>(fn: () => T, label: string): T | null {\n try {\n return fn();\n } catch (err) {\n return debugLog(label, err);\n }\n}\n\nfunction debugLog(label: string, err: unknown): null {\n if (process.env.UNGUARD_DEBUG !== undefined) {\n console.error(`[unguard] cache ${label}:`, err);\n }\n return null;\n}\n","import fg from \"fast-glob\";\nimport ignore from \"ignore\";\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { relative, resolve, sep } from \"node:path\";\nimport type { ResolvedScanConfig } from \"./types.ts\";\n\nexport async function discoverFiles(config: ResolvedScanConfig): Promise<string[]> {\n const globs = expandGlobs(config.paths);\n const discoveredFiles = await fg(globs, {\n ignore: config.ignore,\n absolute: true,\n });\n if (!config.useGitIgnore) return discoveredFiles;\n return applyGitIgnore(discoveredFiles);\n}\n\nfunction expandGlobs(paths: string[]): string[] {\n return paths.map((p) => {\n if (p === \".\") return \"./**/*.{ts,cts,mts,tsx}\";\n if (p.endsWith(\"/\")) return `${p}**/*.{ts,cts,mts,tsx}`;\n if (!p.includes(\"*\") && !p.endsWith(\".ts\") && !p.endsWith(\".tsx\") && !p.endsWith(\".cts\") && !p.endsWith(\".mts\")) {\n return `${p}/**/*.{ts,cts,mts,tsx}`;\n }\n return p;\n });\n}\n\nfunction applyGitIgnore(files: string[]): string[] {\n const gitIgnorePath = resolve(process.cwd(), \".gitignore\");\n if (!existsSync(gitIgnorePath)) return files;\n\n const matcher = ignore().add(readFileSync(gitIgnorePath, \"utf8\"));\n return files.filter((file) => {\n const rel = relative(process.cwd(), file);\n if (rel.startsWith(\"..\")) return true;\n const normalized = rel.split(sep).join(\"/\");\n return !matcher.ignores(normalized);\n });\n}\n"],"mappings":"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","names":["ignore","relative","relative","existsSync","readFileSync","writeFileSync","ignore","existsSync","readFileSync","relative","resolve","concurrency","diagnostics"]}
|