@jrc03c/data-class 0.0.2
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/.prettierrc.json +10 -0
- package/build.mjs +38 -0
- package/dist/data-class.js +3638 -0
- package/dist/data-class.min.js +17 -0
- package/eslint.config.js +37 -0
- package/package.json +29 -0
- package/pnpm-workspace.yaml +2 -0
- package/readme.md +134 -0
- package/src/iife.mjs +3 -0
- package/src/index.mjs +42 -0
- package/src/index.test.mjs +71 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
(()=>{function l(e){return typeof e=="number"&&!isNaN(e)||typeof e=="bigint"}var yt=new Function(`
|
|
2
|
+
try {
|
|
3
|
+
return this === window
|
|
4
|
+
} catch(e) {}
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
return !!importScripts
|
|
8
|
+
} catch(e){}
|
|
9
|
+
|
|
10
|
+
return false
|
|
11
|
+
`);var $=class extends Error{constructor(t){yt()?super(t):super(`
|
|
12
|
+
|
|
13
|
+
\x1B[31m`+t+`
|
|
14
|
+
\x1B[0m`)}};function m(e,t){if(!e)throw new $(t)}function g(e,t){for(let n=0;n<e.length;n++)t(e[n],n,e)}var bt=[Array,ArrayBuffer,BigInt64Array,BigUint64Array,Float32Array,Float64Array,Int16Array,Int32Array,Int8Array,Uint16Array,Uint32Array,Uint8Array,Uint8ClampedArray];function h(e){return e===null||typeof e>"u"}function d(e,t){let n=new Array(e.length);for(let r=0;r<e.length;r++)n[r]=t(e[r],r,e);return n}var _e=d(bt,e=>e.name);function f(e){try{return e instanceof Array?!0:h(e.constructor)?!1:bt.indexOf(e.constructor)>-1||_e.indexOf(e.constructor.name)>-1}catch{return!1}}function N(e){try{return!!e._symbol&&e._symbol===Symbol.for("@jrc03c/js-math-tools/dataframe")}catch{return!1}}function _(e){return typeof e=="function"}function k(e){return typeof e=="object"&&!h(e)&&!f(e)}function b(e){try{return!!e._symbol&&e._symbol===Symbol.for("@jrc03c/js-math-tools/series")}catch{return!1}}function W(e,t){if(N(e)){let i=W(e.values,t);return i.length>0&&l(i[0])&&i[0]>=0&&i[0]<e.index.length&&(i[0]=e.index[i[0]]),i.length>1&&l(i[1])&&i[1]>=0&&i[1]<e.columns.length&&(i[1]=e.columns[i[1]]),i}if(b(e)){let i=W(e.values,t);return i.length>0&&l(i[0])&&i[0]>=0&&i[0]<e.index.length&&(i[0]=e.index[i[0]]),i}if(m(k(e)||f(e),"You must pass (1) an object, array, Series, or DataFrame and (2) a function or value into the `indexOf` function!"),!_(t)){let i=t;t=a=>a===i}function n(i,a,s){if(s=s||[],s.indexOf(i)>-1)return null;if(k(i)){s.push(i);let u=Object.keys(i).concat(Object.getOwnPropertySymbols(i));for(let p=0;p<u.length;p++){let c=u[p],y=i[c];if(a(y))return[c];let w=n(y,a,s);if(w&&w.length>0)return[c].concat(w)}}else if(f(i)){s.push(i);for(let u=0;u<i.length;u++){let p=i[u];if(a(p))return[u];let c=n(p,a,s);if(c&&c.length>0)return[u].concat(c)}}else if(a(i))return[];return null}function r(i){try{return t(i)}catch{return!1}}let o=n(e,r);return o&&o.length>0?o:null}function I(e){function t(n){if(typeof n=="object"){if(n===null)return null;if(f(n))return n instanceof Array?d(n,o=>I(o)):n.slice();if(b(n)){let o=n.copy();return o.values=I(o.values),o}if(N(n)){let o=n.copy();return o.values=I(n.values),o}if(n instanceof Date)return new Date(n.getTime());n=q(n);let r={};return g(Object.keys(n).concat(Object.getOwnPropertySymbols(n)),o=>{r[o]=I(n[o])}),r}else return n}return t(q(e))}function q(e){function t(o,i,a){if(i=i||[],a=a||"",i.indexOf(o)>-1){let s=a.split("/").slice(a.startsWith("/")?1:0);if(s.some((p,c)=>{let y=s.slice(0,s.length-c-1),w=n;return g(y,D=>{w=w[D]}),w===o}))return`<reference to "${n===o?"/":"/"+W(n,o).join("/")}">`}return typeof o=="object"?o===null?null:(i.push(o),f(o)?typeof o.constructor<"u"&&o.constructor.name!=="Array"?o.slice():d(o,(s,u)=>t(s,i,a+"/"+u)):(g(Object.keys(o).concat(Object.getOwnPropertySymbols(o)),s=>{o[s]=t(o[s],i,a+"/"+s.toString())}),o)):o}let n=e,r=t(n);if(N(e)){let o=e.copy();o._values=r.values,o._columns=r.columns,o._index=r.index,r=o}if(b(e)){let o=e.copy();o.name=r.name,o._values=r.values,o._index=r.index,r=o}return r}function H(e){return e instanceof Date&&e.toString()!=="Invalid Date"}var At=["number","int","float","bigint"];function z(e,t){function n(r,o){let i=typeof r,a=typeof o;if(i!==a&&!At.includes(i)&&!At.includes(a))return!1;if(i==="undefined"&&a==="undefined")return!0;if(i==="boolean"||i==="symbol")return r===o;if(i==="number"||i==="bigint")try{let s=r.toString(),u=o.toString();return s===u}catch{return!1}if(i==="string"||i==="function")return r===o;if(i==="object"){if(r===null||o===null)return r===null&&o===null;{if(H(r))return H(o)?r.getTime()===o.getTime():!1;if(H(o))return!1;if(r instanceof RegExp&&o instanceof RegExp)return r.toString()===o.toString();if(f(r)!==f(o))return!1;let s=Object.keys(r).concat(Object.getOwnPropertySymbols(r)),u=Object.keys(o).concat(Object.getOwnPropertySymbols(o));if(s.length!==u.length)return!1;for(let p=0;p<s.length;p++){let c=s[p];if(!n(r[c],o[c]))return!1}return!0}}}try{return n(e,t)}catch{return n(q(e),q(t))}}function ot(e){let t="abcdefg1234567890",n="";for(;n.length<e;)n+=t[Math.floor(Math.random()*t.length)];return n}var Ie=ot(16),Ae=ot(16),Fe=ot(16),xe=ot(16),je=ot(16),ut=class{constructor(){this.clear()}get counts(){return d(this.values,t=>this.get(t))}get values(){return Object.values(this.valuesDict)}clear(){return this.countsDict={},this.valuesDict={},this}count(t){for(let n of t)f(n)?this.count(n):this.increment(n);return this}delete(t){let n=this.getStandardizedKey(t);return delete this.countsDict[n],delete this.valuesDict[n],this}get(t){return this.countsDict[this.getStandardizedKey(t)]||0}getStandardizedKey(t){return typeof t=="object"&&t===null?Ie:h(t)?Ae:_(t)?t.toString():typeof t=="symbol"?t.toString()+" - "+je:t===1/0?Fe:t===-1/0?xe:typeof t=="bigint"?t.toString():N(t)?t.toJSONString():b(t)?JSON.stringify(t.toObject()):JSON.stringify(t)}has(t){return!h(this.countsDict[this.getStandardizedKey(t)])}increment(t){return this.set(t,this.get(t)+1)}set(t,n){let r=this.getStandardizedKey(t);return this.countsDict[r]=n,this.valuesDict[r]=t,this}toArray(){return d(this.values,t=>({value:t,count:this.get(t)}))}toObject(){let t={};return g(this.values,n=>{t[n]=this.get(n)}),t}};function x(e){if(N(e)||b(e))return x(e.values);m(f(e),"The `flatten` function only works on arrays, Series, and DataFrames!");function t(n){let r=[];return g(n,o=>{f(o)?r=r.concat(t(o)):r.push(o)}),r}return t(e)}function B(e,t){t=t||{};let n=new ut,r={},o=x(e),i=[],a=-1/0,s=1/0,u=!1,p=0;for(let y of o){if(typeof y=="bigint"&&(u=!0),!t.shouldDropNaNs||l(y))try{y>a&&(a=y),y<s&&(s=y),p+=Number(y),i.push(y)}catch{a=NaN,s=NaN,p=NaN}n.increment(y)}let c=p/i.length;if(r.counts=n,r.max=a,r.mean=c,r.min=s,r.n=o.length,r.sum=p,isNaN(r.mean)&&(r.max=NaN,r.min=NaN),t.shouldDropNaNs&&(r.nWithoutNaNs=i.length),t.mode){let y=Array.from(d(n.values,M=>[M,n.get(M)])).toSorted((M,at)=>at[1]-M[1]),w=y[0][1],D=[];for(let M of y)if(M[1]==w)D.push(M[0]);else break;r.mode=D.toSorted()}if(t.median)if(isNaN(c))r.median=NaN;else{let y=i.toSorted((D,M)=>Number(D)-Number(M)),w=Math.floor(y.length/2);if(y.length%2===0){let D=y[w-1],M=y[w];if(r.median=(Number(D)+Number(M))/2,u&&typeof D=="bigint"&&typeof M=="bigint")try{r.median=BigInt(r.median)}catch{}}else r.median=y[w]}if(t.stdev||t.variance){let y=0;for(let D of i)y+=Math.pow(Number(D)-c,2);y/=i.length;let w=Math.sqrt(y);r.stdev=w,r.variance=y}if(u){try{r.sum=BigInt(r.sum)}catch{}try{r.mean=BigInt(r.mean)}catch{}t.mode&&(r.mode=d(r.mode,y=>{try{return BigInt(y)}catch{return y}}))}return r}function it(e,t){let{counts:n}=B(e);return h(t)||(_(t)?g(n.values,r=>{t(r)||n.delete(r)}):g(n.values,r=>{z(r,t)||n.delete(r)})),n}function F(e,t){let n=[];for(let r=0;r<e.length;r++)t(e[r],r,e)&&n.push(e[r]);return n}function Nt(e){if(N(e)||b(e))return Nt(e.values);if(f(e)){let t=!1,n=!1,r=null;for(let o of e){if(Nt(o))return!0;if(f(o)){if(r===null)r=o.length;else if(o.length!==r)return!0;t=!0}else n=!0;if(t&&n)return!0}}return!1}function V(e){return Nt(q(e))}function Q(e){if(N(e)||b(e))return Q(e.values);m(f(e),"The `isNested` function only works on arrays, Series, and DataFrames!");for(let t=0;t<e.length;t++)if(f(e[t]))return!0;return!1}var Z="You must pass a natural number or a one-dimensional array of natural numbers into the `ndarray` function!";function E(e){m(!h(e),Z),f(e)||(e=[e]),m(!Q(e),Z),m(e.length>0,Z);let t=e[0];if(typeof t=="bigint"&&(t=Number(t)),m(l(t),Z),m(t>=0,Z),m(Math.floor(t)===t,Z),m(t!==1/0,"We can't create an array containing an infinite number of values!"),e.length===1){let n=[];for(let r=0;r<t;r++)n.push(void 0);return n}else{let n=[];for(let r=0;r<t;r++)n.push(E(e.slice(1)));return n}}var vt=class e{static from(t){return new e(t.a,t.b)}a=0;b=0;step=0;constructor(t,n,r){this.a=t,this.b=n,this.step=r??1}get length(){return Math.abs((Math.max(this.a,this.b)-Math.min(this.a,this.b))/this.step)}get pairIterator(){let t=this[Symbol.iterator]();function*n(){let r=0;for(let o of t)yield[o,r],r++}return n()}[Symbol.iterator](){let t=typeof this.a=="bigint"||typeof this.b=="bigint"||typeof this.step=="bigint",n=t?BigInt(this.a):this.a,r=t?BigInt(this.b):this.b,o=t?BigInt(this.step):this.step;(n<=r&&o<0||n>r&&o>0)&&(o*=t?BigInt(-1):-1);function*i(){if(n<=r)for(let a=n;a<r;a+=o)yield a;else for(let a=n;a>r;a+=o)yield a}return i()}drop(t){return new e(this.a+t*this.step,this.b)}every(t){for(let n of this.pairIterator)if(!t(...n))return!1;return!0}filter(t){let n=[];for(let r of this.pairIterator)t(...r)&&n.push(r[0]);return n}find(t){for(let n of this.pairIterator)if(t(...n))return n[0]}flatMap(){throw new Error("The `RangeIterator.flatMap` method has no implementation!")}forEach(t){for(let n of this.pairIterator)t(...n)}map(t){let n=[];for(let r of this.pairIterator)n.push(t(...r));return n}reduce(t,n){for(let r of this.pairIterator)n=t(r[0],n,r[1]);return n}some(t){for(let n of this.pairIterator)if(t(...n))return!0;return!1}take(t){return new e(this.a,this.a+t*this.step)}toArray(){let t=[];for(let n of this)t.push(n);return t}};function T(e,t,n=1){return m(!h(e)&&!h(t)&&!h(n),"You must pass two numbers and optionally a step value to the `range` function!"),m(l(e)&&l(t)&&l(n),"You must pass two numbers and optionally a step value to the `range` function!"),m(n!==0,"The step value must be greater than 0! (NOTE: The step value is a magnitude; it does not indicate direction.)"),new vt(e,t,n)}function st(e){let t="abcdefg1234567890",n="";for(;n.length<e;)n+=t[Math.floor(Math.random()*t.length)];return n}var Me=st(256),Ee=st(256),Be=st(256),Ue=st(256),Pe=st(256);function P(e){if(N(e)||b(e))return P(e.values);m(f(e),"The `set` function only works on arrays, Series, and DataFrames!");let t=[],n={};return g(x(e),r=>{let o=typeof r=="object"&&r===null?Me:h(r)?Ee:_(r)?r.toString():typeof r=="symbol"?r.toString()+" - "+Pe:r===1/0?Be:r===-1/0?Ue:typeof r=="bigint"?r.toString():N(r)?r.toJSONString():b(r)?JSON.stringify(r.toObject()):JSON.stringify(r);typeof n[o]>"u"&&t.push(r),n[o]=!0}),t}function Ft(e){if(f(e)){let t=Ft(e[0]);return[e.length].concat(t||[])}else return}function v(e){return N(e)||b(e)?v(e.values):(m(f(e),"The `shape` function only works on arrays, Series, and DataFrames!"),Ft(e))}function St(e,t,n){if(h(n)&&(n=0),m(n===0||n===1||n==="vertical"||n==="horizontal",'The only valid axis values for use when appending data to a DataFrame are 0, 1, "vertical", and "horizontal". Note that 0 == "horizontal" and 1 == "vertical".'),f(t)){m(!V(t),"The array of data you're trying to append to this DataFrame is jagged!");let r=v(t);if(r.length===1)if(n===0){let o=e.copy();o._values.push(t);let i=Math.max(e.shape[1],r[0]);for(g(o._values,a=>{for(;a.length<i;)a.push(void 0)});o._index.length<o._values.length;)o._index.push("row"+o._index.length);for(;o._columns.length<i;)o._columns.push("col"+o._columns.length);return o}else{let o=Math.max(e.shape[0],r[0]),i=e.copy();for(T(0,o).forEach(a=>{a>=i._values.length&&i._values.push(E(e.shape[1])),i._values[a].push(t[a])});i._index.length<i._values.length;)i._index.push("row"+i._index.length);for(;i._columns.length<i._values[0].length;)i._columns.push("col"+i._columns.length);return i}else if(r.length===2)if(n===0){let o=Math.max(...d(t,a=>a.length).concat([e.shape[1]])),i=e.copy();for(i._values=d(i._values.concat(t),a=>{for(;a.length<o;)a.push(void 0);return a});i._index.length<i._values.length;)i._index.push("row"+i._index.length);for(;i._columns.length<o;)i._columns.push("col"+i._columns.length);return i}else{let o=Math.max(...d(t,s=>s.length))+e.shape[1],i=Math.max(e.shape[0],r[0]),a=e.copy();for(T(0,i).forEach(s=>{for(s>=a._values.length&&a._values.push(E(e.shape[1])),a._values[s]=a._values[s].concat(t[s]);a._values[s].length<o;)a._values[s].push(void 0)});a._index.length<a._values.length;)a._index.push("row"+a._index.length);for(;a._columns.length<o;)a._columns.push("col"+a._columns.length);return a}else throw new $("Only 1- and 2-dimensional arrays can be appended to a DataFrame!")}else if(b(t)){let r=St(e,t.values,n);return n===0?r.index[r.index.length-1]=r.index.indexOf(t.name)>-1?t.name+" (2)":t.name:r.columns[r.columns.length-1]=r.columns.indexOf(t.name)>-1?t.name+" (2)":t.name,r}else if(N(t))if(n===0){let r=e.copy(),o=P(r._columns.concat(t._columns)).length;for(g(r._values,i=>{for(;i.length<o;)i.push(void 0)}),t.apply(i=>{let a=i.copy(),s=[];g(r._columns,u=>{let p=a._index.indexOf(u);p>-1?(s.push(a._values[p]),a._values.splice(p,1),a._index.splice(p,1)):s.push(void 0)}),r._values.push(s.concat(a._values))},1),r._columns=r._columns.concat(F(t._columns,i=>r._columns.indexOf(i)<0));r._index.length<r._values.length;){let i="row"+r._index.length;r._index.push(i+(e._index.indexOf(i)>-1?" (2)":""))}return r}else{let r=e.copy();return g(r._index,(o,i)=>{let a=t._index.indexOf(o);a>-1?r._values[i]=r._values[i].concat(t._values[a]):r._values[i]=r._values[i].concat(E(t.shape[1]))}),g(t._index,(o,i)=>{r._index.indexOf(o)<0&&(r._index.push(o),r._values.push(E(r._columns.length).concat(t._values[i])))}),r._columns=r._columns.concat(d(t._columns,o=>o+(r._columns.indexOf(o)>-1?" (2)":""))),r}else throw new $("Only 1- or 2-dimensional arrays, Series, and DataFrames can be appended to a DataFrame!")}function xt(e,t,n,r,o){if(o=o||0,m(_(r),"The first parameter to the `apply` method must be a function."),m(o===0||o===1,"The second parameter to the `apply` method (the `axis`) must be 0 or 1."),o===0){let i={},a;if(g(n.columns,(s,u)=>{let p=new t(d(n.values,y=>y[u]));p.name=s,p.index=n.index;let c=r(p,u,n);c instanceof t?i[s]=c.values:i[s]=c,h(a)&&(a=c instanceof t||f(c))}),a){let s=new e(i);return s.index=n.index,s}else{let s=new t(d(n.columns,u=>i[u]));return s.index=n.columns,s}}else if(o===1){let i,a=d(n.values,(s,u)=>{let p=new t(s);p.name=n.index[u],p.index=n.columns;let c=r(p,u,n);return h(i)&&(i=c instanceof t||f(c)),c instanceof t?c.values:c});if(i){let s=new e(a);return s.index=n.index,s.columns=n.columns,s}else{let s=new t(a);return s.index=n.index,s}}}function O(e){return typeof e=="string"}function jt(e,t,n,r,o){let i=s=>s instanceof e,a=s=>s instanceof t;if(h(o))if(i(r)){let s=n.copy(),u=s.shape,p=r.shape;for(let c=0;c<p[1];c++){let y=r.columns[c],w=s.columns.includes(y)?s.columns.indexOf(y):s.columns.length;s.columns.includes(y)||s._columns.push(y);for(let D=0;D<u[0];D++)s._values[D][w]=r._values[D][c]}return s}else{if(a(r))return n.assign(r.name,r.values);if(k(r))return n.assign(new e(r));throw new $("You must pass a DataFrame, Series, or object into the `assign` method!")}else{m(O(r),"If passing two arguments into the `assign` method, then the first argument must be a string name!"),m(f(o)&&!V(o)&&v(o).length===1,"If passing two arguments into the `assign` method, then the second argument must be a 1-dimensional array!");let s=n.copy();if(s.columns.includes(r)){let u=s.columns.indexOf(r);return s.columns[u]=r,g(s.values,(p,c)=>p[u]=o[c]),s}else return s._columns.push(r),g(s._values,(u,p)=>u.push(o[p])),s}}function Mt(e,t){if(t.isEmpty)return new e;let n=new e(I(t.values));return n.columns=t.columns.slice(),n.index=t.index.slice(),n}function Et(e,t,n,r,o){h(r)&&(r=[]),h(o)&&(o=[]),(O(r)||l(r))&&(r=[r]),(O(o)||l(o))&&(o=[o]),m(f(r),"The `drop` method only works on 1-dimensional arrays of numerical indices and/or strings."),m(f(o),"The `drop` method only works on 1-dimensional arrays of numerical indices and/or strings."),m(v(r).length===1,"The `drop` method only works on 1-dimensional arrays of numerical indices and/or strings."),m(v(o).length===1,"The `drop` method only works on 1-dimensional arrays of numerical indices and/or strings.");let i,a;g(n.index,(u,p)=>{r.indexOf(u)<0&&r.indexOf(p)<0&&(i||(i=[]),i.push(u))}),g(n.columns,(u,p)=>{o.indexOf(u)<0&&o.indexOf(p)<0&&(a||(a=[]),a.push(u))});let s=n.get(i,a);if(s instanceof t){let u=new e;u=u.assign(s),n.index.indexOf(s.name)>-1&&(u=u.transpose()),s=u}return s}function ft(e){return l(e)&&(e>=0?Math.floor(e)===e:Math.ceil(e)===e)}function J(e){return ft(e)&&e>=0}function Bt(e,t,n,r,o,i){r=r||0,m(r===0||r===1,"The first parameter of the `dropMissing` method (the `axis`) must be 0 or 1."),i=i||0,m(J(i),"The third parameter of the `dropMissing` method (the `threshold`) should be a whole number (meaning that data should be dropped if it contains more than `threshold` null values)."),o=i>0?"none":o||"any",m(o==="any"||o==="all"||o==="none","The second parameter of the `dropMissing` method (the `condition` parameter, which indicates the condition under which data should be dropped) should be 'any' or 'all' (meaning that if 'any' of the data contains null values, then it should be dropped; or that if 'all' of the data contains null values, then it should be dropped).");function a(p){if(i>0){let c=0;for(let y=0;y<p.length;y++){let w=p[y];if(h(w)&&c++,c>=i)return[]}}else if(o==="any")for(let c=0;c<p.length;c++){let y=p[c];if(h(y))return[]}else if(o==="all"){for(let c=0;c<p.length;c++){let y=p[c];if(!h(y))return p}return[]}return p}let s=n.copy(),u=Math.random().toString();if(r===0){s=s.assign(u,s.index);let p=F(d(s.values,a),y=>y.length>0);if(v(p).length<2)return new e;s.values=p;let c=s.get(null,u);if(h(c))return new e;O(c)&&(c=[c]),c instanceof t&&(c=c.values),s.index=c,s=s.drop(null,u)}else if(r===1){let p={};if(g(s.columns,(y,w)=>{let D=d(s.values,at=>at[w]),M=a(D);M.length>0&&(p[y]=M)}),Object.keys(p).length+Object.getOwnPropertySymbols(p).length===0)return new e;let c=new e(p);return c.index=s.index,c}return s}function lt(e){if(N(e)||b(e))return e.dropNaN(...Object.values(arguments).slice(1));m(f(e),"The `dropNaN` function only works on arrays, Series, and DataFrames!");let t=[];return g(e,n=>{try{return t.push(lt(n))}catch{if(l(n))return t.push(n)}}),t}function Ut(e,t,n,r,o){n=n||0,m(n===0||n===1,"The first parameter of the `dropNaN` method (the `axis`) must be 0 or 1."),o=o||0,m(J(o),"The third parameter of the `dropNaN` method (the `threshold`) should be a whole number (meaning that data should be dropped if it contains more than `threshold` NaN values)."),r=o>0?"none":r||"any",m(r==="any"||r==="all"||r==="none","The second parameter of the `dropNaN` method (the `condition` parameter, which indicates the condition under which data should be dropped) should be 'any' or 'all' (meaning that if 'any' of the data contains NaN values, then it should be dropped; or that if 'all' of the data contains NaN values, then it should be dropped).");function i(s){let u=lt(s);return o>0?s.length-u.length<o:r==="any"?u.length===s.length:r==="all"?u.length>0:!0}let a=t.copy();if(n===0){let s=F(a.index,u=>{let p=a.get(u,null).values;return i(p)});return s.length>0?a.get(s,null):new e}else if(n===1){let s=F(a.columns,u=>{let p=a.get(null,u).values;return i(p)});return s.length>0?a.get(null,s):new e}return a}function Pt(e){let t={};return g(x(e),(n,r)=>{t[n]=r}),t}function tt(e){return Object.keys(e).concat(Object.getOwnPropertySymbols(e)).sort((t,n)=>e[t]-e[n])}function kt(e,t,n,r,o){m(_(r),"The `filter` method takes a single parameter: a function that is used to filter the values."),h(o)&&(o=0),m(o===0||o===1,"The `axis` parameter to the `filter` method must be 0 or 1.");let i=n.copy();if(i.isEmpty)return i;let a=Pt(i.index),s=Pt(i.columns);if(o===0){let u=0,p=F(i.values,(c,y)=>{let w=new t(c);w.name=n.index[y],w.index=n.columns;let D=r(w,y,n);return D?u++:delete a[i.index[y]],D});if(u===0)return new e;if(u===1){let c=new t(p[0]);return c.name=tt(a)[0],c.index=tt(s),c}i.values=p,i.index=tt(a)}else if(o===1){i=i.transpose();let u=0,p=F(i.values,(c,y)=>{let w=new t(c);w.name=n.columns[y],w.index=n.index;let D=r(w,y,n);return D?u++:delete s[i.index[y]],D});if(u===0)return new e;if(u===1){let c=new t(p[0]);return c.name=tt(s)[0],c.index=tt(a),c}i.values=p,i.index=tt(s),i=i.transpose()}return i}function zt(e,t,n){(O(t)||l(t))&&(t=[t]),(O(n)||l(n))&&(n=[n]);for(let o in t)typeof t[o]=="bigint"&&(t[o]=Number(t[o]));for(let o in n)typeof n[o]=="bigint"&&(n[o]=Number(n[o]));let r=P(d((t||[]).concat(n||[]),o=>typeof o));return m(r.length<=2,"Only whole numbers and/or strings are allowed in `get` arrays!"),r.length===1&&m(r[0]==="string"||r[0]==="number","Only whole numbers and/or strings are allowed in `get` arrays!"),r.length===2&&(m(r.indexOf("string")>-1,"Only whole numbers and/or strings are allowed in `get` arrays!"),m(r.indexOf("number")>-1,"Only whole numbers and/or strings are allowed in `get` arrays!")),h(t)||(t=d(t,o=>{if(O(o))return m(e.index.indexOf(o)>-1,`Row "${o}" does not exist!`),o;if(l(o))return m(o>=0,`Index ${o} is out of bounds!`),m(Math.floor(o)===o,"Row numbers must be integers!"),m(o<e.index.length,`Index ${o} is out of bounds!`),e.index[o]})),h(n)||(n=d(n,o=>{if(O(o))return m(e.columns.indexOf(o)>-1,`Column "${o}" does not exist!`),o;if(l(o))return m(o>=0,`Column ${o} is out of bounds!`),m(Math.floor(o)===o,"Column numbers must be integers!"),m(o<e.columns.length,`Column ${o} is out of bounds!`),e.columns[o]})),e.getSubsetByNames(t,n)}function ke(e,t){try{return e<t?-1:e>t?1:0}catch{return e=typeof e=="object"&&e!==null?JSON.stringify(e):e.toString(),t=typeof t=="object"&&t!==null?JSON.stringify(t):t.toString(),e<t?-1:e>t?1:0}}function R(e,t){if(h(t)&&(t=ke),N(e)||b(e))return e.sort(...Object.values(arguments).slice(1));m(f(e),"The `sort` function only works on arrays, Series, and DataFrames!"),m(_(t),"The second parameter of the `sort` function must be a comparison function!");let n=e.slice();return n.sort(t),n}function ze(e){let t=e.toLowerCase(),n="";for(let o=0;o<t.length;o++){let i=t[o];i.match(/[a-z0-9]/g)?n+=i:n+=" "}let r=F(n.split(" "),o=>o.length>0);return r[0]+d(r.slice(1),o=>o[0].toUpperCase()+o.substring(1)).join("")}function wt(e,t,n){h(n)?n=t.columns:O(n)&&(n=[n]);let r={};g(n,i=>{m(O(i),"You must pass either a string or a one-dimensional array of strings into the `getDummies` (AKA `oneHotEncode`) method!");let a=t.columns.indexOf(i);m(a>-1,`The given DataFrame does not have a column called "${i}"!`);let s=d(t.values,p=>p[a]),u=R(P(s));g(s,p=>{g(u,c=>{let y=i+"_"+ze(c.toString());r[y]||(r[y]=[]),p===c?r[y].push(1):r[y].push(0)})})});let o=new e(r);return o.index=t.index,o}function Ct(e,t,n){let r=e.shape;h(t)&&(t=T(0,r[0]).toArray()),h(n)&&(n=T(0,r[1]).toArray()),l(t)&&(t=[t]),l(n)&&(n=[n]),m(f(t)&&f(n),"The `rowIndices` and `colIndices` parameters must be 1-dimensional arrays of whole numbers."),m(v(t).length===1&&v(n).length===1,"The `rowIndices` and `colIndices` parameters must be 1-dimensional arrays of whole numbers."),m(t.length>0,"The `rowIndices` array must contain at least one index."),m(n.length>0,"The `colIndices` array must contain at least one index."),g(t,a=>{m(J(a),"The `rowIndices` and `colIndices` parameters must be 1-dimensional arrays of whole numbers."),m(a<e.index.length,`The row index ${a} is out of bounds.`)}),g(n,a=>{m(J(a),"The `rowIndices` and `colIndices` parameters must be 1-dimensional arrays of whole numbers."),m(a<e.columns.length,`The column index ${a} is out of bounds.`)});let o=d(t,a=>e.index[a]),i=d(n,a=>e.columns[a]);return e.getSubsetByNames(o,i)}function Jt(e,t,n,r,o){h(r)&&(r=n.index),h(o)&&(o=n.columns),O(r)&&(r=[r]),O(o)&&(o=[o]),m(f(r)&&f(o),"The `rows` and `cols` parameters must be 1-dimensional arrays of strings."),m(v(r).length===1&&v(o).length===1,"The `rows` and `cols` parameters must be 1-dimensional arrays of strings."),m(r.length>0,"The `rows` array must contain at least one row name."),m(o.length>0,"The `cols` array must contain at least one column name."),g(r,s=>{m(O(s),"The `rows` and `cols` parameters must be 1-dimensional arrays of strings."),m(n.index.indexOf(s)>-1,`The row name "${s}" does not exist in the list of rows.`)}),g(o,s=>{m(O(s),"The `rows` and `cols` parameters must be 1-dimensional arrays of strings."),m(n.columns.indexOf(s)>-1,`The column name "${s}" does not exist in the list of columns.`)});let i=d(r,s=>d(o,u=>n.values[n.index.indexOf(s)][n.columns.indexOf(u)]));if(r.length===1&&o.length===1)return i[0][0];if(r.length===1){let s=new t(i[0]);return s.name=r[0],s.index=o,s}if(o.length===1){let s=new t(d(i,u=>u[0]));return s.name=o[0],s.index=r,s}let a=new e(i);return a.columns=o,a.index=r,a}function Rt(e,t,n){function r(w,D){return O(w)&&w.length>D?w.substring(0,D-3)+"...":w}if(n.isEmpty)return console.table({}),console.log("Shape:",[0,0],`
|
|
15
|
+
`),n;let o=typeof window>"u"?20:10,i=Math.floor(o/2),a=4,s=Math.floor(a/2),u=o>n.index.length?null:T(0,i).toArray().concat(T(n.index.length-i,n.index.length).toArray()),p=a>n.columns.length?null:T(0,s).toArray().concat(T(n.columns.length-s,n.columns.length).toArray()),c=n.get(u,p);c instanceof t&&(n.shape[0]===1?(c=new e([c.values]),c.index=n.index,c.columns=new t(n.columns).get(p).values):n.shape[1]===1&&(c=new e([c.values]).transpose(),c.index=new t(n.index).get(u).values,c.columns=n.columns)),o<=n.index.length&&(c._index.splice(i,0,"..."),c._values.splice(i,0,T(0,c.columns.length).map(()=>"..."))),a<=n.columns.length&&(c._columns.splice(s,0,"..."),c._values=d(c._values,w=>(w.splice(s,0,"..."),w)));let y=28;return c instanceof t?(c.values=d(c.values,w=>r(w,y)),c.name=r(c.name,y),c.index=d(c.index,w=>r(w,y))):(c.values=d(c.values,w=>d(w,D=>r(D,y))),c.columns=d(c.columns,w=>r(w,y)),c.index=d(c.index,w=>r(w,y))),console.table(c.toDetailedObject()),console.log("Shape:",n.shape,`
|
|
16
|
+
`),n}function Yt(e,t){let n=t?e:e.copy(),r=(n.index.length-1).toString().length;return n.index=T(0,e.shape[0]).map(o=>"row"+o.toString().padStart(r,"0")),n}function X(e,t){if(N(e)||b(e))return X(e.values,t);m(f(e),"The `product` function only works on arrays, Series, and DataFrames!");try{if(e.length===0)return NaN;let n=x(e),r=!1,o=1;for(let i of n){if(!l(i))if(t)i=1;else return NaN;typeof i=="bigint"&&(r=!0,i=Number(i)),o*=i}if(r)try{return BigInt(o)}catch{}return o}catch{return NaN}}function $t(e){return ft(e)&&e>0}function et(e,t){if(N(e)||b(e))return et(e.values,t);if(m(f(e),"The first argument passed into the `reshape` function must be an array!"),l(t)&&(t=[t]),m(f(t),"The second argument passed into the `reshape` function must be a whole number or a one-dimensional array of whole numbers!"),m(v(t).length===1,"The first argument passed into the `reshape` function must be a whole number or a one-dimensional array of whole numbers!"),t=d(t,i=>(typeof i=="bigint"&&(i=Number(i)),m($t(i),"The first argument passed into the `reshape` function must be a whole number or a one-dimensional array of whole numbers!"),Number(i))),t.length===0)return x(e);let n=x(e);if(t.length===1&&t[0]===n.length)return n;m(X(t)===n.length,"The new shape doesn't match the number of values available in `x` (the first argument passed into the `reshape` function)!");let r=[],o=Math.floor(n.length/t[0]);for(let i=0;i<t[0];i++){let a=n.slice(i*o,(i+1)*o);r.push(et(a,t.slice(1)))}return r}var qt=Math.pow(2,64),A=[];Vt(Math.floor(Math.random()*qt));function Ce(e,t){e=j(e);function n(){e+=j("0x9e3779b97f4a7c15");let o=I(e);return o=(o^o>>BigInt(30))*j("0xbf58476d1ce4e5b9"),o=(o^o>>BigInt(27))*j("0x94d049bb133111eb"),o^o>>BigInt(31)}let r=[];for(let o=0;o<t;o++)r.push(n());return r}function j(e){return BigInt.asUintN(64,BigInt(e))}function Kt(e,t){return e=j(e),t=BigInt(t),j(j(e<<t)|j(e>>j(BigInt(64)-t)))}function Vt(e){if(typeof e=="bigint"&&(e=Number(e)),h(e))return I(A);{m(l(e),"If passing a value into the `seed` function, then that value must be an integer!");let t=Ce(Math.floor(e),4);A[0]=t[0],A[1]=t[1],A[2]=t[2],A[3]=t[3]}}function Lt(){let e=j(Kt(A[0]+A[3],23)+A[0]),t=j(A[1]<<BigInt(17));return A[2]=j(A[2]^A[0]),A[3]=j(A[3]^A[1]),A[1]=j(A[1]^A[2]),A[0]=j(A[0]^A[3]),A[2]=j(A[2]^t),A[3]=Kt(A[3],45),Math.floor(Number(e))/qt}function G(e){return h(e)?Lt():(f(e)||(e=[e]),et(d(E(X(e)),Lt),e))}function rt(e){if(N(e)||b(e))return e.shuffle(...Object.values(arguments).slice(1));m(f(e),"The `shuffle` function only works on arrays, Series, and DataFrames!");let t=[],n=e.slice();for(let r=0;r<e.length;r++){let o=Math.floor(G()*n.length);t.push(n.splice(o,1)[0])}return t}function Gt(e,t){return h(t)&&(t=0),m(t===0||t===1,"The `axis` parameter to the `shuffle` must be 0, 1, or undefined."),e.get(t===0?rt(e.index):null,t===1?rt(e.columns):null)}function nt(e){return typeof e=="boolean"}function Wt(e,t,n){return _(t)?Je(e,t,n):Re(e,t,n)}function Je(e,t,n){if(n=h(n)?0:n,m(_(t),"When sorting a DataFrame using a function, the first argument to the `sort` method must be a function!"),m(l(n),"When sorting a DataFrame using a function, the second argument to the `sort` method must be null, undefined, 0, or 1 to indicate the axis along which the data should be sorted! An axis of 0 means that the rows will be sorted relative to each other, whereas an axis of 1 means that the columns will be sorted relative to each other."),n===0){let r=R(e.index,(o,i)=>t(e.get(o,null),e.get(i,null)));return e.get(r,null)}else{let r=R(e.columns,(o,i)=>t(e.get(null,o),e.get(null,i)));return e.get(null,r)}}function Re(e,t,n){let r=e.copy(),o=G().toString();r=r.assign(o,r.index),h(t)&&(t=[o],n=[!0]),(l(t)||O(t))&&(t=[t],(nt(n)||O(n))&&(n=[n])),m(f(t),"The first parameter of the `sort` method must be (1) a string or index representing a column name or index, respectively; (2) a 1-dimensional array of strings and/or indices; or (3) null."),m(v(t).length===1,"The first parameter of the `sort` method must be (1) a string or index representing a column name or index, respectively; (2) a 1-dimensional array of strings and/or indices; or (3) null."),h(n)&&(n=T(0,t.length).map(()=>!0)),m(f(n),"The second parameter of the `sort` method must be (1) a string or boolean representing the sort direction ('ascending' / 'descending', or true / false); (2) a 1-dimensional array of strings and/or booleans; or (3) null."),m(v(n).length===1,"The second parameter of the `sort` method must be (1) a string or boolean representing the sort direction ('ascending' / 'descending', or true / false); (2) a 1-dimensional array of strings and/or booleans; or (3) null."),m(t.length===n.length,"The arrays passed into the `sort` method must be equal in length."),t=d(t,a=>{if(m(O(a)||l(a),"Column references can either be column names (as strings) or column indices (as whole numbers)."),O(a)){let s=r.columns.indexOf(a);return m(s>-1,`The column "${a}" does not exist!`),s}if(l(a))return m(J(a),"Column indices must be whole numbers!"),m(a<r.columns.length,`The index ${a} is out of bounds!`),a}),n=d(n,a=>{if(m(O(a)||nt(a),"Direction references can either be strings ('ascending' or 'descending') or booleans (true or false)."),O(a)){let s=a.trim().toLowerCase();return m(s==="ascending"||s==="descending","Direction references can either be strings ('ascending' or 'descending') or booleans (true or false)."),s==="ascending"}if(nt(a))return a}),r.values=R(r.values,(a,s)=>{let u=0;for(;a[t[u]]===s[t[u]]&&u<t.length;)u++;let p=n[u];if(a[t[u]]===s[t[u]])return 0;if(a[t[u]]<s[t[u]])return p?-1:1;if(a[t[u]]>s[t[u]])return p?1:-1});let i=r.columns.indexOf(o);return r.index=d(r.values,a=>a[i]),r=r.dropColumns(o),r}function Ht(e,t){h(t)?t=0:m(t===0||t===1,"The axis parameter of the `toDetailedObject` method must be undefined, 0, or 1. An axis of 0 indicates that the returned object should be organized first by rows and then by columns. An axis of 1 indicates that the returned object should be organized first by columns and then by rows.");let n={};return t===0?g(e.index,(r,o)=>{let i={};g(e.columns,(a,s)=>{i[a]=e.values[o][s]}),n[r]=i}):g(e.columns,(r,o)=>{let i={};g(e.index,(a,s)=>{i[a]=e.values[s][o]}),n[r]=i}),n}function pt(e,t){return JSON.stringify(e.toObject(t))}async function Xt(e,t){return JSON.parse(pt(e,t))}function Qt(e){let t={};return g(e.columns,n=>{t[n]=e.get(n).values}),t}function Y(e){if(N(e)||b(e)){let n=e.copy();return n.values=Y(n.values),n.index=Y(n.index),n}m(f(e),"The `reverse` function only works on arrays, Series, and DataFrames!");let t=[];for(let n=e.length-1;n>=0;n--)t.push(e[n]);return t}function C(e){if(N(e)||b(e))return e.transpose();m(f(e),"The `transpose` function only works on arrays, Series, and DataFrames!");let t=v(e);if(m(t.length<=2,"I'm not smart enough to know how to transpose arrays that have more than 2 dimensions. Sorry for the inconvenience! Please only pass 1- or 2-dimensional arrays into the `transpose` function!"),t.length===1)return Y(e);if(t.length===2){let n=E(Y(t));for(let r=0;r<t[0];r++)for(let o=0;o<t[1];o++)n[o][r]=e[r][o];return n}}function Ot(e,t,n){if(b(n))return new e(t.values.concat(n.values));if(f(n)){let r=v(n);m(r.length===1&&!Q(r),"Only vectors can be appended to Series!");let o=t.copy();return g(n,(i,a)=>{o._values.push(i),o._index.push("item"+(t.values.length+a))}),o}return Ot(t,[n])}function Zt(e,t){m(_(t),"The parameter to the `apply` method must be a function.");let n=e.copy();return n._values=d(n._values,(r,o)=>t(r,o)),n}function te(e){let t=e.copy(),n=[];return t._values=F(t.values,(r,o)=>h(r)?!1:(n.push(t.index[o]),!0)),t._index=n,t}function ee(e,t){let n=[],r=[];g(t.values,(i,a)=>{l(i)&&(r.push(i),n.push(t.index[a]))});let o=new e(r);return o.name=t.name,o.index=n,o}function re(e,t,n){let r=t.copy(),o=I(r.index),i=[],a=F(r.values,(s,u)=>{let p=n(s,u,r.values);return p||i.push(r.index[u]),p});return g(i,s=>{o.splice(o.indexOf(s),1)}),a.length===0?(r=new e,r.name=t.name,r):(r.values=a,r.index=o,r)}function ne(e,t){(O(t)||l(t))&&(t=[t]);for(let r in t)typeof t[r]=="bigint"&&(t[r]=Number(t[r]));let n=P(d(t||[],r=>typeof r));return m(n.length<=2,"Only whole numbers and/or strings are allowed in `get` arrays!"),n.length===1&&m(n[0]==="string"||n[0]==="number","Only whole numbers and/or strings are allowed in `get` arrays!"),n.length===2&&(m(n.indexOf("string")>-1,"Only whole numbers and/or strings are allowed in `get` arrays!"),m(n.indexOf("number")>-1,"Only whole numbers and/or strings are allowed in `get` arrays!")),h(t)||(t=d(t,r=>{if(typeof r=="string")return m(e.index.indexOf(r)>-1,`Index "${r}" does not exist!`),r;if(typeof r=="number")return m(r>=0,`Index ${r} is out of bounds!`),m(Math.floor(r)===r,"Indices must be integers!"),m(r<e.index.length,`Index ${r} is out of bounds!`),e.index[r]})),e.getSubsetByNames(t)}function oe(e,t){let n=e.shape;h(t)&&(t=T(0,n[0]).toArray()),m(f(t),"The `indices` array must be 1-dimensional array of whole numbers."),m(v(t).length===1,"The `indices` array must be a 1-dimensional array of whole numbers."),m(t.length>0,"The `indices` array must contain at least one index."),g(t,o=>{m(J(o),"The `indices` array must be a 1-dimensional array of whole numbers."),m(o<e.index.length,`The row index ${o} is out of bounds.`)});let r=d(t,o=>e.index[o]);return e.getSubsetByNames(r)}function ie(e,t,n){h(n)&&(n=t.index),m(f(n),"The `indices` array must be a 1-dimensional array of strings."),m(v(n).length===1,"The `indices` array must be a 1-dimensional array of strings."),m(n.length>0,"The `indices` array must contain at least one index name."),g(n,i=>{m(O(i),"The `indices` array must contain only strings."),m(t.index.indexOf(i)>-1,`The name "${i}" does not exist in the index.`)});let r=d(n,i=>t.values[t.index.indexOf(i)]);if(r.length===1)return r[0];let o=new e(r);return o.index=n,o.name=t.name,o}function se(e){let t=e.copy(),n=typeof window>"u"?20:10;if(t.index.length>n){t=t.get(T(0,n/2).toArray().concat(T(t.index.length-n/2,t.index.length).toArray()));let o=I(t.index);o.splice(Math.floor(o.length/2),0,"..."),t.values.push("..."),t.index.push("..."),t=t.get(o)}let r={};return g(t.values,(o,i)=>{let a={};a[t.name]=o,r[t.index[i]]=a}),console.table(r),console.log("Shape:",e.shape,`
|
|
17
|
+
`),e}function me(e){let t=e.copy();return t.get(rt(t.index))}function ae(e,t,n){n=n||((u,p)=>u<p?-1:1),m(h(n)||_(n),"You must pass undefined, null, or a comparison function as the second argument to the `sort` method!");let r=C([t.values,t.index]),o=R(r,(u,p)=>n(u[0],p[0])),i=[],a=[];g(o,u=>{i.push(u[0]),a.push(u[1])});let s=new e;return s._values=i,s._index=a,s.name=t.name,s}function ue(e,t){let n=C([t.values,t.index]);n=C(R(n,(o,i)=>{if(o[1]===i[1])return 0;if(o[1]<i[1])return-1;if(o[1]>i[1])return 1}));let r=new e(n[0]);return r.index=n[1],r.name=t.name,r}function fe(e){let t={};return t[e.name]={},g(e.index,(n,r)=>{t[e.name][n]=e.values[r]}),t}var le=Symbol.for("@jrc03c/js-math-tools/series");function pe(e){class t{static[Symbol.hasInstance](r){try{return!!r._symbol&&r._symbol===le}catch{return!1}}constructor(r){if(this.name="data",Object.defineProperty(this,"_symbol",{configurable:!1,enumerable:!1,writable:!1,value:le}),Object.defineProperty(this,"_values",{value:[],configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(this,"values",{configurable:!0,enumerable:!0,get(){return this._values},set(o){m(f(o),"The new values must be a 1-dimensional array!");let i=v(o);if(m(i.length===1,"The new array of values must be 1-dimensional!"),i[0]<this._index.length)this._index=this._index.slice(0,i[0]);else if(i[0]>this._index.length){let a=(o.length-1).toString().length;this._index=this._index.concat(T(this._index.length,i[0]).map(s=>"item"+s.toString().padStart(a,"0")))}this._values=o}}),Object.defineProperty(this,"_index",{value:[],configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(this,"index",{configurable:!0,enumerable:!0,get(){return this._index},set(o){m(f(o),"The new index must be a 1-dimensional array of strings!"),m(o.length===this.shape[0],"The new index must be the same length as the old index!"),m(v(o).length===1,"The new index must be a 1-dimensional array of strings!"),g(o,i=>{m(O(i),"All of the row names must be strings!")}),this._index=o}}),r){if(r instanceof t)this.name=r.name,this.values=I(r.values),this.index=I(r.index);else if(f(r)){let o=v(r);m(o.length===1,"When passing an array into the constructor of a Series, the array must be 1-dimensional!"),this.values=r}else if(r instanceof Object){let o=d(Object.keys(r).concat(Object.getOwnPropertySymbols(r)),s=>s.toString());m(o.length===1,"When passing an object into the constructor of a Series, the object must have only 1 key-value pair, where the key is the name of the data and the value is the 1-dimensional array of values!");let i=o[0],a=r[i];m(v(a).length===1,"When passing an object into the constructor of a Series, the object must have only 1 key-value pair, where the key is the name of the data and the value is the 1-dimensional array of values!"),this.name=i,this.values=a.slice()}}}get shape(){return v(this.values)}get length(){return this.shape[0]}get isEmpty(){return F(this.values,r=>!h(r)).length===0}clear(){let r=this.copy();return g(r.values,(o,i)=>{r.values[i]=void 0}),r}get(r){return ne(this,r)}getSubsetByNames(r){return ie(t,this,r)}getSubsetByIndices(r){return oe(this,r)}loc(r){return this.getSubsetByNames(r)}iloc(r){return this.getSubsetByIndices(r)}reverse(){let r=new t(Y(this.values));return r.index=Y(this.index),r.name=this.name,r}resetIndex(){let r=this.copy(),o=(r.index.length-1).toString().length;return r.index=T(0,this.shape[0]).map(i=>"item"+i.toString().padStart(o,"0")),r}copy(){let r=new t;return r._values=I(this.values),r._index=I(this.index),r.name=this.name,r}append(r){return Ot(t,this,r)}apply(r){return Zt(this,r)}concat(r){return this.append(r)}dropMissing(r,o){return te(this,r,o)}dropNaN(){return ee(t,this)}toObject(){return fe(this)}print(){return se(this)}shuffle(){return me(this)}sort(r){return ae(t,this,r)}sortByIndex(){return ue(t,this)}filter(r){return re(t,this,r)}toDataFrame(){let r=new e(C([this.values]));return r.columns=[this.name],r.index=this.index,r}transpose(){let r=this.copy();return r.values=Y(r.values),r.index=Y(r.index),r}getDummies(){return this.toDataFrame().getDummies()}oneHotEncode(){return this.getDummies()}}return t}var ce=Symbol.for("@jrc03c/js-math-tools/dataframe");function ct(e){let t="abcdefghijklmnopqrstuvwxyz1234567890",n="";for(let r=0;r<e;r++)n+=t[Math.floor(G()*t.length)];return n}var K=class e{static[Symbol.hasInstance](t){try{return!!t._symbol&&t._symbol===ce}catch{return!1}}constructor(t){if(Object.defineProperty(this,"_symbol",{configurable:!1,enumerable:!1,writable:!1,value:ce}),Object.defineProperty(this,"_values",{value:[],configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(this,"values",{configurable:!0,enumerable:!0,get(){return this._values.length===0||!h(this._values[0])&&this._values[0].length===0?[[]]:this._values},set(n){m(f(n),"The new values must be a 2-dimensional array!");let r=v(n);if(m(r.length===2,"The new array of values must be 2-dimensional!"),r[0]<this._index.length)this._index=this._index.slice(0,r[0]);else if(r[0]>this._index.length){let o=(r[0]-1).toString().length;this._index=this._index.concat(T(this._index.length,r[0]).map(i=>"row"+i.toString().padStart(o,"0")))}if(r[1]<this._columns.length)this._columns=this._columns.slice(0,r[1]);else if(r[1]>this._columns.length){let o=(r[1]-1).toString().length;this._columns=this._columns.concat(T(this._columns.length,r[1]).map(i=>"col"+i.toString().padStart(o,"0")))}this._values=n}}),Object.defineProperty(this,"_columns",{value:[],configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(this,"columns",{configurable:!0,enumerable:!0,get(){return this._columns},set(n){m(f(n),"The new columns list must be a 1-dimensional array of strings!"),m(this.isEmpty||n.length===this.shape[1],"The new columns list must be the same length as the old columns list!"),m(v(n).length===1,"The new columns list must be a 1-dimensional array of strings!"),n=d(n,o=>(typeof o!="string"&&(o=JSON.stringify(o)||o.toString()),o.trim().length===0?"untitled_"+ct(8):o.trim()));let r=(()=>{let o=it(n),i={};return g(o.values,a=>{i[a]=o.get(a)}),i})();n=d(n,o=>r[o]>1?o+"_"+ct(8):o),this._columns=n}}),Object.defineProperty(this,"_index",{value:[],configurable:!0,enumerable:!1,writable:!0}),Object.defineProperty(this,"index",{configurable:!0,enumerable:!0,get(){return this._index},set(n){m(f(n),"The new index must be a 1-dimensional array of strings!"),m(this.isEmpty||n.length===this.shape[0],"The new index must be the same length as the old index!"),m(v(n).length===1,"The new index must be a 1-dimensional array of strings!"),n=d(n,o=>(typeof o!="string"&&(o=JSON.stringify(o)||o.toString()),o.trim().length===0?"untitled_"+ct(8):o.trim()));let r=(()=>{let o=it(n),i={};return g(o.values,a=>{i[a]=o.get(a)}),i})();n=d(n,o=>r[o]>1?o+"_"+ct(8):o),this._index=n}}),m(h(t)||k(t)||f(t),"The `data` passed into the constructor of a DataFrame must be either (1) an object where the key-value pairs are (respectively) column names and 1-dimensional arrays of values, or (2) a 2-dimensional array of values."),t)if(t instanceof e)this.values=I(t.values),this.columns=I(t.columns),this.index=I(t.index);else if(f(t)){let n=v(t);m(n.length===2,"The `data` array passed into the constructor of a DataFrame must be 2-dimensional!"),m(!V(t),"The 2-dimensional array passed into the constructor of a DataFrame must not contain sub-arrays (i.e., rows) of different lengths!"),this.values=t}else{this._columns=d(Object.keys(t).concat(Object.getOwnPropertySymbols(t)),s=>s.toString());let n=[],r=null,o=null;g(this._columns,s=>{h(o)&&(r=s,o=t[s].length),m(t[s].length===o,`The object passed into the DataFrame constructor contains arrays of different lengths! The key "${r}" points to an array containing ${o} items, and the key "${s}" points to an array containing ${t[s].length} items.`),o=t[s].length;let u=t[s];n.push(u)}),this._values=C(n);let i=v(this.values),a=(i[0]-1).toString().length;this._index=T(0,i[0]).map(s=>"row"+s.toString().padStart(a,"0"))}}get shape(){return v(this.values)}get length(){return this.shape[0]}get width(){return this.shape[1]}get rows(){return this.index}set rows(t){this.index=t}get isEmpty(){return this.values.length===0||this.values.every(t=>t.length===0)}clear(){let t=new e(E(this.shape));return t.columns=this.columns.slice(),t.index=this.index.slice(),t}get(t,n){if(arguments.length===0)return this;if(arguments.length===1)try{return this.get(null,t)}catch{return this.get(t,null)}return zt(this,t,n)}getSubsetByNames(t,n){return Jt(e,U,this,t,n)}getSubsetByIndices(t,n){return Ct(this,t,n)}getDummies(t){return wt(e,this,t)}oneHotEncode(t){return wt(e,this,t)}transpose(){let t=new e(C(this.values));return t.columns=this.index.slice(),t.index=this.columns.slice(),t}get T(){return this.transpose()}resetIndex(t){return Yt(this,t)}copy(){return Mt(e,this)}assign(t,n){return jt(e,U,this,t,n)}apply(t,n){return xt(e,U,this,t,n)}dropMissing(t,n,r){return Bt(e,U,this,t,n,r)}dropNaN(t,n,r){return Ut(e,this,t,n,r)}drop(t,n){return Et(e,U,this,t,n)}dropColumns(t){return this.drop(null,t)}dropRows(t){return this.drop(t,null)}toDetailedObject(t){return Ht(this,t)}toObject(){return Qt(this)}toJSONString(t){return pt(this,t)}saveAsJSON(t,n){return Xt(this,t,n)}print(){return Rt(e,U,this)}sort(t,n){return Wt(this,t,n)}sortByIndex(){return this.sort()}filter(t,n){return kt(e,U,this,t,n)}shuffle(t){return Gt(this,t)}append(t,n){return St(this,t,n)}concat(t,n){return this.append(t,n)}join(t,n){return this.append(t,n)}toString(){return JSON.stringify(this)}},U=pe(K);function mt(e,t){return B(e,{shouldDropNaNs:t}).max}function S(e){return m(_(e),"You must pass a function into the `vectorize` function!"),function t(){let n,r,o=[],i=[],a=d(F(Object.keys(arguments),s=>{let u=arguments[s];return f(u)?!0:b(u)?(n=!0,o.push(u),!0):N(u)?(r=!0,i.push(u),!0):!1}),s=>arguments[s]);if(g(a.slice(0,-1),(s,u)=>{m(z(f(s)?v(s):s.shape,f(a[u+1])?v(a[u+1]):a[u+1].shape),`When passing multiple arrays into the \`${e.name}\` function, all of the arrays must have the same shape!`)}),a.length>0){let s=mt(d(a,p=>p.length?p.length:p.values.length)),u=T(0,s).map(p=>{let c=d(Object.keys(arguments),y=>f(arguments[y])?arguments[y][p]:b(arguments[y])||N(arguments[y])?arguments[y].values[p]:arguments[y]);return t(...c)});if(r)try{if(i.length===1&&z(v(i[0]),v(u))){let p=new K(u);return p.index=i[0].index.slice(),p.columns=i[0].columns.slice(),p}else return new K(u)}catch{return u}if(n)try{if(o.length===1&&o[0].length===u.length){let p=new U(u);return p.name=o[0].name,p.index=o[0].index.slice(),p}else return new U(u)}catch{return u}return u}else return e(...arguments)}}function Ye(e){try{return l(e)?typeof e=="bigint"?e<0?-e:e:Math.abs(e):NaN}catch{return NaN}}var ht=S(Ye);function $e(){try{let e=0,t=!1,n=Object.values(arguments);for(let r of n){if(!l(r))return NaN;typeof r=="bigint"&&(t=!0,r=Number(r)),e+=r}if(t)try{return BigInt(e)}catch{}return e}catch{return NaN}}var Tt=S($e);function Ke(e,t){try{return t(e)}catch{return NaN}}var dt=S(Ke);function Le(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.acos(e)):NaN}catch{return NaN}}var qe=S(Le);function Ve(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.asin(e)):NaN}catch{return NaN}}var Ge=S(Ve);function We(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.atan(e)):NaN}catch{return NaN}}var He=S(We);function Qe(e){try{return l(e)?typeof e=="bigint"?e:Math.ceil(e):NaN}catch{return NaN}}var Ze=S(Qe);function tr(e,t){try{if(!l(e))return NaN;if(typeof e=="bigint")return e;if(h(t))t=1e-10;else if(!l(t))return NaN;return ht(e)<t?0:e}catch{return NaN}}var er=S(tr);function Dt(e){if(N(e)||b(e)){let t=e.copy();return t.values=Dt(t.values),t}if(f(e))return d(e,t=>Dt(t));try{let t=JSON.parse(e);return l(t)?typeof t=="bigint"?Number(t):t>=0?Math.floor(t):Math.ceil(t):NaN}catch{return NaN}}var L=S(Dt);function he(e,t,n){try{return l(e)?l(t)?l(n)?typeof e=="bigint"?BigInt(he(L(e),t,n)):e<t?t:e>n?n:e:NaN:NaN:NaN}catch{return NaN}}var rr=S(he);function sr(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.cos(e)):NaN}catch{return NaN}}var mr=S(sr);var ar=Object.freeze({boolean:"boolean",date:"date",null:"null",number:"number",object:"object",string:"string"});function de(e,t){try{if(!l(e))return NaN;if(!l(t))return NaN;if(typeof e=="bigint"||typeof t=="bigint"){let n=de(Number(e),Number(t));try{return BigInt(n)}catch{return n}}return Math.pow(e,t)}catch{return NaN}}var _t=S(de);function ge(e){try{if(!l(e))return NaN;if(typeof e=="bigint"){let t=ge(Number(e));try{return BigInt(t)}catch{return t}}return Math.sqrt(e)}catch{return NaN}}var ye=S(ge);function ur(){try{let e=Object.values(arguments);if(e.length===0)return NaN;let t=!1,n=1;for(let r of e){if(!l(r))return NaN;typeof r=="bigint"&&(t=!0,r=Number(r)),n*=r}if(t)try{return BigInt(n)}catch{}return n}catch{return NaN}}var be=S(ur);function pr(e){try{if(!l(e))return NaN;if(typeof e=="bigint"){if(e===0n)return 1n;e=Number(e)}return Math.exp(e)}catch{return NaN}}var cr=S(pr);function It(e){try{return typeof e=="bigint"?BigInt(It(L(e))):e!==L(e)?NaN:e<=1?1:e*It(e-1)}catch{return NaN}}var hr=S(It);function dr(e){try{if(e==="Infinity")return 1/0;if(e==="-Infinity")return-1/0;let t=JSON.parse(e);return l(t)?t:NaN}catch{return NaN}}var gr=S(dr);function yr(e){try{return l(e)?typeof e=="bigint"?e:Math.floor(e):NaN}catch{return NaN}}var br=S(yr);function Se(e,t,n){try{if(!l(e))return NaN;if(!l(t))return NaN;if(!l(n))return NaN;if(typeof e=="bigint"||typeof t=="bigint"){let r=Se(Number(e),Number(t),n);try{return BigInt(r)}catch{return r}}return n*(t-e)+e}catch{return NaN}}var wr=S(Se);function we(e,t){try{if(t=h(t)?Math.E:t,!l(e))return NaN;if(!l(t))return NaN;if(typeof e=="bigint"||typeof t=="bigint"){let n=we(Number(e),Number(t));try{return BigInt(n)}catch{return n}}return Math.log(e)/Math.log(t)}catch{return NaN}}var Or=S(we);function Oe(e,t){try{if(!l(e))return NaN;if(!l(t))return NaN;if(typeof e=="bigint"||typeof t=="bigint"){let n=Oe(Number(e),Number(t));try{return BigInt(n)}catch{return n}}return e%t}catch{return NaN}}var Tr=S(Oe);var Mg=S((e,t,n,r,o)=>{try{let i=!1;for(let p of[e,t,n,r,o]){if(!l(p))return NaN;typeof p=="bigint"&&(i=!0)}i&&(e=Number(e),t=Number(t),n=Number(n),r=Number(r),o=Number(o));let a=(o-r)*(e-t),s=n-t;if(s===0)return NaN;let u=a/s+r;if(i)try{return BigInt(u)}catch{}return u}catch{return NaN}});function _r(e){try{return l(e)?typeof e=="bigint"?e:Math.round(e):NaN}catch{return NaN}}var Ir=S(_r);function Te(e){try{return l(e)?typeof e=="bigint"?BigInt(Te(Number(e))):e<0?-1:e>0?1:0:NaN}catch{return NaN}}var Ar=S(Te);function Fr(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.sin(e)):NaN}catch{return NaN}}var xr=S(Fr);function Mr(e){try{return l(e)?(typeof e=="bigint"&&(e=Number(e)),Math.tan(e)):NaN}catch{return NaN}}var Er=S(Mr);var De=(()=>{let e=Math.random();class t{static new(r,o){if(r=r||{},typeof r!="object")throw new Error("The value passed into the `Data` constructor must be an object (or undefined)!");let i=new this(e),a=o?Object.keys(r).concat(Object.getOwnPropertySymbols(r)):Object.keys(i).concat(Object.getOwnPropertySymbols(i));for(let s=0;s<a.length;s++){let u=a[s];i[u]=I(r[u])??i[u]}return i}constructor(r){if(r!==e)throw new Error(`New \`${this.constructor.name}\` instances must be created using the \`${this.constructor.name}.new\` static method!`)}}return t})();globalThis.Data=De;})();
|
package/eslint.config.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { defineConfig } from "eslint/config"
|
|
2
|
+
import css from "@eslint/css"
|
|
3
|
+
import globals from "globals"
|
|
4
|
+
import js from "@eslint/js"
|
|
5
|
+
import json from "@eslint/json"
|
|
6
|
+
import markdown from "@eslint/markdown"
|
|
7
|
+
|
|
8
|
+
export default defineConfig([
|
|
9
|
+
{
|
|
10
|
+
files: ["**/*.{js,mjs,cjs}"],
|
|
11
|
+
plugins: { js },
|
|
12
|
+
extends: ["js/recommended"],
|
|
13
|
+
languageOptions: { globals: { ...globals.browser, ...globals.node } },
|
|
14
|
+
rules: {
|
|
15
|
+
"no-empty": ["error", { allowEmptyCatch: true }],
|
|
16
|
+
"no-unused-vars": ["error", { caughtErrors: "none" }],
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
files: ["**/*.json"],
|
|
21
|
+
plugins: { json },
|
|
22
|
+
language: "json/json",
|
|
23
|
+
extends: ["json/recommended"],
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
files: ["**/*.md"],
|
|
27
|
+
plugins: { markdown },
|
|
28
|
+
language: "markdown/commonmark",
|
|
29
|
+
extends: ["markdown/recommended"],
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
files: ["**/*.css"],
|
|
33
|
+
plugins: { css },
|
|
34
|
+
language: "css/css",
|
|
35
|
+
extends: ["css/recommended"],
|
|
36
|
+
},
|
|
37
|
+
])
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"dependencies": {
|
|
3
|
+
"@jrc03c/js-math-tools": "^0.0.104"
|
|
4
|
+
},
|
|
5
|
+
"devDependencies": {
|
|
6
|
+
"@eslint/css": "^0.14.1",
|
|
7
|
+
"@eslint/js": "^9.12.0",
|
|
8
|
+
"@eslint/json": "^0.14.0",
|
|
9
|
+
"@eslint/markdown": "^7.5.1",
|
|
10
|
+
"@jrc03c/fake-jest": "^0.0.21",
|
|
11
|
+
"@jrc03c/watch": "^0.0.18",
|
|
12
|
+
"esbuild": "^0.25.0",
|
|
13
|
+
"eslint": "^9.39.1",
|
|
14
|
+
"eslint-plugin-html": "^7.1.0",
|
|
15
|
+
"globals": "^15.11.0",
|
|
16
|
+
"prettier": "^3.7.1"
|
|
17
|
+
},
|
|
18
|
+
"main": "./src/index.mjs",
|
|
19
|
+
"module": "./src/index.mjs",
|
|
20
|
+
"name": "@jrc03c/data-class",
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "node build.mjs",
|
|
23
|
+
"pub": "npm version patch --force && npm publish --access=public",
|
|
24
|
+
"test": "npx fake-jest",
|
|
25
|
+
"watch": "node build.mjs --watch"
|
|
26
|
+
},
|
|
27
|
+
"type": "module",
|
|
28
|
+
"version": "0.0.2"
|
|
29
|
+
}
|
package/readme.md
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# intro
|
|
2
|
+
|
|
3
|
+
a struct-like class for storing data
|
|
4
|
+
|
|
5
|
+
# installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @jrc03c/data-class
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
# usage
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { Data } from "@jrc03c/data-class"
|
|
15
|
+
|
|
16
|
+
class PersonData extends Data {
|
|
17
|
+
age = 0
|
|
18
|
+
name = "Nobody"
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
console.log(PersonData.new())
|
|
22
|
+
// PersonData { age: 0, name: 'Nobody' }
|
|
23
|
+
|
|
24
|
+
console.log(PersonData.new({ age: 21 }))
|
|
25
|
+
// PersonData { age: 21, name: 'Nobody' }
|
|
26
|
+
|
|
27
|
+
console.log(PersonData.new({ name: "Alice" }))
|
|
28
|
+
// PersonData { age: 0, name: 'Alice' }
|
|
29
|
+
|
|
30
|
+
console.log(PersonData.new({ age: 21, name: "Alice" }))
|
|
31
|
+
// PersonData { age: 21, name: 'Alice' }
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
# why?
|
|
35
|
+
|
|
36
|
+
i made this little library for three main reasons:
|
|
37
|
+
|
|
38
|
+
first, i was tired of writing constructors in which i just copied properties from an options object onto an instance, like this:
|
|
39
|
+
|
|
40
|
+
```js
|
|
41
|
+
class SomeClass {
|
|
42
|
+
prop1 = "..."
|
|
43
|
+
prop2 = "..."
|
|
44
|
+
prop3 = "..."
|
|
45
|
+
// etc.
|
|
46
|
+
|
|
47
|
+
constructor(data) {
|
|
48
|
+
data = data ?? {}
|
|
49
|
+
this.prop1 = data.prop1 ?? this.prop1
|
|
50
|
+
this.prop2 = data.prop2 ?? this.prop2
|
|
51
|
+
this.prop3 = data.prop3 ?? this.prop3
|
|
52
|
+
// etc.
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
in other words, i wanted to be able to just do `new SomeClass(data)` and not have to write a constructor for it.
|
|
58
|
+
|
|
59
|
+
second, i wanted to be able to extend a constructor-less class to add various features like getters / setters, methods, and even constructors if necessary.
|
|
60
|
+
|
|
61
|
+
third, i wanted to be able to verify that an object has a particular interface without relying on typescript. it's much easier to do `x instanceof SomeClass` than to check individual properties. (to be clear, the `Data` class exported by this library doesn't expect or enforce any kind of structure on the data it receives. but such expectations or enforcements could easily be implemented in a subclass of `Data`.)
|
|
62
|
+
|
|
63
|
+
# api
|
|
64
|
+
|
|
65
|
+
## `Data`
|
|
66
|
+
|
|
67
|
+
### `Data.new(options, shouldIncludeAllProperties)` (static method)
|
|
68
|
+
|
|
69
|
+
creates and returns a new instance of `Data`.
|
|
70
|
+
|
|
71
|
+
if an options object (`options`) is passed as the first argument, then that object's properties will be used to overwrite any existing instance property values.
|
|
72
|
+
|
|
73
|
+
if a `true` value (`shouldIncludeAllProperties`) is passed as the second argument, then _all_ properties on the `options` object will be assigned to the instance. for example:
|
|
74
|
+
|
|
75
|
+
```js
|
|
76
|
+
console.log(Data.new({ hello: "world" }))
|
|
77
|
+
// Data {}
|
|
78
|
+
|
|
79
|
+
console.log(Data.new({ hello: "world" }, true))
|
|
80
|
+
// Data { hello: 'world' }
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
be aware that the options object passed into this method is copied before use. in probably 99.99% of cases, this shouldn't cause any problems. but there may be edge cases in which the copying process fails or the data is modified by the copying process in unexpected ways (e.g., to break circular references).
|
|
84
|
+
|
|
85
|
+
# creating subclasses
|
|
86
|
+
|
|
87
|
+
creating a subclass of `Data` is generally pretty straightforward:
|
|
88
|
+
|
|
89
|
+
```js
|
|
90
|
+
class PersonData extends Data {
|
|
91
|
+
age = 0
|
|
92
|
+
name = "Nobody"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(PersonData.new())
|
|
96
|
+
// PersonData { age: 0, name: 'Nobody' }
|
|
97
|
+
|
|
98
|
+
console.log(PersonData.new({ age: 21, name: "Alice" }))
|
|
99
|
+
// PersonData { age: 21, name: 'Alice' }
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
however, a complication arises when overriding the static `new` method while still expecting to use the superclass's `new` functionality. fortunately, it's a pretty easy complication to handle. all you have to do is re-bind the superclass's `new` method, like this:
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
class PersonData extends Data {
|
|
106
|
+
static new() {
|
|
107
|
+
const newTemp = Data.new.bind(this)
|
|
108
|
+
const out = newTemp(...arguments)
|
|
109
|
+
|
|
110
|
+
// do whatever you want here. for example:
|
|
111
|
+
if (typeof out.age !== "number" || out.age < 0) {
|
|
112
|
+
throw new Error("Ages must be non-negative numbers!")
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
if (typeof out.name !== "string" || out.name.length === 0) {
|
|
116
|
+
throw new Error("Names must be non-empty strings!")
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// then return the instance:
|
|
120
|
+
return out
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
age = 0
|
|
124
|
+
name = "Nobody"
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
keep in mind, too, that getters and setters can usually handle sanity checking and may be a bit more elegant (if not less verbose) than overriding the static `new` method.
|
|
129
|
+
|
|
130
|
+
# notes
|
|
131
|
+
|
|
132
|
+
**be aware that you can use neither the `Data` constructor nor any `Data` subclass constructors!** if you try to use them, you'll receive an error!
|
|
133
|
+
|
|
134
|
+
i designed things this way because there were subtle issues related to instance construction that greatly increased the complexity of creating subclasses of `Data` (at least as it was originally conceived). so, the best solution seemed to be to avoid the constructor altogether and to rely on a static method for instance creation. although it's perhaps a bit unorthodox, i'm happy with the result so far — though i'm also willing to revisit the issue if anyone knows any good solutions.
|
package/src/iife.mjs
ADDED
package/src/index.mjs
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { copy } from "@jrc03c/js-math-tools"
|
|
2
|
+
|
|
3
|
+
const Data = (() => {
|
|
4
|
+
const SECRET = Math.random()
|
|
5
|
+
|
|
6
|
+
class Data {
|
|
7
|
+
static new(data, shouldIncludeAllProperties) {
|
|
8
|
+
data = data || {}
|
|
9
|
+
|
|
10
|
+
if (typeof data !== "object") {
|
|
11
|
+
throw new Error(
|
|
12
|
+
"The value passed into the `Data` constructor must be an object (or undefined)!",
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const out = new this(SECRET)
|
|
17
|
+
|
|
18
|
+
const keys = shouldIncludeAllProperties
|
|
19
|
+
? Object.keys(data).concat(Object.getOwnPropertySymbols(data))
|
|
20
|
+
: Object.keys(out).concat(Object.getOwnPropertySymbols(out))
|
|
21
|
+
|
|
22
|
+
for (let i = 0; i < keys.length; i++) {
|
|
23
|
+
const key = keys[i]
|
|
24
|
+
out[key] = copy(data[key]) ?? out[key]
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return out
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
constructor(v) {
|
|
31
|
+
if (v !== SECRET) {
|
|
32
|
+
throw new Error(
|
|
33
|
+
`New \`${this.constructor.name}\` instances must be created using the \`${this.constructor.name}.new\` static method!`,
|
|
34
|
+
)
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return Data
|
|
40
|
+
})()
|
|
41
|
+
|
|
42
|
+
export { Data }
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { copy, isEqual } from "@jrc03c/js-math-tools"
|
|
2
|
+
import { Data } from "./index.mjs"
|
|
3
|
+
import { expect, test } from "@jrc03c/fake-jest"
|
|
4
|
+
|
|
5
|
+
test("Data", () => {
|
|
6
|
+
expect(() => new Data()).toThrow()
|
|
7
|
+
expect(() => new Data({ hello: "world" })).toThrow()
|
|
8
|
+
expect(() => Data.new()).not.toThrow()
|
|
9
|
+
expect(() => Data.new({ hello: "world" })).not.toThrow()
|
|
10
|
+
|
|
11
|
+
const a = { hello: "world" }
|
|
12
|
+
expect(isEqual(a, Data.new(a))).toBe(false)
|
|
13
|
+
expect(isEqual({}, Data.new(a))).toBe(true)
|
|
14
|
+
expect(isEqual(a, Data.new(a, true))).toBe(true)
|
|
15
|
+
expect(isEqual({}, Data.new(a, true))).toBe(false)
|
|
16
|
+
|
|
17
|
+
class PersonData extends Data {
|
|
18
|
+
age = 0
|
|
19
|
+
name = "Nobody"
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const b = { age: 21, name: "Alice Smith" }
|
|
23
|
+
expect(() => new PersonData()).toThrow()
|
|
24
|
+
expect(() => new PersonData(b)).toThrow()
|
|
25
|
+
expect(isEqual(b, PersonData.new(b))).toBe(true)
|
|
26
|
+
expect(PersonData.new({ age: 21 }).age).toBe(21)
|
|
27
|
+
expect(PersonData.new({ age: 21 }).name).toBe("Nobody")
|
|
28
|
+
expect(PersonData.new({ name: "Alice Smith" }).age).toBe(0)
|
|
29
|
+
expect(PersonData.new({ name: "Alice Smith" }).name).toBe("Alice Smith")
|
|
30
|
+
|
|
31
|
+
class EmployeeData extends PersonData {
|
|
32
|
+
title = "Worker"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const c = { age: 32, name: "Bob Jones", title: "Vicar" }
|
|
36
|
+
expect(() => new EmployeeData()).toThrow()
|
|
37
|
+
expect(() => new EmployeeData(c)).toThrow()
|
|
38
|
+
expect(isEqual(c, EmployeeData.new(c))).toBe(true)
|
|
39
|
+
expect(isEqual(b, EmployeeData.new(b))).toBe(false)
|
|
40
|
+
expect(isEqual(c, copy(EmployeeData.new(c)))).toBe(true)
|
|
41
|
+
expect(isEqual(c, structuredClone(EmployeeData.new(c)))).toBe(true)
|
|
42
|
+
|
|
43
|
+
class ProgramEmployeeData extends EmployeeData {
|
|
44
|
+
static new() {
|
|
45
|
+
const newTemp = EmployeeData.new.bind(this)
|
|
46
|
+
const out = newTemp(...arguments)
|
|
47
|
+
|
|
48
|
+
if (out.favoriteLanguages.length === 0) {
|
|
49
|
+
throw new Error("You must include at least one favorite language!")
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return out
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
favoriteLanguages = []
|
|
56
|
+
title = "Programmer"
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
expect(() => ProgramEmployeeData.new()).toThrow()
|
|
60
|
+
|
|
61
|
+
expect(() =>
|
|
62
|
+
ProgramEmployeeData.new({ favoriteLanguages: ["JavaScript"] }),
|
|
63
|
+
).not.toThrow()
|
|
64
|
+
|
|
65
|
+
const d = ProgramEmployeeData.new({ favoriteLanguages: ["Python"] })
|
|
66
|
+
expect(d instanceof ProgramEmployeeData).toBe(true)
|
|
67
|
+
expect(d.age).toBe(0)
|
|
68
|
+
expect(d.name).toBe("Nobody")
|
|
69
|
+
expect(d.title).toBe("Programmer")
|
|
70
|
+
expect(d.favoriteLanguages).toStrictEqual(["Python"])
|
|
71
|
+
})
|