@awsless/json 0.0.4 → 0.0.6

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
@@ -3,6 +3,13 @@
3
3
 
4
4
  The `@awsless/json` package adds support for more JavaScript native types to JSON.
5
5
 
6
+ Features:
7
+ - Lightweight / Using the JS native JSON parser.
8
+ - JSON backwards compatible.
9
+ - No precision loss.
10
+ - Includes support basic JS types.
11
+ - Extendable.
12
+
6
13
  ## The Problem
7
14
 
8
15
  JSON doesn't have support for types like:
@@ -15,6 +22,8 @@ JSON doesn't have support for types like:
15
22
 
16
23
  Having to decode & encode these type of values can get quite annoying. We try to solve this problem by encoding these types using valid JSON syntax.
17
24
 
25
+ Also `JSON.parse/stringify` don't solve the potential loss of precision problem.
26
+
18
27
  ## Basic Usage
19
28
 
20
29
  ```ts
@@ -65,24 +74,51 @@ const $custom: Serializable<Custom, string> = {
65
74
  stringify: v => v.value,
66
75
  }
67
76
 
68
- // Stringify your custom type
77
+ // Stringify your custom type.
69
78
  const json = stringify(new Custom('example'), { $custom })
70
79
 
71
- // Parse the json with your custom type
80
+ // Parse the json with your custom type.
72
81
  const value = parse(json, { $custom })
73
82
  ```
74
83
 
84
+ ## Precision Loss
85
+
86
+ When using the native JSON.parse/stringify functions you could lose precision when parsing native numbers. And you don't always have the ability to extend JSON with your own custom types. For example when you’re communicating with a third-party API. For this reason, we have 2 utility functions that will parse the native JSON number type to your own precision-safe alternative.
87
+
88
+ ```ts
89
+ import { safeNumberParse, safeNumberStringify } from '@awsless/json';
90
+ import { BigFloat } from '@awsless/big-float';
91
+
92
+ const value = new BigFloat(1)
93
+ const json = safeNumberStringify(ONE, {
94
+ is: v => v instanceof BigFloat,
95
+ stringify: v => v.toString(),
96
+ })
97
+
98
+ console.log(json) // '1'
99
+
100
+ const result = safeNumberParse('1', {
101
+ parse: v => new BigFloat(v),
102
+ })
103
+
104
+ console.log(eq(value, result)) // true
105
+ ```
106
+
75
107
  ## Known Issue's
76
108
 
77
- Object properties with `undefined` as value type will be stripped away.
109
+ ### Don't use the $ character inside your JSON.
110
+
111
+ We use the `$` character to encode our special types inside JSON. In order to prevent parsing errors we recommend to avoid using the `$` character inside your object property names.
112
+
113
+ ### Object properties with `undefined` as value type will be stripped away.
78
114
 
79
115
  ```ts
80
- // Will result in an empty object
116
+ // Will result in an empty object.
81
117
  const result = parse(stringify({ key: undefined }))
82
118
 
83
- // Will log false
119
+ // Will log false.
84
120
  console.log('key' in result)
85
121
 
86
- // Will log true
122
+ // Will log true.
87
123
  console.log(result.key === undefined)
88
124
  ```
package/dist/index.cjs CHANGED
@@ -22,9 +22,14 @@ var src_exports = {};
22
22
  __export(src_exports, {
23
23
  createReplacer: () => createReplacer,
24
24
  createReviver: () => createReviver,
25
+ createSafeNumberReplacer: () => createSafeNumberReplacer,
26
+ createSafeNumberReviver: () => createSafeNumberReviver,
25
27
  parse: () => parse,
26
28
  patch: () => patch,
27
- stringify: () => stringify
29
+ safeNumberParse: () => safeNumberParse,
30
+ safeNumberStringify: () => safeNumberStringify,
31
+ stringify: () => stringify,
32
+ unpatch: () => unpatch
28
33
  });
29
34
  module.exports = __toCommonJS(src_exports);
30
35
 
