Skip to content

Commit

Permalink
Feat/Support iteration in the repeat (#121)
Browse files Browse the repository at this point in the history
* Feat/Support iteration in the `repeat` method

* update test

* update README

* bump version to 4.2.0
  • Loading branch information
ishiko732 authored Sep 7, 2024
1 parent 18a19bb commit c0e4d68
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 34 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ The workflow for TS-FSRS can be referenced from the following resources:

# Usage
The [email protected] package requires Node.js version `16.0.0` or higher. Starting with `[email protected]`, the minimum required Node.js version is 18.0.0.
The `[email protected]` package requires Node.js version `16.0.0` or higher. Starting with `[email protected]`, the minimum required Node.js version is `18.0.0`.
From version `3.5.6` onwards, ts-fsrs supports CommonJS, ESM, and UMD module systems.

```
Expand All @@ -32,15 +32,17 @@ bun install ts-fsrs
```typescript
import {createEmptyCard, formatDate, fsrs, generatorParameters, Rating, Grades} from 'ts-fsrs';

const params = generatorParameters({ enable_fuzz: true });
const params = generatorParameters({ enable_fuzz: true, enable_short_term: false });
const f = fsrs(params);
const card = createEmptyCard(new Date('2022-2-1 10:00:00'));// createEmptyCard();
const now = new Date('2022-2-2 10:00:00');// new Date();
const scheduling_cards = f.repeat(card, now);

// console.log(scheduling_cards);
Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const { log, card } = scheduling_cards[grade];
for (const item of scheduling_cards) {
// grades = [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const grade = item.log.rating
const { log, card } = item;
console.group(`${Rating[grade]}`);
console.table({
[`card_${Rating[grade]}`]: {
Expand All @@ -57,7 +59,7 @@ Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Eas
});
console.groupEnd();
console.log('----------------------------------------------------------------');
});
}
```

More refer:
Expand Down Expand Up @@ -105,6 +107,8 @@ import {
let card: Card = createEmptyCard();
const f: FSRS = new FSRS(); // or const f: FSRS = fsrs(params);
let scheduling_cards: RecordLog = f.repeat(card, new Date());
// if you want to specify the grade, you can use the following code: (ts-fsrs >=4.0.0)
// let scheduling_card: RecordLog = f.next(card, new Date(), Rating.Good);
```

## 4. **Retrieving Scheduled Cards**:
Expand Down
12 changes: 8 additions & 4 deletions README_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,17 @@ bun install ts-fsrs
```typescript
import {createEmptyCard, formatDate, fsrs, generatorParameters, Rating, Grades} from 'ts-fsrs';

const params = generatorParameters({enable_fuzz: true});
const params = generatorParameters({ enable_fuzz: true, enable_short_term: false });
const f = fsrs(params);
const card = createEmptyCard(new Date('2022-2-1 10:00:00'));// createEmptyCard();
const now = new Date('2022-2-2 10:00:00');// new Date();
const scheduling_cards = f.repeat(card, now);

// console.log(scheduling_cards);
Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const {log, card} = scheduling_cards[grade];
for (const item of scheduling_cards) {
// grades = [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const grade = item.log.rating
const { log, card } = item;
console.group(`${Rating[grade]}`);
console.table({
[`card_${Rating[grade]}`]: {
Expand All @@ -55,7 +57,7 @@ Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Eas
});
console.groupEnd();
console.log('----------------------------------------------------------------');
});
}
```

更多的参考:
Expand Down Expand Up @@ -109,6 +111,8 @@ import {
let card: Card = createEmptyCard();
const f: FSRS = new FSRS(); // or const f: FSRS = fsrs(params);
let scheduling_cards: RecordLog = f.repeat(card, new Date());
// 如果你想要指定一个特定的评级,你可以这样做:(ts-fsrs版本必须 >= 4.0.0)
// let scheduling_cards: RecordLog = f.next(card, new Date(), Rating.Good);
```

## 4. **检查调度卡片信息**:
Expand Down
12 changes: 8 additions & 4 deletions README_JA.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,17 @@ bun install ts-fsrs
```typescript
import {createEmptyCard, formatDate, fsrs, generatorParameters, Rating, Grades} from 'ts-fsrs';

const params = generatorParameters({enable_fuzz: true});
const params = generatorParameters({ enable_fuzz: true, enable_short_term: false });
const f = fsrs(params);
const card = createEmptyCard(new Date('2022-2-1 10:00:00'));// createEmptyCard();
const now = new Date('2022-2-2 10:00:00');// new Date();
const scheduling_cards = f.repeat(card, now);

// console.log(scheduling_cards);
Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const {log, card} = scheduling_cards[grade];
for (const item of scheduling_cards) {
// grades = [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
const grade = item.log.rating
const { log, card } = item;
console.group(`${Rating[grade]}`);
console.table({
[`card_${Rating[grade]}`]: {
Expand All @@ -58,7 +60,7 @@ Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Eas
});
console.groupEnd();
console.log('----------------------------------------------------------------');
});
}
```

もっと:
Expand Down Expand Up @@ -114,6 +116,8 @@ import {
let card: Card = createEmptyCard();
const f: FSRS = new FSRS(); // or const f: FSRS = fsrs(params);
let scheduling_cards: RecordLog = f.repeat(card, new Date());
// もしくは、開発者が評価を指定する場合:(TS-FSRSのバージョンは4.0.0以降である必要があります)
// let scheduling_cards: RecordLog = f.repeat(card, new Date(), Rating.Good);
```

