clean up interfaces; merge nextSeed/next methods in accessors
This commit is contained in:
parent
f886c5c003
commit
bbaea7cc9e
26 changed files with 650 additions and 293 deletions
45
dist/de/forward.d.ts
vendored
45
dist/de/forward.d.ts
vendored
|
@ -1,34 +1,17 @@
|
|||
import { Deserialize, IDeserializer, IterableAccess, IVisitor, MapAccess } from './interface';
|
||||
export declare class ForwardMapAccess extends MapAccess {
|
||||
private readonly _keys;
|
||||
private readonly _values;
|
||||
private kindex;
|
||||
private vindex;
|
||||
constructor(keys: string[], values: any[]);
|
||||
static fromObject(obj: object): ForwardMapAccess;
|
||||
nextKeySeed<T, K extends Deserialize<T>>(_seed: K): IteratorResult<T>;
|
||||
nextValueSeed<T, V extends Deserialize<T>>(_seed: V): IteratorResult<T>;
|
||||
nextKey<T>(): IteratorResult<T>;
|
||||
nextValue<V>(): IteratorResult<V>;
|
||||
}
|
||||
export declare class ForwardIterableAccess extends IterableAccess {
|
||||
private readonly items;
|
||||
private index;
|
||||
constructor(items: any[]);
|
||||
nextElement<T>(): IteratorResult<T>;
|
||||
}
|
||||
export declare class Forward implements IDeserializer {
|
||||
import { IDeserializer, IVisitor } from './interface';
|
||||
import { Registry } from '../registry';
|
||||
export declare function forward(value: any, into: any, registry?: Registry): unknown;
|
||||
export declare class Forwarder implements IDeserializer {
|
||||
private readonly value;
|
||||
constructor(value: any);
|
||||
static with(value: any): Forward;
|
||||
deserializeAny<T, V extends IVisitor<T>>(_visitor: V): T;
|
||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeFunction<T, V extends IVisitor<T>>(_visitor: V): T;
|
||||
deserializeAny<T>(visitor: IVisitor<T>): T;
|
||||
deserializeBoolean<T>(visitor: IVisitor<T>): T;
|
||||
deserializeNumber<T>(visitor: IVisitor<T>): T;
|
||||
deserializeBigInt<T>(visitor: IVisitor<T>): T;
|
||||
deserializeString<T>(visitor: IVisitor<T>): T;
|
||||
deserializeSymbol<T>(visitor: IVisitor<T>): T;
|
||||
deserializeNull<T>(visitor: IVisitor<T>): T;
|
||||
deserializeObject<T>(visitor: IVisitor<T>): T;
|
||||
deserializeIterable<T>(visitor: IVisitor<T>): T;
|
||||
deserializeFunction<T>(_visitor: IVisitor<T>): T;
|
||||
}
|
||||
|
|
153
dist/de/forward.js
vendored
153
dist/de/forward.js
vendored
|
@ -1,69 +1,19 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Forward = exports.ForwardIterableAccess = exports.ForwardMapAccess = void 0;
|
||||
const utils_1 = require("../utils");
|
||||
exports.Forwarder = void 0;
|
||||
exports.forward = forward;
|
||||
const impl_1 = require("./impl");
|
||||
const interface_1 = require("./interface");
|
||||
class ForwardMapAccess extends interface_1.MapAccess {
|
||||
constructor(keys, values) {
|
||||
super();
|
||||
Object.defineProperty(this, "_keys", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "_values", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "kindex", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
Object.defineProperty(this, "vindex", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
this._keys = keys;
|
||||
this._values = values;
|
||||
}
|
||||
static fromObject(obj) {
|
||||
return new ForwardMapAccess(Object.keys(obj), Object.values(obj));
|
||||
}
|
||||
nextKeySeed(_seed) {
|
||||
return this.nextKey();
|
||||
}
|
||||
nextValueSeed(_seed) {
|
||||
return this.nextValue();
|
||||
}
|
||||
nextKey() {
|
||||
if (this.kindex < this.keys.length) {
|
||||
return utils_1.IterResult.Next(this._keys[this.kindex++]);
|
||||
}
|
||||
else {
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
}
|
||||
nextValue() {
|
||||
if (this.vindex < this.values.length) {
|
||||
return utils_1.IterResult.Next(this._values[this.vindex++]);
|
||||
}
|
||||
else {
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
}
|
||||
const registry_1 = require("../registry");
|
||||
const utils_1 = require("../utils");
|
||||
function forward(value, into, registry = registry_1.GlobalRegistry) {
|
||||
const forwarder = new Forwarder(value);
|
||||
return (0, impl_1.deserialize)(forwarder, into, registry);
|
||||
}
|
||||
exports.ForwardMapAccess = ForwardMapAccess;
|
||||
class ForwardIterableAccess extends interface_1.IterableAccess {
|
||||
constructor(items) {
|
||||
class ForwardMapAccess extends interface_1.MapAccess {
|
||||
constructor(entries) {
|
||||
super();
|
||||
Object.defineProperty(this, "items", {
|
||||
Object.defineProperty(this, "_entries", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
|
@ -73,21 +23,65 @@ class ForwardIterableAccess extends interface_1.IterableAccess {
|
|||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: 0
|
||||
value: -1
|
||||
});
|
||||
this.items = items;
|
||||
this._entries = entries;
|
||||
}
|
||||
nextElement() {
|
||||
if (this.index < this.items.length) {
|
||||
return utils_1.IterResult.Next(this.items[this.index++]);
|
||||
static fromObject(value) {
|
||||
return new this(Object.entries(value));
|
||||
}
|
||||
nextKey(seed) {
|
||||
this.index += 1;
|
||||
if (this.index >= this._entries.length) {
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
else {
|
||||
const key = this._entries[this.index][0];
|
||||
const value = seed != null ? seed(new Forwarder(key)) : key;
|
||||
return utils_1.IterResult.Next(value);
|
||||
}
|
||||
}
|
||||
nextValue(seed) {
|
||||
if (this.index >= this._entries.length) {
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
else {
|
||||
const value = this._entries[this.index][1];
|
||||
const deser = seed != null ? seed(value) : value;
|
||||
return utils_1.IterResult.Next(deser);
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.ForwardIterableAccess = ForwardIterableAccess;
|
||||
class Forward {
|
||||
class ForwardIterableAccess extends interface_1.IterableAccess {
|
||||
constructor(elements) {
|
||||
super();
|
||||
Object.defineProperty(this, "elements", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "index", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: -1
|
||||
});
|
||||
this.elements = elements;
|
||||
}
|
||||
nextElement(seed) {
|
||||
this.index += 1;
|
||||
if (this.index >= this.elements.length) {
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
else {
|
||||
const element = this.elements[this.index];
|
||||
const deser = seed != null ? seed(new Forwarder(element)) : element;
|
||||
return utils_1.IterResult.Next(deser);
|
||||
}
|
||||
}
|
||||
}
|
||||
class Forwarder {
|
||||
constructor(value) {
|
||||
Object.defineProperty(this, "value", {
|
||||
enumerable: true,
|
||||
|
@ -97,11 +91,22 @@ class Forward {
|
|||
});
|
||||
this.value = value;
|
||||
}
|
||||
static with(value) {
|
||||
return new this(value);
|
||||
}
|
||||
deserializeAny(_visitor) {
|
||||
throw new Error("Can't forward to deserializeAny");
|
||||
deserializeAny(visitor) {
|
||||
switch (typeof this.value) {
|
||||
case 'string': return this.deserializeString(visitor);
|
||||
case 'number': return this.deserializeNumber(visitor);
|
||||
case 'bigint': return this.deserializeBigInt(visitor);
|
||||
case 'boolean': return this.deserializeBoolean(visitor);
|
||||
case 'symbol': return this.deserializeSymbol(visitor);
|
||||
case 'undefined': return this.deserializeNull(visitor);
|
||||
case 'object': {
|
||||
switch (true) {
|
||||
case Array.isArray(this.value): return this.deserializeIterable(visitor);
|
||||
default: return this.deserializeObject(visitor);
|
||||
}
|
||||
}
|
||||
case 'function': return this.deserializeFunction(visitor);
|
||||
}
|
||||
}
|
||||
deserializeBoolean(visitor) {
|
||||
return visitor.visitBoolean(this.value);
|
||||
|
@ -131,4 +136,4 @@ class Forward {
|
|||
throw new Error('Method not implemented.');
|
||||
}
|
||||
}
|
||||
exports.Forward = Forward;
|
||||
exports.Forwarder = Forwarder;
|
||||
|
|
8
dist/de/generic.d.ts
vendored
8
dist/de/generic.d.ts
vendored
|
@ -1,10 +1,4 @@
|
|||
import { IDeserializer, IIterableAccess, IMapAccess, IVisitor } from './interface';
|
||||
export declare class GenericSeed<T> {
|
||||
readonly visitor: IVisitor<T>;
|
||||
constructor(visitor?: IVisitor<T>);
|
||||
static deserialize<T, D extends IDeserializer>(deserializer: D, visitor?: IVisitor<T>): T;
|
||||
deserialize<D extends IDeserializer>(deserializer: D): T;
|
||||
}
|
||||
import { IIterableAccess, IMapAccess, IVisitor } from './interface';
|
||||
export declare class Visitor<T> implements IVisitor<T> {
|
||||
private overrides?;
|
||||
constructor(overrides?: Partial<IVisitor<T>>);
|
||||
|
|
20
dist/de/generic.js
vendored
20
dist/de/generic.js
vendored
|
@ -1,26 +1,8 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Visitor = exports.GenericSeed = void 0;
|
||||
exports.Visitor = void 0;
|
||||
const utils_1 = require("../utils");
|
||||
const interface_1 = require("./interface");
|
||||
class GenericSeed {
|
||||
constructor(visitor = new Visitor()) {
|
||||
Object.defineProperty(this, "visitor", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
this.visitor = visitor;
|
||||
}
|
||||
static deserialize(deserializer, visitor = new Visitor()) {
|
||||
return deserializer.deserializeAny(visitor);
|
||||
}
|
||||
deserialize(deserializer) {
|
||||
return GenericSeed.deserialize(deserializer, this.visitor);
|
||||
}
|
||||
}
|
||||
exports.GenericSeed = GenericSeed;
|
||||
class Visitor {
|
||||
constructor(overrides) {
|
||||
Object.defineProperty(this, "overrides", {
|
||||
|
|
1
dist/de/index.d.ts
vendored
1
dist/de/index.d.ts
vendored
|
@ -1,3 +1,4 @@
|
|||
export * from './forward';
|
||||
export * from './generic';
|
||||
export * from './impl';
|
||||
export * from './interface';
|
||||
|
|
1
dist/de/index.js
vendored
1
dist/de/index.js
vendored
|
@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./forward"), exports);
|
||||
__exportStar(require("./generic"), exports);
|
||||
__exportStar(require("./impl"), exports);
|
||||
__exportStar(require("./interface"), exports);
|
||||
|
|
37
dist/de/interface.d.ts
vendored
37
dist/de/interface.d.ts
vendored
|
@ -1,40 +1,31 @@
|
|||
import { Nullable } from '../utils';
|
||||
export interface IMapAccess {
|
||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
nextKey<T>(): IteratorResult<T>;
|
||||
nextValue<V>(): IteratorResult<V>;
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>;
|
||||
nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||
nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>;
|
||||
sizeHint?(): Nullable<number>;
|
||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>;
|
||||
entries<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||
values<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||
entries<K, V>(kseed: Deserialize<K>, vseed: Deserialize<V>): Iterator<[K, V]>;
|
||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>;
|
||||
}
|
||||
export declare abstract class MapAccess {
|
||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
||||
private orDefaultSeed;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
nextKey<T>(): IteratorResult<T>;
|
||||
nextValue<V>(): IteratorResult<V>;
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>;
|
||||
abstract nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||
abstract nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>;
|
||||
private generate;
|
||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]>;
|
||||
keys<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||
values<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||
entries<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): Iterator<[K, V]>;
|
||||
[Symbol.iterator]<K, V>(): Iterator<K, V>;
|
||||
}
|
||||
export interface IIterableAccess {
|
||||
nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>;
|
||||
nextElement<T>(): IteratorResult<T>;
|
||||
nextElement<T>(seed: Deserialize<T>): IteratorResult<T>;
|
||||
sizeHint?(): Nullable<number>;
|
||||
[Symbol.iterator]<T>(): Iterator<T>;
|
||||
}
|
||||
export declare abstract class IterableAccess implements IIterableAccess {
|
||||
abstract nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>;
|
||||
nextElement<T>(): IteratorResult<T>;
|
||||
abstract nextElement<T>(seed: Deserialize<T>): IteratorResult<T>;
|
||||
[Symbol.iterator]<T>(): Iterator<T>;
|
||||
}
|
||||
export declare function isVisitor<T>(visitor: any): visitor is IVisitor<T>;
|
||||
|
|
41
dist/de/interface.js
vendored
41
dist/de/interface.js
vendored
|
@ -3,31 +3,11 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|||
exports.IterableAccess = exports.MapAccess = void 0;
|
||||
exports.isVisitor = isVisitor;
|
||||
const utils_1 = require("../utils");
|
||||
const generic_1 = require("./generic");
|
||||
class MapAccess {
|
||||
orDefaultSeed(seed) {
|
||||
return seed || generic_1.GenericSeed.deserialize;
|
||||
}
|
||||
nextEntrySeed(kseed, vseed) {
|
||||
const key = this.nextKeySeed(kseed);
|
||||
nextEntry(kseed, vseed) {
|
||||
const key = this.nextKey(kseed);
|
||||
if (!key.done) {
|
||||
const value = this.nextValueSeed(vseed);
|
||||
if (!value.done) {
|
||||
return utils_1.IterResult.Next([key.value, value.value]);
|
||||
}
|
||||
}
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
nextKey() {
|
||||
return this.nextKeySeed(generic_1.GenericSeed.deserialize);
|
||||
}
|
||||
nextValue() {
|
||||
return this.nextValueSeed(generic_1.GenericSeed.deserialize);
|
||||
}
|
||||
nextEntry() {
|
||||
const key = this.nextKey();
|
||||
if (!key.done) {
|
||||
const value = this.nextValue();
|
||||
const value = this.nextValue(vseed);
|
||||
if (!value.done) {
|
||||
return utils_1.IterResult.Next([key.value, value.value]);
|
||||
}
|
||||
|
@ -41,19 +21,13 @@ class MapAccess {
|
|||
}
|
||||
}
|
||||
keys(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed));
|
||||
return this.generate(this.nextKey.bind(this, seed));
|
||||
}
|
||||
values(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed));
|
||||
return this.generate(this.nextValue.bind(this, seed));
|
||||
}
|
||||
entries(kseed, vseed) {
|
||||
return this.generate(kseed == null && vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, this.orDefaultSeed(kseed), this.orDefaultSeed(vseed)));
|
||||
return this.generate(this.nextEntry.bind(this, kseed, vseed));
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
|
@ -61,9 +35,6 @@ class MapAccess {
|
|||
}
|
||||
exports.MapAccess = MapAccess;
|
||||
class IterableAccess {
|
||||
nextElement() {
|
||||
return this.nextElementSeed(generic_1.GenericSeed.deserialize);
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return {
|
||||
next: this.nextElement.bind(this)
|
||||
|
|
2
dist/registry.d.ts
vendored
2
dist/registry.d.ts
vendored
|
@ -9,3 +9,5 @@ export declare class Registry {
|
|||
export declare const GlobalRegistry: Registry;
|
||||
export declare const registerSerialize: <T, U>(ctor: Function, serialize: Serialize<T, U>) => void;
|
||||
export declare const registerDeserialize: <T>(ctor: Function, deserialize: Deserialize<T>) => void;
|
||||
export declare function getSerialize<T, U>(value: U, fallback: Serialize<T, U>, registry: Registry): Serialize<T, U>;
|
||||
export declare function getDeserialize<T, U>(value: U, fallback: Deserialize<T>, registry: Registry): Deserialize<T>;
|
||||
|
|
73
dist/registry.js
vendored
73
dist/registry.js
vendored
|
@ -1,6 +1,9 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.registerDeserialize = exports.registerSerialize = exports.GlobalRegistry = exports.Registry = void 0;
|
||||
exports.getSerialize = getSerialize;
|
||||
exports.getDeserialize = getDeserialize;
|
||||
const utils_1 = require("./utils");
|
||||
class Registry {
|
||||
constructor() {
|
||||
Object.defineProperty(this, "serializers", {
|
||||
|
@ -27,3 +30,73 @@ exports.Registry = Registry;
|
|||
exports.GlobalRegistry = new Registry();
|
||||
exports.registerSerialize = exports.GlobalRegistry.registerSerialize.bind(exports.GlobalRegistry);
|
||||
exports.registerDeserialize = exports.GlobalRegistry.registerDeserialize.bind(exports.GlobalRegistry);
|
||||
function getFrom(map, value) {
|
||||
return map.get((0, utils_1.type)(value));
|
||||
}
|
||||
function getSerialize(value, fallback, registry) {
|
||||
return getFrom(registry.serializers, value) || fallback;
|
||||
}
|
||||
function getDeserialize(value, fallback, registry) {
|
||||
return getFrom(registry.deserializers, value) || fallback;
|
||||
}
|
||||
(0, exports.registerSerialize)(Boolean, (ser, value) => ser.serializeBoolean(value));
|
||||
(0, exports.registerSerialize)(String, (ser, value) => ser.serializeString(value));
|
||||
(0, exports.registerSerialize)(Number, (ser, value) => ser.serializeNumber(value));
|
||||
(0, exports.registerSerialize)(BigInt, (ser, value) => ser.serializeBigInt(value));
|
||||
(0, exports.registerSerialize)(Symbol, (ser, value) => ser.serializeSymbol(value));
|
||||
(0, exports.registerSerialize)(utils_1.Null, (ser, _value) => ser.serializeNull());
|
||||
(0, exports.registerSerialize)(Object, (ser, value) => {
|
||||
const obj = Object.entries(value);
|
||||
const serObj = ser.serializeObject(obj.length);
|
||||
obj.forEach(([key, value]) => serObj.serializeEntry(key, value));
|
||||
return serObj.end();
|
||||
});
|
||||
(0, exports.registerSerialize)(Array, (ser, value) => {
|
||||
const arr = value;
|
||||
const iter = ser.serializeIterable(arr.length);
|
||||
arr.forEach((value) => iter.serializeElement(value));
|
||||
return iter.end();
|
||||
});
|
||||
(0, exports.registerDeserialize)(Boolean, (de) => de.deserializeBoolean({
|
||||
visitBoolean(value) {
|
||||
return value;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(String, (de) => de.deserializeString({
|
||||
visitString(value) {
|
||||
return value;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(Number, (de) => de.deserializeNumber({
|
||||
visitNumber(value) {
|
||||
return value;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(BigInt, (de) => de.deserializeBigInt({
|
||||
visitBigInt(value) {
|
||||
return value;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(Symbol, (de) => de.deserializeSymbol({
|
||||
visitSymbol(value) {
|
||||
return value;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(Object, (de) => de.deserializeObject({
|
||||
visitObject(access) {
|
||||
let result = {};
|
||||
for (const [key, value] of access) {
|
||||
result[key] = value;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}));
|
||||
(0, exports.registerDeserialize)(Array, (de) => de.deserializeIterable({
|
||||
visitIterable(access) {
|
||||
let result = [];
|
||||
for (const value of access) {
|
||||
result.push(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}));
|
||||
|
|
13
dist/ser/identity.d.ts
vendored
Normal file
13
dist/ser/identity.d.ts
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
import { ISerializeIterable, ISerializeObject, ISerializer } from './interface';
|
||||
export declare class IdentitySerializer<T> implements ISerializer<T> {
|
||||
serializeAny?(value: any): T;
|
||||
serializeBoolean(value: boolean): T;
|
||||
serializeNumber(value: number): T;
|
||||
serializeBigInt(value: bigint): T;
|
||||
serializeString(value: string): T;
|
||||
serializeSymbol(value: symbol): T;
|
||||
serializeNull(): T;
|
||||
serializeIterable(_len?: number): ISerializeIterable<T>;
|
||||
serializeObject(_len?: number): ISerializeObject<T>;
|
||||
serializeClass(_name: string, _len?: number): ISerializeObject<T>;
|
||||
}
|
80
dist/ser/identity.js
vendored
Normal file
80
dist/ser/identity.js
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.IdentitySerializer = void 0;
|
||||
const interface_1 = require("./interface");
|
||||
class IdentityMap extends interface_1.SerializeObject {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
Object.defineProperty(this, "value", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: {}
|
||||
});
|
||||
Object.defineProperty(this, "currentKey", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
}
|
||||
serializeKey(key) {
|
||||
this.currentKey = key;
|
||||
}
|
||||
serializeValue(value) {
|
||||
this.value[this.currentKey] = value;
|
||||
}
|
||||
end() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
class IdentityIterable extends interface_1.SerializeIterable {
|
||||
constructor() {
|
||||
super(...arguments);
|
||||
Object.defineProperty(this, "value", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: []
|
||||
});
|
||||
}
|
||||
serializeElement(value) {
|
||||
this.value.push(value);
|
||||
}
|
||||
end() {
|
||||
return this.value;
|
||||
}
|
||||
}
|
||||
class IdentitySerializer {
|
||||
serializeAny(value) {
|
||||
return value;
|
||||
}
|
||||
serializeBoolean(value) {
|
||||
return value;
|
||||
}
|
||||
serializeNumber(value) {
|
||||
return value;
|
||||
}
|
||||
serializeBigInt(value) {
|
||||
return value;
|
||||
}
|
||||
serializeString(value) {
|
||||
return value;
|
||||
}
|
||||
serializeSymbol(value) {
|
||||
return value;
|
||||
}
|
||||
serializeNull() {
|
||||
return null;
|
||||
}
|
||||
serializeIterable(_len) {
|
||||
return new IdentityIterable();
|
||||
}
|
||||
serializeObject(_len) {
|
||||
return new IdentityMap();
|
||||
}
|
||||
serializeClass(_name, _len) {
|
||||
return new IdentityMap();
|
||||
}
|
||||
}
|
||||
exports.IdentitySerializer = IdentitySerializer;
|
15
dist/ser/impl.js
vendored
15
dist/ser/impl.js
vendored
|
@ -15,17 +15,17 @@ function serializeObject(serializer, obj) {
|
|||
}
|
||||
return serializer.end();
|
||||
}
|
||||
function serializeIterable(serializer, iter) {
|
||||
for (const item of iter) {
|
||||
serializer.serializeElement(item);
|
||||
}
|
||||
return serializer.end();
|
||||
}
|
||||
function serializeClass(serializer, value) {
|
||||
const name = value.constructor.name;
|
||||
const ser = serializer.serializeClass(name);
|
||||
return serializeObject(ser, value);
|
||||
}
|
||||
function getSerialize(value, registry) {
|
||||
if ((0, utils_1.isObject)(value)) {
|
||||
return registry.serializers.get(value.constructor);
|
||||
}
|
||||
return registry.serializers.get(utils_1.PrimitivePrototype[typeof value]) || defaultSerialize;
|
||||
}
|
||||
function defaultSerialize(serializer, value) {
|
||||
switch (typeof value) {
|
||||
case 'string': return serializer.serializeString(value);
|
||||
|
@ -37,6 +37,7 @@ function defaultSerialize(serializer, value) {
|
|||
case 'object':
|
||||
switch (true) {
|
||||
case value == null: return serializer.serializeNull();
|
||||
case Array.isArray(value): return serializeIterable(serializer.serializeIterable(value.length), value);
|
||||
case !(0, utils_1.isPlainObject)(value): return serializeClass(serializer, value);
|
||||
default: return serializeObject(serializer.serializeObject(), value);
|
||||
}
|
||||
|
@ -44,6 +45,6 @@ function defaultSerialize(serializer, value) {
|
|||
}
|
||||
}
|
||||
function serialize(serializer, value, registry = registry_1.GlobalRegistry) {
|
||||
const ser = getSerialize(value, registry);
|
||||
const ser = (0, registry_1.getSerialize)(value, defaultSerialize, registry);
|
||||
return ser(serializer, value);
|
||||
}
|
||||
|
|
1
dist/ser/index.d.ts
vendored
1
dist/ser/index.d.ts
vendored
|
@ -1,2 +1,3 @@
|
|||
export * from './identity';
|
||||
export * from './impl';
|
||||
export * from './interface';
|
||||
|
|
1
dist/ser/index.js
vendored
1
dist/ser/index.js
vendored
|
@ -14,5 +14,6 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
__exportStar(require("./identity"), exports);
|
||||
__exportStar(require("./impl"), exports);
|
||||
__exportStar(require("./interface"), exports);
|
||||
|
|
1
dist/utils.d.ts
vendored
1
dist/utils.d.ts
vendored
|
@ -28,3 +28,4 @@ export declare const PrimitivePrototype: Readonly<{
|
|||
readonly object: ObjectConstructor;
|
||||
readonly function: FunctionConstructor;
|
||||
}>;
|
||||
export declare function type(value: any): Function | ObjectConstructor | SymbolConstructor | ArrayConstructor | BooleanConstructor | NumberConstructor | BigIntConstructor | StringConstructor | FunctionConstructor;
|
||||
|
|
11
dist/utils.js
vendored
11
dist/utils.js
vendored
|
@ -8,8 +8,9 @@ exports.isIterable = isIterable;
|
|||
exports.isString = isString;
|
||||
exports.isNumber = isNumber;
|
||||
exports.Null = Null;
|
||||
exports.type = type;
|
||||
function isObject(value) {
|
||||
return typeof value === 'object';
|
||||
return typeof value === 'object' && !Array.isArray(value);
|
||||
}
|
||||
function isPlainObject(value) {
|
||||
return Object.getPrototypeOf(value) === Object.prototype;
|
||||
|
@ -48,3 +49,11 @@ exports.PrimitivePrototype = Object.freeze({
|
|||
object: Object,
|
||||
function: Function
|
||||
});
|
||||
function type(value) {
|
||||
switch (true) {
|
||||
case Array.isArray(value): return Array;
|
||||
case isPlainObject(value): return Object;
|
||||
case isObject(value): return value.constructor;
|
||||
default: return exports.PrimitivePrototype[typeof value];
|
||||
}
|
||||
}
|
||||
|
|
132
src/de/forward.ts
Normal file
132
src/de/forward.ts
Normal file
|
@ -0,0 +1,132 @@
|
|||
import { deserialize } from './impl'
|
||||
import { Deserialize, IDeserializer, IMapAccess, IterableAccess, IVisitor, MapAccess } from './interface'
|
||||
import { GlobalRegistry, Registry } from '../registry'
|
||||
import { IterResult } from '../utils'
|
||||
|
||||
export function forward(value: any, into: any, registry: Registry = GlobalRegistry) {
|
||||
const forwarder = new Forwarder(value)
|
||||
return deserialize(forwarder, into, registry)
|
||||
}
|
||||
|
||||
type Entry = [PropertyKey, any]
|
||||
|
||||
class ForwardMapAccess extends MapAccess {
|
||||
private readonly _entries: Entry[]
|
||||
private index: number = -1
|
||||
|
||||
constructor(entries: Entry[]) {
|
||||
super()
|
||||
this._entries = entries
|
||||
}
|
||||
|
||||
static fromObject(value: Record<PropertyKey, any>) {
|
||||
return new this(Object.entries(value))
|
||||
}
|
||||
|
||||
nextKey<T, K extends Deserialize<T>>(seed?: K): IteratorResult<T> {
|
||||
this.index += 1
|
||||
|
||||
if (this.index >= this._entries.length) {
|
||||
return IterResult.Done()
|
||||
} else {
|
||||
const key = this._entries[this.index][0]
|
||||
const value = seed != null ? seed(new Forwarder(key)) : key as T
|
||||
return IterResult.Next(value)
|
||||
}
|
||||
}
|
||||
|
||||
nextValue<T, V extends Deserialize<T>>(seed?: V): IteratorResult<T> {
|
||||
if (this.index >= this._entries.length) {
|
||||
return IterResult.Done()
|
||||
} else {
|
||||
const value = this._entries[this.index][1]
|
||||
const deser = seed != null ? seed(value) : value
|
||||
return IterResult.Next(deser)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ForwardIterableAccess<T> extends IterableAccess {
|
||||
private readonly elements: T[]
|
||||
private index: number = -1
|
||||
|
||||
constructor(elements: T[]) {
|
||||
super()
|
||||
this.elements = elements
|
||||
}
|
||||
|
||||
nextElement<T, D extends Deserialize<T>>(seed?: D): IteratorResult<T> {
|
||||
this.index += 1
|
||||
|
||||
if (this.index >= this.elements.length) {
|
||||
return IterResult.Done()
|
||||
} else {
|
||||
const element = this.elements[this.index]
|
||||
const deser = seed != null ? seed(new Forwarder(element)) : element
|
||||
return IterResult.Next(deser as T)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class Forwarder implements IDeserializer {
|
||||
private readonly value: any
|
||||
|
||||
constructor(value: any) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
deserializeAny<T>(visitor: IVisitor<T>): T {
|
||||
switch (typeof this.value) {
|
||||
case 'string': return this.deserializeString(visitor)
|
||||
case 'number': return this.deserializeNumber(visitor)
|
||||
case 'bigint': return this.deserializeBigInt(visitor)
|
||||
case 'boolean': return this.deserializeBoolean(visitor)
|
||||
case 'symbol': return this.deserializeSymbol(visitor)
|
||||
case 'undefined': return this.deserializeNull(visitor)
|
||||
case 'object': {
|
||||
switch (true) {
|
||||
case Array.isArray(this.value): return this.deserializeIterable(visitor)
|
||||
default: return this.deserializeObject(visitor)
|
||||
}
|
||||
}
|
||||
case 'function': return this.deserializeFunction(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
deserializeBoolean<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitBoolean(this.value)
|
||||
}
|
||||
|
||||
deserializeNumber<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitNumber(this.value)
|
||||
}
|
||||
|
||||
deserializeBigInt<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitBigInt(this.value)
|
||||
}
|
||||
|
||||
deserializeString<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitString(this.value)
|
||||
}
|
||||
|
||||
deserializeSymbol<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitSymbol(this.value)
|
||||
}
|
||||
|
||||
deserializeNull<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitNull()
|
||||
}
|
||||
|
||||
deserializeObject<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitObject(ForwardMapAccess.fromObject(this.value) as IMapAccess)
|
||||
}
|
||||
|
||||
deserializeIterable<T>(visitor: IVisitor<T>): T {
|
||||
return visitor.visitIterable(new ForwardIterableAccess(this.value))
|
||||
}
|
||||
|
||||
deserializeFunction<T>(_visitor: IVisitor<T>): T {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
}
|
||||
|
|
@ -1,21 +1,5 @@
|
|||
import { isFunction } from '../utils'
|
||||
import { IDeserializer, IIterableAccess, IMapAccess, isVisitor, IVisitor } from './interface'
|
||||
|
||||
export class GenericSeed<T> {
|
||||
readonly visitor: IVisitor<T>
|
||||
|
||||
constructor(visitor: IVisitor<T> = new Visitor()) {
|
||||
this.visitor = visitor
|
||||
}
|
||||
|
||||
static deserialize<T, D extends IDeserializer>(deserializer: D, visitor: IVisitor<T> = new Visitor()): T {
|
||||
return deserializer.deserializeAny(visitor)
|
||||
}
|
||||
|
||||
deserialize<D extends IDeserializer>(deserializer: D): T {
|
||||
return GenericSeed.deserialize(deserializer, this.visitor)
|
||||
}
|
||||
}
|
||||
import { IIterableAccess, IMapAccess, isVisitor, IVisitor } from './interface'
|
||||
|
||||
export class Visitor<T> implements IVisitor<T> {
|
||||
private overrides?: Partial<IVisitor<T>>
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export * from './forward'
|
||||
export * from './generic'
|
||||
export * from './impl'
|
||||
export * from './interface'
|
||||
|
|
|
@ -1,55 +1,25 @@
|
|||
import { IterResult, Nullable } from '../utils'
|
||||
import { GenericSeed } from './generic'
|
||||
|
||||
export interface IMapAccess {
|
||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>
|
||||
nextKey<T>(): IteratorResult<T>
|
||||
nextValue<V>(): IteratorResult<V>
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>
|
||||
nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||
nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>
|
||||
sizeHint?(): Nullable<number>
|
||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>
|
||||
entries<T>(seed?: Deserialize<T>): Iterator<T>
|
||||
values<T>(seed?: Deserialize<T>): Iterator<T>
|
||||
entries<K, V>(kseed: Deserialize<K>, vseed: Deserialize<V>): Iterator<[K, V]>
|
||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>
|
||||
}
|
||||
|
||||
export abstract class MapAccess {
|
||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
||||
abstract nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||
abstract nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||
|
||||
private orDefaultSeed<T>(seed?: Deserialize<T>): Deserialize<T> {
|
||||
return seed || GenericSeed.deserialize
|
||||
}
|
||||
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]> {
|
||||
const key = this.nextKeySeed(kseed) as IteratorResult<TK>
|
||||
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]> {
|
||||
const key = this.nextKey(kseed) as IteratorResult<K>
|
||||
|
||||
if (!key.done) {
|
||||
const value = this.nextValueSeed(vseed) as IteratorResult<TV>
|
||||
|
||||
if (!value.done) {
|
||||
return IterResult.Next([key.value, value.value])
|
||||
}
|
||||
}
|
||||
|
||||
return IterResult.Done()
|
||||
}
|
||||
|
||||
nextKey<T>(): IteratorResult<T> {
|
||||
return this.nextKeySeed(GenericSeed.deserialize)
|
||||
}
|
||||
|
||||
nextValue<V>(): IteratorResult<V> {
|
||||
return this.nextValueSeed(GenericSeed.deserialize)
|
||||
}
|
||||
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]> {
|
||||
const key = this.nextKey() as IteratorResult<K>
|
||||
|
||||
if (!key.done) {
|
||||
const value = this.nextValue() as IteratorResult<V>
|
||||
const value = this.nextValue(vseed) as IteratorResult<V>
|
||||
|
||||
if (!value.done) {
|
||||
return IterResult.Next([key.value, value.value])
|
||||
|
@ -67,28 +37,16 @@ export abstract class MapAccess {
|
|||
}
|
||||
}
|
||||
|
||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed) as any
|
||||
)
|
||||
keys<T>(seed?: Deserialize<T>): Iterator<T> {
|
||||
return this.generate<T>(this.nextKey.bind(this, seed) as any)
|
||||
}
|
||||
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed) as any
|
||||
)
|
||||
values<T>(seed?: Deserialize<T>): Iterator<T> {
|
||||
return this.generate(this.nextValue.bind(this, seed) as any)
|
||||
}
|
||||
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]> {
|
||||
return this.generate(
|
||||
kseed == null && vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, this.orDefaultSeed(kseed), this.orDefaultSeed(vseed)) as any
|
||||
)
|
||||
entries<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): Iterator<[K, V]> {
|
||||
return this.generate(this.nextEntry.bind(this, kseed, vseed) as any)
|
||||
}
|
||||
|
||||
[Symbol.iterator]<K, V>(): Iterator<K, V> {
|
||||
|
@ -97,18 +55,13 @@ export abstract class MapAccess {
|
|||
}
|
||||
|
||||
export interface IIterableAccess {
|
||||
nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>
|
||||
nextElement<T>(): IteratorResult<T>
|
||||
nextElement<T>(seed: Deserialize<T>): IteratorResult<T>
|
||||
sizeHint?(): Nullable<number>
|
||||
[Symbol.iterator]<T>(): Iterator<T>
|
||||
}
|
||||
|
||||
export abstract class IterableAccess implements IIterableAccess {
|
||||
abstract nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>
|
||||
|
||||
nextElement<T>(): IteratorResult<T> {
|
||||
return this.nextElementSeed(GenericSeed.deserialize)
|
||||
}
|
||||
abstract nextElement<T>(seed: Deserialize<T>): IteratorResult<T>
|
||||
|
||||
[Symbol.iterator]<T>(): Iterator<T> {
|
||||
return {
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { Deserialize } from './de'
|
||||
import { Serialize } from './ser'
|
||||
import { Deserialize, IDeserializer, IIterableAccess, IMapAccess } from './de'
|
||||
import { ISerializer, Serialize } from './ser'
|
||||
import { isObject, Null, PrimitivePrototype, type } from './utils'
|
||||
|
||||
export class Registry {
|
||||
serializers: Map<Function, Serialize<any, any>> = new Map()
|
||||
|
@ -18,3 +19,95 @@ export const GlobalRegistry = new Registry()
|
|||
export const registerSerialize = GlobalRegistry.registerSerialize.bind(GlobalRegistry)
|
||||
export const registerDeserialize = GlobalRegistry.registerDeserialize.bind(GlobalRegistry)
|
||||
|
||||
function getFrom<T, V>(map: Map<Function, T>, value: V): T {
|
||||
return map.get(type(value)) as T
|
||||
}
|
||||
|
||||
export function getSerialize<T, U>(value: U, fallback: Serialize<T, U>, registry: Registry): Serialize<T, U> {
|
||||
return getFrom(registry.serializers, value) || fallback
|
||||
}
|
||||
|
||||
export function getDeserialize<T, U>(value: U, fallback: Deserialize<T>, registry: Registry): Deserialize<T> {
|
||||
return getFrom(registry.deserializers, value) || fallback
|
||||
}
|
||||
|
||||
registerSerialize(Boolean, <T, U>(ser: ISerializer<T>, value: U) => ser.serializeBoolean(value as boolean))
|
||||
|
||||
registerSerialize(String, <T, U>(ser: ISerializer<T>, value: U) => ser.serializeString(value as string))
|
||||
|
||||
registerSerialize(Number, <T, U>(ser: ISerializer<T>, value: U) => ser.serializeNumber(value as number))
|
||||
|
||||
registerSerialize(BigInt, <T, U>(ser: ISerializer<T>, value: U) => ser.serializeBigInt(value as bigint))
|
||||
|
||||
registerSerialize(Symbol, <T, U>(ser: ISerializer<T>, value: U) => ser.serializeSymbol(value as symbol))
|
||||
|
||||
registerSerialize(Null, <T, U>(ser: ISerializer<T>, _value: U) => ser.serializeNull())
|
||||
|
||||
registerSerialize(Object, <T, U>(ser: ISerializer<T>, value: U) => {
|
||||
const obj = Object.entries(value as object)
|
||||
const serObj = ser.serializeObject(obj.length)
|
||||
obj.forEach(([key, value]) => serObj.serializeEntry(key, value))
|
||||
return serObj.end()
|
||||
})
|
||||
|
||||
registerSerialize(Array, <T, U>(ser: ISerializer<T>, value: U) => {
|
||||
const arr = value as any[]
|
||||
const iter = ser.serializeIterable(arr.length)
|
||||
arr.forEach((value: any) => iter.serializeElement(value))
|
||||
return iter.end()
|
||||
})
|
||||
|
||||
|
||||
registerDeserialize(Boolean, (de: IDeserializer) => de.deserializeBoolean({
|
||||
visitBoolean(value: boolean) {
|
||||
return value
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(String, (de: IDeserializer) => de.deserializeString({
|
||||
visitString(value: string) {
|
||||
return value
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(Number, (de: IDeserializer) => de.deserializeNumber({
|
||||
visitNumber(value: number) {
|
||||
return value
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(BigInt, (de: IDeserializer) => de.deserializeBigInt({
|
||||
visitBigInt(value: bigint) {
|
||||
return value
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(Symbol, (de: IDeserializer) => de.deserializeSymbol({
|
||||
visitSymbol(value: symbol) {
|
||||
return value
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(Object, (de: IDeserializer) => de.deserializeObject({
|
||||
visitObject(access: IMapAccess) {
|
||||
let result = {} as any
|
||||
|
||||
for (const [key, value] of access) {
|
||||
result[key] = value
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}))
|
||||
|
||||
registerDeserialize(Array, (de: IDeserializer) => de.deserializeIterable({
|
||||
visitIterable(access: IIterableAccess) {
|
||||
let result = []
|
||||
|
||||
for (const value of access) {
|
||||
result.push(value)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}))
|
||||
|
|
73
src/ser/identity.ts
Normal file
73
src/ser/identity.ts
Normal file
|
@ -0,0 +1,73 @@
|
|||
import { ISerializeIterable, ISerializeObject, ISerializer, SerializeIterable, SerializeObject } from './interface'
|
||||
|
||||
class IdentityMap<T> extends SerializeObject<T> {
|
||||
private value: Record<any, any> = {}
|
||||
private currentKey?: string
|
||||
|
||||
serializeKey(key: string): void {
|
||||
this.currentKey = key
|
||||
}
|
||||
|
||||
serializeValue<U>(value: U): void {
|
||||
this.value[this.currentKey!] = value
|
||||
}
|
||||
|
||||
end(): T {
|
||||
return this.value
|
||||
}
|
||||
}
|
||||
|
||||
class IdentityIterable<T> extends SerializeIterable<T> {
|
||||
private value: any[] = []
|
||||
|
||||
serializeElement<U>(value: U): void {
|
||||
this.value.push(value)
|
||||
}
|
||||
|
||||
end(): T {
|
||||
return this.value as T
|
||||
}
|
||||
}
|
||||
|
||||
export class IdentitySerializer<T> implements ISerializer<T> {
|
||||
serializeAny?(value: any): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeBoolean(value: boolean): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeNumber(value: number): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeBigInt(value: bigint): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeString(value: string): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeSymbol(value: symbol): T {
|
||||
return value as T
|
||||
}
|
||||
|
||||
serializeNull(): T {
|
||||
return null as T
|
||||
}
|
||||
|
||||
serializeIterable(_len?: number): ISerializeIterable<T> {
|
||||
return new IdentityIterable()
|
||||
}
|
||||
|
||||
serializeObject(_len?: number): ISerializeObject<T> {
|
||||
return new IdentityMap()
|
||||
}
|
||||
|
||||
serializeClass(_name: string, _len?: number): ISerializeObject<T> {
|
||||
return new IdentityMap()
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { ISerializeObject, ISerializer, Serialize } from './interface'
|
||||
import { ISerializeIterable, ISerializeObject, ISerializer, Serialize } from './interface'
|
||||
import { isObject, isPlainObject, PrimitivePrototype } from '../utils'
|
||||
import { GlobalRegistry, Registry } from '../registry'
|
||||
import { getSerialize, GlobalRegistry, Registry } from '../registry'
|
||||
|
||||
class UnhandledTypeError extends TypeError {
|
||||
constructor(serializer: ISerializer<unknown>, value: any) {
|
||||
|
@ -17,19 +17,20 @@ function serializeObject<T, U extends object, S extends ISerializeObject<T>>(ser
|
|||
return serializer.end()
|
||||
}
|
||||
|
||||
function serializeIterable<T, U extends Iterable<U>, S extends ISerializeIterable<T>>(serializer: S, iter: U): T {
|
||||
for (const item of iter) {
|
||||
serializer.serializeElement(item)
|
||||
}
|
||||
|
||||
return serializer.end()
|
||||
}
|
||||
|
||||
function serializeClass<T, U extends object, S extends ISerializer<T>>(serializer: S, value: U): T {
|
||||
const name = value.constructor.name
|
||||
const ser = serializer.serializeClass(name)
|
||||
return serializeObject(ser, value)
|
||||
}
|
||||
|
||||
function getSerialize<T, U>(value: U, registry: Registry): Serialize<T, U> {
|
||||
if (isObject(value)) {
|
||||
return registry.serializers.get(value.constructor) as Serialize<T, U>
|
||||
}
|
||||
|
||||
return registry.serializers.get(PrimitivePrototype[typeof value]) || defaultSerialize as Serialize<T, U>
|
||||
}
|
||||
function defaultSerialize<T, U, S extends ISerializer<T>>(serializer: S, value: U): T {
|
||||
switch (typeof value) {
|
||||
case 'string': return serializer.serializeString(value)
|
||||
|
@ -41,6 +42,7 @@ function defaultSerialize<T, U, S extends ISerializer<T>>(serializer: S, value:
|
|||
case 'object':
|
||||
switch (true) {
|
||||
case value == null: return serializer.serializeNull()
|
||||
case Array.isArray(value): return serializeIterable(serializer.serializeIterable(value.length), value)
|
||||
case !isPlainObject(value): return serializeClass(serializer, value)
|
||||
default: return serializeObject(serializer.serializeObject(), value)
|
||||
}
|
||||
|
@ -49,7 +51,7 @@ function defaultSerialize<T, U, S extends ISerializer<T>>(serializer: S, value:
|
|||
}
|
||||
|
||||
export function serialize<T, U, S extends ISerializer<T>>(serializer: S, value: U, registry: Registry = GlobalRegistry): T {
|
||||
const ser = getSerialize<T, U>(value, registry)
|
||||
const ser = getSerialize<T, U>(value, defaultSerialize, registry)
|
||||
return ser(serializer, value)
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
export * from './identity'
|
||||
export * from './impl'
|
||||
export * from './interface'
|
||||
|
||||
|
|
11
src/utils.ts
11
src/utils.ts
|
@ -11,7 +11,7 @@ export interface ToString {
|
|||
}
|
||||
|
||||
export function isObject(value: any): value is object {
|
||||
return typeof value === 'object'
|
||||
return typeof value === 'object' && !Array.isArray(value)
|
||||
}
|
||||
|
||||
export function isPlainObject(value: any): value is object {
|
||||
|
@ -61,3 +61,12 @@ export const PrimitivePrototype = Object.freeze({
|
|||
function: Function
|
||||
} as const)
|
||||
|
||||
export function type(value: any) {
|
||||
switch (true) {
|
||||
case Array.isArray(value): return Array
|
||||
case isPlainObject(value): return Object
|
||||
case isObject(value): return value.constructor
|
||||
default: return PrimitivePrototype[typeof value]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue