PHP WebShell

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

Просмотр файла: Transformer.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 strict-local
 * @format
 * @oncall react_native
 */

import type {TransformResult, TransformResultWithSource} from '../DeltaBundler';
import type {TransformerConfig, TransformOptions} from './Worker';
import type {ConfigT} from 'metro-config';

import {normalizePathSeparatorsToPosix} from '../lib/pathUtils';
import getTransformCacheKey from './getTransformCacheKey';
import WorkerFarm from './WorkerFarm';
import assert from 'assert';
import crypto from 'crypto';
import fs from 'fs';
import {Cache, stableHash} from 'metro-cache';
import path from 'path';

// eslint-disable-next-line import/no-commonjs
const debug = require('debug')('Metro:Transformer');

type GetOrComputeSha1Fn = string => Promise<
  $ReadOnly<{content?: Buffer, sha1: string}>,
>;

export default class Transformer {
  _config: ConfigT;
  _cache: Cache<TransformResult<>>;
  _baseHash: string;
  _getSha1: GetOrComputeSha1Fn;
  _workerFarm: WorkerFarm;

  constructor(
    config: ConfigT,
    opts: $ReadOnly<{getOrComputeSha1: GetOrComputeSha1Fn}>,
  ) {
    this._config = config;

    this._config.watchFolders.forEach(verifyRootExists);
    this._cache = new Cache(config.cacheStores);
    this._getSha1 = opts.getOrComputeSha1;

    // Remove the transformer config params that we don't want to pass to the
    // transformer. We should change the config object and move them away so we
    // can treat the transformer config params as opaque.
    const {
      getTransformOptions: _getTransformOptions,
      transformVariants: _transformVariants,
      unstable_workerThreads: _workerThreads,
      ...transformerConfig
    } = this._config.transformer;

    const transformerOptions: TransformerConfig = {
      transformerPath: this._config.transformerPath,
      transformerConfig,
    };

    this._workerFarm = new WorkerFarm(config, transformerOptions);

    const globalCacheKey = this._cache.isDisabled
      ? ''
      : getTransformCacheKey({
          cacheVersion: this._config.cacheVersion,
          projectRoot: this._config.projectRoot,
          transformerConfig: transformerOptions,
        });

    const baseHashBuffer = stableHash([globalCacheKey]);
    this._baseHash = baseHashBuffer.toString('binary');
    debug('Base hash: %s', baseHashBuffer.toString('hex'));
  }

  async transformFile(
    filePath: string,
    transformerOptions: TransformOptions,
    fileBuffer?: Buffer,
  ): Promise<TransformResultWithSource<>> {
    const cache = this._cache;

    const {
      customTransformOptions,
      dev,
      experimentalImportSupport,
      inlinePlatform,
      inlineRequires,
      minify,
      nonInlinedRequires,
      platform,
      type,
      unstable_transformProfile,
      unstable_memoizeInlineRequires,
      unstable_nonMemoizedInlineRequires,
      ...extra
    } = transformerOptions;

    for (const key in extra) {
      // $FlowFixMe[cannot-resolve-name]
      if (hasOwnProperty.call(extra, key)) {
        throw new Error(
          'Extra keys detected: ' + Object.keys(extra).join(', '),
        );
      }
    }

    const localPath = path.relative(this._config.projectRoot, filePath);

    const partialKey = stableHash([
      // This is the hash related to the global Bundler config.
      this._baseHash,

      // Project-relative, posix-separated path for portability. Necessary in
      // addition to content hash because transformers receive path as an
      // input, and may apply e.g. extension-based logic.
      normalizePathSeparatorsToPosix(localPath),
      customTransformOptions,
      dev,
      experimentalImportSupport,
      inlinePlatform,
      inlineRequires,
      minify,
      nonInlinedRequires,
      platform,
      type,
      unstable_memoizeInlineRequires,
      unstable_nonMemoizedInlineRequires,
      unstable_transformProfile,
    ]);

    let sha1: string;
    let content: ?Buffer;
    if (fileBuffer) {
      // Shortcut for virtual modules which provide the contents with the filename.
      sha1 = crypto.createHash('sha1').update(fileBuffer).digest('hex');
      content = fileBuffer;
    } else {
      const result = await this._getSha1(filePath);
      sha1 = result.sha1;
      if (result.content) {
        content = result.content;
      }
    }

    let fullKey = Buffer.concat([partialKey, Buffer.from(sha1, 'hex')]);
    let result;
    try {
      result = await cache.get(fullKey);
    } catch (error) {
      this._config.reporter.update({
        type: 'cache_read_error',
        error,
      });
      throw error;
    }

    // A valid result from the cache is used directly; otherwise we call into
    // the transformer to computed the corresponding result.
    const data: $ReadOnly<{
      result: TransformResult<>,
      sha1: string,
    }> = result
      ? {result, sha1}
      : await this._workerFarm.transform(
          localPath,
          transformerOptions,
          content,
        );

    // Only re-compute the full key if the SHA-1 changed. This is because
    // references are used by the cache implementation in a weak map to keep
    // track of the cache that returned the result.
    if (sha1 !== data.sha1) {
      fullKey = Buffer.concat([partialKey, Buffer.from(data.sha1, 'hex')]);
    }

    // Fire-and-forget cache set promise.
    cache.set(fullKey, data.result).catch(error => {
      this._config.reporter.update({
        type: 'cache_write_error',
        error,
      });
    });

    return {
      ...data.result,
      unstable_transformResultKey: fullKey.toString(),
      getSource(): Buffer {
        if (fileBuffer) {
          return fileBuffer;
        }
        return fs.readFileSync(filePath);
      },
    };
  }

  async end(): Promise<void> {
    await this._workerFarm.kill();
  }
}

function verifyRootExists(root: string): void {
  // Verify that the root exists.
  assert(fs.statSync(root).isDirectory(), 'Root has to be a valid directory');
}

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


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