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';
|
import { IDeserializer, IVisitor } from './interface';
|
||||||
export declare class ForwardMapAccess extends MapAccess {
|
import { Registry } from '../registry';
|
||||||
private readonly _keys;
|
export declare function forward(value: any, into: any, registry?: Registry): unknown;
|
||||||
private readonly _values;
|
export declare class Forwarder implements IDeserializer {
|
||||||
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 {
|
|
||||||
private readonly value;
|
private readonly value;
|
||||||
constructor(value: any);
|
constructor(value: any);
|
||||||
static with(value: any): Forward;
|
deserializeAny<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeAny<T, V extends IVisitor<T>>(_visitor: V): T;
|
deserializeBoolean<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeNumber<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeBigInt<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeString<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeSymbol<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeNull<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeObject<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeIterable<T>(visitor: IVisitor<T>): T;
|
||||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T;
|
deserializeFunction<T>(_visitor: IVisitor<T>): T;
|
||||||
deserializeFunction<T, V extends IVisitor<T>>(_visitor: V): T;
|
|
||||||
}
|
}
|
||||||
|
|
153
dist/de/forward.js
vendored
153
dist/de/forward.js
vendored
|
@ -1,69 +1,19 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.Forward = exports.ForwardIterableAccess = exports.ForwardMapAccess = void 0;
|
exports.Forwarder = void 0;
|
||||||
const utils_1 = require("../utils");
|
exports.forward = forward;
|
||||||
|
const impl_1 = require("./impl");
|
||||||
const interface_1 = require("./interface");
|
const interface_1 = require("./interface");
|
||||||
class ForwardMapAccess extends interface_1.MapAccess {
|
const registry_1 = require("../registry");
|
||||||
constructor(keys, values) {
|
const utils_1 = require("../utils");
|
||||||
super();
|
function forward(value, into, registry = registry_1.GlobalRegistry) {
|
||||||
Object.defineProperty(this, "_keys", {
|
const forwarder = new Forwarder(value);
|
||||||
enumerable: true,
|
return (0, impl_1.deserialize)(forwarder, into, registry);
|
||||||
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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
exports.ForwardMapAccess = ForwardMapAccess;
|
class ForwardMapAccess extends interface_1.MapAccess {
|
||||||
class ForwardIterableAccess extends interface_1.IterableAccess {
|
constructor(entries) {
|
||||||
constructor(items) {
|
|
||||||
super();
|
super();
|
||||||
Object.defineProperty(this, "items", {
|
Object.defineProperty(this, "_entries", {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
writable: true,
|
writable: true,
|
||||||
|
@ -73,21 +23,65 @@ class ForwardIterableAccess extends interface_1.IterableAccess {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
configurable: true,
|
configurable: true,
|
||||||
writable: true,
|
writable: true,
|
||||||
value: 0
|
value: -1
|
||||||
});
|
});
|
||||||
this.items = items;
|
this._entries = entries;
|
||||||
}
|
}
|
||||||
nextElement() {
|
static fromObject(value) {
|
||||||
if (this.index < this.items.length) {
|
return new this(Object.entries(value));
|
||||||
return utils_1.IterResult.Next(this.items[this.index++]);
|
}
|
||||||
|
nextKey(seed) {
|
||||||
|
this.index += 1;
|
||||||
|
if (this.index >= this._entries.length) {
|
||||||
|
return utils_1.IterResult.Done();
|
||||||
}
|
}
|
||||||
else {
|
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();
|
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 ForwardIterableAccess extends interface_1.IterableAccess {
|
||||||
class Forward {
|
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) {
|
constructor(value) {
|
||||||
Object.defineProperty(this, "value", {
|
Object.defineProperty(this, "value", {
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
|
@ -97,11 +91,22 @@ class Forward {
|
||||||
});
|
});
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
static with(value) {
|
deserializeAny(visitor) {
|
||||||
return new this(value);
|
switch (typeof this.value) {
|
||||||
}
|
case 'string': return this.deserializeString(visitor);
|
||||||
deserializeAny(_visitor) {
|
case 'number': return this.deserializeNumber(visitor);
|
||||||
throw new Error("Can't forward to deserializeAny");
|
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) {
|
deserializeBoolean(visitor) {
|
||||||
return visitor.visitBoolean(this.value);
|
return visitor.visitBoolean(this.value);
|
||||||
|
@ -131,4 +136,4 @@ class Forward {
|
||||||
throw new Error('Method not implemented.');
|
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';
|
import { 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;
|
|
||||||
}
|
|
||||||
export declare class Visitor<T> implements IVisitor<T> {
|
export declare class Visitor<T> implements IVisitor<T> {
|
||||||
private overrides?;
|
private overrides?;
|
||||||
constructor(overrides?: Partial<IVisitor<T>>);
|
constructor(overrides?: Partial<IVisitor<T>>);
|
||||||
|
|
20
dist/de/generic.js
vendored
20
dist/de/generic.js
vendored
|
@ -1,26 +1,8 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.Visitor = exports.GenericSeed = void 0;
|
exports.Visitor = void 0;
|
||||||
const utils_1 = require("../utils");
|
const utils_1 = require("../utils");
|
||||||
const interface_1 = require("./interface");
|
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 {
|
class Visitor {
|
||||||
constructor(overrides) {
|
constructor(overrides) {
|
||||||
Object.defineProperty(this, "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 './generic';
|
||||||
export * from './impl';
|
export * from './impl';
|
||||||
export * from './interface';
|
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);
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
__exportStar(require("./forward"), exports);
|
||||||
__exportStar(require("./generic"), exports);
|
__exportStar(require("./generic"), exports);
|
||||||
__exportStar(require("./impl"), exports);
|
__exportStar(require("./impl"), exports);
|
||||||
__exportStar(require("./interface"), 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';
|
import { Nullable } from '../utils';
|
||||||
export interface IMapAccess {
|
export interface IMapAccess {
|
||||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>;
|
||||||
nextKey<T>(): IteratorResult<T>;
|
|
||||||
nextValue<V>(): IteratorResult<V>;
|
|
||||||
nextEntry<K, V>(): IteratorResult<[K, V]>;
|
|
||||||
sizeHint?(): Nullable<number>;
|
sizeHint?(): Nullable<number>;
|
||||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
entries<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
values<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>;
|
entries<K, V>(kseed: Deserialize<K>, vseed: Deserialize<V>): Iterator<[K, V]>;
|
||||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>;
|
[Symbol.iterator]<K, V>(): Iterator<[K, V]>;
|
||||||
}
|
}
|
||||||
export declare abstract class MapAccess {
|
export declare abstract class MapAccess {
|
||||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
abstract nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
abstract nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>;
|
||||||
private orDefaultSeed;
|
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>;
|
||||||
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]>;
|
|
||||||
private generate;
|
private generate;
|
||||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
keys<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
values<T>(seed?: Deserialize<T>): Iterator<T>;
|
||||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]>;
|
entries<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): Iterator<[K, V]>;
|
||||||
[Symbol.iterator]<K, V>(): Iterator<K, V>;
|
[Symbol.iterator]<K, V>(): Iterator<K, V>;
|
||||||
}
|
}
|
||||||
export interface IIterableAccess {
|
export interface IIterableAccess {
|
||||||
nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>;
|
nextElement<T>(seed: Deserialize<T>): IteratorResult<T>;
|
||||||
nextElement<T>(): IteratorResult<T>;
|
|
||||||
sizeHint?(): Nullable<number>;
|
sizeHint?(): Nullable<number>;
|
||||||
[Symbol.iterator]<T>(): Iterator<T>;
|
[Symbol.iterator]<T>(): Iterator<T>;
|
||||||
}
|
}
|
||||||
export declare abstract class IterableAccess implements IIterableAccess {
|
export declare abstract class IterableAccess implements IIterableAccess {
|
||||||
abstract nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>;
|
abstract nextElement<T>(seed: Deserialize<T>): IteratorResult<T>;
|
||||||
nextElement<T>(): IteratorResult<T>;
|
|
||||||
[Symbol.iterator]<T>(): Iterator<T>;
|
[Symbol.iterator]<T>(): Iterator<T>;
|
||||||
}
|
}
|
||||||
export declare function isVisitor<T>(visitor: any): visitor is IVisitor<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.IterableAccess = exports.MapAccess = void 0;
|
||||||
exports.isVisitor = isVisitor;
|
exports.isVisitor = isVisitor;
|
||||||
const utils_1 = require("../utils");
|
const utils_1 = require("../utils");
|
||||||
const generic_1 = require("./generic");
|
|
||||||
class MapAccess {
|
class MapAccess {
|
||||||
orDefaultSeed(seed) {
|
nextEntry(kseed, vseed) {
|
||||||
return seed || generic_1.GenericSeed.deserialize;
|
const key = this.nextKey(kseed);
|
||||||
}
|
|
||||||
nextEntrySeed(kseed, vseed) {
|
|
||||||
const key = this.nextKeySeed(kseed);
|
|
||||||
if (!key.done) {
|
if (!key.done) {
|
||||||
const value = this.nextValueSeed(vseed);
|
const value = this.nextValue(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();
|
|
||||||
if (!value.done) {
|
if (!value.done) {
|
||||||
return utils_1.IterResult.Next([key.value, value.value]);
|
return utils_1.IterResult.Next([key.value, value.value]);
|
||||||
}
|
}
|
||||||
|
@ -41,19 +21,13 @@ class MapAccess {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keys(seed) {
|
keys(seed) {
|
||||||
return this.generate(seed == null ?
|
return this.generate(this.nextKey.bind(this, seed));
|
||||||
this.nextKey.bind(this) :
|
|
||||||
this.nextKeySeed.bind(this, seed));
|
|
||||||
}
|
}
|
||||||
values(seed) {
|
values(seed) {
|
||||||
return this.generate(seed == null ?
|
return this.generate(this.nextValue.bind(this, seed));
|
||||||
this.nextValue.bind(this) :
|
|
||||||
this.nextValueSeed.bind(this, seed));
|
|
||||||
}
|
}
|
||||||
entries(kseed, vseed) {
|
entries(kseed, vseed) {
|
||||||
return this.generate(kseed == null && vseed == null ?
|
return this.generate(this.nextEntry.bind(this, kseed, vseed));
|
||||||
this.nextEntry.bind(this) :
|
|
||||||
this.nextEntrySeed.bind(this, this.orDefaultSeed(kseed), this.orDefaultSeed(vseed)));
|
|
||||||
}
|
}
|
||||||
[Symbol.iterator]() {
|
[Symbol.iterator]() {
|
||||||
return this.entries();
|
return this.entries();
|
||||||
|
@ -61,9 +35,6 @@ class MapAccess {
|
||||||
}
|
}
|
||||||
exports.MapAccess = MapAccess;
|
exports.MapAccess = MapAccess;
|
||||||
class IterableAccess {
|
class IterableAccess {
|
||||||
nextElement() {
|
|
||||||
return this.nextElementSeed(generic_1.GenericSeed.deserialize);
|
|
||||||
}
|
|
||||||
[Symbol.iterator]() {
|
[Symbol.iterator]() {
|
||||||
return {
|
return {
|
||||||
next: this.nextElement.bind(this)
|
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 GlobalRegistry: Registry;
|
||||||
export declare const registerSerialize: <T, U>(ctor: Function, serialize: Serialize<T, U>) => void;
|
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 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";
|
"use strict";
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
exports.registerDeserialize = exports.registerSerialize = exports.GlobalRegistry = exports.Registry = void 0;
|
exports.registerDeserialize = exports.registerSerialize = exports.GlobalRegistry = exports.Registry = void 0;
|
||||||
|
exports.getSerialize = getSerialize;
|
||||||
|
exports.getDeserialize = getDeserialize;
|
||||||
|
const utils_1 = require("./utils");
|
||||||
class Registry {
|
class Registry {
|
||||||
constructor() {
|
constructor() {
|
||||||
Object.defineProperty(this, "serializers", {
|
Object.defineProperty(this, "serializers", {
|
||||||
|
@ -27,3 +30,73 @@ exports.Registry = Registry;
|
||||||
exports.GlobalRegistry = new Registry();
|
exports.GlobalRegistry = new Registry();
|
||||||
exports.registerSerialize = exports.GlobalRegistry.registerSerialize.bind(exports.GlobalRegistry);
|
exports.registerSerialize = exports.GlobalRegistry.registerSerialize.bind(exports.GlobalRegistry);
|
||||||
exports.registerDeserialize = exports.GlobalRegistry.registerDeserialize.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();
|
return serializer.end();
|
||||||
}
|
}
|
||||||
|
function serializeIterable(serializer, iter) {
|
||||||
|
for (const item of iter) {
|
||||||
|
serializer.serializeElement(item);
|
||||||
|
}
|
||||||
|
return serializer.end();
|
||||||
|
}
|
||||||
function serializeClass(serializer, value) {
|
function serializeClass(serializer, value) {
|
||||||
const name = value.constructor.name;
|
const name = value.constructor.name;
|
||||||
const ser = serializer.serializeClass(name);
|
const ser = serializer.serializeClass(name);
|
||||||
return serializeObject(ser, value);
|
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) {
|
function defaultSerialize(serializer, value) {
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case 'string': return serializer.serializeString(value);
|
case 'string': return serializer.serializeString(value);
|
||||||
|
@ -37,6 +37,7 @@ function defaultSerialize(serializer, value) {
|
||||||
case 'object':
|
case 'object':
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case value == null: return serializer.serializeNull();
|
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);
|
case !(0, utils_1.isPlainObject)(value): return serializeClass(serializer, value);
|
||||||
default: return serializeObject(serializer.serializeObject(), value);
|
default: return serializeObject(serializer.serializeObject(), value);
|
||||||
}
|
}
|
||||||
|
@ -44,6 +45,6 @@ function defaultSerialize(serializer, value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function serialize(serializer, value, registry = registry_1.GlobalRegistry) {
|
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);
|
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 './impl';
|
||||||
export * from './interface';
|
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);
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||||
};
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
__exportStar(require("./identity"), exports);
|
||||||
__exportStar(require("./impl"), exports);
|
__exportStar(require("./impl"), exports);
|
||||||
__exportStar(require("./interface"), 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 object: ObjectConstructor;
|
||||||
readonly function: FunctionConstructor;
|
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.isString = isString;
|
||||||
exports.isNumber = isNumber;
|
exports.isNumber = isNumber;
|
||||||
exports.Null = Null;
|
exports.Null = Null;
|
||||||
|
exports.type = type;
|
||||||
function isObject(value) {
|
function isObject(value) {
|
||||||
return typeof value === 'object';
|
return typeof value === 'object' && !Array.isArray(value);
|
||||||
}
|
}
|
||||||
function isPlainObject(value) {
|
function isPlainObject(value) {
|
||||||
return Object.getPrototypeOf(value) === Object.prototype;
|
return Object.getPrototypeOf(value) === Object.prototype;
|
||||||
|
@ -48,3 +49,11 @@ exports.PrimitivePrototype = Object.freeze({
|
||||||
object: Object,
|
object: Object,
|
||||||
function: Function
|
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 { isFunction } from '../utils'
|
||||||
import { IDeserializer, IIterableAccess, IMapAccess, isVisitor, IVisitor } from './interface'
|
import { 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Visitor<T> implements IVisitor<T> {
|
export class Visitor<T> implements IVisitor<T> {
|
||||||
private overrides?: Partial<IVisitor<T>>
|
private overrides?: Partial<IVisitor<T>>
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from './forward'
|
||||||
export * from './generic'
|
export * from './generic'
|
||||||
export * from './impl'
|
export * from './impl'
|
||||||
export * from './interface'
|
export * from './interface'
|
||||||
|
|
|
@ -1,55 +1,25 @@
|
||||||
import { IterResult, Nullable } from '../utils'
|
import { IterResult, Nullable } from '../utils'
|
||||||
import { GenericSeed } from './generic'
|
|
||||||
|
|
||||||
export interface IMapAccess {
|
export interface IMapAccess {
|
||||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>
|
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]>
|
||||||
nextKey<T>(): IteratorResult<T>
|
|
||||||
nextValue<V>(): IteratorResult<V>
|
|
||||||
nextEntry<K, V>(): IteratorResult<[K, V]>
|
|
||||||
sizeHint?(): Nullable<number>
|
sizeHint?(): Nullable<number>
|
||||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>
|
entries<T>(seed?: Deserialize<T>): Iterator<T>
|
||||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>
|
values<T>(seed?: Deserialize<T>): Iterator<T>
|
||||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>
|
entries<K, V>(kseed: Deserialize<K>, vseed: Deserialize<V>): Iterator<[K, V]>
|
||||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>
|
[Symbol.iterator]<K, V>(): Iterator<[K, V]>
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class MapAccess {
|
export abstract class MapAccess {
|
||||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
abstract nextKey<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
abstract nextValue<T>(seed?: Deserialize<T>): IteratorResult<T>
|
||||||
|
|
||||||
private orDefaultSeed<T>(seed?: Deserialize<T>): Deserialize<T> {
|
nextEntry<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): IteratorResult<[K, V]> {
|
||||||
return seed || GenericSeed.deserialize
|
const key = this.nextKey(kseed) as IteratorResult<K>
|
||||||
}
|
|
||||||
|
|
||||||
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>
|
|
||||||
|
|
||||||
if (!key.done) {
|
if (!key.done) {
|
||||||
const value = this.nextValueSeed(vseed) as IteratorResult<TV>
|
const value = this.nextValue(vseed) as IteratorResult<V>
|
||||||
|
|
||||||
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>
|
|
||||||
|
|
||||||
if (!value.done) {
|
if (!value.done) {
|
||||||
return IterResult.Next([key.value, value.value])
|
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> {
|
keys<T>(seed?: Deserialize<T>): Iterator<T> {
|
||||||
return this.generate(
|
return this.generate<T>(this.nextKey.bind(this, seed) as any)
|
||||||
seed == null ?
|
|
||||||
this.nextKey.bind(this) :
|
|
||||||
this.nextKeySeed.bind(this, seed) as any
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T> {
|
values<T>(seed?: Deserialize<T>): Iterator<T> {
|
||||||
return this.generate(
|
return this.generate(this.nextValue.bind(this, seed) as any)
|
||||||
seed == null ?
|
|
||||||
this.nextValue.bind(this) :
|
|
||||||
this.nextValueSeed.bind(this, seed) as any
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]> {
|
entries<K, V>(kseed?: Deserialize<K>, vseed?: Deserialize<V>): Iterator<[K, V]> {
|
||||||
return this.generate(
|
return this.generate(this.nextEntry.bind(this, kseed, vseed) as any)
|
||||||
kseed == null && vseed == null ?
|
|
||||||
this.nextEntry.bind(this) :
|
|
||||||
this.nextEntrySeed.bind(this, this.orDefaultSeed(kseed), this.orDefaultSeed(vseed)) as any
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[Symbol.iterator]<K, V>(): Iterator<K, V> {
|
[Symbol.iterator]<K, V>(): Iterator<K, V> {
|
||||||
|
@ -97,18 +55,13 @@ export abstract class MapAccess {
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IIterableAccess {
|
export interface IIterableAccess {
|
||||||
nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>
|
nextElement<T>(seed: Deserialize<T>): IteratorResult<T>
|
||||||
nextElement<T>(): IteratorResult<T>
|
|
||||||
sizeHint?(): Nullable<number>
|
sizeHint?(): Nullable<number>
|
||||||
[Symbol.iterator]<T>(): Iterator<T>
|
[Symbol.iterator]<T>(): Iterator<T>
|
||||||
}
|
}
|
||||||
|
|
||||||
export abstract class IterableAccess implements IIterableAccess {
|
export abstract class IterableAccess implements IIterableAccess {
|
||||||
abstract nextElementSeed<T, D extends Deserialize<T>>(seed: D): IteratorResult<T>
|
abstract nextElement<T>(seed: Deserialize<T>): IteratorResult<T>
|
||||||
|
|
||||||
nextElement<T>(): IteratorResult<T> {
|
|
||||||
return this.nextElementSeed(GenericSeed.deserialize)
|
|
||||||
}
|
|
||||||
|
|
||||||
[Symbol.iterator]<T>(): Iterator<T> {
|
[Symbol.iterator]<T>(): Iterator<T> {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Deserialize } from './de'
|
import { Deserialize, IDeserializer, IIterableAccess, IMapAccess } from './de'
|
||||||
import { Serialize } from './ser'
|
import { ISerializer, Serialize } from './ser'
|
||||||
|
import { isObject, Null, PrimitivePrototype, type } from './utils'
|
||||||
|
|
||||||
export class Registry {
|
export class Registry {
|
||||||
serializers: Map<Function, Serialize<any, any>> = new Map()
|
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 registerSerialize = GlobalRegistry.registerSerialize.bind(GlobalRegistry)
|
||||||
export const registerDeserialize = GlobalRegistry.registerDeserialize.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 { isObject, isPlainObject, PrimitivePrototype } from '../utils'
|
||||||
import { GlobalRegistry, Registry } from '../registry'
|
import { getSerialize, GlobalRegistry, Registry } from '../registry'
|
||||||
|
|
||||||
class UnhandledTypeError extends TypeError {
|
class UnhandledTypeError extends TypeError {
|
||||||
constructor(serializer: ISerializer<unknown>, value: any) {
|
constructor(serializer: ISerializer<unknown>, value: any) {
|
||||||
|
@ -17,19 +17,20 @@ function serializeObject<T, U extends object, S extends ISerializeObject<T>>(ser
|
||||||
return serializer.end()
|
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 {
|
function serializeClass<T, U extends object, S extends ISerializer<T>>(serializer: S, value: U): T {
|
||||||
const name = value.constructor.name
|
const name = value.constructor.name
|
||||||
const ser = serializer.serializeClass(name)
|
const ser = serializer.serializeClass(name)
|
||||||
return serializeObject(ser, value)
|
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 {
|
function defaultSerialize<T, U, S extends ISerializer<T>>(serializer: S, value: U): T {
|
||||||
switch (typeof value) {
|
switch (typeof value) {
|
||||||
case 'string': return serializer.serializeString(value)
|
case 'string': return serializer.serializeString(value)
|
||||||
|
@ -41,6 +42,7 @@ function defaultSerialize<T, U, S extends ISerializer<T>>(serializer: S, value:
|
||||||
case 'object':
|
case 'object':
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case value == null: return serializer.serializeNull()
|
case value == null: return serializer.serializeNull()
|
||||||
|
case Array.isArray(value): return serializeIterable(serializer.serializeIterable(value.length), value)
|
||||||
case !isPlainObject(value): return serializeClass(serializer, value)
|
case !isPlainObject(value): return serializeClass(serializer, value)
|
||||||
default: return serializeObject(serializer.serializeObject(), 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 {
|
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)
|
return ser(serializer, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
export * from './identity'
|
||||||
export * from './impl'
|
export * from './impl'
|
||||||
export * from './interface'
|
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 {
|
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 {
|
export function isPlainObject(value: any): value is object {
|
||||||
|
@ -61,3 +61,12 @@ export const PrimitivePrototype = Object.freeze({
|
||||||
function: Function
|
function: Function
|
||||||
} as const)
|
} 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