"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.ReactEnvType = exports.ReactEnv = void 0;
exports.runTransformersWithContext = runTransformersWithContext;
function _typescript() {
  const data = _interopRequireDefault(require("typescript"));
  _typescript = function () {
    return data;
  };
  return data;
}
function _os() {
  const data = require("os");
  _os = function () {
    return data;
  };
  return data;
}
function _componentModules() {
  const data = require("@teambit/component.modules.component-url");
  _componentModules = function () {
    return data;
  };
  return data;
}
function _builder() {
  const data = require("@teambit/builder");
  _builder = function () {
    return data;
  };
  return data;
}
function _lodash() {
  const data = require("lodash");
  _lodash = function () {
    return data;
  };
  return data;
}
function _preview() {
  const data = require("@teambit/preview");
  _preview = function () {
    return data;
  };
  return data;
}
function _defender() {
  const data = require("@teambit/defender.prettier-formatter");
  _defender = function () {
    return data;
  };
  return data;
}
function _defenderPrettier() {
  const data = require("@teambit/defender.prettier.config-mutator");
  _defenderPrettier = function () {
    return data;
  };
  return data;
}
function _typescript2() {
  const data = require("@teambit/typescript.typescript-compiler");
  _typescript2 = function () {
    return data;
  };
  return data;
}
function _defender2() {
  const data = require("@teambit/defender.eslint-linter");
  _defender2 = function () {
    return data;
  };
  return data;
}
function _defender3() {
  const data = require("@teambit/defender.jest-tester");
  _defender3 = function () {
    return data;
  };
  return data;
}
function _defenderEslint() {
  const data = require("@teambit/defender.eslint.config-mutator");
  _defenderEslint = function () {
    return data;
  };
  return data;
}
function _toolboxPath() {
  const data = require("@teambit/toolbox.path.path");
  _toolboxPath = function () {
    return data;
  };
  return data;
}
function _path() {
  const data = require("path");
  _path = function () {
    return data;
  };
  return data;
}
function _fsExtra() {
  const data = require("fs-extra");
  _fsExtra = function () {
    return data;
  };
  return data;
}
function _react() {
  const data = require("./react.aspect");
  _react = function () {
    return data;
  };
  return data;
}
function _webpackConfig() {
  const data = _interopRequireDefault(require("./webpack/webpack.config.base"));
  _webpackConfig = function () {
    return data;
  };
  return data;
}
function _webpackConfigBase() {
  const data = _interopRequireDefault(require("./webpack/webpack.config.base.prod"));
  _webpackConfigBase = function () {
    return data;
  };
  return data;
}
function _webpackConfigEnv() {
  const data = _interopRequireDefault(require("./webpack/webpack.config.env.dev"));
  _webpackConfigEnv = function () {
    return data;
  };
  return data;
}
function _webpackConfigEnv2() {
  const data = require("./webpack/webpack.config.env.template");
  _webpackConfigEnv2 = function () {
    return data;
  };
  return data;
}
function _webpackConfigComponent() {
  const data = _interopRequireDefault(require("./webpack/webpack.config.component.prod"));
  _webpackConfigComponent = function () {
    return data;
  };
  return data;
}
function _webpackConfigComponent2() {
  const data = _interopRequireDefault(require("./webpack/webpack.config.component.dev"));
  _webpackConfigComponent2 = function () {
    return data;
  };
  return data;
}
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } // ensure reactEnv depends on compositions-app
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// ensure reactEnv depends on docs-app
// eslint-disable-next-line @typescript-eslint/no-unused-vars
// webpack configs for both components and envs
// webpack configs for envs only
// import devPreviewConfigFactory from './webpack/webpack.config.preview.dev';
// webpack configs for components only
const ReactEnvType = exports.ReactEnvType = 'react';
const defaultTsConfig = require('./typescript/tsconfig.json');
const buildTsConfig = require('./typescript/tsconfig.build.json');
const prettierConfig = require('./prettier/prettier.config');

// TODO: move to be taken from the key mode of compiler context

/**
 * a component environment built for [React](https://reactjs.org) .
 */
