@sanity/validation 3.0.0-v3-pte.80 → 3.0.0-v3-pkg-utils.59

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.
Files changed (139) hide show
  1. package/lib/dts/src/index.d.ts +28 -13
  2. package/lib/index.cjs +1446 -1266
  3. package/lib/index.cjs.map +1 -1
  4. package/lib/index.js +1435 -1265
  5. package/lib/index.js.map +1 -1
  6. package/package.json +21 -16
  7. package/src/index.ts +1 -1
  8. package/src/validateDocument.ts +1 -1
  9. package/dist/tsconfig.tsbuildinfo +0 -1
  10. package/lib/dts/src/Rule.d.ts +0 -4
  11. package/lib/dts/src/Rule.d.ts.map +0 -1
  12. package/lib/dts/src/Rule.js +0 -336
  13. package/lib/dts/src/Rule.js.map +0 -1
  14. package/lib/dts/src/ValidationError.d.ts +0 -4
  15. package/lib/dts/src/ValidationError.d.ts.map +0 -1
  16. package/lib/dts/src/ValidationError.js +0 -18
  17. package/lib/dts/src/ValidationError.js.map +0 -1
  18. package/lib/dts/src/index.d.ts.map +0 -1
  19. package/lib/dts/src/index.js +0 -7
  20. package/lib/dts/src/index.js.map +0 -1
  21. package/lib/dts/src/inferFromSchema.d.ts +0 -4
  22. package/lib/dts/src/inferFromSchema.d.ts.map +0 -1
  23. package/lib/dts/src/inferFromSchema.js +0 -14
  24. package/lib/dts/src/inferFromSchema.js.map +0 -1
  25. package/lib/dts/src/inferFromSchemaType.d.ts +0 -5
  26. package/lib/dts/src/inferFromSchemaType.d.ts.map +0 -1
  27. package/lib/dts/src/inferFromSchemaType.js +0 -33
  28. package/lib/dts/src/inferFromSchemaType.js.map +0 -1
  29. package/lib/dts/src/util/convertToValidationMarker.d.ts +0 -6
  30. package/lib/dts/src/util/convertToValidationMarker.d.ts.map +0 -1
  31. package/lib/dts/src/util/convertToValidationMarker.js +0 -51
  32. package/lib/dts/src/util/convertToValidationMarker.js.map +0 -1
  33. package/lib/dts/src/util/deepEquals.d.ts +0 -6
  34. package/lib/dts/src/util/deepEquals.d.ts.map +0 -1
  35. package/lib/dts/src/util/deepEquals.js +0 -65
  36. package/lib/dts/src/util/deepEquals.js.map +0 -1
  37. package/lib/dts/src/util/escapeRegex.d.ts +0 -3
  38. package/lib/dts/src/util/escapeRegex.d.ts.map +0 -1
  39. package/lib/dts/src/util/escapeRegex.js +0 -6
  40. package/lib/dts/src/util/escapeRegex.js.map +0 -1
  41. package/lib/dts/src/util/normalizeValidationRules.d.ts +0 -6
  42. package/lib/dts/src/util/normalizeValidationRules.d.ts.map +0 -1
  43. package/lib/dts/src/util/normalizeValidationRules.js +0 -104
  44. package/lib/dts/src/util/normalizeValidationRules.js.map +0 -1
  45. package/lib/dts/src/util/normalizeValidationRules.test.d.ts +0 -2
  46. package/lib/dts/src/util/normalizeValidationRules.test.d.ts.map +0 -1
  47. package/lib/dts/src/util/normalizeValidationRules.test.js +0 -150
  48. package/lib/dts/src/util/normalizeValidationRules.test.js.map +0 -1
  49. package/lib/dts/src/util/pathToString.d.ts +0 -3
  50. package/lib/dts/src/util/pathToString.d.ts.map +0 -1
  51. package/lib/dts/src/util/pathToString.js +0 -18
  52. package/lib/dts/src/util/pathToString.js.map +0 -1
  53. package/lib/dts/src/util/typeString.d.ts +0 -2
  54. package/lib/dts/src/util/typeString.d.ts.map +0 -1
  55. package/lib/dts/src/util/typeString.js +0 -23
  56. package/lib/dts/src/util/typeString.js.map +0 -1
  57. package/lib/dts/src/util/typeString.test.d.ts +0 -2
  58. package/lib/dts/src/util/typeString.test.d.ts.map +0 -1
  59. package/lib/dts/src/util/typeString.test.js +0 -24
  60. package/lib/dts/src/util/typeString.test.js.map +0 -1
  61. package/lib/dts/src/validateDocument.d.ts +0 -23
  62. package/lib/dts/src/validateDocument.d.ts.map +0 -1
  63. package/lib/dts/src/validateDocument.js +0 -143
  64. package/lib/dts/src/validateDocument.js.map +0 -1
  65. package/lib/dts/src/validateDocument.test.d.ts +0 -2
  66. package/lib/dts/src/validateDocument.test.d.ts.map +0 -1
  67. package/lib/dts/src/validateDocument.test.js +0 -710
  68. package/lib/dts/src/validateDocument.test.js.map +0 -1
  69. package/lib/dts/src/validators/arrayValidator.d.ts +0 -4
  70. package/lib/dts/src/validators/arrayValidator.d.ts.map +0 -1
  71. package/lib/dts/src/validators/arrayValidator.js +0 -79
  72. package/lib/dts/src/validators/arrayValidator.js.map +0 -1
  73. package/lib/dts/src/validators/booleanValidator.d.ts +0 -4
  74. package/lib/dts/src/validators/booleanValidator.d.ts.map +0 -1
  75. package/lib/dts/src/validators/booleanValidator.js +0 -12
  76. package/lib/dts/src/validators/booleanValidator.js.map +0 -1
  77. package/lib/dts/src/validators/dateValidator.d.ts +0 -5
  78. package/lib/dts/src/validators/dateValidator.d.ts.map +0 -1
  79. package/lib/dts/src/validators/dateValidator.js +0 -83
  80. package/lib/dts/src/validators/dateValidator.js.map +0 -1
  81. package/lib/dts/src/validators/genericValidator.d.ts +0 -4
  82. package/lib/dts/src/validators/genericValidator.d.ts.map +0 -1
  83. package/lib/dts/src/validators/genericValidator.js +0 -93
  84. package/lib/dts/src/validators/genericValidator.js.map +0 -1
  85. package/lib/dts/src/validators/numberValidator.d.ts +0 -4
  86. package/lib/dts/src/validators/numberValidator.d.ts.map +0 -1
  87. package/lib/dts/src/validators/numberValidator.js +0 -47
  88. package/lib/dts/src/validators/numberValidator.js.map +0 -1
  89. package/lib/dts/src/validators/objectValidator.d.ts +0 -4
  90. package/lib/dts/src/validators/objectValidator.d.ts.map +0 -1
  91. package/lib/dts/src/validators/objectValidator.js +0 -48
  92. package/lib/dts/src/validators/objectValidator.js.map +0 -1
  93. package/lib/dts/src/validators/slugValidator.d.ts +0 -9
  94. package/lib/dts/src/validators/slugValidator.d.ts.map +0 -1
  95. package/lib/dts/src/validators/slugValidator.js +0 -83
  96. package/lib/dts/src/validators/slugValidator.js.map +0 -1
  97. package/lib/dts/src/validators/stringValidator.d.ts +0 -4
  98. package/lib/dts/src/validators/stringValidator.d.ts.map +0 -1
  99. package/lib/dts/src/validators/stringValidator.js +0 -94
  100. package/lib/dts/src/validators/stringValidator.js.map +0 -1
  101. package/lib/dts/test/array.test.d.ts +0 -2
  102. package/lib/dts/test/array.test.d.ts.map +0 -1
  103. package/lib/dts/test/array.test.js +0 -55
  104. package/lib/dts/test/array.test.js.map +0 -1
  105. package/lib/dts/test/children.test.d.ts +0 -2
  106. package/lib/dts/test/children.test.d.ts.map +0 -1
  107. package/lib/dts/test/children.test.js +0 -70
  108. package/lib/dts/test/children.test.js.map +0 -1
  109. package/lib/dts/test/createSchema.d.ts +0 -6
  110. package/lib/dts/test/createSchema.d.ts.map +0 -1
  111. package/lib/dts/test/createSchema.js +0 -19
  112. package/lib/dts/test/createSchema.js.map +0 -1
  113. package/lib/dts/test/generics.test.d.ts +0 -2
  114. package/lib/dts/test/generics.test.d.ts.map +0 -1
  115. package/lib/dts/test/generics.test.js +0 -60
  116. package/lib/dts/test/generics.test.js.map +0 -1
  117. package/lib/dts/test/infer.test.d.ts +0 -2
  118. package/lib/dts/test/infer.test.d.ts.map +0 -1
  119. package/lib/dts/test/infer.test.js +0 -243
  120. package/lib/dts/test/infer.test.js.map +0 -1
  121. package/lib/dts/test/mocks/mockSanityClient.d.ts +0 -6
  122. package/lib/dts/test/mocks/mockSanityClient.d.ts.map +0 -1
  123. package/lib/dts/test/mocks/mockSanityClient.js +0 -8
  124. package/lib/dts/test/mocks/mockSanityClient.js.map +0 -1
  125. package/lib/dts/test/nullExport.d.ts +0 -3
  126. package/lib/dts/test/nullExport.d.ts.map +0 -1
  127. package/lib/dts/test/nullExport.js +0 -4
  128. package/lib/dts/test/nullExport.js.map +0 -1
  129. package/lib/dts/test/numbers.test.d.ts +0 -2
  130. package/lib/dts/test/numbers.test.d.ts.map +0 -1
  131. package/lib/dts/test/numbers.test.js +0 -57
  132. package/lib/dts/test/numbers.test.js.map +0 -1
  133. package/lib/dts/test/strings.test.d.ts +0 -2
  134. package/lib/dts/test/strings.test.d.ts.map +0 -1
  135. package/lib/dts/test/strings.test.js +0 -100
  136. package/lib/dts/test/strings.test.js.map +0 -1
  137. package/lib/dts/tsconfig.lib.tsbuildinfo +0 -1
  138. package/lib/dts/tsconfig.tsbuildinfo +0 -1
  139. package/tsconfig.tsbuildinfo +0 -1
package/lib/index.cjs CHANGED
@@ -1,1318 +1,1498 @@
1
1
  'use strict';
2
2
 
3
+ const _excluded = ["value", "type", "path", "parent"];
4
+
5
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
6
+
7
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
8
+
9
+ function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
10
+
11
+ function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
12
+
13
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
14
+
15
+ Object.defineProperty(exports, '__esModule', {
16
+ value: true
17
+ });
18
+
3
19
  var lodash = require('lodash');
20
+
4
21
  var types = require('@sanity/types');
22
+
5
23
  var formatDate = require('date-fns/format');
6
24
 
7
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
25
+ function _interopDefaultLegacy(e) {
26
+ return e && typeof e === 'object' && 'default' in e ? e : {
27
+ 'default': e
28
+ };
29
+ }
8
30
 
9
31
  var formatDate__default = /*#__PURE__*/_interopDefaultLegacy(formatDate);
10
32
 
