diff options
| -rw-r--r-- | ext/js/data/json-schema.js | 112 | 
1 files changed, 78 insertions, 34 deletions
| diff --git a/ext/js/data/json-schema.js b/ext/js/data/json-schema.js index b91bfb47..2e3bf9bb 100644 --- a/ext/js/data/json-schema.js +++ b/ext/js/data/json-schema.js @@ -28,6 +28,9 @@ class JsonSchema {          this._refCache = null;          this._valueStack = [];          this._schemaStack = []; +        this._progress = null; +        this._progressCounter = 0; +        this._progressInterval = 1;          this._schemaPush(null, null);          this._valuePush(null, null); @@ -41,6 +44,22 @@ class JsonSchema {          return this._rootSchema;      } +    get progress() { +        return this._progress; +    } + +    set progress(value) { +        this._progress = value; +    } + +    get progressInterval() { +        return this._progressInterval; +    } + +    set progressInterval(value) { +        this._progressInterval = value; +    } +      createProxy(value) {          return (              typeof value === 'object' && value !== null ? @@ -100,6 +119,44 @@ class JsonSchema {          return Array.isArray(required) && required.includes(property);      } +    // Internal state functions for error construction and progress callback + +    getValueStack() { +        const valueStack = []; +        for (let i = 1, ii = this._valueStack.length; i < ii; ++i) { +            const {value, path} = this._valueStack[i]; +            valueStack.push({value, path}); +        } +        return valueStack; +    } + +    getSchemaStack() { +        const schemaStack = []; +        for (let i = 1, ii = this._schemaStack.length; i < ii; ++i) { +            const {schema, path} = this._schemaStack[i]; +            schemaStack.push({schema, path}); +        } +        return schemaStack; +    } + +    getValueStackLength() { +        return this._valueStack.length - 1; +    } + +    getValueStackItem(index) { +        const {value, path} = this._valueStack[index + 1]; +        return {value, path}; +    } + +    getSchemaStackLength() { +        return this._schemaStack.length - 1; +    } + +    getSchemaStackItem(index) { +        const {schema, path} = this._schemaStack[index + 1]; +        return {schema, path}; +    } +      // Stack      _valuePush(value, path) { @@ -123,21 +180,11 @@ class JsonSchema {      // Private      _createError(message) { -        const valueStack = []; -        for (let i = 1, ii = this._valueStack.length; i < ii; ++i) { -            const {value, path} = this._valueStack[i]; -            valueStack.push({value, path}); -        } - -        const schemaStack = []; -        for (let i = 1, ii = this._schemaStack.length; i < ii; ++i) { -            const {schema, path} = this._schemaStack[i]; -            schemaStack.push({schema, path}); -        } - +        const valueStack = this.getValueStack(); +        const schemaStack = this.getSchemaStack();          const error = new Error(message);          error.value = valueStack[valueStack.length - 1].value; -        error.schema = this._schema; +        error.schema = schemaStack[schemaStack.length - 1].schema;          error.valueStack = valueStack;          error.schemaStack = schemaStack;          return error; @@ -347,6 +394,12 @@ class JsonSchema {      }      _validate(value) { +        if (this._progress !== null) { +            const counter = (this._progressCounter + 1) % this._progressInterval; +            this._progressCounter = counter; +            if (counter === 0) { this._progress(this); } +        } +          const ref = this._schema.$ref;          const schemaInfo = (typeof ref === 'string') ? this._getReference(ref) : null; @@ -501,18 +554,16 @@ class JsonSchema {      }      _validateSingleSchema(value) { +        const {type: schemaType, const: schemaConst, enum: schemaEnum} = this._schema;          const type = this._getValueType(value); -        const schemaType = this._schema.type;          if (!this._isValueTypeAny(value, type, schemaType)) {              throw this._createError(`Value type ${type} does not match schema type ${schemaType}`);          } -        const schemaConst = this._schema.const;          if (typeof schemaConst !== 'undefined' && !this._valuesAreEqual(value, schemaConst)) {              throw this._createError('Invalid constant value');          } -        const schemaEnum = this._schema.enum;          if (Array.isArray(schemaEnum) && !this._valuesAreEqualAny(value, schemaEnum)) {              throw this._createError('Invalid enum value');          } @@ -534,44 +585,38 @@ class JsonSchema {      }      _validateNumber(value) { -        const {multipleOf} = this._schema; +        const {multipleOf, minimum, exclusiveMinimum, maximum, exclusiveMaximum} = this._schema;          if (typeof multipleOf === 'number' && Math.floor(value / multipleOf) * multipleOf !== value) {              throw this._createError(`Number is not a multiple of ${multipleOf}`);          } -        const {minimum} = this._schema;          if (typeof minimum === 'number' && value < minimum) {              throw this._createError(`Number is less than ${minimum}`);          } -        const {exclusiveMinimum} = this._schema;          if (typeof exclusiveMinimum === 'number' && value <= exclusiveMinimum) {              throw this._createError(`Number is less than or equal to ${exclusiveMinimum}`);          } -        const {maximum} = this._schema;          if (typeof maximum === 'number' && value > maximum) {              throw this._createError(`Number is greater than ${maximum}`);          } -        const {exclusiveMaximum} = this._schema;          if (typeof exclusiveMaximum === 'number' && value >= exclusiveMaximum) {              throw this._createError(`Number is greater than or equal to ${exclusiveMaximum}`);          }      }      _validateString(value) { -        const {minLength} = this._schema; +        const {minLength, maxLength, pattern} = this._schema;          if (typeof minLength === 'number' && value.length < minLength) {              throw this._createError('String length too short');          } -        const {maxLength} = this._schema;          if (typeof maxLength === 'number' && value.length > maxLength) {              throw this._createError('String length too long');          } -        const {pattern} = this._schema;          if (typeof pattern === 'string') {              let {patternFlags} = this._schema;              if (typeof patternFlags !== 'string') { patternFlags = ''; } @@ -590,14 +635,13 @@ class JsonSchema {      }      _validateArray(value) { +        const {minItems, maxItems} = this._schema;          const {length} = value; -        const {minItems} = this._schema;          if (typeof minItems === 'number' && length < minItems) {              throw this._createError('Array length too short');          } -        const {maxItems} = this._schema;          if (typeof maxItems === 'number' && length > maxItems) {              throw this._createError('Array length too long');          } @@ -648,28 +692,28 @@ class JsonSchema {      }      _validateObject(value) { -        const properties = new Set(Object.getOwnPropertyNames(value)); +        const {required, minProperties, maxProperties} = this._schema; +        const properties = Object.getOwnPropertyNames(value); +        const {length} = properties; -        const {required} = this._schema;          if (Array.isArray(required)) {              for (const property of required) { -                if (!properties.has(property)) { +                if (!Object.prototype.hasOwnProperty.call(value, property)) {                      throw this._createError(`Missing property ${property}`);                  }              }          } -        const {minProperties} = this._schema; -        if (typeof minProperties === 'number' && properties.length < minProperties) { +        if (typeof minProperties === 'number' && length < minProperties) {              throw this._createError('Not enough object properties');          } -        const {maxProperties} = this._schema; -        if (typeof maxProperties === 'number' && properties.length > maxProperties) { +        if (typeof maxProperties === 'number' && length > maxProperties) {              throw this._createError('Too many object properties');          } -        for (const property of properties) { +        for (let i = 0; i < length; ++i) { +            const property = properties[i];              const schemaInfo = this._getObjectPropertySchemaInfo(property);              if (schemaInfo === null) {                  throw this._createError(`No schema found for ${property}`); |