Spaces:
Running
Running
; | |
module.exports = { | |
copy: copy, | |
checkDataType: checkDataType, | |
checkDataTypes: checkDataTypes, | |
coerceToTypes: coerceToTypes, | |
toHash: toHash, | |
getProperty: getProperty, | |
escapeQuotes: escapeQuotes, | |
equal: require('fast-deep-equal'), | |
ucs2length: require('./ucs2length'), | |
varOccurences: varOccurences, | |
varReplace: varReplace, | |
schemaHasRules: schemaHasRules, | |
schemaHasRulesExcept: schemaHasRulesExcept, | |
schemaUnknownRules: schemaUnknownRules, | |
toQuotedString: toQuotedString, | |
getPathExpr: getPathExpr, | |
getPath: getPath, | |
getData: getData, | |
unescapeFragment: unescapeFragment, | |
unescapeJsonPointer: unescapeJsonPointer, | |
escapeFragment: escapeFragment, | |
escapeJsonPointer: escapeJsonPointer | |
}; | |
function copy(o, to) { | |
to = to || {}; | |
for (var key in o) to[key] = o[key]; | |
return to; | |
} | |
function checkDataType(dataType, data, strictNumbers, negate) { | |
var EQUAL = negate ? ' !== ' : ' === ' | |
, AND = negate ? ' || ' : ' && ' | |
, OK = negate ? '!' : '' | |
, NOT = negate ? '' : '!'; | |
switch (dataType) { | |
case 'null': return data + EQUAL + 'null'; | |
case 'array': return OK + 'Array.isArray(' + data + ')'; | |
case 'object': return '(' + OK + data + AND + | |
'typeof ' + data + EQUAL + '"object"' + AND + | |
NOT + 'Array.isArray(' + data + '))'; | |
case 'integer': return '(typeof ' + data + EQUAL + '"number"' + AND + | |
NOT + '(' + data + ' % 1)' + | |
AND + data + EQUAL + data + | |
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')'; | |
case 'number': return '(typeof ' + data + EQUAL + '"' + dataType + '"' + | |
(strictNumbers ? (AND + OK + 'isFinite(' + data + ')') : '') + ')'; | |
default: return 'typeof ' + data + EQUAL + '"' + dataType + '"'; | |
} | |
} | |
function checkDataTypes(dataTypes, data, strictNumbers) { | |
switch (dataTypes.length) { | |
case 1: return checkDataType(dataTypes[0], data, strictNumbers, true); | |
default: | |
var code = ''; | |
var types = toHash(dataTypes); | |
if (types.array && types.object) { | |
code = types.null ? '(': '(!' + data + ' || '; | |
code += 'typeof ' + data + ' !== "object")'; | |
delete types.null; | |
delete types.array; | |
delete types.object; | |
} | |
if (types.number) delete types.integer; | |
for (var t in types) | |
code += (code ? ' && ' : '' ) + checkDataType(t, data, strictNumbers, true); | |
return code; | |
} | |
} | |
var COERCE_TO_TYPES = toHash([ 'string', 'number', 'integer', 'boolean', 'null' ]); | |
function coerceToTypes(optionCoerceTypes, dataTypes) { | |
if (Array.isArray(dataTypes)) { | |
var types = []; | |
for (var i=0; i<dataTypes.length; i++) { | |
var t = dataTypes[i]; | |
if (COERCE_TO_TYPES[t]) types[types.length] = t; | |
else if (optionCoerceTypes === 'array' && t === 'array') types[types.length] = t; | |
} | |
if (types.length) return types; | |
} else if (COERCE_TO_TYPES[dataTypes]) { | |
return [dataTypes]; | |
} else if (optionCoerceTypes === 'array' && dataTypes === 'array') { | |
return ['array']; | |
} | |
} | |
function toHash(arr) { | |
var hash = {}; | |
for (var i=0; i<arr.length; i++) hash[arr[i]] = true; | |
return hash; | |
} | |
var IDENTIFIER = /^[a-z$_][a-z$_0-9]*$/i; | |
var SINGLE_QUOTE = /'|\\/g; | |
function getProperty(key) { | |
return typeof key == 'number' | |
? '[' + key + ']' | |
: IDENTIFIER.test(key) | |
? '.' + key | |
: "['" + escapeQuotes(key) + "']"; | |
} | |
function escapeQuotes(str) { | |
return str.replace(SINGLE_QUOTE, '\\$&') | |
.replace(/\n/g, '\\n') | |
.replace(/\r/g, '\\r') | |
.replace(/\f/g, '\\f') | |
.replace(/\t/g, '\\t'); | |
} | |
function varOccurences(str, dataVar) { | |
dataVar += '[^0-9]'; | |
var matches = str.match(new RegExp(dataVar, 'g')); | |
return matches ? matches.length : 0; | |
} | |
function varReplace(str, dataVar, expr) { | |
dataVar += '([^0-9])'; | |
expr = expr.replace(/\$/g, '$$$$'); | |
return str.replace(new RegExp(dataVar, 'g'), expr + '$1'); | |
} | |
function schemaHasRules(schema, rules) { | |
if (typeof schema == 'boolean') return !schema; | |
for (var key in schema) if (rules[key]) return true; | |
} | |
function schemaHasRulesExcept(schema, rules, exceptKeyword) { | |
if (typeof schema == 'boolean') return !schema && exceptKeyword != 'not'; | |
for (var key in schema) if (key != exceptKeyword && rules[key]) return true; | |
} | |
function schemaUnknownRules(schema, rules) { | |
if (typeof schema == 'boolean') return; | |
for (var key in schema) if (!rules[key]) return key; | |
} | |
function toQuotedString(str) { | |
return '\'' + escapeQuotes(str) + '\''; | |
} | |
function getPathExpr(currentPath, expr, jsonPointers, isNumber) { | |
var path = jsonPointers // false by default | |
? '\'/\' + ' + expr + (isNumber ? '' : '.replace(/~/g, \'~0\').replace(/\\//g, \'~1\')') | |
: (isNumber ? '\'[\' + ' + expr + ' + \']\'' : '\'[\\\'\' + ' + expr + ' + \'\\\']\''); | |
return joinPaths(currentPath, path); | |
} | |
function getPath(currentPath, prop, jsonPointers) { | |
var path = jsonPointers // false by default | |
? toQuotedString('/' + escapeJsonPointer(prop)) | |
: toQuotedString(getProperty(prop)); | |
return joinPaths(currentPath, path); | |
} | |
var JSON_POINTER = /^\/(?:[^~]|~0|~1)*$/; | |
var RELATIVE_JSON_POINTER = /^([0-9]+)(#|\/(?:[^~]|~0|~1)*)?$/; | |
function getData($data, lvl, paths) { | |
var up, jsonPointer, data, matches; | |
if ($data === '') return 'rootData'; | |
if ($data[0] == '/') { | |
if (!JSON_POINTER.test($data)) throw new Error('Invalid JSON-pointer: ' + $data); | |
jsonPointer = $data; | |
data = 'rootData'; | |
} else { | |
matches = $data.match(RELATIVE_JSON_POINTER); | |
if (!matches) throw new Error('Invalid JSON-pointer: ' + $data); | |
up = +matches[1]; | |
jsonPointer = matches[2]; | |
if (jsonPointer == '#') { | |
if (up >= lvl) throw new Error('Cannot access property/index ' + up + ' levels up, current level is ' + lvl); | |
return paths[lvl - up]; | |
} | |
if (up > lvl) throw new Error('Cannot access data ' + up + ' levels up, current level is ' + lvl); | |
data = 'data' + ((lvl - up) || ''); | |
if (!jsonPointer) return data; | |
} | |
var expr = data; | |
var segments = jsonPointer.split('/'); | |
for (var i=0; i<segments.length; i++) { | |
var segment = segments[i]; | |
if (segment) { | |
data += getProperty(unescapeJsonPointer(segment)); | |
expr += ' && ' + data; | |
} | |
} | |
return expr; | |
} | |
function joinPaths (a, b) { | |
if (a == '""') return b; | |
return (a + ' + ' + b).replace(/([^\\])' \+ '/g, '$1'); | |
} | |
function unescapeFragment(str) { | |
return unescapeJsonPointer(decodeURIComponent(str)); | |
} | |
function escapeFragment(str) { | |
return encodeURIComponent(escapeJsonPointer(str)); | |
} | |
function escapeJsonPointer(str) { | |
return str.replace(/~/g, '~0').replace(/\//g, '~1'); | |
} | |
function unescapeJsonPointer(str) { | |
return str.replace(/~1/g, '/').replace(/~0/g, '~'); | |
} | |