pi-lens
Version:
Real-time code feedback for pi — LSP, linters, formatters, type-checking, structural analysis & booboo
81 lines (80 loc) • 2.98 kB
JavaScript
import * as fs from "node:fs";
import * as path from "node:path";
import { walkUpDirs } from "./path-utils.js";
// Opengrep is a fork of Semgrep and natively consumes the same rule format, so
// we discover both `.opengrep.*` (preferred) and the de-facto `.semgrep.*` rule
// files an existing repo may already carry.
export const LOCAL_OPENGREP_CONFIG_NAMES = [
".opengrep.yml",
".opengrep.yaml",
"opengrep.yml",
"opengrep.yaml",
".semgrep.yml",
".semgrep.yaml",
"semgrep.yml",
"semgrep.yaml",
];
export function findLocalOpengrepConfig(startDir) {
for (const dir of walkUpDirs(startDir || process.cwd())) {
for (const name of LOCAL_OPENGREP_CONFIG_NAMES) {
const candidate = path.join(dir, name);
if (fs.existsSync(candidate))
return candidate;
}
}
return undefined;
}
function isRegistryOrAutoConfig(config) {
return (config === "auto" || config.startsWith("p/") || config.startsWith("r/"));
}
export function normalizeOpengrepConfigArg(config, cwd) {
if (!config)
return undefined;
const trimmed = config.trim();
if (!trimmed)
return undefined;
if (isRegistryOrAutoConfig(trimmed))
return trimmed;
return path.isAbsolute(trimmed) ? trimmed : path.resolve(cwd, trimmed);
}
/**
* Decide whether Opengrep dispatch runs, and with which `--config`. The surface
* is intentionally seamless — there is no persisted `.pi-lens/opengrep.json` and
* no management command. Opengrep is enabled when EITHER:
*
* - the repo carries a rule file (`.opengrep.yml`/`.semgrep.yml`, …) — the
* rule file IS the opt-in signal; or
* - `--lens-opengrep` is set — self-sufficient: with no local/explicit config
* it defaults to `--config auto` (Opengrep's login-free Community ruleset).
*
* `--lens-opengrep-config <auto|p/pack|path>` overrides the chosen config.
*/
export function resolveOpengrepConfig(cwd, flags) {
const localConfig = findLocalOpengrepConfig(cwd);
const flagConfig = typeof flags?.config === "string" && flags.config.trim()
? flags.config.trim()
: undefined;
// A non-empty --lens-opengrep-config implies --lens-opengrep (passing a
// config is an unambiguous opt-in).
if (flags?.enabled || flagConfig) {
// Self-sufficient flag: explicit config → local rule file → `auto`.
const explicit = normalizeOpengrepConfigArg(flagConfig ?? localConfig, cwd);
return {
enabled: true,
configArg: explicit ?? "auto",
source: explicit && localConfig && !flagConfig ? "local" : "flag",
};
}
if (localConfig) {
return {
enabled: true,
configArg: localConfig,
source: "local",
};
}
return {
enabled: false,
source: "disabled",
reason: "no local opengrep config (.opengrep.yml) and --lens-opengrep not set",
};
}