schema-dsl 1.2.2 → 1.2.4
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 +11 -10
- package/CHANGELOG.md +4 -3
- package/STATUS.md +28 -3
- package/changelogs/v1.2.3.md +124 -0
- package/docs/add-custom-locale.md +90 -2
- package/index.d.ts +3540 -3532
- package/index.js +87 -24
- package/index.mjs +38 -8
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -110,12 +110,83 @@ dsl.error = {
|
|
|
110
110
|
assert: (condition, code, paramsOrLocale, statusCode, locale) => I18nError.assert(condition, code, paramsOrLocale, statusCode, locale)
|
|
111
111
|
};
|
|
112
112
|
|
|
113
|
+
/**
|
|
114
|
+
* 从目录递归加载语言包(内部函数)
|
|
115
|
+
*
|
|
116
|
+
* 支持子目录递归扫描,子目录名作为模块组织层(不影响语言 key)。
|
|
117
|
+
* 同名 key 冲突时:strict 模式抛错,默认模式打 WARN 日志。
|
|
118
|
+
*
|
|
119
|
+
* @param {string} dirPath - 目录绝对路径
|
|
120
|
+
* @param {Object} options - 配置选项
|
|
121
|
+
* @param {boolean} [options.strict=false] - 严格模式:同名 key 冲突时抛出 Error
|
|
122
|
+
* @private
|
|
123
|
+
*/
|
|
124
|
+
function loadLocalesFromDir(dirPath, options = {}) {
|
|
125
|
+
const fs = require('fs');
|
|
126
|
+
const path = require('path');
|
|
127
|
+
|
|
128
|
+
if (!fs.existsSync(dirPath) || !fs.statSync(dirPath).isDirectory()) {
|
|
129
|
+
console.warn('[schema-dsl] i18n path does not exist or is not a directory:', dirPath);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// 语言代码格式校验:zh-CN / en-US / zh / en 等
|
|
134
|
+
const LOCALE_NAME_RE = /^[a-z]{2,3}(-[A-Z]{2,4})?$/;
|
|
135
|
+
|
|
136
|
+
const entries = fs.readdirSync(dirPath, { withFileTypes: true });
|
|
137
|
+
|
|
138
|
+
entries.forEach(entry => {
|
|
139
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
140
|
+
|
|
141
|
+
if (entry.isDirectory()) {
|
|
142
|
+
// 递归进入子目录(子目录名仅作模块组织层,不影响语言 key)
|
|
143
|
+
loadLocalesFromDir(fullPath, options);
|
|
144
|
+
} else if (entry.isFile()) {
|
|
145
|
+
const ext = path.extname(entry.name);
|
|
146
|
+
if (ext !== '.js' && ext !== '.json') return;
|
|
147
|
+
|
|
148
|
+
const localeName = path.basename(entry.name, ext);
|
|
149
|
+
|
|
150
|
+
// 文件名格式校验:只加载符合语言代码格式的文件
|
|
151
|
+
if (!LOCALE_NAME_RE.test(localeName)) {
|
|
152
|
+
// 仅 debug 级别,不影响正常运行
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let messages;
|
|
157
|
+
try {
|
|
158
|
+
messages = require(path.resolve(fullPath));
|
|
159
|
+
} catch (e) {
|
|
160
|
+
console.warn('[schema-dsl] Failed to load locale file:', fullPath, e.message);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// 冲突检测:检查 messages 的每个 key 是否已存在于当前语言包
|
|
165
|
+
const existing = Locale.locales[localeName] || {};
|
|
166
|
+
const conflictKeys = Object.keys(messages).filter(k => Object.prototype.hasOwnProperty.call(existing, k));
|
|
167
|
+
|
|
168
|
+
if (conflictKeys.length > 0) {
|
|
169
|
+
const keyList = conflictKeys.join(', ');
|
|
170
|
+
const msg = `[schema-dsl] i18n key 冲突 in locale '${localeName}'\n 冲突 key: ${keyList}\n 来源文件: ${fullPath}`;
|
|
171
|
+
if (options.strict) {
|
|
172
|
+
throw new Error(msg);
|
|
173
|
+
} else {
|
|
174
|
+
console.warn(msg);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
Locale.addLocale(localeName, messages);
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
|
|
113
183
|
/**
|
|
114
184
|
* 全局配置
|
|
115
185
|
* @param {Object} options - 配置选项
|
|
116
186
|
* @param {Object} options.patterns - 验证规则扩展 (phone, idCard, creditCard)
|
|
117
|
-
* @param {string|Object} options.i18n -
|
|
187
|
+
* @param {string|Object} options.i18n - 多语言配置(目录路径、对象语言包、或含 localesPath 的对象)
|
|
118
188
|
* @param {Object} options.cache - 缓存配置
|
|
189
|
+
* @param {boolean} [options.strict=false] - 严格模式:i18n 目录扫描时 key 冲突直接抛错(默认 false)
|
|
119
190
|
*/
|
|
120
191
|
dsl.config = function (options = {}) {
|
|
121
192
|
const patterns = require('./lib/config/patterns');
|
|
@@ -127,31 +198,24 @@ dsl.config = function (options = {}) {
|
|
|
127
198
|
if (options.patterns.creditCard) Object.assign(patterns.creditCard, options.patterns.creditCard);
|
|
128
199
|
}
|
|
129
200
|
|
|
130
|
-
// 多语言支持 (v1.0.1
|
|
201
|
+
// 多语言支持 (v1.0.1 优化;v1.2.3 增强:递归子目录 + 冲突检测)
|
|
131
202
|
if (options.i18n) {
|
|
132
|
-
// 方式 1:
|
|
203
|
+
// 方式 1: 传入目录路径(字符串)→ 递归扫描
|
|
133
204
|
if (typeof options.i18n === 'string') {
|
|
134
|
-
|
|
135
|
-
const path = require('path');
|
|
136
|
-
|
|
137
|
-
if (fs.existsSync(options.i18n) && fs.statSync(options.i18n).isDirectory()) {
|
|
138
|
-
const files = fs.readdirSync(options.i18n);
|
|
139
|
-
files.forEach(file => {
|
|
140
|
-
if (file.endsWith('.js') || file.endsWith('.json')) {
|
|
141
|
-
const localeName = path.basename(file, path.extname(file));
|
|
142
|
-
const messages = require(path.resolve(options.i18n, file));
|
|
143
|
-
Locale.addLocale(localeName, messages);
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
} else {
|
|
147
|
-
console.warn('[schema-dsl] i18n path does not exist:', options.i18n);
|
|
148
|
-
}
|
|
205
|
+
loadLocalesFromDir(options.i18n, options);
|
|
149
206
|
}
|
|
150
|
-
// 方式 2:
|
|
207
|
+
// 方式 2: 传入对象
|
|
151
208
|
else if (typeof options.i18n === 'object') {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
209
|
+
// 方式 2a: 含 localesPath 字段 → 走目录扫描(兼容文档记载用法)
|
|
210
|
+
if (options.i18n.localesPath) {
|
|
211
|
+
loadLocalesFromDir(options.i18n.localesPath, options);
|
|
212
|
+
}
|
|
213
|
+
// 方式 2b: 直接传语言包对象 { 'zh-CN': {...}, 'en-US': {...} }(原有逻辑,不变)
|
|
214
|
+
else {
|
|
215
|
+
Object.keys(options.i18n).forEach(locale => {
|
|
216
|
+
Locale.addLocale(locale, options.i18n[locale]);
|
|
217
|
+
});
|
|
218
|
+
}
|
|
155
219
|
}
|
|
156
220
|
}
|
|
157
221
|
|
|
@@ -348,7 +412,6 @@ module.exports = {
|
|
|
348
412
|
// 核心类
|
|
349
413
|
JSONSchemaCore,
|
|
350
414
|
Validator,
|
|
351
|
-
DslBuilder, // v1.1.0 新增:导出DslBuilder供插件使用
|
|
352
415
|
|
|
353
416
|
// 便捷方法(推荐)
|
|
354
417
|
validate, // 便捷验证(单例)
|
|
@@ -388,7 +451,7 @@ module.exports = {
|
|
|
388
451
|
CONSTANTS,
|
|
389
452
|
|
|
390
453
|
// 版本信息
|
|
391
|
-
VERSION: '1.
|
|
454
|
+
VERSION: '1.2.3'
|
|
392
455
|
};
|
|
393
456
|
|
|
394
457
|
|
package/index.mjs
CHANGED
|
@@ -1,30 +1,60 @@
|
|
|
1
1
|
import schemaDsl from './index.js';
|
|
2
2
|
|
|
3
3
|
export const {
|
|
4
|
+
// 统一DSL API
|
|
4
5
|
dsl,
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
DslBuilder,
|
|
7
|
+
|
|
8
|
+
// 配置函数 (v1.0.4+)
|
|
9
|
+
config,
|
|
10
|
+
|
|
11
|
+
// String 扩展控制
|
|
12
|
+
installStringExtensions,
|
|
13
|
+
uninstallStringExtensions,
|
|
14
|
+
|
|
15
|
+
// 核心类
|
|
7
16
|
JSONSchemaCore,
|
|
8
17
|
Validator,
|
|
18
|
+
|
|
19
|
+
// 便捷方法(推荐)
|
|
20
|
+
validate,
|
|
21
|
+
validateAsync,
|
|
22
|
+
getDefaultValidator,
|
|
9
23
|
ErrorFormatter,
|
|
10
24
|
CacheManager,
|
|
11
|
-
|
|
25
|
+
|
|
26
|
+
// 错误类 (v2.1.0 新增)
|
|
27
|
+
ValidationError,
|
|
28
|
+
I18nError,
|
|
29
|
+
|
|
30
|
+
// 错误消息系统
|
|
12
31
|
ErrorCodes,
|
|
13
32
|
MessageTemplate,
|
|
14
33
|
Locale,
|
|
34
|
+
|
|
35
|
+
// 插件系统 (v2.2.0 新增)
|
|
36
|
+
PluginManager,
|
|
37
|
+
|
|
38
|
+
// 导出器
|
|
15
39
|
exporters,
|
|
16
40
|
MongoDBExporter,
|
|
17
41
|
MySQLExporter,
|
|
18
42
|
PostgreSQLExporter,
|
|
43
|
+
MarkdownExporter,
|
|
44
|
+
|
|
45
|
+
// 工具函数
|
|
19
46
|
TypeConverter,
|
|
20
47
|
SchemaHelper,
|
|
21
48
|
SchemaUtils,
|
|
49
|
+
|
|
50
|
+
// 验证器扩展
|
|
22
51
|
CustomKeywords,
|
|
52
|
+
|
|
53
|
+
// 常量
|
|
23
54
|
CONSTANTS,
|
|
24
|
-
VERSION,
|
|
25
|
-
installStringExtensions,
|
|
26
|
-
uninstallStringExtensions
|
|
27
|
-
} = schema-dsl;
|
|
28
55
|
|
|
29
|
-
|
|
56
|
+
// 版本信息
|
|
57
|
+
VERSION
|
|
58
|
+
} = schemaDsl;
|
|
30
59
|
|
|
60
|
+
export default dsl;
|