class ReactEnv {
  constructor(
  /**
   * typescript extension.
   */
  tsAspect,
  /**
   * compiler extension.
   */
  compiler,
  /**
   * webpack extension.
   */
  webpack,
  /**
   * workspace extension.
   */
  workspace,
  /**
   * worker extension.
   */
  worker,
  /**
   * pkg extension.
   */
  pkg,
  /**
   * tester extension
   */
  tester, config, dependencyResolver, devFiles, logger, compilerAspectId) {
    this.tsAspect = tsAspect;
    this.compiler = compiler;
    this.webpack = webpack;
    this.workspace = workspace;
    this.worker = worker;
    this.pkg = pkg;
    this.tester = tester;
    this.config = config;
    this.dependencyResolver = dependencyResolver;
    this.devFiles = devFiles;
    this.logger = logger;
    this.compilerAspectId = compilerAspectId;
    _defineProperty(this, "icon", 'https://static.bit.dev/extensions-icons/react.svg');
  }
  getTsConfig(targetTsConfig) {
    return targetTsConfig ? (0, _lodash().merge)({}, defaultTsConfig, targetTsConfig) : defaultTsConfig;
  }
  getBuildTsConfig(targetTsConfig) {
    return targetTsConfig ? (0, _lodash().merge)({}, buildTsConfig, targetTsConfig) : buildTsConfig;
  }

  /**
   * @deprecated use createCjsJestTester()
   */
  getCjsJestTester(jestConfigPath, jestModulePath) {
    return this.createCjsJestTester(jestConfigPath, jestModulePath);
  }

  /**
   * Get a jest tester instance with react config and cjs configs
   * @param jestConfigPath
   * @param jestModulePath
   * @returns
   */
  createCjsJestTester(jestConfigPath, jestModulePath) {
    const pathToSource = (0, _toolboxPath().pathNormalizeToLinux)(__dirname).replace('/dist', '');
    const defaultConfig = (0, _path().join)(pathToSource, './jest/jest.cjs.config.js');
    const config = jestConfigPath || defaultConfig;
    const worker = this.getJestWorker();
    const tester = _defender3().JestTester.create({
      jest: jestModulePath || require.resolve('jest'),
      config
    }, {
      logger: this.logger,
      worker,
      devFiles: this.devFiles
    });
    return tester;
  }
  getJestWorker() {
    return this.worker.declareWorker('jest', _defender3().jestWorkerPath);
  }

  /**
   * @deprecated use createEsmJestTester()
   */
  getEsmJestTester(jestConfigPath, jestModulePath) {
    return this.createEsmJestTester(jestConfigPath, jestModulePath);
  }

  /**
   * Get a jest tester instance with react config and esm configs
   * @param jestConfigPath
   * @param jestModulePath
   * @returns
   */
  createEsmJestTester(jestConfigPath, jestModulePath) {
    const pathToSource = (0, _toolboxPath().pathNormalizeToLinux)(__dirname).replace('/dist', '');
    const defaultConfig = (0, _path().join)(pathToSource, './jest/jest.esm.config.js');
    const config = jestConfigPath || defaultConfig;
    const worker = this.getJestWorker();
    return _defender3().JestTester.create({
      jest: jestModulePath || require.resolve('jest'),
      config
    }, {
      logger: this.logger,
      worker,
      devFiles: this.devFiles
    });
  }

  /**
   * returns a component tester.
   */
  getTester(jestConfigPath, jestModulePath) {
    return this.createCjsJestTester(jestConfigPath, jestModulePath);
  }
  createTsCompilerOptions(mode = 'dev') {
    const tsconfig = mode === 'dev' ? (0, _lodash().cloneDeep)(defaultTsConfig) : (0, _lodash().cloneDeep)(buildTsConfig);
    const pathToSource = (0, _toolboxPath().pathNormalizeToLinux)(__dirname).replace('/dist/', '/src/');
    const compileJs = true;
    const compileJsx = true;
    return {
      tsconfig,
      // TODO: @david please remove this line and refactor to be something that makes sense.
      types: [(0, _path().resolve)(pathToSource, './typescript/style.d.ts'), (0, _path().resolve)(pathToSource, './typescript/asset.d.ts')],
      compileJs,
      compileJsx
    };
  }

  /**
   * @deprecated use createTsCjsCompiler()
   */
  getTsCjsCompiler(mode = 'dev', transformers = [], tsModule = _typescript().default) {
    return this.createTsCjsCompiler(mode, transformers, tsModule);
  }

  /**
   * Get a compiler instance with react config and set it to cjs module
   * @param mode
   * @param transformers
   * @param tsModule
   * @returns
   */
  createTsCjsCompiler(mode = 'dev', transformers = [], tsModule = _typescript().default) {
    const tsCompileOptions = this.createTsCompilerOptions(mode);
    return this.tsAspect.createCjsCompiler(tsCompileOptions, transformers, tsModule);
  }

  /**
   * @deprecated use createTsEsmCompiler()
   */
  getTsEsmCompiler(mode = 'dev', transformers = [], tsModule = _typescript().default) {
    this.createTsEsmCompiler(mode, transformers, tsModule);
  }

  /**
   * Get a compiler instance with react config and set it to esm module
   * @param mode
   * @param transformers
   * @param tsModule
   * @returns
   */
  createTsEsmCompiler(mode = 'dev', transformers = [], tsModule = _typescript().default) {
    const tsCompileOptions = this.createTsCompilerOptions(mode);
    return this.tsAspect.createEsmCompiler(tsCompileOptions, transformers, tsModule);
  }
  getCompiler(transformers = [], tsModule = _typescript().default) {
    // return this.getTsEsmCompiler('dev', transformers, tsModule);
    return this.createTsCjsCompiler('dev', transformers, tsModule);
  }
  getEslintOptions(options, pluginPath, context) {
    const mergedConfig = {
      // @ts-ignore - this is a bug in the @types/eslint types
      overrideConfig: options,
      extensions: context.extensionFormats,
      useEslintrc: false,
      // TODO: this should be probably be replaced with resolve-plugins-relative-to
      // https://eslint.org/docs/latest/use/command-line-interface#--resolve-plugins-relative-to
      cwd: pluginPath,
      fix: !!context.fix,
      fixTypes: context.fixTypes
    };
    return Object.assign({}, options, {
      config: mergedConfig,
      extensions: context.extensionFormats
    });
  }

  /**
   * returns and configures the component linter.
   */
  getLinter(context, transformers = []) {
    const tsconfigPath = require.resolve('./typescript/tsconfig.json');

    // resolve all plugins from the react environment.
    const eslintConfig = require('./eslint/eslintrc');
    const mergedOptions = this.getEslintOptions(eslintConfig, __dirname, context);
    const configMutator = new (_defenderEslint().EslintConfigMutator)(mergedOptions);
    const transformerContext = {
      fix: !!context.fix
    };
    configMutator.addExtensionTypes(['.md', '.mdx']);
    configMutator.setTsConfig(tsconfigPath);
    const afterMutation = runTransformersWithContext(configMutator.clone(), transformers, transformerContext);
    return _defender2().ESLintLinter.create(afterMutation.raw, {
      logger: this.logger
    });
  }

  /**
   * returns and configures the component formatter.
   */
  getFormatter(context, transformers = []) {
    const configMutator = new (_defenderPrettier().PrettierConfigMutator)(prettierConfig);
    const transformerContext = {
      check: !!(context !== null && context !== void 0 && context.check)
    };
    const afterMutation = runTransformersWithContext(configMutator.clone(), transformers, transformerContext);
    return _defender().PrettierFormatter.create({
      config: afterMutation.raw
    }, {
      logger: this.logger
    });
  }
  getFileMap(components, local = false) {
    return components.reduce((index, component) => {
      component.state.filesystem.files.forEach(file => {
        index[file.path] = {
          id: component.id.toString(),
          homepage: local ? `/${component.id.fullName}` : _componentModules().ComponentUrl.toUrl(component.id)
        };
      });
      return index;
    }, {});
  }
  writeFileMap(components, local) {
    const fileMap = this.getFileMap(components, local);
    const path = (0, _path().join)((0, _os().tmpdir)(), `${Math.random().toString(36).slice(2, 11)}.json`);
    (0, _fsExtra().outputFileSync)(path, JSON.stringify(fileMap));
    return path;
  }

  /**
   * required for `bit start`
   */
  getDevEnvId(id) {
    if (typeof id !== 'string') return _react().ReactAspect.id;
    return id || _react().ReactAspect.id;
  }

  /**
   * get a schema generator instance configured with the correct tsconfig.
   */
  getSchemaExtractor(tsconfig, tsserverPath, contextPath) {
    return this.tsAspect.createSchemaExtractor(this.getTsConfig(tsconfig), tsserverPath, contextPath);
  }

