@raubjo/architect 0.5.1
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 +860 -0
- package/package.json +121 -0
- package/src/cache/cache.ts +46 -0
- package/src/cache/contract.ts +9 -0
- package/src/cache/manager.ts +110 -0
- package/src/cache/provider.ts +11 -0
- package/src/config/contract.ts +63 -0
- package/src/config/discovery.ts +99 -0
- package/src/config/env.global.d.ts +6 -0
- package/src/config/env.ts +68 -0
- package/src/config/index.ts +5 -0
- package/src/config/provider.ts +17 -0
- package/src/config/repository.ts +164 -0
- package/src/container/adapters/builtin.ts +323 -0
- package/src/container/contract.ts +43 -0
- package/src/container/runtime.ts +29 -0
- package/src/events/bus.ts +174 -0
- package/src/events/concerns/dispatchable.ts +10 -0
- package/src/events/provider.ts +9 -0
- package/src/events/types.ts +9 -0
- package/src/foundation/application.ts +136 -0
- package/src/foundation/current-application.ts +20 -0
- package/src/index.ts +58 -0
- package/src/log/contract.ts +21 -0
- package/src/log/drivers/console.ts +54 -0
- package/src/log/drivers/null.ts +23 -0
- package/src/log/drivers/stack.ts +46 -0
- package/src/log/manager.ts +76 -0
- package/src/log/provider.ts +11 -0
- package/src/react.ts +2 -0
- package/src/renderers/adapters/react.tsx +25 -0
- package/src/renderers/adapters/solid.tsx +26 -0
- package/src/renderers/adapters/svelte.ts +73 -0
- package/src/renderers/adapters/vue.ts +22 -0
- package/src/renderers/contract.ts +12 -0
- package/src/runtimes/react.tsx +81 -0
- package/src/runtimes/solid.tsx +47 -0
- package/src/runtimes/svelte.ts +17 -0
- package/src/runtimes/vue.ts +34 -0
- package/src/solid.ts +2 -0
- package/src/store/adapters/contract.ts +11 -0
- package/src/store/adapters/indexed-db.ts +187 -0
- package/src/store/adapters/local-storage.ts +48 -0
- package/src/store/adapters/memory.ts +35 -0
- package/src/store/manager.ts +68 -0
- package/src/store/provider.ts +10 -0
- package/src/store/store.ts +1 -0
- package/src/support/arr.ts +372 -0
- package/src/support/collection.ts +889 -0
- package/src/support/facades/cache.ts +6 -0
- package/src/support/facades/config.ts +6 -0
- package/src/support/facades/event.ts +6 -0
- package/src/support/facades/facade.ts +146 -0
- package/src/support/facades/index.ts +5 -0
- package/src/support/facades/log.ts +6 -0
- package/src/support/facades/store.ts +6 -0
- package/src/support/fluent.ts +56 -0
- package/src/support/globals.ts +8 -0
- package/src/support/lazy-collection.ts +341 -0
- package/src/support/manager.ts +53 -0
- package/src/support/num.ts +50 -0
- package/src/support/pipeline.ts +29 -0
- package/src/support/service-provider.ts +19 -0
- package/src/support/str.ts +682 -0
- package/src/svelte.ts +2 -0
- package/src/types/peer-deps.d.ts +10 -0
- package/src/vue.ts +2 -0
- package/tsconfig.json +15 -0
|
@@ -0,0 +1,889 @@
|
|
|
1
|
+
export class Collection<T> {
|
|
2
|
+
protected items: T[]
|
|
3
|
+
|
|
4
|
+
constructor(items: T[] = []) {
|
|
5
|
+
this.items = [...items]
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// ── Static constructors ────────────────────────────────────────────────────
|
|
9
|
+
|
|
10
|
+
static make<T>(items?: T[] | null): Collection<T> {
|
|
11
|
+
return new Collection(items ?? [])
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
static fromJson(json: string): Collection<unknown> {
|
|
15
|
+
const parsed = JSON.parse(json)
|
|
16
|
+
return new Collection(Array.isArray(parsed) ? parsed : [parsed])
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
static range(start: number, end: number): Collection<number> {
|
|
20
|
+
const result: number[] = []
|
|
21
|
+
for (let i = start; i <= end; i++) result.push(i)
|
|
22
|
+
return new Collection(result)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static times<U>(count: number, callback: (n: number) => U): Collection<U> {
|
|
26
|
+
const result: U[] = []
|
|
27
|
+
for (let i = 1; i <= count; i++) result.push(callback(i))
|
|
28
|
+
return new Collection(result)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
static wrap<U>(value: U | U[] | Collection<U> | null | undefined): Collection<U> {
|
|
32
|
+
if (value == null) return new Collection<U>()
|
|
33
|
+
if (value instanceof Collection) return new Collection(value.all())
|
|
34
|
+
if (Array.isArray(value)) return new Collection(value)
|
|
35
|
+
return new Collection([value as U])
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static unwrap<U>(value: U | U[] | Collection<U>): U[] | U {
|
|
39
|
+
if (value instanceof Collection) return value.all()
|
|
40
|
+
if (Array.isArray(value)) return value
|
|
41
|
+
return value
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// ── Core ──────────────────────────────────────────────────────────────────
|
|
45
|
+
|
|
46
|
+
all(): T[] {
|
|
47
|
+
return [...this.items]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
toArray(): T[] {
|
|
51
|
+
return this.all()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
count(): number {
|
|
55
|
+
return this.items.length
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
isEmpty(): boolean {
|
|
59
|
+
return this.items.length === 0
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
isNotEmpty(): boolean {
|
|
63
|
+
return this.items.length > 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
first(callback?: (item: T, index: number) => boolean): T | null {
|
|
67
|
+
if (!callback) return this.items[0] ?? null
|
|
68
|
+
return this.items.find(callback) ?? null
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
last(callback?: (item: T, index: number) => boolean): T | null {
|
|
72
|
+
if (!callback) return this.items[this.items.length - 1] ?? null
|
|
73
|
+
return [...this.items].reverse().find((item, i) => callback(item, this.items.length - 1 - i)) ?? null
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ── Aliases ───────────────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
average(key?: keyof T | ((item: T) => number)): number {
|
|
79
|
+
return this.avg(key)
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
avg(key?: keyof T | ((item: T) => number)): number {
|
|
83
|
+
if (this.items.length === 0) return 0
|
|
84
|
+
return this.sum(key) / this.items.length
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
some(callback: (item: T, index: number) => boolean): boolean {
|
|
88
|
+
return this.items.some(callback)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
// ── Navigation ────────────────────────────────────────────────────────────
|
|
92
|
+
|
|
93
|
+
after(item: T | ((item: T, index: number) => boolean), strict = false): T | null {
|
|
94
|
+
const idx = this._findIndex(item, strict)
|
|
95
|
+
if (idx === -1 || idx >= this.items.length - 1) return null
|
|
96
|
+
return this.items[idx + 1] ?? null
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
before(item: T | ((item: T, index: number) => boolean), strict = false): T | null {
|
|
100
|
+
const idx = this._findIndex(item, strict)
|
|
101
|
+
if (idx <= 0) return null
|
|
102
|
+
return this.items[idx - 1] ?? null
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected _findIndex(item: T | ((item: T, index: number) => boolean), strict = false): number {
|
|
106
|
+
if (typeof item === "function") {
|
|
107
|
+
return this.items.findIndex(item as (item: T, index: number) => boolean)
|
|
108
|
+
}
|
|
109
|
+
if (strict) {
|
|
110
|
+
return this.items.indexOf(item)
|
|
111
|
+
}
|
|
112
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
113
|
+
return this.items.findIndex((i) => i == item)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ── Counting / stats ──────────────────────────────────────────────────────
|
|
117
|
+
|
|
118
|
+
countBy(callback?: (item: T) => string | number): Record<string, number> {
|
|
119
|
+
const result: Record<string, number> = {}
|
|
120
|
+
for (const item of this.items) {
|
|
121
|
+
const key = String(callback ? callback(item) : item)
|
|
122
|
+
result[key] = (result[key] ?? 0) + 1
|
|
123
|
+
}
|
|
124
|
+
return result
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
sum(key?: keyof T | ((item: T) => number)): number {
|
|
128
|
+
return this.items.reduce((s, i) => s + (this.extractValue(i, key) as number), 0)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
min(key?: keyof T | ((item: T) => number)): T | null {
|
|
132
|
+
if (this.items.length === 0) return null
|
|
133
|
+
return this.items.reduce((min, i) =>
|
|
134
|
+
(this.extractValue(i, key) as number) < (this.extractValue(min, key) as number) ? i : min,
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
max(key?: keyof T | ((item: T) => number)): T | null {
|
|
139
|
+
if (this.items.length === 0) return null
|
|
140
|
+
return this.items.reduce((max, i) =>
|
|
141
|
+
(this.extractValue(i, key) as number) > (this.extractValue(max, key) as number) ? i : max,
|
|
142
|
+
)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
median(key?: keyof T | ((item: T) => number)): number | null {
|
|
146
|
+
if (this.items.length === 0) return null
|
|
147
|
+
const vals = this.items.map((i) => this.extractValue(i, key) as number).sort((a, b) => a - b)
|
|
148
|
+
const mid = Math.floor(vals.length / 2)
|
|
149
|
+
return vals.length % 2 === 0 ? (vals[mid - 1] + vals[mid]) / 2 : vals[mid]
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
mode(key?: keyof T | ((item: T) => number)): T[] {
|
|
153
|
+
if (this.items.length === 0) return []
|
|
154
|
+
const freq = new Map<unknown, number>()
|
|
155
|
+
for (const item of this.items) {
|
|
156
|
+
const v = this.extractValue(item, key)
|
|
157
|
+
freq.set(v, (freq.get(v) ?? 0) + 1)
|
|
158
|
+
}
|
|
159
|
+
const maxFreq = Math.max(...freq.values())
|
|
160
|
+
const modalVals = new Set([...freq.entries()].filter(([, c]) => c === maxFreq).map(([v]) => v))
|
|
161
|
+
return this.items.filter((item) => modalVals.has(this.extractValue(item, key)))
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
percentage(callback: (item: T) => boolean, precision = 2): number {
|
|
165
|
+
if (this.items.length === 0) return 0
|
|
166
|
+
const pct = (this.items.filter(callback).length / this.items.length) * 100
|
|
167
|
+
return Math.round(pct * 10 ** precision) / 10 ** precision
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// ── Searching ─────────────────────────────────────────────────────────────
|
|
171
|
+
|
|
172
|
+
firstOrFail(callback?: (item: T, index: number) => boolean): T {
|
|
173
|
+
const found = this.first(callback)
|
|
174
|
+
if (found === null) throw new Error("Item not found.")
|
|
175
|
+
return found
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
firstWhere(key: keyof T, operatorOrValue: unknown, value?: unknown): T | null {
|
|
179
|
+
const [op, val] = value === undefined ? ["==", operatorOrValue] : [operatorOrValue as string, value]
|
|
180
|
+
return (
|
|
181
|
+
this.items.find((item) => {
|
|
182
|
+
return this._compareOp(item[key], op as string, val)
|
|
183
|
+
}) ?? null
|
|
184
|
+
)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
search(item: T | ((item: T, index: number) => boolean), strict = false): number | false {
|
|
188
|
+
if (typeof item === "function") {
|
|
189
|
+
const idx = this.items.findIndex(item as (item: T, index: number) => boolean)
|
|
190
|
+
return idx === -1 ? false : idx
|
|
191
|
+
}
|
|
192
|
+
if (strict) {
|
|
193
|
+
const idx = this.items.indexOf(item)
|
|
194
|
+
return idx === -1 ? false : idx
|
|
195
|
+
}
|
|
196
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
197
|
+
const idx = this.items.findIndex((i) => i == item)
|
|
198
|
+
return idx === -1 ? false : idx
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
sole(callback?: (item: T, index: number) => boolean): T {
|
|
202
|
+
const matches = callback ? this.items.filter(callback) : this.items
|
|
203
|
+
if (matches.length === 0) throw new Error("No items match the given criteria.")
|
|
204
|
+
if (matches.length > 1) throw new Error("Multiple items match the given criteria.")
|
|
205
|
+
return matches[0]
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
value(key: keyof T): T[keyof T] | null {
|
|
209
|
+
const first = this.first()
|
|
210
|
+
if (first === null || first === undefined) return null
|
|
211
|
+
return first[key]
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// ── Transforming ──────────────────────────────────────────────────────────
|
|
215
|
+
|
|
216
|
+
map<U>(callback: (item: T, index: number) => U): Collection<U> {
|
|
217
|
+
return new Collection(this.items.map(callback))
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
filter(callback?: (item: T, index: number) => boolean): Collection<T> {
|
|
221
|
+
return new Collection(
|
|
222
|
+
callback ? this.items.filter(callback) : this.items.filter(Boolean as unknown as (item: T) => boolean),
|
|
223
|
+
)
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
reject(callback: (item: T, index: number) => boolean): Collection<T> {
|
|
227
|
+
return new Collection(this.items.filter((item, i) => !callback(item, i)))
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
reduce<U>(callback: (carry: U, item: T, index: number) => U, initial: U): U {
|
|
231
|
+
return this.items.reduce(callback, initial)
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
each(callback: (item: T, index: number) => void): this {
|
|
235
|
+
this.items.forEach(callback)
|
|
236
|
+
return this
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
collect(): Collection<T> {
|
|
240
|
+
return new Collection(this.items)
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
flatMap<U>(callback: (item: T, index: number) => U[]): Collection<U> {
|
|
244
|
+
return new Collection(this.items.flatMap(callback))
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
mapSpread<U>(callback: (...args: unknown[]) => U): Collection<U> {
|
|
248
|
+
return new Collection(this.items.map((item) => callback(...(item as unknown as unknown[]))))
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
mapToGroups<K extends string, V>(callback: (item: T, index: number) => [K, V]): Record<string, Collection<V>> {
|
|
252
|
+
const result: Record<string, V[]> = {}
|
|
253
|
+
this.items.forEach((item, i) => {
|
|
254
|
+
const [k, v] = callback(item, i)
|
|
255
|
+
if (!result[k]) result[k] = []
|
|
256
|
+
result[k].push(v)
|
|
257
|
+
})
|
|
258
|
+
return Object.fromEntries(Object.entries(result).map(([k, v]) => [k, new Collection(v as V[])]))
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
mapWithKeys<K extends string, V>(callback: (item: T, index: number) => [K, V]): Record<K, V> {
|
|
262
|
+
const result = {} as Record<K, V>
|
|
263
|
+
this.items.forEach((item, i) => {
|
|
264
|
+
const [k, v] = callback(item, i)
|
|
265
|
+
result[k] = v
|
|
266
|
+
})
|
|
267
|
+
return result
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
transform(callback: (item: T, index: number) => T): this {
|
|
271
|
+
this.items = this.items.map(callback)
|
|
272
|
+
return this
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
undot(): Collection<Record<string, unknown>> {
|
|
276
|
+
return new Collection(
|
|
277
|
+
(this.items as unknown as Record<string, unknown>[]).map((item) => {
|
|
278
|
+
const result: Record<string, unknown> = {}
|
|
279
|
+
for (const [dotKey, val] of Object.entries(item)) {
|
|
280
|
+
const parts = dotKey.split(".")
|
|
281
|
+
let cur = result
|
|
282
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
283
|
+
if (!cur[parts[i]] || typeof cur[parts[i]] !== "object") {
|
|
284
|
+
cur[parts[i]] = {}
|
|
285
|
+
}
|
|
286
|
+
cur = cur[parts[i]] as Record<string, unknown>
|
|
287
|
+
}
|
|
288
|
+
cur[parts[parts.length - 1]] = val
|
|
289
|
+
}
|
|
290
|
+
return result
|
|
291
|
+
}),
|
|
292
|
+
)
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
dot(): Collection<Record<string, unknown>> {
|
|
296
|
+
const flattenObj = (obj: Record<string, unknown>, prefix = ""): Record<string, unknown> => {
|
|
297
|
+
const result: Record<string, unknown> = {}
|
|
298
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
299
|
+
const newKey = prefix ? `${prefix}.${k}` : k
|
|
300
|
+
if (v && typeof v === "object" && !Array.isArray(v)) {
|
|
301
|
+
Object.assign(result, flattenObj(v as Record<string, unknown>, newKey))
|
|
302
|
+
} else {
|
|
303
|
+
result[newKey] = v
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
return result
|
|
307
|
+
}
|
|
308
|
+
return new Collection((this.items as unknown as Record<string, unknown>[]).map((item) => flattenObj(item)))
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
// ── Set operations ────────────────────────────────────────────────────────
|
|
312
|
+
|
|
313
|
+
diff(items: T[] | Collection<T>): Collection<T> {
|
|
314
|
+
const other = items instanceof Collection ? items.all() : items
|
|
315
|
+
return new Collection(this.items.filter((i) => !other.includes(i)))
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
intersect(items: T[] | Collection<T>): Collection<T> {
|
|
319
|
+
const other = items instanceof Collection ? items.all() : items
|
|
320
|
+
return new Collection(this.items.filter((i) => other.includes(i)))
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
union(items: T[] | Collection<T>): Collection<T> {
|
|
324
|
+
const other = items instanceof Collection ? items.all() : items
|
|
325
|
+
const result = [...this.items]
|
|
326
|
+
for (let i = 0; i < other.length; i++) {
|
|
327
|
+
if (i >= result.length) {
|
|
328
|
+
result.push(other[i])
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
return new Collection(result)
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// ── Key/object operations ─────────────────────────────────────────────────
|
|
335
|
+
|
|
336
|
+
pluck<K extends keyof T>(key: K): Collection<T[K]> {
|
|
337
|
+
return new Collection(this.items.map((item) => item[key]))
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
contains(itemOrCallback: T | ((item: T) => boolean)): boolean {
|
|
341
|
+
if (typeof itemOrCallback === "function") {
|
|
342
|
+
return this.items.some(itemOrCallback as (item: T) => boolean)
|
|
343
|
+
}
|
|
344
|
+
return this.items.includes(itemOrCallback)
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
unique(key?: keyof T | ((item: T) => unknown)): Collection<T> {
|
|
348
|
+
const seen = new Set<unknown>()
|
|
349
|
+
return new Collection(
|
|
350
|
+
this.items.filter((item) => {
|
|
351
|
+
const val = this.extractValue(item, key)
|
|
352
|
+
if (seen.has(val)) return false
|
|
353
|
+
seen.add(val)
|
|
354
|
+
return true
|
|
355
|
+
}),
|
|
356
|
+
)
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
except(keys: string[]): Collection<Partial<T>> {
|
|
360
|
+
return new Collection(
|
|
361
|
+
this.items.map((item) => {
|
|
362
|
+
const result = { ...(item as object) } as Partial<T>
|
|
363
|
+
for (const k of keys) {
|
|
364
|
+
delete (result as Record<string, unknown>)[k]
|
|
365
|
+
}
|
|
366
|
+
return result
|
|
367
|
+
}),
|
|
368
|
+
)
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
only(keys: Array<keyof T>): Collection<Partial<T>> {
|
|
372
|
+
return new Collection(
|
|
373
|
+
this.items.map((item) => {
|
|
374
|
+
const result: Partial<T> = {}
|
|
375
|
+
for (const k of keys) {
|
|
376
|
+
result[k] = item[k]
|
|
377
|
+
}
|
|
378
|
+
return result
|
|
379
|
+
}),
|
|
380
|
+
)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
select(keys: Array<keyof T>): Collection<Partial<T>> {
|
|
384
|
+
return this.only(keys)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
forget(index: number): this {
|
|
388
|
+
this.items.splice(index, 1)
|
|
389
|
+
return this
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
pull(index: number): T | null {
|
|
393
|
+
if (index < 0 || index >= this.items.length) return null
|
|
394
|
+
return this.items.splice(index, 1)[0] ?? null
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
put(index: number, value: T): this {
|
|
398
|
+
this.items[index] = value
|
|
399
|
+
return this
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
keyBy(key: keyof T | ((item: T, index: number) => string)): Record<string, T> {
|
|
403
|
+
const result: Record<string, T> = {}
|
|
404
|
+
this.items.forEach((item, i) => {
|
|
405
|
+
const k = typeof key === "function" ? key(item, i) : String(item[key])
|
|
406
|
+
result[k] = item
|
|
407
|
+
})
|
|
408
|
+
return result
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
// ── Stack/queue ───────────────────────────────────────────────────────────
|
|
412
|
+
|
|
413
|
+
pop(count?: number): T | Collection<T> | null {
|
|
414
|
+
if (count !== undefined) {
|
|
415
|
+
const removed = this.items.splice(this.items.length - count, count)
|
|
416
|
+
return new Collection(removed)
|
|
417
|
+
}
|
|
418
|
+
return this.items.pop() ?? null
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
shift(count?: number): T | Collection<T> | null {
|
|
422
|
+
if (count !== undefined) {
|
|
423
|
+
const removed = this.items.splice(0, count)
|
|
424
|
+
return new Collection(removed)
|
|
425
|
+
}
|
|
426
|
+
return this.items.shift() ?? null
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
splice(offset: number, length?: number, replacement: T[] = []): Collection<T> {
|
|
430
|
+
const removed =
|
|
431
|
+
length !== undefined
|
|
432
|
+
? this.items.splice(offset, length, ...replacement)
|
|
433
|
+
: this.items.splice(offset, this.items.length, ...replacement)
|
|
434
|
+
return new Collection(removed)
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
push(...items: T[]): this {
|
|
438
|
+
this.items.push(...items)
|
|
439
|
+
return this
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
prepend(...items: T[]): this {
|
|
443
|
+
this.items.unshift(...items)
|
|
444
|
+
return this
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
// ── Pagination / windowing ────────────────────────────────────────────────
|
|
448
|
+
|
|
449
|
+
forPage(page: number, perPage: number): Collection<T> {
|
|
450
|
+
return new Collection(this.items.slice((page - 1) * perPage, page * perPage))
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
nth(n: number, offset = 0): Collection<T> {
|
|
454
|
+
const result: T[] = []
|
|
455
|
+
for (let i = offset; i < this.items.length; i += n) {
|
|
456
|
+
result.push(this.items[i])
|
|
457
|
+
}
|
|
458
|
+
return new Collection(result)
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
pad(size: number, value: T): Collection<T> {
|
|
462
|
+
const abs = Math.abs(size)
|
|
463
|
+
if (abs <= this.items.length) return new Collection(this.items)
|
|
464
|
+
const padding = Array(abs - this.items.length).fill(value) as T[]
|
|
465
|
+
return size < 0 ? new Collection([...padding, ...this.items]) : new Collection([...this.items, ...padding])
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
slice(offset: number, length?: number): Collection<T> {
|
|
469
|
+
const start = offset
|
|
470
|
+
const end = length !== undefined ? offset + length : undefined
|
|
471
|
+
return new Collection(this.items.slice(start, end))
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
sliding(size: number, step = 1): Collection<Collection<T>> {
|
|
475
|
+
const result: Collection<T>[] = []
|
|
476
|
+
for (let i = 0; i + size <= this.items.length; i += step) {
|
|
477
|
+
result.push(new Collection(this.items.slice(i, i + size)))
|
|
478
|
+
}
|
|
479
|
+
return new Collection(result)
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
split(groups: number): Collection<Collection<T>> {
|
|
483
|
+
if (groups <= 0) return new Collection()
|
|
484
|
+
const size = Math.ceil(this.items.length / groups)
|
|
485
|
+
const result: Collection<T>[] = []
|
|
486
|
+
for (let i = 0; i < this.items.length; i += size) {
|
|
487
|
+
result.push(new Collection(this.items.slice(i, i + size)))
|
|
488
|
+
}
|
|
489
|
+
while (result.length < groups) result.push(new Collection())
|
|
490
|
+
return new Collection(result)
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
splitIn(groups: number): Collection<Collection<T>> {
|
|
494
|
+
if (groups <= 0) return new Collection()
|
|
495
|
+
const size = Math.ceil(this.items.length / groups)
|
|
496
|
+
const result: Collection<T>[] = []
|
|
497
|
+
for (let i = 0; i < groups; i++) {
|
|
498
|
+
result.push(new Collection(this.items.slice(i * size, (i + 1) * size)))
|
|
499
|
+
}
|
|
500
|
+
return new Collection(result)
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// ── Conditional / tap ─────────────────────────────────────────────────────
|
|
504
|
+
|
|
505
|
+
pipe<U>(callback: (collection: Collection<T>) => U): U {
|
|
506
|
+
return callback(this)
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
pipeInto<U>(ctor: new (c: Collection<T>) => U): U {
|
|
510
|
+
return new ctor(this)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
pipeThrough(pipes: Array<(c: Collection<T>) => Collection<T>>): Collection<T> {
|
|
514
|
+
return pipes.reduce((c, fn) => fn(c), this as Collection<T>)
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
tap(callback: (collection: this) => void): this {
|
|
518
|
+
callback(this)
|
|
519
|
+
return this
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
when(condition: boolean, callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
523
|
+
if (condition) callback(this)
|
|
524
|
+
else if (fallback) fallback(this)
|
|
525
|
+
return this
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
unless(condition: boolean, callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
529
|
+
return this.when(!condition, callback, fallback)
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
whenEmpty(callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
533
|
+
return this.when(this.isEmpty(), callback, fallback)
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
whenNotEmpty(callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
537
|
+
return this.when(this.isNotEmpty(), callback, fallback)
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
unlessEmpty(callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
541
|
+
return this.whenNotEmpty(callback, fallback)
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
unlessNotEmpty(callback: (c: this) => unknown, fallback?: (c: this) => unknown): this {
|
|
545
|
+
return this.whenEmpty(callback, fallback)
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
// ── Chunking / grouping ───────────────────────────────────────────────────
|
|
549
|
+
|
|
550
|
+
sortBy(key: keyof T | ((item: T) => unknown), direction: "asc" | "desc" = "asc"): Collection<T> {
|
|
551
|
+
return new Collection(
|
|
552
|
+
[...this.items].sort((a, b) => {
|
|
553
|
+
const av = this.extractValue(a, key) as string | number
|
|
554
|
+
const bv = this.extractValue(b, key) as string | number
|
|
555
|
+
if (av < bv) return direction === "asc" ? -1 : 1
|
|
556
|
+
if (av > bv) return direction === "asc" ? 1 : -1
|
|
557
|
+
return 0
|
|
558
|
+
}),
|
|
559
|
+
)
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
groupBy<K extends string | number>(key: keyof T | ((item: T) => K)): Record<string, Collection<T>> {
|
|
563
|
+
const groups: Record<string, T[]> = {}
|
|
564
|
+
for (const item of this.items) {
|
|
565
|
+
const k = String(this.extractValue(item, key))
|
|
566
|
+
if (!groups[k]) groups[k] = []
|
|
567
|
+
groups[k].push(item)
|
|
568
|
+
}
|
|
569
|
+
return Object.fromEntries(Object.entries(groups).map(([k, v]) => [k, new Collection(v)]))
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
chunk(size: number): Collection<Collection<T>> {
|
|
573
|
+
const chunks: Collection<T>[] = []
|
|
574
|
+
for (let i = 0; i < this.items.length; i += size) {
|
|
575
|
+
chunks.push(new Collection(this.items.slice(i, i + size)))
|
|
576
|
+
}
|
|
577
|
+
return new Collection(chunks)
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
chunkWhile(callback: (current: T, index: number, chunk: Collection<T>) => boolean): Collection<Collection<T>> {
|
|
581
|
+
if (this.items.length === 0) return new Collection()
|
|
582
|
+
const result: Collection<T>[] = []
|
|
583
|
+
let currentChunk: T[] = [this.items[0]]
|
|
584
|
+
for (let i = 1; i < this.items.length; i++) {
|
|
585
|
+
if (callback(this.items[i], i, new Collection(currentChunk))) {
|
|
586
|
+
currentChunk.push(this.items[i])
|
|
587
|
+
} else {
|
|
588
|
+
result.push(new Collection(currentChunk))
|
|
589
|
+
currentChunk = [this.items[i]]
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
result.push(new Collection(currentChunk))
|
|
593
|
+
return new Collection(result)
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
crossJoin<U>(...arrays: U[][]): Collection<unknown[]> {
|
|
597
|
+
let result: unknown[][] = [[]]
|
|
598
|
+
const allArrays: unknown[][] = [this.items as unknown[], ...arrays.map((a) => a as unknown[])]
|
|
599
|
+
for (const arr of allArrays) {
|
|
600
|
+
const newResult: unknown[][] = []
|
|
601
|
+
for (const existing of result) {
|
|
602
|
+
for (const item of arr) {
|
|
603
|
+
newResult.push([...existing, item])
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
result = newResult
|
|
607
|
+
}
|
|
608
|
+
return new Collection(result)
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
eachSpread(callback: (...args: unknown[]) => unknown): this {
|
|
612
|
+
for (const item of this.items) {
|
|
613
|
+
callback(...(item as unknown as unknown[]))
|
|
614
|
+
}
|
|
615
|
+
return this
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
duplicates(key?: keyof T | ((item: T) => unknown)): Collection<T> {
|
|
619
|
+
const seen = new Set<unknown>()
|
|
620
|
+
const result: T[] = []
|
|
621
|
+
for (const item of this.items) {
|
|
622
|
+
const v = this.extractValue(item, key)
|
|
623
|
+
if (seen.has(v)) {
|
|
624
|
+
result.push(item)
|
|
625
|
+
} else {
|
|
626
|
+
seen.add(v)
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
return new Collection(result)
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
multiply(times: number): Collection<T> {
|
|
633
|
+
let result: T[] = []
|
|
634
|
+
for (let i = 0; i < times; i++) result = [...result, ...this.items]
|
|
635
|
+
return new Collection(result)
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
zip<U>(...arrays: U[][]): Collection<unknown[]> {
|
|
639
|
+
const maxLen = Math.max(this.items.length, ...arrays.map((a) => a.length))
|
|
640
|
+
const result: unknown[][] = []
|
|
641
|
+
for (let i = 0; i < maxLen; i++) {
|
|
642
|
+
result.push([this.items[i] as unknown, ...arrays.map((a) => a[i] as unknown)])
|
|
643
|
+
}
|
|
644
|
+
return new Collection(result)
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
// ── Sorting ───────────────────────────────────────────────────────────────
|
|
648
|
+
|
|
649
|
+
sort(callback?: (a: T, b: T) => number): Collection<T> {
|
|
650
|
+
return new Collection([...this.items].sort(callback))
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
sortByDesc(key: keyof T | ((item: T) => unknown)): Collection<T> {
|
|
654
|
+
return this.sortBy(key, "desc")
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
sortDesc(): Collection<T> {
|
|
658
|
+
return new Collection(
|
|
659
|
+
[...this.items].sort((a, b) => {
|
|
660
|
+
if (a > b) return -1
|
|
661
|
+
if (a < b) return 1
|
|
662
|
+
return 0
|
|
663
|
+
}),
|
|
664
|
+
)
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
sortKeys(): Collection<T> {
|
|
668
|
+
return this.values()
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
reverse(): Collection<T> {
|
|
672
|
+
return new Collection([...this.items].reverse())
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// ── Stringification ───────────────────────────────────────────────────────
|
|
676
|
+
|
|
677
|
+
implode(keyOrGlue: keyof T | string, glue?: string): string {
|
|
678
|
+
if (glue !== undefined) {
|
|
679
|
+
return this.items.map((i) => i[keyOrGlue as keyof T]).join(glue)
|
|
680
|
+
}
|
|
681
|
+
return this.items.join(keyOrGlue as string)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
join(glue: string, finalGlue?: string): string {
|
|
685
|
+
if (!finalGlue || this.items.length <= 1) return this.items.join(glue)
|
|
686
|
+
const all = this.items.map(String)
|
|
687
|
+
const last = all.pop() as string
|
|
688
|
+
return all.join(glue) + finalGlue + last
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
toJson(pretty?: boolean): string {
|
|
692
|
+
return JSON.stringify(this.items, null, pretty ? 2 : undefined)
|
|
693
|
+
}
|
|
694
|
+
|
|
695
|
+
toPrettyJson(): string {
|
|
696
|
+
return JSON.stringify(this.items, null, 2)
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// ── Filtering ─────────────────────────────────────────────────────────────
|
|
700
|
+
|
|
701
|
+
doesntContain(itemOrCallback: T | ((item: T, index: number) => boolean)): boolean {
|
|
702
|
+
return !this.contains(itemOrCallback as T | ((item: T) => boolean))
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
every(callback: (item: T, index: number) => boolean): boolean {
|
|
706
|
+
return this.items.every(callback)
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
skipUntil(valueOrCallback: T | ((item: T, index: number) => boolean)): Collection<T> {
|
|
710
|
+
let found = false
|
|
711
|
+
return new Collection(
|
|
712
|
+
this.items.filter((item, i) => {
|
|
713
|
+
if (!found) {
|
|
714
|
+
const match =
|
|
715
|
+
typeof valueOrCallback === "function"
|
|
716
|
+
? (valueOrCallback as (item: T, index: number) => boolean)(item, i)
|
|
717
|
+
: item === valueOrCallback
|
|
718
|
+
if (match) found = true
|
|
719
|
+
return found
|
|
720
|
+
}
|
|
721
|
+
return true
|
|
722
|
+
}),
|
|
723
|
+
)
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
skipWhile(callback: (item: T, index: number) => boolean): Collection<T> {
|
|
727
|
+
let skipping = true
|
|
728
|
+
return new Collection(
|
|
729
|
+
this.items.filter((item, i) => {
|
|
730
|
+
if (skipping && callback(item, i)) return false
|
|
731
|
+
skipping = false
|
|
732
|
+
return true
|
|
733
|
+
}),
|
|
734
|
+
)
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
takeUntil(valueOrCallback: T | ((item: T, index: number) => boolean)): Collection<T> {
|
|
738
|
+
const result: T[] = []
|
|
739
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
740
|
+
const item = this.items[i]
|
|
741
|
+
const match =
|
|
742
|
+
typeof valueOrCallback === "function"
|
|
743
|
+
? (valueOrCallback as (item: T, index: number) => boolean)(item, i)
|
|
744
|
+
: item === valueOrCallback
|
|
745
|
+
if (match) break
|
|
746
|
+
result.push(item)
|
|
747
|
+
}
|
|
748
|
+
return new Collection(result)
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
takeWhile(callback: (item: T, index: number) => boolean): Collection<T> {
|
|
752
|
+
const result: T[] = []
|
|
753
|
+
for (let i = 0; i < this.items.length; i++) {
|
|
754
|
+
if (!callback(this.items[i], i)) break
|
|
755
|
+
result.push(this.items[i])
|
|
756
|
+
}
|
|
757
|
+
return new Collection(result)
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
flatten(depth = Infinity): Collection<unknown> {
|
|
761
|
+
return new Collection(this.items.flat(depth) as unknown[])
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
take(count: number): Collection<T> {
|
|
765
|
+
return new Collection(count >= 0 ? this.items.slice(0, count) : this.items.slice(count))
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
skip(count: number): Collection<T> {
|
|
769
|
+
return new Collection(this.items.slice(count))
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
concat(other: T[] | Collection<T>): Collection<T> {
|
|
773
|
+
const otherItems = other instanceof Collection ? other.all() : other
|
|
774
|
+
return new Collection([...this.items, ...otherItems])
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
values(): Collection<T> {
|
|
778
|
+
return new Collection([...this.items])
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
// ── where-family ──────────────────────────────────────────────────────────
|
|
782
|
+
|
|
783
|
+
where(key: keyof T, operatorOrValue: unknown, value?: unknown): Collection<T> {
|
|
784
|
+
const [op, val] = value === undefined ? ["==", operatorOrValue] : [operatorOrValue as string, value]
|
|
785
|
+
return new Collection(this.items.filter((item) => this._compareOp(item[key], op as string, val)))
|
|
786
|
+
}
|
|
787
|
+
|
|
788
|
+
whereStrict(key: keyof T, value: unknown): Collection<T> {
|
|
789
|
+
return new Collection(this.items.filter((item) => item[key] === value))
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
whereBetween(key: keyof T, range: [unknown, unknown]): Collection<T> {
|
|
793
|
+
const [min, max] = range
|
|
794
|
+
return new Collection(
|
|
795
|
+
this.items.filter((item) => {
|
|
796
|
+
const v = item[key] as never
|
|
797
|
+
return v >= (min as never) && v <= (max as never)
|
|
798
|
+
}),
|
|
799
|
+
)
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
whereNotBetween(key: keyof T, range: [unknown, unknown]): Collection<T> {
|
|
803
|
+
const [min, max] = range
|
|
804
|
+
return this.reject((item) => {
|
|
805
|
+
const v = item[key] as never
|
|
806
|
+
return v >= (min as never) && v <= (max as never)
|
|
807
|
+
})
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
whereIn(key: keyof T, values: unknown[]): Collection<T> {
|
|
811
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
812
|
+
return new Collection(this.items.filter((item) => values.some((v) => item[key] == v)))
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
whereInStrict(key: keyof T, values: unknown[]): Collection<T> {
|
|
816
|
+
return new Collection(this.items.filter((item) => values.includes(item[key] as unknown)))
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
whereNotIn(key: keyof T, values: unknown[]): Collection<T> {
|
|
820
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
821
|
+
return new Collection(this.items.filter((item) => !values.some((v) => item[key] == v)))
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
whereNotInStrict(key: keyof T, values: unknown[]): Collection<T> {
|
|
825
|
+
return new Collection(this.items.filter((item) => !values.includes(item[key] as unknown)))
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
whereNull(key: keyof T): Collection<T> {
|
|
829
|
+
return new Collection(this.items.filter((item) => item[key] == null))
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
whereNotNull(key: keyof T): Collection<T> {
|
|
833
|
+
return new Collection(this.items.filter((item) => item[key] != null))
|
|
834
|
+
}
|
|
835
|
+
|
|
836
|
+
whereInstanceOf<U>(ctor: new (...args: unknown[]) => U): Collection<U> {
|
|
837
|
+
return new Collection(this.items.filter((item) => item instanceof ctor) as unknown as U[])
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
// ── Merge/replace ─────────────────────────────────────────────────────────
|
|
841
|
+
|
|
842
|
+
merge(items: T[] | Collection<T>): Collection<T> {
|
|
843
|
+
const other = items instanceof Collection ? items.all() : items
|
|
844
|
+
return new Collection([...this.items, ...other])
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
replace(items: T[] | Collection<T>): Collection<T> {
|
|
848
|
+
const other = items instanceof Collection ? items.all() : items
|
|
849
|
+
const result = [...this.items]
|
|
850
|
+
for (let i = 0; i < other.length; i++) {
|
|
851
|
+
result[i] = other[i]
|
|
852
|
+
}
|
|
853
|
+
return new Collection(result)
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
// ── protected helpers ───────────────────────────────────────────────────────
|
|
857
|
+
|
|
858
|
+
protected extractValue(item: T, key?: keyof T | ((item: T) => unknown)): unknown {
|
|
859
|
+
if (!key) return item
|
|
860
|
+
return typeof key === "function" ? key(item) : item[key]
|
|
861
|
+
}
|
|
862
|
+
|
|
863
|
+
protected _compareOp(itemVal: unknown, op: string, val: unknown): boolean {
|
|
864
|
+
switch (op) {
|
|
865
|
+
case "===":
|
|
866
|
+
return itemVal === val
|
|
867
|
+
case "!==":
|
|
868
|
+
return itemVal !== val
|
|
869
|
+
case "==":
|
|
870
|
+
case "=":
|
|
871
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
872
|
+
return itemVal == val
|
|
873
|
+
case "!=":
|
|
874
|
+
case "<>":
|
|
875
|
+
// biome-ignore lint/suspicious/noDoubleEquals: intentional loose equality
|
|
876
|
+
return itemVal != val
|
|
877
|
+
case ">":
|
|
878
|
+
return (itemVal as never) > (val as never)
|
|
879
|
+
case "<":
|
|
880
|
+
return (itemVal as never) < (val as never)
|
|
881
|
+
case ">=":
|
|
882
|
+
return (itemVal as never) >= (val as never)
|
|
883
|
+
case "<=":
|
|
884
|
+
return (itemVal as never) <= (val as never)
|
|
885
|
+
default:
|
|
886
|
+
return false
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
}
|