FRE-600: Fix code review blockers

- Consolidated duplicate UndoManagers to single instance
- Fixed connection promise to only resolve on 'connected' status
- Fixed WebSocketProvider import (WebsocketProvider)
- Added proper doc.destroy() cleanup
- Renamed isPresenceInitialized property to avoid conflict

Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
2026-04-25 00:08:01 -04:00
parent 65b552bb08
commit 7c684a42cc
48450 changed files with 5679671 additions and 383 deletions

View File

@@ -0,0 +1,27 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<e21aeb433f191f32b37d05733b0b76bd>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/baseJSBundle.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module, ReadOnlyGraph, SerializerOptions} from '../types';
import type {Bundle} from 'metro-runtime/src/modules/types';
declare function baseJSBundle(
entryPoint: string,
preModules: ReadonlyArray<Module>,
graph: ReadOnlyGraph,
options: SerializerOptions,
): Bundle;
export default baseJSBundle;

View File

@@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = baseJSBundle;
var _getAppendScripts = _interopRequireDefault(
require("../../lib/getAppendScripts"),
);
var _processModules = _interopRequireDefault(
require("./helpers/processModules"),
);
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
function baseJSBundle(entryPoint, preModules, graph, options) {
for (const module of graph.dependencies.values()) {
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,
};
if (options.modulesOnly) {
preModules = [];
}
const preCode = (0, _processModules.default)(
preModules,
processModulesOptions,
)
.map(([_, code]) => code)
.join("\n");
const modules = [...graph.dependencies.values()].sort(
(a, b) => options.createModuleId(a.path) - options.createModuleId(b.path),
);
const postCode = (0, _processModules.default)(
(0, _getAppendScripts.default)(entryPoint, [...preModules, ...modules], {
asyncRequireModulePath: options.asyncRequireModulePath,
createModuleId: options.createModuleId,
getRunModuleStatement: options.getRunModuleStatement,
globalPrefix: options.globalPrefix,
inlineSourceMap: options.inlineSourceMap,
runBeforeMainModule: options.runBeforeMainModule,
runModule: options.runModule,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
sourceMapUrl: options.sourceMapUrl,
sourceUrl: options.sourceUrl,
getSourceUrl: options.getSourceUrl,
}),
processModulesOptions,
)
.map(([_, code]) => code)
.join("\n");
return {
pre: preCode,
post: postCode,
modules: (0, _processModules.default)(
[...graph.dependencies.values()],
processModulesOptions,
).map(([module, code]) => [options.createModuleId(module.path), code]),
};
}

View File

@@ -0,0 +1,84 @@
/**
* 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.
*
* @flow
* @format
* @oncall react_native
*/
import type {
MixedOutput,
Module,
ReadOnlyGraph,
SerializerOptions,
} from '../types';
import type {Bundle} from 'metro-runtime/src/modules/types';
import getAppendScripts from '../../lib/getAppendScripts';
import processModules from './helpers/processModules';
export default function baseJSBundle(
entryPoint: string,
preModules: ReadonlyArray<Module<>>,
graph: ReadOnlyGraph<>,
options: SerializerOptions,
): Bundle {
for (const module of graph.dependencies.values()) {
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,
};
// Do not prepend polyfills or the require runtime when only modules are requested
if (options.modulesOnly) {
preModules = [];
}
const preCode = processModules(preModules, processModulesOptions)
.map(([_, code]) => code)
.join('\n');
const modules = [...graph.dependencies.values()].sort(
(a: Module<MixedOutput>, b: Module<MixedOutput>) =>
options.createModuleId(a.path) - options.createModuleId(b.path),
);
const postCode = processModules(
getAppendScripts(entryPoint, [...preModules, ...modules], {
asyncRequireModulePath: options.asyncRequireModulePath,
createModuleId: options.createModuleId,
getRunModuleStatement: options.getRunModuleStatement,
globalPrefix: options.globalPrefix,
inlineSourceMap: options.inlineSourceMap,
runBeforeMainModule: options.runBeforeMainModule,
runModule: options.runModule,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
sourceMapUrl: options.sourceMapUrl,
sourceUrl: options.sourceUrl,
getSourceUrl: options.getSourceUrl,
}),
processModulesOptions,
)
.map(([_, code]) => code)
.join('\n');
return {
pre: preCode,
post: postCode,
modules: processModules(
[...graph.dependencies.values()],
processModulesOptions,
).map(([module, code]) => [options.createModuleId(module.path), code]),
};
}

View File

@@ -0,0 +1,29 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<1d044a890d1eebbef947f78609d7c58f>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/getAllFiles.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module, ReadOnlyGraph} from '../types';
type Options = {
platform: null | undefined | string;
readonly processModuleFilter: (module: Module) => boolean;
};
declare function getAllFiles(
pre: ReadonlyArray<Module>,
graph: ReadOnlyGraph,
options: Options,
): Promise<ReadonlyArray<string>>;
export default getAllFiles;

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getAllFiles;
var _Assets = require("../../Assets");
var _js = require("./helpers/js");
async function getAllFiles(pre, graph, options) {
const modules = graph.dependencies;
const { processModuleFilter } = options;
const promises = [];
for (const module of pre) {
if (processModuleFilter(module)) {
promises.push([module.path]);
}
}
for (const module of modules.values()) {
if (!(0, _js.isJsModule)(module) || !processModuleFilter(module)) {
continue;
}
if ((0, _js.getJsOutput)(module).type === "js/module/asset") {
promises.push((0, _Assets.getAssetFiles)(module.path, options.platform));
} else {
promises.push([module.path]);
}
}
const dependencies = await Promise.all(promises);
const output = [];
for (const dependencyArray of dependencies) {
output.push(...dependencyArray);
}
return output;
}

View File

@@ -0,0 +1,58 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module, ReadOnlyGraph} from '../types';
import {getAssetFiles} from '../../Assets';
import {getJsOutput, isJsModule} from './helpers/js';
type Options = {
platform: ?string,
+processModuleFilter: (module: Module<>) => boolean,
};
export default async function getAllFiles(
pre: ReadonlyArray<Module<>>,
graph: ReadOnlyGraph<>,
options: Options,
): Promise<ReadonlyArray<string>> {
const modules = graph.dependencies;
const {processModuleFilter} = options;
const promises: Array<Promise<Array<string>> | Array<string>> = [];
for (const module of pre) {
if (processModuleFilter(module)) {
promises.push([module.path]);
}
}
for (const module of modules.values()) {
if (!isJsModule(module) || !processModuleFilter(module)) {
continue;
}
if (getJsOutput(module).type === 'js/module/asset') {
promises.push(getAssetFiles(module.path, options.platform));
} else {
promises.push([module.path]);
}
}
const dependencies = await Promise.all(promises);
const output: Array<string> = [];
for (const dependencyArray of dependencies) {
output.push(...dependencyArray);
}
return output;
}

