{"_id":"@allystudio/url-utils","name":"@allystudio/url-utils","dist-tags":{"latest":"1.0.0"},"versions":{"1.0.0":{"name":"@allystudio/url-utils","version":"1.0.0","description":"Comprehensive URL normalization, validation, and manipulation utilities for web applications","keywords":["url","normalization","validation","domain","path","hostname","utilities","web","crawler","seo","analytics","accessibility","tld","internationalization","punycode"],"homepage":"https://github.com/aleksejleonov/allyship.dev/tree/main/packages/url-utils","repository":{"type":"git","url":"git+https://github.com/aleksejleonov/allyship.dev.git","directory":"packages/url-utils"},"bugs":{"url":"https://github.com/aleksejleonov/allyship.dev/issues"},"author":{"name":"Aleksej Leonov","email":"aleksej@allyship.dev"},"license":"MIT","type":"module","main":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","test":"vitest run","test:watch":"vitest","test:coverage":"vitest run --coverage","lint":"oxlint src","type-check":"tsc --noEmit"},"dependencies":{"tldts":"^6.1.11"},"devDependencies":{"@types/node":"^20.11.5","oxlint":"^0.15.0","tsup":"^8.3.5","typescript":"^5.3.3","vitest":"^3.0.7"},"publishConfig":{"access":"public"},"engines":{"node":">=18"},"_id":"@allystudio/url-utils@1.0.0","gitHead":"487af0dffec62f0f26b6c18f1011831b22b15c24","_nodeVersion":"23.11.0","_npmVersion":"10.9.2","dist":{"integrity":"sha512-aCYkD0gKLv8t9EPz/gl/g63Uf16eBpxiQ1+9kIcplmVkoYA3Wf83BvEqOZp4c6Dgo6Tx3RktpItNsCvfXLsw4w==","shasum":"95387e0ed1d851d2cd7befbbccc9eb60c1da8246","tarball":"https://registry.npmjs.org/@allystudio/url-utils/-/url-utils-1.0.0.tgz","fileCount":5,"unpackedSize":27559,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDLAYO2JRZCpOrl4zkxm+Cyy3mzDQ/MIvGFSkXXbE8MSQIgY8zl6k8soQe0O7EclEnIf/6UnaFdapPu6LZ8RwDPo8o="}]},"_npmUser":{"name":"allystudio","email":"privat@aleksejdix.com","actor":{"name":"allystudio","email":"privat@aleksejdix.com","type":"user"}},"directories":{},"maintainers":[{"name":"allystudio","email":"privat@aleksejdix.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/url-utils_1.0.0_1750416375012_0.47245046897944065"},"_hasShrinkwrap":false}},"time":{"created":"2025-06-20T10:46:14.877Z","1.0.0":"2025-06-20T10:46:15.164Z","modified":"2025-06-20T10:46:15.374Z"},"maintainers":[{"name":"allystudio","email":"privat@aleksejdix.com"}],"description":"Comprehensive URL normalization, validation, and manipulation utilities for web applications","homepage":"https://github.com/aleksejleonov/allyship.dev/tree/main/packages/url-utils","keywords":["url","normalization","validation","domain","path","hostname","utilities","web","crawler","seo","analytics","accessibility","tld","internationalization","punycode"],"repository":{"type":"git","url":"git+https://github.com/aleksejleonov/allyship.dev.git","directory":"packages/url-utils"},"author":{"name":"Aleksej Leonov","email":"aleksej@allyship.dev"},"bugs":{"url":"https://github.com/aleksejleonov/allyship.dev/issues"},"license":"MIT","readme":"# @allystudio/url-utils\n\nComprehensive URL normalization, validation, and manipulation utilities for web applications. This package consolidates all URL handling patterns used across the AllyStudio ecosystem and provides a robust, well-tested foundation for URL operations.\n\n## Features\n\n- 🔧 **URL Normalization** - Consistent URL cleaning across browsers\n- ✅ **Validation** - Comprehensive URL validation with detailed error messages\n- 🎯 **Extraction** - Extract domains, hostnames, paths, and components\n- 🔍 **Comparison** - Compare URLs with flexible options\n- 🌍 **International Support** - Handles international domains and punycode\n- 🚀 **Performance** - Optimized for high-throughput applications\n- 📦 **Zero Dependencies** - Only depends on `tldts` for domain parsing\n- 🧪 **Well Tested** - Comprehensive test suite with 100+ test cases\n\n## Installation\n\n```bash\nnpm install @allystudio/url-utils\n```\n\n## Quick Start\n\n```typescript\nimport { normalizeUrl, extractDomain, compareUrls } from '@allystudio/url-utils'\n\n// Normalize URLs for consistent storage\nconst normalized = normalizeUrl('https://www.Google.com/Path/?utm_source=test')\nconsole.log(normalized.full) // \"google.com/path\"\n\n// Extract domain from any URL\nconst domain = extractDomain('https://sub.example.com/path')\nconsole.log(domain) // \"example.com\"\n\n// Compare URLs intelligently\nconst isSame = compareUrls(\n  'https://example.com/path?param=1',\n  'https://www.example.com/path'\n) // true (ignores query params and www by default)\n```\n\n## API Reference\n\n### Normalization\n\n#### `normalizeUrl(url, options?)`\n\nNormalizes a URL with consistent rules across browsers.\n\n```typescript\ninterface NormalizationOptions {\n  keepQueryParams?: boolean     // Keep query parameters (default: false)\n  keepFragment?: boolean        // Keep hash fragments (default: false)\n  removeWww?: boolean          // Remove www prefix (default: true)\n  removeTrailingSlash?: boolean // Remove trailing slashes (default: true)\n  sortQueryParams?: boolean     // Sort query parameters (default: true)\n}\n\nconst result = normalizeUrl('https://www.example.com/path/?b=2&a=1', {\n  keepQueryParams: true,\n  sortQueryParams: true\n})\n// Returns: { hostname: \"example.com\", domain: \"example.com\", path: \"/path\", full: \"example.com/path?a=1&b=2\", raw: \"...\" }\n```\n\n#### `normalizeUrlString(url, keepQueryParams?)`\n\nSimple string-based normalization (compatible with legacy code).\n\n```typescript\nconst normalized = normalizeUrlString('https://www.example.com/path', false)\n// Returns: \"example.com/path\"\n```\n\n### Validation\n\n#### `isValidPageUrl(url)`\n\nQuick validation for web page URLs.\n\n```typescript\nisValidPageUrl('https://example.com') // true\nisValidPageUrl('chrome://settings')   // false\nisValidPageUrl('localhost')           // false\n```\n\n#### `validateUrl(url)`\n\nDetailed validation with error messages.\n\n```typescript\nconst result = validateUrl('invalid-url')\n// Returns: { isValid: false, error: \"Invalid domain\" }\n```\n\n### Extraction\n\n#### `extractDomain(url)` / `extractHostname(url)` / `extractPath(url)`\n\nExtract specific components from URLs.\n\n```typescript\nextractDomain('https://sub.example.com/path')    // \"example.com\"\nextractHostname('https://sub.example.com/path')  // \"sub.example.com\"\nextractPath('https://example.com/path?param=1')  // \"/path\"\n```\n\n### Comparison\n\n#### `compareUrls(url1, url2, options?)`\n\nCompare URLs with flexible options.\n\n```typescript\ninterface ComparisonOptions {\n  ignoreQueryParams?: boolean  // Ignore query parameters (default: true)\n  ignoreFragment?: boolean     // Ignore hash fragments (default: true)\n  ignoreCase?: boolean        // Ignore case differences (default: true)\n}\n\ncompareUrls(\n  'https://Example.com/path?param=1',\n  'https://www.example.com/path#section',\n  { ignoreQueryParams: true, ignoreFragment: true }\n) // true\n```\n\n#### `compareHostnames(url1, url2)`\n\nCompare just the domains of two URLs.\n\n```typescript\ncompareHostnames('https://sub1.example.com', 'https://sub2.example.com') // true\n```\n\n### Utility Functions\n\n#### `isHomepage(url)`\n\nCheck if a URL points to a homepage.\n\n```typescript\nisHomepage('https://example.com')    // true\nisHomepage('https://example.com/')   // true\nisHomepage('https://example.com/about') // false\n```\n\n#### `isUrlUnderDomain(childUrl, parentDomain)`\n\nCheck if a URL belongs to a specific domain.\n\n```typescript\nisUrlUnderDomain('https://blog.example.com/post', 'example.com') // true\n```\n\n#### `getDisplayUrl(url)`\n\nCreate a display-friendly version of a URL.\n\n```typescript\ngetDisplayUrl('https://example.com/path?param=value')\n// Returns: \"example.com/path?param=value\"\n```\n\n## Use Cases\n\n### Website/Page Management\n\n```typescript\nimport { normalizeUrl, extractDomain, extractPath } from '@allystudio/url-utils'\n\n// Normalize website URLs (remove query params)\nconst websiteUrl = normalizeUrl(userInput).full\n\n// Extract domain and path for database storage\nconst domain = extractDomain(pageUrl)\nconst path = extractPath(pageUrl)\n```\n\n### Web Crawling\n\n```typescript\nimport { normalizeUrlForCrawling, shouldSkipUrl, isUrlUnderDomain } from '@allystudio/url-utils'\n\n// Normalize URLs for crawling (removes query params and fragments)\nconst normalized = normalizeUrlForCrawling(foundUrl, baseUrl)\n\n// Skip non-HTML resources\nif (shouldSkipUrl(url)) {\n  continue\n}\n\n// Stay within domain\nif (!isUrlUnderDomain(foundUrl, targetDomain)) {\n  continue\n}\n```\n\n### Analytics & SEO\n\n```typescript\nimport { normalizeUrl, compareUrls, extractDomain } from '@allystudio/url-utils'\n\n// Deduplicate URLs for analytics\nconst canonical = normalizeUrl(pageUrl, { keepQueryParams: false }).full\n\n// Group pages by domain\nconst domain = extractDomain(pageUrl)\n\n// Compare URLs ignoring tracking parameters\nconst isSamePage = compareUrls(url1, url2, { ignoreQueryParams: true })\n```\n\n## Browser Compatibility\n\n- **Chrome/Edge**: Full support\n- **Firefox**: Full support (IDNs shown in native script)\n- **Safari**: Full support (may handle some Unicode differently)\n- **Mobile**: Full support (respects length limitations)\n\n## International Domain Support\n\nThe package fully supports international domain names (IDNs):\n\n```typescript\n// Handles international domains\nnormalizeUrl('https://グーグル.jp/検索')\n// Returns normalized punycode version\n\n// Supports complex TLD structures\nextractDomain('https://service.gov.uk') // \"gov.uk\"\nextractDomain('https://university.edu.au') // \"edu.au\"\n```\n\n## Error Handling\n\nAll functions include robust error handling:\n\n```typescript\ntry {\n  const result = normalizeUrl(userInput)\n  // Use result.full for normalized URL\n} catch (error) {\n  // Handle invalid URL\n  console.error('Invalid URL:', error.message)\n}\n\n// Or use validation first\nconst validation = validateUrl(userInput)\nif (!validation.isValid) {\n  console.error('Invalid URL:', validation.error)\n} else {\n  const result = normalizeUrl(userInput)\n}\n```\n\n## Performance\n\nThe package is optimized for high-throughput applications:\n\n- Efficient domain parsing with `tldts`\n- Minimal string operations\n- Graceful fallbacks for invalid input\n- No unnecessary object creation\n\n## Migration Guide\n\n### From AllyStudio URL Utils\n\n```typescript\n// Old\nimport { normalizeUrl, extractDomain } from '@/utils/url'\n\n// New\nimport { normalizeUrl, extractDomain } from '@allystudio/url-utils'\n// API is identical, but returns structured objects\n```\n\n### From Allyship URL Utils\n\n```typescript\n// Old\nimport { normalizeUrl } from '@/utils/url'\nconst normalized = normalizeUrl(url, keepQueryParams)\n\n// New\nimport { normalizeUrlString } from '@allystudio/url-utils'\nconst normalized = normalizeUrlString(url, keepQueryParams)\n```\n\n### From Custom Implementations\n\n```typescript\n// Replace custom normalization\nfunction customNormalize(url) {\n  return url.replace(/^https?:\\/\\//, '').replace(/^www\\./, '')\n}\n\n// With robust normalization\nimport { normalizeUrlString } from '@allystudio/url-utils'\nconst normalized = normalizeUrlString(url)\n```\n\n## Contributing\n\nThis package is part of the AllyStudio ecosystem. See the main repository for contribution guidelines.\n\n## License\n\nMIT License - see LICENSE file for details.\n","readmeFilename":"README.md","_rev":"1-b0cb325abcaa7044c51a58e43c954124"}