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,442 +1,449 @@
1
- # 数字比较运算符 (v1.1.2+)
2
-
3
- **版本**: v1.1.2+
4
- **适用类型**: `number`, `integer`
5
-
6
- ## 📋 快速概览
7
-
8
- | 运算符 | 语法 | JSON Schema | 说明 | 示例 |
9
- |-------|------|------------|------|------|
10
- | `>` | `number:>0` | `{ exclusiveMinimum: 0 }` | 大于(不包括边界) | 正数 |
11
- | `>=` | `number:>=18` | `{ minimum: 18 }` | 大于等于 | 年龄限制 |
12
- | `<` | `number:<100` | `{ exclusiveMaximum: 100 }` | 小于(不包括边界) | 温度上限 |
13
- | `<=` | `number:<=100` | `{ maximum: 100 }` | 小于等于 | 评分上限 |
14
- | `=` | `number:=100` | `{ enum: [100] }` | 等于 | 固定值 |
15
-
16
- ---
17
-
18
- ## ✨ 特性
19
-
20
- - ✅ 支持 5 种比较运算符
21
- - ✅ 支持小数(如 `number:>0.5`)
22
- - ✅ 支持负数(如 `number:>-10`)
23
- - ✅ 支持必填标记(如 `number:>=18!`)
24
- - ✅ 适用于 `number` 和 `integer` 类型
25
- - ✅ 完全向后兼容原有范围语法
26
-
27
- ---
28
-
29
- ## 🚀 基础用法
30
-
31
- ### 大于 (>)
32
-
33
- **语法**: `number:>value`
34
-
35
- **JSON Schema**: `{ exclusiveMinimum: value }`
36
-
37
- **说明**: 值必须大于指定值(不包括边界值本身)
38
-
39
- ```javascript
40
- const { dsl, validate } = require('schema-dsl');
41
-
42
- // 基础用法
43
- const schema = dsl({ value: 'number:>0' });
44
-
45
- validate(schema, { value: 1 }); // ✅ true
46
- validate(schema, { value: 0.1 }); // ✅ true
47
- validate(schema, { value: 0 }); // ❌ false (0 不满足 >0)
48
- validate(schema, { value: -1 }); // ❌ false
49
-
50
- // 支持小数
51
- const schema2 = dsl({ value: 'number:>0.5' });
52
- validate(schema2, { value: 0.6 }); // ✅ true
53
- validate(schema2, { value: 0.5 }); // ❌ false (0.5 不满足 >0.5)
54
-
55
- // 支持负数
56
- const schema3 = dsl({ value: 'number:>-10' });
57
- validate(schema3, { value: -9 }); // ✅ true
58
- validate(schema3, { value: -10 }); // ❌ false
59
-
60
- // 配合必填
61
- const schema4 = dsl({ value: 'number:>0!' });
62
- validate(schema4, { value: 1 }); // ✅ true
63
- validate(schema4, {}); // ❌ false (必填)
64
- ```
65
-
66
- ---
67
-
68
- ### 大于等于 (>=)
69
-
70
- **语法**: `number:>=value`
71
-
72
- **JSON Schema**: `{ minimum: value }`
73
-
74
- **说明**: 值必须大于等于指定值(包括边界值)
75
-
76
- ```javascript
77
- // 基础用法
78
- const schema = dsl({ age: 'number:>=18' });
79
-
80
- validate(schema, { age: 18 }); // ✅ true (包括18)
81
- validate(schema, { age: 19 }); // ✅ true
82
- validate(schema, { age: 17 }); // ❌ false
83
-
84
- // 实际应用:年龄验证
85
- const schema2 = dsl({ age: 'number:>=18!' });
86
-
87
- validate(schema2, { age: 20 }); // ✅ true
88
- validate(schema2, { age: 17 }); // ❌ false
89
- validate(schema2, {}); // ❌ false (必填)
90
- ```
91
-
92
- ---
93
-
94
- ### 小于 (<)
95
-
96
- **语法**: `number:<value`
97
-
98
- **JSON Schema**: `{ exclusiveMaximum: value }`
99
-
100
- **说明**: 值必须小于指定值(不包括边界值)
101
-
102
- ```javascript
103
- // 基础用法
104
- const schema = dsl({ value: 'number:<100' });
105
-
106
- validate(schema, { value: 99 }); // ✅ true
107
- validate(schema, { value: 99.9 }); // ✅ true
108
- validate(schema, { value: 100 }); // ❌ false (100 不满足 <100)
109
- validate(schema, { value: 101 }); // ❌ false
110
-
111
- // 实际应用:温度上限
112
- const schema2 = dsl({ temperature: 'number:<100' });
113
-
114
- validate(schema2, { temperature: 99.9 }); // ✅ true
115
- validate(schema2, { temperature: 100 }); // ❌ false
116
- ```
117
-
118
- ---
119
-
120
- ### 小于等于 (<=)
121
-
122
- **语法**: `number:<=value`
123
-
124
- **JSON Schema**: `{ maximum: value }`
125
-
126
- **说明**: 值必须小于等于指定值(包括边界值)
127
-
128
- ```javascript
129
- // 基础用法
130
- const schema = dsl({ score: 'number:<=100' });
131
-
132
- validate(schema, { score: 100 }); // ✅ true (包括100)
133
- validate(schema, { score: 99 }); // ✅ true
134
- validate(schema, { score: 101 }); // ❌ false
135
-
136
- // 实际应用:评分系统
137
- const schema2 = dsl({ score: 'number:<=100!' });
138
-
139
- validate(schema2, { score: 100 }); // ✅ true
140
- validate(schema2, { score: 101 }); // ❌ false
141
- ```
142
-
143
- ---
144
-
145
- ### 等于 (=)
146
-
147
- **语法**: `number:=value`
148
-
149
- **JSON Schema**: `{ enum: [value] }`
150
-
151
- **说明**: 值必须等于指定值
152
-
153
- ```javascript
154
- // 基础用法
155
- const schema = dsl({ level: 'number:=5' });
156
-
157
- validate(schema, { level: 5 }); // ✅ true
158
- validate(schema, { level: 4 }); // ❌ false
159
- validate(schema, { level: 6 }); // ❌ false
160
-
161
- // 支持小数精确匹配
162
- const schema2 = dsl({ price: 'number:=99.99' });
163
-
164
- validate(schema2, { price: 99.99 }); // ✅ true
165
- validate(schema2, { price: 99.98 }); // ❌ false
166
- validate(schema2, { price: 100 }); // ❌ false
167
- ```
168
-
169
- ---
170
-
171
- ## 📊 对比:比较运算符 vs 范围语法
172
-
173
- | 需求 | 范围语法 | 比较运算符 | 推荐 |
174
- |------|---------|-----------|------|
175
- | 18 ≤ x ≤ 120 | `number:18-120` | `number:>=18` + `number:<=120` | 范围语法(更简洁) |
176
- | x ≥ 18 | `number:18-` | `number:>=18` | **比较运算符**(语义更清晰) |
177
- | x ≤ 100 | `number:-100` | `number:<=100` | **比较运算符**(语义更清晰) |
178
- | x > 0(不包括0) | ❌ 无法表达 | `number:>0` | **比较运算符**(唯一方法) |
179
- | x < 100(不包括100) | ❌ 无法表达 | `number:<100` | **比较运算符**(唯一方法) |
180
- | x = 100 | `number:100`(实际是≤100) | `number:=100` | **比较运算符**(精确匹配) |
181
-
182
- ---
183
-
184
- ## 🎯 实际应用场景
185
-
186
- ### 场景 1:用户注册 - 年龄限制
187
-
188
- ```javascript
189
- const schema = dsl({
190
- username: 'string:3-32!',
191
- email: 'email!',
192
- age: 'number:>=18!', // 必须年满18岁
193
- password: 'string:8-!'
194
- });
195
-
196
- // 测试
197
- validate(schema, {
198
- username: 'john',
199
- email: 'john@example.com',
200
- age: 20,
201
- password: '12345678'
202
- }); // ✅ 通过
203
-
204
- validate(schema, {
205
- username: 'tom',
206
- email: 'tom@example.com',
207
- age: 17, // ❌ 未满18岁
208
- password: '12345678'
209
- }); // ❌ 失败
210
- ```
211
-
212
- ---
213
-
214
- ### 场景 2:电商系统 - 价格验证
215
-
216
- ```javascript
217
- const schema = dsl({
218
- productName: 'string:1-100!',
219
- price: 'number:>0!', // 价格必须大于0
220
- discount: 'number:0-100' // 折扣 0-100
221
- });
222
-
223
- // 测试
224
- validate(schema, {
225
- productName: 'iPhone 16',
226
- price: 999.99, // ✅ 大于0
227
- discount: 10
228
- }); // ✅ 通过
229
-
230
- validate(schema, {
231
- productName: 'iPad',
232
- price: 0, // ❌ 不能为0
233
- discount: 50
234
- }); // ❌ 失败
235
- ```
236
-
237
- ---
238
-
239
- ### 场景 3:考试系统 - 评分
240
-
241
- ```javascript
242
- const schema = dsl({
243
- studentId: 'string!',
244
- score: 'number:>=0!', // 分数 ≥ 0
245
- bonus: 'number:<=20' // 额外加分 ≤ 20
246
- });
247
-
248
- // 测试
249
- validate(schema, {
250
- studentId: 'S001',
251
- score: 85,
252
- bonus: 10
253
- }); // ✅ 通过
254
-
255
- validate(schema, {
256
- studentId: 'S002',
257
- score: -5 // ❌ 不能为负数
258
- }); // ❌ 失败
259
- ```
260
-
261
- ---
262
-
263
- ### 场景 4:温度监控 - 范围限制
264
-
265
- ```javascript
266
- const schema = dsl({
267
- deviceId: 'string!',
268
- temperature: 'number:>0', // 温度 > 0
269
- humidity: 'number:<=100' // 湿度 ≤ 100
270
- });
271
-
272
- // 测试
273
- validate(schema, {
274
- deviceId: 'TEMP-001',
275
- temperature: 25.5,
276
- humidity: 60
277
- }); // ✅ 通过
278
-
279
- validate(schema, {
280
- deviceId: 'TEMP-002',
281
- temperature: 0, // ❌ 不能为0
282
- humidity: 60
283
- }); // ❌ 失败
284
- ```
285
-
286
- ---
287
-
288
- ### 场景 5:游戏系统 - 等级验证
289
-
290
- ```javascript
291
- const schema = dsl({
292
- playerId: 'string!',
293
- level: 'number:=5!', // 必须是5级
294
- experience: 'number:>=1000' // 经验 >= 1000
295
- });
296
-
297
- // 测试
298
- validate(schema, {
299
- playerId: 'P001',
300
- level: 5,
301
- experience: 1500
302
- }); // ✅ 通过
303
-
304
- validate(schema, {
305
- playerId: 'P002',
306
- level: 4, // ❌ 必须是5级
307
- experience: 1500
308
- }); // ❌ 失败
309
- ```
310
-
311
- ---
312
-
313
- ## ⚙️ 技术细节
314
-
315
- ### JSON Schema 映射
316
-
317
- ```javascript
318
- // DSL → JSON Schema
319
- dsl({ value: 'number:>0' })
320
- // 生成:
321
- {
322
- type: 'object',
323
- properties: {
324
- value: {
325
- type: 'number',
326
- exclusiveMinimum: 0 // JSON Schema draft-07
327
- }
328
- }
329
- }
330
-
331
- // DSL → JSON Schema
332
- dsl({ age: 'number:>=18' })
333
- // 生成:
334
- {
335
- type: 'object',
336
- properties: {
337
- age: {
338
- type: 'number',
339
- minimum: 18
340
- }
341
- }
342
- }
343
- ```
344
-
345
- ---
346
-
347
- ### integer 类型支持
348
-
349
- 所有比较运算符同样适用于 `integer` 类型:
350
-
351
- ```javascript
352
- const schema = dsl({
353
- count: 'integer:>0', // 整数且大于0
354
- level: 'integer:>=1', // 整数且大于等于1
355
- maxValue: 'integer:<=100' // 整数且小于等于100
356
- });
357
-
358
- validate(schema, {
359
- count: 5,
360
- level: 1,
361
- maxValue: 100
362
- }); // ✅ 通过
363
-
364
- validate(schema, {
365
- count: 1.5, // ❌ 不是整数
366
- level: 1,
367
- maxValue: 100
368
- }); // ❌ 失败
369
- ```
370
-
371
- ---
372
-
373
- ## 🔄 向后兼容性
374
-
375
- 所有原有语法保持不变,无破坏性变更:
376
-
377
- ```javascript
378
- // ✅ 原有语法继续有效
379
- dsl({ age: 'number:18-120' }) // 范围
380
- dsl({ age: 'number:18-' }) // 最小值
381
- dsl({ score: 'number:-100' }) // 最大值
382
- dsl({ count: 'number:100' }) // 最大值
383
-
384
- // ✅ 新增语法
385
- dsl({ age: 'number:>=18' }) // 大于等于
386
- dsl({ value: 'number:>0' }) // 大于
387
- dsl({ score: 'number:<=100' }) // 小于等于
388
- dsl({ temp: 'number:<100' }) // 小于
389
- dsl({ level: 'number:=5' }) // 等于
390
- ```
391
-
392
- ---
393
-
394
- ## ❓ 常见问题
395
-
396
- ### Q1: 为什么需要比较运算符?范围语法不够用吗?
397
-
398
- **A**: 范围语法无法表达"不包括边界值"的需求:
399
- - `number:>0` 表示大于0(不包括0)
400
- - `number:<100` 表示小于100(不包括100)
401
- - 这些用范围语法无法表达
402
-
403
- ---
404
-
405
- ### Q2: `number:=100` 和 `number:100` 有什么区别?
406
-
407
- **A**:
408
- - `number:=100` → `{ enum: [100] }`,精确等于100
409
- - `number:100` → `{ maximum: 100 }`,小于等于100
410
-
411
- ---
412
-
413
- ### Q3: 能否组合多个比较运算符?
414
-
415
- **A**: 当前版本不支持直接组合(如 `number:>0<100`)。建议:
416
- - 使用范围语法:`number:0-100`(包括边界)
417
- - 或分别验证两个字段
418
-
419
- ---
420
-
421
- ### Q4: 支持哪些数值?
422
-
423
- **A**:
424
- - ✅ 正整数:`number:>0`, `number:>=1`
425
- - ✅ 负整数:`number:>-10`, `number:<-5`
426
- - ✅ 小数:`number:>0.5`, `number:<=99.99`
427
- - ✅ 零:`number:>=0`, `number:<=0`
428
-
429
- ---
430
-
431
- ## 📚 相关文档
432
-
433
- - [DSL 语法速查](../README.md#-dsl-语法速查)
434
- - [完整示例](../examples/number-operators.examples.js)
435
- - [测试用例](../test/unit/number-operators.test.js)
436
- - [CHANGELOG](../CHANGELOG.md)
437
-
438
- ---
439
-
440
- **版本**: v1.1.2+
441
- **更新时间**: 2026-01-06
442
-
1
+ # 数字比较运算符 (v1.1.2+)
2
+
3
+ **版本**: v1.1.2+
4
+ **适用类型**: `number`, `integer`
5
+
6
+ ## 📋 快速概览
7
+
8
+ | 运算符 | 语法 | JSON Schema | 说明 | 示例 |
9
+ |-------|------|------------|------|------|
10
+ | `>` | `number:>0` | `{ exclusiveMinimum: 0 }` | 大于(不包括边界) | 正数 |
11
+ | `>=` | `number:>=18` | `{ minimum: 18 }` | 大于等于 | 年龄限制 |
12
+ | `<` | `number:<100` | `{ exclusiveMaximum: 100 }` | 小于(不包括边界) | 温度上限 |
13
+ | `<=` | `number:<=100` | `{ maximum: 100 }` | 小于等于 | 评分上限 |
14
+ | `=` | `number:=100` | `{ enum: [100] }` | 等于 | 固定值 |
15
+
16
+ ---
17
+
18
+ ## ✨ 特性
19
+
20
+ - ✅ 支持 5 种比较运算符
21
+ - ✅ 支持小数(如 `number:>0.5`)
22
+ - ✅ 支持负数(如 `number:>-10`)
23
+ - ✅ 支持必填标记(如 `number:>=18!`)
24
+ - ✅ 适用于 `number` 和 `integer` 类型
25
+ - ✅ 完全向后兼容原有范围语法
26
+
27
+ ---
28
+
29
+ ## 🚀 基础用法
30
+
31
+ ### 大于 (>)
32
+
33
+ **语法**: `number:>value`
34
+
35
+ **JSON Schema**: `{ exclusiveMinimum: value }`
36
+
37
+ **说明**: 值必须大于指定值(不包括边界值本身)
38
+
39
+ ```javascript
40
+ const { dsl, validate } = require('schema-dsl');
41
+
42
+ // 基础用法
43
+ const schema = dsl({ value: 'number:>0' });
44
+
45
+ validate(schema, { value: 1 }); // ✅ true
46
+ validate(schema, { value: 0.1 }); // ✅ true
47
+ validate(schema, { value: 0 }); // ❌ false (0 不满足 >0)
48
+ validate(schema, { value: -1 }); // ❌ false
49
+
50
+ // 支持小数
51
+ const schema2 = dsl({ value: 'number:>0.5' });
52
+ validate(schema2, { value: 0.6 }); // ✅ true
53
+ validate(schema2, { value: 0.5 }); // ❌ false (0.5 不满足 >0.5)
54
+
55
+ // 支持负数
56
+ const schema3 = dsl({ value: 'number:>-10' });
57
+ validate(schema3, { value: -9 }); // ✅ true
58
+ validate(schema3, { value: -10 }); // ❌ false
59
+
60
+ // 配合必填
61
+ const schema4 = dsl({ value: 'number:>0!' });
62
+ validate(schema4, { value: 1 }); // ✅ true
63
+ validate(schema4, {}); // ❌ false (必填)
64
+ ```
65
+
66
+ ---
67
+
68
+ ### 大于等于 (>=)
69
+
70
+ **语法**: `number:>=value`
71
+
72
+ **JSON Schema**: `{ minimum: value }`
73
+
74
+ **说明**: 值必须大于等于指定值(包括边界值)
75
+
76
+ ```javascript
77
+ // 基础用法
78
+ const schema = dsl({ age: 'number:>=18' });
79
+
80
+ validate(schema, { age: 18 }); // ✅ true (包括18)
81
+ validate(schema, { age: 19 }); // ✅ true
82
+ validate(schema, { age: 17 }); // ❌ false
83
+
84
+ // 实际应用:年龄验证
85
+ const schema2 = dsl({ age: 'number:>=18!' });
86
+
87
+ validate(schema2, { age: 20 }); // ✅ true
88
+ validate(schema2, { age: 17 }); // ❌ false
89
+ validate(schema2, {}); // ❌ false (必填)
90
+ ```
91
+
92
+ ---
93
+
94
+ ### 小于 (<)
95
+
96
+ **语法**: `number:<value`
97
+
98
+ **JSON Schema**: `{ exclusiveMaximum: value }`
99
+
100
+ **说明**: 值必须小于指定值(不包括边界值)
101
+
102
+ ```javascript
103
+ // 基础用法
104
+ const schema = dsl({ value: 'number:<100' });
105
+
106
+ validate(schema, { value: 99 }); // ✅ true
107
+ validate(schema, { value: 99.9 }); // ✅ true
108
+ validate(schema, { value: 100 }); // ❌ false (100 不满足 <100)
109
+ validate(schema, { value: 101 }); // ❌ false
110
+
111
+ // 实际应用:温度上限
112
+ const schema2 = dsl({ temperature: 'number:<100' });
113
+
114
+ validate(schema2, { temperature: 99.9 }); // ✅ true
115
+ validate(schema2, { temperature: 100 }); // ❌ false
116
+ ```
117
+
118
+ ---
119
+
120
+ ### 小于等于 (<=)
121
+
122
+ **语法**: `number:<=value`
123
+
124
+ **JSON Schema**: `{ maximum: value }`
125
+
126
+ **说明**: 值必须小于等于指定值(包括边界值)
127
+
128
+ ```javascript
129
+ // 基础用法
130
+ const schema = dsl({ score: 'number:<=100' });
131
+
132
+ validate(schema, { score: 100 }); // ✅ true (包括100)
133
+ validate(schema, { score: 99 }); // ✅ true
134
+ validate(schema, { score: 101 }); // ❌ false
135
+
136
+ // 实际应用:评分系统
137
+ const schema2 = dsl({ score: 'number:<=100!' });
138
+
139
+ validate(schema2, { score: 100 }); // ✅ true
140
+ validate(schema2, { score: 101 }); // ❌ false
141
+ ```
142
+
143
+ ---
144
+
145
+ ### 等于 (=)
146
+
147
+ **语法**: `number:=value`
148
+
149
+ **JSON Schema**: `{ enum: [value] }`
150
+
151
+ **说明**: 值必须等于指定值
152
+
153
+ ```javascript
154
+ // 基础用法
155
+ const schema = dsl({ level: 'number:=5' });
156
+
157
+ validate(schema, { level: 5 }); // ✅ true
158
+ validate(schema, { level: 4 }); // ❌ false
159
+ validate(schema, { level: 6 }); // ❌ false
160
+
161
+ // 支持小数精确匹配
162
+ const schema2 = dsl({ price: 'number:=99.99' });
163
+
164
+ validate(schema2, { price: 99.99 }); // ✅ true
165
+ validate(schema2, { price: 99.98 }); // ❌ false
166
+ validate(schema2, { price: 100 }); // ❌ false
167
+ ```
168
+
169
+ ---
170
+
171
+ ## 📊 对比:比较运算符 vs 范围语法
172
+
173
+ | 需求 | 范围语法 | 比较运算符 | 推荐 |
174
+ |------|---------|-----------|------|
175
+ | 18 ≤ x ≤ 120 | `number:18-120` | `number:>=18` + `number:<=120` | 范围语法(更简洁) |
176
+ | x ≥ 18 | `number:18-` | `number:>=18` | **比较运算符**(语义更清晰) |
177
+ | x ≤ 100 | `number:-100` | `number:<=100` | **比较运算符**(语义更清晰) |
178
+ | x > 0(不包括0) | ❌ 无法表达 | `number:>0` | **比较运算符**(唯一方法) |
179
+ | x < 100(不包括100) | ❌ 无法表达 | `number:<100` | **比较运算符**(唯一方法) |
180
+ | x = 100 | `number:100`(实际是≤100) | `number:=100` | **比较运算符**(精确匹配) |
181
+
182
+ ---
183
+
184
+ ## 🎯 实际应用场景
185
+
186
+ ### 场景 1:用户注册 - 年龄限制
187
+
188
+ ```javascript
189
+ const schema = dsl({
190
+ username: 'string:3-32!',
191
+ email: 'email!',
192
+ age: 'number:>=18!', // 必须年满18岁
193
+ password: 'string:8-!'
194
+ });
195
+
196
+ // 测试
197
+ validate(schema, {
198
+ username: 'john',
199
+ email: 'john@example.com',
200
+ age: 20,
201
+ password: '12345678'
202
+ }); // ✅ 通过
203
+
204
+ validate(schema, {
205
+ username: 'tom',
206
+ email: 'tom@example.com',
207
+ age: 17, // ❌ 未满18岁
208
+ password: '12345678'
209
+ }); // ❌ 失败
210
+ ```
211
+
212
+ ---
213
+
214
+ ### 场景 2:电商系统 - 价格验证
215
+
216
+ ```javascript
217
+ const schema = dsl({
218
+ productName: 'string:1-100!',
219
+ price: 'number:>0!', // 价格必须大于0
220
+ discount: 'number:0-100' // 折扣 0-100
221
+ });
222
+
223
+ // 测试
224
+ validate(schema, {
225
+ productName: 'iPhone 16',
226
+ price: 999.99, // ✅ 大于0
227
+ discount: 10
228
+ }); // ✅ 通过
229
+
230
+ validate(schema, {
231
+ productName: 'iPad',
232
+ price: 0, // ❌ 不能为0
233
+ discount: 50
234
+ }); // ❌ 失败
235
+ ```
236
+
237
+ ---
238
+
239
+ ### 场景 3:考试系统 - 评分
240
+
241
+ ```javascript
242
+ const schema = dsl({
243
+ studentId: 'string!',
244
+ score: 'number:>=0!', // 分数 ≥ 0
245
+ bonus: 'number:<=20' // 额外加分 ≤ 20
246
+ });
247
+
248
+ // 测试
249
+ validate(schema, {
250
+ studentId: 'S001',
251
+ score: 85,
252
+ bonus: 10
253
+ }); // ✅ 通过
254
+
255
+ validate(schema, {
256
+ studentId: 'S002',
257
+ score: -5 // ❌ 不能为负数
258
+ }); // ❌ 失败
259
+ ```
260
+
261
+ ---
262
+
263
+ ### 场景 4:温度监控 - 范围限制
264
+
265
+ ```javascript
266
+ const schema = dsl({
267
+ deviceId: 'string!',
268
+ temperature: 'number:>0', // 温度 > 0
269
+ humidity: 'number:<=100' // 湿度 ≤ 100
270
+ });
271
+
272
+ // 测试
273
+ validate(schema, {
274
+ deviceId: 'TEMP-001',
275
+ temperature: 25.5,
276
+ humidity: 60
277
+ }); // ✅ 通过
278
+
279
+ validate(schema, {
280
+ deviceId: 'TEMP-002',
281
+ temperature: 0, // ❌ 不能为0
282
+ humidity: 60
283
+ }); // ❌ 失败
284
+ ```
285
+
286
+ ---
287
+
288
+ ### 场景 5:游戏系统 - 等级验证
289
+
290
+ ```javascript
291
+ const schema = dsl({
292
+ playerId: 'string!',
293
+ level: 'number:=5!', // 必须是5级
294
+ experience: 'number:>=1000' // 经验 >= 1000
295
+ });
296
+
297
+ // 测试
298
+ validate(schema, {
299
+ playerId: 'P001',
300
+ level: 5,
301
+ experience: 1500
302
+ }); // ✅ 通过
303
+
304
+ validate(schema, {
305
+ playerId: 'P002',
306
+ level: 4, // ❌ 必须是5级
307
+ experience: 1500
308
+ }); // ❌ 失败
309
+ ```
310
+
311
+ ---
312
+
313
+ ## ⚙️ 技术细节
314
+
315
+ ### JSON Schema 映射
316
+
317
+ ```javascript
318
+ // DSL → JSON Schema
319
+ dsl({ value: 'number:>0' })
320
+ // 生成:
321
+ {
322
+ type: 'object',
323
+ properties: {
324
+ value: {
325
+ type: 'number',
326
+ exclusiveMinimum: 0 // JSON Schema draft-07
327
+ }
328
+ }
329
+ }
330
+
331
+ // DSL → JSON Schema
332
+ dsl({ age: 'number:>=18' })
333
+ // 生成:
334
+ {
335
+ type: 'object',
336
+ properties: {
337
+ age: {
338
+ type: 'number',
339
+ minimum: 18
340
+ }
341
+ }
342
+ }
343
+ ```
344
+
345
+ ---
346
+
347
+ ### integer 类型支持
348
+
349
+ 所有比较运算符同样适用于 `integer` 类型:
350
+
351
+ ```javascript
352
+ const schema = dsl({
353
+ count: 'integer:>0', // 整数且大于0
354
+ level: 'integer:>=1', // 整数且大于等于1
355
+ maxValue: 'integer:<=100' // 整数且小于等于100
356
+ });
357
+
358
+ validate(schema, {
359
+ count: 5,
360
+ level: 1,
361
+ maxValue: 100
362
+ }); // ✅ 通过
363
+
364
+ validate(schema, {
365
+ count: 1.5, // ❌ 不是整数
366
+ level: 1,
367
+ maxValue: 100
368
+ }); // ❌ 失败
369
+ ```
370
+
371
+ ---
372
+
373
+ ## 🔄 向后兼容性
374
+
375
+ 所有原有语法保持不变,无破坏性变更:
376
+
377
+ ```javascript
378
+ // ✅ 原有语法继续有效
379
+ dsl({ age: 'number:18-120' }) // 范围
380
+ dsl({ age: 'number:18-' }) // 最小值
381
+ dsl({ score: 'number:-100' }) // 最大值
382
+ dsl({ count: 'number:100' }) // 最大值
383
+
384
+ // ✅ 新增语法
385
+ dsl({ age: 'number:>=18' }) // 大于等于
386
+ dsl({ value: 'number:>0' }) // 大于
387
+ dsl({ score: 'number:<=100' }) // 小于等于
388
+ dsl({ temp: 'number:<100' }) // 小于
389
+ dsl({ level: 'number:=5' }) // 等于
390
+ ```
391
+
392
+ ---
393
+
394
+ ## ❓ 常见问题
395
+
396
+ ### Q1: 为什么需要比较运算符?范围语法不够用吗?
397
+
398
+ **A**: 范围语法无法表达"不包括边界值"的需求:
399
+ - `number:>0` 表示大于0(不包括0)
400
+ - `number:<100` 表示小于100(不包括100)
401
+ - 这些用范围语法无法表达
402
+
403
+ ---
404
+
405
+ ### Q2: `number:=100` 和 `number:100` 有什么区别?
406
+
407
+ **A**:
408
+ - `number:=100` → `{ enum: [100] }`,精确等于100
409
+ - `number:100` → `{ maximum: 100 }`,小于等于100
410
+
411
+ ---
412
+
413
+ ### Q3: 能否组合多个比较运算符?
414
+
415
+ **A**: 当前版本不支持直接组合(如 `number:>0<100`)。建议:
416
+ - 使用范围语法:`number:0-100`(包括边界)
417
+ - 或分别验证两个字段
418
+
419
+ ---
420
+
421
+ ### Q4: 支持哪些数值?
422
+
423
+ **A**:
424
+ - ✅ 正整数:`number:>0`, `number:>=1`
425
+ - ✅ 负整数:`number:>-10`, `number:<-5`
426
+ - ✅ 小数:`number:>0.5`, `number:<=99.99`
427
+ - ✅ 零:`number:>=0`, `number:<=0`
428
+
429
+ ---
430
+
431
+ ## 📚 相关文档
432
+
433
+ - [DSL 语法速查](./dsl-syntax.md)
434
+ - [完整示例](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/number-operators.ts)
435
+ - [测试用例](../test/unit/number-operators.test.ts)
436
+ - [CHANGELOG](https://github.com/vextjs/schema-dsl/blob/main/CHANGELOG.md)
437
+
438
+ ---
439
+
440
+ ## 对应示例文件
441
+
442
+ **示例入口**: [number-operators.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/number-operators.ts)
443
+ **说明**: 覆盖 `>=`、`<`、`<=`、`=` 和整数比较运算符的成功/失败路径,便于直接观察边界行为。
444
+
445
+ ---
446
+
447
+ **版本**: v1.1.2+
448
+ **更新时间**: 2026-05-08
449
+