# url-utils _(no submodules)_ ## Purpose Provides the four foundational URL and XML utility functions that the sitemap builder and parser modules rely on. Keeping these helpers in a dedicated module allows them to be independently tested and reused across all sitemap generation paths without coupling them to any particular class or algorithm. ## Features - `isValidUrl` — validates that a string is an absolute `http` or `https` URL using the platform `URL` constructor - `normalizeUrl` — lowercases the scheme and host of any absolute URL for canonical sitemap output - `escapeXml` — escapes the five XML-special characters (`&`, `<`, `>`, `"`, `'`) - `formatPriority` — clamps a floating-point value to `[0.0, 1.0]` and renders it as a two-decimal-place string ## Usage: Basic Example ```ts import { isValidUrl, escapeXml, formatPriority, } from "@suaveplan/sitemap"; console.log(isValidUrl("https://example.com/")); // true console.log(isValidUrl("ftp://example.com/")); // false console.log(escapeXml("a & b < c")); // "a & b < c" console.log(formatPriority(0.75)); // "0.75" ``` ## Usage: Advanced Example ```ts import { isValidUrl, normalizeUrl, escapeXml, formatPriority } from "@suaveplan/sitemap"; // Normalise user-supplied URLs before XML serialisation const userUrl = "HTTPS://Example.COM/About"; if (isValidUrl(userUrl)) { const canonical = normalizeUrl(userUrl); // "https://example.com/About" const xml = `${escapeXml(canonical)}`; // "https://example.com/About" } // Clamp out-of-range priorities gracefully const userPriority = 1.5; const safeAttr = `${formatPriority(userPriority)}`; // "1.00" ``` ## API Reference ### `isValidUrl(url: string): boolean` Returns `true` when `url` parses as a valid absolute URL with `http:` or `https:` protocol. Returns `false` for any other protocol, relative URLs, or malformed strings. **Throws:** never — all errors are caught internally. ### `normalizeUrl(url: string): string` Lowercases the protocol and hostname of the parsed URL and returns the reconstituted string. If the URL cannot be parsed, the original string is returned unchanged. **Throws:** never. ### `escapeXml(str: string): string` Replaces `&` → `&`, `<` → `<`, `>` → `>`, `"` → `"`, `'` → `'`. Suitable for both element content and attribute values. **Throws:** never. ### `formatPriority(priority: number): string` Clamps `priority` to the closed interval `[0.0, 1.0]` using `Math.max` / `Math.min`, then calls `.toFixed(2)` to produce a two-decimal-place string (e.g. `"0.50"`). **Throws:** never. ## Implementation Notes `isValidUrl` and `normalizeUrl` deliberately delegate to the platform `URL` constructor rather than attempting regex parsing. This gives accurate results for IDNs, percent-encoded paths, and IPv6 host literals without maintaining a custom parser. The `try/catch` wrappers ensure the helpers never throw regardless of input. `escapeXml` uses a sequence of `.replace()` calls rather than a single regex with a callback to keep the implementation readable and free of closure overhead for the common case.