path-class 0.11.0 → 0.11.2

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.
@@ -45,6 +45,15 @@ export declare class Path {
45
45
  */
46
46
  get path(): string;
47
47
  toString(): string;
48
+ /**
49
+ * Format this with the escape codes for printing to the shell in bold blue.
50
+ *
51
+ * Example usage:
52
+ *
53
+ * console.log(`Processing: ${path.blue}`)
54
+ *
55
+ */
56
+ get blue(): string;
48
57
  /** Constructs a new path by appending the given path segments.
49
58
  * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
50
59
  */
@@ -179,6 +179,18 @@ var Path = class _Path {
179
179
  toString() {
180
180
  return this.#path;
181
181
  }
182
+ /**
183
+ * Format this with the escape codes for printing to the shell in bold blue.
184
+ *
185
+ * Example usage:
186
+ *
187
+ * console.log(`Processing: ${path.blue}`)
188
+ *
189
+ */
190
+ get blue() {
191
+ const { styleText } = globalThis.process.getBuiltinModule("node:util");
192
+ return styleText(["bold", "blue"], this.#path);
193
+ }
182
194
  /** Constructs a new path by appending the given path segments.
183
195
  * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
184
196
  */
@@ -499,7 +511,7 @@ var Path = class _Path {
499
511
  );
500
512
  return targetPath;
501
513
  }
502
- // I don't think `lstat` is a great name, but it does match the
514
+ // I don't think `realpath` is a great name, but it does match the
503
515
  // well-established canonical commandline name. So in this case we keep the
504
516
  // name instead of using `realPath`.
505
517
  //
@@ -527,7 +539,7 @@ var Path = class _Path {
527
539
  async chmodX() {
528
540
  const { mode } = await this.stat();
529
541
  await this.chmod(
530
- mode | constants.S_IRWXU | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
542
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
531
543
  );
532
544
  return this;
533
545
  }
@@ -596,4 +608,4 @@ export {
596
608
  stringifyIfPath,
597
609
  mustNotHaveTrailingSlash
598
610
  };
599
- //# sourceMappingURL=chunk-HPGQLKA5.js.map
611
+ //# sourceMappingURL=chunk-QM7EHUFF.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../src/Path.ts"],
4
+ "sourcesContent": ["import {\n appendFile,\n chmod,\n constants,\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n realpath,\n rename,\n rm,\n rmdir,\n stat,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { cwd } from \"node:process\";\nimport { Readable } from \"node:stream\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n xdgCache,\n xdgConfig,\n xdgData,\n xdgRuntime,\n xdgState,\n} from \"xdg-basedir\";\nimport type {\n lstatType,\n readDirType,\n readFileType,\n statType,\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\ntype WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;\nasync function wrangleWritableData(\n data: WritableData | Promise<WritableData>,\n): Promise<Parameters<typeof writeFile>[1]> {\n data = await data;\n if (data instanceof Response) {\n data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);\n }\n if (data instanceof ReadableStream) {\n data = Readable.fromWeb(data);\n }\n return data;\n}\n\nexport enum ResolutionPrefix {\n Absolute = \"absolute\",\n Relative = \"relative\",\n Bare = \"bare\",\n}\n\nexport function resolutionPrefix(pathString: string): ResolutionPrefix {\n if (pathString.startsWith(\"/\")) {\n return ResolutionPrefix.Absolute;\n } else if (pathString.startsWith(\"./\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString.startsWith(\"../\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString === \".\") {\n return ResolutionPrefix.Relative;\n } else if (pathString === \"..\") {\n return ResolutionPrefix.Relative;\n }\n return ResolutionPrefix.Bare;\n}\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n /**\n * If `path` is a string starting with `file:///`, it will be parsed as a file URL.\n */\n constructor(path: string | URL | Path) {\n const s = Path.#pathlikeToString(path);\n this.#setNormalizedPath(s);\n }\n\n static fromString(s: string): Path {\n if (typeof s !== \"string\") {\n throw new Error(\n \"Invalid argument to `Path.fromString(\u2026)` \u2014 expected a string.\",\n );\n }\n return new Path(s);\n }\n\n get resolutionPrefix(): ResolutionPrefix {\n return resolutionPrefix(this.#path);\n }\n\n /**\n * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.\n * Note that `base` must be one of:\n *\n * - a valid second argument to `new URL(\u2026)`.\n * - a `Path` representing an absolute path.\n *\n */\n static resolve(path: string | URL | Path, base: string | URL | Path): Path {\n const baseURL = (() => {\n if (!(base instanceof Path)) {\n if (typeof base === \"string\" && !base.startsWith(\"file://\")) {\n return pathToFileURL(base);\n }\n return base;\n }\n if (!base.isAbsolutePath()) {\n throw new Error(\n \"The `base` arg to `Path.resolve(\u2026)` must be an absolute path.\",\n );\n }\n return pathToFileURL(base.#path);\n })();\n return new Path(new URL(Path.#pathlikeToString(path), baseURL));\n }\n\n static #pathlikeToString(path: string | URL | Path): string {\n if (path instanceof Path) {\n return path.#path;\n }\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n if (typeof path === \"string\") {\n // TODO: allow turning off this heuristic?\n if (path.startsWith(\"file:///\")) {\n return fileURLToPath(path);\n }\n return path;\n }\n throw new Error(\"Invalid path\");\n }\n\n // Preserves the `ResolutionPrefix` status when possible.\n #setNormalizedPath(path: string): void {\n const prefix = resolutionPrefix(path);\n this.#path = join(path);\n if (prefix === ResolutionPrefix.Relative && !this.#path.startsWith(\".\")) {\n // We don't have to handle the case of `\".\"`, as it already starts with `\".\"`\n this.#path = `./${this.#path}`;\n }\n }\n\n isAbsolutePath(): boolean {\n return this.resolutionPrefix === ResolutionPrefix.Absolute;\n }\n\n toFileURL(): URL {\n if (!this.isAbsolutePath()) {\n throw new Error(\n \"Tried to convert to file URL when the path is not absolute.\",\n );\n }\n return pathToFileURL(this.#path);\n }\n\n /**\n * The `Path` can have a trailing slash, indicating that it represents a\n * directory. (If there is no trailing slash, it can represent either a file\n * or a directory.)\n *\n * Some operations will refuse to treat a directory path as a file path. This\n * function identifies such paths.\n */\n hasTrailingSlash(): boolean {\n // TODO: handle Windows semantically\n return this.#path.endsWith(\"/\");\n }\n\n /**\n * Toggles or sets a trailing slash as specified.\n * If the path is `/`, it will always be left as-is.\n */\n // Similar convention to:\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle Most\n // use cases will probably use the `force` parameters, but supporting the\n // \"toggle\" use case is easy to implement and hopefully will make the name\n // and API more familiar to web devs.\n toggleTrailingSlash(force?: boolean): Path {\n if (this.#path === \"/\") {\n return this;\n }\n const wantTrailingSlash = force ?? !this.hasTrailingSlash();\n if (wantTrailingSlash) {\n return this.hasTrailingSlash() ? this : this.join(\"./\");\n } else {\n return this.hasTrailingSlash() ? new Path(this.#path.slice(0, -1)) : this;\n }\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 /**\n * Format this with the escape codes for printing to the shell in bold blue.\n *\n * Example usage:\n *\n * console.log(`Processing: ${path.blue}`)\n *\n */\n get blue() {\n const { styleText } = globalThis.process.getBuiltinModule(\"node:util\");\n return styleText([\"bold\", \"blue\"], this.#path);\n }\n\n /** Constructs a new path by appending the given path segments.\n * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.\n */\n join(...segments: (string | Path)[]): Path {\n const segmentStrings = segments.map((segment) => {\n const s = stringifyIfPath(segment);\n if (resolutionPrefix(s) === ResolutionPrefix.Absolute) {\n throw new Error(\n \"Arguments to `.join(\u2026)` cannot be absolute. Use `.asRelative()` to convert them first if needed.\",\n );\n }\n return s;\n });\n return new Path(join(this.#path, ...segmentStrings));\n }\n\n /**\n * Adjust the prefix to construct a relative path.\n *\n * | Example input | Output |\n * |-----------------|-----------------|\n * | `\"bare\"` | `\"./bare\"` |\n * | `\"./relative\"` | `\"./relative\"` |\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"/absolute\"` | `\"./absolute\"` |\n *\n */\n asRelative(): Path {\n return new Path(`./${this.#path}`);\n }\n\n /**\n * Adjust the prefix to construct an absolute path.\n *\n * | Example input | Output |\n * |-----------------|---------------|\n * | `\"bare\"` | `\"/bare\"` |\n * | `\"./relative\"` | `\"/relative\"` |\n * | `\"../up-first\"` | `\"/up-first\"` |\n * | `\"/absolute\"` | `\"/absolute\"` |\n *\n */\n asAbsolute(): Path {\n return new Path(join(\"/\", this.#path));\n }\n\n /**\n * Adjust the prefix to construct a bare path. Note that this returns `\".\"` if\n * there are no named paths left.\n *\n * | Example input | Output |\n * |-------------------|--------------|\n * | `\"bare\"` | `\"bare\"` |\n * | `\"./relative\" ` | `\"relative\"` |\n * | `\"/absolute\"` | `\"absolute\"` |\n * | `\".\"` | `\".\"` |\n * | `\"down-first/..\"` | `\".\"` |\n * | `\"../up-first\"` | (error) |\n * | `\"..\"` | (error) |\n *\n * Specify `parentTraversalPrefixHandling` in the `options` if you would like\n * to strip or keep resolution prefixes like `../` rather than erroring.\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"strip\" }` |\n * |----------------------|----------------------------------------------------------|\n * | `\"../up-first\"` | `\"up-first\"` |\n * | `\"..\"` | `\".\"` |\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"keep\" }` |\n * |----------------------|---------------------------------------------------------|\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"..\"` | `\"..\"` |\n *\n * If you need the output to start with a named component and return values\n * like `.`, `..`, `../`, or `../\u2026` are not okay, pass\n * `requireNamedComponentPrefix: true`. This is useful if the path represents\n * an `npm`-style package name (e.g. `\"typescript\"`, `\"@biomejs/biome\"`).\n *\n */\n asBare(options?: {\n parentTraversalPrefixHandling?: \"error\" | \"strip\" | \"keep\";\n requireNamedComponentPrefix?: boolean;\n }): Path {\n const path = new Path(join(\".\", this.#path));\n if (!path.#path.startsWith(\"../\") && path.#path !== \"..\") {\n if (\n options?.requireNamedComponentPrefix &&\n path.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n const parentTraversalHandling =\n options?.parentTraversalPrefixHandling ?? \"error\";\n switch (parentTraversalHandling) {\n case \"error\": {\n throw new Error(\n 'Converting path to a bare path resulted in a `..` traversal prefix. Pass `\"strip\"` or `\"keep\"` as the `parentTraversalHandling` option to avoid an error.',\n );\n }\n case \"strip\": {\n let newPath = path.#path.replace(/^(\\.\\.\\/)+/, \"\");\n if ([\"\", \"..\"].includes(newPath)) {\n newPath = \".\";\n }\n const output = new Path(newPath);\n if (\n options?.requireNamedComponentPrefix &&\n output.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return new Path(newPath);\n }\n case \"keep\": {\n if (options?.requireNamedComponentPrefix) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n }\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 mustNotHaveTrailingSlash(this);\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 // TODO: find a neat way to dedup with the sync version?\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\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 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 /**\n * Create a temporary dir inside the global temp dir for the current user.\n *\n * This can be used with [`await\n * using`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/await_using)\n * to automatically delete the dir when it goes out of scope.\n *\n * {\n * await using tempDir = await Path.makeTempDir();\n * // Temporary dir exists while we're inside this block.\n * }\n * // Temporary dir has now been deleted.\n *\n * Note that (due to the semantics of JS runtime implementations) this does\n * not delete the temp dir if the process calls `exit(\u2026)` before the `using`\n * goes out of scope.\n *\n * */\n static async makeTempDir(prefix?: string): Promise<AsyncDisposablePath> {\n return new AsyncDisposablePath(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n async rmDir(): Promise<void> {\n await rmdir(this.#path);\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 read: typeof readFileType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFile(this.#path, options as any) as any;\n\n async readText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n /**\n * Reads JSON from the given file and parses it. No validation is performed\n * (beyond JSON parsing).\n *\n * An optional `fallback` value can be specified. It will be used if (and only\n * if) the file does not exist.\n *\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(\u2026)`.\n async readJSON<T = any>(options?: { fallback?: T }): Promise<T> {\n try {\n return JSON.parse(await this.readText());\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 /**\n * Returns the original `Path` (for chaining).\n */\n async appendFile(\n data: Parameters<typeof appendFile>[1],\n options?: Parameters<typeof appendFile>[2],\n ): Promise<Path> {\n await appendFile(this.#path, data, options);\n return this;\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: WritableData | Promise<WritableData>,\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, await wrangleWritableData(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 /** Returns the destination path. */\n async symlink(\n target: string | URL | Path,\n type?: Parameters<typeof symlink>[2],\n ): Promise<Path> {\n const targetPath = new Path(target);\n await symlink(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlink>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n // I don't think `realpath` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // name instead of using `realPath`.\n //\n // Note: There are no options in our API, because the only option is an\n // encoding. We set the encoding to construct the returned `Path`.\n async realpath(): Promise<Path> {\n return new Path(await realpath(this.#path, \"utf-8\"));\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n stat: typeof statType = (...options) => stat(this.#path, ...options) as any;\n\n // I don't think `lstat` is a great name, but it does match the\n // well-established canonical system call. So in this case we keep the\n // awkward abbreviation.\n lstat: typeof lstatType = (...options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstat(this.#path, ...options) as any;\n\n async chmod(mode: Parameters<typeof chmod>[1]): Promise<Path> {\n await chmod(this.#path, mode);\n return this;\n }\n\n /**\n * Add the executable bit (for everyone) to the given path without modifying other bits (`chmod +x`).\n */\n async chmodX(): Promise<Path> {\n const { mode } = await this.stat();\n await this.chmod(\n mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,\n );\n return this;\n }\n\n static get homedir(): Path {\n return new Path(homedir());\n }\n\n /**\n * Get the current working directory as a path. Always includes a trailing slash.\n * Note that this computes the `cwd` from fresh every time, in case it has changed for the current process.\n */\n static get cwd(): Path {\n return new Path(cwd()).toggleTrailingSlash(true);\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 * {@link Path.xdg.runtime} does not have a default value. Consider\n * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.\n */\n runtime: xdgRuntime ? new Path(xdgRuntime) : undefined,\n runtimeWithStateFallback: xdgRuntime\n ? new Path(xdgRuntime)\n : 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\nexport class AsyncDisposablePath extends Path {\n async [Symbol.asyncDispose]() {\n await this.rm_rf();\n }\n}\n\n/**\n * This function is useful to serialize any `Path`s in a structure to pass on to\n * functions that do not know about the `Path` class, e.g.\n *\n * function process(args: (string | Path)[]) {\n * const argsAsStrings = args.map(stringifyIfPath);\n * }\n *\n */\nexport function stringifyIfPath<T>(value: T | Path): T | string {\n if (value instanceof Path) {\n return value.toString();\n }\n return value;\n}\n\nexport function mustNotHaveTrailingSlash(path: Path): void {\n if (path.hasTrailingSlash()) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ResolutionPrefix"]
7
+ }
@@ -3,7 +3,7 @@ import {
3
3
  Path,
4
4
  ResolutionPrefix,
5
5
  stringifyIfPath
6
- } from "./chunks/chunk-HPGQLKA5.js";
6
+ } from "./chunks/chunk-QM7EHUFF.js";
7
7
  export {
8
8
  AsyncDisposablePath,
9
9
  Path,
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  Path,
3
3
  mustNotHaveTrailingSlash
4
- } from "../chunks/chunk-HPGQLKA5.js";
4
+ } from "../chunks/chunk-QM7EHUFF.js";
5
5
 
6
6
  // src/sync/PathSync.ts
7
7
  import {
@@ -202,7 +202,7 @@ var PathSync = class _PathSync extends Path {
202
202
  chmodXSync() {
203
203
  const { mode } = this.statSync();
204
204
  this.chmodSync(
205
- mode | constants.S_IRWXU | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
205
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
206
206
  );
207
207
  return this;
208
208
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
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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",
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 | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,\n );\n return this;\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "path-class",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
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
@@ -1,11 +1,11 @@
1
1
  import { expect, spyOn, test } from "bun:test";
2
- import { readFile, realpath } from "node:fs/promises";
2
+ import { constants, readFile, realpath } from "node:fs/promises";
3
3
  import { join } from "node:path";
4
4
  import { chdir } from "node:process";
5
5
  import { PrintableShellCommand } from "printable-shell-command";
6
6
  import { Path, ResolutionPrefix, stringifyIfPath } from "./Path";
7
7
 
8
- test("constructor", async () => {
8
+ test.concurrent("constructor", async () => {
9
9
  expect(new Path("bare").path).toEqual("bare");
10
10
  expect(new Path("bare/").path).toEqual("bare/");
11
11
  expect(new Path("bare/path").path).toEqual("bare/path");
@@ -27,7 +27,7 @@ test("constructor", async () => {
27
27
  expect(new Path(new Path("foo")).path).toEqual("foo");
28
28
  });
29
29
 
30
- test(".fromString(…)", async () => {
30
+ test.concurrent(".fromString(…)", async () => {
31
31
  expect(Path.fromString("bare").path).toEqual("bare");
32
32
  // biome-ignore lint/suspicious/noExplicitAny: We're purposely passing an invalid type.
33
33
  expect(() => Path.fromString(new URL("file:///test") as any)).toThrow(
@@ -35,7 +35,7 @@ test(".fromString(…)", async () => {
35
35
  );
36
36
  });
37
37
 
38
- test(".resolutionPrefix", async () => {
38
+ test.concurrent(".resolutionPrefix", async () => {
39
39
  expect(new Path("bare").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
40
40
  expect(new Path("bare/").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
41
41
  expect(new Path("bare/path").resolutionPrefix).toEqual(ResolutionPrefix.Bare);
@@ -79,7 +79,7 @@ test(".resolutionPrefix", async () => {
79
79
  expect(new Path("../").resolutionPrefix).toEqual(ResolutionPrefix.Relative);
80
80
  });
81
81
 
82
- test("Path.resolve(…)", async () => {
82
+ test.concurrent("Path.resolve(…)", async () => {
83
83
  expect(Path.resolve("foo/lish", new Path("/bar/baz")).path).toEqual(
84
84
  "/bar/foo/lish",
85
85
  );
@@ -95,13 +95,13 @@ test("Path.resolve(…)", async () => {
95
95
  );
96
96
  });
97
97
 
98
- test(".isAbsolutePath()", async () => {
98
+ test.concurrent(".isAbsolutePath()", async () => {
99
99
  expect(new Path("/foo/bar").isAbsolutePath()).toBe(true);
100
100
  expect(new Path("foo/bar").isAbsolutePath()).toBe(false);
101
101
  expect(new Path(import.meta.url).isAbsolutePath()).toBe(true);
102
102
  });
103
103
 
104
- test(".toFileURL()", async () => {
104
+ test.concurrent(".toFileURL()", async () => {
105
105
  expect(new Path("/foo/bar").toFileURL().toString()).toEqual(
106
106
  "file:///foo/bar",
107
107
  );
@@ -111,7 +111,7 @@ test(".toFileURL()", async () => {
111
111
  );
112
112
  });
113
113
 
114
- test(".hasTrailingSlash()", async () => {
114
+ test.concurrent(".hasTrailingSlash()", async () => {
115
115
  expect(new Path("/foo/bar").hasTrailingSlash()).toBe(false);
116
116
  expect(new Path("/foo/bar/").hasTrailingSlash()).toBe(true);
117
117
  expect(new Path("foo/bar").hasTrailingSlash()).toBe(false);
@@ -124,7 +124,7 @@ test(".hasTrailingSlash()", async () => {
124
124
  expect(new Path(import.meta.url).join(".").hasTrailingSlash()).toBe(false);
125
125
  });
126
126
 
127
- test(".toggleTrailingSlash(…)", async () => {
127
+ test.concurrent(".toggleTrailingSlash(…)", async () => {
128
128
  expect(new Path("/foo/bar").toggleTrailingSlash().path).toBe("/foo/bar/");
129
129
  expect(new Path("/foo/bar/").toggleTrailingSlash().path).toBe("/foo/bar");
130
130
  expect(new Path("/").toggleTrailingSlash().path).toBe("/");
@@ -134,7 +134,14 @@ test(".toggleTrailingSlash(…)", async () => {
134
134
  expect(new Path("..").toggleTrailingSlash().path).toBe("../");
135
135
  });
136
136
 
137
- test("normalize", async () => {
137
+ test.concurrent(".blue", async () => {
138
+ expect(Path.fromString("bare").path).toEqual("bare");
139
+ expect(`Home dir: ${Path.homedir.blue}`).toEqual(
140
+ "Home dir: \u001b[1m\u001b[34m/mock/home/dir\u001b[39m\u001b[22m",
141
+ );
142
+ });
143
+
144
+ test.concurrent("normalize", async () => {
138
145
  expect(new Path("foo//bar").path).toEqual("foo/bar");
139
146
  expect(new Path("foo////bar").path).toEqual("foo/bar");
140
147
  expect(new Path("foo/bar/").path).toEqual("foo/bar/");
@@ -142,7 +149,7 @@ test("normalize", async () => {
142
149
  expect(new Path("//absolute////bar").path).toEqual("/absolute/bar");
143
150
  });
144
151
 
145
- test(".join(…)", async () => {
152
+ test.concurrent(".join(…)", async () => {
146
153
  expect(new Path("foo").join("bar").path).toEqual("foo/bar");
147
154
  expect(new Path("foo/bar").join("bath", "kitchen/sink").path).toEqual(
148
155
  "foo/bar/bath/kitchen/sink",
@@ -156,7 +163,7 @@ test(".join(…)", async () => {
156
163
  );
157
164
  });
158
165
 
159
- test("asRelative()", async () => {
166
+ test.concurrent("asRelative()", async () => {
160
167
  // From doc comment
161
168
  expect(new Path("bare").asRelative().path).toEqual("./bare");
162
169
  expect(new Path("./relative").asRelative().path).toEqual("./relative");
@@ -174,7 +181,7 @@ test("asRelative()", async () => {
174
181
  expect(new Path("../up/").asRelative().path).toEqual("../up/");
175
182
  });
176
183
 
177
- test("asAbsolute()", async () => {
184
+ test.concurrent("asAbsolute()", async () => {
178
185
  // From doc comment
179
186
  expect(new Path("bare").asAbsolute().path).toEqual("/bare");
180
187
  expect(new Path("./relative").asAbsolute().path).toEqual("/relative");
@@ -186,7 +193,7 @@ test("asAbsolute()", async () => {
186
193
  expect(new Path("../up/").asAbsolute().path).toEqual("/up/");
187
194
  });
188
195
 
189
- test("asBare(…)", async () => {
196
+ test.concurrent("asBare(…)", async () => {
190
197
  const ERROR_1 =
191
198
  'Converting path to a bare path resulted in a `..` traversal prefix. Pass `"strip"` or `"keep"` as the `parentTraversalHandling` option to avoid an error.';
192
199
  const ERROR_2 = "Output does not start with a named component.";
@@ -261,7 +268,7 @@ test("asBare(…)", async () => {
261
268
  ).toThrow(ERROR_2);
262
269
  });
263
270
 
264
- test("traverse", async () => {
271
+ test.concurrent("traverse", async () => {
265
272
  expect(new Path("foo/bar").join("..").path).toEqual("foo");
266
273
  expect(new Path("foo/bar").join(".").path).toEqual("foo/bar");
267
274
  expect(new Path("foo/bar").join("../baz").path).toEqual("foo/baz");
@@ -270,7 +277,7 @@ test("traverse", async () => {
270
277
  expect(new Path("/").join("..").path).toEqual("/");
271
278
  });
272
279
 
273
- test(".extendBasename(…)", async () => {
280
+ test.concurrent(".extendBasename(…)", async () => {
274
281
  expect(new Path("file.mp4").extendBasename(".hevc.qv65.mov").path).toEqual(
275
282
  "file.mp4.hevc.qv65.mov",
276
283
  );
@@ -280,19 +287,19 @@ test(".extendBasename(…)", async () => {
280
287
  );
281
288
  });
282
289
 
283
- test(".parent", async () => {
290
+ test.concurrent(".parent", async () => {
284
291
  expect(new Path("/").parent.path).toEqual("/");
285
292
  expect(new Path("dir").parent.path).toEqual(".");
286
293
  expect(new Path("dir/").parent.path).toEqual(".");
287
294
  });
288
295
 
289
- test(".dirname", async () => {
296
+ test.concurrent(".dirname", async () => {
290
297
  expect(new Path("/").dirname.path).toEqual("/");
291
298
  expect(new Path("dir").dirname.path).toEqual(".");
292
299
  expect(new Path("dir/").dirname.path).toEqual(".");
293
300
  });
294
301
 
295
- test(".basename", async () => {
302
+ test.concurrent(".basename", async () => {
296
303
  expect(new Path("/").basename.path).toEqual("."); // TODO?
297
304
  expect(new Path("dir").basename.path).toEqual("dir");
298
305
  expect(new Path("dir/").basename.path).toEqual("dir");
@@ -301,7 +308,7 @@ test(".basename", async () => {
301
308
  );
302
309
  });
303
310
 
304
- test(".extension", async () => {
311
+ test.concurrent(".extension", async () => {
305
312
  expect(new Path("foo.txt").extension).toEqual(".txt");
306
313
  expect(new Path("foo.").extension).toEqual(".");
307
314
  expect(new Path("foo").extension).toEqual("");
@@ -309,7 +316,7 @@ test(".extension", async () => {
309
316
  expect(() => new Path("/").extension).toThrow();
310
317
  });
311
318
 
312
- test(".extname", async () => {
319
+ test.concurrent(".extname", async () => {
313
320
  expect(new Path("foo.txt").extname).toEqual(".txt");
314
321
  expect(new Path("foo.").extname).toEqual(".");
315
322
  expect(new Path("foo").extname).toEqual("");
@@ -317,7 +324,7 @@ test(".extname", async () => {
317
324
  expect(() => new Path("/").extname).toThrow();
318
325
  });
319
326
 
320
- test(".existsAsFile()", async () => {
327
+ test.concurrent(".existsAsFile()", async () => {
321
328
  const filePath = (await Path.makeTempDir()).join("file.txt");
322
329
  expect(await filePath.exists()).toBe(false);
323
330
  expect(await filePath.exists({ mustBe: "file" })).toBe(false);
@@ -335,7 +342,7 @@ test(".existsAsFile()", async () => {
335
342
  expect(await filePath.existsAsFile()).toBe(true);
336
343
  });
337
344
 
338
- test(".existsAsDir()", async () => {
345
+ test.concurrent(".existsAsDir()", async () => {
339
346
  const filePath = await Path.makeTempDir();
340
347
  expect(await filePath.exists()).toBe(true);
341
348
  expect(() => filePath.exists({ mustBe: "file" })).toThrow(
@@ -350,14 +357,14 @@ test(".existsAsDir()", async () => {
350
357
  expect(await filePath.existsAsDir()).toBe(false);
351
358
  });
352
359
 
353
- test(".mkdir(…) (un-nested)", async () => {
360
+ test.concurrent(".mkdir(…) (un-nested)", async () => {
354
361
  const dir = (await Path.makeTempDir()).join("mkdir-test");
355
362
  expect(await dir.exists()).toBe(false);
356
363
  await dir.mkdir();
357
364
  expect(await dir.exists()).toBe(true);
358
365
  });
359
366
 
360
- test(".mkdir(…) (nested)", async () => {
367
+ test.concurrent(".mkdir(…) (nested)", async () => {
361
368
  const dir = (await Path.makeTempDir()).join("mkdir-test/nested");
362
369
  expect(await dir.exists()).toBe(false);
363
370
  expect(() => dir.mkdir({ recursive: false })).toThrow("no such file");
@@ -365,7 +372,7 @@ test(".mkdir(…) (nested)", async () => {
365
372
  expect(await dir.exists()).toBe(true);
366
373
  });
367
374
 
368
- test(".cp(…)", async () => {
375
+ test.concurrent(".cp(…)", async () => {
369
376
  const parentDir = await Path.makeTempDir();
370
377
  const file1 = parentDir.join("file1.txt");
371
378
  const file2 = parentDir.join("file2.txt");
@@ -379,7 +386,7 @@ test(".cp(…)", async () => {
379
386
  expect(await file2.exists()).toBe(true);
380
387
  });
381
388
 
382
- test(".rename(…)", async () => {
389
+ test.concurrent(".rename(…)", async () => {
383
390
  const parentDir = await Path.makeTempDir();
384
391
  const file1 = parentDir.join("file1.txt");
385
392
  const file2 = parentDir.join("file2.txt");
@@ -393,7 +400,7 @@ test(".rename(…)", async () => {
393
400
  expect(await file2.exists()).toBe(true);
394
401
  });
395
402
 
396
- test(".makeTempDir(…)", async () => {
403
+ test.concurrent(".makeTempDir(…)", async () => {
397
404
  let asyncDisposablePathString: string;
398
405
  {
399
406
  await using tempDir = await Path.makeTempDir();
@@ -414,7 +421,7 @@ test(".makeTempDir(…)", async () => {
414
421
  expect(await new Path(asyncDisposablePathString2).existsAsDir()).toBe(false);
415
422
  });
416
423
 
417
- test(".rm(…) (file)", async () => {
424
+ test.concurrent(".rm(…) (file)", async () => {
418
425
  const file = (await Path.makeTempDir()).join("file.txt");
419
426
  await file.write("");
420
427
  expect(await file.existsAsFile()).toBe(true);
@@ -424,7 +431,7 @@ test(".rm(…) (file)", async () => {
424
431
  expect(async () => file.rm()).toThrowError(/ENOENT/);
425
432
  });
426
433
 
427
- test(".rm(…) (folder)", async () => {
434
+ test.concurrent(".rm(…) (folder)", async () => {
428
435
  const tempDir = await Path.makeTempDir();
429
436
  const file = tempDir.join("file.txt");
430
437
  await file.write("");
@@ -436,7 +443,7 @@ test(".rm(…) (folder)", async () => {
436
443
  expect(async () => tempDir.rm()).toThrowError(/ENOENT/);
437
444
  });
438
445
 
439
- test(".rmDir(…)", async () => {
446
+ test.concurrent(".rmDir(…)", async () => {
440
447
  const tempDir = await Path.makeTempDir();
441
448
  const file = tempDir.join("file.txt");
442
449
  await file.write("");
@@ -448,7 +455,7 @@ test(".rmDir(…)", async () => {
448
455
  expect(async () => tempDir.rmDir()).toThrowError(/ENOENT/);
449
456
  });
450
457
 
451
- test(".rm_rf(…) (file)", async () => {
458
+ test.concurrent(".rm_rf(…) (file)", async () => {
452
459
  const file = (await Path.makeTempDir()).join("file.txt");
453
460
  await file.write("");
454
461
  expect(await file.existsAsFile()).toBe(true);
@@ -459,7 +466,7 @@ test(".rm_rf(…) (file)", async () => {
459
466
  expect(await file.existsAsFile()).toBe(false);
460
467
  });
461
468
 
462
- test(".rm_rf(…) (folder)", async () => {
469
+ test.concurrent(".rm_rf(…) (folder)", async () => {
463
470
  const tempDir = await Path.makeTempDir();
464
471
  await tempDir.join("file.txt").write("");
465
472
  expect(tempDir.path).toContain("/js-temp-");
@@ -470,7 +477,7 @@ test(".rm_rf(…) (folder)", async () => {
470
477
  expect(await tempDir.exists()).toBe(false);
471
478
  });
472
479
 
473
- test(".readText()", async () => {
480
+ test.concurrent(".readText()", async () => {
474
481
  const file = (await Path.makeTempDir()).join("file.txt");
475
482
  await file.write("hi");
476
483
  await file.write("bye");
@@ -479,7 +486,7 @@ test(".readText()", async () => {
479
486
  expect(await readFile(file.path, "utf-8")).toBe("bye");
480
487
  });
481
488
 
482
- test(".readJSON()", async () => {
489
+ test.concurrent(".readJSON()", async () => {
483
490
  const file = (await Path.makeTempDir()).join("file.json");
484
491
  await file.write(JSON.stringify({ foo: "bar" }));
485
492
 
@@ -490,7 +497,7 @@ test(".readJSON()", async () => {
490
497
  >({ foo: "bar" });
491
498
  });
492
499
 
493
- test(".readJSON(…) with fallback", async () => {
500
+ test.concurrent(".readJSON(…) with fallback", async () => {
494
501
  const tempDir = await Path.makeTempDir();
495
502
  const file = tempDir.join("file.json");
496
503
  const json: { foo?: number } = await file.readJSON({ fallback: { foo: 4 } });
@@ -508,7 +515,7 @@ test(".readJSON(…) with fallback", async () => {
508
515
  );
509
516
  });
510
517
 
511
- test(".write(…)", async () => {
518
+ test.concurrent(".write(…)", async () => {
512
519
  const tempDir = await Path.makeTempDir();
513
520
  const file = tempDir.join("file.json");
514
521
  expect(await file.write("foo")).toBe(file);
@@ -524,14 +531,14 @@ test(".write(…)", async () => {
524
531
  ).toEqual("bar");
525
532
  });
526
533
 
527
- test(".writeJSON(…)", async () => {
534
+ test.concurrent(".writeJSON(…)", async () => {
528
535
  const file = (await Path.makeTempDir()).join("file.json");
529
536
  expect(await file.writeJSON({ foo: "bar" })).toBe(file);
530
537
 
531
538
  expect(await file.readJSON()).toEqual<Record<string, string>>({ foo: "bar" });
532
539
  });
533
540
 
534
- test(".appendFile(…)", async () => {
541
+ test.concurrent(".appendFile(…)", async () => {
535
542
  const file = (await Path.makeTempDir()).join("file.txt");
536
543
  await file.appendFile("test\n");
537
544
  expect(await file.readText()).toEqual("test\n");
@@ -539,7 +546,7 @@ test(".appendFile(…)", async () => {
539
546
  expect(await file.readText()).toEqual("test\nmore\n");
540
547
  });
541
548
 
542
- test(".readDir(…)", async () => {
549
+ test.concurrent(".readDir(…)", async () => {
543
550
  const dir = await Path.makeTempDir();
544
551
  await dir.join("file.txt").write("hello");
545
552
  await dir.join("dir/file.json").write("hello");
@@ -553,7 +560,7 @@ test(".readDir(…)", async () => {
553
560
  );
554
561
  });
555
562
 
556
- test(".symlink(…)", async () => {
563
+ test.concurrent(".symlink(…)", async () => {
557
564
  const tempDir = await Path.makeTempDir();
558
565
  const source = tempDir.join("foo.txt");
559
566
  const target = tempDir.join("bar.txt");
@@ -565,7 +572,7 @@ test(".symlink(…)", async () => {
565
572
  expect(await target.readText()).toEqual("hello");
566
573
  });
567
574
 
568
- test(".realpath(…)", async () => {
575
+ test.concurrent(".realpath(…)", async () => {
569
576
  const tempDir = await Path.makeTempDir();
570
577
  const source = tempDir.join("foo.txt");
571
578
  await source.write("hello world!");
@@ -576,7 +583,7 @@ test(".realpath(…)", async () => {
576
583
  );
577
584
  });
578
585
 
579
- test(".stat(…)", async () => {
586
+ test.concurrent(".stat(…)", async () => {
580
587
  const file = (await Path.makeTempDir()).join("foo.txt");
581
588
  await file.write("hello");
582
589
 
@@ -585,7 +592,7 @@ test(".stat(…)", async () => {
585
592
  expect((await file.stat({ bigint: true })).size).toBeTypeOf("bigint");
586
593
  });
587
594
 
588
- test(".lstat(…)", async () => {
595
+ test.concurrent(".lstat(…)", async () => {
589
596
  const tempDir = await Path.makeTempDir();
590
597
  const source = tempDir.join("foo.txt");
591
598
  const target = tempDir.join("bar.txt");
@@ -598,7 +605,7 @@ test(".lstat(…)", async () => {
598
605
  expect(await target.readText()).toEqual("hello");
599
606
  });
600
607
 
601
- test(".chmod(…)", async () => {
608
+ test.concurrent(".chmod(…)", async () => {
602
609
  const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
603
610
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
604
611
  /ENOENT|Premature close/,
@@ -617,7 +624,7 @@ echo hi`);
617
624
  expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
618
625
  });
619
626
 
620
- test(".chmodX(…)", async () => {
627
+ test.concurrent(".chmodX(…)", async () => {
621
628
  const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
622
629
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
623
630
  /ENOENT|Premature close/,
@@ -632,22 +639,28 @@ echo hi`);
632
639
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
633
640
  /EACCES|Premature close/,
634
641
  );
642
+ expect((await binPath.stat()).mode & constants.S_IWUSR).toBeTruthy();
643
+ await binPath.chmod(0o444);
644
+ expect((await binPath.stat()).mode & constants.S_IWUSR).toBeFalsy();
645
+ expect((await binPath.stat()).mode & constants.S_IXUSR).toBeFalsy();
635
646
  await binPath.chmodX();
636
647
  expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
648
+ expect((await binPath.stat()).mode & constants.S_IWUSR).toBeFalsy();
649
+ expect((await binPath.stat()).mode & constants.S_IXUSR).toBeTruthy();
637
650
  });
638
651
 
639
- test(".homedir", async () => {
652
+ test.concurrent(".homedir", async () => {
640
653
  expect(Path.homedir.path).toEqual("/mock/home/dir");
641
654
  });
642
655
 
643
- test(".cwd", async () => {
656
+ test.concurrent(".cwd", async () => {
644
657
  expect(Path.cwd.basename.path).toEqual("path-class");
645
658
  const tempDir = await Path.makeTempDir();
646
659
  chdir(tempDir.path);
647
660
  expect(await realpath(Path.cwd.path)).toEqual(await realpath(tempDir.path));
648
661
  });
649
662
 
650
- test(".xdg", async () => {
663
+ test.concurrent(".xdg", async () => {
651
664
  expect(Path.xdg.cache.path).toEqual("/mock/home/dir/.cache");
652
665
  expect(Path.xdg.config.path).toEqual("/xdg/config");
653
666
  expect(Path.xdg.data.path).toEqual("/mock/home/dir/.local/share");
@@ -661,6 +674,7 @@ test(".xdg", async () => {
661
674
  const spy = spyOn(console, "log");
662
675
 
663
676
  test(".debugPrint(…)", async () => {
677
+ spy.mockReset();
664
678
  Path.homedir.debugPrint("Here is a test log of the mock home directory:");
665
679
  expect(spy.mock.calls).toEqual([
666
680
  ["Here is a test log of the mock home directory:"],
@@ -669,6 +683,7 @@ test(".debugPrint(…)", async () => {
669
683
  });
670
684
 
671
685
  test(".stringifyIfPath(…)", async () => {
686
+ spy.mockReset();
672
687
  expect(stringifyIfPath(Path.homedir)).toBe("/mock/home/dir");
673
688
  expect(stringifyIfPath("/mock/home/dir")).toBe("/mock/home/dir");
674
689
  expect(stringifyIfPath(4)).toBe(4);
package/src/Path.ts CHANGED
@@ -209,6 +209,19 @@ export class Path {
209
209
  return this.#path;
210
210
  }
211
211
 
212
+ /**
213
+ * Format this with the escape codes for printing to the shell in bold blue.
214
+ *
215
+ * Example usage:
216
+ *
217
+ * console.log(`Processing: ${path.blue}`)
218
+ *
219
+ */
220
+ get blue() {
221
+ const { styleText } = globalThis.process.getBuiltinModule("node:util");
222
+ return styleText(["bold", "blue"], this.#path);
223
+ }
224
+
212
225
  /** Constructs a new path by appending the given path segments.
213
226
  * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.
214
227
  */
@@ -589,7 +602,7 @@ export class Path {
589
602
  return targetPath;
590
603
  }
591
604
 
592
- // I don't think `lstat` is a great name, but it does match the
605
+ // I don't think `realpath` is a great name, but it does match the
593
606
  // well-established canonical commandline name. So in this case we keep the
594
607
  // name instead of using `realPath`.
595
608
  //
@@ -620,11 +633,7 @@ export class Path {
620
633
  async chmodX(): Promise<Path> {
621
634
  const { mode } = await this.stat();
622
635
  await this.chmod(
623
- mode |
624
- constants.S_IRWXU |
625
- constants.S_IXUSR |
626
- constants.S_IXGRP |
627
- constants.S_IXOTH,
636
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,
628
637
  );
629
638
  return this;
630
639
  }
@@ -2,11 +2,11 @@ import { expect, test } from "bun:test";
2
2
  import { readFileSync } from "node:fs";
3
3
  import { join } from "node:path";
4
4
  import "./PathSync";
5
+ import { constants } from "node:fs/promises";
5
6
  import { PrintableShellCommand } from "printable-shell-command";
6
-
7
7
  import { PathSync } from "./PathSync";
8
8
 
9
- test(".existsAsFileSync()", () => {
9
+ test.concurrent(".existsAsFileSync()", () => {
10
10
  const filePath = PathSync.makeTempDirSync().join("file.txt");
11
11
  expect(filePath.existsSync()).toBe(false);
12
12
  expect(filePath.existsSync({ mustBe: "file" })).toBe(false);
@@ -24,7 +24,7 @@ test(".existsAsFileSync()", () => {
24
24
  expect(filePath.existsAsFileSync()).toBe(true);
25
25
  });
26
26
 
27
- test(".existsAsDir()", () => {
27
+ test.concurrent(".existsAsDir()", () => {
28
28
  const filePath = PathSync.makeTempDirSync();
29
29
  expect(filePath.existsSync()).toBe(true);
30
30
  expect(() => filePath.existsSync({ mustBe: "file" })).toThrow(
@@ -39,14 +39,14 @@ test(".existsAsDir()", () => {
39
39
  expect(filePath.existsAsDirSync()).toBe(false);
40
40
  });
41
41
 
42
- test(".mkdirSync(…) (un-nested)", () => {
42
+ test.concurrent(".mkdirSync(…) (un-nested)", () => {
43
43
  const dir = PathSync.makeTempDirSync().join("mkdir-test");
44
44
  expect(dir.existsSync()).toBe(false);
45
45
  dir.mkdirSync();
46
46
  expect(dir.existsSync()).toBe(true);
47
47
  });
48
48
 
49
- test(".mkdirSync(…) (nested)", () => {
49
+ test.concurrent(".mkdirSync(…) (nested)", () => {
50
50
  const dir = PathSync.makeTempDirSync().join("mkdir-test/nested");
51
51
  expect(dir.existsSync()).toBe(false);
52
52
  expect(() => dir.mkdirSync({ recursive: false })).toThrow("no such file");
@@ -54,7 +54,7 @@ test(".mkdirSync(…) (nested)", () => {
54
54
  expect(dir.existsSync()).toBe(true);
55
55
  });
56
56
 
57
- test(".cpSync(…)", () => {
57
+ test.concurrent(".cpSync(…)", () => {
58
58
  const parentDir = PathSync.makeTempDirSync();
59
59
  const file1 = parentDir.join("file1.txt");
60
60
  const file2 = parentDir.join("file2.txt");
@@ -68,7 +68,7 @@ test(".cpSync(…)", () => {
68
68
  expect(file2.existsSync()).toBe(true);
69
69
  });
70
70
 
71
- test(".renameSync(…)", () => {
71
+ test.concurrent(".renameSync(…)", () => {
72
72
  const parentDir = PathSync.makeTempDirSync();
73
73
  const file1 = parentDir.join("file1.txt");
74
74
  const file2 = parentDir.join("file2.txt");
@@ -82,7 +82,7 @@ test(".renameSync(…)", () => {
82
82
  expect(file2.existsSync()).toBe(true);
83
83
  });
84
84
 
85
- test(".makeTempDirSync(…)", () => {
85
+ test.concurrent(".makeTempDirSync(…)", () => {
86
86
  const tempDir = PathSync.makeTempDirSync();
87
87
  expect(tempDir.path).toContain("/js-temp-");
88
88
  expect(tempDir.basename.path).toStartWith("js-temp-");
@@ -93,7 +93,7 @@ test(".makeTempDirSync(…)", () => {
93
93
  expect(tempDir2.basename.path).toStartWith("foo");
94
94
  });
95
95
 
96
- test(".rmSync(…) (file)", () => {
96
+ test.concurrent(".rmSync(…) (file)", () => {
97
97
  const file = PathSync.makeTempDirSync().join("file.txt");
98
98
  file.writeSync("");
99
99
  expect(file.existsAsFileSync()).toBe(true);
@@ -103,7 +103,7 @@ test(".rmSync(…) (file)", () => {
103
103
  expect(() => file.rmSync()).toThrowError(/ENOENT/);
104
104
  });
105
105
 
106
- test(".rmSync(…) (folder)", () => {
106
+ test.concurrent(".rmSync(…) (folder)", () => {
107
107
  const tempDir = PathSync.makeTempDirSync();
108
108
  const file = tempDir.join("file.txt");
109
109
  file.writeSync("");
@@ -115,7 +115,7 @@ test(".rmSync(…) (folder)", () => {
115
115
  expect(() => tempDir.rmSync()).toThrowError(/ENOENT/);
116
116
  });
117
117
 
118
- test(".rmDirSync(…) (folder)", () => {
118
+ test.concurrent(".rmDirSync(…) (folder)", () => {
119
119
  const tempDir = PathSync.makeTempDirSync();
120
120
  const file = tempDir.join("file.txt");
121
121
  file.writeSync("");
@@ -127,7 +127,7 @@ test(".rmDirSync(…) (folder)", () => {
127
127
  expect(() => tempDir.rmDirSync()).toThrowError(/ENOENT/);
128
128
  });
129
129
 
130
- test(".rm_rfSync(…) (file)", () => {
130
+ test.concurrent(".rm_rfSync(…) (file)", () => {
131
131
  const file = PathSync.makeTempDirSync().join("file.txt");
132
132
  file.writeSync("");
133
133
  expect(file.existsAsFileSync()).toBe(true);
@@ -138,7 +138,7 @@ test(".rm_rfSync(…) (file)", () => {
138
138
  expect(file.existsAsFileSync()).toBe(false);
139
139
  });
140
140
 
141
- test(".rm_rfSync(…) (folder)", () => {
141
+ test.concurrent(".rm_rfSync(…) (folder)", () => {
142
142
  const tempDir = PathSync.makeTempDirSync();
143
143
  tempDir.join("file.txt").writeSync("");
144
144
  expect(tempDir.path).toContain("/js-temp-");
@@ -149,7 +149,7 @@ test(".rm_rfSync(…) (folder)", () => {
149
149
  expect(tempDir.existsSync()).toBe(false);
150
150
  });
151
151
 
152
- test(".readTextSync()", () => {
152
+ test.concurrent(".readTextSync()", () => {
153
153
  const file = PathSync.makeTempDirSync().join("file.txt");
154
154
  file.writeSync("hi");
155
155
  file.writeSync("bye");
@@ -158,7 +158,7 @@ test(".readTextSync()", () => {
158
158
  expect(readFileSync(file.path, "utf-8")).toBe("bye");
159
159
  });
160
160
 
161
- test(".readJSONSync()", () => {
161
+ test.concurrent(".readJSONSync()", () => {
162
162
  const file = PathSync.makeTempDirSync().join("file.json");
163
163
  file.writeSync(JSON.stringify({ foo: "bar" }));
164
164
 
@@ -169,7 +169,7 @@ test(".readJSONSync()", () => {
169
169
  >({ foo: "bar" });
170
170
  });
171
171
 
172
- test(".readJSONSync(…) with fallback", () => {
172
+ test.concurrent(".readJSONSync(…) with fallback", () => {
173
173
  const tempDir = PathSync.makeTempDirSync();
174
174
  const file = tempDir.join("file.json");
175
175
  const json: { foo?: number } = file.readJSONSync({ fallback: { foo: 4 } });
@@ -187,7 +187,7 @@ test(".readJSONSync(…) with fallback", () => {
187
187
  );
188
188
  });
189
189
 
190
- test(".writeSync(…)", () => {
190
+ test.concurrent(".writeSync(…)", () => {
191
191
  const tempDir = PathSync.makeTempDirSync();
192
192
  const file = tempDir.join("file.json");
193
193
  expect(file.writeSync("foo")).toBe(file);
@@ -203,14 +203,14 @@ test(".writeSync(…)", () => {
203
203
  ).toEqual("bar");
204
204
  });
205
205
 
206
- test(".writeJSONSync(…)", () => {
206
+ test.concurrent(".writeJSONSync(…)", () => {
207
207
  const file = PathSync.makeTempDirSync().join("file.json");
208
208
  expect(file.writeJSONSync({ foo: "bar" })).toBe(file);
209
209
 
210
210
  expect(file.readJSONSync()).toEqual<Record<string, string>>({ foo: "bar" });
211
211
  });
212
212
 
213
- test(".appendFileSync(…)", () => {
213
+ test.concurrent(".appendFileSync(…)", () => {
214
214
  const file = PathSync.makeTempDirSync().join("file.txt");
215
215
  file.appendFileSync("test\n");
216
216
  expect(file.readTextSync()).toEqual("test\n");
@@ -218,7 +218,7 @@ test(".appendFileSync(…)", () => {
218
218
  expect(file.readTextSync()).toEqual("test\nmore\n");
219
219
  });
220
220
 
221
- test(".readDirSync(…)", () => {
221
+ test.concurrent(".readDirSync(…)", () => {
222
222
  const dir = PathSync.makeTempDirSync();
223
223
  dir.join("file.txt").writeSync("hello");
224
224
  dir.join("dir/file.json").writeSync("hello");
@@ -232,7 +232,7 @@ test(".readDirSync(…)", () => {
232
232
  );
233
233
  });
234
234
 
235
- test(".symlinkSync(…)", () => {
235
+ test.concurrent(".symlinkSync(…)", () => {
236
236
  const tempDir = PathSync.makeTempDirSync();
237
237
  const source = tempDir.join("foo.txt");
238
238
  const target = tempDir.join("bar.txt");
@@ -244,7 +244,7 @@ test(".symlinkSync(…)", () => {
244
244
  expect(target.readTextSync()).toEqual("hello");
245
245
  });
246
246
 
247
- test(".realpathSync(…)", () => {
247
+ test.concurrent(".realpathSync(…)", () => {
248
248
  const tempDir = PathSync.makeTempDirSync();
249
249
  const source = tempDir.join("foo.txt");
250
250
  source.writeSync("hello world!");
@@ -253,7 +253,7 @@ test(".realpathSync(…)", () => {
253
253
  expect(source.realpathSync().path).toEqual(target.realpathSync().path);
254
254
  });
255
255
 
256
- test(".statSync(…)", () => {
256
+ test.concurrent(".statSync(…)", () => {
257
257
  const file = PathSync.makeTempDirSync().join("foo.txt");
258
258
  file.writeSync("hello");
259
259
 
@@ -262,7 +262,7 @@ test(".statSync(…)", () => {
262
262
  expect(file.statSync({ bigint: true })?.size).toBeTypeOf("bigint");
263
263
  });
264
264
 
265
- test(".lstatSync(…)", () => {
265
+ test.concurrent(".lstatSync(…)", () => {
266
266
  const tempDir = PathSync.makeTempDirSync();
267
267
  const source = tempDir.join("foo.txt");
268
268
  const target = tempDir.join("bar.txt");
@@ -275,7 +275,7 @@ test(".lstatSync(…)", () => {
275
275
  expect(target.readTextSync()).toEqual("hello");
276
276
  });
277
277
 
278
- test(".chmodSync(…)", () => {
278
+ test.concurrent(".chmodSync(…)", () => {
279
279
  const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
280
280
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
281
281
  /ENOENT|Premature close/,
@@ -294,7 +294,7 @@ echo hi`);
294
294
  expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
295
295
  });
296
296
 
297
- test(".chmodXSync(…)", () => {
297
+ test.concurrent(".chmodXSync(…)", () => {
298
298
  const binPath = PathSync.makeTempDirSync().join("nonexistent.bin");
299
299
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
300
300
  /ENOENT|Premature close/,
@@ -309,6 +309,12 @@ echo hi`);
309
309
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
310
310
  /EACCES|Premature close/,
311
311
  );
312
+ expect(binPath.statSync().mode & constants.S_IWUSR).toBeTruthy();
313
+ binPath.chmodSync(0o444);
314
+ expect(binPath.statSync().mode & constants.S_IWUSR).toBeFalsy();
315
+ expect(binPath.statSync().mode & constants.S_IXUSR).toBeFalsy();
312
316
  binPath.chmodXSync();
313
317
  expect(() => new PrintableShellCommand(binPath, []).text()).not.toThrow();
318
+ expect(binPath.statSync().mode & constants.S_IWUSR).toBeFalsy();
319
+ expect(binPath.statSync().mode & constants.S_IXUSR).toBeTruthy();
314
320
  });
@@ -260,11 +260,7 @@ export class PathSync extends Path {
260
260
  chmodXSync(): PathSync {
261
261
  const { mode } = this.statSync();
262
262
  this.chmodSync(
263
- mode |
264
- constants.S_IRWXU |
265
- constants.S_IXUSR |
266
- constants.S_IXGRP |
267
- constants.S_IXOTH,
263
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,
268
264
  );
269
265
  return this;
270
266
  }
@@ -1,7 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../../../src/Path.ts"],
4
- "sourcesContent": ["import {\n appendFile,\n chmod,\n constants,\n cp,\n lstat,\n mkdir,\n mkdtemp,\n readdir,\n readFile,\n realpath,\n rename,\n rm,\n rmdir,\n stat,\n symlink,\n writeFile,\n} from \"node:fs/promises\";\nimport { homedir, tmpdir } from \"node:os\";\nimport { basename, dirname, extname, join } from \"node:path\";\nimport { cwd } from \"node:process\";\nimport { Readable } from \"node:stream\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\nimport {\n xdgCache,\n xdgConfig,\n xdgData,\n xdgRuntime,\n xdgState,\n} from \"xdg-basedir\";\nimport type {\n lstatType,\n readDirType,\n readFileType,\n statType,\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\ntype WritableData = Parameters<typeof writeFile>[1] | ReadableStream | Response;\nasync function wrangleWritableData(\n data: WritableData | Promise<WritableData>,\n): Promise<Parameters<typeof writeFile>[1]> {\n data = await data;\n if (data instanceof Response) {\n data = data.body ? Readable.fromWeb(data.body) : new Uint8Array(0);\n }\n if (data instanceof ReadableStream) {\n data = Readable.fromWeb(data);\n }\n return data;\n}\n\nexport enum ResolutionPrefix {\n Absolute = \"absolute\",\n Relative = \"relative\",\n Bare = \"bare\",\n}\n\nexport function resolutionPrefix(pathString: string): ResolutionPrefix {\n if (pathString.startsWith(\"/\")) {\n return ResolutionPrefix.Absolute;\n } else if (pathString.startsWith(\"./\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString.startsWith(\"../\")) {\n return ResolutionPrefix.Relative;\n } else if (pathString === \".\") {\n return ResolutionPrefix.Relative;\n } else if (pathString === \"..\") {\n return ResolutionPrefix.Relative;\n }\n return ResolutionPrefix.Bare;\n}\n\nexport class Path {\n // @ts-expect-error ts(2564): False positive. https://github.com/microsoft/TypeScript/issues/32194\n #path: string;\n /**\n * If `path` is a string starting with `file:///`, it will be parsed as a file URL.\n */\n constructor(path: string | URL | Path) {\n const s = Path.#pathlikeToString(path);\n this.#setNormalizedPath(s);\n }\n\n static fromString(s: string): Path {\n if (typeof s !== \"string\") {\n throw new Error(\n \"Invalid argument to `Path.fromString(\u2026)` \u2014 expected a string.\",\n );\n }\n return new Path(s);\n }\n\n get resolutionPrefix(): ResolutionPrefix {\n return resolutionPrefix(this.#path);\n }\n\n /**\n * Similar to `new URL(path, base)`, but accepting and returning `Path` objects.\n * Note that `base` must be one of:\n *\n * - a valid second argument to `new URL(\u2026)`.\n * - a `Path` representing an absolute path.\n *\n */\n static resolve(path: string | URL | Path, base: string | URL | Path): Path {\n const baseURL = (() => {\n if (!(base instanceof Path)) {\n if (typeof base === \"string\" && !base.startsWith(\"file://\")) {\n return pathToFileURL(base);\n }\n return base;\n }\n if (!base.isAbsolutePath()) {\n throw new Error(\n \"The `base` arg to `Path.resolve(\u2026)` must be an absolute path.\",\n );\n }\n return pathToFileURL(base.#path);\n })();\n return new Path(new URL(Path.#pathlikeToString(path), baseURL));\n }\n\n static #pathlikeToString(path: string | URL | Path): string {\n if (path instanceof Path) {\n return path.#path;\n }\n if (path instanceof URL) {\n return fileURLToPath(path);\n }\n if (typeof path === \"string\") {\n // TODO: allow turning off this heuristic?\n if (path.startsWith(\"file:///\")) {\n return fileURLToPath(path);\n }\n return path;\n }\n throw new Error(\"Invalid path\");\n }\n\n // Preserves the `ResolutionPrefix` status when possible.\n #setNormalizedPath(path: string): void {\n const prefix = resolutionPrefix(path);\n this.#path = join(path);\n if (prefix === ResolutionPrefix.Relative && !this.#path.startsWith(\".\")) {\n // We don't have to handle the case of `\".\"`, as it already starts with `\".\"`\n this.#path = `./${this.#path}`;\n }\n }\n\n isAbsolutePath(): boolean {\n return this.resolutionPrefix === ResolutionPrefix.Absolute;\n }\n\n toFileURL(): URL {\n if (!this.isAbsolutePath()) {\n throw new Error(\n \"Tried to convert to file URL when the path is not absolute.\",\n );\n }\n return pathToFileURL(this.#path);\n }\n\n /**\n * The `Path` can have a trailing slash, indicating that it represents a\n * directory. (If there is no trailing slash, it can represent either a file\n * or a directory.)\n *\n * Some operations will refuse to treat a directory path as a file path. This\n * function identifies such paths.\n */\n hasTrailingSlash(): boolean {\n // TODO: handle Windows semantically\n return this.#path.endsWith(\"/\");\n }\n\n /**\n * Toggles or sets a trailing slash as specified.\n * If the path is `/`, it will always be left as-is.\n */\n // Similar convention to:\n // https://developer.mozilla.org/en-US/docs/Web/API/DOMTokenList/toggle Most\n // use cases will probably use the `force` parameters, but supporting the\n // \"toggle\" use case is easy to implement and hopefully will make the name\n // and API more familiar to web devs.\n toggleTrailingSlash(force?: boolean): Path {\n if (this.#path === \"/\") {\n return this;\n }\n const wantTrailingSlash = force ?? !this.hasTrailingSlash();\n if (wantTrailingSlash) {\n return this.hasTrailingSlash() ? this : this.join(\"./\");\n } else {\n return this.hasTrailingSlash() ? new Path(this.#path.slice(0, -1)) : this;\n }\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 * This follows `node` semantics for absolute paths: leading slashes in the given descendant segments are ignored.\n */\n join(...segments: (string | Path)[]): Path {\n const segmentStrings = segments.map((segment) => {\n const s = stringifyIfPath(segment);\n if (resolutionPrefix(s) === ResolutionPrefix.Absolute) {\n throw new Error(\n \"Arguments to `.join(\u2026)` cannot be absolute. Use `.asRelative()` to convert them first if needed.\",\n );\n }\n return s;\n });\n return new Path(join(this.#path, ...segmentStrings));\n }\n\n /**\n * Adjust the prefix to construct a relative path.\n *\n * | Example input | Output |\n * |-----------------|-----------------|\n * | `\"bare\"` | `\"./bare\"` |\n * | `\"./relative\"` | `\"./relative\"` |\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"/absolute\"` | `\"./absolute\"` |\n *\n */\n asRelative(): Path {\n return new Path(`./${this.#path}`);\n }\n\n /**\n * Adjust the prefix to construct an absolute path.\n *\n * | Example input | Output |\n * |-----------------|---------------|\n * | `\"bare\"` | `\"/bare\"` |\n * | `\"./relative\"` | `\"/relative\"` |\n * | `\"../up-first\"` | `\"/up-first\"` |\n * | `\"/absolute\"` | `\"/absolute\"` |\n *\n */\n asAbsolute(): Path {\n return new Path(join(\"/\", this.#path));\n }\n\n /**\n * Adjust the prefix to construct a bare path. Note that this returns `\".\"` if\n * there are no named paths left.\n *\n * | Example input | Output |\n * |-------------------|--------------|\n * | `\"bare\"` | `\"bare\"` |\n * | `\"./relative\" ` | `\"relative\"` |\n * | `\"/absolute\"` | `\"absolute\"` |\n * | `\".\"` | `\".\"` |\n * | `\"down-first/..\"` | `\".\"` |\n * | `\"../up-first\"` | (error) |\n * | `\"..\"` | (error) |\n *\n * Specify `parentTraversalPrefixHandling` in the `options` if you would like\n * to strip or keep resolution prefixes like `../` rather than erroring.\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"strip\" }` |\n * |----------------------|----------------------------------------------------------|\n * | `\"../up-first\"` | `\"up-first\"` |\n * | `\"..\"` | `\".\"` |\n *\n * | Example input | Output with `{ parentTraversalPrefixHandling: \"keep\" }` |\n * |----------------------|---------------------------------------------------------|\n * | `\"../up-first\"` | `\"../up-first\"` |\n * | `\"..\"` | `\"..\"` |\n *\n * If you need the output to start with a named component and return values\n * like `.`, `..`, `../`, or `../\u2026` are not okay, pass\n * `requireNamedComponentPrefix: true`. This is useful if the path represents\n * an `npm`-style package name (e.g. `\"typescript\"`, `\"@biomejs/biome\"`).\n *\n */\n asBare(options?: {\n parentTraversalPrefixHandling?: \"error\" | \"strip\" | \"keep\";\n requireNamedComponentPrefix?: boolean;\n }): Path {\n const path = new Path(join(\".\", this.#path));\n if (!path.#path.startsWith(\"../\") && path.#path !== \"..\") {\n if (\n options?.requireNamedComponentPrefix &&\n path.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n const parentTraversalHandling =\n options?.parentTraversalPrefixHandling ?? \"error\";\n switch (parentTraversalHandling) {\n case \"error\": {\n throw new Error(\n 'Converting path to a bare path resulted in a `..` traversal prefix. Pass `\"strip\"` or `\"keep\"` as the `parentTraversalHandling` option to avoid an error.',\n );\n }\n case \"strip\": {\n let newPath = path.#path.replace(/^(\\.\\.\\/)+/, \"\");\n if ([\"\", \"..\"].includes(newPath)) {\n newPath = \".\";\n }\n const output = new Path(newPath);\n if (\n options?.requireNamedComponentPrefix &&\n output.resolutionPrefix === ResolutionPrefix.Relative\n ) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return new Path(newPath);\n }\n case \"keep\": {\n if (options?.requireNamedComponentPrefix) {\n throw new Error(\"Output does not start with a named component.\");\n }\n return path;\n }\n }\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 mustNotHaveTrailingSlash(this);\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 // TODO: find a neat way to dedup with the sync version?\n async exists(constraints?: {\n mustBe: \"file\" | \"directory\";\n }): Promise<boolean> {\n if (constraints?.mustBe === \"file\") {\n mustNotHaveTrailingSlash(this);\n }\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 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 /**\n * Create a temporary dir inside the global temp dir for the current user.\n *\n * This can be used with [`await\n * using`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/await_using)\n * to automatically delete the dir when it goes out of scope.\n *\n * {\n * await using tempDir = await Path.makeTempDir();\n * // Temporary dir exists while we're inside this block.\n * }\n * // Temporary dir has now been deleted.\n *\n * Note that (due to the semantics of JS runtime implementations) this does\n * not delete the temp dir if the process calls `exit(\u2026)` before the `using`\n * goes out of scope.\n *\n * */\n static async makeTempDir(prefix?: string): Promise<AsyncDisposablePath> {\n return new AsyncDisposablePath(\n await mkdtemp(new Path(tmpdir()).join(prefix ?? \"js-temp-\").toString()),\n );\n }\n\n async rm(options?: Parameters<typeof rm>[1]): Promise<void> {\n await rm(this.#path, options);\n }\n\n async rmDir(): Promise<void> {\n await rmdir(this.#path);\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 read: typeof readFileType = (options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n readFile(this.#path, options as any) as any;\n\n async readText(): Promise<string> {\n return readFile(this.#path, \"utf-8\");\n }\n\n /**\n * Reads JSON from the given file and parses it. No validation is performed\n * (beyond JSON parsing).\n *\n * An optional `fallback` value can be specified. It will be used if (and only\n * if) the file does not exist.\n *\n */\n\n // biome-ignore lint/suspicious/noExplicitAny: Allow a default of `any` to match `JSON.parse(\u2026)`.\n async readJSON<T = any>(options?: { fallback?: T }): Promise<T> {\n try {\n return JSON.parse(await this.readText());\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 /**\n * Returns the original `Path` (for chaining).\n */\n async appendFile(\n data: Parameters<typeof appendFile>[1],\n options?: Parameters<typeof appendFile>[2],\n ): Promise<Path> {\n await appendFile(this.#path, data, options);\n return this;\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: WritableData | Promise<WritableData>,\n options?: Parameters<typeof writeFile>[2],\n ): Promise<Path> {\n await this.parent.mkdir();\n await writeFile(this.#path, await wrangleWritableData(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 /** Returns the destination path. */\n async symlink(\n target: string | URL | Path,\n type?: Parameters<typeof symlink>[2],\n ): Promise<Path> {\n const targetPath = new Path(target);\n await symlink(\n this.path,\n targetPath.path,\n type as Exclude<Parameters<typeof symlink>[2], undefined>, // \uD83E\uDD37\n );\n return targetPath;\n }\n\n // I don't think `lstat` is a great name, but it does match the\n // well-established canonical commandline name. So in this case we keep the\n // name instead of using `realPath`.\n //\n // Note: There are no options in our API, because the only option is an\n // encoding. We set the encoding to construct the returned `Path`.\n async realpath(): Promise<Path> {\n return new Path(await realpath(this.#path, \"utf-8\"));\n }\n\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n stat: typeof statType = (...options) => stat(this.#path, ...options) as any;\n\n // I don't think `lstat` is a great name, but it does match the\n // well-established canonical system call. So in this case we keep the\n // awkward abbreviation.\n lstat: typeof lstatType = (...options) =>\n // biome-ignore lint/suspicious/noExplicitAny: Needed to wrangle the types.\n lstat(this.#path, ...options) as any;\n\n async chmod(mode: Parameters<typeof chmod>[1]): Promise<Path> {\n await chmod(this.#path, mode);\n return this;\n }\n\n /**\n * Add the executable bit (for everyone) to the given path without modifying other bits (`chmod +x`).\n */\n async chmodX(): Promise<Path> {\n const { mode } = await this.stat();\n await this.chmod(\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 static get homedir(): Path {\n return new Path(homedir());\n }\n\n /**\n * Get the current working directory as a path. Always includes a trailing slash.\n * Note that this computes the `cwd` from fresh every time, in case it has changed for the current process.\n */\n static get cwd(): Path {\n return new Path(cwd()).toggleTrailingSlash(true);\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 * {@link Path.xdg.runtime} does not have a default value. Consider\n * {@link Path.xdg.runtimeWithStateFallback} if you need a fallback but do not have a particular fallback in mind.\n */\n runtime: xdgRuntime ? new Path(xdgRuntime) : undefined,\n runtimeWithStateFallback: xdgRuntime\n ? new Path(xdgRuntime)\n : 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\nexport class AsyncDisposablePath extends Path {\n async [Symbol.asyncDispose]() {\n await this.rm_rf();\n }\n}\n\n/**\n * This function is useful to serialize any `Path`s in a structure to pass on to\n * functions that do not know about the `Path` class, e.g.\n *\n * function process(args: (string | Path)[]) {\n * const argsAsStrings = args.map(stringifyIfPath);\n * }\n *\n */\nexport function stringifyIfPath<T>(value: T | Path): T | string {\n if (value instanceof Path) {\n return value.toString();\n }\n return value;\n}\n\nexport function mustNotHaveTrailingSlash(path: Path): void {\n if (path.hasTrailingSlash()) {\n throw new Error(\n \"Path ends with a slash, which cannot be treated as a file.\",\n );\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["ResolutionPrefix"]
7
- }