<commit_before>/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

'use strict';

import type {Config, Path} from 'types/Config';
import type {Console} from 'console';
import type {Environment} from 'types/Environment';
import type {HasteContext} from 'types/HasteMap';
import type {Script} from 'vm';
import type ModuleMap from '../../jest-haste-map/src/ModuleMap';
import type Resolver from '../../jest-resolve/src';

const HasteMap = require('jest-haste-map');
const ResolverClass = require('jest-resolve');

const fs = require('graceful-fs');
const moduleMocker = require('jest-mock');
const path = require('path');
const shouldInstrument = require('./shouldInstrument');
const transform = require('./transform');
const utils = require('jest-util');

type Module = {
  exports: any,
  filename: string,
  children?: Array<any>,
  parent?: Module,
  paths?: Array<Path>,
  require?: Function,
};

type HasteMapOptions = {
  console?: Console,
  maxWorkers: number,
  resetCache: boolean,
};

type InternalModuleOptions = {isInternalModule: boolean};

const NODE_MODULES = path.sep + 'node_modules' + path.sep;
const SNAPSHOT_EXTENSION = 'snap';

const getModuleNameMapper = (config: Config) => {
  if (config.moduleNameMapper.length) {
    const moduleNameMapper = Object.create(null);
    config.moduleNameMapper.forEach(
      map => moduleNameMapper[map[1]] = new RegExp(map[0]),
    );
    return moduleNameMapper;
  }
  return null;
};

const mockParentModule = {
  exports: {},
  filename: 'mock.js',
  id: 'mockParent',
};

const normalizedIDCache = Object.create(null);
const unmockRegExpCache = new WeakMap();

type BooleanObject = {[key: string]: boolean};

class Runtime {
  _config: Config;
  _currentlyExecutingModulePath: string;
  _environment: Environment;
  _explicitShouldMock: BooleanObject;
  _isCurrentlyExecutingManualMock: ?string;
  _mockFactories: {[key: string]: () => any};
  _mockMetaDataCache: {[key: string]: Object};
  _mockRegistry: {[key: string]: any};
  _mocksPattern: ?RegExp;
  _moduleRegistry: {[key: string]: Module};
  _resolver: Resolver;
  _shouldAutoMock: boolean;
  _shouldMockModuleCache: BooleanObject;
  _shouldUnmockTransitiveDependenciesCache: BooleanObject;
  _testRegex: RegExp;
  _transitiveShouldMock: BooleanObject;
  _unmockList: ?RegExp;
  _virtualMocks: BooleanObject;

