schema-dsl 1.2.4 → 2.0.0

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 (242) hide show
  1. package/CHANGELOG.md +87 -210
  2. package/README.md +391 -2249
  3. package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
  4. package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
  5. package/dist/Validator-C7GsVQOH.d.cts +192 -0
  6. package/dist/Validator-hFWKGxir.d.ts +192 -0
  7. package/dist/index.cjs +6594 -0
  8. package/dist/index.d.cts +1145 -0
  9. package/dist/index.d.ts +1145 -0
  10. package/dist/index.js +6528 -0
  11. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  12. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  13. package/dist/plugins/custom-format.cjs +3802 -0
  14. package/dist/plugins/custom-format.d.cts +12 -0
  15. package/dist/plugins/custom-format.d.ts +12 -0
  16. package/dist/plugins/custom-format.js +3772 -0
  17. package/dist/plugins/custom-type-example.cjs +3795 -0
  18. package/dist/plugins/custom-type-example.d.cts +8 -0
  19. package/dist/plugins/custom-type-example.d.ts +8 -0
  20. package/dist/plugins/custom-type-example.js +3765 -0
  21. package/dist/plugins/custom-validator.cjs +146 -0
  22. package/dist/plugins/custom-validator.d.cts +10 -0
  23. package/dist/plugins/custom-validator.d.ts +10 -0
  24. package/dist/plugins/custom-validator.js +121 -0
  25. package/docs/FEATURE-INDEX.md +102 -68
  26. package/docs/add-custom-locale.md +48 -35
  27. package/docs/add-keyword.md +24 -0
  28. package/docs/api-reference.md +396 -154
  29. package/docs/api.md +13 -0
  30. package/docs/best-practices-project-structure.md +19 -10
  31. package/docs/best-practices.md +93 -53
  32. package/docs/cache-manager.md +23 -15
  33. package/docs/compile.md +45 -0
  34. package/docs/conditional-api.md +40 -11
  35. package/docs/custom-extensions-guide.md +80 -152
  36. package/docs/design-philosophy.md +76 -71
  37. package/docs/doc-index.md +324 -0
  38. package/docs/dsl-syntax.md +69 -19
  39. package/docs/dynamic-locale.md +24 -14
  40. package/docs/enum.md +12 -5
  41. package/docs/error-handling.md +53 -44
  42. package/docs/export-guide.md +47 -8
  43. package/docs/export-limitations.md +27 -11
  44. package/docs/faq.md +86 -67
  45. package/docs/frontend-i18n-guide.md +26 -12
  46. package/docs/i18n-user-guide.md +60 -47
  47. package/docs/i18n.md +51 -32
  48. package/docs/index.md +48 -0
  49. package/docs/json-schema-basics.md +40 -0
  50. package/docs/label-vs-description.md +12 -3
  51. package/docs/markdown-exporter.md +15 -6
  52. package/docs/mongodb-exporter.md +11 -4
  53. package/docs/multi-language.md +26 -0
  54. package/docs/multi-type-support.md +26 -33
  55. package/docs/mysql-exporter.md +9 -2
  56. package/docs/number-operators.md +12 -5
  57. package/docs/optional-marker-guide.md +28 -23
  58. package/docs/performance-guide.md +49 -0
  59. package/docs/plugin-system.md +205 -366
  60. package/docs/plugin-type-registration.md +34 -0
  61. package/docs/postgresql-exporter.md +9 -2
  62. package/docs/public/favicon.svg +5 -0
  63. package/docs/quick-start.md +37 -363
  64. package/docs/runtime-locale-support.md +20 -9
  65. package/docs/schema-helper.md +10 -5
  66. package/docs/schema-utils-advanced-issues.md +23 -0
  67. package/docs/schema-utils-best-practices.md +20 -0
  68. package/docs/schema-utils-chaining.md +7 -0
  69. package/docs/schema-utils.md +76 -42
  70. package/docs/security-checklist.md +20 -0
  71. package/docs/string-extensions.md +17 -9
  72. package/docs/troubleshooting.md +36 -21
  73. package/docs/type-converter.md +41 -50
  74. package/docs/type-reference.md +38 -15
  75. package/docs/typescript-guide.md +53 -42
  76. package/docs/union-type-guide.md +11 -1
  77. package/docs/union-types.md +10 -3
  78. package/docs/validate-async.md +36 -25
  79. package/docs/validate-batch.md +49 -0
  80. package/docs/validate-dsl-object-support.md +33 -28
  81. package/docs/validate.md +36 -16
  82. package/docs/validation-guide.md +25 -7
  83. package/docs/validator.md +39 -0
  84. package/package.json +85 -27
  85. package/plugins/custom-format.cjs +8 -0
  86. package/plugins/custom-type-example.cjs +8 -0
  87. package/plugins/custom-validator.cjs +8 -0
  88. package/src/adapters/DslAdapter.ts +111 -0
  89. package/src/adapters/index.ts +1 -0
  90. package/src/config/constants.ts +83 -0
  91. package/src/config/index.ts +2 -0
  92. package/src/config/patterns.ts +77 -0
  93. package/src/core/CacheManager.ts +159 -0
  94. package/src/core/ConditionalBuilder.ts +382 -0
  95. package/src/core/ConditionalRuntime.ts +28 -0
  96. package/src/core/ConditionalValidator.ts +255 -0
  97. package/src/core/DslBuilder.ts +677 -0
  98. package/src/core/ErrorCodes.ts +38 -0
  99. package/src/core/ErrorFormatter.ts +271 -0
  100. package/src/core/JSONSchemaCore.ts +65 -0
  101. package/src/core/Locale.ts +187 -0
  102. package/src/core/MessageTemplate.ts +42 -0
  103. package/src/core/ObjectDslBuilder.ts +64 -0
  104. package/src/core/PluginManager.ts +326 -0
  105. package/src/core/StringExtensions.ts +140 -0
  106. package/src/core/TemplateEngine.ts +44 -0
  107. package/src/core/Validator.ts +448 -0
  108. package/src/errors/I18nError.ts +159 -0
  109. package/src/errors/ValidationError.ts +105 -0
  110. package/src/exporters/BaseExporter.ts +60 -0
  111. package/src/exporters/MarkdownExporter.ts +305 -0
  112. package/src/exporters/MongoDBExporter.ts +126 -0
  113. package/src/exporters/MySQLExporter.ts +155 -0
  114. package/src/exporters/PostgreSQLExporter.ts +222 -0
  115. package/src/exporters/index.ts +18 -0
  116. package/src/index.ts +633 -0
  117. package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
  118. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
  119. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
  120. package/src/locales/index.ts +103 -0
  121. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
  122. package/src/locales/types.ts +156 -0
  123. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
  124. package/src/parser/ConstraintParser.ts +101 -0
  125. package/src/parser/DslParser.ts +470 -0
  126. package/src/parser/SchemaCompiler.ts +66 -0
  127. package/src/parser/TypeRegistry.ts +250 -0
  128. package/src/parser/index.ts +6 -0
  129. package/src/plugins/custom-format.ts +126 -0
  130. package/src/plugins/custom-type-example.ts +108 -0
  131. package/src/plugins/custom-validator.ts +140 -0
  132. package/src/types/conditional.ts +28 -0
  133. package/src/types/config.ts +59 -0
  134. package/src/types/dsl.ts +131 -0
  135. package/src/types/error.ts +60 -0
  136. package/src/types/index.ts +17 -0
  137. package/src/types/infer.ts +128 -0
  138. package/src/types/plugin.ts +58 -0
  139. package/src/types/safe-regex.d.ts +9 -0
  140. package/src/types/schema.ts +66 -0
  141. package/src/types/validate.ts +71 -0
  142. package/src/utils/SchemaHelper.ts +196 -0
  143. package/src/utils/SchemaUtils.ts +346 -0
  144. package/src/utils/TypeConverter.ts +215 -0
  145. package/src/utils/index.ts +10 -0
  146. package/src/validators/CustomKeywords.ts +477 -0
  147. package/.eslintignore +0 -11
  148. package/.eslintrc.json +0 -27
  149. package/CONTRIBUTING.md +0 -368
  150. package/STATUS.md +0 -491
  151. package/changelogs/v1.0.0.md +0 -328
  152. package/changelogs/v1.0.9.md +0 -367
  153. package/changelogs/v1.1.0.md +0 -389
  154. package/changelogs/v1.1.1.md +0 -308
  155. package/changelogs/v1.1.2.md +0 -183
  156. package/changelogs/v1.1.3.md +0 -161
  157. package/changelogs/v1.1.4.md +0 -432
  158. package/changelogs/v1.1.5.md +0 -493
  159. package/changelogs/v1.1.6.md +0 -211
  160. package/changelogs/v1.1.8.md +0 -376
  161. package/changelogs/v1.2.3.md +0 -124
  162. package/docs/INDEX.md +0 -252
  163. package/docs/issues-resolved-summary.md +0 -196
  164. package/docs/performance-benchmark-report.md +0 -179
  165. package/docs/performance-quick-reference.md +0 -123
  166. package/docs/user-questions-answered.md +0 -353
  167. package/docs/validation-rules-v1.0.2.md +0 -1608
  168. package/examples/README.md +0 -81
  169. package/examples/array-dsl-example.js +0 -227
  170. package/examples/conditional-example.js +0 -288
  171. package/examples/conditional-non-object.js +0 -129
  172. package/examples/conditional-validate-example.js +0 -321
  173. package/examples/custom-extension.js +0 -85
  174. package/examples/dsl-match-example.js +0 -74
  175. package/examples/dsl-style.js +0 -118
  176. package/examples/dynamic-locale-configuration.js +0 -348
  177. package/examples/dynamic-locale-example.js +0 -287
  178. package/examples/enum.examples.js +0 -324
  179. package/examples/export-demo.js +0 -130
  180. package/examples/express-integration.js +0 -376
  181. package/examples/i18n-error-handling-complete.js +0 -381
  182. package/examples/i18n-error-handling-quickstart.md +0 -0
  183. package/examples/i18n-error.examples.js +0 -181
  184. package/examples/i18n-full-demo.js +0 -301
  185. package/examples/i18n-memory-safety.examples.js +0 -268
  186. package/examples/markdown-export.js +0 -71
  187. package/examples/middleware-usage.js +0 -93
  188. package/examples/new-features-comparison.js +0 -315
  189. package/examples/password-reset/README.md +0 -153
  190. package/examples/password-reset/schema.js +0 -26
  191. package/examples/password-reset/test.js +0 -101
  192. package/examples/plugin-system.examples.js +0 -205
  193. package/examples/schema-utils-chaining.examples.js +0 -250
  194. package/examples/simple-example.js +0 -122
  195. package/examples/slug.examples.js +0 -179
  196. package/examples/string-extensions.js +0 -297
  197. package/examples/union-type-example.js +0 -127
  198. package/examples/union-types-example.js +0 -77
  199. package/examples/user-registration/README.md +0 -156
  200. package/examples/user-registration/routes.js +0 -92
  201. package/examples/user-registration/schema.js +0 -150
  202. package/examples/user-registration/server.js +0 -74
  203. package/index.d.ts +0 -3540
  204. package/index.js +0 -457
  205. package/index.mjs +0 -60
  206. package/lib/adapters/DslAdapter.js +0 -871
  207. package/lib/adapters/index.js +0 -20
  208. package/lib/config/constants.js +0 -286
  209. package/lib/config/patterns/common.js +0 -47
  210. package/lib/config/patterns/creditCard.js +0 -9
  211. package/lib/config/patterns/idCard.js +0 -9
  212. package/lib/config/patterns/index.js +0 -9
  213. package/lib/config/patterns/licensePlate.js +0 -4
  214. package/lib/config/patterns/passport.js +0 -4
  215. package/lib/config/patterns/phone.js +0 -9
  216. package/lib/config/patterns/postalCode.js +0 -5
  217. package/lib/core/CacheManager.js +0 -376
  218. package/lib/core/ConditionalBuilder.js +0 -503
  219. package/lib/core/DslBuilder.js +0 -1400
  220. package/lib/core/ErrorCodes.js +0 -233
  221. package/lib/core/ErrorFormatter.js +0 -445
  222. package/lib/core/JSONSchemaCore.js +0 -347
  223. package/lib/core/Locale.js +0 -130
  224. package/lib/core/MessageTemplate.js +0 -98
  225. package/lib/core/PluginManager.js +0 -448
  226. package/lib/core/StringExtensions.js +0 -240
  227. package/lib/core/Validator.js +0 -654
  228. package/lib/errors/I18nError.js +0 -328
  229. package/lib/errors/ValidationError.js +0 -191
  230. package/lib/exporters/MarkdownExporter.js +0 -420
  231. package/lib/exporters/MongoDBExporter.js +0 -162
  232. package/lib/exporters/MySQLExporter.js +0 -212
  233. package/lib/exporters/PostgreSQLExporter.js +0 -289
  234. package/lib/exporters/index.js +0 -24
  235. package/lib/locales/index.js +0 -8
  236. package/lib/utils/LRUCache.js +0 -174
  237. package/lib/utils/SchemaHelper.js +0 -240
  238. package/lib/utils/SchemaUtils.js +0 -445
  239. package/lib/utils/TypeConverter.js +0 -245
  240. package/lib/utils/index.js +0 -13
  241. package/lib/validators/CustomKeywords.js +0 -616
  242. package/lib/validators/index.js +0 -11
@@ -1,4 +1,6 @@
1
- module.exports = {
1
+ import type { LocaleMessages } from './types.js'
2
+
3
+ const jaJP: LocaleMessages = {
2
4
  // Generic
3
5
  required: '{{#label}}は必須です',
4
6
  type: '{{#label}}は{{#expected}}型である必要がありますが、{{#actual}}が渡されました',
@@ -12,12 +14,40 @@ module.exports = {
12
14
  'max-depth': '{{#label}}で最大再帰深度 ({{#depth}}) を超えました',
13
15
  exception: '{{#label}}の検証例外: {{#message}}',
14
16
 
15
- // Conditional (ConditionalBuilder)
17
+ // Conditional
16
18
  'conditional.underAge': '未成年者は登録できません',
17
19
  'conditional.blocked': 'アカウントがブロックされています',
18
20
  'conditional.notAllowed': '登録は許可されていません',
19
21
 
20
- // Formats
22
+ // I18nError — generic (v2 additions)
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 (v2 additions)
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 (v2 additions)
41
+ 'user.notFound': 'ユーザーが見つかりません',
42
+ 'user.notVerified': 'ユーザーが確認されていません',
43
+ 'user.noPermission': '管理者権限がありません',
44
+
45
+ // Order (v2 additions)
46
+ 'order.notPaid': { code: 'ORDER_NOT_PAID', message: '注文が支払われていません' },
47
+ 'order.paymentMissing': '支払い情報がありません',
48
+ 'order.addressMissing': '配送先住所がありません',
49
+
50
+ // Format
21
51
  'format.email': '{{#label}}は有効なメールアドレスである必要があります',
22
52
  'format.url': '{{#label}}は有効なURLである必要があります',
23
53
  'format.uuid': '{{#label}}は有効なUUIDである必要があります',
@@ -32,6 +62,11 @@ module.exports = {
32
62
  'string.hostname': '{{#label}}は有効なホスト名である必要があります',
33
63
  'string.pattern': '{{#label}}の形式が必要なパターンと一致しません',
34
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}}は大文字である必要があります',
35
70
 
36
71
  // Number
37
72
  'number.base': '{{#label}}は数値である必要があります',
@@ -40,6 +75,8 @@ module.exports = {
40
75
  'number.integer': '{{#label}}は整数である必要があります',
41
76
  'number.positive': '{{#label}}は正の数である必要があります',
42
77
  'number.negative': '{{#label}}は負の数である必要があります',
78
+ 'number.precision': '{{#label}}の小数点以下は{{#limit}}桁以内である必要があります',
79
+ 'number.port': '{{#label}}は有効なポート番号 (1-65535) である必要があります',
43
80
 
44
81
  // Boolean
45
82
  'boolean.base': '{{#label}}はブール値である必要があります',
@@ -49,7 +86,8 @@ module.exports = {
49
86
  'object.min': '{{#label}}は少なくとも{{#limit}}個のプロパティを持つ必要があります',
50
87
  'object.max': '{{#label}}は最大{{#limit}}個のプロパティを持つことができます',
51
88
  'object.unknown': '{{#label}}に未知のプロパティが含まれています: {{#key}}',
52
- // v1.1.6 - additionalProperties
89
+ 'object.missing': '{{#label}}には必須プロパティがありません',
90
+ 'object.schema': '{{#label}}に追加のプロパティが含まれています',
53
91
  'additionalProperties': '{{#label}}に追加のプロパティを含めてはいけません: {{#key}}',
54
92
 
55
93
  // Array
@@ -58,11 +96,16 @@ module.exports = {
58
96
  'array.max': '{{#label}}は最大{{#limit}}個の要素を持つことができます',
59
97
  'array.length': '{{#label}}は正確に{{#limit}}個の要素を持つ必要があります',
60
98
  'array.unique': '{{#label}}に重複する要素を含めることはできません',
99
+ 'array.sparse': '{{#label}}はスパース配列であってはなりません',
100
+ 'array.includesRequired': '{{#label}}には必須アイテムを含める必要があります',
61
101
 
62
102
  // Date
63
103
  'date.base': '{{#label}}は有効な日付である必要があります',
64
104
  'date.min': '{{#label}}は{{#limit}}より前であってはなりません',
65
105
  'date.max': '{{#label}}は{{#limit}}より後であってはなりません',
106
+ 'date.format': '{{#label}}の日付形式が無効です',
107
+ 'date.greater': '{{#label}}は{{#limit}}より後である必要があります',
108
+ 'date.less': '{{#label}}は{{#limit}}より前である必要があります',
66
109
 
67
110
  // Any
68
111
  'any.required': '{{#label}}は必須です',
@@ -70,7 +113,7 @@ module.exports = {
70
113
  'any.only': '{{#label}}は{{#valids}}と一致する必要があります',
71
114
  'any.unknown': 'フィールド{{#key}}は許可されていません',
72
115
 
73
- // Patterns (Legacy/Specific)
116
+ // Patterns
74
117
  'pattern.phone': '無効な電話番号',
75
118
  'pattern.phone.international': '無効な国際電話番号',
76
119
  'pattern.idCard': '無効なIDカード番号',
@@ -89,30 +132,29 @@ module.exports = {
89
132
  'pattern.macAddress': '無効なMACアドレス',
90
133
  'pattern.cron': '無効なCron式',
91
134
  'pattern.slug': 'URLスラッグには小文字、数字、ハイフンのみを含めることができます',
92
- // v1.0.2 新増
93
135
  'pattern.domain': '{{#label}}は有効なドメイン名である必要があります',
94
136
  'pattern.ip': '{{#label}}は有効なIPアドレスである必要があります',
95
137
  'pattern.base64': '{{#label}}は有効なBase64文字列である必要があります',
96
138
  'pattern.jwt': '{{#label}}は有効なJWTトークンである必要があります',
97
139
  'pattern.json': '{{#label}}は有効なJSON文字列である必要があります',
98
-
99
- // Username & Password
100
140
  'pattern.username': 'ユーザー名は文字で始まり、文字、数字、アンダースコアのみを含む必要があります',
101
141
  'pattern.password.weak': 'パスワードは少なくとも6文字である必要があります',
102
142
  'pattern.password.medium': 'パスワードは少なくとも8文字で、文字と数字を含む必要があります',
103
143
  'pattern.password.strong': 'パスワードは少なくとも8文字で、大文字、小文字、数字を含む必要があります',
104
144
  'pattern.password.veryStrong': 'パスワードは少なくとも10文字で、大文字、小文字、数字、特殊文字を含む必要があります',
145
+ 'pattern.emailOrPhone': 'メールアドレスまたは電話番号である必要があります',
146
+ 'pattern.usernameOrEmail': 'ユーザー名またはメールアドレスである必要があります',
147
+ 'pattern.httpOrHttps': 'http または https で始まるURLである必要があります',
105
148
 
106
- // oneOf (型の結合) - v1.1.0
149
+ // oneOf
107
150
  oneOf: '{{#label}}は次のいずれかの型に一致する必要があります',
108
151
  'oneOf.invalid': '{{#label}}の値は許可された型のいずれとも一致しません',
109
152
 
110
- // Unknown error fallback
111
- 'UNKNOWN_ERROR': '不明な検証エラー',
112
-
113
- // Custom validation
114
- 'CUSTOM_VALIDATION_FAILED': '検証に失敗しました',
115
- 'ASYNC_VALIDATION_NOT_SUPPORTED': '同期validate()では非同期検証はサポートされていません',
116
- 'VALIDATE_MUST_BE_FUNCTION': 'validateは関数である必要があります'
117
- };
153
+ // Error fallback
154
+ UNKNOWN_ERROR: '不明な検証エラー',
155
+ CUSTOM_VALIDATION_FAILED: '検証に失敗しました',
156
+ ASYNC_VALIDATION_NOT_SUPPORTED: '同期validate()では非同期検証はサポートされていません',
157
+ VALIDATE_MUST_BE_FUNCTION: 'validateは関数である必要があります',
158
+ }
118
159
 
160
+ export default jaJP
@@ -0,0 +1,156 @@
1
+ /**
2
+ * LocaleKey — union type of all locale message keys (118 keys)
3
+ *
4
+ * TypeScript compile-time completeness enforcement: every locale file must implement
5
+ * the LocaleMessages interface; adding a new key causes a compiler error in all locales.
6
+ */
7
+
8
+ // ─── Base message value type ──────────────────────────────────────────────────
9
+ /** A message is either a plain string or an object with code (v1.1.5+ format) */
10
+ export type LocaleMessage = string | { code: string | number; message: string }
11
+
12
+ // ─── Key union (for precise key inference in getMessage) ─────────────────────
13
+ export type LocaleKey =
14
+ // Generic
15
+ | 'required'
16
+ | 'type'
17
+ | 'min'
18
+ | 'max'
19
+ | 'length'
20
+ | 'pattern'
21
+ | 'enum'
22
+ | 'custom'
23
+ | 'circular'
24
+ | 'max-depth'
25
+ | 'exception'
26
+ // Conditional
27
+ | 'conditional.underAge'
28
+ | 'conditional.blocked'
29
+ | 'conditional.notAllowed'
30
+ // I18nError — generic
31
+ | 'error.notFound'
32
+ | 'error.forbidden'
33
+ | 'error.unauthorized'
34
+ | 'error.invalid'
35
+ | 'error.duplicate'
36
+ | 'error.conflict'
37
+ // Account
38
+ | 'account.notFound'
39
+ | 'account.inactive'
40
+ | 'account.banned'
41
+ | 'account.insufficientBalance'
42
+ | 'account.insufficientCredits'
43
+ // User
44
+ | 'user.notFound'
45
+ | 'user.notVerified'
46
+ | 'user.noPermission'
47
+ // Order
48
+ | 'order.notPaid'
49
+ | 'order.paymentMissing'
50
+ | 'order.addressMissing'
51
+ // Format
52
+ | 'format.email'
53
+ | 'format.url'
54
+ | 'format.uuid'
55
+ | 'format.date'
56
+ | 'format.datetime'
57
+ | 'format.time'
58
+ | 'format.ipv4'
59
+ | 'format.ipv6'
60
+ | 'format.binary'
61
+ // String
62
+ | 'string.hostname'
63
+ | 'string.pattern'
64
+ | 'string.enum'
65
+ | 'string.length'
66
+ | 'string.alphanum'
67
+ | 'string.trim'
68
+ | 'string.lowercase'
69
+ | 'string.uppercase'
70
+ // Number
71
+ | 'number.base'
72
+ | 'number.min'
73
+ | 'number.max'
74
+ | 'number.integer'
75
+ | 'number.positive'
76
+ | 'number.negative'
77
+ | 'number.precision'
78
+ | 'number.port'
79
+ // Boolean
80
+ | 'boolean.base'
81
+ // Object
82
+ | 'object.base'
83
+ | 'object.min'
84
+ | 'object.max'
85
+ | 'object.unknown'
86
+ | 'object.missing'
87
+ | 'object.schema'
88
+ | 'additionalProperties'
89
+ // Array
90
+ | 'array.base'
91
+ | 'array.min'
92
+ | 'array.max'
93
+ | 'array.length'
94
+ | 'array.unique'
95
+ | 'array.sparse'
96
+ | 'array.includesRequired'
97
+ // Date
98
+ | 'date.base'
99
+ | 'date.min'
100
+ | 'date.max'
101
+ | 'date.format'
102
+ | 'date.greater'
103
+ | 'date.less'
104
+ // Any
105
+ | 'any.required'
106
+ | 'any.invalid'
107
+ | 'any.only'
108
+ | 'any.unknown'
109
+ // Patterns — formats
110
+ | 'pattern.phone'
111
+ | 'pattern.phone.international'
112
+ | 'pattern.idCard'
113
+ | 'pattern.creditCard'
114
+ | 'pattern.creditCard.visa'
115
+ | 'pattern.creditCard.mastercard'
116
+ | 'pattern.creditCard.amex'
117
+ | 'pattern.creditCard.discover'
118
+ | 'pattern.creditCard.jcb'
119
+ | 'pattern.creditCard.unionpay'
120
+ | 'pattern.licensePlate'
121
+ | 'pattern.postalCode'
122
+ | 'pattern.passport'
123
+ | 'pattern.objectId'
124
+ | 'pattern.hexColor'
125
+ | 'pattern.macAddress'
126
+ | 'pattern.cron'
127
+ | 'pattern.slug'
128
+ | 'pattern.domain'
129
+ | 'pattern.ip'
130
+ | 'pattern.base64'
131
+ | 'pattern.jwt'
132
+ | 'pattern.json'
133
+ // Patterns — username & password
134
+ | 'pattern.username'
135
+ | 'pattern.password.weak'
136
+ | 'pattern.password.medium'
137
+ | 'pattern.password.strong'
138
+ | 'pattern.password.veryStrong'
139
+ // Patterns — union
140
+ | 'pattern.emailOrPhone'
141
+ | 'pattern.usernameOrEmail'
142
+ | 'pattern.httpOrHttps'
143
+ // oneOf
144
+ | 'oneOf'
145
+ | 'oneOf.invalid'
146
+ // Error fallback
147
+ | 'UNKNOWN_ERROR'
148
+ | 'CUSTOM_VALIDATION_FAILED'
149
+ | 'ASYNC_VALIDATION_NOT_SUPPORTED'
150
+ | 'VALIDATE_MUST_BE_FUNCTION'
151
+
152
+ /**
153
+ * Complete locale interface — every locale file must implement this (Record<LocaleKey, LocaleMessage>).
154
+ * TypeScript compile-time guarantee: no key can be missing.
155
+ */
156
+ export type LocaleMessages = Record<LocaleKey, LocaleMessage>
@@ -1,4 +1,6 @@
1
- module.exports = {
1
+ import type { LocaleMessages } from './types.js'
2
+
3
+ const zhCN: LocaleMessages = {
2
4
  // Generic
3
5
  required: '{{#label}}不能为空',
4
6
  type: '{{#label}}应该是 {{#expected}} 类型',
@@ -12,13 +14,12 @@ module.exports = {
12
14
  'max-depth': '超过最大递归深度 ({{#depth}}) at {{#label}}',
13
15
  exception: '{{#label}}验证异常: {{#message}}',
14
16
 
15
- // Conditional (ConditionalBuilder)
17
+ // Conditional
16
18
  'conditional.underAge': '未成年用户不能注册',
17
19
  'conditional.blocked': '账号已被封禁',
18
20
  'conditional.notAllowed': '不允许注册',
19
21
 
20
- // I18nError - 通用错误消息 (v1.1.1)
21
- // I18nError - 通用错误消息 (v1.1.1)
22
+ // I18nError generic
22
23
  'error.notFound': '找不到{{#resource}}',
23
24
  'error.forbidden': '没有权限访问{{#resource}}',
24
25
  'error.unauthorized': '未授权,请先登录',
@@ -26,34 +27,27 @@ module.exports = {
26
27
  'error.duplicate': '{{#resource}}已存在',
27
28
  'error.conflict': '操作冲突: {{#reason}}',
28
29
 
29
- // I18nError - 账户相关 (v1.1.1)
30
- // v1.1.5: 部分使用对象格式示例
31
- 'account.notFound': {
32
- code: 'ACCOUNT_NOT_FOUND',
33
- message: '账户不存在'
34
- },
30
+ // Account
31
+ 'account.notFound': { code: 'ACCOUNT_NOT_FOUND', message: '账户不存在' },
35
32
  'account.inactive': '账户未激活',
36
33
  'account.banned': '账户已被封禁',
37
34
  'account.insufficientBalance': {
38
35
  code: 'INSUFFICIENT_BALANCE',
39
- message: '余额不足,当前余额{{#balance}},需要{{#required}}'
36
+ message: '余额不足,当前余额{{#balance}},需要{{#required}}',
40
37
  },
41
38
  'account.insufficientCredits': '积分不足,当前积分{{#credits}},需要{{#required}}',
42
39
 
43
- // I18nError - 用户相关 (v1.1.1)
40
+ // User
44
41
  'user.notFound': '用户不存在',
45
42
  'user.notVerified': '用户未验证',
46
43
  'user.noPermission': '没有管理员权限',
47
44
 
48
- // I18nError - 订单相关 (v1.1.1)
49
- 'order.notPaid': {
50
- code: 'ORDER_NOT_PAID',
51
- message: '订单未支付'
52
- },
45
+ // Order
46
+ 'order.notPaid': { code: 'ORDER_NOT_PAID', message: '订单未支付' },
53
47
  'order.paymentMissing': '缺少支付信息',
54
48
  'order.addressMissing': '缺少收货地址',
55
49
 
56
- // Formats
50
+ // Format
57
51
  'format.email': '{{#label}}必须是有效的邮箱地址',
58
52
  'format.url': '{{#label}}必须是有效的URL地址',
59
53
  'format.uuid': '{{#label}}必须是有效的UUID',
@@ -68,7 +62,6 @@ module.exports = {
68
62
  'string.hostname': '{{#label}}必须是有效的主机名',
69
63
  'string.pattern': '{{#label}}格式不符合要求',
70
64
  'string.enum': '{{#label}}必须是以下值之一: {{#valids}}',
71
- // v1.0.2新增
72
65
  'string.length': '{{#label}}长度必须是{{#limit}}个字符',
73
66
  'string.alphanum': '{{#label}}只能包含字母和数字',
74
67
  'string.trim': '{{#label}}不能包含前后空格',
@@ -82,7 +75,6 @@ module.exports = {
82
75
  'number.integer': '{{#label}}必须是整数',
83
76
  'number.positive': '{{#label}}必须是正数',
84
77
  'number.negative': '{{#label}}必须是负数',
85
- // v1.0.2新增
86
78
  'number.precision': '{{#label}}小数位数不能超过{{#limit}}位',
87
79
  'number.port': '{{#label}}必须是有效的端口号(1-65535)',
88
80
 
@@ -94,10 +86,8 @@ module.exports = {
94
86
  'object.min': '{{#label}}至少需要{{#limit}}个属性',
95
87
  'object.max': '{{#label}}最多只能有{{#limit}}个属性',
96
88
  'object.unknown': '{{#label}}包含未知属性: {{#key}}',
97
- // v1.0.2新增
98
89
  'object.missing': '{{#label}}缺少必需属性',
99
90
  'object.schema': '{{#label}}包含额外属性',
100
- // v1.1.6新增 - additionalProperties
101
91
  'additionalProperties': '{{#label}}不允许有额外属性: {{#key}}',
102
92
 
103
93
  // Array
@@ -106,7 +96,6 @@ module.exports = {
106
96
  'array.max': '{{#label}}最多只能有{{#limit}}个元素',
107
97
  'array.length': '{{#label}}必须有{{#limit}}个元素',
108
98
  'array.unique': '{{#label}}不能包含重复元素',
109
- // v1.0.2新增
110
99
  'array.sparse': '{{#label}}不能是稀疏数组',
111
100
  'array.includesRequired': '{{#label}}必须包含指定元素',
112
101
 
@@ -114,7 +103,6 @@ module.exports = {
114
103
  'date.base': '{{#label}}必须是有效的日期',
115
104
  'date.min': '{{#label}}不能早于{{#limit}}',
116
105
  'date.max': '{{#label}}不能晚于{{#limit}}',
117
- // v1.0.2新增
118
106
  'date.format': '{{#label}}日期格式不正确',
119
107
  'date.greater': '{{#label}}必须晚于{{#limit}}',
120
108
  'date.less': '{{#label}}必须早于{{#limit}}',
@@ -125,7 +113,7 @@ module.exports = {
125
113
  'any.only': '{{#label}}必须匹配{{#valids}}',
126
114
  'any.unknown': '不允许字段{{#key}}',
127
115
 
128
- // Patterns (Legacy/Specific)
116
+ // Patterns
129
117
  'pattern.phone': '请输入有效的手机号',
130
118
  'pattern.phone.international': '请输入有效的国际手机号',
131
119
  'pattern.idCard': '请输入有效的身份证号码',
@@ -144,34 +132,29 @@ module.exports = {
144
132
  'pattern.macAddress': '无效的 MAC 地址',
145
133
  'pattern.cron': '无效的 Cron 表达式',
146
134
  'pattern.slug': 'URL别名只能包含小写字母、数字和连字符',
147
- // v1.0.2新增
148
135
  'pattern.domain': '{{#label}}必须是有效的域名',
149
136
  'pattern.ip': '{{#label}}必须是有效的IP地址',
150
137
  'pattern.base64': '{{#label}}必须是有效的Base64编码',
151
138
  'pattern.jwt': '{{#label}}必须是有效的JWT令牌',
152
139
  'pattern.json': '{{#label}}必须是有效的JSON字符串',
153
-
154
- // Username & Password
155
140
  'pattern.username': '用户名必须以字母开头,只能包含字母、数字和下划线',
156
141
  'pattern.password.weak': '密码至少6位',
157
142
  'pattern.password.medium': '密码至少8位,需包含字母和数字',
158
143
  'pattern.password.strong': '密码至少8位,需包含大小写字母和数字',
159
144
  'pattern.password.veryStrong': '密码至少10位,需包含大小写字母、数字和特殊字符',
160
-
161
- // Union Type (联合类型)
162
145
  'pattern.emailOrPhone': '必须是邮箱或手机号',
163
146
  'pattern.usernameOrEmail': '必须是用户名或邮箱',
164
147
  'pattern.httpOrHttps': '必须是 http 或 https 开头的 URL',
165
148
 
166
- // oneOf (跨类型联合) - v1.1.0 新增
149
+ // oneOf
167
150
  oneOf: '{{#label}}必须匹配以下类型之一',
168
151
  'oneOf.invalid': '{{#label}}的值不匹配任何允许的类型',
169
152
 
170
- // Unknown error fallback
171
- 'UNKNOWN_ERROR': '未知的验证错误',
153
+ // Error fallback
154
+ UNKNOWN_ERROR: '未知的验证错误',
155
+ CUSTOM_VALIDATION_FAILED: '自定义验证失败',
156
+ ASYNC_VALIDATION_NOT_SUPPORTED: '同步验证不支持异步操作',
157
+ VALIDATE_MUST_BE_FUNCTION: 'validate 必须是一个函数',
158
+ }
172
159
 
173
- // Custom validation
174
- 'CUSTOM_VALIDATION_FAILED': '自定义验证失败',
175
- 'ASYNC_VALIDATION_NOT_SUPPORTED': '同步验证不支持异步操作',
176
- 'VALIDATE_MUST_BE_FUNCTION': 'validate 必须是一个函数'
177
- };
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
+ }