Files
CHOMPStation2/tgui/packages/common/string.js
2022-06-25 21:57:53 +00:00

197 lines
4.5 KiB
JavaScript

/**
* @file
* @copyright 2020 Aleksej Komarov
* @license MIT
*/
/**
* Removes excess whitespace and indentation from the string.
*/
export const multiline = (str) => {
if (Array.isArray(str)) {
// Small stub to allow usage as a template tag
return multiline(str.join(''));
}
const lines = str.split('\n');
// Determine base indentation
let minIndent;
for (let line of lines) {
for (let indent = 0; indent < line.length; indent++) {
const char = line[indent];
if (char !== ' ') {
if (minIndent === undefined || indent < minIndent) {
minIndent = indent;
}
break;
}
}
}
if (!minIndent) {
minIndent = 0;
}
// Remove this base indentation and trim the resulting string
// from both ends.
return lines
.map((line) => line.substr(minIndent).trimRight())
.join('\n')
.trim();
};
/**
* Creates a glob pattern matcher.
*
* Matches strings with wildcards.
*
* Example: createGlobPattern('*@domain')('user@domain') === true
*/
export const createGlobPattern = (pattern) => {
const escapeString = (str) => str.replace(/[|\\{}()[\]^$+*?.]/g, '\\$&');
const regex = new RegExp(
'^' +
pattern
.split(/\*+/)
.map(escapeString)
.join('.*') +
'$'
);
return (str) => regex.test(str);
};
/**
* Creates a search terms matcher.
*
* Returns true if given string matches the search text.
*
* @template T
* @param {string} searchText
* @param {(obj: T) => string} stringifier
* @returns {(obj: T) => boolean}
*/
export const createSearch = (searchText, stringifier) => {
const preparedSearchText = searchText.toLowerCase().trim();
return (obj) => {
if (!preparedSearchText) {
return true;
}
const str = stringifier ? stringifier(obj) : obj;
if (!str) {
return false;
}
return str.toLowerCase().includes(preparedSearchText);
};
};
export const isUppercase = (chr) => {
return chr.toUpperCase() === chr;
};
export const capitalize = (str) => {
// Handle array
if (Array.isArray(str)) {
return str.map(capitalize);
}
// Handle string
let chr = str.charAt(0);
if (isUppercase(chr)) {
return str; // Already caps, might be an acronym, so don't mess it up by lowercasing the rest
}
return chr.toUpperCase() + str.slice(1).toLowerCase();
};
export const toTitleCase = (str) => {
// Handle array
if (Array.isArray(str)) {
return str.map(toTitleCase);
}
// Pass non-string
if (typeof str !== 'string') {
return str;
}
// Handle string
const WORDS_UPPER = ['Id', 'Tv', 'Rcd']; // VOREStation Edit
const WORDS_LOWER = [
'A',
'An',
'And',
'As',
'At',
'But',
'By',
'For',
'For',
'From',
'In',
'Into',
'Near',
'Nor',
'Of',
'On',
'Onto',
'Or',
'The',
'To',
'With',
];
let currentStr = str.replace(/([^\W_]+[^\s-]*) */g, (str) => {
return str.charAt(0).toUpperCase() + str.substr(1).toLowerCase();
});
for (let word of WORDS_LOWER) {
const regex = new RegExp('\\s' + word + '\\s', 'g');
currentStr = currentStr.replace(regex, (str) => str.toLowerCase());
}
for (let word of WORDS_UPPER) {
const regex = new RegExp('\\b' + word + '\\b', 'g');
currentStr = currentStr.replace(regex, (str) => str.toUpperCase());
}
return currentStr;
};
/**
* Decodes HTML entities, and removes unnecessary HTML tags.
*
* @param {String} str Encoded HTML string
* @return {String} Decoded HTML string
*/
export const decodeHtmlEntities = (str) => {
if (!str) {
return str;
}
const translate_re = /&(nbsp|amp|deg|quot|lt|gt|apos|trade);/g;
const translate = {
nbsp: ' ',
amp: '&',
deg: '°',
quot: '"',
lt: '<',
gt: '>',
apos: "'",
trade: '™',
};
return (
str
// Newline tags
.replace(/<br>/gi, '\n')
.replace(/<\/?[a-z0-9-_]+[^>]*>/gi, '')
// Basic entities
.replace(translate_re, (match, entity) => translate[entity])
// Decimal entities
.replace(/&#?([0-9]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 10);
return String.fromCharCode(num);
})
// Hex entities
.replace(/&#x?([0-9a-f]+);/gi, (match, numStr) => {
const num = parseInt(numStr, 16);
return String.fromCharCode(num);
})
);
};
/**
* Converts an object into a query string,
*/
export const buildQueryString = (obj) =>
Object.keys(obj)
.map((key) => encodeURIComponent(key) + '=' + encodeURIComponent(obj[key]))
.join('&');