@wessberg/rollup-plugin-ts
Version:
A TypeScript Rollup plugin that bundles declarations, respects Browserslists, and enables seamless integration with transpilers such as babel and swc
1,068 lines (1,032 loc) • 427 kB
JavaScript
'use strict';
var path = require('crosspath');
var chalk = require('chalk');
var util = require('util');
var browserslistGenerator = require('browserslist-generator');
var crypto = require('crypto');
var TSModule = require('typescript');
var browserslist = require('browserslist');
var pluginutils = require('@rollup/pluginutils');
var stringutil = require('@wessberg/stringutil');
var tslib = require('tslib');
var compatfactory = require('compatfactory');
var tsCloneNode = require('ts-clone-node');
var MagicString = require('magic-string');
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var path__default = /*#__PURE__*/_interopDefaultLegacy(path);
var chalk__default = /*#__PURE__*/_interopDefaultLegacy(chalk);
var TSModule__namespace = /*#__PURE__*/_interopNamespace(TSModule);
var MagicString__default = /*#__PURE__*/_interopDefaultLegacy(MagicString);
const SOURCE_MAP_EXTENSION = ".map";
const TS_EXTENSION = ".ts";
const TSX_EXTENSION = ".tsx";
const JS_EXTENSION = ".js";
const JS_MAP_EXTENSION = `${JS_EXTENSION}${SOURCE_MAP_EXTENSION}`;
const JSX_EXTENSION = ".jsx";
const JSON_EXTENSION = ".json";
const MJS_EXTENSION = ".mjs";
const MJSX_EXTENSION = ".mjsx";
const D_TS_EXTENSION = `.d${TS_EXTENSION}`;
const D_TS_MAP_EXTENSION = `.d${TS_EXTENSION}${SOURCE_MAP_EXTENSION}`;
const TSBUILDINFO_EXTENSION = `.tsbuildinfo`;
const ROLLUP_PLUGIN_MULTI_ENTRY_LEGACY = "\0rollup-plugin-multi-entry:entry-point";
const ROLLUP_PLUGIN_VIRTUAL_PREFIX = `\0virtual:`;
const KNOWN_EXTENSIONS = new Set([
D_TS_EXTENSION,
D_TS_MAP_EXTENSION,
JS_MAP_EXTENSION,
TS_EXTENSION,
TSX_EXTENSION,
JS_EXTENSION,
JSX_EXTENSION,
JSON_EXTENSION,
MJS_EXTENSION,
MJSX_EXTENSION,
TSBUILDINFO_EXTENSION
]);
const DEFAULT_TSCONFIG_FILE_NAME = "tsconfig.json";
const NODE_MODULES = "node_modules";
const NODE_MODULES_MATCH_PATH = `/${NODE_MODULES}/`;
const SOURCE_MAP_COMMENT = "//# sourceMappingURL";
const SOURCE_MAP_COMMENT_REGEXP = /\/\/# sourceMappingURL=(\S*)/;
const TSLIB_NAME = `tslib${D_TS_EXTENSION}`;
const BABEL_RUNTIME_PREFIX_1 = "@babel/runtime/";
const BABEL_RUNTIME_PREFIX_2 = "babel-runtime/";
const SWC_HELPERS_PREFIX = "@swc/helpers";
const REGENERATOR_RUNTIME_NAME_1 = `${BABEL_RUNTIME_PREFIX_1}regenerator/index.js`;
const REGENERATOR_RUNTIME_NAME_2 = `${BABEL_RUNTIME_PREFIX_2}regenerator/index.js`;
const REGENERATOR_RUNTIME_NAME_3 = `regenerator-runtime/runtime.js`;
const REGENERATOR_RUNTIME_VIRTUAL_SRC = `${ROLLUP_PLUGIN_VIRTUAL_PREFIX}regenerator-runtime`;
const BABEL_REQUIRE_RUNTIME_HELPER_ESM_REGEXP_1 = new RegExp(`(require\\(["'\`])(${BABEL_RUNTIME_PREFIX_1}helpers/esm/[^"'\`]*)["'\`]\\)`);
const BABEL_REQUIRE_RUNTIME_HELPER_ESM_REGEXP_2 = new RegExp(`(require\\(["'\`])(${BABEL_RUNTIME_PREFIX_2}helpers/esm/[^"'\`]*)["'\`]\\)`);
const BABEL_IMPORT_RUNTIME_HELPER_CJS_REGEXP_1 = new RegExp(`(import\\s+\\w+\\s+from\\s+["'\`])(${BABEL_RUNTIME_PREFIX_1}helpers/[^"'/\`]*)["'\`]`);
const BABEL_IMPORT_RUNTIME_HELPER_CJS_REGEXP_2 = new RegExp(`(import\\s+\\w+\\s+from\\s+["'\`])(${BABEL_RUNTIME_PREFIX_2}helpers/[^"'/\`]*)["'\`]`);
const BABEL_IMPORT_RUNTIME_HELPER_CJS_REGEXP_3 = new RegExp(`(import\\s+["'\`])(${BABEL_RUNTIME_PREFIX_1}helpers/[^"'/\`]*)["'\`]`);
const BABEL_IMPORT_RUNTIME_HELPER_CJS_REGEXP_4 = new RegExp(`(import\\s+["'\`])(${BABEL_RUNTIME_PREFIX_2}helpers/[^"'/\`]*)["'\`]`);
const BABEL_MINIFICATION_BLACKLIST_PRESET_NAMES = [];
const BABEL_MINIFICATION_BLACKLIST_PLUGIN_NAMES = ["@babel/plugin-transform-runtime", "babel-plugin-transform-runtime"];
const BABEL_MINIFY_PRESET_NAMES = ["babel-preset-minify"];
const BABEL_MINIFY_PLUGIN_NAMES = [
"babel-plugin-transform-minify-booleans",
"babel-plugin-minify-builtins",
"babel-plugin-transform-inline-consecutive-adds",
"babel-plugin-minify-dead-code-elimination",
"babel-plugin-minify-constant-folding",
"babel-plugin-minify-flip-comparisons",
"babel-plugin-minify-guarded-expressions",
"babel-plugin-minify-infinity",
"babel-plugin-minify-mangle-names",
"babel-plugin-transform-member-expression-literals",
"babel-plugin-transform-merge-sibling-variables",
"babel-plugin-minify-numeric-literals",
"babel-plugin-transform-property-literals",
"babel-plugin-transform-regexp-constructors",
"babel-plugin-transform-remove-console",
"babel-plugin-transform-remove-debugger",
"babel-plugin-transform-remove-undefined",
"babel-plugin-minify-replace",
"babel-plugin-minify-simplify",
"babel-plugin-transform-simplify-comparison-operators",
"babel-plugin-minify-type-constructors",
"babel-plugin-transform-undefined-to-void"
];
const FORCED_SWC_MODULE_OPTIONS = {
type: "es6"
};
const FORCED_SWC_JSC_OPTIONS = {
externalHelpers: true
};
const FORCED_BABEL_PRESET_ENV_OPTIONS = {
modules: false
};
const FORCED_BABEL_YEARLY_PRESET_OPTIONS = Object.assign({}, FORCED_BABEL_PRESET_ENV_OPTIONS);
const FORCED_BABEL_PLUGIN_TRANSFORM_RUNTIME_OPTIONS = {
helpers: true,
regenerator: true,
// eslint-disable-next-line @typescript-eslint/naming-convention
useESModules: true
};
/**
* Ensures that the given item is in fact an array
*/
function ensureArray(item) {
return Array.isArray(item) ? item : [item];
}
function isTypeScriptLib(p) {
return p.startsWith(`lib.`) && p.endsWith(D_TS_EXTENSION);
}
/**
* Gets the extension of the given file
*/
function getExtension(file) {
if (file.endsWith(D_TS_EXTENSION))
return D_TS_EXTENSION;
else if (file.endsWith(D_TS_MAP_EXTENSION))
return D_TS_MAP_EXTENSION;
return path__default["default"].extname(file);
}
/**
* Returns true if the given path represents an external library
*/
function isExternalLibrary(p) {
return (!p.startsWith(".") && !p.startsWith("/")) || p.includes(NODE_MODULES_MATCH_PATH);
}
/**
* Returns true if the given id represents tslib
*/
function isTslib(p) {
return p === "tslib" || path__default["default"].normalize(p).endsWith(`/tslib/${TSLIB_NAME}`) || path__default["default"].normalize(p).endsWith("/tslib/tslib.es6.js") || path__default["default"].normalize(p).endsWith("/tslib/tslib.js");
}
/**
* Returns true if the given path represents a Babel helper
*/
function isBabelHelper(p) {
return includesBabelEsmHelper(p) || isBabelCjsHelper(p);
}
function isRegeneratorRuntime(p) {
return p.endsWith(REGENERATOR_RUNTIME_NAME_1) || p.endsWith(REGENERATOR_RUNTIME_NAME_2) || p.endsWith(REGENERATOR_RUNTIME_NAME_3) || p === REGENERATOR_RUNTIME_VIRTUAL_SRC;
}
/**
* Returns true if the given path represents a swc helper
*/
function isSwcHelper(p) {
return path__default["default"].normalize(p).includes(`${SWC_HELPERS_PREFIX}`);
}
/**
* Returns true if the given path represents a Babel ESM helper
*/
function includesBabelEsmHelper(p) {
return path__default["default"].normalize(p).includes(`${BABEL_RUNTIME_PREFIX_1}helpers/esm`) || path__default["default"].normalize(p).includes(`${BABEL_RUNTIME_PREFIX_2}helpers/esm`);
}
/**
* Returns true if the given path represents a Babel CJS helper
*/
function isBabelCjsHelper(p) {
return !includesBabelEsmHelper(p) && (path__default["default"].normalize(p).includes(`${BABEL_RUNTIME_PREFIX_1}helpers`) || path__default["default"].normalize(p).includes(`${BABEL_RUNTIME_PREFIX_2}helpers`));
}
/**
* Returns true if the given path represents @babel/preset-env
*/
function isBabelPresetEnv(p) {
return path__default["default"].normalize(p).includes("@babel/preset-env") || path__default["default"].normalize(p).includes("babel-preset-env");
}
/**
* Returns true if the given path is the name of the entry module or @rollup/plugin-multi-entry
*/
function isMultiEntryModule(p, multiEntryModuleName) {
const normalized = path__default["default"].normalize(p);
return normalized === ROLLUP_PLUGIN_MULTI_ENTRY_LEGACY || (multiEntryModuleName != null && normalized === multiEntryModuleName);
}
/**
* Returns true if the given path represents @babel/preset-es[2015|2016|2017]
*/
function isYearlyBabelPreset(p) {
return path__default["default"].normalize(p).includes("@babel/preset-es") || path__default["default"].normalize(p).includes("babel-preset-es");
}
/**
* Returns true if the given path represents @babel/plugin-transform-runtime
*/
function isBabelPluginTransformRuntime(p) {
return path__default["default"].normalize(p).includes("@babel/plugin-transform-runtime") || path__default["default"].normalize(p).includes("babel-plugin-transform-runtime");
}
function somePathsAreRelated(paths, matchPath) {
for (const p of paths) {
if (pathsAreRelated(p, matchPath))
return true;
}
return false;
}
function pathsAreRelated(a, b) {
if (a === b)
return true;
// A node_modules folder may contain one or more nested node_modules
if (a.includes(NODE_MODULES) || b.includes(NODE_MODULES)) {
const firstPathFromNodeModules = a.includes(NODE_MODULES) ? a.slice(a.indexOf(NODE_MODULES)) : a;
const secondPathFromNodeModules = b.includes(NODE_MODULES) ? b.slice(b.indexOf(NODE_MODULES)) : b;
if (firstPathFromNodeModules.includes(secondPathFromNodeModules))
return true;
if (secondPathFromNodeModules.includes(firstPathFromNodeModules))
return true;
}
return false;
}
/**
* Strips the extension from a file
*/
function stripKnownExtension(file) {
let currentExtname;
for (const extName of KNOWN_EXTENSIONS) {
if (file.endsWith(extName)) {
currentExtname = extName;
break;
}
}
if (currentExtname == null)
return file;
return file.slice(0, file.lastIndexOf(currentExtname));
}
/**
* Sets the given extension for the given file
*/
function setExtension(file, extension) {
return path__default["default"].normalize(`${stripKnownExtension(file)}${extension}`);
}
/**
* Ensure that the given path has a leading "."
*/
function ensureHasLeadingDotAndPosix(p, externalGuard = true) {
if (externalGuard && isExternalLibrary(p))
return p;
const posixPath = path__default["default"].normalize(p);
if (posixPath.startsWith("."))
return posixPath;
if (posixPath.startsWith("/"))
return `.${posixPath}`;
return `./${posixPath}`;
}
/**
* Ensures that the given path is relative
*/
function ensureRelative(root, p) {
// If the path is already relative, simply return it
if (!path__default["default"].isAbsolute(p)) {
return path__default["default"].normalize(p);
}
// Otherwise, construct a relative path from the root
return path__default["default"].relative(root, p);
}
/**
* Ensures that the given path is absolute
*/
function ensureAbsolute(root, p) {
// If the path is already absolute, simply return it
if (path__default["default"].isAbsolute(p)) {
return path__default["default"].normalize(p);
}
// Otherwise, construct an absolute path from the root
return path__default["default"].join(root, p);
}
/**
* Checks the id from the given importer with respect to the given externalOption provided to Rollup
*/
function isExternal(id, importer, externalOption) {
var _a;
if (externalOption == null)
return false;
if (externalOption === true)
return true;
if (externalOption === false)
return false;
if (typeof externalOption === "function")
return (_a = externalOption(id, importer, true)) !== null && _a !== void 0 ? _a : false;
const ids = new Set();
const matchers = [];
for (const value of ensureArray(externalOption)) {
if (value instanceof RegExp) {
matchers.push(value);
}
else {
ids.add(value);
}
}
return ids.has(id) || matchers.some(matcher => matcher.test(id));
}
function finalizeParsedCommandLine({ cwd, parsedCommandLineResult: { originalCompilerOptions, parsedCommandLine, tsconfigPath } }) {
// Declarations may be generated, but not as part of the Builder/Incremental program which is used during the transform, renderChunk, and generateBundle phases, so a nice optimization can be to instruct TypeScript not to generate them.
// The raw CompilerOptions will be preserved and used in the last compilation phase to generate declarations if needed.
// However, when 'composite' is true or when incremental compilation is active, declarations must be emitted for buildInfo to work, so under such circumstances this optimization must be skipped.
const canApplySkipDeclarationsOptimization = !Boolean(parsedCommandLine.options.incremental) &&
!Boolean(parsedCommandLine.options.composite) &&
parsedCommandLine.options.tsBuildInfoFile == null &&
(parsedCommandLine.projectReferences == null || parsedCommandLine.projectReferences.length < 1);
if (canApplySkipDeclarationsOptimization) {
parsedCommandLine.options.declaration = false;
parsedCommandLine.options.declarationMap = false;
parsedCommandLine.options.declarationDir = undefined;
}
// Ensure that at tsBuildInfoFile exists if 'composite' or 'incremental' is true
if (parsedCommandLine.options.incremental === true || parsedCommandLine.options.composite === true) {
if (parsedCommandLine.options.tsBuildInfoFile != null) {
parsedCommandLine.options.tsBuildInfoFile = ensureAbsolute(cwd, parsedCommandLine.options.tsBuildInfoFile);
}
// Otherwise, use the _actual_ outDir/outFile from the resolved tsconfig to build the path to the .tsbuildinfo file since TypeScript should be able to actually
// resolve the file from the path pointed to by the user
else {
let tsBuildInfoAbsolutePath;
// Use outDir as the base directory
if (originalCompilerOptions.outDir != null) {
tsBuildInfoAbsolutePath = path__default["default"].join(ensureAbsolute(cwd, originalCompilerOptions.outDir), `${path__default["default"].parse(tsconfigPath).name}${TSBUILDINFO_EXTENSION}`);
}
// Otherwise, use outFile but replace the extension
else if (originalCompilerOptions.outFile != null) {
tsBuildInfoAbsolutePath = ensureAbsolute(cwd, setExtension(originalCompilerOptions.outFile, TSBUILDINFO_EXTENSION));
}
// Otherwise, use 'cwd' as the directory for the .tsbuildinfo file
else {
tsBuildInfoAbsolutePath = path__default["default"].join(ensureAbsolute(cwd, `${path__default["default"].parse(tsconfigPath).name}${TSBUILDINFO_EXTENSION}`));
}
parsedCommandLine.options.tsBuildInfoFile = tsBuildInfoAbsolutePath;
}
}
return parsedCommandLine;
}
function shouldDebugSourceFile(debug, { fileName, text }) {
if (typeof debug === "boolean")
return debug;
return Boolean(debug({
kind: "transformer",
fileName,
text
}));
}
function shouldDebugMetrics(debug, sourceFile) {
if (typeof debug === "boolean")
return debug;
return Boolean(debug(Object.assign({ kind: "metrics" }, (sourceFile == null ? {} : { fileName: sourceFile.fileName }))));
}
function shouldDebugEmit(debug, fileName, text, outputPathKind) {
if (typeof debug === "boolean")
return debug;
return Boolean(debug({
kind: "emit",
fileKind: outputPathKind,
fileName,
text
}));
}
function shouldDebugTsconfig(debug) {
if (typeof debug === "boolean")
return debug;
return Boolean(debug({
kind: "tsconfig"
}));
}
function getFormattedDateTimePrefix() {
const currentDate = new Date();
const currentDateTime = `(${currentDate.getHours().toString().padStart(2, "0")}:${currentDate.getMinutes().toString().padStart(2, "0")}:${currentDate
.getSeconds()
.toString()
.padStart(2, "0")})`;
return `${chalk__default["default"].gray(currentDateTime)} `;
}
function inspect(item, depth = 4) {
console.log(util.inspect(item, { colors: true, depth, maxArrayLength: 1000 }));
}
function logTsconfig(config) {
console.log(`${getFormattedDateTimePrefix()}${chalk__default["default"].red(`tsconfig`)}`);
inspect(config);
}
/**
* Returns true if the given tsconfig is a ParsedCommandLine
*/
function isParsedCommandLine(tsconfig) {
return tsconfig != null && typeof tsconfig !== "string" && typeof tsconfig !== "function" && "options" in tsconfig && !("hook" in tsconfig);
}
/**
* Returns true if the given tsconfig are raw, JSON-serializable CompilerOptions
*/
function isRawCompilerOptions(tsconfig) {
return tsconfig != null && typeof tsconfig !== "string" && typeof tsconfig !== "function" && !("options" in tsconfig) && !("hook" in tsconfig);
}
/**
* Returns true if the given tsconfig is in fact a function that receives resolved CompilerOptions that can be extended
*/
function isTsConfigResolver(tsconfig) {
return tsconfig != null && typeof tsconfig === "function";
}
/**
* Returns true if the given tsconfig is in fact an object that provides a filename for a tsconfig,
* as well as a 'hook' function that receives resolved CompilerOptions that can be extended
*/
function isTsConfigResolverWithFileName(tsconfig) {
return tsconfig != null && typeof tsconfig !== "string" && typeof tsconfig !== "function" && !("options" in tsconfig) && "hook" in tsconfig;
}
/**
* Returns true if the given tsconfig are CompilerOptions
*/
function isCompilerOptions(tsconfig) {
return (tsconfig != null &&
typeof tsconfig !== "string" &&
typeof tsconfig !== "function" &&
!("options" in tsconfig) &&
!("hook" in tsconfig) &&
(("module" in tsconfig && typeof tsconfig.module === "number") ||
("target" in tsconfig && typeof tsconfig.target === "number") ||
("jsx" in tsconfig && typeof tsconfig.jsx === "number") ||
("moduleResolution" in tsconfig && typeof tsconfig.moduleResolution === "number") ||
("newLine" in tsconfig && typeof tsconfig.newLine === "number")));
}
/**
* Gets a ParsedCommandLine based on the given options
*/
function getParsedCommandLine(options) {
const { cwd, tsconfig, fileSystem, forcedCompilerOptions = {}, typescript } = options;
const hasProvidedTsconfig = tsconfig != null;
let originalCompilerOptions;
let parsedCommandLine;
let tsconfigPath = ensureAbsolute(cwd, DEFAULT_TSCONFIG_FILE_NAME);
// If the given tsconfig is already a ParsedCommandLine, use that one, but apply the forced CompilerOptions
if (isParsedCommandLine(tsconfig)) {
originalCompilerOptions = tsconfig.options;
tsconfig.options = Object.assign(Object.assign({}, tsconfig.options), forcedCompilerOptions);
parsedCommandLine = tsconfig;
}
// If the user provided CompilerOptions directly, use those to build a ParsedCommandLine
else if (isCompilerOptions(tsconfig)) {
originalCompilerOptions = typescript.parseJsonConfigFileContent({}, fileSystem, cwd, tsconfig).options;
parsedCommandLine = typescript.parseJsonConfigFileContent({}, fileSystem, cwd, Object.assign(Object.assign({}, tsconfig), forcedCompilerOptions));
}
// If the user provided JSON-serializable ("raw") CompilerOptions directly, use those to build a ParsedCommandLine
else if (isRawCompilerOptions(tsconfig)) {
originalCompilerOptions = typescript.parseJsonConfigFileContent({ compilerOptions: tsconfig }, fileSystem, cwd).options;
parsedCommandLine = typescript.parseJsonConfigFileContent({ compilerOptions: tsconfig }, fileSystem, cwd, forcedCompilerOptions);
}
// Otherwise, attempt to resolve it and parse it
else {
tsconfigPath = ensureAbsolute(cwd, isTsConfigResolverWithFileName(tsconfig) ? tsconfig.fileName : tsconfig != null && !isTsConfigResolver(tsconfig) ? tsconfig : DEFAULT_TSCONFIG_FILE_NAME);
// If the file exists, read the tsconfig on that location
let tsconfigContent = fileSystem.readFile(tsconfigPath);
// Otherwise, if the user hasn't provided any tsconfig at all, start from an empty one (and only use the forced options)
if (tsconfigContent == null && !hasProvidedTsconfig) {
tsconfigContent = "";
}
// Finally, if the user has provided a file that doesn't exist, throw
else if (tsconfigContent == null) {
throw new ReferenceError(`The given tsconfig: '${tsconfigPath}' doesn't exist!`);
}
const tsconfigJson = typescript.parseConfigFileTextToJson(tsconfigPath, tsconfigContent).config;
const basePath = path__default["default"].native.dirname(tsconfigPath);
originalCompilerOptions = typescript.parseJsonConfigFileContent(tsconfigJson, fileSystem, basePath, {}, tsconfigPath).options;
parsedCommandLine = typescript.parseJsonConfigFileContent(tsconfigJson, fileSystem, basePath, forcedCompilerOptions, tsconfigPath);
// If an extension hook has been provided. Make sure to still apply the forced CompilerOptions
if (isTsConfigResolver(tsconfig)) {
originalCompilerOptions = Object.assign({}, tsconfig(originalCompilerOptions));
parsedCommandLine.options = Object.assign(Object.assign({}, tsconfig(parsedCommandLine.options)), forcedCompilerOptions);
}
else if (isTsConfigResolverWithFileName(tsconfig)) {
// If an extension hook has been provided through the 'hook' property. Make sure to still apply the forced CompilerOptions
originalCompilerOptions = Object.assign({}, tsconfig.hook(originalCompilerOptions));
parsedCommandLine.options = Object.assign(Object.assign({}, tsconfig.hook(parsedCommandLine.options)), forcedCompilerOptions);
}
}
// Ensure that the parsed command line, as well as the original CompilerOptions has a base URL
if (parsedCommandLine.options.baseUrl == null) {
parsedCommandLine.options.baseUrl = ".";
}
if (originalCompilerOptions.baseUrl == null) {
originalCompilerOptions.baseUrl = ".";
}
// Remove all non-declaration files from the default file names since these will be handled separately by Rollup.
// Also filter out all files that is matched by the include/exclude globs provided as plugin options
parsedCommandLine.fileNames = parsedCommandLine.fileNames.filter(file => file.endsWith(D_TS_EXTENSION) && options.filter(file));
const parsedCommandLineResult = {
parsedCommandLine,
originalCompilerOptions,
tsconfigPath
};
// On some TypeScript versions such as 3.0.0, the 'composite' feature
// require that a specific configFilePath exists on the CompilerOptions,
// so make sure a path is always set.
if (parsedCommandLine.options.configFilePath == null) {
parsedCommandLine.options.configFilePath = tsconfigPath;
}
// Finalize the parsed command line
finalizeParsedCommandLine(Object.assign(Object.assign({}, options), { parsedCommandLineResult }));
if (shouldDebugTsconfig(options.pluginOptions.debug)) {
logTsconfig(parsedCommandLine);
}
return parsedCommandLineResult;
}
/**
* Gets the ScriptTarget to use from the given Browserslist
*/
function getScriptTargetFromBrowserslist(browserslist, typescript) {
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
switch (browserslistGenerator.getAppropriateEcmaVersionForBrowserslist(browserslist)) {
case "es3":
return typescript.ScriptTarget.ES3;
case "es5":
return typescript.ScriptTarget.ES5;
case "es2015":
return typescript.ScriptTarget.ES2015;
// Support older TypeScript versions that may not supported ES2016 as a ScriptTarget with nullish coalescing
case "es2016":
return (_a = typescript.ScriptTarget.ES2016) !== null && _a !== void 0 ? _a : typescript.ScriptTarget.ES2015;
// Support older TypeScript versions that may not supported ES2017 as a ScriptTarget with nullish coalescing
case "es2017":
return (_c = (_b = typescript.ScriptTarget.ES2017) !== null && _b !== void 0 ? _b : typescript.ScriptTarget.ES2016) !== null && _c !== void 0 ? _c : typescript.ScriptTarget.ES2015;
// Support older TypeScript versions that may not supported ES2018 as a ScriptTarget with nullish coalescing
case "es2018":
return (_f = (_e = (_d = typescript.ScriptTarget.ES2018) !== null && _d !== void 0 ? _d : typescript.ScriptTarget.ES2017) !== null && _e !== void 0 ? _e : typescript.ScriptTarget.ES2016) !== null && _f !== void 0 ? _f : typescript.ScriptTarget.ES2015;
// Support older TypeScript versions that may not supported ES2019 as a ScriptTarget with nullish coalescing
case "es2019":
return (_k = (_j = (_h = (_g = typescript.ScriptTarget.ES2019) !== null && _g !== void 0 ? _g : typescript.ScriptTarget.ES2018) !== null && _h !== void 0 ? _h : typescript.ScriptTarget.ES2017) !== null && _j !== void 0 ? _j : typescript.ScriptTarget.ES2016) !== null && _k !== void 0 ? _k : typescript.ScriptTarget.ES2015;
// Support older TypeScript versions that may not supported ES2020 as a ScriptTarget with nullish coalescing
case "es2020":
return ((_q = (_p = (_o = (_m = (_l = typescript.ScriptTarget.ES2020) !== null && _l !== void 0 ? _l : typescript.ScriptTarget.ES2019) !== null && _m !== void 0 ? _m : typescript.ScriptTarget.ES2018) !== null && _o !== void 0 ? _o : typescript.ScriptTarget.ES2017) !== null && _p !== void 0 ? _p : typescript.ScriptTarget.ES2016) !== null && _q !== void 0 ? _q : typescript.ScriptTarget.ES2015);
// Support older TypeScript versions that may not supported ES2021 as a ScriptTarget with nullish coalescing
case "es2021":
case "es2022":
return ((_w = (_v = (_u = (_t = (_s = (_r = typescript.ScriptTarget.ES2021) !== null && _r !== void 0 ? _r : typescript.ScriptTarget.ES2020) !== null && _s !== void 0 ? _s : typescript.ScriptTarget.ES2019) !== null && _t !== void 0 ? _t : typescript.ScriptTarget.ES2018) !== null && _u !== void 0 ? _u : typescript.ScriptTarget.ES2017) !== null && _v !== void 0 ? _v : typescript.ScriptTarget.ES2016) !== null && _w !== void 0 ? _w : typescript.ScriptTarget.ES2015);
}
}
/**
* Gets the EcmaVersion that represents the given ScriptTarget
*/
function getEcmaVersionForScriptTarget(scriptTarget, typescript) {
switch (scriptTarget) {
case typescript.ScriptTarget.ES3:
return "es3";
case typescript.ScriptTarget.ES5:
return "es5";
case typescript.ScriptTarget.ES2015:
return "es2015";
case typescript.ScriptTarget.ES2016:
return "es2016";
case typescript.ScriptTarget.ES2017:
return "es2017";
case typescript.ScriptTarget.ES2018:
return "es2018";
case typescript.ScriptTarget.ES2019:
return "es2019";
case typescript.ScriptTarget.ES2020:
return "es2020";
case typescript.ScriptTarget.ES2021:
return "es2021";
case typescript.ScriptTarget.ESNext:
case typescript.ScriptTarget.Latest:
case typescript.ScriptTarget.JSON:
return "es2021";
}
}
/**
* Generates a random hash
*/
function generateRandomHash({ length = 8, key } = {}) {
return key == null ? crypto.randomBytes(length / 2).toString("hex") : crypto.createHmac("sha1", key).digest("hex").slice(0, length);
}
function generateRandomIntegerHash(options, offset = 1000000) {
const str = generateRandomHash(options);
let result = 0;
for (let i = 0; i < str.length; i++) {
result = result + str.charCodeAt(i);
}
return result + offset;
}
/**
* Gets the destination directory to use based on the given Rollup output options
*/
function getOutDir(cwd, options) {
let outDir;
if (options == null) {
// Generate a random output directory. The idea is that this will never match any existing files on disk.
// The reason being that Typescript may erroneously think that input files may be overwritten if 'allowJs' is true
// and 'outDir' is '.'
outDir = path__default["default"].join(cwd, generateRandomHash());
}
else if (options.dir != null) {
outDir = options.dir;
}
else if (options.file != null) {
outDir = path__default["default"].dirname(options.file);
}
else {
outDir = cwd;
}
// Return the relative output directory. Default to "." if it should be equal to cwd
const relativeToCwd = ensureRelative(cwd, outDir);
return relativeToCwd === "" ? "." : relativeToCwd;
}
/**
* Gets the ModuleKind to force
*/
function getForcedModuleKindOption({ pluginOptions }) {
// Under these circumstances, TypeScript is a client of Rollup, and Rollup only understands ESM.
// Rollup, not TypeScript, is the decider of which module system(s) to target based on the Rollup configuration.
// Because of this, TypeScript will always be instructed to emit ESM.
return { module: pluginOptions.typescript.ModuleKind.ESNext };
}
/**
* Gets the ScriptTarget to force
*/
function getForcedScriptTargetOption({ pluginOptions, browserslist }) {
// If anything else than TypeScript should perform the transpilation, always target the latest ECMAScript version and let the transpiler take care of the rest
if (pluginOptions.transpiler !== "typescript") {
return { target: pluginOptions.typescript.ScriptTarget.ESNext };
}
// If a Browserslist is provided, and if Typescript should perform the transpilation, decide the appropriate ECMAScript version based on the Browserslist.
else if (browserslist != null && browserslist !== false) {
return { target: getScriptTargetFromBrowserslist(browserslist, pluginOptions.typescript) };
}
// Otherwise, don't force the 'target' option
return {};
}
/**
* Retrieves the CompilerOptions that will be forced
*/
function getForcedCompilerOptions(options) {
return Object.assign(Object.assign(Object.assign({}, getForcedModuleKindOption(options)), getForcedScriptTargetOption(options)), { outDir: getOutDir(options.pluginOptions.cwd),
// Rollup, not Typescript, is the decider of where to put files
outFile: undefined,
// Always generate SourceMaps. Rollup will then decide if it wants to use them or not
sourceMap: true,
// Never use inline source maps. Let Rollup inline the returned SourceMap if it can and if sourcemaps should be emitted in the OutputOptions,
inlineSourceMap: false,
// Since we never use inline source maps, inline sources aren't supported
inlineSources: false,
// Helpers should *always* be imported. We don't want them to be duplicated multiple times within generated chunks
importHelpers: true,
// Node resolution is required when 'importHelpers' are true
moduleResolution: options.pluginOptions.typescript.ModuleResolutionKind.NodeJs,
// Typescript should always be able to emit - otherwise we cannot transform source files
noEmit: false,
// Typescript should always be able to emit - otherwise we cannot transform source files
noEmitOnError: false,
// Typescript should always be able to emit other things than declarations - otherwise we cannot transform source files
emitDeclarationOnly: false,
// Typescript should always be able to emit helpers - since we force 'importHelpers'
noEmitHelpers: false,
// Typescript should always be able to resolve things - otherwise compilation will break
noResolve: false,
// Typescript should never watch files. That is the job of Rollup
watch: false,
// Typescript should never watch files. That is the job of Rollup
preserveWatchOutput: false, skipLibCheck: true });
}
/**
* Returns true if the given OutputFile represents code
*/
function isCodeOutputFile({ name }) {
const extension = getExtension(name);
return [SOURCE_MAP_EXTENSION, D_TS_EXTENSION, D_TS_MAP_EXTENSION].every(otherExtension => extension !== otherExtension);
}
/**
* Returns true if the given OutputFile represents a SourceMap
*/
function isMapOutputFile({ name }) {
const extension = getExtension(name);
return [SOURCE_MAP_EXTENSION, D_TS_MAP_EXTENSION].some(otherExtension => extension === otherExtension);
}
/**
* Gets a SourceDescription from the given EmitOutput
*/
function getSourceDescriptionFromEmitOutput(output) {
const code = output.outputFiles.find(isCodeOutputFile);
if (code == null)
return undefined;
const map = output.outputFiles.find(isMapOutputFile);
// Remove the SourceMap comment from the code if it is given. Rollup is the decider of whether or not to emit SourceMaps and if they should be inlined
const inlinedSourcemapIndex = code.text.indexOf(`\n${SOURCE_MAP_COMMENT}`);
if (inlinedSourcemapIndex >= 0) {
code.text = code.text.slice(0, inlinedSourcemapIndex);
}
return Object.assign({ code: code.text }, (map == null ? {} : { map: map.text }));
}
/**
* Gets diagnostics for the given fileName
*/
function emitDiagnostics({ host, context, pluginOptions }) {
const typescript = host.getTypescript();
let diagnostics = host.getDiagnostics();
// If there is a hook for diagnostics, call it assign the result of calling it to the local variable 'diagnostics'
if (pluginOptions.hook.diagnostics != null) {
diagnostics = pluginOptions.hook.diagnostics(diagnostics);
}
// Don't proceed if the hook returned null or undefined
if (diagnostics == null)
return;
diagnostics.forEach((diagnostic) => {
const message = typescript.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
const position = diagnostic.start == null || diagnostic.file == null ? undefined : diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
// Color-format the diagnostics
const colorFormatted = typescript.formatDiagnosticsWithColorAndContext([diagnostic], host);
// Provide a normalized error code
const code = `${diagnostic.scope == null ? "TS" : diagnostic.scope}${diagnostic.code}`;
// Provide an empty Stack. There's nothing useful in seeing the internals of this Plugin in the reported error
const stack = "";
// Isolate the frame
const newLine = host.getNewLine();
let frame = colorFormatted.slice(colorFormatted.indexOf(message) + message.length);
// Remove the trailing newline from the frame if it has one
if (frame.startsWith(newLine)) {
frame = frame.slice(frame.indexOf(newLine) + newLine.length);
}
switch (diagnostic.category) {
case typescript.DiagnosticCategory.Error:
context.error(Object.assign(Object.assign(Object.assign(Object.assign({ frame,
code, name: code, stack }, (diagnostic.length == null ? {} : { length: diagnostic.length })), (diagnostic.file == null && position == null
? {}
: {
loc: Object.assign(Object.assign(Object.assign({}, (diagnostic.file == null ? {} : { file: diagnostic.file.fileName })), (position == null ? {} : { line: position.line + 1 })), (position == null ? {} : { column: position.character + 1 }))
})), (diagnostic.file == null ? {} : { pos: diagnostic.file.pos })), { message }), position == null ? undefined : { line: position.line + 1, column: position.character + 1 });
break;
case typescript.DiagnosticCategory.Warning:
case typescript.DiagnosticCategory.Message:
case typescript.DiagnosticCategory.Suggestion:
context.warn(Object.assign(Object.assign(Object.assign(Object.assign({ frame,
code, name: code }, (diagnostic.length == null ? {} : { length: diagnostic.length })), { loc: Object.assign(Object.assign(Object.assign({}, (diagnostic.file == null ? {} : { file: diagnostic.file.fileName })), (position == null ? {} : { line: position.line + 1 })), (position == null ? {} : { column: position.character + 1 })) }), (diagnostic.file == null ? {} : { pos: diagnostic.file.pos })), { message }), position == null ? undefined : { line: position.line + 1, column: position.character + 1 });
break;
}
});
}
/**
* Gets the extensions that are supported by Typescript, depending on whether or not to allow JS and JSON
*/
function getSupportedExtensions(allowJs, allowJson) {
return new Set([TS_EXTENSION, TSX_EXTENSION, D_TS_EXTENSION, ...(allowJs ? [JS_EXTENSION, JSX_EXTENSION] : []), ...(allowJson ? [JSON_EXTENSION] : [])]);
}
/**
* Returns true if the given asset is an OutputChunk
*/
function isOutputChunk(thing) {
return !("isAsset" in thing);
}
/**
* Takes all filenames that has been included in the given bundle
*/
function takeBundledFilesNames(bundle) {
const bundledFilenames = new Set();
Object.values(bundle).forEach(value => {
if (isOutputChunk(value)) {
Object.keys(value.modules).forEach(fileName => bundledFilenames.add(path__default["default"].normalize(fileName)));
}
else {
bundledFilenames.add(path__default["default"].normalize(value.fileName));
}
});
return bundledFilenames;
}
/**
* Gets normalized PluginOptions based on the given ones
*/
function getPluginOptions(options) {
// Destructure the options and provide defaults
const { browserslist, transpiler = "typescript", typescript = TSModule__namespace, cwd = path__default["default"].normalize(process.cwd()), tsconfig, transformers, include = [], exclude = [], transpileOnly = false, debug = false, fileSystem = typescript.sys, hook = {} } = options;
// These options will be used no matter what
const baseOptions = {
typescript,
browserslist,
cwd: ensureAbsolute(process.cwd(), cwd),
exclude,
include,
transformers,
tsconfig,
transpileOnly,
debug,
fileSystem,
hook
};
switch (transpiler) {
case "babel": {
return Object.assign(Object.assign(Object.assign({}, baseOptions), ("babelConfig" in options ? { babelConfig: options.babelConfig } : {})), { transpiler: "babel" });
}
case "swc": {
return Object.assign(Object.assign(Object.assign({}, baseOptions), ("swcConfig" in options ? { swcConfig: options.swcConfig } : {})), { transpiler: "swc" });
}
// TypeScript
default: {
return Object.assign(Object.assign({}, baseOptions), { transpiler: "typescript" });
}
}
}
/**
* Returns true if the given browserslist is raw input for a Browserslist
*/
function isBrowserslistInput(browserslist) {
return typeof browserslist === "string" || Array.isArray(browserslist);
}
/**
* Returns true if the given browserslist is an IBrowserslistQueryConfig
*/
function isBrowserslistQueryConfig(browserslist) {
return browserslist != null && !isBrowserslistInput(browserslist) && browserslist !== false && "query" in browserslist && browserslist.query != null;
}
/**
* Returns true if the given browserslist is an IBrowserslistPathConfig
*/
function isBrowserslistPathConfig(browserslist) {
return browserslist != null && !isBrowserslistInput(browserslist) && browserslist !== false && "path" in browserslist && browserslist.path != null;
}
/**
* Gets a Browserslist based on the given options
*/
function getBrowserslist({ browserslist: browserslist$1, cwd, fileSystem }) {
// If a Browserslist is provided directly from the options, use that
if (browserslist$1 != null) {
// If the Browserslist is equal to false, it should never be used. Return undefined
if (browserslist$1 === false) {
return false;
}
// If the Browserslist is some raw input queries, use them directly
else if (isBrowserslistInput(browserslist$1)) {
return browserslistGenerator.normalizeBrowserslist(ensureArray(browserslist$1));
}
// If the Browserslist is a config with raw query options, use them directly
else if (isBrowserslistQueryConfig(browserslist$1)) {
return browserslistGenerator.normalizeBrowserslist(ensureArray(browserslist$1.query));
}
// If the Browserslist is a config with a path, attempt to resolve the Browserslist from that property
else if (isBrowserslistPathConfig(browserslist$1)) {
const browserslistPath = ensureAbsolute(cwd, browserslist$1.path);
const errorMessage = `The given path for a Browserslist: '${browserslistPath}' could not be resolved from '${cwd}'`;
if (!fileSystem.fileExists(path__default["default"].native.normalize(browserslistPath))) {
throw new ReferenceError(errorMessage);
}
else {
// Read the config
const match = browserslist.readConfig(browserslistPath);
if (match == null) {
throw new ReferenceError(errorMessage);
}
else {
return match.defaults;
}
}
}
// The config object could not be validated. Return undefined
else {
return undefined;
}
}
// Otherwise, try to locate a Browserslist
else {
const config = browserslist.findConfig(cwd);
return config == null ? undefined : config.defaults;
}
}
/**
* A Cache over resolved modules
*/
class ResolveCache {
constructor(options) {
this.options = options;
/**
* A memory-persistent cache of resolved modules for files over time
*/
this.RESOLVE_CACHE = new Map();
}
/**
* Gets the resolved path for an id from a parent
*/
getFromCache(id, parent) {
const parentMap = this.RESOLVE_CACHE.get(parent);
if (parentMap == null)
return undefined;
return parentMap.get(id);
}
/**
* Deletes the entry matching the given parent
*/
delete(parent) {
return this.RESOLVE_CACHE.delete(parent);
}
clear() {
this.RESOLVE_CACHE.clear();
}
/**
* Sets the given resolved module in the resolve cache
*/
setInCache(result, id, parent) {
let parentMap = this.RESOLVE_CACHE.get(parent);
if (parentMap == null) {
parentMap = new Map();
this.RESOLVE_CACHE.set(parent, parentMap);
}
parentMap.set(id, result);
return result;
}
/**
* Resolves a module name, including internal helpers such as tslib, even if they aren't included in the language service
*/
resolveModuleName(typescript, moduleName, containingFile, compilerOptions, host, cache, redirectedReference) {
// Default to using Typescript's resolver directly
return typescript.resolveModuleName(moduleName, containingFile, compilerOptions, host, cache, redirectedReference);
}
/**
* Gets a cached module result for the given file from the given parent and returns it if it exists already.
* If not, it will compute it, update the cache, and then return it
*/
get(options) {
const { id, parent, moduleResolutionHost } = options;
let cacheResult = this.getFromCache(id, parent);
const typescript = moduleResolutionHost.getTypescript();
const compilerOptions = moduleResolutionHost.getCompilationSettings();
const cwd = moduleResolutionHost.getCwd();
const nonAmbientSupportedExtensions = moduleResolutionHost.getSupportedNonAmbientExtensions();
if (cacheResult != null) {
return cacheResult;
}
// Resolve the file via Typescript, either through classic or node module resolution
const { resolvedModule } = this.resolveModuleName(typescript, id, parent, compilerOptions, moduleResolutionHost);
// If it could not be resolved, the cache result will be equal to null
if (resolvedModule == null) {
cacheResult = null;
}
// Otherwise, proceed
else {
// Make sure that the path is absolute from the cwd
resolvedModule.resolvedFileName = path__default["default"].includeDriveLetter(path__default["default"].normalize(ensureAbsolute(cwd, resolvedModule.resolvedFileName)));
if (resolvedModule.resolvedFileName.endsWith(D_TS_EXTENSION)) {
resolvedModule.resolvedAmbientFileName = resolvedModule.resolvedFileName;
resolvedModule.resolvedFileName = undefined;
resolvedModule.extension = D_TS_EXTENSION;
if (isTslib(id)) {
// Sometimes the drive letter is omitted by TypeScript on Windows here, which can lead to problems
const candidate = path__default["default"].includeDriveLetter(path__default["default"].normalize(setExtension(resolvedModule.resolvedAmbientFileName, `.es6${JS_EXTENSION}`)));
if (this.options.fileSystem.fileExists(path__default["default"].native.normalize(candidate))) {
resolvedModule.resolvedFileName = candidate;
}
}
// Don't go and attempt to resolve sources for external libraries
else if (resolvedModule.isExternalLibraryImport == null || !resolvedModule.isExternalLibraryImport) {
// Try to determine the resolved file name.
for (const extension of nonAmbientSupportedExtensions) {
const candidate = path__default["default"].normalize(setExtension(resolvedModule.resolvedAmbientFileName, extension));
if (this.options.fileSystem.fileExists(path__default["default"].native.normalize(candidate))) {
resolvedModule.resolvedFileName = candidate;
break;
}
}
}
}
else {
resolvedModule.resolvedAmbientFileName = undefined;
const candidate = path__default["default"].normalize(setExtension(resolvedModule.resolvedFileName, D_TS_EXTENSION));
if (this.options.fileSystem.fileExists(path__default["default"].native.normalize(candidate))) {
resolvedModule.resolvedAmbientFileName = candidate;
}
}
cacheResult = resolvedModule;
}
// Store the new result in the cache
return this.setInCache(cacheResult, id, parent);
}
}
const REGENERATOR_SOURCE = `\
/**
* Copyright (c) 2014-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
"use strict";
var Op = Object.prototype;
var hasOwn = Op.hasOwnProperty;
var undefined; // More compressible than void 0.
var $Symbol = typeof Symbol === "function" ? Symbol : {};
var iteratorSymbol = $Symbol.iterator || "@@iterator";
var asyncIteratorSymbol = $Symbol.asyncIterator || "@@asyncIterator";
var toStringTagSymbol = $Symbol.toStringTag || "@@toStringTag";
function wrap(innerFn, outerFn, self, tryLocsList) {
// If outerFn provided and outerFn.prototype is a Generator, then outerFn.prototype instanceof Generator.
var protoGenerator = outerFn && outerFn.prototype instanceof Generator ? outerFn : Generator;
var generator = Object.create(protoGenerator.prototype);
var context = new Context(tryLocsList || []);
// The ._invoke method unifies the implementations of the .next,
// .throw, and .return methods.
generator._invoke = makeInvokeMethod(innerFn, self, context);
return generator;
}
// Try/catch helper to minimize deoptimizations. Returns a completion
// record like context.tryEntries[i].completion. This interface could
// have been (and was previously) designed to take a closure to be
// invoked without arguments, but in all the cases we care about we
// already have an existing method we want to call, so there's no need
// to create a new function object. We can even get away with assuming
// the method takes exactly one argument, since that happens to be true
// in every case, so we don't have to touch the arguments object. The
// only additional allocation required is the completion record, which
// has a stable shape and so hopefully should be cheap to allocate.
function tryCatch(fn, obj, arg) {
try {
return { type: "normal", arg: fn.call(obj, arg) };
} catch (err) {
return { type: "throw", arg: err };
}
}
var GenStateSuspendedStart = "suspendedStart";
var GenStateSuspendedYield = "suspendedYield";
var GenStateExecuting = "executing";
var GenStateCompleted = "completed";
// Returning this object from the innerFn has the same effect as
// breaking out of the dispatch switch statement.
var ContinueSentinel = {};
// Dummy constructor functions that we use as the .constructor and
// .constructor