node-powertools
Advanced tools
Comparing version
@@ -296,2 +296,123 @@ (function (root, factory) { | ||
function enforceValidTypes(value, types, def) { | ||
var isValidType = types.some(function (type) { | ||
return typeof value === type || (type === 'array' && Array.isArray(value)); | ||
}); | ||
return isValidType ? value : def; | ||
} | ||
function enforceMinMax(value, min, max) { | ||
var isNumber = typeof value === 'number'; | ||
var isString = typeof value === 'string'; | ||
if (min !== undefined) { | ||
if (isNumber && value < min) { | ||
return min; | ||
} else if (isString && value.length < min) { | ||
// return value + ' '.repeat(min - value.length); | ||
} else if (Array.isArray(value) && value.length < min) { | ||
// return value.concat(Array(min - value.length)); | ||
} | ||
} | ||
if (max !== undefined) { | ||
if (isNumber && value > max) { | ||
return max; | ||
} else if (isString && value.length > max) { | ||
return value.slice(0, max); | ||
} else if (Array.isArray(value) && value.length > max) { | ||
return value.slice(0, max); | ||
} | ||
} | ||
return value; | ||
} | ||
function getNestedValue(obj, keyString) { | ||
var keys = keyString.split('.'); | ||
var currentValue = obj; | ||
for (var key of keys) { | ||
if (currentValue === undefined || currentValue === null) { | ||
return undefined; | ||
} | ||
currentValue = currentValue[key]; | ||
} | ||
return currentValue; | ||
} | ||
function setNestedValue(obj, keyString, value) { | ||
var keys = keyString.split('.'); | ||
var currentObject = obj; | ||
for (var i = 0; i < keys.length - 1; i++) { | ||
var key = keys[i]; | ||
if (typeof currentObject[key] !== 'object' || currentObject[key] === null) { | ||
currentObject[key] = {}; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
currentObject[keys[keys.length - 1]] = value; | ||
} | ||
Powertools.defaults = function (user, defaults) { | ||
var updatedSettings = {}; | ||
var alreadyDone = []; | ||
getKeys(defaults) | ||
.forEach(function (key) { | ||
// Get the path to this setting, minus the last key | ||
var pathMinusLast = key.split('.').slice(0, -1).join('.'); | ||
// Break if we've already done this key | ||
if (alreadyDone.indexOf(pathMinusLast) !== -1) { | ||
// console.log('skip', key); | ||
return; | ||
} | ||
// If the user has not set a value for this setting, use the plan default | ||
var userSetting = getNestedValue(user, pathMinusLast); | ||
var planDefault = getNestedValue(defaults, pathMinusLast); | ||
var workingValue; | ||
if (!planDefault || typeof planDefault === 'undefined' || typeof planDefault.default === 'undefined') { | ||
planDefault = { | ||
default: getNestedValue(defaults, key), | ||
} | ||
// console.log('====USING DEFAULT DEFAULT====', planDefault.default); | ||
} | ||
// console.log('proc', key, userSetting, planDefault); | ||
// If the user has not set a value for this setting, use the plan default | ||
if (typeof userSetting === 'undefined') { | ||
workingValue = planDefault.default; | ||
} else { | ||
workingValue = userSetting; | ||
} | ||
// Loop through acceptable types of default and set default if it is not one of them | ||
workingValue = enforceValidTypes(workingValue, planDefault.types, planDefault.default); | ||
// Enforce min and max values | ||
workingValue = enforceMinMax(workingValue, planDefault.min, planDefault.max); | ||
setNestedValue(updatedSettings, pathMinusLast, workingValue); | ||
// console.log('---SET', pathMinusLast, workingValue); | ||
alreadyDone.push(pathMinusLast); | ||
}); | ||
// console.log('---updatedSettings', updatedSettings); | ||
return updatedSettings; | ||
} | ||
// TODO: add ability to do this with plan limits, but need to have a 4th options that says "dont get X.default, just get X" | ||
return Powertools; // Enable if using UMD | ||
@@ -298,0 +419,0 @@ |
{ | ||
"name": "node-powertools", | ||
"version": "0.0.23", | ||
"version": "1.0.0", | ||
"description": "Powerful assistive functions for Node and Browser environments.", | ||
@@ -33,2 +33,2 @@ "main": "dist/index.js", | ||
} | ||
} | ||
} |
@@ -157,2 +157,27 @@ <p align="center"> | ||
### powertools.defaults(settings, defaults) | ||
Easily structure your `settings` object by validating them with a `defaults` object. This function automatically fills in any missing keys in `settings` with the corresponding key in `defaults`, removes any keys in `settings` that are not in `defaults`, and converts any values in `settings` to the same type as the corresponding key in `defaults`. | ||
```js | ||
const defaults = { | ||
name: { | ||
types: ['string'], | ||
default: '', | ||
min: 0, | ||
max: 10, | ||
}, | ||
stats: { | ||
level: { | ||
types: ['number'], | ||
default: 1, | ||
min: 1, | ||
max: 2, | ||
}, | ||
}, | ||
} | ||
powertools.defaults({}, defaults); // Output: {name: '', stats: {level: 1}} | ||
powertools.defaults({name: 'What a long name!'}, defaults); // Output: {name: 'What a lon', stats: {level: 1}} | ||
powertools.defaults({stats: {level: 3}}, defaults); // Output: {name: '', stats: {level: 2}} | ||
``` | ||
``` | ||
### powertools.getKeys(obj) | ||
@@ -159,0 +184,0 @@ Walk through any `obj` and get an array of every key, including nested keys. |
121
src/index.js
@@ -296,2 +296,123 @@ (function (root, factory) { | ||
function enforceValidTypes(value, types, def) { | ||
var isValidType = types.some(function (type) { | ||
return typeof value === type || (type === 'array' && Array.isArray(value)); | ||
}); | ||
return isValidType ? value : def; | ||
} | ||
function enforceMinMax(value, min, max) { | ||
var isNumber = typeof value === 'number'; | ||
var isString = typeof value === 'string'; | ||
if (min !== undefined) { | ||
if (isNumber && value < min) { | ||
return min; | ||
} else if (isString && value.length < min) { | ||
// return value + ' '.repeat(min - value.length); | ||
} else if (Array.isArray(value) && value.length < min) { | ||
// return value.concat(Array(min - value.length)); | ||
} | ||
} | ||
if (max !== undefined) { | ||
if (isNumber && value > max) { | ||
return max; | ||
} else if (isString && value.length > max) { | ||
return value.slice(0, max); | ||
} else if (Array.isArray(value) && value.length > max) { | ||
return value.slice(0, max); | ||
} | ||
} | ||
return value; | ||
} | ||
function getNestedValue(obj, keyString) { | ||
var keys = keyString.split('.'); | ||
var currentValue = obj; | ||
for (var key of keys) { | ||
if (currentValue === undefined || currentValue === null) { | ||
return undefined; | ||
} | ||
currentValue = currentValue[key]; | ||
} | ||
return currentValue; | ||
} | ||
function setNestedValue(obj, keyString, value) { | ||
var keys = keyString.split('.'); | ||
var currentObject = obj; | ||
for (var i = 0; i < keys.length - 1; i++) { | ||
var key = keys[i]; | ||
if (typeof currentObject[key] !== 'object' || currentObject[key] === null) { | ||
currentObject[key] = {}; | ||
} | ||
currentObject = currentObject[key]; | ||
} | ||
currentObject[keys[keys.length - 1]] = value; | ||
} | ||
Powertools.defaults = function (user, defaults) { | ||
var updatedSettings = {}; | ||
var alreadyDone = []; | ||
getKeys(defaults) | ||
.forEach(function (key) { | ||
// Get the path to this setting, minus the last key | ||
var pathMinusLast = key.split('.').slice(0, -1).join('.'); | ||
// Break if we've already done this key | ||
if (alreadyDone.indexOf(pathMinusLast) !== -1) { | ||
// console.log('skip', key); | ||
return; | ||
} | ||
// If the user has not set a value for this setting, use the plan default | ||
var userSetting = getNestedValue(user, pathMinusLast); | ||
var planDefault = getNestedValue(defaults, pathMinusLast); | ||
var workingValue; | ||
if (!planDefault || typeof planDefault === 'undefined' || typeof planDefault.default === 'undefined') { | ||
planDefault = { | ||
default: getNestedValue(defaults, key), | ||
} | ||
// console.log('====USING DEFAULT DEFAULT====', planDefault.default); | ||
} | ||
// console.log('proc', key, userSetting, planDefault); | ||
// If the user has not set a value for this setting, use the plan default | ||
if (typeof userSetting === 'undefined') { | ||
workingValue = planDefault.default; | ||
} else { | ||
workingValue = userSetting; | ||
} | ||
// Loop through acceptable types of default and set default if it is not one of them | ||
workingValue = enforceValidTypes(workingValue, planDefault.types, planDefault.default); | ||
// Enforce min and max values | ||
workingValue = enforceMinMax(workingValue, planDefault.min, planDefault.max); | ||
setNestedValue(updatedSettings, pathMinusLast, workingValue); | ||
// console.log('---SET', pathMinusLast, workingValue); | ||
alreadyDone.push(pathMinusLast); | ||
}); | ||
// console.log('---updatedSettings', updatedSettings); | ||
return updatedSettings; | ||
} | ||
// TODO: add ability to do this with plan limits, but need to have a 4th options that says "dont get X.default, just get X" | ||
return Powertools; // Enable if using UMD | ||
@@ -298,0 +419,0 @@ |
134
test/test.js
@@ -265,2 +265,136 @@ const package = require('../package.json'); | ||
describe('defaults()', () => { | ||
const defaults = { | ||
basic: { | ||
name: { | ||
types: ['string'], | ||
default: '', | ||
max: 10, | ||
}, | ||
stats: { | ||
level: { | ||
types: ['number'], | ||
default: 1, | ||
min: 1, | ||
max: 2, | ||
}, | ||
}, | ||
}, | ||
premium: { | ||
name: { | ||
types: ['string'], | ||
default: '', | ||
max: 10, | ||
}, | ||
stats: { | ||
level: { | ||
types: ['number'], | ||
default: 1, | ||
min: 1, | ||
max: 10, | ||
}, | ||
}, | ||
}, | ||
}; | ||
it('should remove keys not defined in defaults', () => { | ||
const user = { | ||
name: 'John', | ||
stats: { | ||
level: 1, | ||
}, | ||
unacceptable: { | ||
value: 'test', | ||
}, | ||
}; | ||
const planId = 'basic'; | ||
const result = powertools.defaults(user, defaults[planId]); | ||
assert(!result.hasOwnProperty('unacceptable')); | ||
}); | ||
it('should set default values for missing keys in user', () => { | ||
const user = {}; | ||
const planId = 'basic' | ||
const result = powertools.defaults(user, defaults[planId]); | ||
assert.strictEqual(result.name, defaults[planId].name.default); | ||
assert.strictEqual(result.stats.level, defaults[planId].stats.level.default); | ||
}); | ||
it('should enforce acceptable types', () => { | ||
const user = { | ||
name: 123, | ||
stats: { | ||
level: 'invalid', | ||
}, | ||
}; | ||
const planId = 'basic'; | ||
const result = powertools.defaults(user, defaults[planId]); | ||
assert.strictEqual(result.name, defaults[planId].name.default); | ||
assert.strictEqual(result.stats.level, defaults[planId].stats.level.default); | ||
}); | ||
it('should enforce min and max constraints', () => { | ||
const user = { | ||
name: 'John but too long', | ||
stats: { | ||
level: 5, | ||
}, | ||
}; | ||
const planId = 'basic'; | ||
const result = powertools.defaults(user, defaults[planId]); | ||
assert.strictEqual(result.stats.level, defaults[planId].stats.level.max); | ||
assert.strictEqual(result.name, user.name.slice(0, defaults[planId].name.max)); | ||
}); | ||
it('should work with nested properties', () => { | ||
const user = { | ||
name: 'John', | ||
stats: { | ||
level: 10, | ||
invalid: 'test', | ||
}, | ||
}; | ||
const planId = 'premium'; | ||
const result = powertools.defaults(user, defaults[planId]); | ||
assert.strictEqual(result.name, user.name); | ||
assert.strictEqual(result.stats.level, user.stats.level); | ||
assert(!result.stats.hasOwnProperty('invalid')); | ||
}); | ||
// it('should work without requiring strict defaults', () => { | ||
// const user = { | ||
// name: 'John', | ||
// stats: { | ||
// level: 10, | ||
// invalid: 'test', | ||
// }, | ||
// }; | ||
// const defaults = { | ||
// requests: 2, | ||
// devices: 1, | ||
// } | ||
// const planId = 'basic'; | ||
// const result = powertools.defaults(user, defaults[planId]); | ||
// assert.strictEqual(result.requests, user.requests); | ||
// }); | ||
}); | ||
}) |
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
51013
29.54%1132
35.24%0
-100%209
13.59%