update electron to v43

This commit is contained in:
olcxja 2026-07-09 22:38:33 +02:00
commit fb6c8b6ee9
5385 changed files with 513060 additions and 123058 deletions

21
electron/node_modules/@peculiar/json-schema/LICENSE generated vendored Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

158
electron/node_modules/@peculiar/json-schema/README.md generated vendored Normal file
View file

@ -0,0 +1,158 @@
# JSON-SCHEMA
[![License](https://img.shields.io/badge/license-MIT-green.svg?style=flat)](https://raw.githubusercontent.com/PeculiarVentures/json-schema/master/LICENSE.md)
[![CircleCI](https://circleci.com/gh/PeculiarVentures/json-schema.svg?style=svg)](https://circleci.com/gh/PeculiarVentures/json-schema)
[![Coverage Status](https://coveralls.io/repos/github/PeculiarVentures/json-schema/badge.svg?branch=master&t=ddJivl)](https://coveralls.io/github/PeculiarVentures/json-schema?branch=master)
[![npm version](https://badge.fury.io/js/%40peculiar%2Fjson-schema.svg)](https://badge.fury.io/js/%40peculiar%2Fjson-schema)
[![NPM](https://nodei.co/npm/@peculiar/json-schema.png)](https://nodei.co/npm/@peculiar/json-schema/)
This package uses ES2015 [decorators](https://medium.com/google-developers/exploring-es7-decorators-76ecb65fb841) to simplify JSON [schema creation and use](https://json-schema.org/understanding-json-schema/index.html).
## Introduction
JSON (JavaScript Object Notation) is a lightweight data-interchange format that was designed to be easy for humans to read and write but in practice, it is [minefield](http://seriot.ch/parsing_json.html) when it machines need to parse it.
While the use of schemas can help with this problem their use can be complicated. When using `json-schema` this is addressed by using decorators to make both serialization and parsing of XML possible via a simple class that handles the schemas for you.
This is important because validating input data before its use is important to do because all input data is evil. Using a schema helps you handle this data [safely](https://www.whitehatsec.com/blog/handling-untrusted-json-safely/).
## Installation
Installation is handled via `npm`:
```
$ npm install @peculiar/json-schema
```
## Examples
### Node.js
Creating a schema:
```js
import { JsonParser, JsonSerializer, JsonProp, JsonPropTypes, IJsonConverter } from "@peculiar/json-schema";
// custom data converter
const JsonBase64UrlConverter: IJsonConverter<Uint8Array, string> = {
fromJSON: (value: string) => base64UrlToBuffer(value),
toJSON: (value: Uint8Array) => bufferToBase64Url(value),
};
class EcPublicKey {
@JsonProp({ name: "kty" })
keyType = "EC";
@JsonProp({ name: "crv" })
namedCurve = "";
@JsonProp({ converter: JsonBase64UrlConverter })
x = new Uint8Array(0);
@JsonProp({ converter: JsonBase64UrlConverter })
y = new Uint8Array(0);
@JsonProp({ name: "ext", type: JsonPropTypes.Boolean, optional: true })
extractable = false;
@JsonProp({ name: "key_ops", type: JsonPropTypes.String, repeated: true, optional: true })
usages: string[] = [];
}
const json = `{
"kty": "EC",
"crv": "P-256",
"x": "zCQ5BPHPCLZYgdpo1n-x_90P2Ij52d53YVwTh3ZdiMo",
"y": "pDfQTUx0-OiZc5ZuKMcA7v2Q7ZPKsQwzB58bft0JTko",
"ext": true
}`;
const ecPubKey = JsonParser.parse(json, { targetSchema: EcPublicKey });
console.log(ecPubKey);
ecPubKey.usages.push("verify");
const jsonText = JsonSerializer.serialize(ecPubKey, undefined, undefined, 2);
console.log(jsonText);
// Output
//
// EcPublicKey {keyType: "EC", namedCurve: "P-256", x: Uint8Array(32), y: Uint8Array(32), extractable: true, …}
//
// {
// "kty": "EC",
// "crv": "P-256",
// "x": "zCQ5BPHPCLZYgdpo1n+x/90P2Ij52d53YVwTh3ZdiMo=",
// "y": "pDfQTUx0+OiZc5ZuKMcA7v2Q7ZPKsQwzB58bft0JTko=",
// "ext": true,
// "key_ops": [
// "verify"
// ]
// }
```
Extending a Schema:
```js
class BaseObject {
@JsonProp({ name: "i" })
public id = 0;
}
class Word extends BaseObject {
@JsonProp({ name: "t" })
public text = "";
}
class Person extends BaseObject {
@JsonProp({ name: "n" })
public name = 0;
@JsonProp({ name: "w", repeated: true, type: Word })
public words = [];
}
const json = `{
"i":1,
"n":"Bob",
"w":[
{"i":2,"t":"hello"},
{"i":3,"t":"world"}
]
}`;
const person = JsonParser.parse(json, { targetSchema: Person });
console.log(person);
const word = new Word();
word.id = 4;
word.text = "!!!";
const jsonText = JsonSerializer.serialize(person, undefined, undefined, 2);
console.log(jsonText);
// Output
//
// Person {id: 1, name: "Bob", words: [Word {id: 2, text: "hello"}, Word {id: 3, text: "world"}]}
// {
// "i": 1,
// "n": "Bob",
// "w": [
// {
// "i": 2,
// "t": "hello"
// },
// {
// "i": 3,
// "t": "world"
// },
// {
// "i": 4,
// "t": "!!!"
// }
// ]
// }
```
## API
Use [index.d.ts](index.d.ts) file

View file

@ -0,0 +1,484 @@
/**
* Copyright (c) 2020, Peculiar Ventures, All rights reserved.
*/
class JsonError extends Error {
constructor(message, innerError) {
super(innerError
? `${message}. See the inner exception for more details.`
: message);
this.message = message;
this.innerError = innerError;
}
}
class TransformError extends JsonError {
constructor(schema, message, innerError) {
super(message, innerError);
this.schema = schema;
}
}
class ParserError extends TransformError {
constructor(schema, message, innerError) {
super(schema, `JSON doesn't match to '${schema.target.name}' schema. ${message}`, innerError);
}
}
class ValidationError extends JsonError {
}
class SerializerError extends JsonError {
constructor(schemaName, message, innerError) {
super(`Cannot serialize by '${schemaName}' schema. ${message}`, innerError);
this.schemaName = schemaName;
}
}
class KeyError extends ParserError {
constructor(schema, keys, errors = {}) {
super(schema, "Some keys doesn't match to schema");
this.keys = keys;
this.errors = errors;
}
}
var JsonPropTypes;
(function (JsonPropTypes) {
JsonPropTypes[JsonPropTypes["Any"] = 0] = "Any";
JsonPropTypes[JsonPropTypes["Boolean"] = 1] = "Boolean";
JsonPropTypes[JsonPropTypes["Number"] = 2] = "Number";
JsonPropTypes[JsonPropTypes["String"] = 3] = "String";
})(JsonPropTypes || (JsonPropTypes = {}));
function checkType(value, type) {
switch (type) {
case JsonPropTypes.Boolean:
return typeof value === "boolean";
case JsonPropTypes.Number:
return typeof value === "number";
case JsonPropTypes.String:
return typeof value === "string";
}
return true;
}
function throwIfTypeIsWrong(value, type) {
if (!checkType(value, type)) {
throw new TypeError(`Value must be ${JsonPropTypes[type]}`);
}
}
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toJSON && target.prototype.fromJSON) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && target.toJSON && target.fromJSON);
}
}
class JsonSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target) || !!this.findParentSchema(target);
}
get(target) {
const schema = this.items.get(target) || this.findParentSchema(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
create(target) {
const schema = { names: {} };
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.names = {};
for (const name in parentSchema.names) {
schema.names[name] = Object.assign({}, parentSchema.names[name]);
}
}
schema.target = target;
return schema;
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const DEFAULT_SCHEMA = "default";
const schemaStorage = new JsonSchemaStorage();
class PatternValidation {
constructor(pattern) {
this.pattern = new RegExp(pattern);
}
validate(value) {
const pattern = new RegExp(this.pattern.source, this.pattern.flags);
if (typeof value !== "string") {
throw new ValidationError("Incoming value must be string");
}
if (!pattern.exec(value)) {
throw new ValidationError(`Value doesn't match to pattern '${pattern.toString()}'`);
}
}
}
class InclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.Number);
if (!(this.min <= value && value <= this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason [${min},${max}]`);
}
}
}
class ExclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.Number);
if (!(this.min < value && value < this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason (${min},${max})`);
}
}
}
class LengthValidation {
constructor(length, minLength, maxLength) {
this.length = length;
this.minLength = minLength;
this.maxLength = maxLength;
}
validate(value) {
if (this.length !== undefined) {
if (value.length !== this.length) {
throw new ValidationError(`Value length must be exactly ${this.length}.`);
}
return;
}
if (this.minLength !== undefined) {
if (value.length < this.minLength) {
throw new ValidationError(`Value length must be more than ${this.minLength}.`);
}
}
if (this.maxLength !== undefined) {
if (value.length > this.maxLength) {
throw new ValidationError(`Value length must be less than ${this.maxLength}.`);
}
}
}
}
class EnumerationValidation {
constructor(enumeration) {
this.enumeration = enumeration;
}
validate(value) {
throwIfTypeIsWrong(value, JsonPropTypes.String);
if (!this.enumeration.includes(value)) {
throw new ValidationError(`Value must be one of ${this.enumeration.map((v) => `'${v}'`).join(", ")}`);
}
}
}
class JsonTransform {
static checkValues(data, schemaItem) {
const values = Array.isArray(data) ? data : [data];
for (const value of values) {
for (const validation of schemaItem.validations) {
if (validation instanceof LengthValidation && schemaItem.repeated) {
validation.validate(data);
}
else {
validation.validate(value);
}
}
}
}
static checkTypes(value, schemaItem) {
if (schemaItem.repeated && !Array.isArray(value)) {
throw new TypeError("Value must be Array");
}
if (typeof schemaItem.type === "number") {
const values = Array.isArray(value) ? value : [value];
for (const v of values) {
throwIfTypeIsWrong(v, schemaItem.type);
}
}
}
static getSchemaByName(schema, name = DEFAULT_SCHEMA) {
return { ...schema.names[DEFAULT_SCHEMA], ...schema.names[name] };
}
}
class JsonSerializer extends JsonTransform {
static serialize(obj, options, replacer, space) {
const json = this.toJSON(obj, options);
return JSON.stringify(json, replacer, space);
}
static toJSON(obj, options = {}) {
let res;
let targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
if (isConvertible(obj)) {
return obj.toJSON();
}
if (Array.isArray(obj)) {
res = [];
for (const item of obj) {
res.push(this.toJSON(item, options));
}
}
else if (typeof obj === "object") {
if (targetSchema && !schemaStorage.has(targetSchema)) {
throw new JsonError("Cannot get schema for `targetSchema` param");
}
targetSchema = (targetSchema || obj.constructor);
if (schemaStorage.has(targetSchema)) {
const schema = schemaStorage.get(targetSchema);
res = {};
const namedSchema = this.getSchemaByName(schema, schemaName);
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const objItem = obj[key];
let value;
if ((item.optional && objItem === undefined)
|| (item.defaultValue !== undefined && objItem === item.defaultValue)) {
continue;
}
if (!item.optional && objItem === undefined) {
throw new SerializerError(targetSchema.name, `Property '${key}' is required.`);
}
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
value = objItem.map((el) => item.converter.toJSON(el, obj));
}
else {
value = item.converter.toJSON(objItem, obj);
}
}
else {
value = objItem;
}
}
else {
if (item.repeated) {
value = objItem.map((el) => this.toJSON(el, { schemaName }));
}
else {
value = this.toJSON(objItem, { schemaName });
}
}
this.checkTypes(value, item);
this.checkValues(value, item);
res[item.name || key] = value;
}
catch (e) {
if (e instanceof SerializerError) {
throw e;
}
else {
throw new SerializerError(schema.target.name, `Property '${key}' is wrong. ${e.message}`, e);
}
}
}
}
else {
res = {};
for (const key in obj) {
res[key] = this.toJSON(obj[key], { schemaName });
}
}
}
else {
res = obj;
}
return res;
}
}
class JsonParser extends JsonTransform {
static parse(data, options) {
const obj = JSON.parse(data);
return this.fromJSON(obj, options);
}
static fromJSON(target, options) {
const targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
const obj = new targetSchema();
if (isConvertible(obj)) {
return obj.fromJSON(target);
}
const schema = schemaStorage.get(targetSchema);
const namedSchema = this.getSchemaByName(schema, schemaName);
const keyErrors = {};
if (options.strictProperty && !Array.isArray(target)) {
JsonParser.checkStrictProperty(target, namedSchema, schema);
}
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const name = item.name || key;
const value = target[name];
if (value === undefined && (item.optional || item.defaultValue !== undefined)) {
continue;
}
if (!item.optional && value === undefined) {
throw new ParserError(schema, `Property '${name}' is required.`);
}
this.checkTypes(value, item);
this.checkValues(value, item);
if (typeof (item.type) === "number") {
if (item.converter) {
if (item.repeated) {
obj[key] = value.map((el) => item.converter.fromJSON(el, obj));
}
else {
obj[key] = item.converter.fromJSON(value, obj);
}
}
else {
obj[key] = value;
}
}
else {
const newOptions = {
...options,
targetSchema: item.type,
schemaName,
};
if (item.repeated) {
obj[key] = value.map((el) => this.fromJSON(el, newOptions));
}
else {
obj[key] = this.fromJSON(value, newOptions);
}
}
}
catch (e) {
if (!(e instanceof ParserError)) {
e = new ParserError(schema, `Property '${key}' is wrong. ${e.message}`, e);
}
if (options.strictAllKeys) {
keyErrors[key] = e;
}
else {
throw e;
}
}
}
const keys = Object.keys(keyErrors);
if (keys.length) {
throw new KeyError(schema, keys, keyErrors);
}
return obj;
}
static checkStrictProperty(target, namedSchema, schema) {
const jsonProps = Object.keys(target);
const schemaProps = Object.keys(namedSchema);
const keys = [];
for (const key of jsonProps) {
if (schemaProps.indexOf(key) === -1) {
keys.push(key);
}
}
if (keys.length) {
throw new KeyError(schema, keys);
}
}
}
function getValidations(item) {
const validations = [];
if (item.pattern) {
validations.push(new PatternValidation(item.pattern));
}
if (item.type === JsonPropTypes.Number || item.type === JsonPropTypes.Any) {
if (item.minInclusive !== undefined || item.maxInclusive !== undefined) {
validations.push(new InclusiveValidation(item.minInclusive, item.maxInclusive));
}
if (item.minExclusive !== undefined || item.maxExclusive !== undefined) {
validations.push(new ExclusiveValidation(item.minExclusive, item.maxExclusive));
}
if (item.enumeration !== undefined) {
validations.push(new EnumerationValidation(item.enumeration));
}
}
if (item.type === JsonPropTypes.String || item.repeated || item.type === JsonPropTypes.Any) {
if (item.length !== undefined || item.minLength !== undefined || item.maxLength !== undefined) {
validations.push(new LengthValidation(item.length, item.minLength, item.maxLength));
}
}
return validations;
}
const JsonProp = (options = {}) => (target, propertyKey) => {
const errorMessage = `Cannot set type for ${propertyKey} property of ${target.constructor.name} schema`;
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
else {
schema = schemaStorage.get(target.constructor);
if (schema.target !== target.constructor) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
}
const defaultSchema = {
type: JsonPropTypes.Any,
validations: [],
};
const copyOptions = Object.assign(defaultSchema, options);
copyOptions.validations = getValidations(copyOptions);
if (typeof copyOptions.type !== "number") {
if (!schemaStorage.has(copyOptions.type) && !isConvertible(copyOptions.type)) {
throw new Error(`${errorMessage}. Assigning type doesn't have schema.`);
}
}
let schemaNames;
if (Array.isArray(options.schema)) {
schemaNames = options.schema;
}
else {
schemaNames = [options.schema || DEFAULT_SCHEMA];
}
for (const schemaName of schemaNames) {
if (!schema.names[schemaName]) {
schema.names[schemaName] = {};
}
const namedSchema = schema.names[schemaName];
namedSchema[propertyKey] = copyOptions;
}
};
export { JsonError, JsonParser, JsonProp, JsonPropTypes, JsonSerializer, KeyError, ParserError, SerializerError, TransformError, ValidationError };

