UNPKG

projen

Version:

CDK for software projects

1,146 lines (1,145 loc) 113 kB
"use strict"; var __values = (this && this.__values) || function(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; Object.defineProperty(exports, "__esModule", { value: true }); var util_1 = require("@oozcitak/util"); var interfaces_1 = require("./interfaces"); var infra_1 = require("@oozcitak/infra"); var url_1 = require("url"); var _validationErrorCallback; /** * Default ports for a special URL scheme. */ var _defaultPorts = { "ftp": 21, "file": null, "http": 80, "https": 443, "ws": 80, "wss": 443 }; /** * The C0 control percent-encode set are the C0 controls and all code points * greater than U+007E (~). */ var _c0ControlPercentEncodeSet = /[\0-\x1F\x7F-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; /** * The fragment percent-encode set is the C0 control percent-encode set and * U+0020 SPACE, U+0022 ("), U+003C (<), U+003E (>), and U+0060 (`). */ var _fragmentPercentEncodeSet = /[ "<>`]|[\0-\x1F\x7F-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; /** * The path percent-encode set is the fragment percent-encode set and * U+0023 (#), U+003F (?), U+007B ({), and U+007D (}). */ var _pathPercentEncodeSet = /[ "<>`#?{}]|[\0-\x1F\x7F-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; /** * The userinfo percent-encode set is the path percent-encode set and * U+002F (/), U+003A (:), U+003B (;), U+003D (=), U+0040 (@), U+005B ([), * U+005C (\), U+005D (]), U+005E (^), and U+007C (|). */ var _userInfoPercentEncodeSet = /[ "<>`#?{}/:;=@\[\]\\\^\|]|[\0-\x1F\x7F-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; /** * The URL code points are ASCII alphanumeric, U+0021 (!), U+0024 ($), * U+0026 (&), U+0027 ('), U+0028 LEFT PARENTHESIS, U+0029 RIGHT PARENTHESIS, * U+002A (*), U+002B (+), U+002C (,), U+002D (-), U+002E (.), U+002F (/), * U+003A (:), U+003B (;), U+003D (=), U+003F (?), U+0040 (@), U+005F (_), * U+007E (~), and code points in the range U+00A0 to U+10FFFD, inclusive, * excluding surrogates and noncharacters. */ var _urlCodePoints = /[0-9A-Za-z!\$&-\/:;=\?@_~\xA0-\uD7FF\uE000-\uFDCF\uFDF0-\uFFFD]|[\uD800-\uD83E\uD840-\uD87E\uD880-\uD8BE\uD8C0-\uD8FE\uD900-\uD93E\uD940-\uD97E\uD980-\uD9BE\uD9C0-\uD9FE\uDA00-\uDA3E\uDA40-\uDA7E\uDA80-\uDABE\uDAC0-\uDAFE\uDB00-\uDB3E\uDB40-\uDB7E\uDB80-\uDBBE\uDBC0-\uDBFE][\uDC00-\uDFFF]|[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDC00-\uDFFD]/; /** * A forbidden host code point is U+0000 NULL, U+0009 TAB, U+000A LF, * U+000D CR, U+0020 SPACE, U+0023 (#), U+0025 (%), U+002F (/), U+003A (:), * U+003F (?), U+0040 (@), U+005B ([), U+005C (\), or U+005D (]). */ var _forbiddenHostCodePoint = /[\0\t\f\r #%/:?@\[\\\]]/; /** * Sets the callback function for validation errors. * * @param validationErrorCallback - a callback function to be called when a * validation error occurs */ function setValidationErrorCallback(validationErrorCallback) { _validationErrorCallback = validationErrorCallback; } exports.setValidationErrorCallback = setValidationErrorCallback; /** * Generates a validation error. * * @param message - error message */ function validationError(message) { if (_validationErrorCallback !== undefined) { _validationErrorCallback.call(null, "Validation Error: " + message); } } /** * Creates a new URL. */ function newURL() { return { scheme: '', username: '', password: '', host: null, port: null, path: [], query: null, fragment: null, _cannotBeABaseURLFlag: false, _blobURLEntry: null }; } exports.newURL = newURL; /** * Determines if the scheme is a special scheme. * * @param scheme - a scheme */ function isSpecialScheme(scheme) { return (scheme in _defaultPorts); } exports.isSpecialScheme = isSpecialScheme; /** * Determines if the URL has a special scheme. * * @param url - an URL */ function isSpecial(url) { return isSpecialScheme(url.scheme); } exports.isSpecial = isSpecial; /** * Returns the default port for a special scheme. * * @param scheme - a scheme */ function defaultPort(scheme) { return _defaultPorts[scheme] || null; } exports.defaultPort = defaultPort; /** * Determines if the URL has credentials. * * @param url - an URL */ function includesCredentials(url) { return url.username !== '' || url.password !== ''; } exports.includesCredentials = includesCredentials; /** * Determines if an URL cannot have credentials. * * @param url - an URL */ function cannotHaveAUsernamePasswordPort(url) { /** * A URL cannot have a username/password/port if its host is null or the * empty string, its cannot-be-a-base-URL flag is set, or its scheme is * "file". */ return (url.host === null || url.host === "" || url._cannotBeABaseURLFlag || url.scheme === "file"); } exports.cannotHaveAUsernamePasswordPort = cannotHaveAUsernamePasswordPort; /** * Serializes an URL into a string. * * @param url - an URL */ function urlSerializer(url, excludeFragmentFlag) { var e_1, _a; if (excludeFragmentFlag === void 0) { excludeFragmentFlag = false; } /** * 1. Let output be url’s scheme and U+003A (:) concatenated. */ var output = url.scheme + ':'; /** * 2. If url’s host is non-null: */ if (url.host !== null) { /** * 2.1. Append "//" to output. */ output += '//'; /** * 2.2. If url includes credentials, then: */ if (includesCredentials(url)) { /** * 2.2.1. Append url’s username to output. * 2.2.2. If url’s password is not the empty string, then append U+003A (:), * followed by url’s password, to output. * 2.2.3. Append U+0040 (@) to output. */ output += url.username; if (url.password !== '') { output += ':' + url.password; } output += '@'; } /** * 2.3. Append url’s host, serialized, to output. * 2.4. If url’s port is non-null, append U+003A (:) followed by url’s port, * serialized, to output. */ output += hostSerializer(url.host); if (url.port !== null) { output += ':' + url.port; } } else if (url.host === null && url.scheme === "file") { /** * 3. Otherwise, if url’s host is null and url’s scheme is "file", append "//" to output. */ output += '//'; } /** * 4. If url’s cannot-be-a-base-URL flag is set, append url’s path[0] to * output. * 5. Otherwise, then for each string in url’s path, append U+002F (/) * followed by the string to output. */ if (url._cannotBeABaseURLFlag) { output += url.path[0]; } else { try { for (var _b = __values(url.path), _c = _b.next(); !_c.done; _c = _b.next()) { var str = _c.value; output += '/' + str; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } } /** * 6. If url’s query is non-null, append U+003F (?), followed by url’s * query, to output. * 7. If the exclude fragment flag is unset and url’s fragment is non-null, * append U+0023 (#), followed by url’s fragment, to output. * 8. Return output. */ if (url.query !== null) { output += '?' + url.query; } if (!excludeFragmentFlag && url.fragment !== null) { output += '#' + url.fragment; } return output; } exports.urlSerializer = urlSerializer; /** * Serializes a host into a string. * * @param host - a host */ function hostSerializer(host) { /** * 1. If host is an IPv4 address, return the result of running the IPv4 * serializer on host. * 2. Otherwise, if host is an IPv6 address, return U+005B ([), followed * by the result of running the IPv6 serializer on host, followed by * U+005D (]). * 3. Otherwise, host is a domain, opaque host, or empty host, return host. */ if (util_1.isNumber(host)) { return iPv4Serializer(host); } else if (util_1.isArray(host)) { return '[' + iPv6Serializer(host) + ']'; } else { return host; } } exports.hostSerializer = hostSerializer; /** * Serializes an IPv4 address into a string. * * @param address - an IPv4 address */ function iPv4Serializer(address) { /** * 1. Let output be the empty string. * 2. Let n be the value of address. * 3. For each i in the range 1 to 4, inclusive: * 3.1. Prepend n % 256, serialized, to output. * 3.2. If i is not 4, then prepend U+002E (.) to output. * 3.3. Set n to floor(n / 256). * 4. Return output. */ var output = ""; var n = address; for (var i = 1; i <= 4; i++) { output = (n % 256).toString() + output; if (i !== 4) { output = '.' + output; } n = Math.floor(n / 256); } return output; } exports.iPv4Serializer = iPv4Serializer; /** * Serializes an IPv6 address into a string. * * @param address - an IPv6 address represented as a list of eight numbers */ function iPv6Serializer(address) { /** * 1. Let output be the empty string. * 2. Let compress be an index to the first IPv6 piece in the first longest * sequences of address’s IPv6 pieces that are 0. * In 0:f:0:0:f:f:0:0 it would point to the second 0. * 3. If there is no sequence of address’s IPv6 pieces that are 0 that is * longer than 1, then set compress to null. */ var output = ""; var compress = null; var lastIndex = -1; var count = 0; var lastCount = 0; for (var i = 0; i < 8; i++) { if (address[i] !== 0) continue; count = 1; for (var j = i + 1; j < 8; j++) { if (address[j] !== 0) break; count++; continue; } if (count > lastCount) { lastCount = count; lastIndex = i; } } if (lastCount > 1) compress = lastIndex; /** * 4. Let ignore0 be false. * 5. For each pieceIndex in the range 0 to 7, inclusive: */ var ignore0 = false; for (var pieceIndex = 0; pieceIndex < 8; pieceIndex++) { /** * 5.1. If ignore0 is true and address[pieceIndex] is 0, then continue. * 5.2. Otherwise, if ignore0 is true, set ignore0 to false. * 5.3. If compress is pieceIndex, then: */ if (ignore0 && address[pieceIndex] === 0) continue; if (ignore0) ignore0 = false; if (compress === pieceIndex) { /** * 5.3.1. Let separator be "::" if pieceIndex is 0, and U+003A (:) otherwise. * 5.3.2. Append separator to output. * 5.3.3. Set ignore0 to true and continue. */ output += (pieceIndex === 0 ? '::' : ':'); ignore0 = true; continue; } /** * 5.4. Append address[pieceIndex], represented as the shortest possible * lowercase hexadecimal number, to output. * 5.5. If pieceIndex is not 7, then append U+003A (:) to output. */ output += address[pieceIndex].toString(16); if (pieceIndex !== 7) output += ':'; } /** * 6. Return output. */ return output; } exports.iPv6Serializer = iPv6Serializer; /** * Parses an URL string. * * @param input - input string * @param baseURL - base URL * @param encodingOverride - encoding override */ function urlParser(input, baseURL, encodingOverride) { /** * 1. Let url be the result of running the basic URL parser on input with * base, and encoding override as provided. * 2. If url is failure, return failure. * 3. If url’s scheme is not "blob", return url. * 4. Set url’s blob URL entry to the result of resolving the blob URL url, * if that did not return failure, and null otherwise. * 5. Return url. */ var url = basicURLParser(input, baseURL, encodingOverride); if (url === null) return null; if (url.scheme !== "blob") return url; var entry = resolveABlobURL(url); if (entry !== null) { url._blobURLEntry = entry; } else { url._blobURLEntry = null; } return url; } exports.urlParser = urlParser; /** * Parses an URL string. * * @param input - input string * @param baseURL - base URL * @param encodingOverride - encoding override */ function basicURLParser(input, baseURL, encodingOverride, url, stateOverride) { var e_2, _a, e_3, _b; /** * 1. If url is not given: * 1.1. Set url to a new URL. * 1.2. If input contains any leading or trailing C0 control or space, * validation error. * 1.3. Remove any leading and trailing C0 control or space from input. */ if (url === undefined) { url = newURL(); // leading var leadingControlOrSpace = /^[\u0000-\u001F\u0020]+/; var trailingControlOrSpace = /[\u0000-\u001F\u0020]+$/; if (leadingControlOrSpace.test(input) || trailingControlOrSpace.test(input)) { validationError("Input string contains leading or trailing control characters or space."); } input = input.replace(leadingControlOrSpace, ''); input = input.replace(trailingControlOrSpace, ''); } /** * 2. If input contains any ASCII tab or newline, validation error. * 3. Remove all ASCII tab or newline from input. */ var tabOrNewline = /[\u0009\u000A\u000D]/g; if (tabOrNewline.test(input)) { validationError("Input string contains tab or newline characters."); } input = input.replace(tabOrNewline, ''); /** * 4. Let state be state override if given, or scheme start state otherwise. * 5. If base is not given, set it to null. * 6. Let encoding be UTF-8. * 7. If encoding override is given, set encoding to the result of getting * an output encoding from encoding override. */ var state = (stateOverride === undefined ? interfaces_1.ParserState.SchemeStart : stateOverride); if (baseURL === undefined) baseURL = null; var encoding = (encodingOverride === undefined || encodingOverride === "replacement" || encodingOverride === "UTF-16BE" || encodingOverride === "UTF-16LE" ? "UTF-8" : encodingOverride); /** * 8. Let buffer be the empty string. * 9. Let the @ flag, [] flag, and passwordTokenSeenFlag be unset. * 10. Let pointer be a pointer to first code point in input. */ var buffer = ""; var atFlag = false; var arrayFlag = false; var passwordTokenSeenFlag = false; var EOF = ""; var walker = new util_1.StringWalker(input); /** * 11. Keep running the following state machine by switching on state. If * after a run pointer points to the EOF code point, go to the next step. * Otherwise, increase pointer by one and continue with the state machine. */ while (true) { switch (state) { case interfaces_1.ParserState.SchemeStart: /** * 1. If c is an ASCII alpha, append c, lowercased, to buffer, and set * state to scheme state. * 2. Otherwise, if state override is not given, set state to no scheme * state, and decrease pointer by one. * 3. Otherwise, validation error, return failure. */ if (infra_1.codePoint.ASCIIAlpha.test(walker.c())) { buffer += walker.c().toLowerCase(); state = interfaces_1.ParserState.Scheme; } else if (stateOverride === undefined) { state = interfaces_1.ParserState.NoScheme; walker.pointer--; } else { validationError("Invalid scheme start character."); return null; } break; case interfaces_1.ParserState.Scheme: /** * 1. If c is an ASCII alphanumeric, U+002B (+), U+002D (-), or U+002E * (.), append c, lowercased, to buffer. */ if (infra_1.codePoint.ASCIIAlphanumeric.test(walker.c()) || walker.c() === '+' || walker.c() === '-' || walker.c() === '.') { buffer += walker.c().toLowerCase(); } else if (walker.c() === ':') { /** * 2. Otherwise, if c is U+003A (:), then: * 2.1. If state override is given, then: * 2.1.1. If url’s scheme is a special scheme and buffer is not a * special scheme, then return. * 2.1.2. If url’s scheme is not a special scheme and buffer is a * special scheme, then return. * 2.1.3. If url includes credentials or has a non-null port, and * buffer is "file", then return. * 2.1.4. If url’s scheme is "file" and its host is an empty host or * null, then return. */ if (stateOverride !== undefined) { if (isSpecialScheme(url.scheme) && !isSpecialScheme(buffer)) return url; if (!isSpecialScheme(url.scheme) && isSpecialScheme(buffer)) return url; if ((includesCredentials(url) || url.port !== null) && buffer === "file") return url; if (url.scheme === "file" && (url.host === "" || url.host === null)) return url; } /** * 2.2. Set url’s scheme to buffer. */ url.scheme = buffer; /** * 2.3. If state override is given, then: * 2.3.1. If url’s port is url’s scheme’s default port, then set * url’s port to null. * 2.3.2. Return. */ if (stateOverride !== undefined) { if (url.port === defaultPort(url.scheme)) { url.port = null; } return url; } /** * 2.4. Set buffer to the empty string. */ buffer = ""; if (url.scheme === "file") { /** * 2.5. If url’s scheme is "file", then: * 2.5.1. If remaining does not start with "//", validation error. * 2.5.2. Set state to file state. */ if (!walker.remaining().startsWith("//")) { validationError("Invalid file URL scheme, '//' expected."); } state = interfaces_1.ParserState.File; } else if (isSpecial(url) && baseURL !== null && baseURL.scheme === url.scheme) { /** * 2.6. Otherwise, if url is special, base is non-null, and base’s * scheme is equal to url’s scheme, set state to special relative * or authority state. */ state = interfaces_1.ParserState.SpecialRelativeOrAuthority; } else if (isSpecial(url)) { /** * 2.7. Otherwise, if url is special, set state to special * authority slashes state. */ state = interfaces_1.ParserState.SpecialAuthoritySlashes; } else if (walker.remaining().startsWith("/")) { /** * 2.8. Otherwise, if remaining starts with an U+002F (/), set state * to path or authority state and increase pointer by one. */ state = interfaces_1.ParserState.PathOrAuthority; walker.pointer++; } else { /** * 2.9. Otherwise, set url’s cannot-be-a-base-URL flag, append an * empty string to url’s path, and set state to * cannot-be-a-base-URL path state. */ url._cannotBeABaseURLFlag = true; url.path.push(""); state = interfaces_1.ParserState.CannotBeABaseURLPath; } } else if (stateOverride === undefined) { /** * 3. Otherwise, if state override is not given, set buffer to the * empty string, state to no scheme state, and start over (from the * first code point in input). */ buffer = ""; state = interfaces_1.ParserState.NoScheme; walker.pointer = 0; continue; } else { /** * 4. Otherwise, validation error, return failure. */ validationError("Invalid input string."); return null; } break; case interfaces_1.ParserState.NoScheme: /** * 1. If base is null, or base’s cannot-be-a-base-URL flag is set * and c is not U+0023 (#), validation error, return failure. * 2. Otherwise, if base’s cannot-be-a-base-URL flag is set and * c is U+0023 (#), set url’s scheme to base’s scheme, url’s path to * a copy of base’s path, url’s query to base’s query, url’s * fragment to the empty string, set url’s cannot-be-a-base-URL * flag, and set state to fragment state. * 3. Otherwise, if base’s scheme is not "file", set state to * relative state and decrease pointer by one. * 4. Otherwise, set state to file state and decrease pointer by one. */ if (baseURL === null || (baseURL._cannotBeABaseURLFlag && walker.c() !== '#')) { validationError("Invalid input string."); return null; } else if (baseURL._cannotBeABaseURLFlag && walker.c() === '#') { url.scheme = baseURL.scheme; url.path = infra_1.list.clone(baseURL.path); url.query = baseURL.query; url.fragment = ""; url._cannotBeABaseURLFlag = true; state = interfaces_1.ParserState.Fragment; } else if (baseURL.scheme !== "file") { state = interfaces_1.ParserState.Relative; walker.pointer--; } else { state = interfaces_1.ParserState.File; walker.pointer--; } break; case interfaces_1.ParserState.SpecialRelativeOrAuthority: /** * If c is U+002F (/) and remaining starts with U+002F (/), then set * state to special authority ignore slashes state and increase * pointer by one. * Otherwise, validation error, set state to relative state and * decrease pointer by one. */ if (walker.c() === '/' && walker.remaining().startsWith('/')) { state = interfaces_1.ParserState.SpecialAuthorityIgnoreSlashes; walker.pointer++; } else { validationError("Invalid input string."); state = interfaces_1.ParserState.Relative; walker.pointer--; } break; case interfaces_1.ParserState.PathOrAuthority: /** * If c is U+002F (/), then set state to authority state. * Otherwise, set state to path state, and decrease pointer by one. */ if (walker.c() === '/') { state = interfaces_1.ParserState.Authority; } else { state = interfaces_1.ParserState.Path; walker.pointer--; } break; case interfaces_1.ParserState.Relative: /** * Set url’s scheme to base’s scheme, and then, switching on c: */ if (baseURL === null) { throw new Error("Invalid parser state. Base URL is null."); } url.scheme = baseURL.scheme; switch (walker.c()) { case EOF: // EOF /** * Set url’s username to base’s username, url’s password to base’s * password, url’s host to base’s host, url’s port to base’s port, * url’s path to a copy of base’s path, and url’s query to base’s * query. */ url.username = baseURL.username; url.password = baseURL.password; url.host = baseURL.host; url.port = baseURL.port; url.path = infra_1.list.clone(baseURL.path); url.query = baseURL.query; break; case '/': /** * Set state to relative slash state. */ state = interfaces_1.ParserState.RelativeSlash; break; case '?': /** * Set url’s username to base’s username, url’s password to base’s * password, url’s host to base’s host, url’s port to base’s port, * url’s path to a copy of base’s path, url’s query to the empty * string, and state to query state. */ url.username = baseURL.username; url.password = baseURL.password; url.host = baseURL.host; url.port = baseURL.port; url.path = infra_1.list.clone(baseURL.path); url.query = ""; state = interfaces_1.ParserState.Query; break; case '#': /** * Set url’s username to base’s username, url’s password to base’s * password, url’s host to base’s host, url’s port to base’s port, * url’s path to a copy of base’s path, url’s query to base’s * query, url’s fragment to the empty string, and state to * fragment state. */ url.username = baseURL.username; url.password = baseURL.password; url.host = baseURL.host; url.port = baseURL.port; url.path = infra_1.list.clone(baseURL.path); url.query = baseURL.query; url.fragment = ""; state = interfaces_1.ParserState.Fragment; break; default: /** * If url is special and c is U+005C (\), validation error, * set state to relative slash state. * Otherwise, run these steps: * 1. Set url’s username to base’s username, url’s password to * base’s password, url’s host to base’s host, url’s port to * base’s port, url’s path to a copy of base’s path, and then * remove url’s path’s last item, if any. * 2. Set state to path state, and decrease pointer by one. */ if (isSpecial(url) && walker.c() === '\\') { validationError("Invalid input string."); state = interfaces_1.ParserState.RelativeSlash; } else { url.username = baseURL.username; url.password = baseURL.password; url.host = baseURL.host; url.port = baseURL.port; url.path = infra_1.list.clone(baseURL.path); if (url.path.length !== 0) url.path.splice(url.path.length - 1, 1); state = interfaces_1.ParserState.Path; walker.pointer--; } break; } break; case interfaces_1.ParserState.RelativeSlash: /** * 1. If url is special and c is U+002F (/) or U+005C (\), then: * 1.1. If c is U+005C (\), validation error. * 1.2. Set state to special authority ignore slashes state. * 2. Otherwise, if c is U+002F (/), then set state to authority state. * 3. Otherwise, set url’s username to base’s username, url’s password * to base’s password, url’s host to base’s host, url’s port to base’s * port, state to path state, and then, decrease pointer by one. */ if (isSpecial(url) && (walker.c() === '/' || walker.c() === '\\')) { if (walker.c() === '\\') { validationError("Invalid input string."); } state = interfaces_1.ParserState.SpecialAuthorityIgnoreSlashes; } else if (walker.c() === '/') { state = interfaces_1.ParserState.Authority; } else { if (baseURL === null) { throw new Error("Invalid parser state. Base URL is null."); } url.username = baseURL.username; url.password = baseURL.password; url.host = baseURL.host; url.port = baseURL.port; state = interfaces_1.ParserState.Path; walker.pointer--; } break; case interfaces_1.ParserState.SpecialAuthoritySlashes: /** * If c is U+002F (/) and remaining starts with U+002F (/), then set * state to special authority ignore slashes state and increase * pointer by one. * Otherwise, validation error, set state to special authority ignore * slashes state, and decrease pointer by one. */ if (walker.c() === '/' && walker.remaining().startsWith('/')) { state = interfaces_1.ParserState.SpecialAuthorityIgnoreSlashes; walker.pointer++; } else { validationError("Expected '//'."); state = interfaces_1.ParserState.SpecialAuthorityIgnoreSlashes; walker.pointer--; } break; case interfaces_1.ParserState.SpecialAuthorityIgnoreSlashes: /** * If c is neither U+002F (/) nor U+005C (\), then set state to * authority state and decrease pointer by one. * Otherwise, validation error. */ if (walker.c() !== '/' && walker.c() !== '\\') { state = interfaces_1.ParserState.Authority; walker.pointer--; } else { validationError("Unexpected '/' or '\\'."); } break; case interfaces_1.ParserState.Authority: /** * 1. If c is U+0040 (@), then: */ if (walker.c() === '@') { /** * 1.1. Validation error. * 1.2. If the @ flag is set, prepend "%40" to buffer. * 1.3. Set the @ flag. * 1.4. For each codePoint in buffer: */ validationError("Unexpected '@'."); if (atFlag) buffer = '%40' + buffer; atFlag = true; try { for (var buffer_1 = (e_2 = void 0, __values(buffer)), buffer_1_1 = buffer_1.next(); !buffer_1_1.done; buffer_1_1 = buffer_1.next()) { var codePoint = buffer_1_1.value; /** * 1.4.1. If codePoint is U+003A (:) and passwordTokenSeenFlag is * unset, then set passwordTokenSeenFlag and continue. * 1.4.2. Let encodedCodePoints be the result of running UTF-8 * percent encode codePoint using the userinfo percent-encode set. * 1.4.3. If passwordTokenSeenFlag is set, then append * encodedCodePoints to url’s password. * 1.4.4. Otherwise, append encodedCodePoints to url’s username. */ if (codePoint === ':' && !passwordTokenSeenFlag) { passwordTokenSeenFlag = true; continue; } var encodedCodePoints = utf8PercentEncode(codePoint, _userInfoPercentEncodeSet); if (passwordTokenSeenFlag) { url.password += encodedCodePoints; } else { url.username += encodedCodePoints; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (buffer_1_1 && !buffer_1_1.done && (_a = buffer_1.return)) _a.call(buffer_1); } finally { if (e_2) throw e_2.error; } } /** * 1.5. Set buffer to the empty string. */ buffer = ""; } else if (walker.c() === EOF || walker.c() === '/' || walker.c() === '?' || walker.c() === '#' || (isSpecial(url) && walker.c() === '\\')) { /** * 2. Otherwise, if one of the following is true * - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) * - url is special and c is U+005C (\) * then: * 2.1. If @ flag is set and buffer is the empty string, validation * error, return failure. * 2.2. Decrease pointer by the number of code points in buffer plus * one, set buffer to the empty string, and set state to host state. */ if (atFlag && buffer === "") { validationError("Invalid input string."); return null; } walker.pointer -= (buffer.length + 1); buffer = ""; state = interfaces_1.ParserState.Host; } else { /** * 3. Otherwise, append c to buffer. */ buffer += walker.c(); } break; case interfaces_1.ParserState.Host: case interfaces_1.ParserState.Hostname: if (stateOverride !== undefined && url.scheme === "file") { /** * 1. If state override is given and url’s scheme is "file", then * decrease pointer by one and set state to file host state. */ walker.pointer--; state = interfaces_1.ParserState.FileHost; } else if (walker.c() === ':' && !arrayFlag) { /** * 2. Otherwise, if c is U+003A (:) and the [] flag is unset, then: * 2.1. If buffer is the empty string, validation error, return * failure. * 2.2. Let host be the result of host parsing buffer with url is * not special. * 2.3. If host is failure, then return failure. * 2.4. Set url’s host to host, buffer to the empty string, and * state to port state. * 2.5. If state override is given and state override is hostname * state, then return. */ if (buffer === "") { validationError("Invalid input string."); return null; } var host = hostParser(buffer, !isSpecial(url)); if (host === null) return null; url.host = host; buffer = ""; state = interfaces_1.ParserState.Port; if (stateOverride === interfaces_1.ParserState.Hostname) return url; } else if (walker.c() === EOF || walker.c() === '/' || walker.c() === '?' || walker.c() === '#' || (isSpecial(url) && walker.c() === '\\')) { /** * 3. Otherwise, if one of the following is true * - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) * - url is special and c is U+005C (\) * then decrease pointer by one, and then: * 3.1. If url is special and buffer is the empty string, validation * error, return failure. * 3.2. Otherwise, if state override is given, buffer is the empty * string, and either url includes credentials or url’s port is * non-null, validation error, return. * 3.3. Let host be the result of host parsing buffer with url is * not special. * 3.4. If host is failure, then return failure. * 3.5. Set url’s host to host, buffer to the empty string, and * state to path start state. * 3.6. If state override is given, then return. */ walker.pointer--; if (isSpecial(url) && buffer === "") { validationError("Invalid input string."); return null; } else if (stateOverride !== undefined && buffer === "" && (includesCredentials(url) || url.port !== null)) { validationError("Invalid input string."); return url; } var host = hostParser(buffer, !isSpecial(url)); if (host === null) return null; url.host = host; buffer = ""; state = interfaces_1.ParserState.PathStart; if (stateOverride !== undefined) return url; } else { /** * 4. Otherwise: * 4.1. If c is U+005B ([), then set the [] flag. * 4.2. If c is U+005D (]), then unset the [] flag. * 4.3. Append c to buffer. */ if (walker.c() === '[') arrayFlag = true; if (walker.c() === ']') arrayFlag = false; buffer += walker.c(); } break; case interfaces_1.ParserState.Port: if (infra_1.codePoint.ASCIIDigit.test(walker.c())) { /** * 1. If c is an ASCII digit, append c to buffer. */ buffer += walker.c(); } else if (walker.c() === EOF || walker.c() === '/' || walker.c() === '?' || walker.c() === '#' || (isSpecial(url) && walker.c() === '\\') || stateOverride) { /** * 2. Otherwise, if one of the following is true * - c is the EOF code point, U+002F (/), U+003F (?), or U+0023 (#) * - url is special and c is U+005C (\) * - state override is given * then: */ if (buffer !== "") { /** * 2.1. If buffer is not the empty string, then: * 2.1.1. Let port be the mathematical integer value that is * represented by buffer in radix-10 using ASCII digits for digits * with values 0 through 9. * 2.1.2. If port is greater than 2**16 − 1, validation error, * return failure. * 2.1.3. Set url’s port to null, if port is url’s scheme’s default * port, and to port otherwise. * 2.1.4. Set buffer to the empty string. */ if (buffer !== "") { var port = parseInt(buffer, 10); if (port > Math.pow(2, 16) - 1) { validationError("Invalid port number."); return null; } url.port = (port === defaultPort(url.scheme) ? null : port); buffer = ""; } } /** * 2.2. If state override is given, then return. * 2.3. Set state to path start state, and decrease pointer by one. */ if (stateOverride !== undefined) { return url; } state = interfaces_1.ParserState.PathStart; walker.pointer--; } else { /** * 3. Otherwise, validation error, return failure. */ validationError("Invalid input string."); return null; } break; case interfaces_1.ParserState.File: /** * 1. Set url’s scheme to "file". */ url.scheme = "file"; if (walker.c() === '/' || walker.c() === '\\') { /** * 2. If c is U+002F (/) or U+005C (\), then: * 2.1. If c is U+005C (\), validation error. * 2.2. Set state to file slash state. */ if (walker.c() === '\\') { validationError("Invalid input string."); } state = interfaces_1.ParserState.FileSlash; } else if (baseURL !== null && baseURL.scheme === "file") { /** * 3. Otherwise, if base is non-null and base’s scheme is "file", * switch on c: */ switch (walker.c()) { case EOF: /** * Set url’s host to base’s host, url’s path to a copy of base’s * path, and url’s query to base’s query. */ url.host = baseURL.host; url.path = infra_1.list.clone(baseURL.path); url.query = baseURL.query; break; case '?': /** * Set url’s host to base’s host, url’s path to a copy of base’s * path, url’s query to the empty string, and state to query * state. */ url.host = baseURL.host; url.path = infra_1.list.clone(baseURL.path); url.query = ""; state = interfaces_1.ParserState.Query; break; case '#': /** * Set url’s host to base’s host, url’s path to a copy of base’s * path, url’s query to base’s query, url’s fragment to the * empty string, and state to fragment state. */ url.host = baseURL.host; url.path = infra_1.list.clone(baseURL.path); url.query = baseURL.query; url.fragment = ""; state = interfaces_1.ParserState.Fragment; break; default: /** * 1. If the substring from pointer in input does not start * with a Windows drive letter, then set url’s host to base’s * host, url’s path to a copy of base’s path, and then shorten * url’s path. * _Note:_ is a (platform-independent) Windows drive letter * quirk. * 2. Otherwise, validation error. * 3. Set state to path state, and decrease pointer by one. */ if (!startsWithAWindowsDriveLetter(walker.substring())) { url.host = baseURL.host; url.path = infra_1.list.clone(baseURL.path); shorten(url); } else { validationError("Unexpected windows drive letter in input string."); } state = interfaces_1.ParserState.Path; walker.pointer--; break; } }