turbo-stream 2.2.0 → 2.2.2

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/dist/flatten.js CHANGED
@@ -28,135 +28,139 @@ exports.flatten = flatten;
28
28
  function stringify(input, index) {
29
29
  const { deferred, plugins } = this;
30
30
  const str = this.stringified;
31
- const partsForObj = (obj) => Object.keys(obj)
32
- .map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`)
33
- .join(",");
34
- switch (typeof input) {
35
- case "boolean":
36
- case "number":
37
- case "string":
38
- str[index] = JSON.stringify(input);
39
- break;
40
- case "bigint":
41
- str[index] = `["${utils_js_1.TYPE_BIGINT}","${input}"]`;
42
- break;
43
- case "symbol": {
44
- const keyFor = Symbol.keyFor(input);
45
- if (!keyFor)
46
- throw new Error("Cannot encode symbol unless created with Symbol.for()");
47
- str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
48
- break;
49
- }
50
- case "object": {
51
- if (!input) {
52
- str[index] = `${utils_js_1.NULL}`;
31
+ const stack = [[input, index]];
32
+ while (stack.length > 0) {
33
+ const [input, index] = stack.pop();
34
+ const partsForObj = (obj) => Object.keys(obj)
35
+ .map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`)
36
+ .join(",");
37
+ switch (typeof input) {
38
+ case "boolean":
39
+ case "number":
40
+ case "string":
41
+ str[index] = JSON.stringify(input);
42
+ break;
43
+ case "bigint":
44
+ str[index] = `["${utils_js_1.TYPE_BIGINT}","${input}"]`;
45
+ break;
46
+ case "symbol": {
47
+ const keyFor = Symbol.keyFor(input);
48
+ if (!keyFor)
49
+ throw new Error("Cannot encode symbol unless created with Symbol.for()");
50
+ str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
53
51
  break;
54
52
  }
55
- const isArray = Array.isArray(input);
56
- let pluginHandled = false;
57
- if (!isArray && plugins) {
58
- for (const plugin of plugins) {
59
- const pluginResult = plugin(input);
60
- if (Array.isArray(pluginResult)) {
61
- pluginHandled = true;
62
- const [pluginIdentifier, ...rest] = pluginResult;
63
- str[index] = `[${JSON.stringify(pluginIdentifier)}`;
64
- if (rest.length > 0) {
65
- str[index] += `,${rest
66
- .map((v) => flatten.call(this, v))
67
- .join(",")}`;
53
+ case "object": {
54
+ if (!input) {
55
+ str[index] = `${utils_js_1.NULL}`;
56
+ break;
57
+ }
58
+ const isArray = Array.isArray(input);
59
+ let pluginHandled = false;
60
+ if (!isArray && plugins) {
61
+ for (const plugin of plugins) {
62
+ const pluginResult = plugin(input);
63
+ if (Array.isArray(pluginResult)) {
64
+ pluginHandled = true;
65
+ const [pluginIdentifier, ...rest] = pluginResult;
66
+ str[index] = `[${JSON.stringify(pluginIdentifier)}`;
67
+ if (rest.length > 0) {
68
+ str[index] += `,${rest
69
+ .map((v) => flatten.call(this, v))
70
+ .join(",")}`;
71
+ }
72
+ str[index] += "]";
73
+ break;
68
74
  }
69
- str[index] += "]";
70
- break;
71
75
  }
72
76
  }
73
- }
74
- if (!pluginHandled) {
75
- let result = isArray ? "[" : "{";
76
- if (isArray) {
77
- for (let i = 0; i < input.length; i++)
78
- result +=
79
- (i ? "," : "") +
80
- (i in input ? flatten.call(this, input[i]) : utils_js_1.HOLE);
81
- str[index] = `${result}]`;
82
- }
83
- else if (input instanceof Date) {
84
- str[index] = `["${utils_js_1.TYPE_DATE}",${input.getTime()}]`;
85
- }
86
- else if (input instanceof URL) {
87
- str[index] = `["${utils_js_1.TYPE_URL}",${JSON.stringify(input.href)}]`;
88
- }
89
- else if (input instanceof RegExp) {
90
- str[index] = `["${utils_js_1.TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
91
- }
92
- else if (input instanceof Set) {
93
- if (input.size > 0) {
94
- str[index] = `["${utils_js_1.TYPE_SET}",${[...input]
95
- .map((val) => flatten.call(this, val))
96
- .join(",")}]`;
77
+ if (!pluginHandled) {
78
+ let result = isArray ? "[" : "{";
79
+ if (isArray) {
80
+ for (let i = 0; i < input.length; i++)
81
+ result +=
82
+ (i ? "," : "") +
83
+ (i in input ? flatten.call(this, input[i]) : utils_js_1.HOLE);
84
+ str[index] = `${result}]`;
97
85
  }
98
- else {
99
- str[index] = `["${utils_js_1.TYPE_SET}"]`;
86
+ else if (input instanceof Date) {
87
+ str[index] = `["${utils_js_1.TYPE_DATE}",${input.getTime()}]`;
100
88
  }
101
- }
102
- else if (input instanceof Map) {
103
- if (input.size > 0) {
104
- str[index] = `["${utils_js_1.TYPE_MAP}",${[...input]
105
- .flatMap(([k, v]) => [
106
- flatten.call(this, k),
107
- flatten.call(this, v),
108
- ])
109
- .join(",")}]`;
89
+ else if (input instanceof URL) {
90
+ str[index] = `["${utils_js_1.TYPE_URL}",${JSON.stringify(input.href)}]`;
110
91
  }
111
- else {
112
- str[index] = `["${utils_js_1.TYPE_MAP}"]`;
92
+ else if (input instanceof RegExp) {
93
+ str[index] = `["${utils_js_1.TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
113
94
  }
114
- }
115
- else if (input instanceof Promise) {
116
- str[index] = `["${utils_js_1.TYPE_PROMISE}",${index}]`;
117
- deferred[index] = input;
118
- }
119
- else if (input instanceof Error) {
120
- str[index] = `["${utils_js_1.TYPE_ERROR}",${JSON.stringify(input.message)}`;
121
- if (input.name !== "Error") {
122
- str[index] += `,${JSON.stringify(input.name)}`;
95
+ else if (input instanceof Set) {
96
+ if (input.size > 0) {
97
+ str[index] = `["${utils_js_1.TYPE_SET}",${[...input]
98
+ .map((val) => flatten.call(this, val))
99
+ .join(",")}]`;
100
+ }
101
+ else {
102
+ str[index] = `["${utils_js_1.TYPE_SET}"]`;
103
+ }
123
104
  }
124
- str[index] += "]";
125
- }
126
- else if (Object.getPrototypeOf(input) === null) {
127
- str[index] = `["${utils_js_1.TYPE_NULL_OBJECT}",{${partsForObj(input)}}]`;
128
- }
129
- else if (isPlainObject(input)) {
130
- str[index] = `{${partsForObj(input)}}`;
131
- }
132
- else {
133
- throw new Error("Cannot encode object with prototype");
134
- }
135
- }
136
- break;
137
- }
138
- default: {
139
- const isArray = Array.isArray(input);
140
- let pluginHandled = false;
141
- if (!isArray && plugins) {
142
- for (const plugin of plugins) {
143
- const pluginResult = plugin(input);
144
- if (Array.isArray(pluginResult)) {
145
- pluginHandled = true;
146
- const [pluginIdentifier, ...rest] = pluginResult;
147
- str[index] = `[${JSON.stringify(pluginIdentifier)}`;
148
- if (rest.length > 0) {
149
- str[index] += `,${rest
150
- .map((v) => flatten.call(this, v))
151
- .join(",")}`;
105
+ else if (input instanceof Map) {
106
+ if (input.size > 0) {
107
+ str[index] = `["${utils_js_1.TYPE_MAP}",${[...input]
108
+ .flatMap(([k, v]) => [
109
+ flatten.call(this, k),
110
+ flatten.call(this, v),
111
+ ])
112
+ .join(",")}]`;
113
+ }
114
+ else {
115
+ str[index] = `["${utils_js_1.TYPE_MAP}"]`;
116
+ }
117
+ }
118
+ else if (input instanceof Promise) {
119
+ str[index] = `["${utils_js_1.TYPE_PROMISE}",${index}]`;
120
+ deferred[index] = input;
121
+ }
122
+ else if (input instanceof Error) {
123
+ str[index] = `["${utils_js_1.TYPE_ERROR}",${JSON.stringify(input.message)}`;
124
+ if (input.name !== "Error") {
125
+ str[index] += `,${JSON.stringify(input.name)}`;
152
126
  }
153
127
  str[index] += "]";
154
- break;
128
+ }
129
+ else if (Object.getPrototypeOf(input) === null) {
130
+ str[index] = `["${utils_js_1.TYPE_NULL_OBJECT}",{${partsForObj(input)}}]`;
131
+ }
132
+ else if (isPlainObject(input)) {
133
+ str[index] = `{${partsForObj(input)}}`;
134
+ }
135
+ else {
136
+ throw new Error("Cannot encode object with prototype");
155
137
  }
156
138
  }
139
+ break;
157
140
  }
158
- if (!pluginHandled) {
159
- throw new Error("Cannot encode function or unexpected type");
141
+ default: {
142
+ const isArray = Array.isArray(input);
143
+ let pluginHandled = false;
144
+ if (!isArray && plugins) {
145
+ for (const plugin of plugins) {
146
+ const pluginResult = plugin(input);
147
+ if (Array.isArray(pluginResult)) {
148
+ pluginHandled = true;
149
+ const [pluginIdentifier, ...rest] = pluginResult;
150
+ str[index] = `[${JSON.stringify(pluginIdentifier)}`;
151
+ if (rest.length > 0) {
152
+ str[index] += `,${rest
153
+ .map((v) => flatten.call(this, v))
154
+ .join(",")}`;
155
+ }
156
+ str[index] += "]";
157
+ break;
158
+ }
159
+ }
160
+ }
161
+ if (!pluginHandled) {
162
+ throw new Error("Cannot encode function or unexpected type");
163
+ }
160
164
  }
161
165
  }
162
166
  }
@@ -141,6 +141,8 @@ function encode(input, options) {
141
141
  const id = flatten_js_1.flatten.call(encoder, resolved);
142
142
  if (Array.isArray(id)) {
143
143
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_PROMISE}${deferredId}:[["${utils_js_1.TYPE_PREVIOUS_RESOLVED}",${id[0]}]]\n`));
144
+ encoder.index++;
145
+ lastSentIndex++;
144
146
  }
145
147
  else if (id < 0) {
146
148
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_PROMISE}${deferredId}:${id}\n`));
@@ -161,6 +163,8 @@ function encode(input, options) {
161
163
  const id = flatten_js_1.flatten.call(encoder, reason);
162
164
  if (Array.isArray(id)) {
163
165
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_ERROR}${deferredId}:[["${utils_js_1.TYPE_PREVIOUS_RESOLVED}",${id[0]}]]\n`));
166
+ encoder.index++;
167
+ lastSentIndex++;
164
168
  }
165
169
  else if (id < 0) {
166
170
  controller.enqueue(textEncoder.encode(`${utils_js_1.TYPE_ERROR}${deferredId}:${id}\n`));
@@ -74,115 +74,119 @@ function flatten(input) {
74
74
  function stringify(input, index) {
75
75
  const { deferred, plugins } = this;
76
76
  const str = this.stringified;
77
- const partsForObj = (obj) => Object.keys(obj).map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`).join(",");
78
- switch (typeof input) {
79
- case "boolean":
80
- case "number":
81
- case "string":
82
- str[index] = JSON.stringify(input);
83
- break;
84
- case "bigint":
85
- str[index] = `["${TYPE_BIGINT}","${input}"]`;
86
- break;
87
- case "symbol": {
88
- const keyFor = Symbol.keyFor(input);
89
- if (!keyFor)
90
- throw new Error(
91
- "Cannot encode symbol unless created with Symbol.for()"
92
- );
93
- str[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
94
- break;
95
- }
96
- case "object": {
97
- if (!input) {
98
- str[index] = `${NULL}`;
77
+ const stack = [[input, index]];
78
+ while (stack.length > 0) {
79
+ const [input2, index2] = stack.pop();
80
+ const partsForObj = (obj) => Object.keys(obj).map((k) => `"${flatten.call(this, k)}":${flatten.call(this, obj[k])}`).join(",");
81
+ switch (typeof input2) {
82
+ case "boolean":
83
+ case "number":
84
+ case "string":
85
+ str[index2] = JSON.stringify(input2);
86
+ break;
87
+ case "bigint":
88
+ str[index2] = `["${TYPE_BIGINT}","${input2}"]`;
89
+ break;
90
+ case "symbol": {
91
+ const keyFor = Symbol.keyFor(input2);
92
+ if (!keyFor)
93
+ throw new Error(
94
+ "Cannot encode symbol unless created with Symbol.for()"
95
+ );
96
+ str[index2] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
99
97
  break;
100
98
  }
101
- const isArray = Array.isArray(input);
102
- let pluginHandled = false;
103
- if (!isArray && plugins) {
104
- for (const plugin of plugins) {
105
- const pluginResult = plugin(input);
106
- if (Array.isArray(pluginResult)) {
107
- pluginHandled = true;
108
- const [pluginIdentifier, ...rest] = pluginResult;
109
- str[index] = `[${JSON.stringify(pluginIdentifier)}`;
110
- if (rest.length > 0) {
111
- str[index] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
99
+ case "object": {
100
+ if (!input2) {
101
+ str[index2] = `${NULL}`;
102
+ break;
103
+ }
104
+ const isArray = Array.isArray(input2);
105
+ let pluginHandled = false;
106
+ if (!isArray && plugins) {
107
+ for (const plugin of plugins) {
108
+ const pluginResult = plugin(input2);
109
+ if (Array.isArray(pluginResult)) {
110
+ pluginHandled = true;
111
+ const [pluginIdentifier, ...rest] = pluginResult;
112
+ str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
113
+ if (rest.length > 0) {
114
+ str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
115
+ }
116
+ str[index2] += "]";
117
+ break;
112
118
  }
113
- str[index] += "]";
114
- break;
115
119
  }
116
120
  }
117
- }
118
- if (!pluginHandled) {
119
- let result = isArray ? "[" : "{";
120
- if (isArray) {
121
- for (let i = 0; i < input.length; i++)
122
- result += (i ? "," : "") + (i in input ? flatten.call(this, input[i]) : HOLE);
123
- str[index] = `${result}]`;
124
- } else if (input instanceof Date) {
125
- str[index] = `["${TYPE_DATE}",${input.getTime()}]`;
126
- } else if (input instanceof URL) {
127
- str[index] = `["${TYPE_URL}",${JSON.stringify(input.href)}]`;
128
- } else if (input instanceof RegExp) {
129
- str[index] = `["${TYPE_REGEXP}",${JSON.stringify(
130
- input.source
131
- )},${JSON.stringify(input.flags)}]`;
132
- } else if (input instanceof Set) {
133
- if (input.size > 0) {
134
- str[index] = `["${TYPE_SET}",${[...input].map((val) => flatten.call(this, val)).join(",")}]`;
135
- } else {
136
- str[index] = `["${TYPE_SET}"]`;
137
- }
138
- } else if (input instanceof Map) {
139
- if (input.size > 0) {
140
- str[index] = `["${TYPE_MAP}",${[...input].flatMap(([k, v]) => [
141
- flatten.call(this, k),
142
- flatten.call(this, v)
143
- ]).join(",")}]`;
121
+ if (!pluginHandled) {
122
+ let result = isArray ? "[" : "{";
123
+ if (isArray) {
124
+ for (let i = 0; i < input2.length; i++)
125
+ result += (i ? "," : "") + (i in input2 ? flatten.call(this, input2[i]) : HOLE);
126
+ str[index2] = `${result}]`;
127
+ } else if (input2 instanceof Date) {
128
+ str[index2] = `["${TYPE_DATE}",${input2.getTime()}]`;
129
+ } else if (input2 instanceof URL) {
130
+ str[index2] = `["${TYPE_URL}",${JSON.stringify(input2.href)}]`;
131
+ } else if (input2 instanceof RegExp) {
132
+ str[index2] = `["${TYPE_REGEXP}",${JSON.stringify(
133
+ input2.source
134
+ )},${JSON.stringify(input2.flags)}]`;
135
+ } else if (input2 instanceof Set) {
136
+ if (input2.size > 0) {
137
+ str[index2] = `["${TYPE_SET}",${[...input2].map((val) => flatten.call(this, val)).join(",")}]`;
138
+ } else {
139
+ str[index2] = `["${TYPE_SET}"]`;
140
+ }
141
+ } else if (input2 instanceof Map) {
142
+ if (input2.size > 0) {
143
+ str[index2] = `["${TYPE_MAP}",${[...input2].flatMap(([k, v]) => [
144
+ flatten.call(this, k),
145
+ flatten.call(this, v)
146
+ ]).join(",")}]`;
147
+ } else {
148
+ str[index2] = `["${TYPE_MAP}"]`;
149
+ }
150
+ } else if (input2 instanceof Promise) {
151
+ str[index2] = `["${TYPE_PROMISE}",${index2}]`;
152
+ deferred[index2] = input2;
153
+ } else if (input2 instanceof Error) {
154
+ str[index2] = `["${TYPE_ERROR}",${JSON.stringify(input2.message)}`;
155
+ if (input2.name !== "Error") {
156
+ str[index2] += `,${JSON.stringify(input2.name)}`;
157
+ }
158
+ str[index2] += "]";
159
+ } else if (Object.getPrototypeOf(input2) === null) {
160
+ str[index2] = `["${TYPE_NULL_OBJECT}",{${partsForObj(input2)}}]`;
161
+ } else if (isPlainObject(input2)) {
162
+ str[index2] = `{${partsForObj(input2)}}`;
144
163
  } else {
145
- str[index] = `["${TYPE_MAP}"]`;
146
- }
147
- } else if (input instanceof Promise) {
148
- str[index] = `["${TYPE_PROMISE}",${index}]`;
149
- deferred[index] = input;
150
- } else if (input instanceof Error) {
151
- str[index] = `["${TYPE_ERROR}",${JSON.stringify(input.message)}`;
152
- if (input.name !== "Error") {
153
- str[index] += `,${JSON.stringify(input.name)}`;
164
+ throw new Error("Cannot encode object with prototype");
154
165
  }
155
- str[index] += "]";
156
- } else if (Object.getPrototypeOf(input) === null) {
157
- str[index] = `["${TYPE_NULL_OBJECT}",{${partsForObj(input)}}]`;
158
- } else if (isPlainObject(input)) {
159
- str[index] = `{${partsForObj(input)}}`;
160
- } else {
161
- throw new Error("Cannot encode object with prototype");
162
166
  }
167
+ break;
163
168
  }
164
- break;
165
- }
166
- default: {
167
- const isArray = Array.isArray(input);
168
- let pluginHandled = false;
169
- if (!isArray && plugins) {
170
- for (const plugin of plugins) {
171
- const pluginResult = plugin(input);
172
- if (Array.isArray(pluginResult)) {
173
- pluginHandled = true;
174
- const [pluginIdentifier, ...rest] = pluginResult;
175
- str[index] = `[${JSON.stringify(pluginIdentifier)}`;
176
- if (rest.length > 0) {
177
- str[index] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
169
+ default: {
170
+ const isArray = Array.isArray(input2);
171
+ let pluginHandled = false;
172
+ if (!isArray && plugins) {
173
+ for (const plugin of plugins) {
174
+ const pluginResult = plugin(input2);
175
+ if (Array.isArray(pluginResult)) {
176
+ pluginHandled = true;
177
+ const [pluginIdentifier, ...rest] = pluginResult;
178
+ str[index2] = `[${JSON.stringify(pluginIdentifier)}`;
179
+ if (rest.length > 0) {
180
+ str[index2] += `,${rest.map((v) => flatten.call(this, v)).join(",")}`;
181
+ }
182
+ str[index2] += "]";
183
+ break;
178
184
  }
179
- str[index] += "]";
180
- break;
181
185
  }
182
186
  }
183
- }
184
- if (!pluginHandled) {
185
- throw new Error("Cannot encode function or unexpected type");
187
+ if (!pluginHandled) {
188
+ throw new Error("Cannot encode function or unexpected type");
189
+ }
186
190
  }
187
191
  }
188
192
  }
@@ -208,108 +212,216 @@ function unflatten(parsed) {
208
212
  }
209
213
  function hydrate(index) {
210
214
  const { hydrated, values, deferred, plugins } = this;
211
- switch (index) {
212
- case UNDEFINED:
213
- return;
214
- case NULL:
215
- return null;
216
- case NAN:
217
- return NaN;
218
- case POSITIVE_INFINITY:
219
- return Infinity;
220
- case NEGATIVE_INFINITY:
221
- return -Infinity;
222
- case NEGATIVE_ZERO:
223
- return -0;
224
- }
225
- if (hydrated[index])
226
- return hydrated[index];
227
- const value = values[index];
228
- if (!value || typeof value !== "object")
229
- return hydrated[index] = value;
230
- if (Array.isArray(value)) {
231
- if (typeof value[0] === "string") {
232
- const [type, b, c] = value;
233
- switch (type) {
234
- case TYPE_DATE:
235
- return hydrated[index] = new Date(b);
236
- case TYPE_URL:
237
- return hydrated[index] = new URL(b);
238
- case TYPE_BIGINT:
239
- return hydrated[index] = BigInt(b);
240
- case TYPE_REGEXP:
241
- return hydrated[index] = new RegExp(b, c);
242
- case TYPE_SYMBOL:
243
- return hydrated[index] = Symbol.for(b);
244
- case TYPE_SET:
245
- const set = /* @__PURE__ */ new Set();
246
- hydrated[index] = set;
247
- for (let i = 1; i < value.length; i++)
248
- set.add(hydrate.call(this, value[i]));
249
- return set;
250
- case TYPE_MAP:
251
- const map = /* @__PURE__ */ new Map();
252
- hydrated[index] = map;
253
- for (let i = 1; i < value.length; i += 2) {
254
- map.set(
255
- hydrate.call(this, value[i]),
256
- hydrate.call(this, value[i + 1])
257
- );
258
- }
259
- return map;
260
- case TYPE_NULL_OBJECT:
261
- const obj = /* @__PURE__ */ Object.create(null);
262
- hydrated[index] = obj;
263
- for (const key in b)
264
- obj[hydrate.call(this, Number(key))] = hydrate.call(this, b[key]);
265
- return obj;
266
- case TYPE_PROMISE:
267
- if (hydrated[b]) {
268
- return hydrated[index] = hydrated[b];
269
- } else {
270
- const d = new Deferred();
271
- deferred[b] = d;
272
- return hydrated[index] = d.promise;
273
- }
274
- case TYPE_ERROR:
275
- const [, message, errorType] = value;
276
- let error = errorType && globalObj && globalObj[errorType] ? new globalObj[errorType](message) : new Error(message);
277
- hydrated[index] = error;
278
- return error;
279
- case TYPE_PREVIOUS_RESOLVED:
280
- return hydrate.call(this, b);
281
- default:
282
- if (Array.isArray(plugins)) {
283
- const args = value.slice(1).map((i) => hydrate.call(this, i));
284
- for (const plugin of plugins) {
285
- const result = plugin(value[0], ...args);
286
- if (result)
287
- return hydrated[index] = result.value;
215
+ let result;
216
+ const stack = [
217
+ [
218
+ index,
219
+ (v) => {
220
+ result = v;
221
+ }
222
+ ]
223
+ ];
224
+ let postRun = [];
225
+ while (stack.length > 0) {
226
+ const [index2, set] = stack.pop();
227
+ switch (index2) {
228
+ case UNDEFINED:
229
+ set(void 0);
230
+ continue;
231
+ case NULL:
232
+ set(null);
233
+ continue;
234
+ case NAN:
235
+ set(NaN);
236
+ continue;
237
+ case POSITIVE_INFINITY:
238
+ set(Infinity);
239
+ continue;
240
+ case NEGATIVE_INFINITY:
241
+ set(-Infinity);
242
+ continue;
243
+ case NEGATIVE_ZERO:
244
+ set(-0);
245
+ continue;
246
+ }
247
+ if (hydrated[index2]) {
248
+ set(hydrated[index2]);
249
+ continue;
250
+ }
251
+ const value = values[index2];
252
+ if (!value || typeof value !== "object") {
253
+ hydrated[index2] = value;
254
+ set(value);
255
+ continue;
256
+ }
257
+ if (Array.isArray(value)) {
258
+ if (typeof value[0] === "string") {
259
+ const [type, b, c] = value;
260
+ switch (type) {
261
+ case TYPE_DATE:
262
+ set(hydrated[index2] = new Date(b));
263
+ continue;
264
+ case TYPE_URL:
265
+ set(hydrated[index2] = new URL(b));
266
+ continue;
267
+ case TYPE_BIGINT:
268
+ set(hydrated[index2] = BigInt(b));
269
+ continue;
270
+ case TYPE_REGEXP:
271
+ set(hydrated[index2] = new RegExp(b, c));
272
+ continue;
273
+ case TYPE_SYMBOL:
274
+ set(hydrated[index2] = Symbol.for(b));
275
+ continue;
276
+ case TYPE_SET:
277
+ const newSet = /* @__PURE__ */ new Set();
278
+ hydrated[index2] = newSet;
279
+ for (let i = 1; i < value.length; i++)
280
+ stack.push([
281
+ value[i],
282
+ (v) => {
283
+ newSet.add(v);
284
+ }
285
+ ]);
286
+ set(newSet);
287
+ continue;
288
+ case TYPE_MAP:
289
+ const map = /* @__PURE__ */ new Map();
290
+ hydrated[index2] = map;
291
+ for (let i = 1; i < value.length; i += 2) {
292
+ const r = [];
293
+ stack.push([
294
+ value[i + 1],
295
+ (v) => {
296
+ r[1] = v;
297
+ }
298
+ ]);
299
+ stack.push([
300
+ value[i],
301
+ (k) => {
302
+ r[0] = k;
303
+ }
304
+ ]);
305
+ postRun.push(() => {
306
+ map.set(r[0], r[1]);
307
+ });
308
+ }
309
+ set(map);
310
+ continue;
311
+ case TYPE_NULL_OBJECT:
312
+ const obj = /* @__PURE__ */ Object.create(null);
313
+ hydrated[index2] = obj;
314
+ for (const key in b) {
315
+ const r = [];
316
+ stack.push([
317
+ b[key],
318
+ (v) => {
319
+ r[1] = v;
320
+ }
321
+ ]);
322
+ stack.push([
323
+ Number(key),
324
+ (k) => {
325
+ r[0] = k;
326
+ }
327
+ ]);
328
+ postRun.push(() => {
329
+ obj[r[0]] = r[1];
330
+ });
331
+ }
332
+ set(obj);
333
+ continue;
334
+ case TYPE_PROMISE:
335
+ if (hydrated[b]) {
336
+ set(hydrated[index2] = hydrated[b]);
337
+ } else {
338
+ const d = new Deferred();
339
+ deferred[b] = d;
340
+ set(hydrated[index2] = d.promise);
341
+ }
342
+ continue;
343
+ case TYPE_ERROR:
344
+ const [, message, errorType] = value;
345
+ let error = errorType && globalObj && globalObj[errorType] ? new globalObj[errorType](message) : new Error(message);
346
+ hydrated[index2] = error;
347
+ set(error);
348
+ continue;
349
+ case TYPE_PREVIOUS_RESOLVED:
350
+ set(hydrated[index2] = hydrated[b]);
351
+ continue;
352
+ default:
353
+ if (Array.isArray(plugins)) {
354
+ const r = [];
355
+ const vals = value.slice(1);
356
+ for (let i = 0; i < vals.length; i++) {
357
+ const v = vals[i];
358
+ stack.push([
359
+ v,
360
+ (v2) => {
361
+ r[i] = v2;
362
+ }
363
+ ]);
364
+ }
365
+ postRun.push(() => {
366
+ for (const plugin of plugins) {
367
+ const result2 = plugin(value[0], ...r);
368
+ if (result2) {
369
+ set(hydrated[index2] = result2.value);
370
+ return;
371
+ }
372
+ }
373
+ throw new SyntaxError();
374
+ });
375
+ continue;
288
376
  }
377
+ throw new SyntaxError();
378
+ }
379
+ } else {
380
+ const array = [];
381
+ hydrated[index2] = array;
382
+ for (let i = 0; i < value.length; i++) {
383
+ const n = value[i];
384
+ if (n !== HOLE) {
385
+ stack.push([
386
+ n,
387
+ (v) => {
388
+ array[i] = v;
389
+ }
390
+ ]);
289
391
  }
290
- throw new SyntaxError();
392
+ }
393
+ set(array);
394
+ continue;
291
395
  }
292
396
  } else {
293
- const array = [];
294
- hydrated[index] = array;
295
- for (let i = 0; i < value.length; i++) {
296
- const n = value[i];
297
- if (n !== HOLE)
298
- array[i] = hydrate.call(this, n);
397
+ const object = {};
398
+ hydrated[index2] = object;
399
+ for (const key in value) {
400
+ const r = [];
401
+ stack.push([
402
+ value[key],
403
+ (v) => {
404
+ r[1] = v;
405
+ }
406
+ ]);
407
+ stack.push([
408
+ Number(key),
409
+ (k) => {
410
+ r[0] = k;
411
+ }
412
+ ]);
413
+ postRun.push(() => {
414
+ object[r[0]] = r[1];
415
+ });
299
416
  }
300
- return array;
301
- }
302
- } else {
303
- const object = {};
304
- hydrated[index] = object;
305
- for (const key in value) {
306
- object[hydrate.call(this, Number(key))] = hydrate.call(
307
- this,
308
- value[key]
309
- );
417
+ set(object);
418
+ continue;
310
419
  }
311
- return object;
312
420
  }
421
+ while (postRun.length > 0) {
422
+ postRun.pop()();
423
+ }
424
+ return result;
313
425
  }
314
426
 
315
427
  // src/turbo-stream.ts
@@ -452,6 +564,8 @@ function encode(input, options) {
452
564
  `
453
565
  )
454
566
  );
567
+ encoder.index++;
568
+ lastSentIndex++;
455
569
  } else if (id2 < 0) {
456
570
  controller.enqueue(
457
571
  textEncoder.encode(`${TYPE_PROMISE}${deferredId}:${id2}
@@ -480,6 +594,8 @@ function encode(input, options) {
480
594
  `
481
595
  )
482
596
  );
597
+ encoder.index++;
598
+ lastSentIndex++;
483
599
  } else if (id2 < 0) {
484
600
  controller.enqueue(
485
601
  textEncoder.encode(`${TYPE_ERROR}${deferredId}:${id2}
package/dist/unflatten.js CHANGED
@@ -21,107 +21,221 @@ function unflatten(parsed) {
21
21
  exports.unflatten = unflatten;
22
22
  function hydrate(index) {
23
23
  const { hydrated, values, deferred, plugins } = this;
24
- switch (index) {
25
- case utils_js_1.UNDEFINED:
26
- return;
27
- case utils_js_1.NULL:
28
- return null;
29
- case utils_js_1.NAN:
30
- return NaN;
31
- case utils_js_1.POSITIVE_INFINITY:
32
- return Infinity;
33
- case utils_js_1.NEGATIVE_INFINITY:
34
- return -Infinity;
35
- case utils_js_1.NEGATIVE_ZERO:
36
- return -0;
37
- }
38
- if (hydrated[index])
39
- return hydrated[index];
40
- const value = values[index];
41
- if (!value || typeof value !== "object")
42
- return (hydrated[index] = value);
43
- if (Array.isArray(value)) {
44
- if (typeof value[0] === "string") {
45
- const [type, b, c] = value;
46
- switch (type) {
47
- case utils_js_1.TYPE_DATE:
48
- return (hydrated[index] = new Date(b));
49
- case utils_js_1.TYPE_URL:
50
- return (hydrated[index] = new URL(b));
51
- case utils_js_1.TYPE_BIGINT:
52
- return (hydrated[index] = BigInt(b));
53
- case utils_js_1.TYPE_REGEXP:
54
- return (hydrated[index] = new RegExp(b, c));
55
- case utils_js_1.TYPE_SYMBOL:
56
- return (hydrated[index] = Symbol.for(b));
57
- case utils_js_1.TYPE_SET:
58
- const set = new Set();
59
- hydrated[index] = set;
60
- for (let i = 1; i < value.length; i++)
61
- set.add(hydrate.call(this, value[i]));
62
- return set;
63
- case utils_js_1.TYPE_MAP:
64
- const map = new Map();
65
- hydrated[index] = map;
66
- for (let i = 1; i < value.length; i += 2) {
67
- map.set(hydrate.call(this, value[i]), hydrate.call(this, value[i + 1]));
68
- }
69
- return map;
70
- case utils_js_1.TYPE_NULL_OBJECT:
71
- const obj = Object.create(null);
72
- hydrated[index] = obj;
73
- for (const key in b)
74
- obj[hydrate.call(this, Number(key))] = hydrate.call(this, b[key]);
75
- return obj;
76
- case utils_js_1.TYPE_PROMISE:
77
- if (hydrated[b]) {
78
- return (hydrated[index] = hydrated[b]);
79
- }
80
- else {
81
- const d = new utils_js_1.Deferred();
82
- deferred[b] = d;
83
- return (hydrated[index] = d.promise);
84
- }
85
- case utils_js_1.TYPE_ERROR:
86
- const [, message, errorType] = value;
87
- let error = errorType && globalObj && globalObj[errorType]
88
- ? new globalObj[errorType](message)
89
- : new Error(message);
90
- hydrated[index] = error;
91
- return error;
92
- case utils_js_1.TYPE_PREVIOUS_RESOLVED:
93
- return hydrate.call(this, b);
94
- default:
95
- // Run plugins at the end so we have a chance to resolve primitives
96
- // without running into a loop
97
- if (Array.isArray(plugins)) {
98
- const args = value.slice(1).map((i) => hydrate.call(this, i));
99
- for (const plugin of plugins) {
100
- const result = plugin(value[0], ...args);
101
- if (result)
102
- return (hydrated[index] = result.value);
24
+ let result;
25
+ const stack = [
26
+ [
27
+ index,
28
+ (v) => {
29
+ result = v;
30
+ },
31
+ ],
32
+ ];
33
+ let postRun = [];
34
+ while (stack.length > 0) {
35
+ const [index, set] = stack.pop();
36
+ switch (index) {
37
+ case utils_js_1.UNDEFINED:
38
+ set(undefined);
39
+ continue;
40
+ case utils_js_1.NULL:
41
+ set(null);
42
+ continue;
43
+ case utils_js_1.NAN:
44
+ set(NaN);
45
+ continue;
46
+ case utils_js_1.POSITIVE_INFINITY:
47
+ set(Infinity);
48
+ continue;
49
+ case utils_js_1.NEGATIVE_INFINITY:
50
+ set(-Infinity);
51
+ continue;
52
+ case utils_js_1.NEGATIVE_ZERO:
53
+ set(-0);
54
+ continue;
55
+ }
56
+ if (hydrated[index]) {
57
+ set(hydrated[index]);
58
+ continue;
59
+ }
60
+ const value = values[index];
61
+ if (!value || typeof value !== "object") {
62
+ hydrated[index] = value;
63
+ set(value);
64
+ continue;
65
+ }
66
+ if (Array.isArray(value)) {
67
+ if (typeof value[0] === "string") {
68
+ const [type, b, c] = value;
69
+ switch (type) {
70
+ case utils_js_1.TYPE_DATE:
71
+ set((hydrated[index] = new Date(b)));
72
+ continue;
73
+ case utils_js_1.TYPE_URL:
74
+ set((hydrated[index] = new URL(b)));
75
+ continue;
76
+ case utils_js_1.TYPE_BIGINT:
77
+ set((hydrated[index] = BigInt(b)));
78
+ continue;
79
+ case utils_js_1.TYPE_REGEXP:
80
+ set((hydrated[index] = new RegExp(b, c)));
81
+ continue;
82
+ case utils_js_1.TYPE_SYMBOL:
83
+ set((hydrated[index] = Symbol.for(b)));
84
+ continue;
85
+ case utils_js_1.TYPE_SET:
86
+ const newSet = new Set();
87
+ hydrated[index] = newSet;
88
+ for (let i = 1; i < value.length; i++)
89
+ stack.push([
90
+ value[i],
91
+ (v) => {
92
+ newSet.add(v);
93
+ },
94
+ ]);
95
+ set(newSet);
96
+ continue;
97
+ case utils_js_1.TYPE_MAP:
98
+ const map = new Map();
99
+ hydrated[index] = map;
100
+ for (let i = 1; i < value.length; i += 2) {
101
+ const r = [];
102
+ stack.push([
103
+ value[i + 1],
104
+ (v) => {
105
+ r[1] = v;
106
+ },
107
+ ]);
108
+ stack.push([
109
+ value[i],
110
+ (k) => {
111
+ r[0] = k;
112
+ },
113
+ ]);
114
+ postRun.push(() => {
115
+ map.set(r[0], r[1]);
116
+ });
103
117
  }
118
+ set(map);
119
+ continue;
120
+ case utils_js_1.TYPE_NULL_OBJECT:
121
+ const obj = Object.create(null);
122
+ hydrated[index] = obj;
123
+ for (const key in b) {
124
+ const r = [];
125
+ stack.push([
126
+ b[key],
127
+ (v) => {
128
+ r[1] = v;
129
+ },
130
+ ]);
131
+ stack.push([
132
+ Number(key),
133
+ (k) => {
134
+ r[0] = k;
135
+ },
136
+ ]);
137
+ postRun.push(() => {
138
+ obj[r[0]] = r[1];
139
+ });
140
+ }
141
+ set(obj);
142
+ continue;
143
+ case utils_js_1.TYPE_PROMISE:
144
+ if (hydrated[b]) {
145
+ set((hydrated[index] = hydrated[b]));
146
+ }
147
+ else {
148
+ const d = new utils_js_1.Deferred();
149
+ deferred[b] = d;
150
+ set((hydrated[index] = d.promise));
151
+ }
152
+ continue;
153
+ case utils_js_1.TYPE_ERROR:
154
+ const [, message, errorType] = value;
155
+ let error = errorType && globalObj && globalObj[errorType]
156
+ ? new globalObj[errorType](message)
157
+ : new Error(message);
158
+ hydrated[index] = error;
159
+ set(error);
160
+ continue;
161
+ case utils_js_1.TYPE_PREVIOUS_RESOLVED:
162
+ set((hydrated[index] = hydrated[b]));
163
+ continue;
164
+ default:
165
+ // Run plugins at the end so we have a chance to resolve primitives
166
+ // without running into a loop
167
+ if (Array.isArray(plugins)) {
168
+ const r = [];
169
+ const vals = value.slice(1);
170
+ for (let i = 0; i < vals.length; i++) {
171
+ const v = vals[i];
172
+ stack.push([
173
+ v,
174
+ (v) => {
175
+ r[i] = v;
176
+ },
177
+ ]);
178
+ }
179
+ postRun.push(() => {
180
+ for (const plugin of plugins) {
181
+ const result = plugin(value[0], ...r);
182
+ if (result) {
183
+ set((hydrated[index] = result.value));
184
+ return;
185
+ }
186
+ }
187
+ throw new SyntaxError();
188
+ });
189
+ continue;
190
+ }
191
+ throw new SyntaxError();
192
+ }
193
+ }
194
+ else {
195
+ const array = [];
196
+ hydrated[index] = array;
197
+ for (let i = 0; i < value.length; i++) {
198
+ const n = value[i];
199
+ if (n !== utils_js_1.HOLE) {
200
+ stack.push([
201
+ n,
202
+ (v) => {
203
+ array[i] = v;
204
+ },
205
+ ]);
104
206
  }
105
- throw new SyntaxError();
207
+ }
208
+ set(array);
209
+ continue;
106
210
  }
107
211
  }
108
212
  else {
109
- const array = [];
110
- hydrated[index] = array;
111
- for (let i = 0; i < value.length; i++) {
112
- const n = value[i];
113
- if (n !== utils_js_1.HOLE)
114
- array[i] = hydrate.call(this, n);
213
+ const object = {};
214
+ hydrated[index] = object;
215
+ for (const key in value) {
216
+ const r = [];
217
+ stack.push([
218
+ value[key],
219
+ (v) => {
220
+ r[1] = v;
221
+ },
222
+ ]);
223
+ stack.push([
224
+ Number(key),
225
+ (k) => {
226
+ r[0] = k;
227
+ },
228
+ ]);
229
+ postRun.push(() => {
230
+ object[r[0]] = r[1];
231
+ });
115
232
  }
116
- return array;
233
+ set(object);
234
+ continue;
117
235
  }
118
236
  }
119
- else {
120
- const object = {};
121
- hydrated[index] = object;
122
- for (const key in value) {
123
- object[hydrate.call(this, Number(key))] = hydrate.call(this, value[key]);
124
- }
125
- return object;
237
+ while (postRun.length > 0) {
238
+ postRun.pop()();
126
239
  }
240
+ return result;
127
241
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbo-stream",
3
- "version": "2.2.0",
3
+ "version": "2.2.2",
4
4
  "description": "A streaming data transport format that aims to support built-in features such as Promises, Dates, RegExps, Maps, Sets and more.",
5
5
  "files": [
6
6
  "dist",