UNPKG

@rzl-zone/utils-js

Version:

A modern, lightweight set of JavaScript utility functions with TypeScript support for everyday development, crafted to enhance code readability and maintainability.

241 lines (239 loc) 11 kB
/*! * ==================================================== * Rzl Utils-JS. * ---------------------------------------------------- * Version: 3.11.0. * Author: Rizalvin Dwiky. * Repository: https://github.com/rzl-zone/utils-js. * ==================================================== */ type ExtractFileNameOptions = { /** ---------------------------------------------------------- * * ***Indicates whether the input should be treated as a potential domain string.*** * ---------------------------------------------------------- * * - Behavior when `true`: * - The `domainName` option is required and must be a string and non-empty string. * If `domainName` is `undefined`, `null`, or an empty string, a `TypeError` will be thrown. * - The `domainName` is used to determine if the input is a domain-only string. * - Returns `null` if the input exactly matches `domainName` or any of its subdomains **and** has no additional path or filename. * - If the input does not match `domainName` or its subdomains, it will be processed as a regular file-like name. * - Supports **Unicode/IDN domains** (e.g., `tést-ドメイン.com`) and **ASCII filenames**, mixed safely. * * @default false */ domainAware?: boolean; /** ---------------------------------------------------------- * * ***The base domain name used for comparison (e.g., `"example.com"`).*** * ---------------------------------------------------------- * * - Required when `domainAware` is `true`. * - Helps differentiate between a domain-only input (ignored) and a standalone file-like string (processed normally). * - Must be a string and non-empty string. Invalid values (`undefined`, `null`, or empty string) will trigger a `TypeError`. * - Works with both **ASCII domains** and **Unicode/IDN domains**. * - Example: * ```ts * * // ASCII domain + ASCII filename * extractFileName("resume.com", { * domainAware: true, * domainName: "example.com" * }); * // ➔ "resume" * extractFileName("example.com", { * domainAware: true, * domainName: "example.com" * }); * // ➔ null (because input is treated as domain-name) * * // Unicode domain + ASCII filename * extractFileName("tést-ドメイン.com/file.txt", { * domainAware: true, * domainName: "ドメイン.com" * }); * // ➔ "file" * * // Unicode domain + Unicode filename * extractFileName("tést-ドメイン.com/ファイル名.pdf", { * domainAware: true, * domainName: "ドメイン.com" * }); * // ➔ "ファイル名" * * // Invalid domainName, will throw TypeError * extractFileName("resume.com", { * domainAware: true, * domainName: "" * }); * // ➔ TypeError * ``` * * @default undefined */ domainName?: string; }; /** ---------------------------------------------------------- * * ***Utility: `extractFileName`.*** * ---------------------------------------------------------- * * **Extracts the **clean base filename** from nearly any input string, including URLs, local file paths, * UNC paths, and plain filenames.** * * - It automatically safely handles extracts the **base file name** (without extension) from: * - File system paths (Windows, Unix, UNC) * - Protocols like http, https, ftp, file, mailto, or custom schemes * - Percent-encoded, Unicode, and emoji characters * - Dotfiles, reserved OS names, multi-part extensions * - Data URIs * - Optional domain-aware mode to ignore domain-only inputs * - Plain filenames * * - Full support for: * - Unicode, emoji, percent-encoding * - Dotfiles (e.g., `.env`, `.gitignore`) * - Reserved/OS-protected filenames: * `CON`, `PRN`, `AUX`, `NUL`, `COM1`–`COM9`, `LPT1`–`LPT9` * - Known multi-part extensions: * `.tar.gz`, `.tar.bz2`, `.tar.xz`, `.tar.lz`, `.tar.zst`, `.min.js`, `.js.map`, `.log.gz`, `.sql.gz`, * `.backup.tar`, etc. * - Data URIs (`data:[mime];base64,...` ➔ payload string) * - Domain-aware mode (optional) * * ---------------------------------------------------------- * - **Behavior / Features** * - Strips **known extensions**, including multi-part and common double/triple extensions. * - Leaves unknown/custom extensions intact. * - Preserves **dotfiles** as-is (leading dot preserved). * - Returns `null` if: * - input is `null`, `undefined`, or not a string * - input is empty, whitespace-only, or only slashes * - input represents a folder path (trailing slash/backslash, drive/folder only) * - input is a **domain-only string** in domain-aware mode * - Normalizes Windows-style backslashes (`\`) internally as `/`. * - Supports UNC paths, mixed slashes, and Windows drive letters safely. * - Handles URLs: * - Ignores query strings (`?v=1.2.3`) and hash fragments (`#section`) * - Decodes percent-encoded filenames (`my%20file.txt` ➔ `my file.txt`) * - Supports protocol-relative URLs (`//cdn.example.com/file.jpg`) * - Supports uncommon/custom protocols (`ftp://`, `file://`, `mailto:`, etc.) * - Handles **multiple dots**, **trailing dots**, **triple or more extensions** * - Supports filenames on mixed Unicode/ASCII domains: * - Domain names can include Unicode characters (IDN / punycode) * - Filenames may contain ASCII, Unicode, and emoji characters * - Works correctly when domain is Unicode and filename is ASCII, or vice versa * - Supports extremely long filenames safely (up to OS limits) * - Domain-aware mode (`domainAware: true` + `domainName`): * - Parameter `domainName` must be a string and non-empty string; otherwise a TypeError is thrown. * - Returns `null` if input equals `domainName` or any subdomain with no file path * - Extracts filename normally if path/file exists on domain or other domain * - Safe in Node.js and browsers * * ---------------------------------------------------------- * @param {string | null | undefined} input * URL, file path, or plain filename to extract from. * * @param {ExtractFileNameOptions} [options] * Optional configuration: * - `domainAware?: boolean` – treat input as a domain string. Requires `domainName` to be a string and non-empty string; otherwise, a TypeError is thrown. * - `domainName?: string` – base domain for comparison eg (`example.com`), required when `domainAware` is true. * * @returns {string | null} * - Base filename without known extensions * - Original filename if extension unknown * - `null` for invalid inputs, folder paths, or domain-only strings * * ---------------------------------------------------------- * @example * ```ts * // Basic files * extractFileName("document.pdf"); // ➔ "document" * extractFileName("/files/archive.tar.gz"); // ➔ "archive" * extractFileName("C:\\path\\file.txt"); // ➔ "file" * extractFileName(".env"); // ➔ ".env" * extractFileName("folder/"); // ➔ null * * // Not a file * extractFileName("not-file"); // ➔ null * extractFileName("not-file/"); // ➔ null * extractFileName("/not-file/"); // ➔ null * extractFileName("/not-file"); // ➔ null * * // URLs with queries, hashes, protocols * extractFileName("https://example.com/file.txt?ver=1"); // ➔ "file" * extractFileName("https://example.com/archive.tar.gz#part"); // ➔ "archive" * extractFileName("//cdn.example.com/image.png"); // ➔ "image" * * * // Special protocol handling * extractFileName("tel:+6212345678"); // ➔ "+6212345678" * extractFileName("sms:+6212345678"); // ➔ "+6212345678" * extractFileName("mailto:user@domain.com"); // ➔ "user@domain" * extractFileName("data:text/plain;base64,SGVsbG8="); // ➔ "SGVsbG8=" * extractFileName("mailto:resume.com"); // ➔ "resume" * extractFileName("ftp://example.com/image.jpeg"); // ➔ "image" * extractFileName("ftp://files.example.com/app.min.js"); // ➔ "app.min" * extractFileName("file:///C:/path/to/document.pdf"); // ➔ "document" * extractFileName("custom-scheme://example.com/video.mp4"); // ➔ "video" * * // Unicode & emoji * extractFileName("emoji-😊.png"); // ➔ "emoji-😊" * extractFileName("🔥project.tar.gz"); // ➔ "🔥project" * * // Dotfiles * extractFileName(".gitignore"); // ➔ ".gitignore" * extractFileName("/path/.bashrc"); // ➔ ".bashrc" * * // Mixed Unicode domain and ASCII filename * extractFileName("https://tést-ドメイン.com/file.txt"); // ➔ "file" * extractFileName("https://example.com/ファイル名.pdf"); // ➔ "ファイル名" * extractFileName("https://ドメイン例.com/emoji-🔥.png"); // ➔ "emoji-🔥" * * // Reserved filenames * extractFileName("CON"); // ➔ "CON" * extractFileName("NUL.txt"); // ➔ "NUL" * * // Domain-aware mode * extractFileName("example.com", { * domainAware: true, * domainName: "example.com" * }); * // ➔ null * extractFileName("cdn.example.com", { * domainAware: true, * domainName: "example.com" * }); * // ➔ null * extractFileName("resume.com", { * domainAware: true, * domainName: "example.com" * }); * // ➔ "resume" * extractFileName("https://example.com/file.txt", { * domainAware: true, * domainName: "example.com" * }); * // ➔ "file" * * // Windows & UNC paths * extractFileName("C:\\Users\\rzl\\Documents\\file.txt"); // ➔ "file" * extractFileName("\\\\SERVER\\share\\logs\\output.log"); // ➔ "output" * extractFileName("C:/Users\\rzl/mix\\test.pdf"); // ➔ "test" * * // Edge / extreme cases * extractFileName("https://example.com/my%20file%20name.txt"); // ➔ "my file name" * extractFileName("app.min.js.map"); // ➔ "app.min" * extractFileName("backup.tar.bak"); // ➔ "backup.tar.bak" (unknown double extension) * extractFileName("filename."); // ➔ "filename." * extractFileName("a".repeat(255) + ".txt"); // ➔ "a".repeat(255) * ``` * * ---------------------------------------------------------- * @note * - Robust: never throws, handles unusual inputs safely. * - Suitable for display, logging, or safe storage. * - Normalizes slashes consistently. * - Covers nearly all real-world filename, URL, path, data URI, and domain scenarios. * - Handles Windows UNC paths, mixed slashes, percent-encoded, Unicode/emoji filenames. * - Known multi-part extensions list can be extended without breaking functionality. */ declare const extractFileName: (input?: string | null, options?: ExtractFileNameOptions) => string | null; export { type ExtractFileNameOptions, extractFileName };