167 lines
3.9 KiB
TypeScript
167 lines
3.9 KiB
TypeScript
function lowerToPascalCase(str: string) {
|
||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase()).replaceAll(
|
||
" ",
|
||
"",
|
||
);
|
||
}
|
||
function lowerToTrainCase(str: string) {
|
||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase()).replaceAll(
|
||
" ",
|
||
"-",
|
||
);
|
||
}
|
||
|
||
/**
|
||
* @param str
|
||
* @returns camelCased string (single letter words are lower cased, e.g. SSN -> ssn)
|
||
*/
|
||
function lowerToCamelCase(str: string): string {
|
||
const words = str.trim().split(/\s+/);
|
||
const result: string[] = [];
|
||
let i = 0;
|
||
|
||
while (i < words.length) {
|
||
if (words[i].length === 1) {
|
||
// We’ve hit the start of a chain of single-letter words
|
||
let j = i;
|
||
while (j < words.length && words[j].length === 1) {
|
||
j++;
|
||
}
|
||
const chainIsAtStart = i === 0;
|
||
// Process that entire chain
|
||
for (let k = i; k < j; k++) {
|
||
result[k] = chainIsAtStart
|
||
? words[k].toLowerCase()
|
||
: words[k].toUpperCase();
|
||
}
|
||
i = j;
|
||
} else {
|
||
// Normal multi-letter word
|
||
if (i === 0) {
|
||
// first word: all lower
|
||
result[i] = words[i].toLowerCase();
|
||
} else {
|
||
// subsequent words: capitalize first letter
|
||
result[i] = words[i][0].toUpperCase() +
|
||
words[i].slice(1).toLowerCase();
|
||
}
|
||
i++;
|
||
}
|
||
}
|
||
|
||
return result.join("");
|
||
}
|
||
|
||
function lowerToSnakeCase(str: string) {
|
||
return str.replace(" ", "_");
|
||
}
|
||
|
||
function lowerToKebabCase(str: string) {
|
||
return str.replace(" ", "-");
|
||
}
|
||
|
||
function lowerToMacroCase(str: string) {
|
||
return str.replace(/\w\S*/g, (match) => match.toUpperCase()).replaceAll(
|
||
" ",
|
||
"_",
|
||
);
|
||
}
|
||
|
||
function lowerToTitleCase(str: string) {
|
||
return str.replace(/(?:^|\s)\w/g, (match) => match.toUpperCase());
|
||
}
|
||
|
||
type CaseType =
|
||
| "pascal"
|
||
| "camel"
|
||
| "snake"
|
||
| "kebab"
|
||
| "macro"
|
||
| "upper"
|
||
| "lower"
|
||
| "train"
|
||
| "title"
|
||
| "";
|
||
|
||
function parseCase(str: string) {
|
||
const isCaseMap = new Map<CaseType, (str: string) => boolean>([
|
||
["pascal", (str: string) => {
|
||
return /^[A-Z][a-zA-Z]*$/.test(str);
|
||
}],
|
||
["camel", (str: string) => {
|
||
return /^[a-z][a-zA-Z]*$/.test(str);
|
||
}],
|
||
["snake", (str: string) => {
|
||
return /^[a-z][a-z0-9_]*$/.test(str);
|
||
}],
|
||
["kebab", (str: string) => {
|
||
return /^[a-z][a-z0-9-]*$/.test(str);
|
||
}],
|
||
["macro", (str: string) => {
|
||
return /^[A-Z]*$/.test(str);
|
||
}],
|
||
["upper", (str: string) => {
|
||
return /^[A-Z]*$/.test(str);
|
||
}],
|
||
["lower", (str: string) => {
|
||
return /^[a-z]*$/.test(str);
|
||
}],
|
||
["train", (str: string) => {
|
||
return /([A-Z][a-z]*(?:-|$))+/.test(str);
|
||
}],
|
||
]);
|
||
for (const [key, value] of isCaseMap) {
|
||
if (value(str)) return key;
|
||
}
|
||
return "";
|
||
}
|
||
|
||
function coerceCaseToLower(str: string, caseType: CaseType) {
|
||
switch (caseType) {
|
||
case "pascal":
|
||
case "camel":
|
||
return str.replace(/[A-Z]/g, (match) => " " + match.toLowerCase().trim());
|
||
case "macro":
|
||
case "snake":
|
||
case "upper":
|
||
return str.replaceAll("_", " ").toLowerCase();
|
||
case "train":
|
||
case "kebab":
|
||
return str.replaceAll("-", " ").toLowerCase();
|
||
default:
|
||
return str.toLowerCase();
|
||
}
|
||
}
|
||
|
||
export function toCase(str: string, toCase: CaseType) {
|
||
const caseType = parseCase(str) || "";
|
||
if (caseType === toCase) return str;
|
||
const lowerStr = coerceCaseToLower(str, caseType);
|
||
switch (toCase) {
|
||
case "pascal":
|
||
return lowerToPascalCase(lowerStr);
|
||
case "camel":
|
||
return lowerToCamelCase(lowerStr);
|
||
case "snake":
|
||
return lowerToSnakeCase(lowerStr);
|
||
case "kebab":
|
||
return lowerToKebabCase(lowerStr);
|
||
case "macro":
|
||
return lowerToMacroCase(lowerStr);
|
||
case "upper":
|
||
return lowerStr.toUpperCase();
|
||
case "lower":
|
||
return lowerStr.toLowerCase();
|
||
case "train":
|
||
return lowerToTrainCase(lowerStr);
|
||
case "title":
|
||
return lowerToTitleCase(lowerStr);
|
||
default:
|
||
return str;
|
||
}
|
||
}
|
||
|
||
if (import.meta.main) {
|
||
console.log(toCase("SSN", "camel"));
|
||
}
|