@qubit-ltd/json 1.1.4 → 1.2.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 +206 -28
- package/README.zh_CN.md +205 -27
- package/dist/json.cjs +90 -63
- package/dist/json.cjs.map +1 -1
- package/dist/json.min.cjs +1 -1
- package/dist/json.min.cjs.map +1 -1
- package/dist/json.min.mjs +1 -1
- package/dist/json.min.mjs.map +1 -1
- package/dist/json.mjs +90 -63
- package/dist/json.mjs.map +1 -1
- package/doc/api/LosslessNumber.html +1 -1
- package/doc/api/global.html +1 -1
- package/doc/api/index.html +196 -29
- package/doc/json.min.visualization.html +1 -1
- package/doc/json.visualization.html +1 -1
- package/package.json +16 -16
package/README.md
CHANGED
|
@@ -6,26 +6,26 @@
|
|
|
6
6
|
[](https://dl.circleci.com/status-badge/redirect/gh/Haixing-Hu/js-json/tree/master)
|
|
7
7
|
[](https://coveralls.io/github/Haixing-Hu/js-json?branch=master)
|
|
8
8
|
|
|
9
|
-
[@qubit-ltd/json]
|
|
9
|
+
[@qubit-ltd/json] is a JavaScript library that extends the functionality of the
|
|
10
10
|
standard JSON object, providing robust support for working with numbers that
|
|
11
|
-
exceed JavaScript
|
|
11
|
+
exceed JavaScript's safe range. It offers enhanced parsing and stringifying
|
|
12
12
|
capabilities, making it ideal for handling large datasets and complex numerical
|
|
13
|
-
operations while adhering to JSON
|
|
13
|
+
operations while adhering to JSON's structure.
|
|
14
14
|
|
|
15
15
|
## Key Features
|
|
16
16
|
|
|
17
|
-
-
|
|
17
|
+
- **`BigInt` Support**: When parsing JSON strings, numbers outside JavaScript's safe
|
|
18
18
|
integer range are automatically converted to the native `BigInt`, ensuring
|
|
19
19
|
precision is maintained.
|
|
20
|
-
-
|
|
20
|
+
- **`LosslessNumber` Handling**: For floating-point numbers that cannot be accurately
|
|
21
21
|
represented in JavaScript, this library introduces the `LosslessNumber` object.
|
|
22
22
|
This lightweight object preserves the full precision of the number as a string,
|
|
23
23
|
allowing flexible conversion to number or `BigInt` for mathematical operations.
|
|
24
|
-
- Accurate Stringification
|
|
25
|
-
serialized as strings without the
|
|
24
|
+
- **Accurate Stringification**: During the stringify process, `BigInt` values are
|
|
25
|
+
serialized as strings without the "n" suffix, maintaining compatibility with
|
|
26
26
|
the standard JSON format. Similarly, `LosslessNumber` objects are serialized
|
|
27
27
|
using their internal string representation.
|
|
28
|
-
- Collection Serialization
|
|
28
|
+
- **Collection Serialization**: JavaScript's native collections like `Set` and `Map`
|
|
29
29
|
are seamlessly serialized as arrays, allowing for better compatibility with
|
|
30
30
|
JSON structures.
|
|
31
31
|
|
|
@@ -55,42 +55,86 @@ collections like Set and Map.
|
|
|
55
55
|
```javascript
|
|
56
56
|
import Json from '@qubit-ltd/json';
|
|
57
57
|
|
|
58
|
-
//
|
|
58
|
+
// Parse numbers outside the safe range
|
|
59
59
|
const str1 = '{"decimal":2.370,"big_int":9123372036854000123,"big_float":2.3e+500}';
|
|
60
|
-
const obj1 = Json.parse(
|
|
60
|
+
const obj1 = Json.parse(str1);
|
|
61
61
|
console.log(obj1.decimal); // 2.37
|
|
62
62
|
console.log(obj1.big_int); // 9123372036854000123n
|
|
63
63
|
console.log(obj1.big_float); // LosslessNumber { value: '2.3e+500', isLosslessNumber: true }
|
|
64
64
|
console.log(String(obj1.big_float)); // '2.3e+500'
|
|
65
65
|
|
|
66
|
-
//
|
|
66
|
+
// Stringify numbers outside the safe range
|
|
67
67
|
const json1 = Json.stringify(obj1);
|
|
68
68
|
console.log(json1); // '{"decimal":2.37,"big_int":9123372036854000123,"big_float":"2.3e+500"}'
|
|
69
69
|
|
|
70
|
-
//
|
|
70
|
+
// Stringify collections
|
|
71
71
|
const obj2 = {
|
|
72
72
|
x: new Set([{ a: 1 }, { b: 2 }, { c: 3 }]),
|
|
73
73
|
y: new Map([[1, { a: 2 }], [2, { b: 4 }]]),
|
|
74
74
|
};
|
|
75
|
-
const json2 = Json.stringify(
|
|
75
|
+
const json2 = Json.stringify(obj2);
|
|
76
76
|
console.log(json2); // '{"x":[{"a":1},{"b":2},{"c":3}],"y":[[1,{"a":2}],[2,{"b":4}]]}'
|
|
77
77
|
|
|
78
|
-
|
|
79
|
-
|
|
78
|
+
// Pretty-print with indentation
|
|
79
|
+
const json3 = Json.stringify(obj2, null, 2);
|
|
80
|
+
console.log(json3);
|
|
81
|
+
/* Output:
|
|
82
|
+
{
|
|
83
|
+
"x": [
|
|
84
|
+
{
|
|
85
|
+
"a": 1
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"b": 2
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
"c": 3
|
|
92
|
+
}
|
|
93
|
+
],
|
|
94
|
+
"y": [
|
|
95
|
+
[
|
|
96
|
+
1,
|
|
97
|
+
{
|
|
98
|
+
"a": 2
|
|
99
|
+
}
|
|
100
|
+
],
|
|
101
|
+
[
|
|
102
|
+
2,
|
|
103
|
+
{
|
|
104
|
+
"b": 4
|
|
105
|
+
}
|
|
106
|
+
]
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
*/
|
|
80
110
|
```
|
|
81
111
|
|
|
82
112
|
### LosslessNumber Class
|
|
83
113
|
|
|
84
|
-
The LosslessNumber class is used to handle floating-point numbers with full
|
|
114
|
+
The `LosslessNumber` class is used to handle floating-point numbers with full
|
|
85
115
|
precision, avoiding truncation or rounding issues.
|
|
86
116
|
|
|
87
117
|
```javascript
|
|
88
118
|
import Json from '@qubit-ltd/json';
|
|
119
|
+
import { LosslessNumber } from '@qubit-ltd/json';
|
|
120
|
+
|
|
121
|
+
// Parse a number with high precision
|
|
89
122
|
const parsed = Json.parse('{"float": 1.234567891234567891234}');
|
|
90
123
|
console.log(parsed.float); // LosslessNumber { value: '1.234567891234567891234' }
|
|
91
124
|
|
|
92
125
|
// Convert LosslessNumber to standard number
|
|
93
|
-
console.log(parsed.float.valueOf()); // 1.2345678912345679 (standard JS number)
|
|
126
|
+
console.log(parsed.float.valueOf()); // 1.2345678912345679 (standard JS number, precision loss)
|
|
127
|
+
|
|
128
|
+
// Create a LosslessNumber directly
|
|
129
|
+
const largeNumber = new LosslessNumber('9876543210.123456789012345678901234567890');
|
|
130
|
+
console.log(largeNumber.toString()); // '9876543210.123456789012345678901234567890'
|
|
131
|
+
console.log(largeNumber.valueOf()); // 9876543210.123457 (standard JS number with precision loss)
|
|
132
|
+
|
|
133
|
+
// Mathematical operations
|
|
134
|
+
const num1 = new LosslessNumber('1234567890.123456789');
|
|
135
|
+
const num2 = 100;
|
|
136
|
+
// For math operations, LosslessNumber is converted to standard number (with potential precision loss)
|
|
137
|
+
console.log(num1 * num2); // 123456789012.34578
|
|
94
138
|
```
|
|
95
139
|
|
|
96
140
|
### Utility Functions
|
|
@@ -100,7 +144,7 @@ numbers and ensure safe conversions.
|
|
|
100
144
|
|
|
101
145
|
#### `isBigInt(value)`
|
|
102
146
|
|
|
103
|
-
Checks if a string represents a `BigInt` (i.e., ends with an
|
|
147
|
+
Checks if a string represents a `BigInt` (i.e., ends with an "n" suffix).
|
|
104
148
|
|
|
105
149
|
```javascript
|
|
106
150
|
import { isBigInt } from '@qubit-ltd/json';
|
|
@@ -118,6 +162,8 @@ import { isInteger } from '@qubit-ltd/json';
|
|
|
118
162
|
|
|
119
163
|
console.log(isInteger('12345')); // true
|
|
120
164
|
console.log(isInteger('123.45')); // false
|
|
165
|
+
console.log(isInteger('123e5')); // true (12300000 is an integer)
|
|
166
|
+
console.log(isInteger('123e-5')); // false (0.00123 is not an integer)
|
|
121
167
|
```
|
|
122
168
|
|
|
123
169
|
#### `isNumber(value)`
|
|
@@ -131,19 +177,26 @@ console.log(isNumber('12345')); // true
|
|
|
131
177
|
console.log(isNumber('-123.45')); // true
|
|
132
178
|
console.log(isNumber('1.23e-11')); // true
|
|
133
179
|
console.log(isNumber('abc')); // false
|
|
180
|
+
console.log(isNumber('123abc')); // false
|
|
181
|
+
console.log(isNumber('0xFF')); // false (hexadecimal notation not supported)
|
|
134
182
|
```
|
|
135
183
|
|
|
136
184
|
#### `isSafeNumber(value, options)`
|
|
137
185
|
|
|
138
|
-
Checks if a string represents a number within JavaScript
|
|
186
|
+
Checks if a string represents a number within JavaScript's safe range.
|
|
139
187
|
|
|
140
188
|
```javascript
|
|
141
189
|
import { isSafeNumber } from '@qubit-ltd/json';
|
|
142
190
|
|
|
143
191
|
console.log(isSafeNumber('12345')); // true
|
|
144
|
-
console.log(isSafeNumber('12345678901234567890')); // false
|
|
145
|
-
console.log(isSafeNumber('123.45678901234567890')); // false
|
|
146
|
-
|
|
192
|
+
console.log(isSafeNumber('12345678901234567890')); // false (too large for JavaScript's number type)
|
|
193
|
+
console.log(isSafeNumber('123.45678901234567890')); // false (too many significant digits)
|
|
194
|
+
|
|
195
|
+
// With options
|
|
196
|
+
console.log(isSafeNumber('123.45678901234567890', {
|
|
197
|
+
approx: true, // Allow approximate representation
|
|
198
|
+
requiredDigits: 16 // Require at least 16 digits of precision
|
|
199
|
+
})); // true
|
|
147
200
|
```
|
|
148
201
|
|
|
149
202
|
#### `getUnsafeReason(value)`
|
|
@@ -151,11 +204,11 @@ console.log(isSafeNumber('123.45678901234567890', { approx: true, requiredDigits
|
|
|
151
204
|
Explains why a number represented by a string is unsafe, returning one of the
|
|
152
205
|
following reasons:
|
|
153
206
|
|
|
154
|
-
- `'overflow'
|
|
155
|
-
- `'underflow'
|
|
156
|
-
- `'truncate_integer'
|
|
157
|
-
- `'truncate_float'
|
|
158
|
-
- `'none'`:
|
|
207
|
+
- `'overflow'`: The number is too large to be represented in JavaScript
|
|
208
|
+
- `'underflow'`: The number is too small to be represented in JavaScript
|
|
209
|
+
- `'truncate_integer'`: The integer part would be truncated if converted to a JavaScript number
|
|
210
|
+
- `'truncate_float'`: The floating-point part would lose precision if converted to a JavaScript number
|
|
211
|
+
- `'none'`: The value is safe to convert to a JavaScript number
|
|
159
212
|
|
|
160
213
|
```javascript
|
|
161
214
|
import { getUnsafeReason } from '@qubit-ltd/json';
|
|
@@ -170,7 +223,7 @@ console.log(getUnsafeReason('1e-324')); // Output: 'underflow'
|
|
|
170
223
|
#### `toSafeNumberOrThrow(value, options)`
|
|
171
224
|
|
|
172
225
|
Converts a string into a number if it is safe to do so. Throws an error if the
|
|
173
|
-
number is unsafe, explaining the reason.
|
|
226
|
+
number is unsafe, explaining the reason. This is useful for validating numeric inputs.
|
|
174
227
|
|
|
175
228
|
```javascript
|
|
176
229
|
import { toSafeNumberOrThrow } from '@qubit-ltd/json';
|
|
@@ -181,7 +234,93 @@ try {
|
|
|
181
234
|
console.error(e.message); // Output: 'Cannot safely convert to number: the value '-12345678901234567890' would truncate integer and become -12345678901234567000'
|
|
182
235
|
}
|
|
183
236
|
|
|
237
|
+
// Safe conversion example
|
|
184
238
|
console.log(toSafeNumberOrThrow('9007199254740991')); // Output: 9007199254740991
|
|
239
|
+
|
|
240
|
+
// With options
|
|
241
|
+
try {
|
|
242
|
+
console.log(toSafeNumberOrThrow('123.45678901234567890', {
|
|
243
|
+
approx: false, // Do not allow approximate representation
|
|
244
|
+
requiredDigits: 20 // Require at least 20 digits of precision
|
|
245
|
+
}));
|
|
246
|
+
} catch (e) {
|
|
247
|
+
console.error(e.message); // Will throw error about precision loss
|
|
248
|
+
}
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
## Advanced Usage
|
|
252
|
+
|
|
253
|
+
### Custom Parsing Options
|
|
254
|
+
|
|
255
|
+
You can customize how numbers are parsed using options:
|
|
256
|
+
|
|
257
|
+
```javascript
|
|
258
|
+
import Json from '@qubit-ltd/json';
|
|
259
|
+
|
|
260
|
+
const json = '{"bigInt": 9007199254740993, "largeFloat": 1.234567890123456789}';
|
|
261
|
+
|
|
262
|
+
// Use custom parsing options
|
|
263
|
+
const result = Json.parse(json, {
|
|
264
|
+
useBigInt: true, // Default is true - convert large integers to BigInt
|
|
265
|
+
losslessNumbers: true, // Default is true - use LosslessNumber for high-precision floats
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
console.log(typeof result.bigInt); // 'bigint'
|
|
269
|
+
console.log(result.bigInt); // 9007199254740993n
|
|
270
|
+
console.log(result.largeFloat); // LosslessNumber { value: '1.234567890123456789' }
|
|
271
|
+
|
|
272
|
+
// Disable custom number handling
|
|
273
|
+
const standardResult = Json.parse(json, {
|
|
274
|
+
useBigInt: false,
|
|
275
|
+
losslessNumbers: false,
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
console.log(typeof standardResult.bigInt); // 'number'
|
|
279
|
+
console.log(standardResult.bigInt); // 9007199254740992 (precision loss!)
|
|
280
|
+
console.log(standardResult.largeFloat); // 1.2345678901234568 (precision loss!)
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### Custom Stringification Options
|
|
284
|
+
|
|
285
|
+
You can customize how values are stringified:
|
|
286
|
+
|
|
287
|
+
```javascript
|
|
288
|
+
import Json from '@qubit-ltd/json';
|
|
289
|
+
|
|
290
|
+
const data = {
|
|
291
|
+
bigInt: BigInt('9007199254740993'),
|
|
292
|
+
largeFloat: new LosslessNumber('1.234567890123456789'),
|
|
293
|
+
set: new Set([1, 2, 3]),
|
|
294
|
+
map: new Map([['a', 1], ['b', 2]]),
|
|
295
|
+
};
|
|
296
|
+
|
|
297
|
+
// Default stringification (handles BigInt, LosslessNumber, Set, Map)
|
|
298
|
+
console.log(Json.stringify(data));
|
|
299
|
+
// '{"bigInt":9007199254740993,"largeFloat":"1.234567890123456789","set":[1,2,3],"map":[["a",1],["b",2]]}'
|
|
300
|
+
|
|
301
|
+
// With custom options and indentation
|
|
302
|
+
console.log(Json.stringify(data, null, 2));
|
|
303
|
+
/* Output:
|
|
304
|
+
{
|
|
305
|
+
"bigInt": 9007199254740993,
|
|
306
|
+
"largeFloat": "1.234567890123456789",
|
|
307
|
+
"set": [
|
|
308
|
+
1,
|
|
309
|
+
2,
|
|
310
|
+
3
|
|
311
|
+
],
|
|
312
|
+
"map": [
|
|
313
|
+
[
|
|
314
|
+
"a",
|
|
315
|
+
1
|
|
316
|
+
],
|
|
317
|
+
[
|
|
318
|
+
"b",
|
|
319
|
+
2
|
|
320
|
+
]
|
|
321
|
+
]
|
|
322
|
+
}
|
|
323
|
+
*/
|
|
185
324
|
```
|
|
186
325
|
|
|
187
326
|
## <span id="contributing">Contributing</span>
|
|
@@ -189,6 +328,45 @@ console.log(toSafeNumberOrThrow('9007199254740991')); // Output: 90071992547409
|
|
|
189
328
|
If you find any issues or have suggestions for improvements, please feel free
|
|
190
329
|
to open an issue or submit a pull request to the [GitHub repository].
|
|
191
330
|
|
|
331
|
+
### Development Setup
|
|
332
|
+
|
|
333
|
+
1. Clone the repository:
|
|
334
|
+
```sh
|
|
335
|
+
git clone https://github.com/Haixing-Hu/js-json.git
|
|
336
|
+
cd js-json
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
2. Install dependencies:
|
|
340
|
+
```sh
|
|
341
|
+
yarn install
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
3. Run tests:
|
|
345
|
+
```sh
|
|
346
|
+
yarn test
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
4. Build the library:
|
|
350
|
+
```sh
|
|
351
|
+
yarn build
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
### Release Process
|
|
355
|
+
|
|
356
|
+
1. Update version in package.json
|
|
357
|
+
2. Run tests and linting:
|
|
358
|
+
```sh
|
|
359
|
+
yarn lint && yarn test
|
|
360
|
+
```
|
|
361
|
+
3. Build the library:
|
|
362
|
+
```sh
|
|
363
|
+
yarn build:all
|
|
364
|
+
```
|
|
365
|
+
4. Publish to npm:
|
|
366
|
+
```sh
|
|
367
|
+
yarn deploy
|
|
368
|
+
```
|
|
369
|
+
|
|
192
370
|
## <span id="license">License</span>
|
|
193
371
|
|
|
194
372
|
[@qubit-ltd/json] is distributed under the Apache 2.0 license.
|
package/README.zh_CN.md
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
确保精度不丢失。
|
|
17
17
|
- **`LosslessNumber` 处理**:对于无法在 JavaScript 中准确表示的浮点数,该库引入了 `LosslessNumber` 对象。
|
|
18
18
|
这个轻量级对象以字符串形式保存完整的数值精度,允许灵活地转换为数字或 `BigInt` 进行数学运算。
|
|
19
|
-
- **精确的字符串化**:在字符串化过程中,`BigInt` 值会作为字符串序列化,不带
|
|
19
|
+
- **精确的字符串化**:在字符串化过程中,`BigInt` 值会作为字符串序列化,不带 "n" 后缀,以保持与标准 JSON 格式的兼容性。
|
|
20
20
|
同样,`LosslessNumber` 对象使用其内部字符串表示进行序列化。
|
|
21
21
|
- **集合序列化**:JavaScript 原生的集合类型如 `Set` 和 `Map` 会无缝地序列化为数组,以便更好地与 JSON 结构兼容。
|
|
22
22
|
|
|
@@ -43,28 +43,58 @@ yarn add @qubit-ltd/json
|
|
|
43
43
|
```javascript
|
|
44
44
|
import Json from '@qubit-ltd/json';
|
|
45
45
|
|
|
46
|
-
//
|
|
46
|
+
// 解析超出安全范围的数字
|
|
47
47
|
const str1 = '{"decimal":2.370,"big_int":9123372036854000123,"big_float":2.3e+500}';
|
|
48
|
-
const obj1 = Json.parse(
|
|
48
|
+
const obj1 = Json.parse(str1);
|
|
49
49
|
console.log(obj1.decimal); // 2.37
|
|
50
50
|
console.log(obj1.big_int); // 9123372036854000123n
|
|
51
51
|
console.log(obj1.big_float); // LosslessNumber { value: '2.3e+500', isLosslessNumber: true }
|
|
52
52
|
console.log(String(obj1.big_float)); // '2.3e+500'
|
|
53
53
|
|
|
54
|
-
//
|
|
54
|
+
// 序列化超出安全范围的数字
|
|
55
55
|
const json1 = Json.stringify(obj1);
|
|
56
56
|
console.log(json1); // '{"decimal":2.37,"big_int":9123372036854000123,"big_float":"2.3e+500"}'
|
|
57
57
|
|
|
58
|
-
//
|
|
58
|
+
// 序列化集合类型
|
|
59
59
|
const obj2 = {
|
|
60
60
|
x: new Set([{ a: 1 }, { b: 2 }, { c: 3 }]),
|
|
61
61
|
y: new Map([[1, { a: 2 }], [2, { b: 4 }]]),
|
|
62
62
|
};
|
|
63
|
-
const json2 = Json.stringify(
|
|
63
|
+
const json2 = Json.stringify(obj2);
|
|
64
64
|
console.log(json2); // '{"x":[{"a":1},{"b":2},{"c":3}],"y":[[1,{"a":2}],[2,{"b":4}]]}'
|
|
65
65
|
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
// 格式化输出(带缩进)
|
|
67
|
+
const json3 = Json.stringify(obj2, null, 2);
|
|
68
|
+
console.log(json3);
|
|
69
|
+
/* 输出:
|
|
70
|
+
{
|
|
71
|
+
"x": [
|
|
72
|
+
{
|
|
73
|
+
"a": 1
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"b": 2
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
"c": 3
|
|
80
|
+
}
|
|
81
|
+
],
|
|
82
|
+
"y": [
|
|
83
|
+
[
|
|
84
|
+
1,
|
|
85
|
+
{
|
|
86
|
+
"a": 2
|
|
87
|
+
}
|
|
88
|
+
],
|
|
89
|
+
[
|
|
90
|
+
2,
|
|
91
|
+
{
|
|
92
|
+
"b": 4
|
|
93
|
+
}
|
|
94
|
+
]
|
|
95
|
+
]
|
|
96
|
+
}
|
|
97
|
+
*/
|
|
68
98
|
```
|
|
69
99
|
|
|
70
100
|
### LosslessNumber 类
|
|
@@ -73,11 +103,25 @@ console.log(json3); //
|
|
|
73
103
|
|
|
74
104
|
```javascript
|
|
75
105
|
import Json from '@qubit-ltd/json';
|
|
106
|
+
import { LosslessNumber } from '@qubit-ltd/json';
|
|
107
|
+
|
|
108
|
+
// 解析高精度数字
|
|
76
109
|
const parsed = Json.parse('{"float": 1.234567891234567891234}');
|
|
77
110
|
console.log(parsed.float); // LosslessNumber { value: '1.234567891234567891234' }
|
|
78
111
|
|
|
79
|
-
//
|
|
80
|
-
console.log(parsed.float.valueOf()); // 1.2345678912345679
|
|
112
|
+
// 将 LosslessNumber 转换为标准数字
|
|
113
|
+
console.log(parsed.float.valueOf()); // 1.2345678912345679(标准 JS 数字,有精度损失)
|
|
114
|
+
|
|
115
|
+
// 直接创建 LosslessNumber
|
|
116
|
+
const largeNumber = new LosslessNumber('9876543210.123456789012345678901234567890');
|
|
117
|
+
console.log(largeNumber.toString()); // '9876543210.123456789012345678901234567890'
|
|
118
|
+
console.log(largeNumber.valueOf()); // 9876543210.123457(标准 JS 数字,有精度损失)
|
|
119
|
+
|
|
120
|
+
// 数学运算
|
|
121
|
+
const num1 = new LosslessNumber('1234567890.123456789');
|
|
122
|
+
const num2 = 100;
|
|
123
|
+
// 对于数学运算,LosslessNumber 会转换为标准数字(可能有精度损失)
|
|
124
|
+
console.log(num1 * num2); // 123456789012.34578
|
|
81
125
|
```
|
|
82
126
|
|
|
83
127
|
### 实用函数
|
|
@@ -104,6 +148,8 @@ import { isInteger } from '@qubit-ltd/json';
|
|
|
104
148
|
|
|
105
149
|
console.log(isInteger('12345')); // true
|
|
106
150
|
console.log(isInteger('123.45')); // false
|
|
151
|
+
console.log(isInteger('123e5')); // true(12300000 是整数)
|
|
152
|
+
console.log(isInteger('123e-5')); // false(0.00123 不是整数)
|
|
107
153
|
```
|
|
108
154
|
|
|
109
155
|
#### `isNumber(value)`
|
|
@@ -117,6 +163,8 @@ console.log(isNumber('12345')); // true
|
|
|
117
163
|
console.log(isNumber('-123.45')); // true
|
|
118
164
|
console.log(isNumber('1.23e-11')); // true
|
|
119
165
|
console.log(isNumber('abc')); // false
|
|
166
|
+
console.log(isNumber('123abc')); // false
|
|
167
|
+
console.log(isNumber('0xFF')); // false(不支持十六进制表示法)
|
|
120
168
|
```
|
|
121
169
|
|
|
122
170
|
#### `isSafeNumber(value, options)`
|
|
@@ -127,34 +175,39 @@ console.log(isNumber('abc')); // false
|
|
|
127
175
|
import { isSafeNumber } from '@qubit-ltd/json';
|
|
128
176
|
|
|
129
177
|
console.log(isSafeNumber('12345')); // true
|
|
130
|
-
console.log(isSafeNumber('12345678901234567890')); // false
|
|
131
|
-
console.log(isSafeNumber('123.45678901234567890')); // false
|
|
132
|
-
|
|
178
|
+
console.log(isSafeNumber('12345678901234567890')); // false(对于 JavaScript 的数字类型来说太大)
|
|
179
|
+
console.log(isSafeNumber('123.45678901234567890')); // false(有效数字太多)
|
|
180
|
+
|
|
181
|
+
// 使用选项
|
|
182
|
+
console.log(isSafeNumber('123.45678901234567890', {
|
|
183
|
+
approx: true, // 允许近似表示
|
|
184
|
+
requiredDigits: 16 // 要求至少保留 16 位有效数字精度
|
|
185
|
+
})); // true
|
|
133
186
|
```
|
|
134
187
|
|
|
135
188
|
#### `getUnsafeReason(value)`
|
|
136
189
|
|
|
137
190
|
解释为什么由字符串表示的数字不安全,返回以下原因之一:
|
|
138
191
|
|
|
139
|
-
- `'overflow'
|
|
140
|
-
- `'underflow'
|
|
141
|
-
- `'truncate_integer'
|
|
142
|
-
- `'truncate_float'
|
|
143
|
-
- `'none'
|
|
192
|
+
- `'overflow'`(溢出):数字太大,超出了 JavaScript 可表示的范围
|
|
193
|
+
- `'underflow'`(下溢):数字太小,低于 JavaScript 可表示的范围
|
|
194
|
+
- `'truncate_integer'`(整数截断):如果转换为 JavaScript 数字,整数部分会被截断
|
|
195
|
+
- `'truncate_float'`(浮点数截断):如果转换为 JavaScript 数字,浮点部分会失去精度
|
|
196
|
+
- `'none'`:值是安全的,可以安全地转换为 JavaScript 数字
|
|
144
197
|
|
|
145
198
|
```javascript
|
|
146
199
|
import { getUnsafeReason } from '@qubit-ltd/json';
|
|
147
200
|
|
|
148
|
-
console.log(getUnsafeReason('12345')); //
|
|
149
|
-
console.log(getUnsafeReason('12345678901234567890')); //
|
|
150
|
-
console.log(getUnsafeReason('-12345678901234567890.123')); //
|
|
151
|
-
console.log(getUnsafeReason('-1e+1000')); //
|
|
152
|
-
console.log(getUnsafeReason('1e-324')); //
|
|
201
|
+
console.log(getUnsafeReason('12345')); // 输出: 'none'
|
|
202
|
+
console.log(getUnsafeReason('12345678901234567890')); // 输出: 'truncate_integer'
|
|
203
|
+
console.log(getUnsafeReason('-12345678901234567890.123')); // 输出: 'truncate_float'
|
|
204
|
+
console.log(getUnsafeReason('-1e+1000')); // 输出: 'overflow'
|
|
205
|
+
console.log(getUnsafeReason('1e-324')); // 输出: 'underflow'
|
|
153
206
|
```
|
|
154
207
|
|
|
155
208
|
#### `toSafeNumberOrThrow(value, options)`
|
|
156
209
|
|
|
157
|
-
|
|
210
|
+
如果可以安全转换,将字符串转换为数字。如果数字不安全,则抛出错误并解释原因。这对于验证数字输入非常有用。
|
|
158
211
|
|
|
159
212
|
```javascript
|
|
160
213
|
import { toSafeNumberOrThrow } from '@qubit-ltd/json';
|
|
@@ -162,16 +215,141 @@ import { toSafeNumberOrThrow } from '@qubit-ltd/json';
|
|
|
162
215
|
try {
|
|
163
216
|
console.log(toSafeNumberOrThrow('-12345678901234567890'));
|
|
164
217
|
} catch (e) {
|
|
165
|
-
console.error(e.message); //
|
|
218
|
+
console.error(e.message); // 输出: 'Cannot safely convert to number: the value '-12345678901234567890' would truncate integer and become -12345678901234567000'
|
|
166
219
|
}
|
|
167
220
|
|
|
168
|
-
|
|
221
|
+
// 安全转换示例
|
|
222
|
+
console.log(toSafeNumberOrThrow('9007199254740991')); // 输出: 9007199254740991
|
|
223
|
+
|
|
224
|
+
// 使用选项
|
|
225
|
+
try {
|
|
226
|
+
console.log(toSafeNumberOrThrow('123.45678901234567890', {
|
|
227
|
+
approx: false, // 不允许近似表示
|
|
228
|
+
requiredDigits: 20 // 要求至少保留 20 位有效数字精度
|
|
229
|
+
}));
|
|
230
|
+
} catch (e) {
|
|
231
|
+
console.error(e.message); // 将抛出关于精度损失的错误
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## 高级用法
|
|
236
|
+
|
|
237
|
+
### 自定义解析选项
|
|
238
|
+
|
|
239
|
+
您可以使用选项自定义数字的解析方式:
|
|
240
|
+
|
|
241
|
+
```javascript
|
|
242
|
+
import Json from '@qubit-ltd/json';
|
|
243
|
+
|
|
244
|
+
const json = '{"bigInt": 9007199254740993, "largeFloat": 1.234567890123456789}';
|
|
245
|
+
|
|
246
|
+
// 使用自定义解析选项
|
|
247
|
+
const result = Json.parse(json, {
|
|
248
|
+
useBigInt: true, // 默认为 true - 将大整数转换为 BigInt
|
|
249
|
+
losslessNumbers: true, // 默认为 true - 为高精度浮点数使用 LosslessNumber
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
console.log(typeof result.bigInt); // 'bigint'
|
|
253
|
+
console.log(result.bigInt); // 9007199254740993n
|
|
254
|
+
console.log(result.largeFloat); // LosslessNumber { value: '1.234567890123456789' }
|
|
255
|
+
|
|
256
|
+
// 禁用自定义数字处理
|
|
257
|
+
const standardResult = Json.parse(json, {
|
|
258
|
+
useBigInt: false,
|
|
259
|
+
losslessNumbers: false,
|
|
260
|
+
});
|
|
261
|
+
|
|
262
|
+
console.log(typeof standardResult.bigInt); // 'number'
|
|
263
|
+
console.log(standardResult.bigInt); // 9007199254740992(精度损失!)
|
|
264
|
+
console.log(standardResult.largeFloat); // 1.2345678901234568(精度损失!)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### 自定义字符串化选项
|
|
268
|
+
|
|
269
|
+
您可以自定义值的字符串化方式:
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
import Json from '@qubit-ltd/json';
|
|
273
|
+
|
|
274
|
+
const data = {
|
|
275
|
+
bigInt: BigInt('9007199254740993'),
|
|
276
|
+
largeFloat: new LosslessNumber('1.234567890123456789'),
|
|
277
|
+
set: new Set([1, 2, 3]),
|
|
278
|
+
map: new Map([['a', 1], ['b', 2]]),
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
// 默认字符串化(处理 BigInt、LosslessNumber、Set、Map)
|
|
282
|
+
console.log(Json.stringify(data));
|
|
283
|
+
// '{"bigInt":9007199254740993,"largeFloat":"1.234567890123456789","set":[1,2,3],"map":[["a",1],["b",2]]}'
|
|
284
|
+
|
|
285
|
+
// 使用自定义选项和缩进
|
|
286
|
+
console.log(Json.stringify(data, null, 2));
|
|
287
|
+
/* 输出:
|
|
288
|
+
{
|
|
289
|
+
"bigInt": 9007199254740993,
|
|
290
|
+
"largeFloat": "1.234567890123456789",
|
|
291
|
+
"set": [
|
|
292
|
+
1,
|
|
293
|
+
2,
|
|
294
|
+
3
|
|
295
|
+
],
|
|
296
|
+
"map": [
|
|
297
|
+
[
|
|
298
|
+
"a",
|
|
299
|
+
1
|
|
300
|
+
],
|
|
301
|
+
[
|
|
302
|
+
"b",
|
|
303
|
+
2
|
|
304
|
+
]
|
|
305
|
+
]
|
|
306
|
+
}
|
|
307
|
+
*/
|
|
169
308
|
```
|
|
170
309
|
|
|
171
310
|
## <span id="contributing">贡献</span>
|
|
172
311
|
|
|
173
312
|
如果您发现任何问题或有改进建议,请随时在 [GitHub 仓库] 上提交 issue 或 pull request。
|
|
174
313
|
|
|
314
|
+
### 开发设置
|
|
315
|
+
|
|
316
|
+
1. 克隆仓库:
|
|
317
|
+
```sh
|
|
318
|
+
git clone https://github.com/Haixing-Hu/js-json.git
|
|
319
|
+
cd js-json
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
2. 安装依赖:
|
|
323
|
+
```sh
|
|
324
|
+
yarn install
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
3. 运行测试:
|
|
328
|
+
```sh
|
|
329
|
+
yarn test
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
4. 构建库:
|
|
333
|
+
```sh
|
|
334
|
+
yarn build
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### 发布流程
|
|
338
|
+
|
|
339
|
+
1. 更新 package.json 中的版本号
|
|
340
|
+
2. 运行测试和 lint 检查:
|
|
341
|
+
```sh
|
|
342
|
+
yarn lint && yarn test
|
|
343
|
+
```
|
|
344
|
+
3. 构建库:
|
|
345
|
+
```sh
|
|
346
|
+
yarn build:all
|
|
347
|
+
```
|
|
348
|
+
4. 发布到 npm:
|
|
349
|
+
```sh
|
|
350
|
+
yarn deploy
|
|
351
|
+
```
|
|
352
|
+
|
|
175
353
|
## <span id="license">许可证</span>
|
|
176
354
|
|
|
177
355
|
[@qubit-ltd/json] 根据 Apache 2.0 许可证分发。详情请参阅 [LICENSE](LICENSE) 文件。
|
|
@@ -187,7 +365,7 @@ console.log(toSafeNumberOrThrow('9007199254740991')); // Output: 90071992547409
|
|
|
187
365
|
我们对这些贡献者的工作表示感谢,这些工作对本库功能的实现起到了至关重要的作用。
|
|
188
366
|
|
|
189
367
|
[@qubit-ltd/json]: https://npmjs.com/package/@qubit-ltd/json
|
|
190
|
-
[GitHub
|
|
368
|
+
[GitHub 仓库]: https://github.com/Haixing-Hu/js-json
|
|
191
369
|
[Why does JSON.parse corrupt large numbers and how to solve this?]: https://jsoneditoronline.org/indepth/parse/why-does-json-parse-corrupt-large-numbers/
|
|
192
370
|
[json-bigint]: https://github.com/sidorares/json-bigint
|
|
193
371
|
[lossless-json]: https://github.com/josdejong/lossless-json
|