@savvagent/tiny-uri
Version:
Lightweight Javascript library for handling URLs
488 lines (482 loc) • 12.8 kB
JavaScript
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/TinyUri.js
var TinyUri_exports = {};
__export(TinyUri_exports, {
default: () => TinyUri
});
module.exports = __toCommonJS(TinyUri_exports);
// src/Path.js
var Path = class {
/**
* @param {string} f - string path
* @param {object} ctx - context of Uri class
*/
constructor(f, ctx = {}) {
this.ctx = ctx;
this._path = [];
return this.parse(f);
}
/**
* Append to a path
* @param {string} s path to append
* @return {instance} for chaining
*/
append(s) {
this._path.push(s);
return this.ctx;
}
/**
* Delete end of path
* @param {integer} loc - segment of path to delete
* @return {instance} for chaining
*/
delete(loc) {
if (Array.isArray(loc)) {
loc.reverse().forEach((l2) => this._path.splice(l2, 1));
} else if (Number.isInteger(loc)) {
this._path.splice(loc, 1);
} else {
this._path.pop();
}
return this.ctx;
}
/**
* Get the path
* @return {array} path as array
*/
get() {
return this._path;
}
/**
* Parse the path part of a URl
* @param {string} f - string path
* @return {instance} for chaining
*/
parse(f = "") {
let path = decodeURIComponent(f);
let split = path.split("/");
if (Array.isArray(split)) {
if (path.match(/^\//))
split.shift();
if (split[0] === "")
split.shift();
if (split.length > 1 && path.match(/\/$/))
split.pop();
this._path = split;
}
return this;
}
/**
* Replace part of a path
* @param {string} f - path replacement
* @param {integer} loc - location to replace
* @return {instance} for chaining
*/
replace(f, loc) {
if (loc === "file") {
this._path.splice(this._path.length - 1, 1, f);
return this.ctx;
} else if (Number.isInteger(loc)) {
this._path.splice(loc, 1, f);
return this.ctx;
}
this.parse(f);
return this.ctx;
}
/**
* Get string representatio of the path or the uri
* @param {boolen} uri - if true return string represention of uri
* @return {string} path or uri as string
*/
toString(uri) {
if (uri)
return this.ctx.toString();
return Array.isArray(this._path) ? this._path.join("/") : "";
}
};
// src/Query.js
var Query = class {
/**
* @param {string} f - query string
* @param {object} ctx - context of uri instance
* @return {instance} for chaining
*/
constructor(f, ctx = {}) {
Object.assign(this, ctx);
this.ctx = ctx;
this.set(f);
return this;
}
/**
* Add a query string
* @param {object} obj {name: 'value'}
* @return {instance} for chaining
*/
add(obj = {}) {
this._query = this._convert(obj, this._query[0], this._query[1]);
return this.ctx;
}
/**
* Remove the query string
* @return {instance} for chaining
*/
clear() {
this._query = [[], []];
return this.ctx;
}
_convert(obj, p = [], q2 = []) {
for (const key in obj) {
if (Array.isArray(obj[key])) {
for (let i = 0; i < obj[key].length; i++) {
const val = obj[key][i];
p.push(key);
q2.push(val);
}
} else if (obj[key]) {
p.push(key);
q2.push(obj[key]);
}
}
return [p, q2];
}
/**
* Get the query string or get the value of a single query parameter
* @param {string} name representing single query string
* @returns {array} or {string} representing the query string the value of a single query parameter
*/
get(name) {
const dict = {};
const obj = this._query;
for (let i = 0; i < obj[0].length; i++) {
const k2 = obj[0][i];
const v = obj[1][i];
if (dict[k2]) {
dict[k2].push(v);
} else {
dict[k2] = [v];
}
}
if (name)
return dict[name] && dict[name].length ? dict[name][0] : null;
return dict;
}
getUrlTemplateQuery() {
return this._urlTemplateQueryString;
}
/**
* Merge with the query string - replaces query string values if they exist
* @param {object} obj {name: 'value'}
* @return {instance} for chaining
*/
merge(obj) {
const p = this._query[0];
const q2 = this._query[1];
for (const key in obj) {
let kset = false;
for (let i = 0; i < p.length; i++) {
const xKey = p[i];
if (key === xKey) {
if (kset) {
p.splice(i, 1);
q2.splice(i, 1);
continue;
}
if (Array.isArray(obj[key])) {
q2[i] = obj[key].shift();
} else if (typeof obj[key] === "undefined" || obj[key] === null) {
p.splice(i, 1);
q2.splice(i, 1);
delete obj[key];
} else {
q2[i] = obj[key];
delete obj[key];
}
kset = true;
}
}
}
this._query = this._convert(obj, this._query[0], this._query[1]);
return this.ctx;
}
_parse(q2 = "") {
const struct = [[], []];
const pairs = q2.split(/&|;/);
for (let j2 = 0; j2 < pairs.length; j2++) {
const pair = pairs[j2];
const nPair = pair.match(this.qRegEx);
if (nPair && typeof nPair[nPair.length - 1] !== "undefined") {
nPair.shift();
for (let i = 0; i < nPair.length; i++) {
const p = nPair[i];
struct[i].push(decodeURIComponent(p.replace("+", " ", "g")));
}
}
}
return struct;
}
/**
* Set with the query string - replaces existing query string
* @param {obj} or {string} ...q
* @return {instance} for chaining
*/
set(...q2) {
const args = [...q2];
if (args.length === 1) {
if (typeof args[0] === "object") {
this._query = this._convert(args[0]);
} else {
this._query = this._parse(args[0]);
}
} else if (args.length === 0) {
this.clear();
} else {
const obj = {};
obj[args[0]] = args[1];
this.merge(obj);
}
return this.ctx;
}
/**
* Set the url template query string vale
* @param {string} s url-template query string
* @return {instance} for chaining
*/
setUrlTemplateQuery(s) {
this._urlTemplateQueryString = s;
}
/**
* Get string representation of the path or the uri
* @param {boolean} uri - if true return string representation of uri
* @return {string} query or uri as string
*/
toString(uri) {
if (uri)
return this.ctx.toString();
const pairs = [];
const n = this._query[0];
const v = this._query[1];
for (let i = 0; i < n.length; i++) {
pairs.push(encodeURIComponent(n[i]) + "=" + encodeURIComponent(v[i]));
}
return pairs.join("&");
}
};
// ../tiny-utils/dist/esm/index.js
var z = typeof window < "u";
var a = z;
var k = (e) => typeof e == "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/.test(e);
function u(e, t) {
return k(t) ? new Date(t) : k(e) ? new Date(e) : t;
}
function l(e) {
try {
return JSON.parse(e), true;
} catch {
return false;
}
}
var L = (e) => l(e) ? JSON.parse(e, u) : e;
var m = L;
var I = (e) => JSON.stringify(e);
var c = I;
var g = class {
constructor() {
this.db = /* @__PURE__ */ new Map();
}
clear() {
return this.db.clear();
}
del(t) {
return this.db.delete(t);
}
get(t) {
return this.db.get(t);
}
put(t, o) {
return this.set(t, o);
}
set(t, o) {
return this.db.set(t, o);
}
};
var h = class {
constructor() {
window.matchMedia("(display-mode: standalone)").matches ? this.store = window.localStorage : this.store = window.sessionStorage;
}
clear() {
return this.store.clear();
}
del(t) {
return this.store.removeItem(t);
}
get(t) {
if (a)
return m(this.store.getItem(t));
}
put(t, o) {
return this.store.setItem(t, c({ ...this.get(t), ...o }));
}
set(t, o) {
return this.store.setItem(t, c(o));
}
};
var q = a ? new h() : new g();
var x = class {
constructor(t) {
!t || typeof t > "u" ? this.string = "" : this.string = String(t);
}
toString() {
return this.string;
}
append(t) {
return this.string += t, this;
}
insert(t, o) {
let i = this.string.length, r = this.string.slice(0, t), n = this.string.slice(t);
return this.string = r + o + n, this;
}
};
var j = a && typeof navigator < "u" && navigator.languages && navigator.languages.length ? navigator.languages[0] : "en";
var G = j.replace(/-.*/, "");
// src/TinyUri.js
var TinyUri = class _TinyUri {
/**
* @param {string} uri - a URI string
* @return {instance} - return Uri instance for chaining
*/
constructor(uri) {
this.uriRegEx = /^(([^:/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/;
this.authRegEx = /^([^@]+)@/;
this.portRegEx = /:(\d+)$/;
this.qRegEx = /^([^=]+)(?:=(.*))?$/;
this.urlTempQueryRegEx = /\{\?(.*?)\}/;
return this.parse(uri);
}
/**
* @param {string} authority - username password part of URL
* @return {instance} - returns Uri instance for chaining
*/
authority(authority = "") {
if (authority !== "") {
let auth = authority.match(this.authRegEx);
this._authority = authority;
if (auth) {
authority = authority.replace(this.authRegEx, "");
this.userInfo(auth[1]);
}
let port2 = authority.match(this.portRegEx);
if (port2) {
authority = authority.replace(this.portRegEx, "");
this.port(port2[1]);
}
this.host(authority.replace("{", ""));
return this;
}
let userinfo = this.userInfo();
if (userinfo)
authority = userinfo + "@";
authority = authority + this.host();
let port = this.port();
if (port)
authority = authority + (":" + port);
return authority;
}
/**
* @param {string} f - string representation of fragment
* @return {instance} - returns Uri instance for chaining
*/
fragment(f = "") {
return this.gs(f, "_fragment");
}
gs(val, tar, fn) {
if (typeof val !== "undefined") {
this[tar] = val;
return this;
}
return fn ? fn(this[tar]) : this[tar] ? this[tar] : "";
}
/**
* @param {string} f - string representation of host
* @return {instance} - returns Uri instance for chaining
*/
host(f) {
return this.gs(f, "_host");
}
/**
* @param {string} uri - URL
* @return {instance} - returns Uri instance for chaining
*/
parse(uri) {
let f = uri ? uri.match(this.uriRegEx) : [];
let t = uri ? uri.match(this.urlTempQueryRegEx) : [];
this.scheme(f[2]);
this.authority(f[4]);
this.path = new Path(f[5] ? f[5].replace(/{$/, "") : "", this);
this.fragment(f[9]);
this.query = new Query(f[7] ? f[7] : "", this);
if (t)
this.query.setUrlTemplateQuery(t[1]);
return this;
}
/**
* @param {string} f - port part of URL
* @return {instance} - returns Uri instance for chaining
*/
port(f) {
return this.gs(f, "_port");
}
/**
* @param {string} f - protocol part of URL
* @return {instance} - returns Uri instance for chaining
*/
protocol(f) {
return (this._scheme || "").toLowerCase();
}
/**
* @param {string} f - protocol scheme
* @return {instance} - returns Uri instance for chaining
*/
scheme(f) {
return this.gs(f, "_scheme");
}
/**
* @param {string} f - user info part of URL
* @return {instance} - returns Uri instance for chaining
*/
userInfo(f) {
return this.gs(f, "_userinfo", (r) => {
return r ? encodeURI(r) : r;
});
}
/**
* @return {string} - returns string URL
*/
toString() {
let q2 = this.query.toString();
let p = this.path.toString();
let f = this.fragment();
let s = this.scheme();
let str = new x();
let retStr = str.append(s ? s + "://" : "").append(this.authority()).append("/").append(p).append(q2 !== "" ? "?" : "").append(q2).toString().replace("/?", "?").replace(/\/$/, "");
return retStr;
}
static clone(uri) {
return new _TinyUri(uri.toString());
}
};