@satoshibits/functional 1.0.2

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.
Files changed (46) hide show
  1. package/README.md +242 -0
  2. package/dist/array-utils.d.mts +317 -0
  3. package/dist/array-utils.d.mts.map +1 -0
  4. package/dist/array-utils.mjs +370 -0
  5. package/dist/array-utils.mjs.map +1 -0
  6. package/dist/composition.d.mts +603 -0
  7. package/dist/composition.d.mts.map +1 -0
  8. package/dist/composition.mjs +516 -0
  9. package/dist/composition.mjs.map +1 -0
  10. package/dist/object-utils.d.mts +267 -0
  11. package/dist/object-utils.d.mts.map +1 -0
  12. package/dist/object-utils.mjs +258 -0
  13. package/dist/object-utils.mjs.map +1 -0
  14. package/dist/option.d.mts +622 -0
  15. package/dist/option.d.mts.map +1 -0
  16. package/dist/option.mjs +637 -0
  17. package/dist/option.mjs.map +1 -0
  18. package/dist/performance.d.mts +265 -0
  19. package/dist/performance.d.mts.map +1 -0
  20. package/dist/performance.mjs +453 -0
  21. package/dist/performance.mjs.map +1 -0
  22. package/dist/pipeline.d.mts +431 -0
  23. package/dist/pipeline.d.mts.map +1 -0
  24. package/dist/pipeline.mjs +460 -0
  25. package/dist/pipeline.mjs.map +1 -0
  26. package/dist/predicates.d.mts +722 -0
  27. package/dist/predicates.d.mts.map +1 -0
  28. package/dist/predicates.mjs +802 -0
  29. package/dist/predicates.mjs.map +1 -0
  30. package/dist/reader-result.d.mts +422 -0
  31. package/dist/reader-result.d.mts.map +1 -0
  32. package/dist/reader-result.mjs +758 -0
  33. package/dist/reader-result.mjs.map +1 -0
  34. package/dist/result.d.mts +684 -0
  35. package/dist/result.d.mts.map +1 -0
  36. package/dist/result.mjs +814 -0
  37. package/dist/result.mjs.map +1 -0
  38. package/dist/types.d.mts +439 -0
  39. package/dist/types.d.mts.map +1 -0
  40. package/dist/types.mjs +191 -0
  41. package/dist/types.mjs.map +1 -0
  42. package/dist/validation.d.mts +622 -0
  43. package/dist/validation.d.mts.map +1 -0
  44. package/dist/validation.mjs +852 -0
  45. package/dist/validation.mjs.map +1 -0
  46. package/package.json +46 -0
@@ -0,0 +1,802 @@
1
+ "use strict";
2
+ /**
3
+ * @module predicates
4
+ * @description Functional utilities for composing and manipulating predicate functions.
5
+ * Predicates are functions that return boolean values and are fundamental
6
+ * for filtering, validation, and conditional logic. This module provides
7
+ * combinators for building complex predicates from simple ones, along with
8
+ * common predicate patterns for everyday use.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * import { and, or, not, isNotNil, inRange, hasProperty } from './predicates.mts';
13
+ *
14
+ * // compose predicates with logical operators
15
+ * const isPositiveEven = and(
16
+ * (n: number) => n > 0,
17
+ * (n: number) => n % 2 === 0
18
+ * );
19
+ *
20
+ * // create reusable validation functions
21
+ * const isValidUser = and(
22
+ * hasProperty('email'),
23
+ * hasProperty('name'),
24
+ * user => isNotNil(user.email) && user.email.includes('@')
25
+ * );
26
+ *
27
+ * // filter collections
28
+ * const validUsers = users.filter(isValidUser);
29
+ * const adults = people.filter(person => inRange(18, 120)(person.age));
30
+ * ```
31
+ *
32
+ * @category Core
33
+ * @since 2025-07-03
34
+ */
35
+ /**
36
+ * Logical AND combinator for predicates.
37
+ * @description Returns true only if all predicates return true. Short-circuits
38
+ * on the first false result for efficiency. Accepts any number of predicates
39
+ * and combines them into a single predicate function.
40
+ *
41
+ * @template T - The type of value being tested
42
+ * @param {Array<(value: T) => boolean>} predicates - Functions to combine with AND logic
43
+ * @returns {(value: T) => boolean} A predicate that returns true if all predicates pass
44
+ *
45
+ * @category Combinators
46
+ * @example
47
+ * // Basic number validation
48
+ * const isPositive = (n: number) => n > 0;
49
+ * const isEven = (n: number) => n % 2 === 0;
50
+ * const isPositiveEven = and(isPositive, isEven);
51
+ *
52
+ * isPositiveEven(4); // => true
53
+ * isPositiveEven(-2); // => false (not positive)
54
+ * isPositiveEven(3); // => false (not even)
55
+ *
56
+ * @example
57
+ * // Validating user data
58
+ * const hasName = (user: { name?: string }) => !!user.name;
59
+ * const hasEmail = (user: { email?: string }) => !!user.email;
60
+ * const isAdult = (user: { age?: number }) => (user.age ?? 0) >= 18;
61
+ *
62
+ * const isValidAdultUser = and(hasName, hasEmail, isAdult);
63
+ * isValidAdultUser({ name: 'John', email: 'john@example.com', age: 25 }); // => true
64
+ *
65
+ * @example
66
+ * // Form validation with multiple rules
67
+ * const isValidPassword = and(
68
+ * (pwd: string) => pwd.length >= 8,
69
+ * (pwd: string) => /[A-Z]/.test(pwd),
70
+ * (pwd: string) => /[0-9]/.test(pwd),
71
+ * (pwd: string) => /[!@#$%^&*]/.test(pwd)
72
+ * );
73
+ *
74
+ * isValidPassword('Pass123!'); // => true
75
+ * isValidPassword('weak'); // => false
76
+ *
77
+ * @see or - Logical OR combinator
78
+ * @see not - Logical NOT combinator
79
+ * @since 2025-07-03
80
+ */
81
+ export var and = function () {
82
+ var predicates = [];
83
+ for (var _i = 0; _i < arguments.length; _i++) {
84
+ predicates[_i] = arguments[_i];
85
+ }
86
+ return function (value) {
87
+ return predicates.every(function (predicate) { return predicate(value); });
88
+ };
89
+ };
90
+ /**
91
+ * Logical OR combinator for predicates.
92
+ * @description Returns true if at least one predicate returns true. Short-circuits
93
+ * on the first true result for efficiency. Accepts any number of predicates
94
+ * and combines them into a single predicate function.
95
+ *
96
+ * @template T - The type of value being tested
97
+ * @param {Array<(value: T) => boolean>} predicates - Functions to combine with OR logic
98
+ * @returns {(value: T) => boolean} A predicate that returns true if any predicate passes
99
+ *
100
+ * @category Combinators
101
+ * @example
102
+ * // Role-based access control
103
+ * const isAdmin = (user: { role: string }) => user.role === 'admin';
104
+ * const isModerator = (user: { role: string }) => user.role === 'moderator';
105
+ * const hasPrivileges = or(isAdmin, isModerator);
106
+ *
107
+ * hasPrivileges({ role: 'admin' }); // => true
108
+ * hasPrivileges({ role: 'moderator' }); // => true
109
+ * hasPrivileges({ role: 'user' }); // => false
110
+ *
111
+ * @example
112
+ * // Multiple payment methods
113
+ * const hasCreditCard = (payment: { type: string }) => payment.type === 'credit';
114
+ * const hasPayPal = (payment: { type: string }) => payment.type === 'paypal';
115
+ * const hasCrypto = (payment: { type: string }) => payment.type === 'crypto';
116
+ *
117
+ * const acceptsPayment = or(hasCreditCard, hasPayPal, hasCrypto);
118
+ * acceptsPayment({ type: 'paypal' }); // => true
119
+ *
120
+ * @example
121
+ * // Flexible search criteria
122
+ * const searchTerm = 'john';
123
+ * const matchesSearch = or(
124
+ * (user: User) => user.name.toLowerCase().includes(searchTerm),
125
+ * (user: User) => user.email.toLowerCase().includes(searchTerm),
126
+ * (user: User) => user.username.toLowerCase().includes(searchTerm)
127
+ * );
128
+ *
129
+ * const searchResults = users.filter(matchesSearch);
130
+ *
131
+ * @see and - Logical AND combinator
132
+ * @see not - Logical NOT combinator
133
+ * @since 2025-07-03
134
+ */
135
+ export var or = function () {
136
+ var predicates = [];
137
+ for (var _i = 0; _i < arguments.length; _i++) {
138
+ predicates[_i] = arguments[_i];
139
+ }
140
+ return function (value) {
141
+ return predicates.some(function (predicate) { return predicate(value); });
142
+ };
143
+ };
144
+ /**
145
+ * Logical NOT combinator for predicates.
146
+ * @description Inverts the result of a predicate, turning true to false and
147
+ * false to true. Useful for creating the opposite of existing predicates
148
+ * without duplicating logic.
149
+ *
150
+ * @template T - The type of value being tested
151
+ * @param {(value: T) => boolean} predicate - The predicate to invert
152
+ * @returns {(value: T) => boolean} A predicate that returns the opposite result
153
+ *
154
+ * @category Combinators
155
+ * @example
156
+ * // Basic negation
157
+ * const isPositive = (n: number) => n > 0;
158
+ * const isNegativeOrZero = not(isPositive);
159
+ *
160
+ * isNegativeOrZero(-5); // => true
161
+ * isNegativeOrZero(0); // => true
162
+ * isNegativeOrZero(5); // => false
163
+ *
164
+ * @example
165
+ * // Filtering out specific items
166
+ * const isError = (log: { level: string }) => log.level === 'error';
167
+ * const nonErrorLogs = logs.filter(not(isError));
168
+ *
169
+ * @example
170
+ * // Excluding items from selection
171
+ * const isBlacklisted = oneOf(blacklistedIds);
172
+ * const allowedItems = items.filter(not(item => isBlacklisted(item.id)));
173
+ *
174
+ * @see and - Logical AND combinator
175
+ * @see or - Logical OR combinator
176
+ * @since 2025-07-03
177
+ */
178
+ export var not = function (predicate) {
179
+ return function (value) {
180
+ return !predicate(value);
181
+ };
182
+ };
183
+ /**
184
+ * Exclusive OR (XOR) combinator for predicates.
185
+ * @description Returns true if exactly one predicate returns true, but not both.
186
+ * Useful for ensuring mutually exclusive conditions or validating that
187
+ * exactly one option is selected from a pair.
188
+ *
189
+ * @template T - The type of value being tested
190
+ * @param {(value: T) => boolean} predicate1 - First predicate to test
191
+ * @param {(value: T) => boolean} predicate2 - Second predicate to test
192
+ * @returns {(value: T) => boolean} A predicate that returns true if exactly one input predicate passes
193
+ *
194
+ * @category Combinators
195
+ * @example
196
+ * // Authentication method validation
197
+ * const hasUsername = (auth: { username?: string }) => !!auth.username;
198
+ * const hasEmail = (auth: { email?: string }) => !!auth.email;
199
+ * const hasExactlyOneIdentifier = xor(hasUsername, hasEmail);
200
+ *
201
+ * hasExactlyOneIdentifier({ username: 'john' }); // => true
202
+ * hasExactlyOneIdentifier({ email: 'john@example.com' }); // => true
203
+ * hasExactlyOneIdentifier({ username: 'john', email: 'j@e.com' }); // => false
204
+ * hasExactlyOneIdentifier({}); // => false
205
+ *
206
+ * @example
207
+ * // Toggle state validation
208
+ * const isManualMode = (config: Config) => config.mode === 'manual';
209
+ * const hasAutoSettings = (config: Config) => !!config.autoSettings;
210
+ * const isValidConfig = xor(isManualMode, hasAutoSettings);
211
+ * // Ensures either manual mode OR auto settings, but not both
212
+ *
213
+ * @see and - Logical AND combinator
214
+ * @see or - Logical OR combinator
215
+ * @since 2025-07-03
216
+ */
217
+ export var xor = function (predicate1, predicate2) {
218
+ return function (value) {
219
+ var p1 = predicate1(value);
220
+ var p2 = predicate2(value);
221
+ return (p1 && !p2) || (!p1 && p2);
222
+ };
223
+ };
224
+ /**
225
+ * Creates a predicate that checks if a value is not null or undefined.
226
+ * @description Type guard function that narrows types by excluding null and undefined.
227
+ * Particularly useful for filtering arrays and conditional type narrowing.
228
+ * Unlike truthiness checks, this explicitly checks for null/undefined only.
229
+ *
230
+ * @template T - The type of the non-null value
231
+ * @param {T | null | undefined} value - The value to check
232
+ * @returns {value is T} True if the value is not null or undefined
233
+ *
234
+ * @category Type Guards
235
+ * @example
236
+ * // Array filtering with type narrowing
237
+ * const values: (string | null | undefined)[] = ['a', null, 'b', undefined, 'c'];
238
+ * const nonNullValues = values.filter(isNotNil);
239
+ * // => ['a', 'b', 'c'] with type string[]
240
+ *
241
+ * @example
242
+ * // Type guard in conditional
243
+ * function processValue(value: string | null) {
244
+ * if (isNotNil(value)) {
245
+ * // TypeScript knows value is string here
246
+ * return value.toUpperCase();
247
+ * }
248
+ * return 'DEFAULT';
249
+ * }
250
+ *
251
+ * @example
252
+ * // Optional chaining alternative
253
+ * const users: (User | null)[] = await fetchUsers();
254
+ * const activeUsers = users
255
+ * .filter(isNotNil)
256
+ * .filter(user => user.status === 'active');
257
+ *
258
+ * @see isNil - Check if value is null or undefined
259
+ * @see isEmpty - Check if value is empty
260
+ * @since 2025-07-03
261
+ */
262
+ export var isNotNil = function (value) {
263
+ return value !== null && value !== undefined;
264
+ };
265
+ /**
266
+ * Creates a predicate that checks if a value is null or undefined.
267
+ * @description Type guard function that identifies null and undefined values.
268
+ * Useful for validation, error handling, and conditional logic where
269
+ * null/undefined values need special treatment.
270
+ *
271
+ * @template T - The type of the value when not null/undefined
272
+ * @param {T | null | undefined} value - The value to check
273
+ * @returns {value is null | undefined} True if the value is null or undefined
274
+ *
275
+ * @category Type Guards
276
+ * @example
277
+ * // Filtering null/undefined values
278
+ * const values = [1, null, 2, undefined, 3];
279
+ * const nilValues = values.filter(isNil);
280
+ * // => [null, undefined]
281
+ *
282
+ * @example
283
+ * // Early return pattern
284
+ * function processUser(user: User | null) {
285
+ * if (isNil(user)) {
286
+ * return { error: 'User not found' };
287
+ * }
288
+ * // Process user...
289
+ * }
290
+ *
291
+ * @example
292
+ * // Default value handling
293
+ * function getConfig(key: string): string {
294
+ * const value = configMap.get(key);
295
+ * if (isNil(value)) {
296
+ * return getDefaultConfig(key);
297
+ * }
298
+ * return value;
299
+ * }
300
+ *
301
+ * @see isNotNil - Check if value is not null or undefined
302
+ * @see isEmpty - Check if value is empty
303
+ * @since 2025-07-03
304
+ */
305
+ export var isNil = function (value) {
306
+ return value === null || value === undefined;
307
+ };
308
+ /**
309
+ * Checks if a value is empty (null, undefined, empty string, empty array, or empty object).
310
+ * @description Comprehensive emptiness check that handles multiple data types.
311
+ * Returns true for null, undefined, empty strings, arrays with no elements,
312
+ * and objects with no own properties. Does not consider whitespace-only strings as empty.
313
+ *
314
+ * @param {unknown} value - The value to check for emptiness
315
+ * @returns {boolean} True if the value is considered empty
316
+ *
317
+ * @category Value Checks
318
+ * @example
319
+ * // Basic emptiness checks
320
+ * isEmpty(null); // => true
321
+ * isEmpty(undefined); // => true
322
+ * isEmpty(''); // => true
323
+ * isEmpty([]); // => true
324
+ * isEmpty({}); // => true
325
+ * isEmpty('hello'); // => false
326
+ * isEmpty([1, 2, 3]); // => false
327
+ * isEmpty({ a: 1 }); // => false
328
+ *
329
+ * @example
330
+ * // Form validation
331
+ * const formData = { name: '', email: 'test@example.com', bio: null };
332
+ * const emptyFields = Object.entries(formData)
333
+ * .filter(([_, value]) => isEmpty(value))
334
+ * .map(([key]) => key);
335
+ * // => ['name', 'bio']
336
+ *
337
+ * @example
338
+ * // API response validation
339
+ * function handleResponse(data: unknown) {
340
+ * if (isEmpty(data)) {
341
+ * throw new Error('Empty response received');
342
+ * }
343
+ * return processData(data);
344
+ * }
345
+ *
346
+ * @see isNotEmpty - Check if value has content
347
+ * @see isNil - Check if value is null or undefined
348
+ * @since 2025-07-03
349
+ */
350
+ export var isEmpty = function (value) {
351
+ if (value === null || value === undefined)
352
+ return true;
353
+ if (typeof value === 'string')
354
+ return value.length === 0;
355
+ if (Array.isArray(value))
356
+ return value.length === 0;
357
+ if (typeof value === 'object')
358
+ return Object.keys(value).length === 0;
359
+ return false;
360
+ };
361
+ /**
362
+ * Opposite of isEmpty - checks if a value has content.
363
+ * @description Returns true if a value is not empty. A value is considered
364
+ * to have content if it's not null, undefined, an empty string, an empty array,
365
+ * or an empty object.
366
+ *
367
+ * @param {unknown} value - The value to check for content
368
+ * @returns {boolean} True if the value has content
369
+ *
370
+ * @category Value Checks
371
+ * @example
372
+ * // Form field validation
373
+ * const requiredFields = ['name', 'email'];
374
+ * const formData = { name: 'John', email: '', phone: '123' };
375
+ *
376
+ * const filledRequired = requiredFields.every(field =>
377
+ * isNotEmpty(formData[field as keyof typeof formData])
378
+ * );
379
+ * // => false (email is empty)
380
+ *
381
+ * @example
382
+ * // Filter out empty values
383
+ * const config = {
384
+ * apiKey: 'abc123',
385
+ * endpoint: '',
386
+ * timeout: 5000,
387
+ * headers: {}
388
+ * };
389
+ *
390
+ * const validConfig = Object.fromEntries(
391
+ * Object.entries(config).filter(([_, value]) => isNotEmpty(value))
392
+ * );
393
+ * // => { apiKey: 'abc123', timeout: 5000 }
394
+ *
395
+ * @see isEmpty - Check if value is empty
396
+ * @see isNotNil - Check if value is not null or undefined
397
+ * @since 2025-07-03
398
+ */
399
+ export var isNotEmpty = function (value) { return !isEmpty(value); };
400
+ /**
401
+ * Creates a predicate that checks if a value equals a specific value.
402
+ * @description Uses strict equality (===) to compare values. Creates a reusable
403
+ * predicate function that can be used for filtering, finding, or validation.
404
+ *
405
+ * @template T - The type of values being compared
406
+ * @param {T} target - The value to compare against
407
+ * @returns {(value: T) => boolean} A predicate that returns true if the value equals the target
408
+ *
409
+ * @category Comparison
410
+ * @example
411
+ * // Basic filtering
412
+ * const isJohn = equals('John');
413
+ * ['John', 'Jane', 'John', 'Jack'].filter(isJohn);
414
+ * // => ['John', 'John']
415
+ *
416
+ * @example
417
+ * // Status checking
418
+ * const isActive = equals('active');
419
+ * const activeUsers = users.filter(user => isActive(user.status));
420
+ *
421
+ * @example
422
+ * // Finding specific items
423
+ * const isTargetId = equals(targetUserId);
424
+ * const targetUser = users.find(user => isTargetId(user.id));
425
+ *
426
+ * @see oneOf - Check if value is one of multiple values
427
+ * @since 2025-07-03
428
+ */
429
+ export var equals = function (target) {
430
+ return function (value) {
431
+ return value === target;
432
+ };
433
+ };
434
+ /**
435
+ * Creates a predicate that checks if a value is one of the specified values.
436
+ * @description Uses Array.includes internally to check membership. Useful for
437
+ * creating allowlists, checking against enums, or validating against a set
438
+ * of acceptable values.
439
+ *
440
+ * @template T - The type of values in the options array
441
+ * @param {T[]} options - Array of acceptable values
442
+ * @returns {(value: T) => boolean} A predicate that returns true if the value is in the options
443
+ *
444
+ * @category Comparison
445
+ * @example
446
+ * // Day type checking
447
+ * const isWeekend = oneOf(['Saturday', 'Sunday']);
448
+ * isWeekend('Saturday'); // => true
449
+ * isWeekend('Monday'); // => false
450
+ *
451
+ * @example
452
+ * // Permission checking
453
+ * const canEdit = oneOf(['admin', 'editor', 'author']);
454
+ * const editableContent = content.filter(item => canEdit(item.userRole));
455
+ *
456
+ * @example
457
+ * // Enum validation
458
+ * enum Status { Active = 'active', Inactive = 'inactive', Pending = 'pending' }
459
+ * const isValidStatus = oneOf(Object.values(Status));
460
+ *
461
+ * @see equals - Check if value equals a specific value
462
+ * @see includes - Check if array includes a value
463
+ * @since 2025-07-03
464
+ */
465
+ export var oneOf = function (options) {
466
+ return function (value) {
467
+ return options.includes(value);
468
+ };
469
+ };
470
+ /**
471
+ * Creates a predicate that checks if a number is within a range (inclusive).
472
+ * @description Both minimum and maximum values are included in the range.
473
+ * Useful for validating numeric values against acceptable bounds.
474
+ *
475
+ * @param {number} min - The minimum value (inclusive)
476
+ * @param {number} max - The maximum value (inclusive)
477
+ * @returns {(value: number) => boolean} A predicate that returns true if the value is within range
478
+ *
479
+ * @category Numeric
480
+ * @example
481
+ * // Age validation
482
+ * const isValidAge = inRange(18, 65);
483
+ * isValidAge(17); // => false
484
+ * isValidAge(18); // => true
485
+ * isValidAge(30); // => true
486
+ * isValidAge(65); // => true
487
+ * isValidAge(66); // => false
488
+ *
489
+ * @example
490
+ * // Score validation
491
+ * const isPassingGrade = inRange(60, 100);
492
+ * const passingStudents = students.filter(s => isPassingGrade(s.score));
493
+ *
494
+ * @example
495
+ * // Temperature monitoring
496
+ * const isNormalTemp = inRange(36.0, 37.5);
497
+ * const alerts = readings
498
+ * .filter(not(r => isNormalTemp(r.temperature)))
499
+ * .map(r => ({ time: r.time, temp: r.temperature }));
500
+ *
501
+ * @since 2025-07-03
502
+ */
503
+ export var inRange = function (min, max) {
504
+ return function (value) {
505
+ return value >= min && value <= max;
506
+ };
507
+ };
508
+ /**
509
+ * Creates a predicate that checks if a string matches a regular expression.
510
+ * @description Uses RegExp.test() to check if the pattern matches the string.
511
+ * The regular expression can include flags for case-insensitive matching,
512
+ * multiline mode, etc.
513
+ *
514
+ * @param {RegExp} pattern - The regular expression to test against
515
+ * @returns {(value: string) => boolean} A predicate that returns true if the string matches
516
+ *
517
+ * @category String
518
+ * @example
519
+ * // Email validation
520
+ * const isEmail = matches(/^[^\s@]+@[^\s@]+\.[^\s@]+$/);
521
+ * isEmail('test@example.com'); // => true
522
+ * isEmail('invalid-email'); // => false
523
+ *
524
+ * @example
525
+ * // Phone number validation
526
+ * const isPhoneNumber = matches(/^\+?[\d\s-()]+$/);
527
+ * const validPhones = contacts
528
+ * .map(c => c.phone)
529
+ * .filter(isPhoneNumber);
530
+ *
531
+ * @example
532
+ * // URL validation with flags
533
+ * const isHttpUrl = matches(/^https?:\/\//i);
534
+ * const secureUrls = urls.filter(matches(/^https:\/\//));
535
+ *
536
+ * @since 2025-07-03
537
+ */
538
+ export var matches = function (pattern) {
539
+ return function (value) {
540
+ return pattern.test(value);
541
+ };
542
+ };
543
+ /**
544
+ * Creates a predicate that checks if an object has a specific property.
545
+ * @description Type guard that checks for property existence using the 'in' operator.
546
+ * The returned predicate narrows the type to include the checked property.
547
+ * Works with string, number, and symbol keys.
548
+ *
549
+ * @template K - The type of the property key
550
+ * @param {K} key - The property key to check for
551
+ * @returns {<T extends object>(obj: T) => obj is T & Record<K, unknown>} A type guard predicate
552
+ *
553
+ * @category Object
554
+ * @example
555
+ * // Type-safe property filtering
556
+ * const hasEmail = hasProperty('email');
557
+ * const users = [
558
+ * { name: 'John', email: 'john@example.com' },
559
+ * { name: 'Jane' }
560
+ * ];
561
+ * const usersWithEmail = users.filter(hasEmail);
562
+ * // => [{ name: 'John', email: 'john@example.com' }]
563
+ * // TypeScript knows these have email property
564
+ *
565
+ * @example
566
+ * // Feature detection
567
+ * const supportsWebGL = hasProperty('WebGLRenderingContext');
568
+ * if (supportsWebGL(window)) {
569
+ * // Initialize WebGL...
570
+ * }
571
+ *
572
+ * @example
573
+ * // Optional property handling
574
+ * interface User {
575
+ * id: string;
576
+ * name: string;
577
+ * avatar?: string;
578
+ * }
579
+ *
580
+ * const hasAvatar = hasProperty('avatar');
581
+ * const usersWithAvatars = users.filter(hasAvatar);
582
+ * // Now TypeScript knows avatar exists on these users
583
+ *
584
+ * @since 2025-07-03
585
+ */
586
+ export var hasProperty = function (key) {
587
+ return function (obj) {
588
+ return key in obj;
589
+ };
590
+ };
591
+ /**
592
+ * Creates a predicate that checks if an array includes a specific value.
593
+ * @description Creates a predicate function that tests array membership.
594
+ * Uses Array.includes internally, so it uses SameValueZero equality.
595
+ *
596
+ * @template T - The type of elements in the array
597
+ * @param {T} target - The value to search for in arrays
598
+ * @returns {(array: T[]) => boolean} A predicate that returns true if the array includes the target
599
+ *
600
+ * @category Array
601
+ * @example
602
+ * // Language filtering
603
+ * const hasFavorite = includes('JavaScript');
604
+ * const jsDevs = developers.filter(dev => hasFavorite(dev.languages));
605
+ *
606
+ * @example
607
+ * // Tag filtering
608
+ * const hasUrgentTag = includes('urgent');
609
+ * const urgentTasks = tasks.filter(task => hasUrgentTag(task.tags));
610
+ *
611
+ * @example
612
+ * // Permission checking
613
+ * const hasAdminPermission = includes('admin');
614
+ * const adminActions = actions.filter(action =>
615
+ * hasAdminPermission(action.requiredPermissions)
616
+ * );
617
+ *
618
+ * @see oneOf - Check if value is one of multiple values
619
+ * @since 2025-07-03
620
+ */
621
+ export var includes = function (target) {
622
+ return function (array) {
623
+ return array.includes(target);
624
+ };
625
+ };
626
+ /**
627
+ * Creates a predicate that always returns true.
628
+ * @description Useful as a default predicate, for conditional filtering,
629
+ * or as a placeholder during development. The parameter is ignored.
630
+ *
631
+ * @template T - The type of the ignored parameter
632
+ * @param {T} _ - Value is ignored
633
+ * @returns {boolean} Always returns true
634
+ *
635
+ * @category Constants
636
+ * @example
637
+ * // Admin bypass for filters
638
+ * const filters = {
639
+ * status: user.role === 'admin' ? alwaysTrue : equals('published')
640
+ * };
641
+ *
642
+ * @example
643
+ * // Conditional filtering
644
+ * const nameFilter = searchTerm
645
+ * ? (user: User) => user.name.includes(searchTerm)
646
+ * : alwaysTrue;
647
+ *
648
+ * @example
649
+ * // Feature toggle
650
+ * const canAccessFeature = FEATURE_ENABLED ? hasPermission('feature') : alwaysTrue;
651
+ *
652
+ * @see alwaysFalse - Predicate that always returns false
653
+ * @since 2025-07-03
654
+ */
655
+ export var alwaysTrue = function (_) { return true; };
656
+ /**
657
+ * Creates a predicate that always returns false.
658
+ * @description Useful for disabling features, creating empty filter results,
659
+ * or as a placeholder during development. The parameter is ignored.
660
+ *
661
+ * @template T - The type of the ignored parameter
662
+ * @param {T} _ - Value is ignored
663
+ * @returns {boolean} Always returns false
664
+ *
665
+ * @category Constants
666
+ * @example
667
+ * // Conditional record display
668
+ * const filters = {
669
+ * deleted: showDeleted ? alwaysTrue : alwaysFalse
670
+ * };
671
+ *
672
+ * @example
673
+ * // Feature flags
674
+ * const canAccessBeta = BETA_ENABLED ? hasRole('beta') : alwaysFalse;
675
+ *
676
+ * @example
677
+ * // Maintenance mode
678
+ * const canPerformAction = MAINTENANCE_MODE ? alwaysFalse : hasPermission('action');
679
+ *
680
+ * @see alwaysTrue - Predicate that always returns true
681
+ * @since 2025-07-03
682
+ */
683
+ export var alwaysFalse = function (_) { return false; };
684
+ /**
685
+ * Higher-order predicate utilities for complex compositions.
686
+ * @description Advanced utilities for creating and transforming predicates.
687
+ * These functions provide powerful patterns for building complex predicates
688
+ * from simpler ones.
689
+ *
690
+ * @category Advanced
691
+ * @since 2025-07-03
692
+ */
693
+ export var predicateUtils = {
694
+ /**
695
+ * Creates a predicate based on a property value.
696
+ * @description Checks if an object's property equals a specific value.
697
+ * Uses strict equality (===) for comparison.
698
+ *
699
+ * @template T - The type of the object
700
+ * @template K - The type of the property key
701
+ * @param {K} key - The property key to check
702
+ * @param {T[K]} value - The value to compare against
703
+ * @returns {(obj: T) => boolean} A predicate that checks the property value
704
+ *
705
+ * @example
706
+ * // Role-based filtering
707
+ * const isAdminRole = predicateUtils.propEquals('role', 'admin');
708
+ * const admins = users.filter(isAdminRole);
709
+ *
710
+ * @example
711
+ * // Status checking
712
+ * const isPublished = predicateUtils.propEquals('status', 'published');
713
+ * const publishedPosts = posts.filter(isPublished);
714
+ *
715
+ * @since 2025-07-03
716
+ */
717
+ propEquals: function (key, value) {
718
+ return function (obj) {
719
+ return obj[key] === value;
720
+ };
721
+ },
722
+ /**
723
+ * Creates a predicate that checks multiple properties.
724
+ * @description Checks if an object matches all properties in a partial object.
725
+ * Only checks properties that exist in the partial object.
726
+ *
727
+ * @template T - The type of the object being checked
728
+ * @param {Partial<T>} partial - Object with properties to match
729
+ * @returns {(obj: T) => boolean} A predicate that checks all properties match
730
+ *
731
+ * @example
732
+ * // Finding specific users
733
+ * const isJohnDoe = predicateUtils.propsMatch({
734
+ * firstName: 'John',
735
+ * lastName: 'Doe'
736
+ * });
737
+ *
738
+ * const johnDoe = users.find(isJohnDoe);
739
+ *
740
+ * @example
741
+ * // Filtering by multiple criteria
742
+ * const isTargetProduct = predicateUtils.propsMatch({
743
+ * category: 'electronics',
744
+ * inStock: true,
745
+ * featured: true
746
+ * });
747
+ *
748
+ * const featuredElectronics = products.filter(isTargetProduct);
749
+ *
750
+ * @since 2025-07-03
751
+ */
752
+ propsMatch: function (partial) {
753
+ return function (obj) {
754
+ return Object.entries(partial).every(function (_a) {
755
+ var key = _a[0], value = _a[1];
756
+ return obj[key] === value;
757
+ });
758
+ };
759
+ },
760
+ /**
761
+ * Creates a predicate that applies a transformation before testing.
762
+ * @description Contramap allows you to adapt a predicate for one type to work
763
+ * with another type by providing a transformation function. This is the
764
+ * contravariant functor operation for predicates.
765
+ *
766
+ * @template A - The input type
767
+ * @template B - The type the predicate expects
768
+ * @param {(a: A) => B} transform - Function to transform A to B
769
+ * @param {(b: B) => boolean} predicate - Predicate that operates on type B
770
+ * @returns {(value: A) => boolean} A predicate that operates on type A
771
+ *
772
+ * @example
773
+ * // Extract property before testing
774
+ * const hasLongName = predicateUtils.contramap(
775
+ * (user: { name: string }) => user.name,
776
+ * (name: string) => name.length > 10
777
+ * );
778
+ *
779
+ * @example
780
+ * // Case-insensitive comparison
781
+ * const isCaseInsensitiveMatch = (target: string) =>
782
+ * predicateUtils.contramap(
783
+ * (s: string) => s.toLowerCase(),
784
+ * equals(target.toLowerCase())
785
+ * );
786
+ *
787
+ * @example
788
+ * // Date comparison
789
+ * const isAfter2020 = predicateUtils.contramap(
790
+ * (date: Date) => date.getFullYear(),
791
+ * (year: number) => year > 2020
792
+ * );
793
+ *
794
+ * @since 2025-07-03
795
+ */
796
+ contramap: function (transform, predicate) {
797
+ return function (value) {
798
+ return predicate(transform(value));
799
+ };
800
+ },
801
+ };
802
+ //# sourceMappingURL=predicates.mjs.map