From b5be558b5735e06505c29c5429cbdb0f8bbae4e4 Mon Sep 17 00:00:00 2001 From: hypercross Date: Wed, 22 Apr 2026 00:28:10 +0800 Subject: [PATCH] fix(parser): fix empty array and nested bracket parsing Improve the `ValueParser` to correctly disambiguate between empty arrays `[]` and the start of nested structures. This ensures that the parser can distinguish between an array containing a single element that starts with a bracket and an actual empty array. Update tests to reflect that parsed tuples are returned as arrays rather than objects. --- .../tests/parseCsv-combinators.test.ts | 26 +++++++------------ src/value-parser.ts | 21 ++++++++++++--- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/src/csv-loader/tests/parseCsv-combinators.test.ts b/src/csv-loader/tests/parseCsv-combinators.test.ts index 50b7e66..02ca286 100644 --- a/src/csv-loader/tests/parseCsv-combinators.test.ts +++ b/src/csv-loader/tests/parseCsv-combinators.test.ts @@ -183,16 +183,8 @@ describe("parseCsv - references in combinatory schemas", () => { const cactusEnemies = result.data[0].enemies as unknown[]; expect(cactusEnemies).toHaveLength(2); - expect(cactusEnemies[0]).toEqual({ - name: "仙人掌怪", - hp: 12, - effects: [], - }); - expect(cactusEnemies[1]).toEqual({ - name: "仙人掌怪", - hp: 12, - effects: [], - }); + expect(cactusEnemies[0]).toEqual(["仙人掌怪", 12, []]); + expect(cactusEnemies[1]).toEqual(["仙人掌怪", 12, []]); // Second row: snake_pair expect(result.data[1]).toMatchObject({ @@ -206,13 +198,13 @@ describe("parseCsv - references in combinatory schemas", () => { const snakeEnemies = result.data[1].enemies as unknown[]; expect(snakeEnemies).toHaveLength(1); - expect(snakeEnemies[0]).toEqual({ - name: "蛇", - hp: 10, - effects: [ - { effect: "poison", stacks: 2 }, - { effect: "quick", stacks: 1 }, + expect(snakeEnemies[0]).toEqual([ + "蛇", + 10, + [ + ["poison", 2], + ["quick", 1], ], - }); + ]); }); }); diff --git a/src/value-parser.ts b/src/value-parser.ts index ddce0dd..efda476 100644 --- a/src/value-parser.ts +++ b/src/value-parser.ts @@ -304,9 +304,23 @@ class ValueParser { if (!elementIsTupleOrArray) { this.consume(); hasOpenBracket = true; - } else if (this.input[this.pos + 1] === "[") { + } else { + // Element is tuple or array - need to disambiguate + // Save position to check if this is an empty array + const savedPos = this.pos; this.consume(); - hasOpenBracket = true; + this.skipWhitespace(); + if (this.peek() === "]") { + // Empty array [] + this.consume(); + return []; + } else if (this.peek() === "[") { + // Nested brackets [[ - this is the array opener + hasOpenBracket = true; + } else { + // [ belongs to the first element, restore position + this.pos = savedPos; + } } } @@ -324,7 +338,8 @@ class ValueParser { const result: unknown[] = []; while (true) { this.skipWhitespace(); - result.push(this.parseValue(schema.element, false)); + + result.push(this.parseValue(schema.element, elementIsTupleOrArray)); this.skipWhitespace(); if (!this.consumeStr(";")) {