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 CHANGED
@@ -1,4 +1,4 @@
1
- # Turbo Stream
1
+ # Turbo Stream <br> [![turbo-stream's badge](https://deno.bundlejs.com/?q=turbo-stream&badge=detailed)](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
- if (this.indicies.has(input)) {
4
- return this.indicies.get(input);
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
- this.stringified[index] = JSON.stringify(input);
27
+ str[index] = JSON.stringify(input);
27
28
  break;
28
29
  case "bigint":
29
- this.stringified[index] = `["${TYPE_BIGINT}","${input}"]`;
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
- this.stringified[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
36
+ str[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
36
37
  break;
37
38
  case "object":
38
39
  if (!input) {
39
- this.stringified[index] = "null";
40
+ str[index] = "null";
40
41
  break;
41
42
  }
43
+ let result = Array.isArray(input) ? "[" : "{";
42
44
  if (Array.isArray(input)) {
43
- let result = "[";
44
- for (let i = 0; i < input.length; i++) {
45
- if (i > 0)
46
- result += ",";
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
- this.stringified[index] = `["${TYPE_DATE}",${input.getTime()}]`;
59
- break;
50
+ else if (input instanceof Date) {
51
+ str[index] = `["${TYPE_DATE}",${input.getTime()}]`;
60
52
  }
61
- if (input instanceof RegExp) {
62
- this.stringified[index] = `["${TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
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
- let result = `["${TYPE_SET}"`;
67
- for (const value of input) {
68
- result += "," + flatten.call(this, value);
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
- let result = `["${TYPE_MAP}"`;
75
- for (const [key, value] of input) {
76
- result += "," + flatten.call(this, key);
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
- this.stringified[index] = `["${TYPE_PROMISE}",${index}]`;
66
+ else if (input instanceof Promise) {
67
+ str[index] = `["${TYPE_PROMISE}",${index}]`;
84
68
  this.deferred[index] = input;
85
- break;
86
69
  }
87
- if (!isPlainObject(input)) {
88
- throw new Error("Cannot encode object with prototype");
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
- let result = "{";
91
- let sep = false;
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
- case "function":
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, true);
5
- if (!Array.isArray(parsed) || parsed.length === 0) {
6
- throw new Error("Invalid input");
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, standalone) {
14
- if (index === UNDEFINED)
15
- return undefined;
16
- if (index === NAN)
17
- return NaN;
18
- if (index === POSITIVE_INFINITY)
19
- return Infinity;
20
- if (index === NEGATIVE_INFINITY)
21
- return -Infinity;
22
- if (index === NEGATIVE_ZERO)
23
- return -0;
24
- if (standalone)
25
- throw new Error(`Invalid input`);
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
- else if (Array.isArray(value)) {
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
- this.hydrated[index] = new Date(value[1]);
37
- break;
35
+ return (hydrated[index] = new Date(value[1]));
38
36
  case TYPE_BIGINT:
39
- this.hydrated[index] = BigInt(value[1]);
40
- break;
37
+ return (hydrated[index] = BigInt(value[1]));
41
38
  case TYPE_REGEXP:
42
- this.hydrated[index] = new RegExp(value[1], value[2]);
43
- break;
39
+ return (hydrated[index] = new RegExp(value[1], value[2]));
44
40
  case TYPE_SYMBOL:
45
- this.hydrated[index] = Symbol.for(value[1]);
46
- break;
41
+ return (hydrated[index] = Symbol.for(value[1]));
47
42
  case TYPE_SET:
48
43
  const set = new Set();
49
- this.hydrated[index] = set;
50
- for (let i = 1; i < value.length; i += 1) {
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
- this.hydrated[index] = map;
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
- break;
54
+ return map;
61
55
  case TYPE_PROMISE:
62
- if (this.hydrated[value[1]]) {
63
- this.hydrated[index] = this.hydrated[value[1]];
56
+ if (hydrated[value[1]]) {
57
+ return (hydrated[index] = hydrated[value[1]]);
64
58
  }
65
59
  else {
66
- const deferred = new Deferred();
67
- this.deferred[value[1]] = deferred;
68
- this.hydrated[index] = deferred.promise;
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 Error(`Invalid input`);
65
+ throw new SyntaxError();
73
66
  }
74
67
  }
75
68
  else {
76
- const array = new Array(value.length);
77
- this.hydrated[index] = array;
78
- for (let i = 0; i < value.length; i += 1) {
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 === HOLE)
81
- continue;
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
- this.hydrated[index] = object;
89
- for (const key in value) {
90
- const n = value[key];
91
- object[key] = hydrate.call(this, n);
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",
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": "",