path-class 0.3.3 → 0.3.4
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/index.d.ts +9 -0
- package/dist/lib/path-class/index.js +16 -0
- package/dist/lib/path-class/index.js.map +2 -2
- package/package.json +1 -1
- package/src/index.test.ts +59 -52
- package/src/index.ts +17 -0
|
@@ -87,5 +87,14 @@ export declare class Path {
|
|
|
87
87
|
data: Path;
|
|
88
88
|
state: Path;
|
|
89
89
|
};
|
|
90
|
+
/** Chainable function to print the path. Prints the same as:
|
|
91
|
+
*
|
|
92
|
+
* if (args.length > 0) {
|
|
93
|
+
* console.log(...args);
|
|
94
|
+
* }
|
|
95
|
+
* console.log(this.path);
|
|
96
|
+
*
|
|
97
|
+
*/
|
|
98
|
+
debugPrint(...args: any[]): Path;
|
|
90
99
|
}
|
|
91
100
|
export {};
|
|
@@ -218,6 +218,22 @@ var Path = class _Path {
|
|
|
218
218
|
data: new _Path(xdgData ?? _Path.homedir.join(".local/share")),
|
|
219
219
|
state: new _Path(xdgState ?? _Path.homedir.join(".local/state"))
|
|
220
220
|
};
|
|
221
|
+
/** Chainable function to print the path. Prints the same as:
|
|
222
|
+
*
|
|
223
|
+
* if (args.length > 0) {
|
|
224
|
+
* console.log(...args);
|
|
225
|
+
* }
|
|
226
|
+
* console.log(this.path);
|
|
227
|
+
*
|
|
228
|
+
*/
|
|
229
|
+
// biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(…)`.
|
|
230
|
+
debugPrint(...args) {
|
|
231
|
+
if (args.length > 0) {
|
|
232
|
+
console.log(...args);
|
|
233
|
+
}
|
|
234
|
+
console.log(this.#path);
|
|
235
|
+
return this;
|
|
236
|
+
}
|
|
221
237
|
};
|
|
222
238
|
export {
|
|
223
239
|
Path
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/index.ts"],
|
|
4
|
-
"sourcesContent": ["import type { Dirent, ObjectEncodingOptions } from \"node:fs\";\nimport {\n cp,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { default as trash } from \"trash\";\nimport { xdgCache, xdgConfig, xdgData, xdgState } from \"xdg-basedir\";\n\n// Modifying the type of `readdir(\u2026)` from `node:fs/promises` to remove the\n// first parameter is difficult, if not impossible. So we give up and duplicate\n// the types manually. This ensures ergonomic types, such as an inferred return\n// type of `string[]` when `options` is not passed.\n\ndeclare function readDirType(\n options?:\n | (ObjectEncodingOptions & {\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n })\n | BufferEncoding\n | null,\n): Promise<string[]>;\n\ndeclare function readDirType(\n options:\n | {\n encoding: \"buffer\";\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n }\n | \"buffer\",\n): Promise<Buffer[]>;\n\ndeclare function readDirType(\n options?:\n | (ObjectEncodingOptions & {\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n })\n | BufferEncoding\n | null,\n): Promise<string[] | Buffer[]>;\n\ndeclare function readDirType(\n options: ObjectEncodingOptions & {\n withFileTypes: true;\n recursive?: boolean | undefined;\n },\n): Promise<Dirent[]>;\n\ndeclare function readDirType(options: {\n encoding: \"buffer\";\n withFileTypes: true;\n recursive?: boolean | undefined;\n}): Promise<Dirent<Buffer>[]>;\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n constructor(path: string | URL | Path) {\n if (path instanceof Path) {\n this.#setNormalizedPath(path.#path);\n return;\n }\n if (path instanceof URL) {\n this.#setNormalizedPath(fileURLToPath(path));\n return;\n }\n if (typeof path === \"string\") {\n this.#setNormalizedPath(path);\n return;\n }\n throw new Error(\"Invalid path\");\n }\n\n #setNormalizedPath(path: string): void {\n this.#path = join(path);\n }\n\n /**\n * Same as `.toString()`, but more concise.\n */\n get path() {\n return this.#path;\n }\n\n toString(): string {\n return this.#path;\n }\n\n /// Constructs a new path by appending the given path segments.\n // TODO: accept `Path` inputs?\n join(...segments: string[]): Path {\n return new Path(join(this.#path, ...segments));\n }\n\n extendBasename(suffix: string): Path {\n const joinedSuffix = join(suffix);\n if (joinedSuffix !== basename(joinedSuffix)) {\n throw new Error(\"Invalid suffix to extend file name.\");\n }\n // TODO: join basename and dirname instead?\n return new Path(this.#path + joinedSuffix);\n }\n\n get parent(): Path {\n return new Path(dirname(this.#path));\n }\n\n // Normally I'd stick with `node`'s name, but I think `.dirname` is a\n // particularly poor name. So we support `.dirname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.parent`. */\n get dirname(): Path {\n return this.parent;\n }\n\n get basename(): Path {\n return new Path(basename(this.#path));\n }\n\n get extension(): string {\n this.#mustNotHaveTrailingSlash();\n return extname(this.#path);\n }\n\n // Normally I'd stick with `node`'s name, but I think `.extname` is a\n // particularly poor name. So we support `.extname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.extension`. */\n get extname(): string {\n return this.extension;\n }\n\n #mustNotHaveTrailingSlash(): void {\n if (this.#path.endsWith(\"/\")) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n }\n\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(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 this.#mustNotHaveTrailingSlash();\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\n async existsAsFile(): Promise<boolean> {\n return this.exists({ mustBe: \"file\" });\n }\n\n async existsAsDir(): Promise<boolean> {\n return this.exists({ mustBe: \"directory\" });\n }\n\n // I don't think `mkdir` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // awkward abbreviation.\n /** Defaults to `recursive: true`. */\n async mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path> {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n await mkdir(this.#path, { recursive: true, ...optionsObject });\n return this;\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n /** Returns the destination path. */\n async cp(\n destination: string | URL | Path,\n options?: Parameters<typeof cp>[2],\n ): Promise<Path> {\n await cp(this.#path, new Path(destination).#path, options);\n return new Path(destination);\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n async rename(destination: string | URL | Path): Promise<void> {\n await rename(this.#path, new Path(destination).#path);\n }\n\n /** Create a temporary dir inside the global temp dir for the current user. */\n static async makeTempDir(prefix?: string): Promise<Path> {\n return new Path(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async trash(): Promise<void> {\n await trash(this.#path, { glob: false });\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n /**\n * Equivalent to:\n *\n * .rm({ recursive: true, force: true, ...(options ?? {}) })\n *\n */\n async rm_rf(options?: Parameters<typeof rm>[1]): Promise<void> {\n await this.rm({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n async fileText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n async fileJSON<T>(): Promise<T> {\n return JSON.parse(await this.fileText());\n }\n\n /** Creates intermediate directories if they do not exist.\n *\n * Returns the original `Path` (for chaining).\n */\n async write(\n data: Parameters<typeof writeFile>[1],\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, data, options);\n return this;\n }\n\n /**\n * If only `data` is provided, this is equivalent to:\n *\n * .write(JSON.stringify(data, null, \" \"));\n *\n * `replacer` and `space` can also be specified, making this equivalent to:\n *\n * .write(JSON.stringify(data, replacer, space));\n *\n * Returns the original `Path` (for chaining).\n */\n async writeJSON<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): Promise<Path> {\n await this.write(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // Normally we'd add a `@deprecated` alias named `.readdir`, but that would\n // differ only by capitalization of a single non-leading character. This can\n // be a bit confusing, especially when autocompleting. So for this function in\n // particular we don't include an alias.\n readDir: typeof readDirType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdir(this.#path, options as any) as any;\n\n static get homedir(): Path {\n return new Path(homedir());\n }\n\n static xdg = {\n cache: new Path(xdgCache ?? Path.homedir.join(\".cache\")),\n config: new Path(xdgConfig ?? Path.homedir.join(\".config\")),\n data: new Path(xdgData ?? Path.homedir.join(\".local/share\")),\n state: new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n };\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["import type { Dirent, ObjectEncodingOptions } from \"node:fs\";\nimport {\n cp,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n rename,\n rm,\n stat,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { fileURLToPath } from \"node:url\";\nimport { default as trash } from \"trash\";\nimport { xdgCache, xdgConfig, xdgData, xdgState } from \"xdg-basedir\";\n\n// Modifying the type of `readdir(\u2026)` from `node:fs/promises` to remove the\n// first parameter is difficult, if not impossible. So we give up and duplicate\n// the types manually. This ensures ergonomic types, such as an inferred return\n// type of `string[]` when `options` is not passed.\n\ndeclare function readDirType(\n options?:\n | (ObjectEncodingOptions & {\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n })\n | BufferEncoding\n | null,\n): Promise<string[]>;\n\ndeclare function readDirType(\n options:\n | {\n encoding: \"buffer\";\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n }\n | \"buffer\",\n): Promise<Buffer[]>;\n\ndeclare function readDirType(\n options?:\n | (ObjectEncodingOptions & {\n withFileTypes?: false | undefined;\n recursive?: boolean | undefined;\n })\n | BufferEncoding\n | null,\n): Promise<string[] | Buffer[]>;\n\ndeclare function readDirType(\n options: ObjectEncodingOptions & {\n withFileTypes: true;\n recursive?: boolean | undefined;\n },\n): Promise<Dirent[]>;\n\ndeclare function readDirType(options: {\n encoding: \"buffer\";\n withFileTypes: true;\n recursive?: boolean | undefined;\n}): Promise<Dirent<Buffer>[]>;\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n constructor(path: string | URL | Path) {\n if (path instanceof Path) {\n this.#setNormalizedPath(path.#path);\n return;\n }\n if (path instanceof URL) {\n this.#setNormalizedPath(fileURLToPath(path));\n return;\n }\n if (typeof path === \"string\") {\n this.#setNormalizedPath(path);\n return;\n }\n throw new Error(\"Invalid path\");\n }\n\n #setNormalizedPath(path: string): void {\n this.#path = join(path);\n }\n\n /**\n * Same as `.toString()`, but more concise.\n */\n get path() {\n return this.#path;\n }\n\n toString(): string {\n return this.#path;\n }\n\n /// Constructs a new path by appending the given path segments.\n // TODO: accept `Path` inputs?\n join(...segments: string[]): Path {\n return new Path(join(this.#path, ...segments));\n }\n\n extendBasename(suffix: string): Path {\n const joinedSuffix = join(suffix);\n if (joinedSuffix !== basename(joinedSuffix)) {\n throw new Error(\"Invalid suffix to extend file name.\");\n }\n // TODO: join basename and dirname instead?\n return new Path(this.#path + joinedSuffix);\n }\n\n get parent(): Path {\n return new Path(dirname(this.#path));\n }\n\n // Normally I'd stick with `node`'s name, but I think `.dirname` is a\n // particularly poor name. So we support `.dirname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.parent`. */\n get dirname(): Path {\n return this.parent;\n }\n\n get basename(): Path {\n return new Path(basename(this.#path));\n }\n\n get extension(): string {\n this.#mustNotHaveTrailingSlash();\n return extname(this.#path);\n }\n\n // Normally I'd stick with `node`'s name, but I think `.extname` is a\n // particularly poor name. So we support `.extname` for discovery but mark it\n // as deprecated, even if it will never be removed.\n /** @deprecated Alias for `.extension`. */\n get extname(): string {\n return this.extension;\n }\n\n #mustNotHaveTrailingSlash(): void {\n if (this.#path.endsWith(\"/\")) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n }\n\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n let stats: Awaited<ReturnType<typeof stat>>;\n try {\n stats = await stat(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 this.#mustNotHaveTrailingSlash();\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\n async existsAsFile(): Promise<boolean> {\n return this.exists({ mustBe: \"file\" });\n }\n\n async existsAsDir(): Promise<boolean> {\n return this.exists({ mustBe: \"directory\" });\n }\n\n // I don't think `mkdir` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // awkward abbreviation.\n /** Defaults to `recursive: true`. */\n async mkdir(options?: Parameters<typeof mkdir>[1]): Promise<Path> {\n const optionsObject = (() => {\n if (typeof options === \"string\" || typeof options === \"number\") {\n return { mode: options };\n }\n return options ?? {};\n })();\n await mkdir(this.#path, { recursive: true, ...optionsObject });\n return this;\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n /** Returns the destination path. */\n async cp(\n destination: string | URL | Path,\n options?: Parameters<typeof cp>[2],\n ): Promise<Path> {\n await cp(this.#path, new Path(destination).#path, options);\n return new Path(destination);\n }\n\n // TODO: check idempotency semantics when the destination exists and is a folder.\n async rename(destination: string | URL | Path): Promise<void> {\n await rename(this.#path, new Path(destination).#path);\n }\n\n /** Create a temporary dir inside the global temp dir for the current user. */\n static async makeTempDir(prefix?: string): Promise<Path> {\n return new Path(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async trash(): Promise<void> {\n await trash(this.#path, { glob: false });\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n /**\n * Equivalent to:\n *\n * .rm({ recursive: true, force: true, ...(options ?? {}) })\n *\n */\n async rm_rf(options?: Parameters<typeof rm>[1]): Promise<void> {\n await this.rm({ recursive: true, force: true, ...(options ?? {}) });\n }\n\n async fileText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n async fileJSON<T>(): Promise<T> {\n return JSON.parse(await this.fileText());\n }\n\n /** Creates intermediate directories if they do not exist.\n *\n * Returns the original `Path` (for chaining).\n */\n async write(\n data: Parameters<typeof writeFile>[1],\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, data, options);\n return this;\n }\n\n /**\n * If only `data` is provided, this is equivalent to:\n *\n * .write(JSON.stringify(data, null, \" \"));\n *\n * `replacer` and `space` can also be specified, making this equivalent to:\n *\n * .write(JSON.stringify(data, replacer, space));\n *\n * Returns the original `Path` (for chaining).\n */\n async writeJSON<T>(\n data: T,\n replacer: Parameters<typeof JSON.stringify>[1] = null,\n space: Parameters<typeof JSON.stringify>[2] = \" \",\n ): Promise<Path> {\n await this.write(JSON.stringify(data, replacer, space));\n return this;\n }\n\n // Normally we'd add a `@deprecated` alias named `.readdir`, but that would\n // differ only by capitalization of a single non-leading character. This can\n // be a bit confusing, especially when autocompleting. So for this function in\n // particular we don't include an alias.\n readDir: typeof readDirType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readdir(this.#path, options as any) as any;\n\n static get homedir(): Path {\n return new Path(homedir());\n }\n\n static xdg = {\n cache: new Path(xdgCache ?? Path.homedir.join(\".cache\")),\n config: new Path(xdgConfig ?? Path.homedir.join(\".config\")),\n data: new Path(xdgData ?? Path.homedir.join(\".local/share\")),\n state: new Path(xdgState ?? Path.homedir.join(\".local/state\")),\n };\n\n /** Chainable function to print the path. Prints the same as:\n *\n * if (args.length > 0) {\n * console.log(...args);\n * }\n * console.log(this.path);\n *\n */\n // biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(\u2026)`.\n debugPrint(...args: any[]): Path {\n if (args.length > 0) {\n console.log(...args);\n }\n console.log(this.#path);\n return this;\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
package/src/index.test.ts
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
import { expect, test } from "bun:test";
|
|
1
|
+
import { expect, spyOn, test } from "bun:test";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { Path } from ".";
|
|
5
5
|
|
|
6
6
|
test("constructor", async () => {
|
|
7
|
-
expect(new Path("foo").
|
|
8
|
-
expect(new Path("./relative").
|
|
9
|
-
expect(new Path("./relative/nested").
|
|
10
|
-
expect(new Path("/absolute").
|
|
11
|
-
expect(new Path("/absolute/nested").
|
|
12
|
-
expect(new Path("trailing/slash/").
|
|
7
|
+
expect(new Path("foo").path).toEqual("foo");
|
|
8
|
+
expect(new Path("./relative").path).toEqual("relative");
|
|
9
|
+
expect(new Path("./relative/nested").path).toEqual("relative/nested");
|
|
10
|
+
expect(new Path("/absolute").path).toEqual("/absolute");
|
|
11
|
+
expect(new Path("/absolute/nested").path).toEqual("/absolute/nested");
|
|
12
|
+
expect(new Path("trailing/slash/").path).toEqual("trailing/slash/");
|
|
13
13
|
});
|
|
14
14
|
|
|
15
15
|
test("normalize", async () => {
|
|
16
|
-
expect(new Path("foo//bar").
|
|
17
|
-
expect(new Path("foo////bar").
|
|
18
|
-
expect(new Path("foo/bar/").
|
|
19
|
-
expect(new Path("foo/bar//").
|
|
20
|
-
expect(new Path("//absolute////bar").
|
|
16
|
+
expect(new Path("foo//bar").path).toEqual("foo/bar");
|
|
17
|
+
expect(new Path("foo////bar").path).toEqual("foo/bar");
|
|
18
|
+
expect(new Path("foo/bar/").path).toEqual("foo/bar/");
|
|
19
|
+
expect(new Path("foo/bar//").path).toEqual("foo/bar/");
|
|
20
|
+
expect(new Path("//absolute////bar").path).toEqual("/absolute/bar");
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
test("join", async () => {
|
|
24
|
-
expect(new Path("foo").join("bar").
|
|
25
|
-
expect(new Path("foo/bar").join("bath", "kitchen/sink").
|
|
24
|
+
expect(new Path("foo").join("bar").path).toEqual("foo/bar");
|
|
25
|
+
expect(new Path("foo/bar").join("bath", "kitchen/sink").path).toEqual(
|
|
26
26
|
"foo/bar/bath/kitchen/sink",
|
|
27
27
|
);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
test("traverse", async () => {
|
|
31
|
-
expect(new Path("foo/bar").join("..").
|
|
32
|
-
expect(new Path("foo/bar").join(".").
|
|
33
|
-
expect(new Path("foo/bar").join("../baz").
|
|
34
|
-
expect(new Path("/absolute/path").join("../..").
|
|
35
|
-
expect(new Path("/absolute/path").join("../../..").
|
|
36
|
-
expect(new Path("/").join("..").
|
|
31
|
+
expect(new Path("foo/bar").join("..").path).toEqual("foo");
|
|
32
|
+
expect(new Path("foo/bar").join(".").path).toEqual("foo/bar");
|
|
33
|
+
expect(new Path("foo/bar").join("../baz").path).toEqual("foo/baz");
|
|
34
|
+
expect(new Path("/absolute/path").join("../..").path).toEqual("/");
|
|
35
|
+
expect(new Path("/absolute/path").join("../../..").path).toEqual("/");
|
|
36
|
+
expect(new Path("/").join("..").path).toEqual("/");
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
test(".extendBasename(…)", async () => {
|
|
40
|
-
expect(
|
|
41
|
-
|
|
42
|
-
)
|
|
40
|
+
expect(new Path("file.mp4").extendBasename(".hevc.qv65.mov").path).toEqual(
|
|
41
|
+
"file.mp4.hevc.qv65.mov",
|
|
42
|
+
);
|
|
43
43
|
// Trailing dots should not be removed.
|
|
44
|
-
expect(
|
|
45
|
-
|
|
46
|
-
)
|
|
44
|
+
expect(new Path("file.mp4.").extendBasename(".hevc.qv65.mov").path).toEqual(
|
|
45
|
+
"file.mp4..hevc.qv65.mov",
|
|
46
|
+
);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test(".parent", async () => {
|
|
50
|
-
expect(new Path("/").parent.
|
|
51
|
-
expect(new Path("dir").parent.
|
|
52
|
-
expect(new Path("dir/").parent.
|
|
50
|
+
expect(new Path("/").parent.path).toEqual("/");
|
|
51
|
+
expect(new Path("dir").parent.path).toEqual(".");
|
|
52
|
+
expect(new Path("dir/").parent.path).toEqual(".");
|
|
53
53
|
});
|
|
54
54
|
|
|
55
55
|
test(".dirname", async () => {
|
|
56
|
-
expect(new Path("/").dirname.
|
|
57
|
-
expect(new Path("dir").dirname.
|
|
58
|
-
expect(new Path("dir/").dirname.
|
|
56
|
+
expect(new Path("/").dirname.path).toEqual("/");
|
|
57
|
+
expect(new Path("dir").dirname.path).toEqual(".");
|
|
58
|
+
expect(new Path("dir/").dirname.path).toEqual(".");
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
test(".basename", async () => {
|
|
62
|
-
expect(new Path("/").basename.
|
|
63
|
-
expect(new Path("dir").basename.
|
|
64
|
-
expect(new Path("dir/").basename.
|
|
65
|
-
expect(Path.xdg.config.join("foo/bar.json").basename.
|
|
62
|
+
expect(new Path("/").basename.path).toEqual("."); // TODO?
|
|
63
|
+
expect(new Path("dir").basename.path).toEqual("dir");
|
|
64
|
+
expect(new Path("dir/").basename.path).toEqual("dir");
|
|
65
|
+
expect(Path.xdg.config.join("foo/bar.json").basename.path).toEqual(
|
|
66
66
|
"bar.json",
|
|
67
67
|
);
|
|
68
68
|
});
|
|
@@ -144,13 +144,13 @@ test(".rename()", async () => {
|
|
|
144
144
|
|
|
145
145
|
test(".makeTempDir(…)", async () => {
|
|
146
146
|
const tempDir = await Path.makeTempDir();
|
|
147
|
-
expect(tempDir.
|
|
148
|
-
expect(tempDir.basename.
|
|
147
|
+
expect(tempDir.path).toContain("/js-temp-");
|
|
148
|
+
expect(tempDir.basename.path).toStartWith("js-temp-");
|
|
149
149
|
expect(await tempDir.existsAsDir()).toBe(true);
|
|
150
150
|
|
|
151
151
|
const tempDir2 = await Path.makeTempDir("foo");
|
|
152
|
-
expect(tempDir2.
|
|
153
|
-
expect(tempDir2.basename.
|
|
152
|
+
expect(tempDir2.path).not.toContain("/js-temp-");
|
|
153
|
+
expect(tempDir2.basename.path).toStartWith("foo");
|
|
154
154
|
});
|
|
155
155
|
|
|
156
156
|
test("trash", async () => {
|
|
@@ -196,7 +196,7 @@ test("rm_rf (file)", async () => {
|
|
|
196
196
|
test("rm_rf (folder)", async () => {
|
|
197
197
|
const tempDir = await Path.makeTempDir();
|
|
198
198
|
await tempDir.join("file.txt").write("");
|
|
199
|
-
expect(tempDir.
|
|
199
|
+
expect(tempDir.path).toContain("/js-temp-");
|
|
200
200
|
expect(await tempDir.exists()).toBe(true);
|
|
201
201
|
await tempDir.rm_rf();
|
|
202
202
|
expect(await tempDir.exists()).toBe(false);
|
|
@@ -210,7 +210,7 @@ test(".fileText()", async () => {
|
|
|
210
210
|
await file.write("bye");
|
|
211
211
|
|
|
212
212
|
expect(await file.fileText()).toBe("bye");
|
|
213
|
-
expect(await readFile(file.
|
|
213
|
+
expect(await readFile(file.path, "utf-8")).toBe("bye");
|
|
214
214
|
});
|
|
215
215
|
|
|
216
216
|
test(".fileJSON()", async () => {
|
|
@@ -219,7 +219,7 @@ test(".fileJSON()", async () => {
|
|
|
219
219
|
|
|
220
220
|
expect(await file.fileJSON()).toEqual<Record<string, string>>({ foo: "bar" });
|
|
221
221
|
expect(await file.fileJSON<Record<string, string>>()).toEqual({ foo: "bar" });
|
|
222
|
-
expect(await JSON.parse(await readFile(file.
|
|
222
|
+
expect(await JSON.parse(await readFile(file.path, "utf-8"))).toEqual<
|
|
223
223
|
Record<string, string>
|
|
224
224
|
>({ foo: "bar" });
|
|
225
225
|
});
|
|
@@ -229,14 +229,14 @@ test(".write(…)", async () => {
|
|
|
229
229
|
const file = tempDir.join("file.json");
|
|
230
230
|
await file.write("foo");
|
|
231
231
|
|
|
232
|
-
expect(
|
|
233
|
-
|
|
234
|
-
)
|
|
232
|
+
expect(await readFile(join(tempDir.path, "./file.json"), "utf-8")).toEqual(
|
|
233
|
+
"foo",
|
|
234
|
+
);
|
|
235
235
|
|
|
236
236
|
const file2 = tempDir.join("nested/file2.json");
|
|
237
237
|
await file2.write("bar");
|
|
238
238
|
expect(
|
|
239
|
-
await readFile(join(tempDir.
|
|
239
|
+
await readFile(join(tempDir.path, "./nested/file2.json"), "utf-8"),
|
|
240
240
|
).toEqual("bar");
|
|
241
241
|
});
|
|
242
242
|
|
|
@@ -259,12 +259,19 @@ test(".readDir(…)", async () => {
|
|
|
259
259
|
});
|
|
260
260
|
|
|
261
261
|
test("homedir", async () => {
|
|
262
|
-
expect(Path.homedir.
|
|
262
|
+
expect(Path.homedir.path).toEqual("/mock/home/dir");
|
|
263
263
|
});
|
|
264
264
|
|
|
265
265
|
test("XDG", async () => {
|
|
266
|
-
expect(Path.xdg.cache.
|
|
267
|
-
expect(Path.xdg.config.
|
|
268
|
-
expect(Path.xdg.data.
|
|
269
|
-
expect(Path.xdg.state.
|
|
266
|
+
expect(Path.xdg.cache.path).toEqual("/mock/home/dir/.cache");
|
|
267
|
+
expect(Path.xdg.config.path).toEqual("/xdg/config");
|
|
268
|
+
expect(Path.xdg.data.path).toEqual("/mock/home/dir/.local/share");
|
|
269
|
+
expect(Path.xdg.state.path).toEqual("/mock/home/dir/.local/state");
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
const spy = spyOn(console, "log");
|
|
273
|
+
|
|
274
|
+
test("debugPrint", async () => {
|
|
275
|
+
Path.homedir.debugPrint("foo");
|
|
276
|
+
expect(spy.mock.calls).toEqual([["foo"], ["/mock/home/dir"]]);
|
|
270
277
|
});
|
package/src/index.ts
CHANGED
|
@@ -308,4 +308,21 @@ export class Path {
|
|
|
308
308
|
data: new Path(xdgData ?? Path.homedir.join(".local/share")),
|
|
309
309
|
state: new Path(xdgState ?? Path.homedir.join(".local/state")),
|
|
310
310
|
};
|
|
311
|
+
|
|
312
|
+
/** Chainable function to print the path. Prints the same as:
|
|
313
|
+
*
|
|
314
|
+
* if (args.length > 0) {
|
|
315
|
+
* console.log(...args);
|
|
316
|
+
* }
|
|
317
|
+
* console.log(this.path);
|
|
318
|
+
*
|
|
319
|
+
*/
|
|
320
|
+
// biome-ignore lint/suspicious/noExplicitAny: This is the correct type, based on `console.log(…)`.
|
|
321
|
+
debugPrint(...args: any[]): Path {
|
|
322
|
+
if (args.length > 0) {
|
|
323
|
+
console.log(...args);
|
|
324
|
+
}
|
|
325
|
+
console.log(this.#path);
|
|
326
|
+
return this;
|
|
327
|
+
}
|
|
311
328
|
}
|