jasone 0.0.4 → 1.0.0-beta.1

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/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # Jasone
2
2
 
3
- A lightweight, extensible JSON encoder and decoder which supports custom types.
3
+ A lightweight, extensible JSON encoder and decoder that supports custom types.
4
4
 
5
- **NOTICE:** Jasone is still in early development and might not be stable yet.
5
+ **NOTICE:** The documentation is still in progress and a lot of things are missing.
6
6
 
7
7
  ## Features
8
8
 
9
9
  - 🚀 Fast & Lightweight: Minimal footprint.
10
+ - 🧩 Zero dependencies: No external packages required.
10
11
  - 🔌 Extensible: Easily add custom types.
11
12
  - 💻 TypeScript: Written in TypeScript for type safety and better DX.
12
13
 
@@ -33,87 +34,77 @@ bun add jasone
33
34
  ```ts
34
35
  import { Jasone } from "jasone";
35
36
 
36
- const data = { myDate: new Date("2025-04-05T14:30:00.000+02:00") };
37
+ const data = { myDate: new Date("2025-04-05T14:30:00.000Z") };
37
38
  const encoded = JSON.stringify(Jasone.encode(data));
38
39
 
39
- console.log(encoded); // {"myDate":{"$":1,"timestamp":1743856200000}}
40
+ console.log(encoded); // {"myDate":{"$":1,"iso":"2025-04-05T12:30:00.000Z"}}
40
41
  ```
41
42
 
42
43
  ### Decoding
43
44
 
44
45
  ```ts
45
- import { decode } from "jasone";
46
+ import { Jasone } from "jasone";
46
47
 
47
- const encoded = '{"myDate":{"$":1,"timestamp":1743856200000}}';
48
+ const encoded = '{"myDate":{"$":1,"iso":"2025-04-05T12:30:00.000Z"}}';
48
49
  const decoded = Jasone.decode(JSON.parse(encoded));
49
50
 
50
- console.log(decoded); // { myDate: new Date("2025-04-05T14:30:00.000+02:00") }
51
+ console.log(decoded); // { myDate: new Date("2025-04-05T12:30:00.000Z") }
51
52
  ```
52
53
 
53
54
  ## Advanced Usage
54
55
 
55
- Adding custom types is really easy. You just need to create an transformer object and register it with Jasone.
56
+ Adding custom types is easy. You just need to create a transformer object and register it with Jasone.
56
57
 
57
58
  ```ts
58
- import { Jasone } from "jasone";
59
+ import { defaultTransformers, Jasone, type Transformer } from "jasone";
59
60
 
60
61
  class Car {
61
- constructor(public brand: string, public model: string) {}
62
+ constructor(
63
+ public brand: string,
64
+ public model: string,
65
+ ) {}
62
66
 
63
67
  // ...
64
68
  }
65
69
 
66
- // use the `createType` helper
67
- const myType = createType({
68
- // the match function is used to determine if the transformer can encode the given value
69
- matches: (value) => value instanceof Car,
70
-
71
- // the type id is used to identify the type on the encoded object
72
- // (this needs to be unique and a string, numbers are currently reserved for built-in types)
73
- typeId: "Car"
74
-
75
- // the encode function which receives the matched value and need to return an valid JSON object
76
- encode: (car) => ({ brand: car.brand, model: car.model }),
77
-
78
- // the decode function which receives the encoded JSON object and needs to return a original value
79
- decode: ({brand, model}) => new Car(brand, model),
80
- });
81
- ```
82
-
83
- For classes, you can also use a bit more performant way of creating the transformer object:
84
-
85
- ```ts
86
- const myType = createType({
87
- // by using the `target` property, under the hood, Jasone will use the constructor to match
88
- // the type. Which is more performant than using the `matches` property.
89
- target: Car,
90
- typeId: "Car",
91
- encode: (car) => ({brand: car.brand, model: car.model}),
92
- decode: ({brand, model}) => new Car(brand, model),
93
- });
94
- ```
95
-
96
- Now the only thing left is to register the type with Jasone:
97
-
98
- ```ts
99
- Jasone.register(myType);
70
+ const carType: Transformer<Car, { brand: string; model: string }> = {
71
+ encoder: {
72
+ // The filter is used to determine if the transformer can encode the given value.
73
+ // There are many different filters, but for classes, the class constructor is the most efficient.
74
+ filter: { class: Car },
75
+ // The handler is used to encode the value.
76
+ handler: ({ value }) => [
77
+ // The type Id is used to identify the type in the encoded object.
78
+ "Car",
79
+ // Any JSON-compatible value needed to reconstruct the original value.
80
+ { brand: value.brand, model: value.model },
81
+ ],
82
+ },
83
+ decoder: {
84
+ // The filter is used to determine if the transformer can decode the given value.
85
+ filter: "Car",
86
+ // The handler is used to decode the value.
87
+ handler: ({ value }) => new Car(value.brand, value.model),
88
+ },
89
+ };
90
+
91
+ // Register the type with an already instantiated Jasone instance
92
+ Jasone.register(carType);
93
+
94
+ // Or create a new Jasone instance with the type already registered
95
+ new Jasone({ types: [carType] });
96
+
97
+ // Or register the type with default built-in transformers like Date, BigInt, Map, etc.
98
+ new Jasone({ types: [carType, ...defaultTransformers] });
100
99
  ```
101
100
 
102
- And that's it! If you want multiple instances of Jasone with different types, simply create a new instance like so:
101
+ ## Comparison with Superjson
103
102
 
104
- ```ts
105
- const jasone = new Jasone({
106
- types: [myType],
107
- });
108
- ```
109
-
110
- Or
103
+ Jasone provides fewer features than Superjson, but is more performant, has a smaller footprint, and uses a simpler JSON format.
111
104
 
112
- ```ts
113
- const jasone = new Jasone();
105
+ If you only need to encode and decode custom types, Jasone is a great choice.
114
106
 
115
- jasone.register(myType);
116
- ```
107
+ If you need features like referential equality, Superjson may be a better choice. However, most of the time, you don't need those features.
117
108
 
118
109
  ## Contributing
119
110
 
package/index.d.ts CHANGED
@@ -1,143 +1,83 @@
1
+ //#region src/types.d.ts
1
2
  /**
2
3
  * A JSON-compatible value.
3
4
  */
4
5
  type JsonValue = string | number | boolean | null | JsonValue[] | {
5
- [key: string]: JsonValue;
6
+ [key: string]: JsonValue;
6
7
  };
7
8
  /**
8
9
  * The id of an encoded type to identify it on decoding.
9
10
  */
10
11
  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
- */
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
- */
30
- type TypeDecoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TJson, decode: <T = unknown>(value: JsonValue) => T) => TType;
31
- type MatchesFn<TType = unknown> = (value: unknown) => value is TType;
32
- type ClassLike<TInstance> = new <T>(...args: any[]) => TInstance;
33
- declare const typeOf: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
34
- type TypeOf = typeof typeOf;
35
-
36
- type TypeMatcher<TType> = {
37
- /**
38
- * The function that is responsible to determine if a value can be
39
- * encoded with this transformer.
40
- */
41
- matches: MatchesFn<TType>;
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
- */
50
- target: ClassLike<TType>;
12
+ type ClassLike<TInstance> = new (...args: any[]) => TInstance;
13
+ declare const nonJsonTypes: ("bigint" | "symbol" | "undefined" | "object" | "function")[];
14
+ type NonJsonType = {
15
+ bigint: bigint;
16
+ function: Function;
17
+ object: object;
18
+ symbol: symbol;
19
+ undefined: undefined;
51
20
  };
52
- /**
53
- * A type transformer which is responsible for encoding and decoding a type.
54
- */
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
- */
62
- typeId: string | number;
63
- /**
64
- * The function that is responsible to encode the type into a JSON-compatible
65
- * value.
66
- */
67
- encode: TypeEncoder<TType, TJson>;
68
- /**
69
- * The function that is responsible to decode the type from a JSON-compatible
70
- * value.
71
- */
72
- decode: TypeDecoder<TType, TJson>;
21
+ type Context = Record<string, unknown>;
22
+ type EncodeFilter<TType, TContext extends Context = Context> = {
23
+ class?: ClassLike<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> = {
28
+ value: TType;
29
+ jasone: Jasone;
30
+ context: TContext;
73
31
  };
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
- */
81
- declare const createType: <TType, TJson extends Record<string, JsonValue>>(transformer: TypeTransformer<TType, TJson>) => TypeTransformer<TType, TJson>;
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
-
32
+ type EncodeResult<TJson extends JsonValue> = TJson extends Record<string, JsonValue> ? [TypeId, TJson] | [null, JsonValue] : [null, JsonValue];
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>;
36
+ };
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> = {
39
+ value: TJson;
40
+ typeId: TypeId;
41
+ jasone: Jasone;
42
+ context: TContext;
43
+ };
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>;
48
+ };
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;
52
+ };
53
+ //#endregion
54
+ //#region src/jasone.d.ts
115
55
  /**
116
56
  * Jasone options that can be passed to the Jasone constructor.
117
57
  */
