"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('../_virtual/_rolldown/runtime.js');
const require_primordials_error = require('../primordials/error.js');
const require_arrays_join = require('../arrays/join.js');
let node_fs = require("node:fs");
let node_path = require("node:path");
node_path = require_runtime.__toESM(node_path);

//#region src/checks/primordials.ts
/**
* @file Primordials drift check — generic core. Each fleet repo that
*   destructures from Node's internal `primordials` global needs to keep its
*   usage shape-aligned with socket-lib's userland mirror
*   (`@socketsecurity/lib/primordials`). This module is the parser + diff
*   engine; per-repo policy (which dirs to scan, naming aliases, allowlist)
*   lives in a config the caller supplies. Used by the `socket-lib check
*   primordials` CLI subcommand. Kept importable as a library so repos with
*   bespoke needs can compose it directly without going through the CLI. The
*   flow:
*
*   1. Walk the configured `scanDirs` for `*.js` files.
*   2. From each file, extract names from every `const { Foo, Bar } = primordials`
*      destructure.
*   3. Read socket-lib's `primordials/` directory (sibling clone) or
*      `primordials/*.d.ts` (installed `node_modules`) and pull every exported
*      name across all leaves.
*   4. Diff: every destructured name must be either (a) in socket-lib verbatim,
*      (b) in socket-lib via the configured alias map, or (c) in the configured
*      node-internal-only allowlist. Findings come back classified so callers
*      can render or fail-CI on specific kinds.
*/
const NAME_HEAD_RE = /^([A-Za-z_$][A-Za-z0-9_$]*)/;
/**
* Run the primordials drift check against the configured repo. Returns the full
* result including raw inputs (used names, lib exports) so renderers can show
* context, plus a sorted list of findings classified by kind.
*/
function checkPrimordials(config) {
	const repoRoot = config.repoRoot ?? process.cwd();
	const used = /* @__PURE__ */ new Set();
	const usedToFiles = /* @__PURE__ */ new Map();
	for (const dir of config.scanDirs) {
		const jsFiles = collectJsFiles(node_path.default.resolve(repoRoot, dir));
		for (const file of jsFiles) {
			let src;
			try {
				src = (0, node_fs.readFileSync)(file, "utf8");
			} catch {
				continue;
			}
			/* c8 ignore stop */
			if (!src.includes("primordials")) continue;
			const names = extractPrimordialsNames(src);
			if (names.length === 0) continue;
			const rel = node_path.default.relative(repoRoot, file);
			for (const name of names) {
				used.add(name);
				const arr = usedToFiles.get(name) ?? [];
				if (!arr.includes(rel)) arr.push(rel);
				usedToFiles.set(name, arr);
			}
		}
	}
	const socketLibNames = readSocketLibPrimordialNames(resolveSocketLibPrimordials(config));
	const findings = [];
	for (const name of [...used].sort()) {
		if (config.nodeInternalOnly.has(name)) continue;
		if (socketLibNames.has(name)) continue;
		const aliased = config.aliasMap.get(name);
		/* c8 ignore start */
		if (aliased) {
			if (socketLibNames.has(aliased)) continue;
			findings.push({
				kind: "missing-from-socket-lib",
				name,
				files: usedToFiles.get(name) ?? [],
				hint: `\`${name}\` is mapped to socket-lib's \`${aliased}\`, but \`${aliased}\` is not exported. Add \`export const ${aliased} = ${name}\` to the appropriate leaf under socket-lib/src/primordials/.`
			});
			continue;
		}
		/* c8 ignore stop */
		findings.push({
			kind: "unmapped",
			name,
			files: usedToFiles.get(name) ?? [],
			hint: `\`${name}\` is destructured from \`primordials\` but no socket-lib mapping exists. Pick one: ` + /* @__PURE__ */ require_arrays_join.joinOr([
				`add \`${name}\` to the appropriate leaf under socket-lib/src/primordials/`,
				`add a \`${name}\` → \`<libName>\` entry to the alias map`,
				`add \`${name}\` to nodeInternalOnly (if Node-internal only)`
			]) + "."
		});
	}
	return {
		used,
		usedToFiles,
		socketLibNames,
		findings
	};
}
/**
* Recursively collect every `*.js` file under `dir`.
*/
function collectJsFiles(dir) {
	const out = [];
	if (!(0, node_fs.existsSync)(dir)) return out;
	const stack = [dir];
	while (stack.length > 0) {
		const cur = stack.pop();
		let entries;
		try {
			entries = (0, node_fs.readdirSync)(cur);
		} catch {
			continue;
		}
		for (const name of entries) {
			const full = node_path.default.join(cur, name);
			let stat;
			try {
				stat = (0, node_fs.statSync)(full);
			} catch {
				continue;
			}
			if (stat.isDirectory()) stack.push(full);
			else if (stat.isFile() && full.endsWith(".js")) out.push(full);
		}
	}
	return out;
}
/**
* Pull every `const { … } = primordials` destructure body out of `src`.
* Comments are stripped first so commentary inside a destructure doesn't leak
* into captured names. The body regex disallows nested `}`, which is safe after
* the comment-strip pass — destructures themselves don't contain `}`.
*/
function extractPrimordialsNames(src) {
	const cleaned = stripComments(src);
	const re = /const\s*\{\s*([^}]*?)\}\s*=\s*primordials\b/g;
	const out = [];
	let m;
	while ((m = re.exec(cleaned)) !== null) for (const raw of m[1].split(",")) {
		const trimmed = raw.trim();
		if (!trimmed) continue;
		const nameMatch = NAME_HEAD_RE.exec(trimmed);
		/* c8 ignore start */
		if (nameMatch) out.push(nameMatch[1]);
	}
	return out;
}
/**
* Pull every `export const Foo` / `export function Foo` / `export { Foo }` from
* a TS file. Also matches `.d.ts` declaration forms (`export declare const
* Foo`, `export declare function Foo`) since the fallback path reads
* `primordials.d.ts` from `node_modules` when no sibling clone is present.
*/
function extractTsExports(src) {
	const out = /* @__PURE__ */ new Set();
	for (const m of src.matchAll(/^export\s+(?:declare\s+)?const\s+([A-Za-z_$][A-Za-z0-9_$]*)/gm)) out.add(m[1]);
	for (const m of src.matchAll(/^export\s+(?:declare\s+)?function\s+([A-Za-z_$][A-Za-z0-9_$]*)/gm)) out.add(m[1]);
	for (const m of src.matchAll(/^export\s*\{\s*([^}]+)\}/gm)) for (const raw of m[1].split(",")) {
		const trimmed = raw.trim();
		if (!trimmed) continue;
		const nameMatch = NAME_HEAD_RE.exec(trimmed);
		/* c8 ignore start */
		if (nameMatch) out.add(nameMatch[1]);
	}
	return [...out];
}
/**
* Read TS exports from a resolved primordials path. Handles both the legacy
* single-file layout (returns one file's exports) and the post-split directory
* layout (concatenates exports across every `*.ts` / `*.d.ts` leaf).
*/
function readSocketLibPrimordialNames(resolved) {
	if ((0, node_fs.statSync)(resolved).isFile()) return new Set(extractTsExports((0, node_fs.readFileSync)(resolved, "utf8")));
	const out = /* @__PURE__ */ new Set();
	/* c8 ignore start */
	for (const name of (0, node_fs.readdirSync)(resolved)) {
		if (!name.endsWith(".ts") && !name.endsWith(".d.ts")) continue;
		const full = node_path.default.join(resolved, name);
		if (!(0, node_fs.statSync)(full).isFile()) continue;
		for (const exp of extractTsExports((0, node_fs.readFileSync)(full, "utf8"))) out.add(exp);
	}
	/* c8 ignore stop */
	return out;
}
/**
* Locate socket-lib's primordials source. Search order:
*
* 1. `config.socketLibPrimordialsPath` if explicitly set. Accepts either a single
*    file (legacy `primordials.ts` / `.d.ts`) or a directory of leaves
*    (`primordials/`).
* 2. Sibling clone — `<repoRoot>/../socket-lib/src/primordials/` (post-split
*    layout) or `<repoRoot>/../socket-lib/src/primordials.ts` (legacy
*    single-file layout). Preferred for the dev-loop case where a developer is
*    editing socket-lib and a consumer in parallel.
* 3. Installed copy — `<repoRoot>/node_modules/@socketsecurity/lib/
*    dist/primordials/` (post-split) or `<repoRoot>/node_modules/
*    @socketsecurity/lib/dist/primordials.d.ts` (legacy). The CI fallback.
*
* Throws when none of the candidates exist.
*/
function resolveSocketLibPrimordials(config) {
	/* c8 ignore start */
	if (config.socketLibPrimordialsPath) {
		if (!(0, node_fs.existsSync)(config.socketLibPrimordialsPath)) throw new require_primordials_error.ErrorCtor(`socketLibPrimordialsPath does not exist: ${config.socketLibPrimordialsPath}`);
		return config.socketLibPrimordialsPath;
	}
	const repoRoot = config.repoRoot ?? process.cwd();
	const siblingDir = node_path.default.resolve(repoRoot, "..", "socket-lib", "src", "primordials");
	if ((0, node_fs.existsSync)(siblingDir)) return siblingDir;
	const siblingLegacy = node_path.default.resolve(repoRoot, "..", "socket-lib", "src", "primordials.ts");
	if ((0, node_fs.existsSync)(siblingLegacy)) return siblingLegacy;
	const installedDir = node_path.default.resolve(repoRoot, "node_modules", "@socketsecurity", "lib", "dist", "primordials");
	if ((0, node_fs.existsSync)(installedDir)) return installedDir;
	const installedLegacy = node_path.default.resolve(repoRoot, "node_modules", "@socketsecurity", "lib", "dist", "primordials.d.ts");
	if ((0, node_fs.existsSync)(installedLegacy)) return installedLegacy;
	/* c8 ignore stop */
	throw new require_primordials_error.ErrorCtor(`Cannot locate socket-lib primordials source. Looked at:\n  ${siblingDir}\n  ${siblingLegacy}\n  ${installedDir}\n  ${installedLegacy}\nEither clone socket-lib at ../socket-lib or run \`pnpm install\`.`);
}
/**
* Strip `/* … *‍/` block comments and `//` line comments. Comments inside
* primordials destructures would otherwise leak captured names; stripping first
* keeps the regex simple.
*/
function stripComments(src) {
	let out = src.replace(/\/\*[\s\S]*?\*\//g, "");
	out = out.replace(/^[\t ]*\/\/.*$/gm, "");
	out = out.replace(/[\t ]+\/\/.*$/gm, "");
	return out;
}

//#endregion
exports.checkPrimordials = checkPrimordials;
exports.collectJsFiles = collectJsFiles;
exports.extractPrimordialsNames = extractPrimordialsNames;
exports.extractTsExports = extractTsExports;
exports.readSocketLibPrimordialNames = readSocketLibPrimordialNames;
exports.resolveSocketLibPrimordials = resolveSocketLibPrimordials;
exports.stripComments = stripComments;