204 lines
8.4 KiB
JavaScript
204 lines
8.4 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.flatten = void 0;
|
|
const utils_js_1 = require("./utils.js");
|
|
function flatten(input) {
|
|
const { indices } = this;
|
|
const existing = indices.get(input);
|
|
if (existing)
|
|
return [existing];
|
|
if (input === undefined)
|
|
return utils_js_1.UNDEFINED;
|
|
if (input === null)
|
|
return utils_js_1.NULL;
|
|
if (Number.isNaN(input))
|
|
return utils_js_1.NAN;
|
|
if (input === Number.POSITIVE_INFINITY)
|
|
return utils_js_1.POSITIVE_INFINITY;
|
|
if (input === Number.NEGATIVE_INFINITY)
|
|
return utils_js_1.NEGATIVE_INFINITY;
|
|
if (input === 0 && 1 / input < 0)
|
|
return utils_js_1.NEGATIVE_ZERO;
|
|
const index = this.index++;
|
|
indices.set(input, index);
|
|
stringify.call(this, input, index);
|
|
return index;
|
|
}
|
|
exports.flatten = flatten;
|
|
function stringify(input, index) {
|
|
const { deferred, plugins, postPlugins } = this;
|
|
const str = this.stringified;
|
|
const stack = [[input, index]];
|
|
while (stack.length > 0) {
|
|
const [input, index] = stack.pop();
|
|
const partsForObj = (obj) => Object.keys(obj)
|
|
.map((k) => `"_${flatten.call(this, k)}":${flatten.call(this, obj[k])}`)
|
|
.join(",");
|
|
let error = null;
|
|
switch (typeof input) {
|
|
case "boolean":
|
|
case "number":
|
|
case "string":
|
|
str[index] = JSON.stringify(input);
|
|
break;
|
|
case "bigint":
|
|
str[index] = `["${utils_js_1.TYPE_BIGINT}","${input}"]`;
|
|
break;
|
|
case "symbol": {
|
|
const keyFor = Symbol.keyFor(input);
|
|
if (!keyFor) {
|
|
error = new Error("Cannot encode symbol unless created with Symbol.for()");
|
|
}
|
|
else {
|
|
str[index] = `["${utils_js_1.TYPE_SYMBOL}",${JSON.stringify(keyFor)}]`;
|
|
}
|
|
break;
|
|
}
|
|
case "object": {
|
|
if (!input) {
|
|
str[index] = `${utils_js_1.NULL}`;
|
|
break;
|
|
}
|
|
const isArray = Array.isArray(input);
|
|
let pluginHandled = false;
|
|
if (!isArray && plugins) {
|
|
for (const plugin of plugins) {
|
|
const pluginResult = plugin(input);
|
|
if (Array.isArray(pluginResult)) {
|
|
pluginHandled = true;
|
|
const [pluginIdentifier, ...rest] = pluginResult;
|
|
str[index] = `[${JSON.stringify(pluginIdentifier)}`;
|
|
if (rest.length > 0) {
|
|
str[index] += `,${rest
|
|
.map((v) => flatten.call(this, v))
|
|
.join(",")}`;
|
|
}
|
|
str[index] += "]";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pluginHandled) {
|
|
let result = isArray ? "[" : "{";
|
|
if (isArray) {
|
|
for (let i = 0; i < input.length; i++)
|
|
result +=
|
|
(i ? "," : "") +
|
|
(i in input ? flatten.call(this, input[i]) : utils_js_1.HOLE);
|
|
str[index] = `${result}]`;
|
|
}
|
|
else if (input instanceof Date) {
|
|
str[index] = `["${utils_js_1.TYPE_DATE}",${input.getTime()}]`;
|
|
}
|
|
else if (input instanceof URL) {
|
|
str[index] = `["${utils_js_1.TYPE_URL}",${JSON.stringify(input.href)}]`;
|
|
}
|
|
else if (input instanceof RegExp) {
|
|
str[index] = `["${utils_js_1.TYPE_REGEXP}",${JSON.stringify(input.source)},${JSON.stringify(input.flags)}]`;
|
|
}
|
|
else if (input instanceof Set) {
|
|
if (input.size > 0) {
|
|
str[index] = `["${utils_js_1.TYPE_SET}",${[...input]
|
|
.map((val) => flatten.call(this, val))
|
|
.join(",")}]`;
|
|
}
|
|
else {
|
|
str[index] = `["${utils_js_1.TYPE_SET}"]`;
|
|
}
|
|
}
|
|
else if (input instanceof Map) {
|
|
if (input.size > 0) {
|
|
str[index] = `["${utils_js_1.TYPE_MAP}",${[...input]
|
|
.flatMap(([k, v]) => [
|
|
flatten.call(this, k),
|
|
flatten.call(this, v),
|
|
])
|
|
.join(",")}]`;
|
|
}
|
|
else {
|
|
str[index] = `["${utils_js_1.TYPE_MAP}"]`;
|
|
}
|
|
}
|
|
else if (input instanceof Promise) {
|
|
str[index] = `["${utils_js_1.TYPE_PROMISE}",${index}]`;
|
|
deferred[index] = input;
|
|
}
|
|
else if (input instanceof Error) {
|
|
str[index] = `["${utils_js_1.TYPE_ERROR}",${JSON.stringify(input.message)}`;
|
|
if (input.name !== "Error") {
|
|
str[index] += `,${JSON.stringify(input.name)}`;
|
|
}
|
|
str[index] += "]";
|
|
}
|
|
else if (Object.getPrototypeOf(input) === null) {
|
|
str[index] = `["${utils_js_1.TYPE_NULL_OBJECT}",{${partsForObj(input)}}]`;
|
|
}
|
|
else if (isPlainObject(input)) {
|
|
str[index] = `{${partsForObj(input)}}`;
|
|
}
|
|
else {
|
|
error = new Error("Cannot encode object with prototype");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default: {
|
|
const isArray = Array.isArray(input);
|
|
let pluginHandled = false;
|
|
if (!isArray && plugins) {
|
|
for (const plugin of plugins) {
|
|
const pluginResult = plugin(input);
|
|
if (Array.isArray(pluginResult)) {
|
|
pluginHandled = true;
|
|
const [pluginIdentifier, ...rest] = pluginResult;
|
|
str[index] = `[${JSON.stringify(pluginIdentifier)}`;
|
|
if (rest.length > 0) {
|
|
str[index] += `,${rest
|
|
.map((v) => flatten.call(this, v))
|
|
.join(",")}`;
|
|
}
|
|
str[index] += "]";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pluginHandled) {
|
|
error = new Error("Cannot encode function or unexpected type");
|
|
}
|
|
}
|
|
}
|
|
if (error) {
|
|
let pluginHandled = false;
|
|
if (postPlugins) {
|
|
for (const plugin of postPlugins) {
|
|
const pluginResult = plugin(input);
|
|
if (Array.isArray(pluginResult)) {
|
|
pluginHandled = true;
|
|
const [pluginIdentifier, ...rest] = pluginResult;
|
|
str[index] = `[${JSON.stringify(pluginIdentifier)}`;
|
|
if (rest.length > 0) {
|
|
str[index] += `,${rest
|
|
.map((v) => flatten.call(this, v))
|
|
.join(",")}`;
|
|
}
|
|
str[index] += "]";
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (!pluginHandled) {
|
|
throw error;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
const objectProtoNames = Object.getOwnPropertyNames(Object.prototype)
|
|
.sort()
|
|
.join("\0");
|
|
function isPlainObject(thing) {
|
|
const proto = Object.getPrototypeOf(thing);
|
|
return (proto === Object.prototype ||
|
|
proto === null ||
|
|
Object.getOwnPropertyNames(proto).sort().join("\0") === objectProtoNames);
|
|
}
|