Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

oconf

Package Overview
Dependencies
Maintainers
5
Versions
32
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

oconf - npm Package Compare versions

Comparing version 4.1.0 to 5.0.0

test/files/array-with-object-with-array-with-object-with-public.cjson

67

lib/index.js

@@ -24,3 +24,64 @@ /*

return (function readFileAndResolveIncludes(fileName) {
if (Array.isArray(rootFileName)) {
var config = {};
rootFileName.forEach(function (configFileName) {
config = cjson.extend(true, config, load(configFileName, options));
});
return config;
}
// Have to always keep public keys separate within resolvePublic
// If a private key is overwritten by a public key, it's an error, and vice-versa. Name your config keys something else!
// Empty object leaves and non-public keys are filtered out when requesting with public:true
function resolvePublic(obj, isToplevel, publicOnly) {
if (typeof obj === 'object' && obj !== null) {
var publicObj = Array.isArray(obj) ? [] : {};
Object.keys(obj).forEach(function (key) {
if (key !== '#public') {
// Have to extract public and non-public keys separately, otherwise we lose information
var resolvedPublic = resolvePublic(obj[key], false, true);
if (typeof resolvedPublic === 'object' && resolvedPublic !== null && Object.keys(resolvedPublic).length > 0) {
publicObj[key] = resolvedPublic;
}
obj[key] = resolvePublic(obj[key], false, false);
}
});
if (typeof obj['#public'] !== 'undefined') {
if (!(typeof obj['#public'] === 'object' && obj['#public'] !== null && !Array.isArray(obj['#public']))) {
throw new Error('#public must always be an object');
}
Object.keys(obj['#public']).forEach(function (key) {
if (key in obj) {
throw new Error('Unsupported combination of public and non-public properties, check your tree structure');
}
if (obj['#public'][key] !== 'undefined') {
publicObj[key] = obj['#public'][key];
}
});
delete obj['#public'];
}
if (isToplevel && typeof publicObj === 'object' && publicObj !== null && Object.keys(publicObj).length > 0) {
obj['#public'] = publicObj;
}
if (publicOnly) {
return publicObj;
} else {
return cjson.extend(true, obj, publicObj);
}
}
return obj;
}
return resolvePublic((function readFileAndResolveIncludes(fileName) {
var absoluteFileName = Path.resolve(cwd, fileName);

@@ -36,2 +97,3 @@

if (Array.isArray(obj)) {
// An array that should be resolved into an array
return obj.map(resolveIncludes);

@@ -41,2 +103,3 @@ } else if (typeof obj === 'object' && obj !== null) {

_.flatten([obj['#include']]).reverse().forEach(function (fileNameToInclude) {
// Have to resolve from location of current file, not from cwd
var absoluteFileNameToInclude = Path.resolve(Path.dirname(fileName), fileNameToInclude);

@@ -55,3 +118,3 @@ if (!isIgnored(absoluteFileNameToInclude)) {

}(cjson.load(absoluteFileName)));
}(rootFileName));
}(rootFileName)), true, options.public);
};

4

package.json

@@ -5,3 +5,3 @@ {

"description": "Configuration",
"version": "4.1.0",
"version": "5.0.0",
"repository": {

@@ -51,4 +51,4 @@ "type": "git",

"mocha": "*",
"unexpected": "7.0.0"
"unexpected": "10.8.1"
}
}

@@ -17,5 +17,9 @@ # OConf

## Format
## The `#include` directive
The basic idea is to experiment with applying `#include`-statements recusively
Anywhere in your cjson file, you can `#include` another cjson file. The file containing the `#include` directive overrides any values from the file being included, in case of conflicts.
### Format
The basic idea is to experiment with applying `#include`-directives recusively
inside JSON/cJSON documents:

@@ -51,3 +55,3 @@

## Structure
### Structure

@@ -65,2 +69,70 @@ There are no restrictions in how includes work (except no loops). Usually a

## The `#public` directive
With this directive, you can generate a json blob that can be safely exposed to client-side code. This is useful when some properties on the same object are safe to expose to client code, while others are not.
### Restrictions
In case of conflicts between a `#public` and a non-public key on the same object, an error is thrown - it is usually a sign that a new key needs to be introduced if the same key contains different values for client and server code.
The `#include` directives are processed before `#public`.
### Format
Anywhere in your cjson file, you can add a `#public` property to an object, denoting some keys on that property you want grouped together on the `#public` property of the root of your config.
```javascript
// some-public-settings.cjson
{
"some-setting": "default value",
"value": 100,
"fancy-list": {
"expose-foo": true,
"#public": {
"scroll-timeout": 100
}
}
}
```
Will result in a config with:
```javascript
{
"some-setting": "default-value",
"value": 100,
"fancy-list": {
"expose-foo": true,
"scroll-timeout": 100
},
"#public": {
"fancy-list": {
"scroll-timeout": 100
}
}
}
```
### Returning only configuration marked as `#public`
You can instruct `oconf.load` to only return configuration properties marked with `#public`:
> var oconf = require('oconf');
> oconf.load('config/some-public-settings.cjson', { public: true });
{
"fancy-list": {
"scroll-timeout": 100
}
}
Of course you can also just grab the `#public` property from the result of `oconf.load`:
> var oconf = require('oconf');
> oconf.load('config/some-public-settings.cjson')['#public'];
{
"fancy-list": {
"scroll-timeout": 100
}
}
## Binary

@@ -112,2 +184,13 @@

You can also filter out values in the `#public` blob with the `--public` flag.
```
$ oconf --public some-public-settings.cjson
{
"fancy-list": {
"scroll-timeout": 100
}
}
```
## Tests

@@ -114,0 +197,0 @@

@@ -41,3 +41,3 @@ /* global describe, it */

expect(stdout, 'to equal', '');
expect(stderr, 'to match', '');
expect(stderr, 'to equal', '');
done();

@@ -51,3 +51,3 @@ });

expect(stdout, 'to equal', 'qux\n');
expect(stderr, 'to match', '');
expect(stderr, 'to equal', '');
done();

@@ -54,0 +54,0 @@ });

@@ -58,2 +58,14 @@ /* global describe, it */

});
it('should support including multiple files, and print the resolved json structure to stdout', function () {
return expect([testFile('extend-base'), testFile('deep')], 'when passed as arguments to oconf', 'to satisfy', {
err: null,
stdout: formattedJson({
foo: {
bar: "qux"
},
what: "this is from default.cjson."
}),
stderr: ''
});
});
it('should fail when asked for nonexistant file', function () {

@@ -92,3 +104,3 @@ return expect(testFile('nonExistent'), 'when passed as arguments to oconf', 'to satisfy', {

stdout: '',
stderr: expect.it('to match', /Options:/)
stderr: expect.it('to match', /Options/)
});

@@ -199,15 +211,2 @@ });

});
describe('missing --extract-option flag', function () {
it('should return the option value and warn the user', function () {
return expect([
testFile('base'),
'foo'
], 'when passed as arguments to oconf', 'to satisfy', {
err: expect.it('to be an', Error),
code: 1,
stdout: '',
stderr: 'Error: Did you forget the --extract-option flag?\n'
});
});
});
describe('--ignore flag', function () {

@@ -214,0 +213,0 @@ it('should work with no other options', function () {

@@ -25,2 +25,16 @@ /*global describe, it, before*/

});
describe('calling load method with an array of config file names', function () {
var data, dataInclude;
before(function () {
data = oconf.load([testFile('extend-base.cjson'), testFile('deep.cjson')]);
dataInclude = oconf.load(testFile('extend-wrap.cjson'));
});
it('functions like calling #include with an array of filenames in the same order', function () {
expect(data, 'to equal', dataInclude);
});
});
});
describe('#include behaviour', function () {
describe('extend-base.cjson', function () {

@@ -95,3 +109,3 @@ var data;

oconf.load(testFile('loop1.cjson'));
}, 'to throw', /^Loop in loaded files: /);
}, 'to throw', /^Loop in loaded files/);
});

@@ -101,3 +115,3 @@ it('Loading loop2.cjson throws error', function () {

oconf.load(testFile('loop2.cjson'));
}, 'to throw', /^Loop in loaded files:/);
}, 'to throw', /^Loop in loaded files/);
});

