From a48b8ec72303246e5049d6db7f530a5c3199cf2c Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Tue, 26 Mar 2024 17:03:27 +1100 Subject: [PATCH 1/3] refactor(datetime): rename `_common.ts` to `_date_time_formatter.ts` --- datetime/{_common.ts => _date_time_formatter.ts} | 14 +++++++------- datetime/format.ts | 2 +- datetime/parse.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) rename datetime/{_common.ts => _date_time_formatter.ts} (98%) diff --git a/datetime/_common.ts b/datetime/_date_time_formatter.ts similarity index 98% rename from datetime/_common.ts rename to datetime/_date_time_formatter.ts index 12d011f2c324..39d515ff3c4c 100644 --- a/datetime/_common.ts +++ b/datetime/_date_time_formatter.ts @@ -1,34 +1,34 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. -export type Token = { +type Token = { type: string; value: string | number; index: number; [key: string]: unknown; }; -export interface ReceiverResult { +interface ReceiverResult { [name: string]: string | number | unknown; } -export type CallbackResult = { +type CallbackResult = { type: string; value: string | number; [key: string]: unknown; }; type CallbackFunction = (value: unknown) => CallbackResult; -export type TestResult = { value: unknown; length: number } | undefined; -export type TestFunction = ( +type TestResult = { value: unknown; length: number } | undefined; +type TestFunction = ( string: string, ) => TestResult | undefined; -export interface Rule { +interface Rule { test: TestFunction; fn: CallbackFunction; } -export class Tokenizer { +class Tokenizer { rules: Rule[]; constructor(rules: Rule[] = []) { diff --git a/datetime/format.ts b/datetime/format.ts index f4e8b40d30e4..635d110cd985 100644 --- a/datetime/format.ts +++ b/datetime/format.ts @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. -import { DateTimeFormatter } from "./_common.ts"; +import { DateTimeFormatter } from "./_date_time_formatter.ts"; /** * Takes an input `date` and a `formatString` to format to a `string`. diff --git a/datetime/parse.ts b/datetime/parse.ts index 7487dd2b4760..2b9d4ebb757e 100644 --- a/datetime/parse.ts +++ b/datetime/parse.ts @@ -1,7 +1,7 @@ // Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // This module is browser compatible. -import { DateTimeFormatter } from "./_common.ts"; +import { DateTimeFormatter } from "./_date_time_formatter.ts"; /** * Takes an input `string` and a `formatString` to parse to a `date`. From 5dea68fbb715f3c1d984f785c039b6ffdcc07b83 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Wed, 27 Mar 2024 12:30:40 +1100 Subject: [PATCH 2/3] docs(fs): polish documentation --- fs/copy.ts | 102 ++++++++++++++++++------ fs/empty_dir.ts | 26 +++--- fs/ensure_dir.ts | 24 ++++-- fs/ensure_file.ts | 32 ++++---- fs/ensure_link.ts | 32 ++++---- fs/ensure_symlink.ts | 40 +++++++--- fs/eol.ts | 34 ++++---- fs/exists.ts | 184 +++++++++++++++++++++++++++++++------------ 8 files changed, 329 insertions(+), 145 deletions(-) diff --git a/fs/copy.ts b/fs/copy.ts index 2c266b5659a5..1b612ed883c6 100644 --- a/fs/copy.ts +++ b/fs/copy.ts @@ -14,14 +14,15 @@ const isWindows = Deno.build.os === "windows"; /** Options for {@linkcode copy} and {@linkcode copySync}. */ export interface CopyOptions { /** - * overwrite existing file or directory. + * Whether to overwrite existing file or directory. + * * @default {false} */ overwrite?: boolean; /** - * When `true`, will set last modification and access times to the ones of the - * original source files. - * When `false`, timestamp behavior is OS-dependent. + * When `true`, will set last modification and access times to the ones of + * the original source files. When `false`, timestamp behavior is + * OS-dependent. * * @default {false} */ @@ -249,21 +250,49 @@ function copyDirSync( } /** - * Copy a file or directory. The directory can have contents. Like `cp -r`. + * Asynchronously copy a file or directory. The directory can have contents. + * Like `cp -r`. + * + * If `src` is a directory it will copy everything inside of this directory, + * not the entire directory itself. If `src` is a file, `dest` cannot be a + * directory. + * * Requires the `--allow-read` and `--allow-write` flag. * - * @example + * @param src The source file/directory path as a string or URL. + * @param dest The destination file/directory path as a string or URL. + * @param options Options for copying. + * @returns A promise that resolves once the copy operation completes. + * + * @example Basic usage * ```ts * import { copy } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; - * copy("./foo", "./bar"); // returns a promise + * + * await copy("./foo", "./bar"); + * ``` + * + * This will copy the file or directory at `./foo` to `./bar` without + * overwriting. + * + * @example Overwriting files/directories + * ```ts + * import { copy } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; + * + * await copy("./foo", "./bar", { overwrite: true }); + * ``` + * + * This will copy the file or directory at `./foo` to `./bar` and overwrite + * any existing files or directories. + * + * @example Preserving timestamps + * ```ts + * import { copy } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; + * + * await copy("./foo", "./bar", { preserveTimestamps: true }); * ``` * - * @param src the file/directory path. - * Note that if `src` is a directory it will copy everything inside - * of this directory, not the entire directory itself - * @param dest the destination path. Note that if `src` is a file, `dest` cannot - * be a directory - * @param options + * This will copy the file or directory at `./foo` to `./bar` and set the + * last modification and access times to the ones of the original source files. */ export async function copy( src: string | URL, @@ -295,20 +324,49 @@ export async function copy( } /** - * Copy a file or directory. The directory can have contents. Like `cp -r`. + * Synchronously copy a file or directory. The directory can have contents. + * Like `cp -r`. + * + * If `src` is a directory it will copy everything inside of this directory, + * not the entire directory itself. If `src` is a file, `dest` cannot be a + * directory. + * * Requires the `--allow-read` and `--allow-write` flag. * - * @example + * @param src The source file/directory path as a string or URL. + * @param dest The destination file/directory path as a string or URL. + * @param options Options for copying. + * @returns A void value that returns once the copy operation completes. + * + * @example Basic usage * ```ts * import { copySync } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; - * copySync("./foo", "./bar"); // void + * + * copySync("./foo", "./bar"); * ``` - * @param src the file/directory path. - * Note that if `src` is a directory it will copy everything inside - * of this directory, not the entire directory itself - * @param dest the destination path. Note that if `src` is a file, `dest` cannot - * be a directory - * @param options + * + * This will copy the file or directory at `./foo` to `./bar` without + * overwriting. + * + * @example Overwriting files/directories + * ```ts + * import { copySync } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; + * + * copySync("./foo", "./bar", { overwrite: true }); + * ``` + * + * This will copy the file or directory at `./foo` to `./bar` and overwrite + * any existing files or directories. + * + * @example Preserving timestamps + * ```ts + * import { copySync } from "https://deno.land/std@$STD_VERSION/fs/copy.ts"; + * + * copySync("./foo", "./bar", { preserveTimestamps: true }); + * ``` + * + * This will copy the file or directory at `./foo` to `./bar` and set the + * last modification and access times to the ones of the original source files. */ export function copySync( src: string | URL, diff --git a/fs/empty_dir.ts b/fs/empty_dir.ts index cbf7b31d4dbf..52a3f2dd76bb 100644 --- a/fs/empty_dir.ts +++ b/fs/empty_dir.ts @@ -3,17 +3,20 @@ import { join } from "../path/join.ts"; import { toPathString } from "./_to_path_string.ts"; /** - * Ensures that a directory is empty. - * Deletes directory contents if the directory is not empty. - * If the directory does not exist, it is created. + * Asynchronously ensures that a directory is empty deletes the directory + * contents it is not empty. If the directory does not exist, it is created. * The directory itself is not deleted. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param dir The path of the directory to empty, as a string or URL. + * @returns A void promise that resolves once the directory is empty. + * * @example * ```ts - * import { emptyDir } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { emptyDir } from "https://deno.land/std@$STD_VERSION/fs/empty_dir.ts"; * - * emptyDir("./foo"); // returns a promise + * await emptyDir("./foo"); * ``` */ export async function emptyDir(dir: string | URL) { @@ -37,17 +40,20 @@ export async function emptyDir(dir: string | URL) { } /** - * Ensures that a directory is empty. - * Deletes directory contents if the directory is not empty. - * If the directory does not exist, it is created. + * Synchronously ensures that a directory is empty deletes the directory + * contents it is not empty. If the directory does not exist, it is created. * The directory itself is not deleted. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param dir The path of the directory to empty, as a string or URL. + * @returns A void value that returns once the directory is empty. + * * @example * ```ts - * import { emptyDirSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { emptyDirSync } from "https://deno.land/std@$STD_VERSION/fs/empty_dir.ts"; * - * emptyDirSync("./foo"); // void + * emptyDirSync("./foo"); * ``` */ export function emptyDirSync(dir: string | URL) { diff --git a/fs/ensure_dir.ts b/fs/ensure_dir.ts index 2f786cdcb4c0..121ed9818ab5 100644 --- a/fs/ensure_dir.ts +++ b/fs/ensure_dir.ts @@ -2,15 +2,19 @@ import { getFileInfoType } from "./_get_file_info_type.ts"; /** - * Ensures that the directory exists. - * If the directory structure does not exist, it is created. Like mkdir -p. + * Asynchronously ensures that the directory exists. If the directory structure + * does not exist, it is created. Like `mkdir -p`. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param dir The path of the directory to ensure, as a string or URL. + * @returns A promise that resolves once the directory exists. + * * @example * ```ts - * import { ensureDir } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureDir } from "https://deno.land/std@$STD_VERSION/fs/ensure_dir.ts"; * - * ensureDir("./bar"); // returns a promise + * await ensureDir("./bar"); * ``` */ export async function ensureDir(dir: string | URL) { @@ -51,15 +55,19 @@ export async function ensureDir(dir: string | URL) { } /** - * Ensures that the directory exists. - * If the directory structure does not exist, it is created. Like mkdir -p. + * Synchronously ensures that the directory exists. If the directory structure + * does not exist, it is created. Like `mkdir -p`. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param dir The path of the directory to ensure, as a string or URL. + * @returns A void value that returns once the directory exists. + * * @example * ```ts - * import { ensureDirSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureDir } from "https://deno.land/std@$STD_VERSION/fs/ensure_dir.ts"; * - * ensureDirSync("./ensureDirSync"); // void + * await ensureDir("./bar"); * ``` */ export function ensureDirSync(dir: string | URL) { diff --git a/fs/ensure_file.ts b/fs/ensure_file.ts index 2d51ac1424fa..93aa173fb959 100644 --- a/fs/ensure_file.ts +++ b/fs/ensure_file.ts @@ -5,18 +5,20 @@ import { getFileInfoType } from "./_get_file_info_type.ts"; import { toPathString } from "./_to_path_string.ts"; /** - * Ensures that the file exists. - * If the file that is requested to be created is in directories that do not - * exist. - * these directories are created. If the file already exists, - * it is NOTMODIFIED. + * Asynchronously ensures that the file exists. If the file that is requested to + * be created is in directories that do not exist, these directories are created. + * If the file already exists, it is not modified. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param filePath The path of the file to ensure, as a string or URL. + * @returns A void promise that resolves once the file exists. + * * @example * ```ts - * import { ensureFile } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureFile } from "https://deno.land/std@$STD_VERSION/fs/ensure_file.ts"; * - * ensureFile("./folder/targetFile.dat"); // returns promise + * await ensureFile("./folder/targetFile.dat"); * ``` */ export async function ensureFile(filePath: string | URL): Promise { @@ -43,18 +45,20 @@ export async function ensureFile(filePath: string | URL): Promise { } /** - * Ensures that the file exists. - * If the file that is requested to be created is in directories that do not - * exist, - * these directories are created. If the file already exists, - * it is NOT MODIFIED. + * Synchronously ensures that the file exists. If the file that is requested to + * be created is in directories that do not exist, these directories are created. + * If the file already exists, it is not modified. + * * Requires the `--allow-read` and `--allow-write` flag. * + * @param filePath The path of the file to ensure, as a string or URL. + * @returns A void value that returns once the file exists. + * * @example * ```ts - * import { ensureFileSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureFileSync } from "https://deno.land/std@$STD_VERSION/fs/ensure_file.ts"; * - * ensureFileSync("./folder/targetFile.dat"); // void + * ensureFileSync("./folder/targetFile.dat"); * ``` */ export function ensureFileSync(filePath: string | URL): void { diff --git a/fs/ensure_link.ts b/fs/ensure_link.ts index 410ac7383990..ead976339715 100644 --- a/fs/ensure_link.ts +++ b/fs/ensure_link.ts @@ -4,18 +4,20 @@ import { ensureDir, ensureDirSync } from "./ensure_dir.ts"; import { toPathString } from "./_to_path_string.ts"; /** - * Ensures that the hard link exists. - * If the directory structure does not exist, it is created. + * Asynchronously ensures that the hard link exists. If the directory structure + * does not exist, it is created. + * + * @param src The source file path as a string or URL. Directory hard links are + * not allowed. + * @param dest The destination link path as a string or URL. + * @returns A void promise that resolves once the hard link exists. * * @example * ```ts - * import { ensureSymlink } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureSymlink } from "https://deno.land/std@$STD_VERSION/fs/ensure_link.ts"; * - * ensureSymlink("./folder/targetFile.dat", "./folder/targetFile.link.dat"); // returns promise + * await ensureSymlink("./folder/targetFile.dat", "./folder/targetFile.link.dat"); * ``` - * - * @param src the source file path. Directory hard links are not allowed. - * @param dest the destination link path */ export async function ensureLink(src: string | URL, dest: string | URL) { dest = toPathString(dest); @@ -25,18 +27,20 @@ export async function ensureLink(src: string | URL, dest: string | URL) { } /** - * Ensures that the hard link exists. - * If the directory structure does not exist, it is created. + * Synchronously ensures that the hard link exists. If the directory structure + * does not exist, it is created. + * + * @param src The source file path as a string or URL. Directory hard links are + * not allowed. + * @param dest The destination link path as a string or URL. + * @returns A void value that returns once the hard link exists. * * @example * ```ts - * import { ensureSymlinkSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { ensureLinkSync } from "https://deno.land/std@$STD_VERSION/fs/ensure_link.ts"; * - * ensureSymlinkSync("./folder/targetFile.dat", "./folder/targetFile.link.dat"); // void + * ensureLinkSync("./folder/targetFile.dat", "./folder/targetFile.link.dat"); * ``` - * - * @param src the source file path. Directory hard links are not allowed. - * @param dest the destination link path */ export function ensureLinkSync(src: string | URL, dest: string | URL) { dest = toPathString(dest); diff --git a/fs/ensure_symlink.ts b/fs/ensure_symlink.ts index bc2b0e5adc82..5e525f9c615e 100644 --- a/fs/ensure_symlink.ts +++ b/fs/ensure_symlink.ts @@ -17,13 +17,23 @@ function resolveSymlinkTarget(target: string | URL, linkName: string | URL) { } /** - * Ensures that the link exists, and points to a valid file. - * If the directory structure does not exist, it is created. - * If the link already exists, it is not modified but error is thrown if it is not point to the given target. + * Asynchronously ensures that the link exists, and points to a valid file. If + * the directory structure does not exist, it is created. If the link already + * exists, it is not modified but error is thrown if it is not point to the + * given target. + * * Requires the `--allow-read` and `--allow-write` flag. * - * @param target the source file path - * @param linkName the destination link path + * @param target The source file path as a string or URL. + * @param linkName The destination link path as a string or URL. + * @returns A void promise that resolves once the link exists. + * + * @example + * ```ts + * import { ensureSymlink } from "https://deno.land/std@$STD_VERSION/fs/ensure_symlink.ts"; + * + * await ensureSymlink("./folder/targetFile.dat", "./folder/targetFile.link.dat"); + * ``` */ export async function ensureSymlink( target: string | URL, @@ -65,13 +75,23 @@ export async function ensureSymlink( } /** - * Ensures that the link exists, and points to a valid file. - * If the directory structure does not exist, it is created. - * If the link already exists, it is not modified but error is thrown if it is not point to the given target. + * Synchronously ensures that the link exists, and points to a valid file. If + * the directory structure does not exist, it is created. If the link already + * exists, it is not modified but error is thrown if it is not point to the + * given target. + * * Requires the `--allow-read` and `--allow-write` flag. * - * @param target the source file path - * @param linkName the destination link path + * @param target The source file path as a string or URL. + * @param linkName The destination link path as a string or URL. + * @returns A void value that returns once the link exists. + * + * @example + * ```ts + * import { ensureSymlinkSync } from "https://deno.land/std@$STD_VERSION/fs/ensure_symlink.ts"; + * + * ensureSymlinkSync("./folder/targetFile.dat", "./folder/targetFile.link.dat"); + * ``` */ export function ensureSymlinkSync( target: string | URL, diff --git a/fs/eol.ts b/fs/eol.ts index 8b55e1244c14..bbb61cd12a87 100644 --- a/fs/eol.ts +++ b/fs/eol.ts @@ -13,7 +13,7 @@ export const CRLF = "\r\n" as const; * ```ts * import { EOL } from "https://deno.land/std@$STD_VERSION/fs/eol.ts"; * - * EOL; // Returns "\n" on POSIX platforms or "\r\n" on Windows + * EOL; // "\n" on POSIX platforms and "\r\n" on Windows * ``` */ export const EOL: "\n" | "\r\n" = Deno?.build.os === "windows" ? CRLF : LF; @@ -21,22 +21,20 @@ export const EOL: "\n" | "\r\n" = Deno?.build.os === "windows" ? CRLF : LF; const regDetect = /(?:\r?\n)/g; /** - * Detect the EOL character for string input. - * returns null if no newline. + * Returns the detected EOL character(s) detected in the input string. If no EOL + * character is detected, `null` is returned. + * + * @param content The input string to detect EOL characters. + * @returns The detected EOL character(s) or `null` if no EOL character is detected. * * @example * ```ts - * import { detect, EOL } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; - * - * const CRLFinput = "deno\r\nis not\r\nnode"; - * const Mixedinput = "deno\nis not\r\nnode"; - * const LFinput = "deno\nis not\nnode"; - * const NoNLinput = "deno is not node"; + * import { detect } from "https://deno.land/std@$STD_VERSION/fs/eol.ts"; * - * detect(LFinput); // output EOL.LF - * detect(CRLFinput); // output EOL.CRLF - * detect(Mixedinput); // output EOL.CRLF - * detect(NoNLinput); // output null + * detect("deno\r\nis not\r\nnode"); // "\r\n" + * detect("deno\nis not\r\nnode"); // "\r\n" + * detect("deno\nis not\nnode"); // "\n" + * detect("deno is not node"); // null * ``` */ export function detect(content: string): typeof EOL | null { @@ -50,15 +48,19 @@ export function detect(content: string): typeof EOL | null { } /** - * Format the file to the targeted EOL. + * Normalize the input string to the targeted EOL. + * + * @param content The input string to normalize. + * @param eol The EOL character(s) to normalize the input string to. + * @returns The input string normalized to the targeted EOL. * * @example * ```ts - * import { LF, format } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { LF, format } from "https://deno.land/std@$STD_VERSION/fs/eol.ts"; * * const CRLFinput = "deno\r\nis not\r\nnode"; * - * format(CRLFinput, LF); // output "deno\nis not\nnode" + * format(CRLFinput, LF); // "deno\nis not\nnode" * ``` */ export function format(content: string, eol: typeof EOL): string { diff --git a/fs/exists.ts b/fs/exists.ts index fdbb3730662d..83e0ec916990 100644 --- a/fs/exists.ts +++ b/fs/exists.ts @@ -4,50 +4,43 @@ export interface ExistsOptions { /** * When `true`, will check if the path is readable by the user as well. + * * @default {false} */ isReadable?: boolean; /** - * When `true`, will check if the path is a directory as well. - * Directory symlinks are included. + * When `true`, will check if the path is a directory as well. Directory + * symlinks are included. + * * @default {false} */ isDirectory?: boolean; /** - * When `true`, will check if the path is a file as well. - * File symlinks are included. + * When `true`, will check if the path is a file as well. File symlinks are + * included. + * * @default {false} */ isFile?: boolean; } /** - * Test whether or not the given path exists by checking with the file system. Please consider to check if the path is readable and either a file or a directory by providing additional `options`: + * Asynchronously test whether or not the given path exists by checking with + * the file system. * - * ```ts - * import { exists } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; - * const isReadableDir = await exists("./foo", { - * isReadable: true, - * isDirectory: true - * }); - * const isReadableFile = await exists("./bar", { - * isReadable: true, - * isFile: true - * }); - * ``` + * Note: Do not use this function if performing a check before another operation + * on that file. Doing so creates a race condition. Instead, perform the actual + * file operation directly. This function is not recommended for this use case. + * See the recommended method below. * - * Note: Do not use this function if performing a check before another operation on that file. Doing so creates a race condition. Instead, perform the actual file operation directly. + * @see https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use * - * Bad: - * ```ts - * import { exists } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * @param path The path to the file or directory, as a string or URL. + * @param options Additional options for the check. + * @returns A promise that resolves with `true` if the path exists, `false` + * otherwise. * - * if (await exists("./foo")) { - * await Deno.remove("./foo"); - * } - * ``` - * - * Good: + * @example Recommended method * ```ts * // Notice no use of exists * try { @@ -59,7 +52,57 @@ export interface ExistsOptions { * // Do nothing... * } * ``` - * @see https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use + * + * Notice that `exists()` is not used in the above example. Doing so avoids a + * possible race condition. See the above section for details. + * + * @example Basic usage + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./exists"); // true + * await exists("./does_not_exist"); // false + * ``` + * + * @example Check if a path is readable + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./readable", { isReadable: true }); // true + * await exists("./not_readable", { isReadable: true }); // false + * ``` + * + * @example Check if a path is a directory + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./directory", { isDirectory: true }); // true + * await exists("./file", { isDirectory: true }); // false + * ``` + * + * @example Check if a path is a file + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./file", { isFile: true }); // true + * await exists("./directory", { isFile: true }); // false + * ``` + * + * @example Check if a path is a readable directory + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./readable_directory", { isReadable: true, isDirectory: true }); // true + * await exists("./not_readable_directory", { isReadable: true, isDirectory: true }); // false + * ``` + * + * @example Check if a path is a readable file + * ```ts + * import { exists } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * await exists("./readable_file", { isReadable: true, isFile: true }); // true + * await exists("./not_readable_file", { isReadable: true, isFile: true }); // false + * ``` */ export async function exists( path: string | URL, @@ -113,34 +156,23 @@ export async function exists( } /** - * Test whether or not the given path exists by checking with the file system. Please consider to check if the path is readable and either a file or a directory by providing additional `options`: + * Synchronously test whether or not the given path exists by checking with + * the file system. * - * ```ts - * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; - * const isReadableDir = existsSync("./foo", { - * isReadable: true, - * isDirectory: true - * }); - * const isReadableFile = existsSync("./bar", { - * isReadable: true, - * isFile: true - * }); - * ``` + * Note: Do not use this function if performing a check before another operation + * on that file. Doing so creates a race condition. Instead, perform the actual + * file operation directly. This function is not recommended for this use case. + * See the recommended method below. * - * Note: do not use this function if performing a check before another operation on that file. Doing so creates a race condition. Instead, perform the actual file operation directly. + * @see https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use * - * Bad: - * ```ts - * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * @param path The path to the file or directory, as a string or URL. + * @param options Additional options for the check. + * @returns `true` if the path exists, `false` otherwise. * - * if (existsSync("./foo")) { - * Deno.removeSync("./foo"); - * } - * ``` - * - * Good: + * @example Recommended method * ```ts - * // Notice no use of existsSync + * // Notice no use of exists * try { * Deno.removeSync("./foo", { recursive: true }); * } catch (error) { @@ -150,7 +182,57 @@ export async function exists( * // Do nothing... * } * ``` - * @see https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use + * + * Notice that `existsSync()` is not used in the above example. Doing so avoids + * a possible race condition. See the above section for details. + * + * @example Basic usage + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./exists"); // true + * existsSync("./does_not_exist"); // false + * ``` + * + * @example Check if a path is readable + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./readable", { isReadable: true }); // true + * existsSync("./not_readable", { isReadable: true }); // false + * ``` + * + * @example Check if a path is a directory + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./directory", { isDirectory: true }); // true + * existsSync("./file", { isDirectory: true }); // false + * ``` + * + * @example Check if a path is a file + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./file", { isFile: true }); // true + * existsSync("./directory", { isFile: true }); // false + * ``` + * + * @example Check if a path is a readable directory + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./readable_directory", { isReadable: true, isDirectory: true }); // true + * existsSync("./not_readable_directory", { isReadable: true, isDirectory: true }); // false + * ``` + * + * @example Check if a path is a readable file + * ```ts + * import { existsSync } from "https://deno.land/std@$STD_VERSION/fs/exists.ts"; + * + * existsSync("./readable_file", { isReadable: true, isFile: true }); // true + * existsSync("./not_readable_file", { isReadable: true, isFile: true }); // false + * ``` */ export function existsSync( path: string | URL, From e72d53a9ab9749257734ba035164f7b5c2f3a5a3 Mon Sep 17 00:00:00 2001 From: Asher Gomez Date: Wed, 27 Mar 2024 14:57:22 +1100 Subject: [PATCH 3/3] work --- fs/ensure_link.ts | 4 +-- fs/expand_glob.ts | 85 ++++++++++++++++++++++++++++++++++++++++------- fs/mod.ts | 9 +++++ fs/move.ts | 53 ++++++++++++++++++++++++----- fs/walk.ts | 53 ++++++++++++++++++++++++----- 5 files changed, 173 insertions(+), 31 deletions(-) diff --git a/fs/ensure_link.ts b/fs/ensure_link.ts index ead976339715..7d18aaa01357 100644 --- a/fs/ensure_link.ts +++ b/fs/ensure_link.ts @@ -14,9 +14,9 @@ import { toPathString } from "./_to_path_string.ts"; * * @example * ```ts - * import { ensureSymlink } from "https://deno.land/std@$STD_VERSION/fs/ensure_link.ts"; + * import { ensureLink } from "https://deno.land/std@$STD_VERSION/fs/ensure_link.ts"; * - * await ensureSymlink("./folder/targetFile.dat", "./folder/targetFile.link.dat"); + * await ensureLink("./folder/targetFile.dat", "./folder/targetFile.link.dat"); * ``` */ export async function ensureLink(src: string | URL, dest: string | URL) { diff --git a/fs/expand_glob.ts b/fs/expand_glob.ts index 024ebb8eb42f..bad1110ddc48 100644 --- a/fs/expand_glob.ts +++ b/fs/expand_glob.ts @@ -14,7 +14,7 @@ import { type WalkEntry, } from "./_create_walk_entry.ts"; -export type { GlobOptions }; +export type { GlobOptions, WalkEntry }; const isWindows = Deno.build.os === "windows"; @@ -80,18 +80,47 @@ function comparePath(a: WalkEntry, b: WalkEntry): number { } /** - * Expand the glob string from the specified `root` directory and yield each - * result as a `WalkEntry` object. + * Returns an async iterator that yields each file path matching the given glob + * pattern. The file paths are relative to the provided `root` directory. + * If `root` is not provided, the current working directory is used. + * The `root` directory is not included in the yielded file paths. * - * See [`globToRegExp()`](../path/glob.ts#globToRegExp) for details on supported - * syntax. + * Requires the `--allow-read` flag. + * + * @param glob The glob pattern to expand. + * @param options Additional options for the expansion. + * @returns An async iterator that yields each walk entry matching the glob + * pattern. + * + * @example Basic usage + * + * File structure: + * ``` + * folder + * ├── script.ts + * └── foo.ts + * ``` * - * @example * ```ts + * // script.ts * import { expandGlob } from "https://deno.land/std@$STD_VERSION/fs/expand_glob.ts"; - * for await (const file of expandGlob("**\/*.ts")) { - * console.log(file); + * + * const entries = []; + * for await (const entry of expandGlob("*.ts")) { + * entries.push(entry); * } + * + * entries[0]!.path; // "/Users/user/folder/script.ts" + * entries[0]!.name; // "script.ts" + * entries[0]!.isFile; // false + * entries[0]!.isDirectory; // true + * entries[0]!.isSymlink; // false + * + * entries[1]!.path; // "/Users/user/folder/foo.ts" + * entries[1]!.name; // "foo.ts" + * entries[1]!.isFile; // true + * entries[1]!.isDirectory; // false + * entries[1]!.isSymlink; // false * ``` */ export async function* expandGlob( @@ -210,14 +239,46 @@ export async function* expandGlob( } /** - * Synchronous version of `expandGlob()`. + * Returns an iterator that yields each file path matching the given glob + * pattern. The file paths are relative to the provided `root` directory. + * If `root` is not provided, the current working directory is used. + * The `root` directory is not included in the yielded file paths. + * + * Requires the `--allow-read` flag. + * + * @param glob The glob pattern to expand. + * @param options Additional options for the expansion. + * @returns An iterator that yields each walk entry matching the glob pattern. + * + * @example Basic usage + * + * File structure: + * ``` + * folder + * ├── script.ts + * └── foo.ts + * ``` * - * @example * ```ts + * // script.ts * import { expandGlobSync } from "https://deno.land/std@$STD_VERSION/fs/expand_glob.ts"; - * for (const file of expandGlobSync("**\/*.ts")) { - * console.log(file); + * + * const entries = []; + * for (const entry of expandGlobSync("*.ts")) { + * entries.push(entry); * } + * + * entries[0]!.path; // "/Users/user/folder/script.ts" + * entries[0]!.name; // "script.ts" + * entries[0]!.isFile; // false + * entries[0]!.isDirectory; // true + * entries[0]!.isSymlink; // false + * + * entries[1]!.path; // "/Users/user/folder/foo.ts" + * entries[1]!.name; // "foo.ts" + * entries[1]!.isFile; // true + * entries[1]!.isDirectory; // false + * entries[1]!.isSymlink; // false * ``` */ export function* expandGlobSync( diff --git a/fs/mod.ts b/fs/mod.ts index 55c9f07b5c4c..dc544442ddc2 100644 --- a/fs/mod.ts +++ b/fs/mod.ts @@ -3,6 +3,15 @@ /** * Helpers for working with the filesystem. * + * ```ts + * import { ensureFile, copy, ensureDir, move } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * + * await ensureFile("example.txt"); + * await copy("example.txt", "example_copy.txt"); + * await ensureDir("subdir"); + * await move("example_copy.txt", "subdir/example_copy.txt"); + * ``` + * * @module */ diff --git a/fs/move.ts b/fs/move.ts index 07ca9094d4f6..d3240e5a226c 100644 --- a/fs/move.ts +++ b/fs/move.ts @@ -14,6 +14,7 @@ export class SubdirectoryMoveError extends Error { super( `Cannot move '${src}' to a subdirectory of itself, '${dest}'.`, ); + this.name = this.constructor.name; } } @@ -28,14 +29,32 @@ export interface MoveOptions { } /** - * Moves a file or directory. + * Asynchronously moves a file or directory. * - * @example + * @param src The source file or directory as a string or URL. + * @param dest The destination file or directory as a string or URL. + * @param options Options for the move operation. + * @returns A void promise that resolves once the operation completes. + * + * @example Basic usage * ```ts - * import { move } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { move } from "https://deno.land/std@$STD_VERSION/fs/move.ts"; * - * move("./foo", "./bar"); // returns a promise + * await move("./foo", "./bar"); * ``` + * + * This will move the file or directory at `./foo` to `./bar` without + * overwriting. + * + * @example Overwriting + * ```ts + * import { move } from "https://deno.land/std@$STD_VERSION/fs/move.ts"; + * + * await move("./foo", "./bar", { overwrite: true }); + * ``` + * + * This will move the file or directory at `./foo` to `./bar`, overwriting + * `./bar` if it already exists. */ export async function move( src: string | URL, @@ -73,14 +92,32 @@ export async function move( } /** - * Moves a file or directory synchronously. + * Synchronously moves a file or directory. * - * @example + * @param src The source file or directory as a string or URL. + * @param dest The destination file or directory as a string or URL. + * @param options Options for the move operation. + * @returns A void value that returns once the operation completes. + * + * @example Basic usage * ```ts - * import { moveSync } from "https://deno.land/std@$STD_VERSION/fs/mod.ts"; + * import { moveSync } from "https://deno.land/std@$STD_VERSION/fs/move.ts"; * - * moveSync("./foo", "./bar"); // void + * moveSync("./foo", "./bar"); * ``` + * + * This will move the file or directory at `./foo` to `./bar` without + * overwriting. + * + * @example Overwriting + * ```ts + * import { moveSync } from "https://deno.land/std@$STD_VERSION/fs/move.ts"; + * + * moveSync("./foo", "./bar", { overwrite: true }); + * ``` + * + * This will move the file or directory at `./foo` to `./bar`, overwriting + * `./bar` if it already exists. */ export function moveSync( src: string | URL, diff --git a/fs/walk.ts b/fs/walk.ts index 80c6e3a069a1..4214d252ae55 100644 --- a/fs/walk.ts +++ b/fs/walk.ts @@ -54,51 +54,63 @@ function wrapErrorWithPath(err: unknown, root: string) { export interface WalkOptions { /** * The maximum depth of the file tree to be walked recursively. + * * @default {Infinity} */ maxDepth?: number; /** * Indicates whether file entries should be included or not. + * * @default {true} */ includeFiles?: boolean; /** * Indicates whether directory entries should be included or not. + * * @default {true} */ includeDirs?: boolean; /** * Indicates whether symlink entries should be included or not. * This option is meaningful only if `followSymlinks` is set to `false`. + * * @default {true} */ includeSymlinks?: boolean; /** * Indicates whether symlinks should be resolved or not. + * * @default {false} */ followSymlinks?: boolean; /** * Indicates whether the followed symlink's path should be canonicalized. * This option works only if `followSymlinks` is not `false`. + * * @default {true} */ canonicalize?: boolean; /** * List of file extensions used to filter entries. - * If specified, entries without the file extension specified by this option are excluded. + * If specified, entries without the file extension specified by this option + * are excluded. + * * @default {undefined} */ exts?: string[]; /** * List of regular expression patterns used to filter entries. - * If specified, entries that do not match the patterns specified by this option are excluded. + * If specified, entries that do not match the patterns specified by this + * option are excluded. + * * @default {undefined} */ match?: RegExp[]; /** * List of regular expression patterns used to filter entries. - * If specified, entries matching the patterns specified by this option are excluded. + * If specified, entries matching the patterns specified by this option are + * excluded. + * * @default {undefined} */ skip?: RegExp[]; @@ -106,18 +118,41 @@ export interface WalkOptions { export type { WalkEntry }; /** - * Walks the file tree rooted at root, yielding each file or directory in the - * tree filtered according to the given options. + * Recursively walks through a directory and yields information about each file + * and directory encountered. + * + * @param root The root directory to start the walk from, as a string or URL. + * @param options The options for the walk. + * @returns An async iterable iterator that yields `WalkEntry` objects. + * + * @example Basic usage + * + * File structure: + * ``` + * folder + * ├── script.ts + * └── foo.ts + * ``` * - * @example * ```ts * import { walk } from "https://deno.land/std@$STD_VERSION/fs/walk.ts"; - * import { assert } from "https://deno.land/std@$STD_VERSION/assert/assert.ts"; * + * const entries = []; * for await (const entry of walk(".")) { - * console.log(entry.path); - * assert(entry.isFile); + * entries.push(entry); * } + * + * entries[0]!.path; // "folder" + * entries[0]!.name; // "folder" + * entries[0]!.isFile; // false + * entries[0]!.isDirectory; // true + * entries[0]!.isSymlink; // false + * + * entries[1]!.path; // "folder/script.ts" + * entries[1]!.name; // "script.ts" + * entries[1]!.isFile; // true + * entries[1]!.isDirectory; // false + * entries[1]!.isSymlink; // false * ``` */ export async function* walk(