521 lines
24 KiB
JavaScript
521 lines
24 KiB
JavaScript
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.getEmitOutput = exports.getEmitFromWatchHost = exports.getInputFileNameFromOutput = exports.getOutputFileNames = exports.forEachResolvedProjectReference = exports.buildSolutionReferences = exports.reportTranspileErrors = exports.initializeInstance = exports.getTypeScriptInstance = void 0;
|
||
|
const chalk = require("chalk");
|
||
|
const fs = require("fs");
|
||
|
const path = require("path");
|
||
|
const webpack = require("webpack");
|
||
|
const after_compile_1 = require("./after-compile");
|
||
|
const compilerSetup_1 = require("./compilerSetup");
|
||
|
const config_1 = require("./config");
|
||
|
const constants_1 = require("./constants");
|
||
|
const instance_cache_1 = require("./instance-cache");
|
||
|
const logger = require("./logger");
|
||
|
const servicesHost_1 = require("./servicesHost");
|
||
|
const utils_1 = require("./utils");
|
||
|
const watch_run_1 = require("./watch-run");
|
||
|
const instancesBySolutionBuilderConfigs = new Map();
|
||
|
/**
|
||
|
* The loader is executed once for each file seen by webpack. However, we need to keep
|
||
|
* a persistent instance of TypeScript that contains all of the files in the program
|
||
|
* along with definition files and options. This function either creates an instance
|
||
|
* or returns the existing one. Multiple instances are possible by using the
|
||
|
* `instance` property.
|
||
|
*/
|
||
|
function getTypeScriptInstance(loaderOptions, loader) {
|
||
|
const existing = instance_cache_1.getTSInstanceFromCache(loader._compiler, loaderOptions.instance);
|
||
|
if (existing) {
|
||
|
if (!existing.initialSetupPending) {
|
||
|
utils_1.ensureProgram(existing);
|
||
|
}
|
||
|
return { instance: existing };
|
||
|
}
|
||
|
const level = loaderOptions.colors && chalk.supportsColor ? chalk.supportsColor.level : 0;
|
||
|
const colors = new chalk.Instance({ level });
|
||
|
const log = logger.makeLogger(loaderOptions, colors);
|
||
|
const compiler = compilerSetup_1.getCompiler(loaderOptions, log);
|
||
|
if (compiler.errorMessage !== undefined) {
|
||
|
return {
|
||
|
error: utils_1.makeError(loaderOptions, colors.red(compiler.errorMessage), undefined),
|
||
|
};
|
||
|
}
|
||
|
return successfulTypeScriptInstance(loaderOptions, loader, log, colors, compiler.compiler, compiler.compilerCompatible, compiler.compilerDetailsLogMessage);
|
||
|
}
|
||
|
exports.getTypeScriptInstance = getTypeScriptInstance;
|
||
|
function createFilePathKeyMapper(compiler, loaderOptions) {
|
||
|
// Cache file path key - a map lookup is much faster than filesystem/regex operations & the result will never change
|
||
|
const filePathMapperCache = new Map();
|
||
|
// FileName lowercasing copied from typescript
|
||
|
const fileNameLowerCaseRegExp = /[^\u0130\u0131\u00DFa-z0-9\\/:\-_\. ]+/g;
|
||
|
return utils_1.useCaseSensitiveFileNames(compiler, loaderOptions)
|
||
|
? pathResolve
|
||
|
: toFileNameLowerCase;
|
||
|
function pathResolve(filePath) {
|
||
|
let cachedPath = filePathMapperCache.get(filePath);
|
||
|
if (!cachedPath) {
|
||
|
cachedPath = path.resolve(filePath);
|
||
|
filePathMapperCache.set(filePath, cachedPath);
|
||
|
}
|
||
|
return cachedPath;
|
||
|
}
|
||
|
function toFileNameLowerCase(filePath) {
|
||
|
let cachedPath = filePathMapperCache.get(filePath);
|
||
|
if (!cachedPath) {
|
||
|
const filePathKey = pathResolve(filePath);
|
||
|
cachedPath = fileNameLowerCaseRegExp.test(filePathKey)
|
||
|
? filePathKey.replace(fileNameLowerCaseRegExp, ch => ch.toLowerCase())
|
||
|
: filePathKey;
|
||
|
filePathMapperCache.set(filePath, cachedPath);
|
||
|
}
|
||
|
return cachedPath;
|
||
|
}
|
||
|
}
|
||
|
function successfulTypeScriptInstance(loaderOptions, loader, log, colors, compiler, compilerCompatible, compilerDetailsLogMessage) {
|
||
|
const configFileAndPath = config_1.getConfigFile(compiler, colors, loader, loaderOptions, compilerCompatible, log, compilerDetailsLogMessage);
|
||
|
if (configFileAndPath.configFileError !== undefined) {
|
||
|
const { message, file } = configFileAndPath.configFileError;
|
||
|
return {
|
||
|
error: utils_1.makeError(loaderOptions, colors.red('error while reading tsconfig.json:' + constants_1.EOL + message), file),
|
||
|
};
|
||
|
}
|
||
|
const { configFilePath, configFile } = configFileAndPath;
|
||
|
const filePathKeyMapper = createFilePathKeyMapper(compiler, loaderOptions);
|
||
|
if (configFilePath && loaderOptions.projectReferences) {
|
||
|
const configFileKey = filePathKeyMapper(configFilePath);
|
||
|
const existing = getExistingSolutionBuilderHost(configFileKey);
|
||
|
if (existing) {
|
||
|
// Reuse the instance if config file for project references is shared.
|
||
|
instance_cache_1.setTSInstanceInCache(loader._compiler, loaderOptions.instance, existing);
|
||
|
return { instance: existing };
|
||
|
}
|
||
|
}
|
||
|
const module = loader._module;
|
||
|
const basePath = loaderOptions.context || path.dirname(configFilePath || '');
|
||
|
const configParseResult = config_1.getConfigParseResult(compiler, configFile, basePath, configFilePath, loaderOptions);
|
||
|
if (configParseResult.errors.length > 0 && !loaderOptions.happyPackMode) {
|
||
|
const errors = utils_1.formatErrors(configParseResult.errors, loaderOptions, colors, compiler, { file: configFilePath }, loader.context);
|
||
|
/**
|
||
|
* Since webpack 5, the `errors` property is deprecated,
|
||
|
* so we can check if some methods for reporting errors exist.
|
||
|
*/
|
||
|
if (module.addError) {
|
||
|
errors.forEach(error => module.addError(error));
|
||
|
}
|
||
|
else {
|
||
|
module.errors.push(...errors);
|
||
|
}
|
||
|
return {
|
||
|
error: utils_1.makeError(loaderOptions, colors.red('error while parsing tsconfig.json'), configFilePath),
|
||
|
};
|
||
|
}
|
||
|
const compilerOptions = compilerSetup_1.getCompilerOptions(configParseResult, compiler);
|
||
|
const rootFileNames = new Set();
|
||
|
const files = new Map();
|
||
|
const otherFiles = new Map();
|
||
|
const appendTsTsxSuffixesIfRequired = loaderOptions.appendTsSuffixTo.length > 0 ||
|
||
|
loaderOptions.appendTsxSuffixTo.length > 0
|
||
|
? (filePath) => utils_1.appendSuffixesIfMatch({
|
||
|
'.ts': loaderOptions.appendTsSuffixTo,
|
||
|
'.tsx': loaderOptions.appendTsxSuffixTo,
|
||
|
}, filePath)
|
||
|
: (filePath) => filePath;
|
||
|
if (loaderOptions.transpileOnly) {
|
||
|
// quick return for transpiling
|
||
|
// we do need to check for any issues with TS options though
|
||
|
const transpileInstance = {
|
||
|
compiler,
|
||
|
compilerOptions,
|
||
|
appendTsTsxSuffixesIfRequired,
|
||
|
loaderOptions,
|
||
|
rootFileNames,
|
||
|
files,
|
||
|
otherFiles,
|
||
|
version: 0,
|
||
|
program: undefined,
|
||
|
dependencyGraph: new Map(),
|
||
|
transformers: {},
|
||
|
colors,
|
||
|
initialSetupPending: true,
|
||
|
reportTranspileErrors: true,
|
||
|
configFilePath,
|
||
|
configParseResult,
|
||
|
log,
|
||
|
filePathKeyMapper,
|
||
|
};
|
||
|
instance_cache_1.setTSInstanceInCache(loader._compiler, loaderOptions.instance, transpileInstance);
|
||
|
return { instance: transpileInstance };
|
||
|
}
|
||
|
// Load initial files (core lib files, any files specified in tsconfig.json)
|
||
|
let normalizedFilePath;
|
||
|
try {
|
||
|
const filesToLoad = loaderOptions.onlyCompileBundledFiles
|
||
|
? configParseResult.fileNames.filter(fileName => constants_1.dtsDtsxOrDtsDtsxMapRegex.test(fileName))
|
||
|
: configParseResult.fileNames;
|
||
|
filesToLoad.forEach(filePath => {
|
||
|
normalizedFilePath = path.normalize(filePath);
|
||
|
files.set(filePathKeyMapper(normalizedFilePath), {
|
||
|
fileName: normalizedFilePath,
|
||
|
text: fs.readFileSync(normalizedFilePath, 'utf-8'),
|
||
|
version: 0,
|
||
|
});
|
||
|
rootFileNames.add(normalizedFilePath);
|
||
|
});
|
||
|
}
|
||
|
catch (exc) {
|
||
|
return {
|
||
|
error: utils_1.makeError(loaderOptions, colors.red(`A file specified in tsconfig.json could not be found: ${normalizedFilePath}`), normalizedFilePath),
|
||
|
};
|
||
|
}
|
||
|
const instance = {
|
||
|
compiler,
|
||
|
compilerOptions,
|
||
|
appendTsTsxSuffixesIfRequired,
|
||
|
loaderOptions,
|
||
|
rootFileNames,
|
||
|
files,
|
||
|
otherFiles,
|
||
|
languageService: null,
|
||
|
version: 0,
|
||
|
transformers: {},
|
||
|
dependencyGraph: new Map(),
|
||
|
colors,
|
||
|
initialSetupPending: true,
|
||
|
configFilePath,
|
||
|
configParseResult,
|
||
|
log,
|
||
|
filePathKeyMapper,
|
||
|
};
|
||
|
instance_cache_1.setTSInstanceInCache(loader._compiler, loaderOptions.instance, instance);
|
||
|
return { instance };
|
||
|
}
|
||
|
function getExistingSolutionBuilderHost(key) {
|
||
|
const existing = instancesBySolutionBuilderConfigs.get(key);
|
||
|
if (existing)
|
||
|
return existing;
|
||
|
for (const instance of instancesBySolutionBuilderConfigs.values()) {
|
||
|
if (instance.solutionBuilderHost.configFileInfo.has(key)) {
|
||
|
return instance;
|
||
|
}
|
||
|
}
|
||
|
return undefined;
|
||
|
}
|
||
|
// Adding assets in afterCompile is deprecated in webpack 5 so we
|
||
|
// need different behavior for webpack4 and 5
|
||
|
const addAssetHooks = !!webpack.version.match(/^4.*/)
|
||
|
? (loader, instance) => {
|
||
|
// add makeAfterCompile with addAssets = true to emit assets and report errors
|
||
|
loader._compiler.hooks.afterCompile.tapAsync('ts-loader', after_compile_1.makeAfterCompile(instance, instance.configFilePath));
|
||
|
}
|
||
|
: (loader, instance) => {
|
||
|
// We must be running under webpack 5+
|
||
|
// makeAfterCompile is a closure. It returns a function which closes over the variable checkAllFilesForErrors
|
||
|
// We need to get the function once and then reuse it, otherwise it will be recreated each time
|
||
|
// and all files will always be checked.
|
||
|
const cachedMakeAfterCompile = after_compile_1.makeAfterCompile(instance, instance.configFilePath);
|
||
|
// compilation is actually of type webpack.compilation.Compilation, but afterProcessAssets
|
||
|
// only exists in webpack5 and at the time of writing ts-loader is built using webpack4
|
||
|
const makeAssetsCallback = (compilation) => {
|
||
|
compilation.hooks.afterProcessAssets.tap('ts-loader', () => cachedMakeAfterCompile(compilation, () => {
|
||
|
return null;
|
||
|
}));
|
||
|
};
|
||
|
// We need to add the hook above for each run.
|
||
|
// For the first run, we just need to add the hook to loader._compilation
|
||
|
makeAssetsCallback(loader._compilation);
|
||
|
// For future calls in watch mode we need to watch for a new compilation and add the hook
|
||
|
loader._compiler.hooks.compilation.tap('ts-loader', makeAssetsCallback);
|
||
|
// It may be better to add assets at the processAssets stage (https://webpack.js.org/api/compilation-hooks/#processassets)
|
||
|
// This requires Compilation.PROCESS_ASSETS_STAGE_ADDITIONAL, which does not exist in webpack4
|
||
|
// Consider changing this when ts-loader is built using webpack5
|
||
|
};
|
||
|
function initializeInstance(loader, instance) {
|
||
|
if (!instance.initialSetupPending) {
|
||
|
return;
|
||
|
}
|
||
|
instance.initialSetupPending = false;
|
||
|
// same strategy as https://github.com/s-panferov/awesome-typescript-loader/pull/531/files
|
||
|
let { getCustomTransformers: customerTransformers } = instance.loaderOptions;
|
||
|
let getCustomTransformers = Function.prototype;
|
||
|
if (typeof customerTransformers === 'function') {
|
||
|
getCustomTransformers = customerTransformers;
|
||
|
}
|
||
|
else if (typeof customerTransformers === 'string') {
|
||
|
try {
|
||
|
customerTransformers = require(customerTransformers);
|
||
|
}
|
||
|
catch (err) {
|
||
|
throw new Error(`Failed to load customTransformers from "${instance.loaderOptions.getCustomTransformers}": ${err.message}`);
|
||
|
}
|
||
|
if (typeof customerTransformers !== 'function') {
|
||
|
throw new Error(`Custom transformers in "${instance.loaderOptions.getCustomTransformers}" should export a function, got ${typeof getCustomTransformers}`);
|
||
|
}
|
||
|
getCustomTransformers = customerTransformers;
|
||
|
}
|
||
|
if (instance.loaderOptions.transpileOnly) {
|
||
|
const program = (instance.program =
|
||
|
instance.configParseResult.projectReferences !== undefined
|
||
|
? instance.compiler.createProgram({
|
||
|
rootNames: instance.configParseResult.fileNames,
|
||
|
options: instance.configParseResult.options,
|
||
|
projectReferences: instance.configParseResult.projectReferences,
|
||
|
})
|
||
|
: instance.compiler.createProgram([], instance.compilerOptions));
|
||
|
instance.transformers = getCustomTransformers(program);
|
||
|
// Setup watch run for solution building
|
||
|
if (instance.solutionBuilderHost) {
|
||
|
addAssetHooks(loader, instance);
|
||
|
loader._compiler.hooks.watchRun.tapAsync('ts-loader', watch_run_1.makeWatchRun(instance, loader));
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
if (!loader._compiler.hooks) {
|
||
|
throw new Error("You may be using an old version of webpack; please check you're using at least version 4");
|
||
|
}
|
||
|
if (instance.loaderOptions.experimentalWatchApi) {
|
||
|
instance.log.logInfo('Using watch api');
|
||
|
// If there is api available for watch, use it instead of language service
|
||
|
instance.watchHost = servicesHost_1.makeWatchHost(getScriptRegexp(instance), loader, instance, instance.configParseResult.projectReferences);
|
||
|
instance.watchOfFilesAndCompilerOptions = instance.compiler.createWatchProgram(instance.watchHost);
|
||
|
instance.builderProgram = instance.watchOfFilesAndCompilerOptions.getProgram();
|
||
|
instance.program = instance.builderProgram.getProgram();
|
||
|
instance.transformers = getCustomTransformers(instance.program);
|
||
|
}
|
||
|
else {
|
||
|
instance.servicesHost = servicesHost_1.makeServicesHost(getScriptRegexp(instance), loader, instance, instance.configParseResult.projectReferences);
|
||
|
instance.languageService = instance.compiler.createLanguageService(instance.servicesHost, instance.compiler.createDocumentRegistry());
|
||
|
instance.transformers = getCustomTransformers(instance.languageService.getProgram());
|
||
|
}
|
||
|
addAssetHooks(loader, instance);
|
||
|
loader._compiler.hooks.watchRun.tapAsync('ts-loader', watch_run_1.makeWatchRun(instance, loader));
|
||
|
}
|
||
|
}
|
||
|
exports.initializeInstance = initializeInstance;
|
||
|
function getScriptRegexp(instance) {
|
||
|
// If resolveJsonModules is set, we should accept json files
|
||
|
if (instance.configParseResult.options.resolveJsonModule) {
|
||
|
// if allowJs is set then we should accept js(x) files
|
||
|
return instance.configParseResult.options.allowJs === true
|
||
|
? /\.tsx?$|\.json$|\.jsx?$/i
|
||
|
: /\.tsx?$|\.json$/i;
|
||
|
}
|
||
|
// if allowJs is set then we should accept js(x) files
|
||
|
return instance.configParseResult.options.allowJs === true
|
||
|
? /\.tsx?$|\.jsx?$/i
|
||
|
: /\.tsx?$/i;
|
||
|
}
|
||
|
function reportTranspileErrors(instance, loader) {
|
||
|
if (!instance.reportTranspileErrors) {
|
||
|
return;
|
||
|
}
|
||
|
const module = loader._module;
|
||
|
instance.reportTranspileErrors = false;
|
||
|
// happypack does not have _module.errors - see https://github.com/TypeStrong/ts-loader/issues/336
|
||
|
if (!instance.loaderOptions.happyPackMode) {
|
||
|
const solutionErrors = servicesHost_1.getSolutionErrors(instance, loader.context);
|
||
|
const diagnostics = instance.program.getOptionsDiagnostics();
|
||
|
const errors = utils_1.formatErrors(diagnostics, instance.loaderOptions, instance.colors, instance.compiler, { file: instance.configFilePath || 'tsconfig.json' }, loader.context);
|
||
|
/**
|
||
|
* Since webpack 5, the `errors` property is deprecated,
|
||
|
* so we can check if some methods for reporting errors exist.
|
||
|
*/
|
||
|
if (module.addError) {
|
||
|
[...solutionErrors, ...errors].forEach(error => module.addError(error));
|
||
|
}
|
||
|
else {
|
||
|
module.errors.push(...solutionErrors, ...errors);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
exports.reportTranspileErrors = reportTranspileErrors;
|
||
|
function buildSolutionReferences(instance, loader) {
|
||
|
if (!utils_1.supportsSolutionBuild(instance)) {
|
||
|
return;
|
||
|
}
|
||
|
if (!instance.solutionBuilderHost) {
|
||
|
// Use solution builder
|
||
|
instance.log.logInfo('Using SolutionBuilder api');
|
||
|
const scriptRegex = getScriptRegexp(instance);
|
||
|
instance.solutionBuilderHost = servicesHost_1.makeSolutionBuilderHost(scriptRegex, loader, instance);
|
||
|
const solutionBuilder = instance.compiler.createSolutionBuilderWithWatch(instance.solutionBuilderHost, instance.configParseResult.projectReferences.map(ref => ref.path), { verbose: true });
|
||
|
solutionBuilder.build();
|
||
|
instance.solutionBuilderHost.ensureAllReferenceTimestamps();
|
||
|
instancesBySolutionBuilderConfigs.set(instance.filePathKeyMapper(instance.configFilePath), instance);
|
||
|
}
|
||
|
else {
|
||
|
instance.solutionBuilderHost.buildReferences();
|
||
|
}
|
||
|
}
|
||
|
exports.buildSolutionReferences = buildSolutionReferences;
|
||
|
function forEachResolvedProjectReference(resolvedProjectReferences, cb) {
|
||
|
let seenResolvedRefs;
|
||
|
return worker(resolvedProjectReferences);
|
||
|
function worker(resolvedRefs) {
|
||
|
if (resolvedRefs) {
|
||
|
for (const resolvedRef of resolvedRefs) {
|
||
|
if (!resolvedRef) {
|
||
|
continue;
|
||
|
}
|
||
|
if (seenResolvedRefs &&
|
||
|
seenResolvedRefs.some(seenRef => seenRef === resolvedRef)) {
|
||
|
// ignore recursives
|
||
|
continue;
|
||
|
}
|
||
|
(seenResolvedRefs || (seenResolvedRefs = [])).push(resolvedRef);
|
||
|
const result = cb(resolvedRef) || worker(resolvedRef.references);
|
||
|
if (result) {
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return undefined;
|
||
|
}
|
||
|
}
|
||
|
exports.forEachResolvedProjectReference = forEachResolvedProjectReference;
|
||
|
// This code is here as a temporary holder
|
||
|
function fileExtensionIs(fileName, ext) {
|
||
|
return fileName.endsWith(ext);
|
||
|
}
|
||
|
function rootDirOfOptions(instance, configFile) {
|
||
|
return (configFile.options.rootDir ||
|
||
|
instance.compiler.getDirectoryPath(configFile.options.configFilePath));
|
||
|
}
|
||
|
function getOutputPathWithoutChangingExt(instance, inputFileName, configFile, ignoreCase, outputDir) {
|
||
|
return outputDir
|
||
|
? instance.compiler.resolvePath(outputDir, instance.compiler.getRelativePathFromDirectory(rootDirOfOptions(instance, configFile), inputFileName, ignoreCase))
|
||
|
: inputFileName;
|
||
|
}
|
||
|
function getOutputJSFileName(instance, inputFileName, configFile, ignoreCase) {
|
||
|
if (configFile.options.emitDeclarationOnly) {
|
||
|
return undefined;
|
||
|
}
|
||
|
const isJsonFile = fileExtensionIs(inputFileName, '.json');
|
||
|
const outputFileName = instance.compiler.changeExtension(getOutputPathWithoutChangingExt(instance, inputFileName, configFile, ignoreCase, configFile.options.outDir), isJsonFile
|
||
|
? '.json'
|
||
|
: fileExtensionIs(inputFileName, '.tsx') &&
|
||
|
configFile.options.jsx === instance.compiler.JsxEmit.Preserve
|
||
|
? '.jsx'
|
||
|
: '.js');
|
||
|
return !isJsonFile ||
|
||
|
instance.compiler.comparePaths(inputFileName, outputFileName, configFile.options.configFilePath, ignoreCase) !== instance.compiler.Comparison.EqualTo
|
||
|
? outputFileName
|
||
|
: undefined;
|
||
|
}
|
||
|
function getOutputFileNames(instance, configFile, inputFileName) {
|
||
|
const ignoreCase = !utils_1.useCaseSensitiveFileNames(instance.compiler, instance.loaderOptions);
|
||
|
if (instance.compiler.getOutputFileNames) {
|
||
|
return instance.compiler.getOutputFileNames(configFile, inputFileName, ignoreCase);
|
||
|
}
|
||
|
const outputs = [];
|
||
|
const addOutput = (fileName) => fileName && outputs.push(fileName);
|
||
|
const js = getOutputJSFileName(instance, inputFileName, configFile, ignoreCase);
|
||
|
addOutput(js);
|
||
|
if (!fileExtensionIs(inputFileName, '.json')) {
|
||
|
if (js && configFile.options.sourceMap) {
|
||
|
addOutput(`${js}.map`);
|
||
|
}
|
||
|
if ((configFile.options.declaration || configFile.options.composite) &&
|
||
|
instance.compiler.hasTSFileExtension(inputFileName)) {
|
||
|
const dts = instance.compiler.getOutputDeclarationFileName(inputFileName, configFile, ignoreCase);
|
||
|
addOutput(dts);
|
||
|
if (configFile.options.declarationMap) {
|
||
|
addOutput(`${dts}.map`);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return outputs;
|
||
|
}
|
||
|
exports.getOutputFileNames = getOutputFileNames;
|
||
|
function getInputFileNameFromOutput(instance, filePath) {
|
||
|
if (filePath.match(constants_1.tsTsxRegex) && !fileExtensionIs(filePath, '.d.ts')) {
|
||
|
return undefined;
|
||
|
}
|
||
|
if (instance.solutionBuilderHost) {
|
||
|
return instance.solutionBuilderHost.getInputFileNameFromOutput(filePath);
|
||
|
}
|
||
|
const program = utils_1.ensureProgram(instance);
|
||
|
return (program &&
|
||
|
program.getResolvedProjectReferences &&
|
||
|
forEachResolvedProjectReference(program.getResolvedProjectReferences(), ({ commandLine }) => {
|
||
|
const { options, fileNames } = commandLine;
|
||
|
if (!options.outFile && !options.out) {
|
||
|
const input = fileNames.find(file => getOutputFileNames(instance, commandLine, file).find(name => path.resolve(name) === filePath));
|
||
|
return input && path.resolve(input);
|
||
|
}
|
||
|
return undefined;
|
||
|
}));
|
||
|
}
|
||
|
exports.getInputFileNameFromOutput = getInputFileNameFromOutput;
|
||
|
function getEmitFromWatchHost(instance, filePath) {
|
||
|
const program = utils_1.ensureProgram(instance);
|
||
|
const builderProgram = instance.builderProgram;
|
||
|
if (builderProgram && program) {
|
||
|
if (filePath) {
|
||
|
const existing = instance.watchHost.outputFiles.get(instance.filePathKeyMapper(filePath));
|
||
|
if (existing) {
|
||
|
return existing;
|
||
|
}
|
||
|
}
|
||
|
const outputFiles = [];
|
||
|
const writeFile = (fileName, text, writeByteOrderMark) => {
|
||
|
if (fileName.endsWith('.tsbuildinfo')) {
|
||
|
instance.watchHost.tsbuildinfo = {
|
||
|
name: fileName,
|
||
|
writeByteOrderMark,
|
||
|
text,
|
||
|
};
|
||
|
}
|
||
|
else {
|
||
|
outputFiles.push({ name: fileName, writeByteOrderMark, text });
|
||
|
}
|
||
|
};
|
||
|
const sourceFile = filePath ? program.getSourceFile(filePath) : undefined;
|
||
|
// Try emit Next file
|
||
|
while (true) {
|
||
|
const result = builderProgram.emitNextAffectedFile(writeFile,
|
||
|
/*cancellationToken*/ undefined,
|
||
|
/*emitOnlyDtsFiles*/ false, instance.transformers);
|
||
|
if (!result) {
|
||
|
break;
|
||
|
}
|
||
|
// Only put the output file in the cache if the source came from webpack and
|
||
|
// was processed by the loaders
|
||
|
if (result.affected === sourceFile) {
|
||
|
instance.watchHost.outputFiles.set(instance.filePathKeyMapper(result.affected.fileName), outputFiles.slice());
|
||
|
return outputFiles;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return undefined;
|
||
|
}
|
||
|
exports.getEmitFromWatchHost = getEmitFromWatchHost;
|
||
|
function getEmitOutput(instance, filePath) {
|
||
|
if (fileExtensionIs(filePath, instance.compiler.Extension.Dts)) {
|
||
|
return [];
|
||
|
}
|
||
|
if (utils_1.isReferencedFile(instance, filePath)) {
|
||
|
return instance.solutionBuilderHost.getOutputFilesFromReferencedProjectInput(filePath);
|
||
|
}
|
||
|
const program = utils_1.ensureProgram(instance);
|
||
|
if (program !== undefined) {
|
||
|
const sourceFile = program.getSourceFile(filePath);
|
||
|
const outputFiles = [];
|
||
|
const writeFile = (fileName, text, writeByteOrderMark) => outputFiles.push({ name: fileName, writeByteOrderMark, text });
|
||
|
const outputFilesFromWatch = getEmitFromWatchHost(instance, filePath);
|
||
|
if (outputFilesFromWatch) {
|
||
|
return outputFilesFromWatch;
|
||
|
}
|
||
|
program.emit(sourceFile, writeFile,
|
||
|
/*cancellationToken*/ undefined,
|
||
|
/*emitOnlyDtsFiles*/ false, instance.transformers);
|
||
|
return outputFiles;
|
||
|
}
|
||
|
else {
|
||
|
// Emit Javascript
|
||
|
return instance.languageService.getProgram().getSourceFile(filePath) ===
|
||
|
undefined
|
||
|
? []
|
||
|
: instance.languageService.getEmitOutput(filePath).outputFiles;
|
||
|
}
|
||
|
}
|
||
|
exports.getEmitOutput = getEmitOutput;
|
||
|
//# sourceMappingURL=instances.js.map
|