@orkestrel/process 0.0.11 → 0.0.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -25,15 +25,15 @@ import type { SpawnInput } from '@orkestrel/process';
25
25
  *
26
26
  * @remarks
27
27
  * Windows alone needs this list: the host searches the working directory before `PATH` and applies
28
- * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory the
29
- * literal name is tried first and each `PATHEXT` candidate after it, whether or not the name already
30
- * carries an extension — so `report.txt` resolves to a `report.txt` file where one exists and to
31
- * `report.txt.cmd` where none does. The lookup reads the child's effective environment, so an
32
- * overridden `PATH` selects the executable the child would have found. A POSIX host resolves the
33
- * file itself, so the candidate list there is empty. An appended extension is spelled the way
34
- * `PATHEXT` spells it rather than the way the directory entry does, which the case-insensitive host
35
- * treats as the same file. A non-Windows platform returns an empty list because `execvp` performs
36
- * its own lookup.
28
+ * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory,
29
+ * {@link buildExecutableCandidates} enumerates `PATHEXT` candidates for an extensionless name. For
30
+ * an extension-bearing name, it enumerates the literal path before `PATHEXT` candidates, so
31
+ * `report.txt` resolves to a `report.txt` file where one exists and to `report.txt.cmd` where none
32
+ * does. The lookup reads the child's effective environment, so an overridden `PATH` selects the
33
+ * executable the child would have found. A POSIX host resolves the file itself, so the candidate
34
+ * list there is empty. A `PATHEXT` candidate keeps the extension spelling from `PATHEXT`, which the
35
+ * case-insensitive host treats as the same file. A non-Windows platform returns an empty list
36
+ * because `execvp` performs its own lookup.
37
37
  *
38
38
  * @param file - The command executable name or path
39
39
  * @param workspace - The directory searched first
@@ -107,6 +107,10 @@ export declare function buildPlatformSpawn(command: ProcessCommand, file: string
107
107
  /**
108
108
  * Builds the resolved spawn form of one command for the current host.
109
109
  *
110
+ * @remarks
111
+ * When executable lookup returns no regular-file candidate, {@link buildSpawn} preserves the
112
+ * command file as written for native spawning.
113
+ *
110
114
  * @param command - The executable and its argument vector
111
115
  * @param options - The directory searched first and the child's effective environment
112
116
  * @returns The file, argument vector, and verbatim flag to spawn with
@@ -755,6 +759,10 @@ export declare function readVariable(environment: Readonly<Record<string, string
755
759
  * Resolves a command file to the executable path the host would launch, or to `undefined` on a POSIX
756
760
  * host, which performs its own lookup.
757
761
  *
762
+ * @remarks
763
+ * A Windows lookup miss also returns `undefined`. {@link buildSpawn} preserves the command file as
764
+ * written for native spawning.
765
+ *
758
766
  * @param file - The command executable name or path
759
767
  * @param options - The directory searched first and the child's effective environment
760
768
  * @returns The resolved absolute path, or `undefined` when no candidate is a regular file
@@ -25,15 +25,15 @@ import type { SpawnInput } from '@orkestrel/process';
25
25
  *
26
26
  * @remarks
27
27
  * Windows alone needs this list: the host searches the working directory before `PATH` and applies
28
- * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory the
29
- * literal name is tried first and each `PATHEXT` candidate after it, whether or not the name already
30
- * carries an extension — so `report.txt` resolves to a `report.txt` file where one exists and to
31
- * `report.txt.cmd` where none does. The lookup reads the child's effective environment, so an
32
- * overridden `PATH` selects the executable the child would have found. A POSIX host resolves the
33
- * file itself, so the candidate list there is empty. An appended extension is spelled the way
34
- * `PATHEXT` spells it rather than the way the directory entry does, which the case-insensitive host
35
- * treats as the same file. A non-Windows platform returns an empty list because `execvp` performs
36
- * its own lookup.
28
+ * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory,
29
+ * {@link buildExecutableCandidates} enumerates `PATHEXT` candidates for an extensionless name. For
30
+ * an extension-bearing name, it enumerates the literal path before `PATHEXT` candidates, so
31
+ * `report.txt` resolves to a `report.txt` file where one exists and to `report.txt.cmd` where none
32
+ * does. The lookup reads the child's effective environment, so an overridden `PATH` selects the
33
+ * executable the child would have found. A POSIX host resolves the file itself, so the candidate
34
+ * list there is empty. A `PATHEXT` candidate keeps the extension spelling from `PATHEXT`, which the
35
+ * case-insensitive host treats as the same file. A non-Windows platform returns an empty list
36
+ * because `execvp` performs its own lookup.
37
37
  *
38
38
  * @param file - The command executable name or path
39
39
  * @param workspace - The directory searched first
@@ -107,6 +107,10 @@ export declare function buildPlatformSpawn(command: ProcessCommand, file: string
107
107
  /**
108
108
  * Builds the resolved spawn form of one command for the current host.
109
109
  *
110
+ * @remarks
111
+ * When executable lookup returns no regular-file candidate, {@link buildSpawn} preserves the
112
+ * command file as written for native spawning.
113
+ *
110
114
  * @param command - The executable and its argument vector
111
115
  * @param options - The directory searched first and the child's effective environment
112
116
  * @returns The file, argument vector, and verbatim flag to spawn with
@@ -755,6 +759,10 @@ export declare function readVariable(environment: Readonly<Record<string, string
755
759
  * Resolves a command file to the executable path the host would launch, or to `undefined` on a POSIX
756
760
  * host, which performs its own lookup.
757
761
  *
762
+ * @remarks
763
+ * A Windows lookup miss also returns `undefined`. {@link buildSpawn} preserves the command file as
764
+ * written for native spawning.
765
+ *
758
766
  * @param file - The command executable name or path
759
767
  * @param options - The directory searched first and the child's effective environment
760
768
  * @returns The resolved absolute path, or `undefined` when no candidate is a regular file
@@ -3,7 +3,7 @@ import { spawn, spawnSync } from "node:child_process";
3
3
  import { statSync } from "node:fs";
4
4
  import { join, posix, win32 } from "node:path";
5
5
  import { platform } from "node:process";
6
- import { boundsOf, holds, isNonEmptyString, isNonNegativeInteger, isString } from "@orkestrel/contract";
6
+ import { boundsOf, holds, isError, isNonEmptyString, isNonNegativeInteger, isString } from "@orkestrel/contract";
7
7
  import { PROCESS_BACKLOG, PROCESS_CONFIRMATION, PROCESS_DRAIN, PROCESS_EVIDENCE, PROCESS_GRACE, PROCESS_OUTPUT, PROCESS_PATHEXT, PROCESS_TIMER, ProcessError, createDuplicateError, createExecuteError, createInvalidError, createProtocolError } from "../core/index.js";
8
8
  import { createInterface } from "node:readline";
9
9
  import { Emitter } from "@orkestrel/emitter";
@@ -273,15 +273,15 @@ function isFile(target) {
273
273
  *
274
274
  * @remarks
275
275
  * Windows alone needs this list: the host searches the working directory before `PATH` and applies
276
- * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory the
277
- * literal name is tried first and each `PATHEXT` candidate after it, whether or not the name already
278
- * carries an extension — so `report.txt` resolves to a `report.txt` file where one exists and to
279
- * `report.txt.cmd` where none does. The lookup reads the child's effective environment, so an
280
- * overridden `PATH` selects the executable the child would have found. A POSIX host resolves the
281
- * file itself, so the candidate list there is empty. An appended extension is spelled the way
282
- * `PATHEXT` spells it rather than the way the directory entry does, which the case-insensitive host
283
- * treats as the same file. A non-Windows platform returns an empty list because `execvp` performs
284
- * its own lookup.
276
+ * `PATHEXT`, and Node reproduces neither for a direct spawn. Within each searched directory,
277
+ * {@link buildExecutableCandidates} enumerates `PATHEXT` candidates for an extensionless name. For
278
+ * an extension-bearing name, it enumerates the literal path before `PATHEXT` candidates, so
279
+ * `report.txt` resolves to a `report.txt` file where one exists and to `report.txt.cmd` where none
280
+ * does. The lookup reads the child's effective environment, so an overridden `PATH` selects the
281
+ * executable the child would have found. A POSIX host resolves the file itself, so the candidate
282
+ * list there is empty. A `PATHEXT` candidate keeps the extension spelling from `PATHEXT`, which the
283
+ * case-insensitive host treats as the same file. A non-Windows platform returns an empty list
284
+ * because `execvp` performs its own lookup.
285
285
  *
286
286
  * @param file - The command executable name or path
287
287
  * @param workspace - The directory searched first
@@ -296,7 +296,8 @@ function isFile(target) {
296
296
  */
297
297
  function buildExecutableCandidates(file, workspace, environment, platform) {
298
298
  if (platform !== "win32") return Object.freeze([]);
299
- const candidates = [file, ...(readPlatformVariable(environment, "PATHEXT", platform) ?? PROCESS_PATHEXT).split(";").filter((extension) => extension.length > 0).map((extension) => `${file}${extension}`)];
299
+ const extensions = (readPlatformVariable(environment, "PATHEXT", platform) ?? PROCESS_PATHEXT).split(";").filter((extension) => extension.length > 0);
300
+ const candidates = win32.extname(file).length === 0 ? extensions.map((extension) => `${file}${extension}`) : [file, ...extensions.map((extension) => `${file}${extension}`)];
300
301
  const directories = file.includes("/") || file.includes("\\") ? [workspace] : [workspace, ...(readPlatformVariable(environment, "PATH", platform) ?? "").split(";")];
301
302
  const targets = [];
302
303
  for (const directory of directories) {
@@ -309,6 +310,10 @@ function buildExecutableCandidates(file, workspace, environment, platform) {
309
310
  * Resolves a command file to the executable path the host would launch, or to `undefined` on a POSIX
310
311
  * host, which performs its own lookup.
311
312
  *
313
+ * @remarks
314
+ * A Windows lookup miss also returns `undefined`. {@link buildSpawn} preserves the command file as
315
+ * written for native spawning.
316
+ *
312
317
  * @param file - The command executable name or path
313
318
  * @param options - The directory searched first and the child's effective environment
314
319
  * @returns The resolved absolute path, or `undefined` when no candidate is a regular file
@@ -393,6 +398,10 @@ function buildPlatformSpawn(command, file, environment, platform) {
393
398
  /**
394
399
  * Builds the resolved spawn form of one command for the current host.
395
400
  *
401
+ * @remarks
402
+ * When executable lookup returns no regular-file candidate, {@link buildSpawn} preserves the
403
+ * command file as written for native spawning.
404
+ *
396
405
  * @param command - The executable and its argument vector
397
406
  * @param options - The directory searched first and the child's effective environment
398
407
  * @returns The file, argument vector, and verbatim flag to spawn with
@@ -570,7 +579,7 @@ function killProcess(child, signal) {
570
579
  }
571
580
  process.kill(-child.pid, signal);
572
581
  } catch (error) {
573
- if (error instanceof Error && "code" in error && error.code === "ESRCH") {
582
+ if (isError(error) && "code" in error && error.code === "ESRCH") {
574
583
  holds(() => child.kill(signal));
575
584
  return;
576
585
  }
@@ -1845,7 +1854,7 @@ var ProcessManager = class {
1845
1854
  }
1846
1855
  stop(target) {
1847
1856
  if (target === void 0) return this.#stopAll();
1848
- if (typeof target === "string") return this.#stopOne(target);
1857
+ if (isString(target)) return this.#stopOne(target);
1849
1858
  return this.#stopMany(target);
1850
1859
  }
1851
1860
  /**