ts-fsrs 4.3.1 → 4.4.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/dist/index.d.ts CHANGED
@@ -63,10 +63,15 @@ interface FSRSParameters {
63
63
  enable_fuzz: boolean;
64
64
  enable_short_term: boolean;
65
65
  }
66
- type RescheduleOptions = {
67
- enable_fuzz?: boolean;
68
- dateHandler?: (date: Date) => DateInput;
69
- };
66
+ type FSRSHistory = Partial<Omit<ReviewLog, 'rating' | 'review' | 'elapsed_days'>> & ({
67
+ rating: Grade;
68
+ review: DateInput | Date;
69
+ } | {
70
+ rating: Rating.Manual;
71
+ due: DateInput | Date;
72
+ state: State;
73
+ review: DateInput | Date;
74
+ });
70
75
 
71
76
  declare const default_request_retention = 0.9;
72
77
  declare const default_maximum_interval = 36500;
@@ -121,6 +126,48 @@ interface IScheduler {
121
126
  preview(): IPreview;
122
127
  review(state: Grade): RecordLogItem;
123
128
  }
129
+ /**
130
+ * Options for rescheduling.
131
+ *
132
+ * @template T - The type of the result returned by the `recordLogHandler` function.
133
+ */
134
+ type RescheduleOptions<T = RecordLogItem> = {
135
+ /**
136
+ * A function that handles recording the log.
137
+ *
138
+ * @param recordLog - The log to be recorded.
139
+ * @returns The result of recording the log.
140
+ */
141
+ recordLogHandler: (recordLog: RecordLogItem) => T;
142
+ /**
143
+ * A function that defines the order of reviews.
144
+ *
145
+ * @param a - The first FSRSHistory object.
146
+ * @param b - The second FSRSHistory object.
147
+ * @returns A negative number if `a` should be ordered before `b`, a positive number if `a` should be ordered after `b`, or 0 if they have the same order.
148
+ */
149
+ reviewsOrderBy: (a: FSRSHistory, b: FSRSHistory) => number;
150
+ /**
151
+ * Indicating whether to skip manual steps.
152
+ */
153
+ skipManual: boolean;
154
+ /**
155
+ * Indicating whether to update the FSRS memory state.
156
+ */
157
+ update_memory_state: boolean;
158
+ /**
159
+ * The current date and time.
160
+ */
161
+ now: DateInput;
162
+ /**
163
+ * The input for the first card.
164
+ */
165
+ first_card?: CardInput;
166
+ };
167
+ type IReschedule<T = RecordLogItem> = {
168
+ collections: T[];
169
+ reschedule_item: T | null;
170
+ };
124
171
 
125
172
  declare global {
126
173
  export interface Date {
@@ -227,14 +274,13 @@ declare class FSRSAlgorithm {
227
274
  * @param {number} enable_fuzz - This adds a small random delay to the new interval time to prevent cards from sticking together and always being reviewed on the same day.
228
275
  * @return {number} - The fuzzed interval.
229
276
  **/
230
- apply_fuzz(ivl: number, elapsed_days: number, enable_fuzz?: boolean): int;
277
+ apply_fuzz(ivl: number, elapsed_days: number): int;
231
278
  /**
232
279
  * @see The formula used is : {@link FSRSAlgorithm.calculate_interval_modifier}
233
280
  * @param {number} s - Stability (interval when R=90%)
234
281
  * @param {number} elapsed_days t days since the last review
235
- * @param {number} enable_fuzz - This adds a small random delay to the new interval time to prevent cards from sticking together and always being reviewed on the same day.
236
282
  */
237
- next_interval(s: number, elapsed_days: number, enable_fuzz?: boolean): int;
283
+ next_interval(s: number, elapsed_days: number): int;
238
284
  /**
239
285
  * The formula used is :
240
286
  * $$\text{next}_d = D - w_6 \cdot (g - 3)$$
@@ -419,7 +465,7 @@ declare class FSRS extends FSRSAlgorithm {
419
465
  * @param format default:true , Convert the result to another type. (Optional)
420
466
  * @returns The retrievability of the card,if format is true, the result is a string, otherwise it is a number
421
467
  */
422
- get_retrievability<T extends boolean>(card: CardInput | Card, now?: DateInput, format?: T): (T extends true ? string : number);
468
+ get_retrievability<T extends boolean>(card: CardInput | Card, now?: DateInput, format?: T): T extends true ? string : number;
423
469
  /**
424
470
  *
425
471
  * @param card Card to be processed
@@ -499,32 +545,44 @@ declare class FSRS extends FSRSAlgorithm {
499
545
  */
500
546
  forget<R = RecordLogItem>(card: CardInput | Card, now: DateInput, reset_count?: boolean, afterHandler?: (recordLogItem: RecordLogItem) => R): R;
501
547
  /**
548
+ * Reschedules the current card and returns the rescheduled collections and reschedule item.
549
+ *
550
+ * @template T - The type of the record log item.
551
+ * @param {CardInput | Card} current_card - The current card to be rescheduled.
552
+ * @param {Array<FSRSHistory>} reviews - The array of FSRSHistory objects representing the reviews.
553
+ * @param {Partial<RescheduleOptions<T>>} options - The optional reschedule options.
554
+ * @returns {IReschedule<T>} - The rescheduled collections and reschedule item.
502
555
  *
503
- * @param cards scheduled card collection
504
- * @param options Reschedule options,fuzz is enabled by default.If the type of due is not Date, please implement dataHandler.
505
556
  * @example
506
- * ```typescript
507
- * type CardType = Card & {
508
- * cid: number;
509
- * };
510
- * const reviewCard: CardType = {
511
- * cid: 1,
512
- * due: new Date("2024-03-17 04:43:02"),
513
- * stability: 48.26139059062234,
514
- * difficulty: 5.67,
515
- * elapsed_days: 18,
516
- * scheduled_days: 51,
517
- * reps: 8,
518
- * lapses: 1,
519
- * state: State.Review,
520
- * last_review: new Date("2024-01-26 04:43:02"),
521
- * };
522
- * const f = fsrs();
523
- * const reschedule_cards = f.reschedule([reviewCard]);
524
557
  * ```
525
- *
558
+ const f = fsrs()
559
+ const grades: Grade[] = [Rating.Good, Rating.Good, Rating.Good, Rating.Good]
560
+ const reviews_at = [
561
+ new Date(2024, 8, 13),
562
+ new Date(2024, 8, 13),
563
+ new Date(2024, 8, 17),
564
+ new Date(2024, 8, 28),
565
+ ]
566
+
567
+ const reviews: FSRSHistory[] = []
568
+ for (let i = 0; i < grades.length; i++) {
569
+ reviews.push({
570
+ rating: grades[i],
571
+ review: reviews_at[i],
572
+ })
573
+ }
574
+
575
+ const results_short = scheduler.reschedule(
576
+ createEmptyCard(),
577
+ reviews,
578
+ {
579
+ skipManual: false,
580
+ }
581
+ )
582
+ console.log(results_short)
583
+ * ```
526
584
  */
527
- reschedule<T extends CardInput | Card>(cards: Array<T>, options?: RescheduleOptions): Array<T>;
585
+ reschedule<T = RecordLogItem>(current_card: CardInput | Card, reviews?: FSRSHistory[], options?: Partial<RescheduleOptions<T>>): IReschedule<T>;
528
586
  }
529
587
  /**
530
588
  * Create a new instance of TS-FSRS
@@ -553,4 +611,4 @@ declare class TypeConvert {
553
611
  static review_log(log: ReviewLogInput | ReviewLog): ReviewLog;
554
612
  }
555
613
 
556
- export { type Card, type CardInput, DECAY, type DateInput, FACTOR, FSRS, FSRSAlgorithm, type FSRSParameters, FSRSVersion, type Grade, Grades, type IPreview, type IScheduler, Rating, type RatingType, type RecordLog, type RecordLogItem, type ReviewLog, type ReviewLogInput, State, type StateType, TypeConvert, clamp, createEmptyCard, date_diff, date_scheduler, default_enable_fuzz, default_enable_short_term, default_maximum_interval, default_request_retention, default_w, type double, fixDate, fixRating, fixState, formatDate, fsrs, generatorParameters, get_fuzz_range, type int, show_diff_message, type unit };
614
+ export { type Card, type CardInput, DECAY, type DateInput, FACTOR, FSRS, FSRSAlgorithm, type FSRSParameters, FSRSVersion, type Grade, Grades, type IPreview, type IReschedule, type IScheduler, Rating, type RatingType, type RecordLog, type RecordLogItem, type RescheduleOptions, type ReviewLog, type ReviewLogInput, State, type StateType, TypeConvert, clamp, createEmptyCard, date_diff, date_scheduler, default_enable_fuzz, default_enable_short_term, default_maximum_interval, default_request_retention, default_w, type double, fixDate, fixRating, fixState, formatDate, fsrs, generatorParameters, get_fuzz_range, type int, show_diff_message, type unit };
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- var u=(r=>(r[r.New=0]="New",r[r.Learning=1]="Learning",r[r.Review=2]="Review",r[r.Relearning=3]="Relearning",r))(u||{}),l=(r=>(r[r.Manual=0]="Manual",r[r.Again=1]="Again",r[r.Hard=2]="Hard",r[r.Good=3]="Good",r[r.Easy=4]="Easy",r))(l||{});class d{static card(t){return{...t,state:d.state(t.state),due:d.time(t.due),last_review:t.last_review?d.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),s=l[`${e}${i}`];if(s===void 0)throw new Error(`Invalid rating:[${t}]`);return s}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),s=u[`${e}${i}`];if(s===void 0)throw new Error(`Invalid state:[${t}]`);return s}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:d.time(t.due),rating:d.rating(t.rating),state:d.state(t.state),review:d.time(t.review)}}}const E=.9,S=36500,R=[.4072,1.1829,3.1262,15.4722,7.2102,.5316,1.0651,.0234,1.616,.1544,1.0824,1.9813,.0953,.2975,2.2042,.2407,2.9466,.5034,.6567],$=!1,A=!0,T="v4.3.1 using FSRS V5.0",w=r=>{let t=R;return r?.w&&(r.w.length===19?t=r?.w:r.w.length===17&&(t=r?.w.concat([0,0]),console.debug("[FSRS V5]auto fill w to 19 length"))),{request_retention:r?.request_retention||E,maximum_interval:r?.maximum_interval||S,w:t,enable_fuzz:r?.enable_fuzz??$,enable_short_term:r?.enable_short_term??A}};function U(r,t){const e={due:r?d.time(r):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:u.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}Date.prototype.scheduler=function(r,t){return v(this,r,t)},Date.prototype.diff=function(r,t){return H(this,r,t)},Date.prototype.format=function(){return F(this)},Date.prototype.dueFormat=function(r,t,e){return L(this,r,t,e)};function v(r,t,e){return new Date(e?f(r).getTime()+t*24*60*60*1e3:f(r).getTime()+t*60*1e3)}function H(r,t,e){if(!r||!t)throw new Error("Invalid date");const i=f(r).getTime()-f(t).getTime();let s=0;switch(e){case"days":s=Math.floor(i/(24*60*60*1e3));break;case"minutes":s=Math.floor(i/(60*1e3));break}return s}function F(r){const t=f(r),e=t.getFullYear(),i=t.getMonth()+1,s=t.getDate(),a=t.getHours(),n=t.getMinutes(),h=t.getSeconds();return`${e}-${m(i)}-${m(s)} ${m(a)}:${m(n)}:${m(h)}`}function m(r){return r<10?`0${r}`:`${r}`}const p=[60,60,24,31,12],x=["second","min","hour","day","month","year"];function L(r,t,e,i=x){r=f(r),t=f(t),i.length!==x.length&&(i=x);let s=r.getTime()-t.getTime(),a;for(s/=1e3,a=0;a<p.length&&!(s<p[a]);a++)s/=p[a];return`${Math.floor(s)}${e?i[a]:""}`}function f(r){return d.time(r)}function Y(r){return d.state(r)}function j(r){return d.rating(r)}const G=[l.Again,l.Hard,l.Good,l.Easy],O=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function z(r,t,e){let i=1;for(const n of O)i+=n.factor*Math.max(Math.min(r,n.end)-n.start,0);r=Math.min(r,e);let s=Math.max(2,Math.round(r-i));const a=Math.min(Math.round(r+i),e);return r>t&&(s=Math.max(s,t+1)),s=Math.min(s,a),{min_ivl:s,max_ivl:a}}function g(r,t,e){return Math.min(Math.max(r,t),e)}class B{c;s0;s1;s2;constructor(t){const e=J();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function J(){let r=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){r+=t.charCodeAt(e);let i=.02519603282416938*r;r=i>>>0,i-=r,i*=r,r=i>>>0,i-=r,r+=i*4294967296}return(r>>>0)*23283064365386963e-26}}function K(r){const t=new B(r),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const b=-.5,M=19/81;class k{param;intervalModifier;_seed;constructor(t){this.param=new Proxy(w(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");return+((Math.pow(t,1/b)-1)/M).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,s){return i==="request_retention"&&Number.isFinite(s)&&(t.intervalModifier=t.calculate_interval_modifier(Number(s))),Reflect.set(e,i,s),!0}}}update_parameters(t){const e=w(t);for(const i in e)if(i in this.param){const s=i;this.param[s]=e[s]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return this.constrain_difficulty(this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1)}apply_fuzz(t,e,i){if(!i||t<2.5)return Math.round(t);const s=K(this._seed)(),{min_ivl:a,max_ivl:n}=z(t,e,this.param.maximum_interval);return Math.floor(s*(n-a+1)+a)}next_interval(t,e,i=this.param.enable_fuzz){const s=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(s,e,i)}next_difficulty(t,e){const i=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.init_difficulty(l.Easy),i))}constrain_difficulty(t){return Math.min(Math.max(+t.toFixed(8),1),10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,s){const a=l.Hard===s?this.param.w[15]:1,n=l.Easy===s?this.param.w[16]:1;return+g(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*a*n),.01,36500).toFixed(8)}next_forget_stability(t,e,i){return+g(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),.01,36500).toFixed(8)}next_short_term_stability(t,e){return+g(t*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),.01,36500).toFixed(8)}forgetting_curve(t,e){return+Math.pow(1+M*t/e,b).toFixed(8)}}class D{last;current;review_time;next=new Map;algorithm;constructor(t,e,i){this.algorithm=i,this.last=d.card(t),this.current=d.card(t),this.review_time=d.time(e),this.init()}init(){const{state:t,last_review:e}=this.current;let i=0;t!==u.New&&e&&(i=this.review_time.diff(e,"days")),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1,this.initSeed()}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of G)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(e){case u.New:i=this.newState(t);break;case u.Learning:case u.Relearning:i=this.learningState(t);break;case u.Review:i=this.reviewState(t);break}if(i)return i;throw new Error("Invalid grade")}initSeed(){const t=this.review_time.getTime(),e=this.current.reps,i=this.current.difficulty*this.current.stability;this.algorithm.seed=`${t}_${e}_${i}`}buildLog(t){const{last_review:e,due:i,elapsed_days:s}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:s,scheduled_days:this.current.scheduled_days,review:this.review_time}}}class N extends D{newState(t){const e=this.next.get(t);if(e)return e;const i=d.card(this.current);switch(i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),t){case l.Again:i.scheduled_days=0,i.due=this.review_time.scheduler(1),i.state=u.Learning;break;case l.Hard:i.scheduled_days=0,i.due=this.review_time.scheduler(5),i.state=u.Learning;break;case l.Good:i.scheduled_days=0,i.due=this.review_time.scheduler(10),i.state=u.Learning;break;case l.Easy:{const a=this.algorithm.next_interval(i.stability,this.current.elapsed_days,this.algorithm.parameters.enable_fuzz);i.scheduled_days=a,i.due=this.review_time.scheduler(a,!0),i.state=u.Review;break}default:throw new Error("Invalid grade")}const s={card:i,log:this.buildLog(t)};return this.next.set(t,s),s}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:s,stability:a}=this.last,n=d.card(this.current),h=this.current.elapsed_days;switch(n.difficulty=this.algorithm.next_difficulty(s,t),n.stability=this.algorithm.next_short_term_stability(a,t),t){case l.Again:{n.scheduled_days=0,n.due=this.review_time.scheduler(5,!1),n.state=i;break}case l.Hard:{n.scheduled_days=0,n.due=this.review_time.scheduler(10),n.state=i;break}case l.Good:{const c=this.algorithm.next_interval(n.stability,h);n.scheduled_days=c,n.due=this.review_time.scheduler(c,!0),n.state=u.Review;break}case l.Easy:{const c=this.algorithm.next_short_term_stability(a,l.Good),_=this.algorithm.next_interval(c,h),y=Math.max(this.algorithm.next_interval(n.stability,h),_+1);n.scheduled_days=y,n.due=this.review_time.scheduler(y,!0),n.state=u.Review;break}default:throw new Error("Invalid grade")}const o={card:n,log:this.buildLog(t)};return this.next.set(t,o),o}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:s,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),h=d.card(this.current),o=d.card(this.current),c=d.card(this.current),_=d.card(this.current);this.next_ds(h,o,c,_,s,a,n),this.next_interval(h,o,c,_,i),this.next_state(h,o,c,_),h.lapses+=1;const y={card:h,log:this.buildLog(l.Again)},C={card:o,log:super.buildLog(l.Hard)},V={card:c,log:super.buildLog(l.Good)},P={card:_,log:super.buildLog(l.Easy)};return this.next.set(l.Again,y),this.next.set(l.Hard,C),this.next.set(l.Good,V),this.next.set(l.Easy,P),this.next.get(t)}next_ds(t,e,i,s,a,n,h){t.difficulty=this.algorithm.next_difficulty(a,l.Again),t.stability=this.algorithm.next_forget_stability(a,n,h),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,h,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,h,l.Good),s.difficulty=this.algorithm.next_difficulty(a,l.Easy),s.stability=this.algorithm.next_recall_stability(a,n,h,l.Easy)}next_interval(t,e,i,s,a){let n,h;n=this.algorithm.next_interval(e.stability,a),h=this.algorithm.next_interval(i.stability,a),n=Math.min(n,h),h=Math.max(h,n+1);const o=Math.max(this.algorithm.next_interval(s.stability,a),h+1);t.scheduled_days=0,t.due=this.review_time.scheduler(5),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=h,i.due=this.review_time.scheduler(h,!0),s.scheduled_days=o,s.due=this.review_time.scheduler(o,!0)}next_state(t,e,i,s){t.state=u.Relearning,e.state=u.Review,i.state=u.Review,s.state=u.Review}}class I extends D{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=d.card(this.current),s=d.card(this.current),a=d.card(this.current),n=d.card(this.current);this.init_ds(i,s,a,n);const h=0;return this.next_interval(i,s,a,n,h),this.next_state(i,s,a,n),this.update_next(i,s,a,n),this.next.get(t)}init_ds(t,e,i,s){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),s.difficulty=this.algorithm.init_difficulty(l.Easy),s.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:s,stability:a}=this.last,n=this.algorithm.forgetting_curve(i,a),h=d.card(this.current),o=d.card(this.current),c=d.card(this.current),_=d.card(this.current);return this.next_ds(h,o,c,_,s,a,n),this.next_interval(h,o,c,_,i),this.next_state(h,o,c,_),h.lapses+=1,this.update_next(h,o,c,_),this.next.get(t)}next_ds(t,e,i,s,a,n,h){t.difficulty=this.algorithm.next_difficulty(a,l.Again),t.stability=this.algorithm.next_forget_stability(a,n,h),e.difficulty=this.algorithm.next_difficulty(a,l.Hard),e.stability=this.algorithm.next_recall_stability(a,n,h,l.Hard),i.difficulty=this.algorithm.next_difficulty(a,l.Good),i.stability=this.algorithm.next_recall_stability(a,n,h,l.Good),s.difficulty=this.algorithm.next_difficulty(a,l.Easy),s.stability=this.algorithm.next_recall_stability(a,n,h,l.Easy)}next_interval(t,e,i,s,a){let n,h,o,c;n=this.algorithm.next_interval(t.stability,a),h=this.algorithm.next_interval(e.stability,a),o=this.algorithm.next_interval(i.stability,a),c=this.algorithm.next_interval(s.stability,a),n=Math.min(n,h),h=Math.max(h,n+1),o=Math.max(o,h+1),c=Math.max(c,o+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=h,e.due=this.review_time.scheduler(h,!0),i.scheduled_days=o,i.due=this.review_time.scheduler(o,!0),s.scheduled_days=c,s.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,s){t.state=u.Review,e.state=u.Review,i.state=u.Review,s.state=u.Review}update_next(t,e,i,s){const a={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},h={card:i,log:super.buildLog(l.Good)},o={card:s,log:super.buildLog(l.Easy)};this.next.set(l.Again,a),this.next.set(l.Hard,n),this.next.set(l.Good,h),this.next.set(l.Easy,o)}}class q extends k{Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?N:I}params_handler_proxy(){const t=this;return{set:function(e,i,s){return i==="request_retention"&&Number.isFinite(s)?t.intervalModifier=t.calculate_interval_modifier(Number(s)):i==="enable_short_term"&&(t.Scheduler=s===!0?N:I),Reflect.set(e,i,s),!0}}}repeat(t,e,i){const s=this.Scheduler,a=new s(t,e,this).preview();return i&&typeof i=="function"?i(a):a}next(t,e,i,s){const a=this.Scheduler,n=new a(t,e,this),h=d.rating(i);if(h===l.Manual)throw new Error("Cannot review a manual rating");const o=n.review(h);return s&&typeof s=="function"?s(o):o}get_retrievability(t,e,i=!0){const s=d.card(t);e=e?d.time(e):new Date;const a=s.state!==u.New?Math.max(e.diff(s.last_review,"days"),0):0,n=s.state!==u.New?this.forgetting_curve(a,+s.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const s=d.card(t),a=d.review_log(e);if(a.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,h,o;switch(a.state){case u.New:n=a.due,h=void 0,o=0;break;case u.Learning:case u.Relearning:case u.Review:n=a.review,h=a.due,o=s.lapses-(a.rating===l.Again&&a.state===u.Review?1:0);break}const c={...s,due:n,stability:a.stability,difficulty:a.difficulty,elapsed_days:a.last_elapsed_days,scheduled_days:a.scheduled_days,reps:Math.max(0,s.reps-1),lapses:Math.max(0,o),state:a.state,last_review:h};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,s){const a=d.card(t);e=d.time(e);const n=a.state===u.New?0:e.diff(a.last_review,"days"),h={rating:l.Manual,state:a.state,due:a.due,stability:a.stability,difficulty:a.difficulty,elapsed_days:0,last_elapsed_days:a.elapsed_days,scheduled_days:n,review:e},o={card:{...a,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:a.reps,lapses:i?0:a.lapses,state:u.New,last_review:a.last_review},log:h};return s&&typeof s=="function"?s(o):o}reschedule(t,e={}){if(!Array.isArray(t))throw new Error("cards must be an array");const i=[];for(const s of t){if(d.state(s.state)!==u.Review||!s.last_review)continue;const a=Math.floor(s.scheduled_days),n=this.next_interval(+s.stability.toFixed(2),Math.round(s.elapsed_days),e.enable_fuzz??!0);if(n===a||n===0)continue;const h={...s};h.scheduled_days=n;const o=v(h.last_review,n,!0);e.dateHandler&&typeof e.dateHandler=="function"?h.due=e.dateHandler(o):h.due=o,i.push(h)}return i}}const Q=r=>new q(r||{});export{b as DECAY,M as FACTOR,q as FSRS,k as FSRSAlgorithm,T as FSRSVersion,G as Grades,l as Rating,u as State,d as TypeConvert,g as clamp,U as createEmptyCard,H as date_diff,v as date_scheduler,$ as default_enable_fuzz,A as default_enable_short_term,S as default_maximum_interval,E as default_request_retention,R as default_w,f as fixDate,j as fixRating,Y as fixState,F as formatDate,Q as fsrs,w as generatorParameters,z as get_fuzz_range,L as show_diff_message};
1
+ var u=(r=>(r[r.New=0]="New",r[r.Learning=1]="Learning",r[r.Review=2]="Review",r[r.Relearning=3]="Relearning",r))(u||{}),l=(r=>(r[r.Manual=0]="Manual",r[r.Again=1]="Again",r[r.Hard=2]="Hard",r[r.Good=3]="Good",r[r.Easy=4]="Easy",r))(l||{});class h{static card(t){return{...t,state:h.state(t.state),due:h.time(t.due),last_review:t.last_review?h.time(t.last_review):void 0}}static rating(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),a=l[`${e}${i}`];if(a===void 0)throw new Error(`Invalid rating:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid rating:[${t}]`)}static state(t){if(typeof t=="string"){const e=t.charAt(0).toUpperCase(),i=t.slice(1).toLowerCase(),a=u[`${e}${i}`];if(a===void 0)throw new Error(`Invalid state:[${t}]`);return a}else if(typeof t=="number")return t;throw new Error(`Invalid state:[${t}]`)}static time(t){if(typeof t=="object"&&t instanceof Date)return t;if(typeof t=="string"){const e=Date.parse(t);if(isNaN(e))throw new Error(`Invalid date:[${t}]`);return new Date(e)}else if(typeof t=="number")return new Date(t);throw new Error(`Invalid date:[${t}]`)}static review_log(t){return{...t,due:h.time(t.due),rating:h.rating(t.rating),state:h.state(t.state),review:h.time(t.review)}}}const $=.9,A=36500,F=[.4072,1.1829,3.1262,15.4722,7.2102,.5316,1.0651,.0234,1.616,.1544,1.0824,1.9813,.0953,.2975,2.2042,.2407,2.9466,.5034,.6567],L=!1,H=!0,P="v4.4.2 using FSRS V5.0",b=r=>{let t=F;return r?.w&&(r.w.length===19?t=r?.w:r.w.length===17&&(t=r?.w.concat([0,0]),t[4]=+(t[5]*2+t[4]).toFixed(8),t[5]=+(Math.log(t[5]*3+1)/3).toFixed(8),console.debug("[FSRS V5]auto fill w to 19 length"))),{request_retention:r?.request_retention||$,maximum_interval:r?.maximum_interval||A,w:t,enable_fuzz:r?.enable_fuzz??L,enable_short_term:r?.enable_short_term??H}};function w(r,t){const e={due:r?h.time(r):new Date,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:0,lapses:0,state:u.New,last_review:void 0};return t&&typeof t=="function"?t(e):e}Date.prototype.scheduler=function(r,t){return G(this,r,t)},Date.prototype.diff=function(r,t){return k(this,r,t)},Date.prototype.format=function(){return N(this)},Date.prototype.dueFormat=function(r,t,e){return D(this,r,t,e)};function G(r,t,e){return new Date(e?_(r).getTime()+t*24*60*60*1e3:_(r).getTime()+t*60*1e3)}function k(r,t,e){if(!r||!t)throw new Error("Invalid date");const i=_(r).getTime()-_(t).getTime();let a=0;switch(e){case"days":a=Math.floor(i/(24*60*60*1e3));break;case"minutes":a=Math.floor(i/(60*1e3));break}return a}function N(r){const t=_(r),e=t.getFullYear(),i=t.getMonth()+1,a=t.getDate(),s=t.getHours(),n=t.getMinutes(),d=t.getSeconds();return`${e}-${g(i)}-${g(a)} ${g(s)}:${g(n)}:${g(d)}`}function g(r){return r<10?`0${r}`:`${r}`}const M=[60,60,24,31,12],R=["second","min","hour","day","month","year"];function D(r,t,e,i=R){r=_(r),t=_(t),i.length!==R.length&&(i=R);let a=r.getTime()-t.getTime(),s;for(a/=1e3,s=0;s<M.length&&!(a<M[s]);s++)a/=M[s];return`${Math.floor(a)}${e?i[s]:""}`}function _(r){return h.time(r)}function U(r){return h.state(r)}function Y(r){return h.rating(r)}const z=[l.Again,l.Hard,l.Good,l.Easy],j=[{start:2.5,end:7,factor:.15},{start:7,end:20,factor:.1},{start:20,end:1/0,factor:.05}];function I(r,t,e){let i=1;for(const n of j)i+=n.factor*Math.max(Math.min(r,n.end)-n.start,0);r=Math.min(r,e);let a=Math.max(2,Math.round(r-i));const s=Math.min(Math.round(r+i),e);return r>t&&(a=Math.max(a,t+1)),a=Math.min(a,s),{min_ivl:a,max_ivl:s}}function p(r,t,e){return Math.min(Math.max(r,t),e)}class B{c;s0;s1;s2;constructor(t){const e=J();this.c=1,this.s0=e(" "),this.s1=e(" "),this.s2=e(" "),t==null&&(t=+new Date),this.s0-=e(t),this.s0<0&&(this.s0+=1),this.s1-=e(t),this.s1<0&&(this.s1+=1),this.s2-=e(t),this.s2<0&&(this.s2+=1)}next(){const t=2091639*this.s0+this.c*23283064365386963e-26;return this.s0=this.s1,this.s1=this.s2,this.s2=t-(this.c=t|0),this.s2}set state(t){this.c=t.c,this.s0=t.s0,this.s1=t.s1,this.s2=t.s2}get state(){return{c:this.c,s0:this.s0,s1:this.s1,s2:this.s2}}}function J(){let r=4022871197;return function(t){t=String(t);for(let e=0;e<t.length;e++){r+=t.charCodeAt(e);let i=.02519603282416938*r;r=i>>>0,i-=r,i*=r,r=i>>>0,i-=r,r+=i*4294967296}return(r>>>0)*23283064365386963e-26}}function K(r){const t=new B(r),e=()=>t.next();return e.int32=()=>t.next()*4294967296|0,e.double=()=>e()+(e()*2097152|0)*11102230246251565e-32,e.state=()=>t.state,e.importState=i=>(t.state=i,e),e}const E=-.5,S=19/81;class q{param;intervalModifier;_seed;constructor(t){this.param=new Proxy(b(t),this.params_handler_proxy()),this.intervalModifier=this.calculate_interval_modifier(this.param.request_retention)}get interval_modifier(){return this.intervalModifier}set seed(t){this._seed=t}calculate_interval_modifier(t){if(t<=0||t>1)throw new Error("Requested retention rate should be in the range (0,1]");return+((Math.pow(t,1/E)-1)/S).toFixed(8)}get parameters(){return this.param}set parameters(t){this.update_parameters(t)}params_handler_proxy(){const t=this;return{set:function(e,i,a){return i==="request_retention"&&Number.isFinite(a)&&(t.intervalModifier=t.calculate_interval_modifier(Number(a))),Reflect.set(e,i,a),!0}}}update_parameters(t){const e=b(t);for(const i in e)if(i in this.param){const a=i;this.param[a]=e[a]}}init_stability(t){return Math.max(this.param.w[t-1],.1)}init_difficulty(t){return this.constrain_difficulty(this.param.w[4]-Math.exp((t-1)*this.param.w[5])+1)}apply_fuzz(t,e){if(!this.param.enable_fuzz||t<2.5)return Math.round(t);const i=K(this._seed)(),{min_ivl:a,max_ivl:s}=I(t,e,this.param.maximum_interval);return Math.floor(i*(s-a+1)+a)}next_interval(t,e){const i=Math.min(Math.max(1,Math.round(t*this.intervalModifier)),this.param.maximum_interval);return this.apply_fuzz(i,e)}next_difficulty(t,e){const i=t-this.param.w[6]*(e-3);return this.constrain_difficulty(this.mean_reversion(this.init_difficulty(l.Easy),i))}constrain_difficulty(t){return Math.min(Math.max(+t.toFixed(8),1),10)}mean_reversion(t,e){return+(this.param.w[7]*t+(1-this.param.w[7])*e).toFixed(8)}next_recall_stability(t,e,i,a){const s=l.Hard===a?this.param.w[15]:1,n=l.Easy===a?this.param.w[16]:1;return+p(e*(1+Math.exp(this.param.w[8])*(11-t)*Math.pow(e,-this.param.w[9])*(Math.exp((1-i)*this.param.w[10])-1)*s*n),.01,36500).toFixed(8)}next_forget_stability(t,e,i){return+p(this.param.w[11]*Math.pow(t,-this.param.w[12])*(Math.pow(e+1,this.param.w[13])-1)*Math.exp((1-i)*this.param.w[14]),.01,36500).toFixed(8)}next_short_term_stability(t,e){return+p(t*Math.exp(this.param.w[17]*(e-3+this.param.w[18])),.01,36500).toFixed(8)}forgetting_curve(t,e){return+Math.pow(1+S*t/e,E).toFixed(8)}}class C{last;current;review_time;next=new Map;algorithm;constructor(t,e,i){this.algorithm=i,this.last=h.card(t),this.current=h.card(t),this.review_time=h.time(e),this.init()}init(){const{state:t,last_review:e}=this.current;let i=0;t!==u.New&&e&&(i=this.review_time.diff(e,"days")),this.current.last_review=this.review_time,this.current.elapsed_days=i,this.current.reps+=1,this.initSeed()}preview(){return{[l.Again]:this.review(l.Again),[l.Hard]:this.review(l.Hard),[l.Good]:this.review(l.Good),[l.Easy]:this.review(l.Easy),[Symbol.iterator]:this.previewIterator.bind(this)}}*previewIterator(){for(const t of z)yield this.review(t)}review(t){const{state:e}=this.last;let i;switch(e){case u.New:i=this.newState(t);break;case u.Learning:case u.Relearning:i=this.learningState(t);break;case u.Review:i=this.reviewState(t);break}if(i)return i;throw new Error("Invalid grade")}initSeed(){const t=this.review_time.getTime(),e=this.current.reps,i=this.current.difficulty*this.current.stability;this.algorithm.seed=`${t}_${e}_${i}`}buildLog(t){const{last_review:e,due:i,elapsed_days:a}=this.last;return{rating:t,state:this.current.state,due:e||i,stability:this.current.stability,difficulty:this.current.difficulty,elapsed_days:this.current.elapsed_days,last_elapsed_days:a,scheduled_days:this.current.scheduled_days,review:this.review_time}}}class T extends C{newState(t){const e=this.next.get(t);if(e)return e;const i=h.card(this.current);switch(i.difficulty=this.algorithm.init_difficulty(t),i.stability=this.algorithm.init_stability(t),t){case l.Again:i.scheduled_days=0,i.due=this.review_time.scheduler(1),i.state=u.Learning;break;case l.Hard:i.scheduled_days=0,i.due=this.review_time.scheduler(5),i.state=u.Learning;break;case l.Good:i.scheduled_days=0,i.due=this.review_time.scheduler(10),i.state=u.Learning;break;case l.Easy:{const s=this.algorithm.next_interval(i.stability,this.current.elapsed_days);i.scheduled_days=s,i.due=this.review_time.scheduler(s,!0),i.state=u.Review;break}default:throw new Error("Invalid grade")}const a={card:i,log:this.buildLog(t)};return this.next.set(t,a),a}learningState(t){const e=this.next.get(t);if(e)return e;const{state:i,difficulty:a,stability:s}=this.last,n=h.card(this.current),d=this.current.elapsed_days;switch(n.difficulty=this.algorithm.next_difficulty(a,t),n.stability=this.algorithm.next_short_term_stability(s,t),t){case l.Again:{n.scheduled_days=0,n.due=this.review_time.scheduler(5,!1),n.state=i;break}case l.Hard:{n.scheduled_days=0,n.due=this.review_time.scheduler(10),n.state=i;break}case l.Good:{const c=this.algorithm.next_interval(n.stability,d);n.scheduled_days=c,n.due=this.review_time.scheduler(c,!0),n.state=u.Review;break}case l.Easy:{const c=this.algorithm.next_short_term_stability(s,l.Good),f=this.algorithm.next_interval(c,d),y=Math.max(this.algorithm.next_interval(n.stability,d),f+1);n.scheduled_days=y,n.due=this.review_time.scheduler(y,!0),n.state=u.Review;break}default:throw new Error("Invalid grade")}const o={card:n,log:this.buildLog(t)};return this.next.set(t,o),o}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);this.next_ds(d,o,c,f,a,s,n),this.next_interval(d,o,c,f,i),this.next_state(d,o,c,f),d.lapses+=1;const y={card:d,log:this.buildLog(l.Again)},v={card:o,log:super.buildLog(l.Hard)},m={card:c,log:super.buildLog(l.Good)},x={card:f,log:super.buildLog(l.Easy)};return this.next.set(l.Again,y),this.next.set(l.Hard,v),this.next.set(l.Good,m),this.next.set(l.Easy,x),this.next.get(t)}next_ds(t,e,i,a,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again),t.stability=this.algorithm.next_forget_stability(s,n,d),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,a,s){let n,d;n=this.algorithm.next_interval(e.stability,s),d=this.algorithm.next_interval(i.stability,s),n=Math.min(n,d),d=Math.max(d,n+1);const o=Math.max(this.algorithm.next_interval(a.stability,s),d+1);t.scheduled_days=0,t.due=this.review_time.scheduler(5),e.scheduled_days=n,e.due=this.review_time.scheduler(n,!0),i.scheduled_days=d,i.due=this.review_time.scheduler(d,!0),a.scheduled_days=o,a.due=this.review_time.scheduler(o,!0)}next_state(t,e,i,a){t.state=u.Relearning,e.state=u.Review,i.state=u.Review,a.state=u.Review}}class V extends C{newState(t){const e=this.next.get(t);if(e)return e;this.current.scheduled_days=0,this.current.elapsed_days=0;const i=h.card(this.current),a=h.card(this.current),s=h.card(this.current),n=h.card(this.current);this.init_ds(i,a,s,n);const d=0;return this.next_interval(i,a,s,n,d),this.next_state(i,a,s,n),this.update_next(i,a,s,n),this.next.get(t)}init_ds(t,e,i,a){t.difficulty=this.algorithm.init_difficulty(l.Again),t.stability=this.algorithm.init_stability(l.Again),e.difficulty=this.algorithm.init_difficulty(l.Hard),e.stability=this.algorithm.init_stability(l.Hard),i.difficulty=this.algorithm.init_difficulty(l.Good),i.stability=this.algorithm.init_stability(l.Good),a.difficulty=this.algorithm.init_difficulty(l.Easy),a.stability=this.algorithm.init_stability(l.Easy)}learningState(t){return this.reviewState(t)}reviewState(t){const e=this.next.get(t);if(e)return e;const i=this.current.elapsed_days,{difficulty:a,stability:s}=this.last,n=this.algorithm.forgetting_curve(i,s),d=h.card(this.current),o=h.card(this.current),c=h.card(this.current),f=h.card(this.current);return this.next_ds(d,o,c,f,a,s,n),this.next_interval(d,o,c,f,i),this.next_state(d,o,c,f),d.lapses+=1,this.update_next(d,o,c,f),this.next.get(t)}next_ds(t,e,i,a,s,n,d){t.difficulty=this.algorithm.next_difficulty(s,l.Again),t.stability=this.algorithm.next_forget_stability(s,n,d),e.difficulty=this.algorithm.next_difficulty(s,l.Hard),e.stability=this.algorithm.next_recall_stability(s,n,d,l.Hard),i.difficulty=this.algorithm.next_difficulty(s,l.Good),i.stability=this.algorithm.next_recall_stability(s,n,d,l.Good),a.difficulty=this.algorithm.next_difficulty(s,l.Easy),a.stability=this.algorithm.next_recall_stability(s,n,d,l.Easy)}next_interval(t,e,i,a,s){let n,d,o,c;n=this.algorithm.next_interval(t.stability,s),d=this.algorithm.next_interval(e.stability,s),o=this.algorithm.next_interval(i.stability,s),c=this.algorithm.next_interval(a.stability,s),n=Math.min(n,d),d=Math.max(d,n+1),o=Math.max(o,d+1),c=Math.max(c,o+1),t.scheduled_days=n,t.due=this.review_time.scheduler(n,!0),e.scheduled_days=d,e.due=this.review_time.scheduler(d,!0),i.scheduled_days=o,i.due=this.review_time.scheduler(o,!0),a.scheduled_days=c,a.due=this.review_time.scheduler(c,!0)}next_state(t,e,i,a){t.state=u.Review,e.state=u.Review,i.state=u.Review,a.state=u.Review}update_next(t,e,i,a){const s={card:t,log:this.buildLog(l.Again)},n={card:e,log:super.buildLog(l.Hard)},d={card:i,log:super.buildLog(l.Good)},o={card:a,log:super.buildLog(l.Easy)};this.next.set(l.Again,s),this.next.set(l.Hard,n),this.next.set(l.Good,d),this.next.set(l.Easy,o)}}class Q{fsrs;constructor(t){this.fsrs=t}replay(t,e,i){return this.fsrs.next(t,e,i)}handleManualRating(t,e,i,a,s,n,d){if(typeof e>"u")throw new Error("reschedule: state is required for manual rating");let o,c;if(e===u.New)o={rating:l.Manual,state:e,due:d??i,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,review:i},c=w(i),c.last_review=i;else{if(typeof d>"u")throw new Error("reschedule: due is required for manual rating");const f=d.diff(i,"days");o={rating:l.Manual,state:t.state,due:t.last_review||t.due,stability:t.stability,difficulty:t.difficulty,elapsed_days:a,last_elapsed_days:t.elapsed_days,scheduled_days:t.scheduled_days,review:i},c={...t,state:e,due:d,last_review:i,stability:s||t.stability,difficulty:n||t.difficulty,elapsed_days:a,scheduled_days:f,reps:t.reps+1}}return{card:c,log:o}}reschedule(t,e){const i=[];let a=w(t.due);for(const s of e){let n;if(s.review=h.time(s.review),s.rating===l.Manual){let d=0;a.state!==u.New&&a.last_review&&(d=s.review.diff(a.last_review,"days")),n=this.handleManualRating(a,s.state,s.review,d,s.stability,s.difficulty,s.due?h.time(s.due):void 0)}else n=this.replay(a,s.review,s.rating);i.push(n),a=n.card}return i}calculateManualRecord(t,e,i,a){if(!i)return null;const{card:s,log:n}=i,d=h.card(t);return d.due.getTime()===s.due.getTime()?null:(d.scheduled_days=s.due.diff(d.due,"days"),this.handleManualRating(d,s.state,h.time(e),n.elapsed_days,a?s.stability:void 0,a?s.difficulty:void 0,s.due))}}class O extends q{Scheduler;constructor(t){super(t);const{enable_short_term:e}=this.parameters;this.Scheduler=e?T:V}params_handler_proxy(){const t=this;return{set:function(e,i,a){return i==="request_retention"&&Number.isFinite(a)?t.intervalModifier=t.calculate_interval_modifier(Number(a)):i==="enable_short_term"&&(t.Scheduler=a===!0?T:V),Reflect.set(e,i,a),!0}}}repeat(t,e,i){const a=this.Scheduler,s=new a(t,e,this).preview();return i&&typeof i=="function"?i(s):s}next(t,e,i,a){const s=this.Scheduler,n=new s(t,e,this),d=h.rating(i);if(d===l.Manual)throw new Error("Cannot review a manual rating");const o=n.review(d);return a&&typeof a=="function"?a(o):o}get_retrievability(t,e,i=!0){const a=h.card(t);e=e?h.time(e):new Date;const s=a.state!==u.New?Math.max(e.diff(a.last_review,"days"),0):0,n=a.state!==u.New?this.forgetting_curve(s,+a.stability.toFixed(8)):0;return i?`${(n*100).toFixed(2)}%`:n}rollback(t,e,i){const a=h.card(t),s=h.review_log(e);if(s.rating===l.Manual)throw new Error("Cannot rollback a manual rating");let n,d,o;switch(s.state){case u.New:n=s.due,d=void 0,o=0;break;case u.Learning:case u.Relearning:case u.Review:n=s.review,d=s.due,o=a.lapses-(s.rating===l.Again&&s.state===u.Review?1:0);break}const c={...a,due:n,stability:s.stability,difficulty:s.difficulty,elapsed_days:s.last_elapsed_days,scheduled_days:s.scheduled_days,reps:Math.max(0,a.reps-1),lapses:Math.max(0,o),state:s.state,last_review:d};return i&&typeof i=="function"?i(c):c}forget(t,e,i=!1,a){const s=h.card(t);e=h.time(e);const n=s.state===u.New?0:e.diff(s.last_review,"days"),d={rating:l.Manual,state:s.state,due:s.due,stability:s.stability,difficulty:s.difficulty,elapsed_days:0,last_elapsed_days:s.elapsed_days,scheduled_days:n,review:e},o={card:{...s,due:e,stability:0,difficulty:0,elapsed_days:0,scheduled_days:0,reps:i?0:s.reps,lapses:i?0:s.lapses,state:u.New,last_review:s.last_review},log:d};return a&&typeof a=="function"?a(o):o}reschedule(t,e=[],i={}){const{recordLogHandler:a,reviewsOrderBy:s,skipManual:n=!0,now:d=new Date,update_memory_state:o=!1}=i;s&&typeof s=="function"&&e.sort(s),n&&(e=e.filter(x=>x.rating!==l.Manual));const c=new Q(this),f=c.reschedule(i.first_card||w(),e),y=f.length,v=h.card(t),m=c.calculateManualRecord(v,d,y?f[y-1]:void 0,o);return a&&typeof a=="function"?{collections:f.map(a),reschedule_item:m?a(m):null}:{collections:f,reschedule_item:m}}}const W=r=>new O(r||{});export{E as DECAY,S as FACTOR,O as FSRS,q as FSRSAlgorithm,P as FSRSVersion,z as Grades,l as Rating,u as State,h as TypeConvert,p as clamp,w as createEmptyCard,k as date_diff,G as date_scheduler,L as default_enable_fuzz,H as default_enable_short_term,A as default_maximum_interval,$ as default_request_retention,F as default_w,_ as fixDate,Y as fixRating,U as fixState,N as formatDate,W as fsrs,b as generatorParameters,I as get_fuzz_range,D as show_diff_message};
2
2
  //# sourceMappingURL=index.mjs.map