UNPKG

awesome-typescript-loader

Version:
228 lines (190 loc) 6.83 kB
import { ICompilerInfo, IFile, TSCONFIG_INFERRED } from './host'; import * as path from 'path'; import { LoaderPlugin, LoaderPluginDef, LoaderConfig } from './instance'; let colors = require('colors/safe'); export enum MessageType { Init = <any>'init', Compile = <any>'compile' } export interface IMessage { messageType: MessageType; payload: any; } export interface IInitPayload { loaderConfig: LoaderConfig; compilerOptions: ts.CompilerOptions; compilerInfo: ICompilerInfo; webpackOptions: any; defaultLib: string; plugins: LoaderPluginDef[]; } export interface ICompilePayload { files: {[fileName: string]: IFile}; moduleResolutionCache: {[fileName: string]: ts.ResolvedModule}; typeReferenceResolutionCache: {[fileName: string]: ts.ResolvedTypeReferenceDirective}; } export interface IEnv { loaderConfig?: LoaderConfig; compilerOptions?: ts.CompilerOptions; webpackOptions?: any; compiler?: typeof ts; compilerInfo?: ICompilerInfo; host?: Host; files?: {[fileName: string]: IFile}; moduleResolutionCache?: {[fileName: string]: ts.ResolvedModule}; typeReferenceResolutionCache?: {[fileName: string]: ts.ResolvedTypeReferenceDirective}; program?: ts.Program; service?: ts.LanguageService; plugins?: LoaderPluginDef[]; defaultLib?: string; initedPlugins?: LoaderPlugin[]; } export interface SyncResolver { (context: string, fileName: string): string; } let env: IEnv = {}; export class ModuleResolutionHost implements ts.ModuleResolutionHost { servicesHost: Host; constructor(servicesHost: Host) { this.servicesHost = servicesHost; } fileExists(fileName: string) { return this.servicesHost.getScriptSnapshot(fileName) !== undefined; } readFile(fileName: string): string { let snapshot = this.servicesHost.getScriptSnapshot(fileName); return snapshot && snapshot.getText(0, snapshot.getLength()); } } export class Host implements ts.LanguageServiceHost { moduleResolutionHost: ModuleResolutionHost; resolver: SyncResolver; constructor() { this.moduleResolutionHost = new ModuleResolutionHost(this); } getScriptFileNames() { return Object.keys(env.files); } getScriptVersion(fileName: string) { if (env.files[fileName]) { return env.files[fileName].version.toString(); } } getScriptSnapshot(fileName: string) { let file = env.files[fileName]; if (!file) { return null; } return env.compiler.ScriptSnapshot.fromString(file.text); } getCurrentDirectory() { return process.cwd(); } getScriptIsOpen() { return true; } getCompilationSettings() { return env.compilerOptions; } resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string) { if (containingFile.indexOf(TSCONFIG_INFERRED) !== -1) { containingFile = TSCONFIG_INFERRED; } return typeDirectiveNames.map(moduleName => { return env.typeReferenceResolutionCache[`${containingFile}::${moduleName}`]; }); } resolveModuleNames(moduleNames: string[], containingFile: string) { return moduleNames.map(moduleName => { return env.moduleResolutionCache[`${containingFile}::${moduleName}`]; }); } getDefaultLibFileName(options: ts.CompilerOptions) { return env.defaultLib; } log(message) { } } function processInit(payload: IInitPayload) { env.compiler = require(payload.compilerInfo.compilerPath); env.compilerInfo = payload.compilerInfo; env.loaderConfig = payload.loaderConfig; env.compilerOptions = payload.compilerOptions; env.webpackOptions = payload.webpackOptions; env.defaultLib = payload.defaultLib; env.host = new Host(); env.service = env.compiler.createLanguageService(env.host, env.compiler.createDocumentRegistry()); env.plugins = payload.plugins; env.initedPlugins = env.plugins.map(plugin => { return require(plugin.file)(plugin.options); }); } let DECLARATION_FILE = /\.d\.ts/; function processCompile(payload: ICompilePayload) { let instanceName = env.loaderConfig.instanceName || 'default'; let silent = !!env.loaderConfig.forkCheckerSilent; if (!silent) { console.log(colors.cyan(`[${ instanceName }] Checking started in a separate process...`)); } let timeStart = +new Date(); process.send({ messageType: 'progress', payload: { inProgress: true } }); env.files = payload.files; env.moduleResolutionCache = payload.moduleResolutionCache; env.typeReferenceResolutionCache = payload.typeReferenceResolutionCache; let program = env.program = env.service.getProgram(); let allDiagnostics: ts.Diagnostic[] = []; if (env.loaderConfig.skipDeclarationFilesCheck) { let sourceFiles = program.getSourceFiles(); sourceFiles.forEach(sourceFile => { if (!sourceFile.fileName.match(DECLARATION_FILE)) { allDiagnostics = allDiagnostics.concat(env.compiler.getPreEmitDiagnostics(program, sourceFile)); } }); // FIXME internal API allDiagnostics = (env.compiler as any).sortAndDeduplicateDiagnostics(allDiagnostics); } else { allDiagnostics = env.compiler.getPreEmitDiagnostics(program); } if (allDiagnostics.length) { allDiagnostics.forEach(diagnostic => { let message = env.compiler.flattenDiagnosticMessageText(diagnostic.messageText, '\n'); if (diagnostic.file) { let { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start); console.error(`[${ instanceName }] ${colors.red(path.normalize(diagnostic.file.fileName))}:${line + 1}:${character + 1} \n ${colors.red(message)}`); } else { console.error(colors.red(`[${ instanceName }] ${ message }`)); } }); } else { if (!silent) { let timeEnd = +new Date(); console.log( colors.green(`[${ instanceName }] Ok, ${(timeEnd - timeStart) / 1000} sec.`) ); } } env.initedPlugins.forEach(plugin => { plugin.processProgram(program); }); process.send({ messageType: 'progress', payload: { inProgress: false } }); } process.on('message', function(msg: IMessage) { switch (msg.messageType) { case MessageType.Init: processInit(msg.payload); break; case MessageType.Compile: processCompile(msg.payload); break; } });