// Import necessary plugins (if any are used in the module) import * as plugins from './smarturl.plugins.js'; // Interface representing the structure of a URL object export interface IUrlObject { href: string; origin: string; protocol: string; username: string; password: string; host: string; hostname: string; port: string; path: string; pathname: string; search: string; searchParams: ISearchParams; hash: string; } // Interface representing the search parameters as a key-value pair object export interface ISearchParams { [key: string]: string; } // Main Smarturl class implementing the IUrlObject interface export class Smarturl implements IUrlObject { // Static method to create a Smarturl instance from a URL string public static createFromUrl( urlArg: string, optionsArg?: { searchParams?: ISearchParams; } ): Smarturl { // Parse the URL string using the built-in URL class const parsedUrlInstance = new URL(urlArg); const searchParams: ISearchParams = {}; // Array to hold key-value pairs of search parameters const searchParamPairs: { key: string; value: string; }[] = []; // If the URL has search parameters, parse them into key-value pairs if (parsedUrlInstance.search) { parsedUrlInstance.search .replace('?', '') // Remove the '?' at the beginning .split('&') // Split the query string into individual parameters .map((searchParamPair) => { // Split each parameter into key and value and add to the array searchParamPairs.push({ key: searchParamPair.split('=')[0], value: searchParamPair.split('=')[1], }); }); } // Convert the array of key-value pairs into an object for (const searchParamPair of searchParamPairs) { searchParams[searchParamPair.key] = searchParamPair.value; } // Merge any additional search parameters provided in optionsArg if (optionsArg?.searchParams) { for (const key of Object.keys(optionsArg.searchParams)) { searchParams[key] = optionsArg.searchParams[key]; } } // Reconstruct the path with updated search parameters let path = parsedUrlInstance.pathname || ''; if (Object.keys(searchParams).length > 0) { path += '?'; let first = true; for (const key of Object.keys(searchParams)) { if (first) { first = false; } else { path += '&'; } path += `${key}=${searchParams[key]}`; } } // Create an IUrlObject containing all parts of the URL const parsedUrl: IUrlObject = { ...parsedUrlInstance, // Spread operator to include all properties from parsedUrlInstance href: parsedUrlInstance.href, origin: parsedUrlInstance.origin, protocol: parsedUrlInstance.protocol, username: parsedUrlInstance.username, password: parsedUrlInstance.password, host: parsedUrlInstance.host, hostname: parsedUrlInstance.hostname, port: parsedUrlInstance.port, path, // Updated path with new search parameters pathname: parsedUrlInstance.pathname, search: parsedUrlInstance.search, searchParams, // The searchParams object we constructed hash: parsedUrlInstance.hash, }; // Infer default ports if none are specified based on the protocol if (!parsedUrl.port && parsedUrl.protocol === 'https:') { parsedUrl.port = '443'; } if (!parsedUrl.port && parsedUrl.protocol === 'http:') { parsedUrl.port = '80'; } // Create a new Smarturl instance and assign the parsed URL properties const returnSmarturl = new Smarturl(); Object.assign(returnSmarturl, parsedUrl); // Copy all properties from parsedUrl to returnSmarturl return returnSmarturl; } // Static method to create a Smarturl instance from an existing IUrlObject public static createFromParsedUrl(parsedUrlArg: IUrlObject): Smarturl { const returnSmarturl = new Smarturl(); Object.assign(returnSmarturl, parsedUrlArg); // Copy all properties from parsedUrlArg to returnSmarturl return returnSmarturl; } // INSTANCE PROPERTIES (matching IUrlObject interface) href: string; origin: string; protocol: string; username: string; password: string; host: string; hostname: string; port: string; path: string; pathname: string; search: string; searchParams: ISearchParams; hash: string; // Constructor initializes searchParams as an empty object constructor() { this.searchParams = {}; } // Method to create an independent clone of the current Smarturl instance clone(): Smarturl { const clonedInstance = new Smarturl(); Object.assign(clonedInstance, this); // Copy all properties to the new instance clonedInstance.searchParams = { ...this.searchParams }; // Shallow copy of searchParams to prevent shared references return clonedInstance; } /** * Typed method to set a property and return the instance for chaining. * @param prop - The property name to set (must be a key of Smarturl) * @param value - The value to assign to the property * @returns The Smarturl instance for method chaining */ set(prop: K, value: this[K]): this { this[prop] = value; // Set the property to the new value return this; // Return the instance for chaining } // Method to convert the Smarturl instance back into a URL string toString(): string { let userpart = ``; // Initialize the user part of the URL (username and password) // Construct the user part based on the presence of username and password if (this.username && !this.password) { userpart = `${this.username}@`; } if (this.username && this.password) { userpart = `${this.username}:${this.password}@`; } // Construct and return the full URL string return `${this.protocol}//${userpart}${this.hostname}:${this.port}${this.path}`; } }