UNPKG

dynatrace-cordova-outsystems-plugin

Version:

This plugin gives you the ability to use the Dynatrace instrumentation in your hybrid application (Cordova, Ionic, ..). It uses the Mobile Agent, the JavaScript Agent and the Javascript Bridge. The Mobile Agent will give you all device specific values con

604 lines (496 loc) 17.5 kB
var genobj = require('generate-object-property') var genfun = require('generate-function') var jsonpointer = require('jsonpointer') var xtend = require('xtend') var formats = require('./formats') var get = function(obj, additionalSchemas, ptr) { var visit = function(sub) { if (sub && sub.id === ptr) return sub if (typeof sub !== 'object' || !sub) return null return Object.keys(sub).reduce(function(res, k) { return res || visit(sub[k]) }, null) } var res = visit(obj) if (res) return res ptr = ptr.replace(/^#/, '') ptr = ptr.replace(/\/$/, '') try { return jsonpointer.get(obj, decodeURI(ptr)) } catch (err) { var end = ptr.indexOf('#') var other // external reference if (end !== 0) { // fragment doesn't exist. if (end === -1) { other = additionalSchemas[ptr] } else { var ext = ptr.slice(0, end) other = additionalSchemas[ext] var fragment = ptr.slice(end).replace(/^#/, '') try { return jsonpointer.get(other, fragment) } catch (err) {} } } else { other = additionalSchemas[ptr] } return other || null } } var formatName = function(field) { field = JSON.stringify(field) var pattern = /\[([^\[\]"]+)\]/ while (pattern.test(field)) field = field.replace(pattern, '."+$1+"') return field } var types = {} types.any = function() { return 'true' } types.null = function(name) { return name+' === null' } types.boolean = function(name) { return 'typeof '+name+' === "boolean"' } types.array = function(name) { return 'Array.isArray('+name+')' } types.object = function(name) { return 'typeof '+name+' === "object" && '+name+' && !Array.isArray('+name+')' } types.number = function(name) { return 'typeof '+name+' === "number" && isFinite('+name+')' } types.integer = function(name) { return 'typeof '+name+' === "number" && (Math.floor('+name+') === '+name+' || '+name+' > 9007199254740992 || '+name+' < -9007199254740992)' } types.string = function(name) { return 'typeof '+name+' === "string"' } var unique = function(array) { var list = [] for (var i = 0; i < array.length; i++) { list.push(typeof array[i] === 'object' ? JSON.stringify(array[i]) : array[i]) } for (var i = 1; i < list.length; i++) { if (list.indexOf(list[i]) !== i) return false } return true } var isMultipleOf = function(name, multipleOf) { var res; var factor = ((multipleOf | 0) !== multipleOf) ? Math.pow(10, multipleOf.toString().split('.').pop().length) : 1 if (factor > 1) { var factorName = ((name | 0) !== name) ? Math.pow(10, name.toString().split('.').pop().length) : 1 if (factorName > factor) res = true else res = Math.round(factor * name) % (factor * multipleOf) } else res = name % multipleOf; return !res; } var compile = function(schema, cache, root, reporter, opts) { var fmts = opts ? xtend(formats, opts.formats) : formats var scope = {unique:unique, formats:fmts, isMultipleOf:isMultipleOf} var verbose = opts ? !!opts.verbose : false; var greedy = opts && opts.greedy !== undefined ? opts.greedy : false; var syms = {} var gensym = function(name) { return name+(syms[name] = (syms[name] || 0)+1) } var reversePatterns = {} var patterns = function(p) { if (reversePatterns[p]) return reversePatterns[p] var n = gensym('pattern') scope[n] = new RegExp(p) reversePatterns[p] = n return n } var vars = ['i','j','k','l','m','n','o','p','q','r','s','t','u','v','x','y','z'] var genloop = function() { var v = vars.shift() vars.push(v+v[0]) return v } var visit = function(name, node, reporter, filter, schemaPath) { var properties = node.properties var type = node.type var tuple = false if (Array.isArray(node.items)) { // tuple type properties = {} node.items.forEach(function(item, i) { properties[i] = item }) type = 'array' tuple = true } var indent = 0 var error = function(msg, prop, value) { validate('errors++') if (reporter === true) { validate('if (validate.errors === null) validate.errors = []') if (verbose) { validate( 'validate.errors.push({field:%s,message:%s,value:%s,type:%s,schemaPath:%s})', formatName(prop || name), JSON.stringify(msg), value || name, JSON.stringify(type), JSON.stringify(schemaPath) ) } else { validate('validate.errors.push({field:%s,message:%s})', formatName(prop || name), JSON.stringify(msg)) } } } if (node.required === true) { indent++ validate('if (%s === undefined) {', name) error('is required') validate('} else {') } else { indent++ validate('if (%s !== undefined) {', name) } var valid = [].concat(type) .map(function(t) { if (t && !types.hasOwnProperty(t)) { throw new Error('Unknown type: ' + t) } return types[t || 'any'](name) }) .join(' || ') || 'true' if (valid !== 'true') { indent++ validate('if (!(%s)) {', valid) error('is the wrong type') validate('} else {') } if (tuple) { if (node.additionalItems === false) { validate('if (%s.length > %d) {', name, node.items.length) error('has additional items') validate('}') } else if (node.additionalItems) { var i = genloop() validate('for (var %s = %d; %s < %s.length; %s++) {', i, node.items.length, i, name, i) visit(name+'['+i+']', node.additionalItems, reporter, filter, schemaPath.concat('additionalItems')) validate('}') } } if (node.format && fmts[node.format]) { if (type !== 'string' && formats[node.format]) validate('if (%s) {', types.string(name)) var n = gensym('format') scope[n] = fmts[node.format] if (typeof scope[n] === 'function') validate('if (!%s(%s)) {', n, name) else validate('if (!%s.test(%s)) {', n, name) error('must be '+node.format+' format') validate('}') if (type !== 'string' && formats[node.format]) validate('}') } if (Array.isArray(node.required)) { var checkRequired = function (req) { var prop = genobj(name, req); validate('if (%s === undefined) {', prop) error('is required', prop) validate('missing++') validate('}') } validate('if ((%s)) {', type !== 'object' ? types.object(name) : 'true') validate('var missing = 0') node.required.map(checkRequired) validate('}'); if (!greedy) { validate('if (missing === 0) {') indent++ } } if (node.uniqueItems) { if (type !== 'array') validate('if (%s) {', types.array(name)) validate('if (!(unique(%s))) {', name) error('must be unique') validate('}') if (type !== 'array') validate('}') } if (node.enum) { var complex = node.enum.some(function(e) { return typeof e === 'object' }) var compare = complex ? function(e) { return 'JSON.stringify('+name+')'+' !== JSON.stringify('+JSON.stringify(e)+')' } : function(e) { return name+' !== '+JSON.stringify(e) } validate('if (%s) {', node.enum.map(compare).join(' && ') || 'false') error('must be an enum value') validate('}') } if (node.dependencies) { if (type !== 'object') validate('if (%s) {', types.object(name)) Object.keys(node.dependencies).forEach(function(key) { var deps = node.dependencies[key] if (typeof deps === 'string') deps = [deps] var exists = function(k) { return genobj(name, k) + ' !== undefined' } if (Array.isArray(deps)) { validate('if (%s !== undefined && !(%s)) {', genobj(name, key), deps.map(exists).join(' && ') || 'true') error('dependencies not set') validate('}') } if (typeof deps === 'object') { validate('if (%s !== undefined) {', genobj(name, key)) visit(name, deps, reporter, filter, schemaPath.concat(['dependencies', key])) validate('}') } }) if (type !== 'object') validate('}') } if (node.additionalProperties || node.additionalProperties === false) { if (type !== 'object') validate('if (%s) {', types.object(name)) var i = genloop() var keys = gensym('keys') var toCompare = function(p) { return keys+'['+i+'] !== '+JSON.stringify(p) } var toTest = function(p) { return '!'+patterns(p)+'.test('+keys+'['+i+'])' } var additionalProp = Object.keys(properties || {}).map(toCompare) .concat(Object.keys(node.patternProperties || {}).map(toTest)) .join(' && ') || 'true' validate('var %s = Object.keys(%s)', keys, name) ('for (var %s = 0; %s < %s.length; %s++) {', i, i, keys, i) ('if (%s) {', additionalProp) if (node.additionalProperties === false) { if (filter) validate('delete %s', name+'['+keys+'['+i+']]') error('has additional properties', null, JSON.stringify(name+'.') + ' + ' + keys + '['+i+']') } else { visit(name+'['+keys+'['+i+']]', node.additionalProperties, reporter, filter, schemaPath.concat(['additionalProperties'])) } validate ('}') ('}') if (type !== 'object') validate('}') } if (node.$ref) { var sub = get(root, opts && opts.schemas || {}, node.$ref) if (sub) { var fn = cache[node.$ref] if (!fn) { cache[node.$ref] = function proxy(data) { return fn(data) } fn = compile(sub, cache, root, false, opts) } var n = gensym('ref') scope[n] = fn validate('if (!(%s(%s))) {', n, name) error('referenced schema does not match') validate('}') } } if (node.not) { var prev = gensym('prev') validate('var %s = errors', prev) visit(name, node.not, false, filter, schemaPath.concat('not')) validate('if (%s === errors) {', prev) error('negative schema matches') validate('} else {') ('errors = %s', prev) ('}') } if (node.items && !tuple) { if (type !== 'array') validate('if (%s) {', types.array(name)) var i = genloop() validate('for (var %s = 0; %s < %s.length; %s++) {', i, i, name, i) visit(name+'['+i+']', node.items, reporter, filter, schemaPath.concat('items')) validate('}') if (type !== 'array') validate('}') } if (node.patternProperties) { if (type !== 'object') validate('if (%s) {', types.object(name)) var keys = gensym('keys') var i = genloop() validate ('var %s = Object.keys(%s)', keys, name) ('for (var %s = 0; %s < %s.length; %s++) {', i, i, keys, i) Object.keys(node.patternProperties).forEach(function(key) { var p = patterns(key) validate('if (%s.test(%s)) {', p, keys+'['+i+']') visit(name+'['+keys+'['+i+']]', node.patternProperties[key], reporter, filter, schemaPath.concat(['patternProperties', key])) validate('}') }) validate('}') if (type !== 'object') validate('}') } if (node.pattern) { var p = patterns(node.pattern) if (type !== 'string') validate('if (%s) {', types.string(name)) validate('if (!(%s.test(%s))) {', p, name) error('pattern mismatch') validate('}') if (type !== 'string') validate('}') } if (node.allOf) { node.allOf.forEach(function(sch, key) { visit(name, sch, reporter, filter, schemaPath.concat(['allOf', key])) }) } if (node.anyOf && node.anyOf.length) { var prev = gensym('prev') node.anyOf.forEach(function(sch, i) { if (i === 0) { validate('var %s = errors', prev) } else { validate('if (errors !== %s) {', prev) ('errors = %s', prev) } visit(name, sch, false, false, schemaPath) }) node.anyOf.forEach(function(sch, i) { if (i) validate('}') }) validate('if (%s !== errors) {', prev) error('no schemas match') validate('}') } if (node.oneOf && node.oneOf.length) { var prev = gensym('prev') var passes = gensym('passes') validate ('var %s = errors', prev) ('var %s = 0', passes) node.oneOf.forEach(function(sch, i) { visit(name, sch, false, false, schemaPath) validate('if (%s === errors) {', prev) ('%s++', passes) ('} else {') ('errors = %s', prev) ('}') }) validate('if (%s !== 1) {', passes) error('no (or more than one) schemas match') validate('}') } if (node.multipleOf !== undefined) { if (type !== 'number' && type !== 'integer') validate('if (%s) {', types.number(name)) validate('if (!isMultipleOf(%s, %d)) {', name, node.multipleOf) error('has a remainder') validate('}') if (type !== 'number' && type !== 'integer') validate('}') } if (node.maxProperties !== undefined) { if (type !== 'object') validate('if (%s) {', types.object(name)) validate('if (Object.keys(%s).length > %d) {', name, node.maxProperties) error('has more properties than allowed') validate('}') if (type !== 'object') validate('}') } if (node.minProperties !== undefined) { if (type !== 'object') validate('if (%s) {', types.object(name)) validate('if (Object.keys(%s).length < %d) {', name, node.minProperties) error('has less properties than allowed') validate('}') if (type !== 'object') validate('}') } if (node.maxItems !== undefined) { if (type !== 'array') validate('if (%s) {', types.array(name)) validate('if (%s.length > %d) {', name, node.maxItems) error('has more items than allowed') validate('}') if (type !== 'array') validate('}') } if (node.minItems !== undefined) { if (type !== 'array') validate('if (%s) {', types.array(name)) validate('if (%s.length < %d) {', name, node.minItems) error('has less items than allowed') validate('}') if (type !== 'array') validate('}') } if (node.maxLength !== undefined) { if (type !== 'string') validate('if (%s) {', types.string(name)) validate('if (%s.length > %d) {', name, node.maxLength) error('has longer length than allowed') validate('}') if (type !== 'string') validate('}') } if (node.minLength !== undefined) { if (type !== 'string') validate('if (%s) {', types.string(name)) validate('if (%s.length < %d) {', name, node.minLength) error('has less length than allowed') validate('}') if (type !== 'string') validate('}') } if (node.minimum !== undefined) { if (type !== 'number' && type !== 'integer') validate('if (%s) {', types.number(name)) validate('if (%s %s %d) {', name, node.exclusiveMinimum ? '<=' : '<', node.minimum) error('is less than minimum') validate('}') if (type !== 'number' && type !== 'integer') validate('}') } if (node.maximum !== undefined) { if (type !== 'number' && type !== 'integer') validate('if (%s) {', types.number(name)) validate('if (%s %s %d) {', name, node.exclusiveMaximum ? '>=' : '>', node.maximum) error('is more than maximum') validate('}') if (type !== 'number' && type !== 'integer') validate('}') } if (properties) { Object.keys(properties).forEach(function(p) { if (Array.isArray(type) && type.indexOf('null') !== -1) validate('if (%s !== null) {', name) visit( genobj(name, p), properties[p], reporter, filter, schemaPath.concat(tuple ? p : ['properties', p]) ) if (Array.isArray(type) && type.indexOf('null') !== -1) validate('}') }) } while (indent--) validate('}') } var validate = genfun ('function validate(data) {') // Since undefined is not a valid JSON value, we coerce to null and other checks will catch this ('if (data === undefined) data = null') ('validate.errors = null') ('var errors = 0') visit('data', schema, reporter, opts && opts.filter, []) validate ('return errors === 0') ('}') validate = validate.toFunction(scope) validate.errors = null if (Object.defineProperty) { Object.defineProperty(validate, 'error', { get: function() { if (!validate.errors) return '' return validate.errors.map(function(err) { return err.field + ' ' + err.message; }).join('\n') } }) } validate.toJSON = function() { return schema } return validate } module.exports = function(schema, opts) { if (typeof schema === 'string') schema = JSON.parse(schema) return compile(schema, {}, schema, true, opts) } module.exports.filter = function(schema, opts) { var validate = module.exports(schema, xtend(opts, {filter: true})) return function(sch) { validate(sch) return sch } }