diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f3de51f35e5..17329854017 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -7238,12 +7238,9 @@ module ts { return target !== unknownSymbol && ((target.flags & SymbolFlags.Value) !== 0); } - function shouldEmitDeclarations() { - // If the declaration emit and there are no errors being reported in program or by checker - // declarations can be emitted - return compilerOptions.declaration && - !program.getDiagnostics().length && - !getDiagnostics().length; + function hasSemanticErrors() { + // Return true if there is any semantic error in a file or globally + return getDiagnostics().length > 0 || getGlobalDiagnostics().length > 0; } function isReferencedImportDeclaration(node: ImportDeclaration): boolean { @@ -7304,7 +7301,7 @@ module ts { writeTypeToTextWriter(getReturnTypeOfSignature(signature), enclosingDeclaration, flags , writer); } - function invokeEmitter() { + function invokeEmitter(targetSourceFile?: SourceFile) { var resolver: EmitResolver = { getProgram: () => program, getLocalNameOfContainer: getLocalNameOfContainer, @@ -7315,7 +7312,7 @@ module ts { getNodeCheckFlags: getNodeCheckFlags, getEnumMemberValue: getEnumMemberValue, isTopLevelValueImportedViaEntityName: isTopLevelValueImportedViaEntityName, - shouldEmitDeclarations: shouldEmitDeclarations, + hasSemanticErrors: hasSemanticErrors, isDeclarationVisible: isDeclarationVisible, isImplementationOfOverload: isImplementationOfOverload, writeTypeAtLocation: writeTypeAtLocation, @@ -7325,7 +7322,7 @@ module ts { isImportDeclarationEntityNameReferenceDeclarationVisibile: isImportDeclarationEntityNameReferenceDeclarationVisibile }; checkProgram(); - return emitFiles(resolver); + return emitFiles(resolver, targetSourceFile); } function initializeTypeChecker() { diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 28a0a7bb6a3..6bfa537c9f2 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -407,7 +407,7 @@ module ts { return normalizedPathComponents(path, rootLength); } - export function getNormalizedPathFromPathCompoments(pathComponents: string[]) { + export function getNormalizedPathFromPathComponents(pathComponents: string[]) { if (pathComponents && pathComponents.length) { return pathComponents[0] + pathComponents.slice(1).join(directorySeparator); } @@ -468,7 +468,7 @@ module ts { var pathComponents = getNormalizedPathOrUrlComponents(relativeOrAbsolutePath, currentDirectory); var directoryComponents = getNormalizedPathOrUrlComponents(directoryPathOrUrl, currentDirectory); if (directoryComponents.length > 1 && directoryComponents[directoryComponents.length - 1] === "") { - // If the directory path given was of type test/cases/ then we really need components of directry to be only till its name + // If the directory path given was of type test/cases/ then we really need components of directory to be only till its name // that is ["test", "cases", ""] needs to be actually ["test", "cases"] directoryComponents.length--; } @@ -494,7 +494,7 @@ module ts { } // Cant find the relative path, get the absolute path - var absolutePath = getNormalizedPathFromPathCompoments(pathComponents); + var absolutePath = getNormalizedPathFromPathComponents(pathComponents); if (isAbsolutePathAnUrl && isRootedDiskPath(absolutePath)) { absolutePath = "file:///" + absolutePath; } diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 9f5bd2897b6..73064eda695 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -25,7 +25,22 @@ module ts { return indentStrings[1].length; } - export function emitFiles(resolver: EmitResolver): EmitResult { + export function shouldEmitToOwnFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean { + if (!(sourceFile.flags & NodeFlags.DeclarationFile)) { + if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) { + return true; + } + return false; + } + return false; + } + + export function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) { + return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0; + } + + // targetSourceFile is when users only want one file in entire project to be emitted. This is used in compilerOnSave feature + export function emitFiles(resolver: EmitResolver, targetSourceFile?: SourceFile): EmitResult { var program = resolver.getProgram(); var compilerHost = program.getCompilerHost(); var compilerOptions = program.getCompilerOptions(); @@ -34,22 +49,14 @@ module ts { var newLine = program.getCompilerHost().getNewLine(); function getSourceFilePathInNewDir(newDirPath: string, sourceFile: SourceFile) { - var sourceFilePath = getNormalizedPathFromPathCompoments(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory())); + var sourceFilePath = getNormalizedPathFromPathComponents(getNormalizedPathComponents(sourceFile.filename, compilerHost.getCurrentDirectory())); sourceFilePath = sourceFilePath.replace(program.getCommonSourceDirectory(), ""); return combinePaths(newDirPath, sourceFilePath); } - function shouldEmitToOwnFile(sourceFile: SourceFile) { - if (!(sourceFile.flags & NodeFlags.DeclarationFile)) { - if ((isExternalModule(sourceFile) || !compilerOptions.out) && !fileExtensionIs(sourceFile.filename, ".js")) { - return true; - } - } - } - function getOwnEmitOutputFilePath(sourceFile: SourceFile, extension: string) { - if (program.getCompilerOptions().outDir) { - var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(program.getCompilerOptions().outDir, sourceFile)); + if (compilerOptions.outDir) { + var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(getSourceFilePathInNewDir(compilerOptions.outDir, sourceFile)); } else { var emitOutputFilePathWithoutExtension = getModuleNameFromFilename(sourceFile.filename); @@ -58,10 +65,6 @@ module ts { return emitOutputFilePathWithoutExtension + extension; } - function isExternalModuleOrDeclarationFile(sourceFile: SourceFile) { - return isExternalModule(sourceFile) || (sourceFile.flags & NodeFlags.DeclarationFile) !== 0; - } - function getFirstConstructorWithBody(node: ClassDeclaration): ConstructorDeclaration { return forEach(node.members, member => { if (member.kind === SyntaxKind.Constructor && (member).body) { @@ -3082,7 +3085,7 @@ module ts { function writeReferencePath(referencedFile: SourceFile) { var declFileName = referencedFile.flags & NodeFlags.DeclarationFile ? referencedFile.filename // Declaration file, use declaration file name - : shouldEmitToOwnFile(referencedFile) + : shouldEmitToOwnFile(referencedFile, compilerOptions) ? getOwnEmitOutputFilePath(referencedFile, ".d.ts") // Own output file so get the .d.ts file : getModuleNameFromFilename(compilerOptions.out) + ".d.ts";// Global out file @@ -3104,7 +3107,7 @@ module ts { // All the references that are not going to be part of same file if ((referencedFile.flags & NodeFlags.DeclarationFile) || // This is a declare file reference - shouldEmitToOwnFile(referencedFile) || // This is referenced file is emitting its own js file + shouldEmitToOwnFile(referencedFile, compilerOptions) || // This is referenced file is emitting its own js file !addedGlobalFileReference) { // Or the global out file corresponding to this reference was not added writeReferencePath(referencedFile); @@ -3161,29 +3164,54 @@ module ts { } } - var shouldEmitDeclarations = resolver.shouldEmitDeclarations(); + var hasSemanticErrors = resolver.hasSemanticErrors(); + function emitFile(jsFilePath: string, sourceFile?: SourceFile) { emitJavaScript(jsFilePath, sourceFile); - if (shouldEmitDeclarations) { + if (!hasSemanticErrors && compilerOptions.declaration) { emitDeclarations(jsFilePath, sourceFile); } } - forEach(program.getSourceFiles(), sourceFile => { - if (shouldEmitToOwnFile(sourceFile)) { - var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js"); - emitFile(jsFilePath, sourceFile); - } - }); + if (targetSourceFile === undefined) { + forEach(program.getSourceFiles(), sourceFile => { + if (shouldEmitToOwnFile(sourceFile, compilerOptions)) { + var jsFilePath = getOwnEmitOutputFilePath(sourceFile, ".js"); + emitFile(jsFilePath, sourceFile); + } + }); + } + else { + // Emit only one file specified in targetFilename. This is mainly used in compilerOnSave feature + var jsFilePath = getOwnEmitOutputFilePath(targetSourceFile, ".js"); + emitFile(jsFilePath, targetSourceFile); + } + if (compilerOptions.out) { emitFile(compilerOptions.out); } - + // Sort and make the unique list of diagnostics diagnostics.sort(compareDiagnostics); diagnostics = deduplicateSortedDiagnostics(diagnostics); + // Update returnCode if there is any EmitterError + var hasEmitterError = forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error); + + // Check and update returnCode for syntactic and semantic + var returnCode: EmitReturnStatus; + if (hasEmitterError) { + returnCode = EmitReturnStatus.EmitErrorsEncountered; + } else if (hasSemanticErrors && compilerOptions.declaration) { + returnCode = EmitReturnStatus.DeclarationGenerationSkipped; + } else if (hasSemanticErrors && !compilerOptions.declaration) { + returnCode = EmitReturnStatus.JSGeneratedWithSemanticErrors; + } else { + returnCode = EmitReturnStatus.Succeeded; + } + return { + emitResultStatus: returnCode, errors: diagnostics, sourceMaps: sourceMapDataList }; diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 957322a899c..bc01cb7a9e0 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -3965,11 +3965,11 @@ module ts { // Each file contributes into common source file path if (!(sourceFile.flags & NodeFlags.DeclarationFile) && !fileExtensionIs(sourceFile.filename, ".js")) { - var sourcePathCompoments = getNormalizedPathComponents(sourceFile.filename, host.getCurrentDirectory()); - sourcePathCompoments.pop(); // FileName is not part of directory + var sourcePathComponents = getNormalizedPathComponents(sourceFile.filename, host.getCurrentDirectory()); + sourcePathComponents.pop(); // FileName is not part of directory if (commonPathComponents) { - for (var i = 0; i < Math.min(commonPathComponents.length, sourcePathCompoments.length); i++) { - if (commonPathComponents[i] !== sourcePathCompoments[i]) { + for (var i = 0; i < Math.min(commonPathComponents.length, sourcePathComponents.length); i++) { + if (commonPathComponents[i] !== sourcePathComponents[i]) { if (i === 0) { errors.push(createCompilerDiagnostic(Diagnostics.Cannot_find_the_common_subdirectory_path_for_the_input_files)); return; @@ -3982,18 +3982,18 @@ module ts { } // If the fileComponent path completely matched and less than already found update the length - if (sourcePathCompoments.length < commonPathComponents.length) { - commonPathComponents.length = sourcePathCompoments.length; + if (sourcePathComponents.length < commonPathComponents.length) { + commonPathComponents.length = sourcePathComponents.length; } } else { // first file - commonPathComponents = sourcePathCompoments; + commonPathComponents = sourcePathComponents; } } }); - commonSourceDirectory = getNormalizedPathFromPathCompoments(commonPathComponents); + commonSourceDirectory = getNormalizedPathFromPathComponents(commonPathComponents); if (commonSourceDirectory) { // Make sure directory path ends with directory separator so this string can directly // used to replace with "" to get the relative path of the source file and the relative path doesn't diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 120042b9bff..c7893f8d997 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -577,7 +577,7 @@ module ts { export interface SourceMapData { /** Where the sourcemap file is written */ sourceMapFilePath: string; - /** source map url written in the js file */ + /** source map URL written in the js file */ jsSourceMappingURL: string; /** Source map's file field - js file name*/ sourceMapFile: string; @@ -596,7 +596,17 @@ module ts { sourceMapDecodedMappings: SourceMapSpan[]; } + // Return code used by getEmitOutput function to indicate status of the function + export enum EmitReturnStatus { + Succeeded = 0, // All outputs generated as requested (.js, .map, .d.ts), no errors reported + AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated + JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors + DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors + EmitErrorsEncountered = 4 // Emitter errors occurred during emitting process + } + export interface EmitResult { + emitResultStatus: EmitReturnStatus; errors: Diagnostic[]; sourceMaps: SourceMapData[]; // Array of sourceMapData if compiler emitted sourcemaps } @@ -610,7 +620,7 @@ module ts { getSymbolCount(): number; getTypeCount(): number; checkProgram(): void; - emitFiles(): EmitResult; + emitFiles(targetSourceFile?: SourceFile): EmitResult; getParentOfSymbol(symbol: Symbol): Symbol; getTypeOfSymbol(symbol: Symbol): Type; getPropertiesOfType(type: Type): Symbol[]; @@ -668,7 +678,7 @@ module ts { isTopLevelValueImportedViaEntityName(node: ImportDeclaration): boolean; getNodeCheckFlags(node: Node): NodeCheckFlags; getEnumMemberValue(node: EnumMember): number; - shouldEmitDeclarations(): boolean; + hasSemanticErrors(): boolean; isDeclarationVisible(node: Declaration): boolean; isImplementationOfOverload(node: FunctionDeclaration): boolean; writeTypeAtLocation(location: Node, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: TextWriter): void; diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 0bcea9367e4..360dc3df51e 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -122,9 +122,71 @@ module FourSlash { return s.replace(/[&<>"'\/]/g, ch => entityMap[ch]); } + // Name of testcase metadata including ts.CompilerOptions properties that will be used by globalOptions + // To add additional option, add property into the testOptMetadataNames, refer the property in either globalMetadataNames or fileMetadataNames + // Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data + var testOptMetadataNames = { + baselineFile: 'BaselineFile', + declaration: 'declaration', + emitThisFile: 'emitThisFile', // This flag is used for testing getEmitOutput feature. It allows test-cases to indicate what file to be output in multiple files project + filename: 'Filename', + mapRoot: 'mapRoot', + module: 'module', + out: 'out', + outDir: 'outDir', + sourceMap: 'sourceMap', + sourceRoot: 'sourceRoot', + }; + // List of allowed metadata names - var fileMetadataNames = ['Filename']; - var globalMetadataNames = ['Module', 'Target', 'BaselineFile']; // Note: Only BaselineFile is actually supported at the moment + var fileMetadataNames = [testOptMetadataNames.filename, testOptMetadataNames.emitThisFile]; + var globalMetadataNames = [testOptMetadataNames.baselineFile, testOptMetadataNames.declaration, + testOptMetadataNames.mapRoot, testOptMetadataNames.module, testOptMetadataNames.out, + testOptMetadataNames.outDir, testOptMetadataNames.sourceMap, testOptMetadataNames.sourceRoot] + + function convertGlobalOptionsToCompilationSettings(globalOptions: { [idx: string]: string }): ts.CompilationSettings { + var settings: ts.CompilationSettings = {}; + // Convert all property in globalOptions into ts.CompilationSettings + for (var prop in globalOptions) { + if (globalOptions.hasOwnProperty(prop)) { + switch (prop) { + case testOptMetadataNames.declaration: + settings.generateDeclarationFiles = true; + break; + case testOptMetadataNames.mapRoot: + settings.mapRoot = globalOptions[prop]; + break; + case testOptMetadataNames.module: + // create appropriate external module target for CompilationSettings + switch (globalOptions[prop]) { + case "AMD": + settings.moduleGenTarget = ts.ModuleGenTarget.Asynchronous; + break; + case "CommonJS": + settings.moduleGenTarget = ts.ModuleGenTarget.Synchronous; + break; + default: + settings.moduleGenTarget = ts.ModuleGenTarget.Unspecified; + break; + } + break; + case testOptMetadataNames.out: + settings.outFileOption = globalOptions[prop]; + break; + case testOptMetadataNames.outDir: + settings.outDirOption = globalOptions[prop]; + break; + case testOptMetadataNames.sourceMap: + settings.mapSourceFiles = true; + break; + case testOptMetadataNames.sourceRoot: + settings.sourceRoot = globalOptions[prop]; + break; + } + } + } + return settings; + } export var currentTestState: TestState = null; @@ -199,11 +261,15 @@ module FourSlash { private scenarioActions: string[] = []; private taoInvalidReason: string = null; + constructor(public testData: FourSlashData) { // Initialize the language service with all the scripts this.cancellationToken = new TestCancellationToken(); this.languageServiceShimHost = new Harness.LanguageService.TypeScriptLS(this.cancellationToken); + var compilationSettings = convertGlobalOptionsToCompilationSettings(this.testData.globalOptions); + this.languageServiceShimHost.setCompilationSettings(compilationSettings); + var inputFiles: { unitName: string; content: string }[] = []; testData.files.forEach(file => { @@ -220,9 +286,9 @@ module FourSlash { //if (/require\(/.test(lastFile.content) || /reference\spath/.test(lastFile.content)) { // inputFiles.push({ unitName: lastFile.fileName, content: lastFile.content }); //} else { - inputFiles = testData.files.map(file => { - return { unitName: file.fileName, content: file.content }; - }); + inputFiles = testData.files.map(file => { + return { unitName: file.fileName, content: file.content }; + }); //} @@ -876,7 +942,7 @@ module FourSlash { Harness.Baseline.runBaseline( "Breakpoint Locations for " + this.activeFile.fileName, - this.testData.globalOptions['BaselineFile'], + this.testData.globalOptions[testOptMetadataNames.baselineFile], () => { var fileLength = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength(); var resultString = ""; @@ -888,6 +954,48 @@ module FourSlash { true /* run immediately */); } + public baselineGetEmitOutput() { + this.taoInvalidReason = 'baselineGetEmitOutput impossible'; + // Find file to be emitted + var emitFiles: FourSlashFile[] = []; // List of FourSlashFile that has emitThisFile flag on + + var allFourSlashFiles = this.testData.files; + for (var idx = 0; idx < allFourSlashFiles.length; ++idx) { + var file = allFourSlashFiles[idx]; + if (file.fileOptions[testOptMetadataNames.emitThisFile]) { + // Find a file with the flag emitThisFile turned on + emitFiles.push(file); + } + } + + // If there is not emiThisFile flag specified in the test file, throw an error + if (emitFiles.length === 0) { + throw new Error("No emitThisFile is specified in the test file"); + } + + Harness.Baseline.runBaseline( + "Generate getEmitOutput baseline : " + emitFiles.join(" "), + this.testData.globalOptions[testOptMetadataNames.baselineFile], + () => { + var resultString = ""; + // Loop through all the emittedFiles and emit them one by one + emitFiles.forEach(emitFile => { + var emitOutput = this.languageService.getEmitOutput(emitFile.fileName); + var emitOutputStatus = emitOutput.emitOutputStatus; + // Print emitOutputStatus in readable format + resultString += "EmitOutputStatus : " + ts.EmitReturnStatus[emitOutputStatus]; + resultString += "\n"; + emitOutput.outputFiles.forEach((outputFile, idx, array) => { + var filename = "Filename : " + outputFile.name + "\n"; + resultString = resultString + filename + outputFile.text; + }); + resultString += "\n"; + }); + return resultString; + }, + true /* run immediately */); + } + public printBreakpointLocation(pos: number) { Harness.IO.log(this.getBreakpointStatementLocation(pos)); } @@ -1198,7 +1306,7 @@ module FourSlash { private applyEdits(fileName: string, edits: ts.TextChange[], 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 + // of the incremental offset 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()); // Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters @@ -1275,7 +1383,7 @@ module FourSlash { var definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition); if (!definitions || !definitions.length) { - throw new Error('goToDefinition failed - expected to at least one defintion location but got 0'); + throw new Error('goToDefinition failed - expected to at least one definition location but got 0'); } if (definitionIndex >= definitions.length) { @@ -1295,10 +1403,10 @@ module FourSlash { var foundDefinitions = definitions && definitions.length; if (foundDefinitions && negative) { - throw new Error('goToDefinition - expected to 0 defintion locations but got ' + definitions.length); + throw new Error('goToDefinition - expected to 0 definition locations but got ' + definitions.length); } else if (!foundDefinitions && !negative) { - throw new Error('goToDefinition - expected to at least one defintion location but got 0'); + throw new Error('goToDefinition - expected to at least one definition location but got 0'); } } @@ -1412,7 +1520,7 @@ module FourSlash { Harness.Baseline.runBaseline( "Name OrDottedNameSpans for " + this.activeFile.fileName, - this.testData.globalOptions['BaselineFile'], + this.testData.globalOptions[testOptMetadataNames.baselineFile], () => { var fileLength = this.languageServiceShimHost.getScriptSnapshot(this.activeFile.fileName).getLength(); var resultString = ""; @@ -2053,12 +2161,12 @@ module FourSlash { // Comment line, check for global/file @options and record them var match = optionRegex.exec(line.substr(2)); if (match) { - var globalNameIndex = globalMetadataNames.indexOf(match[1]); - var fileNameIndex = fileMetadataNames.indexOf(match[1]); - if (globalNameIndex === -1) { - if (fileNameIndex === -1) { + var globalMetadataNamesIndex = globalMetadataNames.indexOf(match[1]); + var fileMetadataNamesIndex = fileMetadataNames.indexOf(match[1]); + if (globalMetadataNamesIndex === -1) { + if (fileMetadataNamesIndex === -1) { throw new Error('Unrecognized metadata name "' + match[1] + '". Available global metadata names are: ' + globalMetadataNames.join(', ') + '; file metadata names are: ' + fileMetadataNames.join(', ')); - } else { + } else if (fileMetadataNamesIndex === fileMetadataNames.indexOf(testOptMetadataNames.filename)) { // Found an @Filename directive, if this is not the first then create a new subfile if (currentFileContent) { var file = parseFileContent(currentFileContent, currentFileName, markerMap, markers, ranges); @@ -2075,8 +2183,15 @@ module FourSlash { currentFileName = 'tests/cases/fourslash/' + match[2]; currentFileOptions[match[1]] = match[2]; + } else { + // Add other fileMetadata flag + currentFileOptions[match[1]] = match[2]; } } else { + // Check if the match is already existed in the global options + if (opts[match[1]] !== undefined) { + throw new Error("Global Option : '" + match[1] + "' is already existed"); + } opts[match[1]] = match[2]; } } @@ -2186,7 +2301,7 @@ module FourSlash { /// A list of ranges we've collected so far */ var localRanges: Range[] = []; - /// The latest position of the start of an unflushed plaintext area + /// The latest position of the start of an unflushed plain text area var lastNormalCharPosition: number = 0; /// The total number of metacharacters removed from the file (so far) diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 5ee3139d8f7..c227dac7bb0 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -826,7 +826,7 @@ module Harness { totalErrorsReported++; } - // Report glovbal errors: + // Report global errors: var globalErrors = diagnostics.filter(err => !err.filename); globalErrors.forEach(err => outputErrorText(err)); @@ -1016,7 +1016,7 @@ module Harness { } export module TestCaseParser { - /** all the necesarry information to set the right compiler settings */ + /** all the necessary information to set the right compiler settings */ export interface CompilerSetting { flag: string; value: string; diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 1a02157d729..647d0729cbb 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -134,6 +134,7 @@ module Harness.LanguageService { private ls: ts.LanguageServiceShim = null; private fileNameToScript: ts.Map = {}; + private settings: ts.CompilationSettings = {}; constructor(private cancellationToken: ts.CancellationToken = CancellationToken.None) { } @@ -199,13 +200,21 @@ module Harness.LanguageService { /// Returns json for Tools.CompilationSettings public getCompilationSettings(): string { - return JSON.stringify({}); // i.e. default settings + return JSON.stringify(this.settings); } public getCancellationToken(): ts.CancellationToken { return this.cancellationToken; } + public getCurrentDirectory(): string { + return ""; + } + + public getDefaultLibFilename(): string { + return ""; + } + public getScriptFileNames(): string { var fileNames: string[] = []; ts.forEachKey(this.fileNameToScript, (fileName) => { fileNames.push(fileName); }); @@ -236,6 +245,14 @@ module Harness.LanguageService { return this.ls; } + public setCompilationSettings(settings: ts.CompilationSettings) { + for (var key in settings) { + if (settings.hasOwnProperty(key)) { + this.settings[key] = settings[key]; + } + } + } + /** Return a new instance of the classifier service shim */ public getClassifier(): ts.ClassifierShim { return new TypeScript.Services.TypeScriptServicesFactory().createClassifierShim(this); diff --git a/src/services/services.ts b/src/services/services.ts index 41d15c91cd7..6742e86dc38 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -473,6 +473,8 @@ module ts { getScriptSnapshot(fileName: string): TypeScript.IScriptSnapshot; getLocalizedDiagnosticMessages(): any; getCancellationToken(): CancellationToken; + getCurrentDirectory(): string; + getDefaultLibFilename(): string; } // @@ -746,16 +748,9 @@ module ts { docComment: string; } - export enum EmitOutputResult { - Succeeded, - FailedBecauseOfSyntaxErrors, - FailedBecauseOfCompilerOptionsErrors, - FailedToGenerateDeclarationsBecauseOfSemanticErrors - } - export interface EmitOutput { outputFiles: OutputFile[]; - emitOutputResult: EmitOutputResult; + emitOutputStatus: EmitReturnStatus; } export enum OutputFileType { @@ -768,8 +763,6 @@ module ts { name: string; writeByteOrderMark: boolean; text: string; - fileType: OutputFileType; - sourceMapOutput: any; } export enum EndOfLineState { @@ -1478,7 +1471,7 @@ module ts { var program: Program; // this checker is used to answer all LS questions except errors var typeInfoResolver: TypeChecker; - // the sole purpose of this check is to return semantic diagnostics + // the sole purpose of this checker is to return semantic diagnostics // creation is deferred - use getFullTypeCheckChecker to get instance var fullTypeCheckChecker_doNotAccessDirectly: TypeChecker; var useCaseSensitivefilenames = false; @@ -1486,6 +1479,7 @@ module ts { var documentRegistry = documentRegistry; var cancellationToken = new CancellationTokenObject(host.getCancellationToken()); var activeCompletionSession: CompletionSession; // The current active completion session, used to get the completion entry details + var writer: (filename: string, data: string, writeByteOrderMark: boolean) => void = undefined; // Check if the localized messages json is set, otherwise query the host for it if (!TypeScript.LocalizedDiagnosticMessages) { @@ -1510,15 +1504,14 @@ module ts { getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), useCaseSensitiveFileNames: () => useCaseSensitivefilenames, getNewLine: () => "\r\n", - // Need something that doesn't depend on sys.ts here getDefaultLibFilename: (): string => { - throw Error("TOD:: getDefaultLibfilename"); + return host.getDefaultLibFilename(); }, writeFile: (filename, data, writeByteOrderMark) => { - throw Error("TODO: write file"); + writer(filename, data, writeByteOrderMark); }, getCurrentDirectory: (): string => { - throw Error("TODO: getCurrentDirectory"); + return host.getCurrentDirectory(); } }; } @@ -2606,7 +2599,7 @@ module ts { return getReferencesForNode(node, program.getSourceFiles()); } - function getReferencesForNode(node: Node, sourceFiles : SourceFile[]): ReferenceEntry[] { + function getReferencesForNode(node: Node, sourceFiles: SourceFile[]): ReferenceEntry[] { // Labels if (isLabelName(node)) { if (isJumpStatementTarget(node)) { @@ -2649,8 +2642,9 @@ module ts { var searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.getDeclarations()); // Get the text to search for, we need to normalize it as external module names will have quote - var symbolName = getNormalizedSymbolName(symbol); + var symbolName = getNormalizedSymbolName(symbol); + // Get syntactic diagnostics var scope = getSymbolScope(symbol); if (scope) { @@ -2680,7 +2674,7 @@ module ts { else { var name = symbol.name; } - + var length = name.length; if (length >= 2 && name.charCodeAt(0) === CharacterCodes.doubleQuote && name.charCodeAt(length - 1) === CharacterCodes.doubleQuote) { return name.substring(1, length - 1); @@ -3219,7 +3213,6 @@ module ts { start += 1; end -= 1; } - return new ReferenceEntry(node.getSourceFile().filename, TypeScript.TextSpan.fromBounds(start, end), isWriteAccess(node)); } @@ -3327,6 +3320,71 @@ module ts { } } + function containErrors(diagnostics: Diagnostic[]): boolean { + return forEach(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error); + } + + function getEmitOutput(filename: string): EmitOutput { + synchronizeHostData(); + filename = TypeScript.switchToForwardSlashes(filename); + var compilerOptions = program.getCompilerOptions(); + var targetSourceFile = program.getSourceFile(filename); // Current selected file to be output + var emitToSingleFile = ts.shouldEmitToOwnFile(targetSourceFile, compilerOptions); + var emitDeclaration = compilerOptions.declaration; + var emitOutput: EmitOutput = { + outputFiles: [], + emitOutputStatus: undefined, + }; + + function getEmitOutputWriter(filename: string, data: string, writeByteOrderMark: boolean) { + emitOutput.outputFiles.push({ + name: filename, + writeByteOrderMark: writeByteOrderMark, + text: data + }); + } + + // Initialize writer for CompilerHost.writeFile + writer = getEmitOutputWriter; + + var syntacticDiagnostics: Diagnostic[] = []; + var containSyntacticErrors = false; + + if (emitToSingleFile) { + // Check only the file we want to emit + containSyntacticErrors = containErrors(program.getDiagnostics(targetSourceFile)); + } else { + // Check the syntactic of only sourceFiles that will get emitted into single output + // Terminate the process immediately if we encounter a syntax error from one of the sourceFiles + containSyntacticErrors = forEach(program.getSourceFiles(), sourceFile => { + if (!isExternalModuleOrDeclarationFile(sourceFile)) { + // If emit to a single file then we will check all files that do not have external module + return containErrors(program.getDiagnostics(sourceFile)); + } + return false; + }); + } + + if (containSyntacticErrors) { + // If there is a syntax error, terminate the process and report outputStatus + emitOutput.emitOutputStatus = EmitReturnStatus.AllOutputGenerationSkipped; + // Reset writer back to undefined to make sure that we produce an error message + // if CompilerHost.writeFile is called when we are not in getEmitOutput + writer = undefined; + return emitOutput; + } + + // Perform semantic and force a type check before emit to ensure that all symbols are updated + // EmitFiles will report if there is an error from TypeChecker and Emitter + // Depend whether we will have to emit into a single file or not either emit only selected file in the project, emit all files into a single file + var emitFilesResult = emitToSingleFile ? getFullTypeCheckChecker().emitFiles(targetSourceFile) : getFullTypeCheckChecker().emitFiles(); + emitOutput.emitOutputStatus = emitFilesResult.emitResultStatus; + + // Reset writer back to undefined to make sure that we produce an error message if CompilerHost.writeFile method is called when we are not in getEmitOutput + writer = undefined; + return emitOutput; + } + /// Syntactic features function getSyntaxTree(filename: string): TypeScript.SyntaxTree { filename = TypeScript.switchToForwardSlashes(filename); @@ -3867,7 +3925,7 @@ module ts { getFormattingEditsForRange: getFormattingEditsForRange, getFormattingEditsForDocument: getFormattingEditsForDocument, getFormattingEditsAfterKeystroke: getFormattingEditsAfterKeystroke, - getEmitOutput: (filename): EmitOutput => null, + getEmitOutput: getEmitOutput, }; } diff --git a/src/services/shims.ts b/src/services/shims.ts index c626bba0b4c..210a458b0be 100644 --- a/src/services/shims.ts +++ b/src/services/shims.ts @@ -53,6 +53,8 @@ module ts { getScriptSnapshot(fileName: string): ScriptSnapshotShim; getLocalizedDiagnosticMessages(): string; getCancellationToken(): CancellationToken; + getCurrentDirectory(): string; + getDefaultLibFilename(): string; } // @@ -147,19 +149,19 @@ module ts { getDefaultCompilationSettings(): string; } - /// TODO: delete this, it is only needed untill the VS interface is updated + /// TODO: delete this, it is only needed until the VS interface is updated enum LanguageVersion { EcmaScript3 = 0, EcmaScript5 = 1, } - enum ModuleGenTarget { + export enum ModuleGenTarget { Unspecified = 0, Synchronous = 1, Asynchronous = 2, } - interface CompilationSettings { + export interface CompilationSettings { propagateEnumConstants?: boolean; removeComments?: boolean; watch?: boolean; @@ -179,15 +181,18 @@ module ts { gatherDiagnostics?: boolean; codepage?: number; emitBOM?: boolean; + + // Declare indexer signature + [index: string]: any; } function languageVersionToScriptTarget(languageVersion: LanguageVersion): ScriptTarget { if (typeof languageVersion === "undefined") return undefined; switch (languageVersion) { - case LanguageVersion.EcmaScript3: return ScriptTarget.ES3; + case LanguageVersion.EcmaScript3: return ScriptTarget.ES3 case LanguageVersion.EcmaScript5: return ScriptTarget.ES5; - default: throw Error("unsuported LanguageVersion value: " + languageVersion); + default: throw Error("unsupported LanguageVersion value: " + languageVersion); } } @@ -198,7 +203,7 @@ module ts { case ModuleGenTarget.Asynchronous: return ModuleKind.AMD; case ModuleGenTarget.Synchronous: return ModuleKind.CommonJS; case ModuleGenTarget.Unspecified: return ModuleKind.None; - default: throw Error("unsuported ModuleGenTarget value: " + moduleGenTarget); + default: throw Error("unsupported ModuleGenTarget value: " + moduleGenTarget); } } @@ -208,7 +213,7 @@ module ts { switch (scriptTarget) { case ScriptTarget.ES3: return LanguageVersion.EcmaScript3; case ScriptTarget.ES5: return LanguageVersion.EcmaScript5; - default: throw Error("unsuported ScriptTarget value: " + scriptTarget); + default: throw Error("unsupported ScriptTarget value: " + scriptTarget); } } @@ -219,7 +224,7 @@ module ts { case ModuleKind.AMD: return ModuleGenTarget.Asynchronous; case ModuleKind.CommonJS: return ModuleGenTarget.Synchronous; case ModuleKind.None: return ModuleGenTarget.Unspecified; - default: throw Error("unsuported ModuleKind value: " + moduleKind); + default: throw Error("unsupported ModuleKind value: " + moduleKind); } } @@ -323,8 +328,8 @@ module ts { /// TODO: this should be pushed into VS. /// We can not ask the LS instance to resolve, as this will lead to asking the host about files it does not know about, - /// something it is not desinged to handle. for now make sure we never get a "noresolve == false". - /// This value should not matter, as the host runs resolution logic independentlly + /// something it is not designed to handle. for now make sure we never get a "noresolve == false". + /// This value should not matter, as the host runs resolution logic independently options.noResolve = true; return options; @@ -364,6 +369,14 @@ module ts { public getCancellationToken(): CancellationToken { return this.shimHost.getCancellationToken(); } + + public getDefaultLibFilename(): string { + return this.shimHost.getDefaultLibFilename(); + } + + public getCurrentDirectory(): string { + return this.shimHost.getCurrentDirectory(); + } } function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any): any { @@ -421,7 +434,7 @@ module ts { } // DISPOSE - // Ensure (almost) determinstic release of internal Javascript resources when + // Ensure (almost) deterministic release of internal Javascript resources when // some external native objects holds onto us (e.g. Com/Interop). public dispose(dummy: any): void { this.logger.log("dispose()"); @@ -866,7 +879,7 @@ module ts { } -/// TODO: this is used by VS, clean this up on both sides of the interfrace +/// TODO: this is used by VS, clean this up on both sides of the interface module TypeScript.Services { export var TypeScriptServicesFactory = ts.TypeScriptServicesFactory; } diff --git a/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline b/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline new file mode 100644 index 00000000000..6aec1296d81 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputDeclarationMultiFiles.baseline @@ -0,0 +1,30 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile1.js +var x = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); +Filename : tests/cases/fourslash/inputFile1.d.ts +declare var x: number; +declare class Bar { + x: string; + y: number; +} + +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile2.js +var x1 = "hello world"; +var Foo = (function () { + function Foo() { + } + return Foo; +})(); +Filename : tests/cases/fourslash/inputFile2.d.ts +declare var x1: string; +declare class Foo { + x: string; + y: number; +} + diff --git a/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline b/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline new file mode 100644 index 00000000000..ba40a69e39d --- /dev/null +++ b/tests/baselines/reference/getEmitOutputDeclarationSingleFile.baseline @@ -0,0 +1,26 @@ +EmitOutputStatus : Succeeded +Filename : declSingleFile.js +var x = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); +var x1 = "hello world"; +var Foo = (function () { + function Foo() { + } + return Foo; +})(); +Filename : declSingleFile.d.ts +declare var x: number; +declare class Bar { + x: string; + y: number; +} +declare var x1: string; +declare class Foo { + x: string; + y: number; +} + diff --git a/tests/baselines/reference/getEmitOutputMapRoots.baseline b/tests/baselines/reference/getEmitOutputMapRoots.baseline new file mode 100644 index 00000000000..2630257b03a --- /dev/null +++ b/tests/baselines/reference/getEmitOutputMapRoots.baseline @@ -0,0 +1,11 @@ +EmitOutputStatus : Succeeded +Filename : declSingleFile.js.map +{"version":3,"file":"declSingleFile.js","sourceRoot":"","sources":["../tests/cases/fourslash/inputFile.ts"],"names":["M","M.constructor"],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : declSingleFile.js +var x = 109; +var foo = "hello world"; +var M = (function () { + function M() { + } + return M; +})(); +//# sourceMappingURL=mapRootDir/declSingleFile.js.map diff --git a/tests/baselines/reference/getEmitOutputNoErrors.baseline b/tests/baselines/reference/getEmitOutputNoErrors.baseline new file mode 100644 index 00000000000..000ddb29ef5 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputNoErrors.baseline @@ -0,0 +1,9 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile.js +var x; +var M = (function () { + function M() { + } + return M; +})(); + diff --git a/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline b/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline new file mode 100644 index 00000000000..eaca7cda673 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputOnlyOneFile.baseline @@ -0,0 +1,9 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile2.js +var x; +var Foo = (function () { + function Foo() { + } + return Foo; +})(); + diff --git a/tests/baselines/reference/getEmitOutputSingleFile.baseline b/tests/baselines/reference/getEmitOutputSingleFile.baseline new file mode 100644 index 00000000000..fd3d2af4a5a --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSingleFile.baseline @@ -0,0 +1,15 @@ +EmitOutputStatus : Succeeded +Filename : outputDir/singleFile.js +var x; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); +var x; +var Foo = (function () { + function Foo() { + } + return Foo; +})(); + diff --git a/tests/baselines/reference/getEmitOutputSingleFile2.baseline b/tests/baselines/reference/getEmitOutputSingleFile2.baseline new file mode 100644 index 00000000000..aac50ee87cb --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSingleFile2.baseline @@ -0,0 +1,32 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile3.js +exports.foo = 10; +exports.bar = "hello world"; +Filename : tests/cases/fourslash/inputFile3.d.ts +export declare var foo: number; +export declare var bar: string; +Filename : declSingleFile.js +var x = 5; +var Bar = (function () { + function Bar() { + } + return Bar; +})(); +var x1 = "hello world"; +var Foo = (function () { + function Foo() { + } + return Foo; +})(); +Filename : declSingleFile.d.ts +declare var x: number; +declare class Bar { + x: string; + y: number; +} +declare var x1: string; +declare class Foo { + x: string; + y: number; +} + diff --git a/tests/baselines/reference/getEmitOutputSourceMap.baseline b/tests/baselines/reference/getEmitOutputSourceMap.baseline new file mode 100644 index 00000000000..e3b7a47e125 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSourceMap.baseline @@ -0,0 +1,11 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile.js.map +{"version":3,"file":"inputFile.js","sourceRoot":"","sources":["inputFile.ts"],"names":["M","M.constructor"],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : tests/cases/fourslash/inputFile.js +var x = 109; +var foo = "hello world"; +var M = (function () { + function M() { + } + return M; +})(); +//# sourceMappingURL=inputFile.js.map diff --git a/tests/baselines/reference/getEmitOutputSourceMap2.baseline b/tests/baselines/reference/getEmitOutputSourceMap2.baseline new file mode 100644 index 00000000000..d6745389e3a --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSourceMap2.baseline @@ -0,0 +1,19 @@ +EmitOutputStatus : Succeeded +Filename : sample/outDir/inputFile1.js.map +{"version":3,"file":"inputFile1.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile1.ts"],"names":["M","M.constructor"],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : sample/outDir/inputFile1.js +var x = 109; +var foo = "hello world"; +var M = (function () { + function M() { + } + return M; +})(); +//# sourceMappingURL=inputFile1.js.map +EmitOutputStatus : Succeeded +Filename : sample/outDir/inputFile2.js.map +{"version":3,"file":"inputFile2.js","sourceRoot":"","sources":["../../tests/cases/fourslash/inputFile2.ts"],"names":[],"mappings":"AAAA,IAAI,KAAK,GAAG,aAAa,CAAC;AAC1B,EAAE,CAAC,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC;IACvB,IAAI,CAAC,GAAG,EAAE,CAAC;AACd,CAAC"}Filename : sample/outDir/inputFile2.js +var intro = "hello world"; +if (intro !== undefined) { + var k = 10; +} +//# sourceMappingURL=inputFile2.js.map diff --git a/tests/baselines/reference/getEmitOutputSourceRoot.baseline b/tests/baselines/reference/getEmitOutputSourceRoot.baseline new file mode 100644 index 00000000000..d8cba7ddd97 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSourceRoot.baseline @@ -0,0 +1,11 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile.js.map +{"version":3,"file":"inputFile.js","sourceRoot":"sourceRootDir/","sources":["inputFile.ts"],"names":["M","M.constructor"],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : tests/cases/fourslash/inputFile.js +var x = 109; +var foo = "hello world"; +var M = (function () { + function M() { + } + return M; +})(); +//# sourceMappingURL=inputFile.js.map diff --git a/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline b/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline new file mode 100644 index 00000000000..eec0b05ecaa --- /dev/null +++ b/tests/baselines/reference/getEmitOutputSourceRootMultiFiles.baseline @@ -0,0 +1,21 @@ +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile1.js.map +{"version":3,"file":"inputFile1.js","sourceRoot":"sourceRootDir/","sources":["inputFile1.ts"],"names":["M","M.constructor"],"mappings":"AAAA,IAAI,CAAC,GAAG,GAAG,CAAC;AACZ,IAAI,GAAG,GAAG,aAAa,CAAC;AACxB,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : tests/cases/fourslash/inputFile1.js +var x = 109; +var foo = "hello world"; +var M = (function () { + function M() { + } + return M; +})(); +//# sourceMappingURL=inputFile1.js.map +EmitOutputStatus : Succeeded +Filename : tests/cases/fourslash/inputFile2.js.map +{"version":3,"file":"inputFile2.js","sourceRoot":"sourceRootDir/","sources":["inputFile2.ts"],"names":["C","C.constructor"],"mappings":"AAAA,IAAI,GAAG,GAAG,wBAAwB,CAAC;AACnC,IAAM,CAAC;IAAPA,SAAMA,CAACA;IAGPC,CAACA;IAADD,QAACA;AAADA,CAACA,AAHD,IAGC"}Filename : tests/cases/fourslash/inputFile2.js +var bar = "hello world Typescript"; +var C = (function () { + function C() { + } + return C; +})(); +//# sourceMappingURL=inputFile2.js.map diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline new file mode 100644 index 00000000000..13df5b18c36 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors.baseline @@ -0,0 +1,12 @@ +EmitOutputStatus : EmitErrorsEncountered +Filename : tests/cases/fourslash/inputFile.js +var M; +(function (M) { + var C = (function () { + function C() { + } + return C; + })(); + M.foo = new C(); +})(M || (M = {})); + diff --git a/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline new file mode 100644 index 00000000000..c05c01eb91f --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithEmitterErrors2.baseline @@ -0,0 +1,14 @@ +EmitOutputStatus : EmitErrorsEncountered +Filename : tests/cases/fourslash/inputFile.js +define(["require", "exports"], function (require, exports) { + var C = (function () { + function C() { + } + return C; + })(); + var M; + (function (M) { + M.foo = new C(); + })(M = exports.M || (exports.M = {})); +}); + diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline new file mode 100644 index 00000000000..dabcd85e854 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrors.baseline @@ -0,0 +1,4 @@ +EmitOutputStatus : JSGeneratedWithSemanticErrors +Filename : tests/cases/fourslash/inputFile.js +var x = "hello world"; + diff --git a/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline new file mode 100644 index 00000000000..0dd36c74557 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSemanticErrors2.baseline @@ -0,0 +1,4 @@ +EmitOutputStatus : DeclarationGenerationSkipped +Filename : tests/cases/fourslash/inputFile.js +var x = "hello world"; + diff --git a/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline b/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline new file mode 100644 index 00000000000..a5d5d2eb9d7 --- /dev/null +++ b/tests/baselines/reference/getEmitOutputWithSyntaxErrors.baseline @@ -0,0 +1,2 @@ +EmitOutputStatus : AllOutputGenerationSkipped + diff --git a/tests/cases/fourslash_old/eval.ts b/tests/cases/fourslash/eval.ts similarity index 100% rename from tests/cases/fourslash_old/eval.ts rename to tests/cases/fourslash/eval.ts diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index e1b1e26c3c2..ccbaa34b900 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -44,6 +44,16 @@ enum TypingFidelity { High = FourSlash.TypingFidelity.High } +// Return code used by getEmitOutput function to indicate status of the function +// It is a duplicate of the one in types.ts to expose it to testcases in fourslash +enum EmitReturnStatus { + Succeeded = 0, // All outputs generated as requested (.js, .map, .d.ts), no errors reported + AllOutputGenerationSkipped = 1, // No .js generated because of syntax errors, or compiler options errors, nothing generated + JSGeneratedWithSemanticErrors = 2, // .js and .map generated with semantic errors + DeclarationGenerationSkipped = 3, // .d.ts generation skipped because of semantic errors or declaration emitter specific errors; Output .js with semantic errors + EmitErrorsEncountered = 4 // Emitter errors occurred during emitting process +} + module FourSlashInterface { declare var FourSlash; @@ -307,6 +317,10 @@ module FourSlashInterface { FourSlash.currentTestState.baselineCurrentFileNameOrDottedNameSpans(); } + public baselineGetEmitOutput() { + FourSlash.currentTestState.baselineGetEmitOutput(); + } + public nameOrDottedNameSpanTextIs(text: string) { FourSlash.currentTestState.verifyCurrentNameOrDottedNameSpanText(text); } diff --git a/tests/cases/fourslash/getEmitOutputDeclarationMultiFiles.ts b/tests/cases/fourslash/getEmitOutputDeclarationMultiFiles.ts new file mode 100644 index 00000000000..b9c7f5a0db9 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputDeclarationMultiFiles.ts @@ -0,0 +1,22 @@ +/// + +// @BaselineFile: getEmitOutputDeclarationMultiFiles.baseline +// @declaration: true + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// var x: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var x1: string = "hello world"; +//// class Foo{ +//// x : string; +//// y : number; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputDeclarationSingleFile.ts b/tests/cases/fourslash/getEmitOutputDeclarationSingleFile.ts new file mode 100644 index 00000000000..b8e9c58f5b0 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputDeclarationSingleFile.ts @@ -0,0 +1,22 @@ +/// + +// @BaselineFile: getEmitOutputDeclarationSingleFile.baseline +// @declaration: true +// @out: declSingleFile.js + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// var x: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +//// var x1: string = "hello world"; +//// class Foo{ +//// x : string; +//// y : number; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputMapRoot.ts b/tests/cases/fourslash/getEmitOutputMapRoot.ts new file mode 100644 index 00000000000..15932d41c32 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputMapRoot.ts @@ -0,0 +1,17 @@ +/// + +// @BaselineFile: getEmitOutputMapRoots.baseline +// @out: declSingleFile.js +// @sourceMap: true +// @mapRoot: mapRootDir/ + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x = 109; +//// var foo = "hello world"; +//// class M { +//// x: number; +//// y: string; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputNoErrors.ts b/tests/cases/fourslash/getEmitOutputNoErrors.ts new file mode 100644 index 00000000000..b48a86a03ab --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputNoErrors.ts @@ -0,0 +1,12 @@ +/// + +// @BaselineFile: getEmitOutputNoErrors.baseline +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x; +//// class M { +//// x: number; +//// y: string; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputOnlyOneFile.ts b/tests/cases/fourslash/getEmitOutputOnlyOneFile.ts new file mode 100644 index 00000000000..2ad822741f2 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputOnlyOneFile.ts @@ -0,0 +1,20 @@ +/// + +// @BaselineFile: getEmitOutputOnlyOneFile.baseline + +// @Filename: inputFile1.ts +//// var x: any; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var x: any; +//// class Foo{ +//// x : string; +//// y : number +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSingleFile.ts b/tests/cases/fourslash/getEmitOutputSingleFile.ts new file mode 100644 index 00000000000..ec774149f4b --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSingleFile.ts @@ -0,0 +1,21 @@ +/// + +// @BaselineFile: getEmitOutputSingleFile.baseline +// @out: outputDir/singleFile.js + +// @Filename: inputFile1.ts +//// var x: any; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var x: any; +//// class Foo{ +//// x : string; +//// y : number +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSingleFile2.ts b/tests/cases/fourslash/getEmitOutputSingleFile2.ts new file mode 100644 index 00000000000..bcb1012a6ea --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSingleFile2.ts @@ -0,0 +1,27 @@ +/// + +// @BaselineFile: getEmitOutputSingleFile2.baseline +// @declaration: true +// @out: declSingleFile.js +// @outDir: tests/cases/fourslash/ + +// @Filename: inputFile1.ts +//// var x: number = 5; +//// class Bar { +//// x : string; +//// y : number +//// } + +// @Filename: inputFile2.ts +//// var x1: string = "hello world"; +//// class Foo{ +//// x : string; +//// y : number; +//// } + +// @Filename: inputFile3.ts +// @emitThisFile: true +////export var foo = 10; +////export var bar = "hello world" + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSourceMap.ts b/tests/cases/fourslash/getEmitOutputSourceMap.ts new file mode 100644 index 00000000000..df02af35ec3 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSourceMap.ts @@ -0,0 +1,15 @@ +/// + +// @BaselineFile: getEmitOutputSourceMap.baseline +// @sourceMap: true + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x = 109; +//// var foo = "hello world"; +//// class M { +//// x: number; +//// y: string; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSourceMap2.ts b/tests/cases/fourslash/getEmitOutputSourceMap2.ts new file mode 100644 index 00000000000..a8b43328ea5 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSourceMap2.ts @@ -0,0 +1,23 @@ +/// + +// @BaselineFile: getEmitOutputSourceMap2.baseline +// @sourceMap: true +// @outDir: sample/outDir + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// var x = 109; +//// var foo = "hello world"; +//// class M { +//// x: number; +//// y: string; +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var intro = "hello world"; +//// if (intro !== undefined) { +//// var k = 10; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSourceRoot.ts b/tests/cases/fourslash/getEmitOutputSourceRoot.ts new file mode 100644 index 00000000000..b260e593098 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSourceRoot.ts @@ -0,0 +1,16 @@ +/// + +// @BaselineFile: getEmitOutputSourceRoot.baseline +// @sourceMap: true +// @sourceRoot: sourceRootDir/ + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x = 109; +//// var foo = "hello world"; +//// class M { +//// x: number; +//// y: string; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSourceRootMultiFiles.ts b/tests/cases/fourslash/getEmitOutputSourceRootMultiFiles.ts new file mode 100644 index 00000000000..bddf9e423ce --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputSourceRootMultiFiles.ts @@ -0,0 +1,24 @@ +/// + +// @BaselineFile: getEmitOutputSourceRootMultiFiles.baseline +// @sourceMap: true +// @sourceRoot: sourceRootDir/ + +// @Filename: inputFile1.ts +// @emitThisFile: true +//// var x = 109; +//// var foo = "hello world"; +//// class M { +//// x: number; +//// y: string; +//// } + +// @Filename: inputFile2.ts +// @emitThisFile: true +//// var bar = "hello world Typescript"; +//// class C { +//// x: number; +//// y: string[]; +//// } + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithEmitterErrors.ts b/tests/cases/fourslash/getEmitOutputWithEmitterErrors.ts new file mode 100644 index 00000000000..ba643f996d7 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithEmitterErrors.ts @@ -0,0 +1,15 @@ +/// + +// @BaselineFile: getEmitOutputWithEmitterErrors.baseline +// @declaration: true + +// @Filename: inputFile.ts +// @emitThisFile: true +////module M { +//// class C { } +//// export var foo = new C(); +////} + + +// Only generate javscript file. The semantic error should not affect it +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithEmitterErrors2.ts b/tests/cases/fourslash/getEmitOutputWithEmitterErrors2.ts new file mode 100644 index 00000000000..5240a102a28 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithEmitterErrors2.ts @@ -0,0 +1,14 @@ +/// + +// @BaselineFile: getEmitOutputWithEmitterErrors2.baseline +// @declaration: true +// @module: AMD + +// @Filename: inputFile.ts +// @emitThisFile: true +////class C { } +////export module M { +//// export var foo = new C(); +////} + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSemanticErrors.ts b/tests/cases/fourslash/getEmitOutputWithSemanticErrors.ts new file mode 100644 index 00000000000..b4e3a50b0e8 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSemanticErrors.ts @@ -0,0 +1,9 @@ +/// + +// @BaselineFile: getEmitOutputWithSemanticErrors.baseline + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x:number = "hello world"; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSemanticErrors2.ts b/tests/cases/fourslash/getEmitOutputWithSemanticErrors2.ts new file mode 100644 index 00000000000..c67ef0fd29d --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSemanticErrors2.ts @@ -0,0 +1,10 @@ +/// + +// @BaselineFile: getEmitOutputWithSemanticErrors2.baseline +// @declaration: true + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x:number = "hello world"; + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputWithSyntaxErrors.ts b/tests/cases/fourslash/getEmitOutputWithSyntaxErrors.ts new file mode 100644 index 00000000000..87e9bb076a5 --- /dev/null +++ b/tests/cases/fourslash/getEmitOutputWithSyntaxErrors.ts @@ -0,0 +1,9 @@ +/// + +// @BaselineFile: getEmitOutputWithSyntaxErrors.baseline + +// @Filename: inputFile.ts +// @emitThisFile: true +//// var x: + +verify.baselineGetEmitOutput(); \ No newline at end of file diff --git a/tests/cases/fourslash_old/moduleReferenceValue.ts b/tests/cases/fourslash/moduleReferenceValue.ts similarity index 100% rename from tests/cases/fourslash_old/moduleReferenceValue.ts rename to tests/cases/fourslash/moduleReferenceValue.ts diff --git a/tests/cases/fourslash_old/runtimeBehaviorTests.ts b/tests/cases/fourslash/runtimeBehaviorTests.ts similarity index 100% rename from tests/cases/fourslash_old/runtimeBehaviorTests.ts rename to tests/cases/fourslash/runtimeBehaviorTests.ts