@quanxiaoxiao/datav 0.4.0 → 0.5.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.
- package/README.md +680 -165
- package/dist/createArrayAccessor.d.ts +2 -0
- package/dist/createArrayAccessor.d.ts.map +1 -0
- package/dist/createArrayAccessor.js +38 -0
- package/dist/createArrayAccessor.js.map +1 -0
- package/dist/createDataAccessor.d.ts +2 -0
- package/dist/createDataAccessor.d.ts.map +1 -0
- package/dist/createDataAccessor.js +23 -0
- package/dist/createDataAccessor.js.map +1 -0
- package/dist/createDataTransformer.d.ts +14 -0
- package/dist/createDataTransformer.d.ts.map +1 -0
- package/dist/createDataTransformer.js +124 -0
- package/dist/createDataTransformer.js.map +1 -0
- package/dist/createPathAccessor.d.ts +2 -0
- package/dist/createPathAccessor.d.ts.map +1 -0
- package/dist/createPathAccessor.js +38 -0
- package/dist/createPathAccessor.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/parseDotPath.d.ts +2 -0
- package/dist/parseDotPath.d.ts.map +1 -0
- package/dist/parseDotPath.js +14 -0
- package/dist/parseDotPath.js.map +1 -0
- package/dist/parseValueByType.d.ts +11 -0
- package/dist/parseValueByType.d.ts.map +1 -0
- package/dist/parseValueByType.js +122 -0
- package/dist/parseValueByType.js.map +1 -0
- package/dist/utils.d.ts +3 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +22 -0
- package/dist/utils.js.map +1 -0
- package/dist/validateExpressSchema.d.ts +7 -0
- package/dist/validateExpressSchema.d.ts.map +1 -0
- package/dist/validateExpressSchema.js +50 -0
- package/dist/validateExpressSchema.js.map +1 -0
- package/package.json +46 -8
- package/src/createArrayAccessor.test.ts +181 -0
- package/src/createArrayAccessor.ts +48 -0
- package/src/createDataAccessor.test.ts +220 -0
- package/src/createDataAccessor.ts +26 -0
- package/src/createDataTransformer.test.ts +847 -0
- package/src/createDataTransformer.ts +173 -0
- package/src/createPathAccessor.test.ts +217 -0
- package/src/createPathAccessor.ts +45 -0
- package/src/index.ts +11 -0
- package/src/parseDotPath.test.ts +132 -0
- package/src/parseDotPath.ts +13 -0
- package/src/parseValueByType.test.ts +342 -0
- package/src/parseValueByType.ts +165 -0
- package/src/utils.test.ts +85 -0
- package/src/utils.ts +22 -0
- package/src/validateExpressSchema.test.ts +295 -0
- package/src/validateExpressSchema.ts +59 -0
- package/.editorconfig +0 -13
- package/eslint.config.mjs +0 -89
- package/src/checkout.mjs +0 -131
- package/src/checkout.test.mjs +0 -144
- package/src/index.mjs +0 -7
- package/src/select/check.mjs +0 -63
- package/src/select/check.test.mjs +0 -76
- package/src/select/index.mjs +0 -117
- package/src/select/index.test.mjs +0 -1145
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
import { describe, test } from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { validateExpressSchema } from './validateExpressSchema.js';
|
|
5
|
+
|
|
6
|
+
// 用于测试无效类型输入
|
|
7
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
8
|
+
type AnySchema = any;
|
|
9
|
+
|
|
10
|
+
describe('validateExpressSchema', () => {
|
|
11
|
+
describe('基础类型验证', () => {
|
|
12
|
+
const basicTypes = ['string', 'number', 'boolean', 'integer'] as const;
|
|
13
|
+
|
|
14
|
+
basicTypes.forEach(type => {
|
|
15
|
+
test(`应该通过 ${type} 类型验证`, () => {
|
|
16
|
+
assert.doesNotThrow(() => {
|
|
17
|
+
validateExpressSchema({ type });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test('基础类型可以包含可选的 properties', () => {
|
|
23
|
+
assert.doesNotThrow(() => {
|
|
24
|
+
validateExpressSchema({
|
|
25
|
+
type: 'string',
|
|
26
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
27
|
+
properties: ['dataKey'] as any,
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('对象类型验证', () => {
|
|
34
|
+
test('应该通过有效的 object 类型验证', () => {
|
|
35
|
+
assert.doesNotThrow(() => {
|
|
36
|
+
validateExpressSchema({
|
|
37
|
+
type: 'object',
|
|
38
|
+
properties: {
|
|
39
|
+
name: { type: 'string' },
|
|
40
|
+
age: { type: 'number' },
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('应该通过空 properties 的 object 类型验证', () => {
|
|
47
|
+
assert.doesNotThrow(() => {
|
|
48
|
+
validateExpressSchema({
|
|
49
|
+
type: 'object',
|
|
50
|
+
properties: {},
|
|
51
|
+
});
|
|
52
|
+
});
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
test('object 类型缺少 properties 应该抛出错误', () => {
|
|
56
|
+
assert.throws(
|
|
57
|
+
() => validateExpressSchema({ type: 'object' } as AnySchema),
|
|
58
|
+
/Invalid schema/,
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test('object 类型的 properties 必须是对象', () => {
|
|
63
|
+
assert.throws(
|
|
64
|
+
() => validateExpressSchema({
|
|
65
|
+
type: 'object',
|
|
66
|
+
properties: 'invalid',
|
|
67
|
+
} as AnySchema),
|
|
68
|
+
/Invalid schema/,
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
test('object 类型的 properties 不能是数组', () => {
|
|
73
|
+
assert.throws(
|
|
74
|
+
() => validateExpressSchema({
|
|
75
|
+
type: 'object',
|
|
76
|
+
properties: [],
|
|
77
|
+
} as AnySchema),
|
|
78
|
+
/Invalid schema/,
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('数组类型验证', () => {
|
|
84
|
+
test('应该通过 properties 为对象的 array 类型验证', () => {
|
|
85
|
+
assert.doesNotThrow(() => {
|
|
86
|
+
validateExpressSchema({
|
|
87
|
+
type: 'array',
|
|
88
|
+
properties: {
|
|
89
|
+
items: { type: 'string' },
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test('应该通过 properties 为元组的 array 类型验证', () => {
|
|
96
|
+
assert.doesNotThrow(() => {
|
|
97
|
+
validateExpressSchema({
|
|
98
|
+
type: 'array',
|
|
99
|
+
properties: ['items', { type: 'string' }],
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
test('应该通过空 properties 对象的 array 类型验证', () => {
|
|
105
|
+
assert.doesNotThrow(() => {
|
|
106
|
+
validateExpressSchema({
|
|
107
|
+
type: 'array',
|
|
108
|
+
properties: {},
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test('array 类型缺少 properties 应该抛出错误', () => {
|
|
114
|
+
assert.throws(
|
|
115
|
+
() => validateExpressSchema({ type: 'array' } as AnySchema),
|
|
116
|
+
/Invalid schema/,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
describe('元组 properties 验证', () => {
|
|
121
|
+
test('元组长度必须为 2', () => {
|
|
122
|
+
assert.throws(
|
|
123
|
+
() => validateExpressSchema({
|
|
124
|
+
type: 'array',
|
|
125
|
+
properties: ['items'],
|
|
126
|
+
} as AnySchema),
|
|
127
|
+
/Invalid schema/,
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
assert.throws(
|
|
131
|
+
() => validateExpressSchema({
|
|
132
|
+
type: 'array',
|
|
133
|
+
properties: ['items', { type: 'string' }, 'extra'],
|
|
134
|
+
} as AnySchema),
|
|
135
|
+
/Invalid schema/,
|
|
136
|
+
);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
test('元组第一项必须是 string', () => {
|
|
140
|
+
assert.throws(
|
|
141
|
+
() => validateExpressSchema({
|
|
142
|
+
type: 'array',
|
|
143
|
+
properties: [123, { type: 'string' }],
|
|
144
|
+
} as AnySchema),
|
|
145
|
+
/Invalid schema/,
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
test('元组第二项必须是 object', () => {
|
|
150
|
+
assert.throws(
|
|
151
|
+
() => validateExpressSchema({
|
|
152
|
+
type: 'array',
|
|
153
|
+
properties: ['items', 'invalid'],
|
|
154
|
+
} as AnySchema),
|
|
155
|
+
/Invalid schema/,
|
|
156
|
+
);
|
|
157
|
+
|
|
158
|
+
assert.throws(
|
|
159
|
+
() => validateExpressSchema({
|
|
160
|
+
type: 'array',
|
|
161
|
+
properties: ['items', []],
|
|
162
|
+
} as AnySchema),
|
|
163
|
+
/Invalid schema/,
|
|
164
|
+
);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
describe('无效输入验证', () => {
|
|
170
|
+
const invalidInputs = [
|
|
171
|
+
{ input: [], description: '空数组' },
|
|
172
|
+
{ input: 'number', description: '字符串' },
|
|
173
|
+
{ input: 'integer', description: '字符串 integer' },
|
|
174
|
+
{ input: {}, description: '空对象' },
|
|
175
|
+
{ input: { type: 'xxx' }, description: '无效的 type' },
|
|
176
|
+
{ input: { type: 'json' }, description: '不支持的 type: json' },
|
|
177
|
+
{ input: { type: null }, description: 'type 为 null' },
|
|
178
|
+
{ input: { type: undefined }, description: 'type 为 undefined' },
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
invalidInputs.forEach(({ input, description }) => {
|
|
182
|
+
test(`${description}应该抛出错误`, () => {
|
|
183
|
+
assert.throws(
|
|
184
|
+
() => validateExpressSchema(input as AnySchema),
|
|
185
|
+
/Invalid schema/,
|
|
186
|
+
);
|
|
187
|
+
});
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
describe('可选的 resolve 函数', () => {
|
|
192
|
+
const typesWithResolve = [
|
|
193
|
+
{ type: 'string', properties: undefined },
|
|
194
|
+
{ type: 'object', properties: { name: { type: 'string' } } },
|
|
195
|
+
{ type: 'array', properties: ['items', { type: 'number' }] },
|
|
196
|
+
];
|
|
197
|
+
|
|
198
|
+
typesWithResolve.forEach(schema => {
|
|
199
|
+
test(`${schema.type} 类型应该允许包含 resolve 函数`, () => {
|
|
200
|
+
assert.doesNotThrow(() => {
|
|
201
|
+
validateExpressSchema({
|
|
202
|
+
...schema,
|
|
203
|
+
resolve: (value: unknown) => value,
|
|
204
|
+
} as AnySchema);
|
|
205
|
+
});
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
describe('复杂嵌套场景', () => {
|
|
211
|
+
test('应该通过嵌套对象验证', () => {
|
|
212
|
+
assert.doesNotThrow(() => {
|
|
213
|
+
validateExpressSchema({
|
|
214
|
+
type: 'object',
|
|
215
|
+
properties: {
|
|
216
|
+
user: {
|
|
217
|
+
type: 'object',
|
|
218
|
+
properties: {
|
|
219
|
+
name: { type: 'string' },
|
|
220
|
+
age: { type: 'number' },
|
|
221
|
+
address: {
|
|
222
|
+
type: 'object',
|
|
223
|
+
properties: {
|
|
224
|
+
city: { type: 'string' },
|
|
225
|
+
zipCode: { type: 'integer' },
|
|
226
|
+
},
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
test('应该通过嵌套数组验证', () => {
|
|
236
|
+
assert.doesNotThrow(() => {
|
|
237
|
+
validateExpressSchema({
|
|
238
|
+
type: 'array',
|
|
239
|
+
properties: {
|
|
240
|
+
items: {
|
|
241
|
+
type: 'array',
|
|
242
|
+
properties: ['item', { type: 'string' }],
|
|
243
|
+
},
|
|
244
|
+
},
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test('应该通过混合嵌套验证', () => {
|
|
250
|
+
assert.doesNotThrow(() => {
|
|
251
|
+
validateExpressSchema({
|
|
252
|
+
type: 'object',
|
|
253
|
+
properties: {
|
|
254
|
+
users: {
|
|
255
|
+
type: 'array',
|
|
256
|
+
properties: {
|
|
257
|
+
user: {
|
|
258
|
+
type: 'object',
|
|
259
|
+
properties: {
|
|
260
|
+
name: { type: 'string' },
|
|
261
|
+
tags: {
|
|
262
|
+
type: 'array',
|
|
263
|
+
properties: ['tag', { type: 'string' }],
|
|
264
|
+
},
|
|
265
|
+
},
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
},
|
|
269
|
+
},
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
describe('错误消息验证', () => {
|
|
276
|
+
test('错误消息应该包含无效的 schema 信息', () => {
|
|
277
|
+
try {
|
|
278
|
+
validateExpressSchema({ type: 'invalid' } as AnySchema);
|
|
279
|
+
assert.fail('应该抛出错误');
|
|
280
|
+
} catch (error: unknown) {
|
|
281
|
+
assert.match((error as Error).message, /Invalid schema/);
|
|
282
|
+
assert.match((error as Error).message, /invalid/);
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test('错误消息应该包含验证错误详情', () => {
|
|
287
|
+
try {
|
|
288
|
+
validateExpressSchema({ type: 'object' } as AnySchema);
|
|
289
|
+
assert.fail('应该抛出错误');
|
|
290
|
+
} catch (error: unknown) {
|
|
291
|
+
assert.match((error as Error).message, /Validation errors/);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Ajv } from 'ajv';
|
|
2
|
+
|
|
3
|
+
export interface ExpressSchema {
|
|
4
|
+
type: 'string' | 'number' | 'boolean' | 'integer' | 'object' | 'array';
|
|
5
|
+
properties?: Record<string, unknown> | [string, object];
|
|
6
|
+
resolve?: (value: unknown, root: unknown) => unknown;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const ajv = new Ajv();
|
|
10
|
+
|
|
11
|
+
const schemaValidationRules = {
|
|
12
|
+
type: 'object',
|
|
13
|
+
anyOf: [
|
|
14
|
+
{
|
|
15
|
+
properties: {
|
|
16
|
+
type: { enum: ['object'] },
|
|
17
|
+
properties: { type: 'object' },
|
|
18
|
+
},
|
|
19
|
+
required: ['type', 'properties'],
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
properties: {
|
|
23
|
+
type: { enum: ['array'] },
|
|
24
|
+
properties: {
|
|
25
|
+
anyOf: [
|
|
26
|
+
{ type: 'object' },
|
|
27
|
+
{
|
|
28
|
+
type: 'array',
|
|
29
|
+
items: [
|
|
30
|
+
{ type: 'string' },
|
|
31
|
+
{ type: 'object' },
|
|
32
|
+
],
|
|
33
|
+
additionalItems: false,
|
|
34
|
+
minItems: 2,
|
|
35
|
+
maxItems: 2,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
required: ['type', 'properties'],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
properties: {
|
|
44
|
+
type: { enum: ['string', 'number', 'boolean', 'integer'] },
|
|
45
|
+
},
|
|
46
|
+
required: ['type'],
|
|
47
|
+
},
|
|
48
|
+
],
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
const validateSchema = ajv.compile(schemaValidationRules);
|
|
52
|
+
|
|
53
|
+
export function validateExpressSchema(schema: ExpressSchema): void {
|
|
54
|
+
if (!validateSchema(schema)) {
|
|
55
|
+
const schemaStr = JSON.stringify(schema);
|
|
56
|
+
const errorsStr = JSON.stringify(validateSchema.errors);
|
|
57
|
+
throw new Error(`Invalid schema: ${schemaStr}. Validation errors: ${errorsStr}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
package/.editorconfig
DELETED
package/eslint.config.mjs
DELETED
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import js from '@eslint/js';
|
|
2
|
-
import simpleImportSort from 'eslint-plugin-simple-import-sort';
|
|
3
|
-
import globals from 'globals';
|
|
4
|
-
|
|
5
|
-
export default [
|
|
6
|
-
{
|
|
7
|
-
ignores: [
|
|
8
|
-
'node_modules/*',
|
|
9
|
-
],
|
|
10
|
-
},
|
|
11
|
-
js.configs.recommended,
|
|
12
|
-
{
|
|
13
|
-
plugins: {
|
|
14
|
-
'simple-import-sort': simpleImportSort,
|
|
15
|
-
},
|
|
16
|
-
files: [
|
|
17
|
-
'src/**/*.mjs',
|
|
18
|
-
'_index.mjs',
|
|
19
|
-
'scripts/**/*.mjs',
|
|
20
|
-
'eslint.config.mjs',
|
|
21
|
-
],
|
|
22
|
-
languageOptions: {
|
|
23
|
-
ecmaVersion: 2022,
|
|
24
|
-
sourceType: 'module',
|
|
25
|
-
globals: {
|
|
26
|
-
...globals.node,
|
|
27
|
-
},
|
|
28
|
-
},
|
|
29
|
-
rules: {
|
|
30
|
-
'simple-import-sort/imports': 'error',
|
|
31
|
-
'simple-import-sort/exports': 'error',
|
|
32
|
-
'no-duplicate-imports': 2,
|
|
33
|
-
'array-callback-return': 2,
|
|
34
|
-
'prefer-const': 2,
|
|
35
|
-
'no-multi-spaces': 2,
|
|
36
|
-
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
|
37
|
-
'block-scoped-var': 2,
|
|
38
|
-
'consistent-return': 2,
|
|
39
|
-
'default-case': 2,
|
|
40
|
-
'no-shadow': 2,
|
|
41
|
-
'object-shorthand': 2,
|
|
42
|
-
'quote-props': ['error', 'as-needed'],
|
|
43
|
-
quotes: [
|
|
44
|
-
'error',
|
|
45
|
-
'single',
|
|
46
|
-
],
|
|
47
|
-
'object-curly-newline': 2,
|
|
48
|
-
'no-multi-assign': 2,
|
|
49
|
-
'no-else-return': 2,
|
|
50
|
-
indent: [
|
|
51
|
-
'error',
|
|
52
|
-
2,
|
|
53
|
-
],
|
|
54
|
-
'keyword-spacing': 2,
|
|
55
|
-
'no-multiple-empty-lines': ['error', { max: 1, maxEOF: 0 }],
|
|
56
|
-
'space-infix-ops': 2,
|
|
57
|
-
'eol-last': 2,
|
|
58
|
-
'space-in-parens': 2,
|
|
59
|
-
'array-bracket-spacing': 2,
|
|
60
|
-
'object-curly-spacing': ['error', 'always'],
|
|
61
|
-
'block-spacing': 2,
|
|
62
|
-
'key-spacing': 2,
|
|
63
|
-
'no-trailing-spaces': 2,
|
|
64
|
-
'comma-style': 2,
|
|
65
|
-
'no-use-before-define': 2,
|
|
66
|
-
'comma-dangle': [
|
|
67
|
-
'error',
|
|
68
|
-
{
|
|
69
|
-
arrays: 'always-multiline',
|
|
70
|
-
objects: 'always-multiline',
|
|
71
|
-
imports: 'always-multiline',
|
|
72
|
-
exports: 'always-multiline',
|
|
73
|
-
functions: 'always-multiline',
|
|
74
|
-
},
|
|
75
|
-
],
|
|
76
|
-
semi: 2,
|
|
77
|
-
'no-console': 0,
|
|
78
|
-
'max-len': 0,
|
|
79
|
-
'no-continue': 0,
|
|
80
|
-
'no-bitwise': 0,
|
|
81
|
-
'no-mixed-operators': 0,
|
|
82
|
-
'no-underscore-dangle': 0,
|
|
83
|
-
'import/prefer-default-export': 0,
|
|
84
|
-
'class-methods-use-this': 0,
|
|
85
|
-
'no-plusplus': 0,
|
|
86
|
-
'global-require': 0,
|
|
87
|
-
},
|
|
88
|
-
},
|
|
89
|
-
];
|
package/src/checkout.mjs
DELETED
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
import _ from 'lodash';
|
|
2
|
-
|
|
3
|
-
const DATA_TYPE_NUMBER = 'number';
|
|
4
|
-
const DATA_TYPE_STRING = 'string';
|
|
5
|
-
const DATA_TYPE_BOOLEAN = 'boolean';
|
|
6
|
-
const DATA_TYPE_JSON = 'json';
|
|
7
|
-
const DATA_TYPE_ARRAY = 'array';
|
|
8
|
-
const DATA_TYPE_OBJECT = 'object';
|
|
9
|
-
const DATA_TYPE_INTEGER = 'integer';
|
|
10
|
-
|
|
11
|
-
const map = {
|
|
12
|
-
[DATA_TYPE_STRING]: (v) => {
|
|
13
|
-
if (typeof v !== 'string') {
|
|
14
|
-
return v.toString ? `${v.toString()}` : JSON.stringify(v);
|
|
15
|
-
}
|
|
16
|
-
return v;
|
|
17
|
-
},
|
|
18
|
-
[DATA_TYPE_INTEGER]: (v) => {
|
|
19
|
-
if (Number.isNaN(v)) {
|
|
20
|
-
return v;
|
|
21
|
-
}
|
|
22
|
-
if (v === '') {
|
|
23
|
-
return null;
|
|
24
|
-
}
|
|
25
|
-
const type = typeof v;
|
|
26
|
-
if (type !== 'number' && type !== 'string') {
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
29
|
-
const number = Number(v);
|
|
30
|
-
if (Number.isNaN(number)) {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
if (`${number}` !== `${v}`) {
|
|
34
|
-
return null;
|
|
35
|
-
}
|
|
36
|
-
return parseInt(number, 10);
|
|
37
|
-
},
|
|
38
|
-
[DATA_TYPE_NUMBER]: (v) => {
|
|
39
|
-
if (v === '') {
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
const number = Number(v);
|
|
43
|
-
if (Number.isNaN(number)) {
|
|
44
|
-
return null;
|
|
45
|
-
}
|
|
46
|
-
if (`${number}` !== `${v}`) {
|
|
47
|
-
return null;
|
|
48
|
-
}
|
|
49
|
-
return number;
|
|
50
|
-
},
|
|
51
|
-
[DATA_TYPE_BOOLEAN]: (v) => {
|
|
52
|
-
if (v !== 'false' && v !== 'true') {
|
|
53
|
-
return null;
|
|
54
|
-
}
|
|
55
|
-
return v === 'true';
|
|
56
|
-
},
|
|
57
|
-
[DATA_TYPE_JSON]: (v) => {
|
|
58
|
-
try {
|
|
59
|
-
return JSON.parse(v);
|
|
60
|
-
} catch (error) { // eslint-disable-line
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
[DATA_TYPE_OBJECT]: (v) => {
|
|
65
|
-
try {
|
|
66
|
-
const d = JSON.parse(v);
|
|
67
|
-
if (Array.isArray(d)) {
|
|
68
|
-
return null;
|
|
69
|
-
}
|
|
70
|
-
if (typeof d !== 'object') {
|
|
71
|
-
return null;
|
|
72
|
-
}
|
|
73
|
-
return d;
|
|
74
|
-
} catch (error) { // eslint-disable-line
|
|
75
|
-
return null;
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
[DATA_TYPE_ARRAY]: (v) => {
|
|
79
|
-
try {
|
|
80
|
-
const d = JSON.parse(v);
|
|
81
|
-
if (Array.isArray(d)) {
|
|
82
|
-
return d;
|
|
83
|
-
}
|
|
84
|
-
return [];
|
|
85
|
-
} catch (error) { // eslint-disable-line
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
},
|
|
89
|
-
};
|
|
90
|
-
|
|
91
|
-
const typeNameMap = {
|
|
92
|
-
[DATA_TYPE_NUMBER]: 'number',
|
|
93
|
-
[DATA_TYPE_STRING]: 'string',
|
|
94
|
-
[DATA_TYPE_INTEGER]: 'integer',
|
|
95
|
-
[DATA_TYPE_BOOLEAN]: 'boolean',
|
|
96
|
-
[DATA_TYPE_JSON]: 'object',
|
|
97
|
-
[DATA_TYPE_ARRAY]: 'object',
|
|
98
|
-
[DATA_TYPE_OBJECT]: 'object',
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
export default (value, type) => {
|
|
102
|
-
if (type == null) {
|
|
103
|
-
throw new Error('data type is empty');
|
|
104
|
-
}
|
|
105
|
-
if (!Object.hasOwnProperty.call(map, type)) {
|
|
106
|
-
throw new Error(`\`${type}\` invalid data type`);
|
|
107
|
-
}
|
|
108
|
-
if (value == null) {
|
|
109
|
-
return type === DATA_TYPE_ARRAY ? [] : null;
|
|
110
|
-
}
|
|
111
|
-
const valueType = typeof value;
|
|
112
|
-
if (valueType !== 'string') {
|
|
113
|
-
if (type === DATA_TYPE_INTEGER) {
|
|
114
|
-
return map[DATA_TYPE_INTEGER](value);
|
|
115
|
-
}
|
|
116
|
-
if (type === DATA_TYPE_STRING) {
|
|
117
|
-
return map[DATA_TYPE_STRING](value);
|
|
118
|
-
}
|
|
119
|
-
if (valueType === typeNameMap[type]) {
|
|
120
|
-
if (type === DATA_TYPE_ARRAY) {
|
|
121
|
-
return Array.isArray(value) ? value : [];
|
|
122
|
-
}
|
|
123
|
-
if (type === DATA_TYPE_OBJECT) {
|
|
124
|
-
return _.isPlainObject(value) ? value : null;
|
|
125
|
-
}
|
|
126
|
-
return value;
|
|
127
|
-
}
|
|
128
|
-
return type === DATA_TYPE_ARRAY ? [] : null;
|
|
129
|
-
}
|
|
130
|
-
return map[type](value);
|
|
131
|
-
};
|