@beignet/core
Version:
Core framework primitives for Beignet
110 lines • 3.77 kB
JavaScript
const QUERY_VALUE_PREFIX = "~beignet-query:";
function encodeStructuredValue(value, ancestors) {
if (value === null)
return { type: "null" };
if (typeof value === "string")
return { type: "string", value };
if (typeof value === "number" && Number.isFinite(value)) {
return { type: "number", value };
}
if (typeof value === "boolean")
return { type: "boolean", value };
if (value instanceof Date && Number.isFinite(value.getTime())) {
return { type: "date", value: value.toISOString() };
}
if (typeof value !== "object" || value === null) {
throw new TypeError("Query value is not serializable.");
}
if (ancestors.has(value)) {
throw new TypeError("Query value contains a circular reference.");
}
ancestors.add(value);
try {
if (Array.isArray(value)) {
return {
type: "array",
value: value.map((entry) => encodeStructuredValue(entry, ancestors)),
};
}
const prototype = Object.getPrototypeOf(value);
if (prototype !== Object.prototype && prototype !== null) {
throw new TypeError("Query value contains a non-plain object.");
}
return {
type: "object",
value: Object.fromEntries(Object.entries(value)
.filter(([, entry]) => entry !== undefined)
.map(([key, entry]) => [
key,
encodeStructuredValue(entry, ancestors),
])),
};
}
finally {
ancestors.delete(value);
}
}
function decodeStructuredValue(value) {
if (typeof value !== "object" || value === null || !("type" in value)) {
throw new TypeError("Invalid encoded query value.");
}
const encoded = value;
switch (encoded.type) {
case "null":
return null;
case "string":
if (typeof encoded.value === "string")
return encoded.value;
break;
case "number":
if (typeof encoded.value === "number" && Number.isFinite(encoded.value)) {
return encoded.value;
}
break;
case "boolean":
if (typeof encoded.value === "boolean")
return encoded.value;
break;
case "date": {
if (typeof encoded.value !== "string")
break;
const date = new Date(encoded.value);
if (Number.isFinite(date.getTime()))
return date;
break;
}
case "array":
if (Array.isArray(encoded.value)) {
return encoded.value.map(decodeStructuredValue);
}
break;
case "object":
if (typeof encoded.value === "object" &&
encoded.value !== null &&
!Array.isArray(encoded.value)) {
return Object.fromEntries(Object.entries(encoded.value).map(([key, entry]) => [
key,
decodeStructuredValue(entry),
]));
}
break;
}
throw new TypeError("Invalid encoded query value.");
}
export function encodeQueryValue(value) {
if (typeof value === "string" && !value.startsWith(QUERY_VALUE_PREFIX)) {
return value;
}
return `${QUERY_VALUE_PREFIX}${JSON.stringify(encodeStructuredValue(value, new Set()))}`;
}
export function decodeQueryValue(value) {
if (!value.startsWith(QUERY_VALUE_PREFIX))
return value;
try {
return decodeStructuredValue(JSON.parse(value.slice(QUERY_VALUE_PREFIX.length)));
}
catch {
return value;
}
}
//# sourceMappingURL=query-codec.js.map