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/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
- const fs = require('fs');
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
- Object.keys(options.i18n).forEach(locale => {
153
- Locale.addLocale(locale, options.i18n[locale]);
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.0.4'
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
- validate,
6
- getDefaultValidator,
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
- DslBuilder,
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
- export default schemaDsl;
56
+ // 版本信息
57
+ VERSION
58
+ } = schemaDsl;
30
59
 
60
+ export default dsl;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-dsl",
3
- "version": "1.2.2",
3
+ "version": "1.2.4",
4
4
  "description": "简洁强大的JSON Schema验证库 - DSL语法 + String扩展 + 便捷validate",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",