simple js-yaml shell for load YAML/YML files
MIT License
It's instead of require-yaml because of this reason.
And, it can require a yml/yaml/json file/whole directory, or with iterator, or use async callback.
npm install require-yml
2.0.0
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.configs directory:
configs/
|- foo/
|- bar/
|- a.yml
|- b.yaml
|- c.json
|- empty/
const req = require('require-yml')
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)
// >> {}, {}, {}
const all = req('./configs')
console.log(all)
// >> json object {"foo":{"bar":[Object Object]}
undefined
const empty = req('./configs/empty')
console.log(empty)
// >> undefined
const yml = req(['./config/default.yml', './configs/local.yml'])
/\.yml$/
- see below)const yml = req(['./config/default', './configs/local'])
Notes:
.js
, .yml
, .yaml
, .json
, /
(dir).js
first - gives you more power allowing to start with a type that is not native to json
or safe-mode yaml
, e.g:
//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) }
#file: config/strategies/cli-banner.yaml
CliBanner:
prototype:
text: |
-----------------------
| @TITLE |
-----------------------
const yml = req({
targets: ['./config/default', './configs/local'],
extensions: [ '.json', '.yaml' ]
})
./config/default.json
./config/default.yaml
./config/default/
./config/local.json
./config/local.yaml
./config/local/
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 OSfileToProp(file)
returns is used as property nametargets
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.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:
{ pattern: /\.(yml|yaml)$/, load: target => jsYaml.load(fs.readFileSync(resolvePath(target), 'utf8')) },
{ pattern: /\.(json|js)$/, load: target => require(resolvePath(target)) },
loaders
does not effect order of loaded files (order of extensions
does, and only between files in same directory)loaders
extensions
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)
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:
req.onLoadError = function(err) {
// handle your errors here
switch(e.CODE) {
...
}
}
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.
npm test
Test outputs numbered test cases. Numbered test-cases can be used to filter ran tests.
node test 15,18
will run only cases 15,18.