Socket
Socket
Sign inDemoInstall

@jridgewell/resolve-uri

Package Overview
Dependencies
Maintainers
1
Versions
15
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jridgewell/resolve-uri - npm Package Compare versions

Comparing version 2.0.0 to 3.0.0

268

dist/resolve-uri.umd.js

@@ -7,144 +7,164 @@ (function (global, factory) {

// Matches "..", which must be preceeded by "/" or the start of the string, and
// must be followed by a "/". We do not eat the following "/", so that the next
// iteration can match on it.
const parentRegex = /(^|\/)\.\.(?=\/|$)/g;
// Matches the scheme of a URL, which is a strong indicator it is an valid
// absolute URL.
const schemeRegex = /^\s*[a-z][a-z0-9+\-.]*:/i;
function absoluteUrl(url) {
try {
return schemeRegex.test(url) ? new URL(url) : null;
}
catch (_a) {
/* istanbul ignore next */
return null;
}
}
// Matches the scheme of a URL, eg "http://"
const schemeRegex = /^[\w+.-]+:\/\//;
/**
* Creates a directory name that is guaranteed to not be in `str`.
* Matches the parts of a URL:
* 1. Scheme, including ":", guaranteed.
* 2. User/password, including "@", optional.
* 3. Host, guaranteed.
* 4. Port, including ":", optional.
* 5. Path, including "/", optional.
*/
function uniqInStr(str) {
let uniq = String(Math.random()).slice(2);
let index = 0;
while ((index = str.indexOf(uniq, index)) > -1) {
uniq += uniq;
const urlRegex = /^([\w+.-]+:)\/\/([^@]*@)?([^:/]+)(:\d+)?(\/[^#?]*)?/;
function isAbsoluteUrl(input) {
return schemeRegex.test(input);
}
function isSchemeRelativeUrl(input) {
return input.startsWith('//');
}
function isAbsolutePath(input) {
return input.startsWith('/');
}
function parseAbsoluteUrl(input) {
const match = urlRegex.exec(input);
const host = match[3];
return {
scheme: match[1],
user: match[2] || '',
host,
port: match[4] || '',
path: match[5] || (host ? '/' : ''),
relativePath: false,
};
}
function parseUrl(input) {
if (isSchemeRelativeUrl(input)) {
const url = parseAbsoluteUrl('http:' + input);
url.scheme = '';
return url;
}
return uniq;
if (isAbsolutePath(input)) {
const url = parseAbsoluteUrl('http://foo.com' + input);
url.scheme = '';
url.host = '';
return url;
}
if (!isAbsoluteUrl(input)) {
const url = parseAbsoluteUrl('http://foo.com/' + input);
url.scheme = '';
url.host = '';
url.relativePath = true;
return url;
}
return parseAbsoluteUrl(input);
}
/**
* Removes the filename from the path (everything trailing the last "/"). This
* is only safe to call on a path, never call with an absolute or protocol
* relative URL.
*/
function stripPathFilename(path) {
path = normalizePath(path);
// If a path ends with a parent directory "..", then it's a relative path with excess parent
// paths. It's not a file, so we can't strip it.
if (path.endsWith('/..'))
return path;
const index = path.lastIndexOf('/');
return path.slice(0, index + 1);
}
/**
* Normalizes a protocol-relative URL, but keeps it protocol relative by
* stripping out the protocl before returning it.
*/
function normalizeProtocolRelative(input, absoluteBase) {
const { href, protocol } = new URL(input, absoluteBase);
return href.slice(protocol.length);
function mergePaths(url, base) {
// If we're not a relative path, then we're an absolute path, and it doesn't matter what base is.
if (!url.relativePath)
return;
normalizePath(base);
// Resolution happens relative to the base path's directory, not the file.
url.path = stripPathFilename(base.path) + url.path;
// If the base path is absolute, then our path is now absolute too.
url.relativePath = base.relativePath;
}
/**
* Normalizes a simple path (one that has no ".."s, or is absolute so ".."s can
* be normalized absolutely).
* The path can have empty directories "//", unneeded parents "foo/..", or current directory
* "foo/.". We need to normalize to a standard representation.
*/
function normalizeSimplePath(input) {
const { href } = new URL(input, 'https://foo.com/');
return href.slice('https://foo.com/'.length);
}
/**
* Normalizes a path, ensuring that excess ".."s are preserved for relative
* paths in the output.
*
* If the input is absolute, this will return an absolutey normalized path, but
* it will not have a leading "/".
*
* If the input has a leading "..", the output will have a leading "..".
*
* If the input has a leading ".", the output will not have a leading "."
* unless there are too many ".."s, in which case there will be a leading "..".
*/
function normalizePath(input) {
// If there are no ".."s, we can treat this as if it were an absolute path.
// The return won't be an absolute path, so it's easy.
if (!parentRegex.test(input))
return normalizeSimplePath(input);
// We already found one "..". Let's see how many there are.
let total = 1;
while (parentRegex.test(input))
total++;
// If there are ".."s, we need to prefix the the path with the same number of
// unique directories. This is to ensure that we "remember" how many parent
// directories we are accessing. Eg, "../../.." must keep 3, and "foo/../.."
// must keep 1.
const uniqDirectory = `z${uniqInStr(input)}/`;
// Now we can resolve the total path. If there are excess ".."s, they will
// eliminate one or more of the unique directories we prefix with.
const relative = normalizeSimplePath(uniqDirectory.repeat(total) + input);
// We can now count the number of unique directories that were eliminated. If
// there were 3, and 1 was eliminated, we know we only need to add 1 "..". If
// 2 were eliminated, we need to insert 2 ".."s. If all 3 were eliminated,
// then we need 3, etc.
let index = 0;
while (relative.startsWith(uniqDirectory, index)) {
total--;
index += uniqDirectory.length;
function normalizePath(url) {
const { relativePath } = url;
const pieces = url.path.split('/');
// We need to preserve the first piece always, so that we output a leading slash. The item at
// pieces[0] is an empty string.
let pointer = 1;
// Positive is the number of real directories we've output, used for popping a parent directory.
// Eg, "foo/bar/.." will have a positive 2, and we can decrement to be left with just "foo".
let positive = 0;
// We need to keep a trailing slash if we encounter an empty directory (eg, splitting "foo/" will
// generate `["foo", ""]` pieces). And, if we pop a parent directory. But once we encounter a
// real directory, we won't need to append, unless the other conditions happen again.
let addTrailingSlash = false;
for (let i = 1; i < pieces.length; i++) {
const piece = pieces[i];
// An empty directory, could be a trailing slash, or just a double "//" in the path.
if (!piece) {
addTrailingSlash = true;
continue;
}
// If we encounter a real directory, then we don't need to append anymore.
addTrailingSlash = false;
// A current directory, which we can always drop.
if (piece === '.')
continue;
// A parent directory, we need to see if there are any real directories we can pop. Else, we
// have an excess of parents, and we'll need to keep the "..".
if (piece === '..') {
if (positive) {
addTrailingSlash = true;
positive--;
pointer--;
}
else if (relativePath) {
// If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute
// URL, protocol relative URL, or an absolute path, we don't need to keep excess.
pieces[pointer++] = piece;
}
continue;
}
// We've encountered a real directory. Move it to the next insertion pointer, which accounts for
// any popped or dropped directories.
pieces[pointer++] = piece;
positive++;
}
return '../'.repeat(total) + relative.slice(index);
let path = '';
for (let i = 1; i < pointer; i++) {
path += '/' + pieces[i];
}
if (addTrailingSlash)
path += '/';
url.path = path;
}
/**
* Attempts to resolve `input` URL relative to `base`.
* Attempts to resolve `input` URL/path relative to `base`.
*/
function resolve(input, base) {
if (!base)
base = '';
// Absolute URLs are very easy to resolve right.
let url;
if ((url = absoluteUrl(input)))
return url.href;
if (base) {
// Absolute URLs are easy...
if (absoluteUrl(base))
return new URL(input, base).href;
// If base is protocol relative, we'll resolve with it but keep the result
// protocol relative.
if (base.startsWith('//'))
return normalizeProtocolRelative(input, `https:${base}`);
const url = parseUrl(input);
// If we have a base, and the input isn't already an absolute URL, then we need to merge.
if (base && !url.scheme) {
const baseUrl = parseUrl(base);
url.scheme = baseUrl.scheme;
// If there's no host, then we were just a path.
if (!url.host) {
// The host, user, and port are joined, you can't copy one without the others.
url.user = baseUrl.user;
url.host = baseUrl.host;
url.port = baseUrl.port;
}
mergePaths(url, baseUrl);
}
// Normalize input, but keep it protocol relative. We know base doesn't supply
// a protocol, because that would have been handled above.
if (input.startsWith('//'))
return normalizeProtocolRelative(input, 'https://foo.com/');
// We now know that base (if there is one) and input are paths. We've handled
// both absolute and protocol-relative variations above.
// Absolute paths don't need any special handling, because they cannot have
// extra "." or ".."s. That'll all be stripped away. Input takes priority here,
// because if input is an absolute path, base path won't affect it in any way.
if (input.startsWith('/'))
return '/' + normalizeSimplePath(input);
// Since input and base are paths, we need to join them to do any further
// processing. Paths are joined at the directory level, so we need to remove
// the base's filename before joining. We also know that input does not have a
// leading slash, and that the stripped base will have a trailing slash if
// there are any directories (or it'll be empty).
const joined = stripPathFilename(base) + input;
// If base is an absolute path, then input will be relative to it.
if (base.startsWith('/'))
return '/' + normalizeSimplePath(joined);
// We now know both base (if there is one) and input are relative paths.
const relative = normalizePath(joined);
// If base started with a leading ".", or there is no base and input started
// with a ".", then we need to ensure that the relative path starts with a
// ".". We don't know if relative starts with a "..", though, so check before
// prepending.
if ((base || input).startsWith('.') && !relative.startsWith('.')) {
return './' + relative;
normalizePath(url);
// If the input (and base, if there was one) are both relative, then we need to output a relative.
if (url.relativePath) {
// The first char is always a "/".
const path = url.path.slice(1);
// If base started with a leading ".", or there is no base and input started with a ".", then we
// need to ensure that the relative path starts with a ".". We don't know if relative starts
// with a "..", though, so check before prepending.
const keepRelative = (base || input).startsWith('.');
return !keepRelative || path.startsWith('.') ? path : './' + path;
}
return relative;
// If there's no host (and no scheme/user/port), then we need to output an absolute path.
if (!url.host)
return url.path;
// We're outputting either an absolute URL, or a protocol relative one.
return `${url.scheme}//${url.user}${url.host}${url.port}${url.path}`;
}

@@ -151,0 +171,0 @@

/**
* Attempts to resolve `input` URL relative to `base`.
* Attempts to resolve `input` URL/path relative to `base`.
*/
export default function resolve(input: string, base: string | undefined): string;
{
"name": "@jridgewell/resolve-uri",
"version": "2.0.0",
"version": "3.0.0",
"description": "Resolve a URI relative to an optional base URI",

@@ -17,2 +17,10 @@ "keywords": [

"typings": "dist/types/resolve-uri.d.ts",
"exports": {
".": {
"browser": "./dist/resolve-uri.umd.js",
"require": "./dist/resolve-uri.umd.js",
"import": "./dist/resolve-uri.mjs"
},
"./package.json": "./package.json"
},
"files": [

@@ -19,0 +27,0 @@ "dist"

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc