diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ac9598b..0286a9c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,13 +26,13 @@ jobs: with: node-version: 20 - - name: Install dependencies + - name: Install pnpm and dependencies run: | npm i -g pnpm - pnpm i + pnpm i\ - name: Build - run: pnpm build + run: pnpm build --release-branch=${{ github.ref_name }} --build-minify # TODO: Check for linting? @@ -49,5 +49,5 @@ jobs: - name: Purge CDN cache run: | - curl https://purge.jsdelivr.net/gh/pyoncord/bunny-builds@${{ github.ref_name }}/bunny.js + curl https://purge.jsdelivr.net/gh/pyoncord/bunny-build-infos@${{ github.ref_name }}/bunny.js diff --git a/build.mjs b/build.mjs deleted file mode 100644 index 63b1239..0000000 --- a/build.mjs +++ /dev/null @@ -1,168 +0,0 @@ -/* eslint-disable no-restricted-syntax */ -// eslint-disable-next-line simple-import-sort/imports -// todo: rewrite aaaaaaaaa -import swc from "@swc/core"; -import { execSync } from "child_process"; -import esbuild from "esbuild"; -import { readFile } from "fs/promises"; -import { createServer } from "http"; -import { argv } from "process"; - -// @ts-ignore -const isFlag = (s, l) => argv.slice(2).some(c => c === `-${s}` || c === `--${l}`); - -const isRelease = isFlag("r", "release"); -const shouldServe = isFlag("s", "serve"); -const shouldWatch = isFlag("w", "watch"); - -const commitHash = execSync("git rev-parse --short HEAD").toString().trim(); - -try { - const ctx = await esbuild.context({ - entryPoints: ["./src/entry.js"], - bundle: true, - minify: isRelease, - format: "iife", - target: "esnext", - supported: { - // Hermes does not actually supports const and let, even though it syntactically - // accepts it, but it's treated just like 'var' and causes issues - "const-and-let": false - }, - outfile: "dist/bunny.js", - keepNames: true, - footer: { - js: "//# sourceURL=bunny" - }, - define: { - __DEV__: String(!isRelease) - }, - loader: { ".png": "dataurl" }, - legalComments: "none", - plugins: [ - { - name: "runtimeGlobalAlias", - setup: async build => { - const globalMap = { - "react": "globalThis.React", - "react-native": "globalThis.ReactNative" - }; - - Object.keys(globalMap).forEach(key => { - const filter = new RegExp(`^${key}$`); - build.onResolve({ filter }, args => ({ - namespace: "glob-" + key, path: args.path - })); - build.onLoad({ filter, namespace: "glob-" + key }, () => ({ - // @ts-ignore - contents: `Object.defineProperty(module, 'exports', { get: () => ${globalMap[key]} })`, - resolveDir: "src", - })); - }); - } - }, - { - name: "buildLog", - setup: async build => { - build.onStart(() => { - console.clear(); - console.log(`Building with commit hash "${commitHash}", isRelease="${isRelease}"`); - }); - - build.onEnd(result => { - console.log(`Built with ${result.errors?.length} errors!`); - }); - } - }, - { - name: "swc", - setup(build) { - let timeString = Number(new Date).toString(36); - - build.onStart(() => { - timeString = Number(new Date).toString(36); - console.log(`swc plugin: time-string="${timeString}"`); - }); - - build.onLoad({ filter: /\.[jt]sx?$/ }, async args => { - const result = await swc.transformFile(args.path, { - jsc: { - externalHelpers: true, - transform: { - constModules: { - globals: { - "bunny-build": { - version: `"${isRelease ? commitHash : timeString}"` - } - } - }, - react: { - pragma: "__bunny_createElement" - } - }, - }, - // https://github.com/facebook/hermes/blob/3815fec63d1a6667ca3195160d6e12fee6a0d8d5/doc/Features.md - // https://github.com/facebook/hermes/issues/696#issuecomment-1396235791 - env: { - targets: "fully supports es6", - include: [ - "transform-arrow-functions", - "transform-block-scoping", - "transform-classes" - ], - 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" - ] - }, - }); - - return { contents: result.code }; - }); - } - } - ], - external: [] - }); - - if (shouldWatch) { - await ctx.watch(); - console.log("Watching..."); - } - - if (shouldServe) { - await ctx.rebuild(); - - const server = createServer(async (req, res) => { - try { - if (req.url === "/vendetta.js" || req.url === "/pyoncord.js" || req.url === "/bunny.js") { - await ctx.rebuild(); - res.writeHead(200); - res.end(await readFile("./dist/bunny.js"), "utf-8"); - } else { - res.writeHead(404); - res.end(); - } - } catch (error) { - res.writeHead(500); - res.end(); - } - }).listen(4040); - - // @ts-ignore - console.log(`Serving on port ${server.address()?.port}, CTRL+C to stop`); - } - - if (!shouldServe && !shouldWatch) { - ctx.rebuild(); - ctx.dispose(); - } -} catch (e) { - console.error("Build failed...", e); - process.exit(1); -} diff --git a/package.json b/package.json index 6faa576..6f9804e 100644 --- a/package.json +++ b/package.json @@ -1,23 +1,16 @@ { "name": "bunny", - "version": "1.0.0", - "description": "A mod for Discord's mobile apps, fork of Vendetta.", + "private": true, + "author": { + "name": "Pyoncord Team", + "url": "https://github.com/pyoncord" + }, "scripts": { - "dev": "node build.mjs", - "build": "node build.mjs --release", - "serve": "node build.mjs --serve", - "watch": "node build.mjs --watch", + "build": "node scripts/build.mjs", + "serve": "node scripts/serve.mjs", + "serve:adb": "pnpm run serve --adb", "lint": "eslint ./src --ext .js,.jsx,.ts,.tsx" }, - "keywords": [ - "discord", - "android", - "ios", - "react native", - "vendetta", - "bunny" - ], - "author": "pylixonly, Team Vendetta", "license": "BSD-3-Clause", "devDependencies": { "@react-native-clipboard/clipboard": "1.10.0", @@ -29,7 +22,7 @@ "@types/node": "^20.11.25", "@types/react": "~18.2.0", "@types/react-native": "~0.72.0", - "@types/spark-md5": "^3.0.4", + "@types/yargs-parser": "^21.0.3", "@typescript-eslint/eslint-plugin": "^7.1.1", "@typescript-eslint/parser": "^7.1.1", "@typescript-eslint/typescript-estree": "^7.1.1", @@ -43,9 +36,10 @@ "moment": "2.22.2", "type-fest": "^4.12.0", "typescript": "^5.4.5", - "typescript-transform-paths": "^3.4.7" + "yargs-parser": "^21.1.1" }, "dependencies": { + "chalk": "^5.3.0", "fuzzysort": "^2.0.4", "spitroast": "^1.4.4" }, @@ -57,4 +51,4 @@ ] } } -} +} \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f334f7e..8c3124b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,9 @@ settings: excludeLinksFromLockfile: false dependencies: + chalk: + specifier: ^5.3.0 + version: 5.3.0 fuzzysort: specifier: ^2.0.4 version: 2.0.4 @@ -40,9 +43,9 @@ devDependencies: '@types/react-native': specifier: ~0.72.0 version: 0.72.3 - '@types/spark-md5': - specifier: ^3.0.4 - version: 3.0.4 + '@types/yargs-parser': + specifier: ^21.0.3 + version: 21.0.3 '@typescript-eslint/eslint-plugin': specifier: ^7.1.1 version: 7.1.1(@typescript-eslint/parser@7.1.1)(eslint@8.57.0)(typescript@5.4.5) @@ -82,9 +85,9 @@ devDependencies: typescript: specifier: ^5.4.5 version: 5.4.5 - typescript-transform-paths: - specifier: ^3.4.7 - version: 3.4.7(typescript@5.4.5) + yargs-parser: + specifier: ^21.1.1 + version: 21.1.1 packages: @@ -632,8 +635,8 @@ packages: resolution: {integrity: sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==} dev: true - /@types/spark-md5@3.0.4: - resolution: {integrity: sha512-qtOaDz+IXiNndPgYb6t1YoutnGvFRtWSNzpVjkAPCfB2UzTyybuD4Tjgs7VgRawum3JnJNRwNQd4N//SvrHg1Q==} + /@types/yargs-parser@21.0.3: + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} dev: true /@typescript-eslint/eslint-plugin@7.1.1(@typescript-eslint/parser@7.1.1)(eslint@8.57.0)(typescript@5.4.5): @@ -970,6 +973,11 @@ packages: supports-color: 7.2.0 dev: true + /chalk@5.3.0: + resolution: {integrity: sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: false + /color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} @@ -2369,15 +2377,6 @@ packages: possible-typed-array-names: 1.0.0 dev: true - /typescript-transform-paths@3.4.7(typescript@5.4.5): - resolution: {integrity: sha512-1Us1kdkdfKd2unbkBAOV2HHRmbRBYpSuk9nJ7cLD2hP4QmfToiM/VpxNlhJc1eezVwVqSKSBjNSzZsK/fWR/9A==} - peerDependencies: - typescript: '>=3.6.5' - dependencies: - minimatch: 3.1.2 - typescript: 5.4.5 - dev: true - /typescript@5.4.5: resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} engines: {node: '>=14.17'} @@ -2468,6 +2467,11 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true + /yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + dev: true + /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} diff --git a/scripts/adb.mjs b/scripts/adb.mjs new file mode 100644 index 0000000..6163448 --- /dev/null +++ b/scripts/adb.mjs @@ -0,0 +1,29 @@ +// @ts-nocheck +import { execSync } from "child_process"; + +const packageName = process.env.DISCORD_PACKAGE_NAME ?? "com.discord"; + +export function getPackageName() { + return packageName; +} + +export function isADBAvailableAndAppInstalled() { + try { + const out = execSync(`adb shell pm list packages ${packageName}`); + return out.toString().trimEnd() === `package:${packageName}`; + } catch { + return false; + } +} +export async function restartAppFromADB(reversePort) { + if (typeof reversePort === "number") { + await execSync(`adb reverse tcp:${reversePort} tcp:${reversePort}`); + } + + await forceStopAppFromADB(); + await execSync(`adb shell am start ${packageName}/com.discord.main.MainActivity`); +} + +export async function forceStopAppFromADB() { + await execSync(`adb shell am force-stop ${packageName}`); +} diff --git a/scripts/build.mjs b/scripts/build.mjs new file mode 100644 index 0000000..68a3eba --- /dev/null +++ b/scripts/build.mjs @@ -0,0 +1,159 @@ +// @ts-nocheck +/* eslint-disable no-restricted-syntax */ +import swc from "@swc/core"; +import crypto from "crypto"; +import { build } from "esbuild"; +import { readFile, writeFile } from "fs/promises"; +import path from "path"; +import { fileURLToPath } from "url"; +import yargs from "yargs-parser"; + +import { printBuildSuccess } from "./util.mjs"; + +const args = yargs(process.argv.slice(2)); +const { + "release-branch": releaseBranch, + "build-minify": buildMinify +} = args; + +let context = null; + +const config = { + entryPoints: ["src/entry.ts"], + bundle: true, + outfile: "dist/bunny.js", + format: "iife", + splitting: false, + minify: false, + external: [], + supported: { + // Hermes does not actually supports const and let, even though it syntactically + // accepts it, but it's treated just like 'var' and causes issues + "const-and-let": false + }, + footer: { + js: "//# sourceURL=bunny" + }, + loader: { + ".png": "dataurl" + }, + define: { + __DEV__: JSON.stringify(releaseBranch !== "main") + }, + legalComments: "none", + plugins: [ + { + name: "runtimeGlobalAlias", + setup: async build => { + const globalMap = { + "react": "globalThis.React", + "react-native": "globalThis.ReactNative" + }; + + Object.keys(globalMap).forEach(key => { + const filter = new RegExp(`^${key}$`); + build.onResolve({ filter }, args => ({ + namespace: "glob-" + key, path: args.path + })); + build.onLoad({ filter, namespace: "glob-" + key }, () => ({ + // @ts-ignore + contents: `Object.defineProperty(module, 'exports', { get: () => ${globalMap[key]} })`, + resolveDir: "src", + })); + }); + } + }, + { + name: "swc", + setup(build) { + build.onLoad({ filter: /\.[jt]sx?$/ }, async args => { + const result = await swc.transformFile(args.path, { + jsc: { + externalHelpers: true, + transform: { + constModules: { + globals: { + "bunny-build-info": { + version: `"${context.hash}-${releaseBranch ?? "local"}"` + } + } + }, + react: { + pragma: "__bunny_createElement" + } + }, + }, + // https://github.com/facebook/hermes/blob/3815fec63d1a6667ca3195160d6e12fee6a0d8d5/doc/Features.md + // https://github.com/facebook/hermes/issues/696#issuecomment-1396235791 + env: { + targets: "fully supports es6", + include: [ + // Pretend that arrow functions are unsupported, since hermes does not support async arrow functions for some reason + "transform-arrow-functions", + "transform-block-scoping", + "transform-classes" + ], + exclude: [ + "transform-parameters", + "transform-template-literals", + "transform-async-to-generator", + "transform-exponentiation-operator", + "transform-named-capturing-groups-regex", + "transform-nullish-coalescing-operator", + "transform-object-rest-spread", + "transform-optional-chaining" + ] + }, + }); + + return { contents: result.code }; + }); + } + } + ] +}; + +export async function buildBundle() { + context = { + hash: crypto.randomBytes(8).toString("hex").slice(0, 7) + }; + + const initialStartTime = performance.now(); + await build(config); + + return { + config, + context, + timeTook: performance.now() - initialStartTime + }; +} + +const pathToThisFile = path.resolve(fileURLToPath(import.meta.url)); +const pathPassedToNode = path.resolve(process.argv[1]); +const isThisFileBeingRunViaCLI = pathToThisFile.includes(pathPassedToNode); + +if (isThisFileBeingRunViaCLI) { + const { timeTook } = await buildBundle(); + + printBuildSuccess( + context.hash, + releaseBranch, + timeTook + ); + + if (buildMinify) { + const bundleBuffer = await readFile(config.outfile); + + let { code } = await swc.minify( + bundleBuffer.toString(), + { + compress: true, + mangle: true, + } + ); + code += config.footer.js; + + const minFilePath = config.outfile.replace(/\.js$/, ".min.js"); + await writeFile(minFilePath, code); + } +} diff --git a/scripts/serve.mjs b/scripts/serve.mjs new file mode 100644 index 0000000..addcfd8 --- /dev/null +++ b/scripts/serve.mjs @@ -0,0 +1,97 @@ +// @ts-nocheck +import chalk from "chalk"; +import { readFile } from "fs/promises"; +import http from "http"; +import os from "os"; +import readline from "readline"; +import url from "url"; +import yargs from "yargs-parser"; + +import { forceStopAppFromADB, getPackageName, isADBAvailableAndAppInstalled, restartAppFromADB } from "./adb.mjs"; +import { buildBundle } from "./build.mjs"; +import { printBuildSuccess } from "./util.mjs"; + +const args = yargs(process.argv.slice(2)); + +export function serve(options) { + // @ts-ignore + const server = http.createServer(async (req, res) => { + const { pathname } = url.parse(req.url || "", true); + if (pathname?.endsWith(".js")) { + try { + const { config, context, timeTook } = await buildBundle(); + + printBuildSuccess( + context.hash, + args.production, + timeTook + ); + + res.writeHead(200, { "Content-Type": "application/javascript" }); + res.end(await readFile(config.outfile, "utf-8")); + } catch { + res.writeHead(500); + res.end(); + } + } else { + res.writeHead(404); + res.end(); + } + }, options); + + server.listen(args.port ?? 4040); + + console.info(chalk.bold.yellowBright("Serving Bunny bundle, available on:")); + + const netInterfaces = os.networkInterfaces(); + for (const netinterfaces of Object.values(netInterfaces)) { + for (const details of netinterfaces || []) { + if (details.family !== "IPv4") continue; + const port = chalk.green(server.address()?.port.toString()); + console.info(` http://${details.address}:${port}/bundle.js`); + } + } + + return server; +} + +const server = serve(); + +console.log("\nPress Q key or Ctrl+C to exit."); + +if (args.adb && isADBAvailableAndAppInstalled()) { + const packageName = getPackageName(); + + console.log(`Press R key to reload Discord ${chalk.bold.blue(`(${packageName})`)}.`); + console.log(`Press S key to force stop Discord ${chalk.bold.blue(`(${packageName})`)}.`); + + readline.emitKeypressEvents(process.stdin); + + if (process.stdin.isTTY) { + process.stdin.setRawMode(true); + } + + process.stdin.on("keypress", (ch, key) => { + if (!key) return; + + if (key.name === "q" || key.ctrl && key.name === "c") { + process.exit(0); + } + + if (key.name === "r") { + console.info(chalk.yellow(`${chalk.bold("↻ Reloading")} ${packageName}`)); + restartAppFromADB(server.port) + .then(() => console.info(chalk.greenBright(`${chalk.bold("✔ Executed")} reload command`))) + .catch(e => console.error(e)); + } + + if (key.name === "s") { + console.info(chalk.yellow(`${chalk.bold("⎊ Force stopping")} ${packageName}`)); + forceStopAppFromADB() + .then(() => console.info(chalk.greenBright(`${chalk.bold("✔ Executed")} force stop command`))) + .catch(e => console.error(e)); + } + }); +} else if (args.adb) { + console.warn("ADB option enabled but failed to connect to device!"); +} diff --git a/scripts/util.mjs b/scripts/util.mjs new file mode 100644 index 0000000..a0148dc --- /dev/null +++ b/scripts/util.mjs @@ -0,0 +1,16 @@ +// @ts-nocheck +import chalk from "chalk"; + +export function printBuildSuccess( + hash, + branch, + timeTook, + minified +) { + console.info([ + chalk.bold.greenBright("✔ Built bundle" + (minified ? " (minified)" : "")), + hash && chalk.bold.blueBright(`(${hash})`), + !branch && chalk.bold.cyanBright("(local)"), + timeTook && chalk.gray(`in ${timeTook.toFixed(3)}ms`) + ].filter(Boolean).join(" ")); +} diff --git a/src/assets/icons/pyon64.png b/src/assets/icons/pyon64.png deleted file mode 100644 index 9d44b7a..0000000 Binary files a/src/assets/icons/pyon64.png and /dev/null differ diff --git a/src/assets/icons/pyoncord.png b/src/assets/icons/pyoncord.png new file mode 100644 index 0000000..e3f44bf Binary files /dev/null and b/src/assets/icons/pyoncord.png differ diff --git a/src/core/ui/settings/index.ts b/src/core/ui/settings/index.ts index 1a310b1..7006434 100644 --- a/src/core/ui/settings/index.ts +++ b/src/core/ui/settings/index.ts @@ -1,16 +1,13 @@ +import PyoncordIcon from "@assets/icons/pyoncord.png"; import { Strings } from "@core/i18n"; import { requireAssetIndex } from "@lib/api/assets"; import { isFontSupported, isThemeSupported } from "@lib/api/native/loader"; import { useProxy } from "@lib/api/storage"; import { settings } from "@lib/settings"; import { registerSection } from "@ui/settings"; -import { version } from "bunny-build"; +import { version } from "bunny-build-info"; -// @ts-ignore -// eslint-disable-next-line import-alias/import-alias -import _PyoncordIcon from "../../../assets/icons/pyon64.png"; - -export const PyoncordIcon = _PyoncordIcon as string; +export { PyoncordIcon }; export default function initSettings() { registerSection({ diff --git a/src/entry.ts b/src/entry.ts index dfa36f4..a6489ca 100644 --- a/src/entry.ts +++ b/src/entry.ts @@ -1,5 +1,5 @@ import { getFactoryOfProxy } from "@lib/utils/lazy"; -import { version } from "bunny-build"; +import { version } from "bunny-build-info"; import { instead } from "spitroast"; // @ts-ignore - shut up fr diff --git a/src/global.d.ts b/src/global.d.ts index a016786..4b43d15 100644 --- a/src/global.d.ts +++ b/src/global.d.ts @@ -1,12 +1,12 @@ declare global { - var React: typeof import("react"); - var SkiaApi: typeof import("@shopify/react-native-skia").Skia; + var React: typeof import("react"); + var SkiaApi: typeof import("@shopify/react-native-skia").Skia; - interface Window { - [key: string]: any; - vendetta: any; - bunny: typeof import("@lib"); - } + interface Window { + [key: string]: any; + vendetta: any; + bunny: typeof import("@lib"); + } } export { }; diff --git a/src/lib/debug.ts b/src/lib/debug.ts index e055545..9273cab 100644 --- a/src/lib/debug.ts +++ b/src/lib/debug.ts @@ -6,7 +6,7 @@ import { getThemeFromLoader, selectTheme, themes } from "@lib/managers/themes"; import { settings } from "@lib/settings"; import { logger } from "@lib/utils/logger"; import { showToast } from "@ui/toasts"; -import { version } from "bunny-build"; +import { version } from "bunny-build-info"; import { Platform, type PlatformConstants } from "react-native"; export let socket: WebSocket; diff --git a/src/modules.d.ts b/src/modules.d.ts index d667389..bb64d93 100644 --- a/src/modules.d.ts +++ b/src/modules.d.ts @@ -1,5 +1,8 @@ -declare module "bunny-build" { +declare module "bunny-build-info" { const version: string; } -export * from "bunny-build"; +declare module "*.png" { + const str: string; + export default str; +} diff --git a/tsconfig.json b/tsconfig.json index a399671..3428aaa 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,35 +1,45 @@ { - "exclude": ["dist"], - + "exclude": [ + "dist" + ], "compilerOptions": { "strict": true, - "paths": { - "@core/*": ["./src/core/*"], - "@lib": ["./src/lib"], - "@lib/*": ["./src/lib/*"], - "@metro": ["./src/metro"], - "@metro/*": ["./src/metro/*"], - "@ui": ["./src/lib/ui"], - "@ui/*": ["./src/lib/ui/*"], - "@types": ["./src/lib/utils/types.ts"], - "bunny-build": ["./src/modules.d.ts"] + "@core/*": [ + "./src/core/*" + ], + "@lib": [ + "./src/lib" + ], + "@lib/*": [ + "./src/lib/*" + ], + "@metro": [ + "./src/metro" + ], + "@metro/*": [ + "./src/metro/*" + ], + "@ui": [ + "./src/lib/ui" + ], + "@ui/*": [ + "./src/lib/ui/*" + ], + "@types": [ + "./src/lib/utils/types.ts" + ], + "@assets/*": [ + "./src/assets/*" + ] }, - "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, - "noEmit": true, - "allowJs": true, "checkJs": true, - - "plugins": [ - { "transform": "typescript-transform-paths", "afterDeclarations": true } - ], - "jsx": "react", "target": "esnext" } -} +} \ No newline at end of file