@ruan-cat/utils 1.0.1 → 1.0.2
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/package.json +13 -3
- package/src/conditions.ts +6 -3
- package/src/index.ts +3 -4
- package/src/rmmv-class-expand-tools.ts +220 -0
- package/tsconfig.json +53 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ruan-cat/utils",
|
|
3
|
-
"version": "1.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "阮喵喵工具集合。一个纯typescript库。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"_main": "./src/index.ts",
|
|
7
7
|
"_types": "./src/index.ts",
|
|
@@ -28,7 +28,17 @@
|
|
|
28
28
|
"src",
|
|
29
29
|
"tsconfig.json"
|
|
30
30
|
],
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"typedoc": "^0.25.13",
|
|
33
|
+
"typedoc-plugin-markdown": "^4.0.3",
|
|
34
|
+
"typescript": "^5.5.2"
|
|
35
|
+
},
|
|
31
36
|
"scripts": {
|
|
32
|
-
"
|
|
37
|
+
"typedoc": "typedoc",
|
|
38
|
+
"clean:type": "rimraf ./dist",
|
|
39
|
+
"generate:type-1": "vue-tsc -p tsconfig.json --composite false --declaration true --emitDeclarationOnly true",
|
|
40
|
+
"generate:type-2": "tsc -p tsconfig.json --composite false --declaration true --emitDeclarationOnly true",
|
|
41
|
+
"generate:type-3": "vue-tsc -p tsconfig.types.json",
|
|
42
|
+
"get-type": "pnpm clean:type && pnpm generate:type-3"
|
|
33
43
|
}
|
|
34
44
|
}
|
package/src/conditions.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
export type
|
|
1
|
+
export type Condition = (...args: unknown[]) => boolean;
|
|
2
|
+
|
|
3
|
+
/** @deprecated 没必要 */
|
|
4
|
+
export type Conditions = Condition[];
|
|
2
5
|
|
|
3
6
|
/**
|
|
4
7
|
* 是否每一个条件函数都满足?
|
|
@@ -14,10 +17,10 @@ export type Conditions = Array<(...args: unknown[]) => boolean>;
|
|
|
14
17
|
* conditions.every((condition) => condition())
|
|
15
18
|
* ```
|
|
16
19
|
*/
|
|
17
|
-
export function isConditionsEvery(conditions:
|
|
20
|
+
export function isConditionsEvery(conditions: Condition[]) {
|
|
18
21
|
return conditions.every((condition) => condition());
|
|
19
22
|
}
|
|
20
23
|
|
|
21
|
-
export function isConditionsSome(conditions:
|
|
24
|
+
export function isConditionsSome(conditions: Condition[]) {
|
|
22
25
|
return conditions.some((condition) => condition());
|
|
23
26
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
export * from "./
|
|
4
|
-
export * from "./Prettify";
|
|
1
|
+
export * from "./rmmv-class-expand-tools.ts";
|
|
2
|
+
export * from "./conditions.ts";
|
|
3
|
+
export * from "./Prettify.ts";
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import type { OptionalKeysOf } from "type-fest";
|
|
2
|
+
import { forIn, hasIn, isFunction, uniqueId } from "lodash-es";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* rmmv特征基类
|
|
6
|
+
* @description
|
|
7
|
+
* 全部的rmmv类都具有 `initialize` 函数
|
|
8
|
+
*
|
|
9
|
+
* 此类型用于描述此
|
|
10
|
+
*/
|
|
11
|
+
export declare abstract class RmmvClass {
|
|
12
|
+
initialize: (...args: any[]) => void;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 获取对象的全部函数key名称
|
|
17
|
+
* @description
|
|
18
|
+
* 从一个类型内,获取值为函数的key名称
|
|
19
|
+
*/
|
|
20
|
+
export type FunctionKeys<T> = {
|
|
21
|
+
[K in keyof T]: T[K] extends (...args: any[]) => any ? K : never;
|
|
22
|
+
}[keyof T];
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* 属性提示工具
|
|
26
|
+
* @description
|
|
27
|
+
* 对继承的类进行属性提示
|
|
28
|
+
*
|
|
29
|
+
* 对自己新增的属性和函数做属性提示
|
|
30
|
+
*
|
|
31
|
+
* 对全部涉及到的函数,其this全部做判定
|
|
32
|
+
*/
|
|
33
|
+
export type AttributePromptTool<SourceCode extends RmmvClass, UserCode> = ThisType<SourceCode & UserCode> &
|
|
34
|
+
Partial<SourceCode> &
|
|
35
|
+
UserCode;
|
|
36
|
+
|
|
37
|
+
type UserCodeClassAttributeType = {
|
|
38
|
+
counter: number;
|
|
39
|
+
drillCalendar: string[];
|
|
40
|
+
sayFuck: () => void;
|
|
41
|
+
isUserCodeClass(): true;
|
|
42
|
+
getDrillCalendar(): string[];
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* 默认处理策略
|
|
47
|
+
* @description
|
|
48
|
+
* 先回调rmmv源码 再加上用户代码
|
|
49
|
+
*/
|
|
50
|
+
export const defaultHandleStrategy = <const>"source-first";
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 处理策略
|
|
54
|
+
* @description
|
|
55
|
+
* 用户代码相对于rmmv源码的处理策略
|
|
56
|
+
*/
|
|
57
|
+
const handleStrategy = <const>[
|
|
58
|
+
/** 用户代码覆盖掉rmmv源码 */
|
|
59
|
+
"userCode-cover-source",
|
|
60
|
+
|
|
61
|
+
defaultHandleStrategy,
|
|
62
|
+
|
|
63
|
+
/** 先执行用户代码 再回调rmmv源码 */
|
|
64
|
+
"userCode-first",
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* 处理策略
|
|
69
|
+
* @description
|
|
70
|
+
* 用户代码相对于rmmv源码的处理策略
|
|
71
|
+
*/
|
|
72
|
+
export type HandleStrategy = (typeof handleStrategy)[number];
|
|
73
|
+
|
|
74
|
+
function isSourceFirst(handleStrategy: HandleStrategy): handleStrategy is "source-first" {
|
|
75
|
+
return handleStrategy === "source-first";
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function isUserCodeCoverSource(handleStrategy: HandleStrategy): handleStrategy is "userCode-cover-source" {
|
|
79
|
+
return handleStrategy === "userCode-cover-source";
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function isUserCodeFirst(handleStrategy: HandleStrategy): handleStrategy is "userCode-first" {
|
|
83
|
+
return handleStrategy === "userCode-first";
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* 被默认执行默认处理策略的函数名
|
|
88
|
+
* @description
|
|
89
|
+
* 初始化函数默认使用固定的处理策略。
|
|
90
|
+
*/
|
|
91
|
+
export type defaultHandleStrategy_FuncationName = FunctionKeys<RmmvClass>;
|
|
92
|
+
|
|
93
|
+
/** 全部可选字段组成的对象 且该对象的全部字段必填 */
|
|
94
|
+
type AllOptionalFieldObj<T extends object> = Required<Pick<T, OptionalKeysOf<T>>>;
|
|
95
|
+
|
|
96
|
+
/** 给一个对象排除 init 字段 */
|
|
97
|
+
type NoInit<T> = Omit<T, defaultHandleStrategy_FuncationName>;
|
|
98
|
+
|
|
99
|
+
type AllOptionalFieldObj_noInit<T extends object> = NoInit<AllOptionalFieldObj<T>>;
|
|
100
|
+
|
|
101
|
+
/** 处理策略配置的 全部有意义的配置键名 */
|
|
102
|
+
type HandleStrategyConfigKeys<T extends object> = FunctionKeys<AllOptionalFieldObj_noInit<T>>;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* 全部有意义函数的 处理策略配置
|
|
106
|
+
* @description
|
|
107
|
+
* 只有可能去覆盖,拓展的函数名,才值得去配置
|
|
108
|
+
*/
|
|
109
|
+
type HandleStrategyConfig<T extends object> = Record<HandleStrategyConfigKeys<T>, HandleStrategy>;
|
|
110
|
+
|
|
111
|
+
/** rmmv类拓展工具函数配置 */
|
|
112
|
+
type RmmvClassExpandTools<SourceCode extends new (...args: any[]) => RmmvClass, UserCode extends object> = {
|
|
113
|
+
/** 源码 一般是被拓展的类,往往是rmmv的源码类 */
|
|
114
|
+
source: SourceCode;
|
|
115
|
+
|
|
116
|
+
/** 用户代码 插件开发者编写的一个内部完备的对象 */
|
|
117
|
+
userCode: UserCode;
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* 拓展配置 按照要求拓展
|
|
121
|
+
* @description
|
|
122
|
+
* 用户可以不提供配置 就默认按照标准的方式处理
|
|
123
|
+
*/
|
|
124
|
+
config?: Partial<HandleStrategyConfig<UserCode>>;
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
/** 函数别名存储对象 */
|
|
128
|
+
const functionAlias = new Map<string, Function>();
|
|
129
|
+
|
|
130
|
+
/** 生成函数别名id */
|
|
131
|
+
function generateFunctionAliasId(key: string) {
|
|
132
|
+
return uniqueId(`FunctionAliasId_${key}_`);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* rmmv类拓展工具函数
|
|
137
|
+
* @description
|
|
138
|
+
* 预期处理5种情况
|
|
139
|
+
*
|
|
140
|
+
* - 1. 用户代码覆盖掉rmmv源码
|
|
141
|
+
* - 2. 默认处理策略
|
|
142
|
+
* - 3. 先执行用户代码 再回调rmmv源码
|
|
143
|
+
* - 4. 初始化函数默认使用固定的处理策略
|
|
144
|
+
* - 5. 继承对象没有这个属性时 说明是新的函数 直接添加到原型链上
|
|
145
|
+
*/
|
|
146
|
+
export function rmmvClassExpandTools<
|
|
147
|
+
SourceCode extends new (...args: any[]) => RmmvClass,
|
|
148
|
+
UserCode extends object = any,
|
|
149
|
+
>(params: RmmvClassExpandTools<SourceCode, UserCode>) {
|
|
150
|
+
const { source, userCode, config } = params;
|
|
151
|
+
const handleStrategyConfig = config;
|
|
152
|
+
|
|
153
|
+
function getHandleStrategy(key: HandleStrategyConfigKeys<UserCode>): HandleStrategy {
|
|
154
|
+
return handleStrategyConfig?.[key] ?? defaultHandleStrategy;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** 源对象的原型链 */
|
|
158
|
+
const sourcePrototype = source.prototype;
|
|
159
|
+
|
|
160
|
+
/** 属性是否在源对象的原型链内? */
|
|
161
|
+
function isInSourcePrototype(key: string) {
|
|
162
|
+
return hasIn(sourcePrototype, key);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/** 是不是初始化函数的名称? */
|
|
166
|
+
function isInitialize(key: string): key is defaultHandleStrategy_FuncationName {
|
|
167
|
+
return key === "initialize";
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
forIn(userCode, function (value, key, object: Record<string, any>) {
|
|
171
|
+
console.log(` value, key, object `, value, key);
|
|
172
|
+
|
|
173
|
+
// 继承对象有没有这个属性?
|
|
174
|
+
if (isInSourcePrototype(key)) {
|
|
175
|
+
if (isFunction(object[key])) {
|
|
176
|
+
const handleStrategy = getHandleStrategy(key as HandleStrategyConfigKeys<UserCode>);
|
|
177
|
+
|
|
178
|
+
// 1 用户代码覆盖掉rmmv源码
|
|
179
|
+
if (isUserCodeCoverSource(handleStrategy)) {
|
|
180
|
+
sourcePrototype[key] = value;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// 2 初始化函数默认使用固定的处理策略
|
|
184
|
+
// 3 默认处理策略
|
|
185
|
+
if (isInitialize(key) || isSourceFirst(handleStrategy)) {
|
|
186
|
+
const functionAliasId = generateFunctionAliasId(key);
|
|
187
|
+
functionAlias.set(functionAliasId, sourcePrototype[key]);
|
|
188
|
+
|
|
189
|
+
sourcePrototype[key] = function () {
|
|
190
|
+
console.log(` 进入到二次封装的函数 函数id = `, functionAliasId);
|
|
191
|
+
// 先回调rmmv源码
|
|
192
|
+
functionAlias.get(functionAliasId)!.apply(this, arguments);
|
|
193
|
+
value.apply(this, arguments);
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// 4 先执行用户代码 再回调rmmv源码
|
|
198
|
+
if (isUserCodeFirst(handleStrategy)) {
|
|
199
|
+
const functionAliasId = generateFunctionAliasId(key);
|
|
200
|
+
functionAlias.set(functionAliasId, sourcePrototype[key]);
|
|
201
|
+
|
|
202
|
+
sourcePrototype[key] = function () {
|
|
203
|
+
console.log(` 进入到二次封装的函数 函数id = `, functionAliasId);
|
|
204
|
+
// 先执行用户代码
|
|
205
|
+
value.apply(this, arguments);
|
|
206
|
+
functionAlias.get(functionAliasId)!.apply(this, arguments);
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} else {
|
|
211
|
+
if (isFunction(object[key])) {
|
|
212
|
+
/**
|
|
213
|
+
* 5 继承对象没有这个属性时 说明是新的函数
|
|
214
|
+
* 直接添加到原型链上
|
|
215
|
+
*/
|
|
216
|
+
sourcePrototype[key] = value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"composite": true,
|
|
4
|
+
// 项目的根目录
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
// 项目基础目录
|
|
7
|
+
"baseUrl": ".",
|
|
8
|
+
"declaration": true,
|
|
9
|
+
"allowImportingTsExtensions": true,
|
|
10
|
+
"emitDeclarationOnly": true,
|
|
11
|
+
// tsc 编译产物输出目录
|
|
12
|
+
"outDir": "dist",
|
|
13
|
+
"checkJs": true,
|
|
14
|
+
// 项目包含了js
|
|
15
|
+
"allowJs": true,
|
|
16
|
+
"module": "nodenext",
|
|
17
|
+
"target": "ESNext",
|
|
18
|
+
// 模块解析策略
|
|
19
|
+
"moduleResolution": "NodeNext",
|
|
20
|
+
// 是否生成辅助 debug 的 .map.js 文件。
|
|
21
|
+
"sourceMap": false,
|
|
22
|
+
// 产物不消除注释
|
|
23
|
+
"removeComments": false,
|
|
24
|
+
// 严格模式类型检查,建议开启
|
|
25
|
+
"strict": true,
|
|
26
|
+
// 允许引入 .json 模块
|
|
27
|
+
"resolveJsonModule": true,
|
|
28
|
+
// 检查类型时是否跳过类型声明文件,一般在上游依赖存在类型问题时置为 true。
|
|
29
|
+
"skipLibCheck": true,
|
|
30
|
+
// 需要使用 ThisType 工具
|
|
31
|
+
"noImplicitThis": true,
|
|
32
|
+
"types": [
|
|
33
|
+
"typedoc",
|
|
34
|
+
"typedoc-plugin-markdown",
|
|
35
|
+
],
|
|
36
|
+
"paths": {
|
|
37
|
+
"@/*": [
|
|
38
|
+
"./src/*"
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
"include": [
|
|
43
|
+
"./src/**/*.ts",
|
|
44
|
+
"./tests/**/*.ts",
|
|
45
|
+
"./src/**/*.js",
|
|
46
|
+
"./tests/**/*.js",
|
|
47
|
+
// 尝试手动提供一个全局的类型声明。
|
|
48
|
+
"./tests/with-types/types/CanNewTypeByClass.d.ts",
|
|
49
|
+
],
|
|
50
|
+
"exclude": [
|
|
51
|
+
"typedoc.config.cjs"
|
|
52
|
+
]
|
|
53
|
+
}
|