11
- // Follows the same pattern as Rule and RuleClass. @see Rule
12
- const ValidationError = class ValidationError {
13
- message;
14
- paths;
15
- children;
16
- operation;
17
- constructor(message, options = {}) {
18
- this.message = message;
19
- this.paths = options.paths || [];
20
- this.children = options.children;
21
- this.operation = options.operation;
22
- }
23
- cloneWithMessage(msg) {
24
- return new ValidationError(msg, {
25
- paths: this.paths,
26
- children: this.children,
27
- operation: this.operation,
28
- });
29
- }
33
+ const ValidationError = class ValidationError2 {
34
+ constructor(message) {
35
+ let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
36
+ this.message = message;
37
+ this.paths = options.paths || [];
38
+ this.children = options.children;
39
+ this.operation = options.operation;
40
+ }
41
+
42
+ cloneWithMessage(msg) {
43
+ return new ValidationError2(msg, {
44
+ paths: this.paths,
45
+ children: this.children,
46
+ operation: this.operation
47
+ });
48
+ }
49
+
30
50
  };
31
51
 
32
- /* eslint-disable no-useless-escape */
33
- var escapeRegex = (string) => {
34
- // Escape ^$.*+-?=!:|\/()[]{},
35
- return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, '\\$&');
52
+ var escapeRegex = string => {
53
+ return string.replace(/[\^\$\.\*\+\-\?\=\!\:\|\\\/\(\)\[\]\{\}\,]/g, "\\$&");
36
54
  };
37
55
 
38
- function pathToString(path = []) {
39
- return path.reduce((target, segment, i) => {
40
- const segmentType = typeof segment;
41
- if (segmentType === 'number') {
42
- return `${target}[${segment}]`;
43
- }
44
- if (segmentType === 'string') {
45
- const separator = i === 0 ? '' : '.';
46
- return `${target}${separator}${segment}`;
47
- }
48
- if (types.isKeyedObject(segment)) {
49
- return `${target}[_key=="${segment._key}"]`;
50
- }
51
- throw new Error(`Unsupported path segment "${segment}"`);
52
- }, '');
56
+ function pathToString() {
57
+ let path = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
58
+ return path.reduce((target, segment, i) => {
59
+ const segmentType = typeof segment;
60
+
61
+ if (segmentType === "number") {
62
+ return "".concat(target, "[").concat(segment, "]");
63
+ }
64
+
65
+ if (segmentType === "string") {
66
+ const separator = i === 0 ? "" : ".";
67
+ return "".concat(target).concat(separator).concat(segment);
68
+ }
69
+
70
+ if (types.isKeyedObject(segment)) {
71
+ return "".concat(target, "[_key==\"").concat(segment._key, "\"]");
72
+ }
73
+
74
+ throw new Error("Unsupported path segment \"".concat(segment, "\""));
75
+ }, "");
76
+ }
77
+
78
+ function isNonNullable$1(t) {
79
+ return t !== null || t !== void 0;
53
80
  }
54
81
 
55
- function isNonNullable$1(t) {
56
- return t !== null || t !== undefined;
57
- }
58
- function convertToValidationMarker(validatorResult, level, context) {
59
- if (!context) {
60
- throw new Error('missing context');
61
- }
62
- if (validatorResult === true)
63
- return [];
64
- if (Array.isArray(validatorResult)) {
65
- return validatorResult
66
- .flatMap((child) => convertToValidationMarker(child, level, context))
67
- .filter(isNonNullable$1);
68
- }
69
- if (typeof validatorResult === 'string') {
70
- return convertToValidationMarker(new ValidationError(validatorResult), level, context);
71
- }
72
- if (!(validatorResult instanceof ValidationError)) {
73
- // in order to accept the `ValidationErrorLike`, it at least needs to have
74
- // a `message` in the object
75
- if (typeof validatorResult?.message !== 'string') {
76
- throw new Error(`${pathToString(context.path)}: Validator must return 'true' if valid or an error message as a string on errors`);
77
- }
78
- // this is the occurs when an object is returned that wasn't created with the
79
- // `ValidationErrorClass`. in this case, we want to convert it to a class
80
- return convertToValidationMarker(new ValidationError(validatorResult.message, validatorResult), level, context);
81
- }
82
- const results = [];
83
- // the validator result does not include any item-level relative paths,
84
- // then just return the top-level path with the validation result
85
- if (!validatorResult.paths?.length) {
86
- return [
87
- {
88
- level: level || 'error',
89
- item: validatorResult,
90
- path: context.path || [],
91
- },
92
- ];
93
- }
94
- // if the validator result did include item-level relative paths, then for
95
- // each item-level relative path, create a validation marker that concatenates
96
- // the relative path with the path from the validation context
97
- return results.concat(validatorResult.paths.map((path) => ({
98
- path: (context.path || []).concat(path),
99
- level: level || 'error',
100
- item: validatorResult,
101
- })));
82
+ function convertToValidationMarker(validatorResult, level, context) {
83
+ var _a;
84
+
85
+ if (!context) {
86
+ throw new Error("missing context");
87
+ }
88
+
89
+ if (validatorResult === true) return [];
90
+
91
+ if (Array.isArray(validatorResult)) {
92
+ return validatorResult.flatMap(child => convertToValidationMarker(child, level, context)).filter(isNonNullable$1);
93
+ }
94
+
95
+ if (typeof validatorResult === "string") {
96
+ return convertToValidationMarker(new ValidationError(validatorResult), level, context);
97
+ }
98
+
99
+ if (!(validatorResult instanceof ValidationError)) {
100
+ if (typeof (validatorResult == null ? void 0 : validatorResult.message) !== "string") {
101
+ throw new Error("".concat(pathToString(context.path), ": Validator must return 'true' if valid or an error message as a string on errors"));
102
+ }
103
+
104
+ return convertToValidationMarker(new ValidationError(validatorResult.message, validatorResult), level, context);
105
+ }
106
+
107
+ const results = [];
108
+
109
+ if (!((_a = validatorResult.paths) == null ? void 0 : _a.length)) {
110
+ return [{
111
+ level: level || "error",
112
+ item: validatorResult,
113
+ path: context.path || []
114
+ }];
115
+ }
116
+
117
+ return results.concat(validatorResult.paths.map(path => ({
118
+ path: (context.path || []).concat(path),
119
+ level: level || "error",
120
+ item: validatorResult
121
+ })));
122
+ }
123
+
124
+ const _toString = {}.toString;
125
+ const builtIns = [Object, Function, Array, String, Boolean, Number, Date, RegExp, Error];
126
+
127
+ function isBuiltIn(_constructor) {
128
+ for (let i = 0; i < builtIns.length; i++) {
129
+ if (builtIns[i] === _constructor) return true;
130
+ }
131
+
132
+ return false;
102
133
  }
103
134
 
104
- // this file was adapted from a previous dependency `type-of-is`
105
- // https://github.com/stephenhandley/type-of-is/blob/7138a7e79f5af7c286bf8123f60843a91aaebf38/index.js
106
- const _toString = {}.toString;
107
- const builtIns = [Object, Function, Array, String, Boolean, Number, Date, RegExp, Error];
108
- function isBuiltIn(_constructor) {
109
- for (let i = 0; i < builtIns.length; i++) {
110
- if (builtIns[i] === _constructor)
111
- return true;
112
- }
113
- return false;
114
- }
115
- function typeString(obj) {
116
- // [object Blah] -> Blah
117
- const stringType = _toString.call(obj).slice(8, -1);
118
- if (obj === null || obj === undefined)
119
- return stringType.toLowerCase();
120
- // eslint-disable-next-line @typescript-eslint/ban-types
121
- const constructorType = obj.constructor;
122
- if (constructorType && !isBuiltIn(constructorType))
123
- return constructorType.name;
124
- return stringType;
135
+ function typeString(obj) {
136
+ const stringType = _toString.call(obj).slice(8, -1);
137
+
138
+ if (obj === null || obj === void 0) return stringType.toLowerCase();
139
+ const constructorType = obj.constructor;
140
+ if (constructorType && !isBuiltIn(constructorType)) return constructorType.name;
141
+ return stringType;
125
142
  }
126
143
 
127
- /**
128
- * Modified version of fast-deep-equal (https://github.com/epoberezkin/fast-deep-equal)
129
- * MIT-licensed, copyright (c) 2017 Evgeny Poberezkin
130
- **/
131
- // NOTE: when converting to typescript, some of the checks were inlined (vs
132
- // having them in a variable) because the type predicate type narrowing only
133
- // works when type predicate is called inline in the condition that starts the
134
- // control flow branch.
135
- // see here: https://www.typescriptlang.org/docs/handbook/2/narrowing.html
136
- function deepEquals(a, b) {
137
- if (a === b) {
138
- return true;
139
- }
140
- if (Array.isArray(a) && Array.isArray(b)) {
141
- if (a.length != b.length)
142
- return false;
143
- for (let i = 0; i < a.length; i++) {
144
- if (!deepEquals(a[i], b[i])) {
145
- return false;
146
- }
147
- }
148
- return true;
149
- }
150
- if (Array.isArray(a) != Array.isArray(b)) {
151
- return false;
152
- }
153
- if (a && b && typeof a === 'object' && typeof b === 'object') {
154
- const keys = Object.keys(a);
155
- if (keys.length !== Object.keys(b).length) {
156
- return false;
157
- }
158
- if (a instanceof Date && b instanceof Date) {
159
- return a.getTime() === b.getTime();
160
- }
161
- if (a instanceof Date != b instanceof Date) {
162
- return false;
163
- }
164
- if (a instanceof RegExp && b instanceof RegExp) {
165
- return a.toString() == b.toString();
166
- }
167
- if (a instanceof RegExp != b instanceof RegExp) {
168
- return false;
169
- }
170
- for (let i = 0; i < keys.length; i++) {
171
- if (keys[i] === '_key') {
172
- continue;
173
- }
174
- if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
175
- return false;
176
- }
177
- }
178
- for (let i = 0; i < keys.length; i++) {
179
- const key = keys[i];
180
- if (key === '_key') {
181
- continue;
182
- }
183
- if (!deepEquals(a[key], b[key])) {
184
- return false;
185
- }
186
- }
187
- return true;
188
- }
189
- return false;
144
+ function deepEquals(a, b) {
145
+ if (a === b) {
146
+ return true;
147
+ }
148
+
149
+ if (Array.isArray(a) && Array.isArray(b)) {
150
+ if (a.length != b.length) return false;
151
+
152
+ for (let i = 0; i < a.length; i++) {
153
+ if (!deepEquals(a[i], b[i])) {
154
+ return false;
155
+ }
156
+ }
157
+
158
+ return true;
159
+ }
160
+
161
+ if (Array.isArray(a) != Array.isArray(b)) {
162
+ return false;
163
+ }
164
+
165
+ if (a && b && typeof a === "object" && typeof b === "object") {
166
+ const keys = Object.keys(a);
167
+
168
+ if (keys.length !== Object.keys(b).length) {
169
+ return false;
170
+ }
171
+
172
+ if (a instanceof Date && b instanceof Date) {
173
+ return a.getTime() === b.getTime();
174
+ }
175
+
176
+ if (a instanceof Date != b instanceof Date) {
177
+ return false;
178
+ }
179
+
180
+ if (a instanceof RegExp && b instanceof RegExp) {
181
+ return a.toString() == b.toString();
182
+ }
183
+
184
+ if (a instanceof RegExp != b instanceof RegExp) {
185
+ return false;
186
+ }
187
+
188
+ for (let i = 0; i < keys.length; i++) {
189
+ if (keys[i] === "_key") {
190
+ continue;
191
+ }
192
+
193
+ if (!Object.prototype.hasOwnProperty.call(b, keys[i])) {
194
+ return false;
195
+ }
196
+ }
197
+
198
+ for (let i = 0; i < keys.length; i++) {
199
+ const key = keys[i];
200
+
201
+ if (key === "_key") {
202
+ continue;
203
+ }
204
+
205
+ if (!deepEquals(a[key], b[key])) {
206
+ return false;
207
+ }
208
+ }
209
+
210
+ return true;
211
+ }
212
+
213
+ return false;
190
214
  }
191
215
 
192
- const SLOW_VALIDATOR_TIMEOUT = 5000;
193
- const formatValidationErrors = (options) => {
194
- let message;
195
- if (options.message) {
196
- message = options.message;
197
- }
198
- else if (options.results.length === 1) {
199
- message = options.results[0]?.item.message;
200
- }
201
- else {
202
- message = `[${options.results
203
- .map((err) => err.item.message)
204
- .join(` - ${options.operation} - `)}]`;
205
- }
206
- return new ValidationError(message, {
207
- children: options.results.length > 1 ? options.results : undefined,
208
- operation: options.operation,
209
- });
210
- };
211
- const genericValidators = {
212
- type: (expected, value, message) => {
213
- const actualType = typeString(value);
214
- if (actualType !== expected && actualType !== 'undefined') {
215
- return message || `Expected type "${expected}", got "${actualType}"`;
216
- }
217
- return true;
218
- },
219
- presence: (expected, value, message) => {
220
- if (value === undefined && expected === 'required') {
221
- return message || 'Value is required';
222
- }
223
- return true;
224
- },
225
- all: async (children, value, message, context) => {
226
- const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
227
- const results = resolved.flat();
228
- if (!results.length)
229
- return true;
230
- return formatValidationErrors({
231
- message,
232
- results,
233
- operation: 'AND',
234
- });
235
- },
236
- either: async (children, value, message, context) => {
237
- const resolved = await Promise.all(children.map((child) => child.validate(value, context)));
238
- const results = resolved.flat();
239
- // Read: There is at least one rule that matched
240
- if (results.length < children.length)
241
- return true;
242
- return formatValidationErrors({
243
- message,
244
- results,
245
- operation: 'OR',
246
- });
247
- },
248
- valid: (allowedValues, actual, message) => {
249
- const valueType = typeof actual;
250
- if (valueType === 'undefined') {
251
- return true;
252
- }
253
- const value = (valueType === 'number' || valueType === 'string') && `${actual}`;
254
- const strValue = value && value.length > 30 ? `${value.slice(0, 30)}…` : value;
255
- const defaultMessage = value
256
- ? `Value "${strValue}" did not match any allowed values`
257
- : 'Value did not match any allowed values';
258
- return allowedValues.some((expected) => deepEquals(expected, actual))
259
- ? true
260
- : message || defaultMessage;
261
- },
262
- custom: async (fn, value, message, context) => {
263
- const slowTimer = setTimeout(() => {
264
- // eslint-disable-next-line no-console
265
- console.warn(`Custom validator at ${pathToString(context.path)} has taken more than ${SLOW_VALIDATOR_TIMEOUT}ms to respond`);
266
- }, SLOW_VALIDATOR_TIMEOUT);
267
- let result;
268
- try {
269
- result = await fn(value, context);
270
- }
271
- finally {
272
- clearTimeout(slowTimer);
273
- }
274
- if (typeof result === 'string')
275
- return message || result;
276
- return result;
277
- },
216
+ const SLOW_VALIDATOR_TIMEOUT = 5e3;
217
+
218
+ const formatValidationErrors = options => {
219
+ var _a;
220
+
221
+ let message;
222
+
223
+ if (options.message) {
224
+ message = options.message;
225
+ } else if (options.results.length === 1) {
226
+ message = (_a = options.results[0]) == null ? void 0 : _a.item.message;
227
+ } else {
228
+ message = "[".concat(options.results.map(err => err.item.message).join(" - ".concat(options.operation, " - ")), "]");
229
+ }
230
+
231
+ return new ValidationError(message, {
232
+ children: options.results.length > 1 ? options.results : void 0,
233
+ operation: options.operation
234
+ });
278
235
  };
279
236
 
280
- const booleanValidators = {
281
- ...genericValidators,
282
- presence: (flag, value, message) => {
283
- if (flag === 'required' && typeof value !== 'boolean') {
284
- return message || 'Required';
285
- }
286
- return true;
287
- },
237
+ const genericValidators = {
238
+ type: (expected, value, message) => {
239
+ const actualType = typeString(value);
240
+
241
+ if (actualType !== expected && actualType !== "undefined") {
242
+ return message || "Expected type \"".concat(expected, "\", got \"").concat(actualType, "\"");
243
+ }
244
+
245
+ return true;
246
+ },
247
+ presence: (expected, value, message) => {
248
+ if (value === void 0 && expected === "required") {
249
+ return message || "Value is required";
250
+ }
251
+
252
+ return true;
253
+ },
254
+ all: async (children, value, message, context) => {
255
+ const resolved = await Promise.all(children.map(child => child.validate(value, context)));
256
+ const results = resolved.flat();
257
+ if (!results.length) return true;
258
+ return formatValidationErrors({
259
+ message,
260
+ results,
261
+ operation: "AND"
262
+ });
263
+ },
264
+ either: async (children, value, message, context) => {
265
+ const resolved = await Promise.all(children.map(child => child.validate(value, context)));
266
+ const results = resolved.flat();
267
+ if (results.length < children.length) return true;
268
+ return formatValidationErrors({
269
+ message,
270
+ results,
271
+ operation: "OR"
272
+ });
273
+ },
274
+ valid: (allowedValues, actual, message) => {
275
+ const valueType = typeof actual;
276
+
277
+ if (valueType === "undefined") {
278
+ return true;
279
+ }
280
+
281
+ const value = (valueType === "number" || valueType === "string") && "".concat(actual);
282
+ const strValue = value && value.length > 30 ? "".concat(value.slice(0, 30), "\u2026") : value;
283
+ const defaultMessage = value ? "Value \"".concat(strValue, "\" did not match any allowed values") : "Value did not match any allowed values";
284
+ return allowedValues.some(expected => deepEquals(expected, actual)) ? true : message || defaultMessage;
285
+ },
286
+ custom: async (fn, value, message, context) => {
287
+ const slowTimer = setTimeout(() => {
288
+ console.warn("Custom validator at ".concat(pathToString(context.path), " has taken more than ").concat(SLOW_VALIDATOR_TIMEOUT, "ms to respond"));
289
+ }, SLOW_VALIDATOR_TIMEOUT);
290
+ let result;
291
+
292
+ try {
293
+ result = await fn(value, context);
294
+ } finally {
295
+ clearTimeout(slowTimer);
296
+ }
297
+
298
+ if (typeof result === "string") return message || result;
299
+ return result;
300
+ }
288
301
  };
289
302
 
290
- const precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
291
- const numberValidators = {
292
- ...genericValidators,
293
- integer: (_unused, value, message) => {
294
- if (!Number.isInteger(value)) {
295
- return message || 'Must be an integer';
296
- }
297
- return true;
298
- },
299
- precision: (limit, value, message) => {
300
- if (value === undefined)
301
- return true;
302
- const places = value.toString().match(precisionRx);
303
- const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
304
- if (decimals > limit) {
305
- return message || `Max precision is ${limit}`;
306
- }
307
- return true;
308
- },
309
- min: (minNum, value, message) => {
310
- if (value >= minNum) {
311
- return true;
312
- }
313
- return message || `Must be greater than or equal ${minNum}`;
314
- },
315
- max: (maxNum, value, message) => {
316
- if (value <= maxNum) {
317
- return true;
318
- }
319
- return message || `Must be less than or equal ${maxNum}`;
320
- },
321
- greaterThan: (num, value, message) => {
322
- if (value > num) {
323
- return true;
324
- }
325
- return message || `Must be greater than ${num}`;
326
- },
327
- lessThan: (maxNum, value, message) => {
328
- if (value < maxNum) {
329
- return true;
330
- }
331
- return message || `Must be less than ${maxNum}`;
332
- },
303
+ const booleanValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
304
+ presence: (flag, value, message) => {
305
+ if (flag === "required" && typeof value !== "boolean") {
306
+ return message || "Required";
307
+ }
308
+
309
+ return true;
310
+ }
311
+ });
312
+
313
+ const precisionRx = /(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/;
314
+
315
+ const numberValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
316
+ integer: (_unused, value, message) => {
317
+ if (!Number.isInteger(value)) {
318
+ return message || "Must be an integer";
319
+ }
320
+
321
+ return true;
322
+ },
323
+ precision: (limit, value, message) => {
324
+ if (value === void 0) return true;
325
+ const places = value.toString().match(precisionRx);
326
+ const decimals = Math.max((places[1] ? places[1].length : 0) - (places[2] ? parseInt(places[2], 10) : 0), 0);
327
+
328
+ if (decimals > limit) {
329
+ return message || "Max precision is ".concat(limit);
330
+ }
331
+
332
+ return true;
333
+ },
334
+ min: (minNum, value, message) => {
335
+ if (value >= minNum) {
336
+ return true;
337
+ }
338
+
339
+ return message || "Must be greater than or equal ".concat(minNum);
340
+ },
341
+ max: (maxNum, value, message) => {
342
+ if (value <= maxNum) {
343
+ return true;
344
+ }
345
+
346
+ return message || "Must be less than or equal ".concat(maxNum);
347
+ },
348
+ greaterThan: (num, value, message) => {
349
+ if (value > num) {
350
+ return true;
351
+ }
352
+
353
+ return message || "Must be greater than ".concat(num);
354
+ },
355
+ lessThan: (maxNum, value, message) => {
356
+ if (value < maxNum) {
357
+ return true;
358
+ }
359
+
360
+ return message || "Must be less than ".concat(maxNum);
361
+ }
362
+ });
363
+
364
+ const DUMMY_ORIGIN = "http://sanity";
365
+ const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
366
+
367
+ const isRelativeUrl = url => /^\.*\//.test(url);
368
+
369
+ const stringValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
370
+ min: (minLength, value, message) => {
371
+ if (!value || value.length >= minLength) {
372
+ return true;
373
+ }
374
+
375
+ return message || "Must be at least ".concat(minLength, " characters long");
376
+ },
377
+ max: (maxLength, value, message) => {
378
+ if (!value || value.length <= maxLength) {
379
+ return true;
380
+ }
381
+
382
+ return message || "Must be at most ".concat(maxLength, " characters long");
383
+ },
384
+ length: (wantedLength, value, message) => {
385
+ const strValue = value || "";
386
+
387
+ if (strValue.length === wantedLength) {
388
+ return true;
389
+ }
390
+
391
+ return message || "Must be exactly ".concat(wantedLength, " characters long");
392
+ },
393
+ uri: (constraints, value, message) => {
394
+ const strValue = value || "";
395
+ const {
396
+ options
397
+ } = constraints;
398
+ const {
399
+ allowCredentials,
400
+ relativeOnly
401
+ } = options;
402
+ const allowRelative = options.allowRelative || relativeOnly;
403
+ let url;
404
+
405
+ try {
406
+ url = allowRelative ? new URL(strValue, DUMMY_ORIGIN) : new URL(strValue);
407
+ } catch (err) {
408
+ return message || "Not a valid URL";
409
+ }
410
+
411
+ if (relativeOnly && url.origin !== DUMMY_ORIGIN) {
412
+ return message || "Only relative URLs are allowed";
413
+ }
414
+
415
+ if (!allowRelative && url.origin === DUMMY_ORIGIN && isRelativeUrl(strValue)) {
416
+ return message || "Relative URLs are not allowed";
417
+ }
418
+
419
+ if (!allowCredentials && (url.username || url.password)) {
420
+ return message || "Username/password not allowed";
421
+ }
422
+
423
+ const urlScheme = url.protocol.replace(/:$/, "");
424
+ const matchesAllowedScheme = options.scheme.some(scheme => scheme.test(urlScheme));
425
+
426
+ if (!matchesAllowedScheme) {
427
+ return message || "Does not match allowed protocols/schemes";
428
+ }
429
+
430
+ return true;
431
+ },
432
+ stringCasing: (casing, value, message) => {
433
+ const strValue = value || "";
434
+
435
+ if (casing === "uppercase" && strValue !== strValue.toLocaleUpperCase()) {
436
+ return message || "Must be all uppercase letters";
437
+ }
438
+
439
+ if (casing === "lowercase" && strValue !== strValue.toLocaleLowerCase()) {
440
+ return message || "Must be all lowercase letters";
441
+ }
442
+
443
+ return true;
444
+ },
445
+ presence: (flag, value, message) => {
446
+ if (flag === "required" && !value) {
447
+ return message || "Required";
448
+ }
449
+
450
+ return true;
451
+ },
452
+ regex: (options, value, message) => {
453
+ const {
454
+ pattern,
455
+ name,
456
+ invert
457
+ } = options;
458
+ const regName = name || "\"".concat(pattern.toString(), "\"");
459
+ const strValue = value || "";
460
+ const matches = pattern.test(strValue);
461
+
462
+ if (!invert && !matches || invert && matches) {
463
+ const defaultMessage = invert ? "Should not match ".concat(regName, "-pattern") : "Does not match ".concat(regName, "-pattern");
464
+ return message || defaultMessage;
465
+ }
466
+
467
+ return true;
468
+ },
469
+ email: (_unused, value, message) => {
470
+ const strValue = "".concat(value || "").trim();
471
+
472
+ if (!strValue || emailRegex.test(strValue)) {
473
+ return true;
474
+ }
475
+
476
+ return message || "Must be a valid email address";
477
+ }
478
+ });
479
+
480
+ const arrayValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
481
+ min: (minLength, value, message) => {
482
+ if (!value || value.length >= minLength) {
483
+ return true;
484
+ }
485
+
486
+ return message || "Must have at least ".concat(minLength, " items");
487
+ },
488
+ max: (maxLength, value, message) => {
489
+ if (!value || value.length <= maxLength) {
490
+ return true;
491
+ }
492
+
493
+ return message || "Must have at most ".concat(maxLength, " items");
494
+ },
495
+ length: (wantedLength, value, message) => {
496
+ if (!value || value.length === wantedLength) {
497
+ return true;
498
+ }
499
+
500
+ return message || "Must have exactly ".concat(wantedLength, " items");
501
+ },
502
+ presence: (flag, value, message) => {
503
+ if (flag === "required" && !value) {
504
+ return message || "Required";
505
+ }
506
+
507
+ return true;
508
+ },
509
+ valid: (allowedValues, values, message) => {
510
+ const valueType = typeof values;
511
+
512
+ if (valueType === "undefined") {
513
+ return true;
514
+ }
515
+
516
+ const paths = [];
517
+
518
+ for (let i = 0; i < values.length; i++) {
519
+ const value = values[i];
520
+
521
+ if (allowedValues.some(expected => deepEquals(expected, value))) {
522
+ continue;
523
+ }
524
+
525
+ const pathSegment = value && value._key ? {
526
+ _key: value._key
527
+ } : i;
528
+ paths.push([pathSegment]);
529
+ }
530
+
531
+ return paths.length === 0 ? true : new ValidationError(message || "Value did not match any allowed values", {
532
+ paths
533
+ });
534
+ },
535
+ unique: (_unused, value, message) => {
536
+ const dupeIndices = [];
537
+
538
+ if (!value) {
539
+ return true;
540
+ }
541
+
542
+ for (let x = 0; x < value.length; x++) {
543
+ for (let y = x + 1; y < value.length; y++) {
544
+ const itemA = value[x];
545
+ const itemB = value[y];
546
+
547
+ if (!deepEquals(itemA, itemB)) {
548
+ continue;
549
+ }
550
+
551
+ if (dupeIndices.indexOf(x) === -1) {
552
+ dupeIndices.push(x);
553
+ }
554
+
555
+ if (dupeIndices.indexOf(y) === -1) {
556
+ dupeIndices.push(y);
557
+ }
558
+ }
559
+ }
560
+
561
+ const paths = dupeIndices.map(idx => {
562
+ const item = value[idx];
563
+ const pathSegment = item && item._key ? {
564
+ _key: item._key
565
+ } : idx;
566
+ return [pathSegment];
567
+ });
568
+ return dupeIndices.length > 0 ? new ValidationError(message || "Can't be a duplicate", {
569
+ paths
570
+ }) : true;
571
+ }
572
+ });
573
+
574
+ const metaKeys = ["_key", "_type", "_weak"];
575
+
576
+ const objectValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
577
+ presence: (expected, value, message) => {
578
+ if (expected !== "required") {
579
+ return true;
580
+ }
581
+
582
+ const keys = value && Object.keys(value).filter(key => !metaKeys.includes(key));
583
+
584
+ if (value === void 0 || keys && keys.length === 0) {
585
+ return message || "Required";
586
+ }
587
+
588
+ return true;
589
+ },
590
+ reference: async (_unused, value, message, context) => {
591
+ if (!value) {
592
+ return true;
593
+ }
594
+
595
+ if (!types.isReference(value)) {
596
+ return message || true;
597
+ }
598
+
599
+ const {
600
+ type,
601
+ getDocumentExists
602
+ } = context;
603
+
604
+ if (!type) {
605
+ throw new Error("`type` was not provided in validation context");
606
+ }
607
+
608
+ if ("weak" in type && type.weak) {
609
+ return true;
610
+ }
611
+
612
+ if (!getDocumentExists) {
613
+ throw new Error("`getDocumentExists` was not provided in validation context");
614
+ }
615
+
616
+ const exists = await getDocumentExists({
617
+ id: value._ref
618
+ });
619
+
620
+ if (!exists) {
621
+ return "This reference must be published";
622
+ }
623
+
624
+ return true;
625
+ },
626
+ assetRequired: (flag, value, message) => {
627
+ if (!value || !value.asset || !value.asset._ref) {
628
+ const assetType = flag.assetType || "Asset";
629
+ return message || "".concat(assetType, " required");
630
+ }
631
+
632
+ return true;
633
+ }
634
+ });
635
+
636
+ function isRecord$1(obj) {
637
+ return typeof obj === "object" && obj !== null && !Array.isArray(obj);
638
+ }
639
+
640
+ const isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
641
+
642
+ const getFormattedDate = function () {
643
+ let type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : "";
644
+ let value = arguments.length > 1 ? arguments[1] : undefined;
645
+ let options = arguments.length > 2 ? arguments[2] : undefined;
646
+ let format = "yyyy-MM-dd";
647
+
648
+ if (options && options.dateFormat) {
649
+ format = options.dateFormat;
650
+ }
651
+
652
+ if (type === "date") {
653
+ return formatDate__default["default"](new Date(value), format);
654
+ }
655
+
656
+ if (options && options.timeFormat) {
657
+ format += " ".concat(options.timeFormat);
658
+ } else {
659
+ format += " HH:mm";
660
+ }
661
+
662
+ return formatDate__default["default"](new Date(value), format);
333
663
  };
334
664
 
335
- const DUMMY_ORIGIN = 'http://sanity';
336
- const emailRegex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
337
- const isRelativeUrl = (url) => /^\.*\//.test(url);
338
- const stringValidators = {
339
- ...genericValidators,
340
- min: (minLength, value, message) => {
341
- if (!value || value.length >= minLength) {
342
- return true;
343
- }
344
- return message || `Must be at least ${minLength} characters long`;
345
- },
346
- max: (maxLength, value, message) => {
347
- if (!value || value.length <= maxLength) {
348
- return true;
349
- }
350
- return message || `Must be at most ${maxLength} characters long`;
351
- },
352
- length: (wantedLength, value, message) => {
353
- const strValue = value || '';
354
- if (strValue.length === wantedLength) {
355
- return true;
356
- }
357
- return message || `Must be exactly ${wantedLength} characters long`;
358
- },
359
- uri: (constraints, value, message) => {
360
- const strValue = value || '';
361
- const { options } = constraints;
362
- const { allowCredentials, relativeOnly } = options;
363
- const allowRelative = options.allowRelative || relativeOnly;
364
- let url;
365
- try {
366
- // WARNING: Safari checks for a given `base` param by looking at the length of arguments passed
367
- // to new URL(str, base), and will fail if invoked with new URL(strValue, undefined)
368
- url = allowRelative ? new URL(strValue, DUMMY_ORIGIN) : new URL(strValue);
369
- }
370
- catch (err) {
371
- return message || 'Not a valid URL';
372
- }
373
- if (relativeOnly && url.origin !== DUMMY_ORIGIN) {
374
- return message || 'Only relative URLs are allowed';
375
- }
376
- if (!allowRelative && url.origin === DUMMY_ORIGIN && isRelativeUrl(strValue)) {
377
- return message || 'Relative URLs are not allowed';
378
- }
379
- if (!allowCredentials && (url.username || url.password)) {
380
- return message || `Username/password not allowed`;
381
- }
382
- const urlScheme = url.protocol.replace(/:$/, '');
383
- const matchesAllowedScheme = options.scheme.some((scheme) => scheme.test(urlScheme));
384
- if (!matchesAllowedScheme) {
385
- return message || 'Does not match allowed protocols/schemes';
386
- }
387
- return true;
388
- },
389
- stringCasing: (casing, value, message) => {
390
- const strValue = value || '';
391
- if (casing === 'uppercase' && strValue !== strValue.toLocaleUpperCase()) {
392
- return message || `Must be all uppercase letters`;
393
- }
394
- if (casing === 'lowercase' && strValue !== strValue.toLocaleLowerCase()) {
395
- return message || `Must be all lowercase letters`;
396
- }
397
- return true;
398
- },
399
- presence: (flag, value, message) => {
400
- if (flag === 'required' && !value) {
401
- return message || 'Required';
402
- }
403
- return true;
404
- },
405
- regex: (options, value, message) => {
406
- const { pattern, name, invert } = options;
407
- const regName = name || `"${pattern.toString()}"`;
408
- const strValue = value || '';
409
- const matches = pattern.test(strValue);
410
- if ((!invert && !matches) || (invert && matches)) {
411
- const defaultMessage = invert
412
- ? `Should not match ${regName}-pattern`
413
- : `Does not match ${regName}-pattern`;
414
- return message || defaultMessage;
415
- }
416
- return true;
417
- },
418
- email: (_unused, value, message) => {
419
- const strValue = `${value || ''}`.trim();
420
- if (!strValue || emailRegex.test(strValue)) {
421
- return true;
422
- }
423
- return message || 'Must be a valid email address';
424
- },
665
+ function parseDate(date) {
666
+ let throwOnError = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
667
+ if (!date) return null;
668
+ if (date === "now") return new Date();
669
+ const parsed = new Date(date);
670
+ const isInvalid = isNaN(parsed.getTime());
671
+
672
+ if (isInvalid && throwOnError) {
673
+ throw new Error("Unable to parse \"".concat(date, "\" to a date"));
674
+ }
675
+
676
+ return isInvalid ? null : parsed;
677
+ }
678
+
679
+ const dateValidators = _objectSpread(_objectSpread({}, genericValidators), {}, {
680
+ type: (_unused, value, message) => {
681
+ const strVal = "".concat(value);
682
+
683
+ if (!strVal || isoDate.test(value)) {
684
+ return true;
685
+ }
686
+
687
+ return message || "Must be a valid ISO-8601 formatted date string";
688
+ },
689
+ min: (minDate, value, message, context) => {
690
+ const dateVal = parseDate(value);
691
+
692
+ if (!dateVal) {
693
+ return true;
694
+ }
695
+
696
+ if (!value || dateVal >= parseDate(minDate, true)) {
697
+ return true;
698
+ }
699
+
700
+ if (!context.type) {
701
+ throw new Error("`type` was not provided in validation context.");
702
+ }
703
+
704
+ const dateTimeOptions = isRecord$1(context.type.options) ? context.type.options : {};
705
+ const date = getFormattedDate(context.type.name, minDate, dateTimeOptions);
706
+ return message || "Must be at or after ".concat(date);
707
+ },
708
+ max: (maxDate, value, message, context) => {
709
+ const dateVal = parseDate(value);
710
+
711
+ if (!dateVal) {
712
+ return true;
713
+ }
714
+
715
+ if (!value || dateVal <= parseDate(maxDate, true)) {
716
+ return true;
717
+ }
718
+
719
+ if (!context.type) {
720
+ throw new Error("`type` was not provided in validation context.");
721
+ }
722
+
723
+ const dateTimeOptions = isRecord$1(context.type.options) ? context.type.options : {};
724
+ const date = getFormattedDate(context.type.name, maxDate, dateTimeOptions);
725
+ return message || "Must be at or before ".concat(date);
726
+ }
727
+ });
728
+
729
+ var _a;
730
+
731
+ const typeValidators = {
732
+ Boolean: booleanValidators,
733
+ Number: numberValidators,
734
+ String: stringValidators,
735
+ Array: arrayValidators,
736
+ Object: objectValidators,
737
+ Date: dateValidators
425
738
  };
426
739
 
427
- const arrayValidators = {
428
- ...genericValidators,
429
- min: (minLength, value, message) => {
430
- if (!value || value.length >= minLength) {
431
- return true;
432
- }
433
- return message || `Must have at least ${minLength} items`;
434
- },
435
- max: (maxLength, value, message) => {
436
- if (!value || value.length <= maxLength) {
437
- return true;
438
- }
439
- return message || `Must have at most ${maxLength} items`;
440
- },
441
- length: (wantedLength, value, message) => {
442
- if (!value || value.length === wantedLength) {
443
- return true;
444
- }
445
- return message || `Must have exactly ${wantedLength} items`;
446
- },
447
- presence: (flag, value, message) => {
448
- if (flag === 'required' && !value) {
449
- return message || 'Required';
450
- }
451
- return true;
452
- },
453
- valid: (allowedValues, values, message) => {
454
- const valueType = typeof values;
455
- if (valueType === 'undefined') {
456
- return true;
457
- }
458
- const paths = [];
459
- for (let i = 0; i < values.length; i++) {
460
- const value = values[i];
461
- if (allowedValues.some((expected) => deepEquals(expected, value))) {
462
- continue;
463
- }
464
- const pathSegment = value && value._key ? { _key: value._key } : i;
465
- paths.push([pathSegment]);
466
- }
467
- return paths.length === 0
468
- ? true
469
- : new ValidationError(message || 'Value did not match any allowed values', { paths });
470
- },
471
- unique: (_unused, value, message) => {
472
- const dupeIndices = [];
473
- if (!value) {
474
- return true;
475
- }
476
- for (let x = 0; x < value.length; x++) {
477
- for (let y = x + 1; y < value.length; y++) {
478
- const itemA = value[x];
479
- const itemB = value[y];
480
- if (!deepEquals(itemA, itemB)) {
481
- continue;
482
- }
483
- if (dupeIndices.indexOf(x) === -1) {
484
- dupeIndices.push(x);
485
- }
486
- if (dupeIndices.indexOf(y) === -1) {
487
- dupeIndices.push(y);
488
- }
489
- }
490
- }
491
- const paths = dupeIndices.map((idx) => {
492
- const item = value[idx];
493
- const pathSegment = item && item._key ? { _key: item._key } : idx;
494
- return [pathSegment];
495
- });
496
- return dupeIndices.length > 0
497
- ? new ValidationError(message || `Can't be a duplicate`, { paths })
498
- : true;
499
- },
740
+ const getBaseType = type => {
741
+ return type && type.type ? getBaseType(type.type) : type;
500
742
  };
501
743
 
502
- const metaKeys = ['_key', '_type', '_weak'];
503
- const objectValidators = {
504
- ...genericValidators,
505
- presence: (expected, value, message) => {
506
- if (expected !== 'required') {
507
- return true;
508
- }
509
- const keys = value && Object.keys(value).filter((key) => !metaKeys.includes(key));
510
- if (value === undefined || (keys && keys.length === 0)) {
511
- return message || 'Required';
512
- }
513
- return true;
514
- },
515
- reference: async (_unused, value, message, context) => {
516
- if (!value) {
517
- return true;
518
- }
519
- if (!types.isReference(value)) {
520
- return message || true;
521
- }
522
- const { type, getDocumentExists } = context;
523
- if (!type) {
524
- throw new Error(`\`type\` was not provided in validation context`);
525
- }
526
- if ('weak' in type && type.weak) {
527
- return true;
528
- }
529
- if (!getDocumentExists) {
530
- throw new Error(`\`getDocumentExists\` was not provided in validation context`);
531
- }
532
- const exists = await getDocumentExists({ id: value._ref });
533
- if (!exists) {
534
- return 'This reference must be published';
535
- }
536
- return true;
537
- },
538
- assetRequired: (flag, value, message) => {
539
- if (!value || !value.asset || !value.asset._ref) {
540
- const assetType = flag.assetType || 'Asset';
541
- return message || `${assetType} required`;
542
- }
543
- return true;
544
- },
744
+ const isFieldRef = constraint => {
745
+ if (typeof constraint !== "object" || !constraint) return false;
746
+ return constraint.type === Rule.FIELD_REF;
545
747
  };
546
748
 
547
- function isRecord$1(obj) {
548
- return typeof obj === 'object' && obj !== null && !Array.isArray(obj);
549
- }
550
- const isoDate = /^(?:[-+]\d{2})?(?:\d{4}(?!\d{2}\b))(?:(-?)(?:(?:0[1-9]|1[0-2])(?:\1(?:[12]\d|0[1-9]|3[01]))?|W(?:[0-4]\d|5[0-2])(?:-?[1-7])?|(?:00[1-9]|0[1-9]\d|[12]\d{2}|3(?:[0-5]\d|6[1-6])))(?![T]$|[T][\d]+Z$)(?:[T\s](?:(?:(?:[01]\d|2[0-3])(?:(:?)[0-5]\d)?|24:?00)(?:[.,]\d+(?!:))?)(?:\2[0-5]\d(?:[.,]\d+)?)?(?:[Z]|(?:[+-])(?:[01]\d|2[0-3])(?::?[0-5]\d)?)?)?)?$/;
551
- const getFormattedDate = (type = '', value, options) => {
552
- let format = 'yyyy-MM-dd';
553
- if (options && options.dateFormat) {
554
- format = options.dateFormat;
555
- }
556
- if (type === 'date') {
557
- // If the type is date only
558
- return formatDate__default["default"](new Date(value), format);
559
- }
560
- // If the type is datetime
561
- if (options && options.timeFormat) {
562
- format += ` ${options.timeFormat}`;
563
- }
564
- else {
565
- format += ' HH:mm';
566
- }
567
- return formatDate__default["default"](new Date(value), format);
568
- };
569
- function parseDate(date, throwOnError = false) {
570
- if (!date)
571
- return null;
572
- if (date === 'now')
573
- return new Date();
574
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
575
- const parsed = new Date(date);
576
- const isInvalid = isNaN(parsed.getTime());
577
- if (isInvalid && throwOnError) {
578
- throw new Error(`Unable to parse "${date}" to a date`);
579
- }
580
- return isInvalid ? null : parsed;
581
- }
582
- const dateValidators = {
583
- ...genericValidators,
584
- type: (_unused, value, message) => {
585
- const strVal = `${value}`;
586
- if (!strVal || isoDate.test(value)) {
587
- return true;
588
- }
589
- return message || 'Must be a valid ISO-8601 formatted date string';
590
- },
591
- min: (minDate, value, message, context) => {
592
- const dateVal = parseDate(value);
593
- if (!dateVal) {
594
- return true; // `type()` should catch parse errors
595
- }
596
- if (!value || dateVal >= parseDate(minDate, true)) {
597
- return true;
598
- }
599
- if (!context.type) {
600
- throw new Error(`\`type\` was not provided in validation context.`);
601
- }
602
- const dateTimeOptions = isRecord$1(context.type.options)
603
- ? context.type.options
604
- : {};
605
- const date = getFormattedDate(context.type.name, minDate, dateTimeOptions);
606
- return message || `Must be at or after ${date}`;
607
- },
608
- max: (maxDate, value, message, context) => {
609
- const dateVal = parseDate(value);
610
- if (!dateVal) {
611
- return true; // `type()` should catch parse errors
612
- }
613
- if (!value || dateVal <= parseDate(maxDate, true)) {
614
- return true;
615
- }
616
- if (!context.type) {
617
- throw new Error(`\`type\` was not provided in validation context.`);
618
- }
619
- const dateTimeOptions = isRecord$1(context.type.options)
620
- ? context.type.options
621
- : {};
622
- const date = getFormattedDate(context.type.name, maxDate, dateTimeOptions);
623
- return message || `Must be at or before ${date}`;
624
- },
749
+ const EMPTY_ARRAY = [];
750
+ const FIELD_REF = Symbol("FIELD_REF");
751
+ const ruleConstraintTypes$1 = ["Array", "Boolean", "Date", "Number", "Object", "String"];
752
+ const Rule = (_a = class {
753
+ constructor(typeDef) {
754
+ this._type = void 0;
755
+ this._level = void 0;
756
+ this._required = void 0;
757
+ this._typeDef = void 0;
758
+ this._message = void 0;
759
+ this._rules = [];
760
+ this._fieldRules = void 0;
761
+ this.valueOfField = _a.valueOfField.bind(_a);
762
+ this._typeDef = typeDef;
763
+ this.reset();
764
+ }
765
+
766
+ _mergeRequired(next) {
767
+ if (this._required === "required" || next._required === "required") return "required";
768
+ if (this._required === "optional" || next._required === "optional") return "optional";
769
+ return void 0;
770
+ }
771
+
772
+ error(message) {
773
+ const rule = this.clone();
774
+ rule._level = "error";
775
+ rule._message = message || void 0;
776
+ return rule;
777
+ }
778
+
779
+ warning(message) {
780
+ const rule = this.clone();
781
+ rule._level = "warning";
782
+ rule._message = message || void 0;
783
+ return rule;
784
+ }
785
+
786
+ info(message) {
787
+ const rule = this.clone();
788
+ rule._level = "info";
789
+ rule._message = message || void 0;
790
+ return rule;
791
+ }
792
+
793
+ reset() {
794
+ this._type = this._type || void 0;
795
+ this._rules = (this._rules || []).filter(rule => rule.flag === "type");
796
+ this._message = void 0;
797
+ this._required = void 0;
798
+ this._level = "error";
799
+ this._fieldRules = void 0;
800
+ return this;
801
+ }
802
+
803
+ isRequired() {
804
+ return this._required === "required";
805
+ }
806
+
807
+ clone() {
808
+ const rule = new _a();
809
+ rule._type = this._type;
810
+ rule._message = this._message;
811
+ rule._required = this._required;
812
+ rule._rules = lodash.cloneDeep(this._rules);
813
+ rule._level = this._level;
814
+ rule._fieldRules = this._fieldRules;
815
+ rule._typeDef = this._typeDef;
816
+ return rule;
817
+ }
818
+
819
+ cloneWithRules(rules) {
820
+ const rule = this.clone();
821
+ const newRules = /* @__PURE__ */new Set();
822
+ rules.forEach(curr => {
823
+ if (curr.flag === "type") {
824
+ rule._type = curr.constraint;
825
+ }
826
+
827
+ newRules.add(curr.flag);
828
+ });
829
+ rule._rules = rule._rules.filter(curr => {
830
+ const disallowDuplicate = ["type", "uri", "email"].includes(curr.flag);
831
+ const isDuplicate = newRules.has(curr.flag);
832
+ return !(disallowDuplicate && isDuplicate);
833
+ }).concat(rules);
834
+ return rule;
835
+ }
836
+
837
+ merge(rule) {
838
+ if (this._type && rule._type && this._type !== rule._type) {
839
+ throw new Error("merge() failed: conflicting types");
840
+ }
841
+
842
+ const newRule = this.cloneWithRules(rule._rules);
843
+ newRule._type = this._type || rule._type;
844
+ newRule._message = this._message || rule._message;
845
+ newRule._required = this._mergeRequired(rule);
846
+ newRule._level = this._level === "error" ? rule._level : this._level;
847
+ return newRule;
848
+ }
849
+
850
+ type(targetType) {
851
+ const type = "".concat(targetType.slice(0, 1).toUpperCase()).concat(targetType.slice(1));
852
+
853
+ if (!ruleConstraintTypes$1.includes(type)) {
854
+ throw new Error("Unknown type \"".concat(targetType, "\""));
855
+ }
856
+
857
+ const rule = this.cloneWithRules([{
858
+ flag: "type",
859
+ constraint: type
860
+ }]);
861
+ rule._type = type;
862
+ return rule;
863
+ }
864
+
865
+ all(children) {
866
+ return this.cloneWithRules([{
867
+ flag: "all",
868
+ constraint: children
869
+ }]);
870
+ }
871
+
872
+ either(children) {
873
+ return this.cloneWithRules([{
874
+ flag: "either",
875
+ constraint: children
876
+ }]);
877
+ }
878
+
879
+ optional() {
880
+ const rule = this.cloneWithRules([{
881
+ flag: "presence",
882
+ constraint: "optional"
883
+ }]);
884
+ rule._required = "optional";
885
+ return rule;
886
+ }
887
+
888
+ required() {
889
+ const rule = this.cloneWithRules([{
890
+ flag: "presence",
891
+ constraint: "required"
892
+ }]);
893
+ rule._required = "required";
894
+ return rule;
895
+ }
896
+
897
+ custom(fn) {
898
+ return this.cloneWithRules([{
899
+ flag: "custom",
900
+ constraint: fn
901
+ }]);
902
+ }
903
+
904
+ block(fn) {
905
+ return this.cloneWithRules([{
906
+ flag: "custom",
907
+ constraint: fn
908
+ }]);
909
+ }
910
+
911
+ min(len) {
912
+ return this.cloneWithRules([{
913
+ flag: "min",
914
+ constraint: len
915
+ }]);
916
+ }
917
+
918
+ max(len) {
919
+ return this.cloneWithRules([{
920
+ flag: "max",
921
+ constraint: len
922
+ }]);
923
+ }
924
+
925
+ length(len) {
926
+ return this.cloneWithRules([{
927
+ flag: "length",
928
+ constraint: len
929
+ }]);
930
+ }
931
+
932
+ valid(value) {
933
+ const values = Array.isArray(value) ? value : [value];
934
+ return this.cloneWithRules([{
935
+ flag: "valid",
936
+ constraint: values
937
+ }]);
938
+ }
939
+
940
+ integer() {
941
+ return this.cloneWithRules([{
942
+ flag: "integer"
943
+ }]);
944
+ }
945
+
946
+ precision(limit) {
947
+ return this.cloneWithRules([{
948
+ flag: "precision",
949
+ constraint: limit
950
+ }]);
951
+ }
952
+
953
+ positive() {
954
+ return this.cloneWithRules([{
955
+ flag: "min",
956
+ constraint: 0
957
+ }]);
958
+ }
959
+
960
+ negative() {
961
+ return this.cloneWithRules([{
962
+ flag: "lessThan",
963
+ constraint: 0
964
+ }]);
965
+ }
966
+
967
+ greaterThan(num) {
968
+ return this.cloneWithRules([{
969
+ flag: "greaterThan",
970
+ constraint: num
971
+ }]);
972
+ }
973
+
974
+ lessThan(num) {
975
+ return this.cloneWithRules([{
976
+ flag: "lessThan",
977
+ constraint: num
978
+ }]);
979
+ }
980
+
981
+ uppercase() {
982
+ return this.cloneWithRules([{
983
+ flag: "stringCasing",
984
+ constraint: "uppercase"
985
+ }]);
986
+ }
987
+
988
+ lowercase() {
989
+ return this.cloneWithRules([{
990
+ flag: "stringCasing",
991
+ constraint: "lowercase"
992
+ }]);
993
+ }
994
+
995
+ regex(pattern, a, b) {
996
+ var _a2, _b;
997
+
998
+ const name = typeof a === "string" ? a : (_a2 = a == null ? void 0 : a.name) != null ? _a2 : b == null ? void 0 : b.name;
999
+ const invert = typeof a === "string" ? false : (_b = a == null ? void 0 : a.invert) != null ? _b : b == null ? void 0 : b.invert;
1000
+ const constraint = {
1001
+ pattern,
1002
+ name,
1003
+ invert: invert || false
1004
+ };
1005
+ return this.cloneWithRules([{
1006
+ flag: "regex",
1007
+ constraint
1008
+ }]);
1009
+ }
1010
+
1011
+ email() {
1012
+ return this.cloneWithRules([{
1013
+ flag: "email"
1014
+ }]);
1015
+ }
1016
+
1017
+ uri(opts) {
1018
+ const optsScheme = (opts == null ? void 0 : opts.scheme) || ["http", "https"];
1019
+ const schemes = Array.isArray(optsScheme) ? optsScheme : [optsScheme];
1020
+
1021
+ if (!schemes.length) {
1022
+ throw new Error("scheme must have at least 1 scheme specified");
1023
+ }
1024
+
1025
+ const constraint = {
1026
+ options: {
1027
+ scheme: schemes.map(scheme => {
1028
+ if (!(scheme instanceof RegExp) && typeof scheme !== "string") {
1029
+ throw new Error("scheme must be a RegExp or a String");
1030
+ }
1031
+
1032
+ return typeof scheme === "string" ? new RegExp("^".concat(escapeRegex(scheme), "$")) : scheme;
1033
+ }),
1034
+ allowRelative: (opts == null ? void 0 : opts.allowRelative) || false,
1035
+ relativeOnly: (opts == null ? void 0 : opts.relativeOnly) || false,
1036
+ allowCredentials: (opts == null ? void 0 : opts.allowCredentials) || false
1037
+ }
1038
+ };
1039
+ return this.cloneWithRules([{
1040
+ flag: "uri",
1041
+ constraint
1042
+ }]);
1043
+ }
1044
+
1045
+ unique() {
1046
+ return this.cloneWithRules([{
1047
+ flag: "unique"
1048
+ }]);
1049
+ }
1050
+
1051
+ reference() {
1052
+ return this.cloneWithRules([{
1053
+ flag: "reference"
1054
+ }]);
1055
+ }
1056
+
1057
+ fields(rules) {
1058
+ if (this._type !== "Object") {
1059
+ throw new Error("fields() can only be called on an object type");
1060
+ }
1061
+
1062
+ const rule = this.cloneWithRules([]);
1063
+ rule._fieldRules = rules;
1064
+ return rule;
1065
+ }
1066
+
1067
+ assetRequired() {
1068
+ const base = getBaseType(this._typeDef);
1069
+ let assetType;
1070
+
1071
+ if (base && ["image", "file"].includes(base.name)) {
1072
+ assetType = base.name === "image" ? "Image" : "File";
1073
+ } else {
1074
+ assetType = "Asset";
1075
+ }
1076
+
1077
+ return this.cloneWithRules([{
1078
+ flag: "assetRequired",
1079
+ constraint: {
1080
+ assetType
1081
+ }
1082
+ }]);
1083
+ }
1084
+
1085
+ async validate(value, context) {
1086
+ if (!context) {
1087
+ throw new Error("missing context");
1088
+ }
1089
+
1090
+ const valueIsEmpty = value === null || value === void 0;
1091
+
1092
+ if (valueIsEmpty && this._required === "optional") {
1093
+ return EMPTY_ARRAY;
1094
+ }
1095
+
1096
+ const rules = this._required === void 0 && valueIsEmpty ? this._rules.filter(curr => curr.flag === "custom") : this._rules;
1097
+ const validators = this._type && typeValidators[this._type] || genericValidators;
1098
+ const results = await Promise.all(rules.map(async curr => {
1099
+ if (curr.flag === void 0) {
1100
+ throw new Error('Invalid rule, did not contain "flag"-property');
1101
+ }
1102
+
1103
+ const validator = validators[curr.flag];
1104
+
1105
+ if (!validator) {
1106
+ const forType = this._type ? "type \"".concat(this._type, "\"") : "rule without declared type";
1107
+ throw new Error("Validator for flag \"".concat(curr.flag, "\" not found for ").concat(forType));
1108
+ }
1109
+
1110
+ let specConstraint = "constraint" in curr ? curr.constraint : null;
1111
+
1112
+ if (isFieldRef(specConstraint)) {
1113
+ specConstraint = lodash.get(context.parent, specConstraint.path);
1114
+ }
1115
+
1116
+ let result;
1117
+
1118
+ try {
1119
+ result = await validator(specConstraint, value, this._message, context);
1120
+ } catch (err) {
1121
+ const errorFromException = new ValidationError("".concat(pathToString(context.path), ": Exception occurred while validating value: ").concat(err.message));
1122
+ return convertToValidationMarker(errorFromException, "error", context);
1123
+ }
1124
+
1125
+ return convertToValidationMarker(result, this._level, context);
1126
+ }));
1127
+ return results.flat();
1128
+ }
1129
+
1130
+ }, _a.FIELD_REF = FIELD_REF, _a.array = def => new _a(def).type("Array"), _a.object = def => new _a(def).type("Object"), _a.string = def => new _a(def).type("String"), _a.number = def => new _a(def).type("Number"), _a.boolean = def => new _a(def).type("Boolean"), _a.dateTime = def => new _a(def).type("Date"), _a.valueOfField = path => ({
1131
+ type: FIELD_REF,
1132
+ path
1133
+ }), _a);
1134
+ const memoizedWarnOnArraySlug = lodash.memoize(warnOnArraySlug);
1135
+
1136
+ function getDocumentIds(id) {
1137
+ const isDraft = id.indexOf("drafts.") === 0;
1138
+ return {
1139
+ published: isDraft ? id.slice("drafts.".length) : id,
1140
+ draft: isDraft ? id : "drafts.".concat(id)
1141
+ };
1142
+ }
1143
+
1144
+ function serializePath(path) {
1145
+ return path.reduce((target, part, i) => {
1146
+ const isIndex = typeof part === "number";
1147
+ const isKey = types.isKeyedObject(part);
1148
+ const separator = i === 0 ? "" : ".";
1149
+ const add = isIndex || isKey ? "[]" : "".concat(separator).concat(part);
1150
+ return "".concat(target).concat(add);
1151
+ }, "");
1152
+ }
1153
+
1154
+ const defaultIsUnique = (slug, context) => {
1155
+ const {
1156
+ client,
1157
+ document,
1158
+ path,
1159
+ type
1160
+ } = context;
1161
+ const schemaOptions = type == null ? void 0 : type.options;
1162
+
1163
+ if (!document) {
1164
+ throw new Error("`document` was not provided in validation context.");
1165
+ }
1166
+
1167
+ if (!path) {
1168
+ throw new Error("`path` was not provided in validation context.");
1169
+ }
1170
+
1171
+ const disableArrayWarning = (schemaOptions == null ? void 0 : schemaOptions.disableArrayWarning) || false;
1172
+ const {
1173
+ published,
1174
+ draft
1175
+ } = getDocumentIds(document._id);
1176
+ const docType = document._type;
1177
+ const atPath = serializePath(path.concat("current"));
1178
+
1179
+ if (!disableArrayWarning && atPath.includes("[]")) {
1180
+ memoizedWarnOnArraySlug(serializePath(path));
1181
+ }
1182
+
1183
+ const constraints = ["_type == $docType", "!(_id in [$draft, $published])", "".concat(atPath, " == $slug")].join(" && ");
1184
+ return client.fetch("!defined(*[".concat(constraints, "][0]._id)"), {
1185
+ docType,
1186
+ draft,
1187
+ published,
1188
+ slug
1189
+ }, {
1190
+ tag: "validation.slug-is-unique"
1191
+ });
625
1192
  };
626
1193
 
627
- const typeValidators = {
628
- Boolean: booleanValidators,
629
- Number: numberValidators,
630
- String: stringValidators,
631
- Array: arrayValidators,
632
- Object: objectValidators,
633
- Date: dateValidators,
634
- };
635
- const getBaseType = (type) => {
636
- return type && type.type ? getBaseType(type.type) : type;
637
- };
638
- const isFieldRef = (constraint) => {
639
- if (typeof constraint !== 'object' || !constraint)
640
- return false;
641
- return constraint.type === Rule.FIELD_REF;
642
- };
643
- const EMPTY_ARRAY = [];
644
- const FIELD_REF = Symbol('FIELD_REF');
645
- const ruleConstraintTypes$1 = [
646
- 'Array',
647
- 'Boolean',
648
- 'Date',
649
- 'Number',
650
- 'Object',
651
- 'String',
652
- ];
653
- // Note: `RuleClass` and `Rule` are split to fit the current `@sanity/types`
654
- // setup. Classes are a bit weird in the `@sanity/types` package because classes
655
- // create an actual javascript class while simultaneously creating a type
656
- // definition.
657
- //
658
- // This implicitly creates two types:
659
- // 1. the instance type — `Rule` and
660
- // 2. the static/class type - `RuleClass`
661
- //
662
- // The `RuleClass` type contains the static methods and the `Rule` instance
663
- // contains the instance methods.
664
- //
665
- // This package exports the RuleClass as a value without implicitly exporting
666
- // an instance definition. This should help reminder downstream users to import
667
- // from the `@sanity/types` package.
668
- const Rule = class Rule {
669
- static FIELD_REF = FIELD_REF;
670
- static array = (def) => new Rule(def).type('Array');
671
- static object = (def) => new Rule(def).type('Object');
672
- static string = (def) => new Rule(def).type('String');
673
- static number = (def) => new Rule(def).type('Number');
674
- static boolean = (def) => new Rule(def).type('Boolean');
675
- static dateTime = (def) => new Rule(def).type('Date');
676
- static valueOfField = (path) => ({
677
- type: FIELD_REF,
678
- path,
679
- });
680
- _type = undefined;
681
- _level = undefined;
682
- _required = undefined;
683
- _typeDef = undefined;
684
- _message = undefined;
685
- _rules = [];
686
- _fieldRules = undefined;
687
- constructor(typeDef) {
688
- this._typeDef = typeDef;
689
- this.reset();
690
- }
691
- _mergeRequired(next) {
692
- if (this._required === 'required' || next._required === 'required')
693
- return 'required';
694
- if (this._required === 'optional' || next._required === 'optional')
695
- return 'optional';
696
- return undefined;
697
- }
698
- // Alias to static method, since we often have access to an _instance_ of a rule but not the actual Rule class
699
- valueOfField = Rule.valueOfField.bind(Rule);
700
- error(message) {
701
- const rule = this.clone();
702
- rule._level = 'error';
703
- rule._message = message || undefined;
704
- return rule;
705
- }
706
- warning(message) {
707
- const rule = this.clone();
708
- rule._level = 'warning';
709
- rule._message = message || undefined;
710
- return rule;
711
- }
712
- info(message) {
713
- const rule = this.clone();
714
- rule._level = 'info';
715
- rule._message = message || undefined;
716
- return rule;
717
- }
718
- reset() {
719
- this._type = this._type || undefined;
720
- this._rules = (this._rules || []).filter((rule) => rule.flag === 'type');
721
- this._message = undefined;
722
- this._required = undefined;
723
- this._level = 'error';
724
- this._fieldRules = undefined;
725
- return this;
726
- }
727
- isRequired() {
728
- return this._required === 'required';
729
- }
730
- clone() {
731
- const rule = new Rule();
732
- rule._type = this._type;
733
- rule._message = this._message;
734
- rule._required = this._required;
735
- rule._rules = lodash.cloneDeep(this._rules);
736
- rule._level = this._level;
737
- rule._fieldRules = this._fieldRules;
738
- rule._typeDef = this._typeDef;
739
- return rule;
740
- }
741
- cloneWithRules(rules) {
742
- const rule = this.clone();
743
- const newRules = new Set();
744
- rules.forEach((curr) => {
745
- if (curr.flag === 'type') {
746
- rule._type = curr.constraint;
747
- }
748
- newRules.add(curr.flag);
749
- });
750
- rule._rules = rule._rules
751
- .filter((curr) => {
752
- const disallowDuplicate = ['type', 'uri', 'email'].includes(curr.flag);
753
- const isDuplicate = newRules.has(curr.flag);
754
- return !(disallowDuplicate && isDuplicate);
755
- })
756
- .concat(rules);
757
- return rule;
758
- }
759
- merge(rule) {
760
- if (this._type && rule._type && this._type !== rule._type) {
761
- throw new Error('merge() failed: conflicting types');
762
- }
763
- const newRule = this.cloneWithRules(rule._rules);
764
- newRule._type = this._type || rule._type;
765
- newRule._message = this._message || rule._message;
766
- newRule._required = this._mergeRequired(rule);
767
- newRule._level = this._level === 'error' ? rule._level : this._level;
768
- return newRule;
769
- }
770
- // Validation flag setters
771
- type(targetType) {
772
- const type = `${targetType.slice(0, 1).toUpperCase()}${targetType.slice(1)}`;
773
- if (!ruleConstraintTypes$1.includes(type)) {
774
- throw new Error(`Unknown type "${targetType}"`);
775
- }
776
- const rule = this.cloneWithRules([{ flag: 'type', constraint: type }]);
777
- rule._type = type;
778
- return rule;
779
- }
780
- all(children) {
781
- return this.cloneWithRules([{ flag: 'all', constraint: children }]);
782
- }
783
- either(children) {
784
- return this.cloneWithRules([{ flag: 'either', constraint: children }]);
785
- }
786
- // Shared rules
787
- optional() {
788
- const rule = this.cloneWithRules([{ flag: 'presence', constraint: 'optional' }]);
789
- rule._required = 'optional';
790
- return rule;
791
- }
792
- required() {
793
- const rule = this.cloneWithRules([{ flag: 'presence', constraint: 'required' }]);
794
- rule._required = 'required';
795
- return rule;
796
- }
797
- custom(fn) {
798
- return this.cloneWithRules([{ flag: 'custom', constraint: fn }]);
799
- }
800
- /**
801
- * @deprecated use `Rule.custom` instead
802
- */
803
- block(fn) {
804
- return this.cloneWithRules([{ flag: 'custom', constraint: fn }]);
805
- }
806
- min(len) {
807
- return this.cloneWithRules([{ flag: 'min', constraint: len }]);
808
- }
809
- max(len) {
810
- return this.cloneWithRules([{ flag: 'max', constraint: len }]);
811
- }
812
- length(len) {
813
- return this.cloneWithRules([{ flag: 'length', constraint: len }]);
814
- }
815
- valid(value) {
816
- const values = Array.isArray(value) ? value : [value];
817
- return this.cloneWithRules([{ flag: 'valid', constraint: values }]);
818
- }
819
- // Numbers only
820
- integer() {
821
- return this.cloneWithRules([{ flag: 'integer' }]);
822
- }
823
- precision(limit) {
824
- return this.cloneWithRules([{ flag: 'precision', constraint: limit }]);
825
- }
826
- positive() {
827
- return this.cloneWithRules([{ flag: 'min', constraint: 0 }]);
828
- }
829
- negative() {
830
- return this.cloneWithRules([{ flag: 'lessThan', constraint: 0 }]);
831
- }
832
- greaterThan(num) {
833
- return this.cloneWithRules([{ flag: 'greaterThan', constraint: num }]);
834
- }
835
- lessThan(num) {
836
- return this.cloneWithRules([{ flag: 'lessThan', constraint: num }]);
837
- }
838
- // String only
839
- uppercase() {
840
- return this.cloneWithRules([{ flag: 'stringCasing', constraint: 'uppercase' }]);
841
- }
842
- lowercase() {
843
- return this.cloneWithRules([{ flag: 'stringCasing', constraint: 'lowercase' }]);
844
- }
845
- regex(pattern, a, b) {
846
- const name = typeof a === 'string' ? a : a?.name ?? b?.name;
847
- const invert = typeof a === 'string' ? false : a?.invert ?? b?.invert;
848
- const constraint = {
849
- pattern,
850
- name,
851
- invert: invert || false,
852
- };
853
- return this.cloneWithRules([{ flag: 'regex', constraint }]);
854
- }
855
- email() {
856
- return this.cloneWithRules([{ flag: 'email' }]);
857
- }
858
- uri(opts) {
859
- const optsScheme = opts?.scheme || ['http', 'https'];
860
- const schemes = Array.isArray(optsScheme) ? optsScheme : [optsScheme];
861
- if (!schemes.length) {
862
- throw new Error('scheme must have at least 1 scheme specified');
863
- }
864
- const constraint = {
865
- options: {
866
- scheme: schemes.map((scheme) => {
867
- if (!(scheme instanceof RegExp) && typeof scheme !== 'string') {
868
- throw new Error('scheme must be a RegExp or a String');
869
- }
870
- return typeof scheme === 'string' ? new RegExp(`^${escapeRegex(scheme)}$`) : scheme;
871
- }),
872
- allowRelative: opts?.allowRelative || false,
873
- relativeOnly: opts?.relativeOnly || false,
874
- allowCredentials: opts?.allowCredentials || false,
875
- },
876
- };
877
- return this.cloneWithRules([{ flag: 'uri', constraint }]);
878
- }
879
- // Array only
880
- unique() {
881
- return this.cloneWithRules([{ flag: 'unique' }]);
882
- }
883
- // Objects only
884
- reference() {
885
- return this.cloneWithRules([{ flag: 'reference' }]);
886
- }
887
- fields(rules) {
888
- if (this._type !== 'Object') {
889
- throw new Error('fields() can only be called on an object type');
890
- }
891
- const rule = this.cloneWithRules([]);
892
- rule._fieldRules = rules;
893
- return rule;
894
- }
895
- assetRequired() {
896
- const base = getBaseType(this._typeDef);
897
- let assetType;
898
- if (base && ['image', 'file'].includes(base.name)) {
899
- assetType = base.name === 'image' ? 'Image' : 'File';
900
- }
901
- else {
902
- assetType = 'Asset';
903
- }
904
- return this.cloneWithRules([{ flag: 'assetRequired', constraint: { assetType } }]);
905
- }
906
- async validate(value, context) {
907
- if (!context) {
908
- throw new Error('missing context');
909
- }
910
- const valueIsEmpty = value === null || value === undefined;
911
- // Short-circuit on optional, empty fields
912
- if (valueIsEmpty && this._required === 'optional') {
913
- return EMPTY_ARRAY;
914
- }
915
- const rules =
916
- // Run only the _custom_ functions if the rule is not set to required or optional
917
- this._required === undefined && valueIsEmpty
918
- ? this._rules.filter((curr) => curr.flag === 'custom')
919
- : this._rules;
920
- const validators = (this._type && typeValidators[this._type]) || genericValidators;
921
- const results = await Promise.all(rules.map(async (curr) => {
922
- if (curr.flag === undefined) {
923
- throw new Error('Invalid rule, did not contain "flag"-property');
924
- }
925
- const validator = validators[curr.flag];
926
- if (!validator) {
927
- const forType = this._type ? `type "${this._type}"` : 'rule without declared type';
928
- throw new Error(`Validator for flag "${curr.flag}" not found for ${forType}`);
929
- }
930
- let specConstraint = 'constraint' in curr ? curr.constraint : null;
931
- if (isFieldRef(specConstraint)) {
932
- specConstraint = lodash.get(context.parent, specConstraint.path);
933
- }
934
- let result;
935
- try {
936
- result = await validator(specConstraint, value, this._message, context);
937
- }
938
- catch (err) {
939
- const errorFromException = new ValidationError(`${pathToString(context.path)}: Exception occurred while validating value: ${err.message}`);
940
- return convertToValidationMarker(errorFromException, 'error', context);
941
- }
942
- return convertToValidationMarker(result, this._level, context);
943
- }));
944
- return results.flat();
945
- }
1194
+ function warnOnArraySlug(serializedPath) {
1195
+ console.warn(["Slug field at path ".concat(serializedPath, " is within an array and cannot be automatically checked for uniqueness"), "If you need to check for uniqueness, provide your own \"isUnique\" method", "To disable this message, set `disableArrayWarning: true` on the slug `options` field"].join("\n"));
1196
+ }
1197
+
1198
+ const slugValidator = async (value, context) => {
1199
+ var _a;
1200
+
1201
+ if (!value) {
1202
+ return true;
1203
+ }
1204
+
1205
+ if (typeof value !== "object") {
1206
+ return "Slug must be an object";
1207
+ }
1208
+
1209
+ const slugValue = value.current;
1210
+
1211
+ if (!slugValue) {
1212
+ return "Slug must have a value";
1213
+ }
1214
+
1215
+ const options = (_a = context == null ? void 0 : context.type) == null ? void 0 : _a.options;
1216
+ const isUnique = (options == null ? void 0 : options.isUnique) || defaultIsUnique;
1217
+ const wasUnique = await isUnique(slugValue, _objectSpread(_objectSpread({}, context), {}, {
1218
+ defaultIsUnique
1219
+ }));
1220
+
1221
+ if (wasUnique) {
1222
+ return true;
1223
+ }
1224
+
1225
+ return "Slug is already in use";
946
1226
  };
947
1227
 
948
- // import getClient from '../getClient'
949
- const memoizedWarnOnArraySlug = lodash.memoize(warnOnArraySlug);
950
- function getDocumentIds(id) {
951
- const isDraft = id.indexOf('drafts.') === 0;
952
- return {
953
- published: isDraft ? id.slice('drafts.'.length) : id,
954
- draft: isDraft ? id : `drafts.${id}`,
955
- };
956
- }
957
- function serializePath(path) {
958
- return path.reduce((target, part, i) => {
959
- const isIndex = typeof part === 'number';
960
- const isKey = types.isKeyedObject(part);
961
- const separator = i === 0 ? '' : '.';
962
- const add = isIndex || isKey ? '[]' : `${separator}${part}`;
963
- return `${target}${add}`;
964
- }, '');
965
- }
966
- const defaultIsUnique = (slug, context) => {
967
- const { client, document, path, type } = context;
968
- const schemaOptions = type?.options;
969
- if (!document) {
970
- throw new Error(`\`document\` was not provided in validation context.`);
971
- }
972
- if (!path) {
973
- throw new Error(`\`path\` was not provided in validation context.`);
974
- }
975
- const disableArrayWarning = schemaOptions?.disableArrayWarning || false;
976
- const { published, draft } = getDocumentIds(document._id);
977
- const docType = document._type;
978
- const atPath = serializePath(path.concat('current'));
979
- if (!disableArrayWarning && atPath.includes('[]')) {
980
- memoizedWarnOnArraySlug(serializePath(path));
981
- }
982
- const constraints = [
983
- '_type == $docType',
984
- `!(_id in [$draft, $published])`,
985
- `${atPath} == $slug`,
986
- ].join(' && ');
987
- return client.fetch(`!defined(*[${constraints}][0]._id)`, {
988
- docType,
989
- draft,
990
- published,
991
- slug,
992
- }, { tag: 'validation.slug-is-unique' });
993
- };
994
- function warnOnArraySlug(serializedPath) {
995
- /* eslint-disable no-console */
996
- console.warn([
997
- `Slug field at path ${serializedPath} is within an array and cannot be automatically checked for uniqueness`,
998
- `If you need to check for uniqueness, provide your own "isUnique" method`,
999
- `To disable this message, set \`disableArrayWarning: true\` on the slug \`options\` field`,
1000
- ].join('\n'));
1001
- /* eslint-enable no-console */
1002
- }
1003
- /**
1004
- * Validates slugs values by querying for uniqueness from the client.
1005
- *
1006
- * This is a custom rule implementation (e.g. `Rule.custom(slugValidator)`)
1007
- * that's populated in `inferFromSchemaType` when the type name is `slug`
1008
- */
1009
- const slugValidator = async (value, context) => {
1010
- if (!value) {
1011
- return true;
1012
- }
1013
- if (typeof value !== 'object') {
1014
- return 'Slug must be an object';
1015
- }
1016
- const slugValue = value.current;
1017
- if (!slugValue) {
1018
- return 'Slug must have a value';
1019
- }
1020
- const options = context?.type?.options;
1021
- const isUnique = options?.isUnique || defaultIsUnique;
1022
- const wasUnique = await isUnique(slugValue, { ...context, defaultIsUnique });
1023
- if (wasUnique) {
1024
- return true;
1025
- }
1026
- return 'Slug is already in use';
1228
+ const ruleConstraintTypes = {
1229
+ array: true,
1230
+ boolean: true,
1231
+ date: true,
1232
+ number: true,
1233
+ object: true,
1234
+ string: true
1027
1235
  };
1028
1236
 
1029
- const ruleConstraintTypes = {
1030
- array: true,
1031
- boolean: true,
1032
- date: true,
1033
- number: true,
1034
- object: true,
1035
- string: true,
1036
- };
1037
- const isRuleConstraint = (typeString) => typeString in ruleConstraintTypes;
1038
- function getTypeChain(type, visited) {
1039
- if (!type)
1040
- return [];
1041
- if (visited.has(type))
1042
- return [];
1043
- visited.add(type);
1044
- const next = type.type ? getTypeChain(type.type, visited) : [];
1045
- return [...next, type];
1046
- }
1047
- function baseRuleReducer(inputRule, type) {
1048
- let baseRule = inputRule;
1049
- if (isRuleConstraint(type.jsonType)) {
1050
- baseRule = baseRule.type(type.jsonType);
1051
- }
1052
- const typeOptionsList =
1053
- // if type.options is truthy
1054
- type?.options &&
1055
- // and type.options is an object (non-null from the previous)
1056
- typeof type.options === 'object' &&
1057
- // and if `list` is in options
1058
- 'list' in type.options &&
1059
- // then finally access the list
1060
- type.options.list;
1061
- if (Array.isArray(typeOptionsList)) {
1062
- baseRule = baseRule.valid(typeOptionsList.map((option) => extractValueFromListOption(option, type)));
1063
- }
1064
- if (type.name === 'datetime')
1065
- return baseRule.type('Date');
1066
- if (type.name === 'date')
1067
- return baseRule.type('Date');
1068
- if (type.name === 'url')
1069
- return baseRule.uri();
1070
- if (type.name === 'slug')
1071
- return baseRule.custom(slugValidator);
1072
- if (type.name === 'reference')
1073
- return baseRule.reference();
1074
- if (type.name === 'email')
1075
- return baseRule.email();
1076
- return baseRule;
1077
- }
1078
- function hasValueField(typeDef) {
1079
- if (!typeDef)
1080
- return false;
1081
- if (!('fields' in typeDef) && typeDef.type)
1082
- return hasValueField(typeDef.type);
1083
- if (!('fields' in typeDef))
1084
- return false;
1085
- if (!Array.isArray(typeDef.fields))
1086
- return false;
1087
- return typeDef.fields.some((field) => field.name === 'value');
1088
- }
1089
- function extractValueFromListOption(option, typeDef) {
1090
- // If you define a `list` option with object items, where the item has a `value` field,
1091
- // we don't want to treat that as the value but rather the surrounding object
1092
- // This differs from the case where you have a title/value pair setup for a string/number, for instance
1093
- if (typeDef.jsonType === 'object' && hasValueField(typeDef))
1094
- return option;
1095
- return option.value === undefined
1096
- ? option
1097
- : option.value;
1098
- }
1099
- /**
1100
- * Takes in `SchemaValidationValue` and returns an array of `Rule` instances.
1101
- */
1102
- function normalizeValidationRules(typeDef) {
1103
- if (!typeDef) {
1104
- return [];
1105
- }
1106
- const validation = typeDef.validation;
1107
- if (Array.isArray(validation)) {
1108
- return validation.flatMap((i) => normalizeValidationRules({
1109
- ...typeDef,
1110
- validation: i,
1111
- }));
1112
- }
1113
- if (validation instanceof Rule) {
1114
- return [validation];
1115
- }
1116
- const baseRule =
1117
- // using an object + Object.values to de-dupe the type chain by type name
1118
- Object.values(getTypeChain(typeDef, new Set()).reduce((acc, type) => {
1119
- acc[type.name] = type;
1120
- return acc;
1121
- }, {})).reduce(baseRuleReducer, new Rule(typeDef));
1122
- if (!validation) {
1123
- return [baseRule];
1124
- }
1125
- return normalizeValidationRules({
1126
- ...typeDef,
1127
- validation: validation(baseRule),
1128
- });
1237
+ const isRuleConstraint = typeString => typeString in ruleConstraintTypes;
1238
+
1239
+ function getTypeChain(type, visited) {
1240
+ if (!type) return [];
1241
+ if (visited.has(type)) return [];
1242
+ visited.add(type);
1243
+ const next = type.type ? getTypeChain(type.type, visited) : [];
1244
+ return [...next, type];
1129
1245
  }
1130
1246
 
1131
- const isRecord = (maybeRecord) => typeof maybeRecord === 'object' && maybeRecord !== null && !Array.isArray(maybeRecord);
1132
- const isNonNullable = (value) => value !== null && value !== undefined;
1133
- /**
1134
- * @internal
1135
- */
1136
- function resolveTypeForArrayItem(item, candidates) {
1137
- // if there is only one type available, assume that it's the correct one
1138
- if (candidates.length === 1)
1139
- return candidates[0];
1140
- const itemType = types.isTypedObject(item) && item._type;
1141
- const primitive = item === undefined || item === null || (!itemType && typeString(item).toLowerCase());
1142
- if (primitive && primitive !== 'object') {
1143
- return candidates.find((candidate) => candidate.jsonType === primitive);
1144
- }
1145
- return (candidates.find((candidate) => candidate.type?.name === itemType) ||
1146
- candidates.find((candidate) => candidate.name === itemType) ||
1147
- candidates.find((candidate) => candidate.name === 'object' && primitive === 'object'));
1148
- }
1149
- async function validateDocument(client, doc, schema, context) {
1150
- const documentType = schema.get(doc._type);
1151
- if (!documentType) {
1152
- console.warn('Schema type for object type "%s" not found, skipping validation', doc._type);
1153
- return [];
1154
- }
1155
- try {
1156
- return await validateItem({
1157
- client,
1158
- schema,
1159
- parent: undefined,
1160
- value: doc,
1161
- path: [],
1162
- document: doc,
1163
- type: documentType,
1164
- getDocumentExists: context?.getDocumentExists,
1165
- });
1166
- }
1167
- catch (err) {
1168
- console.error(err);
1169
- return [
1170
- {
1171
- level: 'error',
1172
- path: [],
1173
- item: new ValidationError(err?.message),
1174
- },
1175
- ];
1176
- }
1177
- }
1178
- async function validateItem({ value, type, path = [], parent, ...restOfContext }) {
1179
- const rules = normalizeValidationRules(type);
1180
- // run validation for the current value
1181
- const selfChecks = rules.map((rule) => rule.validate(value, {
1182
- ...restOfContext,
1183
- parent,
1184
- path,
1185
- type,
1186
- }));
1187
- // run validation for nested values (conditionally)
1188
- let nestedChecks = [];
1189
- const selfIsRequired = rules.some((rule) => rule.isRequired());
1190
- const shouldRunNestedObjectValidation =
1191
- // run nested validation for objects
1192
- type?.jsonType === 'object' &&
1193
- // if the value is truthy
1194
- (!!value || // or
1195
- // (the value is null or undefined) and the top-level value is required
1196
- ((value === null || value === undefined) && selfIsRequired));
1197
- if (shouldRunNestedObjectValidation) {
1198
- const fieldTypes = type.fields.reduce((acc, field) => {
1199
- acc[field.name] = field.type;
1200
- return acc;
1201
- }, {});
1202
- // Validation for rules set at the object level with `Rule.fields({/* ... */})`
1203
- nestedChecks = nestedChecks.concat(rules
1204
- .map((rule) => rule._fieldRules)
1205
- .filter(isNonNullable)
1206
- .flatMap((fieldResults) => Object.entries(fieldResults))
1207
- .flatMap(([name, validation]) => {
1208
- const fieldType = fieldTypes[name];
1209
- return normalizeValidationRules({ ...fieldType, validation }).map((subRule) => {
1210
- const nestedValue = isRecord(value) ? value[name] : undefined;
1211
- return subRule.validate(nestedValue, {
1212
- ...restOfContext,
1213
- parent: value,
1214
- path: path.concat(name),
1215
- type: fieldType,
1216
- });
1217
- });
1218
- }));
1219
- // Validation from each field's schema `validation: Rule => {/* ... */}` function
1220
- nestedChecks = nestedChecks.concat(type.fields.map((field) => validateItem({
1221
- ...restOfContext,
1222
- parent: value,
1223
- value: isRecord(value) ? value[field.name] : undefined,
1224
- path: path.concat(field.name),
1225
- type: field.type,
1226
- })));
1227
- }
1228
- // note: unlike objects, arrays should not run nested validation for undefined
1229
- // values because we won't have a valid path to put a marker (i.e. missing the
1230
- // key or index in the path) and the downstream form builder won't have a
1231
- // valid target component
1232
- const shouldRunNestedValidationForArrays = type?.jsonType === 'array' && Array.isArray(value);
1233
- if (shouldRunNestedValidationForArrays) {
1234
- nestedChecks = nestedChecks.concat(value.map((item) => validateItem({
1235
- ...restOfContext,
1236
- parent: value,
1237
- value: item,
1238
- path: path.concat(types.isKeyedObject(item) ? { _key: item._key } : value.indexOf(item)),
1239
- type: resolveTypeForArrayItem(item, type.of),
1240
- })));
1241
- }
1242
- // markDefs also do no run nested validation if the parent object is undefined
1243
- // for a similar reason to arrays
1244
- const shouldRunNestedValidationForMarkDefs = types.isBlock(value) && value.markDefs.length && types.isBlockSchemaType(type);
1245
- if (shouldRunNestedValidationForMarkDefs) {
1246
- const [spanChildrenField] = type.fields;
1247
- const spanType = spanChildrenField.type.of.find(types.isSpanSchemaType);
1248
- const annotations = (spanType?.annotations || []).reduce((map, annotationType) => {
1249
- map.set(annotationType.name, annotationType);
1250
- return map;
1251
- }, new Map());
1252
- nestedChecks = nestedChecks.concat(value.markDefs.map((markDef) => validateItem({
1253
- ...restOfContext,
1254
- parent: value,
1255
- value: markDef,
1256
- path: path.concat(['markDefs', { _key: markDef._key }]),
1257
- type: annotations.get(markDef._type),
1258
- })));
1259
- }
1260
- const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat();
1261
- // run `uniqBy` if `_fieldRules` are present because they can
1262
- // cause repeat markers
1263
- if (rules.some((rule) => rule._fieldRules)) {
1264
- return lodash.uniqBy(results, (rule) => JSON.stringify(rule));
1265
- }
1266
- return results;
1247
+ function baseRuleReducer(inputRule, type) {
1248
+ let baseRule = inputRule;
1249
+
1250
+ if (isRuleConstraint(type.jsonType)) {
1251
+ baseRule = baseRule.type(type.jsonType);
1252
+ }
1253
+
1254
+ const typeOptionsList = (type == null ? void 0 : type.options) && typeof type.options === "object" && "list" in type.options && type.options.list;
1255
+
1256
+ if (Array.isArray(typeOptionsList)) {
1257
+ baseRule = baseRule.valid(typeOptionsList.map(option => extractValueFromListOption(option, type)));
1258
+ }
1259
+
1260
+ if (type.name === "datetime") return baseRule.type("Date");
1261
+ if (type.name === "date") return baseRule.type("Date");
1262
+ if (type.name === "url") return baseRule.uri();
1263
+ if (type.name === "slug") return baseRule.custom(slugValidator);
1264
+ if (type.name === "reference") return baseRule.reference();
1265
+ if (type.name === "email") return baseRule.email();
1266
+ return baseRule;
1267
1267
  }
1268
1268
 
1269
- function traverse(typeDef, visited) {
1270
- if (visited.has(typeDef)) {
1271
- return;
1272
- }
1273
- visited.add(typeDef);
1274
- typeDef.validation = normalizeValidationRules(typeDef);
1275
- if ('fields' in typeDef) {
1276
- for (const field of typeDef.fields) {
1277
- traverse(field.type, visited);
1278
- }
1279
- }
1280
- if ('of' in typeDef) {
1281
- for (const candidate of typeDef.of) {
1282
- traverse(candidate, visited);
1283
- }
1284
- }
1285
- // eslint-disable-next-line no-warning-comments
1286
- // @ts-expect-error TODO (eventually): `annotations` does not exist on the SchemaType yet
1287
- if (typeDef.annotations) {
1288
- // eslint-disable-next-line no-warning-comments
1289
- // @ts-expect-error TODO (eventually): `annotations` does not exist on the SchemaType yet
1290
- for (const annotation of typeDef.annotations) {
1291
- traverse(annotation, visited);
1292
- }
1293
- }
1294
- }
1295
- function inferFromSchemaType(typeDef) {
1296
- traverse(typeDef, new Set());
1297
- return typeDef;
1269
+ function hasValueField(typeDef) {
1270
+ if (!typeDef) return false;
1271
+ if (!("fields" in typeDef) && typeDef.type) return hasValueField(typeDef.type);
1272
+ if (!("fields" in typeDef)) return false;
1273
+ if (!Array.isArray(typeDef.fields)) return false;
1274
+ return typeDef.fields.some(field => field.name === "value");
1298
1275
  }
1299
1276
 
1300
- // Note: Mutates schema. Refactor when @sanity/schema supports middlewares
1301
- function inferFromSchema(schema) {
1302
- const typeNames = schema.getTypeNames();
1303
- typeNames.forEach((typeName) => {
1304
- const schemaType = schema.get(typeName);
1305
- if (schemaType) {
1306
- inferFromSchemaType(schemaType);
1307
- }
1308
- });
1309
- return schema;
1277
+ function extractValueFromListOption(option, typeDef) {
1278
+ if (typeDef.jsonType === "object" && hasValueField(typeDef)) return option;
1279
+ return option.value === void 0 ? option : option.value;
1310
1280
  }
1311
1281
 
1312
- var index = { Rule: Rule, validateDocument, inferFromSchema, inferFromSchemaType };
1282
+ function normalizeValidationRules(typeDef) {
1283
+ if (!typeDef) {
1284
+ return [];
1285
+ }
1286
+
1287
+ const validation = typeDef.validation;
1288
+
1289
+ if (Array.isArray(validation)) {
1290
+ return validation.flatMap(i => normalizeValidationRules(_objectSpread(_objectSpread({}, typeDef), {}, {
1291
+ validation: i
1292
+ })));
1293
+ }
1294
+
1295
+ if (validation instanceof Rule) {
1296
+ return [validation];
1297
+ }
1298
+
1299
+ const baseRule = Object.values(getTypeChain(typeDef, /* @__PURE__ */new Set()).reduce((acc, type) => {
1300
+ acc[type.name] = type;
1301
+ return acc;
1302
+ }, {})).reduce(baseRuleReducer, new Rule(typeDef));
1303
+
1304
+ if (!validation) {
1305
+ return [baseRule];
1306
+ }
1307
+
1308
+ return normalizeValidationRules(_objectSpread(_objectSpread({}, typeDef), {}, {
1309
+ validation: validation(baseRule)
1310
+ }));
1311
+ }
1312
+
1313
+ const isRecord = maybeRecord => typeof maybeRecord === "object" && maybeRecord !== null && !Array.isArray(maybeRecord);
1314
+
1315
+ const isNonNullable = value => value !== null && value !== void 0;
1316
+
1317
+ function resolveTypeForArrayItem(item, candidates) {
1318
+ if (candidates.length === 1) return candidates[0];
1319
+
1320
+ const itemType = types.isTypedObject(item) && item._type;
1321
+
1322
+ const primitive = item === void 0 || item === null || !itemType && typeString(item).toLowerCase();
1323
+
1324
+ if (primitive && primitive !== "object") {
1325
+ return candidates.find(candidate => candidate.jsonType === primitive);
1326
+ }
1327
+
1328
+ return candidates.find(candidate => {
1329
+ var _a;
1330
+
1331
+ return ((_a = candidate.type) == null ? void 0 : _a.name) === itemType;
1332
+ }) || candidates.find(candidate => candidate.name === itemType) || candidates.find(candidate => candidate.name === "object" && primitive === "object");
1333
+ }
1334
+
1335
+ async function validateDocument(client, doc, schema, context) {
1336
+ const documentType = schema.get(doc._type);
1337
+
1338
+ if (!documentType) {
1339
+ console.warn('Schema type for object type "%s" not found, skipping validation', doc._type);
1340
+ return [];
1341
+ }
1342
+
1343
+ try {
1344
+ return await validateItem({
1345
+ client,
1346
+ schema,
1347
+ parent: void 0,
1348
+ value: doc,
1349
+ path: [],
1350
+ document: doc,
1351
+ type: documentType,
1352
+ getDocumentExists: context == null ? void 0 : context.getDocumentExists
1353
+ });
1354
+ } catch (err) {
1355
+ console.error(err);
1356
+ return [{
1357
+ level: "error",
1358
+ path: [],
1359
+ item: new ValidationError(err == null ? void 0 : err.message)
1360
+ }];
1361
+ }
1362
+ }
1363
+
1364
+ async function validateItem(_ref) {
1365
+ let {
1366
+ value,
1367
+ type,
1368
+ path = [],
1369
+ parent
1370
+ } = _ref,
1371
+ restOfContext = _objectWithoutProperties(_ref, _excluded);
1372
+
1373
+ const rules = normalizeValidationRules(type);
1374
+ const selfChecks = rules.map(rule => rule.validate(value, _objectSpread(_objectSpread({}, restOfContext), {}, {
1375
+ parent,
1376
+ path,
1377
+ type
1378
+ })));
1379
+ let nestedChecks = [];
1380
+ const selfIsRequired = rules.some(rule => rule.isRequired());
1381
+ const shouldRunNestedObjectValidation = (type == null ? void 0 : type.jsonType) === "object" && (!!value || (value === null || value === void 0) && selfIsRequired);
1382
+
1383
+ if (shouldRunNestedObjectValidation) {
1384
+ const fieldTypes = type.fields.reduce((acc, field) => {
1385
+ acc[field.name] = field.type;
1386
+ return acc;
1387
+ }, {});
1388
+ nestedChecks = nestedChecks.concat(rules.map(rule => rule._fieldRules).filter(isNonNullable).flatMap(fieldResults => Object.entries(fieldResults)).flatMap(_ref2 => {
1389
+ let [name, validation] = _ref2;
1390
+ const fieldType = fieldTypes[name];
1391
+ return normalizeValidationRules(_objectSpread(_objectSpread({}, fieldType), {}, {
1392
+ validation
1393
+ })).map(subRule => {
1394
+ const nestedValue = isRecord(value) ? value[name] : void 0;
1395
+ return subRule.validate(nestedValue, _objectSpread(_objectSpread({}, restOfContext), {}, {
1396
+ parent: value,
1397
+ path: path.concat(name),
1398
+ type: fieldType
1399
+ }));
1400
+ });
1401
+ }));
1402
+ nestedChecks = nestedChecks.concat(type.fields.map(field => validateItem(_objectSpread(_objectSpread({}, restOfContext), {}, {
1403
+ parent: value,
1404
+ value: isRecord(value) ? value[field.name] : void 0,
1405
+ path: path.concat(field.name),
1406
+ type: field.type
1407
+ }))));
1408
+ }
1409
+
1410
+ const shouldRunNestedValidationForArrays = (type == null ? void 0 : type.jsonType) === "array" && Array.isArray(value);
1411
+
1412
+ if (shouldRunNestedValidationForArrays) {
1413
+ nestedChecks = nestedChecks.concat(value.map(item => validateItem(_objectSpread(_objectSpread({}, restOfContext), {}, {
1414
+ parent: value,
1415
+ value: item,
1416
+ path: path.concat(types.isKeyedObject(item) ? {
1417
+ _key: item._key
1418
+ } : value.indexOf(item)),
1419
+ type: resolveTypeForArrayItem(item, type.of)
1420
+ }))));
1421
+ }
1422
+
1423
+ const shouldRunNestedValidationForMarkDefs = types.isBlock(value) && value.markDefs.length && types.isBlockSchemaType(type);
1424
+
1425
+ if (shouldRunNestedValidationForMarkDefs) {
1426
+ const [spanChildrenField] = type.fields;
1427
+ const spanType = spanChildrenField.type.of.find(types.isSpanSchemaType);
1428
+ const annotations = ((spanType == null ? void 0 : spanType.annotations) || []).reduce((map, annotationType) => {
1429
+ map.set(annotationType.name, annotationType);
1430
+ return map;
1431
+ }, /* @__PURE__ */new Map());
1432
+ nestedChecks = nestedChecks.concat(value.markDefs.map(markDef => validateItem(_objectSpread(_objectSpread({}, restOfContext), {}, {
1433
+ parent: value,
1434
+ value: markDef,
1435
+ path: path.concat(["markDefs", {
1436
+ _key: markDef._key
1437
+ }]),
1438
+ type: annotations.get(markDef._type)
1439
+ }))));
1440
+ }
1441
+
1442
+ const results = (await Promise.all([...selfChecks, ...nestedChecks])).flat();
1443
+
1444
+ if (rules.some(rule => rule._fieldRules)) {
1445
+ return lodash.uniqBy(results, rule => JSON.stringify(rule));
1446
+ }
1447
+
1448
+ return results;
1449
+ }
1450
+
1451
+ function traverse(typeDef, visited) {
1452
+ if (visited.has(typeDef)) {
1453
+ return;
1454
+ }
1455
+
1456
+ visited.add(typeDef);
1457
+ typeDef.validation = normalizeValidationRules(typeDef);
1458
+
1459
+ if ("fields" in typeDef) {
1460
+ for (const field of typeDef.fields) {
1461
+ traverse(field.type, visited);
1462
+ }
1463
+ }
1464
+
1465
+ if ("of" in typeDef) {
1466
+ for (const candidate of typeDef.of) {
1467
+ traverse(candidate, visited);
1468
+ }
1469
+ }
1470
+
1471
+ if (typeDef.annotations) {
1472
+ for (const annotation of typeDef.annotations) {
1473
+ traverse(annotation, visited);
1474
+ }
1475
+ }
1476
+ }
1477
+
1478
+ function inferFromSchemaType(typeDef) {
1479
+ traverse(typeDef, /* @__PURE__ */new Set());
1480
+ return typeDef;
1481
+ }
1482
+
1483
+ function inferFromSchema(schema) {
1484
+ const typeNames = schema.getTypeNames();
1485
+ typeNames.forEach(typeName => {
1486
+ const schemaType = schema.get(typeName);
1487
+
1488
+ if (schemaType) {
1489
+ inferFromSchemaType(schemaType);
1490
+ }
1491
+ });
1492
+ return schema;
1493
+ }
1313
1494
 
1314
1495
  exports.Rule = Rule;
1315
- exports["default"] = index;
1316
1496
  exports.inferFromSchema = inferFromSchema;
1317
1497
  exports.inferFromSchemaType = inferFromSchemaType;
1318
1498
  exports.validateDocument = validateDocument;