PHP WebShell

Текущая директория: /usr/lib/node_modules/bitgo/node_modules/metro/src

Просмотр файла: index.flow.js.flow

/**
 * 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 {AssetData} from './Assets';
import type {ReadOnlyGraph} from './DeltaBundler';
import type {ServerOptions} from './Server';
import type {BuildOptions, OutputOptions, RequestOptions} from './shared/types';
import type {HandleFunction} from 'connect';
import type {Server as HttpServer} from 'http';
import type {Server as HttpsServer} from 'https';
import type {TransformProfile} from 'metro-babel-transformer';
import type {
  ConfigT,
  InputConfigT,
  MetroConfig,
  Middleware,
} from 'metro-config';
import type {CustomResolverOptions} from 'metro-resolver';
import type {CustomTransformOptions} from 'metro-transform-worker';
import typeof Yargs from 'yargs';

import makeBuildCommand from './commands/build';
import makeDependenciesCommand from './commands/dependencies';
import makeServeCommand from './commands/serve';
import MetroHmrServer from './HmrServer';
import IncrementalBundler from './IncrementalBundler';
import createWebsocketServer from './lib/createWebsocketServer';
import JsonReporter from './lib/JsonReporter';
import TerminalReporter from './lib/TerminalReporter';
import MetroServer from './Server';
import * as outputBundle from './shared/output/bundle';
import chalk from 'chalk';
import fs from 'fs';
import http from 'http';
import https from 'https';
import {
  getDefaultConfig,
  loadConfig,
  mergeConfig,
  resolveConfig,
} from 'metro-config';
import {Terminal} from 'metro-core';
import net from 'net';
import nullthrows from 'nullthrows';

const DEFAULTS = MetroServer.DEFAULT_BUNDLE_OPTIONS;

type MetroMiddleWare = {
  attachHmrServer: (httpServer: HttpServer | HttpsServer) => void,
  end: () => Promise<void>,
  metroServer: MetroServer,
  middleware: Middleware,
};

export type RunMetroOptions = {
  ...ServerOptions,
  waitForBundler?: boolean,
};

export type RunServerOptions = $ReadOnly<{
  hasReducedPerformance?: boolean,
  host?: string,
  onError?: (Error & {code?: string}) => void,
  onReady?: (server: HttpServer | HttpsServer) => void,
  onClose?: () => void,
  secureServerOptions?: Object,
  secure?: boolean, // deprecated
  secureCert?: string, // deprecated
  secureKey?: string, // deprecated
  unstable_extraMiddleware?: $ReadOnlyArray<HandleFunction>,
  waitForBundler?: boolean,
  watch?: boolean,
  websocketEndpoints?: $ReadOnly<{
    [path: string]: ws$WebSocketServer,
  }>,
}>;

export type RunServerResult = {
  httpServer: HttpServer | HttpsServer,
};

type BuildGraphOptions = {
  entries: $ReadOnlyArray<string>,
  customTransformOptions?: CustomTransformOptions,
  dev?: boolean,
  minify?: boolean,
  onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
  platform?: string,
  type?: 'module' | 'script',
};

export type RunBuildOptions = {
  entry: string,
  assets?: boolean,
  dev?: boolean,
  out?: string,
  bundleOut?: string,
  sourceMapOut?: string,
  onBegin?: () => void,
  onComplete?: () => void,
  onProgress?: (transformedFileCount: number, totalFileCount: number) => void,
  minify?: boolean,
  output?: $ReadOnly<{
    build: (
      MetroServer,
      RequestOptions,
      void | BuildOptions,
    ) => Promise<{
      code: string,
      map: string,
      assets?: $ReadOnlyArray<AssetData>,
      ...
    }>,
    save: (
      {
        code: string,
        map: string,
        ...
      },
      OutputOptions,
      (logMessage: string) => void,
    ) => Promise<mixed>,
    ...
  }>,
  platform?: string,
  sourceMap?: boolean,
  sourceMapUrl?: string,
  customResolverOptions?: CustomResolverOptions,
  customTransformOptions?: CustomTransformOptions,
  unstable_transformProfile?: TransformProfile,
};

export type RunBuildResult = {
  code: string,
  map: string,
  assets?: $ReadOnlyArray<AssetData>,
  ...
};

type BuildCommandOptions = {} | null;
type ServeCommandOptions = {} | null;

export {Terminal, JsonReporter, TerminalReporter};

export type {AssetData} from './Assets';
export type {Reporter, ReportableEvent} from './lib/reporting';
export type {TerminalReportableEvent} from './lib/TerminalReporter';
export type {MetroConfig};

async function getConfig(config: InputConfigT): Promise<ConfigT> {
  const defaultConfig = await getDefaultConfig(config.projectRoot);
  return mergeConfig(defaultConfig, config);
}

export async function runMetro(
  config: InputConfigT,
  options?: RunMetroOptions,
): Promise<MetroServer> {
  const mergedConfig = await getConfig(config);
  const {
    reporter,
    server: {port},
  } = mergedConfig;

  reporter.update({
    hasReducedPerformance: options
      ? Boolean(options.hasReducedPerformance)
      : false,
    port,
    type: 'initialize_started',
  });

  const {waitForBundler = false, ...serverOptions} = options ?? {};
  const server = new MetroServer(mergedConfig, serverOptions);

  const readyPromise = server
    .ready()
    .then(() => {
      reporter.update({
        type: 'initialize_done',
        port,
      });
    })
    .catch(error => {
      reporter.update({
        type: 'initialize_failed',
        port,
        error,
      });
    });
  if (waitForBundler) {
    await readyPromise;
  }

  return server;
}

export {loadConfig, mergeConfig, resolveConfig};

export const createConnectMiddleware = async function (
  config: ConfigT,
  options?: RunMetroOptions,
): Promise<MetroMiddleWare> {
  const metroServer = await runMetro(config, options);

  let enhancedMiddleware: Middleware = metroServer.processRequest;

  // Enhance the resulting middleware using the config options
  if (config.server.enhanceMiddleware) {
    enhancedMiddleware = config.server.enhanceMiddleware(
      enhancedMiddleware,
      metroServer,
    );
  }

  return {
    attachHmrServer(httpServer: HttpServer | HttpsServer): void {
      const wss = createWebsocketServer({
        websocketServer: new MetroHmrServer(
          metroServer.getBundler(),
          metroServer.getCreateModuleId(),
          config,
        ),
      });
      httpServer.on('upgrade', (request, socket, head) => {
        const {pathname} = new URL(request.url, 'resolve://');
        if (pathname === '/hot') {
          wss.handleUpgrade(request, socket, head, ws => {
            wss.emit('connection', ws, request);
          });
        } else {
          socket.destroy();
        }
      });
    },
    metroServer,
    middleware: enhancedMiddleware,
    async end(): Promise<void> {
      await metroServer.end();
    },
  };
};

export const runServer = async (
  config: ConfigT,
  {
    hasReducedPerformance = false,
    host,
    onError,
    onReady,
    onClose,
    secureServerOptions,
    secure, //deprecated
    secureCert, // deprecated
    secureKey, // deprecated
    unstable_extraMiddleware,
    waitForBundler = false,
    websocketEndpoints = {},
    watch,
  }: RunServerOptions = {},
): Promise<RunServerResult> => {
  await earlyPortCheck(host, config.server.port);

  if (secure != null || secureCert != null || secureKey != null) {
    // eslint-disable-next-line no-console
    console.warn(
      chalk.inverse.yellow.bold(' DEPRECATED '),
      'The `secure`, `secureCert`, and `secureKey` options are now deprecated. ' +
        'Please use the `secureServerOptions` object instead to pass options to ' +
        "Metro's https development server.",
    );
  }
  // Lazy require
  // eslint-disable-next-line import/no-commonjs
  const connect = require('connect');

  const serverApp = connect();

  const {
    middleware,
    end: endMiddleware,
    metroServer,
  } = await createConnectMiddleware(config, {
    hasReducedPerformance,
    waitForBundler,
    watch,
  });

  for (const handler of unstable_extraMiddleware ?? []) {
    serverApp.use(handler);
  }

  serverApp.use(middleware);

  let httpServer;

  if (secure || secureServerOptions != null) {
    let options = secureServerOptions;
    if (typeof secureKey === 'string' && typeof secureCert === 'string') {
      options = {
        key: fs.readFileSync(secureKey),
        cert: fs.readFileSync(secureCert),
        ...secureServerOptions,
      };
    }
    // $FlowFixMe[incompatible-type] 'http' and 'https' Flow types do not match
    httpServer = https.createServer(options, serverApp);
  } else {
    httpServer = http.createServer(serverApp);
  }
  return new Promise((resolve, reject) => {
    httpServer.on('error', error => {
      endMiddleware().finally(() => {
        onError?.(error);
        reject(error);
      });
    });

    httpServer.listen(config.server.port, host, () => {
      const {address, port, family} = httpServer.address();
      config.reporter.update({
        type: 'server_listening',
        address,
        port, // Assigned port if configured with port 0
        family,
      });

      websocketEndpoints = {
        ...websocketEndpoints,
        '/hot': createWebsocketServer({
          websocketServer: new MetroHmrServer(
            metroServer.getBundler(),
            metroServer.getCreateModuleId(),
            config,
          ),
        }),
      };

      httpServer.on('upgrade', (request, socket, head) => {
        const {pathname} = new URL(request.url, 'resolve://');
        if (pathname != null && websocketEndpoints[pathname]) {
          websocketEndpoints[pathname].handleUpgrade(
            request,
            socket,
            head,
            ws => {
              websocketEndpoints[pathname].emit('connection', ws, request);
            },
          );
        } else {
          socket.destroy();
        }
      });

      if (onReady) {
        onReady(httpServer);
      }

      resolve({httpServer});
    });

    // Disable any kind of automatic timeout behavior for incoming
    // requests in case it takes the packager more than the default
    // timeout of 120 seconds to respond to a request.
    httpServer.timeout = 0;

    httpServer.on('close', () => {
      endMiddleware()?.finally(() => {
        onClose?.();
      });
    });
  });
};

export const runBuild = async (
  config: ConfigT,
  {
    assets = false,
    customResolverOptions = DEFAULTS.customResolverOptions,
    customTransformOptions = DEFAULTS.customTransformOptions,
    dev = false,
    entry,
    onBegin,
    onComplete,
    onProgress,
    minify = true,
    output = outputBundle,
    out,
    bundleOut,
    sourceMapOut,
    platform = 'web',
    sourceMap = false,
    sourceMapUrl,
    unstable_transformProfile = DEFAULTS.unstable_transformProfile,
  }: RunBuildOptions,
): Promise<RunBuildResult> => {
  const metroServer = await runMetro(config, {
    watch: false,
  });

  try {
    const requestOptions = {
      dev,
      entryFile: entry,
      inlineSourceMap: sourceMap && !sourceMapUrl,
      minify,
      platform,
      ...(sourceMap === false ? {} : {sourceMapUrl}),
      createModuleIdFactory: config.serializer.createModuleIdFactory,
      onProgress,
      customResolverOptions,
      customTransformOptions,
      unstable_transformProfile,
    };

    if (onBegin) {
      onBegin();
    }

    const metroBundle = await output.build(metroServer, requestOptions, {
      withAssets: assets,
    });
    const result: RunBuildResult = {...metroBundle};

    if (assets && result.assets == null) {
      result.assets = await metroServer.getAssets({
        ...MetroServer.DEFAULT_BUNDLE_OPTIONS,
        ...requestOptions,
      });
    }

    if (onComplete) {
      onComplete();
    }

    if (out || bundleOut) {
      const bundleOutput =
        bundleOut ?? nullthrows(out).replace(/(\.js)?$/, '.js');

      const sourcemapOutput =
        sourceMap === false
          ? undefined
          : (sourceMapOut ?? out?.replace(/(\.js)?$/, '.map'));

      const outputOptions: OutputOptions = {
        bundleOutput,
        sourcemapOutput,
        dev,
        platform,
      };

      await output.save(metroBundle, outputOptions, message =>
        config.reporter.update({
          type: 'bundle_save_log',
          message,
        }),
      );
    }

    return result;
  } finally {
    await metroServer.end();
  }
};

export const buildGraph = async function (
  config: InputConfigT,
  {
    customTransformOptions = Object.create(null),
    dev = false,
    entries,
    minify = false,
    onProgress,
    platform = 'web',
    type = 'module',
  }: BuildGraphOptions,
): Promise<ReadOnlyGraph<>> {
  const mergedConfig = await getConfig(config);

  const bundler = new IncrementalBundler(mergedConfig);

  try {
    const {customResolverOptions, ...defaultTransformInputOptions} =
      MetroServer.DEFAULT_GRAPH_OPTIONS;
    return await bundler.buildGraphForEntries(
      entries,
      {
        ...defaultTransformInputOptions,
        customTransformOptions,
        dev,
        minify,
        platform,
        type,
      },
      {customResolverOptions, dev},
    );
  } finally {
    await bundler.end();
  }
};

type AttachMetroCLIOptions = {
  build?: BuildCommandOptions,
  serve?: ServeCommandOptions,
  dependencies?: any,
  ...
};

export const attachMetroCli = function (
  yargs: Yargs,
  options?: AttachMetroCLIOptions = {},
): Yargs {
  const {build = {}, serve = {}, dependencies = {}} = options;

  yargs.strict();

  if (build) {
    yargs.command(makeBuildCommand());
  }
  if (serve) {
    yargs.command(makeServeCommand());
  }
  if (dependencies) {
    yargs.command(makeDependenciesCommand());
  }

  return yargs;
};

async function earlyPortCheck(host: void | string, port: number) {
  const server = net.createServer(c => c.end());
  try {
    await new Promise((resolve, reject) => {
      server.on('error', err => {
        reject(err);
      });
      server.listen(port, host, undefined, () => resolve());
    });
  } finally {
    await new Promise(resolve => server.close(() => resolve()));
  }
}

/**
 * Backwards-compatibility with CommonJS consumers using interopRequireDefault.
 * Do not add to this list.
 *
 * @deprecated Default import from 'metro' is deprecated, use named exports.
 */
export default {
  attachMetroCli,
  runServer,
  Terminal,
  JsonReporter,
  TerminalReporter,
  loadConfig,
  mergeConfig,
  resolveConfig,
  createConnectMiddleware,
  runBuild,
  buildGraph,
};

Выполнить команду


Для локальной разработки. Не используйте в интернете!