Skip to content

Instantly share code, notes, and snippets.

@arvidkahl
Created August 23, 2020 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save arvidkahl/1e2d7120ba5f0a3a035ffe29aa1a6c8e to your computer and use it in GitHub Desktop.
Save arvidkahl/1e2d7120ba5f0a3a035ffe29aa1a6c8e to your computer and use it in GitHub Desktop.
Zero to Published: Automator Workflow to correctly titleize with APA rules ("this is a good title" -> "This Is a Good Title")
const stopwords = 'a an and at but by for in nor of on or so the to up yet'
const defaults = stopwords.split(' ')
function titleCase1(str, options) {
const opts = options || {}
if (!str) return ''
const stop = opts.stopwords || defaults
const keep = opts.keepSpaces
const splitter = /(\s+|[-‑–—])/
return str.split(splitter).map((word, index, all) => {
if (word.match(/\s+/)) return keep ? word : ' '
if (word.match(splitter)) return word
if (
index !== 0 &&
index !== all.length - 1 &&
stop.includes(word.toLowerCase())
) {
return word.toLowerCase()
}
return capitalize(word)
})
.join('')
}
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1)
}
const alwaysLowercase = [
'a',
'an',
'and',
'at',
'but',
'by',
'for',
'in',
'nor',
'of',
'on',
'or',
'so',
'the',
'to',
'up',
'yet',
'v',
'v.',
'vs',
'vs.'
];
const containers = ['(', '[', '{', '"', `'`, '_'];
function isUrl(url) {
return false;
}
function capitalize(string) {
if (string.length === 0) {
return string;
}
const letters = [...string];
const firstLetter = letters.shift();
if (containers.indexOf(firstLetter) !== -1) {
return `${firstLetter}${capitalize(letters)}`;
}
return `${firstLetter.toUpperCase()}${letters.join('')}`;
}
function titleCase(string = '', { excludedWords = [], useDefaultExcludedWords = true } = {}) {
if (string.toUpperCase() === string) {
string = string.toLowerCase();
}
if (useDefaultExcludedWords) {
excludedWords.push(...alwaysLowercase);
}
const words = string.trim().split(/\s+/);
const capitalizedWords = words.map((word, index, array) => {
const isFirstWird = index === 0;
const isLastWord = index === words.length - 1;
const isEmail = /.+@.+\..+/.test(word);
const isFilePath = /^(\/[\w.]+)+/.test(word);
const isFileName = /^\w+\.\w{1,3}$/.test(word);
const hasInternalCapital = /(?![-‑–—])[a-z]+[A-Z].*/.test(word);
const previousWord = index > 1 ? array[index - 1] : '';
const startOfSubPhrase = index > 1 && [...previousWord].pop() === ':';
if (isEmail || isUrl(word) || isFilePath || isFileName || hasInternalCapital) {
return word;
}
const hasHyphen = word.match(/[-‑–—]/g);
if (hasHyphen) {
const isMultiPart = hasHyphen.length > 1;
const [hyphenCharacter] = hasHyphen;
return word.split(hyphenCharacter).map((subWord) => {
if (isMultiPart && excludedWords.indexOf(subWord.toLowerCase()) !== -1) {
return subWord;
}
return capitalize(subWord);
}).join(hyphenCharacter);
}
if (word.indexOf('/') !== -1) {
return word.split('/').map(capitalize).join('/');
}
if (isFirstWird || isLastWord) {
return capitalize(word);
}
if (!startOfSubPhrase && excludedWords.indexOf(word.toLowerCase()) !== -1) {
return word.toLowerCase();
}
return capitalize(word);
});
return capitalizedWords.join(' ');
}
function run(input, parameters) {
if (input.length == 0) return;
input = titleCase(input[0])
return input;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment