"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; Object.defineProperty(exports, "__esModule", { value: true }); var fs = require("fs"); var path = require("path"); var ts = require("typescript"); var VueProgram = /** @class */ (function () { function VueProgram() { } VueProgram.loadProgramConfig = function (configFile, compilerOptions) { var extraExtensions = ['vue']; var parseConfigHost = { fileExists: ts.sys.fileExists, readFile: ts.sys.readFile, useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames, readDirectory: function (rootDir, extensions, excludes, includes, depth) { return ts.sys.readDirectory(rootDir, extensions.concat(extraExtensions), excludes, includes, depth); } }; var tsconfig = ts.readConfigFile(configFile, ts.sys.readFile).config; tsconfig.compilerOptions = tsconfig.compilerOptions || {}; tsconfig.compilerOptions = __assign({}, tsconfig.compilerOptions, compilerOptions); var parsed = ts.parseJsonConfigFileContent(tsconfig, parseConfigHost, path.dirname(configFile)); parsed.options.allowNonTsExtensions = true; return parsed; }; /** * Search for default wildcard or wildcard from options, we only search for that in tsconfig CompilerOptions.paths. * The path is resolved with thie given substitution and includes the CompilerOptions.baseUrl (if given). * If no paths given in tsconfig, then the default substitution is '[tsconfig directory]/src'. * (This is a fast, simplified inspiration of what's described here: https://github.com/Microsoft/TypeScript/issues/5039) */ VueProgram.resolveNonTsModuleName = function (moduleName, containingFile, basedir, options) { var baseUrl = options.baseUrl ? options.baseUrl : basedir; var discardedSymbols = ['.', '..', '/']; var wildcards = []; if (options.paths) { Object.keys(options.paths).forEach(function (key) { var pathSymbol = key[0]; if (discardedSymbols.indexOf(pathSymbol) < 0 && wildcards.indexOf(pathSymbol) < 0) { wildcards.push(pathSymbol); } }); } else { wildcards.push('@'); } var isRelative = !path.isAbsolute(moduleName); var correctWildcard; wildcards.forEach(function (wildcard) { if (moduleName.substr(0, 2) === wildcard + "/") { correctWildcard = wildcard; } }); if (correctWildcard) { var pattern = options.paths ? options.paths[correctWildcard + "/*"] : undefined; var substitution = pattern ? options.paths[correctWildcard + "/*"][0].replace('*', '') : 'src'; moduleName = path.resolve(baseUrl, substitution, moduleName.substr(2)); } else if (isRelative) { moduleName = path.resolve(path.dirname(containingFile), moduleName); } return moduleName; }; VueProgram.isVue = function (filePath) { return path.extname(filePath) === '.vue'; }; VueProgram.createProgram = function (programConfig, basedir, files, watcher, oldProgram) { var host = ts.createCompilerHost(programConfig.options); var realGetSourceFile = host.getSourceFile; // We need a host that can parse Vue SFCs (single file components). host.getSourceFile = function (filePath, languageVersion, onError) { // first check if watcher is watching file - if not - check it's mtime if (!watcher.isWatchingFile(filePath)) { try { var stats = fs.statSync(filePath); files.setMtime(filePath, stats.mtime.valueOf()); } catch (e) { // probably file does not exists files.remove(filePath); } } // get source file only if there is no source in files register if (!files.has(filePath) || !files.getData(filePath).source) { files.mutateData(filePath, function (data) { data.source = realGetSourceFile(filePath, languageVersion, onError); }); } var source = files.getData(filePath).source; // get typescript contents from Vue file if (source && VueProgram.isVue(filePath)) { var resolved = VueProgram.resolveScriptBlock(source.text); source = ts.createSourceFile(filePath, resolved.content, languageVersion, true, resolved.scriptKind); } return source; }; // We need a host with special module resolution for Vue files. host.resolveModuleNames = function (moduleNames, containingFile) { var resolvedModules = []; for (var _i = 0, moduleNames_1 = moduleNames; _i < moduleNames_1.length; _i++) { var moduleName = moduleNames_1[_i]; // Try to use standard resolution. var resolvedModule = ts.resolveModuleName(moduleName, containingFile, programConfig.options, { fileExists: function (fileName) { if (fileName.endsWith('.vue.ts')) { return (host.fileExists(fileName.slice(0, -3)) || host.fileExists(fileName)); } else { return host.fileExists(fileName); } }, readFile: function (fileName) { // This implementation is not necessary. Just for consistent behavior. if (fileName.endsWith('.vue.ts') && !host.fileExists(fileName)) { return host.readFile(fileName.slice(0, -3)); } else { return host.readFile(fileName); } } }).resolvedModule; if (resolvedModule) { if (resolvedModule.resolvedFileName.endsWith('.vue.ts') && !host.fileExists(resolvedModule.resolvedFileName)) { resolvedModule.resolvedFileName = resolvedModule.resolvedFileName.slice(0, -3); } resolvedModules.push(resolvedModule); } else { // For non-ts extensions. var absolutePath = VueProgram.resolveNonTsModuleName(moduleName, containingFile, basedir, programConfig.options); if (VueProgram.isVue(moduleName)) { resolvedModules.push({ resolvedFileName: absolutePath, extension: '.ts' }); } else { resolvedModules.push({ // If the file does exist, return an empty string (because we assume user has provided a ".d.ts" file for it). resolvedFileName: host.fileExists(absolutePath) ? '' : absolutePath, extension: '.ts' }); } } } return resolvedModules; }; return ts.createProgram(programConfig.fileNames, programConfig.options, host, oldProgram // re-use old program ); }; VueProgram.getScriptKindByLang = function (lang) { if (lang === 'ts') { return ts.ScriptKind.TS; } else if (lang === 'tsx') { return ts.ScriptKind.TSX; } else if (lang === 'jsx') { return ts.ScriptKind.JSX; } else { // when lang is "js" or no lang specified return ts.ScriptKind.JS; } }; VueProgram.resolveScriptBlock = function (content) { // We need to import vue-template-compiler lazily because it cannot be included it // as direct dependency because it is an optional dependency of fork-ts-checker-webpack-plugin. // Since its version must not mismatch with user-installed Vue.js, // we should let the users install vue-template-compiler by themselves. var parser; try { // tslint:disable-next-line parser = require('vue-template-compiler'); } catch (err) { throw new Error('When you use `vue` option, make sure to install `vue-template-compiler`.'); } var script = parser.parseComponent(content, { pad: 'space' }).script; // No