"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_map_set = require('../primordials/map-set.js');
const require_node_fs = require('../node/fs.js');
const require_node_path = require('../node/path.js');
const require_primordials_date = require('../primordials/date.js');
const require_primordials_json = require('../primordials/json.js');
const require_paths_socket = require('../paths/socket.js');
const require_dlx_paths = require('./paths.js');
const require_fs_find_up = require('../fs/find-up.js');

//#region src/dlx/detect.ts
/**
* @file Executable type detection for DLX and local filesystem paths. Provides
*   utilities to detect whether a path is a Node.js package or native binary
*   executable. Supports both DLX cache paths and local filesystem paths. Key
*   Functions:
*
*   - detectExecutableType: Generic entry point for any path
*   - detectDlxExecutableType: DLX cache specific detection
*   - detectLocalExecutableType: Local filesystem specific detection Detection
*     Strategies:
*   - DLX cache: Check for node_modules/ directory
*   - Local paths: Check for package.json with bin field, then file extension
*/
/**
* Node.js script file extensions.
*/
const NODE_JS_EXTENSIONS = new require_primordials_map_set.SetCtor([
	".js",
	".mjs",
	".cjs"
]);
const PACKAGE_JSON_PATH_CACHE_MAX_SIZE = 200;
const PACKAGE_JSON_NEGATIVE_TTL_MS = 1e4;
const packageJsonPathCache = new require_primordials_map_set.MapCtor();
function packageJsonPathCacheSet(key, value) {
	if (packageJsonPathCache.has(key)) packageJsonPathCache.delete(key);
	else if (packageJsonPathCache.size >= PACKAGE_JSON_PATH_CACHE_MAX_SIZE) {
		const oldest = packageJsonPathCache.keys().next().value;
		if (oldest !== void 0) packageJsonPathCache.delete(oldest);
	}
	packageJsonPathCache.set(key, {
		path: value,
		at: Date.now()
	});
}
const packageJsonContentCache = new require_primordials_map_set.MapCtor();
/**
* Find package.json in the directory containing the file or parent directories.
* Results are cached to avoid repeated directory traversal.
*
* @private
*
* @param filePath - Path to search from.
*
* @returns Path to package.json if found, undefined otherwise
*/
function findPackageJson(filePath) {
	const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
	const nodePath = /* @__PURE__ */ require_node_path.getNodePath();
	const startDir = nodePath.dirname(nodePath.resolve(filePath));
	const cached = packageJsonPathCache.get(startDir);
	if (cached !== void 0) if (cached.path === void 0) {
		if (require_primordials_date.DateNow() - cached.at < PACKAGE_JSON_NEGATIVE_TTL_MS) return;
		packageJsonPathCache.delete(startDir);
	} else if (fs.existsSync(cached.path)) {
		packageJsonPathCacheSet(startDir, cached.path);
		return cached.path;
	} else packageJsonPathCache.delete(startDir);
	const packageJsonPath = /* @__PURE__ */ require_fs_find_up.findUpSync("package.json", { cwd: startDir });
	packageJsonPathCacheSet(startDir, packageJsonPath);
	return packageJsonPath;
}
/**
* Read and parse package.json with caching. Results are cached to avoid
* repeated file reads.
*
* @private
*
* @param packageJsonPath - Path to package.json.
*
* @returns Parsed package.json or null if invalid
*/
function readPackageJson(packageJsonPath) {
	const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
	let mtimeMs = 0;
	try {
		mtimeMs = fs.statSync(packageJsonPath).mtimeMs;
	} catch {
		packageJsonContentCache.delete(packageJsonPath);
		return;
	}
	const cached = packageJsonContentCache.get(packageJsonPath);
	if (cached !== void 0 && cached.mtimeMs === mtimeMs) return cached.content;
	try {
		const content = require_primordials_json.JSONParse(fs.readFileSync(packageJsonPath, "utf8"));
		packageJsonContentCache.set(packageJsonPath, {
			mtimeMs,
			content
		});
		return content;
	} catch {
		packageJsonContentCache.set(packageJsonPath, {
			mtimeMs,
			content: void 0
		});
		return;
	}
}
/**
* Detect executable type for paths in DLX cache. Uses filesystem structure
* (node_modules/ presence).
*
* @example
*   ;```typescript
*   const result = detectDlxExecutableType('/tmp/.socket/_dlx/a1b2c3d4/tool')
*   console.log(result.type) // 'package' or 'binary'
*   ```
*
* @param filePath - Path within DLX cache (~/.socket/_dlx/)
*
* @returns Detection result
*/
function detectDlxExecutableType(filePath) {
	const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
	const path = /* @__PURE__ */ require_node_path.getNodePath();
	const dlxDir = require_paths_socket.getSocketDlxDir();
	const absolutePath = path.resolve(filePath);
	const cacheKey = path.relative(dlxDir, absolutePath).split(path.sep)[0] ?? "";
	const cacheDir = path.join(dlxDir, cacheKey);
	if (fs.existsSync(path.join(cacheDir, "node_modules"))) return {
		type: "package",
		method: "dlx-cache",
		inDlxCache: true
	};
	return {
		type: "binary",
		method: "dlx-cache",
		inDlxCache: true
	};
}
/**
* Detect if a path is a Node.js package or native binary executable. Works for
* both DLX cache paths and local filesystem paths.
*
* Detection strategy: 1. If in DLX cache: Use detectDlxExecutableType() 2.
* Otherwise: Use detectLocalExecutableType()
*
* @example
*   ;```typescript
*   const result = detectExecutableType('/path/to/tool')
*   if (result.type === 'package') {
*     spawnNode([filePath, ...args])
*   } else {
*     spawn(filePath, args)
*   }
*   ```
*
* @param filePath - Path to executable (DLX cache or local filesystem)
*
* @returns Detection result with type, method, and metadata
*/
function detectExecutableType(filePath) {
	if (require_dlx_paths.isInSocketDlx(filePath)) return detectDlxExecutableType(filePath);
	return detectLocalExecutableType(filePath);
}
/**
* Detect executable type for local filesystem paths. Uses package.json and file
* extension checks.
*
* @example
*   ;```typescript
*   const result = detectLocalExecutableType('/usr/local/bin/tool')
*   if (result.type === 'package') {
*     console.log('Node.js package at:', result.packageJsonPath)
*   }
*   ```
*
* @param filePath - Local filesystem path (not in DLX cache)
*
* @returns Detection result
*/
function detectLocalExecutableType(filePath) {
	const packageJsonPath = findPackageJson(filePath);
	if (packageJsonPath !== void 0) {
		if (readPackageJson(packageJsonPath)?.["bin"]) return {
			type: "package",
			method: "package-json",
			packageJsonPath,
			inDlxCache: false
		};
	}
	if (isJsFilePath(filePath)) return {
		inDlxCache: false,
		method: "file-extension",
		type: "package"
	};
	return {
		type: "binary",
		method: "file-extension",
		inDlxCache: false
	};
}
/**
* Check if a file path indicates a Node.js script.
*
* @example
*   ;```typescript
*   isJsFilePath('index.js') // true
*   isJsFilePath('lib.mjs') // true
*   isJsFilePath('tool.exe') // false
*   ```
*
* @param filePath - Path to check.
*
* @returns True if file has .js, .mjs, or .cjs extension
*/
function isJsFilePath(filePath) {
	const ext = (/* @__PURE__ */ require_node_path.getNodePath()).extname(filePath).toLowerCase();
	return NODE_JS_EXTENSIONS.has(ext);
}
/**
* Simplified helper: Is this a native binary executable?
*
* @example
*   ;```typescript
*   isNativeBinary('/usr/local/bin/tool') // true
*   isNativeBinary('/tmp/project/index.js') // false
*   ```
*
* @param filePath - Path to check.
*
* @returns True if detected as native binary (not Node.js package)
*/
function isNativeBinary(filePath) {
	return detectExecutableType(filePath).type === "binary";
}
/**
* Simplified helper: Is this a Node.js package?
*
* @example
*   ;```typescript
*   isNodePackage('/tmp/project/index.js') // true
*   isNodePackage('/usr/local/bin/tool') // false
*   ```
*
* @param filePath - Path to check.
*
* @returns True if detected as Node.js package
*/
function isNodePackage(filePath) {
	return detectExecutableType(filePath).type === "package";
}

//#endregion
exports.detectDlxExecutableType = detectDlxExecutableType;
exports.detectExecutableType = detectExecutableType;
exports.detectLocalExecutableType = detectLocalExecutableType;
exports.findPackageJson = findPackageJson;
exports.isJsFilePath = isJsFilePath;
exports.isNativeBinary = isNativeBinary;
exports.isNodePackage = isNodePackage;
exports.packageJsonPathCacheSet = packageJsonPathCacheSet;
exports.readPackageJson = readPackageJson;