View file

@ -0,0 +1,495 @@
/**
* Copyright (c) 2020, Peculiar Ventures, All rights reserved.
*/
'use strict';
Object.defineProperty(exports, '__esModule', { value: true });
class JsonError extends Error {
constructor(message, innerError) {
super(innerError
? `${message}. See the inner exception for more details.`
: message);
this.message = message;
this.innerError = innerError;
}
}
class TransformError extends JsonError {
constructor(schema, message, innerError) {
super(message, innerError);
this.schema = schema;
}
}
class ParserError extends TransformError {
constructor(schema, message, innerError) {
super(schema, `JSON doesn't match to '${schema.target.name}' schema. ${message}`, innerError);
}
}
class ValidationError extends JsonError {
}
class SerializerError extends JsonError {
constructor(schemaName, message, innerError) {
super(`Cannot serialize by '${schemaName}' schema. ${message}`, innerError);
this.schemaName = schemaName;
}
}
class KeyError extends ParserError {
constructor(schema, keys, errors = {}) {
super(schema, "Some keys doesn't match to schema");
this.keys = keys;
this.errors = errors;
}
}
(function (JsonPropTypes) {
JsonPropTypes[JsonPropTypes["Any"] = 0] = "Any";
JsonPropTypes[JsonPropTypes["Boolean"] = 1] = "Boolean";
JsonPropTypes[JsonPropTypes["Number"] = 2] = "Number";
JsonPropTypes[JsonPropTypes["String"] = 3] = "String";
})(exports.JsonPropTypes || (exports.JsonPropTypes = {}));
function checkType(value, type) {
switch (type) {
case exports.JsonPropTypes.Boolean:
return typeof value === "boolean";
case exports.JsonPropTypes.Number:
return typeof value === "number";
case exports.JsonPropTypes.String:
return typeof value === "string";
}
return true;
}
function throwIfTypeIsWrong(value, type) {
if (!checkType(value, type)) {
throw new TypeError(`Value must be ${exports.JsonPropTypes[type]}`);
}
}
function isConvertible(target) {
if (target && target.prototype) {
if (target.prototype.toJSON && target.prototype.fromJSON) {
return true;
}
else {
return isConvertible(target.prototype);
}
}
else {
return !!(target && target.toJSON && target.fromJSON);
}
}
class JsonSchemaStorage {
constructor() {
this.items = new Map();
}
has(target) {
return this.items.has(target) || !!this.findParentSchema(target);
}
get(target) {
const schema = this.items.get(target) || this.findParentSchema(target);
if (!schema) {
throw new Error("Cannot get schema for current target");
}
return schema;
}
create(target) {
const schema = { names: {} };
const parentSchema = this.findParentSchema(target);
if (parentSchema) {
Object.assign(schema, parentSchema);
schema.names = {};
for (const name in parentSchema.names) {
schema.names[name] = Object.assign({}, parentSchema.names[name]);
}
}
schema.target = target;
return schema;
}
set(target, schema) {
this.items.set(target, schema);
return this;
}
findParentSchema(target) {
const parent = target.__proto__;
if (parent) {
const schema = this.items.get(parent);
return schema || this.findParentSchema(parent);
}
return null;
}
}
const DEFAULT_SCHEMA = "default";
const schemaStorage = new JsonSchemaStorage();
class PatternValidation {
constructor(pattern) {
this.pattern = new RegExp(pattern);
}
validate(value) {
const pattern = new RegExp(this.pattern.source, this.pattern.flags);
if (typeof value !== "string") {
throw new ValidationError("Incoming value must be string");
}
if (!pattern.exec(value)) {
throw new ValidationError(`Value doesn't match to pattern '${pattern.toString()}'`);
}
}
}
class InclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min <= value && value <= this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason [${min},${max}]`);
}
}
}
class ExclusiveValidation {
constructor(min = Number.MIN_VALUE, max = Number.MAX_VALUE) {
this.min = min;
this.max = max;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.Number);
if (!(this.min < value && value < this.max)) {
const min = this.min === Number.MIN_VALUE ? "MIN" : this.min;
const max = this.max === Number.MAX_VALUE ? "MAX" : this.max;
throw new ValidationError(`Value doesn't match to diapason (${min},${max})`);
}
}
}
class LengthValidation {
constructor(length, minLength, maxLength) {
this.length = length;
this.minLength = minLength;
this.maxLength = maxLength;
}
validate(value) {
if (this.length !== undefined) {
if (value.length !== this.length) {
throw new ValidationError(`Value length must be exactly ${this.length}.`);
}
return;
}
if (this.minLength !== undefined) {
if (value.length < this.minLength) {
throw new ValidationError(`Value length must be more than ${this.minLength}.`);
}
}
if (this.maxLength !== undefined) {
if (value.length > this.maxLength) {
throw new ValidationError(`Value length must be less than ${this.maxLength}.`);
}
}
}
}
class EnumerationValidation {
constructor(enumeration) {
this.enumeration = enumeration;
}
validate(value) {
throwIfTypeIsWrong(value, exports.JsonPropTypes.String);
if (!this.enumeration.includes(value)) {
throw new ValidationError(`Value must be one of ${this.enumeration.map((v) => `'${v}'`).join(", ")}`);
}
}
}
class JsonTransform {
static checkValues(data, schemaItem) {
const values = Array.isArray(data) ? data : [data];
for (const value of values) {
for (const validation of schemaItem.validations) {
if (validation instanceof LengthValidation && schemaItem.repeated) {
validation.validate(data);
}
else {
validation.validate(value);
}
}
}
}
static checkTypes(value, schemaItem) {
if (schemaItem.repeated && !Array.isArray(value)) {
throw new TypeError("Value must be Array");
}
if (typeof schemaItem.type === "number") {
const values = Array.isArray(value) ? value : [value];
for (const v of values) {
throwIfTypeIsWrong(v, schemaItem.type);
}
}
}
static getSchemaByName(schema, name = DEFAULT_SCHEMA) {
return { ...schema.names[DEFAULT_SCHEMA], ...schema.names[name] };
}
}
class JsonSerializer extends JsonTransform {
static serialize(obj, options, replacer, space) {
const json = this.toJSON(obj, options);
return JSON.stringify(json, replacer, space);
}
static toJSON(obj, options = {}) {
let res;
let targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
if (isConvertible(obj)) {
return obj.toJSON();
}
if (Array.isArray(obj)) {
res = [];
for (const item of obj) {
res.push(this.toJSON(item, options));
}
}
else if (typeof obj === "object") {
if (targetSchema && !schemaStorage.has(targetSchema)) {
throw new JsonError("Cannot get schema for `targetSchema` param");
}
targetSchema = (targetSchema || obj.constructor);
if (schemaStorage.has(targetSchema)) {
const schema = schemaStorage.get(targetSchema);
res = {};
const namedSchema = this.getSchemaByName(schema, schemaName);
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const objItem = obj[key];
let value;
if ((item.optional && objItem === undefined)
|| (item.defaultValue !== undefined && objItem === item.defaultValue)) {
continue;
}
if (!item.optional && objItem === undefined) {
throw new SerializerError(targetSchema.name, `Property '${key}' is required.`);
}
if (typeof item.type === "number") {
if (item.converter) {
if (item.repeated) {
value = objItem.map((el) => item.converter.toJSON(el, obj));
}
else {
value = item.converter.toJSON(objItem, obj);
}
}
else {
value = objItem;
}
}
else {
if (item.repeated) {
value = objItem.map((el) => this.toJSON(el, { schemaName }));
}
else {
value = this.toJSON(objItem, { schemaName });
}
}
this.checkTypes(value, item);
this.checkValues(value, item);
res[item.name || key] = value;
}
catch (e) {
if (e instanceof SerializerError) {
throw e;
}
else {
throw new SerializerError(schema.target.name, `Property '${key}' is wrong. ${e.message}`, e);
}
}
}
}
else {
res = {};
for (const key in obj) {
res[key] = this.toJSON(obj[key], { schemaName });
}
}
}
else {
res = obj;
}
return res;
}
}
class JsonParser extends JsonTransform {
static parse(data, options) {
const obj = JSON.parse(data);
return this.fromJSON(obj, options);
}
static fromJSON(target, options) {
const targetSchema = options.targetSchema;
const schemaName = options.schemaName || DEFAULT_SCHEMA;
const obj = new targetSchema();
if (isConvertible(obj)) {
return obj.fromJSON(target);
}
const schema = schemaStorage.get(targetSchema);
const namedSchema = this.getSchemaByName(schema, schemaName);
const keyErrors = {};
if (options.strictProperty && !Array.isArray(target)) {
JsonParser.checkStrictProperty(target, namedSchema, schema);
}
for (const key in namedSchema) {
try {
const item = namedSchema[key];
const name = item.name || key;
const value = target[name];
if (value === undefined && (item.optional || item.defaultValue !== undefined)) {
continue;
}
if (!item.optional && value === undefined) {
throw new ParserError(schema, `Property '${name}' is required.`);
}
this.checkTypes(value, item);
this.checkValues(value, item);
if (typeof (item.type) === "number") {
if (item.converter) {
if (item.repeated) {
obj[key] = value.map((el) => item.converter.fromJSON(el, obj));
}
else {
obj[key] = item.converter.fromJSON(value, obj);
}
}
else {
obj[key] = value;
}
}
else {
const newOptions = {
...options,
targetSchema: item.type,
schemaName,
};
if (item.repeated) {
obj[key] = value.map((el) => this.fromJSON(el, newOptions));
}
else {
obj[key] = this.fromJSON(value, newOptions);
}
}
}
catch (e) {
if (!(e instanceof ParserError)) {
e = new ParserError(schema, `Property '${key}' is wrong. ${e.message}`, e);
}
if (options.strictAllKeys) {
keyErrors[key] = e;
}
else {
throw e;
}
}
}
const keys = Object.keys(keyErrors);
if (keys.length) {
throw new KeyError(schema, keys, keyErrors);
}
return obj;
}
static checkStrictProperty(target, namedSchema, schema) {
const jsonProps = Object.keys(target);
const schemaProps = Object.keys(namedSchema);
const keys = [];
for (const key of jsonProps) {
if (schemaProps.indexOf(key) === -1) {
keys.push(key);
}
}
if (keys.length) {
throw new KeyError(schema, keys);
}
}
}
function getValidations(item) {
const validations = [];
if (item.pattern) {
validations.push(new PatternValidation(item.pattern));
}
if (item.type === exports.JsonPropTypes.Number || item.type === exports.JsonPropTypes.Any) {
if (item.minInclusive !== undefined || item.maxInclusive !== undefined) {
validations.push(new InclusiveValidation(item.minInclusive, item.maxInclusive));
}
if (item.minExclusive !== undefined || item.maxExclusive !== undefined) {
validations.push(new ExclusiveValidation(item.minExclusive, item.maxExclusive));
}
if (item.enumeration !== undefined) {
validations.push(new EnumerationValidation(item.enumeration));
}
}
if (item.type === exports.JsonPropTypes.String || item.repeated || item.type === exports.JsonPropTypes.Any) {
if (item.length !== undefined || item.minLength !== undefined || item.maxLength !== undefined) {
validations.push(new LengthValidation(item.length, item.minLength, item.maxLength));
}
}
return validations;
}
const JsonProp = (options = {}) => (target, propertyKey) => {
const errorMessage = `Cannot set type for ${propertyKey} property of ${target.constructor.name} schema`;
let schema;
if (!schemaStorage.has(target.constructor)) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
else {
schema = schemaStorage.get(target.constructor);
if (schema.target !== target.constructor) {
schema = schemaStorage.create(target.constructor);
schemaStorage.set(target.constructor, schema);
}
}
const defaultSchema = {
type: exports.JsonPropTypes.Any,
validations: [],
};
const copyOptions = Object.assign(defaultSchema, options);
copyOptions.validations = getValidations(copyOptions);
if (typeof copyOptions.type !== "number") {
if (!schemaStorage.has(copyOptions.type) && !isConvertible(copyOptions.type)) {
throw new Error(`${errorMessage}. Assigning type doesn't have schema.`);
}
}
let schemaNames;
if (Array.isArray(options.schema)) {
schemaNames = options.schema;
}
else {
schemaNames = [options.schema || DEFAULT_SCHEMA];
}
for (const schemaName of schemaNames) {
if (!schema.names[schemaName]) {
schema.names[schemaName] = {};
}
const namedSchema = schema.names[schemaName];
namedSchema[propertyKey] = copyOptions;
}
};
exports.JsonError = JsonError;
exports.JsonParser = JsonParser;
exports.JsonProp = JsonProp;
exports.JsonSerializer = JsonSerializer;
exports.KeyError = KeyError;
exports.ParserError = ParserError;
exports.SerializerError = SerializerError;
exports.TransformError = TransformError;
exports.ValidationError = ValidationError;

View file

@ -0,0 +1,51 @@
import { JsonPropTypes } from "./prop_types";
import { IEmptyConstructor, IJsonConverter } from "./types";
export interface IJsonPropOptions {
type?: JsonPropTypes | IEmptyConstructor<any>;
optional?: boolean;
defaultValue?: any;
converter?: IJsonConverter<any, any>;
repeated?: boolean;
name?: string;
/**
* Defines name of schema
*/
schema?: string | string[];
/**
* Defines regular expression for text
*/
pattern?: string | RegExp;
/**
* Defines a list of acceptable values
*/
enumeration?: string[];
/**
* Specifies the exact number of characters or list items allowed. Must be equal to or greater than zero
*/
length?: number;
/**
* Specifies the minimum number of characters or list items allowed. Must be equal to or greater than zero
*/
minLength?: number;
/**
* Specifies the maximum number of characters or list items allowed. Must be equal to or greater than zero
*/
maxLength?: number;
/**
* Specifies the lower bounds for numeric values (the value must be greater than or equal to this value)
*/
minInclusive?: number;
/**
* Specifies the upper bounds for numeric values (the value must be less than or equal to this value)
*/
maxInclusive?: number;
/**
* Specifies the lower bounds for numeric values (the value must be greater than this value)
*/
minExclusive?: number;
/**
* Specifies the upper bounds for numeric values (the value must be less than this value)
*/
maxExclusive?: number;
}
export declare const JsonProp: (options?: IJsonPropOptions) => (target: object, propertyKey: string) => void;

View file

@ -0,0 +1,6 @@
export * from "./json_error";
export * from "./parser_error";
export * from "./validation_error";
export * from "./serializer_error";
export * from "./transform_error";
export * from "./key_error";

View file

@ -0,0 +1,5 @@
export declare class JsonError extends Error {
message: string;
innerError?: Error | undefined;
constructor(message: string, innerError?: Error | undefined);
}

View file

@ -0,0 +1,10 @@
import { IJsonSchema } from "../schema";
import { ParserError } from "./parser_error";
export interface IKeyErrors {
[key: string]: Error;
}
export declare class KeyError extends ParserError {
keys: string[];
errors: IKeyErrors;
constructor(schema: IJsonSchema, keys: string[], errors?: IKeyErrors);
}

View file

@ -0,0 +1,5 @@
import { IJsonSchema } from "../schema";
import { TransformError } from "./transform_error";
export declare class ParserError extends TransformError {
constructor(schema: IJsonSchema, message: string, innerError?: Error);
}

View file

@ -0,0 +1,5 @@
import { JsonError } from "./json_error";
export declare class SerializerError extends JsonError {
schemaName: string;
constructor(schemaName: string, message: string, innerError?: Error);
}

View file

@ -0,0 +1,6 @@
import { IJsonSchema } from "../schema";
import { JsonError } from "./json_error";
export declare class TransformError extends JsonError {
schema: IJsonSchema;
constructor(schema: IJsonSchema, message: string, innerError?: Error);
}

View file

@ -0,0 +1,3 @@
import { JsonError } from "./json_error";
export declare class ValidationError extends JsonError {
}

View file

@ -0,0 +1,5 @@
import { JsonPropTypes } from "./prop_types";
import { IJsonConvertible } from "./types";
export declare function checkType(value: any, type: JsonPropTypes): boolean;
export declare function throwIfTypeIsWrong(value: any, type: JsonPropTypes): void;
export declare function isConvertible(target: any): target is IJsonConvertible;

View file

@ -0,0 +1,6 @@
export * from "./serializer";
export * from "./parser";
export * from "./decorators";
export { JsonPropTypes } from "./prop_types";
export * from "./types";
export * from "./errors";

View file

@ -0,0 +1,26 @@
import { JsonTransform } from "./transform";
import { IEmptyConstructor } from "./types";
export interface IJsonParserOptions<T> {
targetSchema: IEmptyConstructor<T>;
schemaName?: string;
/**
* Enable strict checking of properties. Throw exception if incoming JSON has odd fields
*/
strictProperty?: boolean;
/**
* Checks all properties for object and throws KeyError with list of wrong keys
*/
strictAllKeys?: boolean;
}
export declare class JsonParser extends JsonTransform {
static parse<T>(data: string, options: IJsonParserOptions<T>): T;
static fromJSON<T>(target: any, options: IJsonParserOptions<T>): T;
/**
* Checks for odd properties in target object.
* @param target Target object
* @param namedSchema Named schema with a list of properties
* @param schema
* @throws Throws ParserError exception whenever target object has odd property
*/
private static checkStrictProperty;
}

View file

@ -0,0 +1,6 @@
export declare enum JsonPropTypes {
Any = 0,
Boolean = 1,
Number = 2,
String = 3
}

View file

@ -0,0 +1,35 @@
import { JsonPropTypes } from "./prop_types";
import { IEmptyConstructor, IJsonConverter, IValidation } from "./types";
export interface IValidationEvent {
propName: string;
value: any;
}
export interface IJsonSchemaItem {
type: JsonPropTypes | IEmptyConstructor<any>;
optional?: boolean;
defaultValue?: any;
converter?: IJsonConverter<any, any>;
repeated?: boolean;
name?: string;
validations: IValidation[];
}
export interface IJsonSchema {
target: IEmptyConstructor<any>;
names: {
[key: string]: {
[key: string]: IJsonSchemaItem;
};
};
}
export declare class JsonSchemaStorage {
protected items: Map<object, IJsonSchema>;
has(target: object): boolean;
get(target: object): IJsonSchema;
/**
* Creates new schema
* @param target Target object
*/
create(target: object): IJsonSchema;
set(target: object, schema: IJsonSchema): this;
protected findParentSchema(target: object): IJsonSchema | null;
}

View file

@ -0,0 +1,10 @@
import { JsonTransform } from "./transform";
import { IEmptyConstructor } from "./types";
export interface IJsonSerializerOptions {
targetSchema?: IEmptyConstructor<any>;
schemaName?: string;
}
export declare class JsonSerializer extends JsonTransform {
static serialize(obj: any, options?: IJsonSerializerOptions, replacer?: (key: string, value: any) => any, space?: string | number): string;
static toJSON(obj: any, options?: IJsonSerializerOptions): any;
}

