refactor+chore: metro & misc. (#29)
* Refactored `lib/metro` and added types + cleaned up `tsconfig.json` + minor changes to `build.mjs` and `package.json` * Made requested changes + added eslint rule to restrict top-level await * Exclude `transform-async-to-generator` from `env` (async/await is es7)
This commit is contained in:
parent
fe586035e3
commit
6162dfd08b
10 changed files with 264 additions and 141 deletions
|
|
@ -9,6 +9,10 @@
|
||||||
"import-alias"
|
"import-alias"
|
||||||
],
|
],
|
||||||
"rules": {
|
"rules": {
|
||||||
|
"no-restricted-syntax": [ "error", {
|
||||||
|
"selector": "AwaitExpression:not(:function *)",
|
||||||
|
"message": "Hermes does not support top-level await, and SWC cannot transform it."
|
||||||
|
} ],
|
||||||
"quotes": [ "error", "double", { "avoidEscape": true } ],
|
"quotes": [ "error", "double", { "avoidEscape": true } ],
|
||||||
"jsx-quotes": [ "error", "prefer-double" ],
|
"jsx-quotes": [ "error", "prefer-double" ],
|
||||||
"no-mixed-spaces-and-tabs": "error",
|
"no-mixed-spaces-and-tabs": "error",
|
||||||
|
|
@ -72,4 +76,4 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
build.mjs
25
build.mjs
|
|
@ -6,6 +6,7 @@ import { readFile } from "fs/promises";
|
||||||
import { createServer } from "http";
|
import { createServer } from "http";
|
||||||
import { argv } from "process";
|
import { argv } from "process";
|
||||||
|
|
||||||
|
// @ts-ignore
|
||||||
const isFlag = (s, l) => argv.slice(2).some(c => c === `-${s}` || c === `--${l}`);
|
const isFlag = (s, l) => argv.slice(2).some(c => c === `-${s}` || c === `--${l}`);
|
||||||
|
|
||||||
const isRelease = isFlag("r", "release");
|
const isRelease = isFlag("r", "release");
|
||||||
|
|
@ -16,7 +17,7 @@ const commitHash = execSync("git rev-parse --short HEAD").toString().trim();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const ctx = await esbuild.context({
|
const ctx = await esbuild.context({
|
||||||
entryPoints: ["src/entry.js"],
|
entryPoints: ["./src/entry.js"],
|
||||||
bundle: true,
|
bundle: true,
|
||||||
minify: isRelease,
|
minify: isRelease,
|
||||||
format: "iife",
|
format: "iife",
|
||||||
|
|
@ -33,13 +34,6 @@ try {
|
||||||
},
|
},
|
||||||
loader: { ".png": "dataurl" },
|
loader: { ".png": "dataurl" },
|
||||||
legalComments: "none",
|
legalComments: "none",
|
||||||
alias: {
|
|
||||||
"@lib/*": "src/lib/*",
|
|
||||||
"@core/*": "src/core/*",
|
|
||||||
"@metro/*": "src/lib/metro/*",
|
|
||||||
"@ui/*": "src/lib/ui/*",
|
|
||||||
"@types": "src/utils/types.ts",
|
|
||||||
},
|
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
name: "runtimeGlobalAlias",
|
name: "runtimeGlobalAlias",
|
||||||
|
|
@ -55,6 +49,7 @@ try {
|
||||||
namespace: "glob-" + key, path: args.path
|
namespace: "glob-" + key, path: args.path
|
||||||
}));
|
}));
|
||||||
build.onLoad({ filter, namespace: "glob-" + key }, () => ({
|
build.onLoad({ filter, namespace: "glob-" + key }, () => ({
|
||||||
|
// @ts-ignore
|
||||||
contents: `Object.defineProperty(module, 'exports', { get: () => ${globalMap[key]} })`,
|
contents: `Object.defineProperty(module, 'exports', { get: () => ${globalMap[key]} })`,
|
||||||
resolveDir: "src",
|
resolveDir: "src",
|
||||||
}));
|
}));
|
||||||
|
|
@ -99,16 +94,22 @@ try {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
// https://github.com/facebook/hermes/blob/3815fec63d1a6667ca3195160d6e12fee6a0d8d5/doc/Features.md
|
||||||
|
// https://github.com/facebook/hermes/issues/696#issuecomment-1396235791
|
||||||
env: {
|
env: {
|
||||||
targets: "defaults",
|
targets: "fully supports es6",
|
||||||
include: [
|
include: [
|
||||||
"transform-classes",
|
|
||||||
"transform-arrow-functions",
|
"transform-arrow-functions",
|
||||||
"transform-block-scoping",
|
"transform-block-scoping",
|
||||||
"transform-class-properties"
|
"transform-classes"
|
||||||
],
|
],
|
||||||
exclude: [
|
exclude: [
|
||||||
"transform-parameters"
|
"transform-async-to-generator",
|
||||||
|
"transform-exponentiation-operator",
|
||||||
|
"transform-named-capturing-groups-regex",
|
||||||
|
"transform-nullish-coalescing-operator",
|
||||||
|
"transform-object-rest-spread",
|
||||||
|
"transform-optional-chaining"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
18
package.json
18
package.json
|
|
@ -21,16 +21,17 @@
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@react-native-clipboard/clipboard": "1.10.0",
|
"@react-native-clipboard/clipboard": "1.10.0",
|
||||||
"@swc/core": "^1.4.6",
|
"@swc/core": "^1.4.17",
|
||||||
"@types/chroma-js": "^2.4.4",
|
"@swc/helpers": "^0.5.11",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/chroma-js": "~2.4.0",
|
||||||
|
"@types/lodash": "~4.17.0",
|
||||||
"@types/node": "^20.11.25",
|
"@types/node": "^20.11.25",
|
||||||
"@types/react": "18.2.60",
|
"@types/react": "~18.2.0",
|
||||||
"@types/react-native": "0.72.3",
|
"@types/react-native": "~0.72.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
"@typescript-eslint/eslint-plugin": "^7.1.1",
|
||||||
"@typescript-eslint/parser": "^7.1.1",
|
"@typescript-eslint/parser": "^7.1.1",
|
||||||
"@typescript-eslint/typescript-estree": "^7.1.1",
|
"@typescript-eslint/typescript-estree": "^7.1.1",
|
||||||
"esbuild": "^0.17.19",
|
"esbuild": "^0.20.2",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-import-alias": "^1.2.0",
|
"eslint-plugin-import-alias": "^1.2.0",
|
||||||
"eslint-plugin-react": "^7.34.0",
|
"eslint-plugin-react": "^7.34.0",
|
||||||
|
|
@ -39,11 +40,10 @@
|
||||||
"intl-messageformat": "^10.5.11",
|
"intl-messageformat": "^10.5.11",
|
||||||
"moment": "2.22.2",
|
"moment": "2.22.2",
|
||||||
"type-fest": "^4.12.0",
|
"type-fest": "^4.12.0",
|
||||||
"typescript": "^5.4.2",
|
"typescript": "^5.4.5",
|
||||||
"typescript-transform-paths": "^3.4.7"
|
"typescript-transform-paths": "^3.4.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@swc/helpers": "0.5.0",
|
|
||||||
"fuzzysort": "^2.0.4",
|
"fuzzysort": "^2.0.4",
|
||||||
"spitroast": "^1.4.4"
|
"spitroast": "^1.4.4"
|
||||||
},
|
},
|
||||||
|
|
@ -55,4 +55,4 @@
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,81 +1,67 @@
|
||||||
import { instead } from "@lib/api/patcher";
|
import { instead } from "@lib/api/patcher";
|
||||||
|
import type { Metro } from "@metro/types";
|
||||||
|
import { metroRequire, modules } from "@metro/utils";
|
||||||
|
|
||||||
export type MetroModules = { [id: string]: any; };
|
export type PropIntellisense<P extends PropertyKey> = Record<P, any> & Record<PropertyKey, any>;
|
||||||
export type PropIntellisense<P extends string | symbol> = Record<P, any> & Record<PropertyKey, any>;
|
export type PropsFinder = <T extends PropertyKey>(...props: T[]) => PropIntellisense<T>;
|
||||||
export type PropsFinder = <T extends string | symbol>(...props: T[]) => PropIntellisense<T>;
|
export type PropsFinderAll = <T extends PropertyKey>(...props: T[]) => PropIntellisense<T>[];
|
||||||
export type PropsFinderAll = <T extends string | symbol>(...props: T[]) => PropIntellisense<T>[];
|
|
||||||
|
|
||||||
interface MetroRequire {
|
/** Makes the module associated with the specified ID non-enumberable. */
|
||||||
(moduleId: string): any;
|
function blacklistModule(id: Metro.ModuleID) {
|
||||||
importDefault(moduleId: string): any;
|
Object.defineProperty(modules, id, { enumerable: false });
|
||||||
importAll(moduleId: string): any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metro global vars
|
|
||||||
declare var __r: MetroRequire;
|
|
||||||
declare var modules: MetroModules;
|
|
||||||
|
|
||||||
// Function to blacklist a module, preventing it from being searched again
|
|
||||||
const blacklist = (id: string) => Object.defineProperty(window.modules, id, {
|
|
||||||
value: window.modules[id],
|
|
||||||
enumerable: false,
|
|
||||||
configurable: true,
|
|
||||||
writable: true
|
|
||||||
});
|
|
||||||
|
|
||||||
const functionToString = Function.prototype.toString;
|
const functionToString = Function.prototype.toString;
|
||||||
|
|
||||||
for (const id in window.modules) {
|
for (const id in modules) {
|
||||||
const moduleDefinition = window.modules[id];
|
const metroModule = modules[id];
|
||||||
|
|
||||||
if (moduleDefinition.factory) {
|
if (metroModule!.factory) {
|
||||||
instead("factory", moduleDefinition, (args, orig) => {
|
instead("factory", metroModule, ((args: Parameters<Metro.FactoryFn>, origFunc: Metro.FactoryFn) => {
|
||||||
const { 1: metroRequire, 4: moduleObject } = args;
|
const { 1: metroRequire, 4: moduleObject } = args;
|
||||||
|
|
||||||
args[2 /* metroImportDefault */] = (id: string) => {
|
args[2 /* metroImportDefault */] = id => {
|
||||||
const exp = metroRequire(id);
|
const exps = metroRequire(id);
|
||||||
return exp && exp.__esModule ? exp.default : exp;
|
return exps && exps.__esModule ? exps.default : exps;
|
||||||
};
|
};
|
||||||
|
|
||||||
args[3 /* metroImportAll */] = (id: string) => {
|
args[3 /* metroImportAll */] = id => {
|
||||||
const exp = metroRequire(id);
|
const exps = metroRequire(id);
|
||||||
if (exp && exp.__esModule) return exp;
|
if (exps && exps.__esModule) return exps;
|
||||||
|
|
||||||
const importAll: Record<string, any> = {};
|
const importAll: Record<string, any> = {};
|
||||||
if (exp) Object.assign(importAll, exp);
|
if (exps) Object.assign(importAll, exps);
|
||||||
return importAll.default = exp, importAll;
|
importAll.default = exps;
|
||||||
|
return importAll;
|
||||||
};
|
};
|
||||||
|
|
||||||
orig(...args);
|
origFunc(...args);
|
||||||
if (moduleObject.exports) onModuleRequire(moduleObject.exports);
|
if (moduleObject.exports) onModuleRequire(moduleObject.exports);
|
||||||
});
|
}) as any); // If only spitroast had better types
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blacklist any "bad-actor" modules, e.g. the dreaded null proxy, the window itself, or undefined modules
|
// Blacklist any "bad-actor" modules, e.g. the dreaded null proxy, the window itself, or undefined modules
|
||||||
for (const id in window.modules) {
|
for (const id in modules) {
|
||||||
const module = requireModule(id);
|
const moduleExports = requireModule(id);
|
||||||
|
|
||||||
if (!module || module === window || module["Revenge EOL when?"] === null) {
|
if (!moduleExports || moduleExports === window || moduleExports["Revenge EOL when?"] === null)
|
||||||
blacklist(id);
|
blacklistModule(id);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let patchedInspectSource = false;
|
let patchedInspectSource = false;
|
||||||
|
|
||||||
function onModuleRequire(exports: any) {
|
function onModuleRequire(moduleExports: any) {
|
||||||
// Temporary
|
// Temporary
|
||||||
exports.initSentry &&= () => { };
|
moduleExports.initSentry &&= () => undefined;
|
||||||
if (exports.default?.track && exports.default.trackMaker) {
|
if (moduleExports.default?.track && moduleExports.default.trackMaker)
|
||||||
exports.default.track = () => Promise.resolve();
|
moduleExports.default.track = () => Promise.resolve();
|
||||||
}
|
|
||||||
|
|
||||||
// There are modules registering the same native component
|
// There are modules registering the same native component
|
||||||
if (exports?.default?.name === "requireNativeComponent") {
|
if (moduleExports?.default?.name === "requireNativeComponent") {
|
||||||
instead("default", exports, (args, orig) => {
|
instead("default", moduleExports, (args, origFunc) => {
|
||||||
try {
|
try {
|
||||||
return orig(...args);
|
return origFunc(...args);
|
||||||
} catch {
|
} catch {
|
||||||
return args[0];
|
return args[0];
|
||||||
}
|
}
|
||||||
|
|
@ -83,9 +69,9 @@ function onModuleRequire(exports: any) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook DeveloperExperimentStore
|
// Hook DeveloperExperimentStore
|
||||||
if (exports?.default?.constructor?.displayName === "DeveloperExperimentStore") {
|
if (moduleExports?.default?.constructor?.displayName === "DeveloperExperimentStore") {
|
||||||
exports.default = new Proxy(exports.default, {
|
moduleExports.default = new Proxy(moduleExports.default, {
|
||||||
get: (target, property, receiver) => {
|
get(target, property, receiver) {
|
||||||
if (property === "isDeveloper") {
|
if (property === "isDeveloper") {
|
||||||
// Hopefully won't explode accessing it here :3
|
// Hopefully won't explode accessing it here :3
|
||||||
const { settings } = require("@lib/settings");
|
const { settings } = require("@lib/settings");
|
||||||
|
|
@ -99,66 +85,90 @@ function onModuleRequire(exports: any) {
|
||||||
|
|
||||||
// Funny infinity recursion caused by a race condition
|
// Funny infinity recursion caused by a race condition
|
||||||
if (!patchedInspectSource && window["__core-js_shared__"]) {
|
if (!patchedInspectSource && window["__core-js_shared__"]) {
|
||||||
const inspect = (f: Function) => typeof f === "function" && functionToString.apply(f, []);
|
const inspect = (f: unknown) => typeof f === "function" && functionToString.apply(f, []);
|
||||||
window["__core-js_shared__"].inspectSource = inspect;
|
window["__core-js_shared__"].inspectSource = inspect;
|
||||||
patchedInspectSource = true;
|
patchedInspectSource = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function requireModule(id: string) {
|
const noopHandler = () => undefined;
|
||||||
if (modules[id].isInitialized) return __r(id);
|
|
||||||
|
function requireModule(id: Metro.ModuleID) {
|
||||||
|
if (modules[id]!.isInitialized) return metroRequire(id);
|
||||||
|
|
||||||
// Disable Internal Metro error reporting logic
|
// Disable Internal Metro error reporting logic
|
||||||
const originalHandler = window.ErrorUtils.getGlobalHandler();
|
const originalHandler = ErrorUtils.getGlobalHandler();
|
||||||
window.ErrorUtils.setGlobalHandler(null);
|
ErrorUtils.setGlobalHandler(noopHandler);
|
||||||
|
|
||||||
|
let moduleExports;
|
||||||
try {
|
try {
|
||||||
var exports = __r(id); // metroRequire(id);
|
moduleExports = metroRequire(id);
|
||||||
} catch {
|
} catch {
|
||||||
var exports = undefined;
|
moduleExports = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Done initializing! Now, revert our hacks
|
// Done initializing! Now, revert our hacks
|
||||||
window.ErrorUtils.setGlobalHandler(originalHandler);
|
ErrorUtils.setGlobalHandler(originalHandler);
|
||||||
|
|
||||||
return exports;
|
return moduleExports;
|
||||||
}
|
}
|
||||||
|
|
||||||
function* getModules() {
|
function* getModuleExports() {
|
||||||
yield require("./polyfills/redesign");
|
yield require("@metro/polyfills/redesign");
|
||||||
|
|
||||||
for (const id in modules) {
|
for (const id in modules) {
|
||||||
yield requireModule(id);
|
yield requireModule(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to filter through modules
|
type ExportsFilter = (moduleExports: any) => unknown;
|
||||||
const filterModules = (modules: MetroModules, single = false) => (filter: (m: any) => boolean) => {
|
|
||||||
const found = [];
|
|
||||||
|
|
||||||
for (const exports of getModules()) {
|
function testExports(moduleExports: any, filter: ExportsFilter) {
|
||||||
if (exports.default && exports.__esModule && filter(exports.default)) {
|
if (moduleExports.default && moduleExports.__esModule && filter(moduleExports.default))
|
||||||
if (single) return exports.default;
|
return moduleExports.default;
|
||||||
found.push(exports.default);
|
if (filter(moduleExports))
|
||||||
}
|
return moduleExports;
|
||||||
|
}
|
||||||
|
|
||||||
if (filter(exports)) {
|
/**
|
||||||
if (single) return exports;
|
* Returns the exports of the first module where filter returns truthy, and undefined otherwise.
|
||||||
else found.push(exports);
|
* @param filter find calls filter once for each enumerable module's exports until it finds one where filter returns a thruthy value.
|
||||||
}
|
*/
|
||||||
|
export function find(filter: ExportsFilter) {
|
||||||
|
for (const moduleExports of getModuleExports()) {
|
||||||
|
const testedExports = testExports(moduleExports, filter);
|
||||||
|
if (testedExports !== undefined)
|
||||||
|
return testedExports;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!single) return found;
|
/**
|
||||||
};
|
* Returns the exports of all modules where filter returns truthy.
|
||||||
|
* @param filter findAll calls filter once for each enumerable module's exports, adding the exports to the returned array when filter returns a thruthy value.
|
||||||
|
*/
|
||||||
|
export function findAll(filter: ExportsFilter) {
|
||||||
|
const foundExports: any[] = [];
|
||||||
|
for (const moduleExports of getModuleExports()) {
|
||||||
|
const testedExports = testExports(moduleExports, filter);
|
||||||
|
if (testedExports !== undefined)
|
||||||
|
foundExports.push(testedExports);
|
||||||
|
}
|
||||||
|
return foundExports;
|
||||||
|
}
|
||||||
|
|
||||||
export const find = filterModules(modules, true);
|
const propsFilter = (props: PropertyKey[]) =>
|
||||||
export const findAll = filterModules(modules);
|
(exps: any) => props.every(p => exps[p] !== undefined);
|
||||||
|
const nameFilter = (name: string, defaultExp: boolean) => defaultExp
|
||||||
const propsFilter = (props: (string | symbol)[]) => (m: any) => props.every(p => m[p] !== undefined);
|
? (exps: any) => exps?.name === name
|
||||||
const nameFilter = (name: string, defaultExp: boolean) => (defaultExp ? (m: any) => m?.name === name : (m: any) => m?.default?.name === name);
|
: (exps: any) => exps?.default?.name === name;
|
||||||
const dNameFilter = (displayName: string, defaultExp: boolean) => (defaultExp ? (m: any) => m?.displayName === displayName : (m: any) => m?.default?.displayName === displayName);
|
const dNameFilter = (displayName: string, defaultExp: boolean) => defaultExp
|
||||||
const tNameFilter = (typeName: string, defaultExp: boolean) => (defaultExp ? (m: any) => m?.type?.name === typeName : (m: any) => m?.default?.type?.name === typeName);
|
? (exps: any) => exps?.displayName === displayName
|
||||||
const storeFilter = (name: string) => (m: any) => m.getName && m.getName.length === 0 && m.getName() === name;
|
: (exps: any) => exps?.default?.displayName === displayName;
|
||||||
|
const tNameFilter = (typeName: string, defaultExp: boolean) => defaultExp
|
||||||
|
? (exps: any) => exps?.type?.name === typeName
|
||||||
|
: (exps: any) => exps?.default?.type?.name === typeName;
|
||||||
|
const storeFilter = (name: string) =>
|
||||||
|
(exps: any) => exps.getName && exps.getName.length === 0 && exps.getName() === name;
|
||||||
|
|
||||||
export const findByProps: PropsFinder = (...props) => find(propsFilter(props));
|
export const findByProps: PropsFinder = (...props) => find(propsFilter(props));
|
||||||
export const findByPropsAll: PropsFinderAll = (...props) => findAll(propsFilter(props));
|
export const findByPropsAll: PropsFinderAll = (...props) => findAll(propsFilter(props));
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
export * as common from "./common";
|
export * from "./utils";
|
||||||
export {
|
export {
|
||||||
find,
|
find,
|
||||||
findAll,
|
findAll,
|
||||||
|
|
@ -10,6 +10,7 @@ export {
|
||||||
findByPropsAll,
|
findByPropsAll,
|
||||||
findByStoreName,
|
findByStoreName,
|
||||||
findByTypeName,
|
findByTypeName,
|
||||||
findByTypeNameAll,
|
findByTypeNameAll
|
||||||
} from "./filters";
|
} from "./filters";
|
||||||
export * as filters from "./filters";
|
export * as filters from "./filters";
|
||||||
|
export * as common from "./common";
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import "@metro/index";
|
import { metroRequire, modules } from "@metro";
|
||||||
|
|
||||||
import { LiteralUnion } from "type-fest";
|
import { LiteralUnion } from "type-fest";
|
||||||
|
|
||||||
|
|
@ -103,25 +103,23 @@ type Keys = LiteralUnion<typeof redesignProps extends Set<infer U> ? U : string,
|
||||||
const redesignPropSource = {} as Record<Keys, any>;
|
const redesignPropSource = {} as Record<Keys, any>;
|
||||||
const redesignModule = {} as Record<Keys, any>;
|
const redesignModule = {} as Record<Keys, any>;
|
||||||
|
|
||||||
for (const id in window.modules) {
|
for (const id in modules) {
|
||||||
const exports = window.__r(id);
|
const moduleExports = metroRequire(id);
|
||||||
polyfillRedesignModule(exports);
|
polyfillRedesignModule(moduleExports);
|
||||||
}
|
}
|
||||||
|
|
||||||
function polyfillRedesignModule(exports: any) {
|
function polyfillRedesignModule(moduleExports: any) {
|
||||||
const propMap = new Map<string, string | null>();
|
const propMap = new Map<string, string | null>();
|
||||||
|
|
||||||
for (const prop of redesignProps) {
|
for (const prop of redesignProps) {
|
||||||
if (exports?.[prop]) {
|
if (moduleExports?.[prop])
|
||||||
propMap.set(prop, null);
|
propMap.set(prop, null);
|
||||||
}
|
else if (moduleExports?.default?.[prop])
|
||||||
else if (exports?.default?.[prop]) {
|
|
||||||
propMap.set(prop, "default");
|
propMap.set(prop, "default");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [prop, defaultKey] of propMap) {
|
for (const [prop, defaultKey] of propMap) {
|
||||||
const exportsForProp = defaultKey ? exports[defaultKey] : exports;
|
const exportsForProp = defaultKey ? moduleExports[defaultKey] : moduleExports;
|
||||||
|
|
||||||
if (redesignModule[prop]) {
|
if (redesignModule[prop]) {
|
||||||
if (Object.keys(exportsForProp).length < Object.keys(redesignPropSource[prop]).length) {
|
if (Object.keys(exportsForProp).length < Object.keys(redesignPropSource[prop]).length) {
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,96 @@
|
||||||
|
import type { Nullish } from "@types";
|
||||||
|
|
||||||
|
/** @see {@link https://github.com/facebook/metro/blob/c2d7539dfc10aacb2f99fcc2f268a3b53e867a90/packages/metro-runtime/src/polyfills/require.js} */
|
||||||
|
export namespace Metro {
|
||||||
|
export interface DependencyMap {
|
||||||
|
readonly [indexer: number]: ModuleID;
|
||||||
|
readonly paths?: Readonly<Record<ModuleID, string>> | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type InverseDependencyMap = Record<ModuleID, ModuleID[]>;
|
||||||
|
|
||||||
|
export type FactoryFn = (
|
||||||
|
global: object,
|
||||||
|
require: RequireFn,
|
||||||
|
metroImportDefault: RequireFn,
|
||||||
|
metroImportAll: RequireFn,
|
||||||
|
moduleObject: {
|
||||||
|
exports: any;
|
||||||
|
},
|
||||||
|
exports: any,
|
||||||
|
dependencyMap: DependencyMap | Nullish,
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export interface HotModuleReloadingData {
|
||||||
|
_acceptCallback: (() => void) | Nullish;
|
||||||
|
_disposeCallback: (() => void) | Nullish;
|
||||||
|
_didAccept: boolean;
|
||||||
|
accept: (callback?: (() => void) | undefined) => void;
|
||||||
|
dispose: (callback?: (() => void) | undefined) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModuleID = string | number;
|
||||||
|
|
||||||
|
export interface Module {
|
||||||
|
id?: ModuleID | undefined;
|
||||||
|
exports: any;
|
||||||
|
hot?: HotModuleReloadingData | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ModuleDefinition {
|
||||||
|
dependencyMap: DependencyMap | Nullish;
|
||||||
|
error?: any;
|
||||||
|
factory: FactoryFn | undefined;
|
||||||
|
hasError: boolean;
|
||||||
|
hot?: HotModuleReloadingData | undefined;
|
||||||
|
importedAll: any;
|
||||||
|
importedDefault: any;
|
||||||
|
isInitialized: boolean;
|
||||||
|
path?: string | undefined;
|
||||||
|
publicModule: Module;
|
||||||
|
verboseName?: string | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ModuleList = Record<ModuleID, ModuleDefinition | Nullish>;
|
||||||
|
|
||||||
|
export type RequireFn = (id: ModuleID) => any;
|
||||||
|
|
||||||
|
export type DefineFn = (
|
||||||
|
factory: FactoryFn,
|
||||||
|
moduleId: ModuleID,
|
||||||
|
dependencyMap?: DependencyMap | undefined,
|
||||||
|
verboseName?: string | undefined,
|
||||||
|
inverseDependencies?: InverseDependencyMap | undefined
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export type ModuleDefiner = (moduleId: ModuleID) => void;
|
||||||
|
|
||||||
|
export type ClearFn = () => ModuleList;
|
||||||
|
|
||||||
|
export type RegisterSegmentFn = (
|
||||||
|
segmentId: number,
|
||||||
|
moduleDefiner: ModuleDefiner,
|
||||||
|
moduleIds: Readonly<ModuleID[]> | Nullish
|
||||||
|
) => void;
|
||||||
|
|
||||||
|
export interface Require extends RequireFn {
|
||||||
|
importDefault: RequireFn;
|
||||||
|
importAll: RequireFn;
|
||||||
|
/** @throws {Error} */
|
||||||
|
context: () => never;
|
||||||
|
/** @throws {Error} */
|
||||||
|
resolveWeak: () => never;
|
||||||
|
unpackModuleId: (moduleId: ModuleID) => {
|
||||||
|
localId: number;
|
||||||
|
segmentId: number;
|
||||||
|
};
|
||||||
|
packModuleId: (value: {
|
||||||
|
localId: number;
|
||||||
|
segmentId: number;
|
||||||
|
}) => ModuleID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface Dispatcher {
|
export interface Dispatcher {
|
||||||
_actionHandlers: unknown;
|
_actionHandlers: unknown;
|
||||||
_interceptors?: ((payload: any) => void | boolean)[];
|
_interceptors?: ((payload: any) => void | boolean)[];
|
||||||
|
|
@ -16,4 +109,3 @@ export interface Dispatcher {
|
||||||
unsubscribe(actionType: string, callback: (payload: any) => void): void;
|
unsubscribe(actionType: string, callback: (payload: any) => void): void;
|
||||||
wait(cb: () => void): void;
|
wait(cb: () => void): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
11
src/lib/metro/utils.ts
Normal file
11
src/lib/metro/utils.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
import type { Metro } from "@metro/types";
|
||||||
|
|
||||||
|
export const modules: Metro.ModuleList = window.modules;
|
||||||
|
|
||||||
|
export const metroRequire: Metro.Require = window.__r;
|
||||||
|
|
||||||
|
export const define: Metro.DefineFn = window.__d;
|
||||||
|
|
||||||
|
export const clear: Metro.ClearFn = window.__c;
|
||||||
|
|
||||||
|
export const registerSegment: Metro.RegisterSegmentFn = window.__registerSegment;
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import { LiteralUnion } from "type-fest";
|
import { LiteralUnion } from "type-fest";
|
||||||
|
|
||||||
|
export type Nullish = null | undefined;
|
||||||
|
|
||||||
export type OptionalKeys<T extends Array<string>> = LiteralUnion<T[number], string>;
|
export type OptionalKeys<T extends Array<string>> = LiteralUnion<T[number], string>;
|
||||||
|
|
||||||
export interface Author {
|
export interface Author {
|
||||||
|
|
|
||||||
|
|
@ -1,31 +1,35 @@
|
||||||
{
|
{
|
||||||
"include": ["src"],
|
"exclude": ["dist"],
|
||||||
"exclude": ["node_modules"],
|
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"baseUrl": ".",
|
|
||||||
"sourceMap": true,
|
|
||||||
"module": "ESNext",
|
|
||||||
"target": "ESNext",
|
|
||||||
"declaration": true,
|
|
||||||
"emitDeclarationOnly": true,
|
|
||||||
"moduleResolution": "node",
|
|
||||||
"esModuleInterop": true,
|
|
||||||
"jsx": "react",
|
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"stripInternal": true,
|
|
||||||
"forceConsistentCasingInFileNames": true,
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"skipLibCheck": true,
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@lib/*": ["src/lib/*"],
|
"@core/*": ["./src/core/*"],
|
||||||
"@core/*": ["src/core/*"],
|
"@lib": ["./src/lib"],
|
||||||
"@metro/*": ["src/lib/metro/*"],
|
"@lib/*": ["./src/lib/*"],
|
||||||
"@ui/*": ["src/lib/ui/*"],
|
"@metro": ["./src/lib/metro"],
|
||||||
"@types": ["src/lib/utils/types.ts"],
|
"@metro/*": ["./src/lib/metro/*"],
|
||||||
"bunny-build": ["src/modules.d.ts"]
|
"@ui": ["./src/lib/ui"],
|
||||||
|
"@ui/*": ["./src/lib/ui/*"],
|
||||||
|
"@types": ["./src/lib/utils/types.ts"],
|
||||||
|
"bunny-build": ["./src/modules.d.ts"]
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
|
||||||
|
"noEmit": true,
|
||||||
|
|
||||||
|
"allowJs": true,
|
||||||
|
"checkJs": true,
|
||||||
|
|
||||||
"plugins": [
|
"plugins": [
|
||||||
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
|
{ "transform": "typescript-transform-paths", "afterDeclarations": true }
|
||||||
]
|
],
|
||||||
|
|
||||||
|
"jsx": "react",
|
||||||
|
"target": "esnext"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue