whole_func_string: function affix(aff) {
    var rules = {}
    var replacementTable = []
    var conversion = {in: [], out: []}
    var compoundRuleCodes = {}
    var lines = []
    var flags = {}
    var compoundRules = []
    var index
    var length
    var parts
    var line
    var ruleType
    var entries
    var count
    var remove
    var add
    var source
    var entry
    var ruleLength
    var position
    var rule
    var last
    var value
    var offset
    var character
  
    flags[keyType] = []
  
    // Process the affix buffer into a list of applicable lines.
    aff = aff.toString('utf8')
    index = aff.indexOf(linefeed)
    last = 0
  
    while (index !== -1) {
      pushLine(aff.slice(last, index))
      last = index + 1
      index = aff.indexOf(linefeed, last)
    }
  
    pushLine(aff.slice(last))
  
    // Process each line.
    index = -1
    length = lines.length
  
    while (++index < length) {
      line = lines[index]
      parts = line.split(whiteSpaceExpression)
      ruleType = parts[0]
  
      if (ruleType === replaceType) {
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
          replacementTable.push([parts[1], parts[2]])
        }
  
        index = count
      } else if (ruleType === iconvType || ruleType === oconvType) {
        entry = conversion[ruleType === iconvType ? 'in' : 'out']
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
  
          entry.push([new RegExp(parts[1], 'g'), parts[2]])
        }
  
        index = count
      } else if (ruleType === compoundRuleType) {
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          rule = lines[index].split(whiteSpaceExpression)[1]
          ruleLength = rule.length
          position = -1
  
          compoundRules.push(rule)
  
          while (++position < ruleLength) {
            compoundRuleCodes[rule.charAt(position)] = []
          }
        }
  
        index = count
      } else if (ruleType === prefixType || ruleType === suffixType) {
        count = index + parseInt(parts[3], 10)
        entries = []
  
        rule = {
          type: ruleType,
          combineable: parts[2] === combineable,
          entries: entries
        }
  
        rules[parts[1]] = rule
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
          remove = parts[2]
          add = parts[3].split(slash)
          source = parts[4]
  
          entry = {
            add: '',
            remove: '',
            match: '',
            continuation: parse(flags, add[1])
          }
  
          if (add && add[0] !== digit0) {
            entry.add = add[0]
          }
  
          try {
            if (remove !== digit0) {
              entry.remove = ruleType === suffixType ? end(remove) : remove
            }
  
            if (source && source !== dot) {
              entry.match = (ruleType === suffixType ? end : start)(source)
            }
          } catch (error) {
            // Ignore invalid regex patterns.
            entry = null
          }
  
          if (entry) {
            entries.push(entry)
          }
        }
  
        index = count
      } else if (ruleType === tryType) {
        source = parts[1]
        count = source.length
        offset = -1
        value = []
  
        while (++offset < count) {
          character = source.charAt(offset)
  
          if (character.toLowerCase() === character) {
            value.push(character)
          }
        }
  
        // Some dictionaries may forget a character.  Notably the enUS forgets
        // the `j`, `x`, and `y`.
        offset = -1
        count = alphabet.length
  
        while (++offset < count) {
          character = alphabet[offset]
  
          if (source.indexOf(character) === -1) {
            value.push(character)
          }
        }
  
        flags[ruleType] = value
      } else if (ruleType === keyType) {
        flags[ruleType] = flags[ruleType].concat(parts[1].split('|'))
      } else if (ruleType === compoundInType) {
        flags[ruleType] = Number(parts[1])
      } else if (ruleType === onlyInCompoundType) {
        // If we add this ONLYINCOMPOUND flag to `compoundRuleCodes`, then
        // `parseDic` will do the work of saving the list of words that are
        // compound-only.
        flags[ruleType] = parts[1]
        compoundRuleCodes[parts[1]] = []
      } else if (
        ruleType === keepCaseFlag ||
        ruleType === wordCharsType ||
        ruleType === flagType ||
        ruleType === noSuggestType
      ) {
        flags[ruleType] = parts[1]
      } else {
        // Default handling.  Set them for now.
        flags[ruleType] = parts[1]
      }
    }
  
    // Default for `COMPOUNDMIN` is `3`.  See man 4 hunspell.
    if (isNaN(flags[compoundInType])) {
      flags[compoundInType] = defaultCompoundInType
    }
  
    if (flags[keyType].length === 0) {
      flags[keyType] = defaultKeyboardLayout
    }
  
    /* istanbul ignore if - Dictionaries seem to always have this. */
    if (!flags[tryType]) {
      flags[tryType] = alphabet.concat()
    }
  
    if (!flags[keepCaseFlag]) {
      flags[keepCaseFlag] = false
    }
  
    return {
      compoundRuleCodes: compoundRuleCodes,
      replacementTable: replacementTable,
      conversion: conversion,
      compoundRules: compoundRules,
      rules: rules,
      flags: flags
    }
  
    function pushLine(line) {
      line = trim(line)
  
      // Hash can be a valid flag, so we only discard line that starts with it.
      if (line && line.charCodeAt(0) !== numberSign) {
        lines.push(line)
      }
    }
  }
