173 lines
5.0 kB
1
import { WebpackModule, WebpackModuleFunc, WebpackRequireType } from "@moonlight-mod/types";
2
import { Spacepack } from "@moonlight-mod/types/coreExtensions/spacepack";
3
import { processFind, testFind } from "@moonlight-mod/core/util/patch";
4
5
const webpackRequire = require as unknown as WebpackRequireType;
6
const cache = webpackRequire.c;
7
const modules = webpackRequire.m;
8
9
const logger = moonlight.getLogger("spacepack");
10
11
export const spacepack: Spacepack = {
12
require: webpackRequire,
13
modules,
14
cache,
15
16
inspect: (module: number | string) => {
17
if (typeof module === "number") {
18
module = module.toString();
19
}
20
21
if (module in moonlight.moonmap.modules) {
22
module = moonlight.moonmap.modules[module];
23
}
24
25
if (!(module in modules)) {
26
return null;
27
}
28
29
const func = modules[module];
30
if (func.__moonlight === true) {
31
return func;
32
}
33
34
const funcStr = func.toString();
35
36
return new Function(
37
"module",
38
"exports",
39
"require",
40
`(${funcStr}).apply(this, arguments)\n` + `//# sourceURL=Webpack-Module-${module}`
41
) as WebpackModuleFunc;
42
},
43
44
findByCode: (...args: (string | RegExp)[]) => {
45
return Object.entries(modules)
46
.filter(([id, mod]) => !args.some((item) => !testFind(mod.toString(), processFind(item))))
47
.map(([id]) => {
48
//if (!(id in cache)) require(id);
49
//return cache[id];
50
51
let exports;
52
try {
53
exports = require(id);
54
} catch (e) {
55
logger.error(`Error requiring module "${id}": `, e);
56
}
57
58
return {
59
id,
60
exports
61
};
62
})
63
.filter((item) => item !== null);
64
},
65
66
findByExports: (...args: string[]) => {
67
return Object.entries(cache)
68
.filter(
69
([id, { exports }]) =>
70
!args.some(
71
(item) =>
72
!(
73
exports !== undefined &&
74
exports !== window &&
75
(exports?.[item] || exports?.default?.[item] || exports?.Z?.[item] || exports?.ZP?.[item])
76
)
77
)
78
)
79
.map((item) => item[1])
80
.reduce<WebpackModule[]>((prev, curr) => {
81
if (!prev.includes(curr)) prev.push(curr);
82
return prev;
83
}, []);
84
},
85
86
findObjectFromKey: (exports: Record<string, any>, key: string) => {
87
let subKey;
88
if (key.indexOf(".") > -1) {
89
const splitKey = key.split(".");
90
key = splitKey[0];
91
subKey = splitKey[1];
92
}
93
for (const exportKey in exports) {
94
const obj = exports[exportKey];
95
if (obj && obj[key] !== undefined) {
96
if (subKey) {
97
if (obj[key][subKey]) return obj;
98
} else {
99
return obj;
100
}
101
}
102
}
103
return null;
104
},
105
106
findObjectFromValue: (exports: Record<string, any>, value: any) => {
107
for (const exportKey in exports) {
108
const obj = exports[exportKey];
109
// eslint-disable-next-line eqeqeq
110
if (obj == value) return obj;
111
for (const subKey in obj) {
112
// eslint-disable-next-line eqeqeq
113
if (obj && obj[subKey] == value) {
114
return obj;
115
}
116
}
117
}
118
return null;
119
},
120
121
findObjectFromKeyValuePair: (exports: Record<string, any>, key: string, value: any) => {
122
for (const exportKey in exports) {
123
const obj = exports[exportKey];
124
// eslint-disable-next-line eqeqeq
125
if (obj && obj[key] == value) {
126
return obj;
127
}
128
}
129
return null;
130
},
131
132
findFunctionByStrings: (exports: Record<string, any>, ...strings: (string | RegExp)[]) => {
133
return (
134
Object.entries(exports).filter(
135
([index, func]) =>
136
typeof func === "function" && !strings.some((query) => !testFind(func.toString(), processFind(query)))
137
)?.[0]?.[1] ?? null
138
);
139
},
140
141
lazyLoad: (find: string | RegExp | (string | RegExp)[], chunk: RegExp, module: RegExp) => {
142
const mod = Array.isArray(find) ? spacepack.findByCode(...find) : spacepack.findByCode(find);
143
if (mod.length < 1) return Promise.reject("Module find failed");
144
145
const findId = mod[0].id;
146
const findCode = webpackRequire.m[findId].toString().replace(/\n/g, "");
147
148
let chunkIds;
149
if (chunk.flags.includes("g")) {
150
chunkIds = [...findCode.matchAll(chunk)].map(([, id]) => id);
151
} else {
152
const match = findCode.match(chunk);
153
if (match) chunkIds = [...match[0].matchAll(/"(\d+)"/g)].map(([, id]) => id);
154
}
155
156
if (!chunkIds || chunkIds.length === 0) return Promise.reject("Chunk ID match failed");
157
158
const moduleId = findCode.match(module)?.[1];
159
if (!moduleId) return Promise.reject("Module ID match failed");
160
161
return Promise.all(chunkIds.map((c) => webpackRequire.e(c))).then(() => webpackRequire(moduleId));
162
},
163
164
filterReal: (modules: WebpackModule[]) => {
165
return modules.filter((module) => module.id.toString().match(/^\d+$/));
166
}
167
};
168
169
if (moonlight.getConfigOption<boolean>("spacepack", "addToGlobalScope") === true) {
170
window.spacepack = spacepack;
171
}
172
173
export default spacepack;
174