bellpull
API reference

bellpull/which

Every export of bellpull/which, with its signature and doc comment: pathExtensions, extensionCandidates, searchPath, whichAllSync, whichSync, resolveExecutable and 5 more, plus 3 types.

import { pathExtensions, extensionCandidates, searchPath, … } from 'bellpull/which';

Functions

extensionCandidates

The extensions tried for this command, in order.

On Windows a command that already carries a dot may be complete as written, so the empty extension goes first — which does the same, and whoami.cmd on PATH depends on it.

function extensionCandidates(command: string, options: WhichOptions): string[];
ParameterType
commandstring
optionsWhichOptions

Returns string[]

pathExtensions

The PATHEXT list for this runtime, as an array. [''] off Windows: no expansion.

Exported because it is the one half of Windows resolution that can be checked from another platform: which extensions are tried, and in what order, is policy, whereas whether C:\\tools\\npm.cmd exists is a fact about a filesystem that is not here.

function pathExtensions(options: WhichOptions): string[];
ParameterType
optionsWhichOptions

Returns string[]

resolveExecutable

Where command resolves to for the purpose of spawning it — two PATHEXT attempts, not one, as cross-spawn does.

PATHEXT answers "what would the shell run if I typed this", which is right for which and wrong for a spawner: an extensionless file with a #! line is still runnable here, because spawn-args.ts puts the interpreter in front of it. So the walk is repeated with expansion disabled.

One function, because two callers asking this differently is a bug and was one. spawn-args.ts made both attempts and run.ts only the first, so on Windows a shebang script resolved for the parse and was then refused by run() with NotFoundError. Off Windows pathExtensions is always [''] and the second attempt is the first, so the divergence was invisible to a 68 / 68 grading.

function resolveExecutable(command: string, options: WhichOptions): Resolution | undefined;
ParameterType
commandstring
optionsWhichOptions

Returns Resolution \| undefined

runPath

PATH with every node_modules/.bin from cwd upward in front of it — npm-run-path's contract (104 M/wk, 2 dependencies, last published 2024-08-26).

Twelve lines rather than a sibling dependency (design R4): the walk stops at the filesystem root, which resolve of '..' reports by returning its own argument.

function runPath(options: WhichOptions): string;
ParameterType
optionsWhichOptions

Returns string

searchPath

The directories this runtime would search, in order — the static projection of resolution (PRINCIPLES rule 6).

A caller, or an agent, reads what would happen without running anything. It is also where the two refusals above become visible: an entry dropped for being empty or relative is listed with the reason, so a PATH that silently does less than its author expected says so.

function searchPath(options: WhichOptions): SearchEntry[];
ParameterType
optionsWhichOptions

Returns SearchEntry[]

whichAllSync

Every place command resolves to, best first. Empty when it resolves nowhere.

all in which's API; here it is the primitive and the single answer is the first of it, because "there are two nodes on this PATH" is the finding an investigation wants and throwing away everything after the first is what stops it being available.

function whichAllSync(command: string, options: WhichOptions): Resolution[];
ParameterType
commandstring
optionsWhichOptions

Returns Resolution[]

whichOrThrowSync

Where command resolves to, throwing {@link NotFoundError} when it resolves nowhere.

which's own shape, for the callers that want it — and the one place in this package where not finding something is an exception, because the caller asked a question that has no other answer.

function whichOrThrowSync(command: string, options: WhichOptions): Resolution;
ParameterType
commandstring
optionsWhichOptions

Returns Resolution

whichSync

Where command resolves to, or undefined.

The non-throwing form, because "it is not installed" is an ordinary answer that a caller branches on — the same argument the Result in run.ts makes about a non-zero exit.

function whichSync(command: string, options: WhichOptions): Resolution | undefined;
ParameterType
commandstring
optionsWhichOptions

Returns Resolution \| undefined

Classes

NotFoundError

Error with the code a caller switches on, and the command it could not find.

class NotFoundError extends Error {
    readonly command: string;
    readonly code = "ENOENT";
    constructor(command: string);
}

Constants

delimiter

The platform-specific file delimiter. ';' or ':'.

const delimiter: ";" | ":";

sep

The platform-specific file separator. '\' or '/'.

const sep: "\\" | "/";

Interfaces

Resolution

Where an executable was found, and what found it.

interface Resolution {
    /** The absolute path of the file that would be executed. */
    path: string;
    /**
     * The `PATH` entry it was found under, or `''` when the command carried its own path and
     * `PATH` was never consulted. This is the field no incumbent returns.
     */
    from: string;
    /**
     * The extension appended from `PATHEXT` to find it — `.CMD`, `.EXE`. Always `''` off
     * Windows, where the file is executable or it is not.
     */
    ext: string;
}

SearchEntry

One directory to search, and whether it was skipped and why.

interface SearchEntry {
    /** The entry as it appeared on `PATH`, before quotes were stripped or it was resolved. */
    raw: string;
    /** The absolute directory that will be searched, when it will be. */
    dir?: string;
    /** Why it will not be, when it will not: a reader can see the hole rather than infer it. */
    skipped?: 'empty' | 'relative';
}

WhichOptions

interface WhichOptions {
    /** The ambient state. Required in spirit; defaulted only by the façades. */
    runtime: Runtime;
    /** Override the `PATH` string. Overrides `runtime.env`'s, as `which`'s `path` does. */
    path?: string | undefined;
    /** Override `PATHEXT`. `''` disables extension expansion entirely. */
    pathExt?: string | undefined;
    /** Resolve relative entries and relative commands against this instead of `runtime.cwd`. */
    cwd?: string | undefined;
}

On this page