174 lines
6.6 KiB
Plaintext
174 lines
6.6 KiB
Plaintext
import { MESSAGE_TYPE } from "./message-type-contract";
|
|
import { normalizeFieldInfo } from "./reflection-info";
|
|
import { ReflectionTypeCheck } from "./reflection-type-check";
|
|
import { ReflectionJsonReader } from "./reflection-json-reader";
|
|
import { ReflectionJsonWriter } from "./reflection-json-writer";
|
|
import { ReflectionBinaryReader } from "./reflection-binary-reader";
|
|
import { ReflectionBinaryWriter } from "./reflection-binary-writer";
|
|
import { reflectionCreate } from "./reflection-create";
|
|
import { reflectionMergePartial } from "./reflection-merge-partial";
|
|
import { typeofJsonValue } from "./json-typings";
|
|
import { jsonReadOptions, jsonWriteOptions, } from "./json-format-contract";
|
|
import { reflectionEquals } from "./reflection-equals";
|
|
import { binaryWriteOptions } from "./binary-writer";
|
|
import { binaryReadOptions } from "./binary-reader";
|
|
const baseDescriptors = Object.getOwnPropertyDescriptors(Object.getPrototypeOf({}));
|
|
const messageTypeDescriptor = baseDescriptors[MESSAGE_TYPE] = {};
|
|
/**
|
|
* This standard message type provides reflection-based
|
|
* operations to work with a message.
|
|
*/
|
|
export class MessageType {
|
|
constructor(name, fields, options) {
|
|
this.defaultCheckDepth = 16;
|
|
this.typeName = name;
|
|
this.fields = fields.map(normalizeFieldInfo);
|
|
this.options = options !== null && options !== void 0 ? options : {};
|
|
messageTypeDescriptor.value = this;
|
|
this.messagePrototype = Object.create(null, baseDescriptors);
|
|
this.refTypeCheck = new ReflectionTypeCheck(this);
|
|
this.refJsonReader = new ReflectionJsonReader(this);
|
|
this.refJsonWriter = new ReflectionJsonWriter(this);
|
|
this.refBinReader = new ReflectionBinaryReader(this);
|
|
this.refBinWriter = new ReflectionBinaryWriter(this);
|
|
}
|
|
create(value) {
|
|
let message = reflectionCreate(this);
|
|
if (value !== undefined) {
|
|
reflectionMergePartial(this, message, value);
|
|
}
|
|
return message;
|
|
}
|
|
/**
|
|
* Clone the message.
|
|
*
|
|
* Unknown fields are discarded.
|
|
*/
|
|
clone(message) {
|
|
let copy = this.create();
|
|
reflectionMergePartial(this, copy, message);
|
|
return copy;
|
|
}
|
|
/**
|
|
* Determines whether two message of the same type have the same field values.
|
|
* Checks for deep equality, traversing repeated fields, oneof groups, maps
|
|
* and messages recursively.
|
|
* Will also return true if both messages are `undefined`.
|
|
*/
|
|
equals(a, b) {
|
|
return reflectionEquals(this, a, b);
|
|
}
|
|
/**
|
|
* Is the given value assignable to our message type
|
|
* and contains no [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
|
|
*/
|
|
is(arg, depth = this.defaultCheckDepth) {
|
|
return this.refTypeCheck.is(arg, depth, false);
|
|
}
|
|
/**
|
|
* Is the given value assignable to our message type,
|
|
* regardless of [excess properties](https://www.typescriptlang.org/docs/handbook/interfaces.html#excess-property-checks)?
|
|
*/
|
|
isAssignable(arg, depth = this.defaultCheckDepth) {
|
|
return this.refTypeCheck.is(arg, depth, true);
|
|
}
|
|
/**
|
|
* Copy partial data into the target message.
|
|
*/
|
|
mergePartial(target, source) {
|
|
reflectionMergePartial(this, target, source);
|
|
}
|
|
/**
|
|
* Create a new message from binary format.
|
|
*/
|
|
fromBinary(data, options) {
|
|
let opt = binaryReadOptions(options);
|
|
return this.internalBinaryRead(opt.readerFactory(data), data.byteLength, opt);
|
|
}
|
|
/**
|
|
* Read a new message from a JSON value.
|
|
*/
|
|
fromJson(json, options) {
|
|
return this.internalJsonRead(json, jsonReadOptions(options));
|
|
}
|
|
/**
|
|
* Read a new message from a JSON string.
|
|
* This is equivalent to `T.fromJson(JSON.parse(json))`.
|
|
*/
|
|
fromJsonString(json, options) {
|
|
let value = JSON.parse(json);
|
|
return this.fromJson(value, options);
|
|
}
|
|
/**
|
|
* Write the message to canonical JSON value.
|
|
*/
|
|
toJson(message, options) {
|
|
return this.internalJsonWrite(message, jsonWriteOptions(options));
|
|
}
|
|
/**
|
|
* Convert the message to canonical JSON string.
|
|
* This is equivalent to `JSON.stringify(T.toJson(t))`
|
|
*/
|
|
toJsonString(message, options) {
|
|
var _a;
|
|
let value = this.toJson(message, options);
|
|
return JSON.stringify(value, null, (_a = options === null || options === void 0 ? void 0 : options.prettySpaces) !== null && _a !== void 0 ? _a : 0);
|
|
}
|
|
/**
|
|
* Write the message to binary format.
|
|
*/
|
|
toBinary(message, options) {
|
|
let opt = binaryWriteOptions(options);
|
|
return this.internalBinaryWrite(message, opt.writerFactory(), opt).finish();
|
|
}
|
|
/**
|
|
* This is an internal method. If you just want to read a message from
|
|
* JSON, use `fromJson()` or `fromJsonString()`.
|
|
*
|
|
* Reads JSON value and merges the fields into the target
|
|
* according to protobuf rules. If the target is omitted,
|
|
* a new instance is created first.
|
|
*/
|
|
internalJsonRead(json, options, target) {
|
|
if (json !== null && typeof json == "object" && !Array.isArray(json)) {
|
|
let message = target !== null && target !== void 0 ? target : this.create();
|
|
this.refJsonReader.read(json, message, options);
|
|
return message;
|
|
}
|
|
throw new Error(`Unable to parse message ${this.typeName} from JSON ${typeofJsonValue(json)}.`);
|
|
}
|
|
/**
|
|
* This is an internal method. If you just want to write a message
|
|
* to JSON, use `toJson()` or `toJsonString().
|
|
*
|
|
* Writes JSON value and returns it.
|
|
*/
|
|
internalJsonWrite(message, options) {
|
|
return this.refJsonWriter.write(message, options);
|
|
}
|
|
/**
|
|
* This is an internal method. If you just want to write a message
|
|
* in binary format, use `toBinary()`.
|
|
*
|
|
* Serializes the message in binary format and appends it to the given
|
|
* writer. Returns passed writer.
|
|
*/
|
|
internalBinaryWrite(message, writer, options) {
|
|
this.refBinWriter.write(message, writer, options);
|
|
return writer;
|
|
}
|
|
/**
|
|
* This is an internal method. If you just want to read a message from
|
|
* binary data, use `fromBinary()`.
|
|
*
|
|
* Reads data from binary format and merges the fields into
|
|
* the target according to protobuf rules. If the target is
|
|
* omitted, a new instance is created first.
|
|
*/
|
|
internalBinaryRead(reader, length, options, target) {
|
|
let message = target !== null && target !== void 0 ? target : this.create();
|
|
this.refBinReader.read(reader, message, options, length);
|
|
return message;
|
|
}
|
|
}
|