-
-
Notifications
You must be signed in to change notification settings - Fork 319
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!(postcss-normalize-url): inline third-party dep and remove options
Inline a simplified version of normalize-url. Reasons: - the two most recent major releases of normalize-url use ES modules, so cssnano cannot use them - most options change the meaning of the URLs, so it is unlikely that turning them on during minification makes sense THe remaining code removes redundant slashes and default ports, so performs the same as the previous default configuration. It does not sort parameters any more because we haven't yet found a method that preserves the correct encoding in all cases. If the user does not like these transforms they can turn the plugin off completely.
- Loading branch information
1 parent
697a0e5
commit 2f3ca13
Showing
7 changed files
with
174 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'postcss-normalize-url': major | ||
--- | ||
|
||
feat!: drop third-party normalize-url and remove options |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,152 @@ | ||
/* Derived from normalize-url https://github.com/sindresorhus/normalize-url/main/index.js by Sindre Sorhus */ | ||
|
||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/Data_URIs | ||
const DATA_URL_DEFAULT_MIME_TYPE = 'text/plain'; | ||
const DATA_URL_DEFAULT_CHARSET = 'us-ascii'; | ||
|
||
const supportedProtocols = new Set(['https:', 'http:', 'file:']); | ||
|
||
/** | ||
* @param {string} urlString | ||
* @return {boolean} */ | ||
function hasCustomProtocol(urlString) { | ||
try { | ||
const { protocol } = new URL(urlString); | ||
return protocol.endsWith(':') && !supportedProtocols.has(protocol); | ||
} catch { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* @param {string} urlString | ||
* @return {string} */ | ||
function normalizeDataURL(urlString) { | ||
const match = /^data:(?<type>[^,]*?),(?<data>[^#]*?)(?:#(?<hash>.*))?$/.exec( | ||
urlString | ||
); | ||
|
||
if (!match) { | ||
throw new Error(`Invalid URL: ${urlString}`); | ||
} | ||
|
||
let { type, data, hash } = | ||
/** @type {{type: string, data: string, hash: string}} */ (match.groups); | ||
const mediaType = type.split(';'); | ||
|
||
let isBase64 = false; | ||
if (mediaType[mediaType.length - 1] === 'base64') { | ||
mediaType.pop(); | ||
isBase64 = true; | ||
} | ||
|
||
// Lowercase MIME type | ||
const mimeType = mediaType.shift()?.toLowerCase() ?? ''; | ||
const attributes = mediaType | ||
.map( | ||
/** @type {(string: string) => string} */ (attribute) => { | ||
let [key, value = ''] = attribute | ||
.split('=') | ||
.map( | ||
/** @type {(string: string) => string} */ (string) => string.trim() | ||
); | ||
|
||
// Lowercase `charset` | ||
if (key === 'charset') { | ||
value = value.toLowerCase(); | ||
|
||
if (value === DATA_URL_DEFAULT_CHARSET) { | ||
return ''; | ||
} | ||
} | ||
|
||
return `${key}${value ? `=${value}` : ''}`; | ||
} | ||
) | ||
.filter(Boolean); | ||
|
||
const normalizedMediaType = [...attributes]; | ||
|
||
if (isBase64) { | ||
normalizedMediaType.push('base64'); | ||
} | ||
|
||
if ( | ||
normalizedMediaType.length > 0 || | ||
(mimeType && mimeType !== DATA_URL_DEFAULT_MIME_TYPE) | ||
) { | ||
normalizedMediaType.unshift(mimeType); | ||
} | ||
|
||
return `data:${normalizedMediaType.join(';')},${ | ||
isBase64 ? data.trim() : data | ||
}${hash ? `#${hash}` : ''}`; | ||
} | ||
|
||
/** | ||
* @param {string} urlString | ||
* @return {string} | ||
*/ | ||
function normalizeUrl(urlString) { | ||
urlString = urlString.trim(); | ||
|
||
// Data URL | ||
if (/^data:/i.test(urlString)) { | ||
return normalizeDataURL(urlString); | ||
} | ||
|
||
if (hasCustomProtocol(urlString)) { | ||
return urlString; | ||
} | ||
|
||
const hasRelativeProtocol = urlString.startsWith('//'); | ||
const isRelativeUrl = !hasRelativeProtocol && /^\.*\//.test(urlString); | ||
|
||
// Prepend protocol | ||
if (!isRelativeUrl) { | ||
urlString = urlString.replace(/^(?!(?:\w+:)?\/\/)|^\/\//, 'http:'); | ||
} | ||
|
||
const urlObject = new URL(urlString); | ||
|
||
// Remove duplicate slashes if not preceded by a protocol | ||
if (urlObject.pathname) { | ||
urlObject.pathname = urlObject.pathname.replace( | ||
/(?<!\b[a-z][a-z\d+\-.]{1,50}:)\/{2,}/g, | ||
'/' | ||
); | ||
} | ||
|
||
// Decode URI octets | ||
if (urlObject.pathname) { | ||
try { | ||
urlObject.pathname = decodeURI(urlObject.pathname); | ||
} catch { | ||
/* Do nothing */ | ||
} | ||
} | ||
|
||
if (urlObject.hostname) { | ||
// Remove trailing dot | ||
urlObject.hostname = urlObject.hostname.replace(/\.$/, ''); | ||
} | ||
|
||
urlObject.pathname = urlObject.pathname.replace(/\/$/, ''); | ||
|
||
// Take advantage of many of the Node `url` normalizations | ||
urlString = urlObject.toString(); | ||
|
||
// Remove ending `/` | ||
if (urlObject.pathname === '/' && urlObject.hash === '') { | ||
urlString = urlString.replace(/\/$/, ''); | ||
} | ||
|
||
// Restore relative protocol | ||
if (hasRelativeProtocol) { | ||
urlString = urlString.replace(/^http:\/\//, '//'); | ||
} | ||
|
||
return urlString; | ||
} | ||
|
||
module.exports = normalizeUrl; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,9 @@ | ||
export = pluginCreator; | ||
/** @typedef {normalize.Options} Options */ | ||
/** | ||
* @type {import('postcss').PluginCreator<Options>} | ||
* @param {Options} opts | ||
* @type {import('postcss').PluginCreator<void>} | ||
* @return {import('postcss').Plugin} | ||
*/ | ||
declare function pluginCreator(opts: Options): import('postcss').Plugin; | ||
declare function pluginCreator(): import('postcss').Plugin; | ||
declare namespace pluginCreator { | ||
export { postcss, Options }; | ||
const postcss: true; | ||
} | ||
type Options = normalize.Options; | ||
declare var postcss: true; | ||
import normalize = require("normalize-url"); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
export = normalizeUrl; | ||
/** | ||
* @param {string} urlString | ||
* @return {string} | ||
*/ | ||
declare function normalizeUrl(urlString: string): string; |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.