{"version":3,"file":"resolve-uri.mjs","sources":["../../src/resolve-uri.ts"],"sourcesContent":["// Matches the scheme of a URL, eg \"http://\"\nconst schemeRegex = /^[\\w+.-]+:\\/\\//;\n\n/**\n * Matches the parts of a URL:\n * 1. Scheme, including \":\", guaranteed.\n * 2. User/password, including \"@\", optional.\n * 3. Host, guaranteed.\n * 4. Port, including \":\", optional.\n * 5. Path, including \"/\", optional.\n */\nconst urlRegex = /^([\\w+.-]+:)\\/\\/([^@/#?]*@)?([^:/#?]*)(:\\d+)?(\\/[^#?]*)?/;\n\ntype Url = {\n scheme: string;\n user: string;\n host: string;\n port: string;\n path: string;\n relativePath: boolean;\n};\n\nfunction isAbsoluteUrl(input: string): boolean {\n return schemeRegex.test(input);\n}\n\nfunction isSchemeRelativeUrl(input: string): boolean {\n return input.startsWith('//');\n}\n\nfunction isAbsolutePath(input: string): boolean {\n return input.startsWith('/');\n}\n\nfunction parseAbsoluteUrl(input: string): Url {\n const match = urlRegex.exec(input)!;\n return {\n scheme: match[1],\n user: match[2] || '',\n host: match[3],\n port: match[4] || '',\n path: match[5] || '/',\n relativePath: false,\n };\n}\n\nfunction parseUrl(input: string): Url {\n if (isSchemeRelativeUrl(input)) {\n const url = parseAbsoluteUrl('http:' + input);\n url.scheme = '';\n return url;\n }\n if (isAbsolutePath(input)) {\n const url = parseAbsoluteUrl('http://foo.com' + input);\n url.scheme = '';\n url.host = '';\n return url;\n }\n if (!isAbsoluteUrl(input)) {\n const url = parseAbsoluteUrl('http://foo.com/' + input);\n url.scheme = '';\n url.host = '';\n url.relativePath = true;\n return url;\n }\n return parseAbsoluteUrl(input);\n}\n\nfunction stripPathFilename(path: string): string {\n // If a path ends with a parent directory \"..\", then it's a relative path with excess parent\n // paths. It's not a file, so we can't strip it.\n if (path.endsWith('/..')) return path;\n const index = path.lastIndexOf('/');\n return path.slice(0, index + 1);\n}\n\nfunction mergePaths(url: Url, base: Url) {\n // If we're not a relative path, then we're an absolute path, and it doesn't matter what base is.\n if (!url.relativePath) return;\n\n normalizePath(base);\n\n // If the path is just a \"/\", then it was an empty path to begin with (remember, we're a relative\n // path).\n if (url.path === '/') {\n url.path = base.path;\n } else {\n // Resolution happens relative to the base path's directory, not the file.\n url.path = stripPathFilename(base.path) + url.path;\n }\n\n // If the base path is absolute, then our path is now absolute too.\n url.relativePath = base.relativePath;\n}\n\n/**\n * The path can have empty directories \"//\", unneeded parents \"foo/..\", or current directory\n * \"foo/.\". We need to normalize to a standard representation.\n */\nfunction normalizePath(url: Url) {\n const { relativePath } = url;\n const pieces = url.path.split('/');\n\n // We need to preserve the first piece always, so that we output a leading slash. The item at\n // pieces[0] is an empty string.\n let pointer = 1;\n\n // Positive is the number of real directories we've output, used for popping a parent directory.\n // Eg, \"foo/bar/..\" will have a positive 2, and we can decrement to be left with just \"foo\".\n let positive = 0;\n\n // We need to keep a trailing slash if we encounter an empty directory (eg, splitting \"foo/\" will\n // generate `[\"foo\", \"\"]` pieces). And, if we pop a parent directory. But once we encounter a\n // real directory, we won't need to append, unless the other conditions happen again.\n let addTrailingSlash = false;\n\n for (let i = 1; i < pieces.length; i++) {\n const piece = pieces[i];\n\n // An empty directory, could be a trailing slash, or just a double \"//\" in the path.\n if (!piece) {\n addTrailingSlash = true;\n continue;\n }\n\n // If we encounter a real directory, then we don't need to append anymore.\n addTrailingSlash = false;\n\n // A current directory, which we can always drop.\n if (piece === '.') continue;\n\n // A parent directory, we need to see if there are any real directories we can pop. Else, we\n // have an excess of parents, and we'll need to keep the \"..\".\n if (piece === '..') {\n if (positive) {\n addTrailingSlash = true;\n positive--;\n pointer--;\n } else if (relativePath) {\n // If we're in a relativePath, then we need to keep the excess parents. Else, in an absolute\n // URL, protocol relative URL, or an absolute path, we don't need to keep excess.\n pieces[pointer++] = piece;\n }\n continue;\n }\n\n // We've encountered a real directory. Move it to the next insertion pointer, which accounts for\n // any popped or dropped directories.\n pieces[pointer++] = piece;\n positive++;\n }\n\n let path = '';\n for (let i = 1; i < pointer; i++) {\n path += '/' + pieces[i];\n }\n if (!path || (addTrailingSlash && !path.endsWith('/..'))) {\n path += '/';\n }\n url.path = path;\n}\n\n/**\n * Attempts to resolve `input` URL/path relative to `base`.\n */\nexport default function resolve(input: string, base: string | undefined): string {\n if (!input && !base) return '';\n\n const url = parseUrl(input);\n\n // If we have a base, and the input isn't already an absolute URL, then we need to merge.\n if (base && !url.scheme) {\n const baseUrl = parseUrl(base);\n url.scheme = baseUrl.scheme;\n // If there's no host, then we were just a path.\n if (!url.host || baseUrl.scheme === 'file:') {\n // The host, user, and port are joined, you can't copy one without the others.\n url.user = baseUrl.user;\n url.host = baseUrl.host;\n url.port = baseUrl.port;\n }\n mergePaths(url, baseUrl);\n }\n\n normalizePath(url);\n\n // If the input (and base, if there was one) are both relative, then we need to output a relative.\n if (url.relativePath) {\n // The first char is always a \"/\".\n const path = url.path.slice(1);\n if (!path) return '.';\n\n // If base started with a leading \".\", or there is no base and input started with a \".\", then we\n // need to ensure that the relative path starts with a \".\". We don't know if relative starts\n // with a \"..\", though, so check before prepending.\n const keepRelative = (base || input).startsWith('.');\n return !keepRelative || path.startsWith('.') ? path : './' + path;\n }\n // If there's no host (and no scheme/user/port), then we need to output an absolute path.\n if (!url.scheme && !url.host) return url.path;\n // We're outputting either an absolute URL, or a protocol relative one.\n return `${url.scheme}//${url.user}${url.host}${url.port}${url.path}`;\n}\n"],"names":[],"mappings":"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"}