is-kit 1.8.2 → 1.10.0

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
@@ -116,6 +116,7 @@ This is the core idea of `is-kit`:
116
116
  If you are new to the library, these are the pieces to remember:
117
117
 
118
118
  - `define<T>(fn)` turns a boolean check into a typed guard.
119
+ - `lazy(factory)` defers a guard definition so recursive structures can refer to themselves.
119
120
  - `predicateToRefine(fn)` upgrades an existing predicate so it can participate in narrowing chains.
120
121
  - `struct({...})` builds an object-shape guard.
121
122
  - `safeParse(guard, value)` gives you a small tagged result object.
@@ -224,7 +225,31 @@ import { oneOfValues } from 'is-kit';
224
225
  const isStatus = oneOfValues('draft', 'published', 'archived');
225
226
  ```
226
227
 
227
- ### 6. Handle null and undefined explicitly
228
+ ### 6. Validate recursive structures
229
+
230
+ Use `lazy` when a guard needs to refer to itself. The factory runs on first use,
231
+ and the resulting guard is cached.
232
+
233
+ ```ts
234
+ import { arrayOf, isString, lazy, typedStruct } from 'is-kit';
235
+ import type { Predicate } from 'is-kit';
236
+
237
+ type Tree = {
238
+ readonly value: string;
239
+ readonly children: readonly Tree[];
240
+ };
241
+
242
+ const isTree: Predicate<Tree> = lazy(() =>
243
+ typedStruct<Tree>()({
244
+ value: isString,
245
+ children: arrayOf(isTree)
246
+ })
247
+ );
248
+ ```
249
+
250
+ `lazy` does not detect circular references in the input value.
251
+
252
+ ### 7. Handle null and undefined explicitly
228
253
 
229
254
  Use the nullish helpers to say exactly what is allowed.
230
255
 
@@ -245,7 +270,7 @@ const isDefinedString = required(optional(isString));
245
270
  const isNonNullString = nonNull(nullable(isString));
246
271
  ```
247
272
 
248
- ### 7. Parse or assert unknown input
273
+ ### 8. Parse or assert unknown input
249
274
 
250
275
  Use `safeParse` when you want a result object, and `assert` when invalid data should stop execution.
251
276
 
@@ -264,7 +289,39 @@ assert(isString, input, 'Expected a string');
264
289
  input.toUpperCase();
