/*! * ======================================================================== * @rzl-zone/utils-js * ------------------------------------------------------------------------ * Version: `3.15.0` * Author: `Rizalvin Dwiky ` * Repository: `https://github.com/rzl-zone/rzl-zone/tree/main/packages/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 * 1. #### Basic files: * ```ts * extractFileName("document.pdf"); * // ➔ "document" * extractFileName("/files/archive.tar.gz"); * // ➔ "archive" * extractFileName("C:\\path\\file.txt"); * // ➔ "file" * extractFileName(".env"); * // ➔ ".env" * extractFileName("folder/"); * // ➔ null * ``` * --- * 2. #### Not a file: * ```ts * extractFileName("not-file"); * // ➔ null * extractFileName("not-file/"); * // ➔ null * extractFileName("/not-file/"); * // ➔ null * extractFileName("/not-file"); * // ➔ null * ``` * --- * 3. #### URLs with `queries`, `hashes`, `protocols`: * ```ts * 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" * ``` * --- * 4. #### Special protocol handling: * ```ts * 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" * ``` * --- * 5. #### Unicode & emoji: * ```ts * extractFileName("emoji-😊.png"); * // ➔ "emoji-😊" * extractFileName("🔥project.tar.gz"); * // ➔ "🔥project" * ``` * 6. #### Dotfiles: * ```ts * extractFileName(".gitignore"); * // ➔ ".gitignore" * extractFileName("/path/.bashrc"); * // ➔ ".bashrc" * ``` * --- * 7. #### Mixed Unicode domain and ASCII filename: * ```ts * extractFileName("https://tést-ドメイン.com/file.txt"); * // ➔ "file" * extractFileName("https://example.com/ファイル名.pdf"); * // ➔ "ファイル名" * extractFileName("https://ドメイン例.com/emoji-🔥.png"); * // ➔ "emoji-🔥" * ``` * 8. #### Reserved filenames: * ```ts * extractFileName("CON"); * // ➔ "CON" * extractFileName("NUL.txt"); * // ➔ "NUL" * ``` * --- * 9. #### Domain-aware mode: * ```ts * 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" * ``` * --- * 10. #### Windows & UNC paths: * ```ts * extractFileName("C:\\Users\\rzl\\Documents\\file.txt"); * // ➔ "file" * extractFileName("\\\\SERVER\\share\\logs\\output.log"); * // ➔ "output" * extractFileName("C:/Users\\rzl/mix\\test.pdf"); * // ➔ "test" * ``` * --- * 11. #### Edge / extreme cases: * ```ts * 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 { ExtractFileNameOptions, extractFileName };