|
| 1 | +const assert = require('assert') |
| 2 | +const fs = require('fs').promises |
| 3 | +const path = require('path') |
| 4 | +const walk = require('walk-sync') |
| 5 | +const yaml = require('js-yaml') |
| 6 | +const { isRegExp, set } = require('lodash') |
| 7 | +const filenameToKey = require('./filename-to-key') |
| 8 | + |
| 9 | +module.exports = async function dataDirectory (dir, opts = {}) { |
| 10 | + const defaultOpts = { |
| 11 | + preprocess: (content) => { return content }, |
| 12 | + ignorePatterns: [/README\.md$/i], |
| 13 | + extensions: [ |
| 14 | + '.json', |
| 15 | + '.md', |
| 16 | + '.markdown', |
| 17 | + '.yaml', |
| 18 | + '.yml' |
| 19 | + ] |
| 20 | + } |
| 21 | + |
| 22 | + opts = Object.assign({}, defaultOpts, opts) |
| 23 | + |
| 24 | + // validate input |
| 25 | + assert(Array.isArray(opts.ignorePatterns)) |
| 26 | + assert(opts.ignorePatterns.every(isRegExp)) |
| 27 | + assert(Array.isArray(opts.extensions)) |
| 28 | + assert(opts.extensions.length) |
| 29 | + |
| 30 | + // start with an empty data object |
| 31 | + const data = {} |
| 32 | + |
| 33 | + // find YAML and Markdown files in the given directory, recursively |
| 34 | + await Promise.all(walk(dir, { includeBasePath: true }) |
| 35 | + .filter(filename => { |
| 36 | + // ignore files that match any of ignorePatterns regexes |
| 37 | + if (opts.ignorePatterns.some(pattern => pattern.test(filename))) return false |
| 38 | + |
| 39 | + // ignore files that don't have a whitelisted file extension |
| 40 | + return opts.extensions.includes(path.extname(filename).toLowerCase()) |
| 41 | + }) |
| 42 | + .map(async filename => { |
| 43 | + // derive `foo.bar.baz` object key from `foo/bar/baz.yml` filename |
| 44 | + const key = filenameToKey(path.relative(dir, filename)) |
| 45 | + const extension = path.extname(filename).toLowerCase() |
| 46 | + |
| 47 | + let fileContent = await fs.readFile(filename, 'utf8') |
| 48 | + |
| 49 | + if (opts.preprocess) fileContent = opts.preprocess(fileContent) |
| 50 | + |
| 51 | + // add this file's data to the global data object |
| 52 | + switch (extension) { |
| 53 | + case '.json': |
| 54 | + set(data, key, JSON.parse(fileContent)) |
| 55 | + break |
| 56 | + case '.yaml': |
| 57 | + case '.yml': |
| 58 | + set(data, key, yaml.safeLoad(fileContent, { filename })) |
| 59 | + break |
| 60 | + case '.md': |
| 61 | + case '.markdown': |
| 62 | + set(data, key, fileContent) |
| 63 | + break |
| 64 | + } |
| 65 | + })) |
| 66 | + |
| 67 | + return data |
| 68 | +} |
0 commit comments