## 4. **スケジュールされたカードの取得**:
Expand Down
13 changes: 3 additions & 10 deletions __tests__/FSRSV5.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ describe('FSRS V5 ', () => {
0.6468,
]
const f: FSRS = fsrs({ w })
const grade: Grade[] = [Rating.Again, Rating.Hard, Rating.Good, Rating.Easy]
it('ivl_history', () => {
let card = createEmptyCard()
let now = new Date(2022, 11, 29, 12, 30, 0, 0)
Expand All @@ -37,7 +36,7 @@ describe('FSRS V5 ', () => {
]
const ivl_history: number[] = []
for (const rating of ratings) {
for (const check of grade) {
for (const check of Grades) {
const rollbackCard = f.rollback(
scheduling_cards[check].card,
scheduling_cards[check].log
Expand Down Expand Up @@ -89,12 +88,6 @@ describe('FSRS V5 ', () => {
const card = createEmptyCard()
const now = new Date(2022, 11, 29, 12, 30, 0, 0)
const scheduling_cards = f.repeat(card, now)
const grades: Grade[] = [
Rating.Again,
Rating.Hard,
Rating.Good,
Rating.Easy,
]

const stability: number[] = []
const difficulty: number[] = []
Expand All @@ -103,8 +96,8 @@ describe('FSRS V5 ', () => {
const reps: number[] = []
const lapses: number[] = []
const states: State[] = []
for (const rating of grades) {
const first_card = scheduling_cards[rating].card
for (const item of scheduling_cards) {
const first_card = item.card
stability.push(first_card.stability)
difficulty.push(first_card.difficulty)
reps.push(first_card.reps)
Expand Down
40 changes: 40 additions & 0 deletions __tests__/impl/abstract_scheduler.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import {
createEmptyCard,
fsrs,
Grade,
type IPreview,
Rating,
} from '../../src/fsrs'

describe('basic schduler', () => {
const now = new Date()

it('[Symbol.iterator]', () => {
const card = createEmptyCard(now)
const f = fsrs()
const preview = f.repeat(card, now)
const again = f.next(card, now, Rating.Again)
const hard = f.next(card, now, Rating.Hard)
const good = f.next(card, now, Rating.Good)
const easy = f.next(card, now, Rating.Easy)

const expect_preview = {
[Rating.Again]: again,
[Rating.Hard]: hard,
[Rating.Good]: good,
[Rating.Easy]: easy,
[Symbol.iterator]: preview[Symbol.iterator],
} satisfies IPreview
expect(preview).toEqual(expect_preview)
for (const item of preview) {
expect(item).toEqual(expect_preview[<Grade>item.log.rating])
}
const iterator = preview[Symbol.iterator]()
expect(iterator.next().value).toEqual(again)
expect(iterator.next().value).toEqual(hard)
expect(iterator.next().value).toEqual(good)
expect(iterator.next().value).toEqual(easy)
expect(iterator.next().done).toBeTruthy()
})

})
18 changes: 18 additions & 0 deletions __tests__/impl/basic_schduler.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,17 @@ describe('basic schduler', () => {
[Rating.Hard]: hard,
[Rating.Good]: good,
[Rating.Easy]: easy,
[Symbol.iterator]: basicScheduler[`previewIterator`].bind(basicScheduler),
})
for (const item of preview) {
expect(item).toEqual(basicScheduler.review(<Grade>item.log.rating))
}
const iterator = preview[Symbol.iterator]()
expect(iterator.next().value).toEqual(again)
expect(iterator.next().value).toEqual(hard)
expect(iterator.next().value).toEqual(good)
expect(iterator.next().value).toEqual(easy)
expect(iterator.next().done).toBeTruthy()
})
it('[State.New]invalid grade', () => {
const card = createEmptyCard(now)
Expand All @@ -52,7 +62,11 @@ describe('basic schduler', () => {
[Rating.Hard]: hard,
[Rating.Good]: good,
[Rating.Easy]: easy,
[Symbol.iterator]: basicScheduler[`previewIterator`].bind(basicScheduler),
})
for (const item of preview) {
expect(item).toEqual(basicScheduler.review(<Grade>item.log.rating))
}
})
it('[State.Learning]invalid grade', () => {
const cardByNew = createEmptyCard(now)
Expand Down Expand Up @@ -82,7 +96,11 @@ describe('basic schduler', () => {
[Rating.Hard]: hard,
[Rating.Good]: good,
[Rating.Easy]: easy,
[Symbol.iterator]: basicScheduler[`previewIterator`].bind(basicScheduler),
})
for (const item of preview) {
expect(item).toEqual(basicScheduler.review(<Grade>item.log.rating))
}
})
it('[State.Review]invalid grade', () => {
const cardByNew = createEmptyCard(now)
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ts-fsrs",
"version": "4.1.3",
"version": "4.2.0",
"description": "ts-fsrs is a versatile package based on TypeScript that supports ES modules, CommonJS, and UMD. It implements the Free Spaced Repetition Scheduler (FSRS) algorithm, enabling developers to integrate FSRS into their flashcard applications to enhance the user learning experience.",
"main": "dist/index.cjs",
"umd": "dist/index.umd.js",
Expand Down
16 changes: 12 additions & 4 deletions src/fsrs/abstract_schduler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { FSRSAlgorithm } from './algorithm'
import { TypeConvert } from './convert'
import { Grades } from './help'
import {
type Card,
type RecordLog,
type Grade,
type RecordLogItem,
State,
Expand All @@ -11,7 +11,7 @@ import {
type CardInput,
type DateInput,
} from './models'
import type { IScheduler } from './types'
import type { IPreview, IScheduler } from './types'

export abstract class AbstractScheduler implements IScheduler {
protected last: Card
Expand Down Expand Up @@ -45,14 +45,22 @@ export abstract class AbstractScheduler implements IScheduler {
this.initSeed()
}

public preview(): RecordLog {
public preview(): IPreview {
return {
[Rating.Again]: this.review(Rating.Again),
[Rating.Hard]: this.review(Rating.Hard),
[Rating.Good]: this.review(Rating.Good),
[Rating.Easy]: this.review(Rating.Easy),
} satisfies RecordLog
[Symbol.iterator]: this.previewIterator.bind(this),
} satisfies IPreview
}

private *previewIterator(): IterableIterator<RecordLogItem> {
for (const grade of Grades) {
yield this.review(grade)
}
}

public review(grade: Grade): RecordLogItem {
const { state } = this.last
let item: RecordLogItem | undefined
Expand Down
2 changes: 1 addition & 1 deletion src/fsrs/default.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const default_w = [
export const default_enable_fuzz = false
export const default_enable_short_term = true

export const FSRSVersion: string = 'v4.1.3 using FSRS V5.0'
export const FSRSVersion: string = 'v4.2.0 using FSRS V5.0'

export const generatorParameters = (
props?: Partial<FSRSParameters>
Expand Down
6 changes: 3 additions & 3 deletions src/fsrs/fsrs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
ReviewLogInput,
State,
} from './models'
import type { int } from './types'
import type { int, IPreview } from './types'
import { FSRSAlgorithm } from './algorithm'
import { TypeConvert } from './convert'
import BasicScheduler from './impl/basic_schduler'
Expand Down Expand Up @@ -106,10 +106,10 @@ export class FSRS extends FSRSAlgorithm {
* const recordLog = f.repeat(card, new Date(), repeatAfterHandler);
* ```
*/
repeat<R = RecordLog>(
repeat<R = IPreview>(
card: CardInput | Card,
now: DateInput,
afterHandler?: (recordLog: RecordLog) => R
afterHandler?: (recordLog: IPreview) => R
): R {
const Schduler = this.Schduler
const instace = new Schduler(card, now, this satisfies FSRSAlgorithm)
Expand Down
7 changes: 5 additions & 2 deletions src/fsrs/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import type {
Card,
Grade,
RecordLog,
RecordLogItem,
Expand All @@ -9,7 +8,11 @@ export type unit = 'days' | 'minutes'
export type int = number & { __int__: void }
export type double = number & { __double__: void }

export interface IPreview extends RecordLog {
[Symbol.iterator](): IterableIterator<RecordLogItem>
}

export interface IScheduler {
preview(): RecordLog
preview(): IPreview
review(state: Grade): RecordLogItem
}

0 comments on commit c0e4d68

Please sign in to comment.