is-kit 1.11.0 → 1.11.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 CHANGED
@@ -111,6 +111,69 @@ This is the core idea of `is-kit`:
111
111
  2. Compose them.
112
112
  3. Reuse them anywhere TypeScript narrowing matters.
113
113
 
114
+ ## 🧭 Guard Composition Guide
115
+
116
+ When writing reusable guards with `is-kit`, start from the library primitives:
117
+ use `define` for custom runtime checks, and use logic combinators such as
118
+ `and`, `or`, and `not` when combining existing guards. This keeps the result
119
+ reusable as a named guard and preserves the type-level intent in hover,
120
+ completion, and generated declarations.
121
+
122
+ ```ts
123
+ import {
124
+ and,
125
+ define,
126
+ isNil,
127
+ isNumber,
128
+ isString,
129
+ nullish,
130
+ or,
131
+ predicateToRefine
132
+ } from 'is-kit';
133
+
134
+ const isId = or(isString, isNumber);
135
+ const isNullishString = nullish(isString);
136
+
137
+ const isSlug = define<string>(
138
+ (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
139
+ );
140
+
141
+ const isPositiveNumber = and(
142
+ isNumber,
143
+ predicateToRefine<number>((value) => value > 0)
144
+ );
145
+
146
+ isNil(null); // true
147
+ isNil(undefined); // true
148
+ isId('user-1'); // true
149
+ isNullishString(undefined); // true
150
+ isSlug('release-110'); // true
151
+ isPositiveNumber(1); // true
152
+ ```
153
+
154
+ Prefer these forms when generating or reviewing code:
155
+
156
+ ```ts
157
+ declare const value: unknown;
158
+
159
+ // Prefer
160
+ const isId = or(isString, isNumber);
161
+ const isMaybeName = nullish(isString);
162
+ const isSlug = define<string>(
163
+ (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
164
+ );
165
+
166
+ // Avoid
167
+ const isId = (value: unknown) => isString(value) || isNumber(value);
168
+ const isMaybeName = (value: unknown) => value == null || isString(value);
169
+ const isSlug = (value: unknown): value is string =>
170
+ isString(value) && /^[a-z0-9-]+$/.test(value);
171
+ ```
172
+
173
+ For AI agents or repository-wide conventions, copy
174
+ [docs/agent-rules.md](./docs/agent-rules.md) into the consumer repository's
175
+ agent instructions.
176
+
114
177
  ## ⌚ A 30-second Mental Model
115
178
 
116
179
  If you are new to the library, these are the pieces to remember:
package/dist/index.d.mts CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * is-kit guard authoring guide:
3
+ * - Use define<T>(...) for reusable custom runtime checks.
4
+ * - Use and, andAll, or, and not to compose existing guards instead of
5
+ * hand-written boolean wrappers.
6
+ * - Use nullable, optional, or nullish to widen guards for nullish values.
7
+ * - Use struct or typedStruct for object-shape guards.
8
+ */
1
9
  type Predicate<T> = (value: unknown) => value is T;
2
10
  type Refinement<A, B extends A> = (value: A) => value is B;
3
11
  type Guard<T> = Predicate<T>;
@@ -69,12 +77,18 @@ declare function assert<A, B extends A>(refine: Refine<A, B>, value: A, message?
69
77
 
70
78
  /**
71
79
  * Wraps a user function as a typed predicate.
80
+ * Prefer `define<T>(...)` when creating a reusable custom guard from a runtime
81
+ * boolean check.
72
82
  *
73
83
  * Note: The correctness of the predicate is the caller's responsibility.
74
84
  * Its result is coerced to a boolean using `!!` for consistent guard behavior.
75
85
  *
76
86
  * @param fn Function that returns truthy when the value matches the target shape.
77
87
  * @returns Predicate narrowing to the intended type when it returns true.
88
+ * @example
89
+ * const isSlug = define<string>(
90
+ * (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
91
+ * );
78
92
  */
79
93
  declare function define<T>(fn: (value: unknown) => value is T): Predicate<T>;
80
94
  declare function define<T>(fn: (value: unknown) => boolean): Predicate<T>;
@@ -146,49 +160,76 @@ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
146
160
 
147
161
  /**
148
162
  * Combines a precondition guard with an additional refinement to narrow the type.
163
+ * Prefer this over hand-written `precondition(x) && condition(x)` when the
164
+ * composed predicate should be reused as a guard.
149
165
  *
150
166
  * @param precondition Broad guard evaluated first; short-circuits on failure.
151
167
  * @param condition Refinement evaluated only when `precondition` passes.
152
168
  * @returns Predicate that narrows the input to a subtype.
169
+ * @example
170
+ * const isPositiveNumber = and(
171
+ * isNumber,
172
+ * predicateToRefine<number>((value) => value > 0)
173
+ * );
174
+ * @see andAll
153
175
  */
154
176
  declare function and<A, B extends A>(precondition: Guard<A>, condition: Refine<A, B>): Predicate<B>;
155
177
  /**
156
178
  * Chains a sequence of refinements after a precondition, returning the final guard type.
179
+ * Use this instead of nested `&&` checks when each step should keep narrowing
180
+ * the next refinement.
157
181
  *
158
182
  * @param precondition Initial guard applied first.
159
183
  * @param steps Subsequent refinements applied in order.
160
184
  * @returns Guard reflecting the result of the refinement chain.
185
+ * @example
186
+ * const isPublicTitle = andAll(isString, minLength(4), startsWithPublic);
187
+ * @see and
161
188
  */
162
189
  declare function andAll<A>(precondition: Guard<A>): Guard<A>;
163
190
  declare function andAll<A, B extends A>(precondition: Guard<A>, step1: Refine<A, B>): Guard<B>;
164
191
  declare function andAll<A, B extends A, C extends B>(precondition: Guard<A>, step1: Refine<A, B>, step2: Refine<B, C>): Guard<C>;
165
192
  /**
166
193
  * Logical OR over multiple guards.
194
+ * Prefer this over hand-written `guardA(x) || guardB(x)` when the composed
195
+ * predicate should be reused as a guard.
167
196
  *
168
197
  * @param guards Guards to evaluate; passes if any guard passes.
169
198
  * @returns Guard for the union of all guarded types.
199
+ * @example
200
+ * const isId = or(isString, isNumber);
201
+ * @see oneOf
170
202
  */
171
203
  declare function or<P extends readonly Guard<unknown>[]>(...guards: P): Guard<OutOfGuards<P>>;
172
204
  /**
173
205
  * Adapts a guard so it can be used as a refinement within a known supertype.
174
206
  *
175
207
  * @returns Function that converts a `Guard<T>` into a `Refine<A, T>` when `T extends A`.
208
+ * @see and
176
209
  */
177
210
  declare function guardIn<A>(): <T extends A>(guard: Guard<T>) => Refine<A, T>;
178
211
  /**
179
212
  * Logical negation of a guard/refinement.
213
+ * Use this when a negated predicate should be named and reused.
180
214
  *
181
215
  * @param guard Guard or refinement to negate.
182
216
  * @returns Refinement excluding the guarded subtype from the input type.
217
+ * @example
218
+ * const isPresent = not(isNil);
183
219
  */
184
220
  declare function not<A, T>(guard: Guard<T>): Refine<A, Exclude<A, Extract<A, T>>>;
185
221
  declare function not<A, B extends A>(refine: Refine<A, B>): Refine<A, Exclude<A, B>>;
186
222
 
187
223
  /**
188
224
  * Allows `null` in addition to values accepted by the given guard/refinement.
225
+ * Use this instead of hand-writing `value === null || guard(value)` when the
226
+ * widened predicate should stay reusable.
189
227
  *
190
228
  * @param guard Guard/refinement for the base type.
191
229
  * @returns Guard/refinement widened to include `null`.
230
+ * @example
231
+ * const isNullableString = nullable(isString);
232
+ * @see nullish
192
233
  */
193
234
  declare function nullable<T>(guard: Guard<T>): Guard<T | null>;
194
235
  declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null, B | null>;
@@ -197,22 +238,33 @@ declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null
197
238
  *
198
239
  * @param guard Guard/refinement possibly including `null`.
199
240
  * @returns Guard/refinement with `null` excluded.
241
+ * @example
242
+ * const isNonNullString = nonNull(nullable(isString));
200
243
  */
201
244
  declare function nonNull<T>(guard: Guard<T>): Guard<Exclude<T, null>>;
202
245
  declare function nonNull<A, B extends A>(refine: Refine<A, B>): Refine<Exclude<A, null>, Exclude<B, null>>;
203
246
  /**
204
247
  * Allows `null` or `undefined` in addition to values accepted by the guard.
248
+ * Use this instead of hand-writing `isNil(value) || guard(value)` when widening
249
+ * another guard.
205
250
  *
206
251
  * @param guard Guard/refinement for the base type.
207
252
  * @returns Guard/refinement widened to include `null | undefined`.
253
+ * @example
254
+ * const isNullishString = nullish(isString);
255
+ * @see isNil
208
256
  */
209
257
  declare function nullish<T>(guard: Guard<T>): Guard<T | null | undefined>;
210
258
  declare function nullish<A, B extends A>(refine: Refine<A, B>): Refine<A | null | undefined, B | null | undefined>;
211
259
  /**
212
260
  * Allows `undefined` in addition to values accepted by the guard.
261
+ * Use this for value-level optionality. For optional object keys in `struct`,
262
+ * use `optionalKey(...)`.
213
263
  *
214
264
  * @param guard Guard/refinement for the base type.
215
265
  * @returns Guard/refinement widened to include `undefined`.
266
+ * @example
267
+ * const isOptionalString = optional(isString);
216
268
  */
217
269
  declare function optional<T>(guard: Guard<T>): Guard<T | undefined>;
218
270
  declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | undefined, B | undefined>;
@@ -221,6 +273,8 @@ declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | unde
221
273
  *
222
274
  * @param guard Guard/refinement that may accept `undefined`.
223
275
  * @returns Guard/refinement with `undefined` removed.
276
+ * @example
277
+ * const isRequiredString = required(optional(isString));
224
278
  */
225
279
  declare function required<T>(guard: Guard<T | undefined>): Guard<T>;
226
280
  declare function required<A, B extends A>(refine: Refine<A | undefined, B | undefined>): Refine<A, B>;
@@ -351,17 +405,21 @@ declare const isSymbol: Predicate<symbol>;
351
405
  /**
352
406
  * Checks whether a value is exactly `undefined`.
353
407
  *
354
- * To accept `null` as well, use {@link isNil}.
408
+ * For reusable nullish checks, use {@link isNil} or compose a named guard with
409
+ * {@link or} once and reuse it.
355
410
  *
356
411
  * @returns Predicate narrowing to `undefined`.
412
+ * @see isNil
357
413
  */
358
414
  declare const isUndefined: Predicate<undefined>;
359
415
  /**
360
416
  * Checks whether a value is exactly `null`.
361
417
  *
362
- * To accept `undefined` as well, use {@link isNil}.
418
+ * For reusable nullish checks, use {@link isNil} or compose a named guard with
419
+ * {@link or} once and reuse it.
363
420
  *
364
421
  * @returns Predicate narrowing to `null`.
422
+ * @see isNil
365
423
  */
366
424
  declare const isNull: Predicate<null>;
367
425
  /**
package/dist/index.d.ts CHANGED
@@ -1,3 +1,11 @@
1
+ /**
2
+ * is-kit guard authoring guide:
3
+ * - Use define<T>(...) for reusable custom runtime checks.
4
+ * - Use and, andAll, or, and not to compose existing guards instead of
5
+ * hand-written boolean wrappers.
6
+ * - Use nullable, optional, or nullish to widen guards for nullish values.
7
+ * - Use struct or typedStruct for object-shape guards.
8
+ */
1
9
  type Predicate<T> = (value: unknown) => value is T;
2
10
  type Refinement<A, B extends A> = (value: A) => value is B;
3
11
  type Guard<T> = Predicate<T>;
@@ -69,12 +77,18 @@ declare function assert<A, B extends A>(refine: Refine<A, B>, value: A, message?
69
77
 
70
78
  /**
71
79
  * Wraps a user function as a typed predicate.
80
+ * Prefer `define<T>(...)` when creating a reusable custom guard from a runtime
81
+ * boolean check.
72
82
  *
73
83
  * Note: The correctness of the predicate is the caller's responsibility.
74
84
  * Its result is coerced to a boolean using `!!` for consistent guard behavior.
75
85
  *
76
86
  * @param fn Function that returns truthy when the value matches the target shape.
77
87
  * @returns Predicate narrowing to the intended type when it returns true.
88
+ * @example
89
+ * const isSlug = define<string>(
90
+ * (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
91
+ * );
78
92
  */
79
93
  declare function define<T>(fn: (value: unknown) => value is T): Predicate<T>;
80
94
  declare function define<T>(fn: (value: unknown) => boolean): Predicate<T>;
@@ -146,49 +160,76 @@ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
146
160
 
147
161
  /**
148
162
  * Combines a precondition guard with an additional refinement to narrow the type.
163
+ * Prefer this over hand-written `precondition(x) && condition(x)` when the
164
+ * composed predicate should be reused as a guard.
149
165
  *
150
166
  * @param precondition Broad guard evaluated first; short-circuits on failure.
151
167
  * @param condition Refinement evaluated only when `precondition` passes.
152
168
  * @returns Predicate that narrows the input to a subtype.
169
+ * @example
170
+ * const isPositiveNumber = and(
171
+ * isNumber,
172
+ * predicateToRefine<number>((value) => value > 0)
173
+ * );
174
+ * @see andAll
153
175
  */
154
176
  declare function and<A, B extends A>(precondition: Guard<A>, condition: Refine<A, B>): Predicate<B>;
155
177
  /**
156
178
  * Chains a sequence of refinements after a precondition, returning the final guard type.
179
+ * Use this instead of nested `&&` checks when each step should keep narrowing
180
+ * the next refinement.
157
181
  *
158
182
  * @param precondition Initial guard applied first.
159
183
  * @param steps Subsequent refinements applied in order.
160
184
  * @returns Guard reflecting the result of the refinement chain.
185
+ * @example
186
+ * const isPublicTitle = andAll(isString, minLength(4), startsWithPublic);
187
+ * @see and
161
188
  */
162
189
  declare function andAll<A>(precondition: Guard<A>): Guard<A>;
163
190
  declare function andAll<A, B extends A>(precondition: Guard<A>, step1: Refine<A, B>): Guard<B>;
164
191
  declare function andAll<A, B extends A, C extends B>(precondition: Guard<A>, step1: Refine<A, B>, step2: Refine<B, C>): Guard<C>;
165
192
  /**
166
193
  * Logical OR over multiple guards.
194
+ * Prefer this over hand-written `guardA(x) || guardB(x)` when the composed
195
+ * predicate should be reused as a guard.
167
196
  *
168
197
  * @param guards Guards to evaluate; passes if any guard passes.
169
198
  * @returns Guard for the union of all guarded types.
199
+ * @example
200
+ * const isId = or(isString, isNumber);
201
+ * @see oneOf
170
202
  */
171
203
  declare function or<P extends readonly Guard<unknown>[]>(...guards: P): Guard<OutOfGuards<P>>;
172
204
  /**
173
205
  * Adapts a guard so it can be used as a refinement within a known supertype.
174
206
  *
175
207
  * @returns Function that converts a `Guard<T>` into a `Refine<A, T>` when `T extends A`.
208
+ * @see and
176
209
  */
177
210
  declare function guardIn<A>(): <T extends A>(guard: Guard<T>) => Refine<A, T>;
178
211
  /**
179
212
  * Logical negation of a guard/refinement.
213
+ * Use this when a negated predicate should be named and reused.
180
214
  *
181
215
  * @param guard Guard or refinement to negate.
182
216
  * @returns Refinement excluding the guarded subtype from the input type.
217
+ * @example
218
+ * const isPresent = not(isNil);
183
219
  */
184
220
  declare function not<A, T>(guard: Guard<T>): Refine<A, Exclude<A, Extract<A, T>>>;
185
221
  declare function not<A, B extends A>(refine: Refine<A, B>): Refine<A, Exclude<A, B>>;
186
222
 
187
223
  /**
188
224
  * Allows `null` in addition to values accepted by the given guard/refinement.
225
+ * Use this instead of hand-writing `value === null || guard(value)` when the
226
+ * widened predicate should stay reusable.
189
227
  *
190
228
  * @param guard Guard/refinement for the base type.
191
229
  * @returns Guard/refinement widened to include `null`.
230
+ * @example
231
+ * const isNullableString = nullable(isString);
232
+ * @see nullish
192
233
  */
193
234
  declare function nullable<T>(guard: Guard<T>): Guard<T | null>;
194
235
  declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null, B | null>;
@@ -197,22 +238,33 @@ declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null
197
238
  *
198
239
  * @param guard Guard/refinement possibly including `null`.
199
240
  * @returns Guard/refinement with `null` excluded.
241
+ * @example
242
+ * const isNonNullString = nonNull(nullable(isString));
200
243
  */
201
244
  declare function nonNull<T>(guard: Guard<T>): Guard<Exclude<T, null>>;
202
245
  declare function nonNull<A, B extends A>(refine: Refine<A, B>): Refine<Exclude<A, null>, Exclude<B, null>>;
203
246
  /**
204
247
  * Allows `null` or `undefined` in addition to values accepted by the guard.
248
+ * Use this instead of hand-writing `isNil(value) || guard(value)` when widening
249
+ * another guard.
205
250
  *
206
251
  * @param guard Guard/refinement for the base type.
207
252
  * @returns Guard/refinement widened to include `null | undefined`.
253
+ * @example
254
+ * const isNullishString = nullish(isString);
255
+ * @see isNil
208
256
  */
209
257
  declare function nullish<T>(guard: Guard<T>): Guard<T | null | undefined>;
210
258
  declare function nullish<A, B extends A>(refine: Refine<A, B>): Refine<A | null | undefined, B | null | undefined>;
211
259
  /**
212
260
  * Allows `undefined` in addition to values accepted by the guard.
261
+ * Use this for value-level optionality. For optional object keys in `struct`,
262
+ * use `optionalKey(...)`.
213
263
  *
214
264
  * @param guard Guard/refinement for the base type.
215
265
  * @returns Guard/refinement widened to include `undefined`.
266
+ * @example
267
+ * const isOptionalString = optional(isString);
216
268
  */
217
269
  declare function optional<T>(guard: Guard<T>): Guard<T | undefined>;
218
270
  declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | undefined, B | undefined>;
@@ -221,6 +273,8 @@ declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | unde
221
273
  *
222
274
  * @param guard Guard/refinement that may accept `undefined`.
223
275
  * @returns Guard/refinement with `undefined` removed.
276
+ * @example
277
+ * const isRequiredString = required(optional(isString));
224
278
  */
225
279
  declare function required<T>(guard: Guard<T | undefined>): Guard<T>;
226
280
  declare function required<A, B extends A>(refine: Refine<A | undefined, B | undefined>): Refine<A, B>;
@@ -351,17 +405,21 @@ declare const isSymbol: Predicate<symbol>;
351
405
  /**
352
406
  * Checks whether a value is exactly `undefined`.
353
407
  *
354
- * To accept `null` as well, use {@link isNil}.
408
+ * For reusable nullish checks, use {@link isNil} or compose a named guard with
409
+ * {@link or} once and reuse it.
355
410
  *
356
411
  * @returns Predicate narrowing to `undefined`.
412
+ * @see isNil
357
413
  */
358
414
  declare const isUndefined: Predicate<undefined>;
359
415
  /**
360
416
  * Checks whether a value is exactly `null`.
361
417
  *
362
- * To accept `undefined` as well, use {@link isNil}.
418
+ * For reusable nullish checks, use {@link isNil} or compose a named guard with
419
+ * {@link or} once and reuse it.
363
420
  *
364
421
  * @returns Predicate narrowing to `null`.
422
+ * @see isNil
365
423
  */
366
424
  declare const isNull: Predicate<null>;
367
425
  /**
package/dist/index.js CHANGED
@@ -114,6 +114,10 @@ function define(fn) {
114
114
  return (value) => !!fn(value);
115
115
  }
116
116
 
117
+ // src/utils/own-properties.ts
118
+ var hasOwnPropertyKey = (value, key) => Object.hasOwn(value, key);
119
+ var hasOwnPropertyKeys = (value, keys) => keys.every((key) => hasOwnPropertyKey(value, key));
120
+
117
121
  // src/utils/guard-collections.ts
118
122
  var everyIterableValue = (values, predicate) => {
119
123
  for (const value of values) {
@@ -237,19 +241,19 @@ function equalsBy(guard, selector) {
237
241
  }
238
242
  function equalsKey(key, target) {
239
243
  const hasMatchingKey = define((input) => {
240
- return isObject(input) && Object.hasOwn(input, key) && Object.is(input[key], target);
244
+ return isObject(input) && hasOwnPropertyKey(input, key) && Object.is(input[key], target);
241
245
  });
242
246
  return (input) => hasMatchingKey(input);
243
247
  }
244
248
 
245
249
  // src/core/key.ts
246
- var hasKey = (key) => define((input) => isObject(input) && Object.hasOwn(input, key));
250
+ var hasKey = (key) => define((input) => isObject(input) && hasOwnPropertyKey(input, key));
247
251
  var hasKeys = (...keys) => {
248
252
  if (keys.length === 0) {
249
253
  return define(() => false);
250
254
  }
251
255
  return define(
252
- (input) => isObject(input) && keys.every((key) => Object.hasOwn(input, key))
256
+ (input) => isObject(input) && hasOwnPropertyKeys(input, keys)
253
257
  );
254
258
  };
255
259
  function narrowKeyTo(guard, key) {
@@ -469,12 +473,14 @@ var isOptionalSchemaField = define(
469
473
  var hasRequiredKeys = (obj, entries) => (
470
474
  // WHY: Required fields must be own properties; inherited values should not
471
475
  // satisfy a schema because `struct` models object payload shape, not prototype chains.
472
- entries.every(([key, guard]) => Object.hasOwn(obj, key) && guard(obj[key]))
476
+ entries.every(([key, guard]) => hasOwnPropertyKey(obj, key) && guard(obj[key]))
473
477
  );
474
478
  var hasValidOptionalKeys = (obj, entries) => (
475
479
  // WHY: Optional keys are validated only when present. Missing keys stay valid
476
480
  // without forcing callers to encode `undefined` into the value guard.
477
- entries.every(([key, guard]) => !Object.hasOwn(obj, key) || guard(obj[key]))
481
+ entries.every(
482
+ ([key, guard]) => !hasOwnPropertyKey(obj, key) || guard(obj[key])
483
+ )
478
484
  );
479
485
  var hasOnlyAllowedKeys = (obj, allowed) => Object.keys(obj).every((key) => allowed.has(key));
480
486
  function optionalKey(guard) {
@@ -485,7 +491,7 @@ function struct(schema, options) {
485
491
  const optionalEntries = [];
486
492
  const schemaKeys = [];
487
493
  for (const key in schema) {
488
- if (!Object.hasOwn(schema, key)) continue;
494
+ if (!hasOwnPropertyKey(schema, key)) continue;
489
495
  const field = schema[key];
490
496
  schemaKeys.push(key);
491
497
  if (isOptionalSchemaField(field)) {
package/dist/index.mjs CHANGED
@@ -10,6 +10,10 @@ function define(fn) {
10
10
  return (value) => !!fn(value);
11
11
  }
12
12
 
13
+ // src/utils/own-properties.ts
14
+ var hasOwnPropertyKey = (value, key) => Object.hasOwn(value, key);
15
+ var hasOwnPropertyKeys = (value, keys) => keys.every((key) => hasOwnPropertyKey(value, key));
16
+
13
17
  // src/utils/guard-collections.ts
14
18
  var everyIterableValue = (values, predicate) => {
15
19
  for (const value of values) {
@@ -133,19 +137,19 @@ function equalsBy(guard, selector) {
133
137
  }
134
138
  function equalsKey(key, target) {
135
139
  const hasMatchingKey = define((input) => {
136
- return isObject(input) && Object.hasOwn(input, key) && Object.is(input[key], target);
140
+ return isObject(input) && hasOwnPropertyKey(input, key) && Object.is(input[key], target);
137
141
  });
138
142
  return (input) => hasMatchingKey(input);
139
143
  }
140
144
 
141
145
  // src/core/key.ts
142
- var hasKey = (key) => define((input) => isObject(input) && Object.hasOwn(input, key));
146
+ var hasKey = (key) => define((input) => isObject(input) && hasOwnPropertyKey(input, key));
143
147
  var hasKeys = (...keys) => {
144
148
  if (keys.length === 0) {
145
149
  return define(() => false);
146
150
  }
147
151
  return define(
148
- (input) => isObject(input) && keys.every((key) => Object.hasOwn(input, key))
152
+ (input) => isObject(input) && hasOwnPropertyKeys(input, keys)
149
153
  );
150
154
  };
151
155
  function narrowKeyTo(guard, key) {
@@ -365,12 +369,14 @@ var isOptionalSchemaField = define(
365
369
  var hasRequiredKeys = (obj, entries) => (
366
370
  // WHY: Required fields must be own properties; inherited values should not
367
371
  // satisfy a schema because `struct` models object payload shape, not prototype chains.
368
- entries.every(([key, guard]) => Object.hasOwn(obj, key) && guard(obj[key]))
372
+ entries.every(([key, guard]) => hasOwnPropertyKey(obj, key) && guard(obj[key]))
369
373
  );
370
374
  var hasValidOptionalKeys = (obj, entries) => (
371
375
  // WHY: Optional keys are validated only when present. Missing keys stay valid
372
376
  // without forcing callers to encode `undefined` into the value guard.
373
- entries.every(([key, guard]) => !Object.hasOwn(obj, key) || guard(obj[key]))
377
+ entries.every(
378
+ ([key, guard]) => !hasOwnPropertyKey(obj, key) || guard(obj[key])
379
+ )
374
380
  );
375
381
  var hasOnlyAllowedKeys = (obj, allowed) => Object.keys(obj).every((key) => allowed.has(key));
376
382
  function optionalKey(guard) {
@@ -381,7 +387,7 @@ function struct(schema, options) {
381
387
  const optionalEntries = [];
382
388
  const schemaKeys = [];
383
389
  for (const key in schema) {
384
- if (!Object.hasOwn(schema, key)) continue;
390
+ if (!hasOwnPropertyKey(schema, key)) continue;
385
391
  const field = schema[key];
386
392
  schemaKeys.push(key);
387
393
  if (isOptionalSchemaField(field)) {
package/docs/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # is-kit docs
2
+
3
+ This directory contains the public documentation site for `is-kit`.
4
+
5
+ The site is built with Next.js and shadcn/ui. It serves the marketing pages, hand-written API guides, and the generated TypeDoc output.
6
+
7
+ ## What lives here
8
+
9
+ - `app/` - Next.js routes and page entry points
10
+ - `components/` - reusable docs-site UI and page sections
11
+ - `constants/` - site navigation and page metadata
12
+ - `lib/` - docs-specific helpers and data shaping
13
+ - `public/` - static assets and generated API output
14
+
15
+ ## Local development
16
+
17
+ From the repository root:
18
+
19
+ ```bash
20
+ pnpm --filter ./docs dev
21
+ ```
22
+
23
+ Other common commands:
24
+
25
+ ```bash
26
+ pnpm --filter ./docs build
27
+ pnpm --filter ./docs start
28
+ ```
29
+
30
+ If you use `mise`, run the same commands through `mise exec`.
31
+
32
+ ## Generated API reference
33
+
34
+ The API reference is generated from the library source with TypeDoc and written to `docs/public/api`.
35
+
36
+ From the repository root:
37
+
38
+ ```bash
39
+ pnpm typedoc
40
+ ```
41
+
42
+ After generation, the docs site serves that static output under `/api`.
43
+
44
+ ## Common editing workflow
45
+
46
+ ### Update a guide or landing page
47
+
48
+ Edit the relevant route in `app/` and the supporting components in `components/`.
49
+
50
+ ### Update navigation or docs metadata
51
+
52
+ Check the files under `constants/` and `lib/`.
53
+
54
+ ### Refresh generated API docs
55
+
56
+ Run:
57
+
58
+ ```bash
59
+ pnpm typedoc
60
+ ```
61
+
62
+ ### Add or update static assets
63
+
64
+ Place them under `public/`.
65
+
66
+ ## shadcn/ui
67
+
68
+ The docs app is already configured for shadcn/ui with the `@/*` alias.
69
+
70
+ List available components:
71
+
72
+ ```bash
73
+ pnpm --filter ./docs run shadcn:list
74
+ ```
75
+
76
+ Add a component:
77
+
78
+ ```bash
79
+ pnpm --filter ./docs run shadcn:add button
80
+ ```
81
+
82
+ If you need to reinitialize shadcn:
83
+
84
+ ```bash
85
+ pnpm --filter ./docs run shadcn:init
86
+ ```
87
+
88
+ ## Example
89
+
90
+ ```tsx
91
+ import { Button } from '@/components/ui/button';
92
+
93
+ export default function Example() {
94
+ return (
95
+ <div className='space-x-2'>
96
+ <Button>Default</Button>
97
+ <Button variant='secondary'>Secondary</Button>
98
+ </div>
99
+ );
100
+ }
101
+ ```
@@ -0,0 +1,63 @@
1
+ # is-kit Agent Rules
2
+
3
+ Copy this into a consumer repository's `AGENTS.md`, `CLAUDE.md`, or
4
+ `.agents/rules/is-kit.md` when AI agents generate or review code that uses
5
+ `is-kit`.
6
+
7
+ ## Usage Rules
8
+
9
+ - Build reusable custom guards with `define<T>(...)` instead of writing
10
+ standalone type-predicate functions by hand.
11
+ - Prefer `is-kit` combinators over hand-written boolean composition when
12
+ combining existing guards.
13
+ - Use `or(isA, isB)` instead of `(value) => isA(value) || isB(value)` when the
14
+ result should be a reusable guard.
15
+ - Use `and(baseGuard, refinement)` or `andAll(...)` instead of hand-written
16
+ `&&` checks when narrowing should be preserved.
17
+ - Use `not(guard)` for reusable negated guards.
18
+ - Use `nullable(guard)`, `optional(guard)`, or `nullish(guard)` when widening an
19
+ existing guard to accept `null` and/or `undefined`.
20
+ - Use `isNil(value)` when checking a value directly for `null | undefined`.
21
+ - Use `optionalKey(guard)` for optional object keys inside `struct`.
22
+
23
+ ## Preferred Examples
24
+
25
+ ```ts
26
+ import {
27
+ and,
28
+ define,
29
+ isNil,
30
+ isNumber,
31
+ isString,
32
+ nullish,
33
+ or,
34
+ predicateToRefine
35
+ } from 'is-kit';
36
+
37
+ const isId = or(isString, isNumber);
38
+ const isMaybeName = nullish(isString);
39
+ const isSlug = define<string>(
40
+ (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
41
+ );
42
+ const isPositiveNumber = and(
43
+ isNumber,
44
+ predicateToRefine<number>((value) => value > 0)
45
+ );
46
+
47
+ declare const value: unknown;
48
+
49
+ if (isNil(value)) {
50
+ return;
51
+ }
52
+ ```
53
+
54
+ ## Avoid
55
+
56
+ ```ts
57
+ declare const value: unknown;
58
+
59
+ const isId = (value: unknown) => isString(value) || isNumber(value);
60
+ const isMaybeName = (value: unknown) => value == null || isString(value);
61
+ const isSlug = (value: unknown): value is string =>
62
+ isString(value) && /^[a-z0-9-]+$/.test(value);
63
+ ```
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "is-kit",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "Make 'isXXX' easier. Let's make your code type safe and more readable!",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -22,6 +22,7 @@
22
22
  ],
23
23
  "files": [
24
24
  "dist",
25
+ "docs/agent-rules.md",
25
26
  "README.md",
26
27
  "LICENSE"
27
28
  ],