View File

@@ -0,0 +1,32 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<0a49d828c4a80d52ccab4d4766b84c86>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/getAssets.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {AssetData} from '../../Assets';
import type {Module, ReadOnlyDependencies} from '../types';
type Options = {
readonly processModuleFilter: (module: Module) => boolean;
assetPlugins: ReadonlyArray<string>;
platform: null | undefined | string;
projectRoot: string;
publicPath: string;
};
declare function getAssets(
dependencies: ReadOnlyDependencies,
options: Options,
): Promise<ReadonlyArray<AssetData>>;
export default getAssets;

View File

@@ -0,0 +1,36 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getAssets;
var _Assets = require("../../Assets");
var _js = require("./helpers/js");
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
async function getAssets(dependencies, options) {
const promises = [];
const { processModuleFilter } = options;
for (const module of dependencies.values()) {
if (
(0, _js.isJsModule)(module) &&
processModuleFilter(module) &&
(0, _js.getJsOutput)(module).type === "js/module/asset" &&
_path.default.relative(options.projectRoot, module.path) !==
"package.json"
) {
promises.push(
(0, _Assets.getAssetData)(
module.path,
_path.default.relative(options.projectRoot, module.path),
options.assetPlugins,
options.platform,
options.publicPath,
),
);
}
}
return await Promise.all(promises);
}

View File

@@ -0,0 +1,54 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {AssetData} from '../../Assets';
import type {Module, ReadOnlyDependencies} from '../types';
import {getAssetData} from '../../Assets';
import {getJsOutput, isJsModule} from './helpers/js';
import path from 'path';
type Options = {
+processModuleFilter: (module: Module<>) => boolean,
assetPlugins: ReadonlyArray<string>,
platform: ?string,
projectRoot: string,
publicPath: string,
};
export default async function getAssets(
dependencies: ReadOnlyDependencies<>,
options: Options,
): Promise<ReadonlyArray<AssetData>> {
const promises = [];
const {processModuleFilter} = options;
for (const module of dependencies.values()) {
if (
isJsModule(module) &&
processModuleFilter(module) &&
getJsOutput(module).type === 'js/module/asset' &&
path.relative(options.projectRoot, module.path) !== 'package.json'
) {
promises.push(
getAssetData(
module.path,
path.relative(options.projectRoot, module.path),
options.assetPlugins,
options.platform,
options.publicPath,
),
);
}
}
return await Promise.all(promises);
}

View File

@@ -0,0 +1,33 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<623892927b76c4f68802bb69f19d9974>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/getExplodedSourceMap.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../types';
import type {
FBSourceFunctionMap,
MetroSourceMapSegmentTuple,
} from 'metro-source-map';
export type ExplodedSourceMap = ReadonlyArray<{
readonly map: Array<MetroSourceMapSegmentTuple>;
readonly firstLine1Based: number;
readonly functionMap: null | undefined | FBSourceFunctionMap;
readonly path: string;
}>;
export declare function getExplodedSourceMap(
modules: ReadonlyArray<Module>,
options: {readonly processModuleFilter: (module: Module) => boolean},
): ExplodedSourceMap;

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.getExplodedSourceMap = getExplodedSourceMap;
var _js = require("./helpers/js");
function getExplodedSourceMap(modules, options) {
const modulesToProcess = modules
.filter(_js.isJsModule)
.filter(options.processModuleFilter);
const result = [];
let firstLine1Based = 1;
for (const module of modulesToProcess) {
const { path } = module;
const { lineCount, functionMap, map } = (0, _js.getJsOutput)(module).data;
result.push({
firstLine1Based,
functionMap,
path,
map,
});
firstLine1Based += lineCount;
}
return result;
}

View File

@@ -0,0 +1,47 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../types';
import type {
FBSourceFunctionMap,
MetroSourceMapSegmentTuple,
} from 'metro-source-map';
import {getJsOutput, isJsModule} from './helpers/js';
export type ExplodedSourceMap = ReadonlyArray<{
+map: Array<MetroSourceMapSegmentTuple>,
+firstLine1Based: number,
+functionMap: ?FBSourceFunctionMap,
+path: string,
}>;
export function getExplodedSourceMap(
modules: ReadonlyArray<Module<>>,
options: {
+processModuleFilter: (module: Module<>) => boolean,
},
): ExplodedSourceMap {
const modulesToProcess = modules
.filter(isJsModule)
.filter(options.processModuleFilter);
const result = [];
let firstLine1Based = 1;
for (const module of modulesToProcess) {
const {path} = module;
const {lineCount, functionMap, map} = getJsOutput(module).data;
result.push({firstLine1Based, functionMap, path, map});
firstLine1Based += lineCount;
}
return result;
}

View File

@@ -0,0 +1,55 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<b01899b6156596978e6b8e7ba93e97a4>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/getRamBundleInfo.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {ModuleTransportLike} from '../../shared/types';
import type {Module, ReadOnlyGraph, SerializerOptions} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
import type {GetTransformOptions} from 'metro-config';
type Options = Readonly<
Omit<
SerializerOptions,
| keyof SourceMapGeneratorOptions
| keyof {
getTransformOptions: null | undefined | GetTransformOptions;
platform: null | undefined | string;
}
> &
Omit<
SourceMapGeneratorOptions,
keyof {
getTransformOptions: null | undefined | GetTransformOptions;
platform: null | undefined | string;
}
> & {
getTransformOptions: null | undefined | GetTransformOptions;
platform: null | undefined | string;
}
>;
export type RamBundleInfo = {
getDependencies: ($$PARAM_0$$: string) => Set<string>;
startupModules: ReadonlyArray<ModuleTransportLike>;
lazyModules: ReadonlyArray<ModuleTransportLike>;
groups: Map<number, Set<number>>;
};
declare function getRamBundleInfo(
entryPoint: string,
pre: ReadonlyArray<Module>,
graph: ReadOnlyGraph,
options: Options,
): Promise<RamBundleInfo>;
export default getRamBundleInfo;

View File

@@ -0,0 +1,121 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getRamBundleInfo;
var _util = require("../../Bundler/util");
var _getAppendScripts = _interopRequireDefault(
require("../../lib/getAppendScripts"),
);
var _getTransitiveDependencies = _interopRequireDefault(
require("./helpers/getTransitiveDependencies"),
);
var _js = require("./helpers/js");
var _sourceMapObject = require("./sourceMapObject");
var _nullthrows = _interopRequireDefault(require("nullthrows"));
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
async function getRamBundleInfo(entryPoint, pre, graph, options) {
let modules = [...pre, ...graph.dependencies.values()];
modules = modules.concat(
(0, _getAppendScripts.default)(entryPoint, modules, options),
);
modules.forEach((module) => options.createModuleId(module.path));
const ramModules = modules
.filter(_js.isJsModule)
.filter(options.processModuleFilter)
.map((module) => ({
id: options.createModuleId(module.path),
code: (0, _js.wrapModule)(module, options),
map: (0, _sourceMapObject.sourceMapObject)([module], {
excludeSource: options.excludeSource,
processModuleFilter: options.processModuleFilter,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
getSourceUrl: options.getSourceUrl,
}),
name: _path.default.basename(module.path),
sourcePath: module.path,
source: module.getSource().toString(),
type: (0, _nullthrows.default)(
module.output.find(({ type }) => type.startsWith("js")),
).type,
}));
const { preloadedModules, ramGroups } = await _getRamOptions(
entryPoint,
{
dev: options.dev,
platform: options.platform,
},
(filePath) => (0, _getTransitiveDependencies.default)(filePath, graph),
options.getTransformOptions,
);
const startupModules = [];
const lazyModules = [];
ramModules.forEach((module) => {
if (preloadedModules.hasOwnProperty(module.sourcePath)) {
startupModules.push(module);
return;
}
if (module.type.startsWith("js/script")) {
startupModules.push(module);
return;
}
if (module.type.startsWith("js/module")) {
lazyModules.push(module);
}
});
const groups = (0, _util.createRamBundleGroups)(
ramGroups,
lazyModules,
(module, dependenciesByPath) => {
const deps = (0, _getTransitiveDependencies.default)(
module.sourcePath,
graph,
);
const output = new Set();
for (const dependency of deps) {
const module = dependenciesByPath.get(dependency);
if (module) {
output.add(module.id);
}
}
return output;
},
);
return {
getDependencies: (filePath) =>
(0, _getTransitiveDependencies.default)(filePath, graph),
groups,
lazyModules,
startupModules,
};
}
async function _getRamOptions(
entryFile,
options,
getDependencies,
getTransformOptions,
) {
if (getTransformOptions == null) {
return {
preloadedModules: {},
ramGroups: [],
};
}
const { preloadedModules, ramGroups } = await getTransformOptions(
[entryFile],
{
dev: options.dev,
hot: true,
platform: options.platform,
},
async (x) => Array.from(getDependencies),
);
return {
preloadedModules: preloadedModules || {},
ramGroups: ramGroups || [],
};
}

View File

@@ -0,0 +1,171 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {ModuleTransportLike, RamModuleTransport} from '../../shared/types';
import type {Module, ReadOnlyGraph, SerializerOptions} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
import type {GetTransformOptions} from 'metro-config';
import {createRamBundleGroups} from '../../Bundler/util';
import getAppendScripts from '../../lib/getAppendScripts';
import getTransitiveDependencies from './helpers/getTransitiveDependencies';
import {isJsModule, wrapModule} from './helpers/js';
import {sourceMapObject} from './sourceMapObject';
import nullthrows from 'nullthrows';
import path from 'path';
type Options = Readonly<{
...SerializerOptions,
...SourceMapGeneratorOptions,
getTransformOptions: ?GetTransformOptions,
platform: ?string,
}>;
export type RamBundleInfo = {
getDependencies: string => Set<string>,
startupModules: ReadonlyArray<ModuleTransportLike>,
lazyModules: ReadonlyArray<ModuleTransportLike>,
groups: Map<number, Set<number>>,
};
export default async function getRamBundleInfo(
entryPoint: string,
pre: ReadonlyArray<Module<>>,
graph: ReadOnlyGraph<>,
options: Options,
): Promise<RamBundleInfo> {
let modules: ReadonlyArray<Module<>> = [
...pre,
...graph.dependencies.values(),
];
modules = modules.concat(getAppendScripts(entryPoint, modules, options));
modules.forEach((module: Module<>) => options.createModuleId(module.path));
const ramModules: Array<RamModuleTransport> = modules
.filter(isJsModule)
.filter(options.processModuleFilter)
.map((module: Module<>): RamModuleTransport => ({
id: options.createModuleId(module.path),
code: wrapModule(module, options),
map: sourceMapObject([module], {
excludeSource: options.excludeSource,
processModuleFilter: options.processModuleFilter,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
getSourceUrl: options.getSourceUrl,
}),
name: path.basename(module.path),
sourcePath: module.path,
source: module.getSource().toString(),
type: nullthrows(module.output.find(({type}) => type.startsWith('js')))
.type,
}));
const {preloadedModules, ramGroups} = await _getRamOptions(
entryPoint,
{
dev: options.dev,
platform: options.platform,
},
(filePath: string) => getTransitiveDependencies(filePath, graph),
options.getTransformOptions,
);
const startupModules = [];
const lazyModules = [];
ramModules.forEach((module: RamModuleTransport) => {
if (preloadedModules.hasOwnProperty(module.sourcePath)) {
startupModules.push(module);
return;
}
if (module.type.startsWith('js/script')) {
startupModules.push(module);
return;
}
if (module.type.startsWith('js/module')) {
lazyModules.push(module);
}
});
const groups = createRamBundleGroups(
ramGroups,
lazyModules,
(
module: ModuleTransportLike,
dependenciesByPath: Map<string, ModuleTransportLike>,
): Set<number> => {
const deps = getTransitiveDependencies(module.sourcePath, graph);
const output = new Set<number>();
for (const dependency of deps) {
const module = dependenciesByPath.get(dependency);
if (module) {
output.add(module.id);
}
}
return output;
},
);
return {
getDependencies: (filePath: string): Set<string> =>
getTransitiveDependencies(filePath, graph),
groups,
lazyModules,
startupModules,
};
}
/**
* Returns the options needed to create a RAM bundle.
*/
async function _getRamOptions(
entryFile: string,
options: {
dev: boolean,
platform: ?string,
...
},
getDependencies: string => Iterable<string>,
getTransformOptions: ?GetTransformOptions,
): Promise<
Readonly<{
preloadedModules: Readonly<{[string]: true, ...}>,
ramGroups: ReadonlyArray<string>,
}>,
> {
if (getTransformOptions == null) {
return {
preloadedModules: {},
ramGroups: [],
};
}
const {preloadedModules, ramGroups} = await getTransformOptions(
[entryFile],
{dev: options.dev, hot: true, platform: options.platform},
/* $FlowFixMe[incompatible-type](>=0.99.0 site=react_native_fb) This comment suppresses an
* error found when Flow v0.99 was deployed. To see the error, delete this
* comment and run Flow. */
async (x: string) => Array.from(getDependencies),
);
return {
// $FlowFixMe[sketchy-null-bool]
preloadedModules: preloadedModules || {},
ramGroups: ramGroups || [],
};
}

View File

@@ -0,0 +1,19 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<f9cd017db02091bdd4f6d114e4744087>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/helpers/getInlineSourceMappingURL.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
declare function getInlineSourceMappingURL(sourceMap: string): string;
export default getInlineSourceMappingURL;

View File

@@ -0,0 +1,10 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getInlineSourceMappingURL;
function getInlineSourceMappingURL(sourceMap) {
const base64 = Buffer.from(sourceMap).toString("base64");
return `data:application/json;charset=utf-8;base64,${base64}`;
}

View File

@@ -0,0 +1,15 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
export default function getInlineSourceMappingURL(sourceMap: string): string {
const base64 = Buffer.from(sourceMap).toString('base64');
return `data:application/json;charset=utf-8;base64,${base64}`;
}

View File

@@ -0,0 +1,40 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<cd7e523b4fdfbff33e663b21c4529401>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/helpers/getSourceMapInfo.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../../types';
import type {
FBSourceFunctionMap,
MetroSourceMapSegmentTuple,
} from 'metro-source-map';
declare function getSourceMapInfo(
module: Module,
options: {
readonly excludeSource: boolean;
readonly shouldAddToIgnoreList: ($$PARAM_0$$: Module) => boolean;
getSourceUrl: null | undefined | ((module: Module) => string);
},
): {
readonly map: Array<MetroSourceMapSegmentTuple>;
readonly functionMap: null | undefined | FBSourceFunctionMap;
readonly code: string;
readonly path: string;
readonly source: string;
readonly lineCount: number;
readonly isIgnored: boolean;
};
export default getSourceMapInfo;

View File

@@ -0,0 +1,21 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getSourceMapInfo;
var _js = require("./js");
function getSourceMapInfo(module, options) {
return {
...(0, _js.getJsOutput)(module).data,
isIgnored: options.shouldAddToIgnoreList(module),
path: options?.getSourceUrl?.(module) ?? module.path,
source: options.excludeSource ? "" : getModuleSource(module),
};
}
function getModuleSource(module) {
if ((0, _js.getJsOutput)(module).type === "js/module/asset") {
return "";
}
return module.getSource().toString();
}

View File

@@ -0,0 +1,50 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../../types';
import type {
FBSourceFunctionMap,
MetroSourceMapSegmentTuple,
} from 'metro-source-map';
import {getJsOutput} from './js';
export default function getSourceMapInfo(
module: Module<>,
options: {
+excludeSource: boolean,
+shouldAddToIgnoreList: (Module<>) => boolean,
getSourceUrl: ?(module: Module<>) => string,
},
): {
+map: Array<MetroSourceMapSegmentTuple>,
+functionMap: ?FBSourceFunctionMap,
+code: string,
+path: string,
+source: string,
+lineCount: number,
+isIgnored: boolean,
} {
return {
...getJsOutput(module).data,
isIgnored: options.shouldAddToIgnoreList(module),
path: options?.getSourceUrl?.(module) ?? module.path,
source: options.excludeSource ? '' : getModuleSource(module),
};
}
function getModuleSource(module: Module<>): string {
if (getJsOutput(module).type === 'js/module/asset') {
return '';
}
return module.getSource().toString();
}

View File

@@ -0,0 +1,24 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<55bd91c160900bb31ffe72e2ddfad85d>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/helpers/getTransitiveDependencies.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {ReadOnlyGraph} from '../../types';
declare function getTransitiveDependencies<T>(
path: string,
graph: ReadOnlyGraph<T>,
): Set<string>;
export default getTransitiveDependencies;

View File

@@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = getTransitiveDependencies;
var _isResolvedDependency = require("../../../lib/isResolvedDependency");
function getTransitiveDependencies(path, graph) {
const dependencies = _getDeps(path, graph, new Set());
dependencies.delete(path);
return dependencies;
}
function _getDeps(path, graph, deps) {
if (deps.has(path)) {
return deps;
}
const module = graph.dependencies.get(path);
if (!module) {
return deps;
}
deps.add(path);
for (const dependency of module.dependencies.values()) {
if ((0, _isResolvedDependency.isResolvedDependency)(dependency)) {
_getDeps(dependency.absolutePath, graph, deps);
}
}
return deps;
}

View File

@@ -0,0 +1,53 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {ReadOnlyGraph} from '../../types';
import {isResolvedDependency} from '../../../lib/isResolvedDependency';
export default function getTransitiveDependencies<T>(
path: string,
graph: ReadOnlyGraph<T>,
): Set<string> {
const dependencies = _getDeps(path, graph, new Set());
// Remove the main entry point, since this method only returns the
// dependencies.
dependencies.delete(path);
return dependencies;
}
function _getDeps<T>(
path: string,
graph: ReadOnlyGraph<T>,
deps: Set<string>,
): Set<string> {
if (deps.has(path)) {
return deps;
}
const module = graph.dependencies.get(path);
if (!module) {
return deps;
}
deps.add(path);
for (const dependency of module.dependencies.values()) {
if (isResolvedDependency(dependency)) {
_getDeps(dependency.absolutePath, graph, deps);
}
}
return deps;
}

View File

@@ -0,0 +1,37 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<f61e17deebe7e34585ad214ae287e704>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/helpers/js.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {MixedOutput, Module} from '../../types';
import type {JsOutput} from 'metro-transform-worker';
export type Options = Readonly<{
createModuleId: ($$PARAM_0$$: string) => number | string;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: null | undefined | string;
}>;
export declare function wrapModule(module: Module, options: Options): string;
export declare function getModuleParams(
module: Module,
options: Options,
): Array<unknown>;
export declare function getJsOutput(
module: Readonly<{output: ReadonlyArray<MixedOutput>; path?: string}>,
): JsOutput;
export declare function isJsModule(module: Module): boolean;

View File

@@ -0,0 +1,133 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.getJsOutput = getJsOutput;
exports.getModuleParams = getModuleParams;
exports.isJsModule = isJsModule;
exports.wrapModule = wrapModule;
var _isResolvedDependency = require("../../../lib/isResolvedDependency");
var _pathUtils = require("../../../lib/pathUtils");
var _invariant = _interopRequireDefault(require("invariant"));
var jscSafeUrl = _interopRequireWildcard(require("jsc-safe-url"));
var _metroTransformPlugins = require("metro-transform-plugins");
var _path = _interopRequireDefault(require("path"));
function _interopRequireWildcard(e, t) {
if ("function" == typeof WeakMap)
var r = new WeakMap(),
n = new WeakMap();
return (_interopRequireWildcard = function (e, t) {
if (!t && e && e.__esModule) return e;
var o,
i,
f = { __proto__: null, default: e };
if (null === e || ("object" != typeof e && "function" != typeof e))
return f;
if ((o = t ? n : r)) {
if (o.has(e)) return o.get(e);
o.set(e, f);
}
for (const t in e)
"default" !== t &&
{}.hasOwnProperty.call(e, t) &&
((i =
(o = Object.defineProperty) &&
Object.getOwnPropertyDescriptor(e, t)) &&
(i.get || i.set)
? o(f, t, i)
: (f[t] = e[t]));
return f;
})(e, t);
}
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
function wrapModule(module, options) {
const output = getJsOutput(module);
if (output.type.startsWith("js/script")) {
return output.data.code;
}
const params = getModuleParams(module, options);
return (0, _metroTransformPlugins.addParamsToDefineCall)(
output.data.code,
...params,
);
}
function getModuleParams(module, options) {
const moduleId = options.createModuleId(module.path);
const paths = {};
let hasPaths = false;
const dependencyMapArray = Array.from(module.dependencies.values()).map(
(dependency) => {
if (!(0, _isResolvedDependency.isResolvedDependency)(dependency)) {
return null;
}
const id = options.createModuleId(dependency.absolutePath);
if (options.includeAsyncPaths && dependency.data.data.asyncType != null) {
hasPaths = true;
(0, _invariant.default)(
options.sourceUrl != null,
"sourceUrl is required when includeAsyncPaths is true",
);
const { searchParams } = new URL(
jscSafeUrl.toNormalUrl(options.sourceUrl),
);
searchParams.set("modulesOnly", "true");
searchParams.set("runModule", "false");
const bundlePath = _path.default.relative(
options.serverRoot,
dependency.absolutePath,
);
paths[id] =
"/" +
_path.default.join(
_path.default.dirname(bundlePath),
_path.default.basename(
bundlePath,
_path.default.extname(bundlePath),
),
) +
".bundle?" +
searchParams.toString();
}
return id;
},
);
const params = [
moduleId,
hasPaths
? {
...dependencyMapArray,
paths,
}
: dependencyMapArray,
];
if (options.dev) {
params.push(
(0, _pathUtils.normalizePathSeparatorsToPosix)(
_path.default.relative(options.projectRoot, module.path),
),
);
}
return params;
}
function getJsOutput(module) {
const jsModules = module.output.filter(({ type }) => type.startsWith("js/"));
(0, _invariant.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, _invariant.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;
}
function isJsModule(module) {
return module.output.filter(isJsOutput).length > 0;
}
function isJsOutput(output) {
return output.type.startsWith("js/");
}

View File

@@ -0,0 +1,154 @@
/**
* 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.
*
* @flow
* @format
* @oncall react_native
*/
import type {MixedOutput, Module} from '../../types';
import type {JsOutput} from 'metro-transform-worker';
import {isResolvedDependency} from '../../../lib/isResolvedDependency';
import {normalizePathSeparatorsToPosix} from '../../../lib/pathUtils';
import invariant from 'invariant';
import * as jscSafeUrl from 'jsc-safe-url';
import {addParamsToDefineCall} from 'metro-transform-plugins';
import path from 'path';
export type Options = Readonly<{
createModuleId: string => number | string,
dev: boolean,
includeAsyncPaths: boolean,
projectRoot: string,
serverRoot: string,
sourceUrl: ?string,
...
}>;
export function wrapModule(module: Module<>, options: Options): string {
const output = getJsOutput(module);
if (output.type.startsWith('js/script')) {
return output.data.code;
}
const params = getModuleParams(module, options);
return addParamsToDefineCall(output.data.code, ...params);
}
export function getModuleParams(
module: Module<>,
options: Options,
): Array<unknown> {
const moduleId = options.createModuleId(module.path);
const paths: {[moduleID: number | string]: unknown} = {};
let hasPaths = false;
const dependencyMapArray = Array.from(module.dependencies.values()).map(
dependency => {
if (!isResolvedDependency(dependency)) {
// An unresolved dependency, which should cause a runtime error
// when required.
return null;
}
const id = options.createModuleId(dependency.absolutePath);
if (options.includeAsyncPaths && dependency.data.data.asyncType != null) {
hasPaths = true;
invariant(
options.sourceUrl != null,
'sourceUrl is required when includeAsyncPaths is 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(
jscSafeUrl.toNormalUrl(options.sourceUrl),
);
searchParams.set('modulesOnly', 'true');
searchParams.set('runModule', 'false');
const bundlePath = path.relative(
options.serverRoot,
dependency.absolutePath,
);
paths[id] =
'/' +
path.join(
// TODO: This is not the proper Metro URL encoding of a file path
path.dirname(bundlePath),
// Strip the file extension
path.basename(bundlePath, path.extname(bundlePath)),
) +
'.bundle?' +
searchParams.toString();
}
return id;
},
);
const params = [
moduleId,
hasPaths
? {
// $FlowFixMe[not-an-object] Intentionally spreading an array into an object
...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(
normalizePathSeparatorsToPosix(
path.relative(options.projectRoot, module.path),
),
);
}
return params;
}
export function getJsOutput(
module: Readonly<{
output: ReadonlyArray<MixedOutput>,
path?: string,
...
}>,
): JsOutput {
const jsModules = module.output.filter(({type}) => type.startsWith('js/'));
invariant(
jsModules.length === 1,
`Modules must have exactly one JS output, but ${
module.path ?? 'unknown module'
} has ${jsModules.length} JS outputs.`,
);
const jsOutput: JsOutput = jsModules[0] as any;
invariant(
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;
}
export function isJsModule(module: Module<>): boolean {
return module.output.filter(isJsOutput).length > 0;
}
function isJsOutput(output: MixedOutput): boolean {
return output.type.startsWith('js/');
}

View File

@@ -0,0 +1,32 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<1c5fe56fba9dbedcde1dbaeb5a486467>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/helpers/processModules.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../../types';
declare function processModules(
modules: ReadonlyArray<Module>,
$$PARAM_1$$: Readonly<{
filter?: (module: Module) => boolean;
createModuleId: ($$PARAM_0$$: string) => number;
dev: boolean;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
sourceUrl: null | undefined | string;
}>,
): ReadonlyArray<[Module, string]>;
export default processModules;

View File

@@ -0,0 +1,34 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = processModules;
var _js = require("./js");
function processModules(
modules,
{
filter = () => true,
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
},
) {
return [...modules]
.filter(_js.isJsModule)
.filter(filter)
.map((module) => [
module,
(0, _js.wrapModule)(module, {
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
}),
]);
}

View File

@@ -0,0 +1,50 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../../types';
import {isJsModule, wrapModule} from './js';
export default function processModules(
modules: ReadonlyArray<Module<>>,
{
filter = () => true,
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
}: Readonly<{
filter?: (module: Module<>) => boolean,
createModuleId: string => number,
dev: boolean,
includeAsyncPaths: boolean,
projectRoot: string,
serverRoot: string,
sourceUrl: ?string,
}>,
): ReadonlyArray<[Module<>, string]> {
return [...modules]
.filter(isJsModule)
.filter(filter)
.map((module: Module<>) => [
module,
wrapModule(module, {
createModuleId,
dev,
includeAsyncPaths,
projectRoot,
serverRoot,
sourceUrl,
}),
]);
}

View File

@@ -0,0 +1,37 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<d8ccae61344526a4f6da61987b3dad9b>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/hmrJSBundle.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {DeltaResult, ReadOnlyGraph} from '../types';
import type {HmrModule} from 'metro-runtime/src/modules/types';
type Options = Readonly<{
clientUrl: URL;
createModuleId: ($$PARAM_0$$: string) => number;
includeAsyncPaths: boolean;
projectRoot: string;
serverRoot: string;
}>;
declare function hmrJSBundle(
delta: DeltaResult,
graph: ReadOnlyGraph,
options: Options,
): {
readonly added: ReadonlyArray<HmrModule>;
readonly deleted: ReadonlyArray<number>;
readonly modified: ReadonlyArray<HmrModule>;
};
export default hmrJSBundle;

View File

@@ -0,0 +1,128 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.default = hmrJSBundle;
var _js = require("./helpers/js");
var jscSafeUrl = _interopRequireWildcard(require("jsc-safe-url"));
var _metroTransformPlugins = require("metro-transform-plugins");
var _path = _interopRequireDefault(require("path"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
function _interopRequireWildcard(e, t) {
if ("function" == typeof WeakMap)
var r = new WeakMap(),
n = new WeakMap();
return (_interopRequireWildcard = function (e, t) {
if (!t && e && e.__esModule) return e;
var o,
i,
f = { __proto__: null, default: e };
if (null === e || ("object" != typeof e && "function" != typeof e))
return f;
if ((o = t ? n : r)) {
if (o.has(e)) return o.get(e);
o.set(e, f);
}
for (const t in e)
"default" !== t &&
{}.hasOwnProperty.call(e, t) &&
((i =
(o = Object.defineProperty) &&
Object.getOwnPropertyDescriptor(e, t)) &&
(i.get || i.set)
? o(f, t, i)
: (f[t] = e[t]));
return f;
})(e, t);
}
const debug = require("debug")("Metro:HMR");
function generateModules(sourceModules, graph, options) {
const modules = [];
for (const module of sourceModules) {
if ((0, _js.isJsModule)(module)) {
const getPathname = (extension) => {
return _path.default
.relative(
options.serverRoot ?? options.projectRoot,
_path.default.join(
_path.default.dirname(module.path),
_path.default.basename(
module.path,
_path.default.extname(module.path),
) +
"." +
extension,
),
)
.split(_path.default.sep)
.map((segment) => encodeURIComponent(segment))
.join("/");
};
const clientUrl = new URL(options.clientUrl);
clientUrl.searchParams.delete("excludeSource");
clientUrl.pathname = getPathname("map");
const sourceMappingURL = clientUrl.toString();
clientUrl.pathname = getPathname("bundle");
const sourceURL = jscSafeUrl.toJscSafeUrl(clientUrl.toString());
debug(
"got sourceMappingURL: %s\nand sourceURL: %s\nfor module: %s",
sourceMappingURL,
sourceURL,
module.path,
);
const code =
prepareModule(module, graph, options) +
`\n//# sourceMappingURL=${sourceMappingURL}\n` +
`//# sourceURL=${sourceURL}\n`;
modules.push({
module: [options.createModuleId(module.path), code],
sourceMappingURL,
sourceURL,
});
}
}
return modules;
}
function prepareModule(module, graph, options) {
const code = (0, _js.wrapModule)(module, {
...options,
sourceUrl: options.clientUrl.toString(),
dev: true,
});
const inverseDependencies = getInverseDependencies(module.path, graph);
const inverseDependenciesById = Object.create(null);
Object.keys(inverseDependencies).forEach((path) => {
inverseDependenciesById[options.createModuleId(path)] = inverseDependencies[
path
].map(options.createModuleId);
});
return (0, _metroTransformPlugins.addParamsToDefineCall)(
code,
inverseDependenciesById,
);
}
function getInverseDependencies(path, graph, inverseDependencies = {}) {
if (path in inverseDependencies) {
return inverseDependencies;
}
const module = graph.dependencies.get(path);
if (!module) {
return inverseDependencies;
}
inverseDependencies[path] = [];
for (const inverse of module.inverseDependencies) {
inverseDependencies[path].push(inverse);
getInverseDependencies(inverse, graph, inverseDependencies);
}
return inverseDependencies;
}
function hmrJSBundle(delta, graph, options) {
return {
added: generateModules(delta.added.values(), graph, options),
modified: generateModules(delta.modified.values(), graph, options),
deleted: [...delta.deleted].map((path) => options.createModuleId(path)),
};
}

View File

@@ -0,0 +1,162 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {DeltaResult, Module, ReadOnlyGraph} from '../types';
import type {HmrModule} from 'metro-runtime/src/modules/types';
import {isJsModule, wrapModule} from './helpers/js';
import * as jscSafeUrl from 'jsc-safe-url';
import {addParamsToDefineCall} from 'metro-transform-plugins';
import path from 'path';
// eslint-disable-next-line import/no-commonjs
const debug = require('debug')('Metro:HMR');
type Options = Readonly<{
clientUrl: URL,
createModuleId: string => number,
includeAsyncPaths: boolean,
projectRoot: string,
serverRoot: string,
...
}>;
function generateModules(
sourceModules: Iterable<Module<>>,
graph: ReadOnlyGraph<>,
options: Options,
): ReadonlyArray<HmrModule> {
const modules = [];
for (const module of sourceModules) {
if (isJsModule(module)) {
const getPathname = (extension: 'bundle' | 'map') => {
return (
path
.relative(
options.serverRoot ?? options.projectRoot,
path.join(
path.dirname(module.path),
path.basename(module.path, path.extname(module.path)) +
'.' +
extension,
),
)
.split(path.sep)
// using this Metro particular convention for encoding file paths as URL paths.
.map(segment => encodeURIComponent(segment))
.join('/')
);
};
const clientUrl = new URL(options.clientUrl);
clientUrl.searchParams.delete('excludeSource');
clientUrl.pathname = getPathname('map');
const sourceMappingURL = clientUrl.toString();
clientUrl.pathname = getPathname('bundle');
const sourceURL = jscSafeUrl.toJscSafeUrl(clientUrl.toString());
debug(
'got sourceMappingURL: %s\nand sourceURL: %s\nfor module: %s',
sourceMappingURL,
sourceURL,
module.path,
);
const code =
prepareModule(module, graph, options) +
`\n//# sourceMappingURL=${sourceMappingURL}\n` +
`//# sourceURL=${sourceURL}\n`;
modules.push({
module: [options.createModuleId(module.path), code],
sourceMappingURL,
sourceURL,
});
}
}
return modules;
}
function prepareModule(
module: Module<>,
graph: ReadOnlyGraph<>,
options: Options,
): string {
const code = wrapModule(module, {
...options,
sourceUrl: options.clientUrl.toString(),
dev: true,
});
const inverseDependencies = getInverseDependencies(module.path, graph);
// Transform the inverse dependency paths to ids.
const inverseDependenciesById = Object.create(null);
Object.keys(inverseDependencies).forEach((path: string) => {
// $FlowFixMe[prop-missing]
// $FlowFixMe[invalid-computed-prop]
inverseDependenciesById[options.createModuleId(path)] = inverseDependencies[
path
].map(options.createModuleId);
});
return addParamsToDefineCall(code, inverseDependenciesById);
}
/**
* Instead of adding the whole inverseDependncies object into each changed
* module (which can be really huge if the dependency graph is big), we only
* add the needed inverseDependencies for each changed module (we do this by
* traversing upwards the dependency graph).
*/
function getInverseDependencies(
path: string,
graph: ReadOnlyGraph<>,
inverseDependencies: {[key: string]: Array<string>, ...} = {},
): {[key: string]: Array<string>, ...} {
// Dependency alredy traversed.
if (path in inverseDependencies) {
return inverseDependencies;
}
const module = graph.dependencies.get(path);
if (!module) {
return inverseDependencies;
}
inverseDependencies[path] = [];
for (const inverse of module.inverseDependencies) {
inverseDependencies[path].push(inverse);
getInverseDependencies(inverse, graph, inverseDependencies);
}
return inverseDependencies;
}
export default function hmrJSBundle(
delta: DeltaResult<>,
graph: ReadOnlyGraph<>,
options: Options,
): {
+added: ReadonlyArray<HmrModule>,
+deleted: ReadonlyArray<number>,
+modified: ReadonlyArray<HmrModule>,
} {
return {
added: generateModules(delta.added.values(), graph, options),
modified: generateModules(delta.modified.values(), graph, options),
deleted: [...delta.deleted].map((path: string) =>
options.createModuleId(path),
),
};
}

View File

@@ -0,0 +1,36 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<49bc83c20821024a7b77f5d5c3168d62>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/sourceMapGenerator.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../types';
import {fromRawMappings, fromRawMappingsNonBlocking} from 'metro-source-map';
export type SourceMapGeneratorOptions = Readonly<{
excludeSource: boolean;
processModuleFilter: (module: Module) => boolean;
shouldAddToIgnoreList: (module: Module) => boolean;
getSourceUrl: null | undefined | ((module: Module) => string);
}>;
declare function sourceMapGenerator(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): ReturnType<typeof fromRawMappings>;
declare function sourceMapGeneratorNonBlocking(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): ReturnType<typeof fromRawMappingsNonBlocking>;
export {sourceMapGenerator, sourceMapGeneratorNonBlocking};

View File

@@ -0,0 +1,76 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.sourceMapGenerator = sourceMapGenerator;
exports.sourceMapGeneratorNonBlocking = sourceMapGeneratorNonBlocking;
var _getSourceMapInfo = _interopRequireDefault(
require("./helpers/getSourceMapInfo"),
);
var _js = require("./helpers/js");
var _metroSourceMap = require("metro-source-map");
function _interopRequireDefault(e) {
return e && e.__esModule ? e : { default: e };
}
function getSourceMapInfosImpl(isBlocking, onDone, modules, options) {
const sourceMapInfos = [];
const modulesToProcess = modules
.filter(_js.isJsModule)
.filter(options.processModuleFilter);
function processNextModule() {
if (modulesToProcess.length === 0) {
return true;
}
const mod = modulesToProcess.shift();
const info = (0, _getSourceMapInfo.default)(mod, {
excludeSource: options.excludeSource,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
getSourceUrl: options.getSourceUrl,
});
sourceMapInfos.push(info);
return false;
}
function workLoop() {
const time = process.hrtime();
while (true) {
const isDone = processNextModule();
if (isDone) {
onDone(sourceMapInfos);
break;
}
if (!isBlocking) {
const diff = process.hrtime(time);
const NS_IN_MS = 1000000;
if (diff[1] > 50 * NS_IN_MS) {
setImmediate(workLoop);
break;
}
}
}
}
workLoop();
}
function sourceMapGenerator(modules, options) {
let sourceMapInfos;
getSourceMapInfosImpl(
true,
(infos) => {
sourceMapInfos = infos;
},
modules,
options,
);
if (sourceMapInfos == null) {
throw new Error(
"Expected getSourceMapInfosImpl() to finish synchronously.",
);
}
return (0, _metroSourceMap.fromRawMappings)(sourceMapInfos);
}
async function sourceMapGeneratorNonBlocking(modules, options) {
const sourceMapInfos = await new Promise((resolve) => {
getSourceMapInfosImpl(false, resolve, modules, options);
});
return (0, _metroSourceMap.fromRawMappingsNonBlocking)(sourceMapInfos);
}

View File

@@ -0,0 +1,111 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../types';
import getSourceMapInfo from './helpers/getSourceMapInfo';
import {isJsModule} from './helpers/js';
import {fromRawMappings, fromRawMappingsNonBlocking} from 'metro-source-map';
export type SourceMapGeneratorOptions = Readonly<{
excludeSource: boolean,
processModuleFilter: (module: Module<>) => boolean,
shouldAddToIgnoreList: (module: Module<>) => boolean,
getSourceUrl: ?(module: Module<>) => string,
}>;
function getSourceMapInfosImpl(
isBlocking: boolean,
onDone: (ReadonlyArray<ReturnType<typeof getSourceMapInfo>>) => void,
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): void {
const sourceMapInfos = [];
const modulesToProcess = modules
.filter(isJsModule)
.filter(options.processModuleFilter);
function processNextModule() {
if (modulesToProcess.length === 0) {
return true;
}
const mod = modulesToProcess.shift();
// $FlowFixMe[incompatible-type]
const info = getSourceMapInfo(mod, {
excludeSource: options.excludeSource,
shouldAddToIgnoreList: options.shouldAddToIgnoreList,
getSourceUrl: options.getSourceUrl,
});
sourceMapInfos.push(info);
return false;
}
function workLoop() {
const time = process.hrtime();
while (true) {
const isDone = processNextModule();
if (isDone) {
onDone(sourceMapInfos);
break;
}
if (!isBlocking) {
// Keep the loop running but try to avoid blocking
// for too long because this is not in a worker yet.
const diff = process.hrtime(time);
const NS_IN_MS = 1000000;
if (diff[1] > 50 * NS_IN_MS) {
// We've blocked for more than 50ms.
// This code currently runs on the main thread,
// so let's give Metro an opportunity to handle requests.
setImmediate(workLoop);
break;
}
}
}
}
workLoop();
}
function sourceMapGenerator(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): ReturnType<typeof fromRawMappings> {
let sourceMapInfos;
getSourceMapInfosImpl(
true,
infos => {
sourceMapInfos = infos;
},
modules,
options,
);
if (sourceMapInfos == null) {
throw new Error(
'Expected getSourceMapInfosImpl() to finish synchronously.',
);
}
return fromRawMappings(sourceMapInfos);
}
async function sourceMapGeneratorNonBlocking(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): ReturnType<typeof fromRawMappingsNonBlocking> {
const sourceMapInfos = await new Promise<
ReadonlyArray<ReturnType<typeof getSourceMapInfo>>,
>(resolve => {
getSourceMapInfosImpl(false, resolve, modules, options);
});
return fromRawMappingsNonBlocking(sourceMapInfos);
}
export {sourceMapGenerator, sourceMapGeneratorNonBlocking};

View File

@@ -0,0 +1,30 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<cb907f1a9aa40efd505a19826a21be6d>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/sourceMapObject.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
import type {MixedSourceMap} from 'metro-source-map';
declare function sourceMapObject(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): MixedSourceMap;
declare function sourceMapObjectNonBlocking(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): Promise<MixedSourceMap>;
export {sourceMapObject, sourceMapObjectNonBlocking};

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.sourceMapObject = sourceMapObject;
exports.sourceMapObjectNonBlocking = sourceMapObjectNonBlocking;
var _sourceMapGenerator = require("./sourceMapGenerator");
function sourceMapObject(modules, options) {
const generator = (0, _sourceMapGenerator.sourceMapGenerator)(
modules,
options,
);
return generator.toMap(undefined, {
excludeSource: options.excludeSource,
});
}
async function sourceMapObjectNonBlocking(modules, options) {
const generator = await (0,
_sourceMapGenerator.sourceMapGeneratorNonBlocking)(modules, options);
return generator.toMap(undefined, {
excludeSource: options.excludeSource,
});
}

View File

@@ -0,0 +1,41 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
import type {MixedSourceMap} from 'metro-source-map';
import {
sourceMapGenerator,
sourceMapGeneratorNonBlocking,
} from './sourceMapGenerator';
function sourceMapObject(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): MixedSourceMap {
const generator = sourceMapGenerator(modules, options);
return generator.toMap(undefined, {
excludeSource: options.excludeSource,
});
}
async function sourceMapObjectNonBlocking(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): Promise<MixedSourceMap> {
const generator = await sourceMapGeneratorNonBlocking(modules, options);
return generator.toMap(undefined, {
excludeSource: options.excludeSource,
});
}
export {sourceMapObject, sourceMapObjectNonBlocking};

View File

@@ -0,0 +1,29 @@
/**
* 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.
*
* @noformat
* @oncall react_native
* @generated SignedSource<<578dd38524928420df15b0aba8f32e77>>
*
* This file was translated from Flow by scripts/generateTypeScriptDefinitions.js
* Original file: packages/metro/src/DeltaBundler/Serializers/sourceMapString.js
* To regenerate, run:
* js1 build metro-ts-defs (internal) OR
* yarn run build-ts-defs (OSS)
*/
import type {Module} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
declare function sourceMapString(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): string;
declare function sourceMapStringNonBlocking(
modules: ReadonlyArray<Module>,
options: SourceMapGeneratorOptions,
): Promise<string>;
export {sourceMapString, sourceMapStringNonBlocking};

View File

@@ -0,0 +1,23 @@
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true,
});
exports.sourceMapString = sourceMapString;
exports.sourceMapStringNonBlocking = sourceMapStringNonBlocking;
var _sourceMapGenerator = require("./sourceMapGenerator");
function sourceMapString(modules, options) {
return (0, _sourceMapGenerator.sourceMapGenerator)(modules, options).toString(
undefined,
{
excludeSource: options.excludeSource,
},
);
}
async function sourceMapStringNonBlocking(modules, options) {
const generator = await (0,
_sourceMapGenerator.sourceMapGeneratorNonBlocking)(modules, options);
return generator.toString(undefined, {
excludeSource: options.excludeSource,
});
}

View File

@@ -0,0 +1,39 @@
/**
* 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.
*
* @flow strict-local
* @format
* @oncall react_native
*/
import type {Module} from '../types';
import type {SourceMapGeneratorOptions} from './sourceMapGenerator';
import {
sourceMapGenerator,
sourceMapGeneratorNonBlocking,
} from './sourceMapGenerator';
function sourceMapString(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): string {
return sourceMapGenerator(modules, options).toString(undefined, {
excludeSource: options.excludeSource,
});
}
async function sourceMapStringNonBlocking(
modules: ReadonlyArray<Module<>>,
options: SourceMapGeneratorOptions,
): Promise<string> {
const generator = await sourceMapGeneratorNonBlocking(modules, options);
return generator.toString(undefined, {
excludeSource: options.excludeSource,
});
}
export {sourceMapString, sourceMapStringNonBlocking};