yapi-apifox-to-typescript 4.2.2 → 5.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/lib/cjs/ApifoxToYApiData.js +312 -576
- package/lib/cjs/Generator.js +513 -1171
- package/lib/cjs/SwaggerToYApiServer.js +125 -336
- package/lib/cjs/_virtual/_rolldown/runtime.js +23 -0
- package/lib/cjs/cli.js +171 -280
- package/lib/cjs/helpers.js +125 -209
- package/lib/cjs/index.js +15 -19
- package/lib/cjs/mini-ut.js +220 -0
- package/lib/cjs/swaggerJsonToYApiData.js +268 -482
- package/lib/cjs/types.js +93 -93
- package/lib/cjs/utils.js +364 -769
- package/lib/esm/ApifoxToYApiData.d.ts +49 -0
- package/lib/esm/ApifoxToYApiData.js +310 -560
- package/lib/esm/Generator.d.ts +53 -0
- package/lib/esm/Generator.js +509 -1146
- package/lib/esm/SwaggerToYApiServer.d.ts +23 -0
- package/lib/esm/SwaggerToYApiServer.js +119 -317
- package/lib/esm/_virtual/_rolldown/runtime.js +7 -0
- package/lib/esm/cli.d.ts +4 -0
- package/lib/esm/cli.js +162 -251
- package/lib/esm/helpers.d.ts +49 -0
- package/lib/esm/helpers.js +125 -198
- package/lib/esm/index.d.ts +2 -897
- package/lib/esm/index.js +3 -2
- package/lib/esm/mini-ut.d.ts +105 -0
- package/lib/esm/mini-ut.js +198 -0
- package/lib/esm/swaggerJsonToYApiData.d.ts +6 -0
- package/lib/esm/swaggerJsonToYApiData.js +265 -469
- package/lib/esm/types.d.ts +695 -0
- package/lib/esm/types.js +87 -73
- package/lib/esm/utils.d.ts +95 -0
- package/lib/esm/utils.js +350 -720
- package/package.json +49 -59
package/lib/cjs/helpers.js
CHANGED
|
@@ -1,218 +1,134 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
|
|
4
|
-
|
|
5
|
-
exports.__esModule = true;
|
|
6
|
-
exports.FileData = void 0;
|
|
7
|
-
exports.defineConfig = defineConfig;
|
|
8
|
-
exports.parseRequestData = parseRequestData;
|
|
9
|
-
exports.prepare = prepare;
|
|
10
|
-
|
|
11
|
-
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
|
|
12
|
-
|
|
13
|
-
var _types = require("./types");
|
|
14
|
-
|
|
1
|
+
const require_types = require("./types.js");
|
|
2
|
+
//#region src/helpers.ts
|
|
15
3
|
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
4
|
+
* 定义配置。
|
|
5
|
+
*
|
|
6
|
+
* @param config 配置
|
|
7
|
+
*/
|
|
20
8
|
function defineConfig(config, hooks) {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
return config;
|
|
9
|
+
if (hooks) Object.defineProperty(config, "hooks", {
|
|
10
|
+
value: hooks,
|
|
11
|
+
configurable: false,
|
|
12
|
+
enumerable: false,
|
|
13
|
+
writable: false
|
|
14
|
+
});
|
|
15
|
+
return config;
|
|
31
16
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
var _proto = FileData.prototype;
|
|
62
|
-
|
|
63
|
-
_proto.getOriginalFileData = function getOriginalFileData() {
|
|
64
|
-
return this.originalFileData;
|
|
65
|
-
}
|
|
66
|
-
/**
|
|
67
|
-
* 获取选项。
|
|
68
|
-
*/
|
|
69
|
-
;
|
|
70
|
-
|
|
71
|
-
_proto.getOptions = function getOptions() {
|
|
72
|
-
return this.options;
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
return FileData;
|
|
76
|
-
}();
|
|
17
|
+
var FileData = class {
|
|
18
|
+
/**
|
|
19
|
+
* 文件数据辅助类,统一网页、小程序等平台的文件上传。
|
|
20
|
+
*
|
|
21
|
+
* @param originalFileData 原始文件数据
|
|
22
|
+
* @param options 若使用内部的 getFormData,则选项会被其使用
|
|
23
|
+
*/
|
|
24
|
+
constructor(originalFileData, options) {
|
|
25
|
+
this.originalFileData = originalFileData;
|
|
26
|
+
this.options = options;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* 获取原始文件数据。
|
|
30
|
+
*
|
|
31
|
+
* @returns 原始文件数据
|
|
32
|
+
*/
|
|
33
|
+
getOriginalFileData() {
|
|
34
|
+
return this.originalFileData;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* 获取选项。
|
|
38
|
+
*/
|
|
39
|
+
getOptions() {
|
|
40
|
+
return this.options;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
77
43
|
/**
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
exports.FileData = FileData;
|
|
86
|
-
|
|
44
|
+
* 解析请求数据,从请求数据中分离出普通数据和文件数据。
|
|
45
|
+
*
|
|
46
|
+
* @param requestData 要解析的请求数据
|
|
47
|
+
* @returns 包含普通数据(data)和文件数据(fileData)的对象,data、fileData 为空对象时,表示没有此类数据
|
|
48
|
+
*/
|
|
87
49
|
function parseRequestData(requestData) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
}
|
|
102
|
-
});
|
|
103
|
-
} else {
|
|
104
|
-
result.data = requestData;
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return result;
|
|
50
|
+
const result = {
|
|
51
|
+
data: {},
|
|
52
|
+
fileData: {}
|
|
53
|
+
};
|
|
54
|
+
/* istanbul ignore else */
|
|
55
|
+
if (requestData != null) {
|
|
56
|
+
if (typeof requestData === "object" && !Array.isArray(requestData)) Object.keys(requestData).forEach((key) => {
|
|
57
|
+
if (requestData[key] && requestData[key] instanceof FileData) result.fileData[key] = requestData[key].getOriginalFileData();
|
|
58
|
+
else result.data[key] = requestData[key];
|
|
59
|
+
});
|
|
60
|
+
else result.data = requestData;
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
109
63
|
}
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
} else if (arrayFormat === _types.QueryStringArrayFormat.repeat) {
|
|
122
|
-
str = value.map(function (v) {
|
|
123
|
-
return encodeURIComponent(key) + "=" + encodeURIComponent(v);
|
|
124
|
-
}).join('&');
|
|
125
|
-
} else if (arrayFormat === _types.QueryStringArrayFormat.comma) {
|
|
126
|
-
str = encodeURIComponent(key) + "=" + encodeURIComponent(value.join(','));
|
|
127
|
-
} else if (arrayFormat === _types.QueryStringArrayFormat.json) {
|
|
128
|
-
str = encodeURIComponent(key) + "=" + encodeURIComponent(JSON.stringify(value));
|
|
129
|
-
} else {
|
|
130
|
-
str = value.map(function (v) {
|
|
131
|
-
return encodeURIComponent(key + "[]") + "=" + encodeURIComponent(v);
|
|
132
|
-
}).join('&');
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
return str;
|
|
64
|
+
var queryStringify = (key, value, arrayFormat) => {
|
|
65
|
+
let str = "";
|
|
66
|
+
if (value != null) {
|
|
67
|
+
if (!Array.isArray(value)) str = `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
|
|
68
|
+
else if (arrayFormat === require_types.QueryStringArrayFormat.indices) str = value.map((v, i) => `${encodeURIComponent(`${key}[${i}]`)}=${encodeURIComponent(v)}`).join("&");
|
|
69
|
+
else if (arrayFormat === require_types.QueryStringArrayFormat.repeat) str = value.map((v) => `${encodeURIComponent(key)}=${encodeURIComponent(v)}`).join("&");
|
|
70
|
+
else if (arrayFormat === require_types.QueryStringArrayFormat.comma) str = `${encodeURIComponent(key)}=${encodeURIComponent(value.join(","))}`;
|
|
71
|
+
else if (arrayFormat === require_types.QueryStringArrayFormat.json) str = `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value))}`;
|
|
72
|
+
else str = value.map((v) => `${encodeURIComponent(`${key}[]`)}=${encodeURIComponent(v)}`).join("&");
|
|
73
|
+
}
|
|
74
|
+
return str;
|
|
137
75
|
};
|
|
138
76
|
/**
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
77
|
+
* 准备要传给请求函数的参数。
|
|
78
|
+
*/
|
|
143
79
|
function prepare(requestConfig, requestData) {
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
Object.keys(fileData).forEach(function (key) {
|
|
200
|
-
var options = requestData[key].getOptions();
|
|
201
|
-
var files = Array.isArray(fileData[key]) ? fileData[key] : [fileData[key]];
|
|
202
|
-
files.forEach(function (file) {
|
|
203
|
-
formData.append(key, file, useNativeFormData ? options == null ? void 0 : options.filename : options);
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
return formData;
|
|
207
|
-
};
|
|
208
|
-
|
|
209
|
-
return (0, _extends2.default)({}, requestConfig, {
|
|
210
|
-
path: requestPath,
|
|
211
|
-
rawData: requestData,
|
|
212
|
-
data: data,
|
|
213
|
-
hasFileData: fileData && Object.keys(fileData).length > 0,
|
|
214
|
-
fileData: fileData,
|
|
215
|
-
allData: allData,
|
|
216
|
-
getFormData: getFormData
|
|
217
|
-
});
|
|
218
|
-
}
|
|
80
|
+
let requestPath = requestConfig.path;
|
|
81
|
+
const { data, fileData } = parseRequestData(requestData);
|
|
82
|
+
const dataIsObject = data != null && typeof data === "object" && !Array.isArray(data);
|
|
83
|
+
if (dataIsObject) {
|
|
84
|
+
if (requestConfig.paramNames && Array.isArray(requestConfig.paramNames) && requestConfig.paramNames.length > 0) Object.keys(data).forEach((key) => {
|
|
85
|
+
if (requestConfig.paramNames.indexOf(key) >= 0) {
|
|
86
|
+
requestPath = requestPath.replace(new RegExp(`\\{${key}\\}`, "g"), data[key]).replace(new RegExp(`/:${key}(?=/|$)`, "g"), `/${data[key]}`);
|
|
87
|
+
delete data[key];
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
let queryString = "";
|
|
91
|
+
if (requestConfig.queryNames && Array.isArray(requestConfig.queryNames) && requestConfig.queryNames.length > 0) Object.keys(data).forEach((key) => {
|
|
92
|
+
if (requestConfig.queryNames.indexOf(key) >= 0) {
|
|
93
|
+
if (data[key] != null) queryString += `${queryString ? "&" : ""}${queryStringify(key, data[key], requestConfig.queryStringArrayFormat || require_types.QueryStringArrayFormat.brackets)}`;
|
|
94
|
+
delete data[key];
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
if (queryString) requestPath += `${requestPath.indexOf("?") > -1 ? "&" : "?"}${queryString}`;
|
|
98
|
+
}
|
|
99
|
+
const allData = {
|
|
100
|
+
...dataIsObject ? data : {},
|
|
101
|
+
...fileData
|
|
102
|
+
};
|
|
103
|
+
const getFormData = () => {
|
|
104
|
+
const useNativeFormData = typeof FormData !== "undefined";
|
|
105
|
+
const UniFormData = useNativeFormData ? FormData : void 0;
|
|
106
|
+
if (!UniFormData) throw new Error("当前环境不支持 FormData");
|
|
107
|
+
const formData = new UniFormData();
|
|
108
|
+
Object.keys(data).forEach((key) => {
|
|
109
|
+
formData.append(key, data[key]);
|
|
110
|
+
});
|
|
111
|
+
Object.keys(fileData).forEach((key) => {
|
|
112
|
+
const options = requestData[key].getOptions();
|
|
113
|
+
(Array.isArray(fileData[key]) ? fileData[key] : [fileData[key]]).forEach((file) => {
|
|
114
|
+
formData.append(key, file, useNativeFormData ? options?.filename : options);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
return formData;
|
|
118
|
+
};
|
|
119
|
+
return {
|
|
120
|
+
...requestConfig,
|
|
121
|
+
path: requestPath,
|
|
122
|
+
rawData: requestData,
|
|
123
|
+
data,
|
|
124
|
+
hasFileData: fileData && Object.keys(fileData).length > 0,
|
|
125
|
+
fileData,
|
|
126
|
+
allData,
|
|
127
|
+
getFormData
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
//#endregion
|
|
131
|
+
exports.FileData = FileData;
|
|
132
|
+
exports.defineConfig = defineConfig;
|
|
133
|
+
exports.parseRequestData = parseRequestData;
|
|
134
|
+
exports.prepare = prepare;
|
package/lib/cjs/index.js
CHANGED
|
@@ -1,19 +1,15 @@
|
|
|
1
|
-
"
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (key === "default" || key === "__esModule") return;
|
|
17
|
-
if (key in exports && exports[key] === _helpers[key]) return;
|
|
18
|
-
exports[key] = _helpers[key];
|
|
19
|
-
});
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_types = require("./types.js");
|
|
3
|
+
const require_helpers = require("./helpers.js");
|
|
4
|
+
exports.FileData = require_helpers.FileData;
|
|
5
|
+
exports.Method = require_types.Method;
|
|
6
|
+
exports.QueryStringArrayFormat = require_types.QueryStringArrayFormat;
|
|
7
|
+
exports.RequestBodyType = require_types.RequestBodyType;
|
|
8
|
+
exports.RequestFormItemType = require_types.RequestFormItemType;
|
|
9
|
+
exports.RequestParamType = require_types.RequestParamType;
|
|
10
|
+
exports.RequestQueryType = require_types.RequestQueryType;
|
|
11
|
+
exports.Required = require_types.Required;
|
|
12
|
+
exports.ResponseBodyType = require_types.ResponseBodyType;
|
|
13
|
+
exports.defineConfig = require_helpers.defineConfig;
|
|
14
|
+
exports.parseRequestData = require_helpers.parseRequestData;
|
|
15
|
+
exports.prepare = require_helpers.prepare;
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
//#region src/mini-ut.ts
|
|
2
|
+
/** 是否为数组。 */
|
|
3
|
+
function isArray(value) {
|
|
4
|
+
return Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
/** 是否为函数(对齐 `lodash.isFunction`,`class` 也视为函数)。 */
|
|
7
|
+
function isFunction(value) {
|
|
8
|
+
return typeof value === "function";
|
|
9
|
+
}
|
|
10
|
+
/** 是否为对象(`lodash.isObject` 语义:非 `null` 的 `object` 或 `function`)。 */
|
|
11
|
+
function isObject(value) {
|
|
12
|
+
return value !== null && (typeof value === "object" || typeof value === "function");
|
|
13
|
+
}
|
|
14
|
+
/** 是否为纯对象(构造器为 `Object` 或原型为 `null`)。 */
|
|
15
|
+
function isPlainObject(value) {
|
|
16
|
+
if (value === null || typeof value !== "object") return false;
|
|
17
|
+
const proto = Object.getPrototypeOf(value);
|
|
18
|
+
return proto === null || proto === Object.prototype;
|
|
19
|
+
}
|
|
20
|
+
/** 是否为类 Promise 对象。 */
|
|
21
|
+
function isPromiseLike(value) {
|
|
22
|
+
return value != null && (typeof value === "object" || typeof value === "function") && typeof value.then === "function";
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 是否为空(对齐 `lodash.isEmpty`):
|
|
26
|
+
* - `null`/`undefined` -> `true`
|
|
27
|
+
* - 数组 / 字符串 -> `length === 0`
|
|
28
|
+
* - Map / Set -> `size === 0`
|
|
29
|
+
* - 纯对象 -> 没有可枚举自有键
|
|
30
|
+
* - 数字 / 布尔 / 函数 -> `true`
|
|
31
|
+
*/
|
|
32
|
+
function isEmpty(value) {
|
|
33
|
+
if (value === null || value === void 0) return true;
|
|
34
|
+
if (isArray(value) || typeof value === "string") return value.length === 0;
|
|
35
|
+
if (value instanceof Map || value instanceof Set) return value.size === 0;
|
|
36
|
+
if (typeof value === "object") return Object.keys(value).length === 0;
|
|
37
|
+
return true;
|
|
38
|
+
}
|
|
39
|
+
/** 将任意值转为数组(`lodash.castArray` 语义)。 */
|
|
40
|
+
function castArray(value) {
|
|
41
|
+
if (value === void 0) return [];
|
|
42
|
+
return isArray(value) ? value.slice() : [value];
|
|
43
|
+
}
|
|
44
|
+
/** 返回数组最后一项,非数组或空数组返回 `undefined`。 */
|
|
45
|
+
function last(list) {
|
|
46
|
+
return isArray(list) && list.length ? list[list.length - 1] : void 0;
|
|
47
|
+
}
|
|
48
|
+
/** 数组去重(保持首次出现顺序)。 */
|
|
49
|
+
function uniq(list) {
|
|
50
|
+
return list ? Array.from(new Set(list)) : [];
|
|
51
|
+
}
|
|
52
|
+
/** `Object.values` 的宽松版:非对象返回 `[]`。 */
|
|
53
|
+
function values(obj) {
|
|
54
|
+
if (obj === null || obj === void 0) return [];
|
|
55
|
+
return Object.keys(obj).map((k) => obj[k]);
|
|
56
|
+
}
|
|
57
|
+
function each(collection, iteratee) {
|
|
58
|
+
if (collection === null || collection === void 0) return;
|
|
59
|
+
if (isArray(collection)) {
|
|
60
|
+
for (let i = 0; i < collection.length; i++) if (iteratee(collection[i], i) === false) return;
|
|
61
|
+
} else if (typeof collection === "object") {
|
|
62
|
+
for (const key of Object.keys(collection)) if (iteratee(collection[key], key) === false) return;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
/** 遍历对象自有可枚举键(`lodash.forOwn` 语义)。 */
|
|
66
|
+
function forOwn(obj, iteratee) {
|
|
67
|
+
if (obj === null || obj === void 0) return;
|
|
68
|
+
for (const key of Object.keys(obj)) if (iteratee(obj[key], key) === false) return;
|
|
69
|
+
}
|
|
70
|
+
function find(collection, predicate) {
|
|
71
|
+
if (collection === null || collection === void 0) return void 0;
|
|
72
|
+
if (isArray(collection)) {
|
|
73
|
+
for (let i = 0; i < collection.length; i++) if (predicate(collection[i], i)) return collection[i];
|
|
74
|
+
} else if (typeof collection === "object") {
|
|
75
|
+
for (const key of Object.keys(collection)) if (predicate(collection[key], key)) return collection[key];
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/** 按 `iteratee` 结果分组(`lodash.groupBy` 语义)。 */
|
|
79
|
+
function groupBy(list, iteratee) {
|
|
80
|
+
const result = {};
|
|
81
|
+
if (!list) return result;
|
|
82
|
+
for (const item of list) {
|
|
83
|
+
const key = String(iteratee(item));
|
|
84
|
+
if (!Object.prototype.hasOwnProperty.call(result, key)) result[key] = [];
|
|
85
|
+
result[key].push(item);
|
|
86
|
+
}
|
|
87
|
+
return result;
|
|
88
|
+
}
|
|
89
|
+
/** 浅拷贝对象,剔除指定顶层键(`lodash.omit` 简化版,够用即可)。 */
|
|
90
|
+
function omit(obj, keys) {
|
|
91
|
+
if (obj === null || obj === void 0) return obj;
|
|
92
|
+
const result = {};
|
|
93
|
+
const drop = new Set(keys);
|
|
94
|
+
for (const key of Object.keys(obj)) if (!drop.has(key)) result[key] = obj[key];
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/** 基于 `iteratee` 重映射对象的键(`lodash.mapKeys` 简化版)。 */
|
|
98
|
+
function mapKeys(obj, iteratee) {
|
|
99
|
+
const result = {};
|
|
100
|
+
if (!obj) return result;
|
|
101
|
+
for (const key of Object.keys(obj)) result[iteratee(obj[key], key)] = obj[key];
|
|
102
|
+
return result;
|
|
103
|
+
}
|
|
104
|
+
/** 空函数,常用于 `.catch(noop)` 吞掉错误。 */
|
|
105
|
+
function noop() {}
|
|
106
|
+
/**
|
|
107
|
+
* 深克隆(对齐 vtils `cloneDeepFast`:只处理普通对象 / 数组 / Date,
|
|
108
|
+
* 其它引用值按浅拷贝,性能优于 JSON 版)。
|
|
109
|
+
*/
|
|
110
|
+
function cloneDeepFast(value) {
|
|
111
|
+
if (value === null || typeof value !== "object") return value;
|
|
112
|
+
if (value instanceof Date) return new Date(value.getTime());
|
|
113
|
+
if (isArray(value)) return value.map((item) => cloneDeepFast(item));
|
|
114
|
+
const o2 = {};
|
|
115
|
+
for (const key of Object.keys(value)) o2[key] = cloneDeepFast(value[key]);
|
|
116
|
+
return o2;
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 深度遍历(对齐 vtils `traverse`:数组按 index、纯对象按 key 递归;
|
|
120
|
+
* 回调形如 `(value, key, parent)`)。
|
|
121
|
+
*/
|
|
122
|
+
function traverse(value, callback) {
|
|
123
|
+
if (isArray(value)) value.forEach((item, index) => {
|
|
124
|
+
callback(item, index, value);
|
|
125
|
+
if (value[index] !== void 0) traverse(item, callback);
|
|
126
|
+
});
|
|
127
|
+
else if (isPlainObject(value)) forOwn(value, (item, key) => {
|
|
128
|
+
callback(item, key, value);
|
|
129
|
+
if (Object.prototype.hasOwnProperty.call(value, key)) traverse(item, callback);
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* 空行 / 缩进剥离(对齐 vtils `dedent`):
|
|
134
|
+
* - 支持模板字符串标签用法:`dedent\`...\``
|
|
135
|
+
* - 支持字符串参数用法:`dedent(text)`
|
|
136
|
+
* 行为:移除首尾空行,按最短公共前导空白对齐去缩进。
|
|
137
|
+
*/
|
|
138
|
+
function dedent(input, ...values) {
|
|
139
|
+
let text;
|
|
140
|
+
if (typeof input === "string") text = input;
|
|
141
|
+
else text = input.reduce((acc, chunk, i) => acc + chunk + (i < values.length ? String(values[i]) : ""), "");
|
|
142
|
+
const lines = text.split("\n");
|
|
143
|
+
let commonLeadingWhitespace = null;
|
|
144
|
+
let firstLineIndex = null;
|
|
145
|
+
let lastLineIndex = null;
|
|
146
|
+
for (let index = 0; index < lines.length; index++) {
|
|
147
|
+
const leading = lines[index].match(/^\s*/)[0];
|
|
148
|
+
if (leading.length !== lines[index].length) {
|
|
149
|
+
lastLineIndex = index;
|
|
150
|
+
if (firstLineIndex === null) firstLineIndex = index;
|
|
151
|
+
if (commonLeadingWhitespace === null || leading.length < commonLeadingWhitespace.length) commonLeadingWhitespace = leading;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
if (commonLeadingWhitespace === null || firstLineIndex === null || lastLineIndex === null) return text;
|
|
155
|
+
return lines.slice(firstLineIndex, lastLineIndex + 1).map((line) => line.substr(commonLeadingWhitespace.length)).join("\n");
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* 缓存函数结果(对齐 `lodash.memoize` 简化版)。
|
|
159
|
+
* - 未传 `resolver` 时以第一个入参做 Map key;
|
|
160
|
+
* - 传入 `resolver` 时以 `resolver(...args)` 的结果做 Map key。
|
|
161
|
+
*/
|
|
162
|
+
function memoize(fn, resolver) {
|
|
163
|
+
const cache = /* @__PURE__ */ new Map();
|
|
164
|
+
const wrapped = function(...args) {
|
|
165
|
+
const key = resolver ? resolver.apply(this, args) : args[0];
|
|
166
|
+
if (cache.has(key)) return cache.get(key);
|
|
167
|
+
const result = fn.apply(this, args);
|
|
168
|
+
cache.set(key, result);
|
|
169
|
+
return result;
|
|
170
|
+
};
|
|
171
|
+
return wrapped;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* 以 Go 风格返回 `[err, value]`(对齐 vtils `run`)。
|
|
175
|
+
* 支持同步 / 异步函数;出错时 err 有值,value 为 `undefined`。
|
|
176
|
+
*/
|
|
177
|
+
function run(fn) {
|
|
178
|
+
return new Promise((resolve) => {
|
|
179
|
+
try {
|
|
180
|
+
const res = fn();
|
|
181
|
+
if (!isPromiseLike(res)) return resolve([null, res]);
|
|
182
|
+
Promise.resolve(res).then((value) => resolve([null, value]), (err) => resolve([err, void 0]));
|
|
183
|
+
} catch (err) {
|
|
184
|
+
resolve([err, void 0]);
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
/** 等待一段时间的 Promise,附带 `.cancel()`(对齐 vtils `wait`)。 */
|
|
189
|
+
function wait(milliseconds, value) {
|
|
190
|
+
let timer;
|
|
191
|
+
const promise = new Promise((resolve) => {
|
|
192
|
+
timer = setTimeout(() => resolve(value), milliseconds);
|
|
193
|
+
});
|
|
194
|
+
promise.cancel = () => clearTimeout(timer);
|
|
195
|
+
return promise;
|
|
196
|
+
}
|
|
197
|
+
//#endregion
|
|
198
|
+
exports.castArray = castArray;
|
|
199
|
+
exports.cloneDeepFast = cloneDeepFast;
|
|
200
|
+
exports.dedent = dedent;
|
|
201
|
+
exports.each = each;
|
|
202
|
+
exports.find = find;
|
|
203
|
+
exports.forOwn = forOwn;
|
|
204
|
+
exports.groupBy = groupBy;
|
|
205
|
+
exports.isArray = isArray;
|
|
206
|
+
exports.isEmpty = isEmpty;
|
|
207
|
+
exports.isFunction = isFunction;
|
|
208
|
+
exports.isObject = isObject;
|
|
209
|
+
exports.isPlainObject = isPlainObject;
|
|
210
|
+
exports.isPromiseLike = isPromiseLike;
|
|
211
|
+
exports.last = last;
|
|
212
|
+
exports.mapKeys = mapKeys;
|
|
213
|
+
exports.memoize = memoize;
|
|
214
|
+
exports.noop = noop;
|
|
215
|
+
exports.omit = omit;
|
|
216
|
+
exports.run = run;
|
|
217
|
+
exports.traverse = traverse;
|
|
218
|
+
exports.uniq = uniq;
|
|
219
|
+
exports.values = values;
|
|
220
|
+
exports.wait = wait;
|