<commit_before>'use strict';

const tmpdir = require('../utilities/tmpdir');
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');
const path = require('path');
const fs = require('fs-extra');
const resolve = require('resolve');
const compile = require('../utilities/compile');
const TypescriptOutput = require('./typescript-output-plugin');
const CompilerState = require('./compiler-state');

const debugTsc = require('debug')('ember-cli-typescript:tsc');

module.exports = class IncrementalTypescriptCompiler {
  constructor(app, project) {
    if (project._incrementalTsCompiler) {
      throw new Error(
        'Multiple IncrementalTypescriptCompiler instances may not be used with the same project.'
      );
    }

    project._incrementalTsCompiler = this;

    this.app = app;
    this.project = project;
    this.addons = this._discoverAddons(project, []);
    this.state = new CompilerState();

    this._ts = project.require('typescript');
    this._watchProgram = null;
    this._compilerOptions = null;
  }

  treeForHost() {
    let appRoot = `${this._relativeAppRoot()}/app`;
    let srcRoot = `${this._relativeAppRoot()}/src`;

    let trees = {};
    if (fs.existsSync(appRoot)) {
      trees[appRoot] = 'app';
    }

    if (fs.existsSync(srcRoot)) {
      // MU apps currently include tests in production builds, and it's not yet clear
      // how those will be filtered out in the future. We may or may not wind up needing
      // to do that filtering here.
      trees[srcRoot] = 'app/src';
    }

    let appTree = new TypescriptOutput(this, trees);
    let mirage = this._mirageDirectory();
    let mirageTree = mirage && new TypescriptOutput(this, {
      [mirage]: 'app/mirage',
    });

    let tree = new MergeTrees([mirageTree, appTree].filter(Boolean), { overwrite: true });
    return new Funnel(tree, { srcDir: 'app' });
  }

  // Returns any developing addons' app trees. Note that the host app itself is managed
  // by treeForHost() above, as it needs to be treated specially by the build to always
  // 'win' when the host and an addon have clashing files.
  treeForApp() {
    let addonAppTrees = this.addons.map(addon => {
      return new TypescriptOutput(this, {
        [`${this._relativeAddonRoot(addon)}/app`]: 'app',
      });
    });

    let tree = new MergeTrees(addonAppTrees, { overwrite: true });
    return new Funnel(tree, { srcDir: 'app', allowEmpty: true });
  }

  treeForAddons() {
    let paths = {};
    for (let addon of this.addons) {
      let absoluteRoot = this._addonRoot(addon);
      let relativeRoot = this._relativeAddonRoot(addon);

      if (fs.existsSync(`${absoluteRoot}/addon`)) {
        paths[`${relativeRoot}/addon`] = addon.name;
      }

      if (fs.existsSync(`${absoluteRoot}/src`)) {
        paths[`${relativeRoot}/src`] = `${addon.name}/src`;
      }
    }
    return new TypescriptOutput(this, paths);
  }

  treeForAddonTestSupport() {
    let paths = {};
    for (let addon of this.addons) {
      paths[`${this._relativeAddonRoot(addon)}/addon-test-support`] = `${addon.name}/test-support`;
    }
    return new TypescriptOutput(this, paths);
  }

  treeForTestSupport() {
    let paths = {};
    for (let addon of this.addons) {
      paths[`${this._relativeAddonRoot(addon)}/test-support`] = `test-support`;
    }
    return new TypescriptOutput(this, paths);
  }

  treeForTests() {
    let tree = new TypescriptOutput(this, { tests: 'tests' });
    return new Funnel(tree, { srcDir: 'tests' });
  }

  buildPromise() {
    return this.state.buildDeferred.promise;
  }

  outDir() {
    if (!this._outDir) {
      let outDir = path.join(tmpdir(), `e-c-ts-${process.pid}`);<commit_msg>fix: clean up system temp directory when running.<commit_after>'use strict';

const tmpdir = require('../utilities/tmpdir');
const Funnel = require('broccoli-funnel');
const MergeTrees = require('broccoli-merge-trees');
const path = require('path');
const fs = require('fs-extra');
const resolve = require('resolve');
const compile = require('../utilities/compile');
const TypescriptOutput = require('./typescript-output-plugin');
const CompilerState = require('./compiler-state');

const debugTsc = require('debug')('ember-cli-typescript:tsc');

module.exports = class IncrementalTypescriptCompiler {
  constructor(app, project) {
    if (project._incrementalTsCompiler) {
      throw new Error(
        'Multiple IncrementalTypescriptCompiler instances may not be used with the same project.'
      );
    }

    project._incrementalTsCompiler = this;

    this.app = app;
    this.project = project;
    this.addons = this._discoverAddons(project, []);
    this.state = new CompilerState();

    this._ts = project.require('typescript');
    this._watchProgram = null;
    this._compilerOptions = null;
  }

  treeForHost() {
    let appRoot = `${this._relativeAppRoot()}/app`;
    let srcRoot = `${this._relativeAppRoot()}/src`;

    let trees = {};
    if (fs.existsSync(appRoot)) {
      trees[appRoot] = 'app';
    }

    if (fs.existsSync(srcRoot)) {
      // MU apps currently include tests in production builds, and it's not yet clear
      // how those will be filtered out in the future. We may or may not wind up needing
      // to do that filtering here.
      trees[srcRoot] = 'app/src';
    }

    let appTree = new TypescriptOutput(this, trees);
    let mirage = this._mirageDirectory();
    let mirageTree = mirage && new TypescriptOutput(this, {
      [mirage]: 'app/mirage',
    });

    let tree = new MergeTrees([mirageTree, appTree].filter(Boolean), { overwrite: true });
    return new Funnel(tree, { srcDir: 'app' });
  }

  // Returns any developing addons' app trees. Note that the host app itself is managed
  // by treeForHost() above, as it needs to be treated specially by the build to always
  // 'win' when the host and an addon have clashing files.
  treeForApp() {
    let addonAppTrees = this.addons.map(addon => {
      return new TypescriptOutput(this, {
        [`${this._relativeAddonRoot(addon)}/app`]: 'app',
      });
    });

    let tree = new MergeTrees(addonAppTrees, { overwrite: true });
    return new Funnel(tree, { srcDir: 'app', allowEmpty: true });
  }

  treeForAddons() {
    let paths = {};
    for (let addon of this.addons) {
      let absoluteRoot = this._addonRoot(addon);
      let relativeRoot = this._relativeAddonRoot(addon);

      if (fs.existsSync(`${absoluteRoot}/addon`)) {
        paths[`${relativeRoot}/addon`] = addon.name;
      }

      if (fs.existsSync(`${absoluteRoot}/src`)) {
        paths[`${relativeRoot}/src`] = `${addon.name}/src`;
      }
    }
    return new TypescriptOutput(this, paths);
  }

  treeForAddonTestSupport() {
    let paths = {};
    for (let addon of this.addons) {
      paths[`${this._relativeAddonRoot(addon)}/addon-test-support`] = `${addon.name}/test-support`;
    }
    return new TypescriptOutput(this, paths);
  }

  treeForTestSupport() {
    let paths = {};
    for (let addon of this.addons) {
      paths[`${this._relativeAddonRoot(addon)}/test-support`] = `test-support`;
    }
    return new TypescriptOutput(this, paths);
  }

  treeForTests() {
    let tree = new TypescriptOutput(this, { tests: 'tests' });
    return new Funnel(tree, { srcDir: 'tests' });
  }

  buildPromise() {
    return this.state.buildDeferred.promise;
  }

  outDir() {
    if (!this._outDir) {
      let outDir = path.join(tmpdir(), `e-c-ts-${process.pid}`);
      fs.removeSync(outDir);

{'fraction_non_alphanumeric': 0.1456, 'fraction_numerical': 0.0, 'mean_word_length': 3.2667804323094427, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7313140', 'n_tokens_mistral': 2398, 'n_tokens_neox': 2343, 'n_words': 579}