projen
Version:
CDK for software projects
1,146 lines (1,145 loc) • 113 kB
JavaScript
"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;
}
}