source: Dev/trunk/src/node_modules/tv4/tv4.js @ 484

Last change on this file since 484 was 484, checked in by hendrikvanantwerpen, 11 years ago

Commit node_modules, to make checkouts and builds more deterministic.

File size: 39.7 KB
Line 
1/*
2Author: Geraint Luff and others
3Year: 2013
4
5This code is released into the "public domain" by its author(s).  Anybody may use, alter and distribute the code without restriction.  The author makes no guarantees, and takes no liability of any kind for use of this code.
6
7If you find a bug or make an improvement, it would be courteous to let the author know, but it is not compulsory.
8*/
9(function (global) {
10'use strict';
11
12// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FObject%2Fkeys
13if (!Object.keys) {
14        Object.keys = (function () {
15                var hasOwnProperty = Object.prototype.hasOwnProperty,
16                        hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
17                        dontEnums = [
18                                'toString',
19                                'toLocaleString',
20                                'valueOf',
21                                'hasOwnProperty',
22                                'isPrototypeOf',
23                                'propertyIsEnumerable',
24                                'constructor'
25                        ],
26                        dontEnumsLength = dontEnums.length;
27
28                return function (obj) {
29                        if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) {
30                                throw new TypeError('Object.keys called on non-object');
31                        }
32
33                        var result = [];
34
35                        for (var prop in obj) {
36                                if (hasOwnProperty.call(obj, prop)) {
37                                        result.push(prop);
38                                }
39                        }
40
41                        if (hasDontEnumBug) {
42                                for (var i=0; i < dontEnumsLength; i++) {
43                                        if (hasOwnProperty.call(obj, dontEnums[i])) {
44                                                result.push(dontEnums[i]);
45                                        }
46                                }
47                        }
48                        return result;
49                };
50        })();
51}
52// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
53if (!Object.create) {
54        Object.create = (function(){
55                function F(){}
56
57                return function(o){
58                        if (arguments.length !== 1) {
59                                throw new Error('Object.create implementation only accepts one parameter.');
60                        }
61                        F.prototype = o;
62                        return new F();
63                };
64        })();
65}
66// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FisArray
67if(!Array.isArray) {
68        Array.isArray = function (vArg) {
69                return Object.prototype.toString.call(vArg) === "[object Array]";
70        };
71}
72// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf?redirectlocale=en-US&redirectslug=JavaScript%2FReference%2FGlobal_Objects%2FArray%2FindexOf
73if (!Array.prototype.indexOf) {
74        Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
75                if (this === null) {
76                        throw new TypeError();
77                }
78                var t = Object(this);
79                var len = t.length >>> 0;
80
81                if (len === 0) {
82                        return -1;
83                }
84                var n = 0;
85                if (arguments.length > 1) {
86                        n = Number(arguments[1]);
87                        if (n !== n) { // shortcut for verifying if it's NaN
88                                n = 0;
89                        } else if (n !== 0 && n !== Infinity && n !== -Infinity) {
90                                n = (n > 0 || -1) * Math.floor(Math.abs(n));
91                        }
92                }
93                if (n >= len) {
94                        return -1;
95                }
96                var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
97                for (; k < len; k++) {
98                        if (k in t && t[k] === searchElement) {
99                                return k;
100                        }
101                }
102                return -1;
103        };
104}
105
106// Grungey Object.isFrozen hack
107if (!Object.isFrozen) {
108        Object.isFrozen = function (obj) {
109                var key = "tv4_test_frozen_key";
110                while (obj.hasOwnProperty(key)) {
111                        key += Math.random();
112                }
113                try {
114                        obj[key] = true;
115                        delete obj[key];
116                        return false;
117                } catch (e) {
118                        return true;
119                }
120        };
121}
122var ValidatorContext = function ValidatorContext(parent, collectMultiple, errorMessages, checkRecursive, trackUnknownProperties) {
123        this.missing = [];
124        this.missingMap = {};
125        this.formatValidators = parent ? Object.create(parent.formatValidators) : {};
126        this.schemas = parent ? Object.create(parent.schemas) : {};
127        this.collectMultiple = collectMultiple;
128        this.errors = [];
129        this.handleError = collectMultiple ? this.collectError : this.returnError;
130        if (checkRecursive) {
131                this.checkRecursive = true;
132                this.scanned = [];
133                this.scannedFrozen = [];
134                this.scannedFrozenSchemas = [];
135                this.key = 'tv4_validation_id';
136        }
137        if (trackUnknownProperties) {
138                this.trackUnknownProperties = true;
139                this.knownPropertyPaths = {};
140                this.unknownPropertyPaths = {};
141        }
142        this.errorMessages = errorMessages;
143};
144ValidatorContext.prototype.createError = function (code, messageParams, dataPath, schemaPath, subErrors) {
145        var messageTemplate = this.errorMessages[code] || ErrorMessagesDefault[code];
146        if (typeof messageTemplate !== 'string') {
147                return new ValidationError(code, "Unknown error code " + code + ": " + JSON.stringify(messageParams), dataPath, schemaPath, subErrors);
148        }
149        // Adapted from Crockford's supplant()
150        var message = messageTemplate.replace(/\{([^{}]*)\}/g, function (whole, varName) {
151                var subValue = messageParams[varName];
152                return typeof subValue === 'string' || typeof subValue === 'number' ? subValue : whole;
153        });
154        return new ValidationError(code, message, dataPath, schemaPath, subErrors);
155};
156ValidatorContext.prototype.returnError = function (error) {
157        return error;
158};
159ValidatorContext.prototype.collectError = function (error) {
160        if (error) {
161                this.errors.push(error);
162        }
163        return null;
164};
165ValidatorContext.prototype.prefixErrors = function (startIndex, dataPath, schemaPath) {
166        for (var i = startIndex; i < this.errors.length; i++) {
167                this.errors[i] = this.errors[i].prefixWith(dataPath, schemaPath);
168        }
169        return this;
170};
171ValidatorContext.prototype.banUnknownProperties = function () {
172        for (var unknownPath in this.unknownPropertyPaths) {
173                var error = this.createError(ErrorCodes.UNKNOWN_PROPERTY, {path: unknownPath}, unknownPath, "");
174                var result = this.handleError(error);
175                if (result) {
176                        return result;
177                }
178        }
179        return null;
180};
181
182ValidatorContext.prototype.addFormat = function (format, validator) {
183        if (typeof format === 'object') {
184                for (var key in format) {
185                        this.addFormat(key, format[key]);
186                }
187                return this;
188        }
189        this.formatValidators[format] = validator;
190};
191ValidatorContext.prototype.resolveRefs = function (schema, urlHistory) {
192        if (schema['$ref'] !== undefined) {
193                urlHistory = urlHistory || {};
194                if (urlHistory[schema['$ref']]) {
195                        return this.createError(ErrorCodes.CIRCULAR_REFERENCE, {urls: Object.keys(urlHistory).join(', ')}, '', '');
196                }
197                urlHistory[schema['$ref']] = true;
198                schema = this.getSchema(schema['$ref'], urlHistory);
199        }
200        return schema;
201};
202ValidatorContext.prototype.getSchema = function (url, urlHistory) {
203        var schema;
204        if (this.schemas[url] !== undefined) {
205                schema = this.schemas[url];
206                return this.resolveRefs(schema, urlHistory);
207        }
208        var baseUrl = url;
209        var fragment = "";
210        if (url.indexOf('#') !== -1) {
211                fragment = url.substring(url.indexOf("#") + 1);
212                baseUrl = url.substring(0, url.indexOf("#"));
213        }
214        if (typeof this.schemas[baseUrl] === 'object') {
215                schema = this.schemas[baseUrl];
216                var pointerPath = decodeURIComponent(fragment);
217                if (pointerPath === "") {
218                        return this.resolveRefs(schema, urlHistory);
219                } else if (pointerPath.charAt(0) !== "/") {
220                        return undefined;
221                }
222                var parts = pointerPath.split("/").slice(1);
223                for (var i = 0; i < parts.length; i++) {
224                        var component = parts[i].replace(/~1/g, "/").replace(/~0/g, "~");
225                        if (schema[component] === undefined) {
226                                schema = undefined;
227                                break;
228                        }
229                        schema = schema[component];
230                }
231                if (schema !== undefined) {
232                        return this.resolveRefs(schema, urlHistory);
233                }
234        }
235        if (this.missing[baseUrl] === undefined) {
236                this.missing.push(baseUrl);
237                this.missing[baseUrl] = baseUrl;
238                this.missingMap[baseUrl] = baseUrl;
239        }
240};
241ValidatorContext.prototype.searchSchemas = function (schema, url) {
242        if (typeof schema.id === "string") {
243                if (isTrustedUrl(url, schema.id)) {
244                        if (this.schemas[schema.id] === undefined) {
245                                this.schemas[schema.id] = schema;
246                        }
247                }
248        }
249        if (typeof schema === "object") {
250                for (var key in schema) {
251                        if (key !== "enum") {
252                                if (typeof schema[key] === "object") {
253                                        this.searchSchemas(schema[key], url);
254                                } else if (key === "$ref") {
255                                        var uri = getDocumentUri(schema[key]);
256                                        if (uri && this.schemas[uri] === undefined && this.missingMap[uri] === undefined) {
257                                                this.missingMap[uri] = uri;
258                                        }
259                                }
260                        }
261                }
262        }
263};
264ValidatorContext.prototype.addSchema = function (url, schema) {
265        //overload
266        if (typeof schema === 'undefined') {
267                if (typeof url === 'object' && typeof url.id === 'string') {
268                        schema = url;
269                        url = schema.id;
270                }
271                else {
272                        return;
273                }
274        }
275        if (url = getDocumentUri(url) + "#") {
276                // Remove empty fragment
277                url = getDocumentUri(url);
278        }
279        this.schemas[url] = schema;
280        delete this.missingMap[url];
281        normSchema(schema, url);
282        this.searchSchemas(schema, url);
283};
284
285ValidatorContext.prototype.getSchemaMap = function () {
286        var map = {};
287        for (var key in this.schemas) {
288                map[key] = this.schemas[key];
289        }
290        return map;
291};
292
293ValidatorContext.prototype.getSchemaUris = function (filterRegExp) {
294        var list = [];
295        for (var key in this.schemas) {
296                if (!filterRegExp || filterRegExp.test(key)) {
297                        list.push(key);
298                }
299        }
300        return list;
301};
302
303ValidatorContext.prototype.getMissingUris = function (filterRegExp) {
304        var list = [];
305        for (var key in this.missingMap) {
306                if (!filterRegExp || filterRegExp.test(key)) {
307                        list.push(key);
308                }
309        }
310        return list;
311};
312
313ValidatorContext.prototype.dropSchemas = function () {
314        this.schemas = {};
315        this.reset();
316};
317ValidatorContext.prototype.reset = function () {
318        this.missing = [];
319        this.missingMap = {};
320        this.errors = [];
321};
322
323ValidatorContext.prototype.validateAll = function (data, schema, dataPathParts, schemaPathParts, dataPointerPath) {
324        var topLevel;
325        schema = this.resolveRefs(schema);
326        if (!schema) {
327                return null;
328        } else if (schema instanceof ValidationError) {
329                this.errors.push(schema);
330                return schema;
331        }
332
333        if (this.checkRecursive && (typeof data) === 'object') {
334                topLevel = !this.scanned.length;
335                if (data[this.key] && data[this.key].indexOf(schema) !== -1) { return null; }
336                var frozenIndex;
337                if (Object.isFrozen(data)) {
338                        frozenIndex = this.scannedFrozen.indexOf(data);
339                        if (frozenIndex !== -1 && this.scannedFrozenSchemas[frozenIndex].indexOf(schema) !== -1) { return null; }
340                }
341                this.scanned.push(data);
342                if (Object.isFrozen(data)) {
343                        if (frozenIndex === -1) {
344                                frozenIndex = this.scannedFrozen.length;
345                                this.scannedFrozen.push(data);
346                                this.scannedFrozenSchemas.push([]);
347                        }
348                        this.scannedFrozenSchemas[frozenIndex].push(schema);
349                } else {
350                        if (!data[this.key]) {
351                                try {
352                                        Object.defineProperty(data, this.key, {
353                                                value: [],
354                                                configurable: true
355                                        });
356                                } catch (e) {
357                                        //IE 7/8 workaround
358                                        data[this.key] = [];
359                                }
360                        }
361                        data[this.key].push(schema);
362                }
363        }
364
365        var errorCount = this.errors.length;
366        var error = this.validateBasic(data, schema, dataPointerPath)
367                || this.validateNumeric(data, schema, dataPointerPath)
368                || this.validateString(data, schema, dataPointerPath)
369                || this.validateArray(data, schema, dataPointerPath)
370                || this.validateObject(data, schema, dataPointerPath)
371                || this.validateCombinations(data, schema, dataPointerPath)
372                || this.validateFormat(data, schema, dataPointerPath)
373                || null;
374
375        if (topLevel) {
376                while (this.scanned.length) {
377                        var item = this.scanned.pop();
378                        delete item[this.key];
379                }
380                this.scannedFrozen = [];
381                this.scannedFrozenSchemas = [];
382        }
383
384        if (error || errorCount !== this.errors.length) {
385                while ((dataPathParts && dataPathParts.length) || (schemaPathParts && schemaPathParts.length)) {
386                        var dataPart = (dataPathParts && dataPathParts.length) ? "" + dataPathParts.pop() : null;
387                        var schemaPart = (schemaPathParts && schemaPathParts.length) ? "" + schemaPathParts.pop() : null;
388                        if (error) {
389                                error = error.prefixWith(dataPart, schemaPart);
390                        }
391                        this.prefixErrors(errorCount, dataPart, schemaPart);
392                }
393        }
394
395        return this.handleError(error);
396};
397ValidatorContext.prototype.validateFormat = function (data, schema) {
398        if (typeof schema.format !== 'string' || !this.formatValidators[schema.format]) {
399                return null;
400        }
401        var errorMessage = this.formatValidators[schema.format].call(null, data, schema);
402        if (typeof errorMessage === 'string' || typeof errorMessage === 'number') {
403                return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage}).prefixWith(null, "format");
404        } else if (errorMessage && typeof errorMessage === 'object') {
405                return this.createError(ErrorCodes.FORMAT_CUSTOM, {message: errorMessage.message || "?"}, errorMessage.dataPath || null, errorMessage.schemaPath || "/format");
406        }
407        return null;
408};
409
410function recursiveCompare(A, B) {
411        if (A === B) {
412                return true;
413        }
414        if (typeof A === "object" && typeof B === "object") {
415                if (Array.isArray(A) !== Array.isArray(B)) {
416                        return false;
417                } else if (Array.isArray(A)) {
418                        if (A.length !== B.length) {
419                                return false;
420                        }
421                        for (var i = 0; i < A.length; i++) {
422                                if (!recursiveCompare(A[i], B[i])) {
423                                        return false;
424                                }
425                        }
426                } else {
427                        var key;
428                        for (key in A) {
429                                if (B[key] === undefined && A[key] !== undefined) {
430                                        return false;
431                                }
432                        }
433                        for (key in B) {
434                                if (A[key] === undefined && B[key] !== undefined) {
435                                        return false;
436                                }
437                        }
438                        for (key in A) {
439                                if (!recursiveCompare(A[key], B[key])) {
440                                        return false;
441                                }
442                        }
443                }
444                return true;
445        }
446        return false;
447}
448
449ValidatorContext.prototype.validateBasic = function validateBasic(data, schema, dataPointerPath) {
450        var error;
451        if (error = this.validateType(data, schema, dataPointerPath)) {
452                return error.prefixWith(null, "type");
453        }
454        if (error = this.validateEnum(data, schema, dataPointerPath)) {
455                return error.prefixWith(null, "type");
456        }
457        return null;
458};
459
460ValidatorContext.prototype.validateType = function validateType(data, schema) {
461        if (schema.type === undefined) {
462                return null;
463        }
464        var dataType = typeof data;
465        if (data === null) {
466                dataType = "null";
467        } else if (Array.isArray(data)) {
468                dataType = "array";
469        }
470        var allowedTypes = schema.type;
471        if (typeof allowedTypes !== "object") {
472                allowedTypes = [allowedTypes];
473        }
474
475        for (var i = 0; i < allowedTypes.length; i++) {
476                var type = allowedTypes[i];
477                if (type === dataType || (type === "integer" && dataType === "number" && (data % 1 === 0))) {
478                        return null;
479                }
480        }
481        return this.createError(ErrorCodes.INVALID_TYPE, {type: dataType, expected: allowedTypes.join("/")});
482};
483
484ValidatorContext.prototype.validateEnum = function validateEnum(data, schema) {
485        if (schema["enum"] === undefined) {
486                return null;
487        }
488        for (var i = 0; i < schema["enum"].length; i++) {
489                var enumVal = schema["enum"][i];
490                if (recursiveCompare(data, enumVal)) {
491                        return null;
492                }
493        }
494        return this.createError(ErrorCodes.ENUM_MISMATCH, {value: (typeof JSON !== 'undefined') ? JSON.stringify(data) : data});
495};
496
497ValidatorContext.prototype.validateNumeric = function validateNumeric(data, schema, dataPointerPath) {
498        return this.validateMultipleOf(data, schema, dataPointerPath)
499                || this.validateMinMax(data, schema, dataPointerPath)
500                || null;
501};
502
503ValidatorContext.prototype.validateMultipleOf = function validateMultipleOf(data, schema) {
504        var multipleOf = schema.multipleOf || schema.divisibleBy;
505        if (multipleOf === undefined) {
506                return null;
507        }
508        if (typeof data === "number") {
509                if (data % multipleOf !== 0) {
510                        return this.createError(ErrorCodes.NUMBER_MULTIPLE_OF, {value: data, multipleOf: multipleOf});
511                }
512        }
513        return null;
514};
515
516ValidatorContext.prototype.validateMinMax = function validateMinMax(data, schema) {
517        if (typeof data !== "number") {
518                return null;
519        }
520        if (schema.minimum !== undefined) {
521                if (data < schema.minimum) {
522                        return this.createError(ErrorCodes.NUMBER_MINIMUM, {value: data, minimum: schema.minimum}).prefixWith(null, "minimum");
523                }
524                if (schema.exclusiveMinimum && data === schema.minimum) {
525                        return this.createError(ErrorCodes.NUMBER_MINIMUM_EXCLUSIVE, {value: data, minimum: schema.minimum}).prefixWith(null, "exclusiveMinimum");
526                }
527        }
528        if (schema.maximum !== undefined) {
529                if (data > schema.maximum) {
530                        return this.createError(ErrorCodes.NUMBER_MAXIMUM, {value: data, maximum: schema.maximum}).prefixWith(null, "maximum");
531                }
532                if (schema.exclusiveMaximum && data === schema.maximum) {
533                        return this.createError(ErrorCodes.NUMBER_MAXIMUM_EXCLUSIVE, {value: data, maximum: schema.maximum}).prefixWith(null, "exclusiveMaximum");
534                }
535        }
536        return null;
537};
538
539ValidatorContext.prototype.validateString = function validateString(data, schema, dataPointerPath) {
540        return this.validateStringLength(data, schema, dataPointerPath)
541                || this.validateStringPattern(data, schema, dataPointerPath)
542                || null;
543};
544
545ValidatorContext.prototype.validateStringLength = function validateStringLength(data, schema) {
546        if (typeof data !== "string") {
547                return null;
548        }
549        if (schema.minLength !== undefined) {
550                if (data.length < schema.minLength) {
551                        return this.createError(ErrorCodes.STRING_LENGTH_SHORT, {length: data.length, minimum: schema.minLength}).prefixWith(null, "minLength");
552                }
553        }
554        if (schema.maxLength !== undefined) {
555                if (data.length > schema.maxLength) {
556                        return this.createError(ErrorCodes.STRING_LENGTH_LONG, {length: data.length, maximum: schema.maxLength}).prefixWith(null, "maxLength");
557                }
558        }
559        return null;
560};
561
562ValidatorContext.prototype.validateStringPattern = function validateStringPattern(data, schema) {
563        if (typeof data !== "string" || schema.pattern === undefined) {
564                return null;
565        }
566        var regexp = new RegExp(schema.pattern);
567        if (!regexp.test(data)) {
568                return this.createError(ErrorCodes.STRING_PATTERN, {pattern: schema.pattern}).prefixWith(null, "pattern");
569        }
570        return null;
571};
572ValidatorContext.prototype.validateArray = function validateArray(data, schema, dataPointerPath) {
573        if (!Array.isArray(data)) {
574                return null;
575        }
576        return this.validateArrayLength(data, schema, dataPointerPath)
577                || this.validateArrayUniqueItems(data, schema, dataPointerPath)
578                || this.validateArrayItems(data, schema, dataPointerPath)
579                || null;
580};
581
582ValidatorContext.prototype.validateArrayLength = function validateArrayLength(data, schema) {
583        var error;
584        if (schema.minItems !== undefined) {
585                if (data.length < schema.minItems) {
586                        error = (this.createError(ErrorCodes.ARRAY_LENGTH_SHORT, {length: data.length, minimum: schema.minItems})).prefixWith(null, "minItems");
587                        if (this.handleError(error)) {
588                                return error;
589                        }
590                }
591        }
592        if (schema.maxItems !== undefined) {
593                if (data.length > schema.maxItems) {
594                        error = (this.createError(ErrorCodes.ARRAY_LENGTH_LONG, {length: data.length, maximum: schema.maxItems})).prefixWith(null, "maxItems");
595                        if (this.handleError(error)) {
596                                return error;
597                        }
598                }
599        }
600        return null;
601};
602
603ValidatorContext.prototype.validateArrayUniqueItems = function validateArrayUniqueItems(data, schema) {
604        if (schema.uniqueItems) {
605                for (var i = 0; i < data.length; i++) {
606                        for (var j = i + 1; j < data.length; j++) {
607                                if (recursiveCompare(data[i], data[j])) {
608                                        var error = (this.createError(ErrorCodes.ARRAY_UNIQUE, {match1: i, match2: j})).prefixWith(null, "uniqueItems");
609                                        if (this.handleError(error)) {
610                                                return error;
611                                        }
612                                }
613                        }
614                }
615        }
616        return null;
617};
618
619ValidatorContext.prototype.validateArrayItems = function validateArrayItems(data, schema, dataPointerPath) {
620        if (schema.items === undefined) {
621                return null;
622        }
623        var error, i;
624        if (Array.isArray(schema.items)) {
625                for (i = 0; i < data.length; i++) {
626                        if (i < schema.items.length) {
627                                if (error = this.validateAll(data[i], schema.items[i], [i], ["items", i], dataPointerPath + "/" + i)) {
628                                        return error;
629                                }
630                        } else if (schema.additionalItems !== undefined) {
631                                if (typeof schema.additionalItems === "boolean") {
632                                        if (!schema.additionalItems) {
633                                                error = (this.createError(ErrorCodes.ARRAY_ADDITIONAL_ITEMS, {})).prefixWith("" + i, "additionalItems");
634                                                if (this.handleError(error)) {
635                                                        return error;
636                                                }
637                                        }
638                                } else if (error = this.validateAll(data[i], schema.additionalItems, [i], ["additionalItems"], dataPointerPath + "/" + i)) {
639                                        return error;
640                                }
641                        }
642                }
643        } else {
644                for (i = 0; i < data.length; i++) {
645                        if (error = this.validateAll(data[i], schema.items, [i], ["items"], dataPointerPath + "/" + i)) {
646                                return error;
647                        }
648                }
649        }
650        return null;
651};
652
653ValidatorContext.prototype.validateObject = function validateObject(data, schema, dataPointerPath) {
654        if (typeof data !== "object" || data === null || Array.isArray(data)) {
655                return null;
656        }
657        return this.validateObjectMinMaxProperties(data, schema, dataPointerPath)
658                || this.validateObjectRequiredProperties(data, schema, dataPointerPath)
659                || this.validateObjectProperties(data, schema, dataPointerPath)
660                || this.validateObjectDependencies(data, schema, dataPointerPath)
661                || null;
662};
663
664ValidatorContext.prototype.validateObjectMinMaxProperties = function validateObjectMinMaxProperties(data, schema) {
665        var keys = Object.keys(data);
666        var error;
667        if (schema.minProperties !== undefined) {
668                if (keys.length < schema.minProperties) {
669                        error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MINIMUM, {propertyCount: keys.length, minimum: schema.minProperties}).prefixWith(null, "minProperties");
670                        if (this.handleError(error)) {
671                                return error;
672                        }
673                }
674        }
675        if (schema.maxProperties !== undefined) {
676                if (keys.length > schema.maxProperties) {
677                        error = this.createError(ErrorCodes.OBJECT_PROPERTIES_MAXIMUM, {propertyCount: keys.length, maximum: schema.maxProperties}).prefixWith(null, "maxProperties");
678                        if (this.handleError(error)) {
679                                return error;
680                        }
681                }
682        }
683        return null;
684};
685
686ValidatorContext.prototype.validateObjectRequiredProperties = function validateObjectRequiredProperties(data, schema) {
687        if (schema.required !== undefined) {
688                for (var i = 0; i < schema.required.length; i++) {
689                        var key = schema.required[i];
690                        if (data[key] === undefined) {
691                                var error = this.createError(ErrorCodes.OBJECT_REQUIRED, {key: key}).prefixWith(null, "" + i).prefixWith(null, "required");
692                                if (this.handleError(error)) {
693                                        return error;
694                                }
695                        }
696                }
697        }
698        return null;
699};
700
701ValidatorContext.prototype.validateObjectProperties = function validateObjectProperties(data, schema, dataPointerPath) {
702        var error;
703        for (var key in data) {
704                var keyPointerPath = dataPointerPath + "/" + key.replace(/~/g, '~0').replace(/\//g, '~1');
705                var foundMatch = false;
706                if (schema.properties !== undefined && schema.properties[key] !== undefined) {
707                        foundMatch = true;
708                        if (error = this.validateAll(data[key], schema.properties[key], [key], ["properties", key], keyPointerPath)) {
709                                return error;
710                        }
711                }
712                if (schema.patternProperties !== undefined) {
713                        for (var patternKey in schema.patternProperties) {
714                                var regexp = new RegExp(patternKey);
715                                if (regexp.test(key)) {
716                                        foundMatch = true;
717                                        if (error = this.validateAll(data[key], schema.patternProperties[patternKey], [key], ["patternProperties", patternKey], keyPointerPath)) {
718                                                return error;
719                                        }
720                                }
721                        }
722                }
723                if (!foundMatch) {
724                        if (schema.additionalProperties !== undefined) {
725                                if (this.trackUnknownProperties) {
726                                        this.knownPropertyPaths[keyPointerPath] = true;
727                                        delete this.unknownPropertyPaths[keyPointerPath];
728                                }
729                                if (typeof schema.additionalProperties === "boolean") {
730                                        if (!schema.additionalProperties) {
731                                                error = this.createError(ErrorCodes.OBJECT_ADDITIONAL_PROPERTIES, {}).prefixWith(key, "additionalProperties");
732                                                if (this.handleError(error)) {
733                                                        return error;
734                                                }
735                                        }
736                                } else {
737                                        if (error = this.validateAll(data[key], schema.additionalProperties, [key], ["additionalProperties"], keyPointerPath)) {
738                                                return error;
739                                        }
740                                }
741                        } else if (this.trackUnknownProperties && !this.knownPropertyPaths[keyPointerPath]) {
742                                this.unknownPropertyPaths[keyPointerPath] = true;
743                        }
744                } else if (this.trackUnknownProperties) {
745                        this.knownPropertyPaths[keyPointerPath] = true;
746                        delete this.unknownPropertyPaths[keyPointerPath];
747                }
748        }
749        return null;
750};
751
752ValidatorContext.prototype.validateObjectDependencies = function validateObjectDependencies(data, schema, dataPointerPath) {
753        var error;
754        if (schema.dependencies !== undefined) {
755                for (var depKey in schema.dependencies) {
756                        if (data[depKey] !== undefined) {
757                                var dep = schema.dependencies[depKey];
758                                if (typeof dep === "string") {
759                                        if (data[dep] === undefined) {
760                                                error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: dep}).prefixWith(null, depKey).prefixWith(null, "dependencies");
761                                                if (this.handleError(error)) {
762                                                        return error;
763                                                }
764                                        }
765                                } else if (Array.isArray(dep)) {
766                                        for (var i = 0; i < dep.length; i++) {
767                                                var requiredKey = dep[i];
768                                                if (data[requiredKey] === undefined) {
769                                                        error = this.createError(ErrorCodes.OBJECT_DEPENDENCY_KEY, {key: depKey, missing: requiredKey}).prefixWith(null, "" + i).prefixWith(null, depKey).prefixWith(null, "dependencies");
770                                                        if (this.handleError(error)) {
771                                                                return error;
772                                                        }
773                                                }
774                                        }
775                                } else {
776                                        if (error = this.validateAll(data, dep, [], ["dependencies", depKey], dataPointerPath)) {
777                                                return error;
778                                        }
779                                }
780                        }
781                }
782        }
783        return null;
784};
785
786ValidatorContext.prototype.validateCombinations = function validateCombinations(data, schema, dataPointerPath) {
787        return this.validateAllOf(data, schema, dataPointerPath)
788                || this.validateAnyOf(data, schema, dataPointerPath)
789                || this.validateOneOf(data, schema, dataPointerPath)
790                || this.validateNot(data, schema, dataPointerPath)
791                || null;
792};
793
794ValidatorContext.prototype.validateAllOf = function validateAllOf(data, schema, dataPointerPath) {
795        if (schema.allOf === undefined) {
796                return null;
797        }
798        var error;
799        for (var i = 0; i < schema.allOf.length; i++) {
800                var subSchema = schema.allOf[i];
801                if (error = this.validateAll(data, subSchema, [], ["allOf", i], dataPointerPath)) {
802                        return error;
803                }
804        }
805        return null;
806};
807
808ValidatorContext.prototype.validateAnyOf = function validateAnyOf(data, schema, dataPointerPath) {
809        if (schema.anyOf === undefined) {
810                return null;
811        }
812        var errors = [];
813        var startErrorCount = this.errors.length;
814        var oldUnknownPropertyPaths, oldKnownPropertyPaths;
815        if (this.trackUnknownProperties) {
816                oldUnknownPropertyPaths = this.unknownPropertyPaths;
817                oldKnownPropertyPaths = this.knownPropertyPaths;
818        }
819        var errorAtEnd = true;
820        for (var i = 0; i < schema.anyOf.length; i++) {
821                if (this.trackUnknownProperties) {
822                        this.unknownPropertyPaths = {};
823                        this.knownPropertyPaths = {};
824                }
825                var subSchema = schema.anyOf[i];
826
827                var errorCount = this.errors.length;
828                var error = this.validateAll(data, subSchema, [], ["anyOf", i], dataPointerPath);
829
830                if (error === null && errorCount === this.errors.length) {
831                        this.errors = this.errors.slice(0, startErrorCount);
832
833                        if (this.trackUnknownProperties) {
834                                for (var knownKey in this.knownPropertyPaths) {
835                                        oldKnownPropertyPaths[knownKey] = true;
836                                        delete oldUnknownPropertyPaths[knownKey];
837                                }
838                                for (var unknownKey in this.unknownPropertyPaths) {
839                                        if (!oldKnownPropertyPaths[unknownKey]) {
840                                                oldUnknownPropertyPaths[unknownKey] = true;
841                                        }
842                                }
843                                // We need to continue looping so we catch all the property definitions, but we don't want to return an error
844                                errorAtEnd = false;
845                                continue;
846                        }
847
848                        return null;
849                }
850                if (error) {
851                        errors.push(error.prefixWith(null, "" + i).prefixWith(null, "anyOf"));
852                }
853        }
854        if (this.trackUnknownProperties) {
855                this.unknownPropertyPaths = oldUnknownPropertyPaths;
856                this.knownPropertyPaths = oldKnownPropertyPaths;
857        }
858        if (errorAtEnd) {
859                errors = errors.concat(this.errors.slice(startErrorCount));
860                this.errors = this.errors.slice(0, startErrorCount);
861                return this.createError(ErrorCodes.ANY_OF_MISSING, {}, "", "/anyOf", errors);
862        }
863};
864
865ValidatorContext.prototype.validateOneOf = function validateOneOf(data, schema, dataPointerPath) {
866        if (schema.oneOf === undefined) {
867                return null;
868        }
869        var validIndex = null;
870        var errors = [];
871        var startErrorCount = this.errors.length;
872        var oldUnknownPropertyPaths, oldKnownPropertyPaths;
873        if (this.trackUnknownProperties) {
874                oldUnknownPropertyPaths = this.unknownPropertyPaths;
875                oldKnownPropertyPaths = this.knownPropertyPaths;
876        }
877        for (var i = 0; i < schema.oneOf.length; i++) {
878                if (this.trackUnknownProperties) {
879                        this.unknownPropertyPaths = {};
880                        this.knownPropertyPaths = {};
881                }
882                var subSchema = schema.oneOf[i];
883
884                var errorCount = this.errors.length;
885                var error = this.validateAll(data, subSchema, [], ["oneOf", i], dataPointerPath);
886
887                if (error === null && errorCount === this.errors.length) {
888                        if (validIndex === null) {
889                                validIndex = i;
890                        } else {
891                                this.errors = this.errors.slice(0, startErrorCount);
892                                return this.createError(ErrorCodes.ONE_OF_MULTIPLE, {index1: validIndex, index2: i}, "", "/oneOf");
893                        }
894                        if (this.trackUnknownProperties) {
895                                for (var knownKey in this.knownPropertyPaths) {
896                                        oldKnownPropertyPaths[knownKey] = true;
897                                        delete oldUnknownPropertyPaths[knownKey];
898                                }
899                                for (var unknownKey in this.unknownPropertyPaths) {
900                                        if (!oldKnownPropertyPaths[unknownKey]) {
901                                                oldUnknownPropertyPaths[unknownKey] = true;
902                                        }
903                                }
904                        }
905                } else if (error) {
906                        errors.push(error.prefixWith(null, "" + i).prefixWith(null, "oneOf"));
907                }
908        }
909        if (this.trackUnknownProperties) {
910                this.unknownPropertyPaths = oldUnknownPropertyPaths;
911                this.knownPropertyPaths = oldKnownPropertyPaths;
912        }
913        if (validIndex === null) {
914                errors = errors.concat(this.errors.slice(startErrorCount));
915                this.errors = this.errors.slice(0, startErrorCount);
916                return this.createError(ErrorCodes.ONE_OF_MISSING, {}, "", "/oneOf", errors);
917        } else {
918                this.errors = this.errors.slice(0, startErrorCount);
919        }
920        return null;
921};
922
923ValidatorContext.prototype.validateNot = function validateNot(data, schema, dataPointerPath) {
924        if (schema.not === undefined) {
925                return null;
926        }
927        var oldErrorCount = this.errors.length;
928        var oldUnknownPropertyPaths, oldKnownPropertyPaths;
929        if (this.trackUnknownProperties) {
930                oldUnknownPropertyPaths = this.unknownPropertyPaths;
931                oldKnownPropertyPaths = this.knownPropertyPaths;
932                this.unknownPropertyPaths = {};
933                this.knownPropertyPaths = {};
934        }
935        var error = this.validateAll(data, schema.not, null, null, dataPointerPath);
936        var notErrors = this.errors.slice(oldErrorCount);
937        this.errors = this.errors.slice(0, oldErrorCount);
938        if (this.trackUnknownProperties) {
939                this.unknownPropertyPaths = oldUnknownPropertyPaths;
940                this.knownPropertyPaths = oldKnownPropertyPaths;
941        }
942        if (error === null && notErrors.length === 0) {
943                return this.createError(ErrorCodes.NOT_PASSED, {}, "", "/not");
944        }
945        return null;
946};
947
948// parseURI() and resolveUrl() are from https://gist.github.com/1088850
949//   -  released as public domain by author ("Yaffle") - see comments on gist
950
951function parseURI(url) {
952        var m = String(url).replace(/^\s+|\s+$/g, '').match(/^([^:\/?#]+:)?(\/\/(?:[^:@]*(?::[^:@]*)?@)?(([^:\/?#]*)(?::(\d*))?))?([^?#]*)(\?[^#]*)?(#[\s\S]*)?/);
953        // authority = '//' + user + ':' + pass '@' + hostname + ':' port
954        return (m ? {
955                href     : m[0] || '',
956                protocol : m[1] || '',
957                authority: m[2] || '',
958                host     : m[3] || '',
959                hostname : m[4] || '',
960                port     : m[5] || '',
961                pathname : m[6] || '',
962                search   : m[7] || '',
963                hash     : m[8] || ''
964        } : null);
965}
966
967function resolveUrl(base, href) {// RFC 3986
968
969        function removeDotSegments(input) {
970                var output = [];
971                input.replace(/^(\.\.?(\/|$))+/, '')
972                        .replace(/\/(\.(\/|$))+/g, '/')
973                        .replace(/\/\.\.$/, '/../')
974                        .replace(/\/?[^\/]*/g, function (p) {
975                                if (p === '/..') {
976                                        output.pop();
977                                } else {
978                                        output.push(p);
979                                }
980                });
981                return output.join('').replace(/^\//, input.charAt(0) === '/' ? '/' : '');
982        }
983
984        href = parseURI(href || '');
985        base = parseURI(base || '');
986
987        return !href || !base ? null : (href.protocol || base.protocol) +
988                (href.protocol || href.authority ? href.authority : base.authority) +
989                removeDotSegments(href.protocol || href.authority || href.pathname.charAt(0) === '/' ? href.pathname : (href.pathname ? ((base.authority && !base.pathname ? '/' : '') + base.pathname.slice(0, base.pathname.lastIndexOf('/') + 1) + href.pathname) : base.pathname)) +
990                (href.protocol || href.authority || href.pathname ? href.search : (href.search || base.search)) +
991                href.hash;
992}
993
994function getDocumentUri(uri) {
995        return uri.split('#')[0];
996}
997function normSchema(schema, baseUri) {
998        if (baseUri === undefined) {
999                baseUri = schema.id;
1000        } else if (typeof schema.id === "string") {
1001                baseUri = resolveUrl(baseUri, schema.id);
1002                schema.id = baseUri;
1003        }
1004        if (typeof schema === "object") {
1005                if (Array.isArray(schema)) {
1006                        for (var i = 0; i < schema.length; i++) {
1007                                normSchema(schema[i], baseUri);
1008                        }
1009                } else if (typeof schema['$ref'] === "string") {
1010                        schema['$ref'] = resolveUrl(baseUri, schema['$ref']);
1011                } else {
1012                        for (var key in schema) {
1013                                if (key !== "enum") {
1014                                        normSchema(schema[key], baseUri);
1015                                }
1016                        }
1017                }
1018        }
1019}
1020
1021var ErrorCodes = {
1022        INVALID_TYPE: 0,
1023        ENUM_MISMATCH: 1,
1024        ANY_OF_MISSING: 10,
1025        ONE_OF_MISSING: 11,
1026        ONE_OF_MULTIPLE: 12,
1027        NOT_PASSED: 13,
1028        // Numeric errors
1029        NUMBER_MULTIPLE_OF: 100,
1030        NUMBER_MINIMUM: 101,
1031        NUMBER_MINIMUM_EXCLUSIVE: 102,
1032        NUMBER_MAXIMUM: 103,
1033        NUMBER_MAXIMUM_EXCLUSIVE: 104,
1034        // String errors
1035        STRING_LENGTH_SHORT: 200,
1036        STRING_LENGTH_LONG: 201,
1037        STRING_PATTERN: 202,
1038        // Object errors
1039        OBJECT_PROPERTIES_MINIMUM: 300,
1040        OBJECT_PROPERTIES_MAXIMUM: 301,
1041        OBJECT_REQUIRED: 302,
1042        OBJECT_ADDITIONAL_PROPERTIES: 303,
1043        OBJECT_DEPENDENCY_KEY: 304,
1044        // Array errors
1045        ARRAY_LENGTH_SHORT: 400,
1046        ARRAY_LENGTH_LONG: 401,
1047        ARRAY_UNIQUE: 402,
1048        ARRAY_ADDITIONAL_ITEMS: 403,
1049        // Format errors
1050        FORMAT_CUSTOM: 500,
1051        // Schema structure
1052        CIRCULAR_REFERENCE: 500,
1053        // Non-standard validation options
1054        UNKNOWN_PROPERTY: 1000
1055};
1056var ErrorMessagesDefault = {
1057        INVALID_TYPE: "invalid type: {type} (expected {expected})",
1058        ENUM_MISMATCH: "No enum match for: {value}",
1059        ANY_OF_MISSING: "Data does not match any schemas from \"anyOf\"",
1060        ONE_OF_MISSING: "Data does not match any schemas from \"oneOf\"",
1061        ONE_OF_MULTIPLE: "Data is valid against more than one schema from \"oneOf\": indices {index1} and {index2}",
1062        NOT_PASSED: "Data matches schema from \"not\"",
1063        // Numeric errors
1064        NUMBER_MULTIPLE_OF: "Value {value} is not a multiple of {multipleOf}",
1065        NUMBER_MINIMUM: "Value {value} is less than minimum {minimum}",
1066        NUMBER_MINIMUM_EXCLUSIVE: "Value {value} is equal to exclusive minimum {minimum}",
1067        NUMBER_MAXIMUM: "Value {value} is greater than maximum {maximum}",
1068        NUMBER_MAXIMUM_EXCLUSIVE: "Value {value} is equal to exclusive maximum {maximum}",
1069        // String errors
1070        STRING_LENGTH_SHORT: "String is too short ({length} chars), minimum {minimum}",
1071        STRING_LENGTH_LONG: "String is too long ({length} chars), maximum {maximum}",
1072        STRING_PATTERN: "String does not match pattern: {pattern}",
1073        // Object errors
1074        OBJECT_PROPERTIES_MINIMUM: "Too few properties defined ({propertyCount}), minimum {minimum}",
1075        OBJECT_PROPERTIES_MAXIMUM: "Too many properties defined ({propertyCount}), maximum {maximum}",
1076        OBJECT_REQUIRED: "Missing required property: {key}",
1077        OBJECT_ADDITIONAL_PROPERTIES: "Additional properties not allowed",
1078        OBJECT_DEPENDENCY_KEY: "Dependency failed - key must exist: {missing} (due to key: {key})",
1079        // Array errors
1080        ARRAY_LENGTH_SHORT: "Array is too short ({length}), minimum {minimum}",
1081        ARRAY_LENGTH_LONG: "Array is too long ({length}), maximum {maximum}",
1082        ARRAY_UNIQUE: "Array items are not unique (indices {match1} and {match2})",
1083        ARRAY_ADDITIONAL_ITEMS: "Additional items not allowed",
1084        // Format errors
1085        FORMAT_CUSTOM: "Format validation failed ({message})",
1086        // Schema structure
1087        CIRCULAR_REFERENCE: "Circular $refs: {urls}",
1088        // Non-standard validation options
1089        UNKNOWN_PROPERTY: "Unknown property (not in schema)"
1090};
1091
1092function ValidationError(code, message, dataPath, schemaPath, subErrors) {
1093        if (code === undefined) {
1094                throw new Error ("No code supplied for error: "+ message);
1095        }
1096        this.code = code;
1097        this.message = message;
1098        this.dataPath = dataPath || "";
1099        this.schemaPath = schemaPath || "";
1100        this.subErrors = subErrors || null;
1101}
1102ValidationError.prototype = new Error();
1103ValidationError.prototype.prefixWith = function (dataPrefix, schemaPrefix) {
1104        if (dataPrefix !== null) {
1105                dataPrefix = dataPrefix.replace(/~/g, "~0").replace(/\//g, "~1");
1106                this.dataPath = "/" + dataPrefix + this.dataPath;
1107        }
1108        if (schemaPrefix !== null) {
1109                schemaPrefix = schemaPrefix.replace(/~/g, "~0").replace(/\//g, "~1");
1110                this.schemaPath = "/" + schemaPrefix + this.schemaPath;
1111        }
1112        if (this.subErrors !== null) {
1113                for (var i = 0; i < this.subErrors.length; i++) {
1114                        this.subErrors[i].prefixWith(dataPrefix, schemaPrefix);
1115                }
1116        }
1117        return this;
1118};
1119
1120function isTrustedUrl(baseUrl, testUrl) {
1121        if(testUrl.substring(0, baseUrl.length) === baseUrl){
1122                var remainder = testUrl.substring(baseUrl.length);
1123                if ((testUrl.length > 0 && testUrl.charAt(baseUrl.length - 1) === "/")
1124                        || remainder.charAt(0) === "#"
1125                        || remainder.charAt(0) === "?") {
1126                        return true;
1127                }
1128        }
1129        return false;
1130}
1131
1132var languages = {};
1133function createApi(language) {
1134        var globalContext = new ValidatorContext();
1135        var currentLanguage = language || 'en';
1136        var api = {
1137                addFormat: function () {
1138                        globalContext.addFormat.apply(globalContext, arguments);
1139                },
1140                language: function (code) {
1141                        if (!code) {
1142                                return currentLanguage;
1143                        }
1144                        if (!languages[code]) {
1145                                code = code.split('-')[0]; // fall back to base language
1146                        }
1147                        if (languages[code]) {
1148                                currentLanguage = code;
1149                                return code; // so you can tell if fall-back has happened
1150                        }
1151                        return false;
1152                },
1153                addLanguage: function (code, messageMap) {
1154                        var key;
1155                        for (key in ErrorCodes) {
1156                                if (messageMap[key] && !messageMap[ErrorCodes[key]]) {
1157                                        messageMap[ErrorCodes[key]] = messageMap[key];
1158                                }
1159                        }
1160                        var rootCode = code.split('-')[0];
1161                        if (!languages[rootCode]) { // use for base language if not yet defined
1162                                languages[code] = messageMap;
1163                                languages[rootCode] = messageMap;
1164                        } else {
1165                                languages[code] = Object.create(languages[rootCode]);
1166                                for (key in messageMap) {
1167                                        if (typeof languages[rootCode][key] === 'undefined') {
1168                                                languages[rootCode][key] = messageMap[key];
1169                                        }
1170                                        languages[code][key] = messageMap[key];
1171                                }
1172                        }
1173                        return this;
1174                },
1175                freshApi: function (language) {
1176                        var result = createApi();
1177                        if (language) {
1178                                result.language(language);
1179                        }
1180                        return result;
1181                },
1182                validate: function (data, schema, checkRecursive, banUnknownProperties) {
1183                        var context = new ValidatorContext(globalContext, false, languages[currentLanguage], checkRecursive, banUnknownProperties);
1184                        if (typeof schema === "string") {
1185                                schema = {"$ref": schema};
1186                        }
1187                        context.addSchema("", schema);
1188                        var error = context.validateAll(data, schema, null, null, "");
1189                        if (!error && banUnknownProperties) {
1190                                error = context.banUnknownProperties();
1191                        }
1192                        this.error = error;
1193                        this.missing = context.missing;
1194                        this.valid = (error === null);
1195                        return this.valid;
1196                },
1197                validateResult: function () {
1198                        var result = {};
1199                        this.validate.apply(result, arguments);
1200                        return result;
1201                },
1202                validateMultiple: function (data, schema, checkRecursive, banUnknownProperties) {
1203                        var context = new ValidatorContext(globalContext, true, languages[currentLanguage], checkRecursive, banUnknownProperties);
1204                        if (typeof schema === "string") {
1205                                schema = {"$ref": schema};
1206                        }
1207                        context.addSchema("", schema);
1208                        context.validateAll(data, schema, null, null, "");
1209                        if (banUnknownProperties) {
1210                                context.banUnknownProperties();
1211                        }
1212                        var result = {};
1213                        result.errors = context.errors;
1214                        result.missing = context.missing;
1215                        result.valid = (result.errors.length === 0);
1216                        return result;
1217                },
1218                addSchema: function () {
1219                        return globalContext.addSchema.apply(globalContext, arguments);
1220                },
1221                getSchema: function () {
1222                        return globalContext.getSchema.apply(globalContext, arguments);
1223                },
1224                getSchemaMap: function () {
1225                        return globalContext.getSchemaMap.apply(globalContext, arguments);
1226                },
1227                getSchemaUris: function () {
1228                        return globalContext.getSchemaUris.apply(globalContext, arguments);
1229                },
1230                getMissingUris: function () {
1231                        return globalContext.getMissingUris.apply(globalContext, arguments);
1232                },
1233                dropSchemas: function () {
1234                        globalContext.dropSchemas.apply(globalContext, arguments);
1235                },
1236                reset: function () {
1237                        globalContext.reset();
1238                        this.error = null;
1239                        this.missing = [];
1240                        this.valid = true;
1241                },
1242                missing: [],
1243                error: null,
1244                valid: true,
1245                normSchema: normSchema,
1246                resolveUrl: resolveUrl,
1247                getDocumentUri: getDocumentUri,
1248                errorCodes: ErrorCodes
1249        };
1250        return api;
1251}
1252
1253var tv4 = createApi();
1254tv4.addLanguage('en-gb', ErrorMessagesDefault);
1255
1256//legacy property
1257tv4.tv4 = tv4;
1258
1259if (typeof module !== 'undefined' && module.exports){
1260        module.exports = tv4;
1261}
1262else {
1263        global.tv4 = tv4;
1264}
1265
1266})(this);
1267
1268//@ sourceMappingURL=tv4.js.map
Note: See TracBrowser for help on using the repository browser.