clean up interfaces; merge nextSeed/next methods in accessors

This commit is contained in:
Rowan 2025-05-25 10:54:38 -05:00
parent f886c5c003
commit bbaea7cc9e
26 changed files with 650 additions and 293 deletions

45
dist/de/forward.d.ts vendored
View file

@ -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
View file

@ -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;

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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);

View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View 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
View 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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View file

@ -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
View 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.')
}
}

View file

@ -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>>

View file

@ -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'

View file

@ -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 {

View file

@ -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
View 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()
}
}

View file

@ -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)
} }

View file

@ -1,3 +1,4 @@
export * from './identity'
export * from './impl' export * from './impl'
export * from './interface' export * from './interface'

View file

@ -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]
}
}