path-class 0.10.14 → 0.11.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../../../../src/sync/index.ts", "../../../../src/sync/static.ts"],
4
- "sourcesContent": ["import {\n appendFileSync,\n chmodSync,\n cpSync,\n lstatSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmdirSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport \"./static\";\nimport type {\n lstatSyncType,\n readDirSyncType,\n readFileSyncType,\n statSyncType,\n} from \"./modifiedNodeTypes\";\n\n// Note that (non-static) functions in this file are defined using `function(\u2026)\n// { \u2026 }` rather than arrow functions, specifically because we want `this` to\n// operate on the `Path` instance.\n\ndeclare module \"../Path\" {\n interface Path {\n existsSync(constraints?: { mustBe: \"file\" | \"directory\" }): boolean;\n existsAsFileSync(): boolean;\n existsAsDirSync(): boolean;\n\n mkdirSync(options?: Parameters<typeof mkdirSync>[1]): Path;\n cpSync(\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n ): Path;\n renameSync(destination: string | URL | Path): void;\n\n rmSync(options?: Parameters<typeof rmSync>[1]): void;\n rmDirSync(options?: Parameters<typeof rmdirSync>[1]): void;\n rm_rfSync(options?: Parameters<typeof rmSync>[1]): void;\n\n readSync: typeof readFileSyncType;\n readTextSync(): string;\n readJSONSync<T>(options?: { fallback?: T }): T;\n\n appendFileSync(\n data: Parameters<typeof appendFileSync>[1],\n options?: Parameters<typeof appendFileSync>[2],\n ): Path;\n\n writeSync(\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2] | undefined,\n ): Path;\n writeJSONSync<T>(\n data: T,\n replacer?: Parameters<typeof JSON.stringify>[1],\n space?: Parameters<typeof JSON.stringify>[2],\n ): Path;\n\n readDirSync: typeof readDirSyncType;\n\n /** Returns the destination path. */\n symlinkSync(\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n ): Path;\n realpathSync(): Path;\n\n statSync: typeof statSyncType;\n lstatSync: typeof lstatSyncType;\n chmodSync(mode: Parameters<typeof chmodSync>[1]): void;\n }\n}\n\n// TODO: find a neat way to dedup with the async version? // lint-sync-code-expect-error\nPath.prototype.existsSync = function (constraints?: {\n mustBe: \"file\" | \"directory\";\n}): boolean {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: ReturnType<typeof statSync>;\n try {\n stats = statSync(this.path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`Path exists but is not a file: ${this.path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`Path exists but is not a directory: ${this.path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n};\n\nPath.prototype.existsAsFileSync = function (): boolean {\n return this.existsSync({ mustBe: \"file\" });\n};\n\nPath.prototype.existsAsDirSync = function (): boolean {\n return this.existsSync({ mustBe: \"directory\" });\n};\n\nPath.prototype.mkdirSync = function (\n options?: Parameters<typeof mkdirSync>[1],\n): Path {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n mkdirSync(this.path, { recursive: true, ...optionsObject });\n return this;\n};\n\nPath.prototype.cpSync = function (\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n): Path {\n cpSync(this.path, new Path(destination).path, options);\n return new Path(destination);\n};\n\nPath.prototype.renameSync = function (destination: string | URL | Path): void {\n renameSync(this.path, new Path(destination).path);\n};\n\nPath.prototype.rmSync = function (\n options?: Parameters<typeof rmSync>[1],\n): void {\n rmSync(this.path, options);\n};\n\nPath.prototype.rmDirSync = function (): void {\n rmdirSync(this.path);\n};\n\nPath.prototype.rm_rfSync = function (\n options?: Parameters<typeof rmSync>[1],\n): void {\n this.rmSync({ recursive: true, force: true, ...(options ?? {}) });\n};\n\nPath.prototype.readSync = function () {\n /** @ts-expect-error ts(2683) */\n return readFileSync(this.path);\n} as typeof readFileSyncType;\n\nPath.prototype.readTextSync = function (): string {\n return readFileSync(this.path, \"utf-8\");\n};\n\nPath.prototype.readJSONSync = function <T>(options?: { fallback?: T }): T {\n try {\n return JSON.parse(this.readTextSync());\n } catch (e) {\n if (\n (e as { code?: string }).code === \"ENOENT\" &&\n options &&\n \"fallback\" in options\n ) {\n return options.fallback as T;\n }\n throw e;\n }\n};\n\nPath.prototype.appendFileSync = function (\n data: Parameters<typeof appendFileSync>[1],\n options?: Parameters<typeof appendFileSync>[2],\n): Path {\n appendFileSync(this.path, data, options);\n return this;\n};\n\nPath.prototype.writeSync = function (\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2],\n): Path {\n this.parent.mkdirSync();\n writeFileSync(this.path, data, options);\n return this;\n};\n\nPath.prototype.writeJSONSync = function <T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n): Path {\n this.parent.mkdirSync();\n this.writeSync(JSON.stringify(data, replacer, space));\n return this;\n};\n\n/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.readDirSync = function (options) {\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n return readdirSync(this.path, options as any);\n};\n\nPath.prototype.symlinkSync = function (\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n): Path {\n const targetPath = new Path(target);\n symlinkSync(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlinkSync>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n};\n\nPath.prototype.realpathSync = function (): Path {\n return new Path(realpathSync(this.path));\n};\n\n/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.statSync = function (\n options?: Parameters<typeof statSync>[1],\n): ReturnType<typeof statSync> {\n return statSync(this.path, options);\n};\n\n/** @ts-expect-error ts(2322): Wrangle types */\nPath.prototype.lstatSync = function (\n options?: Parameters<typeof lstatSync>[1],\n): ReturnType<typeof lstatSync> {\n return lstatSync(this.path, options);\n};\n\nPath.prototype.chmodSync = function (\n mode: Parameters<typeof chmodSync>[1],\n): void {\n chmodSync(this.path, mode);\n};\n", "import { mkdtempSync } from \"node:fs\";\nimport { tmpdir } from \"node:os\";\nimport { Path } from \"../Path\";\n\ndeclare module \"../Path\" {\n namespace Path {\n export function makeTempDirSync(prefix?: string): Path;\n }\n}\n\nPath.makeTempDirSync = (prefix?: string): Path =>\n new Path(\n mkdtempSync(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n"],
5
- "mappings": "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",
3
+ "sources": ["../../../../src/sync/PathSync.ts"],
4
+ "sourcesContent": ["import {\n appendFileSync,\n chmodSync,\n cpSync,\n lstatSync,\n mkdirSync,\n mkdtempSync,\n readdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmdirSync,\n rmSync,\n statSync,\n symlinkSync,\n writeFileSync,\n} from \"node:fs\";\nimport { constants } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { mustNotHaveTrailingSlash, Path } from \"../Path\";\nimport type {\n lstatSyncType,\n readDirSyncType,\n readFileSyncType,\n statSyncType,\n} from \"./modifiedNodeTypes\";\n\nexport class PathSync extends Path {\n static override fromString(s: string): PathSync {\n return new PathSync(s);\n }\n\n static override resolve(...args: Parameters<typeof Path.resolve>): PathSync {\n return new PathSync(Path.resolve(...args));\n }\n\n override toggleTrailingSlash(\n ...args: Parameters<Path[\"toggleTrailingSlash\"]>\n ): PathSync {\n return new PathSync(super.toggleTrailingSlash(...args));\n }\n\n override join(...args: Parameters<Path[\"join\"]>): PathSync {\n return new PathSync(super.join(...args));\n }\n\n override asRelative(...args: Parameters<Path[\"asRelative\"]>): PathSync {\n return new PathSync(super.asRelative(...args));\n }\n\n override asAbsolute(...args: Parameters<Path[\"asAbsolute\"]>): PathSync {\n return new PathSync(super.asAbsolute(...args));\n }\n\n override asBare(...args: Parameters<Path[\"asBare\"]>): PathSync {\n return new PathSync(super.asBare(...args));\n }\n\n override extendBasename(\n ...args: Parameters<Path[\"extendBasename\"]>\n ): PathSync {\n return new PathSync(super.extendBasename(...args));\n }\n\n override get parent(): PathSync {\n return new PathSync(super.parent);\n }\n\n override get dirname(): PathSync {\n return new PathSync(super.dirname);\n }\n\n override get basename(): PathSync {\n return new PathSync(super.basename);\n }\n\n static override get homedir(): PathSync {\n return new PathSync(Path.homedir);\n }\n\n static override get cwd(): PathSync {\n return new PathSync(Path.cwd);\n }\n\n override debugPrint(...args: Parameters<Path[\"debugPrint\"]>): PathSync {\n return new PathSync(super.debugPrint(...args));\n }\n\n // TODO: find a neat way to dedup with the async version? // lint-sync-code-expect-error\n existsSync(constraints?: { mustBe: \"file\" | \"directory\" }): boolean {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\n let stats: ReturnType<typeof statSync>;\n try {\n stats = statSync(this.path);\n // biome-ignore lint/suspicious/noExplicitAny: TypeScript limitation\n } catch (e: any) {\n if (e.code === \"ENOENT\") {\n return false;\n }\n throw e;\n }\n if (!constraints?.mustBe) {\n return true;\n }\n switch (constraints?.mustBe) {\n case \"file\": {\n if (stats.isFile()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a file: ${this.path}`);\n }\n case \"directory\": {\n if (stats.isDirectory()) {\n return true;\n }\n throw new Error(`PathSync exists but is not a directory: ${this.path}`);\n }\n default: {\n throw new Error(\"Invalid path type constraint\");\n }\n }\n }\n\n existsAsFileSync(): boolean {\n return this.existsSync({ mustBe: \"file\" });\n }\n\n existsAsDirSync(): boolean {\n return this.existsSync({ mustBe: \"directory\" });\n }\n\n mkdirSync(options?: Parameters<typeof mkdirSync>[1]): PathSync {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n mkdirSync(this.path, { recursive: true, ...optionsObject });\n return this;\n }\n\n cpSync(\n destination: string | URL | Path,\n options?: Parameters<typeof cpSync>[2],\n ): PathSync {\n cpSync(this.path, new Path(destination).path, options);\n return new PathSync(destination);\n }\n\n renameSync(destination: string | URL | Path): void {\n renameSync(this.path, new Path(destination).path);\n }\n\n static makeTempDirSync(prefix?: string): PathSync {\n return new PathSync(\n mkdtempSync(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n rmSync(options?: Parameters<typeof rmSync>[1]): void {\n rmSync(this.path, options);\n }\n\n rmDirSync(): void {\n rmdirSync(this.path);\n }\n\n rm_rfSync(options?: Parameters<typeof rmSync>[1]): void {\n this.rmSync({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n readSync: typeof readFileSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFileSync(this.path, options) as any;\n\n readTextSync(): string {\n return readFileSync(this.path, \"utf-8\");\n }\n\n readJSONSync<T>(options?: { fallback?: T }): T {\n try {\n return JSON.parse(this.readTextSync());\n } catch (e) {\n if (\n (e as { code?: string }).code === \"ENOENT\" &&\n options &&\n \"fallback\" in options\n ) {\n return options.fallback as T;\n }\n throw e;\n }\n }\n\n appendFileSync(\n data: Parameters<typeof appendFileSync>[1],\n options?: Parameters<typeof appendFileSync>[2],\n ): PathSync {\n appendFileSync(this.path, data, options);\n return this;\n }\n\n writeSync(\n data: Parameters<typeof writeFileSync>[1],\n options?: Parameters<typeof writeFileSync>[2],\n ): PathSync {\n this.parent.mkdirSync();\n writeFileSync(this.path, data, options);\n return this;\n }\n\n writeJSONSync<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): PathSync {\n this.parent.mkdirSync();\n this.writeSync(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Type wrangling.\n readDirSync: typeof readDirSyncType = (options: any) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdirSync(this.path, options) as any;\n\n symlinkSync(\n target: string | URL | Path,\n type?: Parameters<typeof symlinkSync>[2],\n ): PathSync {\n const targetPath = new PathSync(target);\n symlinkSync(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlinkSync>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n realpathSync(): PathSync {\n return new PathSync(realpathSync(this.path));\n }\n\n statSync: typeof statSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n statSync(this.path, options) as any;\n\n lstatSync: typeof lstatSyncType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstatSync(this.path, options) as any;\n\n chmodSync(mode: Parameters<typeof chmodSync>[1]): PathSync {\n chmodSync(this.path, mode);\n return this;\n }\n\n chmodXSync(): PathSync {\n const { mode } = this.statSync();\n this.chmodSync(\n mode |\n constants.S_IRWXU |\n constants.S_IXUSR |\n constants.S_IXGRP |\n constants.S_IXOTH,\n );\n return this;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,4 +1,5 @@
1
- import type { BigIntStats, Dirent, ObjectEncodingOptions, StatSyncOptions, Stats } from "node:fs";
1
+ import type { Abortable } from "node:events";
2
+ import type { BigIntStats, Dirent, Mode, ObjectEncodingOptions, StatSyncOptions, Stats } from "node:fs";
2
3
  export declare function readFileSyncType(options?: {
3
4
  encoding?: null | undefined;
4
5
  flag?: string | undefined;
@@ -10,6 +11,11 @@ export declare function readFileSyncType(options: {
10
11
  export declare function readFileSyncType(options?: (ObjectEncodingOptions & {
11
12
  flag?: string | undefined;
12
13
  }) | BufferEncoding | null): string | NonSharedBuffer;
14
+ export type WriteFileOptions = (ObjectEncodingOptions & Abortable & {
15
+ mode?: Mode | undefined;
16
+ flag?: string | undefined;
17
+ flush?: boolean | undefined;
18
+ }) | BufferEncoding | null;
13
19
  export declare function readDirSyncType(options?: {
14
20
  encoding: BufferEncoding | null;
15
21
  withFileTypes?: false | undefined;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "path-class",
3
- "version": "0.10.14",
3
+ "version": "0.11.0",
4
4
  "description": "A semantic `Path` class for `node` and `bun`. Inspired by `bun`'s [`file(…)`](https://bun.com/docs/runtime/file-io) API, but `node`-compatible.",
5
5
  "author": "Lucas Garron <code@garron.net>",
6
6
  "license": "MIT",
package/src/Path.test.ts CHANGED
@@ -598,7 +598,7 @@ test(".lstat(…)", async () => {
598
598
  expect(await target.readText()).toEqual("hello");
599
599
  });
600
600
 
601
- test.only(".chmod(…)", async () => {
601
+ test(".chmod(…)", async () => {
602
602
  const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
603
603
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
604
604
  /ENOENT|Premature close/,
@@ -617,6 +617,25 @@ echo hi`);
617
617
  expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
618
618
  });
619
619
 
620
+ test(".chmodX(…)", async () => {
621
+ const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
622
+ expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
623
+ /ENOENT|Premature close/,
624
+ );
625
+ await binPath.write(`#!/usr/bin/env bash
626
+
627
+ echo hi`);
628
+ // TODO: why doesn't this work here instead (but works in `printable-shell-comand`)?
629
+ // await binPath.write(`#!/usr/bin/env -S bun run --
630
+
631
+ // console.log("hi");`);
632
+ expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
633
+ /EACCES|Premature close/,
634
+ );
635
+ await binPath.chmodX();
636
+ expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
637
+ });
638
+
620
639
  test(".homedir", async () => {
621
640
  expect(Path.homedir.path).toEqual("/mock/home/dir");
622
641
  });
package/src/Path.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  appendFile,
3
3
  chmod,
4
+ constants,
4
5
  cp,
5
6
  lstat,
6
7
  mkdir,
@@ -58,7 +59,7 @@ export enum ResolutionPrefix {
58
59
  Bare = "bare",
59
60
  }
60
61
 
61
- function resolutionPrefix(pathString: string): ResolutionPrefix {
62
+ export function resolutionPrefix(pathString: string): ResolutionPrefix {
62
63
  if (pathString.startsWith("/")) {
63
64
  return ResolutionPrefix.Absolute;
64
65
  } else if (pathString.startsWith("./")) {
@@ -613,6 +614,21 @@ export class Path {
613
614
  return this;
614
615
  }
615
616
 
617
+ /**
618
+ * Add the executable bit (for everyone) to the given path without modifying other bits (`chmod +x`).
619
+ */
620
+ async chmodX(): Promise<Path> {
621
+ const { mode } = await this.stat();
622
+ await this.chmod(
623
+ mode |
624
+ constants.S_IRWXU |
625
+ constants.S_IXUSR |
626
+ constants.S_IXGRP |
627
+ constants.S_IXOTH,
628
+ );
629
+ return this;
630
+ }
631
+
616
632
  static get homedir(): Path {
617
633
  return new Path(homedir());
618
634
  }
@@ -1,12 +1,13 @@
1
1
  import { expect, test } from "bun:test";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
- import { Path } from "../Path";
5
- import "./index";
4
+ import "./PathSync";
6
5
  import { PrintableShellCommand } from "printable-shell-command";
7
6
 
7
+ import { PathSync } from "./PathSync";
8
+
8
9
  test(".existsAsFileSync()", () => {
9
- const filePath = Path.makeTempDirSync().join("file.txt");
10
+ const filePath = PathSync.makeTempDirSync().join("file.txt");
10
11
  expect(filePath.existsSync()).toBe(false);
11
12
  expect(filePath.existsSync({ mustBe: "file" })).toBe(false);
12
13
  expect(filePath.existsSync({ mustBe: "directory" })).toBe(false);
@@ -18,16 +19,16 @@ test(".existsAsFileSync()", () => {
18
19
  expect(filePath.existsSync()).toBe(true);
19
20
  expect(filePath.existsSync({ mustBe: "file" })).toBe(true);
20
21
  expect(() => filePath.existsSync({ mustBe: "directory" })).toThrow(
21
- /Path exists but is not a directory/,
22
+ /PathSync exists but is not a directory/,
22
23
  );
23
24
  expect(filePath.existsAsFileSync()).toBe(true);
24
25
  });
25
26
 
26
27
  test(".existsAsDir()", () => {
27
- const filePath = Path.makeTempDirSync();
28
+ const filePath = PathSync.makeTempDirSync();
28
29
  expect(filePath.existsSync()).toBe(true);
29
30
  expect(() => filePath.existsSync({ mustBe: "file" })).toThrow(
30
- /Path exists but is not a file/,
31
+ /PathSync exists but is not a file/,
31
32
  );
32
33
  expect(filePath.existsSync({ mustBe: "directory" })).toBe(true);
33
34
  expect(filePath.existsAsDirSync()).toBe(true);
@@ -39,14 +40,14 @@ test(".existsAsDir()", () => {
39
40
  });
40
41
 
41
42
  test(".mkdirSync(…) (un-nested)", () => {
42
- const dir = Path.makeTempDirSync().join("mkdir-test");
43
+ const dir = PathSync.makeTempDirSync().join("mkdir-test");
43
44
  expect(dir.existsSync()).toBe(false);
44
45
  dir.mkdirSync();
45
46
  expect(dir.existsSync()).toBe(true);
46
47
  });
47
48
 
48
49
  test(".mkdirSync(…) (nested)", () => {
49
- const dir = Path.makeTempDirSync().join("mkdir-test/nested");
50
+ const dir = PathSync.makeTempDirSync().join("mkdir-test/nested");
50
51
  expect(dir.existsSync()).toBe(false);
51
52
  expect(() => dir.mkdirSync({ recursive: false })).toThrow("no such file");
52
53
  dir.mkdirSync();
@@ -54,7 +55,7 @@ test(".mkdirSync(…) (nested)", () => {
54
55
  });
55
56
 
56
57
  test(".cpSync(…)", () => {
57
- const parentDir = Path.makeTempDirSync();
58
+ const parentDir = PathSync.makeTempDirSync();
58
59
  const file1 = parentDir.join("file1.txt");
59
60
  const file2 = parentDir.join("file2.txt");
60
61
 
@@ -68,7 +69,7 @@ test(".cpSync(…)", () => {
68
69
  });
69
70
 
70
71
  test(".renameSync(…)", () => {
71
- const parentDir = Path.makeTempDirSync();
72
+ const parentDir = PathSync.makeTempDirSync();
72
73
  const file1 = parentDir.join("file1.txt");
73
74
  const file2 = parentDir.join("file2.txt");
74
75
 
@@ -82,18 +83,18 @@ test(".renameSync(…)", () => {
82
83
  });
83
84
 
84
85
  test(".makeTempDirSync(…)", () => {
85
- const tempDir = Path.makeTempDirSync();
86
+ const tempDir = PathSync.makeTempDirSync();
86
87
  expect(tempDir.path).toContain("/js-temp-");
87
88
  expect(tempDir.basename.path).toStartWith("js-temp-");
88
89
  expect(tempDir.existsAsDirSync()).toBe(true);
89
90
 
90
- const tempDir2 = Path.makeTempDirSync("foo");
91
+ const tempDir2 = PathSync.makeTempDirSync("foo");
91
92
  expect(tempDir2.path).not.toContain("/js-temp-");
92
93
  expect(tempDir2.basename.path).toStartWith("foo");
93
94
  });
94
95
 
95
96
  test(".rmSync(…) (file)", () => {
96
- const file = Path.makeTempDirSync().join("file.txt");
97
+ const file = PathSync.makeTempDirSync().join("file.txt");
97
98
  file.writeSync("");
98
99
  expect(file.existsAsFileSync()).toBe(true);
99
100
  file.rmSync();
@@ -103,7 +104,7 @@ test(".rmSync(…) (file)", () => {
103
104
  });
104
105
 
105
106
  test(".rmSync(…) (folder)", () => {
106
- const tempDir = Path.makeTempDirSync();
107
+ const tempDir = PathSync.makeTempDirSync();
107
108
  const file = tempDir.join("file.txt");
108
109
  file.writeSync("");
109
110
  expect(tempDir.existsAsDirSync()).toBe(true);
@@ -115,7 +116,7 @@ test(".rmSync(…) (folder)", () => {
115
116
  });
116
117
 
117
118
  test(".rmDirSync(…) (folder)", () => {
118
- const tempDir = Path.makeTempDirSync();
119
+ const tempDir = PathSync.makeTempDirSync();
119
120
  const file = tempDir.join("file.txt");
120
121
  file.writeSync("");
121
122
  expect(tempDir.existsAsDirSync()).toBe(true);
@@ -127,7 +128,7 @@ test(".rmDirSync(…) (folder)", () => {
127
128
  });
128
129
 
129
130
  test(".rm_rfSync(…) (file)", () => {
130
- const file = Path.makeTempDirSync().join("file.txt");
131
+ const file = PathSync.makeTempDirSync().join("file.txt");
131
132
  file.writeSync("");
132
133
  expect(file.existsAsFileSync()).toBe(true);
133
134
  file.rm_rfSync();
@@ -138,7 +139,7 @@ test(".rm_rfSync(…) (file)", () => {
138
139
  });
139
140
 
140
141
  test(".rm_rfSync(…) (folder)", () => {
141
- const tempDir = Path.makeTempDirSync();
142
+ const tempDir = PathSync.makeTempDirSync();
142
143
  tempDir.join("file.txt").writeSync("");
143
144
  expect(tempDir.path).toContain("/js-temp-");
144
145
  expect(tempDir.existsSync()).toBe(true);
@@ -149,7 +150,7 @@ test(".rm_rfSync(…) (folder)", () => {
149
150
  });
150
151
 
151
152
  test(".readTextSync()", () => {
152
- const file = Path.makeTempDirSync().join("file.txt");
153
+ const file = PathSync.makeTempDirSync().join("file.txt");
153
154
  file.writeSync("hi");
154
155
  file.writeSync("bye");
155
156
 
@@ -158,7 +159,7 @@ test(".readTextSync()", () => {
158
159
  });
159
160
 
160
161
  test(".readJSONSync()", () => {
161
- const file = Path.makeTempDirSync().join("file.json");
162
+ const file = PathSync.makeTempDirSync().join("file.json");
162
163
  file.writeSync(JSON.stringify({ foo: "bar" }));
163
164
 
164
165
  expect(file.readJSONSync()).toEqual<Record<string, string>>({ foo: "bar" });
@@ -169,7 +170,7 @@ test(".readJSONSync()", () => {
169
170
  });
170
171
 
171
172
  test(".readJSONSync(…) with fallback", () => {
172
- const tempDir = Path.makeTempDirSync();
173
+ const tempDir = PathSync.makeTempDirSync();
173
174
  const file = tempDir.join("file.json");
174
175
  const json: { foo?: number } = file.readJSONSync({ fallback: { foo: 4 } });
175
176
  expect(json).toEqual({ foo: 4 });
@@ -187,7 +188,7 @@ test(".readJSONSync(…) with fallback", () => {
187
188
  });
188
189
 
189
190
  test(".writeSync(…)", () => {
190
- const tempDir = Path.makeTempDirSync();
191
+ const tempDir = PathSync.makeTempDirSync();
191
192
  const file = tempDir.join("file.json");
192
193
  expect(file.writeSync("foo")).toBe(file);
193
194
 
@@ -203,14 +204,14 @@ test(".writeSync(…)", () => {
203
204
  });
204
205
 
205
206
  test(".writeJSONSync(…)", () => {
206
- const file = Path.makeTempDirSync().join("file.json");
207
+ const file = PathSync.makeTempDirSync().join("file.json");
207
208
  expect(file.writeJSONSync({ foo: "bar" })).toBe(file);
208
209
 
209
210
  expect(file.readJSONSync()).toEqual<Record<string, string>>({ foo: "bar" });
210
211
  });
211
212
 
212
213
  test(".appendFileSync(…)", () => {
213
- const file = Path.makeTempDirSync().join("file.txt");
214
+ const file = PathSync.makeTempDirSync().join("file.txt");
214
215
  file.appendFileSync("test\n");
215
216
  expect(file.readTextSync()).toEqual("test\n");
216
217
  file.appendFileSync("more\n");
@@ -218,7 +219,7 @@ test(".appendFileSync(…)", () => {
218
219
  });
219
220
 
220
221
  test(".readDirSync(…)", () => {
221
- const dir = Path.makeTempDirSync();
222
+ const dir = PathSync.makeTempDirSync();
222
223
  dir.join("file.txt").writeSync("hello");
223
224
  dir.join("dir/file.json").writeSync("hello");
224
225
 
@@ -232,7 +233,7 @@ test(".readDirSync(…)", () => {
232
233
  });
233
234
 
234
235
  test(".symlinkSync(…)", () => {
235
- const tempDir = Path.makeTempDirSync();
236
+ const tempDir = PathSync.makeTempDirSync();
236
237
  const source = tempDir.join("foo.txt");
237
238
  const target = tempDir.join("bar.txt");
238
239
  source.symlinkSync(target);
@@ -244,7 +245,7 @@ test(".symlinkSync(…)", () => {
244
245
  });
245
246
 
246
247
  test(".realpathSync(…)", () => {
247
- const tempDir = Path.makeTempDirSync();
248
+ const tempDir = PathSync.makeTempDirSync();
248
249
  const source = tempDir.join("foo.txt");
249
250
  source.writeSync("hello world!");
250
251
  const target = tempDir.join("bar.txt");
@@ -253,7 +254,7 @@ test(".realpathSync(…)", () => {
253
254
  });
254
255
 
255
256
  test(".statSync(…)", () => {
256
- const file = Path.makeTempDirSync().join("foo.txt");
257
+ const file = PathSync.makeTempDirSync().join("foo.txt");
257
258
  file.writeSync("hello");
258
259
 
259
260
  expect(file.statSync()?.size).toEqual(5);
@@ -262,7 +263,7 @@ test(".statSync(…)", () => {
262
263
  });
263
264
 
264
265
  test(".lstatSync(…)", () => {
265
- const tempDir = Path.makeTempDirSync();
266
+ const tempDir = PathSync.makeTempDirSync();
266
267
  const source = tempDir.join("foo.txt");
267
268
  const target = tempDir.join("bar.txt");
268
269
  source.symlinkSync(target);
@@ -274,21 +275,40 @@ test(".lstatSync(…)", () => {
274
275
  expect(target.readTextSync()).toEqual("hello");
275
276
  });
276
277
 
277
- test.only(".chmod(…)", async () => {
278
- const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
278
+ test(".chmodSync(…)", () => {
279
+ const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
280
+ expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
281
+ /ENOENT|Premature close/,
282
+ );
283
+ binPath.writeSync(`#!/usr/bin/env bash
284
+
285
+ echo hi`);
286
+ // TODO: why doesn't this work here instead (but works in `printable-shell-comand`)?
287
+ // binPath.writeSync(`#!/usr/bin/env -S bun run --
288
+
289
+ // console.log("hi");`);
290
+ expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
291
+ /EACCES|Premature close/,
292
+ );
293
+ binPath.chmodSync(0o755);
294
+ expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
295
+ });
296
+
297
+ test(".chmodXSync(…)", () => {
298
+ const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
279
299
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
280
300
  /ENOENT|Premature close/,
281
301
  );
282
- await binPath.write(`#!/usr/bin/env bash
302
+ binPath.writeSync(`#!/usr/bin/env bash
283
303
 
284
304
  echo hi`);
285
305
  // TODO: why doesn't this work here instead (but works in `printable-shell-comand`)?
286
- // await binPath.write(`#!/usr/bin/env -S bun run --
306
+ // binPath.writeSync(`#!/usr/bin/env -S bun run --
287
307
 
288
308
  // console.log("hi");`);
289
309
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
290
310
  /EACCES|Premature close/,
291
311
  );
292
- await binPath.chmod(0o755);
293
- expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
312
+ binPath.chmodXSync();
313
+ expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
294
314
  });