Skip to content

Commit c7bc455

Browse files
committed
remove the need of quotes in the json
1 parent 999e58a commit c7bc455

File tree

6 files changed

+390
-154
lines changed

6 files changed

+390
-154
lines changed

build/index.cjs

Lines changed: 85 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,10 +40,9 @@ var assert = (condition, message = "Assertion failed") => {
4040
var assertEq = (a, b, message = "Assertion failed") => {
4141
if (a !== b) throw new Error(`${message}: '${a}' !== '${b}'`);
4242
};
43-
var numbers = "0123456789";
4443
var JsonParser = class {
4544
#queue;
46-
#last = "";
45+
#text = "";
4746
#index = 0;
4847
#stream;
4948
constructor(queue) {
@@ -54,13 +53,7 @@ var JsonParser = class {
5453
return char === " " || char === "\n" || char === " " || char === "\r";
5554
}
5655
async #next(len = 1) {
57-
let str = "";
58-
for (let i = 0; i < len; i++) {
59-
const char = await this.#queue.shiftUnsafe();
60-
if (char === import_superqueue.default.EOF) return void 0;
61-
str += char;
62-
}
63-
this.#last = str.charAt(len - 1);
56+
const str = await this.#peek(len);
6457
this.#index += len;
6558
return str;
6659
}
@@ -69,9 +62,23 @@ var JsonParser = class {
6962
assert(chunk !== void 0, `Unexpected end of JSON input at index ${this.#index}: ${message}`);
7063
return chunk;
7164
}
65+
async #peek(len = 1) {
66+
while (this.#text.length < this.#index + len) {
67+
const char = await this.#queue.shiftUnsafe();
68+
if (char === import_superqueue.default.EOF) return void 0;
69+
this.#text += char;
70+
}
71+
const result = this.#text.slice(this.#index, this.#index + len);
72+
return result;
73+
}
74+
async #peekNonEof(len, message) {
75+
const chunk = await this.#peek(len);
76+
assert(chunk !== void 0, `Unexpected end of JSON input at index ${this.#index}: ${message}`);
77+
return chunk;
78+
}
7279
async #skipWhiteSpaces() {
73-
for (let char = await this.#nextNonEof(1, "skipWhiteSpaces"); ; char = await this.#nextNonEof(1, "skipWhiteSpaces")) {
74-
if (!this.#isWhitespace(char)) return char;
80+
for (let char = await this.#peekNonEof(1, "skipWhiteSpaces"); this.#isWhitespace(char); char = await this.#peekNonEof(1, "skipWhiteSpaces")) {
81+
this.#nextNonEof();
7582
}
7683
}
7784
async #expectNext(expected) {
@@ -86,15 +93,14 @@ var JsonParser = class {
8693
throw new Error("Data must be a function when using deep: true");
8794
}
8895
const newData = data(result.data);
89-
if (newData) {
96+
if (newData !== void 0) {
9097
throw new Error(
9198
"Update data must be undefined when using deep: true"
9299
);
93100
}
94-
return;
95101
} else {
96102
const newData = data instanceof Function ? data(result.data) : data;
97-
if (!newData) {
103+
if (newData === void 0) {
98104
throw new Error("Update data cannot be undefined");
99105
}
100106
result.data = newData;
@@ -108,7 +114,8 @@ var JsonParser = class {
108114
}
109115
async parseValue(skip = true) {
110116
if (skip) await this.#skipWhiteSpaces();
111-
switch (this.#last) {
117+
const next = await this.#peekNonEof();
118+
switch (next) {
112119
case "{":
113120
return this.parseObject();
114121
case "[":
@@ -121,6 +128,7 @@ var JsonParser = class {
121128
return this.parseBoolean(false);
122129
case "n":
123130
return this.parseNull();
131+
case "-":
124132
case "0":
125133
case "1":
126134
case "2":
@@ -133,60 +141,84 @@ var JsonParser = class {
133141
case "9":
134142
return this.parseNumber();
135143
default:
136-
throw new Error(`Unexpected token ${this.#last} at index ${this.#index} while parsing value in JSON`);
144+
throw new Error(`Unexpected token ${next} at index ${this.#index} while parsing value in JSON`);
137145
}
138146
}
139147
parseObject() {
140148
return this.#wrapResult({}, async (update) => {
141-
while (true) {
149+
await this.#expectNext("{");
150+
do {
142151
await this.#skipWhiteSpaces();
143-
if (this.#last === "}") break;
144-
const key = this.parseString();
152+
if (await this.#peekNonEof() === "}") break;
153+
const key = this.parseKey();
145154
await key.wait;
146-
assertEq(await this.#skipWhiteSpaces(), ":");
155+
await this.#skipWhiteSpaces();
156+
await this.#expectNext(":");
147157
const val = await this.parseValue();
148158
update((data) => void (data[key.data] = val), true);
149159
await val.wait;
150-
if (typeof val.data !== "number" || this.#isWhitespace(this.#last)) {
151-
await this.#skipWhiteSpaces();
152-
}
153-
if (this.#last === "}") break;
154-
if (this.#last !== ",") {
155-
throw new Error(`Unexpected token ${this.#last} at index ${this.#index} while parsing object in JSON`);
156-
}
157-
}
160+
await this.#skipWhiteSpaces();
161+
if (await this.#peekNonEof() === "}") break;
162+
await this.#expectNext(",");
163+
} while (true);
164+
await this.#expectNext("}");
158165
});
159166
}
160167
parseArray() {
161168
return this.#wrapResult([], async (update) => {
162-
while (true) {
169+
await this.#expectNext("[");
170+
do {
163171
await this.#skipWhiteSpaces();
164-
if (this.#last === "]") break;
172+
if (await this.#peekNonEof() === "]") break;
165173
const val = await this.parseValue(false);
166174
update((data) => void data.push(val), true);
167175
await val.wait;
168-
if (typeof val.data !== "number" || this.#isWhitespace(this.#last)) {
169-
await this.#skipWhiteSpaces();
170-
}
171-
if (this.#last === "]") break;
172-
if (this.#last !== ",")
173-
throw new Error(`Unexpected token ${this.#last} at index ${this.#index} while parsing array in JSON`);
174-
}
176+
await this.#skipWhiteSpaces();
177+
if (await this.#peekNonEof() === "]") break;
178+
await this.#expectNext(",");
179+
} while (true);
180+
await this.#expectNext("]");
175181
});
176182
}
183+
#numbers = "0123456789";
177184
parseNumber() {
178-
return this.#wrapResult(parseInt(this.#last), async (update) => {
179-
for (let char = await this.#next(); ; char = await this.#next()) {
180-
if (!char || !(numbers.includes(char) && char !== ".")) {
181-
break;
182-
}
183-
update((num) => parseFloat(num.toString() + char));
185+
return this.#wrapResult(0, async (update) => {
186+
let str = "";
187+
const negative = await this.#peekNonEof() === "-";
188+
if (negative) {
189+
str += "-";
190+
await this.#nextNonEof();
191+
}
192+
for (let char = await this.#peekNonEof(); this.#numbers.includes(char) || char === "."; char = await this.#peekNonEof()) {
193+
await this.#nextNonEof();
194+
str += char;
195+
update(() => Number(str));
196+
}
197+
});
198+
}
199+
parseKey() {
200+
return this.#wrapResult("", async (update) => {
201+
const char = await this.#peekNonEof();
202+
const key = char === '"' ? this.parseString() : this.parseIdentifier();
203+
await key.wait;
204+
update(key.data);
205+
});
206+
}
207+
#letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_1234567890";
208+
parseIdentifier() {
209+
return this.#wrapResult("", async (update) => {
210+
for (let char = await this.#peekNonEof(); this.#letters.includes(char); char = await this.#peekNonEof()) {
211+
await this.#nextNonEof();
212+
update((id) => id + char);
184213
}
185214
});
186215
}
187216
parseString() {
188217
return this.#wrapResult("", async (update) => {
189-
for (let char = await this.#nextNonEof(); char !== '"'; char = await this.#nextNonEof()) {
218+
await this.#expectNext('"');
219+
await this.#peekNonEof();
220+
while (await this.#peekNonEof() !== '"') {
221+
const char = await this.#nextNonEof();
190222
if (char !== "\\") {
191223
update((str) => str + char);
192224
continue;
@@ -212,19 +244,21 @@ var JsonParser = class {
212244
} else if (nextChar === "U") {
213245
const char2 = parseInt(await this.#nextNonEof(8), 16);
214246
update((str) => str + String.fromCharCode(char2));
247+
} else {
248+
throw new Error(`Invalid escape sequence ${nextChar} at index ${this.#index} in JSON`);
215249
}
216-
throw new Error(`Invalid escape sequence ${nextChar} at index ${this.#index} in JSON`);
217250
}
251+
await this.#expectNext('"');
218252
});
219253
}
220254
parseBoolean(expected) {
221255
return this.#wrapResult(
222256
expected,
223-
() => this.#expectNext(expected ? "rue" : "alse")
257+
() => this.#expectNext(expected ? "true" : "false")
224258
);
225259
}
226260
parseNull() {
227-
return this.#wrapResult(null, () => this.#expectNext("ull"));
261+
return this.#wrapResult(null, () => this.#expectNext("null"));
228262
}
229263
async resolve() {
230264
return this.#resolve(await this.#stream);
@@ -234,7 +268,10 @@ var JsonParser = class {
234268
case "object":
235269
if (Array.isArray(stream.data)) {
236270
return stream.data.map(this.#resolve);
237-
} else {
271+
} else if (stream.data === null) {
272+
return null;
273+
}
274+
{
238275
const result = {};
239276
for (const key in stream.data) {
240277
result[key] = this.#resolve(stream.data[key]);

build/index.d.cts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ declare class JsonParser<T> {
1616
parseObject(): JSONStreamResult<JSONObjectStream>;
1717
parseArray(): JSONStreamResult<JSONArrayStream>;
1818
parseNumber(): JSONStreamResult<number>;
19+
parseKey(): JSONStreamResult<string>;
20+
parseIdentifier(): JSONStreamResult<string>;
1921
parseString(): JSONStreamResult<string>;
2022
parseBoolean(expected: boolean): JSONStreamResult<boolean>;
2123
parseNull(): JSONStreamResult<null>;

build/index.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ declare class JsonParser<T> {
1616
parseObject(): JSONStreamResult<JSONObjectStream>;
1717
parseArray(): JSONStreamResult<JSONArrayStream>;
1818
parseNumber(): JSONStreamResult<number>;
19+
parseKey(): JSONStreamResult<string>;
20+
parseIdentifier(): JSONStreamResult<string>;
1921
parseString(): JSONStreamResult<string>;
2022
parseBoolean(expected: boolean): JSONStreamResult<boolean>;
2123
parseNull(): JSONStreamResult<null>;

0 commit comments

Comments
 (0)