Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merge/Dev 3.1.0-beta8 #52

Merged
merged 15 commits into from
Nov 20, 2023
5 changes: 5 additions & 0 deletions .babelrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"presets": [
["@babel/env", {"modules": false}]
]
}
38 changes: 38 additions & 0 deletions .github/workflows/deploy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Deploy to GitHub Pages

on:
push:
branches:
- master

permissions:
contents: read
pages: write
id-token: write

jobs:
build-and-deploy:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 16

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Build docs
run: pnpm run docs
- name: Copy example folder
run: cp -R example docs/example

- name: Deploy to GitHub Pages
uses: JamesIves/[email protected]
with:
branch: gh-pages
folder: docs
30 changes: 30 additions & 0 deletions .github/workflows/npm-beta-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This workflow will run tests using node and then publish a package to GitHub Packages when a release is created
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages

name: Publish Beta Package to npm.js

on:
push:
branches:
- dev

jobs:
publish-npm:
runs-on: ubuntu-latest
permissions:
contents: read
id-token: write
steps:
- uses: actions/checkout@v2
- uses: pnpm/[email protected]
with:
version: 8.7.1
- run: pnpm install
- run: pnpm lint
- run: pnpm test
- run: pnpm build
- uses: JS-DevTools/npm-publish@v2
with:
token: ${{secrets.npm_token}}
provenance: true
tag: beta
19 changes: 4 additions & 15 deletions .github/workflows/npm-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,12 @@ name: Publish Package to npm.js
on:
release:
types: [published]
push:
branches:
- master
repository_dispatch:
types: [publish-npm]

jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: pnpm/[email protected]
with:
version: 8.7.1
- run: pnpm install
- run: pnpm lint
- run: pnpm test
- run: pnpm build

publish-npm:
needs: build
runs-on: ubuntu-latest
permissions:
contents: write
Expand All @@ -35,6 +22,8 @@ jobs:
with:
version: 8.7.1
- run: pnpm install
- run: pnpm lint
- run: pnpm test
- run: pnpm build
- uses: JS-DevTools/npm-publish@v2
with:
Expand Down
57 changes: 57 additions & 0 deletions .github/workflows/pr-test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
name: PR Test

on:
pull_request:
branches:
- master

jobs:
test:
runs-on: ubuntu-latest
permissions:
checks: write
pull-requests: write
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Set up Node.js
uses: actions/setup-node@v2
with:
node-version: 16

- uses: pnpm/[email protected]
with:
version: 8.7.1

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run tests
run: pnpm test

- name: jest coverage report
uses: ArtiomTr/[email protected]
with:
github-token: ${{ secrets.GITHUB_TOKEN }}

- name: Check test status
id: test-status
run: echo "::set-output name=status::$(if grep -q 'Test failed' test-results.txt; then echo 'failure'; else echo 'success'; fi)"

