turbo-stream 2.2.1 → 2.2.3

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