@shaxpir/duiduidui-models 1.7.5 → 1.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/models/Progress.d.ts +7 -8
- package/dist/models/Progress.js +33 -36
- package/dist/models/SkillLevel.d.ts +72 -0
- package/dist/models/SkillLevel.js +106 -0
- package/dist/models/Streaks.js +7 -20
- package/dist/models/index.d.ts +1 -0
- package/dist/models/index.js +1 -0
- package/package.json +8 -4
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
import { Doc } from '@shaxpir/sharedb/lib/client';
|
|
2
2
|
import { CompactDate } from "@shaxpir/shaxpir-common";
|
|
3
3
|
import { ShareSync } from '../repo';
|
|
4
|
-
import { Bounds } from './BayesianScore';
|
|
5
4
|
import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
|
|
6
5
|
export interface UncertainValue {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
rating: number;
|
|
7
|
+
rating_deviation: number;
|
|
8
|
+
volatility: number;
|
|
10
9
|
}
|
|
11
10
|
export interface StreakData {
|
|
12
11
|
daily: {
|
|
@@ -43,16 +42,16 @@ export declare class Progress extends Content {
|
|
|
43
42
|
get payload(): ProgressPayload;
|
|
44
43
|
getSkillLevel(): UncertainValue;
|
|
45
44
|
getSkillLevelValue(): number;
|
|
46
|
-
|
|
45
|
+
getSkillLevelRatingDeviation(): number;
|
|
46
|
+
getSkillLevelVolatility(): number;
|
|
47
47
|
getSkillLevelLowerBound(): number;
|
|
48
48
|
getSkillLevelUpperBound(): number;
|
|
49
49
|
needsCalibration(): boolean;
|
|
50
50
|
getCognitiveLoad(): number;
|
|
51
51
|
setSkillLevel(uncertainValue: UncertainValue): void;
|
|
52
52
|
setSkillLevelValue(value: number): void;
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
setSkillLevelUpperBound(upperBound: number): void;
|
|
53
|
+
setSkillLevelRatingDeviation(ratingDeviation: number): void;
|
|
54
|
+
setSkillLevelVolatility(volatility: number): void;
|
|
56
55
|
setCognitiveLoad(value: number): void;
|
|
57
56
|
getStreaks(): StreakData | undefined;
|
|
58
57
|
setStreaks(streaks: StreakData): void;
|
package/dist/models/Progress.js
CHANGED
|
@@ -24,12 +24,9 @@ class Progress extends Content_1.Content {
|
|
|
24
24
|
},
|
|
25
25
|
payload: {
|
|
26
26
|
skill_level: {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
lower: 0, // Can't be worse than absolute beginner
|
|
31
|
-
upper: 1000 // Could potentially be advanced
|
|
32
|
-
}
|
|
27
|
+
rating: 0, // Start at absolute beginner (knows ~0 characters)
|
|
28
|
+
rating_deviation: 50, // Initial uncertainty (±100 chars at 95% CI)
|
|
29
|
+
volatility: 0.06 // Moderate initial volatility
|
|
33
30
|
},
|
|
34
31
|
cognitive_load: 0,
|
|
35
32
|
total_review_count: 0 // Start with zero lifetime reviews
|
|
@@ -49,24 +46,33 @@ class Progress extends Content_1.Content {
|
|
|
49
46
|
}
|
|
50
47
|
getSkillLevelValue() {
|
|
51
48
|
this.checkDisposed("Progress.getSkillLevelValue");
|
|
52
|
-
return this.payload.skill_level.
|
|
49
|
+
return this.payload.skill_level.rating;
|
|
53
50
|
}
|
|
54
|
-
|
|
55
|
-
this.checkDisposed("Progress.
|
|
56
|
-
return this.payload.skill_level.
|
|
51
|
+
getSkillLevelRatingDeviation() {
|
|
52
|
+
this.checkDisposed("Progress.getSkillLevelRatingDeviation");
|
|
53
|
+
return this.payload.skill_level.rating_deviation;
|
|
54
|
+
}
|
|
55
|
+
getSkillLevelVolatility() {
|
|
56
|
+
this.checkDisposed("Progress.getSkillLevelVolatility");
|
|
57
|
+
return this.payload.skill_level.volatility;
|
|
57
58
|
}
|
|
58
59
|
getSkillLevelLowerBound() {
|
|
59
60
|
this.checkDisposed("Progress.getSkillLevelLowerBound");
|
|
60
|
-
|
|
61
|
+
const { SkillLevelModel } = require('./SkillLevel');
|
|
62
|
+
const bounds = SkillLevelModel.calculateBounds(this.payload.skill_level.rating, this.payload.skill_level.rating_deviation);
|
|
63
|
+
return bounds.lower;
|
|
61
64
|
}
|
|
62
65
|
getSkillLevelUpperBound() {
|
|
63
66
|
this.checkDisposed("Progress.getSkillLevelUpperBound");
|
|
64
|
-
|
|
67
|
+
const { SkillLevelModel } = require('./SkillLevel');
|
|
68
|
+
const bounds = SkillLevelModel.calculateBounds(this.payload.skill_level.rating, this.payload.skill_level.rating_deviation);
|
|
69
|
+
return bounds.upper;
|
|
65
70
|
}
|
|
66
71
|
needsCalibration() {
|
|
67
72
|
this.checkDisposed("Progress.needsCalibration");
|
|
68
|
-
// High
|
|
69
|
-
|
|
73
|
+
// High rating deviation means we need more data to calibrate user level
|
|
74
|
+
// rating_deviation > 30 means confidence bounds are still quite wide (±60 chars at 95% CI)
|
|
75
|
+
return this.payload.skill_level.rating_deviation > 30;
|
|
70
76
|
}
|
|
71
77
|
getCognitiveLoad() {
|
|
72
78
|
this.checkDisposed("Progress.getCognitiveLoad");
|
|
@@ -76,42 +82,33 @@ class Progress extends Content_1.Content {
|
|
|
76
82
|
this.checkDisposed("Progress.setSkillLevel");
|
|
77
83
|
if (!shaxpir_common_1.Struct.equals(this.payload.skill_level, uncertainValue)) {
|
|
78
84
|
const batch = new Operation_1.BatchOperation(this);
|
|
79
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
80
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
81
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
82
|
-
batch.setPathValue(['payload', 'skill_level', 'bounds', 'upper'], uncertainValue.bounds.upper);
|
|
85
|
+
batch.setPathValue(['payload', 'skill_level', 'rating'], uncertainValue.rating);
|
|
86
|
+
batch.setPathValue(['payload', 'skill_level', 'rating_deviation'], uncertainValue.rating_deviation);
|
|
87
|
+
batch.setPathValue(['payload', 'skill_level', 'volatility'], uncertainValue.volatility);
|
|
83
88
|
batch.commit();
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
setSkillLevelValue(value) {
|
|
87
92
|
this.checkDisposed("Progress.setSkillLevelValue");
|
|
88
|
-
if (this.payload.skill_level.
|
|
89
|
-
const batch = new Operation_1.BatchOperation(this);
|
|
90
|
-
batch.setPathValue(['payload', 'skill_level', 'value'], value);
|
|
91
|
-
batch.commit();
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
setSkillLevelUncertainty(uncertainty) {
|
|
95
|
-
this.checkDisposed("Progress.setSkillLevelUncertainty");
|
|
96
|
-
if (this.payload.skill_level.uncertainty !== uncertainty) {
|
|
93
|
+
if (this.payload.skill_level.rating !== value) {
|
|
97
94
|
const batch = new Operation_1.BatchOperation(this);
|
|
98
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
95
|
+
batch.setPathValue(['payload', 'skill_level', 'rating'], value);
|
|
99
96
|
batch.commit();
|
|
100
97
|
}
|
|
101
98
|
}
|
|
102
|
-
|
|
103
|
-
this.checkDisposed("Progress.
|
|
104
|
-
if (this.payload.skill_level.
|
|
99
|
+
setSkillLevelRatingDeviation(ratingDeviation) {
|
|
100
|
+
this.checkDisposed("Progress.setSkillLevelRatingDeviation");
|
|
101
|
+
if (this.payload.skill_level.rating_deviation !== ratingDeviation) {
|
|
105
102
|
const batch = new Operation_1.BatchOperation(this);
|
|
106
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
103
|
+
batch.setPathValue(['payload', 'skill_level', 'rating_deviation'], ratingDeviation);
|
|
107
104
|
batch.commit();
|
|
108
105
|
}
|
|
109
106
|
}
|
|
110
|
-
|
|
111
|
-
this.checkDisposed("Progress.
|
|
112
|
-
if (this.payload.skill_level.
|
|
107
|
+
setSkillLevelVolatility(volatility) {
|
|
108
|
+
this.checkDisposed("Progress.setSkillLevelVolatility");
|
|
109
|
+
if (this.payload.skill_level.volatility !== volatility) {
|
|
113
110
|
const batch = new Operation_1.BatchOperation(this);
|
|
114
|
-
batch.setPathValue(['payload', 'skill_level', '
|
|
111
|
+
batch.setPathValue(['payload', 'skill_level', 'volatility'], volatility);
|
|
115
112
|
batch.commit();
|
|
116
113
|
}
|
|
117
114
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { ReviewResult } from './Review';
|
|
2
|
+
import { Bounds } from './BayesianScore';
|
|
3
|
+
/**
|
|
4
|
+
* Represents a skill level rating with uncertainty bounds.
|
|
5
|
+
* Uses the Glicko-2 rating system for skill assessment.
|
|
6
|
+
*/
|
|
7
|
+
export interface SkillLevel {
|
|
8
|
+
rating: number;
|
|
9
|
+
rating_deviation: number;
|
|
10
|
+
volatility: number;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Model for updating and managing skill levels using the Glicko-2 rating system.
|
|
14
|
+
*
|
|
15
|
+
* Unlike traditional Glicko-2 which uses a 1500-centered scale for chess,
|
|
16
|
+
* this adapts the algorithm to DuiDuiDui's semantic scale where:
|
|
17
|
+
* - Rating 0 = absolute beginner (knows ~0 characters)
|
|
18
|
+
* - Rating 100 = knows ~100 characters
|
|
19
|
+
* - Rating 3000 = knows ~3000 characters
|
|
20
|
+
*
|
|
21
|
+
* The Glicko-2 algorithm is used without the typical scaling transformations,
|
|
22
|
+
* working directly on our 0-10000 absolute scale.
|
|
23
|
+
*/
|
|
24
|
+
export declare class SkillLevelModel {
|
|
25
|
+
/**
|
|
26
|
+
* Update skill level using the Glicko-2 algorithm after a review.
|
|
27
|
+
*
|
|
28
|
+
* @param rating Current skill level rating
|
|
29
|
+
* @param ratingDeviation Current rating deviation (uncertainty)
|
|
30
|
+
* @param volatility Current volatility (performance consistency)
|
|
31
|
+
* @param cardDifficulty Difficulty of the card reviewed (on same scale as rating)
|
|
32
|
+
* @param cardRatingDeviation Rating deviation for the card (typically fixed, e.g., 100)
|
|
33
|
+
* @param outcome Review result (FAIL/HARD/GOOD/EASY)
|
|
34
|
+
* @param tau System constant controlling volatility changes (default 0.5)
|
|
35
|
+
* @returns Updated skill level with new rating, rating_deviation, and volatility
|
|
36
|
+
*/
|
|
37
|
+
static updateWithGlicko2(rating: number, ratingDeviation: number, volatility: number, cardDifficulty: number, cardRatingDeviation: number, outcome: ReviewResult, tau?: number): SkillLevel;
|
|
38
|
+
/**
|
|
39
|
+
* Map a review outcome to a numeric score for Glicko-2.
|
|
40
|
+
*
|
|
41
|
+
* @param outcome Review result
|
|
42
|
+
* @returns Numeric score from 0.0 (complete failure) to 1.0 (perfect success)
|
|
43
|
+
*/
|
|
44
|
+
static outcomeToScore(outcome: ReviewResult): number;
|
|
45
|
+
/**
|
|
46
|
+
* Calculate confidence bounds from Glicko-2 parameters.
|
|
47
|
+
* Returns a proper statistical confidence interval.
|
|
48
|
+
*
|
|
49
|
+
* @param rating Current skill level rating
|
|
50
|
+
* @param ratingDeviation Rating deviation (standard deviation of rating)
|
|
51
|
+
* @param confidence Confidence level (0.95 for 95%, 0.99 for 99%)
|
|
52
|
+
* @returns Bounds object with lower and upper confidence limits
|
|
53
|
+
*/
|
|
54
|
+
static calculateBounds(rating: number, ratingDeviation: number, confidence?: number): Bounds;
|
|
55
|
+
/**
|
|
56
|
+
* Create a default skill level for a new user.
|
|
57
|
+
* Starts at rating 0 (knows no characters) with high uncertainty.
|
|
58
|
+
*
|
|
59
|
+
* @param initialRatingDeviation Initial rating deviation (default 50, meaning ±100 char uncertainty at 95% CI)
|
|
60
|
+
* @param initialVolatility Initial volatility (default 0.06, moderate)
|
|
61
|
+
* @returns New SkillLevel object
|
|
62
|
+
*/
|
|
63
|
+
static createDefault(initialRatingDeviation?: number, initialVolatility?: number): SkillLevel;
|
|
64
|
+
/**
|
|
65
|
+
* Check if the skill level has high confidence (low uncertainty).
|
|
66
|
+
*
|
|
67
|
+
* @param ratingDeviation Rating deviation
|
|
68
|
+
* @param threshold Maximum rating deviation to be considered "high confidence" (default 15)
|
|
69
|
+
* @returns True if uncertainty is low (rating deviation below threshold)
|
|
70
|
+
*/
|
|
71
|
+
static isHighConfidence(ratingDeviation: number, threshold?: number): boolean;
|
|
72
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.SkillLevelModel = void 0;
|
|
7
|
+
const glicko2_lite_1 = __importDefault(require("glicko2-lite"));
|
|
8
|
+
/**
|
|
9
|
+
* Model for updating and managing skill levels using the Glicko-2 rating system.
|
|
10
|
+
*
|
|
11
|
+
* Unlike traditional Glicko-2 which uses a 1500-centered scale for chess,
|
|
12
|
+
* this adapts the algorithm to DuiDuiDui's semantic scale where:
|
|
13
|
+
* - Rating 0 = absolute beginner (knows ~0 characters)
|
|
14
|
+
* - Rating 100 = knows ~100 characters
|
|
15
|
+
* - Rating 3000 = knows ~3000 characters
|
|
16
|
+
*
|
|
17
|
+
* The Glicko-2 algorithm is used without the typical scaling transformations,
|
|
18
|
+
* working directly on our 0-10000 absolute scale.
|
|
19
|
+
*/
|
|
20
|
+
class SkillLevelModel {
|
|
21
|
+
/**
|
|
22
|
+
* Update skill level using the Glicko-2 algorithm after a review.
|
|
23
|
+
*
|
|
24
|
+
* @param rating Current skill level rating
|
|
25
|
+
* @param ratingDeviation Current rating deviation (uncertainty)
|
|
26
|
+
* @param volatility Current volatility (performance consistency)
|
|
27
|
+
* @param cardDifficulty Difficulty of the card reviewed (on same scale as rating)
|
|
28
|
+
* @param cardRatingDeviation Rating deviation for the card (typically fixed, e.g., 100)
|
|
29
|
+
* @param outcome Review result (FAIL/HARD/GOOD/EASY)
|
|
30
|
+
* @param tau System constant controlling volatility changes (default 0.5)
|
|
31
|
+
* @returns Updated skill level with new rating, rating_deviation, and volatility
|
|
32
|
+
*/
|
|
33
|
+
static updateWithGlicko2(rating, ratingDeviation, volatility, cardDifficulty, cardRatingDeviation, outcome, tau = 0.5) {
|
|
34
|
+
// Map outcome to numeric score (0.0 to 1.0)
|
|
35
|
+
const score = SkillLevelModel.outcomeToScore(outcome);
|
|
36
|
+
// Call glicko2-lite with a single match
|
|
37
|
+
// Match format: [opponentRating, opponentRD, outcome]
|
|
38
|
+
const result = (0, glicko2_lite_1.default)(rating, ratingDeviation, volatility, [
|
|
39
|
+
[cardDifficulty, cardRatingDeviation, score]
|
|
40
|
+
], { tau });
|
|
41
|
+
return {
|
|
42
|
+
rating: result.rating,
|
|
43
|
+
rating_deviation: result.rd,
|
|
44
|
+
volatility: result.vol
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Map a review outcome to a numeric score for Glicko-2.
|
|
49
|
+
*
|
|
50
|
+
* @param outcome Review result
|
|
51
|
+
* @returns Numeric score from 0.0 (complete failure) to 1.0 (perfect success)
|
|
52
|
+
*/
|
|
53
|
+
static outcomeToScore(outcome) {
|
|
54
|
+
switch (outcome) {
|
|
55
|
+
case 'EASY': return 1.0;
|
|
56
|
+
case 'GOOD': return 0.67;
|
|
57
|
+
case 'HARD': return 0.33;
|
|
58
|
+
case 'FAIL': return 0.0;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Calculate confidence bounds from Glicko-2 parameters.
|
|
63
|
+
* Returns a proper statistical confidence interval.
|
|
64
|
+
*
|
|
65
|
+
* @param rating Current skill level rating
|
|
66
|
+
* @param ratingDeviation Rating deviation (standard deviation of rating)
|
|
67
|
+
* @param confidence Confidence level (0.95 for 95%, 0.99 for 99%)
|
|
68
|
+
* @returns Bounds object with lower and upper confidence limits
|
|
69
|
+
*/
|
|
70
|
+
static calculateBounds(rating, ratingDeviation, confidence = 0.95) {
|
|
71
|
+
// Z-score for desired confidence level
|
|
72
|
+
// 95% CI: ±1.96 standard deviations
|
|
73
|
+
// 99% CI: ±2.58 standard deviations
|
|
74
|
+
const z = confidence === 0.95 ? 1.96 : confidence === 0.99 ? 2.58 : 1.96;
|
|
75
|
+
return {
|
|
76
|
+
lower: Math.max(0, rating - z * ratingDeviation),
|
|
77
|
+
upper: rating + z * ratingDeviation
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Create a default skill level for a new user.
|
|
82
|
+
* Starts at rating 0 (knows no characters) with high uncertainty.
|
|
83
|
+
*
|
|
84
|
+
* @param initialRatingDeviation Initial rating deviation (default 50, meaning ±100 char uncertainty at 95% CI)
|
|
85
|
+
* @param initialVolatility Initial volatility (default 0.06, moderate)
|
|
86
|
+
* @returns New SkillLevel object
|
|
87
|
+
*/
|
|
88
|
+
static createDefault(initialRatingDeviation = 50, initialVolatility = 0.06) {
|
|
89
|
+
return {
|
|
90
|
+
rating: 0,
|
|
91
|
+
rating_deviation: initialRatingDeviation,
|
|
92
|
+
volatility: initialVolatility
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Check if the skill level has high confidence (low uncertainty).
|
|
97
|
+
*
|
|
98
|
+
* @param ratingDeviation Rating deviation
|
|
99
|
+
* @param threshold Maximum rating deviation to be considered "high confidence" (default 15)
|
|
100
|
+
* @returns True if uncertainty is low (rating deviation below threshold)
|
|
101
|
+
*/
|
|
102
|
+
static isHighConfidence(ratingDeviation, threshold = 15) {
|
|
103
|
+
return ratingDeviation < threshold;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
exports.SkillLevelModel = SkillLevelModel;
|
package/dist/models/Streaks.js
CHANGED
|
@@ -94,10 +94,10 @@ class Streaks {
|
|
|
94
94
|
}
|
|
95
95
|
}
|
|
96
96
|
// Calculate monthly streak
|
|
97
|
-
// Extract
|
|
97
|
+
// Extract YYYYMM from CompactDate
|
|
98
98
|
const monthlyActivity = new Set();
|
|
99
99
|
for (const date of activityDates) {
|
|
100
|
-
const month =
|
|
100
|
+
const month = shaxpir_common_1.Time.getYearMonth(date);
|
|
101
101
|
monthlyActivity.add(month);
|
|
102
102
|
}
|
|
103
103
|
const sortedMonths = Array.from(monthlyActivity).sort();
|
|
@@ -110,10 +110,7 @@ class Streaks {
|
|
|
110
110
|
}
|
|
111
111
|
else {
|
|
112
112
|
// Check if consecutive month
|
|
113
|
-
|
|
114
|
-
const [currentYear, currentMonthNum] = month.split('-').map(Number);
|
|
115
|
-
if ((currentYear === lastYear && currentMonthNum === lastMonthNum + 1) ||
|
|
116
|
-
(currentYear === lastYear + 1 && lastMonthNum === 12 && currentMonthNum === 1)) {
|
|
113
|
+
if (shaxpir_common_1.Time.areConsecutiveMonths(lastMonth, month)) {
|
|
117
114
|
monthlyStreak++;
|
|
118
115
|
}
|
|
119
116
|
else {
|
|
@@ -123,23 +120,13 @@ class Streaks {
|
|
|
123
120
|
lastMonth = month;
|
|
124
121
|
}
|
|
125
122
|
// Check if current month streak is active
|
|
126
|
-
const currentMonth =
|
|
123
|
+
const currentMonth = shaxpir_common_1.Time.getYearMonth(today);
|
|
127
124
|
const lastActiveMonth = sortedMonths[sortedMonths.length - 1];
|
|
128
125
|
const lastMonthDate = shaxpir_common_1.Time.plus(today, -30, 'days');
|
|
129
|
-
const previousMonth = shaxpir_common_1.Time.dateFrom(lastMonthDate)
|
|
126
|
+
const previousMonth = shaxpir_common_1.Time.getYearMonth(shaxpir_common_1.Time.dateFrom(lastMonthDate));
|
|
130
127
|
if (lastActiveMonth === currentMonth || lastActiveMonth === previousMonth) {
|
|
131
128
|
monthlyCurrent = monthlyStreak;
|
|
132
129
|
}
|
|
133
|
-
// Get week string for last activity (ISO week format)
|
|
134
|
-
const getWeekString = (date) => {
|
|
135
|
-
// Simple week calculation: YYYY-Www where ww is week of year
|
|
136
|
-
const [year, month, day] = date.split('-').map(Number);
|
|
137
|
-
const dateObj = new Date(year, month - 1, day);
|
|
138
|
-
const startOfYear = new Date(year, 0, 1);
|
|
139
|
-
const dayOfYear = Math.floor((dateObj.getTime() - startOfYear.getTime()) / (24 * 60 * 60 * 1000)) + 1;
|
|
140
|
-
const weekNumber = Math.ceil(dayOfYear / 7);
|
|
141
|
-
return `${year}-W${weekNumber.toString().padStart(2, '0')}`;
|
|
142
|
-
};
|
|
143
130
|
// We know lastDate has a value since activityDates.length > 0
|
|
144
131
|
const finalLastDate = lastDate || activityDates[activityDates.length - 1];
|
|
145
132
|
return {
|
|
@@ -155,8 +142,8 @@ class Streaks {
|
|
|
155
142
|
},
|
|
156
143
|
last_activity: {
|
|
157
144
|
date: finalLastDate,
|
|
158
|
-
week: getWeekString(finalLastDate),
|
|
159
|
-
month:
|
|
145
|
+
week: shaxpir_common_1.Time.getWeekString(finalLastDate),
|
|
146
|
+
month: shaxpir_common_1.Time.getYearMonth(finalLastDate)
|
|
160
147
|
},
|
|
161
148
|
total_days: activityDates.length
|
|
162
149
|
};
|
package/dist/models/index.d.ts
CHANGED
package/dist/models/index.js
CHANGED
|
@@ -37,6 +37,7 @@ __exportStar(require("./Profile"), exports);
|
|
|
37
37
|
__exportStar(require("./Progress"), exports);
|
|
38
38
|
__exportStar(require("./Review"), exports);
|
|
39
39
|
__exportStar(require("./Session"), exports);
|
|
40
|
+
__exportStar(require("./SkillLevel"), exports);
|
|
40
41
|
__exportStar(require("./Social"), exports);
|
|
41
42
|
__exportStar(require("./Streaks"), exports);
|
|
42
43
|
__exportStar(require("./Term"), exports);
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shaxpir/duiduidui-models",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/shaxpir/duiduidui-models"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"build": "tsc",
|
|
10
|
-
"test": "mocha tests",
|
|
11
|
-
"test:watch": "mocha -w tests"
|
|
10
|
+
"test": "npm run build && mocha -r ts-node/register tests/**/*.ts",
|
|
11
|
+
"test:watch": "npm run build && mocha -r ts-node/register -w tests/**/*.ts"
|
|
12
12
|
},
|
|
13
13
|
"main": "dist/index.js",
|
|
14
14
|
"types": "dist/index.d.ts",
|
|
@@ -18,16 +18,20 @@
|
|
|
18
18
|
"dependencies": {
|
|
19
19
|
"@shaxpir/duiduidui-models": "^1.4.14",
|
|
20
20
|
"@shaxpir/sharedb": "^6.0.6",
|
|
21
|
-
"@shaxpir/shaxpir-common": "1.4.
|
|
21
|
+
"@shaxpir/shaxpir-common": "^1.4.1",
|
|
22
|
+
"glicko2-lite": "^4.0.0",
|
|
22
23
|
"ot-json1": "1.0.1",
|
|
23
24
|
"ot-text-unicode": "4.0.0",
|
|
24
25
|
"reconnecting-websocket": "4.4.0"
|
|
25
26
|
},
|
|
26
27
|
"devDependencies": {
|
|
28
|
+
"@types/chai": "^5.2.3",
|
|
27
29
|
"@types/lodash": "^4.17.20",
|
|
30
|
+
"@types/mocha": "^10.0.10",
|
|
28
31
|
"@types/node": "^18.0.50",
|
|
29
32
|
"chai": "^4.3.7",
|
|
30
33
|
"mocha": "^10.2.0",
|
|
34
|
+
"ts-node": "^10.9.2",
|
|
31
35
|
"tslint": "^5.12.1",
|
|
32
36
|
"typescript": "latest"
|
|
33
37
|
}
|