@shaxpir/duiduidui-models 1.9.17 → 1.9.19
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/Session.d.ts
CHANGED
|
@@ -5,13 +5,18 @@ import { Conditions } from './Condition';
|
|
|
5
5
|
import { Content, ContentBody, ContentId, ContentMeta, ContentRef } from "./Content";
|
|
6
6
|
import { Review } from './Review';
|
|
7
7
|
import { UncertainValue } from './Progress';
|
|
8
|
+
/**
|
|
9
|
+
* How aggressively the card selection algorithm stretches the user
|
|
10
|
+
* beyond their current skill level.
|
|
11
|
+
*/
|
|
12
|
+
export type ChallengeLevel = 'easy' | 'mild' | 'medium' | 'hard' | 'max';
|
|
8
13
|
export interface SessionConfig {
|
|
9
14
|
constraints?: {
|
|
10
15
|
card_limit?: number | null;
|
|
11
16
|
time_limit?: number;
|
|
12
17
|
};
|
|
13
18
|
selection?: {
|
|
14
|
-
|
|
19
|
+
challenge?: ChallengeLevel;
|
|
15
20
|
filters?: Conditions;
|
|
16
21
|
strategy?: {
|
|
17
22
|
name: string;
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { CompactDateTime } from "@shaxpir/shaxpir-common";
|
|
2
|
+
import { AnyCondition, Conditions } from '../models/Condition';
|
|
3
|
+
/**
|
|
4
|
+
* Interface for objects that can be matched against Conditions.
|
|
5
|
+
* This is the minimum set of fields needed for condition matching.
|
|
6
|
+
*
|
|
7
|
+
* Implementers include AnnotatedPhrase (in the app) and potentially
|
|
8
|
+
* other phrase-like objects that need condition checking.
|
|
9
|
+
*/
|
|
10
|
+
export interface ConditionMatchable {
|
|
11
|
+
tags?: string[];
|
|
12
|
+
starred_at?: CompactDateTime | null;
|
|
13
|
+
theta?: number | null;
|
|
14
|
+
difficulty: number;
|
|
15
|
+
content_id?: string;
|
|
16
|
+
last_review_utc?: CompactDateTime | null;
|
|
17
|
+
created_at?: CompactDateTime;
|
|
18
|
+
updated_at?: CompactDateTime;
|
|
19
|
+
review_count?: number;
|
|
20
|
+
implied_review_count?: number;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Utility for checking if objects match Conditions.
|
|
24
|
+
*
|
|
25
|
+
* This is used by:
|
|
26
|
+
* - UnifiedSearchQuery to filter search results
|
|
27
|
+
* - CollectionProficiencyService to determine which Collections contain a phrase
|
|
28
|
+
*/
|
|
29
|
+
export declare const ConditionMatcher: {
|
|
30
|
+
/**
|
|
31
|
+
* Check if a single condition matches a matchable object.
|
|
32
|
+
*/
|
|
33
|
+
conditionMatches(condition: AnyCondition, item: ConditionMatchable): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Check if an item matches all the provided conditions.
|
|
36
|
+
*
|
|
37
|
+
* Conditions use three logical groups:
|
|
38
|
+
* - all: Item must match ALL of these conditions
|
|
39
|
+
* - any: Item must match AT LEAST ONE of these conditions
|
|
40
|
+
* - none: Item must match NONE of these conditions
|
|
41
|
+
*/
|
|
42
|
+
matchesConditions(item: ConditionMatchable, conditions: Conditions | undefined): boolean;
|
|
43
|
+
/**
|
|
44
|
+
* Filter an array of items to only those matching the conditions.
|
|
45
|
+
*/
|
|
46
|
+
filterByConditions<T extends ConditionMatchable>(items: T[], conditions: Conditions | undefined): T[];
|
|
47
|
+
/**
|
|
48
|
+
* Check if an item matches any of the provided Conditions sets.
|
|
49
|
+
* Useful for checking membership in multiple Collections at once.
|
|
50
|
+
*/
|
|
51
|
+
matchesAnyConditions(item: ConditionMatchable, conditionsList: Conditions[]): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Find all Conditions sets that an item matches.
|
|
54
|
+
* Returns indices of matching conditions in the input array.
|
|
55
|
+
*/
|
|
56
|
+
findMatchingConditions(item: ConditionMatchable, conditionsList: Conditions[]): number[];
|
|
57
|
+
};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ConditionMatcher = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Utility for checking if objects match Conditions.
|
|
6
|
+
*
|
|
7
|
+
* This is used by:
|
|
8
|
+
* - UnifiedSearchQuery to filter search results
|
|
9
|
+
* - CollectionProficiencyService to determine which Collections contain a phrase
|
|
10
|
+
*/
|
|
11
|
+
exports.ConditionMatcher = {
|
|
12
|
+
/**
|
|
13
|
+
* Check if a single condition matches a matchable object.
|
|
14
|
+
*/
|
|
15
|
+
conditionMatches(condition, item) {
|
|
16
|
+
switch (condition.type) {
|
|
17
|
+
case 'tag': {
|
|
18
|
+
const tagCond = condition;
|
|
19
|
+
const allTags = item.tags || [];
|
|
20
|
+
return allTags.includes(tagCond.tag);
|
|
21
|
+
}
|
|
22
|
+
case 'starred': {
|
|
23
|
+
const starredCond = condition;
|
|
24
|
+
const isStarred = item.starred_at !== null && item.starred_at !== undefined;
|
|
25
|
+
return starredCond.value === isStarred;
|
|
26
|
+
}
|
|
27
|
+
case 'theta': {
|
|
28
|
+
const thetaCond = condition;
|
|
29
|
+
if (item.theta === null || item.theta === undefined)
|
|
30
|
+
return false;
|
|
31
|
+
if (thetaCond.min !== undefined && item.theta < thetaCond.min)
|
|
32
|
+
return false;
|
|
33
|
+
if (thetaCond.max !== undefined && item.theta > thetaCond.max)
|
|
34
|
+
return false;
|
|
35
|
+
return true;
|
|
36
|
+
}
|
|
37
|
+
case 'grade': {
|
|
38
|
+
const gradeCond = condition;
|
|
39
|
+
if (item.theta === null || item.theta === undefined)
|
|
40
|
+
return false;
|
|
41
|
+
// Map theta to grade: A (0.8-1), B (0.6-0.8), C (0.4-0.6), D (0.2-0.4), F (0-0.2)
|
|
42
|
+
let itemGrade;
|
|
43
|
+
if (item.theta >= 0.8)
|
|
44
|
+
itemGrade = 'A';
|
|
45
|
+
else if (item.theta >= 0.6)
|
|
46
|
+
itemGrade = 'B';
|
|
47
|
+
else if (item.theta >= 0.4)
|
|
48
|
+
itemGrade = 'C';
|
|
49
|
+
else if (item.theta >= 0.2)
|
|
50
|
+
itemGrade = 'D';
|
|
51
|
+
else
|
|
52
|
+
itemGrade = 'F';
|
|
53
|
+
return itemGrade === gradeCond.grade;
|
|
54
|
+
}
|
|
55
|
+
case 'difficulty': {
|
|
56
|
+
const diffCond = condition;
|
|
57
|
+
if (diffCond.min !== undefined && item.difficulty < diffCond.min)
|
|
58
|
+
return false;
|
|
59
|
+
if (diffCond.max !== undefined && item.difficulty > diffCond.max)
|
|
60
|
+
return false;
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
case 'has_term': {
|
|
64
|
+
const hasTermCond = condition;
|
|
65
|
+
const hasTerm = item.content_id !== undefined;
|
|
66
|
+
return hasTermCond.value === hasTerm;
|
|
67
|
+
}
|
|
68
|
+
case 'temporal': {
|
|
69
|
+
const tempCond = condition;
|
|
70
|
+
let fieldValue;
|
|
71
|
+
switch (tempCond.field) {
|
|
72
|
+
case 'last_review_utc':
|
|
73
|
+
fieldValue = item.last_review_utc;
|
|
74
|
+
break;
|
|
75
|
+
case 'starred_at':
|
|
76
|
+
fieldValue = item.starred_at;
|
|
77
|
+
break;
|
|
78
|
+
case 'created_at':
|
|
79
|
+
fieldValue = item.created_at;
|
|
80
|
+
break;
|
|
81
|
+
case 'updated_at':
|
|
82
|
+
fieldValue = item.updated_at;
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
if (fieldValue === null || fieldValue === undefined) {
|
|
86
|
+
// No value means condition can't be satisfied for most operators
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
// For temporal conditions, we'd need to compare against current time
|
|
90
|
+
// This is complex because we need access to ClockService
|
|
91
|
+
// For now, return true (don't filter out) - these conditions are
|
|
92
|
+
// typically used in SQL queries rather than in-memory filtering
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
case 'count': {
|
|
96
|
+
const countCond = condition;
|
|
97
|
+
let fieldValue;
|
|
98
|
+
switch (countCond.field) {
|
|
99
|
+
case 'review_count':
|
|
100
|
+
fieldValue = item.review_count ?? 0;
|
|
101
|
+
break;
|
|
102
|
+
case 'implied_review_count':
|
|
103
|
+
fieldValue = item.implied_review_count ?? 0;
|
|
104
|
+
break;
|
|
105
|
+
}
|
|
106
|
+
switch (countCond.operator) {
|
|
107
|
+
case '>': return fieldValue > countCond.value;
|
|
108
|
+
case '<': return fieldValue < countCond.value;
|
|
109
|
+
case '>=': return fieldValue >= countCond.value;
|
|
110
|
+
case '<=': return fieldValue <= countCond.value;
|
|
111
|
+
case '=': return fieldValue === countCond.value;
|
|
112
|
+
case '!=': return fieldValue !== countCond.value;
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
case 'component': {
|
|
117
|
+
// Component conditions require database lookups and are not
|
|
118
|
+
// suitable for in-memory filtering. Return true (don't filter out).
|
|
119
|
+
return true;
|
|
120
|
+
}
|
|
121
|
+
default:
|
|
122
|
+
// For unsupported conditions, default to true (don't filter out)
|
|
123
|
+
return true;
|
|
124
|
+
}
|
|
125
|
+
},
|
|
126
|
+
/**
|
|
127
|
+
* Check if an item matches all the provided conditions.
|
|
128
|
+
*
|
|
129
|
+
* Conditions use three logical groups:
|
|
130
|
+
* - all: Item must match ALL of these conditions
|
|
131
|
+
* - any: Item must match AT LEAST ONE of these conditions
|
|
132
|
+
* - none: Item must match NONE of these conditions
|
|
133
|
+
*/
|
|
134
|
+
matchesConditions(item, conditions) {
|
|
135
|
+
if (!conditions)
|
|
136
|
+
return true;
|
|
137
|
+
// Check 'all' conditions - item must match ALL of these
|
|
138
|
+
if (conditions.all && conditions.all.length > 0) {
|
|
139
|
+
for (const cond of conditions.all) {
|
|
140
|
+
if (!exports.ConditionMatcher.conditionMatches(cond, item)) {
|
|
141
|
+
return false;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Check 'any' conditions - item must match AT LEAST ONE of these
|
|
146
|
+
if (conditions.any && conditions.any.length > 0) {
|
|
147
|
+
let matchedAny = false;
|
|
148
|
+
for (const cond of conditions.any) {
|
|
149
|
+
if (exports.ConditionMatcher.conditionMatches(cond, item)) {
|
|
150
|
+
matchedAny = true;
|
|
151
|
+
break;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (!matchedAny)
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
// Check 'none' conditions - item must match NONE of these
|
|
158
|
+
if (conditions.none && conditions.none.length > 0) {
|
|
159
|
+
for (const cond of conditions.none) {
|
|
160
|
+
if (exports.ConditionMatcher.conditionMatches(cond, item)) {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
return true;
|
|
166
|
+
},
|
|
167
|
+
/**
|
|
168
|
+
* Filter an array of items to only those matching the conditions.
|
|
169
|
+
*/
|
|
170
|
+
filterByConditions(items, conditions) {
|
|
171
|
+
if (!conditions)
|
|
172
|
+
return items;
|
|
173
|
+
return items.filter(item => exports.ConditionMatcher.matchesConditions(item, conditions));
|
|
174
|
+
},
|
|
175
|
+
/**
|
|
176
|
+
* Check if an item matches any of the provided Conditions sets.
|
|
177
|
+
* Useful for checking membership in multiple Collections at once.
|
|
178
|
+
*/
|
|
179
|
+
matchesAnyConditions(item, conditionsList) {
|
|
180
|
+
for (const conditions of conditionsList) {
|
|
181
|
+
if (exports.ConditionMatcher.matchesConditions(item, conditions)) {
|
|
182
|
+
return true;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
},
|
|
187
|
+
/**
|
|
188
|
+
* Find all Conditions sets that an item matches.
|
|
189
|
+
* Returns indices of matching conditions in the input array.
|
|
190
|
+
*/
|
|
191
|
+
findMatchingConditions(item, conditionsList) {
|
|
192
|
+
const matches = [];
|
|
193
|
+
for (let i = 0; i < conditionsList.length; i++) {
|
|
194
|
+
if (exports.ConditionMatcher.matchesConditions(item, conditionsList[i])) {
|
|
195
|
+
matches.push(i);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
return matches;
|
|
199
|
+
}
|
|
200
|
+
};
|
package/dist/util/index.d.ts
CHANGED
package/dist/util/index.js
CHANGED
|
@@ -16,6 +16,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
16
16
|
};
|
|
17
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
18
18
|
__exportStar(require("./AvatarUri"), exports);
|
|
19
|
+
__exportStar(require("./ConditionMatcher"), exports);
|
|
19
20
|
__exportStar(require("./Database"), exports);
|
|
20
21
|
__exportStar(require("./Encryption"), exports);
|
|
21
22
|
__exportStar(require("./Logging"), exports);
|