unguard 0.10.3 → 0.10.4
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/cli.js +7 -1
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -69,7 +69,7 @@ async function main(argv) {
|
|
|
69
69
|
rules: values.filter ? [values.filter] : void 0,
|
|
70
70
|
ignore: ignore.length > 0 ? ignore : void 0,
|
|
71
71
|
rulePolicy: rulePolicy.length > 0 ? rulePolicy : void 0,
|
|
72
|
-
showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value :
|
|
72
|
+
showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value : config?.severity,
|
|
73
73
|
failOn: failOnResult.value
|
|
74
74
|
});
|
|
75
75
|
const diagnostics = execution.visibleDiagnostics;
|
|
@@ -249,6 +249,12 @@ function loadConfig(path) {
|
|
|
249
249
|
}
|
|
250
250
|
config.failOn = raw.failOn;
|
|
251
251
|
}
|
|
252
|
+
if (raw.severity !== void 0) {
|
|
253
|
+
if (!isStringArray(raw.severity) || !raw.severity.every(isSeverity)) {
|
|
254
|
+
throw new Error(`Invalid config in ${basename(path)}: "severity" must be an array of error, warning, info.`);
|
|
255
|
+
}
|
|
256
|
+
config.severity = raw.severity;
|
|
257
|
+
}
|
|
252
258
|
if (raw.rules !== void 0) {
|
|
253
259
|
if (typeof raw.rules !== "object" || raw.rules === null || Array.isArray(raw.rules)) {
|
|
254
260
|
throw new Error(`Invalid config in ${basename(path)}: "rules" must be an object.`);
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { basename, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport pc from \"picocolors\";\nimport { executeScan, type FailOn, type RulePolicyEntry, type RulePolicySeverity, type Severity } from \"./engine.ts\";\nimport { isFailOn, isRulePolicySeverity, isSeverity, toRulePolicyEntries } from \"./scan/config.ts\";\nimport type { RulePolicy } from \"./scan/types.ts\";\nimport type { Diagnostic } from \"./rules/types.ts\";\n\ninterface UnguardConfig {\n paths?: string[];\n ignore?: string[];\n rules?: RulePolicy;\n failOn?: FailOn;\n}\n\nexport async function main(argv: string[]): Promise<number> {\n const rawArgs = argv.slice(2);\n const userArgs = rawArgs[0] === \"scan\" ? rawArgs.slice(1) : rawArgs;\n\n const { values, positionals: cliPaths } = parseArgs({\n args: userArgs,\n options: {\n strict: { type: \"boolean\", default: false },\n filter: { type: \"string\" },\n format: { type: \"string\", default: \"grouped\" },\n severity: { type: \"string\", multiple: true, default: [] },\n ignore: { type: \"string\", multiple: true, default: [] },\n rule: { type: \"string\", multiple: true, default: [] },\n config: { type: \"string\" },\n \"fail-on\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n allowPositionals: true,\n });\n\n if (values.help) {\n printHelp();\n return 0;\n }\n\n let config: UnguardConfig | null = null;\n try {\n const configPath = findConfigPath(values.config);\n config = configPath ? loadConfig(configPath) : null;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(pc.red(message));\n return 1;\n }\n\n const rulePolicyResult = parseRulePolicyArgs(values.rule);\n if (!rulePolicyResult.ok) {\n console.error(pc.red(rulePolicyResult.message));\n return 1;\n }\n\n const severityFiltersResult = parseSeverityFilters(values.severity);\n if (!severityFiltersResult.ok) {\n console.error(pc.red(severityFiltersResult.message));\n return 1;\n }\n\n const failOnResult = resolveFailOn(values[\"fail-on\"], config?.failOn);\n if (!failOnResult.ok) {\n console.error(pc.red(failOnResult.message));\n return 1;\n }\n\n const paths = cliPaths.length > 0 ? cliPaths : config?.paths ?? [];\n const ignore = [...(config?.ignore ?? []), ...values.ignore];\n const rulePolicy = [\n ...toRulePolicyEntries(config?.rules),\n ...rulePolicyResult.value,\n ];\n\n const execution = await executeScan({\n paths,\n strict: values.strict,\n rules: values.filter ? [values.filter] : undefined,\n ignore: ignore.length > 0 ? ignore : undefined,\n rulePolicy: rulePolicy.length > 0 ? rulePolicy : undefined,\n showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value : undefined,\n failOn: failOnResult.value,\n });\n\n const diagnostics = execution.visibleDiagnostics;\n if (diagnostics.length === 0) {\n console.log(pc.green(`No issues found in ${execution.fileCount} files.`));\n return execution.exitCode;\n }\n\n if (values.format === \"flat\") {\n printDiagnosticsFlat(diagnostics);\n } else {\n printDiagnostics(diagnostics);\n }\n printSummary(diagnostics, execution.fileCount);\n\n return execution.exitCode;\n}\n\nfunction printHelp() {\n console.log(`unguard: data-shape static analyzer\n\nUsage:\n unguard scan [paths...] [options]\n unguard [paths...] [options]\n\nOptions:\n --config <path> Path to unguard config file (defaults to ./unguard.config.json)\n --strict Treat all diagnostics as errors\n --filter <rule> Run only the specified rule\n --rule <sel=sev> Override rule severity (supports id, *, category:<name>, tag:<name>)\n --ignore <glob> Ignore path glob. Repeatable.\n --severity <levels> Filter output by severity (comma-separated and/or repeatable)\n --fail-on <level> Exit threshold: none, error, warning, info (default: info)\n --format <mode> Output format: grouped (default) or flat\n -h, --help Show this help\n\nExit codes:\n 0 Clean, or does not meet --fail-on threshold\n 1 Meets threshold without errors\n 2 Meets threshold with at least one error\n\nExamples:\n unguard scan src\n unguard scan src --rule duplicate-*=warning\n unguard scan src --rule category:cross-file=warning\n unguard scan src --rule tag:safety=error\n unguard scan src --severity=error,warning\n unguard scan src --fail-on=error`);\n}\n\nfunction printDiagnostics(diagnostics: Diagnostic[]) {\n const byFile = new Map<string, Diagnostic[]>();\n for (const diagnostic of diagnostics) {\n let list = byFile.get(diagnostic.file);\n if (list === undefined) {\n list = [];\n byFile.set(diagnostic.file, list);\n }\n list.push(diagnostic);\n }\n\n const cwd = `${process.cwd()}/`;\n const cwdBase = process.cwd();\n\n for (const [file, fileDiagnostics] of byFile) {\n const rel = relative(cwdBase, file);\n console.log(pc.underline(rel));\n\n for (const diagnostic of fileDiagnostics) {\n const loc = `${diagnostic.line}:${diagnostic.column}`;\n const sev = diagnostic.severity === \"error\"\n ? pc.red(\"error\")\n : diagnostic.severity === \"warning\"\n ? pc.yellow(\"warning\")\n : pc.blue(\"info\");\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n const rule = pc.dim(diagnostic.ruleId);\n const annotation = diagnostic.annotation !== undefined ? ` ${pc.cyan(diagnostic.annotation)}` : \"\";\n console.log(` ${pc.dim(loc.padEnd(10))} ${sev} ${msg} ${rule}${annotation}`);\n }\n\n console.log();\n }\n}\n\nfunction printDiagnosticsFlat(diagnostics: Diagnostic[]) {\n const cwdBase = process.cwd();\n const cwd = `${cwdBase}/`;\n\n for (const diagnostic of diagnostics) {\n const rel = relative(cwdBase, diagnostic.file);\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n console.log(`${rel}:${diagnostic.line}:${diagnostic.column} ${diagnostic.severity} [${diagnostic.ruleId}] ${msg}`);\n }\n}\n\nfunction printSummary(diagnostics: Diagnostic[], fileCount: number) {\n const counts = new Map<string, number>();\n for (const diagnostic of diagnostics) {\n const prev = counts.get(diagnostic.ruleId);\n counts.set(diagnostic.ruleId, (prev === undefined ? 0 : prev) + 1);\n }\n\n const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);\n const maxRule = Math.max(...sorted.map(([rule]) => rule.length));\n\n console.log(pc.bold(\"Summary\"));\n for (const [rule, count] of sorted) {\n console.log(` ${rule.padEnd(maxRule)} ${pc.bold(String(count))}`);\n }\n\n console.log(\n `\\n${pc.bold(String(diagnostics.length))} issue${diagnostics.length === 1 ? \"\" : \"s\"} in ${fileCount} files.`,\n );\n}\n\nfunction parseSeverityFilters(values: string[]): { ok: true; value: Severity[] } | { ok: false; message: string } {\n const levels = splitCsv(values);\n const parsed: Severity[] = [];\n for (const value of levels) {\n if (!isSeverity(value)) {\n return { ok: false, message: `Invalid --severity value \"${value}\". Use error, warning, info.` };\n }\n parsed.push(value);\n }\n return { ok: true, value: parsed };\n}\n\nfunction parseRulePolicyArgs(values: string[]): { ok: true; value: RulePolicyEntry[] } | { ok: false; message: string } {\n const entries: RulePolicyEntry[] = [];\n\n for (const arg of values) {\n const separator = resolveRuleSeparator(arg);\n if (separator === null) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Use <selector>=<off|info|warning|error>.` };\n }\n\n const selector = arg.slice(0, separator).trim();\n const severity = arg.slice(separator + 1).trim();\n if (!selector) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Rule selector is required.` };\n }\n if (!isRulePolicySeverity(severity)) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Severity must be off, info, warning, or error.` };\n }\n\n entries.push({ selector, severity });\n }\n\n return { ok: true, value: entries };\n}\n\nfunction resolveRuleSeparator(value: string): number | null {\n const equalIndex = value.indexOf(\"=\");\n if (equalIndex >= 0) return equalIndex;\n const colonIndex = value.lastIndexOf(\":\");\n if (colonIndex <= 0) return null;\n return colonIndex;\n}\n\nfunction splitCsv(values: string[]): string[] {\n return values\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n}\n\nfunction findConfigPath(cliValue: string | undefined): string | null {\n if (cliValue) {\n const explicitPath = resolve(process.cwd(), cliValue);\n if (!existsSync(explicitPath)) throw new Error(`Config file not found: ${cliValue}`);\n return explicitPath;\n }\n\n const candidates = [\"unguard.config.json\", \".unguardrc.json\"];\n for (const candidate of candidates) {\n const candidatePath = resolve(process.cwd(), candidate);\n if (existsSync(candidatePath)) return candidatePath;\n }\n return null;\n}\n\nfunction loadConfig(path: string): UnguardConfig {\n const text = readFileSync(path, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Invalid JSON in ${basename(path)}: ${message}`);\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid config in ${basename(path)}: expected a JSON object.`);\n }\n\n const raw = parsed as Record<string, unknown>;\n const config: UnguardConfig = {};\n\n if (raw.paths !== undefined) {\n if (!isStringArray(raw.paths)) throw new Error(`Invalid config in ${basename(path)}: \"paths\" must be a string array.`);\n config.paths = raw.paths;\n }\n\n if (raw.ignore !== undefined) {\n if (!isStringArray(raw.ignore)) throw new Error(`Invalid config in ${basename(path)}: \"ignore\" must be a string array.`);\n config.ignore = raw.ignore;\n }\n\n if (raw.failOn !== undefined) {\n if (typeof raw.failOn !== \"string\" || !isFailOn(raw.failOn)) {\n throw new Error(`Invalid config in ${basename(path)}: \"failOn\" must be one of none, error, warning, info.`);\n }\n config.failOn = raw.failOn;\n }\n\n if (raw.rules !== undefined) {\n if (typeof raw.rules !== \"object\" || raw.rules === null || Array.isArray(raw.rules)) {\n throw new Error(`Invalid config in ${basename(path)}: \"rules\" must be an object.`);\n }\n\n const rules: Record<string, RulePolicySeverity> = {};\n for (const [selector, severity] of Object.entries(raw.rules as Record<string, unknown>)) {\n if (typeof severity !== \"string\" || !isRulePolicySeverity(severity)) {\n throw new Error(`Invalid config in ${basename(path)}: rule \"${selector}\" must be off, info, warning, or error.`);\n }\n rules[selector] = severity;\n }\n config.rules = rules;\n }\n\n return config;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction resolveFailOn(\n cliValue: string | undefined,\n configValue: FailOn | undefined,\n): { ok: true; value: FailOn } | { ok: false; message: string } {\n const selected = cliValue ?? configValue ?? \"info\";\n if (!isFailOn(selected)) {\n return { ok: false, message: `Invalid --fail-on value \"${selected}\". Use none, error, warning, or info.` };\n }\n return { ok: true, value: selected };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/cli.ts"],"sourcesContent":["import { existsSync, readFileSync } from \"node:fs\";\nimport { basename, relative, resolve } from \"node:path\";\nimport { parseArgs } from \"node:util\";\nimport pc from \"picocolors\";\nimport { executeScan, type FailOn, type RulePolicyEntry, type RulePolicySeverity, type Severity } from \"./engine.ts\";\nimport { isFailOn, isRulePolicySeverity, isSeverity, toRulePolicyEntries } from \"./scan/config.ts\";\nimport type { RulePolicy } from \"./scan/types.ts\";\nimport type { Diagnostic } from \"./rules/types.ts\";\n\ninterface UnguardConfig {\n paths?: string[];\n ignore?: string[];\n rules?: RulePolicy;\n failOn?: FailOn;\n severity?: Severity[];\n}\n\nexport async function main(argv: string[]): Promise<number> {\n const rawArgs = argv.slice(2);\n const userArgs = rawArgs[0] === \"scan\" ? rawArgs.slice(1) : rawArgs;\n\n const { values, positionals: cliPaths } = parseArgs({\n args: userArgs,\n options: {\n strict: { type: \"boolean\", default: false },\n filter: { type: \"string\" },\n format: { type: \"string\", default: \"grouped\" },\n severity: { type: \"string\", multiple: true, default: [] },\n ignore: { type: \"string\", multiple: true, default: [] },\n rule: { type: \"string\", multiple: true, default: [] },\n config: { type: \"string\" },\n \"fail-on\": { type: \"string\" },\n help: { type: \"boolean\", short: \"h\", default: false },\n },\n allowPositionals: true,\n });\n\n if (values.help) {\n printHelp();\n return 0;\n }\n\n let config: UnguardConfig | null = null;\n try {\n const configPath = findConfigPath(values.config);\n config = configPath ? loadConfig(configPath) : null;\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n console.error(pc.red(message));\n return 1;\n }\n\n const rulePolicyResult = parseRulePolicyArgs(values.rule);\n if (!rulePolicyResult.ok) {\n console.error(pc.red(rulePolicyResult.message));\n return 1;\n }\n\n const severityFiltersResult = parseSeverityFilters(values.severity);\n if (!severityFiltersResult.ok) {\n console.error(pc.red(severityFiltersResult.message));\n return 1;\n }\n\n const failOnResult = resolveFailOn(values[\"fail-on\"], config?.failOn);\n if (!failOnResult.ok) {\n console.error(pc.red(failOnResult.message));\n return 1;\n }\n\n const paths = cliPaths.length > 0 ? cliPaths : config?.paths ?? [];\n const ignore = [...(config?.ignore ?? []), ...values.ignore];\n const rulePolicy = [\n ...toRulePolicyEntries(config?.rules),\n ...rulePolicyResult.value,\n ];\n\n const execution = await executeScan({\n paths,\n strict: values.strict,\n rules: values.filter ? [values.filter] : undefined,\n ignore: ignore.length > 0 ? ignore : undefined,\n rulePolicy: rulePolicy.length > 0 ? rulePolicy : undefined,\n showSeverities: severityFiltersResult.value.length > 0 ? severityFiltersResult.value : config?.severity,\n failOn: failOnResult.value,\n });\n\n const diagnostics = execution.visibleDiagnostics;\n if (diagnostics.length === 0) {\n console.log(pc.green(`No issues found in ${execution.fileCount} files.`));\n return execution.exitCode;\n }\n\n if (values.format === \"flat\") {\n printDiagnosticsFlat(diagnostics);\n } else {\n printDiagnostics(diagnostics);\n }\n printSummary(diagnostics, execution.fileCount);\n\n return execution.exitCode;\n}\n\nfunction printHelp() {\n console.log(`unguard: data-shape static analyzer\n\nUsage:\n unguard scan [paths...] [options]\n unguard [paths...] [options]\n\nOptions:\n --config <path> Path to unguard config file (defaults to ./unguard.config.json)\n --strict Treat all diagnostics as errors\n --filter <rule> Run only the specified rule\n --rule <sel=sev> Override rule severity (supports id, *, category:<name>, tag:<name>)\n --ignore <glob> Ignore path glob. Repeatable.\n --severity <levels> Filter output by severity (comma-separated and/or repeatable)\n --fail-on <level> Exit threshold: none, error, warning, info (default: info)\n --format <mode> Output format: grouped (default) or flat\n -h, --help Show this help\n\nExit codes:\n 0 Clean, or does not meet --fail-on threshold\n 1 Meets threshold without errors\n 2 Meets threshold with at least one error\n\nExamples:\n unguard scan src\n unguard scan src --rule duplicate-*=warning\n unguard scan src --rule category:cross-file=warning\n unguard scan src --rule tag:safety=error\n unguard scan src --severity=error,warning\n unguard scan src --fail-on=error`);\n}\n\nfunction printDiagnostics(diagnostics: Diagnostic[]) {\n const byFile = new Map<string, Diagnostic[]>();\n for (const diagnostic of diagnostics) {\n let list = byFile.get(diagnostic.file);\n if (list === undefined) {\n list = [];\n byFile.set(diagnostic.file, list);\n }\n list.push(diagnostic);\n }\n\n const cwd = `${process.cwd()}/`;\n const cwdBase = process.cwd();\n\n for (const [file, fileDiagnostics] of byFile) {\n const rel = relative(cwdBase, file);\n console.log(pc.underline(rel));\n\n for (const diagnostic of fileDiagnostics) {\n const loc = `${diagnostic.line}:${diagnostic.column}`;\n const sev = diagnostic.severity === \"error\"\n ? pc.red(\"error\")\n : diagnostic.severity === \"warning\"\n ? pc.yellow(\"warning\")\n : pc.blue(\"info\");\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n const rule = pc.dim(diagnostic.ruleId);\n const annotation = diagnostic.annotation !== undefined ? ` ${pc.cyan(diagnostic.annotation)}` : \"\";\n console.log(` ${pc.dim(loc.padEnd(10))} ${sev} ${msg} ${rule}${annotation}`);\n }\n\n console.log();\n }\n}\n\nfunction printDiagnosticsFlat(diagnostics: Diagnostic[]) {\n const cwdBase = process.cwd();\n const cwd = `${cwdBase}/`;\n\n for (const diagnostic of diagnostics) {\n const rel = relative(cwdBase, diagnostic.file);\n const msg = diagnostic.message.replaceAll(cwd, \"\");\n console.log(`${rel}:${diagnostic.line}:${diagnostic.column} ${diagnostic.severity} [${diagnostic.ruleId}] ${msg}`);\n }\n}\n\nfunction printSummary(diagnostics: Diagnostic[], fileCount: number) {\n const counts = new Map<string, number>();\n for (const diagnostic of diagnostics) {\n const prev = counts.get(diagnostic.ruleId);\n counts.set(diagnostic.ruleId, (prev === undefined ? 0 : prev) + 1);\n }\n\n const sorted = [...counts.entries()].sort((a, b) => b[1] - a[1]);\n const maxRule = Math.max(...sorted.map(([rule]) => rule.length));\n\n console.log(pc.bold(\"Summary\"));\n for (const [rule, count] of sorted) {\n console.log(` ${rule.padEnd(maxRule)} ${pc.bold(String(count))}`);\n }\n\n console.log(\n `\\n${pc.bold(String(diagnostics.length))} issue${diagnostics.length === 1 ? \"\" : \"s\"} in ${fileCount} files.`,\n );\n}\n\nfunction parseSeverityFilters(values: string[]): { ok: true; value: Severity[] } | { ok: false; message: string } {\n const levels = splitCsv(values);\n const parsed: Severity[] = [];\n for (const value of levels) {\n if (!isSeverity(value)) {\n return { ok: false, message: `Invalid --severity value \"${value}\". Use error, warning, info.` };\n }\n parsed.push(value);\n }\n return { ok: true, value: parsed };\n}\n\nfunction parseRulePolicyArgs(values: string[]): { ok: true; value: RulePolicyEntry[] } | { ok: false; message: string } {\n const entries: RulePolicyEntry[] = [];\n\n for (const arg of values) {\n const separator = resolveRuleSeparator(arg);\n if (separator === null) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Use <selector>=<off|info|warning|error>.` };\n }\n\n const selector = arg.slice(0, separator).trim();\n const severity = arg.slice(separator + 1).trim();\n if (!selector) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Rule selector is required.` };\n }\n if (!isRulePolicySeverity(severity)) {\n return { ok: false, message: `Invalid --rule value \"${arg}\". Severity must be off, info, warning, or error.` };\n }\n\n entries.push({ selector, severity });\n }\n\n return { ok: true, value: entries };\n}\n\nfunction resolveRuleSeparator(value: string): number | null {\n const equalIndex = value.indexOf(\"=\");\n if (equalIndex >= 0) return equalIndex;\n const colonIndex = value.lastIndexOf(\":\");\n if (colonIndex <= 0) return null;\n return colonIndex;\n}\n\nfunction splitCsv(values: string[]): string[] {\n return values\n .flatMap((value) => value.split(\",\"))\n .map((value) => value.trim())\n .filter((value) => value.length > 0);\n}\n\nfunction findConfigPath(cliValue: string | undefined): string | null {\n if (cliValue) {\n const explicitPath = resolve(process.cwd(), cliValue);\n if (!existsSync(explicitPath)) throw new Error(`Config file not found: ${cliValue}`);\n return explicitPath;\n }\n\n const candidates = [\"unguard.config.json\", \".unguardrc.json\"];\n for (const candidate of candidates) {\n const candidatePath = resolve(process.cwd(), candidate);\n if (existsSync(candidatePath)) return candidatePath;\n }\n return null;\n}\n\nfunction loadConfig(path: string): UnguardConfig {\n const text = readFileSync(path, \"utf8\");\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch (err) {\n const message = err instanceof Error ? err.message : String(err);\n throw new Error(`Invalid JSON in ${basename(path)}: ${message}`);\n }\n\n if (typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) {\n throw new Error(`Invalid config in ${basename(path)}: expected a JSON object.`);\n }\n\n const raw = parsed as Record<string, unknown>;\n const config: UnguardConfig = {};\n\n if (raw.paths !== undefined) {\n if (!isStringArray(raw.paths)) throw new Error(`Invalid config in ${basename(path)}: \"paths\" must be a string array.`);\n config.paths = raw.paths;\n }\n\n if (raw.ignore !== undefined) {\n if (!isStringArray(raw.ignore)) throw new Error(`Invalid config in ${basename(path)}: \"ignore\" must be a string array.`);\n config.ignore = raw.ignore;\n }\n\n if (raw.failOn !== undefined) {\n if (typeof raw.failOn !== \"string\" || !isFailOn(raw.failOn)) {\n throw new Error(`Invalid config in ${basename(path)}: \"failOn\" must be one of none, error, warning, info.`);\n }\n config.failOn = raw.failOn;\n }\n\n if (raw.severity !== undefined) {\n if (!isStringArray(raw.severity) || !raw.severity.every(isSeverity)) {\n throw new Error(`Invalid config in ${basename(path)}: \"severity\" must be an array of error, warning, info.`);\n }\n config.severity = raw.severity as Severity[];\n }\n\n if (raw.rules !== undefined) {\n if (typeof raw.rules !== \"object\" || raw.rules === null || Array.isArray(raw.rules)) {\n throw new Error(`Invalid config in ${basename(path)}: \"rules\" must be an object.`);\n }\n\n const rules: Record<string, RulePolicySeverity> = {};\n for (const [selector, severity] of Object.entries(raw.rules as Record<string, unknown>)) {\n if (typeof severity !== \"string\" || !isRulePolicySeverity(severity)) {\n throw new Error(`Invalid config in ${basename(path)}: rule \"${selector}\" must be off, info, warning, or error.`);\n }\n rules[selector] = severity;\n }\n config.rules = rules;\n }\n\n return config;\n}\n\nfunction isStringArray(value: unknown): value is string[] {\n return Array.isArray(value) && value.every((entry) => typeof entry === \"string\");\n}\n\nfunction resolveFailOn(\n cliValue: string | undefined,\n configValue: FailOn | undefined,\n): { ok: true; value: FailOn } | { ok: false; message: string } {\n const selected = cliValue ?? configValue ?? \"info\";\n if (!isFailOn(selected)) {\n return { ok: false, message: `Invalid --fail-on value \"${selected}\". Use none, error, warning, or info.` };\n }\n return { ok: true, value: selected };\n}\n"],"mappings":";;;;;;;;;AAAA,SAAS,YAAY,oBAAoB;AACzC,SAAS,UAAU,UAAU,eAAe;AAC5C,SAAS,iBAAiB;AAC1B,OAAO,QAAQ;AAcf,eAAsB,KAAK,MAAiC;AAC1D,QAAM,UAAU,KAAK,MAAM,CAAC;AAC5B,QAAM,WAAW,QAAQ,CAAC,MAAM,SAAS,QAAQ,MAAM,CAAC,IAAI;AAE5D,QAAM,EAAE,QAAQ,aAAa,SAAS,IAAI,UAAU;AAAA,IAClD,MAAM;AAAA,IACN,SAAS;AAAA,MACP,QAAQ,EAAE,MAAM,WAAW,SAAS,MAAM;AAAA,MAC1C,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,QAAQ,EAAE,MAAM,UAAU,SAAS,UAAU;AAAA,MAC7C,UAAU,EAAE,MAAM,UAAU,UAAU,MAAM,SAAS,CAAC,EAAE;AAAA,MACxD,QAAQ,EAAE,MAAM,UAAU,UAAU,MAAM,SAAS,CAAC,EAAE;AAAA,MACtD,MAAM,EAAE,MAAM,UAAU,UAAU,MAAM,SAAS,CAAC,EAAE;AAAA,MACpD,QAAQ,EAAE,MAAM,SAAS;AAAA,MACzB,WAAW,EAAE,MAAM,SAAS;AAAA,MAC5B,MAAM,EAAE,MAAM,WAAW,OAAO,KAAK,SAAS,MAAM;AAAA,IACtD;AAAA,IACA,kBAAkB;AAAA,EACpB,CAAC;AAED,MAAI,OAAO,MAAM;AACf,cAAU;AACV,WAAO;AAAA,EACT;AAEA,MAAI,SAA+B;AACnC,MAAI;AACF,UAAM,aAAa,eAAe,OAAO,MAAM;AAC/C,aAAS,aAAa,WAAW,UAAU,IAAI;AAAA,EACjD,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,YAAQ,MAAM,GAAG,IAAI,OAAO,CAAC;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,oBAAoB,OAAO,IAAI;AACxD,MAAI,CAAC,iBAAiB,IAAI;AACxB,YAAQ,MAAM,GAAG,IAAI,iBAAiB,OAAO,CAAC;AAC9C,WAAO;AAAA,EACT;AAEA,QAAM,wBAAwB,qBAAqB,OAAO,QAAQ;AAClE,MAAI,CAAC,sBAAsB,IAAI;AAC7B,YAAQ,MAAM,GAAG,IAAI,sBAAsB,OAAO,CAAC;AACnD,WAAO;AAAA,EACT;AAEA,QAAM,eAAe,cAAc,OAAO,SAAS,GAAG,QAAQ,MAAM;AACpE,MAAI,CAAC,aAAa,IAAI;AACpB,YAAQ,MAAM,GAAG,IAAI,aAAa,OAAO,CAAC;AAC1C,WAAO;AAAA,EACT;AAEA,QAAM,QAAQ,SAAS,SAAS,IAAI,WAAW,QAAQ,SAAS,CAAC;AACjE,QAAM,SAAS,CAAC,GAAI,QAAQ,UAAU,CAAC,GAAI,GAAG,OAAO,MAAM;AAC3D,QAAM,aAAa;AAAA,IACjB,GAAG,oBAAoB,QAAQ,KAAK;AAAA,IACpC,GAAG,iBAAiB;AAAA,EACtB;AAEA,QAAM,YAAY,MAAM,YAAY;AAAA,IAClC;AAAA,IACA,QAAQ,OAAO;AAAA,IACf,OAAO,OAAO,SAAS,CAAC,OAAO,MAAM,IAAI;AAAA,IACzC,QAAQ,OAAO,SAAS,IAAI,SAAS;AAAA,IACrC,YAAY,WAAW,SAAS,IAAI,aAAa;AAAA,IACjD,gBAAgB,sBAAsB,MAAM,SAAS,IAAI,sBAAsB,QAAQ,QAAQ;AAAA,IAC/F,QAAQ,aAAa;AAAA,EACvB,CAAC;AAED,QAAM,cAAc,UAAU;AAC9B,MAAI,YAAY,WAAW,GAAG;AAC5B,YAAQ,IAAI,GAAG,MAAM,sBAAsB,UAAU,SAAS,SAAS,CAAC;AACxE,WAAO,UAAU;AAAA,EACnB;AAEA,MAAI,OAAO,WAAW,QAAQ;AAC5B,yBAAqB,WAAW;AAAA,EAClC,OAAO;AACL,qBAAiB,WAAW;AAAA,EAC9B;AACA,eAAa,aAAa,UAAU,SAAS;AAE7C,SAAO,UAAU;AACnB;AAEA,SAAS,YAAY;AACnB,UAAQ,IAAI;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,mCA4BqB;AACnC;AAEA,SAAS,iBAAiB,aAA2B;AACnD,QAAM,SAAS,oBAAI,IAA0B;AAC7C,aAAW,cAAc,aAAa;AACpC,QAAI,OAAO,OAAO,IAAI,WAAW,IAAI;AACrC,QAAI,SAAS,QAAW;AACtB,aAAO,CAAC;AACR,aAAO,IAAI,WAAW,MAAM,IAAI;AAAA,IAClC;AACA,SAAK,KAAK,UAAU;AAAA,EACtB;AAEA,QAAM,MAAM,GAAG,QAAQ,IAAI,CAAC;AAC5B,QAAM,UAAU,QAAQ,IAAI;AAE5B,aAAW,CAAC,MAAM,eAAe,KAAK,QAAQ;AAC5C,UAAM,MAAM,SAAS,SAAS,IAAI;AAClC,YAAQ,IAAI,GAAG,UAAU,GAAG,CAAC;AAE7B,eAAW,cAAc,iBAAiB;AACxC,YAAM,MAAM,GAAG,WAAW,IAAI,IAAI,WAAW,MAAM;AACnD,YAAM,MAAM,WAAW,aAAa,UAChC,GAAG,IAAI,OAAO,IACd,WAAW,aAAa,YACxB,GAAG,OAAO,SAAS,IACnB,GAAG,KAAK,MAAM;AAClB,YAAM,MAAM,WAAW,QAAQ,WAAW,KAAK,EAAE;AACjD,YAAM,OAAO,GAAG,IAAI,WAAW,MAAM;AACrC,YAAM,aAAa,WAAW,eAAe,SAAY,KAAK,GAAG,KAAK,WAAW,UAAU,CAAC,KAAK;AACjG,cAAQ,IAAI,KAAK,GAAG,IAAI,IAAI,OAAO,EAAE,CAAC,CAAC,IAAI,GAAG,KAAK,GAAG,KAAK,IAAI,GAAG,UAAU,EAAE;AAAA,IAChF;AAEA,YAAQ,IAAI;AAAA,EACd;AACF;AAEA,SAAS,qBAAqB,aAA2B;AACvD,QAAM,UAAU,QAAQ,IAAI;AAC5B,QAAM,MAAM,GAAG,OAAO;AAEtB,aAAW,cAAc,aAAa;AACpC,UAAM,MAAM,SAAS,SAAS,WAAW,IAAI;AAC7C,UAAM,MAAM,WAAW,QAAQ,WAAW,KAAK,EAAE;AACjD,YAAQ,IAAI,GAAG,GAAG,IAAI,WAAW,IAAI,IAAI,WAAW,MAAM,IAAI,WAAW,QAAQ,KAAK,WAAW,MAAM,KAAK,GAAG,EAAE;AAAA,EACnH;AACF;AAEA,SAAS,aAAa,aAA2B,WAAmB;AAClE,QAAM,SAAS,oBAAI,IAAoB;AACvC,aAAW,cAAc,aAAa;AACpC,UAAM,OAAO,OAAO,IAAI,WAAW,MAAM;AACzC,WAAO,IAAI,WAAW,SAAS,SAAS,SAAY,IAAI,QAAQ,CAAC;AAAA,EACnE;AAEA,QAAM,SAAS,CAAC,GAAG,OAAO,QAAQ,CAAC,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC;AAC/D,QAAM,UAAU,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,CAAC,IAAI,MAAM,KAAK,MAAM,CAAC;AAE/D,UAAQ,IAAI,GAAG,KAAK,SAAS,CAAC;AAC9B,aAAW,CAAC,MAAM,KAAK,KAAK,QAAQ;AAClC,YAAQ,IAAI,KAAK,KAAK,OAAO,OAAO,CAAC,KAAK,GAAG,KAAK,OAAO,KAAK,CAAC,CAAC,EAAE;AAAA,EACpE;AAEA,UAAQ;AAAA,IACN;AAAA,EAAK,GAAG,KAAK,OAAO,YAAY,MAAM,CAAC,CAAC,SAAS,YAAY,WAAW,IAAI,KAAK,GAAG,OAAO,SAAS;AAAA,EACtG;AACF;AAEA,SAAS,qBAAqB,QAAoF;AAChH,QAAM,SAAS,SAAS,MAAM;AAC9B,QAAM,SAAqB,CAAC;AAC5B,aAAW,SAAS,QAAQ;AAC1B,QAAI,CAAC,WAAW,KAAK,GAAG;AACtB,aAAO,EAAE,IAAI,OAAO,SAAS,6BAA6B,KAAK,+BAA+B;AAAA,IAChG;AACA,WAAO,KAAK,KAAK;AAAA,EACnB;AACA,SAAO,EAAE,IAAI,MAAM,OAAO,OAAO;AACnC;AAEA,SAAS,oBAAoB,QAA2F;AACtH,QAAM,UAA6B,CAAC;AAEpC,aAAW,OAAO,QAAQ;AACxB,UAAM,YAAY,qBAAqB,GAAG;AAC1C,QAAI,cAAc,MAAM;AACtB,aAAO,EAAE,IAAI,OAAO,SAAS,yBAAyB,GAAG,8CAA8C;AAAA,IACzG;AAEA,UAAM,WAAW,IAAI,MAAM,GAAG,SAAS,EAAE,KAAK;AAC9C,UAAM,WAAW,IAAI,MAAM,YAAY,CAAC,EAAE,KAAK;AAC/C,QAAI,CAAC,UAAU;AACb,aAAO,EAAE,IAAI,OAAO,SAAS,yBAAyB,GAAG,gCAAgC;AAAA,IAC3F;AACA,QAAI,CAAC,qBAAqB,QAAQ,GAAG;AACnC,aAAO,EAAE,IAAI,OAAO,SAAS,yBAAyB,GAAG,oDAAoD;AAAA,IAC/G;AAEA,YAAQ,KAAK,EAAE,UAAU,SAAS,CAAC;AAAA,EACrC;AAEA,SAAO,EAAE,IAAI,MAAM,OAAO,QAAQ;AACpC;AAEA,SAAS,qBAAqB,OAA8B;AAC1D,QAAM,aAAa,MAAM,QAAQ,GAAG;AACpC,MAAI,cAAc,EAAG,QAAO;AAC5B,QAAM,aAAa,MAAM,YAAY,GAAG;AACxC,MAAI,cAAc,EAAG,QAAO;AAC5B,SAAO;AACT;AAEA,SAAS,SAAS,QAA4B;AAC5C,SAAO,OACJ,QAAQ,CAAC,UAAU,MAAM,MAAM,GAAG,CAAC,EACnC,IAAI,CAAC,UAAU,MAAM,KAAK,CAAC,EAC3B,OAAO,CAAC,UAAU,MAAM,SAAS,CAAC;AACvC;AAEA,SAAS,eAAe,UAA6C;AACnE,MAAI,UAAU;AACZ,UAAM,eAAe,QAAQ,QAAQ,IAAI,GAAG,QAAQ;AACpD,QAAI,CAAC,WAAW,YAAY,EAAG,OAAM,IAAI,MAAM,0BAA0B,QAAQ,EAAE;AACnF,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,CAAC,uBAAuB,iBAAiB;AAC5D,aAAW,aAAa,YAAY;AAClC,UAAM,gBAAgB,QAAQ,QAAQ,IAAI,GAAG,SAAS;AACtD,QAAI,WAAW,aAAa,EAAG,QAAO;AAAA,EACxC;AACA,SAAO;AACT;AAEA,SAAS,WAAW,MAA6B;AAC/C,QAAM,OAAO,aAAa,MAAM,MAAM;AACtC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,SAAS,KAAK;AACZ,UAAM,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC/D,UAAM,IAAI,MAAM,mBAAmB,SAAS,IAAI,CAAC,KAAK,OAAO,EAAE;AAAA,EACjE;AAEA,MAAI,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,MAAM,GAAG;AAC1E,UAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,2BAA2B;AAAA,EAChF;AAEA,QAAM,MAAM;AACZ,QAAM,SAAwB,CAAC;AAE/B,MAAI,IAAI,UAAU,QAAW;AAC3B,QAAI,CAAC,cAAc,IAAI,KAAK,EAAG,OAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,mCAAmC;AACrH,WAAO,QAAQ,IAAI;AAAA,EACrB;AAEA,MAAI,IAAI,WAAW,QAAW;AAC5B,QAAI,CAAC,cAAc,IAAI,MAAM,EAAG,OAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,oCAAoC;AACvH,WAAO,SAAS,IAAI;AAAA,EACtB;AAEA,MAAI,IAAI,WAAW,QAAW;AAC5B,QAAI,OAAO,IAAI,WAAW,YAAY,CAAC,SAAS,IAAI,MAAM,GAAG;AAC3D,YAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,uDAAuD;AAAA,IAC5G;AACA,WAAO,SAAS,IAAI;AAAA,EACtB;AAEA,MAAI,IAAI,aAAa,QAAW;AAC9B,QAAI,CAAC,cAAc,IAAI,QAAQ,KAAK,CAAC,IAAI,SAAS,MAAM,UAAU,GAAG;AACnE,YAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,wDAAwD;AAAA,IAC7G;AACA,WAAO,WAAW,IAAI;AAAA,EACxB;AAEA,MAAI,IAAI,UAAU,QAAW;AAC3B,QAAI,OAAO,IAAI,UAAU,YAAY,IAAI,UAAU,QAAQ,MAAM,QAAQ,IAAI,KAAK,GAAG;AACnF,YAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,8BAA8B;AAAA,IACnF;AAEA,UAAM,QAA4C,CAAC;AACnD,eAAW,CAAC,UAAU,QAAQ,KAAK,OAAO,QAAQ,IAAI,KAAgC,GAAG;AACvF,UAAI,OAAO,aAAa,YAAY,CAAC,qBAAqB,QAAQ,GAAG;AACnE,cAAM,IAAI,MAAM,qBAAqB,SAAS,IAAI,CAAC,WAAW,QAAQ,yCAAyC;AAAA,MACjH;AACA,YAAM,QAAQ,IAAI;AAAA,IACpB;AACA,WAAO,QAAQ;AAAA,EACjB;AAEA,SAAO;AACT;AAEA,SAAS,cAAc,OAAmC;AACxD,SAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,CAAC,UAAU,OAAO,UAAU,QAAQ;AACjF;AAEA,SAAS,cACP,UACA,aAC8D;AAC9D,QAAM,WAAW,YAAY,eAAe;AAC5C,MAAI,CAAC,SAAS,QAAQ,GAAG;AACvB,WAAO,EAAE,IAAI,OAAO,SAAS,4BAA4B,QAAQ,wCAAwC;AAAA,EAC3G;AACA,SAAO,EAAE,IAAI,MAAM,OAAO,SAAS;AACrC;","names":[]}
|