@@ -130,13 +135,52 @@ var createReplacer = (types = {}) => {
130
135
 
131
136
  // src/patch.ts
132
137
  var patch = (value, types = {}) => {
133
- return parse(stringify(value, types), types);
138
+ return parse(JSON.stringify(value), types);
139
+ };
140
+ var unpatch = (value, types = {}) => {
141
+ return JSON.parse(stringify(value, types));
142
+ };
143
+
144
+ // src/safe-number/parse.ts
145
+ var safeNumberParse = (json, props) => {
146
+ return JSON.parse(
147
+ json,
148
+ // @ts-ignore
149
+ createSafeNumberReviver(props)
150
+ );
151
+ };
152
+ var createSafeNumberReviver = (props) => {
153
+ return function(_, value, context) {
154
+ if (typeof value === "number") {
155
+ return props.parse(context.source);
156
+ }
157
+ return value;
158
+ };
159
+ };
160
+
161
+ // src/safe-number/stringify.ts
162
+ var safeNumberStringify = (value, props) => {
163
+ return JSON.stringify(value, createSafeNumberReplacer(props));
164
+ };
165
+ var createSafeNumberReplacer = (props) => {
166
+ return function(key, value) {
167
+ const original = this[key];
168
+ if (props.is(original)) {
169
+ return JSON.rawJSON(props.stringify(original));
170
+ }
171
+ return value;
172
+ };
134
173
  };
135
174
  // Annotate the CommonJS export names for ESM import in node:
136
175
  0 && (module.exports = {
137
176
  createReplacer,
138
177
  createReviver,
178
+ createSafeNumberReplacer,
179
+ createSafeNumberReviver,
139
180
  parse,
140
181
  patch,
141
- stringify
182
+ safeNumberParse,
183
+ safeNumberStringify,
184
+ stringify,
185
+ unpatch
142
186
  });
package/dist/index.d.cts CHANGED
@@ -5,14 +5,32 @@ type Serializable<I, O> = {
5
5
  };
6
6
  type SerializableTypes = Record<string, Serializable<any, any>>;
7
7
 
8
- declare const patch: <T>(value: T, types?: SerializableTypes) => T;
8
+ declare const patch: (value: unknown, types?: SerializableTypes) => any;
9
+ declare const unpatch: (value: unknown, types?: SerializableTypes) => any;
9
10
 
10
11
  declare const parse: (json: string, types?: SerializableTypes) => any;
11
- type Reviver = (this: any, key: string, value: any) => any;
12
- declare const createReviver: (types?: SerializableTypes) => Reviver;
12
+ type Reviver$1 = (this: any, key: string, value: any) => any;
13
+ declare const createReviver: (types?: SerializableTypes) => Reviver$1;
13
14
 
14
15
  declare const stringify: (value: unknown, types?: SerializableTypes) => string;
16
+ type Replacer$1 = (this: any, key: string, value: any) => any;
17
+ declare const createReplacer: (types?: SerializableTypes) => Replacer$1;
18
+
19
+ type Props$1 = {
20
+ parse: (value: string) => unknown;
21
+ };
22
+ declare const safeNumberParse: (json: string, props: Props$1) => any;
23
+ type Reviver = (this: any, key: string, value: any, context: {
24
+ source: string;
25
+ }) => any;
26
+ declare const createSafeNumberReviver: (props: Props$1) => Reviver;
27
+
28
+ type Props<T> = {
29
+ is: (value: unknown) => value is T;
30
+ stringify: (value: T) => string;
31
+ };
32
+ declare const safeNumberStringify: <T>(value: unknown, props: Props<T>) => string;
15
33
  type Replacer = (this: any, key: string, value: any) => any;
16
- declare const createReplacer: (types?: SerializableTypes) => Replacer;
34
+ declare const createSafeNumberReplacer: <T>(props: Props<T>) => Replacer;
17
35
 
18
- export { type Serializable, createReplacer, createReviver, parse, patch, stringify };
36
+ export { type Serializable, createReplacer, createReviver, createSafeNumberReplacer, createSafeNumberReviver, parse, patch, safeNumberParse, safeNumberStringify, stringify, unpatch };
package/dist/index.d.ts CHANGED
@@ -5,14 +5,32 @@ type Serializable<I, O> = {
5
5
  };
6
6
  type SerializableTypes = Record<string, Serializable<any, any>>;
7
7
 
8
- declare const patch: <T>(value: T, types?: SerializableTypes) => T;
8
+ declare const patch: (value: unknown, types?: SerializableTypes) => any;
9
+ declare const unpatch: (value: unknown, types?: SerializableTypes) => any;
9
10
 
10
11
  declare const parse: (json: string, types?: SerializableTypes) => any;
11
- type Reviver = (this: any, key: string, value: any) => any;
12
- declare const createReviver: (types?: SerializableTypes) => Reviver;
12
+ type Reviver$1 = (this: any, key: string, value: any) => any;
13
+ declare const createReviver: (types?: SerializableTypes) => Reviver$1;
13
14
 
14
15
  declare const stringify: (value: unknown, types?: SerializableTypes) => string;
16
+ type Replacer$1 = (this: any, key: string, value: any) => any;
17
+ declare const createReplacer: (types?: SerializableTypes) => Replacer$1;
18
+
19
+ type Props$1 = {
20
+ parse: (value: string) => unknown;
21
+ };
22
+ declare const safeNumberParse: (json: string, props: Props$1) => any;
23
+ type Reviver = (this: any, key: string, value: any, context: {
24
+ source: string;
25
+ }) => any;
26
+ declare const createSafeNumberReviver: (props: Props$1) => Reviver;
27
+
28
+ type Props<T> = {
29
+ is: (value: unknown) => value is T;
30
+ stringify: (value: T) => string;
31
+ };
32
+ declare const safeNumberStringify: <T>(value: unknown, props: Props<T>) => string;
15
33
  type Replacer = (this: any, key: string, value: any) => any;
16
- declare const createReplacer: (types?: SerializableTypes) => Replacer;
34
+ declare const createSafeNumberReplacer: <T>(props: Props<T>) => Replacer;
17
35
 
18
- export { type Serializable, createReplacer, createReviver, parse, patch, stringify };
36
+ export { type Serializable, createReplacer, createReviver, createSafeNumberReplacer, createSafeNumberReviver, parse, patch, safeNumberParse, safeNumberStringify, stringify, unpatch };
package/dist/index.js CHANGED
@@ -100,12 +100,51 @@ var createReplacer = (types = {}) => {
100
100
 
101
101
  // src/patch.ts
102
102
  var patch = (value, types = {}) => {
103
- return parse(stringify(value, types), types);
103
+ return parse(JSON.stringify(value), types);
104
+ };
105
+ var unpatch = (value, types = {}) => {
106
+ return JSON.parse(stringify(value, types));
107
+ };
108
+
109
+ // src/safe-number/parse.ts
110
+ var safeNumberParse = (json, props) => {
111
+ return JSON.parse(
112
+ json,
113
+ // @ts-ignore
114
+ createSafeNumberReviver(props)
115
+ );
116
+ };
117
+ var createSafeNumberReviver = (props) => {
118
+ return function(_, value, context) {
119
+ if (typeof value === "number") {
120
+ return props.parse(context.source);
121
+ }
122
+ return value;
123
+ };
124
+ };
125
+
126
+ // src/safe-number/stringify.ts
127
+ var safeNumberStringify = (value, props) => {
128
+ return JSON.stringify(value, createSafeNumberReplacer(props));
129
+ };
130
+ var createSafeNumberReplacer = (props) => {
131
+ return function(key, value) {
132
+ const original = this[key];
133
+ if (props.is(original)) {
134
+ return JSON.rawJSON(props.stringify(original));
135
+ }
136
+ return value;
137
+ };
104
138
  };
105
139
  export {
106
140
  createReplacer,
107
141
  createReviver,
142
+ createSafeNumberReplacer,
143
+ createSafeNumberReviver,
108
144
  parse,
109
145
  patch,
110
- stringify
146
+ safeNumberParse,
147
+ safeNumberStringify,
148
+ stringify,
149
+ unpatch
111
150
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@awsless/json",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "keywords": [