//#region String
/**
* Compares two strings using the Jaro-Winkler Distance algorithm.
* @memberOf string
* @function
* @example
* _$.jaroDistance('test', 'tes');//0.9416666666666667
* @returns {Number} A number representing how similar the two strings are, where 1 is exactly the same and 0 is totally different
* @param {String} a The first string
* @param {String} b The second string
*/
export let jaroDistance = function (a, b) {
let adjustments = {
A: "E",
A: "I",
A: "O",
A: "U",
B: "V",
E: "I",
E: "O",
E: "U",
I: "O",
I: "U",
O: "U",
I: "Y",
E: "Y",
C: "G",
E: "F",
W: "U",
W: "V",
X: "K",
S: "Z",
X: "S",
Q: "C",
U: "V",
M: "N",
L: "I",
Q: "O",
P: "R",
I: "J",
2: "Z",
5: "S",
8: "B",
1: "I",
1: "L",
0: "O",
0: "Q",
C: "K",
G: "J",
E: " ",
Y: " ",
S: " ",
};
if (!a || !b) {
return 0.0;
}
a = a.trim().toUpperCase();
b = b.trim().toUpperCase();
var a_len = a.length;
var b_len = b.length;
var a_flag = [];
var b_flag = [];
var search_range = Math.floor(Math.max(a_len, b_len) / 2) - 1;
var minv = Math.min(a_len, b_len);
var Num_com = 0;
var yl1 = b_len - 1;
for (var i = 0; i < a_len; i++) {
var lowlim = i >= search_range ? i - search_range : 0;
var hilim = i + search_range <= yl1 ? i + search_range : yl1;
for (var j = lowlim; j <= hilim; j++) {
if (b_flag[j] !== 1 && a[j] === b[i]) {
a_flag[j] = 1;
b_flag[i] = 1;
Num_com++;
break;
}
}
}
if (Num_com === 0) {
return 0.0;
}
var k = 0;
var N_trans = 0;
for (var i = 0; i < a_len; i++) {
if (a_flag[i] === 1) {
var j;
for (j = k; j < b_len; j++) {
if (b_flag[j] === 1) {
k = j + 1;
break;
}
}
if (a[i] !== b[j]) {
N_trans++;
}
}
}
N_trans = Math.floor(N_trans / 2);
var N_simi = 0;
var adjwt = adjustments;
if (minv > Num_com) {
for (var i = 0; i < a_len; i++) {
if (!a_flag[i]) {
for (var j = 0; j < b_len; j++) {
if (!b_flag[j]) {
if (adjwt[a[i]] === b[j]) {
N_simi += 3;
b_flag[j] = 2;
break;
}
}
}
}
}
}
var Num_sim = N_simi / 10.0 + Num_com;
var weight =
Num_sim / a_len + Num_sim / b_len + (Num_com - N_trans) / Num_com;
weight = weight / 3;
if (weight > 0.7) {
var j = minv >= 4 ? 4 : minv;
var i;
for (i = 0; i < j && a[i] === b[i]; i++) {}
if (i) {
weight += i * 0.1 * (1.0 - weight);
}
if (minv > 4 && Num_com > i + 1 && 2 * Num_com >= minv + i) {
weight +=
(1 - weight) *
((Num_com - i - 1) / (a_len * b_len - i * 2 + 2));
}
}
return weight;
};
/**
* Prefixes the given CSS property for the current browser.
* @memberOf string
* @function
* @example
* document.body.style[_$.prefix("appearance")] = "hidden";//Sets the document body's appearance property to "hidden".
* @param {String} prop The property to prefix.
* @returns {String} The prefixed value (camelCased, instead of css-case, so mozAppearance instead of -moz-appearance).
*/
export let prefixCSS = (prop = req("string", "property")) => {
node();
const capitalizedProp =
prop.charAt(0).toUpperCase() + prop.slice(1);
const prefixes = ["", "webkit", "moz", "ms", "o"];
const i = prefixes.findIndex(
(prefix) =>
typeof document.body.style[
prefix ? prefix + capitalizedProp : prop
] !== "undefined",
);
return i !== -1
? i === 0
? prop
: prefixes[i] + capitalizedProp
: null;
};
/**
* Parses a cookie string into object and value pairs.
* @memberOf string
* @function
* @example
* _$.parseCookie("foo=bar; something=hello%20world");//Returns {foo: "bar", something: "hello world"};
* @param {String} str The string to parse.
*/
export let parseCookie = (str = req("string", "cookie string")) =>
str
.split(";")
.map((v) => v.split("="))
.reduce((acc, v) => {
acc[decodeURIComponent(v[0].trim())] = decodeURIComponent(
v[1].trim(),
);
return acc;
}, {});
/**
* Hashes a string using the crypto api.
* @memberOf string
* @function
* @example
* _$.hash(
JSON.stringify({ a: 'a', b: [1, 2, 3, 4], foo: { c: 'bar' } })
).then(console.log);
// '04aa106279f5977f59f9067fa9712afc4aedc6f5862a8defc34552d8c7206393'
* @param {String} val The string to hash
* @returns {Promise} A promise that resolves into the hashed string.
*/
export let hash = (val = req("string", "input string")) => {
node();
return crypto.subtle
.digest("SHA-256", new TextEncoder("utf-8").encode(val))
.then((h) => {
let hexes = [],
view = new DataView(h);
for (let i = 0; i < view.byteLength; i += 4)
hexes.push(
("00000000" + view.getUint32(i).toString(16)).slice(-8),
);
return hexes.join("");
});
};
/**
* @callback mapCallback
* @param {any} item The item
* @param {Number} i The index of the item
* @param {Array} arr The original array
*/
/**
* Lets you use a for loop in template literals.
* @function
* @memberOf string
* @param {Array} arr The array to loop.
* @param {mapCallback} callback The callback to return strings
* @example
* console.log(`Things: ${_$.forTemplateLiteral(["apple", "orange"], (item, i) => {return `an ${item}`})}`)
* // "Things: an apple an orange
* @returns {String} String that has been for looped
*/
export let forTemplateLiteral = (
arr = req("array", "array"),
callback = req("function", "callback"),
) => {
return arr.map(callback).join``;
};
/**
* Maps a string like an array.
* @memberOf string
* @function
* @example
* _$.mapString("Hello world", (e) => e.toUpperCase());//Returns "HELLO WORLD"
* @param {String} str The string to map
* @param {mapCallback} fn The callback function to run to map the string.
*/
export let mapString = (
str = req("string", "string"),
fn = req("function", "callback"),
) => Array.prototype.map.call(str, fn).join("");
/**
* Removes the accents from a string.
* @memberOf string
* @function
* @returns {String} The string without accents.
* @example
* console.log(_$.decurr("déjà vu")); // "deja vu"
* @param {String} str The string to use.
*/
export let deburr = (str = req("string", "string")) =>
str.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
/**
* Removes tags from the HTML string specified.
* @function
* @memberOf string
* @param {String} html The string of HTML to remove tags from.
* @example
* console.log(_$.removeTags("<div>Hello</div>")); // "Hello"
* @returns {String} THe string of HTML without the tags.
*/
export let removeTags = (html = req("string", "html string")) =>
html.replace(/<[^>]*>/g, "");
/**
* Speaks the text given.
* @memberOf string
* @function
* @param {String} text The text to split
* @param {String} [lang=en-US] The language to speak with.
* @param {Number} [volume=1] The volume
* @param {String|Number} [voice=1] The voice to use.
* @param {Number} [pitch=1] The pitch
* @param {Number} [volume=1] The volume
* @param {Number} [rate=1] The speed.
* @example
* _$.speak("Bijou is awesome!"); // speaks "Bijou is awesome!"
* @returns {SpeechSynthesisUtterance} The SpeechSynthesisUtterance
*/
export let speak = (
text = req("string", "text"),
lang = "en",
volume = 1,
voice = 1,
pitch = 1,
rate = 1,
) => {
var msg = new SpeechSynthesisUtterance();
var voices = window.speechSynthesis.getVoices();
let def = voices.filter((c) => c.default);
msg.voice = voice
? typeof voice === "number"
? voices[voice]
: voice
: def;
msg.volume = volume; // From 0 to 1
msg.rate = rate; // From 0.1 to 10
msg.pitch = pitch; // From 0 to 2
msg.text = text;
msg.lang = lang;
window.speechSynthesis.speak(msg);
return msg;
};
/**
* Returns the last space in the string given replaced with " "
* @function
* @memberOf string
* @param {String} text The string to replace
* @example
* document.querySelector("h1").innerHTML = _$.widows(document.querySelector("h1").innerHTML);
* //Replaces the last space in the <h1>'s innerText with " "
* @returns {String} The replaced string.
*/
export let widows = (text = req("string", "text")) => {
var wordArray = text.split(" ");
var finalTitle = "";
for (var i = 0; i <= wordArray.length - 1; i++) {
finalTitle += wordArray[i];
if (i == wordArray.length - 2) {
finalTitle += " ";
} else {
finalTitle += " ";
}
}
return finalTitle;
};
/**
* Undoes camelCase.
* @function
* @memberOf string
* @param {String} str The string to unCamelCase.
* @example
* console.log(_$.unCamelCase("helloWorld")); // "Hello World"
* @returns {String} The string of unCamelCased code.
*/
export let unCamelCase = function (str = req("string", "string")) {
return str
.replace(/([a-z])([A-Z])/g, "$1 $2")
.replace(/\b([A-Z]+)([A-Z])([a-z])/, "$1 $2$3")
.replace(/^./, function (s) {
return s.toUpperCase();
});
};
/**
* camelCases a string.
* @function
* @memberOf string
* @param {String} str The string of non-camelCased text.
* @example
* console.log(_$.camelCase("Hello world")); // "helloWorld"
* @returns {String} The camelCased string.
*/
export let camelCase = (str = req("string", "string")) => {
return str
.replace(/(?:^\w|[A-Z]|\b\w)/g, function (word, index) {
return index === 0 ? word.toLowerCase() : word.toUpperCase();
})
.replace(/\s+/g, "");
};
/**
* Scrambles the order of characters in a string. Thanks to @\Touchcreator for the suggestion for this.
* @function
* @memberOf string
* @param {String} str The string to be scrambled
* @example
* console.log(_$.scrambleString("Hello world")); // e.g. "owllH rdloe"
* @returns {String} The scrambled text.
*/
export let scrambleString = (str = req("string")) => {
var a = str.split(""),
n = a.length;
for (var i = n - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var tmp = a[i];
a[i] = a[j];
a[j] = tmp;
}
return a.join("");
};
/**
* Hashes a string to a unique integer (This cannot be decrypted easily).
* @function
* @memberOf string
* @param {String} str The String to hash.
* @param {Number} [seed=0] The seed of the hash.
* @example
* console.log(_$.hashString("Hello world")); // 3494146707865688
* @returns {Number} The hashed string.
*/
export let hashString = (str = req("string"), seed = 0) => {
let h1 = 0xdeadbeef ^ seed,
h2 = 0x41c6ce57 ^ seed;
for (let i = 0, ch; i < str.length; i++) {
ch = str.charCodeAt(i);
h1 = Math.imul(h1 ^ ch, 2654435761);
h2 = Math.imul(h2 ^ ch, 1597334677);
}
h1 =
Math.imul(h1 ^ (h1 >>> 16), 2246822507) ^
Math.imul(h2 ^ (h2 >>> 13), 3266489909);
h2 =
Math.imul(h2 ^ (h2 >>> 16), 2246822507) ^
Math.imul(h1 ^ (h1 >>> 13), 3266489909);
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
};
/**
* Gets the edit distance between two strings.
* @function
* @memberOf string
* @param {String} a The first string
* @param {String} b The seconds string
* @example
* console.log(_$.editDistance("hello", "Hello")); // 1
* @returns {Number} The edit distance between two strings
*/
export let editDistance = (
a = req("string", "string 1"),
b = req("string", "string 2"),
) => {
if (a.length == 0) return b.length;
if (b.length == 0) return a.length;
var matrix = [];
// increment along the first column of each row
var i;
for (i = 0; i <= b.length; i++) {
matrix[i] = [i];
}
// increment each column in the first row
var j;
for (j = 0; j <= a.length; j++) {
matrix[0][j] = j;
}
// Fill in the rest of the matrix
for (i = 1; i <= b.length; i++) {
for (j = 1; j <= a.length; j++) {
if (b.charAt(i - 1) == a.charAt(j - 1)) {
matrix[i][j] = matrix[i - 1][j - 1];
} else {
matrix[i][j] = Math.min(
matrix[i - 1][j - 1] + 1, // substitution
Math.min(
matrix[i][j - 1] + 1, // insertion
matrix[i - 1][j] + 1,
),
); // deletion
}
}
}
return matrix[b.length][a.length];
};
/**
* Returns the size of a string in bytes.
* @function
* @memberOf string
* @param {String} str
* @example
* console.log(_$.byteSize("Hello world")); 11
* @returns {Number} The byte size of the string.
*/
export let byteSize = (str = req("string", "string")) =>
new Blob([str]).size;
/**
* Finds and replace multiple values with multiple other values.
* @function
* @memberOf string
* @param {String} text The text to operate the replace on.
* @param {Object} replace The object with find and replace values.
* @example
* _$.replaceMultiple("I have a cat, a dog, and a goat.", {dog: "cat", goat: "dog", cat: "goat"});//Returns "I have a goat, a cat and a dog"
* @returns {String} The replaced string
*/
export let replaceMultiple = (
text = req("string", "text"),
replacer = req("object", "replace key pairs"),
) => {
var re = new RegExp(Object.keys(replacer).join("|"), "gi");
text = text.replace(re, function (matched) {
return replacer[matched];
});
return text;
};
/**
* Returns the queries from a given url (Or just the current url)
* @function
* @memberOf string
* @param {String} query The url query to get.
* @param {String} [url=window.location.href] The url to find the query in. (By default this is the current url)
* @example
* // If the website adress of the current page was "https://example.com/?q=hello&hello=world"
* console.log(_$.urlQuery("hello")); // "world"
* // Or on a custom url:
* console.log(_$.urlQuery("q", "https://google.com/search?q=something")); // "something"
* @returns {String} The url query
*/
export let urlQuery = (
query = req("string", "query"),
url = window.location.href,
) => {
query = query.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp(`[?&]${query}(=([^&#]*)|&|#|$)`),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return "";
return decodeURIComponent(results[2].replace(/\+/g, " "));
};
/**
* Sanitizes an HTML string. It is quite possible that this is not production ready so use with caution. (I did my best though >=( )
* @function
* @memberOf string
* @param {String} html The input string to sanitize.
* @param {Array} [tags=undefined] The array of tags to allow, there is a default list though.
* @param {Array} [attributes=undefined] The array of attributes to allow. By default only allows "href" and "src" attributes.
* @example
* console.log(_$.sanitizeHTML("<script>alert('hello')></script><b>A normal tag</b>")); // "<b>A normal tag</b>"
* @returns {String} The sanitized HTML string.
*/
export let sanitize = (
html = req("string", "input html"),
tags = undefined,
attributes = undefined,
) => {
node();
var attributes = attributes || [
{ attribute: "src", tags: "*", regex: /^(?:https|http|\/\/):/ },
{ attribute: "href", tags: "*", regex: /^(?:https|http|\/\/):/ },
{ attribute: "width", tags: "*", regex: /^[0-9]+$/ },
{ attribute: "height", tags: "*", regex: /^[0-9]+$/ },
{ attribute: "id", tags: "*", regex: /^[a-zA-Z]+$/ },
{ attribute: "class", tags: "*", regex: /^[a-zA-Z ]+$/ },
{
attribute: "value",
tags: ["INPUT", "TEXTAREA"],
regex: /^.+$/,
},
{
attribute: "checked",
tags: ["INPUT"],
regex: /^(?:true|false)+$/,
},
{
attribute: "placeholder",
tags: ["INPUT", "TEXTAREA"],
regex: /^.+$/,
},
{
attribute: "alt",
tags: ["IMG", "AREA", "INPUT"],
//"^" and "$" match beggining and end
regex: /^[0-9a-zA-Z]+$/,
},
{
attribute: "autofocus",
tags: ["INPUT"],
regex: /^(?:true|false)+$/,
},
{
attribute: "for",
tags: ["LABEL", "OUTPUT"],
regex: /^[a-zA-Z0-9]+$/,
},
];
var tags = tags || [
"I",
"P",
"B",
"BODY",
"HTML",
"DEL",
"INS",
"STRONG",
"SMALL",
"A",
"IMG",
"CITE",
"FIGCAPTION",
"ASIDE",
"ARTICLE",
"SUMMARY",
"DETAILS",
"NAV",
"TD",
"TH",
"TABLE",
"THEAD",
"TBODY",
"NAV",
"SPAN",
"BR",
"CODE",
"PRE",
"BLOCKQUOTE",
"EM",
"HR",
"H1",
"H2",
"H3",
"H4",
"H5",
"H6",
"DIV",
"MAIN",
"HEADER",
"FOOTER",
"SELECT",
"COL",
"AREA",
"ADDRESS",
"ABBR",
"BDI",
"BDO",
];
attributes = attributes.map((el) => {
if (typeof el === "string") {
return { attribute: el, tags: "*", regex: /^.+$/ };
}
let output = el;
if (!el.hasOwnProperty("tags")) {
output.tags = "*";
}
if (!el.hasOwnProperty("regex")) {
output.regex = /^.+$/;
}
return output;
});
var el = new DOMParser().parseFromString(html, "text/html");
var elements = el.querySelectorAll("*");
for (let i = 0; i < elements.length; i++) {
const current = elements[i];
let attr_list = get_attributes(current);
for (let j = 0; j < attr_list.length; j++) {
const attribute = attr_list[j];
if (!attribute_matches(current, attribute)) {
current.removeAttribute(attr_list[j]);
}
}
if (!tags.includes(current.tagName)) {
current.remove();
}
}
return el.documentElement.innerHTML;
function attribute_matches(element, attribute) {
let output = attributes.filter((attr) => {
let returnval =
attr.attribute === attribute &&
(attr.tags === "*" || attr.tags.includes(element.tagName)) &&
attr.regex.test(element.getAttribute(attribute));
return returnval;
});
return output.length > 0;
}
function get_attributes(element) {
for (
var i = 0, atts = element.attributes, n = atts.length, arr = [];
i < n;
i++
) {
arr.push(atts[i].nodeName);
}
return arr;
}
};
/**
* Converts markdown to HTML.
* @param {String} src The markdown to convert to HTML.
* @memberOf string
* @function
* @example
* console.log(_$.markdownToHTML("_Italic text_, **bold text**")); // "<em>Italic text</em>, <b>bold text</b>"
* @returns {String} The string of HTML converted from the markdown input.
*/
export let markdownToHTML = (src = req("string", "input")) => {
var rx_lt = /</g;
var rx_gt = />/g;
var rx_space = /\t|\r|\uf8ff/g;
var rx_escape = /\\([\\\|`*_{}\[\]()#+\-~])/g;
var rx_hr = /^([*\-=_] *){3,}$/gm;
var rx_blockquote = /\n *> *([^]*?)(?=(\n|$){2})/g;
var rx_list =
/\n( *)(?:[*\-+]|((\d+)|([a-z])|[A-Z])[.)]) +([^]*?)(?=(\n|$){2})/g;
var rx_listjoin = /<\/(ol|ul)>\n\n<\1>/g;
var rx_highlight =
/(^|[^A-Za-z\d\\])(([*_])|(~)|(\^)|(--)|(\+\+)|`)(\2?)([^<]*?)\2\8(?!\2)(?=\W|_|$)/g;
var rx_code = /\n((```|~~~).*\n?([^]*?)\n?\2|(( {4}.*?\n)+))/g;
var rx_link =
/((!?)\[(.*?)\]\((.*?)( ".*")?\)|\\([\\`*_{}\[\]()#+\-.!~]))/g;
var rx_table = /\n(( *\|.*?\| *\n)+)/g;
var rx_thead = /^.*\n( *\|( *\:?-+\:?-+\:? *\|)* *\n|)/;
var rx_row = /.*\n/g;
var rx_cell = /\||(.*?[^\\])\|/g;
var rx_heading =
/(?=^|>|\n)([>\s]*?)(#{1,6}) (.*?)( #*)? *(?=\n|$)/g;
var rx_para = /(?=^|>|\n)\s*\n+([^<]+?)\n+\s*(?=\n|<|$)/g;
var rx_stash = /-\d+\uf8ff/g;
function replace(rex, fn) {
src = src.replace(rex, fn);
}
function element(tag, content) {
return "<" + tag + ">" + content + "</" + tag + ">";
}
function blockquote(src) {
return src.replace(rx_blockquote, function (all, content) {
return element(
"blockquote",
blockquote(highlight(content.replace(/^ *> */gm, ""))),
);
});
}
function list(src) {
return src.replace(
rx_list,
function (all, ind, ol, num, low, content) {
var entry = element(
"li",
highlight(
content
.split(
RegExp(
"\n ?" +
ind +
"(?:(?:\\d+|[a-zA-Z])[.)]|[*\\-+]) +",
"g",
),
)
.map(list)
.join("</li><li>"),
),
);
return (
"\n" +
(ol
? '<ol start="' +
(num
? ol + '">'
: parseInt(ol, 36) -
9 +
'" style="list-style-type:' +
(low ? "low" : "upp") +
'er-alpha">') +
entry +
"</ol>"
: element("ul", entry))
);
},
);
}
function highlight(src) {
return src.replace(
rx_highlight,
function (all, _, p1, emp, sub, sup, small, big, p2, content) {
return (
_ +
element(
emp
? p2
? "strong"
: "em"
: sub
? p2
? "s"
: "sub"
: sup
? "sup"
: small
? "small"
: big
? "big"
: "code",
highlight(content),
)
);
},
);
}
function unesc(str) {
return str.replace(rx_escape, "$1");
}
var stash = [];
var si = 0;
src = "\n" + src + "\n";
replace(rx_lt, "<");
replace(rx_gt, ">");
replace(rx_space, " ");
// blockquote
src = blockquote(src);
// horizontal rule
replace(rx_hr, "<hr/>");
// list
src = list(src);
replace(rx_listjoin, "");
// code
replace(rx_code, function (all, p1, p2, p3, p4) {
stash[--si] = element(
"pre",
element("code", p3 || p4.replace(/^ {4}/gm, "")),
);
return si + "\uf8ff";
});
// link or image
replace(rx_link, function (all, p1, p2, p3, p4, p5, p6) {
stash[--si] = p6
? p6
: p2
? p4
? '<img src="' +
_$.escapeHTML(p4) +
'" alt="' +
_$.escapeHTML(p3) +
'"/>'
: p1
: /^https?:\/\//g.test(p4)
? '<a href="' +
_$.escapeHTML(p4) +
'">' +
unesc(highlight(p3)) +
"</a>"
: p1;
return si + "\uf8ff";
});
// table
replace(rx_table, function (all, table) {
var sep = table.match(rx_thead)[1];
return (
"\n" +
element(
"table",
table.replace(rx_row, function (row, ri) {
return row == sep
? ""
: element(
"tr",
row.replace(rx_cell, function (all, cell, ci) {
return ci
? element(
sep && !ri ? "th" : "td",
unesc(highlight(cell || "")),
)
: "";
}),
);
}),
)
);
});
// heading
replace(rx_heading, function (all, _, p1, p2) {
return _ + element("h" + p1.length, unesc(highlight(p2)));
});
// paragraph
replace(rx_para, function (all, content) {
return element("p", unesc(highlight(content)));
});
// stash
replace(rx_stash, function (all) {
return stash[parseInt(all)];
});
return src.trim();
};
/**
* Counts the syllables in the word given.
* @memberOf string
* @function
* @param {String} word The word to count syllables of
* @example
* console.log(_$.syllables("Hello")); // 2
* @returns {Number} The number of syllables in the specified word.
*/
export let syllables = (word = req("string", "word")) => {
word = word.toLowerCase();
var t_some = 0;
if (word.length > 3) {
if (word.substring(0, 4) == "some") {
word = word.replace("some", "");
t_some++;
}
}
word = word.replace(/(?:[^laeiouy]|ed|[^laeiouy]e)$/, "");
word = word.replace(/^y/, "");
var syl = word.match(/[aeiouy]{1,2}/g);
console.log(syl);
if (syl) {
return syl.length + t_some;
}
};
/**
* Converts a string to title case
* @memberOf string
* @function
* @param {String} str The string to convert to title case.
* @example
* _$.titleCase("hello world");//Returns "Hello World"
* @returns {String} The string in title case.
*/
export let titleCase = (str = req("string", "string")) =>
str
.toLowerCase()
.split(" ")
.map((word, index) =>
[
"at",
"by",
"for",
"in",
"of",
"off",
"on",
"out",
"to",
"up",
"as",
"if",
"but",
"per",
"via",
"for",
"and",
"nor",
"but",
"or",
"yet",
"so",
"the",
"a",
"an",
].includes(word) && index != 0
? word
: String.fromCodePoint(word.codePointAt(0)).toUpperCase() +
word.slice(word.codePointAt(0) > 0xffff ? 2 : 1),
)
.join(" ");
/**
* Capitalizes the first letter of the string
* @memberOf string
* @function
* @param {String} str The string to capitalize.
* @example
* console.log(_$.capitalize("hello world")); // "Hello world"
* @returns {String} The capitalized string.
*/
export let capitalize = (str = req("string", "string")) =>
String.fromCodePoint(str.codePointAt(0)).toUpperCase() +
str.slice(str.codePointAt(0) > 0xffff ? 2 : 1);
/**
* Replaces between two indexes of a string.
* @memberOf string
* @function
* @example
* console.log(_$.replaceBetween("Hello world", 6, 11, "earthlings")); // "Hello earthlings"
* @param {String} string The string to operate on.
* @param {Number} start The start index
* @param {Number} end The end index
* @param {String} what What to replace with.
* @returns {String} The replaced string
*/
export let replaceBetween = (
string = req("string", "string"),
start = req("number", "start"),
end = req("number", "end"),
what = req("string", "replace with"),
) => string.substring(0, start) + what + string.substring(end);
/**
* Escapes a string of HTML
* @function
* @memberOf string
* @param {String} str The string of HTML to escape.
* @example
* console.log(_$.escapeHTML("<div>")); // "<div>"
* @returns {String} The escaped HTML.
*/
export let escapeHTML = (str = req("string")) =>
str.replace(
/[&<>'"]/g,
(tag) =>
({
"&": "&",
"<": "<",
">": ">",
"'": "'",
'"': """,
}[tag] || tag),
);
/**
* Unescapes a string of HTML
* @function
* @memberOf string
* @param {String} str The string of HTML to unescape.
* @example
* console.log(_$.unescapeHTML("<div>")); // "<div>"
* @returns {String} The unescaped HTML.
*/
export let unescapeHTML = (str = req("string")) =>
str.replace(
/&|<|>|'|"/g,
(tag) =>
({
"&": "&",
"<": "<",
">": ">",
"'": "'",
""": '"',
}[tag] || tag),
);
/**
* Returns the previous page that the user visited.
* @function
* @memberOf string
* @example
* console.log(_$.previousPage()); // e.g. "https://bijou.js.org"
* @returns {String} The url of the previous page the user visited.
*/
export let previousPage = () => {
node();
return document.referrer || window.location.href;
};
/**
* Processes a markdown list by extracting the content of each list item and returning
* an array of objects with the content and its index in the list.
*
* @memberOf string
* @function
* @param {string} list - the list to be processed
* @returns {Array} - An array of objects with the content and its index in the list
* @example
*
* const list = '- Item 1\n- Item 2\n- Item 3';
* const processedList = processList(list);
*
* // Returns:
* // [
* // { content: 'Item 1', idx: 0 },
* // { content: 'Item 2', idx: 1 },
* // { content: 'Item 3', idx: 2 }
* // ]
*
*/
export let processList = (list) => {
const list_re =
/\n(?:-|(?:[0-9]+|[a-zA-Z])\.?)\s*(?<content>[^\n]+)/gi;
return list
.match(new RegExp(list_re, "gi"))
.map((i, idx) => ({ ...i.match(list_re).groups, idx }));
};
//#endregion String
Source