-
Notifications
You must be signed in to change notification settings - Fork 34
/
webpack.ts
151 lines (128 loc) · 4.12 KB
/
webpack.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import Logger from './logger';
declare global {
interface Window {
webpackChunksteamui: any;
}
}
const logger = new Logger('Webpack');
// In most case an object with getters for each property. Look for the first call to r.d in the module, usually near or at the top.
export type ModuleID = string; // number string
export type Module = any;
export type Export = any;
type FilterFn = (module: any) => boolean;
type ExportFilterFn = (moduleExport: any, exportName?: any) => boolean;
type FindFn = (module: any) => any;
export let modules = new Map<ModuleID, Module>();
function initModuleCache() {
const startTime = performance.now();
logger.group('Webpack Module Init');
// Webpack 5, currently on beta
// Generate a fake module ID
const id = Symbol("@decky/ui");
let webpackRequire!: ((id: any) => Module) & { m: object };
// Insert our module in a new chunk.
// The module will then be called with webpack's internal require function as its first argument
window.webpackChunksteamui.push([
[id],
{},
(r: any) => {
webpackRequire = r;
},
]);
logger.log(
'Initializing all modules. Errors here likely do not matter, as they are usually just failing module side effects.',
);
// Loop over every module ID
for (let id of Object.keys(webpackRequire.m)) {
try {
const module = webpackRequire(id);
if (module) {
modules.set(id, module);
}
} catch (e) {
logger.debug('Ignoring require error for module', id, e);
}
}
logger.groupEnd(`Modules initialized in ${performance.now() - startTime}ms...`);
}
initModuleCache();
export const findModule = (filter: FilterFn) => {
for (const m of modules.values()) {
if (m.default && filter(m.default)) return m.default;
if (filter(m)) return m;
}
};
export const findModuleDetailsByExport = (
filter: ExportFilterFn,
minExports?: number,
): [module: Module | undefined, moduleExport: any, exportName: any, moduleID: string | undefined] => {
for (const [id, m] of modules) {
if (!m) continue;
for (const mod of [m.default, m]) {
if (typeof mod !== 'object') continue;
if (minExports && Object.keys(mod).length < minExports) continue;
for (let exportName in mod) {
if (mod?.[exportName]) {
const filterRes = filter(mod[exportName], exportName);
if (filterRes) {
return [mod, mod[exportName], exportName, id];
} else {
continue;
}
}
}
}
}
return [undefined, undefined, undefined, undefined];
};
export const findModuleByExport = (filter: ExportFilterFn, minExports?: number) => {
return findModuleDetailsByExport(filter, minExports)?.[0];
};
export const findModuleExport = (filter: ExportFilterFn, minExports?: number) => {
return findModuleDetailsByExport(filter, minExports)?.[1];
};
/**
* @deprecated use findModuleExport instead
*/
export const findModuleChild = (filter: FindFn) => {
for (const m of modules.values()) {
for (const mod of [m.default, m]) {
const filterRes = filter(mod);
if (filterRes) {
return filterRes;
} else {
continue;
}
}
}
};
/**
* @deprecated use createModuleMapping instead
*/
export const findAllModules = (filter: FilterFn) => {
const out = [];
for (const m of modules.values()) {
if (m.default && filter(m.default)) out.push(m.default);
if (filter(m)) out.push(m);
}
return out;
};
export const createModuleMapping = (filter: FilterFn) => {
const mapping = new Map<ModuleID, Module>();
for (const [id, m] of modules) {
if (m.default && filter(m.default)) mapping.set(id, m.default);
if (filter(m)) mapping.set(id, m);
}
return mapping;
};
export const CommonUIModule = findModule((m: Module) => {
if (typeof m !== 'object') return false;
for (let prop in m) {
if (m[prop]?.contextType?._currentValue && Object.keys(m).length > 60) return true;
}
return false;
});
export const IconsModule = findModuleByExport(
(e) => e?.toString && /Spinner\)}\)?,.\.createElement\(\"path\",{d:\"M18 /.test(e.toString()),
);
export const ReactRouter = findModuleByExport((e) => e.computeRootMatch);