@@ -145,1 +159,236 @@ });

});
describe('#public behaviour', function () {
describe('when loading with public:false (the default)', function () {
describe('where the root object contains a #public property', function () {
var data;
before(function () {
data = oconf.load(testFile('public-base.cjson'));
});
it('should fold the #public properties down into the base structure', function () {
expect(data, 'to equal', {
foo: 'do not expose to public',
what: 'what is public',
'#public': {
what: 'what is public'
}
});
});
});
describe('where a child object contains some #public properties', function () {
var data;
before(function () {
data = oconf.load(testFile('public-deep.cjson'));
});
it('should fold the #public properties down into the base structure', function () {
expect(data, 'to equal', {
foo: "do not expose to public",
bar: {
quux: "super secret"
},
hello: {
earth: "mostly harmless",
answer: 42
},
'#public': {
hello: {
answer: 42
}
}
});
});
});
describe('where a child object in a child array contains some #public properties', function () {
var data;
before(function () {
data = oconf.load(testFile('array-with-object-with-public.cjson'));
});
it('should fold the #public properties down into the base structure', function () {
expect(data, 'to equal', {
foo: [
{
bar: 'quux'
}
],
'#public': {
foo: [
{
bar: 'quux'
}
]
}
});
});
});
describe('where a child object in a child array contains some #public properties', function () {
var data;
before(function () {
data = oconf.load(testFile('array-with-object-with-array-with-object-with-public.cjson'));
});
it.skip('should fold the #public properties down into the base structure', function () {
expect(data, 'to exhaustively satisfy', {
0: {
foo: [
{
bar: 'quux'
}
]
},
'#public': [{
foo: [
{
bar: 'quux'
}
]
}]
}).and('to be an array');
});
});
describe('when trying to overwrite a public property with a property that was declared public at another level', function () {
it('should throw an error', function () {
expect(function () {
oconf.load(testFile('public-conflict.cjson'));
}, 'to throw', /^Unsupported combination of public and non/);
});
});
describe('where trying to overwrite a non-public property with a #public one', function () {
it('should throw an error', function () {
expect(function () {
oconf.load(testFile('public-deep-with-include.cjson'));
}, 'to throw', /^Unsupported combination of public and non/);
});
});
describe('where trying to overwrite a #public property with a non-public one', function () {
it('should throw an error', function () {
expect(function () {
oconf.load(testFile('public-deep-with-include.cjson'));
}, 'to throw', /^Unsupported combination of public and non/);
});
});
describe('where including a file that already has a #public property which we try to overwrite', function () {
var data;
before(function () {
data = oconf.load(testFile('public-deep-with-public-include.cjson'));
});
it('should overwrite the included #public property with our value', function () {
expect(data, 'to equal', {
foo: "do not expose to public",
bar: {
quux: "super secret"
},
hello: {
earth: "mostly harmless",
answer: 'Insufficient data for meaningful answer'
},
'#public': {
hello: {
answer: 'Insufficient data for meaningful answer'
}
}
});
});
});
describe('when calling load method with an array of config file names containing public properties', function () {
var data, dataInclude;
before(function () {
data = oconf.load([testFile('public-left.cjson'), testFile('public-right.cjson')]);
dataInclude = oconf.load(testFile('public-left-right-wrap.cjson'));
});
it('functions like calling #include with an array of filenames in the same order', function () {
expect(data, 'to equal', dataInclude);
});
});
});
describe('when loading with public:true', function () {
describe('where the root object contains a #public property', function () {
var data;
before(function () {
data = oconf.load(testFile('public-base.cjson'), { public: true });
});
it('should fold the #public properties down into the base structure, and omit secret properties and leaves', function () {
expect(data, 'to equal', {
what: 'what is public'
});
});
});
describe('where a child object contains some #public properties', function () {
var data;
before(function () {
data = oconf.load(testFile('public-deep.cjson'), { public: true });
});
it('should fold the #public properties down into the base structure, and omit secret properties and leaves', function () {
expect(data, 'to equal', {
hello: {
answer: 42
}
});
});
});
describe('where trying to overwrite a non-public property with a #public one', function () {
it('should throw an error', function () {
expect(function () {
oconf.load(testFile('public-deep-with-include.cjson'), { public: true });
}, 'to throw', /^Unsupported combination of public and non/);
});
});
describe('where trying to overwrite a #public property with a non-public one', function () {
it('should throw an error', function () {
expect(function () {
oconf.load(testFile('public-deep-with-include.cjson'), { public: true });
}, 'to throw', /^Unsupported combination of public and non/);
});
});
describe('where including a file that overwrites a #public property with another public one', function () {
var data;
before(function () {
data = oconf.load(testFile('public-deep-with-public-include.cjson'), { public: true });
});
it('should overwrite the included #public property with our value, and omit secret properties and leaves', function () {
expect(data, 'to equal', {
hello: {
answer: 'Insufficient data for meaningful answer'
}
});
});
});
describe('when there are no #public properties at all', function () {
var data;
before(function () {
data = oconf.load(testFile('base.cjson'), { public: true });
});
it('should return an empty object', function () {
expect(data, 'to equal', {});
});
});
});
describe('with public-array.cjson', function () {
it('throws an error', function () {
expect(function () {
oconf.load(testFile('public-array.cjson'));
}, 'to throw', /^\#public must always be an object/);
});
});
describe('with public-non-object.cjson', function () {
it('throws an error', function () {
expect(function () {
oconf.load(testFile('public-non-object.cjson'));
}, 'to throw', /^\#public must always be an object/);
});
});
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc