ts-fsrs 5.0.0 → 5.0.1
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/README.md +9 -5
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.umd.js +1 -1
- package/package.json +4 -1
package/README.md
CHANGED
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
---
|
|
4
4
|
|
|
5
5
|
# About
|
|
6
|
-
[](https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-6)
|
|
7
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
8
|
+
[](https://www.npmjs.com/package/ts-fsrs)
|
|
9
|
+
[](https://codecov.io/gh/open-spaced-repetition/ts-fsrs)
|
|
11
|
+
[](https://github.com/open-spaced-repetition/ts-fsrs/actions/workflows/publish.yml)
|
|
13
|
+
[](https://github.com/open-spaced-repetition/ts-fsrs/actions/workflows/deploy.yml)
|
|
11
15
|
|
|
12
16
|
ts-fsrs is a versatile package written in TypeScript that supports [ES modules](https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c), [CommonJS](https://en.wikipedia.org/wiki/CommonJS), and UMD. It implements the [Free Spaced Repetition Scheduler (FSRS) algorithm](https://github.com/open-spaced-repetition/free-spaced-repetition-scheduler), enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.
|
|
13
17
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";var h=(s=>(s[s.New=0]="New",s[s.Learning=1]="Learning",s[s.Review=2]="Review",s[s.Relearning=3]="Relearning",s))(h||{}),l=(s=>(s[s.Manual=0]="Manual",s[s.Again=1]="Again",s[s.Hard=2]="Hard",s[s.Good=3]="Good",s[s.Easy=4]="Easy",s))(l||{});class o{static card(t){return{...t,state:o.state(t.state),due:o.time(t.due),last_review:t.last_review?o.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=l[`${e}${i}`];if(r===void 0)throw new Error(`Invalid rating:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=h[`${e}${i}`];if(r===void 0)throw new Error(`Invalid state:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:o.time(t.due),rating:o.rating(t.rating),state:o.state(t.state),review:o.time(t.review)}}}Date.prototype.scheduler=function(s,t){return H(this,s,t)},Date.prototype.diff=function(s,t){return C(this,s,t)},Date.prototype.format=function(){return G(this)},Date.prototype.dueFormat=function(s,t,e){return T(this,s,t,e)};function H(s,t,e){return new Date(e?o.time(s).getTime()+t*24*60*60*1e3:o.time(s).getTime()+t*60*1e3)}function C(s,t,e){if(!s||!t)throw new Error("Invalid date");const i=o.time(s).getTime()-o.time(t).getTime();let r=0;switch(e){case"days":r=Math.floor(i/(24*60*60*1e3));break;case"minutes":r=Math.floor(i/(60*1e3));break}return r}function G(s){const t=o.time(s),e=t.getFullYear(),i=t.getMonth()+1,r=t.getDate(),a=t.getHours(),n=t.getMinutes(),d=t.getSeconds();return`${e}-${v(i)}-${v(r)} ${v(a)}:${v(n)}:${v(d)}`}function v(s){return s<10?`0${s}`:`${s}`}const A=[60,60,24,31,12],F=["second","min","hour","day","month","year"];function T(s,t,e,i=F){s=o.time(s),t=o.time(t),i.length!==F.length&&(i=F);let r=s.getTime()-t.getTime(),a;for(r/=1e3,a=0;a<A.length&&!(r<A[a]);a++)r/=A[a];return`${Math.floor(r)}${e?i[a]:""}`}function rt(s){return o.time(s)}function at(s){return o.state(s)}function st(s){return o.rating(s)}const z=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),nt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function U(s,t,e){let i=1;for(const n of nt)i+=n.factor*Math.max(Math.min(s,n.end)-n.start,0);s=Math.min(s,e);let r=Math.max(2,Math.round(s-i));const a=Math.min(Math.round(s+i),e);return s>t&&(r=Math.max(r,t+1)),r=Math.min(r,a),{min_ivl:r,max_ivl:a}}function y(s,t,e){return Math.min(Math.max(s,t),e)}function P(s,t){const e=Date.UTC(s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate()),i=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((i-e)/864e5)}const lt="5.0.0",k=.9,q=36500,Y=!1,j=!0,O=Object.freeze(["1m","10m"]),W=Object.freeze(["10m"]),dt=`v${lt} using FSRS-6.0`,m=.001,ot=36500,x=100,D=.5,X=.2,L=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,X]),B=2,V=s=>[[m,x],[m,x],[m,x],[m,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,s],[0,s],[0,.8],[.1,.8]],S=(s,t)=>{let e=B;if(Math.max(0,t)>1){const i=-(Math.log(s[11])+Math.log(Math.pow(2,s[13])-1)+s[14]*.3)/t;e=y(+i.toFixed(8),.01,2)}return V(e).map(([i,r],a)=>y(s[a],i,r))},ut=s=>{if(s.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${s}`);if(![17,19,21].includes(s.length))throw Error(`Invalid parameter length: ${s.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return s},M=s=>{if(s===void 0)return[...L];switch(s.length){case 21:return[...s];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...s,0,D];case 17:{const t=[...s];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,D])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...L]}},N=s=>{const t=Array.isArray(s?.learning_steps)?s.learning_steps:O,e=Array.isArray(s?.relearning_steps)?s.relearning_steps:W,i=S(M(s?.w),e.length);return{request_retention:s?.request_retention||k,maximum_interval:s?.maximum_interval||q,w:i,enable_fuzz:s?.enable_fuzz??Y,enable_short_term:s?.enable_short_term??j,learning_steps:t,relearning_steps:e}};function E(s,t){const e={due:s?o.time(s):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:h.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}class ht{c;s0;s1;s2;constructor(t){const e=ct();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function ct(){let s=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){s+=t.charCodeAt(e);let i=.02519603282416938*s;s=i>>>0,i-=s,i*=s,s=i>>>0,i-=s,s+=i*4294967296}return(s>>>0)*23283064365386963e-26}}function _t(s){const t=new ht(s),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const I=s=>{const t=typeof s=="number"?-s:-s[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function R(s,t,e){const{decay:i,factor:r}=I(s);return+Math.pow(1+r*t/e,i).toFixed(8)}class J{param;intervalModifier;_seed;constructor(t){this.param=new Proxy(N(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=R.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:i}=I(this.param.w);return+((Math.pow(t,1/e)-1)/i).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="w"&&(r=S(M(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}update_parameters(t){const e=N(t);for(const i in e)if(i in this.param){const r=i;this.param[r]=e[r]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return y(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const i=_t(this._seed)(),{min_ivl:r,max_ivl:a}=U(t,e,this.param.maximum_interval);return Math.floor(i*(a-r+1)+r)}next_interval(t,e){const i=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(i,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const i=-this.param.w[6]*(e-3),r=t+this.linear_damping(i,t);return y(this.mean_reversion(this.init_difficulty(l.Easy),r),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,r){const a=l.Hard===r?this.param.w[15]:1,n=l.Easy===r?this.param.w[16]:1;return+y(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*a*n),m,36500).toFixed(8)}next_forget_stability(t,e,i){return+y(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),m,36500).toFixed(8)}next_short_term_stability(t,e){const i=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),r=e>=3?Math.max(i,1):i;return+y(t*r,m,36500).toFixed(8)}forgetting_curve;next_state(t,e,i){const{difficulty:r,stability:a}=t??{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(i<0||i>4)throw new Error(`Invalid grade "${i}"`);if(r===0&&a===0)return{difficulty:this.init_difficulty(i),stability:this.init_stability(i)};if(i===0)return{difficulty:r,stability:a};if(r<1||a<m)throw new Error(`Invalid memory state { difficulty: ${r}, stability: ${a} }`);const n=this.forgetting_curve(e,a),d=this.next_recall_stability(r,a,n,i),u=this.next_forget_stability(r,a,n),c=this.next_short_term_stability(a,i);let _=d;if(i===1){let[g,p]=[0,0];this.param.enable_short_term&&(g=this.param.w[17],p=this.param.w[18]);const f=a/Math.exp(g*p);_=y(+f.toFixed(8),m,u)}return e===0&&this.param.enable_short_term&&(_=c),{difficulty:this.next_difficulty(r,i),stability:_}}}function K(){const s=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${s}_${t}_${e}`}function ft(s){return function(){const t=Reflect.get(this.current,s)??0,e=this.current.reps;return String(t+e||0)}}const Q=s=>{const t=s.slice(-1),e=parseInt(s.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${s}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${s}, expected m/h/d`)}},Z=(s,t,e)=>{const i=t===h.Relearning||t===h.Review?s.relearning_steps:s.learning_steps,r=i.length;if(r===0||e>=r)return{};const a=i[0],n=Q,d=()=>n(a),u=()=>{if(r===1)return Math.round(n(a)*1.5);const f=i[1];return Math.round((n(a)+n(f))/2)},c=f=>f<0||f>=r?null:i[f],_=f=>n(f),g={},p=c(Math.max(0,e));if(t===h.Review)return g[l.Again]={scheduled_minutes:n(p),next_step:0},g;{g[l.Again]={scheduled_minutes:d(),next_step:0},g[l.Hard]={scheduled_minutes:u(),next_step:e};const f=c(e+1);if(f){const w=_(f);w&&(g[l.Good]={scheduled_minutes:Math.round(w),next_step:e+1})}}return g};var b=(s=>(s.SCHEDULER="Scheduler",s.LEARNING_STEPS="LearningSteps",s.SEED="Seed",s))(b||{});class ${last;current;review_time;next=new Map;algorithm;strategies;constructor(t,e,i,r){this.algorithm=i,this.last=o.card(t),this.current=o.card(t),this.review_time=o.time(e),this.strategies=r,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let i=0;t!==h.New&&e&&(i=P(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1;let r=K;if(this.strategies){const a=this.strategies.get(b.SEED);a&&(r=a)}this.algorithm.seed=r.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of z)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(this.checkGrade(t),e){case h.New:i=this.newState(t);break;case h.Learning:case h.Relearning:i=this.learningState(t);break;case h.Review:i=this.reviewState(t);break}return i}buildLog(t){const{last_review:e,due:i,elapsed_days:r}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:r,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}class tt extends ${learningStepsStrategy;constructor(t,e,i,r){super(t,e,i,r);let a=Z;if(this.strategies){const n=this.strategies.get(b.LEARNING_STEPS);n&&(a=n)}this.learningStepsStrategy=a}getLearningInfo(t,e){const i=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const r=this.learningStepsStrategy(i,t.state,this.current.state===h.Learning?t.learning_steps+1:t.learning_steps),a=Math.max(0,r[e]?.scheduled_minutes??0),n=Math.max(0,r[e]?.next_step??0);return{scheduled_minutes:a,next_steps:n}}applyLearningSteps(t,e,i){const{scheduled_minutes:r,next_steps:a}=this.getLearningInfo(this.current,e);if(r>0&&r<1440)t.learning_steps=a,t.scheduled_days=0,t.state=i,t.due=this.review_time.scheduler(Math.round(r),!1);else if(t.state=h.Review,r>=1440)t.learning_steps=a,t.due=this.review_time.scheduler(Math.round(r),!1),t.scheduled_days=Math.floor(r/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const i=o.card(this.current);i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),this.applyLearningSteps(i,t,h.Learning);const r={card:i,log:this.buildLog(t)};return this.next.set(t,r),r}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:r,stability:a}=this.last,n=o.card(this.current);n.difficulty=this.algorithm.next_difficulty(r,t),n.stability=this.algorithm.next_short_term_stability(a,t),this.applyLearningSteps(n,t,i);const d={card:n,log:this.buildLog(t)};return this.next.set(t,d),d}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),d=o.card(this.current),u=o.card(this.current),c=o.card(this.current),_=o.card(this.current);this.next_ds(d,u,c,_,r,a,n),this.next_interval(u,c,_,i),this.next_state(u,c,_),this.applyLearningSteps(d,l.Again,h.Relearning),d.lapses+=1;const g={card:d,log:this.buildLog(l.Again)},p={card:u,log:super.buildLog(l.Hard)},f={card:c,log:super.buildLog(l.Good)},w={card:_,log:super.buildLog(l.Easy)};return this.next.set(l.Again,g),this.next.set(l.Hard,p),this.next.set(l.Good,f),this.next.set(l.Easy,w),this.next.get(t)}next_ds(t,e,i,r,a,n,d){t.difficulty=this.algorithm.next_difficulty(a,l.Again);const u=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),c=this.algorithm.next_forget_stability(a,n,d);t.stability=y(+u.toFixed(8),m,c),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(a,l.Easy),r.stability=this.algorithm.next_recall_stability(a,n,d,l.Easy)}next_interval(t,e,i,r){let a,n;a=this.algorithm.next_interval(t.stability,r),n=this.algorithm.next_interval(e.stability,r),a=Math.min(a,n),n=Math.max(n,a+1);const d=Math.max(this.algorithm.next_interval(i.stability,r),n+1);t.scheduled_days=a,t.due=this.review_time.scheduler(a,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=d,i.due=this.review_time.scheduler(d,!0)}next_state(t,e,i){t.state=h.Review,t.learning_steps=0,e.state=h.Review,e.learning_steps=0,i.state=h.Review,i.learning_steps=0}}class et extends ${newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=o.card(this.current),r=o.card(this.current),a=o.card(this.current),n=o.card(this.current);return this.init_ds(i,r,a,n),this.next_interval(i,r,a,n,0),this.next_state(i,r,a,n),this.update_next(i,r,a,n),this.next.get(t)}init_ds(t,e,i,r){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),r.difficulty=this.algorithm.init_difficulty(l.Easy),r.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),d=o.card(this.current),u=o.card(this.current),c=o.card(this.current),_=o.card(this.current);return this.next_ds(d,u,c,_,r,a,n),this.next_interval(d,u,c,_,i),this.next_state(d,u,c,_),d.lapses+=1,this.update_next(d,u,c,_),this.next.get(t)}next_ds(t,e,i,r,a,n,d){t.difficulty=this.algorithm.next_difficulty(a,l.Again);const u=this.algorithm.next_forget_stability(a,n,d);t.stability=y(n,m,u),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(a,l.Easy),r.stability=this.algorithm.next_recall_stability(a,n,d,l.Easy)}next_interval(t,e,i,r,a){let n,d,u,c;n=this.algorithm.next_interval(t.stability,a),d=this.algorithm.next_interval(e.stability,a),u=this.algorithm.next_interval(i.stability,a),c=this.algorithm.next_interval(r.stability,a),n=Math.min(n,d),d=Math.max(d,n+1),u=Math.max(u,d+1),c=Math.max(c,u+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=d,e.due=this.review_time.scheduler(d,!0),i.scheduled_days=u,i.due=this.review_time.scheduler(u,!0),r.scheduled_days=c,r.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,r){t.state=h.Review,t.learning_steps=0,e.state=h.Review,e.learning_steps=0,i.state=h.Review,i.learning_steps=0,r.state=h.Review,r.learning_steps=0}update_next(t,e,i,r){const a={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},d={card:i,log:super.buildLog(l.Good)},u={card:r,log:super.buildLog(l.Easy)};this.next.set(l.Again,a),this.next.set(l.Hard,n),this.next.set(l.Good,d),this.next.set(l.Easy,u)}}class gt{fsrs;constructor(t){this.fsrs=t}replay(t,e,i){return this.fsrs.next(t,e,i)}handleManualRating(t,e,i,r,a,n,d){if(typeof e>"u")throw new Error("reschedule: state is required for manual rating");let u,c;if(e===h.New)u={rating:l.Manual,state:e,due:d??i,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c=E(i),c.last_review=i;else{if(typeof d>"u")throw new Error("reschedule: due is required for manual rating");const _=d.diff(i,"days");u={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c={...t,state:e,due:d,last_review:i,stability:a||t.stability,difficulty:n||t.difficulty,elapsed_days:r,scheduled_days:_,reps:t.reps+1}}return{card:c,log:u}}reschedule(t,e){const i=[];let r=E(t.due);for(const a of e){let n;if(a.review=o.time(a.review),a.rating===l.Manual){let d=0;r.state!==h.New&&r.last_review&&(d=a.review.diff(r.last_review,"days")),n=this.handleManualRating(r,a.state,a.review,d,a.stability,a.difficulty,a.due?o.time(a.due):void 0)}else n=this.replay(r,a.review,a.rating);i.push(n),r=n.card}return i}calculateManualRecord(t,e,i,r){if(!i)return null;const{card:a,log:n}=i,d=o.card(t);return d.due.getTime()===a.due.getTime()?null:(d.scheduled_days=a.due.diff(d.due,"days"),this.handleManualRating(d,a.state,o.time(e),n.elapsed_days,r?a.stability:void 0,r?a.difficulty:void 0,a.due))}}class it extends J{strategyHandler=new Map;Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?tt:et}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="enable_short_term"?t.Scheduler=r===!0?tt:et:i==="w"&&(r=S(M(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const i=this.strategyHandler.get(b.SCHEDULER)||this.Scheduler;return new i(t,e,this,this.strategyHandler)}repeat(t,e,i){const r=this.getScheduler(t,e).preview();return i&&typeof i=="function"?i(r):r}next(t,e,i,r){const a=this.getScheduler(t,e),n=o.rating(i);if(n===l.Manual)throw new Error("Cannot review a manual rating");const d=a.review(n);return r&&typeof r=="function"?r(d):d}get_retrievability(t,e,i=!0){const r=o.card(t);e=e?o.time(e):new Date;const a=r.state!==h.New?Math.max(e.diff(r.last_review,"days"),0):0,n=r.state!==h.New?this.forgetting_curve(a,+r.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const r=o.card(t),a=o.review_log(e);if(a.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,d,u;switch(a.state){case h.New:n=a.due,d=void 0,u=0;break;case h.Learning:case h.Relearning:case h.Review:n=a.review,d=a.due,u=r.lapses-(a.rating===l.Again&&a.state===h.Review?1:0);break}const c={...r,due:n,stability:a.stability,difficulty:a.difficulty,elapsed_days:a.last_elapsed_days,scheduled_days:a.scheduled_days,reps:Math.max(0,r.reps-1),lapses:Math.max(0,u),learning_steps:a.learning_steps,state:a.state,last_review:d};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,r){const a=o.card(t);e=o.time(e);const n=a.state===h.New?0:e.diff(a.last_review,"days"),d={rating:l.Manual,state:a.state,due:a.due,stability:a.stability,difficulty:a.difficulty,elapsed_days:0,last_elapsed_days:a.elapsed_days,scheduled_days:n,learning_steps:a.learning_steps,review:e},u={card:{...a,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:a.reps,lapses:i?0:a.lapses,learning_steps:0,state:h.New,last_review:a.last_review},log:d};return r&&typeof r=="function"?r(u):u}reschedule(t,e=[],i={}){const{recordLogHandler:r,reviewsOrderBy:a,skipManual:n=!0,now:d=new Date,update_memory_state:u=!1}=i;a&&typeof a=="function"&&e.sort(a),n&&(e=e.filter(w=>w.rating!==l.Manual));const c=new gt(this),_=c.reschedule(i.first_card||E(),e),g=_.length,p=o.card(t),f=c.calculateManualRecord(p,d,g?_[g-1]:void 0,u);return r&&typeof r=="function"?{collections:_.map(r),reschedule_item:f?r(f):null}:{collections:_,reschedule_item:f}}}const mt=s=>new it(s||{});exports.AbstractScheduler=$,exports.BasicLearningStepsStrategy=Z,exports.CLAMP_PARAMETERS=V,exports.ConvertStepUnitToMinutes=Q,exports.DefaultInitSeedStrategy=K,exports.FSRS=it,exports.FSRS5_DEFAULT_DECAY=D,exports.FSRS6_DEFAULT_DECAY=X,exports.FSRSAlgorithm=J,exports.FSRSVersion=dt,exports.GenSeedStrategyWithCardId=ft,exports.Grades=z,exports.INIT_S_MAX=x,exports.Rating=l,exports.S_MAX=ot,exports.S_MIN=m,exports.State=h,exports.StrategyMode=b,exports.TypeConvert=o,exports.W17_W18_Ceiling=B,exports.checkParameters=ut,exports.clamp=y,exports.clipParameters=S,exports.computeDecayFactor=I,exports.createEmptyCard=E,exports.dateDiffInDays=P,exports.date_diff=C,exports.date_scheduler=H,exports.default_enable_fuzz=Y,exports.default_enable_short_term=j,exports.default_learning_steps=O,exports.default_maximum_interval=q,exports.default_relearning_steps=W,exports.default_request_retention=k,exports.default_w=L,exports.fixDate=rt,exports.fixRating=st,exports.fixState=at,exports.forgetting_curve=R,exports.formatDate=G,exports.fsrs=mt,exports.generatorParameters=N,exports.get_fuzz_range=U,exports.migrateParameters=M,exports.show_diff_message=T,module.exports=Object.assign(exports.default||{},exports);
|
|
1
|
+
"use strict";var h=(s=>(s[s.New=0]="New",s[s.Learning=1]="Learning",s[s.Review=2]="Review",s[s.Relearning=3]="Relearning",s))(h||{}),l=(s=>(s[s.Manual=0]="Manual",s[s.Again=1]="Again",s[s.Hard=2]="Hard",s[s.Good=3]="Good",s[s.Easy=4]="Easy",s))(l||{});class o{static card(t){return{...t,state:o.state(t.state),due:o.time(t.due),last_review:t.last_review?o.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=l[`${e}${i}`];if(r===void 0)throw new Error(`Invalid rating:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=h[`${e}${i}`];if(r===void 0)throw new Error(`Invalid state:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:o.time(t.due),rating:o.rating(t.rating),state:o.state(t.state),review:o.time(t.review)}}}Date.prototype.scheduler=function(s,t){return H(this,s,t)},Date.prototype.diff=function(s,t){return C(this,s,t)},Date.prototype.format=function(){return G(this)},Date.prototype.dueFormat=function(s,t,e){return T(this,s,t,e)};function H(s,t,e){return new Date(e?o.time(s).getTime()+t*24*60*60*1e3:o.time(s).getTime()+t*60*1e3)}function C(s,t,e){if(!s||!t)throw new Error("Invalid date");const i=o.time(s).getTime()-o.time(t).getTime();let r=0;switch(e){case"days":r=Math.floor(i/(24*60*60*1e3));break;case"minutes":r=Math.floor(i/(60*1e3));break}return r}function G(s){const t=o.time(s),e=t.getFullYear(),i=t.getMonth()+1,r=t.getDate(),a=t.getHours(),n=t.getMinutes(),d=t.getSeconds();return`${e}-${v(i)}-${v(r)} ${v(a)}:${v(n)}:${v(d)}`}function v(s){return s<10?`0${s}`:`${s}`}const A=[60,60,24,31,12],F=["second","min","hour","day","month","year"];function T(s,t,e,i=F){s=o.time(s),t=o.time(t),i.length!==F.length&&(i=F);let r=s.getTime()-t.getTime(),a;for(r/=1e3,a=0;a<A.length&&!(r<A[a]);a++)r/=A[a];return`${Math.floor(r)}${e?i[a]:""}`}function rt(s){return o.time(s)}function at(s){return o.state(s)}function st(s){return o.rating(s)}const z=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),nt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function U(s,t,e){let i=1;for(const n of nt)i+=n.factor*Math.max(Math.min(s,n.end)-n.start,0);s=Math.min(s,e);let r=Math.max(2,Math.round(s-i));const a=Math.min(Math.round(s+i),e);return s>t&&(r=Math.max(r,t+1)),r=Math.min(r,a),{min_ivl:r,max_ivl:a}}function y(s,t,e){return Math.min(Math.max(s,t),e)}function P(s,t){const e=Date.UTC(s.getUTCFullYear(),s.getUTCMonth(),s.getUTCDate()),i=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((i-e)/864e5)}const lt="5.0.1",k=.9,q=36500,Y=!1,j=!0,O=Object.freeze(["1m","10m"]),W=Object.freeze(["10m"]),dt=`v${lt} using FSRS-6.0`,m=.001,ot=36500,x=100,D=.5,X=.2,L=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,X]),B=2,V=s=>[[m,x],[m,x],[m,x],[m,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,s],[0,s],[0,.8],[.1,.8]],S=(s,t)=>{let e=B;if(Math.max(0,t)>1){const i=-(Math.log(s[11])+Math.log(Math.pow(2,s[13])-1)+s[14]*.3)/t;e=y(+i.toFixed(8),.01,2)}return V(e).map(([i,r],a)=>y(s[a],i,r))},ut=s=>{if(s.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${s}`);if(![17,19,21].includes(s.length))throw Error(`Invalid parameter length: ${s.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return s},M=s=>{if(s===void 0)return[...L];switch(s.length){case 21:return[...s];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...s,0,D];case 17:{const t=[...s];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,D])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...L]}},N=s=>{const t=Array.isArray(s?.learning_steps)?s.learning_steps:O,e=Array.isArray(s?.relearning_steps)?s.relearning_steps:W,i=S(M(s?.w),e.length);return{request_retention:s?.request_retention||k,maximum_interval:s?.maximum_interval||q,w:i,enable_fuzz:s?.enable_fuzz??Y,enable_short_term:s?.enable_short_term??j,learning_steps:t,relearning_steps:e}};function E(s,t){const e={due:s?o.time(s):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:h.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}class ht{c;s0;s1;s2;constructor(t){const e=ct();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function ct(){let s=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){s+=t.charCodeAt(e);let i=.02519603282416938*s;s=i>>>0,i-=s,i*=s,s=i>>>0,i-=s,s+=i*4294967296}return(s>>>0)*23283064365386963e-26}}function _t(s){const t=new ht(s),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const I=s=>{const t=typeof s=="number"?-s:-s[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function R(s,t,e){const{decay:i,factor:r}=I(s);return+Math.pow(1+r*t/e,i).toFixed(8)}class J{param;intervalModifier;_seed;constructor(t){this.param=new Proxy(N(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=R.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:i}=I(this.param.w);return+((Math.pow(t,1/e)-1)/i).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="w"&&(r=S(M(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}update_parameters(t){const e=N(t);for(const i in e)if(i in this.param){const r=i;this.param[r]=e[r]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return y(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const i=_t(this._seed)(),{min_ivl:r,max_ivl:a}=U(t,e,this.param.maximum_interval);return Math.floor(i*(a-r+1)+r)}next_interval(t,e){const i=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(i,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const i=-this.param.w[6]*(e-3),r=t+this.linear_damping(i,t);return y(this.mean_reversion(this.init_difficulty(l.Easy),r),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,r){const a=l.Hard===r?this.param.w[15]:1,n=l.Easy===r?this.param.w[16]:1;return+y(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*a*n),m,36500).toFixed(8)}next_forget_stability(t,e,i){return+y(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),m,36500).toFixed(8)}next_short_term_stability(t,e){const i=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),r=e>=3?Math.max(i,1):i;return+y(t*r,m,36500).toFixed(8)}forgetting_curve;next_state(t,e,i){const{difficulty:r,stability:a}=t??{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(i<0||i>4)throw new Error(`Invalid grade "${i}"`);if(r===0&&a===0)return{difficulty:this.init_difficulty(i),stability:this.init_stability(i)};if(i===0)return{difficulty:r,stability:a};if(r<1||a<m)throw new Error(`Invalid memory state { difficulty: ${r}, stability: ${a} }`);const n=this.forgetting_curve(e,a),d=this.next_recall_stability(r,a,n,i),u=this.next_forget_stability(r,a,n),c=this.next_short_term_stability(a,i);let _=d;if(i===1){let[g,p]=[0,0];this.param.enable_short_term&&(g=this.param.w[17],p=this.param.w[18]);const f=a/Math.exp(g*p);_=y(+f.toFixed(8),m,u)}return e===0&&this.param.enable_short_term&&(_=c),{difficulty:this.next_difficulty(r,i),stability:_}}}function K(){const s=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${s}_${t}_${e}`}function ft(s){return function(){const t=Reflect.get(this.current,s)??0,e=this.current.reps;return String(t+e||0)}}const Q=s=>{const t=s.slice(-1),e=parseInt(s.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${s}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${s}, expected m/h/d`)}},Z=(s,t,e)=>{const i=t===h.Relearning||t===h.Review?s.relearning_steps:s.learning_steps,r=i.length;if(r===0||e>=r)return{};const a=i[0],n=Q,d=()=>n(a),u=()=>{if(r===1)return Math.round(n(a)*1.5);const f=i[1];return Math.round((n(a)+n(f))/2)},c=f=>f<0||f>=r?null:i[f],_=f=>n(f),g={},p=c(Math.max(0,e));if(t===h.Review)return g[l.Again]={scheduled_minutes:n(p),next_step:0},g;{g[l.Again]={scheduled_minutes:d(),next_step:0},g[l.Hard]={scheduled_minutes:u(),next_step:e};const f=c(e+1);if(f){const w=_(f);w&&(g[l.Good]={scheduled_minutes:Math.round(w),next_step:e+1})}}return g};var b=(s=>(s.SCHEDULER="Scheduler",s.LEARNING_STEPS="LearningSteps",s.SEED="Seed",s))(b||{});class ${last;current;review_time;next=new Map;algorithm;strategies;constructor(t,e,i,r){this.algorithm=i,this.last=o.card(t),this.current=o.card(t),this.review_time=o.time(e),this.strategies=r,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let i=0;t!==h.New&&e&&(i=P(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1;let r=K;if(this.strategies){const a=this.strategies.get(b.SEED);a&&(r=a)}this.algorithm.seed=r.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of z)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(this.checkGrade(t),e){case h.New:i=this.newState(t);break;case h.Learning:case h.Relearning:i=this.learningState(t);break;case h.Review:i=this.reviewState(t);break}return i}buildLog(t){const{last_review:e,due:i,elapsed_days:r}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:r,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}class tt extends ${learningStepsStrategy;constructor(t,e,i,r){super(t,e,i,r);let a=Z;if(this.strategies){const n=this.strategies.get(b.LEARNING_STEPS);n&&(a=n)}this.learningStepsStrategy=a}getLearningInfo(t,e){const i=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const r=this.learningStepsStrategy(i,t.state,this.current.state===h.Learning?t.learning_steps+1:t.learning_steps),a=Math.max(0,r[e]?.scheduled_minutes??0),n=Math.max(0,r[e]?.next_step??0);return{scheduled_minutes:a,next_steps:n}}applyLearningSteps(t,e,i){const{scheduled_minutes:r,next_steps:a}=this.getLearningInfo(this.current,e);if(r>0&&r<1440)t.learning_steps=a,t.scheduled_days=0,t.state=i,t.due=this.review_time.scheduler(Math.round(r),!1);else if(t.state=h.Review,r>=1440)t.learning_steps=a,t.due=this.review_time.scheduler(Math.round(r),!1),t.scheduled_days=Math.floor(r/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const i=o.card(this.current);i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),this.applyLearningSteps(i,t,h.Learning);const r={card:i,log:this.buildLog(t)};return this.next.set(t,r),r}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:r,stability:a}=this.last,n=o.card(this.current);n.difficulty=this.algorithm.next_difficulty(r,t),n.stability=this.algorithm.next_short_term_stability(a,t),this.applyLearningSteps(n,t,i);const d={card:n,log:this.buildLog(t)};return this.next.set(t,d),d}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),d=o.card(this.current),u=o.card(this.current),c=o.card(this.current),_=o.card(this.current);this.next_ds(d,u,c,_,r,a,n),this.next_interval(u,c,_,i),this.next_state(u,c,_),this.applyLearningSteps(d,l.Again,h.Relearning),d.lapses+=1;const g={card:d,log:this.buildLog(l.Again)},p={card:u,log:super.buildLog(l.Hard)},f={card:c,log:super.buildLog(l.Good)},w={card:_,log:super.buildLog(l.Easy)};return this.next.set(l.Again,g),this.next.set(l.Hard,p),this.next.set(l.Good,f),this.next.set(l.Easy,w),this.next.get(t)}next_ds(t,e,i,r,a,n,d){t.difficulty=this.algorithm.next_difficulty(a,l.Again);const u=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),c=this.algorithm.next_forget_stability(a,n,d);t.stability=y(+u.toFixed(8),m,c),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(a,l.Easy),r.stability=this.algorithm.next_recall_stability(a,n,d,l.Easy)}next_interval(t,e,i,r){let a,n;a=this.algorithm.next_interval(t.stability,r),n=this.algorithm.next_interval(e.stability,r),a=Math.min(a,n),n=Math.max(n,a+1);const d=Math.max(this.algorithm.next_interval(i.stability,r),n+1);t.scheduled_days=a,t.due=this.review_time.scheduler(a,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=d,i.due=this.review_time.scheduler(d,!0)}next_state(t,e,i){t.state=h.Review,t.learning_steps=0,e.state=h.Review,e.learning_steps=0,i.state=h.Review,i.learning_steps=0}}class et extends ${newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=o.card(this.current),r=o.card(this.current),a=o.card(this.current),n=o.card(this.current);return this.init_ds(i,r,a,n),this.next_interval(i,r,a,n,0),this.next_state(i,r,a,n),this.update_next(i,r,a,n),this.next.get(t)}init_ds(t,e,i,r){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),r.difficulty=this.algorithm.init_difficulty(l.Easy),r.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),d=o.card(this.current),u=o.card(this.current),c=o.card(this.current),_=o.card(this.current);return this.next_ds(d,u,c,_,r,a,n),this.next_interval(d,u,c,_,i),this.next_state(d,u,c,_),d.lapses+=1,this.update_next(d,u,c,_),this.next.get(t)}next_ds(t,e,i,r,a,n,d){t.difficulty=this.algorithm.next_difficulty(a,l.Again);const u=this.algorithm.next_forget_stability(a,n,d);t.stability=y(n,m,u),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(a,l.Easy),r.stability=this.algorithm.next_recall_stability(a,n,d,l.Easy)}next_interval(t,e,i,r,a){let n,d,u,c;n=this.algorithm.next_interval(t.stability,a),d=this.algorithm.next_interval(e.stability,a),u=this.algorithm.next_interval(i.stability,a),c=this.algorithm.next_interval(r.stability,a),n=Math.min(n,d),d=Math.max(d,n+1),u=Math.max(u,d+1),c=Math.max(c,u+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=d,e.due=this.review_time.scheduler(d,!0),i.scheduled_days=u,i.due=this.review_time.scheduler(u,!0),r.scheduled_days=c,r.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,r){t.state=h.Review,t.learning_steps=0,e.state=h.Review,e.learning_steps=0,i.state=h.Review,i.learning_steps=0,r.state=h.Review,r.learning_steps=0}update_next(t,e,i,r){const a={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},d={card:i,log:super.buildLog(l.Good)},u={card:r,log:super.buildLog(l.Easy)};this.next.set(l.Again,a),this.next.set(l.Hard,n),this.next.set(l.Good,d),this.next.set(l.Easy,u)}}class gt{fsrs;constructor(t){this.fsrs=t}replay(t,e,i){return this.fsrs.next(t,e,i)}handleManualRating(t,e,i,r,a,n,d){if(typeof e>"u")throw new Error("reschedule: state is required for manual rating");let u,c;if(e===h.New)u={rating:l.Manual,state:e,due:d??i,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c=E(i),c.last_review=i;else{if(typeof d>"u")throw new Error("reschedule: due is required for manual rating");const _=d.diff(i,"days");u={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c={...t,state:e,due:d,last_review:i,stability:a||t.stability,difficulty:n||t.difficulty,elapsed_days:r,scheduled_days:_,reps:t.reps+1}}return{card:c,log:u}}reschedule(t,e){const i=[];let r=E(t.due);for(const a of e){let n;if(a.review=o.time(a.review),a.rating===l.Manual){let d=0;r.state!==h.New&&r.last_review&&(d=a.review.diff(r.last_review,"days")),n=this.handleManualRating(r,a.state,a.review,d,a.stability,a.difficulty,a.due?o.time(a.due):void 0)}else n=this.replay(r,a.review,a.rating);i.push(n),r=n.card}return i}calculateManualRecord(t,e,i,r){if(!i)return null;const{card:a,log:n}=i,d=o.card(t);return d.due.getTime()===a.due.getTime()?null:(d.scheduled_days=a.due.diff(d.due,"days"),this.handleManualRating(d,a.state,o.time(e),n.elapsed_days,r?a.stability:void 0,r?a.difficulty:void 0,a.due))}}class it extends J{strategyHandler=new Map;Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?tt:et}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="enable_short_term"?t.Scheduler=r===!0?tt:et:i==="w"&&(r=S(M(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const i=this.strategyHandler.get(b.SCHEDULER)||this.Scheduler;return new i(t,e,this,this.strategyHandler)}repeat(t,e,i){const r=this.getScheduler(t,e).preview();return i&&typeof i=="function"?i(r):r}next(t,e,i,r){const a=this.getScheduler(t,e),n=o.rating(i);if(n===l.Manual)throw new Error("Cannot review a manual rating");const d=a.review(n);return r&&typeof r=="function"?r(d):d}get_retrievability(t,e,i=!0){const r=o.card(t);e=e?o.time(e):new Date;const a=r.state!==h.New?Math.max(e.diff(r.last_review,"days"),0):0,n=r.state!==h.New?this.forgetting_curve(a,+r.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const r=o.card(t),a=o.review_log(e);if(a.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,d,u;switch(a.state){case h.New:n=a.due,d=void 0,u=0;break;case h.Learning:case h.Relearning:case h.Review:n=a.review,d=a.due,u=r.lapses-(a.rating===l.Again&&a.state===h.Review?1:0);break}const c={...r,due:n,stability:a.stability,difficulty:a.difficulty,elapsed_days:a.last_elapsed_days,scheduled_days:a.scheduled_days,reps:Math.max(0,r.reps-1),lapses:Math.max(0,u),learning_steps:a.learning_steps,state:a.state,last_review:d};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,r){const a=o.card(t);e=o.time(e);const n=a.state===h.New?0:e.diff(a.last_review,"days"),d={rating:l.Manual,state:a.state,due:a.due,stability:a.stability,difficulty:a.difficulty,elapsed_days:0,last_elapsed_days:a.elapsed_days,scheduled_days:n,learning_steps:a.learning_steps,review:e},u={card:{...a,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:a.reps,lapses:i?0:a.lapses,learning_steps:0,state:h.New,last_review:a.last_review},log:d};return r&&typeof r=="function"?r(u):u}reschedule(t,e=[],i={}){const{recordLogHandler:r,reviewsOrderBy:a,skipManual:n=!0,now:d=new Date,update_memory_state:u=!1}=i;a&&typeof a=="function"&&e.sort(a),n&&(e=e.filter(w=>w.rating!==l.Manual));const c=new gt(this),_=c.reschedule(i.first_card||E(),e),g=_.length,p=o.card(t),f=c.calculateManualRecord(p,d,g?_[g-1]:void 0,u);return r&&typeof r=="function"?{collections:_.map(r),reschedule_item:f?r(f):null}:{collections:_,reschedule_item:f}}}const mt=s=>new it(s||{});exports.AbstractScheduler=$,exports.BasicLearningStepsStrategy=Z,exports.CLAMP_PARAMETERS=V,exports.ConvertStepUnitToMinutes=Q,exports.DefaultInitSeedStrategy=K,exports.FSRS=it,exports.FSRS5_DEFAULT_DECAY=D,exports.FSRS6_DEFAULT_DECAY=X,exports.FSRSAlgorithm=J,exports.FSRSVersion=dt,exports.GenSeedStrategyWithCardId=ft,exports.Grades=z,exports.INIT_S_MAX=x,exports.Rating=l,exports.S_MAX=ot,exports.S_MIN=m,exports.State=h,exports.StrategyMode=b,exports.TypeConvert=o,exports.W17_W18_Ceiling=B,exports.checkParameters=ut,exports.clamp=y,exports.clipParameters=S,exports.computeDecayFactor=I,exports.createEmptyCard=E,exports.dateDiffInDays=P,exports.date_diff=C,exports.date_scheduler=H,exports.default_enable_fuzz=Y,exports.default_enable_short_term=j,exports.default_learning_steps=O,exports.default_maximum_interval=q,exports.default_relearning_steps=W,exports.default_request_retention=k,exports.default_w=L,exports.fixDate=rt,exports.fixRating=st,exports.fixState=at,exports.forgetting_curve=R,exports.formatDate=G,exports.fsrs=mt,exports.generatorParameters=N,exports.get_fuzz_range=U,exports.migrateParameters=M,exports.show_diff_message=T,module.exports=Object.assign(exports.default||{},exports);
|
|
2
2
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var u=(a=>(a[a.New=0]="New",a[a.Learning=1]="Learning",a[a.Review=2]="Review",a[a.Relearning=3]="Relearning",a))(u||{}),l=(a=>(a[a.Manual=0]="Manual",a[a.Again=1]="Again",a[a.Hard=2]="Hard",a[a.Good=3]="Good",a[a.Easy=4]="Easy",a))(l||{});class h{static card(t){return{...t,state:h.state(t.state),due:h.time(t.due),last_review:t.last_review?h.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=l[`${e}${i}`];if(r===void 0)throw new Error(`Invalid rating:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=u[`${e}${i}`];if(r===void 0)throw new Error(`Invalid state:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:h.time(t.due),rating:h.rating(t.rating),state:h.state(t.state),review:h.time(t.review)}}}Date.prototype.scheduler=function(a,t){return H(this,a,t)},Date.prototype.diff=function(a,t){return G(this,a,t)},Date.prototype.format=function(){return z(this)},Date.prototype.dueFormat=function(a,t,e){return C(this,a,t,e)};function H(a,t,e){return new Date(e?h.time(a).getTime()+t*24*60*60*1e3:h.time(a).getTime()+t*60*1e3)}function G(a,t,e){if(!a||!t)throw new Error("Invalid date");const i=h.time(a).getTime()-h.time(t).getTime();let r=0;switch(e){case"days":r=Math.floor(i/(24*60*60*1e3));break;case"minutes":r=Math.floor(i/(60*1e3));break}return r}function z(a){const t=h.time(a),e=t.getFullYear(),i=t.getMonth()+1,r=t.getDate(),s=t.getHours(),n=t.getMinutes(),d=t.getSeconds();return`${e}-${v(i)}-${v(r)} ${v(s)}:${v(n)}:${v(d)}`}function v(a){return a<10?`0${a}`:`${a}`}const F=[60,60,24,31,12],A=["second","min","hour","day","month","year"];function C(a,t,e,i=A){a=h.time(a),t=h.time(t),i.length!==A.length&&(i=A);let r=a.getTime()-t.getTime(),s;for(r/=1e3,s=0;s<F.length&&!(r<F[s]);s++)r/=F[s];return`${Math.floor(r)}${e?i[s]:""}`}function rt(a){return h.time(a)}function st(a){return h.state(a)}function at(a){return h.rating(a)}const T=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),nt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function U(a,t,e){let i=1;for(const n of nt)i+=n.factor*Math.max(Math.min(a,n.end)-n.start,0);a=Math.min(a,e);let r=Math.max(2,Math.round(a-i));const s=Math.min(Math.round(a+i),e);return a>t&&(r=Math.max(r,t+1)),r=Math.min(r,s),{min_ivl:r,max_ivl:s}}function m(a,t,e){return Math.min(Math.max(a,t),e)}function k(a,t){const e=Date.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate()),i=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((i-e)/864e5)}const lt="5.0.0",q=.9,P=36500,j=!1,O=!0,Y=Object.freeze(["1m","10m"]),W=Object.freeze(["10m"]),dt=`v${lt} using FSRS-6.0`,y=.001,ht=36500,x=100,L=.5,B=.2,N=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,B]),X=2,V=a=>[[y,x],[y,x],[y,x],[y,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,a],[0,a],[0,.8],[.1,.8]],M=(a,t)=>{let e=X;if(Math.max(0,t)>1){const i=-(Math.log(a[11])+Math.log(Math.pow(2,a[13])-1)+a[14]*.3)/t;e=m(+i.toFixed(8),.01,2)}return V(e).map(([i,r],s)=>m(a[s],i,r))},ot=a=>{if(a.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${a}`);if(![17,19,21].includes(a.length))throw Error(`Invalid parameter length: ${a.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return a},S=a=>{if(a===void 0)return[...N];switch(a.length){case 21:return[...a];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...a,0,L];case 17:{const t=[...a];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,L])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...N]}},$=a=>{const t=Array.isArray(a?.learning_steps)?a.learning_steps:Y,e=Array.isArray(a?.relearning_steps)?a.relearning_steps:W,i=M(S(a?.w),e.length);return{request_retention:a?.request_retention||q,maximum_interval:a?.maximum_interval||P,w:i,enable_fuzz:a?.enable_fuzz??j,enable_short_term:a?.enable_short_term??O,learning_steps:t,relearning_steps:e}};function E(a,t){const e={due:a?h.time(a):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:u.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}class ut{c;s0;s1;s2;constructor(t){const e=ct();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function ct(){let a=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){a+=t.charCodeAt(e);let i=.02519603282416938*a;a=i>>>0,i-=a,i*=a,a=i>>>0,i-=a,a+=i*4294967296}return(a>>>0)*23283064365386963e-26}}function ft(a){const t=new ut(a),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const D=a=>{const t=typeof a=="number"?-a:-a[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function R(a,t,e){const{decay:i,factor:r}=D(a);return+Math.pow(1+r*t/e,i).toFixed(8)}class J{param;intervalModifier;_seed;constructor(t){this.param=new Proxy($(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=R.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:i}=D(this.param.w);return+((Math.pow(t,1/e)-1)/i).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="w"&&(r=M(S(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}update_parameters(t){const e=$(t);for(const i in e)if(i in this.param){const r=i;this.param[r]=e[r]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return m(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const i=ft(this._seed)(),{min_ivl:r,max_ivl:s}=U(t,e,this.param.maximum_interval);return Math.floor(i*(s-r+1)+r)}next_interval(t,e){const i=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(i,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const i=-this.param.w[6]*(e-3),r=t+this.linear_damping(i,t);return m(this.mean_reversion(this.init_difficulty(l.Easy),r),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,r){const s=l.Hard===r?this.param.w[15]:1,n=l.Easy===r?this.param.w[16]:1;return+m(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*s*n),y,36500).toFixed(8)}next_forget_stability(t,e,i){return+m(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),y,36500).toFixed(8)}next_short_term_stability(t,e){const i=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),r=e>=3?Math.max(i,1):i;return+m(t*r,y,36500).toFixed(8)}forgetting_curve;next_state(t,e,i){const{difficulty:r,stability:s}=t??{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(i<0||i>4)throw new Error(`Invalid grade "${i}"`);if(r===0&&s===0)return{difficulty:this.init_difficulty(i),stability:this.init_stability(i)};if(i===0)return{difficulty:r,stability:s};if(r<1||s<y)throw new Error(`Invalid memory state { difficulty: ${r}, stability: ${s} }`);const n=this.forgetting_curve(e,s),d=this.next_recall_stability(r,s,n,i),o=this.next_forget_stability(r,s,n),c=this.next_short_term_stability(s,i);let f=d;if(i===1){let[g,p]=[0,0];this.param.enable_short_term&&(g=this.param.w[17],p=this.param.w[18]);const _=s/Math.exp(g*p);f=m(+_.toFixed(8),y,o)}return e===0&&this.param.enable_short_term&&(f=c),{difficulty:this.next_difficulty(r,i),stability:f}}}function K(){const a=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${a}_${t}_${e}`}function _t(a){return function(){const t=Reflect.get(this.current,a)??0,e=this.current.reps;return String(t+e||0)}}const Q=a=>{const t=a.slice(-1),e=parseInt(a.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${a}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${a}, expected m/h/d`)}},Z=(a,t,e)=>{const i=t===u.Relearning||t===u.Review?a.relearning_steps:a.learning_steps,r=i.length;if(r===0||e>=r)return{};const s=i[0],n=Q,d=()=>n(s),o=()=>{if(r===1)return Math.round(n(s)*1.5);const _=i[1];return Math.round((n(s)+n(_))/2)},c=_=>_<0||_>=r?null:i[_],f=_=>n(_),g={},p=c(Math.max(0,e));if(t===u.Review)return g[l.Again]={scheduled_minutes:n(p),next_step:0},g;{g[l.Again]={scheduled_minutes:d(),next_step:0},g[l.Hard]={scheduled_minutes:o(),next_step:e};const _=c(e+1);if(_){const w=f(_);w&&(g[l.Good]={scheduled_minutes:Math.round(w),next_step:e+1})}}return g};var b=(a=>(a.SCHEDULER="Scheduler",a.LEARNING_STEPS="LearningSteps",a.SEED="Seed",a))(b||{});class I{last;current;review_time;next=new Map;algorithm;strategies;constructor(t,e,i,r){this.algorithm=i,this.last=h.card(t),this.current=h.card(t),this.review_time=h.time(e),this.strategies=r,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let i=0;t!==u.New&&e&&(i=k(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1;let r=K;if(this.strategies){const s=this.strategies.get(b.SEED);s&&(r=s)}this.algorithm.seed=r.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of T)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(this.checkGrade(t),e){case u.New:i=this.newState(t);break;case u.Learning:case u.Relearning:i=this.learningState(t);break;case u.Review:i=this.reviewState(t);break}return i}buildLog(t){const{last_review:e,due:i,elapsed_days:r}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:r,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}class tt extends I{learningStepsStrategy;constructor(t,e,i,r){super(t,e,i,r);let s=Z;if(this.strategies){const n=this.strategies.get(b.LEARNING_STEPS);n&&(s=n)}this.learningStepsStrategy=s}getLearningInfo(t,e){const i=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const r=this.learningStepsStrategy(i,t.state,this.current.state===u.Learning?t.learning_steps+1:t.learning_steps),s=Math.max(0,r[e]?.scheduled_minutes??0),n=Math.max(0,r[e]?.next_step??0);return{scheduled_minutes:s,next_steps:n}}applyLearningSteps(t,e,i){const{scheduled_minutes:r,next_steps:s}=this.getLearningInfo(this.current,e);if(r>0&&r<1440)t.learning_steps=s,t.scheduled_days=0,t.state=i,t.due=this.review_time.scheduler(Math.round(r),!1);else if(t.state=u.Review,r>=1440)t.learning_steps=s,t.due=this.review_time.scheduler(Math.round(r),!1),t.scheduled_days=Math.floor(r/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const i=h.card(this.current);i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),this.applyLearningSteps(i,t,u.Learning);const r={card:i,log:this.buildLog(t)};return this.next.set(t,r),r}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:r,stability:s}=this.last,n=h.card(this.current);n.difficulty=this.algorithm.next_difficulty(r,t),n.stability=this.algorithm.next_short_term_stability(s,t),this.applyLearningSteps(n,t,i);const d={card:n,log:this.buildLog(t)};return this.next.set(t,d),d}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);this.next_ds(d,o,c,f,r,s,n),this.next_interval(o,c,f,i),this.next_state(o,c,f),this.applyLearningSteps(d,l.Again,u.Relearning),d.lapses+=1;const g={card:d,log:this.buildLog(l.Again)},p={card:o,log:super.buildLog(l.Hard)},_={card:c,log:super.buildLog(l.Good)},w={card:f,log:super.buildLog(l.Easy)};return this.next.set(l.Again,g),this.next.set(l.Hard,p),this.next.set(l.Good,_),this.next.set(l.Easy,w),this.next.get(t)}next_ds(t,e,i,r,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const o=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),c=this.algorithm.next_forget_stability(s,n,d);t.stability=m(+o.toFixed(8),y,c),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(s,l.Easy),r.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,r){let s,n;s=this.algorithm.next_interval(t.stability,r),n=this.algorithm.next_interval(e.stability,r),s=Math.min(s,n),n=Math.max(n,s+1);const d=Math.max(this.algorithm.next_interval(i.stability,r),n+1);t.scheduled_days=s,t.due=this.review_time.scheduler(s,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=d,i.due=this.review_time.scheduler(d,!0)}next_state(t,e,i){t.state=u.Review,t.learning_steps=0,e.state=u.Review,e.learning_steps=0,i.state=u.Review,i.learning_steps=0}}class et extends I{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=h.card(this.current),r=h.card(this.current),s=h.card(this.current),n=h.card(this.current);return this.init_ds(i,r,s,n),this.next_interval(i,r,s,n,0),this.next_state(i,r,s,n),this.update_next(i,r,s,n),this.next.get(t)}init_ds(t,e,i,r){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),r.difficulty=this.algorithm.init_difficulty(l.Easy),r.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);return this.next_ds(d,o,c,f,r,s,n),this.next_interval(d,o,c,f,i),this.next_state(d,o,c,f),d.lapses+=1,this.update_next(d,o,c,f),this.next.get(t)}next_ds(t,e,i,r,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const o=this.algorithm.next_forget_stability(s,n,d);t.stability=m(n,y,o),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(s,l.Easy),r.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,r,s){let n,d,o,c;n=this.algorithm.next_interval(t.stability,s),d=this.algorithm.next_interval(e.stability,s),o=this.algorithm.next_interval(i.stability,s),c=this.algorithm.next_interval(r.stability,s),n=Math.min(n,d),d=Math.max(d,n+1),o=Math.max(o,d+1),c=Math.max(c,o+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=d,e.due=this.review_time.scheduler(d,!0),i.scheduled_days=o,i.due=this.review_time.scheduler(o,!0),r.scheduled_days=c,r.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,r){t.state=u.Review,t.learning_steps=0,e.state=u.Review,e.learning_steps=0,i.state=u.Review,i.learning_steps=0,r.state=u.Review,r.learning_steps=0}update_next(t,e,i,r){const s={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},d={card:i,log:super.buildLog(l.Good)},o={card:r,log:super.buildLog(l.Easy)};this.next.set(l.Again,s),this.next.set(l.Hard,n),this.next.set(l.Good,d),this.next.set(l.Easy,o)}}class gt{fsrs;constructor(t){this.fsrs=t}replay(t,e,i){return this.fsrs.next(t,e,i)}handleManualRating(t,e,i,r,s,n,d){if(typeof e>"u")throw new Error("reschedule: state is required for manual rating");let o,c;if(e===u.New)o={rating:l.Manual,state:e,due:d??i,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c=E(i),c.last_review=i;else{if(typeof d>"u")throw new Error("reschedule: due is required for manual rating");const f=d.diff(i,"days");o={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c={...t,state:e,due:d,last_review:i,stability:s||t.stability,difficulty:n||t.difficulty,elapsed_days:r,scheduled_days:f,reps:t.reps+1}}return{card:c,log:o}}reschedule(t,e){const i=[];let r=E(t.due);for(const s of e){let n;if(s.review=h.time(s.review),s.rating===l.Manual){let d=0;r.state!==u.New&&r.last_review&&(d=s.review.diff(r.last_review,"days")),n=this.handleManualRating(r,s.state,s.review,d,s.stability,s.difficulty,s.due?h.time(s.due):void 0)}else n=this.replay(r,s.review,s.rating);i.push(n),r=n.card}return i}calculateManualRecord(t,e,i,r){if(!i)return null;const{card:s,log:n}=i,d=h.card(t);return d.due.getTime()===s.due.getTime()?null:(d.scheduled_days=s.due.diff(d.due,"days"),this.handleManualRating(d,s.state,h.time(e),n.elapsed_days,r?s.stability:void 0,r?s.difficulty:void 0,s.due))}}class it extends J{strategyHandler=new Map;Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?tt:et}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="enable_short_term"?t.Scheduler=r===!0?tt:et:i==="w"&&(r=M(S(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const i=this.strategyHandler.get(b.SCHEDULER)||this.Scheduler;return new i(t,e,this,this.strategyHandler)}repeat(t,e,i){const r=this.getScheduler(t,e).preview();return i&&typeof i=="function"?i(r):r}next(t,e,i,r){const s=this.getScheduler(t,e),n=h.rating(i);if(n===l.Manual)throw new Error("Cannot review a manual rating");const d=s.review(n);return r&&typeof r=="function"?r(d):d}get_retrievability(t,e,i=!0){const r=h.card(t);e=e?h.time(e):new Date;const s=r.state!==u.New?Math.max(e.diff(r.last_review,"days"),0):0,n=r.state!==u.New?this.forgetting_curve(s,+r.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const r=h.card(t),s=h.review_log(e);if(s.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,d,o;switch(s.state){case u.New:n=s.due,d=void 0,o=0;break;case u.Learning:case u.Relearning:case u.Review:n=s.review,d=s.due,o=r.lapses-(s.rating===l.Again&&s.state===u.Review?1:0);break}const c={...r,due:n,stability:s.stability,difficulty:s.difficulty,elapsed_days:s.last_elapsed_days,scheduled_days:s.scheduled_days,reps:Math.max(0,r.reps-1),lapses:Math.max(0,o),learning_steps:s.learning_steps,state:s.state,last_review:d};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,r){const s=h.card(t);e=h.time(e);const n=s.state===u.New?0:e.diff(s.last_review,"days"),d={rating:l.Manual,state:s.state,due:s.due,stability:s.stability,difficulty:s.difficulty,elapsed_days:0,last_elapsed_days:s.elapsed_days,scheduled_days:n,learning_steps:s.learning_steps,review:e},o={card:{...s,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:s.reps,lapses:i?0:s.lapses,learning_steps:0,state:u.New,last_review:s.last_review},log:d};return r&&typeof r=="function"?r(o):o}reschedule(t,e=[],i={}){const{recordLogHandler:r,reviewsOrderBy:s,skipManual:n=!0,now:d=new Date,update_memory_state:o=!1}=i;s&&typeof s=="function"&&e.sort(s),n&&(e=e.filter(w=>w.rating!==l.Manual));const c=new gt(this),f=c.reschedule(i.first_card||E(),e),g=f.length,p=h.card(t),_=c.calculateManualRecord(p,d,g?f[g-1]:void 0,o);return r&&typeof r=="function"?{collections:f.map(r),reschedule_item:_?r(_):null}:{collections:f,reschedule_item:_}}}const yt=a=>new it(a||{});export{I as AbstractScheduler,Z as BasicLearningStepsStrategy,V as CLAMP_PARAMETERS,Q as ConvertStepUnitToMinutes,K as DefaultInitSeedStrategy,it as FSRS,L as FSRS5_DEFAULT_DECAY,B as FSRS6_DEFAULT_DECAY,J as FSRSAlgorithm,dt as FSRSVersion,_t as GenSeedStrategyWithCardId,T as Grades,x as INIT_S_MAX,l as Rating,ht as S_MAX,y as S_MIN,u as State,b as StrategyMode,h as TypeConvert,X as W17_W18_Ceiling,ot as checkParameters,m as clamp,M as clipParameters,D as computeDecayFactor,E as createEmptyCard,k as dateDiffInDays,G as date_diff,H as date_scheduler,j as default_enable_fuzz,O as default_enable_short_term,Y as default_learning_steps,P as default_maximum_interval,W as default_relearning_steps,q as default_request_retention,N as default_w,rt as fixDate,at as fixRating,st as fixState,R as forgetting_curve,z as formatDate,yt as fsrs,$ as generatorParameters,U as get_fuzz_range,S as migrateParameters,C as show_diff_message};
|
|
1
|
+
var u=(a=>(a[a.New=0]="New",a[a.Learning=1]="Learning",a[a.Review=2]="Review",a[a.Relearning=3]="Relearning",a))(u||{}),l=(a=>(a[a.Manual=0]="Manual",a[a.Again=1]="Again",a[a.Hard=2]="Hard",a[a.Good=3]="Good",a[a.Easy=4]="Easy",a))(l||{});class h{static card(t){return{...t,state:h.state(t.state),due:h.time(t.due),last_review:t.last_review?h.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=l[`${e}${i}`];if(r===void 0)throw new Error(`Invalid rating:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),r=u[`${e}${i}`];if(r===void 0)throw new Error(`Invalid state:[${t}]`);return r}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:h.time(t.due),rating:h.rating(t.rating),state:h.state(t.state),review:h.time(t.review)}}}Date.prototype.scheduler=function(a,t){return H(this,a,t)},Date.prototype.diff=function(a,t){return G(this,a,t)},Date.prototype.format=function(){return z(this)},Date.prototype.dueFormat=function(a,t,e){return C(this,a,t,e)};function H(a,t,e){return new Date(e?h.time(a).getTime()+t*24*60*60*1e3:h.time(a).getTime()+t*60*1e3)}function G(a,t,e){if(!a||!t)throw new Error("Invalid date");const i=h.time(a).getTime()-h.time(t).getTime();let r=0;switch(e){case"days":r=Math.floor(i/(24*60*60*1e3));break;case"minutes":r=Math.floor(i/(60*1e3));break}return r}function z(a){const t=h.time(a),e=t.getFullYear(),i=t.getMonth()+1,r=t.getDate(),s=t.getHours(),n=t.getMinutes(),d=t.getSeconds();return`${e}-${v(i)}-${v(r)} ${v(s)}:${v(n)}:${v(d)}`}function v(a){return a<10?`0${a}`:`${a}`}const F=[60,60,24,31,12],A=["second","min","hour","day","month","year"];function C(a,t,e,i=A){a=h.time(a),t=h.time(t),i.length!==A.length&&(i=A);let r=a.getTime()-t.getTime(),s;for(r/=1e3,s=0;s<F.length&&!(r<F[s]);s++)r/=F[s];return`${Math.floor(r)}${e?i[s]:""}`}function rt(a){return h.time(a)}function st(a){return h.state(a)}function at(a){return h.rating(a)}const T=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),nt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function U(a,t,e){let i=1;for(const n of nt)i+=n.factor*Math.max(Math.min(a,n.end)-n.start,0);a=Math.min(a,e);let r=Math.max(2,Math.round(a-i));const s=Math.min(Math.round(a+i),e);return a>t&&(r=Math.max(r,t+1)),r=Math.min(r,s),{min_ivl:r,max_ivl:s}}function m(a,t,e){return Math.min(Math.max(a,t),e)}function k(a,t){const e=Date.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate()),i=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((i-e)/864e5)}const lt="5.0.1",q=.9,P=36500,j=!1,O=!0,Y=Object.freeze(["1m","10m"]),W=Object.freeze(["10m"]),dt=`v${lt} using FSRS-6.0`,y=.001,ht=36500,x=100,L=.5,B=.2,N=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,B]),X=2,V=a=>[[y,x],[y,x],[y,x],[y,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,a],[0,a],[0,.8],[.1,.8]],M=(a,t)=>{let e=X;if(Math.max(0,t)>1){const i=-(Math.log(a[11])+Math.log(Math.pow(2,a[13])-1)+a[14]*.3)/t;e=m(+i.toFixed(8),.01,2)}return V(e).map(([i,r],s)=>m(a[s],i,r))},ot=a=>{if(a.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${a}`);if(![17,19,21].includes(a.length))throw Error(`Invalid parameter length: ${a.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return a},S=a=>{if(a===void 0)return[...N];switch(a.length){case 21:return[...a];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...a,0,L];case 17:{const t=[...a];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,L])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...N]}},$=a=>{const t=Array.isArray(a?.learning_steps)?a.learning_steps:Y,e=Array.isArray(a?.relearning_steps)?a.relearning_steps:W,i=M(S(a?.w),e.length);return{request_retention:a?.request_retention||q,maximum_interval:a?.maximum_interval||P,w:i,enable_fuzz:a?.enable_fuzz??j,enable_short_term:a?.enable_short_term??O,learning_steps:t,relearning_steps:e}};function E(a,t){const e={due:a?h.time(a):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:u.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}class ut{c;s0;s1;s2;constructor(t){const e=ct();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function ct(){let a=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){a+=t.charCodeAt(e);let i=.02519603282416938*a;a=i>>>0,i-=a,i*=a,a=i>>>0,i-=a,a+=i*4294967296}return(a>>>0)*23283064365386963e-26}}function ft(a){const t=new ut(a),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const D=a=>{const t=typeof a=="number"?-a:-a[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function R(a,t,e){const{decay:i,factor:r}=D(a);return+Math.pow(1+r*t/e,i).toFixed(8)}class J{param;intervalModifier;_seed;constructor(t){this.param=new Proxy($(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=R.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:i}=D(this.param.w);return+((Math.pow(t,1/e)-1)/i).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="w"&&(r=M(S(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}update_parameters(t){const e=$(t);for(const i in e)if(i in this.param){const r=i;this.param[r]=e[r]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return m(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const i=ft(this._seed)(),{min_ivl:r,max_ivl:s}=U(t,e,this.param.maximum_interval);return Math.floor(i*(s-r+1)+r)}next_interval(t,e){const i=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(i,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const i=-this.param.w[6]*(e-3),r=t+this.linear_damping(i,t);return m(this.mean_reversion(this.init_difficulty(l.Easy),r),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,r){const s=l.Hard===r?this.param.w[15]:1,n=l.Easy===r?this.param.w[16]:1;return+m(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*s*n),y,36500).toFixed(8)}next_forget_stability(t,e,i){return+m(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),y,36500).toFixed(8)}next_short_term_stability(t,e){const i=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),r=e>=3?Math.max(i,1):i;return+m(t*r,y,36500).toFixed(8)}forgetting_curve;next_state(t,e,i){const{difficulty:r,stability:s}=t??{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(i<0||i>4)throw new Error(`Invalid grade "${i}"`);if(r===0&&s===0)return{difficulty:this.init_difficulty(i),stability:this.init_stability(i)};if(i===0)return{difficulty:r,stability:s};if(r<1||s<y)throw new Error(`Invalid memory state { difficulty: ${r}, stability: ${s} }`);const n=this.forgetting_curve(e,s),d=this.next_recall_stability(r,s,n,i),o=this.next_forget_stability(r,s,n),c=this.next_short_term_stability(s,i);let f=d;if(i===1){let[g,p]=[0,0];this.param.enable_short_term&&(g=this.param.w[17],p=this.param.w[18]);const _=s/Math.exp(g*p);f=m(+_.toFixed(8),y,o)}return e===0&&this.param.enable_short_term&&(f=c),{difficulty:this.next_difficulty(r,i),stability:f}}}function K(){const a=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${a}_${t}_${e}`}function _t(a){return function(){const t=Reflect.get(this.current,a)??0,e=this.current.reps;return String(t+e||0)}}const Q=a=>{const t=a.slice(-1),e=parseInt(a.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${a}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${a}, expected m/h/d`)}},Z=(a,t,e)=>{const i=t===u.Relearning||t===u.Review?a.relearning_steps:a.learning_steps,r=i.length;if(r===0||e>=r)return{};const s=i[0],n=Q,d=()=>n(s),o=()=>{if(r===1)return Math.round(n(s)*1.5);const _=i[1];return Math.round((n(s)+n(_))/2)},c=_=>_<0||_>=r?null:i[_],f=_=>n(_),g={},p=c(Math.max(0,e));if(t===u.Review)return g[l.Again]={scheduled_minutes:n(p),next_step:0},g;{g[l.Again]={scheduled_minutes:d(),next_step:0},g[l.Hard]={scheduled_minutes:o(),next_step:e};const _=c(e+1);if(_){const w=f(_);w&&(g[l.Good]={scheduled_minutes:Math.round(w),next_step:e+1})}}return g};var b=(a=>(a.SCHEDULER="Scheduler",a.LEARNING_STEPS="LearningSteps",a.SEED="Seed",a))(b||{});class I{last;current;review_time;next=new Map;algorithm;strategies;constructor(t,e,i,r){this.algorithm=i,this.last=h.card(t),this.current=h.card(t),this.review_time=h.time(e),this.strategies=r,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let i=0;t!==u.New&&e&&(i=k(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1;let r=K;if(this.strategies){const s=this.strategies.get(b.SEED);s&&(r=s)}this.algorithm.seed=r.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of T)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(this.checkGrade(t),e){case u.New:i=this.newState(t);break;case u.Learning:case u.Relearning:i=this.learningState(t);break;case u.Review:i=this.reviewState(t);break}return i}buildLog(t){const{last_review:e,due:i,elapsed_days:r}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:r,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}class tt extends I{learningStepsStrategy;constructor(t,e,i,r){super(t,e,i,r);let s=Z;if(this.strategies){const n=this.strategies.get(b.LEARNING_STEPS);n&&(s=n)}this.learningStepsStrategy=s}getLearningInfo(t,e){const i=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const r=this.learningStepsStrategy(i,t.state,this.current.state===u.Learning?t.learning_steps+1:t.learning_steps),s=Math.max(0,r[e]?.scheduled_minutes??0),n=Math.max(0,r[e]?.next_step??0);return{scheduled_minutes:s,next_steps:n}}applyLearningSteps(t,e,i){const{scheduled_minutes:r,next_steps:s}=this.getLearningInfo(this.current,e);if(r>0&&r<1440)t.learning_steps=s,t.scheduled_days=0,t.state=i,t.due=this.review_time.scheduler(Math.round(r),!1);else if(t.state=u.Review,r>=1440)t.learning_steps=s,t.due=this.review_time.scheduler(Math.round(r),!1),t.scheduled_days=Math.floor(r/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const i=h.card(this.current);i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),this.applyLearningSteps(i,t,u.Learning);const r={card:i,log:this.buildLog(t)};return this.next.set(t,r),r}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:r,stability:s}=this.last,n=h.card(this.current);n.difficulty=this.algorithm.next_difficulty(r,t),n.stability=this.algorithm.next_short_term_stability(s,t),this.applyLearningSteps(n,t,i);const d={card:n,log:this.buildLog(t)};return this.next.set(t,d),d}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);this.next_ds(d,o,c,f,r,s,n),this.next_interval(o,c,f,i),this.next_state(o,c,f),this.applyLearningSteps(d,l.Again,u.Relearning),d.lapses+=1;const g={card:d,log:this.buildLog(l.Again)},p={card:o,log:super.buildLog(l.Hard)},_={card:c,log:super.buildLog(l.Good)},w={card:f,log:super.buildLog(l.Easy)};return this.next.set(l.Again,g),this.next.set(l.Hard,p),this.next.set(l.Good,_),this.next.set(l.Easy,w),this.next.get(t)}next_ds(t,e,i,r,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const o=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),c=this.algorithm.next_forget_stability(s,n,d);t.stability=m(+o.toFixed(8),y,c),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(s,l.Easy),r.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,r){let s,n;s=this.algorithm.next_interval(t.stability,r),n=this.algorithm.next_interval(e.stability,r),s=Math.min(s,n),n=Math.max(n,s+1);const d=Math.max(this.algorithm.next_interval(i.stability,r),n+1);t.scheduled_days=s,t.due=this.review_time.scheduler(s,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=d,i.due=this.review_time.scheduler(d,!0)}next_state(t,e,i){t.state=u.Review,t.learning_steps=0,e.state=u.Review,e.learning_steps=0,i.state=u.Review,i.learning_steps=0}}class et extends I{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=h.card(this.current),r=h.card(this.current),s=h.card(this.current),n=h.card(this.current);return this.init_ds(i,r,s,n),this.next_interval(i,r,s,n,0),this.next_state(i,r,s,n),this.update_next(i,r,s,n),this.next.get(t)}init_ds(t,e,i,r){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),r.difficulty=this.algorithm.init_difficulty(l.Easy),r.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:r,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);return this.next_ds(d,o,c,f,r,s,n),this.next_interval(d,o,c,f,i),this.next_state(d,o,c,f),d.lapses+=1,this.update_next(d,o,c,f),this.next.get(t)}next_ds(t,e,i,r,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const o=this.algorithm.next_forget_stability(s,n,d);t.stability=m(n,y,o),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),r.difficulty=this.algorithm.next_difficulty(s,l.Easy),r.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,r,s){let n,d,o,c;n=this.algorithm.next_interval(t.stability,s),d=this.algorithm.next_interval(e.stability,s),o=this.algorithm.next_interval(i.stability,s),c=this.algorithm.next_interval(r.stability,s),n=Math.min(n,d),d=Math.max(d,n+1),o=Math.max(o,d+1),c=Math.max(c,o+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=d,e.due=this.review_time.scheduler(d,!0),i.scheduled_days=o,i.due=this.review_time.scheduler(o,!0),r.scheduled_days=c,r.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,r){t.state=u.Review,t.learning_steps=0,e.state=u.Review,e.learning_steps=0,i.state=u.Review,i.learning_steps=0,r.state=u.Review,r.learning_steps=0}update_next(t,e,i,r){const s={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},d={card:i,log:super.buildLog(l.Good)},o={card:r,log:super.buildLog(l.Easy)};this.next.set(l.Again,s),this.next.set(l.Hard,n),this.next.set(l.Good,d),this.next.set(l.Easy,o)}}class gt{fsrs;constructor(t){this.fsrs=t}replay(t,e,i){return this.fsrs.next(t,e,i)}handleManualRating(t,e,i,r,s,n,d){if(typeof e>"u")throw new Error("reschedule: state is required for manual rating");let o,c;if(e===u.New)o={rating:l.Manual,state:e,due:d??i,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c=E(i),c.last_review=i;else{if(typeof d>"u")throw new Error("reschedule: due is required for manual rating");const f=d.diff(i,"days");o={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:r,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:i},c={...t,state:e,due:d,last_review:i,stability:s||t.stability,difficulty:n||t.difficulty,elapsed_days:r,scheduled_days:f,reps:t.reps+1}}return{card:c,log:o}}reschedule(t,e){const i=[];let r=E(t.due);for(const s of e){let n;if(s.review=h.time(s.review),s.rating===l.Manual){let d=0;r.state!==u.New&&r.last_review&&(d=s.review.diff(r.last_review,"days")),n=this.handleManualRating(r,s.state,s.review,d,s.stability,s.difficulty,s.due?h.time(s.due):void 0)}else n=this.replay(r,s.review,s.rating);i.push(n),r=n.card}return i}calculateManualRecord(t,e,i,r){if(!i)return null;const{card:s,log:n}=i,d=h.card(t);return d.due.getTime()===s.due.getTime()?null:(d.scheduled_days=s.due.diff(d.due,"days"),this.handleManualRating(d,s.state,h.time(e),n.elapsed_days,r?s.stability:void 0,r?s.difficulty:void 0,s.due))}}class it extends J{strategyHandler=new Map;Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?tt:et}params_handler_proxy(){const t=this;return{set:function(e,i,r){return i==="request_retention"&&Number.isFinite(r)?t.intervalModifier=t.calculate_interval_modifier(Number(r)):i==="enable_short_term"?t.Scheduler=r===!0?tt:et:i==="w"&&(r=M(S(r),e.relearning_steps.length),t.forgetting_curve=R.bind(this,r),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,i,r),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const i=this.strategyHandler.get(b.SCHEDULER)||this.Scheduler;return new i(t,e,this,this.strategyHandler)}repeat(t,e,i){const r=this.getScheduler(t,e).preview();return i&&typeof i=="function"?i(r):r}next(t,e,i,r){const s=this.getScheduler(t,e),n=h.rating(i);if(n===l.Manual)throw new Error("Cannot review a manual rating");const d=s.review(n);return r&&typeof r=="function"?r(d):d}get_retrievability(t,e,i=!0){const r=h.card(t);e=e?h.time(e):new Date;const s=r.state!==u.New?Math.max(e.diff(r.last_review,"days"),0):0,n=r.state!==u.New?this.forgetting_curve(s,+r.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const r=h.card(t),s=h.review_log(e);if(s.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,d,o;switch(s.state){case u.New:n=s.due,d=void 0,o=0;break;case u.Learning:case u.Relearning:case u.Review:n=s.review,d=s.due,o=r.lapses-(s.rating===l.Again&&s.state===u.Review?1:0);break}const c={...r,due:n,stability:s.stability,difficulty:s.difficulty,elapsed_days:s.last_elapsed_days,scheduled_days:s.scheduled_days,reps:Math.max(0,r.reps-1),lapses:Math.max(0,o),learning_steps:s.learning_steps,state:s.state,last_review:d};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,r){const s=h.card(t);e=h.time(e);const n=s.state===u.New?0:e.diff(s.last_review,"days"),d={rating:l.Manual,state:s.state,due:s.due,stability:s.stability,difficulty:s.difficulty,elapsed_days:0,last_elapsed_days:s.elapsed_days,scheduled_days:n,learning_steps:s.learning_steps,review:e},o={card:{...s,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:s.reps,lapses:i?0:s.lapses,learning_steps:0,state:u.New,last_review:s.last_review},log:d};return r&&typeof r=="function"?r(o):o}reschedule(t,e=[],i={}){const{recordLogHandler:r,reviewsOrderBy:s,skipManual:n=!0,now:d=new Date,update_memory_state:o=!1}=i;s&&typeof s=="function"&&e.sort(s),n&&(e=e.filter(w=>w.rating!==l.Manual));const c=new gt(this),f=c.reschedule(i.first_card||E(),e),g=f.length,p=h.card(t),_=c.calculateManualRecord(p,d,g?f[g-1]:void 0,o);return r&&typeof r=="function"?{collections:f.map(r),reschedule_item:_?r(_):null}:{collections:f,reschedule_item:_}}}const yt=a=>new it(a||{});export{I as AbstractScheduler,Z as BasicLearningStepsStrategy,V as CLAMP_PARAMETERS,Q as ConvertStepUnitToMinutes,K as DefaultInitSeedStrategy,it as FSRS,L as FSRS5_DEFAULT_DECAY,B as FSRS6_DEFAULT_DECAY,J as FSRSAlgorithm,dt as FSRSVersion,_t as GenSeedStrategyWithCardId,T as Grades,x as INIT_S_MAX,l as Rating,ht as S_MAX,y as S_MIN,u as State,b as StrategyMode,h as TypeConvert,X as W17_W18_Ceiling,ot as checkParameters,m as clamp,M as clipParameters,D as computeDecayFactor,E as createEmptyCard,k as dateDiffInDays,G as date_diff,H as date_scheduler,j as default_enable_fuzz,O as default_enable_short_term,Y as default_learning_steps,P as default_maximum_interval,W as default_relearning_steps,q as default_request_retention,N as default_w,rt as fixDate,at as fixRating,st as fixState,R as forgetting_curve,z as formatDate,yt as fsrs,$ as generatorParameters,U as get_fuzz_range,S as migrateParameters,C as show_diff_message};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.umd.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
(function(d,c){typeof exports=="object"&&typeof module!="undefined"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(d=typeof globalThis!="undefined"?globalThis:d||self,c(d.FSRS={}))})(this,function(d){"use strict";var c=(i=>(i[i.New=0]="New",i[i.Learning=1]="Learning",i[i.Review=2]="Review",i[i.Relearning=3]="Relearning",i))(c||{}),l=(i=>(i[i.Manual=0]="Manual",i[i.Again=1]="Again",i[i.Hard=2]="Hard",i[i.Good=3]="Good",i[i.Easy=4]="Easy",i))(l||{}),pt=Object.defineProperty,vt=Object.defineProperties,wt=Object.getOwnPropertyDescriptors,G=Object.getOwnPropertySymbols,bt=Object.prototype.hasOwnProperty,St=Object.prototype.propertyIsEnumerable,z=(i,t,e)=>t in i?pt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,U=(i,t)=>{for(var e in t||(t={}))bt.call(t,e)&&z(i,e,t[e]);if(G)for(var e of G(t))St.call(t,e)&&z(i,e,t[e]);return i},k=(i,t)=>vt(i,wt(t));class o{static card(t){return k(U({},t),{state:o.state(t.state),due:o.time(t.due),last_review:t.last_review?o.time(t.last_review):void 0})}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),r=t.slice(1).toLowerCase(),a=l[`${e}${r}`];if(a===void 0)throw new Error(`Invalid rating:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),r=t.slice(1).toLowerCase(),a=c[`${e}${r}`];if(a===void 0)throw new Error(`Invalid state:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return k(U({},t),{due:o.time(t.due),rating:o.rating(t.rating),state:o.state(t.state),review:o.time(t.review)})}}Date.prototype.scheduler=function(i,t){return q(this,i,t)},Date.prototype.diff=function(i,t){return Y(this,i,t)},Date.prototype.format=function(){return W(this)},Date.prototype.dueFormat=function(i,t,e){return X(this,i,t,e)};function q(i,t,e){return new Date(e?o.time(i).getTime()+t*24*60*60*1e3:o.time(i).getTime()+t*60*1e3)}function Y(i,t,e){if(!i||!t)throw new Error("Invalid date");const r=o.time(i).getTime()-o.time(t).getTime();let a=0;switch(e){case"days":a=Math.floor(r/(24*60*60*1e3));break;case"minutes":a=Math.floor(r/(60*1e3));break}return a}function W(i){const t=o.time(i),e=t.getFullYear(),r=t.getMonth()+1,a=t.getDate(),s=t.getHours(),n=t.getMinutes(),u=t.getSeconds();return`${e}-${S(r)}-${S(a)} ${S(s)}:${S(n)}:${S(u)}`}function S(i){return i<10?`0${i}`:`${i}`}const L=[60,60,24,31,12],I=["second","min","hour","day","month","year"];function X(i,t,e,r=I){i=o.time(i),t=o.time(t),r.length!==I.length&&(r=I);let a=i.getTime()-t.getTime(),s;for(a/=1e3,s=0;s<L.length&&!(a<L[s]);s++)a/=L[s];return`${Math.floor(a)}${e?r[s]:""}`}function xt(i){return o.time(i)}function Mt(i){return o.state(i)}function Et(i){return o.rating(i)}const B=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),Rt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function V(i,t,e){let r=1;for(const n of Rt)r+=n.factor*Math.max(Math.min(i,n.end)-n.start,0);i=Math.min(i,e);let a=Math.max(2,Math.round(i-r));const s=Math.min(Math.round(i+r),e);return i>t&&(a=Math.max(a,t+1)),a=Math.min(a,s),{min_ivl:a,max_ivl:s}}function p(i,t,e){return Math.min(Math.max(i,t),e)}function J(i,t){const e=Date.UTC(i.getUTCFullYear(),i.getUTCMonth(),i.getUTCDate()),r=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((r-e)/864e5)}const $t="5.0.0",K=.9,Q=36500,Z=!1,tt=!0,et=Object.freeze(["1m","10m"]),it=Object.freeze(["10m"]),Ft=`v${$t} using FSRS-6.0`,m=.001,At=36500,x=100,N=.5,rt=.2,O=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,rt]),at=2,st=i=>[[m,x],[m,x],[m,x],[m,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,i],[0,i],[0,.8],[.1,.8]],E=(i,t)=>{let e=at;if(Math.max(0,t)>1){const r=-(Math.log(i[11])+Math.log(Math.pow(2,i[13])-1)+i[14]*.3)/t;e=p(+r.toFixed(8),.01,2)}return st(e).map(([r,a],s)=>p(i[s],r,a))},Dt=i=>{if(i.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${i}`);if(![17,19,21].includes(i.length))throw Error(`Invalid parameter length: ${i.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return i},R=i=>{if(i===void 0)return[...O];switch(i.length){case 21:return[...i];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...i,0,N];case 17:{const t=[...i];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,N])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...O]}},P=i=>{var t,e;const r=Array.isArray(i==null?void 0:i.learning_steps)?i.learning_steps:et,a=Array.isArray(i==null?void 0:i.relearning_steps)?i.relearning_steps:it,s=E(R(i==null?void 0:i.w),a.length);return{request_retention:(i==null?void 0:i.request_retention)||K,maximum_interval:(i==null?void 0:i.maximum_interval)||Q,w:s,enable_fuzz:(t=i==null?void 0:i.enable_fuzz)!=null?t:Z,enable_short_term:(e=i==null?void 0:i.enable_short_term)!=null?e:tt,learning_steps:r,relearning_steps:a}};function $(i,t){const e={due:i?o.time(i):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:c.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}var Lt=Object.defineProperty,It=(i,t,e)=>t in i?Lt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,F=(i,t,e)=>It(i,typeof t!="symbol"?t+"":t,e);let Nt=class{constructor(t){F(this,"c"),F(this,"s0"),F(this,"s1"),F(this,"s2");const e=Ot();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}};function Ot(){let i=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){i+=t.charCodeAt(e);let r=.02519603282416938*i;i=r>>>0,r-=i,r*=i,i=r>>>0,r-=i,i+=r*4294967296}return(i>>>0)*23283064365386963e-26}}function Pt(i){const t=new Nt(i),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=r=>(t.state=r,e),e}var jt=Object.defineProperty,Ct=(i,t,e)=>t in i?jt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,A=(i,t,e)=>Ct(i,typeof t!="symbol"?t+"":t,e);const j=i=>{const t=typeof i=="number"?-i:-i[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function D(i,t,e){const{decay:r,factor:a}=j(i);return+Math.pow(1+a*t/e,r).toFixed(8)}class nt{constructor(t){A(this,"param"),A(this,"intervalModifier"),A(this,"_seed"),A(this,"forgetting_curve"),this.param=new Proxy(P(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=D.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:r}=j(this.param.w);return+((Math.pow(t,1/e)-1)/r).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,r,a){return r==="request_retention"&&Number.isFinite(a)?t.intervalModifier=t.calculate_interval_modifier(Number(a)):r==="w"&&(a=E(R(a),e.relearning_steps.length),t.forgetting_curve=D.bind(this,a),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,r,a),!0}}}update_parameters(t){const e=P(t);for(const r in e)if(r in this.param){const a=r;this.param[a]=e[a]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return p(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const r=Pt(this._seed)(),{min_ivl:a,max_ivl:s}=V(t,e,this.param.maximum_interval);return Math.floor(r*(s-a+1)+a)}next_interval(t,e){const r=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(r,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const r=-this.param.w[6]*(e-3),a=t+this.linear_damping(r,t);return p(this.mean_reversion(this.init_difficulty(l.Easy),a),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,r,a){const s=l.Hard===a?this.param.w[15]:1,n=l.Easy===a?this.param.w[16]:1;return+p(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-r)*this.param.w[10])-1)*s*n),m,36500).toFixed(8)}next_forget_stability(t,e,r){return+p(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-r)*this.param.w[14]),m,36500).toFixed(8)}next_short_term_stability(t,e){const r=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),a=e>=3?Math.max(r,1):r;return+p(t*a,m,36500).toFixed(8)}next_state(t,e,r){const{difficulty:a,stability:s}=t!=null?t:{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(r<0||r>4)throw new Error(`Invalid grade "${r}"`);if(a===0&&s===0)return{difficulty:this.init_difficulty(r),stability:this.init_stability(r)};if(r===0)return{difficulty:a,stability:s};if(a<1||s<m)throw new Error(`Invalid memory state { difficulty: ${a}, stability: ${s} }`);const n=this.forgetting_curve(e,s),u=this.next_recall_stability(a,s,n,r),h=this.next_forget_stability(a,s,n),f=this.next_short_term_stability(s,r);let _=u;if(r===1){let[y,v]=[0,0];this.param.enable_short_term&&(y=this.param.w[17],v=this.param.w[18]);const g=s/Math.exp(y*v);_=p(+g.toFixed(8),m,h)}return e===0&&this.param.enable_short_term&&(_=f),{difficulty:this.next_difficulty(a,r),stability:_}}}function lt(){const i=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${i}_${t}_${e}`}function Ht(i){return function(){var t;const e=(t=Reflect.get(this.current,i))!=null?t:0,r=this.current.reps;return String(e+r||0)}}const ut=i=>{const t=i.slice(-1),e=parseInt(i.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${i}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${i}, expected m/h/d`)}},dt=(i,t,e)=>{const r=t===c.Relearning||t===c.Review?i.relearning_steps:i.learning_steps,a=r.length;if(a===0||e>=a)return{};const s=r[0],n=ut,u=()=>n(s),h=()=>{if(a===1)return Math.round(n(s)*1.5);const g=r[1];return Math.round((n(s)+n(g))/2)},f=g=>g<0||g>=a?null:r[g],_=g=>n(g),y={},v=f(Math.max(0,e));if(t===c.Review)return y[l.Again]={scheduled_minutes:n(v),next_step:0},y;{y[l.Again]={scheduled_minutes:u(),next_step:0},y[l.Hard]={scheduled_minutes:h(),next_step:e};const g=f(e+1);if(g){const b=_(g);b&&(y[l.Good]={scheduled_minutes:Math.round(b),next_step:e+1})}}return y};var M=(i=>(i.SCHEDULER="Scheduler",i.LEARNING_STEPS="LearningSteps",i.SEED="Seed",i))(M||{}),Tt=Object.defineProperty,Gt=(i,t,e)=>t in i?Tt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,w=(i,t,e)=>Gt(i,typeof t!="symbol"?t+"":t,e);class C{constructor(t,e,r,a){w(this,"last"),w(this,"current"),w(this,"review_time"),w(this,"next",new Map),w(this,"algorithm"),w(this,"strategies"),this.algorithm=r,this.last=o.card(t),this.current=o.card(t),this.review_time=o.time(e),this.strategies=a,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let r=0;t!==c.New&&e&&(r=J(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=r,this.current.reps+=1;let a=lt;if(this.strategies){const s=this.strategies.get(M.SEED);s&&(a=s)}this.algorithm.seed=a.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of B)yield this.review(t)}review(t){const{state:e}=this.last;let r;switch(this.checkGrade(t),e){case c.New:r=this.newState(t);break;case c.Learning:case c.Relearning:r=this.learningState(t);break;case c.Review:r=this.reviewState(t);break}return r}buildLog(t){const{last_review:e,due:r,elapsed_days:a}=this.last;return{rating:t,state:this.current.state,due:e||r,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:a,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}var zt=Object.defineProperty,Ut=(i,t,e)=>t in i?zt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,kt=(i,t,e)=>Ut(i,t+"",e);let ot=class extends C{constructor(t,e,r,a){super(t,e,r,a),kt(this,"learningStepsStrategy");let s=dt;if(this.strategies){const n=this.strategies.get(M.LEARNING_STEPS);n&&(s=n)}this.learningStepsStrategy=s}getLearningInfo(t,e){var r,a,s,n;const u=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const h=this.learningStepsStrategy(u,t.state,this.current.state===c.Learning?t.learning_steps+1:t.learning_steps),f=Math.max(0,(a=(r=h[e])==null?void 0:r.scheduled_minutes)!=null?a:0),_=Math.max(0,(n=(s=h[e])==null?void 0:s.next_step)!=null?n:0);return{scheduled_minutes:f,next_steps:_}}applyLearningSteps(t,e,r){const{scheduled_minutes:a,next_steps:s}=this.getLearningInfo(this.current,e);if(a>0&&a<1440)t.learning_steps=s,t.scheduled_days=0,t.state=r,t.due=this.review_time.scheduler(Math.round(a),!1);else if(t.state=c.Review,a>=1440)t.learning_steps=s,t.due=this.review_time.scheduler(Math.round(a),!1),t.scheduled_days=Math.floor(a/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const r=o.card(this.current);r.difficulty=this.algorithm.init_difficulty(t),r.stability=this.algorithm.init_stability(t),this.applyLearningSteps(r,t,c.Learning);const a={card:r,log:this.buildLog(t)};return this.next.set(t,a),a}learningState(t){const e=this.next.get(t);if(e)return e;const{state:r,difficulty:a,stability:s}=this.last,n=o.card(this.current);n.difficulty=this.algorithm.next_difficulty(a,t),n.stability=this.algorithm.next_short_term_stability(s,t),this.applyLearningSteps(n,t,r);const u={card:n,log:this.buildLog(t)};return this.next.set(t,u),u}reviewState(t){const e=this.next.get(t);if(e)return e;const r=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(r,s),u=o.card(this.current),h=o.card(this.current),f=o.card(this.current),_=o.card(this.current);this.next_ds(u,h,f,_,a,s,n),this.next_interval(h,f,_,r),this.next_state(h,f,_),this.applyLearningSteps(u,l.Again,c.Relearning),u.lapses+=1;const y={card:u,log:this.buildLog(l.Again)},v={card:h,log:super.buildLog(l.Hard)},g={card:f,log:super.buildLog(l.Good)},b={card:_,log:super.buildLog(l.Easy)};return this.next.set(l.Again,y),this.next.set(l.Hard,v),this.next.set(l.Good,g),this.next.set(l.Easy,b),this.next.get(t)}next_ds(t,e,r,a,s,n,u){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const h=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),f=this.algorithm.next_forget_stability(s,n,u);t.stability=p(+h.toFixed(8),m,f),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,u,l.Hard),r.difficulty=this.algorithm.next_difficulty(s,l.Good),r.stability=this.algorithm.next_recall_stability(s,n,u,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,u,l.Easy)}next_interval(t,e,r,a){let s,n;s=this.algorithm.next_interval(t.stability,a),n=this.algorithm.next_interval(e.stability,a),s=Math.min(s,n),n=Math.max(n,s+1);const u=Math.max(this.algorithm.next_interval(r.stability,a),n+1);t.scheduled_days=s,t.due=this.review_time.scheduler(s,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),r.scheduled_days=u,r.due=this.review_time.scheduler(u,!0)}next_state(t,e,r){t.state=c.Review,t.learning_steps=0,e.state=c.Review,e.learning_steps=0,r.state=c.Review,r.learning_steps=0}};class ht extends C{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const r=o.card(this.current),a=o.card(this.current),s=o.card(this.current),n=o.card(this.current);return this.init_ds(r,a,s,n),this.next_interval(r,a,s,n,0),this.next_state(r,a,s,n),this.update_next(r,a,s,n),this.next.get(t)}init_ds(t,e,r,a){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),r.difficulty=this.algorithm.init_difficulty(l.Good),r.stability=this.algorithm.init_stability(l.Good),a.difficulty=this.algorithm.init_difficulty(l.Easy),a.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const r=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(r,s),u=o.card(this.current),h=o.card(this.current),f=o.card(this.current),_=o.card(this.current);return this.next_ds(u,h,f,_,a,s,n),this.next_interval(u,h,f,_,r),this.next_state(u,h,f,_),u.lapses+=1,this.update_next(u,h,f,_),this.next.get(t)}next_ds(t,e,r,a,s,n,u){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const h=this.algorithm.next_forget_stability(s,n,u);t.stability=p(n,m,h),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,u,l.Hard),r.difficulty=this.algorithm.next_difficulty(s,l.Good),r.stability=this.algorithm.next_recall_stability(s,n,u,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,u,l.Easy)}next_interval(t,e,r,a,s){let n,u,h,f;n=this.algorithm.next_interval(t.stability,s),u=this.algorithm.next_interval(e.stability,s),h=this.algorithm.next_interval(r.stability,s),f=this.algorithm.next_interval(a.stability,s),n=Math.min(n,u),u=Math.max(u,n+1),h=Math.max(h,u+1),f=Math.max(f,h+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=u,e.due=this.review_time.scheduler(u,!0),r.scheduled_days=h,r.due=this.review_time.scheduler(h,!0),a.scheduled_days=f,a.due=this.review_time.scheduler(f,!0)}next_state(t,e,r,a){t.state=c.Review,t.learning_steps=0,e.state=c.Review,e.learning_steps=0,r.state=c.Review,r.learning_steps=0,a.state=c.Review,a.learning_steps=0}update_next(t,e,r,a){const s={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},u={card:r,log:super.buildLog(l.Good)},h={card:a,log:super.buildLog(l.Easy)};this.next.set(l.Again,s),this.next.set(l.Hard,n),this.next.set(l.Good,u),this.next.set(l.Easy,h)}}var qt=Object.defineProperty,Yt=Object.defineProperties,Wt=Object.getOwnPropertyDescriptors,ct=Object.getOwnPropertySymbols,Xt=Object.prototype.hasOwnProperty,Bt=Object.prototype.propertyIsEnumerable,H=(i,t,e)=>t in i?qt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,Vt=(i,t)=>{for(var e in t||(t={}))Xt.call(t,e)&&H(i,e,t[e]);if(ct)for(var e of ct(t))Bt.call(t,e)&&H(i,e,t[e]);return i},Jt=(i,t)=>Yt(i,Wt(t)),Kt=(i,t,e)=>H(i,t+"",e);class Qt{constructor(t){Kt(this,"fsrs"),this.fsrs=t}replay(t,e,r){return this.fsrs.next(t,e,r)}handleManualRating(t,e,r,a,s,n,u){if(typeof e=="undefined")throw new Error("reschedule: state is required for manual rating");let h,f;if(e===c.New)h={rating:l.Manual,state:e,due:u!=null?u:r,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:r},f=$(r),f.last_review=r;else{if(typeof u=="undefined")throw new Error("reschedule: due is required for manual rating");const _=u.diff(r,"days");h={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:r},f=Jt(Vt({},t),{state:e,due:u,last_review:r,stability:s||t.stability,difficulty:n||t.difficulty,elapsed_days:a,scheduled_days:_,reps:t.reps+1})}return{card:f,log:h}}reschedule(t,e){const r=[];let a=$(t.due);for(const s of e){let n;if(s.review=o.time(s.review),s.rating===l.Manual){let u=0;a.state!==c.New&&a.last_review&&(u=s.review.diff(a.last_review,"days")),n=this.handleManualRating(a,s.state,s.review,u,s.stability,s.difficulty,s.due?o.time(s.due):void 0)}else n=this.replay(a,s.review,s.rating);r.push(n),a=n.card}return r}calculateManualRecord(t,e,r,a){if(!r)return null;const{card:s,log:n}=r,u=o.card(t);return u.due.getTime()===s.due.getTime()?null:(u.scheduled_days=s.due.diff(u.due,"days"),this.handleManualRating(u,s.state,o.time(e),n.elapsed_days,a?s.stability:void 0,a?s.difficulty:void 0,s.due))}}var Zt=Object.defineProperty,te=Object.defineProperties,ee=Object.getOwnPropertyDescriptors,ft=Object.getOwnPropertySymbols,ie=Object.prototype.hasOwnProperty,re=Object.prototype.propertyIsEnumerable,T=(i,t,e)=>t in i?Zt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,_t=(i,t)=>{for(var e in t||(t={}))ie.call(t,e)&&T(i,e,t[e]);if(ft)for(var e of ft(t))re.call(t,e)&&T(i,e,t[e]);return i},gt=(i,t)=>te(i,ee(t)),yt=(i,t,e)=>T(i,typeof t!="symbol"?t+"":t,e);class mt extends nt{constructor(t){super(t),yt(this,"strategyHandler",new Map),yt(this,"Scheduler");const{enable_short_term:e}=this.parameters;this.Scheduler=e?ot:ht}params_handler_proxy(){const t=this;return{set:function(e,r,a){return r==="request_retention"&&Number.isFinite(a)?t.intervalModifier=t.calculate_interval_modifier(Number(a)):r==="enable_short_term"?t.Scheduler=a===!0?ot:ht:r==="w"&&(a=E(R(a),e.relearning_steps.length),t.forgetting_curve=D.bind(this,a),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,r,a),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const r=this.strategyHandler.get(M.SCHEDULER)||this.Scheduler;return new r(t,e,this,this.strategyHandler)}repeat(t,e,r){const a=this.getScheduler(t,e).preview();return r&&typeof r=="function"?r(a):a}next(t,e,r,a){const s=this.getScheduler(t,e),n=o.rating(r);if(n===l.Manual)throw new Error("Cannot review a manual rating");const u=s.review(n);return a&&typeof a=="function"?a(u):u}get_retrievability(t,e,r=!0){const a=o.card(t);e=e?o.time(e):new Date;const s=a.state!==c.New?Math.max(e.diff(a.last_review,"days"),0):0,n=a.state!==c.New?this.forgetting_curve(s,+a.stability.toFixed(8)):0;return r?`${(n*100).toFixed(2)}%`:n}rollback(t,e,r){const a=o.card(t),s=o.review_log(e);if(s.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,u,h;switch(s.state){case c.New:n=s.due,u=void 0,h=0;break;case c.Learning:case c.Relearning:case c.Review:n=s.review,u=s.due,h=a.lapses-(s.rating===l.Again&&s.state===c.Review?1:0);break}const f=gt(_t({},a),{due:n,stability:s.stability,difficulty:s.difficulty,elapsed_days:s.last_elapsed_days,scheduled_days:s.scheduled_days,reps:Math.max(0,a.reps-1),lapses:Math.max(0,h),learning_steps:s.learning_steps,state:s.state,last_review:u});return r&&typeof r=="function"?r(f):f}forget(t,e,r=!1,a){const s=o.card(t);e=o.time(e);const n=s.state===c.New?0:e.diff(s.last_review,"days"),u={rating:l.Manual,state:s.state,due:s.due,stability:s.stability,difficulty:s.difficulty,elapsed_days:0,last_elapsed_days:s.elapsed_days,scheduled_days:n,learning_steps:s.learning_steps,review:e},h={card:gt(_t({},s),{due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:r?0:s.reps,lapses:r?0:s.lapses,learning_steps:0,state:c.New,last_review:s.last_review}),log:u};return a&&typeof a=="function"?a(h):h}reschedule(t,e=[],r={}){const{recordLogHandler:a,reviewsOrderBy:s,skipManual:n=!0,now:u=new Date,update_memory_state:h=!1}=r;s&&typeof s=="function"&&e.sort(s),n&&(e=e.filter(b=>b.rating!==l.Manual));const f=new Qt(this),_=f.reschedule(r.first_card||$(),e),y=_.length,v=o.card(t),g=f.calculateManualRecord(v,u,y?_[y-1]:void 0,h);return a&&typeof a=="function"?{collections:_.map(a),reschedule_item:g?a(g):null}:{collections:_,reschedule_item:g}}}const ae=i=>new mt(i||{});d.AbstractScheduler=C,d.BasicLearningStepsStrategy=dt,d.CLAMP_PARAMETERS=st,d.ConvertStepUnitToMinutes=ut,d.DefaultInitSeedStrategy=lt,d.FSRS=mt,d.FSRS5_DEFAULT_DECAY=N,d.FSRS6_DEFAULT_DECAY=rt,d.FSRSAlgorithm=nt,d.FSRSVersion=Ft,d.GenSeedStrategyWithCardId=Ht,d.Grades=B,d.INIT_S_MAX=x,d.Rating=l,d.S_MAX=At,d.S_MIN=m,d.State=c,d.StrategyMode=M,d.TypeConvert=o,d.W17_W18_Ceiling=at,d.checkParameters=Dt,d.clamp=p,d.clipParameters=E,d.computeDecayFactor=j,d.createEmptyCard=$,d.dateDiffInDays=J,d.date_diff=Y,d.date_scheduler=q,d.default_enable_fuzz=Z,d.default_enable_short_term=tt,d.default_learning_steps=et,d.default_maximum_interval=Q,d.default_relearning_steps=it,d.default_request_retention=K,d.default_w=O,d.fixDate=xt,d.fixRating=Et,d.fixState=Mt,d.forgetting_curve=D,d.formatDate=W,d.fsrs=ae,d.generatorParameters=P,d.get_fuzz_range=V,d.migrateParameters=R,d.show_diff_message=X});
|
|
1
|
+
(function(d,c){typeof exports=="object"&&typeof module!="undefined"?c(exports):typeof define=="function"&&define.amd?define(["exports"],c):(d=typeof globalThis!="undefined"?globalThis:d||self,c(d.FSRS={}))})(this,function(d){"use strict";var c=(i=>(i[i.New=0]="New",i[i.Learning=1]="Learning",i[i.Review=2]="Review",i[i.Relearning=3]="Relearning",i))(c||{}),l=(i=>(i[i.Manual=0]="Manual",i[i.Again=1]="Again",i[i.Hard=2]="Hard",i[i.Good=3]="Good",i[i.Easy=4]="Easy",i))(l||{}),pt=Object.defineProperty,vt=Object.defineProperties,wt=Object.getOwnPropertyDescriptors,G=Object.getOwnPropertySymbols,bt=Object.prototype.hasOwnProperty,St=Object.prototype.propertyIsEnumerable,z=(i,t,e)=>t in i?pt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,U=(i,t)=>{for(var e in t||(t={}))bt.call(t,e)&&z(i,e,t[e]);if(G)for(var e of G(t))St.call(t,e)&&z(i,e,t[e]);return i},k=(i,t)=>vt(i,wt(t));class o{static card(t){return k(U({},t),{state:o.state(t.state),due:o.time(t.due),last_review:t.last_review?o.time(t.last_review):void 0})}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),r=t.slice(1).toLowerCase(),a=l[`${e}${r}`];if(a===void 0)throw new Error(`Invalid rating:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),r=t.slice(1).toLowerCase(),a=c[`${e}${r}`];if(a===void 0)throw new Error(`Invalid state:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return k(U({},t),{due:o.time(t.due),rating:o.rating(t.rating),state:o.state(t.state),review:o.time(t.review)})}}Date.prototype.scheduler=function(i,t){return q(this,i,t)},Date.prototype.diff=function(i,t){return Y(this,i,t)},Date.prototype.format=function(){return W(this)},Date.prototype.dueFormat=function(i,t,e){return X(this,i,t,e)};function q(i,t,e){return new Date(e?o.time(i).getTime()+t*24*60*60*1e3:o.time(i).getTime()+t*60*1e3)}function Y(i,t,e){if(!i||!t)throw new Error("Invalid date");const r=o.time(i).getTime()-o.time(t).getTime();let a=0;switch(e){case"days":a=Math.floor(r/(24*60*60*1e3));break;case"minutes":a=Math.floor(r/(60*1e3));break}return a}function W(i){const t=o.time(i),e=t.getFullYear(),r=t.getMonth()+1,a=t.getDate(),s=t.getHours(),n=t.getMinutes(),u=t.getSeconds();return`${e}-${S(r)}-${S(a)} ${S(s)}:${S(n)}:${S(u)}`}function S(i){return i<10?`0${i}`:`${i}`}const L=[60,60,24,31,12],I=["second","min","hour","day","month","year"];function X(i,t,e,r=I){i=o.time(i),t=o.time(t),r.length!==I.length&&(r=I);let a=i.getTime()-t.getTime(),s;for(a/=1e3,s=0;s<L.length&&!(a<L[s]);s++)a/=L[s];return`${Math.floor(a)}${e?r[s]:""}`}function xt(i){return o.time(i)}function Mt(i){return o.state(i)}function Et(i){return o.rating(i)}const B=Object.freeze([l.Again,l.Hard,l.Good,l.Easy]),Rt=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function V(i,t,e){let r=1;for(const n of Rt)r+=n.factor*Math.max(Math.min(i,n.end)-n.start,0);i=Math.min(i,e);let a=Math.max(2,Math.round(i-r));const s=Math.min(Math.round(i+r),e);return i>t&&(a=Math.max(a,t+1)),a=Math.min(a,s),{min_ivl:a,max_ivl:s}}function p(i,t,e){return Math.min(Math.max(i,t),e)}function J(i,t){const e=Date.UTC(i.getUTCFullYear(),i.getUTCMonth(),i.getUTCDate()),r=Date.UTC(t.getUTCFullYear(),t.getUTCMonth(),t.getUTCDate());return Math.floor((r-e)/864e5)}const $t="5.0.1",K=.9,Q=36500,Z=!1,tt=!0,et=Object.freeze(["1m","10m"]),it=Object.freeze(["10m"]),Ft=`v${$t} using FSRS-6.0`,m=.001,At=36500,x=100,N=.5,rt=.2,O=Object.freeze([.2172,1.1771,3.2602,16.1507,7.0114,.57,2.0966,.0069,1.5261,.112,1.0178,1.849,.1133,.3127,2.2934,.2191,3.0004,.7536,.3332,.1437,rt]),at=2,st=i=>[[m,x],[m,x],[m,x],[m,x],[1,10],[.001,4],[.001,4],[.001,.75],[0,4.5],[0,.8],[.001,3.5],[.001,5],[.001,.25],[.001,.9],[0,4],[0,1],[1,6],[0,i],[0,i],[0,.8],[.1,.8]],E=(i,t)=>{let e=at;if(Math.max(0,t)>1){const r=-(Math.log(i[11])+Math.log(Math.pow(2,i[13])-1)+i[14]*.3)/t;e=p(+r.toFixed(8),.01,2)}return st(e).map(([r,a],s)=>p(i[s],r,a))},Dt=i=>{if(i.find(t=>!isFinite(t)&&!isNaN(t))!==void 0)throw Error(`Non-finite or NaN value in parameters ${i}`);if(![17,19,21].includes(i.length))throw Error(`Invalid parameter length: ${i.length}. Must be 17, 19 or 21 for FSRSv4, 5 and 6 respectively.`);return i},R=i=>{if(i===void 0)return[...O];switch(i.length){case 21:return[...i];case 19:return console.debug("[FSRS-6]auto fill w from 19 to 21 length"),[...i,0,N];case 17:{const t=[...i];return t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),t[6]=+(t[6]+.5).toFixed(8),console.debug("[FSRS-6]auto fill w from 17 to 21 length"),t.concat([0,0,0,N])}default:return console.warn("[FSRS]Invalid parameters length, using default parameters"),[...O]}},P=i=>{var t,e;const r=Array.isArray(i==null?void 0:i.learning_steps)?i.learning_steps:et,a=Array.isArray(i==null?void 0:i.relearning_steps)?i.relearning_steps:it,s=E(R(i==null?void 0:i.w),a.length);return{request_retention:(i==null?void 0:i.request_retention)||K,maximum_interval:(i==null?void 0:i.maximum_interval)||Q,w:s,enable_fuzz:(t=i==null?void 0:i.enable_fuzz)!=null?t:Z,enable_short_term:(e=i==null?void 0:i.enable_short_term)!=null?e:tt,learning_steps:r,relearning_steps:a}};function $(i,t){const e={due:i?o.time(i):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,learning_steps:0,state:c.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}var Lt=Object.defineProperty,It=(i,t,e)=>t in i?Lt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,F=(i,t,e)=>It(i,typeof t!="symbol"?t+"":t,e);let Nt=class{constructor(t){F(this,"c"),F(this,"s0"),F(this,"s1"),F(this,"s2");const e=Ot();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}};function Ot(){let i=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){i+=t.charCodeAt(e);let r=.02519603282416938*i;i=r>>>0,r-=i,r*=i,i=r>>>0,r-=i,i+=r*4294967296}return(i>>>0)*23283064365386963e-26}}function Pt(i){const t=new Nt(i),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=r=>(t.state=r,e),e}var jt=Object.defineProperty,Ct=(i,t,e)=>t in i?jt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,A=(i,t,e)=>Ct(i,typeof t!="symbol"?t+"":t,e);const j=i=>{const t=typeof i=="number"?-i:-i[20],e=Math.exp(Math.pow(t,-1)*Math.log(.9))-1;return{decay:t,factor:+e.toFixed(8)}};function D(i,t,e){const{decay:r,factor:a}=j(i);return+Math.pow(1+a*t/e,r).toFixed(8)}class nt{constructor(t){A(this,"param"),A(this,"intervalModifier"),A(this,"_seed"),A(this,"forgetting_curve"),this.param=new Proxy(P(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention),this.forgetting_curve=D.bind(this,this.param.w)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");const{decay:e,factor:r}=j(this.param.w);return+((Math.pow(t,1/e)-1)/r).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,r,a){return r==="request_retention"&&Number.isFinite(a)?t.intervalModifier=t.calculate_interval_modifier(Number(a)):r==="w"&&(a=E(R(a),e.relearning_steps.length),t.forgetting_curve=D.bind(this,a),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,r,a),!0}}}update_parameters(t){const e=P(t);for(const r in e)if(r in this.param){const a=r;this.param[a]=e[a]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){const e=this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1;return p(+e.toFixed(8),1,10)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const r=Pt(this._seed)(),{min_ivl:a,max_ivl:s}=V(t,e,this.param.maximum_interval);return Math.floor(r*(s-a+1)+a)}next_interval(t,e){const r=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(r,e)}linear_damping(t,e){return+(t*(10-e)/9).toFixed(8)}next_difficulty(t,e){const r=-this.param.w[6]*(e-3),a=t+this.linear_damping(r,t);return p(this.mean_reversion(this.init_difficulty(l.Easy),a),1,10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,r,a){const s=l.Hard===a?this.param.w[15]:1,n=l.Easy===a?this.param.w[16]:1;return+p(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-r)*this.param.w[10])-1)*s*n),m,36500).toFixed(8)}next_forget_stability(t,e,r){return+p(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-r)*this.param.w[14]),m,36500).toFixed(8)}next_short_term_stability(t,e){const r=Math.pow(t,-this.param.w[19])*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),a=e>=3?Math.max(r,1):r;return+p(t*a,m,36500).toFixed(8)}next_state(t,e,r){const{difficulty:a,stability:s}=t!=null?t:{difficulty:0,stability:0};if(e<0)throw new Error(`Invalid delta_t "${e}"`);if(r<0||r>4)throw new Error(`Invalid grade "${r}"`);if(a===0&&s===0)return{difficulty:this.init_difficulty(r),stability:this.init_stability(r)};if(r===0)return{difficulty:a,stability:s};if(a<1||s<m)throw new Error(`Invalid memory state { difficulty: ${a}, stability: ${s} }`);const n=this.forgetting_curve(e,s),u=this.next_recall_stability(a,s,n,r),h=this.next_forget_stability(a,s,n),f=this.next_short_term_stability(s,r);let _=u;if(r===1){let[y,v]=[0,0];this.param.enable_short_term&&(y=this.param.w[17],v=this.param.w[18]);const g=s/Math.exp(y*v);_=p(+g.toFixed(8),m,h)}return e===0&&this.param.enable_short_term&&(_=f),{difficulty:this.next_difficulty(a,r),stability:_}}}function lt(){const i=this.review_time.getTime(),t=this.current.reps,e=this.current.difficulty*this.current.stability;return`${i}_${t}_${e}`}function Ht(i){return function(){var t;const e=(t=Reflect.get(this.current,i))!=null?t:0,r=this.current.reps;return String(e+r||0)}}const ut=i=>{const t=i.slice(-1),e=parseInt(i.slice(0,-1),10);if(isNaN(e)||!Number.isFinite(e)||e<0)throw new Error(`Invalid step value: ${i}`);switch(t){case"m":return e;case"h":return e*60;case"d":return e*1440;default:throw new Error(`Invalid step unit: ${i}, expected m/h/d`)}},dt=(i,t,e)=>{const r=t===c.Relearning||t===c.Review?i.relearning_steps:i.learning_steps,a=r.length;if(a===0||e>=a)return{};const s=r[0],n=ut,u=()=>n(s),h=()=>{if(a===1)return Math.round(n(s)*1.5);const g=r[1];return Math.round((n(s)+n(g))/2)},f=g=>g<0||g>=a?null:r[g],_=g=>n(g),y={},v=f(Math.max(0,e));if(t===c.Review)return y[l.Again]={scheduled_minutes:n(v),next_step:0},y;{y[l.Again]={scheduled_minutes:u(),next_step:0},y[l.Hard]={scheduled_minutes:h(),next_step:e};const g=f(e+1);if(g){const b=_(g);b&&(y[l.Good]={scheduled_minutes:Math.round(b),next_step:e+1})}}return y};var M=(i=>(i.SCHEDULER="Scheduler",i.LEARNING_STEPS="LearningSteps",i.SEED="Seed",i))(M||{}),Tt=Object.defineProperty,Gt=(i,t,e)=>t in i?Tt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,w=(i,t,e)=>Gt(i,typeof t!="symbol"?t+"":t,e);class C{constructor(t,e,r,a){w(this,"last"),w(this,"current"),w(this,"review_time"),w(this,"next",new Map),w(this,"algorithm"),w(this,"strategies"),this.algorithm=r,this.last=o.card(t),this.current=o.card(t),this.review_time=o.time(e),this.strategies=a,this.init()}checkGrade(t){if(!Number.isFinite(t)||t<0||t>4)throw new Error(`Invalid grade "${t}",expected 1-4`)}init(){const{state:t,last_review:e}=this.current;let r=0;t!==c.New&&e&&(r=J(e,this.review_time)),this.current.last_review=this.review_time,this.current.elapsed_days=r,this.current.reps+=1;let a=lt;if(this.strategies){const s=this.strategies.get(M.SEED);s&&(a=s)}this.algorithm.seed=a.call(this)}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of B)yield this.review(t)}review(t){const{state:e}=this.last;let r;switch(this.checkGrade(t),e){case c.New:r=this.newState(t);break;case c.Learning:case c.Relearning:r=this.learningState(t);break;case c.Review:r=this.reviewState(t);break}return r}buildLog(t){const{last_review:e,due:r,elapsed_days:a}=this.last;return{rating:t,state:this.current.state,due:e||r,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:a,scheduled_days:this.current.scheduled_days,learning_steps:this.current.learning_steps,review:this.review_time}}}var zt=Object.defineProperty,Ut=(i,t,e)=>t in i?zt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,kt=(i,t,e)=>Ut(i,t+"",e);let ot=class extends C{constructor(t,e,r,a){super(t,e,r,a),kt(this,"learningStepsStrategy");let s=dt;if(this.strategies){const n=this.strategies.get(M.LEARNING_STEPS);n&&(s=n)}this.learningStepsStrategy=s}getLearningInfo(t,e){var r,a,s,n;const u=this.algorithm.parameters;t.learning_steps=t.learning_steps||0;const h=this.learningStepsStrategy(u,t.state,this.current.state===c.Learning?t.learning_steps+1:t.learning_steps),f=Math.max(0,(a=(r=h[e])==null?void 0:r.scheduled_minutes)!=null?a:0),_=Math.max(0,(n=(s=h[e])==null?void 0:s.next_step)!=null?n:0);return{scheduled_minutes:f,next_steps:_}}applyLearningSteps(t,e,r){const{scheduled_minutes:a,next_steps:s}=this.getLearningInfo(this.current,e);if(a>0&&a<1440)t.learning_steps=s,t.scheduled_days=0,t.state=r,t.due=this.review_time.scheduler(Math.round(a),!1);else if(t.state=c.Review,a>=1440)t.learning_steps=s,t.due=this.review_time.scheduler(Math.round(a),!1),t.scheduled_days=Math.floor(a/1440);else{t.learning_steps=0;const n=this.algorithm.next_interval(t.stability,this.current.elapsed_days);t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0)}}newState(t){const e=this.next.get(t);if(e)return e;const r=o.card(this.current);r.difficulty=this.algorithm.init_difficulty(t),r.stability=this.algorithm.init_stability(t),this.applyLearningSteps(r,t,c.Learning);const a={card:r,log:this.buildLog(t)};return this.next.set(t,a),a}learningState(t){const e=this.next.get(t);if(e)return e;const{state:r,difficulty:a,stability:s}=this.last,n=o.card(this.current);n.difficulty=this.algorithm.next_difficulty(a,t),n.stability=this.algorithm.next_short_term_stability(s,t),this.applyLearningSteps(n,t,r);const u={card:n,log:this.buildLog(t)};return this.next.set(t,u),u}reviewState(t){const e=this.next.get(t);if(e)return e;const r=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(r,s),u=o.card(this.current),h=o.card(this.current),f=o.card(this.current),_=o.card(this.current);this.next_ds(u,h,f,_,a,s,n),this.next_interval(h,f,_,r),this.next_state(h,f,_),this.applyLearningSteps(u,l.Again,c.Relearning),u.lapses+=1;const y={card:u,log:this.buildLog(l.Again)},v={card:h,log:super.buildLog(l.Hard)},g={card:f,log:super.buildLog(l.Good)},b={card:_,log:super.buildLog(l.Easy)};return this.next.set(l.Again,y),this.next.set(l.Hard,v),this.next.set(l.Good,g),this.next.set(l.Easy,b),this.next.get(t)}next_ds(t,e,r,a,s,n,u){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const h=n/Math.exp(this.algorithm.parameters.w[17]*this.algorithm.parameters.w[18]),f=this.algorithm.next_forget_stability(s,n,u);t.stability=p(+h.toFixed(8),m,f),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,u,l.Hard),r.difficulty=this.algorithm.next_difficulty(s,l.Good),r.stability=this.algorithm.next_recall_stability(s,n,u,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,u,l.Easy)}next_interval(t,e,r,a){let s,n;s=this.algorithm.next_interval(t.stability,a),n=this.algorithm.next_interval(e.stability,a),s=Math.min(s,n),n=Math.max(n,s+1);const u=Math.max(this.algorithm.next_interval(r.stability,a),n+1);t.scheduled_days=s,t.due=this.review_time.scheduler(s,!0),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),r.scheduled_days=u,r.due=this.review_time.scheduler(u,!0)}next_state(t,e,r){t.state=c.Review,t.learning_steps=0,e.state=c.Review,e.learning_steps=0,r.state=c.Review,r.learning_steps=0}};class ht extends C{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const r=o.card(this.current),a=o.card(this.current),s=o.card(this.current),n=o.card(this.current);return this.init_ds(r,a,s,n),this.next_interval(r,a,s,n,0),this.next_state(r,a,s,n),this.update_next(r,a,s,n),this.next.get(t)}init_ds(t,e,r,a){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),r.difficulty=this.algorithm.init_difficulty(l.Good),r.stability=this.algorithm.init_stability(l.Good),a.difficulty=this.algorithm.init_difficulty(l.Easy),a.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const r=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(r,s),u=o.card(this.current),h=o.card(this.current),f=o.card(this.current),_=o.card(this.current);return this.next_ds(u,h,f,_,a,s,n),this.next_interval(u,h,f,_,r),this.next_state(u,h,f,_),u.lapses+=1,this.update_next(u,h,f,_),this.next.get(t)}next_ds(t,e,r,a,s,n,u){t.difficulty=this.algorithm.next_difficulty(s,l.Again);const h=this.algorithm.next_forget_stability(s,n,u);t.stability=p(n,m,h),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,u,l.Hard),r.difficulty=this.algorithm.next_difficulty(s,l.Good),r.stability=this.algorithm.next_recall_stability(s,n,u,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,u,l.Easy)}next_interval(t,e,r,a,s){let n,u,h,f;n=this.algorithm.next_interval(t.stability,s),u=this.algorithm.next_interval(e.stability,s),h=this.algorithm.next_interval(r.stability,s),f=this.algorithm.next_interval(a.stability,s),n=Math.min(n,u),u=Math.max(u,n+1),h=Math.max(h,u+1),f=Math.max(f,h+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=u,e.due=this.review_time.scheduler(u,!0),r.scheduled_days=h,r.due=this.review_time.scheduler(h,!0),a.scheduled_days=f,a.due=this.review_time.scheduler(f,!0)}next_state(t,e,r,a){t.state=c.Review,t.learning_steps=0,e.state=c.Review,e.learning_steps=0,r.state=c.Review,r.learning_steps=0,a.state=c.Review,a.learning_steps=0}update_next(t,e,r,a){const s={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},u={card:r,log:super.buildLog(l.Good)},h={card:a,log:super.buildLog(l.Easy)};this.next.set(l.Again,s),this.next.set(l.Hard,n),this.next.set(l.Good,u),this.next.set(l.Easy,h)}}var qt=Object.defineProperty,Yt=Object.defineProperties,Wt=Object.getOwnPropertyDescriptors,ct=Object.getOwnPropertySymbols,Xt=Object.prototype.hasOwnProperty,Bt=Object.prototype.propertyIsEnumerable,H=(i,t,e)=>t in i?qt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,Vt=(i,t)=>{for(var e in t||(t={}))Xt.call(t,e)&&H(i,e,t[e]);if(ct)for(var e of ct(t))Bt.call(t,e)&&H(i,e,t[e]);return i},Jt=(i,t)=>Yt(i,Wt(t)),Kt=(i,t,e)=>H(i,t+"",e);class Qt{constructor(t){Kt(this,"fsrs"),this.fsrs=t}replay(t,e,r){return this.fsrs.next(t,e,r)}handleManualRating(t,e,r,a,s,n,u){if(typeof e=="undefined")throw new Error("reschedule: state is required for manual rating");let h,f;if(e===c.New)h={rating:l.Manual,state:e,due:u!=null?u:r,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:r},f=$(r),f.last_review=r;else{if(typeof u=="undefined")throw new Error("reschedule: due is required for manual rating");const _=u.diff(r,"days");h={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,learning_steps:t.learning_steps,review:r},f=Jt(Vt({},t),{state:e,due:u,last_review:r,stability:s||t.stability,difficulty:n||t.difficulty,elapsed_days:a,scheduled_days:_,reps:t.reps+1})}return{card:f,log:h}}reschedule(t,e){const r=[];let a=$(t.due);for(const s of e){let n;if(s.review=o.time(s.review),s.rating===l.Manual){let u=0;a.state!==c.New&&a.last_review&&(u=s.review.diff(a.last_review,"days")),n=this.handleManualRating(a,s.state,s.review,u,s.stability,s.difficulty,s.due?o.time(s.due):void 0)}else n=this.replay(a,s.review,s.rating);r.push(n),a=n.card}return r}calculateManualRecord(t,e,r,a){if(!r)return null;const{card:s,log:n}=r,u=o.card(t);return u.due.getTime()===s.due.getTime()?null:(u.scheduled_days=s.due.diff(u.due,"days"),this.handleManualRating(u,s.state,o.time(e),n.elapsed_days,a?s.stability:void 0,a?s.difficulty:void 0,s.due))}}var Zt=Object.defineProperty,te=Object.defineProperties,ee=Object.getOwnPropertyDescriptors,ft=Object.getOwnPropertySymbols,ie=Object.prototype.hasOwnProperty,re=Object.prototype.propertyIsEnumerable,T=(i,t,e)=>t in i?Zt(i,t,{enumerable:!0,configurable:!0,writable:!0,value:e}):i[t]=e,_t=(i,t)=>{for(var e in t||(t={}))ie.call(t,e)&&T(i,e,t[e]);if(ft)for(var e of ft(t))re.call(t,e)&&T(i,e,t[e]);return i},gt=(i,t)=>te(i,ee(t)),yt=(i,t,e)=>T(i,typeof t!="symbol"?t+"":t,e);class mt extends nt{constructor(t){super(t),yt(this,"strategyHandler",new Map),yt(this,"Scheduler");const{enable_short_term:e}=this.parameters;this.Scheduler=e?ot:ht}params_handler_proxy(){const t=this;return{set:function(e,r,a){return r==="request_retention"&&Number.isFinite(a)?t.intervalModifier=t.calculate_interval_modifier(Number(a)):r==="enable_short_term"?t.Scheduler=a===!0?ot:ht:r==="w"&&(a=E(R(a),e.relearning_steps.length),t.forgetting_curve=D.bind(this,a),t.intervalModifier=t.calculate_interval_modifier(Number(e.request_retention))),Reflect.set(e,r,a),!0}}}useStrategy(t,e){return this.strategyHandler.set(t,e),this}clearStrategy(t){return t?this.strategyHandler.delete(t):this.strategyHandler.clear(),this}getScheduler(t,e){const r=this.strategyHandler.get(M.SCHEDULER)||this.Scheduler;return new r(t,e,this,this.strategyHandler)}repeat(t,e,r){const a=this.getScheduler(t,e).preview();return r&&typeof r=="function"?r(a):a}next(t,e,r,a){const s=this.getScheduler(t,e),n=o.rating(r);if(n===l.Manual)throw new Error("Cannot review a manual rating");const u=s.review(n);return a&&typeof a=="function"?a(u):u}get_retrievability(t,e,r=!0){const a=o.card(t);e=e?o.time(e):new Date;const s=a.state!==c.New?Math.max(e.diff(a.last_review,"days"),0):0,n=a.state!==c.New?this.forgetting_curve(s,+a.stability.toFixed(8)):0;return r?`${(n*100).toFixed(2)}%`:n}rollback(t,e,r){const a=o.card(t),s=o.review_log(e);if(s.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,u,h;switch(s.state){case c.New:n=s.due,u=void 0,h=0;break;case c.Learning:case c.Relearning:case c.Review:n=s.review,u=s.due,h=a.lapses-(s.rating===l.Again&&s.state===c.Review?1:0);break}const f=gt(_t({},a),{due:n,stability:s.stability,difficulty:s.difficulty,elapsed_days:s.last_elapsed_days,scheduled_days:s.scheduled_days,reps:Math.max(0,a.reps-1),lapses:Math.max(0,h),learning_steps:s.learning_steps,state:s.state,last_review:u});return r&&typeof r=="function"?r(f):f}forget(t,e,r=!1,a){const s=o.card(t);e=o.time(e);const n=s.state===c.New?0:e.diff(s.last_review,"days"),u={rating:l.Manual,state:s.state,due:s.due,stability:s.stability,difficulty:s.difficulty,elapsed_days:0,last_elapsed_days:s.elapsed_days,scheduled_days:n,learning_steps:s.learning_steps,review:e},h={card:gt(_t({},s),{due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:r?0:s.reps,lapses:r?0:s.lapses,learning_steps:0,state:c.New,last_review:s.last_review}),log:u};return a&&typeof a=="function"?a(h):h}reschedule(t,e=[],r={}){const{recordLogHandler:a,reviewsOrderBy:s,skipManual:n=!0,now:u=new Date,update_memory_state:h=!1}=r;s&&typeof s=="function"&&e.sort(s),n&&(e=e.filter(b=>b.rating!==l.Manual));const f=new Qt(this),_=f.reschedule(r.first_card||$(),e),y=_.length,v=o.card(t),g=f.calculateManualRecord(v,u,y?_[y-1]:void 0,h);return a&&typeof a=="function"?{collections:_.map(a),reschedule_item:g?a(g):null}:{collections:_,reschedule_item:g}}}const ae=i=>new mt(i||{});d.AbstractScheduler=C,d.BasicLearningStepsStrategy=dt,d.CLAMP_PARAMETERS=st,d.ConvertStepUnitToMinutes=ut,d.DefaultInitSeedStrategy=lt,d.FSRS=mt,d.FSRS5_DEFAULT_DECAY=N,d.FSRS6_DEFAULT_DECAY=rt,d.FSRSAlgorithm=nt,d.FSRSVersion=Ft,d.GenSeedStrategyWithCardId=Ht,d.Grades=B,d.INIT_S_MAX=x,d.Rating=l,d.S_MAX=At,d.S_MIN=m,d.State=c,d.StrategyMode=M,d.TypeConvert=o,d.W17_W18_Ceiling=at,d.checkParameters=Dt,d.clamp=p,d.clipParameters=E,d.computeDecayFactor=j,d.createEmptyCard=$,d.dateDiffInDays=J,d.date_diff=Y,d.date_scheduler=q,d.default_enable_fuzz=Z,d.default_enable_short_term=tt,d.default_learning_steps=et,d.default_maximum_interval=Q,d.default_relearning_steps=it,d.default_request_retention=K,d.default_w=O,d.fixDate=xt,d.fixRating=Et,d.fixState=Mt,d.forgetting_curve=D,d.formatDate=W,d.fsrs=ae,d.generatorParameters=P,d.get_fuzz_range=V,d.migrateParameters=R,d.show_diff_message=X});
|
|
2
2
|
//# sourceMappingURL=index.umd.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-fsrs",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.1",
|
|
4
4
|
"description": "ts-fsrs is a versatile package written in TypeScript that supports ES modules, CommonJS, and UMD. It implements the Free Spaced Repetition Scheduler (FSRS) algorithm, enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.",
|
|
5
|
+
"types": "dist/index.d.ts",
|
|
6
|
+
"main": "dist/index.cjs",
|
|
7
|
+
"module": "dist/index.mjs",
|
|
5
8
|
"exports": {
|
|
6
9
|
".": {
|
|
7
10
|
"require": "./dist/index.cjs",
|