logitar-js
Version:
Helper functions distributed by Logitar.
464 lines (463 loc) • 15 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.UrlBuilder = exports.Credentials = void 0;
const stringUtils_1 = require("./stringUtils");
/**
* Represents credentials to be used in an authentication system.
*/
class Credentials {
/**
* Returns the identifier of the credentials, typically an username.
* @returns The identifier of the credentials.
*/
getIdentifier() {
return this.identifier;
}
/**
* Sets the identifier of the credentials, typically an username.
* @param identifier The identifier to set.
*/
setIdentifier(identifier) {
this.identifier = identifier;
}
/**
* Returns the secret of the credentials, typically a password.
* @returns The secret of the credentials.
*/
getSecret() {
return this.secret;
}
/**
* Sets the secret of the credentials, typically a password.
* @param secret The secret to set.
*/
setSecret(secret) {
this.secret = secret;
}
/**
* Creates a new instance of the `Credentials` class.
* @param identifier The identifier of the credentials, typically an username.
* @param secret The secret of the credentials, typically a password.
*/
constructor(identifier = "", secret = "") {
this.identifier = identifier;
this.secret = secret;
}
/**
* Parses the specified credentials using the `{identifier}:{secret}` format into a new instance of the `Credentials` class.
* @param credentials
* @returns The created instance.
*/
static parse(credentials) {
credentials = (0, stringUtils_1.cleanTrim)(credentials);
if (typeof credentials !== "string") {
return undefined;
}
const index = credentials.indexOf(":");
if (index < 0) {
return new Credentials(credentials);
}
return new Credentials(credentials.substring(0, index), credentials.substring(index + 1));
}
}
exports.Credentials = Credentials;
/**
* Represents a builder class used to build URLs.
*/
class UrlBuilder {
/**
* Returns the list of supported URL schemes.
* @returns The supported URL schemes.
*/
static getSupportedSchemes() {
return [...UrlBuilder.supportedSchemes];
}
/**
* Returns a value indicating whether or not the specified scheme is supported.
* @param scheme The scheme to check.
* @returns True if the scheme is supported, or false otherwise.
*/
static isSchemeSupported(scheme) {
return UrlBuilder.supportedSchemes.has(scheme.trim().toLowerCase());
}
/**
* Returns the scheme of the URL.
* @returns The scheme of the URL.
*/
getScheme() {
return this.scheme;
}
/**
* Sets the scheme of the URL.
* @param scheme The scheme to set.
* @param inferPort If true, the port will be inferred from the scheme.
* @returns The instance of the builder.
* @throws {Error} The scheme is not supported.
*/
setScheme(scheme, inferPort) {
if (!UrlBuilder.isSchemeSupported(scheme)) {
throw new Error(`The scheme '${scheme}' is not supported.`);
}
this.scheme = scheme.trim().toLowerCase();
if (inferPort) {
this.port = UrlBuilder.inferPort(scheme);
}
return this;
}
/**
* Returns the credentials of the URL.
* @returns The credentials of the URL.
*/
getCredentials() {
return this.credentials;
}
/**
* Sets the credentials of the URL.
* @param credentials The credentials to set.
* @returns The instance of the builder.
*/
setCredentials(credentials) {
this.credentials = credentials;
return this;
}
/**
* Returns the host of the URL.
* @returns The host of the URL.
*/
getHost() {
return this.host;
}
/**
* Sets the host of the URL. The default host will be set if the specified host is empty.
* @param host The host of the URL.
* @returns The instance of the builder.
*/
setHost(host) {
var _a;
this.host = (_a = (0, stringUtils_1.cleanTrim)(host)) !== null && _a !== void 0 ? _a : UrlBuilder.DEFAULT_HOST;
return this;
}
/**
* Returns the port of the URL.
* @returns The port of the URL.
*/
getPort() {
return this.port;
}
/**
* Sets the portal of the URL.
* @param port The port of the URL.
* @returns The instance of the builder.
* @throws {Error} The port is not a number or not within port ranges (0-65535).
*/
setPort(port) {
if (isNaN(port) || port < 0 || port > 65535) {
throw new Error(`The port '${port}' must be a value between 0 and 65535.`);
}
this.port = port;
return this;
}
/**
* Returns the authority of the URL.
* @returns The authority of the URL.
*/
getAuthority() {
let authority = "";
if (this.credentials) {
authority += `${this.credentials.getIdentifier()}:${this.credentials.getSecret()}@`;
}
authority += `${this.host}:${this.port}`;
return authority;
}
/**
* Sets the authority of the URL.
* @param authority The authority of the URL.
* @returns The instance of the builder.
* @throws {Error} The value is not a valid URL authority.
*/
setAuthority(authority) {
const parts = authority.split("@");
if (parts.length > 2) {
throw new Error(`The value '${authority}' is not a valid URL authority.`);
}
else if (parts.length === 2) {
this.setCredentials(Credentials.parse(parts[0]));
}
const endPoint = parts[parts.length - 1];
const index = endPoint.indexOf(":");
if (index < 0) {
this.setHost(endPoint);
}
else {
this.setHost(endPoint.substring(0, index));
this.setPort(Number(endPoint.substring(index + 1)));
}
return this;
}
/**
* Returns the list of segments of the URL path.
* @returns The segments of the URL.
*/
getSegments() {
return [...this.segments];
}
/**
* Sets the segments of the URL path. Empty segments will be discarded.
* @param segments The segments of the URL.
* @returns The instance of the builder.
*/
setSegments(segments) {
this.segments.length = 0;
segments.forEach((segment) => {
if (!(0, stringUtils_1.isNullOrWhiteSpace)(segment)) {
this.segments.push(segment.trim());
}
});
return this;
}
/**
* Returns the path of the URL.
* @returns The path of the URL.
*/
getPath() {
return this.segments.length === 0 ? undefined : `/${this.segments.join("/")}`;
}
/**
* Sets the path of the URL.
* @param path The path of the URL.
* @returns The instance of the builder.
*/
setPath(path) {
var _a;
this.setSegments((_a = path === null || path === void 0 ? void 0 : path.split("/")) !== null && _a !== void 0 ? _a : []);
return this;
}
/**
* Returns the query parameters of the URL.
* @returns The query parameters of the URL.
*/
getQuery() {
return new Map(this.query);
}
/**
* Returns the query string of the URL.
* @returns The query string of the URL.
*/
getQueryString() {
if (this.query.size === 0) {
return undefined;
}
const parameters = [];
this.query.forEach((values, key) => values.forEach((value) => parameters.push([key, value].join("="))));
return `?${parameters.join("&")}`;
}
/**
* Adds a query parameter to the URL. The specified values will be appended to existing values associated to this key. Empty keys and values will be discarded.
* @param key The key of the parameter.
* @param values The value or the values of the parameter.
* @returns The instance of the builder.
*/
addQuery(key, values) {
var _a;
if (typeof values === "string") {
return this.addQuery(key, [values]);
}
if (!(0, stringUtils_1.isNullOrWhiteSpace)(key)) {
key = key.trim();
const existingValues = (_a = this.query.get(key)) !== null && _a !== void 0 ? _a : [];
values.forEach((value) => {
if (!(0, stringUtils_1.isNullOrWhiteSpace)(value)) {
existingValues.push(value.trim());
}
});
this.setQuery(key, existingValues);
}
return this;
}
/**
* Sets a query parameter to the URL. The specified values will replace the existing values associated to this key. Empty keys and values will be discarded.
* @param key The key of the parameter.
* @param values The value or the values of the parameter.
* @returns The instance of the builder.
*/
setQuery(key, values) {
if (typeof values === "string") {
return this.setQuery(key, [values]);
}
if (!(0, stringUtils_1.isNullOrWhiteSpace)(key)) {
key = key.trim();
const newValues = [];
values.forEach((value) => {
if (!(0, stringUtils_1.isNullOrWhiteSpace)(value)) {
newValues.push(value.trim());
}
});
if (newValues.length > 0) {
this.query.set(key, newValues);
}
else {
this.query.delete(key);
}
}
return this;
}
/**
* Sets the query string of the URL. Empty keys and values will be discarded.
* @param queryString The query string of the URL.
* @returns The instance of the builder.
*/
setQueryString(queryString) {
var _a;
queryString = (0, stringUtils_1.cleanTrim)((0, stringUtils_1.trimStart)((_a = queryString === null || queryString === void 0 ? void 0 : queryString.trim()) !== null && _a !== void 0 ? _a : "", "?"));
this.query.clear();
if (typeof queryString === "string") {
const parameters = queryString.split("&");
parameters.forEach((parameter) => {
const index = parameter.indexOf("=");
if (index >= 0) {
this.addQuery(parameter.substring(0, index), parameter.substring(index + 1));
}
});
}
return this;
}
/**
* Returns the fragment of the URL.
* @returns The fragment of the URL.
*/
getFragment() {
return this.fragment;
}
/**
* Sets the fragment of the URL.
* @param fragment The fragment of the URL.
* @returns The instance of the builder.
*/
setFragment(fragment) {
var _a;
fragment = (0, stringUtils_1.cleanTrim)((0, stringUtils_1.trimStart)((_a = fragment === null || fragment === void 0 ? void 0 : fragment.trim()) !== null && _a !== void 0 ? _a : "", "#"));
this.fragment = typeof fragment !== "string" ? undefined : `#${fragment}`;
return this;
}
/**
* Returns the parameters of the URL. Parameters are tokens that replace values in built URLs.
* @returns The parameters of the URL.
*/
getParameters() {
return new Map(this.parameters);
}
/**
* Sets a parameter of the URL. Parameters are tokens that replace values in built URLs.
* @param key The key of the parameter.
* @param value The value of the parameter.
* @returns The instance of the builder.
* @throws {Error} The key is empty.
*/
setParameter(key, value) {
if ((0, stringUtils_1.isNullOrWhiteSpace)(key)) {
throw new Error("The parameter key is required.");
}
key = key.trim();
if ((0, stringUtils_1.isNullOrWhiteSpace)(value)) {
this.parameters.delete(key);
}
else if (value) {
this.parameters.set(key, value.trim());
}
return this;
}
/**
* Creates a new instance of the `UrlBuilder` class.
* @param options The initialization options.
*/
constructor(options) {
this.scheme = UrlBuilder.DEFAULT_SCHEME;
this.host = UrlBuilder.DEFAULT_HOST;
this.port = 80;
this.segments = [];
this.query = new Map();
this.parameters = new Map();
options = options !== null && options !== void 0 ? options : {};
if (options.scheme) {
this.setScheme(options.scheme, true);
}
if (options.host) {
this.setHost(options.host);
}
if (options.port) {
this.setPort(options.port);
}
if (options.path) {
this.setPath(options.path);
}
if (options.queryString) {
this.setQueryString(options.queryString);
}
if (options.fragment) {
this.setFragment(options.fragment);
}
if (options.credentials) {
this.setCredentials(options.credentials);
}
}
/**
* Builds an URL of the specified kind.
* @param kind The URL kind (defaults to `Absolute`).
* @returns The built URL.
*/
build(kind = "Absolute") {
let url = "";
if (kind === "Absolute") {
url += `${this.scheme}://${this.getAuthority()}`;
}
const path = this.getPath();
if (typeof path === "string") {
url += path;
}
const queryString = this.getQueryString();
if (typeof queryString === "string") {
url += queryString;
}
const fragment = this.getFragment();
if (typeof fragment === "string") {
url += fragment;
}
this.parameters.forEach((value, key) => {
const pattern = `\\{${key}\\}`;
url = url.replace(new RegExp(pattern, "g"), value);
});
return url;
}
/**
* Builds an absolute URL.
* @returns The built URL.
*/
buildAbsolute() {
return this.build("Absolute");
}
/**
* Builds a relative URL.
* @returns The built URL.
*/
buildRelative() {
return this.build("Relative");
}
static inferPort(scheme) {
switch (scheme.trim().toLowerCase()) {
case "https":
return 443;
default:
return 80;
}
}
}
exports.UrlBuilder = UrlBuilder;
/**
* The default URL scheme.
*/
UrlBuilder.DEFAULT_SCHEME = "http";
/**
* The default URL host.
*/
UrlBuilder.DEFAULT_HOST = "localhost";
UrlBuilder.supportedSchemes = new Set(["http", "https"]);