rittenhop-dev/versions/5.94.2/node_modules/@tryghost/url-utils/lib/utils/relative-to-absolute.js
2024-09-23 19:40:12 -04:00

95 lines
3.2 KiB
JavaScript

// require the whatwg compatible URL library (same behaviour in node and browser)
const {URL} = require('url');
const urlJoin = require('./url-join');
// NOTE: Ghost's relative->absolute handling is a little strange when the rootUrl
// includes a subdirectory. Root-relative paths such as /content/image.jpg are
// actually treated as subdirectory-relative. This means that it's possible to
// migrate from a root config to a subdirectory config without migrating data
// in the database, _however_ that means that the database will now have a mix
// of path styles (/content/image.png and /subdir/content/image.png). To handle
// this when all root-relative paths are treated as subdir-relative we have to
// rely on subdirectory deduplication.
/**
* Convert a root-relative path to an absolute URL based on the supplied root.
* Will _only_ convert root-relative urls (/some/path not some/path)
*
* @param {string} path
* @param {string} rootUrl
* @param {string} itemPath
* @param {object} options
* @returns {string} The passed in url or an absolute URL using
*/
const relativeToAbsolute = function relativeToAbsolute(path, rootUrl, itemPath, _options) {
// itemPath is optional, if it's an object it may be the options param instead
if (typeof itemPath === 'object' && !_options) {
_options = itemPath;
itemPath = null;
}
// itemPath could be sent as a full url in which case, extract the pathname
if (itemPath && itemPath.match(/^http/)) {
const itemUrl = new URL(itemPath);
itemPath = itemUrl.pathname;
}
const defaultOptions = {
assetsOnly: false,
staticImageUrlPrefix: 'content/images'
};
const options = Object.assign({}, defaultOptions, _options);
// return the path as-is if it's not an asset path and we're only modifying assets
if (options.assetsOnly) {
const staticImageUrlPrefixRegex = new RegExp(options.staticImageUrlPrefix);
if (!path.match(staticImageUrlPrefixRegex)) {
return path;
}
}
// if URL is absolute return it as-is
try {
const parsed = new URL(path, 'http://relative');
if (parsed.origin !== 'http://relative') {
return path;
}
// Do not convert protocol relative URLs
if (path.lastIndexOf('//', 0) === 0) {
return path;
}
} catch (e) {
return path;
}
// return the path as-is if it's a pure hash param
if (path.startsWith('#')) {
return path;
}
// return the path as-is if it's not root-relative and we have no itemPath
if (!itemPath && !path.match(/^\//)) {
return path;
}
// force root to always have a trailing-slash for consistent behaviour
if (!rootUrl.endsWith('/')) {
rootUrl = `${rootUrl}/`;
}
const parsedRootUrl = new URL(rootUrl);
const basePath = path.startsWith('/') ? '' : itemPath;
const fullPath = urlJoin([parsedRootUrl.pathname, basePath, path], {rootUrl});
const absoluteUrl = new URL(fullPath, rootUrl);
if (options.secure) {
absoluteUrl.protocol = 'https:';
}
return absoluteUrl.toString();
};
module.exports = relativeToAbsolute;