function collectDocs (functionNames, inputPath) {
  function normalizeWindowsPath(path) {
    return path.replace(/\\/g, '/')
  }

  // glob doesn't work on Windows, which has \ separators instead of /
  const linuxInputPath = normalizeWindowsPath(inputPath + '**/*.js')
  const files = glob.sync(linuxInputPath).sort().map(normalizeWindowsPath)

  // generate path information for each of the files
  const functions = {} // TODO: change to array
  files.forEach(function (fullPath) {
    const path = fullPath.split('/')
    const name = path.pop().replace(/.js$/, '')
    const functionIndex = path.indexOf('function')
    let category

    // Note: determining whether a file is a function and what it's category
    // is a bit tricky and quite specific to the structure of the code,
    // we reckon with some edge cases here.
    if (!path.includes('docs') && functionIndex !== -1) {
      if (path.includes('expression')) {
        category = 'expression'
      } else if (/\/lib\/cjs\/type\/[a-zA-Z0-9_]*\/function/.test(fullPath)) {
        // for type/bignumber/function/bignumber.js, type/fraction/function/fraction.js, etc
        category = 'construction'
      } else if (/\/lib\/cjs\/core\/function/.test(fullPath)) {
        category = 'core'
      } else {
        category = path[functionIndex + 1]
      }
    } else if (fullPath.endsWith('/lib/cjs/expression/parse.js')) {
      // TODO: this is an ugly special case
      category = 'expression'
    } else if (path.join('/').endsWith('/lib/cjs/type')) {
      // for boolean.js, number.js, string.js
      category = 'construction'
    }

    if (!functionNames.includes(name) || IGNORE_FUNCTIONS[name]) {
      category = null
    }

    if (category) {
      functions[name] = {
        name,
        category,
        fullPath
      }
    } else {
      // TODO: throw a warning that no category could be found (instead of silently ignoring it).
      //  Right now, this matches too many functions, so to do that, we first must make the glob matching relevant
      //  files more specific, and we need to extend the list with functions we want to ignore.
    }
  })

  // loop over all files, generate a doc for each of them
  Object.keys(functions).forEach(name => {
    const fn = functions[name]
    const code = String(fs.readFileSync(fn.fullPath))

    const isFunction = (functionNames.includes(name)) && !IGNORE_FUNCTIONS[name]
    const doc = isFunction ? generateDoc(name, code) : null

    if (isFunction && doc) {
      fn.doc = doc
      fn.issues = validateDoc(doc)
    } else {
      // log('Ignoring', fn.fullPath)
      delete functions[name]
    }
  })
  return functions
}
Iterate over all source files and produce an object with information on
all in-line documentation.
@param {String[]} functionNames  List with all functions exported from the main instance of mathjs
@param {String} inputPath        Path to location of source files
@returns {object} docinfo
    Object whose keys are function names, and whose values are objects with
    keys name, category, fullPath, doc, and issues
    giving the relevant information