schema-dsl 1.2.5 → 2.0.1

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 (243) hide show
  1. package/CHANGELOG.md +130 -238
  2. package/LICENSE +21 -21
  3. package/README.md +628 -2486
  4. package/dist/DslBuilder-BIgQOAXp.d.ts +343 -0
  5. package/dist/DslBuilder-CjHTucNQ.d.cts +343 -0
  6. package/dist/Validator-CllRdrY0.d.ts +192 -0
  7. package/dist/Validator-D6okG9tr.d.cts +192 -0
  8. package/dist/index.cjs +6640 -0
  9. package/dist/index.d.cts +1151 -0
  10. package/dist/index.d.ts +1151 -0
  11. package/dist/index.js +6574 -0
  12. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  13. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  14. package/dist/plugins/custom-format.cjs +3818 -0
  15. package/dist/plugins/custom-format.d.cts +12 -0
  16. package/dist/plugins/custom-format.d.ts +12 -0
  17. package/dist/plugins/custom-format.js +3788 -0
  18. package/dist/plugins/custom-type-example.cjs +3811 -0
  19. package/dist/plugins/custom-type-example.d.cts +8 -0
  20. package/dist/plugins/custom-type-example.d.ts +8 -0
  21. package/dist/plugins/custom-type-example.js +3781 -0
  22. package/dist/plugins/custom-validator.cjs +144 -0
  23. package/dist/plugins/custom-validator.d.cts +10 -0
  24. package/dist/plugins/custom-validator.d.ts +10 -0
  25. package/dist/plugins/custom-validator.js +119 -0
  26. package/docs/FEATURE-INDEX.md +553 -519
  27. package/docs/add-custom-locale.md +496 -483
  28. package/docs/add-keyword.md +24 -0
  29. package/docs/api-reference.md +1047 -805
  30. package/docs/api.md +13 -0
  31. package/docs/best-practices-project-structure.md +417 -408
  32. package/docs/best-practices.md +712 -672
  33. package/docs/cache-manager.md +344 -336
  34. package/docs/compile.md +45 -0
  35. package/docs/conditional-api.md +1307 -1278
  36. package/docs/custom-extensions-guide.md +339 -411
  37. package/docs/design-philosophy.md +606 -601
  38. package/docs/doc-index.md +324 -0
  39. package/docs/dsl-syntax.md +714 -664
  40. package/docs/dynamic-locale.md +608 -598
  41. package/docs/enum.md +482 -475
  42. package/docs/error-handling.md +1975 -1966
  43. package/docs/export-guide.md +501 -462
  44. package/docs/export-limitations.md +567 -551
  45. package/docs/faq.md +596 -577
  46. package/docs/frontend-i18n-guide.md +307 -293
  47. package/docs/i18n-user-guide.md +487 -474
  48. package/docs/i18n.md +476 -457
  49. package/docs/index.md +48 -0
  50. package/docs/json-schema-basics.md +40 -0
  51. package/docs/label-vs-description.md +271 -262
  52. package/docs/markdown-exporter.md +406 -397
  53. package/docs/mongodb-exporter.md +302 -295
  54. package/docs/multi-language.md +26 -0
  55. package/docs/multi-type-support.md +322 -329
  56. package/docs/mysql-exporter.md +280 -273
  57. package/docs/number-operators.md +449 -442
  58. package/docs/optional-marker-guide.md +326 -321
  59. package/docs/performance-guide.md +49 -0
  60. package/docs/plugin-system.md +381 -542
  61. package/docs/plugin-type-registration.md +34 -0
  62. package/docs/postgresql-exporter.md +311 -304
  63. package/docs/public/favicon.svg +5 -0
  64. package/docs/quick-start.md +435 -761
  65. package/docs/runtime-locale-support.md +532 -521
  66. package/docs/schema-helper.md +345 -340
  67. package/docs/schema-utils-advanced-issues.md +23 -0
  68. package/docs/schema-utils-best-practices.md +20 -0
  69. package/docs/schema-utils-chaining.md +150 -143
  70. package/docs/schema-utils.md +524 -490
  71. package/docs/security-checklist.md +20 -0
  72. package/docs/string-extensions.md +488 -480
  73. package/docs/troubleshooting.md +486 -471
  74. package/docs/type-converter.md +310 -319
  75. package/docs/type-reference.md +242 -219
  76. package/docs/typescript-guide.md +584 -573
  77. package/docs/union-type-guide.md +157 -147
  78. package/docs/union-types.md +284 -277
  79. package/docs/validate-async.md +491 -480
  80. package/docs/validate-batch.md +49 -0
  81. package/docs/validate-dsl-object-support.md +578 -573
  82. package/docs/validate.md +506 -486
  83. package/docs/validation-guide.md +502 -484
  84. package/docs/validator.md +39 -0
  85. package/package.json +131 -73
  86. package/plugins/custom-format.cjs +8 -0
  87. package/plugins/custom-type-example.cjs +8 -0
  88. package/plugins/custom-validator.cjs +8 -0
  89. package/src/adapters/DslAdapter.ts +111 -0
  90. package/src/adapters/index.ts +1 -0
  91. package/src/config/constants.ts +83 -0
  92. package/src/config/index.ts +2 -0
  93. package/src/config/patterns.ts +77 -0
  94. package/src/core/CacheManager.ts +169 -0
  95. package/src/core/ConditionalBuilder.ts +382 -0
  96. package/src/core/ConditionalRuntime.ts +28 -0
  97. package/src/core/ConditionalValidator.ts +255 -0
  98. package/src/core/DslBuilder.ts +687 -0
  99. package/src/core/ErrorCodes.ts +38 -0
  100. package/src/core/ErrorFormatter.ts +271 -0
  101. package/src/core/JSONSchemaCore.ts +65 -0
  102. package/src/core/Locale.ts +187 -0
  103. package/src/core/MessageTemplate.ts +42 -0
  104. package/src/core/ObjectDslBuilder.ts +64 -0
  105. package/src/core/PluginManager.ts +326 -0
  106. package/src/core/StringExtensions.ts +140 -0
  107. package/src/core/TemplateEngine.ts +44 -0
  108. package/src/core/Validator.ts +448 -0
  109. package/src/errors/I18nError.ts +159 -0
  110. package/src/errors/ValidationError.ts +105 -0
  111. package/src/exporters/BaseExporter.ts +60 -0
  112. package/src/exporters/MarkdownExporter.ts +305 -0
  113. package/src/exporters/MongoDBExporter.ts +126 -0
  114. package/src/exporters/MySQLExporter.ts +156 -0
  115. package/src/exporters/PostgreSQLExporter.ts +222 -0
  116. package/src/exporters/index.ts +18 -0
  117. package/src/index.ts +651 -0
  118. package/{lib/locales/en-US.js → src/locales/en-US.ts} +160 -176
  119. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +160 -113
  120. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +160 -113
  121. package/src/locales/index.ts +103 -0
  122. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +160 -118
  123. package/src/locales/types.ts +156 -0
  124. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +160 -177
  125. package/src/parser/ConstraintParser.ts +101 -0
  126. package/src/parser/DslParser.ts +470 -0
  127. package/src/parser/SchemaCompiler.ts +66 -0
  128. package/src/parser/TypeRegistry.ts +250 -0
  129. package/src/parser/index.ts +6 -0
  130. package/src/plugins/custom-format.ts +124 -0
  131. package/src/plugins/custom-type-example.ts +106 -0
  132. package/src/plugins/custom-validator.ts +138 -0
  133. package/src/types/conditional.ts +28 -0
  134. package/src/types/config.ts +59 -0
  135. package/src/types/dsl.ts +131 -0
  136. package/src/types/error.ts +60 -0
  137. package/src/types/index.ts +17 -0
  138. package/src/types/infer.ts +128 -0
  139. package/src/types/plugin.ts +58 -0
  140. package/src/types/safe-regex.d.ts +9 -0
  141. package/src/types/schema.ts +66 -0
  142. package/src/types/validate.ts +71 -0
  143. package/src/utils/SchemaHelper.ts +196 -0
  144. package/src/utils/SchemaUtils.ts +365 -0
  145. package/src/utils/TypeConverter.ts +215 -0
  146. package/src/utils/index.ts +10 -0
  147. package/src/validators/CustomKeywords.ts +477 -0
  148. package/.eslintignore +0 -11
  149. package/.eslintrc.json +0 -27
  150. package/CONTRIBUTING.md +0 -368
  151. package/STATUS.md +0 -491
  152. package/changelogs/v1.0.0.md +0 -328
  153. package/changelogs/v1.0.9.md +0 -367
  154. package/changelogs/v1.1.0.md +0 -389
  155. package/changelogs/v1.1.1.md +0 -308
  156. package/changelogs/v1.1.2.md +0 -183
  157. package/changelogs/v1.1.3.md +0 -161
  158. package/changelogs/v1.1.4.md +0 -432
  159. package/changelogs/v1.1.5.md +0 -493
  160. package/changelogs/v1.1.6.md +0 -211
  161. package/changelogs/v1.1.8.md +0 -376
  162. package/changelogs/v1.2.3.md +0 -124
  163. package/docs/INDEX.md +0 -252
  164. package/docs/issues-resolved-summary.md +0 -196
  165. package/docs/performance-benchmark-report.md +0 -179
  166. package/docs/performance-quick-reference.md +0 -123
  167. package/docs/user-questions-answered.md +0 -353
  168. package/docs/validation-rules-v1.0.2.md +0 -1608
  169. package/examples/README.md +0 -81
  170. package/examples/array-dsl-example.js +0 -227
  171. package/examples/conditional-example.js +0 -288
  172. package/examples/conditional-non-object.js +0 -129
  173. package/examples/conditional-validate-example.js +0 -321
  174. package/examples/custom-extension.js +0 -85
  175. package/examples/dsl-match-example.js +0 -74
  176. package/examples/dsl-style.js +0 -118
  177. package/examples/dynamic-locale-configuration.js +0 -348
  178. package/examples/dynamic-locale-example.js +0 -287
  179. package/examples/enum.examples.js +0 -324
  180. package/examples/export-demo.js +0 -130
  181. package/examples/express-integration.js +0 -376
  182. package/examples/i18n-error-handling-complete.js +0 -381
  183. package/examples/i18n-error-handling-quickstart.md +0 -0
  184. package/examples/i18n-error.examples.js +0 -181
  185. package/examples/i18n-full-demo.js +0 -301
  186. package/examples/i18n-memory-safety.examples.js +0 -268
  187. package/examples/markdown-export.js +0 -71
  188. package/examples/middleware-usage.js +0 -93
  189. package/examples/new-features-comparison.js +0 -315
  190. package/examples/password-reset/README.md +0 -153
  191. package/examples/password-reset/schema.js +0 -26
  192. package/examples/password-reset/test.js +0 -101
  193. package/examples/plugin-system.examples.js +0 -205
  194. package/examples/schema-utils-chaining.examples.js +0 -250
  195. package/examples/simple-example.js +0 -122
  196. package/examples/slug.examples.js +0 -179
  197. package/examples/string-extensions.js +0 -297
  198. package/examples/union-type-example.js +0 -127
  199. package/examples/union-types-example.js +0 -77
  200. package/examples/user-registration/README.md +0 -156
  201. package/examples/user-registration/routes.js +0 -92
  202. package/examples/user-registration/schema.js +0 -150
  203. package/examples/user-registration/server.js +0 -74
  204. package/index.d.ts +0 -3658
  205. package/index.js +0 -475
  206. package/index.mjs +0 -60
  207. package/lib/adapters/DslAdapter.js +0 -995
  208. package/lib/adapters/index.js +0 -20
  209. package/lib/config/constants.js +0 -286
  210. package/lib/config/patterns/common.js +0 -47
  211. package/lib/config/patterns/creditCard.js +0 -9
  212. package/lib/config/patterns/idCard.js +0 -9
  213. package/lib/config/patterns/index.js +0 -9
  214. package/lib/config/patterns/licensePlate.js +0 -4
  215. package/lib/config/patterns/passport.js +0 -4
  216. package/lib/config/patterns/phone.js +0 -9
  217. package/lib/config/patterns/postalCode.js +0 -5
  218. package/lib/core/CacheManager.js +0 -376
  219. package/lib/core/ConditionalBuilder.js +0 -503
  220. package/lib/core/DslBuilder.js +0 -1589
  221. package/lib/core/ErrorCodes.js +0 -233
  222. package/lib/core/ErrorFormatter.js +0 -445
  223. package/lib/core/JSONSchemaCore.js +0 -347
  224. package/lib/core/Locale.js +0 -130
  225. package/lib/core/MessageTemplate.js +0 -98
  226. package/lib/core/PluginManager.js +0 -448
  227. package/lib/core/StringExtensions.js +0 -240
  228. package/lib/core/Validator.js +0 -654
  229. package/lib/errors/I18nError.js +0 -328
  230. package/lib/errors/ValidationError.js +0 -191
  231. package/lib/exporters/MarkdownExporter.js +0 -420
  232. package/lib/exporters/MongoDBExporter.js +0 -162
  233. package/lib/exporters/MySQLExporter.js +0 -212
  234. package/lib/exporters/PostgreSQLExporter.js +0 -289
  235. package/lib/exporters/index.js +0 -24
  236. package/lib/locales/index.js +0 -8
  237. package/lib/utils/LRUCache.js +0 -174
  238. package/lib/utils/SchemaHelper.js +0 -240
  239. package/lib/utils/SchemaUtils.js +0 -445
  240. package/lib/utils/TypeConverter.js +0 -245
  241. package/lib/utils/index.js +0 -13
  242. package/lib/validators/CustomKeywords.js +0 -616
  243. package/lib/validators/index.js +0 -11
