From 0a08a42abed4f26cb2103a52660ea6c3a11add0f Mon Sep 17 00:00:00 2001 From: Mohamed Hegazy Date: Tue, 29 Jul 2014 10:37:01 -0700 Subject: [PATCH] enbale fourslash tests --- Jakefile | 10 +- src/compiler/core.ts | 8 + src/harness/fourslash.ts | 462 ++++++++++++-------------- src/harness/harnessLanguageService.ts | 213 +++++++----- src/harness/runner.ts | 6 +- src/services/core/diagnosticCore.ts | 7 +- src/services/services.ts | 4 +- src/services/shims.ts | 8 + 8 files changed, 361 insertions(+), 357 deletions(-) diff --git a/Jakefile b/Jakefile index f8d7f15e7a6..d738359e221 100644 --- a/Jakefile +++ b/Jakefile @@ -62,19 +62,17 @@ var servicesSources = [ var harnessSources = [ "harness.ts", "sourceMapRecorder.ts", -// TODO Re-enable -// "harnessLanguageService.ts", -// "fourslash.ts", - "runner.ts", + "harnessLanguageService.ts", + "fourslash.ts", "external/json2.ts", "runnerbase.ts", "compilerRunner.ts", "typeWriter.ts", -// TODO Re-enable fourslash and project tests -// "fourslashRunner.ts", + "fourslashRunner.ts", "projectsRunner.ts", "unittestrunner.ts", "rwcRunner.ts", + "runner.ts" ].map(function (f) { return path.join(harnessDirectory, f); }); diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 6f9f2629a80..824aaca5a46 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -134,6 +134,14 @@ module ts { return result; } + export function forEachKey(map: Map, callback: (key: string) => U): U { + var result: U; + for (var id in map) { + if (result = callback(id)) break; + } + return result; + } + export function mapToArray(map: Map): T[] { var result: T[] = []; for (var id in map) result.push(map[id]); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 3037971471a..ac11fecbd3f 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -14,6 +14,7 @@ // /// +/// /// module FourSlash { @@ -108,7 +109,7 @@ module FourSlash { High } - var entityMap: TypeScript.IIndexable = { + var entityMap: ts.Map = { '&': '&', '"': '"', "'": ''', @@ -127,7 +128,7 @@ module FourSlash { export var currentTestState: TestState = null; - export class TestCancellationToken implements TypeScript.ICancellationToken { + export class TestCancellationToken implements ts.CancellationToken { // 0 - cancelled // >0 - not cancelled // <0 - not cancelled and value denotes number of isCancellationRequested after which token become cancelled @@ -162,7 +163,7 @@ module FourSlash { f(); } catch (e) { - if (e instanceof TypeScript.OperationCanceledException) { + if (e instanceof ts.OperationCanceledException) { return; } } @@ -172,9 +173,8 @@ module FourSlash { export class TestState { // Language service instance - public languageServiceShimHost: Harness.TypeScriptLS = null; - private languageService: TypeScript.Services.ILanguageService = null; - private newLanguageService: ts.LanguageService = null; + public languageServiceShimHost: Harness.LanguageService.TypeScriptLS; + private languageService: ts.LanguageService; // A reference to the language service's compiler state's compiler instance private compiler: () => { getSyntaxTree(fileName: string): TypeScript.SyntaxTree; getSourceUnit(fileName: string): TypeScript.SourceUnitSyntax; }; @@ -189,7 +189,7 @@ module FourSlash { // Whether or not we should format on keystrokes public enableFormatting = true; - public formatCodeOptions: TypeScript.Services.FormatCodeOptions = null; + public formatCodeOptions: ts.FormatCodeOptions; public cancellationToken: TestCancellationToken; @@ -202,7 +202,7 @@ module FourSlash { constructor(public testData: FourSlashData) { // Initialize the language service with all the scripts this.cancellationToken = new TestCancellationToken(); - this.languageServiceShimHost = new Harness.TypeScriptLS(this.cancellationToken); + this.languageServiceShimHost = new Harness.LanguageService.TypeScriptLS(this.cancellationToken); var harnessCompiler = Harness.Compiler.getCompiler(); var inputFiles: { unitName: string; content: string }[] = []; @@ -226,40 +226,48 @@ module FourSlash { }); } - // NEWTODO: Re-implement commented-out section - // harnessCompiler.addInputFiles(inputFiles); - try { - // var resolvedFiles = harnessCompiler.resolve(); + // NEWTODO: Re-implement commented-out section + //harnessCompiler.addInputFiles(inputFiles); + //try { + // var resolvedFiles = harnessCompiler.resolve(); - //resolvedFiles.forEach(file => { - // if (!Harness.isLibraryFile(file.path)) { - // var fixedPath = file.path.substr(file.path.indexOf('tests/')); - // var content = harnessCompiler.getContentForFile(fixedPath); - // this.languageServiceShimHost.addScript(fixedPath, content); - // } - //}); + // resolvedFiles.forEach(file => { + // if (!Harness.isLibraryFile(file.path)) { + // var fixedPath = file.path.substr(file.path.indexOf('tests/')); + // var content = harnessCompiler.getContentForFile(fixedPath); + // this.languageServiceShimHost.addScript(fixedPath, content); + // } + // }); - // NEWTODO: For now do not resolve, just use the input files - inputFiles.forEach(file => { - if (!Harness.isLibraryFile(file.unitName)) { - this.languageServiceShimHost.addScript(file.unitName, file.content); - } - }); + // this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); + //} + //finally { + // // harness no longer needs the results of the above work, make sure the next test operations are in a clean state + // harnessCompiler.reset(); + //} - this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); - } - finally { - // harness no longer needs the results of the above work, make sure the next test operations are in a clean state - //harnessCompiler.reset(); - } + /// NEWTODO: For now do not resolve, just use the input files inputFiles.forEach(file => { if (!Harness.isLibraryFile(file.unitName)) { this.languageServiceShimHost.addScript(file.unitName, file.content); } }); + this.languageServiceShimHost.addScript('lib.d.ts', Harness.Compiler.libTextMinimal); // Sneak into the language service and get its compiler so we can examine the syntax trees this.languageService = this.languageServiceShimHost.getLanguageService().languageService; - this.newLanguageService = this.languageServiceShimHost.newLS; var compilerState = (this.languageService).compiler; this.compiler = () => compilerState.compiler; - this.formatCodeOptions = new TypeScript.Services.FormatCodeOptions(); + this.formatCodeOptions = { + IndentSize: 4, + TabSize: 4, + NewLineCharacter: sys.newLine, + ConvertTabsToSpaces: true, + InsertSpaceAfterCommaDelimiter: true, + InsertSpaceAfterSemicolonInForStatements: true, + InsertSpaceBeforeAndAfterBinaryOperators: true, + InsertSpaceAfterKeywordsInControlFlowStatements: true, + InsertSpaceAfterFunctionKeywordForAnonymousFunctions: false, + InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, + PlaceOpenBraceOnNewLineForFunctions: false, + PlaceOpenBraceOnNewLineForControlBlocks: false, + }; this.testData.files.forEach(file => { var filename = file.fileName.replace(Harness.IO.directoryName(file.fileName), '').substr(1); @@ -308,7 +316,7 @@ module FourSlash { public openFile(name: string): void; public openFile(indexOrName: any) { var fileToOpen: FourSlashFile = this.findFile(indexOrName); - fileToOpen.fileName = Harness.Path.switchToForwardSlashes(fileToOpen.fileName); + fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName); this.activeFile = fileToOpen; var filename = fileToOpen.fileName.replace(Harness.IO.directoryName(fileToOpen.fileName), '').substr(1); this.scenarioActions.push(''); @@ -318,9 +326,7 @@ module FourSlash { var startMarker = this.getMarkerByName(startMarkerName); var endMarker = this.getMarkerByName(endMarkerName); var predicate = function (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) { - // NEWTODO: make this more specific again - //return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; - return ((errorMinChar >= startPos) && (errorLimChar <= endPos)) ? true : false; + return ((errorMinChar === startPos) && (errorLimChar === endPos)) ? true : false; }; var exists = this.anyErrorInRange(predicate, startMarker, endMarker); @@ -328,28 +334,15 @@ module FourSlash { this.taoInvalidReason = 'verifyErrorExistsBetweenMarkers NYI'; if (exists !== negative) { - this.new_printErrorLog(negative, this.new_getAllDiagnostics()); + this.printErrorLog(negative, this.getAllDiagnostics()); throw new Error("Failure between markers: " + startMarkerName + ", " + endMarkerName); } } - private getDiagnostics(fileName: string): TypeScript.Diagnostic[] { + private getDiagnostics(fileName: string): ts.Diagnostic[] { var syntacticErrors = this.languageService.getSyntacticDiagnostics(fileName); var semanticErrors = this.languageService.getSemanticDiagnostics(fileName); - var diagnostics: TypeScript.Diagnostic[] = []; - diagnostics.push.apply(diagnostics, syntacticErrors); - diagnostics.push.apply(diagnostics, semanticErrors); - - return diagnostics; - } - - - private new_getDiagnostics(fileName: string): ts.Diagnostic[] { - var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(fileName); - var semanticErrors = this.newLanguageService.getSemanticDiagnostics(fileName); - - var diagnostics: ts.Diagnostic[] = []; diagnostics.push.apply(diagnostics, syntacticErrors); diagnostics.push.apply(diagnostics, semanticErrors); @@ -357,9 +350,8 @@ module FourSlash { return diagnostics; } - - private getAllDiagnostics(): TypeScript.Diagnostic[] { - var diagnostics: TypeScript.Diagnostic[] = []; + private getAllDiagnostics(): ts.Diagnostic[] { + var diagnostics: ts.Diagnostic[] = []; var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames()); for (var i = 0, n = fileNames.length; i < n; i++) { @@ -369,17 +361,6 @@ module FourSlash { return diagnostics; } - private new_getAllDiagnostics(): ts.Diagnostic[] { - var diagnostics: ts.Diagnostic[] = []; - - var fileNames = JSON.parse(this.languageServiceShimHost.getScriptFileNames()); - for (var i = 0, n = fileNames.length; i < n; i++) { - diagnostics.push.apply(this.new_getDiagnostics(fileNames[i])); - } - - return diagnostics; - } - public verifyErrorExistsAfterMarker(markerName: string, negative: boolean, after: boolean) { var marker: Marker = this.getMarkerByName(markerName); var predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean; @@ -397,17 +378,17 @@ module FourSlash { this.taoInvalidReason = 'verifyErrorExistsAfterMarker NYI'; var exists = this.anyErrorInRange(predicate, marker); - var diagnostics = this.new_getAllDiagnostics(); + var diagnostics = this.getAllDiagnostics(); if (exists !== negative) { - this.new_printErrorLog(negative, diagnostics); + this.printErrorLog(negative, diagnostics); throw new Error("Failure at marker: " + markerName); } } private anyErrorInRange(predicate: (errorMinChar: number, errorLimChar: number, startPos: number, endPos: number) => boolean, startMarker: Marker, endMarker?: Marker) { - var errors = this.new_getDiagnostics(startMarker.fileName); + var errors = this.getDiagnostics(startMarker.fileName); var exists = false; var startPos = startMarker.position; @@ -415,7 +396,7 @@ module FourSlash { var endPos = endMarker.position; } - errors.forEach((error)=> { + errors.forEach(function (error: ts.Diagnostic) { if (predicate(error.start, error.start + error.length, startPos, endPos)) { exists = true; } @@ -424,26 +405,14 @@ module FourSlash { return exists; } - private printErrorLog(expectErrors: boolean, errors: TypeScript.Diagnostic[]) { + private printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) { if (expectErrors) { Harness.IO.log("Expected error not found. Error list is:"); } else { Harness.IO.log("Unexpected error(s) found. Error list is:"); } - errors.forEach(function (error: TypeScript.Diagnostic) { - Harness.IO.log(" minChar: " + error.start() + ", limChar: " + (error.start() + error.length()) + ", message: " + error.message() + "\n"); - }); - } - - private new_printErrorLog(expectErrors: boolean, errors: ts.Diagnostic[]) { - if (expectErrors) { - Harness.IO.log("Expected error not found. Error list is:"); - } else { - Harness.IO.log("Unexpected error(s) found. Error list is:"); - } - - errors.forEach(error => { + errors.forEach(function (error: ts.Diagnostic) { Harness.IO.log(" minChar: " + error.start + ", limChar: " + (error.start + error.length) + ", message: " + error.messageText + "\n"); }); } @@ -754,22 +723,22 @@ module FourSlash { this.taoInvalidReason = 'verifyCurrentSignatureHelpIs NYI'; var help = this.getActiveSignatureHelp(); - assert.equal(help.prefix + help.parameters.map(p => p.display).join(help.separator) + help.suffix, expected); + assert.equal(help.signatureInfo, expected); } public verifyCurrentParameterIsVariable(isVariable: boolean) { this.taoInvalidReason = 'verifyCurrentParameterIsVariable NYI'; - var signature = this.getActiveSignatureHelp(); - assert.isNotNull(signature); - assert.equal(isVariable, signature.isVariadic); + var activeParameter = this.getActiveParameter(); + assert.isNotNull(activeParameter.parameter); + assert.equal(isVariable, activeParameter.parameter.isVariable); } public verifyCurrentParameterHelpName(name: string) { this.taoInvalidReason = 'verifyCurrentParameterHelpName NYI'; var activeParameter = this.getActiveParameter(); - var activeParameterName = activeParameter.name; + var activeParameterName = activeParameter.parameter ? activeParameter.parameter.name : activeParameter.typeParameter.name; assert.equal(activeParameterName, name); } @@ -778,14 +747,16 @@ module FourSlash { var activeSignature = this.getActiveSignatureHelp(); var activeParameter = this.getActiveParameter(); - assert.equal(activeParameter.display, parameter); + var activeParameterMinChar = activeParameter.parameter ? activeParameter.parameter.minChar : activeParameter.typeParameter.minChar; + var activeParameterLimChar = activeParameter.parameter ? activeParameter.parameter.limChar : activeParameter.typeParameter.limChar; + assert.equal(activeSignature.signatureInfo.substring(activeParameterMinChar, activeParameterLimChar), parameter); } public verifyCurrentParameterHelpDocComment(docComment: string) { this.taoInvalidReason = 'verifyCurrentParameterHelpDocComment NYI'; var activeParameter = this.getActiveParameter(); - var activeParameterDocComment = activeParameter.documentation; + var activeParameterDocComment = activeParameter.parameter ? activeParameter.parameter.docComment : activeParameter.typeParameter.docComment; assert.equal(activeParameterDocComment, docComment); } @@ -798,13 +769,13 @@ module FourSlash { public verifyCurrentSignatureHelpTypeParameterCount(expectedCount: number) { this.taoInvalidReason = 'verifyCurrentSignatureHelpTypeParameterCount NYI'; - // assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount); + assert.equal(this.getActiveSignatureHelp().typeParameters.length, expectedCount); } public verifyCurrentSignatureHelpDocComment(docComment: string) { this.taoInvalidReason = 'verifyCurrentSignatureHelpDocComment NYI'; - var actualDocComment = this.getActiveSignatureHelp().documentation; + var actualDocComment = this.getActiveSignatureHelp().docComment; assert.equal(actualDocComment, docComment); } @@ -812,15 +783,15 @@ module FourSlash { this.scenarioActions.push(''); this.scenarioActions.push(''); - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - var actual = help && help.items ? help.items.length : 0; + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var actual = help && help.formal ? help.formal.length : 0; assert.equal(actual, expected); } public verifySignatureHelpPresent(shouldBePresent = true) { this.taoInvalidReason = 'verifySignatureHelpPresent NYI'; - var actual = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var actual = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (shouldBePresent) { if (!actual) { throw new Error("Expected signature help to be present, but it wasn't"); @@ -832,32 +803,45 @@ module FourSlash { } } - //private getFormalParameter() { - // var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - // return help.formal; - //} + private getFormalParameter() { + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + return help.formal; + } private getActiveSignatureHelp() { - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); + var activeFormal = help.activeFormal; // If the signature hasn't been narrowed down yet (e.g. no parameters have yet been entered), // 'activeFormal' will be -1 (even if there is only 1 signature). Signature help will show the // first signature in the signature group, so go with that - var index = help.selectedItemIndex < 0 ? 0 : help.selectedItemIndex; + if (activeFormal === -1) { + activeFormal = 0; + } - return help.items[index]; + return help.formal[activeFormal]; } - private getActiveParameter(): TypeScript.Services.SignatureHelpParameter { + private getActiveParameter(): { parameter: ts.FormalParameterInfo; typeParameter: ts.FormalTypeParameterInfo; } { var currentSig = this.getActiveSignatureHelp(); - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); - - var item = help.items[help.selectedItemIndex]; - var state = this.languageService.getSignatureHelpCurrentArgumentState(this.activeFile.fileName, this.currentCaretPosition, help.applicableSpan.start()); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); // Same logic as in getActiveSignatureHelp - this value might be -1 until a parameter value actually gets typed - var currentParam = state === null ? 0 : state.argumentIndex; - return item.parameters[currentParam]; + var currentParam = help.actual.currentParameter; + if (currentParam === -1) currentParam = 0; + + if (help.actual.currentParameterIsTypeParameter) { + return { + parameter: null, + typeParameter: currentSig.typeParameters[currentParam] + }; + } + else { + return { + parameter: currentSig.parameters[currentParam], + typeParameter: null + }; + } } public getBreakpointStatementLocation(pos: number) { @@ -866,7 +850,7 @@ module FourSlash { var spanInfo = this.languageService.getBreakpointStatementAtPosition(this.activeFile.fileName, pos); var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: "; if (spanInfo !== null) { - resultString = resultString + this.activeFile.content.substr(spanInfo.start(), spanInfo.length()); + resultString = resultString + this.activeFile.content.substr(spanInfo.minChar, spanInfo.limChar - spanInfo.minChar); } return resultString; } @@ -884,7 +868,8 @@ module FourSlash { resultString = resultString + this.getBreakpointStatementLocation(pos); } return resultString; - }); + }, + true /* run immediately */); } public printBreakpointLocation(pos: number) { @@ -896,7 +881,7 @@ module FourSlash { } public printCurrentParameterHelp() { - var help = this.languageService.getSignatureHelpItems(this.activeFile.fileName, this.currentCaretPosition); + var help = this.languageService.getSignatureAtPosition(this.activeFile.fileName, this.currentCaretPosition); Harness.IO.log(JSON.stringify(help)); } @@ -906,10 +891,6 @@ module FourSlash { } public printErrorList() { - Harness.IO.log("--------------"); - Harness.IO.log("Old Errors"); - Harness.IO.log("--------------"); - var syntacticErrors = this.languageService.getSyntacticDiagnostics(this.activeFile.fileName); var semanticErrors = this.languageService.getSemanticDiagnostics(this.activeFile.fileName); var errorList = syntacticErrors.concat(semanticErrors); @@ -917,27 +898,7 @@ module FourSlash { if (errorList.length) { errorList.forEach(err => { - Harness.IO.log("start: " + err.start() + ", length: " + err.length() + ", message: " + err.message()); - }); - } - - Harness.IO.log("--------------"); - Harness.IO.log("New Errors"); - Harness.IO.log("--------------"); - this.new_printErrorList(); - } - - public new_printErrorList() { - var syntacticErrors = this.newLanguageService.getSyntacticDiagnostics(this.activeFile.fileName); - var semanticErrors = this.newLanguageService.getSemanticDiagnostics(this.activeFile.fileName); - var errorList = syntacticErrors.concat(semanticErrors); - Harness.IO.log('Error list (' + errorList.length + ' errors)'); - - - if (errorList.length) { - errorList.forEach(error => { - Harness.IO.log("start: " + error.start + ", length: " + error.length + - ", message: " + error.messageText); + Harness.IO.log("start: " + err.start + ", length: " + err.length + ", message: " + err.messageText); }); } } @@ -1100,10 +1061,10 @@ module FourSlash { offset++; if (ch === '(' || ch === ',') { - // Signature help - this.languageService.getSignatureHelpItems(this.activeFile.fileName, offset); + /* Signature help*/ + this.languageService.getSignatureAtPosition(this.activeFile.fileName, offset); } else if (prevChar === ' ' && /A-Za-z_/.test(ch)) { - // Completions + /* Completions */ this.languageService.getCompletionsAtPosition(this.activeFile.fileName, offset, false); } @@ -1141,7 +1102,7 @@ module FourSlash { // Handle formatting if (this.enableFormatting) { - var edits = this.languageService.getFormattingEditsForRange(this.activeFile.fileName, start, offset, this.formatCodeOptions); + var edits = this.languageService.getFormattingEditsOnPaste(this.activeFile.fileName, start, offset, this.formatCodeOptions); offset += this.applyEdits(this.activeFile.fileName, edits, true); this.editCheckpoint(this.activeFile.fileName); } @@ -1154,46 +1115,44 @@ module FourSlash { } private checkPostEditInvariants() { - if (this.editValidation === IncrementalEditValidation.None) { - return; - } + return; - // Get syntactic errors (to force a refresh) - var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName)); + /// TODO: reimplement this section + //if (this.editValidation === IncrementalEditValidation.None) { + // return; + //} - // Check syntactic structure - var compilationSettings = new TypeScript.CompilationSettings(); - compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; - var immutableSettings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings); + //// Get syntactic errors (to force a refresh) + //var incrSyntaxErrs = JSON.stringify(this.languageService.getSyntacticDiagnostics(this.activeFile.fileName)); - var parseOptions = immutableSettings.codeGenTarget(); - var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); - var content = snapshot.getText(0, snapshot.getLength()); - var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), parseOptions, TypeScript.isDTSFile(this.activeFile.fileName)); - var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics()); + //// Check syntactic structure + //var snapshot = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName); + //var content = snapshot.getText(0, snapshot.getLength()); + //var refSyntaxTree = TypeScript.Parser.parse(this.activeFile.fileName, TypeScript.SimpleText.fromString(content), ts.ScriptTarget.ES5, TypeScript.isDTSFile(this.activeFile.fileName)); + //var fullSyntaxErrs = JSON.stringify(refSyntaxTree.diagnostics()); - if (incrSyntaxErrs !== fullSyntaxErrs) { - throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); - } + //if (incrSyntaxErrs !== fullSyntaxErrs) { + // throw new Error('Mismatched incremental/full syntactic errors for file ' + this.activeFile.fileName + '.\n=== Incremental errors ===\n' + incrSyntaxErrs + '\n=== Full Errors ===\n' + fullSyntaxErrs); + //} - if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { - var compiler = new TypeScript.TypeScriptCompiler(); - for (var i = 0; i < this.testData.files.length; i++) { - snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); - compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), TypeScript.ByteOrderMark.None, "0", true); - } + // if (this.editValidation !== IncrementalEditValidation.SyntacticOnly) { + // var compiler = new TypeScript.TypeScriptCompiler(); + // for (var i = 0; i < this.testData.files.length; i++) { + // snapshot = this.languageServiceShimHost.getScriptSnapshot(this.testData.files[i].fileName); + // compiler.addFile(this.testData.files[i].fileName, TypeScript.ScriptSnapshot.fromString(snapshot.getText(0, snapshot.getLength())), ts.ByteOrderMark.None, 0, true); + // } - compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), TypeScript.ByteOrderMark.None, "0", true); + // compiler.addFile('lib.d.ts', TypeScript.ScriptSnapshot.fromString(Harness.Compiler.libTextMinimal), ts.ByteOrderMark.None, 0, true); - for (var i = 0; i < this.testData.files.length; i++) { - var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); - var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); + // for (var i = 0; i < this.testData.files.length; i++) { + // var refSemanticErrs = JSON.stringify(compiler.getSemanticDiagnostics(this.testData.files[i].fileName)); + // var incrSemanticErrs = JSON.stringify(this.languageService.getSemanticDiagnostics(this.testData.files[i].fileName)); - if (incrSemanticErrs !== refSemanticErrs) { - throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); - } - } - } + // if (incrSemanticErrs !== refSemanticErrs) { + // throw new Error('Mismatched incremental/full semantic errors for file ' + this.testData.files[i].fileName + '\n=== Incremental errors ===\n' + incrSemanticErrs + '\n=== Full Errors ===\n' + refSemanticErrs); + // } + // } + // } } private fixCaretPosition() { @@ -1207,18 +1166,18 @@ module FourSlash { }; } - private applyEdits(fileName: string, edits: TypeScript.Services.TextChange[], isFormattingEdit = false): number { + private applyEdits(fileName: string, edits: ts.TextEdit[], isFormattingEdit = false): number { // We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track // of the incremental offest from each edit to the next. Assumption is that these edit ranges don't overlap var runningOffset = 0; - edits = edits.sort((a, b) => a.span.start() - b.span.start()); + edits = edits.sort((a, b) => a.minChar - b.minChar); // Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters var snapshot = this.languageServiceShimHost.getScriptSnapshot(fileName); var oldContent = snapshot.getText(0, snapshot.getLength()); for (var j = 0; j < edits.length; j++) { - this.languageServiceShimHost.editScript(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - this.updateMarkersForEdit(fileName, edits[j].span.start() + runningOffset, edits[j].span.end() + runningOffset, edits[j].newText); - var change = (edits[j].span.start() - edits[j].span.end()) + edits[j].newText.length; + this.languageServiceShimHost.editScript(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text); + this.updateMarkersForEdit(fileName, edits[j].minChar + runningOffset, edits[j].limChar + runningOffset, edits[j].text); + var change = (edits[j].minChar - edits[j].limChar) + edits[j].text.length; runningOffset += change; // TODO: Consider doing this at least some of the time for higher fidelity. Currently causes a failure (bug 707150) // this.languageService.getScriptLexicalStructure(fileName); @@ -1238,7 +1197,7 @@ module FourSlash { public formatDocument() { this.scenarioActions.push(''); - var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, this.formatCodeOptions); + var edits = this.languageService.getFormattingEditsForDocument(this.activeFile.fileName, 0, this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength(), this.formatCodeOptions); this.currentCaretPosition += this.applyEdits(this.activeFile.fileName, edits, true); this.fixCaretPosition(); } @@ -1295,7 +1254,7 @@ module FourSlash { var definition = definitions[definitionIndex]; this.openFile(definition.fileName); - this.currentCaretPosition = definition.textSpan.start(); + this.currentCaretPosition = definition.minChar; } public verifyDefinitionLocationExists(negative: boolean) { @@ -1331,7 +1290,7 @@ module FourSlash { throw new Error('verifyCaretAtMarker failed - expected to be in file "' + pos.fileName + '", but was in file "' + this.activeFile.fileName + '"'); } if (pos.position !== this.currentCaretPosition) { - throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*' + '/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')'); + throw new Error('verifyCaretAtMarker failed - expected to be at marker "/*' + markerName + '*/, but was at position ' + this.currentCaretPosition + '(' + this.getLineColStringAtCaret() + ')'); } } @@ -1401,7 +1360,7 @@ module FourSlash { '\t Actual: null'); } - var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.start(), span.end()); + var actual = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(span.minChar, span.limChar); if (actual !== text) { throw new Error('verifyCurrentNameOrDottedNameSpanText\n' + '\tExpected: "' + text + '"\n' + @@ -1413,7 +1372,7 @@ module FourSlash { var spanInfo = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, pos, pos); var resultString = "\n**Pos: " + pos + " SpanInfo: " + JSON.stringify(spanInfo) + "\n** Statement: "; if (spanInfo !== null) { - resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.start(), spanInfo.end()); + resultString = resultString + this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getText(spanInfo.minChar, spanInfo.limChar); } return resultString; } @@ -1431,7 +1390,8 @@ module FourSlash { resultString = resultString + this.getNameOrDottedNameSpan(pos); } return resultString; - }); + }, + true /* run immediately */); } public printNameOrDottedNameSpans(pos: number) { @@ -1441,7 +1401,7 @@ module FourSlash { public verifyOutliningSpans(spans: TextSpan[]) { this.taoInvalidReason = 'verifyOutliningSpans NYI'; - var actual = this.languageService.getOutliningSpans(this.activeFile.fileName); + var actual = this.languageService.getOutliningRegions(this.activeFile.fileName); if (actual.length !== spans.length) { throw new Error('verifyOutliningSpans failed - expected total spans to be ' + spans.length + ', but was ' + actual.length); @@ -1450,27 +1410,8 @@ module FourSlash { for (var i = 0; i < spans.length; i++) { var expectedSpan = spans[i]; var actualSpan = actual[i]; - if (expectedSpan.start !== actualSpan.textSpan.start() || expectedSpan.end !== actualSpan.textSpan.end()) { - throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.textSpan.start() + ',' + actualSpan.textSpan.end() + ')'); - } - } - } - - public verifyTodoComments(descriptors: string[], spans: TextSpan[]) { - var actual = this.languageService.getTodoComments(this.activeFile.fileName, - descriptors.map(d => new TypeScript.Services.TodoCommentDescriptor(d, 0))); - - if (actual.length !== spans.length) { - throw new Error('verifyTodoComments failed - expected total spans to be ' + spans.length + ', but was ' + actual.length); - } - - for (var i = 0; i < spans.length; i++) { - var expectedSpan = spans[i]; - var actualComment = actual[i]; - var actualCommentSpan = new TypeScript.TextSpan(actualComment.position, actualComment.message.length); - - if (expectedSpan.start !== actualCommentSpan.start() || expectedSpan.end !== actualCommentSpan.end()) { - throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualCommentSpan.start() + ',' + actualCommentSpan.end() + ')'); + if (expectedSpan.start !== actualSpan.start() || expectedSpan.end !== actualSpan.end()) { + throw new Error('verifyOutliningSpans failed - span ' + (i + 1) + ' expected: (' + expectedSpan.start + ',' + expectedSpan.end + '), actual: (' + actualSpan.start() + ',' + actualSpan.end() + ')'); } } } @@ -1485,9 +1426,9 @@ module FourSlash { } var actualMatchPosition = -1; - if (bracePosition == actual[0].start()) { + if (bracePosition >= actual[0].start() && bracePosition <= actual[0].end()) { actualMatchPosition = actual[1].start(); - } else if (bracePosition == actual[1].start()) { + } else if (bracePosition >= actual[1].start() && bracePosition <= actual[1].end()) { actualMatchPosition = actual[0].start(); } else { throw new Error('verifyMatchingBracePosition failed - could not find the brace position: ' + bracePosition + ' in the returned list: (' + actual[0].start() + ',' + actual[0].end() + ') and (' + actual[1].start() + ',' + actual[1].end() + ')'); @@ -1512,7 +1453,7 @@ module FourSlash { this.taoInvalidReason = 'verifyTypesAgainstFullCheckAtPositions impossible'; // Create a from-scratch LS to check against - var referenceLanguageServiceShimHost = new Harness.TypeScriptLS(); + var referenceLanguageServiceShimHost = new Harness.LanguageService.TypeScriptLS(); var referenceLanguageServiceShim = referenceLanguageServiceShimHost.getLanguageService(); var referenceLanguageService = referenceLanguageServiceShim.languageService; @@ -1528,7 +1469,7 @@ module FourSlash { } for (i = 0; i < positions.length; i++) { - var nameOf = (type: TypeScript.Services.TypeInfo) => type ? type.fullSymbolName : '(none)'; + var nameOf = (type: ts.TypeInfo) => type ? type.fullSymbolName : '(none)'; var pullName: string, refName: string; var anyFailed = false; @@ -1571,14 +1512,16 @@ module FourSlash { } } - /// Check number of navigationItems which match both searchValue and matchKind. - /// Report an error if expected value and actual value do not match. + /* + Check number of navigationItems which match both searchValue and matchKind. + Report an error if expected value and actual value do not match. + */ public verifyNavigationItemsCount(expected: number, searchValue: string, matchKind?: string) { this.taoInvalidReason = 'verifyNavigationItemsCount NYI'; var items = this.languageService.getNavigateToItems(searchValue); var actual = 0; - var item: TypeScript.Services.NavigateToItem = null; + var item: ts.NavigateToItem = null; // Count only the match that match the same MatchKind for (var i = 0; i < items.length; ++i) { @@ -1593,8 +1536,10 @@ module FourSlash { } } - /// Verify that returned navigationItems from getNavigateToItems have matched searchValue, matchKind, and kind. - /// Report an error if getNavigateToItems does not find any matched searchValue. + /* + Verify that returned navigationItems from getNavigateToItems have matched searchValue, matchKind, and kind. + Report an error if getNavigateToItems does not find any matched searchValue. + */ public verifyNavigationItemsListContains( name: string, kind: string, @@ -1630,61 +1575,70 @@ module FourSlash { public verifyGetScriptLexicalStructureListCount(expected: number) { this.taoInvalidReason = 'verifyNavigationItemsListContains impossible'; - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); - var actual = this.getNavigationBarItemsCount(items); - + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); + var actual = (items && items.length) || 0; if (expected != actual) { throw new Error('verifyGetScriptLexicalStructureListCount failed - found: ' + actual + ' navigation items, expected: ' + expected + '.'); } } - private getNavigationBarItemsCount(items: TypeScript.Services.NavigationBarItem[]) { - var result = 0; - if (items) { - for (var i = 0, n = items.length; i < n; i++) { - result++; - result += this.getNavigationBarItemsCount(items[i].childItems); - } - } - - return result; - } - public verifGetScriptLexicalStructureListContains( name: string, kind: string, + fileName?: string, + parentName?: string, + isAdditionalSpan?: boolean, markerPosition?: number) { this.taoInvalidReason = 'verifGetScriptLexicalStructureListContains impossible'; - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); if (!items || items.length === 0) { throw new Error('verifyGetScriptLexicalStructureListContains failed - found 0 navigation items, expected at least one.'); } - if (this.navigationBarItemsContains(items, name, kind)) { - return; - } - - var missingItem = { name: name, kind: kind }; - throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')'); - } - - private navigationBarItemsContains(items: TypeScript.Services.NavigationBarItem[], name: string, kind: string) { - if (items) { - for (var i = 0; i < items.length; i++) { - var item = items[i]; - if (item && item.text === name && item.kind === kind) { - return true; + for (var i = 0; i < items.length; i++) { + var item = items[i]; + if (item && item.name === name && item.kind === kind && + (fileName === undefined || item.fileName === fileName) && + (parentName === undefined || item.containerName === parentName)) { + if (markerPosition !== undefined || isAdditionalSpan !== undefined) { + if (isAdditionalSpan) { + if (item.additionalSpans && + item.additionalSpans.some(span => span.minChar <= markerPosition && markerPosition <= span.limChar)) { + // marker is in an additional span for this item. + return; + } + else { + throw new Error( + 'verifGetScriptLexicalStructureListContains failed - ' + + 'no additional span was found that contained the position: ' + JSON.stringify(markerPosition) + + ' in the item: ' + JSON.stringify(item)); + } + } + else if (!isAdditionalSpan) { + if (item.minChar <= markerPosition && + markerPosition <= item.minChar) { + // marker is in span normal item's span + return; + } + else { + throw new Error( + 'verifGetScriptLexicalStructureListContains failed - ' + + 'marker was positioned: ' + JSON.stringify(markerPosition) + + ' which is not in the item: ' + JSON.stringify(item)); + } + } } - - if (this.navigationBarItemsContains(item.childItems, name, kind)) { - return true; + else { + return; } } } - return false; + + var missingItem = { name: name, kind: kind, fileName: fileName, parentName: parentName }; + throw new Error('verifyGetScriptLexicalStructureListContains failed - could not find the item: ' + JSON.stringify(missingItem) + ' in the returned list: (' + JSON.stringify(items) + ')'); } public printNavigationItems(searchValue: string) { @@ -1700,14 +1654,14 @@ module FourSlash { } public printScriptLexicalStructureItems() { - var items = this.languageService.getNavigationBarItems(this.activeFile.fileName); + var items = this.languageService.getScriptLexicalStructure(this.activeFile.fileName); var length = items && items.length; Harness.IO.log('NavigationItems list (' + length + ' items)'); for (var i = 0; i < length; i++) { var item = items[i]; - Harness.IO.log('name: ' + item.text + ', kind: ' + item.kind); + Harness.IO.log('name: ' + item.name + ', kind: ' + item.kind + ', parentName: ' + item.containerName + ', fileName: ' + item.fileName); } } @@ -1726,7 +1680,7 @@ module FourSlash { for (var i = 0; i < occurances.length; i++) { var occurance = occurances[i]; - if (occurance && occurance.fileName === fileName && occurance.textSpan.start() === start && occurance.textSpan.end() === end) { + if (occurance && occurance.fileName === fileName && occurance.minChar === start && occurance.limChar === end) { if (typeof isWriteAccess !== "undefined" && occurance.isWriteAccess !== isWriteAccess) { throw new Error('verifyOccurancesAtPositionListContains failed - item isWriteAccess value doe not match, actual: ' + occurance.isWriteAccess + ', expected: ' + isWriteAccess + '.'); } @@ -1798,7 +1752,7 @@ module FourSlash { return result; } - private assertItemInCompletionList(items: TypeScript.Services.CompletionEntry[], name: string, type?: string, docComment?: string, fullSymbolName?: string, kind?: string) { + private assertItemInCompletionList(items: ts.CompletionEntry[], name: string, type?: string, docComment?: string, fullSymbolName?: string, kind?: string) { this.scenarioActions.push(''); this.scenarioActions.push(''); diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index c9075949dd6..e3646b98e03 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -1,10 +1,13 @@ -module Harness.LanguageService { +/// +/// + +module Harness.LanguageService { export class ScriptInfo { public version: number = 1; public editRanges: { length: number; textChangeRange: TypeScript.TextChangeRange; }[] = []; public lineMap: TypeScript.LineMap = null; - constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: TypeScript.ByteOrderMark = TypeScript.ByteOrderMark.None) { + constructor(public fileName: string, public content: string, public isOpen = true, public byteOrderMark: ts.ByteOrderMark = ts.ByteOrderMark.None) { this.setContent(content); } @@ -51,7 +54,7 @@ } } - class ScriptSnapshotShim implements TypeScript.Services.IScriptSnapshotShim { + class ScriptSnapshotShim implements ts.ScriptSnapshotShim { private lineMap: TypeScript.LineMap = null; private textSnapshot: string; private version: number; @@ -77,9 +80,8 @@ return JSON.stringify(this.lineMap.lineStarts()); } - public getChangeRange(oldScript: TypeScript.Services.IScriptSnapshotShim): string { - var oldShim = oldScript; - var range = this.scriptInfo.getTextChangeRangeBetweenVersions(oldShim.version, this.version); + public getTextChangeRangeSinceVersion(scriptVersion: number): string { + var range = this.scriptInfo.getTextChangeRangeBetweenVersions(scriptVersion, this.version); if (range === null) { return null; } @@ -88,14 +90,91 @@ } } - export class TypeScriptLS implements TypeScript.Services.ILanguageServiceShimHost { - IO = TypeScript.Environment ? TypeScript.Environment : Network.getEnvironment(); - private ls: TypeScript.Services.ILanguageServiceShim = null; + class CancellationToken { + public static None: CancellationToken = new CancellationToken(null) + + constructor(private cancellationToken: ts.CancellationToken) { + } + + public isCancellationRequested() { + return this.cancellationToken && this.cancellationToken.isCancellationRequested(); + } + } + + class ScriptSnapshotShimAdapter implements TypeScript.IScriptSnapshot { + private lineStartPositions: number[] = null; + constructor(private scriptSnapshotShim: ts.ScriptSnapshotShim) {} + getText(start: number, end: number): string {return this.scriptSnapshotShim.getText(start, end);} + getLength(): number {return this.scriptSnapshotShim.getLength();} + getLineStartPositions(): number[] { return JSON.parse(this.scriptSnapshotShim.getLineStartPositions()); } + getTextChangeRangeSinceVersion(scriptVersion: number): TypeScript.TextChangeRange { + var encoded = this.scriptSnapshotShim.getTextChangeRangeSinceVersion(scriptVersion); + if (encoded == null) { + return null; + } + + var decoded: { span: { start: number; length: number; }; newLength: number; } = JSON.parse(encoded); + return new TypeScript.TextChangeRange( + new TypeScript.TextSpan(decoded.span.start, decoded.span.length), decoded.newLength); + } + } + + class LanguageServiceShimHostAdapter implements ts.LanguageServiceHost { + constructor(private shimHost: ts.LanguageServiceShimHost) { } + information(): boolean { return this.shimHost.information(); } + debug(): boolean { return this.shimHost.debug(); } + warning(): boolean { return this.shimHost.warning();} + error(): boolean { return this.shimHost.error(); } + fatal(): boolean { return this.shimHost.fatal(); } + log(s: string): void { this.shimHost.log(s); } + getCompilationSettings(): ts.CompilerOptions { return JSON.parse(this.shimHost.getCompilationSettings()); } + getScriptFileNames(): string[] { return JSON.parse(this.shimHost.getScriptFileNames());} + getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot { return new ScriptSnapshotShimAdapter(this.shimHost.getScriptSnapshot(fileName));} + getScriptVersion(fileName: string): number { return this.shimHost.getScriptVersion(fileName);} + getScriptIsOpen(fileName: string): boolean { return this.shimHost.getScriptIsOpen(fileName); } + getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.shimHost.getScriptByteOrderMark(fileName);} + getLocalizedDiagnosticMessages(): any { JSON.parse(this.shimHost.getLocalizedDiagnosticMessages());} + getCancellationToken(): ts.CancellationToken { return this.shimHost.getCancellationToken(); } + } + + export class NonCachingDocumentRegistry implements ts.DocumentRegistry { + + public static Instance: ts.DocumentRegistry = new NonCachingDocumentRegistry(); + + public acquireDocument( + fileName: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: TypeScript.IScriptSnapshot, + byteOrderMark: ts.ByteOrderMark, + version: number, + isOpen: boolean, + referencedFiles: string[]= []): ts.Document { + return ts.createDocument(compilationSettings, fileName, scriptSnapshot, byteOrderMark, version, isOpen, referencedFiles); + } + + public updateDocument( + document: ts.Document, + fileName: string, + compilationSettings: ts.CompilerOptions, + scriptSnapshot: TypeScript.IScriptSnapshot, + version: number, + isOpen: boolean, + textChangeRange: TypeScript.TextChangeRange + ): ts.Document { + return document.update(scriptSnapshot, version, isOpen, textChangeRange); + } + + public releaseDocument(fileName: string, compilationSettings: ts.CompilerOptions): void { + // no op since this class doesn't cache anything + } + } + export class TypeScriptLS implements ts.LanguageServiceShimHost { + private ls: ts.LanguageServiceShim = null; public newLS: ts.LanguageService; - private fileNameToScript = new TypeScript.StringHashTable(); + private fileNameToScript: ts.Map = {}; - constructor(private cancellationToken: TypeScript.ICancellationToken = TypeScript.CancellationToken.None) { + constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) { } public addDefaultLibrary() { @@ -107,17 +186,16 @@ } public addFile(fileName: string) { - var code = Harness.Environment.readFile(fileName); + var code = Harness.IO.readFile(fileName); this.addScript(fileName, code); } private getScriptInfo(fileName: string): ScriptInfo { - return this.fileNameToScript.lookup(fileName); + return this.fileNameToScript[fileName]; } public addScript(fileName: string, content: string) { - var script = new ScriptInfo(fileName, content); - this.fileNameToScript.add(fileName, script); + this.fileNameToScript[fileName] = new ScriptInfo(fileName, content); } public updateScript(fileName: string, content: string) { @@ -155,91 +233,64 @@ } ////////////////////////////////////////////////////////////////////// - // ILanguageServiceShimHost implementation + // LanguageServiceShimHost implementation // /// Returns json for Tools.CompilationSettings public getCompilationSettings(): string { - return ""; // i.e. default settings + return JSON.stringify({}); // i.e. default settings } - public getCancellationToken(): TypeScript.ICancellationToken { + public getCancellationToken(): ts.CancellationToken { return this.cancellationToken; } public getScriptFileNames(): string { - return JSON.stringify(this.fileNameToScript.getAllKeys()); + var fileNames: string[] = []; + ts.forEachKey(this.fileNameToScript, (fileName) => { fileNames.push(fileName); }); + return JSON.stringify(fileNames); } - public getScriptSnapshot(fileName: string): TypeScript.Services.IScriptSnapshotShim { + public getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim { return new ScriptSnapshotShim(this.getScriptInfo(fileName)); } - public getScriptVersion(fileName: string): string { - return this.getScriptInfo(fileName).version.toString(); + public getScriptVersion(fileName: string): number { + return this.getScriptInfo(fileName).version; } public getScriptIsOpen(fileName: string): boolean { return this.getScriptInfo(fileName).isOpen; } - public getScriptByteOrderMark(fileName: string): TypeScript.ByteOrderMark { + public getScriptByteOrderMark(fileName: string): ts.ByteOrderMark { return this.getScriptInfo(fileName).byteOrderMark; } - public getDiagnosticsObject(): TypeScript.Services.ILanguageServicesDiagnostics { - return new LanguageServicesDiagnostics(""); - } - public getLocalizedDiagnosticMessages(): string { - return ""; - } - - public fileExists(s: string) { - return this.IO.fileExists(s); - } - - public directoryExists(s: string) { - return this.IO.directoryExists(s); - } - - public resolveRelativePath(path: string, directory: string): string { - if (TypeScript.isRooted(path) || !directory) { - return this.IO.absolutePath(path); - } - else { - return this.IO.absolutePath(TypeScript.IOUtils.combine(directory, path)); - } - } - - public getParentDirectory(path: string): string { - return this.IO.directoryName(path); + return JSON.stringify({}); } /** Return a new instance of the language service shim, up-to-date wrt to typecheck. * To access the non-shim (i.e. actual) language service, use the "ls.languageService" property. */ - public getLanguageService(): TypeScript.Services.ILanguageServiceShim { + public getLanguageService(): ts.LanguageServiceShim { var ls = new TypeScript.Services.TypeScriptServicesFactory().createLanguageServiceShim(this); this.ls = ls; - var hostAdapter = new ts.LanguageServiceShimHostAdapter(this); - this.newLS = ts.createLanguageService(hostAdapter); + var hostAdapter = new LanguageServiceShimHostAdapter(this); + + this.newLS = ts.createLanguageService(hostAdapter, NonCachingDocumentRegistry.Instance); return ls; } /** Parse file given its source text */ public parseSourceText(fileName: string, sourceText: TypeScript.IScriptSnapshot): TypeScript.SourceUnitSyntax { - var compilationSettings = new TypeScript.CompilationSettings(); - compilationSettings.codeGenTarget = TypeScript.LanguageVersion.EcmaScript5; - - var settings = TypeScript.ImmutableCompilationSettings.fromCompilationSettings(compilationSettings); - var parseOptions = settings.codeGenTarget(); - return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), parseOptions, TypeScript.isDTSFile(fileName)).sourceUnit(); + return TypeScript.Parser.parse(fileName, TypeScript.SimpleText.fromScriptSnapshot(sourceText), ts.ScriptTarget.ES5, TypeScript.isDTSFile(fileName)).sourceUnit(); } /** Parse a file on disk given its fileName */ public parseFile(fileName: string) { - var sourceText = TypeScript.ScriptSnapshot.fromString(this.IO.readFile(fileName, /*codepage:*/ null).contents) + var sourceText = TypeScript.ScriptSnapshot.fromString(Harness.IO.readFile(fileName)) return this.parseSourceText(fileName, sourceText); } @@ -248,7 +299,7 @@ * @param col 1 based index */ public lineColToPosition(fileName: string, line: number, col: number): number { - var script: ScriptInfo = this.fileNameToScript.lookup(fileName); + var script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); assert.isTrue(line >= 1); assert.isTrue(col >= 1); @@ -261,7 +312,7 @@ * @param col 0 based index */ public positionToZeroBasedLineCol(fileName: string, position: number): TypeScript.ILineAndCharacter { - var script: ScriptInfo = this.fileNameToScript.lookup(fileName); + var script: ScriptInfo = this.fileNameToScript[fileName]; assert.isNotNull(script); var result = script.lineMap.getLineAndCharacterFromPosition(position); @@ -272,10 +323,10 @@ } /** Verify that applying edits to sourceFileName result in the content of the file baselineFileName */ - public checkEdits(sourceFileName: string, baselineFileName: string, edits: TypeScript.Services.TextChange[]) { - var script = Utils.readFile(sourceFileName); - var formattedScript = this.applyEdits(script.contents, edits); - var baseline = Utils.readFile(baselineFileName).contents; + public checkEdits(sourceFileName: string, baselineFileName: string, edits: ts.TextEdit[]) { + var script = Harness.IO.readFile(sourceFileName); + var formattedScript = this.applyEdits(script, edits); + var baseline = Harness.IO.readFile(baselineFileName); function noDiff(text1: string, text2: string) { text1 = text1.replace(/^\s+|\s+$/g, "").replace(/\r\n?/g, "\n"); @@ -301,26 +352,26 @@ /** Apply an array of text edits to a string, and return the resulting string. */ - public applyEdits(content: string, edits: TypeScript.Services.TextChange[]): string { + public applyEdits(content: string, edits: ts.TextEdit[]): string { var result = content; edits = this.normalizeEdits(edits); for (var i = edits.length - 1; i >= 0; i--) { var edit = edits[i]; - var prefix = result.substring(0, edit.span.start()); - var middle = edit.newText; - var suffix = result.substring(edit.span.end()); + var prefix = result.substring(0, edit.minChar); + var middle = edit.text; + var suffix = result.substring(edit.limChar); result = prefix + middle + suffix; } return result; } /** Normalize an array of edits by removing overlapping entries and sorting entries on the minChar position. */ - private normalizeEdits(edits: TypeScript.Services.TextChange[]): TypeScript.Services.TextChange[] { - var result: TypeScript.Services.TextChange[] = []; + private normalizeEdits(edits: ts.TextEdit[]): ts.TextEdit[] { + var result: ts.TextEdit[] = []; - function mapEdits(edits: TypeScript.Services.TextChange[]): { edit: TypeScript.Services.TextChange; index: number; }[] { - var result: { edit: TypeScript.Services.TextChange; index: number; }[] = []; + function mapEdits(edits: ts.TextEdit[]): { edit: ts.TextEdit; index: number; }[] { + var result: { edit: ts.TextEdit; index: number; }[] = []; for (var i = 0; i < edits.length; i++) { result.push({ edit: edits[i], index: i }); } @@ -328,7 +379,7 @@ } var temp = mapEdits(edits).sort(function (a, b) { - var result = a.edit.span.start() - b.edit.span.start(); + var result = a.edit.minChar - b.edit.limChar; if (result === 0) result = a.index - b.index; return result; @@ -347,7 +398,7 @@ } var nextEdit = temp[next].edit; - var gap = nextEdit.span.start() - currentEdit.span.end(); + var gap = nextEdit.minChar - currentEdit.limChar; // non-overlapping edits if (gap >= 0) { @@ -359,7 +410,7 @@ // overlapping edits: for now, we only support ignoring an next edit // entirely contained in the current edit. - if (currentEdit.span.end() >= nextEdit.span.end()) { + if (currentEdit.minChar >= nextEdit.limChar) { next++; continue; } @@ -371,15 +422,5 @@ return result; } } - - export class LanguageServicesDiagnostics implements TypeScript.Services.ILanguageServicesDiagnostics { - - constructor(private destination: string) { } - - public log(content: string): void { - //Imitates the LanguageServicesDiagnostics object when not in Visual Studio - } - - } } \ No newline at end of file diff --git a/src/harness/runner.ts b/src/harness/runner.ts index 26b768729fc..accf41684c0 100644 --- a/src/harness/runner.ts +++ b/src/harness/runner.ts @@ -62,12 +62,10 @@ if (testConfigFile !== '') { runners.push(new ProjectRunner()); break; case 'fourslash': - // TODO: Re-enable Fourslash tests - // runners.push(new FourslashRunner()); + runners.push(new FourslashRunner()); break; case 'fourslash-generated': - // TODO: Re-enable Fourslash tests - // runners.push(new GeneratedFourslashRunner()); + runners.push(new GeneratedFourslashRunner()); break; case 'unittests': runners.push(new UnitTestRunner(UnittestTestType.Compiler)); diff --git a/src/services/core/diagnosticCore.ts b/src/services/core/diagnosticCore.ts index 8485052af8f..0c12a354933 100644 --- a/src/services/core/diagnosticCore.ts +++ b/src/services/core/diagnosticCore.ts @@ -145,11 +145,8 @@ module TypeScript { } export function getLocalizedText(diagnosticKey: string, args: any[]): string { - if (LocalizedDiagnosticMessages) { - //Debug.assert(LocalizedDiagnosticMessages.hasOwnProperty(diagnosticKey)); - } - - var diagnosticMessageText: string = LocalizedDiagnosticMessages ? LocalizedDiagnosticMessages[diagnosticKey] : diagnosticKey; + + var diagnosticMessageText: string = diagnosticKey; Debug.assert(diagnosticMessageText !== undefined && diagnosticMessageText !== null); var actualCount = args ? args.length : 0; diff --git a/src/services/services.ts b/src/services/services.ts index 8e969ceb5a0..14581c0c3d6 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -811,7 +811,7 @@ module ts { } } - function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { + export function createDocument(compilationSettings: CompilerOptions, fileName: string, scriptSnapshot: TypeScript.IScriptSnapshot, byteOrderMark: ByteOrderMark, version: number, isOpen: boolean, referencedFiles: string[]): Document { return new DocumentObject(compilationSettings, fileName, referencedFiles, scriptSnapshot, byteOrderMark, version, isOpen, /*syntaxTree:*/ null, /*soruceFile*/ null); } @@ -1339,7 +1339,7 @@ module ts { function dispose(): void { if (program) { forEach(program.getSourceFiles(), - (f) => documentRegistry.releaseDocument(f.filename, program.getCompilerOptions())); + (f) => { documentRegistry.releaseDocument(f.filename, program.getCompilerOptions()); }); } } diff --git a/src/services/shims.ts b/src/services/shims.ts index c2402aebd52..8debe8f973b 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -173,6 +173,8 @@ module ts { } function languageVersionToScriptTarget(languageVersion: LanguageVersion): ScriptTarget { + if (typeof languageVersion === "undefined") return undefined; + switch (languageVersion) { case LanguageVersion.EcmaScript3: return ScriptTarget.ES3; case LanguageVersion.EcmaScript5: return ScriptTarget.ES5; @@ -181,6 +183,8 @@ module ts { } function moduleGenTargetToModuleKind(moduleGenTarget: ModuleGenTarget): ModuleKind { + if (typeof moduleGenTarget === "undefined") return undefined; + switch (moduleGenTarget) { case ModuleGenTarget.Asynchronous: return ModuleKind.AMD; case ModuleGenTarget.Synchronous: return ModuleKind.CommonJS; @@ -190,6 +194,8 @@ module ts { } function scriptTargetTolanguageVersion(scriptTarget: ScriptTarget): LanguageVersion { + if (typeof scriptTarget === "undefined") return undefined; + switch (scriptTarget) { case ScriptTarget.ES3: return LanguageVersion.EcmaScript3; case ScriptTarget.ES5: return LanguageVersion.EcmaScript5; @@ -198,6 +204,8 @@ module ts { } function moduleKindToModuleGenTarget(moduleKind: ModuleKind): ModuleGenTarget { + if (typeof moduleKind === "undefined") return undefined; + switch (moduleKind) { case ModuleKind.AMD: return ModuleGenTarget.Asynchronous; case ModuleKind.CommonJS: return ModuleGenTarget.Synchronous;