mm_validate 0.0.0-stage → 1.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/LICENSE ADDED
@@ -0,0 +1,15 @@
1
+ ISC License
2
+
3
+ Copyright (c) 2026 qww
4
+
5
+ Permission to use, copy, modify, and/or distribute this software for any
6
+ purpose with or without fee is hereby granted, provided that the above
7
+ copyright notice and this permission notice appear in all copies.
8
+
9
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,191 @@
1
- # Temporary Holding Version
1
+ # mm_validate
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ 一个轻量的 Node.js 参数验证模块。按 **JSON Schema 常用子集** 校验参数,校验失败时返回**首个**错误信息,并通过字段路径直接定位出错位置。
4
+
5
+ - 入口:`index.js`(CommonJS)
6
+ - 运行时依赖:无
7
+ - 测试覆盖率:100%(见 `jest.config.js` 阈值)
8
+
9
+ ## 特性
10
+
11
+ - **零依赖**:只依赖 Node.js 原生能力,安装体积小。
12
+ - **短路返回**:按关键字顺序校验,命中第一个错误立即返回。
13
+ - **路径提示**:嵌套对象与数组的错误信息自动附带路径,如 `user.age`、`[1].id`。
14
+ - **递归校验**:支持 `properties` 与 `items` 的任意层级嵌套。
15
+ - **结果简单**:通过返回空字符串 `''`,失败返回错误描述,便于直接用于 `if` 判断。
16
+
17
+ ## 安装
18
+
19
+ ```bash
20
+ npm install mm_validate
21
+ ```
22
+
23
+ ## 环境要求
24
+
25
+ - Node.js >= 16
26
+ - 模块规范:CommonJS
27
+
28
+ ## 快速开始
29
+
30
+ ```js
31
+ 'use strict';
32
+
33
+ const { Validate } = require('mm_validate');
34
+
35
+ const schema = {
36
+ type: 'object',
37
+ required: ['name', 'age'],
38
+ properties: {
39
+ name: { type: 'string', min_length: 2, max_length: 20 },
40
+ age: { type: 'integer', minimum: 0, maximum: 150 },
41
+ role: { type: 'string', enum: ['admin', 'user'] },
42
+ tags: { type: 'array', items: { type: 'string' } }
43
+ }
44
+ };
45
+
46
+ const validate = new Validate(schema);
47
+
48
+ console.log(validate.check({ name: '张三', age: 28, role: 'admin', tags: ['a'] }));
49
+ // ''
50
+
51
+ console.log(validate.check({ name: '张三' }));
52
+ // 'age: required missing'
53
+
54
+ console.log(validate.check({ name: '张三', age: 'x' }));
55
+ // 'age: type expected "integer" but got "string"'
56
+ ```
57
+
58
+ ## API
59
+
60
+ ### `new Validate(config = {})`
61
+
62
+ 创建一个校验器。
63
+
64
+ | 参数 | 类型 | 说明 |
65
+ | --- | --- | --- |
66
+ | `config` | `Object` | 校验配置(JSON Schema 常用子集)。传入非对象(如 `null`、数组)时不执行任何校验。 |
67
+
68
+ 校验器会按引用保存配置,可在创建后修改 `validate.config` 复用实例。
69
+
70
+ ### `check(params)`
71
+
72
+ 校验参数。
73
+
74
+ | 参数 | 类型 | 说明 |
75
+ | --- | --- | --- |
76
+ | `params` | `*` | 待校验的参数。 |
77
+
78
+ | 返回值 | 说明 |
79
+ | --- | --- |
80
+ | `''` | 校验通过 |
81
+ | `string` | 校验失败,返回首个错误信息(含字段路径) |
82
+
83
+ ## 支持的校验关键字
84
+
85
+ | 关键字 | 适用类型 | 说明 | 错误示例 |
86
+ | --- | --- | --- | --- |
87
+ | `type` | 任意 | 数据类型:`null` / `array` / `object` / `string` / `number` / `integer` / `boolean`。`number` 不接受 `NaN`、`Infinity` | `type expected "string" but got "number"` |
88
+ | `enum` | 任意 | 值必须属于枚举数组 | `enum expected ["admin","user"] but got "guest"` |
89
+ | `const` | 任意 | 值必须严格等于指定值 | `const expected 1 but got 2` |
90
+ | `min_length` | `string` | 字符串最小长度 | `min_length expected >= 3 but got 2` |
91
+ | `max_length` | `string` | 字符串最大长度 | `max_length expected <= 1 but got 2` |
92
+ | `minimum` | `number` | 数值下限(包含) | `minimum expected >= 3 but got 2` |
93
+ | `maximum` | `number` | 数值上限(包含) | `maximum expected <= 1 but got 2` |
94
+ | `pattern` | `string` | 正则表达式(字符串形式) | `pattern expected match /^[a-z]+$/ but got "qww123"` |
95
+ | `required` | `object` | 必填字段名数组 | `name: required missing` |
96
+ | `properties` | `object` | 子字段配置,递归校验 | `user.age: type expected "number" but got "string"` |
97
+ | `items` | `array` | 数组元素配置,递归校验 | `[1].id: type expected "number" but got "string"` |
98
+
99
+ 校验顺序为:`type` → `enum` → `const` → `min_length` / `max_length` → `minimum` / `maximum` → `pattern` → `required` → `properties` → `items`。
100
+
101
+ 未声明或类型不符合要求的关键字会被跳过。例如 `min_length` 只对字符串生效,`required` 只对对象生效。
102
+
103
+ ## 错误信息与路径
104
+
105
+ 错误信息格式为 `路径: 错误详情`,顶层错误不带路径前缀。
106
+
107
+ | 场景 | 路径示例 |
108
+ | --- | --- |
109
+ | 顶层字段 | `age` |
110
+ | 嵌套对象 | `user.age` |
111
+ | 数组元素 | `[1]` |
112
+ | 对象数组元素字段 | `[1].id` |
113
+ | 嵌套数组 | `[1][1]` |
114
+
115
+ ## 在接口中校验参数
116
+
117
+ ```js
118
+ 'use strict';
119
+
120
+ const { Validate } = require('mm_validate');
121
+
122
+ const ARTICLE_SCHEMA = {
123
+ type: 'object',
124
+ required: ['title', 'content', 'status'],
125
+ properties: {
126
+ title: { type: 'string', min_length: 2, max_length: 50 },
127
+ content: { type: 'string', min_length: 1 },
128
+ status: { type: 'string', enum: ['draft', 'published'] },
129
+ views: { type: 'integer', minimum: 0 },
130
+ tags: { type: 'array', items: { type: 'string', min_length: 1 } }
131
+ }
132
+ };
133
+
134
+ /**
135
+ * 校验接口请求参数
136
+ * @param {Object} params 请求参数
137
+ * @returns {{code: number, msg: string}} 校验结果
138
+ */
139
+ function validateRequest(params) {
140
+ const tip = new Validate(ARTICLE_SCHEMA).check(params);
141
+ return tip === '' ? { code: 0, msg: 'ok' } : { code: 1, msg: tip };
142
+ }
143
+
144
+ console.log(
145
+ validateRequest({
146
+ title: 'mm_validate 使用说明',
147
+ content: '按 JSON Schema 常用子集校验参数。',
148
+ status: 'published'
149
+ })
150
+ );
151
+ // { code: 0, msg: 'ok' }
152
+
153
+ console.log(validateRequest({ title: 'a', content: '', status: 'deleted' }));
154
+ // { code: 1, msg: 'title: min_length expected >= 2 but got 1' }
155
+ ```
156
+
157
+ ## 运行示例
158
+
159
+ ```bash
160
+ npm run demo
161
+ ```
162
+
163
+ 示例覆盖基础类型、对象嵌套、数组元素、接口参数四类场景,源码见 `example/index.js`。
164
+
165
+ ## 测试
166
+
167
+ ```bash
168
+ npm test
169
+ ```
170
+
171
+ 使用 Jest 运行单元测试并生成覆盖率报告。`jest.config.js` 已配置语句、分支、函数、行覆盖率均为 **100%**,未达标时命令会失败。
172
+
173
+ ## 目录结构
174
+
175
+ ```
176
+ mm_validate/
177
+ ├── index.js # 入口,导出 Validate
178
+ ├── lib/
179
+ │ └── validate.js # 校验器实现
180
+ ├── example/
181
+ │ └── index.js # 使用示例
182
+ ├── test/
183
+ │ ├── index.test.js
184
+ │ └── validate.test.js
185
+ ├── jest.config.js
186
+ └── package.json
187
+ ```
188
+
189
+ ## 许可证
190
+
191
+ [ISC](LICENSE)
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ const { Validate } = require('../index');
4
+
5
+ const ARTICLE_SCHEMA = {
6
+ type: 'object',
7
+ required: ['title', 'content', 'status'],
8
+ properties: {
9
+ title: { type: 'string', min_length: 2, max_length: 50 },
10
+ content: { type: 'string', min_length: 1 },
11
+ status: { type: 'string', enum: ['draft', 'published'] },
12
+ views: { type: 'integer', minimum: 0 },
13
+ tags: { type: 'array', items: { type: 'string', min_length: 1 } }
14
+ }
15
+ };
16
+
17
+ /**
18
+ * 输出单次校验结果
19
+ * @param {string} title 场景名称
20
+ * @param {Object} schema 校验配置
21
+ * @param {*} params 调用参数
22
+ * @returns {void}
23
+ */
24
+ function printResult(title, schema, params) {
25
+ const tip = new Validate(schema).check(params);
26
+ const result = tip === '' ? '通过' : tip;
27
+ console.log(`${title} -> ${result}`);
28
+ }
29
+
30
+ /**
31
+ * 基础类型校验
32
+ * @returns {void}
33
+ */
34
+ function demoBasic() {
35
+ console.log('=== 基础类型校验 ===');
36
+ printResult('字符串通过', { type: 'string' }, 'hello');
37
+ printResult('字符串失败', { type: 'string' }, 100);
38
+ printResult('整数通过', { type: 'integer', minimum: 0, maximum: 150 }, 30);
39
+ printResult('整数失败', { type: 'integer', minimum: 0 }, 1.5);
40
+ printResult('枚举失败', { type: 'string', enum: ['admin', 'user'] }, 'guest');
41
+ printResult('正则失败', { type: 'string', pattern: '^[a-z]+$' }, 'qww123');
42
+ }
43
+
44
+ /**
45
+ * 对象与嵌套字段校验
46
+ * @returns {void}
47
+ */
48
+ function demoObject() {
49
+ console.log('=== 对象校验 ===');
50
+ const schema = {
51
+ type: 'object',
52
+ required: ['name', 'age'],
53
+ properties: {
54
+ name: { type: 'string', min_length: 1 },
55
+ age: { type: 'integer', minimum: 0, maximum: 150 },
56
+ address: {
57
+ type: 'object',
58
+ required: ['city'],
59
+ properties: { city: { type: 'string' } }
60
+ }
61
+ }
62
+ };
63
+
64
+ printResult('对象通过', schema, { name: '张三', age: 28, address: { city: '广州' } });
65
+ printResult('缺少必填字段', schema, { name: '张三' });
66
+ printResult('嵌套字段错误', schema, { name: '张三', age: 28, address: {} });
67
+ }
68
+
69
+ /**
70
+ * 数组元素校验
71
+ * @returns {void}
72
+ */
73
+ function demoArray() {
74
+ console.log('=== 数组校验 ===');
75
+ const schema = { type: 'array', items: { type: 'number' } };
76
+ printResult('数组通过', schema, [1, 2, 3]);
77
+ printResult('数组元素错误', schema, [1, 'x', 3]);
78
+ }
79
+
80
+ /**
81
+ * 校验接口请求参数并返回统一结构
82
+ * @param {Object} params 请求参数
83
+ * @returns {{code: number, msg: string}} 校验结果
84
+ */
85
+ function validateRequest(params) {
86
+ const tip = new Validate(ARTICLE_SCHEMA).check(params);
87
+ return tip === '' ? { code: 0, msg: 'ok' } : { code: 1, msg: tip };
88
+ }
89
+
90
+ /**
91
+ * 接口参数校验场景
92
+ * @returns {void}
93
+ */
94
+ function demoRequest() {
95
+ console.log('=== 接口参数校验 ===');
96
+ const ok_params = {
97
+ title: 'mm_validate 使用说明',
98
+ content: '按 JSON Schema 常用子集校验参数。',
99
+ status: 'published',
100
+ views: 100,
101
+ tags: ['nodejs', 'validate']
102
+ };
103
+ console.log('合法参数 ->', validateRequest(ok_params));
104
+
105
+ const bad_params = { title: 'a', content: '', status: 'deleted', views: -1, tags: [''] };
106
+ console.log('非法参数 ->', validateRequest(bad_params));
107
+ }
108
+
109
+ /**
110
+ * 运行全部示例
111
+ * @returns {void}
112
+ */
113
+ function demo() {
114
+ demoBasic();
115
+ demoObject();
116
+ demoArray();
117
+ demoRequest();
118
+ }
119
+
120
+ demo();
package/index.js ADDED
@@ -0,0 +1,24 @@
1
+ 'use strict';
2
+
3
+ const Admin = require('mm_corejs').Admin;
4
+ const Validate = require('./lib/validate');
5
+
6
+ const admin = new Admin();
7
+ admin.setClass(Validate);
8
+
9
+ module.exports = {
10
+ Validate,
11
+ admin,
12
+ /**
13
+ * 获取指定作用域的校验器实例,不存在时创建
14
+ * @param {string} [scope] 作用域名称,缺省时使用 os
15
+ * @param {Object} [config] 校验配置(JSON Schema 常用子集)
16
+ * @returns {Validate} 校验器实例
17
+ */
18
+ validateAdmin(scope, config = {}) {
19
+ if (!scope) {
20
+ scope = 'os';
21
+ }
22
+ return admin.get(scope, config);
23
+ }
24
+ };
@@ -0,0 +1,303 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * 参数验证器 —— 按 JSON Schema 常用子集校验参数,返回首个错误信息。
5
+ *
6
+ * 支持的关键字:
7
+ * type / enum / const / min_length / max_length / minimum / maximum
8
+ * pattern / required / properties / items
9
+ *
10
+ * 用法:
11
+ * new Validate(schema).check(params) === '' 表示通过。
12
+ */
13
+ class Validate {
14
+ /**
15
+ * 构造函数
16
+ * @param {Object} config 校验配置(JSON Schema 常用子集),非对象时视为不校验
17
+ */
18
+ constructor(config = {}) {
19
+ this.config = config;
20
+ }
21
+
22
+ /**
23
+ * 校验参数
24
+ * @param {*} params 调用参数
25
+ * @returns {string} 验证通过返回空字符串,否则返回首个错误信息
26
+ */
27
+ check(params) {
28
+ return this._checkSchema(params, this.config, '');
29
+ }
30
+
31
+ // ---------- 校验编排 ----------
32
+ /**
33
+ * 按 schema 递归校验任意值,按关键字顺序短路返回首个错误
34
+ * @param {*} value 待校验值
35
+ * @param {Object} schema 校验配置
36
+ * @param {string} path 字段路径
37
+ * @returns {string} 错误信息或空字符串
38
+ */
39
+ _checkSchema(value, schema, path) {
40
+ if (!this._isObject(schema)) return '';
41
+ return (
42
+ this._checkType(value, schema, path) ||
43
+ this._checkEnum(value, schema, path) ||
44
+ this._checkConst(value, schema, path) ||
45
+ this._checkLength(value, schema, path) ||
46
+ this._checkRange(value, schema, path) ||
47
+ this._checkPattern(value, schema, path) ||
48
+ this._checkRequired(value, schema, path) ||
49
+ this._checkProperties(value, schema, path) ||
50
+ this._checkItems(value, schema, path)
51
+ );
52
+ }
53
+
54
+ // ---------- 关键字校验 ----------
55
+ /**
56
+ * 校验 type 关键字
57
+ * @param {*} value 待校验值
58
+ * @param {Object} schema 校验配置
59
+ * @param {string} path 字段路径
60
+ * @returns {string} 错误信息或空字符串
61
+ */
62
+ _checkType(value, schema, path) {
63
+ if (schema.type === undefined) return '';
64
+ if (this._isType(value, schema.type)) return '';
65
+ const detail = `type expected "${schema.type}" but got "${this._getTypeName(value)}"`;
66
+ return this._getPathMessage(path, detail);
67
+ }
68
+
69
+ /**
70
+ * 校验 enum 关键字
71
+ * @param {*} value 待校验值
72
+ * @param {Object} schema 校验配置
73
+ * @param {string} path 字段路径
74
+ * @returns {string} 错误信息或空字符串
75
+ */
76
+ _checkEnum(value, schema, path) {
77
+ if (!Array.isArray(schema.enum)) return '';
78
+ if (schema.enum.includes(value)) return '';
79
+ const detail = `enum expected ${JSON.stringify(schema.enum)} but got ${JSON.stringify(value)}`;
80
+ return this._getPathMessage(path, detail);
81
+ }
82
+
83
+ /**
84
+ * 校验 const 关键字
85
+ * @param {*} value 待校验值
86
+ * @param {Object} schema 校验配置
87
+ * @param {string} path 字段路径
88
+ * @returns {string} 错误信息或空字符串
89
+ */
90
+ _checkConst(value, schema, path) {
91
+ if (schema.const === undefined) return '';
92
+ if (value === schema.const) return '';
93
+ const detail = `const expected ${JSON.stringify(schema.const)} but got ${JSON.stringify(value)}`;
94
+ return this._getPathMessage(path, detail);
95
+ }
96
+
97
+ /**
98
+ * 校验 min_length / max_length 关键字
99
+ * @param {*} value 待校验值
100
+ * @param {Object} schema 校验配置
101
+ * @param {string} path 字段路径
102
+ * @returns {string} 错误信息或空字符串
103
+ */
104
+ _checkLength(value, schema, path) {
105
+ if (typeof value !== 'string') return '';
106
+ if (typeof schema.min_length === 'number' && value.length < schema.min_length) {
107
+ const detail = `min_length expected >= ${schema.min_length} but got ${value.length}`;
108
+ return this._getPathMessage(path, detail);
109
+ }
110
+ if (typeof schema.max_length === 'number' && value.length > schema.max_length) {
111
+ const detail = `max_length expected <= ${schema.max_length} but got ${value.length}`;
112
+ return this._getPathMessage(path, detail);
113
+ }
114
+ return '';
115
+ }
116
+
117
+ /**
118
+ * 校验 minimum / maximum 关键字
119
+ * @param {*} value 待校验值
120
+ * @param {Object} schema 校验配置
121
+ * @param {string} path 字段路径
122
+ * @returns {string} 错误信息或空字符串
123
+ */
124
+ _checkRange(value, schema, path) {
125
+ if (typeof value !== 'number') return '';
126
+ if (typeof schema.minimum === 'number' && value < schema.minimum) {
127
+ const detail = `minimum expected >= ${schema.minimum} but got ${value}`;
128
+ return this._getPathMessage(path, detail);
129
+ }
130
+ if (typeof schema.maximum === 'number' && value > schema.maximum) {
131
+ const detail = `maximum expected <= ${schema.maximum} but got ${value}`;
132
+ return this._getPathMessage(path, detail);
133
+ }
134
+ return '';
135
+ }
136
+
137
+ /**
138
+ * 校验 pattern 关键字
139
+ * @param {*} value 待校验值
140
+ * @param {Object} schema 校验配置
141
+ * @param {string} path 字段路径
142
+ * @returns {string} 错误信息或空字符串
143
+ */
144
+ _checkPattern(value, schema, path) {
145
+ if (typeof value !== 'string') return '';
146
+ if (typeof schema.pattern !== 'string') return '';
147
+ if (new RegExp(schema.pattern).test(value)) return '';
148
+ const detail = `pattern expected match /${schema.pattern}/ but got "${value}"`;
149
+ return this._getPathMessage(path, detail);
150
+ }
151
+
152
+ /**
153
+ * 校验 required 关键字
154
+ * @param {*} value 待校验值
155
+ * @param {Object} schema 校验配置
156
+ * @param {string} path 字段路径
157
+ * @returns {string} 错误信息或空字符串
158
+ */
159
+ _checkRequired(value, schema, path) {
160
+ if (!Array.isArray(schema.required)) return '';
161
+ if (!this._isObject(value)) return '';
162
+ for (const key of schema.required) {
163
+ if (this._isOwnProperty(value, key)) continue;
164
+ return this._getPathMessage(this._getKeyPath(path, key), 'required missing');
165
+ }
166
+ return '';
167
+ }
168
+
169
+ /**
170
+ * 校验 properties 关键字(递归)
171
+ * @param {*} value 待校验值
172
+ * @param {Object} schema 校验配置
173
+ * @param {string} path 字段路径
174
+ * @returns {string} 错误信息或空字符串
175
+ */
176
+ _checkProperties(value, schema, path) {
177
+ if (!this._isObject(schema.properties)) return '';
178
+ if (!this._isObject(value)) return '';
179
+ for (const key of Object.keys(schema.properties)) {
180
+ if (!this._isOwnProperty(value, key)) continue;
181
+ const tip = this._checkSchema(value[key], schema.properties[key], this._getKeyPath(path, key));
182
+ if (tip) return tip;
183
+ }
184
+ return '';
185
+ }
186
+
187
+ /**
188
+ * 校验 items 关键字(递归)
189
+ * @param {*} value 待校验值
190
+ * @param {Object} schema 校验配置
191
+ * @param {string} path 字段路径
192
+ * @returns {string} 错误信息或空字符串
193
+ */
194
+ _checkItems(value, schema, path) {
195
+ if (!this._isObject(schema.items)) return '';
196
+ if (!Array.isArray(value)) return '';
197
+ for (let i = 0; i < value.length; i++) {
198
+ const tip = this._checkSchema(value[i], schema.items, this._getArrayPath(path, i));
199
+ if (tip) return tip;
200
+ }
201
+ return '';
202
+ }
203
+
204
+ // ---------- 类型判定 ----------
205
+ /**
206
+ * 判断值是否匹配指定 JSON 类型
207
+ * @param {*} value 待判定值
208
+ * @param {string} type 类型名称
209
+ * @returns {boolean} 是否匹配
210
+ */
211
+ _isType(value, type) {
212
+ switch (type) {
213
+ case 'null':
214
+ return value === null;
215
+ case 'array':
216
+ return Array.isArray(value);
217
+ case 'object':
218
+ return this._isObject(value);
219
+ case 'string':
220
+ return typeof value === 'string';
221
+ case 'number':
222
+ return this._isFiniteNumber(value);
223
+ case 'integer':
224
+ return Number.isInteger(value);
225
+ case 'boolean':
226
+ return typeof value === 'boolean';
227
+ default:
228
+ return false;
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 获取值的 JSON 类型名称
234
+ * @param {*} value 待判定值
235
+ * @returns {string} 类型名称
236
+ */
237
+ _getTypeName(value) {
238
+ if (value === null) return 'null';
239
+ if (Array.isArray(value)) return 'array';
240
+ return typeof value;
241
+ }
242
+
243
+ /**
244
+ * 判断值是否为有限数字(排除 NaN / Infinity)
245
+ * @param {*} value 待判定值
246
+ * @returns {boolean} 是否为有限数字
247
+ */
248
+ _isFiniteNumber(value) {
249
+ return typeof value === 'number' && Number.isFinite(value);
250
+ }
251
+
252
+ /**
253
+ * 判断值是否为普通对象(排除 null 与数组)
254
+ * @param {*} value 待判定值
255
+ * @returns {boolean} 是否为普通对象
256
+ */
257
+ _isObject(value) {
258
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
259
+ }
260
+
261
+ // ---------- 路径与属性 ----------
262
+ /**
263
+ * 判断对象自身是否包含指定字段
264
+ * @param {Object} target 目标对象
265
+ * @param {string} key 字段名
266
+ * @returns {boolean} 是否包含该字段
267
+ */
268
+ _isOwnProperty(target, key) {
269
+ return Object.prototype.hasOwnProperty.call(target, key);
270
+ }
271
+
272
+ /**
273
+ * 拼接对象字段路径
274
+ * @param {string} path 父级路径
275
+ * @param {string} key 字段名
276
+ * @returns {string} 字段路径
277
+ */
278
+ _getKeyPath(path, key) {
279
+ return path ? `${path}.${key}` : key;
280
+ }
281
+
282
+ /**
283
+ * 拼接数组元素路径
284
+ * @param {string} path 父级路径
285
+ * @param {number} index 元素下标
286
+ * @returns {string} 元素路径
287
+ */
288
+ _getArrayPath(path, index) {
289
+ return `${path}[${index}]`;
290
+ }
291
+
292
+ /**
293
+ * 为错误详情附加路径前缀
294
+ * @param {string} path 字段路径
295
+ * @param {string} detail 错误详情
296
+ * @returns {string} 完整错误信息
297
+ */
298
+ _getPathMessage(path, detail) {
299
+ return path ? `${path}: ${detail}` : detail;
300
+ }
301
+ }
302
+
303
+ module.exports = Validate;
package/package.json CHANGED
@@ -1,6 +1,53 @@
1
1
  {
2
2
  "name": "mm_validate",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0",
4
+ "description": "这是一个通用的 Node.js 参数验证模块,按 JSON Schema 常用子集校验参数,返回首个错误信息。",
5
+ "keywords": [
6
+ "mm_mod",
7
+ "mm_infra",
8
+ "mm_common",
9
+ "超级美眉",
10
+ "参数验证",
11
+ "数据校验",
12
+ "json schema",
13
+ "validate",
14
+ "validator",
15
+ "schema",
16
+ "nodejs",
17
+ "commonjs"
18
+ ],
19
+ "layer": "infra",
20
+ "group": "common",
21
+ "author": "邱文武",
22
+ "license": "ISC",
23
+ "type": "commonjs",
24
+ "engines": {
25
+ "node": ">=16"
26
+ },
27
+ "main": "index.js",
28
+ "files": [
29
+ "index.js",
30
+ "lib",
31
+ "example"
32
+ ],
33
+ "directories": {
34
+ "example": "example",
35
+ "lib": "lib"
36
+ },
37
+ "homepage": "https://gitee.com/qiuwenwu91/mm_validate#readme",
38
+ "bugs": {
39
+ "url": "https://gitee.com/qiuwenwu91/mm_validate/issues"
40
+ },
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "git+https://gitee.com/qiuwenwu91/mm_validate.git"
44
+ },
45
+ "scripts": {
46
+ "test": "jest --coverage",
47
+ "demo": "node example/index.js",
48
+ "prepublishOnly": "npm test"
49
+ },
50
+ "devDependencies": {
51
+ "jest": "^30.5.2"
52
+ }
53
+ }