81 lines
2.7 KiB
TypeScript
81 lines
2.7 KiB
TypeScript
/**
|
|
* Return only the user arguments (excluding runtime executable and script path),
|
|
* across Node.js, Deno (run/compiled), and Bun.
|
|
*
|
|
* - Deno: uses Deno.args directly (already user-only in both run and compile).
|
|
* - Node/Bun: uses process.execPath's basename to decide if there is a script arg.
|
|
* If execPath basename is a known launcher (node/nodejs/bun/deno), skip 2; else skip 1.
|
|
*/
|
|
export function getUserArgs(argv?: string[]): string[] {
|
|
// If argv is explicitly provided, use it instead of Deno.args
|
|
// This handles test scenarios where process.argv is manually modified
|
|
const useProvidedArgv = argv !== undefined;
|
|
|
|
// Prefer Deno.args when available and no custom argv provided;
|
|
// it's the most reliable for Deno run and compiled.
|
|
// deno-lint-ignore no-explicit-any
|
|
const g: any = typeof globalThis !== 'undefined' ? globalThis : {};
|
|
if (!useProvidedArgv && g.Deno && g.Deno.args && Array.isArray(g.Deno.args)) {
|
|
return g.Deno.args.slice();
|
|
}
|
|
|
|
const a =
|
|
argv ?? (typeof process !== 'undefined' && Array.isArray(process.argv) ? process.argv : []);
|
|
|
|
if (!Array.isArray(a) || a.length === 0) return [];
|
|
|
|
// Determine execPath in Node/Bun (or compat shims)
|
|
let execPath = '';
|
|
if (typeof process !== 'undefined' && typeof process.execPath === 'string') {
|
|
execPath = process.execPath;
|
|
} else if (g.Deno && typeof g.Deno.execPath === 'function') {
|
|
// Fallback for unusual shims: try Deno.execPath() if present.
|
|
try {
|
|
execPath = g.Deno.execPath();
|
|
} catch {
|
|
/* ignore */
|
|
}
|
|
}
|
|
|
|
const base = basename(execPath).toLowerCase();
|
|
const knownLaunchers = new Set([
|
|
'node',
|
|
'node.exe',
|
|
'nodejs',
|
|
'nodejs.exe',
|
|
'bun',
|
|
'bun.exe',
|
|
'deno',
|
|
'deno.exe',
|
|
'tsx',
|
|
'tsx.exe',
|
|
'ts-node',
|
|
'ts-node.exe',
|
|
]);
|
|
|
|
// Always skip the executable (argv[0]).
|
|
let offset = Math.min(1, a.length);
|
|
|
|
// If the executable is a known runtime launcher, there's almost always a script path in argv[1].
|
|
// This handles Node, Bun, and "deno run" (but NOT "deno compile" which won't match 'deno').
|
|
if (knownLaunchers.has(base)) {
|
|
offset = Math.min(2, a.length);
|
|
}
|
|
|
|
// Safety: if offset would skip all elements and array is not empty, don't skip anything
|
|
// This handles edge cases like test environments with unusual argv setups
|
|
if (offset >= a.length && a.length > 0) {
|
|
offset = 0;
|
|
}
|
|
|
|
// Note: we intentionally avoid path/URL heuristics on argv[1] so we don't
|
|
// accidentally drop the first user arg when it's a path-like value in compiled mode.
|
|
return a.slice(offset);
|
|
}
|
|
|
|
function basename(p: string): string {
|
|
if (!p) return '';
|
|
const parts = p.split(/[/\\]/);
|
|
return parts[parts.length - 1] || '';
|
|
}
|