start werk

This commit is contained in:
Daniel Hübleitner
2019-09-17 23:18:00 +02:00
commit 615619e6e7
3598 changed files with 1238825 additions and 0 deletions
+180
View File
@@ -0,0 +1,180 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const constants = require("./constants");
const instances_1 = require("./instances");
const utils_1 = require("./utils");
function makeAfterCompile(instance, configFilePath) {
let getCompilerOptionDiagnostics = true;
let checkAllFilesForErrors = true;
return (compilation, callback) => {
// Don't add errors for child compilations
if (compilation.compiler.isChild()) {
callback();
return;
}
removeTSLoaderErrors(compilation.errors);
provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath);
getCompilerOptionDiagnostics = false;
const modules = determineModules(compilation);
const filesToCheckForErrors = determineFilesToCheckForErrors(checkAllFilesForErrors, instance);
checkAllFilesForErrors = false;
const filesWithErrors = new Map();
provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance);
provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation);
instance.filesWithErrors = filesWithErrors;
instance.modifiedFiles = null;
instance.projectsMissingSourceMaps = new Set();
callback();
};
}
exports.makeAfterCompile = makeAfterCompile;
/**
* handle compiler option errors after the first compile
*/
function provideCompilerOptionDiagnosticErrorsToWebpack(getCompilerOptionDiagnostics, compilation, instance, configFilePath) {
if (getCompilerOptionDiagnostics) {
const { languageService, loaderOptions, compiler, program } = instance;
const errorsToAdd = utils_1.formatErrors(program === undefined
? languageService.getCompilerOptionsDiagnostics()
: program.getOptionsDiagnostics(), loaderOptions, instance.colors, compiler, { file: configFilePath || 'tsconfig.json' }, compilation.compiler.context);
compilation.errors.push(...errorsToAdd);
}
}
/**
* build map of all modules based on normalized filename
* this is used for quick-lookup when trying to find modules
* based on filepath
*/
function determineModules(compilation) {
return compilation.modules.reduce((modules, module) => {
if (module.resource) {
const modulePath = path.normalize(module.resource);
const existingModules = modules.get(modulePath);
if (existingModules !== undefined) {
if (existingModules.indexOf(module) === -1) {
existingModules.push(module);
}
}
else {
modules.set(modulePath, [module]);
}
}
return modules;
}, new Map());
}
function determineFilesToCheckForErrors(checkAllFilesForErrors, instance) {
const { files, modifiedFiles, filesWithErrors, otherFiles } = instance;
// calculate array of files to check
const filesToCheckForErrors = new Map();
if (checkAllFilesForErrors) {
// check all files on initial run
for (const [filePath, file] of files) {
filesToCheckForErrors.set(filePath, file);
}
for (const [filePath, file] of otherFiles) {
filesToCheckForErrors.set(filePath, file);
}
}
else if (modifiedFiles !== null && modifiedFiles !== undefined) {
// check all modified files, and all dependants
for (const modifiedFileName of modifiedFiles.keys()) {
utils_1.collectAllDependants(instance.reverseDependencyGraph, modifiedFileName).forEach(fileName => {
const fileToCheckForErrors = files.get(fileName) || otherFiles.get(fileName);
filesToCheckForErrors.set(fileName, fileToCheckForErrors);
});
}
}
// re-check files with errors from previous build
if (filesWithErrors !== undefined) {
for (const [fileWithErrorName, fileWithErrors] of filesWithErrors) {
filesToCheckForErrors.set(fileWithErrorName, fileWithErrors);
}
}
return filesToCheckForErrors;
}
function provideErrorsToWebpack(filesToCheckForErrors, filesWithErrors, compilation, modules, instance) {
const { compiler, program, languageService, files, loaderOptions, compilerOptions, otherFiles } = instance;
const filePathRegex = compilerOptions.checkJs === true
? constants.dtsTsTsxJsJsxRegex
: constants.dtsTsTsxRegex;
for (const filePath of filesToCheckForErrors.keys()) {
if (filePath.match(filePathRegex) === null) {
continue;
}
const sourceFile = program === undefined ? undefined : program.getSourceFile(filePath);
// If the source file is undefined, that probably means its actually part of an unbuilt project reference,
// which will have already produced a more useful error than the one we would get by proceeding here.
// If its undefined and were not using project references at all, I guess carry on so the user will
// get a useful error about which file was unexpectedly missing.
if (utils_1.isUsingProjectReferences(instance) && sourceFile === undefined) {
continue;
}
const errors = program === undefined
? [
...languageService.getSyntacticDiagnostics(filePath),
...languageService.getSemanticDiagnostics(filePath)
]
: [
...program.getSyntacticDiagnostics(sourceFile),
...program.getSemanticDiagnostics(sourceFile)
];
if (errors.length > 0) {
const fileWithError = files.get(filePath) || otherFiles.get(filePath);
filesWithErrors.set(filePath, fileWithError);
}
// if we have access to a webpack module, use that
const associatedModules = modules.get(filePath);
if (associatedModules !== undefined) {
associatedModules.forEach(module => {
// remove any existing errors
removeTSLoaderErrors(module.errors);
// append errors
const formattedErrors = utils_1.formatErrors(errors, loaderOptions, instance.colors, compiler, { module }, compilation.compiler.context);
module.errors.push(...formattedErrors);
compilation.errors.push(...formattedErrors);
});
}
else {
// otherwise it's a more generic error
const formattedErrors = utils_1.formatErrors(errors, loaderOptions, instance.colors, compiler, { file: filePath }, compilation.compiler.context);
compilation.errors.push(...formattedErrors);
}
}
}
/**
* gather all declaration files from TypeScript and output them to webpack
*/
function provideDeclarationFilesToWebpack(filesToCheckForErrors, instance, compilation) {
for (const filePath of filesToCheckForErrors.keys()) {
if (filePath.match(constants.tsTsxRegex) === null) {
continue;
}
const outputFiles = instances_1.getEmitOutput(instance, filePath);
const declarationFiles = outputFiles.filter(outputFile => outputFile.name.match(constants.dtsDtsxOrDtsDtsxMapRegex));
declarationFiles.forEach(declarationFile => {
const assetPath = path.relative(compilation.compiler.outputPath, declarationFile.name);
compilation.assets[assetPath] = {
source: () => declarationFile.text,
size: () => declarationFile.text.length
};
});
}
}
/**
* handle all other errors. The basic approach here to get accurate error
* reporting is to start with a "blank slate" each compilation and gather
* all errors from all files. Since webpack tracks errors in a module from
* compilation-to-compilation, and since not every module always runs through
* the loader, we need to detect and remove any pre-existing errors.
*/
function removeTSLoaderErrors(errors) {
let index = -1;
let length = errors.length;
while (++index < length) {
if (errors[index].loaderSource === 'ts-loader') {
errors.splice(index--, 1);
length--;
}
}
}
+57
View File
@@ -0,0 +1,57 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const semver = require("semver");
const typescript = require("typescript");
function getCompiler(loaderOptions, log) {
let compiler;
let errorMessage;
let compilerDetailsLogMessage;
let compilerCompatible = false;
try {
compiler = require(loaderOptions.compiler);
}
catch (e) {
errorMessage =
loaderOptions.compiler === 'typescript'
? 'Could not load TypeScript. Try installing with `yarn add typescript` or `npm install typescript`. If TypeScript is installed globally, try using `yarn link typescript` or `npm link typescript`.'
: `Could not load TypeScript compiler with NPM package name \`${loaderOptions.compiler}\`. Are you sure it is correctly installed?`;
}
if (errorMessage === undefined) {
compilerDetailsLogMessage = `ts-loader: Using ${loaderOptions.compiler}@${compiler.version}`;
compilerCompatible = false;
if (loaderOptions.compiler === 'typescript') {
if (compiler.version !== undefined &&
semver.gte(compiler.version, '2.4.1')) {
// don't log yet in this case, if a tsconfig.json exists we want to combine the message
compilerCompatible = true;
}
else {
log.logError(`${compilerDetailsLogMessage}. This version is incompatible with ts-loader. Please upgrade to the latest version of TypeScript.`);
}
}
else {
log.logWarning(`${compilerDetailsLogMessage}. This version may or may not be compatible with ts-loader.`);
}
}
return {
compiler,
compilerCompatible,
compilerDetailsLogMessage,
errorMessage
};
}
exports.getCompiler = getCompiler;
function getCompilerOptions(configParseResult) {
const compilerOptions = Object.assign({}, configParseResult.options, {
skipLibCheck: true,
suppressOutputPathCheck: true // This is why: https://github.com/Microsoft/TypeScript/issues/7363
});
// if `module` is not specified and not using ES6+ target, default to CJS module output
if (compilerOptions.module === undefined &&
(compilerOptions.target !== undefined &&
compilerOptions.target < typescript.ScriptTarget.ES2015)) {
compilerOptions.module = typescript.ModuleKind.CommonJS;
}
return compilerOptions;
}
exports.getCompilerOptions = getCompilerOptions;
+85
View File
@@ -0,0 +1,85 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const utils_1 = require("./utils");
function getConfigFile(compiler, colors, loader, loaderOptions, compilerCompatible, log, compilerDetailsLogMessage) {
const configFilePath = findConfigFile(compiler, path.dirname(loader.resourcePath), loaderOptions.configFile);
let configFileError;
let configFile;
if (configFilePath !== undefined) {
if (compilerCompatible) {
log.logInfo(`${compilerDetailsLogMessage} and ${configFilePath}`);
}
else {
log.logInfo(`ts-loader: Using config file at ${configFilePath}`);
}
configFile = compiler.readConfigFile(configFilePath, compiler.sys.readFile);
if (configFile.error !== undefined) {
configFileError = utils_1.formatErrors([configFile.error], loaderOptions, colors, compiler, { file: configFilePath }, loader.context)[0];
}
}
else {
if (compilerCompatible) {
log.logInfo(compilerDetailsLogMessage);
}
configFile = {
config: {
compilerOptions: {},
files: []
}
};
}
if (configFileError === undefined) {
configFile.config.compilerOptions = Object.assign({}, configFile.config.compilerOptions, loaderOptions.compilerOptions);
}
return {
configFilePath,
configFile,
configFileError
};
}
exports.getConfigFile = getConfigFile;
/**
* Find a tsconfig file by name or by path.
* By name, the tsconfig.json is found using the same method as `tsc`, starting in the current
* directory and continuing up the parent directory chain.
* By path, the file will be found by resolving the given path relative to the requesting entry file.
*
* @param compiler The TypeScript compiler instance
* @param requestDirPath The directory in which the entry point requesting the tsconfig.json lies
* @param configFile The tsconfig file name to look for or a path to that file
* @return The absolute path to the tsconfig file, undefined if none was found.
*/
function findConfigFile(compiler, requestDirPath, configFile) {
// If `configFile` is an absolute path, return it right away
if (path.isAbsolute(configFile)) {
return compiler.sys.fileExists(configFile) ? configFile : undefined;
}
// If `configFile` is a relative path, resolve it.
// We define a relative path as: starts with
// one or two dots + a common directory delimiter
if (configFile.match(/^\.\.?(\/|\\)/) !== null) {
const resolvedPath = path.resolve(requestDirPath, configFile);
return compiler.sys.fileExists(resolvedPath) ? resolvedPath : undefined;
// If `configFile` is a file name, find it in the directory tree
}
else {
while (true) {
const fileName = path.join(requestDirPath, configFile);
if (compiler.sys.fileExists(fileName)) {
return fileName;
}
const parentPath = path.dirname(requestDirPath);
if (parentPath === requestDirPath) {
break;
}
requestDirPath = parentPath;
}
return undefined;
}
}
function getConfigParseResult(compiler, configFile, basePath) {
const configParseResult = compiler.parseJsonConfigFileContent(configFile.config, compiler.sys, basePath);
return configParseResult;
}
exports.getConfigParseResult = getConfigParseResult;
+19
View File
@@ -0,0 +1,19 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const os = require("os");
exports.EOL = os.EOL;
exports.CarriageReturnLineFeed = '\r\n';
exports.LineFeed = '\n';
exports.CarriageReturnLineFeedCode = 0;
exports.LineFeedCode = 1;
exports.extensionRegex = /\.[^.]+$/;
exports.tsxRegex = /\.tsx$/i;
exports.tsTsxRegex = /\.ts(x?)$/i;
exports.dtsDtsxOrDtsDtsxMapRegex = /\.d\.ts(x?)(\.map)?$/i;
exports.dtsTsTsxRegex = /(\.d)?\.ts(x?)$/i;
exports.dtsTsTsxJsJsxRegex = /((\.d)?\.ts(x?)|js(x?))$/i;
exports.tsTsxJsJsxRegex = /\.tsx?$|\.jsx?$/i;
exports.jsJsx = /\.js(x?)$/i;
exports.jsJsxMap = /\.js(x?)\.map$/i;
exports.jsonRegex = /\.json$/i;
exports.nodeModules = /node_modules/i;
+309
View File
@@ -0,0 +1,309 @@
"use strict";
const loaderUtils = require("loader-utils");
const path = require("path");
const constants = require("./constants");
const instances_1 = require("./instances");
const utils_1 = require("./utils");
const webpackInstances = [];
const loaderOptionsCache = {};
/**
* The entry point for ts-loader
*/
function loader(contents) {
// tslint:disable-next-line:no-unused-expression strict-boolean-expressions
this.cacheable && this.cacheable();
const callback = this.async();
const options = getLoaderOptions(this);
const instanceOrError = instances_1.getTypeScriptInstance(options, this);
if (instanceOrError.error !== undefined) {
callback(new Error(instanceOrError.error.message));
return;
}
return successLoader(this, contents, callback, options, instanceOrError.instance);
}
function successLoader(loaderContext, contents, callback, options, instance) {
const rawFilePath = path.normalize(loaderContext.resourcePath);
const filePath = options.appendTsSuffixTo.length > 0 || options.appendTsxSuffixTo.length > 0
? utils_1.appendSuffixesIfMatch({
'.ts': options.appendTsSuffixTo,
'.tsx': options.appendTsxSuffixTo
}, rawFilePath)
: rawFilePath;
const fileVersion = updateFileInCache(filePath, contents, instance);
const referencedProject = utils_1.getAndCacheProjectReference(filePath, instance);
if (referencedProject !== undefined) {
const [relativeProjectConfigPath, relativeFilePath] = [
path.relative(loaderContext.rootContext, referencedProject.sourceFile.fileName),
path.relative(loaderContext.rootContext, filePath)
];
if (referencedProject.commandLine.options.outFile !== undefined) {
throw new Error(`The referenced project at ${relativeProjectConfigPath} is using ` +
`the outFile' option, which is not supported with ts-loader.`);
}
const jsFileName = utils_1.getAndCacheOutputJSFileName(filePath, referencedProject, instance);
const relativeJSFileName = path.relative(loaderContext.rootContext, jsFileName);
if (!instance.compiler.sys.fileExists(jsFileName)) {
throw new Error(`Could not find output JavaScript file for input ` +
`${relativeFilePath} (looked at ${relativeJSFileName}).\n` +
`The input file is part of a project reference located at ` +
`${relativeProjectConfigPath}, so ts-loader is looking for the ` +
'projects pre-built output on disk. Try running `tsc --build` ' +
'to build project references.');
}
// Since the output JS file is being read from disk instead of using the
// input TS file, we need to tell the loader that the compilation doesnt
// actually depend on the current file, but depends on the JS file instead.
loaderContext.clearDependencies();
loaderContext.addDependency(jsFileName);
utils_1.validateSourceMapOncePerProject(instance, loaderContext, jsFileName, referencedProject);
const mapFileName = jsFileName + '.map';
const outputText = instance.compiler.sys.readFile(jsFileName);
const sourceMapText = instance.compiler.sys.readFile(mapFileName);
makeSourceMapAndFinish(sourceMapText, outputText, filePath, contents, loaderContext, options, fileVersion, callback);
}
else {
const { outputText, sourceMapText } = options.transpileOnly
? getTranspilationEmit(filePath, contents, instance, loaderContext)
: getEmit(rawFilePath, filePath, instance, loaderContext);
makeSourceMapAndFinish(sourceMapText, outputText, filePath, contents, loaderContext, options, fileVersion, callback);
}
}
function makeSourceMapAndFinish(sourceMapText, outputText, filePath, contents, loaderContext, options, fileVersion, callback) {
if (outputText === null || outputText === undefined) {
const additionalGuidance = !options.allowTsInNodeModules && filePath.indexOf('node_modules') !== -1
? ' By default, ts-loader will not compile .ts files in node_modules.\n' +
'You should not need to recompile .ts files there, but if you really want to, use the allowTsInNodeModules option.\n' +
'See: https://github.com/Microsoft/TypeScript/issues/12358'
: '';
throw new Error(`TypeScript emitted no output for ${filePath}.${additionalGuidance}`);
}
const { sourceMap, output } = makeSourceMap(sourceMapText, outputText, filePath, contents, loaderContext);
// _module.meta is not available inside happypack
if (!options.happyPackMode && loaderContext._module.buildMeta !== undefined) {
// Make sure webpack is aware that even though the emitted JavaScript may be the same as
// a previously cached version the TypeScript may be different and therefore should be
// treated as new
loaderContext._module.buildMeta.tsLoaderFileVersion = fileVersion;
}
callback(null, output, sourceMap);
}
/**
* either retrieves loader options from the cache
* or creates them, adds them to the cache and returns
*/
function getLoaderOptions(loaderContext) {
// differentiate the TypeScript instance based on the webpack instance
let webpackIndex = webpackInstances.indexOf(loaderContext._compiler);
if (webpackIndex === -1) {
webpackIndex = webpackInstances.push(loaderContext._compiler) - 1;
}
const loaderOptions = loaderUtils.getOptions(loaderContext) ||
{};
const instanceName = webpackIndex + '_' + (loaderOptions.instance || 'default');
if (!loaderOptionsCache.hasOwnProperty(instanceName)) {
loaderOptionsCache[instanceName] = new WeakMap();
}
const cache = loaderOptionsCache[instanceName];
if (cache.has(loaderOptions)) {
return cache.get(loaderOptions);
}
validateLoaderOptions(loaderOptions);
const options = makeLoaderOptions(instanceName, loaderOptions);
cache.set(loaderOptions, options);
return options;
}
const validLoaderOptions = [
'silent',
'logLevel',
'logInfoToStdOut',
'instance',
'compiler',
'context',
'configFile',
'transpileOnly',
'ignoreDiagnostics',
'errorFormatter',
'colors',
'compilerOptions',
'appendTsSuffixTo',
'appendTsxSuffixTo',
'onlyCompileBundledFiles',
'happyPackMode',
'getCustomTransformers',
'reportFiles',
'experimentalWatchApi',
'allowTsInNodeModules',
'experimentalFileCaching',
'projectReferences',
'resolveModuleName',
'resolveTypeReferenceDirective'
];
/**
* Validate the supplied loader options.
* At present this validates the option names only; in future we may look at validating the values too
* @param loaderOptions
*/
function validateLoaderOptions(loaderOptions) {
const loaderOptionKeys = Object.keys(loaderOptions);
// tslint:disable-next-line:prefer-for-of
for (let i = 0; i < loaderOptionKeys.length; i++) {
const option = loaderOptionKeys[i];
const isUnexpectedOption = validLoaderOptions.indexOf(option) === -1;
if (isUnexpectedOption) {
throw new Error(`ts-loader was supplied with an unexpected loader option: ${option}
Please take a look at the options you are supplying; the following are valid options:
${validLoaderOptions.join(' / ')}
`);
}
}
if (loaderOptions.context !== undefined &&
!path.isAbsolute(loaderOptions.context)) {
throw new Error(`Option 'context' has to be an absolute path. Given '${loaderOptions.context}'.`);
}
}
function makeLoaderOptions(instanceName, loaderOptions) {
const options = Object.assign({}, {
silent: false,
logLevel: 'WARN',
logInfoToStdOut: false,
compiler: 'typescript',
configFile: 'tsconfig.json',
context: undefined,
transpileOnly: false,
compilerOptions: {},
appendTsSuffixTo: [],
appendTsxSuffixTo: [],
transformers: {},
happyPackMode: false,
colors: true,
onlyCompileBundledFiles: false,
reportFiles: [],
// When the watch API usage stabilises look to remove this option and make watch usage the default behaviour when available
experimentalWatchApi: false,
allowTsInNodeModules: false,
experimentalFileCaching: true
}, loaderOptions);
options.ignoreDiagnostics = utils_1.arrify(options.ignoreDiagnostics).map(Number);
options.logLevel = options.logLevel.toUpperCase();
options.instance = instanceName;
// happypack can be used only together with transpileOnly mode
options.transpileOnly = options.happyPackMode ? true : options.transpileOnly;
return options;
}
/**
* Either add file to the overall files cache or update it in the cache when the file contents have changed
* Also add the file to the modified files
*/
function updateFileInCache(filePath, contents, instance) {
let fileWatcherEventKind;
// Update file contents
let file = instance.files.get(filePath);
if (file === undefined) {
file = instance.otherFiles.get(filePath);
if (file !== undefined) {
instance.otherFiles.delete(filePath);
instance.files.set(filePath, file);
}
else {
if (instance.watchHost !== undefined) {
fileWatcherEventKind = instance.compiler.FileWatcherEventKind.Created;
}
file = { version: 0 };
instance.files.set(filePath, file);
}
instance.changedFilesList = true;
}
if (instance.watchHost !== undefined && contents === undefined) {
fileWatcherEventKind = instance.compiler.FileWatcherEventKind.Deleted;
}
if (file.text !== contents) {
file.version++;
file.text = contents;
instance.version++;
if (instance.watchHost !== undefined &&
fileWatcherEventKind === undefined) {
fileWatcherEventKind = instance.compiler.FileWatcherEventKind.Changed;
}
}
if (instance.watchHost !== undefined && fileWatcherEventKind !== undefined) {
instance.hasUnaccountedModifiedFiles = true;
instance.watchHost.invokeFileWatcher(filePath, fileWatcherEventKind);
instance.watchHost.invokeDirectoryWatcher(path.dirname(filePath), filePath);
}
// push this file to modified files hash.
if (instance.modifiedFiles === null || instance.modifiedFiles === undefined) {
instance.modifiedFiles = new Map();
}
instance.modifiedFiles.set(filePath, file);
return file.version;
}
function getEmit(rawFilePath, filePath, instance, loaderContext) {
const outputFiles = instances_1.getEmitOutput(instance, filePath);
loaderContext.clearDependencies();
loaderContext.addDependency(rawFilePath);
const allDefinitionFiles = [...instance.files.keys()].filter(defFilePath => defFilePath.match(constants.dtsDtsxOrDtsDtsxMapRegex));
// Make this file dependent on *all* definition files in the program
const addDependency = loaderContext.addDependency.bind(loaderContext);
allDefinitionFiles.forEach(addDependency);
// Additionally make this file dependent on all imported files
const fileDependencies = instance.dependencyGraph[filePath];
const additionalDependencies = fileDependencies === undefined
? []
: fileDependencies.map(({ resolvedFileName, originalFileName }) => {
const projectReference = utils_1.getAndCacheProjectReference(resolvedFileName, instance);
// In the case of dependencies that are part of a project reference,
// the real dependency that webpack should watch is the JS output file.
return projectReference !== undefined
? utils_1.getAndCacheOutputJSFileName(resolvedFileName, projectReference, instance)
: originalFileName;
});
if (additionalDependencies.length > 0) {
additionalDependencies.forEach(addDependency);
}
loaderContext._module.buildMeta.tsLoaderDefinitionFileVersions = allDefinitionFiles
.concat(additionalDependencies)
.map(defFilePath => defFilePath +
'@' +
(instance.files.get(defFilePath) || { version: '?' }).version);
const outputFile = outputFiles
.filter(file => file.name.match(constants.jsJsx))
.pop();
const outputText = outputFile === undefined ? undefined : outputFile.text;
const sourceMapFile = outputFiles
.filter(file => file.name.match(constants.jsJsxMap))
.pop();
const sourceMapText = sourceMapFile === undefined ? undefined : sourceMapFile.text;
return { outputText, sourceMapText };
}
/**
* Transpile file
*/
function getTranspilationEmit(fileName, contents, instance, loaderContext) {
const { outputText, sourceMapText, diagnostics } = instance.compiler.transpileModule(contents, {
compilerOptions: Object.assign({}, instance.compilerOptions, { rootDir: undefined }),
transformers: instance.transformers,
reportDiagnostics: true,
fileName
});
// _module.errors is not available inside happypack - see https://github.com/TypeStrong/ts-loader/issues/336
if (!instance.loaderOptions.happyPackMode) {
const errors = utils_1.formatErrors(diagnostics, instance.loaderOptions, instance.colors, instance.compiler, { module: loaderContext._module }, loaderContext.context);
loaderContext._module.errors.push(...errors);
}
return { outputText, sourceMapText };
}
function makeSourceMap(sourceMapText, outputText, filePath, contents, loaderContext) {
if (sourceMapText === undefined) {
return { output: outputText, sourceMap: undefined };
}
return {
output: outputText.replace(/^\/\/# sourceMappingURL=[^\r\n]*/gm, ''),
sourceMap: Object.assign(JSON.parse(sourceMapText), {
sources: [loaderUtils.getRemainingRequest(loaderContext)],
file: filePath,
sourcesContent: [contents]
})
};
}
module.exports = loader;
+199
View File
@@ -0,0 +1,199 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const chalk_1 = require("chalk");
const fs = require("fs");
const path = require("path");
const after_compile_1 = require("./after-compile");
const compilerSetup_1 = require("./compilerSetup");
const config_1 = require("./config");
const constants_1 = require("./constants");
const logger = require("./logger");
const servicesHost_1 = require("./servicesHost");
const utils_1 = require("./utils");
const watch_run_1 = require("./watch-run");
const instances = {};
/**
* 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) {
if (instances.hasOwnProperty(loaderOptions.instance)) {
const instance = instances[loaderOptions.instance];
utils_1.ensureProgram(instance);
return { instance: instances[loaderOptions.instance] };
}
const colors = new chalk_1.default.constructor({ enabled: loaderOptions.colors });
const log = logger.makeLogger(loaderOptions, colors);
const compiler = compilerSetup_1.getCompiler(loaderOptions, log);
if (compiler.errorMessage !== undefined) {
return { error: utils_1.makeError(colors.red(compiler.errorMessage), undefined) };
}
return successfulTypeScriptInstance(loaderOptions, loader, log, colors, compiler.compiler, compiler.compilerCompatible, compiler.compilerDetailsLogMessage);
}
exports.getTypeScriptInstance = getTypeScriptInstance;
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(colors.red('error while reading tsconfig.json:' + constants_1.EOL + message), file)
};
}
const { configFilePath, configFile } = configFileAndPath;
const basePath = loaderOptions.context || path.dirname(configFilePath || '');
const configParseResult = config_1.getConfigParseResult(compiler, configFile, basePath);
if (configParseResult.errors.length > 0 && !loaderOptions.happyPackMode) {
const errors = utils_1.formatErrors(configParseResult.errors, loaderOptions, colors, compiler, { file: configFilePath }, loader.context);
loader._module.errors.push(...errors);
return {
error: utils_1.makeError(colors.red('error while parsing tsconfig.json'), configFilePath)
};
}
const compilerOptions = compilerSetup_1.getCompilerOptions(configParseResult);
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;
// same strategy as https://github.com/s-panferov/awesome-typescript-loader/pull/531/files
let { getCustomTransformers: customerTransformers } = 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 "${loaderOptions.getCustomTransformers}": ${err.message}`);
}
if (typeof customerTransformers !== 'function') {
throw new Error(`Custom transformers in "${loaderOptions.getCustomTransformers}" should export a function, got ${typeof getCustomTransformers}`);
}
getCustomTransformers = customerTransformers;
}
if (loaderOptions.transpileOnly) {
// quick return for transpiling
// we do need to check for any issues with TS options though
const program = configParseResult.projectReferences !== undefined
? compiler.createProgram({
rootNames: configParseResult.fileNames,
options: configParseResult.options,
projectReferences: configParseResult.projectReferences
})
: compiler.createProgram([], compilerOptions);
// happypack does not have _module.errors - see https://github.com/TypeStrong/ts-loader/issues/336
if (!loaderOptions.happyPackMode) {
const diagnostics = program.getOptionsDiagnostics();
const errors = utils_1.formatErrors(diagnostics, loaderOptions, colors, compiler, { file: configFilePath || 'tsconfig.json' }, loader.context);
loader._module.errors.push(...errors);
}
instances[loaderOptions.instance] = {
compiler,
compilerOptions,
appendTsTsxSuffixesIfRequired,
loaderOptions,
files,
otherFiles,
program,
dependencyGraph: {},
reverseDependencyGraph: {},
transformers: getCustomTransformers(program),
colors
};
return { instance: instances[loaderOptions.instance] };
}
// 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(normalizedFilePath, {
text: fs.readFileSync(normalizedFilePath, 'utf-8'),
version: 0
});
});
}
catch (exc) {
return {
error: utils_1.makeError(colors.red(`A file specified in tsconfig.json could not be found: ${normalizedFilePath}`), normalizedFilePath)
};
}
// if allowJs is set then we should accept js(x) files
const scriptRegex = configParseResult.options.allowJs === true
? /\.tsx?$|\.jsx?$/i
: /\.tsx?$/i;
const instance = (instances[loaderOptions.instance] = {
compiler,
compilerOptions,
appendTsTsxSuffixesIfRequired,
loaderOptions,
files,
otherFiles,
languageService: null,
version: 0,
transformers: {},
dependencyGraph: {},
reverseDependencyGraph: {},
modifiedFiles: null,
colors
});
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 (loaderOptions.experimentalWatchApi && compiler.createWatchProgram) {
log.logInfo('Using watch api');
// If there is api available for watch, use it instead of language service
instance.watchHost = servicesHost_1.makeWatchHost(scriptRegex, log, loader, instance, configParseResult.projectReferences);
instance.watchOfFilesAndCompilerOptions = compiler.createWatchProgram(instance.watchHost);
instance.program = instance.watchOfFilesAndCompilerOptions
.getProgram()
.getProgram();
instance.transformers = getCustomTransformers(instance.program);
}
else {
const servicesHost = servicesHost_1.makeServicesHost(scriptRegex, log, loader, instance, loaderOptions.experimentalFileCaching, configParseResult.projectReferences);
instance.languageService = compiler.createLanguageService(servicesHost.servicesHost, compiler.createDocumentRegistry());
if (servicesHost.clearCache !== null) {
loader._compiler.hooks.watchRun.tap('ts-loader', servicesHost.clearCache);
}
instance.transformers = getCustomTransformers(instance.languageService.getProgram());
}
loader._compiler.hooks.afterCompile.tapAsync('ts-loader', after_compile_1.makeAfterCompile(instance, configFilePath));
loader._compiler.hooks.watchRun.tapAsync('ts-loader', watch_run_1.makeWatchRun(instance));
return { instance };
}
function getEmitOutput(instance, filePath) {
const program = utils_1.ensureProgram(instance);
if (program !== undefined) {
const outputFiles = [];
const writeFile = (fileName, text, writeByteOrderMark) => outputFiles.push({ name: fileName, writeByteOrderMark, text });
const sourceFile = program.getSourceFile(filePath);
// The source file will be undefined if its part of an unbuilt project reference
if (sourceFile !== undefined || !utils_1.isUsingProjectReferences(instance)) {
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;
+2
View File
@@ -0,0 +1,2 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
+37
View File
@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const console_1 = require("console");
var LogLevel;
(function (LogLevel) {
LogLevel[LogLevel["INFO"] = 1] = "INFO";
LogLevel[LogLevel["WARN"] = 2] = "WARN";
LogLevel[LogLevel["ERROR"] = 3] = "ERROR";
})(LogLevel = exports.LogLevel || (exports.LogLevel = {}));
const stderrConsole = new console_1.Console(process.stderr);
const stdoutConsole = new console_1.Console(process.stdout);
const doNothingLogger = (_message) => { };
const makeLoggerFunc = (loaderOptions) => loaderOptions.silent
? (_whereToLog, _message) => { }
: (whereToLog, message) =>
// tslint:disable-next-line:no-console
console.log.call(whereToLog, message);
const makeExternalLogger = (loaderOptions, logger) => (message) => logger(loaderOptions.logInfoToStdOut ? stdoutConsole : stderrConsole, message);
const makeLogInfo = (loaderOptions, logger, green) => LogLevel[loaderOptions.logLevel] <= LogLevel.INFO
? (message) => logger(loaderOptions.logInfoToStdOut ? stdoutConsole : stderrConsole, green(message))
: doNothingLogger;
const makeLogError = (loaderOptions, logger, red) => LogLevel[loaderOptions.logLevel] <= LogLevel.ERROR
? (message) => logger(stderrConsole, red(message))
: doNothingLogger;
const makeLogWarning = (loaderOptions, logger, yellow) => LogLevel[loaderOptions.logLevel] <= LogLevel.WARN
? (message) => logger(stderrConsole, yellow(message))
: doNothingLogger;
function makeLogger(loaderOptions, colors) {
const logger = makeLoggerFunc(loaderOptions);
return {
log: makeExternalLogger(loaderOptions, logger),
logInfo: makeLogInfo(loaderOptions, logger, colors.green),
logWarning: makeLogWarning(loaderOptions, logger, colors.yellow),
logError: makeLogError(loaderOptions, logger, colors.red)
};
}
exports.makeLogger = makeLogger;
+8
View File
@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
// tslint:disable-next-line:no-submodule-imports
const node = require('enhanced-resolve/lib/node');
function makeResolver(options) {
return node.create.sync(options.resolve);
}
exports.makeResolver = makeResolver;
+330
View File
@@ -0,0 +1,330 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const constants = require("./constants");
const resolver_1 = require("./resolver");
const utils_1 = require("./utils");
/**
* Create the TypeScript language service
*/
function makeServicesHost(scriptRegex, log, loader, instance, enableFileCaching, projectReferences) {
const { compiler, compilerOptions, appendTsTsxSuffixesIfRequired, files, loaderOptions: { resolveModuleName: customResolveModuleName, resolveTypeReferenceDirective: customResolveTypeReferenceDirective } } = instance;
const newLine = compilerOptions.newLine === constants.CarriageReturnLineFeedCode
? constants.CarriageReturnLineFeed
: compilerOptions.newLine === constants.LineFeedCode
? constants.LineFeed
: constants.EOL;
// make a (sync) resolver that follows webpack's rules
const resolveSync = resolver_1.makeResolver(loader._compiler.options);
const readFileWithFallback = (filePath, encoding) => compiler.sys.readFile(filePath, encoding) || utils_1.readFile(filePath, encoding);
const fileExists = (filePathToCheck) => compiler.sys.fileExists(filePathToCheck) ||
utils_1.readFile(filePathToCheck) !== undefined;
const moduleResolutionHost = {
fileExists,
readFile: readFileWithFallback,
realpath: compiler.sys.realpath,
directoryExists: compiler.sys.directoryExists
};
const clearCache = enableFileCaching ? addCache(moduleResolutionHost) : null;
// loader.context seems to work fine on Linux / Mac regardless causes problems for @types resolution on Windows for TypeScript < 2.3
const getCurrentDirectory = () => loader.context;
const resolvers = makeResolvers(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance);
const servicesHost = {
getProjectVersion: () => `${instance.version}`,
getProjectReferences: () => projectReferences,
getScriptFileNames: () => [...files.keys()].filter(filePath => filePath.match(scriptRegex)),
getScriptVersion: (fileName) => {
fileName = path.normalize(fileName);
const file = files.get(fileName);
return file === undefined ? '' : file.version.toString();
},
getScriptSnapshot: (fileName) => {
// This is called any time TypeScript needs a file's text
// We either load from memory or from disk
fileName = path.normalize(fileName);
let file = files.get(fileName);
if (file === undefined) {
const text = utils_1.readFile(fileName);
if (text === undefined) {
return undefined;
}
file = { version: 0, text };
files.set(fileName, file);
}
return compiler.ScriptSnapshot.fromString(file.text);
},
/**
* getDirectories is also required for full import and type reference completions.
* Without it defined, certain completions will not be provided
*/
getDirectories: compiler.sys.getDirectories,
/**
* For @types expansion, these two functions are needed.
*/
directoryExists: moduleResolutionHost.directoryExists,
useCaseSensitiveFileNames: () => compiler.sys.useCaseSensitiveFileNames,
realpath: moduleResolutionHost.realpath,
// The following three methods are necessary for @types resolution from TS 2.4.1 onwards see: https://github.com/Microsoft/TypeScript/issues/16772
fileExists: moduleResolutionHost.fileExists,
readFile: moduleResolutionHost.readFile,
readDirectory: compiler.sys.readDirectory,
getCurrentDirectory,
getCompilationSettings: () => compilerOptions,
getDefaultLibFileName: (options) => compiler.getDefaultLibFilePath(options),
getNewLine: () => newLine,
trace: log.log,
log: log.log,
// used for (/// <reference types="...">) see https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/250#issuecomment-485061329
resolveTypeReferenceDirectives: resolvers.resolveTypeReferenceDirectives,
resolveModuleNames: resolvers.resolveModuleNames,
getCustomTransformers: () => instance.transformers
};
return { servicesHost, clearCache };
}
exports.makeServicesHost = makeServicesHost;
function makeResolvers(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance) {
const resolveTypeReferenceDirective = makeResolveTypeReferenceDirective(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective);
const resolveTypeReferenceDirectives = (typeDirectiveNames, containingFile, _redirectedReference) => typeDirectiveNames.map(directive => resolveTypeReferenceDirective(directive, containingFile)
.resolvedTypeReferenceDirective);
const resolveModuleName = makeResolveModuleName(compiler, compilerOptions, moduleResolutionHost, customResolveModuleName);
const resolveModuleNames = (moduleNames, containingFile, _reusedNames, _redirectedReference) => {
const resolvedModules = moduleNames.map(moduleName => resolveModule(resolveSync, resolveModuleName, appendTsTsxSuffixesIfRequired, scriptRegex, moduleName, containingFile));
populateDependencyGraphs(resolvedModules, instance, containingFile);
return resolvedModules;
};
return {
resolveTypeReferenceDirectives,
resolveModuleNames
};
}
/**
* Create the TypeScript Watch host
*/
function makeWatchHost(scriptRegex, log, loader, instance, projectReferences) {
const { compiler, compilerOptions, appendTsTsxSuffixesIfRequired, files, otherFiles, loaderOptions: { resolveModuleName: customResolveModuleName, resolveTypeReferenceDirective: customResolveTypeReferenceDirective } } = instance;
const newLine = compilerOptions.newLine === constants.CarriageReturnLineFeedCode
? constants.CarriageReturnLineFeed
: compilerOptions.newLine === constants.LineFeedCode
? constants.LineFeed
: constants.EOL;
// make a (sync) resolver that follows webpack's rules
const resolveSync = resolver_1.makeResolver(loader._compiler.options);
const readFileWithFallback = (filePath, encoding) => compiler.sys.readFile(filePath, encoding) || utils_1.readFile(filePath, encoding);
const moduleResolutionHost = {
fileExists,
readFile: readFileWithFallback,
realpath: compiler.sys.realpath
};
// loader.context seems to work fine on Linux / Mac regardless causes problems for @types resolution on Windows for TypeScript < 2.3
const getCurrentDirectory = () => loader.context;
const watchedFiles = {};
const watchedDirectories = {};
const watchedDirectoriesRecursive = {};
const resolvers = makeResolvers(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective, customResolveModuleName, resolveSync, appendTsTsxSuffixesIfRequired, scriptRegex, instance);
const watchHost = {
rootFiles: getRootFileNames(),
options: compilerOptions,
useCaseSensitiveFileNames: () => compiler.sys.useCaseSensitiveFileNames,
getNewLine: () => newLine,
getCurrentDirectory,
getDefaultLibFileName: options => compiler.getDefaultLibFilePath(options),
fileExists,
readFile: readFileWithCachingText,
directoryExists: dirPath => compiler.sys.directoryExists(path.normalize(dirPath)),
getDirectories: dirPath => compiler.sys.getDirectories(path.normalize(dirPath)),
readDirectory: (dirPath, extensions, exclude, include, depth) => compiler.sys.readDirectory(path.normalize(dirPath), extensions, exclude, include, depth),
realpath: dirPath => compiler.sys.resolvePath(path.normalize(dirPath)),
trace: logData => log.log(logData),
watchFile,
watchDirectory,
// used for (/// <reference types="...">) see https://github.com/Realytics/fork-ts-checker-webpack-plugin/pull/250#issuecomment-485061329
resolveTypeReferenceDirectives: resolvers.resolveTypeReferenceDirectives,
resolveModuleNames: resolvers.resolveModuleNames,
invokeFileWatcher,
invokeDirectoryWatcher,
updateRootFileNames: () => {
instance.changedFilesList = false;
if (instance.watchOfFilesAndCompilerOptions !== undefined) {
instance.watchOfFilesAndCompilerOptions.updateRootFileNames(getRootFileNames());
}
},
createProgram: projectReferences === undefined
? compiler.createAbstractBuilder
: createBuilderProgramWithReferences
};
return watchHost;
function getRootFileNames() {
return [...files.keys()].filter(filePath => filePath.match(scriptRegex));
}
function readFileWithCachingText(fileName, encoding) {
fileName = path.normalize(fileName);
const file = files.get(fileName) || otherFiles.get(fileName);
if (file !== undefined) {
return file.text;
}
const text = readFileWithFallback(fileName, encoding);
if (text === undefined) {
return undefined;
}
otherFiles.set(fileName, { version: 0, text });
return text;
}
function fileExists(fileName) {
const filePath = path.normalize(fileName);
return files.has(filePath) || compiler.sys.fileExists(filePath);
}
function invokeWatcherCallbacks(callbacks, fileName, eventKind) {
if (callbacks !== undefined) {
// The array copy is made to ensure that even if one of the callback removes the callbacks,
// we dont miss any callbacks following it
const cbs = callbacks.slice();
for (const cb of cbs) {
cb(fileName, eventKind);
}
}
}
function invokeFileWatcher(fileName, eventKind) {
fileName = path.normalize(fileName);
invokeWatcherCallbacks(watchedFiles[fileName], fileName, eventKind);
}
function invokeDirectoryWatcher(directory, fileAddedOrRemoved) {
directory = path.normalize(directory);
invokeWatcherCallbacks(watchedDirectories[directory], fileAddedOrRemoved);
invokeRecursiveDirectoryWatcher(directory, fileAddedOrRemoved);
}
function invokeRecursiveDirectoryWatcher(directory, fileAddedOrRemoved) {
directory = path.normalize(directory);
invokeWatcherCallbacks(watchedDirectoriesRecursive[directory], fileAddedOrRemoved);
const basePath = path.dirname(directory);
if (directory !== basePath) {
invokeRecursiveDirectoryWatcher(basePath, fileAddedOrRemoved);
}
}
function createWatcher(file, callbacks, callback) {
file = path.normalize(file);
const existing = callbacks[file];
if (existing === undefined) {
callbacks[file] = [callback];
}
else {
existing.push(callback);
}
return {
close: () => {
// tslint:disable-next-line:no-shadowed-variable
const existing = callbacks[file];
if (existing !== undefined) {
utils_1.unorderedRemoveItem(existing, callback);
}
}
};
}
function watchFile(fileName, callback, _pollingInterval) {
return createWatcher(fileName, watchedFiles, callback);
}
function watchDirectory(fileName, callback, recursive) {
return createWatcher(fileName, recursive === true ? watchedDirectoriesRecursive : watchedDirectories, callback);
}
function createBuilderProgramWithReferences(rootNames, options, host, oldProgram, configFileParsingDiagnostics) {
const program = compiler.createProgram({
rootNames: rootNames,
options: options,
host,
oldProgram: oldProgram && oldProgram.getProgram(),
configFileParsingDiagnostics,
projectReferences
});
const builderProgramHost = host;
return compiler.createAbstractBuilder(program, builderProgramHost, oldProgram, configFileParsingDiagnostics);
}
}
exports.makeWatchHost = makeWatchHost;
function makeResolveTypeReferenceDirective(compiler, compilerOptions, moduleResolutionHost, customResolveTypeReferenceDirective) {
if (customResolveTypeReferenceDirective === undefined) {
return (directive, containingFile) => compiler.resolveTypeReferenceDirective(directive, containingFile, compilerOptions, moduleResolutionHost);
}
return (directive, containingFile) => customResolveTypeReferenceDirective(directive, containingFile, compilerOptions, moduleResolutionHost, compiler.resolveTypeReferenceDirective);
}
function isJsImplementationOfTypings(resolvedModule, tsResolution) {
return (resolvedModule.resolvedFileName.endsWith('js') &&
/\.d\.ts$/.test(tsResolution.resolvedFileName));
}
function resolveModule(resolveSync, resolveModuleName, appendTsTsxSuffixesIfRequired, scriptRegex, moduleName, containingFile) {
let resolutionResult;
try {
const originalFileName = resolveSync(undefined, path.normalize(path.dirname(containingFile)), moduleName);
const resolvedFileName = appendTsTsxSuffixesIfRequired(originalFileName);
if (resolvedFileName.match(scriptRegex) !== null) {
resolutionResult = { resolvedFileName, originalFileName };
}
// tslint:disable-next-line:no-empty
}
catch (e) { }
const tsResolution = resolveModuleName(moduleName, containingFile);
if (tsResolution.resolvedModule !== undefined) {
const resolvedFileName = path.normalize(tsResolution.resolvedModule.resolvedFileName);
const tsResolutionResult = {
originalFileName: resolvedFileName,
resolvedFileName,
isExternalLibraryImport: tsResolution.resolvedModule.isExternalLibraryImport
};
return resolutionResult === undefined ||
resolutionResult.resolvedFileName ===
tsResolutionResult.resolvedFileName ||
isJsImplementationOfTypings(resolutionResult, tsResolutionResult)
? tsResolutionResult
: resolutionResult;
}
return resolutionResult;
}
function makeResolveModuleName(compiler, compilerOptions, moduleResolutionHost, customResolveModuleName) {
if (customResolveModuleName === undefined) {
return (moduleName, containingFile) => compiler.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost);
}
return (moduleName, containingFile) => customResolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost, compiler.resolveModuleName);
}
function populateDependencyGraphs(resolvedModules, instance, containingFile) {
resolvedModules = resolvedModules.filter(mod => mod !== null && mod !== undefined);
instance.dependencyGraph[path.normalize(containingFile)] = resolvedModules;
resolvedModules.forEach(resolvedModule => {
if (instance.reverseDependencyGraph[resolvedModule.resolvedFileName] ===
undefined) {
instance.reverseDependencyGraph[resolvedModule.resolvedFileName] = {};
}
instance.reverseDependencyGraph[resolvedModule.resolvedFileName][path.normalize(containingFile)] = true;
});
}
const cacheableFunctions = [
'fileExists',
'directoryExists',
'realpath'
];
function addCache(servicesHost) {
const clearCacheFunctions = [];
cacheableFunctions.forEach((functionToCache) => {
const originalFunction = servicesHost[functionToCache];
if (originalFunction !== undefined) {
const cache = createCache(originalFunction);
servicesHost[functionToCache] = cache.getCached;
clearCacheFunctions.push(cache.clear);
}
});
return () => clearCacheFunctions.forEach(clear => clear());
}
function createCache(originalFunction) {
const cache = new Map();
return {
clear: () => {
cache.clear();
},
getCached: (arg) => {
let res = cache.get(arg);
if (res !== undefined) {
return res;
}
res = originalFunction(arg);
cache.set(arg, res);
return res;
}
};
}
+3
View File
@@ -0,0 +1,3 @@
import * as webpack from 'webpack';
import { TSInstance } from './interfaces';
export declare function makeAfterCompile(instance: TSInstance, configFilePath: string | undefined): (compilation: webpack.compilation.Compilation, callback: () => void) => void;
+10
View File
@@ -0,0 +1,10 @@
import * as typescript from 'typescript';
import { LoaderOptions } from './interfaces';
import * as logger from './logger';
export declare function getCompiler(loaderOptions: LoaderOptions, log: logger.Logger): {
compiler: typeof typescript | undefined;
compilerCompatible: boolean;
compilerDetailsLogMessage: string | undefined;
errorMessage: string | undefined;
};
export declare function getCompilerOptions(configParseResult: typescript.ParsedCommandLine): typescript.CompilerOptions;
+16
View File
@@ -0,0 +1,16 @@
import { Chalk } from 'chalk';
import * as typescript from 'typescript';
import * as webpack from 'webpack';
import { LoaderOptions, WebpackError } from './interfaces';
import * as logger from './logger';
interface ConfigFile {
config?: any;
error?: typescript.Diagnostic;
}
export declare function getConfigFile(compiler: typeof typescript, colors: Chalk, loader: webpack.loader.LoaderContext, loaderOptions: LoaderOptions, compilerCompatible: boolean, log: logger.Logger, compilerDetailsLogMessage: string): {
configFilePath: string | undefined;
configFile: ConfigFile;
configFileError: WebpackError | undefined;
};
export declare function getConfigParseResult(compiler: typeof typescript, configFile: ConfigFile, basePath: string): typescript.ParsedCommandLine;
export {};
+16
View File
@@ -0,0 +1,16 @@
export declare const EOL: string;
export declare const CarriageReturnLineFeed = "\r\n";
export declare const LineFeed = "\n";
export declare const CarriageReturnLineFeedCode = 0;
export declare const LineFeedCode = 1;
export declare const extensionRegex: RegExp;
export declare const tsxRegex: RegExp;
export declare const tsTsxRegex: RegExp;
export declare const dtsDtsxOrDtsDtsxMapRegex: RegExp;
export declare const dtsTsTsxRegex: RegExp;
export declare const dtsTsTsxJsJsxRegex: RegExp;
export declare const tsTsxJsJsxRegex: RegExp;
export declare const jsJsx: RegExp;
export declare const jsJsxMap: RegExp;
export declare const jsonRegex: RegExp;
export declare const nodeModules: RegExp;
+14
View File
@@ -0,0 +1,14 @@
import * as webpack from 'webpack';
import { LoaderOptions } from './interfaces';
/**
* The entry point for ts-loader
*/
declare function loader(this: webpack.loader.LoaderContext, contents: string): void;
export = loader;
/**
* expose public types via declaration merging
*/
declare namespace loader {
interface Options extends LoaderOptions {
}
}
+15
View File
@@ -0,0 +1,15 @@
import * as typescript from 'typescript';
import * as webpack from 'webpack';
import { LoaderOptions, TSInstance, WebpackError } from './interfaces';
/**
* 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.
*/
export declare function getTypeScriptInstance(loaderOptions: LoaderOptions, loader: webpack.loader.LoaderContext): {
instance?: TSInstance;
error?: WebpackError;
};
export declare function getEmitOutput(instance: TSInstance, filePath: string): typescript.OutputFile[];
+136
View File
@@ -0,0 +1,136 @@
export { ModuleResolutionHost } from 'typescript';
import * as typescript from 'typescript';
import { Chalk } from 'chalk';
export interface ErrorInfo {
code: number;
severity: Severity;
content: string;
file: string;
line: number;
character: number;
context: string;
}
export declare type FileLocation = {
line: number;
character: number;
};
export interface WebpackError {
module?: any;
file?: string;
message: string;
location?: FileLocation;
loaderSource: string;
}
export interface WebpackModule {
resource: string;
errors: WebpackError[];
buildMeta: {
tsLoaderFileVersion: number;
tsLoaderDefinitionFileVersions: string[];
};
}
export declare type ResolveSync = (context: string | undefined, path: string, moduleName: string) => string;
export interface WatchHost extends typescript.WatchCompilerHostOfFilesAndCompilerOptions<typescript.BuilderProgram> {
invokeFileWatcher(fileName: string, eventKind: typescript.FileWatcherEventKind): void;
invokeDirectoryWatcher(directory: string, fileAddedOrRemoved: string): void;
updateRootFileNames(): void;
}
export interface TSInstance {
compiler: typeof typescript;
compilerOptions: typescript.CompilerOptions;
/** Used for Vue for the most part */
appendTsTsxSuffixesIfRequired: (filePath: string) => string;
loaderOptions: LoaderOptions;
/**
* a cache of all the files
*/
files: TSFiles;
/**
* contains the modified files - cleared each time after-compile is called
*/
modifiedFiles?: TSFiles | null;
/**
* Paths to project references that are missing source maps.
* Cleared each time after-compile is called. Used to dedupe
* warnings about source maps during a single compilation.
*/
projectsMissingSourceMaps?: Set<string>;
languageService?: typescript.LanguageService | null;
version?: number;
dependencyGraph: DependencyGraph;
reverseDependencyGraph: ReverseDependencyGraph;
filesWithErrors?: TSFiles;
transformers: typescript.CustomTransformers;
colors: Chalk;
otherFiles: TSFiles;
watchHost?: WatchHost;
watchOfFilesAndCompilerOptions?: typescript.WatchOfFilesAndCompilerOptions<typescript.BuilderProgram>;
program?: typescript.Program;
hasUnaccountedModifiedFiles?: boolean;
changedFilesList?: boolean;
}
export interface LoaderOptionsCache {
[name: string]: WeakMap<LoaderOptions, LoaderOptions>;
}
export interface TSInstances {
[name: string]: TSInstance;
}
export interface DependencyGraph {
[file: string]: ResolvedModule[] | undefined;
}
export interface ReverseDependencyGraph {
[file: string]: {
[file: string]: boolean;
} | undefined;
}
export declare type LogLevel = 'INFO' | 'WARN' | 'ERROR';
export declare type ResolveModuleName = (moduleName: string, containingFile: string, compilerOptions: typescript.CompilerOptions, moduleResolutionHost: typescript.ModuleResolutionHost) => typescript.ResolvedModuleWithFailedLookupLocations;
export declare type CustomResolveModuleName = (moduleName: string, containingFile: string, compilerOptions: typescript.CompilerOptions, moduleResolutionHost: typescript.ModuleResolutionHost, parentResolver: ResolveModuleName) => typescript.ResolvedModuleWithFailedLookupLocations;
export declare type CustomResolveTypeReferenceDirective = (typeDirectiveName: string, containingFile: string, compilerOptions: typescript.CompilerOptions, moduleResolutionHost: typescript.ModuleResolutionHost, parentResolver: typeof typescript.resolveTypeReferenceDirective) => typescript.ResolvedTypeReferenceDirectiveWithFailedLookupLocations;
export interface LoaderOptions {
silent: boolean;
logLevel: LogLevel;
logInfoToStdOut: boolean;
instance: string;
compiler: string;
configFile: string;
context: string;
transpileOnly: boolean;
ignoreDiagnostics: number[];
reportFiles: string[];
errorFormatter: (message: ErrorInfo, colors: Chalk) => string;
onlyCompileBundledFiles: boolean;
colors: boolean;
compilerOptions: typescript.CompilerOptions;
appendTsSuffixTo: RegExp[];
appendTsxSuffixTo: RegExp[];
happyPackMode: boolean;
getCustomTransformers: string | ((program: typescript.Program) => typescript.CustomTransformers | undefined);
experimentalWatchApi: boolean;
allowTsInNodeModules: boolean;
experimentalFileCaching: boolean;
projectReferences: boolean;
resolveModuleName: CustomResolveModuleName;
resolveTypeReferenceDirective: CustomResolveTypeReferenceDirective;
}
export interface TSFile {
text?: string;
version: number;
projectReference?: {
/**
* Undefined here means weve already checked and confirmed there is no
* project reference for the file. Dont bother checking again.
*/
project?: typescript.ResolvedProjectReference;
outputFileName?: string;
};
}
/** where key is filepath */
export declare type TSFiles = Map<string, TSFile>;
export interface ResolvedModule {
originalFileName: string;
resolvedFileName: string;
resolvedModule?: ResolvedModule;
isExternalLibraryImport?: boolean;
}
export declare type Severity = 'error' | 'warning';
+16
View File
@@ -0,0 +1,16 @@
import { Chalk } from 'chalk';
import { LoaderOptions } from './interfaces';
declare type LoggerFunc = (message: string) => void;
export interface Logger {
log: LoggerFunc;
logInfo: LoggerFunc;
logWarning: LoggerFunc;
logError: LoggerFunc;
}
export declare enum LogLevel {
INFO = 1,
WARN = 2,
ERROR = 3
}
export declare function makeLogger(loaderOptions: LoaderOptions, colors: Chalk): Logger;
export {};
+3
View File
@@ -0,0 +1,3 @@
import * as webpack from 'webpack';
import { ResolveSync } from './interfaces';
export declare function makeResolver(options: webpack.Configuration): ResolveSync;
+17
View File
@@ -0,0 +1,17 @@
import * as typescript from 'typescript';
import * as webpack from 'webpack';
import { TSInstance, WatchHost } from './interfaces';
import * as logger from './logger';
export declare type Action = () => void;
export interface ServiceHostWhichMayBeCacheable {
servicesHost: typescript.LanguageServiceHost;
clearCache: Action | null;
}
/**
* Create the TypeScript language service
*/
export declare function makeServicesHost(scriptRegex: RegExp, log: logger.Logger, loader: webpack.loader.LoaderContext, instance: TSInstance, enableFileCaching: boolean, projectReferences?: ReadonlyArray<typescript.ProjectReference>): ServiceHostWhichMayBeCacheable;
/**
* Create the TypeScript Watch host
*/
export declare function makeWatchHost(scriptRegex: RegExp, log: logger.Logger, loader: webpack.loader.LoaderContext, instance: TSInstance, projectReferences?: ReadonlyArray<typescript.ProjectReference>): WatchHost;
+49
View File
@@ -0,0 +1,49 @@
import { Chalk } from 'chalk';
import * as typescript from 'typescript';
import * as webpack from 'webpack';
import { DependencyGraph, LoaderOptions, ReverseDependencyGraph, TSInstance, WebpackError, WebpackModule } from './interfaces';
/**
* Take TypeScript errors, parse them and format to webpack errors
* Optionally adds a file name
*/
export declare function formatErrors(diagnostics: ReadonlyArray<typescript.Diagnostic> | undefined, loaderOptions: LoaderOptions, colors: Chalk, compiler: typeof typescript, merge: {
file?: string;
module?: WebpackModule;
}, context: string): WebpackError[];
export declare function readFile(fileName: string, encoding?: string | undefined): string | undefined;
export declare function makeError(message: string, file: string | undefined, location?: {
line: number;
character: number;
}): WebpackError;
export declare function appendSuffixIfMatch(patterns: RegExp[], filePath: string, suffix: string): string;
export declare function appendSuffixesIfMatch(suffixDict: {
[suffix: string]: RegExp[];
}, filePath: string): string;
export declare function unorderedRemoveItem<T>(array: T[], item: T): boolean;
/**
* Recursively collect all possible dependants of passed file
*/
export declare function collectAllDependants(reverseDependencyGraph: ReverseDependencyGraph, fileName: string, collected?: {
[file: string]: boolean;
}): string[];
/**
* Recursively collect all possible dependencies of passed file
*/
export declare function collectAllDependencies(dependencyGraph: DependencyGraph, filePath: string, collected?: {
[file: string]: boolean;
}): string[];
export declare function arrify<T>(val: T | T[]): T[];
export declare function ensureProgram(instance: TSInstance): typescript.Program | undefined;
export declare function supportsProjectReferences(instance: TSInstance): true | undefined;
export declare function isUsingProjectReferences(instance: TSInstance): boolean;
/**
* Gets the project reference for a file from the cache if it exists,
* or gets it from TypeScript and caches it otherwise.
*/
export declare function getAndCacheProjectReference(filePath: string, instance: TSInstance): typescript.ResolvedProjectReference | undefined;
export declare function validateSourceMapOncePerProject(instance: TSInstance, loader: webpack.loader.LoaderContext, jsFileName: string, project: typescript.ResolvedProjectReference): void;
/**
* Gets the output JS file path for an input file governed by a composite project.
* Pulls from the cache if it exists; computes and caches the result otherwise.
*/
export declare function getAndCacheOutputJSFileName(inputFileName: string, projectReference: typescript.ResolvedProjectReference, instance: TSInstance): string;
+6
View File
@@ -0,0 +1,6 @@
import * as webpack from 'webpack';
import { TSInstance } from './interfaces';
/**
* Make function which will manually update changed files
*/
export declare function makeWatchRun(instance: TSInstance): (compiler: webpack.Compiler, callback: () => void) => void;
+281
View File
@@ -0,0 +1,281 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const fs = require("fs");
const micromatch = require("micromatch");
const path = require("path");
const typescript = require("typescript");
const constants = require("./constants");
/**
* The default error formatter.
*/
function defaultErrorFormatter(error, colors) {
const messageColor = error.severity === 'warning' ? colors.bold.yellow : colors.bold.red;
return (colors.grey('[tsl] ') +
messageColor(error.severity.toUpperCase()) +
(error.file === ''
? ''
: messageColor(' in ') +
colors.bold.cyan(`${error.file}(${error.line},${error.character})`)) +
constants.EOL +
messageColor(` TS${error.code}: ${error.content}`));
}
/**
* Take TypeScript errors, parse them and format to webpack errors
* Optionally adds a file name
*/
function formatErrors(diagnostics, loaderOptions, colors, compiler, merge, context) {
return diagnostics === undefined
? []
: diagnostics
.filter(diagnostic => {
if (loaderOptions.ignoreDiagnostics.indexOf(diagnostic.code) !== -1) {
return false;
}
if (loaderOptions.reportFiles.length > 0 &&
diagnostic.file !== undefined) {
const relativeFileName = path.relative(context, diagnostic.file.fileName);
const matchResult = micromatch([relativeFileName], loaderOptions.reportFiles);
if (matchResult.length === 0) {
return false;
}
}
return true;
})
.map(diagnostic => {
const file = diagnostic.file;
const position = file === undefined
? undefined
: file.getLineAndCharacterOfPosition(diagnostic.start);
const errorInfo = {
code: diagnostic.code,
severity: compiler.DiagnosticCategory[diagnostic.category].toLowerCase(),
content: compiler.flattenDiagnosticMessageText(diagnostic.messageText, constants.EOL),
file: file === undefined ? '' : path.normalize(file.fileName),
line: position === undefined ? 0 : position.line + 1,
character: position === undefined ? 0 : position.character + 1,
context
};
const message = loaderOptions.errorFormatter === undefined
? defaultErrorFormatter(errorInfo, colors)
: loaderOptions.errorFormatter(errorInfo, colors);
const error = makeError(message, merge.file === undefined ? errorInfo.file : merge.file, position === undefined
? undefined
: { line: errorInfo.line, character: errorInfo.character });
return Object.assign(error, merge);
});
}
exports.formatErrors = formatErrors;
function readFile(fileName, encoding = 'utf8') {
fileName = path.normalize(fileName);
try {
return fs.readFileSync(fileName, encoding);
}
catch (e) {
return undefined;
}
}
exports.readFile = readFile;
function makeError(message, file, location) {
return {
message,
location,
file,
loaderSource: 'ts-loader'
};
}
exports.makeError = makeError;
function appendSuffixIfMatch(patterns, filePath, suffix) {
if (patterns.length > 0) {
for (const regexp of patterns) {
if (filePath.match(regexp) !== null) {
return filePath + suffix;
}
}
}
return filePath;
}
exports.appendSuffixIfMatch = appendSuffixIfMatch;
function appendSuffixesIfMatch(suffixDict, filePath) {
let amendedPath = filePath;
for (const suffix in suffixDict) {
amendedPath = appendSuffixIfMatch(suffixDict[suffix], amendedPath, suffix);
}
return amendedPath;
}
exports.appendSuffixesIfMatch = appendSuffixesIfMatch;
function unorderedRemoveItem(array, item) {
for (let i = 0; i < array.length; i++) {
if (array[i] === item) {
// Fill in the "hole" left at `index`.
array[i] = array[array.length - 1];
array.pop();
return true;
}
}
return false;
}
exports.unorderedRemoveItem = unorderedRemoveItem;
/**
* Recursively collect all possible dependants of passed file
*/
function collectAllDependants(reverseDependencyGraph, fileName, collected = {}) {
const result = {};
result[fileName] = true;
collected[fileName] = true;
const dependants = reverseDependencyGraph[fileName];
if (dependants !== undefined) {
Object.keys(dependants).forEach(dependantFileName => {
if (!collected[dependantFileName]) {
collectAllDependants(reverseDependencyGraph, dependantFileName, collected).forEach(fName => (result[fName] = true));
}
});
}
return Object.keys(result);
}
exports.collectAllDependants = collectAllDependants;
/**
* Recursively collect all possible dependencies of passed file
*/
function collectAllDependencies(dependencyGraph, filePath, collected = {}) {
const result = {};
result[filePath] = true;
collected[filePath] = true;
const directDependencies = dependencyGraph[filePath];
if (directDependencies !== undefined) {
directDependencies.forEach(dependencyModule => {
if (!collected[dependencyModule.originalFileName]) {
collectAllDependencies(dependencyGraph, dependencyModule.resolvedFileName, collected).forEach(depFilePath => (result[depFilePath] = true));
}
});
}
return Object.keys(result);
}
exports.collectAllDependencies = collectAllDependencies;
function arrify(val) {
if (val === null || val === undefined) {
return [];
}
return Array.isArray(val) ? val : [val];
}
exports.arrify = arrify;
function ensureProgram(instance) {
if (instance && instance.watchHost) {
if (instance.hasUnaccountedModifiedFiles) {
if (instance.changedFilesList) {
instance.watchHost.updateRootFileNames();
}
if (instance.watchOfFilesAndCompilerOptions) {
instance.program = instance.watchOfFilesAndCompilerOptions
.getProgram()
.getProgram();
}
instance.hasUnaccountedModifiedFiles = false;
}
return instance.program;
}
if (instance.languageService) {
return instance.languageService.getProgram();
}
return instance.program;
}
exports.ensureProgram = ensureProgram;
function supportsProjectReferences(instance) {
const program = ensureProgram(instance);
return program && !!program.getProjectReferences;
}
exports.supportsProjectReferences = supportsProjectReferences;
function isUsingProjectReferences(instance) {
if (instance.loaderOptions.projectReferences &&
supportsProjectReferences(instance)) {
const program = ensureProgram(instance);
return Boolean(program && program.getProjectReferences());
}
return false;
}
exports.isUsingProjectReferences = isUsingProjectReferences;
/**
* Gets the project reference for a file from the cache if it exists,
* or gets it from TypeScript and caches it otherwise.
*/
function getAndCacheProjectReference(filePath, instance) {
const file = instance.files.get(filePath);
if (file !== undefined && file.projectReference) {
return file.projectReference.project;
}
const projectReference = getProjectReferenceForFile(filePath, instance);
if (file !== undefined) {
file.projectReference = { project: projectReference };
}
return projectReference;
}
exports.getAndCacheProjectReference = getAndCacheProjectReference;
function getResolvedProjectReferences(program) {
const getProjectReferences = program.getResolvedProjectReferences ||
program.getProjectReferences;
if (getProjectReferences) {
return getProjectReferences();
}
return;
}
function getProjectReferenceForFile(filePath, instance) {
if (isUsingProjectReferences(instance)) {
const program = ensureProgram(instance);
return (program &&
getResolvedProjectReferences(program).find(ref => (ref &&
ref.commandLine.fileNames.some(file => path.normalize(file) === filePath)) ||
false));
}
return;
}
function validateSourceMapOncePerProject(instance, loader, jsFileName, project) {
const { projectsMissingSourceMaps = new Set() } = instance;
if (!projectsMissingSourceMaps.has(project.sourceFile.fileName)) {
instance.projectsMissingSourceMaps = projectsMissingSourceMaps;
projectsMissingSourceMaps.add(project.sourceFile.fileName);
const mapFileName = jsFileName + '.map';
if (!instance.compiler.sys.fileExists(mapFileName)) {
const [relativeJSPath, relativeProjectConfigPath] = [
path.relative(loader.rootContext, jsFileName),
path.relative(loader.rootContext, project.sourceFile.fileName)
];
loader.emitWarning(new Error('Could not find source map file for referenced project output ' +
`${relativeJSPath}. Ensure the 'sourceMap' compiler option ` +
`is enabled in ${relativeProjectConfigPath} to ensure Webpack ` +
'can map project references to the appropriate source files.'));
}
}
}
exports.validateSourceMapOncePerProject = validateSourceMapOncePerProject;
/**
* Gets the output JS file path for an input file governed by a composite project.
* Pulls from the cache if it exists; computes and caches the result otherwise.
*/
function getAndCacheOutputJSFileName(inputFileName, projectReference, instance) {
const file = instance.files.get(inputFileName);
if (file && file.projectReference && file.projectReference.outputFileName) {
return file.projectReference.outputFileName;
}
const outputFileName = getOutputJavaScriptFileName(inputFileName, projectReference);
if (file !== undefined) {
file.projectReference = file.projectReference || {
project: projectReference
};
file.projectReference.outputFileName = outputFileName;
}
return outputFileName;
}
exports.getAndCacheOutputJSFileName = getAndCacheOutputJSFileName;
// Adapted from https://github.com/Microsoft/TypeScript/blob/45101491c0b077c509b25830ef0ee5f85b293754/src/compiler/tsbuild.ts#L305
function getOutputJavaScriptFileName(inputFileName, projectReference) {
const { options } = projectReference.commandLine;
const projectDirectory = options.rootDir || path.dirname(projectReference.sourceFile.fileName);
const relativePath = path.relative(projectDirectory, inputFileName);
const outputPath = path.resolve(options.outDir || projectDirectory, relativePath);
const newExtension = constants.jsonRegex.test(inputFileName)
? '.json'
: constants.tsxRegex.test(inputFileName) &&
options.jsx === typescript.JsxEmit.Preserve
? '.jsx'
: '.js';
return outputPath.replace(constants.extensionRegex, newExtension);
}
+51
View File
@@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const path = require("path");
const constants = require("./constants");
const utils_1 = require("./utils");
/**
* Make function which will manually update changed files
*/
function makeWatchRun(instance) {
// Called Before starting compilation after watch
const lastTimes = new Map();
const startTime = 0;
return (compiler, callback) => {
if (null === instance.modifiedFiles) {
instance.modifiedFiles = new Map();
}
// startTime = startTime || watching.startTime;
const times = compiler.fileTimestamps;
for (const [filePath, date] of times) {
if (date > (lastTimes.get(filePath) || startTime) &&
filePath.match(constants.tsTsxJsJsxRegex) !== null) {
continue;
}
lastTimes.set(filePath, date);
updateFile(instance, filePath);
}
// On watch update add all known dts files expect the ones in node_modules
// (skip @types/* and modules with typings)
for (const filePath of instance.files.keys()) {
if (filePath.match(constants.dtsDtsxOrDtsDtsxMapRegex) !== null &&
filePath.match(constants.nodeModules) === null) {
updateFile(instance, filePath);
}
}
callback();
};
}
exports.makeWatchRun = makeWatchRun;
function updateFile(instance, filePath) {
const nFilePath = path.normalize(filePath);
const file = instance.files.get(nFilePath) || instance.otherFiles.get(nFilePath);
if (file !== undefined) {
file.text = utils_1.readFile(nFilePath) || '';
file.version++;
instance.version++;
instance.modifiedFiles.set(nFilePath, file);
if (instance.watchHost !== undefined) {
instance.watchHost.invokeFileWatcher(nFilePath, instance.compiler.FileWatcherEventKind.Changed);
}
}
}