is-kit 1.6.1 → 1.6.3
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 +270 -173
- package/dist/index.js +28 -20
- package/dist/index.mjs +28 -20
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,260 +1,295 @@
|
|
|
1
1
|
# is-kit
|
|
2
2
|
|
|
3
3
|
<p align="center">
|
|
4
|
-
|
|
4
|
+
<img
|
|
5
|
+
src="https://raw.githubusercontent.com/nyaomaru/is-kit/main/docs/public/iskit_image.png"
|
|
6
|
+
width="600"
|
|
7
|
+
alt="is-kit logo"
|
|
8
|
+
/>
|
|
5
9
|
</p>
|
|
6
10
|
|
|
7
11
|
<p align="center">
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
<a href="https://www.npmjs.com/package/is-kit">
|
|
13
|
+
<img src="https://img.shields.io/npm/v/is-kit.svg" alt="npm version">
|
|
14
|
+
</a>
|
|
15
|
+
<a href="https://jsr.io/@nyaomaru/is-kit">
|
|
16
|
+
<img src="https://img.shields.io/jsr/v/@nyaomaru/is-kit" alt="JSR">
|
|
17
|
+
</a>
|
|
18
|
+
<a href="https://www.npmjs.com/package/is-kit">
|
|
19
|
+
<img src="https://img.shields.io/npm/dt/is-kit.svg" alt="npm downloads">
|
|
20
|
+
</a>
|
|
21
|
+
<a href="https://github.com/nyaomaru/is-kit/blob/main/LICENSE">
|
|
22
|
+
<img src="https://img.shields.io/npm/l/is-kit.svg?sanitize=true" alt="License">
|
|
23
|
+
</a>
|
|
20
24
|
</p>
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
Runtime-safe 🛡️, composable 🧩, and ergonomic ✨.
|
|
26
|
+
`is-kit` is a lightweight, zero-dependency toolkit for building reusable TypeScript **type guards**.
|
|
24
27
|
|
|
25
|
-
|
|
28
|
+
It helps you write small `isFoo` functions, compose them into **richer runtime checks**, and keep **TypeScript narrowing** natural inside regular control flow.
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
**Runtime-safe** 🛡️, **composable** 🧩, and **ergonomic** ✨ without asking you to adopt a heavy schema workflow.
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
- Build and reuse **typed guards**
|
|
33
|
+
- **Compose guards** with `and`, `or`, `not`, `oneOf`
|
|
34
|
+
- **Validate object** shapes and collections
|
|
35
|
+
- **Parse or assert** `unknown` values without a large schema framework
|
|
31
36
|
|
|
32
|
-
|
|
33
|
-
- Type-safe
|
|
34
|
-
- Composable
|
|
35
|
-
- Zero-dependency
|
|
37
|
+
[📚 Documentation Site](https://is-kit-docs.vercel.app/)
|
|
36
38
|
|
|
37
|
-
>
|
|
39
|
+
> Best for **app-internal narrowing, filtering, and reusable guards**.
|
|
38
40
|
|
|
39
|
-
##
|
|
41
|
+
## 🤔 Why use `is-kit`?
|
|
40
42
|
|
|
41
|
-
|
|
43
|
+
Tired of rewriting the same `isFoo` checks again and again?
|
|
44
|
+
|
|
45
|
+
`is-kit` is a good fit when you want to:
|
|
46
|
+
|
|
47
|
+
- **write reusable `isX`** functions instead of one-off inline checks
|
|
48
|
+
- keep runtime validation **lightweight and dependency-free**
|
|
49
|
+
- **narrow values directly** in `if`, `filter`, and other TypeScript control flow
|
|
50
|
+
- **compose validation logic** from small guards instead of large schema objects
|
|
51
|
+
|
|
52
|
+
`is-kit` is probably not the best first choice if you mainly want:
|
|
53
|
+
|
|
54
|
+
- rich, structured validation errors
|
|
55
|
+
- schema-first workflows
|
|
56
|
+
- data transformation pipelines
|
|
57
|
+
|
|
58
|
+
In those cases, a schema validator such as `Zod` may be a better fit. (Of course, you can combine them 🍲)
|
|
59
|
+
|
|
60
|
+
`is-kit` is meant to take the boring part out of writing guards, while still feeling like normal TypeScript.
|
|
61
|
+
|
|
62
|
+
> Grab a coffee ☕ and let `is-kit` handle the repetitive part.
|
|
63
|
+
|
|
64
|
+
## 📥 Install
|
|
42
65
|
|
|
43
66
|
```bash
|
|
44
67
|
pnpm add is-kit
|
|
45
68
|
# or
|
|
46
69
|
bun add is-kit
|
|
47
70
|
# or
|
|
48
|
-
npm
|
|
71
|
+
npm install is-kit
|
|
49
72
|
# or
|
|
50
73
|
yarn add is-kit
|
|
51
74
|
```
|
|
52
75
|
|
|
53
|
-
ESM and CJS builds are
|
|
76
|
+
ESM and CJS builds are available for npm consumers, and bundled types are included.
|
|
54
77
|
|
|
55
|
-
### JSR
|
|
78
|
+
### JSR
|
|
56
79
|
|
|
57
80
|
```ts
|
|
58
|
-
|
|
59
|
-
import { define, and, or } from 'jsr:@nyaomaru/is-kit';
|
|
81
|
+
import { and, define, or } from 'jsr:@nyaomaru/is-kit';
|
|
60
82
|
```
|
|
61
83
|
|
|
62
|
-
## Quick
|
|
84
|
+
## ✨ Quick Start
|
|
63
85
|
|
|
64
|
-
|
|
86
|
+
Start with a plain object guard and parse an `unknown` value.
|
|
65
87
|
|
|
66
88
|
```ts
|
|
67
|
-
import {
|
|
68
|
-
define,
|
|
69
|
-
and,
|
|
70
|
-
or,
|
|
71
|
-
not,
|
|
72
|
-
mapOf,
|
|
73
|
-
optionalKey,
|
|
74
|
-
setOf,
|
|
75
|
-
struct,
|
|
76
|
-
oneOfValues,
|
|
77
|
-
isNumber,
|
|
78
|
-
isString,
|
|
79
|
-
predicateToRefine
|
|
80
|
-
} from 'is-kit';
|
|
89
|
+
import { isNumber, isString, optionalKey, safeParse, struct } from 'is-kit';
|
|
81
90
|
|
|
82
|
-
|
|
83
|
-
const isShortString = define<string>((v) => isString(v) && v.length <= 3);
|
|
84
|
-
const isPositive = and(
|
|
85
|
-
isNumber,
|
|
86
|
-
predicateToRefine<number>((v) => v > 0)
|
|
87
|
-
);
|
|
91
|
+
declare const input: unknown;
|
|
88
92
|
|
|
89
|
-
// Combine them (or / not)
|
|
90
|
-
const isShortOrPositive = or(isShortString, isPositive);
|
|
91
|
-
const isOther = not(isShortOrPositive);
|
|
92
|
-
|
|
93
|
-
// Define object shapes
|
|
94
|
-
const isRole = oneOfValues(['admin', 'member'] as const);
|
|
95
|
-
const isTags = setOf(isString);
|
|
96
|
-
const isScores = mapOf(isString, isNumber);
|
|
97
93
|
const isUser = struct({
|
|
98
|
-
id:
|
|
99
|
-
name: isString,
|
|
100
|
-
|
|
101
|
-
nickname: optionalKey(isShortString) // key may be absent; when present, string <= 3
|
|
94
|
+
id: isNumber,
|
|
95
|
+
name: isString,
|
|
96
|
+
nickname: optionalKey(isString)
|
|
102
97
|
});
|
|
103
98
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
isScores(new Map([['math', 98]])); // true
|
|
111
|
-
|
|
112
|
-
const maybeUser: unknown = { id: 7, name: 'Rin', role: 'admin' };
|
|
113
|
-
if (isUser(maybeUser)) {
|
|
114
|
-
// The type is narrowed inside this block
|
|
115
|
-
maybeUser.role; // 'admin' | 'member'
|
|
116
|
-
maybeUser.nickname?.toUpperCase();
|
|
99
|
+
const result = safeParse(isUser, input);
|
|
100
|
+
|
|
101
|
+
if (result.valid) {
|
|
102
|
+
result.value.id;
|
|
103
|
+
result.value.name;
|
|
104
|
+
result.value.nickname?.toUpperCase();
|
|
117
105
|
}
|
|
118
106
|
```
|
|
119
107
|
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
108
|
+
This is the core idea of `is-kit`:
|
|
109
|
+
|
|
110
|
+
1. Build small guards.
|
|
111
|
+
2. Compose them.
|
|
112
|
+
3. Reuse them anywhere TypeScript narrowing matters.
|
|
113
|
+
|
|
114
|
+
## ⌚ A 30-second Mental Model
|
|
115
|
+
|
|
116
|
+
If you are new to the library, these are the pieces to remember:
|
|
117
|
+
|
|
118
|
+
- `define<T>(fn)` turns a boolean check into a typed guard.
|
|
119
|
+
- `predicateToRefine(fn)` upgrades an existing predicate so it can participate in narrowing chains.
|
|
120
|
+
- `struct({...})` builds an object-shape guard.
|
|
121
|
+
- `safeParse(guard, value)` gives you a small tagged result object.
|
|
122
|
+
- `assert(guard, value)` throws if the value does not match.
|
|
123
|
+
|
|
124
|
+
## ⚒️ Common Usage
|
|
125
|
+
|
|
126
|
+
### 1. Create a custom guard
|
|
127
|
+
|
|
128
|
+
Use `define` when you already know the runtime condition you want.
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
import { define, isString } from 'is-kit';
|
|
132
|
+
|
|
133
|
+
const isShortString = define<string>(
|
|
134
|
+
(value) => isString(value) && value.length <= 3
|
|
135
|
+
);
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
### 2. Add refinements to an existing guard
|
|
139
|
+
|
|
140
|
+
Use `and` plus `predicateToRefine` when you want a broad guard first and a narrower condition after that.
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { and, isNumber, predicateToRefine } from 'is-kit';
|
|
144
|
+
|
|
145
|
+
const isPositiveNumber = and(
|
|
146
|
+
isNumber,
|
|
147
|
+
predicateToRefine<number>((value) => value > 0)
|
|
148
|
+
);
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### 3. Compose multiple guards
|
|
152
|
+
|
|
153
|
+
Use `or` and `oneOf` to combine smaller guards into readable predicates.
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
import { oneOf, or, isBoolean, isNumber, isString } from 'is-kit';
|
|
157
|
+
|
|
158
|
+
const isStringOrNumber = or(isString, isNumber);
|
|
159
|
+
const isScalar = oneOf(isString, isNumber, isBoolean);
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Use `not(...)` when you want the complement of an existing guard or refinement.
|
|
163
|
+
|
|
164
|
+
### 4. Validate object shapes
|
|
165
|
+
|
|
166
|
+
Use `struct` for plain-object payloads. Keys are required by default.
|
|
167
|
+
|
|
168
|
+
```ts
|
|
169
|
+
import { isNumber, isString, optionalKey, struct } from 'is-kit';
|
|
170
|
+
|
|
171
|
+
const isProfile = struct(
|
|
172
|
+
{
|
|
173
|
+
id: isNumber,
|
|
174
|
+
name: isString,
|
|
175
|
+
bio: optionalKey(isString)
|
|
176
|
+
},
|
|
177
|
+
{ exact: true }
|
|
178
|
+
);
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
`optionalKey(guard)` means the property may be missing.
|
|
123
182
|
|
|
124
|
-
|
|
125
|
-
`isPositive` can be used standalone or as part of a `struct` definition.
|
|
183
|
+
If the property must exist but the value may be `undefined`, use `optional(guard)` instead.
|
|
126
184
|
|
|
127
|
-
|
|
128
|
-
|
|
185
|
+
```ts
|
|
186
|
+
import { isString, optional, optionalKey, struct } from 'is-kit';
|
|
129
187
|
|
|
130
|
-
|
|
188
|
+
const isConfig = struct({
|
|
189
|
+
label: isString,
|
|
190
|
+
subtitle: optional(isString),
|
|
191
|
+
note: optionalKey(optional(isString))
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 5. Validate arrays, tuples, maps, sets, and records
|
|
131
196
|
|
|
132
|
-
|
|
133
|
-
collections while preserving precise readonly types.
|
|
197
|
+
Collection combinators keep your element guards reusable.
|
|
134
198
|
|
|
135
199
|
```ts
|
|
136
200
|
import {
|
|
137
201
|
arrayOf,
|
|
202
|
+
isNumber,
|
|
203
|
+
isString,
|
|
138
204
|
mapOf,
|
|
139
205
|
recordOf,
|
|
140
206
|
setOf,
|
|
141
|
-
|
|
142
|
-
isString
|
|
207
|
+
tupleOf
|
|
143
208
|
} from 'is-kit';
|
|
144
209
|
|
|
145
210
|
const isStringArray = arrayOf(isString);
|
|
146
|
-
const
|
|
211
|
+
const isPoint = tupleOf(isNumber, isNumber);
|
|
212
|
+
const isTagSet = setOf(isString);
|
|
147
213
|
const isScoreMap = mapOf(isString, isNumber);
|
|
148
214
|
const isStringRecord = recordOf(isString, isString);
|
|
149
|
-
|
|
150
|
-
isStringArray(['a', 'b']); // true
|
|
151
|
-
isStringSet(new Set(['a', 'b'])); // true
|
|
152
|
-
isScoreMap(new Map([['math', 98]])); // true
|
|
153
|
-
isStringRecord({ a: 'x', b: 'y' }); // true
|
|
154
215
|
```
|
|
155
216
|
|
|
156
|
-
|
|
217
|
+
Use `oneOfValues` for unions of literal primitives.
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
import { oneOfValues } from 'is-kit';
|
|
221
|
+
|
|
222
|
+
const isStatus = oneOfValues('draft', 'published', 'archived');
|
|
223
|
+
```
|
|
157
224
|
|
|
158
|
-
|
|
225
|
+
### 6. Handle null and undefined explicitly
|
|
159
226
|
|
|
160
|
-
|
|
227
|
+
Use the nullish helpers to say exactly what is allowed.
|
|
161
228
|
|
|
162
229
|
```ts
|
|
163
230
|
import {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
isZero,
|
|
171
|
-
isNaN,
|
|
172
|
-
isInfiniteNumber
|
|
231
|
+
isString,
|
|
232
|
+
nonNull,
|
|
233
|
+
nullable,
|
|
234
|
+
nullish,
|
|
235
|
+
optional,
|
|
236
|
+
required
|
|
173
237
|
} from 'is-kit';
|
|
174
238
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
// Numeric helpers
|
|
182
|
-
isNumber(10); // true
|
|
183
|
-
isInteger(42); // true
|
|
184
|
-
isSafeInteger(2 ** 53); // false
|
|
185
|
-
isPositive(3); // true
|
|
186
|
-
isPositive(0); // false
|
|
187
|
-
isNegative(-3); // true
|
|
188
|
-
isNegative(-0); // false
|
|
189
|
-
isZero(0); // true
|
|
190
|
-
isZero(1); // false
|
|
191
|
-
isNaN(NaN); // true
|
|
192
|
-
isNaN(0); // false
|
|
193
|
-
isInfiniteNumber(Infinity); // true
|
|
194
|
-
isInfiniteNumber(1); // false
|
|
239
|
+
const isNullableString = nullable(isString);
|
|
240
|
+
const isNullishString = nullish(isString);
|
|
241
|
+
const isOptionalString = optional(isString);
|
|
242
|
+
const isDefinedString = required(optional(isString));
|
|
243
|
+
const isNonNullString = nonNull(nullable(isString));
|
|
195
244
|
```
|
|
196
245
|
|
|
197
|
-
###
|
|
246
|
+
### 7. Parse or assert unknown input
|
|
198
247
|
|
|
199
|
-
|
|
200
|
-
`isInstanceOf` when you want a reusable guard from a class constructor.
|
|
201
|
-
For content-aware map/set validation, pair `isMap` / `isSet` with `mapOf`
|
|
202
|
-
and `setOf`.
|
|
248
|
+
Use `safeParse` when you want a result object, and `assert` when invalid data should stop execution.
|
|
203
249
|
|
|
204
250
|
```ts
|
|
205
|
-
import {
|
|
251
|
+
import { assert, isString, safeParse } from 'is-kit';
|
|
206
252
|
|
|
207
|
-
|
|
208
|
-
class Dog extends Animal {}
|
|
253
|
+
declare const input: unknown;
|
|
209
254
|
|
|
210
|
-
const
|
|
255
|
+
const parsed = safeParse(isString, input);
|
|
211
256
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
isAnimal({}); // false
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Core Ideas
|
|
257
|
+
if (parsed.valid) {
|
|
258
|
+
parsed.value.toUpperCase();
|
|
259
|
+
}
|
|
219
260
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
- **Stay ergonomic**: helpers like `nullable`, `optional`, `equals`, `safeParse`, `assert`, `hasKey`, `hasKeys`, `narrowKeyTo`.
|
|
261
|
+
assert(isString, input, 'Expected a string');
|
|
262
|
+
input.toUpperCase();
|
|
263
|
+
```
|
|
224
264
|
|
|
225
|
-
###
|
|
265
|
+
### 8. Narrow object keys
|
|
226
266
|
|
|
227
|
-
Use
|
|
228
|
-
`narrowKeyTo` when you need to narrow a property to a specific literal value.
|
|
267
|
+
Use key helpers when the important part of a value is one property.
|
|
229
268
|
|
|
230
269
|
```ts
|
|
231
270
|
import {
|
|
232
271
|
hasKey,
|
|
233
272
|
hasKeys,
|
|
234
|
-
isString,
|
|
235
273
|
isNumber,
|
|
274
|
+
isString,
|
|
236
275
|
narrowKeyTo,
|
|
237
276
|
oneOfValues,
|
|
238
|
-
or,
|
|
239
277
|
struct
|
|
240
278
|
} from 'is-kit';
|
|
241
279
|
|
|
242
|
-
// Base guard (e.g., via struct)
|
|
243
|
-
type User = { id: string; age: number; role: 'admin' | 'guest' | 'trial' };
|
|
244
280
|
const isUser = struct({
|
|
245
|
-
id:
|
|
246
|
-
|
|
247
|
-
role: oneOfValues('admin', '
|
|
281
|
+
id: isNumber,
|
|
282
|
+
name: isString,
|
|
283
|
+
role: oneOfValues('admin', 'member', 'guest')
|
|
248
284
|
});
|
|
249
285
|
|
|
250
286
|
const hasRole = hasKey('role');
|
|
251
287
|
const hasRoleAndId = hasKeys('role', 'id');
|
|
252
288
|
const byRole = narrowKeyTo(isUser, 'role');
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
const
|
|
289
|
+
const isAdmin = byRole('admin');
|
|
290
|
+
|
|
291
|
+
const value: unknown = { id: 1, name: 'nyaomaru', role: 'admin' };
|
|
256
292
|
|
|
257
|
-
declare const value: unknown;
|
|
258
293
|
if (hasRole(value)) {
|
|
259
294
|
value.role;
|
|
260
295
|
}
|
|
@@ -264,23 +299,85 @@ if (hasRoleAndId(value)) {
|
|
|
264
299
|
value.id;
|
|
265
300
|
}
|
|
266
301
|
|
|
267
|
-
if (
|
|
268
|
-
|
|
302
|
+
if (isAdmin(value)) {
|
|
303
|
+
value.role;
|
|
304
|
+
value.name;
|
|
269
305
|
}
|
|
270
306
|
```
|
|
271
307
|
|
|
272
|
-
##
|
|
308
|
+
## 🌍 Real-world use cases
|
|
309
|
+
|
|
310
|
+
Here are the kinds of problems `is-kit` is especially good at solving:
|
|
311
|
+
|
|
312
|
+
### API response checks
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
import { isNumber, isString, safeParse, struct } from 'is-kit';
|
|
316
|
+
|
|
317
|
+
const isPost = struct({
|
|
318
|
+
id: isNumber,
|
|
319
|
+
title: isString
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
const parsed = safeParse(isPost, payload);
|
|
323
|
+
if (parsed.valid) {
|
|
324
|
+
renderPost(parsed.value);
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
### Safe array filtering
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
import { isNumber } from 'is-kit';
|
|
332
|
+
|
|
333
|
+
const values: unknown[] = [1, 'two', 3];
|
|
334
|
+
const numbers = values.filter(isNumber);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
### Narrowing by discriminant
|
|
338
|
+
|
|
339
|
+
```ts
|
|
340
|
+
import { isNumber, isString, narrowKeyTo, oneOfValues, struct } from 'is-kit';
|
|
341
|
+
|
|
342
|
+
const isEvent = struct({
|
|
343
|
+
type: oneOfValues('click', 'submit'),
|
|
344
|
+
label: isString,
|
|
345
|
+
timestamp: isNumber
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
const byType = narrowKeyTo(isEvent, 'type');
|
|
349
|
+
const isSubmitEvent = byType('submit');
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## 🎯 API Overview
|
|
353
|
+
|
|
354
|
+
The library is organized around a few small building blocks:
|
|
355
|
+
|
|
356
|
+
- **Primitives**: `isString`, `isNumber`, `isBoolean`, `isInteger`, ...
|
|
357
|
+
- **Composition**: `define`, `and`, `andAll`, `or`, `not`, `oneOf`
|
|
358
|
+
- **Object shapes**: `struct`, `optionalKey`, `hasKey`, `hasKeys`, `narrowKeyTo`
|
|
359
|
+
- **Collections**: `arrayOf`, `tupleOf`, `setOf`, `mapOf`, `recordOf`
|
|
360
|
+
- **Literals**: `oneOfValues`, `equals`, `equalsBy`, `equalsKey`
|
|
361
|
+
- **Nullish handling**: `nullable`, `nonNull`, `nullish`, `optional`, `required`
|
|
362
|
+
- **Result helpers**: `safeParse`, `safeParseWith`, `assert`
|
|
363
|
+
|
|
364
|
+
For the full API list and dedicated pages, use the docs site below.
|
|
365
|
+
|
|
366
|
+
## 📚 Full Documentation
|
|
367
|
+
|
|
368
|
+
For detailed API pages and more examples, see:
|
|
273
369
|
|
|
274
|
-
|
|
370
|
+
https://is-kit-docs.vercel.app/
|
|
275
371
|
|
|
276
|
-
|
|
372
|
+
## 👨💻 Development
|
|
277
373
|
|
|
278
|
-
|
|
374
|
+
Requires Node 22 and pnpm 10.12.4.
|
|
279
375
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
376
|
+
- `pnpm lint`
|
|
377
|
+
- `pnpm build`
|
|
378
|
+
- `pnpm test`
|
|
379
|
+
- `pnpm test:types`
|
|
283
380
|
|
|
284
|
-
|
|
381
|
+
See `DEVELOPER.md` for setup details and `CONTRIBUTE.md` for contribution workflow.
|
|
285
382
|
|
|
286
|
-
|
|
383
|
+
Pick a guard, compose it, and ship with confidence 🚀
|
package/dist/index.js
CHANGED
|
@@ -161,8 +161,20 @@ function required(fn) {
|
|
|
161
161
|
return (value) => value !== void 0 && fn(value);
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
// src/utils/object-tags.ts
|
|
165
|
+
var objectToString = Object.prototype.toString;
|
|
166
|
+
var OBJECT_TAG_DATE = "[object Date]";
|
|
167
|
+
var OBJECT_TAG_REGEXP = "[object RegExp]";
|
|
168
|
+
var OBJECT_TAG_MAP = "[object Map]";
|
|
169
|
+
var OBJECT_TAG_SET = "[object Set]";
|
|
170
|
+
var OBJECT_TAG_WEAK_MAP = "[object WeakMap]";
|
|
171
|
+
var OBJECT_TAG_WEAK_SET = "[object WeakSet]";
|
|
172
|
+
var OBJECT_TAG_ARRAY_BUFFER = "[object ArrayBuffer]";
|
|
173
|
+
var OBJECT_TAG_DATA_VIEW = "[object DataView]";
|
|
174
|
+
var OBJECT_TAG_ERROR = "[object Error]";
|
|
175
|
+
var getTag = (value) => objectToString.call(value);
|
|
176
|
+
|
|
164
177
|
// src/core/object.ts
|
|
165
|
-
var getTag = (value) => Object.prototype.toString.call(value);
|
|
166
178
|
var isFunction = define(
|
|
167
179
|
(value) => typeof value === "function"
|
|
168
180
|
);
|
|
@@ -176,46 +188,46 @@ var isPlainObject = define((value) => {
|
|
|
176
188
|
});
|
|
177
189
|
var isArray = define(Array.isArray);
|
|
178
190
|
var isDate = define(
|
|
179
|
-
(value) => getTag(value) ===
|
|
191
|
+
(value) => getTag(value) === OBJECT_TAG_DATE && !Number.isNaN(value.getTime())
|
|
180
192
|
);
|
|
181
193
|
var isRegExp = define(
|
|
182
|
-
(value) => getTag(value) ===
|
|
194
|
+
(value) => getTag(value) === OBJECT_TAG_REGEXP
|
|
183
195
|
);
|
|
184
196
|
var isMap = define(
|
|
185
|
-
(value) => getTag(value) ===
|
|
197
|
+
(value) => getTag(value) === OBJECT_TAG_MAP
|
|
186
198
|
);
|
|
187
199
|
var isSet = define(
|
|
188
|
-
(value) => getTag(value) ===
|
|
200
|
+
(value) => getTag(value) === OBJECT_TAG_SET
|
|
189
201
|
);
|
|
190
202
|
var isWeakMap = define(
|
|
191
|
-
(value) => getTag(value) ===
|
|
203
|
+
(value) => getTag(value) === OBJECT_TAG_WEAK_MAP
|
|
192
204
|
);
|
|
193
205
|
var isWeakSet = define(
|
|
194
|
-
(value) => getTag(value) ===
|
|
206
|
+
(value) => getTag(value) === OBJECT_TAG_WEAK_SET
|
|
195
207
|
);
|
|
196
208
|
var isPromiseLike = define((value) => {
|
|
197
209
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
198
|
-
return
|
|
210
|
+
return isFunction(value.then);
|
|
199
211
|
});
|
|
200
212
|
var isIterable = define((value) => {
|
|
201
213
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
202
|
-
return
|
|
214
|
+
return isFunction(value[Symbol.iterator]);
|
|
203
215
|
});
|
|
204
216
|
var isAsyncIterable = define((value) => {
|
|
205
217
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
206
|
-
return
|
|
218
|
+
return isFunction(value[Symbol.asyncIterator]);
|
|
207
219
|
});
|
|
208
220
|
var isArrayBuffer = define(
|
|
209
|
-
(value) => getTag(value) ===
|
|
221
|
+
(value) => getTag(value) === OBJECT_TAG_ARRAY_BUFFER
|
|
210
222
|
);
|
|
211
223
|
var isDataView = define(
|
|
212
|
-
(value) => getTag(value) ===
|
|
224
|
+
(value) => getTag(value) === OBJECT_TAG_DATA_VIEW
|
|
213
225
|
);
|
|
214
226
|
var isTypedArray = define(
|
|
215
|
-
(value) => ArrayBuffer.isView(value) && getTag(value) !==
|
|
227
|
+
(value) => ArrayBuffer.isView(value) && getTag(value) !== OBJECT_TAG_DATA_VIEW
|
|
216
228
|
);
|
|
217
229
|
var isError = define(
|
|
218
|
-
(value) => value instanceof Error || getTag(value) ===
|
|
230
|
+
(value) => value instanceof Error || getTag(value) === OBJECT_TAG_ERROR
|
|
219
231
|
);
|
|
220
232
|
var isURL = typeof URL !== "undefined" ? define((value) => value instanceof URL) : define(() => false);
|
|
221
233
|
var isBlob = typeof Blob !== "undefined" ? define((value) => value instanceof Blob) : define(() => false);
|
|
@@ -406,10 +418,6 @@ var ONE_OF_VALUES_LINEAR_SCAN_MAX = 8;
|
|
|
406
418
|
var isSingleArrayArg = define(
|
|
407
419
|
(value) => Array.isArray(value) && value.length === 1 && Array.isArray(value[0])
|
|
408
420
|
);
|
|
409
|
-
var isZeroNumber = and(
|
|
410
|
-
isNumber,
|
|
411
|
-
predicateToRefine((value) => value === 0)
|
|
412
|
-
);
|
|
413
421
|
var normalizeValues = (args) => isSingleArrayArg(args) ? args[0] : args;
|
|
414
422
|
var createLinearPredicate = (items) => {
|
|
415
423
|
return define((input) => {
|
|
@@ -421,7 +429,7 @@ var createSetPredicate = (items) => {
|
|
|
421
429
|
let hasNegativeZero = false;
|
|
422
430
|
const valueSet = /* @__PURE__ */ new Set();
|
|
423
431
|
for (const literalValue of items) {
|
|
424
|
-
if (
|
|
432
|
+
if (isZero(literalValue)) {
|
|
425
433
|
if (Object.is(literalValue, -0)) hasNegativeZero = true;
|
|
426
434
|
else hasPositiveZero = true;
|
|
427
435
|
} else {
|
|
@@ -429,7 +437,7 @@ var createSetPredicate = (items) => {
|
|
|
429
437
|
}
|
|
430
438
|
}
|
|
431
439
|
return define((input) => {
|
|
432
|
-
if (
|
|
440
|
+
if (isZero(input)) {
|
|
433
441
|
return Object.is(input, -0) ? hasNegativeZero : hasPositiveZero;
|
|
434
442
|
}
|
|
435
443
|
return valueSet.has(input);
|
package/dist/index.mjs
CHANGED
|
@@ -68,8 +68,20 @@ function required(fn) {
|
|
|
68
68
|
return (value) => value !== void 0 && fn(value);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// src/utils/object-tags.ts
|
|
72
|
+
var objectToString = Object.prototype.toString;
|
|
73
|
+
var OBJECT_TAG_DATE = "[object Date]";
|
|
74
|
+
var OBJECT_TAG_REGEXP = "[object RegExp]";
|
|
75
|
+
var OBJECT_TAG_MAP = "[object Map]";
|
|
76
|
+
var OBJECT_TAG_SET = "[object Set]";
|
|
77
|
+
var OBJECT_TAG_WEAK_MAP = "[object WeakMap]";
|
|
78
|
+
var OBJECT_TAG_WEAK_SET = "[object WeakSet]";
|
|
79
|
+
var OBJECT_TAG_ARRAY_BUFFER = "[object ArrayBuffer]";
|
|
80
|
+
var OBJECT_TAG_DATA_VIEW = "[object DataView]";
|
|
81
|
+
var OBJECT_TAG_ERROR = "[object Error]";
|
|
82
|
+
var getTag = (value) => objectToString.call(value);
|
|
83
|
+
|
|
71
84
|
// src/core/object.ts
|
|
72
|
-
var getTag = (value) => Object.prototype.toString.call(value);
|
|
73
85
|
var isFunction = define(
|
|
74
86
|
(value) => typeof value === "function"
|
|
75
87
|
);
|
|
@@ -83,46 +95,46 @@ var isPlainObject = define((value) => {
|
|
|
83
95
|
});
|
|
84
96
|
var isArray = define(Array.isArray);
|
|
85
97
|
var isDate = define(
|
|
86
|
-
(value) => getTag(value) ===
|
|
98
|
+
(value) => getTag(value) === OBJECT_TAG_DATE && !Number.isNaN(value.getTime())
|
|
87
99
|
);
|
|
88
100
|
var isRegExp = define(
|
|
89
|
-
(value) => getTag(value) ===
|
|
101
|
+
(value) => getTag(value) === OBJECT_TAG_REGEXP
|
|
90
102
|
);
|
|
91
103
|
var isMap = define(
|
|
92
|
-
(value) => getTag(value) ===
|
|
104
|
+
(value) => getTag(value) === OBJECT_TAG_MAP
|
|
93
105
|
);
|
|
94
106
|
var isSet = define(
|
|
95
|
-
(value) => getTag(value) ===
|
|
107
|
+
(value) => getTag(value) === OBJECT_TAG_SET
|
|
96
108
|
);
|
|
97
109
|
var isWeakMap = define(
|
|
98
|
-
(value) => getTag(value) ===
|
|
110
|
+
(value) => getTag(value) === OBJECT_TAG_WEAK_MAP
|
|
99
111
|
);
|
|
100
112
|
var isWeakSet = define(
|
|
101
|
-
(value) => getTag(value) ===
|
|
113
|
+
(value) => getTag(value) === OBJECT_TAG_WEAK_SET
|
|
102
114
|
);
|
|
103
115
|
var isPromiseLike = define((value) => {
|
|
104
116
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
105
|
-
return
|
|
117
|
+
return isFunction(value.then);
|
|
106
118
|
});
|
|
107
119
|
var isIterable = define((value) => {
|
|
108
120
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
109
|
-
return
|
|
121
|
+
return isFunction(value[Symbol.iterator]);
|
|
110
122
|
});
|
|
111
123
|
var isAsyncIterable = define((value) => {
|
|
112
124
|
if (!isObject(value) && !isFunction(value)) return false;
|
|
113
|
-
return
|
|
125
|
+
return isFunction(value[Symbol.asyncIterator]);
|
|
114
126
|
});
|
|
115
127
|
var isArrayBuffer = define(
|
|
116
|
-
(value) => getTag(value) ===
|
|
128
|
+
(value) => getTag(value) === OBJECT_TAG_ARRAY_BUFFER
|
|
117
129
|
);
|
|
118
130
|
var isDataView = define(
|
|
119
|
-
(value) => getTag(value) ===
|
|
131
|
+
(value) => getTag(value) === OBJECT_TAG_DATA_VIEW
|
|
120
132
|
);
|
|
121
133
|
var isTypedArray = define(
|
|
122
|
-
(value) => ArrayBuffer.isView(value) && getTag(value) !==
|
|
134
|
+
(value) => ArrayBuffer.isView(value) && getTag(value) !== OBJECT_TAG_DATA_VIEW
|
|
123
135
|
);
|
|
124
136
|
var isError = define(
|
|
125
|
-
(value) => value instanceof Error || getTag(value) ===
|
|
137
|
+
(value) => value instanceof Error || getTag(value) === OBJECT_TAG_ERROR
|
|
126
138
|
);
|
|
127
139
|
var isURL = typeof URL !== "undefined" ? define((value) => value instanceof URL) : define(() => false);
|
|
128
140
|
var isBlob = typeof Blob !== "undefined" ? define((value) => value instanceof Blob) : define(() => false);
|
|
@@ -313,10 +325,6 @@ var ONE_OF_VALUES_LINEAR_SCAN_MAX = 8;
|
|
|
313
325
|
var isSingleArrayArg = define(
|
|
314
326
|
(value) => Array.isArray(value) && value.length === 1 && Array.isArray(value[0])
|
|
315
327
|
);
|
|
316
|
-
var isZeroNumber = and(
|
|
317
|
-
isNumber,
|
|
318
|
-
predicateToRefine((value) => value === 0)
|
|
319
|
-
);
|
|
320
328
|
var normalizeValues = (args) => isSingleArrayArg(args) ? args[0] : args;
|
|
321
329
|
var createLinearPredicate = (items) => {
|
|
322
330
|
return define((input) => {
|
|
@@ -328,7 +336,7 @@ var createSetPredicate = (items) => {
|
|
|
328
336
|
let hasNegativeZero = false;
|
|
329
337
|
const valueSet = /* @__PURE__ */ new Set();
|
|
330
338
|
for (const literalValue of items) {
|
|
331
|
-
if (
|
|
339
|
+
if (isZero(literalValue)) {
|
|
332
340
|
if (Object.is(literalValue, -0)) hasNegativeZero = true;
|
|
333
341
|
else hasPositiveZero = true;
|
|
334
342
|
} else {
|
|
@@ -336,7 +344,7 @@ var createSetPredicate = (items) => {
|
|
|
336
344
|
}
|
|
337
345
|
}
|
|
338
346
|
return define((input) => {
|
|
339
|
-
if (
|
|
347
|
+
if (isZero(input)) {
|
|
340
348
|
return Object.is(input, -0) ? hasNegativeZero : hasPositiveZero;
|
|
341
349
|
}
|
|
342
350
|
return valueSet.has(input);
|