@oxog/string
Version:
Comprehensive string manipulation utilities with zero dependencies
138 lines (137 loc) • 4.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.reverse = reverse;
exports.shuffle = shuffle;
exports.repeat = repeat;
exports.truncate = truncate;
exports.pad = pad;
exports.wrap = wrap;
exports.slugify = slugify;
const unicode_1 = require("../utils/unicode");
const unicode_2 = require("../utils/unicode");
function reverse(str) {
return (0, unicode_1.reverseUnicode)(str);
}
function shuffle(str) {
const chars = (0, unicode_1.getGraphemes)(str);
for (let i = chars.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[chars[i], chars[j]] = [chars[j], chars[i]];
}
return chars.join('');
}
function repeat(str, count, separator = '') {
if (count < 0) {
throw new Error('Count must be non-negative');
}
if (count === 0)
return '';
if (count === 1)
return str;
const parts = [];
for (let i = 0; i < count; i++) {
parts.push(str);
}
return parts.join(separator);
}
function truncate(str, length, options = {}) {
const { suffix = '...', preserveWords = false } = options;
if (str.length <= length)
return str;
if (preserveWords) {
const words = str.split(/\s+/);
let result = '';
for (const word of words) {
const potential = result ? `${result} ${word}` : word;
if (potential.length + suffix.length > length) {
break;
}
result = potential;
}
return result ? result + suffix : str.slice(0, Math.max(0, length - suffix.length)) + suffix;
}
return str.slice(0, Math.max(0, length - suffix.length)) + suffix;
}
function pad(str, length, fillString = ' ', type = 'end') {
if (str.length >= length)
return str;
const padLength = length - str.length;
const fill = fillString.repeat(Math.ceil(padLength / fillString.length)).slice(0, padLength);
switch (type) {
case 'start':
return fill + str;
case 'end':
return str + fill;
case 'both':
const leftPadLength = Math.floor(padLength / 2);
const rightPadLength = padLength - leftPadLength;
const leftFill = fillString.repeat(Math.ceil(leftPadLength / fillString.length)).slice(0, leftPadLength);
const rightFill = fillString.repeat(Math.ceil(rightPadLength / fillString.length)).slice(0, rightPadLength);
return leftFill + str + rightFill;
default:
return str + fill;
}
}
function wrap(str, width, options = {}) {
const { indent = '', cut = false } = options;
if (width <= 0)
return str;
const words = str.split(/\s+/);
const lines = [];
let currentLine = '';
for (const word of words) {
const potential = currentLine ? `${currentLine} ${word}` : word;
const potentialWidth = (0, unicode_1.getStringWidth)(potential);
if (potentialWidth <= width) {
currentLine = potential;
}
else {
if (currentLine) {
lines.push(indent + currentLine);
currentLine = word;
}
else {
// Word is longer than width
if (cut) {
const chars = (0, unicode_1.getGraphemes)(word);
let chunk = '';
for (const char of chars) {
const chunkWidth = (0, unicode_1.getStringWidth)(chunk + char);
if (chunkWidth > width && chunk) {
lines.push(indent + chunk);
chunk = char;
}
else {
chunk += char;
}
}
if (chunk) {
currentLine = chunk;
}
}
else {
currentLine = word;
}
}
}
}
if (currentLine) {
lines.push(indent + currentLine);
}
return lines.join('\n');
}
function slugify(str, options = {}) {
const { separator = '-', lowercase = true, strict = false, locale } = options;
let result = (0, unicode_2.removeAccents)(str);
if (lowercase) {
result = locale ? result.toLocaleLowerCase(locale) : result.toLowerCase();
}
if (strict) {
result = result.replace(/[^a-zA-Z0-9]+/g, separator);
}
else {
result = result.replace(/[^\w\s-]/g, '').replace(/[\s_-]+/g, separator);
}
result = result.replace(new RegExp(`^\\${separator}+|\\${separator}+$`, 'g'), '');
return result;
}