jasone 1.0.0-beta.0 → 1.0.0-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +36 -33
  2. package/index.js +1 -1
  3. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -18,34 +18,37 @@ type NonJsonType = {
18
18
  symbol: symbol;
19
19
  undefined: undefined;
20
20
  };
21
- type EncodeFilter<TType> = {
21
+ type Context = Record<string, unknown>;
22
+ type EncodeFilter<TType, TContext extends Context = Context> = {
22
23
  class?: ClassLike<TType>;
23
- any?: (value: unknown) => boolean;
24
- } & { [Key in keyof NonJsonType]?: ((value: NonJsonType[Key]) => boolean) | boolean };
25
- type EncodeHandler<TType, TJson extends JsonValue> = (ctx: EncodeContext<TType>) => EncodeResult<TJson>;
26
- type EncodeContext<TType> = {
24
+ any?: (options: EncodeOptions<unknown, TContext>) => boolean;
25
+ } & { [Key in keyof NonJsonType]?: ((options: EncodeOptions<NonJsonType[Key], TContext>) => boolean) | boolean };
26
+ type EncodeHandler<TType, TJson extends JsonValue, TContext extends Context = Context> = (ctx: EncodeOptions<TType, TContext>) => EncodeResult<TJson>;
27
+ type EncodeOptions<TType, TContext extends Context = Context> = {
27
28
  value: TType;
28
29
  jasone: Jasone;
30
+ context: TContext;
29
31
  };
30
32
  type EncodeResult<TJson extends JsonValue> = TJson extends Record<string, JsonValue> ? [TypeId, TJson] | [null, JsonValue] : [null, JsonValue];
31
- type Encoder<TType = unknown, TJson extends JsonValue = JsonValue> = {
32
- filter?: EncodeFilter<TType> | EncodeFilter<TType>[];
33
- handler: EncodeHandler<TType, TJson>;
33
+ type Encoder<TType = unknown, TJson extends JsonValue = JsonValue, TContext extends Context = Context> = {
34
+ filter?: EncodeFilter<TType, TContext> | EncodeFilter<TType, TContext>[];
35
+ handler: EncodeHandler<TType, TJson, TContext>;
34
36
  };
35
- type DecodeFilter = TypeId | ((typeId: TypeId, value: Record<string, JsonValue>) => boolean);
36
- type DecodeContext<TJson extends Record<string, JsonValue>> = {
37
+ type DecodeFilter<TContext extends Context = Context> = TypeId | ((options: DecodeOptions<Record<string, JsonValue>, TContext>) => boolean);
38
+ type DecodeOptions<TJson extends Record<string, JsonValue>, TContext extends Context = Context> = {
37
39
  value: TJson;
38
40
  typeId: TypeId;
39
41
  jasone: Jasone;
42
+ context: TContext;
40
43
  };
41
- type DecodeHandler<TType, TJson extends Record<string, JsonValue>> = (ctx: DecodeContext<TJson>) => TType;
42
- type Decoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = {
43
- filter?: DecodeFilter | DecodeFilter[];
44
- handler: DecodeHandler<TType, TJson>;
44
+ type DecodeHandler<TType, TJson extends Record<string, JsonValue>, TContext extends Context = Context> = (ctx: DecodeOptions<TJson, TContext>) => TType;
45
+ type Decoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>, TContext extends Context = Context> = {
46
+ filter?: DecodeFilter<TContext> | DecodeFilter<TContext>[];
47
+ handler: DecodeHandler<TType, TJson, TContext>;
45
48
  };
46
- type Transformer<TType = unknown, TJson extends JsonValue = JsonValue> = {
47
- encoder?: Encoder<TType, TJson>;
48
- decoder?: TJson extends Record<string, JsonValue> ? Decoder<TType, TJson> : never;
49
+ type Transformer<TType = unknown, TJson extends JsonValue = JsonValue, TContext extends Context = Context> = {
50
+ encoder?: Encoder<TType, TJson, TContext>;
51
+ decoder?: TJson extends Record<string, JsonValue> ? Decoder<TType, TJson, TContext> : never;
49
52
  };
50
53
  //#endregion
51
54
  //#region src/jasone.d.ts
@@ -74,7 +77,7 @@ type JasoneOptions = {
74
77
  * const jasone = new Jasone({ types: [myCustomTransformer] });
75
78
  * ```
76
79
  */
77
- types?: Transformer<any, any>[];
80
+ types?: Transformer<any, any, any>[];
78
81
  };
79
82
  /**
80
83
  * Jasone is a JSON encoder and decoder that can handle custom types.
@@ -114,29 +117,29 @@ declare class Jasone {
114
117
  *
115
118
  * @param type The type to register.
116
119
  */
117
- register<TType, TJson extends JsonValue>(transformer: Transformer<TType, TJson>): void;
120
+ register<TType, TJson extends JsonValue, TContext extends Context = Context>(transformer: Transformer<TType, TJson, TContext>): void;
118
121
  /**
119
122
  * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
120
123
  *
121
124
  * @param value The value to encode.
122
125
  * @returns A JSON-compatible Jasone encoded value.
123
126
  */
124
- encode(value: unknown): JsonValue;
127
+ encode(value: unknown, context?: Context): JsonValue;
125
128
  /**
126
129
  * Decode an Jasone encoded value to its decoded value.
127
130
  *
128
131
  * @param value The Jasone encoded value to decode.
129
132
  * @returns The decoded value.
130
133
  */
131
- decode<T = unknown>(value: JsonValue): T;
134
+ decode<T = unknown>(value: JsonValue, context?: Context): T;
132
135
  /**
133
136
  * Alias for `encode`.
134
137
  */
135
- serialize(value: unknown): JsonValue;
138
+ serialize(value: unknown, context?: Context): JsonValue;
136
139
  /**
137
140
  * Alias for `decode`.
138
141
  */
139
- deserialize<T = unknown>(value: JsonValue): T;
142
+ deserialize<T = unknown>(value: JsonValue, context?: Context): T;
140
143
  /**
141
144
  * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
142
145
  *
@@ -146,7 +149,7 @@ declare class Jasone {
146
149
  * JSON.stringify(this.encode(value));
147
150
  * ```
148
151
  */
149
- stringify(value: unknown): string;
152
+ stringify(value: unknown, context?: Context): string;
150
153
  /**
151
154
  * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
152
155
  *
@@ -156,7 +159,7 @@ declare class Jasone {
156
159
  * this.decode(JSON.parse(value));
157
160
  * ```
158
161
  */
159
- parse<T = unknown>(value: string): T;
162
+ parse<T = unknown>(value: string, context?: Context): T;
160
163
  /**
161
164
  * The default Jasone instance with the default types already registered.
162
165
  */
@@ -172,22 +175,22 @@ declare class Jasone {
172
175
  * @param value The value to encode.
173
176
  * @returns A JSON-compatible Jasone encoded value.
174
177
  */
175
- static encode: (value: unknown) => JsonValue;
178
+ static encode: (value: unknown, context?: Context) => JsonValue;
176
179
  /**
177
180
  * Alias for `encode`.
178
181
  */
179
- static serialize: (value: unknown) => JsonValue;
182
+ static serialize: (value: unknown, context?: Context) => JsonValue;
180
183
  /**
181
184
  * Decode an Jasone encoded value to its decoded value.
182
185
  *
183
186
  * @param value The Jasone encoded value to decode.
184
187
  * @returns The decoded value.
185
188
  */
186
- static decode: <T = unknown>(value: JsonValue) => T;
189
+ static decode: <T = unknown>(value: JsonValue, context?: Context) => T;
187
190
  /**
188
191
  * Alias for `decode`.
189
192
  */
190
- static deserialize: <T = unknown>(value: JsonValue) => T;
193
+ static deserialize: <T = unknown>(value: JsonValue, context?: Context) => T;
191
194
  /**
192
195
  * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
193
196
  *
@@ -197,7 +200,7 @@ declare class Jasone {
197
200
  * JSON.stringify(Jasone.encode(value));
198
201
  * ```
199
202
  */
200
- static stringify: (value: unknown) => string;
203
+ static stringify: (value: unknown, context?: Context) => string;
201
204
  /**
202
205
  * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
203
206
  *
@@ -207,13 +210,13 @@ declare class Jasone {
207
210
  * Jasone.decode(JSON.parse(value));
208
211
  * ```
209
212
  */
210
- static parse: <T = unknown>(value: string) => T;
213
+ static parse: <T = unknown>(value: string, context?: Context) => T;
211
214
  /**
212
215
  * Register a new type to this Jasone instance.
213
216
  *
214
217
  * @param type The type to register.
215
218
  */
216
- static register: <TType, TJson extends JsonValue>(transformer: Transformer<TType, TJson>) => void;
219
+ static register: <TType, TJson extends JsonValue, TContext extends Context = Context>(transformer: Transformer<TType, TJson, TContext>) => void;
217
220
  }
218
221
  //#endregion
219
222
  //#region src/transformers/bigint.d.ts
@@ -256,4 +259,4 @@ declare const urlTransformer: Transformer<URL, {
256
259
  */
257
260
  declare const defaultTransformers: Transformer[];
258
261
  //#endregion
259
- export { ClassLike, DecodeContext, DecodeFilter, DecodeHandler, Decoder, EncodeContext, EncodeFilter, EncodeHandler, EncodeResult, Encoder, Jasone, JasoneOptions, JsonValue, NonJsonType, Transformer, TypeId, type bigIntTransformer, type dateTransformer, defaultTransformers, type mapTransformer, nonJsonTypes, type regExpTransformer, type setTransformer, type undefinedTransformer, type urlTransformer };
262
+ export { ClassLike, Context, DecodeFilter, DecodeHandler, DecodeOptions, Decoder, EncodeFilter, EncodeHandler, EncodeOptions, EncodeResult, Encoder, Jasone, JasoneOptions, JsonValue, NonJsonType, Transformer, TypeId, type bigIntTransformer, type dateTransformer, defaultTransformers, type mapTransformer, nonJsonTypes, type regExpTransformer, type setTransformer, type undefinedTransformer, type urlTransformer };
package/index.js CHANGED
@@ -1 +1 @@
1
- var JasoneError=class extends Error{},UnknownTypeIdError=class extends JasoneError{constructor(typeId,value){super(`Unknown type id: ${typeId}`,{cause:value})}},NonJsonValueError=class extends JasoneError{constructor(value){super(`Non-JSON value received`,{cause:value})}},IllegalEncoderResultError=class extends JasoneError{constructor(value){super(`Illegal encoder result received: The encoder result cannot contains the type identifer.`,{cause:value})}},UnhandledValueError=class extends JasoneError{constructor(value){super(`Unhandled value received: No encoder found for this value.`,{cause:value})}},DuplicatedTypeIdError=class extends JasoneError{constructor(typeId,decoder){super(`Duplicated type id: The TypeId<${JSON.stringify(typeId)}> is already registered.`,{cause:decoder})}};let TypeIdRegistry=function(TypeIdRegistry$1){return TypeIdRegistry$1[TypeIdRegistry$1.Undefined=0]=`Undefined`,TypeIdRegistry$1[TypeIdRegistry$1.Date=1]=`Date`,TypeIdRegistry$1[TypeIdRegistry$1.BigInt=2]=`BigInt`,TypeIdRegistry$1[TypeIdRegistry$1.RegExp=3]=`RegExp`,TypeIdRegistry$1[TypeIdRegistry$1.Set=4]=`Set`,TypeIdRegistry$1[TypeIdRegistry$1.Map=5]=`Map`,TypeIdRegistry$1[TypeIdRegistry$1.URL=6]=`URL`,TypeIdRegistry$1}({});const bigIntTransformer={encoder:{filter:{bigint:!0},handler:({value})=>[TypeIdRegistry.BigInt,{bigint:value.toString()}]},decoder:{filter:TypeIdRegistry.BigInt,handler:({value})=>BigInt(value.bigint)}},dateTransformer={encoder:{filter:{class:Date,object:obj=>obj instanceof Date},handler:({value})=>[TypeIdRegistry.Date,{iso:value.toISOString()}]},decoder:{filter:TypeIdRegistry.Date,handler:({value})=>new Date(value.iso)}},mapTransformer={encoder:{filter:{class:Map,object:obj=>obj instanceof Map},handler:({value,jasone})=>[TypeIdRegistry.Map,{entries:value.entries().map(([key,val])=>[jasone.encode(key),jasone.encode(val)]).toArray()}]},decoder:{filter:TypeIdRegistry.Map,handler:({value,jasone})=>new Map(value.entries.map(([key,val])=>[jasone.decode(key),jasone.decode(val)]))}},regExpTransformer={encoder:{filter:{class:RegExp,object:obj=>obj instanceof RegExp},handler:({value})=>[TypeIdRegistry.RegExp,{source:value.source,flags:value.flags}]},decoder:{filter:TypeIdRegistry.RegExp,handler:({value})=>new RegExp(value.source,value.flags)}},setTransformer={encoder:{filter:{class:Set,object:obj=>obj instanceof Set},handler:({value,jasone})=>[TypeIdRegistry.Set,{values:value.values().map(entry=>jasone.encode(entry)).toArray()}]},decoder:{filter:TypeIdRegistry.Set,handler:({value,jasone})=>new Set(value.values.map(entry=>jasone.decode(entry)))}},undefinedTransformer={encoder:{filter:{undefined:!0},handler:()=>[TypeIdRegistry.Undefined,{}]},decoder:{filter:TypeIdRegistry.Undefined,handler:()=>void 0}},urlTransformer={encoder:{filter:{class:URL,object:obj=>obj instanceof URL},handler:({value})=>[TypeIdRegistry.URL,{url:value.toString()}]},decoder:{filter:TypeIdRegistry.URL,handler:({value})=>new URL(value.url)}},defaultTransformers=[undefinedTransformer,dateTransformer,bigIntTransformer,regExpTransformer,setTransformer,mapTransformer,urlTransformer],nonJsonTypes=[`bigint`,`function`,`object`,`symbol`,`undefined`],matchEncoderFilters=(filterInput,value)=>{if(!filterInput)return!0;let filters=Array.isArray(filterInput)?filterInput:[filterInput],type=typeof value;for(let filter of filters){if(filter.any?.(value)||type===`object`&&value!==null&&filter.class===value.constructor)return!0;for(let field of nonJsonTypes){if(type!==field)continue;let typeFilter=filter[field];if(typeFilter===!0||typeFilter?.(value))return!0}}return!1},matchDecoderFilters=(filterInput,value,typeId)=>{if(filterInput===void 0)return!0;let filters=Array.isArray(filterInput)?filterInput:[filterInput];for(let filter of filters)if(typeof filter==`function`&&filter(typeId,value)||filter===typeId)return!0;return!1};var Jasone=class Jasone{#typeIdentifier;#anyDecoder=[];#typeIdDecoder=new Map;#anyEncoder=[];#classEncoder=new Map;#customEncoder={bigint:[],function:[],object:[],symbol:[],undefined:[]};constructor(options={}){this.#typeIdentifier=options.typeIdentifier??`$`;for(let transformer of options.types??[])this.register(transformer)}#registerEncoder(encoder){let filters=encoder.filter?Array.isArray(encoder.filter)?encoder.filter:[encoder.filter]:[];filters.length===0&&this.#anyEncoder.push(encoder);for(let filter of filters){if(filter.any&&this.#anyEncoder.push(encoder),filter.class){let classList=this.#classEncoder.get(filter.class);classList||(classList=[],this.#classEncoder.set(filter.class,classList)),classList.push(encoder)}for(let field of Object.keys(filter))nonJsonTypes.includes(field)&&filter[field]&&this.#customEncoder[field].push(encoder)}}#registerDecoder(decoder){let filters=decoder.filter?Array.isArray(decoder.filter)?decoder.filter:[decoder.filter]:[];filters.length===0&&this.#anyDecoder.push(decoder);for(let filter of filters){if(typeof filter==`function`){this.#anyDecoder.push(decoder);continue}if(this.#typeIdDecoder.has(filter))throw new DuplicatedTypeIdError(filter,decoder);this.#typeIdDecoder.set(filter,decoder)}}register(transformer){transformer.encoder&&this.#registerEncoder(transformer.encoder),transformer.decoder&&this.#registerDecoder(transformer.decoder)}encode(value){let type=typeof value;switch(type){case`boolean`:case`number`:case`string`:return value;case`object`:if(value===null)return null;if(Array.isArray(value))return value.map(entry=>this.encode(entry));if(Object.getPrototypeOf(value)===Object.prototype){let encodedObject=Object.fromEntries(Object.entries(value).map(([key,inner])=>[key,this.encode(inner)]));return this.#typeIdentifier in encodedObject&&(encodedObject[this.#typeIdentifier]=[encodedObject[this.#typeIdentifier]]),encodedObject}}let encoder;if(type===`object`&&(encoder??=this.#classEncoder.get(value.constructor)?.find(inner=>matchEncoderFilters(inner.filter,value))),encoder??=this.#customEncoder[type].find(inner=>matchEncoderFilters(inner.filter,value)),encoder??=this.#anyEncoder.find(inner=>matchEncoderFilters(inner.filter,value)),!encoder)throw new UnhandledValueError(value);let[typeId,result]=encoder.handler({value,jasone:this});if(typeId!==null&&this.#typeIdentifier in result)throw new IllegalEncoderResultError(result);return typeId===null?result:{[this.#typeIdentifier]:typeId,...result}}decode(value){return this.#decode(value)}#decode(value,ignoreTypeIdentifier=!1){switch(typeof value){case`boolean`:case`number`:case`string`:return value;case`object`:if(value===null)return null;if(Array.isArray(value))return value.map(inner=>this.#decode(inner));if(this.#typeIdentifier in value&&!Array.isArray(value)&&!ignoreTypeIdentifier){let typeId=value[this.#typeIdentifier];if(Array.isArray(typeId)){let[escaped]=typeId,cloned={...value};return cloned[this.#typeIdentifier]=escaped,this.#decode(cloned,!0)}let decoder;if(decoder??=this.#typeIdDecoder.get(typeId),decoder??=this.#anyDecoder.find(entry=>matchDecoderFilters(entry.filter,value,typeId)),!decoder)throw new UnknownTypeIdError(typeId,value);return decoder.handler({typeId,value,jasone:this})}if(Object.getPrototypeOf(value)===Object.prototype)return Object.fromEntries(Object.entries(value).map(([key,inner])=>[key,this.#decode(inner)]));break}throw new NonJsonValueError(value)}serialize(value){return this.encode(value)}deserialize(value){return this.decode(value)}stringify(value){return JSON.stringify(this.encode(value))}parse(value){return this.decode(JSON.parse(value))}static default=new Jasone({types:defaultTransformers});static encode=Jasone.default.encode.bind(Jasone.default);static serialize=Jasone.default.serialize.bind(Jasone.default);static decode=Jasone.default.decode.bind(Jasone.default);static deserialize=Jasone.default.deserialize.bind(Jasone.default);static stringify=Jasone.default.stringify.bind(Jasone.default);static parse=Jasone.default.parse.bind(Jasone.default);static register=Jasone.default.register.bind(Jasone.default)};export{Jasone,defaultTransformers,nonJsonTypes};
1
+ var JasoneError=class extends Error{},UnknownTypeIdError=class extends JasoneError{constructor(typeId,value){super(`Unknown type id: ${typeId}`,{cause:value})}},NonJsonValueError=class extends JasoneError{constructor(value){super(`Non-JSON value received`,{cause:value})}},IllegalEncoderResultError=class extends JasoneError{constructor(value){super(`Illegal encoder result received: The encoder result cannot contains the type identifer.`,{cause:value})}},UnhandledValueError=class extends JasoneError{constructor(value){super(`Unhandled value received: No encoder found for this value.`,{cause:value})}},DuplicatedTypeIdError=class extends JasoneError{constructor(typeId,decoder){super(`Duplicated type id: The TypeId<${JSON.stringify(typeId)}> is already registered.`,{cause:decoder})}};let TypeIdRegistry=function(TypeIdRegistry$1){return TypeIdRegistry$1[TypeIdRegistry$1.Undefined=0]=`Undefined`,TypeIdRegistry$1[TypeIdRegistry$1.Date=1]=`Date`,TypeIdRegistry$1[TypeIdRegistry$1.BigInt=2]=`BigInt`,TypeIdRegistry$1[TypeIdRegistry$1.RegExp=3]=`RegExp`,TypeIdRegistry$1[TypeIdRegistry$1.Set=4]=`Set`,TypeIdRegistry$1[TypeIdRegistry$1.Map=5]=`Map`,TypeIdRegistry$1[TypeIdRegistry$1.URL=6]=`URL`,TypeIdRegistry$1}({});const bigIntTransformer={encoder:{filter:{bigint:!0},handler:({value})=>[TypeIdRegistry.BigInt,{bigint:value.toString()}]},decoder:{filter:TypeIdRegistry.BigInt,handler:({value})=>BigInt(value.bigint)}},dateTransformer={encoder:{filter:{class:Date,object:({value})=>value instanceof Date},handler:({value})=>[TypeIdRegistry.Date,{iso:value.toISOString()}]},decoder:{filter:TypeIdRegistry.Date,handler:({value})=>new Date(value.iso)}},mapTransformer={encoder:{filter:{class:Map,object:({value})=>value instanceof Map},handler:({value,jasone})=>[TypeIdRegistry.Map,{entries:value.entries().map(([key,val])=>[jasone.encode(key),jasone.encode(val)]).toArray()}]},decoder:{filter:TypeIdRegistry.Map,handler:({value,jasone})=>new Map(value.entries.map(([key,val])=>[jasone.decode(key),jasone.decode(val)]))}},regExpTransformer={encoder:{filter:{class:RegExp,object:({value})=>value instanceof RegExp},handler:({value})=>[TypeIdRegistry.RegExp,{source:value.source,flags:value.flags}]},decoder:{filter:TypeIdRegistry.RegExp,handler:({value})=>new RegExp(value.source,value.flags)}},setTransformer={encoder:{filter:{class:Set,object:({value})=>value instanceof Set},handler:({value,jasone})=>[TypeIdRegistry.Set,{values:value.values().map(entry=>jasone.encode(entry)).toArray()}]},decoder:{filter:TypeIdRegistry.Set,handler:({value,jasone})=>new Set(value.values.map(entry=>jasone.decode(entry)))}},undefinedTransformer={encoder:{filter:{undefined:!0},handler:()=>[TypeIdRegistry.Undefined,{}]},decoder:{filter:TypeIdRegistry.Undefined,handler:()=>void 0}},urlTransformer={encoder:{filter:{class:URL,object:({value})=>value instanceof URL},handler:({value})=>[TypeIdRegistry.URL,{url:value.toString()}]},decoder:{filter:TypeIdRegistry.URL,handler:({value})=>new URL(value.url)}},defaultTransformers=[undefinedTransformer,dateTransformer,bigIntTransformer,regExpTransformer,setTransformer,mapTransformer,urlTransformer],nonJsonTypes=[`bigint`,`function`,`object`,`symbol`,`undefined`],matchEncoderFilters=(filterInput,value,jasone,context)=>{if(!filterInput)return!0;let filters=Array.isArray(filterInput)?filterInput:[filterInput],type=typeof value;for(let filter of filters){if(filter.any?.({value,jasone,context})||type===`object`&&value!==null&&filter.class===value.constructor)return!0;for(let field of nonJsonTypes){if(type!==field)continue;let typeFilter=filter[field];if(typeFilter===!0||typeof typeFilter==`function`&&typeFilter({value,jasone,context}))return!0}}return!1},matchDecoderFilters=(filterInput,value,typeId,jasone,context)=>{if(filterInput===void 0)return!0;let filters=Array.isArray(filterInput)?filterInput:[filterInput];for(let filter of filters)if(typeof filter==`function`&&filter({typeId,value,jasone,context})||filter===typeId)return!0;return!1};var Jasone=class Jasone{#typeIdentifier;#anyDecoder=[];#typeIdDecoder=new Map;#anyEncoder=[];#classEncoder=new Map;#customEncoder={bigint:[],function:[],object:[],symbol:[],undefined:[]};constructor(options={}){this.#typeIdentifier=options.typeIdentifier??`$`;for(let transformer of options.types??[])this.register(transformer)}#registerEncoder(encoder){let filters=encoder.filter?Array.isArray(encoder.filter)?encoder.filter:[encoder.filter]:[];filters.length===0&&this.#anyEncoder.push(encoder);for(let filter of filters){if(filter.any&&this.#anyEncoder.push(encoder),filter.class){let classList=this.#classEncoder.get(filter.class);classList||(classList=[],this.#classEncoder.set(filter.class,classList)),classList.push(encoder)}for(let field of Object.keys(filter))nonJsonTypes.includes(field)&&filter[field]&&this.#customEncoder[field].push(encoder)}}#registerDecoder(decoder){let filters=decoder.filter?Array.isArray(decoder.filter)?decoder.filter:[decoder.filter]:[];filters.length===0&&this.#anyDecoder.push(decoder);for(let filter of filters){if(typeof filter==`function`){this.#anyDecoder.push(decoder);continue}if(this.#typeIdDecoder.has(filter))throw new DuplicatedTypeIdError(filter,decoder);this.#typeIdDecoder.set(filter,decoder)}}register(transformer){transformer.encoder&&this.#registerEncoder(transformer.encoder),transformer.decoder&&this.#registerDecoder(transformer.decoder)}encode(value,context={}){let type=typeof value;switch(type){case`boolean`:case`number`:case`string`:return value;case`object`:if(value===null)return null;if(Array.isArray(value))return value.map(entry=>this.encode(entry,context));if(Object.getPrototypeOf(value)===Object.prototype){let encodedObject=Object.fromEntries(Object.entries(value).map(([key,inner])=>[key,this.encode(inner,context)]));return this.#typeIdentifier in encodedObject&&(encodedObject[this.#typeIdentifier]=[encodedObject[this.#typeIdentifier]]),encodedObject}}let encoder;if(type===`object`&&(encoder??=this.#classEncoder.get(value.constructor)?.find(inner=>matchEncoderFilters(inner.filter,value,this,context))),encoder??=this.#customEncoder[type].find(inner=>matchEncoderFilters(inner.filter,value,this,context)),encoder??=this.#anyEncoder.find(inner=>matchEncoderFilters(inner.filter,value,this,context)),!encoder)throw new UnhandledValueError(value);let[typeId,result]=encoder.handler({value,jasone:this,context});if(typeId!==null&&this.#typeIdentifier in result)throw new IllegalEncoderResultError(result);return typeId===null?result:{[this.#typeIdentifier]:typeId,...result}}decode(value,context={}){return this.#decode(value,context)}#decode(value,context,ignoreTypeIdentifier=!1){switch(typeof value){case`boolean`:case`number`:case`string`:return value;case`object`:if(value===null)return null;if(Array.isArray(value))return value.map(inner=>this.#decode(inner,context));if(this.#typeIdentifier in value&&!Array.isArray(value)&&!ignoreTypeIdentifier){let typeId=value[this.#typeIdentifier];if(Array.isArray(typeId)){let[escaped]=typeId,cloned={...value};return cloned[this.#typeIdentifier]=escaped,this.#decode(cloned,context,!0)}let decoder;if(decoder??=this.#typeIdDecoder.get(typeId),decoder??=this.#anyDecoder.find(entry=>matchDecoderFilters(entry.filter,value,typeId,this,context)),!decoder)throw new UnknownTypeIdError(typeId,value);return decoder.handler({typeId,value,jasone:this,context})}if(Object.getPrototypeOf(value)===Object.prototype)return Object.fromEntries(Object.entries(value).map(([key,inner])=>[key,this.#decode(inner,context)]));break}throw new NonJsonValueError(value)}serialize(value,context={}){return this.encode(value,context)}deserialize(value,context={}){return this.decode(value,context)}stringify(value,context={}){return JSON.stringify(this.encode(value,context))}parse(value,context={}){return this.decode(JSON.parse(value),context)}static default=new Jasone({types:defaultTransformers});static encode=Jasone.default.encode.bind(Jasone.default);static serialize=Jasone.default.serialize.bind(Jasone.default);static decode=Jasone.default.decode.bind(Jasone.default);static deserialize=Jasone.default.deserialize.bind(Jasone.default);static stringify=Jasone.default.stringify.bind(Jasone.default);static parse=Jasone.default.parse.bind(Jasone.default);static register=Jasone.default.register.bind(Jasone.default)};export{Jasone,defaultTransformers,nonJsonTypes};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jasone",
3
- "version": "1.0.0-beta.0",
3
+ "version": "1.0.0-beta.2",
4
4
  "type": "module",
5
5
  "author": "Lukas Heizmann <lukas@heizmann.dev>",
6
6
  "license": "MIT",