@magic/types 0.1.39 → 0.1.41

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
@@ -3,24 +3,9 @@
3
3
  typechecking utilities
4
4
 
5
5
  [![NPM version][npm-image]][npm-url]
6
- [![Linux Build Status][travis-image]][travis-url]
7
- [![Windows Build Status][appveyor-image]][appveyor-url]
8
- [![Coverage Status][coveralls-image]][coveralls-url]
9
- [![Greenkeeper badge][greenkeeper-image]][greenkeeper-url]
10
- [![Known Vulnerabilities][snyk-image]][snyk-url]
11
6
 
12
7
  [npm-image]: https://img.shields.io/npm/v/@magic/types.svg
13
8
  [npm-url]: https://www.npmjs.com/package/@magic/types
14
- [travis-image]: https://img.shields.io/travis/com/magic/types/master
15
- [travis-url]: https://travis-ci.com/magic/types
16
- [appveyor-image]: https://img.shields.io/appveyor/ci/magic/types/master.svg
17
- [appveyor-url]: https://ci.appveyor.com/project/magic/types/branch/master
18
- [coveralls-image]: https://coveralls.io/repos/github/magic/types/badge.svg
19
- [coveralls-url]: https://coveralls.io/github/magic/types
20
- [greenkeeper-image]: https://badges.greenkeeper.io/magic/types.svg
21
- [greenkeeper-url]: https://badges.greenkeeper.io/magic/types.svg
22
- [snyk-image]: https://snyk.io/test/github/magic/types/badge.svg
23
- [snyk-url]: https://snyk.io/test/github/magic/types
24
9
 
25
10
  ##### install
26
11
 
@@ -45,6 +30,19 @@ import is from '@magic/types'
45
30
  is.array([]) // true
46
31
  ```
47
32
 
33
+ ##### import deep
34
+
35
+ ```javascript
36
+ import { deep } from '@magic/types'
37
+
38
+ deep.isDeepEqual([1, 2, 3], [1, 2, 3]) // true
39
+ // also: deep.deepEqual, deep.deepEq, is.isDeepEqual
40
+ deep.isDeepDifferent([1, 2, 3], [1, 2, 3]) // false
41
+ // also: deep.deepDifferent, deep.deepDiff, is.isDeepDifferent
42
+ deep.isEqual([1, 2, 3], [1, 2, 3]) // true
43
+ // also: is.deep.isEqual, is.deep.equal, is.deep.eq
44
+ ```
45
+
48
46
  ##### functions
49
47
 
50
48
  ```javascript
@@ -52,13 +50,20 @@ is.array([]) // true
52
50
  // comparisons
53
51
 
54
52
  // test a value for multiple types
55
- is(ele, ...types)
56
- // alias is.eq, isEq, test
53
+ is.is(ele, ...types)
54
+ // alias is.type, is.testType, is.types, test
57
55
 
58
56
  // test if a value is not of a type
59
57
  not(ele, ...types)
60
58
  // alias is.neq, isNeq, isNot
61
59
 
60
+ // not (and is.not) is also a namespace with negated versions of every check:
61
+ is.not.array([]) // false
62
+ is.not.len.eq('abc', 'def') // false
63
+ is.not.case.upper('lowercase') // true
64
+ is.not.deep.eq([1], [1]) // false
65
+ is.not.ip.v4('192.168.1.1') // false
66
+
62
67
  isSameType('string', 'string')
63
68
  // alias isSame, is.same, is.sameType
64
69
 
@@ -74,7 +79,7 @@ isBoolean(true) // true
74
79
  isDefined(undefined) //false
75
80
  // alias isDef, is.defined, is.def
76
81
 
77
- isUndefined(undefined) //false
82
+ isUndefined(undefined) //true
78
83
  // alias isUndef, is.undefined, is.undef
79
84
 
80
85
  isFunction(() => {}) // true
@@ -84,7 +89,7 @@ isAsyncFunction(async () => {}) // true
84
89
  // alias isAsyncFunc, isAsyncFn, is.asyncFunction, is.asyncFunc, is.asyncFn
85
90
 
86
91
  isGeneratorFunction(* () => {}) // true
87
- // alias isGeneratorFunc, isGeneratorFunc, is.generatorFunction, is.generatorFunc, is.generatorFn
92
+ // alias isGeneratorFunc, isGeneratorFn, isGenerator, is.generatorFunction, is.generatorFunc, is.generatorFn, generator, generatorFn, generatorFunc, generatorFunction
88
93
 
89
94
  isNumber(1) // true
90
95
  // alias isNum, is.number, is.num
@@ -98,21 +103,41 @@ isFloat(1.1) // true
98
103
  isObject({}) // true
99
104
  // alias isObj, is.object, is.obj
100
105
 
106
+ isObjectNative({}) // true
107
+ isObjectNative([]) // false
108
+ // alias is.objectNative
109
+
101
110
  isString('') // true
102
111
  // alias isStr, is.string, is.str
103
112
 
104
113
  isRGBAObject({ r: 1, g: 1, b: 1, a: 1 }) // true
105
114
  // alias isRGBA, is.rgbaObject, is.rgba
106
115
 
107
- isRGBObject
116
+ isRGBObject({ r: 1, g: 1, b: 1 }) // true
108
117
  // alias isRGB, is.rgbObject, is.rgb
109
118
 
119
+ isRGBValue({ r: 1, g: 1, b: 1 }) // true
120
+ // alias isRGBObject, is.rgbValue
121
+
122
+ isRGBAValue({ r: 1, g: 1, b: 1, a: 1 }) // true
123
+ // alias isRGBAObject, is.rgbaValue
124
+
110
125
  isHexColor('#333') // true
111
126
  // alias isHex, is.hex, is.hexColor
112
127
 
128
+ isHexColor3('#333') // true
129
+ isHexColor4('#3333') // true
130
+ isHexColor6('#333333') // true
131
+ isHexColor8('#33333333') // true
132
+ // aliases is.hex3, is.hexColor3, is.hex4, is.hexColor4, is.hex6, is.hexColor6, is.hex8, is.hexColor8
133
+
113
134
  isHexAlphaColor('#3333') // true
114
135
  // alias isHexa, is.hexa, is.hexAlphaColor
115
136
 
137
+ isHexAlphaColor4('#3333') // true
138
+ isHexAlphaColor8('#33333333') // true
139
+ // aliases is.hexa4, is.hexAlphaColor4, is.hexa8, is.hexAlphaColor8
140
+
116
141
  isColor('#444') // true
117
142
  // alias isCol, is.color, is.col
118
143
 
@@ -135,14 +160,39 @@ isError(new Error('')) // true
135
160
  // alias isErr, is.error, is.err
136
161
 
137
162
  isIterable([]) // true
138
- // alias is.iterable
163
+ // alias is.iterable, is.iter, isIter
139
164
 
140
165
  isEmail('a@b.c') // true
141
166
  // alias isMail, is.email, is.mail
142
167
 
168
+ isIP('192.168.1.1') // true
169
+ isIP('::1') // true
170
+ // alias ip, is.ip, isIp, isIP
171
+
143
172
  isIp('192.168.1.1') // true
144
173
  isIp('::1') // true
145
- // alias ip, is.ip, ipV4, ipV6, isIPv4, isIPv6
174
+ // alias ip, is.ip
175
+
176
+ isIp.v4('192.168.1.1') // true
177
+ isIp.v6('::1') // true
178
+
179
+ isIPv4('192.168.1.1') // true
180
+ // aliases ipV4, is.ipV4, is.ipv4, is.v4
181
+
182
+ isIPv6('::1') // true
183
+ // aliases ipV6, is.ipV6, is.ipv6, is.v6
184
+
185
+ isMap(new Map()) // true
186
+ // alias is.map, is.map, map
187
+
188
+ isSet(new Set()) // true
189
+ // alias is.set, is.set, set
190
+
191
+ isWeakMap(new WeakMap()) // true
192
+ // alias is.weakMap, is.weakMap, weakMap
193
+
194
+ isWeakSet(new WeakSet()) // true
195
+ // alias is.weakSet, is.weakSet, weakSet
146
196
 
147
197
  isNull(null) // true
148
198
  // alias isNil, is.nil, is.null
@@ -150,41 +200,49 @@ isNull(null) // true
150
200
  isUndefinedOrNull(undefined || null) // true
151
201
  // alias is.undefinedOrNull, is.undefinedOrNil, is.undefOrNull, is.undefOrNil
152
202
 
153
- isBuffer(new Buffer('test')) // true
203
+ isBuffer(Buffer.from('test')) // true
154
204
  // alias isBuff, is.buffer, is.buff
155
205
 
156
- isPromise(new Promise()) // true
206
+ isPromise(new Promise(r => r())) // true
157
207
  // alias is.promise, isThenable, isThen, is.thenable, is.then
158
208
 
159
- // removed (for now?)!
160
- isArguments(() => return arguments) // true
209
+ // (call with a function's arguments object)
210
+ (function () {
211
+ isArguments(arguments) // true
212
+ })()
161
213
  // alias isArgs, is.arguments, is.args
162
214
 
163
215
  isUUID(uuid) // true
164
216
  // alias is.uuid
165
217
 
166
- testType(42, 'number') // true
167
- // alias is.type
218
+ isType(42, 'number') // true
219
+ // alias is.type, is.testType, isType
168
220
 
169
- test(42, ['string', 'object']) // false
221
+ is.test(42, ['string', 'object']) // false
170
222
  // alias is.types
171
223
 
172
- isEq(42, 'number') // true
224
+ is.eq('abc', 'def') // true
173
225
  // alias is.eq
226
+ // is.eq compares lengths, see "length" section below
174
227
 
175
- isNot = isNeq = is.not(42, 'number') // true
228
+ isNot = isNeq = is.not(42, 'string') // true
176
229
  // alias is.neq
177
230
 
178
- isDeepEqual([1, 2, 3], [1, 2, 3]) // true
231
+ deep.isDeepEqual([1, 2, 3], [1, 2, 3]) // true
179
232
  // alias is.deep.eq, is.deep.equal
180
- isDeepDifferent([1, 2, 3], [1, 2, 3]) // false
233
+ // also deep.deepEqual, deep.deepEq, is.isDeepEqual
234
+ deep.isDeepDifferent([1, 2, 3], [1, 2, 3]) // false
181
235
  // alias is.deep.diff, is.deep.different
236
+ // also deep.deepDifferent, deep.deepDiff, is.isDeepDifferent
182
237
 
183
- isDeepEqual([1, 2, 3], [3, 2, 1]) // true
184
- isDeepEqual([1, 2, 3], [3, 2, 1], { strict: true }) // false
238
+ deep.isDifferent([1, 2, 3], [1, 2, 3]) // false
239
+ // alias is.deep.isDifferent, is.deep.different, is.deep.diff
185
240
 
186
- isDeepEqual({a: 1, b: 2, c: 3 }, { c: 3, b: 2, a: 1 }) // true
187
- isDeepEqual({a: 1, b: 2, c: 3 }, { c: 3, b: 2, a: 1 }, { strict: true }) // false
241
+ deep.isDeepEqual([1, 2, 3], [3, 2, 1]) // true
242
+ deep.isDeepEqual([1, 2, 3], [3, 2, 1], { strict: true }) // false
243
+
244
+ deep.isDeepEqual({a: 1, b: 2, c: 3 }, { c: 3, b: 2, a: 1 }) // true
245
+ deep.isDeepEqual({a: 1, b: 2, c: 3 }, { c: 3, b: 2, a: 1 }, { strict: true }) // false
188
246
 
189
247
  isEvery([1, 2, 3], 'number') // true
190
248
  isEvery([1, 2, 3], is.number) // true
@@ -194,7 +252,7 @@ isSome([1, 'str', {}], 'number') // true
194
252
  isSome([1, 'str', {}], is.number) // true
195
253
  // alias is.some
196
254
 
197
- isSymbol(Symbol('testing)) // true
255
+ isSymbol(Symbol('testing')) // true
198
256
  // alias is.symbol, is.sym
199
257
 
200
258
  isNone([1, 2, 3], 'string') // true
@@ -209,10 +267,10 @@ isCase('lowercase', 'low') // true
209
267
  // alias is.case
210
268
 
211
269
  isUpperCase('UPPERCASE') // true
212
- // alias is.case.upper, is.isCase.upper
270
+ // alias is.case.upper, isCase.upper
213
271
 
214
272
  isLowerCase('lowercase') // true
215
- // alias is.case.lower, is.isCase.lower
273
+ // alias is.case.lower, isCase.lower
216
274
 
217
275
  isMergeableObject({}) // true
218
276
  // alias is.mergeable, is.mergeableObject, isMergeable
@@ -221,9 +279,47 @@ const mod = await import('path/to/file')
221
279
  isModule(mod) // true
222
280
  // alias is.module
223
281
 
282
+ isComparable(1) // true
283
+ isComparable('str') // true
284
+ isComparable(true) // true
285
+ isComparable({}) // false
286
+ // aliases is.comparable, is.Comparable
287
+
224
288
  isOwnProp({ test: undefined }, 'test') // true
225
289
  // alias isOwnProperty, is.ownProperty, is.ownProp, is.prop
226
290
 
291
+ // length
292
+
293
+ // get the length of a string, array, map, set, regexp, or object
294
+ // numbers return themselves
295
+ getLength('test') // 4
296
+ getLength([1, 2, 3]) // 3
297
+ getLength(new Set([1, 2])) // 2
298
+ getLength(123) // 123
299
+ // aliases is.len, is.count, is.length, is.ln
300
+
301
+ // compare lengths, both arguments can be anything with a length
302
+ // these can also be curried: is.gt('abcd')('ab') // true
303
+ is.eq('abc', 'def') // true
304
+ is.gt('abcd', 'ab') // true
305
+ is.gte('abc', 'ab') // true
306
+ is.lt('ab', 'abc') // true
307
+ is.lte('abc', 'abc') // true
308
+ // aliases is.equal, is.greater, is.bigger, is.greaterequal, is.biggerequal,
309
+ // is.gteq, is.lower, is.smaller, is.lowerequal, is.smallerequal, is.lteq
310
+
311
+ isLengthEqual('abc', 3) // true
312
+ isLengthGreater('abc', 2) // true
313
+ isLengthGreaterOrEqual('ab', 2) // true
314
+ isLengthSmaller('ab', 3) // true
315
+ isLengthSmallerOrEqual('abc', 3) // true
316
+ // aliases is.isLengthEqual, is.isLengthGreater, is.isLengthGreaterOrEqual,
317
+ // is.isLengthSmaller, is.isLengthSmallerOrEqual
318
+
319
+ compareCount('abc', 3) // true
320
+
321
+ // the length functions also exist as methods on the length checks:
322
+ is.len.eq('abc', 'def') // true
227
323
  ```
228
324
 
229
325
  #### Changelog
@@ -416,6 +512,24 @@ update dependencies
416
512
  - add isIp and variants to allow ip v4 and v6 checks
417
513
  - update dependencies
418
514
 
419
- ##### 0.1.40 - unreleased
515
+ ##### 0.1.40
516
+
517
+ - add is.not negations of all type functions
518
+ - update docs
519
+ - update dependencies
520
+
521
+ ##### 0.1.41
522
+
523
+ - isArray accepts type predicates and narrows the element type: `isArray(arr, isString, isNumber)` → `e is (string | number)[]`, falling back to `unknown[]` without predicates
524
+ - change isArray return type from `unknown[]` to `any[]` in generated types
525
+ - add `scripts/add-node-reference.mjs` and run it after tsc in the build so `Buffer` resolves in the generated `.d.ts` files
526
+ - move `@types/node` from dependencies to devDependencies
527
+ - add `oxlint.config.ts` and lint fixes (curly braces, unused `@ts-expect-error` removals)
528
+ - use bundler module resolution in tsconfig, disable strict, add separate `tsconfig.test.json` for fixtures
529
+ - update dependencies (@magic/core, @magic/format, @magic/lint, @magic/test, @swc/core)
530
+ - update docs
531
+ - update dependencies
532
+
533
+ ##### 0.1.42 - unreleased
420
534
 
421
- ...
535
+ - ...
package/package.json CHANGED
@@ -1,13 +1,35 @@
1
1
  {
2
2
  "name": "@magic/types",
3
- "version": "0.1.39",
4
- "author": "Wizards & Witches",
3
+ "version": "0.1.41",
4
+ "description": "typechecking library",
5
+ "keywords": [
6
+ "magic",
7
+ "typechecking",
8
+ "types"
9
+ ],
5
10
  "homepage": "https://github.com/magic/types",
11
+ "bugs": {
12
+ "url": "https://github.com/magic/types/issues"
13
+ },
6
14
  "license": "AGPL-3.0",
7
- "description": "typechecking library",
15
+ "author": "Wizards & Witches",
16
+ "contributors": [
17
+ {
18
+ "name": "jascha ehrenreich",
19
+ "github": "jaeh"
20
+ }
21
+ ],
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git+https://github.com/magic/types.git"
25
+ },
26
+ "files": [
27
+ "src",
28
+ "types"
29
+ ],
30
+ "type": "module",
8
31
  "main": "src/index.js",
9
32
  "types": "./types/index.d.ts",
10
- "type": "module",
11
33
  "exports": {
12
34
  ".": {
13
35
  "import": "./src/index.js",
@@ -16,7 +38,7 @@
16
38
  },
17
39
  "scripts": {
18
40
  "start": "t",
19
- "build": "tsc && npm run format",
41
+ "build": "tsc && node scripts/add-node-reference.mjs && npm run format",
20
42
  "prepublishOnly": "npm run test && npm run build",
21
43
  "build:docs": "NODE_ENV=production magic build",
22
44
  "prod": "NODE_ENV=production magic build serve",
@@ -27,50 +49,30 @@
27
49
  "format": "f -w --exclude docs",
28
50
  "format:check": "f --exclude docs",
29
51
  "calls": "calls",
30
- "lint": "tsc --noEmit"
52
+ "tsc": "tsc --noEmit",
53
+ "tsc:test": "tsc --noEmit -p tsconfig.test.json",
54
+ "lint": "lint",
55
+ "check": "npm run tsc && npm run tsc:test && npm run lint"
31
56
  },
32
- "engines": {
33
- "node": ">=18"
34
- },
35
- "engineStrict": true,
36
- "repository": {
37
- "type": "git",
38
- "url": "git+https://github.com/magic/types.git"
39
- },
40
- "bugs": {
41
- "url": "https://github.com/magic/types/issues"
42
- },
43
- "files": [
44
- "src",
45
- "types"
46
- ],
47
57
  "devDependencies": {
48
58
  "@magic-modules/git-badges": "0.0.12",
49
59
  "@magic-modules/light-switch": "0.0.12",
50
60
  "@magic-modules/no-spy": "0.0.9",
51
61
  "@magic-modules/pre": "0.0.12",
52
62
  "@magic-themes/docs": "0.0.15",
53
- "@magic/core": "0.0.159",
54
- "@magic/format": "0.0.75",
55
- "@magic/test": "0.3.23",
56
- "typescript": "6.0.3"
63
+ "@magic/core": "0.0.161",
64
+ "@magic/format": "0.0.79",
65
+ "@magic/lint": "0.0.5",
66
+ "@magic/test": "0.3.55",
67
+ "@types/node": "26.6.6",
68
+ "typescript": "npm:@typescript/typescript6"
57
69
  },
58
- "keywords": [
59
- "magic",
60
- "types",
61
- "typechecking"
62
- ],
63
- "contributors": [
64
- {
65
- "name": "jascha ehrenreich",
66
- "github": "jaeh"
67
- }
68
- ],
69
- "dependencies": {
70
- "@types/node": "26.1.0"
70
+ "engines": {
71
+ "node": ">=18"
71
72
  },
73
+ "engineStrict": true,
72
74
  "allowScripts": {
73
- "@swc/core@1.3.41": true,
74
- "canvas@3.2.3": true
75
+ "canvas@3.2.3": true,
76
+ "@swc/core@1.15.47": true
75
77
  }
76
78
  }
package/src/deep/index.js CHANGED
@@ -11,10 +11,10 @@ export const deepDiff = different
11
11
 
12
12
  export const deep = {
13
13
  isDifferent: different,
14
- different: different,
14
+ different,
15
15
  diff: different,
16
16
 
17
17
  isEqual: equal,
18
- equal: equal,
18
+ equal,
19
19
  eq: equal,
20
20
  }
package/src/fns.js CHANGED
@@ -1,9 +1,21 @@
1
+ /// <reference types="node" />
1
2
  /**
2
3
  * Check if a value is an Array
3
- * @param {unknown} e - value to test
4
- * @returns {e is unknown[]} - true if value is an array
4
+ * @type {<P extends readonly ((e: unknown) => e is unknown)[]>(e: unknown, ...predicates: P) => e is P extends readonly [] ? unknown[] : (P[number] extends (e: unknown) => e is infer U ? U : never)[]}
5
5
  */
6
- export const isArray = e => Array.isArray(e)
6
+ export const isArray = (e, ...predicates) => {
7
+ if (!Array.isArray(e)) {
8
+ return false
9
+ }
10
+
11
+ // If no predicates provided, just check if it's an array
12
+ if (predicates.length === 0) {
13
+ return true
14
+ }
15
+
16
+ // Each element must pass at least one predicate
17
+ return e.every(element => predicates.some(predicate => predicate(element)))
18
+ }
7
19
 
8
20
  /**
9
21
  * Check if a value is a boolean
@@ -432,16 +444,26 @@ export const isArguments = e => Object.prototype.toString.call(e) === '[object A
432
444
  * @returns {boolean}
433
445
  */
434
446
  export const isUUID = e => {
435
- if (!isDefined(e)) return false
436
- if (!isString(e)) return false
447
+ if (!isDefined(e)) {
448
+ return false
449
+ }
450
+ if (!isString(e)) {
451
+ return false
452
+ }
437
453
 
438
454
  const split = e.split('-')
439
- if (!isLengthEqual(split, 5)) return false
455
+ if (!isLengthEqual(split, 5)) {
456
+ return false
457
+ }
440
458
 
441
459
  const lengths = [8, 4, 4, 4, 12]
442
- if (lengths.some((l, i) => split[i].length !== l)) return false
460
+ if (lengths.some((l, i) => split[i].length !== l)) {
461
+ return false
462
+ }
443
463
 
444
- if (Object.values(e).some(s => s > 'f')) return false
464
+ if (Object.values(e).some(s => s > 'f')) {
465
+ return false
466
+ }
445
467
 
446
468
  return true
447
469
  }
@@ -638,9 +660,13 @@ isCase.lower = isLowerCase
638
660
  * @returns {boolean} - true if value is an IPv4 address
639
661
  */
640
662
  export const isIPv4 = a => {
641
- if (!isString(a)) return false
663
+ if (!isString(a)) {
664
+ return false
665
+ }
642
666
  const parts = a.split('.')
643
- if (parts.length !== 4) return false
667
+ if (parts.length !== 4) {
668
+ return false
669
+ }
644
670
  return parts.every(part => {
645
671
  const num = Number(part)
646
672
  return /^(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])$/.test(part) && String(num) === part
package/src/index.js CHANGED
@@ -4,5 +4,6 @@ export * from './fns.js'
4
4
  export * as deep from './deep/index.js'
5
5
 
6
6
  export const is = def
7
+ export const not = is.not
7
8
 
8
9
  export default is
package/src/lib.js CHANGED
@@ -30,6 +30,16 @@ import * as deep from './deep/index.js'
30
30
  * }} EnhancedLengthFunction
31
31
  */
32
32
 
33
+ /**
34
+ * The `is.not` namespace: the original `isNot` check function, extended at
35
+ * runtime (by `addNotFunctions`) with a negated version of every `is.*` check
36
+ * and their nested sub-checks (e.g. `.upper`, `.eq`, `.v4`, `deep`). Each
37
+ * added property is either a negated check function or an object of them.
38
+ * @typedef {((e: unknown, ...types: string[]) => boolean) & {
39
+ * [key: string]: any
40
+ * }} NotNamespace
41
+ */
42
+
33
43
  // Create enhanced length functions with comparison methods
34
44
  const lengthFunctions = {
35
45
  eq: fns.isLengthEqual,
@@ -126,7 +136,7 @@ export const is = /** @type {const} */ {
126
136
  empty: fns.isEmpty,
127
137
 
128
138
  isNot: fns.isNot,
129
- not: fns.isNot,
139
+ not: /** @type {NotNamespace} */ (fns.isNot),
130
140
  isNeq: fns.isNot,
131
141
  neq: fns.isNot,
132
142
 
@@ -343,4 +353,100 @@ export const is = /** @type {const} */ {
343
353
  ...deep,
344
354
  }
345
355
 
356
+ /**
357
+ * Negation helper: creates a function that returns the logical NOT of fn
358
+ * @param {any} fn - function to negate
359
+ * @returns {(...args: any[]) => boolean} - negated function
360
+ */
361
+ const negate =
362
+ fn =>
363
+ (...args) =>
364
+ !fn(...args)
365
+
366
+ /**
367
+ * Add negated functions to the existing is.not namespace
368
+ * @param {any} obj - source object (the is namespace)
369
+ * @param {any} target - target object (the is.not namespace)
370
+ */
371
+ const addNotFunctions = (obj, target) => {
372
+ // Skip certain properties that shouldn't be copied
373
+ const skipKeys = new Set(['length', 'name', 'prototype', 'caller', 'callee', 'arguments'])
374
+
375
+ for (const [key, value] of Object.entries(obj)) {
376
+ if (key === 'not' || skipKeys.has(key)) {
377
+ continue
378
+ }
379
+ if (fns.isFunction(value)) {
380
+ target[key] = negate(value)
381
+ // Handle function sub-properties (e.g., isCase.upper, isIp.v4)
382
+ if (value.upper) {
383
+ target[key].upper = negate(value.upper)
384
+ }
385
+ if (value.lower) {
386
+ target[key].lower = negate(value.lower)
387
+ }
388
+ if (value.v4) {
389
+ target[key].v4 = negate(value.v4)
390
+ }
391
+ if (value.v6) {
392
+ target[key].v6 = negate(value.v6)
393
+ }
394
+ // Handle all length comparison functions
395
+ if (value.eq) {
396
+ target[key].eq = negate(value.eq)
397
+ }
398
+ if (value.equal) {
399
+ target[key].equal = negate(value.equal)
400
+ }
401
+ if (value.gt) {
402
+ target[key].gt = negate(value.gt)
403
+ }
404
+ if (value.bigger) {
405
+ target[key].bigger = negate(value.bigger)
406
+ }
407
+ if (value.biggerequal) {
408
+ target[key].biggerequal = negate(value.biggerequal)
409
+ }
410
+ if (value.greater) {
411
+ target[key].greater = negate(value.greater)
412
+ }
413
+ if (value.greaterequal) {
414
+ target[key].greaterequal = negate(value.greaterequal)
415
+ }
416
+ if (value.gte) {
417
+ target[key].gte = negate(value.gte)
418
+ }
419
+ if (value.gteq) {
420
+ target[key].gteq = negate(value.gteq)
421
+ }
422
+ if (value.lower) {
423
+ target[key].lower = negate(value.lower)
424
+ }
425
+ if (value.smaller) {
426
+ target[key].smaller = negate(value.smaller)
427
+ }
428
+ if (value.lt) {
429
+ target[key].lt = negate(value.lt)
430
+ }
431
+ if (value.lowerequal) {
432
+ target[key].lowerequal = negate(value.lowerequal)
433
+ }
434
+ if (value.smallerequal) {
435
+ target[key].smallerequal = negate(value.smallerequal)
436
+ }
437
+ if (value.lte) {
438
+ target[key].lte = negate(value.lte)
439
+ }
440
+ if (value.lteq) {
441
+ target[key].lteq = negate(value.lteq)
442
+ }
443
+ } else if (fns.isObjectNative(value)) {
444
+ target[key] = {}
445
+ addNotFunctions(value, target[key])
446
+ }
447
+ }
448
+ }
449
+
450
+ addNotFunctions(is, is.not)
451
+
346
452
  export default is
package/types/fns.d.ts CHANGED
@@ -1,4 +1,14 @@
1
- export function isArray(e: unknown): e is unknown[]
1
+ /// <reference types="node" />
2
+ /**
3
+ * Check if a value is an Array
4
+ * @type {<P extends readonly ((e: unknown) => e is unknown)[]>(e: unknown, ...predicates: P) => e is P extends readonly [] ? unknown[] : (P[number] extends (e: unknown) => e is infer U ? U : never)[]}
5
+ */
6
+ export const isArray: <P extends readonly ((e: unknown) => e is unknown)[]>(
7
+ e: unknown,
8
+ ...predicates: P
9
+ ) => e is P extends readonly []
10
+ ? unknown[]
11
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
2
12
  export function isBoolean(e: unknown): e is boolean
3
13
  export function isDefined(e: unknown): e is NonNullable<unknown>
4
14
  export function isUndefined(e: unknown): e is undefined
package/types/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  export * from './fns.js'
2
3
  export * as deep from './deep/index.js'
3
4
  export const is: {
@@ -234,13 +235,33 @@ export const is: {
234
235
  isEmpty: (e: unknown) => boolean
235
236
  empty: (e: unknown) => boolean
236
237
  isNot: (e: unknown, ...types: string[]) => boolean
237
- not: (e: unknown, ...types: string[]) => boolean
238
+ not: import('./lib.js').NotNamespace
238
239
  isNeq: (e: unknown, ...types: string[]) => boolean
239
240
  neq: (e: unknown, ...types: string[]) => boolean
240
- isArray: (e: unknown) => e is unknown[]
241
- isArr: (e: unknown) => e is unknown[]
242
- array: (e: unknown) => e is unknown[]
243
- arr: (e: unknown) => e is unknown[]
241
+ isArray: <P extends readonly ((e: unknown) => e is unknown)[]>(
242
+ e: unknown,
243
+ ...predicates: P
244
+ ) => e is P extends readonly []
245
+ ? unknown[]
246
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
247
+ isArr: <P extends readonly ((e: unknown) => e is unknown)[]>(
248
+ e: unknown,
249
+ ...predicates: P
250
+ ) => e is P extends readonly []
251
+ ? unknown[]
252
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
253
+ array: <P extends readonly ((e: unknown) => e is unknown)[]>(
254
+ e: unknown,
255
+ ...predicates: P
256
+ ) => e is P extends readonly []
257
+ ? unknown[]
258
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
259
+ arr: <P extends readonly ((e: unknown) => e is unknown)[]>(
260
+ e: unknown,
261
+ ...predicates: P
262
+ ) => e is P extends readonly []
263
+ ? unknown[]
264
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
244
265
  isBoolean: (e: unknown) => e is boolean
245
266
  isBool: (e: unknown) => e is boolean
246
267
  boolean: (e: unknown) => e is boolean
@@ -769,4 +790,5 @@ export const is: {
769
790
  (a: unknown): (c: unknown) => boolean
770
791
  }
771
792
  }
793
+ export const not: import('./lib.js').NotNamespace
772
794
  export default is
package/types/lib.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference types="node" />
1
2
  export const is: {
2
3
  isDeepEqual: {
3
4
  /**
@@ -232,13 +233,33 @@ export const is: {
232
233
  isEmpty: (e: unknown) => boolean
233
234
  empty: (e: unknown) => boolean
234
235
  isNot: (e: unknown, ...types: string[]) => boolean
235
- not: (e: unknown, ...types: string[]) => boolean
236
+ not: NotNamespace
236
237
  isNeq: (e: unknown, ...types: string[]) => boolean
237
238
  neq: (e: unknown, ...types: string[]) => boolean
238
- isArray: (e: unknown) => e is unknown[]
239
- isArr: (e: unknown) => e is unknown[]
240
- array: (e: unknown) => e is unknown[]
241
- arr: (e: unknown) => e is unknown[]
239
+ isArray: <P extends readonly ((e: unknown) => e is unknown)[]>(
240
+ e: unknown,
241
+ ...predicates: P
242
+ ) => e is P extends readonly []
243
+ ? unknown[]
244
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
245
+ isArr: <P extends readonly ((e: unknown) => e is unknown)[]>(
246
+ e: unknown,
247
+ ...predicates: P
248
+ ) => e is P extends readonly []
249
+ ? unknown[]
250
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
251
+ array: <P extends readonly ((e: unknown) => e is unknown)[]>(
252
+ e: unknown,
253
+ ...predicates: P
254
+ ) => e is P extends readonly []
255
+ ? unknown[]
256
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
257
+ arr: <P extends readonly ((e: unknown) => e is unknown)[]>(
258
+ e: unknown,
259
+ ...predicates: P
260
+ ) => e is P extends readonly []
261
+ ? unknown[]
262
+ : (P[number] extends ((e: unknown) => e is infer U) ? U : never)[]
242
263
  isBoolean: (e: unknown) => e is boolean
243
264
  isBool: (e: unknown) => e is boolean
244
265
  boolean: (e: unknown) => e is boolean
@@ -787,4 +808,13 @@ export type EnhancedLengthFunction = typeof fns.getLength & {
787
808
  lte: LengthComparison
788
809
  lteq: LengthComparison
789
810
  }
811
+ /**
812
+ * The `is.not` namespace: the original `isNot` check function, extended at
813
+ * runtime (by `addNotFunctions`) with a negated version of every `is.*` check
814
+ * and their nested sub-checks (e.g. `.upper`, `.eq`, `.v4`, `deep`). Each
815
+ * added property is either a negated check function or an object of them.
816
+ */
817
+ export type NotNamespace = ((e: unknown, ...types: string[]) => boolean) & {
818
+ [key: string]: any
819
+ }
790
820
  import * as fns from './fns.js'