File: /var/dev/nowruzgan/rest/node_modules/rttc/lib/get-path-info.js
/**
* Module dependencies
*/
var _ = require('lodash');
var TYPES = require('./helpers/types');
var dehydrate = require('./dehydrate');
var buildSchemaIterator = require('./helpers/build-schema-iterator');
/**
* Given an exemplar schema and a keypath, return information
* about the specified segment.
*
* If the path is inside of a generic, then the exemplar is '*',
* and this path is optional. If the path is inside of a `ref`,
* then the exemplar is '===', and this path is optional.
*
*
* @param {*} schema - an exemplar or type schema
* @param {String} path - a valid dot-deliminited path, where empty string ('') is the root (e.g. "" or "foo" or "foo.bar" or "foo.0.bar.0.baz")
*
* @returns {Dictionary}
* @property {*} exemplar
* @property {Boolean} optional
*
* @throws E_MALFORMED_PATH
* If keypath is invalid for the provided schema
*
* @throws E_UNREACHABLE
* if keypath is unreachable (meaning it is not allowed in the schema)
*/
module.exports = function getPathInfo (schema, path) {
// Dehydrate the schema to avoid circular recursion
var dehydratedSchema = dehydrate(schema);
// Derive an array of "hops" from the provided keypath.
var hops = (path === '') ? [] : path.split('.');
// These variables are used by the iterator below.
var currentExemplar = dehydratedSchema;
// By default the path is not optional.
var optional = false;
_.each(hops, function dereferenceEach(hop){
if (_.isArray(currentExemplar)) {
if (!_.isFinite(+hop)) {
// If the hop cannot be cast to a positive integer,
// something funny is going on.
throw (function (){
var err = new Error('Malformed keypath: "'+path+'" (non-numeric hop `'+hop+'` is not a valid array index)');
err.code = 'E_MALFORMED_PATH';
return err;
})();
}
// generic array
if (_.isEqual(currentExemplar, [])) {
optional = true;
currentExemplar = TYPES.json.getExemplar();
}
// patterned array
else {
optional = false;
if (_.isUndefined(currentExemplar[0])) {
throw (function (){
var err = new Error('Keypath: "'+path+'" is unreachable in schema');
err.code = 'E_UNREACHABLE';
return err;
})();
}
else {
currentExemplar = currentExemplar[0];
}
}
}
else if (_.isObject(currentExemplar)) {
// generic dictionary
if (_.isEqual(currentExemplar, {})) {
optional = true;
currentExemplar = TYPES.json.getExemplar();
}
// facted dictionary
else {
optional = false;
if (_.isUndefined(currentExemplar[hop])) {
throw (function (){
var err = new Error('Keypath: "'+path+'" is unreachable in schema');
err.code = 'E_UNREACHABLE';
return err;
})();
}
else {
currentExemplar = currentExemplar[hop];
}
}
}
// generic json
else if (TYPES.json.isExemplar(currentExemplar)) {
optional = true;
currentExemplar = TYPES.json.getExemplar();
}
// mutable reference
else if (TYPES.ref.isExemplar(currentExemplar)) {
optional = true;
currentExemplar = TYPES.ref.getExemplar();
}
// lamda
else if (TYPES.lamda.isExemplar(currentExemplar)) {
throw (function (){
var err = new Error('Keypath: "'+path+'" is unreachable in schema');
err.code = 'E_UNREACHABLE';
return err;
})();
}
// primitive
else {
throw (function (){
var err = new Error('Keypath: "'+path+'" is unreachable in schema');
err.code = 'E_UNREACHABLE';
return err;
})();
}
});
return {
exemplar: currentExemplar,
optional: optional
};
};