UNPKG

@liskhq/lisk-codec

Version:

Implementation of decoder and encoder using Lisk JSON schema according to the Lisk protocol

189 lines 8.43 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.codec = exports.Codec = exports.validateSchema = exports.emptySchema = void 0; const lisk_validator_1 = require("@liskhq/lisk-validator"); const lisk_utils_1 = require("@liskhq/lisk-utils"); const utils_1 = require("./utils"); const collection_1 = require("./collection"); const json_wrapper_1 = require("./json_wrapper"); exports.emptySchema = { $id: '/lisk/empty', type: 'object', properties: {}, }; const validateSchema = (schema) => { var _a; lisk_validator_1.validator.removeSchema(schema.$id); const schemaToValidate = { ...schema, $schema: (_a = schema.$schema) !== null && _a !== void 0 ? _a : lisk_validator_1.liskSchemaIdentifier, }; lisk_validator_1.validator.validateSchema(schemaToValidate); try { lisk_validator_1.validator.compile(schemaToValidate); } finally { lisk_validator_1.validator.removeSchema(schema.$id); } return true; }; exports.validateSchema = validateSchema; class Codec { constructor() { this._compileSchemas = {}; } addSchema(schema) { (0, exports.validateSchema)(schema); const schemaName = schema.$id; this._compileSchemas[schemaName] = this._compileSchema(schema, [], []); return true; } encode(schema, message) { if (this._compileSchemas[schema.$id] === undefined) { this.addSchema(schema); } const compiledSchema = this._compileSchemas[schema.$id]; const res = (0, collection_1.writeObject)(compiledSchema, message, []); return Buffer.concat(res[0]); } decode(schema, message) { if (this._compileSchemas[schema.$id] === undefined) { this.addSchema(schema); } const compiledSchema = this._compileSchemas[schema.$id]; const [res] = (0, collection_1.readObject)(message, 0, compiledSchema, message.length); return res; } decodeJSON(schema, message) { const decodedMessage = this.decode(schema, message); const jsonMessageAsObject = this.toJSON(schema, decodedMessage); return jsonMessageAsObject; } encodeJSON(schema, message) { const objectFromJson = this.fromJSON(schema, message); return this.encode(schema, objectFromJson); } toJSON(schema, message) { const messageCopy = lisk_utils_1.objects.cloneDeep(message); messageCopy[Symbol.iterator] = json_wrapper_1.iterator; (0, json_wrapper_1.recursiveTypeCast)('toJSON', messageCopy, schema, []); return messageCopy; } fromJSON(schema, message) { const messageCopy = lisk_utils_1.objects.cloneDeep(message); messageCopy[Symbol.iterator] = json_wrapper_1.iterator; (0, json_wrapper_1.recursiveTypeCast)('fromJSON', messageCopy, schema, []); return messageCopy; } clearCache() { this._compileSchemas = {}; } _compileSchema(schema, compiledSchema, dataPath) { if (schema.type === 'object') { const { properties } = schema; if (properties === undefined) { throw new Error('Invalid schema. Missing "properties" property'); } for (const property of Object.values(properties)) { if (!('fieldNumber' in property)) { throw new Error('Invalid schema. Missing "fieldNumber" in properties'); } } const currentDepthSchema = Object.entries(properties).sort((a, b) => a[1].fieldNumber - b[1].fieldNumber); for (let i = 0; i < currentDepthSchema.length; i += 1) { const [schemaPropertyName, schemaPropertyValue] = currentDepthSchema[i]; if (schemaPropertyValue.type === 'object') { if (!('fieldNumber' in schemaPropertyValue)) { throw new Error('Invalid schema. Missing "fieldNumber" in properties'); } dataPath.push(schemaPropertyName); const nestedSchema = [ { propertyName: schemaPropertyName, schemaProp: { type: schemaPropertyValue.type, fieldNumber: schemaPropertyValue.fieldNumber, }, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }, ]; const res = this._compileSchema(schemaPropertyValue, nestedSchema, dataPath); compiledSchema.push(res); dataPath.pop(); } else if (schemaPropertyValue.type === 'array') { if (schemaPropertyValue.items === undefined) { throw new Error('Invalid schema. Missing "items" property for Array schema'); } if (!('fieldNumber' in schemaPropertyValue)) { throw new Error('Invalid schema. Missing "fieldNumber" in properties'); } dataPath.push(schemaPropertyName); if (schemaPropertyValue.items.type === 'object') { const nestedSchema = [ { propertyName: schemaPropertyName, schemaProp: { type: 'object', fieldNumber: schemaPropertyValue.fieldNumber, }, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }, ]; const res = this._compileSchema(schemaPropertyValue.items, nestedSchema, dataPath); compiledSchema.push([ { propertyName: schemaPropertyName, schemaProp: { type: schemaPropertyValue.type, fieldNumber: schemaPropertyValue.fieldNumber, }, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }, res, ]); dataPath.pop(); } else { compiledSchema.push([ { propertyName: schemaPropertyName, schemaProp: { type: schemaPropertyValue.type, fieldNumber: schemaPropertyValue.fieldNumber, }, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }, { propertyName: schemaPropertyName, schemaProp: { dataType: schemaPropertyValue.items.dataType, fieldNumber: schemaPropertyValue.fieldNumber, }, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }, ]); dataPath.pop(); } } else { compiledSchema.push({ propertyName: schemaPropertyName, schemaProp: schemaPropertyValue, dataPath: [...dataPath], binaryKey: (0, utils_1.generateKey)(schemaPropertyValue), }); } } } return compiledSchema; } } exports.Codec = Codec; exports.codec = new Codec(); //# sourceMappingURL=codec.js.map