ts-fsrs 3.1.1 → 3.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -50,7 +50,7 @@ Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Eas
50
50
 
51
51
  More refer:
52
52
  - [Docs - Github Pages](https://ishiko732.github.io/ts-fsrs/)
53
- - [Example.html - Github Pages](https://ishiko732.github.io/example.html)
53
+ - [Example.html - Github Pages](https://ishiko732.github.io/ts-fsrs/example)
54
54
  - [Browser](https://github.com/ishiko732/ts-fsrs/blob/master/example/example.html) (ts-fsrs package using CDN)
55
55
  - [Next.js+Prisma](https://github.com/ishiko732/ts-fsrs-demo)
56
56
 
@@ -1,2 +1,2 @@
1
- "use strict";var t,e,a=require("seedrandom");function s(t,e,a){return new Date(a?t.getTime()+24*e*60*60*1e3:t.getTime()+60*e*1e3)}function i(t,e,a){if(!t||!e)throw new Error("Invalid date");const s=t.getTime()-e.getTime();let i=0;switch(a){case"days":i=Math.floor(s/864e5);break;case"minutes":i=Math.floor(s/6e4)}return i}function r(t){const e=t.getFullYear(),a=t.getMonth()+1,s=t.getDate(),i=t.getHours(),r=t.getMinutes(),d=t.getSeconds();return`${e}-${n(a)}-${n(s)} ${n(i)}:${n(r)}:${n(d)}`}function n(t){return t<10?`0${t}`:`${t}`}exports.State=void 0,(t=exports.State||(exports.State={}))[t.New=0]="New",t[t.Learning=1]="Learning",t[t.Review=2]="Review",t[t.Relearning=3]="Relearning",exports.Rating=void 0,(e=exports.Rating||(exports.Rating={}))[e.Manual=0]="Manual",e[e.Again=1]="Again",e[e.Hard=2]="Hard",e[e.Good=3]="Good",e[e.Easy=4]="Easy",Date.prototype.scheduler=function(t,e){return s(this,t,e)},Date.prototype.diff=function(t,e){return i(this,t,e)},Date.prototype.format=function(){return r(this)},Date.prototype.dueFormat=function(t,e){return l(this,t,e)};const d=[60,60,24,31,12],o=["second","min","hour","day","month","year"];function l(t,e,a,s=o){t=h(t),e=h(e),s.length!==o.length&&(s=o);let i,r=t.getTime()-e.getTime();for(r/=1e3,i=0;i<d.length&&!(r<d[i]);i++)r/=d[i];return`${Math.floor(r)}${a?s[i]:""}`}function h(t){if("object"==typeof t&&t instanceof Date)return t;if("string"==typeof t){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}if("number"==typeof t)return new Date(t);throw new Error(`Invalid date:[${t}]`)}function p(t){if("string"==typeof t)return exports.State[t];if("number"==typeof t)return t;throw new Error(`Invalid state:[${t}]`)}function u(t){if("string"==typeof t)return exports.Rating[t];if("number"==typeof t)return t;throw new Error(`Invalid rating:[${t}]`)}const y=[exports.Rating.Again,exports.Rating.Hard,exports.Rating.Good,exports.Rating.Easy];class c{again;hard;good;easy;last_review;last_elapsed_days;copy(t){return{...t}}constructor(t,e){this.last_review=t.last_review||t.due,this.last_elapsed_days=t.elapsed_days,t.elapsed_days=t.state===exports.State.New?0:e.diff(t.last_review,"days"),t.last_review=e,t.reps+=1,this.again=this.copy(t),this.hard=this.copy(t),this.good=this.copy(t),this.easy=this.copy(t)}update_state(t){return t===exports.State.New?(this.again.state=exports.State.Learning,this.hard.state=exports.State.Learning,this.good.state=exports.State.Learning,this.easy.state=exports.State.Review,this.again.lapses+=1):t===exports.State.Learning||t===exports.State.Relearning?(this.again.state=t,this.hard.state=t,this.good.state=exports.State.Review,this.easy.state=exports.State.Review):t===exports.State.Review&&(this.again.state=exports.State.Relearning,this.hard.state=exports.State.Review,this.good.state=exports.State.Review,this.easy.state=exports.State.Review,this.again.lapses+=1),this}schedule(t,e,a,i){return this.again.scheduled_days=0,this.hard.scheduled_days=e,this.good.scheduled_days=a,this.easy.scheduled_days=i,this.again.due=s(t,5),this.hard.due=e>0?s(t,e,!0):s(t,10),this.good.due=s(t,a,!0),this.easy.due=s(t,i,!0),this}record_log(t,e){return{[exports.Rating.Again]:{card:this.again,log:{rating:exports.Rating.Again,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Hard]:{card:this.hard,log:{rating:exports.Rating.Hard,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Good]:{card:this.good,log:{rating:exports.Rating.Good,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Easy]:{card:this.easy,log:{rating:exports.Rating.Easy,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}}}}}const f=[.4,.6,2.4,5.8,4.93,.94,.86,.01,1.49,.14,.94,2.18,.05,.34,1.26,.29,2.61],_=t=>({request_retention:t?.request_retention||.9,maximum_interval:t?.maximum_interval||36500,w:t?.w||f,enable_fuzz:t?.enable_fuzz||false});class g{param;intervalModifier;seed;constructor(t){this.param=_(t),this.intervalModifier=9*(1/this.param.request_retention-1)}init_ds(t){t.again.difficulty=this.init_difficulty(exports.Rating.Again),t.again.stability=this.init_stability(exports.Rating.Again),t.hard.difficulty=this.init_difficulty(exports.Rating.Hard),t.hard.stability=this.init_stability(exports.Rating.Hard),t.good.difficulty=this.init_difficulty(exports.Rating.Good),t.good.stability=this.init_stability(exports.Rating.Good),t.easy.difficulty=this.init_difficulty(exports.Rating.Easy),t.easy.stability=this.init_stability(exports.Rating.Easy)}next_ds(t,e,a,s){t.again.difficulty=this.next_difficulty(e,exports.Rating.Again),t.again.stability=this.next_forget_stability(t.again.difficulty,a,s),t.hard.difficulty=this.next_difficulty(e,exports.Rating.Hard),t.hard.stability=this.next_recall_stability(t.hard.difficulty,a,s,exports.Rating.Hard),t.good.difficulty=this.next_difficulty(e,exports.Rating.Good),t.good.stability=this.next_recall_stability(t.good.difficulty,a,s,exports.Rating.Good),t.easy.difficulty=this.next_difficulty(e,exports.Rating.Easy),t.easy.stability=this.next_recall_stability(t.easy.difficulty,a,s,exports.Rating.Easy)}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return Math.min(Math.max(this.param.w[4]-(t-3)*this.param.w[5],1),10)}apply_fuzz(t){if(!this.param.enable_fuzz||t<2.5)return t;const e=a(this.seed)();t=Math.round(t);const s=Math.max(2,Math.round(.95*t-1)),i=Math.round(1.05*t+1);return Math.floor(e*(i-s+1)+s)}next_interval(t){const e=this.apply_fuzz(t*this.intervalModifier);return Math.min(Math.max(Math.round(e),1),this.param.maximum_interval)}next_difficulty(t,e){const a=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.param.w[4],a))}constrain_difficulty(t){return Math.min(Math.max(Number(t.toFixed(2)),1),10)}mean_reversion(t,e){return this.param.w[7]*t+(1-this.param.w[7])*e}next_recall_stability(t,e,a,s){const i=exports.Rating.Hard===s?this.param.w[15]:1,r=exports.Rating.Easy===s?this.param.w[16]:1;return e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-a)*this.param.w[10])-1)*i*r)}next_forget_stability(t,e,a){return this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-a)*this.param.w[14])}current_retrievability(t,e){return Math.pow(1+t/(9*e),-1)}}class x extends g{constructor(t){super(t)}preProcessCard(t){return{...t,state:p(t.state),due:h(t.due),last_review:t.last_review?h(t.last_review):void 0}}preProcessDate(t){return h(t)}preProcessLog(t){return{...t,rating:u(t.rating),state:p(t.state),review:h(t.review)}}repeat=(t,e)=>{t=this.preProcessCard(t),e=this.preProcessDate(e);const a=new c(t,e).update_state(t.state);let s,i,r;switch(this.seed=String(e.getTime())+String(t.reps),t.state){case exports.State.New:this.init_ds(a),a.again.due=e.scheduler(1),a.hard.due=e.scheduler(5),a.good.due=e.scheduler(10),s=this.next_interval(a.easy.stability),a.easy.scheduled_days=s,a.easy.due=e.scheduler(s,!0);break;case exports.State.Learning:case exports.State.Relearning:r=0,i=this.next_interval(a.good.stability),s=Math.max(this.next_interval(a.easy.stability),i+1),a.schedule(e,r,i,s);break;case exports.State.Review:{const n=t.elapsed_days,d=t.difficulty,o=t.stability,l=this.current_retrievability(n,o);this.next_ds(a,d,o,l),r=this.next_interval(a.hard.stability),i=this.next_interval(a.good.stability),r=Math.min(r,i),i=Math.max(i,r+1),s=Math.max(this.next_interval(a.easy.stability),i+1),a.schedule(e,r,i,s);break}}return a.record_log(t,e)};get_retrievability=(t,e)=>{if(t=this.preProcessCard(t),e=this.preProcessDate(e),t.state!==exports.State.Review)return;const a=Math.max(e.diff(t.last_review,"days"),0);return(100*this.current_retrievability(a,t.stability)).toFixed(2)+"%"};rollback=(t,e)=>{if(t=this.preProcessCard(t),(e=this.preProcessLog(e)).rating===exports.Rating.Manual)throw new Error("Cannot rollback a manual rating");let a,s,i;switch(e.state){case exports.State.New:a=e.due,s=void 0,i=0;break;case exports.State.Learning:case exports.State.Relearning:case exports.State.Review:a=e.review,s=e.due,i=t.lapses-(e.rating===exports.Rating.Again&&e.state===exports.State.Review?1:0)}return{...t,due:a,stability:e.stability,difficulty:e.difficulty,elapsed_days:e.last_elapsed_days,scheduled_days:e.scheduled_days,reps:Math.max(0,t.reps-1),lapses:Math.max(0,i),state:e.state,last_review:s}};forget=(t,e,a=!1)=>{t=this.preProcessCard(t),e=this.preProcessDate(e);const s=t.state===exports.State.New?0:e.diff(t.last_review,"days"),i={rating:exports.Rating.Manual,state:t.state,due:t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:0,last_elapsed_days:t.elapsed_days,scheduled_days:s,review:e};return{card:{...t,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:a?0:t.reps,lapses:a?0:t.lapses,state:exports.State.New,last_review:t.last_review},log:i}}}exports.FSRS=x,exports.FSRSVersion="3.1.1",exports.Grades=y,exports.SchedulingCard=c,exports.createEmptyCard=t=>({due:t?h(t):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:exports.State.New,last_review:void 0}),exports.date_diff=i,exports.date_scheduler=s,exports.default_enable_fuzz=false,exports.default_maximum_interval=36500,exports.default_request_retention=.9,exports.default_w=f,exports.fixDate=h,exports.fixRating=u,exports.fixState=p,exports.formatDate=r,exports.fsrs=t=>new x(t||{}),exports.generatorParameters=_,exports.show_diff_message=l;
1
+ "use strict";var t,e,a=require("seedrandom");function s(t,e,a){return new Date(a?t.getTime()+24*e*60*60*1e3:t.getTime()+60*e*1e3)}function i(t,e,a){if(!t||!e)throw new Error("Invalid date");const s=t.getTime()-e.getTime();let i=0;switch(a){case"days":i=Math.floor(s/864e5);break;case"minutes":i=Math.floor(s/6e4)}return i}function r(t){const e=t.getFullYear(),a=t.getMonth()+1,s=t.getDate(),i=t.getHours(),r=t.getMinutes(),d=t.getSeconds();return`${e}-${n(a)}-${n(s)} ${n(i)}:${n(r)}:${n(d)}`}function n(t){return t<10?`0${t}`:`${t}`}exports.State=void 0,(t=exports.State||(exports.State={}))[t.New=0]="New",t[t.Learning=1]="Learning",t[t.Review=2]="Review",t[t.Relearning=3]="Relearning",exports.Rating=void 0,(e=exports.Rating||(exports.Rating={}))[e.Manual=0]="Manual",e[e.Again=1]="Again",e[e.Hard=2]="Hard",e[e.Good=3]="Good",e[e.Easy=4]="Easy",Date.prototype.scheduler=function(t,e){return s(this,t,e)},Date.prototype.diff=function(t,e){return i(this,t,e)},Date.prototype.format=function(){return r(this)},Date.prototype.dueFormat=function(t,e){return l(this,t,e)};const d=[60,60,24,31,12],o=["second","min","hour","day","month","year"];function l(t,e,a,s=o){t=h(t),e=h(e),s.length!==o.length&&(s=o);let i,r=t.getTime()-e.getTime();for(r/=1e3,i=0;i<d.length&&!(r<d[i]);i++)r/=d[i];return`${Math.floor(r)}${a?s[i]:""}`}function h(t){if("object"==typeof t&&t instanceof Date)return t;if("string"==typeof t){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}if("number"==typeof t)return new Date(t);throw new Error(`Invalid date:[${t}]`)}function p(t){if("string"==typeof t)return exports.State[t];if("number"==typeof t)return t;throw new Error(`Invalid state:[${t}]`)}function u(t){if("string"==typeof t)return exports.Rating[t];if("number"==typeof t)return t;throw new Error(`Invalid rating:[${t}]`)}const y=[exports.Rating.Again,exports.Rating.Hard,exports.Rating.Good,exports.Rating.Easy];class c{again;hard;good;easy;last_review;last_elapsed_days;copy(t){return{...t}}constructor(t,e){this.last_review=t.last_review||t.due,this.last_elapsed_days=t.elapsed_days,t.elapsed_days=t.state===exports.State.New?0:e.diff(t.last_review,"days"),t.last_review=e,t.reps+=1,this.again=this.copy(t),this.hard=this.copy(t),this.good=this.copy(t),this.easy=this.copy(t)}update_state(t){return t===exports.State.New?(this.again.state=exports.State.Learning,this.hard.state=exports.State.Learning,this.good.state=exports.State.Learning,this.easy.state=exports.State.Review):t===exports.State.Learning||t===exports.State.Relearning?(this.again.state=t,this.hard.state=t,this.good.state=exports.State.Review,this.easy.state=exports.State.Review):t===exports.State.Review&&(this.again.state=exports.State.Relearning,this.hard.state=exports.State.Review,this.good.state=exports.State.Review,this.easy.state=exports.State.Review,this.again.lapses+=1),this}schedule(t,e,a,i){return this.again.scheduled_days=0,this.hard.scheduled_days=e,this.good.scheduled_days=a,this.easy.scheduled_days=i,this.again.due=s(t,5),this.hard.due=e>0?s(t,e,!0):s(t,10),this.good.due=s(t,a,!0),this.easy.due=s(t,i,!0),this}record_log(t,e){return{[exports.Rating.Again]:{card:this.again,log:{rating:exports.Rating.Again,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Hard]:{card:this.hard,log:{rating:exports.Rating.Hard,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Good]:{card:this.good,log:{rating:exports.Rating.Good,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[exports.Rating.Easy]:{card:this.easy,log:{rating:exports.Rating.Easy,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}}}}}const f=[.4,.6,2.4,5.8,4.93,.94,.86,.01,1.49,.14,.94,2.18,.05,.34,1.26,.29,2.61],_=t=>({request_retention:t?.request_retention||.9,maximum_interval:t?.maximum_interval||36500,w:t?.w||f,enable_fuzz:t?.enable_fuzz||false});class g{param;intervalModifier;seed;constructor(t){this.param=_(t),this.intervalModifier=9*(1/this.param.request_retention-1)}init_ds(t){t.again.difficulty=this.init_difficulty(exports.Rating.Again),t.again.stability=this.init_stability(exports.Rating.Again),t.hard.difficulty=this.init_difficulty(exports.Rating.Hard),t.hard.stability=this.init_stability(exports.Rating.Hard),t.good.difficulty=this.init_difficulty(exports.Rating.Good),t.good.stability=this.init_stability(exports.Rating.Good),t.easy.difficulty=this.init_difficulty(exports.Rating.Easy),t.easy.stability=this.init_stability(exports.Rating.Easy)}next_ds(t,e,a,s){t.again.difficulty=this.next_difficulty(e,exports.Rating.Again),t.again.stability=this.next_forget_stability(t.again.difficulty,a,s),t.hard.difficulty=this.next_difficulty(e,exports.Rating.Hard),t.hard.stability=this.next_recall_stability(t.hard.difficulty,a,s,exports.Rating.Hard),t.good.difficulty=this.next_difficulty(e,exports.Rating.Good),t.good.stability=this.next_recall_stability(t.good.difficulty,a,s,exports.Rating.Good),t.easy.difficulty=this.next_difficulty(e,exports.Rating.Easy),t.easy.stability=this.next_recall_stability(t.easy.difficulty,a,s,exports.Rating.Easy)}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return Math.min(Math.max(this.param.w[4]-(t-3)*this.param.w[5],1),10)}apply_fuzz(t){if(!this.param.enable_fuzz||t<2.5)return t;const e=a(this.seed)();t=Math.round(t);const s=Math.max(2,Math.round(.95*t-1)),i=Math.round(1.05*t+1);return Math.floor(e*(i-s+1)+s)}next_interval(t){const e=this.apply_fuzz(t*this.intervalModifier);return Math.min(Math.max(Math.round(e),1),this.param.maximum_interval)}next_difficulty(t,e){const a=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.param.w[4],a))}constrain_difficulty(t){return Math.min(Math.max(Number(t.toFixed(2)),1),10)}mean_reversion(t,e){return this.param.w[7]*t+(1-this.param.w[7])*e}next_recall_stability(t,e,a,s){const i=exports.Rating.Hard===s?this.param.w[15]:1,r=exports.Rating.Easy===s?this.param.w[16]:1;return e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-a)*this.param.w[10])-1)*i*r)}next_forget_stability(t,e,a){return this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-a)*this.param.w[14])}current_retrievability(t,e){return Math.pow(1+t/(9*e),-1)}}class x extends g{constructor(t){super(t)}preProcessCard(t){return{...t,state:p(t.state),due:h(t.due),last_review:t.last_review?h(t.last_review):void 0}}preProcessDate(t){return h(t)}preProcessLog(t){return{...t,rating:u(t.rating),state:p(t.state),review:h(t.review)}}repeat=(t,e)=>{t=this.preProcessCard(t),e=this.preProcessDate(e);const a=new c(t,e).update_state(t.state);let s,i,r;switch(this.seed=String(e.getTime())+String(t.reps),t.state){case exports.State.New:this.init_ds(a),a.again.due=e.scheduler(1),a.hard.due=e.scheduler(5),a.good.due=e.scheduler(10),s=this.next_interval(a.easy.stability),a.easy.scheduled_days=s,a.easy.due=e.scheduler(s,!0);break;case exports.State.Learning:case exports.State.Relearning:r=0,i=this.next_interval(a.good.stability),s=Math.max(this.next_interval(a.easy.stability),i+1),a.schedule(e,r,i,s);break;case exports.State.Review:{const n=t.elapsed_days,d=t.difficulty,o=t.stability,l=this.current_retrievability(n,o);this.next_ds(a,d,o,l),r=this.next_interval(a.hard.stability),i=this.next_interval(a.good.stability),r=Math.min(r,i),i=Math.max(i,r+1),s=Math.max(this.next_interval(a.easy.stability),i+1),a.schedule(e,r,i,s);break}}return a.record_log(t,e)};get_retrievability=(t,e)=>{if(t=this.preProcessCard(t),e=this.preProcessDate(e),t.state!==exports.State.Review)return;const a=Math.max(e.diff(t.last_review,"days"),0);return(100*this.current_retrievability(a,t.stability)).toFixed(2)+"%"};rollback=(t,e)=>{if(t=this.preProcessCard(t),(e=this.preProcessLog(e)).rating===exports.Rating.Manual)throw new Error("Cannot rollback a manual rating");let a,s,i;switch(e.state){case exports.State.New:a=e.due,s=void 0,i=0;break;case exports.State.Learning:case exports.State.Relearning:case exports.State.Review:a=e.review,s=e.due,i=t.lapses-(e.rating===exports.Rating.Again&&e.state===exports.State.Review?1:0)}return{...t,due:a,stability:e.stability,difficulty:e.difficulty,elapsed_days:e.last_elapsed_days,scheduled_days:e.scheduled_days,reps:Math.max(0,t.reps-1),lapses:Math.max(0,i),state:e.state,last_review:s}};forget=(t,e,a=!1)=>{t=this.preProcessCard(t),e=this.preProcessDate(e);const s=t.state===exports.State.New?0:e.diff(t.last_review,"days"),i={rating:exports.Rating.Manual,state:t.state,due:t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:0,last_elapsed_days:t.elapsed_days,scheduled_days:s,review:e};return{card:{...t,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:a?0:t.reps,lapses:a?0:t.lapses,state:exports.State.New,last_review:t.last_review},log:i}}}exports.FSRS=x,exports.FSRSVersion="3.1.2",exports.Grades=y,exports.SchedulingCard=c,exports.createEmptyCard=t=>({due:t?h(t):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:exports.State.New,last_review:void 0}),exports.date_diff=i,exports.date_scheduler=s,exports.default_enable_fuzz=false,exports.default_maximum_interval=36500,exports.default_request_retention=.9,exports.default_w=f,exports.fixDate=h,exports.fixRating=u,exports.fixState=p,exports.formatDate=r,exports.fsrs=t=>new x(t||{}),exports.generatorParameters=_,exports.show_diff_message=l;
2
2
  //# sourceMappingURL=ts-fsrs.cjs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ts-fsrs.cjs.js","sources":["../src/fsrs/models.ts","../src/fsrs/help.ts","../src/fsrs/scheduler.ts","../src/fsrs/default.ts","../src/fsrs/algorithm.ts","../src/fsrs/fsrs.ts"],"sourcesContent":["export type StateType = \"New\" | \"Learning\" | \"Review\" | \"Relearning\";\n\nexport enum State {\n New = 0,\n Learning = 1,\n Review = 2,\n Relearning = 3,\n}\n\nexport type RatingType = \"Again\" | \"Hard\" | \"Good\" | \"Easy\";\n\nexport enum Rating {\n Manual = 0,\n Again = 1,\n Hard = 2,\n Good = 3,\n Easy = 4,\n}\n\ntype ExcludeManual<T> = Exclude<T, Rating.Manual>;\n\nexport type Grade = ExcludeManual<Rating>;\n\nexport interface ReviewLog {\n rating: Rating;\n state: State;\n due: Date;\n stability: number;\n difficulty: number;\n elapsed_days: number;\n last_elapsed_days: number;\n scheduled_days: number;\n review: Date;\n}\nexport type RecordLogItem = {\n card: Card;\n log: ReviewLog;\n};\nexport type RecordLog = {\n [key in Grade]: RecordLogItem;\n};\n\nexport interface Card {\n due: Date; // Due date\n stability: number; // Stability\n difficulty: number; // Difficulty level\n elapsed_days: number; // Number of days elapsed\n scheduled_days: number; // Number of days scheduled\n reps: number; // Repetition count\n lapses: number; // Number of lapses or mistakes\n state: State; // Card's state (New, Learning, Review, Relearning)\n last_review?: Date; // Date of the last review (optional)\n}\n\nexport type CardInput = Card & { state: StateType | State };\nexport type DateInput = Date | number | string;\nexport type ReviewLogInput = ReviewLog & {\n rating: RatingType | Rating;\n state: StateType | State;\n};\n\nexport interface FSRSParameters {\n request_retention: number;\n maximum_interval: number;\n w: number[];\n enable_fuzz: boolean;\n}\n","import type { int, unit } from \"./type\";\nimport { Grade, Rating, State } from \"./models\";\n\ndeclare global {\n export interface Date {\n scheduler(t: int, isDay?: boolean): Date;\n\n diff(pre: Date, unit: unit): int;\n\n format(): string;\n\n dueFormat(last_review: Date, unit?: boolean): string;\n }\n}\n\nDate.prototype.scheduler = function (t: int, isDay?: boolean): Date {\n return date_scheduler(this, t, isDay);\n};\n\n/**\n * 当前时间与之前的时间差值\n * @param pre 比当前时间还要之前\n * @param unit 单位: days | minutes\n */\nDate.prototype.diff = function (pre: Date, unit: unit): int {\n return date_diff(this, pre, unit) as int;\n};\n\nDate.prototype.format = function (): string {\n return formatDate(this);\n};\n\nDate.prototype.dueFormat = function (last_review: Date, unit?: boolean) {\n return show_diff_message(this, last_review, unit);\n};\n\n/**\n * 计算日期和时间的偏移,并返回一个新的日期对象。\n * @param now 当前日期和时间\n * @param t 时间偏移量,当 isDay 为 true 时表示天数,为 false 时表示分钟\n * @param isDay (可选)是否按天数单位进行偏移,默认为 false,表示按分钟单位计算偏移\n * @returns 偏移后的日期和时间对象\n */\nexport function date_scheduler(now: Date, t: number, isDay?: boolean): Date {\n return new Date(\n isDay\n ? now.getTime() + t * 24 * 60 * 60 * 1000\n : now.getTime() + t * 60 * 1000,\n );\n}\n\nexport function date_diff(now: Date, pre: Date, unit: unit): number {\n if (!now || !pre) {\n throw new Error(\"Invalid date\");\n }\n const diff = now.getTime() - pre.getTime();\n let r = 0;\n switch (unit) {\n case \"days\":\n r = Math.floor(diff / (24 * 60 * 60 * 1000));\n break;\n case \"minutes\":\n r = Math.floor(diff / (60 * 1000));\n break;\n }\n return r;\n}\n\nexport function formatDate(date: Date): string {\n const year: number = date.getFullYear();\n const month: number = date.getMonth() + 1;\n const day: number = date.getDate();\n const hours: number = date.getHours();\n const minutes: number = date.getMinutes();\n const seconds: number = date.getSeconds();\n\n return `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(\n minutes,\n )}:${padZero(seconds)}`;\n}\n\nfunction padZero(num: number): string {\n return num < 10 ? `0${num}` : `${num}`;\n}\n\nconst TIMEUNIT = [60, 60, 24, 31, 12];\nconst TIMEUNITFORMAT = [\"second\", \"min\", \"hour\", \"day\", \"month\", \"year\"];\n\nexport function show_diff_message(\n due: Date,\n last_review: Date,\n unit?: boolean,\n timeUnit: string[] = TIMEUNITFORMAT,\n): string {\n due = fixDate(due);\n last_review = fixDate(last_review);\n if (timeUnit.length !== TIMEUNITFORMAT.length) {\n timeUnit = TIMEUNITFORMAT;\n }\n let diff = due.getTime() - last_review.getTime();\n let i;\n diff /= 1000;\n for (i = 0; i < TIMEUNIT.length; i++) {\n if (diff < TIMEUNIT[i]) {\n break;\n } else {\n diff /= TIMEUNIT[i];\n }\n }\n return `${Math.floor(diff)}${unit ? timeUnit[i] : \"\"}`;\n}\n\nexport function fixDate(value: unknown) {\n if (typeof value === \"object\" && value instanceof Date) {\n return value;\n } else if (typeof value === \"string\") {\n const timestamp = Date.parse(value);\n if (!isNaN(timestamp)) {\n return new Date(timestamp);\n } else {\n throw new Error(`Invalid date:[${value}]`);\n }\n } else if (typeof value === \"number\") {\n return new Date(value);\n }\n throw new Error(`Invalid date:[${value}]`);\n}\n\nexport function fixState(value: unknown): State {\n if (typeof value === \"string\") {\n return State[value as keyof typeof State];\n } else if (typeof value === \"number\") {\n return value as State;\n }\n throw new Error(`Invalid state:[${value}]`);\n}\n\nexport function fixRating(value: unknown): Rating {\n if (typeof value === \"string\") {\n return Rating[value as keyof typeof Rating];\n } else if (typeof value === \"number\") {\n return value as Rating;\n }\n throw new Error(`Invalid rating:[${value}]`);\n}\n\nexport const Grades: Grade[] = [\n Rating.Again,\n Rating.Hard,\n Rating.Good,\n Rating.Easy,\n];\n","import { Card, Rating, RecordLog, State } from \"./models\";\nimport { date_scheduler } from \"./help\";\n\nexport class SchedulingCard {\n again: Card;\n hard: Card;\n good: Card;\n easy: Card;\n last_review: Date;\n last_elapsed_days: number;\n\n private copy(card: Card): Card {\n return {\n ...card,\n };\n }\n\n constructor(card: Card, now: Date) {\n this.last_review = card.last_review || card.due;\n this.last_elapsed_days = card.elapsed_days;\n card.elapsed_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\"); //相距时间\n card.last_review = now; // 上次复习时间\n card.reps += 1;\n this.again = this.copy(card);\n this.hard = this.copy(card);\n this.good = this.copy(card);\n this.easy = this.copy(card);\n }\n\n update_state(state: State) {\n if (state === State.New) {\n this.again.state = State.Learning;\n this.hard.state = State.Learning;\n this.good.state = State.Learning;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n } else if (state === State.Learning || state === State.Relearning) {\n this.again.state = state;\n this.hard.state = state;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n } else if (state === State.Review) {\n this.again.state = State.Relearning;\n this.hard.state = State.Review;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n }\n return this;\n }\n\n schedule(\n now: Date,\n hard_interval: number,\n good_interval: number,\n easy_interval: number,\n ): SchedulingCard {\n this.again.scheduled_days = 0;\n this.hard.scheduled_days = hard_interval;\n this.good.scheduled_days = good_interval;\n this.easy.scheduled_days = easy_interval;\n this.again.due = date_scheduler(now, 5);\n this.hard.due =\n hard_interval > 0\n ? date_scheduler(now, hard_interval, true)\n : date_scheduler(now, 10);\n this.good.due = date_scheduler(now, good_interval, true);\n this.easy.due = date_scheduler(now, easy_interval, true);\n return this;\n }\n\n record_log(card: Card, now: Date): RecordLog {\n return {\n [Rating.Again]: {\n card: this.again,\n log: {\n rating: Rating.Again,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Hard]: {\n card: this.hard,\n log: {\n rating: Rating.Hard,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Good]: {\n card: this.good,\n log: {\n rating: Rating.Good,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Easy]: {\n card: this.easy,\n log: {\n rating: Rating.Easy,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n };\n }\n}\n","import { Card, DateInput, FSRSParameters, State } from \"./models\";\nimport { fixDate } from \"./help\";\n\nexport const default_request_retention = 0.9;\nexport const default_maximum_interval = 36500;\nexport const default_w = [\n 0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05,\n 0.34, 1.26, 0.29, 2.61,\n];\nexport const default_enable_fuzz = false;\n\nexport const FSRSVersion: string = \"3.1.1\";\n\nexport const generatorParameters = (\n props?: Partial<FSRSParameters>,\n): FSRSParameters => {\n return {\n request_retention: props?.request_retention || default_request_retention,\n maximum_interval: props?.maximum_interval || default_maximum_interval,\n w: props?.w || default_w,\n enable_fuzz: props?.enable_fuzz || default_enable_fuzz,\n };\n};\n\nexport const createEmptyCard = (now?: DateInput): Card => {\n return {\n due: now ? fixDate(now) : new Date(),\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: 0,\n lapses: 0,\n state: State.New,\n last_review: undefined,\n };\n};\n","import pseudorandom from \"seedrandom\";\nimport { generatorParameters } from \"./default\";\nimport { SchedulingCard } from \"./scheduler\";\nimport { FSRSParameters, Grade, Rating } from \"./models\";\nimport type { int } from \"./type\";\n\n// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-v4\nexport class FSRSAlgorithm {\n protected param: FSRSParameters;\n private readonly intervalModifier: number;\n protected seed?: string;\n\n constructor(param: Partial<FSRSParameters>) {\n this.param = generatorParameters(param);\n // Ref: https://github.com/open-spaced-repetition/py-fsrs/blob/ecd68e453611eb808c7367c7a5312d7cadeedf5c/src/fsrs/fsrs.py#L79\n // The formula used is : I(r,s)=9 \\cdot s \\cdot (\\frac{1}{r}-1)\n this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n }\n\n init_ds(s: SchedulingCard): void {\n s.again.difficulty = this.init_difficulty(Rating.Again);\n s.again.stability = this.init_stability(Rating.Again);\n s.hard.difficulty = this.init_difficulty(Rating.Hard);\n s.hard.stability = this.init_stability(Rating.Hard);\n s.good.difficulty = this.init_difficulty(Rating.Good);\n s.good.stability = this.init_stability(Rating.Good);\n s.easy.difficulty = this.init_difficulty(Rating.Easy);\n s.easy.stability = this.init_stability(Rating.Easy);\n }\n\n /**\n * Updates the difficulty and stability values of the scheduling card based on the last difficulty,\n * last stability, and the current retrievability.\n * @param {SchedulingCard} s scheduling Card\n * @param {number} last_d Difficulty\n * @param {number} last_s Stability\n * @param retrievability Retrievability\n */\n next_ds(\n s: SchedulingCard,\n last_d: number,\n last_s: number,\n retrievability: number,\n ): void {\n s.again.difficulty = this.next_difficulty(last_d, Rating.Again);\n s.again.stability = this.next_forget_stability(\n s.again.difficulty,\n last_s,\n retrievability,\n );\n s.hard.difficulty = this.next_difficulty(last_d, Rating.Hard);\n s.hard.stability = this.next_recall_stability(\n s.hard.difficulty,\n last_s,\n retrievability,\n Rating.Hard,\n );\n s.good.difficulty = this.next_difficulty(last_d, Rating.Good);\n s.good.stability = this.next_recall_stability(\n s.good.difficulty,\n last_s,\n retrievability,\n Rating.Good,\n );\n s.easy.difficulty = this.next_difficulty(last_d, Rating.Easy);\n s.easy.stability = this.next_recall_stability(\n s.easy.difficulty,\n last_s,\n retrievability,\n Rating.Easy,\n );\n }\n\n /**\n * The formula used is :\n * S_0(G) = w_{G-1}\n * \\max \\{S_0,0.1\\}\n * @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return Stability (interval when R=90%)\n */\n init_stability(g: Grade): number {\n return Math.max(this.param.w[g - 1], 0.1);\n }\n\n /**\n * The formula used is :\n * $$D_0(G) = w_4 - (G-3) \\cdot w_5$$\n * $$\\min \\{\\max \\{D_0(G),1\\},10\\}$$\n * where the D_0(3)=w_4 when the first rating is good.\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} Difficulty D \\in [1,10]\n */\n init_difficulty(g: Grade): number {\n return Math.min(\n Math.max(this.param.w[4] - (g - 3) * this.param.w[5], 1),\n 10,\n );\n }\n\n /**\n * If fuzzing is disabled or ivl is less than 2.5, it returns the original interval.\n * @param {number} ivl - The interval to be fuzzed.\n * @return {number} - The fuzzed interval.\n **/\n apply_fuzz(ivl: number): number {\n if (!this.param.enable_fuzz || ivl < 2.5) return ivl;\n const generator = pseudorandom(this.seed);\n const fuzz_factor = generator();\n ivl = Math.round(ivl);\n const min_ivl = Math.max(2, Math.round(ivl * 0.95 - 1));\n const max_ivl = Math.round(ivl * 1.05 + 1);\n return Math.floor(fuzz_factor * (max_ivl - min_ivl + 1) + min_ivl);\n }\n\n /**\n * Ref:\n * constructor(param: Partial<FSRSParameters>)\n * this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n * @param {number} s - Stability (interval when R=90%)\n */\n next_interval(s: number): int {\n const newInterval = this.apply_fuzz(s * this.intervalModifier);\n return Math.min(\n Math.max(Math.round(newInterval), 1),\n this.param.maximum_interval,\n ) as int;\n }\n\n /**\n * The formula used is :\n * $$next_d = D - w_6 \\cdot (R - 2)$$\n * $$D^\\prime(D,R) = w_5 \\cdot D_0(2) +(1 - w_5) \\cdot next_d$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} next_D\n */\n next_difficulty(d: number, g: Grade): number {\n const next_d = d - this.param.w[6] * (g - 3);\n return this.constrain_difficulty(\n this.mean_reversion(this.param.w[4], next_d),\n );\n }\n\n /**\n * The formula used is :\n * $$\\min \\{\\max \\{D_0,1\\},10\\}$$\n * @param {number} difficulty D \\in [1,10]\n */\n constrain_difficulty(difficulty: number): number {\n return Math.min(Math.max(Number(difficulty.toFixed(2)), 1), 10);\n }\n\n /**\n * The formula used is :\n * $$w_7 \\cdot init +(1 - w_7) \\cdot current$$\n * @param {number} init $$w_2 : D_0(3) = w_2 + (R-2) \\cdot w_3= w_2$$\n * @param {number} current $$D - w_6 \\cdot (R - 2)$$\n * @return {number} difficulty\n */\n mean_reversion(init: number, current: number): number {\n return this.param.w[7] * init + (1 - this.param.w[7]) * current;\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_r(D,S,R,G) = S\\cdot(e^{w_8}\\cdot (11-D)\\cdot S^{-w_9}\\cdot(e^{w_10\\cdot(1-R)}-1)\\cdot w_15(if G=2) \\cdot w_16(if G=4)+1)$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @param {Grade} g Grade (Rating[0.again,1.hard,2.good,3.easy])\n * @return {number} S^\\prime_r new stability after recall\n */\n next_recall_stability(d: number, s: number, r: number, g: Grade): number {\n const hard_penalty = Rating.Hard === g ? this.param.w[15] : 1;\n const easy_bound = Rating.Easy === g ? this.param.w[16] : 1;\n return (\n s *\n (1 +\n Math.exp(this.param.w[8]) *\n (11 - d) *\n Math.pow(s, -this.param.w[9]) *\n (Math.exp((1 - r) * this.param.w[10]) - 1) *\n hard_penalty *\n easy_bound)\n );\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_f(D,S,R) = w_11\\cdot D^{-w_{12}}\\cdot ((S+1)^{w_{13}}-1) \\cdot e^{w_{14}\\cdot(1-R)}.$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @return {number} S^\\prime_f new stability after forgetting\n */\n next_forget_stability(d: number, s: number, r: number): number {\n return (\n this.param.w[11] *\n Math.pow(d, -this.param.w[12]) *\n (Math.pow(s + 1, this.param.w[13]) - 1) *\n Math.exp((1 - r) * this.param.w[14])\n );\n }\n\n /**\n * The formula used is :\n * $$R(t,S) = (1 + \\frac{t}{9 \\cdot S})^{-1},$$\n * @param {number} t t days since the last review\n * @param {number} s Stability (interval when R=90%)\n * @return {number} r Retrievability (probability of recall)\n */\n current_retrievability(t: number, s: number): number {\n return Math.pow(1 + t / (9 * s), -1);\n }\n}\n","import { SchedulingCard } from \"./scheduler\";\nimport { fixDate, fixRating, fixState } from \"./help\";\nimport {\n Card,\n CardInput,\n DateInput,\n FSRSParameters,\n Rating,\n RecordLog,\n RecordLogItem,\n ReviewLog,\n ReviewLogInput,\n State,\n} from \"./models\";\nimport type { int } from \"./type\";\nimport { FSRSAlgorithm } from \"./algorithm\";\n\nexport class FSRS extends FSRSAlgorithm {\n constructor(param: Partial<FSRSParameters>) {\n super(param);\n }\n\n private preProcessCard(_card: CardInput): Card {\n return {\n ..._card,\n state: fixState(_card.state),\n due: fixDate(_card.due),\n last_review: _card.last_review ? fixDate(_card.last_review) : undefined,\n };\n }\n\n private preProcessDate(_date: DateInput): Date {\n return fixDate(_date);\n }\n\n private preProcessLog(_log: ReviewLogInput): ReviewLog {\n return {\n ..._log,\n rating: fixRating(_log.rating),\n state: fixState(_log.state),\n review: fixDate(_log.review),\n };\n }\n\n repeat = (card: CardInput, now: DateInput): RecordLog => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const s = new SchedulingCard(card, now).update_state(card.state);\n this.seed = String(now.getTime()) + String(card.reps);\n let easy_interval, good_interval, hard_interval;\n switch (card.state) {\n case State.New:\n this.init_ds(s);\n s.again.due = now.scheduler(1 as int);\n s.hard.due = now.scheduler(5 as int);\n s.good.due = now.scheduler(10 as int);\n easy_interval = this.next_interval(s.easy.stability);\n s.easy.scheduled_days = easy_interval;\n s.easy.due = now.scheduler(easy_interval, true);\n break;\n case State.Learning:\n case State.Relearning:\n hard_interval = 0;\n good_interval = this.next_interval(s.good.stability);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n case State.Review: {\n const interval = card.elapsed_days;\n const last_d = card.difficulty;\n const last_s = card.stability;\n const retrievability = this.current_retrievability(interval, last_s);\n this.next_ds(s, last_d, last_s, retrievability);\n hard_interval = this.next_interval(s.hard.stability);\n good_interval = this.next_interval(s.good.stability);\n hard_interval = Math.min(hard_interval, good_interval);\n good_interval = Math.max(good_interval, hard_interval + 1);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n }\n }\n return s.record_log(card, now);\n };\n\n get_retrievability = (card: Card, now: Date): undefined | string => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n if (card.state !== State.Review) {\n return undefined;\n }\n const t = Math.max(now.diff(card.last_review as Date, \"days\"), 0);\n return (\n (this.current_retrievability(t, card.stability) * 100).toFixed(2) + \"%\"\n );\n };\n\n rollback = (card: CardInput, log: ReviewLogInput): Card => {\n card = this.preProcessCard(card);\n log = this.preProcessLog(log);\n if (log.rating === Rating.Manual) {\n throw new Error(\"Cannot rollback a manual rating\");\n }\n let last_due, last_review, last_lapses;\n switch (log.state) {\n case State.New:\n last_due = log.due;\n last_review = undefined;\n last_lapses = 0;\n break;\n case State.Learning:\n case State.Relearning:\n case State.Review:\n last_due = log.review;\n last_review = log.due;\n last_lapses =\n card.lapses -\n (log.rating === Rating.Again && log.state === State.Review ? 1 : 0);\n break;\n }\n\n return {\n ...card,\n due: last_due,\n stability: log.stability,\n difficulty: log.difficulty,\n elapsed_days: log.last_elapsed_days,\n scheduled_days: log.scheduled_days,\n reps: Math.max(0, card.reps - 1),\n lapses: Math.max(0, last_lapses),\n state: log.state,\n last_review: last_review,\n };\n };\n\n forget = (\n card: CardInput,\n now: DateInput,\n reset_count: boolean = false,\n ): RecordLogItem => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const scheduled_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\");\n const forget_log: ReviewLog = {\n rating: Rating.Manual,\n state: card.state,\n due: card.due,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: 0,\n last_elapsed_days: card.elapsed_days,\n scheduled_days: scheduled_days,\n review: now,\n };\n const forget_card: Card = {\n ...card,\n due: now,\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: reset_count ? 0 : card.reps,\n lapses: reset_count ? 0 : card.lapses,\n state: State.New,\n last_review: card.last_review,\n };\n return { card: forget_card, log: forget_log };\n };\n}\n\nexport const fsrs = (params?: Partial<FSRSParameters>) => {\n return new FSRS(params || {});\n};\n"],"names":["State","Rating","date_scheduler","now","t","isDay","Date","getTime","date_diff","pre","unit","Error","diff","r","Math","floor","formatDate","date","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","seconds","getSeconds","padZero","num","prototype","scheduler","this","format","dueFormat","last_review","show_diff_message","TIMEUNIT","TIMEUNITFORMAT","due","timeUnit","fixDate","length","i","value","timestamp","parse","isNaN","fixState","fixRating","Grades","Again","Hard","Good","Easy","SchedulingCard","again","hard","good","easy","last_elapsed_days","copy","card","constructor","elapsed_days","state","New","reps","update_state","Learning","Review","lapses","Relearning","schedule","hard_interval","good_interval","easy_interval","scheduled_days","record_log","log","rating","stability","difficulty","review","default_w","generatorParameters","props","request_retention","maximum_interval","w","enable_fuzz","FSRSAlgorithm","param","intervalModifier","seed","init_ds","s","init_difficulty","init_stability","next_ds","last_d","last_s","retrievability","next_difficulty","next_forget_stability","next_recall_stability","g","max","min","apply_fuzz","ivl","fuzz_factor","pseudorandom","generator","round","min_ivl","max_ivl","next_interval","newInterval","d","next_d","constrain_difficulty","mean_reversion","Number","toFixed","init","current","hard_penalty","easy_bound","exp","pow","current_retrievability","FSRS","super","preProcessCard","_card","undefined","preProcessDate","_date","preProcessLog","_log","repeat","String","interval","get_retrievability","rollback","Manual","last_due","last_lapses","forget","reset_count","forget_log","params"],"mappings":"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"}
