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,177 +1,160 @@
1
- module.exports = {
2
- // Generic
3
- required: '{{#label}}不能为空',
4
- type: '{{#label}}应该是 {{#expected}} 类型',
5
- min: '{{#label}}长度不能少于{{#limit}}个字符',
6
- max: '{{#label}}长度不能超过{{#limit}}个字符',
7
- length: '{{#label}}长度必须是{{#limit}}个字符',
8
- pattern: '{{#label}}格式不正确',
9
- enum: '{{#label}}必须是以下值之一: {{#allowed}}',
10
- custom: '{{#label}}验证失败: {{#message}}',
11
- circular: '{{#label}}检测到循环引用',
12
- 'max-depth': '超过最大递归深度 ({{#depth}}) at {{#label}}',
13
- exception: '{{#label}}验证异常: {{#message}}',
14
-
15
- // Conditional (ConditionalBuilder)
16
- 'conditional.underAge': '未成年用户不能注册',
17
- 'conditional.blocked': '账号已被封禁',
18
- 'conditional.notAllowed': '不允许注册',
19
-
20
- // I18nError - 通用错误消息 (v1.1.1)
21
- // I18nError - 通用错误消息 (v1.1.1)
22
- 'error.notFound': '找不到{{#resource}}',
23
- 'error.forbidden': '没有权限访问{{#resource}}',
24
- 'error.unauthorized': '未授权,请先登录',
25
- 'error.invalid': '{{#field}}无效',
26
- 'error.duplicate': '{{#resource}}已存在',
27
- 'error.conflict': '操作冲突: {{#reason}}',
28
-
29
- // I18nError - 账户相关 (v1.1.1)
30
- // v1.1.5: 部分使用对象格式示例
31
- 'account.notFound': {
32
- code: 'ACCOUNT_NOT_FOUND',
33
- message: '账户不存在'
34
- },
35
- 'account.inactive': '账户未激活',
36
- 'account.banned': '账户已被封禁',
37
- 'account.insufficientBalance': {
38
- code: 'INSUFFICIENT_BALANCE',
39
- message: '余额不足,当前余额{{#balance}},需要{{#required}}'
40
- },
41
- 'account.insufficientCredits': '积分不足,当前积分{{#credits}},需要{{#required}}',
42
-
43
- // I18nError - 用户相关 (v1.1.1)
44
- 'user.notFound': '用户不存在',
45
- 'user.notVerified': '用户未验证',
46
- 'user.noPermission': '没有管理员权限',
47
-
48
- // I18nError - 订单相关 (v1.1.1)
49
- 'order.notPaid': {
50
- code: 'ORDER_NOT_PAID',
51
- message: '订单未支付'
52
- },
53
- 'order.paymentMissing': '缺少支付信息',
54
- 'order.addressMissing': '缺少收货地址',
55
-
56
- // Formats
57
- 'format.email': '{{#label}}必须是有效的邮箱地址',
58
- 'format.url': '{{#label}}必须是有效的URL地址',
59
- 'format.uuid': '{{#label}}必须是有效的UUID',
60
- 'format.date': '{{#label}}必须是有效的日期格式 (YYYY-MM-DD)',
61
- 'format.datetime': '{{#label}}必须是有效的日期时间格式 (ISO 8601)',
62
- 'format.time': '{{#label}}必须是有效的时间格式 (HH:mm:ss)',
63
- 'format.ipv4': '{{#label}}必须是有效的IPv4地址',
64
- 'format.ipv6': '{{#label}}必须是有效的IPv6地址',
65
- 'format.binary': '{{#label}}必须是有效的Base64编码',
66
-
67
- // String
68
- 'string.hostname': '{{#label}}必须是有效的主机名',
69
- 'string.pattern': '{{#label}}格式不符合要求',
70
- 'string.enum': '{{#label}}必须是以下值之一: {{#valids}}',
71
- // v1.0.2新增
72
- 'string.length': '{{#label}}长度必须是{{#limit}}个字符',
73
- 'string.alphanum': '{{#label}}只能包含字母和数字',
74
- 'string.trim': '{{#label}}不能包含前后空格',
75
- 'string.lowercase': '{{#label}}必须是小写',
76
- 'string.uppercase': '{{#label}}必须是大写',
77
-
78
- // Number
79
- 'number.base': '{{#label}}必须是数字类型',
80
- 'number.min': '{{#label}}不能小于{{#limit}}',
81
- 'number.max': '{{#label}}不能大于{{#limit}}',
82
- 'number.integer': '{{#label}}必须是整数',
83
- 'number.positive': '{{#label}}必须是正数',
84
- 'number.negative': '{{#label}}必须是负数',
85
- // v1.0.2新增
86
- 'number.precision': '{{#label}}小数位数不能超过{{#limit}}',
87
- 'number.port': '{{#label}}必须是有效的端口号(1-65535)',
88
-
89
- // Boolean
90
- 'boolean.base': '{{#label}}必须是布尔类型',
91
-
92
- // Object
93
- 'object.base': '{{#label}}必须是对象类型',
94
- 'object.min': '{{#label}}至少需要{{#limit}}个属性',
95
- 'object.max': '{{#label}}最多只能有{{#limit}}个属性',
96
- 'object.unknown': '{{#label}}包含未知属性: {{#key}}',
97
- // v1.0.2新增
98
- 'object.missing': '{{#label}}缺少必需属性',
99
- 'object.schema': '{{#label}}包含额外属性',
100
- // v1.1.6新增 - additionalProperties
101
- 'additionalProperties': '{{#label}}不允许有额外属性: {{#key}}',
102
-
103
- // Array
104
- 'array.base': '{{#label}}必须是数组类型',
105
- 'array.min': '{{#label}}至少需要{{#limit}}个元素',
106
- 'array.max': '{{#label}}最多只能有{{#limit}}个元素',
107
- 'array.length': '{{#label}}必须有{{#limit}}个元素',
108
- 'array.unique': '{{#label}}不能包含重复元素',
109
- // v1.0.2新增
110
- 'array.sparse': '{{#label}}不能是稀疏数组',
111
- 'array.includesRequired': '{{#label}}必须包含指定元素',
112
-
113
- // Date
114
- 'date.base': '{{#label}}必须是有效的日期',
115
- 'date.min': '{{#label}}不能早于{{#limit}}',
116
- 'date.max': '{{#label}}不能晚于{{#limit}}',
117
- // v1.0.2新增
118
- 'date.format': '{{#label}}日期格式不正确',
119
- 'date.greater': '{{#label}}必须晚于{{#limit}}',
120
- 'date.less': '{{#label}}必须早于{{#limit}}',
121
-
122
- // Any
123
- 'any.required': '{{#label}}是必填项',
124
- 'any.invalid': '{{#label}}包含无效值',
125
- 'any.only': '{{#label}}必须匹配{{#valids}}',
126
- 'any.unknown': '不允许字段{{#key}}',
127
-
128
- // Patterns (Legacy/Specific)
129
- 'pattern.phone': '请输入有效的手机号',
130
- 'pattern.phone.international': '请输入有效的国际手机号',
131
- 'pattern.idCard': '请输入有效的身份证号码',
132
- 'pattern.creditCard': '无效的信用卡号',
133
- 'pattern.creditCard.visa': '无效的Visa卡号',
134
- 'pattern.creditCard.mastercard': '无效的万事达卡号',
135
- 'pattern.creditCard.amex': '无效的美国运通卡号',
136
- 'pattern.creditCard.discover': '无效的Discover卡号',
137
- 'pattern.creditCard.jcb': '无效的JCB卡号',
138
- 'pattern.creditCard.unionpay': '无效的银联卡号',
139
- 'pattern.licensePlate': '请输入有效的车牌号',
140
- 'pattern.postalCode': '请输入有效的邮政编码',
141
- 'pattern.passport': '请输入有效的护照号码',
142
- 'pattern.objectId': '无效的 ObjectId',
143
- 'pattern.hexColor': '无效的十六进制颜色值',
144
- 'pattern.macAddress': '无效的 MAC 地址',
145
- 'pattern.cron': '无效的 Cron 表达式',
146
- 'pattern.slug': 'URL别名只能包含小写字母、数字和连字符',
147
- // v1.0.2新增
148
- 'pattern.domain': '{{#label}}必须是有效的域名',
149
- 'pattern.ip': '{{#label}}必须是有效的IP地址',
150
- 'pattern.base64': '{{#label}}必须是有效的Base64编码',
151
- 'pattern.jwt': '{{#label}}必须是有效的JWT令牌',
152
- 'pattern.json': '{{#label}}必须是有效的JSON字符串',
153
-
154
- // Username & Password
155
- 'pattern.username': '用户名必须以字母开头,只能包含字母、数字和下划线',
156
- 'pattern.password.weak': '密码至少6位',
157
- 'pattern.password.medium': '密码至少8位,需包含字母和数字',
158
- 'pattern.password.strong': '密码至少8位,需包含大小写字母和数字',
159
- 'pattern.password.veryStrong': '密码至少10位,需包含大小写字母、数字和特殊字符',
160
-
161
- // Union Type (联合类型)
162
- 'pattern.emailOrPhone': '必须是邮箱或手机号',
163
- 'pattern.usernameOrEmail': '必须是用户名或邮箱',
164
- 'pattern.httpOrHttps': '必须是 http 或 https 开头的 URL',
165
-
166
- // oneOf (跨类型联合) - v1.1.0 新增
167
- oneOf: '{{#label}}必须匹配以下类型之一',
168
- 'oneOf.invalid': '{{#label}}的值不匹配任何允许的类型',
169
-
170
- // Unknown error fallback
171
- 'UNKNOWN_ERROR': '未知的验证错误',
172
-
173
- // Custom validation
174
- 'CUSTOM_VALIDATION_FAILED': '自定义验证失败',
175
- 'ASYNC_VALIDATION_NOT_SUPPORTED': '同步验证不支持异步操作',
176
- 'VALIDATE_MUST_BE_FUNCTION': 'validate 必须是一个函数'
177
- };
1
+ import type { LocaleMessages } from './types.js'
2
+
3
+ const zhCN: LocaleMessages = {
4
+ // Generic
5
+ required: '{{#label}}不能为空',
6
+ type: '{{#label}}应该是 {{#expected}} 类型',
7
+ min: '{{#label}}长度不能少于{{#limit}}个字符',
8
+ max: '{{#label}}长度不能超过{{#limit}}个字符',
9
+ length: '{{#label}}长度必须是{{#limit}}个字符',
10
+ pattern: '{{#label}}格式不正确',
11
+ enum: '{{#label}}必须是以下值之一: {{#allowed}}',
12
+ custom: '{{#label}}验证失败: {{#message}}',
13
+ circular: '{{#label}}检测到循环引用',
14
+ 'max-depth': '超过最大递归深度 ({{#depth}}) at {{#label}}',
15
+ exception: '{{#label}}验证异常: {{#message}}',
16
+
17
+ // Conditional
18
+ 'conditional.underAge': '未成年用户不能注册',
19
+ 'conditional.blocked': '账号已被封禁',
20
+ 'conditional.notAllowed': '不允许注册',
21
+
22
+ // I18nError — generic
23
+ 'error.notFound': '找不到{{#resource}}',
24
+ 'error.forbidden': '没有权限访问{{#resource}}',
25
+ 'error.unauthorized': '未授权,请先登录',
26
+ 'error.invalid': '{{#field}}无效',
27
+ 'error.duplicate': '{{#resource}}已存在',
28
+ 'error.conflict': '操作冲突: {{#reason}}',
29
+
30
+ // Account
31
+ 'account.notFound': { code: 'ACCOUNT_NOT_FOUND', message: '账户不存在' },
32
+ 'account.inactive': '账户未激活',
33
+ 'account.banned': '账户已被封禁',
34
+ 'account.insufficientBalance': {
35
+ code: 'INSUFFICIENT_BALANCE',
36
+ message: '余额不足,当前余额{{#balance}},需要{{#required}}',
37
+ },
38
+ 'account.insufficientCredits': '积分不足,当前积分{{#credits}},需要{{#required}}',
39
+
40
+ // User
41
+ 'user.notFound': '用户不存在',
42
+ 'user.notVerified': '用户未验证',
43
+ 'user.noPermission': '没有管理员权限',
44
+
45
+ // Order
46
+ 'order.notPaid': { code: 'ORDER_NOT_PAID', message: '订单未支付' },
47
+ 'order.paymentMissing': '缺少支付信息',
48
+ 'order.addressMissing': '缺少收货地址',
49
+
50
+ // Format
51
+ 'format.email': '{{#label}}必须是有效的邮箱地址',
52
+ 'format.url': '{{#label}}必须是有效的URL地址',
53
+ 'format.uuid': '{{#label}}必须是有效的UUID',
54
+ 'format.date': '{{#label}}必须是有效的日期格式 (YYYY-MM-DD)',
55
+ 'format.datetime': '{{#label}}必须是有效的日期时间格式 (ISO 8601)',
56
+ 'format.time': '{{#label}}必须是有效的时间格式 (HH:mm:ss)',
57
+ 'format.ipv4': '{{#label}}必须是有效的IPv4地址',
58
+ 'format.ipv6': '{{#label}}必须是有效的IPv6地址',
59
+ 'format.binary': '{{#label}}必须是有效的Base64编码',
60
+
61
+ // String
62
+ 'string.hostname': '{{#label}}必须是有效的主机名',
63
+ 'string.pattern': '{{#label}}格式不符合要求',
64
+ 'string.enum': '{{#label}}必须是以下值之一: {{#valids}}',
65
+ 'string.length': '{{#label}}长度必须是{{#limit}}个字符',
66
+ 'string.alphanum': '{{#label}}只能包含字母和数字',
67
+ 'string.trim': '{{#label}}不能包含前后空格',
68
+ 'string.lowercase': '{{#label}}必须是小写',
69
+ 'string.uppercase': '{{#label}}必须是大写',
70
+
71
+ // Number
72
+ 'number.base': '{{#label}}必须是数字类型',
73
+ 'number.min': '{{#label}}不能小于{{#limit}}',
74
+ 'number.max': '{{#label}}不能大于{{#limit}}',
75
+ 'number.integer': '{{#label}}必须是整数',
76
+ 'number.positive': '{{#label}}必须是正数',
77
+ 'number.negative': '{{#label}}必须是负数',
78
+ 'number.precision': '{{#label}}小数位数不能超过{{#limit}}位',
79
+ 'number.port': '{{#label}}必须是有效的端口号(1-65535)',
80
+
81
+ // Boolean
82
+ 'boolean.base': '{{#label}}必须是布尔类型',
83
+
84
+ // Object
85
+ 'object.base': '{{#label}}必须是对象类型',
86
+ 'object.min': '{{#label}}至少需要{{#limit}}个属性',
87
+ 'object.max': '{{#label}}最多只能有{{#limit}}个属性',
88
+ 'object.unknown': '{{#label}}包含未知属性: {{#key}}',
89
+ 'object.missing': '{{#label}}缺少必需属性',
90
+ 'object.schema': '{{#label}}包含额外属性',
91
+ 'additionalProperties': '{{#label}}不允许有额外属性: {{#key}}',
92
+
93
+ // Array
94
+ 'array.base': '{{#label}}必须是数组类型',
95
+ 'array.min': '{{#label}}至少需要{{#limit}}个元素',
96
+ 'array.max': '{{#label}}最多只能有{{#limit}}个元素',
97
+ 'array.length': '{{#label}}必须有{{#limit}}个元素',
98
+ 'array.unique': '{{#label}}不能包含重复元素',
99
+ 'array.sparse': '{{#label}}不能是稀疏数组',
100
+ 'array.includesRequired': '{{#label}}必须包含指定元素',
101
+
102
+ // Date
103
+ 'date.base': '{{#label}}必须是有效的日期',
104
+ 'date.min': '{{#label}}不能早于{{#limit}}',
105
+ 'date.max': '{{#label}}不能晚于{{#limit}}',
106
+ 'date.format': '{{#label}}日期格式不正确',
107
+ 'date.greater': '{{#label}}必须晚于{{#limit}}',
108
+ 'date.less': '{{#label}}必须早于{{#limit}}',
109
+
110
+ // Any
111
+ 'any.required': '{{#label}}是必填项',
112
+ 'any.invalid': '{{#label}}包含无效值',
113
+ 'any.only': '{{#label}}必须匹配{{#valids}}',
114
+ 'any.unknown': '不允许字段{{#key}}',
115
+
116
+ // Patterns
117
+ 'pattern.phone': '请输入有效的手机号',
118
+ 'pattern.phone.international': '请输入有效的国际手机号',
119
+ 'pattern.idCard': '请输入有效的身份证号码',
120
+ 'pattern.creditCard': '无效的信用卡号',
121
+ 'pattern.creditCard.visa': '无效的Visa卡号',
122
+ 'pattern.creditCard.mastercard': '无效的万事达卡号',
123
+ 'pattern.creditCard.amex': '无效的美国运通卡号',
124
+ 'pattern.creditCard.discover': '无效的Discover卡号',
125
+ 'pattern.creditCard.jcb': '无效的JCB卡号',
126
+ 'pattern.creditCard.unionpay': '无效的银联卡号',
127
+ 'pattern.licensePlate': '请输入有效的车牌号',
128
+ 'pattern.postalCode': '请输入有效的邮政编码',
129
+ 'pattern.passport': '请输入有效的护照号码',
130
+ 'pattern.objectId': '无效的 ObjectId',
131
+ 'pattern.hexColor': '无效的十六进制颜色值',
132
+ 'pattern.macAddress': '无效的 MAC 地址',
133
+ 'pattern.cron': '无效的 Cron 表达式',
134
+ 'pattern.slug': 'URL别名只能包含小写字母、数字和连字符',
135
+ 'pattern.domain': '{{#label}}必须是有效的域名',
136
+ 'pattern.ip': '{{#label}}必须是有效的IP地址',
137
+ 'pattern.base64': '{{#label}}必须是有效的Base64编码',
138
+ 'pattern.jwt': '{{#label}}必须是有效的JWT令牌',
139
+ 'pattern.json': '{{#label}}必须是有效的JSON字符串',
140
+ 'pattern.username': '用户名必须以字母开头,只能包含字母、数字和下划线',
141
+ 'pattern.password.weak': '密码至少6位',
142
+ 'pattern.password.medium': '密码至少8位,需包含字母和数字',
143
+ 'pattern.password.strong': '密码至少8位,需包含大小写字母和数字',
144
+ 'pattern.password.veryStrong': '密码至少10位,需包含大小写字母、数字和特殊字符',
145
+ 'pattern.emailOrPhone': '必须是邮箱或手机号',
146
+ 'pattern.usernameOrEmail': '必须是用户名或邮箱',
147
+ 'pattern.httpOrHttps': '必须是 http 或 https 开头的 URL',
148
+
149
+ // oneOf
150
+ oneOf: '{{#label}}必须匹配以下类型之一',
151
+ 'oneOf.invalid': '{{#label}}的值不匹配任何允许的类型',
152
+
153
+ // Error fallback
154
+ UNKNOWN_ERROR: '未知的验证错误',
155
+ CUSTOM_VALIDATION_FAILED: '自定义验证失败',
156
+ ASYNC_VALIDATION_NOT_SUPPORTED: '同步验证不支持异步操作',
157
+ VALIDATE_MUST_BE_FUNCTION: 'validate 必须是一个函数',
158
+ }
159
+
160
+ export default zhCN
@@ -0,0 +1,101 @@
1
+ import type { JSONSchema } from '../types/schema.js'
2
+
3
+ /**
4
+ * ConstraintParser — parses DSL constraint strings into Partial<JSONSchema>
5
+ *
6
+ * Fixes:
7
+ * DA-03 string:N semantic divergence → always returns exactLength:N (not minLength+maxLength)
8
+ * DB-03 negative range support → regex updated to /^(-?\d*\.?\d*)-(-?\d*\.?\d*)$/
9
+ *
10
+ * Return type is always Partial<JSONSchema>; never returns a raw string (v1 bug)
11
+ */
12
+ export const ConstraintParser = {
13
+ /**
14
+ * Parse a constraint string
15
+ * @param constraintStr - The constraint portion (type name and '!' already stripped)
16
+ * @param baseType - Base type name ('string' | 'number' | 'integer' | 'array' | ...)
17
+ * @returns Partial<JSONSchema>; returns {} when unparseable (avoids polluting the target schema)
18
+ */
19
+ parse(constraintStr: string, baseType: string): Partial<JSONSchema> {
20
+ if (!constraintStr) return {}
21
+
22
+ const s = constraintStr.trim()
23
+ if (!s) return {}
24
+
25
+ // ========== 1. Comparison operators (number/integer only, highest priority) ==========
26
+ if (baseType === 'number' || baseType === 'integer') {
27
+ // >= : greater than or equal (supports negative and decimal)
28
+ const gteMatch = /^>=(-?\d+(?:\.\d+)?)$/.exec(s)
29
+ if (gteMatch) return { minimum: parseFloat(gteMatch[1]) }
30
+
31
+ // <= : less than or equal
32
+ const lteMatch = /^<=(-?\d+(?:\.\d+)?)$/.exec(s)
33
+ if (lteMatch) return { maximum: parseFloat(lteMatch[1]) }
34
+
35
+ // > : greater than
36
+ const gtMatch = /^>(-?\d+(?:\.\d+)?)$/.exec(s)
37
+ if (gtMatch) return { exclusiveMinimum: parseFloat(gtMatch[1]) }
38
+
39
+ // < : less than
40
+ const ltMatch = /^<(-?\d+(?:\.\d+)?)$/.exec(s)
41
+ if (ltMatch) return { exclusiveMaximum: parseFloat(ltMatch[1]) }
42
+
43
+ // = : exact equal
44
+ const eqMatch = /^=(-?\d+(?:\.\d+)?)$/.exec(s)
45
+ if (eqMatch) return { enum: [parseFloat(eqMatch[1])] }
46
+ }
47
+
48
+ // ========== 2. Enum (x|y|z) ==========
49
+ // Only when '|' is present and it is not a pure numeric range
50
+ if (s.includes('|') && !/^-?\d*\.?\d*--?\d*\.?\d*$/.test(s)) {
51
+ return { enum: s.split('|').map(v => v.trim()) }
52
+ }
53
+
54
+ // ========== 3. Range constraint (supports negatives — fix DB-03) ==========
55
+ // Format: N-M, N-, -M (N/M may include a minus sign and decimal point)
56
+ // Regex: /^(-?\d*\.?\d*)-(-?\d*\.?\d*)$/
57
+ // Note: in "-M" format the value is treated as an upper bound (absolute value), not a negative lower bound
58
+ const rangeMatch = /^(-?\d*\.?\d*)-(-?\d*\.?\d*)$/.exec(s)
59
+ if (rangeMatch) {
60
+ const [, rawMin, rawMax] = rangeMatch
61
+ const result: Partial<JSONSchema> = {}
62
+
63
+ if (baseType === 'string') {
64
+ // string type: minLength / maxLength (integers, non-negative)
65
+ if (rawMin) result.minLength = Math.max(0, parseInt(rawMin, 10))
66
+ // "-M" format: take absolute value
67
+ if (rawMax) result.maxLength = Math.abs(parseInt(rawMax, 10))
68
+ } else if (baseType === 'array') {
69
+ if (rawMin) result.minItems = Math.max(0, parseInt(rawMin, 10))
70
+ if (rawMax) result.maxItems = Math.abs(parseInt(rawMax, 10))
71
+ } else {
72
+ // number / integer
73
+ if (rawMin) result.minimum = parseFloat(rawMin)
74
+ if (rawMax) result.maximum = parseFloat(rawMax)
75
+ }
76
+
77
+ return result
78
+ }
79
+
80
+ // ========== 4. Single-value constraint ==========
81
+ // Positive integer or decimal, no leading minus (negatives are handled by comparison operators above)
82
+ const singleMatch = /^(\d+(?:\.\d+)?)$/.exec(s)
83
+ if (singleMatch) {
84
+ const value = parseFloat(singleMatch[1])
85
+
86
+ if (baseType === 'string') {
87
+ // v1 compat: string:N → exactLength:N (exact length)
88
+ return { exactLength: Math.floor(value) }
89
+ } else if (baseType === 'array') {
90
+ return { maxItems: Math.floor(value) }
91
+ } else {
92
+ // number/integer single value = upper bound (maximum)
93
+ return { maximum: value }
94
+ }
95
+ }
96
+
97
+ // ========== 5. Unparseable: warn and return {} ==========
98
+ console.warn(`[schema-dsl] ConstraintParser: unrecognized constraint "${constraintStr}" for type "${baseType}" — ignored`)
99
+ return {}
100
+ },
101
+ }