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,130 +0,0 @@
1
- /**
2
- * 数据库导出示例
3
- *
4
- * 演示如何将JSON Schema导出为MongoDB、MySQL、PostgreSQL Schema
5
- * 包含v2.0.1 String扩展特性
6
- */
7
-
8
- const { dsl, exporters } = require('../index');
9
-
10
- // ========== 1. 定义用户Schema(使用String扩展)==========
11
-
12
- const userSchema = dsl({
13
- id: 'string!',
14
- // ✨ String扩展:username带正则验证
15
- username: 'string:3-32!'
16
- .pattern(/^[a-zA-Z0-9_]+$/)
17
- .label('用户名'),
18
- // ✨ String扩展:email带标签
19
- email: 'email!'
20
- .label('邮箱地址'),
21
- password: 'string:8-64!',
22
- age: 'number:18-120',
23
- gender: 'male|female|other',
24
- status: 'active|inactive|pending',
25
- role: 'user|admin|moderator',
26
- createdAt: 'date!',
27
- updatedAt: 'date!',
28
- profile: {
29
- bio: 'string:500',
30
- // ✨ String扩展:website带描述
31
- website: 'url'.description('个人主页'),
32
- avatar: 'url'.label('头像URL'),
33
- location: 'string:100'
34
- },
35
- preferences: {
36
- language: 'en|zh|ja|ko',
37
- theme: 'light|dark|auto',
38
- emailNotifications: 'boolean',
39
- smsNotifications: 'boolean'
40
- }
41
- });
42
-
43
- console.log('========== 用户Schema(JSON Schema格式) ==========');
44
- console.log(JSON.stringify(userSchema, null, 2));
45
-
46
- // ========== 2. 导出为MongoDB Schema ==========
47
-
48
- console.log('\n========== MongoDB验证Schema ==========');
49
- const mongoExporter = new exporters.MongoDBExporter({ strict: true });
50
- const mongoSchema = mongoExporter.export(userSchema);
51
- console.log(JSON.stringify(mongoSchema, null, 2));
52
-
53
- // 生成MongoDB命令
54
- console.log('\n========== MongoDB创建集合命令 ==========');
55
- const mongoCommand = mongoExporter.generateCommand('users', userSchema);
56
- console.log(mongoCommand);
57
-
58
- // ========== 3. 导出为MySQL DDL ==========
59
-
60
- console.log('\n========== MySQL CREATE TABLE ==========');
61
- const mysqlExporter = new exporters.MySQLExporter({
62
- engine: 'InnoDB',
63
- charset: 'utf8mb4',
64
- collate: 'utf8mb4_unicode_ci'
65
- });
66
- const mysqlDDL = mysqlExporter.export('users', userSchema);
67
- console.log(mysqlDDL);
68
-
69
- // 生成索引
70
- console.log('\n========== MySQL索引 ==========');
71
- console.log(mysqlExporter.generateIndex('users', 'username', { unique: true }));
72
- console.log(mysqlExporter.generateIndex('users', 'email', { unique: true }));
73
- console.log(mysqlExporter.generateIndex('users', 'status'));
74
-
75
- // ========== 4. 导出为PostgreSQL DDL ==========
76
-
77
- console.log('\n========== PostgreSQL CREATE TABLE ==========');
78
- const pgExporter = new exporters.PostgreSQLExporter({ schema: 'public' });
79
- const pgDDL = pgExporter.export('users', userSchema);
80
- console.log(pgDDL);
81
-
82
- // 生成索引
83
- console.log('\n========== PostgreSQL索引 ==========');
84
- console.log(pgExporter.generateIndex('users', 'username', { unique: true, method: 'btree' }));
85
- console.log(pgExporter.generateIndex('users', 'email', { unique: true, method: 'btree' }));
86
- console.log(pgExporter.generateIndex('users', 'status', { method: 'hash' }));
87
-
88
- // ========== 5. 多表导出示例 ==========
89
-
90
- console.log('\n========== 多表导出示例 ==========');
91
-
92
- // 文章表
93
- const articleSchema = dsl({
94
- id: 'string!',
95
- title: 'string:1-200!',
96
- content: 'string!',
97
- authorId: 'string!',
98
- categoryId: 'string!',
99
- status: 'draft|published|archived',
100
- tags: 'array<string:1-50>',
101
- viewCount: 'number',
102
- likeCount: 'number',
103
- createdAt: 'date!',
104
- updatedAt: 'date!'
105
- });
106
-
107
- // 评论表
108
- const commentSchema = dsl({
109
- id: 'string!',
110
- articleId: 'string!',
111
- userId: 'string!',
112
- content: 'string:1-500!',
113
- parentId: 'string',
114
- status: 'pending|approved|rejected',
115
- createdAt: 'date!'
116
- });
117
-
118
- console.log('\n--- MySQL多表DDL ---');
119
- console.log(mysqlExporter.export('articles', articleSchema));
120
- console.log('\n');
121
- console.log(mysqlExporter.export('comments', commentSchema));
122
-
123
- console.log('\n--- PostgreSQL多表DDL ---');
124
- console.log(pgExporter.export('articles', articleSchema));
125
- console.log('\n');
126
- console.log(pgExporter.export('comments', commentSchema));
127
-
128
- console.log('\n✅ 数据库导出示例完成!');
129
-
130
-
@@ -1,376 +0,0 @@
1
- /**
2
- * Express 集成示例 - 异步验证与 Schema 链式调用
3
- *
4
- * 展示如何在 Express 中使用:
5
- * 1. validateAsync 异步验证
6
- * 2. ValidationError 错误处理
7
- * 3. SchemaUtils 链式调用
8
- * 4. 完整 CRUD 场景
9
- *
10
- * @version 1.0.3
11
- * @date 2025-12-29
12
- */
13
-
14
- const express = require('express');
15
- const { dsl, validateAsync, ValidationError, SchemaUtils } = require('../index');
16
-
17
- const app = express();
18
- app.use(express.json());
19
-
20
- // ===== 模拟数据库 =====
21
- const db = {
22
- users: [],
23
- nextId: 1
24
- };
25
-
26
- // ===== 定义完整 User Schema =====
27
- const fullUserSchema = dsl({
28
- id: 'objectId!',
29
- name: 'string:1-50!',
30
- email: 'email!',
31
- password: 'string:8-32!',
32
- age: 'integer:18-120',
33
- role: 'admin|user|guest',
34
- createdAt: 'date',
35
- updatedAt: 'date'
36
- });
37
-
38
- // ===== 派生各种 Schema =====
39
-
40
- // POST /users - 创建用户 Schema(排除系统字段)
41
- const createUserSchema = SchemaUtils.omit(fullUserSchema, ['id', 'createdAt', 'updatedAt']);
42
-
43
- // GET /users/:id - 公开用户 Schema(移除敏感字段)
44
- const publicUserSchema = SchemaUtils.omit(fullUserSchema, ['password']);
45
-
46
- // PATCH /users/:id - 更新用户 Schema(部分验证)
47
- const updateUserSchema = SchemaUtils
48
- .pick(fullUserSchema, ['name', 'age'])
49
- .partial();
50
-
51
- // PUT /users/:id - 替换用户 Schema(排除系统字段)
52
- const replaceUserSchema = SchemaUtils.omit(fullUserSchema, ['id', 'createdAt', 'updatedAt']);
53
-
54
- // ===== 路由实现 =====
55
-
56
- /**
57
- * POST /users - 创建用户
58
- *
59
- * 使用 createUserSchema:
60
- * - 排除系统字段(id, createdAt, updatedAt)
61
- */
62
- app.post('/users', async (req, res, next) => {
63
- try {
64
- console.log('\n[POST /users] 创建用户');
65
- console.log('请求体:', req.body);
66
-
67
- // 使用 validateAsync 验证
68
- const data = await validateAsync(createUserSchema, req.body);
69
-
70
- console.log('验证通过,数据:', data);
71
-
72
- // 保存到数据库
73
- const user = {
74
- id: String(db.nextId++),
75
- ...data,
76
- createdAt: new Date().toISOString(),
77
- updatedAt: new Date().toISOString()
78
- };
79
-
80
- db.users.push(user);
81
-
82
- // 返回公开信息
83
- const { validate } = require('../index');
84
- const result = validate(publicUserSchema, user);
85
-
86
- console.log('返回数据:', result.data);
87
-
88
- res.status(201).json({
89
- success: true,
90
- user: result.data
91
- });
92
-
93
- } catch (error) {
94
- next(error);
95
- }
96
- });
97
-
98
- /**
99
- * GET /users - 获取所有用户
100
- *
101
- * 使用 publicUserSchema 自动移除敏感字段
102
- */
103
- app.get('/users', (req, res) => {
104
- console.log('\n[GET /users] 获取所有用户');
105
-
106
- const { validate } = require('../index');
107
-
108
- // 对每个用户应用 publicUserSchema
109
- const publicUsers = db.users.map(user => {
110
- const result = validate(publicUserSchema, user);
111
- return result.data;
112
- });
113
-
114
- console.log(`返回 ${publicUsers.length} 个用户`);
115
-
116
- res.json({
117
- success: true,
118
- count: publicUsers.length,
119
- users: publicUsers
120
- });
121
- });
122
-
123
- /**
124
- * GET /users/:id - 获取单个用户
125
- *
126
- * 使用 publicUserSchema 移除敏感字段
127
- */
128
- app.get('/users/:id', (req, res) => {
129
- console.log(`\n[GET /users/${req.params.id}] 获取用户`);
130
-
131
- const user = db.users.find(u => u.id === req.params.id);
132
-
133
- if (!user) {
134
- console.log('用户不存在');
135
- return res.status(404).json({
136
- success: false,
137
- error: '用户不存在'
138
- });
139
- }
140
-
141
- // 使用 clean 模式自动移除敏感字段
142
- const { validate } = require('../index');
143
- const result = validate(publicUserSchema, user);
144
-
145
- console.log('返回数据:', result.data);
146
-
147
- res.json({
148
- success: true,
149
- user: result.data
150
- });
151
- });
152
-
153
- /**
154
- * PATCH /users/:id - 部分更新用户
155
- *
156
- * 使用 updateUserSchema:
157
- * - 只验证 name 和 age
158
- * - 部分验证(可选)
159
- * - 宽松模式(允许额外字段)
160
- */
161
- app.patch('/users/:id', async (req, res, next) => {
162
- try {
163
- console.log(`\n[PATCH /users/${req.params.id}] 部分更新用户`);
164
- console.log('请求体:', req.body);
165
-
166
- const user = db.users.find(u => u.id === req.params.id);
167
-
168
- if (!user) {
169
- console.log('用户不存在');
170
- return res.status(404).json({
171
- success: false,
172
- error: '用户不存在'
173
- });
174
- }
175
-
176
- // 验证部分数据
177
- const data = await validateAsync(updateUserSchema, req.body);
178
-
179
- console.log('验证通过,更新字段:', data);
180
-
181
- // 更新用户
182
- Object.assign(user, data, {
183
- updatedAt: new Date().toISOString()
184
- });
185
-
186
- // 返回公开信息
187
- const { validate } = require('../index');
188
- const result = validate(publicUserSchema, user);
189
-
190
- console.log('返回数据:', result.data);
191
-
192
- res.json({
193
- success: true,
194
- user: result.data
195
- });
196
-
197
- } catch (error) {
198
- next(error);
199
- }
200
- });
201
-
202
- /**
203
- * PUT /users/:id - 替换用户
204
- *
205
- * 使用 replaceUserSchema:
206
- * - 排除系统字段
207
- * - 严格模式(必填字段必须全部提供)
208
- */
209
- app.put('/users/:id', async (req, res, next) => {
210
- try {
211
- console.log(`\n[PUT /users/${req.params.id}] 替换用户`);
212
- console.log('请求体:', req.body);
213
-
214
- const userIndex = db.users.findIndex(u => u.id === req.params.id);
215
-
216
- if (userIndex === -1) {
217
- console.log('用户不存在');
218
- return res.status(404).json({
219
- success: false,
220
- error: '用户不存在'
221
- });
222
- }
223
-
224
- // 验证完整数据
225
- const data = await validateAsync(replaceUserSchema, req.body);
226
-
227
- console.log('验证通过,替换用户:', data);
228
-
229
- // 替换用户(保留 id 和 createdAt)
230
- const oldUser = db.users[userIndex];
231
- db.users[userIndex] = {
232
- id: oldUser.id,
233
- ...data,
234
- createdAt: oldUser.createdAt,
235
- updatedAt: new Date().toISOString()
236
- };
237
-
238
- // 返回公开信息
239
- const { validate } = require('../index');
240
- const result = validate(publicUserSchema, db.users[userIndex]);
241
-
242
- console.log('返回数据:', result.data);
243
-
244
- res.json({
245
- success: true,
246
- user: result.data
247
- });
248
-
249
- } catch (error) {
250
- next(error);
251
- }
252
- });
253
-
254
- /**
255
- * DELETE /users/:id - 删除用户
256
- */
257
- app.delete('/users/:id', (req, res) => {
258
- console.log(`\n[DELETE /users/${req.params.id}] 删除用户`);
259
-
260
- const userIndex = db.users.findIndex(u => u.id === req.params.id);
261
-
262
- if (userIndex === -1) {
263
- console.log('用户不存在');
264
- return res.status(404).json({
265
- success: false,
266
- error: '用户不存在'
267
- });
268
- }
269
-
270
- db.users.splice(userIndex, 1);
271
-
272
- console.log('删除成功');
273
-
274
- res.json({
275
- success: true,
276
- message: '用户已删除'
277
- });
278
- });
279
-
280
- // ===== 全局错误处理中间件 =====
281
-
282
- /**
283
- * ValidationError 错误处理
284
- *
285
- * 自动捕获 validateAsync 抛出的 ValidationError
286
- * 返回友好的错误信息
287
- */
288
- app.use((error, req, res, next) => {
289
- if (error instanceof ValidationError) {
290
- console.log('\n[错误] ValidationError 被捕获');
291
- console.log('错误数量:', error.getErrorCount());
292
- console.log('字段错误:', error.getFieldErrors());
293
-
294
- return res.status(error.statusCode).json(error.toJSON());
295
- }
296
-
297
- // 其他错误
298
- console.error('\n[错误] 服务器错误:', error);
299
- res.status(500).json({
300
- error: 'Internal Server Error',
301
- message: error.message
302
- });
303
- });
304
-
305
- // ===== 启动服务器 =====
306
-
307
- const PORT = 3000;
308
-
309
- app.listen(PORT, () => {
310
- console.log(`\n========================================`);
311
- console.log(` Express 集成示例服务器已启动`);
312
- console.log(` 监听端口: ${PORT}`);
313
- console.log(`========================================\n`);
314
- console.log(`可用的 API 端点:`);
315
- console.log(` POST http://localhost:${PORT}/users - 创建用户`);
316
- console.log(` GET http://localhost:${PORT}/users - 获取所有用户`);
317
- console.log(` GET http://localhost:${PORT}/users/:id - 获取单个用户`);
318
- console.log(` PATCH http://localhost:${PORT}/users/:id - 部分更新用户`);
319
- console.log(` PUT http://localhost:${PORT}/users/:id - 替换用户`);
320
- console.log(` DELETE http://localhost:${PORT}/users/:id - 删除用户`);
321
- console.log(`\n========================================\n`);
322
-
323
- // 打印测试命令
324
- printTestCommands();
325
- });
326
-
327
- // ===== 测试命令 =====
328
-
329
- function printTestCommands() {
330
- console.log(`测试命令(使用 curl):\n`);
331
-
332
- console.log(`# 1. 创建用户(成功)`);
333
- console.log(`curl -X POST http://localhost:${PORT}/users \\`);
334
- console.log(` -H "Content-Type: application/json" \\`);
335
- console.log(` -d '{"name":"John Doe","email":"john@example.com","password":"password123","age":30,"role":"user"}'\n`);
336
-
337
- console.log(`# 2. 创建用户(失败 - 缺少必填字段)`);
338
- console.log(`curl -X POST http://localhost:${PORT}/users \\`);
339
- console.log(` -H "Content-Type: application/json" \\`);
340
- console.log(` -d '{"name":"Jane"}'\n`);
341
-
342
- console.log(`# 3. 创建用户(失败 - 额外字段被拒绝)`);
343
- console.log(`curl -X POST http://localhost:${PORT}/users \\`);
344
- console.log(` -H "Content-Type: application/json" \\`);
345
- console.log(` -d '{"name":"Bob","email":"bob@example.com","password":"password123","extraField":"not allowed"}'\n`);
346
-
347
- console.log(`# 4. 获取所有用户`);
348
- console.log(`curl http://localhost:${PORT}/users\n`);
349
-
350
- console.log(`# 5. 获取单个用户(替换 ID)`);
351
- console.log(`curl http://localhost:${PORT}/users/1\n`);
352
-
353
- console.log(`# 6. 部分更新用户(成功 - 只更新 name)`);
354
- console.log(`curl -X PATCH http://localhost:${PORT}/users/1 \\`);
355
- console.log(` -H "Content-Type: application/json" \\`);
356
- console.log(` -d '{"name":"John Updated"}'\n`);
357
-
358
- console.log(`# 7. 部分更新用户(成功 - 允许额外字段)`);
359
- console.log(`curl -X PATCH http://localhost:${PORT}/users/1 \\`);
360
- console.log(` -H "Content-Type: application/json" \\`);
361
- console.log(` -d '{"age":31,"extraField":"allowed"}'\n`);
362
-
363
- console.log(`# 8. 替换用户(成功 - 必须提供所有必填字段)`);
364
- console.log(`curl -X PUT http://localhost:${PORT}/users/1 \\`);
365
- console.log(` -H "Content-Type: application/json" \\`);
366
- console.log(` -d '{"name":"John Replaced","email":"john.new@example.com","password":"newpassword123","age":32}'\n`);
367
-
368
- console.log(`# 9. 删除用户`);
369
- console.log(`curl -X DELETE http://localhost:${PORT}/users/1\n`);
370
-
371
- console.log(`========================================\n`);
372
- }
373
-
374
- // 导出 app 用于测试
375
- module.exports = app;
376
-