  /**
   * returns and configures the React component dev server.
   * required for `bit start`
   */
  getDevServer(context, transformers = [], webpackModulePath, webpackDevServerModulePath) {
    const baseConfig = (0, _webpackConfig().default)(false);
    const envDevConfig = (0, _webpackConfigEnv().default)(context.id);
    const componentDevConfig = (0, _webpackConfigComponent2().default)(this.workspace.path, context.id);
    const defaultTransformer = configMutator => {
      const merged = configMutator.merge([baseConfig, envDevConfig, componentDevConfig]);
      return merged;
    };
    return this.webpack.createDevServer(context, [defaultTransformer, ...transformers], webpackModulePath, webpackDevServerModulePath);
  }
  async getBundler(context, transformers = [], webpackModulePath) {
    return this.createComponentsWebpackBundler(context, transformers, webpackModulePath);
  }
  async createComponentsWebpackBundler(context, transformers = [], webpackModulePath) {
    const baseConfig = (0, _webpackConfig().default)(!context.development);
    const baseProdConfig = (0, _webpackConfigBase().default)(context.development);
    const componentProdConfig = (0, _webpackConfigComponent().default)();
    const defaultTransformer = configMutator => {
      const merged = configMutator.merge([baseConfig, baseProdConfig, componentProdConfig]);
      return merged;
    };
    const mergedTransformers = [defaultTransformer, ...transformers];
    return this.createWebpackBundler(context, mergedTransformers, webpackModulePath);
  }
  async createTemplateWebpackBundler(context, transformers = [], webpackModulePath) {
    const baseConfig = (0, _webpackConfig().default)(!context.development);
    const baseProdConfig = (0, _webpackConfigBase().default)(context.development);
    const templateConfig = (0, _webpackConfigEnv2().templateWebpackConfigFactory)();
    const defaultTransformer = configMutator => {
      const merged = configMutator.merge([baseConfig, baseProdConfig, templateConfig]);
      return merged;
    };
    const mergedTransformers = [defaultTransformer, ...transformers];
    return this.createWebpackBundler(context, mergedTransformers, webpackModulePath);
  }
  async createWebpackBundler(context, transformers = [], webpackModulePath) {
    return this.webpack.createBundler(context, transformers, undefined, webpackModulePath);
  }
  getAdditionalHostDependencies() {
    return ['@teambit/mdx.ui.mdx-scope-context', '@mdx-js/react', 'react', 'react-dom'];
  }

  /**
   * returns a path to a docs template.
   */
  getDocsTemplate() {
    return require.resolve('@teambit/react.ui.docs-app');
  }
  /**
   * returns the path to the compositions template
   */
  getMounter() {
    return require.resolve('@teambit/react.ui.compositions-app');
  }
  getPreviewConfig() {
    return {
      strategyName: _preview().COMPONENT_PREVIEW_STRATEGY_NAME,
      splitComponentBundle: true,
      isScaling: true
    };
  }

  /**
   * define the package json properties to add to each component.
   */
  getPackageJsonProps() {
    // React compile by default to esm, so uses type module
    // return this.getEsmPackageJsonProps();
    return this.getCjsPackageJsonProps();
  }

  /**
   * @deprecated use createCjsPackageJsonProps()
   */
  getCjsPackageJsonProps() {
    return this.createCjsPackageJsonProps();
  }

  /**
   * Get the default package.json props for a cjs component
   * @returns
   */
  createCjsPackageJsonProps() {
    return this.tsAspect.getCjsPackageJsonProps();
  }

  /**
   * @deprecated use createEsmPackageJsonProps()
   */
  getEsmPackageJsonProps() {
    return this.createEsmPackageJsonProps();
  }

  /**
   * Get the default package.json props for an esm component
   * @returns
   */
  createEsmPackageJsonProps() {
    return this.tsAspect.getEsmPackageJsonProps();
  }
  getNpmIgnore() {
    return [`${_builder().CAPSULE_ARTIFACTS_DIR}/*`];
  }

  /**
   * adds dependencies to all configured components.
   */
  getDependencies() {
    return {
      dependencies: {
        react: '-',
        'react-dom': '-',
        'core-js': '^3.0.0'
      },
      // TODO: add this only if using ts
      devDependencies: {
        react: '-',
        'react-dom': '-',
        '@types/mocha': '-',
        '@types/node': '12.20.4',
        '@types/react': '^17.0.8',
        '@types/react-dom': '^17.0.5',
        '@types/jest': '^26.0.0',
        // This is added as dev dep since our jest file transformer uses babel plugins that require this to be installed
        '@babel/runtime': '7.20.0',
        '@types/testing-library__jest-dom': '5.9.5'
      },
      peerDependencies: {
        react: '^16.8.0 || ^17.0.0',
        'react-dom': '^16.8.0 || ^17.0.0'
      }
    };
  }