1
+ {"version":3,"file":"ts-fsrs.cjs.js","sources":["../src/fsrs/models.ts","../src/fsrs/help.ts","../src/fsrs/scheduler.ts","../src/fsrs/default.ts","../src/fsrs/algorithm.ts","../src/fsrs/fsrs.ts"],"sourcesContent":["export type StateType = \"New\" | \"Learning\" | \"Review\" | \"Relearning\";\n\nexport enum State {\n New = 0,\n Learning = 1,\n Review = 2,\n Relearning = 3,\n}\n\nexport type RatingType = \"Again\" | \"Hard\" | \"Good\" | \"Easy\";\n\nexport enum Rating {\n Manual = 0,\n Again = 1,\n Hard = 2,\n Good = 3,\n Easy = 4,\n}\n\ntype ExcludeManual<T> = Exclude<T, Rating.Manual>;\n\nexport type Grade = ExcludeManual<Rating>;\n\nexport interface ReviewLog {\n rating: Rating;\n state: State;\n due: Date;\n stability: number;\n difficulty: number;\n elapsed_days: number;\n last_elapsed_days: number;\n scheduled_days: number;\n review: Date;\n}\nexport type RecordLogItem = {\n card: Card;\n log: ReviewLog;\n};\nexport type RecordLog = {\n [key in Grade]: RecordLogItem;\n};\n\nexport interface Card {\n due: Date; // Due date\n stability: number; // Stability\n difficulty: number; // Difficulty level\n elapsed_days: number; // Number of days elapsed\n scheduled_days: number; // Number of days scheduled\n reps: number; // Repetition count\n lapses: number; // Number of lapses or mistakes\n state: State; // Card's state (New, Learning, Review, Relearning)\n last_review?: Date; // Date of the last review (optional)\n}\n\nexport type CardInput = Card & { state: StateType | State };\nexport type DateInput = Date | number | string;\nexport type ReviewLogInput = ReviewLog & {\n rating: RatingType | Rating;\n state: StateType | State;\n};\n\nexport interface FSRSParameters {\n request_retention: number;\n maximum_interval: number;\n w: number[];\n enable_fuzz: boolean;\n}\n","import type { int, unit } from \"./type\";\nimport { Grade, Rating, State } from \"./models\";\n\ndeclare global {\n export interface Date {\n scheduler(t: int, isDay?: boolean): Date;\n\n diff(pre: Date, unit: unit): int;\n\n format(): string;\n\n dueFormat(last_review: Date, unit?: boolean): string;\n }\n}\n\nDate.prototype.scheduler = function (t: int, isDay?: boolean): Date {\n return date_scheduler(this, t, isDay);\n};\n\n/**\n * 当前时间与之前的时间差值\n * @param pre 比当前时间还要之前\n * @param unit 单位: days | minutes\n */\nDate.prototype.diff = function (pre: Date, unit: unit): int {\n return date_diff(this, pre, unit) as int;\n};\n\nDate.prototype.format = function (): string {\n return formatDate(this);\n};\n\nDate.prototype.dueFormat = function (last_review: Date, unit?: boolean) {\n return show_diff_message(this, last_review, unit);\n};\n\n/**\n * 计算日期和时间的偏移,并返回一个新的日期对象。\n * @param now 当前日期和时间\n * @param t 时间偏移量,当 isDay 为 true 时表示天数,为 false 时表示分钟\n * @param isDay (可选)是否按天数单位进行偏移,默认为 false,表示按分钟单位计算偏移\n * @returns 偏移后的日期和时间对象\n */\nexport function date_scheduler(now: Date, t: number, isDay?: boolean): Date {\n return new Date(\n isDay\n ? now.getTime() + t * 24 * 60 * 60 * 1000\n : now.getTime() + t * 60 * 1000,\n );\n}\n\nexport function date_diff(now: Date, pre: Date, unit: unit): number {\n if (!now || !pre) {\n throw new Error(\"Invalid date\");\n }\n const diff = now.getTime() - pre.getTime();\n let r = 0;\n switch (unit) {\n case \"days\":\n r = Math.floor(diff / (24 * 60 * 60 * 1000));\n break;\n case \"minutes\":\n r = Math.floor(diff / (60 * 1000));\n break;\n }\n return r;\n}\n\nexport function formatDate(date: Date): string {\n const year: number = date.getFullYear();\n const month: number = date.getMonth() + 1;\n const day: number = date.getDate();\n const hours: number = date.getHours();\n const minutes: number = date.getMinutes();\n const seconds: number = date.getSeconds();\n\n return `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(\n minutes,\n )}:${padZero(seconds)}`;\n}\n\nfunction padZero(num: number): string {\n return num < 10 ? `0${num}` : `${num}`;\n}\n\nconst TIMEUNIT = [60, 60, 24, 31, 12];\nconst TIMEUNITFORMAT = [\"second\", \"min\", \"hour\", \"day\", \"month\", \"year\"];\n\nexport function show_diff_message(\n due: Date,\n last_review: Date,\n unit?: boolean,\n timeUnit: string[] = TIMEUNITFORMAT,\n): string {\n due = fixDate(due);\n last_review = fixDate(last_review);\n if (timeUnit.length !== TIMEUNITFORMAT.length) {\n timeUnit = TIMEUNITFORMAT;\n }\n let diff = due.getTime() - last_review.getTime();\n let i;\n diff /= 1000;\n for (i = 0; i < TIMEUNIT.length; i++) {\n if (diff < TIMEUNIT[i]) {\n break;\n } else {\n diff /= TIMEUNIT[i];\n }\n }\n return `${Math.floor(diff)}${unit ? timeUnit[i] : \"\"}`;\n}\n\nexport function fixDate(value: unknown) {\n if (typeof value === \"object\" && value instanceof Date) {\n return value;\n } else if (typeof value === \"string\") {\n const timestamp = Date.parse(value);\n if (!isNaN(timestamp)) {\n return new Date(timestamp);\n } else {\n throw new Error(`Invalid date:[${value}]`);\n }\n } else if (typeof value === \"number\") {\n return new Date(value);\n }\n throw new Error(`Invalid date:[${value}]`);\n}\n\nexport function fixState(value: unknown): State {\n if (typeof value === \"string\") {\n return State[value as keyof typeof State];\n } else if (typeof value === \"number\") {\n return value as State;\n }\n throw new Error(`Invalid state:[${value}]`);\n}\n\nexport function fixRating(value: unknown): Rating {\n if (typeof value === \"string\") {\n return Rating[value as keyof typeof Rating];\n } else if (typeof value === \"number\") {\n return value as Rating;\n }\n throw new Error(`Invalid rating:[${value}]`);\n}\n\nexport const Grades: Grade[] = [\n Rating.Again,\n Rating.Hard,\n Rating.Good,\n Rating.Easy,\n];\n","import { Card, Rating, RecordLog, State } from \"./models\";\nimport { date_scheduler } from \"./help\";\n\nexport class SchedulingCard {\n again: Card;\n hard: Card;\n good: Card;\n easy: Card;\n last_review: Date;\n last_elapsed_days: number;\n\n private copy(card: Card): Card {\n return {\n ...card,\n };\n }\n\n constructor(card: Card, now: Date) {\n this.last_review = card.last_review || card.due;\n this.last_elapsed_days = card.elapsed_days;\n card.elapsed_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\"); //相距时间\n card.last_review = now; // 上次复习时间\n card.reps += 1;\n this.again = this.copy(card);\n this.hard = this.copy(card);\n this.good = this.copy(card);\n this.easy = this.copy(card);\n }\n\n update_state(state: State) {\n if (state === State.New) {\n this.again.state = State.Learning;\n this.hard.state = State.Learning;\n this.good.state = State.Learning;\n this.easy.state = State.Review;\n } else if (state === State.Learning || state === State.Relearning) {\n this.again.state = state;\n this.hard.state = state;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n } else if (state === State.Review) {\n this.again.state = State.Relearning;\n this.hard.state = State.Review;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n }\n return this;\n }\n\n schedule(\n now: Date,\n hard_interval: number,\n good_interval: number,\n easy_interval: number,\n ): SchedulingCard {\n this.again.scheduled_days = 0;\n this.hard.scheduled_days = hard_interval;\n this.good.scheduled_days = good_interval;\n this.easy.scheduled_days = easy_interval;\n this.again.due = date_scheduler(now, 5);\n this.hard.due =\n hard_interval > 0\n ? date_scheduler(now, hard_interval, true)\n : date_scheduler(now, 10);\n this.good.due = date_scheduler(now, good_interval, true);\n this.easy.due = date_scheduler(now, easy_interval, true);\n return this;\n }\n\n record_log(card: Card, now: Date): RecordLog {\n return {\n [Rating.Again]: {\n card: this.again,\n log: {\n rating: Rating.Again,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Hard]: {\n card: this.hard,\n log: {\n rating: Rating.Hard,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Good]: {\n card: this.good,\n log: {\n rating: Rating.Good,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Easy]: {\n card: this.easy,\n log: {\n rating: Rating.Easy,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n };\n }\n}\n","import { Card, DateInput, FSRSParameters, State } from \"./models\";\nimport { fixDate } from \"./help\";\n\nexport const default_request_retention = 0.9;\nexport const default_maximum_interval = 36500;\nexport const default_w = [\n 0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05,\n 0.34, 1.26, 0.29, 2.61,\n];\nexport const default_enable_fuzz = false;\n\nexport const FSRSVersion: string = \"3.1.2\";\n\nexport const generatorParameters = (\n props?: Partial<FSRSParameters>,\n): FSRSParameters => {\n return {\n request_retention: props?.request_retention || default_request_retention,\n maximum_interval: props?.maximum_interval || default_maximum_interval,\n w: props?.w || default_w,\n enable_fuzz: props?.enable_fuzz || default_enable_fuzz,\n };\n};\n\nexport const createEmptyCard = (now?: DateInput): Card => {\n return {\n due: now ? fixDate(now) : new Date(),\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: 0,\n lapses: 0,\n state: State.New,\n last_review: undefined,\n };\n};\n","import pseudorandom from \"seedrandom\";\nimport { generatorParameters } from \"./default\";\nimport { SchedulingCard } from \"./scheduler\";\nimport { FSRSParameters, Grade, Rating } from \"./models\";\nimport type { int } from \"./type\";\n\n// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-v4\nexport class FSRSAlgorithm {\n protected param: FSRSParameters;\n private readonly intervalModifier: number;\n protected seed?: string;\n\n constructor(param: Partial<FSRSParameters>) {\n this.param = generatorParameters(param);\n // Ref: https://github.com/open-spaced-repetition/py-fsrs/blob/ecd68e453611eb808c7367c7a5312d7cadeedf5c/src/fsrs/fsrs.py#L79\n // The formula used is : I(r,s)=9 \\cdot s \\cdot (\\frac{1}{r}-1)\n this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n }\n\n init_ds(s: SchedulingCard): void {\n s.again.difficulty = this.init_difficulty(Rating.Again);\n s.again.stability = this.init_stability(Rating.Again);\n s.hard.difficulty = this.init_difficulty(Rating.Hard);\n s.hard.stability = this.init_stability(Rating.Hard);\n s.good.difficulty = this.init_difficulty(Rating.Good);\n s.good.stability = this.init_stability(Rating.Good);\n s.easy.difficulty = this.init_difficulty(Rating.Easy);\n s.easy.stability = this.init_stability(Rating.Easy);\n }\n\n /**\n * Updates the difficulty and stability values of the scheduling card based on the last difficulty,\n * last stability, and the current retrievability.\n * @param {SchedulingCard} s scheduling Card\n * @param {number} last_d Difficulty\n * @param {number} last_s Stability\n * @param retrievability Retrievability\n */\n next_ds(\n s: SchedulingCard,\n last_d: number,\n last_s: number,\n retrievability: number,\n ): void {\n s.again.difficulty = this.next_difficulty(last_d, Rating.Again);\n s.again.stability = this.next_forget_stability(\n s.again.difficulty,\n last_s,\n retrievability,\n );\n s.hard.difficulty = this.next_difficulty(last_d, Rating.Hard);\n s.hard.stability = this.next_recall_stability(\n s.hard.difficulty,\n last_s,\n retrievability,\n Rating.Hard,\n );\n s.good.difficulty = this.next_difficulty(last_d, Rating.Good);\n s.good.stability = this.next_recall_stability(\n s.good.difficulty,\n last_s,\n retrievability,\n Rating.Good,\n );\n s.easy.difficulty = this.next_difficulty(last_d, Rating.Easy);\n s.easy.stability = this.next_recall_stability(\n s.easy.difficulty,\n last_s,\n retrievability,\n Rating.Easy,\n );\n }\n\n /**\n * The formula used is :\n * S_0(G) = w_{G-1}\n * \\max \\{S_0,0.1\\}\n * @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return Stability (interval when R=90%)\n */\n init_stability(g: Grade): number {\n return Math.max(this.param.w[g - 1], 0.1);\n }\n\n /**\n * The formula used is :\n * $$D_0(G) = w_4 - (G-3) \\cdot w_5$$\n * $$\\min \\{\\max \\{D_0(G),1\\},10\\}$$\n * where the D_0(3)=w_4 when the first rating is good.\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} Difficulty D \\in [1,10]\n */\n init_difficulty(g: Grade): number {\n return Math.min(\n Math.max(this.param.w[4] - (g - 3) * this.param.w[5], 1),\n 10,\n );\n }\n\n /**\n * If fuzzing is disabled or ivl is less than 2.5, it returns the original interval.\n * @param {number} ivl - The interval to be fuzzed.\n * @return {number} - The fuzzed interval.\n **/\n apply_fuzz(ivl: number): number {\n if (!this.param.enable_fuzz || ivl < 2.5) return ivl;\n const generator = pseudorandom(this.seed);\n const fuzz_factor = generator();\n ivl = Math.round(ivl);\n const min_ivl = Math.max(2, Math.round(ivl * 0.95 - 1));\n const max_ivl = Math.round(ivl * 1.05 + 1);\n return Math.floor(fuzz_factor * (max_ivl - min_ivl + 1) + min_ivl);\n }\n\n /**\n * Ref:\n * constructor(param: Partial<FSRSParameters>)\n * this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n * @param {number} s - Stability (interval when R=90%)\n */\n next_interval(s: number): int {\n const newInterval = this.apply_fuzz(s * this.intervalModifier);\n return Math.min(\n Math.max(Math.round(newInterval), 1),\n this.param.maximum_interval,\n ) as int;\n }\n\n /**\n * The formula used is :\n * $$next_d = D - w_6 \\cdot (R - 2)$$\n * $$D^\\prime(D,R) = w_5 \\cdot D_0(2) +(1 - w_5) \\cdot next_d$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} next_D\n */\n next_difficulty(d: number, g: Grade): number {\n const next_d = d - this.param.w[6] * (g - 3);\n return this.constrain_difficulty(\n this.mean_reversion(this.param.w[4], next_d),\n );\n }\n\n /**\n * The formula used is :\n * $$\\min \\{\\max \\{D_0,1\\},10\\}$$\n * @param {number} difficulty D \\in [1,10]\n */\n constrain_difficulty(difficulty: number): number {\n return Math.min(Math.max(Number(difficulty.toFixed(2)), 1), 10);\n }\n\n /**\n * The formula used is :\n * $$w_7 \\cdot init +(1 - w_7) \\cdot current$$\n * @param {number} init $$w_2 : D_0(3) = w_2 + (R-2) \\cdot w_3= w_2$$\n * @param {number} current $$D - w_6 \\cdot (R - 2)$$\n * @return {number} difficulty\n */\n mean_reversion(init: number, current: number): number {\n return this.param.w[7] * init + (1 - this.param.w[7]) * current;\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_r(D,S,R,G) = S\\cdot(e^{w_8}\\cdot (11-D)\\cdot S^{-w_9}\\cdot(e^{w_10\\cdot(1-R)}-1)\\cdot w_15(if G=2) \\cdot w_16(if G=4)+1)$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @param {Grade} g Grade (Rating[0.again,1.hard,2.good,3.easy])\n * @return {number} S^\\prime_r new stability after recall\n */\n next_recall_stability(d: number, s: number, r: number, g: Grade): number {\n const hard_penalty = Rating.Hard === g ? this.param.w[15] : 1;\n const easy_bound = Rating.Easy === g ? this.param.w[16] : 1;\n return (\n s *\n (1 +\n Math.exp(this.param.w[8]) *\n (11 - d) *\n Math.pow(s, -this.param.w[9]) *\n (Math.exp((1 - r) * this.param.w[10]) - 1) *\n hard_penalty *\n easy_bound)\n );\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_f(D,S,R) = w_11\\cdot D^{-w_{12}}\\cdot ((S+1)^{w_{13}}-1) \\cdot e^{w_{14}\\cdot(1-R)}.$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @return {number} S^\\prime_f new stability after forgetting\n */\n next_forget_stability(d: number, s: number, r: number): number {\n return (\n this.param.w[11] *\n Math.pow(d, -this.param.w[12]) *\n (Math.pow(s + 1, this.param.w[13]) - 1) *\n Math.exp((1 - r) * this.param.w[14])\n );\n }\n\n /**\n * The formula used is :\n * $$R(t,S) = (1 + \\frac{t}{9 \\cdot S})^{-1},$$\n * @param {number} t t days since the last review\n * @param {number} s Stability (interval when R=90%)\n * @return {number} r Retrievability (probability of recall)\n */\n current_retrievability(t: number, s: number): number {\n return Math.pow(1 + t / (9 * s), -1);\n }\n}\n","import { SchedulingCard } from \"./scheduler\";\nimport { fixDate, fixRating, fixState } from \"./help\";\nimport {\n Card,\n CardInput,\n DateInput,\n FSRSParameters,\n Rating,\n RecordLog,\n RecordLogItem,\n ReviewLog,\n ReviewLogInput,\n State,\n} from \"./models\";\nimport type { int } from \"./type\";\nimport { FSRSAlgorithm } from \"./algorithm\";\n\nexport class FSRS extends FSRSAlgorithm {\n constructor(param: Partial<FSRSParameters>) {\n super(param);\n }\n\n private preProcessCard(_card: CardInput): Card {\n return {\n ..._card,\n state: fixState(_card.state),\n due: fixDate(_card.due),\n last_review: _card.last_review ? fixDate(_card.last_review) : undefined,\n };\n }\n\n private preProcessDate(_date: DateInput): Date {\n return fixDate(_date);\n }\n\n private preProcessLog(_log: ReviewLogInput): ReviewLog {\n return {\n ..._log,\n rating: fixRating(_log.rating),\n state: fixState(_log.state),\n review: fixDate(_log.review),\n };\n }\n\n repeat = (card: CardInput, now: DateInput): RecordLog => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const s = new SchedulingCard(card, now).update_state(card.state);\n this.seed = String(now.getTime()) + String(card.reps);\n let easy_interval, good_interval, hard_interval;\n switch (card.state) {\n case State.New:\n this.init_ds(s);\n s.again.due = now.scheduler(1 as int);\n s.hard.due = now.scheduler(5 as int);\n s.good.due = now.scheduler(10 as int);\n easy_interval = this.next_interval(s.easy.stability);\n s.easy.scheduled_days = easy_interval;\n s.easy.due = now.scheduler(easy_interval, true);\n break;\n case State.Learning:\n case State.Relearning:\n hard_interval = 0;\n good_interval = this.next_interval(s.good.stability);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n case State.Review: {\n const interval = card.elapsed_days;\n const last_d = card.difficulty;\n const last_s = card.stability;\n const retrievability = this.current_retrievability(interval, last_s);\n this.next_ds(s, last_d, last_s, retrievability);\n hard_interval = this.next_interval(s.hard.stability);\n good_interval = this.next_interval(s.good.stability);\n hard_interval = Math.min(hard_interval, good_interval);\n good_interval = Math.max(good_interval, hard_interval + 1);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n }\n }\n return s.record_log(card, now);\n };\n\n get_retrievability = (card: Card, now: Date): undefined | string => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n if (card.state !== State.Review) {\n return undefined;\n }\n const t = Math.max(now.diff(card.last_review as Date, \"days\"), 0);\n return (\n (this.current_retrievability(t, card.stability) * 100).toFixed(2) + \"%\"\n );\n };\n\n rollback = (card: CardInput, log: ReviewLogInput): Card => {\n card = this.preProcessCard(card);\n log = this.preProcessLog(log);\n if (log.rating === Rating.Manual) {\n throw new Error(\"Cannot rollback a manual rating\");\n }\n let last_due, last_review, last_lapses;\n switch (log.state) {\n case State.New:\n last_due = log.due;\n last_review = undefined;\n last_lapses = 0;\n break;\n case State.Learning:\n case State.Relearning:\n case State.Review:\n last_due = log.review;\n last_review = log.due;\n last_lapses =\n card.lapses -\n (log.rating === Rating.Again && log.state === State.Review ? 1 : 0);\n break;\n }\n\n return {\n ...card,\n due: last_due,\n stability: log.stability,\n difficulty: log.difficulty,\n elapsed_days: log.last_elapsed_days,\n scheduled_days: log.scheduled_days,\n reps: Math.max(0, card.reps - 1),\n lapses: Math.max(0, last_lapses),\n state: log.state,\n last_review: last_review,\n };\n };\n\n forget = (\n card: CardInput,\n now: DateInput,\n reset_count: boolean = false,\n ): RecordLogItem => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const scheduled_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\");\n const forget_log: ReviewLog = {\n rating: Rating.Manual,\n state: card.state,\n due: card.due,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: 0,\n last_elapsed_days: card.elapsed_days,\n scheduled_days: scheduled_days,\n review: now,\n };\n const forget_card: Card = {\n ...card,\n due: now,\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: reset_count ? 0 : card.reps,\n lapses: reset_count ? 0 : card.lapses,\n state: State.New,\n last_review: card.last_review,\n };\n return { card: forget_card, log: forget_log };\n };\n}\n\nexport const fsrs = (params?: Partial<FSRSParameters>) => {\n return new FSRS(params || {});\n};\n"],"names":["State","Rating","date_scheduler","now","t","isDay","Date","getTime","date_diff","pre","unit","Error","diff","r","Math","floor","formatDate","date","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","seconds","getSeconds","padZero","num","prototype","scheduler","this","format","dueFormat","last_review","show_diff_message","TIMEUNIT","TIMEUNITFORMAT","due","timeUnit","fixDate","length","i","value","timestamp","parse","isNaN","fixState","fixRating","Grades","Again","Hard","Good","Easy","SchedulingCard","again","hard","good","easy","last_elapsed_days","copy","card","constructor","elapsed_days","state","New","reps","update_state","Learning","Review","Relearning","lapses","schedule","hard_interval","good_interval","easy_interval","scheduled_days","record_log","log","rating","stability","difficulty","review","default_w","generatorParameters","props","request_retention","maximum_interval","w","enable_fuzz","FSRSAlgorithm","param","intervalModifier","seed","init_ds","s","init_difficulty","init_stability","next_ds","last_d","last_s","retrievability","next_difficulty","next_forget_stability","next_recall_stability","g","max","min","apply_fuzz","ivl","fuzz_factor","pseudorandom","generator","round","min_ivl","max_ivl","next_interval","newInterval","d","next_d","constrain_difficulty","mean_reversion","Number","toFixed","init","current","hard_penalty","easy_bound","exp","pow","current_retrievability","FSRS","super","preProcessCard","_card","undefined","preProcessDate","_date","preProcessLog","_log","repeat","String","interval","get_retrievability","rollback","Manual","last_due","last_lapses","forget","reset_count","forget_log","params"],"mappings":"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"}
package/dist/ts-fsrs.js CHANGED
@@ -1,2 +1,2 @@
1
- import t from"seedrandom";var e,a;function i(t,e,a){return new Date(a?t.getTime()+24*e*60*60*1e3:t.getTime()+60*e*1e3)}function s(t,e,a){if(!t||!e)throw new Error("Invalid date");const i=t.getTime()-e.getTime();let s=0;switch(a){case"days":s=Math.floor(i/864e5);break;case"minutes":s=Math.floor(i/6e4)}return s}function r(t){const e=t.getFullYear(),a=t.getMonth()+1,i=t.getDate(),s=t.getHours(),r=t.getMinutes(),n=t.getSeconds();return`${e}-${d(a)}-${d(i)} ${d(s)}:${d(r)}:${d(n)}`}function d(t){return t<10?`0${t}`:`${t}`}!function(t){t[t.New=0]="New",t[t.Learning=1]="Learning",t[t.Review=2]="Review",t[t.Relearning=3]="Relearning"}(e||(e={})),function(t){t[t.Manual=0]="Manual",t[t.Again=1]="Again",t[t.Hard=2]="Hard",t[t.Good=3]="Good",t[t.Easy=4]="Easy"}(a||(a={})),Date.prototype.scheduler=function(t,e){return i(this,t,e)},Date.prototype.diff=function(t,e){return s(this,t,e)},Date.prototype.format=function(){return r(this)},Date.prototype.dueFormat=function(t,e){return h(this,t,e)};const n=[60,60,24,31,12],l=["second","min","hour","day","month","year"];function h(t,e,a,i=l){t=o(t),e=o(e),i.length!==l.length&&(i=l);let s,r=t.getTime()-e.getTime();for(r/=1e3,s=0;s<n.length&&!(r<n[s]);s++)r/=n[s];return`${Math.floor(r)}${a?i[s]:""}`}function o(t){if("object"==typeof t&&t instanceof Date)return t;if("string"==typeof t){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}if("number"==typeof t)return new Date(t);throw new Error(`Invalid date:[${t}]`)}function y(t){if("string"==typeof t)return e[t];if("number"==typeof t)return t;throw new Error(`Invalid state:[${t}]`)}function u(t){if("string"==typeof t)return a[t];if("number"==typeof t)return t;throw new Error(`Invalid rating:[${t}]`)}const c=[a.Again,a.Hard,a.Good,a.Easy];class f{again;hard;good;easy;last_review;last_elapsed_days;copy(t){return{...t}}constructor(t,a){this.last_review=t.last_review||t.due,this.last_elapsed_days=t.elapsed_days,t.elapsed_days=t.state===e.New?0:a.diff(t.last_review,"days"),t.last_review=a,t.reps+=1,this.again=this.copy(t),this.hard=this.copy(t),this.good=this.copy(t),this.easy=this.copy(t)}update_state(t){return t===e.New?(this.again.state=e.Learning,this.hard.state=e.Learning,this.good.state=e.Learning,this.easy.state=e.Review,this.again.lapses+=1):t===e.Learning||t===e.Relearning?(this.again.state=t,this.hard.state=t,this.good.state=e.Review,this.easy.state=e.Review):t===e.Review&&(this.again.state=e.Relearning,this.hard.state=e.Review,this.good.state=e.Review,this.easy.state=e.Review,this.again.lapses+=1),this}schedule(t,e,a,s){return this.again.scheduled_days=0,this.hard.scheduled_days=e,this.good.scheduled_days=a,this.easy.scheduled_days=s,this.again.due=i(t,5),this.hard.due=e>0?i(t,e,!0):i(t,10),this.good.due=i(t,a,!0),this.easy.due=i(t,s,!0),this}record_log(t,e){return{[a.Again]:{card:this.again,log:{rating:a.Again,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Hard]:{card:this.hard,log:{rating:a.Hard,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Good]:{card:this.good,log:{rating:a.Good,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Easy]:{card:this.easy,log:{rating:a.Easy,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}}}}}const _=.9,p=36500,g=[.4,.6,2.4,5.8,4.93,.94,.86,.01,1.49,.14,.94,2.18,.05,.34,1.26,.29,2.61],w=!1,m="3.1.1",v=t=>({request_retention:t?.request_retention||.9,maximum_interval:t?.maximum_interval||36500,w:t?.w||g,enable_fuzz:t?.enable_fuzz||false}),b=t=>({due:t?o(t):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:e.New,last_review:void 0});class x{param;intervalModifier;seed;constructor(t){this.param=v(t),this.intervalModifier=9*(1/this.param.request_retention-1)}init_ds(t){t.again.difficulty=this.init_difficulty(a.Again),t.again.stability=this.init_stability(a.Again),t.hard.difficulty=this.init_difficulty(a.Hard),t.hard.stability=this.init_stability(a.Hard),t.good.difficulty=this.init_difficulty(a.Good),t.good.stability=this.init_stability(a.Good),t.easy.difficulty=this.init_difficulty(a.Easy),t.easy.stability=this.init_stability(a.Easy)}next_ds(t,e,i,s){t.again.difficulty=this.next_difficulty(e,a.Again),t.again.stability=this.next_forget_stability(t.again.difficulty,i,s),t.hard.difficulty=this.next_difficulty(e,a.Hard),t.hard.stability=this.next_recall_stability(t.hard.difficulty,i,s,a.Hard),t.good.difficulty=this.next_difficulty(e,a.Good),t.good.stability=this.next_recall_stability(t.good.difficulty,i,s,a.Good),t.easy.difficulty=this.next_difficulty(e,a.Easy),t.easy.stability=this.next_recall_stability(t.easy.difficulty,i,s,a.Easy)}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return Math.min(Math.max(this.param.w[4]-(t-3)*this.param.w[5],1),10)}apply_fuzz(e){if(!this.param.enable_fuzz||e<2.5)return e;const a=t(this.seed)();e=Math.round(e);const i=Math.max(2,Math.round(.95*e-1)),s=Math.round(1.05*e+1);return Math.floor(a*(s-i+1)+i)}next_interval(t){const e=this.apply_fuzz(t*this.intervalModifier);return Math.min(Math.max(Math.round(e),1),this.param.maximum_interval)}next_difficulty(t,e){const a=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.param.w[4],a))}constrain_difficulty(t){return Math.min(Math.max(Number(t.toFixed(2)),1),10)}mean_reversion(t,e){return this.param.w[7]*t+(1-this.param.w[7])*e}next_recall_stability(t,e,i,s){const r=a.Hard===s?this.param.w[15]:1,d=a.Easy===s?this.param.w[16]:1;return 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)*r*d)}next_forget_stability(t,e,a){return this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-a)*this.param.w[14])}current_retrievability(t,e){return Math.pow(1+t/(9*e),-1)}}class M extends x{constructor(t){super(t)}preProcessCard(t){return{...t,state:y(t.state),due:o(t.due),last_review:t.last_review?o(t.last_review):void 0}}preProcessDate(t){return o(t)}preProcessLog(t){return{...t,rating:u(t.rating),state:y(t.state),review:o(t.review)}}repeat=(t,a)=>{t=this.preProcessCard(t),a=this.preProcessDate(a);const i=new f(t,a).update_state(t.state);let s,r,d;switch(this.seed=String(a.getTime())+String(t.reps),t.state){case e.New:this.init_ds(i),i.again.due=a.scheduler(1),i.hard.due=a.scheduler(5),i.good.due=a.scheduler(10),s=this.next_interval(i.easy.stability),i.easy.scheduled_days=s,i.easy.due=a.scheduler(s,!0);break;case e.Learning:case e.Relearning:d=0,r=this.next_interval(i.good.stability),s=Math.max(this.next_interval(i.easy.stability),r+1),i.schedule(a,d,r,s);break;case e.Review:{const e=t.elapsed_days,n=t.difficulty,l=t.stability,h=this.current_retrievability(e,l);this.next_ds(i,n,l,h),d=this.next_interval(i.hard.stability),r=this.next_interval(i.good.stability),d=Math.min(d,r),r=Math.max(r,d+1),s=Math.max(this.next_interval(i.easy.stability),r+1),i.schedule(a,d,r,s);break}}return i.record_log(t,a)};get_retrievability=(t,a)=>{if(t=this.preProcessCard(t),a=this.preProcessDate(a),t.state!==e.Review)return;const i=Math.max(a.diff(t.last_review,"days"),0);return(100*this.current_retrievability(i,t.stability)).toFixed(2)+"%"};rollback=(t,i)=>{if(t=this.preProcessCard(t),(i=this.preProcessLog(i)).rating===a.Manual)throw new Error("Cannot rollback a manual rating");let s,r,d;switch(i.state){case e.New:s=i.due,r=void 0,d=0;break;case e.Learning:case e.Relearning:case e.Review:s=i.review,r=i.due,d=t.lapses-(i.rating===a.Again&&i.state===e.Review?1:0)}return{...t,due:s,stability:i.stability,difficulty:i.difficulty,elapsed_days:i.last_elapsed_days,scheduled_days:i.scheduled_days,reps:Math.max(0,t.reps-1),lapses:Math.max(0,d),state:i.state,last_review:r}};forget=(t,i,s=!1)=>{t=this.preProcessCard(t),i=this.preProcessDate(i);const r=t.state===e.New?0:i.diff(t.last_review,"days"),d={rating:a.Manual,state:t.state,due:t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:0,last_elapsed_days:t.elapsed_days,scheduled_days:r,review:i};return{card:{...t,due:i,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:s?0:t.reps,lapses:s?0:t.lapses,state:e.New,last_review:t.last_review},log:d}}}const R=t=>new M(t||{});export{M as FSRS,m as FSRSVersion,c as Grades,a as Rating,f as SchedulingCard,e as State,b as createEmptyCard,s as date_diff,i as date_scheduler,w as default_enable_fuzz,p as default_maximum_interval,_ as default_request_retention,g as default_w,o as fixDate,u as fixRating,y as fixState,r as formatDate,R as fsrs,v as generatorParameters,h as show_diff_message};
1
+ import t from"seedrandom";var e,a;function i(t,e,a){return new Date(a?t.getTime()+24*e*60*60*1e3:t.getTime()+60*e*1e3)}function s(t,e,a){if(!t||!e)throw new Error("Invalid date");const i=t.getTime()-e.getTime();let s=0;switch(a){case"days":s=Math.floor(i/864e5);break;case"minutes":s=Math.floor(i/6e4)}return s}function r(t){const e=t.getFullYear(),a=t.getMonth()+1,i=t.getDate(),s=t.getHours(),r=t.getMinutes(),n=t.getSeconds();return`${e}-${d(a)}-${d(i)} ${d(s)}:${d(r)}:${d(n)}`}function d(t){return t<10?`0${t}`:`${t}`}!function(t){t[t.New=0]="New",t[t.Learning=1]="Learning",t[t.Review=2]="Review",t[t.Relearning=3]="Relearning"}(e||(e={})),function(t){t[t.Manual=0]="Manual",t[t.Again=1]="Again",t[t.Hard=2]="Hard",t[t.Good=3]="Good",t[t.Easy=4]="Easy"}(a||(a={})),Date.prototype.scheduler=function(t,e){return i(this,t,e)},Date.prototype.diff=function(t,e){return s(this,t,e)},Date.prototype.format=function(){return r(this)},Date.prototype.dueFormat=function(t,e){return h(this,t,e)};const n=[60,60,24,31,12],l=["second","min","hour","day","month","year"];function h(t,e,a,i=l){t=o(t),e=o(e),i.length!==l.length&&(i=l);let s,r=t.getTime()-e.getTime();for(r/=1e3,s=0;s<n.length&&!(r<n[s]);s++)r/=n[s];return`${Math.floor(r)}${a?i[s]:""}`}function o(t){if("object"==typeof t&&t instanceof Date)return t;if("string"==typeof t){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}if("number"==typeof t)return new Date(t);throw new Error(`Invalid date:[${t}]`)}function y(t){if("string"==typeof t)return e[t];if("number"==typeof t)return t;throw new Error(`Invalid state:[${t}]`)}function u(t){if("string"==typeof t)return a[t];if("number"==typeof t)return t;throw new Error(`Invalid rating:[${t}]`)}const c=[a.Again,a.Hard,a.Good,a.Easy];class f{again;hard;good;easy;last_review;last_elapsed_days;copy(t){return{...t}}constructor(t,a){this.last_review=t.last_review||t.due,this.last_elapsed_days=t.elapsed_days,t.elapsed_days=t.state===e.New?0:a.diff(t.last_review,"days"),t.last_review=a,t.reps+=1,this.again=this.copy(t),this.hard=this.copy(t),this.good=this.copy(t),this.easy=this.copy(t)}update_state(t){return t===e.New?(this.again.state=e.Learning,this.hard.state=e.Learning,this.good.state=e.Learning,this.easy.state=e.Review):t===e.Learning||t===e.Relearning?(this.again.state=t,this.hard.state=t,this.good.state=e.Review,this.easy.state=e.Review):t===e.Review&&(this.again.state=e.Relearning,this.hard.state=e.Review,this.good.state=e.Review,this.easy.state=e.Review,this.again.lapses+=1),this}schedule(t,e,a,s){return this.again.scheduled_days=0,this.hard.scheduled_days=e,this.good.scheduled_days=a,this.easy.scheduled_days=s,this.again.due=i(t,5),this.hard.due=e>0?i(t,e,!0):i(t,10),this.good.due=i(t,a,!0),this.easy.due=i(t,s,!0),this}record_log(t,e){return{[a.Again]:{card:this.again,log:{rating:a.Again,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Hard]:{card:this.hard,log:{rating:a.Hard,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Good]:{card:this.good,log:{rating:a.Good,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}},[a.Easy]:{card:this.easy,log:{rating:a.Easy,state:t.state,due:this.last_review,stability:t.stability,difficulty:t.difficulty,elapsed_days:t.elapsed_days,last_elapsed_days:this.last_elapsed_days,scheduled_days:t.scheduled_days,review:e}}}}}const _=.9,p=36500,g=[.4,.6,2.4,5.8,4.93,.94,.86,.01,1.49,.14,.94,2.18,.05,.34,1.26,.29,2.61],w=!1,m="3.1.2",v=t=>({request_retention:t?.request_retention||.9,maximum_interval:t?.maximum_interval||36500,w:t?.w||g,enable_fuzz:t?.enable_fuzz||false}),b=t=>({due:t?o(t):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:e.New,last_review:void 0});class x{param;intervalModifier;seed;constructor(t){this.param=v(t),this.intervalModifier=9*(1/this.param.request_retention-1)}init_ds(t){t.again.difficulty=this.init_difficulty(a.Again),t.again.stability=this.init_stability(a.Again),t.hard.difficulty=this.init_difficulty(a.Hard),t.hard.stability=this.init_stability(a.Hard),t.good.difficulty=this.init_difficulty(a.Good),t.good.stability=this.init_stability(a.Good),t.easy.difficulty=this.init_difficulty(a.Easy),t.easy.stability=this.init_stability(a.Easy)}next_ds(t,e,i,s){t.again.difficulty=this.next_difficulty(e,a.Again),t.again.stability=this.next_forget_stability(t.again.difficulty,i,s),t.hard.difficulty=this.next_difficulty(e,a.Hard),t.hard.stability=this.next_recall_stability(t.hard.difficulty,i,s,a.Hard),t.good.difficulty=this.next_difficulty(e,a.Good),t.good.stability=this.next_recall_stability(t.good.difficulty,i,s,a.Good),t.easy.difficulty=this.next_difficulty(e,a.Easy),t.easy.stability=this.next_recall_stability(t.easy.difficulty,i,s,a.Easy)}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return Math.min(Math.max(this.param.w[4]-(t-3)*this.param.w[5],1),10)}apply_fuzz(e){if(!this.param.enable_fuzz||e<2.5)return e;const a=t(this.seed)();e=Math.round(e);const i=Math.max(2,Math.round(.95*e-1)),s=Math.round(1.05*e+1);return Math.floor(a*(s-i+1)+i)}next_interval(t){const e=this.apply_fuzz(t*this.intervalModifier);return Math.min(Math.max(Math.round(e),1),this.param.maximum_interval)}next_difficulty(t,e){const a=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.param.w[4],a))}constrain_difficulty(t){return Math.min(Math.max(Number(t.toFixed(2)),1),10)}mean_reversion(t,e){return this.param.w[7]*t+(1-this.param.w[7])*e}next_recall_stability(t,e,i,s){const r=a.Hard===s?this.param.w[15]:1,d=a.Easy===s?this.param.w[16]:1;return 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)*r*d)}next_forget_stability(t,e,a){return this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-a)*this.param.w[14])}current_retrievability(t,e){return Math.pow(1+t/(9*e),-1)}}class M extends x{constructor(t){super(t)}preProcessCard(t){return{...t,state:y(t.state),due:o(t.due),last_review:t.last_review?o(t.last_review):void 0}}preProcessDate(t){return o(t)}preProcessLog(t){return{...t,rating:u(t.rating),state:y(t.state),review:o(t.review)}}repeat=(t,a)=>{t=this.preProcessCard(t),a=this.preProcessDate(a);const i=new f(t,a).update_state(t.state);let s,r,d;switch(this.seed=String(a.getTime())+String(t.reps),t.state){case e.New:this.init_ds(i),i.again.due=a.scheduler(1),i.hard.due=a.scheduler(5),i.good.due=a.scheduler(10),s=this.next_interval(i.easy.stability),i.easy.scheduled_days=s,i.easy.due=a.scheduler(s,!0);break;case e.Learning:case e.Relearning:d=0,r=this.next_interval(i.good.stability),s=Math.max(this.next_interval(i.easy.stability),r+1),i.schedule(a,d,r,s);break;case e.Review:{const e=t.elapsed_days,n=t.difficulty,l=t.stability,h=this.current_retrievability(e,l);this.next_ds(i,n,l,h),d=this.next_interval(i.hard.stability),r=this.next_interval(i.good.stability),d=Math.min(d,r),r=Math.max(r,d+1),s=Math.max(this.next_interval(i.easy.stability),r+1),i.schedule(a,d,r,s);break}}return i.record_log(t,a)};get_retrievability=(t,a)=>{if(t=this.preProcessCard(t),a=this.preProcessDate(a),t.state!==e.Review)return;const i=Math.max(a.diff(t.last_review,"days"),0);return(100*this.current_retrievability(i,t.stability)).toFixed(2)+"%"};rollback=(t,i)=>{if(t=this.preProcessCard(t),(i=this.preProcessLog(i)).rating===a.Manual)throw new Error("Cannot rollback a manual rating");let s,r,d;switch(i.state){case e.New:s=i.due,r=void 0,d=0;break;case e.Learning:case e.Relearning:case e.Review:s=i.review,r=i.due,d=t.lapses-(i.rating===a.Again&&i.state===e.Review?1:0)}return{...t,due:s,stability:i.stability,difficulty:i.difficulty,elapsed_days:i.last_elapsed_days,scheduled_days:i.scheduled_days,reps:Math.max(0,t.reps-1),lapses:Math.max(0,d),state:i.state,last_review:r}};forget=(t,i,s=!1)=>{t=this.preProcessCard(t),i=this.preProcessDate(i);const r=t.state===e.New?0:i.diff(t.last_review,"days"),d={rating:a.Manual,state:t.state,due:t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:0,last_elapsed_days:t.elapsed_days,scheduled_days:r,review:i};return{card:{...t,due:i,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:s?0:t.reps,lapses:s?0:t.lapses,state:e.New,last_review:t.last_review},log:d}}}const R=t=>new M(t||{});export{M as FSRS,m as FSRSVersion,c as Grades,a as Rating,f as SchedulingCard,e as State,b as createEmptyCard,s as date_diff,i as date_scheduler,w as default_enable_fuzz,p as default_maximum_interval,_ as default_request_retention,g as default_w,o as fixDate,u as fixRating,y as fixState,r as formatDate,R as fsrs,v as generatorParameters,h as show_diff_message};
2
2
  //# sourceMappingURL=ts-fsrs.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ts-fsrs.js","sources":["../src/fsrs/models.ts","../src/fsrs/help.ts","../src/fsrs/scheduler.ts","../src/fsrs/default.ts","../src/fsrs/algorithm.ts","../src/fsrs/fsrs.ts"],"sourcesContent":["export type StateType = \"New\" | \"Learning\" | \"Review\" | \"Relearning\";\n\nexport enum State {\n New = 0,\n Learning = 1,\n Review = 2,\n Relearning = 3,\n}\n\nexport type RatingType = \"Again\" | \"Hard\" | \"Good\" | \"Easy\";\n\nexport enum Rating {\n Manual = 0,\n Again = 1,\n Hard = 2,\n Good = 3,\n Easy = 4,\n}\n\ntype ExcludeManual<T> = Exclude<T, Rating.Manual>;\n\nexport type Grade = ExcludeManual<Rating>;\n\nexport interface ReviewLog {\n rating: Rating;\n state: State;\n due: Date;\n stability: number;\n difficulty: number;\n elapsed_days: number;\n last_elapsed_days: number;\n scheduled_days: number;\n review: Date;\n}\nexport type RecordLogItem = {\n card: Card;\n log: ReviewLog;\n};\nexport type RecordLog = {\n [key in Grade]: RecordLogItem;\n};\n\nexport interface Card {\n due: Date; // Due date\n stability: number; // Stability\n difficulty: number; // Difficulty level\n elapsed_days: number; // Number of days elapsed\n scheduled_days: number; // Number of days scheduled\n reps: number; // Repetition count\n lapses: number; // Number of lapses or mistakes\n state: State; // Card's state (New, Learning, Review, Relearning)\n last_review?: Date; // Date of the last review (optional)\n}\n\nexport type CardInput = Card & { state: StateType | State };\nexport type DateInput = Date | number | string;\nexport type ReviewLogInput = ReviewLog & {\n rating: RatingType | Rating;\n state: StateType | State;\n};\n\nexport interface FSRSParameters {\n request_retention: number;\n maximum_interval: number;\n w: number[];\n enable_fuzz: boolean;\n}\n","import type { int, unit } from \"./type\";\nimport { Grade, Rating, State } from \"./models\";\n\ndeclare global {\n export interface Date {\n scheduler(t: int, isDay?: boolean): Date;\n\n diff(pre: Date, unit: unit): int;\n\n format(): string;\n\n dueFormat(last_review: Date, unit?: boolean): string;\n }\n}\n\nDate.prototype.scheduler = function (t: int, isDay?: boolean): Date {\n return date_scheduler(this, t, isDay);\n};\n\n/**\n * 当前时间与之前的时间差值\n * @param pre 比当前时间还要之前\n * @param unit 单位: days | minutes\n */\nDate.prototype.diff = function (pre: Date, unit: unit): int {\n return date_diff(this, pre, unit) as int;\n};\n\nDate.prototype.format = function (): string {\n return formatDate(this);\n};\n\nDate.prototype.dueFormat = function (last_review: Date, unit?: boolean) {\n return show_diff_message(this, last_review, unit);\n};\n\n/**\n * 计算日期和时间的偏移,并返回一个新的日期对象。\n * @param now 当前日期和时间\n * @param t 时间偏移量,当 isDay 为 true 时表示天数,为 false 时表示分钟\n * @param isDay (可选)是否按天数单位进行偏移,默认为 false,表示按分钟单位计算偏移\n * @returns 偏移后的日期和时间对象\n */\nexport function date_scheduler(now: Date, t: number, isDay?: boolean): Date {\n return new Date(\n isDay\n ? now.getTime() + t * 24 * 60 * 60 * 1000\n : now.getTime() + t * 60 * 1000,\n );\n}\n\nexport function date_diff(now: Date, pre: Date, unit: unit): number {\n if (!now || !pre) {\n throw new Error(\"Invalid date\");\n }\n const diff = now.getTime() - pre.getTime();\n let r = 0;\n switch (unit) {\n case \"days\":\n r = Math.floor(diff / (24 * 60 * 60 * 1000));\n break;\n case \"minutes\":\n r = Math.floor(diff / (60 * 1000));\n break;\n }\n return r;\n}\n\nexport function formatDate(date: Date): string {\n const year: number = date.getFullYear();\n const month: number = date.getMonth() + 1;\n const day: number = date.getDate();\n const hours: number = date.getHours();\n const minutes: number = date.getMinutes();\n const seconds: number = date.getSeconds();\n\n return `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(\n minutes,\n )}:${padZero(seconds)}`;\n}\n\nfunction padZero(num: number): string {\n return num < 10 ? `0${num}` : `${num}`;\n}\n\nconst TIMEUNIT = [60, 60, 24, 31, 12];\nconst TIMEUNITFORMAT = [\"second\", \"min\", \"hour\", \"day\", \"month\", \"year\"];\n\nexport function show_diff_message(\n due: Date,\n last_review: Date,\n unit?: boolean,\n timeUnit: string[] = TIMEUNITFORMAT,\n): string {\n due = fixDate(due);\n last_review = fixDate(last_review);\n if (timeUnit.length !== TIMEUNITFORMAT.length) {\n timeUnit = TIMEUNITFORMAT;\n }\n let diff = due.getTime() - last_review.getTime();\n let i;\n diff /= 1000;\n for (i = 0; i < TIMEUNIT.length; i++) {\n if (diff < TIMEUNIT[i]) {\n break;\n } else {\n diff /= TIMEUNIT[i];\n }\n }\n return `${Math.floor(diff)}${unit ? timeUnit[i] : \"\"}`;\n}\n\nexport function fixDate(value: unknown) {\n if (typeof value === \"object\" && value instanceof Date) {\n return value;\n } else if (typeof value === \"string\") {\n const timestamp = Date.parse(value);\n if (!isNaN(timestamp)) {\n return new Date(timestamp);\n } else {\n throw new Error(`Invalid date:[${value}]`);\n }\n } else if (typeof value === \"number\") {\n return new Date(value);\n }\n throw new Error(`Invalid date:[${value}]`);\n}\n\nexport function fixState(value: unknown): State {\n if (typeof value === \"string\") {\n return State[value as keyof typeof State];\n } else if (typeof value === \"number\") {\n return value as State;\n }\n throw new Error(`Invalid state:[${value}]`);\n}\n\nexport function fixRating(value: unknown): Rating {\n if (typeof value === \"string\") {\n return Rating[value as keyof typeof Rating];\n } else if (typeof value === \"number\") {\n return value as Rating;\n }\n throw new Error(`Invalid rating:[${value}]`);\n}\n\nexport const Grades: Grade[] = [\n Rating.Again,\n Rating.Hard,\n Rating.Good,\n Rating.Easy,\n];\n","import { Card, Rating, RecordLog, State } from \"./models\";\nimport { date_scheduler } from \"./help\";\n\nexport class SchedulingCard {\n again: Card;\n hard: Card;\n good: Card;\n easy: Card;\n last_review: Date;\n last_elapsed_days: number;\n\n private copy(card: Card): Card {\n return {\n ...card,\n };\n }\n\n constructor(card: Card, now: Date) {\n this.last_review = card.last_review || card.due;\n this.last_elapsed_days = card.elapsed_days;\n card.elapsed_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\"); //相距时间\n card.last_review = now; // 上次复习时间\n card.reps += 1;\n this.again = this.copy(card);\n this.hard = this.copy(card);\n this.good = this.copy(card);\n this.easy = this.copy(card);\n }\n\n update_state(state: State) {\n if (state === State.New) {\n this.again.state = State.Learning;\n this.hard.state = State.Learning;\n this.good.state = State.Learning;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n } else if (state === State.Learning || state === State.Relearning) {\n this.again.state = state;\n this.hard.state = state;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n } else if (state === State.Review) {\n this.again.state = State.Relearning;\n this.hard.state = State.Review;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n }\n return this;\n }\n\n schedule(\n now: Date,\n hard_interval: number,\n good_interval: number,\n easy_interval: number,\n ): SchedulingCard {\n this.again.scheduled_days = 0;\n this.hard.scheduled_days = hard_interval;\n this.good.scheduled_days = good_interval;\n this.easy.scheduled_days = easy_interval;\n this.again.due = date_scheduler(now, 5);\n this.hard.due =\n hard_interval > 0\n ? date_scheduler(now, hard_interval, true)\n : date_scheduler(now, 10);\n this.good.due = date_scheduler(now, good_interval, true);\n this.easy.due = date_scheduler(now, easy_interval, true);\n return this;\n }\n\n record_log(card: Card, now: Date): RecordLog {\n return {\n [Rating.Again]: {\n card: this.again,\n log: {\n rating: Rating.Again,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Hard]: {\n card: this.hard,\n log: {\n rating: Rating.Hard,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Good]: {\n card: this.good,\n log: {\n rating: Rating.Good,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Easy]: {\n card: this.easy,\n log: {\n rating: Rating.Easy,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n };\n }\n}\n","import { Card, DateInput, FSRSParameters, State } from \"./models\";\nimport { fixDate } from \"./help\";\n\nexport const default_request_retention = 0.9;\nexport const default_maximum_interval = 36500;\nexport const default_w = [\n 0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05,\n 0.34, 1.26, 0.29, 2.61,\n];\nexport const default_enable_fuzz = false;\n\nexport const FSRSVersion: string = \"3.1.1\";\n\nexport const generatorParameters = (\n props?: Partial<FSRSParameters>,\n): FSRSParameters => {\n return {\n request_retention: props?.request_retention || default_request_retention,\n maximum_interval: props?.maximum_interval || default_maximum_interval,\n w: props?.w || default_w,\n enable_fuzz: props?.enable_fuzz || default_enable_fuzz,\n };\n};\n\nexport const createEmptyCard = (now?: DateInput): Card => {\n return {\n due: now ? fixDate(now) : new Date(),\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: 0,\n lapses: 0,\n state: State.New,\n last_review: undefined,\n };\n};\n","import pseudorandom from \"seedrandom\";\nimport { generatorParameters } from \"./default\";\nimport { SchedulingCard } from \"./scheduler\";\nimport { FSRSParameters, Grade, Rating } from \"./models\";\nimport type { int } from \"./type\";\n\n// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-v4\nexport class FSRSAlgorithm {\n protected param: FSRSParameters;\n private readonly intervalModifier: number;\n protected seed?: string;\n\n constructor(param: Partial<FSRSParameters>) {\n this.param = generatorParameters(param);\n // Ref: https://github.com/open-spaced-repetition/py-fsrs/blob/ecd68e453611eb808c7367c7a5312d7cadeedf5c/src/fsrs/fsrs.py#L79\n // The formula used is : I(r,s)=9 \\cdot s \\cdot (\\frac{1}{r}-1)\n this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n }\n\n init_ds(s: SchedulingCard): void {\n s.again.difficulty = this.init_difficulty(Rating.Again);\n s.again.stability = this.init_stability(Rating.Again);\n s.hard.difficulty = this.init_difficulty(Rating.Hard);\n s.hard.stability = this.init_stability(Rating.Hard);\n s.good.difficulty = this.init_difficulty(Rating.Good);\n s.good.stability = this.init_stability(Rating.Good);\n s.easy.difficulty = this.init_difficulty(Rating.Easy);\n s.easy.stability = this.init_stability(Rating.Easy);\n }\n\n /**\n * Updates the difficulty and stability values of the scheduling card based on the last difficulty,\n * last stability, and the current retrievability.\n * @param {SchedulingCard} s scheduling Card\n * @param {number} last_d Difficulty\n * @param {number} last_s Stability\n * @param retrievability Retrievability\n */\n next_ds(\n s: SchedulingCard,\n last_d: number,\n last_s: number,\n retrievability: number,\n ): void {\n s.again.difficulty = this.next_difficulty(last_d, Rating.Again);\n s.again.stability = this.next_forget_stability(\n s.again.difficulty,\n last_s,\n retrievability,\n );\n s.hard.difficulty = this.next_difficulty(last_d, Rating.Hard);\n s.hard.stability = this.next_recall_stability(\n s.hard.difficulty,\n last_s,\n retrievability,\n Rating.Hard,\n );\n s.good.difficulty = this.next_difficulty(last_d, Rating.Good);\n s.good.stability = this.next_recall_stability(\n s.good.difficulty,\n last_s,\n retrievability,\n Rating.Good,\n );\n s.easy.difficulty = this.next_difficulty(last_d, Rating.Easy);\n s.easy.stability = this.next_recall_stability(\n s.easy.difficulty,\n last_s,\n retrievability,\n Rating.Easy,\n );\n }\n\n /**\n * The formula used is :\n * S_0(G) = w_{G-1}\n * \\max \\{S_0,0.1\\}\n * @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return Stability (interval when R=90%)\n */\n init_stability(g: Grade): number {\n return Math.max(this.param.w[g - 1], 0.1);\n }\n\n /**\n * The formula used is :\n * $$D_0(G) = w_4 - (G-3) \\cdot w_5$$\n * $$\\min \\{\\max \\{D_0(G),1\\},10\\}$$\n * where the D_0(3)=w_4 when the first rating is good.\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} Difficulty D \\in [1,10]\n */\n init_difficulty(g: Grade): number {\n return Math.min(\n Math.max(this.param.w[4] - (g - 3) * this.param.w[5], 1),\n 10,\n );\n }\n\n /**\n * If fuzzing is disabled or ivl is less than 2.5, it returns the original interval.\n * @param {number} ivl - The interval to be fuzzed.\n * @return {number} - The fuzzed interval.\n **/\n apply_fuzz(ivl: number): number {\n if (!this.param.enable_fuzz || ivl < 2.5) return ivl;\n const generator = pseudorandom(this.seed);\n const fuzz_factor = generator();\n ivl = Math.round(ivl);\n const min_ivl = Math.max(2, Math.round(ivl * 0.95 - 1));\n const max_ivl = Math.round(ivl * 1.05 + 1);\n return Math.floor(fuzz_factor * (max_ivl - min_ivl + 1) + min_ivl);\n }\n\n /**\n * Ref:\n * constructor(param: Partial<FSRSParameters>)\n * this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n * @param {number} s - Stability (interval when R=90%)\n */\n next_interval(s: number): int {\n const newInterval = this.apply_fuzz(s * this.intervalModifier);\n return Math.min(\n Math.max(Math.round(newInterval), 1),\n this.param.maximum_interval,\n ) as int;\n }\n\n /**\n * The formula used is :\n * $$next_d = D - w_6 \\cdot (R - 2)$$\n * $$D^\\prime(D,R) = w_5 \\cdot D_0(2) +(1 - w_5) \\cdot next_d$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} next_D\n */\n next_difficulty(d: number, g: Grade): number {\n const next_d = d - this.param.w[6] * (g - 3);\n return this.constrain_difficulty(\n this.mean_reversion(this.param.w[4], next_d),\n );\n }\n\n /**\n * The formula used is :\n * $$\\min \\{\\max \\{D_0,1\\},10\\}$$\n * @param {number} difficulty D \\in [1,10]\n */\n constrain_difficulty(difficulty: number): number {\n return Math.min(Math.max(Number(difficulty.toFixed(2)), 1), 10);\n }\n\n /**\n * The formula used is :\n * $$w_7 \\cdot init +(1 - w_7) \\cdot current$$\n * @param {number} init $$w_2 : D_0(3) = w_2 + (R-2) \\cdot w_3= w_2$$\n * @param {number} current $$D - w_6 \\cdot (R - 2)$$\n * @return {number} difficulty\n */\n mean_reversion(init: number, current: number): number {\n return this.param.w[7] * init + (1 - this.param.w[7]) * current;\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_r(D,S,R,G) = S\\cdot(e^{w_8}\\cdot (11-D)\\cdot S^{-w_9}\\cdot(e^{w_10\\cdot(1-R)}-1)\\cdot w_15(if G=2) \\cdot w_16(if G=4)+1)$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @param {Grade} g Grade (Rating[0.again,1.hard,2.good,3.easy])\n * @return {number} S^\\prime_r new stability after recall\n */\n next_recall_stability(d: number, s: number, r: number, g: Grade): number {\n const hard_penalty = Rating.Hard === g ? this.param.w[15] : 1;\n const easy_bound = Rating.Easy === g ? this.param.w[16] : 1;\n return (\n s *\n (1 +\n Math.exp(this.param.w[8]) *\n (11 - d) *\n Math.pow(s, -this.param.w[9]) *\n (Math.exp((1 - r) * this.param.w[10]) - 1) *\n hard_penalty *\n easy_bound)\n );\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_f(D,S,R) = w_11\\cdot D^{-w_{12}}\\cdot ((S+1)^{w_{13}}-1) \\cdot e^{w_{14}\\cdot(1-R)}.$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @return {number} S^\\prime_f new stability after forgetting\n */\n next_forget_stability(d: number, s: number, r: number): number {\n return (\n this.param.w[11] *\n Math.pow(d, -this.param.w[12]) *\n (Math.pow(s + 1, this.param.w[13]) - 1) *\n Math.exp((1 - r) * this.param.w[14])\n );\n }\n\n /**\n * The formula used is :\n * $$R(t,S) = (1 + \\frac{t}{9 \\cdot S})^{-1},$$\n * @param {number} t t days since the last review\n * @param {number} s Stability (interval when R=90%)\n * @return {number} r Retrievability (probability of recall)\n */\n current_retrievability(t: number, s: number): number {\n return Math.pow(1 + t / (9 * s), -1);\n }\n}\n","import { SchedulingCard } from \"./scheduler\";\nimport { fixDate, fixRating, fixState } from \"./help\";\nimport {\n Card,\n CardInput,\n DateInput,\n FSRSParameters,\n Rating,\n RecordLog,\n RecordLogItem,\n ReviewLog,\n ReviewLogInput,\n State,\n} from \"./models\";\nimport type { int } from \"./type\";\nimport { FSRSAlgorithm } from \"./algorithm\";\n\nexport class FSRS extends FSRSAlgorithm {\n constructor(param: Partial<FSRSParameters>) {\n super(param);\n }\n\n private preProcessCard(_card: CardInput): Card {\n return {\n ..._card,\n state: fixState(_card.state),\n due: fixDate(_card.due),\n last_review: _card.last_review ? fixDate(_card.last_review) : undefined,\n };\n }\n\n private preProcessDate(_date: DateInput): Date {\n return fixDate(_date);\n }\n\n private preProcessLog(_log: ReviewLogInput): ReviewLog {\n return {\n ..._log,\n rating: fixRating(_log.rating),\n state: fixState(_log.state),\n review: fixDate(_log.review),\n };\n }\n\n repeat = (card: CardInput, now: DateInput): RecordLog => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const s = new SchedulingCard(card, now).update_state(card.state);\n this.seed = String(now.getTime()) + String(card.reps);\n let easy_interval, good_interval, hard_interval;\n switch (card.state) {\n case State.New:\n this.init_ds(s);\n s.again.due = now.scheduler(1 as int);\n s.hard.due = now.scheduler(5 as int);\n s.good.due = now.scheduler(10 as int);\n easy_interval = this.next_interval(s.easy.stability);\n s.easy.scheduled_days = easy_interval;\n s.easy.due = now.scheduler(easy_interval, true);\n break;\n case State.Learning:\n case State.Relearning:\n hard_interval = 0;\n good_interval = this.next_interval(s.good.stability);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n case State.Review: {\n const interval = card.elapsed_days;\n const last_d = card.difficulty;\n const last_s = card.stability;\n const retrievability = this.current_retrievability(interval, last_s);\n this.next_ds(s, last_d, last_s, retrievability);\n hard_interval = this.next_interval(s.hard.stability);\n good_interval = this.next_interval(s.good.stability);\n hard_interval = Math.min(hard_interval, good_interval);\n good_interval = Math.max(good_interval, hard_interval + 1);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n }\n }\n return s.record_log(card, now);\n };\n\n get_retrievability = (card: Card, now: Date): undefined | string => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n if (card.state !== State.Review) {\n return undefined;\n }\n const t = Math.max(now.diff(card.last_review as Date, \"days\"), 0);\n return (\n (this.current_retrievability(t, card.stability) * 100).toFixed(2) + \"%\"\n );\n };\n\n rollback = (card: CardInput, log: ReviewLogInput): Card => {\n card = this.preProcessCard(card);\n log = this.preProcessLog(log);\n if (log.rating === Rating.Manual) {\n throw new Error(\"Cannot rollback a manual rating\");\n }\n let last_due, last_review, last_lapses;\n switch (log.state) {\n case State.New:\n last_due = log.due;\n last_review = undefined;\n last_lapses = 0;\n break;\n case State.Learning:\n case State.Relearning:\n case State.Review:\n last_due = log.review;\n last_review = log.due;\n last_lapses =\n card.lapses -\n (log.rating === Rating.Again && log.state === State.Review ? 1 : 0);\n break;\n }\n\n return {\n ...card,\n due: last_due,\n stability: log.stability,\n difficulty: log.difficulty,\n elapsed_days: log.last_elapsed_days,\n scheduled_days: log.scheduled_days,\n reps: Math.max(0, card.reps - 1),\n lapses: Math.max(0, last_lapses),\n state: log.state,\n last_review: last_review,\n };\n };\n\n forget = (\n card: CardInput,\n now: DateInput,\n reset_count: boolean = false,\n ): RecordLogItem => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const scheduled_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\");\n const forget_log: ReviewLog = {\n rating: Rating.Manual,\n state: card.state,\n due: card.due,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: 0,\n last_elapsed_days: card.elapsed_days,\n scheduled_days: scheduled_days,\n review: now,\n };\n const forget_card: Card = {\n ...card,\n due: now,\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: reset_count ? 0 : card.reps,\n lapses: reset_count ? 0 : card.lapses,\n state: State.New,\n last_review: card.last_review,\n };\n return { card: forget_card, log: forget_log };\n };\n}\n\nexport const fsrs = (params?: Partial<FSRSParameters>) => {\n return new FSRS(params || {});\n};\n"],"names":["State","Rating","date_scheduler","now","t","isDay","Date","getTime","date_diff","pre","unit","Error","diff","r","Math","floor","formatDate","date","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","seconds","getSeconds","padZero","num","prototype","scheduler","this","format","dueFormat","last_review","show_diff_message","TIMEUNIT","TIMEUNITFORMAT","due","timeUnit","fixDate","length","i","value","timestamp","parse","isNaN","fixState","fixRating","Grades","Again","Hard","Good","Easy","SchedulingCard","again","hard","good","easy","last_elapsed_days","copy","card","constructor","elapsed_days","state","New","reps","update_state","Learning","Review","lapses","Relearning","schedule","hard_interval","good_interval","easy_interval","scheduled_days","record_log","log","rating","stability","difficulty","review","default_request_retention","default_maximum_interval","default_w","default_enable_fuzz","FSRSVersion","generatorParameters","props","request_retention","maximum_interval","w","enable_fuzz","createEmptyCard","undefined","FSRSAlgorithm","param","intervalModifier","seed","init_ds","s","init_difficulty","init_stability","next_ds","last_d","last_s","retrievability","next_difficulty","next_forget_stability","next_recall_stability","g","max","min","apply_fuzz","ivl","fuzz_factor","pseudorandom","generator","round","min_ivl","max_ivl","next_interval","newInterval","d","next_d","constrain_difficulty","mean_reversion","Number","toFixed","init","current","hard_penalty","easy_bound","exp","pow","current_retrievability","FSRS","super","preProcessCard","_card","preProcessDate","_date","preProcessLog","_log","repeat","String","interval","get_retrievability","rollback","Manual","last_due","last_lapses","forget","reset_count","forget_log","fsrs","params"],"mappings":"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"}
1
+ {"version":3,"file":"ts-fsrs.js","sources":["../src/fsrs/models.ts","../src/fsrs/help.ts","../src/fsrs/scheduler.ts","../src/fsrs/default.ts","../src/fsrs/algorithm.ts","../src/fsrs/fsrs.ts"],"sourcesContent":["export type StateType = \"New\" | \"Learning\" | \"Review\" | \"Relearning\";\n\nexport enum State {\n New = 0,\n Learning = 1,\n Review = 2,\n Relearning = 3,\n}\n\nexport type RatingType = \"Again\" | \"Hard\" | \"Good\" | \"Easy\";\n\nexport enum Rating {\n Manual = 0,\n Again = 1,\n Hard = 2,\n Good = 3,\n Easy = 4,\n}\n\ntype ExcludeManual<T> = Exclude<T, Rating.Manual>;\n\nexport type Grade = ExcludeManual<Rating>;\n\nexport interface ReviewLog {\n rating: Rating;\n state: State;\n due: Date;\n stability: number;\n difficulty: number;\n elapsed_days: number;\n last_elapsed_days: number;\n scheduled_days: number;\n review: Date;\n}\nexport type RecordLogItem = {\n card: Card;\n log: ReviewLog;\n};\nexport type RecordLog = {\n [key in Grade]: RecordLogItem;\n};\n\nexport interface Card {\n due: Date; // Due date\n stability: number; // Stability\n difficulty: number; // Difficulty level\n elapsed_days: number; // Number of days elapsed\n scheduled_days: number; // Number of days scheduled\n reps: number; // Repetition count\n lapses: number; // Number of lapses or mistakes\n state: State; // Card's state (New, Learning, Review, Relearning)\n last_review?: Date; // Date of the last review (optional)\n}\n\nexport type CardInput = Card & { state: StateType | State };\nexport type DateInput = Date | number | string;\nexport type ReviewLogInput = ReviewLog & {\n rating: RatingType | Rating;\n state: StateType | State;\n};\n\nexport interface FSRSParameters {\n request_retention: number;\n maximum_interval: number;\n w: number[];\n enable_fuzz: boolean;\n}\n","import type { int, unit } from \"./type\";\nimport { Grade, Rating, State } from \"./models\";\n\ndeclare global {\n export interface Date {\n scheduler(t: int, isDay?: boolean): Date;\n\n diff(pre: Date, unit: unit): int;\n\n format(): string;\n\n dueFormat(last_review: Date, unit?: boolean): string;\n }\n}\n\nDate.prototype.scheduler = function (t: int, isDay?: boolean): Date {\n return date_scheduler(this, t, isDay);\n};\n\n/**\n * 当前时间与之前的时间差值\n * @param pre 比当前时间还要之前\n * @param unit 单位: days | minutes\n */\nDate.prototype.diff = function (pre: Date, unit: unit): int {\n return date_diff(this, pre, unit) as int;\n};\n\nDate.prototype.format = function (): string {\n return formatDate(this);\n};\n\nDate.prototype.dueFormat = function (last_review: Date, unit?: boolean) {\n return show_diff_message(this, last_review, unit);\n};\n\n/**\n * 计算日期和时间的偏移,并返回一个新的日期对象。\n * @param now 当前日期和时间\n * @param t 时间偏移量,当 isDay 为 true 时表示天数,为 false 时表示分钟\n * @param isDay (可选)是否按天数单位进行偏移,默认为 false,表示按分钟单位计算偏移\n * @returns 偏移后的日期和时间对象\n */\nexport function date_scheduler(now: Date, t: number, isDay?: boolean): Date {\n return new Date(\n isDay\n ? now.getTime() + t * 24 * 60 * 60 * 1000\n : now.getTime() + t * 60 * 1000,\n );\n}\n\nexport function date_diff(now: Date, pre: Date, unit: unit): number {\n if (!now || !pre) {\n throw new Error(\"Invalid date\");\n }\n const diff = now.getTime() - pre.getTime();\n let r = 0;\n switch (unit) {\n case \"days\":\n r = Math.floor(diff / (24 * 60 * 60 * 1000));\n break;\n case \"minutes\":\n r = Math.floor(diff / (60 * 1000));\n break;\n }\n return r;\n}\n\nexport function formatDate(date: Date): string {\n const year: number = date.getFullYear();\n const month: number = date.getMonth() + 1;\n const day: number = date.getDate();\n const hours: number = date.getHours();\n const minutes: number = date.getMinutes();\n const seconds: number = date.getSeconds();\n\n return `${year}-${padZero(month)}-${padZero(day)} ${padZero(hours)}:${padZero(\n minutes,\n )}:${padZero(seconds)}`;\n}\n\nfunction padZero(num: number): string {\n return num < 10 ? `0${num}` : `${num}`;\n}\n\nconst TIMEUNIT = [60, 60, 24, 31, 12];\nconst TIMEUNITFORMAT = [\"second\", \"min\", \"hour\", \"day\", \"month\", \"year\"];\n\nexport function show_diff_message(\n due: Date,\n last_review: Date,\n unit?: boolean,\n timeUnit: string[] = TIMEUNITFORMAT,\n): string {\n due = fixDate(due);\n last_review = fixDate(last_review);\n if (timeUnit.length !== TIMEUNITFORMAT.length) {\n timeUnit = TIMEUNITFORMAT;\n }\n let diff = due.getTime() - last_review.getTime();\n let i;\n diff /= 1000;\n for (i = 0; i < TIMEUNIT.length; i++) {\n if (diff < TIMEUNIT[i]) {\n break;\n } else {\n diff /= TIMEUNIT[i];\n }\n }\n return `${Math.floor(diff)}${unit ? timeUnit[i] : \"\"}`;\n}\n\nexport function fixDate(value: unknown) {\n if (typeof value === \"object\" && value instanceof Date) {\n return value;\n } else if (typeof value === \"string\") {\n const timestamp = Date.parse(value);\n if (!isNaN(timestamp)) {\n return new Date(timestamp);\n } else {\n throw new Error(`Invalid date:[${value}]`);\n }\n } else if (typeof value === \"number\") {\n return new Date(value);\n }\n throw new Error(`Invalid date:[${value}]`);\n}\n\nexport function fixState(value: unknown): State {\n if (typeof value === \"string\") {\n return State[value as keyof typeof State];\n } else if (typeof value === \"number\") {\n return value as State;\n }\n throw new Error(`Invalid state:[${value}]`);\n}\n\nexport function fixRating(value: unknown): Rating {\n if (typeof value === \"string\") {\n return Rating[value as keyof typeof Rating];\n } else if (typeof value === \"number\") {\n return value as Rating;\n }\n throw new Error(`Invalid rating:[${value}]`);\n}\n\nexport const Grades: Grade[] = [\n Rating.Again,\n Rating.Hard,\n Rating.Good,\n Rating.Easy,\n];\n","import { Card, Rating, RecordLog, State } from \"./models\";\nimport { date_scheduler } from \"./help\";\n\nexport class SchedulingCard {\n again: Card;\n hard: Card;\n good: Card;\n easy: Card;\n last_review: Date;\n last_elapsed_days: number;\n\n private copy(card: Card): Card {\n return {\n ...card,\n };\n }\n\n constructor(card: Card, now: Date) {\n this.last_review = card.last_review || card.due;\n this.last_elapsed_days = card.elapsed_days;\n card.elapsed_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\"); //相距时间\n card.last_review = now; // 上次复习时间\n card.reps += 1;\n this.again = this.copy(card);\n this.hard = this.copy(card);\n this.good = this.copy(card);\n this.easy = this.copy(card);\n }\n\n update_state(state: State) {\n if (state === State.New) {\n this.again.state = State.Learning;\n this.hard.state = State.Learning;\n this.good.state = State.Learning;\n this.easy.state = State.Review;\n } else if (state === State.Learning || state === State.Relearning) {\n this.again.state = state;\n this.hard.state = state;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n } else if (state === State.Review) {\n this.again.state = State.Relearning;\n this.hard.state = State.Review;\n this.good.state = State.Review;\n this.easy.state = State.Review;\n this.again.lapses += 1;\n }\n return this;\n }\n\n schedule(\n now: Date,\n hard_interval: number,\n good_interval: number,\n easy_interval: number,\n ): SchedulingCard {\n this.again.scheduled_days = 0;\n this.hard.scheduled_days = hard_interval;\n this.good.scheduled_days = good_interval;\n this.easy.scheduled_days = easy_interval;\n this.again.due = date_scheduler(now, 5);\n this.hard.due =\n hard_interval > 0\n ? date_scheduler(now, hard_interval, true)\n : date_scheduler(now, 10);\n this.good.due = date_scheduler(now, good_interval, true);\n this.easy.due = date_scheduler(now, easy_interval, true);\n return this;\n }\n\n record_log(card: Card, now: Date): RecordLog {\n return {\n [Rating.Again]: {\n card: this.again,\n log: {\n rating: Rating.Again,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Hard]: {\n card: this.hard,\n log: {\n rating: Rating.Hard,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Good]: {\n card: this.good,\n log: {\n rating: Rating.Good,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n [Rating.Easy]: {\n card: this.easy,\n log: {\n rating: Rating.Easy,\n state: card.state,\n due: this.last_review,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: card.elapsed_days,\n last_elapsed_days: this.last_elapsed_days,\n scheduled_days: card.scheduled_days,\n review: now,\n },\n },\n };\n }\n}\n","import { Card, DateInput, FSRSParameters, State } from \"./models\";\nimport { fixDate } from \"./help\";\n\nexport const default_request_retention = 0.9;\nexport const default_maximum_interval = 36500;\nexport const default_w = [\n 0.4, 0.6, 2.4, 5.8, 4.93, 0.94, 0.86, 0.01, 1.49, 0.14, 0.94, 2.18, 0.05,\n 0.34, 1.26, 0.29, 2.61,\n];\nexport const default_enable_fuzz = false;\n\nexport const FSRSVersion: string = \"3.1.2\";\n\nexport const generatorParameters = (\n props?: Partial<FSRSParameters>,\n): FSRSParameters => {\n return {\n request_retention: props?.request_retention || default_request_retention,\n maximum_interval: props?.maximum_interval || default_maximum_interval,\n w: props?.w || default_w,\n enable_fuzz: props?.enable_fuzz || default_enable_fuzz,\n };\n};\n\nexport const createEmptyCard = (now?: DateInput): Card => {\n return {\n due: now ? fixDate(now) : new Date(),\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: 0,\n lapses: 0,\n state: State.New,\n last_review: undefined,\n };\n};\n","import pseudorandom from \"seedrandom\";\nimport { generatorParameters } from \"./default\";\nimport { SchedulingCard } from \"./scheduler\";\nimport { FSRSParameters, Grade, Rating } from \"./models\";\nimport type { int } from \"./type\";\n\n// Ref: https://github.com/open-spaced-repetition/fsrs4anki/wiki/The-Algorithm#fsrs-v4\nexport class FSRSAlgorithm {\n protected param: FSRSParameters;\n private readonly intervalModifier: number;\n protected seed?: string;\n\n constructor(param: Partial<FSRSParameters>) {\n this.param = generatorParameters(param);\n // Ref: https://github.com/open-spaced-repetition/py-fsrs/blob/ecd68e453611eb808c7367c7a5312d7cadeedf5c/src/fsrs/fsrs.py#L79\n // The formula used is : I(r,s)=9 \\cdot s \\cdot (\\frac{1}{r}-1)\n this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n }\n\n init_ds(s: SchedulingCard): void {\n s.again.difficulty = this.init_difficulty(Rating.Again);\n s.again.stability = this.init_stability(Rating.Again);\n s.hard.difficulty = this.init_difficulty(Rating.Hard);\n s.hard.stability = this.init_stability(Rating.Hard);\n s.good.difficulty = this.init_difficulty(Rating.Good);\n s.good.stability = this.init_stability(Rating.Good);\n s.easy.difficulty = this.init_difficulty(Rating.Easy);\n s.easy.stability = this.init_stability(Rating.Easy);\n }\n\n /**\n * Updates the difficulty and stability values of the scheduling card based on the last difficulty,\n * last stability, and the current retrievability.\n * @param {SchedulingCard} s scheduling Card\n * @param {number} last_d Difficulty\n * @param {number} last_s Stability\n * @param retrievability Retrievability\n */\n next_ds(\n s: SchedulingCard,\n last_d: number,\n last_s: number,\n retrievability: number,\n ): void {\n s.again.difficulty = this.next_difficulty(last_d, Rating.Again);\n s.again.stability = this.next_forget_stability(\n s.again.difficulty,\n last_s,\n retrievability,\n );\n s.hard.difficulty = this.next_difficulty(last_d, Rating.Hard);\n s.hard.stability = this.next_recall_stability(\n s.hard.difficulty,\n last_s,\n retrievability,\n Rating.Hard,\n );\n s.good.difficulty = this.next_difficulty(last_d, Rating.Good);\n s.good.stability = this.next_recall_stability(\n s.good.difficulty,\n last_s,\n retrievability,\n Rating.Good,\n );\n s.easy.difficulty = this.next_difficulty(last_d, Rating.Easy);\n s.easy.stability = this.next_recall_stability(\n s.easy.difficulty,\n last_s,\n retrievability,\n Rating.Easy,\n );\n }\n\n /**\n * The formula used is :\n * S_0(G) = w_{G-1}\n * \\max \\{S_0,0.1\\}\n * @param g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return Stability (interval when R=90%)\n */\n init_stability(g: Grade): number {\n return Math.max(this.param.w[g - 1], 0.1);\n }\n\n /**\n * The formula used is :\n * $$D_0(G) = w_4 - (G-3) \\cdot w_5$$\n * $$\\min \\{\\max \\{D_0(G),1\\},10\\}$$\n * where the D_0(3)=w_4 when the first rating is good.\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} Difficulty D \\in [1,10]\n */\n init_difficulty(g: Grade): number {\n return Math.min(\n Math.max(this.param.w[4] - (g - 3) * this.param.w[5], 1),\n 10,\n );\n }\n\n /**\n * If fuzzing is disabled or ivl is less than 2.5, it returns the original interval.\n * @param {number} ivl - The interval to be fuzzed.\n * @return {number} - The fuzzed interval.\n **/\n apply_fuzz(ivl: number): number {\n if (!this.param.enable_fuzz || ivl < 2.5) return ivl;\n const generator = pseudorandom(this.seed);\n const fuzz_factor = generator();\n ivl = Math.round(ivl);\n const min_ivl = Math.max(2, Math.round(ivl * 0.95 - 1));\n const max_ivl = Math.round(ivl * 1.05 + 1);\n return Math.floor(fuzz_factor * (max_ivl - min_ivl + 1) + min_ivl);\n }\n\n /**\n * Ref:\n * constructor(param: Partial<FSRSParameters>)\n * this.intervalModifier = 9 * (1 / this.param.request_retention - 1);\n * @param {number} s - Stability (interval when R=90%)\n */\n next_interval(s: number): int {\n const newInterval = this.apply_fuzz(s * this.intervalModifier);\n return Math.min(\n Math.max(Math.round(newInterval), 1),\n this.param.maximum_interval,\n ) as int;\n }\n\n /**\n * The formula used is :\n * $$next_d = D - w_6 \\cdot (R - 2)$$\n * $$D^\\prime(D,R) = w_5 \\cdot D_0(2) +(1 - w_5) \\cdot next_d$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {Grade} g Grade (rating at Anki) [1.again,2.hard,3.good,4.easy]\n * @return {number} next_D\n */\n next_difficulty(d: number, g: Grade): number {\n const next_d = d - this.param.w[6] * (g - 3);\n return this.constrain_difficulty(\n this.mean_reversion(this.param.w[4], next_d),\n );\n }\n\n /**\n * The formula used is :\n * $$\\min \\{\\max \\{D_0,1\\},10\\}$$\n * @param {number} difficulty D \\in [1,10]\n */\n constrain_difficulty(difficulty: number): number {\n return Math.min(Math.max(Number(difficulty.toFixed(2)), 1), 10);\n }\n\n /**\n * The formula used is :\n * $$w_7 \\cdot init +(1 - w_7) \\cdot current$$\n * @param {number} init $$w_2 : D_0(3) = w_2 + (R-2) \\cdot w_3= w_2$$\n * @param {number} current $$D - w_6 \\cdot (R - 2)$$\n * @return {number} difficulty\n */\n mean_reversion(init: number, current: number): number {\n return this.param.w[7] * init + (1 - this.param.w[7]) * current;\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_r(D,S,R,G) = S\\cdot(e^{w_8}\\cdot (11-D)\\cdot S^{-w_9}\\cdot(e^{w_10\\cdot(1-R)}-1)\\cdot w_15(if G=2) \\cdot w_16(if G=4)+1)$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @param {Grade} g Grade (Rating[0.again,1.hard,2.good,3.easy])\n * @return {number} S^\\prime_r new stability after recall\n */\n next_recall_stability(d: number, s: number, r: number, g: Grade): number {\n const hard_penalty = Rating.Hard === g ? this.param.w[15] : 1;\n const easy_bound = Rating.Easy === g ? this.param.w[16] : 1;\n return (\n s *\n (1 +\n Math.exp(this.param.w[8]) *\n (11 - d) *\n Math.pow(s, -this.param.w[9]) *\n (Math.exp((1 - r) * this.param.w[10]) - 1) *\n hard_penalty *\n easy_bound)\n );\n }\n\n /**\n * The formula used is :\n * $$S^\\prime_f(D,S,R) = w_11\\cdot D^{-w_{12}}\\cdot ((S+1)^{w_{13}}-1) \\cdot e^{w_{14}\\cdot(1-R)}.$$\n * @param {number} d Difficulty D \\in [1,10]\n * @param {number} s Stability (interval when R=90%)\n * @param {number} r Retrievability (probability of recall)\n * @return {number} S^\\prime_f new stability after forgetting\n */\n next_forget_stability(d: number, s: number, r: number): number {\n return (\n this.param.w[11] *\n Math.pow(d, -this.param.w[12]) *\n (Math.pow(s + 1, this.param.w[13]) - 1) *\n Math.exp((1 - r) * this.param.w[14])\n );\n }\n\n /**\n * The formula used is :\n * $$R(t,S) = (1 + \\frac{t}{9 \\cdot S})^{-1},$$\n * @param {number} t t days since the last review\n * @param {number} s Stability (interval when R=90%)\n * @return {number} r Retrievability (probability of recall)\n */\n current_retrievability(t: number, s: number): number {\n return Math.pow(1 + t / (9 * s), -1);\n }\n}\n","import { SchedulingCard } from \"./scheduler\";\nimport { fixDate, fixRating, fixState } from \"./help\";\nimport {\n Card,\n CardInput,\n DateInput,\n FSRSParameters,\n Rating,\n RecordLog,\n RecordLogItem,\n ReviewLog,\n ReviewLogInput,\n State,\n} from \"./models\";\nimport type { int } from \"./type\";\nimport { FSRSAlgorithm } from \"./algorithm\";\n\nexport class FSRS extends FSRSAlgorithm {\n constructor(param: Partial<FSRSParameters>) {\n super(param);\n }\n\n private preProcessCard(_card: CardInput): Card {\n return {\n ..._card,\n state: fixState(_card.state),\n due: fixDate(_card.due),\n last_review: _card.last_review ? fixDate(_card.last_review) : undefined,\n };\n }\n\n private preProcessDate(_date: DateInput): Date {\n return fixDate(_date);\n }\n\n private preProcessLog(_log: ReviewLogInput): ReviewLog {\n return {\n ..._log,\n rating: fixRating(_log.rating),\n state: fixState(_log.state),\n review: fixDate(_log.review),\n };\n }\n\n repeat = (card: CardInput, now: DateInput): RecordLog => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const s = new SchedulingCard(card, now).update_state(card.state);\n this.seed = String(now.getTime()) + String(card.reps);\n let easy_interval, good_interval, hard_interval;\n switch (card.state) {\n case State.New:\n this.init_ds(s);\n s.again.due = now.scheduler(1 as int);\n s.hard.due = now.scheduler(5 as int);\n s.good.due = now.scheduler(10 as int);\n easy_interval = this.next_interval(s.easy.stability);\n s.easy.scheduled_days = easy_interval;\n s.easy.due = now.scheduler(easy_interval, true);\n break;\n case State.Learning:\n case State.Relearning:\n hard_interval = 0;\n good_interval = this.next_interval(s.good.stability);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n case State.Review: {\n const interval = card.elapsed_days;\n const last_d = card.difficulty;\n const last_s = card.stability;\n const retrievability = this.current_retrievability(interval, last_s);\n this.next_ds(s, last_d, last_s, retrievability);\n hard_interval = this.next_interval(s.hard.stability);\n good_interval = this.next_interval(s.good.stability);\n hard_interval = Math.min(hard_interval, good_interval);\n good_interval = Math.max(good_interval, hard_interval + 1);\n easy_interval = Math.max(\n this.next_interval(s.easy.stability),\n good_interval + 1,\n );\n s.schedule(now, hard_interval, good_interval, easy_interval);\n break;\n }\n }\n return s.record_log(card, now);\n };\n\n get_retrievability = (card: Card, now: Date): undefined | string => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n if (card.state !== State.Review) {\n return undefined;\n }\n const t = Math.max(now.diff(card.last_review as Date, \"days\"), 0);\n return (\n (this.current_retrievability(t, card.stability) * 100).toFixed(2) + \"%\"\n );\n };\n\n rollback = (card: CardInput, log: ReviewLogInput): Card => {\n card = this.preProcessCard(card);\n log = this.preProcessLog(log);\n if (log.rating === Rating.Manual) {\n throw new Error(\"Cannot rollback a manual rating\");\n }\n let last_due, last_review, last_lapses;\n switch (log.state) {\n case State.New:\n last_due = log.due;\n last_review = undefined;\n last_lapses = 0;\n break;\n case State.Learning:\n case State.Relearning:\n case State.Review:\n last_due = log.review;\n last_review = log.due;\n last_lapses =\n card.lapses -\n (log.rating === Rating.Again && log.state === State.Review ? 1 : 0);\n break;\n }\n\n return {\n ...card,\n due: last_due,\n stability: log.stability,\n difficulty: log.difficulty,\n elapsed_days: log.last_elapsed_days,\n scheduled_days: log.scheduled_days,\n reps: Math.max(0, card.reps - 1),\n lapses: Math.max(0, last_lapses),\n state: log.state,\n last_review: last_review,\n };\n };\n\n forget = (\n card: CardInput,\n now: DateInput,\n reset_count: boolean = false,\n ): RecordLogItem => {\n card = this.preProcessCard(card);\n now = this.preProcessDate(now);\n const scheduled_days =\n card.state === State.New ? 0 : now.diff(card.last_review as Date, \"days\");\n const forget_log: ReviewLog = {\n rating: Rating.Manual,\n state: card.state,\n due: card.due,\n stability: card.stability,\n difficulty: card.difficulty,\n elapsed_days: 0,\n last_elapsed_days: card.elapsed_days,\n scheduled_days: scheduled_days,\n review: now,\n };\n const forget_card: Card = {\n ...card,\n due: now,\n stability: 0,\n difficulty: 0,\n elapsed_days: 0,\n scheduled_days: 0,\n reps: reset_count ? 0 : card.reps,\n lapses: reset_count ? 0 : card.lapses,\n state: State.New,\n last_review: card.last_review,\n };\n return { card: forget_card, log: forget_log };\n };\n}\n\nexport const fsrs = (params?: Partial<FSRSParameters>) => {\n return new FSRS(params || {});\n};\n"],"names":["State","Rating","date_scheduler","now","t","isDay","Date","getTime","date_diff","pre","unit","Error","diff","r","Math","floor","formatDate","date","year","getFullYear","month","getMonth","day","getDate","hours","getHours","minutes","getMinutes","seconds","getSeconds","padZero","num","prototype","scheduler","this","format","dueFormat","last_review","show_diff_message","TIMEUNIT","TIMEUNITFORMAT","due","timeUnit","fixDate","length","i","value","timestamp","parse","isNaN","fixState","fixRating","Grades","Again","Hard","Good","Easy","SchedulingCard","again","hard","good","easy","last_elapsed_days","copy","card","constructor","elapsed_days","state","New","reps","update_state","Learning","Review","Relearning","lapses","schedule","hard_interval","good_interval","easy_interval","scheduled_days","record_log","log","rating","stability","difficulty","review","default_request_retention","default_maximum_interval","default_w","default_enable_fuzz","FSRSVersion","generatorParameters","props","request_retention","maximum_interval","w","enable_fuzz","createEmptyCard","undefined","FSRSAlgorithm","param","intervalModifier","seed","init_ds","s","init_difficulty","init_stability","next_ds","last_d","last_s","retrievability","next_difficulty","next_forget_stability","next_recall_stability","g","max","min","apply_fuzz","ivl","fuzz_factor","pseudorandom","generator","round","min_ivl","max_ivl","next_interval","newInterval","d","next_d","constrain_difficulty","mean_reversion","Number","toFixed","init","current","hard_penalty","easy_bound","exp","pow","current_retrievability","FSRS","super","preProcessCard","_card","preProcessDate","_date","preProcessLog","_log","repeat","String","interval","get_retrievability","rollback","Manual","last_due","last_lapses","forget","reset_count","forget_log","fsrs","params"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ts-fsrs",
3
- "version": "3.1.1",
3
+ "version": "3.1.2",
4
4
  "description": "ts-fsrs is a TypeScript package used to implement the Free Spaced Repetition Scheduler (FSRS) algorithm. It helps developers apply FSRS to their flashcard applications, thereby improving the user learning experience.",
5
5
  "main": "dist/ts-fsrs.js",
6
6
  "module": "dist/ts-fsrs.mjs",