modelfusion 0.35.0 → 0.35.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.
@@ -4,69 +4,121 @@ exports.fixJson = void 0;
4
4
  // Implemented as a scanner with additional fixing
5
5
  // that performs a single linear time scan pass over the partial JSON:
6
6
  function fixJson(input) {
7
- const stack = ["BEFORE_VALUE"];
7
+ const stack = ["ROOT"];
8
8
  let lastValidIndex = -1;
9
9
  let literalStart = null;
10
+ function processValueStart(char, i, swapState) {
11
+ {
12
+ switch (char) {
13
+ case '"': {
14
+ lastValidIndex = i;
15
+ stack.pop();
16
+ stack.push(swapState);
17
+ stack.push("INSIDE_STRING");
18
+ break;
19
+ }
20
+ case "f":
21
+ case "t":
22
+ case "n": {
23
+ lastValidIndex = i;
24
+ literalStart = i;
25
+ stack.pop();
26
+ stack.push(swapState);
27
+ stack.push("INSIDE_LITERAL");
28
+ break;
29
+ }
30
+ case "-": {
31
+ stack.pop();
32
+ stack.push(swapState);
33
+ stack.push("INSIDE_NUMBER");
34
+ break;
35
+ }
36
+ case "0":
37
+ case "1":
38
+ case "2":
39
+ case "3":
40
+ case "4":
41
+ case "5":
42
+ case "6":
43
+ case "7":
44
+ case "8":
45
+ case "9": {
46
+ lastValidIndex = i;
47
+ stack.pop();
48
+ stack.push(swapState);
49
+ stack.push("INSIDE_NUMBER");
50
+ break;
51
+ }
52
+ case "{": {
53
+ lastValidIndex = i;
54
+ stack.pop();
55
+ stack.push(swapState);
56
+ stack.push("INSIDE_OBJECT_START");
57
+ break;
58
+ }
59
+ case "[": {
60
+ lastValidIndex = i;
61
+ stack.pop();
62
+ stack.push(swapState);
63
+ stack.push("INSIDE_ARRAY_START");
64
+ break;
65
+ }
66
+ }
67
+ }
68
+ }
69
+ function processAfterObjectValue(char, i) {
70
+ switch (char) {
71
+ case ",": {
72
+ stack.pop();
73
+ stack.push("INSIDE_OBJECT_AFTER_COMMA");
74
+ break;
75
+ }
76
+ case "}": {
77
+ lastValidIndex = i;
78
+ stack.pop();
79
+ break;
80
+ }
81
+ }
82
+ }
83
+ function processAfterArrayValue(char, i) {
84
+ switch (char) {
85
+ case ",": {
86
+ stack.pop();
87
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
88
+ break;
89
+ }
90
+ case "]": {
91
+ lastValidIndex = i;
92
+ stack.pop();
93
+ break;
94
+ }
95
+ }
96
+ }
10
97
  for (let i = 0; i < input.length; i++) {
11
98
  const char = input[i];
12
99
  const currentState = stack[stack.length - 1];
13
100
  switch (currentState) {
14
- case "BEFORE_VALUE": {
101
+ case "ROOT":
102
+ processValueStart(char, i, "FINISH");
103
+ break;
104
+ case "INSIDE_OBJECT_START": {
15
105
  switch (char) {
16
106
  case '"': {
17
- lastValidIndex = i;
18
- stack.pop();
19
- stack.push("INSIDE_STRING");
20
- break;
21
- }
22
- case "f":
23
- case "t":
24
- case "n": {
25
- lastValidIndex = i;
26
- literalStart = i;
27
- stack.pop();
28
- stack.push("INSIDE_LITERAL");
29
- break;
30
- }
31
- case "-": {
32
107
  stack.pop();
33
- stack.push("INSIDE_NUMBER");
34
- break;
35
- }
36
- case "0":
37
- case "1":
38
- case "2":
39
- case "3":
40
- case "4":
41
- case "5":
42
- case "6":
43
- case "7":
44
- case "8":
45
- case "9": {
46
- lastValidIndex = i;
47
- stack.pop();
48
- stack.push("INSIDE_NUMBER");
49
- break;
50
- }
51
- case "{": {
52
- lastValidIndex = i;
53
- stack.pop();
54
- stack.push("INSIDE_OBJECT");
108
+ stack.push("INSIDE_OBJECT_KEY");
55
109
  break;
56
110
  }
57
- case "[": {
58
- lastValidIndex = i;
111
+ case "}": {
59
112
  stack.pop();
60
- stack.push("INSIDE_ARRAY");
61
- stack.push("BEFORE_VALUE");
62
113
  break;
63
114
  }
64
115
  }
65
116
  break;
66
117
  }
67
- case "INSIDE_OBJECT": {
118
+ case "INSIDE_OBJECT_AFTER_COMMA": {
68
119
  switch (char) {
69
120
  case '"': {
121
+ stack.pop();
70
122
  stack.push("INSIDE_OBJECT_KEY");
71
123
  break;
72
124
  }
@@ -77,22 +129,30 @@ function fixJson(input) {
77
129
  switch (char) {
78
130
  case '"': {
79
131
  stack.pop();
80
- stack.push("AFTER_OBJECT_KEY");
132
+ stack.push("INSIDE_OBJECT_AFTER_KEY");
81
133
  break;
82
134
  }
83
135
  }
84
136
  break;
85
137
  }
86
- case "AFTER_OBJECT_KEY": {
138
+ case "INSIDE_OBJECT_AFTER_KEY": {
87
139
  switch (char) {
88
140
  case ":": {
89
141
  stack.pop();
90
- stack.push("BEFORE_VALUE");
142
+ stack.push("INSIDE_OBJECT_BEFORE_VALUE");
91
143
  break;
92
144
  }
93
145
  }
94
146
  break;
95
147
  }
148
+ case "INSIDE_OBJECT_BEFORE_VALUE": {
149
+ processValueStart(char, i, "INSIDE_OBJECT_AFTER_VALUE");
150
+ break;
151
+ }
152
+ case "INSIDE_OBJECT_AFTER_VALUE": {
153
+ processAfterObjectValue(char, i);
154
+ break;
155
+ }
96
156
  case "INSIDE_STRING": {
97
157
  switch (char) {
98
158
  case '"': {
@@ -110,10 +170,31 @@ function fixJson(input) {
110
170
  }
111
171
  break;
112
172
  }
113
- case "INSIDE_ARRAY": {
173
+ case "INSIDE_ARRAY_START": {
174
+ switch (char) {
175
+ case "]": {
176
+ lastValidIndex = i;
177
+ stack.pop();
178
+ break;
179
+ }
180
+ default: {
181
+ lastValidIndex = i;
182
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
183
+ break;
184
+ }
185
+ }
186
+ break;
187
+ }
188
+ case "INSIDE_ARRAY_AFTER_VALUE": {
114
189
  switch (char) {
115
190
  case ",": {
116
- stack.push("BEFORE_VALUE");
191
+ stack.pop();
192
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
193
+ break;
194
+ }
195
+ case "]": {
196
+ lastValidIndex = i;
197
+ stack.pop();
117
198
  break;
118
199
  }
119
200
  default: {
@@ -123,6 +204,10 @@ function fixJson(input) {
123
204
  }
124
205
  break;
125
206
  }
207
+ case "INSIDE_ARRAY_AFTER_COMMA": {
208
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
209
+ break;
210
+ }
126
211
  case "INSIDE_STRING_ESCAPE": {
127
212
  stack.pop();
128
213
  lastValidIndex = i;
@@ -151,8 +236,25 @@ function fixJson(input) {
151
236
  }
152
237
  case ",": {
153
238
  stack.pop();
154
- if (stack[stack.length - 1] === "INSIDE_ARRAY") {
155
- stack.push("BEFORE_VALUE");
239
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
240
+ processAfterArrayValue(char, i);
241
+ }
242
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
243
+ processAfterObjectValue(char, i);
244
+ }
245
+ break;
246
+ }
247
+ case "}": {
248
+ stack.pop();
249
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
250
+ processAfterObjectValue(char, i);
251
+ }
252
+ break;
253
+ }
254
+ case "]": {
255
+ stack.pop();
256
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
257
+ processAfterArrayValue(char, i);
156
258
  }
157
259
  break;
158
260
  }
@@ -164,13 +266,16 @@ function fixJson(input) {
164
266
  break;
165
267
  }
166
268
  case "INSIDE_LITERAL": {
167
- const partialLiteral = input.substring(literalStart, i);
269
+ const partialLiteral = input.substring(literalStart, i + 1);
168
270
  if (!"false".startsWith(partialLiteral) &&
169
271
  !"true".startsWith(partialLiteral) &&
170
272
  !"null".startsWith(partialLiteral)) {
171
273
  stack.pop();
172
- if (stack[stack.length - 1] === "INSIDE_ARRAY") {
173
- stack.push("BEFORE_VALUE");
274
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
275
+ processAfterObjectValue(char, i);
276
+ }
277
+ else if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
278
+ processAfterArrayValue(char, i);
174
279
  }
175
280
  }
176
281
  else {
@@ -188,11 +293,18 @@ function fixJson(input) {
188
293
  result += '"';
189
294
  break;
190
295
  }
191
- case "INSIDE_OBJECT": {
296
+ case "INSIDE_OBJECT_KEY":
297
+ case "INSIDE_OBJECT_AFTER_KEY":
298
+ case "INSIDE_OBJECT_AFTER_COMMA":
299
+ case "INSIDE_OBJECT_START":
300
+ case "INSIDE_OBJECT_BEFORE_VALUE":
301
+ case "INSIDE_OBJECT_AFTER_VALUE": {
192
302
  result += "}";
193
303
  break;
194
304
  }
195
- case "INSIDE_ARRAY": {
305
+ case "INSIDE_ARRAY_START":
306
+ case "INSIDE_ARRAY_AFTER_COMMA":
307
+ case "INSIDE_ARRAY_AFTER_VALUE": {
196
308
  result += "]";
197
309
  break;
198
310
  }
@@ -1,69 +1,121 @@
1
1
  // Implemented as a scanner with additional fixing
2
2
  // that performs a single linear time scan pass over the partial JSON:
3
3
  export function fixJson(input) {
4
- const stack = ["BEFORE_VALUE"];
4
+ const stack = ["ROOT"];
5
5
  let lastValidIndex = -1;
6
6
  let literalStart = null;
7
+ function processValueStart(char, i, swapState) {
8
+ {
9
+ switch (char) {
10
+ case '"': {
11
+ lastValidIndex = i;
12
+ stack.pop();
13
+ stack.push(swapState);
14
+ stack.push("INSIDE_STRING");
15
+ break;
16
+ }
17
+ case "f":
18
+ case "t":
19
+ case "n": {
20
+ lastValidIndex = i;
21
+ literalStart = i;
22
+ stack.pop();
23
+ stack.push(swapState);
24
+ stack.push("INSIDE_LITERAL");
25
+ break;
26
+ }
27
+ case "-": {
28
+ stack.pop();
29
+ stack.push(swapState);
30
+ stack.push("INSIDE_NUMBER");
31
+ break;
32
+ }
33
+ case "0":
34
+ case "1":
35
+ case "2":
36
+ case "3":
37
+ case "4":
38
+ case "5":
39
+ case "6":
40
+ case "7":
41
+ case "8":
42
+ case "9": {
43
+ lastValidIndex = i;
44
+ stack.pop();
45
+ stack.push(swapState);
46
+ stack.push("INSIDE_NUMBER");
47
+ break;
48
+ }
49
+ case "{": {
50
+ lastValidIndex = i;
51
+ stack.pop();
52
+ stack.push(swapState);
53
+ stack.push("INSIDE_OBJECT_START");
54
+ break;
55
+ }
56
+ case "[": {
57
+ lastValidIndex = i;
58
+ stack.pop();
59
+ stack.push(swapState);
60
+ stack.push("INSIDE_ARRAY_START");
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ }
66
+ function processAfterObjectValue(char, i) {
67
+ switch (char) {
68
+ case ",": {
69
+ stack.pop();
70
+ stack.push("INSIDE_OBJECT_AFTER_COMMA");
71
+ break;
72
+ }
73
+ case "}": {
74
+ lastValidIndex = i;
75
+ stack.pop();
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ function processAfterArrayValue(char, i) {
81
+ switch (char) {
82
+ case ",": {
83
+ stack.pop();
84
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
85
+ break;
86
+ }
87
+ case "]": {
88
+ lastValidIndex = i;
89
+ stack.pop();
90
+ break;
91
+ }
92
+ }
93
+ }
7
94
  for (let i = 0; i < input.length; i++) {
8
95
  const char = input[i];
9
96
  const currentState = stack[stack.length - 1];
10
97
  switch (currentState) {
11
- case "BEFORE_VALUE": {
98
+ case "ROOT":
99
+ processValueStart(char, i, "FINISH");
100
+ break;
101
+ case "INSIDE_OBJECT_START": {
12
102
  switch (char) {
13
103
  case '"': {
14
- lastValidIndex = i;
15
- stack.pop();
16
- stack.push("INSIDE_STRING");
17
- break;
18
- }
19
- case "f":
20
- case "t":
21
- case "n": {
22
- lastValidIndex = i;
23
- literalStart = i;
24
- stack.pop();
25
- stack.push("INSIDE_LITERAL");
26
- break;
27
- }
28
- case "-": {
29
104
  stack.pop();
30
- stack.push("INSIDE_NUMBER");
31
- break;
32
- }
33
- case "0":
34
- case "1":
35
- case "2":
36
- case "3":
37
- case "4":
38
- case "5":
39
- case "6":
40
- case "7":
41
- case "8":
42
- case "9": {
43
- lastValidIndex = i;
44
- stack.pop();
45
- stack.push("INSIDE_NUMBER");
46
- break;
47
- }
48
- case "{": {
49
- lastValidIndex = i;
50
- stack.pop();
51
- stack.push("INSIDE_OBJECT");
105
+ stack.push("INSIDE_OBJECT_KEY");
52
106
  break;
53
107
  }
54
- case "[": {
55
- lastValidIndex = i;
108
+ case "}": {
56
109
  stack.pop();
57
- stack.push("INSIDE_ARRAY");
58
- stack.push("BEFORE_VALUE");
59
110
  break;
60
111
  }
61
112
  }
62
113
  break;
63
114
  }
64
- case "INSIDE_OBJECT": {
115
+ case "INSIDE_OBJECT_AFTER_COMMA": {
65
116
  switch (char) {
66
117
  case '"': {
118
+ stack.pop();
67
119
  stack.push("INSIDE_OBJECT_KEY");
68
120
  break;
69
121
  }
@@ -74,22 +126,30 @@ export function fixJson(input) {
74
126
  switch (char) {
75
127
  case '"': {
76
128
  stack.pop();
77
- stack.push("AFTER_OBJECT_KEY");
129
+ stack.push("INSIDE_OBJECT_AFTER_KEY");
78
130
  break;
79
131
  }
80
132
  }
81
133
  break;
82
134
  }
83
- case "AFTER_OBJECT_KEY": {
135
+ case "INSIDE_OBJECT_AFTER_KEY": {
84
136
  switch (char) {
85
137
  case ":": {
86
138
  stack.pop();
87
- stack.push("BEFORE_VALUE");
139
+ stack.push("INSIDE_OBJECT_BEFORE_VALUE");
88
140
  break;
89
141
  }
90
142
  }
91
143
  break;
92
144
  }
145
+ case "INSIDE_OBJECT_BEFORE_VALUE": {
146
+ processValueStart(char, i, "INSIDE_OBJECT_AFTER_VALUE");
147
+ break;
148
+ }
149
+ case "INSIDE_OBJECT_AFTER_VALUE": {
150
+ processAfterObjectValue(char, i);
151
+ break;
152
+ }
93
153
  case "INSIDE_STRING": {
94
154
  switch (char) {
95
155
  case '"': {
@@ -107,10 +167,31 @@ export function fixJson(input) {
107
167
  }
108
168
  break;
109
169
  }
110
- case "INSIDE_ARRAY": {
170
+ case "INSIDE_ARRAY_START": {
171
+ switch (char) {
172
+ case "]": {
173
+ lastValidIndex = i;
174
+ stack.pop();
175
+ break;
176
+ }
177
+ default: {
178
+ lastValidIndex = i;
179
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
180
+ break;
181
+ }
182
+ }
183
+ break;
184
+ }
185
+ case "INSIDE_ARRAY_AFTER_VALUE": {
111
186
  switch (char) {
112
187
  case ",": {
113
- stack.push("BEFORE_VALUE");
188
+ stack.pop();
189
+ stack.push("INSIDE_ARRAY_AFTER_COMMA");
190
+ break;
191
+ }
192
+ case "]": {
193
+ lastValidIndex = i;
194
+ stack.pop();
114
195
  break;
115
196
  }
116
197
  default: {
@@ -120,6 +201,10 @@ export function fixJson(input) {
120
201
  }
121
202
  break;
122
203
  }
204
+ case "INSIDE_ARRAY_AFTER_COMMA": {
205
+ processValueStart(char, i, "INSIDE_ARRAY_AFTER_VALUE");
206
+ break;
207
+ }
123
208
  case "INSIDE_STRING_ESCAPE": {
124
209
  stack.pop();
125
210
  lastValidIndex = i;
@@ -148,8 +233,25 @@ export function fixJson(input) {
148
233
  }
149
234
  case ",": {
150
235
  stack.pop();
151
- if (stack[stack.length - 1] === "INSIDE_ARRAY") {
152
- stack.push("BEFORE_VALUE");
236
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
237
+ processAfterArrayValue(char, i);
238
+ }
239
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
240
+ processAfterObjectValue(char, i);
241
+ }
242
+ break;
243
+ }
244
+ case "}": {
245
+ stack.pop();
246
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
247
+ processAfterObjectValue(char, i);
248
+ }
249
+ break;
250
+ }
251
+ case "]": {
252
+ stack.pop();
253
+ if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
254
+ processAfterArrayValue(char, i);
153
255
  }
154
256
  break;
155
257
  }
@@ -161,13 +263,16 @@ export function fixJson(input) {
161
263
  break;
162
264
  }
163
265
  case "INSIDE_LITERAL": {
164
- const partialLiteral = input.substring(literalStart, i);
266
+ const partialLiteral = input.substring(literalStart, i + 1);
165
267
  if (!"false".startsWith(partialLiteral) &&
166
268
  !"true".startsWith(partialLiteral) &&
167
269
  !"null".startsWith(partialLiteral)) {
168
270
  stack.pop();
169
- if (stack[stack.length - 1] === "INSIDE_ARRAY") {
170
- stack.push("BEFORE_VALUE");
271
+ if (stack[stack.length - 1] === "INSIDE_OBJECT_AFTER_VALUE") {
272
+ processAfterObjectValue(char, i);
273
+ }
274
+ else if (stack[stack.length - 1] === "INSIDE_ARRAY_AFTER_VALUE") {
275
+ processAfterArrayValue(char, i);
171
276
  }
172
277
  }
173
278
  else {
@@ -185,11 +290,18 @@ export function fixJson(input) {
185
290
  result += '"';
186
291
  break;
187
292
  }
188
- case "INSIDE_OBJECT": {
293
+ case "INSIDE_OBJECT_KEY":
294
+ case "INSIDE_OBJECT_AFTER_KEY":
295
+ case "INSIDE_OBJECT_AFTER_COMMA":
296
+ case "INSIDE_OBJECT_START":
297
+ case "INSIDE_OBJECT_BEFORE_VALUE":
298
+ case "INSIDE_OBJECT_AFTER_VALUE": {
189
299
  result += "}";
190
300
  break;
191
301
  }
192
- case "INSIDE_ARRAY": {
302
+ case "INSIDE_ARRAY_START":
303
+ case "INSIDE_ARRAY_AFTER_COMMA":
304
+ case "INSIDE_ARRAY_AFTER_VALUE": {
193
305
  result += "]";
194
306
  break;
195
307
  }
@@ -66,19 +66,46 @@ const fixJson_1 = require("./fixJson");
66
66
  (0, vitest_1.test)("should handle incomplete array", () => {
67
67
  (0, vitest_1.expect)((0, fixJson_1.fixJson)("[")).toBe("[]");
68
68
  });
69
+ (0, vitest_1.test)("should handle closing bracket after number in array", () => {
70
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)("[[1], [2")).toBe("[[1], [2]]");
71
+ });
72
+ (0, vitest_1.test)("should handle closing bracket after string in array", () => {
73
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)(`[["1"], ["2`)).toBe(`[["1"], ["2"]]`);
74
+ });
75
+ (0, vitest_1.test)("should handle closing bracket after literal in array", () => {
76
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)("[[false], [nu")).toBe("[[false], [null]]");
77
+ });
78
+ (0, vitest_1.test)("should handle closing bracket after array in array", () => {
79
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)("[[[]], [[]")).toBe("[[[]], [[]]]");
80
+ });
81
+ (0, vitest_1.test)("should handle closing bracket after object in array", () => {
82
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)("[[{}], [{")).toBe("[[{}], [{}]]");
83
+ });
69
84
  (0, vitest_1.test)("should handle trailing comma", () => {
70
85
  (0, vitest_1.expect)((0, fixJson_1.fixJson)("[1, ")).toBe("[1]");
71
86
  });
72
87
  (0, vitest_1.test)("should handle closing array", () => {
73
- (0, vitest_1.expect)((0, fixJson_1.fixJson)('["a": [], "b": 123')).toBe('["a": [], "b": 123]');
88
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)("[[], 123")).toBe("[[], 123]");
74
89
  });
75
90
  });
76
91
  (0, vitest_1.describe)("object", () => {
77
92
  (0, vitest_1.test)("should handle keys without values", () => {
78
93
  (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"key":')).toBe("{}");
79
94
  });
80
- (0, vitest_1.test)("should handle closing brace in object", () => {
81
- (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": 1}')).toBe('{"a": {"b": 1}}');
95
+ (0, vitest_1.test)("should handle closing brace after number in object", () => {
96
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": 1}, "c": {"d": 2')).toBe('{"a": {"b": 1}, "c": {"d": 2}}');
97
+ });
98
+ (0, vitest_1.test)("should handle closing brace after string in object", () => {
99
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": "1"}, "c": {"d": 2')).toBe('{"a": {"b": "1"}, "c": {"d": 2}}');
100
+ });
101
+ (0, vitest_1.test)("should handle closing brace after literal in object", () => {
102
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": false}, "c": {"d": 2')).toBe('{"a": {"b": false}, "c": {"d": 2}}');
103
+ });
104
+ (0, vitest_1.test)("should handle closing brace after array in object", () => {
105
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": []}, "c": {"d": 2')).toBe('{"a": {"b": []}, "c": {"d": 2}}');
106
+ });
107
+ (0, vitest_1.test)("should handle closing brace after object in object", () => {
108
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": {"b": {}}, "c": {"d": 2')).toBe('{"a": {"b": {}}, "c": {"d": 2}}');
82
109
  });
83
110
  (0, vitest_1.test)("should handle partial keys (first key)", () => {
84
111
  (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"ke')).toBe("{}");
@@ -127,4 +154,33 @@ const fixJson_1 = require("./fixJson");
127
154
  (0, vitest_1.expect)((0, fixJson_1.fixJson)('{"a": 1, "b": "')).toBe('{"a": 1, "b": ""}');
128
155
  });
129
156
  });
157
+ (0, vitest_1.describe)("regression", () => {
158
+ (0, vitest_1.test)("should handle complex nesting 1", () => {
159
+ (0, vitest_1.expect)((0, fixJson_1.fixJson)([
160
+ "{",
161
+ ' "a": [',
162
+ " {",
163
+ ' "a1": "v1",',
164
+ ' "a2": "v2",',
165
+ ` "a3": "v3"`,
166
+ " }",
167
+ " ],",
168
+ ' "b": [',
169
+ " {",
170
+ ' "b1": "n',
171
+ ].join("\n"))).toBe([
172
+ "{",
173
+ ' "a": [',
174
+ " {",
175
+ ' "a1": "v1",',
176
+ ' "a2": "v2",',
177
+ ` "a3": "v3"`,
178
+ " }",
179
+ " ],",
180
+ ' "b": [',
181
+ " {",
182
+ ' "b1": "n"}]}',
183
+ ].join("\n"));
184
+ });
185
+ });
130
186
  });
@@ -64,19 +64,46 @@ describe("fixJson", () => {
64
64
  test("should handle incomplete array", () => {
65
65
  expect(fixJson("[")).toBe("[]");
66
66
  });
67
+ test("should handle closing bracket after number in array", () => {
68
+ expect(fixJson("[[1], [2")).toBe("[[1], [2]]");
69
+ });
70
+ test("should handle closing bracket after string in array", () => {
71
+ expect(fixJson(`[["1"], ["2`)).toBe(`[["1"], ["2"]]`);
72
+ });
73
+ test("should handle closing bracket after literal in array", () => {
74
+ expect(fixJson("[[false], [nu")).toBe("[[false], [null]]");
75
+ });
76
+ test("should handle closing bracket after array in array", () => {
77
+ expect(fixJson("[[[]], [[]")).toBe("[[[]], [[]]]");
78
+ });
79
+ test("should handle closing bracket after object in array", () => {
80
+ expect(fixJson("[[{}], [{")).toBe("[[{}], [{}]]");
81
+ });
67
82
  test("should handle trailing comma", () => {
68
83
  expect(fixJson("[1, ")).toBe("[1]");
69
84
  });
70
85
  test("should handle closing array", () => {
71
- expect(fixJson('["a": [], "b": 123')).toBe('["a": [], "b": 123]');
86
+ expect(fixJson("[[], 123")).toBe("[[], 123]");
72
87
  });
73
88
  });
74
89
  describe("object", () => {
75
90
  test("should handle keys without values", () => {
76
91
  expect(fixJson('{"key":')).toBe("{}");
77
92
  });
78
- test("should handle closing brace in object", () => {
79
- expect(fixJson('{"a": {"b": 1}')).toBe('{"a": {"b": 1}}');
93
+ test("should handle closing brace after number in object", () => {
94
+ expect(fixJson('{"a": {"b": 1}, "c": {"d": 2')).toBe('{"a": {"b": 1}, "c": {"d": 2}}');
95
+ });
96
+ test("should handle closing brace after string in object", () => {
97
+ expect(fixJson('{"a": {"b": "1"}, "c": {"d": 2')).toBe('{"a": {"b": "1"}, "c": {"d": 2}}');
98
+ });
99
+ test("should handle closing brace after literal in object", () => {
100
+ expect(fixJson('{"a": {"b": false}, "c": {"d": 2')).toBe('{"a": {"b": false}, "c": {"d": 2}}');
101
+ });
102
+ test("should handle closing brace after array in object", () => {
103
+ expect(fixJson('{"a": {"b": []}, "c": {"d": 2')).toBe('{"a": {"b": []}, "c": {"d": 2}}');
104
+ });
105
+ test("should handle closing brace after object in object", () => {
106
+ expect(fixJson('{"a": {"b": {}}, "c": {"d": 2')).toBe('{"a": {"b": {}}, "c": {"d": 2}}');
80
107
  });
81
108
  test("should handle partial keys (first key)", () => {
82
109
  expect(fixJson('{"ke')).toBe("{}");
@@ -125,4 +152,33 @@ describe("fixJson", () => {
125
152
  expect(fixJson('{"a": 1, "b": "')).toBe('{"a": 1, "b": ""}');
126
153
  });
127
154
  });
155
+ describe("regression", () => {
156
+ test("should handle complex nesting 1", () => {
157
+ expect(fixJson([
158
+ "{",
159
+ ' "a": [',
160
+ " {",
161
+ ' "a1": "v1",',
162
+ ' "a2": "v2",',
163
+ ` "a3": "v3"`,
164
+ " }",
165
+ " ],",
166
+ ' "b": [',
167
+ " {",
168
+ ' "b1": "n',
169
+ ].join("\n"))).toBe([
170
+ "{",
171
+ ' "a": [',
172
+ " {",
173
+ ' "a1": "v1",',
174
+ ' "a2": "v2",',
175
+ ` "a3": "v3"`,
176
+ " }",
177
+ " ],",
178
+ ' "b": [',
179
+ " {",
180
+ ' "b1": "n"}]}',
181
+ ].join("\n"));
182
+ });
183
+ });
128
184
  });
@@ -3,7 +3,7 @@ import { AsyncIterableResultPromise } from "../AsyncIterableResultPromise.js";
3
3
  import { DeltaEvent } from "../DeltaEvent.js";
4
4
  import { ModelFunctionOptions } from "../ModelFunctionOptions.js";
5
5
  import { StructureGenerationModel, StructureGenerationModelSettings } from "./StructureGenerationModel.js";
6
- type StructureStreamPart<STRUCTURE> = {
6
+ export type StructureStreamPart<STRUCTURE> = {
7
7
  isComplete: false;
8
8
  value: unknown;
9
9
  } | {
@@ -14,4 +14,3 @@ export declare function streamStructure<STRUCTURE, PROMPT, FULL_DELTA, NAME exte
14
14
  generateStructureStreamResponse: (structureDefinition: StructureDefinition<NAME, STRUCTURE>, prompt: PROMPT, options: ModelFunctionOptions<SETTINGS>) => PromiseLike<AsyncIterable<DeltaEvent<FULL_DELTA>>>;
15
15
  extractPartialStructure: (fullDelta: FULL_DELTA) => unknown | undefined;
16
16
  }, structureDefinition: StructureDefinition<NAME, STRUCTURE>, prompt: PROMPT, options?: ModelFunctionOptions<SETTINGS>): AsyncIterableResultPromise<StructureStreamPart<STRUCTURE>>;
17
- export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "modelfusion",
3
3
  "description": "Build multimodal applications, chatbots, and agents with JavaScript and TypeScript.",
4
- "version": "0.35.0",
4
+ "version": "0.35.1",
5
5
  "author": "Lars Grammel",
6
6
  "license": "MIT",
7
7
  "keywords": [