add rename options for ser/de
This commit is contained in:
parent
da1fad1cd0
commit
b4c7a9ba2b
28 changed files with 981 additions and 124 deletions
8
dist/de/forward.d.ts
vendored
8
dist/de/forward.d.ts
vendored
|
@ -1,13 +1,13 @@
|
|||
import { Deserialize, IDeserializer, IterableAccess, IVisitor, MapAccess } from './interface';
|
||||
export declare class ForwardMapAccess extends MapAccess {
|
||||
private readonly keys;
|
||||
private readonly values;
|
||||
private readonly _keys;
|
||||
private readonly _values;
|
||||
private kindex;
|
||||
private vindex;
|
||||
constructor(keys: string[], values: any[]);
|
||||
static fromObject(obj: object): ForwardMapAccess;
|
||||
nextKeySeed<T, K extends Deserialize>(_seed: K): IteratorResult<T>;
|
||||
nextValueSeed<T, V extends Deserialize>(_seed: V): IteratorResult<T>;
|
||||
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>;
|
||||
}
|
||||
|
|
12
dist/de/forward.js
vendored
12
dist/de/forward.js
vendored
|
@ -6,13 +6,13 @@ const interface_1 = require("./interface");
|
|||
class ForwardMapAccess extends interface_1.MapAccess {
|
||||
constructor(keys, values) {
|
||||
super();
|
||||
Object.defineProperty(this, "keys", {
|
||||
Object.defineProperty(this, "_keys", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "values", {
|
||||
Object.defineProperty(this, "_values", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
|
@ -30,8 +30,8 @@ class ForwardMapAccess extends interface_1.MapAccess {
|
|||
writable: true,
|
||||
value: 0
|
||||
});
|
||||
this.keys = keys;
|
||||
this.values = values;
|
||||
this._keys = keys;
|
||||
this._values = values;
|
||||
}
|
||||
static fromObject(obj) {
|
||||
return new ForwardMapAccess(Object.keys(obj), Object.values(obj));
|
||||
|
@ -44,7 +44,7 @@ class ForwardMapAccess extends interface_1.MapAccess {
|
|||
}
|
||||
nextKey() {
|
||||
if (this.kindex < this.keys.length) {
|
||||
return utils_1.IterResult.Next(this.keys[this.kindex++]);
|
||||
return utils_1.IterResult.Next(this._keys[this.kindex++]);
|
||||
}
|
||||
else {
|
||||
return utils_1.IterResult.Done();
|
||||
|
@ -52,7 +52,7 @@ class ForwardMapAccess extends interface_1.MapAccess {
|
|||
}
|
||||
nextValue() {
|
||||
if (this.vindex < this.values.length) {
|
||||
return utils_1.IterResult.Next(this.values[this.vindex++]);
|
||||
return utils_1.IterResult.Next(this._values[this.vindex++]);
|
||||
}
|
||||
else {
|
||||
return utils_1.IterResult.Done();
|
||||
|
|
21
dist/de/generic.d.ts
vendored
21
dist/de/generic.d.ts
vendored
|
@ -1,3 +1,4 @@
|
|||
import { SerdeOptions } from '../option';
|
||||
import { IDeserializer, IIterableAccess, IMapAccess, IVisitor } from './interface';
|
||||
export declare class GenericSeed<T> {
|
||||
readonly visitor: IVisitor<T>;
|
||||
|
@ -5,7 +6,10 @@ export declare class GenericSeed<T> {
|
|||
static deserialize<T, D extends IDeserializer>(deserializer: D, visitor?: IVisitor<T>): T;
|
||||
deserialize<D extends IDeserializer>(deserializer: D): T;
|
||||
}
|
||||
export declare class GenericVisitor<T> implements IVisitor<T> {
|
||||
export declare class ProxyVisitor<T> implements IVisitor<T> {
|
||||
private overrides?;
|
||||
private options?;
|
||||
constructor(overrides?: Partial<IVisitor<T>>, options?: SerdeOptions);
|
||||
visitBoolean(value: boolean): T;
|
||||
visitNumber(value: number): T;
|
||||
visitBigInt(value: bigint): T;
|
||||
|
@ -15,3 +19,18 @@ export declare class GenericVisitor<T> implements IVisitor<T> {
|
|||
visitObject(access: IMapAccess): T;
|
||||
visitIterable(access: IIterableAccess): T;
|
||||
}
|
||||
export declare class ProxyDeserializer implements IDeserializer {
|
||||
private readonly deserializer;
|
||||
private readonly options?;
|
||||
constructor(deserializer: IDeserializer, options?: SerdeOptions);
|
||||
deserializeAny<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeFunction<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
}
|
||||
|
|
196
dist/de/generic.js
vendored
196
dist/de/generic.js
vendored
|
@ -1,8 +1,9 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.GenericVisitor = exports.GenericSeed = void 0;
|
||||
exports.ProxyDeserializer = exports.ProxyVisitor = exports.GenericSeed = void 0;
|
||||
const utils_1 = require("../utils");
|
||||
class GenericSeed {
|
||||
constructor(visitor = new GenericVisitor()) {
|
||||
constructor(visitor = new ProxyVisitor()) {
|
||||
Object.defineProperty(this, "visitor", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
|
@ -11,7 +12,7 @@ class GenericSeed {
|
|||
});
|
||||
this.visitor = visitor;
|
||||
}
|
||||
static deserialize(deserializer, visitor = new GenericVisitor()) {
|
||||
static deserialize(deserializer, visitor = new ProxyVisitor()) {
|
||||
return deserializer.deserializeAny(visitor);
|
||||
}
|
||||
deserialize(deserializer) {
|
||||
|
@ -19,34 +20,156 @@ class GenericSeed {
|
|||
}
|
||||
}
|
||||
exports.GenericSeed = GenericSeed;
|
||||
class GenericVisitor {
|
||||
class ProxyMapAccess {
|
||||
constructor(access, options) {
|
||||
Object.defineProperty(this, "access", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "options", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
if (access instanceof ProxyMapAccess) {
|
||||
return this;
|
||||
}
|
||||
this.access = access;
|
||||
this.options = options;
|
||||
}
|
||||
wrapResponse(result) {
|
||||
var _a, _b, _c, _d;
|
||||
if (result.done) {
|
||||
return result;
|
||||
}
|
||||
else if ((0, utils_1.isString)(result.value)) {
|
||||
const key = (_b = (_a = this.options) === null || _a === void 0 ? void 0 : _a.getDeserializationPropertyName(result.value)) !== null && _b !== void 0 ? _b : result.value;
|
||||
return utils_1.IterResult.Next(key);
|
||||
}
|
||||
else if (Array.isArray(result.value)) {
|
||||
const [alias, value] = result.value;
|
||||
const key = (_d = (_c = this.options) === null || _c === void 0 ? void 0 : _c.getDeserializationPropertyName(alias)) !== null && _d !== void 0 ? _d : alias;
|
||||
return utils_1.IterResult.Next([
|
||||
key,
|
||||
value
|
||||
]);
|
||||
}
|
||||
else {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
nextKeySeed(seed) {
|
||||
return this.wrapResponse(this.access.nextKeySeed(seed));
|
||||
}
|
||||
nextValueSeed(seed) {
|
||||
return this.access.nextValueSeed(seed);
|
||||
}
|
||||
nextEntrySeed(kseed, vseed) {
|
||||
return this.wrapResponse(this.access.nextEntrySeed(kseed, vseed));
|
||||
}
|
||||
nextKey() {
|
||||
return this.wrapResponse(this.access.nextKey());
|
||||
}
|
||||
nextValue() {
|
||||
return this.access.nextValue();
|
||||
}
|
||||
nextEntry() {
|
||||
return this.wrapResponse(this.access.nextEntry());
|
||||
}
|
||||
sizeHint() {
|
||||
var _a, _b;
|
||||
return (_b = (_a = this.access).sizeHint) === null || _b === void 0 ? void 0 : _b.call(_a);
|
||||
}
|
||||
*generate(next) {
|
||||
let item;
|
||||
while ((item = next()) && !item.done) {
|
||||
yield item.value;
|
||||
}
|
||||
}
|
||||
keys(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed));
|
||||
}
|
||||
values(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed));
|
||||
}
|
||||
entries(kseed, vseed) {
|
||||
return this.generate(kseed == null || vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, kseed, vseed));
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
}
|
||||
}
|
||||
class ProxyVisitor {
|
||||
constructor(overrides, options) {
|
||||
Object.defineProperty(this, "overrides", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "options", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
if (overrides instanceof ProxyVisitor) {
|
||||
return overrides;
|
||||
}
|
||||
this.overrides = overrides;
|
||||
this.options = options;
|
||||
}
|
||||
visitBoolean(value) {
|
||||
return value;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitBoolean) === null || _b === void 0 ? void 0 : _b.call(_a, value)) !== null && _c !== void 0 ? _c : value;
|
||||
}
|
||||
visitNumber(value) {
|
||||
return value;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitNumber) === null || _b === void 0 ? void 0 : _b.call(_a, value)) !== null && _c !== void 0 ? _c : value;
|
||||
}
|
||||
visitBigInt(value) {
|
||||
return value;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitBigInt) === null || _b === void 0 ? void 0 : _b.call(_a, value)) !== null && _c !== void 0 ? _c : value;
|
||||
}
|
||||
visitString(value) {
|
||||
return value;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitString) === null || _b === void 0 ? void 0 : _b.call(_a, value)) !== null && _c !== void 0 ? _c : value;
|
||||
}
|
||||
visitSymbol(value) {
|
||||
return value;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitSymbol) === null || _b === void 0 ? void 0 : _b.call(_a, value)) !== null && _c !== void 0 ? _c : value;
|
||||
}
|
||||
visitNull() {
|
||||
return null;
|
||||
var _a, _b, _c;
|
||||
return (_c = (_b = (_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitNull) === null || _b === void 0 ? void 0 : _b.call(_a)) !== null && _c !== void 0 ? _c : null;
|
||||
}
|
||||
visitObject(access) {
|
||||
var _a, _b;
|
||||
const proxy = new ProxyMapAccess(access, this.options);
|
||||
if ((0, utils_1.isFunction)((_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitObject)) {
|
||||
return (_b = this.overrides) === null || _b === void 0 ? void 0 : _b.visitObject(proxy);
|
||||
}
|
||||
const result = [];
|
||||
let entry;
|
||||
while ((entry = access.nextEntry()) && !entry.done) {
|
||||
while ((entry = proxy.nextEntry()) && !entry.done) {
|
||||
result.push(entry.value);
|
||||
}
|
||||
return Object.fromEntries(result);
|
||||
}
|
||||
visitIterable(access) {
|
||||
var _a, _b;
|
||||
if ((0, utils_1.isFunction)((_a = this.overrides) === null || _a === void 0 ? void 0 : _a.visitIterable)) {
|
||||
return (_b = this.overrides) === null || _b === void 0 ? void 0 : _b.visitIterable(access);
|
||||
}
|
||||
const result = [];
|
||||
let element;
|
||||
while ((element = access.nextElement())) {
|
||||
|
@ -55,4 +178,53 @@ class GenericVisitor {
|
|||
return result;
|
||||
}
|
||||
}
|
||||
exports.GenericVisitor = GenericVisitor;
|
||||
exports.ProxyVisitor = ProxyVisitor;
|
||||
class ProxyDeserializer {
|
||||
constructor(deserializer, options) {
|
||||
Object.defineProperty(this, "deserializer", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "options", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
this.deserializer = deserializer;
|
||||
this.options = options;
|
||||
}
|
||||
deserializeAny(visitor) {
|
||||
return this.deserializer.deserializeAny(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeBoolean(visitor) {
|
||||
return this.deserializer.deserializeBoolean(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeNumber(visitor) {
|
||||
return this.deserializer.deserializeNumber(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeBigInt(visitor) {
|
||||
return this.deserializer.deserializeBigInt(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeString(visitor) {
|
||||
return this.deserializer.deserializeString(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeSymbol(visitor) {
|
||||
return this.deserializer.deserializeSymbol(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeNull(visitor) {
|
||||
return this.deserializer.deserializeNull(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeObject(visitor) {
|
||||
return this.deserializer.deserializeObject(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeIterable(visitor) {
|
||||
return this.deserializer.deserializeIterable(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
deserializeFunction(visitor) {
|
||||
return this.deserializer.deserializeFunction(new ProxyVisitor(visitor, this.options));
|
||||
}
|
||||
}
|
||||
exports.ProxyDeserializer = ProxyDeserializer;
|
||||
|
|
4
dist/de/impl.js
vendored
4
dist/de/impl.js
vendored
|
@ -2,12 +2,14 @@
|
|||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.deserialize = deserialize;
|
||||
const registry_1 = require("../registry");
|
||||
const generic_1 = require("./generic");
|
||||
function deserialize(deserializer, into, registry = registry_1.GlobalRegistry) {
|
||||
var _a;
|
||||
const de = registry.deserializers.get(into);
|
||||
if (de == null) {
|
||||
throw new ReferenceError(`No deserializer for ${into.name}`);
|
||||
}
|
||||
else {
|
||||
return de(deserializer);
|
||||
return de(new generic_1.ProxyDeserializer(deserializer, (_a = into === null || into === void 0 ? void 0 : into[Symbol.metadata]) === null || _a === void 0 ? void 0 : _a.serde));
|
||||
}
|
||||
}
|
||||
|
|
47
dist/de/interface.d.ts
vendored
47
dist/de/interface.d.ts
vendored
|
@ -1,20 +1,29 @@
|
|||
import { Nullable } from "../utils";
|
||||
import { Nullable } from '../utils';
|
||||
export interface IMapAccess {
|
||||
nextKeySeed<T, K extends Deserialize>(seed: K): IteratorResult<T>;
|
||||
nextValueSeed<T, V extends Deserialize>(seed: V): IteratorResult<T>;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
nextKey<T>(): IteratorResult<T>;
|
||||
nextValue<V>(): IteratorResult<V>;
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>;
|
||||
sizeHint?(): Nullable<number>;
|
||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>;
|
||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>;
|
||||
}
|
||||
export declare abstract class MapAccess {
|
||||
abstract nextKeySeed<T, K extends Deserialize>(seed: K): IteratorResult<T>;
|
||||
abstract nextValueSeed<T, V extends Deserialize>(seed: V): IteratorResult<T>;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>;
|
||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>;
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>;
|
||||
abstract nextKey<T>(): IteratorResult<T>;
|
||||
abstract nextValue<V>(): IteratorResult<V>;
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>;
|
||||
private generate;
|
||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T>;
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>;
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]>;
|
||||
[Symbol.iterator]<K, V>(): Iterator<K, V>;
|
||||
}
|
||||
export interface IIterableAccess {
|
||||
nextElement<T>(): IteratorResult<T>;
|
||||
|
@ -34,17 +43,17 @@ export interface IVisitor<T> {
|
|||
visitIterable(access: IIterableAccess): T;
|
||||
}
|
||||
export interface IDeserializer {
|
||||
deserializeAny<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeFunction<T, V extends IVisitor<T>>(visitor: V): T;
|
||||
deserializeAny<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeBoolean<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeNumber<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeBigInt<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeString<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeSymbol<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeNull<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeObject<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeIterable<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
deserializeFunction<T>(visitor: Partial<IVisitor<T>>): T;
|
||||
}
|
||||
export interface Deserialize {
|
||||
<T>(deserializer: IDeserializer): T;
|
||||
export interface Deserialize<T> {
|
||||
(deserializer: IDeserializer): T;
|
||||
}
|
||||
|
|
24
dist/de/interface.js
vendored
24
dist/de/interface.js
vendored
|
@ -23,6 +23,30 @@ class MapAccess {
|
|||
}
|
||||
return utils_1.IterResult.Done();
|
||||
}
|
||||
*generate(next) {
|
||||
let item;
|
||||
while ((item = next())) {
|
||||
yield item.value;
|
||||
}
|
||||
}
|
||||
keys(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed));
|
||||
}
|
||||
values(seed) {
|
||||
return this.generate(seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed));
|
||||
}
|
||||
entries(kseed, vseed) {
|
||||
return this.generate(kseed == null || vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, kseed, vseed));
|
||||
}
|
||||
[Symbol.iterator]() {
|
||||
return this.entries();
|
||||
}
|
||||
}
|
||||
exports.MapAccess = MapAccess;
|
||||
class IterableAccess {
|
||||
|
|
2
dist/decorator.d.ts
vendored
Normal file
2
dist/decorator.d.ts
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
import { ContainerOptions, PropertyOptions } from './option';
|
||||
export declare function serde(options: ContainerOptions | PropertyOptions): (target: any, context: DecoratorContext) => void;
|
34
dist/decorator.js
vendored
Normal file
34
dist/decorator.js
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.serde = serde;
|
||||
const option_1 = require("./option");
|
||||
const ContextKind = Object.freeze({
|
||||
Class: 'class',
|
||||
Method: 'method',
|
||||
Getter: 'getter',
|
||||
Setter: 'setter',
|
||||
Field: 'field',
|
||||
Accessor: 'accessor'
|
||||
});
|
||||
function decorateClass(target, context, options) {
|
||||
const serde = context.metadata.serde;
|
||||
context.metadata.serde = new option_1.SerdeOptions(target, options, serde === null || serde === void 0 ? void 0 : serde.properties);
|
||||
}
|
||||
function decorateField(context, options) {
|
||||
const serde = context.metadata.serde || new option_1.SerdeOptions(undefined);
|
||||
serde.properties.set(context.name, options);
|
||||
context.metadata.serde = serde;
|
||||
}
|
||||
function serde(options) {
|
||||
return function (target, context) {
|
||||
switch (context.kind) {
|
||||
case ContextKind.Class:
|
||||
decorateClass(target, context, options);
|
||||
break;
|
||||
case ContextKind.Field:
|
||||
decorateField(context, options);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
||||
}
|
2
dist/index.d.ts
vendored
2
dist/index.d.ts
vendored
|
@ -1,6 +1,8 @@
|
|||
import '@tsmetadata/polyfill';
|
||||
export * as ser from './ser/impl';
|
||||
export * as de from './de/impl';
|
||||
export * from './decorator';
|
||||
export * from './option';
|
||||
export * from './case';
|
||||
export * from './registry';
|
||||
export * from './utils';
|
||||
|
|
2
dist/index.js
vendored
2
dist/index.js
vendored
|
@ -40,6 +40,8 @@ exports.de = exports.ser = void 0;
|
|||
require("@tsmetadata/polyfill");
|
||||
exports.ser = __importStar(require("./ser/impl"));
|
||||
exports.de = __importStar(require("./de/impl"));
|
||||
__exportStar(require("./decorator"), exports);
|
||||
__exportStar(require("./option"), exports);
|
||||
__exportStar(require("./case"), exports);
|
||||
__exportStar(require("./registry"), exports);
|
||||
__exportStar(require("./utils"), exports);
|
||||
|
|
71
dist/option.d.ts
vendored
Normal file
71
dist/option.d.ts
vendored
Normal file
|
@ -0,0 +1,71 @@
|
|||
import { Deserialize } from './de';
|
||||
import { Serialize } from './ser';
|
||||
import { CaseConvention } from './case';
|
||||
import { Nullable } from './utils';
|
||||
export interface RenameOptions {
|
||||
serialize?: string;
|
||||
deserialize?: string;
|
||||
}
|
||||
export interface RenameAllOptions {
|
||||
serialize?: CaseConvention;
|
||||
deserialize?: CaseConvention;
|
||||
}
|
||||
export interface ContainerOptions {
|
||||
rename?: RenameOptions | string;
|
||||
renameAll?: RenameAllOptions | CaseConvention;
|
||||
default?: () => any;
|
||||
denyUnknownFields?: boolean;
|
||||
tag?: string;
|
||||
untagged?: boolean;
|
||||
}
|
||||
interface Predicate {
|
||||
<T>(value: T): boolean;
|
||||
}
|
||||
export interface SkipOptions {
|
||||
serialize?: Predicate | boolean;
|
||||
deserialize?: Predicate | boolean;
|
||||
}
|
||||
export interface PropertyOptions {
|
||||
alias?: string | string[];
|
||||
default?: () => any;
|
||||
flatten?: boolean;
|
||||
rename?: RenameOptions | string;
|
||||
skip?: SkipOptions | Predicate | boolean;
|
||||
serializeWith?: Serialize<any>;
|
||||
deserializeWith?: Deserialize<any>;
|
||||
}
|
||||
export declare const Stage: Readonly<{
|
||||
readonly Serialize: 0;
|
||||
readonly Deserialize: 1;
|
||||
}>;
|
||||
export declare class PropertyMap extends Map<string, PropertyOptions> {
|
||||
private readonly options;
|
||||
private readonly aliases;
|
||||
constructor(options: SerdeOptions, iterable?: Iterable<any>);
|
||||
private setAliasesFromOptions;
|
||||
set(key: string, value: PropertyOptions): this;
|
||||
addAlias(alias: string | Iterable<string>, key: string): void;
|
||||
getFieldFromAlias(alias: string): string | undefined;
|
||||
private buildAliasMap;
|
||||
}
|
||||
export type Stage = typeof Stage[keyof typeof Stage];
|
||||
export declare class SerdeOptions {
|
||||
readonly target: Nullable<any>;
|
||||
readonly container: ContainerOptions;
|
||||
readonly properties: PropertyMap;
|
||||
constructor(target: any, container?: ContainerOptions, properties?: PropertyMap);
|
||||
private getClassName;
|
||||
getSerializedClassName(defaultName?: string): string | undefined;
|
||||
getDeserializedClassName(defaultName?: string): string | undefined;
|
||||
getCaseConvention(stage: Stage): CaseConvention | undefined;
|
||||
applyCaseConvention(stage: Stage, property: string): string;
|
||||
getPropertyRename(stage: Stage, property: string): string | undefined;
|
||||
getSerializationPropertyName(property: string): string;
|
||||
getNameFromAlias(alias: string): string | undefined;
|
||||
getDeserializationPropertyName(property: string): string;
|
||||
shouldSkip(stage: Stage, property: string, value: any): boolean;
|
||||
shouldSerialize(property: string, value: any): boolean;
|
||||
shouldDeserialize(property: string, value: any): boolean;
|
||||
defaultFor(property: string): any;
|
||||
}
|
||||
export {};
|
209
dist/option.js
vendored
Normal file
209
dist/option.js
vendored
Normal file
|
@ -0,0 +1,209 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SerdeOptions = exports.PropertyMap = exports.Stage = void 0;
|
||||
const case_1 = require("./case");
|
||||
const utils_1 = require("./utils");
|
||||
exports.Stage = Object.freeze({
|
||||
Serialize: 0,
|
||||
Deserialize: 1
|
||||
});
|
||||
class PropertyMap extends Map {
|
||||
constructor(options, iterable) {
|
||||
super(iterable);
|
||||
Object.defineProperty(this, "options", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "aliases", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: new Map()
|
||||
});
|
||||
this.options = options;
|
||||
this.buildAliasMap();
|
||||
}
|
||||
setAliasesFromOptions(key, options) {
|
||||
this.aliases.set(key, key);
|
||||
if (options.alias != null) {
|
||||
this.addAlias(options.alias, key);
|
||||
}
|
||||
if ((0, utils_1.isString)(options.rename)) {
|
||||
this.aliases.set(options.rename, key);
|
||||
}
|
||||
else if ((0, utils_1.isNumber)(this.options.container.renameAll)) {
|
||||
this.aliases.set(this.options.applyCaseConvention(exports.Stage.Deserialize, key), key);
|
||||
}
|
||||
}
|
||||
set(key, value) {
|
||||
super.set(key, value);
|
||||
this.setAliasesFromOptions(key, value);
|
||||
return this;
|
||||
}
|
||||
addAlias(alias, key) {
|
||||
if ((0, utils_1.isString)(alias)) {
|
||||
this.aliases.set(alias, key);
|
||||
}
|
||||
else if ((0, utils_1.isIterable)(alias)) {
|
||||
for (const a of alias) {
|
||||
this.addAlias(a, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
getFieldFromAlias(alias) {
|
||||
return this.aliases.get(alias);
|
||||
}
|
||||
buildAliasMap() {
|
||||
for (const [key, value] of this.entries()) {
|
||||
if (value.alias != null) {
|
||||
this.addAlias(value.alias, key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.PropertyMap = PropertyMap;
|
||||
class SerdeOptions {
|
||||
constructor(target, container = {}, properties = new PropertyMap(this)) {
|
||||
Object.defineProperty(this, "target", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "container", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
Object.defineProperty(this, "properties", {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
value: void 0
|
||||
});
|
||||
this.target = target;
|
||||
this.container = container;
|
||||
this.properties = properties;
|
||||
}
|
||||
getClassName(stage, defaultName) {
|
||||
var _a, _b, _c, _d;
|
||||
if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
|
||||
if ((0, utils_1.isString)(this.container.rename)) {
|
||||
return this.container.rename;
|
||||
}
|
||||
else if (stage === exports.Stage.Serialize && (0, utils_1.isString)((_c = this.container.rename) === null || _c === void 0 ? void 0 : _c.serialize)) {
|
||||
return this.container.rename.serialize;
|
||||
}
|
||||
else if (stage === exports.Stage.Deserialize && (0, utils_1.isString)((_d = this.container.rename) === null || _d === void 0 ? void 0 : _d.deserialize)) {
|
||||
return this.container.rename.serialize;
|
||||
}
|
||||
else {
|
||||
return defaultName;
|
||||
}
|
||||
}
|
||||
getSerializedClassName(defaultName) {
|
||||
var _a, _b;
|
||||
if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
|
||||
return this.getClassName(exports.Stage.Serialize, defaultName);
|
||||
}
|
||||
getDeserializedClassName(defaultName) {
|
||||
var _a, _b;
|
||||
if (defaultName === void 0) { defaultName = (_b = (_a = this.target) === null || _a === void 0 ? void 0 : _a.constructor) === null || _b === void 0 ? void 0 : _b.name; }
|
||||
return this.getClassName(exports.Stage.Deserialize, defaultName);
|
||||
}
|
||||
getCaseConvention(stage) {
|
||||
var _a, _b;
|
||||
if ((0, utils_1.isNumber)(this.container.renameAll)) {
|
||||
if (stage === exports.Stage.Serialize) {
|
||||
return this.container.renameAll;
|
||||
}
|
||||
else {
|
||||
return case_1.CaseConvention.CamelCase;
|
||||
}
|
||||
}
|
||||
else if (stage === exports.Stage.Serialize && (0, utils_1.isNumber)((_a = this.container.renameAll) === null || _a === void 0 ? void 0 : _a.serialize)) {
|
||||
return this.container.renameAll.serialize;
|
||||
}
|
||||
else if (stage === exports.Stage.Deserialize && (0, utils_1.isNumber)((_b = this.container.renameAll) === null || _b === void 0 ? void 0 : _b.deserialize)) {
|
||||
return this.container.renameAll.deserialize;
|
||||
}
|
||||
}
|
||||
applyCaseConvention(stage, property) {
|
||||
const convention = this.getCaseConvention(stage);
|
||||
return convention != null ? (0, case_1.convertCase)(property, convention) : property;
|
||||
}
|
||||
getPropertyRename(stage, property) {
|
||||
var _a, _b;
|
||||
const options = this.properties.get(property);
|
||||
if (options == null) {
|
||||
return;
|
||||
}
|
||||
else if ((0, utils_1.isString)(options.rename)) {
|
||||
return options.rename;
|
||||
}
|
||||
else if (stage == exports.Stage.Serialize && (0, utils_1.isString)((_a = options.rename) === null || _a === void 0 ? void 0 : _a.serialize)) {
|
||||
return options.rename.serialize;
|
||||
}
|
||||
else if (stage == exports.Stage.Deserialize && (0, utils_1.isString)((_b = options.rename) === null || _b === void 0 ? void 0 : _b.deserialize)) {
|
||||
return options.rename.deserialize;
|
||||
}
|
||||
}
|
||||
getSerializationPropertyName(property) {
|
||||
return this.getPropertyRename(exports.Stage.Serialize, property) ||
|
||||
this.applyCaseConvention(exports.Stage.Serialize, property);
|
||||
}
|
||||
getNameFromAlias(alias) {
|
||||
return this.properties.getFieldFromAlias(alias);
|
||||
}
|
||||
getDeserializationPropertyName(property) {
|
||||
return this.getNameFromAlias(property) ||
|
||||
this.applyCaseConvention(exports.Stage.Deserialize, property);
|
||||
}
|
||||
shouldSkip(stage, property, value) {
|
||||
var _a, _b, _c, _d;
|
||||
const options = this.properties.get(property);
|
||||
if (options == null) {
|
||||
return false;
|
||||
}
|
||||
else if (typeof options.skip === 'boolean') {
|
||||
return options.skip;
|
||||
}
|
||||
else if ((0, utils_1.isFunction)(options.skip)) {
|
||||
return options.skip(value);
|
||||
}
|
||||
else if (stage === exports.Stage.Serialize && typeof ((_a = options.skip) === null || _a === void 0 ? void 0 : _a.serialize) === 'boolean') {
|
||||
return options.skip.serialize;
|
||||
}
|
||||
else if (stage === exports.Stage.Serialize && (0, utils_1.isFunction)((_b = options.skip) === null || _b === void 0 ? void 0 : _b.serialize)) {
|
||||
return options.skip.serialize(value);
|
||||
}
|
||||
else if (stage === exports.Stage.Deserialize && typeof ((_c = options.skip) === null || _c === void 0 ? void 0 : _c.deserialize) === 'boolean') {
|
||||
return options.skip.deserialize;
|
||||
}
|
||||
else if (stage === exports.Stage.Deserialize && (0, utils_1.isFunction)((_d = options.skip) === null || _d === void 0 ? void 0 : _d.deserialize)) {
|
||||
return options.skip.deserialize(value);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
shouldSerialize(property, value) {
|
||||
return !this.shouldSkip(exports.Stage.Serialize, property, value);
|
||||
}
|
||||
shouldDeserialize(property, value) {
|
||||
return !this.shouldSkip(exports.Stage.Deserialize, property, value);
|
||||
}
|
||||
defaultFor(property) {
|
||||
const options = this.properties.get(property);
|
||||
if (options != null && (0, utils_1.isFunction)(options.default)) {
|
||||
return options.default();
|
||||
}
|
||||
else if ((0, utils_1.isFunction)(this.container.default)) {
|
||||
return this.container.default();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.SerdeOptions = SerdeOptions;
|
6
dist/registry.d.ts
vendored
6
dist/registry.d.ts
vendored
|
@ -2,10 +2,10 @@ import { Deserialize } from './de';
|
|||
import { Serialize } from './ser';
|
||||
export declare class Registry {
|
||||
serializers: Map<Function, Serialize<any>>;
|
||||
deserializers: Map<Function, Deserialize>;
|
||||
deserializers: Map<Function, Deserialize<any>>;
|
||||
registerSerializer<T>(ctor: Function, serialize: Serialize<T>): void;
|
||||
registerDeserializer(ctor: Function, deserialize: Deserialize): void;
|
||||
registerDeserializer<T>(ctor: Function, deserialize: Deserialize<T>): void;
|
||||
}
|
||||
export declare const GlobalRegistry: Registry;
|
||||
export declare const registerSerializer: <T>(ctor: Function, serialize: Serialize<T>) => void;
|
||||
export declare const registerDeserializer: (ctor: Function, deserialize: Deserialize) => void;
|
||||
export declare const registerDeserializer: <T>(ctor: Function, deserialize: Deserialize<T>) => void;
|
||||
|
|
2
dist/ser/impl.d.ts
vendored
2
dist/ser/impl.d.ts
vendored
|
@ -1,4 +1,4 @@
|
|||
import { SerdeOptions } from './decorator';
|
||||
import { Serializer } from './interface';
|
||||
import { Nullable } from '../utils';
|
||||
import { SerdeOptions } from '../option';
|
||||
export declare function serialize<T, V, S extends Serializer<T>>(serializer: S, value: V, optionsGetter?: (value: V) => Nullable<SerdeOptions>): T;
|
||||
|
|
5
dist/ser/impl.js
vendored
5
dist/ser/impl.js
vendored
|
@ -9,7 +9,8 @@ class UnhandledTypeError extends TypeError {
|
|||
}
|
||||
function serializeObject(serializer, obj, options) {
|
||||
for (const key in obj) {
|
||||
serializer.serializeEntry(key, obj[key]);
|
||||
const name = (options === null || options === void 0 ? void 0 : options.getSerializationPropertyName(key)) || key;
|
||||
serializer.serializeEntry(name, obj[key]);
|
||||
}
|
||||
return serializer.end();
|
||||
}
|
||||
|
@ -20,7 +21,7 @@ function serializeClass(serializer, value, options) {
|
|||
}
|
||||
const defaultGetter = (value) => {
|
||||
var _a;
|
||||
return (_a = value[Symbol.metadata]) === null || _a === void 0 ? void 0 : _a.serde;
|
||||
return (_a = value.constructor[Symbol.metadata]) === null || _a === void 0 ? void 0 : _a.serde;
|
||||
};
|
||||
function serialize(serializer, value, optionsGetter = defaultGetter) {
|
||||
switch (typeof value) {
|
||||
|
|
1
dist/utils.d.ts
vendored
1
dist/utils.d.ts
vendored
|
@ -6,7 +6,6 @@ export type Primitive = string | number | boolean | symbol | bigint | null | und
|
|||
export interface ToString {
|
||||
toString(): string;
|
||||
}
|
||||
export declare function staticImplements<T>(): <U extends T>(constructor: U) => void;
|
||||
export declare function isPlainObject(value: any): boolean;
|
||||
export declare function isFunction(value: any): value is Function;
|
||||
export declare function isIterable(value: any): value is Iterable<any>;
|
||||
|
|
4
dist/utils.js
vendored
4
dist/utils.js
vendored
|
@ -1,15 +1,11 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.IterResult = void 0;
|
||||
exports.staticImplements = staticImplements;
|
||||
exports.isPlainObject = isPlainObject;
|
||||
exports.isFunction = isFunction;
|
||||
exports.isIterable = isIterable;
|
||||
exports.isString = isString;
|
||||
exports.isNumber = isNumber;
|
||||
function staticImplements() {
|
||||
return (constructor) => { constructor; };
|
||||
}
|
||||
function isPlainObject(value) {
|
||||
return Object.getPrototypeOf(value) === Object.prototype;
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@ import { IterResult } from '../utils'
|
|||
import { Deserialize, IDeserializer, IterableAccess, IVisitor, MapAccess } from './interface'
|
||||
|
||||
export class ForwardMapAccess extends MapAccess {
|
||||
private readonly keys: string[]
|
||||
private readonly values: any[]
|
||||
private readonly _keys: string[]
|
||||
private readonly _values: any[]
|
||||
|
||||
private kindex: number = 0
|
||||
private vindex: number = 0
|
||||
|
||||
constructor(keys: string[], values: any[]) {
|
||||
super()
|
||||
this.keys = keys
|
||||
this.values = values
|
||||
this._keys = keys
|
||||
this._values = values
|
||||
}
|
||||
|
||||
static fromObject(obj: object): ForwardMapAccess {
|
||||
|
@ -21,17 +21,17 @@ export class ForwardMapAccess extends MapAccess {
|
|||
)
|
||||
}
|
||||
|
||||
nextKeySeed<T, K extends Deserialize>(_seed: K): IteratorResult<T> {
|
||||
nextKeySeed<T, K extends Deserialize<T>>(_seed: K): IteratorResult<T> {
|
||||
return this.nextKey()
|
||||
}
|
||||
|
||||
nextValueSeed<T, V extends Deserialize>(_seed: V): IteratorResult<T> {
|
||||
nextValueSeed<T, V extends Deserialize<T>>(_seed: V): IteratorResult<T> {
|
||||
return this.nextValue()
|
||||
}
|
||||
|
||||
nextKey<T>(): IteratorResult<T> {
|
||||
if (this.kindex < this.keys.length) {
|
||||
return IterResult.Next(this.keys[this.kindex++]) as IteratorResult<T>
|
||||
return IterResult.Next(this._keys[this.kindex++]) as IteratorResult<T>
|
||||
} else {
|
||||
return IterResult.Done()
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ export class ForwardMapAccess extends MapAccess {
|
|||
|
||||
nextValue<V>(): IteratorResult<V> {
|
||||
if (this.vindex < this.values.length) {
|
||||
return IterResult.Next(this.values[this.vindex++]) as IteratorResult<V>
|
||||
return IterResult.Next(this._values[this.vindex++]) as IteratorResult<V>
|
||||
} else {
|
||||
return IterResult.Done()
|
||||
}
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
import { IDeserializer, IIterableAccess, IMapAccess, IVisitor } from './interface'
|
||||
import { SerdeOptions } from '../option'
|
||||
import { isFunction, isString, IterResult, Nullable } from '../utils'
|
||||
import { Deserialize, IDeserializer, IIterableAccess, IMapAccess, IVisitor } from './interface'
|
||||
|
||||
export class GenericSeed<T> {
|
||||
readonly visitor: IVisitor<T>
|
||||
|
||||
constructor(visitor: IVisitor<T> = new GenericVisitor()) {
|
||||
constructor(visitor: IVisitor<T> = new ProxyVisitor()) {
|
||||
this.visitor = visitor
|
||||
}
|
||||
|
||||
static deserialize<T, D extends IDeserializer>(deserializer: D, visitor: IVisitor<T> = new GenericVisitor()): T {
|
||||
static deserialize<T, D extends IDeserializer>(deserializer: D, visitor: IVisitor<T> = new ProxyVisitor()): T {
|
||||
return deserializer.deserializeAny(visitor)
|
||||
}
|
||||
|
||||
|
@ -16,36 +18,150 @@ export class GenericSeed<T> {
|
|||
}
|
||||
}
|
||||
|
||||
export class GenericVisitor<T> implements IVisitor<T> {
|
||||
class ProxyMapAccess implements IMapAccess {
|
||||
private access!: IMapAccess
|
||||
private options?: SerdeOptions
|
||||
|
||||
constructor(access: IMapAccess, options?: SerdeOptions) {
|
||||
if (access instanceof ProxyMapAccess) {
|
||||
return this
|
||||
}
|
||||
|
||||
this.access = access
|
||||
this.options = options
|
||||
}
|
||||
|
||||
private wrapResponse<T, I extends IteratorResult<T> = IteratorResult<T>>(result: I): I {
|
||||
if (result.done) {
|
||||
return result
|
||||
} else if (isString(result.value)) {
|
||||
const key = this.options?.getDeserializationPropertyName(result.value) ?? result.value
|
||||
return IterResult.Next(key) as I
|
||||
} else if (Array.isArray(result.value)) {
|
||||
const [alias, value] = result.value
|
||||
const key = this.options?.getDeserializationPropertyName(alias) ?? alias
|
||||
return IterResult.Next([
|
||||
key,
|
||||
value
|
||||
]) as I
|
||||
} else {
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T> {
|
||||
return this.wrapResponse<T>(this.access.nextKeySeed(seed))
|
||||
}
|
||||
|
||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T> {
|
||||
return this.access.nextValueSeed(seed)
|
||||
}
|
||||
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]> {
|
||||
return this.wrapResponse<[TK, TV]>(this.access.nextEntrySeed(kseed, vseed))
|
||||
}
|
||||
|
||||
nextKey<T>(): IteratorResult<T> {
|
||||
return this.wrapResponse<T>(this.access.nextKey())
|
||||
}
|
||||
|
||||
nextValue<V>(): IteratorResult<V> {
|
||||
return this.access.nextValue()
|
||||
}
|
||||
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]> {
|
||||
return this.wrapResponse<[K, V]>(this.access.nextEntry())
|
||||
}
|
||||
|
||||
sizeHint?(): Nullable<number> {
|
||||
return this.access.sizeHint?.()
|
||||
}
|
||||
|
||||
private *generate<T>(next: () => IteratorResult<T>): Iterator<T> {
|
||||
let item: IteratorResult<T>
|
||||
|
||||
while ((item = next()) && !item.done) {
|
||||
yield item.value
|
||||
}
|
||||
}
|
||||
|
||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed) as any
|
||||
)
|
||||
}
|
||||
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed) as any
|
||||
)
|
||||
}
|
||||
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]> {
|
||||
return this.generate(
|
||||
kseed == null || vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, kseed, vseed) as any
|
||||
)
|
||||
}
|
||||
|
||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]> {
|
||||
return this.entries() as Iterator<[K, V]>
|
||||
}
|
||||
}
|
||||
|
||||
export class ProxyVisitor<T> implements IVisitor<T> {
|
||||
private overrides?: Partial<IVisitor<T>>
|
||||
private options?: SerdeOptions
|
||||
|
||||
constructor(overrides?: Partial<IVisitor<T>>, options?: SerdeOptions) {
|
||||
if (overrides instanceof ProxyVisitor) {
|
||||
return overrides
|
||||
}
|
||||
|
||||
this.overrides = overrides
|
||||
this.options = options
|
||||
}
|
||||
|
||||
visitBoolean(value: boolean): T {
|
||||
return value as T
|
||||
return this.overrides?.visitBoolean?.(value) ?? value as T
|
||||
}
|
||||
|
||||
visitNumber(value: number): T {
|
||||
return value as T
|
||||
return this.overrides?.visitNumber?.(value) ?? value as T
|
||||
}
|
||||
|
||||
visitBigInt(value: bigint): T {
|
||||
return value as T
|
||||
return this.overrides?.visitBigInt?.(value) ?? value as T
|
||||
}
|
||||
|
||||
visitString(value: string): T {
|
||||
return value as T
|
||||
return this.overrides?.visitString?.(value) ?? value as T
|
||||
}
|
||||
|
||||
visitSymbol(value: symbol): T {
|
||||
return value as T
|
||||
return this.overrides?.visitSymbol?.(value) ?? value as T
|
||||
}
|
||||
|
||||
visitNull(): T {
|
||||
return null as T
|
||||
return this.overrides?.visitNull?.() ?? null as T
|
||||
}
|
||||
|
||||
visitObject(access: IMapAccess): T {
|
||||
const proxy = new ProxyMapAccess(access, this.options)
|
||||
|
||||
if (isFunction(this.overrides?.visitObject)) {
|
||||
return this.overrides?.visitObject(proxy)
|
||||
}
|
||||
|
||||
const result = []
|
||||
let entry
|
||||
|
||||
while ((entry = access.nextEntry()) && !entry.done) {
|
||||
while ((entry = proxy.nextEntry()) && !entry.done) {
|
||||
result.push(entry.value)
|
||||
}
|
||||
|
||||
|
@ -53,6 +169,10 @@ export class GenericVisitor<T> implements IVisitor<T> {
|
|||
}
|
||||
|
||||
visitIterable(access: IIterableAccess): T {
|
||||
if (isFunction(this.overrides?.visitIterable)) {
|
||||
return this.overrides?.visitIterable(access)
|
||||
}
|
||||
|
||||
const result = []
|
||||
let element
|
||||
|
||||
|
@ -64,5 +184,53 @@ export class GenericVisitor<T> implements IVisitor<T> {
|
|||
}
|
||||
}
|
||||
|
||||
export class ProxyDeserializer implements IDeserializer {
|
||||
private readonly deserializer: IDeserializer
|
||||
private readonly options?: SerdeOptions
|
||||
|
||||
constructor(deserializer: IDeserializer, options?: SerdeOptions) {
|
||||
this.deserializer = deserializer
|
||||
this.options = options
|
||||
}
|
||||
|
||||
deserializeAny<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeAny(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeBoolean(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeNumber(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeBigInt(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeString(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeSymbol(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeNull(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeObject(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeIterable(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
|
||||
deserializeFunction<T, V extends IVisitor<T>>(visitor: V): T {
|
||||
return this.deserializer.deserializeFunction(new ProxyVisitor(visitor, this.options))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import { GlobalRegistry, Registry } from '../registry'
|
||||
import { Constructor } from '../utils'
|
||||
import { ProxyDeserializer } from './generic'
|
||||
import { IDeserializer } from './interface'
|
||||
|
||||
export function deserialize<T, D extends IDeserializer>(deserializer: D, into: Constructor<T>, registry: Registry = GlobalRegistry): T {
|
||||
|
@ -8,7 +9,7 @@ export function deserialize<T, D extends IDeserializer>(deserializer: D, into: C
|
|||
if (de == null) {
|
||||
throw new ReferenceError(`No deserializer for ${into.name}`)
|
||||
} else {
|
||||
return de(deserializer)
|
||||
return de(new ProxyDeserializer(deserializer, (into as any)?.[Symbol.metadata]?.serde))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,20 +1,24 @@
|
|||
import { IterResult, Nullable } from "../utils"
|
||||
import { IterResult, Nullable } from '../utils'
|
||||
|
||||
export interface IMapAccess {
|
||||
nextKeySeed<T, K extends Deserialize>(seed: K): IteratorResult<T>
|
||||
nextValueSeed<T, V extends Deserialize>(seed: V): IteratorResult<T>
|
||||
nextEntrySeed<TK, TV, K extends Deserialize, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]>
|
||||
nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
||||
nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
||||
nextEntrySeed<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): IteratorResult<[TK, TV]>
|
||||
nextKey<T>(): IteratorResult<T>
|
||||
nextValue<V>(): IteratorResult<V>
|
||||
nextEntry<K, V>(): IteratorResult<[K, V]>
|
||||
sizeHint?(): Nullable<number>
|
||||
entries<T, K extends Deserialize<T>>(seed?: K): Iterator<T>
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T>
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed: K, vseed: V): Iterator<[TK, TV]>
|
||||
[Symbol.iterator]<K, V>(): Iterator<[K, V]>
|
||||
}
|
||||
|
||||
export abstract class MapAccess {
|
||||
abstract nextKeySeed<T, K extends Deserialize>(seed: K): IteratorResult<T>
|
||||
abstract nextValueSeed<T, V extends Deserialize>(seed: V): IteratorResult<T>
|
||||
abstract nextKeySeed<T, K extends Deserialize<T>>(seed: K): IteratorResult<T>
|
||||
abstract nextValueSeed<T, V extends Deserialize<T>>(seed: V): IteratorResult<T>
|
||||
|
||||
nextEntrySeed<TK, TV, K extends Deserialize, V extends Deserialize>(kseed: K, vseed: V): IteratorResult<[TK, TV]> {
|
||||
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) {
|
||||
|
@ -44,6 +48,43 @@ export abstract class MapAccess {
|
|||
|
||||
return IterResult.Done()
|
||||
}
|
||||
|
||||
private *generate<T>(next: () => IteratorResult<T>): Iterator<T> {
|
||||
let item
|
||||
|
||||
while ((item = next())) {
|
||||
yield item.value
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
keys<T, K extends Deserialize<T>>(seed?: K): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextKey.bind(this) :
|
||||
this.nextKeySeed.bind(this, seed) as any
|
||||
)
|
||||
}
|
||||
|
||||
values<T, V extends Deserialize<T>>(seed?: V): Iterator<T> {
|
||||
return this.generate(
|
||||
seed == null ?
|
||||
this.nextValue.bind(this) :
|
||||
this.nextValueSeed.bind(this, seed) as any
|
||||
)
|
||||
}
|
||||
|
||||
entries<TK, TV, K extends Deserialize<TK>, V extends Deserialize<TV>>(kseed?: K, vseed?: V): Iterator<[TK, TV]> {
|
||||
return this.generate(
|
||||
kseed == null || vseed == null ?
|
||||
this.nextEntry.bind(this) :
|
||||
this.nextEntrySeed.bind(this, kseed, vseed) as any
|
||||
)
|
||||
}
|
||||
|
||||
[Symbol.iterator]<K, V>(): Iterator<K, V> {
|
||||
return this.entries() as Iterator<K, V>
|
||||
}
|
||||
}
|
||||
|
||||
export interface IIterableAccess {
|
||||
|
@ -67,19 +108,19 @@ export interface IVisitor<T> {
|
|||
}
|
||||
|
||||
export interface IDeserializer {
|
||||
deserializeAny<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeBoolean<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeNumber<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeBigInt<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeString<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeSymbol<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeNull<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeObject<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeIterable<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeFunction<T, V extends IVisitor<T>>(visitor: V): T
|
||||
deserializeAny<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeBoolean<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeNumber<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeBigInt<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeString<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeSymbol<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeNull<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeObject<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeIterable<T>(visitor: Partial<IVisitor<T>>): T
|
||||
deserializeFunction<T>(visitor: Partial<IVisitor<T>>): T
|
||||
}
|
||||
|
||||
export interface Deserialize {
|
||||
<T>(deserializer: IDeserializer): T
|
||||
export interface Deserialize<T> {
|
||||
(deserializer: IDeserializer): T
|
||||
}
|
||||
|
||||
|
|
44
src/decorator.ts
Normal file
44
src/decorator.ts
Normal file
|
@ -0,0 +1,44 @@
|
|||
import { ContainerOptions, PropertyOptions, SerdeOptions } from './option'
|
||||
import { Nullable } from './utils'
|
||||
|
||||
const ContextKind = Object.freeze({
|
||||
Class: 'class',
|
||||
Method: 'method',
|
||||
Getter: 'getter',
|
||||
Setter: 'setter',
|
||||
Field: 'field',
|
||||
Accessor: 'accessor'
|
||||
} as const)
|
||||
|
||||
function decorateClass(target: Function, context: DecoratorContext, options: ContainerOptions) {
|
||||
const serde = context.metadata.serde as Nullable<SerdeOptions>
|
||||
|
||||
context.metadata.serde = new SerdeOptions(
|
||||
target,
|
||||
options,
|
||||
serde?.properties
|
||||
)
|
||||
}
|
||||
|
||||
function decorateField(context: DecoratorContext, options: PropertyOptions) {
|
||||
const serde = (context.metadata.serde as SerdeOptions) || new SerdeOptions(undefined)
|
||||
serde.properties.set(context.name as string, options)
|
||||
context.metadata.serde = serde
|
||||
}
|
||||
|
||||
export function serde(options: ContainerOptions | PropertyOptions) {
|
||||
return function(target: any, context: DecoratorContext) {
|
||||
switch (context.kind) {
|
||||
case ContextKind.Class:
|
||||
decorateClass(target, context, options)
|
||||
break
|
||||
|
||||
case ContextKind.Field:
|
||||
decorateField(context, options)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2,6 +2,8 @@ import '@tsmetadata/polyfill'
|
|||
|
||||
export * as ser from './ser/impl'
|
||||
export * as de from './de/impl'
|
||||
export * from './decorator'
|
||||
export * from './option'
|
||||
export * from './case'
|
||||
export * from './registry'
|
||||
export * from './utils'
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
import { CaseConvention, convertCase } from '../case'
|
||||
import { Deserialize } from '../de'
|
||||
import { isFunction, isNumber, isString, Nullable } from '../utils'
|
||||
import { Serialize } from './interface'
|
||||
import { Deserialize } from './de'
|
||||
import { Serialize } from './ser'
|
||||
import { CaseConvention, convertCase } from './case'
|
||||
import { isFunction, isIterable, isNumber, isString, Nullable } from './utils'
|
||||
|
||||
export interface RenameOptions {
|
||||
serialize?: string
|
||||
|
@ -37,7 +37,7 @@ export interface PropertyOptions {
|
|||
rename?: RenameOptions | string
|
||||
skip?: SkipOptions | Predicate | boolean
|
||||
serializeWith?: Serialize<any>
|
||||
deserializeWith?: Deserialize
|
||||
deserializeWith?: Deserialize<any>
|
||||
}
|
||||
|
||||
export const Stage = Object.freeze({
|
||||
|
@ -45,14 +45,67 @@ export const Stage = Object.freeze({
|
|||
Deserialize: 1
|
||||
} as const)
|
||||
|
||||
export class PropertyMap extends Map<string, PropertyOptions> {
|
||||
private readonly options: SerdeOptions
|
||||
private readonly aliases: Map<string, string> = new Map()
|
||||
|
||||
constructor(options: SerdeOptions, iterable?: Iterable<any>) {
|
||||
super(iterable)
|
||||
this.options = options
|
||||
this.buildAliasMap()
|
||||
}
|
||||
|
||||
private setAliasesFromOptions(key: string, options: PropertyOptions) {
|
||||
this.aliases.set(key, key)
|
||||
|
||||
if (options.alias != null) {
|
||||
this.addAlias(options.alias, key)
|
||||
}
|
||||
|
||||
if (isString(options.rename)) {
|
||||
this.aliases.set(options.rename, key)
|
||||
} else if (isNumber(this.options.container.renameAll)) {
|
||||
this.aliases.set(this.options.applyCaseConvention(Stage.Deserialize, key), key)
|
||||
}
|
||||
}
|
||||
|
||||
set(key: string, value: PropertyOptions): this {
|
||||
super.set(key, value)
|
||||
this.setAliasesFromOptions(key, value)
|
||||
return this
|
||||
}
|
||||
|
||||
addAlias(alias: string | Iterable<string>, key: string) {
|
||||
if (isString(alias)) {
|
||||
this.aliases.set(alias, key)
|
||||
} else if (isIterable(alias)) {
|
||||
for (const a of alias) {
|
||||
this.addAlias(a, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getFieldFromAlias(alias: string) {
|
||||
return this.aliases.get(alias)
|
||||
}
|
||||
|
||||
private buildAliasMap() {
|
||||
for (const [key, value] of this.entries()) {
|
||||
if (value.alias != null) {
|
||||
this.addAlias(value.alias, key)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export type Stage = typeof Stage[keyof typeof Stage]
|
||||
|
||||
export class SerdeOptions {
|
||||
readonly target: Nullable<any>
|
||||
readonly container: ContainerOptions
|
||||
readonly properties: Map<string, PropertyOptions>
|
||||
readonly properties: PropertyMap
|
||||
|
||||
constructor(target: any, container: ContainerOptions = {}, properties: Map<string, PropertyOptions> = new Map()) {
|
||||
constructor(target: any, container: ContainerOptions = {}, properties: PropertyMap = new PropertyMap(this)) {
|
||||
this.target = target
|
||||
this.container = container
|
||||
this.properties = properties
|
||||
|
@ -78,45 +131,54 @@ export class SerdeOptions {
|
|||
return this.getClassName(Stage.Deserialize, defaultName)
|
||||
}
|
||||
|
||||
private applyPropertyCase(stage: Stage, property: string) {
|
||||
getCaseConvention(stage: Stage) {
|
||||
if (isNumber(this.container.renameAll)) {
|
||||
return convertCase(property, this.container.renameAll)
|
||||
if (stage === Stage.Serialize) {
|
||||
return this.container.renameAll
|
||||
} else {
|
||||
return CaseConvention.CamelCase
|
||||
}
|
||||
} else if (stage === Stage.Serialize && isNumber(this.container.renameAll?.serialize)) {
|
||||
return convertCase(property, this.container.renameAll.serialize)
|
||||
return this.container.renameAll.serialize
|
||||
} else if (stage === Stage.Deserialize && isNumber(this.container.renameAll?.deserialize)) {
|
||||
return convertCase(property, this.container.renameAll.deserialize)
|
||||
} else {
|
||||
return property
|
||||
return this.container.renameAll.deserialize
|
||||
}
|
||||
}
|
||||
|
||||
private getPropertyName(stage: Stage, property: string) {
|
||||
applyCaseConvention(stage: Stage, property: string) {
|
||||
const convention = this.getCaseConvention(stage)
|
||||
return convention != null ? convertCase(property, convention) : property
|
||||
}
|
||||
|
||||
getPropertyRename(stage: Stage, property: string) {
|
||||
const options = this.properties.get(property)
|
||||
|
||||
if (options == null) {
|
||||
return property
|
||||
return
|
||||
} else if (isString(options.rename)) {
|
||||
return options.rename
|
||||
} else if (stage == Stage.Serialize && isString(options.rename?.serialize)) {
|
||||
return options.rename.serialize
|
||||
} else if (stage == Stage.Deserialize && isString(options.rename?.deserialize)) {
|
||||
return options.rename.deserialize
|
||||
} else {
|
||||
return property
|
||||
}
|
||||
}
|
||||
|
||||
getSerializationPropertyName(property: string) {
|
||||
const name = this.getPropertyName(Stage.Serialize, property)
|
||||
return this.applyPropertyCase(Stage.Serialize, name)
|
||||
return this.getPropertyRename(Stage.Serialize, property) ||
|
||||
this.applyCaseConvention(Stage.Serialize, property)
|
||||
}
|
||||
|
||||
getNameFromAlias(alias: string) {
|
||||
return this.properties.getFieldFromAlias(alias)
|
||||
}
|
||||
|
||||
getDeserializationPropertyName(property: string) {
|
||||
const name = this.getPropertyName(Stage.Deserialize, property)
|
||||
return this.applyPropertyCase(Stage.Deserialize, name)
|
||||
return this.getNameFromAlias(property) ||
|
||||
this.applyCaseConvention(Stage.Deserialize, property)
|
||||
}
|
||||
|
||||
private shouldSkip(stage: Stage, property: string, value: any) {
|
||||
shouldSkip(stage: Stage, property: string, value: any) {
|
||||
const options = this.properties.get(property)
|
||||
if (options == null) {
|
||||
return false
|
|
@ -3,13 +3,13 @@ import { Serialize } from './ser'
|
|||
|
||||
export class Registry {
|
||||
serializers: Map<Function, Serialize<any>> = new Map()
|
||||
deserializers: Map<Function, Deserialize> = new Map()
|
||||
deserializers: Map<Function, Deserialize<any>> = new Map()
|
||||
|
||||
registerSerializer<T>(ctor: Function, serialize: Serialize<T>) {
|
||||
this.serializers.set(ctor, serialize)
|
||||
}
|
||||
|
||||
registerDeserializer(ctor: Function, deserialize: Deserialize) {
|
||||
registerDeserializer<T>(ctor: Function, deserialize: Deserialize<T>) {
|
||||
this.deserializers.set(ctor, deserialize)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { SerdeOptions } from './decorator'
|
||||
import { ISerializeObject, Serializer } from './interface'
|
||||
import { isPlainObject, Nullable } from '../utils'
|
||||
import { SerdeOptions } from '../option'
|
||||
|
||||
class UnhandledTypeError extends TypeError {
|
||||
constructor(serializer: Serializer<unknown>, value: any) {
|
||||
|
@ -10,7 +10,8 @@ class UnhandledTypeError extends TypeError {
|
|||
|
||||
function serializeObject<T, V extends object, S extends ISerializeObject<T>>(serializer: S, obj: V, options?: SerdeOptions): T {
|
||||
for (const key in obj) {
|
||||
serializer.serializeEntry(key, obj[key])
|
||||
const name = options?.getSerializationPropertyName(key) || key
|
||||
serializer.serializeEntry(name, obj[key])
|
||||
}
|
||||
|
||||
return serializer.end()
|
||||
|
@ -23,7 +24,7 @@ function serializeClass<T, V extends object, S extends Serializer<T>>(serializer
|
|||
}
|
||||
|
||||
const defaultGetter = (value: any): Nullable<SerdeOptions> => {
|
||||
return value[Symbol.metadata]?.serde
|
||||
return value.constructor[Symbol.metadata]?.serde
|
||||
}
|
||||
|
||||
export function serialize<T, V, S extends Serializer<T>>(serializer: S, value: V, optionsGetter: (value: V) => Nullable<SerdeOptions> = defaultGetter): T {
|
||||
|
|
|
@ -10,10 +10,6 @@ export interface ToString {
|
|||
toString(): string
|
||||
}
|
||||
|
||||
export function staticImplements<T>() {
|
||||
return <U extends T>(constructor: U) => { constructor }
|
||||
}
|
||||
|
||||
export function isPlainObject(value: any): boolean {
|
||||
return Object.getPrototypeOf(value) === Object.prototype
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue