@open-spaced-repetition/sm-2
Version:
Typescript Package for SM-2 Spaced Repetition
138 lines (136 loc) • 3.56 kB
JavaScript
// src/Card.ts
var Card = class _Card {
constructor(cardId = null, n = 0, EF = 2.5, I = 0, due = null, needsExtraReview = false) {
if (cardId == null) {
cardId = Date.now();
}
this.cardId = cardId;
this.n = n;
this.EF = EF;
this.I = I;
if (due == null) {
due = /* @__PURE__ */ new Date();
}
this.due = due;
this.needsExtraReview = needsExtraReview;
}
equals(other) {
return this.cardId == other.cardId && this.n == other.n && this.EF == other.EF && this.I == other.I && this.due.getTime() == other.due.getTime() && this.needsExtraReview == other.needsExtraReview;
}
clone() {
return new _Card(
this.cardId,
this.n,
this.EF,
this.I,
new Date(this.due),
this.needsExtraReview
);
}
toJSON() {
return {
cardId: this.cardId,
n: this.n,
EF: this.EF,
I: this.I,
due: this.due.toISOString(),
needsExtraReview: this.needsExtraReview
};
}
static fromJSON(json) {
return new _Card(
json.cardId,
json.n,
json.EF,
json.I,
new Date(json.due),
json.needsExtraReview
);
}
};
// src/ReviewLog.ts
var ReviewLog = class _ReviewLog {
constructor(cardId, rating, reviewDatetime, reviewDuration = null) {
this.cardId = cardId;
this.rating = rating;
this.reviewDatetime = reviewDatetime;
this.reviewDuration = reviewDuration;
}
equals(other) {
return this.cardId == other.cardId && this.rating == other.rating && this.reviewDatetime.getTime() == other.reviewDatetime.getTime() && this.reviewDuration == other.reviewDuration;
}
clone() {
return new _ReviewLog(
this.cardId,
this.rating,
new Date(this.reviewDatetime),
this.reviewDuration
);
}
toJSON() {
return {
cardId: this.cardId,
rating: this.rating,
reviewDatetime: this.reviewDatetime.toISOString(),
reviewDuration: this.reviewDuration
};
}
static fromJSON(json) {
return new _ReviewLog(
json.cardId,
json.rating,
new Date(json.reviewDatetime),
json.reviewDuration
);
}
};
// src/Scheduler.ts
var Scheduler = class {
static reviewCard(card, rating, reviewDatetime = null, reviewDuration = null) {
card = card.clone();
if (reviewDatetime == null) {
reviewDatetime = /* @__PURE__ */ new Date();
}
let cardIsDue = reviewDatetime >= card.due;
if (!cardIsDue) {
throw new Error(`Card is not due for review until ${card.due}`);
}
if (card.needsExtraReview) {
if (rating >= 4) {
card.needsExtraReview = false;
card.due.setDate(card.due.getDate() + card.I);
}
} else {
if (rating >= 3) {
card.EF = card.EF + (0.1 - (5 - rating) * (0.08 + (5 - rating) * 0.02));
card.EF = Math.max(1.3, card.EF);
if (card.n == 0) {
card.I = 1;
} else if (card.n == 1) {
card.I = 6;
} else {
card.I = Math.ceil(card.I * card.EF);
}
card.n += 1;
if (rating >= 4) {
card.due.setDate(card.due.getDate() + card.I);
} else {
card.needsExtraReview = true;
card.due = reviewDatetime;
}
} else {
card.n = 0;
card.I = 0;
card.due = reviewDatetime;
}
}
const reviewLog = new ReviewLog(card.cardId, rating, reviewDatetime, reviewDuration);
return { card, reviewLog };
}
};
export {
Card,
ReviewLog,
Scheduler
};
//# sourceMappingURL=index.js.map