"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.isSupportedExtension = isSupportedExtension;
exports.getLinkToFileContent = getLinkToFileContent;
exports.getLinkToPackageContent = getLinkToPackageContent;
exports.EXTENSIONS_TO_REPLACE_TO_JS_IN_PACKAGES = exports.EXTENSIONS_TO_STRIP_FROM_PACKAGES = exports.JAVASCRIPT_FLAVORS_EXTENSIONS = void 0;

function _normalizePath() {
  const data = _interopRequireDefault(require("normalize-path"));

  _normalizePath = function () {
    return data;
  };

  return data;
}

function _ramda() {
  const data = _interopRequireDefault(require("ramda"));

  _ramda = function () {
    return data;
  };

  return data;
}

function _fileTypesPlugins() {
  const data = _interopRequireDefault(require("../plugins/file-types-plugins"));

  _fileTypesPlugins = function () {
    return data;
  };

  return data;
}

function _utils() {
  const data = require("../utils");

  _utils = function () {
    return data;
  };

  return data;
}

function _logger() {
  const data = _interopRequireDefault(require("../logger/logger"));

  _logger = function () {
    return data;
  };

  return data;
}

const LINKS_CONTENT_TEMPLATES = {
  js: "module.exports = require('{filePath}');",
  ts: "export * from '{filePath}';",
  jsx: "export * from '{filePath}';",
  tsx: "export * from '{filePath}';",
  css: "@import '{filePath}.css';",
  scss: "@import '{filePath}.scss';",
  sass: "@import '{filePath}.sass';",
  less: "@import '{filePath}.less';",
  vue: "<script>\nmodule.exports = require('{filePath}.vue');\n</script>"
};
const PACKAGES_LINKS_CONTENT_TEMPLATES = {
  css: "@import '~{filePath}';",
  scss: "@import '~{filePath}';",
  sass: "@import '~{filePath}';",
  less: "@import '~{filePath}';",
  'st.css': ':import { -st-from: "{filePath}";}',
  vue: "<script>\nmodule.exports = require('{filePath}');\n</script>"
};
const fileExtensionsForNpmLinkGenerator = ['js', 'ts', 'jsx', 'tsx'];
const JAVASCRIPT_FLAVORS_EXTENSIONS = ['js', 'ts', 'jsx', 'tsx'];
exports.JAVASCRIPT_FLAVORS_EXTENSIONS = JAVASCRIPT_FLAVORS_EXTENSIONS;
const EXTENSIONS_TO_STRIP_FROM_PACKAGES = ['js', 'ts', 'jsx', 'tsx'];
exports.EXTENSIONS_TO_STRIP_FROM_PACKAGES = EXTENSIONS_TO_STRIP_FROM_PACKAGES;
const EXTENSIONS_TO_REPLACE_TO_JS_IN_PACKAGES = ['ts', 'jsx', 'tsx'];
exports.EXTENSIONS_TO_REPLACE_TO_JS_IN_PACKAGES = EXTENSIONS_TO_REPLACE_TO_JS_IN_PACKAGES;

function isSupportedExtension(filePath) {
  const ext = (0, _utils().getExt)(filePath);
  const supportedExtensions = getSupportedExtensions();
  return supportedExtensions.includes(ext);
}

function getLinkToFileContent(filePath, importSpecifiers) {
  const fileExt = (0, _utils().getExt)(filePath);

  if (!filePath.startsWith('.')) {
    filePath = `./${filePath}`; // it must be relative, otherwise, it'll search it in node_modules
  }

  const filePathWithoutExt = (0, _utils().getWithoutExt)(filePath);
  const template = getTemplateForFile(fileExt, filePath, importSpecifiers);
  if (!template) return _logWhenNoTemplateWasFound(filePath, fileExt);
  return template.replace(/{filePath}/g, (0, _normalizePath().default)(filePathWithoutExt));
}

function getLinkToPackageContent(filePath, bitPackageName, importSpecifiers) {
  const fileExt = (0, _utils().getExt)(filePath);
  const template = getTemplateForPackage(fileExt, importSpecifiers);
  if (!template) return _logWhenNoTemplateWasFound(filePath, fileExt);
  return template.replace(/{filePath}/g, bitPackageName);
}

