From 3b044063de3dea82d0230878896adce25667dcc6 Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Tue, 30 Jun 2015 22:06:15 +0200 Subject: [PATCH 1/3] Add language service API to get the compile and runtime dependencies of a source file --- src/services/services.ts | 74 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 3 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index 018a11fc4bb3d..f1c3736fd7503 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -1027,9 +1027,11 @@ namespace ts { getFormattingEditsForRange(fileName: string, start: number, end: number, options: FormatCodeOptions): TextChange[]; getFormattingEditsForDocument(fileName: string, options: FormatCodeOptions): TextChange[]; getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: FormatCodeOptions): TextChange[]; + + getDependencies(fileName: string): DependencyInfo; getEmitOutput(fileName: string): EmitOutput; - + getProgram(): Program; getSourceFile(fileName: string): SourceFile; @@ -1267,11 +1269,20 @@ namespace ts { autoCollapse: boolean; } + export interface DependencyInfo { + /** The file name of the dependency information */ + fileName: string; + /** The compile time dependencies of a file */ + compileTime: string[]; + /** The runtime dependencies of a file */ + runtime: string[]; + } + export interface EmitOutput { outputFiles: OutputFile[]; emitSkipped: boolean; } - + export const enum OutputFileType { JavaScript, SourceMap, @@ -5762,6 +5773,62 @@ namespace ts { return forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error); } + function getDependencies(fileName: string): DependencyInfo { + synchronizeHostData(); + + let sourceFile = getValidSourceFile(fileName); + if (!sourceFile) { + return undefined; + } + + let resolver = program.getDiagnosticsProducingTypeChecker().getEmitResolver(sourceFile); + + let runtime: string[] = []; + let compileTime: string[] = []; + for (let node of sourceFile.amdDependencies) { + runtime.push(node.path); + } + + function getModuleNameText(node: ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration): string { + let moduleName = getExternalModuleName(node); + return (moduleName).text; + } + + for (let node of sourceFile.statements) { + switch (node.kind) { + case SyntaxKind.ImportDeclaration: + let importDeclaration = node; + if (!importDeclaration.importClause || resolver.isReferencedAliasDeclaration(importDeclaration.importClause, /*checkChildren*/ true)) { + runtime.push(getModuleNameText(importDeclaration)); + } else { + compileTime.push(getModuleNameText(importDeclaration)); + } + break; + case SyntaxKind.ImportEqualsDeclaration: + let importEqualsDeclaration = node; + if (importEqualsDeclaration.moduleReference.kind === SyntaxKind.ExternalModuleReference && resolver.isReferencedAliasDeclaration(importEqualsDeclaration)) { + runtime.push(getModuleNameText(importEqualsDeclaration)); + } else { + compileTime.push(getModuleNameText(importEqualsDeclaration)); + } + break; + case SyntaxKind.ExportDeclaration: + let exportDeclaration = node; + if (exportDeclaration.moduleSpecifier && (!exportDeclaration.exportClause || resolver.isValueAliasDeclaration(exportDeclaration))) { + // export * as mod from 'mod' && export {x , y } from 'mod' + runtime.push(getModuleNameText(exportDeclaration)); + } + // export { x, y } does neither generate a runtime nor a compile time dependency + break; + } + } + return { + fileName: sourceFile.fileName, + compileTime: compileTime, + runtime: runtime + } + } + function getEmitOutput(fileName: string): EmitOutput { synchronizeHostData(); @@ -5783,7 +5850,7 @@ namespace ts { emitSkipped: emitOutput.emitSkipped }; } - + function getMeaningFromDeclaration(node: Node): SemanticMeaning { switch (node.kind) { case SyntaxKind.Parameter: @@ -6810,6 +6877,7 @@ namespace ts { getFormattingEditsForRange, getFormattingEditsForDocument, getFormattingEditsAfterKeystroke, + getDependencies, getEmitOutput, getSourceFile, getProgram From d690e35f52ab551d09d6759615c005adab49601a Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Tue, 30 Jun 2015 23:23:06 +0200 Subject: [PATCH 2/3] update harness, client and shim --- src/harness/harnessLanguageService.ts | 3 +++ src/server/client.ts | 4 ++++ src/services/shims.ts | 12 ++++++++++++ 3 files changed, 19 insertions(+) diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 8eb778175334c..31c9318b1fc1d 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -384,6 +384,9 @@ module Harness.LanguageService { getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: ts.FormatCodeOptions): ts.TextChange[] { return unwrapJSONCallResult(this.shim.getFormattingEditsAfterKeystroke(fileName, position, key, JSON.stringify(options))); } + getDependencies(fileName: string): ts.DependencyInfo { + return unwrapJSONCallResult(this.shim.getDependencies(fileName)); + } getEmitOutput(fileName: string): ts.EmitOutput { return unwrapJSONCallResult(this.shim.getEmitOutput(fileName)); } diff --git a/src/server/client.ts b/src/server/client.ts index e4a524dd21034..19c07a8a37087 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -369,6 +369,10 @@ namespace ts.server { }); } + getDependencies(fileName: string): DependencyInfo { + throw new Error("Not Implemented Yet."); + } + getEmitOutput(fileName: string): EmitOutput { throw new Error("Not Implemented Yet."); } diff --git a/src/services/shims.ts b/src/services/shims.ts index 2e8b3eb774d59..3a5ad5697af87 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -197,6 +197,8 @@ namespace ts { getFormattingEditsForDocument(fileName: string, options: string/*Services.FormatCodeOptions*/): string; getFormattingEditsAfterKeystroke(fileName: string, position: number, key: string, options: string/*Services.FormatCodeOptions*/): string; + getDependencies(fileName: string): string; + getEmitOutput(fileName: string): string; } @@ -799,6 +801,16 @@ namespace ts { return items; }); } + + public getDependencies(fileName: string): string { + return this.forwardJSONCall( + "getDependencies('" + fileName + "')", + () => { + var dependencies = this.languageService.getDependencies(fileName); + return dependencies; + } + ) + } /// Emit public getEmitOutput(fileName: string): string { From 7ac7c9e6c8f00665c523a403a62d050599b2617f Mon Sep 17 00:00:00 2001 From: Dirk Baeumer Date: Fri, 17 Jul 2015 11:38:05 +0200 Subject: [PATCH 3/3] Handle export import correctly --- src/services/services.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/services/services.ts b/src/services/services.ts index f1c3736fd7503..23af73f4f594c 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -5806,10 +5806,12 @@ namespace ts { break; case SyntaxKind.ImportEqualsDeclaration: let importEqualsDeclaration = node; - if (importEqualsDeclaration.moduleReference.kind === SyntaxKind.ExternalModuleReference && resolver.isReferencedAliasDeclaration(importEqualsDeclaration)) { - runtime.push(getModuleNameText(importEqualsDeclaration)); - } else { - compileTime.push(getModuleNameText(importEqualsDeclaration)); + if (importEqualsDeclaration.moduleReference.kind === SyntaxKind.ExternalModuleReference) { + if (resolver.isReferencedAliasDeclaration(importEqualsDeclaration)) { + runtime.push(getModuleNameText(importEqualsDeclaration)); + } else { + compileTime.push(getModuleNameText(importEqualsDeclaration)); + } } break; case SyntaxKind.ExportDeclaration: