jasone 0.0.2 → 0.0.4

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.
package/index.cjs CHANGED
@@ -1 +1 @@
1
- "use strict";var i=Object.defineProperty;var T=Object.getOwnPropertyDescriptor;var f=Object.getOwnPropertyNames;var m=Object.prototype.hasOwnProperty;var y=(t,e)=>{for(var r in e)i(t,r,{get:e[r],enumerable:!0})},h=(t,e,r,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let n of f(e))!m.call(t,n)&&n!==r&&i(t,n,{get:()=>e[n],enumerable:!(o=T(e,n))||o.enumerable});return t};var u=t=>h(i({},"__esModule",{value:!0}),t);var E={};y(E,{Jasone:()=>c,createType:()=>s});module.exports=u(E);var a={};y(a,{bigIntType:()=>I,dateType:()=>g,mapType:()=>w,regExpType:()=>x,setType:()=>b,undefinedType:()=>l,urlType:()=>J});var s=t=>t;var l=s({matches:t=>t===void 0,typeId:0,encode:()=>({}),decode:()=>{}});var g=s({target:Date,typeId:1,encode:t=>({timestamp:t.getTime()}),decode:({timestamp:t})=>new Date(t)});var I=s({matches:t=>typeof t=="bigint",typeId:2,encode:t=>({bigint:t.toString()}),decode:({bigint:t})=>BigInt(t)});var x=s({matches:t=>t instanceof RegExp,typeId:3,encode:t=>({source:t.source,flags:t.flags}),decode:({source:t,flags:e})=>new RegExp(t,e)});var b=s({matches:t=>t instanceof Set,typeId:4,encode:(t,e)=>({set:Array.from(t.values().map(r=>e(r)))}),decode:({set:t},e)=>new Set(t.map(r=>e(r)))});var w=s({matches:t=>t instanceof Map,typeId:5,encode:(t,e)=>({map:Array.from(t.entries().map(([r,o])=>[e(r),e(o)]))}),decode:({map:t},e)=>new Map(t.map(([r,o])=>{if(r===void 0||o===void 0)throw new Error("Illegal value received.",{cause:t});return[e(r),e(o)]}))});var J=s({matches:t=>t instanceof URL,typeId:6,encode:t=>({url:t.toString()}),decode:({url:t})=>new URL(t)});var c=class t{#e;#r=new Map;#o=new Map;#n=[];constructor(e={}){this.#e=e.typeIdentifier??"$";for(let r of e.types??[])this.register(r)}register(e){this.#r.set(e.typeId,e.decode),"matches"in e?this.#n.push({matches:e.matches,typeId:e.typeId,encode:e.encode}):this.#o.set(e.target,{typeId:e.typeId,encode:e.encode})}encode(e){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(n=>this.encode(n));if(Object.getPrototypeOf(e)===Object.prototype){let n=Object.fromEntries(Object.entries(e).map(([d,p])=>[d,this.encode(p)]));return this.#e in n&&(n[this.#e]=[this.encode(n[this.#e])]),n}}let r;if(typeof e=="object"&&e!==null&&(r=this.#o.get(e.constructor)),r||(r=this.#n.find(({matches:n})=>n(e))),!r)throw new Error("No encoder found.",{cause:e});let o=r.encode(e,this.encode.bind(this));return{[this.#e]:r.typeId,...o}}decode(e){return this.#t(e)}#t(e,r=!1){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(o=>this.#t(o));if(this.#e in e&&!Array.isArray(e)&&!r){let o=e[this.#e];if(Array.isArray(o)){if(o.length!==1)throw new Error("Illegal value received. Escaped type identifiers must have exactly one element.",{cause:e});let[d]=o,p={...e};return p[this.#e]=d,this.#t(p,!0)}let n=this.#r.get(o);if(!n)throw new Error(`No decoder found for type id: ${o}`,{cause:e});return n(e,this.decode.bind(this))}if(Object.getPrototypeOf(e)===Object.prototype)return Object.fromEntries(Object.entries(e).map(([o,n])=>[o,this.#t(n)]));break}throw new Error("Illegal value received.",{cause:e})}static default=new t({types:Object.values(a)});static register=t.default.register.bind(t.default);static encode=t.default.encode.bind(t.default);static decode=t.default.decode.bind(t.default)};0&&(module.exports={Jasone,createType});
1
+ "use strict";var c=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var I=Object.getOwnPropertyNames;var b=Object.prototype.hasOwnProperty;var w=(t,e)=>{for(var r in e)c(t,r,{get:e[r],enumerable:!0})},J=(t,e,r,n)=>{if(e&&typeof e=="object"||typeof e=="function")for(let o of I(e))!b.call(t,o)&&o!==r&&c(t,o,{get:()=>e[o],enumerable:!(n=g(e,o))||n.enumerable});return t};var x=t=>J(c({},"__esModule",{value:!0}),t);var E={};w(E,{Jasone:()=>d,bigIntType:()=>a,createType:()=>s,dateType:()=>y,defaultTypes:()=>l,mapType:()=>T,regExpType:()=>f,setType:()=>m,undefinedType:()=>u,urlType:()=>h});module.exports=x(E);var s=t=>t;var a=s({matches:t=>typeof t=="bigint",typeId:2,encode:t=>({bigint:t.toString()}),decode:({bigint:t})=>BigInt(t)});var y=s({target:Date,typeId:1,encode:t=>({timestamp:t.getTime()}),decode:({timestamp:t})=>new Date(t)});var T=s({target:Map,typeId:5,encode:(t,e)=>({map:Array.from(t.entries().map(([r,n])=>[e(r),e(n)]))}),decode:({map:t},e)=>new Map(t.map(([r,n])=>{if(r===void 0||n===void 0)throw new Error("Illegal value received.",{cause:t});return[e(r),e(n)]}))});var f=s({target:RegExp,typeId:3,encode:t=>({source:t.source,flags:t.flags}),decode:({source:t,flags:e})=>new RegExp(t,e)});var m=s({target:Set,typeId:4,encode:(t,e)=>({set:Array.from(t.values().map(r=>e(r)))}),decode:({set:t},e)=>new Set(t.map(r=>e(r)))});var u=s({matches:t=>t===void 0,typeId:0,encode:()=>({}),decode:()=>{}});var h=s({target:URL,typeId:6,encode:t=>({url:t.toString()}),decode:({url:t})=>new URL(t)});var l=[u,y,a,f,m,T,h];var d=class t{#e;#r=new Map;#n=new Map;#o=[];constructor(e={}){this.#e=e.typeIdentifier??"$";for(let r of e.types??[])this.register(r)}register(e){this.#r.set(e.typeId,e.decode),"matches"in e?this.#o.push({matches:e.matches,typeId:e.typeId,encode:e.encode}):this.#n.set(e.target,{typeId:e.typeId,encode:e.encode})}encode(e){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(o=>this.encode(o));if(Object.getPrototypeOf(e)===Object.prototype){let o=Object.fromEntries(Object.entries(e).map(([i,p])=>[i,this.encode(p)]));return this.#e in o&&(o[this.#e]=[this.encode(o[this.#e])]),o}}let r;if(typeof e=="object"&&e!==null&&(r=this.#n.get(e.constructor)),r||(r=this.#o.find(({matches:o})=>o(e))),!r)throw new Error("No encoder found.",{cause:e});let n=r.encode(e,this.encode.bind(this));return{[this.#e]:r.typeId,...n}}decode(e){return this.#t(e)}#t(e,r=!1){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(n=>this.#t(n));if(this.#e in e&&!Array.isArray(e)&&!r){let n=e[this.#e];if(Array.isArray(n)){if(n.length!==1)throw new Error("Illegal value received. Escaped type identifiers must have exactly one element.",{cause:e});let[i]=n,p={...e};return p[this.#e]=i,this.#t(p,!0)}let o=this.#r.get(n);if(!o)throw new Error(`No decoder found for type id: ${n}`,{cause:e});return o(e,this.decode.bind(this))}if(Object.getPrototypeOf(e)===Object.prototype)return Object.fromEntries(Object.entries(e).map(([n,o])=>[n,this.#t(o)]));break}throw new Error("Illegal value received.",{cause:e})}serialize(e){return this.encode(e)}deserialize(e){return this.decode(e)}stringify(e){return JSON.stringify(this.encode(e))}parse(e){return this.decode(JSON.parse(e))}static default=new t({types:l});static register=t.default.register.bind(t.default);static encode=t.default.encode.bind(t.default);static serialize=t.default.serialize.bind(t.default);static decode=t.default.decode.bind(t.default);static deserialize=t.default.deserialize.bind(t.default);static stringify=t.default.stringify.bind(t.default);static parse=t.default.parse.bind(t.default)};0&&(module.exports={Jasone,bigIntType,createType,dateType,defaultTypes,mapType,regExpType,setType,undefinedType,urlType});
package/index.d.cts CHANGED
@@ -1,40 +1,273 @@
1
+ /**
2
+ * A JSON-compatible value.
3
+ */
1
4
  type JsonValue = string | number | boolean | null | JsonValue[] | {
2
5
  [key: string]: JsonValue;
3
6
  };
7
+ /**
8
+ * The id of an encoded type to identify it on decoding.
9
+ */
4
10
  type TypeId = string | number;
11
+ /**
12
+ * A function that is responsible to encode a type into a JSON-compatible value.
13
+ *
14
+ * @param value The value to encode.
15
+ * @param encode A function that works exactly the same as `Jasone.encode` useful
16
+ * to encode values recursively. This function comes from the instance
17
+ * where the type transformer is registered, so it has the same types.
18
+ * @returns A JSON-compatible value.
19
+ */
5
20
  type TypeEncoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TType, encode: <T = unknown>(value: T) => JsonValue) => TJson;
21
+ /**
22
+ * A function that is responsible to decode a type back to its decoded value.
23
+ *
24
+ * @param value The value to decode.
25
+ * @param encode A function that works exactly the same as `Jasone.decode` useful
26
+ * to decode values recursively. This function comes from the instance
27
+ * where the type transformer is registered, so it has the same types.
28
+ * @returns A JSON-compatible value.
29
+ */
6
30
  type TypeDecoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TJson, decode: <T = unknown>(value: JsonValue) => T) => TType;
