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.
- package/CHANGELOG.md +87 -210
- package/README.md +391 -2249
- package/dist/DslBuilder-DQDN0ZxZ.d.cts +341 -0
- package/dist/DslBuilder-DkLaOo9Q.d.ts +341 -0
- package/dist/Validator-C7GsVQOH.d.cts +192 -0
- package/dist/Validator-hFWKGxir.d.ts +192 -0
- package/dist/index.cjs +6594 -0
- package/dist/index.d.cts +1145 -0
- package/dist/index.d.ts +1145 -0
- package/dist/index.js +6528 -0
- package/dist/plugin-CIKtTMtS.d.cts +246 -0
- package/dist/plugin-CIKtTMtS.d.ts +246 -0
- package/dist/plugins/custom-format.cjs +3802 -0
- package/dist/plugins/custom-format.d.cts +12 -0
- package/dist/plugins/custom-format.d.ts +12 -0
- package/dist/plugins/custom-format.js +3772 -0
- package/dist/plugins/custom-type-example.cjs +3795 -0
- package/dist/plugins/custom-type-example.d.cts +8 -0
- package/dist/plugins/custom-type-example.d.ts +8 -0
- package/dist/plugins/custom-type-example.js +3765 -0
- package/dist/plugins/custom-validator.cjs +146 -0
- package/dist/plugins/custom-validator.d.cts +10 -0
- package/dist/plugins/custom-validator.d.ts +10 -0
- package/dist/plugins/custom-validator.js +121 -0
- package/docs/FEATURE-INDEX.md +102 -68
- package/docs/add-custom-locale.md +48 -35
- package/docs/add-keyword.md +24 -0
- package/docs/api-reference.md +396 -154
- package/docs/api.md +13 -0
- package/docs/best-practices-project-structure.md +19 -10
- package/docs/best-practices.md +93 -53
- package/docs/cache-manager.md +23 -15
- package/docs/compile.md +45 -0
- package/docs/conditional-api.md +40 -11
- package/docs/custom-extensions-guide.md +80 -152
- package/docs/design-philosophy.md +76 -71
- package/docs/doc-index.md +324 -0
- package/docs/dsl-syntax.md +69 -19
- package/docs/dynamic-locale.md +24 -14
- package/docs/enum.md +12 -5
- package/docs/error-handling.md +53 -44
- package/docs/export-guide.md +47 -8
- package/docs/export-limitations.md +27 -11
- package/docs/faq.md +86 -67
- package/docs/frontend-i18n-guide.md +26 -12
- package/docs/i18n-user-guide.md +60 -47
- package/docs/i18n.md +51 -32
- package/docs/index.md +48 -0
- package/docs/json-schema-basics.md +40 -0
- package/docs/label-vs-description.md +12 -3
- package/docs/markdown-exporter.md +15 -6
- package/docs/mongodb-exporter.md +11 -4
- package/docs/multi-language.md +26 -0
- package/docs/multi-type-support.md +26 -33
- package/docs/mysql-exporter.md +9 -2
- package/docs/number-operators.md +12 -5
- package/docs/optional-marker-guide.md +28 -23
- package/docs/performance-guide.md +49 -0
- package/docs/plugin-system.md +205 -366
- package/docs/plugin-type-registration.md +34 -0
- package/docs/postgresql-exporter.md +9 -2
- package/docs/public/favicon.svg +5 -0
- package/docs/quick-start.md +37 -363
- package/docs/runtime-locale-support.md +20 -9
- package/docs/schema-helper.md +10 -5
- package/docs/schema-utils-advanced-issues.md +23 -0
- package/docs/schema-utils-best-practices.md +20 -0
- package/docs/schema-utils-chaining.md +7 -0
- package/docs/schema-utils.md +76 -42
- package/docs/security-checklist.md +20 -0
- package/docs/string-extensions.md +17 -9
- package/docs/troubleshooting.md +36 -21
- package/docs/type-converter.md +41 -50
- package/docs/type-reference.md +38 -15
- package/docs/typescript-guide.md +53 -42
- package/docs/union-type-guide.md +11 -1
- package/docs/union-types.md +10 -3
- package/docs/validate-async.md +36 -25
- package/docs/validate-batch.md +49 -0
- package/docs/validate-dsl-object-support.md +33 -28
- package/docs/validate.md +36 -16
- package/docs/validation-guide.md +25 -7
- package/docs/validator.md +39 -0
- package/package.json +85 -27
- package/plugins/custom-format.cjs +8 -0
- package/plugins/custom-type-example.cjs +8 -0
- package/plugins/custom-validator.cjs +8 -0
- package/src/adapters/DslAdapter.ts +111 -0
- package/src/adapters/index.ts +1 -0
- package/src/config/constants.ts +83 -0
- package/src/config/index.ts +2 -0
- package/src/config/patterns.ts +77 -0
- package/src/core/CacheManager.ts +159 -0
- package/src/core/ConditionalBuilder.ts +382 -0
- package/src/core/ConditionalRuntime.ts +28 -0
- package/src/core/ConditionalValidator.ts +255 -0
- package/src/core/DslBuilder.ts +677 -0
- package/src/core/ErrorCodes.ts +38 -0
- package/src/core/ErrorFormatter.ts +271 -0
- package/src/core/JSONSchemaCore.ts +65 -0
- package/src/core/Locale.ts +187 -0
- package/src/core/MessageTemplate.ts +42 -0
- package/src/core/ObjectDslBuilder.ts +64 -0
- package/src/core/PluginManager.ts +326 -0
- package/src/core/StringExtensions.ts +140 -0
- package/src/core/TemplateEngine.ts +44 -0
- package/src/core/Validator.ts +448 -0
- package/src/errors/I18nError.ts +159 -0
- package/src/errors/ValidationError.ts +105 -0
- package/src/exporters/BaseExporter.ts +60 -0
- package/src/exporters/MarkdownExporter.ts +305 -0
- package/src/exporters/MongoDBExporter.ts +126 -0
- package/src/exporters/MySQLExporter.ts +155 -0
- package/src/exporters/PostgreSQLExporter.ts +222 -0
- package/src/exporters/index.ts +18 -0
- package/src/index.ts +633 -0
- package/{lib/locales/en-US.js → src/locales/en-US.ts} +21 -37
- package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +63 -16
- package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +74 -27
- package/src/locales/index.ts +103 -0
- package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +59 -17
- package/src/locales/types.ts +156 -0
- package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +21 -38
- package/src/parser/ConstraintParser.ts +101 -0
- package/src/parser/DslParser.ts +470 -0
- package/src/parser/SchemaCompiler.ts +66 -0
- package/src/parser/TypeRegistry.ts +250 -0
- package/src/parser/index.ts +6 -0
- package/src/plugins/custom-format.ts +126 -0
- package/src/plugins/custom-type-example.ts +108 -0
- package/src/plugins/custom-validator.ts +140 -0
- package/src/types/conditional.ts +28 -0
- package/src/types/config.ts +59 -0
- package/src/types/dsl.ts +131 -0
- package/src/types/error.ts +60 -0
- package/src/types/index.ts +17 -0
- package/src/types/infer.ts +128 -0
- package/src/types/plugin.ts +58 -0
- package/src/types/safe-regex.d.ts +9 -0
- package/src/types/schema.ts +66 -0
- package/src/types/validate.ts +71 -0
- package/src/utils/SchemaHelper.ts +196 -0
- package/src/utils/SchemaUtils.ts +346 -0
- package/src/utils/TypeConverter.ts +215 -0
- package/src/utils/index.ts +10 -0
- package/src/validators/CustomKeywords.ts +477 -0
- package/.eslintignore +0 -11
- package/.eslintrc.json +0 -27
- package/CONTRIBUTING.md +0 -368
- package/STATUS.md +0 -491
- package/changelogs/v1.0.0.md +0 -328
- package/changelogs/v1.0.9.md +0 -367
- package/changelogs/v1.1.0.md +0 -389
- package/changelogs/v1.1.1.md +0 -308
- package/changelogs/v1.1.2.md +0 -183
- package/changelogs/v1.1.3.md +0 -161
- package/changelogs/v1.1.4.md +0 -432
- package/changelogs/v1.1.5.md +0 -493
- package/changelogs/v1.1.6.md +0 -211
- package/changelogs/v1.1.8.md +0 -376
- package/changelogs/v1.2.3.md +0 -124
- package/docs/INDEX.md +0 -252
- package/docs/issues-resolved-summary.md +0 -196
- package/docs/performance-benchmark-report.md +0 -179
- package/docs/performance-quick-reference.md +0 -123
- package/docs/user-questions-answered.md +0 -353
- package/docs/validation-rules-v1.0.2.md +0 -1608
- package/examples/README.md +0 -81
- package/examples/array-dsl-example.js +0 -227
- package/examples/conditional-example.js +0 -288
- package/examples/conditional-non-object.js +0 -129
- package/examples/conditional-validate-example.js +0 -321
- package/examples/custom-extension.js +0 -85
- package/examples/dsl-match-example.js +0 -74
- package/examples/dsl-style.js +0 -118
- package/examples/dynamic-locale-configuration.js +0 -348
- package/examples/dynamic-locale-example.js +0 -287
- package/examples/enum.examples.js +0 -324
- package/examples/export-demo.js +0 -130
- package/examples/express-integration.js +0 -376
- package/examples/i18n-error-handling-complete.js +0 -381
- package/examples/i18n-error-handling-quickstart.md +0 -0
- package/examples/i18n-error.examples.js +0 -181
- package/examples/i18n-full-demo.js +0 -301
- package/examples/i18n-memory-safety.examples.js +0 -268
- package/examples/markdown-export.js +0 -71
- package/examples/middleware-usage.js +0 -93
- package/examples/new-features-comparison.js +0 -315
- package/examples/password-reset/README.md +0 -153
- package/examples/password-reset/schema.js +0 -26
- package/examples/password-reset/test.js +0 -101
- package/examples/plugin-system.examples.js +0 -205
- package/examples/schema-utils-chaining.examples.js +0 -250
- package/examples/simple-example.js +0 -122
- package/examples/slug.examples.js +0 -179
- package/examples/string-extensions.js +0 -297
- package/examples/union-type-example.js +0 -127
- package/examples/union-types-example.js +0 -77
- package/examples/user-registration/README.md +0 -156
- package/examples/user-registration/routes.js +0 -92
- package/examples/user-registration/schema.js +0 -150
- package/examples/user-registration/server.js +0 -74
- package/index.d.ts +0 -3540
- package/index.js +0 -457
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -871
- package/lib/adapters/index.js +0 -20
- package/lib/config/constants.js +0 -286
- package/lib/config/patterns/common.js +0 -47
- package/lib/config/patterns/creditCard.js +0 -9
- package/lib/config/patterns/idCard.js +0 -9
- package/lib/config/patterns/index.js +0 -9
- package/lib/config/patterns/licensePlate.js +0 -4
- package/lib/config/patterns/passport.js +0 -4
- package/lib/config/patterns/phone.js +0 -9
- package/lib/config/patterns/postalCode.js +0 -5
- package/lib/core/CacheManager.js +0 -376
- package/lib/core/ConditionalBuilder.js +0 -503
- package/lib/core/DslBuilder.js +0 -1400
- package/lib/core/ErrorCodes.js +0 -233
- package/lib/core/ErrorFormatter.js +0 -445
- package/lib/core/JSONSchemaCore.js +0 -347
- package/lib/core/Locale.js +0 -130
- package/lib/core/MessageTemplate.js +0 -98
- package/lib/core/PluginManager.js +0 -448
- package/lib/core/StringExtensions.js +0 -240
- package/lib/core/Validator.js +0 -654
- package/lib/errors/I18nError.js +0 -328
- package/lib/errors/ValidationError.js +0 -191
- package/lib/exporters/MarkdownExporter.js +0 -420
- package/lib/exporters/MongoDBExporter.js +0 -162
- package/lib/exporters/MySQLExporter.js +0 -212
- package/lib/exporters/PostgreSQLExporter.js +0 -289
- package/lib/exporters/index.js +0 -24
- package/lib/locales/index.js +0 -8
- package/lib/utils/LRUCache.js +0 -174
- package/lib/utils/SchemaHelper.js +0 -240
- package/lib/utils/SchemaUtils.js +0 -445
- package/lib/utils/TypeConverter.js +0 -245
- package/lib/utils/index.js +0 -13
- package/lib/validators/CustomKeywords.js +0 -616
- package/lib/validators/index.js +0 -11
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# 自定义类型注册
|
|
2
|
+
|
|
3
|
+
当前版本通过 `TypeRegistry` 提供类型注册能力;如果你更偏向 DSL 侧入口,也可以使用 `DslBuilder.registerType()`,它内部会委托给 `TypeRegistry`。
|
|
4
|
+
|
|
5
|
+
```javascript
|
|
6
|
+
const { TypeRegistry, dsl } = require('schema-dsl');
|
|
7
|
+
|
|
8
|
+
TypeRegistry.register('evenNumber', {
|
|
9
|
+
baseSchema: { type: 'number', multipleOf: 2 }
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const schema = dsl({ value: 'evenNumber!' });
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
如果你希望统一从 Builder 侧管理自定义类型,也可以这样写:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
const { DslBuilder } = require('schema-dsl');
|
|
19
|
+
|
|
20
|
+
DslBuilder.registerType('orderCode', {
|
|
21
|
+
type: 'string',
|
|
22
|
+
pattern: '^ORD\\d{6}$'
|
|
23
|
+
});
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
插件化扩展可结合 [plugin-system.md](./plugin-system.md) 使用。
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## 对应示例文件
|
|
31
|
+
|
|
32
|
+
**示例入口**: [plugin-type-registration.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/plugin-type-registration.ts)
|
|
33
|
+
**说明**: 同时覆盖 `TypeRegistry.register()` 和 `DslBuilder.registerType()` 两条入口,以及注册后的真实验证与清理流程。
|
|
34
|
+
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# PostgreSQL 导出器文档
|
|
2
2
|
|
|
3
|
-
> **模块**: `
|
|
3
|
+
> **模块**: `src/exporters/PostgreSQLExporter.ts`
|
|
4
4
|
|
|
5
5
|
> **用途**: 将 JSON Schema 转换为 PostgreSQL CREATE TABLE 语句
|
|
6
6
|
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
|
|
21
21
|
## 概述
|
|
22
22
|
|
|
23
|
-
`PostgreSQLExporter` 将
|
|
23
|
+
`PostgreSQLExporter` 将 schema-dsl 生成的 JSON Schema 转换为 PostgreSQL 的 DDL 语句,支持丰富的 PostgreSQL 特性。
|
|
24
24
|
|
|
25
25
|
### 核心功能
|
|
26
26
|
|
|
@@ -302,3 +302,10 @@ exporter.generateIndex('users', 'metadata', { method: 'gin' });
|
|
|
302
302
|
- [TypeConverter](type-converter.md)
|
|
303
303
|
- [**导出限制说明**](export-limitations.md) ⚠️
|
|
304
304
|
|
|
305
|
+
---
|
|
306
|
+
|
|
307
|
+
## 对应示例文件
|
|
308
|
+
|
|
309
|
+
**示例入口**: [postgresql-exporter.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/postgresql-exporter.ts)
|
|
310
|
+
**说明**: 覆盖 PostgreSQL DDL 导出、CHECK 约束示意,以及 `generateIndex()` 生成 `gin` 索引。
|
|
311
|
+
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64" fill="none">
|
|
2
|
+
<rect width="64" height="64" rx="14" fill="#0F172A" />
|
|
3
|
+
<path d="M18 22.5L32 14L46 22.5V41.5L32 50L18 41.5V22.5Z" fill="#38BDF8" />
|
|
4
|
+
<path d="M32 20L40 24.8V34.2L32 39L24 34.2V24.8L32 20Z" fill="#E2E8F0" />
|
|
5
|
+
</svg>
|
package/docs/quick-start.md
CHANGED
|
@@ -28,6 +28,10 @@
|
|
|
28
28
|
npm install schema-dsl
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
+
> **Node.js 要求**:`>=18.0.0`
|
|
32
|
+
>
|
|
33
|
+
> 当前 TypeScript 重构版以 `Node.js >=18.0.0` 为唯一运行时基线,不再承诺旧 Node 版本兼容。
|
|
34
|
+
|
|
31
35
|
---
|
|
32
36
|
|
|
33
37
|
## 📖 5分钟快速入门
|
|
@@ -135,34 +139,32 @@ const schema = dsl({
|
|
|
135
139
|
### 4. 完整示例(2分钟)
|
|
136
140
|
|
|
137
141
|
```javascript
|
|
138
|
-
const { dsl,
|
|
142
|
+
const { dsl, validate } = require('schema-dsl');
|
|
139
143
|
|
|
140
144
|
// 定义用户注册Schema
|
|
141
145
|
const registerSchema = dsl({
|
|
142
146
|
// 用户名:正则验证
|
|
143
|
-
username: 'string:3-32!'
|
|
147
|
+
username: dsl('string:3-32!')
|
|
144
148
|
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
145
149
|
.label('用户名')
|
|
146
|
-
.
|
|
147
|
-
|
|
148
|
-
'min': '至少3个字符',
|
|
149
|
-
'max': '最多32个字符'
|
|
150
|
+
.error({
|
|
151
|
+
pattern: '只能包含字母、数字和下划线'
|
|
150
152
|
}),
|
|
151
153
|
|
|
152
154
|
// 邮箱:标签
|
|
153
|
-
email: 'email!'.label('邮箱地址'),
|
|
155
|
+
email: dsl('email!').label('邮箱地址'),
|
|
154
156
|
|
|
155
157
|
// 密码:复杂正则
|
|
156
|
-
password: 'string:8-64!'
|
|
158
|
+
password: dsl('string:8-64!')
|
|
157
159
|
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
|
|
158
160
|
.label('密码')
|
|
159
|
-
.
|
|
160
|
-
|
|
161
|
+
.error({
|
|
162
|
+
pattern: '必须包含大小写字母和数字'
|
|
161
163
|
}),
|
|
162
164
|
|
|
163
165
|
// 简单字段
|
|
164
166
|
age: 'number:18-120',
|
|
165
|
-
|
|
167
|
+
role: 'user|admin'
|
|
166
168
|
});
|
|
167
169
|
|
|
168
170
|
// 验证数据
|
|
@@ -171,7 +173,7 @@ const testData = {
|
|
|
171
173
|
email: 'john@example.com',
|
|
172
174
|
password: 'Password123',
|
|
173
175
|
age: 25,
|
|
174
|
-
|
|
176
|
+
role: 'user'
|
|
175
177
|
};
|
|
176
178
|
|
|
177
179
|
const result = validate(registerSchema, testData);
|
|
@@ -236,12 +238,13 @@ const formSchema = dsl({
|
|
|
236
238
|
|
|
237
239
|
### 自定义验证
|
|
238
240
|
|
|
241
|
+
> `.custom()` 当前仅支持同步函数;如果需要异步查重,请在 `validate()` / `validateAsync()` 通过后于业务层单独执行。
|
|
242
|
+
|
|
239
243
|
```javascript
|
|
240
244
|
const schema = dsl({
|
|
241
245
|
username: 'string:3-32!'
|
|
242
|
-
.custom(
|
|
243
|
-
|
|
244
|
-
if (exists) {
|
|
246
|
+
.custom((value) => {
|
|
247
|
+
if (value === 'admin') {
|
|
245
248
|
return '用户名已存在';
|
|
246
249
|
}
|
|
247
250
|
})
|
|
@@ -277,9 +280,9 @@ const schema = dsl({
|
|
|
277
280
|
|
|
278
281
|
### 示例代码
|
|
279
282
|
|
|
280
|
-
- [
|
|
281
|
-
|
|
282
|
-
|
|
283
|
+
- [Quick Start 完整示例](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/quick-start.ts)
|
|
284
|
+
|
|
285
|
+
其余主题示例现在都已分别挂到各自文档底部,并统一切到稳定 GitHub 示例链接。
|
|
283
286
|
|
|
284
287
|
### 高级功能
|
|
285
288
|
|
|
@@ -344,31 +347,20 @@ Schema-DSL 使用**运行时解析 DSL**,而非编译时构建(如 Zod),
|
|
|
344
347
|
|
|
345
348
|
#### ⚠️ 性能权衡
|
|
346
349
|
|
|
347
|
-
|
|
350
|
+
S1 有效数据与 Zod 持平,S3 嵌套场景快约 28%,无效数据公平对比快 89x:
|
|
348
351
|
|
|
349
|
-
| 库名 |
|
|
352
|
+
| 库名 | 性能 | 场景 |
|
|
350
353
|
|------|-----------|------|
|
|
351
|
-
| Ajv |
|
|
352
|
-
|
|
|
353
|
-
| **Schema-DSL** | **
|
|
354
|
-
|
|
|
355
|
-
|
|
|
354
|
+
| Ajv (raw) | 4.732M ops/s | 底层引擎,无 DSL 层 |
|
|
355
|
+
| **Schema-DSL** | **1.301M ops/s**(S1有效) | 全功能(DSL + i18n + coerce)|
|
|
356
|
+
| **Schema-DSL** | **1.205M ops/s**(S2 无效,均无 i18n)| 公平对比(均无 i18n)|
|
|
357
|
+
| Zod | 1.305M ops/s(S1有效)/ 13.49K(S2 无效)| 编译时构建,错误路径异常驱动 |
|
|
358
|
+
| Joi | 154K ops/s | 功能丰富 |
|
|
356
359
|
|
|
357
360
|
**结论**:
|
|
358
|
-
- ✅
|
|
359
|
-
- ✅
|
|
360
|
-
-
|
|
361
|
-
|
|
362
|
-
**权衡**:
|
|
363
|
-
```
|
|
364
|
-
损失: 比 Zod 慢 1.9倍
|
|
365
|
-
换来:
|
|
366
|
-
✅ 代码量减少 65%
|
|
367
|
-
✅ 完全动态的验证规则
|
|
368
|
-
✅ 多租户/配置驱动支持
|
|
369
|
-
✅ 前后端共享规则
|
|
370
|
-
✅ 低代码平台基础
|
|
371
|
-
```
|
|
361
|
+
- ✅ S3 嵌套有效场景比 Zod 快 **28%**;S1 简单有效场景持平(差 <1%)
|
|
362
|
+
- ✅ 无效数据公平对比(均无 i18n)比 Zod 快 **89x**
|
|
363
|
+
- ✅ 内置缓存,热路径零解析开销
|
|
372
364
|
|
|
373
365
|
### 适用场景
|
|
374
366
|
|
|
@@ -413,13 +405,13 @@ uninstallStringExtensions();
|
|
|
413
405
|
|
|
414
406
|
### Q: 支持TypeScript吗?
|
|
415
407
|
|
|
416
|
-
**A**: 支持!
|
|
408
|
+
**A**: 支持!schema-dsl 提供完整的 TypeScript 类型定义。
|
|
417
409
|
|
|
418
410
|
---
|
|
419
411
|
|
|
420
412
|
## 🎉 恭喜!
|
|
421
413
|
|
|
422
|
-
你已经掌握了
|
|
414
|
+
你已经掌握了 schema-dsl 的核心用法!
|
|
423
415
|
|
|
424
416
|
**核心要点**:
|
|
425
417
|
1. ✅ DSL语法简洁直观
|
|
@@ -431,331 +423,13 @@ uninstallStringExtensions();
|
|
|
431
423
|
|
|
432
424
|
---
|
|
433
425
|
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
**最后更新**: 2025-12-26
|
|
437
|
-
- [🔧 自定义验证](#-自定义验证)
|
|
438
|
-
- [🗄️ 数据库导出](#️-数据库导出)
|
|
439
|
-
- [📚 下一步](#-下一步)
|
|
440
|
-
|
|
441
|
-
---
|
|
442
|
-
|
|
443
|
-
## 🚀 安装
|
|
444
|
-
|
|
445
|
-
```bash
|
|
446
|
-
npm install schema-dsl
|
|
447
|
-
```
|
|
448
|
-
|
|
449
|
-
---
|
|
450
|
-
|
|
451
|
-
## 📖 5分钟快速入门
|
|
452
|
-
|
|
453
|
-
### 1. Hello World(30秒)
|
|
454
|
-
|
|
455
|
-
```javascript
|
|
456
|
-
const { dsl, Validator } = require('schema-dsl');
|
|
457
|
-
|
|
458
|
-
// 定义Schema
|
|
459
|
-
const schema = dsl({
|
|
460
|
-
name: 'string:1-50!',
|
|
461
|
-
email: 'email!'
|
|
462
|
-
});
|
|
463
|
-
|
|
464
|
-
// 验证数据
|
|
465
|
-
const validator = new Validator();
|
|
466
|
-
const result = validator.validate(schema, {
|
|
467
|
-
name: '张三',
|
|
468
|
-
email: 'zhangsan@example.com'
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
console.log(result.valid); // true
|
|
472
|
-
```
|
|
473
|
-
|
|
474
|
-
**解释**:
|
|
475
|
-
- `'string:1-50!'` - 必填字符串,长度1-50
|
|
476
|
-
- `'email!'` - 必填邮箱
|
|
477
|
-
- `!` 表示必填
|
|
478
|
-
|
|
479
|
-
---
|
|
480
|
-
|
|
481
|
-
### 2. DSL 语法速查(1分钟)
|
|
482
|
-
|
|
483
|
-
```javascript
|
|
484
|
-
// 基本类型
|
|
485
|
-
'string' // 字符串
|
|
486
|
-
'number' // 数字
|
|
487
|
-
'integer' // 整数
|
|
488
|
-
'boolean' // 布尔值
|
|
489
|
-
'email' // 邮箱
|
|
490
|
-
'url' // URL
|
|
491
|
-
'date' // 日期
|
|
492
|
-
|
|
493
|
-
// 约束
|
|
494
|
-
'string:3-32' // 长度3-32(范围)
|
|
495
|
-
'string:100' // 最大长度100(简写)
|
|
496
|
-
'string:-100' // 最大长度100(明确写法)
|
|
497
|
-
'string:10-' // 最小长度10(无最大限制)
|
|
498
|
-
'number:18-120' // 范围18-120
|
|
499
|
-
|
|
500
|
-
// 必填
|
|
501
|
-
'string!' // 必填字符串
|
|
502
|
-
'email!' // 必填邮箱
|
|
503
|
-
|
|
504
|
-
// 枚举
|
|
505
|
-
'active|inactive|pending' // 三选一
|
|
506
|
-
|
|
507
|
-
// 数组
|
|
508
|
-
'array<string>' // 字符串数组
|
|
509
|
-
'array:1-10<string>' // 1-10个字符串
|
|
510
|
-
'array<string:1-50>' // 带约束的数组元素
|
|
511
|
-
```
|
|
512
|
-
|
|
513
|
-
**语法规则**:
|
|
514
|
-
- `type:max` → 最大值(简写)
|
|
515
|
-
- `type:min-max` → 范围
|
|
516
|
-
- `type:min-` → 只限最小
|
|
517
|
-
- `type:-max` → 只限最大
|
|
518
|
-
|
|
519
|
-
---
|
|
520
|
-
|
|
521
|
-
### 3. String 扩展 - 核心特性(2分钟)
|
|
522
|
-
|
|
523
|
-
字符串支持链式调用:
|
|
426
|
+
## 对应示例文件
|
|
524
427
|
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
// ✨ 字符串直接链式调用,无需 dsl() 包裹
|
|
528
|
-
email: 'email!'
|
|
529
|
-
.pattern(/custom/)
|
|
530
|
-
.label('邮箱地址'),
|
|
531
|
-
|
|
532
|
-
username: 'string:3-32!'
|
|
533
|
-
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
534
|
-
.messages({
|
|
535
|
-
'string.pattern': '只能包含字母、数字和下划线'
|
|
536
|
-
})
|
|
537
|
-
.label('用户名'),
|
|
538
|
-
|
|
539
|
-
// 简单字段仍然可以用纯DSL
|
|
540
|
-
age: 'number:18-120',
|
|
541
|
-
role: 'user|admin'
|
|
542
|
-
});
|
|
543
|
-
```
|
|
544
|
-
|
|
545
|
-
**可用方法**:
|
|
546
|
-
- `.pattern(regex)` - 正则验证
|
|
547
|
-
- `.label(text)` - 字段标签
|
|
548
|
-
- `.messages(obj)` - 自定义消息
|
|
549
|
-
- `.description(text)` - 描述
|
|
550
|
-
- `.custom(fn)` - 自定义验证器
|
|
428
|
+
**示例入口**: [quick-start.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/quick-start.ts)
|
|
429
|
+
**说明**: 覆盖快速上手中的 Hello World、String 扩展、用户注册示例,以及 `validate()` 与 `Validator.compile()` 的基础复用路径,可直接运行参考。
|
|
551
430
|
|
|
552
431
|
---
|
|
553
432
|
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
```javascript
|
|
557
|
-
const { dsl, validate } = require('schema-dsl');
|
|
558
|
-
|
|
559
|
-
// 定义用户注册Schema
|
|
560
|
-
const registerSchema = dsl({
|
|
561
|
-
// 用户名:正则验证
|
|
562
|
-
username: 'string:3-32!'
|
|
563
|
-
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
564
|
-
.label('用户名')
|
|
565
|
-
.messages({
|
|
566
|
-
'pattern': '只能包含字母、数字和下划线',
|
|
567
|
-
'min': '至少3个字符',
|
|
568
|
-
'max': '最多32个字符'
|
|
569
|
-
}),
|
|
570
|
-
|
|
571
|
-
// 邮箱:标签
|
|
572
|
-
email: 'email!'.label('邮箱地址'),
|
|
573
|
-
|
|
574
|
-
// 密码:复杂正则
|
|
575
|
-
password: 'string:8-64!'
|
|
576
|
-
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
|
|
577
|
-
.label('密码')
|
|
578
|
-
.messages({
|
|
579
|
-
'pattern': '必须包含大小写字母和数字'
|
|
580
|
-
}),
|
|
581
|
-
|
|
582
|
-
// 简单字段
|
|
583
|
-
age: 'number:18-120',
|
|
584
|
-
gender: 'male|female|other'
|
|
585
|
-
});
|
|
586
|
-
|
|
587
|
-
// 验证数据
|
|
588
|
-
const testData = {
|
|
589
|
-
username: 'john_doe',
|
|
590
|
-
email: 'john@example.com',
|
|
591
|
-
password: 'Password123',
|
|
592
|
-
age: 25,
|
|
593
|
-
gender: 'male'
|
|
594
|
-
};
|
|
595
|
-
|
|
596
|
-
const result = validate(registerSchema, testData);
|
|
597
|
-
|
|
598
|
-
if (result.valid) {
|
|
599
|
-
console.log('✅ 验证通过!');
|
|
600
|
-
} else {
|
|
601
|
-
console.log('❌ 验证失败:', result.errors);
|
|
602
|
-
}
|
|
603
|
-
```
|
|
604
|
-
|
|
605
|
-
---
|
|
606
|
-
|
|
607
|
-
## 💡 最佳实践
|
|
608
|
-
|
|
609
|
-
### 1. 简单字段用纯DSL
|
|
610
|
-
|
|
611
|
-
```javascript
|
|
612
|
-
const schema = dsl({
|
|
613
|
-
name: 'string:1-50!', // ✅ 简洁
|
|
614
|
-
age: 'number:18-120', // ✅ 清晰
|
|
615
|
-
role: 'user|admin' // ✅ 直观
|
|
616
|
-
});
|
|
617
|
-
```
|
|
618
|
-
|
|
619
|
-
### 2. 复杂字段用String扩展
|
|
620
|
-
|
|
621
|
-
```javascript
|
|
622
|
-
const schema = dsl({
|
|
623
|
-
email: 'email!'
|
|
624
|
-
.pattern(/custom/)
|
|
625
|
-
.messages({...})
|
|
626
|
-
.label('邮箱'),
|
|
627
|
-
|
|
628
|
-
username: 'string:3-32!'
|
|
629
|
-
.pattern(/^\w+$/)
|
|
630
|
-
.custom(checkExists)
|
|
631
|
-
});
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
### 3. 80/20 法则
|
|
635
|
-
|
|
636
|
-
**80%字段用纯DSL,20%字段用String扩展**
|
|
637
|
-
|
|
638
|
-
---
|
|
639
|
-
|
|
640
|
-
## 🎯 常见场景
|
|
641
|
-
|
|
642
|
-
### 表单验证
|
|
643
|
-
|
|
644
|
-
```javascript
|
|
645
|
-
const formSchema = dsl({
|
|
646
|
-
email: 'email!'.label('邮箱地址'),
|
|
647
|
-
password: 'string:8-64!'.label('密码'),
|
|
648
|
-
nickname: 'string:2-20'.label('昵称'),
|
|
649
|
-
bio: 'string:500',
|
|
650
|
-
website: 'url',
|
|
651
|
-
age: 'number:18-120',
|
|
652
|
-
gender: 'male|female|other'
|
|
653
|
-
});
|
|
654
|
-
```
|
|
655
|
-
|
|
656
|
-
### 自定义验证
|
|
657
|
-
|
|
658
|
-
```javascript
|
|
659
|
-
const schema = dsl({
|
|
660
|
-
username: 'string:3-32!'
|
|
661
|
-
.custom(async (value) => {
|
|
662
|
-
const exists = await checkUsernameExists(value);
|
|
663
|
-
if (exists) {
|
|
664
|
-
return { error: 'username.exists', message: '用户名已存在' };
|
|
665
|
-
}
|
|
666
|
-
return true;
|
|
667
|
-
})
|
|
668
|
-
});
|
|
669
|
-
```
|
|
670
|
-
|
|
671
|
-
### 嵌套对象
|
|
672
|
-
|
|
673
|
-
```javascript
|
|
674
|
-
const schema = dsl({
|
|
675
|
-
user: {
|
|
676
|
-
profile: {
|
|
677
|
-
name: 'string:1-50!'.label('姓名'),
|
|
678
|
-
avatar: 'url'.label('头像'),
|
|
679
|
-
social: {
|
|
680
|
-
twitter: 'url'.pattern(/twitter\.com/),
|
|
681
|
-
github: 'url'.pattern(/github\.com/)
|
|
682
|
-
}
|
|
683
|
-
}
|
|
684
|
-
}
|
|
685
|
-
});
|
|
686
|
-
```
|
|
687
|
-
|
|
688
|
-
---
|
|
689
|
-
|
|
690
|
-
## 📚 下一步
|
|
691
|
-
|
|
692
|
-
### 深入学习
|
|
693
|
-
|
|
694
|
-
- [DSL 语法完整指南](./dsl-syntax.md)
|
|
695
|
-
- [API 参考文档](./api-reference.md)
|
|
696
|
-
- [String 扩展文档](./string-extensions.md)
|
|
697
|
-
|
|
698
|
-
### 示例代码
|
|
699
|
-
|
|
700
|
-
- [String扩展完整示例](../examples/string-extensions.js)
|
|
701
|
-
- [用户注册示例](../examples/user-registration/)
|
|
702
|
-
- [数据库导出示例](../examples/export-demo.js)
|
|
703
|
-
|
|
704
|
-
### 高级功能
|
|
705
|
-
|
|
706
|
-
- [自定义验证器](./api-reference.md#custom)
|
|
707
|
-
- [条件验证(when)](./api-reference.md#when)
|
|
708
|
-
- [数据库Schema导出](./api-reference.md#导出器)
|
|
709
|
-
|
|
710
|
-
---
|
|
711
|
-
|
|
712
|
-
## 🆘 常见问题
|
|
713
|
-
|
|
714
|
-
### Q: String扩展和纯DSL有什么区别?
|
|
715
|
-
|
|
716
|
-
**A**:
|
|
717
|
-
- **纯DSL**: 适合简单字段,语法简洁
|
|
718
|
-
- **String扩展**: 适合复杂验证,支持链式调用
|
|
719
|
-
|
|
720
|
-
```javascript
|
|
721
|
-
// 纯DSL(简单)
|
|
722
|
-
name: 'string:1-50!'
|
|
723
|
-
|
|
724
|
-
// String扩展(复杂)
|
|
725
|
-
email: 'email!'
|
|
726
|
-
.pattern(/custom/)
|
|
727
|
-
.messages({...})
|
|
728
|
-
```
|
|
729
|
-
|
|
730
|
-
### Q: 如何禁用String扩展?
|
|
731
|
-
|
|
732
|
-
**A**:
|
|
733
|
-
```javascript
|
|
734
|
-
const { uninstallStringExtensions } = require('schema-dsl');
|
|
735
|
-
uninstallStringExtensions();
|
|
736
|
-
```
|
|
737
|
-
|
|
738
|
-
### Q: 支持TypeScript吗?
|
|
739
|
-
|
|
740
|
-
**A**: 支持!SchemaI-DSL提供完整的TypeScript类型定义。
|
|
741
|
-
|
|
742
|
-
---
|
|
743
|
-
|
|
744
|
-
## 🎉 恭喜!
|
|
745
|
-
|
|
746
|
-
你已经掌握了SchemaI-DSL的核心用法!
|
|
747
|
-
|
|
748
|
-
**核心要点**:
|
|
749
|
-
1. ✅ DSL语法简洁直观
|
|
750
|
-
2. ✅ String扩展强大灵活
|
|
751
|
-
3. ✅ 80%用DSL,20%用扩展
|
|
752
|
-
4. ✅ 字符串可以直接链式调用
|
|
753
|
-
|
|
754
|
-
**开始使用**: `npm install schema-dsl`
|
|
755
|
-
|
|
756
|
-
---
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
**最后更新**: 2025-12-25
|
|
433
|
+
**最后更新**: 2026-05-08
|
|
760
434
|
|
|
761
435
|
|
|
@@ -188,13 +188,17 @@ dsl.error.assert(
|
|
|
188
188
|
```javascript
|
|
189
189
|
const { dsl } = require('schema-dsl');
|
|
190
190
|
|
|
191
|
+
function getRequestLocale(acceptLanguage) {
|
|
192
|
+
return acceptLanguage?.split(',')[0]?.trim() || 'zh-CN';
|
|
193
|
+
}
|
|
194
|
+
|
|
191
195
|
// Express 中间件
|
|
192
196
|
app.get('/api/account/:id', async (req, res, next) => {
|
|
193
197
|
try {
|
|
194
198
|
const account = await getAccount(req.params.id);
|
|
195
199
|
|
|
196
200
|
// 根据请求头获取语言
|
|
197
|
-
const locale = req.headers['accept-language']
|
|
201
|
+
const locale = getRequestLocale(req.headers['accept-language']);
|
|
198
202
|
|
|
199
203
|
// 使用运行时语言抛出错误
|
|
200
204
|
dsl.error.assert(account, 'account.notFound', {}, 404, locale);
|
|
@@ -236,7 +240,7 @@ async function getUserService(userId, locale) {
|
|
|
236
240
|
// 服务 B: API 网关
|
|
237
241
|
app.get('/api/users/:id', async (req, res) => {
|
|
238
242
|
try {
|
|
239
|
-
const locale = req.headers['accept-language']
|
|
243
|
+
const locale = getRequestLocale(req.headers['accept-language']);
|
|
240
244
|
|
|
241
245
|
// 调用用户服务,传递 locale
|
|
242
246
|
const user = await getUserService(req.params.id, locale);
|
|
@@ -343,7 +347,7 @@ const resolvers = {
|
|
|
343
347
|
// ❌ 并发不安全
|
|
344
348
|
app.get('/api/account/:id', async (req, res) => {
|
|
345
349
|
// 修改全局状态
|
|
346
|
-
Locale.setLocale(req.headers['accept-language']);
|
|
350
|
+
Locale.setLocale(req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN');
|
|
347
351
|
|
|
348
352
|
// 如果同时有多个请求,语言会互相干扰
|
|
349
353
|
const error = dsl.error.create('account.notFound');
|
|
@@ -356,7 +360,7 @@ app.get('/api/account/:id', async (req, res) => {
|
|
|
356
360
|
```javascript
|
|
357
361
|
// ✅ 并发安全
|
|
358
362
|
app.get('/api/account/:id', async (req, res) => {
|
|
359
|
-
const locale = req.headers['accept-language'];
|
|
363
|
+
const locale = req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN';
|
|
360
364
|
|
|
361
365
|
// 不修改全局状态,每个请求独立
|
|
362
366
|
const error = dsl.error.create('account.notFound', {}, 404, locale);
|
|
@@ -422,7 +426,7 @@ console.log(error2.message); // "Insufficient balance, current: 50, required: 1
|
|
|
422
426
|
```javascript
|
|
423
427
|
// ✅ 推荐
|
|
424
428
|
app.get('/api/account/:id', async (req, res) => {
|
|
425
|
-
const locale = req.headers['accept-language'] || 'zh-CN';
|
|
429
|
+
const locale = req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN';
|
|
426
430
|
|
|
427
431
|
try {
|
|
428
432
|
const account = await getAccount(req.params.id);
|
|
@@ -435,7 +439,7 @@ app.get('/api/account/:id', async (req, res) => {
|
|
|
435
439
|
|
|
436
440
|
// ❌ 不推荐
|
|
437
441
|
app.get('/api/account/:id', async (req, res) => {
|
|
438
|
-
Locale.setLocale(req.headers['accept-language']); // 并发不安全
|
|
442
|
+
Locale.setLocale(req.headers['accept-language']?.split(',')[0]?.trim() || 'zh-CN'); // 并发不安全
|
|
439
443
|
// ...
|
|
440
444
|
});
|
|
441
445
|
```
|
|
@@ -446,7 +450,7 @@ app.get('/api/account/:id', async (req, res) => {
|
|
|
446
450
|
// 工具函数
|
|
447
451
|
function getUserLocale(req) {
|
|
448
452
|
return req.user?.locale ||
|
|
449
|
-
req.headers['accept-language'] ||
|
|
453
|
+
req.headers['accept-language']?.split(',')[0]?.trim() ||
|
|
450
454
|
'zh-CN';
|
|
451
455
|
}
|
|
452
456
|
|
|
@@ -504,7 +508,7 @@ app.get('/api/users/:id', async (req, res) => {
|
|
|
504
508
|
- 现有代码无需修改
|
|
505
509
|
- `locale` 参数为可选参数
|
|
506
510
|
- 不传 `locale` 时使用全局语言
|
|
507
|
-
-
|
|
511
|
+
- 相关单元测试已覆盖
|
|
508
512
|
|
|
509
513
|
---
|
|
510
514
|
|
|
@@ -516,6 +520,13 @@ app.get('/api/users/:id', async (req, res) => {
|
|
|
516
520
|
|
|
517
521
|
---
|
|
518
522
|
|
|
519
|
-
|
|
523
|
+
## 对应示例文件
|
|
524
|
+
|
|
525
|
+
**示例入口**: [runtime-locale-support.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/runtime-locale-support.ts)
|
|
526
|
+
**说明**: 覆盖运行时指定 locale 创建错误对象、参数插值,以及“局部语言切换不污染全局状态”的关键行为。
|
|
527
|
+
|
|
528
|
+
---
|
|
529
|
+
|
|
530
|
+
**最后更新**: 2026-05-08
|
|
520
531
|
**作者**: schema-dsl Team
|
|
521
532
|
|
package/docs/schema-helper.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SchemaHelper Schema辅助工具
|
|
2
2
|
|
|
3
|
-
> **模块**: `
|
|
3
|
+
> **模块**: `src/utils/SchemaHelper.ts`
|
|
4
4
|
|
|
5
5
|
> **用途**: 提供 JSON Schema 操作的常用辅助方法
|
|
6
6
|
|
|
@@ -36,8 +36,7 @@
|
|
|
36
36
|
## 快速开始
|
|
37
37
|
|
|
38
38
|
```javascript
|
|
39
|
-
const { SchemaHelper } = require('schema-dsl
|
|
40
|
-
const { dsl } = require('schema-dsl');
|
|
39
|
+
const { SchemaHelper, dsl } = require('schema-dsl');
|
|
41
40
|
|
|
42
41
|
// 创建 Schema
|
|
43
42
|
const userSchema = dsl({
|
|
@@ -263,8 +262,7 @@ const summary = SchemaHelper.summarizeSchema(userSchema);
|
|
|
263
262
|
### Schema 分析工具
|
|
264
263
|
|
|
265
264
|
```javascript
|
|
266
|
-
const { SchemaHelper } = require('schema-dsl
|
|
267
|
-
const { dsl } = require('schema-dsl');
|
|
265
|
+
const { SchemaHelper, dsl } = require('schema-dsl');
|
|
268
266
|
|
|
269
267
|
function analyzeSchema(schema, name = 'Schema') {
|
|
270
268
|
console.log(`\n=== ${name} 分析 ===`);
|
|
@@ -338,3 +336,10 @@ function compareSchemaVersions(oldSchema, newSchema) {
|
|
|
338
336
|
- [SchemaUtils](schema-utils.md)
|
|
339
337
|
- [API 参考](api-reference.md)
|
|
340
338
|
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## 对应示例文件
|
|
342
|
+
|
|
343
|
+
**示例入口**: [schema-helper.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/schema-helper.ts)
|
|
344
|
+
**说明**: 覆盖 `isValidSchema()`、`generateSchemaId()`、`flattenSchema()`、`extractRequiredFields()`、`summarizeSchema()` 与 `compareSchemas()`。
|
|
345
|
+
|