Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions borsh-ts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,10 +310,12 @@ function serializeStruct(schema: Schema, obj: any, writer: BinaryWriter) {
obj.borshSerialize(writer);
return;
}

const structSchema = schema.get(obj.constructor);
if (!structSchema) {
throw new BorshError(`Class ${obj.constructor.name} is missing in schema`);
}

if (structSchema.kind === "struct") {
structSchema.fields.map(([fieldName, fieldType]: [any, any]) => {
serializeField(schema, fieldName, obj[fieldName], fieldType, writer);
Expand Down
2 changes: 1 addition & 1 deletion lib/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/// <reference types="node" />
import BN from 'bn.js';
import BN from "bn.js";
export declare function baseEncode(value: Uint8Array | string): string;
export declare function baseDecode(value: string): Buffer;
export declare type Schema = Map<Function, any>;
Expand Down
77 changes: 43 additions & 34 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ const bn_js_1 = __importDefault(require("bn.js"));
const bs58_1 = __importDefault(require("bs58"));
// TODO: Make sure this polyfill not included when not required
const encoding = __importStar(require("text-encoding-utf-8"));
const TextDecoder = (typeof global.TextDecoder !== 'function') ? encoding.TextDecoder : global.TextDecoder;
const textDecoder = new TextDecoder('utf-8', { fatal: true });
const TextDecoder = typeof global.TextDecoder !== "function"
? encoding.TextDecoder
: global.TextDecoder;
const textDecoder = new TextDecoder("utf-8", { fatal: true });
function baseEncode(value) {
if (typeof (value) === 'string') {
value = Buffer.from(value, 'utf8');
if (typeof value === "string") {
value = Buffer.from(value, "utf8");
}
return bs58_1.default.encode(Buffer.from(value));
}
Expand All @@ -56,7 +58,7 @@ class BorshError extends Error {
addToFieldPath(fieldName) {
this.fieldPath.splice(0, 0, fieldName);
// NOTE: Modifying message directly as jest doesn't use .toString()
this.message = this.originalMessage + ': ' + this.fieldPath.join('.');
this.message = this.originalMessage + ": " + this.fieldPath.join(".");
}
}
exports.BorshError = BorshError;
Expand Down Expand Up @@ -88,28 +90,32 @@ class BinaryWriter {
}
writeU64(value) {
this.maybeResize();
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 8)));
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 8)));
}
writeU128(value) {
this.maybeResize();
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 16)));
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 16)));
}
writeU256(value) {
this.maybeResize();
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 32)));
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 32)));
}
writeU512(value) {
this.maybeResize();
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray('le', 64)));
this.writeBuffer(Buffer.from(new bn_js_1.default(value).toArray("le", 64)));
}
writeBuffer(buffer) {
// Buffer.from is needed as this.buf.subarray can return plain Uint8Array in browser
this.buf = Buffer.concat([Buffer.from(this.buf.subarray(0, this.length)), buffer, Buffer.alloc(INITIAL_LENGTH)]);
this.buf = Buffer.concat([
Buffer.from(this.buf.subarray(0, this.length)),
buffer,
Buffer.alloc(INITIAL_LENGTH),
]);
this.length += buffer.length;
}
writeString(str) {
this.maybeResize();
const b = Buffer.from(str, 'utf8');
const b = Buffer.from(str, "utf8");
this.writeU32(b.length);
this.writeBuffer(b);
}
Expand Down Expand Up @@ -138,8 +144,8 @@ function handlingRangeError(target, propertyKey, propertyDescriptor) {
catch (e) {
if (e instanceof RangeError) {
const code = e.code;
if (['ERR_BUFFER_OUT_OF_BOUNDS', 'ERR_OUT_OF_RANGE'].indexOf(code) >= 0) {
throw new BorshError('Reached the end of buffer when deserializing');
if (["ERR_BUFFER_OUT_OF_BOUNDS", "ERR_OUT_OF_RANGE"].indexOf(code) >= 0) {
throw new BorshError("Reached the end of buffer when deserializing");
}
}
throw e;
Expand Down Expand Up @@ -168,22 +174,22 @@ class BinaryReader {
}
readU64() {
const buf = this.readBuffer(8);
return new bn_js_1.default(buf, 'le');
return new bn_js_1.default(buf, "le");
}
readU128() {
const buf = this.readBuffer(16);
return new bn_js_1.default(buf, 'le');
return new bn_js_1.default(buf, "le");
}
readU256() {
const buf = this.readBuffer(32);
return new bn_js_1.default(buf, 'le');
return new bn_js_1.default(buf, "le");
}
readU512() {
const buf = this.readBuffer(64);
return new bn_js_1.default(buf, 'le');
return new bn_js_1.default(buf, "le");
}
readBuffer(len) {
if ((this.offset + len) > this.buf.length) {
if (this.offset + len > this.buf.length) {
throw new BorshError(`Expected buffer length ${len} isn't within bounds`);
}
const result = this.buf.slice(this.offset, this.offset + len);
Expand Down Expand Up @@ -250,17 +256,17 @@ function capitalizeFirstLetter(string) {
function serializeField(schema, fieldName, value, fieldType, writer) {
try {
// TODO: Handle missing values properly (make sure they never result in just skipped write)
if (typeof fieldType === 'string') {
if (typeof fieldType === "string") {
writer[`write${capitalizeFirstLetter(fieldType)}`](value);
}
else if (fieldType instanceof Array) {
if (typeof fieldType[0] === 'number') {
if (typeof fieldType[0] === "number") {
if (value.length !== fieldType[0]) {
throw new BorshError(`Expecting byte array of length ${fieldType[0]}, but got ${value.length} bytes`);
}
writer.writeFixedArray(value);
}
else if (fieldType.length === 2 && typeof fieldType[1] === 'number') {
else if (fieldType.length === 2 && typeof fieldType[1] === "number") {
if (value.length !== fieldType[1]) {
throw new BorshError(`Expecting byte array of length ${fieldType[1]}, but got ${value.length} bytes`);
}
Expand All @@ -269,12 +275,14 @@ function serializeField(schema, fieldName, value, fieldType, writer) {
}
}
else {
writer.writeArray(value, (item) => { serializeField(schema, fieldName, item, fieldType[0], writer); });
writer.writeArray(value, (item) => {
serializeField(schema, fieldName, item, fieldType[0], writer);
});
}
}
else if (fieldType.kind !== undefined) {
switch (fieldType.kind) {
case 'option': {
case "option": {
if (value === null || value === undefined) {
writer.writeU8(0);
}
Expand All @@ -284,7 +292,8 @@ function serializeField(schema, fieldName, value, fieldType, writer) {
}
break;
}
default: throw new BorshError(`FieldType ${fieldType} unrecognized`);
default:
throw new BorshError(`FieldType ${fieldType} unrecognized`);
}
}
else {
Expand All @@ -299,20 +308,20 @@ function serializeField(schema, fieldName, value, fieldType, writer) {
}
}
function serializeStruct(schema, obj, writer) {
if (typeof obj.borshSerialize === 'function') {
if (typeof obj.borshSerialize === "function") {
obj.borshSerialize(writer);
return;
}
const structSchema = schema.get(obj.constructor);
if (!structSchema) {
throw new BorshError(`Class ${obj.constructor.name} is missing in schema`);
}
if (structSchema.kind === 'struct') {
if (structSchema.kind === "struct") {
structSchema.fields.map(([fieldName, fieldType]) => {
serializeField(schema, fieldName, obj[fieldName], fieldType, writer);
});
}
else if (structSchema.kind === 'enum') {
else if (structSchema.kind === "enum") {
const name = obj[structSchema.field];
for (let idx = 0; idx < structSchema.values.length; ++idx) {
const [fieldName, fieldType] = structSchema.values[idx];
Expand All @@ -337,14 +346,14 @@ function serialize(schema, obj, Writer = BinaryWriter) {
exports.serialize = serialize;
function deserializeField(schema, fieldName, fieldType, reader) {
try {
if (typeof fieldType === 'string') {
if (typeof fieldType === "string") {
return reader[`read${capitalizeFirstLetter(fieldType)}`]();
}
if (fieldType instanceof Array) {
if (typeof fieldType[0] === 'number') {
if (typeof fieldType[0] === "number") {
return reader.readFixedArray(fieldType[0]);
}
else if (typeof fieldType[1] === 'number') {
else if (typeof fieldType[1] === "number") {
const arr = [];
for (let i = 0; i < fieldType[1]; i++) {
arr.push(deserializeField(schema, null, fieldType[0], reader));
Expand All @@ -355,7 +364,7 @@ function deserializeField(schema, fieldName, fieldType, reader) {
return reader.readArray(() => deserializeField(schema, fieldName, fieldType[0], reader));
}
}
if (fieldType.kind === 'option') {
if (fieldType.kind === "option") {
const option = reader.readU8();
if (option) {
return deserializeField(schema, fieldName, fieldType.type, reader);
Expand All @@ -372,21 +381,21 @@ function deserializeField(schema, fieldName, fieldType, reader) {
}
}
function deserializeStruct(schema, classType, reader) {
if (typeof classType.borshDeserialize === 'function') {
if (typeof classType.borshDeserialize === "function") {
return classType.borshDeserialize(reader);
}
const structSchema = schema.get(classType);
if (!structSchema) {
throw new BorshError(`Class ${classType.name} is missing in schema`);
}
if (structSchema.kind === 'struct') {
if (structSchema.kind === "struct") {
const result = {};
for (const [fieldName, fieldType] of schema.get(classType).fields) {
result[fieldName] = deserializeField(schema, fieldName, fieldType, reader);
}
return new classType(result);
}
if (structSchema.kind === 'enum') {
if (structSchema.kind === "enum") {
const idx = reader.readU8();
if (idx >= structSchema.values.length) {
throw new BorshError(`Enum index: ${idx} is out of range`);
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"pretest": "yarn build",
"lint": "eslint borsh-ts/**/*.ts",
"pretty": "prettier --write borsh-ts/**/*.ts package.json",
"pretty:check": "yarn pretty --check",
"pretty:check": "yarn prettier --loglevel error --check borsh-ts/**/*.ts package.json",
"fix": "eslint borsh-ts/**/*.ts --fix"
},
"repository": {
Expand Down