7
31
  type MatchesFn<TType = unknown> = (value: unknown) => value is TType;
8
- type ClassLike<TInstance> = new (...args: unknown[]) => TInstance;
32
+ type ClassLike<TInstance> = new <T>(...args: any[]) => TInstance;
9
33
  declare const typeOf: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
10
34
  type TypeOf = typeof typeOf;
11
35
 
12
36
  type TypeMatcher<TType> = {
37
+ /**
38
+ * The function that is responsible to determine if a value can be
39
+ * encoded with this transformer.
40
+ */
13
41
  matches: MatchesFn<TType>;
14
42
  } | {
43
+ /**
44
+ * The class that can be encoded with this transformer.
45
+ *
46
+ * Using the `target` property only works on classes with an
47
+ * `constructor`. Internally, Jasone matches the constructor of the
48
+ * class with the `target` property.
49
+ */
15
50
  target: ClassLike<TType>;
16
51
  };
52
+ /**
53
+ * A type transformer which is responsible for encoding and decoding a type.
54
+ */
17
55
  type TypeTransformer<TType, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = TypeMatcher<TType> & {
56
+ /**
57
+ * The id of the type that is used to identify the type on decoding.
58
+ *
59
+ * This id should be unique for each type and it is recommended to use strings
60
+ * to avoid conflicts with built-in types (which used positive integers).
61
+ */
18
62
  typeId: string | number;
63
+ /**
64
+ * The function that is responsible to encode the type into a JSON-compatible
65
+ * value.
66
+ */
19
67
  encode: TypeEncoder<TType, TJson>;
68
+ /**
69
+ * The function that is responsible to decode the type from a JSON-compatible
70
+ * value.
71
+ */
20
72
  decode: TypeDecoder<TType, TJson>;
21
73
  };
74
+ /**
75
+ * A convenience function to create a type transformer which automatically
76
+ * infer the types for you, so you don't have to.
77
+ *
78
+ * @param transformer The transformer to create.
79
+ * @returns The exact same transformer you passed in, but with the types inferred.
80
+ */
22
81
  declare const createType: <TType, TJson extends Record<string, JsonValue>>(transformer: TypeTransformer<TType, TJson>) => TypeTransformer<TType, TJson>;
23
82
 
83
+ declare const bigIntType: TypeTransformer<bigint, {
84
+ bigint: string;
85
+ }>;
86
+
87
+ declare const dateType: TypeTransformer<Date, {
88
+ timestamp: number;
89
+ }>;
90
+
91
+ declare const mapType: TypeTransformer<Map<unknown, unknown>, {
92
+ map: JsonValue[][];
93
+ }>;
94
+
95
+ declare const regExpType: TypeTransformer<RegExp, {
96
+ source: string;
97
+ flags: string;
98
+ }>;
99
+
100
+ declare const setType: TypeTransformer<Set<unknown>, {
101
+ set: JsonValue[];
102
+ }>;
103
+
104
+ declare const undefinedType: TypeTransformer<undefined, {}>;
105
+
106
+ declare const urlType: TypeTransformer<URL, {
107
+ url: string;
108
+ }>;
109
+
110
+ /**
111
+ * The default types that are used by the default Jasone instance.
112
+ */
113
+ declare const defaultTypes: TypeTransformer<any, any>[];
114
+
115
+ /**
116
+ * Jasone options that can be passed to the Jasone constructor.
117
+ */
24
118
  type JasoneOptions = {
119
+ /**
120
+ * The type identifier that is used to determine if an object is a typed object.
121
+ *
122
+ * @default "$"
123
+ */
25
124
  typeIdentifier?: string;
125
+ /**
126
+ * The types that are used to encode and decode objects.
127
+ *
128
+ * If not provided, the default types are used. By providing your own types,
129
+ * the default types are not used anymore, so be sure to also include them.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * // your custom type WITH default types
134
+ * const jasone = new Jasone({ types: [myCustomType, ...defaultTypes] });
135
+ *
136
+ * // your custom type WITHOUT default types
137
+ * const jasone = new Jasone({ types: [myCustomType] });
138
+ * ```
139
+ */
26
140
  types?: TypeTransformer<any, any>[];
27
141
  };
142
+ /**
143
+ * Jasone is a JSON encoder and decoder that can handle custom types.
144
+ *
145
+ * It exposes the default Jasone instance as `Jasone.default` and also
146
+ * registers the methods as static methods on the class itself, so you
147
+ * can easily use them without having to create an instance.
148
+ *
149
+ * ```ts
150
+ * const encoded = Jasone.encode(value);
151
+ * const decoded = Jasone.decode(value);
152
+ * ```
153
+ *
154
+ * If you want to use your own types, you can either register them on any
155
+ * instance (even on `Jasone.default`) or instantiate your own Jasone instance.
156
+ *
157
+ * ```ts
158
+ * // use our own types without the default types (Date, BigInt, Map, etc.)
159
+ * const myInstance = new Jasone({ types: [myCustomType] });
160
+ *
161
+ * // or use our own types with the default types (recommend)
162
+ * const myInstance = new Jasone({ types: [myCustomType, ...defaultTypes] });
163
+ *
164
+ * const encoded = myInstance.encode(value);
165
+ * const decoded = myInstance.decode(value);
166
+ * ```
167
+ */
28
168
  declare class Jasone {
29
169
  #private;
30
170
  constructor(options?: JasoneOptions);
171
+ /**
172
+ * Register a new type to this Jasone instance.
173
+ *
174
+ * @param type The type to register.
175
+ */
31
176
  register<TType, TJson extends Record<string, JsonValue>>(type: TypeTransformer<TType, TJson>): void;
177
+ /**
178
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
179
+ *
180
+ * @param value The value to encode.
181
+ * @returns A JSON-compatible Jasone encoded value.
182
+ */
32
183
  encode(value: unknown): JsonValue;
184
+ /**
185
+ * Decode an Jasone encoded value to its decoded value.
186
+ *
187
+ * @param value The Jasone encoded value to decode.
188
+ * @returns The decoded value.
189
+ */
33
190
  decode<T = unknown>(value: JsonValue): T;
191
+ /**
192
+ * Alias for `encode`.
193
+ */
194
+ serialize(value: unknown): JsonValue;
195
+ /**
196
+ * Alias for `decode`.
197
+ */
198
+ deserialize<T = unknown>(value: JsonValue): T;
199
+ /**
200
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
201
+ *
202
+ * Under the hood, this functions looks like this:
203
+ *
204
+ * ```ts
205
+ * JSON.stringify(this.encode(value));
206
+ * ```
207
+ */
208
+ stringify(value: unknown): string;
209
+ /**
210
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
211
+ *
212
+ * Under the hood, this functions looks like this:
213
+ *
214
+ * ```ts
215
+ * this.decode(JSON.parse(value));
216
+ * ```
217
+ */
218
+ parse<T = unknown>(value: string): T;
219
+ /**
220
+ * The default Jasone instance with the default types already registered.
221
+ */
34
222
  static default: Jasone;
223
+ /**
224
+ * Register a new type to the default Jasone instance.
225
+ *
226
+ * @param type The type to register.
227
+ */
35
228
  static register: <TType, TJson extends Record<string, JsonValue>>(type: TypeTransformer<TType, TJson>) => void;
229
+ /**
230
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
231
+ *
232
+ * @param value The value to encode.
233
+ * @returns A JSON-compatible Jasone encoded value.
234
+ */
36
235
  static encode: (value: unknown) => JsonValue;
236
+ /**
237
+ * Alias for `encode`.
238
+ */
239
+ static serialize: (value: unknown) => JsonValue;
240
+ /**
241
+ * Decode an Jasone encoded value to its decoded value.
242
+ *
243
+ * @param value The Jasone encoded value to decode.
244
+ * @returns The decoded value.
245
+ */
37
246
  static decode: <T = unknown>(value: JsonValue) => T;
247
+ /**
248
+ * Alias for `decode`.
249
+ */
250
+ static deserialize: <T = unknown>(value: JsonValue) => T;
251
+ /**
252
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
253
+ *
254
+ * Under the hood, this functions looks like this:
255
+ *
256
+ * ```ts
257
+ * JSON.stringify(Jasone.encode(value));
258
+ * ```
259
+ */
260
+ static stringify: (value: unknown) => string;
261
+ /**
262
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
263
+ *
264
+ * Under the hood, this functions looks like this:
265
+ *
266
+ * ```ts
267
+ * Jasone.decode(JSON.parse(value));
268
+ * ```
269
+ */
270
+ static parse: <T = unknown>(value: string) => T;
38
271
  }
39
272
 
40
- export { type ClassLike, Jasone, type JasoneOptions, type JsonValue, type MatchesFn, type TypeDecoder, type TypeEncoder, type TypeId, type TypeMatcher, type TypeOf, type TypeTransformer, createType };
273
+ export { type ClassLike, Jasone, type JasoneOptions, type JsonValue, type MatchesFn, type TypeDecoder, type TypeEncoder, type TypeId, type TypeMatcher, type TypeOf, type TypeTransformer, bigIntType, createType, dateType, defaultTypes, mapType, regExpType, setType, undefinedType, urlType };
package/index.d.ts CHANGED
@@ -1,40 +1,273 @@
1
+ /**
2
+ * A JSON-compatible value.
3
+ */
1
4
  type JsonValue = string | number | boolean | null | JsonValue[] | {
2
5
  [key: string]: JsonValue;
3
6
  };
7
+ /**
8
+ * The id of an encoded type to identify it on decoding.
9
+ */
4
10
  type TypeId = string | number;
11
+ /**
12
+ * A function that is responsible to encode a type into a JSON-compatible value.
13
+ *
14
+ * @param value The value to encode.
15
+ * @param encode A function that works exactly the same as `Jasone.encode` useful
16
+ * to encode values recursively. This function comes from the instance
17
+ * where the type transformer is registered, so it has the same types.
18
+ * @returns A JSON-compatible value.
19
+ */
5
20
  type TypeEncoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TType, encode: <T = unknown>(value: T) => JsonValue) => TJson;
21
+ /**
22
+ * A function that is responsible to decode a type back to its decoded value.
23
+ *
24
+ * @param value The value to decode.
25
+ * @param encode A function that works exactly the same as `Jasone.decode` useful
26
+ * to decode values recursively. This function comes from the instance
27
+ * where the type transformer is registered, so it has the same types.
28
+ * @returns A JSON-compatible value.
29
+ */
6
30
  type TypeDecoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TJson, decode: <T = unknown>(value: JsonValue) => T) => TType;
7
31
  type MatchesFn<TType = unknown> = (value: unknown) => value is TType;
8
- type ClassLike<TInstance> = new (...args: unknown[]) => TInstance;
32
+ type ClassLike<TInstance> = new <T>(...args: any[]) => TInstance;
9
33
  declare const typeOf: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
10
34
  type TypeOf = typeof typeOf;
11
35
 
12
36
  type TypeMatcher<TType> = {
37
+ /**
38
+ * The function that is responsible to determine if a value can be
39
+ * encoded with this transformer.
40
+ */
13
41
  matches: MatchesFn<TType>;
14
42
  } | {
43
+ /**
44
+ * The class that can be encoded with this transformer.
45
+ *
46
+ * Using the `target` property only works on classes with an
47
+ * `constructor`. Internally, Jasone matches the constructor of the
48
+ * class with the `target` property.
49
+ */
15
50
  target: ClassLike<TType>;
16
51
  };
52
+ /**
53
+ * A type transformer which is responsible for encoding and decoding a type.
54
+ */
17
55
  type TypeTransformer<TType, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = TypeMatcher<TType> & {
56
+ /**
57
+ * The id of the type that is used to identify the type on decoding.
58
+ *
59
+ * This id should be unique for each type and it is recommended to use strings
60
+ * to avoid conflicts with built-in types (which used positive integers).
61
+ */
18
62
  typeId: string | number;
63
+ /**
64
+ * The function that is responsible to encode the type into a JSON-compatible
65
+ * value.
66
+ */
19
67
  encode: TypeEncoder<TType, TJson>;
68
+ /**
69
+ * The function that is responsible to decode the type from a JSON-compatible
70
+ * value.
71
+ */
20
72
  decode: TypeDecoder<TType, TJson>;
21
73
  };
74
+ /**
75
+ * A convenience function to create a type transformer which automatically
76
+ * infer the types for you, so you don't have to.
77
+ *
78
+ * @param transformer The transformer to create.
79
+ * @returns The exact same transformer you passed in, but with the types inferred.
80
+ */
22
81
  declare const createType: <TType, TJson extends Record<string, JsonValue>>(transformer: TypeTransformer<TType, TJson>) => TypeTransformer<TType, TJson>;
23
82
 
83
+ declare const bigIntType: TypeTransformer<bigint, {
84
+ bigint: string;
85
+ }>;
86
+
87
+ declare const dateType: TypeTransformer<Date, {
88
+ timestamp: number;
89
+ }>;
90
+
91
+ declare const mapType: TypeTransformer<Map<unknown, unknown>, {
92
+ map: JsonValue[][];
93
+ }>;
94
+
95
+ declare const regExpType: TypeTransformer<RegExp, {
96
+ source: string;
97
+ flags: string;
98
+ }>;
99
+
100
+ declare const setType: TypeTransformer<Set<unknown>, {
101
+ set: JsonValue[];
102
+ }>;
103
+
104
+ declare const undefinedType: TypeTransformer<undefined, {}>;
105
+
106
+ declare const urlType: TypeTransformer<URL, {
107
+ url: string;
108
+ }>;
109
+
110
+ /**
111
+ * The default types that are used by the default Jasone instance.
112
+ */
113
+ declare const defaultTypes: TypeTransformer<any, any>[];
114
+
115
+ /**
116
+ * Jasone options that can be passed to the Jasone constructor.
117
+ */
24
118
  type JasoneOptions = {
119
+ /**
120
+ * The type identifier that is used to determine if an object is a typed object.
121
+ *
122
+ * @default "$"
123
+ */
25
124
  typeIdentifier?: string;
125
+ /**
126
+ * The types that are used to encode and decode objects.
127
+ *
128
+ * If not provided, the default types are used. By providing your own types,
129
+ * the default types are not used anymore, so be sure to also include them.
130
+ *
131
+ * @example
132
+ * ```ts
133
+ * // your custom type WITH default types
134
+ * const jasone = new Jasone({ types: [myCustomType, ...defaultTypes] });
135
+ *
136
+ * // your custom type WITHOUT default types
137
+ * const jasone = new Jasone({ types: [myCustomType] });
138
+ * ```
139
+ */
26
140
  types?: TypeTransformer<any, any>[];
27
141
  };
142
+ /**
143
+ * Jasone is a JSON encoder and decoder that can handle custom types.
144
+ *
145
+ * It exposes the default Jasone instance as `Jasone.default` and also
146
+ * registers the methods as static methods on the class itself, so you
147
+ * can easily use them without having to create an instance.
148
+ *
149
+ * ```ts
150
+ * const encoded = Jasone.encode(value);
151
+ * const decoded = Jasone.decode(value);
152
+ * ```
153
+ *
154
+ * If you want to use your own types, you can either register them on any
155
+ * instance (even on `Jasone.default`) or instantiate your own Jasone instance.
156
+ *
157
+ * ```ts
158
+ * // use our own types without the default types (Date, BigInt, Map, etc.)
159
+ * const myInstance = new Jasone({ types: [myCustomType] });
160
+ *
161
+ * // or use our own types with the default types (recommend)
162
+ * const myInstance = new Jasone({ types: [myCustomType, ...defaultTypes] });
163
+ *
164
+ * const encoded = myInstance.encode(value);
165
+ * const decoded = myInstance.decode(value);
166
+ * ```
167
+ */
28
168
  declare class Jasone {
29
169
  #private;
30
170
  constructor(options?: JasoneOptions);
171
+ /**
172
+ * Register a new type to this Jasone instance.
173
+ *
174
+ * @param type The type to register.
175
+ */
31
176
  register<TType, TJson extends Record<string, JsonValue>>(type: TypeTransformer<TType, TJson>): void;
177
+ /**
178
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
179
+ *
180
+ * @param value The value to encode.
181
+ * @returns A JSON-compatible Jasone encoded value.
182
+ */
32
183
  encode(value: unknown): JsonValue;
184
+ /**
185
+ * Decode an Jasone encoded value to its decoded value.
186
+ *
187
+ * @param value The Jasone encoded value to decode.
188
+ * @returns The decoded value.
189
+ */
33
190
  decode<T = unknown>(value: JsonValue): T;
191
+ /**
192
+ * Alias for `encode`.
193
+ */
194
+ serialize(value: unknown): JsonValue;
195
+ /**
196
+ * Alias for `decode`.
197
+ */
198
+ deserialize<T = unknown>(value: JsonValue): T;
199
+ /**
200
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
201
+ *
202
+ * Under the hood, this functions looks like this:
203
+ *
204
+ * ```ts
205
+ * JSON.stringify(this.encode(value));
206
+ * ```
207
+ */
208
+ stringify(value: unknown): string;
209
+ /**
210
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
211
+ *
212
+ * Under the hood, this functions looks like this:
213
+ *
214
+ * ```ts
215
+ * this.decode(JSON.parse(value));
216
+ * ```
217
+ */
218
+ parse<T = unknown>(value: string): T;
219
+ /**
220
+ * The default Jasone instance with the default types already registered.
221
+ */
34
222
  static default: Jasone;
223
+ /**
224
+ * Register a new type to the default Jasone instance.
225
+ *
226
+ * @param type The type to register.
227
+ */
35
228
  static register: <TType, TJson extends Record<string, JsonValue>>(type: TypeTransformer<TType, TJson>) => void;
229
+ /**
230
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
231
+ *
232
+ * @param value The value to encode.
233
+ * @returns A JSON-compatible Jasone encoded value.
234
+ */
36
235
  static encode: (value: unknown) => JsonValue;
236
+ /**
237
+ * Alias for `encode`.
238
+ */
239
+ static serialize: (value: unknown) => JsonValue;
240
+ /**
241
+ * Decode an Jasone encoded value to its decoded value.
242
+ *
243
+ * @param value The Jasone encoded value to decode.
244
+ * @returns The decoded value.
245
+ */
37
246
  static decode: <T = unknown>(value: JsonValue) => T;
247
+ /**
248
+ * Alias for `decode`.
249
+ */
250
+ static deserialize: <T = unknown>(value: JsonValue) => T;
251
+ /**
252
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
253
+ *
254
+ * Under the hood, this functions looks like this:
255
+ *
256
+ * ```ts
257
+ * JSON.stringify(Jasone.encode(value));
258
+ * ```
259
+ */
260
+ static stringify: (value: unknown) => string;
261
+ /**
262
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
263
+ *
264
+ * Under the hood, this functions looks like this:
265
+ *
266
+ * ```ts
267
+ * Jasone.decode(JSON.parse(value));
268
+ * ```
269
+ */
270
+ static parse: <T = unknown>(value: string) => T;
38
271
  }
39
272
 
40
- export { type ClassLike, Jasone, type JasoneOptions, type JsonValue, type MatchesFn, type TypeDecoder, type TypeEncoder, type TypeId, type TypeMatcher, type TypeOf, type TypeTransformer, createType };
273
+ export { type ClassLike, Jasone, type JasoneOptions, type JsonValue, type MatchesFn, type TypeDecoder, type TypeEncoder, type TypeId, type TypeMatcher, type TypeOf, type TypeTransformer, bigIntType, createType, dateType, defaultTypes, mapType, regExpType, setType, undefinedType, urlType };
package/index.js CHANGED
@@ -1 +1 @@
1
- var a=Object.defineProperty;var y=(t,e)=>{for(var r in e)a(t,r,{get:e[r],enumerable:!0})};var d={};y(d,{bigIntType:()=>m,dateType:()=>f,mapType:()=>l,regExpType:()=>h,setType:()=>u,undefinedType:()=>T,urlType:()=>g});var n=t=>t;var T=n({matches:t=>t===void 0,typeId:0,encode:()=>({}),decode:()=>{}});var f=n({target:Date,typeId:1,encode:t=>({timestamp:t.getTime()}),decode:({timestamp:t})=>new Date(t)});var m=n({matches:t=>typeof t=="bigint",typeId:2,encode:t=>({bigint:t.toString()}),decode:({bigint:t})=>BigInt(t)});var h=n({matches:t=>t instanceof RegExp,typeId:3,encode:t=>({source:t.source,flags:t.flags}),decode:({source:t,flags:e})=>new RegExp(t,e)});var u=n({matches:t=>t instanceof Set,typeId:4,encode:(t,e)=>({set:Array.from(t.values().map(r=>e(r)))}),decode:({set:t},e)=>new Set(t.map(r=>e(r)))});var l=n({matches:t=>t instanceof Map,typeId:5,encode:(t,e)=>({map:Array.from(t.entries().map(([r,o])=>[e(r),e(o)]))}),decode:({map:t},e)=>new Map(t.map(([r,o])=>{if(r===void 0||o===void 0)throw new Error("Illegal value received.",{cause:t});return[e(r),e(o)]}))});var g=n({matches:t=>t instanceof URL,typeId:6,encode:t=>({url:t.toString()}),decode:({url:t})=>new URL(t)});var i=class t{#e;#r=new Map;#o=new Map;#n=[];constructor(e={}){this.#e=e.typeIdentifier??"$";for(let r of e.types??[])this.register(r)}register(e){this.#r.set(e.typeId,e.decode),"matches"in e?this.#n.push({matches:e.matches,typeId:e.typeId,encode:e.encode}):this.#o.set(e.target,{typeId:e.typeId,encode:e.encode})}encode(e){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(s=>this.encode(s));if(Object.getPrototypeOf(e)===Object.prototype){let s=Object.fromEntries(Object.entries(e).map(([c,p])=>[c,this.encode(p)]));return this.#e in s&&(s[this.#e]=[this.encode(s[this.#e])]),s}}let r;if(typeof e=="object"&&e!==null&&(r=this.#o.get(e.constructor)),r||(r=this.#n.find(({matches:s})=>s(e))),!r)throw new Error("No encoder found.",{cause:e});let o=r.encode(e,this.encode.bind(this));return{[this.#e]:r.typeId,...o}}decode(e){return this.#t(e)}#t(e,r=!1){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(o=>this.#t(o));if(this.#e in e&&!Array.isArray(e)&&!r){let o=e[this.#e];if(Array.isArray(o)){if(o.length!==1)throw new Error("Illegal value received. Escaped type identifiers must have exactly one element.",{cause:e});let[c]=o,p={...e};return p[this.#e]=c,this.#t(p,!0)}let s=this.#r.get(o);if(!s)throw new Error(`No decoder found for type id: ${o}`,{cause:e});return s(e,this.decode.bind(this))}if(Object.getPrototypeOf(e)===Object.prototype)return Object.fromEntries(Object.entries(e).map(([o,s])=>[o,this.#t(s)]));break}throw new Error("Illegal value received.",{cause:e})}static default=new t({types:Object.values(d)});static register=t.default.register.bind(t.default);static encode=t.default.encode.bind(t.default);static decode=t.default.decode.bind(t.default)};export{i as Jasone,n as createType};
1
+ var o=t=>t;var c=o({matches:t=>typeof t=="bigint",typeId:2,encode:t=>({bigint:t.toString()}),decode:({bigint:t})=>BigInt(t)});var a=o({target:Date,typeId:1,encode:t=>({timestamp:t.getTime()}),decode:({timestamp:t})=>new Date(t)});var y=o({target:Map,typeId:5,encode:(t,e)=>({map:Array.from(t.entries().map(([r,n])=>[e(r),e(n)]))}),decode:({map:t},e)=>new Map(t.map(([r,n])=>{if(r===void 0||n===void 0)throw new Error("Illegal value received.",{cause:t});return[e(r),e(n)]}))});var T=o({target:RegExp,typeId:3,encode:t=>({source:t.source,flags:t.flags}),decode:({source:t,flags:e})=>new RegExp(t,e)});var f=o({target:Set,typeId:4,encode:(t,e)=>({set:Array.from(t.values().map(r=>e(r)))}),decode:({set:t},e)=>new Set(t.map(r=>e(r)))});var m=o({matches:t=>t===void 0,typeId:0,encode:()=>({}),decode:()=>{}});var u=o({target:URL,typeId:6,encode:t=>({url:t.toString()}),decode:({url:t})=>new URL(t)});var h=[m,a,c,T,f,y,u];var i=class t{#e;#r=new Map;#n=new Map;#o=[];constructor(e={}){this.#e=e.typeIdentifier??"$";for(let r of e.types??[])this.register(r)}register(e){this.#r.set(e.typeId,e.decode),"matches"in e?this.#o.push({matches:e.matches,typeId:e.typeId,encode:e.encode}):this.#n.set(e.target,{typeId:e.typeId,encode:e.encode})}encode(e){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(s=>this.encode(s));if(Object.getPrototypeOf(e)===Object.prototype){let s=Object.fromEntries(Object.entries(e).map(([d,p])=>[d,this.encode(p)]));return this.#e in s&&(s[this.#e]=[this.encode(s[this.#e])]),s}}let r;if(typeof e=="object"&&e!==null&&(r=this.#n.get(e.constructor)),r||(r=this.#o.find(({matches:s})=>s(e))),!r)throw new Error("No encoder found.",{cause:e});let n=r.encode(e,this.encode.bind(this));return{[this.#e]:r.typeId,...n}}decode(e){return this.#t(e)}#t(e,r=!1){switch(typeof e){case"string":case"number":case"boolean":return e;case"object":if(e===null)return null;if(Array.isArray(e))return e.map(n=>this.#t(n));if(this.#e in e&&!Array.isArray(e)&&!r){let n=e[this.#e];if(Array.isArray(n)){if(n.length!==1)throw new Error("Illegal value received. Escaped type identifiers must have exactly one element.",{cause:e});let[d]=n,p={...e};return p[this.#e]=d,this.#t(p,!0)}let s=this.#r.get(n);if(!s)throw new Error(`No decoder found for type id: ${n}`,{cause:e});return s(e,this.decode.bind(this))}if(Object.getPrototypeOf(e)===Object.prototype)return Object.fromEntries(Object.entries(e).map(([n,s])=>[n,this.#t(s)]));break}throw new Error("Illegal value received.",{cause:e})}serialize(e){return this.encode(e)}deserialize(e){return this.decode(e)}stringify(e){return JSON.stringify(this.encode(e))}parse(e){return this.decode(JSON.parse(e))}static default=new t({types:h});static register=t.default.register.bind(t.default);static encode=t.default.encode.bind(t.default);static serialize=t.default.serialize.bind(t.default);static decode=t.default.decode.bind(t.default);static deserialize=t.default.deserialize.bind(t.default);static stringify=t.default.stringify.bind(t.default);static parse=t.default.parse.bind(t.default)};export{i as Jasone,c as bigIntType,o as createType,a as dateType,h as defaultTypes,y as mapType,T as regExpType,f as setType,m as undefinedType,u as urlType};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "jasone",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "author": "Lukas Heizmann <lukas@heizmann.dev>",
6
6
  "license": "MIT",