Load a yml/yaml/json file or whole directory
npm install require-ymlbash
npm install require-yml
`
Breaking changes in
2.0.0
- version 1.x defaults to suppresses load/parse errors, version 2.x defaults to throw them.
- v1.4.x and v2.x let you provide your own error handlers: restore original behavior by providing your own onLoadError as an empty function.
Usage
configs directory:
`sh
configs/
|- foo/
|- bar/
|- a.yml
|- b.yaml
|- c.json
|- empty/
`
`javascript
const req = require('require-yml')
`
$3
`javascript
const yml = req('./configs/foo/bar/a.yml')
const yaml = req('./configs/foo/bar/b') // b.yaml
const json = req('./configs/foo/bar/c.json')
console.log(yml, yaml, json)
// >> {}, {}, {}
`
$3
`javascript
const all = req('./configs')
console.log(all)
// >> json object {"foo":{"bar":[Object Object]}
`
* All files in the directory are required, as properties of an object.
* By default, the file base name as it appears on the OS is used as property name in the returned object.
$3
`javascript
const empty = req('./configs/empty')
console.log(empty)
// >> undefined
`
$3
`javascript
const yml = req(['./config/default.yml', './configs/local.yml'])
`
* having directories in these names will cause an error you should handle. We don't know of such use-case, but if you ever encounter one - you may provide your own loaders for the pattern /\.yml$/ - see below)
$3
`javascript
const yml = req(['./config/default', './configs/local'])
`
Notes:
- by default, tool tries extensions by this order: .js, .yml, .yaml, .json, / (dir)
All found are merged on each other, the later cascades.
- the built-in .js first - gives you more power allowing to start with a type that is not native to json or safe-mode yaml, e.g:
`javascript
//file: config/strategies/cli-banner.js
module.export = function CliBanner() { }
CliBanner.prototype.text = '@TITLE'
CliBanner.prototype.header = function(title) { return this.text.replace(/@TITLE/, title) }
`
`yaml
#file: config/strategies/cli-banner.yaml
CliBanner:
prototype:
text: |
-----------------------
| @TITLE |
-----------------------
`
$3
`javascript
const yml = req({
targets: ['./config/default', './configs/local'],
extensions: [ '.json', '.yaml' ]
})
`
this results in try the load order below, where each stage treats it's previous as defaults and cascades* it with it's own values, whenever such are found:
* file: ./config/default.json
* file:./config/default.yaml
* directory: ./config/default/
* file: ./config/local.json
* file: ./config/local.yaml
* directory: ./config/local/
* Note: Mind the difference between loading a list of files and loading a directory:
- list of files - merges the later into the former, the later cascades.
- directory - uses by default file base-names as property names, where files of same name and different extensions are basically a list of files.
$3
`javascript
const path = require('path')
const camelCase = require('lodash/camelCase')
const yml = req({
target: './config',
fileToProp: file => camelCase(path.baseName(file))
})
`
* file provided to fileToProp is a full absolute path as it appears on your OS
* what fileToProp(file) returns is used as property name
* if there is already a value there - it is merged into and cascaded by the current.
* Note: targets is a synonym for target for readability . Each can be provided as a string or as an array of strings. If you provide both - target is used, targets is ignored. When it's provided as a string - it's understood as a list of files with a single-element.
$3
`javascript
const fs = require('fs')
const jsonc = require('jsonc')
const yml = req({
targets: ['./config/default', './configs/local'],
loaders: [{
pattern: /.jsonc?$/, //<-- this will match .json and .jsonc alike
load: target => jsonc.parse(fs.readFileSync(target)),
}]
`
Notes:
* user loaders precede built-in ones. Loader of first matched pattern is used.
The built-in loaders are:
`
{ pattern: /\.(yml|yaml)$/, load: target => jsYaml.load(fs.readFileSync(resolvePath(target), 'utf8')) },
{ pattern: /\.(json|js)$/, load: target => require(resolvePath(target)) },
`
* order of loaders does not effect order of loaded files (order of extensions does, and only between files in same directory)
* You can support custom extensions by providing loaders
* You can have the tool try your custom extensions for paths you provide without extension by including it in extensions
$3
`javascript
const mapper = function(json) {
json.inject = 'everywhere'
return json
}
// v >= 2.0
const yml2 = req({ target: './configs', mapper })
console.log(yml2.foo.bar.a.inject)
// >> 'everywhere'
// legacy form (supported for backward compatibility)
const yml1 = req('./configs', mapper)
console.log(yml1.foo.bar.a.inject)
`
* mapper iterator is called for every value that is loaded before being added to the value tree.
* use mappers to map or mutate loaded values.
* suppress loaded values by returning a falsy value.
$3
`javascript
const yml = req({
target: './configs',
mapper: function broken(json) {
a = b // -> throws a is undefined
},
onLoadError: err => {
// handle your errors here
switch(e.CODE) {
...
}
},
})
`
or use the global hook:
`javascript
req.onLoadError = function(err) {
// handle your errors here
switch(e.CODE) {
...
}
}
`
$3
`javascript
req('./configs', null, function(yml){
console.log(yml.foo.bar.a)
})
// >> {}
`
Note: operation is pseudo async. Nothing happens in parallel, but the loading happens on next tick after your code has ran and all your declarations are made.
Test
`sh
npm test
`
Test outputs numbered test cases. Numbered test-cases can be used to filter ran tests.
`sh
node test 15,18
``