View file

@ -0,0 +1,6 @@
import { JsonSchemaStorage } from "./schema";
/**
* Name of default schema
*/
export declare const DEFAULT_SCHEMA = "default";
export declare const schemaStorage: JsonSchemaStorage;

View file

@ -0,0 +1,9 @@
import { IJsonSchema, IJsonSchemaItem } from "./schema";
export interface IJsonNamedSchema {
[key: string]: IJsonSchemaItem;
}
export declare class JsonTransform {
protected static checkValues(data: any, schemaItem: IJsonSchemaItem): void;
protected static checkTypes(value: any, schemaItem: IJsonSchemaItem): void;
protected static getSchemaByName(schema: IJsonSchema, name?: string): IJsonNamedSchema;
}

View file

@ -0,0 +1,12 @@
export declare type IEmptyConstructor<T> = new () => T;
export interface IJsonConverter<T, S> {
fromJSON(value: S, target: any): T;
toJSON(value: T, target: any): S;
}
export interface IJsonConvertible<T = any> {
fromJSON(json: T): this;
toJSON(): T;
}
export interface IValidation {
validate(value: any): void;
}

View file

@ -0,0 +1,6 @@
import { IValidation } from "../types";
export declare class EnumerationValidation implements IValidation {
private enumeration;
constructor(enumeration: string[]);
validate(value: any): void;
}

