diff --git a/cdn/radash.esm.js b/cdn/radash.esm.js index 726c4f3f..e3906b8f 100644 --- a/cdn/radash.esm.js +++ b/cdn/radash.esm.js @@ -703,12 +703,12 @@ const uid = (length, specials = "") => { ); }; -const series = (...items) => { - const { itemsByValue, itemsByIndex } = items.reduce( +const series = (items, toKey = (item) => `${item}`) => { + const { indexesByKey, itemsByIndex } = items.reduce( (acc, item, idx) => ({ - itemsByValue: { - ...acc.itemsByValue, - [item]: idx + indexesByKey: { + ...acc.indexesByKey, + [toKey(item)]: idx }, itemsByIndex: { ...acc.itemsByIndex, @@ -716,29 +716,43 @@ const series = (...items) => { } }), { - itemsByValue: {}, + indexesByKey: {}, itemsByIndex: {} } ); + const min = (a, b) => { + return indexesByKey[toKey(a)] < indexesByKey[toKey(b)] ? a : b; + }; + const max = (a, b) => { + return indexesByKey[toKey(a)] > indexesByKey[toKey(b)] ? a : b; + }; + const first = () => { + return itemsByIndex[0]; + }; + const last = () => { + return itemsByIndex[items.length - 1]; + }; + const next = (current) => { + return itemsByIndex[indexesByKey[toKey(current)] + 1] ?? first(); + }; + const previous = (current) => { + return itemsByIndex[indexesByKey[toKey(current)] - 1] ?? last(); + }; + const spin = (current, num) => { + if (num === 0) + return current; + const abs = Math.abs(num); + const rel = abs > items.length ? abs % items.length : abs; + return list(0, rel - 1).reduce(num > 0 ? next : previous, current); + }; return { - min: (a, b) => { - return itemsByValue[a] < itemsByValue[b] ? a : b; - }, - max: (a, b) => { - return itemsByValue[a] > itemsByValue[b] ? a : b; - }, - first: () => { - return itemsByIndex[0]; - }, - last: () => { - return itemsByIndex[items.length - 1]; - }, - next: (current, defaultValue) => { - return itemsByIndex[itemsByValue[current] + 1] ?? defaultValue; - }, - previous: (current, defaultValue) => { - return itemsByIndex[itemsByValue[current] - 1] ?? defaultValue; - } + min, + max, + first, + last, + next, + previous, + spin }; }; diff --git a/cdn/radash.js b/cdn/radash.js index 175efa60..09fa7a49 100644 --- a/cdn/radash.js +++ b/cdn/radash.js @@ -706,12 +706,12 @@ var radash = (function (exports) { ); }; - const series = (...items) => { - const { itemsByValue, itemsByIndex } = items.reduce( + const series = (items, toKey = (item) => `${item}`) => { + const { indexesByKey, itemsByIndex } = items.reduce( (acc, item, idx) => ({ - itemsByValue: { - ...acc.itemsByValue, - [item]: idx + indexesByKey: { + ...acc.indexesByKey, + [toKey(item)]: idx }, itemsByIndex: { ...acc.itemsByIndex, @@ -719,29 +719,43 @@ var radash = (function (exports) { } }), { - itemsByValue: {}, + indexesByKey: {}, itemsByIndex: {} } ); + const min = (a, b) => { + return indexesByKey[toKey(a)] < indexesByKey[toKey(b)] ? a : b; + }; + const max = (a, b) => { + return indexesByKey[toKey(a)] > indexesByKey[toKey(b)] ? a : b; + }; + const first = () => { + return itemsByIndex[0]; + }; + const last = () => { + return itemsByIndex[items.length - 1]; + }; + const next = (current) => { + return itemsByIndex[indexesByKey[toKey(current)] + 1] ?? first(); + }; + const previous = (current) => { + return itemsByIndex[indexesByKey[toKey(current)] - 1] ?? last(); + }; + const spin = (current, num) => { + if (num === 0) + return current; + const abs = Math.abs(num); + const rel = abs > items.length ? abs % items.length : abs; + return list(0, rel - 1).reduce(num > 0 ? next : previous, current); + }; return { - min: (a, b) => { - return itemsByValue[a] < itemsByValue[b] ? a : b; - }, - max: (a, b) => { - return itemsByValue[a] > itemsByValue[b] ? a : b; - }, - first: () => { - return itemsByIndex[0]; - }, - last: () => { - return itemsByIndex[items.length - 1]; - }, - next: (current, defaultValue) => { - return itemsByIndex[itemsByValue[current] + 1] ?? defaultValue; - }, - previous: (current, defaultValue) => { - return itemsByIndex[itemsByValue[current] - 1] ?? defaultValue; - } + min, + max, + first, + last, + next, + previous, + spin }; }; diff --git a/cdn/radash.min.js b/cdn/radash.min.js index 4d6d5556..96e6c16a 100644 --- a/cdn/radash.min.js +++ b/cdn/radash.min.js @@ -1 +1 @@ -var radash=function(i){"use strict";const O=t=>!!t&&t.constructor===Symbol,C=t=>!!t&&t.constructor===Array,E=t=>!!t&&t.constructor===Object,N=t=>t==null||typeof t!="object"&&typeof t!="function",m=t=>!!(t&&t.constructor&&t.call&&t.apply),B=t=>typeof t=="string"||t instanceof String,L=t=>a(t)&&t%1===0,D=t=>a(t)&&t%1!==0,a=t=>{try{return Number(t)===t}catch{return!1}},_=t=>Object.prototype.toString.call(t)==="[object Date]",F=t=>{if(t===!0||t===!1||t==null)return!0;if(a(t))return t===0;if(_(t))return isNaN(t.getTime());if(m(t)||O(t))return!1;const e=t.length;if(a(e))return e===0;const n=t.size;return a(n)?n===0:Object.keys(t).length===0},$=(t,e)=>{if(Object.is(t,e))return!0;if(t instanceof Date&&e instanceof Date)return t.getTime()===e.getTime();if(t instanceof RegExp&&e instanceof RegExp)return t.toString()===e.toString();if(typeof t!="object"||t===null||typeof e!="object"||e===null)return!1;const n=Reflect.ownKeys(t),r=Reflect.ownKeys(e);if(n.length!==r.length)return!1;for(let c=0;ct.reduce((n,r)=>{const c=e(r);return n[c]||(n[c]=[]),n[c].push(r),n},{});function Z(...t){return!t||!t.length?[]:new Array(Math.max(...t.map(({length:e})=>e))).fill([]).map((e,n)=>t.map(r=>r[n]))}function q(t,e){if(!t||!t.length)return{};const n=m(e)?e:C(e)?(r,c)=>e[c]:(r,c)=>e;return t.reduce((r,c,s)=>({...r,[c]:n(c,s)}),{})}const w=(t,e)=>!t||(t.length??0)===0?null:t.reduce(e),I=(t,e)=>(t||[]).reduce((n,r)=>n+(e?e(r):r),0),M=(t,e=void 0)=>t?.length>0?t[0]:e,U=(t,e=void 0)=>t?.length>0?t[t.length-1]:e,z=(t,e,n=!1)=>{if(!t)return[];const r=(s,u)=>e(s)-e(u),c=(s,u)=>e(u)-e(s);return t.slice().sort(n===!0?c:r)},V=(t,e,n="asc")=>{if(!t)return[];const r=(s,u)=>`${e(s)}`.localeCompare(e(u)),c=(s,u)=>`${e(u)}`.localeCompare(e(s));return t.slice().sort(n==="desc"?c:r)},K=(t,e)=>t.reduce((n,r)=>{const c=e(r);return{...n,[c]:(n[c]??0)+1}},{}),J=(t,e,n)=>{if(!t)return[];if(!e)return[...t];for(let r=0;rr)=>t.reduce((r,c)=>({...r,[e(c)]:n(c)}),{}),X=(t,e,n)=>t.reduce((r,c)=>n(c)?[...r,e(c)]:r,[]),Y=(t,e)=>{const n=e||(r=>r);return w(t,(r,c)=>n(r)>n(c)?r:c)},G=(t,e)=>{const n=e||(r=>r);return w(t,(r,c)=>n(r){const n=Math.ceil(t.length/e);return new Array(n).fill(null).map((r,c)=>t.slice(c*e,c*e+e))},Q=(t,e)=>{const n=t.reduce((r,c)=>{const s=e?e(c):c;return r[s]?r:{...r,[s]:c}},{});return Object.values(n)};function*y(t,e,n=c=>c,r=1){const c=m(n)?n:()=>n,s=e?t:0,u=e??t;for(let o=s;o<=u&&(yield c(o),!(o+r>u));o+=r);}const P=(t,e,n,r)=>Array.from(y(t,e,n,r)),v=t=>t.reduce((e,n)=>[...e,...n],[]),x=(t,e,n)=>{if(!t||!e)return!1;const r=n??(s=>s),c=e.reduce((s,u)=>({...s,[r(u)]:!0}),{});return t.some(s=>c[r(s)])},S=(t,e)=>t?t.reduce((n,r)=>{const[c,s]=n;return e(r)?[[...c,r],s]:[c,[...s,r]]},[[],[]]):[[],[]],tt=(t,e,n)=>!e&&!t?[]:e?t?n?t.reduce((r,c)=>{const s=e.find(u=>n(c)===n(u));return s?[...r,s]:[...r,c]},[]):t:[]:t,et=(t,e,n)=>{if(!t&&!e)return[];if(!e)return[...t];if(!t)return[e];for(let r=0;r{if(!t&&!e)return[];if(!t)return[e];if(!e)return[...t];const c=n?(o,l)=>n(o,l)===n(e,l):o=>o===e;return t.find(c)?t.filter((o,l)=>!c(o,l)):(r?.strategy??"append")==="append"?[...t,e]:[e,...t]},rt=t=>t?.filter(e=>!!e)??[],T=(t,e,n)=>{let r=n;for(let c=1;c<=t;c++)r=e(r,c);return r},ct=(t,e,n=r=>r)=>{if(!t?.length&&!e?.length)return[];if(t?.length===void 0)return[...e];if(!e?.length)return[...t];const r=e.reduce((c,s)=>({...c,[n(s)]:!0}),{});return t.filter(c=>!r[n(c)])};function it(t,e){if(t.length===0)return t;const n=e%t.length;return n===0?t:[...t.slice(-n,t.length),...t.slice(0,-n)]}const st=async(t,e,n)=>{const r=n!==void 0;if(!r&&t?.length<1)throw new Error("Cannot reduce empty array with no init value");const c=r?t:t.slice(1);let s=r?n:t[0];for(const u of c)s=await e(s,u);return s},ut=async(t,e)=>{if(!t)return[];let n=[],r=0;for(const c of t){const s=await e(c,r++);n.push(s)}return n},ot=async t=>{const e=[],n=(s,u)=>e.push({fn:s,rethrow:u?.rethrow??!1}),[r,c]=await d(t)(n);for(const{fn:s,rethrow:u}of e){const[o]=await d(s)(r);if(u)throw o}if(r)throw r;return c};class lt extends Error{constructor(e=[]){super();const n=e.find(r=>r.name)?.name??"";this.name=`AggregateError(${n}...)`,this.message=`AggregateError with ${e.length} errors`,this.stack=e.find(r=>r.stack)?.stack??this.stack,this.errors=e}}const ft=async(t,e,n)=>{const r=e.map((f,h)=>({index:h,item:f})),c=async f=>{const h=[];for(;;){const A=r.pop();if(!A)return f(h);const[Wt,Xt]=await d(n)(A.item);h.push({error:Wt,result:Xt,index:A.index})}},s=P(1,t).map(()=>new Promise(c)),u=await Promise.all(s),[o,l]=S(z(u.flat(),f=>f.index),f=>!!f.error);if(o.length>0)throw new lt(o.map(f=>f.error));return l.map(f=>f.result)},at=async(t,e)=>{const n=t?.times??3,r=t?.delay,c=t?.backoff??null;for(const s of y(1,n)){const[u,o]=await d(e)(l=>{throw{_exited:l}});if(!u)return o;if(u._exited)throw u._exited;if(s===n)throw u;r&&await p(r),c&&await p(c(s))}},p=t=>new Promise(e=>setTimeout(e,t)),d=t=>async(...e)=>{try{return[null,await t(...e)]}catch(n){return[n,null]}},dt=(...t)=>(...e)=>t.slice(1).reduce((n,r)=>r(n),t[0](...e)),gt=(...t)=>t.reverse().reduce((e,n)=>n(e)),mt=(t,...e)=>(...n)=>t(...e,...n),ht=(t,e)=>n=>t({...e,...n}),wt=t=>new Proxy({},{get:(e,n)=>t(n)}),yt=(t,e,n,r)=>function(...s){const u=n?n(...s):JSON.stringify({args:s}),o=t[u];if(o!==void 0&&o.exp>new Date().getTime())return o.value;const l=e(...s);return t[u]={exp:new Date().getTime()+r,value:l},l},pt=(t,{key:e=null,ttl:n=300}={})=>yt({},t,e,n),bt=({delay:t},e)=>{let n=null;return(...c)=>{clearTimeout(n),n=setTimeout(()=>e(...c),t)}},kt=({interval:t},e)=>{let n=!0;return(...c)=>{!n||(e(...c),n=!1,setTimeout(()=>{n=!0},t))}},At=(t,e)=>{const n=()=>{};return new Proxy(Object.assign(n,t),{get:(r,c)=>r[c],set:(r,c,s)=>(r[c]=s,!0),apply:(r,c,s)=>e(Object.assign({},r))(...s)})},Ot=(t,e)=>{const n=e===void 0?0:e;if(t==null)return n;const r=parseFloat(t);return isNaN(r)?n:r},Ct=(t,e)=>{const n=e===void 0?0:e;if(t==null)return n;const r=parseInt(t);return isNaN(r)?n:r},Et=(t,e=n=>n===void 0)=>t?Object.keys(t).reduce((r,c)=>e(t[c])?r:{...r,[c]:t[c]},{}):{},b=(t,e)=>Object.keys(t).reduce((r,c)=>({...r,[e(c,t[c])]:t[c]}),{}),Nt=(t,e)=>Object.keys(t).reduce((r,c)=>({...r,[c]:e(t[c],c)}),{}),_t=(t,e)=>t?Object.entries(t).reduce((n,[r,c])=>{const[s,u]=e(r,c);return{...n,[s]:u}},{}):{},$t=t=>t?Object.keys(t).reduce((n,r)=>({...n,[t[r]]:r}),{}):{},zt=t=>b(t,e=>e.toLowerCase()),Pt=t=>b(t,e=>e.toUpperCase()),St=t=>{if(N(t))return t;if(typeof t=="function")return t.bind({});const e=new t.constructor;return Object.getOwnPropertyNames(t).forEach(n=>{e[n]=t[n]}),e},Tt=(t,e)=>{if(!t)return[];const n=Object.entries(t);return n.length===0?[]:n.reduce((r,c)=>[...r,e(c[0],c[1])],[])},jt=(t,e)=>t?e.reduce((n,r)=>(t.hasOwnProperty(r)&&(n[r]=t[r]),n),{}):{},Bt=(t,e)=>t?!e||e.length===0?t:e.reduce((n,r)=>(delete n[r],n),{...t}):{},Lt=(t,e,n=null)=>{const r=e.split(/[\.\[\]]/g);let c=t;for(const s of r){if(c===null||c===void 0)return n;s.trim()!==""&&(c=c[s])}return c===void 0?n:c},j=(t,e)=>!t&&!e?{}:t?e?Object.entries(t).reduce((n,[r,c])=>({...n,[r]:(()=>E(c)?j(c,e[r]):e[r])()}),{}):t:e,k=(t,e)=>Math.floor(Math.random()*(e-t+1)+t),Dt=t=>{const e=t.length;if(e===0)return null;const n=k(0,e-1);return t[n]},Ft=t=>t.map(e=>({rand:Math.random(),value:e})).sort((e,n)=>e.rand-n.rand).map(e=>e.value),Rt=(t,e="")=>{const n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"+e;return T(t,r=>r+n.charAt(k(0,n.length-1)),"")},Zt=(...t)=>{const{itemsByValue:e,itemsByIndex:n}=t.reduce((r,c,s)=>({itemsByValue:{...r.itemsByValue,[c]:s},itemsByIndex:{...r.itemsByIndex,[s]:c}}),{itemsByValue:{},itemsByIndex:{}});return{min:(r,c)=>e[r]e[r]>e[c]?r:c,first:()=>n[0],last:()=>n[t.length-1],next:(r,c)=>n[e[r]+1]??c,previous:(r,c)=>n[e[r]-1]??c}},g=t=>{if(!t||t.length===0)return"";const e=t.toLowerCase();return e.substring(0,1).toUpperCase()+e.substring(1,e.length)},qt=t=>{const e=t?.replace(/([A-Z])+/g,g)?.split(/(?=[A-Z])|[\.\-\s_]/).map(n=>n.toLowerCase())??[];return e.length===0?"":e.length===1?e[0]:e.reduce((n,r)=>`${n}${r.charAt(0).toUpperCase()}${r.slice(1)}`)},It=t=>{const e=t?.replace(/([A-Z])+/g,g).split(/(?=[A-Z])|[\.\-\s_]/).map(n=>n.toLowerCase())??[];return e.length===0?"":e.length===1?e[0]:e.reduce((n,r)=>`${n}_${r.toLowerCase()}`)},Mt=t=>{const e=t?.replace(/([A-Z])+/g,g)?.split(/(?=[A-Z])|[\.\-\s_]/).map(n=>n.toLowerCase())??[];return e.length===0?"":e.length===1?e[0]:e.reduce((n,r)=>`${n}-${r.toLowerCase()}`)},Ut=t=>{const e=t?.split(/[\.\-\s_]/).map(n=>n.toLowerCase())??[];return e.length===0?"":e.map(n=>n.charAt(0).toUpperCase()+n.slice(1)).join("")},Vt=t=>t?t.split(/(?=[A-Z])|[\.\-\s_]/).map(e=>e.trim()).filter(e=>!!e).map(e=>g(e.toLowerCase())).join(" "):"",Kt=(t,e,n=/\{\{(.+?)\}\}/g)=>Array.from(t.matchAll(n)).reduce((r,c)=>r.replace(c[0],e[c[1]]),t),Jt=(t,e=" ")=>{if(!t)return"";const n=new RegExp(`^[${e}]+|[${e}]+$`,"g");return t.replace(n,"")};return i.alphabetical=V,i.assign=j,i.boil=w,i.callable=At,i.camel=qt,i.capitalize=g,i.chain=dt,i.clone=St,i.cluster=H,i.compose=gt,i.counting=K,i.dash=Mt,i.debounce=bt,i.defer=ot,i.diff=ct,i.draw=Dt,i.first=M,i.flat=v,i.fork=S,i.get=Lt,i.group=R,i.intersects=x,i.invert=$t,i.isArray=C,i.isDate=_,i.isEmpty=F,i.isEqual=$,i.isFloat=D,i.isFunction=m,i.isInt=L,i.isNumber=a,i.isObject=E,i.isPrimitive=N,i.isString=B,i.isSymbol=O,i.iterate=T,i.last=U,i.list=P,i.listify=Tt,i.lowerize=zt,i.map=ut,i.mapEntries=_t,i.mapKeys=b,i.mapValues=Nt,i.max=Y,i.memo=pt,i.merge=tt,i.min=G,i.objectify=W,i.omit=Bt,i.parallel=ft,i.partial=mt,i.partob=ht,i.pascal=Ut,i.pick=jt,i.proxied=wt,i.random=k,i.range=y,i.reduce=st,i.replace=J,i.replaceOrAppend=et,i.retry=at,i.select=X,i.series=Zt,i.shake=Et,i.shift=it,i.shuffle=Ft,i.sift=rt,i.sleep=p,i.snake=It,i.sort=z,i.sum=I,i.template=Kt,i.throttle=kt,i.title=Vt,i.toFloat=Ot,i.toInt=Ct,i.toggle=nt,i.trim=Jt,i.try=d,i.tryit=d,i.uid=Rt,i.unique=Q,i.upperize=Pt,i.zip=Z,i.zipToObject=q,i}({}); +var radash=function(s){"use strict";const $=t=>!!t&&t.constructor===Symbol,N=t=>!!t&&t.constructor===Array,_=t=>!!t&&t.constructor===Object,z=t=>t==null||typeof t!="object"&&typeof t!="function",p=t=>!!(t&&t.constructor&&t.call&&t.apply),D=t=>typeof t=="string"||t instanceof String,F=t=>h(t)&&t%1===0,R=t=>h(t)&&t%1!==0,h=t=>{try{return Number(t)===t}catch{return!1}},P=t=>Object.prototype.toString.call(t)==="[object Date]",Z=t=>{if(t===!0||t===!1||t==null)return!0;if(h(t))return t===0;if(P(t))return isNaN(t.getTime());if(p(t)||$(t))return!1;const n=t.length;if(h(n))return n===0;const e=t.size;return h(e)?e===0:Object.keys(t).length===0},S=(t,n)=>{if(Object.is(t,n))return!0;if(t instanceof Date&&n instanceof Date)return t.getTime()===n.getTime();if(t instanceof RegExp&&n instanceof RegExp)return t.toString()===n.toString();if(typeof t!="object"||t===null||typeof n!="object"||n===null)return!1;const e=Reflect.ownKeys(t),r=Reflect.ownKeys(n);if(e.length!==r.length)return!1;for(let c=0;ct.reduce((e,r)=>{const c=n(r);return e[c]||(e[c]=[]),e[c].push(r),e},{});function q(...t){return!t||!t.length?[]:new Array(Math.max(...t.map(({length:n})=>n))).fill([]).map((n,e)=>t.map(r=>r[e]))}function I(t,n){if(!t||!t.length)return{};const e=p(n)?n:N(n)?(r,c)=>n[c]:(r,c)=>n;return t.reduce((r,c,i)=>({...r,[c]:e(c,i)}),{})}const b=(t,n)=>!t||(t.length??0)===0?null:t.reduce(n),U=(t,n)=>(t||[]).reduce((e,r)=>e+(n?n(r):r),0),J=(t,n=void 0)=>t?.length>0?t[0]:n,K=(t,n=void 0)=>t?.length>0?t[t.length-1]:n,T=(t,n,e=!1)=>{if(!t)return[];const r=(i,u)=>n(i)-n(u),c=(i,u)=>n(u)-n(i);return t.slice().sort(e===!0?c:r)},W=(t,n,e="asc")=>{if(!t)return[];const r=(i,u)=>`${n(i)}`.localeCompare(n(u)),c=(i,u)=>`${n(u)}`.localeCompare(n(i));return t.slice().sort(e==="desc"?c:r)},X=(t,n)=>t.reduce((e,r)=>{const c=n(r);return{...e,[c]:(e[c]??0)+1}},{}),Y=(t,n,e)=>{if(!t)return[];if(!n)return[...t];for(let r=0;rr)=>t.reduce((r,c)=>({...r,[n(c)]:e(c)}),{}),H=(t,n,e)=>t.reduce((r,c)=>e(c)?[...r,n(c)]:r,[]),Q=(t,n)=>{const e=n||(r=>r);return b(t,(r,c)=>e(r)>e(c)?r:c)},V=(t,n)=>{const e=n||(r=>r);return b(t,(r,c)=>e(r){const e=Math.ceil(t.length/n);return new Array(e).fill(null).map((r,c)=>t.slice(c*n,c*n+n))},x=(t,n)=>{const e=t.reduce((r,c)=>{const i=n?n(c):c;return r[i]?r:{...r,[i]:c}},{});return Object.values(e)};function*k(t,n,e=c=>c,r=1){const c=p(e)?e:()=>e,i=n?t:0,u=n??t;for(let o=i;o<=u&&(yield c(o),!(o+r>u));o+=r);}const A=(t,n,e,r)=>Array.from(k(t,n,e,r)),tt=t=>t.reduce((n,e)=>[...n,...e],[]),nt=(t,n,e)=>{if(!t||!n)return!1;const r=e??(i=>i),c=n.reduce((i,u)=>({...i,[r(u)]:!0}),{});return t.some(i=>c[r(i)])},j=(t,n)=>t?t.reduce((e,r)=>{const[c,i]=e;return n(r)?[[...c,r],i]:[c,[...i,r]]},[[],[]]):[[],[]],et=(t,n,e)=>!n&&!t?[]:n?t?e?t.reduce((r,c)=>{const i=n.find(u=>e(c)===e(u));return i?[...r,i]:[...r,c]},[]):t:[]:t,rt=(t,n,e)=>{if(!t&&!n)return[];if(!n)return[...t];if(!t)return[n];for(let r=0;r{if(!t&&!n)return[];if(!t)return[n];if(!n)return[...t];const c=e?(o,f)=>e(o,f)===e(n,f):o=>o===n;return t.find(c)?t.filter((o,f)=>!c(o,f)):(r?.strategy??"append")==="append"?[...t,n]:[n,...t]},st=t=>t?.filter(n=>!!n)??[],B=(t,n,e)=>{let r=e;for(let c=1;c<=t;c++)r=n(r,c);return r},it=(t,n,e=r=>r)=>{if(!t?.length&&!n?.length)return[];if(t?.length===void 0)return[...n];if(!n?.length)return[...t];const r=n.reduce((c,i)=>({...c,[e(i)]:!0}),{});return t.filter(c=>!r[e(c)])};function ut(t,n){if(t.length===0)return t;const e=n%t.length;return e===0?t:[...t.slice(-e,t.length),...t.slice(0,-e)]}const ot=async(t,n,e)=>{const r=e!==void 0;if(!r&&t?.length<1)throw new Error("Cannot reduce empty array with no init value");const c=r?t:t.slice(1);let i=r?e:t[0];for(const u of c)i=await n(i,u);return i},lt=async(t,n)=>{if(!t)return[];let e=[],r=0;for(const c of t){const i=await n(c,r++);e.push(i)}return e},ft=async t=>{const n=[],e=(i,u)=>n.push({fn:i,rethrow:u?.rethrow??!1}),[r,c]=await m(t)(e);for(const{fn:i,rethrow:u}of n){const[o]=await m(i)(r);if(u)throw o}if(r)throw r;return c};class at extends Error{constructor(n=[]){super();const e=n.find(r=>r.name)?.name??"";this.name=`AggregateError(${e}...)`,this.message=`AggregateError with ${n.length} errors`,this.stack=n.find(r=>r.stack)?.stack??this.stack,this.errors=n}}const dt=async(t,n,e)=>{const r=n.map((a,y)=>({index:y,item:a})),c=async a=>{const y=[];for(;;){const l=r.pop();if(!l)return a(y);const[d,g]=await m(e)(l.item);y.push({error:d,result:g,index:l.index})}},i=A(1,t).map(()=>new Promise(c)),u=await Promise.all(i),[o,f]=j(T(u.flat(),a=>a.index),a=>!!a.error);if(o.length>0)throw new at(o.map(a=>a.error));return f.map(a=>a.result)},gt=async(t,n)=>{const e=t?.times??3,r=t?.delay,c=t?.backoff??null;for(const i of k(1,e)){const[u,o]=await m(n)(f=>{throw{_exited:f}});if(!u)return o;if(u._exited)throw u._exited;if(i===e)throw u;r&&await O(r),c&&await O(c(i))}},O=t=>new Promise(n=>setTimeout(n,t)),m=t=>async(...n)=>{try{return[null,await t(...n)]}catch(e){return[e,null]}},ht=(...t)=>(...n)=>t.slice(1).reduce((e,r)=>r(e),t[0](...n)),mt=(...t)=>t.reverse().reduce((n,e)=>e(n)),wt=(t,...n)=>(...e)=>t(...n,...e),yt=(t,n)=>e=>t({...n,...e}),pt=t=>new Proxy({},{get:(n,e)=>t(e)}),bt=(t,n,e,r)=>function(...i){const u=e?e(...i):JSON.stringify({args:i}),o=t[u];if(o!==void 0&&o.exp>new Date().getTime())return o.value;const f=n(...i);return t[u]={exp:new Date().getTime()+r,value:f},f},kt=(t,{key:n=null,ttl:e=300}={})=>bt({},t,n,e),At=({delay:t},n)=>{let e=null;return(...c)=>{clearTimeout(e),e=setTimeout(()=>n(...c),t)}},Ot=({interval:t},n)=>{let e=!0;return(...c)=>{!e||(n(...c),e=!1,setTimeout(()=>{e=!0},t))}},Ct=(t,n)=>{const e=()=>{};return new Proxy(Object.assign(e,t),{get:(r,c)=>r[c],set:(r,c,i)=>(r[c]=i,!0),apply:(r,c,i)=>n(Object.assign({},r))(...i)})},Et=(t,n)=>{const e=n===void 0?0:n;if(t==null)return e;const r=parseFloat(t);return isNaN(r)?e:r},$t=(t,n)=>{const e=n===void 0?0:n;if(t==null)return e;const r=parseInt(t);return isNaN(r)?e:r},Nt=(t,n=e=>e===void 0)=>t?Object.keys(t).reduce((r,c)=>n(t[c])?r:{...r,[c]:t[c]},{}):{},C=(t,n)=>Object.keys(t).reduce((r,c)=>({...r,[n(c,t[c])]:t[c]}),{}),_t=(t,n)=>Object.keys(t).reduce((r,c)=>({...r,[c]:n(t[c],c)}),{}),zt=(t,n)=>t?Object.entries(t).reduce((e,[r,c])=>{const[i,u]=n(r,c);return{...e,[i]:u}},{}):{},Pt=t=>t?Object.keys(t).reduce((e,r)=>({...e,[t[r]]:r}),{}):{},St=t=>C(t,n=>n.toLowerCase()),Tt=t=>C(t,n=>n.toUpperCase()),jt=t=>{if(z(t))return t;if(typeof t=="function")return t.bind({});const n=new t.constructor;return Object.getOwnPropertyNames(t).forEach(e=>{n[e]=t[e]}),n},Bt=(t,n)=>{if(!t)return[];const e=Object.entries(t);return e.length===0?[]:e.reduce((r,c)=>[...r,n(c[0],c[1])],[])},Lt=(t,n)=>t?n.reduce((e,r)=>(t.hasOwnProperty(r)&&(e[r]=t[r]),e),{}):{},Dt=(t,n)=>t?!n||n.length===0?t:n.reduce((e,r)=>(delete e[r],e),{...t}):{},Ft=(t,n,e=null)=>{const r=n.split(/[\.\[\]]/g);let c=t;for(const i of r){if(c===null||c===void 0)return e;i.trim()!==""&&(c=c[i])}return c===void 0?e:c},L=(t,n)=>!t&&!n?{}:t?n?Object.entries(t).reduce((e,[r,c])=>({...e,[r]:(()=>_(c)?L(c,n[r]):n[r])()}),{}):t:n,E=(t,n)=>Math.floor(Math.random()*(n-t+1)+t),Rt=t=>{const n=t.length;if(n===0)return null;const e=E(0,n-1);return t[e]},Zt=t=>t.map(n=>({rand:Math.random(),value:n})).sort((n,e)=>n.rand-e.rand).map(n=>n.value),Mt=(t,n="")=>{const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"+n;return B(t,r=>r+e.charAt(E(0,e.length-1)),"")},qt=(t,n=e=>`${e}`)=>{const{indexesByKey:e,itemsByIndex:r}=t.reduce((l,d,g)=>({indexesByKey:{...l.indexesByKey,[n(d)]:g},itemsByIndex:{...l.itemsByIndex,[g]:d}}),{indexesByKey:{},itemsByIndex:{}}),c=(l,d)=>e[n(l)]e[n(l)]>e[n(d)]?l:d,u=()=>r[0],o=()=>r[t.length-1],f=l=>r[e[n(l)]+1]??u(),a=l=>r[e[n(l)]-1]??o();return{min:c,max:i,first:u,last:o,next:f,previous:a,spin:(l,d)=>{if(d===0)return l;const g=Math.abs(d),Gt=g>t.length?g%t.length:g;return A(0,Gt-1).reduce(d>0?f:a,l)}}},w=t=>{if(!t||t.length===0)return"";const n=t.toLowerCase();return n.substring(0,1).toUpperCase()+n.substring(1,n.length)},It=t=>{const n=t?.replace(/([A-Z])+/g,w)?.split(/(?=[A-Z])|[\.\-\s_]/).map(e=>e.toLowerCase())??[];return n.length===0?"":n.length===1?n[0]:n.reduce((e,r)=>`${e}${r.charAt(0).toUpperCase()}${r.slice(1)}`)},Ut=t=>{const n=t?.replace(/([A-Z])+/g,w).split(/(?=[A-Z])|[\.\-\s_]/).map(e=>e.toLowerCase())??[];return n.length===0?"":n.length===1?n[0]:n.reduce((e,r)=>`${e}_${r.toLowerCase()}`)},Jt=t=>{const n=t?.replace(/([A-Z])+/g,w)?.split(/(?=[A-Z])|[\.\-\s_]/).map(e=>e.toLowerCase())??[];return n.length===0?"":n.length===1?n[0]:n.reduce((e,r)=>`${e}-${r.toLowerCase()}`)},Kt=t=>{const n=t?.split(/[\.\-\s_]/).map(e=>e.toLowerCase())??[];return n.length===0?"":n.map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join("")},Wt=t=>t?t.split(/(?=[A-Z])|[\.\-\s_]/).map(n=>n.trim()).filter(n=>!!n).map(n=>w(n.toLowerCase())).join(" "):"",Xt=(t,n,e=/\{\{(.+?)\}\}/g)=>Array.from(t.matchAll(e)).reduce((r,c)=>r.replace(c[0],n[c[1]]),t),Yt=(t,n=" ")=>{if(!t)return"";const e=new RegExp(`^[${n}]+|[${n}]+$`,"g");return t.replace(e,"")};return s.alphabetical=W,s.assign=L,s.boil=b,s.callable=Ct,s.camel=It,s.capitalize=w,s.chain=ht,s.clone=jt,s.cluster=v,s.compose=mt,s.counting=X,s.dash=Jt,s.debounce=At,s.defer=ft,s.diff=it,s.draw=Rt,s.first=J,s.flat=tt,s.fork=j,s.get=Ft,s.group=M,s.intersects=nt,s.invert=Pt,s.isArray=N,s.isDate=P,s.isEmpty=Z,s.isEqual=S,s.isFloat=R,s.isFunction=p,s.isInt=F,s.isNumber=h,s.isObject=_,s.isPrimitive=z,s.isString=D,s.isSymbol=$,s.iterate=B,s.last=K,s.list=A,s.listify=Bt,s.lowerize=St,s.map=lt,s.mapEntries=zt,s.mapKeys=C,s.mapValues=_t,s.max=Q,s.memo=kt,s.merge=et,s.min=V,s.objectify=G,s.omit=Dt,s.parallel=dt,s.partial=wt,s.partob=yt,s.pascal=Kt,s.pick=Lt,s.proxied=pt,s.random=E,s.range=k,s.reduce=ot,s.replace=Y,s.replaceOrAppend=rt,s.retry=gt,s.select=H,s.series=qt,s.shake=Nt,s.shift=ut,s.shuffle=Zt,s.sift=st,s.sleep=O,s.snake=Ut,s.sort=T,s.sum=U,s.template=Xt,s.throttle=Ot,s.title=Wt,s.toFloat=Et,s.toInt=$t,s.toggle=ct,s.trim=Yt,s.try=m,s.tryit=m,s.uid=Mt,s.unique=x,s.upperize=Tt,s.zip=q,s.zipToObject=I,s}({}); diff --git a/src/series.ts b/src/series.ts index f92caa9b..480736f2 100644 --- a/src/series.ts +++ b/src/series.ts @@ -1,13 +1,18 @@ +import { list } from './array' + /** * Creates a series object around a list of values * that should be treated with order. */ -export const series = (...items: T[]) => { - const { itemsByValue, itemsByIndex } = items.reduce( +export const series = ( + items: T[], + toKey: (item: T) => string | symbol = item => `${item}` +) => { + const { indexesByKey, itemsByIndex } = items.reduce( (acc, item, idx) => ({ - itemsByValue: { - ...acc.itemsByValue, - [item]: idx + indexesByKey: { + ...acc.indexesByKey, + [toKey(item)]: idx }, itemsByIndex: { ...acc.itemsByIndex, @@ -15,58 +20,71 @@ export const series = (...items: T[]) => { } }), { - itemsByValue: {} as Record, + indexesByKey: {} as Record, itemsByIndex: {} as Record } ) + /** + * Given two values in the series, returns the + * value that occurs later in the series + */ + const min = (a: T, b: T): T => { + return indexesByKey[toKey(a)] < indexesByKey[toKey(b)] ? a : b + } + /** + * Given two values in the series, returns the + * value that occurs earlier in the series + */ + const max = (a: T, b: T): T => { + return indexesByKey[toKey(a)] > indexesByKey[toKey(b)] ? a : b + } + /** + * Returns the first item from the series + */ + const first = (): T => { + return itemsByIndex[0] + } + /** + * Returns the last item in the series + */ + const last = (): T => { + return itemsByIndex[items.length - 1] + } + /** + * Given an item in the series returns the next item + * in the series or default if the given value is + * the last item in the series + */ + const next = (current: T): T => { + return itemsByIndex[indexesByKey[toKey(current)] + 1] ?? first() + } + /** + * Given an item in the series returns the previous item + * in the series or default if the given value is + * the first item in the series + */ + const previous = (current: T): T => { + return itemsByIndex[indexesByKey[toKey(current)] - 1] ?? last() + } + /** + * A more dynamic method than next and previous that + * lets you move many times in either direction. + * @example series(weekdays).spin('wednesday', 3) => 'monday' + * @example series(weekdays).spin('wednesday', -3) => 'friday' + */ + const spin = (current: T, num: number): T => { + if (num === 0) return current + const abs = Math.abs(num) + const rel = abs > items.length ? abs % items.length : abs + return list(0, rel - 1).reduce(num > 0 ? next : previous, current) + } return { - /** - * Given two values in the series, returns the - * value that occurs later in the series - */ - min: (a: T, b: T): T => { - return itemsByValue[a] < itemsByValue[b] ? a : b - }, - /** - * Given two values in the series, returns the - * value that occurs earlier in the series - */ - max: (a: T, b: T): T => { - return itemsByValue[a] > itemsByValue[b] ? a : b - }, - /** - * Returns the first item from the series - */ - first: () => { - return itemsByIndex[0] - }, - /** - * Returns the last item in the series - */ - last: () => { - return itemsByIndex[items.length - 1] - }, - /** - * Given an item in the series returns the next item - * in the series or default if the given value is - * the last item in the series - */ - next: ( - current: T, - defaultValue?: TDefault - ): T | TDefault => { - return itemsByIndex[itemsByValue[current] + 1] ?? defaultValue - }, - /** - * Given an item in the series returns the previous item - * in the series or default if the given value is - * the first item in the series - */ - previous: ( - current: T, - defaultValue?: TDefault - ): T | TDefault => { - return itemsByIndex[itemsByValue[current] - 1] ?? defaultValue - } + min, + max, + first, + last, + next, + previous, + spin } } diff --git a/src/tests/series.test.ts b/src/tests/series.test.ts index a03de3b1..a30ac482 100644 --- a/src/tests/series.test.ts +++ b/src/tests/series.test.ts @@ -3,13 +3,13 @@ import * as _ from '..' describe('series module', () => { type Weekday = 'monday' | 'tuesday' | 'wednesday' | 'thursday' | 'friday' - const sut = _.series( + const sut = _.series([ 'monday', 'tuesday', 'wednesday', 'thursday', 'friday' - ) + ]) describe('min function', () => { test('correctly returns min', () => { @@ -52,12 +52,8 @@ describe('series module', () => { const result = sut.next('wednesday') assert.equal(result, 'thursday') }) - test('returns null by default if exhausted', () => { + test('returns first given last exhausted', () => { const result = sut.next('friday') - assert.equal(result, null) - }) - test('returns given default if exhausted', () => { - const result = sut.next('friday', 'monday') assert.equal(result, 'monday') }) }) @@ -67,13 +63,28 @@ describe('series module', () => { const result = sut.previous('wednesday') assert.equal(result, 'tuesday') }) - test('returns null by default if exhausted', () => { + test('returns last given first exhausted', () => { const result = sut.previous('monday') - assert.equal(result, null) + assert.equal(result, 'friday') + }) + }) + + describe('spin function', () => { + test('returns current given zero', () => { + const result = sut.spin('wednesday', 0) + assert.equal(result, 'wednesday') }) - test('returns given default if exhausted', () => { - const result = sut.previous('monday', 'friday') + test('returns friday given -3 starting at wednesday', () => { + const result = sut.spin('wednesday', -3) assert.equal(result, 'friday') }) + test('returns monday given 3 starting at wednesday', () => { + const result = sut.spin('wednesday', 3) + assert.equal(result, 'monday') + }) + test('returns monday given 13 starting at wednesday', () => { + const result = sut.spin('wednesday', 13) + assert.equal(result, 'monday') + }) }) })