@jwerre/vellum 1.1.1 → 1.2.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/README.md CHANGED
@@ -243,6 +243,7 @@ There is a working example of Vellum in the `routes` directory. To run it, clone
243
243
  - [add](#add)
244
244
  - [Parameters](#parameters-11)
245
245
  - [Examples](#examples-17)
246
+ - [sort](#sort)
246
247
  - [reset](#reset)
247
248
  - [Parameters](#parameters-12)
248
249
  - [Examples](#examples-18)
@@ -863,6 +864,11 @@ collection.add(existingUser);
863
864
 
864
865
  Returns **any** The model instance that was added to the collection
865
866
 
867
+ #### sort
868
+
869
+ Sorts the collection using the comparator if one is defined.
870
+ Called automatically when items are added to the collection.
871
+
866
872
  #### reset
867
873
 
868
874
  Resets the collection with new data, replacing all existing items.
@@ -33,6 +33,46 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
33
33
  };
34
34
  /** Returns the API endpoint URL for this collection */
35
35
  abstract endpoint(): string;
36
+ /**
37
+ * Optional comparator for sorting the collection.
38
+ *
39
+ * By default, there is no comparator for a collection. If you define a comparator,
40
+ * it will be used to sort the collection any time a model is added.
41
+ *
42
+ * A comparator can be defined in three ways:
43
+ *
44
+ * 1. **sortBy** - Pass a function that takes a single model argument and returns
45
+ * a numeric or string value by which the model should be ordered relative to others.
46
+ *
47
+ * 2. **sort** - Pass a comparator function that takes two model arguments and returns
48
+ * -1 if the first model should come before the second, 0 if they are of the same
49
+ * rank, and 1 if the first model should come after.
50
+ *
51
+ * 3. **attribute name** - Pass a string indicating the attribute to sort by.
52
+ *
53
+ * Note: The implementation depends on the arity of your comparator function to
54
+ * determine between sortBy (1 argument) and sort (2 arguments) styles, so be
55
+ * careful if your comparator function is bound.
56
+ *
57
+ * @returns A comparator function, string attribute name, or undefined for no sorting
58
+ *
59
+ * @example
60
+ * // Sort by attribute name
61
+ * comparator = () => 'createdAt';
62
+ *
63
+ * @example
64
+ * // Sort using sortBy (single argument)
65
+ * comparator = () => (model: UserModel) => model.get('age');
66
+ *
67
+ * @example
68
+ * // Sort using sort comparator (two arguments)
69
+ * comparator = () => (a: UserModel, b: UserModel) => {
70
+ * if (a.get('priority') < b.get('priority')) return -1;
71
+ * if (a.get('priority') > b.get('priority')) return 1;
72
+ * return 0;
73
+ * };
74
+ */
75
+ comparator?(): string | ((model: M) => string | number) | ((a: M, b: M) => number) | undefined;
36
76
  /**
37
77
  * Creates a new Collection instance.
38
78
  *
@@ -66,6 +106,11 @@ export declare abstract class Collection<M extends Model<T>, T extends object> {
66
106
  * collection.add(existingUser);
67
107
  */
68
108
  add(data: T | M): M;
109
+ /**
110
+ * Sorts the collection using the comparator if one is defined.
111
+ * Called automatically when items are added to the collection.
112
+ */
113
+ private sort;
69
114
  /**
70
115
  * Resets the collection with new data, replacing all existing items.
71
116
  *
@@ -65,8 +65,55 @@ export class Collection {
65
65
  add(data) {
66
66
  const instance = data instanceof Model ? data : new this.model(data);
67
67
  this.items.push(instance);
68
+ this.sort();
68
69
  return instance;
69
70
  }
71
+ /**
72
+ * Sorts the collection using the comparator if one is defined.
73
+ * Called automatically when items are added to the collection.
74
+ */
75
+ sort() {
76
+ if (!this.comparator) {
77
+ return;
78
+ }
79
+ const comparator = this.comparator();
80
+ if (!comparator) {
81
+ return;
82
+ }
83
+ // String attribute name
84
+ if (typeof comparator === 'string') {
85
+ const attr = comparator;
86
+ this.items.sort((a, b) => {
87
+ const aVal = a.get(attr);
88
+ const bVal = b.get(attr);
89
+ if (aVal < bVal)
90
+ return -1;
91
+ if (aVal > bVal)
92
+ return 1;
93
+ return 0;
94
+ });
95
+ return;
96
+ }
97
+ // Function comparator - check arity
98
+ if (comparator.length === 1) {
99
+ // sortBy function (single argument)
100
+ const sortByFn = comparator;
101
+ this.items.sort((a, b) => {
102
+ const aVal = sortByFn(a);
103
+ const bVal = sortByFn(b);
104
+ if (aVal < bVal)
105
+ return -1;
106
+ if (aVal > bVal)
107
+ return 1;
108
+ return 0;
109
+ });
110
+ }
111
+ else {
112
+ // sort function (two arguments)
113
+ const sortFn = comparator;
114
+ this.items.sort(sortFn);
115
+ }
116
+ }
70
117
  /**
71
118
  * Resets the collection with new data, replacing all existing items.
72
119
  *
@@ -81,6 +128,7 @@ export class Collection {
81
128
  */
82
129
  reset(data) {
83
130
  this.items = data.map((attrs) => new this.model(attrs));
131
+ this.sort();
84
132
  }
85
133
  /**
86
134
  * Finds the first item in the collection that matches the given query.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jwerre/vellum",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Structural state management library for Svelte 5",
5
5
  "repository": {
6
6
  "type": "git",