path-class 0.11.1 → 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.
@@ -539,7 +539,7 @@ var Path = class _Path {
539
539
  async chmodX() {
540
540
  const { mode } = await this.stat();
541
541
  await this.chmod(
542
- mode | constants.S_IRWXU | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
542
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH
543
543
  );
544
544
  return this;
545
545
  }
@@ -608,4 +608,4 @@ export {
608
608
  stringifyIfPath,
609
609
  mustNotHaveTrailingSlash
610
610
  };
611
- //# sourceMappingURL=chunk-55PEPNLJ.js.map
611
+ //# sourceMappingURL=chunk-QM7EHUFF.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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 |\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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",
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
6
  "names": ["ResolutionPrefix"]
7
7
  }
@@ -3,7 +3,7 @@ import {
3
3
  Path,
4
4
  ResolutionPrefix,
5
5
  stringifyIfPath
6
- } from "./chunks/chunk-55PEPNLJ.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-55PEPNLJ.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.1",
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,14 +134,14 @@ test(".toggleTrailingSlash(…)", async () => {
134
134
  expect(new Path("..").toggleTrailingSlash().path).toBe("../");
135
135
  });
136
136
 
137
- test(".blue", async () => {
137
+ test.concurrent(".blue", async () => {
138
138
  expect(Path.fromString("bare").path).toEqual("bare");
139
139
  expect(`Home dir: ${Path.homedir.blue}`).toEqual(
140
140
  "Home dir: \u001b[1m\u001b[34m/mock/home/dir\u001b[39m\u001b[22m",
141
141
  );
142
142
  });
143
143
 
144
- test("normalize", async () => {
144
+ test.concurrent("normalize", async () => {
145
145
  expect(new Path("foo//bar").path).toEqual("foo/bar");
146
146
  expect(new Path("foo////bar").path).toEqual("foo/bar");
147
147
  expect(new Path("foo/bar/").path).toEqual("foo/bar/");
@@ -149,7 +149,7 @@ test("normalize", async () => {
149
149
  expect(new Path("//absolute////bar").path).toEqual("/absolute/bar");
150
150
  });
151
151
 
152
- test(".join(…)", async () => {
152
+ test.concurrent(".join(…)", async () => {
153
153
  expect(new Path("foo").join("bar").path).toEqual("foo/bar");
154
154
  expect(new Path("foo/bar").join("bath", "kitchen/sink").path).toEqual(
155
155
  "foo/bar/bath/kitchen/sink",
@@ -163,7 +163,7 @@ test(".join(…)", async () => {
163
163
  );
164
164
  });
165
165
 
166
- test("asRelative()", async () => {
166
+ test.concurrent("asRelative()", async () => {
167
167
  // From doc comment
168
168
  expect(new Path("bare").asRelative().path).toEqual("./bare");
169
169
  expect(new Path("./relative").asRelative().path).toEqual("./relative");
@@ -181,7 +181,7 @@ test("asRelative()", async () => {
181
181
  expect(new Path("../up/").asRelative().path).toEqual("../up/");
182
182
  });
183
183
 
184
- test("asAbsolute()", async () => {
184
+ test.concurrent("asAbsolute()", async () => {
185
185
  // From doc comment
186
186
  expect(new Path("bare").asAbsolute().path).toEqual("/bare");
187
187
  expect(new Path("./relative").asAbsolute().path).toEqual("/relative");
@@ -193,7 +193,7 @@ test("asAbsolute()", async () => {
193
193
  expect(new Path("../up/").asAbsolute().path).toEqual("/up/");
194
194
  });
195
195
 
196
- test("asBare(…)", async () => {
196
+ test.concurrent("asBare(…)", async () => {
197
197
  const ERROR_1 =
198
198
  'Converting path to a bare path resulted in a `..` traversal prefix. Pass `"strip"` or `"keep"` as the `parentTraversalHandling` option to avoid an error.';
199
199
  const ERROR_2 = "Output does not start with a named component.";
@@ -268,7 +268,7 @@ test("asBare(…)", async () => {
268
268
  ).toThrow(ERROR_2);
269
269
  });
270
270
 
271
- test("traverse", async () => {
271
+ test.concurrent("traverse", async () => {
272
272
  expect(new Path("foo/bar").join("..").path).toEqual("foo");
273
273
  expect(new Path("foo/bar").join(".").path).toEqual("foo/bar");
274
274
  expect(new Path("foo/bar").join("../baz").path).toEqual("foo/baz");
@@ -277,7 +277,7 @@ test("traverse", async () => {
277
277
  expect(new Path("/").join("..").path).toEqual("/");
278
278
  });
279
279
 
280
- test(".extendBasename(…)", async () => {
280
+ test.concurrent(".extendBasename(…)", async () => {
281
281
  expect(new Path("file.mp4").extendBasename(".hevc.qv65.mov").path).toEqual(
282
282
  "file.mp4.hevc.qv65.mov",
283
283
  );
@@ -287,19 +287,19 @@ test(".extendBasename(…)", async () => {
287
287
  );
288
288
  });
289
289
 
290
- test(".parent", async () => {
290
+ test.concurrent(".parent", async () => {
291
291
  expect(new Path("/").parent.path).toEqual("/");
292
292
  expect(new Path("dir").parent.path).toEqual(".");
293
293
  expect(new Path("dir/").parent.path).toEqual(".");
294
294
  });
295
295
 
296
- test(".dirname", async () => {
296
+ test.concurrent(".dirname", async () => {
297
297
  expect(new Path("/").dirname.path).toEqual("/");
298
298
  expect(new Path("dir").dirname.path).toEqual(".");
299
299
  expect(new Path("dir/").dirname.path).toEqual(".");
300
300
  });
301
301
 
302
- test(".basename", async () => {
302
+ test.concurrent(".basename", async () => {
303
303
  expect(new Path("/").basename.path).toEqual("."); // TODO?
304
304
  expect(new Path("dir").basename.path).toEqual("dir");
305
305
  expect(new Path("dir/").basename.path).toEqual("dir");
@@ -308,7 +308,7 @@ test(".basename", async () => {
308
308
  );
309
309
  });
310
310
 
311
- test(".extension", async () => {
311
+ test.concurrent(".extension", async () => {
312
312
  expect(new Path("foo.txt").extension).toEqual(".txt");
313
313
  expect(new Path("foo.").extension).toEqual(".");
314
314
  expect(new Path("foo").extension).toEqual("");
@@ -316,7 +316,7 @@ test(".extension", async () => {
316
316
  expect(() => new Path("/").extension).toThrow();
317
317
  });
318
318
 
319
- test(".extname", async () => {
319
+ test.concurrent(".extname", async () => {
320
320
  expect(new Path("foo.txt").extname).toEqual(".txt");
321
321
  expect(new Path("foo.").extname).toEqual(".");
322
322
  expect(new Path("foo").extname).toEqual("");
@@ -324,7 +324,7 @@ test(".extname", async () => {
324
324
  expect(() => new Path("/").extname).toThrow();
325
325
  });
326
326
 
327
- test(".existsAsFile()", async () => {
327
+ test.concurrent(".existsAsFile()", async () => {
328
328
  const filePath = (await Path.makeTempDir()).join("file.txt");
329
329
  expect(await filePath.exists()).toBe(false);
330
330
  expect(await filePath.exists({ mustBe: "file" })).toBe(false);
@@ -342,7 +342,7 @@ test(".existsAsFile()", async () => {
342
342
  expect(await filePath.existsAsFile()).toBe(true);
343
343
  });
344
344
 
345
- test(".existsAsDir()", async () => {
345
+ test.concurrent(".existsAsDir()", async () => {
346
346
  const filePath = await Path.makeTempDir();
347
347
  expect(await filePath.exists()).toBe(true);
348
348
  expect(() => filePath.exists({ mustBe: "file" })).toThrow(
@@ -357,14 +357,14 @@ test(".existsAsDir()", async () => {
357
357
  expect(await filePath.existsAsDir()).toBe(false);
358
358
  });
359
359
 
360
- test(".mkdir(…) (un-nested)", async () => {
360
+ test.concurrent(".mkdir(…) (un-nested)", async () => {
361
361
  const dir = (await Path.makeTempDir()).join("mkdir-test");
362
362
  expect(await dir.exists()).toBe(false);
363
363
  await dir.mkdir();
364
364
  expect(await dir.exists()).toBe(true);
365
365
  });
366
366
 
367
- test(".mkdir(…) (nested)", async () => {
367
+ test.concurrent(".mkdir(…) (nested)", async () => {
368
368
  const dir = (await Path.makeTempDir()).join("mkdir-test/nested");
369
369
  expect(await dir.exists()).toBe(false);
370
370
  expect(() => dir.mkdir({ recursive: false })).toThrow("no such file");
@@ -372,7 +372,7 @@ test(".mkdir(…) (nested)", async () => {
372
372
  expect(await dir.exists()).toBe(true);
373
373
  });
374
374
 
375
- test(".cp(…)", async () => {
375
+ test.concurrent(".cp(…)", async () => {
376
376
  const parentDir = await Path.makeTempDir();
377
377
  const file1 = parentDir.join("file1.txt");
378
378
  const file2 = parentDir.join("file2.txt");
@@ -386,7 +386,7 @@ test(".cp(…)", async () => {
386
386
  expect(await file2.exists()).toBe(true);
387
387
  });
388
388
 
389
- test(".rename(…)", async () => {
389
+ test.concurrent(".rename(…)", async () => {
390
390
  const parentDir = await Path.makeTempDir();
391
391
  const file1 = parentDir.join("file1.txt");
392
392
  const file2 = parentDir.join("file2.txt");
@@ -400,7 +400,7 @@ test(".rename(…)", async () => {
400
400
  expect(await file2.exists()).toBe(true);
401
401
  });
402
402
 
403
- test(".makeTempDir(…)", async () => {
403
+ test.concurrent(".makeTempDir(…)", async () => {
404
404
  let asyncDisposablePathString: string;
405
405
  {
406
406
  await using tempDir = await Path.makeTempDir();
@@ -421,7 +421,7 @@ test(".makeTempDir(…)", async () => {
421
421
  expect(await new Path(asyncDisposablePathString2).existsAsDir()).toBe(false);
422
422
  });
423
423
 
424
- test(".rm(…) (file)", async () => {
424
+ test.concurrent(".rm(…) (file)", async () => {
425
425
  const file = (await Path.makeTempDir()).join("file.txt");
426
426
  await file.write("");
427
427
  expect(await file.existsAsFile()).toBe(true);
@@ -431,7 +431,7 @@ test(".rm(…) (file)", async () => {
431
431
  expect(async () => file.rm()).toThrowError(/ENOENT/);
432
432
  });
433
433
 
434
- test(".rm(…) (folder)", async () => {
434
+ test.concurrent(".rm(…) (folder)", async () => {
435
435
  const tempDir = await Path.makeTempDir();
436
436
  const file = tempDir.join("file.txt");
437
437
  await file.write("");
@@ -443,7 +443,7 @@ test(".rm(…) (folder)", async () => {
443
443
  expect(async () => tempDir.rm()).toThrowError(/ENOENT/);
444
444
  });
445
445
 
446
- test(".rmDir(…)", async () => {
446
+ test.concurrent(".rmDir(…)", async () => {
447
447
  const tempDir = await Path.makeTempDir();
448
448
  const file = tempDir.join("file.txt");
449
449
  await file.write("");
@@ -455,7 +455,7 @@ test(".rmDir(…)", async () => {
455
455
  expect(async () => tempDir.rmDir()).toThrowError(/ENOENT/);
456
456
  });
457
457
 
458
- test(".rm_rf(…) (file)", async () => {
458
+ test.concurrent(".rm_rf(…) (file)", async () => {
459
459
  const file = (await Path.makeTempDir()).join("file.txt");
460
460
  await file.write("");
461
461
  expect(await file.existsAsFile()).toBe(true);
@@ -466,7 +466,7 @@ test(".rm_rf(…) (file)", async () => {
466
466
  expect(await file.existsAsFile()).toBe(false);
467
467
  });
468
468
 
469
- test(".rm_rf(…) (folder)", async () => {
469
+ test.concurrent(".rm_rf(…) (folder)", async () => {
470
470
  const tempDir = await Path.makeTempDir();
471
471
  await tempDir.join("file.txt").write("");
472
472
  expect(tempDir.path).toContain("/js-temp-");
@@ -477,7 +477,7 @@ test(".rm_rf(…) (folder)", async () => {
477
477
  expect(await tempDir.exists()).toBe(false);
478
478
  });
479
479
 
480
- test(".readText()", async () => {
480
+ test.concurrent(".readText()", async () => {
481
481
  const file = (await Path.makeTempDir()).join("file.txt");
482
482
  await file.write("hi");
483
483
  await file.write("bye");
@@ -486,7 +486,7 @@ test(".readText()", async () => {
486
486
  expect(await readFile(file.path, "utf-8")).toBe("bye");
487
487
  });
488
488
 
489
- test(".readJSON()", async () => {
489
+ test.concurrent(".readJSON()", async () => {
490
490
  const file = (await Path.makeTempDir()).join("file.json");
491
491
  await file.write(JSON.stringify({ foo: "bar" }));
492
492
 
@@ -497,7 +497,7 @@ test(".readJSON()", async () => {
497
497
  >({ foo: "bar" });
498
498
  });
499
499
 
500
- test(".readJSON(…) with fallback", async () => {
500
+ test.concurrent(".readJSON(…) with fallback", async () => {
501
501
  const tempDir = await Path.makeTempDir();
502
502
  const file = tempDir.join("file.json");
503
503
  const json: { foo?: number } = await file.readJSON({ fallback: { foo: 4 } });
@@ -515,7 +515,7 @@ test(".readJSON(…) with fallback", async () => {
515
515
  );
516
516
  });
517
517
 
518
- test(".write(…)", async () => {
518
+ test.concurrent(".write(…)", async () => {
519
519
  const tempDir = await Path.makeTempDir();
520
520
  const file = tempDir.join("file.json");
521
521
  expect(await file.write("foo")).toBe(file);
@@ -531,14 +531,14 @@ test(".write(…)", async () => {
531
531
  ).toEqual("bar");
532
532
  });
533
533
 
534
- test(".writeJSON(…)", async () => {
534
+ test.concurrent(".writeJSON(…)", async () => {
535
535
  const file = (await Path.makeTempDir()).join("file.json");
536
536
  expect(await file.writeJSON({ foo: "bar" })).toBe(file);
537
537
 
538
538
  expect(await file.readJSON()).toEqual<Record<string, string>>({ foo: "bar" });
539
539
  });
540
540
 
541
- test(".appendFile(…)", async () => {
541
+ test.concurrent(".appendFile(…)", async () => {
542
542
  const file = (await Path.makeTempDir()).join("file.txt");
543
543
  await file.appendFile("test\n");
544
544
  expect(await file.readText()).toEqual("test\n");
@@ -546,7 +546,7 @@ test(".appendFile(…)", async () => {
546
546
  expect(await file.readText()).toEqual("test\nmore\n");
547
547
  });
548
548
 
549
- test(".readDir(…)", async () => {
549
+ test.concurrent(".readDir(…)", async () => {
550
550
  const dir = await Path.makeTempDir();
551
551
  await dir.join("file.txt").write("hello");
552
552
  await dir.join("dir/file.json").write("hello");
@@ -560,7 +560,7 @@ test(".readDir(…)", async () => {
560
560
  );
561
561
  });
562
562
 
563
- test(".symlink(…)", async () => {
563
+ test.concurrent(".symlink(…)", async () => {
564
564
  const tempDir = await Path.makeTempDir();
565
565
  const source = tempDir.join("foo.txt");
566
566
  const target = tempDir.join("bar.txt");
@@ -572,7 +572,7 @@ test(".symlink(…)", async () => {
572
572
  expect(await target.readText()).toEqual("hello");
573
573
  });
574
574
 
575
- test(".realpath(…)", async () => {
575
+ test.concurrent(".realpath(…)", async () => {
576
576
  const tempDir = await Path.makeTempDir();
577
577
  const source = tempDir.join("foo.txt");
578
578
  await source.write("hello world!");
@@ -583,7 +583,7 @@ test(".realpath(…)", async () => {
583
583
  );
584
584
  });
585
585
 
586
- test(".stat(…)", async () => {
586
+ test.concurrent(".stat(…)", async () => {
587
587
  const file = (await Path.makeTempDir()).join("foo.txt");
588
588
  await file.write("hello");
589
589
 
@@ -592,7 +592,7 @@ test(".stat(…)", async () => {
592
592
  expect((await file.stat({ bigint: true })).size).toBeTypeOf("bigint");
593
593
  });
594
594
 
595
- test(".lstat(…)", async () => {
595
+ test.concurrent(".lstat(…)", async () => {
596
596
  const tempDir = await Path.makeTempDir();
597
597
  const source = tempDir.join("foo.txt");
598
598
  const target = tempDir.join("bar.txt");
@@ -605,7 +605,7 @@ test(".lstat(…)", async () => {
605
605
  expect(await target.readText()).toEqual("hello");
606
606
  });
607
607
 
608
- test(".chmod(…)", async () => {
608
+ test.concurrent(".chmod(…)", async () => {
609
609
  const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
610
610
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
611
611
  /ENOENT|Premature close/,
@@ -624,7 +624,7 @@ echo hi`);
624
624
  expect(await new PrintableShellCommand(binPath, []).text()).toEqual("hi\n");
625
625
  });
626
626
 
627
- test(".chmodX(…)", async () => {
627
+ test.concurrent(".chmodX(…)", async () => {
628
628
  const binPath = (await Path.makeTempDir()).join("nonexistent.bin");
629
629
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
630
630
  /ENOENT|Premature close/,
@@ -639,22 +639,28 @@ echo hi`);
639
639
  expect(() => new PrintableShellCommand(binPath, []).text()).toThrow(
640
640
  /EACCES|Premature close/,
641
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();
642
646
  await binPath.chmodX();
643
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();
644
650
  });
645
651
 
646
- test(".homedir", async () => {
652
+ test.concurrent(".homedir", async () => {
647
653
  expect(Path.homedir.path).toEqual("/mock/home/dir");
648
654
  });
649
655
 
650
- test(".cwd", async () => {
656
+ test.concurrent(".cwd", async () => {
651
657
  expect(Path.cwd.basename.path).toEqual("path-class");
652
658
  const tempDir = await Path.makeTempDir();
653
659
  chdir(tempDir.path);
654
660
  expect(await realpath(Path.cwd.path)).toEqual(await realpath(tempDir.path));
655
661
  });
656
662
 
657
- test(".xdg", async () => {
663
+ test.concurrent(".xdg", async () => {
658
664
  expect(Path.xdg.cache.path).toEqual("/mock/home/dir/.cache");
659
665
  expect(Path.xdg.config.path).toEqual("/xdg/config");
660
666
  expect(Path.xdg.data.path).toEqual("/mock/home/dir/.local/share");
@@ -668,6 +674,7 @@ test(".xdg", async () => {
668
674
  const spy = spyOn(console, "log");
669
675
 
670
676
  test(".debugPrint(…)", async () => {
677
+ spy.mockReset();
671
678
  Path.homedir.debugPrint("Here is a test log of the mock home directory:");
672
679
  expect(spy.mock.calls).toEqual([
673
680
  ["Here is a test log of the mock home directory:"],
@@ -676,6 +683,7 @@ test(".debugPrint(…)", async () => {
676
683
  });
677
684
 
678
685
  test(".stringifyIfPath(…)", async () => {
686
+ spy.mockReset();
679
687
  expect(stringifyIfPath(Path.homedir)).toBe("/mock/home/dir");
680
688
  expect(stringifyIfPath("/mock/home/dir")).toBe("/mock/home/dir");
681
689
  expect(stringifyIfPath(4)).toBe(4);
package/src/Path.ts CHANGED
@@ -633,11 +633,7 @@ export class Path {
633
633
  async chmodX(): Promise<Path> {
634
634
  const { mode } = await this.stat();
635
635
  await this.chmod(
636
- mode |
637
- constants.S_IRWXU |
638
- constants.S_IXUSR |
639
- constants.S_IXGRP |
640
- constants.S_IXOTH,
636
+ mode | constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH,
641
637
  );
642
638
  return this;
643
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
  }