"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

var _path = _interopRequireDefault(require("path"));

var _fs = _interopRequireDefault(require("fs"));

var _utils = require("../utils");

var _log = require("../utils/log");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

let excludeDocsJSON = '{}';

if (_fs.default.existsSync('./__testUtils__/conf/excludeDocs.json')) {
  excludeDocsJSON = _fs.default.readFileSync('./__testUtils__/conf/excludeDocs.json').toString();

  if (excludeDocsJSON.indexOf('\\') !== -1) {
    excludeDocsJSON = excludeDocsJSON.replace(/\\/g, '\\\\');
  }
}

let excludeDocsArray = JSON.parse(excludeDocsJSON); // if (Object.keys(excludeDocsArray).length > 0) {
// }

let getRegex = regexString => regexString.map(str => new RegExp(str));

class UnusedFilesFindPlugin {
  constructor(options = {}) {
    this.usedFilesExcludes = getRegex(options.usedFilesExcludes);
    this.appFilesExcludes = getRegex(options.appFilesExcludes);
    this.origin = options.origin;
    this.delete = options.delete;
    this.sstest = options.ssTest || false;
    this.outputFileName = options.outputFileName;
    this.docsFilename = options.docsFilename || 'Undocsfiles.json';

    if (!this.origin) {
      throw new Error('You must provide origin point of the app');
    }
  }

  isIgnoredUsedFile(file) {
    let result;

    for (let i = 0; i < this.usedFilesExcludes.length; i++) {
      let exclude = this.usedFilesExcludes[i];
      result = exclude.test(file);

      if (result) {
        break;
      }
    }

    return result;
  }

  unDocumentedFiles(outputPath) {
    let status = _fs.default.existsSync(_path.default.join(outputPath, this.outputFileName));

    let unDocsCompObj = {};

    if (status) {
      let data = _fs.default.readFileSync(_path.default.join(outputPath, this.outputFileName)).toString();

      let walkSync = (dir, filelist = [], undocList = []) => {
        let files = _fs.default.readdirSync(dir);

        files.forEach(file => {
          if (_fs.default.statSync(`${dir}/${file}`).isDirectory()) {
            filelist = walkSync(`${dir}/${file}`, filelist, undocList); //eslint-disable-line
          } else {
            if (file.includes('.docs')) {
              if (!(`${dir}/${file}` in JSON.parse(data))) {
                filelist.push(`${dir.replace(_path.default.join(process.cwd(), 'src', 'components'), '')}/${file}`);
              }
            } else {
              if (file.includes('.js') && !file.includes('.spec') && !file.includes('.json')) {
                if (!files.includes('docs')) {
                  if (!excludeDocsArray.docs.exclude.includes(`${dir.replace(_path.default.join(process.cwd(), 'src', 'components'), '')}/${file}`)) {
                    undocList.push(`${dir.replace(_path.default.join(process.cwd(), 'src', 'components'), '')}/${file}`);
                  }
                }
              }
            }
          }
        });
        unDocsCompObj.withoutDocs = undocList;
        return filelist;
      };

      unDocsCompObj.noEnteredComp = walkSync(_path.default.join(process.cwd(), 'src', 'components'), [], []);
      (0, _utils.writeFile)(_path.default.join(outputPath, this.docsFilename), JSON.stringify(unDocsCompObj));
      Object.keys(unDocsCompObj).forEach(key => {
        if (unDocsCompObj[key].length > 0) {
          if (key === 'withoutDocs') {
            (0, _log.log)('\x1b[36m%s\x1b[0m', '\nPlease write docs file for below componenst :- \n');
            unDocsCompObj[key].forEach(value => {
              if (!excludeDocsArray.docs.exclude.includes(value)) {
                (0, _log.log)('\x1b[33m%s\x1b[0m', `${value}`);
              }
            });
          }
        }
      });
    }
  }

  isIgnoredAllFile(file) {
    let result;

    for (let i = 0; i < this.appFilesExcludes.length; i++) {
      let exclude = this.appFilesExcludes[i];
      result = exclude.test(file);

      if (result) {
        break;
      }
    }

    return result;
  }

  getAllFiles(rootPath) {
    let allFiles = [];

    let files = _fs.default.readdirSync(rootPath).map(file => _path.default.join(rootPath, file));

    files.forEach(file => {
      if (_fs.default.statSync(file).isDirectory()) {
        allFiles = allFiles.concat(this.getAllFiles(file));
      } else {
        if (!this.isIgnoredAllFile(file)) {
          allFiles.push(file);
        }
      }
    });
    return allFiles;
  }

  apply(compiler) {
    compiler.hooks.afterEmit.tap('UnusedFilesShowPlugin', compilation => {
      let {
        path: outputPath
      } = compilation.compiler.options.output;
      let usedFiles = Array.from(compilation.fileDependencies).reduce((files, usedFile) => {
        if (!this.isIgnoredUsedFile(usedFile)) {
          files[usedFile] = true;
        }

        return files;
      }, {});
      let allFiles = this.getAllFiles(this.origin);
      let unusedFiles = [];
      allFiles.forEach(file => {
        if (!usedFiles[file]) {
          unusedFiles.push(file);
        }
      });

      if (!unusedFiles.length) {
        (0, _log.log)('There is no unused files');
      } else {
        if (this.outputFileName) {
          (0, _log.log)(`You can see unused files info from ${_path.default.join(outputPath, this.outputFileName)} path`);
          (0, _utils.makeDir)(outputPath);
          (0, _utils.writeFile)(_path.default.join(outputPath, this.outputFileName), JSON.stringify(unusedFiles)).then(() => {
            if (this.sstest) {
              this.unDocumentedFiles(outputPath);
            }
          });
        }
      }

      if (this.delete) {
        unusedFiles.forEach(file => {
          _fs.default.unlinkSync(file);

          (0, _log.log)(`Deleted - ${file}`);
        });
      }
    });
  }

}

var _default = UnusedFilesFindPlugin;
exports.default = _default;