118
58
  type JasoneOptions = {
119
- /**
120
- * The type identifier that is used to determine if an object is a typed object.
121
- *
122
- * @default "$"
123
- */
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
- */
140
- types?: TypeTransformer<any, any>[];
59
+ /**
60
+ * The type identifier that is used to determine if an object is a typed object.
61
+ *
62
+ * @default "$"
63
+ */
64
+ typeIdentifier?: string;
65
+ /**
66
+ * The type transformers that are used to transform types.
67
+ *
68
+ * If not provided, the default transformers are used. By providing your own transformers,
69
+ * the default transformers are not used anymore, so be sure to also include them if needed.
70
+ *
71
+ * @example
72
+ * ```ts
73
+ * // your custom transformer WITH default type transformers
74
+ * const jasone = new Jasone({ types: [myCustomTransformer, ...defaultTransformers] });
75
+ *
76
+ * // your custom transformer WITHOUT default type transformers
77
+ * const jasone = new Jasone({ types: [myCustomTransformer] });
78
+ * ```
79
+ */
80
+ types?: Transformer<any, any>[];
141
81
  };
142
82
  /**
143
83
  * Jasone is a JSON encoder and decoder that can handle custom types.
@@ -156,118 +96,167 @@ type JasoneOptions = {
156
96
  *
157
97
  * ```ts
158
98
  * // use our own types without the default types (Date, BigInt, Map, etc.)
159
- * const myInstance = new Jasone({ types: [myCustomType] });
99
+ * const myInstance = new Jasone({
100
+ * types: [myCustomTransformer]
101
+ * });
160
102
  *
161
103
  * // or use our own types with the default types (recommend)
162
- * const myInstance = new Jasone({ types: [myCustomType, ...defaultTypes] });
104
+ * const myInstance = new Jasone({
105
+ * types: [myCustomTransformer, ...defaultTransformers],
106
+ * });
163
107
  *
164
108
  * const encoded = myInstance.encode(value);
165
109
  * const decoded = myInstance.decode(value);
166
110
  * ```
167
111
  */
168
112
  declare class Jasone {
169
- #private;
170
- constructor(options?: JasoneOptions);
171
- /**
172
- * Register a new type to this Jasone instance.
173
- *
174
- * @param type The type to register.
175
- */
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
- */
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
- */
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
- */
222
- static default: Jasone;
223
- /**
224
- * Register a new type to the default Jasone instance.
225
- *
226
- * @param type The type to register.
227
- */
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
- */
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
- */
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;
113
+ #private;
114
+ constructor(options?: JasoneOptions);
115
+ /**
116
+ * Register a new type to this Jasone instance.
117
+ *
118
+ * @param type The type to register.
119
+ */
120
+ register<TType, TJson extends JsonValue, TContext extends Context = Context>(transformer: Transformer<TType, TJson, TContext>): void;
121
+ /**
122
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
123
+ *
124
+ * @param value The value to encode.
125
+ * @returns A JSON-compatible Jasone encoded value.
126
+ */
127
+ encode(value: unknown, context?: Context): JsonValue;
128
+ /**
129
+ * Decode an Jasone encoded value to its decoded value.
130
+ *
131
+ * @param value The Jasone encoded value to decode.
132
+ * @returns The decoded value.
133
+ */
134
+ decode<T = unknown>(value: JsonValue, context?: Context): T;
135
+ /**
136
+ * Alias for `encode`.
137
+ */
138
+ serialize(value: unknown, context?: Context): JsonValue;
139
+ /**
140
+ * Alias for `decode`.
141
+ */
142
+ deserialize<T = unknown>(value: JsonValue, context?: Context): T;
143
+ /**
144
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
145
+ *
146
+ * Under the hood, this functions looks like this:
147
+ *
148
+ * ```ts
149
+ * JSON.stringify(this.encode(value));
150
+ * ```
151
+ */
152
+ stringify(value: unknown, context?: Context): string;
153
+ /**
154
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
155
+ *
156
+ * Under the hood, this functions looks like this:
157
+ *
158
+ * ```ts
159
+ * this.decode(JSON.parse(value));
160
+ * ```
161
+ */
162
+ parse<T = unknown>(value: string, context?: Context): T;
163
+ /**
164
+ * The default Jasone instance with the default types already registered.
165
+ */
166
+ static default: Jasone;
167
+ /**
168
+ * Register a new type to the default Jasone instance.
169
+ *
170
+ * @param type The type to register.
171
+ */
172
+ /**
173
+ * Encode an arbitrary value to a JSON-compatible Jasone encoded value.
174
+ *
175
+ * @param value The value to encode.
176
+ * @returns A JSON-compatible Jasone encoded value.
177
+ */
178
+ static encode: (value: unknown, context?: Context) => JsonValue;
179
+ /**
180
+ * Alias for `encode`.
181
+ */
182
+ static serialize: (value: unknown, context?: Context) => JsonValue;
183
+ /**
184
+ * Decode an Jasone encoded value to its decoded value.
185
+ *
186
+ * @param value The Jasone encoded value to decode.
187
+ * @returns The decoded value.
188
+ */
189
+ static decode: <T = unknown>(value: JsonValue, context?: Context) => T;
190
+ /**
191
+ * Alias for `decode`.
192
+ */
193
+ static deserialize: <T = unknown>(value: JsonValue, context?: Context) => T;
194
+ /**
195
+ * A wrapper around `JSON.stringify` that encodes a value and stringifies it.
196
+ *
197
+ * Under the hood, this functions looks like this:
198
+ *
199
+ * ```ts
200
+ * JSON.stringify(Jasone.encode(value));
201
+ * ```
202
+ */
203
+ static stringify: (value: unknown, context?: Context) => string;
204
+ /**
205
+ * A wrapper around `JSON.parse` that parses a Jasone encoded value and decodes it.
206
+ *
207
+ * Under the hood, this functions looks like this:
208
+ *
209
+ * ```ts
210
+ * Jasone.decode(JSON.parse(value));
211
+ * ```
212
+ */
213
+ static parse: <T = unknown>(value: string, context?: Context) => T;
214
+ /**
215
+ * Register a new type to this Jasone instance.
216
+ *
217
+ * @param type The type to register.
218
+ */
219
+ static register: <TType, TJson extends JsonValue, TContext extends Context = Context>(transformer: Transformer<TType, TJson, TContext>) => void;
271
220
  }
272
-
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 };
221
+ //#endregion
222
+ //#region src/transformers/bigint.d.ts
223
+ declare const bigIntTransformer: Transformer<bigint, {
224
+ bigint: string;
225
+ }>;
226
+ //#endregion
227
+ //#region src/transformers/date.d.ts
228
+ declare const dateTransformer: Transformer<Date, {
229
+ iso: string;
230
+ }>;
231
+ //#endregion
232
+ //#region src/transformers/map.d.ts
233
+ declare const mapTransformer: Transformer<Map<unknown, unknown>, {
234
+ entries: [key: JsonValue, value: JsonValue][];
235
+ }>;
236
+ //#endregion
237
+ //#region src/transformers/regexp.d.ts
238
+ declare const regExpTransformer: Transformer<RegExp, {
239
+ source: string;
240
+ flags: string;
241
+ }>;
242
+ //#endregion
243
+ //#region src/transformers/set.d.ts
244
+ declare const setTransformer: Transformer<Set<unknown>, {
245
+ values: JsonValue[];
246
+ }>;
247
+ //#endregion
248
+ //#region src/transformers/undefined.d.ts
249
+ declare const undefinedTransformer: Transformer<undefined, {}>;
250
+ //#endregion
251
+ //#region src/transformers/url.d.ts
252
+ declare const urlTransformer: Transformer<URL, {
253
+ url: string;
254
+ }>;
255
+ //#endregion
256
+ //#region src/transformers/index.d.ts
257
+ /**
258
+ * The default type transformers that are used by the default Jasone instance.
259
+ */
260
+ declare const defaultTransformers: Transformer[];
261
+ //#endregion
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 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};
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,17 +1,15 @@
1
1
  {
2
2
  "name": "jasone",
3
- "version": "0.0.4",
3
+ "version": "1.0.0-beta.1",
4
4
  "type": "module",
5
5
  "author": "Lukas Heizmann <lukas@heizmann.dev>",
6
6
  "license": "MIT",
7
- "main": "./index.cjs",
8
7
  "module": "./index.js",
9
8
  "types": "./index.d.ts",
10
9
  "exports": {
11
10
  ".": {
12
- "import": "./index.js",
13
- "require": "./index.cjs",
14
- "types": "./index.d.ts"
11
+ "types": "./index.d.ts",
12
+ "default": "./index.js"
15
13
  }
16
14
  },
17
15
  "repository": {
package/index.cjs DELETED
@@ -1 +0,0 @@
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 DELETED
@@ -1,273 +0,0 @@
1
- /**
2
- * A JSON-compatible value.
3
- */
4
- type JsonValue = string | number | boolean | null | JsonValue[] | {
5
- [key: string]: JsonValue;
6
- };
7
- /**
8
- * The id of an encoded type to identify it on decoding.
9
- */
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
- */
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
- */
30
- type TypeDecoder<TType = unknown, TJson extends Record<string, JsonValue> = Record<string, JsonValue>> = (value: TJson, decode: <T = unknown>(value: JsonValue) => T) => TType;
31
- type MatchesFn<TType = unknown> = (value: unknown) => value is TType;
32
- type ClassLike<TInstance> = new <T>(...args: any[]) => TInstance;
33
- declare const typeOf: "string" | "number" | "bigint" | "boolean" | "symbol" | "undefined" | "object" | "function";
34
- type TypeOf = typeof typeOf;
35
-
36
- type TypeMatcher<TType> = {
37
- /**
38
- * The function that is responsible to determine if a value can be
39
- * encoded with this transformer.
40
- */
41
- matches: MatchesFn<TType>;
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
- */
50
- target: ClassLike<TType>;
51
- };
52
- /**
53
- * A type transformer which is responsible for encoding and decoding a type.
54
- */
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
- */
62
- typeId: string | number;
63
- /**
64
- * The function that is responsible to encode the type into a JSON-compatible
65
- * value.
66
- */
67
- encode: TypeEncoder<TType, TJson>;
68
- /**
69
- * The function that is responsible to decode the type from a JSON-compatible
70
- * value.
71
- */
72
- decode: TypeDecoder<TType, TJson>;
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
- */
81
- declare const createType: <TType, TJson extends Record<string, JsonValue>>(transformer: TypeTransformer<TType, TJson>) => TypeTransformer<TType, TJson>;
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
- */
118
- type JasoneOptions = {
119
- /**
120
- * The type identifier that is used to determine if an object is a typed object.
121
- *
122
- * @default "$"
123
- */
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
- */
140
- types?: TypeTransformer<any, any>[];
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
- */
168
- declare class Jasone {
169
- #private;
170
- constructor(options?: JasoneOptions);
171
- /**
172
- * Register a new type to this Jasone instance.
173
- *
174
- * @param type The type to register.
175
- */
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
- */
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
- */
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
- */
222
- static default: Jasone;
223
- /**
224
- * Register a new type to the default Jasone instance.
225
- *
226
- * @param type The type to register.
227
- */
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
- */
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
- */
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;
271
- }
272
-
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 };