ts-switch-case
Version:
A TypeScript-first switch-case utility with object-based and chainable syntax
173 lines (169 loc) • 5.89 kB
JavaScript
;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// index.ts
var index_exports = {};
__export(index_exports, {
assertUnreachable: () => assertUnreachable,
switchCase: () => switchCase
});
module.exports = __toCommonJS(index_exports);
// src/utils.ts
function logCyclicError(obj, path, context) {
console.error("[Cyclic Reference]", {
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
context,
path: path.join(" -> "),
objectType: obj?.constructor?.name || "unknown"
});
}
function isCyclic(obj, seen = /* @__PURE__ */ new WeakSet(), path = ["root"]) {
if (obj && typeof obj === "object") {
if (seen.has(obj)) {
logCyclicError(obj, path, "Cycle detected");
return true;
}
seen.add(obj);
for (const key in obj) {
if (isCyclic(obj[key], seen, [...path, key])) return true;
}
}
return false;
}
// src/switchCase.ts
function switchCase(value, discriminatorOrCases, casesOrDefault, defaultHandler) {
if (discriminatorOrCases === void 0) {
const cases2 = [];
let defaultFn;
const builder = {
case(match, handler) {
cases2.push({ match, handler });
return this;
},
default(handler) {
defaultFn = handler;
return this;
},
exhaustive() {
return this.run();
},
run() {
for (const { match, handler } of cases2) {
const isMatch = typeof match === "function" ? match(value) : match === value;
if (isMatch) {
return typeof handler === "function" ? handler(value) : handler;
}
}
if (defaultFn) {
return defaultFn(value);
}
throw new Error(`No matching case for value: ${JSON.stringify(value)}`);
}
};
return builder;
}
if (Array.isArray(discriminatorOrCases)) {
if (isCyclic(discriminatorOrCases))
throw new Error(
"Cyclic cases detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
const cases2 = discriminatorOrCases;
const defaultFn = casesOrDefault;
for (const { match, handler } of cases2) {
if (match(value)) {
return typeof handler === "function" ? handler(value) : handler;
}
}
if (defaultFn) {
return defaultFn(value);
}
throw new Error(`No matching case for value: ${JSON.stringify(value)}`);
}
if (typeof discriminatorOrCases === "object") {
if (isCyclic(discriminatorOrCases))
throw new Error(
"Cyclic cases detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
const cases2 = discriminatorOrCases;
const defaultFn = casesOrDefault;
const literalHandler = cases2[String(value)];
if (literalHandler !== void 0) {
const result = typeof literalHandler === "function" ? literalHandler() : literalHandler;
if (isCyclic(result))
throw new Error(
"Cyclic result detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
return result;
}
for (const key of Object.keys(cases2)) {
const c = cases2[key];
if (typeof c !== "function") {
const match = typeof c.match === "function" ? c.match(value) : c.match === value;
if (match) {
const result = typeof c.handler === "function" ? c.handler(value) : c.handler;
if (isCyclic(result))
throw new Error(
"Cyclic result detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
return result;
}
}
}
if (defaultFn) {
const result = defaultFn(value);
if (isCyclic(result))
throw new Error(
"Cyclic result detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
return result;
}
throw new Error(`No matching case for value: ${JSON.stringify(value)}`);
}
if (isCyclic(casesOrDefault)) throw new Error("Cyclic cases");
const discriminator = discriminatorOrCases;
const cases = casesOrDefault;
const discriminatorValue = String(value[discriminator]);
const handlerOrValue = cases[discriminatorValue];
if (handlerOrValue !== void 0) {
const result = typeof handlerOrValue === "function" ? handlerOrValue(value) : handlerOrValue;
if (isCyclic(result))
throw new Error(
"Cyclic result detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
return result;
}
if (defaultHandler) {
const result = defaultHandler(value);
if (isCyclic(result))
throw new Error(
"Cyclic result detected. See ts-switch-case README for handling cycles (e.g., sanitizeNode for React)."
);
return result;
}
throw new Error(
`No matching case for ${String(discriminator)}: ${discriminatorValue}`
);
}
function assertUnreachable(value) {
throw new Error(`Unreachable case: ${value}`);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
assertUnreachable,
switchCase
});