109 lines
5.4 KiB
JavaScript
109 lines
5.4 KiB
JavaScript
|
"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;
|