slang-ts 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- const e=e=>{let t=globalThis?.queueMicrotask;typeof t==`function`?t(e):Promise.resolve().then(e)},t=e=>typeof e==`object`&&!!e&&`type`in e&&(e.type===`Ok`||e.type===`Err`),n=Symbol(`slang.activate`),r=e=>typeof e==`object`&&!!e&&`isSome`in e&&`isNone`in e,i=e=>typeof e==`object`&&!!e&&typeof e.valueOf?.()==`symbol`;function a(e){return i(e)?{ok:!0,value:e.valueOf().description}:t(e)?e.isOk?{ok:!0,value:e.value}:{ok:!1,error:l(e.error)}:r(e)?e.isSome?{ok:!0,value:e.value}:{ok:!1,error:`Option was None`}:{ok:!0,value:e}}function o(e){let t=e;for(let e of[`message`,`error`,`reason`]){let n=t[e];if(typeof n==`string`&&n.length>0)return n}}function s(e,t){return e.length>t?`${e.slice(0,t)}...`:e}function c(e){let t=/* @__PURE__ */ new WeakSet;try{let n=JSON.stringify(e,(e,n)=>{if(typeof n==`bigint`)return n.toString();if(typeof n!=`function`&&typeof n!=`symbol`){if(typeof n==`object`&&n){if(t.has(n))return`[Circular]`;t.add(n)}return n}});if(typeof n==`string`&&n.length>0&&n!==`{}`)return n}catch{}return Object.prototype.toString.call(e)}function l(e,t=512){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;if(typeof e==`bigint`)return e.toString();if(e==null)return String(e);if(typeof e==`object`){let n=o(e);return s(n===void 0?c(e):n,t)}return String(e)}const u=`slang.nestedResultPanic`;function d(){let e=/* @__PURE__ */ Error(`A Result cannot be nested inside another Result`);throw Object.defineProperty(e,u,{value:!0}),e}function f(e){return e instanceof Error&&e[u]===!0}let p=`development`,m=null;const h=e=>{typeof e==`object`&&e?m=e.printFn??null:p=e===`production`||e===`prod`?`production`:`development`},g=e=>{if(typeof e==`string`)return e;if(typeof e==`symbol`)return String(e);if(typeof e==`function`)return`[Function ${e.name}]`;try{return String(e)}catch{try{return JSON.stringify(e)??`null`}catch{return Object.prototype.toString.call(e)}}},_=(...e)=>{let t=e.map(g).join(` `).concat(`
2
- `);m?m(t):p!==`production`&&globalThis.console?.log?.(t)};function v(e){throw Error(e)}function y(e,t){return{outcome:e,category:t,else(t){return e.isOk?e.value:typeof t==`function`?t(e.error):t},panic(t){if(e.isOk)return e.value;throw Error(t??e.error)}}}function b(e){return y(T(e),void 0)}function x(e,t){return y(D(t),e)}function S(e,t){return e.outcome.isErr?y(D(e.outcome.error),e.category):t(e.outcome.value)}const C=e=>({[Symbol.iterator]:e}),ee=e=>y(D(e.message),e.category);function w(e,t=void 0,n=!1,r={consumed:!1}){let i=(e,i=t)=>w(e,i,n,r),a=i=>{if(t!==void 0)return ee(t);if(n&&r.consumed)return x(`INVALID_INPUT`,`This iterator has already been consumed`);r.consumed=!0;let a;try{return a=e(),b(i(a))}catch(e){return x(`INVALID_INPUT`,l(e))}finally{a?.return?.()}};return{map(t){return i(function*(){let n=0;for(let r of C(e))yield t(r,n++)})},filter(t){return i(function*(){let n=0;for(let r of C(e))t(r,n++)&&(yield r)})},flatMap(t){return i(function*(){let n=0;for(let r of C(e))yield*t(r,n++)})},take(t){return!Number.isSafeInteger(t)||t<0?i(function*(){},{category:`INVALID_INDEX`,message:`take needs a nonnegative integer`}):i(function*(){if(t===0)return;let n=C(e)[Symbol.iterator](),r=0;try{for(;r<t;){let e=n.next();if(e.done===!0)return;yield e.value,r+=1}}finally{n.return?.()}})},drop(t){return!Number.isSafeInteger(t)||t<0?i(function*(){},{category:`INVALID_INDEX`,message:`drop needs a nonnegative integer`}):i(function*(){let n=0;for(let r of C(e))n<t?n+=1:yield r})},chunk(t){return!Number.isSafeInteger(t)||t<=0?i(function*(){},{category:`INVALID_CHUNK_SIZE`,message:`chunk size must be a positive integer`}):i(function*(){let n=[];for(let r of C(e))n.push(r),n.length===t&&(yield n,n=[]);n.length>0&&(yield n)})},reduce(e,t){return a(n=>{let r=t,i=0;for(;;){let t=n.next();if(t.done===!0)return r;r=e(r,t.value,i++)}})},count(){return a(e=>{let t=0;for(;;){if(e.next().done===!0)return t;t+=1}})},toArray(){return a(e=>{let t=[];for(;;){let n=e.next();if(n.done===!0)return t;t.push(n.value)}})}}}function te(e){let t=typeof e==`string`||typeof e==`object`&&e&&Symbol.iterator in e?e:void 0;if(t!==void 0){let e=!1;try{e=t[Symbol.iterator]()===t}catch{}return w(()=>t[Symbol.iterator](),void 0,e)}return w(()=>{throw Error(`Cannot iterate a non-iterable value`)},{category:`INVALID_INPUT`,message:`Cannot iterate a non-iterable value`})}function T(n,r){t(n)&&d();let i=Object.freeze({type:`Ok`,value:n,...r===void 0?{}:{message:r},isOk:!0,isErr:!1}),a=e=>{let n=e=>e===void 0?o:t(e)?(t(e.value)&&d(),e):T(e);try{let t=e(i.value);return t instanceof Promise?t.then(e=>n(e)).catch(e=>D(l(e))):n(t)}catch(e){return D(l(e))}},o={...i,expect:(e=>i.value),unwrap:(()=>(e(()=>{}),{else(e){return i.value}})),andThen:a,iterate:()=>te(i.value)};return o}function E(e,t,...n){return T(e,t)}function D(t,n){let r=Object.freeze({type:`Err`,error:t,isOk:!1,isErr:!0}),i=e=>a,a={...r,expect:(e=>{throw Error(e??t)}),unwrap:(()=>{let n=!1;return e(()=>{if(!n)throw Error(t)}),{else(e){return n=!0,typeof e==`function`?e(t):e}}}),andThen:i};return O(a,n)}function O(e,t){return t===void 0||Object.defineProperty(e,"raw",{value:t,enumerable:!1,writable:!1,configurable:!1}),e}const k=e=>e==null||e===``||Number.isNaN(e)||e===1/0||e===-1/0;function ne(e){if(k(e))throw Error(`Cannot wrap null, undefined, NaN, or empty string in Some`);return Object.freeze({type:`Some`,value:e,isSome:!0,isNone:!1})}const re=Object.freeze({type:`None`,isSome:!1,isNone:!0});let A=null;function ie(e){A=e}function j(t){let n=k(t)?re:ne(t),r=(e=>{if(!A)throw Error(`Converter not initialized`);return A(n,e)}),i=(e=>{if(n.isSome)return n.value;throw Error(e??`Expected Some, got None`)}),a=(()=>{let t=!1,r=n;return e(()=>{if(!t)throw Error(`Expected else`)}),{else(e){if(t=!0,r.isSome)return r.value;let n=typeof e==`function`?e(void 0):e;if(k(n))throw Error(`Fallback must be truthy`);return n}}}),o=(e=>{let t=n;if(t.isNone)return s;let r=t.value;try{let t=e(r);return t instanceof Promise?t.then(e=>e===void 0?s:j(e)).catch(()=>j(null)):t===void 0?s:j(t)}catch{return j(null)}}),s={...n,to:r,expect:i,unwrap:a,andThen:o};return s}const M=e=>{if(typeof e!=`object`||!e)return e;let t=e;return t.isSome===!0||t.isOk===!0?t.value:e},ae=e=>{if(typeof e==`object`&&e){let t=e;if(t.isNone===!0||t.isErr===!0)return!0}return k(M(e))};function oe(e,t=D(`No value!`)){for(let t of e)if(!ae(t))return T(M(t));return t}let N=null;function se(e){N=e}function P(e){let t=Symbol(e),n=Object(t);return n.to=(e=>{if(!N)throw Error(`Converter not initialized`);return N(t,e)}),n.andThen=t=>{let r;try{r=t(e)}catch(e){v(`Atom.andThen: fn threw an error: ${l(e)}`)}return r===void 0?n:(typeof r!=`string`&&v(`Atom.andThen: fn must return a string, got ${typeof r}`),P(r))},n}const F=e=>typeof e==`object`&&!!e&&`isSome`in e&&`isNone`in e;function I(e,t){if(e&&(e.type===`Ok`||e.type===`Err`))throw Error(`Cannot convert a Result to any other type`);switch(t){case`option`:return F(e)?e:j(typeof e==`symbol`?e.description:e);case`atom`:if(F(e)){if(e.isNone)throw Error(`Cannot convert None to Atom`);if(typeof e.value!=`string`)throw Error(`Only string values can be converted to Atom`);return P(e.value)}if(typeof e==`symbol`)return e;throw Error(`Cannot convert type ${typeof e} to Atom`);case`result`:return F(e)?e.isSome?E(e.value):D(`Value is None`):E(typeof e==`symbol`?e.description:e);default:throw Error(`Invalid target: ${t}`)}}ie(I),se(I);function ce(e,t){let n=t[e.type];if(!n)throw Error(`Non-exhaustive match — missing handler for '${e.type}'`);return n(e)}const le=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`||typeof e==`symbol`;function ue(e,t){let n=e=>typeof e?.valueOf==`function`?e.valueOf():e,r=e=>typeof e==`symbol`?e.description:void 0,i=n(e);if(!le(i))throw Error(`Unsupported match all value type: ${typeof i}`);let a=r(i)??i,o=typeof a==`boolean`||typeof a==`number`?String(a):a;return o!=null&&o in t?t[o](e):t._()}function de(e,t=!1){if(!t&&!Array.isArray(e))throw Error(`Only arrays allowed when includeValues=false`);return Array.isArray(e)?e:e instanceof Set?Array.from(e):Object.values(e)}function L(e,t){let{fillValue:n,includeValues:r=!1}=t||{};if(e.length===0)return[];let i=e.map(e=>de(e,r)),a=Math.max(...i.map(e=>e.length)),o=Math.min(...i.map(e=>e.length)),s=n===void 0?o:a,c=[];for(let e=0;e<s;e++)c.push(i.map(t=>e<t.length?t[e]:n));return c}function fe(e,t,n){return L(e,n).map(t)}function pe(e){if(e.length===0)return[];let t=e[0]?.length??0,n=Array.from({length:t},()=>[]);for(let t of e)t.forEach((e,t)=>n[t]?.push(e));return n}async function me(e,n,...o){let s=n?.throw??!1,c=n?.collectValues??!1,u=[],p=[],m=e=>c?O(e,{errors:p,values:u}):e;try{let n=await e(),o=a(n),s=/* @__PURE__ */ new Set,l=+!!t(n),f=t(n)?n.raw:void 0,h=o.ok?void 0:n;for(;o.ok;){let e=o.value;if(t(e)&&(l+=1,l>1&&d()),c&&u.push(e),!i(e)&&!t(e)&&!r(e))return m(T(e));if(typeof e==`object`&&e){if(s.has(e))return m(D(`Cannot resolve a circular value`));s.add(e)}o=a(e),o.ok||(h=e)}return c?(p.push(t(h)?h.error:o.error),m(D(o.error))):D(o.error,f)}catch(e){if(f(e))throw e;let t=l(e);if(s)throw e instanceof Error?e:Error(t);return c?(p.push(e),m(D(t))):D(t,e)}}const R=e=>Number.isSafeInteger(e),z=(e,t)=>e<0?t+e:e;function he(e){return Array.isArray(e)?{ok:!0,value:e}:t(e)?e.isOk===!0&&Array.isArray(e.value)?{ok:!0,value:e.value}:{ok:!1,message:`list expects a raw array or a successful Ok holding one`}:{ok:!1,message:`list expects an array or a successful Ok`}}function B(e,t){let n=y(e,t),r=e=>B(e.outcome,e.category),i=((e,...t)=>S(n,n=>{if(!R(e))return x(`INVALID_INDEX`,`Index must be an integer`);let r=z(e,n.length);return r<0||r>=n.length?t.length===0?x(`OUT_OF_BOUNDS`,`No item at index ${e}`):b(t[0]):b(n[r])}));return{...n,get:i,take(e){return r(S(n,t=>R(e)?e<0||e>t.length?x(`OUT_OF_BOUNDS`,`take(${e}) is outside 0..${t.length}`):b(t.slice(0,e)):x(`INVALID_INDEX`,`take needs an integer count`)))},skip(e){return r(S(n,t=>R(e)?Math.abs(e)>t.length?x(`OUT_OF_BOUNDS`,`skip(${e}) is outside -${t.length}..${t.length}`):b(e>=0?t.slice(e):t.slice(0,t.length+e)):x(`INVALID_INDEX`,`skip needs an integer count`)))},range(e,t){return r(S(n,n=>{if(!R(e)||!R(t))return x(`INVALID_INDEX`,`range needs integer bounds`);let r=z(e,n.length),i=z(t,n.length);return r<0||r>n.length||i<0||i>n.length?x(`OUT_OF_BOUNDS`,`range(${e}, ${t}) is outside 0..${n.length}`):r>i?x(`INVALID_RANGE`,`range start must not exceed end`):b(n.slice(r,i))}))},chunk(e){let t=S(n,t=>{if(!R(e)||e<=0)return x(`INVALID_CHUNK_SIZE`,`chunk size must be a positive integer`);let n=[];for(let r=0;r<t.length;r+=e)n.push(t.slice(r,r+e));return b(n)});return B(t.outcome,t.category)},count(){return S(n,e=>b(e.length))},prune(e){return r(S(n,t=>{let n=e??(e=>!k(e));return b(t.filter((e,t)=>n(e,t)))}))}}}function ge(e){let t=he(e);return t.ok?B(E(t.value),void 0):B(D(t.message),`INVALID_INPUT`)}const V=e=>Object.prototype.toString.call(e)===`[object Object]`,_e=/* @__PURE__ */ new Set([`__proto__`,`constructor`,`prototype`]);function H(e,t){let n={...e};for(let[e,r]of Object.entries(t)){if(_e.has(e))continue;let t=n[e];n[e]=V(r)&&V(t)?H(t,r):r}return n}function U(e,t){let n=y(e,t),r=e=>U(e.outcome,e.category),i=e=>V(e)?e:void 0,a=((e,...t)=>S(n,n=>{let r=i(n);if(r===void 0)return x(`INVALID_INPUT`,`get expects a plain object`);let a=typeof e==`string`?[e]:e,o=r;for(let e of a){if(!V(o)||!Object.hasOwn(o,e))return t.length===0?x(`OUT_OF_BOUNDS`,`No value at path ${a.join(`.`)}`):b(t[0]);o=o[e]}return b(o)}));return{...n,get:a,pick(...e){return r(S(n,t=>{let n=i(t);return n===void 0?x(`INVALID_INPUT`,`pick expects a plain object`):b(Object.fromEntries(e.filter(e=>Object.hasOwn(n,e)).map(e=>[e,n[e]])))}))},omit(...e){return r(S(n,t=>{let n=i(t);if(n===void 0)return x(`INVALID_INPUT`,`omit expects a plain object`);let r=new Set(e);return b(Object.fromEntries(Object.entries(n).filter(([e])=>!r.has(e))))}))},merge(e){return r(S(n,t=>{let n=i(t);return n===void 0?x(`INVALID_INPUT`,`merge expects a plain object`):V(e)?b(H(n,e)):x(`INVALID_INPUT`,`merge expects a plain object source`)}))},count(){return S(n,e=>{let t=i(e);return t===void 0?x(`INVALID_INPUT`,`count expects a plain object`):b(Object.keys(t).length)})},countBy(e){return S(n,t=>{if(!Array.isArray(t))return x(`INVALID_INPUT`,`countBy expects a collection`);let n=t,r=/* @__PURE__ */ new Map;for(let t of n){let n=String(e(t));r.set(n,(r.get(n)??0)+1)}return b(Object.fromEntries(r))})},keyBy(e){return S(n,t=>{if(!Array.isArray(t))return x(`INVALID_INPUT`,`keyBy expects a collection`);let n=t,r=/* @__PURE__ */ new Map;for(let t of n)r.set(String(e(t)),t);return b(Object.fromEntries(r))})},prune(e){return r(S(n,t=>{let n=i(t);if(n===void 0)return x(`INVALID_INPUT`,`prune expects a plain object`);let r=e??(e=>!k(e));return b(Object.fromEntries(Object.entries(n).filter(([e,t])=>r(t,e))))}))}}}function ve(e){return t(e)?e.isOk===!0?{ok:!0,value:e.value}:{ok:!1,message:`struct expects a raw value or a successful Ok`}:{ok:!0,value:e}}function ye(e){let t=ve(e);return t.ok?U(T(t.value),void 0):U(D(t.message),`INVALID_INPUT`)}function W(e){if(e instanceof Set)return new Set(e);if(e instanceof Map)return new Set(e.keys());if(typeof e==`string`)return new Set(e);if(typeof e==`object`&&e){if(Symbol.iterator in e)return new Set(e);if(Object.prototype.toString.call(e)===`[object Object]`)return new Set(Object.keys(e))}}function G(e){return t(e)?e.isOk===!0?{ok:!0,value:e.value}:{ok:!1,message:`sets expects a raw collection or a successful Ok`}:{ok:!0,value:e}}function K(e,t){let n=y(e,t),r=e=>K(e.outcome,e.category),i=(e,t)=>r(S(n,n=>{let r=G(e),i=r.ok?W(r.value):void 0;return i===void 0?x(`INVALID_INPUT`,`sets expects an iterable, set, map or object`):b(t(n,i))}));return{...n,has(e){return S(n,t=>b(t.has(e)))},unique(){return r(S(n,e=>b(new Set(e))))},union(e){return i(e,(e,t)=>/* @__PURE__ */ new Set([...e,...t]))},intersection(e){return i(e,(e,t)=>new Set([...e].filter(e=>t.has(e))))},difference(e){return i(e,(e,t)=>new Set([...e].filter(e=>!t.has(e))))},count(){return S(n,e=>b(e.size))}}}function be(e){let t=G(e);if(!t.ok)return K(D(t.message),`INVALID_INPUT`);let n=W(t.value);return n===void 0?K(D(`sets expects an iterable, set, map or object`),`INVALID_INPUT`):K(T(n),void 0)}const q=Symbol(`slang.memo.leaf`);function xe(e){let t=/* @__PURE__ */ new Map,n=e=>{let n=t;for(let t of e){let e=n.get(t);e===void 0&&(e=/* @__PURE__ */ new Map,n.set(t,e)),n=e}return n},r=((...t)=>{let r=n(t);if(r.has(q))return r.get(q);let i=e(...t);return r.set(q,i),i instanceof Promise&&i.catch(()=>{r.delete(q)}),i});return r.clear=()=>{t=/* @__PURE__ */ new Map},r}function Se(e,t={}){let n=t.concurrency??1/0,r=t.throttle??0;if(n!==1/0&&(!Number.isSafeInteger(n)||n<=0))throw Error(`concurrency must be a positive integer`);if(!Number.isSafeInteger(r)||r<0)throw Error(`throttle must be a nonnegative integer`);let i=0,a=0,o,s=[],c=e=>{o===void 0&&(o=setTimeout(()=>{o=void 0,l()},e))},l=()=>{for(;s.length>0&&i<n;){let e=r>0?Math.max(0,a+r-Date.now()):0;if(e>0){c(e);return}let t=s.shift();if(t===void 0)return;if(i+=1,a=Date.now(),t(),r>0){c(r);return}}},u=()=>{let e=!1;return()=>{e||(e=!0,i>0&&--i,l())}};return{name:e,acquire(){return new Promise(e=>{s.push(()=>e(u())),l()})}}}const J=e=>typeof e==`object`&&!!e&&typeof e.key==`string`&&e.key.length>0&&`value`in e,Y=(e,t)=>{for(let n of e.values())if(n.key===t)return!0;return!1},Ce=e=>e.size===0?1/0:Math.min(...e.keys()),we=e=>e.size===0?-1/0:Math.max(...e.keys()),Te=(e,t)=>{let n;for(let r of e.keys())r<t&&(n===void 0||r>n)&&(n=r);return n===void 0?void 0:e.get(n)},Ee=(e,t)=>{let n;for(let r of e.keys())r>t&&(n===void 0||r<n)&&(n=r);return n===void 0?void 0:e.get(n)};function De(e={}){let t=e.maxHistory??50,n=e.maxSteps??null,r=e.keyEvalFn;if(!Number.isSafeInteger(t)||t<=0)throw Error(`maxHistory must be a positive integer`);if(n!==null&&(!Number.isSafeInteger(n)||n<0))throw Error(`maxSteps must be a nonnegative integer or null`);let i=/* @__PURE__ */ new Map,a=-1,o=0,s=Promise.resolve(),c=e=>{let t=s.then(e,e);return s=t.then(()=>void 0,()=>void 0),t},u=e=>{for(let e of[...i.keys()])e>a&&i.delete(e);for(a+=1,i.set(a,e),o+=1;i.size>t;){let e=Ce(i);if(e===a)break;i.delete(e)}},d=async(e,t)=>{let s=t.fallback??!1,c=i.get(a),d=e=>s&&c!==void 0?T(c):D(e);if(n!==null&&o>=n)return D(`Step limit reached`);let f;try{f=await e(c,e=>e)}catch(e){return d(l(e))}if(!J(f))return d(`A step needs a nonempty string key and a value`);let p=f;if(Y(i,p.key))throw Error(`Duplicate step key: ${p.key}`);if(r!==void 0){let e;try{e=await r(p.key)}catch(e){return d(l(e))}if(!e)throw Error(`Step key rejected: ${p.key}`)}return u(p),T(p)};return{next:(e,t={})=>c(()=>d(e,t)),prev:(e=-1)=>{if(!Number.isSafeInteger(e)||e>=0)throw Error(`prev offset must be a negative integer`);let n=a+e,r=n<0,o=e=>(a=n,e),s=e=>{if(r)throw Error(`Cannot step before the first step`);let a=e(Te(i,n),e=>e,Ee(i,n));if(!J(a))throw Error(`Recovered step is invalid`);let s=a;if(Y(i,s.key))throw Error(`Duplicate step key: ${s.key}`);for(i.set(n,s);i.size>t;){let e=we(i);if(e===n)break;i.delete(e)}return o(s)};return{else(e){let t=i.get(n);return t===void 0?s(e):o(t)},panic(e){let t=i.get(n);if(t!==void 0)return o(t);throw Error(r?e??`Cannot step before the first step`:e??`History unavailable`)}}},get current(){return i.get(a)},get size(){return i.size}}}function X(e){return e.error??`Unknown error`}function Oe(e){let t=a(e);return t.ok?E(t.value):D(t.error)}async function ke(e,n){try{let r=await e(n);return t(r)?(t(r.value)&&d(),r):D(`Pipeline function must return a Result`)}catch(e){if(f(e))throw e;return D(l(e))}}function Ae(e,...t){return{async run(n){let{onEach:r,onSuccess:i,onError:a,allowErrors:o=!1}=n??{},s=Oe(e);for(let e=0;e<t.length;e++){let n=t[e],i=t[e+1];if(s.isErr&&!o)return a?.(Error(X(s))),s;s=await ke(n,s),r?.({prevResult:s,currentFn:n.name||`fn${e+1}`,nextFn:i?i.name||`fn${e+2}`:void 0})}return s.isOk?i?.(s.value):a?.(Error(X(s))),s}}}function Z(){let e=new AbortController;return Object.assign(e.signal,{fire:()=>e.abort()})}const Q=e=>l(e),$=(e,t)=>{if(e.aborted)return t.abort(),()=>{};let n=()=>t.abort();return e.addEventListener(`abort`,n,{once:!0}),()=>e.removeEventListener(`abort`,n)};function je(e,t={}){let r=new AbortController,i=Z(),o=()=>{},s=new Promise(e=>{o=e}),c=!1,l=!1,u=e=>{l||(l=!0,o(e),i.fire())},d=async(e,n,i)=>{let o=t.group===void 0?()=>{}:await t.group.acquire();if(r.signal.aborted)return o(),{kind:`aborted`};let s=!1,c,l=i===void 0?()=>{}:$(i,n),u=$(r.signal,n);t.timeout!==void 0&&(c=setTimeout(()=>{s=!0,n.abort()},t.timeout));let d=e=>(c!==void 0&&clearTimeout(c),l(),u(),o(),e);try{let t=a(await e(n.signal));return n.signal.aborted?r.signal.aborted?d({kind:`aborted`}):i?.aborted?d({kind:`stopped`}):d(s?{kind:`timedOut`}:{kind:`aborted`}):t.ok?d({kind:`value`,value:t.value}):d({kind:`error`,error:t.error})}catch(e){return r.signal.aborted?d({kind:`aborted`}):i?.aborted?d({kind:`stopped`}):n.signal.aborted?d(s?{kind:`timedOut`}:{kind:`aborted`}):d({kind:`error`,error:Q(e)})}},f=e=>new Promise(t=>{if(e.aborted){t();return}e[n]?.();let i=()=>{a(),t()},a=()=>{e.removeEventListener(`abort`,i),r.signal.removeEventListener(`abort`,i)};e.addEventListener(`abort`,i,{once:!0}),r.signal.addEventListener(`abort`,i,{once:!0})}),p=e=>new Promise(t=>{if(r.signal.aborted){t();return}let n=()=>{clearTimeout(a),i(),t()},i=()=>r.signal.removeEventListener(`abort`,n),a=setTimeout(n,e);r.signal.addEventListener(`abort`,n,{once:!0})}),m=async()=>{let{defer:n,delay:i,retry:a,retryUntil:o}=t,s=e;if(s===void 0)return;if(r.signal.aborted||n!==void 0&&(await f(n),r.signal.aborted))return u(D(`Aborted`));if(o!==void 0){let e=o.signal;for(;;){if(r.signal.aborted)return u(D(`Aborted`));if(e.aborted)return u(D(`Stopped`));let t=new AbortController,n=await d(s,t,e);switch(n.kind){case`value`:return u(T(n.value));case`aborted`:return u(D(`Aborted`));case`stopped`:return u(D(`Stopped`));case`timedOut`:case`error`:if(r.signal.aborted)return u(D(`Aborted`));if(e.aborted)return u(D(`Stopped`));o.delay!==void 0&&await p(o.delay)}}}if(a!==void 0&&a>0){let e=a;for(;;){if(r.signal.aborted||(i!==void 0&&await p(i),r.signal.aborted))return u(D(`Aborted`));let t=new AbortController,n=await d(s,t,void 0);switch(n.kind){case`value`:return u(T(n.value));case`aborted`:return u(D(`Aborted`));case`timedOut`:return u(D(`Timed out`));case`stopped`:return u(D(`Stopped`));case`error`:if(e>0){--e;continue}return u(D(n.error))}}}if(i!==void 0&&await p(i),r.signal.aborted)return u(D(`Aborted`));let c=new AbortController,l=await d(s,c,void 0);switch(l.kind){case`value`:return u(T(l.value));case`aborted`:return u(D(`Aborted`));case`timedOut`:return u(D(`Timed out`));case`stopped`:return u(D(`Stopped`));case`error`:return u(D(l.error))}},h=()=>{c||(c=!0,e!==void 0&&m())};i[n]=h;let g={done:i,abort:()=>{r.abort(),u(D(`Aborted`))},resolve:e=>u(T(e)),reject:e=>u(D(Q(e))),tap:e=>je(async()=>{let t=await g;return t.isOk&&await e(t.value),t}),then:(e,t)=>(h(),s.then(e,t)),catch:e=>(h(),s.catch(e)),finally:e=>(h(),s.finally(e))};return g}function Me(e){let{type:t}=e;if(t===`race`&&e.count<1)throw Error(`superRunner race count must be at least 1`);let r=new AbortController,i=Z(),a=()=>{},o=new Promise(e=>{a=e}),s=!1,c=!1,l=e=>{c||(c=!0,a(e),i.fire())},u=t===`sequence`?e.runners:Object.values(e.runners),d=()=>{for(let e of u)e.abort()},f=async e=>{let t=[];for(let n of e){if(r.signal.aborted)return l(D(`Aborted`));let e=await n;if(r.signal.aborted)return l(D(`Aborted`));if(e.isErr)return l(D(e.error));t.push(e.value)}l(E(t))},p=async e=>{let t=Object.entries(e),n={},i=0;for(let[e,a]of t)a.then(a=>{if(i+=1,a.isOk)n[e]=a.value;else if(!r.signal.aborted&&!c){d(),l(D(a.error));return}i===t.length&&l(E(n))});t.length===0&&l(E(n))},m=async(e,t)=>{let n=Object.entries(e),r={},i=0,a=0;for(let[e,o]of n)o.then(o=>{a+=1,o.isOk&&(r[e]=o.value,i+=1,i>=t)?(d(),l(E(r))):a===n.length&&l(D(i===0?`All runners failed`:`Not enough runners succeeded`))});n.length===0&&l(D(`All runners failed`))},h=()=>(s||(s=!0,t===`sequence`?f(e.runners):t===`all`?p(e.runners):m(e.runners,e.count)),o);return i[n]=h,{done:i,start:h,abort:()=>{r.abort(),d(),l(D(`Aborted`))}}}function Ne(){let e=/* @__PURE__ */ new Map,t=t=>{let n=e.get(t.topic);if(n!==void 0)for(let e of n)try{e(t)}catch(e){_(`channel subscriber threw:`,e)}};return{send:t,subscribe:(t,n)=>{let r=e.get(t.topic);return r===void 0&&(r=/* @__PURE__ */ new Set,e.set(t.topic,r)),r.add(n),()=>{let r=e.get(t.topic);r!==void 0&&r.delete(n)}},when:e=>{e.signal.aborted?t({topic:e.topic,data:e.data}):e.signal.addEventListener(`abort`,()=>t({topic:e.topic,data:e.data}),{once:!0})}}}export{D as Err,E as Ok,oe as Options,I as _to,P as atom,Ne as createChannel,Z as createSignal,De as createStepper,k as isFalsy,ge as list,ce as match,ue as matchAll,xe as memoized,j as option,v as panic,Ae as pipe,_ as println,me as safeTry,e as scheduleMicrotask,h as setEnvironment,be as sets,ye as struct,je as superPromise,Me as superRunner,Se as taskGroup,pe as unzip,L as zip,fe as zipWith};
1
+ const e=e=>{let t=globalThis?.queueMicrotask;typeof t==`function`?t(e):Promise.resolve().then(e)},t=e=>typeof e==`object`&&!!e&&`type`in e&&(e.type===`Ok`||e.type===`Err`),n=Symbol(`slang.activate`),r=e=>typeof e==`object`&&!!e&&`isSome`in e&&`isNone`in e,i=e=>typeof e==`object`&&!!e&&typeof e.valueOf?.()==`symbol`;function a(e){return i(e)?{ok:!0,value:e.valueOf().description}:t(e)?e.isOk?{ok:!0,value:e.value}:{ok:!1,error:u(e.error)}:r(e)?e.isSome?{ok:!0,value:e.value}:{ok:!1,error:`Option was None`}:{ok:!0,value:e}}function o(e){let t=e;for(let e of[`message`,`error`,`reason`]){let n=t[e];if(typeof n==`string`&&n.length>0)return n}}function s(e,t){return e.length>t?`${e.slice(0,t)}...`:e}function c(e){let t=/* @__PURE__ */ new WeakSet;try{return JSON.stringify(e,(e,n)=>{if(typeof n==`bigint`)return n.toString();if(typeof n!=`function`&&typeof n!=`symbol`){if(n instanceof Set)return Array.from(n);if(n instanceof Map)return Object.fromEntries(n);if(typeof n==`object`&&n){if(t.has(n))return`[Circular]`;t.add(n)}return n}})}catch{return}}function l(e){let t=c(e);return typeof t==`string`&&t.length>0&&t!==`{}`?t:Object.prototype.toString.call(e)}function u(e,t=512){if(e instanceof Error)return e.message;if(typeof e==`string`)return e;if(typeof e==`bigint`)return e.toString();if(e==null)return String(e);if(typeof e==`object`){let n=o(e);return s(n===void 0?l(e):n,t)}return String(e)}const d=`slang.nestedResultPanic`;function f(){let e=/* @__PURE__ */ Error(`A Result cannot be nested inside another Result`);throw Object.defineProperty(e,d,{value:!0}),e}function p(e){return e instanceof Error&&e[d]===!0}let m=`development`,h=null;const g=e=>{typeof e==`object`&&e?h=e.printFn??null:m=e===`production`||e===`prod`?`production`:`development`},ee=e=>{if(Array.isArray(e))return!0;let t=e.toString;return typeof t!=`function`||t===Object.prototype.toString},te=e=>{if(typeof e==`string`)return e;if(typeof e==`symbol`)return String(e);if(typeof e==`function`)return`[Function ${e.name}]`;if(typeof e==`object`&&e&&ee(e))return c(e)??Object.prototype.toString.call(e);try{return String(e)}catch{try{return JSON.stringify(e)??`null`}catch{return Object.prototype.toString.call(e)}}},_=(...e)=>{let t=e.map(te).join(` `).concat(`
2
+ `);h?h(t):m!==`production`&&globalThis.console?.log?.(t)};function v(e){throw Error(e)}function y(e,t){return{outcome:e,category:t,else(t){return e.isOk?e.value:typeof t==`function`?t(e.error):t},panic(t){if(e.isOk)return e.value;throw Error(t??e.error)}}}function b(e){return y(E(e),void 0)}function x(e,t){return y(O(t),e)}function S(e,t){return e.outcome.isErr?y(O(e.outcome.error),e.category):t(e.outcome.value)}const C=e=>({[Symbol.iterator]:e}),ne=e=>y(O(e.message),e.category);function w(e,t=void 0,n=!1,r={consumed:!1}){let i=(e,i=t)=>w(e,i,n,r),a=i=>{if(t!==void 0)return ne(t);if(n&&r.consumed)return x(`INVALID_INPUT`,`This iterator has already been consumed`);r.consumed=!0;let a;try{return a=e(),b(i(a))}catch(e){return x(`INVALID_INPUT`,u(e))}finally{a?.return?.()}};return{map(t){return i(function*(){let n=0;for(let r of C(e))yield t(r,n++)})},filter(t){return i(function*(){let n=0;for(let r of C(e))t(r,n++)&&(yield r)})},flatMap(t){return i(function*(){let n=0;for(let r of C(e))yield*t(r,n++)})},take(t){return!Number.isSafeInteger(t)||t<0?i(function*(){},{category:`INVALID_INDEX`,message:`take needs a nonnegative integer`}):i(function*(){if(t===0)return;let n=C(e)[Symbol.iterator](),r=0;try{for(;r<t;){let e=n.next();if(e.done===!0)return;yield e.value,r+=1}}finally{n.return?.()}})},drop(t){return!Number.isSafeInteger(t)||t<0?i(function*(){},{category:`INVALID_INDEX`,message:`drop needs a nonnegative integer`}):i(function*(){let n=0;for(let r of C(e))n<t?n+=1:yield r})},chunk(t){return!Number.isSafeInteger(t)||t<=0?i(function*(){},{category:`INVALID_CHUNK_SIZE`,message:`chunk size must be a positive integer`}):i(function*(){let n=[];for(let r of C(e))n.push(r),n.length===t&&(yield n,n=[]);n.length>0&&(yield n)})},reduce(e,t){return a(n=>{let r=t,i=0;for(;;){let t=n.next();if(t.done===!0)return r;r=e(r,t.value,i++)}})},count(){return a(e=>{let t=0;for(;;){if(e.next().done===!0)return t;t+=1}})},toArray(){return a(e=>{let t=[];for(;;){let n=e.next();if(n.done===!0)return t;t.push(n.value)}})}}}function re(e){let t=typeof e==`string`||typeof e==`object`&&e&&Symbol.iterator in e?e:void 0;if(t!==void 0){let e=!1;try{e=t[Symbol.iterator]()===t}catch{}return w(()=>t[Symbol.iterator](),void 0,e)}return w(()=>{throw Error(`Cannot iterate a non-iterable value`)},{category:`INVALID_INPUT`,message:`Cannot iterate a non-iterable value`})}function T({call:e,original:n}){let r=e=>e===void 0?n:t(e)?(t(e.value)&&f(),e):E(e);try{let t=e();return t instanceof Promise?t.then(e=>r(e)).catch(e=>O(u(e))):r(t)}catch(e){return O(u(e))}}function E(n,r){t(n)&&f();let i=Object.freeze({type:`Ok`,value:n,...r===void 0?{}:{message:r},isOk:!0,isErr:!1}),a=e=>T({call:()=>e(i.value),original:c}),o=e=>c,s=e=>c,c={...i,expect:(e=>i.value),unwrap:(()=>(e(()=>{}),{else(e){return i.value}})),andThen:a,mapErr:o,orFn:s,iterate:()=>re(i.value)};return c}function D(e,t,...n){return E(e,t)}function O(t,n){let r=Object.freeze({type:`Err`,error:t,isOk:!1,isErr:!0}),i=e=>s,a=e=>{try{return O(e(t),n)}catch(e){return O(u(e),n)}},o=e=>T({call:()=>e(t,n),original:s}),s={...r,expect:(e=>{throw Error(e??t)}),unwrap:(()=>{let n=!1;return e(()=>{if(!n)throw Error(t)}),{else(e){return n=!0,typeof e==`function`?e(t):e}}}),andThen:i,mapErr:a,orFn:o};return k(s,n)}function k(e,t){return t===void 0||Object.defineProperty(e,"raw",{value:t,enumerable:!1,writable:!1,configurable:!1}),e}function ie(e){let t=e.find(e=>e.isErr);return t===void 0?E(e.map(e=>e.value)):t}function ae(e){return e.filter(e=>e.isErr).map(e=>e.error)}const A=e=>e==null||e===``||Number.isNaN(e)||e===1/0||e===-1/0;function oe(e){if(A(e))throw Error(`Cannot wrap null, undefined, NaN, or empty string in Some`);return Object.freeze({type:`Some`,value:e,isSome:!0,isNone:!1})}const se=Object.freeze({type:`None`,isSome:!1,isNone:!0});let j=null;function ce(e){j=e}function M(t){let n=A(t)?se:oe(t),r=(e=>{if(!j)throw Error(`Converter not initialized`);return j(n,e)}),i=(e=>{if(n.isSome)return n.value;throw Error(e??`Expected Some, got None`)}),a=(()=>{let t=!1,r=n;return e(()=>{if(!t)throw Error(`Expected else`)}),{else(e){if(t=!0,r.isSome)return r.value;let n=typeof e==`function`?e(void 0):e;if(A(n))throw Error(`Fallback must be truthy`);return n}}}),o=(e=>{let t=n;if(t.isNone)return s;let r=t.value;try{let t=e(r);return t instanceof Promise?t.then(e=>e===void 0?s:M(e)).catch(()=>M(null)):t===void 0?s:M(t)}catch{return M(null)}}),s={...n,to:r,expect:i,unwrap:a,andThen:o};return s}const N=e=>{if(typeof e!=`object`||!e)return e;let t=e;return t.isSome===!0||t.isOk===!0?t.value:e},le=e=>{if(typeof e==`object`&&e){let t=e;if(t.isNone===!0||t.isErr===!0)return!0}return A(N(e))};function ue(e,t=O(`No value!`)){for(let t of e)if(!le(t))return E(N(t));return t}let P=null;function de(e){P=e}function F(e){let t=Symbol(e),n=Object(t);return n.to=(e=>{if(!P)throw Error(`Converter not initialized`);return P(t,e)}),n.andThen=t=>{let r;try{r=t(e)}catch(e){v(`Atom.andThen: fn threw an error: ${u(e)}`)}return r===void 0?n:(typeof r!=`string`&&v(`Atom.andThen: fn must return a string, got ${typeof r}`),F(r))},n}const I=e=>typeof e==`object`&&!!e&&`isSome`in e&&`isNone`in e;function L(e,t){if(e&&(e.type===`Ok`||e.type===`Err`))throw Error(`Cannot convert a Result to any other type`);switch(t){case`option`:return I(e)?e:M(typeof e==`symbol`?e.description:e);case`atom`:if(I(e)){if(e.isNone)throw Error(`Cannot convert None to Atom`);if(typeof e.value!=`string`)throw Error(`Only string values can be converted to Atom`);return F(e.value)}if(typeof e==`symbol`)return e;throw Error(`Cannot convert type ${typeof e} to Atom`);case`result`:return I(e)?e.isSome?D(e.value):O(`Value is None`):D(typeof e==`symbol`?e.description:e);default:throw Error(`Invalid target: ${t}`)}}ce(L),de(L);function fe(e,t){let n=t[e.type];if(!n)throw Error(`Non-exhaustive match: missing handler for '${e.type}'`);return n(e)}const pe=e=>typeof e==`string`||typeof e==`number`||typeof e==`boolean`||typeof e==`symbol`;function me(e,t){let n=e=>typeof e?.valueOf==`function`?e.valueOf():e,r=e=>typeof e==`symbol`?e.description:void 0,i=n(e);if(!pe(i))throw Error(`Unsupported match all value type: ${typeof i}`);let a=r(i)??i,o=typeof a==`boolean`||typeof a==`number`?String(a):a;return o!=null&&o in t?t[o](e):t._()}function he(e,t=!1){if(!t&&!Array.isArray(e))throw Error(`Only arrays allowed when includeValues=false`);return Array.isArray(e)?e:e instanceof Set?Array.from(e):Object.values(e)}function R(e,t){let{fillValue:n,includeValues:r=!1}=t||{};if(e.length===0)return[];let i=e.map(e=>he(e,r)),a=Math.max(...i.map(e=>e.length)),o=Math.min(...i.map(e=>e.length)),s=n===void 0?o:a,c=[];for(let e=0;e<s;e++)c.push(i.map(t=>e<t.length?t[e]:n));return c}function ge(e,t,n){return R(e,n).map(t)}function _e(e){if(e.length===0)return[];let t=e[0]?.length??0,n=Array.from({length:t},()=>[]);for(let t of e)t.forEach((e,t)=>n[t]?.push(e));return n}const ve=e=>e!==null&&(typeof e==`object`||typeof e==`function`)&&typeof e.then==`function`,z=(e,t)=>e.collectValues?k(t,{errors:e.errors,values:e.values}):t,ye=(e,n)=>{let o=a(e),s=/* @__PURE__ */ new Set,c=+!!t(e),l=t(e)?e.raw:void 0,u=o.ok?void 0:e;for(;o.ok;){let e=o.value;if(t(e)&&(c+=1,c>1&&f()),n.collectValues&&n.values.push(e),!i(e)&&!t(e)&&!r(e))return z(n,E(e));if(typeof e==`object`&&e){if(s.has(e))return z(n,O(`Cannot resolve a circular value`));s.add(e)}o=a(e),o.ok||(u=e)}return n.collectValues?(n.errors.push(t(u)?u.error:o.error),z(n,O(o.error))):O(o.error,l)},B=(e,t)=>{if(p(e))throw e;let n=u(e);if(t.shouldThrow)throw e instanceof Error?e:Error(n);return t.collectValues?(t.errors.push(e),z(t,O(n))):O(n,e)},V=(e,t)=>{try{return ye(e,t)}catch(e){return B(e,t)}};function be(e,t){let n={shouldThrow:t?.throw??!1,collectValues:t?.collectValues??!1,values:[],errors:[]},r;try{r=e()}catch(e){return B(e,n)}return ve(r)?Promise.resolve(r).then(e=>V(e,n),e=>B(e,n)):V(r,n)}const H=e=>Number.isSafeInteger(e),U=(e,t)=>e<0?t+e:e;function xe(e){return Array.isArray(e)?{ok:!0,value:e}:t(e)?e.isOk===!0&&Array.isArray(e.value)?{ok:!0,value:e.value}:{ok:!1,message:`list expects a raw array or a successful Ok holding one`}:{ok:!1,message:`list expects an array or a successful Ok`}}function W(e,t){let n=y(e,t),r=e=>W(e.outcome,e.category),i=((e,...t)=>S(n,n=>{if(!H(e))return x(`INVALID_INDEX`,`Index must be an integer`);let r=U(e,n.length);return r<0||r>=n.length?t.length===0?x(`OUT_OF_BOUNDS`,`No item at index ${e}`):b(t[0]):b(n[r])}));return{...n,get:i,take(e){return r(S(n,t=>H(e)?e<0||e>t.length?x(`OUT_OF_BOUNDS`,`take(${e}) is outside 0..${t.length}`):b(t.slice(0,e)):x(`INVALID_INDEX`,`take needs an integer count`)))},skip(e){return r(S(n,t=>H(e)?Math.abs(e)>t.length?x(`OUT_OF_BOUNDS`,`skip(${e}) is outside -${t.length}..${t.length}`):b(e>=0?t.slice(e):t.slice(0,t.length+e)):x(`INVALID_INDEX`,`skip needs an integer count`)))},range(e,t){return r(S(n,n=>{if(!H(e)||!H(t))return x(`INVALID_INDEX`,`range needs integer bounds`);let r=U(e,n.length),i=U(t,n.length);return r<0||r>n.length||i<0||i>n.length?x(`OUT_OF_BOUNDS`,`range(${e}, ${t}) is outside 0..${n.length}`):r>i?x(`INVALID_RANGE`,`range start must not exceed end`):b(n.slice(r,i))}))},chunk(e){let t=S(n,t=>{if(!H(e)||e<=0)return x(`INVALID_CHUNK_SIZE`,`chunk size must be a positive integer`);let n=[];for(let r=0;r<t.length;r+=e)n.push(t.slice(r,r+e));return b(n)});return W(t.outcome,t.category)},count(){return S(n,e=>b(e.length))},prune(e){return r(S(n,t=>{let n=e??(e=>!A(e));return b(t.filter((e,t)=>n(e,t)))}))}}}function Se(e){let t=xe(e);return t.ok?W(D(t.value),void 0):W(O(t.message),`INVALID_INPUT`)}const G=e=>Object.prototype.toString.call(e)===`[object Object]`,Ce=/* @__PURE__ */ new Set([`__proto__`,`constructor`,`prototype`]);function K(e,t){let n={...e};for(let[e,r]of Object.entries(t)){if(Ce.has(e))continue;let t=n[e];n[e]=G(r)&&G(t)?K(t,r):r}return n}function q(e,t){let n=y(e,t),r=e=>q(e.outcome,e.category),i=e=>G(e)?e:void 0,a=((e,...t)=>S(n,n=>{let r=i(n);if(r===void 0)return x(`INVALID_INPUT`,`get expects a plain object`);let a=typeof e==`string`?[e]:e,o=r;for(let e of a){if(!G(o)||!Object.hasOwn(o,e))return t.length===0?x(`OUT_OF_BOUNDS`,`No value at path ${a.join(`.`)}`):b(t[0]);o=o[e]}return b(o)}));return{...n,get:a,pick(...e){return r(S(n,t=>{let n=i(t);return n===void 0?x(`INVALID_INPUT`,`pick expects a plain object`):b(Object.fromEntries(e.filter(e=>Object.hasOwn(n,e)).map(e=>[e,n[e]])))}))},omit(...e){return r(S(n,t=>{let n=i(t);if(n===void 0)return x(`INVALID_INPUT`,`omit expects a plain object`);let r=new Set(e);return b(Object.fromEntries(Object.entries(n).filter(([e])=>!r.has(e))))}))},merge(e){return r(S(n,t=>{let n=i(t);return n===void 0?x(`INVALID_INPUT`,`merge expects a plain object`):G(e)?b(K(n,e)):x(`INVALID_INPUT`,`merge expects a plain object source`)}))},count(){return S(n,e=>{let t=i(e);return t===void 0?x(`INVALID_INPUT`,`count expects a plain object`):b(Object.keys(t).length)})},countBy(e){return S(n,t=>{if(!Array.isArray(t))return x(`INVALID_INPUT`,`countBy expects a collection`);let n=t,r=/* @__PURE__ */ new Map;for(let t of n){let n=String(e(t));r.set(n,(r.get(n)??0)+1)}return b(Object.fromEntries(r))})},keyBy(e){return S(n,t=>{if(!Array.isArray(t))return x(`INVALID_INPUT`,`keyBy expects a collection`);let n=t,r=/* @__PURE__ */ new Map;for(let t of n)r.set(String(e(t)),t);return b(Object.fromEntries(r))})},prune(e){return r(S(n,t=>{let n=i(t);if(n===void 0)return x(`INVALID_INPUT`,`prune expects a plain object`);let r=e??(e=>!A(e));return b(Object.fromEntries(Object.entries(n).filter(([e,t])=>r(t,e))))}))}}}function we(e){return t(e)?e.isOk===!0?{ok:!0,value:e.value}:{ok:!1,message:`struct expects a raw value or a successful Ok`}:{ok:!0,value:e}}function Te(e){let t=we(e);return t.ok?q(E(t.value),void 0):q(O(t.message),`INVALID_INPUT`)}function J(e){if(e instanceof Set)return new Set(e);if(e instanceof Map)return new Set(e.keys());if(typeof e==`string`)return new Set(e);if(typeof e==`object`&&e){if(Symbol.iterator in e)return new Set(e);if(Object.prototype.toString.call(e)===`[object Object]`)return new Set(Object.keys(e))}}function Y(e){return t(e)?e.isOk===!0?{ok:!0,value:e.value}:{ok:!1,message:`sets expects a raw collection or a successful Ok`}:{ok:!0,value:e}}function X(e,t){let n=y(e,t),r=e=>X(e.outcome,e.category),i=(e,t)=>r(S(n,n=>{let r=Y(e),i=r.ok?J(r.value):void 0;return i===void 0?x(`INVALID_INPUT`,`sets expects an iterable, set, map or object`):b(t(n,i))}));return{...n,has(e){return S(n,t=>b(t.has(e)))},unique(){return r(S(n,e=>b(new Set(e))))},union(e){return i(e,(e,t)=>/* @__PURE__ */ new Set([...e,...t]))},intersection(e){return i(e,(e,t)=>new Set([...e].filter(e=>t.has(e))))},difference(e){return i(e,(e,t)=>new Set([...e].filter(e=>!t.has(e))))},count(){return S(n,e=>b(e.size))}}}function Ee(e){let t=Y(e);if(!t.ok)return X(O(t.message),`INVALID_INPUT`);let n=J(t.value);return n===void 0?X(O(`sets expects an iterable, set, map or object`),`INVALID_INPUT`):X(E(n),void 0)}const Z=Symbol(`slang.memo.leaf`);function De(e){let t=/* @__PURE__ */ new Map,n=e=>{let n=t;for(let t of e){let e=n.get(t);e===void 0&&(e=/* @__PURE__ */ new Map,n.set(t,e)),n=e}return n},r=((...t)=>{let r=n(t);if(r.has(Z))return r.get(Z);let i=e(...t);return r.set(Z,i),i instanceof Promise&&i.catch(()=>{r.delete(Z)}),i});return r.clear=()=>{t=/* @__PURE__ */ new Map},r}function Oe(e,t={}){let n=t.concurrency??1/0,r=t.throttle??0;if(n!==1/0&&(!Number.isSafeInteger(n)||n<=0))throw Error(`concurrency must be a positive integer`);if(!Number.isSafeInteger(r)||r<0)throw Error(`throttle must be a nonnegative integer`);let i=0,a=0,o,s=[],c=e=>{o===void 0&&(o=setTimeout(()=>{o=void 0,l()},e))},l=()=>{for(;s.length>0&&i<n;){let e=r>0?Math.max(0,a+r-Date.now()):0;if(e>0){c(e);return}let t=s.shift();if(t===void 0)return;if(i+=1,a=Date.now(),t(),r>0){c(r);return}}},u=()=>{let e=!1;return()=>{e||(e=!0,i>0&&--i,l())}};return{name:e,acquire(){return new Promise(e=>{s.push(()=>e(u())),l()})}}}const Q=e=>typeof e==`object`&&!!e&&typeof e.key==`string`&&e.key.length>0&&`value`in e,ke=(e,t)=>{for(let n of e.values())if(n.key===t)return!0;return!1},Ae=e=>e.size===0?1/0:Math.min(...e.keys()),je=e=>e.size===0?-1/0:Math.max(...e.keys()),Me=(e,t)=>{let n;for(let r of e.keys())r<t&&(n===void 0||r>n)&&(n=r);return n===void 0?void 0:e.get(n)},Ne=(e,t)=>{let n;for(let r of e.keys())r>t&&(n===void 0||r<n)&&(n=r);return n===void 0?void 0:e.get(n)};function Pe(e={}){let t=e.maxHistory??50,n=e.maxSteps??null,r=e.keyEvalFn;if(!Number.isSafeInteger(t)||t<=0)throw Error(`maxHistory must be a positive integer`);if(n!==null&&(!Number.isSafeInteger(n)||n<0))throw Error(`maxSteps must be a nonnegative integer or null`);let i=/* @__PURE__ */ new Map,a=-1,o=0,s=Promise.resolve(),c=e=>{let t=s.then(e,e);return s=t.then(()=>void 0,()=>void 0),t},l=e=>{for(let e of[...i.keys()])e>a&&i.delete(e);for(a+=1,i.set(a,e),o+=1;i.size>t;){let e=Ae(i);if(e===a)break;i.delete(e)}},d=async(e,t)=>{let s=t.fallback??!1,c=i.get(a),d=e=>s&&c!==void 0?E(c):O(e);if(n!==null&&o>=n)return O(`Step limit reached`);let f;try{f=await e(c,e=>e)}catch(e){return d(u(e))}if(!Q(f))return d(`A step needs a nonempty string key and a value`);let p=f;if(ke(i,p.key))throw Error(`Duplicate step key: ${p.key}`);if(r!==void 0){let e;try{e=await r(p.key)}catch(e){return d(u(e))}if(!e)throw Error(`Step key rejected: ${p.key}`)}return l(p),E(p)};return{next:(e,t={})=>c(()=>d(e,t)),prev:(e=-1)=>{if(!Number.isSafeInteger(e)||e>=0)throw Error(`prev offset must be a negative integer`);let n=a+e,r=n<0,o=e=>(a=n,e),s=e=>{if(r)throw Error(`Cannot step before the first step`);let a=e(Me(i,n),e=>e,Ne(i,n));if(!Q(a))throw Error(`Recovered step is invalid`);let s=a;if(ke(i,s.key))throw Error(`Duplicate step key: ${s.key}`);for(i.set(n,s);i.size>t;){let e=je(i);if(e===n)break;i.delete(e)}return o(s)};return{else(e){let t=i.get(n);return t===void 0?s(e):o(t)},panic(e){let t=i.get(n);if(t!==void 0)return o(t);throw Error(r?e??`Cannot step before the first step`:e??`History unavailable`)}}},get current(){return i.get(a)},get size(){return i.size}}}function Fe(e){return e.error??`Unknown error`}function Ie(e){let t=a(e);return t.ok?D(t.value):O(t.error)}async function Le(e,n){try{let r=await e(n);return t(r)?(t(r.value)&&f(),r):O(`Pipeline function must return a Result`)}catch(e){if(p(e))throw e;return O(u(e))}}function Re(e,...t){return{async run(n){let{onEach:r,onSuccess:i,onError:a,allowErrors:o=!1}=n??{},s=Ie(e);for(let e=0;e<t.length;e++){let n=t[e],i=t[e+1];if(s.isErr&&!o)return a?.(Error(Fe(s))),s;s=await Le(n,s),r?.({prevResult:s,currentFn:n.name||`fn${e+1}`,nextFn:i?i.name||`fn${e+2}`:void 0})}return s.isOk?i?.(s.value):a?.(Error(Fe(s))),s}}}function $(){let e=new AbortController;return Object.assign(e.signal,{fire:()=>e.abort()})}const ze=e=>u(e),Be=(e,t)=>{if(e.aborted)return t.abort(),()=>{};let n=()=>t.abort();return e.addEventListener(`abort`,n,{once:!0}),()=>e.removeEventListener(`abort`,n)};function Ve(e,t={}){let r=new AbortController,i=$(),o=()=>{},s=new Promise(e=>{o=e}),c=!1,l=!1,u=e=>{l||(l=!0,o(e),i.fire())},d=async(e,n,i)=>{let o=t.group===void 0?()=>{}:await t.group.acquire();if(r.signal.aborted)return o(),{kind:`aborted`};let s=!1,c,l=i===void 0?()=>{}:Be(i,n),u=Be(r.signal,n);t.timeout!==void 0&&(c=setTimeout(()=>{s=!0,n.abort()},t.timeout));let d=e=>(c!==void 0&&clearTimeout(c),l(),u(),o(),e);try{let t=a(await e(n.signal));return n.signal.aborted?r.signal.aborted?d({kind:`aborted`}):i?.aborted?d({kind:`stopped`}):d(s?{kind:`timedOut`}:{kind:`aborted`}):t.ok?d({kind:`value`,value:t.value}):d({kind:`error`,error:t.error})}catch(e){return r.signal.aborted?d({kind:`aborted`}):i?.aborted?d({kind:`stopped`}):n.signal.aborted?d(s?{kind:`timedOut`}:{kind:`aborted`}):d({kind:`error`,error:ze(e)})}},f=e=>new Promise(t=>{if(e.aborted){t();return}e[n]?.();let i=()=>{a(),t()},a=()=>{e.removeEventListener(`abort`,i),r.signal.removeEventListener(`abort`,i)};e.addEventListener(`abort`,i,{once:!0}),r.signal.addEventListener(`abort`,i,{once:!0})}),p=e=>new Promise(t=>{if(r.signal.aborted){t();return}let n=()=>{clearTimeout(a),i(),t()},i=()=>r.signal.removeEventListener(`abort`,n),a=setTimeout(n,e);r.signal.addEventListener(`abort`,n,{once:!0})}),m=async()=>{let{defer:n,delay:i,retry:a,retryUntil:o}=t,s=e;if(s===void 0)return;if(r.signal.aborted||n!==void 0&&(await f(n),r.signal.aborted))return u(O(`Aborted`));if(o!==void 0){let e=o.signal;for(;;){if(r.signal.aborted)return u(O(`Aborted`));if(e.aborted)return u(O(`Stopped`));let t=new AbortController,n=await d(s,t,e);switch(n.kind){case`value`:return u(E(n.value));case`aborted`:return u(O(`Aborted`));case`stopped`:return u(O(`Stopped`));case`timedOut`:case`error`:if(r.signal.aborted)return u(O(`Aborted`));if(e.aborted)return u(O(`Stopped`));o.delay!==void 0&&await p(o.delay)}}}if(a!==void 0&&a>0){let e=a;for(;;){if(r.signal.aborted||(i!==void 0&&await p(i),r.signal.aborted))return u(O(`Aborted`));let t=new AbortController,n=await d(s,t,void 0);switch(n.kind){case`value`:return u(E(n.value));case`aborted`:return u(O(`Aborted`));case`timedOut`:return u(O(`Timed out`));case`stopped`:return u(O(`Stopped`));case`error`:if(e>0){--e;continue}return u(O(n.error))}}}if(i!==void 0&&await p(i),r.signal.aborted)return u(O(`Aborted`));let c=new AbortController,l=await d(s,c,void 0);switch(l.kind){case`value`:return u(E(l.value));case`aborted`:return u(O(`Aborted`));case`timedOut`:return u(O(`Timed out`));case`stopped`:return u(O(`Stopped`));case`error`:return u(O(l.error))}},h=()=>{c||(c=!0,e!==void 0&&m())};i[n]=h;let g={done:i,abort:()=>{r.abort(),u(O(`Aborted`))},resolve:e=>u(E(e)),reject:e=>u(O(ze(e))),tap:e=>Ve(async()=>{let t=await g;return t.isOk&&await e(t.value),t}),then:(e,t)=>(h(),s.then(e,t)),catch:e=>(h(),s.catch(e)),finally:e=>(h(),s.finally(e))};return g}function He(e){let{type:t}=e;if(t===`race`&&e.count<1)throw Error(`superRunner race count must be at least 1`);let r=new AbortController,i=$(),a=()=>{},o=new Promise(e=>{a=e}),s=!1,c=!1,l=e=>{c||(c=!0,a(e),i.fire())},u=t===`sequence`?e.runners:Object.values(e.runners),d=()=>{for(let e of u)e.abort()},f=async e=>{let t=[];for(let n of e){if(r.signal.aborted)return l(O(`Aborted`));let e=await n;if(r.signal.aborted)return l(O(`Aborted`));if(e.isErr)return l(O(e.error));t.push(e.value)}l(D(t))},p=async e=>{let t=Object.entries(e),n={},i=0;for(let[e,a]of t)a.then(a=>{if(i+=1,a.isOk)n[e]=a.value;else if(!r.signal.aborted&&!c){d(),l(O(a.error));return}i===t.length&&l(D(n))});t.length===0&&l(D(n))},m=async(e,t)=>{let n=Object.entries(e),r={},i=0,a=0;for(let[e,o]of n)o.then(o=>{a+=1,o.isOk&&(r[e]=o.value,i+=1,i>=t)?(d(),l(D(r))):a===n.length&&l(O(i===0?`All runners failed`:`Not enough runners succeeded`))});n.length===0&&l(O(`All runners failed`))},h=()=>(s||(s=!0,t===`sequence`?f(e.runners):t===`all`?p(e.runners):m(e.runners,e.count)),o);return i[n]=h,{done:i,start:h,abort:()=>{r.abort(),d(),l(O(`Aborted`))}}}function Ue(){let e=/* @__PURE__ */ new Map,t=t=>{let n=e.get(t.topic);if(n!==void 0)for(let e of n)try{e(t)}catch(e){_(`channel subscriber threw:`,e)}};return{send:t,subscribe:(t,n)=>{let r=e.get(t.topic);return r===void 0&&(r=/* @__PURE__ */ new Set,e.set(t.topic,r)),r.add(n),()=>{let r=e.get(t.topic);r!==void 0&&r.delete(n)}},when:e=>{e.signal.aborted?t({topic:e.topic,data:e.data}):e.signal.addEventListener(`abort`,()=>t({topic:e.topic,data:e.data}),{once:!0})}}}export{O as Err,D as Ok,ue as Options,L as _to,F as atom,ae as combineErrors,ie as combineResults,Ue as createChannel,$ as createSignal,Pe as createStepper,A as isFalsy,Se as list,fe as match,me as matchAll,De as memoized,M as option,v as panic,Re as pipe,_ as println,be as safeTry,e as scheduleMicrotask,g as setEnvironment,Ee as sets,Te as struct,Ve as superPromise,He as superRunner,Oe as taskGroup,_e as unzip,R as zip,ge as zipWith};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slang-ts",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Functional programming utilities for TypeScript: Option, Result, SafeTry, pattern matching, async control, and data helpers",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/skill/SKILL.md CHANGED
@@ -1,10 +1,19 @@
1
1
  # slang-ts agent skill
2
2
 
3
- This skill tells AI agents how to work with slang-ts — its APIs, patterns, and conventions — so agents can write correct TypeScript against it.
3
+ Use this skill to write correct TypeScript with slang-ts: its APIs, the patterns it expects, and
4
+ the conventions to follow.
4
5
 
5
6
  ## What slang-ts is
6
7
 
7
- slang-ts is a zero-dependency functional programming library for TypeScript. It brings Rust- and Erlang-style utilities: `Option`, `Result`, `SafeTry`, pattern matching (`match`/`matchAll`), async control (`SuperPromise`, `SuperRunner`, `taskGroup`, `Signal`, `Channel`), and data helpers (`list`, `struct`, `sets`, `Ok.iterate`, `memoized`, `zip`, `pipe`, `atom`, `to`).
8
+ slang-ts is a zero-dependency functional programming library for TypeScript, with utilities
9
+ brought over from Rust and Erlang:
10
+
11
+ - Failures as values: `Result` (`Ok`, `Err`), `Option`, `safeTry`, `combineResults`, `combineErrors`, `match`, `matchAll`, `Options`, `pipe`, `panic`
12
+ - Data helpers: `list`, `struct`, `sets`, `Ok(value).iterate()`, `memoized`, `zip`, `zipWith`, `unzip`
13
+ - Conversion: `atom`, `.to()` on every wrapper
14
+ - Async work: `superPromise`, `superRunner`, `taskGroup`, `createSignal`, `createChannel`
15
+ - Step history: `createStepper`
16
+ - Output: `println`, `setEnvironment`
8
17
 
9
18
  Import only what you use:
10
19
 
@@ -16,47 +25,210 @@ import { option, Ok, Err, match, superPromise, list } from "slang-ts";
16
25
 
17
26
  ### Option
18
27
 
19
- `option(value)` → `Some(value)` or `None`. `0` and `false` count as present; `null`, `undefined`, `""`, `NaN`, and `Infinity` are `None`.
28
+ `option<T>(value): Option<T>` wraps a value which may be missing.
29
+
30
+ `0` and `false` count as present. `null`, `undefined`, `""`, `NaN`, `Infinity` and `-Infinity`
31
+ become `None`.
20
32
 
21
33
  ```ts