func_code_string: function affix(aff) {
    var rules = {}
    var replacementTable = []
    var conversion = {in: [], out: []}
    var compoundRuleCodes = {}
    var lines = []
    var flags = {}
    var compoundRules = []
    var index
    var length
    var parts
    var line
    var ruleType
    var entries
    var count
    var remove
    var add
    var source
    var entry
    var ruleLength
    var position
    var rule
    var last
    var value
    var offset
    var character
  
    flags[keyType] = []
  
    // Process the affix buffer into a list of applicable lines.
    aff = aff.toString('utf8')
    index = aff.indexOf(linefeed)
    last = 0
  
    while (index !== -1) {
      pushLine(aff.slice(last, index))
      last = index + 1
      index = aff.indexOf(linefeed, last)
    }
  
    pushLine(aff.slice(last))
  
    // Process each line.
    index = -1
    length = lines.length
  
    while (++index < length) {
      line = lines[index]
      parts = line.split(whiteSpaceExpression)
      ruleType = parts[0]
  
      if (ruleType === replaceType) {
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
          replacementTable.push([parts[1], parts[2]])
        }
  
        index = count
      } else if (ruleType === iconvType || ruleType === oconvType) {
        entry = conversion[ruleType === iconvType ? 'in' : 'out']
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
  
          entry.push([new RegExp(parts[1], 'g'), parts[2]])
        }
  
        index = count
      } else if (ruleType === compoundRuleType) {
        count = index + parseInt(parts[1], 10)
  
        while (++index <= count) {
          rule = lines[index].split(whiteSpaceExpression)[1]
          ruleLength = rule.length
          position = -1
  
          compoundRules.push(rule)
  
          while (++position < ruleLength) {
            compoundRuleCodes[rule.charAt(position)] = []
          }
        }
  
        index = count
      } else if (ruleType === prefixType || ruleType === suffixType) {
        count = index + parseInt(parts[3], 10)
        entries = []
  
        rule = {
          type: ruleType,
          combineable: parts[2] === combineable,
          entries: entries
        }
  
        rules[parts[1]] = rule
  
        while (++index <= count) {
          parts = lines[index].split(whiteSpaceExpression)
          remove = parts[2]
          add = parts[3].split(slash)
          source = parts[4]
  
          entry = {
            add: '',
            remove: '',
            match: '',
            continuation: parse(flags, add[1])
          }
  
          if (add && add[0] !== digit0) {
            entry.add = add[0]
          }
  
          try {
            if (remove !== digit0) {
              entry.remove = ruleType === suffixType ? end(remove) : remove
            }
  
            if (source && source !== dot) {
              entry.match = (ruleType === suffixType ? end : start)(source)
            }
          } catch (error) {
            // Ignore invalid regex patterns.
            entry = null
          }
  
          if (entry) {
            entries.push(entry)
          }
        }
  
        index = count
      } else if (ruleType === tryType) {
        source = parts[1]
        count = source.length
        offset = -1
        value = []
  
        while (++offset < count) {
          character = source.charAt(offset)
  
          if (character.toLowerCase() === character) {
            value.push(character)
          }
        }
  
        // Some dictionaries may forget a character.  Notably the enUS forgets
        // the `j`, `x`, and `y`.
        offset = -1
        count = alphabet.length
  
        while (++offset < count) {
          character = alphabet[offset]
  
          if (source.indexOf(character) === -1) {
            value.push(character)
          }
        }
  
        flags[ruleType] = value
      } else if (ruleType === keyType) {
        flags[ruleType] = flags[ruleType].concat(parts[1].split('|'))
      } else if (ruleType === compoundInType) {
        flags[ruleType] = Number(parts[1])
      } else if (ruleType === onlyInCompoundType) {
        // If we add this ONLYINCOMPOUND flag to `compoundRuleCodes`, then
        // `parseDic` will do the work of saving the list of words that are
        // compound-only.
        flags[ruleType] = parts[1]
        compoundRuleCodes[parts[1]] = []
      } else if (
        ruleType === keepCaseFlag ||
        ruleType === wordCharsType ||
        ruleType === flagType ||
        ruleType === noSuggestType
      ) {
        flags[ruleType] = parts[1]
      } else {
        // Default handling.  Set them for now.
        flags[ruleType] = parts[1]
      }
    }
  
    // Default for `COMPOUNDMIN` is `3`.  See man 4 hunspell.
    if (isNaN(flags[compoundInType])) {
      flags[compoundInType] = defaultCompoundInType
    }
  
    if (flags[keyType].length === 0) {
      flags[keyType] = defaultKeyboardLayout
    }
  
    /* istanbul ignore if - Dictionaries seem to always have this. */
    if (!flags[tryType]) {
      flags[tryType] = alphabet.concat()
    }
  
    if (!flags[keepCaseFlag]) {
      flags[keepCaseFlag] = false
    }
  
    return {
      compoundRuleCodes: compoundRuleCodes,
      replacementTable: replacementTable,
      conversion: conversion,
      compoundRules: compoundRules,
      rules: rules,
      flags: flags
    }
  
    function pushLine(line) {
      line = trim(line)
  
      // Hash can be a valid flag, so we only discard line that starts with it.
      if (line && line.charCodeAt(0) !== numberSign) {
        lines.push(line)
      }
    }
  }
func_documentation_string: Parse an affix file.