function getSupportedExtensions() {
  const extensions = Object.keys(LINKS_CONTENT_TEMPLATES);

  _fileTypesPlugins().default.forEach(plugin => {
    extensions.push(plugin.getExtension());
  });

  return extensions;
}
/**
 * Get the template for the generated link file.
 *
 * For ES6 and TypeScript the template is more complicated and we often need to know how originally the variables were
 * imported, whether default (e.g. import foo from './bar') or non-default (e.g. import { foo } from './bar').
 *
 * The importSpecifier.linkFile attribute exists when the main-file doesn't require the variable directly, but uses a
 * link-file to require it indirectly. E.g. src/bar.js: `import foo from './utils;` utils/index.js: `import foo from './foo';`
 */


function getTemplateForFile(fileExt, filePath, importSpecifiers) {
  if (importSpecifiers && importSpecifiers.length) {
    if (fileExt === 'js' || fileExt === 'jsx') {
      // @see e2e/flows/es6-link-files.e2e.js file for cases covered by the following snippet
      return es6TemplateWithImportSpecifiers(importSpecifiers);
    } else if (fileExt === 'ts' || fileExt === 'tsx') {
      return tsTemplateWithImportSpecifiers(importSpecifiers);
    }
  }

  return _getTemplate(fileExt, importSpecifiers);
}

function getTemplateForPackage(fileExt, importSpecifiers) {
  if (importSpecifiers && importSpecifiers.length) {
    if (fileExt === 'js' || fileExt === 'jsx') {
      // @see e2e/flows/es6-link-files.e2e.js file for cases covered by the following snippet
      return es6TemplateWithImportSpecifiers(importSpecifiers);
    } else if (fileExt === 'ts' || fileExt === 'tsx') {
      return tsTemplateWithImportSpecifiers(importSpecifiers);
    }
  }

  if (!fileExtensionsForNpmLinkGenerator.includes(fileExt)) {
    return PACKAGES_LINKS_CONTENT_TEMPLATES[fileExt];
  }

  return _getTemplate(fileExt, importSpecifiers);
}

function _getTemplate(fileExt, importSpecifiers) {
  _addPluginsTemplatesToLinkContentTemplates(importSpecifiers);

  return LINKS_CONTENT_TEMPLATES[fileExt];
}

function _addPluginsTemplatesToLinkContentTemplates(importSpecifiers) {
  _fileTypesPlugins().default.forEach(plugin => {
    LINKS_CONTENT_TEMPLATES[plugin.getExtension()] = plugin.getTemplate(importSpecifiers);
  });
}

function _logWhenNoTemplateWasFound(filePath, fileExt) {
  _logger().default.debug(`no template was found for ${filePath}, because .${fileExt} extension is not supported`);

  return '';
}

function tsTemplateWithImportSpecifiers(importSpecifiers) {
  return importSpecifiers.map(importSpecifier => {
    let importPart = 'import ';

    if (importSpecifier.linkFile && importSpecifier.linkFile.isDefault || !importSpecifier.linkFile && importSpecifier.mainFile.isDefault) {
      importPart += `${importSpecifier.mainFile.name}`;
    } else {
      importPart += `{ ${importSpecifier.mainFile.name} }`;
    }

    importPart += " from '{filePath}';";
    let exportPart = 'export ';

    if (importSpecifier.mainFile.isDefault) {
      exportPart += `default ${importSpecifier.mainFile.name};`;
    } else {
      exportPart += `{ ${importSpecifier.mainFile.name} };`;
    }

    return `${importPart}\n${exportPart}`;
  }).join('\n');
}

function es6TemplateWithImportSpecifiers(importSpecifiers) {
  return _ramda().default.uniq(importSpecifiers.map(importSpecifier => {
    if (!importSpecifier.linkFile) {
      // when no link-file is involved, use the standard non-es6 syntax (a privilege that doesn't exist for TS)
      return LINKS_CONTENT_TEMPLATES.js;
    } // for link files we need to know whether the main-file imports the variable as default or non-default


    let exportPart = 'exports';

    if (importSpecifier.mainFile.isDefault) {
      exportPart += '.default';
    } else {
      exportPart += `.${importSpecifier.mainFile.name}`;
    }

    const linkVariable = `_${importSpecifier.linkFile.name}`;
    const linkRequire = `var ${linkVariable} = require('{filePath}');`; // when add-module-export babel plugin is used, there is no .default
    // the link-file should support both cases, with and without that plugin

    const pathPart = importSpecifier.linkFile.isDefault ? `${linkVariable} && ${linkVariable}.hasOwnProperty('default') ? ${linkVariable}.default : ${linkVariable}` : `${linkVariable}.${importSpecifier.mainFile.name}`;
    return `${linkRequire}\n${exportPart} = ${pathPart};`;
  })).join('\n');
}