265
290
  ```
266
291
 
267
- ### 8. Narrow object keys
292
+ ### 9. Decode and validate JSON input
293
+
294
+ Use `safeJsonParse` at a JSON text boundary. It decodes the text, treats the
295
+ result as `unknown`, and only returns the value after the guard accepts it.
296
+ Invalid JSON and guard mismatches both return `{ valid: false }`; values are not
297
+ coerced to satisfy the guard.
298
+
299
+ ```ts
300
+ import { isString, safeJsonParse, typedStruct } from 'is-kit';
301
+
302
+ type User = {
303
+ id: string;
304
+ name: string;
305
+ };
306
+
307
+ const isUser = typedStruct<User>()({
308
+ id: isString,
309
+ name: isString
310
+ });
311
+
312
+ declare const input: string;
313
+ const result = safeJsonParse(input, isUser);
314
+
315
+ if (result.valid) {
316
+ result.value.name.toUpperCase();
317
+ }
318
+ ```
319
+
320
+ `safeJsonParse` is a decode-then-guard helper. It does not perform schema
321
+ coercion and does not depend on a transport or schema format such as HTTP or
322
+ OpenAPI.
323
+
324
+ ### 10. Narrow object keys
268
325
 
269
326
  Use key helpers when the important part of a value is one property.
270
327
 
@@ -378,7 +435,7 @@ The library is organized around a few small building blocks:
378
435
  - **Collections**: `arrayOf`, `nonEmptyArrayOf`, `tupleOf`, `setOf`, `mapOf`, `recordOf`
379
436
  - **Literals**: `oneOfValues`, `equals`, `equalsBy`, `equalsKey`
380
437
  - **Nullish handling**: `nullable`, `nonNull`, `nullish`, `optional`, `required`
381
- - **Result helpers**: `safeParse`, `safeParseWith`, `assert`
438
+ - **Result helpers**: `safeParse`, `safeParseWith`, `safeJsonParse`, `assert`
382
439
 
383
440
  For the full API list and dedicated pages, use the docs site below.
384
441
 
package/dist/index.d.mts CHANGED
@@ -133,6 +133,17 @@ declare const hasKeys: <const KS extends readonly [PropertyKey, ...PropertyKey[]
133
133
  */
134
134
  declare function narrowKeyTo<A, K extends keyof A>(guard: Guard<A>, key: K): <const T extends A[K]>(target: T) => Predicate<A & Record<K, T>>;
135
135
 
136
+ /**
137
+ * Creates a predicate whose implementation is initialized on first use.
138
+ *
139
+ * The initialized predicate is cached after the factory returns successfully.
140
+ * Circular references in the input value are not detected.
141
+ *
142
+ * @param factory Function that creates the predicate when it is first evaluated.
143
+ * @returns Predicate that delegates to the lazily initialized implementation.
144
+ */
145
+ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
146
+
136
147
  /**
137
148
  * Combines a precondition guard with an additional refinement to narrow the type.
138
149
  *
@@ -232,6 +243,14 @@ declare function safeParse(fn: (value: unknown) => boolean, value: unknown): Par
232
243
  */
233
244
  declare function safeParseWith<T>(guard: Guard<T>): (value: unknown) => ParseResult<T>;
234
245
  declare function safeParseWith<A, B extends A>(refine: Refine<A, B>): (value: A) => ParseResult<B>;
246
+ /**
247
+ * Decodes JSON text and validates the decoded value without coercion.
248
+ *
249
+ * @param input JSON text to decode.
250
+ * @param guard Guard used to validate the decoded `unknown` value.
251
+ * @returns The decoded value when valid; `{ valid: false }` for invalid JSON or a guard mismatch.
252
+ */
253
+ declare function safeJsonParse<T>(input: string, guard: Predicate<T>): ParseResult<T>;
235
254
 
236
255
  /**
237
256
  * Converts a boolean predicate into a refinement preserving the input type.
@@ -645,4 +664,4 @@ declare const everyOwnEnumerableEntry: (values: Record<string, unknown>, keyPred
645
664
  */
646
665
  declare const toBooleanPredicates: <A>(predicates: readonly ((value: A) => boolean)[]) => ReadonlyArray<(value: A) => boolean>;
647
666
 
648
- 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, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
667
+ 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, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, 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
@@ -133,6 +133,17 @@ declare const hasKeys: <const KS extends readonly [PropertyKey, ...PropertyKey[]
133
133
  */
134
134
  declare function narrowKeyTo<A, K extends keyof A>(guard: Guard<A>, key: K): <const T extends A[K]>(target: T) => Predicate<A & Record<K, T>>;
135
135
 
136
+ /**
137
+ * Creates a predicate whose implementation is initialized on first use.
138
+ *
139
+ * The initialized predicate is cached after the factory returns successfully.
140
+ * Circular references in the input value are not detected.
141
+ *
142
+ * @param factory Function that creates the predicate when it is first evaluated.
143
+ * @returns Predicate that delegates to the lazily initialized implementation.
144
+ */
145
+ declare function lazy<T>(factory: () => Predicate<T>): Predicate<T>;
146
+
136
147
  /**
137
148
  * Combines a precondition guard with an additional refinement to narrow the type.
138
149
  *
@@ -232,6 +243,14 @@ declare function safeParse(fn: (value: unknown) => boolean, value: unknown): Par
232
243
  */
233
244
  declare function safeParseWith<T>(guard: Guard<T>): (value: unknown) => ParseResult<T>;
234
245
  declare function safeParseWith<A, B extends A>(refine: Refine<A, B>): (value: A) => ParseResult<B>;
246
+ /**
247
+ * Decodes JSON text and validates the decoded value without coercion.
248
+ *
249
+ * @param input JSON text to decode.
250
+ * @param guard Guard used to validate the decoded `unknown` value.
251
+ * @returns The decoded value when valid; `{ valid: false }` for invalid JSON or a guard mismatch.
252
+ */
253
+ declare function safeJsonParse<T>(input: string, guard: Predicate<T>): ParseResult<T>;
235
254
 
236
255
  /**
237
256
  * Converts a boolean predicate into a refinement preserving the input type.
@@ -645,4 +664,4 @@ declare const everyOwnEnumerableEntry: (values: Record<string, unknown>, keyPred
645
664
  */
646
665
  declare const toBooleanPredicates: <A>(predicates: readonly ((value: A) => boolean)[]) => ReadonlyArray<(value: A) => boolean>;
647
666
 
648
- 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, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, isNull, isNumber, isNumberPrimitive, isObject, isPlainObject, isPositive, isPrimitive, isPromiseLike, isRegExp, isSafeInteger, isSet, isString, isSymbol, isTypedArray, isURL, isUndefined, isWeakMap, isWeakSet, isZero, mapOf, narrowKeyTo, nonEmptyArrayOf, nonNull, not, nullable, nullish, oneOf, oneOfValues, optional, optionalKey, or, predicateToRefine, recordOf, required, safeParse, safeParseWith, setOf, struct, toBooleanPredicates, tupleOf, typedStruct };
667
+ 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, isFiniteNumber, isFunction, isInfiniteNumber, isInstanceOf, isInteger, isIterable, isMap, isNaN, isNegative, 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
@@ -73,6 +73,7 @@ __export(index_exports, {
73
73
  isWeakMap: () => isWeakMap,
74
74
  isWeakSet: () => isWeakSet,
75
75
  isZero: () => isZero,
76
+ lazy: () => lazy,
76
77
  mapOf: () => mapOf,
77
78
  narrowKeyTo: () => narrowKeyTo,
78
79
  nonEmptyArrayOf: () => nonEmptyArrayOf,
@@ -88,6 +89,7 @@ __export(index_exports, {
88
89
  predicateToRefine: () => predicateToRefine,
89
90
  recordOf: () => recordOf,
90
91
  required: () => required,
92
+ safeJsonParse: () => safeJsonParse,
91
93
  safeParse: () => safeParse,
92
94
  safeParseWith: () => safeParseWith,
93
95
  setOf: () => setOf,
@@ -219,6 +221,15 @@ function narrowKeyTo(guard, key) {
219
221
  };
220
222
  }
221
223
 
224
+ // src/core/lazy.ts
225
+ function lazy(factory) {
226
+ let predicate;
227
+ return (value) => {
228
+ predicate ??= factory();
229
+ return predicate(value);
230
+ };
231
+ }
232
+
222
233
  // src/utils/guard-collections.ts
223
234
  var everyArrayValue = (values, predicate) => {
224
235
  for (const value of values) {
@@ -317,6 +328,15 @@ function safeParse(fn, value) {
317
328
  function safeParseWith(fn) {
318
329
  return (value) => safeParse(fn, value);
319
330
  }
331
+ function safeJsonParse(input, guard) {
332
+ let value;
333
+ try {
334
+ value = JSON.parse(input);
335
+ } catch {
336
+ return { valid: false };
337
+ }
338
+ return safeParse(guard, value);
339
+ }
320
340
 
321
341
  // src/core/predicate.ts
322
342
  var predicateToRefine = (fn) => (value) => fn(value);
@@ -550,6 +570,7 @@ function tupleOf(...guards) {
550
570
  isWeakMap,
551
571
  isWeakSet,
552
572
  isZero,
573
+ lazy,
553
574
  mapOf,
554
575
  narrowKeyTo,
555
576
  nonEmptyArrayOf,
@@ -565,6 +586,7 @@ function tupleOf(...guards) {
565
586
  predicateToRefine,
566
587
  recordOf,
567
588
  required,
589
+ safeJsonParse,
568
590
  safeParse,
569
591
  safeParseWith,
570
592
  setOf,
package/dist/index.mjs CHANGED
@@ -119,6 +119,15 @@ function narrowKeyTo(guard, key) {
119
119
  };
120
120
  }
121
121
 
122
+ // src/core/lazy.ts
123
+ function lazy(factory) {
124
+ let predicate;
125
+ return (value) => {
126
+ predicate ??= factory();
127
+ return predicate(value);
128
+ };
129
+ }
130
+
122
131
  // src/utils/guard-collections.ts
123
132
  var everyArrayValue = (values, predicate) => {
124
133
  for (const value of values) {
@@ -217,6 +226,15 @@ function safeParse(fn, value) {
217
226
  function safeParseWith(fn) {
218
227
  return (value) => safeParse(fn, value);
219
228
  }
229
+ function safeJsonParse(input, guard) {
230
+ let value;
231
+ try {
232
+ value = JSON.parse(input);
233
+ } catch {
234
+ return { valid: false };
235
+ }
236
+ return safeParse(guard, value);
237
+ }
220
238
 
221
239
  // src/core/predicate.ts
222
240
  var predicateToRefine = (fn) => (value) => fn(value);
@@ -449,6 +467,7 @@ export {
449
467
  isWeakMap,
450
468
  isWeakSet,
451
469
  isZero,
470
+ lazy,
452
471
  mapOf,
453
472
  narrowKeyTo,
454
473
  nonEmptyArrayOf,
@@ -464,6 +483,7 @@ export {
464
483
  predicateToRefine,
465
484
  recordOf,
466
485
  required,
486
+ safeJsonParse,
467
487
  safeParse,
468
488
  safeParseWith,
469
489
  setOf,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "is-kit",
3
- "version": "1.8.2",
3
+ "version": "1.10.0",
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",