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

creature-features

Package Overview
Dependencies
Maintainers
1
Versions
17
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

creature-features - npm Package Compare versions

Comparing version 2.1.2 to 3.0.0

.eslintrc.json

3

features/default.json

@@ -6,3 +6,4 @@ {

"DefaultLocation": true,
"IsThisTheDefaultFile": true
"IsThisTheDefaultFile": true,
"IsCustomLocation": false
}

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

"IsDevelopment": true,
"IsTest": false
"IsTest": false,
"IsDefaultLocation": true,
"IsDevelopmentFromDefault": true
}

@@ -1,15 +0,16 @@

'use strict';
const path = require('path');
const fs = require('fs');
const endWith = require('end-with');
const random = require('random-weighted');
const exists = fs.existsSync;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
module.exports = function(config) {
let env;
let featuresFile;
let baseFeatures;
let defaults = {
location: './features/'
};
var path = require('path');
var fs = require('fs');
var endWith = require('end-with');
var exists = require('file-exists');
module.exports = function (config) {
var env = void 0,
featuresFile = void 0,
baseFeatures = void 0,
overrides = void 0,
locationBase = './features/';
const settings = Object.assign({}, defaults, config);
if (arguments.length === 0) {

@@ -21,14 +22,16 @@ env = process.env.NODE_ENV || 'development';

} else {
//config is believed to be an object
env = config.env ? config.env : process.env.NODE_ENV;
overrides = config;
delete overrides.env;
if (overrides.location) {
locationBase = endWith(overrides.location, '/') ? overrides.location : overrides.location + '/';
}
}
}
featuresFile = '' + locationBase + env + '.json';
baseFeatures = locationBase + 'default.json';
featuresFile = `${
endWith(settings.location, '/')
? settings.location
: settings.location + '/'
}${env}.json`;
baseFeatures = `${
endWith(settings.location, '/')
? settings.location
: settings.location + '/'
}default.json`;

@@ -43,14 +46,77 @@ var featuresFiles = [];

// look for a "named" development file
var files = fs.readdirSync(path.join(process.cwd(), './features'));
for (var i = 0; i < files.length; i++) {
if (files[i].indexOf('development.') > -1 && files[i] !== 'development.json') {
const files = fs.readdirSync(path.join(process.cwd(), './features'));
for (let i = 0; i < files.length; i++) {
if (
files[i].indexOf('development.') > -1 &&
files[i] !== 'development.json'
) {
featuresFiles.push('./features/' + files[i]);
}
};
}
}
var requiredFeatures = featuresFiles.map(function (file) {
return require(file);
const requiredFeatures = featuresFiles
.filter(f => exists(f))
.map(function(file) {
return require(file);
});
const feats = requiredFeatures.reduce((prev, current) => {
return { ...prev, ...current };
}, {});
const featureProxy = new Proxy(feats, {
get: (obj, prop) => {
if (obj[prop] === undefined) {
throw new Error(`${prop} feature is undefined`);
}
if (obj[prop] === true || obj[prop] === false) {
return obj[prop];
}
if (obj[prop].range !== undefined) {
//validate
const total = obj[prop].range.reduce(
(previous, current) => previous + current,
0
);
if (total !== 100) {
throw new Error('Range values must total 100');
}
const range = obj[prop].range.map(v => v / 100);
return random(range) === 0;
}
return (...args) =>
Reflect.apply(
(...args) => {
if (args.length === 2 && typeof args[1] === 'string') {
const check = `
'use strict';
const ${obj[prop].parameters} = '${args[1]}'
return ${obj[prop].check}`;
const funced = new Function(check);
const result = funced();
return result;
}
const check = `
'use strict';
const { ${obj[prop].parameters} } = ${JSON.stringify(args[1])}
return ${obj[prop].check}`;
const funced = new Function(check);
const result = funced();
return result;
},
featureProxy,
[prop, ...args]
);
},
set: () => {
throw new Error('Not allowed to set a value');
}
});
return Object.assign.apply(Object, _toConsumableArray(requiredFeatures));
};
return featureProxy;
};
{
"name": "creature-features",
"version": "2.1.2",
"version": "3.0.0",
"description": "Feature flags for node.js",
"main": "index.js",
"engines": {
"node": ">=10.0.0"
},
"scripts": {
"build": "babel src -d .",
"pretest": "npm run build",
"test": "ava test/*.js",
"cov": "cross-env NODE_ENV=test nyc ava test/*.js"
"lint": "eslint ./index.js ./test/*.test.js",
"test": "jest test/*.test.js",
"cov": "jest test/*.test.js --coverage"
},

@@ -19,6 +21,5 @@ "repository": {

"flags",
"features",
"toggles",
"feature",
"toggles",
"feature flags",
"feature toggles",
"continuous delivery",

@@ -34,13 +35,16 @@ "continuous integration"

"devDependencies": {
"ava": "^0.17.0",
"babel-cli": "^6.22.2",
"babel-preset-env": "^1.1.8",
"cross-env": "^3.1.3",
"nyc": "^10.0.0",
"tape": "^4.6.3"
"cross-env": "^5.2.0",
"eslint": "^5.6.0",
"eslint-config-prettier": "^3.1.0",
"eslint-plugin-node": "^7.0.1",
"eslint-plugin-prettier": "^2.6.2",
"jest-cli": "^23.6.0",
"prettier": "^1.14.3"
},
"dependencies": {
"end-with": "^1.0.2",
"file-exists": "^2.0.0"
"file-exists": "^5.0.1",
"random-weighted": "^1.0.0",
"weighted": "^0.3.0"
}
}
# Creature Features
## Dead simple feature flags for node.js
### Install

@@ -15,3 +16,3 @@ ```bash

-- test.json (settings for test)
-- production.json (settigns for production)
-- production.json (settigns for production)
-- {any other environment}.json

@@ -31,3 +32,3 @@ ```

const features = require('creature-features')();
// Default behavior
if (features.FeatureOne) {

@@ -39,2 +40,58 @@ // do something new

```
#### Rules Based
```json
{
"FeatureOne": true,
"FeatureTwo": true,
"RuleForEmailFeature": {
"parameters": "email",
"check": "email.indexOf('test') > -1"
},
"RuleForEmailAndRoleFeature": {
"parameters": "email,role",
"check": "email.indexOf('test') > -1 && role ==='admin'"
}
}
```
```javascript
const features = require('creature-features')();
// Default behavior
if (features.RuleForEmailFeature(user.email)) {
// do something new
} else {
// do the old thing
}
if (features.RuleForEmailAndRoleFeature({ email: user.email, role: user.account.role })) {
// do something new
} else {
// do the old thing
}
```
#### Weight Based
```json
{
"FeatureOne": true,
"FeatureTwo": true,
"PercentBasedFiftyFifty": {
"range": [50, 50]
},
"PercentBasedOneThird": {
"range": [33, 67]
},
}
```
```javascript
const features = require('creature-features')();
// Roughly 50% of the the time this will be true
if (features.PercentBasedFiftyFifty) {
// do something new
}
// Roughly 33% of the the time this will be true
if (features.PercentBasedOneThird) {
// do something new
}
```
### In Webpack

@@ -41,0 +98,0 @@ ```javascript

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

"LocationIsTest": true,
"DevelopmentFeature": true
"DevelopmentFeature": true,
"IsDefaultLocation": false,
"IsDevelopmentFromDefault": false
}

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