Skip to content

Commit

Permalink
pref/separate the code
Browse files Browse the repository at this point in the history
  • Loading branch information
ishiko732 committed Sep 26, 2024
1 parent 3db3103 commit 1ad0c06
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 75 deletions.
84 changes: 10 additions & 74 deletions src/fsrs/fsrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { TypeConvert } from './convert'
import BasicScheduler from './impl/basic_scheduler'
import LongTermScheduler from './impl/long_term_scheduler'
import { createEmptyCard } from './default'
import { Reschedule } from './reschedule'

export class FSRS extends FSRSAlgorithm {
private Scheduler
Expand Down Expand Up @@ -411,81 +412,16 @@ export class FSRS extends FSRSAlgorithm {
if (skipManual) {
reviews = reviews.filter((review) => review.rating !== Rating.Manual)
}
const datum: T[] = []
let card: Card | undefined = undefined
for (const [index, review] of reviews.entries()) {
card = <Card>(card || createEmptyCard(review.review))
let log: ReviewLog
if (!skipManual && review.rating === Rating.Manual) {
if (typeof review.state === 'undefined') {
throw new Error('reschedule: state is required for manual rating')
}
if (<State>review.state === State.New) {
log = {
rating: Rating.Manual,
state: <State>review.state,
due: <Date>review.due,
stability: card.stability,
difficulty: card.difficulty,
elapsed_days: review.elapsed_days,
last_elapsed_days: card.elapsed_days,
scheduled_days: card.scheduled_days,
review: <Date>review.review,
}
card = createEmptyCard<Card>(review.review)
card.last_review = review.review
} else {
if (typeof review.due === 'undefined') {
throw new Error('reschedule: due is required for manual rating')
}
const scheduled_days = review.due.diff(review.review as Date, 'days')
const elapsed_days =
review.elapsed_days ||
review.review.diff(card.last_review as Date, 'days')
log = {
rating: Rating.Manual,
state: <State>review.state,
due: <Date>card.last_review,
stability: card.stability,
difficulty: card.difficulty,
elapsed_days: elapsed_days,
last_elapsed_days: card.elapsed_days,
scheduled_days: card.scheduled_days,
review: <Date>review.review,
}
card = <Card>{
...card,
state: <State>review.state,
due: <Date>review.due,
last_review: <Date>review.review,
stability: review.stability || card.stability,
difficulty: review.difficulty || card.difficulty,
elapsed_days: elapsed_days,
scheduled_days: scheduled_days,
reps: index + 1,
}
}
datum.push(
<T>(
(recordLogHandler && typeof recordLogHandler === 'function'
? recordLogHandler({ card, log })
: { card, log })
)
)
} else {
const item = this.next(card, review.review, <Grade>review.rating)
card = item.card
datum.push(
<T>(
(recordLogHandler && typeof recordLogHandler === 'function'
? recordLogHandler(item)
: item)
)
)
}
}
const rescheduleSvc = new Reschedule(this)

return datum
const collections = rescheduleSvc.reschedule(
options.card || createEmptyCard(),
reviews
)
if (recordLogHandler && typeof recordLogHandler === 'function') {
return collections.map(recordLogHandler)
}
return collections as T[]
}
}

Expand Down
110 changes: 110 additions & 0 deletions src/fsrs/reschedule.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { TypeConvert } from './convert'
import { createEmptyCard } from './default'
import type { FSRS } from './fsrs'
import {
Card,
CardInput,
FSRSHistory,
Grade,
Rating,
RecordLogItem,
ReviewLog,
State,
} from './models'

export class Reschedule {
private fsrs: FSRS
constructor(fsrs: FSRS) {
this.fsrs = fsrs
}

replay(card: Card, reviewed: Date, rating: Grade): RecordLogItem {
return this.fsrs.next(card, reviewed, rating)
}

processManual(
card: Card,
state: State,
reviewed: Date,
elapsed_days?: number,
stability?: number,
difficulty?: number,
due?: Date
): RecordLogItem {
if (typeof state === 'undefined') {
throw new Error('reschedule: state is required for manual rating')
}
let log: ReviewLog
let next_card: Card
if (<State>state === State.New) {
log = {
rating: Rating.Manual,
state: state,
due: <Date>due ?? reviewed,
stability: card.stability,
difficulty: card.difficulty,
elapsed_days: elapsed_days || 0,
last_elapsed_days: card.elapsed_days,
scheduled_days: card.scheduled_days,
review: <Date>reviewed,
} satisfies ReviewLog
next_card = createEmptyCard<Card>(reviewed)
next_card.last_review = reviewed
} else {
if (typeof due === 'undefined') {
throw new Error('reschedule: due is required for manual rating')
}
const scheduled_days = due.diff(reviewed as Date, 'days')
elapsed_days =
elapsed_days || reviewed.diff(card.last_review as Date, 'days')
log = {
rating: Rating.Manual,
state: <State>state,
due: <Date>card.last_review,
stability: card.stability,
difficulty: card.difficulty,
elapsed_days: elapsed_days,
last_elapsed_days: card.elapsed_days,
scheduled_days: card.scheduled_days,
review: <Date>reviewed,
} satisfies ReviewLog
next_card = {
...card,
state: <State>state,
due: <Date>due,
last_review: <Date>reviewed,
stability: stability || card.stability,
difficulty: difficulty || card.difficulty,
elapsed_days: elapsed_days,
scheduled_days: scheduled_days,
reps: card.reps + 1,
} satisfies Card
}

return { card: next_card, log }
}

reschedule(card: CardInput, reviews: FSRSHistory[]) {
const collections: RecordLogItem[] = []
let _card = TypeConvert.card(card)
for (const review of reviews) {
let item: RecordLogItem
if (review.rating === Rating.Manual) {
item = this.processManual(
_card,
review.state,
review.review,
review.elapsed_days,
review.stability,
review.difficulty,
review.due
)
} else {
item = this.replay(_card, review.review, review.rating)
}
collections.push(item)
_card = item.card
}
return collections
}
}
4 changes: 3 additions & 1 deletion src/fsrs/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import type {
Card,
CardInput,
FSRSHistory,
Grade,
RecordLog,
Expand All @@ -21,7 +22,8 @@ export interface IScheduler {
}

export type RescheduleOptions<T> = {
recordLogHandler:(recordLog: RecordLogItem) => T
recordLogHandler: (recordLog: RecordLogItem) => T
reviewsOrderBy: (a: FSRSHistory, b: FSRSHistory) => number
skipManual: boolean
card?: CardInput
}

0 comments on commit 1ad0c06

Please sign in to comment.