turbo-stream 0.0.3 → 0.0.5
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/README.md +4 -4
- package/dist/flatten.js +36 -58
- package/dist/unflatten.js +47 -56
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Turbo Stream
|
|
1
|
+
# Turbo Stream <br> [](https://bundlejs.com/?q=turbo-stream)
|
|
2
2
|
|
|
3
3
|
A streaming data transport format that aims to support built-in features such as Promises, Dates, RegExps, Maps, Sets and more.
|
|
4
4
|
|
|
@@ -18,10 +18,10 @@ npm install turbo-stream
|
|
|
18
18
|
```js
|
|
19
19
|
import { decode, encode } from "turbo-stream";
|
|
20
20
|
|
|
21
|
-
const encodedStream = encode(Promise.resolve(42));
|
|
21
|
+
const encodedStream = encode({ answer: Promise.resolve(42) });
|
|
22
22
|
const decoded = await decode(encodedStream);
|
|
23
|
-
console.log(decoded.value); // a Promise
|
|
24
|
-
console.log(await decoded.value); // 42
|
|
23
|
+
console.log(decoded.value.answer); // a Promise
|
|
24
|
+
console.log(await decoded.value.answer); // 42
|
|
25
25
|
await decoded.done; // wait for the stream to finish
|
|
26
26
|
```
|
|
27
27
|
|
package/dist/flatten.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_MAP, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, } from "./utils.js";
|
|
2
2
|
export function flatten(input) {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
const existing = this.indicies.get(input);
|
|
4
|
+
if (existing)
|
|
5
|
+
return existing;
|
|
6
6
|
if (input === undefined)
|
|
7
7
|
return UNDEFINED;
|
|
8
8
|
if (Number.isNaN(input))
|
|
@@ -19,88 +19,66 @@ export function flatten(input) {
|
|
|
19
19
|
return index;
|
|
20
20
|
}
|
|
21
21
|
function stringify(input, index) {
|
|
22
|
+
const str = this.stringified;
|
|
22
23
|
switch (typeof input) {
|
|
23
24
|
case "boolean":
|
|
24
25
|
case "number":
|
|
25
26
|
case "string":
|
|
26
|
-
|
|
27
|
+
str[index] = JSON.stringify(input);
|
|
27
28
|
break;
|
|
28
29
|
case "bigint":
|
|
29
|
-
|
|
30
|
+
str[index] = `["${TYPE_BIGINT}","${input}"]`;
|
|
30
31
|
break;
|
|
31
32
|
case "symbol":
|
|
32
33
|
const keyFor = Symbol.keyFor(input);
|
|
33
34
|
if (!keyFor)
|
|
34
35
|
throw new Error("Cannot encode symbol unless created with Symbol.for()");
|
|
35
|
-
|
|
36
|
+
str[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
|
|
36
37
|
break;
|
|
37
38
|
case "object":
|
|
38
39
|
if (!input) {
|
|
39
|
-
|
|
40
|
+
str[index] = "null";
|
|
40
41
|
break;
|
|
41
42
|
}
|
|
43
|
+
let result = Array.isArray(input) ? "[" : "{";
|
|
42
44
|
if (Array.isArray(input)) {
|
|
43
|
-
let
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (i in input) {
|
|
48
|
-
result += flatten.call(this, input[i]);
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
result += HOLE;
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
this.stringified[index] = result + "]";
|
|
55
|
-
break;
|
|
45
|
+
for (let i = 0; i < input.length; i++)
|
|
46
|
+
result +=
|
|
47
|
+
(i ? "," : "") + (i in input ? flatten.call(this, input[i]) : HOLE);
|
|
48
|
+
str[index] = result + "]";
|
|
56
49
|
}
|
|
57
|
-
if (input instanceof Date) {
|
|
58
|
-
|
|
59
|
-
break;
|
|
50
|
+
else if (input instanceof Date) {
|
|
51
|
+
str[index] = `["${TYPE_DATE}",${input.getTime()}]`;
|
|
60
52
|
}
|
|
61
|
-
if (input instanceof RegExp) {
|
|
62
|
-
|
|
63
|
-
break;
|
|
53
|
+
else if (input instanceof RegExp) {
|
|
54
|
+
str[index] = `["${TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
|
|
64
55
|
}
|
|
65
|
-
if (input instanceof Set) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
this.stringified[index] = result + "]";
|
|
71
|
-
break;
|
|
56
|
+
else if (input instanceof Set) {
|
|
57
|
+
str[index] = `["${TYPE_SET}",${[...input]
|
|
58
|
+
.map((val) => flatten.call(this, val))
|
|
59
|
+
.join(",")}]`;
|
|
72
60
|
}
|
|
73
|
-
if (input instanceof Map) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
result += "," + flatten.call(this, value);
|
|
78
|
-
}
|
|
79
|
-
this.stringified[index] = result + "]";
|
|
80
|
-
break;
|
|
61
|
+
else if (input instanceof Map) {
|
|
62
|
+
str[index] = `["${TYPE_MAP}",${[...input]
|
|
63
|
+
.flatMap(([k, v]) => [flatten.call(this, k), flatten.call(this, v)])
|
|
64
|
+
.join(",")}]`;
|
|
81
65
|
}
|
|
82
|
-
if (input instanceof Promise) {
|
|
83
|
-
|
|
66
|
+
else if (input instanceof Promise) {
|
|
67
|
+
str[index] = `["${TYPE_PROMISE}",${index}]`;
|
|
84
68
|
this.deferred[index] = input;
|
|
85
|
-
break;
|
|
86
69
|
}
|
|
87
|
-
if (
|
|
88
|
-
|
|
70
|
+
else if (isPlainObject(input)) {
|
|
71
|
+
const parts = [];
|
|
72
|
+
for (const key in input)
|
|
73
|
+
parts.push(`${JSON.stringify(key)}:${flatten.call(this, input[key])}`);
|
|
74
|
+
str[index] = "{" + parts.join(",") + "}";
|
|
89
75
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
for (const key in input) {
|
|
93
|
-
if (sep)
|
|
94
|
-
result += ",";
|
|
95
|
-
sep = true;
|
|
96
|
-
result += JSON.stringify(key) + ":" + flatten.call(this, input[key]);
|
|
76
|
+
else {
|
|
77
|
+
throw new Error("Cannot encode object with prototype");
|
|
97
78
|
}
|
|
98
|
-
this.stringified[index] = result + "}";
|
|
99
79
|
break;
|
|
100
|
-
|
|
101
|
-
throw new Error("Cannot encode function");
|
|
102
|
-
case "undefined":
|
|
103
|
-
throw new Error("This should never happen");
|
|
80
|
+
default:
|
|
81
|
+
throw new Error("Cannot encode function or unexpected type");
|
|
104
82
|
}
|
|
105
83
|
}
|
|
106
84
|
const objectProtoNames = Object.getOwnPropertyNames(Object.prototype)
|
package/dist/unflatten.js
CHANGED
|
@@ -1,95 +1,86 @@
|
|
|
1
1
|
import { Deferred, HOLE, NAN, NEGATIVE_INFINITY, NEGATIVE_ZERO, POSITIVE_INFINITY, TYPE_BIGINT, TYPE_DATE, TYPE_MAP, TYPE_PROMISE, TYPE_REGEXP, TYPE_SET, TYPE_SYMBOL, UNDEFINED, } from "./utils.js";
|
|
2
2
|
export function unflatten(parsed) {
|
|
3
3
|
if (typeof parsed === "number")
|
|
4
|
-
return hydrate.call(this, parsed
|
|
5
|
-
if (!Array.isArray(parsed) || parsed.length
|
|
6
|
-
throw new
|
|
7
|
-
}
|
|
4
|
+
return hydrate.call(this, parsed);
|
|
5
|
+
if (!Array.isArray(parsed) || !parsed.length)
|
|
6
|
+
throw new SyntaxError();
|
|
8
7
|
const startIndex = this.values.length;
|
|
9
8
|
this.values.push(...parsed);
|
|
10
9
|
this.hydrated.length = this.values.length;
|
|
11
10
|
return hydrate.call(this, startIndex);
|
|
12
11
|
}
|
|
13
|
-
function hydrate(index
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (index in this.hydrated)
|
|
27
|
-
return this.hydrated[index];
|
|
28
|
-
const value = this.values[index];
|
|
29
|
-
if (!value || typeof value !== "object") {
|
|
30
|
-
this.hydrated[index] = value;
|
|
12
|
+
function hydrate(index) {
|
|
13
|
+
const { hydrated, values, deferred } = this;
|
|
14
|
+
switch (index) {
|
|
15
|
+
case UNDEFINED:
|
|
16
|
+
return;
|
|
17
|
+
case NAN:
|
|
18
|
+
return NaN;
|
|
19
|
+
case POSITIVE_INFINITY:
|
|
20
|
+
return Infinity;
|
|
21
|
+
case NEGATIVE_INFINITY:
|
|
22
|
+
return -Infinity;
|
|
23
|
+
case NEGATIVE_ZERO:
|
|
24
|
+
return -0;
|
|
31
25
|
}
|
|
32
|
-
|
|
26
|
+
if (hydrated[index])
|
|
27
|
+
return hydrated[index];
|
|
28
|
+
const value = values[index];
|
|
29
|
+
if (!value || typeof value !== "object")
|
|
30
|
+
return (hydrated[index] = value);
|
|
31
|
+
if (Array.isArray(value)) {
|
|
33
32
|
if (typeof value[0] === "string") {
|
|
34
33
|
switch (value[0]) {
|
|
35
34
|
case TYPE_DATE:
|
|
36
|
-
|
|
37
|
-
break;
|
|
35
|
+
return (hydrated[index] = new Date(value[1]));
|
|
38
36
|
case TYPE_BIGINT:
|
|
39
|
-
|
|
40
|
-
break;
|
|
37
|
+
return (hydrated[index] = BigInt(value[1]));
|
|
41
38
|
case TYPE_REGEXP:
|
|
42
|
-
|
|
43
|
-
break;
|
|
39
|
+
return (hydrated[index] = new RegExp(value[1], value[2]));
|
|
44
40
|
case TYPE_SYMBOL:
|
|
45
|
-
|
|
46
|
-
break;
|
|
41
|
+
return (hydrated[index] = Symbol.for(value[1]));
|
|
47
42
|
case TYPE_SET:
|
|
48
43
|
const set = new Set();
|
|
49
|
-
|
|
50
|
-
for (let i = 1; i < value.length; i
|
|
44
|
+
hydrated[index] = set;
|
|
45
|
+
for (let i = 1; i < value.length; i++)
|
|
51
46
|
set.add(hydrate.call(this, value[i]));
|
|
52
|
-
|
|
53
|
-
break;
|
|
47
|
+
return set;
|
|
54
48
|
case TYPE_MAP:
|
|
55
49
|
const map = new Map();
|
|
56
|
-
|
|
50
|
+
hydrated[index] = map;
|
|
57
51
|
for (let i = 1; i < value.length; i += 2) {
|
|
58
52
|
map.set(hydrate.call(this, value[i]), hydrate.call(this, value[i + 1]));
|
|
59
53
|
}
|
|
60
|
-
|
|
54
|
+
return map;
|
|
61
55
|
case TYPE_PROMISE:
|
|
62
|
-
if (
|
|
63
|
-
|
|
56
|
+
if (hydrated[value[1]]) {
|
|
57
|
+
return (hydrated[index] = hydrated[value[1]]);
|
|
64
58
|
}
|
|
65
59
|
else {
|
|
66
|
-
const
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
const d = new Deferred();
|
|
61
|
+
deferred[value[1]] = d;
|
|
62
|
+
return (hydrated[index] = d.promise);
|
|
69
63
|
}
|
|
70
|
-
break;
|
|
71
64
|
default:
|
|
72
|
-
throw new
|
|
65
|
+
throw new SyntaxError();
|
|
73
66
|
}
|
|
74
67
|
}
|
|
75
68
|
else {
|
|
76
|
-
const array =
|
|
77
|
-
|
|
78
|
-
for (let i = 0; i < value.length; i
|
|
69
|
+
const array = [];
|
|
70
|
+
hydrated[index] = array;
|
|
71
|
+
for (let i = 0; i < value.length; i++) {
|
|
79
72
|
const n = value[i];
|
|
80
|
-
if (n
|
|
81
|
-
|
|
82
|
-
array[i] = hydrate.call(this, n);
|
|
73
|
+
if (n !== HOLE)
|
|
74
|
+
array[i] = hydrate.call(this, n);
|
|
83
75
|
}
|
|
76
|
+
return array;
|
|
84
77
|
}
|
|
85
78
|
}
|
|
86
79
|
else {
|
|
87
80
|
const object = {};
|
|
88
|
-
|
|
89
|
-
for (const key in value)
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
81
|
+
hydrated[index] = object;
|
|
82
|
+
for (const key in value)
|
|
83
|
+
object[key] = hydrate.call(this, value[key]);
|
|
84
|
+
return object;
|
|
93
85
|
}
|
|
94
|
-
return this.hydrated[index];
|
|
95
86
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turbo-stream",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
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
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"build": "tsc --outDir dist --project tsconfig.lib.json",
|
|
21
21
|
"test": "node --no-warnings --loader tsm --enable-source-maps --test-reporter tap --test src/*.spec.ts",
|
|
22
22
|
"test-typecheck": "tsc --noEmit --project tsconfig.spec.json",
|
|
23
|
-
"prepublish": "attw $(npm pack)"
|
|
23
|
+
"prepublish": "attw $(npm pack) --ignore-rules cjs-resolves-to-esm"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [],
|
|
26
26
|
"author": "",
|