Pig Latin

by Peter Hozák

HTML

<div id="app"></div>

CSS

body {
  background: transparent;
  color: #eee;
}

table {
  border-collapse: collapse;
  margin: auto;
}

td {
  border-bottom: 1px solid #666;
  padding: 5px;
  white-space: pre;
}

.pass {
  background: #060;
}

.fail {
  background: #600;
}

JavaScript

// Translate to "pig latin" with rules requested via email.
// simple usage: pigLatin('string')
// TODO: document advanced usage
function pigLatin(
  str,
  {
    validate = validateDefault,
    tokenize = tokenizeDefault,
    endsWithWay = endsWithWayDefault,
    beginsWithVowel = beginsWithVowelDefault,
    beginsWithConsonant = beginsWithConsonantDefault,
    featuresPreservingTool = featuresPreservingToolDefault,
  } = {}
) {
  const {error} = validate(str)
  if (error) {
    throw new Error(error)
  }
  const tokens = tokenize(str)
  const {extractFeatures, applyFeatures} = featuresPreservingTool()
  
  const modifiedTokens = tokens.map((token, index) => {
    if (index % 2) {
      // every even token is a word, odd token is a separator
      return token
    }
    
    // convert token to simplified string that can be modified (e.g. lowercase without punctuation) + features object
    const {simplified, features} = extractFeatures(token)
    let modified = simplified
    if (!endsWithWay(simplified)) {
      if (beginsWithVowel(simplified)) {
        modified = `${simplified}way`
      } else if (beginsWithConsonant(simplified)) {
        modified = `${simplified.substr(1)}${simplified.substr(0, 1)}ay`
      }
    }
    // apply features back (e.g. uppercase and punctuation on correct positions)
    return applyFeatures({modified, features})
  })
  
  return modifiedTokens.join('')
}


function validateDefault(str) {
  const split = str.split(/([^a-z'’.\s\-])/i)
  if (split.length === 1) {
    return {error: null}
  }
  return {error: `Unsupported character (${split[1]}) in '${split[0]}-->${split[1]}<--${split.splice(2).join('')}'}`}
}

function tokenizeDefault(str) {
  // every second token (odd array index) should be a word-separator
  return str.split(/([\s\-])/)
}

function endsWithWayDefault(str) {
  return str.match(/way$/i)
}

// simple implementation to detect start with a vowel or consonant by the 1st letter
// ignoring more complex fonetic rules...