@atproto/lex-schema 0.0.2 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +68 -0
- package/dist/core/$type.d.ts +6 -3
- package/dist/core/$type.d.ts.map +1 -1
- package/dist/core/$type.js +1 -0
- package/dist/core/$type.js.map +1 -1
- package/dist/core/record-key.d.ts +3 -3
- package/dist/core/record-key.d.ts.map +1 -1
- package/dist/core/record-key.js +12 -6
- package/dist/core/record-key.js.map +1 -1
- package/dist/core/result.d.ts.map +1 -1
- package/dist/core/result.js +6 -0
- package/dist/core/result.js.map +1 -1
- package/dist/core/string-format.d.ts +30 -27
- package/dist/core/string-format.d.ts.map +1 -1
- package/dist/core/string-format.js +56 -42
- package/dist/core/string-format.js.map +1 -1
- package/dist/core/types.d.ts +9 -1
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/types.js.map +1 -1
- package/dist/external.d.ts +31 -28
- package/dist/external.d.ts.map +1 -1
- package/dist/external.js +33 -17
- package/dist/external.js.map +1 -1
- package/dist/schema/_parameters.d.ts +2 -2
- package/dist/schema/_parameters.d.ts.map +1 -1
- package/dist/schema/array.d.ts +5 -6
- package/dist/schema/array.d.ts.map +1 -1
- package/dist/schema/array.js +5 -6
- package/dist/schema/array.js.map +1 -1
- package/dist/schema/blob.d.ts +2 -3
- package/dist/schema/blob.d.ts.map +1 -1
- package/dist/schema/blob.js +1 -2
- package/dist/schema/blob.js.map +1 -1
- package/dist/schema/boolean.d.ts +4 -5
- package/dist/schema/boolean.d.ts.map +1 -1
- package/dist/schema/boolean.js +2 -3
- package/dist/schema/boolean.js.map +1 -1
- package/dist/schema/bytes.d.ts +3 -4
- package/dist/schema/bytes.d.ts.map +1 -1
- package/dist/schema/bytes.js +2 -3
- package/dist/schema/bytes.js.map +1 -1
- package/dist/schema/cid.d.ts +13 -6
- package/dist/schema/cid.d.ts.map +1 -1
- package/dist/schema/cid.js +2 -4
- package/dist/schema/cid.js.map +1 -1
- package/dist/schema/custom.d.ts +3 -4
- package/dist/schema/custom.d.ts.map +1 -1
- package/dist/schema/custom.js +4 -3
- package/dist/schema/custom.js.map +1 -1
- package/dist/schema/dict.d.ts +3 -3
- package/dist/schema/dict.d.ts.map +1 -1
- package/dist/schema/dict.js +1 -1
- package/dist/schema/dict.js.map +1 -1
- package/dist/schema/discriminated-union.d.ts +15 -24
- package/dist/schema/discriminated-union.d.ts.map +1 -1
- package/dist/schema/discriminated-union.js +40 -64
- package/dist/schema/discriminated-union.js.map +1 -1
- package/dist/schema/enum.d.ts +8 -4
- package/dist/schema/enum.d.ts.map +1 -1
- package/dist/schema/enum.js +5 -3
- package/dist/schema/enum.js.map +1 -1
- package/dist/schema/integer.d.ts +3 -4
- package/dist/schema/integer.d.ts.map +1 -1
- package/dist/schema/integer.js +3 -4
- package/dist/schema/integer.js.map +1 -1
- package/dist/schema/intersection.d.ts +22 -14
- package/dist/schema/intersection.d.ts.map +1 -1
- package/dist/schema/intersection.js +12 -22
- package/dist/schema/intersection.js.map +1 -1
- package/dist/schema/literal.d.ts +7 -3
- package/dist/schema/literal.d.ts.map +1 -1
- package/dist/schema/literal.js +5 -3
- package/dist/schema/literal.js.map +1 -1
- package/dist/schema/never.d.ts +2 -2
- package/dist/schema/never.d.ts.map +1 -1
- package/dist/schema/never.js +1 -1
- package/dist/schema/never.js.map +1 -1
- package/dist/schema/null.d.ts +2 -3
- package/dist/schema/null.d.ts.map +1 -1
- package/dist/schema/null.js +1 -2
- package/dist/schema/null.js.map +1 -1
- package/dist/schema/nullable.d.ts +7 -0
- package/dist/schema/nullable.d.ts.map +1 -0
- package/dist/schema/nullable.js +19 -0
- package/dist/schema/nullable.js.map +1 -0
- package/dist/schema/object.d.ts +10 -44
- package/dist/schema/object.d.ts.map +1 -1
- package/dist/schema/object.js +10 -46
- package/dist/schema/object.js.map +1 -1
- package/dist/schema/optional.d.ts +7 -0
- package/dist/schema/optional.d.ts.map +1 -0
- package/dist/schema/optional.js +25 -0
- package/dist/schema/optional.js.map +1 -0
- package/dist/schema/params.d.ts +14 -19
- package/dist/schema/params.d.ts.map +1 -1
- package/dist/schema/params.js +10 -24
- package/dist/schema/params.js.map +1 -1
- package/dist/schema/payload.d.ts +4 -4
- package/dist/schema/payload.d.ts.map +1 -1
- package/dist/schema/payload.js.map +1 -1
- package/dist/schema/permission-set.d.ts +6 -6
- package/dist/schema/permission-set.d.ts.map +1 -1
- package/dist/schema/permission-set.js +1 -2
- package/dist/schema/permission-set.js.map +1 -1
- package/dist/schema/permission.d.ts +0 -1
- package/dist/schema/permission.d.ts.map +1 -1
- package/dist/schema/permission.js +0 -1
- package/dist/schema/permission.js.map +1 -1
- package/dist/schema/procedure.d.ts +8 -9
- package/dist/schema/procedure.d.ts.map +1 -1
- package/dist/schema/procedure.js +0 -1
- package/dist/schema/procedure.js.map +1 -1
- package/dist/schema/query.d.ts +7 -8
- package/dist/schema/query.d.ts.map +1 -1
- package/dist/schema/query.js +0 -1
- package/dist/schema/query.js.map +1 -1
- package/dist/schema/record.d.ts +34 -28
- package/dist/schema/record.d.ts.map +1 -1
- package/dist/schema/record.js +1 -2
- package/dist/schema/record.js.map +1 -1
- package/dist/schema/ref.d.ts +2 -3
- package/dist/schema/ref.d.ts.map +1 -1
- package/dist/schema/ref.js +1 -2
- package/dist/schema/ref.js.map +1 -1
- package/dist/schema/refine.d.ts +18 -0
- package/dist/schema/refine.d.ts.map +1 -0
- package/dist/schema/refine.js +33 -0
- package/dist/schema/refine.js.map +1 -0
- package/dist/schema/regexp.d.ts +7 -0
- package/dist/schema/regexp.d.ts.map +1 -0
- package/dist/schema/regexp.js +22 -0
- package/dist/schema/regexp.js.map +1 -0
- package/dist/schema/string.d.ts +4 -8
- package/dist/schema/string.d.ts.map +1 -1
- package/dist/schema/string.js +6 -3
- package/dist/schema/string.js.map +1 -1
- package/dist/schema/subscription.d.ts +7 -6
- package/dist/schema/subscription.d.ts.map +1 -1
- package/dist/schema/subscription.js.map +1 -1
- package/dist/schema/token.d.ts +2 -3
- package/dist/schema/token.d.ts.map +1 -1
- package/dist/schema/token.js +1 -2
- package/dist/schema/token.js.map +1 -1
- package/dist/schema/typed-object.d.ts +29 -27
- package/dist/schema/typed-object.d.ts.map +1 -1
- package/dist/schema/typed-object.js +1 -2
- package/dist/schema/typed-object.js.map +1 -1
- package/dist/schema/typed-ref.d.ts +2 -2
- package/dist/schema/typed-ref.d.ts.map +1 -1
- package/dist/schema/typed-ref.js +1 -1
- package/dist/schema/typed-ref.js.map +1 -1
- package/dist/schema/typed-union.d.ts +3 -4
- package/dist/schema/typed-union.d.ts.map +1 -1
- package/dist/schema/typed-union.js +3 -10
- package/dist/schema/typed-union.js.map +1 -1
- package/dist/schema/union.d.ts +2 -2
- package/dist/schema/union.d.ts.map +1 -1
- package/dist/schema/union.js +1 -1
- package/dist/schema/union.js.map +1 -1
- package/dist/schema/unknown-object.d.ts +2 -3
- package/dist/schema/unknown-object.d.ts.map +1 -1
- package/dist/schema/unknown-object.js +1 -2
- package/dist/schema/unknown-object.js.map +1 -1
- package/dist/schema/unknown.d.ts +2 -2
- package/dist/schema/unknown.d.ts.map +1 -1
- package/dist/schema/unknown.js +1 -1
- package/dist/schema/unknown.js.map +1 -1
- package/dist/schema.d.ts +4 -0
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +6 -1
- package/dist/schema.js.map +1 -1
- package/dist/util/array-agg.d.ts.map +1 -1
- package/dist/util/array-agg.js +1 -0
- package/dist/util/array-agg.js.map +1 -1
- package/dist/util/lazy-property.d.ts +2 -0
- package/dist/util/lazy-property.d.ts.map +1 -0
- package/dist/util/lazy-property.js +14 -0
- package/dist/util/lazy-property.js.map +1 -0
- package/dist/validation/schema.d.ts +24 -0
- package/dist/validation/schema.d.ts.map +1 -0
- package/dist/validation/schema.js +57 -0
- package/dist/validation/schema.js.map +1 -0
- package/dist/validation/validation-error.d.ts +3 -3
- package/dist/validation/validation-error.d.ts.map +1 -1
- package/dist/validation/validation-error.js +32 -4
- package/dist/validation/validation-error.js.map +1 -1
- package/dist/validation/validation-issue.d.ts +32 -24
- package/dist/validation/validation-issue.d.ts.map +1 -1
- package/dist/validation/validation-issue.js +136 -92
- package/dist/validation/validation-issue.js.map +1 -1
- package/dist/validation/validator.d.ts +20 -50
- package/dist/validation/validator.d.ts.map +1 -1
- package/dist/validation/validator.js +40 -134
- package/dist/validation/validator.js.map +1 -1
- package/dist/validation.d.ts +1 -0
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +1 -0
- package/dist/validation.js.map +1 -1
- package/package.json +8 -4
- package/src/core/$type.ts +7 -4
- package/src/core/record-key.ts +12 -5
- package/src/core/result.ts +6 -0
- package/src/core/string-format.ts +97 -61
- package/src/core/types.ts +12 -6
- package/src/external.ts +92 -70
- package/src/schema/_parameters.test.ts +416 -0
- package/src/schema/array.test.ts +237 -0
- package/src/schema/array.ts +17 -11
- package/src/schema/blob.test.ts +506 -0
- package/src/schema/blob.ts +3 -5
- package/src/schema/boolean.test.ts +116 -0
- package/src/schema/boolean.ts +5 -7
- package/src/schema/bytes.test.ts +226 -0
- package/src/schema/bytes.ts +4 -6
- package/src/schema/cid.test.ts +155 -0
- package/src/schema/cid.ts +14 -8
- package/src/schema/custom.test.ts +413 -0
- package/src/schema/custom.ts +10 -8
- package/src/schema/dict.test.ts +198 -0
- package/src/schema/dict.ts +6 -8
- package/src/schema/discriminated-union.test.ts +675 -0
- package/src/schema/discriminated-union.ts +68 -95
- package/src/schema/enum.test.ts +396 -0
- package/src/schema/enum.ts +12 -5
- package/src/schema/integer.test.ts +312 -0
- package/src/schema/integer.ts +5 -7
- package/src/schema/intersection.test.ts +32 -0
- package/src/schema/intersection.ts +37 -40
- package/src/schema/literal.test.ts +531 -0
- package/src/schema/literal.ts +12 -5
- package/src/schema/never.test.ts +174 -0
- package/src/schema/never.ts +3 -10
- package/src/schema/null.test.ts +79 -0
- package/src/schema/null.ts +3 -5
- package/src/schema/nullable.test.ts +480 -0
- package/src/schema/nullable.ts +23 -0
- package/src/schema/object.test.ts +47 -115
- package/src/schema/object.ts +19 -123
- package/src/schema/optional.test.ts +485 -0
- package/src/schema/optional.ts +31 -0
- package/src/schema/params.test.ts +582 -0
- package/src/schema/params.ts +37 -55
- package/src/schema/payload.test.ts +345 -0
- package/src/schema/payload.ts +5 -5
- package/src/schema/permission-set.test.ts +679 -0
- package/src/schema/permission-set.ts +6 -8
- package/src/schema/permission.test.ts +536 -0
- package/src/schema/permission.ts +0 -2
- package/src/schema/procedure.test.ts +443 -0
- package/src/schema/procedure.ts +11 -13
- package/src/schema/query.test.ts +408 -0
- package/src/schema/query.ts +9 -11
- package/src/schema/record.test.ts +694 -0
- package/src/schema/record.ts +38 -36
- package/src/schema/ref.test.ts +365 -0
- package/src/schema/ref.ts +8 -5
- package/src/schema/refine.test.ts +578 -0
- package/src/schema/refine.ts +85 -0
- package/src/schema/regexp.test.ts +580 -0
- package/src/schema/regexp.ts +22 -0
- package/src/schema/string.test.ts +612 -0
- package/src/schema/string.ts +11 -17
- package/src/schema/subscription.test.ts +689 -0
- package/src/schema/subscription.ts +13 -8
- package/src/schema/token.test.ts +428 -0
- package/src/schema/token.ts +3 -5
- package/src/schema/typed-object.test.ts +612 -0
- package/src/schema/typed-object.ts +23 -20
- package/src/schema/typed-ref.test.ts +823 -0
- package/src/schema/typed-ref.ts +10 -5
- package/src/schema/typed-union.test.ts +378 -0
- package/src/schema/typed-union.ts +6 -15
- package/src/schema/union.test.ts +200 -0
- package/src/schema/union.ts +5 -4
- package/src/schema/unknown-object.test.ts +592 -0
- package/src/schema/unknown-object.ts +3 -5
- package/src/schema/unknown.test.ts +312 -0
- package/src/schema/unknown.ts +3 -3
- package/src/schema.ts +7 -1
- package/src/util/array-agg.ts +1 -0
- package/src/util/lazy-property.ts +14 -0
- package/src/validation/schema.ts +92 -0
- package/src/validation/validation-error.ts +60 -9
- package/src/validation/validation-issue.ts +141 -144
- package/src/validation/validator.ts +67 -206
- package/src/validation.ts +1 -0
- package/tsconfig.build.json +12 -0
- package/tsconfig.json +7 -0
- package/tsconfig.tests.json +9 -0
|
@@ -1,72 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ValidatorContext =
|
|
3
|
+
exports.ValidatorContext = void 0;
|
|
4
4
|
const core_js_1 = require("../core.js");
|
|
5
5
|
const validation_error_js_1 = require("./validation-error.js");
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* This property is used for type inference purposes and does not actually
|
|
9
|
-
* exist at runtime.
|
|
10
|
-
*
|
|
11
|
-
* @deprecated For internal use only (not actually deprecated)
|
|
12
|
-
*/
|
|
13
|
-
_lex;
|
|
14
|
-
lexiconType;
|
|
15
|
-
assert(input) {
|
|
16
|
-
const result = this.validate(input, { allowTransform: false });
|
|
17
|
-
if (!result.success)
|
|
18
|
-
throw result.error;
|
|
19
|
-
}
|
|
20
|
-
check(input) {
|
|
21
|
-
const result = this.validate(input, { allowTransform: false });
|
|
22
|
-
return result.success;
|
|
23
|
-
}
|
|
24
|
-
maybe(input) {
|
|
25
|
-
return this.check(input) ? input : undefined;
|
|
26
|
-
}
|
|
27
|
-
parse(input, options) {
|
|
28
|
-
const result = ValidatorContext.validate(input, this, options);
|
|
29
|
-
if (!result.success)
|
|
30
|
-
throw result.error;
|
|
31
|
-
return result.value;
|
|
32
|
-
}
|
|
33
|
-
validate(input, options) {
|
|
34
|
-
return ValidatorContext.validate(input, this, options);
|
|
35
|
-
}
|
|
36
|
-
// @NOTE The built lexicons namespaces will export utility functions that
|
|
37
|
-
// allow accessing the schema's methods without the need to specify ".main."
|
|
38
|
-
// as part of the namespace. This way, a utility for a particular record type
|
|
39
|
-
// can be called like "app.bsky.feed.post.<utility>()" instead of
|
|
40
|
-
// "app.bsky.feed.post.main.<utility>()". Because those utilities could
|
|
41
|
-
// conflict with other schemas (e.g. if there is a lexicon definition at
|
|
42
|
-
// "#<utility>"), those exported utilities will be prefixed with "$". In order
|
|
43
|
-
// to be able to consistently call the utilities, when using the "main" and
|
|
44
|
-
// non "main" definitions, we also expose the same methods with a "$" prefix.
|
|
45
|
-
// Thanks to this, both of the following call will be possible:
|
|
46
|
-
//
|
|
47
|
-
// - "app.bsky.feed.post.$parse(...)" // calls a utility function created by "lex build"
|
|
48
|
-
// - "app.bsky.feed.defs.postView.$parse(...)" // uses the alias defined below on the schema instance
|
|
49
|
-
$assert(input) {
|
|
50
|
-
return this.assert(input);
|
|
51
|
-
}
|
|
52
|
-
$check(input) {
|
|
53
|
-
return this.check(input);
|
|
54
|
-
}
|
|
55
|
-
$maybe(input) {
|
|
56
|
-
return this.maybe(input);
|
|
57
|
-
}
|
|
58
|
-
$parse(input, options) {
|
|
59
|
-
return this.parse(input, options);
|
|
60
|
-
}
|
|
61
|
-
$validate(input, options) {
|
|
62
|
-
return this.validate(input, options);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
exports.Validator = Validator;
|
|
66
|
-
const asIssue = ({ path, ...issue }, currentPath) => ({
|
|
67
|
-
...issue,
|
|
68
|
-
path: path != null ? currentPath.concat(path) : [...currentPath],
|
|
69
|
-
});
|
|
6
|
+
const validation_issue_js_1 = require("./validation-issue.js");
|
|
70
7
|
class ValidatorContext {
|
|
71
8
|
options;
|
|
72
9
|
/**
|
|
@@ -82,14 +19,15 @@ class ValidatorContext {
|
|
|
82
19
|
constructor(options) {
|
|
83
20
|
this.options = options;
|
|
84
21
|
// Create a copy because we will be mutating the array during validation.
|
|
85
|
-
this.currentPath = options?.path != null ?
|
|
22
|
+
this.currentPath = options?.path != null ? Array.from(options.path) : [];
|
|
86
23
|
}
|
|
87
24
|
get path() {
|
|
88
|
-
return
|
|
25
|
+
return Array.from(this.currentPath);
|
|
89
26
|
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
27
|
+
concatPath(path) {
|
|
28
|
+
if (path == null)
|
|
29
|
+
return this.path;
|
|
30
|
+
return this.currentPath.concat(path);
|
|
93
31
|
}
|
|
94
32
|
/**
|
|
95
33
|
* This is basically the entry point for validation within a context. Use this
|
|
@@ -97,9 +35,13 @@ class ValidatorContext {
|
|
|
97
35
|
* this method enforces the {@link ValidationOptions.allowTransform} option.
|
|
98
36
|
*/
|
|
99
37
|
validate(input, validator) {
|
|
38
|
+
// This is the only place where validateInContext should be called.
|
|
100
39
|
const result = validator.validateInContext(input, this);
|
|
101
40
|
if (result.success) {
|
|
102
|
-
if (
|
|
41
|
+
if (
|
|
42
|
+
// Defaults to true
|
|
43
|
+
this.options?.allowTransform === false &&
|
|
44
|
+
!Object.is(result.value, input)) {
|
|
103
45
|
// If the value changed, it means that a default (or some other
|
|
104
46
|
// transformation) was applied, meaning that the original value did
|
|
105
47
|
// *not* match the (output) schema. When "allowTransform" is false, we
|
|
@@ -116,7 +58,7 @@ class ValidatorContext {
|
|
|
116
58
|
if (this.issues.length > 0) {
|
|
117
59
|
// Validator returned a success but issues were added via the context.
|
|
118
60
|
// This means the overall validation failed.
|
|
119
|
-
return
|
|
61
|
+
return (0, core_js_1.failure)(new validation_error_js_1.ValidationError(Array.from(this.issues)));
|
|
120
62
|
}
|
|
121
63
|
}
|
|
122
64
|
return result;
|
|
@@ -132,77 +74,41 @@ class ValidatorContext {
|
|
|
132
74
|
}
|
|
133
75
|
}
|
|
134
76
|
addIssue(issue) {
|
|
135
|
-
this.issues.push(
|
|
77
|
+
this.issues.push(issue);
|
|
136
78
|
}
|
|
137
79
|
success(value) {
|
|
138
80
|
return (0, core_js_1.success)(value);
|
|
139
81
|
}
|
|
140
82
|
failure(issue) {
|
|
141
|
-
return (0, core_js_1.failure)(new validation_error_js_1.ValidationError([...this.issues,
|
|
142
|
-
}
|
|
143
|
-
issueInvalidValue(input, values, path) {
|
|
144
|
-
return this.failure({
|
|
145
|
-
code: 'invalid_value',
|
|
146
|
-
input,
|
|
147
|
-
values,
|
|
148
|
-
path,
|
|
149
|
-
});
|
|
150
|
-
}
|
|
151
|
-
issueInvalidType(input, expected, path) {
|
|
152
|
-
return this.failure({
|
|
153
|
-
code: 'invalid_type',
|
|
154
|
-
input,
|
|
155
|
-
expected: Array.isArray(expected) ? expected : [expected],
|
|
156
|
-
path,
|
|
157
|
-
});
|
|
83
|
+
return (0, core_js_1.failure)(new validation_error_js_1.ValidationError([...this.issues, issue]));
|
|
158
84
|
}
|
|
159
|
-
|
|
160
|
-
return this.
|
|
85
|
+
issueInvalidValue(input, values) {
|
|
86
|
+
return this.failure(new validation_issue_js_1.IssueInvalidValue(this.path, input, values));
|
|
161
87
|
}
|
|
162
|
-
|
|
163
|
-
return this.
|
|
88
|
+
issueInvalidType(input, expected) {
|
|
89
|
+
return this.failure(new validation_issue_js_1.IssueInvalidType(this.path, input, [expected]));
|
|
164
90
|
}
|
|
165
91
|
issueRequiredKey(input, key) {
|
|
166
|
-
return this.failure(
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
actual,
|
|
187
|
-
input,
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
issueTooSmall(input, type, minimum, actual) {
|
|
191
|
-
return this.failure({
|
|
192
|
-
code: 'too_small',
|
|
193
|
-
type,
|
|
194
|
-
minimum,
|
|
195
|
-
actual,
|
|
196
|
-
input,
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
custom(input, message, path) {
|
|
200
|
-
return this.failure({
|
|
201
|
-
code: 'custom',
|
|
202
|
-
input,
|
|
203
|
-
message,
|
|
204
|
-
path,
|
|
205
|
-
});
|
|
92
|
+
return this.failure(new validation_issue_js_1.IssueRequiredKey(this.path, input, key));
|
|
93
|
+
}
|
|
94
|
+
issueInvalidFormat(input, format, msg) {
|
|
95
|
+
return this.failure(new validation_issue_js_1.IssueInvalidFormat(this.path, input, format, msg));
|
|
96
|
+
}
|
|
97
|
+
issueTooBig(input, type, max, actual) {
|
|
98
|
+
return this.failure(new validation_issue_js_1.IssueTooBig(this.path, input, max, type, actual));
|
|
99
|
+
}
|
|
100
|
+
issueTooSmall(input, type, min, actual) {
|
|
101
|
+
return this.failure(new validation_issue_js_1.IssueTooSmall(this.path, input, min, type, actual));
|
|
102
|
+
}
|
|
103
|
+
issueInvalidPropertyValue(input, property, values) {
|
|
104
|
+
const value = input[property];
|
|
105
|
+
const path = this.concatPath(property);
|
|
106
|
+
return this.failure(new validation_issue_js_1.IssueInvalidValue(path, value, values));
|
|
107
|
+
}
|
|
108
|
+
issueInvalidPropertyType(input, property, expected) {
|
|
109
|
+
const value = input[property];
|
|
110
|
+
const path = this.concatPath(property);
|
|
111
|
+
return this.failure(new validation_issue_js_1.IssueInvalidType(path, value, [expected]));
|
|
206
112
|
}
|
|
207
113
|
}
|
|
208
114
|
exports.ValidatorContext = ValidatorContext;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validation/validator.ts"],"names":[],"mappings":";;;AAAA,wCAA2E;AAE3E,+DAAuD;AAsBvD,MAAsB,SAAS;IAC7B;;;;;OAKG;IACH,IAAI,CAAqB;IAEhB,WAAW,CAAS;IAqC7B,MAAM,CAAC,KAAc;QACnB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9D,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,MAAM,CAAC,KAAK,CAAA;IACzC,CAAC;IAED,KAAK,CAAC,KAAc;QAClB,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,CAAA;QAC9D,OAAO,MAAM,CAAC,OAAO,CAAA;IACvB,CAAC;IAED,KAAK,CAAI,KAAQ;QACf,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9C,CAAC;IAOD,KAAK,CAAC,KAAc,EAAE,OAA2B;QAC/C,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;QAC9D,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,MAAM,MAAM,CAAC,KAAK,CAAA;QACvC,OAAO,MAAM,CAAC,KAAK,CAAA;IACrB,CAAC;IAUD,QAAQ,CACN,KAAc,EACd,OAA2B;QAE3B,OAAO,gBAAgB,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAA;IACxD,CAAC;IAED,yEAAyE;IACzE,4EAA4E;IAC5E,6EAA6E;IAC7E,iEAAiE;IACjE,uEAAuE;IACvE,wEAAwE;IACxE,8EAA8E;IAC9E,2EAA2E;IAC3E,6EAA6E;IAC7E,+DAA+D;IAC/D,EAAE;IACF,wFAAwF;IACxF,qGAAqG;IAErG,OAAO,CAAC,KAAc;QACpB,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IAC3B,CAAC;IAED,MAAM,CAAC,KAAc;QACnB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,MAAM,CAAI,KAAQ;QAChB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAC1B,CAAC;IAED,MAAM,CAAC,KAAc,EAAE,OAA2B;QAChD,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACnC,CAAC;IAED,SAAS,CACP,KAAc,EACd,OAA2B;QAE3B,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IACtC,CAAC;CACF;AA1HD,8BA0HC;AASD,MAAM,OAAO,GAAG,CACd,EAAE,IAAI,EAAE,GAAG,KAAK,EAAmB,EACnC,WAAmC,EACQ,EAAE,CAAC,CAAC;IAC/C,GAAG,KAAK;IACR,IAAI,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC;CACjE,CAAC,CAAA;AAEF,MAAa,gBAAgB;IAiBI;IAhB/B;;;OAGG;IACH,MAAM,CAAC,QAAQ,CACb,KAAc,EACd,SAAuB,EACvB,UAA6B,EAAE;QAE/B,MAAM,OAAO,GAAG,IAAI,gBAAgB,CAAC,OAAO,CAAC,CAAA;QAC7C,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAC3C,CAAC;IAEgB,WAAW,CAAe;IAC1B,MAAM,GAAsB,EAAE,CAAA;IAE/C,YAA+B,OAA0B;QAA1B,YAAO,GAAP,OAAO,CAAmB;QACvD,yEAAyE;QACzE,IAAI,CAAC,WAAW,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;IACnE,CAAC;IAED,IAAI,IAAI;QACN,OAAO,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC,CAAA;IAC9B,CAAC;IAED,IAAI,cAAc;QAChB,kBAAkB;QAClB,OAAO,IAAI,CAAC,OAAO,EAAE,cAAc,KAAK,KAAK,CAAA;IAC/C,CAAC;IAED;;;;OAIG;IACH,QAAQ,CAAI,KAAc,EAAE,SAAuB;QACjD,MAAM,MAAM,GAAG,SAAS,CAAC,iBAAiB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;QAEvD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YACnB,IAAI,CAAC,IAAI,CAAC,cAAc,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,CAAC;gBAC5D,+DAA+D;gBAC/D,mEAAmE;gBACnE,sEAAsE;gBACtE,2BAA2B;gBAE3B,sEAAsE;gBACtE,iEAAiE;gBACjE,iEAAiE;gBACjE,WAAW;gBAEX,qEAAqE;gBACrE,iEAAiE;gBACjE,sEAAsE;gBACtE,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YACtD,CAAC;YAED,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC3B,sEAAsE;gBACtE,4CAA4C;gBAC5C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,qCAAe,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAA;YACpE,CAAC;QACH,CAAC;QAED,OAAO,MAAM,CAAA;IACf,CAAC;IAED,aAAa,CACX,KAAQ,EACR,GAAM,EACN,SAAuB;QAEvB,wEAAwE;QACxE,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;QAC1B,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,SAAS,CAAC,CAAA;QAC7C,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,CAAA;QAC3B,CAAC;IACH,CAAC;IAED,QAAQ,CAAC,KAAsB;QAC7B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAA;IACpD,CAAC;IAED,OAAO,CAAI,KAAQ;QACjB,OAAO,IAAA,iBAAO,EAAC,KAAK,CAAC,CAAA;IACvB,CAAC;IAED,OAAO,CAAC,KAAsB;QAC5B,OAAO,IAAA,iBAAO,EACZ,IAAI,qCAAe,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CACxE,CAAA;IACH,CAAC;IAED,iBAAiB,CACf,KAAc,EACd,MAA0B,EAC1B,IAA2C;QAE3C,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,eAAe;YACrB,KAAK;YACL,MAAM;YACN,IAAI;SACL,CAAC,CAAA;IACJ,CAAC;IAED,gBAAgB,CACd,KAAc,EACd,QAAoC,EACpC,IAA2C;QAE3C,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,cAAc;YACpB,KAAK;YACL,QAAQ,EAAE,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YACzD,IAAI;SACL,CAAC,CAAA;IACJ,CAAC;IAED,yBAAyB,CACvB,KAAQ,EACR,QAA+B,EAC/B,MAA0B;QAE1B,OAAO,IAAI,CAAC,iBAAiB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAA;IAClE,CAAC;IAED,wBAAwB,CACtB,KAAQ,EACR,QAA+B,EAC/B,QAAoC;QAEpC,OAAO,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAA;IACnE,CAAC;IAED,gBAAgB,CAAC,KAAa,EAAE,GAAgB;QAC9C,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,cAAc;YACpB,GAAG;YACH,KAAK;YACL,IAAI,EAAE,GAAG;SACV,CAAC,CAAA;IACJ,CAAC;IAED,kBAAkB,CAAC,KAAc,EAAE,MAAc,EAAE,OAAgB;QACjE,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,gBAAgB;YACtB,OAAO;YACP,MAAM;YACN,KAAK;SACN,CAAC,CAAA;IACJ,CAAC;IAED,WAAW,CACT,KAAc,EACd,IAAyB,EACzB,OAAe,EACf,MAAc;QAEd,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,SAAS;YACf,IAAI;YACJ,OAAO;YACP,MAAM;YACN,KAAK;SACN,CAAC,CAAA;IACJ,CAAC;IAED,aAAa,CACX,KAAc,EACd,IAA2B,EAC3B,OAAe,EACf,MAAc;QAEd,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,WAAW;YACjB,IAAI;YACJ,OAAO;YACP,MAAM;YACN,KAAK;SACN,CAAC,CAAA;IACJ,CAAC;IAED,MAAM,CACJ,KAAc,EACd,OAAe,EACf,IAA2C;QAE3C,OAAO,IAAI,CAAC,OAAO,CAAC;YAClB,IAAI,EAAE,QAAQ;YACd,KAAK;YACL,OAAO;YACP,IAAI;SACL,CAAC,CAAA;IACJ,CAAC;CACF;AArMD,4CAqMC","sourcesContent":["import { ResultFailure, ResultSuccess, failure, success } from '../core.js'\nimport { PropertyKey } from './property-key.js'\nimport { ValidationError } from './validation-error.js'\nimport {\n IssueTooBig,\n IssueTooSmall,\n ValidationIssue,\n} from './validation-issue.js'\n\nexport type ValidationSuccess<Value = any> = ResultSuccess<Value>\nexport type ValidationFailure = ResultFailure<ValidationError>\nexport type ValidationResult<Value = any> =\n | ValidationSuccess<Value>\n | ValidationFailure\n\ntype ValidationOptions = {\n path?: PropertyKey[]\n\n /** @default true */\n allowTransform?: boolean\n}\n\nexport type Infer<T extends Validator> = T['_lex']['output']\n\nexport abstract class Validator<Output = any> {\n /**\n * This property is used for type inference purposes and does not actually\n * exist at runtime.\n *\n * @deprecated For internal use only (not actually deprecated)\n */\n _lex!: { output: Output }\n\n readonly lexiconType?: string\n\n /**\n * @internal **INTERNAL API, DO NOT USE**.\n *\n * Use {@link Validator.assert assert}, {@link Validator.check check},\n * {@link Validator.parse parse} or {@link Validator.validate validate}\n * instead.\n *\n * This method is implemented by subclasses to perform transformation and\n * validation of the input value. Do not call this method directly; as the\n * {@link ValidatorContext.options.allowTransform} option will **not** be\n * enforced. See {@link ValidatorContext.validate} for details. When\n * delegating validation from one validator sub-class implementation to\n * another schema, {@link ValidatorContext.validate} should be used instead\n * of calling {@link Validator.validateInContext}. This will allow to stop the\n * validation process if the value was transformed (by the other schema) but\n * transformations are not allowed.\n *\n * By convention, the {@link ValidationResult} must return the original input\n * value if validation was successful and no transformation was applied (i.e.\n * the input already conformed to the schema). If a default value, or any\n * other transformation was applied, the returned value c&an be different from\n * the input.\n *\n * This convention allows the {@link Validator.check check} and\n * {@link Validator.assert assert} methods to check whether the input value\n * exactly matches the schema (without defaults or transformations), by\n * checking if the returned value is strictly equal to the input.\n *\n * @see {@link ValidatorContext.validate}\n */\n abstract validateInContext(\n input: unknown,\n ctx: ValidatorContext,\n ): ValidationResult<Output>\n\n assert(input: unknown): asserts input is Output {\n const result = this.validate(input, { allowTransform: false })\n if (!result.success) throw result.error\n }\n\n check(input: unknown): input is Output {\n const result = this.validate(input, { allowTransform: false })\n return result.success\n }\n\n maybe<I>(input: I): (I & Output) | undefined {\n return this.check(input) ? input : undefined\n }\n\n parse<I>(\n input: I,\n options: ValidationOptions & { allowTransform: false },\n ): I & Output\n parse(input: unknown, options?: ValidationOptions): Output\n parse(input: unknown, options?: ValidationOptions): Output {\n const result = ValidatorContext.validate(input, this, options)\n if (!result.success) throw result.error\n return result.value\n }\n\n validate<I>(\n input: I,\n options: ValidationOptions & { allowTransform: false },\n ): ValidationResult<I & Output>\n validate(\n input: unknown,\n options?: ValidationOptions,\n ): ValidationResult<Output>\n validate(\n input: unknown,\n options?: ValidationOptions,\n ): ValidationResult<Output> {\n return ValidatorContext.validate(input, this, options)\n }\n\n // @NOTE The built lexicons namespaces will export utility functions that\n // allow accessing the schema's methods without the need to specify \".main.\"\n // as part of the namespace. This way, a utility for a particular record type\n // can be called like \"app.bsky.feed.post.<utility>()\" instead of\n // \"app.bsky.feed.post.main.<utility>()\". Because those utilities could\n // conflict with other schemas (e.g. if there is a lexicon definition at\n // \"#<utility>\"), those exported utilities will be prefixed with \"$\". In order\n // to be able to consistently call the utilities, when using the \"main\" and\n // non \"main\" definitions, we also expose the same methods with a \"$\" prefix.\n // Thanks to this, both of the following call will be possible:\n //\n // - \"app.bsky.feed.post.$parse(...)\" // calls a utility function created by \"lex build\"\n // - \"app.bsky.feed.defs.postView.$parse(...)\" // uses the alias defined below on the schema instance\n\n $assert(input: unknown): asserts input is Output {\n return this.assert(input)\n }\n\n $check(input: unknown): input is Output {\n return this.check(input)\n }\n\n $maybe<I>(input: I): (I & Output) | undefined {\n return this.maybe(input)\n }\n\n $parse(input: unknown, options?: ValidationOptions): Output {\n return this.parse(input, options)\n }\n\n $validate(\n input: unknown,\n options?: ValidationOptions,\n ): ValidationResult<Output> {\n return this.validate(input, options)\n }\n}\n\nexport type ContextualIssue = {\n [Code in ValidationIssue['code']]: Omit<\n Extract<ValidationIssue, { code: Code }>,\n 'path'\n > & { path?: PropertyKey | readonly PropertyKey[] }\n}[ValidationIssue['code']]\n\nconst asIssue = (\n { path, ...issue }: ContextualIssue,\n currentPath: readonly PropertyKey[],\n): ValidationIssue & { path: PropertyKey[] } => ({\n ...issue,\n path: path != null ? currentPath.concat(path) : [...currentPath],\n})\n\nexport class ValidatorContext {\n /**\n * Creates a new validation context and validates the input using the\n * provided validator.\n */\n static validate<V>(\n input: unknown,\n validator: Validator<V>,\n options: ValidationOptions = {},\n ): ValidationResult<V> {\n const context = new ValidatorContext(options)\n return context.validate(input, validator)\n }\n\n private readonly currentPath: PropertyKey[]\n private readonly issues: ValidationIssue[] = []\n\n protected constructor(readonly options: ValidationOptions) {\n // Create a copy because we will be mutating the array during validation.\n this.currentPath = options?.path != null ? [...options.path] : []\n }\n\n get path() {\n return [...this.currentPath]\n }\n\n get allowTransform() {\n // Default to true\n return this.options?.allowTransform !== false\n }\n\n /**\n * This is basically the entry point for validation within a context. Use this\n * method instead of {@link Validator.validateInContext} directly, because\n * this method enforces the {@link ValidationOptions.allowTransform} option.\n */\n validate<V>(input: unknown, validator: Validator<V>): ValidationResult<V> {\n const result = validator.validateInContext(input, this)\n\n if (result.success) {\n if (!this.allowTransform && !Object.is(result.value, input)) {\n // If the value changed, it means that a default (or some other\n // transformation) was applied, meaning that the original value did\n // *not* match the (output) schema. When \"allowTransform\" is false, we\n // consider this a failure.\n\n // This check is the reason why Validator.validateInContext should not\n // be used directly, and ValidatorContext.validate should be used\n // instead, even when delegating validation from one validator to\n // another.\n\n // This if block comes before the next one because 'this.issues' will\n // end-up being appended to the returned ValidationError (see the\n // \"failure\" method below), resulting in a more complete error report.\n return this.issueInvalidValue(input, [result.value])\n }\n\n if (this.issues.length > 0) {\n // Validator returned a success but issues were added via the context.\n // This means the overall validation failed.\n return { success: false, error: new ValidationError(this.issues) }\n }\n }\n\n return result\n }\n\n validateChild<I extends object, K extends PropertyKey & keyof I, V>(\n input: I,\n key: K,\n validator: Validator<V>,\n ): ValidationResult<V> {\n // Instead of creating a new context, we just push/pop the path segment.\n this.currentPath.push(key)\n try {\n return this.validate(input[key], validator)\n } finally {\n this.currentPath.length--\n }\n }\n\n addIssue(issue: ContextualIssue): void {\n this.issues.push(asIssue(issue, this.currentPath))\n }\n\n success<V>(value: V): ValidationResult<V> {\n return success(value)\n }\n\n failure(issue: ContextualIssue): ValidationFailure {\n return failure(\n new ValidationError([...this.issues, asIssue(issue, this.currentPath)]),\n )\n }\n\n issueInvalidValue(\n input: unknown,\n values: readonly unknown[],\n path?: PropertyKey | readonly PropertyKey[],\n ) {\n return this.failure({\n code: 'invalid_value',\n input,\n values,\n path,\n })\n }\n\n issueInvalidType(\n input: unknown,\n expected: string | readonly string[],\n path?: PropertyKey | readonly PropertyKey[],\n ) {\n return this.failure({\n code: 'invalid_type',\n input,\n expected: Array.isArray(expected) ? expected : [expected],\n path,\n })\n }\n\n issueInvalidPropertyValue<I>(\n input: I,\n property: keyof I & PropertyKey,\n values: readonly unknown[],\n ) {\n return this.issueInvalidValue(input[property], values, property)\n }\n\n issueInvalidPropertyType<I>(\n input: I,\n property: keyof I & PropertyKey,\n expected: string | readonly string[],\n ) {\n return this.issueInvalidType(input[property], expected, property)\n }\n\n issueRequiredKey(input: object, key: PropertyKey) {\n return this.failure({\n code: 'required_key',\n key,\n input,\n path: key,\n })\n }\n\n issueInvalidFormat(input: unknown, format: string, message?: string) {\n return this.failure({\n code: 'invalid_format',\n message,\n format,\n input,\n })\n }\n\n issueTooBig(\n input: unknown,\n type: IssueTooBig['type'],\n maximum: number,\n actual: number,\n ) {\n return this.failure({\n code: 'too_big',\n type,\n maximum,\n actual,\n input,\n })\n }\n\n issueTooSmall(\n input: unknown,\n type: IssueTooSmall['type'],\n minimum: number,\n actual: number,\n ) {\n return this.failure({\n code: 'too_small',\n type,\n minimum,\n actual,\n input,\n })\n }\n\n custom(\n input: unknown,\n message: string,\n path?: PropertyKey | readonly PropertyKey[],\n ) {\n return this.failure({\n code: 'custom',\n input,\n message,\n path,\n })\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/validation/validator.ts"],"names":[],"mappings":"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","sourcesContent":["import { ResultFailure, ResultSuccess, failure, success } from '../core.js'\nimport { PropertyKey } from './property-key.js'\nimport { ValidationError } from './validation-error.js'\nimport {\n Issue,\n IssueInvalidFormat,\n IssueInvalidType,\n IssueInvalidValue,\n IssueRequiredKey,\n IssueTooBig,\n IssueTooSmall,\n MeasurableType,\n} from './validation-issue.js'\n\nexport type ValidationSuccess<Value = any> = ResultSuccess<Value>\nexport type ValidationFailure = ResultFailure<ValidationError>\nexport type ValidationResult<Value = any> =\n | ValidationSuccess<Value>\n | ValidationFailure\n\nexport type ValidationOptions = {\n path?: PropertyKey[]\n\n /** @default true */\n allowTransform?: boolean\n}\n\nexport type Infer<T extends Validator> = T['_lex']['output']\n\nexport interface Validator<Output = any> {\n /**\n * This property is used for type inference purposes and does not actually\n * exist at runtime.\n *\n * @deprecated **INTERNAL API, DO NOT USE**.\n */\n readonly ['_lex']: { output: Output }\n\n /**\n * @internal **INTERNAL API**: use {@link ValidatorContext.validate} instead\n *\n * This method is implemented by subclasses to perform transformation and\n * validation of the input value. Do not call this method directly; as the\n * {@link ValidatorContext.options.allowTransform} option will **not** be\n * enforced. See {@link ValidatorContext.validate} for details. When\n * delegating validation from one validator sub-class implementation to\n * another schema, {@link ValidatorContext.validate} must be used instead of\n * calling {@link Validator.validateInContext}. This will allow to stop the\n * validation process if the value was transformed (by the other schema) but\n * transformations are not allowed.\n *\n * By convention, the {@link ValidationResult} must return the original input\n * value if validation was successful and no transformation was applied (i.e.\n * the input already conformed to the schema). If a default value, or any\n * other transformation was applied, the returned value c&an be different from\n * the input.\n *\n * This convention allows the {@link Validator.check check} and\n * {@link Validator.assert assert} methods to check whether the input value\n * exactly matches the schema (without defaults or transformations), by\n * checking if the returned value is strictly equal to the input.\n *\n * @see {@link ValidatorContext.validate}\n */\n validateInContext(\n input: unknown,\n ctx: ValidatorContext,\n ): ValidationResult<Output>\n}\n\nexport class ValidatorContext {\n /**\n * Creates a new validation context and validates the input using the\n * provided validator.\n */\n static validate<V>(\n input: unknown,\n validator: Validator<V>,\n options: ValidationOptions = {},\n ): ValidationResult<V> {\n const context = new ValidatorContext(options)\n return context.validate(input, validator)\n }\n\n private readonly currentPath: PropertyKey[]\n private readonly issues: Issue[] = []\n\n protected constructor(readonly options: ValidationOptions) {\n // Create a copy because we will be mutating the array during validation.\n this.currentPath = options?.path != null ? Array.from(options.path) : []\n }\n\n get path() {\n return Array.from(this.currentPath)\n }\n\n concatPath(path?: PropertyKey | readonly PropertyKey[]) {\n if (path == null) return this.path\n return this.currentPath.concat(path)\n }\n\n /**\n * This is basically the entry point for validation within a context. Use this\n * method instead of {@link Validator.validateInContext} directly, because\n * this method enforces the {@link ValidationOptions.allowTransform} option.\n */\n validate<V>(input: unknown, validator: Validator<V>): ValidationResult<V> {\n // This is the only place where validateInContext should be called.\n const result = validator.validateInContext(input, this)\n\n if (result.success) {\n if (\n // Defaults to true\n this.options?.allowTransform === false &&\n !Object.is(result.value, input)\n ) {\n // If the value changed, it means that a default (or some other\n // transformation) was applied, meaning that the original value did\n // *not* match the (output) schema. When \"allowTransform\" is false, we\n // consider this a failure.\n\n // This check is the reason why Validator.validateInContext should not\n // be used directly, and ValidatorContext.validate should be used\n // instead, even when delegating validation from one validator to\n // another.\n\n // This if block comes before the next one because 'this.issues' will\n // end-up being appended to the returned ValidationError (see the\n // \"failure\" method below), resulting in a more complete error report.\n return this.issueInvalidValue(input, [result.value])\n }\n\n if (this.issues.length > 0) {\n // Validator returned a success but issues were added via the context.\n // This means the overall validation failed.\n return failure(new ValidationError(Array.from(this.issues)))\n }\n }\n\n return result as ValidationResult<V>\n }\n\n validateChild<\n I extends object,\n K extends PropertyKey & keyof I,\n V extends Validator,\n >(input: I, key: K, validator: V): ValidationResult<Infer<V>> {\n // Instead of creating a new context, we just push/pop the path segment.\n this.currentPath.push(key)\n try {\n return this.validate(input[key], validator)\n } finally {\n this.currentPath.length--\n }\n }\n\n addIssue(issue: Issue): void {\n this.issues.push(issue)\n }\n\n success<V>(value: V): ValidationResult<V> {\n return success(value)\n }\n\n failure(issue: Issue): ValidationFailure {\n return failure(new ValidationError([...this.issues, issue]))\n }\n\n issueInvalidValue(input: unknown, values: readonly unknown[]) {\n return this.failure(new IssueInvalidValue(this.path, input, values))\n }\n\n issueInvalidType(input: unknown, expected: string) {\n return this.failure(new IssueInvalidType(this.path, input, [expected]))\n }\n\n issueRequiredKey(input: object, key: PropertyKey) {\n return this.failure(new IssueRequiredKey(this.path, input, key))\n }\n\n issueInvalidFormat(input: unknown, format: string, msg?: string) {\n return this.failure(new IssueInvalidFormat(this.path, input, format, msg))\n }\n\n issueTooBig(\n input: unknown,\n type: MeasurableType,\n max: number,\n actual: number,\n ) {\n return this.failure(new IssueTooBig(this.path, input, max, type, actual))\n }\n\n issueTooSmall(\n input: unknown,\n type: MeasurableType,\n min: number,\n actual: number,\n ) {\n return this.failure(new IssueTooSmall(this.path, input, min, type, actual))\n }\n\n issueInvalidPropertyValue<I>(\n input: I,\n property: keyof I & PropertyKey,\n values: readonly unknown[],\n ) {\n const value = input[property]\n const path = this.concatPath(property)\n return this.failure(new IssueInvalidValue(path, value, values))\n }\n\n issueInvalidPropertyType<I>(\n input: I,\n property: keyof I & PropertyKey,\n expected: string,\n ) {\n const value = input[property]\n const path = this.concatPath(property)\n return this.failure(new IssueInvalidType(path, value, [expected]))\n }\n}\n"]}
|
package/dist/validation.d.ts
CHANGED
package/dist/validation.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAA;AAC5C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA"}
|
|
1
|
+
{"version":3,"file":"validation.d.ts","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"AAAA,cAAc,8BAA8B,CAAA;AAC5C,cAAc,wBAAwB,CAAA;AACtC,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,2BAA2B,CAAA"}
|
package/dist/validation.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
const tslib_1 = require("tslib");
|
|
4
4
|
tslib_1.__exportStar(require("./validation/property-key.js"), exports);
|
|
5
|
+
tslib_1.__exportStar(require("./validation/schema.js"), exports);
|
|
5
6
|
tslib_1.__exportStar(require("./validation/validation-error.js"), exports);
|
|
6
7
|
tslib_1.__exportStar(require("./validation/validation-issue.js"), exports);
|
|
7
8
|
tslib_1.__exportStar(require("./validation/validator.js"), exports);
|
package/dist/validation.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":";;;AAAA,uEAA4C;AAC5C,2EAAgD;AAChD,2EAAgD;AAChD,oEAAyC","sourcesContent":["export * from './validation/property-key.js'\nexport * from './validation/validation-error.js'\nexport * from './validation/validation-issue.js'\nexport * from './validation/validator.js'\n"]}
|
|
1
|
+
{"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":";;;AAAA,uEAA4C;AAC5C,iEAAsC;AACtC,2EAAgD;AAChD,2EAAgD;AAChD,oEAAyC","sourcesContent":["export * from './validation/property-key.js'\nexport * from './validation/schema.js'\nexport * from './validation/validation-error.js'\nexport * from './validation/validation-issue.js'\nexport * from './validation/validator.js'\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atproto/lex-schema",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.3",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Lexicon schema system for AT Lexicons",
|
|
6
6
|
"keywords": [
|
|
@@ -16,7 +16,11 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"./src",
|
|
19
|
-
"./
|
|
19
|
+
"./tsconfig.build.json",
|
|
20
|
+
"./tsconfig.tests.json",
|
|
21
|
+
"./tsconfig.json",
|
|
22
|
+
"./dist",
|
|
23
|
+
"./CHANGELOG.md"
|
|
20
24
|
],
|
|
21
25
|
"sideEffects": false,
|
|
22
26
|
"type": "commonjs",
|
|
@@ -32,8 +36,8 @@
|
|
|
32
36
|
},
|
|
33
37
|
"dependencies": {
|
|
34
38
|
"tslib": "^2.8.1",
|
|
35
|
-
"@atproto/syntax": "0.4.
|
|
36
|
-
"@atproto/lex-data": "0.0.
|
|
39
|
+
"@atproto/syntax": "0.4.2",
|
|
40
|
+
"@atproto/lex-data": "0.0.2"
|
|
37
41
|
},
|
|
38
42
|
"devDependencies": {
|
|
39
43
|
"jest": "^28.1.2"
|
package/src/core/$type.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { NsidString } from './string-format.js'
|
|
2
2
|
|
|
3
3
|
export type $Type<
|
|
4
|
-
N extends
|
|
4
|
+
N extends NsidString = NsidString,
|
|
5
5
|
H extends string = string,
|
|
6
|
-
> = N extends
|
|
6
|
+
> = N extends NsidString
|
|
7
7
|
? string extends H
|
|
8
8
|
? N | `${N}#${string}`
|
|
9
9
|
: H extends 'main'
|
|
@@ -11,7 +11,10 @@ export type $Type<
|
|
|
11
11
|
: `${N}#${H}`
|
|
12
12
|
: never
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export type $TypeOf<O extends { $type?: string }> = NonNullable<O['$type']>
|
|
15
|
+
|
|
16
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
17
|
+
export function $type<N extends NsidString, H extends string>(
|
|
15
18
|
nsid: N,
|
|
16
19
|
hash: H,
|
|
17
20
|
): $Type<N, H> {
|
package/src/core/record-key.ts
CHANGED
|
@@ -1,15 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
import { isValidRecordKey } from '@atproto/syntax'
|
|
2
2
|
|
|
3
|
-
export
|
|
3
|
+
export type LexiconRecordKey = 'any' | 'nsid' | 'tid' | `literal:${string}`
|
|
4
|
+
|
|
5
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
6
|
+
export function isLexiconRecordKey<T>(key: T): key is T & LexiconRecordKey {
|
|
4
7
|
return (
|
|
5
8
|
key === 'any' ||
|
|
6
9
|
key === 'nsid' ||
|
|
7
10
|
key === 'tid' ||
|
|
8
|
-
(typeof key === 'string' &&
|
|
11
|
+
(typeof key === 'string' &&
|
|
12
|
+
key.startsWith('literal:') &&
|
|
13
|
+
key.length > 8 &&
|
|
14
|
+
isValidRecordKey(key.slice(8)))
|
|
9
15
|
)
|
|
10
16
|
}
|
|
11
17
|
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
19
|
+
export function asLexiconRecordKey(key: unknown): LexiconRecordKey {
|
|
20
|
+
if (isLexiconRecordKey(key)) return key
|
|
14
21
|
throw new Error(`Invalid record key: ${String(key)}`)
|
|
15
22
|
}
|
package/src/core/result.ts
CHANGED
|
@@ -3,18 +3,22 @@ export type ResultFailure<E = Error> = { success: false; error: E }
|
|
|
3
3
|
|
|
4
4
|
export type Result<V = any, E = Error> = ResultSuccess<V> | ResultFailure<E>
|
|
5
5
|
|
|
6
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
6
7
|
export function success<V>(value: V): ResultSuccess<V> {
|
|
7
8
|
return { success: true, value }
|
|
8
9
|
}
|
|
9
10
|
|
|
11
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
10
12
|
export function failure<E>(error: E): ResultFailure<E> {
|
|
11
13
|
return { success: false, error }
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
14
17
|
export function failureError<T>(result: ResultFailure<T>): T {
|
|
15
18
|
return result.error
|
|
16
19
|
}
|
|
17
20
|
|
|
21
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
18
22
|
export function successValue<T>(result: ResultSuccess<T>): T {
|
|
19
23
|
return result.value
|
|
20
24
|
}
|
|
@@ -38,6 +42,7 @@ export function successValue<T>(result: ResultSuccess<T>): T {
|
|
|
38
42
|
* }
|
|
39
43
|
* ```
|
|
40
44
|
*/
|
|
45
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
41
46
|
export function catchall(err: unknown): ResultFailure<Error> {
|
|
42
47
|
if (err instanceof Error) return failure(err)
|
|
43
48
|
return failure(new Error('Unknown error', { cause: err }))
|
|
@@ -65,6 +70,7 @@ export function catchall(err: unknown): ResultFailure<Error> {
|
|
|
65
70
|
* console.error(result.error) // FooError | BarError
|
|
66
71
|
* }
|
|
67
72
|
*/
|
|
73
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
68
74
|
export function createCatcher<T>(Ctor: new (...args: any[]) => T) {
|
|
69
75
|
return (err: unknown): ResultFailure<T> => {
|
|
70
76
|
if (err instanceof Ctor) return failure(err)
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { ensureValidCidString, isLanguage } from '@atproto/lex-data'
|
|
2
2
|
import {
|
|
3
|
+
AtIdentifierString,
|
|
4
|
+
AtUriString,
|
|
5
|
+
DatetimeString,
|
|
6
|
+
DidString,
|
|
7
|
+
HandleString,
|
|
8
|
+
NsidString,
|
|
9
|
+
RecordKeyString,
|
|
10
|
+
TidString,
|
|
11
|
+
ensureValidAtIdentifier,
|
|
3
12
|
ensureValidAtUri,
|
|
4
13
|
ensureValidDatetime,
|
|
5
14
|
ensureValidDid,
|
|
@@ -9,13 +18,87 @@ import {
|
|
|
9
18
|
ensureValidTid,
|
|
10
19
|
} from '@atproto/syntax'
|
|
11
20
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
21
|
+
type AssertFn<T> = <I extends string>(input: I) => asserts input is I & T
|
|
22
|
+
type CastFn<T> = <I extends string>(input: I) => I & T
|
|
23
|
+
|
|
24
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
25
|
+
function createCastFunction<T>(assertFn: AssertFn<T>): CastFn<T> {
|
|
26
|
+
return <I extends string>(input: I) => {
|
|
27
|
+
assertFn(input)
|
|
28
|
+
return input as I & T
|
|
16
29
|
}
|
|
17
30
|
}
|
|
18
31
|
|
|
32
|
+
// Re-export utility typed as assertion functions so that TypeScript can
|
|
33
|
+
// infer the narrowed type after calling them.
|
|
34
|
+
|
|
35
|
+
export type {
|
|
36
|
+
AtIdentifierString,
|
|
37
|
+
AtUriString,
|
|
38
|
+
DatetimeString,
|
|
39
|
+
DidString,
|
|
40
|
+
HandleString,
|
|
41
|
+
NsidString,
|
|
42
|
+
RecordKeyString,
|
|
43
|
+
TidString,
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const assertDid: AssertFn<DidString> = ensureValidDid
|
|
47
|
+
export const assertAtUri: AssertFn<AtUriString> = ensureValidAtUri
|
|
48
|
+
export const assertAtIdentifier: AssertFn<AtIdentifierString> =
|
|
49
|
+
ensureValidAtIdentifier
|
|
50
|
+
export const assertNsid: AssertFn<NsidString> = ensureValidNsid
|
|
51
|
+
export const assertTid: AssertFn<TidString> = ensureValidTid
|
|
52
|
+
export const assertRecordKey: AssertFn<RecordKeyString> = ensureValidRecordKey
|
|
53
|
+
export const assertDatetime: AssertFn<DatetimeString> = ensureValidDatetime
|
|
54
|
+
export const assertCidString: AssertFn<string> = ensureValidCidString
|
|
55
|
+
export const assertHandle: AssertFn<HandleString> = ensureValidHandle
|
|
56
|
+
|
|
57
|
+
// Export utilities for formats missing from @atproto/syntax
|
|
58
|
+
|
|
59
|
+
export type CidString = string
|
|
60
|
+
export type UriString = `${string}:${string}`
|
|
61
|
+
export type LanguageString = string
|
|
62
|
+
|
|
63
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
64
|
+
export function assertUri(input: string): asserts input is UriString {
|
|
65
|
+
if (!/^\w+:(?:\/\/)?[^\s/][^\s]*$/.test(input)) {
|
|
66
|
+
throw new Error('Invalid URI')
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
71
|
+
export function assertLanguage(input: string): asserts input is LanguageString {
|
|
72
|
+
if (!isLanguage(input)) {
|
|
73
|
+
throw new Error('Invalid BCP 47 string')
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const asDid: CastFn<DidString> =
|
|
78
|
+
/*#__PURE__*/ createCastFunction(ensureValidDid)
|
|
79
|
+
export const asAtUri: CastFn<AtUriString> =
|
|
80
|
+
/*#__PURE__*/ createCastFunction(ensureValidAtUri)
|
|
81
|
+
export const asNsid: CastFn<NsidString> =
|
|
82
|
+
/*#__PURE__*/ createCastFunction(ensureValidNsid)
|
|
83
|
+
export const asTid: CastFn<TidString> =
|
|
84
|
+
/*#__PURE__*/ createCastFunction(ensureValidTid)
|
|
85
|
+
export const asRecordKey: CastFn<RecordKeyString> =
|
|
86
|
+
/*#__PURE__*/ createCastFunction(ensureValidRecordKey)
|
|
87
|
+
export const asDatetime: CastFn<DatetimeString> =
|
|
88
|
+
/*#__PURE__*/ createCastFunction(ensureValidDatetime)
|
|
89
|
+
export const asCidString: CastFn<string> =
|
|
90
|
+
/*#__PURE__*/ createCastFunction(ensureValidCidString)
|
|
91
|
+
export const asHandle: CastFn<HandleString> =
|
|
92
|
+
/*#__PURE__*/ createCastFunction(ensureValidHandle)
|
|
93
|
+
export const asUri: CastFn<UriString> =
|
|
94
|
+
/*#__PURE__*/ createCastFunction(assertUri)
|
|
95
|
+
export const asLanguage: CastFn<LanguageString> =
|
|
96
|
+
/*#__PURE__*/ createCastFunction(assertLanguage)
|
|
97
|
+
export const asAtIdentifier: CastFn<AtIdentifierString> =
|
|
98
|
+
/*#__PURE__*/ createCastFunction(assertAtIdentifier)
|
|
99
|
+
|
|
100
|
+
// String formatting types and utilities
|
|
101
|
+
|
|
19
102
|
export const STRING_FORMATS = Object.freeze([
|
|
20
103
|
'datetime',
|
|
21
104
|
'uri',
|
|
@@ -32,72 +115,24 @@ export const STRING_FORMATS = Object.freeze([
|
|
|
32
115
|
|
|
33
116
|
export type StringFormat = (typeof STRING_FORMATS)[number]
|
|
34
117
|
|
|
35
|
-
export type Did<M extends string = string> = `did:${M}:${string}`
|
|
36
|
-
export type Uri = `${string}:${string}`
|
|
37
|
-
export type Nsid = `${string}.${string}.${string}`
|
|
38
|
-
/** An ISO 8601 formatted datetime string (YYYY-MM-DDTHH:mm:ss.sssZ) */
|
|
39
|
-
export type Datetime = `${string}T${string}`
|
|
40
|
-
export type Handle = `${string}.${string}`
|
|
41
|
-
export type AtIdentifier = Did | Handle
|
|
42
|
-
export type AtUri = `at://${AtIdentifier}/${Nsid}/${string}`
|
|
43
|
-
|
|
44
118
|
export type InferStringFormat<F> =
|
|
45
119
|
//
|
|
46
120
|
F extends 'datetime'
|
|
47
|
-
?
|
|
121
|
+
? DatetimeString
|
|
48
122
|
: F extends 'uri'
|
|
49
|
-
?
|
|
123
|
+
? UriString
|
|
50
124
|
: F extends 'at-uri'
|
|
51
|
-
?
|
|
125
|
+
? AtUriString
|
|
52
126
|
: F extends 'did'
|
|
53
|
-
?
|
|
127
|
+
? DidString
|
|
54
128
|
: F extends 'handle'
|
|
55
|
-
?
|
|
129
|
+
? HandleString
|
|
56
130
|
: F extends 'at-identifier'
|
|
57
|
-
?
|
|
131
|
+
? AtIdentifierString
|
|
58
132
|
: F extends 'nsid'
|
|
59
|
-
?
|
|
60
|
-
:
|
|
61
|
-
|
|
62
|
-
type AssertFn<T> = <I extends string>(input: I) => asserts input is I & T
|
|
63
|
-
|
|
64
|
-
// Re-export utility typed as assertion functions so that TypeScript can
|
|
65
|
-
// infer the narrowed type after calling them.
|
|
66
|
-
|
|
67
|
-
export const assertDid: AssertFn<Did> = ensureValidDid
|
|
68
|
-
export const assertAtUri: AssertFn<AtUri> = ensureValidAtUri
|
|
69
|
-
export const assertNsid: AssertFn<Nsid> = ensureValidNsid
|
|
70
|
-
export const assertTid: AssertFn<string> = ensureValidTid
|
|
71
|
-
export const assertRecordKey: AssertFn<string> = ensureValidRecordKey
|
|
72
|
-
export const assertDatetime: AssertFn<Datetime> = ensureValidDatetime
|
|
73
|
-
export const assertCidString: AssertFn<string> = ensureValidCidString
|
|
74
|
-
export const assertHandle: AssertFn<Handle> = ensureValidHandle
|
|
75
|
-
|
|
76
|
-
// Export utilities for formats missing from @atproto/syntax
|
|
77
|
-
|
|
78
|
-
export const assertUri: AssertFn<Uri> = (input) => {
|
|
79
|
-
if (!/^\w+:(?:\/\/)?[^\s/][^\s]*$/.test(input)) {
|
|
80
|
-
throw new Error('Invalid URI')
|
|
81
|
-
}
|
|
82
|
-
}
|
|
83
|
-
export const assertLanguage: AssertFn<string> = (input) => {
|
|
84
|
-
if (!isLanguage(input)) {
|
|
85
|
-
throw new Error('Invalid BCP 47 string')
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
export const assertAtIdentifier: AssertFn<AtIdentifier> = (input) => {
|
|
89
|
-
if (input.startsWith('did:web:') || input.startsWith('did:plc:')) {
|
|
90
|
-
assertDid(input)
|
|
91
|
-
} else if (input.startsWith('did:')) {
|
|
92
|
-
throw new Error('Invalid DID method')
|
|
93
|
-
} else {
|
|
94
|
-
try {
|
|
95
|
-
assertHandle(input)
|
|
96
|
-
} catch (cause) {
|
|
97
|
-
throw new Error('Invalid DID or handle', { cause })
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
133
|
+
? NsidString
|
|
134
|
+
: // LanguageString | CidString | TidString | RecordKeyString
|
|
135
|
+
string
|
|
101
136
|
|
|
102
137
|
const formatters = /*#__PURE__*/ new Map<StringFormat, (str: string) => void>([
|
|
103
138
|
['datetime', assertDatetime],
|
|
@@ -113,6 +148,7 @@ const formatters = /*#__PURE__*/ new Map<StringFormat, (str: string) => void>([
|
|
|
113
148
|
['record-key', assertRecordKey],
|
|
114
149
|
] as const)
|
|
115
150
|
|
|
151
|
+
/*@__NO_SIDE_EFFECTS__*/
|
|
116
152
|
export function assertStringFormat<F extends StringFormat>(
|
|
117
153
|
input: string,
|
|
118
154
|
format: F,
|