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.
- package/dist/lib/path-class/Path.d.ts +5 -0
- package/dist/lib/path-class/chunks/{chunk-24VX37N3.js → chunk-HPGQLKA5.js} +12 -1
- package/dist/lib/path-class/chunks/chunk-HPGQLKA5.js.map +7 -0
- package/dist/lib/path-class/index.js +1 -1
- package/dist/lib/path-class/sync/PathSync.d.ts +46 -0
- package/dist/lib/path-class/sync/index.d.ts +1 -33
- package/dist/lib/path-class/sync/index.js +179 -119
- package/dist/lib/path-class/sync/index.js.map +3 -3
- package/dist/lib/path-class/sync/modifiedNodeTypes.d.ts +7 -1
- package/package.json +1 -1
- package/src/Path.test.ts +20 -1
- package/src/Path.ts +17 -1
- package/src/sync/{sync.test.ts → PathSync.test.ts} +54 -34
- package/src/sync/PathSync.ts +271 -0
- package/src/sync/index.ts +1 -261
- package/src/sync/modifiedNodeTypes.ts +11 -0
- package/dist/lib/path-class/chunks/chunk-24VX37N3.js.map +0 -7
- package/dist/lib/path-class/sync/static.d.ts +0 -6
- package/src/sync/static.ts +0 -14
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["../../../../src/sync/
|
|
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 {
|
|
5
|
-
"mappings": ";;;;;;AAAA;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK
|
|
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 {
|
|
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.
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
/
|
|
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 =
|
|
28
|
+
const filePath = PathSync.makeTempDirSync();
|
|
28
29
|
expect(filePath.existsSync()).toBe(true);
|
|
29
30
|
expect(() => filePath.existsSync({ mustBe: "file" })).toThrow(
|
|
30
|
-
/
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
278
|
-
const binPath =
|
|
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
|
-
|
|
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
|
-
//
|
|
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
|
-
|
|
293
|
-
expect(
|
|
312
|
+
binPath.chmodXSync();
|
|
313
|
+
expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
|
|
294
314
|
});
|