merge:
needs: test
runs-on: ubuntu-latest
if: ${{ needs.test.outputs.status == 'success' }}

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Trigger npm-publish workflow
uses: peter-evans/repository-dispatch@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
repository: ishiko732/ts-fsrs
event-type: publish-npm
19 changes: 9 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
# About The
[![ts-fsrs npm version](https://img.shields.io/npm/v/ts-fsrs.svg)](https://www.npmjs.com/package/ts-fsrs)
[![ts-fsrs beta npm version](https://img.shields.io/npm/v/ts-fsrs/beta.svg)](https://www.npmjs.com/package/ts-fsrs)
[![Build and Publish](https://github.com/ishiko732/ts-fsrs/actions/workflows/npm-publish.yml/badge.svg)](https://github.com/ishiko732/ts-fsrs/actions/workflows/npm-publish.yml)
[![Deploy](https://github.com/ishiko732/ts-fsrs/actions/workflows/deploy.yml/badge.svg)](https://github.com/ishiko732/ts-fsrs/actions/workflows/deploy.yml)

ts-fsrs is a TypeScript package used to implement the [Free Spaced Repetition Scheduler (FSRS) algorithm](https://github.com/open-spaced-repetition/free-spaced-repetition-scheduler). It helps
developers apply FSRS to their flashcard applications, there by improving the user learning experience.
Expand All @@ -7,15 +11,8 @@ developers apply FSRS to their flashcard applications, there by improving the us

```
npm install ts-fsrs
```

# Environment Variables
If you need to customize default parameters, you can modify the values using `.env`/`.env.local`/`.env.production`/`.env.development`.

Copy the [.env.local.example](./example/.env.local.example) file in this directory to .env.local (which will be ignored by Git):

```bash
cp .env.local.example .env.local
yarn install ts-fsrs
pnpm install ts-fsrs
```

# Example
Expand Down Expand Up @@ -51,7 +48,9 @@ Grades.forEach(grade => { // [Rating.Again, Rating.Hard, Rating.Good, Rating.Eas
});
```

> More examples refer to the [Example](https://github.com/ishiko732/ts-fsrs/blob/master/example/index.ts)
More examples refer:
- [Browser](https://github.com/ishiko732/ts-fsrs/blob/master/example/example.html) (ts-fsrs package using CDN)
- [Next.js+Prisma](https://github.com/ishiko732/ts-fsrs-demo)


# Basic Use
Expand Down
57 changes: 56 additions & 1 deletion __tests__/FSRSV4.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import {
generatorParameters,
FSRS,
createEmptyCard,
State,
Grade,
Grades,
} from "../src/fsrs";

Expand Down Expand Up @@ -47,11 +49,12 @@ describe("FSRS V4 AC by py-fsrs", () => {
],
enable_fuzz: false,
});
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);
let scheduling_cards = f.repeat(card, now);
const ratings = [
const ratings: Grade[] = [
Rating.Good,
Rating.Good,
Rating.Good,
Expand All @@ -68,6 +71,16 @@ describe("FSRS V4 AC by py-fsrs", () => {
];
const ivl_history: number[] = [];
for (const rating of ratings) {
for (const check of grade) {
const rollbackCard = f.rollback(
scheduling_cards[check].card,
scheduling_cards[check].log,
);
expect(rollbackCard).toEqual(card);
expect(scheduling_cards[check].log.elapsed_days).toEqual(
card.last_review ? now.diff(card.last_review as Date, "days") : 0,
);
}
card = scheduling_cards[rating].card;
const ivl = card.scheduled_days;
ivl_history.push(ivl);
Expand All @@ -79,4 +92,46 @@ describe("FSRS V4 AC by py-fsrs", () => {
0, 5, 16, 43, 106, 236, 0, 0, 12, 25, 47, 85, 147,
]);
});

it("first repeat", () => {
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[] = [];
const elapsed_days: number[] = [];
const scheduled_days: number[] = [];
const reps: number[] = [];
const lapses: number[] = [];
const states: State[] = [];
for (const rating of grades) {
const first_card = scheduling_cards[rating].card;
stability.push(first_card.stability);
difficulty.push(first_card.difficulty);
reps.push(first_card.reps);
lapses.push(first_card.lapses);
elapsed_days.push(first_card.elapsed_days);
scheduled_days.push(first_card.scheduled_days);
states.push(first_card.state);
}
expect(stability).toEqual([1.14, 1.01, 5.44, 14.67]);
expect(difficulty).toEqual([8.4348, 6.8686, 5.3024, 3.7361999999999993]);
expect(reps).toEqual([1, 1, 1, 1]);
expect(lapses).toEqual([1, 0, 0, 0]);
expect(elapsed_days).toEqual([0, 0, 0, 0]);
expect(scheduled_days).toEqual([0, 0, 0, 15]);
expect(states).toEqual([
State.Learning,
State.Learning,
State.Learning,
State.Review,
]);
});
});
74 changes: 74 additions & 0 deletions __tests__/elapsed_days.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Ref:https://github.com/ishiko732/ts-fsrs/issues/44

import { fsrs, FSRS, createEmptyCard, Rating, Grade } from "../src/fsrs";

describe("elapsed_days", () => {
const f: FSRS = fsrs();

const createDue = new Date(Date.UTC(2023, 9, 18, 14, 32, 3, 370));
const grades: Grade[] = [
Rating.Good,
Rating.Again,
Rating.Again,
Rating.Good,
];
let currentLog = null;
let index = 0;
let card = createEmptyCard(createDue);
test("first repeat[Rating.Good]", () => {
const firstDue = new Date(Date.UTC(2023, 10, 5, 8, 27, 2, 605));
const sc = f.repeat(card, firstDue);
currentLog = sc[grades[index]].log;

expect(currentLog.elapsed_days).toEqual(0);
// console.log(sc[grades[index]].log)
card = sc[grades[index]].card;
// console.log(card)
index += 1;
});

test("second repeat[Rating.Again]", () => {
// 2023-11-08 15:02:09.791,4.93,2023-11-05 08:27:02.605
const secondDue = new Date(Date.UTC(2023, 10, 8, 15, 2, 9, 791));
expect(card).not.toBeNull()
const sc = f.repeat(card, secondDue);

currentLog = sc[grades[index]].log;
expect(currentLog.elapsed_days).toEqual(secondDue.diff(card.last_review as Date,'days')); // 3
expect(currentLog.elapsed_days).toEqual(3); // 0
card = sc[grades[index]].card;
// console.log(card)
// console.log(currentLog)
index += 1;
});

test("third repeat[Rating.Again]", () => {
// 2023-11-08 15:02:30.799,4.93,2023-11-08 15:02:09.791
const secondDue = new Date(Date.UTC(2023, 10, 8, 15, 2, 30, 799));
expect(card).not.toBeNull()
const sc = f.repeat(card, secondDue);

currentLog = sc[grades[index]].log;
expect(currentLog.elapsed_days).toEqual(secondDue.diff(card.last_review as Date,'days')); // 0
expect(currentLog.elapsed_days).toEqual(0); // 0
// console.log(currentLog);
card = sc[grades[index]].card;
// console.log(card);
index += 1;
});

test("fourth repeat[Rating.Good]", () => {
// 2023-11-08 15:04:08.739,4.93,2023-11-08 15:02:30.799
const secondDue = new Date(Date.UTC(2023, 10, 8, 15, 4, 8, 739));
expect(card).not.toBeNull()
const sc = f.repeat(card, secondDue);

currentLog = sc[grades[index]].log;
expect(currentLog.elapsed_days).toEqual(secondDue.diff(card.last_review as Date,'days')); // 0
expect(currentLog.elapsed_days).toEqual(0); // 0
// console.log(currentLog);
card = sc[grades[index]].card;
// console.log(card);
index += 1;
})
});
Loading
Loading