@@ -1,616 +0,0 @@
1
- /**
2
- * 自定义JSON Schema关键字
3
- *
4
- * 扩展ajv支持自定义验证关键字
5
- *
6
- * @module lib/validators/CustomKeywords
7
- * @version 1.0.0
8
- */
9
-
10
- const Locale = require('../core/Locale');
11
-
12
- /**
13
- * 自定义关键字集合
14
- * @class CustomKeywords
15
- */
16
- class CustomKeywords {
17
- /**
18
- * 注册所有自定义关键字到ajv实例
19
- * @static
20
- * @param {Ajv} ajv - ajv实例
21
- */
22
- static registerAll(ajv) {
23
- this.registerRegexKeyword(ajv);
24
- this.registerFunctionKeyword(ajv);
25
- this.registerRangeKeyword(ajv);
26
- this.registerCustomValidatorsKeyword(ajv);
27
- this.registerMetadataKeywords(ajv);
28
- // 新增验证器(v1.0.2)
29
- this.registerStringValidators(ajv);
30
- this.registerNumberValidators(ajv);
31
- this.registerObjectValidators(ajv);
32
- this.registerArrayValidators(ajv);
33
- this.registerDateValidators(ajv);
34
- }
35
-
36
- /**
37
- * 注册元数据关键字(_label, _customMessages等)
38
- * @static
39
- * @param {Ajv} ajv - ajv实例
40
- */
41
- static registerMetadataKeywords(ajv) {
42
- // _label: 字段标签
43
- ajv.addKeyword({
44
- keyword: '_label',
45
- metaSchema: { type: 'string' }
46
- });
47
-
48
- // _customMessages: 自定义错误消息
49
- ajv.addKeyword({
50
- keyword: '_customMessages',
51
- metaSchema: { type: 'object' }
52
- });
53
-
54
- // _description: 描述
55
- ajv.addKeyword({
56
- keyword: '_description',
57
- metaSchema: { type: 'string' }
58
- });
59
-
60
- // _whenConditions: 条件验证
61
- ajv.addKeyword({
62
- keyword: '_whenConditions',
63
- metaSchema: { type: 'array' }
64
- });
65
-
66
- // _required: 内部使用的必填标记
67
- ajv.addKeyword({
68
- keyword: '_required',
69
- metaSchema: { type: 'boolean' }
70
- });
71
- }
72
-
73
- /**
74
- * 注册 _customValidators 关键字(SchemaIO 内部使用)
75
- * @static
76
- * @param {Ajv} ajv - ajv实例
77
- */
78
- static registerCustomValidatorsKeyword(ajv) {
79
- ajv.addKeyword({
80
- keyword: '_customValidators',
81
- validate: function validate(validators, data) {
82
- if (!Array.isArray(validators)) return true;
83
-
84
- for (const validator of validators) {
85
- try {
86
- const result = validator(data);
87
-
88
- // 处理 Promise (异步验证)
89
- if (result instanceof Promise) {
90
- // ajv 默认不支持同步验证中的异步操作
91
- // 这里我们只能抛出错误提示
92
- // 真正的异步支持需要 Validator.validateAsync
93
- const messageConfig = Locale.getMessage('ASYNC_VALIDATION_NOT_SUPPORTED');
94
- const errorMessage = typeof messageConfig === 'object' && messageConfig.message
95
- ? messageConfig.message
96
- : messageConfig;
97
- throw new Error(errorMessage);
98
- }
99
-
100
- // 处理返回值
101
- if (result === false) {
102
- const messageConfig = Locale.getMessage('CUSTOM_VALIDATION_FAILED');
103
- const errorMessage = typeof messageConfig === 'object' && messageConfig.message
104
- ? messageConfig.message
105
- : messageConfig;
106
- validate.errors = [{ message: errorMessage }];
107
- return false;
108
- }
109
- if (typeof result === 'string') {
110
- validate.errors = [{ message: result }];
111
- return false;
112
- }
113
- if (result && typeof result === 'object' && result.error) {
114
- validate.errors = [{ message: result.message || Locale.getMessage('CUSTOM_VALIDATION_FAILED') }];
115
- return false;
116
- }
117
- } catch (error) {
118
- validate.errors = [{ message: error.message }];
119
- return false;
120
- }
121
- }
122
- return true;
123
- },
124
- errors: true
125
- });
126
- }
127
-
128
- /**
129
- * 注册regex关键字(正则验证)
130
- * @static
131
- * @param {Ajv} ajv - ajv实例
132
- */
133
- static registerRegexKeyword(ajv) {
134
- ajv.addKeyword({
135
- keyword: 'regex',
136
- type: 'string',
137
- schemaType: 'string',
138
- validate: function validate(schema, data) {
139
- try {
140
- const regex = new RegExp(schema);
141
- return regex.test(data);
142
- } catch (error) {
143
- validate.errors = [{ message: `Invalid regex: ${error.message}` }];
144
- return false;
145
- }
146
- },
147
- errors: true
148
- });
149
- }
150
-
151
- /**
152
- * 注册function关键字(自定义函数验证)
153
- * @static
154
- * @param {Ajv} ajv - ajv实例
155
- */
156
- static registerFunctionKeyword(ajv) {
157
- ajv.addKeyword({
158
- keyword: 'validate',
159
- validate: function validate(schema, data) {
160
- if (typeof schema !== 'function') {
161
- validate.errors = [{ message: Locale.getMessage('VALIDATE_MUST_BE_FUNCTION') }];
162
- return false;
163
- }
164
-
165
- try {
166
- const result = schema(data);
167
- if (typeof result === 'boolean') {
168
- return result;
169
- }
170
- if (result && typeof result.valid === 'boolean') {
171
- if (!result.valid && result.message) {
172
- validate.errors = [{ message: result.message }];
173
- }
174
- return result.valid;
175
- }
176
- return true;
177
- } catch (error) {
178
- validate.errors = [{ message: error.message }];
179
- return false;
180
- }
181
- },
182
- errors: true
183
- });
184
- }
185
-
186
- /**
187
- * 注册range关键字(数值范围验证)
188
- * @static
189
- * @param {Ajv} ajv - ajv实例
190
- */
191
- static registerRangeKeyword(ajv) {
192
- ajv.addKeyword({
193
- keyword: 'range',
194
- type: 'number',
195
- schemaType: 'object',
196
- validate: function validate(schema, data) {
197
- const { min, max } = schema;
198
-
199
- if (min !== undefined && data < min) {
200
- validate.errors = [{ message: `must be >= ${min}` }];
201
- return false;
202
- }
203
-
204
- if (max !== undefined && data > max) {
205
- validate.errors = [{ message: `must be <= ${max}` }];
206
- return false;
207
- }
208
-
209
- return true;
210
- },
211
- errors: true
212
- });
213
- }
214
-
215
- /**
216
- * 注册 String 类型验证器(v1.0.2新增)
217
- * @static
218
- * @param {Ajv} ajv - ajv实例
219
- */
220
- static registerStringValidators(ajv) {
221
- // exactLength: 精确长度验证
222
- ajv.addKeyword({
223
- keyword: 'exactLength',
224
- type: 'string',
225
- schemaType: 'number',
226
- validate: function validate(schema, data) {
227
- if (data.length !== schema) {
228
- validate.errors = [{
229
- keyword: 'exactLength',
230
- message: `string.length`,
231
- params: { limit: schema }
232
- }];
233
- return false;
234
- }
235
- return true;
236
- },
237
- errors: true
238
- });
239
-
240
- // alphanum: 只能包含字母和数字
241
- ajv.addKeyword({
242
- keyword: 'alphanum',
243
- type: 'string',
244
- schemaType: 'boolean',
245
- validate: function validate(schema, data) {
246
- if (schema && !/^[a-zA-Z0-9]*$/.test(data)) {
247
- validate.errors = [{
248
- keyword: 'alphanum',
249
- message: 'string.alphanum',
250
- params: {}
251
- }];
252
- return false;
253
- }
254
- return true;
255
- },
256
- errors: true
257
- });
258
-
259
- // trim: 不能包含前后空格
260
- ajv.addKeyword({
261
- keyword: 'trim',
262
- type: 'string',
263
- schemaType: 'boolean',
264
- validate: function validate(schema, data) {
265
- if (schema && data !== data.trim()) {
266
- validate.errors = [{
267
- keyword: 'trim',
268
- message: 'string.trim',
269
- params: {}
270
- }];
271
- return false;
272
- }
273
- return true;
274
- },
275
- errors: true
276
- });
277
-
278
- // lowercase: 必须是小写
279
- ajv.addKeyword({
280
- keyword: 'lowercase',
281
- type: 'string',
282
- schemaType: 'boolean',
283
- validate: function validate(schema, data) {
284
- if (schema && data !== data.toLowerCase()) {
285
- validate.errors = [{
286
- keyword: 'lowercase',
287
- message: 'string.lowercase',
288
- params: {}
289
- }];
290
- return false;
291
- }
292
- return true;
293
- },
294
- errors: true
295
- });
296
-
297
- // uppercase: 必须是大写
298
- ajv.addKeyword({
299
- keyword: 'uppercase',
300
- type: 'string',
301
- schemaType: 'boolean',
302
- validate: function validate(schema, data) {
303
- if (schema && data !== data.toUpperCase()) {
304
- validate.errors = [{
305
- keyword: 'uppercase',
306
- message: 'string.uppercase',
307
- params: {}
308
- }];
309
- return false;
310
- }
311
- return true;
312
- },
313
- errors: true
314
- });
315
-
316
- // jsonString: JSON字符串验证
317
- ajv.addKeyword({
318
- keyword: 'jsonString',
319
- type: 'string',
320
- schemaType: 'boolean',
321
- validate: function validate(schema, data) {
322
- if (schema) {
323
- try {
324
- JSON.parse(data);
325
- return true;
326
- } catch (error) {
327
- validate.errors = [{
328
- keyword: 'jsonString',
329
- message: 'pattern.json',
330
- params: {}
331
- }];
332
- return false;
333
- }
334
- }
335
- return true;
336
- },
337
- errors: true
338
- });
339
- }
340
-
341
- /**
342
- * 注册 Number 类型验证器(v1.0.2新增)
343
- * @static
344
- * @param {Ajv} ajv - ajv实例
345
- */
346
- static registerNumberValidators(ajv) {
347
- // precision: 小数位数限制
348
- ajv.addKeyword({
349
- keyword: 'precision',
350
- type: 'number',
351
- schemaType: 'number',
352
- validate: function validate(schema, data) {
353
- const decimalPart = String(data).split('.')[1];
354
- const actualPrecision = decimalPart ? decimalPart.length : 0;
355
-
356
- if (actualPrecision > schema) {
357
- validate.errors = [{
358
- keyword: 'precision',
359
- message: 'number.precision',
360
- params: { limit: schema }
361
- }];
362
- return false;
363
- }
364
- return true;
365
- },
366
- errors: true
367
- });
368
-
369
- // port: 端口号验证 (1-65535)
370
- ajv.addKeyword({
371
- keyword: 'port',
372
- type: ['integer', 'number'],
373
- schemaType: 'boolean',
374
- validate: function validate(schema, data) {
375
- if (schema && (data < 1 || data > 65535 || !Number.isInteger(data))) {
376
- validate.errors = [{
377
- keyword: 'port',
378
- message: 'number.port',
379
- params: {}
380
- }];
381
- return false;
382
- }
383
- return true;
384
- },
385
- errors: true
386
- });
387
- }
388
-
389
- /**
390
- * 注册 Object 类型验证器(v1.0.2新增)
391
- * @static
392
- * @param {Ajv} ajv - ajv实例
393
- */
394
- static registerObjectValidators(ajv) {
395
- // requiredAll: 要求所有定义的属性都必须存在
396
- ajv.addKeyword({
397
- keyword: 'requiredAll',
398
- type: 'object',
399
- schemaType: 'boolean',
400
- validate: function validate(schema, data, parentSchema) {
401
- if (!schema) return true;
402
-
403
- const properties = parentSchema.properties;
404
- if (!properties) return true;
405
-
406
- const missingKeys = Object.keys(properties).filter(key => !(key in data));
407
-
408
- if (missingKeys.length > 0) {
409
- validate.errors = [{
410
- keyword: 'requiredAll',
411
- message: 'object.missing',
412
- params: { missing: missingKeys }
413
- }];
414
- return false;
415
- }
416
- return true;
417
- },
418
- errors: true
419
- });
420
-
421
- // strictSchema: 严格模式,不允许额外属性
422
- ajv.addKeyword({
423
- keyword: 'strictSchema',
424
- type: 'object',
425
- schemaType: 'boolean',
426
- validate: function validate(schema, data, parentSchema) {
427
- if (!schema) return true;
428
-
429
- const properties = parentSchema.properties || {};
430
- const allowedKeys = Object.keys(properties);
431
- const extraKeys = Object.keys(data).filter(key => !allowedKeys.includes(key));
432
-
433
- if (extraKeys.length > 0) {
434
- validate.errors = [{
435
- keyword: 'strictSchema',
436
- message: 'object.schema',
437
- params: { extra: extraKeys }
438
- }];
439
- return false;
440
- }
441
- return true;
442
- },
443
- errors: true
444
- });
445
- }
446
-
447
- /**
448
- * 注册 Array 类型验证器(v1.0.2新增)
449
- * @static
450
- * @param {Ajv} ajv - ajv实例
451
- */
452
- static registerArrayValidators(ajv) {
453
- // noSparse: 不允许稀疏数组(undefined元素)
454
- ajv.addKeyword({
455
- keyword: 'noSparse',
456
- type: 'array',
457
- schemaType: 'boolean',
458
- validate: function validate(schema, data) {
459
- if (schema) {
460
- for (let i = 0; i < data.length; i++) {
461
- if (!(i in data)) {
462
- validate.errors = [{
463
- keyword: 'noSparse',
464
- message: 'array.sparse',
465
- params: { index: i }
466
- }];
467
- return false;
468
- }
469
- }
470
- }
471
- return true;
472
- },
473
- errors: true
474
- });
475
-
476
- // includesRequired: 必须包含指定的元素
477
- ajv.addKeyword({
478
- keyword: 'includesRequired',
479
- type: 'array',
480
- schemaType: 'array',
481
- validate: function validate(schema, data) {
482
- if (!Array.isArray(schema) || schema.length === 0) return true;
483
-
484
- const missing = schema.filter(required => {
485
- return !data.some(item => {
486
- if (typeof required === 'object' && required !== null) {
487
- return JSON.stringify(item) === JSON.stringify(required);
488
- }
489
- return item === required;
490
- });
491
- });
492
-
493
- if (missing.length > 0) {
494
- validate.errors = [{
495
- keyword: 'includesRequired',
496
- message: 'array.includesRequired',
497
- params: { missing }
498
- }];
499
- return false;
500
- }
501
- return true;
502
- },
503
- errors: true
504
- });
505
- }
506
-
507
- /**
508
- * 注册 Date 类型验证器(v1.0.2新增)
509
- * @static
510
- * @param {Ajv} ajv - ajv实例
511
- */
512
- static registerDateValidators(ajv) {
513
- // dateFormat: 自定义日期格式验证
514
- ajv.addKeyword({
515
- keyword: 'dateFormat',
516
- type: 'string',
517
- schemaType: 'string',
518
- validate: function validate(schema, data) {
519
- // 支持常见格式: YYYY-MM-DD, YYYY/MM/DD, DD-MM-YYYY, DD/MM/YYYY
520
- const formats = {
521
- 'YYYY-MM-DD': /^\d{4}-\d{2}-\d{2}$/,
522
- 'YYYY/MM/DD': /^\d{4}\/\d{2}\/\d{2}$/,
523
- 'DD-MM-YYYY': /^\d{2}-\d{2}-\d{4}$/,
524
- 'DD/MM/YYYY': /^\d{2}\/\d{2}\/\d{4}$/,
525
- 'ISO8601': /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/
526
- };
527
-
528
- const pattern = formats[schema];
529
- if (!pattern) {
530
- validate.errors = [{
531
- keyword: 'dateFormat',
532
- message: 'date.format',
533
- params: { format: schema }
534
- }];
535
- return false;
536
- }
537
-
538
- if (!pattern.test(data)) {
539
- validate.errors = [{
540
- keyword: 'dateFormat',
541
- message: 'date.format',
542
- params: { format: schema }
543
- }];
544
- return false;
545
- }
546
- return true;
547
- },
548
- errors: true
549
- });
550
-
551
- // dateGreater: 日期必须大于指定日期
552
- ajv.addKeyword({
553
- keyword: 'dateGreater',
554
- type: 'string',
555
- schemaType: 'string',
556
- validate: function validate(schema, data) {
557
- const dataDate = new Date(data);
558
- const compareDate = new Date(schema);
559
-
560
- if (isNaN(dataDate.getTime()) || isNaN(compareDate.getTime())) {
561
- validate.errors = [{
562
- keyword: 'dateGreater',
563
- message: 'date.greater',
564
- params: { limit: schema }
565
- }];
566
- return false;
567
- }
568
-
569
- if (dataDate <= compareDate) {
570
- validate.errors = [{
571
- keyword: 'dateGreater',
572
- message: 'date.greater',
573
- params: { limit: schema }
574
- }];
575
- return false;
576
- }
577
- return true;
578
- },
579
- errors: true
580
- });
581
-
582
- // dateLess: 日期必须小于指定日期
583
- ajv.addKeyword({
584
- keyword: 'dateLess',
585
- type: 'string',
586
- schemaType: 'string',
587
- validate: function validate(schema, data) {
588
- const dataDate = new Date(data);
589
- const compareDate = new Date(schema);
590
-
591
- if (isNaN(dataDate.getTime()) || isNaN(compareDate.getTime())) {
592
- validate.errors = [{
593
- keyword: 'dateLess',
594
- message: 'date.less',
595
- params: { limit: schema }
596
- }];
597
- return false;
598
- }
599
-
600
- if (dataDate >= compareDate) {
601
- validate.errors = [{
602
- keyword: 'dateLess',
603
- message: 'date.less',
604
- params: { limit: schema }
605
- }];
606
- return false;
607
- }
608
- return true;
609
- },
610
- errors: true
611
- });
612
- }
613
- }
614
-
615
- module.exports = CustomKeywords;
616
-
@@ -1,11 +0,0 @@
1
- /**
2
- * Validators - 验证器统一导出
3
- * @module lib/validators
4
- */
5
-
6
- const CustomKeywords = require('./CustomKeywords');
7
-
8
- module.exports = {
9
- CustomKeywords
10
- };
11
-