@orpc/openapi-client
Version:
<div align="center"> <image align="center" src="https://orpc.dev/logo.webp" width=280 alt="oRPC logo" /> </div>
147 lines (144 loc) • 4.89 kB
JavaScript
import { isObject, NullProtoObj } from '@orpc/shared';
class StandardBracketNotationSerializer {
maxArrayIndex;
constructor(options = {}) {
this.maxArrayIndex = options.maxBracketNotationArrayIndex ?? 9999;
}
serialize(data, segments = [], result = []) {
if (Array.isArray(data)) {
data.forEach((item, i) => {
this.serialize(item, [...segments, i], result);
});
} else if (isObject(data)) {
for (const key in data) {
this.serialize(data[key], [...segments, key], result);
}
} else {
result.push([this.stringifyPath(segments), data]);
}
return result;
}
deserialize(serialized) {
if (serialized.length === 0) {
return {};
}
const arrayPushStyles = /* @__PURE__ */ new WeakSet();
const ref = { value: [] };
for (const [path, value] of serialized) {
const segments = this.parsePath(path);
let currentRef = ref;
let nextSegment = "value";
segments.forEach((segment, i) => {
if (!Array.isArray(currentRef[nextSegment]) && !isObject(currentRef[nextSegment])) {
currentRef[nextSegment] = [];
}
if (i !== segments.length - 1) {
if (Array.isArray(currentRef[nextSegment]) && !isValidArrayIndex(segment, this.maxArrayIndex)) {
if (arrayPushStyles.has(currentRef[nextSegment])) {
arrayPushStyles.delete(currentRef[nextSegment]);
currentRef[nextSegment] = pushStyleArrayToObject(currentRef[nextSegment]);
} else {
currentRef[nextSegment] = arrayToObject(currentRef[nextSegment]);
}
}
} else {
if (Array.isArray(currentRef[nextSegment])) {
if (segment === "") {
if (currentRef[nextSegment].length && !arrayPushStyles.has(currentRef[nextSegment])) {
currentRef[nextSegment] = arrayToObject(currentRef[nextSegment]);
}
} else {
if (arrayPushStyles.has(currentRef[nextSegment])) {
arrayPushStyles.delete(currentRef[nextSegment]);
currentRef[nextSegment] = pushStyleArrayToObject(currentRef[nextSegment]);
} else if (!isValidArrayIndex(segment, this.maxArrayIndex)) {
currentRef[nextSegment] = arrayToObject(currentRef[nextSegment]);
}
}
}
}
currentRef = currentRef[nextSegment];
nextSegment = segment;
});
if (Array.isArray(currentRef) && nextSegment === "") {
arrayPushStyles.add(currentRef);
currentRef.push(value);
} else if (nextSegment in currentRef) {
if (Array.isArray(currentRef[nextSegment])) {
currentRef[nextSegment].push(value);
} else {
currentRef[nextSegment] = [currentRef[nextSegment], value];
}
} else {
currentRef[nextSegment] = value;
}
}
return ref.value;
}
stringifyPath(segments) {
return segments.map((segment) => {
return segment.toString().replace(/[\\[\]]/g, (match) => {
switch (match) {
case "\\":
return "\\\\";
case "[":
return "\\[";
case "]":
return "\\]";
/* v8 ignore next 2 */
default:
return match;
}
});
}).reduce((result, segment, i) => {
if (i === 0) {
return segment;
}
return `${result}[${segment}]`;
}, "");
}
parsePath(path) {
const segments = [];
let inBrackets = false;
let currentSegment = "";
let backslashCount = 0;
for (let i = 0; i < path.length; i++) {
const char = path[i];
const nextChar = path[i + 1];
if (inBrackets && char === "]" && (nextChar === void 0 || nextChar === "[") && backslashCount % 2 === 0) {
if (nextChar === void 0) {
inBrackets = false;
}
segments.push(currentSegment);
currentSegment = "";
i++;
} else if (segments.length === 0 && char === "[" && backslashCount % 2 === 0) {
inBrackets = true;
segments.push(currentSegment);
currentSegment = "";
} else if (char === "\\") {
backslashCount++;
} else {
currentSegment += "\\".repeat(backslashCount / 2) + char;
backslashCount = 0;
}
}
return inBrackets || segments.length === 0 ? [path] : segments;
}
}
function isValidArrayIndex(value, maxIndex) {
return /^0$|^[1-9]\d*$/.test(value) && Number(value) <= maxIndex;
}
function arrayToObject(array) {
const obj = new NullProtoObj();
array.forEach((item, i) => {
obj[i] = item;
});
return obj;
}
function pushStyleArrayToObject(array) {
const obj = new NullProtoObj();
obj[""] = array.length === 1 ? array[0] : array;
return obj;
}
export { StandardBracketNotationSerializer as S };