You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

164 lines
4.1 KiB

'use strict';
var Document;
var utils = require('../../utils');
/*!
* exports
*/
exports.compile = compile;
exports.defineKey = defineKey;
/*!
* Compiles schemas.
*/
function compile(tree, proto, prefix, options) {
Document = Document || require('../../document');
var keys = Object.keys(tree);
var i = keys.length;
var len = keys.length;
var limb;
var key;
if (options.retainKeyOrder) {
for (i = 0; i < len; ++i) {
key = keys[i];
limb = tree[key];
defineKey(key,
((utils.getFunctionName(limb.constructor) === 'Object'
&& Object.keys(limb).length)
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
? limb
: null)
, proto
, prefix
, keys
, options);
}
} else {
while (i--) {
key = keys[i];
limb = tree[key];
defineKey(key,
((utils.getFunctionName(limb.constructor) === 'Object'
&& Object.keys(limb).length)
&& (!limb[options.typeKey] || (options.typeKey === 'type' && limb.type.type))
? limb
: null)
, proto
, prefix
, keys
, options);
}
}
}
/*!
* Defines the accessor named prop on the incoming prototype.
*/
function defineKey(prop, subprops, prototype, prefix, keys, options) {
Document = Document || require('../../document');
var path = (prefix ? prefix + '.' : '') + prop;
prefix = prefix || '';
if (subprops) {
Object.defineProperty(prototype, prop, {
enumerable: true,
configurable: true,
get: function() {
var _this = this;
if (!this.$__.getters) {
this.$__.getters = {};
}
if (!this.$__.getters[path]) {
var nested = Object.create(Document.prototype, getOwnPropertyDescriptors(this));
// save scope for nested getters/setters
if (!prefix) {
nested.$__.scope = this;
}
nested.$__.nestedPath = path;
Object.defineProperty(nested, 'schema', {
enumerable: false,
configurable: true,
writable: false,
value: prototype.schema
});
Object.defineProperty(nested, 'toObject', {
enumerable: false,
configurable: true,
writable: false,
value: function() {
return utils.clone(_this.get(path), { retainKeyOrder: true });
}
});
Object.defineProperty(nested, 'toJSON', {
enumerable: false,
configurable: true,
writable: false,
value: function() {
return _this.get(path);
}
});
Object.defineProperty(nested, '$__isNested', {
enumerable: false,
configurable: true,
writable: false,
value: true
});
compile(subprops, nested, path, options);
this.$__.getters[path] = nested;
}
return this.$__.getters[path];
},
set: function(v) {
if (v instanceof Document) {
v = v.toObject({ transform: false });
}
var doc = this.$__.scope || this;
return doc.$set(path, v);
}
});
} else {
Object.defineProperty(prototype, prop, {
enumerable: true,
configurable: true,
get: function() {
return this.get.call(this.$__.scope || this, path);
},
set: function(v) {
return this.$set.call(this.$__.scope || this, path, v);
}
});
}
}
// gets descriptors for all properties of `object`
// makes all properties non-enumerable to match previous behavior to #2211
function getOwnPropertyDescriptors(object) {
var result = {};
Object.getOwnPropertyNames(object).forEach(function(key) {
result[key] = Object.getOwnPropertyDescriptor(object, key);
// Assume these are schema paths, ignore them re: #5470
if (result[key].get) {
delete result[key];
return;
}
result[key].enumerable = ['isNew', '$__', 'errors', '_doc'].indexOf(key) === -1;
});
return result;
}