View file

@ -0,0 +1,7 @@
import { IValidation } from "../types";
export declare class ExclusiveValidation implements IValidation {
private min;
private max;
constructor(min?: number, max?: number);
validate(value: any): void;
}

View file

@ -0,0 +1,7 @@
import { IValidation } from "../types";
export declare class InclusiveValidation implements IValidation {
private min;
private max;
constructor(min?: number, max?: number);
validate(value: any): void;
}

View file

@ -0,0 +1,5 @@
export * from "./pattern";
export * from "./inclusive";
export * from "./exclusive";
export * from "./length";
export * from "./enumeration";

View file

@ -0,0 +1,8 @@
import { IValidation } from "../types";
export declare class LengthValidation implements IValidation {
private length?;
private minLength?;
private maxLength?;
constructor(length?: number | undefined, minLength?: number | undefined, maxLength?: number | undefined);
validate(value: any): void;
}

View file

@ -0,0 +1,6 @@
import { IValidation } from "../types";
export declare class PatternValidation implements IValidation {
private pattern;
constructor(pattern: string | RegExp);
validate(value: any): void;
}

View file

@ -0,0 +1,95 @@
{
"name": "@peculiar/json-schema",
"version": "1.1.12",
"description": "This package uses ES2015 decorators to simplify JSON schema creation and use",
"main": "build/index.js",
"module": "build/index.es.js",
"types": "build/types/index.d.ts",
"scripts": {
"test": "mocha",
"prepare": "npm run build",
"lint": "tslint -p .",
"lint:fix": "tslint --fix -p .",
"build": "npm run build:module && npm run build:types",
"build:module": "rollup -c",
"build:types": "tsc -p tsconfig.types.json",
"clear": "rimraf build/*",
"rebuild": "npm run clear && npm run build",
"prepub": "npm run lint && npm run build",
"pub": "npm version patch && npm publish",
"postpub": "git push && git push --tags origin master",
"prepub:next": "npm run lint && npm run build",
"pub:next": "npm version prerelease --preid=next && npm publish --tag next",
"postpub:next": "git push",
"coverage": "nyc npm test",
"coveralls": "nyc report --reporter=text-lcov | coveralls"
},
"repository": {
"type": "git",
"url": "git+https://github.com/PeculiarVentures/json-schema.git"
},
"keywords": [
"json",
"stringify",
"serialize",
"parse",
"convert",
"decorator"
],
"author": "PeculiarVentures, Inc",
"contributors": [
{
"email": "rmh@unmitigatedrisk.com",
"name": "Ryan Hurst"
},
{
"email": "microshine@mail.ru",
"name": "Miroshin Stepan"
}
],
"license": "MIT",
"bugs": {
"url": "https://github.com/PeculiarVentures/json-schema/issues"
},
"homepage": "https://github.com/PeculiarVentures/json-schema#readme",
"engines": {
"node": ">=8.0.0"
},
"devDependencies": {
"@types/mocha": "^8.0.0",
"@types/node": "^12.12.51",
"mocha": "^8.0.1",
"rimraf": "^3.0.2",
"rollup": "^2.22.2",
"rollup-plugin-typescript2": "^0.27.1",
"ts-node": "^8.10.2",
"tslint": "^6.1.2",
"typescript": "^3.9.7"
},
"dependencies": {
"tslib": "^2.0.0"
},
"nyc": {
"extension": [
".ts",
".tsx"
],
"include": [
"src/**/*.ts"
],
"exclude": [
"**/*.d.ts"
],
"reporter": [
"text-summary",
"html"
]
},
"mocha": {
"require": "ts-node/register",
"extension": [
"ts"
],
"watch-files": "test/**/*.ts"
}
}