Phase 3 follow-up: type-check + tests grün, ts-fsrs v5 API
- tsconfig.base.json: allowImportingTsExtensions + noEmit (.ts-Imports
in dev, kein tsc-Output, vitest/bun/vite handhaben Build)
- ts-fsrs v5.3.2 API-Updates:
- scheduler.next(card, now, grade) statt repeat(card, now)[rating].card
- Grade-Type für RATING_TO_FSRS (excluded Manual)
- learning_steps-Feld auf Review (Schema, Drizzle-Column, Adapter,
DTO-Konverter, Tests)
- apps/web: extends .svelte-kit/tsconfig.json (SvelteKit-Empfehlung),
test-Script mit --passWithNoTests
- apps/api: dropped types: ['bun-types'] (stale)
- pnpm-lock.yaml committed
Status:
- pnpm run type-check ✅ 4/4 packages grün (api, domain, web mit
svelte-check 0 errors)
- pnpm run test ✅ 46 Tests grün (cards-domain: 27, apps/api: 19,
apps/web: --passWithNoTests)
- pnpm install ✅ 136 packages, 8s
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
45a47e0ffd
commit
5f67bd9f3e
11 changed files with 2345 additions and 35 deletions
|
|
@ -8,20 +8,18 @@
|
|||
|
||||
import {
|
||||
createEmptyCard,
|
||||
default_w,
|
||||
FSRS,
|
||||
generatorParameters,
|
||||
Rating as FsrsRating,
|
||||
State as FsrsState,
|
||||
type Card as FsrsCard,
|
||||
type FSRSParameters,
|
||||
type Grade,
|
||||
} from 'ts-fsrs';
|
||||
|
||||
import type { Rating, Review, ReviewState } from './schemas/review.ts';
|
||||
import type { FsrsSettings } from './schemas/fsrs-settings.ts';
|
||||
|
||||
/** Public Rating ↔ ts-fsrs Rating mapping. */
|
||||
const RATING_TO_FSRS: Record<Rating, FsrsRating> = {
|
||||
/** Public Rating ↔ ts-fsrs Grade (Manual ist explizit ausgeschlossen). */
|
||||
const RATING_TO_FSRS: Record<Rating, Grade> = {
|
||||
again: FsrsRating.Again,
|
||||
hard: FsrsRating.Hard,
|
||||
good: FsrsRating.Good,
|
||||
|
|
@ -45,13 +43,14 @@ const STATE_TO_FSRS: Record<ReviewState, FsrsState> = {
|
|||
|
||||
/** Baut einen FSRS-Scheduler aus per-Deck-Settings + globalen Defaults. */
|
||||
export function buildScheduler(settings: FsrsSettings = {}): FSRS {
|
||||
const params: FSRSParameters = generatorParameters({
|
||||
request_retention: settings.request_retention,
|
||||
maximum_interval: settings.maximum_interval,
|
||||
w: settings.w ?? default_w,
|
||||
enable_fuzz: settings.enable_fuzz ?? true,
|
||||
return new FSRS({
|
||||
...(settings.request_retention !== undefined && {
|
||||
request_retention: settings.request_retention,
|
||||
}),
|
||||
...(settings.maximum_interval !== undefined && { maximum_interval: settings.maximum_interval }),
|
||||
...(settings.w !== undefined && { w: settings.w }),
|
||||
...(settings.enable_fuzz !== undefined && { enable_fuzz: settings.enable_fuzz }),
|
||||
});
|
||||
return new FSRS(params);
|
||||
}
|
||||
|
||||
/** Initialer Review-State für eine neue Karte (sub_index). */
|
||||
|
|
@ -72,6 +71,7 @@ export function newReview(args: {
|
|||
difficulty: fc.difficulty,
|
||||
elapsed_days: fc.elapsed_days,
|
||||
scheduled_days: fc.scheduled_days,
|
||||
learning_steps: fc.learning_steps,
|
||||
reps: fc.reps,
|
||||
lapses: fc.lapses,
|
||||
state: STATE_FROM_FSRS[fc.state],
|
||||
|
|
@ -88,10 +88,8 @@ export function gradeReview(
|
|||
): Review {
|
||||
const reviewedAt = now ?? new Date();
|
||||
const scheduler = buildScheduler(settings);
|
||||
const fc = toFsrsCard(current);
|
||||
const log = scheduler.repeat(fc, reviewedAt);
|
||||
const next = log[RATING_TO_FSRS[rating]].card;
|
||||
return fromFsrsCard(current, next);
|
||||
const result = scheduler.next(toFsrsCard(current), reviewedAt, RATING_TO_FSRS[rating]);
|
||||
return fromFsrsCard(current, result.card);
|
||||
}
|
||||
|
||||
/** Konvertiert unseren Review-Datensatz in eine ts-fsrs Card. */
|
||||
|
|
@ -102,6 +100,7 @@ export function toFsrsCard(r: Review): FsrsCard {
|
|||
difficulty: r.difficulty,
|
||||
elapsed_days: r.elapsed_days,
|
||||
scheduled_days: r.scheduled_days,
|
||||
learning_steps: r.learning_steps,
|
||||
reps: r.reps,
|
||||
lapses: r.lapses,
|
||||
state: STATE_TO_FSRS[r.state],
|
||||
|
|
@ -118,6 +117,7 @@ export function fromFsrsCard(prev: Review, fc: FsrsCard): Review {
|
|||
difficulty: fc.difficulty,
|
||||
elapsed_days: fc.elapsed_days,
|
||||
scheduled_days: fc.scheduled_days,
|
||||
learning_steps: fc.learning_steps,
|
||||
reps: fc.reps,
|
||||
lapses: fc.lapses,
|
||||
state: STATE_FROM_FSRS[fc.state],
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ export const ReviewSchema = z
|
|||
difficulty: z.number().min(0).max(10),
|
||||
elapsed_days: z.number().nonnegative().default(0),
|
||||
scheduled_days: z.number().nonnegative().default(0),
|
||||
learning_steps: z.number().int().nonnegative().default(0),
|
||||
reps: z.number().int().nonnegative().default(0),
|
||||
lapses: z.number().int().nonnegative().default(0),
|
||||
state: ReviewStateSchema.default('new'),
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
"extends": "../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue