is-kit 1.11.0 → 1.11.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.
- package/README.md +63 -0
- package/dist/index.d.mts +89 -16
- package/dist/index.d.ts +89 -16
- package/dist/index.js +12 -6
- package/dist/index.mjs +12 -6
- package/docs/README.md +101 -0
- package/docs/agent-rules.md +63 -0
- package/package.json +2 -1
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>;
|
|
@@ -55,6 +63,34 @@ type InferSchema<S extends SchemaShape<S>> = Simplify<{
|
|
|
55
63
|
} & {
|
|
56
64
|
readonly [K in OptionalSchemaKeys<S>]?: InferSchemaField<S[K]>;
|
|
57
65
|
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Extracts optional keys from an object type.
|
|
68
|
+
*/
|
|
69
|
+
type OptionalObjectKeys<T> = {
|
|
70
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
71
|
+
}[keyof T];
|
|
72
|
+
/**
|
|
73
|
+
* Extracts required keys from an object type.
|
|
74
|
+
*/
|
|
75
|
+
type RequiredObjectKeys<T> = Exclude<keyof T, OptionalObjectKeys<T>>;
|
|
76
|
+
/**
|
|
77
|
+
* Schema shape checked against an existing object type by `typedStruct`.
|
|
78
|
+
*/
|
|
79
|
+
type TypedStructShape<T extends object> = {
|
|
80
|
+
readonly [K in Extract<RequiredObjectKeys<T>, string>]-?: Predicate<T[K]>;
|
|
81
|
+
} & {
|
|
82
|
+
readonly [K in Extract<OptionalObjectKeys<T>, string>]-?: OptionalSchemaField<Predicate<T[K]>>;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Keeps a schema type while rejecting keys outside the expected shape.
|
|
86
|
+
*/
|
|
87
|
+
type NoExtraKeys<S, Shape> = S & {
|
|
88
|
+
readonly [K in Exclude<keyof S, keyof Shape>]: never;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Field set accepted by `typedStruct` for a target object type.
|
|
92
|
+
*/
|
|
93
|
+
type TypedStructFields<T extends object, S extends TypedStructShape<T>> = NoExtraKeys<S, TypedStructShape<T>>;
|
|
58
94
|
|
|
59
95
|
/**
|
|
60
96
|
* Asserts that a value satisfies a guard or refinement, otherwise throws.
|
|
@@ -69,12 +105,18 @@ declare function assert<A, B extends A>(refine: Refine<A, B>, value: A, message?
|
|
|
69
105
|
|
|
70
106
|
/**
|
|
71
107
|
* Wraps a user function as a typed predicate.
|
|
108
|
+
* Prefer `define<T>(...)` when creating a reusable custom guard from a runtime
|
|
109
|
+
* boolean check.
|
|
72
110
|
*
|
|
73
111
|
* Note: The correctness of the predicate is the caller's responsibility.
|
|
74
112
|
* Its result is coerced to a boolean using `!!` for consistent guard behavior.
|
|
75
113
|
*
|
|
76
114
|
* @param fn Function that returns truthy when the value matches the target shape.
|
|
77
115
|
* @returns Predicate narrowing to the intended type when it returns true.
|
|
116
|
+
* @example
|
|
117
|
+
* const isSlug = define<string>(
|
|
118
|
+
* (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
|
|
119
|
+
* );
|
|
78
120
|
*/
|
|
79
121
|
declare function define<T>(fn: (value: unknown) => value is T): Predicate<T>;
|
|
80
122
|
declare function define<T>(fn: (value: unknown) => boolean): Predicate<T>;
|
|
@@ -146,49 +188,76 @@ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
|
|
|
146
188
|
|
|
147
189
|
/**
|
|
148
190
|
* Combines a precondition guard with an additional refinement to narrow the type.
|
|
191
|
+
* Prefer this over hand-written `precondition(x) && condition(x)` when the
|
|
192
|
+
* composed predicate should be reused as a guard.
|
|
149
193
|
*
|
|
150
194
|
* @param precondition Broad guard evaluated first; short-circuits on failure.
|
|
151
195
|
* @param condition Refinement evaluated only when `precondition` passes.
|
|
152
196
|
* @returns Predicate that narrows the input to a subtype.
|
|
197
|
+
* @example
|
|
198
|
+
* const isPositiveNumber = and(
|
|
199
|
+
* isNumber,
|
|
200
|
+
* predicateToRefine<number>((value) => value > 0)
|
|
201
|
+
* );
|
|
202
|
+
* @see andAll
|
|
153
203
|
*/
|
|
154
204
|
declare function and<A, B extends A>(precondition: Guard<A>, condition: Refine<A, B>): Predicate<B>;
|
|
155
205
|
/**
|
|
156
206
|
* Chains a sequence of refinements after a precondition, returning the final guard type.
|
|
207
|
+
* Use this instead of nested `&&` checks when each step should keep narrowing
|
|
208
|
+
* the next refinement.
|
|
157
209
|
*
|
|
158
210
|
* @param precondition Initial guard applied first.
|
|
159
211
|
* @param steps Subsequent refinements applied in order.
|
|
160
212
|
* @returns Guard reflecting the result of the refinement chain.
|
|
213
|
+
* @example
|
|
214
|
+
* const isPublicTitle = andAll(isString, minLength(4), startsWithPublic);
|
|
215
|
+
* @see and
|
|
161
216
|
*/
|
|
162
217
|
declare function andAll<A>(precondition: Guard<A>): Guard<A>;
|
|
163
218
|
declare function andAll<A, B extends A>(precondition: Guard<A>, step1: Refine<A, B>): Guard<B>;
|
|
164
219
|
declare function andAll<A, B extends A, C extends B>(precondition: Guard<A>, step1: Refine<A, B>, step2: Refine<B, C>): Guard<C>;
|
|
165
220
|
/**
|
|
166
221
|
* Logical OR over multiple guards.
|
|
222
|
+
* Prefer this over hand-written `guardA(x) || guardB(x)` when the composed
|
|
223
|
+
* predicate should be reused as a guard.
|
|
167
224
|
*
|
|
168
225
|
* @param guards Guards to evaluate; passes if any guard passes.
|
|
169
226
|
* @returns Guard for the union of all guarded types.
|
|
227
|
+
* @example
|
|
228
|
+
* const isId = or(isString, isNumber);
|
|
229
|
+
* @see oneOf
|
|
170
230
|
*/
|
|
171
231
|
declare function or<P extends readonly Guard<unknown>[]>(...guards: P): Guard<OutOfGuards<P>>;
|
|
172
232
|
/**
|
|
173
233
|
* Adapts a guard so it can be used as a refinement within a known supertype.
|
|
174
234
|
*
|
|
175
235
|
* @returns Function that converts a `Guard<T>` into a `Refine<A, T>` when `T extends A`.
|
|
236
|
+
* @see and
|
|
176
237
|
*/
|
|
177
238
|
declare function guardIn<A>(): <T extends A>(guard: Guard<T>) => Refine<A, T>;
|
|
178
239
|
/**
|
|
179
240
|
* Logical negation of a guard/refinement.
|
|
241
|
+
* Use this when a negated predicate should be named and reused.
|
|
180
242
|
*
|
|
181
243
|
* @param guard Guard or refinement to negate.
|
|
182
244
|
* @returns Refinement excluding the guarded subtype from the input type.
|
|
245
|
+
* @example
|
|
246
|
+
* const isPresent = not(isNil);
|
|
183
247
|
*/
|
|
184
248
|
declare function not<A, T>(guard: Guard<T>): Refine<A, Exclude<A, Extract<A, T>>>;
|
|
185
249
|
declare function not<A, B extends A>(refine: Refine<A, B>): Refine<A, Exclude<A, B>>;
|
|
186
250
|
|
|
187
251
|
/**
|
|
188
252
|
* Allows `null` in addition to values accepted by the given guard/refinement.
|
|
253
|
+
* Use this instead of hand-writing `value === null || guard(value)` when the
|
|
254
|
+
* widened predicate should stay reusable.
|
|
189
255
|
*
|
|
190
256
|
* @param guard Guard/refinement for the base type.
|
|
191
257
|
* @returns Guard/refinement widened to include `null`.
|
|
258
|
+
* @example
|
|
259
|
+
* const isNullableString = nullable(isString);
|
|
260
|
+
* @see nullish
|
|
192
261
|
*/
|
|
193
262
|
declare function nullable<T>(guard: Guard<T>): Guard<T | null>;
|
|
194
263
|
declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null, B | null>;
|
|
@@ -197,22 +266,33 @@ declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null
|
|
|
197
266
|
*
|
|
198
267
|
* @param guard Guard/refinement possibly including `null`.
|
|
199
268
|
* @returns Guard/refinement with `null` excluded.
|
|
269
|
+
* @example
|
|
270
|
+
* const isNonNullString = nonNull(nullable(isString));
|
|
200
271
|
*/
|
|
201
272
|
declare function nonNull<T>(guard: Guard<T>): Guard<Exclude<T, null>>;
|
|
202
273
|
declare function nonNull<A, B extends A>(refine: Refine<A, B>): Refine<Exclude<A, null>, Exclude<B, null>>;
|
|
203
274
|
/**
|
|
204
275
|
* Allows `null` or `undefined` in addition to values accepted by the guard.
|
|
276
|
+
* Use this instead of hand-writing `isNil(value) || guard(value)` when widening
|
|
277
|
+
* another guard.
|
|
205
278
|
*
|
|
206
279
|
* @param guard Guard/refinement for the base type.
|
|
207
280
|
* @returns Guard/refinement widened to include `null | undefined`.
|
|
281
|
+
* @example
|
|
282
|
+
* const isNullishString = nullish(isString);
|
|
283
|
+
* @see isNil
|
|
208
284
|
*/
|
|
209
285
|
declare function nullish<T>(guard: Guard<T>): Guard<T | null | undefined>;
|
|
210
286
|
declare function nullish<A, B extends A>(refine: Refine<A, B>): Refine<A | null | undefined, B | null | undefined>;
|
|
211
287
|
/**
|
|
212
288
|
* Allows `undefined` in addition to values accepted by the guard.
|
|
289
|
+
* Use this for value-level optionality. For optional object keys in `struct`,
|
|
290
|
+
* use `optionalKey(...)`.
|
|
213
291
|
*
|
|
214
292
|
* @param guard Guard/refinement for the base type.
|
|
215
293
|
* @returns Guard/refinement widened to include `undefined`.
|
|
294
|
+
* @example
|
|
295
|
+
* const isOptionalString = optional(isString);
|
|
216
296
|
*/
|
|
217
297
|
declare function optional<T>(guard: Guard<T>): Guard<T | undefined>;
|
|
218
298
|
declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | undefined, B | undefined>;
|
|
@@ -221,6 +301,8 @@ declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | unde
|
|
|
221
301
|
*
|
|
222
302
|
* @param guard Guard/refinement that may accept `undefined`.
|
|
223
303
|
* @returns Guard/refinement with `undefined` removed.
|
|
304
|
+
* @example
|
|
305
|
+
* const isRequiredString = required(optional(isString));
|
|
224
306
|
*/
|
|
225
307
|
declare function required<T>(guard: Guard<T | undefined>): Guard<T>;
|
|
226
308
|
declare function required<A, B extends A>(refine: Refine<A | undefined, B | undefined>): Refine<A, B>;
|
|
@@ -351,17 +433,21 @@ declare const isSymbol: Predicate<symbol>;
|
|
|
351
433
|
/**
|
|
352
434
|
* Checks whether a value is exactly `undefined`.
|
|
353
435
|
*
|
|
354
|
-
*
|
|
436
|
+
* For reusable nullish checks, use {@link isNil} or compose a named guard with
|
|
437
|
+
* {@link or} once and reuse it.
|
|
355
438
|
*
|
|
356
439
|
* @returns Predicate narrowing to `undefined`.
|
|
440
|
+
* @see isNil
|
|
357
441
|
*/
|
|
358
442
|
declare const isUndefined: Predicate<undefined>;
|
|
359
443
|
/**
|
|
360
444
|
* Checks whether a value is exactly `null`.
|
|
361
445
|
*
|
|
362
|
-
*
|
|
446
|
+
* For reusable nullish checks, use {@link isNil} or compose a named guard with
|
|
447
|
+
* {@link or} once and reuse it.
|
|
363
448
|
*
|
|
364
449
|
* @returns Predicate narrowing to `null`.
|
|
450
|
+
* @see isNil
|
|
365
451
|
*/
|
|
366
452
|
declare const isNull: Predicate<null>;
|
|
367
453
|
/**
|
|
@@ -604,19 +690,6 @@ declare function struct<const S extends SchemaShape<S>>(schema: S, options?: {
|
|
|
604
690
|
exact?: boolean;
|
|
605
691
|
}): Predicate<InferSchema<S>>;
|
|
606
692
|
|
|
607
|
-
type OptionalKeys<T> = {
|
|
608
|
-
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
609
|
-
}[keyof T];
|
|
610
|
-
type RequiredKeys<T> = Exclude<keyof T, OptionalKeys<T>>;
|
|
611
|
-
type TypedStructShape<T extends object> = {
|
|
612
|
-
readonly [K in Extract<RequiredKeys<T>, string>]-?: Predicate<T[K]>;
|
|
613
|
-
} & {
|
|
614
|
-
readonly [K in Extract<OptionalKeys<T>, string>]-?: OptionalSchemaField<Predicate<T[K]>>;
|
|
615
|
-
};
|
|
616
|
-
type NoExtraKeys<S, Shape> = S & {
|
|
617
|
-
readonly [K in Exclude<keyof S, keyof Shape>]: never;
|
|
618
|
-
};
|
|
619
|
-
type TypedStructFields<T extends object, S extends TypedStructShape<T>> = NoExtraKeys<S, TypedStructShape<T>>;
|
|
620
693
|
/**
|
|
621
694
|
* Creates a `struct` builder checked against an existing object type.
|
|
622
695
|
* Optional target keys must also be declared with `optionalKey` so type drift
|
|
@@ -690,4 +763,4 @@ declare const everyOwnEnumerableEntry: (values: Record<string, unknown>, keyPred
|
|
|
690
763
|
*/
|
|
691
764
|
declare const toBooleanPredicates: <A>(predicates: readonly ((value: A) => boolean)[]) => ReadonlyArray<(value: A) => boolean>;
|
|
692
765
|
|
|
693
|
-
export { type ChainResult, type Guard, type GuardedOf, type GuardedWithin, type InferSchema, type OptionalSchemaField, type OutOfGuards, type ParseResult, type Predicate, type Primitive, type Refine, type RefineChain, type Refinement, type Schema, type SchemaField, and, andAll, arrayOf, assert, define, equals, equalsBy, equalsKey, everyArrayValue, everyMapEntry, everyOwnEnumerableEntry, everySetValue, everyTupleValue, guardIn, hasKey, hasKeys, isArray, isArrayBuffer, isAsyncIterable, isBigInt, isBlob, isBoolean, isDataView, isDate, isError, isFile, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNil, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, lazy, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeJsonParse, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
|
|
766
|
+
export { type ChainResult, type Guard, type GuardedOf, type GuardedWithin, type InferSchema, type NoExtraKeys, type OptionalObjectKeys, type OptionalSchemaField, type OutOfGuards, type ParseResult, type Predicate, type Primitive, type Refine, type RefineChain, type Refinement, type RequiredObjectKeys, type Schema, type SchemaField, type TypedStructFields, type TypedStructShape, and, andAll, arrayOf, assert, define, equals, equalsBy, equalsKey, everyArrayValue, everyMapEntry, everyOwnEnumerableEntry, everySetValue, everyTupleValue, guardIn, hasKey, hasKeys, isArray, isArrayBuffer, isAsyncIterable, isBigInt, isBlob, isBoolean, isDataView, isDate, isError, isFile, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNil, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, lazy, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeJsonParse, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
|
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>;
|
|
@@ -55,6 +63,34 @@ type InferSchema<S extends SchemaShape<S>> = Simplify<{
|
|
|
55
63
|
} & {
|
|
56
64
|
readonly [K in OptionalSchemaKeys<S>]?: InferSchemaField<S[K]>;
|
|
57
65
|
}>;
|
|
66
|
+
/**
|
|
67
|
+
* Extracts optional keys from an object type.
|
|
68
|
+
*/
|
|
69
|
+
type OptionalObjectKeys<T> = {
|
|
70
|
+
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
71
|
+
}[keyof T];
|
|
72
|
+
/**
|
|
73
|
+
* Extracts required keys from an object type.
|
|
74
|
+
*/
|
|
75
|
+
type RequiredObjectKeys<T> = Exclude<keyof T, OptionalObjectKeys<T>>;
|
|
76
|
+
/**
|
|
77
|
+
* Schema shape checked against an existing object type by `typedStruct`.
|
|
78
|
+
*/
|
|
79
|
+
type TypedStructShape<T extends object> = {
|
|
80
|
+
readonly [K in Extract<RequiredObjectKeys<T>, string>]-?: Predicate<T[K]>;
|
|
81
|
+
} & {
|
|
82
|
+
readonly [K in Extract<OptionalObjectKeys<T>, string>]-?: OptionalSchemaField<Predicate<T[K]>>;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Keeps a schema type while rejecting keys outside the expected shape.
|
|
86
|
+
*/
|
|
87
|
+
type NoExtraKeys<S, Shape> = S & {
|
|
88
|
+
readonly [K in Exclude<keyof S, keyof Shape>]: never;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Field set accepted by `typedStruct` for a target object type.
|
|
92
|
+
*/
|
|
93
|
+
type TypedStructFields<T extends object, S extends TypedStructShape<T>> = NoExtraKeys<S, TypedStructShape<T>>;
|
|
58
94
|
|
|
59
95
|
/**
|
|
60
96
|
* Asserts that a value satisfies a guard or refinement, otherwise throws.
|
|
@@ -69,12 +105,18 @@ declare function assert<A, B extends A>(refine: Refine<A, B>, value: A, message?
|
|
|
69
105
|
|
|
70
106
|
/**
|
|
71
107
|
* Wraps a user function as a typed predicate.
|
|
108
|
+
* Prefer `define<T>(...)` when creating a reusable custom guard from a runtime
|
|
109
|
+
* boolean check.
|
|
72
110
|
*
|
|
73
111
|
* Note: The correctness of the predicate is the caller's responsibility.
|
|
74
112
|
* Its result is coerced to a boolean using `!!` for consistent guard behavior.
|
|
75
113
|
*
|
|
76
114
|
* @param fn Function that returns truthy when the value matches the target shape.
|
|
77
115
|
* @returns Predicate narrowing to the intended type when it returns true.
|
|
116
|
+
* @example
|
|
117
|
+
* const isSlug = define<string>(
|
|
118
|
+
* (value) => isString(value) && /^[a-z0-9-]+$/.test(value)
|
|
119
|
+
* );
|
|
78
120
|
*/
|
|
79
121
|
declare function define<T>(fn: (value: unknown) => value is T): Predicate<T>;
|
|
80
122
|
declare function define<T>(fn: (value: unknown) => boolean): Predicate<T>;
|
|
@@ -146,49 +188,76 @@ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
|
|
|
146
188
|
|
|
147
189
|
/**
|
|
148
190
|
* Combines a precondition guard with an additional refinement to narrow the type.
|
|
191
|
+
* Prefer this over hand-written `precondition(x) && condition(x)` when the
|
|
192
|
+
* composed predicate should be reused as a guard.
|
|
149
193
|
*
|
|
150
194
|
* @param precondition Broad guard evaluated first; short-circuits on failure.
|
|
151
195
|
* @param condition Refinement evaluated only when `precondition` passes.
|
|
152
196
|
* @returns Predicate that narrows the input to a subtype.
|
|
197
|
+
* @example
|
|
198
|
+
* const isPositiveNumber = and(
|
|
199
|
+
* isNumber,
|
|
200
|
+
* predicateToRefine<number>((value) => value > 0)
|
|
201
|
+
* );
|
|
202
|
+
* @see andAll
|
|
153
203
|
*/
|
|
154
204
|
declare function and<A, B extends A>(precondition: Guard<A>, condition: Refine<A, B>): Predicate<B>;
|
|
155
205
|
/**
|
|
156
206
|
* Chains a sequence of refinements after a precondition, returning the final guard type.
|
|
207
|
+
* Use this instead of nested `&&` checks when each step should keep narrowing
|
|
208
|
+
* the next refinement.
|
|
157
209
|
*
|
|
158
210
|
* @param precondition Initial guard applied first.
|
|
159
211
|
* @param steps Subsequent refinements applied in order.
|
|
160
212
|
* @returns Guard reflecting the result of the refinement chain.
|
|
213
|
+
* @example
|
|
214
|
+
* const isPublicTitle = andAll(isString, minLength(4), startsWithPublic);
|
|
215
|
+
* @see and
|
|
161
216
|
*/
|
|
162
217
|
declare function andAll<A>(precondition: Guard<A>): Guard<A>;
|
|
163
218
|
declare function andAll<A, B extends A>(precondition: Guard<A>, step1: Refine<A, B>): Guard<B>;
|
|
164
219
|
declare function andAll<A, B extends A, C extends B>(precondition: Guard<A>, step1: Refine<A, B>, step2: Refine<B, C>): Guard<C>;
|
|
165
220
|
/**
|
|
166
221
|
* Logical OR over multiple guards.
|
|
222
|
+
* Prefer this over hand-written `guardA(x) || guardB(x)` when the composed
|
|
223
|
+
* predicate should be reused as a guard.
|
|
167
224
|
*
|
|
168
225
|
* @param guards Guards to evaluate; passes if any guard passes.
|
|
169
226
|
* @returns Guard for the union of all guarded types.
|
|
227
|
+
* @example
|
|
228
|
+
* const isId = or(isString, isNumber);
|
|
229
|
+
* @see oneOf
|
|
170
230
|
*/
|
|
171
231
|
declare function or<P extends readonly Guard<unknown>[]>(...guards: P): Guard<OutOfGuards<P>>;
|
|
172
232
|
/**
|
|
173
233
|
* Adapts a guard so it can be used as a refinement within a known supertype.
|
|
174
234
|
*
|
|
175
235
|
* @returns Function that converts a `Guard<T>` into a `Refine<A, T>` when `T extends A`.
|
|
236
|
+
* @see and
|
|
176
237
|
*/
|
|
177
238
|
declare function guardIn<A>(): <T extends A>(guard: Guard<T>) => Refine<A, T>;
|
|
178
239
|
/**
|
|
179
240
|
* Logical negation of a guard/refinement.
|
|
241
|
+
* Use this when a negated predicate should be named and reused.
|
|
180
242
|
*
|
|
181
243
|
* @param guard Guard or refinement to negate.
|
|
182
244
|
* @returns Refinement excluding the guarded subtype from the input type.
|
|
245
|
+
* @example
|
|
246
|
+
* const isPresent = not(isNil);
|
|
183
247
|
*/
|
|
184
248
|
declare function not<A, T>(guard: Guard<T>): Refine<A, Exclude<A, Extract<A, T>>>;
|
|
185
249
|
declare function not<A, B extends A>(refine: Refine<A, B>): Refine<A, Exclude<A, B>>;
|
|
186
250
|
|
|
187
251
|
/**
|
|
188
252
|
* Allows `null` in addition to values accepted by the given guard/refinement.
|
|
253
|
+
* Use this instead of hand-writing `value === null || guard(value)` when the
|
|
254
|
+
* widened predicate should stay reusable.
|
|
189
255
|
*
|
|
190
256
|
* @param guard Guard/refinement for the base type.
|
|
191
257
|
* @returns Guard/refinement widened to include `null`.
|
|
258
|
+
* @example
|
|
259
|
+
* const isNullableString = nullable(isString);
|
|
260
|
+
* @see nullish
|
|
192
261
|
*/
|
|
193
262
|
declare function nullable<T>(guard: Guard<T>): Guard<T | null>;
|
|
194
263
|
declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null, B | null>;
|
|
@@ -197,22 +266,33 @@ declare function nullable<A, B extends A>(refine: Refine<A, B>): Refine<A | null
|
|
|
197
266
|
*
|
|
198
267
|
* @param guard Guard/refinement possibly including `null`.
|
|
199
268
|
* @returns Guard/refinement with `null` excluded.
|
|
269
|
+
* @example
|
|
270
|
+
* const isNonNullString = nonNull(nullable(isString));
|
|
200
271
|
*/
|
|
201
272
|
declare function nonNull<T>(guard: Guard<T>): Guard<Exclude<T, null>>;
|
|
202
273
|
declare function nonNull<A, B extends A>(refine: Refine<A, B>): Refine<Exclude<A, null>, Exclude<B, null>>;
|
|
203
274
|
/**
|
|
204
275
|
* Allows `null` or `undefined` in addition to values accepted by the guard.
|
|
276
|
+
* Use this instead of hand-writing `isNil(value) || guard(value)` when widening
|
|
277
|
+
* another guard.
|
|
205
278
|
*
|
|
206
279
|
* @param guard Guard/refinement for the base type.
|
|
207
280
|
* @returns Guard/refinement widened to include `null | undefined`.
|
|
281
|
+
* @example
|
|
282
|
+
* const isNullishString = nullish(isString);
|
|
283
|
+
* @see isNil
|
|
208
284
|
*/
|
|
209
285
|
declare function nullish<T>(guard: Guard<T>): Guard<T | null | undefined>;
|
|
210
286
|
declare function nullish<A, B extends A>(refine: Refine<A, B>): Refine<A | null | undefined, B | null | undefined>;
|
|
211
287
|
/**
|
|
212
288
|
* Allows `undefined` in addition to values accepted by the guard.
|
|
289
|
+
* Use this for value-level optionality. For optional object keys in `struct`,
|
|
290
|
+
* use `optionalKey(...)`.
|
|
213
291
|
*
|
|
214
292
|
* @param guard Guard/refinement for the base type.
|
|
215
293
|
* @returns Guard/refinement widened to include `undefined`.
|
|
294
|
+
* @example
|
|
295
|
+
* const isOptionalString = optional(isString);
|
|
216
296
|
*/
|
|
217
297
|
declare function optional<T>(guard: Guard<T>): Guard<T | undefined>;
|
|
218
298
|
declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | undefined, B | undefined>;
|
|
@@ -221,6 +301,8 @@ declare function optional<A, B extends A>(refine: Refine<A, B>): Refine<A | unde
|
|
|
221
301
|
*
|
|
222
302
|
* @param guard Guard/refinement that may accept `undefined`.
|
|
223
303
|
* @returns Guard/refinement with `undefined` removed.
|
|
304
|
+
* @example
|
|
305
|
+
* const isRequiredString = required(optional(isString));
|
|
224
306
|
*/
|
|
225
307
|
declare function required<T>(guard: Guard<T | undefined>): Guard<T>;
|
|
226
308
|
declare function required<A, B extends A>(refine: Refine<A | undefined, B | undefined>): Refine<A, B>;
|
|
@@ -351,17 +433,21 @@ declare const isSymbol: Predicate<symbol>;
|
|
|
351
433
|
/**
|
|
352
434
|
* Checks whether a value is exactly `undefined`.
|
|
353
435
|
*
|
|
354
|
-
*
|
|
436
|
+
* For reusable nullish checks, use {@link isNil} or compose a named guard with
|
|
437
|
+
* {@link or} once and reuse it.
|
|
355
438
|
*
|
|
356
439
|
* @returns Predicate narrowing to `undefined`.
|
|
440
|
+
* @see isNil
|
|
357
441
|
*/
|
|
358
442
|
declare const isUndefined: Predicate<undefined>;
|
|
359
443
|
/**
|
|
360
444
|
* Checks whether a value is exactly `null`.
|
|
361
445
|
*
|
|
362
|
-
*
|
|
446
|
+
* For reusable nullish checks, use {@link isNil} or compose a named guard with
|
|
447
|
+
* {@link or} once and reuse it.
|
|
363
448
|
*
|
|
364
449
|
* @returns Predicate narrowing to `null`.
|
|
450
|
+
* @see isNil
|
|
365
451
|
*/
|
|
366
452
|
declare const isNull: Predicate<null>;
|
|
367
453
|
/**
|
|
@@ -604,19 +690,6 @@ declare function struct<const S extends SchemaShape<S>>(schema: S, options?: {
|
|
|
604
690
|
exact?: boolean;
|
|
605
691
|
}): Predicate<InferSchema<S>>;
|
|
606
692
|
|
|
607
|
-
type OptionalKeys<T> = {
|
|
608
|
-
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
|
|
609
|
-
}[keyof T];
|
|
610
|
-
type RequiredKeys<T> = Exclude<keyof T, OptionalKeys<T>>;
|
|
611
|
-
type TypedStructShape<T extends object> = {
|
|
612
|
-
readonly [K in Extract<RequiredKeys<T>, string>]-?: Predicate<T[K]>;
|
|
613
|
-
} & {
|
|
614
|
-
readonly [K in Extract<OptionalKeys<T>, string>]-?: OptionalSchemaField<Predicate<T[K]>>;
|
|
615
|
-
};
|
|
616
|
-
type NoExtraKeys<S, Shape> = S & {
|
|
617
|
-
readonly [K in Exclude<keyof S, keyof Shape>]: never;
|
|
618
|
-
};
|
|
619
|
-
type TypedStructFields<T extends object, S extends TypedStructShape<T>> = NoExtraKeys<S, TypedStructShape<T>>;
|
|
620
693
|
/**
|
|
621
694
|
* Creates a `struct` builder checked against an existing object type.
|
|
622
695
|
* Optional target keys must also be declared with `optionalKey` so type drift
|
|
@@ -690,4 +763,4 @@ declare const everyOwnEnumerableEntry: (values: Record<string, unknown>, keyPred
|
|
|
690
763
|
*/
|
|
691
764
|
declare const toBooleanPredicates: <A>(predicates: readonly ((value: A) => boolean)[]) => ReadonlyArray<(value: A) => boolean>;
|
|
692
765
|
|
|
693
|
-
export { type ChainResult, type Guard, type GuardedOf, type GuardedWithin, type InferSchema, type OptionalSchemaField, type OutOfGuards, type ParseResult, type Predicate, type Primitive, type Refine, type RefineChain, type Refinement, type Schema, type SchemaField, and, andAll, arrayOf, assert, define, equals, equalsBy, equalsKey, everyArrayValue, everyMapEntry, everyOwnEnumerableEntry, everySetValue, everyTupleValue, guardIn, hasKey, hasKeys, isArray, isArrayBuffer, isAsyncIterable, isBigInt, isBlob, isBoolean, isDataView, isDate, isError, isFile, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNil, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, lazy, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeJsonParse, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
|
|
766
|
+
export { type ChainResult, type Guard, type GuardedOf, type GuardedWithin, type InferSchema, type NoExtraKeys, type OptionalObjectKeys, type OptionalSchemaField, type OutOfGuards, type ParseResult, type Predicate, type Primitive, type Refine, type RefineChain, type Refinement, type RequiredObjectKeys, type Schema, type SchemaField, type TypedStructFields, type TypedStructShape, and, andAll, arrayOf, assert, define, equals, equalsBy, equalsKey, everyArrayValue, everyMapEntry, everyOwnEnumerableEntry, everySetValue, everyTupleValue, guardIn, hasKey, hasKeys, isArray, isArrayBuffer, isAsyncIterable, isBigInt, isBlob, isBoolean, isDataView, isDate, isError, isFile, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNil, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, lazy, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeJsonParse, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
|
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) &&
|
|
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) &&
|
|
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) &&
|
|
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]) =>
|
|
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(
|
|
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 (!
|
|
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) &&
|
|
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) &&
|
|
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) &&
|
|
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]) =>
|
|
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(
|
|
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 (!
|
|
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.
|
|
3
|
+
"version": "1.11.2",
|
|
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
|
],
|