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.
		
		
		
		
		
			
		
			
				
					
					
						
							239 lines
						
					
					
						
							6.8 KiB
						
					
					
				
			
		
		
	
	
							239 lines
						
					
					
						
							6.8 KiB
						
					
					
				'use strict'; | 
						|
 | 
						|
 | 
						|
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, '~'); | 
						|
}
 | 
						|
 |