jsonh-ts 1.0.0
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/build/index.d.ts +22 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +22 -0
- package/build/index.js.map +1 -0
- package/build/json-token-type.d.ts +77 -0
- package/build/json-token-type.d.ts.map +1 -0
- package/build/json-token-type.js +79 -0
- package/build/json-token-type.js.map +1 -0
- package/build/jsonh-number-parser.d.ts +21 -0
- package/build/jsonh-number-parser.d.ts.map +1 -0
- package/build/jsonh-number-parser.js +174 -0
- package/build/jsonh-number-parser.js.map +1 -0
- package/build/jsonh-reader-options.d.ts +25 -0
- package/build/jsonh-reader-options.d.ts.map +1 -0
- package/build/jsonh-reader-options.js +26 -0
- package/build/jsonh-reader-options.js.map +1 -0
- package/build/jsonh-reader.d.ts +68 -0
- package/build/jsonh-reader.d.ts.map +1 -0
- package/build/jsonh-reader.js +1218 -0
- package/build/jsonh-reader.js.map +1 -0
- package/build/jsonh-token.d.ts +21 -0
- package/build/jsonh-token.d.ts.map +1 -0
- package/build/jsonh-token.js +36 -0
- package/build/jsonh-token.js.map +1 -0
- package/build/jsonh-version.d.ts +15 -0
- package/build/jsonh-version.d.ts.map +1 -0
- package/build/jsonh-version.js +17 -0
- package/build/jsonh-version.js.map +1 -0
- package/build/result-helpers.d.ts +6 -0
- package/build/result-helpers.d.ts.map +1 -0
- package/build/result-helpers.js +11 -0
- package/build/result-helpers.js.map +1 -0
- package/build/result.d.ts +48 -0
- package/build/result.d.ts.map +1 -0
- package/build/result.js +95 -0
- package/build/result.js.map +1 -0
- package/build/string-text-reader.d.ts +11 -0
- package/build/string-text-reader.d.ts.map +1 -0
- package/build/string-text-reader.js +33 -0
- package/build/string-text-reader.js.map +1 -0
- package/build/text-reader.d.ts +20 -0
- package/build/text-reader.d.ts.map +1 -0
- package/build/text-reader.js +19 -0
- package/build/text-reader.js.map +1 -0
- package/index.ts +21 -0
- package/json-token-type.ts +77 -0
- package/jsonh-number-parser.ts +191 -0
- package/jsonh-reader-options.ts +26 -0
- package/jsonh-reader.ts +1317 -0
- package/jsonh-token.ts +37 -0
- package/jsonh-version.ts +15 -0
- package/package.json +30 -0
- package/result.ts +97 -0
- package/string-text-reader.ts +35 -0
- package/text-reader.ts +30 -0
- package/tsconfig.json +38 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import Result = require("./result.js");
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Methods for parsing JSONH numbers.
|
|
5
|
+
*
|
|
6
|
+
* Unlike `JsonhReader.readElement()`, minimal validation is done here. Ensure the input is valid.
|
|
7
|
+
*/
|
|
8
|
+
class JsonhNumberParser {
|
|
9
|
+
/**
|
|
10
|
+
* Converts a JSONH number to a base-10 real.
|
|
11
|
+
* For example:
|
|
12
|
+
*
|
|
13
|
+
* ```
|
|
14
|
+
* Input: +5.2e3.0
|
|
15
|
+
* Output: 5200
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
static parse(jsonhNumber: string): Result<number> {
|
|
19
|
+
// Remove underscores
|
|
20
|
+
jsonhNumber = jsonhNumber.replaceAll("_", "");
|
|
21
|
+
let digits: string = jsonhNumber;
|
|
22
|
+
|
|
23
|
+
// Get sign
|
|
24
|
+
let sign: number = 1;
|
|
25
|
+
if (digits.startsWith('-')) {
|
|
26
|
+
sign = -1;
|
|
27
|
+
digits = digits.slice(1);
|
|
28
|
+
}
|
|
29
|
+
else if (digits.startsWith('+')) {
|
|
30
|
+
sign = 1;
|
|
31
|
+
digits = digits.slice(1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Decimal
|
|
35
|
+
let baseDigits: string = "0123456789";
|
|
36
|
+
// Hexadecimal
|
|
37
|
+
if (digits.startsWith("0x") || digits.startsWith("0X")) {
|
|
38
|
+
baseDigits = "0123456789abcdef";
|
|
39
|
+
digits = digits.slice(2);
|
|
40
|
+
}
|
|
41
|
+
// Binary
|
|
42
|
+
else if (digits.startsWith("0b") || digits.startsWith("0B")) {
|
|
43
|
+
baseDigits = "01";
|
|
44
|
+
digits = digits.slice(2);
|
|
45
|
+
}
|
|
46
|
+
// Octal
|
|
47
|
+
else if (digits.startsWith("0o") || digits.startsWith("0O")) {
|
|
48
|
+
baseDigits = "01234567";
|
|
49
|
+
digits = digits.slice(2);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Parse number with base digits
|
|
53
|
+
let number: Result<number> = this.#parseFractionalNumberWithExponent(digits, baseDigits);
|
|
54
|
+
if (number.isError) {
|
|
55
|
+
return number;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// Apply sign
|
|
59
|
+
if (sign !== 1) {
|
|
60
|
+
number.value *= sign;
|
|
61
|
+
}
|
|
62
|
+
return number;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Converts a fractional number with an exponent (e.g. `12.3e4.5`) from the given base (e.g. `01234567`) to a base-10 real.
|
|
67
|
+
*/
|
|
68
|
+
static #parseFractionalNumberWithExponent(digits: string, baseDigits: string): Result<number> {
|
|
69
|
+
// Find exponent
|
|
70
|
+
let exponentIndex: number = -1;
|
|
71
|
+
// Hexadecimal exponent
|
|
72
|
+
if (baseDigits.includes('e')) {
|
|
73
|
+
for (let index: number = 0; index < digits.length; index++) {
|
|
74
|
+
if (digits.at(index) !== 'e' && digits.at(index) !== 'E') {
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (index + 1 >= digits.length || (digits.at(index + 1) !== '+' && digits.at(index + 1) !== '-')) {
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
exponentIndex = index;
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// Exponent
|
|
85
|
+
else {
|
|
86
|
+
exponentIndex = this.#indexOfAny(digits, ['e', 'E']);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// If no exponent then parse real
|
|
90
|
+
if (exponentIndex < 0) {
|
|
91
|
+
return this.#parseFractionalNumber(digits, baseDigits);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Get mantissa and exponent
|
|
95
|
+
let mantissaPart: string = digits.slice(0, exponentIndex);
|
|
96
|
+
let exponentPart: string = digits.slice(exponentIndex + 1);
|
|
97
|
+
|
|
98
|
+
// Parse mantissa and exponent
|
|
99
|
+
let mantissa: Result<number> = this.#parseFractionalNumber(mantissaPart, baseDigits);
|
|
100
|
+
if (mantissa.isError) {
|
|
101
|
+
return mantissa;
|
|
102
|
+
}
|
|
103
|
+
let exponent: Result<number> = this.#parseFractionalNumber(exponentPart, baseDigits);
|
|
104
|
+
if (exponent.isError) {
|
|
105
|
+
return exponent;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// Multiply mantissa by 10 ^ exponent
|
|
109
|
+
return Result.fromValue(mantissa.value * (10 ** exponent.value));
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Converts a fractional number (e.g. `123.45`) from the given base (e.g. `01234567`) to a base-10 real.
|
|
113
|
+
*/
|
|
114
|
+
static #parseFractionalNumber(digits: string, baseDigits: string): Result<number> {
|
|
115
|
+
// Find dot
|
|
116
|
+
let dotIndex: number = digits.indexOf('.');
|
|
117
|
+
// If no dot then normalize integer
|
|
118
|
+
if (dotIndex < 0) {
|
|
119
|
+
return this.#parseWholeNumber(digits, baseDigits);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Get parts of number
|
|
123
|
+
let wholePart: string = digits.slice(0, dotIndex);
|
|
124
|
+
let fractionalPart: string = digits.slice(dotIndex + 1);
|
|
125
|
+
|
|
126
|
+
// Parse parts of number
|
|
127
|
+
let whole: Result<number> = this.#parseWholeNumber(wholePart, baseDigits);
|
|
128
|
+
if (whole.isError) {
|
|
129
|
+
return whole;
|
|
130
|
+
}
|
|
131
|
+
let fraction: Result<number> = this.#parseWholeNumber(fractionalPart, baseDigits);
|
|
132
|
+
if (fraction.isError) {
|
|
133
|
+
return fraction;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Combine whole and fraction
|
|
137
|
+
return Result.fromValue(Number.parseFloat(whole.value + '.' + fraction.value));
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Converts a whole number (e.g. `12345`) from the given base (e.g. `01234567`) to a base-10 integer.
|
|
141
|
+
*/
|
|
142
|
+
static #parseWholeNumber(digits: string, baseDigits: string): Result<number> {
|
|
143
|
+
// Get sign
|
|
144
|
+
let sign: number = 1;
|
|
145
|
+
if (digits.startsWith('-')) {
|
|
146
|
+
sign = -1;
|
|
147
|
+
digits = digits.slice(1);
|
|
148
|
+
}
|
|
149
|
+
else if (digits.startsWith('+')) {
|
|
150
|
+
sign = 1;
|
|
151
|
+
digits = digits.slice(1);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Add each column of digits
|
|
155
|
+
let integer: number = 0;
|
|
156
|
+
for (let index: number = 0; index < digits.length; index++) {
|
|
157
|
+
// Get current digit
|
|
158
|
+
let digitChar: string = digits.at(index)!;
|
|
159
|
+
let digitInt: number = baseDigits.indexOf(digitChar.toLowerCase());
|
|
160
|
+
|
|
161
|
+
// Ensure digit is valid
|
|
162
|
+
if (digitInt < 0) {
|
|
163
|
+
return Result.fromError(new Error(`Invalid digit: '${digitChar}'`));
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Get magnitude of current digit column
|
|
167
|
+
let columnNumber: number = digits.length - 1 - index;
|
|
168
|
+
let columnMagnitude: number = baseDigits.length ** columnNumber;
|
|
169
|
+
|
|
170
|
+
// Add value of column
|
|
171
|
+
integer += digitInt * columnMagnitude;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Apply sign
|
|
175
|
+
if (sign !== 1) {
|
|
176
|
+
integer *= sign;
|
|
177
|
+
}
|
|
178
|
+
return Result.fromValue(integer);
|
|
179
|
+
}
|
|
180
|
+
static #indexOfAny(input: string, chars: ReadonlyArray<string>): number {
|
|
181
|
+
for (let i: number = 0; i < input.length; i++) {
|
|
182
|
+
let char: string = input.at(i)!;
|
|
183
|
+
if (chars.includes(char)) {
|
|
184
|
+
return i;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return -1;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export = JsonhNumberParser;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import JsonhVersion = require("./jsonh-version.js");
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Options for a JsonhReader.
|
|
5
|
+
*/
|
|
6
|
+
class JsonhReaderOptions {
|
|
7
|
+
/**
|
|
8
|
+
* Specifies the major version of the JSONH specification to use.
|
|
9
|
+
*/
|
|
10
|
+
version: JsonhVersion = JsonhVersion.Latest;
|
|
11
|
+
/**
|
|
12
|
+
* Enables/disables parsing unclosed inputs.
|
|
13
|
+
*
|
|
14
|
+
* ```
|
|
15
|
+
* {
|
|
16
|
+
"key": "val
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* This is potentially useful for large language models that stream responses.
|
|
20
|
+
*
|
|
21
|
+
* Only some tokens can be incomplete in this mode, so it should not be relied upon.
|
|
22
|
+
*/
|
|
23
|
+
incompleteInputs: boolean = false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export = JsonhReaderOptions;
|