Skip to content

Instantly share code, notes, and snippets.

@kbjr
Created June 13, 2015 20:25
Show Gist options
  • Save kbjr/84d14c0b096bdd56d03c to your computer and use it in GitHub Desktop.
Save kbjr/84d14c0b096bdd56d03c to your computer and use it in GitHub Desktop.
Find Object Scope
//
// Finds a specified property path in a nested object structure
//
// @param {obj} the object to search
// @param {path} the property path (eg. "foo.bar.[0].{baz:qux}.property")
// @return object
//
function findObjectScope(obj, path) {
var scope = obj;
var steps = path.split('.');
var property = steps.pop();
var current;
var parsed;
try {
while (current = steps.shift()) {
parsed = parseProperty(current);
parsed = stepDownKey(scope, parsed);
scope = scope[parsed];
}
current = property;
property = parseProperty(property);
property = stepDownKey(scope, property);
}
// If any error occurs during the parsing, return a dummy object
// with an error message
catch (err) {
return {
error: err,
current: current,
object: obj,
path: path,
scope: scope,
property: null,
get: function() { /* noop */ },
set: function() { /* noop */ }
};
}
// Return the "scoped" object property descriptor
return {
error: null,
current: current,
object: obj,
path: path,
scope: scope,
property: property,
get: function() {
return scope[property];
},
set: function(value) {
scope[property] = value;
}
};
}
//
// Parses a single property step in the path
//
// @param {prop} the property string (eg. "foo", "[0]", or "{bar:baz}")
// @return string|array
//
function parseProperty(prop) {
var wrapped;
// "Array" style bracket syntax
if (wrapped = wrappedIn(prop, '[', ']')) {
return wrapped;
}
// "Object" style key:value pair syntax
else if (wrapped = wrappedIn(prop, '{', '}')) {
return wrapped.split(':');
}
// "Standard" string property name
else {
return prop;
}
}
//
// Determines if a string is wrapped in the given characters, and returns the unwrapped
// string if it is
//
// @param {str} the string to check
// @param {begin} the opening string
// @param {end} the closing string
// @return string|false
//
function wrappedIn(str, begin, end) {
if (str[0] === begin && str.slice(-1) === end) {
return str.slice(1, -1);
}
return false;
}
//
// Given a parsed property from `parseProperty`, find the actual matching property name
// on the real object so we can step down into the next scope
//
// @param {obj} the object to look in
// @param {prop} the property to look for
// @return string
//
function stepDownKey(obj, prop) {
if (Array.isArray(prop)) {
Object.keys(obj).some(function(key) {
var value = obj[key];
if (value && typeof value === 'object' && value[prop[0]] === prop[1]) {
prop = key;
return true;
}
});
}
return prop;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment