diabetic-utils
Version:
Zero-bloat TypeScript utilities for diabetes data: glucose, A1C, conversions, time-in-range, and more.
2 lines • 10.6 kB
JavaScript
;function ee(e){return `${e.toFixed(1)}%`}function d(e){return typeof e=="number"&&Number.isFinite(e)&&e>0&&e<20}function ne(e,t){let n=t?.normalMax??5.7,i=t?.prediabetesMax??6.5;return d(e)?e<=n?"normal":e<=i?"prediabetes":"diabetes":"invalid"}function te(e,t=[6.5,7],n){let i=n?.min??t[0],o=n?.max??t[1];return d(e)&&e>=i&&e<=o}function re(e,t){if(!d(e)||!d(t))throw new Error("Invalid A1C value");return +(e-t).toFixed(2)}function oe(e){if(!Array.isArray(e)||e.length<2)return "insufficient data";let t=e[e.length-1]-e[0];return Math.abs(t)<.1?"stable":t>0?"increasing":"decreasing"}var O=405,g={VERY_SENSITIVE:1,NORMAL:2,EARLY_RESISTANCE:2.9},_=70,y=180,I=3.9,v=10,h=28.7,x=46.7,M=18.0182,m="mg/dL",f="mmol/L",F="#D32F2F",H="#388E3C",P="#4CAF50",V="#2E7D32",k="#FBC02D",Y="#F57C00",ue={LOW:F,NORMAL:H,ELEVATED:k,HIGH:Y,NORMAL_UP:P,NORMAL_DOWN:V},se={STEADY:"\u2192",RISING:"\u2197",FALLING:"\u2198",RAPIDRISE:"\u2191",RAPIDFALL:"\u2193"};function w(e){return typeof e=="object"&&e!==null&&"value"in e&&"unit"in e&&typeof e.value=="number"&&typeof e.unit=="string"}function N(e){return typeof e!="string"?false:/^\d+(\.\d+)?\s+(mg\/dL|mmol\/L)$/i.test(e.trim())}function W(e,t=m,n){let i=n?.mgdl??_,o=n?.mmoll??I;return t===m?e<i:e<o}function $(e,t=m,n){let i=n?.mgdl??y,o=n?.mmoll??v;return t===m?e>i:e>o}function fe(e,t=m,n){return W(e,t,n?.hypo)?"low":$(e,t,n?.hyper)?"high":"normal"}function T(e){if(!N(e))throw new Error('Invalid glucose string format. Use "100 mg/dL" or "5.5 mmol/L".');let n=e.trim().replace(/\s+/g," ").match(/^([\d.]+) (mg\/dL|mmol\/L)$/i),[,i,o]=n;return {value:parseFloat(i),unit:o.toLowerCase()==="mg/dl"?m:f}}function R(e,t){return typeof e=="number"&&Number.isFinite(e)&&e>0&&(t===m||t===f)}function E(e){return typeof e=="number"&&Number.isFinite(e)&&e>0&&e<1e3}function j(e,t){if(!R(e,m))throw new Error("Invalid fasting glucose value (must be a positive number in mg/dL)");if(!E(t))throw new Error("Invalid fasting insulin value (must be a positive number in \xB5IU/mL)");let n=e*t/405;return {value:n,interpretation:B(n)}}function B(e){return e<g.VERY_SENSITIVE?"Very insulin sensitive":e>=g.VERY_SENSITIVE&&e<g.NORMAL?"Normal insulin sensitivity":e>=g.NORMAL&&e<g.EARLY_RESISTANCE?"Early insulin resistance":"Significant insulin resistance"}function Me(e,t,n){if(!d(e))throw new Error("Invalid A1C value (must be a positive number < 20%)");if(!R(t,m))throw new Error("Invalid fasting glucose value (must be a positive number in mg/dL)");if(!E(n))throw new Error("Invalid fasting insulin value (must be a positive number in \xB5IU/mL)");let i=h*e-x,o=j(t,n),r=[];return t>i+20&&r.push("Fasting glucose is higher than estimated average glucose from A1C."),n<2&&t>110&&r.push("Low insulin with high glucose may indicate reduced insulin secretion."),{estimatedAverageGlucose:i,homaIR:o,flags:r,recommendation:r.length?"Some inconsistencies were detected in your markers. This may occur for various reasons including diet, stress, or lab variability. Always consult your healthcare provider for interpretation and guidance.":"Your markers appear consistent based on this informational analysis. This does not replace professional medical advice. Always consult your healthcare provider for interpretation and guidance.",disclaimer:"This tool is for informational and educational purposes only. It does not constitute medical advice, diagnosis, or treatment."}}function Ge(e){return +((e+x)/h).toFixed(2)}function Oe(e){return Math.round(e*h-x)}function _e(e){if(e<0)throw new Error("A1C must be positive");let t=Number((e*h-x).toFixed(10));return Math.round(t)}function ye(e,t=m){return +(((t===f?e*M:e)+46.7)/28.7).toFixed(2)}function Ie(e){return +(3.31+.02392*e).toFixed(2)}function ve(e,t){let n,i;if(w(e))n=e.value,i=e.unit;else if(typeof e=="string"){let r=T(e);n=r.value,i=r.unit;}else {if(!t)throw new Error("Unit is required when input is a number.");n=e,i=t;}if(![m,f].includes(i))throw new Error(`Unsupported glucose unit: ${i}`);if(n<=0||!Number.isFinite(n))throw new Error("Glucose value must be a positive number.");let o=i===f?1.57*n+3.5:.03*n+2.4;return parseFloat(o.toFixed(1))}function we(e){if(!Number.isFinite(e)||e<=0)throw new Error("Invalid glucose value");return +(e/M).toFixed(1)}function Ne(e){if(!Number.isFinite(e)||e<=0)throw new Error("Invalid glucose value");return Math.round(e*M)}function Te({value:e,unit:t}){if(!Number.isFinite(e)||e<=0)throw new Error("Invalid glucose value");if(![m,f].includes(t))throw new Error("Invalid unit");return t===m?{value:Math.round(e/M*10)/10,unit:f}:{value:Math.round(e*M),unit:m}}function Ce(e,t,n={}){let i=n.digits??0,o=n.suffix??true,r=e.toFixed(i);return o?`${r} ${t}`:r}function De(e,t=1){return `${e.toFixed(t)}%`}function Ue(e,t){if(isNaN(Date.parse(e)))throw new RangeError("Invalid ISO timestamp");return new Date(e).toLocaleString("en-US",{timeZone:t,year:"numeric",month:"short",day:"2-digit",hour:"2-digit",minute:"2-digit"})}function He(e,t){if(e.length===0)return {inRange:0,belowRange:0,aboveRange:0};let n=0,i=0,o=0;for(let s of e)s.value<t.min?i++:s.value>t.max?o++:n++;let r=e.length;return {inRange:+(n/r*100).toFixed(1),belowRange:+(i/r*100).toFixed(1),aboveRange:+(o/r*100).toFixed(1)}}function Pe(e){return `In Range: ${e.inRange}%, Below: ${e.belowRange}%, Above: ${e.aboveRange}%`}function Ve(e){return e.reduce((t,n)=>{let i=n.timestamp.split("T")[0];return t[i]=t[i]||[],t[i].push(n),t},{})}function ke(e,t,n){return e.length===0?0:e.filter(o=>o>=t&&o<=n).length/e.length*100}var $e=[m,f];function L(e,t={}){if(!Array.isArray(e)||e.length<2)return NaN;let n=e.filter(u=>typeof u=="number"&&!isNaN(u)&&isFinite(u)&&u!==null&&u!==void 0);if(n.length<3)return NaN;let i=n.reduce((u,c)=>u+c,0)/n.length,o=n.reduce((u,c)=>u+Math.pow(c-i,2),0)/(n.length-1),r=Math.sqrt(o);if(r===0||!isFinite(r))return NaN;let{shortWindow:s=Math.max(3,Math.min(5,Math.floor(n.length/8))),longWindow:a=Math.max(s+2,Math.min(32,Math.floor(n.length/3))),direction:l="auto"}=t;if(n.length<10||a>=n.length-2)return A(n,r);try{let u=q(n,s,a),c=z(n,u);if(c.length<3)return A(n,r);let b=Z(c,r);return b.length===0?A(n,r):J(b,l)}catch{return A(n,r)}}function q(e,t,n){let i=S(e,t),o=S(e,n),r=[0];for(let s=1;s<i.length;s++){let a=i[s-1],l=i[s],u=o[s-1],c=o[s];(a<=u&&l>c||a>=u&&l<c)&&r.push(s);}return r.push(e.length-1),r}function S(e,t){let n=[],i=Math.floor(t/2);for(let o=0;o<e.length;o++){let r=Math.max(0,o-i),s=Math.min(e.length-1,o+i),a=0,l=0;for(let u=r;u<=s;u++)a+=e[u],l++;n.push(a/l);}return n}function z(e,t){let n=[];for(let i=0;i<t.length-1;i++){let o=t[i],r=t[i+1],s=o,a=e[o],l=true;if(n.length>0)l=n[n.length-1].type==="nadir";else {let u=e[o],c=e[o],b=o,G=o;for(let p=o+1;p<=r;p++)e[p]>u&&(u=e[p],b=p),e[p]<c&&(c=e[p],G=p);let D=Math.abs(u-e[o]),U=Math.abs(c-e[o]);D>=U?(s=b,a=u,l=true):(s=G,a=c,l=false);}if(l)for(let u=o;u<=r;u++)e[u]>a&&(a=e[u],s=u);else for(let u=o;u<=r;u++)e[u]<a&&(a=e[u],s=u);n.push({index:s,value:a,type:l?"peak":"nadir"});}return n}function Z(e,t){let n=[];for(let i=0;i<e.length-2;i++){let o=e[i],r=e[i+1],s=e[i+2],a=Math.abs(r.value-o.value),l=Math.abs(s.value-r.value);a>t&&l>t&&n.push({leftAmplitude:a,rightAmplitude:l,direction:r.type==="peak"?"ascending":"descending",indices:[o.index,r.index,s.index]});}return n}function J(e,t){let n;t==="auto"?n=e[0].direction:n=t;let i=e.filter(r=>r.direction===n);if(i.length===0)return NaN;let o=i.map(r=>n==="ascending"?r.leftAmplitude:r.rightAmplitude);return o.reduce((r,s)=>r+s,0)/o.length}function A(e,t){if(e.length<3)return NaN;let n=[],i=Math.max(1,Math.min(3,Math.floor(e.length/10)));for(let r=i;r<e.length-i;r++){let s=e[r],a=true,l=true;for(let u=r-i;u<=r+i;u++)u!==r&&(e[u]>=s&&(a=false),e[u]<=s&&(l=false));a?n.push({index:r,value:s,type:"peak"}):l&&n.push({index:r,value:s,type:"nadir"});}if(n.length===0)for(let r=1;r<e.length-1;r++)e[r]>e[r-1]&&e[r]>e[r+1]?n.push({index:r,value:e[r],type:"peak"}):e[r]<e[r-1]&&e[r]<e[r+1]&&n.push({index:r,value:e[r],type:"nadir"});if(n.length<2)return NaN;let o=[];for(let r=0;r<n.length-1;r++){let s=n[r],a=n[r+1],l=Math.abs(a.value-s.value);l>t&&o.push(l);}for(let r=0;r<n.length-2;r++){let s=n[r],a=n[r+1],l=n[r+2];if(s.type==="peak"&&a.type==="nadir"&&l.type==="peak"||s.type==="nadir"&&a.type==="peak"&&l.type==="nadir"){let u=Math.abs(a.value-s.value),c=Math.abs(l.value-a.value);if(u>t&&c>t){let b=(u+c)/2;o.push(b);}}}return o.length===0?NaN:o.reduce((r,s)=>r+s,0)/o.length}function C(e){if(!Array.isArray(e)||e.length<2)return NaN;let t=e.reduce((i,o)=>i+o,0)/e.length,n=e.reduce((i,o)=>i+Math.pow(o-t,2),0)/(e.length-1);return Math.sqrt(n)}function K(e){if(!Array.isArray(e)||e.length<2)return NaN;let t=e.reduce((i,o)=>i+o,0)/e.length;return t===0?NaN:C(e)/t*100}function Q(e,t){if(!Array.isArray(e)||e.length===0)return {};let n=[...e].sort((o,r)=>o-r),i={};for(let o of t){if(typeof o!="number"||o<0||o>100)continue;let r=Math.ceil(o/100*n.length);i[o]=n[Math.max(0,r-1)];}return i}function X(e,t){return L(e,t)}exports.A1C_TO_EAG_CONSTANT=x;exports.A1C_TO_EAG_MULTIPLIER=h;exports.AllowedGlucoseUnits=$e;exports.GLUCOSE_COLOR_ELEVATED=k;exports.GLUCOSE_COLOR_HIGH=Y;exports.GLUCOSE_COLOR_LOW=F;exports.GLUCOSE_COLOR_NORMAL=H;exports.GLUCOSE_COLOR_NORMAL_DOWN=V;exports.GLUCOSE_COLOR_NORMAL_UP=P;exports.GLUCOSE_ZONE_COLORS=ue;exports.HOMA_IR_CUTOFFS=g;exports.HOMA_IR_DENOMINATOR=O;exports.HYPER_THRESHOLD_MGDL=y;exports.HYPER_THRESHOLD_MMOLL=v;exports.HYPO_THRESHOLD_MGDL=_;exports.HYPO_THRESHOLD_MMOLL=I;exports.MGDL_MMOLL_CONVERSION=M;exports.MG_DL=m;exports.MMOL_L=f;exports.TREND_ARROWS=se;exports.a1cDelta=re;exports.a1cToGMI=Ie;exports.a1cTrend=oe;exports.calculateHOMAIR=j;exports.calculateTIR=He;exports.calculateTimeInRange=ke;exports.checkGlycemicAlignment=Me;exports.clinicalMAGE=L;exports.convertGlucoseUnit=Te;exports.estimateA1CFromAverage=ye;exports.estimateA1CFromAvgGlucose=Ge;exports.estimateAvgGlucoseFromA1C=Oe;exports.estimateEAG=_e;exports.estimateGMI=ve;exports.formatA1C=ee;exports.formatDate=Ue;exports.formatGlucose=Ce;exports.formatPercentage=De;exports.getA1CCategory=ne;exports.getGlucoseLabel=fe;exports.getTIRSummary=Pe;exports.glucoseCoefficientOfVariation=K;exports.glucoseMAGE=X;exports.glucosePercentiles=Q;exports.glucoseStandardDeviation=C;exports.groupByDay=Ve;exports.isA1CInTarget=te;exports.isEstimateGMIOptions=w;exports.isHyper=$;exports.isHypo=W;exports.isValidA1C=d;exports.isValidGlucoseString=N;exports.isValidGlucoseValue=R;exports.mgDlToMmolL=we;exports.mmolLToMgDl=Ne;exports.parseGlucoseString=T;//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map