schema-dsl 2.3.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/.eslintignore +10 -0
- package/.eslintrc.json +27 -0
- package/.github/CODE_OF_CONDUCT.md +45 -0
- package/.github/ISSUE_TEMPLATE/bug_report.md +57 -0
- package/.github/ISSUE_TEMPLATE/config.yml +11 -0
- package/.github/ISSUE_TEMPLATE/feature_request.md +45 -0
- package/.github/ISSUE_TEMPLATE/question.md +31 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +70 -0
- package/.github/SECURITY.md +184 -0
- package/.github/workflows/ci.yml +35 -0
- package/CHANGELOG.md +633 -0
- package/CONTRIBUTING.md +368 -0
- package/LICENSE +21 -0
- package/README.md +1122 -0
- package/STATUS.md +273 -0
- package/docs/FEATURE-INDEX.md +521 -0
- package/docs/INDEX.md +224 -0
- package/docs/api-reference.md +1098 -0
- package/docs/best-practices.md +672 -0
- package/docs/cache-manager.md +336 -0
- package/docs/design-philosophy.md +602 -0
- package/docs/dsl-syntax.md +654 -0
- package/docs/dynamic-locale.md +552 -0
- package/docs/error-handling.md +703 -0
- package/docs/export-guide.md +459 -0
- package/docs/faq.md +576 -0
- package/docs/frontend-i18n-guide.md +290 -0
- package/docs/i18n-user-guide.md +488 -0
- package/docs/label-vs-description.md +262 -0
- package/docs/markdown-exporter.md +398 -0
- package/docs/mongodb-exporter.md +279 -0
- package/docs/multi-type-support.md +319 -0
- package/docs/mysql-exporter.md +257 -0
- package/docs/plugin-system.md +542 -0
- package/docs/postgresql-exporter.md +290 -0
- package/docs/quick-start.md +761 -0
- package/docs/schema-helper.md +340 -0
- package/docs/schema-utils.md +492 -0
- package/docs/string-extensions.md +480 -0
- package/docs/troubleshooting.md +471 -0
- package/docs/type-converter.md +319 -0
- package/docs/type-reference.md +219 -0
- package/docs/validate.md +486 -0
- package/docs/validation-guide.md +484 -0
- package/examples/array-dsl-example.js +227 -0
- package/examples/custom-extension.js +85 -0
- package/examples/dsl-match-example.js +74 -0
- package/examples/dsl-style.js +118 -0
- package/examples/dynamic-locale-configuration.js +348 -0
- package/examples/dynamic-locale-example.js +287 -0
- package/examples/export-demo.js +130 -0
- package/examples/i18n-full-demo.js +310 -0
- package/examples/i18n-memory-safety.examples.js +268 -0
- package/examples/markdown-export.js +71 -0
- package/examples/middleware-usage.js +93 -0
- package/examples/password-reset/README.md +153 -0
- package/examples/password-reset/schema.js +26 -0
- package/examples/password-reset/test.js +101 -0
- package/examples/plugin-system.examples.js +205 -0
- package/examples/simple-example.js +122 -0
- package/examples/string-extensions.js +297 -0
- package/examples/user-registration/README.md +156 -0
- package/examples/user-registration/routes.js +92 -0
- package/examples/user-registration/schema.js +150 -0
- package/examples/user-registration/server.js +74 -0
- package/index.d.ts +1999 -0
- package/index.js +270 -0
- package/index.mjs +30 -0
- package/lib/adapters/DslAdapter.js +653 -0
- package/lib/adapters/index.js +20 -0
- package/lib/config/constants.js +286 -0
- package/lib/config/patterns/creditCard.js +9 -0
- package/lib/config/patterns/idCard.js +9 -0
- package/lib/config/patterns/index.js +8 -0
- package/lib/config/patterns/licensePlate.js +4 -0
- package/lib/config/patterns/passport.js +4 -0
- package/lib/config/patterns/phone.js +9 -0
- package/lib/config/patterns/postalCode.js +5 -0
- package/lib/core/CacheManager.js +376 -0
- package/lib/core/DslBuilder.js +740 -0
- package/lib/core/ErrorCodes.js +233 -0
- package/lib/core/ErrorFormatter.js +342 -0
- package/lib/core/JSONSchemaCore.js +347 -0
- package/lib/core/Locale.js +119 -0
- package/lib/core/MessageTemplate.js +89 -0
- package/lib/core/PluginManager.js +448 -0
- package/lib/core/StringExtensions.js +209 -0
- package/lib/core/Validator.js +316 -0
- package/lib/exporters/MarkdownExporter.js +420 -0
- package/lib/exporters/MongoDBExporter.js +162 -0
- package/lib/exporters/MySQLExporter.js +212 -0
- package/lib/exporters/PostgreSQLExporter.js +289 -0
- package/lib/exporters/index.js +24 -0
- package/lib/locales/en-US.js +65 -0
- package/lib/locales/es-ES.js +66 -0
- package/lib/locales/fr-FR.js +66 -0
- package/lib/locales/index.js +8 -0
- package/lib/locales/ja-JP.js +66 -0
- package/lib/locales/zh-CN.js +93 -0
- package/lib/utils/LRUCache.js +174 -0
- package/lib/utils/SchemaHelper.js +240 -0
- package/lib/utils/SchemaUtils.js +313 -0
- package/lib/utils/TypeConverter.js +245 -0
- package/lib/utils/index.js +13 -0
- package/lib/validators/CustomKeywords.js +203 -0
- package/lib/validators/index.js +11 -0
- package/package.json +70 -0
- package/plugins/custom-format.js +101 -0
- package/plugins/custom-validator.js +200 -0
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
# String 扩展文档
|
|
2
|
+
|
|
3
|
+
> **更新时间**: 2025-12-25
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 📑 目录
|
|
8
|
+
|
|
9
|
+
- [核心特性](#核心特性)
|
|
10
|
+
- [可用方法](#可用方法)
|
|
11
|
+
- [快速开始](#快速开始)
|
|
12
|
+
- [详细示例](#详细示例)
|
|
13
|
+
- [多语言支持](#多语言支持)
|
|
14
|
+
- [安装与卸载](#安装与卸载)
|
|
15
|
+
- [最佳实践](#最佳实践)
|
|
16
|
+
- [常见问题](#常见问题)
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## 核心特性
|
|
21
|
+
|
|
22
|
+
**字符串可以直接调用链式方法**
|
|
23
|
+
|
|
24
|
+
```javascript
|
|
25
|
+
// ✅ 字符串直接链式调用
|
|
26
|
+
email: 'email!'.pattern(/custom/).label('邮箱')
|
|
27
|
+
|
|
28
|
+
// ✅ 纯DSL仍然有效
|
|
29
|
+
age: 'number:18-120'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
**优势**:
|
|
33
|
+
- ✅ 更简洁自然
|
|
34
|
+
- ✅ 减少代码量
|
|
35
|
+
- ✅ 100%向后兼容
|
|
36
|
+
|
|
37
|
+
## 替代方案(非侵入式)
|
|
38
|
+
|
|
39
|
+
如果你介意修改 `String.prototype`,可以直接使用 `dsl()` 包裹字符串:
|
|
40
|
+
|
|
41
|
+
```javascript
|
|
42
|
+
const { dsl } = require('schema-dsl');
|
|
43
|
+
|
|
44
|
+
// 禁用 String 扩展
|
|
45
|
+
require('schema-dsl').uninstallStringExtensions();
|
|
46
|
+
|
|
47
|
+
const schema = dsl({
|
|
48
|
+
// 使用 dsl() 包裹字符串
|
|
49
|
+
email: dsl('email!').pattern(/custom/).label('邮箱'),
|
|
50
|
+
|
|
51
|
+
// 纯DSL不受影响
|
|
52
|
+
age: 'number:18-120'
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 可用方法
|
|
59
|
+
|
|
60
|
+
| 方法 | 说明 | 示例 |
|
|
61
|
+
|------|------|------|
|
|
62
|
+
| `.pattern(regex, msg?)` | 正则验证 | `'string!'.pattern(/^\w+$/)` |
|
|
63
|
+
| `.label(text)` | 字段标签 | `'email!'.label('邮箱地址')` |
|
|
64
|
+
| `.messages(obj)` | 自定义消息 | `'string!'.messages({...})` |
|
|
65
|
+
| `.description(text)` | 描述 | `'url'.description('主页')` |
|
|
66
|
+
| `.custom(fn)` | 自定义验证 | `'string!'.custom(async...)` |
|
|
67
|
+
| `.default(value)` | 默认值 | `'string'.default('guest')` |
|
|
68
|
+
| `.username(range?)` | 用户名验证 | `'string!'.username('5-20')` |
|
|
69
|
+
| `.phone(country)` | 手机号验证 | `'string!'.phone('cn')` |
|
|
70
|
+
| `.phoneNumber(country)` | 手机号验证(别名) | `'string!'.phoneNumber('cn')` |
|
|
71
|
+
| `.idCard(country)` | 身份证验证 | `'string!'.idCard('cn')` |
|
|
72
|
+
| `.slug()` | URL别名验证 | `'string!'.slug()` |
|
|
73
|
+
| `.password(strength)` | 密码验证 | `'string!'.password('strong')` |
|
|
74
|
+
| `.format(name)` | 设置格式 | `'string'.format('email')` |
|
|
75
|
+
| `.toSchema()` | 转为Schema | `'string!'.toSchema()` |
|
|
76
|
+
| `.creditCard(type)` | 信用卡验证 | `'string!'.creditCard('visa')` |
|
|
77
|
+
| `.licensePlate(country)` | 车牌验证 | `'string!'.licensePlate('cn')` |
|
|
78
|
+
| `.postalCode(country)` | 邮编验证 | `'string!'.postalCode('cn')` |
|
|
79
|
+
| `.passport(country)` | 护照验证 | `'string!'.passport('cn')` |
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## 快速开始
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
const { dsl } = require('schema-dsl');
|
|
87
|
+
|
|
88
|
+
const schema = dsl({
|
|
89
|
+
// 字符串直接链式调用
|
|
90
|
+
email: 'email!'.label('邮箱地址'),
|
|
91
|
+
|
|
92
|
+
username: 'string:3-32!'
|
|
93
|
+
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
94
|
+
.label('用户名'),
|
|
95
|
+
|
|
96
|
+
// 简单字段用纯DSL
|
|
97
|
+
age: 'number:18-120',
|
|
98
|
+
role: 'user|admin'
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 详细示例
|
|
105
|
+
|
|
106
|
+
### 1. 正则验证
|
|
107
|
+
|
|
108
|
+
```javascript
|
|
109
|
+
const schema = dsl({
|
|
110
|
+
username: 'string:3-32!'
|
|
111
|
+
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
112
|
+
.messages({
|
|
113
|
+
'pattern': '只能包含字母、数字和下划线'
|
|
114
|
+
})
|
|
115
|
+
.label('用户名'),
|
|
116
|
+
|
|
117
|
+
phone: 'string:11!'
|
|
118
|
+
.pattern(/^1[3-9]\d{9}$/)
|
|
119
|
+
.messages({
|
|
120
|
+
'pattern': '请输入有效的手机号'
|
|
121
|
+
})
|
|
122
|
+
.label('手机号'),
|
|
123
|
+
|
|
124
|
+
password: 'string:8-64!'
|
|
125
|
+
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
|
|
126
|
+
.messages({
|
|
127
|
+
'pattern': '密码必须包含大小写字母和数字'
|
|
128
|
+
})
|
|
129
|
+
.label('密码')
|
|
130
|
+
});
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
**正确的错误码**:
|
|
134
|
+
- `'required'` - 必填字段
|
|
135
|
+
- `'min'` - 最小长度/值
|
|
136
|
+
- `'max'` - 最大长度/值
|
|
137
|
+
- `'pattern'` - 正则验证
|
|
138
|
+
- `'format'` - 格式验证(email/url等)
|
|
139
|
+
- `'enum'` - 枚举值
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
### 2. 自定义错误消息
|
|
144
|
+
|
|
145
|
+
```javascript
|
|
146
|
+
const schema = dsl({
|
|
147
|
+
email: 'email!'
|
|
148
|
+
.label('邮箱地址')
|
|
149
|
+
.messages({
|
|
150
|
+
'format': '请输入有效的邮箱地址',
|
|
151
|
+
'required': '邮箱地址不能为空'
|
|
152
|
+
}),
|
|
153
|
+
|
|
154
|
+
bio: 'string:500'
|
|
155
|
+
.label('个人简介')
|
|
156
|
+
.messages({
|
|
157
|
+
'max': '个人简介不能超过{{#limit}}个字符'
|
|
158
|
+
}),
|
|
159
|
+
|
|
160
|
+
age: 'number:18-120'
|
|
161
|
+
.messages({
|
|
162
|
+
'min': '年龄不能小于{{#limit}}',
|
|
163
|
+
'max': '年龄不能大于{{#limit}}'
|
|
164
|
+
})
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**消息模板变量**:
|
|
169
|
+
- `{{#label}}` - 字段标签
|
|
170
|
+
- `{{#limit}}` - 约束值(min/max)
|
|
171
|
+
- `{{#value}}` - 当前值
|
|
172
|
+
- `{{#pattern}}` - 正则表达式
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### 3. 自定义验证器
|
|
177
|
+
|
|
178
|
+
```javascript
|
|
179
|
+
const schema = dsl({
|
|
180
|
+
// 最优雅:只在失败时返回错误消息
|
|
181
|
+
username: 'string:3-32!'
|
|
182
|
+
.custom(async (value) => {
|
|
183
|
+
const exists = await checkUsernameExists(value);
|
|
184
|
+
if (exists) return '用户名已被占用';
|
|
185
|
+
// 成功时无需返回
|
|
186
|
+
})
|
|
187
|
+
.label('用户名'),
|
|
188
|
+
|
|
189
|
+
// 支持同步验证
|
|
190
|
+
password: 'string:8-64!'
|
|
191
|
+
.custom((value) => {
|
|
192
|
+
if (!/[A-Z]/.test(value)) return '必须包含大写字母';
|
|
193
|
+
if (!/[a-z]/.test(value)) return '必须包含小写字母';
|
|
194
|
+
if (!/\d/.test(value)) return '必须包含数字';
|
|
195
|
+
})
|
|
196
|
+
.label('密码')
|
|
197
|
+
});
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
**支持的返回值**:
|
|
201
|
+
- 不返回/`undefined` → 验证通过 ✅
|
|
202
|
+
- 返回字符串 → 验证失败(错误消息)
|
|
203
|
+
- 返回 `{ error, message }` → 自定义错误码
|
|
204
|
+
- 抛出异常 → 验证失败
|
|
205
|
+
- 返回 `true` → 验证通过
|
|
206
|
+
- 返回 `false` → 验证失败(默认消息)
|
|
207
|
+
|
|
208
|
+
**注意**:
|
|
209
|
+
- 异步验证器(async)需要使用 `validator.validateAsync()`(计划中)或在外部处理。
|
|
210
|
+
- 目前 `validator.validate()` 是同步的,如果 `.custom()` 返回 Promise,会抛出错误提示。
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
---
|
|
214
|
+
|
|
215
|
+
### 5. 默认验证器
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
const schema = dsl({
|
|
219
|
+
// 用户名验证(自动正则+长度)
|
|
220
|
+
username: 'string!'.username('5-20'), // 5-20个字符
|
|
221
|
+
|
|
222
|
+
// 手机号验证
|
|
223
|
+
phone: 'string!'.phone('cn'), // 中国手机号
|
|
224
|
+
|
|
225
|
+
// 密码强度
|
|
226
|
+
password: 'string!'.password('strong'), // 强密码
|
|
227
|
+
|
|
228
|
+
// 身份证验证
|
|
229
|
+
idCard: 'string!'.idCard('cn'),
|
|
230
|
+
|
|
231
|
+
// URL别名验证
|
|
232
|
+
slug: 'string!'.slug()
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
**username 预设**:
|
|
237
|
+
- `'short'` - 2-16
|
|
238
|
+
- `'medium'` - 3-32(默认)
|
|
239
|
+
- `'long'` - 5-64
|
|
240
|
+
- `'3-32'` - 自定义范围
|
|
241
|
+
|
|
242
|
+
**phone 支持的国家**:
|
|
243
|
+
- `'cn'` - 中国(11位)
|
|
244
|
+
- `'us'` - 美国
|
|
245
|
+
- `'uk'` - 英国
|
|
246
|
+
|
|
247
|
+
**password 强度**:
|
|
248
|
+
- `'weak'` - 6-64
|
|
249
|
+
- `'medium'` - 8-64(默认)
|
|
250
|
+
- `'strong'` - 8-64(大小写+数字)
|
|
251
|
+
|
|
252
|
+
---
|
|
253
|
+
|
|
254
|
+
### 6. 完整表单示例
|
|
255
|
+
|
|
256
|
+
```javascript
|
|
257
|
+
const { dsl, Validator } = require('schema-dsl');
|
|
258
|
+
|
|
259
|
+
const formSchema = dsl({
|
|
260
|
+
email: 'email!'
|
|
261
|
+
.label('邮箱地址')
|
|
262
|
+
.description('用于登录和接收通知')
|
|
263
|
+
.messages({
|
|
264
|
+
'format': '请输入有效的邮箱地址'
|
|
265
|
+
}),
|
|
266
|
+
|
|
267
|
+
username: 'string:3-32!'
|
|
268
|
+
.pattern(/^[a-zA-Z0-9_]+$/)
|
|
269
|
+
.messages({
|
|
270
|
+
'pattern': '只能包含字母、数字和下划线',
|
|
271
|
+
'min': '用户名至少3个字符',
|
|
272
|
+
'max': '用户名最多32个字符'
|
|
273
|
+
})
|
|
274
|
+
.label('用户名'),
|
|
275
|
+
|
|
276
|
+
password: 'string:8-64!'
|
|
277
|
+
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).+$/)
|
|
278
|
+
.messages({
|
|
279
|
+
'pattern': '密码必须包含大小写字母、数字和特殊字符'
|
|
280
|
+
})
|
|
281
|
+
.label('密码'),
|
|
282
|
+
|
|
283
|
+
// 简单字段
|
|
284
|
+
age: 'number:18-120',
|
|
285
|
+
gender: 'male|female|other'
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
// 验证
|
|
289
|
+
const { validate } = require('schema-dsl');
|
|
290
|
+
const result = validate(formSchema, {
|
|
291
|
+
email: 'user@example.com',
|
|
292
|
+
username: 'john_doe',
|
|
293
|
+
password: 'Password123!',
|
|
294
|
+
age: 25,
|
|
295
|
+
gender: 'male'
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
console.log(result.valid); // true
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
## 多语言支持
|
|
304
|
+
|
|
305
|
+
### 方案1: 全局多语言配置(推荐)
|
|
306
|
+
|
|
307
|
+
```javascript
|
|
308
|
+
const { Locale } = require('schema-dsl');
|
|
309
|
+
|
|
310
|
+
// 设置语言
|
|
311
|
+
Locale.setLocale('zh-CN');
|
|
312
|
+
|
|
313
|
+
// 添加自定义语言包
|
|
314
|
+
Locale.addLocale('zh-CN', {
|
|
315
|
+
'required': '{{#label}}不能为空',
|
|
316
|
+
'min': '{{#label}}至少{{#limit}}个字符',
|
|
317
|
+
'max': '{{#label}}最多{{#limit}}个字符',
|
|
318
|
+
'pattern': '{{#label}}格式不正确',
|
|
319
|
+
'format': '请输入有效的{{#label}}'
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
// Schema中使用label
|
|
323
|
+
const schema = dsl({
|
|
324
|
+
email: 'email!'
|
|
325
|
+
.label('邮箱地址'), // 错误消息会自动使用"邮箱地址"
|
|
326
|
+
|
|
327
|
+
username: 'string:3-32!'
|
|
328
|
+
.label('用户名')
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
// 切换语言
|
|
332
|
+
Locale.setLocale('en-US'); // 自动切换为英文消息
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
### 方案2: 字段级多语言
|
|
336
|
+
|
|
337
|
+
```javascript
|
|
338
|
+
const schema = dsl({
|
|
339
|
+
email: 'email!'
|
|
340
|
+
.label('邮箱地址')
|
|
341
|
+
.messages({
|
|
342
|
+
'format': '请输入有效的邮箱地址',
|
|
343
|
+
'required': '邮箱地址不能为空'
|
|
344
|
+
})
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 方案3: 运行时动态切换
|
|
349
|
+
|
|
350
|
+
```javascript
|
|
351
|
+
const { Locale } = require('schema-dsl');
|
|
352
|
+
|
|
353
|
+
// 根据用户语言偏好切换
|
|
354
|
+
function getSchema(locale) {
|
|
355
|
+
Locale.setLocale(locale);
|
|
356
|
+
|
|
357
|
+
return dsl({
|
|
358
|
+
email: 'email!'.label(
|
|
359
|
+
locale === 'zh-CN' ? '邮箱地址' : 'Email Address'
|
|
360
|
+
)
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
const zhSchema = getSchema('zh-CN');
|
|
365
|
+
const enSchema = getSchema('en-US');
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**推荐方案**: 方案1(全局配置) + 方案2(特殊字段覆盖)
|
|
369
|
+
|
|
370
|
+
---
|
|
371
|
+
|
|
372
|
+
## 安装与卸载
|
|
373
|
+
|
|
374
|
+
### 自动安装
|
|
375
|
+
|
|
376
|
+
String扩展在导入时自动安装:
|
|
377
|
+
|
|
378
|
+
```javascript
|
|
379
|
+
const { dsl } = require('schema-dsl');
|
|
380
|
+
// String扩展已自动安装
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
### 手动禁用
|
|
384
|
+
|
|
385
|
+
```javascript
|
|
386
|
+
const { uninstallStringExtensions } = require('schema-dsl');
|
|
387
|
+
|
|
388
|
+
uninstallStringExtensions();
|
|
389
|
+
|
|
390
|
+
// 之后只能用纯DSL
|
|
391
|
+
'email!'.pattern(/custom/) // ❌ 报错
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
### 重新启用
|
|
395
|
+
|
|
396
|
+
```javascript
|
|
397
|
+
const { installStringExtensions } = require('schema-dsl');
|
|
398
|
+
|
|
399
|
+
installStringExtensions();
|
|
400
|
+
|
|
401
|
+
// String扩展恢复
|
|
402
|
+
'email!'.pattern(/custom/) // ✅ 正常
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
---
|
|
406
|
+
|
|
407
|
+
## 最佳实践
|
|
408
|
+
|
|
409
|
+
### 1. 简单字段用纯DSL
|
|
410
|
+
|
|
411
|
+
```javascript
|
|
412
|
+
const schema = dsl({
|
|
413
|
+
name: 'string:1-50!',
|
|
414
|
+
age: 'number:18-120',
|
|
415
|
+
role: 'user|admin'
|
|
416
|
+
});
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
### 2. 复杂字段用链式调用
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
const schema = dsl({
|
|
423
|
+
email: 'email!'
|
|
424
|
+
.pattern(/custom/)
|
|
425
|
+
.messages({...})
|
|
426
|
+
.label('邮箱'),
|
|
427
|
+
|
|
428
|
+
username: 'string:3-32!'
|
|
429
|
+
.pattern(/^\w+$/)
|
|
430
|
+
.custom(checkExists)
|
|
431
|
+
});
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
### 3. 遵循 80/20 法则
|
|
435
|
+
|
|
436
|
+
**80%字段用纯DSL,20%字段用String扩展**
|
|
437
|
+
|
|
438
|
+
---
|
|
439
|
+
|
|
440
|
+
## 常见问题
|
|
441
|
+
|
|
442
|
+
### Q1: String扩展会污染全局吗?
|
|
443
|
+
|
|
444
|
+
**A**: 会扩展 `String.prototype`,但冲突概率极低。提供 `uninstallStringExtensions()` 可以卸载。
|
|
445
|
+
|
|
446
|
+
### Q2: 性能如何?
|
|
447
|
+
|
|
448
|
+
**A**: 性能开销极小(<5%),测试显示反而更快(少了函数调用)。
|
|
449
|
+
|
|
450
|
+
### Q3: TypeScript 支持吗?
|
|
451
|
+
|
|
452
|
+
**A**: 完全支持,通过类型定义文件。
|
|
453
|
+
|
|
454
|
+
### Q4: 正确的错误码是什么?
|
|
455
|
+
|
|
456
|
+
**A**:
|
|
457
|
+
- `'required'` - 必填
|
|
458
|
+
- `'min'` / `'max'` - 长度/值范围
|
|
459
|
+
- `'pattern'` - 正则
|
|
460
|
+
- `'format'` - 格式(email/url)
|
|
461
|
+
- `'enum'` - 枚举
|
|
462
|
+
|
|
463
|
+
### Q5: 如何支持多语言?
|
|
464
|
+
|
|
465
|
+
**A**: 使用 `Locale` 全局配置(推荐)或字段级 `.messages()` 覆盖。
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## 相关文档
|
|
470
|
+
|
|
471
|
+
- [DSL 语法](./dsl-syntax.md)
|
|
472
|
+
- [API 参考](./api-reference.md)
|
|
473
|
+
- [多语言支持](./multi-language.md)
|
|
474
|
+
- [示例代码](../examples/string-extensions.js)
|
|
475
|
+
|
|
476
|
+
---
|
|
477
|
+
|
|
478
|
+
**最后更新**: 2025-12-25
|
|
479
|
+
|
|
480
|
+
|