  constructor(
    config: Config,
    environment: Environment,
    resolver: Resolver,
  ) {
    this._moduleRegistry = Object.create(null);
    this._mockRegistry = Object.create(null);
    this._config = config;
    this._environment = environment;
    this._resolver = resolver;

    this._currentlyExecutingModulePath = '';
    this._explicitShouldMock = Object.create(null);
    this._isCurrentlyExecutingManualMock = null;
    this._mockFactories = Object.create(null);
    this._mocksPattern =
      config.mocksPattern ? new RegExp(config.mocksPattern) : null;
    this._shouldAutoMock = config.automock;
    this._testRegex = new RegExp(config.testRegex.replace(/\//g, path.sep));
    this._virtualMocks = Object.create(null);

    this._mockMetaDataCache = Object.create(null);
    this._shouldMockModuleCache = Object.create(null);
    this._shouldUnmockTransitiveDependenciesCache = Object.create(null);
    this._transitiveShouldMock = Object.create(null);

    this._unmockList = unmockRegExpCache.get(config);
    if (
      !this._unmockList &&
      config.automock &&
      config.unmockedModulePathPatterns
    ) {
      this._unmockList =
        new RegExp(config.unmockedModulePathPatterns.join('|'));
      unmockRegExpCache.set(config, this._unmockList);
    }

    if (config.automock) {
      config.setupFiles.forEach(filePath => {
        if (filePath && filePath.includes(NODE_MODULES)) {
          const moduleID = this._normalizeID(filePath);
          this._transitiveShouldMock[moduleID] = false;
        }
      });
    }

    this.resetModules();

    if (config.setupFiles.length) {
      for (let i = 0; i < config.setupFiles.length; i++) {
        this.requireModule(config.setupFiles[i]);
      }
    }
  }

  static createHasteContext(
    config: Config,
    options: {
      console?: Console,
      maxWorkers: number,
    },
  ): Promise<HasteContext> {
    utils.createDirectory(config.cacheDirectory);
    const instance = Runtime.createHasteMap(config, {
      console: options.console,
      maxWorkers: options.maxWorkers,
      resetCache: !config.cache,
    });
    return instance.build().then(
      hasteMap => ({
        hasteFS: hasteMap.hasteFS,
        resolver: Runtime.createResolver(config, hasteMap.moduleMap),
      }),
      error => {
        throw error;
      },
    );
  }

  static createHasteMap(
    config: Config,
    options?: HasteMapOptions,
  ): HasteMap {
    const ignorePattern = new RegExp(
      [config.cacheDirectory].concat(config.modulePathIgnorePatterns).join('|'),
    );

    return new HasteMap({
      cacheDirectory: config.cacheDirectory,
      console: options && options.console,
      extensions: [SNAPSHOT_EXTENSION].concat(config.moduleFileExtensions),
      ignorePattern,
      maxWorkers: (options && options.maxWorkers) || 1,
      mocksPattern: config.mocksPattern,
      name: config.name,
      platforms: config.haste.platforms || ['ios', 'android'],
      providesModuleNodeModules: config.haste.providesModuleNodeModules,
      resetCache: options && options.resetCache,
      roots: config.testPathDirs,
      useWatchman: config.watchman,
    });
  }

  static createResolver(
    config: Config,
    moduleMap: ModuleMap,
  ): Resolver {
    return new ResolverClass(moduleMap, {
      browser: config.browser,
      defaultPlatform: config.haste.defaultPlatform,
      extensions: config.moduleFileExtensions.map(extension => '.' + extension),
      hasCoreModules: true,
      moduleDirectories: config.moduleDirectories,
      moduleNameMapper: getModuleNameMapper(config),
      modulePaths: config.modulePaths,
      platforms: config.haste.platforms,
    });
  }

  static runCLI(args?: Object, info?: Array<string>) {
    return require('./cli').run(args, info);
  }

  static getCLIOptions() {
    return require('./cli/args').options;
  }

  requireModule(
    from: Path,
    moduleName?: string,
    options: ?InternalModuleOptions,
  ) {
    const moduleID = this._normalizeID(from, moduleName);
    let modulePath;

    // Some old tests rely on this mocking behavior. Ideally we'll change this
    // to be more explicit.
    const moduleResource = moduleName && this._resolver.getModule(moduleName);
    const manualMock =
      moduleName && this._resolver.getMockModule(from, moduleName);
    if (
      (!options || !options.isInternalModule) &&
      !moduleResource &&
      manualMock &&
      manualMock !== this._isCurrentlyExecutingManualMock &&
      this._explicitShouldMock[moduleID] !== false
    ) {
      modulePath = manualMock;
    }

    if (moduleName && this._resolver.isCoreModule(moduleName)) {
      // $FlowFixMe
      return require(moduleName);
    }

    if (!modulePath) {
      modulePath = this._resolveModule(from, moduleName);
    }

    if (!this._moduleRegistry[modulePath]) {
      // We must register the pre-allocated module object first so that any
      // circular dependencies that may arise while evaluating the module can
      // be satisfied.
      const localModule = {
        filename: modulePath,
        exports: {},
      };
      this._moduleRegistry[modulePath] = localModule;
      if (path.extname(modulePath) === '.json') {
        localModule.exports = this._environment.global.JSON.parse(
          fs.readFileSync(modulePath, 'utf8'),
        );
      } else if (path.extname(modulePath) === '.node') {
        // $FlowFixMe
        localModule.exports = require(modulePath);
      } else {
        this._execModule(localModule, options);
      }
    }
    return this._moduleRegistry[modulePath].exports;
  }

  requireInternalModule(from: Path, to?: string) {
    return this.requireModule(from, to, {isInternalModule: true});
  }

  requireMock(from: Path, moduleName: string) {
    const moduleID = this._normalizeID(from, moduleName);

    if (this._mockRegistry[moduleID]) {<commit_msg>Split internal module registry from main module registry<commit_after>/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 *
 * @flow
 */

'use strict';

import type {Config, Path} from 'types/Config';
import type {Console} from 'console';
import type {Environment} from 'types/Environment';
import type {HasteContext} from 'types/HasteMap';
import type {Script} from 'vm';
import type ModuleMap from '../../jest-haste-map/src/ModuleMap';
import type Resolver from '../../jest-resolve/src';

const HasteMap = require('jest-haste-map');
const ResolverClass = require('jest-resolve');

const fs = require('graceful-fs');
const moduleMocker = require('jest-mock');
const path = require('path');
const shouldInstrument = require('./shouldInstrument');
const transform = require('./transform');
const utils = require('jest-util');

type Module = {
  exports: any,
  filename: string,
  children?: Array<any>,
  parent?: Module,
  paths?: Array<Path>,
  require?: Function,
};

type HasteMapOptions = {
  console?: Console,
  maxWorkers: number,
  resetCache: boolean,
};

type InternalModuleOptions = {isInternalModule: boolean};

const NODE_MODULES = path.sep + 'node_modules' + path.sep;
const SNAPSHOT_EXTENSION = 'snap';

const getModuleNameMapper = (config: Config) => {
  if (config.moduleNameMapper.length) {
    const moduleNameMapper = Object.create(null);
    config.moduleNameMapper.forEach(
      map => moduleNameMapper[map[1]] = new RegExp(map[0]),
    );
    return moduleNameMapper;
  }
  return null;
};

const mockParentModule = {
  exports: {},
  filename: 'mock.js',
  id: 'mockParent',
};

const normalizedIDCache = Object.create(null);
const unmockRegExpCache = new WeakMap();

type BooleanObject = {[key: string]: boolean};

class Runtime {
  _config: Config;
  _currentlyExecutingModulePath: string;
  _environment: Environment;
  _explicitShouldMock: BooleanObject;
  _isCurrentlyExecutingManualMock: ?string;
  _mockFactories: {[key: string]: () => any};
  _mockMetaDataCache: {[key: string]: Object};
  _mockRegistry: {[key: string]: any};
  _mocksPattern: ?RegExp;
  _moduleRegistry: {[key: string]: Module};
  _internalModuleRegistry: {[key: string]: Module};
  _resolver: Resolver;
  _shouldAutoMock: boolean;
  _shouldMockModuleCache: BooleanObject;
  _shouldUnmockTransitiveDependenciesCache: BooleanObject;
  _testRegex: RegExp;
  _transitiveShouldMock: BooleanObject;
  _unmockList: ?RegExp;
  _virtualMocks: BooleanObject;

  constructor(
    config: Config,
    environment: Environment,
    resolver: Resolver,
  ) {
    this._moduleRegistry = Object.create(null);
    this._internalModuleRegistry = Object.create(null);
    this._mockRegistry = Object.create(null);
    this._config = config;
    this._environment = environment;
    this._resolver = resolver;

    this._currentlyExecutingModulePath = '';
    this._explicitShouldMock = Object.create(null);
    this._isCurrentlyExecutingManualMock = null;
    this._mockFactories = Object.create(null);
    this._mocksPattern =
      config.mocksPattern ? new RegExp(config.mocksPattern) : null;
    this._shouldAutoMock = config.automock;
    this._testRegex = new RegExp(config.testRegex.replace(/\//g, path.sep));
    this._virtualMocks = Object.create(null);

    this._mockMetaDataCache = Object.create(null);
    this._shouldMockModuleCache = Object.create(null);
    this._shouldUnmockTransitiveDependenciesCache = Object.create(null);
    this._transitiveShouldMock = Object.create(null);

    this._unmockList = unmockRegExpCache.get(config);
    if (
      !this._unmockList &&
      config.automock &&
      config.unmockedModulePathPatterns
    ) {
      this._unmockList =
        new RegExp(config.unmockedModulePathPatterns.join('|'));
      unmockRegExpCache.set(config, this._unmockList);
    }

    if (config.automock) {
      config.setupFiles.forEach(filePath => {
        if (filePath && filePath.includes(NODE_MODULES)) {
          const moduleID = this._normalizeID(filePath);
          this._transitiveShouldMock[moduleID] = false;
        }
      });
    }

    this.resetModules();

    if (config.setupFiles.length) {
      for (let i = 0; i < config.setupFiles.length; i++) {
        this.requireModule(config.setupFiles[i]);
      }
    }
  }

  static createHasteContext(
    config: Config,
    options: {
      console?: Console,
      maxWorkers: number,
    },
  ): Promise<HasteContext> {
    utils.createDirectory(config.cacheDirectory);
    const instance = Runtime.createHasteMap(config, {
      console: options.console,
      maxWorkers: options.maxWorkers,
      resetCache: !config.cache,
    });
    return instance.build().then(
      hasteMap => ({
        hasteFS: hasteMap.hasteFS,
        resolver: Runtime.createResolver(config, hasteMap.moduleMap),
      }),
      error => {
        throw error;
      },
    );
  }

  static createHasteMap(
    config: Config,
    options?: HasteMapOptions,
  ): HasteMap {
    const ignorePattern = new RegExp(
      [config.cacheDirectory].concat(config.modulePathIgnorePatterns).join('|'),
    );

    return new HasteMap({
      cacheDirectory: config.cacheDirectory,
      console: options && options.console,
      extensions: [SNAPSHOT_EXTENSION].concat(config.moduleFileExtensions),
      ignorePattern,
      maxWorkers: (options && options.maxWorkers) || 1,
      mocksPattern: config.mocksPattern,
      name: config.name,
      platforms: config.haste.platforms || ['ios', 'android'],
      providesModuleNodeModules: config.haste.providesModuleNodeModules,
      resetCache: options && options.resetCache,
      roots: config.testPathDirs,
      useWatchman: config.watchman,
    });
  }

  static createResolver(
    config: Config,
    moduleMap: ModuleMap,
  ): Resolver {
    return new ResolverClass(moduleMap, {
      browser: config.browser,
      defaultPlatform: config.haste.defaultPlatform,
      extensions: config.moduleFileExtensions.map(extension => '.' + extension),
      hasCoreModules: true,
      moduleDirectories: config.moduleDirectories,
      moduleNameMapper: getModuleNameMapper(config),
      modulePaths: config.modulePaths,
      platforms: config.haste.platforms,
    });
  }

  static runCLI(args?: Object, info?: Array<string>) {
    return require('./cli').run(args, info);
  }

  static getCLIOptions() {
    return require('./cli/args').options;
  }

  requireModule(
    from: Path,
    moduleName?: string,
    options: ?InternalModuleOptions,
  ) {
    const moduleID = this._normalizeID(from, moduleName);
    let modulePath;

    const moduleRegistry = (!options || !options.isInternalModule) ?
      this._moduleRegistry :
      this._internalModuleRegistry;

    // Some old tests rely on this mocking behavior. Ideally we'll change this
    // to be more explicit.
    const moduleResource = moduleName && this._resolver.getModule(moduleName);
    const manualMock =
      moduleName && this._resolver.getMockModule(from, moduleName);
    if (
      (!options || !options.isInternalModule) &&
      !moduleResource &&
      manualMock &&
      manualMock !== this._isCurrentlyExecutingManualMock &&
      this._explicitShouldMock[moduleID] !== false
    ) {
      modulePath = manualMock;
    }

    if (moduleName && this._resolver.isCoreModule(moduleName)) {
      // $FlowFixMe
      return require(moduleName);
    }

    if (!modulePath) {
      modulePath = this._resolveModule(from, moduleName);
    }

    if (!moduleRegistry[modulePath]) {
      // We must register the pre-allocated module object first so that any
      // circular dependencies that may arise while evaluating the module can
      // be satisfied.
      const localModule = {
        filename: modulePath,
        exports: {},
      };
      moduleRegistry[modulePath] = localModule;
      if (path.extname(modulePath) === '.json') {
        localModule.exports = this._environment.global.JSON.parse(
          fs.readFileSync(modulePath, 'utf8'),
        );
      } else if (path.extname(modulePath) === '.node') {
        // $FlowFixMe
        localModule.exports = require(modulePath);
      } else {
        this._execModule(localModule, options);
      }
    }
    return moduleRegistry[modulePath].exports;
  }

  requireInternalModule(from: Path, to?: string) {
    return this.requireModule(from, to, {isInternalModule: true});
  }

  requireMock(from: Path, moduleName: string) {
    const moduleID = this._normalizeID(from, moduleName);

    if (this._mockRegistry[moduleID]) {
{'fraction_non_alphanumeric': 0.1197444831591173, 'fraction_numerical': 0.0010452961672473868, 'mean_word_length': 3.4776391055642226, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6593856', 'n_tokens_mistral': 5096, 'n_tokens_neox': 5028, 'n_words': 1119}