@evolu/common 8.9.0 → 8.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/dist/src/Bytes.d.ts +647 -0
- package/dist/src/Bytes.d.ts.map +1 -0
- package/dist/src/{Binary.js → Bytes.js} +266 -16
- package/dist/src/Config.d.ts +142 -0
- package/dist/src/Config.d.ts.map +1 -0
- package/dist/src/Config.js +181 -0
- package/dist/src/Fs.d.ts +302 -0
- package/dist/src/Fs.d.ts.map +1 -0
- package/dist/src/Fs.js +111 -0
- package/dist/src/Number.d.ts +50 -7
- package/dist/src/Number.d.ts.map +1 -1
- package/dist/src/Number.js +47 -8
- package/dist/src/Object.d.ts +32 -0
- package/dist/src/Object.d.ts.map +1 -1
- package/dist/src/Object.js +41 -0
- package/dist/src/Sqlite.js +1 -1
- package/dist/src/Time.d.ts +74 -12
- package/dist/src/Time.d.ts.map +1 -1
- package/dist/src/Time.js +40 -2
- package/dist/src/Type.d.ts +1451 -79
- package/dist/src/Type.d.ts.map +1 -1
- package/dist/src/Type.js +1303 -96
- package/dist/src/index.d.ts +3 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/intl/_en.d.ts +24 -1
- package/dist/src/intl/_en.d.ts.map +1 -1
- package/dist/src/intl/_en.js +20 -0
- package/dist/src/intl/ar.d.ts +24 -1
- package/dist/src/intl/ar.d.ts.map +1 -1
- package/dist/src/intl/ar.js +20 -0
- package/dist/src/intl/bn.d.ts +24 -1
- package/dist/src/intl/bn.d.ts.map +1 -1
- package/dist/src/intl/bn.js +20 -0
- package/dist/src/intl/ca.d.ts +24 -1
- package/dist/src/intl/ca.d.ts.map +1 -1
- package/dist/src/intl/ca.js +20 -0
- package/dist/src/intl/cs.d.ts +24 -1
- package/dist/src/intl/cs.d.ts.map +1 -1
- package/dist/src/intl/cs.js +20 -0
- package/dist/src/intl/da.d.ts +24 -1
- package/dist/src/intl/da.d.ts.map +1 -1
- package/dist/src/intl/da.js +20 -0
- package/dist/src/intl/de.d.ts +24 -1
- package/dist/src/intl/de.d.ts.map +1 -1
- package/dist/src/intl/de.js +20 -0
- package/dist/src/intl/el.d.ts +24 -1
- package/dist/src/intl/el.d.ts.map +1 -1
- package/dist/src/intl/el.js +20 -0
- package/dist/src/intl/es.d.ts +24 -1
- package/dist/src/intl/es.d.ts.map +1 -1
- package/dist/src/intl/es.js +20 -0
- package/dist/src/intl/fa.d.ts +24 -1
- package/dist/src/intl/fa.d.ts.map +1 -1
- package/dist/src/intl/fa.js +20 -0
- package/dist/src/intl/fi.d.ts +24 -1
- package/dist/src/intl/fi.d.ts.map +1 -1
- package/dist/src/intl/fi.js +20 -0
- package/dist/src/intl/fil.d.ts +24 -1
- package/dist/src/intl/fil.d.ts.map +1 -1
- package/dist/src/intl/fil.js +20 -0
- package/dist/src/intl/fr.d.ts +24 -1
- package/dist/src/intl/fr.d.ts.map +1 -1
- package/dist/src/intl/fr.js +20 -0
- package/dist/src/intl/he.d.ts +24 -1
- package/dist/src/intl/he.d.ts.map +1 -1
- package/dist/src/intl/he.js +20 -0
- package/dist/src/intl/hi.d.ts +24 -1
- package/dist/src/intl/hi.d.ts.map +1 -1
- package/dist/src/intl/hi.js +20 -0
- package/dist/src/intl/hr.d.ts +24 -1
- package/dist/src/intl/hr.d.ts.map +1 -1
- package/dist/src/intl/hr.js +20 -0
- package/dist/src/intl/hu.d.ts +22 -1
- package/dist/src/intl/hu.d.ts.map +1 -1
- package/dist/src/intl/hu.js +18 -0
- package/dist/src/intl/id.d.ts +24 -1
- package/dist/src/intl/id.d.ts.map +1 -1
- package/dist/src/intl/id.js +20 -0
- package/dist/src/intl/it.d.ts +24 -1
- package/dist/src/intl/it.d.ts.map +1 -1
- package/dist/src/intl/it.js +20 -0
- package/dist/src/intl/ja.d.ts +24 -1
- package/dist/src/intl/ja.d.ts.map +1 -1
- package/dist/src/intl/ja.js +20 -0
- package/dist/src/intl/ko.d.ts +24 -1
- package/dist/src/intl/ko.d.ts.map +1 -1
- package/dist/src/intl/ko.js +20 -0
- package/dist/src/intl/ml.d.ts +24 -1
- package/dist/src/intl/ml.d.ts.map +1 -1
- package/dist/src/intl/ml.js +20 -0
- package/dist/src/intl/mr.d.ts +24 -1
- package/dist/src/intl/mr.d.ts.map +1 -1
- package/dist/src/intl/mr.js +20 -0
- package/dist/src/intl/ms.d.ts +24 -1
- package/dist/src/intl/ms.d.ts.map +1 -1
- package/dist/src/intl/ms.js +20 -0
- package/dist/src/intl/nb.d.ts +22 -1
- package/dist/src/intl/nb.d.ts.map +1 -1
- package/dist/src/intl/nb.js +18 -0
- package/dist/src/intl/nl.d.ts +24 -1
- package/dist/src/intl/nl.d.ts.map +1 -1
- package/dist/src/intl/nl.js +20 -0
- package/dist/src/intl/pa.d.ts +24 -1
- package/dist/src/intl/pa.d.ts.map +1 -1
- package/dist/src/intl/pa.js +20 -0
- package/dist/src/intl/pl.d.ts +23 -0
- package/dist/src/intl/pl.d.ts.map +1 -1
- package/dist/src/intl/pl.js +20 -0
- package/dist/src/intl/pt-BR.d.ts +24 -1
- package/dist/src/intl/pt-BR.d.ts.map +1 -1
- package/dist/src/intl/pt-BR.js +20 -0
- package/dist/src/intl/pt.d.ts +24 -1
- package/dist/src/intl/pt.d.ts.map +1 -1
- package/dist/src/intl/pt.js +20 -0
- package/dist/src/intl/ro.d.ts +24 -1
- package/dist/src/intl/ro.d.ts.map +1 -1
- package/dist/src/intl/ro.js +20 -0
- package/dist/src/intl/sk.d.ts +24 -1
- package/dist/src/intl/sk.d.ts.map +1 -1
- package/dist/src/intl/sk.js +20 -0
- package/dist/src/intl/sl.d.ts +24 -1
- package/dist/src/intl/sl.d.ts.map +1 -1
- package/dist/src/intl/sl.js +20 -0
- package/dist/src/intl/sv.d.ts +24 -1
- package/dist/src/intl/sv.d.ts.map +1 -1
- package/dist/src/intl/sv.js +20 -0
- package/dist/src/intl/sw.d.ts +21 -0
- package/dist/src/intl/sw.d.ts.map +1 -1
- package/dist/src/intl/sw.js +18 -0
- package/dist/src/intl/ta.d.ts +24 -1
- package/dist/src/intl/ta.d.ts.map +1 -1
- package/dist/src/intl/ta.js +20 -0
- package/dist/src/intl/te.d.ts +24 -1
- package/dist/src/intl/te.d.ts.map +1 -1
- package/dist/src/intl/te.js +20 -0
- package/dist/src/intl/th.d.ts +24 -1
- package/dist/src/intl/th.d.ts.map +1 -1
- package/dist/src/intl/th.js +20 -0
- package/dist/src/intl/tr.d.ts +24 -1
- package/dist/src/intl/tr.d.ts.map +1 -1
- package/dist/src/intl/tr.js +20 -0
- package/dist/src/intl/uk.d.ts +80 -57
- package/dist/src/intl/uk.d.ts.map +1 -1
- package/dist/src/intl/uk.js +174 -149
- package/dist/src/intl/ur.d.ts +24 -1
- package/dist/src/intl/ur.d.ts.map +1 -1
- package/dist/src/intl/ur.js +20 -0
- package/dist/src/intl/vi.d.ts +24 -1
- package/dist/src/intl/vi.d.ts.map +1 -1
- package/dist/src/intl/vi.js +20 -0
- package/dist/src/intl/zh-CN.d.ts +24 -1
- package/dist/src/intl/zh-CN.d.ts.map +1 -1
- package/dist/src/intl/zh-CN.js +20 -0
- package/dist/src/intl/zh-TW.d.ts +24 -1
- package/dist/src/intl/zh-TW.d.ts.map +1 -1
- package/dist/src/intl/zh-TW.js +20 -0
- package/dist/src/local-first/Protocol.d.ts +1 -1
- package/dist/src/local-first/Protocol.d.ts.map +1 -1
- package/dist/src/local-first/Protocol.js +1 -1
- package/dist/src/local-first/Schema.d.ts +10 -0
- package/dist/src/local-first/Schema.d.ts.map +1 -1
- package/dist/src/local-first/Storage.js +1 -1
- package/dist/src/local-first/Timestamp.js +1 -1
- package/package.json +1 -1
- package/src/{Binary.test.ts → Bytes.test.ts} +286 -1
- package/src/{Binary.ts → Bytes.ts} +652 -21
- package/src/Config.test.ts +672 -0
- package/src/Config.ts +410 -0
- package/src/Fs.test.ts +105 -0
- package/src/Fs.ts +414 -0
- package/src/Number.test.ts +82 -18
- package/src/Number.ts +76 -8
- package/src/Object.test.ts +115 -1
- package/src/Object.ts +44 -0
- package/src/Sqlite.ts +1 -1
- package/src/Time.test.ts +82 -11
- package/src/Time.ts +141 -16
- package/src/Type.test.ts +3114 -157
- package/src/Type.ts +2553 -196
- package/src/index.ts +3 -1
- package/src/intl/_en.ts +70 -0
- package/src/intl/ar.ts +71 -0
- package/src/intl/bn.ts +70 -0
- package/src/intl/ca.ts +70 -0
- package/src/intl/cs.ts +70 -0
- package/src/intl/da.ts +70 -0
- package/src/intl/de.ts +70 -0
- package/src/intl/el.ts +70 -0
- package/src/intl/es.ts +70 -0
- package/src/intl/fa.ts +70 -0
- package/src/intl/fi.ts +70 -0
- package/src/intl/fil.ts +70 -0
- package/src/intl/fr.ts +70 -0
- package/src/intl/he.ts +70 -0
- package/src/intl/hi.ts +70 -0
- package/src/intl/hr.ts +70 -0
- package/src/intl/hu.ts +69 -0
- package/src/intl/id.ts +70 -0
- package/src/intl/intl.test.ts +819 -1
- package/src/intl/it.ts +70 -0
- package/src/intl/ja.ts +70 -0
- package/src/intl/ko.ts +68 -0
- package/src/intl/ml.ts +70 -0
- package/src/intl/mr.ts +70 -0
- package/src/intl/ms.ts +71 -0
- package/src/intl/nb.ts +69 -0
- package/src/intl/nl.ts +70 -0
- package/src/intl/pa.ts +70 -0
- package/src/intl/pl.ts +63 -0
- package/src/intl/pt-BR.ts +70 -0
- package/src/intl/pt.ts +71 -0
- package/src/intl/ro.ts +70 -0
- package/src/intl/sk.ts +71 -0
- package/src/intl/sl.ts +70 -0
- package/src/intl/sv.ts +70 -0
- package/src/intl/sw.ts +62 -0
- package/src/intl/ta.ts +70 -0
- package/src/intl/te.ts +70 -0
- package/src/intl/th.ts +68 -0
- package/src/intl/tr.ts +70 -0
- package/src/intl/uk.ts +228 -155
- package/src/intl/ur.ts +70 -0
- package/src/intl/vi.ts +70 -0
- package/src/intl/zh-CN.ts +68 -0
- package/src/intl/zh-TW.ts +68 -0
- package/src/local-first/Protocol.test.ts +1 -1
- package/src/local-first/Protocol.ts +1 -1
- package/src/local-first/Schema.ts +11 -0
- package/src/local-first/Storage.ts +1 -1
- package/src/local-first/Timestamp.ts +1 -1
- package/dist/src/Binary.d.ts +0 -254
- package/dist/src/Binary.d.ts.map +0 -1
package/dist/src/Type.d.ts
CHANGED
|
@@ -236,15 +236,22 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
236
236
|
*/
|
|
237
237
|
readonly to: [Parent] extends [infer P extends TypeNode] ? ToOperation<Output, CanonicalInput, P> : (value: Output) => CanonicalInput;
|
|
238
238
|
/**
|
|
239
|
-
*
|
|
240
|
-
*
|
|
239
|
+
* Runs the deepest `from` operation, which accepts this Type's `Input`, and
|
|
240
|
+
* returns its decoded value or throws an Error.
|
|
241
|
+
*
|
|
242
|
+
* Returned validation errors use this Type's {@link Type.formatError} as the
|
|
243
|
+
* Error message and preserve the original validation error as `cause`. With
|
|
244
|
+
* `{ errors: "all" }`, the cause retains all collected errors; the message
|
|
245
|
+
* still follows `formatError`, which describes the first issue.
|
|
241
246
|
*
|
|
242
247
|
* The typed `Input` boundary is asserted before the remaining pipeline runs.
|
|
243
|
-
* A boundary violation is a bug, so it throws directly
|
|
244
|
-
*
|
|
248
|
+
* A boundary violation is a bug, so it throws directly with its assertion
|
|
249
|
+
* message instead of formatting a returned validation error.
|
|
245
250
|
*
|
|
246
251
|
* `Type.orThrow.parent(value)` does not exist. To throw after starting from a
|
|
247
|
-
* typed boundary, call
|
|
252
|
+
* typed boundary, call {@link getOrThrow} with the corresponding `from`
|
|
253
|
+
* operation. Its generic Error message differs from this operation's
|
|
254
|
+
* message.
|
|
248
255
|
*
|
|
249
256
|
* Use `orThrow` for startup and configuration, module constants, test
|
|
250
257
|
* fixtures, and internal invariants where failure must stop the current flow.
|
|
@@ -256,20 +263,31 @@ export interface Type<Name extends TypeName, in out Input, in out Output, Error
|
|
|
256
263
|
* ```ts
|
|
257
264
|
* import {
|
|
258
265
|
* assertEqual,
|
|
259
|
-
*
|
|
266
|
+
* assertInstanceOf,
|
|
267
|
+
* assertErr,
|
|
260
268
|
* minLength,
|
|
261
269
|
* String,
|
|
270
|
+
* trySync,
|
|
262
271
|
* } from "@evolu/common";
|
|
263
272
|
*
|
|
264
273
|
* const NonEmptyString = minLength(1)(String);
|
|
265
274
|
*
|
|
266
275
|
* const value = NonEmptyString.orThrow("Evolu");
|
|
267
276
|
*
|
|
268
|
-
* // Equivalent because `from.parent` is this Type's deepest `from` operation:
|
|
269
|
-
* const sameValue = getOrThrow(NonEmptyString.from.parent("Evolu"));
|
|
270
|
-
*
|
|
271
277
|
* assertEqual(value, "Evolu");
|
|
272
|
-
*
|
|
278
|
+
*
|
|
279
|
+
* const failed = trySync(() => NonEmptyString.orThrow(""));
|
|
280
|
+
* assertErr(failed);
|
|
281
|
+
* assertInstanceOf(failed.error, Error);
|
|
282
|
+
* assertEqual(
|
|
283
|
+
* failed.error.message,
|
|
284
|
+
* 'The value "" does not meet the minimum length of 1.',
|
|
285
|
+
* );
|
|
286
|
+
* assertEqual(failed.error.cause, {
|
|
287
|
+
* type: "MinLength1",
|
|
288
|
+
* value: "",
|
|
289
|
+
* min: 1,
|
|
290
|
+
* });
|
|
273
291
|
* ```
|
|
274
292
|
*/
|
|
275
293
|
readonly orThrow: TypeOperationFn<"orThrow", Input, Output, never>;
|
|
@@ -355,6 +373,50 @@ export interface TypeValueError<Name extends TypeName = TypeName> extends TypeEr
|
|
|
355
373
|
* @group Core
|
|
356
374
|
*/
|
|
357
375
|
export type TypeErrorFormatter<Error extends TypeError> = (error: Error) => string;
|
|
376
|
+
/**
|
|
377
|
+
* A formatted validation issue located by its path from the root value.
|
|
378
|
+
*
|
|
379
|
+
* @group Core
|
|
380
|
+
*/
|
|
381
|
+
export interface TypeIssue {
|
|
382
|
+
readonly path: ReadonlyArray<PropertyKey>;
|
|
383
|
+
readonly message: string;
|
|
384
|
+
}
|
|
385
|
+
/**
|
|
386
|
+
* Converts an error from a {@link Type} into formatted issues with paths.
|
|
387
|
+
*
|
|
388
|
+
* Pass the Type that produced the error. This uses its nested and localized
|
|
389
|
+
* formatters without validating the input again. To retain every issue, decode
|
|
390
|
+
* with `{ errors: "all" }`; this function cannot recover errors omitted during
|
|
391
|
+
* validation. A root issue has an empty path.
|
|
392
|
+
*
|
|
393
|
+
* ### Example
|
|
394
|
+
*
|
|
395
|
+
* ```ts
|
|
396
|
+
* import {
|
|
397
|
+
* assertEqual,
|
|
398
|
+
* assertErr,
|
|
399
|
+
* IntFromString,
|
|
400
|
+
* object,
|
|
401
|
+
* typeErrorToIssues,
|
|
402
|
+
* } from "@evolu/common";
|
|
403
|
+
*
|
|
404
|
+
* const Settings = object({ port: IntFromString });
|
|
405
|
+
*
|
|
406
|
+
* const result = Settings.fromUnknown({ port: "http" }, { errors: "all" });
|
|
407
|
+
* assertErr(result);
|
|
408
|
+
*
|
|
409
|
+
* assertEqual(typeErrorToIssues(Settings, result.error), [
|
|
410
|
+
* {
|
|
411
|
+
* path: ["port"],
|
|
412
|
+
* message: 'The value "http" is not a decimal integer.',
|
|
413
|
+
* },
|
|
414
|
+
* ]);
|
|
415
|
+
* ```
|
|
416
|
+
*
|
|
417
|
+
* @group Core
|
|
418
|
+
*/
|
|
419
|
+
export declare const typeErrorToIssues: <T extends TypeNode>(type: T, error: InferErrors<NoInfer<T>>) => NonEmptyReadonlyArray<TypeIssue>;
|
|
358
420
|
/**
|
|
359
421
|
* The common structural shape of every {@link Type}, with its specific type
|
|
360
422
|
* parameters erased.
|
|
@@ -379,6 +441,21 @@ export interface TypeNode {
|
|
|
379
441
|
readonly fromUnknown: (value: unknown, options?: ValidationOptions) => Result<unknown, TypeError>;
|
|
380
442
|
readonly is: (value: unknown) => boolean;
|
|
381
443
|
}
|
|
444
|
+
declare const outputValidationSymbolType: unique symbol;
|
|
445
|
+
declare const getRuntimeTypeIssuesSymbolType: unique symbol;
|
|
446
|
+
type RuntimeOutputValidation = (value: unknown, options?: ValidationOptions) => Result<unknown, TypeError>;
|
|
447
|
+
interface RuntimeTypeIssue {
|
|
448
|
+
readonly name: TypeName;
|
|
449
|
+
readonly error: TypeError;
|
|
450
|
+
readonly path: ReadonlyArray<PropertyKey>;
|
|
451
|
+
readonly formatError: TypeErrorFormatter<TypeError>;
|
|
452
|
+
readonly alternatives?: ReadonlyArray<{
|
|
453
|
+
readonly index: number;
|
|
454
|
+
readonly name: TypeName;
|
|
455
|
+
readonly issues: NonEmptyReadonlyArray<RuntimeTypeIssue>;
|
|
456
|
+
}>;
|
|
457
|
+
}
|
|
458
|
+
type RuntimeGetTypeIssues = (error: TypeError, mode: ValidationOptions["errors"]) => NonEmptyReadonlyArray<RuntimeTypeIssue>;
|
|
382
459
|
/**
|
|
383
460
|
* Asserts type equality or validates a value with a {@link Type}.
|
|
384
461
|
*
|
|
@@ -435,6 +512,11 @@ export declare function assertType<T extends TypeNode>(type: T, value: unknown):
|
|
|
435
512
|
* that produced them. Different localized Type sets can coexist in separate
|
|
436
513
|
* application or dependency-injection scopes.
|
|
437
514
|
*
|
|
515
|
+
* A Union formatter supplies the summary of the failure. Retained member
|
|
516
|
+
* failures are appended using their own localized formatters, with member
|
|
517
|
+
* indexes, Type names, and paths identifying each alternative. The Union still
|
|
518
|
+
* produces one issue at its enclosing path.
|
|
519
|
+
*
|
|
438
520
|
* Localization is scoped to the selected Types instead of a package-wide
|
|
439
521
|
* translation registry. Static imports give bundlers an explicit dependency
|
|
440
522
|
* graph, so unrelated Types, locales, and formatters can be removed. Bundling
|
|
@@ -655,7 +737,7 @@ type ReflectedTypes<T extends TypeNode> = typeof reflectedTypesSymbol extends ke
|
|
|
655
737
|
readonly name: "Object";
|
|
656
738
|
readonly props: infer Props extends ObjectProps;
|
|
657
739
|
readonly record?: infer Rest;
|
|
658
|
-
} ?
|
|
740
|
+
} ? DefaultableObjectPropertyType<Props[keyof Props]> | Extract<Rest, TypeNode> : never;
|
|
659
741
|
type RootType<T extends TypeNode> = T extends {
|
|
660
742
|
readonly parent: infer Parent extends TypeNode;
|
|
661
743
|
} ? RootType<Parent> : T;
|
|
@@ -716,7 +798,42 @@ interface ValidationFailure<Error> {
|
|
|
716
798
|
readonly [validationFailureSymbol]: Error;
|
|
717
799
|
}
|
|
718
800
|
type ValidateParent<T extends ConcreteTypeNode> = IsUnion<T> extends false ? T : CompileTimeError<"Type", "Parent must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
719
|
-
|
|
801
|
+
/**
|
|
802
|
+
* Requires one concrete output {@link Type} node in a factory parameter.
|
|
803
|
+
*
|
|
804
|
+
* Rejects TypeScript unions of Type nodes. A {@link union} Type is one concrete
|
|
805
|
+
* node and remains valid. Use an intersection with the inferred parameter type
|
|
806
|
+
* to preserve its specific Type. This guard performs no runtime validation.
|
|
807
|
+
*
|
|
808
|
+
* ### Example
|
|
809
|
+
*
|
|
810
|
+
* ```ts
|
|
811
|
+
* import {
|
|
812
|
+
* assertSame,
|
|
813
|
+
* Number,
|
|
814
|
+
* String,
|
|
815
|
+
* union,
|
|
816
|
+
* type AnyType,
|
|
817
|
+
* type ValidateOutput,
|
|
818
|
+
* } from "@evolu/common";
|
|
819
|
+
*
|
|
820
|
+
* const defineOutput = <T extends AnyType>(
|
|
821
|
+
* type: T & ValidateOutput<T>,
|
|
822
|
+
* ): T => type;
|
|
823
|
+
*
|
|
824
|
+
* assertSame(defineOutput(String), String);
|
|
825
|
+
*
|
|
826
|
+
* const Value = union(String, Number);
|
|
827
|
+
* assertSame(defineOutput(Value), Value);
|
|
828
|
+
*
|
|
829
|
+
* const uncertain = String as typeof String | typeof Number;
|
|
830
|
+
* // @ts-expect-error Output Type must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.
|
|
831
|
+
* defineOutput(uncertain);
|
|
832
|
+
* ```
|
|
833
|
+
*
|
|
834
|
+
* @group Construction
|
|
835
|
+
*/
|
|
836
|
+
export type ValidateOutput<T extends AnyType> = IsUnion<T> extends false ? T : CompileTimeError<"Type", "Output Type must be one concrete Type node. Pass a Union Type node instead of a union of Type nodes.">;
|
|
720
837
|
type ValidateConcreteTypeName<Name extends TypeName> = IsTypeNameUnion<Name> extends false ? {} extends Readonly<Record<Name, never>> ? ConcreteChildTypeNameError : Name : ConcreteChildTypeNameError;
|
|
721
838
|
type ValidateChildTypeName<Name extends TypeName, ParentType extends TypeNode> = [ChildTypeNameValidationError<Name, ParentType>] extends [never] ? Name : ChildTypeNameValidationError<Name, ParentType>;
|
|
722
839
|
type ChildTypeNameValidationError<Name extends TypeName, ParentType extends TypeNode> = IsTypeNameUnion<Name> extends true ? ConcreteChildTypeNameError : {} extends Readonly<Record<Name, never>> ? ConcreteChildTypeNameError : Name extends InferErrors<ParentType>["type"] ? ChildTypeNameCollisionError : never;
|
|
@@ -748,6 +865,8 @@ type ConcreteChildTypeNameError = CompileTimeError<"Type", "Name must be one con
|
|
|
748
865
|
* its error's `type` must equal that name and must not duplicate an inherited
|
|
749
866
|
* error type. An infallible child has no own error to format.
|
|
750
867
|
*
|
|
868
|
+
* Use {@link createTypeWithError} to wrap an existing validator's errors.
|
|
869
|
+
*
|
|
751
870
|
* ### Example
|
|
752
871
|
*
|
|
753
872
|
* A root Type for a custom external value category:
|
|
@@ -778,6 +897,7 @@ type ConcreteChildTypeNameError = CompileTimeError<"Type", "Name must be one con
|
|
|
778
897
|
* );
|
|
779
898
|
*
|
|
780
899
|
* assertOk(Text.fromUnknown("Evolu"), "Evolu");
|
|
900
|
+
*
|
|
781
901
|
* const invalid = Text.fromUnknown(42);
|
|
782
902
|
* assertErr(invalid);
|
|
783
903
|
* assertType(Data, invalid.error);
|
|
@@ -791,6 +911,48 @@ export declare function createType<Name extends TypeName, Output, Error extends
|
|
|
791
911
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode>(name: ValidateConcreteTypeName<Name>, parent: ValidateParent<ParentType>, fromParent: (value: ParentType["Output"]) => Result<ParentType["Output"], never>): Type<Name, ParentType["Input"], ParentType["Output"], never, ParentType, InferErrors<ParentType>, ChildCustomFrom<ParentType, ParentType["Output"], never>, CanonicalInputForChild<ParentType, ParentType["Output"]>, IdentityEncodingOf<ParentType>>;
|
|
792
912
|
/** Creates a fallible child Type that narrows its parent's Output. */
|
|
793
913
|
export declare function createType<Name extends TypeName, ParentType extends ConcreteTypeNode, Output extends ParentType["Output"], Error extends TypeError<Name>>(name: Name, parent: ValidateBrandParent<Name, ParentType>, fromParent: (value: ParentType["Output"]) => Result<Output, Error>, formatError: [Error] extends [never] ? never : TypeErrorFormatter<NoInfer<Error>>): Type<Name, ParentType["Input"], Output, Error, ParentType, Error | InferErrors<ParentType>, ChildCustomFrom<ParentType, Output, Error>, CanonicalInputForChild<ParentType, Output>, IdentityEncodingOf<ParentType>>;
|
|
914
|
+
/**
|
|
915
|
+
* Creates a root {@link Type} with a custom error for an existing validator.
|
|
916
|
+
*
|
|
917
|
+
* The source must use identity encoding. The new Type accepts its Output as
|
|
918
|
+
* Input and hides its parent boundaries. Validation and error collection are
|
|
919
|
+
* delegated automatically; the mapper receives the failure and original value.
|
|
920
|
+
* The formatter presents the mapped error as one issue.
|
|
921
|
+
*
|
|
922
|
+
* ### Example
|
|
923
|
+
*
|
|
924
|
+
* ```ts
|
|
925
|
+
* import {
|
|
926
|
+
* assertEqual,
|
|
927
|
+
* assertErr,
|
|
928
|
+
* createTypeWithError,
|
|
929
|
+
* Number,
|
|
930
|
+
* String,
|
|
931
|
+
* union,
|
|
932
|
+
* type TypeError,
|
|
933
|
+
* type UnionError,
|
|
934
|
+
* } from "@evolu/common";
|
|
935
|
+
*
|
|
936
|
+
* interface ValueError extends TypeError<"Value"> {
|
|
937
|
+
* readonly cause: UnionError;
|
|
938
|
+
* }
|
|
939
|
+
*
|
|
940
|
+
* const Value = createTypeWithError(
|
|
941
|
+
* "Value",
|
|
942
|
+
* union(String, Number),
|
|
943
|
+
* (cause): ValueError => ({ type: "Value", cause }),
|
|
944
|
+
* () => "Enter text or a number.",
|
|
945
|
+
* );
|
|
946
|
+
*
|
|
947
|
+
* const result = Value.fromUnknown(false, { errors: "all" });
|
|
948
|
+
* assertErr(result);
|
|
949
|
+
* assertEqual(result.error.cause.errors.length, 2);
|
|
950
|
+
* assertEqual(Value.formatError(result.error), "Enter text or a number.");
|
|
951
|
+
* ```
|
|
952
|
+
*
|
|
953
|
+
* @group Construction
|
|
954
|
+
*/
|
|
955
|
+
export declare const createTypeWithError: <Name extends TypeName, T extends ConcreteTypeNode, Error extends TypeError<Name>>(name: Name & ValidateConcreteTypeName<Name>, type: T & ValidateOutput<T> & (IdentityEncodingOf<T> extends true ? unknown : CompileTimeError<"Type", "Source Type must use identity encoding.">), mapError: (error: InferErrors<T>, value: unknown) => Error, formatError: TypeErrorFormatter<NoInfer<Error>>) => Type<Name, T["Output"], T["Output"], Error>;
|
|
794
956
|
/**
|
|
795
957
|
* Transform {@link Type}.
|
|
796
958
|
*
|
|
@@ -943,8 +1105,33 @@ type DeepestFromError<Operation> = DeepestFromOperation<Operation> extends (...a
|
|
|
943
1105
|
readonly error: infer Error extends TypeError;
|
|
944
1106
|
} ? Error : never : never;
|
|
945
1107
|
type TypeFromError<T extends TypeNode> = unknown extends T[typeof customFromSymbol] ? DeepestFromError<TypeFromOperation<T>> : [T[typeof customFromSymbol]] extends [never] ? NonRootErrors<T> : DeepestFromError<T[typeof customFromSymbol]>;
|
|
1108
|
+
type RuntimeOperationFn<Value> = (value: never, options?: ValidationOptions) => Value;
|
|
1109
|
+
type RuntimeOperation<Value> = RuntimeOperationFn<Value> & {
|
|
1110
|
+
parent?: RuntimeOperation<Value>;
|
|
1111
|
+
};
|
|
1112
|
+
type RuntimeEncoder = RuntimeOperation<unknown>;
|
|
1113
|
+
declare const encoderSymbolType: unique symbol;
|
|
1114
|
+
declare const fromSymbolType: unique symbol;
|
|
946
1115
|
declare const templateLiteralSyntaxSymbolType: unique symbol;
|
|
947
1116
|
declare const templateLiteralSyntaxSymbol: typeof templateLiteralSyntaxSymbolType;
|
|
1117
|
+
/**
|
|
1118
|
+
* Type-erased {@link Type} used to traverse and invoke heterogeneous Type nodes
|
|
1119
|
+
* at runtime.
|
|
1120
|
+
*/
|
|
1121
|
+
type RuntimeTypeNode = Omit<TypeNode, typeof customFromSymbol> & {
|
|
1122
|
+
readonly [customFromSymbol]: never;
|
|
1123
|
+
readonly fromUnknown: (value: unknown, options: ValidationOptions) => Result<unknown, TypeError>;
|
|
1124
|
+
readonly formatError: TypeErrorFormatter<TypeError>;
|
|
1125
|
+
readonly from: RuntimeOperation<Result<unknown, TypeError>>;
|
|
1126
|
+
readonly to: RuntimeEncoder;
|
|
1127
|
+
readonly orThrow: RuntimeOperation<unknown>;
|
|
1128
|
+
readonly orNull: RuntimeOperation<unknown>;
|
|
1129
|
+
readonly [outputValidationSymbolType]: RuntimeOutputValidation;
|
|
1130
|
+
readonly [fromSymbolType]: RuntimeOperation<Result<unknown, TypeError>>;
|
|
1131
|
+
readonly [encoderSymbolType]: RuntimeEncoder;
|
|
1132
|
+
readonly [getRuntimeTypeIssuesSymbolType]: RuntimeGetTypeIssues;
|
|
1133
|
+
readonly [templateLiteralSyntaxSymbolType]?: true;
|
|
1134
|
+
};
|
|
948
1135
|
/**
|
|
949
1136
|
* An infallible {@link Type} accepting every value.
|
|
950
1137
|
*
|
|
@@ -1082,6 +1269,7 @@ export declare const String: Type<"String", string, string, TypeOfError<"String"
|
|
|
1082
1269
|
* >();
|
|
1083
1270
|
*
|
|
1084
1271
|
* assertOk(Age.fromUnknown(122), 122);
|
|
1272
|
+
*
|
|
1085
1273
|
* const invalid = Age.fromUnknown(200);
|
|
1086
1274
|
* assertErr(invalid);
|
|
1087
1275
|
* assertType(Data, invalid.error);
|
|
@@ -1107,6 +1295,47 @@ export declare const BigInt: Type<"BigInt", bigint, bigint, TypeOfError<"BigInt"
|
|
|
1107
1295
|
* @group Base
|
|
1108
1296
|
*/
|
|
1109
1297
|
export declare const Boolean: Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>;
|
|
1298
|
+
/**
|
|
1299
|
+
* Error returned when a string is neither `true` nor `false`.
|
|
1300
|
+
*
|
|
1301
|
+
* @group Base
|
|
1302
|
+
*/
|
|
1303
|
+
export interface BooleanFromStringError extends TypeError<"BooleanFromString"> {
|
|
1304
|
+
readonly value: string;
|
|
1305
|
+
}
|
|
1306
|
+
/**
|
|
1307
|
+
* Transforms a boolean spelled as text into a {@link Boolean}.
|
|
1308
|
+
*
|
|
1309
|
+
* This is useful for inputs that carry booleans as text, such as environment
|
|
1310
|
+
* variables, URL query parameters, and form fields. Exactly `true` and `false`
|
|
1311
|
+
* are accepted, the spellings JSON and JavaScript use, so a boolean has one
|
|
1312
|
+
* representation in every source.
|
|
1313
|
+
*
|
|
1314
|
+
* ### Example
|
|
1315
|
+
*
|
|
1316
|
+
* ```ts
|
|
1317
|
+
* import {
|
|
1318
|
+
* assertEqual,
|
|
1319
|
+
* assertErr,
|
|
1320
|
+
* assertOk,
|
|
1321
|
+
* BooleanFromString,
|
|
1322
|
+
* } from "@evolu/common";
|
|
1323
|
+
*
|
|
1324
|
+
* assertOk(BooleanFromString.fromUnknown("true"), true);
|
|
1325
|
+
* assertOk(BooleanFromString.fromUnknown("false"), false);
|
|
1326
|
+
* assertEqual(BooleanFromString.to(true), "true");
|
|
1327
|
+
*
|
|
1328
|
+
* const invalid = BooleanFromString.fromUnknown("yes");
|
|
1329
|
+
* assertErr(invalid, { type: "BooleanFromString", value: "yes" });
|
|
1330
|
+
* assertEqual(
|
|
1331
|
+
* BooleanFromString.formatError(invalid.error),
|
|
1332
|
+
* 'The value "yes" is not a boolean. Use true or false.',
|
|
1333
|
+
* );
|
|
1334
|
+
* ```
|
|
1335
|
+
*
|
|
1336
|
+
* @group Base
|
|
1337
|
+
*/
|
|
1338
|
+
export declare const BooleanFromString: TransformType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, Type<"Boolean", boolean, boolean, TypeOfError<"Boolean">, null, TypeOfError<"Boolean">, never, boolean, true>, "BooleanFromString", BooleanFromStringError, "false" | "true">;
|
|
1110
1339
|
/**
|
|
1111
1340
|
* A JavaScript symbol {@link Type}.
|
|
1112
1341
|
*
|
|
@@ -1236,6 +1465,7 @@ export declare function objectTag<Name extends keyof ObjectTagOutputByName>(name
|
|
|
1236
1465
|
* "TaggedValue",
|
|
1237
1466
|
* instanceOf(TaggedValue),
|
|
1238
1467
|
* );
|
|
1468
|
+
*
|
|
1239
1469
|
* const value = new TaggedValue();
|
|
1240
1470
|
* const result = TaggedValueType.fromUnknown(value);
|
|
1241
1471
|
*
|
|
@@ -1338,6 +1568,34 @@ export interface InstanceOfError extends TypeValueError<"InstanceOf"> {
|
|
|
1338
1568
|
}
|
|
1339
1569
|
type ValidateInstanceConstructor<Constructor extends InstanceConstructor> = IsUnion<Constructor> extends false ? "prototype" extends keyof Constructor ? Constructor : InstanceConstructorCompileTimeError : InstanceConstructorCompileTimeError;
|
|
1340
1570
|
type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor must preserve one concrete constructor. Create a Union Type from separate Instance Types instead of passing a union or erased constructor.">;
|
|
1571
|
+
/**
|
|
1572
|
+
* Requires one concrete literal type in a factory parameter.
|
|
1573
|
+
*
|
|
1574
|
+
* Preserves an exact literal and produces a compile-time error for widened,
|
|
1575
|
+
* union, branded, or open template literal types. Use an intersection with the
|
|
1576
|
+
* inferred parameter type, as {@link prefixed} does. This guard performs no
|
|
1577
|
+
* runtime validation.
|
|
1578
|
+
*
|
|
1579
|
+
* ### Example
|
|
1580
|
+
*
|
|
1581
|
+
* ```ts
|
|
1582
|
+
* import { assertType, type ValidateLiteral } from "@evolu/common";
|
|
1583
|
+
*
|
|
1584
|
+
* const definePrefix = <Prefix extends string>(
|
|
1585
|
+
* prefix: Prefix & ValidateLiteral<Prefix>,
|
|
1586
|
+
* ): Prefix => prefix;
|
|
1587
|
+
*
|
|
1588
|
+
* const prefix = definePrefix("APP_");
|
|
1589
|
+
* assertType<typeof prefix, "APP_">();
|
|
1590
|
+
*
|
|
1591
|
+
* const widened: string = "APP_";
|
|
1592
|
+
* // @ts-expect-error Expected must be one concrete literal value.
|
|
1593
|
+
* definePrefix(widened);
|
|
1594
|
+
* ```
|
|
1595
|
+
*
|
|
1596
|
+
* @group Unions
|
|
1597
|
+
*/
|
|
1598
|
+
export type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
|
|
1341
1599
|
/**
|
|
1342
1600
|
* Literal {@link Type}.
|
|
1343
1601
|
*
|
|
@@ -1366,6 +1624,7 @@ type InstanceConstructorCompileTimeError = CompileTimeError<"Type", "Constructor
|
|
|
1366
1624
|
*
|
|
1367
1625
|
* assertType<typeof Ready.Output, "ready">();
|
|
1368
1626
|
* assertOk(Ready.fromUnknown("ready"), "ready");
|
|
1627
|
+
*
|
|
1369
1628
|
* const invalid = Ready.fromUnknown("pending");
|
|
1370
1629
|
* assertErr(invalid);
|
|
1371
1630
|
* assertType(Data, invalid.error);
|
|
@@ -1390,7 +1649,6 @@ export interface LiteralType<Expected extends Literal> extends Type<"Literal", W
|
|
|
1390
1649
|
}
|
|
1391
1650
|
type LiteralParent<Expected extends Literal> = Expected extends string ? typeof String : Expected extends number ? typeof Number : Expected extends bigint ? typeof BigInt : Expected extends boolean ? typeof Boolean : null;
|
|
1392
1651
|
type LiteralParentErrors<Expected extends Literal> = LiteralParent<Expected> extends infer Parent extends TypeNode ? InferErrors<Parent> : never;
|
|
1393
|
-
type ValidateLiteral<Expected extends Literal> = IsUnion<Expected> extends false ? {} extends Readonly<Record<`${Expected}`, never>> ? LiteralCompileTimeError : Expected : LiteralCompileTimeError;
|
|
1394
1652
|
type LiteralCompileTimeError = CompileTimeError<"Type", "Expected must be one concrete literal value.">;
|
|
1395
1653
|
/**
|
|
1396
1654
|
* Error returned when a value does not equal the expected literal.
|
|
@@ -1435,6 +1693,11 @@ export declare const Null: LiteralType<null>;
|
|
|
1435
1693
|
* errors: "all" }` to retain every member failure and collect nested errors
|
|
1436
1694
|
* within each member.
|
|
1437
1695
|
*
|
|
1696
|
+
* Formatting keeps one Union issue at the enclosing path and appends the
|
|
1697
|
+
* retained failures below its summary. Member indexes identify alternatives,
|
|
1698
|
+
* not positions in the input. Nested member paths appear in the message.
|
|
1699
|
+
* Formatting never retries validation or recovers discarded failures.
|
|
1700
|
+
*
|
|
1438
1701
|
* Member order matters when multiple members accept the same value: validation
|
|
1439
1702
|
* and encoding use the first matching member. When member Inputs overlap,
|
|
1440
1703
|
* decoding the value emitted by the first member selected for an Output must
|
|
@@ -1683,6 +1946,7 @@ interface UnionErrorValue<Error extends TypeError, MemberError extends UnionMemb
|
|
|
1683
1946
|
* assertOk(result, ["cs", "CZ"]);
|
|
1684
1947
|
* const locale = result.value;
|
|
1685
1948
|
* assertType<typeof locale, SupportedLocale>();
|
|
1949
|
+
*
|
|
1686
1950
|
* const invalid = SupportedLocale.fromUnknown("cs/CZ");
|
|
1687
1951
|
* assertErr(invalid);
|
|
1688
1952
|
* assertType(Data, invalid.error);
|
|
@@ -1960,6 +2224,7 @@ type TemplateLiteralStringWidth<Value extends string, Width extends ReadonlyArra
|
|
|
1960
2224
|
* }
|
|
1961
2225
|
*
|
|
1962
2226
|
* assertOk(Int64.fromUnknown(42n), 42n);
|
|
2227
|
+
*
|
|
1963
2228
|
* const invalid = Int64.fromUnknown(2n ** 63n);
|
|
1964
2229
|
* assertErr(invalid);
|
|
1965
2230
|
* assertType(Data, invalid.error);
|
|
@@ -2009,6 +2274,7 @@ export interface BrandType<ParentType extends TypeNode, Name extends TypeName, E
|
|
|
2009
2274
|
*
|
|
2010
2275
|
* const value = "2023-01-01T12:00:00.000Z";
|
|
2011
2276
|
* assertOk(DateIso.fromUnknown(value), value);
|
|
2277
|
+
*
|
|
2012
2278
|
* const invalid = DateIso.fromUnknown("2023-01-01");
|
|
2013
2279
|
* assertErr(invalid);
|
|
2014
2280
|
* assertType(Data, invalid.error);
|
|
@@ -2135,6 +2401,7 @@ export interface UInt64Error extends TypeError<"UInt64"> {
|
|
|
2135
2401
|
* }
|
|
2136
2402
|
*
|
|
2137
2403
|
* assertOk(TrimmedString.fromUnknown("Evolu"), "Evolu");
|
|
2404
|
+
*
|
|
2138
2405
|
* const invalid = TrimmedString.fromUnknown(" Evolu");
|
|
2139
2406
|
* assertErr(invalid);
|
|
2140
2407
|
* assertType(Data, invalid.error);
|
|
@@ -2216,57 +2483,643 @@ export type BrandFactory<Name extends TypeName, Value, Error extends TypeError<N
|
|
|
2216
2483
|
export type ValidateBrandFactoryNumber<Value extends number> = IsUnion<Value> extends false ? {} extends Record<`${Value}`, never> ? Value & Readonly<Record<BrandFactoryNumberError, never>> : Value : Value & Readonly<Record<BrandFactoryNumberError, never>>;
|
|
2217
2484
|
type BrandFactoryNumberError = CompileTimeError<"Brand Factory", "Parameter must be one concrete numeric literal instead of a widened, union, or branded number.">;
|
|
2218
2485
|
/**
|
|
2219
|
-
*
|
|
2486
|
+
* Naming conventions accepted by {@link identifier}.
|
|
2220
2487
|
*
|
|
2221
|
-
*
|
|
2488
|
+
* @group String
|
|
2489
|
+
*/
|
|
2490
|
+
export type IdentifierCasing = "camelCase" | "PascalCase" | "snake_case" | "kebab-case" | "CONSTANT_CASE";
|
|
2491
|
+
/**
|
|
2492
|
+
* Brand names of the Types that {@link identifier} creates, by casing.
|
|
2493
|
+
*
|
|
2494
|
+
* @group String
|
|
2495
|
+
*/
|
|
2496
|
+
export interface IdentifierBrandByCasing {
|
|
2497
|
+
readonly camelCase: "CamelCaseIdentifier";
|
|
2498
|
+
readonly PascalCase: "PascalCaseIdentifier";
|
|
2499
|
+
readonly snake_case: "SnakeCaseIdentifier";
|
|
2500
|
+
readonly "kebab-case": "KebabCaseIdentifier";
|
|
2501
|
+
readonly CONSTANT_CASE: "ConstantCaseIdentifier";
|
|
2502
|
+
}
|
|
2503
|
+
/**
|
|
2504
|
+
* Adds identifier validation in a naming convention to an existing string Type.
|
|
2505
|
+
*
|
|
2506
|
+
* An identifier is one or more ASCII words, each starting with a letter and
|
|
2507
|
+
* continuing with letters or digits. camelCase and PascalCase start every word
|
|
2508
|
+
* after the first with an uppercase letter, so `httpUrl` has two words and
|
|
2509
|
+
* `httpURL` has four. snake_case, kebab-case, and CONSTANT_CASE put exactly one
|
|
2510
|
+
* separator between words. Validation keeps the spelling and rejects empty
|
|
2511
|
+
* strings, whitespace, punctuation, and non-ASCII characters.
|
|
2512
|
+
*
|
|
2513
|
+
* Words never start with a digit. Identifier grammars in most languages forbid
|
|
2514
|
+
* a leading digit, and camelCase cannot mark a word boundary before one, so the
|
|
2515
|
+
* rule applies to every word and keeps every conversion exact. Join an
|
|
2516
|
+
* abbreviation such as `2FA` to the previous word, as in `MAX2FA_ATTEMPTS` and
|
|
2517
|
+
* `max2faAttempts`, or spell the number out, as in `TWO_FACTOR_SECRET`.
|
|
2518
|
+
*
|
|
2519
|
+
* Convert validated identifiers with functions such as
|
|
2520
|
+
* {@link camelCaseToSnakeCase}. Conversions preserve word boundaries, and
|
|
2521
|
+
* converting back restores the original spelling. They return only the
|
|
2522
|
+
* destination brand, dropping unrelated constraints such as input length.
|
|
2222
2523
|
*
|
|
2223
2524
|
* ### Example
|
|
2224
2525
|
*
|
|
2225
2526
|
* ```ts
|
|
2226
2527
|
* import {
|
|
2227
|
-
* assertEqual,
|
|
2228
2528
|
* assertErr,
|
|
2229
2529
|
* assertOk,
|
|
2230
|
-
*
|
|
2231
|
-
*
|
|
2530
|
+
* identifier,
|
|
2531
|
+
* maxLength,
|
|
2232
2532
|
* String,
|
|
2533
|
+
* } from "@evolu/common";
|
|
2534
|
+
*
|
|
2535
|
+
* const EnvName = identifier("CONSTANT_CASE")(maxLength(16)(String));
|
|
2536
|
+
*
|
|
2537
|
+
* assertOk(EnvName.fromUnknown("HTTP2_PORT"), "HTTP2_PORT");
|
|
2538
|
+
* assertErr(EnvName.fromUnknown("HTTP_2_PORT"));
|
|
2539
|
+
* ```
|
|
2540
|
+
*
|
|
2541
|
+
* @group String
|
|
2542
|
+
*/
|
|
2543
|
+
export declare const identifier: <Casing extends IdentifierCasing>(casing: Casing) => BrandFactory<IdentifierBrandByCasing[Casing], string, IdentifierError<Casing>>;
|
|
2544
|
+
/**
|
|
2545
|
+
* Error returned when {@link identifier} rejects a string.
|
|
2546
|
+
*
|
|
2547
|
+
* @group String
|
|
2548
|
+
*/
|
|
2549
|
+
export interface IdentifierError<Casing extends IdentifierCasing = IdentifierCasing> extends TypeError<IdentifierBrandByCasing[Casing]> {
|
|
2550
|
+
readonly value: string;
|
|
2551
|
+
readonly casing: Casing;
|
|
2552
|
+
}
|
|
2553
|
+
/**
|
|
2554
|
+
* A validated camelCase identifier, such as `http2Port`.
|
|
2555
|
+
*
|
|
2556
|
+
* See {@link identifier} for the grammar and the conversion functions.
|
|
2557
|
+
*
|
|
2558
|
+
* @group String
|
|
2559
|
+
*/
|
|
2560
|
+
export declare const CamelCaseIdentifier: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "CamelCaseIdentifier", IdentifierError<"camelCase">>;
|
|
2561
|
+
export type CamelCaseIdentifier = typeof CamelCaseIdentifier.Output;
|
|
2562
|
+
/**
|
|
2563
|
+
* A validated PascalCase identifier, such as `Http2Port`.
|
|
2564
|
+
*
|
|
2565
|
+
* See {@link identifier} for the grammar and the conversion functions.
|
|
2566
|
+
*
|
|
2567
|
+
* @group String
|
|
2568
|
+
*/
|
|
2569
|
+
export declare const PascalCaseIdentifier: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "PascalCaseIdentifier", IdentifierError<"PascalCase">>;
|
|
2570
|
+
export type PascalCaseIdentifier = typeof PascalCaseIdentifier.Output;
|
|
2571
|
+
/**
|
|
2572
|
+
* A validated snake_case identifier, such as `http2_port`.
|
|
2573
|
+
*
|
|
2574
|
+
* See {@link identifier} for the grammar and the conversion functions.
|
|
2575
|
+
*
|
|
2576
|
+
* @group String
|
|
2577
|
+
*/
|
|
2578
|
+
export declare const SnakeCaseIdentifier: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "SnakeCaseIdentifier", IdentifierError<"snake_case">>;
|
|
2579
|
+
export type SnakeCaseIdentifier = typeof SnakeCaseIdentifier.Output;
|
|
2580
|
+
/**
|
|
2581
|
+
* A validated kebab-case identifier, such as `http2-port`.
|
|
2582
|
+
*
|
|
2583
|
+
* See {@link identifier} for the grammar and the conversion functions.
|
|
2584
|
+
*
|
|
2585
|
+
* @group String
|
|
2586
|
+
*/
|
|
2587
|
+
export declare const KebabCaseIdentifier: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "KebabCaseIdentifier", IdentifierError<"kebab-case">>;
|
|
2588
|
+
export type KebabCaseIdentifier = typeof KebabCaseIdentifier.Output;
|
|
2589
|
+
/**
|
|
2590
|
+
* A validated CONSTANT_CASE identifier, such as `HTTP2_PORT`.
|
|
2591
|
+
*
|
|
2592
|
+
* See {@link identifier} for the grammar and the conversion functions.
|
|
2593
|
+
*
|
|
2594
|
+
* @group String
|
|
2595
|
+
*/
|
|
2596
|
+
export declare const ConstantCaseIdentifier: BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "ConstantCaseIdentifier", IdentifierError<"CONSTANT_CASE">>;
|
|
2597
|
+
export type ConstantCaseIdentifier = typeof ConstantCaseIdentifier.Output;
|
|
2598
|
+
/**
|
|
2599
|
+
* Converts a {@link CamelCaseIdentifier} to a {@link PascalCaseIdentifier}.
|
|
2600
|
+
*
|
|
2601
|
+
* Converts `http2Port` to `Http2Port`. Use {@link pascalCaseToCamelCase} to
|
|
2602
|
+
* recover the original spelling.
|
|
2603
|
+
*
|
|
2604
|
+
* @group String
|
|
2605
|
+
*/
|
|
2606
|
+
export declare const camelCaseToPascalCase: (value: CamelCaseIdentifier) => PascalCaseIdentifier;
|
|
2607
|
+
/**
|
|
2608
|
+
* Converts a {@link CamelCaseIdentifier} to a {@link SnakeCaseIdentifier}.
|
|
2609
|
+
*
|
|
2610
|
+
* Converts `http2Port` to `http2_port`. Use {@link snakeCaseToCamelCase} to
|
|
2611
|
+
* recover the original spelling.
|
|
2612
|
+
*
|
|
2613
|
+
* @group String
|
|
2614
|
+
*/
|
|
2615
|
+
export declare const camelCaseToSnakeCase: (value: CamelCaseIdentifier) => SnakeCaseIdentifier;
|
|
2616
|
+
/**
|
|
2617
|
+
* Converts a {@link CamelCaseIdentifier} to a {@link KebabCaseIdentifier}.
|
|
2618
|
+
*
|
|
2619
|
+
* Converts `http2Port` to `http2-port`. Use {@link kebabCaseToCamelCase} to
|
|
2620
|
+
* recover the original spelling.
|
|
2621
|
+
*
|
|
2622
|
+
* @group String
|
|
2623
|
+
*/
|
|
2624
|
+
export declare const camelCaseToKebabCase: (value: CamelCaseIdentifier) => KebabCaseIdentifier;
|
|
2625
|
+
/**
|
|
2626
|
+
* Converts a {@link CamelCaseIdentifier} to a {@link ConstantCaseIdentifier}.
|
|
2627
|
+
*
|
|
2628
|
+
* Converts `http2Port` to `HTTP2_PORT`. Use {@link constantCaseToCamelCase} to
|
|
2629
|
+
* recover the original spelling.
|
|
2630
|
+
*
|
|
2631
|
+
* @group String
|
|
2632
|
+
*/
|
|
2633
|
+
export declare const camelCaseToConstantCase: (value: CamelCaseIdentifier) => ConstantCaseIdentifier;
|
|
2634
|
+
/**
|
|
2635
|
+
* Converts a {@link PascalCaseIdentifier} to a {@link CamelCaseIdentifier}.
|
|
2636
|
+
*
|
|
2637
|
+
* Converts `Http2Port` to `http2Port`. Use {@link camelCaseToPascalCase} to
|
|
2638
|
+
* recover the original spelling.
|
|
2639
|
+
*
|
|
2640
|
+
* @group String
|
|
2641
|
+
*/
|
|
2642
|
+
export declare const pascalCaseToCamelCase: (value: PascalCaseIdentifier) => CamelCaseIdentifier;
|
|
2643
|
+
/**
|
|
2644
|
+
* Converts a {@link PascalCaseIdentifier} to a {@link SnakeCaseIdentifier}.
|
|
2645
|
+
*
|
|
2646
|
+
* Converts `Http2Port` to `http2_port`. Use {@link snakeCaseToPascalCase} to
|
|
2647
|
+
* recover the original spelling.
|
|
2648
|
+
*
|
|
2649
|
+
* @group String
|
|
2650
|
+
*/
|
|
2651
|
+
export declare const pascalCaseToSnakeCase: (value: PascalCaseIdentifier) => SnakeCaseIdentifier;
|
|
2652
|
+
/**
|
|
2653
|
+
* Converts a {@link PascalCaseIdentifier} to a {@link KebabCaseIdentifier}.
|
|
2654
|
+
*
|
|
2655
|
+
* Converts `Http2Port` to `http2-port`. Use {@link kebabCaseToPascalCase} to
|
|
2656
|
+
* recover the original spelling.
|
|
2657
|
+
*
|
|
2658
|
+
* @group String
|
|
2659
|
+
*/
|
|
2660
|
+
export declare const pascalCaseToKebabCase: (value: PascalCaseIdentifier) => KebabCaseIdentifier;
|
|
2661
|
+
/**
|
|
2662
|
+
* Converts a {@link PascalCaseIdentifier} to a {@link ConstantCaseIdentifier}.
|
|
2663
|
+
*
|
|
2664
|
+
* Converts `Http2Port` to `HTTP2_PORT`. Use {@link constantCaseToPascalCase} to
|
|
2665
|
+
* recover the original spelling.
|
|
2666
|
+
*
|
|
2667
|
+
* @group String
|
|
2668
|
+
*/
|
|
2669
|
+
export declare const pascalCaseToConstantCase: (value: PascalCaseIdentifier) => ConstantCaseIdentifier;
|
|
2670
|
+
/**
|
|
2671
|
+
* Converts a {@link SnakeCaseIdentifier} to a {@link CamelCaseIdentifier}.
|
|
2672
|
+
*
|
|
2673
|
+
* Converts `http2_port` to `http2Port`. Use {@link camelCaseToSnakeCase} to
|
|
2674
|
+
* recover the original spelling.
|
|
2675
|
+
*
|
|
2676
|
+
* @group String
|
|
2677
|
+
*/
|
|
2678
|
+
export declare const snakeCaseToCamelCase: (value: SnakeCaseIdentifier) => CamelCaseIdentifier;
|
|
2679
|
+
/**
|
|
2680
|
+
* Converts a {@link SnakeCaseIdentifier} to a {@link PascalCaseIdentifier}.
|
|
2681
|
+
*
|
|
2682
|
+
* Converts `http2_port` to `Http2Port`. Use {@link pascalCaseToSnakeCase} to
|
|
2683
|
+
* recover the original spelling.
|
|
2684
|
+
*
|
|
2685
|
+
* @group String
|
|
2686
|
+
*/
|
|
2687
|
+
export declare const snakeCaseToPascalCase: (value: SnakeCaseIdentifier) => PascalCaseIdentifier;
|
|
2688
|
+
/**
|
|
2689
|
+
* Converts a {@link SnakeCaseIdentifier} to a {@link KebabCaseIdentifier}.
|
|
2690
|
+
*
|
|
2691
|
+
* Converts `http2_port` to `http2-port`. Use {@link kebabCaseToSnakeCase} to
|
|
2692
|
+
* recover the original spelling.
|
|
2693
|
+
*
|
|
2694
|
+
* @group String
|
|
2695
|
+
*/
|
|
2696
|
+
export declare const snakeCaseToKebabCase: (value: SnakeCaseIdentifier) => KebabCaseIdentifier;
|
|
2697
|
+
/**
|
|
2698
|
+
* Converts a {@link SnakeCaseIdentifier} to a {@link ConstantCaseIdentifier}.
|
|
2699
|
+
*
|
|
2700
|
+
* Converts `http2_port` to `HTTP2_PORT`. Use {@link constantCaseToSnakeCase} to
|
|
2701
|
+
* recover the original spelling.
|
|
2702
|
+
*
|
|
2703
|
+
* @group String
|
|
2704
|
+
*/
|
|
2705
|
+
export declare const snakeCaseToConstantCase: (value: SnakeCaseIdentifier) => ConstantCaseIdentifier;
|
|
2706
|
+
/**
|
|
2707
|
+
* Converts a {@link KebabCaseIdentifier} to a {@link CamelCaseIdentifier}.
|
|
2708
|
+
*
|
|
2709
|
+
* Converts `http2-port` to `http2Port`. Use {@link camelCaseToKebabCase} to
|
|
2710
|
+
* recover the original spelling.
|
|
2711
|
+
*
|
|
2712
|
+
* @group String
|
|
2713
|
+
*/
|
|
2714
|
+
export declare const kebabCaseToCamelCase: (value: KebabCaseIdentifier) => CamelCaseIdentifier;
|
|
2715
|
+
/**
|
|
2716
|
+
* Converts a {@link KebabCaseIdentifier} to a {@link PascalCaseIdentifier}.
|
|
2717
|
+
*
|
|
2718
|
+
* Converts `http2-port` to `Http2Port`. Use {@link pascalCaseToKebabCase} to
|
|
2719
|
+
* recover the original spelling.
|
|
2720
|
+
*
|
|
2721
|
+
* @group String
|
|
2722
|
+
*/
|
|
2723
|
+
export declare const kebabCaseToPascalCase: (value: KebabCaseIdentifier) => PascalCaseIdentifier;
|
|
2724
|
+
/**
|
|
2725
|
+
* Converts a {@link KebabCaseIdentifier} to a {@link SnakeCaseIdentifier}.
|
|
2726
|
+
*
|
|
2727
|
+
* Converts `http2-port` to `http2_port`. Use {@link snakeCaseToKebabCase} to
|
|
2728
|
+
* recover the original spelling.
|
|
2729
|
+
*
|
|
2730
|
+
* @group String
|
|
2731
|
+
*/
|
|
2732
|
+
export declare const kebabCaseToSnakeCase: (value: KebabCaseIdentifier) => SnakeCaseIdentifier;
|
|
2733
|
+
/**
|
|
2734
|
+
* Converts a {@link KebabCaseIdentifier} to a {@link ConstantCaseIdentifier}.
|
|
2735
|
+
*
|
|
2736
|
+
* Converts `http2-port` to `HTTP2_PORT`. Use {@link constantCaseToKebabCase} to
|
|
2737
|
+
* recover the original spelling.
|
|
2738
|
+
*
|
|
2739
|
+
* @group String
|
|
2740
|
+
*/
|
|
2741
|
+
export declare const kebabCaseToConstantCase: (value: KebabCaseIdentifier) => ConstantCaseIdentifier;
|
|
2742
|
+
/**
|
|
2743
|
+
* Converts a {@link ConstantCaseIdentifier} to a {@link CamelCaseIdentifier}.
|
|
2744
|
+
*
|
|
2745
|
+
* Converts `HTTP2_PORT` to `http2Port`. Use {@link camelCaseToConstantCase} to
|
|
2746
|
+
* recover the original spelling.
|
|
2747
|
+
*
|
|
2748
|
+
* @group String
|
|
2749
|
+
*/
|
|
2750
|
+
export declare const constantCaseToCamelCase: (value: ConstantCaseIdentifier) => CamelCaseIdentifier;
|
|
2751
|
+
/**
|
|
2752
|
+
* Decodes a {@link ConstantCaseIdentifier} to a {@link CamelCaseIdentifier} and
|
|
2753
|
+
* restores the original spelling when encoding.
|
|
2754
|
+
*
|
|
2755
|
+
* ### Example
|
|
2756
|
+
*
|
|
2757
|
+
* ```ts
|
|
2758
|
+
* import {
|
|
2759
|
+
* assertEqual,
|
|
2760
|
+
* assertOk,
|
|
2761
|
+
* CamelCaseIdentifierFromConstantCaseIdentifier,
|
|
2762
|
+
* } from "@evolu/common";
|
|
2763
|
+
*
|
|
2764
|
+
* const Key = CamelCaseIdentifierFromConstantCaseIdentifier;
|
|
2765
|
+
* const result = Key.fromUnknown("HTTP2_PORT");
|
|
2766
|
+
* assertOk(result, "http2Port");
|
|
2767
|
+
* assertEqual(Key.to(result.value), "HTTP2_PORT");
|
|
2768
|
+
* ```
|
|
2769
|
+
*
|
|
2770
|
+
* @group String
|
|
2771
|
+
*/
|
|
2772
|
+
export declare const CamelCaseIdentifierFromConstantCaseIdentifier: TransformType<BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "ConstantCaseIdentifier", IdentifierError<"CONSTANT_CASE">>, BrandType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, "CamelCaseIdentifier", IdentifierError<"camelCase">>, "CamelCaseIdentifierFromConstantCaseIdentifier", never, string & Brand<"ConstantCaseIdentifier">>;
|
|
2773
|
+
/**
|
|
2774
|
+
* Converts a {@link ConstantCaseIdentifier} to a {@link PascalCaseIdentifier}.
|
|
2775
|
+
*
|
|
2776
|
+
* Converts `HTTP2_PORT` to `Http2Port`. Use {@link pascalCaseToConstantCase} to
|
|
2777
|
+
* recover the original spelling.
|
|
2778
|
+
*
|
|
2779
|
+
* @group String
|
|
2780
|
+
*/
|
|
2781
|
+
export declare const constantCaseToPascalCase: (value: ConstantCaseIdentifier) => PascalCaseIdentifier;
|
|
2782
|
+
/**
|
|
2783
|
+
* Converts a {@link ConstantCaseIdentifier} to a {@link SnakeCaseIdentifier}.
|
|
2784
|
+
*
|
|
2785
|
+
* Converts `HTTP2_PORT` to `http2_port`. Use {@link snakeCaseToConstantCase} to
|
|
2786
|
+
* recover the original spelling.
|
|
2787
|
+
*
|
|
2788
|
+
* @group String
|
|
2789
|
+
*/
|
|
2790
|
+
export declare const constantCaseToSnakeCase: (value: ConstantCaseIdentifier) => SnakeCaseIdentifier;
|
|
2791
|
+
/**
|
|
2792
|
+
* Converts a {@link ConstantCaseIdentifier} to a {@link KebabCaseIdentifier}.
|
|
2793
|
+
*
|
|
2794
|
+
* Converts `HTTP2_PORT` to `http2-port`. Use {@link kebabCaseToConstantCase} to
|
|
2795
|
+
* recover the original spelling.
|
|
2796
|
+
*
|
|
2797
|
+
* @group String
|
|
2798
|
+
*/
|
|
2799
|
+
export declare const constantCaseToKebabCase: (value: ConstantCaseIdentifier) => KebabCaseIdentifier;
|
|
2800
|
+
/**
|
|
2801
|
+
* Adds capitalized text validation to an existing string Type.
|
|
2802
|
+
*
|
|
2803
|
+
* Narrows the output to TypeScript's `Capitalize<string>` while preserving the
|
|
2804
|
+
* parent Type's constraints. Validation leaves the text unchanged. Use
|
|
2805
|
+
* {@link capitalize} to change its casing.
|
|
2806
|
+
*
|
|
2807
|
+
* ### Example
|
|
2808
|
+
*
|
|
2809
|
+
* ```ts
|
|
2810
|
+
* import {
|
|
2811
|
+
* assertErr,
|
|
2812
|
+
* assertOk,
|
|
2233
2813
|
* capitalized,
|
|
2234
|
-
*
|
|
2814
|
+
* maxLength,
|
|
2815
|
+
* String,
|
|
2235
2816
|
* } from "@evolu/common";
|
|
2236
2817
|
*
|
|
2237
|
-
* const
|
|
2238
|
-
*
|
|
2818
|
+
* const Label = capitalized(maxLength(50)(String));
|
|
2819
|
+
* assertOk(Label.fromUnknown("Hello world"), "Hello world");
|
|
2820
|
+
* assertErr(Label.fromUnknown("hello world"));
|
|
2821
|
+
* ```
|
|
2239
2822
|
*
|
|
2240
|
-
*
|
|
2823
|
+
* @group String
|
|
2824
|
+
*/
|
|
2825
|
+
export declare const capitalized: <ParentType extends ConcreteTypeNode & {
|
|
2826
|
+
readonly Output: string;
|
|
2827
|
+
}>(parent: ValidateBrandParent<"Capitalized", ParentType>) => ReturnType<typeof createType<"Capitalized", ParentType, ParentType["Output"] & Capitalize<string>, CapitalizedError>>;
|
|
2828
|
+
/**
|
|
2829
|
+
* Error returned when {@link capitalized} rejects a string.
|
|
2241
2830
|
*
|
|
2242
|
-
*
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
*
|
|
2249
|
-
*
|
|
2831
|
+
* @group String
|
|
2832
|
+
*/
|
|
2833
|
+
export interface CapitalizedError extends TypeError<"Capitalized"> {
|
|
2834
|
+
readonly value: string;
|
|
2835
|
+
}
|
|
2836
|
+
/**
|
|
2837
|
+
* Validates capitalized text as TypeScript's `Capitalize<string>`.
|
|
2838
|
+
*
|
|
2839
|
+
* The rest of the text can use any casing. Empty strings and text starting with
|
|
2840
|
+
* an uncased character, such as a digit or emoji, are valid. Use
|
|
2841
|
+
* {@link capitalize} to produce a capitalized value from any string.
|
|
2842
|
+
*
|
|
2843
|
+
* Capitalization applies to general text, including spaces and punctuation.
|
|
2844
|
+
* Both `hello` and `Hello` become `Hello`, so the original initial casing
|
|
2845
|
+
* cannot be recovered. Capitalization does not identify words or turn text into
|
|
2846
|
+
* an identifier.
|
|
2847
|
+
*
|
|
2848
|
+
* ### Example
|
|
2849
|
+
*
|
|
2850
|
+
* ```ts
|
|
2851
|
+
* import { assertErr, assertOk, CapitalizedString } from "@evolu/common";
|
|
2852
|
+
*
|
|
2853
|
+
* const text: CapitalizedString = "Hello world";
|
|
2854
|
+
* assertOk(CapitalizedString.fromUnknown(text), text);
|
|
2855
|
+
* assertErr(CapitalizedString.fromUnknown("hello world"));
|
|
2856
|
+
* assertOk(CapitalizedString.fromUnknown(""), "");
|
|
2857
|
+
* ```
|
|
2858
|
+
*
|
|
2859
|
+
* @group String
|
|
2860
|
+
*/
|
|
2861
|
+
export declare const CapitalizedString: Type<"Capitalized", string, Capitalize<string>, CapitalizedError, Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, CapitalizedError | TypeOfError<"String">, never, Capitalize<string>, true>;
|
|
2862
|
+
export type CapitalizedString = typeof CapitalizedString.Output;
|
|
2863
|
+
/**
|
|
2864
|
+
* Uppercases the first Unicode code point and returns a
|
|
2865
|
+
* {@link CapitalizedString}.
|
|
2866
|
+
*
|
|
2867
|
+
* Preserves the remainder of the string and leaves an empty string unchanged.
|
|
2868
|
+
* Uses JavaScript's default Unicode casing without locale-specific rules.
|
|
2869
|
+
* Changing case can change the length, so input brands are not retained.
|
|
2870
|
+
*
|
|
2871
|
+
* ### Example
|
|
2872
|
+
*
|
|
2873
|
+
* ```ts
|
|
2874
|
+
* import { assertEqual, assertType, capitalize } from "@evolu/common";
|
|
2875
|
+
*
|
|
2876
|
+
* const text = capitalize("hello world");
|
|
2877
|
+
* assertEqual(text, "Hello world");
|
|
2878
|
+
* assertType<typeof text, "Hello world">();
|
|
2879
|
+
* assertEqual(capitalize(text), text);
|
|
2880
|
+
* ```
|
|
2881
|
+
*
|
|
2882
|
+
* @group String
|
|
2883
|
+
*/
|
|
2884
|
+
export declare const capitalize: <S extends string>(value: S) => Capitalize<S>;
|
|
2885
|
+
/**
|
|
2886
|
+
* Adds uncapitalized text validation to an existing string Type.
|
|
2887
|
+
*
|
|
2888
|
+
* Narrows the output to TypeScript's `Uncapitalize<string>` while preserving
|
|
2889
|
+
* the parent Type's constraints. Validation leaves the text unchanged. Use
|
|
2890
|
+
* {@link uncapitalize} to change its casing.
|
|
2891
|
+
*
|
|
2892
|
+
* ### Example
|
|
2893
|
+
*
|
|
2894
|
+
* ```ts
|
|
2895
|
+
* import {
|
|
2896
|
+
* assertErr,
|
|
2897
|
+
* assertOk,
|
|
2898
|
+
* uncapitalized,
|
|
2899
|
+
* maxLength,
|
|
2900
|
+
* String,
|
|
2901
|
+
* } from "@evolu/common";
|
|
2902
|
+
*
|
|
2903
|
+
* const Label = uncapitalized(maxLength(50)(String));
|
|
2904
|
+
* assertOk(Label.fromUnknown("hello WORLD"), "hello WORLD");
|
|
2905
|
+
* assertErr(Label.fromUnknown("Hello WORLD"));
|
|
2906
|
+
* ```
|
|
2907
|
+
*
|
|
2908
|
+
* @group String
|
|
2909
|
+
*/
|
|
2910
|
+
export declare const uncapitalized: <ParentType extends ConcreteTypeNode & {
|
|
2911
|
+
readonly Output: string;
|
|
2912
|
+
}>(parent: ValidateBrandParent<"Uncapitalized", ParentType>) => ReturnType<typeof createType<"Uncapitalized", ParentType, ParentType["Output"] & Uncapitalize<string>, UncapitalizedError>>;
|
|
2913
|
+
/**
|
|
2914
|
+
* Error returned when {@link uncapitalized} rejects a string.
|
|
2915
|
+
*
|
|
2916
|
+
* @group String
|
|
2917
|
+
*/
|
|
2918
|
+
export interface UncapitalizedError extends TypeError<"Uncapitalized"> {
|
|
2919
|
+
readonly value: string;
|
|
2920
|
+
}
|
|
2921
|
+
/**
|
|
2922
|
+
* Validates uncapitalized text as TypeScript's `Uncapitalize<string>`.
|
|
2923
|
+
*
|
|
2924
|
+
* The rest of the text can use any casing. Empty strings and text starting with
|
|
2925
|
+
* an uncased character, such as a digit or emoji, are valid. Use
|
|
2926
|
+
* {@link uncapitalize} to produce an uncapitalized value from any string.
|
|
2927
|
+
*
|
|
2928
|
+
* ### Example
|
|
2929
|
+
*
|
|
2930
|
+
* ```ts
|
|
2931
|
+
* import { assertErr, assertOk, UncapitalizedString } from "@evolu/common";
|
|
2932
|
+
*
|
|
2933
|
+
* const text: UncapitalizedString = "hello WORLD";
|
|
2934
|
+
* assertOk(UncapitalizedString.fromUnknown(text), text);
|
|
2935
|
+
* assertErr(UncapitalizedString.fromUnknown("Hello WORLD"));
|
|
2936
|
+
* assertOk(UncapitalizedString.fromUnknown(""), "");
|
|
2937
|
+
* ```
|
|
2938
|
+
*
|
|
2939
|
+
* @group String
|
|
2940
|
+
*/
|
|
2941
|
+
export declare const UncapitalizedString: Type<"Uncapitalized", string, Uncapitalize<string>, UncapitalizedError, Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, TypeOfError<"String"> | UncapitalizedError, never, Uncapitalize<string>, true>;
|
|
2942
|
+
export type UncapitalizedString = typeof UncapitalizedString.Output;
|
|
2943
|
+
/**
|
|
2944
|
+
* Lowercases the first Unicode code point and returns a
|
|
2945
|
+
* {@link UncapitalizedString}.
|
|
2946
|
+
*
|
|
2947
|
+
* Preserves the remainder of the string and leaves an empty string unchanged.
|
|
2948
|
+
* Uses JavaScript's default Unicode casing without locale-specific rules.
|
|
2949
|
+
* Changing case can change the length, so input brands are not retained.
|
|
2950
|
+
*
|
|
2951
|
+
* ### Example
|
|
2952
|
+
*
|
|
2953
|
+
* ```ts
|
|
2954
|
+
* import { assertEqual, assertType, uncapitalize } from "@evolu/common";
|
|
2955
|
+
*
|
|
2956
|
+
* const text = uncapitalize("Hello WORLD");
|
|
2957
|
+
* assertEqual(text, "hello WORLD");
|
|
2958
|
+
* assertType<typeof text, "hello WORLD">();
|
|
2959
|
+
* assertEqual(uncapitalize(text), text);
|
|
2960
|
+
* ```
|
|
2961
|
+
*
|
|
2962
|
+
* @group String
|
|
2963
|
+
*/
|
|
2964
|
+
export declare const uncapitalize: <S extends string>(value: S) => Uncapitalize<S>;
|
|
2965
|
+
/**
|
|
2966
|
+
* Adds uppercased text validation to an existing string Type.
|
|
2967
|
+
*
|
|
2968
|
+
* Narrows the output to TypeScript's `Uppercase<string>` while preserving the
|
|
2969
|
+
* parent Type's constraints. Validation leaves the text unchanged. Use
|
|
2970
|
+
* {@link uppercase} to change its casing.
|
|
2971
|
+
*
|
|
2972
|
+
* ### Example
|
|
2973
|
+
*
|
|
2974
|
+
* ```ts
|
|
2975
|
+
* import {
|
|
2976
|
+
* assertErr,
|
|
2977
|
+
* assertOk,
|
|
2978
|
+
* uppercased,
|
|
2979
|
+
* maxLength,
|
|
2980
|
+
* String,
|
|
2981
|
+
* } from "@evolu/common";
|
|
2982
|
+
*
|
|
2983
|
+
* const Label = uppercased(maxLength(50)(String));
|
|
2984
|
+
* assertOk(Label.fromUnknown("HELLO WORLD"), "HELLO WORLD");
|
|
2985
|
+
* assertErr(Label.fromUnknown("Hello world"));
|
|
2986
|
+
* ```
|
|
2987
|
+
*
|
|
2988
|
+
* @group String
|
|
2989
|
+
*/
|
|
2990
|
+
export declare const uppercased: <ParentType extends ConcreteTypeNode & {
|
|
2991
|
+
readonly Output: string;
|
|
2992
|
+
}>(parent: ValidateBrandParent<"Uppercased", ParentType>) => ReturnType<typeof createType<"Uppercased", ParentType, ParentType["Output"] & Uppercase<string>, UppercasedError>>;
|
|
2993
|
+
/**
|
|
2994
|
+
* Error returned when {@link uppercased} rejects a string.
|
|
2995
|
+
*
|
|
2996
|
+
* @group String
|
|
2997
|
+
*/
|
|
2998
|
+
export interface UppercasedError extends TypeError<"Uppercased"> {
|
|
2999
|
+
readonly value: string;
|
|
3000
|
+
}
|
|
3001
|
+
/**
|
|
3002
|
+
* Validates uppercased text as TypeScript's `Uppercase<string>`.
|
|
3003
|
+
*
|
|
3004
|
+
* Checks the whole string using JavaScript's Unicode uppercase mapping. Empty
|
|
3005
|
+
* strings and uncased characters, such as digits and emoji, are valid. Use
|
|
3006
|
+
* {@link uppercase} to produce an uppercased value from any string.
|
|
3007
|
+
*
|
|
3008
|
+
* ### Example
|
|
3009
|
+
*
|
|
3010
|
+
* ```ts
|
|
3011
|
+
* import { assertErr, assertOk, UppercasedString } from "@evolu/common";
|
|
3012
|
+
*
|
|
3013
|
+
* const text: UppercasedString = "HELLO WORLD";
|
|
3014
|
+
* assertOk(UppercasedString.fromUnknown(text), text);
|
|
3015
|
+
* assertErr(UppercasedString.fromUnknown("Hello world"));
|
|
3016
|
+
* assertOk(UppercasedString.fromUnknown(""), "");
|
|
3017
|
+
* ```
|
|
3018
|
+
*
|
|
3019
|
+
* @group String
|
|
3020
|
+
*/
|
|
3021
|
+
export declare const UppercasedString: Type<"Uppercased", string, Uppercase<string>, UppercasedError, Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, TypeOfError<"String"> | UppercasedError, never, Uppercase<string>, true>;
|
|
3022
|
+
export type UppercasedString = typeof UppercasedString.Output;
|
|
3023
|
+
/**
|
|
3024
|
+
* Uppercases the whole string and returns a {@link UppercasedString}.
|
|
3025
|
+
*
|
|
3026
|
+
* Leaves an empty string unchanged. Uses JavaScript's default Unicode casing
|
|
3027
|
+
* without locale-specific rules. Changing case can change the length, so input
|
|
3028
|
+
* brands are not retained.
|
|
3029
|
+
*
|
|
3030
|
+
* ### Example
|
|
3031
|
+
*
|
|
3032
|
+
* ```ts
|
|
3033
|
+
* import { assertEqual, assertType, uppercase } from "@evolu/common";
|
|
3034
|
+
*
|
|
3035
|
+
* const text = uppercase("Hello world");
|
|
3036
|
+
* assertEqual(text, "HELLO WORLD");
|
|
3037
|
+
* assertType<typeof text, "HELLO WORLD">();
|
|
3038
|
+
* assertEqual(uppercase(text), text);
|
|
3039
|
+
* ```
|
|
3040
|
+
*
|
|
3041
|
+
* @group String
|
|
3042
|
+
*/
|
|
3043
|
+
export declare const uppercase: <S extends string>(value: S) => Uppercase<S>;
|
|
3044
|
+
/**
|
|
3045
|
+
* Adds lowercased text validation to an existing string Type.
|
|
3046
|
+
*
|
|
3047
|
+
* Narrows the output to TypeScript's `Lowercase<string>` while preserving the
|
|
3048
|
+
* parent Type's constraints. Validation leaves the text unchanged. Use
|
|
3049
|
+
* {@link lowercase} to change its casing.
|
|
3050
|
+
*
|
|
3051
|
+
* ### Example
|
|
3052
|
+
*
|
|
3053
|
+
* ```ts
|
|
3054
|
+
* import {
|
|
3055
|
+
* assertErr,
|
|
3056
|
+
* assertOk,
|
|
3057
|
+
* lowercased,
|
|
3058
|
+
* maxLength,
|
|
3059
|
+
* String,
|
|
3060
|
+
* } from "@evolu/common";
|
|
3061
|
+
*
|
|
3062
|
+
* const Label = lowercased(maxLength(50)(String));
|
|
3063
|
+
* assertOk(Label.fromUnknown("hello world"), "hello world");
|
|
3064
|
+
* assertErr(Label.fromUnknown("Hello WORLD"));
|
|
2250
3065
|
* ```
|
|
2251
3066
|
*
|
|
2252
3067
|
* @group String
|
|
2253
3068
|
*/
|
|
2254
|
-
export declare const
|
|
3069
|
+
export declare const lowercased: <ParentType extends ConcreteTypeNode & {
|
|
3070
|
+
readonly Output: string;
|
|
3071
|
+
}>(parent: ValidateBrandParent<"Lowercased", ParentType>) => ReturnType<typeof createType<"Lowercased", ParentType, ParentType["Output"] & Lowercase<string>, LowercasedError>>;
|
|
2255
3072
|
/**
|
|
2256
|
-
* Error returned when {@link
|
|
3073
|
+
* Error returned when {@link lowercased} rejects a string.
|
|
2257
3074
|
*
|
|
2258
3075
|
* @group String
|
|
2259
3076
|
*/
|
|
2260
|
-
export interface
|
|
3077
|
+
export interface LowercasedError extends TypeError<"Lowercased"> {
|
|
2261
3078
|
readonly value: string;
|
|
2262
3079
|
}
|
|
2263
3080
|
/**
|
|
2264
|
-
*
|
|
3081
|
+
* Validates lowercased text as TypeScript's `Lowercase<string>`.
|
|
3082
|
+
*
|
|
3083
|
+
* Checks the whole string using JavaScript's Unicode lowercase mapping. Empty
|
|
3084
|
+
* strings and uncased characters, such as digits and emoji, are valid. Use
|
|
3085
|
+
* {@link lowercase} to produce a lowercased value from any string.
|
|
3086
|
+
*
|
|
3087
|
+
* ### Example
|
|
3088
|
+
*
|
|
3089
|
+
* ```ts
|
|
3090
|
+
* import { assertErr, assertOk, LowercasedString } from "@evolu/common";
|
|
3091
|
+
*
|
|
3092
|
+
* const text: LowercasedString = "hello world";
|
|
3093
|
+
* assertOk(LowercasedString.fromUnknown(text), text);
|
|
3094
|
+
* assertErr(LowercasedString.fromUnknown("Hello WORLD"));
|
|
3095
|
+
* assertOk(LowercasedString.fromUnknown(""), "");
|
|
3096
|
+
* ```
|
|
2265
3097
|
*
|
|
2266
3098
|
* @group String
|
|
2267
3099
|
*/
|
|
2268
|
-
export declare const
|
|
2269
|
-
export type
|
|
3100
|
+
export declare const LowercasedString: Type<"Lowercased", string, Lowercase<string>, LowercasedError, Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, LowercasedError | TypeOfError<"String">, never, Lowercase<string>, true>;
|
|
3101
|
+
export type LowercasedString = typeof LowercasedString.Output;
|
|
3102
|
+
/**
|
|
3103
|
+
* Lowercases the whole string and returns a {@link LowercasedString}.
|
|
3104
|
+
*
|
|
3105
|
+
* Leaves an empty string unchanged. Uses JavaScript's default Unicode casing
|
|
3106
|
+
* without locale-specific rules. Changing case can change the length, so input
|
|
3107
|
+
* brands are not retained.
|
|
3108
|
+
*
|
|
3109
|
+
* ### Example
|
|
3110
|
+
*
|
|
3111
|
+
* ```ts
|
|
3112
|
+
* import { assertEqual, assertType, lowercase } from "@evolu/common";
|
|
3113
|
+
*
|
|
3114
|
+
* const text = lowercase("Hello WORLD");
|
|
3115
|
+
* assertEqual(text, "hello world");
|
|
3116
|
+
* assertType<typeof text, "hello world">();
|
|
3117
|
+
* assertEqual(lowercase(text), text);
|
|
3118
|
+
* ```
|
|
3119
|
+
*
|
|
3120
|
+
* @group String
|
|
3121
|
+
*/
|
|
3122
|
+
export declare const lowercase: <S extends string>(value: S) => Lowercase<S>;
|
|
2270
3123
|
/**
|
|
2271
3124
|
* String {@link Brand} without surrounding whitespace.
|
|
2272
3125
|
*
|
|
@@ -2318,6 +3171,116 @@ export type TrimmedString = typeof TrimmedString.Output;
|
|
|
2318
3171
|
* @group String
|
|
2319
3172
|
*/
|
|
2320
3173
|
export declare const trim: (value: string) => TrimmedString;
|
|
3174
|
+
/**
|
|
3175
|
+
* String {@link Brand} requiring an exact, case-sensitive prefix.
|
|
3176
|
+
*
|
|
3177
|
+
* Validation preserves the complete string, including the prefix. An empty
|
|
3178
|
+
* prefix accepts every string allowed by the parent Type. The prefix must be
|
|
3179
|
+
* one concrete string literal so different prefixes have distinct brands.
|
|
3180
|
+
*
|
|
3181
|
+
* ### Example
|
|
3182
|
+
*
|
|
3183
|
+
* ```ts
|
|
3184
|
+
* import {
|
|
3185
|
+
* assertEqual,
|
|
3186
|
+
* assertErr,
|
|
3187
|
+
* assertOk,
|
|
3188
|
+
* assertType,
|
|
3189
|
+
* maxLength,
|
|
3190
|
+
* startsWith,
|
|
3191
|
+
* String,
|
|
3192
|
+
* type Brand,
|
|
3193
|
+
* } from "@evolu/common";
|
|
3194
|
+
*
|
|
3195
|
+
* const EnvName = startsWith("APP_")(maxLength(64)(String));
|
|
3196
|
+
*
|
|
3197
|
+
* const name = EnvName.fromUnknown("APP_PORT");
|
|
3198
|
+
* assertOk(name, "APP_PORT");
|
|
3199
|
+
* assertType<
|
|
3200
|
+
* typeof name.value,
|
|
3201
|
+
* string & Brand<"MaxLength64"> & Brand<"StartsWithAPP_">
|
|
3202
|
+
* >();
|
|
3203
|
+
*
|
|
3204
|
+
* assertEqual(EnvName.to(name.value), "APP_PORT");
|
|
3205
|
+
*
|
|
3206
|
+
* assertErr(EnvName.fromUnknown("app_PORT"));
|
|
3207
|
+
* assertErr(EnvName.fromUnknown("APP_" + "X".repeat(61)));
|
|
3208
|
+
* ```
|
|
3209
|
+
*
|
|
3210
|
+
* @group String
|
|
3211
|
+
*/
|
|
3212
|
+
export declare const startsWith: <Prefix extends string>(prefix: Prefix & ValidateLiteral<Prefix>) => BrandFactory<`StartsWith${Prefix}`, string, StartsWithError<Prefix>>;
|
|
3213
|
+
/**
|
|
3214
|
+
* Error returned when {@link startsWith} rejects a string.
|
|
3215
|
+
*
|
|
3216
|
+
* @group String
|
|
3217
|
+
*/
|
|
3218
|
+
export interface StartsWithError<Prefix extends string = string> extends TypeError<`StartsWith${Prefix}`> {
|
|
3219
|
+
readonly value: string;
|
|
3220
|
+
readonly prefix: Prefix;
|
|
3221
|
+
}
|
|
3222
|
+
/**
|
|
3223
|
+
* Decodes a prefixed string with another {@link Type} and restores the prefix
|
|
3224
|
+
* when encoding.
|
|
3225
|
+
*
|
|
3226
|
+
* Uses {@link startsWith} to validate an exact, case-sensitive prefix before
|
|
3227
|
+
* removing one occurrence. The wrapped Type validates and decodes the suffix;
|
|
3228
|
+
* its constraints apply to the suffix, and its Output is preserved. Encoding
|
|
3229
|
+
* prepends the prefix to the wrapped Type's canonical string representation. An
|
|
3230
|
+
* empty prefix leaves that representation unchanged.
|
|
3231
|
+
*
|
|
3232
|
+
* The prefix must be one concrete string literal. The wrapped Type must accept
|
|
3233
|
+
* a string Input and encode to strings; its Output can have another type, as
|
|
3234
|
+
* with {@link PortFromString}.
|
|
3235
|
+
*
|
|
3236
|
+
* ### Example
|
|
3237
|
+
*
|
|
3238
|
+
* ```ts
|
|
3239
|
+
* import {
|
|
3240
|
+
* assertEqual,
|
|
3241
|
+
* assertErr,
|
|
3242
|
+
* assertOk,
|
|
3243
|
+
* assertType,
|
|
3244
|
+
* ConstantCaseIdentifier,
|
|
3245
|
+
* prefixed,
|
|
3246
|
+
* PortFromString,
|
|
3247
|
+
* type Port,
|
|
3248
|
+
* } from "@evolu/common";
|
|
3249
|
+
*
|
|
3250
|
+
* const EnvName = prefixed("APP_")(ConstantCaseIdentifier);
|
|
3251
|
+
*
|
|
3252
|
+
* const name = EnvName.fromUnknown("APP_PORT");
|
|
3253
|
+
* assertOk(name, "PORT");
|
|
3254
|
+
* assertType<typeof name.value, ConstantCaseIdentifier>();
|
|
3255
|
+
*
|
|
3256
|
+
* assertEqual(EnvName.to(name.value), "APP_PORT");
|
|
3257
|
+
*
|
|
3258
|
+
* assertErr(EnvName.fromUnknown("OTHER_PORT"));
|
|
3259
|
+
* assertErr(EnvName.fromUnknown("APP_port"));
|
|
3260
|
+
*
|
|
3261
|
+
* const PortSetting = prefixed("port:")(PortFromString);
|
|
3262
|
+
*
|
|
3263
|
+
* const port = PortSetting.fromUnknown("port:04000");
|
|
3264
|
+
* assertOk(port, 4000);
|
|
3265
|
+
* assertType<typeof port.value, Port>();
|
|
3266
|
+
*
|
|
3267
|
+
* assertEqual(PortSetting.to(port.value), "port:4000");
|
|
3268
|
+
* ```
|
|
3269
|
+
*
|
|
3270
|
+
* @group String
|
|
3271
|
+
*/
|
|
3272
|
+
export declare const prefixed: <Prefix extends string>(prefix: Prefix & ValidateLiteral<Prefix>) => <T extends ConcreteTypeNode & {
|
|
3273
|
+
readonly Input: string;
|
|
3274
|
+
readonly CanonicalInput: string;
|
|
3275
|
+
}>(type: T & ValidateOutput<T> & (string extends T["Input"] ? unknown : PrefixedInputTypeError)) => PrefixedType<Prefix, T>;
|
|
3276
|
+
/**
|
|
3277
|
+
* The {@link Type} returned by {@link prefixed}.
|
|
3278
|
+
*
|
|
3279
|
+
* @group String
|
|
3280
|
+
*/
|
|
3281
|
+
export interface PrefixedType<Prefix extends string, T extends TypeNode> extends TransformType<BrandType<typeof String, `StartsWith${Prefix}`, StartsWithError<Prefix>>, T, `Prefixed${Prefix}`, never> {
|
|
3282
|
+
}
|
|
3283
|
+
type PrefixedInputTypeError = CompileTimeError<"Type", "Prefixed Type Input must accept every string.">;
|
|
2321
3284
|
/**
|
|
2322
3285
|
* Minimum-length {@link Brand} for values whose `length` is at least `min`.
|
|
2323
3286
|
*
|
|
@@ -2460,6 +3423,7 @@ export interface LengthError<Exact extends number = number> extends TypeError<`L
|
|
|
2460
3423
|
* assertType<UrlSafeString, string & Brand<"UrlSafeString">>();
|
|
2461
3424
|
*
|
|
2462
3425
|
* assertOk(UrlSafeString.fromUnknown("abc-123_DEF"), "abc-123_DEF");
|
|
3426
|
+
*
|
|
2463
3427
|
* const invalid = UrlSafeString.fromUnknown("not safe");
|
|
2464
3428
|
* assertErr(invalid);
|
|
2465
3429
|
* assertType(Data, invalid.error);
|
|
@@ -2555,7 +3519,13 @@ export declare const uint8ArrayToBase64Url: (bytes: Uint8Array) => Base64Url;
|
|
|
2555
3519
|
*/
|
|
2556
3520
|
export declare const base64UrlToUint8Array: (value: Base64Url) => Uint8Array;
|
|
2557
3521
|
/**
|
|
2558
|
-
* A non-empty URL-safe
|
|
3522
|
+
* A non-empty file-system-safe and URL-safe token of at most 64 UTF-16 code
|
|
3523
|
+
* units.
|
|
3524
|
+
*
|
|
3525
|
+
* Evolu uses it for database file names, storage pool names, and log prefixes.
|
|
3526
|
+
* It accepts the {@link UrlSafeString} alphabet in any order, so it may start
|
|
3527
|
+
* with a digit, `-`, or `_`. It is not a language identifier; for
|
|
3528
|
+
* word-structured names, use {@link identifier}.
|
|
2559
3529
|
*
|
|
2560
3530
|
* @group String
|
|
2561
3531
|
*/
|
|
@@ -3093,6 +4063,7 @@ export type PositiveFiniteNumber = typeof PositiveFiniteNumber.Output;
|
|
|
3093
4063
|
* assertType<Int, number & Brand<"Int">>();
|
|
3094
4064
|
*
|
|
3095
4065
|
* assertOk(Int.fromUnknown(42), 42);
|
|
4066
|
+
*
|
|
3096
4067
|
* const invalid = Int.fromUnknown(1.5);
|
|
3097
4068
|
* assertErr(invalid);
|
|
3098
4069
|
* assertType(Data, invalid.error);
|
|
@@ -3141,6 +4112,52 @@ export declare const zeroNonNegativeInt: number & Brand<"NonNaN"> & Brand<"Finit
|
|
|
3141
4112
|
*/
|
|
3142
4113
|
export declare const PositiveInt: BrandType<BrandType<BrandType<BrandType<BrandType<Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>, "NonNaN", NonNaNError>, "Finite", FiniteError>, "Int", IntError>, "NonNegative", NonNegativeError>, "Positive", PositiveError>;
|
|
3143
4114
|
export type PositiveInt = typeof PositiveInt.Output;
|
|
4115
|
+
/**
|
|
4116
|
+
* Error returned when a string is not a decimal integer.
|
|
4117
|
+
*
|
|
4118
|
+
* @group Number
|
|
4119
|
+
*/
|
|
4120
|
+
export interface IntFromStringError extends TypeError<"IntFromString"> {
|
|
4121
|
+
readonly value: string;
|
|
4122
|
+
}
|
|
4123
|
+
/**
|
|
4124
|
+
* Transforms a decimal integer string into an {@link Int}.
|
|
4125
|
+
*
|
|
4126
|
+
* This is useful for inputs that carry numbers as text, such as environment
|
|
4127
|
+
* variables, URL query parameters, and form fields. The string must consist of
|
|
4128
|
+
* an optional minus sign and digits; the {@link Int} constraint then rejects
|
|
4129
|
+
* values outside the safe integer range.
|
|
4130
|
+
*
|
|
4131
|
+
* ### Example
|
|
4132
|
+
*
|
|
4133
|
+
* ```ts
|
|
4134
|
+
* import {
|
|
4135
|
+
* assertEqual,
|
|
4136
|
+
* assertErr,
|
|
4137
|
+
* assertOk,
|
|
4138
|
+
* assertSame,
|
|
4139
|
+
* IntFromString,
|
|
4140
|
+
* } from "@evolu/common";
|
|
4141
|
+
*
|
|
4142
|
+
* assertOk(IntFromString.fromUnknown("4000"), 4000);
|
|
4143
|
+
* assertOk(IntFromString.fromUnknown("-1"), -1);
|
|
4144
|
+
* assertEqual(IntFromString.to(IntFromString.orThrow("42")), "42");
|
|
4145
|
+
*
|
|
4146
|
+
* const negativeZero = IntFromString.orThrow("-0");
|
|
4147
|
+
* assertSame(negativeZero, -0);
|
|
4148
|
+
* assertEqual(IntFromString.to(negativeZero), "-0");
|
|
4149
|
+
*
|
|
4150
|
+
* const invalid = IntFromString.fromUnknown("4000.5");
|
|
4151
|
+
* assertErr(invalid, { type: "IntFromString", value: "4000.5" });
|
|
4152
|
+
* assertEqual(
|
|
4153
|
+
* IntFromString.formatError(invalid.error),
|
|
4154
|
+
* 'The value "4000.5" is not a decimal integer.',
|
|
4155
|
+
* );
|
|
4156
|
+
* ```
|
|
4157
|
+
*
|
|
4158
|
+
* @group Number
|
|
4159
|
+
*/
|
|
4160
|
+
export declare const IntFromString: TransformType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, BrandType<BrandType<BrandType<Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>, "NonNaN", NonNaNError>, "Finite", FiniteError>, "Int", IntError>, "IntFromString", IntFromStringError, string>;
|
|
3144
4161
|
/**
|
|
3145
4162
|
* Minimum {@link PositiveInt} value.
|
|
3146
4163
|
*
|
|
@@ -3277,6 +4294,55 @@ export interface LessThanOrEqualToError<Max extends number = number> extends Typ
|
|
|
3277
4294
|
readonly value: number;
|
|
3278
4295
|
readonly max: Max;
|
|
3279
4296
|
}
|
|
4297
|
+
/**
|
|
4298
|
+
* A TCP or UDP port as an integer from zero through 65535, inclusive.
|
|
4299
|
+
*
|
|
4300
|
+
* When binding a server, zero requests an automatically assigned port. Use
|
|
4301
|
+
* {@link PortFromString} for configuration values supplied as text.
|
|
4302
|
+
*
|
|
4303
|
+
* ### Example
|
|
4304
|
+
*
|
|
4305
|
+
* ```ts
|
|
4306
|
+
* import { assertErr, assertOk, Port } from "@evolu/common";
|
|
4307
|
+
*
|
|
4308
|
+
* assertOk(Port.fromUnknown(0), 0);
|
|
4309
|
+
* assertOk(Port.fromUnknown(4000), 4000);
|
|
4310
|
+
* assertOk(Port.fromUnknown(65535), 65535);
|
|
4311
|
+
* assertErr(Port.fromUnknown(-1));
|
|
4312
|
+
* assertErr(Port.fromUnknown(65536));
|
|
4313
|
+
* assertErr(Port.fromUnknown(4000.5));
|
|
4314
|
+
* ```
|
|
4315
|
+
*
|
|
4316
|
+
* @group Number
|
|
4317
|
+
*/
|
|
4318
|
+
export declare const Port: BrandType<BrandType<BrandType<BrandType<BrandType<BrandType<Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>, "NonNaN", NonNaNError>, "Finite", FiniteError>, "Int", IntError>, "NonNegative", NonNegativeError>, "LessThanOrEqualTo65535", LessThanOrEqualToError<65535>>, "Port", never>;
|
|
4319
|
+
export type Port = typeof Port.Output;
|
|
4320
|
+
/**
|
|
4321
|
+
* Parses a decimal integer string and validates it as a {@link Port}.
|
|
4322
|
+
*
|
|
4323
|
+
* Uses {@link IntFromString} for decimal parsing, including its rejection of
|
|
4324
|
+
* whitespace, plus signs, fractions, and exponent notation.
|
|
4325
|
+
*
|
|
4326
|
+
* ### Example
|
|
4327
|
+
*
|
|
4328
|
+
* ```ts
|
|
4329
|
+
* import {
|
|
4330
|
+
* assertEqual,
|
|
4331
|
+
* assertErr,
|
|
4332
|
+
* assertOk,
|
|
4333
|
+
* PortFromString,
|
|
4334
|
+
* } from "@evolu/common";
|
|
4335
|
+
*
|
|
4336
|
+
* assertOk(PortFromString.fromUnknown("0"), 0);
|
|
4337
|
+
* assertOk(PortFromString.fromUnknown("4000"), 4000);
|
|
4338
|
+
* assertErr(PortFromString.fromUnknown("65536"));
|
|
4339
|
+
* assertErr(PortFromString.fromUnknown("http"));
|
|
4340
|
+
* assertEqual(PortFromString.to(PortFromString.orThrow("04000")), "4000");
|
|
4341
|
+
* ```
|
|
4342
|
+
*
|
|
4343
|
+
* @group Number
|
|
4344
|
+
*/
|
|
4345
|
+
export declare const PortFromString: TransformType<TransformType<Type<"String", string, string, TypeOfError<"String">, null, TypeOfError<"String">, never, string, true>, BrandType<BrandType<BrandType<Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>, "NonNaN", NonNaNError>, "Finite", FiniteError>, "Int", IntError>, "IntFromString", IntFromStringError, string>, BrandType<BrandType<BrandType<BrandType<BrandType<BrandType<Type<"Number", number, number, TypeOfError<"Number">, null, TypeOfError<"Number">, never, number, true>, "NonNaN", NonNaNError>, "Finite", FiniteError>, "Int", IntError>, "NonNegative", NonNegativeError>, "LessThanOrEqualTo65535", LessThanOrEqualToError<65535>>, "Port", never>, "PortFromString", never, number & Brand<"NonNaN"> & Brand<"Finite"> & Brand<"Int"> & Brand<"NonNegative"> & Brand<"LessThanOrEqualTo65535"> & Brand<"Port">>;
|
|
3280
4346
|
/**
|
|
3281
4347
|
* Finite {@link Number} from zero to one, inclusive.
|
|
3282
4348
|
*
|
|
@@ -3526,6 +4592,7 @@ export type NegativeDecimalString = typeof NegativeDecimalString.Output;
|
|
|
3526
4592
|
* >();
|
|
3527
4593
|
*
|
|
3528
4594
|
* assertOk(Tenths.fromUnknown(0.3), 0.3);
|
|
4595
|
+
*
|
|
3529
4596
|
* const invalid = Tenths.fromUnknown(0.31);
|
|
3530
4597
|
* assertErr(invalid);
|
|
3531
4598
|
* assertType(Data, invalid.error);
|
|
@@ -3622,6 +4689,7 @@ export interface BetweenError<Min extends number = number, Max extends number =
|
|
|
3622
4689
|
*
|
|
3623
4690
|
* const UserId = brand("UserId", String);
|
|
3624
4691
|
* const UserIds = array(UserId);
|
|
4692
|
+
*
|
|
3625
4693
|
* const result = UserIds.from.parent(["ada", "grace"]);
|
|
3626
4694
|
*
|
|
3627
4695
|
* assertType<
|
|
@@ -3630,6 +4698,7 @@ export interface BetweenError<Min extends number = number, Max extends number =
|
|
|
3630
4698
|
* >();
|
|
3631
4699
|
* assertOk(result, ["ada", "grace"]);
|
|
3632
4700
|
* assertOk(UserIds.fromUnknown(["ada", "grace"]), ["ada", "grace"]);
|
|
4701
|
+
*
|
|
3633
4702
|
* const invalid = UserIds.fromUnknown("ada");
|
|
3634
4703
|
* assertErr(invalid);
|
|
3635
4704
|
* assertType(Data, invalid.error);
|
|
@@ -4146,53 +5215,92 @@ interface TupleItemsErrorValue<Error extends TypeError, IncludeStructuralIssues
|
|
|
4146
5215
|
};
|
|
4147
5216
|
}
|
|
4148
5217
|
/**
|
|
4149
|
-
* Decimal
|
|
5218
|
+
* Decimal integer string from `"0"` to `"9"`.
|
|
4150
5219
|
*
|
|
4151
5220
|
* @group String
|
|
4152
5221
|
*/
|
|
4153
5222
|
export declare const Digit: UnionType<readonly [LiteralType<"0">, LiteralType<"1">, LiteralType<"2">, LiteralType<"3">, LiteralType<"4">, LiteralType<"5">, LiteralType<"6">, LiteralType<"7">, LiteralType<"8">, LiteralType<"9">]>;
|
|
4154
5223
|
export type Digit = typeof Digit.Output;
|
|
4155
5224
|
/**
|
|
4156
|
-
* Decimal
|
|
5225
|
+
* Decimal integer string from `"1"` to `"9"`.
|
|
4157
5226
|
*
|
|
4158
5227
|
* @group String
|
|
4159
5228
|
*/
|
|
4160
5229
|
export declare const Digit1To9: UnionType<readonly [LiteralType<"1">, LiteralType<"2">, LiteralType<"3">, LiteralType<"4">, LiteralType<"5">, LiteralType<"6">, LiteralType<"7">, LiteralType<"8">, LiteralType<"9">]>;
|
|
4161
5230
|
export type Digit1To9 = typeof Digit1To9.Output;
|
|
4162
5231
|
/**
|
|
4163
|
-
* Decimal string from `"1"` to `"6"`.
|
|
5232
|
+
* Decimal integer string from `"1"` to `"6"`.
|
|
4164
5233
|
*
|
|
4165
5234
|
* @group String
|
|
4166
5235
|
*/
|
|
4167
5236
|
export declare const Digit1To6: UnionType<readonly [LiteralType<"1">, LiteralType<"2">, LiteralType<"3">, LiteralType<"4">, LiteralType<"5">, LiteralType<"6">]>;
|
|
4168
5237
|
export type Digit1To6 = typeof Digit1To6.Output;
|
|
4169
5238
|
/**
|
|
4170
|
-
* Decimal string from `"1"` to `"23"
|
|
5239
|
+
* Decimal integer string from `"1"` to `"23"`, without a leading zero.
|
|
4171
5240
|
*
|
|
4172
5241
|
* @group String
|
|
4173
5242
|
*/
|
|
4174
|
-
export declare const Digit1To23: UnionType<readonly [
|
|
5243
|
+
export declare const Digit1To23: UnionType<readonly [
|
|
5244
|
+
typeof Digit1To9,
|
|
5245
|
+
TemplateLiteralType<readonly ["1", typeof Digit]>,
|
|
5246
|
+
TemplateLiteralType<readonly [
|
|
5247
|
+
"2",
|
|
5248
|
+
UnionType<readonly [
|
|
5249
|
+
LiteralType<"0">,
|
|
5250
|
+
LiteralType<"1">,
|
|
5251
|
+
LiteralType<"2">,
|
|
5252
|
+
LiteralType<"3">
|
|
5253
|
+
]>
|
|
5254
|
+
]>
|
|
5255
|
+
]>;
|
|
4175
5256
|
export type Digit1To23 = typeof Digit1To23.Output;
|
|
4176
5257
|
/**
|
|
4177
|
-
* Decimal string from `"1"` to `"51"
|
|
5258
|
+
* Decimal integer string from `"1"` to `"51"`, without a leading zero.
|
|
4178
5259
|
*
|
|
4179
5260
|
* @group String
|
|
4180
5261
|
*/
|
|
4181
|
-
export declare const Digit1To51: UnionType<readonly [
|
|
5262
|
+
export declare const Digit1To51: UnionType<readonly [
|
|
5263
|
+
typeof Digit1To9,
|
|
5264
|
+
TemplateLiteralType<readonly [
|
|
5265
|
+
UnionType<readonly [
|
|
5266
|
+
LiteralType<"1">,
|
|
5267
|
+
LiteralType<"2">,
|
|
5268
|
+
LiteralType<"3">,
|
|
5269
|
+
LiteralType<"4">
|
|
5270
|
+
]>,
|
|
5271
|
+
typeof Digit
|
|
5272
|
+
]>,
|
|
5273
|
+
TemplateLiteralType<readonly ["5", UnionType<readonly [LiteralType<"0">, LiteralType<"1">]>]>
|
|
5274
|
+
]>;
|
|
4182
5275
|
export type Digit1To51 = typeof Digit1To51.Output;
|
|
4183
5276
|
/**
|
|
4184
|
-
* Decimal string from `"1"` to `"99"
|
|
5277
|
+
* Decimal integer string from `"1"` to `"99"`, without a leading zero.
|
|
4185
5278
|
*
|
|
4186
5279
|
* @group String
|
|
4187
5280
|
*/
|
|
4188
|
-
export declare const Digit1To99: UnionType<readonly [
|
|
5281
|
+
export declare const Digit1To99: UnionType<readonly [
|
|
5282
|
+
typeof Digit1To9,
|
|
5283
|
+
TemplateLiteralType<readonly [typeof Digit1To9, typeof Digit]>
|
|
5284
|
+
]>;
|
|
4189
5285
|
export type Digit1To99 = typeof Digit1To99.Output;
|
|
4190
5286
|
/**
|
|
4191
|
-
* Decimal string from `"1"` to `"59"
|
|
5287
|
+
* Decimal integer string from `"1"` to `"59"`, without a leading zero.
|
|
4192
5288
|
*
|
|
4193
5289
|
* @group String
|
|
4194
5290
|
*/
|
|
4195
|
-
export declare const Digit1To59: UnionType<readonly [
|
|
5291
|
+
export declare const Digit1To59: UnionType<readonly [
|
|
5292
|
+
typeof Digit1To9,
|
|
5293
|
+
TemplateLiteralType<readonly [
|
|
5294
|
+
UnionType<readonly [
|
|
5295
|
+
LiteralType<"1">,
|
|
5296
|
+
LiteralType<"2">,
|
|
5297
|
+
LiteralType<"3">,
|
|
5298
|
+
LiteralType<"4">,
|
|
5299
|
+
LiteralType<"5">
|
|
5300
|
+
]>,
|
|
5301
|
+
typeof Digit
|
|
5302
|
+
]>
|
|
5303
|
+
]>;
|
|
4196
5304
|
export type Digit1To59 = typeof Digit1To59.Output;
|
|
4197
5305
|
type PlainObjectError = ObjectError<Readonly<Record<never, never>>, ObjectPropertyAccessError | ObjectExcessPropertyError>;
|
|
4198
5306
|
/**
|
|
@@ -4301,6 +5409,7 @@ export { _Object as Object };
|
|
|
4301
5409
|
* const valueType = typeof value;
|
|
4302
5410
|
*
|
|
4303
5411
|
* assertEqual(valueType, "function");
|
|
5412
|
+
*
|
|
4304
5413
|
* const called = trySync(
|
|
4305
5414
|
* () => {
|
|
4306
5415
|
* if (value !== undefined) value.toFixed(0);
|
|
@@ -4336,6 +5445,7 @@ export { _Object as Object };
|
|
|
4336
5445
|
* const valueType = typeof value;
|
|
4337
5446
|
*
|
|
4338
5447
|
* assertEqual(valueType, "function");
|
|
5448
|
+
*
|
|
4339
5449
|
* const called = trySync(
|
|
4340
5450
|
* () => {
|
|
4341
5451
|
* if (value !== undefined) value.toFixed(0);
|
|
@@ -4370,6 +5480,16 @@ interface RecordTypeNode extends TypeNode {
|
|
|
4370
5480
|
interface ObjectRecordTypeNode extends RecordTypeNode {
|
|
4371
5481
|
readonly key: typeof String;
|
|
4372
5482
|
}
|
|
5483
|
+
type RuntimeRecordKeyTypeNode = Omit<RuntimeTypeNode, "fromUnknown" | "from" | "to"> & {
|
|
5484
|
+
readonly fromUnknown: (value: unknown, options: ValidationOptions) => Result<string, TypeError>;
|
|
5485
|
+
readonly from: RuntimeOperation<Result<string, TypeError>>;
|
|
5486
|
+
readonly to: (value: never) => string;
|
|
5487
|
+
};
|
|
5488
|
+
interface RuntimeRecordTypeNode extends RuntimeTypeNode {
|
|
5489
|
+
readonly name: "Record";
|
|
5490
|
+
readonly key: RuntimeRecordKeyTypeNode;
|
|
5491
|
+
readonly value: RuntimeTypeNode;
|
|
5492
|
+
}
|
|
4373
5493
|
type RecordShape<KeyType extends TypeNode, ValueType extends TypeNode, Field extends "Input" | "Output" | "CanonicalInput"> = [Extract<RecordTypeField<KeyType, Field>, string>] extends [never] ? Readonly<Record<string, never>> : Readonly<Partial<Record<Extract<RecordTypeField<KeyType, Field>, string>, RecordTypeField<ValueType, Field>>>>;
|
|
4374
5494
|
type RecordTypeField<T extends TypeNode, Field extends "Input" | "Output" | "CanonicalInput"> = Field extends "CanonicalInput" ? CanonicalInputOf<T> : T[Field];
|
|
4375
5495
|
type RecordParent<KeyType extends TypeNode, ValueType extends TypeNode> = [
|
|
@@ -4499,6 +5619,7 @@ interface RecordEntriesErrorValue<KeyError extends TypeError, ValueError extends
|
|
|
4499
5619
|
export interface OptionalProperty<T extends TypeNode> {
|
|
4500
5620
|
readonly type: T;
|
|
4501
5621
|
readonly [errorsSymbol]: InferErrors<T>;
|
|
5622
|
+
readonly [optionalPropertySymbol]: true;
|
|
4502
5623
|
}
|
|
4503
5624
|
/**
|
|
4504
5625
|
* Optional {@link object} property.
|
|
@@ -4534,13 +5655,147 @@ export interface OptionalProperty<T extends TypeNode> {
|
|
|
4534
5655
|
* @group Objects
|
|
4535
5656
|
*/
|
|
4536
5657
|
export declare const optional: <T extends TypeNode>(type: ValidateOptionalPropertyType<T>) => OptionalProperty<T>;
|
|
5658
|
+
declare const optionalPropertySymbolType: unique symbol;
|
|
5659
|
+
declare const optionalPropertySymbol: typeof optionalPropertySymbolType;
|
|
4537
5660
|
type ValidateOptionalPropertyType<T extends TypeNode> = IsUnion<T> extends false ? T extends ConcreteTypeNode ? T : ObjectPropertyTypeError : ObjectPropertyTypeError;
|
|
5661
|
+
/**
|
|
5662
|
+
* A value decoded by {@link withDefault} with the `preserve` strategy.
|
|
5663
|
+
*
|
|
5664
|
+
* `defaultUsed` distinguishes supplied values from defaults, even when their
|
|
5665
|
+
* values are equal. `original` records the decoded absence, not the raw input
|
|
5666
|
+
* before other transformations.
|
|
5667
|
+
*
|
|
5668
|
+
* @group Construction
|
|
5669
|
+
*/
|
|
5670
|
+
export type Defaulted<Value, Default = Value, Original extends "missing" | "null" | "undefined" = "missing" | "null" | "undefined"> = {
|
|
5671
|
+
readonly value: Value;
|
|
5672
|
+
readonly defaultUsed: false;
|
|
5673
|
+
} | {
|
|
5674
|
+
readonly value: Default;
|
|
5675
|
+
readonly defaultUsed: true;
|
|
5676
|
+
readonly original: Original;
|
|
5677
|
+
};
|
|
5678
|
+
/**
|
|
5679
|
+
* The value Type returned by {@link withDefault}.
|
|
5680
|
+
*
|
|
5681
|
+
* @group Construction
|
|
5682
|
+
*/
|
|
5683
|
+
export interface WithDefaultType<T extends TypeNode, Value, Strategy extends "replace" | "preserve"> extends Type<"WithDefault", T["Input"], WithDefaultOutput<T, Value, Strategy>, never, T, InferErrors<T>, ChildCustomFrom<T, WithDefaultOutput<T, Value, Strategy>, never>, T["CanonicalInput"], false> {
|
|
5684
|
+
}
|
|
5685
|
+
/**
|
|
5686
|
+
* An optional input property made required in the Output by {@link withDefault}.
|
|
5687
|
+
*
|
|
5688
|
+
* @group Objects
|
|
5689
|
+
*/
|
|
5690
|
+
export interface WithDefaultProperty<T extends TypeNode, Value, Strategy extends "replace" | "preserve"> {
|
|
5691
|
+
readonly type: T;
|
|
5692
|
+
readonly value: Value;
|
|
5693
|
+
readonly strategy: Strategy;
|
|
5694
|
+
/** @ignore */
|
|
5695
|
+
readonly [errorsSymbol]: InferErrors<T>;
|
|
5696
|
+
/** @ignore */
|
|
5697
|
+
readonly [defaultPropertySymbol]: RuntimeDefaultOperations;
|
|
5698
|
+
}
|
|
5699
|
+
/**
|
|
5700
|
+
* Supplies a decoded default for absence accepted by another {@link Type}.
|
|
5701
|
+
*
|
|
5702
|
+
* You might not need this: use `??` where a value is consumed if the default
|
|
5703
|
+
* does not need to become part of the decoded data. By default, replacement
|
|
5704
|
+
* loses the distinction between absence and an explicitly supplied value. Set
|
|
5705
|
+
* `strategy: "preserve"` to retain it.
|
|
5706
|
+
*
|
|
5707
|
+
* Defaults apply after decoding, to `null` and `undefined` accepted by the
|
|
5708
|
+
* wrapped Type, and to missing properties when wrapping {@link optional}. Types
|
|
5709
|
+
* whose Output excludes both `null` and `undefined` require `optional`;
|
|
5710
|
+
* otherwise there is no accepted absence to default. Invalid supplied values
|
|
5711
|
+
* still fail. An optional property does not accept an explicit `undefined`
|
|
5712
|
+
* unless its Type does. The default must be an Output of the wrapped Type; it
|
|
5713
|
+
* is checked when constructing the declaration. It may itself be `null` or
|
|
5714
|
+
* `undefined` when the wrapped Output accepts that value.
|
|
5715
|
+
*
|
|
5716
|
+
* Omitting `strategy` returns the effective value and encodes it as supplied
|
|
5717
|
+
* data. `strategy: "preserve"` returns {@link Defaulted} and restores absence
|
|
5718
|
+
* when encoding. A supplied value equal to the default still has `defaultUsed:
|
|
5719
|
+
* false`. Preserved defaults must equal the configured value: {@link Data}
|
|
5720
|
+
* values use structural equality, and other values use reference identity.
|
|
5721
|
+
* Every decoded absence reuses the configured default by reference; defaults
|
|
5722
|
+
* are not cloned. Treat default values as immutable, like other Type
|
|
5723
|
+
* declarations.
|
|
5724
|
+
*
|
|
5725
|
+
* Pass the default value as the second argument. Add `{ strategy: "preserve" }`
|
|
5726
|
+
* as the third argument to retain supplied-input evidence. Explicit `strategy:
|
|
5727
|
+
* "replace"` is not accepted.
|
|
5728
|
+
*
|
|
5729
|
+
* ### Example
|
|
5730
|
+
*
|
|
5731
|
+
* ```ts
|
|
5732
|
+
* import {
|
|
5733
|
+
* assertEqual,
|
|
5734
|
+
* assertErr,
|
|
5735
|
+
* assertOk,
|
|
5736
|
+
* Boolean,
|
|
5737
|
+
* nullOr,
|
|
5738
|
+
* object,
|
|
5739
|
+
* optional,
|
|
5740
|
+
* withDefault,
|
|
5741
|
+
* } from "@evolu/common";
|
|
5742
|
+
*
|
|
5743
|
+
* const Settings = object({
|
|
5744
|
+
* enabled: withDefault(optional(Boolean), true, {
|
|
5745
|
+
* strategy: "preserve",
|
|
5746
|
+
* }),
|
|
5747
|
+
* });
|
|
5748
|
+
*
|
|
5749
|
+
* const missing = Settings.fromUnknown({});
|
|
5750
|
+
* assertOk(missing, {
|
|
5751
|
+
* enabled: { value: true, defaultUsed: true, original: "missing" },
|
|
5752
|
+
* });
|
|
5753
|
+
* assertEqual(Settings.to(missing.value), {});
|
|
5754
|
+
*
|
|
5755
|
+
* assertOk(Settings.fromUnknown({ enabled: true }), {
|
|
5756
|
+
* enabled: { value: true, defaultUsed: false },
|
|
5757
|
+
* });
|
|
5758
|
+
* assertErr(Settings.fromUnknown({ enabled: undefined }));
|
|
5759
|
+
*
|
|
5760
|
+
* const Enabled = withDefault(nullOr(Boolean), true);
|
|
5761
|
+
*
|
|
5762
|
+
* assertOk(Enabled.fromUnknown(null), true);
|
|
5763
|
+
* assertEqual(Enabled.to(true), true);
|
|
5764
|
+
* ```
|
|
5765
|
+
*
|
|
5766
|
+
* @group Construction
|
|
5767
|
+
*/
|
|
5768
|
+
export declare function withDefault<T extends TypeNode, const Value extends NoInfer<T["Output"]>>(property: OptionalProperty<T> & {
|
|
5769
|
+
readonly type: ValidateDefaultType<T, true>;
|
|
5770
|
+
}, value: Value): WithDefaultProperty<T, Value, "replace">;
|
|
5771
|
+
export declare function withDefault<T extends TypeNode, const Value extends NoInfer<T["Output"]>>(property: OptionalProperty<T> & {
|
|
5772
|
+
readonly type: ValidateDefaultType<T, true>;
|
|
5773
|
+
}, value: Value, options: {
|
|
5774
|
+
readonly strategy: "preserve";
|
|
5775
|
+
}): WithDefaultProperty<T, Value, "preserve">;
|
|
5776
|
+
export declare function withDefault<T extends TypeNode, const Value extends NoInfer<T["Output"]>>(type: T & ValidateDefaultType<T>, value: Value): WithDefaultType<T, Value, "replace">;
|
|
5777
|
+
export declare function withDefault<T extends TypeNode, const Value extends NoInfer<T["Output"]>>(type: T & ValidateDefaultType<T>, value: Value, options: {
|
|
5778
|
+
readonly strategy: "preserve";
|
|
5779
|
+
}): WithDefaultType<T, Value, "preserve">;
|
|
5780
|
+
type ValidateDefaultType<T extends TypeNode, Optional extends boolean = false> = ValidateOptionalPropertyType<T> & ([ChildTypeNameValidationError<"WithDefault", T>] extends [never] ? unknown : ChildTypeNameValidationError<"WithDefault", T>) & (Optional extends true ? unknown : [DefaultOriginal<T>] extends [never] ? CompileTimeError<"Type", "withDefault requires an optional property or a Type whose Output includes null or undefined."> : unknown);
|
|
5781
|
+
type DefaultOriginal<T extends TypeNode> = (null extends T["Output"] ? "null" : never) | (undefined extends T["Output"] ? "undefined" : never);
|
|
5782
|
+
type WithDefaultOutput<T extends TypeNode, Value, Strategy extends "replace" | "preserve", Original extends "missing" | "null" | "undefined" = DefaultOriginal<T>> = Strategy extends "replace" ? NonNullable<T["Output"]> | Value : Defaulted<NonNullable<T["Output"]>, Value, Original>;
|
|
5783
|
+
declare const defaultPropertySymbolType: unique symbol;
|
|
5784
|
+
declare const defaultPropertySymbol: typeof defaultPropertySymbolType;
|
|
5785
|
+
interface RuntimeDefaultOperations {
|
|
5786
|
+
readonly output: RuntimeTypeNode;
|
|
5787
|
+
readonly decode: (value: unknown) => unknown;
|
|
5788
|
+
readonly encode: (value: never) => unknown;
|
|
5789
|
+
readonly createObject: (props: ObjectProps, record: RuntimeRecordTypeNode | undefined) => ObjectTypeNode;
|
|
5790
|
+
readonly partial: (type: RuntimeTypeNode) => OptionalProperty<TypeNode>;
|
|
5791
|
+
}
|
|
4538
5792
|
/**
|
|
4539
5793
|
* Properties used to construct an {@link object} Type.
|
|
4540
5794
|
*
|
|
4541
5795
|
* @group Objects
|
|
4542
5796
|
*/
|
|
4543
|
-
export type ObjectProps = Readonly<Record<string, TypeNode | OptionalProperty<TypeNode>>>;
|
|
5797
|
+
export type ObjectProps = Readonly<Record<string, TypeNode | OptionalProperty<TypeNode> | WithDefaultProperty<TypeNode, unknown, "replace" | "preserve">>>;
|
|
5798
|
+
type ObjectValueProps = Readonly<Record<string, TypeNode | OptionalProperty<TypeNode>>>;
|
|
4544
5799
|
type ObjectProperty = ObjectProps[string];
|
|
4545
5800
|
/**
|
|
4546
5801
|
* Plain object {@link Type}.
|
|
@@ -4548,7 +5803,10 @@ type ObjectProperty = ObjectProps[string];
|
|
|
4548
5803
|
* Use `object(props)` for objects with fixed property names. Properties are
|
|
4549
5804
|
* required unless wrapped with {@link optional}. An optional property may be
|
|
4550
5805
|
* absent, but a present value is still validated and does not implicitly accept
|
|
4551
|
-
* `undefined`.
|
|
5806
|
+
* `undefined`. Wrapping an optional property with {@link withDefault} keeps the
|
|
5807
|
+
* input optional and makes the decoded output required. A default for a
|
|
5808
|
+
* nullable or undefined-accepting Type alone does not make the property
|
|
5809
|
+
* optional.
|
|
4552
5810
|
*
|
|
4553
5811
|
* Without a second argument, `fromUnknown` rejects additional properties. Pass
|
|
4554
5812
|
* a {@link record} with the predefined {@link String} key Type to validate and
|
|
@@ -4636,6 +5894,7 @@ type ObjectProperty = ObjectProps[string];
|
|
|
4636
5894
|
* const valueType = typeof value;
|
|
4637
5895
|
*
|
|
4638
5896
|
* assertEqual(valueType, "function");
|
|
5897
|
+
*
|
|
4639
5898
|
* const called = trySync(
|
|
4640
5899
|
* () => {
|
|
4641
5900
|
* if (value !== undefined) value.toFixed(0);
|
|
@@ -4671,6 +5930,7 @@ type ObjectProperty = ObjectProps[string];
|
|
|
4671
5930
|
* const valueType = typeof value;
|
|
4672
5931
|
*
|
|
4673
5932
|
* assertEqual(valueType, "function");
|
|
5933
|
+
*
|
|
4674
5934
|
* const called = trySync(
|
|
4675
5935
|
* () => {
|
|
4676
5936
|
* if (value !== undefined) value.toFixed(0);
|
|
@@ -4686,7 +5946,7 @@ type ObjectProperty = ObjectProps[string];
|
|
|
4686
5946
|
*
|
|
4687
5947
|
* @group Objects
|
|
4688
5948
|
*/
|
|
4689
|
-
export declare function object<const Props extends
|
|
5949
|
+
export declare function object<const Props extends ObjectValueProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): StrictObjectType<Props>;
|
|
4690
5950
|
/**
|
|
4691
5951
|
* Creates an Object Type with additional record properties.
|
|
4692
5952
|
*
|
|
@@ -4705,6 +5965,7 @@ export declare function object<const Props extends ObjectProps>(props: Props, ..
|
|
|
4705
5965
|
* { authorization: String },
|
|
4706
5966
|
* record(String, String),
|
|
4707
5967
|
* );
|
|
5968
|
+
*
|
|
4708
5969
|
* const result = RequestHeaders.fromUnknown({
|
|
4709
5970
|
* authorization: "Bearer token",
|
|
4710
5971
|
* "x-request-id": "request-1",
|
|
@@ -4717,11 +5978,22 @@ export declare function object<const Props extends ObjectProps>(props: Props, ..
|
|
|
4717
5978
|
* assertType<(typeof result.value)["x-request-id"], string | undefined>();
|
|
4718
5979
|
* ```
|
|
4719
5980
|
*/
|
|
4720
|
-
export declare function object<const Props extends
|
|
5981
|
+
export declare function object<const Props extends ObjectValueProps, const Rest extends RecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
|
|
4721
5982
|
ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
|
|
4722
5983
|
] extends [never] ? [] : [
|
|
4723
5984
|
ValidationFailure<ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>>
|
|
4724
5985
|
]): ObjectWithRecordType<Props, Rest extends ObjectRecordTypeNode ? Rest : never>;
|
|
5986
|
+
/** Creates an Object Type with explicit defaults for optional inputs. */
|
|
5987
|
+
export declare function object<const Props extends ObjectProps>(props: Props, ...validation: [ObjectValidationError<Props>] extends [never] ? [] : [ValidationFailure<ObjectValidationError<Props>>]): ObjectType<Props>;
|
|
5988
|
+
/**
|
|
5989
|
+
* Creates an Object Type with explicit defaults and additional record
|
|
5990
|
+
* properties.
|
|
5991
|
+
*/
|
|
5992
|
+
export declare function object<const Props extends ObjectProps, const Rest extends ObjectRecordTypeNode & ConcreteTypeNode>(props: Props, record: Rest, ...validation: [
|
|
5993
|
+
ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>
|
|
5994
|
+
] extends [never] ? [] : [
|
|
5995
|
+
ValidationFailure<ObjectValidationError<Props> | ObjectRecordValidationError<Props, Rest>>
|
|
5996
|
+
]): ObjectType<Props, Rest>;
|
|
4725
5997
|
interface ObjectTypeNode extends TypeNode {
|
|
4726
5998
|
readonly name: "Object";
|
|
4727
5999
|
readonly props: ObjectProps;
|
|
@@ -4732,16 +6004,18 @@ type ObjectValidationError<Props extends ObjectProps> = IsUnion<Props> extends f
|
|
|
4732
6004
|
}[keyof Props] : ObjectPropsTypeError;
|
|
4733
6005
|
type ObjectRecordValidationError<Props extends ObjectProps, Rest extends RecordTypeNode & ConcreteTypeNode> = IsUnion<Rest> extends false ? Rest["key"] extends typeof String ? typeof String extends Rest["key"] ? ObjectRecordPropertyValidationError<Props, Rest["value"]> : ObjectRecordKeyTypeError : ObjectRecordKeyTypeError : ObjectRecordTypeError;
|
|
4734
6006
|
type ObjectRecordPropertyValidationError<Props extends ObjectProps, ValueType extends TypeNode> = [
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
6007
|
+
DefaultableObjectPropertyType<Props[keyof Props]>["Input"],
|
|
6008
|
+
DefaultableObjectPropertyType<Props[keyof Props]>["Output"],
|
|
6009
|
+
DefaultableObjectPropertyType<Props[keyof Props]>["CanonicalInput"]
|
|
4738
6010
|
] extends [ValueType["Input"], ValueType["Output"], ValueType["CanonicalInput"]] ? never : ObjectRecordPropertyTypeError<Props, ValueType>;
|
|
4739
|
-
type ObjectRecordPropertyTypeError<Props extends ObjectProps, ValueType extends TypeNode> = [
|
|
6011
|
+
type ObjectRecordPropertyTypeError<Props extends ObjectProps, ValueType extends TypeNode> = [DefaultableObjectPropertyType<Props[keyof Props]>["Input"]] extends [
|
|
4740
6012
|
ValueType["Input"]
|
|
4741
|
-
] ? [
|
|
6013
|
+
] ? [DefaultableObjectPropertyType<Props[keyof Props]>["Output"]] extends [
|
|
4742
6014
|
ValueType["Output"]
|
|
4743
6015
|
] ? ObjectRecordCanonicalInputTypeError : ObjectRecordOutputTypeError : ObjectRecordInputTypeError;
|
|
4744
|
-
type ObjectPropertyValidationError<Property extends ObjectProperty> = IsUnion<Property> extends false ? Property extends
|
|
6016
|
+
type ObjectPropertyValidationError<Property extends ObjectProperty> = IsUnion<Property> extends false ? Property extends TypeNode ? ObjectPropertyTypeValidationError<Property> : Property extends {
|
|
6017
|
+
readonly type: infer T extends TypeNode;
|
|
6018
|
+
} ? ObjectPropertyTypeValidationError<T> : ObjectPropertyTypeError : ObjectPropertyTypeError;
|
|
4745
6019
|
type ObjectPropertyTypeValidationError<T extends TypeNode> = IsUnion<T> extends false ? T extends ConcreteTypeNode ? [
|
|
4746
6020
|
Extract<"ObjectMissingProperty" | "ObjectPropertyAccess" | "ObjectExcessProperty", InferErrors<T>["type"]>
|
|
4747
6021
|
] extends [never] ? never : CompileTimeError<"Type", "Property Type must not use an error tag reserved for Object structure."> : ObjectPropertyTypeError : ObjectPropertyTypeError;
|
|
@@ -4763,60 +6037,73 @@ type ObjectRecordCanonicalInputTypeError = CompileTimeError<"Type", "Every decla
|
|
|
4763
6037
|
*
|
|
4764
6038
|
* @group Objects
|
|
4765
6039
|
*/
|
|
4766
|
-
export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
|
|
4767
|
-
type
|
|
6040
|
+
export type ObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined = undefined> = Props extends ObjectValueProps ? Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props> : DefaultObjectType<Props, Rest>;
|
|
6041
|
+
type ObjectValueType<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode | undefined> = Rest extends ObjectRecordTypeNode ? ObjectWithRecordType<Props, Rest> : StrictObjectType<Props>;
|
|
6042
|
+
type DefaultableObjectPropertyType<Property extends ObjectProperty> = Property extends WithDefaultProperty<infer T, infer Value, infer Strategy> ? Type<"WithDefault", T["Input"], WithDefaultOutput<T, Value, Strategy, "missing" | DefaultOriginal<T>>, never, T, InferErrors<T>, never, T["CanonicalInput"], false> : Property extends TypeNode | OptionalProperty<TypeNode> ? ObjectPropertyType<Property> : never;
|
|
6043
|
+
type DefaultInputProps<Props extends ObjectProps> = {
|
|
6044
|
+
readonly [Key in keyof Props]: Props[Key] extends WithDefaultProperty<infer T, unknown, "replace" | "preserve"> ? OptionalProperty<T> : Extract<Props[Key], TypeNode | OptionalProperty<TypeNode>>;
|
|
6045
|
+
};
|
|
6046
|
+
type DefaultOutputProps<Props extends ObjectProps> = {
|
|
6047
|
+
readonly [Key in keyof Props]: Props[Key] extends WithDefaultProperty<infer T, infer Value, infer Strategy> ? Type<"DefaultValue", WithDefaultOutput<T, Value, Strategy, "missing" | DefaultOriginal<T>>, WithDefaultOutput<T, Value, Strategy, "missing" | DefaultOriginal<T>>, never> : Extract<Props[Key], TypeNode | OptionalProperty<TypeNode>>;
|
|
6048
|
+
};
|
|
6049
|
+
type DefaultObjectType<Props extends ObjectProps, Rest extends ObjectRecordTypeNode | undefined> = Type<"Object", ObjectValueType<DefaultInputProps<Props>, Rest>["Input"], ObjectValueType<DefaultOutputProps<Props>, Rest>["Output"], TypeFromError<ObjectValueType<DefaultInputProps<Props>, Rest>>, RootType<ObjectValueType<DefaultInputProps<Props>, Rest>>, InferErrors<ObjectValueType<DefaultInputProps<Props>, Rest>>, never, ObjectValueType<DefaultInputProps<Props>, Rest>["CanonicalInput"], false> & {
|
|
6050
|
+
readonly props: Readonly<Props>;
|
|
6051
|
+
} & (Rest extends ObjectRecordTypeNode ? {
|
|
6052
|
+
readonly record: Rest;
|
|
6053
|
+
} : {});
|
|
6054
|
+
type StrictObjectType<Props extends ObjectValueProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, [
|
|
4768
6055
|
StrictObjectParents<Props>
|
|
4769
6056
|
] extends [null] ? StrictObjectFromUnknownError<StrictObjectFromUnknownPropertyErrors<Props>> : ObjectFromParentError<ObjectFromParentPropertyErrors<Props>>, [
|
|
4770
6057
|
StrictObjectParents<Props>
|
|
4771
6058
|
] extends [null] ? null : StrictRootObjectType<RootObjectProps<Props>>, StrictObjectFromUnknownError<StrictObjectFromUnknownPropertyErrors<Props>>, never, StrictObjectShape<Props, "CanonicalInput">, AllTypesUseIdentityEncoding<ObjectPropertyType<Props[keyof Props]>>> & {
|
|
4772
6059
|
readonly props: Readonly<Props>;
|
|
4773
6060
|
};
|
|
4774
|
-
type ObjectWithRecordType<Props extends
|
|
6061
|
+
type ObjectWithRecordType<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode> = Type<"Object", ObjectWithRecordShape<Props, Rest, "Input">, ObjectWithRecordShape<Props, Rest, "Output">, [
|
|
4775
6062
|
ObjectWithRecordParents<Props, Rest>
|
|
4776
6063
|
] extends [null] ? ObjectError<ObjectDeclaredErrors<Props>, ObjectRestFromUnknownError<Rest>> : ObjectPropertiesError<ObjectFromParentPropertyErrors<Props>, ObjectRestFromParentError<Rest>>, [
|
|
4777
6064
|
ObjectWithRecordParents<Props, Rest>
|
|
4778
6065
|
] extends [null] ? null : RootObjectWithRecordType<RootObjectProps<Props>, RootObjectRecord<Rest>>, ObjectError<ObjectDeclaredErrors<Props>, ObjectRestFromUnknownError<Rest>>, never, ObjectWithRecordShape<Props, Rest, "CanonicalInput">, AllTypesUseIdentityEncoding<ObjectPropertyType<Props[keyof Props]> | Rest>> & ObjectWithRecordReflection<Props, Rest>;
|
|
4779
|
-
type StrictObjectShape<Props extends
|
|
6066
|
+
type StrictObjectShape<Props extends ObjectValueProps, Field extends "Input" | "Output" | "CanonicalInput"> = keyof Props extends never ? Readonly<Record<string, never>> : {
|
|
4780
6067
|
readonly [Key in RequiredObjectKeys<Props>]: ObjectTypeField<ObjectPropertyType<Props[Key]>, Field>;
|
|
4781
6068
|
} & {
|
|
4782
6069
|
readonly [Key in OptionalObjectKeys<Props>]?: ObjectTypeField<ObjectPropertyType<Props[Key]>, Field>;
|
|
4783
6070
|
};
|
|
4784
|
-
type ObjectWithRecordShape<Props extends
|
|
4785
|
-
type ObjectDeclaredShape<Props extends
|
|
6071
|
+
type ObjectWithRecordShape<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode, Field extends "Input" | "Output" | "CanonicalInput"> = keyof Props extends never ? ObjectRestShape<Rest, Field> : ObjectDeclaredShape<Props, Field> & ObjectRestShape<Rest, Field>;
|
|
6072
|
+
type ObjectDeclaredShape<Props extends ObjectValueProps, Field extends "Input" | "Output" | "CanonicalInput"> = Simplify<{
|
|
4786
6073
|
readonly [Key in RequiredObjectKeys<Props>]: ObjectTypeField<ObjectPropertyType<Props[Key]>, Field>;
|
|
4787
6074
|
} & {
|
|
4788
6075
|
readonly [Key in OptionalObjectKeys<Props>]?: ObjectTypeField<ObjectPropertyType<Props[Key]>, Field>;
|
|
4789
6076
|
}>;
|
|
4790
6077
|
type ObjectRestShape<Rest extends ObjectRecordTypeNode, Field extends "Input" | "Output" | "CanonicalInput"> = Readonly<Partial<Record<string, ObjectTypeField<Rest["value"], Field>>>>;
|
|
4791
6078
|
type ObjectTypeField<T extends TypeNode, Field extends "Input" | "Output" | "CanonicalInput"> = Field extends "CanonicalInput" ? CanonicalInputOf<T> : T[Field];
|
|
4792
|
-
type RequiredObjectKeys<Props extends
|
|
4793
|
-
type OptionalObjectKeys<Props extends
|
|
6079
|
+
type RequiredObjectKeys<Props extends ObjectValueProps> = Exclude<keyof Props, OptionalObjectKeys<Props>>;
|
|
6080
|
+
type OptionalObjectKeys<Props extends ObjectValueProps> = {
|
|
4794
6081
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Key : never;
|
|
4795
6082
|
}[keyof Props];
|
|
4796
|
-
type ObjectPropertyType<Property extends
|
|
4797
|
-
type ObjectFromParentPropertyErrors<Props extends
|
|
6083
|
+
type ObjectPropertyType<Property extends ObjectValueProps[string]> = Property extends OptionalProperty<infer T> ? T : Property;
|
|
6084
|
+
type ObjectFromParentPropertyErrors<Props extends ObjectValueProps> = {
|
|
4798
6085
|
readonly [Key in keyof Props]: TypeFromError<ObjectPropertyType<Props[Key]>>;
|
|
4799
6086
|
};
|
|
4800
|
-
type StrictRootObjectType<Props extends
|
|
6087
|
+
type StrictRootObjectType<Props extends ObjectValueProps> = Type<"Object", StrictObjectShape<Props, "Input">, StrictObjectShape<Props, "Output">, StrictObjectFromUnknownError<StrictObjectFromUnknownPropertyErrors<Props>>, null, StrictObjectFromUnknownError<StrictObjectFromUnknownPropertyErrors<Props>>, never, StrictObjectShape<Props, "CanonicalInput">, AllTypesUseIdentityEncoding<ObjectPropertyType<Props[keyof Props]>>> & {
|
|
4801
6088
|
readonly props: Readonly<Props>;
|
|
4802
6089
|
};
|
|
4803
|
-
type RootObjectWithRecordType<Props extends
|
|
4804
|
-
type StrictObjectParents<Props extends
|
|
4805
|
-
type ObjectWithRecordParents<Props extends
|
|
4806
|
-
type RootObjectProps<Props extends
|
|
6090
|
+
type RootObjectWithRecordType<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode> = Type<"Object", ObjectWithRecordShape<Props, Rest, "Input">, ObjectWithRecordShape<Props, Rest, "Output">, ObjectError<ObjectDeclaredErrors<Props>, ObjectRestFromUnknownError<Rest>>, null, ObjectError<ObjectDeclaredErrors<Props>, ObjectRestFromUnknownError<Rest>>, never, ObjectWithRecordShape<Props, Rest, "CanonicalInput">, AllTypesUseIdentityEncoding<ObjectPropertyType<Props[keyof Props]> | Rest>> & ObjectWithRecordReflection<Props, Rest>;
|
|
6091
|
+
type StrictObjectParents<Props extends ObjectValueProps> = ObjectPropertyType<Props[keyof Props]>["parent"];
|
|
6092
|
+
type ObjectWithRecordParents<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode> = ObjectPropertyType<Props[keyof Props]>["parent"] | Rest["parent"];
|
|
6093
|
+
type RootObjectProps<Props extends ObjectValueProps> = {
|
|
4807
6094
|
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<infer T> ? OptionalProperty<RootType<T>> : Props[Key] extends TypeNode ? RootType<Props[Key]> : never;
|
|
4808
6095
|
};
|
|
4809
6096
|
type RootObjectRecord<Rest extends ObjectRecordTypeNode> = RecordType<typeof String, RootType<Rest["value"]>>;
|
|
4810
|
-
interface ObjectWithRecordReflection<Props extends
|
|
6097
|
+
interface ObjectWithRecordReflection<Props extends ObjectValueProps, Rest extends ObjectRecordTypeNode> {
|
|
4811
6098
|
readonly props: Readonly<Props>;
|
|
4812
6099
|
readonly record: Rest;
|
|
4813
6100
|
}
|
|
4814
|
-
type ObjectDeclaredErrors<Props extends
|
|
6101
|
+
type ObjectDeclaredErrors<Props extends ObjectValueProps> = {
|
|
4815
6102
|
readonly [Key in RequiredObjectKeys<Props>]: Props[Key][typeof errorsSymbol];
|
|
4816
6103
|
} & {
|
|
4817
6104
|
readonly [Key in OptionalObjectKeys<Props>]?: Props[Key][typeof errorsSymbol];
|
|
4818
6105
|
};
|
|
4819
|
-
type StrictObjectFromUnknownPropertyErrors<Props extends
|
|
6106
|
+
type StrictObjectFromUnknownPropertyErrors<Props extends ObjectValueProps> = {
|
|
4820
6107
|
readonly [Key in RequiredObjectKeys<Props>]: Props[Key][typeof errorsSymbol] | ObjectMissingPropertyError | ObjectPropertyAccessError;
|
|
4821
6108
|
} & {
|
|
4822
6109
|
readonly [Key in OptionalObjectKeys<Props>]: Props[Key][typeof errorsSymbol] | ObjectPropertyAccessError;
|
|
@@ -4933,7 +6220,8 @@ type ObjectRestFromParentError<Rest extends ObjectRecordTypeNode | undefined> =
|
|
|
4933
6220
|
* Object {@link Type} with every property optional.
|
|
4934
6221
|
*
|
|
4935
6222
|
* No property is required, but every present property must still satisfy its
|
|
4936
|
-
* Type.
|
|
6223
|
+
* Type. For {@link withDefault} properties, this disables the missing-property
|
|
6224
|
+
* default; defaults for present `null` or `undefined` values still apply.
|
|
4937
6225
|
*
|
|
4938
6226
|
* ### Example
|
|
4939
6227
|
*
|
|
@@ -4963,7 +6251,7 @@ export declare const partial: <const Props extends ObjectProps>(props: Props, ..
|
|
|
4963
6251
|
* @group Objects
|
|
4964
6252
|
*/
|
|
4965
6253
|
export type PartialObjectProps<Props extends ObjectProps> = {
|
|
4966
|
-
readonly [Key in keyof Props]: Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
|
|
6254
|
+
readonly [Key in keyof Props]: Props[Key] extends WithDefaultProperty<infer T, infer Value, infer Strategy> ? OptionalProperty<WithDefaultType<T, Value, Strategy>> : Props[Key] extends OptionalProperty<TypeNode> ? Props[Key] : Props[Key] extends TypeNode ? OptionalProperty<Props[Key]> : never;
|
|
4967
6255
|
};
|
|
4968
6256
|
/**
|
|
4969
6257
|
* Object {@link Type} making every property whose Union Type includes
|
|
@@ -5023,12 +6311,91 @@ export type NullableToOptionalProps<Props extends ObjectProps> = {
|
|
|
5023
6311
|
*
|
|
5024
6312
|
* @group Objects
|
|
5025
6313
|
*/
|
|
5026
|
-
export declare const omit: <const Props extends ObjectProps, const Keys extends ReadonlyArray<keyof Props>, Rest extends ObjectRecordTypeNode | undefined = undefined>(objectType:
|
|
6314
|
+
export declare const omit: <const Props extends ObjectProps, const Keys extends ReadonlyArray<keyof Props>, Rest extends ObjectRecordTypeNode | undefined = undefined>(objectType: {
|
|
6315
|
+
readonly props: Props;
|
|
6316
|
+
readonly record?: Rest;
|
|
6317
|
+
} & NoInfer<ObjectType<Props, Rest>>, ...keys: Keys & ([ValidateOmitKeys<Keys>] extends [never] ? unknown : readonly [ValidationFailure<ValidateOmitKeys<Keys>>])) => ObjectType<Omit<Props, Keys[number]>, Rest>;
|
|
5027
6318
|
type ValidateOmitKeys<Keys extends ReadonlyArray<PropertyKey>> = number extends Keys["length"] ? OmitKeysTupleError : IsUnion<Keys["length"]> extends false ? {
|
|
5028
6319
|
readonly [Index in keyof Keys & `${number}`]: IsUnion<Keys[Index]> extends false ? {} extends Readonly<Record<Keys[Index], never>> ? OmitKeyConcreteTypeError : never : OmitKeyConcreteTypeError;
|
|
5029
6320
|
}[keyof Keys & `${number}`] : OmitKeysTupleError;
|
|
5030
6321
|
type OmitKeysTupleError = CompileTimeError<"Type", "Omitted keys must use one concrete finite tuple.">;
|
|
5031
6322
|
type OmitKeyConcreteTypeError = CompileTimeError<"Type", "Each omitted key must be one concrete property key.">;
|
|
6323
|
+
/**
|
|
6324
|
+
* The {@link Type} returned by {@link objectKeys}.
|
|
6325
|
+
*
|
|
6326
|
+
* @group Objects
|
|
6327
|
+
*/
|
|
6328
|
+
export interface ObjectKeysType<Key extends TypeNode, T extends TypeNode & {
|
|
6329
|
+
readonly props: ObjectProps;
|
|
6330
|
+
}> extends Type<"ObjectKeys", unknown, T["Output"], ObjectKeysError<T> | TransformOutputError<"ObjectKeys", InferErrors<T>>, typeof Unknown, ObjectKeysError<T> | TransformOutputError<"ObjectKeys", InferErrors<T>>, never, Readonly<Record<string, T["CanonicalInput"][keyof T["CanonicalInput"]]>>, false> {
|
|
6331
|
+
readonly key: Key;
|
|
6332
|
+
readonly output: T;
|
|
6333
|
+
readonly [reflectedTypesSymbol]?: Key | T;
|
|
6334
|
+
}
|
|
6335
|
+
/**
|
|
6336
|
+
* Renames a strict {@link object} Type's encoded keys using a string codec.
|
|
6337
|
+
*
|
|
6338
|
+
* The object declaration uses semantic keys. Each key must be a valid Output of
|
|
6339
|
+
* the key Type. Its canonical encoding becomes the external property name.
|
|
6340
|
+
* Decoding accepts those exact names; aliases and unknown properties are
|
|
6341
|
+
* rejected. Values, optionality, and semantic Output stay with the object Type.
|
|
6342
|
+
* Only the outer keys change. Nested field codecs keep their own behavior.
|
|
6343
|
+
*
|
|
6344
|
+
* Construction rejects invalid schema keys, duplicate encodings, and key codecs
|
|
6345
|
+
* that do not decode their encodings back to the declared keys. These are
|
|
6346
|
+
* schema mistakes; invalid external values return normal Type errors. Error
|
|
6347
|
+
* paths use the external names, including missing required properties.
|
|
6348
|
+
*
|
|
6349
|
+
* ### Example
|
|
6350
|
+
*
|
|
6351
|
+
* ```ts
|
|
6352
|
+
* import {
|
|
6353
|
+
* assertEqual,
|
|
6354
|
+
* assertErr,
|
|
6355
|
+
* assertOk,
|
|
6356
|
+
* CamelCaseIdentifierFromConstantCaseIdentifier,
|
|
6357
|
+
* object,
|
|
6358
|
+
* objectKeys,
|
|
6359
|
+
* optional,
|
|
6360
|
+
* PortFromString,
|
|
6361
|
+
* prefixed,
|
|
6362
|
+
* } from "@evolu/common";
|
|
6363
|
+
*
|
|
6364
|
+
* const Key = prefixed("APP_")(
|
|
6365
|
+
* CamelCaseIdentifierFromConstantCaseIdentifier,
|
|
6366
|
+
* );
|
|
6367
|
+
* const Settings = objectKeys(Key)(
|
|
6368
|
+
* object({ port: optional(PortFromString) }),
|
|
6369
|
+
* );
|
|
6370
|
+
*
|
|
6371
|
+
* const result = Settings.fromUnknown({ APP_PORT: "04000" });
|
|
6372
|
+
* assertOk(result, { port: 4000 });
|
|
6373
|
+
*
|
|
6374
|
+
* assertEqual(Settings.to(result.value), { APP_PORT: "4000" });
|
|
6375
|
+
*
|
|
6376
|
+
* assertErr(Settings.fromUnknown({ APP_POTR: "4000" }));
|
|
6377
|
+
* ```
|
|
6378
|
+
*
|
|
6379
|
+
* @group Objects
|
|
6380
|
+
*/
|
|
6381
|
+
export declare const objectKeys: <Key extends ConcreteTypeNode & {
|
|
6382
|
+
readonly Output: string;
|
|
6383
|
+
readonly CanonicalInput: string;
|
|
6384
|
+
}>(key: Key & ValidateOutput<Key>) => <T extends ConcreteTypeNode & {
|
|
6385
|
+
readonly name: "Object";
|
|
6386
|
+
readonly props: ObjectProps;
|
|
6387
|
+
readonly record?: never;
|
|
6388
|
+
}>(type: T & ValidateOutput<T>) => ObjectKeysType<Key, T>;
|
|
6389
|
+
/**
|
|
6390
|
+
* An error from the externally named object decoded by {@link objectKeys}.
|
|
6391
|
+
*
|
|
6392
|
+
* @group Objects
|
|
6393
|
+
*/
|
|
6394
|
+
export interface ObjectKeysError<T extends TypeNode & {
|
|
6395
|
+
readonly props: ObjectProps;
|
|
6396
|
+
}> extends TypeError<"ObjectKeys">, TransparentTypeError {
|
|
6397
|
+
readonly error: ObjectError<Readonly<Record<string, T["props"][keyof T["props"]][typeof errorsSymbol] | ObjectMissingPropertyError | ObjectExcessPropertyError>>>;
|
|
6398
|
+
}
|
|
5032
6399
|
/**
|
|
5033
6400
|
* Creates a {@link Type} for {@link Result} values.
|
|
5034
6401
|
*
|
|
@@ -5122,7 +6489,9 @@ export type UnknownResult = typeof UnknownResult.Output;
|
|
|
5122
6489
|
* type: "Loaded",
|
|
5123
6490
|
* value: "Evolu",
|
|
5124
6491
|
* });
|
|
6492
|
+
*
|
|
5125
6493
|
* assertFalse(Loading.is({ type: "Loading", progress: 1 }));
|
|
6494
|
+
*
|
|
5126
6495
|
* assertType<
|
|
5127
6496
|
* typeof Loading.Output extends { readonly type: "Loading" }
|
|
5128
6497
|
* ? true
|
|
@@ -5168,6 +6537,7 @@ export declare function typed<const Tag extends TypeName, const Props extends Ob
|
|
|
5168
6537
|
* } from "@evolu/common";
|
|
5169
6538
|
*
|
|
5170
6539
|
* const Open = typed("Open", { label: String }, record(String, String));
|
|
6540
|
+
*
|
|
5171
6541
|
* const result = Open.fromUnknown({
|
|
5172
6542
|
* type: "Open",
|
|
5173
6543
|
* label: "Ready",
|
|
@@ -5316,6 +6686,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
5316
6686
|
* };
|
|
5317
6687
|
*
|
|
5318
6688
|
* assertEqual(describeNext({ ok: true, value: "item" }), "Value: item");
|
|
6689
|
+
*
|
|
5319
6690
|
* assertEqual(
|
|
5320
6691
|
* describeNext({
|
|
5321
6692
|
* ok: false,
|
|
@@ -5323,6 +6694,7 @@ type TypedTypePropertyError = CompileTimeError<"Type", 'Additional properties mu
|
|
|
5323
6694
|
* }),
|
|
5324
6695
|
* "Done: complete",
|
|
5325
6696
|
* );
|
|
6697
|
+
*
|
|
5326
6698
|
* assertEqual(
|
|
5327
6699
|
* describeNext({
|
|
5328
6700
|
* ok: false,
|