UNPKG

@guanghechen/helper-string

Version:
206 lines (201 loc) 6.51 kB
'use strict'; const SPLIT_LOWER_UPPER_RE = /([\p{Ll}\d])(\p{Lu})/gu; const SPLIT_UPPER_UPPER_RE = /(\p{Lu})([\p{Lu}][\p{Ll}])/gu; const SPLIT_NUMBER_LOWER_RE = /(\d)(\p{Ll})/gu; const SPLIT_LETTER_NUMBER_RE = /(\p{L})(\d)/gu; const DEFAULT_STRIP_REGEXP = /[^\p{L}\d]+/giu; const SPLIT_REPLACE_VALUE = '$1\0$2'; function split(input, options = {}) { let result = input .replace(SPLIT_LOWER_UPPER_RE, SPLIT_REPLACE_VALUE) .replace(SPLIT_UPPER_UPPER_RE, SPLIT_REPLACE_VALUE); if (options.separateNumbers) { result = result .replace(SPLIT_NUMBER_LOWER_RE, SPLIT_REPLACE_VALUE) .replace(SPLIT_LETTER_NUMBER_RE, SPLIT_REPLACE_VALUE); } result = result.replace(DEFAULT_STRIP_REGEXP, '\0'); let start = 0; let end = result.length; while (result.charAt(start) === '\0') start += 1; if (start === end) return []; while (result.charAt(end - 1) === '\0') end -= 1; return result.slice(start, end).split(/\0/g); } function camelCase(input, options) { const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); const transform = pascalCaseTransformFactory(lower, upper); return split(input, options) .map((word, index) => { if (index === 0) return lower(word); return transform(word, index); }) .join(''); } function pascalCase(input, options) { const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); return split(input, options).map(pascalCaseTransformFactory(lower, upper)).join(''); } function capitalCase(input, options) { const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); return split(input, options).map(capitalCaseTransformFactory(lower, upper)).join(' '); } function constantCase(input, options) { const upper = upperFactory(options?.locale); return split(input, options).map(upper).join('_'); } function dotCase(input, options) { const lower = lowerFactory(options?.locale); return split(input, options).map(lower).join('.'); } function kebabCase(input, options) { const lower = lowerFactory(options?.locale); return split(input, options).map(lower).join('-'); } function pathCase(input, options) { const lower = lowerFactory(options?.locale); return split(input, options).map(lower).join('/'); } function sentenceCase(input, options) { const lower = lowerFactory(options?.locale); const upper = upperFactory(options?.locale); const transform = capitalCaseTransformFactory(lower, upper); return split(input, options) .map((word, index) => { if (index === 0) return transform(word, index); return lower(word); }) .join(' '); } function snakeCase(input, options) { const lower = lowerFactory(options?.locale); return split(input, options).map(lower).join('_'); } function lowerFactory(locale) { return locale === false ? (input) => input.toLowerCase() : (input) => input.toLocaleLowerCase(locale); } function upperFactory(locale) { return locale === false ? (input) => input.toUpperCase() : (input) => input.toLocaleUpperCase(locale); } const capitalCaseTransformFactory = (lower, upper) => { return (word) => `${upper(word[0])}${lower(word.slice(1))}`; }; const pascalCaseTransformFactory = (lower, upper) => { return (word, index) => { const char0 = word[0]; const initial = index > 0 && char0 >= '0' && char0 <= '9' ? '_' + char0 : upper(char0); return initial + lower(word.slice(1)); }; }; const TOKENS = /\S+|./g; const IS_MANUAL_CASE = /\p{Ll}(?=[\p{Lu}])|\.\p{L}/u; const ALPHANUMERIC_PATTERN = /[\p{L}\d]+/gu; const WORD_SEPARATORS = new Set(['—', '–', '-', '―', '/']); const SMALL_WORDS = new Set([ 'an', 'and', 'as', 'at', 'because', 'but', 'by', 'en', 'for', 'if', 'in', 'neither', 'nor', 'of', 'on', 'or', 'only', 'over', 'per', 'so', 'some', 'that', 'than', 'the', 'to', 'up', 'upon', 'v', 'vs', 'versus', 'via', 'when', 'with', 'without', 'yet', ]); function titleCase(input, options = {}) { let result = ''; let m; const { smallWords = SMALL_WORDS, locale } = typeof options === 'string' || Array.isArray(options) ? { locale: options } : options; while ((m = TOKENS.exec(input)) !== null) { const { 0: token, index } = m; if (IS_MANUAL_CASE.test(token)) { result += token; } else { result += token.replace(ALPHANUMERIC_PATTERN, (m, i) => { if (index > 0 && index + token.length < input.length && smallWords.has(m)) { return m; } if (i > 1 && !WORD_SEPARATORS.has(input.charAt(index + i - 1))) { return m; } return m.charAt(0).toLocaleUpperCase(locale) + m.slice(1); }); } } return result; } function composeTextTransformers(...transformers) { return text => { let result = text; for (const transformer of transformers) { result = transformer(result); } return result; }; } const toCamelCase = text => camelCase(text); const toCapitalCase = text => capitalCase(text); const toConstantCase = text => constantCase(text); const toDotCase = text => dotCase(text); const toKebabCase = text => kebabCase(text); const toLowerCase = text => text.toLocaleLowerCase(); const toPascalCase = text => pascalCase(text); const toPathCase = text => pathCase(text); const toSentenceCase = text => sentenceCase(text); const toSnakeCase = text => snakeCase(text); const toTitleCase = text => titleCase(text); const toTrim = text => text.trim(); const toUpperCase = text => text.toLocaleUpperCase(); exports.composeTextTransformers = composeTextTransformers; exports.toCamelCase = toCamelCase; exports.toCapitalCase = toCapitalCase; exports.toConstantCase = toConstantCase; exports.toDotCase = toDotCase; exports.toKebabCase = toKebabCase; exports.toLowerCase = toLowerCase; exports.toPascalCase = toPascalCase; exports.toPathCase = toPathCase; exports.toSentenceCase = toSentenceCase; exports.toSnakeCase = toSnakeCase; exports.toTitleCase = toTitleCase; exports.toTrim = toTrim; exports.toUpperCase = toUpperCase;