22
- const port = option(process.env.PORT).unwrap().else(3000);
34
+ import { option, println } from "slang-ts";
35
+
36
+ const savedPort = new URLSearchParams("port=8080").get("port");
37
+
38
+ const port = option(savedPort).unwrap().else("3000");
39
+
40
+ println("Port:", port); // "8080"
23
41
  ```
24
42
 
25
- Never read `.value` on `None`. Check `.isSome` / `.isNone` first, or use `.unwrap().else(fallback)`.
43
+ - Check `.isSome` / `.isNone` before reading `.value`, or use `.unwrap().else(fallback)`.
44
+ - `.unwrap()` must be finished with `.else(...)`. `.else` throws if the fallback is a value
45
+ `option()` treats as missing; `0` and `false` are valid fallbacks.
46
+ - `.expect(message?)` returns the value or throws on `None`.
26
47
 
27
48
  ### Result
28
49
 
29
- `Ok(value, message?)` / `Err(error)`. Failures travel as values, not throws.
50
+ `Result<T, E>` is `Ok<T>` or `Err<E>`.
51
+
52
+ ```ts
53
+ // Signature
54
+ Ok<T>(value, message?); // success, with an optional message for the user
55
+ Err(error, raw?); // failure: a human-readable error, plus an optional cause for logs
56
+ ```
57
+
58
+ `Err(error, raw?)` keeps the original cause on the non-enumerable `.raw` for logs; `.error`
59
+ stays human-readable.
60
+
61
+ ```ts
62
+ import { Ok, Err, type Result, println } from "slang-ts";
63
+
64
+ function splitBill(total: number, people: number): Result<number, string> {
65
+ if (people === 0) {
66
+ return Err("Add at least one person to split the bill");
67
+ }
68
+
69
+ return Ok(total / people);
70
+ }
71
+
72
+ const share = splitBill(120, 4);
73
+
74
+ if (share.isOk) {
75
+ println("Each person pays:", share.value); // 30
76
+ } else {
77
+ println("Could not split the bill:", share.error);
78
+ }
79
+ ```
80
+
81
+ - Branch with `if (result.isOk) { ... } else { ... }`.
82
+ - Get the value with `.unwrap().else(fallback)`, or `.expect(message?)` when a failure should
83
+ throw.
84
+ - `.andThen(fn)` transforms an `Ok` and skips an `Err`. A plain return becomes `Ok`, a
85
+ returned `Result` passes through, `undefined` keeps the original, and a throw or rejection
86
+ becomes `Err(message)`.
87
+ - `.mapErr(fn)` rewrites an `Err`'s message (`fn` receives the message, returns a string) and
88
+ keeps the original `.raw`. Use it at a route or page edge to turn a technical message into
89
+ a human one. Sync only. On `Ok` it returns the same `Ok`.
90
+ - `.orFn(fn)` recovers from an `Err`: `fn(error, raw)` follows the same rules as `andThen`
91
+ (plain value becomes `Ok`, a `Result` passes through, `undefined` keeps the original `Err`,
92
+ a throw or rejection becomes `Err(message)`). On `Ok` it returns the same `Ok`. It is not
93
+ `unwrap().else()`, which leaves the `Result` and returns a plain value.
94
+ - With a sync callback, `andThen` and `orFn` return a `Result`; read it without `await`. With
95
+ an async callback, or one typed as either a value or a promise, or `unknown`, they return
96
+ `Result | Promise<Result>`: `await` it. The skipped side never calls the callback and
97
+ returns the same instance synchronously, so the async case stays a union.
98
+ - A `Result` never nests inside another `Result`: `Ok(Ok(x))` and `Ok(Err(x))` do not compile.
99
+
100
+ ### safeTry
101
+
102
+ `safeTry(fn, options?)` runs a sync or async function and turns every failure (a throw, a
103
+ returned `Err`, a returned `None`) into one `Err`. Sync in, sync out:
104
+
105
+ - A function returning a plain value gets its `Result` directly; read it without `await`.
106
+ - A function returning a promise (or any thenable) gets `Promise<Result>`. `await` it.
107
+ - A function typed as either a value or a promise, or `unknown`, gets the union. `await` it.
108
+ - A sync result is a plain `Result`: `await` on it works, `.then()` does not exist.
109
+ - `{ throw: true }`: a sync throw throws from the call; an async throw rejects the promise.
30
110
 
31
111
  ```ts
32
- function divide(a: number, b: number): Result<number, string> {
33
- return b === 0 ? Err("Cannot divide by zero") : Ok(a / b);
112
+ import { safeTry, println } from "slang-ts";
113
+
114
+ type Settings = {
115
+ theme: string;
116
+ };
117
+
118
+ const settings = safeTry(() => {
119
+ return JSON.parse('{"theme":"dark"}') as Settings;
120
+ });
121
+
122
+ if (settings.isOk) {
123
+ println("Theme:", settings.value.theme); // "dark"
124
+ } else {
125
+ println("Could not read the settings:", settings.error);
34
126
  }
35
127
  ```
36
128
 
37
- Branch with `if (result.isOk) { ... } else { ... }`. Finish chains with `.unwrap().else(fallback)` or `.unwrap().panic(message?)`.
129
+ ### combineResults / combineErrors
38
130
 
39
- `Err(error, raw?)` keeps the original cause on the non-enumerable `.raw` for logs; `.error` stays human-readable.
131
+ `combineResults(results)` returns `Ok([...values])` typed as a tuple when every result is `Ok`,
132
+ or the first `Err` as the same instance (`.raw` kept). An empty array gives `Ok([])`.
133
+ `combineErrors(results)` returns every error message in input order, `[]` when all are `Ok`.
134
+
135
+ ```ts
136
+ import { Ok, Err, combineResults, combineErrors, type Result, println } from "slang-ts";
137
+
138
+ function validateEmail(input: string): Result<string, string> {
139
+ if (!input.includes("@")) {
140
+ return Err("Enter a valid email address");
141
+ }
142
+
143
+ return Ok(input.toLowerCase());
144
+ }
145
+
146
+ function validateAge(input: string): Result<number, string> {
147
+ const age = Number(input);
148
+
149
+ if (!Number.isInteger(age) || age < 13) {
150
+ return Err("You must be at least 13 to sign up");
151
+ }
152
+
153
+ return Ok(age);
154
+ }
155
+
156
+ const fields: [Result<string, string>, Result<number, string>] = [
157
+ validateEmail("ada@example.com"),
158
+ validateAge("29"),
159
+ ];
160
+
161
+ const problems = combineErrors(fields);
162
+
163
+ if (problems.length > 0) {
164
+ println("Fix these fields:", problems);
165
+ } else {
166
+ const values = combineResults(fields);
167
+
168
+ if (values.isOk) {
169
+ const [email, age] = values.value; // typed [string, number]
170
+
171
+ println(email, age); // "ada@example.com" 29
172
+ }
173
+ }
174
+ ```
175
+
176
+ - Arrays of results only, and sync. `await` promises first; run async tasks with
177
+ `superRunner`; chain dependent steps with `pipe`.
178
+ - Pass an array literal or a tuple-typed value to keep the tuple type.
40
179
 
41
180
  ### match / matchAll
42
181
 
43
- `match(result, { Ok: ..., Err: ... })` is exhaustive — TypeScript requires both cases.
182
+ `match(value, patterns)` handles every case of an `Option` or `Result`. TypeScript requires both
183
+ cases. Each handler receives the wrapper itself.
184
+
185
+ ```ts
186
+ import { Ok, match, println } from "slang-ts";
187
+
188
+ const saved = Ok({ id: "u_1", name: "Ada" });
189
+
190
+ const greeting = match(saved, {
191
+ Ok: (user) => `Welcome back, ${user.value.name}`,
192
+ Err: (failed) => `Could not load your profile: ${failed.error}`,
193
+ });
194
+
195
+ println(greeting); // "Welcome back, Ada"
196
+ ```
44
197
 
45
- `matchAll` is for strings, numbers, booleans, symbols, and `Atom`s. It always needs a `_` fallback since there's no finite set of cases.
198
+ `matchAll(value, patterns)` matches strings, numbers, booleans and `Atom`s. It always needs a
199
+ `_` fallback.
46
200
 
47
201
  ```ts
48
- const message = matchAll(failed.category, {
202
+ import { list, matchAll, println } from "slang-ts";
203
+
204
+ const failed = list(["a", "b", "c"]).take(5);
205
+
206
+ const message = matchAll(String(failed.category), {
49
207
  OUT_OF_BOUNDS: () => "That page is out of range.",
50
- _: (category) => `Unexpected failure: ${category}`,
208
+ _: () => "Something went wrong.",
51
209
  });
210
+
211
+ println(message); // "That page is out of range."
52
212
  ```
53
213
 
54
214
  ## Collection chains (list, struct, sets, Ok.iterate)
55
215
 
56
- These return a `Fallible<T>`, not a plain `Result`. Finish with `.else(fallback)` or `.panic(message?)`. On failure, `.category` holds a string like `"OUT_OF_BOUNDS"` or `"INVALID_INPUT"`.
216
+ These return a `Fallible<T>`, not a `Result`. Finish with `.else(fallback)` or
217
+ `.panic(message?)`. On failure, `.category` holds a string such as `"OUT_OF_BOUNDS"` or
218
+ `"INVALID_INPUT"`.
219
+
220
+ - `list`, `struct` and `sets` run each method at once and return a new chain. `Ok.iterate` is
221
+ lazy: steps run only when `toArray`, `reduce` or `count` is called.
222
+ - Nothing throws mid-chain. The first failure is kept and later steps are skipped.
223
+ - Inputs are never changed; each step returns new arrays, objects or sets.
224
+ - `list`, `struct` and `sets` accept a raw value or a successful `Ok` holding one; an `Err`
225
+ fails with `INVALID_INPUT`.
57
226
 
58
227
  ```ts
228
+ import { list, println } from "slang-ts";
229
+
59
230
  const failed = list([1, 2, 3]).range(1, 99).take(1);
231
+
60
232
  if (failed.category === "OUT_OF_BOUNDS") {
61
233
  println(failed.else([])); // []
62
234
  } else {
@@ -64,101 +236,241 @@ if (failed.category === "OUT_OF_BOUNDS") {
64
236
  }
65
237
  ```
66
238
 
67
- - `get` already takes a fallback: `get(key, fallback)`. Do not pair `get(x, fallback)` with `.else(fallback)` — that's redundant.
68
- - `.panic()` throws; once you panic, no custom user message is read afterward.
239
+ - `get` takes a fallback: `get(key, fallback)`. Finish it with `.panic()`, or use
240
+ `get(key).else(fallback)`. Never pair `get(key, fallback)` with `.else(fallback)`.
241
+ - `.panic()` throws; once you panic, no custom message is read afterward.
69
242
 
70
243
  ### list
71
244
 
72
- Strict indexed arrays with `get`, `take`, `skip`, `range`, `chunk`, `count`, `prune`. Bounds are strict — out-of-range fails instead of clamping.
245
+ `list<T>(input): ListChain<T>` reads and slices an array with strict bounds. Every index,
246
+ count and bound must be an integer inside the array; negative indices count from the end. An
247
+ out-of-range request fails with `OUT_OF_BOUNDS` instead of returning fewer items.
73
248
 
74
249
  ```ts
75
- const page = list(users).range(start, end).else([]);
250
+ import { list, println } from "slang-ts";
251
+
252
+ const users = ["Ada", "Grace", "Linus"];
253
+
254
+ const page = list(users).range(0, 2).else([]);
255
+
256
+ println(page); // ["Ada","Grace"]
76
257
  ```
77
258
 
259
+ Methods: `get`, `take`, `skip`, `range`, `chunk`, `count`, `prune`.
260
+
78
261
  ### struct
79
262
 
80
- Safe record access and shaping. `get`, `pick`, `omit`, `merge`, `countBy`, `keyBy`.
263
+ `struct<T>(input): StructChain<T>` reads paths through a record and shapes it. `get` reads own
264
+ properties only: an absent key fails, a key holding `undefined` succeeds. `merge` deep merges
265
+ plain objects; arrays and other values in the patch replace the old value.
266
+
267
+ Methods: `get`, `pick`, `omit`, `merge`, `count`, `countBy`, `keyBy`, `prune`.
81
268
 
82
269
  ```ts
83
- const port = struct(config).get(["server", "port"], 3000);
270
+ import { struct, println } from "slang-ts";
271
+
272
+ const config = {
273
+ server: { host: "localhost" },
274
+ };
275
+
276
+ const port = struct(config).get(["server", "port"], 3000).panic();
277
+
278
+ println("Port:", port); // 3000
84
279
  ```
85
280
 
281
+ - `prune` drops Slang-falsy values (`null`, `undefined`, `""`, `NaN`, `Infinity`, `-Infinity`)
282
+ and keeps `0` and `false`. Its predicate receives `(value, key)` and returns `true` to keep a
283
+ value. It needs a plain object.
284
+ - The wrong shape for an operation fails with `INVALID_INPUT`. A missing `get` path fails with
285
+ `OUT_OF_BOUNDS`. Once a chain fails, later steps are skipped and the category stays on
286
+ `.category`.
287
+
86
288
  ### sets
87
289
 
88
- Membership and set algebra. `has`, `unique`, `union`, `intersection`, `difference`. Objects compare by identity; primitives by value.
290
+ `sets<T>(input): SetsChain<T>` handles membership and set operations.
291
+
292
+ Methods: `has`, `unique`, `union`, `intersection`, `difference`, `count`. An array, string or
293
+ iterable gives its values, a `Map` its keys, a plain object its own keys. Objects compare by
294
+ identity; primitives by value. The other side of an operation accepts the same inputs.
89
295
 
90
296
  ### Ok.iterate
91
297
 
92
- Lazy pipelines over a successful `Ok`. `map`, `filter`, `flatMap`, `take`, `drop`, `chunk`, then `reduce`, `count`, or `toArray`.
298
+ `Ok<T>(value).iterate(): IterateChain<T>` builds a lazy pipeline over the iterable in a
299
+ successful `Ok`. Values pass through every step one at a time, so `take(n)` stops reading the
300
+ source early. A throw in a callback or the source becomes a failure with `INVALID_INPUT`. A
301
+ single-use source, such as a generator, can be finished once.
302
+
303
+ Methods: `map`, `filter`, `flatMap`, `take`, `drop`, `chunk`, `reduce`, `count`, `toArray`.
93
304
 
94
305
  ```ts
306
+ import { Ok, println } from "slang-ts";
307
+
308
+ type User = {
309
+ name: string;
310
+ active: boolean;
311
+ };
312
+
313
+ const users: User[] = [
314
+ { name: "Ada", active: true },
315
+ { name: "Grace", active: false },
316
+ ];
317
+
95
318
  const names = Ok(users)
96
319
  .iterate()
97
- .filter((u) => u.active)
98
- .map((u) => u.name)
320
+ .filter((user) => user.active)
321
+ .map((user) => user.name)
99
322
  .toArray()
100
323
  .else([]);
324
+
325
+ println(names); // ["Ada"]
101
326
  ```
102
327
 
103
328
  ## Async
104
329
 
105
330
  ### SuperPromise
106
331
 
107
- One async operation with timeout, retry, cancellation, and `Ok`/`Err` settlement. Your function gets an `AbortSignal`.
332
+ `superPromise<T>(fn, options?): SuperPromise<T>` is a native promise plus start, retry, timeout
333
+ and cancel controls. Your function receives an `AbortSignal`. Awaiting it gives `Ok` or `Err`;
334
+ it never rejects.
335
+
336
+ Options: `defer`, `delay`, `timeout`, `retry`, `retryUntil`, `group`.
108
337
 
109
338
  ```ts
339
+ import { superPromise, println } from "slang-ts";
340
+
341
+ type User = {
342
+ id: string;
343
+ name: string;
344
+ };
345
+
110
346
  const user = await superPromise(
111
- async (signal) => {
112
- const response = await fetch(`/api/users/${id}`, { signal });
113
- return response.json();
347
+ async (signal: AbortSignal): Promise<User> => {
348
+ const response = await fetch("https://example.com/api/users/u_1", { signal });
349
+
350
+ if (!response.ok) {
351
+ throw new Error("Could not load the user");
352
+ }
353
+
354
+ return (await response.json()) as User;
114
355
  },
115
- { timeout: 5000, retry: 2 },
356
+ { timeout: 5000, retry: 2 }, // 5 seconds per attempt, up to 2 retries
116
357
  );
358
+
359
+ if (user.isOk) {
360
+ println("User:", user.value.name);
361
+ } else {
362
+ println("Could not load the user:", user.error);
363
+ }
117
364
  ```
118
365
 
119
366
  ### SuperRunner
120
367
 
121
- Run `SuperPromise`s in sequence, parallel, or race. `start()` runs once.
368
+ `superRunner(config): SuperRunner<Value>` runs several already-created `SuperPromise`s in
369
+ sequence, in parallel (`all`), or as a race (`race`, with a `count`). `start()` runs once; later
370
+ calls return the same result.
122
371
 
123
372
  ```ts
124
- const all = superRunner({ type: "all", runners: { a, b } });
125
- const result = await all.start();
373
+ import { superPromise, superRunner, println } from "slang-ts";
374
+
375
+ const profile = superPromise(async (): Promise<string> => {
376
+ return "Ada";
377
+ });
378
+
379
+ const orders = superPromise(async (): Promise<number> => {
380
+ return 3;
381
+ });
382
+
383
+ const dashboard = superRunner({ type: "all", runners: { profile, orders } });
384
+
385
+ const loaded = await dashboard.start();
386
+
387
+ if (loaded.isOk) {
388
+ println(loaded.value); // {"profile":"Ada","orders":3}
389
+ }
126
390
  ```
127
391
 
128
392
  ### taskGroup
129
393
 
130
- Shared concurrency limit and start spacing across tasks. Retries wait for a new slot.
394
+ `taskGroup(name, options?): TaskGroup` shares a concurrency limit and start spacing across tasks
395
+ and runners. A retry waits for a new slot.
131
396
 
132
397
  ```ts
133
- const api = taskGroup("user-api", { concurrency: 3, throttle: 200 });
134
- const task = superPromise(fetchUsers, { group: api });
398
+ import { taskGroup, superPromise, println } from "slang-ts";
399
+
400
+ const api = taskGroup("user-api", { concurrency: 3, throttle: 200 }); // starts at least 200 ms apart
401
+
402
+ const task = superPromise(async (): Promise<string> => {
403
+ return "Ada";
404
+ }, { group: api });
405
+
406
+ const user = await task;
407
+
408
+ println(user.isOk); // true
135
409
  ```
136
410
 
137
411
  ### Signal / Channel
138
412
 
139
- `createSignal()` — a trigger that fires once (`fire()`), AbortSignal-compatible.
413
+ `createSignal(): Signal` is a trigger which fires once (`fire()`). It works anywhere an
414
+ `AbortSignal` does.
415
+
416
+ `createChannel(): Channel` is in-process publish/subscribe. `subscribe({ topic }, handler)`
417
+ returns an unsubscribe function, `send({ topic, data })` runs every subscriber of the topic, and
418
+ `when({ signal, topic, data })` sends once the signal fires.
419
+
420
+ ```ts
421
+ import { createChannel, createSignal, println } from "slang-ts";
422
+
423
+ const events = createChannel();
424
+
425
+ const unsubscribe = events.subscribe({ topic: "order.placed" }, (event) => {
426
+ println("Order placed:", event.data); // Order placed: {"orderId":"o_42"}
427
+ });
428
+
429
+ events.send({ topic: "order.placed", data: { orderId: "o_42" } });
430
+
431
+ const shutdown = createSignal();
140
432
 
141
- `createChannel()` — in-process publish/subscribe. `subscribe(topic, handler)` returns an unsubscribe function.
433
+ events.when({ signal: shutdown, topic: "order.placed", data: { orderId: "o_43" } });
434
+
435
+ shutdown.fire(); // Order placed: {"orderId":"o_43"}
436
+
437
+ unsubscribe();
438
+ ```
142
439
 
143
440
  ## Other utilities
144
441
 
145
- - `atom("name")` — unique symbol with a readable description; matches in `matchAll` by description.
146
- - `to` — convert between `Option`, `Atom`, `Result` (e.g. `option("ready").to("atom")`).
147
- - `pipe` — run `Result`-returning steps in order, stopping at the first failure.
148
- - `zip` / `zipWith` / `unzip` — combine parallel collections.
149
- - `memoized` — cache a function by argument identity.
150
- - `panic(message)` — throw immediately for unrecoverable states.
151
- - `println` — dev logging, silent in production unless `setEnvironment` routes it.
442
+ - `atom<T>(name): Atom<T>`: a unique symbol with a readable description; `matchAll` matches it
443
+ by description.
444
+ - `.to(target)`: converts between `Option`, `Atom` and `Result`, such as
445
+ `option("ready").to("atom")`. `_to(value, target)` is the same conversion as a function.
446
+ - `Options(values, fallback?)`: the first usable value from a mix of raw values, `Option`s and
447
+ `Result`s, as `Ok`, or the fallback (`Err("No value!")` by default).
448
+ - `pipe(initial, ...fns).run(options?)`: runs `Result` steps in order and stops at the first
449
+ `Err`. Each function receives the previous `Result`; `run` returns a promise.
450
+ - `zip(inputs, options?)` / `zipWith` / `unzip`: rows of items at the same position across arrays.
451
+ Stops at the shortest input unless `fillValue` is set. Returns plain arrays, not a `Result`,
452
+ and throws on a non-array input unless `includeValues: true`.
453
+ - `memoized(fn)`: stores results per argument list (primitives by value, objects by identity).
454
+ An async result is stored as its promise, so concurrent callers share one call; a rejected
455
+ promise is removed. A throw stores nothing. No size limit or expiry; `.clear()` empties it.
456
+ - `createStepper(config?)`: a history of named steps with `next`, `prev`, `current` and `size`.
457
+ - `panic(message)`: throws at once, for states the program cannot recover from.
458
+ - `println`: development output, silent in production unless `setEnvironment({ printFn })`
459
+ routes it. Plain objects, arrays, sets and maps print as JSON.
460
+ - `isFalsy(value)`: `true` for the values `option()` treats as `None`.
152
461
 
153
462
  ## Conventions agents should follow
154
463
 
155
- - Named params in an object for multi-arg functions, not positional.
156
- - No classes — use functions and plain objects.
464
+ - Named params in an object for multi-argument functions, not positional.
465
+ - No classes: use functions and plain objects.
157
466
  - Error categories are strings (`.category`), not numeric codes. Never call them "error codes."
158
- - `get` accepts a fallback; don't chain `.else()` after a `get` that already has one.
159
- - `.panic()` throws — only for unrecoverable states. Use `Result` / `.else()` for expected failures.
467
+ - `get` accepts a fallback; finish it with `.panic()`, not a second `.else()` fallback.
468
+ - `.panic()` throws: only for unrecoverable states. Use `Result` / `.else()` for expected
469
+ failures.
470
+ - Write `if` / `else` with braces; avoid ternaries and `&&` for control flow in examples.
160
471
  - Zero runtime dependencies; ESM only.
161
472
 
162
473
  ## Package contents
163
474
 
164
- The published package ships `dist/` (JS + bundled declarations), `CHANGELOG.md`, and `skill/SKILL.md` (this file, for agents working with slang-ts).
475
+ The published package ships `dist/` (JavaScript and bundled declarations), `CHANGELOG.md`, and
476
+ `skill/SKILL.md` (this file, for agents working with slang-ts).