diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/reformat-urls.js | 89 | ||||
| -rw-r--r-- | src/validators.js | 40 |
2 files changed, 112 insertions, 17 deletions
diff --git a/src/reformat-urls.js b/src/reformat-urls.js index a42d7a4a..69b15de5 100644 --- a/src/reformat-urls.js +++ b/src/reformat-urls.js @@ -25,11 +25,82 @@ function https(namespace, domain) { ]; } +function trimQueryParameter(namespace, domain, parameter) { + return [ + `${namespace}: trim ?${parameter} query parameter`, + + re('gmi', [ + '^(', + '- https://', + '(?:' + domain + ')', + '\/.*', + ')', + + '[&?]' + parameter + '=', + '[^\n&?]+', + ]), + + '$1', + ]; +} + +function trimTrailingSlash(namespace, domain) { + return [ + `${namespace}: trim trailing slash`, + + re('gmi', [ + '^(', + '- https://', + '(?:' + domain + ')', + '\/.*', + ')', + + '/', + '(?=[#?]|$)', + ]), + + '$1', + ]; +} + // Rules are evaluated top to bottom, in order, // so each rule can build off previous ones. const findreplace = []; +// General + +findreplace.push([ + `general: add slash to stand in for empty path`, + re('gmi', ['^(- [a-z]*://[^\n?#/]+)(?=[?#]|$)']), + '$1/', +]); + +// Apple Music + +findreplace.push([ + `apple music: trim country code`, + /^(- https:\/\/music.apple.com\/)[a-z][a-z]\//gmi, + '$1', +]); + +// SoundCloud + +findreplace.push(trimTrailingSlash('soundcloud', 'soundcloud.com')); + +// Spotify + +findreplace.push(trimQueryParameter('spotify', 'open\.spotify\.com', 'si')); +findreplace.push(trimQueryParameter('spotify', 'open\.spotify\.com', 'nd')); + +// Tumblr + +findreplace.push([ + `tumblr: tumblr.com -> www.tumblr.com`, + /^- https:\/\/tumblr\.com\//gmi, + '- https://www.tumblr.com/', +]); + // Twitter const twitterDomains = @@ -63,23 +134,7 @@ const youtubeDomains = findreplace.push(https('youtube', youtubeDomains)); -findreplace.push([ - `youtube: trim ?si search parameter`, - - re('gmi', [ - '^(', - '- https://', - '(?:' + youtubeDomains + ')', - '\/.*', - ')', - - '[&?]si=', - '[a-z0-9_-]+', - '$', - ]), - - '$1', -]); +findreplace.push(trimQueryParameter('youtube', youtubeDomains, 'si')); findreplace.push([ `youtube: youtu.be -> www.youtube.com/watch?v=___`, diff --git a/src/validators.js b/src/validators.js index 19d74991..7dcd7b8c 100644 --- a/src/validators.js +++ b/src/validators.js @@ -743,6 +743,9 @@ export function isCuratedURL(string) { `not ${colors.red(url.hostname)}`); switch (url.hostname) { + case 'tumblr.com': + throw useHostname('www.tumblr.com'); + case 'www.twitter.com': case 'x.com': throw useHostname('twitter.com'); @@ -768,12 +771,49 @@ export function isCuratedURL(string) { } }; + const dropTrailingSlash = () => { + if (url.pathname.length >= 3 && url.pathname.endsWith('/')) { + throw new Error( + `Remove slash at end: ` + + url.pathname.slice(0, -1) + + colors.bright(colors.red('/'))); + } + }; + switch (url.hostname) { + case 'soundcloud.com': + dropTrailingSlash(); + break; + + case 'open.spotify.com': + dropSearchParam('si', `tracking parameter`); + dropSearchParam('nd', `unnecessary parameter`); + break; + case 'www.youtube.com': dropSearchParam('si', `tracking parameter`); break; } + if (url.hostname === 'music.apple.com') { + const countryMatch = + url.pathname.match(/^\/[a-z][a-z]\//); + + if (countryMatch) { + throw new Error(`Remove country code ${colors.red(countryMatch[0])}`); + } + } + + if (url.pathname === '/' && string === url.origin + url.hash + url.search) { + if (url.hash) { + throw new Error(`Add slash before "#" hash`); + } else if (url.search) { + throw new Error(`Add slash before "?" query`); + } else { + throw new Error(`Add slash at end`); + } + } + return true; } |