Socket
Socket
Sign inDemoInstall

simpl-schema

Package Overview
Dependencies
Maintainers
2
Versions
73
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

simpl-schema - npm Package Compare versions

Comparing version 0.5.0 to 1.0.0

dist/clean/AutoValueRunner.js

46

CHANGELOG.md

@@ -25,5 +25,49 @@ <!-- START doctoc generated TOC please keep comment here to allow auto update -->

## 1.0.0
*BREAKING CHANGE:* autoValue and defaultValue handling has been rewritten to fix all known issues. As part of this rewrite, the behavior has changed to address a point of common confusion.
Previously, when you cleaned an object to add autoValues, a `defaultValue` would be added (and an `autoValue` function would run) even if the parent object was not present. (It would be created.)
Now, an `autoValue`/`defaultValue` will run only if the object in which it appears exists. Usually this is what you want, but if you are relying on the previous behavior, you can achieve the same thing by making sure that all ancestor objects have a `defaultValue: {}`.
For example, this:
```js
{
profile: {
type: Object,
optional: true,
},
'profile.language': {
type: String,
defaultValue: 'en',
},
}
```
previously cleaned `{}` to become `{ profile: { language: 'en' } }` but now would remain `{}`. If you want cleaning to result in `{ profile: { language: 'en' } }`, add the `profile` default value like:
```js
{
profile: {
type: Object,
optional: true,
defaultValue: {},
},
'profile.language': {
type: String,
defaultValue: 'en',
},
}
```
If `profile` were nested under another object, you'd have to add `defaultValue: {}` to that object definition, too, and so on.
- Fix regression that resulted in `_constructorOptions key is missing "type"` error reappearing in some situations
- Fix errors when validating an object that has a property named `length`
## 0.5.0
- Remove underscore dependency in favor of seperated lodash modules
- Remove underscore dependency in favor of seperated lodash modules

@@ -30,0 +74,0 @@ ## 0.4.2

2

dist/clean.js

@@ -19,3 +19,3 @@ 'use strict';

var _utility = require('./utility.js');
var _utility = require('./utility');

@@ -22,0 +22,0 @@ var _SimpleSchema = require('./SimpleSchema');

@@ -7,20 +7,10 @@ 'use strict';

var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };
var _getPositionsForAutoValue = require('./getPositionsForAutoValue');
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _getPositionsForAutoValue2 = _interopRequireDefault(_getPositionsForAutoValue);
var _lodash = require('lodash.foreach');
var _AutoValueRunner = require('./AutoValueRunner');
var _lodash2 = _interopRequireDefault(_lodash);
var _AutoValueRunner2 = _interopRequireDefault(_AutoValueRunner);
var _mongoObject = require('mongo-object');
var _mongoObject2 = _interopRequireDefault(_mongoObject);
var _utility = require('../utility.js');
var _lodash3 = require('lodash.includes');
var _lodash4 = _interopRequireDefault(_lodash3);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@@ -41,89 +31,9 @@

function setAutoValues(autoValueFunctions, mongoObject, isModifier, extendedAutoValueContext) {
var doneKeys = [];
// Sort by how many dots each field name has, asc, such that we can auto-create
// objects and arrays before we run the autoValues for properties within them.
var sortedAutoValueFunctions = autoValueFunctions.sort(function (a, b) {
return a.fieldName.split('.').length - b.fieldName.split('.').length;
});
function getFieldInfo(key) {
var keyInfo = mongoObject.getInfoForKey(key) || {};
return {
isSet: keyInfo.value !== undefined,
value: keyInfo.value,
operator: keyInfo.operator || null
};
}
function runAV(func, closestSubschemaFieldName) {
var affectedKey = this.key;
// If already called for this key, skip it
if ((0, _lodash4.default)(doneKeys, affectedKey)) return;
var fieldParentName = (0, _utility.getParentOfKey)(affectedKey, true);
var doUnset = false;
if (Array.isArray(getFieldInfo(fieldParentName.slice(0, -1)).value)) {
if (isNaN(this.key.split('.').slice(-1).pop())) {
// parent is an array, but the key to be set is not an integer (see issue #80)
return;
}
}
var autoValue = func.call(_extends({
isSet: this.value !== undefined,
unset: function unset() {
doUnset = true;
},
value: this.value,
operator: this.operator,
field: function field(fName) {
return getFieldInfo(closestSubschemaFieldName + fName);
},
siblingField: function siblingField(fName) {
return getFieldInfo(fieldParentName + fName);
}
}, extendedAutoValueContext || {}), mongoObject.getObject());
// Update tracking of which keys we've run autovalue for
doneKeys.push(affectedKey);
if (doUnset) mongoObject.removeValueForPosition(this.position);
if (autoValue === undefined) return;
// If the user's auto value is of the pseudo-modifier format, parse it
// into operator and value.
if (isModifier) {
var op = void 0;
var newValue = void 0;
if (autoValue && (typeof autoValue === 'undefined' ? 'undefined' : _typeof(autoValue)) === 'object') {
var avOperator = Object.keys(autoValue).find(function (avProp) {
return avProp.substring(0, 1) === '$';
});
if (avOperator) {
op = avOperator;
newValue = autoValue[avOperator];
}
}
// Add $set for updates and upserts if necessary. Keep this
// above the "if (op)" block below since we might change op
// in this line.
if (!op && this.position.slice(0, 1) !== '$') {
op = '$set';
newValue = autoValue;
}
if (op) {
// Update/change value
mongoObject.removeValueForPosition(this.position);
mongoObject.setValueForPosition(op + '[' + affectedKey + ']', newValue);
return;
}
}
// Update/change value
mongoObject.setValueForPosition(this.position, autoValue);
}
(0, _lodash2.default)(autoValueFunctions, function (_ref) {
sortedAutoValueFunctions.forEach(function (_ref) {
var func = _ref.func,

@@ -133,62 +43,15 @@ fieldName = _ref.fieldName,

// autoValue should run for the exact key only, for each array item if under array
// should run whenever
// 1 it is set
// 2 it will be set by an ancestor field being set
// 3 it is not set and is not within an array
// 4 it is not set and is within an array, run for each array item that is set
// 5 if doing $set[a.$] or $set[a.$.b]
var avRunner = new _AutoValueRunner2.default({
closestSubschemaFieldName: closestSubschemaFieldName,
extendedAutoValueContext: extendedAutoValueContext,
func: func,
isModifier: isModifier,
mongoObject: mongoObject
});
var test = fieldName;
var positions = [];
var lastDot = void 0;
var lastDollar = fieldName.lastIndexOf('$');
var isOrIsWithinArray = lastDollar !== -1;
var positions = (0, _getPositionsForAutoValue2.default)({ fieldName: fieldName, isModifier: isModifier, mongoObject: mongoObject });
// Starting from the whole dotted field name for which the autoValue function
// is defined, work backwards until finding one that is set.
while (test.length > 0) {
var currentPositions = mongoObject.getPositionsInfoForGenericKey(test);
if (fieldName !== test && currentPositions.length > 0) {
(function () {
var lastPart = '';
if (fieldName.indexOf(test + '.') === 0) {
lastPart = fieldName.replace(test + '.', '');
if (lastPart.startsWith('$.')) lastPart = lastPart.slice(2);
}
currentPositions = currentPositions.map(function (position) {
position.key = position.key + '.' + lastPart;
position.position = position.position + '[' + lastPart.replace(/\./g, '][') + ']';
position.value = mongoObject.getValueForPosition(position.position);
return position;
});
})();
}
positions = positions.concat(currentPositions);
// Do the parent
lastDot = test.lastIndexOf('.');
if (lastDot > -1) {
test = test.slice(0, lastDot);
} else {
test = '';
}
}
if (positions.length === 0) {
if (!isOrIsWithinArray) {
positions.push({
key: fieldName,
value: undefined,
operator: isModifier ? '$set' : null,
position: isModifier ? '$set[' + fieldName + ']' : _mongoObject2.default._keyToPosition(fieldName)
});
}
}
// Run the autoValue function once for each place in the object that
// has a value or that potentially should.
(0, _lodash2.default)(positions, function (position) {
runAV.call(position, func, closestSubschemaFieldName);
});
positions.forEach(avRunner.runForPosition.bind(avRunner));
});

@@ -195,0 +58,0 @@ }

@@ -15,25 +15,21 @@ 'use strict';

var _lodash = require('lodash.foreach');
var _lodash = require('lodash.omit');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.omit');
var _lodash3 = require('lodash.isobject');
var _lodash4 = _interopRequireDefault(_lodash3);
var _lodash5 = require('lodash.isobject');
var _lodash5 = require('lodash.union');
var _lodash6 = _interopRequireDefault(_lodash5);
var _lodash7 = require('lodash.union');
var _lodash7 = require('lodash.includes');
var _lodash8 = _interopRequireDefault(_lodash7);
var _lodash9 = require('lodash.includes');
var _lodash10 = _interopRequireDefault(_lodash9);
var _SimpleSchema = require('./SimpleSchema');
var _utility = require('./utility.js');
var _utility = require('./utility');

@@ -71,3 +67,3 @@ var _typeValidator = require('./validation/typeValidator');

// First do some basic checks of the object, and throw errors if necessary
if (!(0, _lodash6.default)(obj)) {
if (!(0, _lodash4.default)(obj)) {
throw new Error('The first argument of validate() must be an object');

@@ -108,3 +104,4 @@ }

// Prepare the context object for the validator functions
var fieldParentName = (0, _utility.getParentOfKey)(affectedKey, true);
var fieldParentNameWithEndDot = (0, _utility.getParentOfKey)(affectedKey, true);
var fieldParentName = fieldParentNameWithEndDot.slice(0, -1);

@@ -164,4 +161,7 @@ function getFieldInfo(key) {

operator: op,
parentField: function parentField() {
return getFieldInfo(fieldParentName);
},
siblingField: function siblingField(fName) {
return getFieldInfo(fieldParentName + fName);
return getFieldInfo(fieldParentNameWithEndDot + fName);
},

@@ -186,3 +186,3 @@

// and add them to inner props like "type" and "min"
definition: _extends({}, (0, _lodash4.default)(def, 'type'), typeDef)
definition: _extends({}, (0, _lodash2.default)(def, 'type'), typeDef)
});

@@ -282,3 +282,3 @@

if (Array.isArray(val)) {
(0, _lodash2.default)(val, function (v, i) {
val.forEach(function (v, i) {
checkObj({

@@ -299,3 +299,3 @@ val: v,

// any missing required keys, and to run any custom functions for other keys.
var keysToCheck = (0, _lodash8.default)(presentKeys, childKeys);
var keysToCheck = (0, _lodash6.default)(presentKeys, childKeys);

@@ -307,3 +307,3 @@ // If this object is within an array, make sure we check for

// Check all keys in the merged list
(0, _lodash2.default)(keysToCheck, function (key) {
keysToCheck.forEach(function (key) {
checkObj({

@@ -321,15 +321,5 @@ val: val[key],

function checkModifier(mod) {
// If this is an upsert, add all the $setOnInsert keys to $set;
// since we don't know whether it will be an insert or update, we'll
// validate upserts as if they will be an insert.
if ('$setOnInsert' in mod) {
if (isUpsert) {
mod.$set = mod.$set || {};
mod.$set = Object.assign(mod.$set, mod.$setOnInsert);
}
delete mod.$setOnInsert;
}
// Loop through operators
(0, _lodash2.default)(mod, function (opObj, op) {
Object.keys(mod).forEach(function (op) {
var opObj = mod[op];
// If non-operators are mixed in, throw error

@@ -342,6 +332,6 @@ if (op.slice(0, 1) !== '$') {

// so we check them all with undefined value to force any 'required' checks to fail
if (isUpsert && op === '$set') {
if (isUpsert && (op === '$set' || op === '$setOnInsert')) {
var presentKeys = Object.keys(opObj);
schema.objectKeys().forEach(function (schemaKey) {
if (!(0, _lodash10.default)(presentKeys, schemaKey)) {
if (!(0, _lodash8.default)(presentKeys, schemaKey)) {
checkObj({

@@ -355,3 +345,6 @@ val: undefined,

}
(0, _lodash2.default)(opObj, function (v, k) {
// Don't use forEach here because it will not properly handle an
// object that has a property named `length`
Object.keys(opObj).forEach(function (k) {
var v = opObj[k];
if (op === '$push' || op === '$addToSet') {

@@ -392,5 +385,5 @@ if ((typeof v === 'undefined' ? 'undefined' : _typeof(v)) === 'object' && '$each' in v) {

// Remove error types the user doesn't care about
if ((0, _lodash10.default)(ignoreTypes, errObj.type)) return false;
if ((0, _lodash8.default)(ignoreTypes, errObj.type)) return false;
// Make sure there is only one error per fieldName
if ((0, _lodash10.default)(addedFieldNames, errObj.name)) return false;
if ((0, _lodash8.default)(addedFieldNames, errObj.name)) return false;

@@ -397,0 +390,0 @@ addedFieldNames.push(errObj.name);

@@ -9,6 +9,2 @@ 'use strict';

var _lodash = require('lodash.foreach');
var _lodash2 = _interopRequireDefault(_lodash);
var _mongoObject = require('mongo-object');

@@ -26,3 +22,4 @@

(0, _lodash2.default)(schema, function (definition, key) {
Object.keys(schema).forEach(function (key) {
var definition = schema[key];
// CASE 1: Not shorthand. Just clone

@@ -29,0 +26,0 @@ if (_mongoObject2.default.isBasicObject(definition)) {

@@ -20,26 +20,22 @@ 'use strict';

var _lodash = require('lodash.foreach');
var _lodash = require('lodash.without');
var _lodash2 = _interopRequireDefault(_lodash);
var _lodash3 = require('lodash.without');
var _lodash3 = require('lodash.omit');
var _lodash4 = _interopRequireDefault(_lodash3);
var _lodash5 = require('lodash.omit');
var _lodash5 = require('lodash.every');
var _lodash6 = _interopRequireDefault(_lodash5);
var _lodash7 = require('lodash.every');
var _lodash7 = require('lodash.pick');
var _lodash8 = _interopRequireDefault(_lodash7);
var _lodash9 = require('lodash.pick');
var _lodash9 = require('lodash.uniq');
var _lodash10 = _interopRequireDefault(_lodash9);
var _lodash11 = require('lodash.uniq');
var _lodash12 = _interopRequireDefault(_lodash11);
var _messageBox = require('message-box');

@@ -49,5 +45,5 @@

var _lodash13 = require('lodash.includes');
var _lodash11 = require('lodash.includes');
var _lodash14 = _interopRequireDefault(_lodash13);
var _lodash12 = _interopRequireDefault(_lodash11);

@@ -154,3 +150,3 @@ var _clone = require('clone');

def.type.definitions.forEach(function (typeDef) {
if (typeDef.type instanceof SimpleSchema) {
if (SimpleSchema.isSimpleSchema(typeDef.type)) {
func(typeDef.type, ancestor, genericKey.slice(ancestor.length + 1));

@@ -211,5 +207,8 @@ foundSchema = true;

value: function mergedSchema() {
var _this2 = this;
var mergedSchema = {};
(0, _lodash2.default)(this._schema, function (keySchema, key) {
Object.keys(this._schema).forEach(function (key) {
var keySchema = _this2._schema[key];
mergedSchema[key] = keySchema;

@@ -219,4 +218,5 @@

if (!SimpleSchema.isSimpleSchema(typeDef.type)) return;
(0, _lodash2.default)(typeDef.type.mergedSchema(), function (subKeySchema, subKey) {
mergedSchema[key + '.' + subKey] = subKeySchema;
var childSchema = typeDef.type.mergedSchema();
Object.keys(childSchema).forEach(function (subKey) {
mergedSchema[key + '.' + subKey] = childSchema[subKey];
});

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

value: function getDefinition(key, propList, functionContext) {
var _this2 = this;
var _this3 = this;

@@ -247,12 +247,13 @@ var defs = this.schema(key);

var getPropIterator = function getPropIterator(obj) {
return function (val, prop) {
if (Array.isArray(propList) && !(0, _lodash14.default)(propList, prop)) return;
var getPropIterator = function getPropIterator(obj, newObj) {
return function (prop) {
if (Array.isArray(propList) && !(0, _lodash12.default)(propList, prop)) return;
var val = obj[prop];
// For any options that support specifying a function, evaluate the functions
if (propsThatCanBeFunction.indexOf(prop) > -1 && typeof val === 'function') {
obj[prop] = val.call(functionContext || {});
newObj[prop] = val.call(functionContext || {});
// Inflect label if undefined
if (prop === 'label' && typeof obj[prop] !== 'string') obj[prop] = inflectedLabel(key, _this2._constructorOptions.humanizeAutoLabels);
if (prop === 'label' && typeof newObj[prop] !== 'string') newObj[prop] = inflectedLabel(key, _this3._constructorOptions.humanizeAutoLabels);
} else {
obj[prop] = val;
newObj[prop] = val;
}

@@ -263,3 +264,3 @@ };

var result = {};
(0, _lodash2.default)(defs, getPropIterator(result));
Object.keys(defs).forEach(getPropIterator(defs, result));

@@ -271,3 +272,3 @@ // Resolve all the types and convert to a normal array to make it easier

var newTypeDef = {};
(0, _lodash2.default)(typeDef, getPropIterator(newTypeDef));
Object.keys(typeDef).forEach(getPropIterator(typeDef, newTypeDef));
return newTypeDef;

@@ -345,5 +346,6 @@ });

(0, _lodash2.default)(this.mergedSchema(), function (val, k) {
var mergedSchema = this.mergedSchema();
Object.keys(mergedSchema).forEach(function (k) {
if (k.indexOf(searchString) === 0) {
newSchemaDef[k.slice(searchString.length)] = val;
newSchemaDef[k.slice(searchString.length)] = mergedSchema[k];
}

@@ -361,8 +363,10 @@ });

value: function autoValueFunctions() {
var _this4 = this;
var result = [];
function addFuncs(autoValues, closestSubschemaFieldName) {
(0, _lodash2.default)(autoValues, function (func, fieldName) {
Object.keys(autoValues).forEach(function (fieldName) {
result.push({
func: func,
func: autoValues[fieldName],
fieldName: fieldName,

@@ -376,4 +380,4 @@ closestSubschemaFieldName: closestSubschemaFieldName

(0, _lodash2.default)(this._schema, function (keySchema, key) {
keySchema.type.definitions.forEach(function (typeDef) {
Object.keys(this._schema).forEach(function (key) {
_this4._schema[key].type.definitions.forEach(function (typeDef) {
if (!SimpleSchema.isSimpleSchema(typeDef.type)) return;

@@ -402,5 +406,7 @@ result = result.concat(typeDef.type.autoValueFunctions().map(function (_ref) {

value: function blackboxKeys() {
var _this5 = this;
var blackboxKeys = this._blackboxKeys;
(0, _lodash2.default)(this._schema, function (keySchema, key) {
keySchema.type.definitions.forEach(function (typeDef) {
Object.keys(this._schema).forEach(function (key) {
_this5._schema[key].type.definitions.forEach(function (typeDef) {
if (!SimpleSchema.isSimpleSchema(typeDef.type)) return;

@@ -412,3 +418,3 @@ typeDef.type._blackboxKeys.forEach(function (blackboxKey) {

});
return (0, _lodash12.default)(blackboxKeys);
return (0, _lodash10.default)(blackboxKeys);
}

@@ -421,10 +427,10 @@

value: function keyIsInBlackBox(key) {
var _this3 = this;
var _this6 = this;
var isInBlackBox = false;
(0, _utility.forEachKeyAncestor)(_mongoObject2.default.makeKeyGeneric(key), function (ancestor, remainder) {
if (_this3._blackboxKeys.indexOf(ancestor) > -1) {
if (_this6._blackboxKeys.indexOf(ancestor) > -1) {
isInBlackBox = true;
} else {
var testKeySchema = _this3.schema(ancestor);
var testKeySchema = _this6.schema(ancestor);
if (testKeySchema) {

@@ -448,3 +454,3 @@ testKeySchema.type.definitions.forEach(function (typeDef) {

value: function allowsKey(key) {
var _this4 = this;
var _this7 = this;

@@ -456,3 +462,3 @@ // Loop through all keys in the schema

var fieldSchema = _this4.schema(loopKey);
var fieldSchema = _this7.schema(loopKey);
var compare1 = key.slice(0, loopKey.length + 2);

@@ -466,3 +472,3 @@ var compare2 = compare1.slice(0, -1);

// Black box handling
if (_this4._blackboxKeys.indexOf(loopKey) > -1) {
if (_this7._blackboxKeys.indexOf(loopKey) > -1) {
// If the test key is the black box key + ".$", then the test

@@ -511,3 +517,3 @@ // key is NOT allowed because black box keys are by definition

value: function extend() {
var _this5 = this;
var _this8 = this;

@@ -529,19 +535,19 @@ var schema = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

// Update all of the information cached on the instance
(0, _lodash2.default)(schemaObj, function (definition, fieldName) {
definition = (0, _clone2.default)(definition);
Object.keys(schemaObj).forEach(function (fieldName) {
var definition = (0, _clone2.default)(schemaObj[fieldName]);
standardizeDefinition(definition);
// Merge/extend with any existing definition
if (_this5._schema[fieldName]) {
if (!_this5._schema.hasOwnProperty(fieldName)) {
if (_this8._schema[fieldName]) {
if (!_this8._schema.hasOwnProperty(fieldName)) {
// fieldName is actually a method from Object itself!
throw new Error(fieldName + ' key is actually the name of a method on Object, please rename it');
}
_this5._schema[fieldName] = _extends({}, _this5._schema[fieldName], (0, _lodash6.default)(definition, 'type'));
if (definition.type) _this5._schema[fieldName].type.extend(definition.type);
_this8._schema[fieldName] = _extends({}, _this8._schema[fieldName], (0, _lodash4.default)(definition, 'type'));
if (definition.type) _this8._schema[fieldName].type.extend(definition.type);
} else {
_this5._schema[fieldName] = definition;
_this8._schema[fieldName] = definition;
}
checkAndScrubDefinition(fieldName, _this5._schema[fieldName], _this5._constructorOptions, schemaObj);
checkAndScrubDefinition(fieldName, _this8._schema[fieldName], _this8._constructorOptions, schemaObj);
});

@@ -560,12 +566,14 @@

// Update all of the information cached on the instance
(0, _lodash2.default)(this._schema, function (definition, fieldName) {
Object.keys(this._schema).forEach(function (fieldName) {
var definition = _this8._schema[fieldName];
// Keep list of all keys for speedier checking
_this5._schemaKeys.push(fieldName);
_this8._schemaKeys.push(fieldName);
// Keep list of all top level keys
if (fieldName.indexOf('.') === -1) _this5._firstLevelSchemaKeys.push(fieldName);
if (fieldName.indexOf('.') === -1) _this8._firstLevelSchemaKeys.push(fieldName);
// Initialize label reactive dependency (Meteor only)
if (_this5._constructorOptions.tracker) {
_this5._depsLabels[fieldName] = new _this5._constructorOptions.tracker.Dependency();
if (_this8._constructorOptions.tracker) {
_this8._depsLabels[fieldName] = new _this8._constructorOptions.tracker.Dependency();
}

@@ -575,5 +583,5 @@

// XXX For now if any oneOf type is blackbox, then the whole field is.
(0, _lodash8.default)(definition.type.definitions, function (oneOfDef) {
(0, _lodash6.default)(definition.type.definitions, function (oneOfDef) {
if (oneOfDef.blackbox === true) {
_this5._blackboxKeys.push(fieldName);
_this8._blackboxKeys.push(fieldName);
return false; // exit loop

@@ -585,3 +593,3 @@ }

// Keep list of autoValue functions by key
if (definition.autoValue) _this5._autoValues[fieldName] = definition.autoValue;
if (definition.autoValue) _this8._autoValues[fieldName] = definition.autoValue;
});

@@ -592,3 +600,4 @@

var setObjectKeys = function setObjectKeys(curSchema, schemaParentKey) {
(0, _lodash2.default)(curSchema, function (definition, fieldName) {
Object.keys(curSchema).forEach(function (fieldName) {
var definition = curSchema[fieldName];
fieldName = schemaParentKey ? schemaParentKey + '.' + fieldName : fieldName;

@@ -598,4 +607,4 @@ if (fieldName.indexOf('.') > -1 && fieldName.slice(-2) !== '.$') {

var parentKeyWithDot = parentKey + '.';
_this5._objectKeys[parentKeyWithDot] = _this5._objectKeys[parentKeyWithDot] || [];
_this5._objectKeys[parentKeyWithDot].push(fieldName.slice(fieldName.lastIndexOf('.') + 1));
_this8._objectKeys[parentKeyWithDot] = _this8._objectKeys[parentKeyWithDot] || [];
_this8._objectKeys[parentKeyWithDot].push(fieldName.slice(fieldName.lastIndexOf('.') + 1));
}

@@ -666,3 +675,3 @@

value: function validate(obj, options) {
var _this6 = this;
var _this9 = this;

@@ -681,3 +690,3 @@ // For Meteor apps, `check` option can be passed to silence audit-argument-checks

objects.forEach(function (oneObj) {
var validationContext = _this6.newContext();
var validationContext = _this9.newContext();
var isValid = validationContext.validate(oneObj, options);

@@ -691,3 +700,3 @@

// we set it to the first validation error message.
var message = _this6.messageForError(errors[0]);
var message = _this9.messageForError(errors[0]);

@@ -702,3 +711,3 @@ var error = new Error(message);

error.details = errors.map(function (errorDetail) {
return _extends({}, errorDetail, { message: _this6.messageForError(errorDetail) });
return _extends({}, errorDetail, { message: _this9.messageForError(errorDetail) });
});

@@ -727,3 +736,3 @@

value: function validateAndReturnErrorsPromise(obj, options) {
var _this7 = this;
var _this10 = this;

@@ -737,3 +746,3 @@ var validationContext = this.newContext();

var errors = validationContext.validationErrors().map(function (errorDetail) {
return _extends({}, errorDetail, { message: _this7.messageForError(errorDetail) });
return _extends({}, errorDetail, { message: _this10.messageForError(errorDetail) });
});

@@ -746,3 +755,3 @@

value: function validator() {
var _this8 = this;
var _this11 = this;

@@ -755,9 +764,9 @@ var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};

// Do this here and pass into both functions for better performance
optionsClone.mongoObject = new _mongoObject2.default(obj, _this8.blackboxKeys());
_this8.clean(obj, optionsClone);
optionsClone.mongoObject = new _mongoObject2.default(obj, _this11.blackboxKeys());
_this11.clean(obj, optionsClone);
}
if (options.returnErrorsPromise) {
return _this8.validateAndReturnErrorsPromise(obj, optionsClone);
return _this11.validateAndReturnErrorsPromise(obj, optionsClone);
}
return _this8.validate(obj, optionsClone);
return _this11.validate(obj, optionsClone);
};

@@ -792,10 +801,11 @@ }

value: function labels(_labels) {
var _this9 = this;
var _this12 = this;
(0, _lodash2.default)(_labels, function (label, key) {
Object.keys(_labels).forEach(function (key) {
var label = _labels[key];
if (typeof label !== 'string' && typeof label !== 'function') return;
if (!_this9._schema.hasOwnProperty(key)) return;
if (!_this12._schema.hasOwnProperty(key)) return;
_this9._schema[key].label = label;
_this9._depsLabels[key] && _this9._depsLabels[key].changed();
_this12._schema[key].label = label;
_this12._depsLabels[key] && _this12._depsLabels[key].changed();
});

@@ -815,3 +825,3 @@ }

value: function label(key) {
var _this10 = this;
var _this13 = this;

@@ -821,4 +831,4 @@ // Get all labels

var result = {};
(0, _lodash2.default)(this._schemaKeys, function (schemaKey) {
result[schemaKey] = _this10.label(schemaKey);
this._schemaKeys.forEach(function (schemaKey) {
result[schemaKey] = _this13.label(schemaKey);
});

@@ -854,3 +864,3 @@ return result;

if ((0, _lodash14.default)(schemaDefinitionOptions, prop)) {
if ((0, _lodash12.default)(schemaDefinitionOptions, prop)) {
return def[prop];

@@ -1009,8 +1019,9 @@ }

function checkSchemaOverlap(schema) {
(0, _lodash2.default)(schema, function (val, key) {
Object.keys(schema).forEach(function (key) {
var val = schema[key];
if (!val.type) throw new Error(key + ' key is missing "type"');
(0, _lodash2.default)(val.type.definitions, function (def) {
val.type.definitions.forEach(function (def) {
if (!SimpleSchema.isSimpleSchema(def.type)) return;
(0, _lodash2.default)(def.type._schema, function (subVal, subKey) {
Object.keys(def.type._schema).forEach(function (subKey) {
var newKey = key + '.' + subKey;

@@ -1048,2 +1059,5 @@ if (schema.hasOwnProperty(newKey)) {

// If parent is set, we should update this position instead of $setOnInsert
if (this.parentField().isSet) return defaultValue;
// We don't know whether it's an upsert, but if it's not, this seems to be ignored,

@@ -1059,6 +1073,6 @@ // so this is a safe way to make sure the default value is added on upsert insert.

if (def.type && !(def.type instanceof _SimpleSchemaGroup2.default)) {
def.type = new _SimpleSchemaGroup2.default((0, _lodash10.default)(def, oneOfProps));
def.type = new _SimpleSchemaGroup2.default((0, _lodash8.default)(def, oneOfProps));
}
(0, _lodash4.default)(oneOfProps, 'type').forEach(function (prop) {
(0, _lodash2.default)(oneOfProps, 'type').forEach(function (prop) {
delete def[prop];

@@ -1073,3 +1087,3 @@ });

// Validate the field definition
(0, _lodash2.default)(definition, function (val, key) {
Object.keys(definition).forEach(function (key) {
if (schemaDefinitionOptions.indexOf(key) === -1) {

@@ -1091,3 +1105,3 @@ throw new Error('Invalid definition for ' + fieldName + ' field: "' + key + '" is not a supported property');

if (SimpleSchema.isSimpleSchema(type)) {
(0, _lodash2.default)(type._schema, function (subVal, subKey) {
Object.keys(type._schema).forEach(function (subKey) {
var newKey = fieldName + '.' + subKey;

@@ -1156,2 +1170,4 @@ if (fullSchemaObj.hasOwnProperty(newKey)) {

return function pickOrOmit() {
var _this14 = this;
for (var _len4 = arguments.length, args = Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {

@@ -1163,3 +1179,3 @@ args[_key4] = arguments[_key4];

var newSchema = {};
(0, _lodash2.default)(this._schema, function (value, key) {
Object.keys(this._schema).forEach(function (key) {
// Pick/omit it if it IS in the array of keys they want OR if it

@@ -1172,3 +1188,3 @@ // STARTS WITH something that is in the array plus a period

if (includeIt && type === 'pick' || !includeIt && type === 'omit') {
newSchema[key] = value;
newSchema[key] = _this14._schema[key];
}

@@ -1175,0 +1191,0 @@ });

@@ -9,3 +9,3 @@ 'use strict';

var _utility = require('../utility.js');
var _utility = require('../utility');

@@ -12,0 +12,0 @@ function doDateChecks(def, keyValue) {

@@ -9,2 +9,10 @@ 'use strict';

function getMapIterator(obj, matchKey, keyAdjust) {
return function (key) {
var val = obj[key];
if (val === undefined || val === null) return null;
if (keyAdjust(key) === matchKey) return key;
};
}
// Check for missing required values. The general logic is this:

@@ -23,16 +31,48 @@ // * If the operator is $unset or $rename, it's invalid.

// If value is null, no matter what, we add required
if (this.value === null) return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
// If operator would remove, we add required
if (this.operator === '$unset' || this.operator === '$rename') return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
// The rest of these apply only if the value is undefined
if (this.value !== undefined) return;
// At this point, if it's a normal, non-modifier object, then a missing value is an error
if (!this.operator) return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
// Everything beyond this point deals with modifier objects only
// We can skip the required check for keys that are ancestors
// of those in $set or $setOnInsert because they will be created
// by MongoDB while setting.
var setKeys = Object.keys(this.obj.$set || {}).concat(Object.keys(this.obj.$setOnInsert || {}));
var willBeCreatedAutomatically = setKeys.some(function (sk) {
return sk.slice(0, _this.key.length + 1) === _this.key + '.';
var obj = this.obj;
var keysWithValueInSet = Object.keys(obj.$set || {}).map(getMapIterator(obj.$set, this.key + '.', function (k) {
return k.slice(0, _this.key.length + 1);
})).filter(function (v) {
return !!v;
});
var keysWithValueInSetOnInsert = Object.keys(obj.$setOnInsert || {}).map(getMapIterator(obj.$setOnInsert, this.key + '.', function (k) {
return k.slice(0, _this.key.length + 1);
})).filter(function (v) {
return !!v;
});
var willBeCreatedAutomatically = keysWithValueInSet.concat(keysWithValueInSetOnInsert).some(function (v) {
return v;
});
if (willBeCreatedAutomatically) return;
if (this.value === null || this.operator === '$unset' || this.operator === '$rename' || this.value === undefined && (this.isInArrayItemObject || this.isInSubObject || !this.operator || this.operator === '$set')) {
return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
}
// In the case of $set and $setOnInsert, the value may be undefined here
// but it is set in another operator. So check that first.
var fieldInfo = this.field(this.key);
if (fieldInfo.isSet && fieldInfo.value !== null) return;
// Required if in an array or sub object
if (this.isInArrayItemObject || this.isInSubObject) return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
// If we've got this far with an undefined $set or $setOnInsert value,
// it's a required error.
if (this.operator === '$set' || this.operator === '$setOnInsert') return _SimpleSchema.SimpleSchema.ErrorTypes.REQUIRED;
}
exports.default = requiredValidator;

@@ -45,3 +45,3 @@ 'use strict';

if (expectedType === Object || expectedType instanceof _SimpleSchema.SimpleSchema) {
if (expectedType === Object || _SimpleSchema.SimpleSchema.isSimpleSchema(expectedType)) {
// Is it an object?

@@ -48,0 +48,0 @@ if (keyValue === Object(keyValue) && !(keyValue instanceof Date)) return;

{
"name": "simpl-schema",
"version": "0.5.0",
"version": "1.0.0",
"description": "A schema validation package that supports direct validation of MongoDB update modifier objects.",

@@ -24,4 +24,3 @@ "author": "Eric Dobbertin <aldeed@gmail.com>",

"lint": "eslint .",
"lint:fix": "eslint . --fix || true",
"prepublish": "npm test && npm run build",
"prepare": "npm run lint && npm test && npm run build",
"test": "mocha --compilers js:babel-core/register --recursive \"lib/**/*.tests.js\"",

@@ -33,8 +32,5 @@ "test:watch": "npm test -- --watch"

"extend": "^3.0.1",
"message-box": "^0.1.1",
"mongo-object": "^0.0.3",
"lodash.every": "^4.6.0",
"lodash.find": "^4.6.0",
"lodash.findwhere": "^3.1.0",
"lodash.foreach": "^4.5.0",
"lodash.every": "^4.6.0",
"lodash.includes": "^4.3.0",

@@ -44,6 +40,8 @@ "lodash.isempty": "^4.4.0",

"lodash.omit": "^4.5.0",
"lodash.without": "^4.4.0",
"lodash.pick": "^4.4.0",
"lodash.union": "^4.6.0",
"lodash.uniq": "^4.5.0"
"lodash.uniq": "^4.5.0",
"lodash.without": "^4.4.0",
"message-box": "^0.1.1",
"mongo-object": "^0.0.3"
},

@@ -50,0 +48,0 @@ "devDependencies": {

@@ -142,2 +142,29 @@ # simple-schema

### Validate a Meteor Method Argument and Satisfy `audit-argument-checks`
To avoid errors about not checking all arguments when you are using SimpleSchema to validate Meteor method arguments, you must pass `check` as an option when creating your SimpleSchema instance.
```js
import SimpleSchema from 'simpl-schema';
import { check } from 'meteor/check';
import { Meteor } from 'meteor/meteor';
SimpleSchema.defineValidationErrorTransform(error => {
const ddpError = new Meteor.Error(error.message);
ddpError.error = 'validation-error';
ddpError.details = error.details;
return ddpError;
});
const myMethodObjArgSchema = new SimpleSchema({ name: String }, { check });
Meteor.methods({
myMethod(obj) {
myMethodObjArgSchema.validate(obj);
// Now do other method stuff knowing that obj satisfies the schema
},
});
```
### Validate an Object and Get the Errors

@@ -685,3 +712,3 @@

Set this to any value that you want to be used as the default when an object does not include this field or has this field set to `undefined`. This value will be injected into the object by a call to `mySimpleSchema.clean()` with `getAutovalues: true`. Default values are set only when cleaning *non-modifier* objects.
Set this to any value that you want to be used as the default when an object does not include this field or has this field set to `undefined`. This value will be injected into the object by a call to `mySimpleSchema.clean()` with `getAutovalues: true`.

@@ -691,3 +718,3 @@ Note the following points of confusion:

* A default value itself is not cleaned. So, for example, if your default value is "", it will not be removed by the `removeEmptyStrings` operation in the cleaning.
* A default value is *always* added if there isn't a value set. Even if the property is a child of an optional object, and the optional object is not present, the object will be added and its property will be set to the default value. Effectively, this means that if you provide a default value for one property of an object, you must provide a default value for all properties of that object or risk confusing validation errors.
* A default value is added only if there isn't a value set AND the parent object exists. Usually this is what you want, but if you need to ensure that it will always be added, you can add `defaultValue: {}` to all ancestor objects.

@@ -718,2 +745,3 @@ If you need more control, use the `autoValue` option instead.

* `siblingField()`: Use this method to get information about other fields that have the same parent object. Works the same way as `field()`. This is helpful when you use sub-schemas or when you're dealing with arrays of objects.
* `parentField()`: Use this method to get information about the parent object. Works the same way as `field()`.

@@ -720,0 +748,0 @@ ### Getting field properties

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