UNPKG

property-expr-csp

Version:

tiny util for getting and setting deep object props safely

127 lines (108 loc) 2.87 kB
/** * Based on Kendo UI Core expression code <https://github.com/telerik/kendo-ui-core#license-information> * And on the original property-expr package <https://github.com/jquense/expr> */ 'use strict' var SPLIT_REGEX = /[^.^\]^[]+|(?=\[\]|\.\.)/g, DIGIT_REGEX = /^\d+$/, LEAD_DIGIT_REGEX = /^\d/, SPEC_CHAR_REGEX = /[~`!#$%\^&*+=\-\[\]\\';,/{}|\\":<>\?]/g, NO_QUOTES_REGEX = /^\s*(['"])(.*)(\1)\s*$/, BREAK_FOR_EACH_SYMBOL = {} module.exports = { forEach: forEach, setter: function(path) { return function(data, value) { return setter(path, data, value) } }, getter: function(path, safe) { return function(data) { return getter(path, data, safe) } }, split: function(path) { return path.match(SPLIT_REGEX) }, join: function(segments) { return segments.reduce(function(path, part) { return ( path + (isQuoted(part) || DIGIT_REGEX.test(part) ? '[' + part + ']' : (path ? '.' : '') + part) ) }, '') } } function setter(path, data, value) { forEach(path, function(part, isBracket, isArray, idx, parts) { part = normalizePropertyName(part, isBracket, isArray) if (idx === parts.length - 1) { data[part] = value } else { data = data[part] } }) } function getter(path, data, safe) { var value forEach(path, function(part, isBracket, isArray, idx, parts) { if (safe && !data) { return BREAK_FOR_EACH_SYMBOL } part = normalizePropertyName(part, isBracket, isArray) data = data[part] if (idx === parts.length - 1) { value = data } else if (safe) { data = data || {} } }) return value } function forEach(path, cb, thisArg) { forEachPart(path.match(SPLIT_REGEX), cb, thisArg) } function forEachPart(parts, iter, thisArg) { var len = parts.length, part, idx, isArray, isBracket for (idx = 0; idx < len; idx++) { part = parts[idx] if (part) { if (shouldBeQuoted(part)) { part = '"' + part + '"' } isBracket = isQuoted(part) isArray = !isBracket && /^\d+$/.test(part) if (iter.call(thisArg, part, isBracket, isArray, idx, parts) === BREAK_FOR_EACH_SYMBOL) { break } } } } function isQuoted(str) { return ( typeof str === 'string' && str && ["'", '"'].indexOf(str.charAt(0)) !== -1 ) } function normalizePropertyName(part, isBracket, isArray) { if (isBracket && !isArray) { part = part.replace(NO_QUOTES_REGEX, '$2') } else { part = part.trim() } return part } function hasLeadingNumber(part) { return part.match(LEAD_DIGIT_REGEX) && !part.match(DIGIT_REGEX) } function hasSpecialChars(part) { return SPEC_CHAR_REGEX.test(part) } function shouldBeQuoted(part) { return !isQuoted(part) && (hasLeadingNumber(part) || hasSpecialChars(part)) }