UNPKG

@ayonli/jsext

Version:

A JavaScript extension package for building strong and modern applications.

241 lines (240 loc) β€’ 7.72 kB
import { ByteArray } from "../bytes.ts"; import { ControlKeys, ControlSequences, FunctionKeys, NavigationKeys } from "./constants.ts"; export { ControlKeys, ControlSequences, FunctionKeys, NavigationKeys, }; /** * The command-line arguments passed to the program. * * This variable is the same as `Deno.args` in Deno and `process.argv.slice(2)` * in Node.js or Bun. * * @example * ```ts * // main.ts * // launch with `deno run main.ts --name=Bob --age=30` * // or `node main.js --name=Bob --age=30` * // or `bun run main.ts --name=Bob --age=30` * import { args } from "@ayonli/jsext/cli"; * * console.log(args); * // [ * // "--name=Bob", * // "--age=30" * // ] * ``` */ export declare const args: string[]; /** * Whether the standard IO is a text terminal. */ export declare const isTTY: boolean; /** * Returns the width of a single character. * * @example * ```ts * import { charWidth } from "@ayonli/jsext/cli"; * * console.log(charWidth("a")); // 1 * console.log(charWidth("δ½ ")); // 2 * console.log(charWidth("πŸ‘‹")); // 2 * console.log(charWidth("β™₯")); // 1 * ``` */ export declare function charWidth(char: string): 1 | 2; /** * Returns the width of a string. * * @example * ```ts * import { stringWidth } from "@ayonli/jsext/cli"; * * console.log(stringWidth("Hello, World!")); // 13 * console.log(stringWidth("δ½ ε₯½οΌŒδΈ–η•ŒοΌ")); // 12 * console.log(stringWidth("πŸ‘‹πŸŒπŸš€β™₯️♣")); // 8 * ``` */ export declare function stringWidth(str: string): number; /** * Requests the standard input to be used only by the given task until it is * completed. * * This function sets the `stdin` in raw mode, and excludes other parts of the * program from reading from it at the same time . This is important so that our * program won't be affected by other tasks, especially in a REPL environment. * * @example * ```ts * // A simple program that reads a line of text from user input. * import process from "node:process"; * import bytes, { equals } from "@ayonli/jsext/bytes"; * import { chars } from "@ayonli/jsext/string"; * import { * ControlKeys, * ControlSequences, * lockStdin, * readStdin, * writeStdout, * isTypingInput, * moveLeftBy, * } from "@ayonli/jsext/cli"; * * const input = await lockStdin(async () => { * await writeStdout(bytes("Type something: ")); * * const buf: string[] = [] * * while (true) { * const input = await readStdin(); * * if (equals(input, ControlKeys.CTRL_C) || equals(input, ControlKeys.ESC)) { * console.error("\nUser cancelled"); * process.exit(1); * } else if (equals(input, ControlKeys.CR) || equals(input, ControlKeys.LF)) { * await writeStdout(ControlKeys.LF); * break; * } else if (equals(input, ControlKeys.BS) || equals(input, ControlKeys.DEL)) { * if (buf.length > 0) { * const char = buf.pop()!; * await moveLeftBy(char); * await writeStdout(ControlSequences.CLR_RIGHT); * } * } else if (isTypingInput(input)) { * buf.push(...chars(String(input))); * await writeStdout(input); * } * } * * return buf.join("") * }); * * console.log(`You typed: ${input}`); * ``` */ export declare function lockStdin<T>(task: () => Promise<T>): Promise<T | null>; /** * Reads a chunk of data from the standard input. This could be a single key * stroke, or a multi-byte sequence for input from an IME. * * NOTE: This function should be used within the task function of {@link lockStdin}. */ export declare function readStdin(): Promise<ByteArray>; /** * Writes a chunk of data to the standard output. */ export declare function writeStdout(data: ByteArray): Promise<void>; /** * Writes a chunk of data to the standard output synchronously. * * NOTE: Despite the function name, the synchronous behavior is only guaranteed * in Deno, in Node.js, it may still be asynchronous. * * Since the behavior is not guaranteed, it is recommended to use the asynchronous * `writeStdout` function instead. This synchronous function is only provided for * special cases where the asynchronous behavior is not acceptable. */ export declare function writeStdoutSync(data: ByteArray): void; /** * Moves the cursor to the left base on the width of the given string. */ export declare function moveLeftBy(str: string): Promise<void>; /** * Moves the cursor to the right base on the width of the given string. */ export declare function moveRightBy(str: string): Promise<void>; /** * Returns `true` if the given data is a typing input. That is, it is not a * control key, navigation key, or function key. */ export declare function isTypingInput(data: ByteArray): boolean; /** * Returns the current size of the application window. * * In the terminal, this is the size of the terminal window, where `width` and * `height` are the corresponding columns and rows. * * In the browser, this is the size of the viewport, where `width` and `height` * are measured in pixels. */ export declare function getWindowSize(): { width: number; height: number; }; /** Checks if the program is running in Windows Subsystem for Linux. */ export declare function isWSL(): boolean; /** * Options for parsing CLI arguments, used by the {@link parseArgs} function. */ export interface ParseOptions { /** * A map of alias characters to their full names. Once set, we can use the * alias characters in the arguments, and they will be converted to their * full names in the result object after parsing. */ alias?: { [char: string]: string; }; /** * Argument names that should be treated as lists. When an argument is in * this list, the result object will store its values in an array. */ lists?: string[]; /** * By default, the {@link parseArgs} function will automatically convert the * argument value to a number or boolean if it looks like one. If we don't * want this behavior for some arguments, we can set this option to `true`, * or an array of argument names that should not be coerced. */ noCoercion?: boolean | string[]; } /** * Parses the given CLI arguments into an object. * * @example * ```ts * import { parseArgs } from "@ayonli/jsext/cli"; * * const args = parseArgs([ * "Bob", * "--age", "30", * "--married", * "--wife=Alice", * "--children", "Mia", * "--children", "Ava", * "-p" * ], { * alias: { "p": "has-parents" }, * lists: ["children"], * }); * * console.log(args); * // { * // "0": "Bob", * // age: 30, * // married: true, * // wife: "Alice", * // children: ["Mia", "Ava"], * // "has-parents": true * // } * ``` */ export declare function parseArgs(args: string[], options?: ParseOptions): { [key: string]: string | number | boolean | (string | number | boolean)[]; [x: number]: string | number | boolean; "--"?: string[]; }; /** * Quotes a string to be used as a single argument to a shell command. * * @example * ```ts * import { quote } from "@ayonli/jsext/cli"; * * console.log(quote("Hello, World!")); // "Hello, World!" * console.log(quote("Hello, 'World'!")); // "Hello, 'World'!" * console.log(quote("Hello, \"World\"!")); // "Hello, \"World\"!" * console.log(quote("Hello, $World!")); // "Hello, \$World!" * console.log(quote("Hello, `World`!")); // "Hello, \`World\`!" * console.log(quote("Hello, \\World!")); // "Hello, \\World!" * ``` */ export declare function quote(arg: string): string;