schema-dsl 2.0.0 → 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 (145) hide show
  1. package/CHANGELOG.md +130 -113
  2. package/LICENSE +21 -21
  3. package/README.md +628 -628
  4. package/dist/{DslBuilder-DkLaOo9Q.d.ts → DslBuilder-BIgQOAXp.d.ts} +2 -0
  5. package/dist/{DslBuilder-DQDN0ZxZ.d.cts → DslBuilder-CjHTucNQ.d.cts} +2 -0
  6. package/dist/{Validator-hFWKGxir.d.ts → Validator-CllRdrY0.d.ts} +1 -1
  7. package/dist/{Validator-C7GsVQOH.d.cts → Validator-D6okG9tr.d.cts} +1 -1
  8. package/dist/index.cjs +75 -29
  9. package/dist/index.d.cts +10 -4
  10. package/dist/index.d.ts +10 -4
  11. package/dist/index.js +75 -29
  12. package/dist/plugins/custom-format.cjs +33 -17
  13. package/dist/plugins/custom-format.d.cts +1 -1
  14. package/dist/plugins/custom-format.d.ts +1 -1
  15. package/dist/plugins/custom-format.js +33 -17
  16. package/dist/plugins/custom-type-example.cjs +33 -17
  17. package/dist/plugins/custom-type-example.d.cts +1 -1
  18. package/dist/plugins/custom-type-example.d.ts +1 -1
  19. package/dist/plugins/custom-type-example.js +33 -17
  20. package/dist/plugins/custom-validator.cjs +0 -2
  21. package/dist/plugins/custom-validator.d.cts +1 -1
  22. package/dist/plugins/custom-validator.d.ts +1 -1
  23. package/dist/plugins/custom-validator.js +0 -2
  24. package/docs/FEATURE-INDEX.md +553 -553
  25. package/docs/add-custom-locale.md +496 -496
  26. package/docs/add-keyword.md +24 -24
  27. package/docs/api-reference.md +1047 -1047
  28. package/docs/api.md +13 -13
  29. package/docs/best-practices-project-structure.md +417 -417
  30. package/docs/best-practices.md +712 -712
  31. package/docs/cache-manager.md +344 -344
  32. package/docs/compile.md +45 -45
  33. package/docs/conditional-api.md +1307 -1307
  34. package/docs/custom-extensions-guide.md +339 -339
  35. package/docs/design-philosophy.md +606 -606
  36. package/docs/doc-index.md +324 -324
  37. package/docs/dsl-syntax.md +714 -714
  38. package/docs/dynamic-locale.md +608 -608
  39. package/docs/enum.md +482 -482
  40. package/docs/error-handling.md +1975 -1975
  41. package/docs/export-guide.md +501 -501
  42. package/docs/export-limitations.md +567 -567
  43. package/docs/faq.md +596 -596
  44. package/docs/frontend-i18n-guide.md +307 -307
  45. package/docs/i18n-user-guide.md +487 -487
  46. package/docs/i18n.md +476 -476
  47. package/docs/index.md +48 -48
  48. package/docs/json-schema-basics.md +40 -40
  49. package/docs/label-vs-description.md +271 -271
  50. package/docs/markdown-exporter.md +406 -406
  51. package/docs/mongodb-exporter.md +302 -302
  52. package/docs/multi-language.md +26 -26
  53. package/docs/multi-type-support.md +322 -322
  54. package/docs/mysql-exporter.md +280 -280
  55. package/docs/number-operators.md +449 -449
  56. package/docs/optional-marker-guide.md +326 -326
  57. package/docs/performance-guide.md +49 -49
  58. package/docs/plugin-system.md +381 -381
  59. package/docs/plugin-type-registration.md +34 -34
  60. package/docs/postgresql-exporter.md +311 -311
  61. package/docs/public/favicon.svg +4 -4
  62. package/docs/quick-start.md +435 -435
  63. package/docs/runtime-locale-support.md +532 -532
  64. package/docs/schema-helper.md +345 -345
  65. package/docs/schema-utils-advanced-issues.md +23 -23
  66. package/docs/schema-utils-best-practices.md +20 -20
  67. package/docs/schema-utils-chaining.md +150 -150
  68. package/docs/schema-utils.md +524 -524
  69. package/docs/security-checklist.md +20 -20
  70. package/docs/string-extensions.md +488 -488
  71. package/docs/troubleshooting.md +486 -486
  72. package/docs/type-converter.md +310 -310
  73. package/docs/type-reference.md +242 -242
  74. package/docs/typescript-guide.md +584 -584
  75. package/docs/union-type-guide.md +157 -157
  76. package/docs/union-types.md +284 -284
  77. package/docs/validate-async.md +491 -491
  78. package/docs/validate-batch.md +49 -49
  79. package/docs/validate-dsl-object-support.md +578 -578
  80. package/docs/validate.md +506 -506
  81. package/docs/validation-guide.md +502 -502
  82. package/docs/validator.md +39 -39
  83. package/package.json +131 -131
  84. package/plugins/custom-format.cjs +8 -8
  85. package/plugins/custom-type-example.cjs +8 -8
  86. package/plugins/custom-validator.cjs +8 -8
  87. package/src/adapters/DslAdapter.ts +111 -111
  88. package/src/adapters/index.ts +1 -1
  89. package/src/config/constants.ts +83 -83
  90. package/src/config/index.ts +2 -2
  91. package/src/config/patterns.ts +77 -77
  92. package/src/core/CacheManager.ts +169 -159
  93. package/src/core/ConditionalBuilder.ts +382 -382
  94. package/src/core/ConditionalRuntime.ts +27 -27
  95. package/src/core/ConditionalValidator.ts +254 -254
  96. package/src/core/DslBuilder.ts +687 -677
  97. package/src/core/ErrorCodes.ts +38 -38
  98. package/src/core/ErrorFormatter.ts +271 -271
  99. package/src/core/JSONSchemaCore.ts +65 -65
  100. package/src/core/Locale.ts +187 -187
  101. package/src/core/MessageTemplate.ts +42 -42
  102. package/src/core/ObjectDslBuilder.ts +64 -64
  103. package/src/core/PluginManager.ts +326 -326
  104. package/src/core/StringExtensions.ts +140 -140
  105. package/src/core/TemplateEngine.ts +44 -44
  106. package/src/core/Validator.ts +448 -448
  107. package/src/errors/I18nError.ts +159 -159
  108. package/src/errors/ValidationError.ts +105 -105
  109. package/src/exporters/BaseExporter.ts +60 -60
  110. package/src/exporters/MarkdownExporter.ts +305 -305
  111. package/src/exporters/MongoDBExporter.ts +126 -126
  112. package/src/exporters/MySQLExporter.ts +156 -155
  113. package/src/exporters/PostgreSQLExporter.ts +222 -222
  114. package/src/exporters/index.ts +18 -18
  115. package/src/index.ts +651 -633
  116. package/src/locales/en-US.ts +160 -160
  117. package/src/locales/es-ES.ts +160 -160
  118. package/src/locales/fr-FR.ts +160 -160
  119. package/src/locales/index.ts +103 -103
  120. package/src/locales/ja-JP.ts +160 -160
  121. package/src/locales/types.ts +156 -156
  122. package/src/locales/zh-CN.ts +160 -160
  123. package/src/parser/ConstraintParser.ts +101 -101
  124. package/src/parser/DslParser.ts +470 -470
  125. package/src/parser/SchemaCompiler.ts +66 -66
  126. package/src/parser/TypeRegistry.ts +250 -250
  127. package/src/parser/index.ts +6 -6
  128. package/src/plugins/custom-format.ts +124 -126
  129. package/src/plugins/custom-type-example.ts +106 -108
  130. package/src/plugins/custom-validator.ts +138 -140
  131. package/src/types/conditional.ts +28 -28
  132. package/src/types/config.ts +59 -59
  133. package/src/types/dsl.ts +131 -131
  134. package/src/types/error.ts +60 -60
  135. package/src/types/index.ts +17 -17
  136. package/src/types/infer.ts +127 -127
  137. package/src/types/plugin.ts +58 -58
  138. package/src/types/safe-regex.d.ts +9 -9
  139. package/src/types/schema.ts +66 -66
  140. package/src/types/validate.ts +71 -71
  141. package/src/utils/SchemaHelper.ts +196 -196
  142. package/src/utils/SchemaUtils.ts +365 -346
  143. package/src/utils/TypeConverter.ts +215 -215
  144. package/src/utils/index.ts +10 -10
  145. package/src/validators/CustomKeywords.ts +477 -477
@@ -1,160 +1,160 @@
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
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
@@ -1,101 +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
- }
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
+ }