  /**
   * returns the component build pipeline.
   */
  getBuildPipe(modifiers = {}) {
    var _modifiers$tsModifier, _modifiers$jestModifi, _modifiers$jestModifi2, _modifiers$tsModifier2;
    const transformers = (modifiers === null || modifiers === void 0 || (_modifiers$tsModifier = modifiers.tsModifier) === null || _modifiers$tsModifier === void 0 ? void 0 : _modifiers$tsModifier.transformers) || [];
    const pathToSource = (0, _toolboxPath().pathNormalizeToLinux)(__dirname).replace('/dist', '');
    const jestConfigPath = (modifiers === null || modifiers === void 0 || (_modifiers$jestModifi = modifiers.jestModifier) === null || _modifiers$jestModifi === void 0 || (_modifiers$jestModifi = _modifiers$jestModifi.transformers) === null || _modifiers$jestModifi === void 0 ? void 0 : _modifiers$jestModifi[0]()) || (0, _path().join)(pathToSource, './jest/jest.cjs.config.js');
    const jestPath = (modifiers === null || modifiers === void 0 || (_modifiers$jestModifi2 = modifiers.jestModifier) === null || _modifiers$jestModifi2 === void 0 ? void 0 : _modifiers$jestModifi2.module) || require.resolve('jest');
    const worker = this.getJestWorker();
    const testerTask = _defender3().JestTask.create({
      config: jestConfigPath,
      jest: jestPath
    }, {
      logger: this.logger,
      worker,
      devFiles: this.devFiles
    });
    return [this.createCjsCompilerTask(transformers, (modifiers === null || modifiers === void 0 || (_modifiers$tsModifier2 = modifiers.tsModifier) === null || _modifiers$tsModifier2 === void 0 ? void 0 : _modifiers$tsModifier2.module) || _typescript().default), testerTask];
  }

  /**
   * @deprecated use createBuildPipeWithoutCompiler()
   */
  getBuildPipeWithoutCompiler() {
    return this.createBuildPipeWithoutCompiler();
  }

  /**
   * Get the react build pipeline without the compilation task.
   * This help in cases you want to only replace the compilation task with something else
   * @returns
   */
  createBuildPipeWithoutCompiler() {
    const pipeWithoutCompiler = this.getBuildPipe().filter(task => task.aspectId !== this.compilerAspectId);
    return pipeWithoutCompiler;
  }

  /**
   * @deprecated use createEsmCompilerTask()
   */
  getEsmCompilerTask(transformers = [], tsModule = _typescript().default) {
    return this.createEsmCompilerTask(transformers, tsModule);
  }

  /**
   * Get a compiler task with react config and set to esm module
   * @param transformers
   * @param tsModule
   * @returns
   */
  createEsmCompilerTask(transformers = [], tsModule = _typescript().default) {
    const tsCompiler = this.createTsEsmCompiler('build', transformers, tsModule);
    return this.compiler.createTask('TSCompiler', tsCompiler);
  }

  /**
   * @deprecated use createCjsCompilerTask()
   * */
  getCjsCompilerTask(transformers = [], tsModule = _typescript().default) {
    return this.createCjsCompilerTask(transformers, tsModule);
  }

  /**
   * Get a compiler task with react config and set to cjs module
   * @param transformers
   * @param tsModule
   * @returns
   */
  createCjsCompilerTask(transformers = [], tsModule = _typescript().default) {
    const tsCompiler = this.createTsCjsCompiler('build', transformers, tsModule);
    return this.compiler.createTask('TSCompiler', tsCompiler);
  }
  workspaceConfig() {
    return [_typescript2().TypescriptConfigWriter.create({
      tsconfig: require.resolve('./typescript/tsconfig.cjs.json')
      // types: resolveTypes(__dirname, ["./types"]),
    }, this.logger), _defender2().EslintConfigWriter.create({
      configPath: require.resolve('./eslint/eslintrc.js'),
      tsconfig: require.resolve('./typescript/tsconfig.cjs.json')
    }, this.logger), _defender().PrettierConfigWriter.create({
      configPath: require.resolve('./prettier/prettier.config.js')
    }, this.logger)];
  }
  async __getDescriptor() {
    return {
      type: ReactEnvType
    };
  }
}
exports.ReactEnv = ReactEnv;
function runTransformersWithContext(config, transformers = [], context) {
  if (!Array.isArray(transformers)) return config;
  const newConfig = transformers.reduce((acc, transformer) => {
    return transformer(acc, context);
  }, config);
  return newConfig;
}

//# sourceMappingURL=react.env.js.map