@nauverse/make-url
Advanced tools
Comparing version 1.5.0 to 1.6.0
@@ -1,84 +0,104 @@ | ||
const d = { | ||
const R = { | ||
forceProtocol: "auto", | ||
trailingSlash: "add", | ||
strict: !1, | ||
allowEmptyPathSegments: !1 | ||
}, f = { | ||
allowEmptyPathSegments: !1, | ||
arraySerializer: "repeat" | ||
}, u = { | ||
queryParams: {}, | ||
hashParam: "", | ||
config: d | ||
config: R | ||
}; | ||
let l = { | ||
...f.config | ||
let p = { | ||
...u.config | ||
}; | ||
function p() { | ||
return l; | ||
function S() { | ||
return p; | ||
} | ||
function P(s) { | ||
l = { | ||
...f.config, | ||
...s | ||
function U(a) { | ||
p = { | ||
...u.config, | ||
...a | ||
}; | ||
} | ||
function U(...s) { | ||
if (s.length === 0 || s.length > 0 && typeof s[0] != "string") | ||
function A(...a) { | ||
if (a.length === 0 || a.length > 0 && typeof a[0] != "string") | ||
throw new Error("makeURL must receive at least one string item"); | ||
let i = { config: {} }; | ||
const g = []; | ||
s.forEach((t, o) => { | ||
let c = { config: {} }; | ||
const d = []; | ||
a.forEach((t, e) => { | ||
if (typeof t == "string") | ||
g.push(t); | ||
d.push(t); | ||
else { | ||
if (o !== s.length - 1) | ||
if (e !== a.length - 1) | ||
throw new Error( | ||
"Params config object argument must be the last argument" | ||
); | ||
i = t; | ||
c = t; | ||
} | ||
}); | ||
const n = { | ||
...f, | ||
...i, | ||
const i = { | ||
...u, | ||
...c, | ||
config: { | ||
...l, | ||
...i == null ? void 0 : i.config | ||
...p, | ||
...c == null ? void 0 : c.config | ||
} | ||
}, c = g.map((t) => t.replace(/\s+/g, "-").replace(/[^a-zA-Z0-9-._~:/?#\[\]@!$&'()*+,;=]/g, (o) => encodeURIComponent(o))); | ||
if (!c[0].includes("://") && n.config.forceProtocol !== "none") | ||
if (n.config.forceProtocol === "auto" || n.config.forceProtocol === "auto-insecure") { | ||
const t = n.config.forceProtocol === "auto"; | ||
}; | ||
let l = !1; | ||
const s = d.map((t, e) => { | ||
let o = "", n = t.trim(); | ||
return e === 0 && (n.startsWith("http://") ? (o = "http://", n = n.slice(7)) : n.startsWith("https://") ? (o = "https://", n = n.slice(8)) : n.startsWith("//") && n.includes(".") && (o = "//", n = n.slice(2), l = !0)), `${o}${n.split("/").map((h) => encodeURIComponent(h).replace(/%3A/g, ":")).join("/")}`; | ||
}); | ||
if (!s[0].includes("://") && !l && i.config.forceProtocol !== "none") | ||
if (i.config.forceProtocol === "auto" || i.config.forceProtocol === "auto-insecure") { | ||
const t = i.config.forceProtocol === "auto"; | ||
try { | ||
c[0].includes(".") && (new URL("https://" + c[0]), c[0] = `${t ? "https" : "http"}://${c[0]}`); | ||
s[0].includes(".") && (new URL("https://" + s[0]), s[0] = `${t ? "https" : "http"}://${s[0]}`); | ||
} catch { | ||
} | ||
} else | ||
c[0] = `${n.config.forceProtocol}://${c[0]}`; | ||
let e = c.join("/"); | ||
n.config.trailingSlash === "add" && !e.endsWith("/") && (e += "/"), n.config.trailingSlash === "remove" && e.endsWith("/") && (e = e.slice(0, -1)), n.config.allowEmptyPathSegments || (e = e.replace(new RegExp("(?<!:)\\/{2,}", "g"), "/")); | ||
const a = {}; | ||
Object.entries(n.queryParams).forEach(([t, o]) => { | ||
let r = ""; | ||
typeof o == "string" ? r = o : typeof o == "number" ? r = o.toString() : typeof o == "object" ? r = JSON.stringify(o) : r = `${o}`, r = encodeURIComponent(r), a[t] = r; | ||
}), Object.entries(a).forEach(([t, o]) => { | ||
let r = !1; | ||
const u = new RegExp(`:${t}`, "g"); | ||
e = e.replace(u, () => (r = !0, o)), r && delete a[t]; | ||
s[0] = `${i.config.forceProtocol}://${s[0]}`; | ||
let r = s.join("/"); | ||
if (i.config.trailingSlash === "add" && !r.endsWith("/") && (r += "/"), i.config.trailingSlash === "remove" && r.endsWith("/") && (r = r.slice(0, -1)), !i.config.allowEmptyPathSegments) { | ||
let t = ""; | ||
l && (t = "//", r = r.slice(2)), r = `${t}${r.replace(new RegExp("(?<!:)\\/{2,}", "g"), "/")}`; | ||
} | ||
const g = {}; | ||
Object.entries(i.queryParams).forEach(([t, e]) => { | ||
let o = "", n = !1; | ||
typeof e == "string" ? o = e : typeof e == "number" ? o = e.toString() : Array.isArray(e) ? (n = !0, i.config.arraySerializer === "stringify" ? o = JSON.stringify(e) : i.config.arraySerializer === "repeat" ? o = e : o = e.join(",")) : typeof e == "object" ? o = JSON.stringify(e) : o = `${e}`, g[t] = { | ||
value: o, | ||
isArray: n | ||
}; | ||
}); | ||
const h = new URLSearchParams(a).toString(); | ||
h && (e += `?${h}`); | ||
const m = n.hashParam.trim(); | ||
if (m !== "" && (e += `#${encodeURIComponent(m)}`), n.config.strict) | ||
const f = new URLSearchParams(); | ||
Object.entries(g).forEach(([t, e]) => { | ||
if (e.isArray) { | ||
Array.isArray(e.value) ? e.value.forEach((P) => { | ||
f.append(t, P); | ||
}) : f.append(t, e.value); | ||
return; | ||
} | ||
let o = !1; | ||
const n = new RegExp(`:${t}`, "g"), h = encodeURIComponent(e.value); | ||
r = r.replace(n, () => (o = !0, h)), o ? delete g[t] : f.append(t, e.value); | ||
}); | ||
const m = f.toString(); | ||
m && (r += `?${m}`); | ||
const y = i.hashParam.trim(); | ||
if (y !== "" && (r += `#${encodeURIComponent(y)}`), i.config.strict) | ||
try { | ||
if (!new URL(e).host.includes(".")) | ||
if (!new URL(r).host.includes(".")) | ||
throw null; | ||
} catch { | ||
throw new Error(`The generated URL is not valid: ${e}`); | ||
throw new Error(`The generated URL is not valid: ${r}`); | ||
} | ||
return e; | ||
return r; | ||
} | ||
export { | ||
d as BASE_DEFAULT_MAKE_URL_CONFIG, | ||
p as getMakeURLDefaultConfig, | ||
U as makeURL, | ||
P as setMakeURLDefaultConfig | ||
R as BASE_DEFAULT_MAKE_URL_CONFIG, | ||
S as getMakeURLDefaultConfig, | ||
A as makeURL, | ||
U as setMakeURLDefaultConfig | ||
}; |
@@ -6,2 +6,3 @@ export interface IConfig { | ||
allowEmptyPathSegments: boolean; | ||
arraySerializer: "stringify" | "repeat" | "comma"; | ||
} | ||
@@ -8,0 +9,0 @@ export interface IParams<T> { |
@@ -22,5 +22,10 @@ { | ||
"url-builder", | ||
"query-string" | ||
"query-string", | ||
"uri", | ||
"build", | ||
"concat", | ||
"concatenate", | ||
"urlcat" | ||
], | ||
"version": "1.5.0", | ||
"version": "1.6.0", | ||
"type": "module", | ||
@@ -27,0 +32,0 @@ "main": "./dist/make-url.umd.cjs", |
160
README.md
@@ -73,7 +73,6 @@ <h1 align="center"> | ||
<center> | ||
<table> | ||
<thead> | ||
<tr> | ||
<th align="center"><strong>v1</strong></th> | ||
<th><strong>v1</strong></th> | ||
</tr> | ||
@@ -83,16 +82,48 @@ </thead> | ||
<tr> | ||
<td align="center">Latest version</td> | ||
<td>0️⃣ Zero dependencies</td> | ||
</tr> | ||
<tr> | ||
<td align="center">No dependencies</td> | ||
<td>👌 1kB <a href="https://bundlephobia.com/package/@nauverse/make-url@latest">minified and gzipped</a></td> | ||
</tr> | ||
<tr> | ||
<td align="center">1kB <a href="https://bundlephobia.com/package/@nauverse/make-url@latest">minified and gzipped</a></td> | ||
<td>✍️ TypeScript types provided</td> | ||
</tr> | ||
<tr> | ||
<td align="center" colspan="2">TypeScript types provided</td> | ||
<td>🛟 Safe escaping everywhere</td> | ||
</tr> | ||
<tr> | ||
<td>🧠 Smart concatenating</td> | ||
</tr> | ||
<tr> | ||
<td>❓ Support for query parameters (add them in any format and they will be safely escaped and added)</td> | ||
</tr> | ||
<tr> | ||
<td>#️⃣ Support for hash parameter</td> | ||
</tr> | ||
<tr> | ||
<td>🤓 Smart trailing slash handling (and fully configurable)</td> | ||
</tr> | ||
<tr> | ||
<td>🌍 Global default config option (if you use always the same settings, you can make it constant, instead of having to specify them on each function call)</td> | ||
</tr> | ||
<tr> | ||
<td>🔗 URL type detection (if it is a full URL, a relative URL, an absolute URL...)</td> | ||
</tr> | ||
<tr> | ||
<td>🚔 Protocol enforcing settings (plus a smart mode so it handles it for you)</td> | ||
</tr> | ||
<tr> | ||
<td>🎛️ Enable or disable removing extra slashes (so it supports RFC 3986)</td> | ||
</tr> | ||
<tr> | ||
<td>📋 Query parameters support arrays, with three modes: stringify, repeat key and comma-separated</td> | ||
</tr> | ||
<tr> | ||
<td>🧘 It also supports the relative protocol (`//example.com/my-page`)</td> | ||
</tr> | ||
<tr> | ||
<td>✅ Production ready</td> | ||
</tr> | ||
</tbody> | ||
</table> | ||
</center> | ||
@@ -157,18 +188,2 @@ ## Why? | ||
So, what does this library offer? | ||
- Escaping all parameters | ||
- Concatenating all parts (there will always be exactly one <kbd>/</kbd> and <kbd>?</kbd> character between them) | ||
- Support for query parameters (you can pass any value as a query parameter key and it will be added as a valid query parameter to the URL) | ||
- Support for hash parameters | ||
- Support for URL parameters (with the `:<query key>` template in the URL) | ||
- Fully type-safe | ||
- Trailing slash handling (you can choose if always add or remove it) | ||
- Global default config option (if you use always the same settings, you can make it constant, instead of having to specify them on each function call) | ||
- URL type detection (if it is a full URL, a relative URL, an absolute URL...) | ||
- Protocol enforcing | ||
- Enable or disable removing extra slashes | ||
- Production-ready | ||
- Zero dependencies | ||
## How? | ||
@@ -289,2 +304,64 @@ | ||
### `arraySerializer` | ||
> By default, it is set to `repeat` | ||
Arrays are a special kind of data, specially when sending them as query parameters to the server. There are many ways to handle them and we try to support all of them. | ||
The default mode used is `repeat` but you can change it in any function call you need it or globally by using the `setMakeURLDefaultConfig` function. | ||
There are three possible values: `repeat`, `comma` and `stringify`. Each of them specify how to handle the arrays. Let's see some examples: | ||
#### makeURL with `arraySerializer: 'repeat'` | ||
~~~ts | ||
makeURL("https://example.com", "/test", { | ||
queryParams: { | ||
arr: ['a', 'b', 'c'] | ||
}, | ||
config: { | ||
arraySerializer: 'repeat' | ||
} | ||
}); | ||
// https://example.com/test?arr=a&arr=b&arr=c | ||
~~~ | ||
#### makeURL with `arraySerializer: 'stringify'` | ||
~~~ts | ||
makeURL("https://example.com", "/test", { | ||
queryParams: { | ||
arr: ['a', 'b', 'c'] | ||
}, | ||
config: { | ||
arraySerializer: 'repeat' | ||
} | ||
}); | ||
// https://example.com/test?arr=%5B%22a%22%2C%22b%22%2C%22c%22%5D | ||
~~~ | ||
#### makeURL with `arraySerializer: 'comma'` | ||
~~~ts | ||
makeURL("https://example.com", "/test", { | ||
queryParams: { | ||
arr: ['a', 'b', 'c'] | ||
}, | ||
config: { | ||
arraySerializer: 'comma' | ||
} | ||
}); | ||
// https://example.com/test?arr=a%2Cb%2Cc | ||
~~~ | ||
> Important: Arrays are not supported for URL variables (no matter the `mode` you use), so they won't be replaced there but added as a query parameter. See one example below: | ||
#### makeURL with `arraySerializer: 'comma'` with array as URL variable | ||
~~~ts | ||
makeURL("https://example.com", "/test/:arr", { | ||
queryParams: { | ||
arr: ['a', 'b', 'c'] | ||
}, | ||
config: { | ||
arraySerializer: 'comma' | ||
} | ||
}); | ||
// https://example.com/test/:arr?arr=a%2Cb%2Cc <- Notice that we can not replace arrays in URL variables | ||
~~~ | ||
### `trailingSlash` | ||
@@ -706,2 +783,39 @@ > By default, it is set to `add` | ||
--- | ||
### About the relative protocol | ||
Sometimes you might want to build URLs that use the relative protocol (`//`) so you obtain URLs like `//example.com/my/path?test=1`. | ||
Luckily, this module supports building them, just keep in mind these URLs, like the relative and the absolute ones; are <b>not compatible</b> with `strict: true`. | ||
If you have `strict: false`, you can do use them. Here you have some examples: | ||
#### makeURL with `strict: false` and a relative protocol URL | ||
~~~ts | ||
makeURL("//example.com", "test/a", { | ||
config: { | ||
strict: false | ||
} | ||
}); | ||
// //example.com/test/a | ||
~~~ | ||
#### makeURL with `strict: false` and a relative protocol URL but an invalid domain | ||
~~~ts | ||
makeURL("//example", "test/a", { | ||
config: { | ||
strict: false | ||
} | ||
}); | ||
// /example/test/a <- It is transformed to an absolute URL | ||
~~~ | ||
#### makeURL with `strict: true` and a relative protocol URL | ||
~~~ts | ||
makeURL("//example.com", "test/a", { | ||
config: { | ||
strict: true | ||
} | ||
}); | ||
// Throws an error | ||
~~~ | ||
--- | ||
### Full examples | ||
@@ -708,0 +822,0 @@ To finish with this "guide", I want to provide some examples combining several of the explained settings: |
Sorry, the diff of this file is not supported yet
37949
173
926