@shaxpir/duiduidui-models 1.9.27 → 1.9.29

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.
@@ -1,8 +1,10 @@
1
1
  import { Doc } from '@shaxpir/sharedb/lib/client';
2
2
  import { CompactDateTime } from "@shaxpir/shaxpir-common";
3
3
  import { ShareSync } from '../repo';
4
+ import { ArrayView } from './ArrayView';
4
5
  import { Conditions } from './Condition';
5
6
  import { Content, ContentBody, ContentId, ContentMeta } from "./Content";
7
+ import { AnnotatedPhrase } from './Phrase';
6
8
  import { SkillLevel } from './SkillLevel';
7
9
  /**
8
10
  * Display metadata for a Collection, used in the UI.
@@ -13,6 +15,13 @@ export interface CollectionDisplay {
13
15
  icon?: string;
14
16
  sort_order: number;
15
17
  }
18
+ /**
19
+ * A phrase explicitly included in a Collection, independent of condition matching.
20
+ */
21
+ export interface CollectionPhrase {
22
+ text: string;
23
+ sense_rank: number;
24
+ }
16
25
  /**
17
26
  * The payload for a Collection document.
18
27
  *
@@ -22,6 +31,7 @@ export interface CollectionDisplay {
22
31
  export interface CollectionPayload {
23
32
  collection_key: string;
24
33
  conditions: Conditions;
34
+ phrases: CollectionPhrase[];
25
35
  display: CollectionDisplay;
26
36
  proficiency: SkillLevel;
27
37
  term_scores: {
@@ -42,6 +52,7 @@ export interface CollectionBody extends ContentBody {
42
52
  export interface CollectionCreateParams {
43
53
  collectionKey: string;
44
54
  conditions: Conditions;
55
+ phrases: CollectionPhrase[];
45
56
  display: CollectionDisplay;
46
57
  isBuiltin?: boolean;
47
58
  isVisible?: boolean;
@@ -64,6 +75,7 @@ export declare class Collection extends Content {
64
75
  text: string;
65
76
  senseRank: number;
66
77
  };
78
+ private _phrasesView;
67
79
  constructor(doc: Doc, shouldAcquire: boolean, shareSync: ShareSync);
68
80
  /**
69
81
  * Create a new Collection for a user.
@@ -72,6 +84,7 @@ export declare class Collection extends Content {
72
84
  get payload(): CollectionPayload;
73
85
  get collectionKey(): string;
74
86
  get conditions(): Conditions;
87
+ get phrases(): ArrayView<CollectionPhrase>;
75
88
  get display(): CollectionDisplay;
76
89
  get name(): string;
77
90
  get description(): string;
@@ -123,6 +136,13 @@ export declare class Collection extends Content {
123
136
  D: number;
124
137
  F: number;
125
138
  };
139
+ /**
140
+ * Check if a phrase belongs to this collection.
141
+ *
142
+ * First checks for an exact match in the explicit phrases list,
143
+ * then falls back to condition matching if no explicit match is found.
144
+ */
145
+ matches(phrase: AnnotatedPhrase): boolean;
126
146
  /**
127
147
  * Update the IRT proficiency rating.
128
148
  */
@@ -3,7 +3,9 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Collection = void 0;
4
4
  const shaxpir_common_1 = require("@shaxpir/shaxpir-common");
5
5
  const repo_1 = require("../repo");
6
+ const ConditionMatcher_1 = require("../util/ConditionMatcher");
6
7
  const SenseRankEncoder_1 = require("../util/SenseRankEncoder");
8
+ const ArrayView_1 = require("./ArrayView");
7
9
  const Content_1 = require("./Content");
8
10
  const ContentKind_1 = require("./ContentKind");
9
11
  const Operation_1 = require("./Operation");
@@ -31,6 +33,7 @@ class Collection extends Content_1.Content {
31
33
  }
32
34
  constructor(doc, shouldAcquire, shareSync) {
33
35
  super(doc, shouldAcquire, shareSync);
36
+ this._phrasesView = new ArrayView_1.ArrayView(this, ['payload', 'phrases']);
34
37
  }
35
38
  /**
36
39
  * Create a new Collection for a user.
@@ -50,6 +53,7 @@ class Collection extends Content_1.Content {
50
53
  payload: {
51
54
  collection_key: params.collectionKey,
52
55
  conditions: params.conditions,
56
+ phrases: params.phrases,
53
57
  display: params.display,
54
58
  // Initial IRT proficiency - high uncertainty, no data yet
55
59
  proficiency: SkillLevel_1.SkillLevelModel.createDefault(),
@@ -86,6 +90,13 @@ class Collection extends Content_1.Content {
86
90
  return this.payload.conditions;
87
91
  }
88
92
  // ============================================================
93
+ // Explicit phrases getters
94
+ // ============================================================
95
+ get phrases() {
96
+ this.checkDisposed("Collection.phrases");
97
+ return this._phrasesView;
98
+ }
99
+ // ============================================================
89
100
  // Display metadata getters
90
101
  // ============================================================
91
102
  get display() {
@@ -222,6 +233,27 @@ class Collection extends Content_1.Content {
222
233
  };
223
234
  }
224
235
  // ============================================================
236
+ // Matching
237
+ // ============================================================
238
+ /**
239
+ * Check if a phrase belongs to this collection.
240
+ *
241
+ * First checks for an exact match in the explicit phrases list,
242
+ * then falls back to condition matching if no explicit match is found.
243
+ */
244
+ matches(phrase) {
245
+ this.checkDisposed("Collection.matches");
246
+ // First, check for an exact match in the explicit phrases list
247
+ const phrases = this.payload.phrases;
248
+ for (const p of phrases) {
249
+ if (p.text === phrase.text && p.sense_rank === phrase.sense_rank) {
250
+ return true;
251
+ }
252
+ }
253
+ // If no explicit match, fall back to condition matching
254
+ return ConditionMatcher_1.ConditionMatcher.matchesConditions(phrase, this.payload.conditions);
255
+ }
256
+ // ============================================================
225
257
  // Mutators
226
258
  // ============================================================
227
259
  /**
@@ -160,6 +160,14 @@ exports.Condition = {
160
160
  .join(', ');
161
161
  errors.push(`Conditions [${conflictingTypes}] in 'any' section require a term record, but has_term is false`);
162
162
  }
163
+ // Check for contradictory difficulty conditions (min >= max)
164
+ const difficultyCondition = conditions.all?.find(c => c.type === 'difficulty');
165
+ if (difficultyCondition) {
166
+ const { min, max } = difficultyCondition;
167
+ if (min !== undefined && max !== undefined && min >= max) {
168
+ errors.push(`Min difficulty (${min}) must be less than max difficulty (${max})`);
169
+ }
170
+ }
163
171
  return errors;
164
172
  },
165
173
  // Backward compatibility aliases (deprecated - use requiresStarred/allowsStarred/excludesStarred instead)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shaxpir/duiduidui-models",
3
- "version": "1.9.27",
3
+ "version": "1.9.29",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/shaxpir/duiduidui-models"