feat(smart-app): implement complete mobile app MVP

- App.tsx: full navigation (Auth stack + Main tabs with 5 screens)
- Auth: LoginScreen, RegisterScreen, ForgotPasswordScreen
- HomeScreen: dashboard with IoT metrics, weather widget, alerts, quick actions, sensors
- MapScreen: interactive map with layer toggles (6 layers)
- MarketplaceScreen: categories (6), products (5), search
- ChatScreen: AI chat with quick prompts (4), bot responses
- ProfileScreen: user info, stats, menu (9 items), logout
- AlertsScreen: alert list with severity, acknowledge
- SensorsScreen: sensor list with type filters (6 types), search
- ZonesScreen: zone cards with stats
- SettingsScreen: language picker (FR/EN/ES/DE), privacy, about
- Stores: iotStore (sensors, zones, alerts), notificationStore, uiStore + i18n
- Hooks: useSensors, useAlerts, useNotifications, useLocation
- Components: Card, Button, LoadingSpinner, ErrorBoundary, Header
- Services: iotService, notificationService (with axios API client)
- Utils: formatters (temp, AQI, noise, dates), validators (email, password, IBAN)
- Theme: colors.ts with full design system (Blue Ocean palette)
- Ditto: fixed MongoDB connection, new JWT secrets, official gateway image
This commit is contained in:
Eric FELIXINE
2026-06-01 18:00:35 -04:00
parent 08ca495bde
commit e30ae8ed09
35578 changed files with 3703534 additions and 43 deletions

View File

@@ -0,0 +1,35 @@
import { MixedOutput, Module, ReadOnlyGraph, Reporter } from 'metro';
import { ConfigT as MetroConfig, InputConfigT } from 'metro-config';
import { INTERNAL_CALLSITES_REGEX } from './customizeFrame';
export interface LoadOptions {
config?: string;
maxWorkers?: number;
port?: number;
reporter?: Reporter;
resetCache?: boolean;
}
export interface DefaultConfigOptions {
/** @deprecated */
mode?: 'exotic';
/**
* **Experimental:** Enable CSS support for Metro web, and shim on native.
*
* This is an experimental feature and may change in the future. The underlying implementation
* is subject to change, and native support for CSS Modules may be added in the future during a non-major SDK release.
*/
isCSSEnabled?: boolean;
/**
* **Experimental:** Modify premodules before a code asset is serialized
*
* This is an experimental feature and may change in the future. The underlying implementation
* is subject to change.
*/
unstable_beforeAssetSerializationPlugins?: ((serializationInput: {
graph: ReadOnlyGraph<MixedOutput>;
premodules: Module[];
debugId?: string;
}) => Module[])[];
}
export declare function getDefaultConfig(projectRoot: string, { mode, isCSSEnabled, unstable_beforeAssetSerializationPlugins }?: DefaultConfigOptions): InputConfigT;
export { MetroConfig, INTERNAL_CALLSITES_REGEX };
export declare const EXPO_DEBUG: boolean;

View File

@@ -0,0 +1,270 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.EXPO_DEBUG = exports.INTERNAL_CALLSITES_REGEX = exports.getDefaultConfig = void 0;
// Copyright 2023-present 650 Industries (Expo). All rights reserved.
const config_1 = require("@expo/config");
const paths_1 = require("@expo/config/paths");
const runtimeEnv = __importStar(require("@expo/env"));
const json_file_1 = __importDefault(require("@expo/json-file"));
const chalk_1 = __importDefault(require("chalk"));
const metro_cache_1 = require("metro-cache");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const resolve_from_1 = __importDefault(require("resolve-from"));
const customizeFrame_1 = require("./customizeFrame");
Object.defineProperty(exports, "INTERNAL_CALLSITES_REGEX", { enumerable: true, get: function () { return customizeFrame_1.INTERNAL_CALLSITES_REGEX; } });
const env_1 = require("./env");
const file_store_1 = require("./file-store");
const getModulesPaths_1 = require("./getModulesPaths");
const getWatchFolders_1 = require("./getWatchFolders");
const rewriteRequestUrl_1 = require("./rewriteRequestUrl");
const withExpoSerializers_1 = require("./serializer/withExpoSerializers");
const postcss_1 = require("./transform-worker/postcss");
const metro_config_1 = require("./traveling/metro-config");
const debug = require('debug')('expo:metro:config');
function getAssetPlugins(projectRoot) {
const hashAssetFilesPath = resolve_from_1.default.silent(projectRoot, 'expo-asset/tools/hashAssetFiles');
if (!hashAssetFilesPath) {
throw new Error(`The required package \`expo-asset\` cannot be found`);
}
return [hashAssetFilesPath];
}
let hasWarnedAboutExotic = false;
// Patch Metro's graph to support always parsing certain modules. This enables
// things like Tailwind CSS which update based on their own heuristics.
function patchMetroGraphToSupportUncachedModules() {
const { Graph } = require('metro/src/DeltaBundler/Graph');
const original_traverseDependencies = Graph.prototype.traverseDependencies;
if (!original_traverseDependencies.__patched) {
original_traverseDependencies.__patched = true;
Graph.prototype.traverseDependencies = function (paths, options) {
this.dependencies.forEach((dependency) => {
// Find any dependencies that have been marked as `skipCache` and ensure they are invalidated.
// `skipCache` is set when a CSS module is found by PostCSS.
if (dependency.output.find((file) => file.data.css?.skipCache) &&
!paths.includes(dependency.path)) {
// Ensure we invalidate the `unstable_transformResultKey` (input hash) so the module isn't removed in
// the Graph._processModule method.
dependency.unstable_transformResultKey = dependency.unstable_transformResultKey + '.';
// Add the path to the list of modified paths so it gets run through the transformer again,
// this will ensure it is passed to PostCSS -> Tailwind.
paths.push(dependency.path);
}
});
// Invoke the original method with the new paths to ensure the standard behavior is preserved.
return original_traverseDependencies.call(this, paths, options);
};
// Ensure we don't patch the method twice.
Graph.prototype.traverseDependencies.__patched = true;
}
}
function getDefaultConfig(projectRoot, { mode, isCSSEnabled = true, unstable_beforeAssetSerializationPlugins } = {}) {
const { getDefaultConfig: getDefaultMetroConfig, mergeConfig } = (0, metro_config_1.importMetroConfig)(projectRoot);
if (isCSSEnabled) {
patchMetroGraphToSupportUncachedModules();
}
const isExotic = mode === 'exotic' || env_1.env.EXPO_USE_EXOTIC;
if (isExotic && !hasWarnedAboutExotic) {
hasWarnedAboutExotic = true;
console.log(chalk_1.default.gray(`\u203A Feature ${chalk_1.default.bold `EXPO_USE_EXOTIC`} has been removed in favor of the default transformer.`));
}
const reactNativePath = path_1.default.dirname((0, resolve_from_1.default)(projectRoot, 'react-native/package.json'));
const sourceExtsConfig = { isTS: true, isReact: true, isModern: true };
const sourceExts = (0, paths_1.getBareExtensions)([], sourceExtsConfig);
// Add support for cjs (without platform extensions).
sourceExts.push('cjs');
const reanimatedVersion = getPkgVersion(projectRoot, 'react-native-reanimated');
let sassVersion = null;
if (isCSSEnabled) {
sassVersion = getPkgVersion(projectRoot, 'sass');
// Enable SCSS by default so we can provide a better error message
// when sass isn't installed.
sourceExts.push('scss', 'sass', 'css');
}
const envFiles = runtimeEnv.getFiles(process.env.NODE_ENV, { silent: true });
const pkg = (0, config_1.getPackageJson)(projectRoot);
const watchFolders = (0, getWatchFolders_1.getWatchFolders)(projectRoot);
const nodeModulesPaths = (0, getModulesPaths_1.getModulesPaths)(projectRoot);
if (env_1.env.EXPO_DEBUG) {
console.log();
console.log(`Expo Metro config:`);
try {
console.log(`- Version: ${require('../package.json').version}`);
}
catch { }
console.log(`- Extensions: ${sourceExts.join(', ')}`);
console.log(`- React Native: ${reactNativePath}`);
console.log(`- Watch Folders: ${watchFolders.join(', ')}`);
console.log(`- Node Module Paths: ${nodeModulesPaths.join(', ')}`);
console.log(`- Env Files: ${envFiles}`);
console.log(`- Sass: ${sassVersion}`);
console.log(`- Reanimated: ${reanimatedVersion}`);
console.log();
}
const {
// Remove the default reporter which metro always resolves to be the react-native-community/cli reporter.
// This prints a giant React logo which is less accessible to users on smaller terminals.
reporter, ...metroDefaultValues } = getDefaultMetroConfig.getDefaultValues(projectRoot);
const cacheStore = new file_store_1.FileStore({
root: path_1.default.join(os_1.default.tmpdir(), 'metro-cache'),
});
const serverRoot = (0, getModulesPaths_1.getServerRoot)(projectRoot);
// Merge in the default config from Metro here, even though loadConfig uses it as defaults.
// This is a convenience for getDefaultConfig use in metro.config.js, e.g. to modify assetExts.
const metroConfig = mergeConfig(metroDefaultValues, {
watchFolders,
resolver: {
unstable_conditionsByPlatform: {
ios: ['react-native'],
android: ['react-native'],
// This is removed for server platforms.
web: ['browser'],
},
unstable_conditionNames: ['require', 'import'],
resolverMainFields: ['react-native', 'browser', 'main'],
platforms: ['ios', 'android'],
assetExts: metroDefaultValues.resolver.assetExts
.concat(
// Add default support for `expo-image` file types.
['heic', 'avif'],
// Add default support for `expo-sqlite` file types.
['db'])
.filter((assetExt) => !sourceExts.includes(assetExt)),
sourceExts,
nodeModulesPaths,
},
cacheStores: [cacheStore],
watcher: {
// strip starting dot from env files
additionalExts: envFiles.map((file) => file.replace(/^\./, '')),
},
serializer: {
getModulesRunBeforeMainModule: () => {
const preModules = [
// MUST be first
require.resolve(path_1.default.join(reactNativePath, 'Libraries/Core/InitializeCore')),
];
const stdRuntime = resolve_from_1.default.silent(projectRoot, 'expo/build/winter');
if (stdRuntime) {
preModules.push(stdRuntime);
}
// We need to shift this to be the first module so web Fast Refresh works as expected.
// This will only be applied if the module is installed and imported somewhere in the bundle already.
const metroRuntime = resolve_from_1.default.silent(projectRoot, '@expo/metro-runtime');
if (metroRuntime) {
preModules.push(metroRuntime);
}
return preModules;
},
getPolyfills: ({ platform }) => {
// Do nothing for nullish platforms.
if (!platform) {
return [];
}
if (platform === 'web') {
return [
// Ensure that the error-guard polyfill is included in the web polyfills to
// make metro-runtime work correctly.
require.resolve('@react-native/js-polyfills/error-guard'),
];
}
// Native behavior.
return require('@react-native/js-polyfills')();
},
},
server: {
rewriteRequestUrl: (0, rewriteRequestUrl_1.getRewriteRequestUrl)(projectRoot),
port: Number(env_1.env.RCT_METRO_PORT) || 8081,
// NOTE(EvanBacon): Moves the server root down to the monorepo root.
// This enables proper monorepo support for web.
unstable_serverRoot: serverRoot,
},
symbolicator: {
customizeFrame: (0, customizeFrame_1.getDefaultCustomizeFrame)(),
},
transformerPath: require.resolve('./transform-worker/transform-worker'),
transformer: {
// Custom: These are passed to `getCacheKey` and ensure invalidation when the version changes.
// @ts-expect-error: not on type.
unstable_renameRequire: false,
postcssHash: (0, postcss_1.getPostcssConfigHash)(projectRoot),
browserslistHash: pkg.browserslist
? (0, metro_cache_1.stableHash)(JSON.stringify(pkg.browserslist)).toString('hex')
: null,
sassVersion,
// Ensure invalidation when the version changes due to the Babel plugin.
reanimatedVersion,
// Ensure invalidation when using identical projects in monorepos
_expoRelativeProjectRoot: path_1.default.relative(serverRoot, projectRoot),
// `require.context` support
unstable_allowRequireContext: true,
allowOptionalDependencies: true,
babelTransformerPath: require.resolve('./babel-transformer'),
// See: https://github.com/facebook/react-native/blob/v0.73.0/packages/metro-config/index.js#L72-L74
asyncRequireModulePath: (0, resolve_from_1.default)(reactNativePath, metroDefaultValues.transformer.asyncRequireModulePath),
assetRegistryPath: '@react-native/assets-registry/registry',
assetPlugins: getAssetPlugins(projectRoot),
getTransformOptions: async () => ({
transform: {
experimentalImportSupport: false,
inlineRequires: false,
},
}),
},
});
return (0, withExpoSerializers_1.withExpoSerializers)(metroConfig, { unstable_beforeAssetSerializationPlugins });
}
exports.getDefaultConfig = getDefaultConfig;
// re-export for legacy cases.
exports.EXPO_DEBUG = env_1.env.EXPO_DEBUG;
function getPkgVersion(projectRoot, pkgName) {
const targetPkg = resolve_from_1.default.silent(projectRoot, pkgName);
if (!targetPkg)
return null;
const targetPkgJson = findUpPackageJson(targetPkg);
if (!targetPkgJson)
return null;
const pkg = json_file_1.default.read(targetPkgJson);
debug(`${pkgName} package.json:`, targetPkgJson);
const pkgVersion = pkg.version;
if (typeof pkgVersion === 'string') {
return pkgVersion;
}
return null;
}
function findUpPackageJson(cwd) {
if (['.', path_1.default.sep].includes(cwd))
return null;
const found = resolve_from_1.default.silent(cwd, './package.json');
if (found) {
return found;
}
return findUpPackageJson(path_1.default.dirname(cwd));
}
//# sourceMappingURL=ExpoMetroConfig.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
export { type PluginItem, type TransformOptions, transformFromAstSync, transformSync, } from '@babel/core';

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformSync = exports.transformFromAstSync = void 0;
// re-exported because babel/core is hard to mock.
var core_1 = require("@babel/core");
Object.defineProperty(exports, "transformFromAstSync", { enumerable: true, get: function () { return core_1.transformFromAstSync; } });
Object.defineProperty(exports, "transformSync", { enumerable: true, get: function () { return core_1.transformSync; } });
//# sourceMappingURL=babel-core.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"babel-core.js","sourceRoot":"","sources":["../src/babel-core.ts"],"names":[],"mappings":";;;AAAA,kDAAkD;AAClD,oCAKqB;AAFnB,4GAAA,oBAAoB,OAAA;AACpB,qGAAA,aAAa,OAAA"}

View File

@@ -0,0 +1,17 @@
import type { TransformOptions } from './babel-core';
export type ExpoBabelCaller = TransformOptions['caller'] & {
supportsReactCompiler?: boolean;
isReactServer?: boolean;
isHMREnabled?: boolean;
isServer?: boolean;
isNodeModule?: boolean;
preserveEnvVars?: boolean;
isDev?: boolean;
asyncRoutes?: boolean;
baseUrl?: string;
engine?: string;
bundler?: 'metro' | (string & object);
platform?: string | null;
routerRoot?: string;
projectRoot: string;
};

View File

@@ -0,0 +1,135 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const node_assert_1 = __importDefault(require("node:assert"));
const loadBabelConfig_1 = require("./loadBabelConfig");
const transformSync_1 = require("./transformSync");
const debug = require('debug')('expo:metro-config:babel-transformer');
function isCustomTruthy(value) {
return value === true || value === 'true';
}
function memoize(fn) {
const cache = new Map();
return ((...args) => {
const key = JSON.stringify(args);
if (cache.has(key)) {
return cache.get(key);
}
const result = fn(...args);
cache.set(key, result);
return result;
});
}
const memoizeWarning = memoize((message) => {
debug(message);
});
function getBabelCaller({ filename, options, }) {
const isNodeModule = filename.includes('node_modules');
const isReactServer = options.customTransformOptions?.environment === 'react-server';
const isGenericServer = options.customTransformOptions?.environment === 'node';
const isServer = isReactServer || isGenericServer;
const routerRoot = typeof options.customTransformOptions?.routerRoot === 'string'
? decodeURI(options.customTransformOptions.routerRoot)
: undefined;
if (routerRoot == null) {
memoizeWarning('Warning: Missing transform.routerRoot option in Metro bundling request, falling back to `app` as routes directory. This can occur if you bundle without Expo CLI or expo/metro-config.');
}
return {
name: 'metro',
bundler: 'metro',
platform: options.platform,
// Empower the babel preset to know the env it's bundling for.
// Metro automatically updates the cache to account for the custom transform options.
isServer,
// Enable React Server Component rules for AST.
isReactServer,
// The base url to make requests from, used for hosting from non-standard locations.
baseUrl: typeof options.customTransformOptions?.baseUrl === 'string'
? decodeURI(options.customTransformOptions.baseUrl)
: '',
// Ensure we always use a mostly-valid router root.
routerRoot: routerRoot ?? 'app',
isDev: options.dev,
// This value indicates if the user has disabled the feature or not.
// Other criteria may still cause the feature to be disabled, but all inputs used are
// already considered in the cache key.
preserveEnvVars: isCustomTruthy(options.customTransformOptions?.preserveEnvVars)
? true
: undefined,
asyncRoutes: isCustomTruthy(options.customTransformOptions?.asyncRoutes) ? true : undefined,
// Pass the engine to babel so we can automatically transpile for the correct
// target environment.
engine: stringOrUndefined(options.customTransformOptions?.engine),
// Provide the project root for accurately reading the Expo config.
projectRoot: options.projectRoot,
isNodeModule,
isHMREnabled: options.hot,
// Set the standard Babel flag to disable ESM transformations.
supportsStaticESM: options.experimentalImportSupport,
// Enable React compiler support in Babel.
// TODO: Remove this in the future when compiler is on by default.
supportsReactCompiler: isCustomTruthy(options.customTransformOptions?.reactCompiler)
? true
: undefined,
};
}
function stringOrUndefined(value) {
return typeof value === 'string' ? value : undefined;
}
const transform = ({ filename, src, options,
// `plugins` is used for `functionMapBabelPlugin` from `metro-source-map`. Could make sense to move this to `babel-preset-expo` too.
plugins, }) => {
const OLD_BABEL_ENV = process.env.BABEL_ENV;
process.env.BABEL_ENV = options.dev ? 'development' : process.env.BABEL_ENV || 'production';
try {
const babelConfig = {
// ES modules require sourceType='module' but OSS may not always want that
sourceType: 'unambiguous',
// The output we want from Babel methods
ast: true,
code: false,
// NOTE(EvanBacon): We split the parse/transform steps up to accommodate
// Hermes parsing, but this defaults to cloning the AST which increases
// the transformation time by a fair amount.
// You get this behavior by default when using Babel's `transform` method directly.
cloneInputAst: false,
// Options for debugging
cwd: options.projectRoot,
filename,
highlightCode: true,
// Load the project babel config file.
...(0, loadBabelConfig_1.loadBabelConfig)(options),
babelrc: typeof options.enableBabelRCLookup === 'boolean' ? options.enableBabelRCLookup : true,
plugins,
// NOTE(EvanBacon): We heavily leverage the caller functionality to mutate the babel config.
// This compensates for the lack of a format plugin system in Metro. Users can modify the
// all (most) of the transforms in their local Babel config.
// This also helps us keep the transform layers small and focused on a single task. We can also use this to
// ensure the Babel config caching is more accurate.
// Additionally, by moving everything Babel-related to the Babel preset, it makes it easier for users to reason
// about the requirements of an Expo project, making it easier to migrate to other transpilers in the future.
caller: getBabelCaller({ filename, options }),
};
const result = (0, transformSync_1.transformSync)(src, babelConfig, options);
// The result from `transformFromAstSync` can be null (if the file is ignored)
if (!result) {
// BabelTransformer specifies that the `ast` can never be null but
// the function returns here. Discovered when typing `BabelNode`.
return { ast: null };
}
(0, node_assert_1.default)(result.ast);
return { ast: result.ast, metadata: result.metadata };
}
finally {
if (OLD_BABEL_ENV) {
process.env.BABEL_ENV = OLD_BABEL_ENV;
}
}
};
const babelTransformer = {
transform,
};
module.exports = babelTransformer;
//# sourceMappingURL=babel-transformer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"babel-transformer.js","sourceRoot":"","sources":["../src/babel-transformer.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,10 @@
import { SymbolicatorConfigT } from 'metro-config';
type CustomizeFrameFunc = SymbolicatorConfigT['customizeFrame'];
export declare const INTERNAL_CALLSITES_REGEX: RegExp;
/**
* The default frame processor. This is used to modify the stack traces.
* This method attempts to collapse all frames that aren't relevant to
* the user by default.
*/
export declare function getDefaultCustomizeFrame(): CustomizeFrameFunc;
export {};

View File

@@ -0,0 +1,97 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDefaultCustomizeFrame = exports.INTERNAL_CALLSITES_REGEX = void 0;
const url_1 = require("url");
// Import only the types here, the values will be imported from the project, at runtime.
exports.INTERNAL_CALLSITES_REGEX = new RegExp([
'/Libraries/Renderer/implementations/.+\\.js$',
'/Libraries/BatchedBridge/MessageQueue\\.js$',
'/Libraries/YellowBox/.+\\.js$',
'/Libraries/LogBox/.+\\.js$',
'/Libraries/Core/Timers/.+\\.js$',
'node_modules/react-devtools-core/.+\\.js$',
'node_modules/react-refresh/.+\\.js$',
'node_modules/scheduler/.+\\.js$',
// Metro replaces `require()` with a different method,
// we want to omit this method from the stack trace.
// This is akin to most React tooling.
'/metro/.*/polyfills/require.js$',
// Hide frames related to a fast refresh.
'/metro/.*/lib/bundle-modules/.+\\.js$',
'node_modules/react-native/Libraries/Utilities/HMRClient.js$',
'node_modules/eventemitter3/index.js',
'node_modules/event-target-shim/dist/.+\\.js$',
// Improve errors thrown by invariant (ex: `Invariant Violation: "main" has not been registered`).
'node_modules/invariant/.+\\.js$',
// Remove babel runtime additions
'node_modules/regenerator-runtime/.+\\.js$',
// Remove react native setImmediate ponyfill
'node_modules/promise/setimmediate/.+\\.js$',
// Babel helpers that implement language features
'node_modules/@babel/runtime/.+\\.js$',
// Hide Hermes internal bytecode
'/InternalBytecode/InternalBytecode\\.js$',
// Block native code invocations
`\\[native code\\]`,
// Hide react-dom (web)
'node_modules/react-dom/.+\\.js$',
// Hide node.js evaluation code
'node_modules/require-from-string/.+\\.js$',
// Block expo's metro-runtime
'@expo/metro-runtime/.+\\.ts',
// Block upstream metro-runtime
'/metro-runtime/.+\\.js$',
// Block all whatwg polyfills
'node_modules/whatwg-.+\\.js$',
// Hide expo-router warnings which are often wrapping all routes and imports.
'node_modules/expo-router/build/',
// No Expo CLI logs
'/@expo/cli/.+',
// No context modules as these are virtual
'.+?ctx=[a-zA-Z0-9]+$',
// Hide react-native-web warning wrappers. These are most likely related to style deprecations.
'/react-native-web/dist/.+\\.js$',
].join('|'));
function isUrl(value) {
try {
// eslint-disable-next-line no-new
new url_1.URL(value);
return true;
}
catch {
return false;
}
}
/**
* The default frame processor. This is used to modify the stack traces.
* This method attempts to collapse all frames that aren't relevant to
* the user by default.
*/
function getDefaultCustomizeFrame() {
return (frame) => {
if (frame.file && isUrl(frame.file)) {
return {
...frame,
// HACK: This prevents Metro from attempting to read the invalid file URL it sent us.
lineNumber: null,
column: null,
// This prevents the invalid frame from being shown by default.
collapse: true,
};
}
let collapse = Boolean(frame.file && exports.INTERNAL_CALLSITES_REGEX.test(frame.file));
if (!collapse) {
// This represents the first frame of the stacktrace.
// Often this looks like: `__r(0);`.
// The URL will also be unactionable in the app and therefore not very useful to the developer.
if (frame.column === 3 &&
frame.methodName === 'global code' &&
frame.file?.match(/^https?:\/\//g)) {
collapse = true;
}
}
return { ...(frame || {}), collapse };
};
}
exports.getDefaultCustomizeFrame = getDefaultCustomizeFrame;
//# sourceMappingURL=customizeFrame.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"customizeFrame.js","sourceRoot":"","sources":["../src/customizeFrame.ts"],"names":[],"mappings":";;;AAEA,6BAA0B;AAI1B,wFAAwF;AAC3E,QAAA,wBAAwB,GAAG,IAAI,MAAM,CAChD;IACE,8CAA8C;IAC9C,6CAA6C;IAC7C,+BAA+B;IAC/B,4BAA4B;IAC5B,iCAAiC;IACjC,2CAA2C;IAC3C,qCAAqC;IACrC,iCAAiC;IACjC,sDAAsD;IACtD,oDAAoD;IACpD,sCAAsC;IACtC,iCAAiC;IACjC,yCAAyC;IACzC,uCAAuC;IACvC,6DAA6D;IAC7D,qCAAqC;IACrC,8CAA8C;IAC9C,kGAAkG;IAClG,iCAAiC;IACjC,iCAAiC;IACjC,2CAA2C;IAC3C,4CAA4C;IAC5C,4CAA4C;IAC5C,iDAAiD;IACjD,sCAAsC;IACtC,gCAAgC;IAChC,0CAA0C;IAC1C,gCAAgC;IAChC,mBAAmB;IACnB,uBAAuB;IACvB,iCAAiC;IACjC,+BAA+B;IAC/B,2CAA2C;IAC3C,6BAA6B;IAC7B,6BAA6B;IAC7B,+BAA+B;IAC/B,yBAAyB;IAEzB,6BAA6B;IAC7B,8BAA8B;IAC9B,6EAA6E;IAC7E,iCAAiC;IACjC,mBAAmB;IACnB,eAAe;IACf,0CAA0C;IAC1C,sBAAsB;IACtB,+FAA+F;IAC/F,iCAAiC;CAClC,CAAC,IAAI,CAAC,GAAG,CAAC,CACZ,CAAC;AAEF,SAAS,KAAK,CAAC,KAAa;IAC1B,IAAI;QACF,kCAAkC;QAClC,IAAI,SAAG,CAAC,KAAK,CAAC,CAAC;QACf,OAAO,IAAI,CAAC;KACb;IAAC,MAAM;QACN,OAAO,KAAK,CAAC;KACd;AACH,CAAC;AAED;;;;GAIG;AACH,SAAgB,wBAAwB;IACtC,OAAO,CAAC,KAAwC,EAAE,EAAE;QAClD,IAAI,KAAK,CAAC,IAAI,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE;YACnC,OAAO;gBACL,GAAG,KAAK;gBACR,qFAAqF;gBACrF,UAAU,EAAE,IAAI;gBAChB,MAAM,EAAE,IAAI;gBACZ,+DAA+D;gBAC/D,QAAQ,EAAE,IAAI;aACf,CAAC;SACH;QACD,IAAI,QAAQ,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,IAAI,gCAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;QAEhF,IAAI,CAAC,QAAQ,EAAE;YACb,qDAAqD;YACrD,oCAAoC;YACpC,+FAA+F;YAC/F,IACE,KAAK,CAAC,MAAM,KAAK,CAAC;gBAClB,KAAK,CAAC,UAAU,KAAK,aAAa;gBAClC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,eAAe,CAAC,EAClC;gBACA,QAAQ,GAAG,IAAI,CAAC;aACjB;SACF;QAED,OAAO,EAAE,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC;AA7BD,4DA6BC"}

View File

@@ -0,0 +1,14 @@
declare class Env {
/** Enable debug logging */
get EXPO_DEBUG(): boolean;
/** Enable the experimental "exotic" mode. [Learn more](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1). */
get EXPO_USE_EXOTIC(): boolean;
/** The React Metro port that's baked into react-native scripts and tools. */
get RCT_METRO_PORT(): number;
/** Enable auto server root detection for Metro. This will change the server root to the workspace root. */
get EXPO_USE_METRO_WORKSPACE_ROOT(): boolean;
/** Disable Environment Variable injection in client bundles. */
get EXPO_NO_CLIENT_ENV_VARS(): boolean;
}
export declare const env: Env;
export {};

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.env = void 0;
const getenv_1 = require("getenv");
class Env {
/** Enable debug logging */
get EXPO_DEBUG() {
return (0, getenv_1.boolish)('EXPO_DEBUG', false);
}
/** Enable the experimental "exotic" mode. [Learn more](https://blog.expo.dev/drastically-faster-bundling-in-react-native-a54f268e0ed1). */
get EXPO_USE_EXOTIC() {
return (0, getenv_1.boolish)('EXPO_USE_EXOTIC', false);
}
/** The React Metro port that's baked into react-native scripts and tools. */
get RCT_METRO_PORT() {
return (0, getenv_1.int)('RCT_METRO_PORT', 8081);
}
/** Enable auto server root detection for Metro. This will change the server root to the workspace root. */
get EXPO_USE_METRO_WORKSPACE_ROOT() {
return (0, getenv_1.boolish)('EXPO_USE_METRO_WORKSPACE_ROOT', false);
}
/** Disable Environment Variable injection in client bundles. */
get EXPO_NO_CLIENT_ENV_VARS() {
return (0, getenv_1.boolish)('EXPO_NO_CLIENT_ENV_VARS', false);
}
}
exports.env = new Env();
//# sourceMappingURL=env.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"env.js","sourceRoot":"","sources":["../src/env.ts"],"names":[],"mappings":";;;AAAA,mCAAsC;AAEtC,MAAM,GAAG;IACP,2BAA2B;IAC3B,IAAI,UAAU;QACZ,OAAO,IAAA,gBAAO,EAAC,YAAY,EAAE,KAAK,CAAC,CAAC;IACtC,CAAC;IAED,2IAA2I;IAC3I,IAAI,eAAe;QACjB,OAAO,IAAA,gBAAO,EAAC,iBAAiB,EAAE,KAAK,CAAC,CAAC;IAC3C,CAAC;IAED,6EAA6E;IAC7E,IAAI,cAAc;QAChB,OAAO,IAAA,YAAG,EAAC,gBAAgB,EAAE,IAAI,CAAC,CAAC;IACrC,CAAC;IAED,2GAA2G;IAC3G,IAAI,6BAA6B;QAC/B,OAAO,IAAA,gBAAO,EAAC,+BAA+B,EAAE,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,gEAAgE;IAChE,IAAI,uBAAuB;QACzB,OAAO,IAAA,gBAAO,EAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;IACnD,CAAC;CACF;AAEY,QAAA,GAAG,GAAG,IAAI,GAAG,EAAE,CAAC"}

View File

@@ -0,0 +1,5 @@
/// <reference types="node" />
import UpstreamFileStore from 'metro-cache/src/stores/FileStore';
export declare class FileStore<T> extends UpstreamFileStore<T> {
set(key: Buffer, value: any): Promise<void>;
}

View File

@@ -0,0 +1,20 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileStore = void 0;
const FileStore_1 = __importDefault(require("metro-cache/src/stores/FileStore"));
const debug = require('debug')('expo:metro:cache');
class FileStore extends FileStore_1.default {
async set(key, value) {
// Prevent caching of CSS files that have the skipCache flag set.
if (value?.output?.[0]?.data?.css?.skipCache) {
debug('Skipping caching for CSS file:', value.path);
return;
}
return await super.set(key, value);
}
}
exports.FileStore = FileStore;
//# sourceMappingURL=file-store.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"file-store.js","sourceRoot":"","sources":["../src/file-store.ts"],"names":[],"mappings":";;;;;;AAAA,iFAAiE;AAEjE,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC,kBAAkB,CAAuB,CAAC;AAEzE,MAAa,SAAa,SAAQ,mBAAoB;IACpD,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAU;QAC/B,iEAAiE;QACjE,IAAI,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,GAAG,EAAE,SAAS,EAAE;YAC5C,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;YACpD,OAAO;SACR;QACD,OAAO,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IACrC,CAAC;CACF;AATD,8BASC"}

View File

@@ -0,0 +1,4 @@
/** Wraps `findWorkspaceRoot` and guards against having an empty `package.json` file in an upper directory. */
export declare function getWorkspaceRoot(projectRoot: string): string | null;
export declare function getModulesPaths(projectRoot: string): string[];
export declare function getServerRoot(projectRoot: string): string;

View File

@@ -0,0 +1,41 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getServerRoot = exports.getModulesPaths = exports.getWorkspaceRoot = void 0;
const find_yarn_workspace_root_1 = __importDefault(require("find-yarn-workspace-root"));
const path_1 = __importDefault(require("path"));
const env_1 = require("./env");
/** Wraps `findWorkspaceRoot` and guards against having an empty `package.json` file in an upper directory. */
function getWorkspaceRoot(projectRoot) {
try {
return (0, find_yarn_workspace_root_1.default)(projectRoot);
}
catch (error) {
if (error.message.includes('Unexpected end of JSON input')) {
return null;
}
throw error;
}
}
exports.getWorkspaceRoot = getWorkspaceRoot;
function getModulesPaths(projectRoot) {
const paths = [];
// Only add the project root if it's not the current working directory
// this minimizes the chance of Metro resolver breaking on new Node.js versions.
const workspaceRoot = getWorkspaceRoot(path_1.default.resolve(projectRoot)); // Absolute path or null
if (workspaceRoot) {
paths.push(path_1.default.resolve(projectRoot, 'node_modules'));
paths.push(path_1.default.resolve(workspaceRoot, 'node_modules'));
}
return paths;
}
exports.getModulesPaths = getModulesPaths;
function getServerRoot(projectRoot) {
return env_1.env.EXPO_USE_METRO_WORKSPACE_ROOT
? getWorkspaceRoot(projectRoot) ?? projectRoot
: projectRoot;
}
exports.getServerRoot = getServerRoot;
//# sourceMappingURL=getModulesPaths.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getModulesPaths.js","sourceRoot":"","sources":["../src/getModulesPaths.ts"],"names":[],"mappings":";;;;;;AAAA,wFAAyD;AACzD,gDAAwB;AAExB,+BAA4B;AAE5B,8GAA8G;AAC9G,SAAgB,gBAAgB,CAAC,WAAmB;IAClD,IAAI;QACF,OAAO,IAAA,kCAAiB,EAAC,WAAW,CAAC,CAAC;KACvC;IAAC,OAAO,KAAU,EAAE;QACnB,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAAE;YAC1D,OAAO,IAAI,CAAC;SACb;QACD,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AATD,4CASC;AAED,SAAgB,eAAe,CAAC,WAAmB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,sEAAsE;IACtE,gFAAgF;IAChF,MAAM,aAAa,GAAG,gBAAgB,CAAC,cAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,wBAAwB;IAC3F,IAAI,aAAa,EAAE;QACjB,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC;QACtD,KAAK,CAAC,IAAI,CAAC,cAAI,CAAC,OAAO,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC,CAAC;KACzD;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAZD,0CAYC;AAED,SAAgB,aAAa,CAAC,WAAmB;IAC/C,OAAO,SAAG,CAAC,6BAA6B;QACtC,CAAC,CAAC,gBAAgB,CAAC,WAAW,CAAC,IAAI,WAAW;QAC9C,CAAC,CAAC,WAAW,CAAC;AAClB,CAAC;AAJD,sCAIC"}

View File

@@ -0,0 +1,16 @@
/**
* @param workspaceProjectRoot Root file path for the yarn workspace
* @param linkedPackages List of folders that contain linked node modules, ex: `['packages/*', 'apps/*']`
* @returns List of valid package.json file paths, ex: `['/Users/me/app/apps/my-app/package.json', '/Users/me/app/packages/my-package/package.json']`
*/
export declare function globAllPackageJsonPaths(workspaceProjectRoot: string, linkedPackages: string[]): string[];
/**
* @param workspaceProjectRoot root file path for a yarn workspace.
* @returns list of package.json file paths that are linked to the yarn workspace.
*/
export declare function resolveAllWorkspacePackageJsonPaths(workspaceProjectRoot: string): string[];
/**
* @param projectRoot file path to app's project root
* @returns list of node module paths to watch in Metro bundler, ex: `['/Users/me/app/node_modules/', '/Users/me/app/apps/my-app/', '/Users/me/app/packages/my-package/']`
*/
export declare function getWatchFolders(projectRoot: string): string[];

View File

@@ -0,0 +1,98 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getWatchFolders = exports.resolveAllWorkspacePackageJsonPaths = exports.globAllPackageJsonPaths = void 0;
const assert_1 = __importDefault(require("assert"));
const fs_1 = __importDefault(require("fs"));
const glob_1 = require("glob");
const path_1 = __importDefault(require("path"));
const getModulesPaths_1 = require("./getModulesPaths");
function readJsonFile(filePath) {
// Read with fs
const file = fs_1.default.readFileSync(filePath, 'utf8');
// Parse with JSON.parse
return JSON.parse(file);
}
function isValidJsonFile(filePath) {
try {
// Throws if invalid or unable to read.
readJsonFile(filePath);
return true;
}
catch {
return false;
}
}
/**
* @param workspaceProjectRoot Root file path for the yarn workspace
* @param linkedPackages List of folders that contain linked node modules, ex: `['packages/*', 'apps/*']`
* @returns List of valid package.json file paths, ex: `['/Users/me/app/apps/my-app/package.json', '/Users/me/app/packages/my-package/package.json']`
*/
function globAllPackageJsonPaths(workspaceProjectRoot, linkedPackages) {
return linkedPackages
.map((glob) => {
return (0, glob_1.sync)(path_1.default.join(glob, 'package.json').replace(/\\/g, '/'), {
cwd: workspaceProjectRoot,
absolute: true,
ignore: ['**/@(Carthage|Pods|node_modules)/**'],
}).map((pkgPath) => {
return isValidJsonFile(pkgPath) ? pkgPath : null;
});
})
.flat()
.filter(Boolean)
.map((p) => path_1.default.join(p));
}
exports.globAllPackageJsonPaths = globAllPackageJsonPaths;
function getWorkspacePackagesArray({ workspaces }) {
if (Array.isArray(workspaces)) {
return workspaces;
}
(0, assert_1.default)(workspaces?.packages, 'Could not find a `workspaces` object in the root package.json');
return workspaces.packages;
}
/**
* @param workspaceProjectRoot root file path for a yarn workspace.
* @returns list of package.json file paths that are linked to the yarn workspace.
*/
function resolveAllWorkspacePackageJsonPaths(workspaceProjectRoot) {
try {
const rootPackageJsonFilePath = path_1.default.join(workspaceProjectRoot, 'package.json');
// Could throw if package.json is invalid.
const rootPackageJson = readJsonFile(rootPackageJsonFilePath);
// Extract the "packages" array or use "workspaces" as packages array (yarn workspaces spec).
const packages = getWorkspacePackagesArray(rootPackageJson);
// Glob all package.json files and return valid paths.
return globAllPackageJsonPaths(workspaceProjectRoot, packages);
}
catch {
return [];
}
}
exports.resolveAllWorkspacePackageJsonPaths = resolveAllWorkspacePackageJsonPaths;
/**
* @param projectRoot file path to app's project root
* @returns list of node module paths to watch in Metro bundler, ex: `['/Users/me/app/node_modules/', '/Users/me/app/apps/my-app/', '/Users/me/app/packages/my-package/']`
*/
function getWatchFolders(projectRoot) {
const workspaceRoot = (0, getModulesPaths_1.getWorkspaceRoot)(path_1.default.resolve(projectRoot));
// Rely on default behavior in standard projects.
if (!workspaceRoot) {
return [];
}
const packages = resolveAllWorkspacePackageJsonPaths(workspaceRoot);
if (!packages.length) {
return [];
}
return uniqueItems([
path_1.default.join(workspaceRoot, 'node_modules'),
...packages.map((pkg) => path_1.default.dirname(pkg)),
]);
}
exports.getWatchFolders = getWatchFolders;
function uniqueItems(items) {
return [...new Set(items)];
}
//# sourceMappingURL=getWatchFolders.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getWatchFolders.js","sourceRoot":"","sources":["../src/getWatchFolders.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,9 @@
import type { TransformOptions } from './babel-core';
/**
* Returns a memoized function that checks for the existence of a
* project-level .babelrc file. If it doesn't exist, it reads the
* default React Native babelrc file and uses that.
*/
export declare const loadBabelConfig: ({ projectRoot }: {
projectRoot: string;
}) => Pick<TransformOptions, "extends" | "presets">;

View File

@@ -0,0 +1,45 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadBabelConfig = void 0;
/**
* Copyright (c) 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
/**
* Returns a memoized function that checks for the existence of a
* project-level .babelrc file. If it doesn't exist, it reads the
* default React Native babelrc file and uses that.
*/
exports.loadBabelConfig = (function () {
let babelRC = null;
return function _getBabelRC({ projectRoot }) {
if (babelRC !== null) {
return babelRC;
}
babelRC = {};
if (projectRoot) {
// Check for various babel config files in the project root
// TODO(EvanBacon): We might want to disable babelrc lookup when the user specifies `enableBabelRCLookup: false`.
const possibleBabelRCPaths = ['.babelrc', '.babelrc.js', 'babel.config.js'];
const foundBabelRCPath = possibleBabelRCPaths.find((configFileName) => node_fs_1.default.existsSync(node_path_1.default.resolve(projectRoot, configFileName)));
// Extend the config if a babel config file is found
if (foundBabelRCPath) {
babelRC.extends = node_path_1.default.resolve(projectRoot, foundBabelRCPath);
}
}
// Use the default preset for react-native if no babel config file is found
if (!babelRC.extends) {
babelRC.presets = [require('babel-preset-expo')];
}
return babelRC;
};
})();
//# sourceMappingURL=loadBabelConfig.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"loadBabelConfig.js","sourceRoot":"","sources":["../src/loadBabelConfig.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;GAMG;AACH,sDAAyB;AACzB,0DAA6B;AAI7B;;;;GAIG;AACU,QAAA,eAAe,GAAG,CAAC;IAC9B,IAAI,OAAO,GAAyD,IAAI,CAAC;IAEzE,OAAO,SAAS,WAAW,CAAC,EAAE,WAAW,EAA2B;QAClE,IAAI,OAAO,KAAK,IAAI,EAAE;YACpB,OAAO,OAAO,CAAC;SAChB;QAED,OAAO,GAAG,EAAE,CAAC;QAEb,IAAI,WAAW,EAAE;YACf,2DAA2D;YAC3D,iHAAiH;YACjH,MAAM,oBAAoB,GAAG,CAAC,UAAU,EAAE,aAAa,EAAE,iBAAiB,CAAC,CAAC;YAE5E,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,IAAI,CAAC,CAAC,cAAc,EAAE,EAAE,CACpE,iBAAE,CAAC,UAAU,CAAC,mBAAI,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC,CACzD,CAAC;YAEF,oDAAoD;YACpD,IAAI,gBAAgB,EAAE;gBACpB,OAAO,CAAC,OAAO,GAAG,mBAAI,CAAC,OAAO,CAAC,WAAW,EAAE,gBAAgB,CAAC,CAAC;aAC/D;SACF;QAED,2EAA2E;QAC3E,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;YACpB,OAAO,CAAC,OAAO,GAAG,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,CAAC;SAClD;QAED,OAAO,OAAO,CAAC;IACjB,CAAC,CAAC;AACJ,CAAC,CAAC,EAAE,CAAC"}

View File

@@ -0,0 +1,2 @@
export declare function getRouterDirectory(projectRoot: string): string;
export declare function getRewriteRequestUrl(projectRoot: string): (url: string) => string;

View File

@@ -0,0 +1,102 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getRewriteRequestUrl = exports.getRouterDirectory = void 0;
// Copyright 2023-present 650 Industries (Expo). All rights reserved.
const config_1 = require("@expo/config");
const paths_1 = require("@expo/config/paths");
const chalk_1 = __importDefault(require("chalk"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const getModulesPaths_1 = require("./getModulesPaths");
const debug = require('debug')('expo:metro:config:rewriteRequestUrl');
function directoryExistsSync(file) {
try {
return fs_1.default.statSync(file)?.isDirectory() ?? false;
}
catch {
return false;
}
}
function isEnableHermesManaged(expoConfig, platform) {
switch (platform) {
case 'android': {
return (expoConfig.android?.jsEngine ?? expoConfig.jsEngine) !== 'jsc';
}
case 'ios': {
return (expoConfig.ios?.jsEngine ?? expoConfig.jsEngine) !== 'jsc';
}
default:
return false;
}
}
function getRouterDirectoryModuleIdWithManifest(projectRoot, exp) {
return exp.extra?.router?.root ?? getRouterDirectory(projectRoot);
}
function getRouterDirectory(projectRoot) {
// more specific directories first
if (directoryExistsSync(path_1.default.join(projectRoot, 'src/app'))) {
debug('Using src/app as the root directory for Expo Router.');
return 'src/app';
}
debug('Using app as the root directory for Expo Router.');
return 'app';
}
exports.getRouterDirectory = getRouterDirectory;
function getRewriteRequestUrl(projectRoot) {
function rewriteExpoRequestUrl(url) {
// Like: `/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
// Sometimes a fully qualified URL is passed in, e.g. `http://localhost:19001/.expo/.virtual-metro-entry.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
if (url.includes('/.expo/.virtual-metro-entry.bundle?')) {
const { pkg, exp } = (0, config_1.getConfig)(projectRoot, { skipSDKVersionRequirement: true });
const ensured = url.startsWith('/') ? new URL(url, 'https://acme.dev') : new URL(url);
// TODO: Maybe this function could be memoized in some capacity?
const { searchParams } = ensured;
const platform = searchParams.get('platform') ?? 'web';
debug('Rewriting magic request url to entry point', { url, platform });
const entry = (0, paths_1.resolveEntryPoint)(projectRoot, {
platform,
pkg,
});
if (!entry) {
throw new Error((0, chalk_1.default) `The project entry file could not be resolved (platform: ${platform}, root: ${projectRoot}). Define it in the {bold package.json} "main" field.`);
}
// Infer the missing transform properties to attempt to match the manifest request.
// NOTE: Keep in sync with metroOptions.ts
if (!ensured.searchParams.has('transform.routerRoot')) {
ensured.searchParams.set('transform.routerRoot', getRouterDirectoryModuleIdWithManifest(projectRoot, exp));
}
if (!ensured.searchParams.has('transform.reactCompiler') && exp.experiments?.reactCompiler) {
ensured.searchParams.set('transform.reactCompiler', String(!!exp.experiments?.reactCompiler));
}
if (!ensured.searchParams.has('transform.engine')) {
const isHermesEnabled = isEnableHermesManaged(exp, platform);
if (isHermesEnabled) {
debug('Enabling Hermes for managed project');
ensured.searchParams.set('transform.engine', 'hermes');
ensured.searchParams.set('transform.bytecode', 'true');
}
}
const serverRoot = (0, getModulesPaths_1.getServerRoot)(projectRoot);
const relativeEntry = path_1.default.relative(serverRoot, entry).replace(/\.[tj]sx?$/, '');
debug('Resolved entry point', { entry, relativeEntry, serverRoot });
// Only return the pathname when url is relative
if (url.startsWith('/')) {
// Like: `/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
return '/' + relativeEntry + '.bundle?' + searchParams.toString();
}
// Modify the pathname within the URL and return the full URL
ensured.pathname = '/' + relativeEntry + '.bundle';
const outputUrl = ensured.toString();
debug('Redirected:', outputUrl);
// Like: `http://localhost:19001/index.bundle?platform=ios&dev=true&minify=false&modulesOnly=false&runModule=true&app=com.bacon.test-custom-entry`
return outputUrl;
}
return url;
}
return rewriteExpoRequestUrl;
}
exports.getRewriteRequestUrl = getRewriteRequestUrl;
//# sourceMappingURL=rewriteRequestUrl.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"rewriteRequestUrl.js","sourceRoot":"","sources":["../src/rewriteRequestUrl.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,12 @@
/**
* Copyright © 2023 650 Industries.
* Copyright (c) 2022, Sentry.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Deterministically hashes a string and turns the hash into a uuid.
* https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/58271f1af2ade6b3e64d393d70376ae53bc5bd2f/packages/bundler-plugin-core/src/utils.ts#L174
*/
export declare function stringToUUID(str: string): string;

View File

@@ -0,0 +1,38 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.stringToUUID = void 0;
const node_crypto_1 = __importDefault(require("node:crypto"));
/**
* Copyright © 2023 650 Industries.
* Copyright (c) 2022, Sentry.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* Deterministically hashes a string and turns the hash into a uuid.
* https://github.com/getsentry/sentry-javascript-bundler-plugins/blob/58271f1af2ade6b3e64d393d70376ae53bc5bd2f/packages/bundler-plugin-core/src/utils.ts#L174
*/
function stringToUUID(str) {
const md5sum = node_crypto_1.default.createHash('md5');
md5sum.update(str);
const md5Hash = md5sum.digest('hex');
// Position 16 is fixed to either 8, 9, a, or b in the uuid v4 spec (10xx in binary)
// RFC 4122 section 4.4
const v4variant = ['8', '9', 'a', 'b'][md5Hash.substring(16, 17).charCodeAt(0) % 4];
return (md5Hash.substring(0, 8) +
'-' +
md5Hash.substring(8, 12) +
'-4' +
md5Hash.substring(13, 16) +
'-' +
v4variant +
md5Hash.substring(17, 20) +
'-' +
md5Hash.substring(20)).toLowerCase();
}
exports.stringToUUID = stringToUUID;
//# sourceMappingURL=debugId.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"debugId.js","sourceRoot":"","sources":["../../src/serializer/debugId.ts"],"names":[],"mappings":";;;;;;AAAA,8DAAiC;AAEjC;;;;;;GAMG;AAEH;;;GAGG;AACH,SAAgB,YAAY,CAAC,GAAW;IACtC,MAAM,MAAM,GAAG,qBAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACxC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAErC,oFAAoF;IACpF,uBAAuB;IACvB,MAAM,SAAS,GAAG,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAW,CAAC;IAE9F,OAAO,CACL,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC;QACvB,GAAG;QACH,OAAO,CAAC,SAAS,CAAC,CAAC,EAAE,EAAE,CAAC;QACxB,IAAI;QACJ,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC;QACzB,GAAG;QACH,SAAS;QACT,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,CAAC;QACzB,GAAG;QACH,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CACtB,CAAC,WAAW,EAAE,CAAC;AAClB,CAAC;AArBD,oCAqBC"}

View File

@@ -0,0 +1,14 @@
/// <reference types="node" />
/**
* Copyright © 2022 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { ReadOnlyGraph, MixedOutput, Module, SerializerOptions } from 'metro';
import { SerializerParameters } from './withExpoSerializers';
export declare function getTransformEnvironment(url: string): string | null;
/** Strips the process.env polyfill in server environments to allow for accessing environment variables off the global. */
export declare function serverPreludeSerializerPlugin(entryPoint: string, preModules: readonly Module<MixedOutput>[], graph: ReadOnlyGraph, options: SerializerOptions): SerializerParameters;
export declare function environmentVariableSerializerPlugin(entryPoint: string, preModules: readonly Module<MixedOutput>[], graph: ReadOnlyGraph, options: SerializerOptions): SerializerParameters;
export declare function getEnvVarDevString(env?: NodeJS.ProcessEnv): string;

View File

@@ -0,0 +1,119 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getEnvVarDevString = exports.environmentVariableSerializerPlugin = exports.serverPreludeSerializerPlugin = exports.getTransformEnvironment = void 0;
const CountingSet_1 = __importDefault(require("metro/src/lib/CountingSet"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const debug = require('debug')('expo:metro-config:serializer:env-var');
function getTransformEnvironment(url) {
const match = url.match(/[&?]transform\.environment=([^&]+)/);
return match ? match[1] : null;
}
exports.getTransformEnvironment = getTransformEnvironment;
function getAllExpoPublicEnvVars(inputEnv = process.env) {
// Create an object containing all environment variables that start with EXPO_PUBLIC_
const env = {};
for (const key in inputEnv) {
if (key.startsWith('EXPO_PUBLIC_')) {
// @ts-expect-error: TS doesn't know that the key starts with EXPO_PUBLIC_
env[key] = inputEnv[key];
}
}
return env;
}
function isServerEnvironment(graph, options) {
// Requests from a dev server will use sourceUrl.
if (!graph.transformOptions.customTransformOptions) {
if (options.sourceUrl) {
const env = getTransformEnvironment(options.sourceUrl);
return env === 'node' || env === 'react-server';
}
return false;
}
// Other requests will use customTransformOptions.environment.
const env = graph.transformOptions.customTransformOptions.environment;
return env === 'node' || env === 'react-server';
}
/** Strips the process.env polyfill in server environments to allow for accessing environment variables off the global. */
function serverPreludeSerializerPlugin(entryPoint, preModules, graph, options) {
if (isServerEnvironment(graph, options)) {
const prelude = preModules.find((module) => module.path === '__prelude__');
if (prelude) {
debug('Stripping environment variable polyfill in server environment.');
prelude.output[0].data.code = prelude.output[0].data.code
.replace(/process=this\.process\|\|{},/, '')
.replace(/process\.env=process\.env\|\|{};process\.env\.NODE_ENV=process\.env\.NODE_ENV\|\|"\w+";/, '');
}
}
return [entryPoint, preModules, graph, options];
}
exports.serverPreludeSerializerPlugin = serverPreludeSerializerPlugin;
function environmentVariableSerializerPlugin(entryPoint, preModules, graph, options) {
// Skip replacement in Node.js environments.
if (isServerEnvironment(graph, options)) {
debug('Skipping environment variable inlining in Node.js environment.');
return [entryPoint, preModules, graph, options];
}
// In development, we need to add the process.env object to ensure it
// persists between Fast Refresh updates.
if (!options.dev) {
debug('Skipping environment variable inlining in production environment in favor of babel-preset-expo inlining with source maps.');
return [entryPoint, preModules, graph, options];
}
const code = getEnvVarDevString();
const prelude = preModules.find((module) => module.path === '\0polyfill:environment-variables');
if (prelude) {
debug('Injecting environment variables in virtual module.');
// !!MUST!! be one line in order to ensure Metro's asymmetric serializer system can handle it.
prelude.output[0].data.code = code;
return [entryPoint, preModules, graph, options];
}
// Old system which doesn't work very well since Metro doesn't serialize graphs the same way in all cases.
// e.g. the `.map` endpoint is serialized differently to error symbolication.
// Inject the new module at index 1
// @ts-expect-error: The preModules are mutable and we need to mutate them in order to ensure the changes are applied outside of the serializer.
preModules.splice(
// Inject at index 1 to ensure it runs after the prelude (which injects env vars).
1, 0, getEnvPrelude(code));
return [entryPoint, preModules, graph, options];
}
exports.environmentVariableSerializerPlugin = environmentVariableSerializerPlugin;
function getEnvVarDevString(env = process.env) {
// Set the process.env object to the current environment variables object
// ensuring they aren't iterable, settable, or enumerable.
const str = `process.env=Object.defineProperties(process.env, {` +
Object.keys(getAllExpoPublicEnvVars(env))
.map((key) => `${JSON.stringify(key)}: { value: ${JSON.stringify(env[key])} }`)
.join(',') +
'});';
const code = '/* HMR env vars from Expo CLI (dev-only) */ ' + str;
const lineCount = (0, countLines_1.default)(code);
if (lineCount !== 1) {
throw new Error(`Virtual environment variable code must be one line, got "${lineCount}" lines.`);
}
return code;
}
exports.getEnvVarDevString = getEnvVarDevString;
function getEnvPrelude(code) {
const name = `\0polyfill:environment-variables`;
return {
dependencies: new Map(),
getSource: () => Buffer.from(code),
inverseDependencies: new CountingSet_1.default(),
path: name,
output: [
{
type: 'js/script/virtual',
data: {
code,
// @ts-expect-error: typed incorrectly upstream
lineCount: 1,
map: [],
},
},
],
};
}
//# sourceMappingURL=environmentVariableSerializerPlugin.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"environmentVariableSerializerPlugin.js","sourceRoot":"","sources":["../../src/serializer/environmentVariableSerializerPlugin.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,12 @@
interface HermesBundleOutput {
hbc: Uint8Array;
sourcemap: string | null;
}
type BuildHermesOptions = {
filename: string;
code: string;
map: string | null;
minify?: boolean;
};
export declare function buildHermesBundleAsync(options: BuildHermesOptions): Promise<HermesBundleOutput>;
export {};

View File

@@ -0,0 +1,113 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildHermesBundleAsync = void 0;
const spawn_async_1 = __importDefault(require("@expo/spawn-async"));
const chalk_1 = __importDefault(require("chalk"));
const fs_extra_1 = __importDefault(require("fs-extra"));
const metro_source_map_1 = require("metro-source-map");
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const process_1 = __importDefault(require("process"));
const debug = require('debug')('expo:metro:hermes');
function importHermesCommandFromProject() {
const platformExecutable = getHermesCommandPlatform();
const hermescLocations = [
// Override hermesc dir by environment variables
process_1.default.env['REACT_NATIVE_OVERRIDE_HERMES_DIR']
? `${process_1.default.env['REACT_NATIVE_OVERRIDE_HERMES_DIR']}/build/bin/hermesc`
: '',
// Building hermes from source
'react-native/ReactAndroid/hermes-engine/build/hermes/bin/hermesc',
// Prebuilt hermesc in official react-native 0.69+
`react-native/sdks/hermesc/${platformExecutable}`,
// Legacy hermes-engine package
`hermes-engine/${platformExecutable}`,
];
for (const location of hermescLocations) {
try {
return require.resolve(location);
}
catch { }
}
throw new Error('Cannot find the hermesc executable.');
}
function getHermesCommandPlatform() {
switch (os_1.default.platform()) {
case 'darwin':
return 'osx-bin/hermesc';
case 'linux':
return 'linux64-bin/hermesc';
case 'win32':
return 'win64-bin/hermesc.exe';
default:
throw new Error(`Unsupported host platform for Hermes compiler: ${os_1.default.platform()}`);
}
}
// Only one hermes build at a time is supported.
let currentHermesBuild = null;
async function buildHermesBundleAsync(options) {
if (currentHermesBuild) {
debug(`Waiting for existing Hermes builds to finish`);
await currentHermesBuild;
}
currentHermesBuild = directlyBuildHermesBundleAsync(options);
return await currentHermesBuild;
}
exports.buildHermesBundleAsync = buildHermesBundleAsync;
async function directlyBuildHermesBundleAsync({ code, map, minify = false, filename, }) {
const tempDir = path_1.default.join(os_1.default.tmpdir(), `expo-bundler-${Math.random()}-${Date.now()}`);
await fs_extra_1.default.ensureDir(tempDir);
try {
const tempBundleFile = path_1.default.join(tempDir, 'index.js');
await fs_extra_1.default.writeFile(tempBundleFile, code);
if (map) {
const tempSourcemapFile = path_1.default.join(tempDir, 'index.js.map');
await fs_extra_1.default.writeFile(tempSourcemapFile, map);
}
const tempHbcFile = path_1.default.join(tempDir, 'index.hbc');
const hermesCommand = importHermesCommandFromProject();
const args = ['-emit-binary', '-out', tempHbcFile, tempBundleFile];
if (minify) {
args.push('-O');
}
if (map) {
args.push('-output-source-map');
}
debug(`Running hermesc: ${hermesCommand} ${args.join(' ')}`);
await (0, spawn_async_1.default)(hermesCommand, args);
let hbc;
let sourcemap = null;
if (!map) {
hbc = await fs_extra_1.default.readFile(tempHbcFile);
}
else {
[hbc, sourcemap] = await Promise.all([
fs_extra_1.default.readFile(tempHbcFile),
createHermesSourcemapAsync(map, `${tempHbcFile}.map`),
]);
}
return {
hbc,
sourcemap,
};
}
catch (error) {
console.error(chalk_1.default.red(`\nFailed to generate Hermes bytecode for: ${filename}`));
if ('status' in error) {
console.error(error.output.join('\n'));
}
throw error;
}
finally {
await fs_extra_1.default.remove(tempDir);
}
}
async function createHermesSourcemapAsync(sourcemap, hermesMapFile) {
const bundlerSourcemap = JSON.parse(sourcemap);
const hermesSourcemap = await fs_extra_1.default.readJSON(hermesMapFile);
return JSON.stringify((0, metro_source_map_1.composeSourceMaps)([bundlerSourcemap, hermesSourcemap]));
}
//# sourceMappingURL=exportHermes.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"exportHermes.js","sourceRoot":"","sources":["../../src/serializer/exportHermes.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,5 @@
export declare function getExportPathForDependencyWithOptions(dependencyPath: string, { platform, src, serverRoot }: {
platform: string;
serverRoot: string;
src: string;
}): string;

View File

@@ -0,0 +1,27 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getExportPathForDependencyWithOptions = void 0;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const path_1 = __importDefault(require("path"));
const getCssDeps_1 = require("./getCssDeps");
function getExportPathForDependencyWithOptions(dependencyPath, { platform, src, serverRoot }) {
const bundlePath = path_1.default.relative(serverRoot, dependencyPath);
const relativePathname = path_1.default.join(path_1.default.dirname(bundlePath),
// Strip the file extension
path_1.default.basename(bundlePath, path_1.default.extname(bundlePath)));
const name = (0, getCssDeps_1.fileNameFromContents)({
filepath: relativePathname,
src,
});
return `_expo/static/js/${platform}/${name}.js`;
}
exports.getExportPathForDependencyWithOptions = getExportPathForDependencyWithOptions;
//# sourceMappingURL=exportPath.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"exportPath.js","sourceRoot":"","sources":["../../src/serializer/exportPath.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;GAKG;AACH,gDAAwB;AAExB,6CAAoD;AAEpD,SAAgB,qCAAqC,CACnD,cAAsB,EACtB,EAAE,QAAQ,EAAE,GAAG,EAAE,UAAU,EAAyD;IAEpF,MAAM,UAAU,GAAG,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IAC7D,MAAM,gBAAgB,GAAG,cAAI,CAAC,IAAI,CAChC,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC;IACxB,2BAA2B;IAC3B,cAAI,CAAC,QAAQ,CAAC,UAAU,EAAE,cAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CACpD,CAAC;IACF,MAAM,IAAI,GAAG,IAAA,iCAAoB,EAAC;QAChC,QAAQ,EAAE,gBAAgB;QAC1B,GAAG;KACJ,CAAC,CAAC;IACH,OAAO,mBAAmB,QAAQ,IAAI,IAAI,KAAK,CAAC;AAClD,CAAC;AAfD,sFAeC"}

View File

@@ -0,0 +1,38 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork with bundle splitting and better source map support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js#L1
*/
import type { MixedOutput, Module, ReadOnlyGraph, SerializerOptions } from 'metro';
export type ModuleMap = [number, string][];
export type Bundle = {
modules: ModuleMap;
post: string;
pre: string;
};
export type ExpoSerializerOptions = SerializerOptions & {
serializerOptions?: {
baseUrl?: string;
skipWrapping?: boolean;
splitChunks?: boolean;
output?: string;
includeSourceMaps?: boolean;
};
debugId?: string;
};
export declare function getPlatformOption(graph: Pick<ReadOnlyGraph, 'transformOptions'>, options: Pick<SerializerOptions, 'sourceUrl'>): string | null;
export declare function getBaseUrlOption(graph: Pick<ReadOnlyGraph, 'transformOptions'>, options: Pick<ExpoSerializerOptions, 'serializerOptions'>): string;
export declare function baseJSBundle(entryPoint: string, preModules: readonly Module[], graph: Pick<ReadOnlyGraph, 'dependencies' | 'transformOptions'>, options: ExpoSerializerOptions): Bundle;
export declare function baseJSBundleWithDependencies(entryPoint: string, preModules: readonly Module[], dependencies: Module<MixedOutput>[], options: ExpoSerializerOptions & {
platform: string;
baseUrl: string;
splitChunks: boolean;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
debugId?: string;
}): Bundle;

View File

@@ -0,0 +1,142 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork with bundle splitting and better source map support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js#L1
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.baseJSBundleWithDependencies = exports.baseJSBundle = exports.getBaseUrlOption = exports.getPlatformOption = void 0;
const jsc_safe_url_1 = require("jsc-safe-url");
const CountingSet_1 = __importDefault(require("metro/src/lib/CountingSet"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const getAppendScripts_1 = __importDefault(require("metro/src/lib/getAppendScripts"));
const processModules_1 = require("./processModules");
function getPlatformOption(graph, options) {
if (graph.transformOptions?.platform != null) {
return graph.transformOptions.platform;
}
if (!options.sourceUrl) {
return null;
}
const sourceUrl = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const url = new URL(sourceUrl, 'https://expo.dev');
return url.searchParams.get('platform') ?? null;
}
exports.getPlatformOption = getPlatformOption;
function getBaseUrlOption(graph, options) {
const baseUrl = graph.transformOptions?.customTransformOptions?.baseUrl;
if (typeof baseUrl === 'string') {
// This tells us that the value came over a URL and may be encoded.
const mayBeEncoded = options.serializerOptions == null;
const option = mayBeEncoded ? decodeURIComponent(baseUrl) : baseUrl;
return option.replace(/\/+$/, '') + '/';
}
return '/';
}
exports.getBaseUrlOption = getBaseUrlOption;
function baseJSBundle(entryPoint, preModules, graph, options) {
const platform = getPlatformOption(graph, options);
if (platform == null) {
throw new Error('platform could not be determined for Metro bundle');
}
return baseJSBundleWithDependencies(entryPoint, preModules, [...graph.dependencies.values()], {
...options,
baseUrl: getBaseUrlOption(graph, options),
splitChunks: !!options.serializerOptions?.splitChunks,
platform,
skipWrapping: !!options.serializerOptions?.skipWrapping,
computedAsyncModulePaths: null,
});
}
exports.baseJSBundle = baseJSBundle;
function baseJSBundleWithDependencies(entryPoint, preModules, dependencies, options) {
for (const module of dependencies) {
options.createModuleId(module.path);
}
const processModulesOptions = {
filter: options.processModuleFilter,
createModuleId: options.createModuleId,
dev: options.dev,
includeAsyncPaths: options.includeAsyncPaths,
projectRoot: options.projectRoot,
serverRoot: options.serverRoot,
sourceUrl: options.sourceUrl,
platform: options.platform,
baseUrl: options.baseUrl,
splitChunks: options.splitChunks,
skipWrapping: options.skipWrapping,
computedAsyncModulePaths: options.computedAsyncModulePaths,
};
// Do not prepend polyfills or the require runtime when only modules are requested
if (options.modulesOnly) {
preModules = [];
}
const preCode = (0, processModules_1.processModules)(preModules, processModulesOptions)
.map(([, code]) => code.src)
.join('\n');
const modules = [...dependencies].sort((a, b) => options.createModuleId(a.path) - options.createModuleId(b.path));
const sourceMapUrl = options.serializerOptions?.includeSourceMaps === false ? undefined : options.sourceMapUrl;
const modulesWithAnnotations = (0, getAppendScripts_1.default)(entryPoint, [...preModules, ...modules], {
asyncRequireModulePath: options.asyncRequireModulePath,
createModuleId: options.createModuleId,
getRunModuleStatement: options.getRunModuleStatement,
inlineSourceMap: options.inlineSourceMap,
runBeforeMainModule: options.runBeforeMainModule,
runModule: options.runModule,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
sourceMapUrl,
// This directive doesn't make a lot of sense in the context of a large single bundle that represent
// multiple files. It's usually used for things like TypeScript where you want the file name to appear with a
// different extension. Since it's unclear to me (Bacon) how it is used on native, I'm only disabling in web and native in production.
sourceUrl: options.platform === 'web' ? undefined : !options.dev ? undefined : options.sourceUrl,
});
// If the `debugId` annotation is available and we aren't inlining the source map, add it to the bundle.
// NOTE: We may want to move this assertion up further.
const hasExternalMaps = !options.inlineSourceMap && !!sourceMapUrl;
if (hasExternalMaps && options.debugId != null) {
const code = `//# debugId=${options.debugId}`;
modulesWithAnnotations.push({
path: 'debug-id-annotation',
dependencies: new Map(),
getSource: () => Buffer.from(''),
inverseDependencies: new CountingSet_1.default(),
output: [
{
type: 'js/script/virtual',
data: {
code,
lineCount: (0, countLines_1.default)(code),
map: [],
},
},
],
});
}
const postCode = (0, processModules_1.processModules)(modulesWithAnnotations, processModulesOptions)
.map(([, code]) => code.src)
.join('\n');
const mods = (0, processModules_1.processModules)([...dependencies], processModulesOptions).map(([module, code]) => [
options.createModuleId(module.path),
code,
]);
return {
pre: preCode,
post: postCode,
modules: mods.map(([id, code]) => [
id,
typeof code === 'number' ? code : code.src,
]),
};
}
exports.baseJSBundleWithDependencies = baseJSBundleWithDependencies;
//# sourceMappingURL=baseJSBundle.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"baseJSBundle.js","sourceRoot":"","sources":["../../../src/serializer/fork/baseJSBundle.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,37 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the metro helper, but with bundle splitting support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/helpers/js.js#L1
*/
import type { MixedOutput, Module } from 'metro';
import type { JsOutput } from 'metro-transform-worker';
export type Options = {
createModuleId: (module: string) => number | string;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: string | undefined;
splitChunks: boolean;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
};
export declare function wrapModule(module: Module, options: Options): {
src: string;
paths: Record<string, string>;
};
export declare function getModuleParams(module: Module, options: Pick<Options, 'createModuleId' | 'sourceUrl' | 'includeAsyncPaths' | 'serverRoot' | 'splitChunks' | 'dev' | 'projectRoot' | 'computedAsyncModulePaths'>): {
params: any[];
paths: Record<string, string>;
};
export declare function getJsOutput(module: {
output: readonly MixedOutput[];
path?: string;
}): JsOutput;
export declare function isJsModule(module: Module): boolean;
export declare function isJsOutput(output: MixedOutput): output is MixedOutput;

View File

@@ -0,0 +1,102 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the metro helper, but with bundle splitting support.
* https://github.com/facebook/metro/blob/bbdd7d7c5e6e0feb50a9967ffae1f723c1d7c4e8/packages/metro/src/DeltaBundler/Serializers/helpers/js.js#L1
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.isJsOutput = exports.isJsModule = exports.getJsOutput = exports.getModuleParams = exports.wrapModule = void 0;
const assert_1 = __importDefault(require("assert"));
const jsc_safe_url_1 = __importDefault(require("jsc-safe-url"));
const metro_transform_plugins_1 = require("metro-transform-plugins");
const path_1 = __importDefault(require("path"));
function wrapModule(module, options) {
const output = getJsOutput(module);
if (output.type.startsWith('js/script')) {
return { src: output.data.code, paths: {} };
}
const { params, paths } = getModuleParams(module, options);
const src = (0, metro_transform_plugins_1.addParamsToDefineCall)(output.data.code, ...params);
return { src, paths };
}
exports.wrapModule = wrapModule;
function getModuleParams(module, options) {
const moduleId = options.createModuleId(module.path);
const paths = {};
let hasPaths = false;
const dependencyMapArray = Array.from(module.dependencies.values()).map((dependency) => {
const id = options.createModuleId(dependency.absolutePath);
if (
// NOTE(EvanBacon): Disabled this to ensure that paths are provided even when the entire bundle
// is created. This is required for production bundle splitting.
// options.includeAsyncPaths &&
dependency.data.data.asyncType != null) {
if (options.includeAsyncPaths) {
if (options.sourceUrl) {
hasPaths = true;
// TODO: Only include path if the target is not in the bundle
// Construct a server-relative URL for the split bundle, propagating
// most parameters from the main bundle's URL.
const { searchParams } = new URL(jsc_safe_url_1.default.toNormalUrl(options.sourceUrl));
searchParams.set('modulesOnly', 'true');
searchParams.set('runModule', 'false');
const bundlePath = path_1.default.relative(options.serverRoot, dependency.absolutePath);
paths[id] =
'/' +
path_1.default.join(path_1.default.dirname(bundlePath),
// Strip the file extension
path_1.default.basename(bundlePath, path_1.default.extname(bundlePath))) +
'.bundle?' +
searchParams.toString();
}
}
else if (options.splitChunks && options.computedAsyncModulePaths != null) {
hasPaths = true;
// A template string that we'll match and replace later when we know the content hash for a given path.
paths[id] = options.computedAsyncModulePaths[dependency.absolutePath];
}
}
return id;
});
const params = [
moduleId,
hasPaths
? {
...dependencyMapArray,
paths,
}
: dependencyMapArray,
];
if (options.dev) {
// Add the relative path of the module to make debugging easier.
// This is mapped to `module.verboseName` in `require.js`.
params.push(path_1.default.relative(options.projectRoot, module.path));
}
return { params, paths };
}
exports.getModuleParams = getModuleParams;
function getJsOutput(module) {
const jsModules = module.output.filter(({ type }) => type.startsWith('js/'));
(0, assert_1.default)(jsModules.length === 1, `Modules must have exactly one JS output, but ${module.path ?? 'unknown module'} has ${jsModules.length} JS outputs.`);
const jsOutput = jsModules[0];
(0, assert_1.default)(Number.isFinite(jsOutput.data.lineCount), `JS output must populate lineCount, but ${module.path ?? 'unknown module'} has ${jsOutput.type} output with lineCount '${jsOutput.data.lineCount}'`);
return jsOutput;
}
exports.getJsOutput = getJsOutput;
function isJsModule(module) {
return module.output.filter(isJsOutput).length > 0;
}
exports.isJsModule = isJsModule;
function isJsOutput(output) {
return output.type.startsWith('js/');
}
exports.isJsOutput = isJsOutput;
//# sourceMappingURL=js.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"js.js","sourceRoot":"","sources":["../../../src/serializer/fork/js.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,23 @@
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import type { Module } from 'metro';
export declare function processModules(modules: readonly Module[], { filter, createModuleId, dev, includeAsyncPaths, projectRoot, serverRoot, sourceUrl, splitChunks, skipWrapping, computedAsyncModulePaths, }: {
splitChunks: boolean;
filter?: (module: Module) => boolean;
createModuleId: (module: string) => number;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: string | undefined;
skipWrapping: boolean;
computedAsyncModulePaths: Record<string, string> | null;
}): readonly [Module, {
src: string;
paths: Record<string, string>;
}][];

View File

@@ -0,0 +1,32 @@
"use strict";
/**
* Copyright © 2022 650 Industries.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.processModules = void 0;
const js_1 = require("./js");
function processModules(modules, { filter = () => true, createModuleId, dev, includeAsyncPaths, projectRoot, serverRoot, sourceUrl, splitChunks, skipWrapping, computedAsyncModulePaths, }) {
return [...modules]
.filter(js_1.isJsModule)
.filter(filter)
.map((module) => [
module,
(0, js_1.wrapModule)(module, {
splitChunks,
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
skipWrapping,
computedAsyncModulePaths,
}),
]);
}
exports.processModules = processModules;
//# sourceMappingURL=processModules.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"processModules.js","sourceRoot":"","sources":["../../../src/serializer/fork/processModules.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AAIH,6BAA8C;AAE9C,SAAgB,cAAc,CAC5B,OAA0B,EAC1B,EACE,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,EACnB,cAAc,EACd,GAAG,EACH,iBAAiB,EACjB,WAAW,EACX,UAAU,EACV,SAAS,EACT,WAAW,EACX,YAAY,EACZ,wBAAwB,GAYzB;IAED,OAAO,CAAC,GAAG,OAAO,CAAC;SAChB,MAAM,CAAC,eAAU,CAAC;SAClB,MAAM,CAAC,MAAM,CAAC;SACd,GAAG,CAAC,CAAC,MAAc,EAAE,EAAE,CAAC;QACvB,MAAM;QACN,IAAA,eAAU,EAAC,MAAM,EAAE;YACjB,WAAW;YACX,cAAc;YACd,GAAG;YACH,iBAAiB;YACjB,WAAW;YACX,UAAU;YACV,SAAS;YACT,YAAY;YACZ,wBAAwB;SACzB,CAAC;KACH,CAAC,CAAC;AACP,CAAC;AA3CD,wCA2CC"}

View File

@@ -0,0 +1,34 @@
import type { Module } from 'metro';
import { SerialAsset } from './serializerAssets';
export type ReadOnlyDependencies<T = any> = ReadonlyMap<string, Module<T>>;
type Options = {
processModuleFilter: (modules: Module) => boolean;
assetPlugins: readonly string[];
platform?: string | null;
projectRoot: string;
publicPath: string;
};
export type JSModule = Module<{
data: {
code: string;
map: unknown;
lineCount: number;
css?: {
code: string;
map: unknown;
lineCount: number;
skipCache?: boolean;
};
};
type: 'js/module';
}> & {
unstable_transformResultKey?: string;
};
export declare function filterJsModules(dependencies: ReadOnlyDependencies, type: 'js/script' | 'js/module' | 'js/module/asset', { processModuleFilter, projectRoot }: Pick<Options, 'projectRoot' | 'processModuleFilter'>): JSModule[];
export declare function getCssSerialAssets<T extends any>(dependencies: ReadOnlyDependencies<T>, { processModuleFilter, projectRoot }: Pick<Options, 'projectRoot' | 'processModuleFilter'>): SerialAsset[];
export declare function fileNameFromContents({ filepath, src }: {
filepath: string;
src: string;
}): string;
export declare function getFileName(module: string): string;
export {};

View File

@@ -0,0 +1,79 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFileName = exports.fileNameFromContents = exports.getCssSerialAssets = exports.filterJsModules = void 0;
const js_1 = require("metro/src/DeltaBundler/Serializers/helpers/js");
const path_1 = __importDefault(require("path"));
const css_1 = require("../transform-worker/css");
const hash_1 = require("../utils/hash");
// s = static
const STATIC_EXPORT_DIRECTORY = '_expo/static/css';
function filterJsModules(dependencies, type, { processModuleFilter, projectRoot }) {
const assets = [];
for (const module of dependencies.values()) {
if ((0, js_1.isJsModule)(module) &&
processModuleFilter(module) &&
(0, js_1.getJsOutput)(module).type === type &&
path_1.default.relative(projectRoot, module.path) !== 'package.json') {
assets.push(module);
}
}
return assets;
}
exports.filterJsModules = filterJsModules;
function getCssSerialAssets(dependencies, { processModuleFilter, projectRoot }) {
const assets = [];
for (const module of filterJsModules(dependencies, 'js/module', {
processModuleFilter,
projectRoot,
})) {
const cssMetadata = getCssMetadata(module);
if (cssMetadata) {
const contents = cssMetadata.code;
const originFilename = path_1.default.relative(projectRoot, module.path);
const filename = path_1.default.join(
// Consistent location
STATIC_EXPORT_DIRECTORY,
// Hashed file contents + name for caching
fileNameFromContents({
// Stable filename for hashing in CI.
filepath: originFilename,
src: contents,
}) + '.css');
assets.push({
type: 'css',
originFilename,
filename,
source: contents,
metadata: {
hmrId: (0, css_1.pathToHtmlSafeName)(originFilename),
},
});
}
}
return assets;
}
exports.getCssSerialAssets = getCssSerialAssets;
function getCssMetadata(module) {
const data = module.output[0]?.data;
if (data && typeof data === 'object' && 'css' in data) {
if (typeof data.css !== 'object' || !('code' in data.css)) {
throw new Error(`Unexpected CSS metadata in Metro module (${module.path}): ${JSON.stringify(data.css)}`);
}
return data.css;
}
return null;
}
function fileNameFromContents({ filepath, src }) {
// Decode if the path is encoded from the Metro dev server, then normalize paths for Windows support.
const decoded = decodeURIComponent(filepath).replace(/\\/g, '/');
return getFileName(decoded) + '-' + (0, hash_1.hashString)(src);
}
exports.fileNameFromContents = fileNameFromContents;
function getFileName(module) {
return path_1.default.basename(module).replace(/\.[^.]+$/, '');
}
exports.getFileName = getFileName;
//# sourceMappingURL=getCssDeps.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getCssDeps.js","sourceRoot":"","sources":["../../src/serializer/getCssDeps.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,41 @@
/**
* Copyright © 2023-present 650 Industries (Expo). All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { FBSourceFunctionMap, MetroSourceMapSegmentTuple } from 'metro-source-map';
export type JSFileType = 'js/script' | 'js/module' | 'js/module/asset';
export type JsOutput = {
data: {
code: string;
lineCount: number;
map: MetroSourceMapSegmentTuple[];
functionMap: FBSourceFunctionMap | null;
css?: {
code: string;
lineCount: number;
map: MetroSourceMapSegmentTuple[];
functionMap: FBSourceFunctionMap | null;
};
};
type: JSFileType;
};
export type ExpoJsOutput = Omit<JsOutput, 'data'> & {
data: JsOutput['data'] & {
profiling?: {
start: number;
end: number;
duration: number;
};
css?: {
code: string;
lineCount: number;
map: unknown[];
functionMap: null;
skipCache?: boolean;
};
};
};
export declare function isExpoJsOutput(output: any): output is ExpoJsOutput;
export declare function isTransformOptionTruthy(option: any): boolean;

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isTransformOptionTruthy = exports.isExpoJsOutput = void 0;
function isExpoJsOutput(output) {
return 'data' in output && typeof output.data === 'object';
}
exports.isExpoJsOutput = isExpoJsOutput;
// Because transform options can be passed directly during export, or through a query parameter
// during a request, we need to normalize the options.
function isTransformOptionTruthy(option) {
return option === true || option === 'true' || option === '1';
}
exports.isTransformOptionTruthy = isTransformOptionTruthy;
//# sourceMappingURL=jsOutput.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"jsOutput.js","sourceRoot":"","sources":["../../src/serializer/jsOutput.ts"],"names":[],"mappings":";;;AA4CA,SAAgB,cAAc,CAAC,MAAW;IACxC,OAAO,MAAM,IAAI,MAAM,IAAI,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,CAAC;AAC7D,CAAC;AAFD,wCAEC;AAED,+FAA+F;AAC/F,sDAAsD;AACtD,SAAgB,uBAAuB,CAAC,MAAW;IACjD,OAAO,MAAM,KAAK,IAAI,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,KAAK,GAAG,CAAC;AAChE,CAAC;AAFD,0DAEC"}

View File

@@ -0,0 +1,44 @@
import { AssetData, MetroConfig, MixedOutput, Module, ReadOnlyGraph } from 'metro';
import { ConfigT, SerializerConfigT } from 'metro-config';
import { ExpoSerializerOptions } from './fork/baseJSBundle';
import { SerialAsset } from './serializerAssets';
import { SerializerConfigOptions } from './withExpoSerializers';
type Serializer = NonNullable<ConfigT['serializer']['customSerializer']>;
type SerializerParameters = Parameters<Serializer>;
export type SerializeChunkOptions = {
includeSourceMaps: boolean;
splitChunks: boolean;
} & SerializerConfigOptions;
export declare function graphToSerialAssetsAsync(config: MetroConfig, serializeChunkOptions: SerializeChunkOptions, ...props: SerializerParameters): Promise<{
artifacts: SerialAsset[] | null;
assets: AssetData[];
}>;
export declare class Chunk {
name: string;
entries: Module<MixedOutput>[];
graph: ReadOnlyGraph<MixedOutput>;
options: ExpoSerializerOptions;
isAsync: boolean;
isVendor: boolean;
deps: Set<Module>;
preModules: Set<Module>;
requiredChunks: Set<Chunk>;
constructor(name: string, entries: Module<MixedOutput>[], graph: ReadOnlyGraph<MixedOutput>, options: ExpoSerializerOptions, isAsync?: boolean, isVendor?: boolean);
private getPlatform;
private getFilename;
private getStableChunkSource;
private getFilenameForConfig;
private serializeToCodeWithTemplates;
hasAbsolutePath(absolutePath: string): boolean;
private getComputedPathsForAsyncDependencies;
private getAdjustedSourceMapUrl;
private serializeToCode;
private boolishTransformOption;
serializeToAssetsAsync(serializerConfig: Partial<SerializerConfigT>, chunks: Chunk[], { includeSourceMaps, unstable_beforeAssetSerializationPlugins }: SerializeChunkOptions): Promise<SerialAsset[]>;
private supportsBytecode;
isHermesEnabled(): boolean;
}
export declare function getSortedModules(modules: Module<MixedOutput>[], { createModuleId, }: {
createModuleId: (path: string) => number;
}): readonly Module<any>[];
export {};

View File

@@ -0,0 +1,467 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSortedModules = exports.Chunk = exports.graphToSerialAssetsAsync = void 0;
/**
* Copyright © 2023 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const assert_1 = __importDefault(require("assert"));
const sourceMapString_1 = __importDefault(require("metro/src/DeltaBundler/Serializers/sourceMapString"));
const bundleToString_1 = __importDefault(require("metro/src/lib/bundleToString"));
const path_1 = __importDefault(require("path"));
const debugId_1 = require("./debugId");
const exportHermes_1 = require("./exportHermes");
const exportPath_1 = require("./exportPath");
const baseJSBundle_1 = require("./fork/baseJSBundle");
const getCssDeps_1 = require("./getCssDeps");
const getAssets_1 = __importDefault(require("../transform-worker/getAssets"));
// Convert file paths to regex matchers.
function pathToRegex(path) {
// Escape regex special characters, except for '*'
let regexSafePath = path.replace(/[-[\]{}()+?.,\\^$|#\s]/g, '\\$&');
// Replace '*' with '.*' to act as a wildcard in regex
regexSafePath = regexSafePath.replace(/\*/g, '.*');
// Create a RegExp object with the modified string
return new RegExp('^' + regexSafePath + '$');
}
const sourceMapString = typeof sourceMapString_1.default !== 'function'
? sourceMapString_1.default.sourceMapString
: sourceMapString_1.default;
async function graphToSerialAssetsAsync(config, serializeChunkOptions, ...props) {
const [entryFile, preModules, graph, options] = props;
const cssDeps = (0, getCssDeps_1.getCssSerialAssets)(graph.dependencies, {
projectRoot: options.projectRoot,
processModuleFilter: options.processModuleFilter,
});
// Create chunks for splitting.
const chunks = new Set();
[
{
test: pathToRegex(entryFile),
},
].map((chunkSettings) => gatherChunks(chunks, chunkSettings, preModules, graph, options, false));
// Get the common modules and extract them into a separate chunk.
const entryChunk = [...chunks.values()].find((chunk) => !chunk.isAsync && chunk.hasAbsolutePath(entryFile));
if (entryChunk) {
for (const chunk of chunks.values()) {
if (chunk !== entryChunk && chunk.isAsync) {
for (const dep of chunk.deps.values()) {
if (entryChunk.deps.has(dep)) {
// Remove the dependency from the async chunk since it will be loaded in the main chunk.
chunk.deps.delete(dep);
}
}
}
}
const toCompare = [...chunks.values()];
const commonDependencies = [];
while (toCompare.length) {
const chunk = toCompare.shift();
for (const chunk2 of toCompare) {
if (chunk !== chunk2 && chunk.isAsync && chunk2.isAsync) {
const commonDeps = [...chunk.deps].filter((dep) => chunk2.deps.has(dep));
for (const dep of commonDeps) {
chunk.deps.delete(dep);
chunk2.deps.delete(dep);
}
commonDependencies.push(...commonDeps);
}
}
}
// If common dependencies were found, extract them to the entry chunk.
// TODO: Extract the metro-runtime to a common chunk apart from the entry chunk then load the common dependencies before the entry chunk.
if (commonDependencies.length) {
for (const dep of commonDependencies) {
entryChunk.deps.add(dep);
}
// const commonDependenciesUnique = [...new Set(commonDependencies)];
// const commonChunk = new Chunk(
// chunkIdForModules(commonDependenciesUnique),
// commonDependenciesUnique,
// graph,
// options,
// false,
// true
// );
// entryChunk.requiredChunks.add(commonChunk);
// chunks.add(commonChunk);
}
// TODO: Optimize this pass more.
// Remove all dependencies from async chunks that are already in the common chunk.
for (const chunk of [...chunks.values()]) {
if (chunk !== entryChunk) {
for (const dep of chunk.deps) {
if (entryChunk.deps.has(dep)) {
chunk.deps.delete(dep);
}
}
}
}
}
const jsAssets = await serializeChunksAsync(chunks, config.serializer ?? {}, serializeChunkOptions);
// TODO: Can this be anything besides true?
const isExporting = true;
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(graph, { serializerOptions: serializeChunkOptions });
const assetPublicUrl = (baseUrl.replace(/\/+$/, '') ?? '') + '/assets';
const publicPath = isExporting
? graph.transformOptions.platform === 'web'
? `/assets?export_path=${assetPublicUrl}`
: assetPublicUrl
: '/assets/?unstable_path=.';
// TODO: Convert to serial assets
// TODO: Disable this call dynamically in development since assets are fetched differently.
const metroAssets = (await (0, getAssets_1.default)(graph.dependencies, {
processModuleFilter: options.processModuleFilter,
assetPlugins: config.transformer?.assetPlugins ?? [],
platform: (0, baseJSBundle_1.getPlatformOption)(graph, options) ?? 'web',
projectRoot: options.projectRoot,
publicPath,
}));
return { artifacts: [...jsAssets, ...cssDeps], assets: metroAssets };
}
exports.graphToSerialAssetsAsync = graphToSerialAssetsAsync;
class Chunk {
name;
entries;
graph;
options;
isAsync;
isVendor;
deps = new Set();
preModules = new Set();
// Chunks that are required to be loaded synchronously before this chunk.
// These are included in the HTML as <script> tags.
requiredChunks = new Set();
constructor(name, entries, graph, options, isAsync = false, isVendor = false) {
this.name = name;
this.entries = entries;
this.graph = graph;
this.options = options;
this.isAsync = isAsync;
this.isVendor = isVendor;
this.deps = new Set(entries);
}
getPlatform() {
(0, assert_1.default)(this.graph.transformOptions.platform, "platform is required to be in graph's transformOptions");
return this.graph.transformOptions.platform;
}
getFilename(src) {
return this.options.dev
? this.name
: (0, exportPath_1.getExportPathForDependencyWithOptions)(this.name, {
platform: this.getPlatform(),
src,
serverRoot: this.options.serverRoot,
});
}
getStableChunkSource(serializerConfig) {
return this.options.dev
? ''
: this.serializeToCodeWithTemplates(serializerConfig, {
// Disable source maps when creating a sha to reduce the number of possible changes that could
// influence the cache hit.
serializerOptions: {
includeSourceMaps: false,
},
sourceMapUrl: undefined,
debugId: undefined,
});
}
getFilenameForConfig(serializerConfig) {
return this.getFilename(this.getStableChunkSource(serializerConfig));
}
serializeToCodeWithTemplates(serializerConfig, options = {}) {
const entryFile = this.name;
// TODO: Disable all debugId steps when a dev server is enabled. This is an export-only feature.
const preModules = [...this.preModules.values()];
const dependencies = [...this.deps];
const jsSplitBundle = (0, baseJSBundle_1.baseJSBundleWithDependencies)(entryFile, preModules, dependencies, {
...this.options,
runBeforeMainModule: serializerConfig?.getModulesRunBeforeMainModule?.(path_1.default.relative(this.options.projectRoot, entryFile)) ?? [],
runModule: !this.isVendor && !this.isAsync,
modulesOnly: this.preModules.size === 0,
platform: this.getPlatform(),
baseUrl: (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options),
splitChunks: !!this.options.serializerOptions?.splitChunks,
skipWrapping: true,
computedAsyncModulePaths: null,
...options,
});
return (0, bundleToString_1.default)(jsSplitBundle).code;
}
hasAbsolutePath(absolutePath) {
return [...this.deps].some((module) => module.path === absolutePath);
}
getComputedPathsForAsyncDependencies(serializerConfig, chunks) {
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options);
// Only calculate production paths when all chunks are being exported.
if (this.options.includeAsyncPaths) {
return null;
}
const computedAsyncModulePaths = {};
this.deps.forEach((module) => {
module.dependencies.forEach((dependency) => {
if (dependency.data.data.asyncType) {
const chunkContainingModule = chunks.find((chunk) => chunk.hasAbsolutePath(dependency.absolutePath));
(0, assert_1.default)(chunkContainingModule, 'Chunk containing module not found: ' + dependency.absolutePath);
// NOTE(kitten): We shouldn't have any async imports on non-async chunks
// However, due to how chunks merge, some async imports may now be pointing
// at entrypoint (or vendor) chunks. We omit the path so that the async import
// helper doesn't reload and reevaluate the entrypoint.
if (chunkContainingModule.isAsync) {
const moduleIdName = chunkContainingModule.getFilenameForConfig(serializerConfig);
computedAsyncModulePaths[dependency.absolutePath] = (baseUrl ?? '/') + moduleIdName;
}
}
});
});
return computedAsyncModulePaths;
}
getAdjustedSourceMapUrl(serializerConfig) {
// Metro really only accounts for development, so we'll use the defaults here.
if (this.options.dev) {
return this.options.sourceMapUrl ?? null;
}
if (this.options.serializerOptions?.includeSourceMaps !== true) {
return null;
}
if (this.options.inlineSourceMap || !this.options.sourceMapUrl) {
return this.options.sourceMapUrl ?? null;
}
const platform = this.getPlatform();
const isAbsolute = platform !== 'web';
const baseUrl = (0, baseJSBundle_1.getBaseUrlOption)(this.graph, this.options);
const filename = this.getFilenameForConfig(serializerConfig);
const isAbsoluteBaseUrl = !!baseUrl?.match(/https?:\/\//);
const pathname = (isAbsoluteBaseUrl ? '' : baseUrl.replace(/\/+$/, '')) +
'/' +
filename.replace(/^\/+$/, '') +
'.map';
let adjustedSourceMapUrl = this.options.sourceMapUrl;
// Metro has lots of issues...
if (this.options.sourceMapUrl.startsWith('//localhost')) {
adjustedSourceMapUrl = 'http:' + this.options.sourceMapUrl;
}
try {
const parsed = new URL(pathname, isAbsoluteBaseUrl ? baseUrl : adjustedSourceMapUrl);
if (isAbsoluteBaseUrl || isAbsolute) {
return parsed.href;
}
return parsed.pathname;
}
catch (error) {
// NOTE: export:embed that don't use baseUrl will use file paths instead of URLs.
if (!this.options.dev && isAbsolute) {
return adjustedSourceMapUrl;
}
console.error(`Failed to link source maps because the source map URL "${this.options.sourceMapUrl}" is corrupt:`, error);
return null;
}
}
serializeToCode(serializerConfig, { debugId, chunks }) {
return this.serializeToCodeWithTemplates(serializerConfig, {
skipWrapping: false,
sourceMapUrl: this.getAdjustedSourceMapUrl(serializerConfig) ?? undefined,
computedAsyncModulePaths: this.getComputedPathsForAsyncDependencies(serializerConfig, chunks),
debugId,
});
}
boolishTransformOption(name) {
const value = this.graph.transformOptions?.customTransformOptions?.[name];
return value === true || value === 'true';
}
async serializeToAssetsAsync(serializerConfig, chunks, { includeSourceMaps, unstable_beforeAssetSerializationPlugins }) {
// Create hash without wrapping to prevent it changing when the wrapping changes.
const outputFile = this.getFilenameForConfig(serializerConfig);
// We already use a stable hash for the output filename, so we'll reuse that for the debugId.
const debugId = (0, debugId_1.stringToUUID)(path_1.default.basename(outputFile, path_1.default.extname(outputFile)));
let premodules = [...this.preModules];
if (unstable_beforeAssetSerializationPlugins) {
for (const plugin of unstable_beforeAssetSerializationPlugins) {
premodules = plugin({ graph: this.graph, premodules, debugId });
}
this.preModules = new Set(premodules);
}
const jsCode = this.serializeToCode(serializerConfig, { chunks, debugId });
const relativeEntry = path_1.default.relative(this.options.projectRoot, this.name);
const jsAsset = {
filename: outputFile,
originFilename: relativeEntry,
type: 'js',
metadata: {
isAsync: this.isAsync,
requires: [...this.requiredChunks.values()].map((chunk) => chunk.getFilenameForConfig(serializerConfig)),
// Provide a list of module paths that can be used for matching chunks to routes.
// TODO: Move HTML serializing closer to this code so we can reduce passing this much data around.
modulePaths: [...this.deps].map((module) => module.path),
},
source: jsCode,
};
const assets = [jsAsset];
const mutateSourceMapWithDebugId = (sourceMap) => {
// TODO: Upstream this so we don't have to parse the source map back and forth.
if (!debugId) {
return sourceMap;
}
// NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore
// we don't need to disambiguate between multiple source maps.
const sourceMapObject = JSON.parse(sourceMap);
sourceMapObject.debugId = debugId;
// NOTE: Sentry does this, but bun does not.
// sourceMapObject.debug_id = debugId;
return JSON.stringify(sourceMapObject);
};
if (
// Only include the source map if the `options.sourceMapUrl` option is provided and we are exporting a static build.
includeSourceMaps &&
!this.options.inlineSourceMap &&
this.options.sourceMapUrl) {
const modules = [
...this.preModules,
...getSortedModules([...this.deps], {
createModuleId: this.options.createModuleId,
}),
].map((module) => {
// TODO: Make this user-configurable.
// Make all paths relative to the server root to prevent the entire user filesystem from being exposed.
if (module.path.startsWith('/')) {
return {
...module,
path: '/' + path_1.default.relative(this.options.serverRoot ?? this.options.projectRoot, module.path),
};
}
return module;
});
// TODO: We may not need to mutate the original source map with a `debugId` when hermes is enabled since we'll have different source maps.
const sourceMap = mutateSourceMapWithDebugId(sourceMapString(modules, {
excludeSource: false,
...this.options,
}));
assets.push({
filename: this.options.dev ? jsAsset.filename + '.map' : outputFile + '.map',
originFilename: jsAsset.originFilename,
type: 'map',
metadata: {},
source: sourceMap,
});
}
if (this.boolishTransformOption('bytecode') && this.isHermesEnabled()) {
const adjustedSource = jsAsset.source.replace(/^\/\/# (sourceMappingURL)=(.*)$/gm, (...props) => {
if (props[1] === 'sourceMappingURL') {
const mapName = props[2].replace(/\.js\.map$/, '.hbc.map');
return `//# ${props[1]}=` + mapName;
}
return '';
});
// TODO: Generate hbc for each chunk
const hermesBundleOutput = await (0, exportHermes_1.buildHermesBundleAsync)({
filename: this.name,
code: adjustedSource,
map: assets[1] ? assets[1].source : null,
// TODO: Maybe allow prod + no minify.
minify: true, //!this.options.dev,
});
if (hermesBundleOutput.hbc) {
// TODO: Unclear if we should add multiple assets, link the assets, or mutate the first asset.
// jsAsset.metadata.hbc = hermesBundleOutput.hbc;
// @ts-expect-error: TODO
jsAsset.source = hermesBundleOutput.hbc;
jsAsset.filename = jsAsset.filename.replace(/\.js$/, '.hbc');
}
if (assets[1] && hermesBundleOutput.sourcemap) {
assets[1].source = mutateSourceMapWithDebugId(hermesBundleOutput.sourcemap);
assets[1].filename = assets[1].filename.replace(/\.js\.map$/, '.hbc.map');
}
}
return assets;
}
supportsBytecode() {
return this.getPlatform() !== 'web';
}
isHermesEnabled() {
// TODO: Revisit.
// TODO: There could be an issue with having the serializer for export:embed output hermes since the native scripts will
// also create hermes bytecode. We may need to disable in one of the two places.
return (!this.options.dev &&
this.supportsBytecode() &&
this.graph.transformOptions.customTransformOptions?.engine === 'hermes');
}
}
exports.Chunk = Chunk;
function getEntryModulesForChunkSettings(graph, settings) {
return [...graph.dependencies.entries()]
.filter(([path]) => settings.test.test(path))
.map(([, module]) => module);
}
function chunkIdForModules(modules) {
return modules
.map((module) => module.path)
.sort()
.join('=>');
}
function gatherChunks(chunks, settings, preModules, graph, options, isAsync = false) {
let entryModules = getEntryModulesForChunkSettings(graph, settings);
const existingChunks = [...chunks.values()];
entryModules = entryModules.filter((module) => {
return !existingChunks.find((chunk) => chunk.entries.includes(module));
});
// Prevent processing the same entry file twice.
if (!entryModules.length) {
return chunks;
}
const entryChunk = new Chunk(chunkIdForModules(entryModules), entryModules, graph, options, isAsync);
// Add all the pre-modules to the first chunk.
if (preModules.length) {
// On native, use the preModules in insert code in the entry chunk.
for (const module of preModules.values()) {
entryChunk.preModules.add(module);
}
}
chunks.add(entryChunk);
function includeModule(entryModule) {
for (const dependency of entryModule.dependencies.values()) {
if (dependency.data.data.asyncType &&
// Support disabling multiple chunks.
entryChunk.options.serializerOptions?.splitChunks !== false) {
gatherChunks(chunks, { test: pathToRegex(dependency.absolutePath) }, [], graph, options, true);
}
else {
const module = graph.dependencies.get(dependency.absolutePath);
if (module) {
// Prevent circular dependencies from creating infinite loops.
if (!entryChunk.deps.has(module)) {
entryChunk.deps.add(module);
includeModule(module);
}
}
}
}
}
for (const entryModule of entryModules) {
includeModule(entryModule);
}
return chunks;
}
async function serializeChunksAsync(chunks, serializerConfig, options) {
const jsAssets = [];
const chunksArray = [...chunks.values()];
await Promise.all(chunksArray.map(async (chunk) => {
jsAssets.push(...(await chunk.serializeToAssetsAsync(serializerConfig, chunksArray, options)));
}));
return jsAssets;
}
function getSortedModules(modules, { createModuleId, }) {
// Assign IDs to modules in a consistent order
for (const module of modules) {
createModuleId(module.path);
}
// Sort by IDs
return modules.sort((a, b) => createModuleId(a.path) - createModuleId(b.path));
}
exports.getSortedModules = getSortedModules;
//# sourceMappingURL=serializeChunks.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,10 @@
export type SerialAsset = {
originFilename: string;
filename: string;
source: string;
type: 'css' | 'js' | 'map';
metadata: {
isAsync?: boolean;
modulePaths?: string[];
} & Record<string, boolean | string | string[]>;
};

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=serializerAssets.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"serializerAssets.js","sourceRoot":"","sources":["../../src/serializer/serializerAssets.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,24 @@
import { MetroConfig, MixedOutput, Module, ReadOnlyGraph } from 'metro';
import { ConfigT, InputConfigT } from 'metro-config';
import { ExpoSerializerOptions } from './fork/baseJSBundle';
import { SerialAsset } from './serializerAssets';
export type Serializer = NonNullable<ConfigT['serializer']['customSerializer']>;
export type SerializerParameters = [
string,
readonly Module[],
ReadOnlyGraph,
ExpoSerializerOptions
];
export type SerializerConfigOptions = {
unstable_beforeAssetSerializationPlugins?: ((serializationInput: {
graph: ReadOnlyGraph<MixedOutput>;
premodules: Module[];
debugId?: string;
}) => Module[])[];
};
export type SerializerPlugin = (...props: SerializerParameters) => SerializerParameters;
export declare function withExpoSerializers(config: InputConfigT, options?: SerializerConfigOptions): InputConfigT;
export declare function withSerializerPlugins(config: InputConfigT, processors: SerializerPlugin[], options?: SerializerConfigOptions): InputConfigT;
export declare function createDefaultExportCustomSerializer(config: Partial<MetroConfig>, configOptions?: SerializerConfigOptions): Serializer;
export declare function createSerializerFromSerialProcessors(config: MetroConfig, processors: (SerializerPlugin | undefined)[], originalSerializer: Serializer | null, options?: SerializerConfigOptions): Serializer;
export { SerialAsset };

View File

@@ -0,0 +1,207 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createSerializerFromSerialProcessors = exports.createDefaultExportCustomSerializer = exports.withSerializerPlugins = exports.withExpoSerializers = void 0;
/**
* Copyright © 2022 650 Industries.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const jsc_safe_url_1 = require("jsc-safe-url");
const sourceMapString_1 = __importDefault(require("metro/src/DeltaBundler/Serializers/sourceMapString"));
const bundleToString_1 = __importDefault(require("metro/src/lib/bundleToString"));
const debugId_1 = require("./debugId");
const environmentVariableSerializerPlugin_1 = require("./environmentVariableSerializerPlugin");
const baseJSBundle_1 = require("./fork/baseJSBundle");
const serializeChunks_1 = require("./serializeChunks");
const env_1 = require("../env");
const sourceMapString = typeof sourceMapString_1.default !== 'function'
? sourceMapString_1.default.sourceMapString
: sourceMapString_1.default;
function withExpoSerializers(config, options = {}) {
const processors = [];
processors.push(environmentVariableSerializerPlugin_1.serverPreludeSerializerPlugin);
if (!env_1.env.EXPO_NO_CLIENT_ENV_VARS) {
processors.push(environmentVariableSerializerPlugin_1.environmentVariableSerializerPlugin);
}
return withSerializerPlugins(config, processors, options);
}
exports.withExpoSerializers = withExpoSerializers;
// There can only be one custom serializer as the input doesn't match the output.
// Here we simply run
function withSerializerPlugins(config, processors, options = {}) {
const originalSerializer = config.serializer?.customSerializer;
return {
...config,
serializer: {
...config.serializer,
customSerializer: createSerializerFromSerialProcessors(config, processors, originalSerializer ?? null, options),
},
};
}
exports.withSerializerPlugins = withSerializerPlugins;
function createDefaultExportCustomSerializer(config, configOptions = {}) {
return async (entryPoint, preModules, graph, options) => {
const isPossiblyDev = graph.transformOptions.hot;
// TODO: This is a temporary solution until we've converged on using the new serializer everywhere.
const enableDebugId = options.inlineSourceMap !== true && !isPossiblyDev;
let debugId;
const loadDebugId = () => {
if (!enableDebugId || debugId) {
return debugId;
}
// TODO: Perform this cheaper.
const bundle = (0, baseJSBundle_1.baseJSBundle)(entryPoint, preModules, graph, {
...options,
debugId: undefined,
});
const outputCode = (0, bundleToString_1.default)(bundle).code;
debugId = (0, debugId_1.stringToUUID)(outputCode);
return debugId;
};
let premodulesToBundle = [...preModules];
let bundleCode = null;
let bundleMap = null;
if (config.serializer?.customSerializer) {
const bundle = await config.serializer?.customSerializer(entryPoint, premodulesToBundle, graph, options);
if (typeof bundle === 'string') {
bundleCode = bundle;
}
else {
bundleCode = bundle.code;
bundleMap = bundle.map;
}
}
else {
const debugId = loadDebugId();
if (configOptions.unstable_beforeAssetSerializationPlugins) {
for (const plugin of configOptions.unstable_beforeAssetSerializationPlugins) {
premodulesToBundle = plugin({ graph, premodules: [...premodulesToBundle], debugId });
}
}
bundleCode = (0, bundleToString_1.default)((0, baseJSBundle_1.baseJSBundle)(entryPoint, premodulesToBundle, graph, {
...options,
debugId,
})).code;
}
const getEnsuredMaps = () => {
bundleMap ??= sourceMapString([...premodulesToBundle, ...(0, serializeChunks_1.getSortedModules)([...graph.dependencies.values()], options)], {
// TODO: Surface this somehow.
excludeSource: false,
// excludeSource: options.serializerOptions?.excludeSource,
processModuleFilter: options.processModuleFilter,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
});
return bundleMap;
};
if (!bundleMap && options.sourceUrl) {
const url = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const parsed = new URL(url, 'http://expo.dev');
// Is dev server request for source maps...
if (parsed.pathname.endsWith('.map')) {
return {
code: bundleCode,
map: getEnsuredMaps(),
};
}
}
if (isPossiblyDev) {
if (bundleMap == null) {
return bundleCode;
}
return {
code: bundleCode,
map: bundleMap,
};
}
// Exports....
bundleMap ??= getEnsuredMaps();
if (enableDebugId) {
const mutateSourceMapWithDebugId = (sourceMap) => {
// NOTE: debugId isn't required for inline source maps because the source map is included in the same file, therefore
// we don't need to disambiguate between multiple source maps.
const sourceMapObject = JSON.parse(sourceMap);
sourceMapObject.debugId = loadDebugId();
// NOTE: Sentry does this, but bun does not.
// sourceMapObject.debug_id = debugId;
return JSON.stringify(sourceMapObject);
};
return {
code: bundleCode,
map: mutateSourceMapWithDebugId(bundleMap),
};
}
return {
code: bundleCode,
map: bundleMap,
};
};
}
exports.createDefaultExportCustomSerializer = createDefaultExportCustomSerializer;
function getDefaultSerializer(config, fallbackSerializer, configOptions = {}) {
const defaultSerializer = fallbackSerializer ?? createDefaultExportCustomSerializer(config, configOptions);
return async (...props) => {
const [, , , options] = props;
const customSerializerOptions = options.serializerOptions;
// Custom options can only be passed outside of the dev server, meaning
// we don't need to stringify the results at the end, i.e. this is `npx expo export` or `npx expo export:embed`.
const supportsNonSerialReturn = !!customSerializerOptions?.output;
const serializerOptions = (() => {
if (customSerializerOptions) {
return {
outputMode: customSerializerOptions.output,
splitChunks: customSerializerOptions.splitChunks,
includeSourceMaps: customSerializerOptions.includeSourceMaps,
};
}
if (options.sourceUrl) {
const sourceUrl = (0, jsc_safe_url_1.isJscSafeUrl)(options.sourceUrl)
? (0, jsc_safe_url_1.toNormalUrl)(options.sourceUrl)
: options.sourceUrl;
const url = new URL(sourceUrl, 'https://expo.dev');
return {
outputMode: url.searchParams.get('serializer.output'),
splitChunks: url.searchParams.get('serializer.splitChunks') === 'true',
includeSourceMaps: url.searchParams.get('serializer.map') === 'true',
};
}
return null;
})();
if (serializerOptions?.outputMode !== 'static') {
return defaultSerializer(...props);
}
// Mutate the serializer options with the parsed options.
options.serializerOptions = {
...options.serializerOptions,
...serializerOptions,
};
const assets = await (0, serializeChunks_1.graphToSerialAssetsAsync)(config, {
includeSourceMaps: !!serializerOptions.includeSourceMaps,
splitChunks: !!serializerOptions.splitChunks,
...configOptions,
}, ...props);
if (supportsNonSerialReturn) {
// @ts-expect-error: this is future proofing for adding assets to the output as well.
return assets;
}
return JSON.stringify(assets);
};
}
function createSerializerFromSerialProcessors(config, processors, originalSerializer, options = {}) {
const finalSerializer = getDefaultSerializer(config, originalSerializer, options);
return (...props) => {
for (const processor of processors) {
if (processor) {
props = processor(...props);
}
}
return finalSerializer(...props);
};
}
exports.createSerializerFromSerialProcessors = createSerializerFromSerialProcessors;
//# sourceMappingURL=withExpoSerializers.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,4 @@
import { BabelTransformerArgs } from 'metro-babel-transformer';
export declare function transform({ filename, options }: BabelTransformerArgs, assetRegistryPath: string, assetDataPlugins: readonly string[]): Promise<{
ast: import("@babel/parser").ParseResult<import("@babel/types").File>;
}>;

View File

@@ -0,0 +1,34 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the upstream transformer, but with modifications made for web production hashing.
* https://github.com/facebook/metro/blob/412771475c540b6f85d75d9dcd5a39a6e0753582/packages/metro-transform-worker/src/utils/assetTransformer.js#L1
*/
const util_1 = require("metro/src/Bundler/util");
const node_path_1 = __importDefault(require("node:path"));
const getAssets_1 = require("./getAssets");
async function transform({ filename, options }, assetRegistryPath, assetDataPlugins) {
options ??= options || {
platform: '',
projectRoot: '',
inlineRequires: false,
minify: false,
};
const absolutePath = node_path_1.default.resolve(options.projectRoot, filename);
const data = await (0, getAssets_1.getUniversalAssetData)(absolutePath, filename, assetDataPlugins, options.platform, options.publicPath);
return {
ast: (0, util_1.generateAssetCodeFileAst)(assetRegistryPath, data),
};
}
exports.transform = transform;
//# sourceMappingURL=asset-transformer.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"asset-transformer.js","sourceRoot":"","sources":["../../src/transform-worker/asset-transformer.ts"],"names":[],"mappings":";;;;;;AAAA;;;;;;;;;GASG;AACH,iDAAkE;AAElE,0DAA6B;AAE7B,2CAAoD;AAE7C,KAAK,UAAU,SAAS,CAC7B,EAAE,QAAQ,EAAE,OAAO,EAAwB,EAC3C,iBAAyB,EACzB,gBAAmC;IAEnC,OAAO,KAAK,OAAO,IAAI;QACrB,QAAQ,EAAE,EAAE;QACZ,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,KAAK;QACrB,MAAM,EAAE,KAAK;KACd,CAAC;IAEF,MAAM,YAAY,GAAG,mBAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IAEjE,MAAM,IAAI,GAAG,MAAM,IAAA,iCAAqB,EACtC,YAAY,EACZ,QAAQ,EACR,gBAAgB,EAChB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,UAAU,CACnB,CAAC;IAEF,OAAO;QACL,GAAG,EAAE,IAAA,+BAAwB,EAAC,iBAAiB,EAAE,IAAI,CAAC;KACvD,CAAC;AACJ,CAAC;AAzBD,8BAyBC"}

View File

@@ -0,0 +1,21 @@
/// <reference types="node" />
export declare function transformCssModuleWeb(props: {
filename: string;
src: string;
options: {
projectRoot: string;
minify: boolean;
dev: boolean;
sourceMap: boolean;
};
}): Promise<{
output: string;
css: Buffer;
map: void | Buffer;
}>;
export declare function convertLightningCssToReactNativeWebStyleSheet(input: import('lightningcss').CSSModuleExports): {
styles: Record<string, string>;
reactNativeWeb: Record<string, any>;
variables: Record<string, string>;
};
export declare function matchCssModule(filePath: string): boolean;

View File

@@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.matchCssModule = exports.convertLightningCssToReactNativeWebStyleSheet = exports.transformCssModuleWeb = void 0;
const css_1 = require("./css");
const RNW_CSS_CLASS_ID = '_';
async function transformCssModuleWeb(props) {
const { transform } = require('lightningcss');
// TODO: Add bundling to resolve imports
// https://lightningcss.dev/bundling.html#bundling-order
const cssResults = transform({
filename: props.filename,
code: Buffer.from(props.src),
sourceMap: props.options.sourceMap,
cssModules: {
// Prevent renaming CSS variables to ensure
// variables created in global files are available.
dashedIdents: false,
},
// cssModules: true,
projectRoot: props.options.projectRoot,
minify: props.options.minify,
});
const codeAsString = cssResults.code.toString();
const { styles, reactNativeWeb, variables } = convertLightningCssToReactNativeWebStyleSheet(cssResults.exports);
let outputModule = `module.exports=Object.assign(${JSON.stringify(styles)},{unstable_styles:${JSON.stringify(reactNativeWeb)}},${JSON.stringify(variables)});`;
if (props.options.dev) {
const runtimeCss = (0, css_1.wrapDevelopmentCSS)({
...props,
src: codeAsString,
});
outputModule += '\n' + runtimeCss;
}
return {
output: outputModule,
css: cssResults.code,
map: cssResults.map,
};
}
exports.transformCssModuleWeb = transformCssModuleWeb;
function convertLightningCssToReactNativeWebStyleSheet(input) {
const styles = {};
const reactNativeWeb = {};
const variables = {};
// e.g. { container: { name: 'ahs8IW_container', composes: [], isReferenced: false }, }
Object.entries(input).map(([key, value]) => {
// order matters here
let className = value.name;
if (value.composes.length) {
className += ' ' + value.composes.map((value) => value.name).join(' ');
}
// CSS Variables will be `{string: string}`
if (key.startsWith('--')) {
variables[key] = className;
}
styles[key] = className;
reactNativeWeb[key] = { $$css: true, [RNW_CSS_CLASS_ID]: className };
return {
[key]: { $$css: true, [RNW_CSS_CLASS_ID]: className },
};
});
return { styles, reactNativeWeb, variables };
}
exports.convertLightningCssToReactNativeWebStyleSheet = convertLightningCssToReactNativeWebStyleSheet;
function matchCssModule(filePath) {
return !!/\.module(\.(native|ios|android|web))?\.(css|s[ac]ss)$/.test(filePath);
}
exports.matchCssModule = matchCssModule;
//# sourceMappingURL=css-modules.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css-modules.js","sourceRoot":"","sources":["../../src/transform-worker/css-modules.ts"],"names":[],"mappings":"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"}

View File

@@ -0,0 +1,7 @@
export declare function pathToHtmlSafeName(path: string): string;
export declare function getHotReplaceTemplate(id: string): string;
export declare function wrapDevelopmentCSS(props: {
src: string;
filename: string;
}): string;
export declare function escapeBackticksAndOctals(str: string): string;

View File

@@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.escapeBackticksAndOctals = exports.wrapDevelopmentCSS = exports.getHotReplaceTemplate = exports.pathToHtmlSafeName = void 0;
function pathToHtmlSafeName(path) {
return path.replace(/[^a-zA-Z0-9_]/g, '_');
}
exports.pathToHtmlSafeName = pathToHtmlSafeName;
function getHotReplaceTemplate(id) {
// In dev mode, we need to replace the style tag instead of appending it
// use the path as the expo-css-hmr attribute to find the style tag
// to replace.
const attr = JSON.stringify(pathToHtmlSafeName(id));
return `style.setAttribute('data-expo-css-hmr', ${attr});
const previousStyle = document.querySelector('[data-expo-css-hmr=${attr}]');
if (previousStyle) {
previousStyle.parentNode.removeChild(previousStyle);
}`;
}
exports.getHotReplaceTemplate = getHotReplaceTemplate;
function wrapDevelopmentCSS(props) {
const withBackTicksEscaped = escapeBackticksAndOctals(props.src);
return `(() => {
if (typeof window === 'undefined') {
return
}
const head = document.head || document.getElementsByTagName('head')[0];
const style = document.createElement('style');
${getHotReplaceTemplate(props.filename)}
style.setAttribute('data-expo-loader', 'css');
head.appendChild(style);
const css = \`${withBackTicksEscaped}\`;
if (style.styleSheet){
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
})();`;
}
exports.wrapDevelopmentCSS = wrapDevelopmentCSS;
function escapeBackticksAndOctals(str) {
if (typeof str !== 'string') {
return '';
}
return str
.replace(/\\/g, '\\\\')
.replace(/`/g, '\\`')
.replace(/[\0-\7]/g, (match) => `\\0${match.charCodeAt(0).toString(8)}`);
}
exports.escapeBackticksAndOctals = escapeBackticksAndOctals;
//# sourceMappingURL=css.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"css.js","sourceRoot":"","sources":["../../src/transform-worker/css.ts"],"names":[],"mappings":";;;AAAA,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;AAC7C,CAAC;AAFD,gDAEC;AAED,SAAgB,qBAAqB,CAAC,EAAU;IAC9C,wEAAwE;IACxE,mEAAmE;IACnE,cAAc;IACd,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC;IACpD,OAAO,2CAA2C,IAAI;qEACa,IAAI;;;IAGrE,CAAC;AACL,CAAC;AAVD,sDAUC;AAED,SAAgB,kBAAkB,CAAC,KAAwC;IACzE,MAAM,oBAAoB,GAAG,wBAAwB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjE,OAAO;;;;;;IAML,qBAAqB,CAAC,KAAK,CAAC,QAAQ,CAAC;;;kBAGvB,oBAAoB;;;;;;MAMhC,CAAC;AACP,CAAC;AAlBD,gDAkBC;AAED,SAAgB,wBAAwB,CAAC,GAAW;IAClD,IAAI,OAAO,GAAG,KAAK,QAAQ,EAAE;QAC3B,OAAO,EAAE,CAAC;KACX;IAED,OAAO,GAAG;SACP,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC;SACtB,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC;SACpB,OAAO,CAAC,UAAU,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAC7E,CAAC;AATD,4DASC"}

View File

@@ -0,0 +1,23 @@
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import { AssetData, Module } from 'metro';
import { ReadOnlyDependencies } from '../serializer/getCssDeps';
type Options = {
processModuleFilter: (modules: Module) => boolean;
assetPlugins: readonly string[];
platform?: string | null;
projectRoot: string;
publicPath: string;
};
export declare function getUniversalAssetData(assetPath: string, localPath: string, assetDataPlugins: readonly string[], platform: string | null | undefined, publicPath: string): Promise<HashedAssetData>;
export type HashedAssetData = AssetData & {
fileHashes: string[];
_name?: string;
};
export default function getAssets(dependencies: ReadOnlyDependencies, options: Options): Promise<HashedAssetData[]>;
export {};

View File

@@ -0,0 +1,49 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getUniversalAssetData = void 0;
const Assets_1 = require("metro/src/Assets");
const js_1 = require("metro/src/DeltaBundler/Serializers/helpers/js");
const node_assert_1 = __importDefault(require("node:assert"));
const node_crypto_1 = __importDefault(require("node:crypto"));
const node_path_1 = __importDefault(require("node:path"));
function md5Hash(data) {
if (data.length === 1)
return data[0];
const hash = node_crypto_1.default.createHash('md5');
hash.update(data.join(''));
return hash.digest('hex');
}
function assertHashedAssetData(data) {
(0, node_assert_1.default)('fileHashes' in data, 'Assets must have hashed files. Ensure the expo-asset plugin is installed.');
}
async function getUniversalAssetData(assetPath, localPath, assetDataPlugins, platform, publicPath) {
const data = await (0, Assets_1.getAssetData)(assetPath, localPath, assetDataPlugins, platform, publicPath);
assertHashedAssetData(data);
// NOTE(EvanBacon): This is where we modify the asset to include a hash in the name for web cache invalidation.
if (platform === 'web' && publicPath.includes('?export_path=')) {
// `local-image.[contenthash]`. Using `.` but this won't work if we ever apply to Android because Android res files cannot contain `.`.
// TODO: Prevent one multi-res image from updating the hash in all images.
// @ts-expect-error: name is typed as readonly.
data.name = `${data.name}.${md5Hash(data.fileHashes)}`;
}
return data;
}
exports.getUniversalAssetData = getUniversalAssetData;
async function getAssets(dependencies, options) {
const promises = [];
const { processModuleFilter } = options;
for (const module of dependencies.values()) {
if ((0, js_1.isJsModule)(module) &&
processModuleFilter(module) &&
(0, js_1.getJsOutput)(module).type === 'js/module/asset' &&
node_path_1.default.relative(options.projectRoot, module.path) !== 'package.json') {
promises.push(getUniversalAssetData(module.path, node_path_1.default.relative(options.projectRoot, module.path), options.assetPlugins, options.platform, options.publicPath));
}
}
return await Promise.all(promises);
}
exports.default = getAssets;
//# sourceMappingURL=getAssets.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"getAssets.js","sourceRoot":"","sources":["../../src/transform-worker/getAssets.ts"],"names":[],"mappings":";;;;;;AAQA,6CAAgD;AAChD,sEAAwF;AACxF,8DAAiC;AACjC,8DAAiC;AACjC,0DAA6B;AAY7B,SAAS,OAAO,CAAC,IAAc;IAC7B,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,qBAAM,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5B,CAAC;AAED,SAAS,qBAAqB,CAAC,IAAe;IAC5C,IAAA,qBAAM,EACJ,YAAY,IAAI,IAAI,EACpB,2EAA2E,CAC5E,CAAC;AACJ,CAAC;AAEM,KAAK,UAAU,qBAAqB,CACzC,SAAiB,EACjB,SAAiB,EACjB,gBAAmC,EACnC,QAAmC,EACnC,UAAkB;IAElB,MAAM,IAAI,GAAG,MAAM,IAAA,qBAAY,EAAC,SAAS,EAAE,SAAS,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC9F,qBAAqB,CAAC,IAAI,CAAC,CAAC;IAE5B,+GAA+G;IAC/G,IAAI,QAAQ,KAAK,KAAK,IAAI,UAAU,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE;QAC9D,uIAAuI;QACvI,0EAA0E;QAC1E,+CAA+C;QAC/C,IAAI,CAAC,IAAI,GAAG,GAAG,IAAI,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC;KACxD;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAnBD,sDAmBC;AAIc,KAAK,UAAU,SAAS,CACrC,YAAkC,EAClC,OAAgB;IAEhB,MAAM,QAAQ,GAA+B,EAAE,CAAC;IAChD,MAAM,EAAE,mBAAmB,EAAE,GAAG,OAAO,CAAC;IAExC,KAAK,MAAM,MAAM,IAAI,YAAY,CAAC,MAAM,EAAE,EAAE;QAC1C,IACE,IAAA,eAAU,EAAC,MAAM,CAAC;YAClB,mBAAmB,CAAC,MAAM,CAAC;YAC3B,IAAA,gBAAW,EAAC,MAAM,CAAC,CAAC,IAAI,KAAK,iBAAiB;YAC9C,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,cAAc,EAClE;YACA,QAAQ,CAAC,IAAI,CACX,qBAAqB,CACnB,MAAM,CAAC,IAAI,EACX,mBAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,IAAI,CAAC,EAC/C,OAAO,CAAC,YAAY,EACpB,OAAO,CAAC,QAAQ,EAChB,OAAO,CAAC,UAAU,CACnB,CACF,CAAC;SACH;KACF;IAED,OAAO,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACrC,CAAC;AA3BD,4BA2BC"}

View File

@@ -0,0 +1,11 @@
/// <reference types="node" />
/// <reference types="metro" />
import type { TransformResultDependency } from 'metro/src/DeltaBundler';
import { JsOutput, JsTransformerConfig, JsTransformOptions } from 'metro-transform-worker';
export { JsTransformOptions };
interface TransformResponse {
readonly dependencies: readonly TransformResultDependency[];
readonly output: readonly JsOutput[];
}
export declare function transform(config: JsTransformerConfig, projectRoot: string, filename: string, data: Buffer, options: JsTransformOptions): Promise<TransformResponse>;
export declare function getCacheKey(config: JsTransformerConfig): string;

View File

@@ -0,0 +1,466 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getCacheKey = exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* Fork of the Metro transformer worker, but with additional transforms moved to `babel-preset-expo` and modifications made for web support.
* https://github.com/facebook/metro/blob/412771475c540b6f85d75d9dcd5a39a6e0753582/packages/metro-transform-worker/src/index.js#L1
*/
const core_1 = require("@babel/core");
const generator_1 = __importDefault(require("@babel/generator"));
const babylon = __importStar(require("@babel/parser"));
const types = __importStar(require("@babel/types"));
const JsFileWrapping_1 = __importDefault(require("metro/src/ModuleGraph/worker/JsFileWrapping"));
const collectDependencies_1 = __importStar(require("metro/src/ModuleGraph/worker/collectDependencies"));
const generateImportNames_1 = __importDefault(require("metro/src/ModuleGraph/worker/generateImportNames"));
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const metro_cache_1 = require("metro-cache");
const metro_cache_key_1 = __importDefault(require("metro-cache-key"));
const metro_source_map_1 = require("metro-source-map");
const metro_transform_plugins_1 = __importDefault(require("metro-transform-plugins"));
const getMinifier_1 = __importDefault(require("metro-transform-worker/src/utils/getMinifier"));
const node_assert_1 = __importDefault(require("node:assert"));
const assetTransformer = __importStar(require("./asset-transformer"));
const resolveOptions_1 = require("./resolveOptions");
// asserts non-null
function nullthrows(x, message) {
(0, node_assert_1.default)(x != null, message);
return x;
}
function getDynamicDepsBehavior(inPackages, filename) {
switch (inPackages) {
case 'reject':
return 'reject';
case 'throwAtRuntime':
return /(?:^|[/\\])node_modules[/\\]/.test(filename) ? inPackages : 'reject';
default:
throw new Error(`invalid value for dynamic deps behavior: \`${inPackages}\``);
}
}
const minifyCode = async (config, projectRoot, filename, code, source, map, reserved = []) => {
const sourceMap = (0, metro_source_map_1.fromRawMappings)([
{
code,
source,
map,
// functionMap is overridden by the serializer
functionMap: null,
path: filename,
// isIgnored is overriden by the serializer
isIgnored: false,
},
]).toMap(undefined, {});
const minify = (0, getMinifier_1.default)(config.minifierPath);
try {
const minified = await minify({
code,
map: sourceMap,
filename,
reserved,
config: config.minifierConfig,
});
return {
code: minified.code,
map: minified.map ? (0, metro_source_map_1.toBabelSegments)(minified.map).map(metro_source_map_1.toSegmentTuple) : [],
};
}
catch (error) {
if (error.constructor.name === 'JS_Parse_Error') {
throw new Error(`${error.message} in file ${filename} at ${error.line}:${error.col}`);
}
throw error;
}
};
const disabledDependencyTransformer = {
transformSyncRequire: () => { },
transformImportCall: () => { },
transformPrefetch: () => { },
transformIllegalDynamicRequire: () => { },
};
class InvalidRequireCallError extends Error {
innerError;
filename;
constructor(innerError, filename) {
super(`${filename}:${innerError.message}`);
this.innerError = innerError;
this.filename = filename;
}
}
async function transformJS(file, { config, options, projectRoot }) {
// Transformers can output null ASTs (if they ignore the file). In that case
// we need to parse the module source code to get their AST.
let ast = file.ast ?? babylon.parse(file.code, { sourceType: 'unambiguous' });
// NOTE(EvanBacon): This can be really expensive on larger files. We should replace it with a cheaper alternative that just iterates and matches.
const { importDefault, importAll } = (0, generateImportNames_1.default)(ast);
// Add "use strict" if the file was parsed as a module, and the directive did
// not exist yet.
const { directives } = ast.program;
if (ast.program.sourceType === 'module' &&
directives != null &&
directives.findIndex((d) => d.value.value === 'use strict') === -1) {
directives.push(types.directive(types.directiveLiteral('use strict')));
}
// Perform the import-export transform (in case it's still needed), then
// fold requires and perform constant folding (if in dev).
const plugins = [];
const babelPluginOpts = {
...options,
inlineableCalls: [importDefault, importAll],
importDefault,
importAll,
};
// NOTE(EvanBacon): This is effectively a replacement for the `@babel/plugin-transform-modules-commonjs`
// plugin that's running in `@@react-native/babel-preset`, but with shared names for inlining requires.
if (options.experimentalImportSupport === true) {
plugins.push([metro_transform_plugins_1.default.importExportPlugin, babelPluginOpts]);
}
// NOTE(EvanBacon): This can basically never be safely enabled because it doesn't respect side-effects and
// has no ability to respect side-effects because the transformer hasn't collected all dependencies yet.
if (options.inlineRequires) {
plugins.push([
metro_transform_plugins_1.default.inlineRequiresPlugin,
{
...babelPluginOpts,
ignoredRequires: options.nonInlinedRequires,
},
]);
}
// NOTE(EvanBacon): We apply this conditionally in `babel-preset-expo` with other AST transforms.
// plugins.push([metroTransformPlugins.inlinePlugin, babelPluginOpts]);
// TODO: This MUST be run even though no plugins are added, otherwise the babel runtime generators are broken.
if (plugins.length) {
ast = nullthrows(
// @ts-expect-error
(0, core_1.transformFromAstSync)(ast, '', {
ast: true,
babelrc: false,
code: false,
configFile: false,
comments: true,
filename: file.filename,
plugins,
sourceMaps: false,
// NOTE(kitten): This was done to wipe the paths/scope caches, which the `constantFoldingPlugin` needs to work,
// but has been replaced with `programPath.scope.crawl()`.
// Old Note from Metro:
// > Not-Cloning the input AST here should be safe because other code paths above this call
// > are mutating the AST as well and no code is depending on the original AST.
// > However, switching the flag to false caused issues with ES Modules if `experimentalImportSupport` isn't used https://github.com/facebook/metro/issues/641
// > either because one of the plugins is doing something funky or Babel messes up some caches.
// > Make sure to test the above mentioned case before flipping the flag back to false.
cloneInputAst: false,
}).ast);
}
if (!options.dev) {
// NOTE(kitten): Any Babel helpers that have been added (`path.hub.addHelper(...)`) will usually not have any
// references, and hence the `constantFoldingPlugin` below will remove them.
// To fix the references we add an explicit `programPath.scope.crawl()`. Alternatively, we could also wipe the
// Babel traversal cache (`traverse.cache.clear()`)
const clearProgramScopePlugin = {
visitor: {
Program: {
enter(path) {
path.scope.crawl();
},
},
},
};
// Run the constant folding plugin in its own pass, avoiding race conditions
// with other plugins that have exit() visitors on Program (e.g. the ESM
// transform).
ast = nullthrows(
// @ts-expect-error
(0, core_1.transformFromAstSync)(ast, '', {
ast: true,
babelrc: false,
code: false,
configFile: false,
comments: true,
filename: file.filename,
plugins: [
clearProgramScopePlugin,
[metro_transform_plugins_1.default.constantFoldingPlugin, babelPluginOpts],
],
sourceMaps: false,
// NOTE(kitten): In Metro, this is also false, but only works because the prior run of `transformFromAstSync` was always
// running with `cloneInputAst: true`.
// This isn't needed anymore since `clearProgramScopePlugin` re-crawls the ASTs scope instead.
cloneInputAst: false,
}).ast);
}
let dependencyMapName = '';
let dependencies;
let wrappedAst;
// If the module to transform is a script (meaning that is not part of the
// dependency graph and it code will just be prepended to the bundle modules),
// we need to wrap it differently than a commonJS module (also, scripts do
// not have dependencies).
if (file.type === 'js/script') {
dependencies = [];
wrappedAst = JsFileWrapping_1.default.wrapPolyfill(ast);
}
else {
try {
const opts = {
asyncRequireModulePath: config.asyncRequireModulePath,
dependencyTransformer: config.unstable_disableModuleWrapping === true
? disabledDependencyTransformer
: undefined,
dynamicRequires: getDynamicDepsBehavior(config.dynamicDepsInPackages, file.filename),
inlineableCalls: [importDefault, importAll],
keepRequireNames: options.dev,
allowOptionalDependencies: config.allowOptionalDependencies,
dependencyMapName: config.unstable_dependencyMapReservedName,
unstable_allowRequireContext: config.unstable_allowRequireContext,
};
({ ast, dependencies, dependencyMapName } = (0, collectDependencies_1.default)(ast, opts));
}
catch (error) {
if (error instanceof collectDependencies_1.InvalidRequireCallError) {
throw new InvalidRequireCallError(error, file.filename);
}
throw error;
}
if (config.unstable_disableModuleWrapping === true) {
wrappedAst = ast;
}
else {
// TODO: Replace this with a cheaper transform that doesn't require AST.
({ ast: wrappedAst } = JsFileWrapping_1.default.wrapModule(ast, importDefault, importAll, dependencyMapName, config.globalPrefix,
// TODO: This config is optional to allow its introduction in a minor
// release. It should be made non-optional in ConfigT or removed in
// future.
// @ts-expect-error: Not on types yet (Metro 0.80.9).
config.unstable_renameRequire === false));
}
}
const reserved = [];
if (config.unstable_dependencyMapReservedName != null) {
reserved.push(config.unstable_dependencyMapReservedName);
}
const minify = (0, resolveOptions_1.shouldMinify)(options);
if (minify &&
file.inputFileSize <= config.optimizationSizeLimit &&
!config.unstable_disableNormalizePseudoGlobals) {
// NOTE(EvanBacon): Simply pushing this function will mutate the AST, so it must run before the `generate` step!!
reserved.push(...metro_transform_plugins_1.default.normalizePseudoGlobals(wrappedAst, {
reservedNames: reserved,
}));
}
const result = (0, generator_1.default)(wrappedAst, {
comments: true,
compact: config.unstable_compactOutput,
filename: file.filename,
retainLines: false,
sourceFileName: file.filename,
sourceMaps: true,
}, file.code);
// @ts-expect-error: incorrectly typed upstream
let map = result.rawMappings ? result.rawMappings.map(metro_source_map_1.toSegmentTuple) : [];
let code = result.code;
if (minify) {
({ map, code } = await minifyCode(config, projectRoot, file.filename, result.code, file.code, map, reserved));
}
const output = [
{
data: {
code,
lineCount: (0, countLines_1.default)(code),
map,
functionMap: file.functionMap,
},
type: file.type,
},
];
return {
dependencies,
output,
};
}
/** Transforms an asset file. */
async function transformAsset(file, context) {
const { assetRegistryPath, assetPlugins } = context.config;
// TODO: Add web asset hashing in production.
const result = await assetTransformer.transform(getBabelTransformArgs(file, context), assetRegistryPath, assetPlugins);
const jsFile = {
...file,
type: 'js/module/asset',
ast: result.ast,
functionMap: null,
};
return transformJS(jsFile, context);
}
/**
* Transforms a JavaScript file with Babel before processing the file with
* the generic JavaScript transformation.
*/
async function transformJSWithBabel(file, context) {
const { babelTransformerPath } = context.config;
const transformer = require(babelTransformerPath);
// HACK: React Compiler injects import statements and exits the Babel process which leaves the code in
// a malformed state. For now, we'll enable the experimental import support which compiles import statements
// outside of the standard Babel process.
if (!context.options.experimentalImportSupport) {
const reactCompilerFlag = context.options.customTransformOptions?.reactCompiler;
if (reactCompilerFlag === true || reactCompilerFlag === 'true') {
// @ts-expect-error: readonly.
context.options.experimentalImportSupport = true;
}
}
const transformResult = await transformer.transform(
// functionMapBabelPlugin populates metadata.metro.functionMap
getBabelTransformArgs(file, context, [metro_source_map_1.functionMapBabelPlugin]));
const jsFile = {
...file,
ast: transformResult.ast,
functionMap: transformResult.metadata?.metro?.functionMap ??
// Fallback to deprecated explicitly-generated `functionMap`
transformResult.functionMap ??
null,
};
return await transformJS(jsFile, context);
}
async function transformJSON(file, { options, config, projectRoot }) {
let code = config.unstable_disableModuleWrapping === true
? JsFileWrapping_1.default.jsonToCommonJS(file.code)
: JsFileWrapping_1.default.wrapJson(file.code, config.globalPrefix);
let map = [];
const minify = (0, resolveOptions_1.shouldMinify)(options);
if (minify) {
({ map, code } = await minifyCode(config, projectRoot, file.filename, code, file.code, map));
}
let jsType;
if (file.type === 'asset') {
jsType = 'js/module/asset';
}
else if (file.type === 'script') {
jsType = 'js/script';
}
else {
jsType = 'js/module';
}
const output = [
{
data: { code, lineCount: (0, countLines_1.default)(code), map, functionMap: null },
type: jsType,
},
];
return {
dependencies: [],
output,
};
}
function getBabelTransformArgs(file, { options, config, projectRoot }, plugins = []) {
const { inlineRequires: _, ...babelTransformerOptions } = options;
return {
filename: file.filename,
options: {
...babelTransformerOptions,
enableBabelRCLookup: config.enableBabelRCLookup,
enableBabelRuntime: config.enableBabelRuntime,
hermesParser: config.hermesParser,
projectRoot,
publicPath: config.publicPath,
globalPrefix: config.globalPrefix,
platform: babelTransformerOptions.platform ?? null,
},
plugins,
src: file.code,
};
}
async function transform(config, projectRoot, filename, data, options) {
const context = {
config,
projectRoot,
options,
};
const sourceCode = data.toString('utf8');
const { unstable_dependencyMapReservedName } = config;
if (unstable_dependencyMapReservedName != null) {
const position = sourceCode.indexOf(unstable_dependencyMapReservedName);
if (position > -1) {
throw new SyntaxError('Source code contains the reserved string `' +
unstable_dependencyMapReservedName +
'` at character offset ' +
position);
}
}
if (filename.endsWith('.json')) {
const jsonFile = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type,
};
return transformJSON(jsonFile, context);
}
if (options.type === 'asset') {
const file = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type,
};
return transformAsset(file, context);
}
const file = {
filename,
inputFileSize: data.length,
code: sourceCode,
type: options.type === 'script' ? 'js/script' : 'js/module',
functionMap: null,
};
return transformJSWithBabel(file, context);
}
exports.transform = transform;
function getCacheKey(config) {
const { babelTransformerPath, minifierPath, ...remainingConfig } = config;
const filesKey = (0, metro_cache_key_1.default)([
require.resolve(babelTransformerPath),
require.resolve(minifierPath),
require.resolve('metro-transform-worker/src/utils/getMinifier'),
require.resolve('./asset-transformer'),
require.resolve('metro/src/ModuleGraph/worker/generateImportNames'),
require.resolve('metro/src/ModuleGraph/worker/JsFileWrapping'),
...metro_transform_plugins_1.default.getTransformPluginCacheKeyFiles(),
]);
const babelTransformer = require(babelTransformerPath);
return [
filesKey,
(0, metro_cache_1.stableHash)(remainingConfig).toString('hex'),
babelTransformer.getCacheKey ? babelTransformer.getCacheKey() : '',
].join('$');
}
exports.getCacheKey = getCacheKey;
//# sourceMappingURL=metro-transform-worker.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,20 @@
type PostCSSInputConfig = {
plugins?: any[];
from?: string;
to?: string;
syntax?: string;
map?: boolean;
parser?: string;
stringifier?: string;
};
export declare function transformPostCssModule(projectRoot: string, { src, filename }: {
src: string;
filename: string;
}): Promise<{
src: string;
hasPostcss: boolean;
}>;
export declare function pluginFactory(): (plugins?: any) => Map<string, any>;
export declare function resolvePostcssConfig(projectRoot: string): PostCSSInputConfig | null;
export declare function getPostcssConfigHash(projectRoot: string): string | null;
export {};

View File

@@ -0,0 +1,207 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getPostcssConfigHash = exports.resolvePostcssConfig = exports.pluginFactory = exports.transformPostCssModule = void 0;
/**
* Copyright © 2023 650 Industries.
* Copyright JS Foundation and other contributors
*
* https://github.com/webpack-contrib/postcss-loader/
*/
const json_file_1 = __importDefault(require("@expo/json-file"));
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const resolve_from_1 = __importDefault(require("resolve-from"));
const require_1 = require("./utils/require");
const CONFIG_FILE_NAME = 'postcss.config';
const debug = require('debug')('expo:metro:transformer:postcss');
async function transformPostCssModule(projectRoot, { src, filename }) {
const inputConfig = resolvePostcssConfig(projectRoot);
if (!inputConfig) {
return { src, hasPostcss: false };
}
return {
src: await processWithPostcssInputConfigAsync(projectRoot, {
inputConfig,
src,
filename,
}),
hasPostcss: true,
};
}
exports.transformPostCssModule = transformPostCssModule;
async function processWithPostcssInputConfigAsync(projectRoot, { src, filename, inputConfig }) {
const { plugins, processOptions } = await parsePostcssConfigAsync(projectRoot, {
config: inputConfig,
resourcePath: filename,
});
debug('options:', processOptions);
debug('plugins:', plugins);
// TODO: Surely this can be cached...
const postcss = require('postcss');
const processor = postcss.default(plugins);
const { content } = await processor.process(src, processOptions);
return content;
}
async function parsePostcssConfigAsync(projectRoot, { resourcePath: file, config: { plugins: inputPlugins, map, parser, stringifier, syntax, ...config } = {}, }) {
const factory = pluginFactory();
factory(inputPlugins);
// delete config.plugins;
const plugins = [...factory()].map((item) => {
const [plugin, options] = item;
if (typeof plugin === 'string') {
return loadPlugin(projectRoot, plugin, options, file);
}
return plugin;
});
if (config.from) {
config.from = path_1.default.resolve(projectRoot, config.from);
}
if (config.to) {
config.to = path_1.default.resolve(projectRoot, config.to);
}
const processOptions = {
from: file,
to: file,
map: false,
};
if (typeof parser === 'string') {
try {
processOptions.parser = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, parser) ?? parser);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${parser}" parser failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
if (typeof stringifier === 'string') {
try {
processOptions.stringifier = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, stringifier) ?? stringifier);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${stringifier}" stringifier failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
if (typeof syntax === 'string') {
try {
processOptions.syntax = await (0, require_1.tryRequireThenImport)(resolve_from_1.default.silent(projectRoot, syntax) ?? syntax);
}
catch (error) {
throw new Error(`Loading PostCSS "${syntax}" syntax failed: ${error.message}\n\n(@${file})`);
}
}
if (map === true) {
// https://github.com/postcss/postcss/blob/master/docs/source-maps.md
processOptions.map = { inline: true };
}
return { plugins, processOptions };
}
function loadPlugin(projectRoot, plugin, options, file) {
try {
debug('load plugin:', plugin);
// e.g. `tailwindcss`
let loadedPlugin = require((0, resolve_from_1.default)(projectRoot, plugin));
if (loadedPlugin.default) {
loadedPlugin = loadedPlugin.default;
}
if (!options || !Object.keys(options).length) {
return loadedPlugin;
}
return loadedPlugin(options);
}
catch (error) {
if (error instanceof Error) {
throw new Error(`Loading PostCSS "${plugin}" plugin failed: ${error.message}\n\n(@${file})`);
}
throw error;
}
}
function pluginFactory() {
const listOfPlugins = new Map();
return (plugins) => {
if (typeof plugins === 'undefined') {
return listOfPlugins;
}
if (Array.isArray(plugins)) {
for (const plugin of plugins) {
if (Array.isArray(plugin)) {
const [name, options] = plugin;
if (typeof name !== 'string') {
throw new Error(`PostCSS plugin must be a string, but "${name}" was found. Please check your configuration.`);
}
listOfPlugins.set(name, options);
}
else if (plugin && typeof plugin === 'function') {
listOfPlugins.set(plugin, undefined);
}
else if (plugin &&
Object.keys(plugin).length === 1 &&
(typeof plugin[Object.keys(plugin)[0]] === 'object' ||
typeof plugin[Object.keys(plugin)[0]] === 'boolean') &&
plugin[Object.keys(plugin)[0]] !== null) {
const [name] = Object.keys(plugin);
const options = plugin[name];
if (options === false) {
listOfPlugins.delete(name);
}
else {
listOfPlugins.set(name, options);
}
}
else if (plugin) {
listOfPlugins.set(plugin, undefined);
}
}
}
else {
const objectPlugins = Object.entries(plugins);
for (const [name, options] of objectPlugins) {
if (options === false) {
listOfPlugins.delete(name);
}
else {
listOfPlugins.set(name, options);
}
}
}
return listOfPlugins;
};
}
exports.pluginFactory = pluginFactory;
function resolvePostcssConfig(projectRoot) {
// TODO: Maybe support platform-specific postcss config files in the future.
const jsConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.js');
if (fs_1.default.existsSync(jsConfigPath)) {
debug('load file:', jsConfigPath);
return (0, require_1.requireUncachedFile)(jsConfigPath);
}
const jsonConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.json');
if (fs_1.default.existsSync(jsonConfigPath)) {
debug('load file:', jsonConfigPath);
return json_file_1.default.read(jsonConfigPath, { json5: true });
}
return null;
}
exports.resolvePostcssConfig = resolvePostcssConfig;
function getPostcssConfigHash(projectRoot) {
// TODO: Maybe recurse plugins and add versions to the hash in the future.
const { stableHash } = require('metro-cache');
const jsConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.js');
if (fs_1.default.existsSync(jsConfigPath)) {
return stableHash(fs_1.default.readFileSync(jsConfigPath, 'utf8')).toString('hex');
}
const jsonConfigPath = path_1.default.join(projectRoot, CONFIG_FILE_NAME + '.json');
if (fs_1.default.existsSync(jsonConfigPath)) {
return stableHash(fs_1.default.readFileSync(jsonConfigPath, 'utf8')).toString('hex');
}
return null;
}
exports.getPostcssConfigHash = getPostcssConfigHash;
//# sourceMappingURL=postcss.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,2 @@
import { JsTransformOptions } from 'metro-transform-worker';
export declare function shouldMinify(options: Pick<JsTransformOptions, 'unstable_transformProfile' | 'customTransformOptions' | 'minify'>): boolean;

View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.shouldMinify = void 0;
function isHermesEngine(options) {
// NOTE: This has multiple inputs since we also use the `customTransformOptions.engine` option to indicate the Hermes engine.
return (options.unstable_transformProfile === 'hermes-canary' ||
options.unstable_transformProfile === 'hermes-stable');
}
function isBytecodeEnabled(options) {
return (options.customTransformOptions?.bytecode === true ||
options.customTransformOptions?.bytecode === 'true');
}
function shouldMinify(options) {
// If using Hermes + bytecode, then skip minification because the Hermes compiler will minify the code.
if (isHermesEngine(options) && isBytecodeEnabled(options)) {
return false;
}
return options.minify;
}
exports.shouldMinify = shouldMinify;
//# sourceMappingURL=resolveOptions.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"resolveOptions.js","sourceRoot":"","sources":["../../src/transform-worker/resolveOptions.ts"],"names":[],"mappings":";;;AAEA,SAAS,cAAc,CAAC,OAA8D;IACpF,6HAA6H;IAC7H,OAAO,CACL,OAAO,CAAC,yBAAyB,KAAK,eAAe;QACrD,OAAO,CAAC,yBAAyB,KAAK,eAAe,CACtD,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,OAA2D;IACpF,OAAO,CACL,OAAO,CAAC,sBAAsB,EAAE,QAAQ,KAAK,IAAI;QACjD,OAAO,CAAC,sBAAsB,EAAE,QAAQ,KAAK,MAAM,CACpD,CAAC;AACJ,CAAC;AAED,SAAgB,YAAY,CAC1B,OAGC;IAED,uGAAuG;IACvG,IAAI,cAAc,CAAC,OAAO,CAAC,IAAI,iBAAiB,CAAC,OAAO,CAAC,EAAE;QACzD,OAAO,KAAK,CAAC;KACd;IAED,OAAO,OAAO,CAAC,MAAM,CAAC;AACxB,CAAC;AAZD,oCAYC"}

View File

@@ -0,0 +1,9 @@
/// <reference types="source-map-js" />
export declare function matchSass(filename: string): import('sass').Syntax | null;
export declare function compileSass(projectRoot: string, { filename, src }: {
filename: string;
src: string;
}, options?: Partial<import('sass').StringOptions<'sync'>>): {
src: string;
map: import("source-map-js").RawSourceMap | undefined;
};

View File

@@ -0,0 +1,41 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.compileSass = exports.matchSass = void 0;
const resolve_from_1 = __importDefault(require("resolve-from"));
let sassInstance = null;
function getSassInstance(projectRoot) {
if (!sassInstance) {
const sassPath = resolve_from_1.default.silent(projectRoot, 'sass');
if (!sassPath) {
throw new Error(`Cannot parse Sass files without the module 'sass' installed. Run 'yarn add sass' and try again.`);
}
sassInstance = require(sassPath);
}
return sassInstance;
}
function matchSass(filename) {
if (filename.endsWith('.sass')) {
return 'indented';
}
else if (filename.endsWith('.scss')) {
return 'scss';
}
return null;
}
exports.matchSass = matchSass;
function compileSass(projectRoot, { filename, src },
// TODO: Expose to users somehow...
options) {
const sass = getSassInstance(projectRoot);
const result = sass.compileString(src, options);
return {
src: result.css,
// TODO: Should we use this? Leaning towards no since the CSS will be parsed again by the CSS loader.
map: result.sourceMap,
};
}
exports.compileSass = compileSass;
//# sourceMappingURL=sass.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"sass.js","sourceRoot":"","sources":["../../src/transform-worker/sass.ts"],"names":[],"mappings":";;;;;;AAAA,gEAAuC;AAEvC,IAAI,YAAY,GAAiC,IAAI,CAAC;AAEtD,SAAS,eAAe,CAAC,WAAmB;IAC1C,IAAI,CAAC,YAAY,EAAE;QACjB,MAAM,QAAQ,GAAG,sBAAW,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QAEzD,IAAI,CAAC,QAAQ,EAAE;YACb,MAAM,IAAI,KAAK,CACb,iGAAiG,CAClG,CAAC;SACH;QAED,YAAY,GAAG,OAAO,CAAC,QAAQ,CAA0B,CAAC;KAC3D;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAgB,SAAS,CAAC,QAAgB;IACxC,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QAC9B,OAAO,UAAU,CAAC;KACnB;SAAM,IAAI,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE;QACrC,OAAO,MAAM,CAAC;KACf;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAPD,8BAOC;AAED,SAAgB,WAAW,CACzB,WAAmB,EACnB,EAAE,QAAQ,EAAE,GAAG,EAAqC;AACpD,mCAAmC;AACnC,OAAuD;IAEvD,MAAM,IAAI,GAAG,eAAe,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAChD,OAAO;QACL,GAAG,EAAE,MAAM,CAAC,GAAG;QACf,qGAAqG;QACrG,GAAG,EAAE,MAAM,CAAC,SAAS;KACtB,CAAC;AACJ,CAAC;AAbD,kCAaC"}

View File

@@ -0,0 +1,3 @@
/// <reference types="node" />
import type { JsTransformerConfig, JsTransformOptions, TransformResponse } from 'metro-transform-worker';
export declare function transform(config: JsTransformerConfig, projectRoot: string, filename: string, data: Buffer, options: JsTransformOptions): Promise<TransformResponse>;

View File

@@ -0,0 +1,184 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transform = void 0;
/**
* Copyright 2023-present 650 Industries (Expo). All rights reserved.
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const countLines_1 = __importDefault(require("metro/src/lib/countLines"));
const css_1 = require("./css");
const css_modules_1 = require("./css-modules");
const worker = __importStar(require("./metro-transform-worker"));
const postcss_1 = require("./postcss");
const sass_1 = require("./sass");
async function transform(config, projectRoot, filename, data, options) {
const isCss = options.type !== 'asset' && /\.(s?css|sass)$/.test(filename);
// If the file is not CSS, then use the default behavior.
if (!isCss) {
const environment = options.customTransformOptions?.environment;
const isClientEnvironment = environment !== 'node' && environment !== 'react-server';
if (isClientEnvironment &&
// TODO: Ensure this works with windows.
(filename.match(new RegExp(`^app/\\+html(\\.${options.platform})?\\.([tj]sx?|[cm]js)?$`)) ||
// Strip +api files.
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/))) {
// Remove the server-only +html file and API Routes from the bundle when bundling for a client environment.
return worker.transform(config, projectRoot, filename, !options.minify
? Buffer.from(
// Use a string so this notice is visible in the bundle if the user is
// looking for it.
'"> The server-only file was removed from the client JS bundle by Expo CLI."')
: Buffer.from(''), options);
}
if (isClientEnvironment &&
!filename.match(/\/node_modules\//) &&
filename.match(/\+api(\.(native|ios|android|web))?\.[tj]sx?$/)) {
// Clear the contents of +api files when bundling for the client.
// This ensures that the client doesn't accidentally use the server-only +api files.
return worker.transform(config, projectRoot, filename, Buffer.from(''), options);
}
return worker.transform(config, projectRoot, filename, data, options);
}
// If the platform is not web, then return an empty module.
if (options.platform !== 'web') {
const code = (0, css_modules_1.matchCssModule)(filename) ? 'module.exports={ unstable_styles: {} };' : '';
return worker.transform(config, projectRoot, filename,
// TODO: Native CSS Modules
Buffer.from(code), options);
}
let code = data.toString('utf8');
// Apply postcss transforms
const postcssResults = await (0, postcss_1.transformPostCssModule)(projectRoot, {
src: code,
filename,
});
if (postcssResults.hasPostcss) {
code = postcssResults.src;
}
// TODO: When native has CSS support, this will need to move higher up.
const syntax = (0, sass_1.matchSass)(filename);
if (syntax) {
code = (0, sass_1.compileSass)(projectRoot, { filename, src: code }, { syntax }).src;
}
// If the file is a CSS Module, then transform it to a JS module
// in development and a static CSS file in production.
if ((0, css_modules_1.matchCssModule)(filename)) {
const results = await (0, css_modules_1.transformCssModuleWeb)({
filename,
src: code,
options: {
projectRoot,
dev: options.dev,
minify: options.minify,
sourceMap: false,
},
});
const jsModuleResults = await worker.transform(config, projectRoot, filename, Buffer.from(results.output), options);
const cssCode = results.css.toString();
const output = [
{
type: 'js/module',
data: {
...jsModuleResults.output[0]?.data,
// Append additional css metadata for static extraction.
css: {
code: cssCode,
lineCount: (0, countLines_1.default)(cssCode),
map: [],
functionMap: null,
},
},
},
];
return {
dependencies: jsModuleResults.dependencies,
output,
};
}
// Global CSS:
const { transform } = require('lightningcss');
// TODO: Add bundling to resolve imports
// https://lightningcss.dev/bundling.html#bundling-order
const cssResults = transform({
filename,
code: Buffer.from(code),
sourceMap: false,
cssModules: false,
projectRoot,
minify: options.minify,
});
// TODO: Warnings:
// cssResults.warnings.forEach((warning) => {
// });
// Create a mock JS module that exports an empty object,
// this ensures Metro dependency graph is correct.
const jsModuleResults = await worker.transform(config, projectRoot, filename, options.dev ? Buffer.from((0, css_1.wrapDevelopmentCSS)({ src: code, filename })) : Buffer.from(''), options);
const cssCode = cssResults.code.toString();
// In production, we export the CSS as a string and use a special type to prevent
// it from being included in the JS bundle. We'll extract the CSS like an asset later
// and append it to the HTML bundle.
const output = [
{
type: 'js/module',
data: {
...jsModuleResults.output[0].data,
// Append additional css metadata for static extraction.
css: {
code: cssCode,
lineCount: (0, countLines_1.default)(cssCode),
map: [],
functionMap: null,
// Disable caching for CSS files when postcss is enabled and has been run on the file.
// This ensures that things like tailwind can update on every change.
skipCache: postcssResults.hasPostcss,
},
},
},
];
return {
dependencies: jsModuleResults.dependencies,
output,
};
}
exports.transform = transform;
/**
* A custom Metro transformer that adds support for processing Expo-specific bundler features.
* - Global CSS files on web.
* - CSS Modules on web.
* - TODO: Tailwind CSS on web.
*/
module.exports = {
// Use defaults for everything that's not custom.
...worker,
transform,
};
//# sourceMappingURL=transform-worker.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transform-worker.js","sourceRoot":"","sources":["../../src/transform-worker/transform-worker.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;GAMG;AACH,0EAAkD;AAOlD,+BAA2C;AAC3C,+CAAsE;AACtE,iEAAmD;AACnD,uCAAmD;AACnD,iCAAgD;AAGzC,KAAK,UAAU,SAAS,CAC7B,MAA2B,EAC3B,WAAmB,EACnB,QAAgB,EAChB,IAAY,EACZ,OAA2B;IAE3B,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,KAAK,OAAO,IAAI,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IAC3E,yDAAyD;IACzD,IAAI,CAAC,KAAK,EAAE;QACV,MAAM,WAAW,GAAG,OAAO,CAAC,sBAAsB,EAAE,WAAW,CAAC;QAChE,MAAM,mBAAmB,GAAG,WAAW,KAAK,MAAM,IAAI,WAAW,KAAK,cAAc,CAAC;QACrF,IACE,mBAAmB;YACnB,wCAAwC;YACxC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,mBAAmB,OAAO,CAAC,QAAQ,yBAAyB,CAAC,CAAC;gBACvF,oBAAoB;gBACpB,QAAQ,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC,EACjE;YACA,2GAA2G;YAC3G,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ,EACR,CAAC,OAAO,CAAC,MAAM;gBACb,CAAC,CAAC,MAAM,CAAC,IAAI;gBACT,sEAAsE;gBACtE,kBAAkB;gBAClB,6EAA6E,CAC9E;gBACH,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EACnB,OAAO,CACR,CAAC;SACH;QAED,IACE,mBAAmB;YACnB,CAAC,QAAQ,CAAC,KAAK,CAAC,kBAAkB,CAAC;YACnC,QAAQ,CAAC,KAAK,CAAC,8CAA8C,CAAC,EAC9D;YACA,iEAAiE;YACjE,oFAAoF;YACpF,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,OAAO,CAAC,CAAC;SAClF;QAED,OAAO,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;KACvE;IAED,2DAA2D;IAC3D,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE;QAC9B,MAAM,IAAI,GAAG,IAAA,4BAAc,EAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,yCAAyC,CAAC,CAAC,CAAC,EAAE,CAAC;QACvF,OAAO,MAAM,CAAC,SAAS,CACrB,MAAM,EACN,WAAW,EACX,QAAQ;QACR,2BAA2B;QAC3B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EACjB,OAAO,CACR,CAAC;KACH;IAED,IAAI,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAEjC,2BAA2B;IAC3B,MAAM,cAAc,GAAG,MAAM,IAAA,gCAAsB,EAAC,WAAW,EAAE;QAC/D,GAAG,EAAE,IAAI;QACT,QAAQ;KACT,CAAC,CAAC;IAEH,IAAI,cAAc,CAAC,UAAU,EAAE;QAC7B,IAAI,GAAG,cAAc,CAAC,GAAG,CAAC;KAC3B;IAED,uEAAuE;IACvE,MAAM,MAAM,GAAG,IAAA,gBAAS,EAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,MAAM,EAAE;QACV,IAAI,GAAG,IAAA,kBAAW,EAAC,WAAW,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC;KAC1E;IAED,gEAAgE;IAChE,sDAAsD;IACtD,IAAI,IAAA,4BAAc,EAAC,QAAQ,CAAC,EAAE;QAC5B,MAAM,OAAO,GAAG,MAAM,IAAA,mCAAqB,EAAC;YAC1C,QAAQ;YACR,GAAG,EAAE,IAAI;YACT,OAAO,EAAE;gBACP,WAAW;gBACX,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,MAAM,EAAE,OAAO,CAAC,MAAM;gBACtB,SAAS,EAAE,KAAK;aACjB;SACF,CAAC,CAAC;QAEH,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,SAAS,CAC5C,MAAM,EACN,WAAW,EACX,QAAQ,EACR,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,EAC3B,OAAO,CACR,CAAC;QAEF,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAe;YACzB;gBACE,IAAI,EAAE,WAAW;gBACjB,IAAI,EAAE;oBACJ,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,IAAI;oBAElC,wDAAwD;oBACxD,GAAG,EAAE;wBACH,IAAI,EAAE,OAAO;wBACb,SAAS,EAAE,IAAA,oBAAU,EAAC,OAAO,CAAC;wBAC9B,GAAG,EAAE,EAAE;wBACP,WAAW,EAAE,IAAI;qBAClB;iBACF;aACF;SACF,CAAC;QAEF,OAAO;YACL,YAAY,EAAE,eAAe,CAAC,YAAY;YAC1C,MAAM;SACP,CAAC;KACH;IAED,cAAc;IAEd,MAAM,EAAE,SAAS,EAAE,GAAG,OAAO,CAAC,cAAc,CAAkC,CAAC;IAE/E,wCAAwC;IACxC,wDAAwD;IAExD,MAAM,UAAU,GAAG,SAAS,CAAC;QAC3B,QAAQ;QACR,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;QACvB,SAAS,EAAE,KAAK;QAChB,UAAU,EAAE,KAAK;QACjB,WAAW;QACX,MAAM,EAAE,OAAO,CAAC,MAAM;KACvB,CAAC,CAAC;IAEH,kBAAkB;IAClB,6CAA6C;IAC7C,MAAM;IAEN,wDAAwD;IACxD,kDAAkD;IAClD,MAAM,eAAe,GAAG,MAAM,MAAM,CAAC,SAAS,CAC5C,MAAM,EACN,WAAW,EACX,QAAQ,EACR,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAA,wBAAkB,EAAC,EAAE,GAAG,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,EACxF,OAAO,CACR,CAAC;IAEF,MAAM,OAAO,GAAG,UAAU,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;IAE3C,iFAAiF;IACjF,qFAAqF;IACrF,oCAAoC;IACpC,MAAM,MAAM,GAAmB;QAC7B;YACE,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE;gBACJ,GAAI,eAAe,CAAC,MAAM,CAAC,CAAC,CAAkB,CAAC,IAAI;gBAEnD,wDAAwD;gBACxD,GAAG,EAAE;oBACH,IAAI,EAAE,OAAO;oBACb,SAAS,EAAE,IAAA,oBAAU,EAAC,OAAO,CAAC;oBAC9B,GAAG,EAAE,EAAE;oBACP,WAAW,EAAE,IAAI;oBACjB,sFAAsF;oBACtF,qEAAqE;oBACrE,SAAS,EAAE,cAAc,CAAC,UAAU;iBACrC;aACF;SACF;KACF,CAAC;IAEF,OAAO;QACL,YAAY,EAAE,eAAe,CAAC,YAAY;QAC1C,MAAM;KACP,CAAC;AACJ,CAAC;AAxLD,8BAwLC;AAED;;;;;GAKG;AACH,MAAM,CAAC,OAAO,GAAG;IACf,iDAAiD;IACjD,GAAG,MAAM;IACT,SAAS;CACV,CAAC"}

View File

@@ -0,0 +1,2 @@
export declare function tryRequireThenImport<TModule>(moduleId: string): Promise<TModule>;
export declare function requireUncachedFile(moduleId: string): any;

View File

@@ -0,0 +1,40 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.requireUncachedFile = exports.tryRequireThenImport = void 0;
async function tryRequireThenImport(moduleId) {
try {
return require(moduleId);
}
catch (requireError) {
let importESM;
try {
// eslint-disable-next-line no-new-func
importESM = new Function('id', 'return import(id);');
}
catch {
importESM = null;
}
if (requireError?.code === 'ERR_REQUIRE_ESM' && importESM) {
return (await importESM(moduleId)).default;
}
throw requireError;
}
}
exports.tryRequireThenImport = tryRequireThenImport;
function requireUncachedFile(moduleId) {
try {
// delete require.cache[require.resolve(moduleId)];
}
catch { }
try {
return require(moduleId);
}
catch (error) {
if (error instanceof Error) {
error.message = `Cannot load file ${moduleId}: ${error.message}`;
}
throw error;
}
}
exports.requireUncachedFile = requireUncachedFile;
//# sourceMappingURL=require.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"require.js","sourceRoot":"","sources":["../../../src/transform-worker/utils/require.ts"],"names":[],"mappings":";;;AAAO,KAAK,UAAU,oBAAoB,CAAU,QAAgB;IAClE,IAAI;QACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC1B;IAAC,OAAO,YAAiB,EAAE;QAC1B,IAAI,SAAS,CAAC;QACd,IAAI;YACF,uCAAuC;YACvC,SAAS,GAAG,IAAI,QAAQ,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC;SACtD;QAAC,MAAM;YACN,SAAS,GAAG,IAAI,CAAC;SAClB;QAED,IAAI,YAAY,EAAE,IAAI,KAAK,iBAAiB,IAAI,SAAS,EAAE;YACzD,OAAO,CAAC,MAAM,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC;SAC5C;QAED,MAAM,YAAY,CAAC;KACpB;AACH,CAAC;AAlBD,oDAkBC;AAED,SAAgB,mBAAmB,CAAC,QAAgB;IAClD,IAAI;QACF,mDAAmD;KACpD;IAAC,MAAM,GAAE;IACV,IAAI;QACF,OAAO,OAAO,CAAC,QAAQ,CAAC,CAAC;KAC1B;IAAC,OAAO,KAAc,EAAE;QACvB,IAAI,KAAK,YAAY,KAAK,EAAE;YAC1B,KAAK,CAAC,OAAO,GAAG,oBAAoB,QAAQ,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;SAClE;QACD,MAAM,KAAK,CAAC;KACb;AACH,CAAC;AAZD,kDAYC"}

View File

@@ -0,0 +1,10 @@
/**
* Copyright (c) 650 Industries (Expo). All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import * as babel from './babel-core';
export declare function transformSync(src: string, babelConfig: babel.TransformOptions, { hermesParser }: {
hermesParser?: boolean;
}): import("@babel/core").BabelFileResult | null;

View File

@@ -0,0 +1,59 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformSync = void 0;
/**
* Copyright (c) 650 Industries (Expo). All rights reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
const babel = __importStar(require("./babel-core"));
// TS detection conditions copied from @react-native/babel-preset
function isTypeScriptSource(fileName) {
return fileName?.endsWith('.ts');
}
function isTSXSource(fileName) {
return fileName?.endsWith('.tsx');
}
function transformSync(src, babelConfig, { hermesParser }) {
const useBabelCore = isTypeScriptSource(babelConfig.filename) ||
isTSXSource(babelConfig.filename) ||
!hermesParser;
const parser = useBabelCore ? parseWithBabel : parseWithHermes;
return parser(src, babelConfig);
}
exports.transformSync = transformSync;
function parseWithHermes(src, babelConfig) {
const sourceAst = require('hermes-parser').parse(src, {
babel: true,
sourceType: babelConfig.sourceType,
});
return babel.transformFromAstSync(sourceAst, src, babelConfig);
}
function parseWithBabel(src, babelConfig) {
return babel.transformSync(src, babelConfig);
}
//# sourceMappingURL=transformSync.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"transformSync.js","sourceRoot":"","sources":["../src/transformSync.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;GAKG;AACH,oDAAsC;AAEtC,iEAAiE;AACjE,SAAS,kBAAkB,CAAC,QAAgB;IAC1C,OAAO,QAAQ,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC;AACnC,CAAC;AAED,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED,SAAgB,aAAa,CAC3B,GAAW,EACX,WAAmC,EACnC,EAAE,YAAY,EAA8B;IAE5C,MAAM,YAAY,GAChB,kBAAkB,CAAC,WAAW,CAAC,QAAS,CAAC;QACzC,WAAW,CAAC,WAAW,CAAC,QAAS,CAAC;QAClC,CAAC,YAAY,CAAC;IAEhB,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,eAAe,CAAC;IAE/D,OAAO,MAAM,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAClC,CAAC;AAbD,sCAaC;AAED,SAAS,eAAe,CAAC,GAAW,EAAE,WAAmC;IACvE,MAAM,SAAS,GAAG,OAAO,CAAC,eAAe,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE;QACpD,KAAK,EAAE,IAAI;QACX,UAAU,EAAE,WAAW,CAAC,UAAU;KACnC,CAAC,CAAC;IACH,OAAO,KAAK,CAAC,oBAAoB,CAAC,SAAS,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,cAAc,CAAC,GAAW,EAAE,WAAmC;IACtE,OAAO,KAAK,CAAC,aAAa,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;AAC/C,CAAC"}

View File

@@ -0,0 +1,3 @@
export declare function importMetroConfig(projectRoot: string): typeof import('metro-config') & {
getDefaultConfig: import('metro-config/src/defaults/index').default;
};

Some files were not shown because too many files have changed in this diff Show More