"use strict"; var constants = require("./constants"); var path = require("path"); var makeResolver = require("./resolver"); var utils = require("./utils"); /** * Create the TypeScript language service */ function makeServicesHost(scriptRegex, log, loader, instance, appendTsSuffixTo) { var compiler = instance.compiler, compilerOptions = instance.compilerOptions, files = instance.files; var newLine = compilerOptions.newLine === constants.CarriageReturnLineFeedCode ? constants.CarriageReturnLineFeed : compilerOptions.newLine === constants.LineFeedCode ? constants.LineFeed : constants.EOL; // make a (sync) resolver that follows webpack's rules var resolveSync = makeResolver(loader.options); var moduleResolutionHost = { fileExists: function (fileName) { return utils.readFile(fileName) !== undefined; }, readFile: function (fileName) { return utils.readFile(fileName); }, }; return { getProjectVersion: function () { return "" + instance.version; }, getScriptFileNames: function () { return Object.keys(files).filter(function (filePath) { return !!filePath.match(scriptRegex); }); }, getScriptVersion: function (fileName) { fileName = path.normalize(fileName); return files[fileName] && files[fileName].version.toString(); }, getScriptSnapshot: function (fileName) { // This is called any time TypeScript needs a file's text // We either load from memory or from disk fileName = path.normalize(fileName); var file = files[fileName]; if (!file) { var text = utils.readFile(fileName); if (!text) { return undefined; } file = files[fileName] = { version: 0, text: text }; } 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 ? compiler.sys.getDirectories : undefined, /** * For @types expansion, these two functions are needed. */ directoryExists: compiler.sys ? compiler.sys.directoryExists : undefined, getCurrentDirectory: function () { return process.cwd(); }, getCompilationSettings: function () { return compilerOptions; }, getDefaultLibFileName: function (options) { return compiler.getDefaultLibFilePath(options); }, getNewLine: function () { return newLine; }, log: log.log, resolveModuleNames: function (moduleNames, containingFile) { return resolveModuleNames(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, moduleNames, containingFile); } }; } function resolveModuleNames(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, moduleNames, containingFile) { var resolvedModules = moduleNames.map(function (moduleName) { return resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, moduleName, containingFile); }); populateDependencyGraphs(resolvedModules, instance, containingFile); return resolvedModules; } function resolveModuleName(resolveSync, moduleResolutionHost, appendTsSuffixTo, scriptRegex, instance, moduleName, containingFile) { var compiler = instance.compiler, compilerOptions = instance.compilerOptions; var resolutionResult; try { var originalFileName = resolveSync(undefined, path.normalize(path.dirname(containingFile)), moduleName); var resolvedFileName = utils.appendTsSuffixIfMatch(appendTsSuffixTo, originalFileName); if (resolvedFileName.match(scriptRegex)) { resolutionResult = { resolvedFileName: resolvedFileName, originalFileName: originalFileName }; } } catch (e) { } var tsResolution = compiler.resolveModuleName(moduleName, containingFile, compilerOptions, moduleResolutionHost); if (tsResolution.resolvedModule) { var resolvedFileName = path.normalize(tsResolution.resolvedModule.resolvedFileName); var tsResolutionResult = { originalFileName: resolvedFileName, resolvedFileName: resolvedFileName, isExternalLibraryImport: tsResolution.resolvedModule.isExternalLibraryImport }; if (resolutionResult) { if (resolutionResult.resolvedFileName === tsResolutionResult.resolvedFileName) { resolutionResult.isExternalLibraryImport = tsResolutionResult.isExternalLibraryImport; } } else { resolutionResult = tsResolutionResult; } } return resolutionResult; } function populateDependencyGraphs(resolvedModules, instance, containingFile) { resolvedModules = resolvedModules .filter(function (m) { return m !== null && m !== undefined; }); instance.dependencyGraph[path.normalize(containingFile)] = resolvedModules; resolvedModules.forEach(function (resolvedModule) { if (!instance.reverseDependencyGraph[resolvedModule.resolvedFileName]) { instance.reverseDependencyGraph[resolvedModule.resolvedFileName] = {}; } instance.reverseDependencyGraph[resolvedModule.resolvedFileName][path.normalize(containingFile)] = true; }); } module.exports = makeServicesHost;