"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var bs_logger_1 = require("bs-logger"); var memoize = require("lodash.memoize"); var path_1 = require("path"); var constants_1 = require("../constants"); var messages_1 = require("../util/messages"); var compiler_utils_1 = require("./compiler-utils"); function doTypeChecking(configs, fileName, service, logger) { if (configs.shouldReportDiagnostic(fileName)) { var diagnostics = service.getSemanticDiagnostics(fileName).concat(service.getSyntacticDiagnostics(fileName)); configs.raiseDiagnostics(diagnostics, fileName, logger); } } exports.compileUsingLanguageService = function (configs, logger, memoryCache) { var _a; logger.debug('compileUsingLanguageService(): create typescript compiler'); var ts = configs.compilerModule; var cwd = configs.cwd; var cacheDir = configs.tsCacheDir; var options = configs.typescript.options; var serviceHostTraceCtx = (_a = { namespace: 'ts:serviceHost', call: null }, _a[bs_logger_1.LogContexts.logLevel] = bs_logger_1.LogLevels.trace, _a); var projectVersion = 1; var updateMemoryCache = function (contents, fileName) { var _a; logger.debug({ fileName: fileName }, "updateMemoryCache(): update memory cache for language service"); var shouldIncrementProjectVersion = false; var fileVersion = (_a = memoryCache.versions[fileName]) !== null && _a !== void 0 ? _a : 0; var isFileInCache = fileVersion !== 0; if (!isFileInCache) { memoryCache.versions[fileName] = 1; shouldIncrementProjectVersion = true; } var previousContents = memoryCache.contents[fileName]; if (previousContents !== contents) { memoryCache.versions[fileName] = fileVersion + 1; memoryCache.contents[fileName] = contents; if (isFileInCache) shouldIncrementProjectVersion = true; } if (shouldIncrementProjectVersion) projectVersion++; }; var serviceHost = { getProjectVersion: function () { return String(projectVersion); }, getScriptFileNames: function () { return Object.keys(memoryCache.versions); }, getScriptVersion: function (fileName) { var normalizedFileName = path_1.normalize(fileName); var version = memoryCache.versions[normalizedFileName]; return version === undefined ? undefined : String(version); }, getScriptSnapshot: function (fileName) { var normalizedFileName = path_1.normalize(fileName); var hit = compiler_utils_1.hasOwn.call(memoryCache.contents, normalizedFileName); logger.trace({ normalizedFileName: normalizedFileName, cacheHit: hit }, "getScriptSnapshot():", 'cache', hit ? 'hit' : 'miss'); if (!hit) memoryCache.contents[normalizedFileName] = ts.sys.readFile(normalizedFileName); var contents = memoryCache.contents[normalizedFileName]; if (contents === undefined) return; return ts.ScriptSnapshot.fromString(contents); }, fileExists: memoize(ts.sys.fileExists), readFile: logger.wrap(serviceHostTraceCtx, 'readFile', memoize(ts.sys.readFile)), readDirectory: memoize(ts.sys.readDirectory), getDirectories: memoize(ts.sys.getDirectories), directoryExists: memoize(ts.sys.directoryExists), realpath: memoize(ts.sys.realpath), getNewLine: function () { return constants_1.LINE_FEED; }, getCurrentDirectory: function () { return cwd; }, getCompilationSettings: function () { return options; }, getDefaultLibFileName: function () { return ts.getDefaultLibFilePath(options); }, getCustomTransformers: function () { return configs.tsCustomTransformers; }, }; logger.debug('compileUsingLanguageService(): creating language service'); var service = ts.createLanguageService(serviceHost); return { compileFn: function (code, fileName) { var normalizedFileName = path_1.normalize(fileName); logger.debug({ normalizedFileName: normalizedFileName }, 'compileFn(): compiling using language service'); updateMemoryCache(code, normalizedFileName); var output = service.getEmitOutput(normalizedFileName); logger.debug("diagnoseFn(): computing diagnostics for " + normalizedFileName + " using language service"); doTypeChecking(configs, normalizedFileName, service, logger); if (cacheDir) { if (compiler_utils_1.isTestFile(configs.testMatchPatterns, normalizedFileName)) { compiler_utils_1.cacheResolvedModules(normalizedFileName, code, memoryCache, service.getProgram(), cacheDir, logger); } else { Object.entries(memoryCache.resolvedModules) .filter(function (entry) { return (entry[1].modulePaths.find(function (modulePath) { return modulePath === normalizedFileName; }) && !compiler_utils_1.hasOwn.call(memoryCache.outputs, entry[0])); }) .forEach(function (entry) { logger.debug("diagnoseFn(): computing diagnostics for test file that imports " + normalizedFileName + " using language service"); var testFileName = entry[0]; updateMemoryCache(entry[1].testFileContent, testFileName); doTypeChecking(configs, testFileName, service, logger); }); } } if (output.emitSkipped) { throw new TypeError(path_1.relative(cwd, normalizedFileName) + ": Emit skipped for language service"); } if (!output.outputFiles.length) { throw new TypeError(messages_1.interpolate("Unable to require `.d.ts` file for file: {{file}}.\nThis is usually the result of a faulty configuration or import. Make sure there is a `.js`, `.json` or another executable extension available alongside `{{file}}`.", { file: path_1.basename(normalizedFileName), })); } return [output.outputFiles[1].text, output.outputFiles[0].text]; }, program: service.getProgram(), }; };