matchable
Version:
A utility to define and match on tagged unions (like enums with payloads) — safely.
2 lines (1 loc) • 1.31 kB
JavaScript
function m(t,a){let e={};for(let n of t._tags){let o=a[n];o&&(e[n]=o)}return a.default&&(e.default=a.default),e}function u(t){return typeof t=="object"&&t!==null&&"tag"in t}function h(t,a){return u(a)&&typeof a.tag=="string"&&t._tags.includes(a.tag)}function p(t){let a={};for(let n of t)a[n]=o=>u(o)&&o.tag===n;return{...a,Valid:n=>u(n)&&typeof n.tag=="string"&&t.includes(n.tag)}}function g(t,a){try{let e=JSON.parse(a);if(!t.is.Valid(e))throw new TypeError("Deserialized object is not a valid variant");return e}catch(e){throw e instanceof SyntaxError?new TypeError("Invalid JSON"):e}}function d(t){return JSON.stringify(t)}function _(t){let a=Symbol("matchable.instance"),e={},n=Object.keys(t),o=p(n);for(let r of n){let i=t[r];if(typeof i!="function")throw new TypeError(`Invalid constructor for tag: ${r}`);e[r]=(...c)=>{let l=i(...c);return{tag:r,...l,__matchable_id__:a}}}function y(r,i){let{tag:c}=r;if("__matchable_id__"in r&&r.__matchable_id__!==a)throw new Error(`Mismatched matchable instance for tag: ${c}`);if(c in i){let l=i[c];if(typeof l=="function")return l(r)}if("default"in i&&typeof i.default=="function")return i.default(r);throw new Error(`Unhandled tag: ${c}`)}return{...e,_tags:n,deserialize:r=>g({_tags:n,is:o},r),is:o,match:y,serialize:d}}export{m as group,h as isValid,_ as matchable};