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.

677 lines (673 loc) 10.8 kB
/*! * ==================================================== * Rzl Utils-JS. * ---------------------------------------------------- * Version: 3.11.0. * Author: Rizalvin Dwiky. * Repository: https://github.com/rzl-zone/utils-js. * ==================================================== */ import { punycodeUtilsJS } from './chunk-6YGBRENU.js'; import { isNonEmptyString, assertIsPlainObject, assertIsBoolean } from './chunk-MSUW5VHZ.js'; var EXTENSIONS_FILE = /* @__PURE__ */ new Set([ // 📄 Text & Document "txt", "md", "rtf", "tex", "doc", "docx", "odt", "ott", "pdf", "djvu", "epub", "fb2", "lit", "lrf", "xls", "xlsx", "ods", "csv", "tsv", "ppt", "pptx", "pps", "bib", "cba", "cbt", "cbz", "cbr", "opds", "fodt", "pages", "rtfd", "sxc", "sxw", "wpd", "xps", "dotx", "dotm", "xltx", "xltm", "sldx", "sldm", "fods", "mdx", "markdown", "texi", "textile", // 🖼️ Image "jpg", "jpeg", "png", "gif", "bmp", "tif", "tiff", "webp", "svg", "ico", "heif", "heic", "raw", "cr2", "nef", "orf", "sr2", "dng", "dds", "psd", "exr", "xcf", "ai", "eps", "cdr", "indd", "pcx", "pgm", "ppm", "pbm", "pnm", "jfif", "ras", "tga", "j2k", "jp2", "emf", "wmf", "hdp", "mdi", "hevc", // 🎵 Audio "mp3", "wav", "ogg", "flac", "aac", "m4a", "wma", "alac", "aiff", "aif", "amr", "mid", "midi", "opus", "au", "caf", "ape", "mka", "spx", "ra", "ram", "mpc", "wv", "aifc", "mod", "it", "s3m", "xm", "kar", "m4b", "voc", "snd", "a52", "ac3", "dts", // 🎥 Video "mp4", "mkv", "avi", "mov", "wmv", "webm", "mpeg", "mpg", "3gp", "3g2", "m4v", "ts", "mts", "asf", "rm", "rmvb", "vob", "f4v", "ogv", "m2ts", "dav", "mxf", "mjpeg", "flv", "divx", "f4a", "f4p", "m2v", "ogm", "vp8", "vp9", "xvid", "yuv", "mng", "dv", "m1v", "roq", "m2t", "av1", "hevc", "m3u", "m3u8", // 🗃️ Archive & Compression "zip", "rar", "7z", "tar", "gz", "bz", "bz2", "xz", "tgz", "tbz2", "txz", "lz", "lzma", "z", "cab", "arj", "ace", "rpm", "deb", "pkg", "apk", "jar", "war", "ear", "sit", "sitx", "cpgz", "tlz", "tlzma", "tzo", "cpio", "shar", "bzip", "gzip", "7zip", "rar5", "tbz", "txz", // 💾 Disk Image "iso", "img", "vhd", "vmdk", "qcow2", "vhdx", "bin", "cue", "nrg", "daa", "sdi", "vfd", "ima", "dmg", "vdi", "toast", "ccd", "mdf", "cdi", "bif", "bifc", "bifd", // 🗃️ Database & Data "sql", "db", "dbf", "mdb", "accdb", "json", "toml", "ini", "log", "plist", "pkl", "msgpack", "h5", "hdf5", "parquet", "avro", "orc", "ndjson", "pdb", "sqlite", "sqlite3", "dbx", "sdf", "nc", "netcdf", "grib", "geojson", "gml", "hjson", "cdb", "db3", "dta", "sav", "sas7bdat", "ldif", "fdb", "gdb", "sqlite2", "h5ad", "nc4", "xmind", "drawio", "sdc", "jsonl", "yaml", "yml", "toml", // 💻 Code & Script "js", "jsx", "ts", "tsx", "c", "cpp", "net", "h", "hpp", "java", "py", "rb", "go", "rs", "php", "pl", "sh", "bat", "cmd", "ps1", "lua", "swift", "kt", "scala", "cs", "vb", "dart", "m", "r", "jl", "fs", "vbproj", "sln", "pri", "gemspec", "gradle", "coffee", "erl", "ex", "exs", "hs", "lisp", "clj", "groovy", "scm", "vbs", "nim", "rkt", "ml", "mli", "fsx", "psm1", "cbl", "for", "f90", "lock", "tsconfig", "vue", "svelte", "cjs", "mjs", "mts", "cts", "json5", "es6", "module", "systemjs", // 🌐 Web & Config "html", "htm", "xhtml", "css", "scss", "sass", "less", "xml", "xlf", "po", "pot", "jsp", "asp", "aspx", "jspf", "cgi", "cfm", "env", "babelrc", "cfg", "config", "conf", "editorconfig", "eslintrc", "gitconfig", "gitattributes", "gitignore", "prettierrc", "webmanifest", "dockerfile", // ".dockerfile", // 🔠 Font "ttf", "otf", "woff", "woff2", "eot", "dfont", "pfa", "pfb", "fon", "fnt", "bdf", "ps", // 🗺️ CAD & GIS "dwg", "dxf", "shp", "kml", "kmz", "gpx", "stl", "step", "iges", "igs", "3ds", "3dm", "fbx", "obj", "dae", "ifc", // 🔧 System / Binary / Execution "exe", "msi", "run", "com", "app", "elf", "dll", "so", "dylib", "sys", "scr", "bin", "out", // 🔐 Certificates / Crypto "pem", "crt", "cer", "der", "csr", "p12", "pfx", "jks", "asc", "gpg", "pgp", "p7b", "p7c", "spc", "key", "pub", "cert", "p7m", // 🎮 Games & Projects "nes", "sfc", "gba", "nds", "rom", "pak", "vpk", "bik", "cso", "wad", "wadx", "smc", "gb", "gbc", // 🔬 Bioinformatics "fasta", "fa", "fas", "ffn", "faa", "fna", "frn", "fastq", "fq", "bam", "bed", "sam", "vcf", "gff", "gff3", "gtf", "fai", "tbi", "fast5", "fqz", "fq5" ]); var DOUBLE_EXTENSIONS_FILE = /* @__PURE__ */ new Set([ "log.gz", "tar.gz", "tar.bz2", "tar.bz", "tar.xz", "tar.lz", "tar.lzma", "tar.Z", "tar.zst", "tar.lz4", "log.gz", "sql.gz", "csv.gz", "tsv.gz", "json.gz", "ndjson.gz", "fq.gz", "sam.gz", "fasta.gz", "fa.gz", "ffn.gz", "faa.gz", "fna.gz", "frn.gz", "fastq.gz", "js.map", "css.map" ]); var SPECIAL_FILENAMES = /* @__PURE__ */ new Set([ "Makefile", "Dockerfile", ".dockerignore", ".npmrc", ".envrc", ".htgroup", ".eslintignore", ".env.test", ".env.local", ".env.production", ".env.development", ".env.example", ".dockerfile", ".htaccess", ".htpasswd", ".babelrc", ".eslintrc", ".editorconfig", ".prettierignore", "docker-compose.override.yml", "docker-compose.yml", "Vagrantfile", "Procfile", "Gemfile", "Rakefile", "package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml", "tsconfig.json", "webpack.config.js", "vite.config.js", "vite.config.ts", "Gruntfile.js", "gulpfile.js", "babel.config.js", "babel.js", "rollup.js", // SPECIAL PRESERVE NAME "CON", "NUL", "PRN", "AUX", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" ]); var extractFileName = (input, options = {}) => { if (!isNonEmptyString(input)) return null; assertIsPlainObject(options, { message: ({ currentType, validType }) => `Second parameter (\`options\`) must be of type \`${validType}\`, but received: \`${currentType}\`.` }); const { domainName, domainAware = false } = options; assertIsBoolean(domainAware, { message: ({ currentType, validType }) => `Parameter \`domainAware\` property of the \`options\` (second parameter) must be of type \`${validType}\`, but received: \`${currentType}\`.` }); let pathname = input.trim(); pathname = pathname.replace(/\\/g, "/"); if (domainAware) { if (!isNonEmptyString(domainName)) { throw new TypeError( `If parameter \`domainAware\` is set to \`true\`, the option parameter \`domainName\` is required as string, and cant be an empty-string.` ); } const cleanDomain = punycodeUtilsJS.toASCII(domainName).replace(/^https?:\/\//i, "").replace(/^www\./, "").replace(/\/.*$/, "").toLowerCase(); const inputDomain = punycodeUtilsJS.toASCII(input).replace(/^https?:\/\//i, "").replace(/^www\./, "").toLowerCase(); const inputHost = inputDomain.split("/")[0].split(/[?#]/)[0]; const matchesDomain = inputHost === cleanDomain || inputHost.endsWith(`.${cleanDomain}`); const hasPath = /\/[^/]+$/.test(inputDomain); if (matchesDomain && !hasPath) return null; } const protocolMatch = pathname.match(/^([a-zA-Z][a-zA-Z0-9+.-]*):(.+)$/); if (protocolMatch) { const scheme = protocolMatch[1].toLowerCase(); const rest = protocolMatch[2]; if (["tel", "sms"].some((sch) => sch.startsWith(scheme))) { const clean = rest.split("?")[0].split("#")[0]; return clean.trim() || null; } else if (scheme === "mailto") { const parts = rest.split("/"); let last = parts[parts.length - 1]; last = last.split("?")[0].split("#")[0]; const dotIndex = last.lastIndexOf("."); if (dotIndex > 0) last = last.slice(0, dotIndex); return last || null; } else if (scheme === "data") { const commaIndex = rest.indexOf(","); if (commaIndex === -1) return null; let payload = rest.slice(commaIndex + 1); payload = payload.split("?")[0].split("#")[0]; return payload.trim() || null; } } if (/^[a-z][a-z\d+\-.]*:\/{3,}/i.test(pathname)) { pathname = pathname.replace(/^[a-z][a-z\d+\-.]*:\/{2,}/i, ""); } else { try { const isProbablyUrl = /^[a-z][a-z\d+\-.]*:(\/\/)?/i.test(pathname); pathname = isProbablyUrl ? new URL(pathname).pathname : new URL(`http://localhost/${pathname}`).pathname; } catch { pathname = pathname.replace(/^[a-z][a-z\d+\-.]*:(\/\/)?/i, ""); } } const segments = pathname.split("/").filter(Boolean); if (segments.length === 0) return null; let lastSegment = segments[segments.length - 1].split("?")[0].split("#")[0]; lastSegment = lastSegment.replace(/[?#]+$/, ""); if (!lastSegment) return null; lastSegment = lastSegment.replace(/%2F/gi, "/").replace(/%5C/gi, "\\").replace(/%2E/gi, "."); if (lastSegment.includes("/")) { const parts = lastSegment.split("/").filter(Boolean); lastSegment = parts[parts.length - 1]; } let filename = decodeURIComponent(lastSegment); if (!filename) return null; if (SPECIAL_FILENAMES.has(filename)) return filename; if (/^\.[^.\s][^/]*$/.test(filename)) return filename; if (!filename.includes(".")) return null; const sortedDouble = [...DOUBLE_EXTENSIONS_FILE].sort((a, b) => b.length - a.length); for (const ext of sortedDouble) { const dotExt = `.${ext.toLowerCase()}`; if (filename.toLowerCase().endsWith(dotExt)) { filename = filename.slice(0, filename.length - dotExt.length); break; } } const sortedSingle = [...EXTENSIONS_FILE].sort((a, b) => b.length - a.length); for (const ext of sortedSingle) { const dotExt = `.${ext.toLowerCase()}`; if (filename.toLowerCase().endsWith(dotExt)) { filename = filename.slice(0, filename.length - dotExt.length); break; } } return filename || null; }; export { extractFileName };