Skip to content

Commit

Permalink
feat: minify things
Browse files Browse the repository at this point in the history
chore: update attw script
  • Loading branch information
jacob-ebey committed Oct 25, 2023
1 parent 5927ba1 commit 1db51bf
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 122 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "turbo-stream",
"version": "0.0.3",
"version": "0.0.4",
"description": "A streaming data transport format that aims to support built-in features such as Promises, Dates, RegExps, Maps, Sets and more.",
"type": "module",
"files": [
Expand All @@ -20,7 +20,7 @@
"build": "tsc --outDir dist --project tsconfig.lib.json",
"test": "node --no-warnings --loader tsm --enable-source-maps --test-reporter tap --test src/*.spec.ts",
"test-typecheck": "tsc --noEmit --project tsconfig.spec.json",
"prepublish": "attw $(npm pack)"
"prepublish": "attw $(npm pack) --ignore-rules cjs-resolves-to-esm"
},
"keywords": [],
"author": "",
Expand Down
107 changes: 37 additions & 70 deletions src/flatten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ import {
} from "./utils.js";

export function flatten(this: ThisEncode, input: unknown): number {
if (this.indicies.has(input)) {
return this.indicies.get(input)!;
}
const existing = this.indicies.get(input);
if (existing) return existing;

if (input === undefined) return UNDEFINED;
if (Number.isNaN(input)) return NAN;
Expand All @@ -29,102 +28,71 @@ export function flatten(this: ThisEncode, input: unknown): number {
const index = this.index++;
this.indicies.set(input, index);
stringify.call(this, input, index);

return index;
}

function stringify(this: ThisEncode, input: unknown, index: number) {
const str = this.stringified;

switch (typeof input) {
case "boolean":
case "number":
case "string":
this.stringified[index] = JSON.stringify(input);
str[index] = JSON.stringify(input);
break;
case "bigint":
this.stringified[index] = `["${TYPE_BIGINT}","${input}"]`;
str[index] = `["${TYPE_BIGINT}","${input}"]`;
break;
case "symbol":
const keyFor = Symbol.keyFor(input);
if (!keyFor)
throw new Error(
"Cannot encode symbol unless created with Symbol.for()"
);
this.stringified[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
str[index] = `["${TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
break;
case "object":
if (!input) {
this.stringified[index] = "null";
str[index] = "null";
break;
}

let result = Array.isArray(input) ? "[" : "{";
if (Array.isArray(input)) {
let result = "[";
for (let i = 0; i < input.length; i++) {
if (i > 0) result += ",";
if (i in input) {
result += flatten.call(this, input[i]);
} else {
result += HOLE;
}
}
this.stringified[index] = result + "]";
break;
}

if (input instanceof Date) {
this.stringified[index] = `["${TYPE_DATE}",${input.getTime()}]`;
break;
}

if (input instanceof RegExp) {
this.stringified[index] = `["${TYPE_REGEXP}",${JSON.stringify(
for (let i = 0; i < input.length; i++)
result +=
(i ? "," : "") + (i in input ? flatten.call(this, input[i]) : HOLE);
str[index] = result + "]";
} else if (input instanceof Date) {
str[index] = `["${TYPE_DATE}",${input.getTime()}]`;
} else if (input instanceof RegExp) {
str[index] = `["${TYPE_REGEXP}",${JSON.stringify(
input.source
)},${JSON.stringify(input.flags)}]`;
break;
}

if (input instanceof Set) {
let result = `["${TYPE_SET}"`;
for (const value of input) {
result += "," + flatten.call(this, value);
}
this.stringified[index] = result + "]";
break;
}

if (input instanceof Map) {
let result = `["${TYPE_MAP}"`;
for (const [key, value] of input) {
result += "," + flatten.call(this, key);
result += "," + flatten.call(this, value);
}
this.stringified[index] = result + "]";
break;
}

if (input instanceof Promise) {
this.stringified[index] = `["${TYPE_PROMISE}",${index}]`;
} else if (input instanceof Set) {
str[index] = `["${TYPE_SET}",${[...input]
.map((val) => flatten.call(this, val))
.join(",")}]`;
} else if (input instanceof Map) {
str[index] = `["${TYPE_MAP}",${[...input]
.flatMap(([k, v]) => [flatten.call(this, k), flatten.call(this, v)])
.join(",")}]`;
} else if (input instanceof Promise) {
str[index] = `["${TYPE_PROMISE}",${index}]`;
this.deferred[index] = input;
break;
}

if (!isPlainObject(input)) {
} else if (isPlainObject(input)) {
const parts = [];
for (const key in input)
parts.push(
`${JSON.stringify(key)}:${flatten.call(this, input[key])}`
);
str[index] = "{" + parts.join(",") + "}";
} else {
throw new Error("Cannot encode object with prototype");
}

let result = "{";
let sep = false;
for (const key in input) {
if (sep) result += ",";
sep = true;
result += JSON.stringify(key) + ":" + flatten.call(this, input[key]);
}
this.stringified[index] = result + "}";
break;
case "function":
throw new Error("Cannot encode function");
case "undefined":
throw new Error("This should never happen");
default:
throw new Error("Cannot encode function or unexpected type");
}
}

Expand All @@ -136,7 +104,6 @@ function isPlainObject(
thing: unknown
): thing is Record<string | number | symbol, unknown> {
const proto = Object.getPrototypeOf(thing);

return (
proto === Object.prototype ||
proto === null ||
Expand Down
95 changes: 45 additions & 50 deletions src/unflatten.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,9 @@ import {
} from "./utils.js";

export function unflatten(this: ThisDecode, parsed: unknown): unknown {
if (typeof parsed === "number") return hydrate.call(this, parsed, true);
if (typeof parsed === "number") return hydrate.call(this, parsed);

if (!Array.isArray(parsed) || parsed.length === 0) {
throw new Error("Invalid input");
}
if (!Array.isArray(parsed) || !parsed.length) throw new SyntaxError();

const startIndex = this.values.length;
this.values.push(...parsed);
Expand All @@ -30,84 +28,81 @@ export function unflatten(this: ThisDecode, parsed: unknown): unknown {
return hydrate.call(this, startIndex);
}

function hydrate(this: ThisDecode, index: number, standalone?: true) {
if (index === UNDEFINED) return undefined;
if (index === NAN) return NaN;
if (index === POSITIVE_INFINITY) return Infinity;
if (index === NEGATIVE_INFINITY) return -Infinity;
if (index === NEGATIVE_ZERO) return -0;
function hydrate(this: ThisDecode, index: number) {
const { hydrated, values, deferred } = this;

switch (index) {
case UNDEFINED:
return;
case NAN:
return NaN;
case POSITIVE_INFINITY:
return Infinity;
case NEGATIVE_INFINITY:
return -Infinity;
case NEGATIVE_ZERO:
return -0;
}

if (standalone) throw new Error(`Invalid input`);
if (hydrated[index]) return hydrated[index];

if (index in this.hydrated) return this.hydrated[index];
const value = values[index];
if (!value || typeof value !== "object") return (hydrated[index] = value);

const value = this.values[index];
if (!value || typeof value !== "object") {
this.hydrated[index] = value;
} else if (Array.isArray(value)) {
if (Array.isArray(value)) {
if (typeof value[0] === "string") {
switch (value[0]) {
case TYPE_DATE:
this.hydrated[index] = new Date(value[1]);
break;
return (hydrated[index] = new Date(value[1]));
case TYPE_BIGINT:
this.hydrated[index] = BigInt(value[1]);
break;
return (hydrated[index] = BigInt(value[1]));
case TYPE_REGEXP:
this.hydrated[index] = new RegExp(value[1], value[2]);
break;
return (hydrated[index] = new RegExp(value[1], value[2]));
case TYPE_SYMBOL:
this.hydrated[index] = Symbol.for(value[1]);
break;
return (hydrated[index] = Symbol.for(value[1]));
case TYPE_SET:
const set = new Set();
this.hydrated[index] = set;
for (let i = 1; i < value.length; i += 1) {
hydrated[index] = set;
for (let i = 1; i < value.length; i++)
set.add(hydrate.call(this, value[i]));
}
break;
return set;
case TYPE_MAP:
const map = new Map();
this.hydrated[index] = map;
hydrated[index] = map;
for (let i = 1; i < value.length; i += 2) {
map.set(
hydrate.call(this, value[i]),
hydrate.call(this, value[i + 1])
);
}
break;
return map;
case TYPE_PROMISE:
if (this.hydrated[value[1]]) {
this.hydrated[index] = this.hydrated[value[1]];
if (hydrated[value[1]]) {
return (hydrated[index] = hydrated[value[1]]);
} else {
const deferred = new Deferred();
this.deferred[value[1]] = deferred;
this.hydrated[index] = deferred.promise;
const d = new Deferred();
deferred[value[1]] = d;
return (hydrated[index] = d.promise);
}
break;
default:
throw new Error(`Invalid input`);
throw new SyntaxError();
}
} else {
const array = new Array(value.length);
this.hydrated[index] = array;
const array: unknown[] = [];
hydrated[index] = array;

for (let i = 0; i < value.length; i += 1) {
for (let i = 0; i < value.length; i++) {
const n = value[i];
if (n === HOLE) continue;

array[i] = hydrate.call(this, n);
if (n !== HOLE) array[i] = hydrate.call(this, n);
}
return array;
}
} else {
const object: Record<string, unknown> = {};
this.hydrated[index] = object;
hydrated[index] = object;

for (const key in value) {
const n = (value as any)[key];
object[key] = hydrate.call(this, n);
}
for (const key in value)
object[key] = hydrate.call(this, (value as Record<string, number>)[key]);
return object;
}

return this.hydrated[index];
}

0 comments on commit 1db51bf

Please sign in to comment.