| 8 | import matter from 'gray-matter' |
| 9 | |
| 10 | export default function dataDirectory(dir, opts = {}) { |
| 11 | const defaultOpts = { |
| 12 | preprocess: (content) => { |
| 13 | return content |
| 14 | }, |
| 15 | ignorePatterns: [/README\.md$/i], |
| 16 | extensions: ['.json', '.md', '.markdown', '.yml'], |
| 17 | } |
| 18 | |
| 19 | opts = Object.assign({}, defaultOpts, opts) |
| 20 | |
| 21 | // validate input |
| 22 | assert(Array.isArray(opts.ignorePatterns)) |
| 23 | assert(opts.ignorePatterns.every(isRegExp)) |
| 24 | assert(Array.isArray(opts.extensions)) |
| 25 | assert(opts.extensions.length) |
| 26 | |
| 27 | // start with an empty data object |
| 28 | const data = {} |
| 29 | |
| 30 | // find YAML and Markdown files in the given directory, recursively |
| 31 | const filenames = walk(dir, { includeBasePath: true }).filter((filename) => { |
| 32 | // ignore files that match any of ignorePatterns regexes |
| 33 | if (opts.ignorePatterns.some((pattern) => pattern.test(filename))) return false |
| 34 | |
| 35 | // ignore files that don't have a whitelisted file extension |
| 36 | return opts.extensions.includes(path.extname(filename).toLowerCase()) |
| 37 | }) |
| 38 | |
| 39 | const files = filenames.map((filename) => [filename, fs.readFileSync(filename, 'utf8')]) |
| 40 | files.forEach(([filename, fileContent]) => { |
| 41 | // derive `foo.bar.baz` object key from `foo/bar/baz.yml` filename |
| 42 | const key = filenameToKey(path.relative(dir, filename)) |
| 43 | const extension = path.extname(filename).toLowerCase() |
| 44 | |
| 45 | if (opts.preprocess) fileContent = opts.preprocess(fileContent) |
| 46 | |
| 47 | // Add this file's data to the global data object. |
| 48 | // Note we want to use `setWith` instead of `set` so we can customize the type during path creation. |
| 49 | // If we just use `set`, then e.g. `release-notes.enterprise-server.2-20.0` will be an Array but |
| 50 | // `release-notes.enterprise-server.3-0.0` will be an Object. |
| 51 | // See https://lodash.com/docs#set for an explanation. |
| 52 | switch (extension) { |
| 53 | case '.json': |
| 54 | setWith(data, key, JSON.parse(fileContent), Object) |
| 55 | break |
| 56 | case '.yml': |
| 57 | setWith(data, key, yaml.load(fileContent, { filename }), Object) |
| 58 | break |
| 59 | case '.md': |
| 60 | case '.markdown': |
| 61 | // Use `matter` to drop frontmatter, since localized reusable Markdown files |
| 62 | // can potentially have frontmatter, but we want to prevent the frontmatter |
| 63 | // from being rendered. |
| 64 | setWith(data, key, matter(fileContent).content, Object) |
| 65 | break |
| 66 | } |
| 67 | }) |