schema-dsl 1.2.5 → 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 -212
- 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 -3658
- package/index.js +0 -475
- package/index.mjs +0 -60
- package/lib/adapters/DslAdapter.js +0 -995
- 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 -1589
- 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
package/index.js
DELETED
|
@@ -1,475 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* schema-dsl - 主入口文件
|
|
3
|
-
*
|
|
4
|
-
* 统一的DSL Builder Pattern
|
|
5
|
-
* 简洁 + 强大 = 完美平衡
|
|
6
|
-
*
|
|
7
|
-
* @module schema-dsl
|
|
8
|
-
* @version 1.0.4
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
// ========== 核心层 ==========
|
|
12
|
-
const JSONSchemaCore = require("./lib/core/JSONSchemaCore");
|
|
13
|
-
const Validator = require("./lib/core/Validator");
|
|
14
|
-
const ErrorFormatter = require("./lib/core/ErrorFormatter");
|
|
15
|
-
const CacheManager = require("./lib/core/CacheManager");
|
|
16
|
-
const DslBuilder = require("./lib/core/DslBuilder");
|
|
17
|
-
const PluginManager = require("./lib/core/PluginManager");
|
|
18
|
-
const ConditionalBuilder = require("./lib/core/ConditionalBuilder");
|
|
19
|
-
|
|
20
|
-
// ========== 错误消息系统 ==========
|
|
21
|
-
const ErrorCodes = require("./lib/core/ErrorCodes");
|
|
22
|
-
const MessageTemplate = require("./lib/core/MessageTemplate");
|
|
23
|
-
const Locale = require("./lib/core/Locale");
|
|
24
|
-
|
|
25
|
-
// ========== 错误类 ==========
|
|
26
|
-
const ValidationError = require("./lib/errors/ValidationError");
|
|
27
|
-
const I18nError = require("./lib/errors/I18nError");
|
|
28
|
-
|
|
29
|
-
// ========== String 扩展 ==========
|
|
30
|
-
const {
|
|
31
|
-
installStringExtensions,
|
|
32
|
-
uninstallStringExtensions,
|
|
33
|
-
} = require("./lib/core/StringExtensions");
|
|
34
|
-
|
|
35
|
-
// ========== 适配器层 ==========
|
|
36
|
-
const dsl = require("./lib/adapters/DslAdapter");
|
|
37
|
-
|
|
38
|
-
// 挂载静态方法 (v2.1.0)
|
|
39
|
-
dsl.match = dsl.DslAdapter.match;
|
|
40
|
-
|
|
41
|
-
// ✅ 智能 dsl.if:根据参数类型选择实现
|
|
42
|
-
dsl.if = function (...args) {
|
|
43
|
-
// 如果第一个参数是函数 → 使用新的 ConditionalBuilder(链式API)
|
|
44
|
-
if (typeof args[0] === "function") {
|
|
45
|
-
return ConditionalBuilder.start(args[0]);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// 如果第一个参数是字符串且有3个参数 → 使用原有的字段条件实现
|
|
49
|
-
// dsl.if('fieldName', thenSchema, elseSchema)
|
|
50
|
-
if (typeof args[0] === "string" && args.length >= 2) {
|
|
51
|
-
return dsl.DslAdapter.if(args[0], args[1], args[2]);
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// 其他情况 → 调用 ConditionalBuilder 让它抛出正确的错误
|
|
55
|
-
return ConditionalBuilder.start(args[0]);
|
|
56
|
-
};
|
|
57
|
-
|
|
58
|
-
// ✅ dsl.error:统一的多语言错误抛出(v1.1.1+)
|
|
59
|
-
// v1.1.8: 支持简化语法,智能参数识别
|
|
60
|
-
dsl.error = {
|
|
61
|
-
/**
|
|
62
|
-
* 创建多语言错误(不抛出)
|
|
63
|
-
* @param {string} code - 错误代码(多语言 key)
|
|
64
|
-
* @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
|
|
65
|
-
* @param {number} statusCode - HTTP 状态码
|
|
66
|
-
* @param {string} locale - 语言环境(仅当第2个参数是对象时有效)
|
|
67
|
-
* @returns {I18nError} 错误实例
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* // 简化语法
|
|
71
|
-
* dsl.error.create('account.notFound', 'zh-CN');
|
|
72
|
-
*
|
|
73
|
-
* @example
|
|
74
|
-
* // 标准语法
|
|
75
|
-
* dsl.error.create('account.notFound', { id: '123' }, 404, 'zh-CN');
|
|
76
|
-
*/
|
|
77
|
-
create: (code, paramsOrLocale, statusCode, locale) =>
|
|
78
|
-
I18nError.create(code, paramsOrLocale, statusCode, locale),
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* 抛出多语言错误
|
|
82
|
-
* @param {string} code - 错误代码(多语言 key)
|
|
83
|
-
* @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
|
|
84
|
-
* @param {number} statusCode - HTTP 状态码
|
|
85
|
-
* @param {string} locale - 语言环境(仅当第2个参数是对象时有效)
|
|
86
|
-
* @throws {I18nError} 直接抛出错误
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* // 简化语法
|
|
90
|
-
* dsl.error.throw('account.notFound', 'zh-CN');
|
|
91
|
-
*
|
|
92
|
-
* @example
|
|
93
|
-
* // 标准语法
|
|
94
|
-
* dsl.error.throw('account.notFound', { id: '123' }, 404, 'zh-CN');
|
|
95
|
-
*/
|
|
96
|
-
throw: (code, paramsOrLocale, statusCode, locale) =>
|
|
97
|
-
I18nError.throw(code, paramsOrLocale, statusCode, locale),
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* 断言方法 - 条件不满足时抛错
|
|
101
|
-
* @param {boolean} condition - 条件表达式
|
|
102
|
-
* @param {string} code - 错误代码(多语言 key)
|
|
103
|
-
* @param {Object|string} paramsOrLocale - 错误参数对象 或 语言代码(智能识别)
|
|
104
|
-
* @param {number} statusCode - HTTP 状态码
|
|
105
|
-
* @param {string} locale - 语言环境(仅当第3个参数是对象时有效)
|
|
106
|
-
*
|
|
107
|
-
* @example
|
|
108
|
-
* // 简化语法
|
|
109
|
-
* dsl.error.assert(account, 'account.notFound', 'zh-CN');
|
|
110
|
-
*
|
|
111
|
-
* @example
|
|
112
|
-
* // 标准语法
|
|
113
|
-
* dsl.error.assert(account, 'account.notFound', { id: '123' }, 404, 'zh-CN');
|
|
114
|
-
*/
|
|
115
|
-
assert: (condition, code, paramsOrLocale, statusCode, locale) =>
|
|
116
|
-
I18nError.assert(condition, code, paramsOrLocale, statusCode, locale),
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* 从目录递归加载语言包(内部函数)
|
|
121
|
-
*
|
|
122
|
-
* 支持子目录递归扫描,子目录名作为模块组织层(不影响语言 key)。
|
|
123
|
-
* 同名 key 冲突时:strict 模式抛错,默认模式打 WARN 日志。
|
|
124
|
-
*
|
|
125
|
-
* @param {string} dirPath - 目录绝对路径
|
|
126
|
-
* @param {Object} options - 配置选项
|
|
127
|
-
* @param {boolean} [options.strict=false] - 严格模式:同名 key 冲突时抛出 Error
|
|
128
|
-
* @private
|
|
129
|
-
*/
|
|
130
|
-
function loadLocalesFromDir(dirPath, options = {}) {
|
|
131
|
-
const fs = require("fs");
|
|
132
|
-
const path = require("path");
|
|
133
|
-
|
|
134
|
-
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
135
|
-
console.warn(
|
|
136
|
-
"[schema-dsl] i18n path does not exist or is not a directory:",
|
|
137
|
-
dirPath,
|
|
138
|
-
);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// 语言代码格式校验:zh-CN / en-US / zh / en 等
|
|
143
|
-
const LOCALE_NAME_RE = /^[a-z]{2,3}(-[A-Z]{2,4})?$/;
|
|
144
|
-
|
|
145
|
-
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
146
|
-
|
|
147
|
-
entries.forEach((entry) => {
|
|
148
|
-
const fullPath = path.join(dirPath, entry.name);
|
|
149
|
-
|
|
150
|
-
if (entry.isDirectory()) {
|
|
151
|
-
// 递归进入子目录(子目录名仅作模块组织层,不影响语言 key)
|
|
152
|
-
loadLocalesFromDir(fullPath, options);
|
|
153
|
-
} else if (entry.isFile()) {
|
|
154
|
-
const ext = path.extname(entry.name);
|
|
155
|
-
if (ext !== ".js" && ext !== ".cjs" && ext !== ".json") return;
|
|
156
|
-
|
|
157
|
-
const localeName = path.basename(entry.name, ext);
|
|
158
|
-
|
|
159
|
-
// 文件名格式校验:只加载符合语言代码格式的文件
|
|
160
|
-
if (!LOCALE_NAME_RE.test(localeName)) {
|
|
161
|
-
// 仅 debug 级别,不影响正常运行
|
|
162
|
-
return;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
let messages;
|
|
166
|
-
try {
|
|
167
|
-
messages = require(path.resolve(fullPath));
|
|
168
|
-
} catch (e) {
|
|
169
|
-
console.warn(
|
|
170
|
-
"[schema-dsl] Failed to load locale file:",
|
|
171
|
-
fullPath,
|
|
172
|
-
e.message,
|
|
173
|
-
);
|
|
174
|
-
return;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
// 冲突检测:检查 messages 的每个 key 是否已存在于当前语言包
|
|
178
|
-
const existing = Locale.locales[localeName] || {};
|
|
179
|
-
const conflictKeys = Object.keys(messages).filter((k) =>
|
|
180
|
-
Object.prototype.hasOwnProperty.call(existing, k),
|
|
181
|
-
);
|
|
182
|
-
|
|
183
|
-
if (conflictKeys.length > 0) {
|
|
184
|
-
const keyList = conflictKeys.join(", ");
|
|
185
|
-
const msg = `[schema-dsl] i18n key 冲突 in locale '${localeName}'\n 冲突 key: ${keyList}\n 来源文件: ${fullPath}`;
|
|
186
|
-
if (options.strict) {
|
|
187
|
-
throw new Error(msg);
|
|
188
|
-
} else {
|
|
189
|
-
console.warn(msg);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
Locale.addLocale(localeName, messages);
|
|
194
|
-
}
|
|
195
|
-
});
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* 全局配置
|
|
200
|
-
* @param {Object} options - 配置选项
|
|
201
|
-
* @param {Object} options.patterns - 验证规则扩展 (phone, idCard, creditCard)
|
|
202
|
-
* @param {string|Object} options.i18n - 多语言配置(目录路径、对象语言包、或含 localesPath 的对象)
|
|
203
|
-
* @param {Object} options.cache - 缓存配置
|
|
204
|
-
* @param {boolean} [options.strict=false] - 严格模式:i18n 目录扫描时 key 冲突直接抛错(默认 false)
|
|
205
|
-
*/
|
|
206
|
-
dsl.config = function (options = {}) {
|
|
207
|
-
const patterns = require("./lib/config/patterns");
|
|
208
|
-
|
|
209
|
-
// patterns 配置
|
|
210
|
-
if (options.patterns) {
|
|
211
|
-
if (options.patterns.phone)
|
|
212
|
-
Object.assign(patterns.phone, options.patterns.phone);
|
|
213
|
-
if (options.patterns.idCard)
|
|
214
|
-
Object.assign(patterns.idCard, options.patterns.idCard);
|
|
215
|
-
if (options.patterns.creditCard)
|
|
216
|
-
Object.assign(patterns.creditCard, options.patterns.creditCard);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
// 多语言支持 (v1.0.1 优化;v1.2.3 增强:递归子目录 + 冲突检测)
|
|
220
|
-
if (options.i18n) {
|
|
221
|
-
// 方式 1: 传入目录路径(字符串)→ 递归扫描
|
|
222
|
-
if (typeof options.i18n === "string") {
|
|
223
|
-
loadLocalesFromDir(options.i18n, options);
|
|
224
|
-
}
|
|
225
|
-
// 方式 2: 传入对象
|
|
226
|
-
else if (typeof options.i18n === "object") {
|
|
227
|
-
// 方式 2a: 含 localesPath 字段 → 走目录扫描(兼容文档记载用法)
|
|
228
|
-
if (options.i18n.localesPath) {
|
|
229
|
-
loadLocalesFromDir(options.i18n.localesPath, options);
|
|
230
|
-
}
|
|
231
|
-
// 方式 2b: 直接传语言包对象 { 'zh-CN': {...}, 'en-US': {...} }(原有逻辑,不变)
|
|
232
|
-
else {
|
|
233
|
-
Object.keys(options.i18n).forEach((locale) => {
|
|
234
|
-
Locale.addLocale(locale, options.i18n[locale]);
|
|
235
|
-
});
|
|
236
|
-
}
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// 缓存配置 (v1.0.4+)
|
|
241
|
-
if (options.cache) {
|
|
242
|
-
// 如果 Validator 还未创建,保存配置供后续创建时使用
|
|
243
|
-
if (!_defaultValidator) {
|
|
244
|
-
_validatorOptions.cache = options.cache;
|
|
245
|
-
} else {
|
|
246
|
-
// 如果已创建,动态修改现有实例的配置(向后兼容)
|
|
247
|
-
const cacheOpts = _defaultValidator.cache.options;
|
|
248
|
-
if (options.cache.maxSize !== undefined) {
|
|
249
|
-
cacheOpts.maxSize = options.cache.maxSize;
|
|
250
|
-
}
|
|
251
|
-
if (options.cache.ttl !== undefined) {
|
|
252
|
-
cacheOpts.ttl = options.cache.ttl;
|
|
253
|
-
}
|
|
254
|
-
if (options.cache.enabled !== undefined) {
|
|
255
|
-
cacheOpts.enabled = options.cache.enabled;
|
|
256
|
-
}
|
|
257
|
-
if (options.cache.statsEnabled !== undefined) {
|
|
258
|
-
cacheOpts.statsEnabled = options.cache.statsEnabled;
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
};
|
|
263
|
-
|
|
264
|
-
// ========== 导出器层 ==========
|
|
265
|
-
const exporters = require("./lib/exporters");
|
|
266
|
-
|
|
267
|
-
// ========== 初始化默认语言包 ==========
|
|
268
|
-
const defaultLocales = require("./lib/locales");
|
|
269
|
-
Object.entries(defaultLocales).forEach(([locale, messages]) => {
|
|
270
|
-
Locale.addLocale(locale, messages);
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
// ========== 单例Validator ==========
|
|
274
|
-
let _defaultValidator = null;
|
|
275
|
-
let _validatorOptions = {}; // 存储 Validator 配置选项
|
|
276
|
-
|
|
277
|
-
/**
|
|
278
|
-
* 获取默认Validator实例(单例)
|
|
279
|
-
* @returns {Validator}
|
|
280
|
-
*/
|
|
281
|
-
function getDefaultValidator() {
|
|
282
|
-
if (!_defaultValidator) {
|
|
283
|
-
_defaultValidator = new Validator(_validatorOptions);
|
|
284
|
-
}
|
|
285
|
-
return _defaultValidator;
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
/**
|
|
289
|
-
* 智能类型转换:只转换字符串→数字(当schema要求number且能转换时)
|
|
290
|
-
* @private
|
|
291
|
-
* @param {*} data - 原始数据
|
|
292
|
-
* @param {Object} schema - JSON Schema对象
|
|
293
|
-
* @returns {*} 转换后的数据
|
|
294
|
-
*/
|
|
295
|
-
function smartCoerceTypes(data, schema) {
|
|
296
|
-
if (!data || typeof data !== "object") return data;
|
|
297
|
-
|
|
298
|
-
// 获取 schema 对象
|
|
299
|
-
const schemaObj = schema.toSchema ? schema.toSchema() : schema;
|
|
300
|
-
const properties = schemaObj.properties || {};
|
|
301
|
-
|
|
302
|
-
// 处理数组
|
|
303
|
-
if (Array.isArray(data)) {
|
|
304
|
-
return data.map((item) => smartCoerceTypes(item, schema));
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// 处理对象
|
|
308
|
-
const result = { ...data };
|
|
309
|
-
|
|
310
|
-
Object.keys(result).forEach((key) => {
|
|
311
|
-
const value = result[key];
|
|
312
|
-
const fieldSchema = properties[key];
|
|
313
|
-
|
|
314
|
-
if (!fieldSchema) return;
|
|
315
|
-
|
|
316
|
-
// ⚠️ 关键修复:如果字段有 enum 约束,不进行类型转换
|
|
317
|
-
// 原因:枚举验证需要严格匹配类型
|
|
318
|
-
// 例如:数字枚举 [1,2,3] 不应该接受字符串 "1"
|
|
319
|
-
if (fieldSchema.enum) {
|
|
320
|
-
return; // 跳过枚举字段的转换
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// 核心规则:只有同时满足以下三个条件才转换
|
|
324
|
-
// 1. 值是字符串
|
|
325
|
-
// 2. Schema 要求 number 类型
|
|
326
|
-
// 3. 能正常转换为有效数字
|
|
327
|
-
// 4. 不是枚举字段(已在上面检查)
|
|
328
|
-
if (fieldSchema.type === "number" && typeof value === "string") {
|
|
329
|
-
const trimmed = value.trim();
|
|
330
|
-
if (trimmed !== "") {
|
|
331
|
-
const num = Number(trimmed);
|
|
332
|
-
if (!isNaN(num)) {
|
|
333
|
-
result[key] = num;
|
|
334
|
-
}
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
// 处理嵌套对象
|
|
338
|
-
else if (
|
|
339
|
-
fieldSchema.type === "object" &&
|
|
340
|
-
typeof value === "object" &&
|
|
341
|
-
value !== null
|
|
342
|
-
) {
|
|
343
|
-
result[key] = smartCoerceTypes(value, fieldSchema);
|
|
344
|
-
}
|
|
345
|
-
// 处理数组元素
|
|
346
|
-
else if (fieldSchema.type === "array" && Array.isArray(value)) {
|
|
347
|
-
if (fieldSchema.items && fieldSchema.items.type === "number") {
|
|
348
|
-
result[key] = value.map((item) => {
|
|
349
|
-
if (typeof item === "string") {
|
|
350
|
-
const trimmed = item.trim();
|
|
351
|
-
if (trimmed !== "") {
|
|
352
|
-
const num = Number(trimmed);
|
|
353
|
-
return !isNaN(num) ? num : item;
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
return item;
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
return result;
|
|
363
|
-
}
|
|
364
|
-
|
|
365
|
-
/**
|
|
366
|
-
* 便捷验证方法(使用默认Validator)
|
|
367
|
-
* @param {Object} schema - JSON Schema对象
|
|
368
|
-
* @param {*} data - 待验证数据
|
|
369
|
-
* @param {Object} [options] - 验证选项
|
|
370
|
-
* @param {boolean} [options.format=true] - 是否格式化错误
|
|
371
|
-
* @param {string} [options.locale] - 动态指定语言(如 'zh-CN', 'en-US')
|
|
372
|
-
* @param {Object} [options.messages] - 自定义错误消息
|
|
373
|
-
* @param {boolean} [options.coerce=true] - 是否启用智能类型转换(字符串→数字)
|
|
374
|
-
* @returns {Object} 验证结果
|
|
375
|
-
*
|
|
376
|
-
* @example
|
|
377
|
-
* const { validate, dsl } = require('schema-dsl');
|
|
378
|
-
*
|
|
379
|
-
* const schema = dsl({ email: 'email!' });
|
|
380
|
-
*
|
|
381
|
-
* // 基本验证(默认启用智能转换)
|
|
382
|
-
* const result1 = validate(schema, { userId: '123', age: '25' });
|
|
383
|
-
* // userId 和 age 自动转为数字
|
|
384
|
-
*
|
|
385
|
-
* // 禁用智能转换
|
|
386
|
-
* const result2 = validate(schema, data, { coerce: false });
|
|
387
|
-
*
|
|
388
|
-
* // 指定语言
|
|
389
|
-
* const result3 = validate(schema, { email: 'invalid' }, { locale: 'zh-CN' });
|
|
390
|
-
*/
|
|
391
|
-
function validate(schema, data, options = {}) {
|
|
392
|
-
// 默认启用智能转换(只转换字符串→数字)
|
|
393
|
-
const shouldCoerce = options.coerce !== false;
|
|
394
|
-
|
|
395
|
-
if (shouldCoerce) {
|
|
396
|
-
data = smartCoerceTypes(data, schema);
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
return getDefaultValidator().validate(schema, data, options);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
// ========== 工具函数 ==========
|
|
403
|
-
const { TypeConverter, SchemaHelper } = require("./lib/utils");
|
|
404
|
-
const SchemaUtils = require("./lib/utils/SchemaUtils");
|
|
405
|
-
|
|
406
|
-
// ========== 验证器扩展 ==========
|
|
407
|
-
const { CustomKeywords } = require("./lib/validators");
|
|
408
|
-
|
|
409
|
-
// ========== 常量 ==========
|
|
410
|
-
const CONSTANTS = require("./lib/config/constants");
|
|
411
|
-
|
|
412
|
-
// ========== 自动安装 String 扩展 ==========
|
|
413
|
-
installStringExtensions(dsl);
|
|
414
|
-
|
|
415
|
-
// ========== 导出 ==========
|
|
416
|
-
|
|
417
|
-
// 导入 validateAsync
|
|
418
|
-
const { validateAsync } = require("./lib/adapters/DslAdapter");
|
|
419
|
-
|
|
420
|
-
module.exports = {
|
|
421
|
-
// 统一DSL API
|
|
422
|
-
dsl,
|
|
423
|
-
DslBuilder,
|
|
424
|
-
|
|
425
|
-
// 配置函数 (v1.0.4+)
|
|
426
|
-
config: dsl.config,
|
|
427
|
-
|
|
428
|
-
// String 扩展控制
|
|
429
|
-
installStringExtensions: () => installStringExtensions(dsl),
|
|
430
|
-
uninstallStringExtensions,
|
|
431
|
-
|
|
432
|
-
// 核心类
|
|
433
|
-
JSONSchemaCore,
|
|
434
|
-
Validator,
|
|
435
|
-
|
|
436
|
-
// 便捷方法(推荐)
|
|
437
|
-
validate, // 便捷验证(单例)
|
|
438
|
-
validateAsync, // v2.1.0 新增:异步验证
|
|
439
|
-
getDefaultValidator, // 获取单例Validator
|
|
440
|
-
ErrorFormatter,
|
|
441
|
-
CacheManager,
|
|
442
|
-
|
|
443
|
-
// 错误类 (v2.1.0 新增)
|
|
444
|
-
ValidationError,
|
|
445
|
-
I18nError, // v1.1.1 新增:多语言错误类
|
|
446
|
-
|
|
447
|
-
// 错误消息系统
|
|
448
|
-
ErrorCodes,
|
|
449
|
-
MessageTemplate,
|
|
450
|
-
Locale,
|
|
451
|
-
|
|
452
|
-
// 插件系统 (v2.2.0 新增)
|
|
453
|
-
PluginManager,
|
|
454
|
-
|
|
455
|
-
// 导出器
|
|
456
|
-
exporters,
|
|
457
|
-
MongoDBExporter: exporters.MongoDBExporter,
|
|
458
|
-
MySQLExporter: exporters.MySQLExporter,
|
|
459
|
-
PostgreSQLExporter: exporters.PostgreSQLExporter,
|
|
460
|
-
MarkdownExporter: exporters.MarkdownExporter,
|
|
461
|
-
|
|
462
|
-
// 工具函数
|
|
463
|
-
TypeConverter,
|
|
464
|
-
SchemaHelper,
|
|
465
|
-
SchemaUtils, // v2.0.1新增:Schema工具类
|
|
466
|
-
|
|
467
|
-
// 验证器扩展
|
|
468
|
-
CustomKeywords,
|
|
469
|
-
|
|
470
|
-
// 常量
|
|
471
|
-
CONSTANTS,
|
|
472
|
-
|
|
473
|
-
// 版本信息
|
|
474
|
-
VERSION: "1.2.3",
|
|
475
|
-
};
|
package/index.mjs
DELETED
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import schemaDsl from './index.js';
|
|
2
|
-
|
|
3
|
-
export const {
|
|
4
|
-
// 统一DSL API
|
|
5
|
-
dsl,
|
|
6
|
-
DslBuilder,
|
|
7
|
-
|
|
8
|
-
// 配置函数 (v1.0.4+)
|
|
9
|
-
config,
|
|
10
|
-
|
|
11
|
-
// String 扩展控制
|
|
12
|
-
installStringExtensions,
|
|
13
|
-
uninstallStringExtensions,
|
|
14
|
-
|
|
15
|
-
// 核心类
|
|
16
|
-
JSONSchemaCore,
|
|
17
|
-
Validator,
|
|
18
|
-
|
|
19
|
-
// 便捷方法(推荐)
|
|
20
|
-
validate,
|
|
21
|
-
validateAsync,
|
|
22
|
-
getDefaultValidator,
|
|
23
|
-
ErrorFormatter,
|
|
24
|
-
CacheManager,
|
|
25
|
-
|
|
26
|
-
// 错误类 (v2.1.0 新增)
|
|
27
|
-
ValidationError,
|
|
28
|
-
I18nError,
|
|
29
|
-
|
|
30
|
-
// 错误消息系统
|
|
31
|
-
ErrorCodes,
|
|
32
|
-
MessageTemplate,
|
|
33
|
-
Locale,
|
|
34
|
-
|
|
35
|
-
// 插件系统 (v2.2.0 新增)
|
|
36
|
-
PluginManager,
|
|
37
|
-
|
|
38
|
-
// 导出器
|
|
39
|
-
exporters,
|
|
40
|
-
MongoDBExporter,
|
|
41
|
-
MySQLExporter,
|
|
42
|
-
PostgreSQLExporter,
|
|
43
|
-
MarkdownExporter,
|
|
44
|
-
|
|
45
|
-
// 工具函数
|
|
46
|
-
TypeConverter,
|
|
47
|
-
SchemaHelper,
|
|
48
|
-
SchemaUtils,
|
|
49
|
-
|
|
50
|
-
// 验证器扩展
|
|
51
|
-
CustomKeywords,
|
|
52
|
-
|
|
53
|
-
// 常量
|
|
54
|
-
CONSTANTS,
|
|
55
|
-
|
|
56
|
-
// 版本信息
|
|
57
|
-
VERSION
|
|
58
|
-
} = schemaDsl;
|
|
59
|
-
|
|
60
|
-
export default dsl;
|