diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 0f8820c0610..f279dea186a 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -16,6 +16,8 @@ module ts { var emptySymbols: SymbolTable = {}; var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || ScriptTarget.ES3; + var emitResolver = createResolver(); var checker: TypeChecker = { @@ -6358,7 +6360,7 @@ module ts { function checkTaggedTemplateExpression(node: TaggedTemplateExpression): Type { // Grammar checking - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { grammarErrorOnFirstToken(node.template, Diagnostics.Tagged_templates_are_only_available_when_targeting_ECMAScript_6_and_higher); } @@ -10056,7 +10058,7 @@ module ts { globalRegExpType = getGlobalType("RegExp"); // If we're in ES6 mode, load the TemplateStringsArray. // Otherwise, default to 'unknown' for the purposes of type checking in LS scenarios. - globalTemplateStringsArrayType = compilerOptions.target >= ScriptTarget.ES6 + globalTemplateStringsArrayType = languageVersion >= ScriptTarget.ES6 ? getGlobalType("TemplateStringsArray") : unknownType; anyArrayType = createArrayType(anyType); @@ -10429,7 +10431,7 @@ module ts { return; var computedPropertyName = node; - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { grammarErrorOnNode(node, Diagnostics.Computed_property_names_are_only_available_when_targeting_ECMAScript_6_and_higher); } else if (computedPropertyName.expression.kind === SyntaxKind.BinaryExpression && (computedPropertyName.expression).operator === SyntaxKind.CommaToken) { @@ -10529,7 +10531,7 @@ module ts { function checkGrammarAccessor(accessor: MethodDeclaration): boolean { var kind = accessor.kind; - if (compilerOptions.target < ScriptTarget.ES5) { + if (languageVersion < ScriptTarget.ES5) { return grammarErrorOnNode(accessor.name, Diagnostics.Accessors_are_only_available_when_targeting_ECMAScript_5_and_higher); } else if (isInAmbientContext(accessor)) { @@ -10734,7 +10736,7 @@ module ts { return grammarErrorAtPos(getSourceFileOfNode(declarationList), declarations.pos, declarations.end - declarations.pos, Diagnostics.Variable_declaration_list_cannot_be_empty); } - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { if (isLet(declarationList)) { return grammarErrorOnFirstToken(declarationList, Diagnostics.let_declarations_are_only_available_when_targeting_ECMAScript_6_and_higher); } @@ -10836,7 +10838,7 @@ module ts { function grammarErrorOnFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { var sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { - var scanner = createScanner(compilerOptions.target, /*skipTrivia*/ true, sourceFile.text); + var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text); var start = scanToken(scanner, node.pos); diagnostics.push(createFileDiagnostic(sourceFile, start, scanner.getTextPos() - start, message, arg0, arg1, arg2)); return true; @@ -10978,7 +10980,7 @@ module ts { if (node.parserContextFlags & ParserContextFlags.StrictMode) { return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_allowed_in_strict_mode); } - else if (compilerOptions.target >= ScriptTarget.ES5) { + else if (languageVersion >= ScriptTarget.ES5) { return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher); } } @@ -10987,7 +10989,7 @@ module ts { function grammarErrorAfterFirstToken(node: Node, message: DiagnosticMessage, arg0?: any, arg1?: any, arg2?: any): boolean { var sourceFile = getSourceFileOfNode(node); if (!hasParseDiagnostics(sourceFile)) { - var scanner = createScanner(compilerOptions.target, /*skipTrivia*/ true, sourceFile.text); + var scanner = createScanner(languageVersion, /*skipTrivia*/ true, sourceFile.text); scanToken(scanner, node.pos); diagnostics.push(createFileDiagnostic(sourceFile, scanner.getTextPos(), 0, message, arg0, arg1, arg2)); return true; diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index fa31f25f7c3..23bbba5c6ca 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -33,6 +33,10 @@ module ts { type: "boolean", description: Diagnostics.Print_this_message, }, + { + name: "listFiles", + type: "boolean", + }, { name: "locale", type: "string", @@ -40,6 +44,7 @@ module ts { { name: "mapRoot", type: "string", + isFilePath: true, description: Diagnostics.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations, paramType: Diagnostics.LOCATION, }, @@ -90,6 +95,7 @@ module ts { { name: "outDir", type: "string", + isFilePath: true, description: Diagnostics.Redirect_output_structure_to_the_directory, paramType: Diagnostics.DIRECTORY, }, @@ -98,6 +104,14 @@ module ts { type: "boolean", description: Diagnostics.Do_not_erase_const_enum_declarations_in_generated_code }, + { + name: "project", + shortName: "p", + type: "string", + isFilePath: true, + description: Diagnostics.Compile_the_project_in_the_given_directory, + paramType: Diagnostics.DIRECTORY + }, { name: "removeComments", type: "boolean", @@ -111,6 +125,7 @@ module ts { { name: "sourceRoot", type: "string", + isFilePath: true, description: Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations, paramType: Diagnostics.LOCATION, }, @@ -141,26 +156,19 @@ module ts { } ]; - var shortOptionNames: Map = {}; - var optionNameMap: Map = {}; - - forEach(optionDeclarations, option => { - optionNameMap[option.name.toLowerCase()] = option; - - if (option.shortName) { - shortOptionNames[option.shortName] = option.name; - } - }); - export function parseCommandLine(commandLine: string[]): ParsedCommandLine { - // Set default compiler option values - var options: CompilerOptions = { - target: ScriptTarget.ES3, - module: ModuleKind.None - }; + var options: CompilerOptions = {}; var filenames: string[] = []; var errors: Diagnostic[] = []; + var shortOptionNames: Map = {}; + var optionNameMap: Map = {}; + forEach(optionDeclarations, option => { + optionNameMap[option.name.toLowerCase()] = option; + if (option.shortName) { + shortOptionNames[option.shortName] = option.name; + } + }); parseStrings(commandLine); return { options, @@ -256,4 +264,84 @@ module ts { parseStrings(args); } } + + export function readConfigFile(filename: string): any { + try { + var text = sys.readFile(filename); + return /\S/.test(text) ? JSON.parse(text) : {}; + } + catch (e) { + } + } + + export function parseConfigFile(json: any, basePath?: string): ParsedCommandLine { + var errors: Diagnostic[] = []; + + return { + options: getCompilerOptions(), + filenames: getFiles(), + errors + }; + + function getCompilerOptions(): CompilerOptions { + var options: CompilerOptions = {}; + var optionNameMap: Map = {}; + forEach(optionDeclarations, option => { + optionNameMap[option.name] = option; + }); + var jsonOptions = json["compilerOptions"]; + if (jsonOptions) { + for (var id in jsonOptions) { + if (hasProperty(optionNameMap, id)) { + var opt = optionNameMap[id]; + var optType = opt.type; + var value = jsonOptions[id]; + var expectedType = typeof optType === "string" ? optType : "string"; + if (typeof value === expectedType) { + if (typeof optType !== "string") { + var key = value.toLowerCase(); + if (hasProperty(optType, key)) { + value = optType[key]; + } + else { + errors.push(createCompilerDiagnostic(opt.error)); + value = 0; + } + } + if (opt.isFilePath) { + value = normalizePath(combinePaths(basePath, value)); + } + options[opt.name] = value; + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, id, expectedType)); + } + } + else { + errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, id)); + } + } + } + return options; + } + + function getFiles(): string[] { + var files: string[] = []; + if (hasProperty(json, "files")) { + if (json["files"] instanceof Array) { + var files = map(json["files"], s => combinePaths(basePath, s)); + } + } + else { + var sysFiles = sys.readDirectory(basePath, ".ts"); + for (var i = 0; i < sysFiles.length; i++) { + var name = sysFiles[i]; + if (!fileExtensionIs(name, ".d.ts") || !contains(sysFiles, name.substr(0, name.length - 5) + ".ts")) { + files.push(name); + } + } + } + return files; + } + } } diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 2e5a471bb27..4a710c035ba 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -178,6 +178,19 @@ module ts { return result; } + export function extend(first: Map, second: Map): Map { + var result: Map = {}; + for (var id in first) { + result[id] = first[id]; + } + for (var id in second) { + if (!hasProperty(result, id)) { + result[id] = second[id]; + } + } + return result; + } + export function forEachValue(map: Map, callback: (value: T) => U): U { var result: U; for (var id in map) { @@ -568,7 +581,7 @@ module ts { export function combinePaths(path1: string, path2: string) { if (!(path1 && path1.length)) return path2; if (!(path2 && path2.length)) return path1; - if (path2.charAt(0) === directorySeparator) return path2; + if (getRootLength(path2) !== 0) return path2; if (path1.charAt(path1.length - 1) === directorySeparator) return path1 + path2; return path1 + directorySeparator + path2; } diff --git a/src/compiler/diagnosticInformationMap.generated.ts b/src/compiler/diagnosticInformationMap.generated.ts index 9d62ee0e030..64511ad8072 100644 --- a/src/compiler/diagnosticInformationMap.generated.ts +++ b/src/compiler/diagnosticInformationMap.generated.ts @@ -380,11 +380,13 @@ module ts { Cannot_read_file_0_Colon_1: { code: 5012, category: DiagnosticCategory.Error, key: "Cannot read file '{0}': {1}" }, Unsupported_file_encoding: { code: 5013, category: DiagnosticCategory.Error, key: "Unsupported file encoding." }, Unknown_compiler_option_0: { code: 5023, category: DiagnosticCategory.Error, key: "Unknown compiler option '{0}'." }, + Compiler_option_0_requires_a_value_of_type_1: { code: 5024, category: DiagnosticCategory.Error, key: "Compiler option '{0}' requires a value of type {1}." }, Could_not_write_file_0_Colon_1: { code: 5033, category: DiagnosticCategory.Error, key: "Could not write file '{0}': {1}" }, - Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5038, category: DiagnosticCategory.Error, key: "Option mapRoot cannot be specified without specifying sourcemap option." }, - Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5039, category: DiagnosticCategory.Error, key: "Option sourceRoot cannot be specified without specifying sourcemap option." }, - Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option noEmit cannot be specified with option out or outDir." }, - Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option noEmit cannot be specified with option declaration." }, + Option_mapRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5038, category: DiagnosticCategory.Error, key: "Option 'mapRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_sourceRoot_cannot_be_specified_without_specifying_sourcemap_option: { code: 5039, category: DiagnosticCategory.Error, key: "Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option." }, + Option_noEmit_cannot_be_specified_with_option_out_or_outDir: { code: 5040, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'out' or 'outDir'." }, + Option_noEmit_cannot_be_specified_with_option_declaration: { code: 5041, category: DiagnosticCategory.Error, key: "Option 'noEmit' cannot be specified with option 'declaration'." }, + Option_project_cannot_be_mixed_with_source_files_on_a_command_line: { code: 5042, category: DiagnosticCategory.Error, key: "Option 'project' cannot be mixed with source files on a command line." }, Concatenate_and_emit_output_to_single_file: { code: 6001, category: DiagnosticCategory.Message, key: "Concatenate and emit output to single file." }, Generates_corresponding_d_ts_file: { code: 6002, category: DiagnosticCategory.Message, key: "Generates corresponding '.d.ts' file." }, Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations: { code: 6003, category: DiagnosticCategory.Message, key: "Specifies the location where debugger should locate map files instead of generated locations." }, @@ -399,6 +401,7 @@ module ts { Specify_module_code_generation_Colon_commonjs_or_amd: { code: 6016, category: DiagnosticCategory.Message, key: "Specify module code generation: 'commonjs' or 'amd'" }, Print_this_message: { code: 6017, category: DiagnosticCategory.Message, key: "Print this message." }, Print_the_compiler_s_version: { code: 6019, category: DiagnosticCategory.Message, key: "Print the compiler's version." }, + Compile_the_project_in_the_given_directory: { code: 6020, category: DiagnosticCategory.Message, key: "Compile the project in the given directory." }, Syntax_Colon_0: { code: 6023, category: DiagnosticCategory.Message, key: "Syntax: {0}" }, options: { code: 6024, category: DiagnosticCategory.Message, key: "options" }, file: { code: 6025, category: DiagnosticCategory.Message, key: "file" }, @@ -406,7 +409,7 @@ module ts { Options_Colon: { code: 6027, category: DiagnosticCategory.Message, key: "Options:" }, Version_0: { code: 6029, category: DiagnosticCategory.Message, key: "Version {0}" }, Insert_command_line_options_and_files_from_a_file: { code: 6030, category: DiagnosticCategory.Message, key: "Insert command line options and files from a file." }, - File_change_detected_Compiling: { code: 6032, category: DiagnosticCategory.Message, key: "File change detected. Compiling..." }, + File_change_detected_Starting_incremental_compilation: { code: 6032, category: DiagnosticCategory.Message, key: "File change detected. Starting incremental compilation..." }, KIND: { code: 6034, category: DiagnosticCategory.Message, key: "KIND" }, FILE: { code: 6035, category: DiagnosticCategory.Message, key: "FILE" }, VERSION: { code: 6036, category: DiagnosticCategory.Message, key: "VERSION" }, diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index ee962edc3a0..6c33fa42013 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -1618,26 +1618,34 @@ "category": "Error", "code": 5023 }, + "Compiler option '{0}' requires a value of type {1}.": { + "category": "Error", + "code": 5024 + }, "Could not write file '{0}': {1}": { "category": "Error", "code": 5033 }, - "Option mapRoot cannot be specified without specifying sourcemap option.": { + "Option 'mapRoot' cannot be specified without specifying 'sourcemap' option.": { "category": "Error", "code": 5038 }, - "Option sourceRoot cannot be specified without specifying sourcemap option.": { + "Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option.": { "category": "Error", "code": 5039 }, - "Option noEmit cannot be specified with option out or outDir.": { + "Option 'noEmit' cannot be specified with option 'out' or 'outDir'.": { "category": "Error", "code": 5040 }, - "Option noEmit cannot be specified with option declaration.": { + "Option 'noEmit' cannot be specified with option 'declaration'.": { "category": "Error", "code": 5041 }, + "Option 'project' cannot be mixed with source files on a command line.": { + "category": "Error", + "code": 5042 + }, "Concatenate and emit output to single file.": { "category": "Message", "code": 6001 @@ -1694,6 +1702,10 @@ "category": "Message", "code": 6019 }, + "Compile the project in the given directory.": { + "category": "Message", + "code": 6020 + }, "Syntax: {0}": { "category": "Message", "code": 6023 @@ -1722,7 +1734,7 @@ "category": "Message", "code": 6030 }, - "File change detected. Compiling...": { + "File change detected. Starting incremental compilation...": { "category": "Message", "code": 6032 }, diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index d82e577971d..dafd03717a6 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -170,9 +170,10 @@ module ts { function writeCommentRange(currentSourceFile: SourceFile, writer: EmitTextWriter, comment: CommentRange, newLine: string){ if (currentSourceFile.text.charCodeAt(comment.pos + 1) === CharacterCodes.asterisk) { var firstCommentLineAndCharacter = currentSourceFile.getLineAndCharacterFromPosition(comment.pos); + var lastLine = currentSourceFile.getLineStarts().length; var firstCommentLineIndent: number; for (var pos = comment.pos, currentLine = firstCommentLineAndCharacter.line; pos < comment.end; currentLine++) { - var nextLineStart = currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1); + var nextLineStart = currentLine === lastLine ? (comment.end + 1) : currentSourceFile.getPositionFromLineAndCharacter(currentLine + 1, /*character*/1); if (pos !== comment.pos) { // If we are not emitting first line, we need to write the spaces to adjust the alignment @@ -339,6 +340,7 @@ module ts { function emitDeclarations(host: EmitHost, resolver: EmitResolver, diagnostics: Diagnostic[], jsFilePath: string, root?: SourceFile): DeclarationEmit { var newLine = host.getNewLine(); var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || ScriptTarget.ES3; var write: (s: string) => void; var writeLine: () => void; @@ -1473,6 +1475,7 @@ module ts { export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile?: SourceFile): EmitResult { // var program = resolver.getProgram(); var compilerOptions = host.getCompilerOptions(); + var languageVersion = compilerOptions.target || ScriptTarget.ES3; var sourceMapDataList: SourceMapData[] = compilerOptions.sourceMap ? [] : undefined; var diagnostics: Diagnostic[] = []; var newLine = host.getNewLine(); @@ -2021,14 +2024,14 @@ module ts { } function emitLiteral(node: LiteralExpression) { - var text = compilerOptions.target < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind) ? getTemplateLiteralAsStringLiteral(node) : + var text = languageVersion < ScriptTarget.ES6 && isTemplateLiteralKind(node.kind) ? getTemplateLiteralAsStringLiteral(node) : node.parent ? getSourceTextOfNodeFromSourceFile(currentSourceFile, node) : node.text; if (compilerOptions.sourceMap && (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) { writer.writeLiteral(text); } // For version below ES6, emit binary integer literal and octal integer literal in canonical form - else if (compilerOptions.target < ScriptTarget.ES6 && node.kind === SyntaxKind.NumericLiteral && isBinaryOrOctalIntegerLiteral(text)) { + else if (languageVersion < ScriptTarget.ES6 && node.kind === SyntaxKind.NumericLiteral && isBinaryOrOctalIntegerLiteral(text)) { write(node.text); } else { @@ -2043,7 +2046,7 @@ module ts { function emitTemplateExpression(node: TemplateExpression): void { // In ES6 mode and above, we can simply emit each portion of a template in order, but in // ES3 & ES5 we must convert the template expression into a series of string concatenations. - if (compilerOptions.target >= ScriptTarget.ES6) { + if (languageVersion >= ScriptTarget.ES6) { forEachChild(node, emit); return; } @@ -2150,7 +2153,7 @@ module ts { // // TODO (drosen): Note that we need to account for the upcoming 'yield' and // spread ('...') unary operators that are anticipated for ES6. - Debug.assert(compilerOptions.target <= ScriptTarget.ES5); + Debug.assert(languageVersion < ScriptTarget.ES6); switch (expression.kind) { case SyntaxKind.BinaryExpression: switch ((expression).operator) { @@ -2335,7 +2338,7 @@ module ts { write("[]"); return; } - if (compilerOptions.target >= ScriptTarget.ES6) { + if (languageVersion >= ScriptTarget.ES6) { write("["); emitList(elements, 0, elements.length, /*multiLine*/(node.flags & NodeFlags.MultiLine) !== 0, /*trailingComma*/ elements.hasTrailingComma); @@ -2385,7 +2388,7 @@ module ts { write(" "); } emitList(properties, 0, properties.length, /*multiLine*/ multiLine, - /*trailingComma*/ properties.hasTrailingComma && compilerOptions.target >= ScriptTarget.ES5); + /*trailingComma*/ properties.hasTrailingComma && languageVersion >= ScriptTarget.ES5); if (!multiLine) { write(" "); } @@ -2405,7 +2408,7 @@ module ts { } emitLeadingComments(node); emit(node.name); - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { write(": function "); } emitSignatureAndBody(node); @@ -2431,7 +2434,7 @@ module ts { // export var obj = { y }; // } // The short-hand property in obj need to emit as such ... = { y : m.y } regardless of the TargetScript version - if (compilerOptions.target < ScriptTarget.ES6 || resolver.getExpressionNamePrefix(node.name)) { + if (languageVersion < ScriptTarget.ES6 || resolver.getExpressionNamePrefix(node.name)) { // Emit identifier as an identifier write(": "); // Even though this is stored as identifier treat it as an expression @@ -2513,7 +2516,7 @@ module ts { } function emitTaggedTemplateExpression(node: TaggedTemplateExpression): void { - Debug.assert(compilerOptions.target >= ScriptTarget.ES6, "Trying to emit a tagged template in pre-ES6 mode."); + Debug.assert(languageVersion >= ScriptTarget.ES6, "Trying to emit a tagged template in pre-ES6 mode."); emit(node.tag); write(" "); emit(node.template); @@ -2605,7 +2608,7 @@ module ts { function emitBinaryExpression(node: BinaryExpression) { - if (compilerOptions.target < ScriptTarget.ES6 && node.operator === SyntaxKind.EqualsToken && + if (languageVersion < ScriptTarget.ES6 && node.operator === SyntaxKind.EqualsToken && (node.left.kind === SyntaxKind.ObjectLiteralExpression || node.left.kind === SyntaxKind.ArrayLiteralExpression)) { emitDestructuring(node); } @@ -3101,7 +3104,7 @@ module ts { function emitVariableDeclaration(node: VariableDeclaration) { emitLeadingComments(node); if (isBindingPattern(node.name)) { - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { emitDestructuring(node); } else { @@ -3136,7 +3139,7 @@ module ts { function emitParameter(node: ParameterDeclaration) { emitLeadingComments(node); - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { if (isBindingPattern(node.name)) { var name = createTempVariable(node); if (!tempParameters) { @@ -3160,7 +3163,7 @@ module ts { } function emitDefaultValueAssignments(node: FunctionLikeDeclaration) { - if (compilerOptions.target < ScriptTarget.ES6) { + if (languageVersion < ScriptTarget.ES6) { var tempIndex = 0; forEach(node.parameters, p => { if (isBindingPattern(p.name)) { @@ -3190,7 +3193,7 @@ module ts { } function emitRestParameter(node: FunctionLikeDeclaration) { - if (compilerOptions.target < ScriptTarget.ES6 && hasRestParameters(node)) { + if (languageVersion < ScriptTarget.ES6 && hasRestParameters(node)) { var restIndex = node.parameters.length - 1; var restParam = node.parameters[restIndex]; var tempName = createTempVariable(node, /*forLoopVariable*/ true).text; @@ -3269,7 +3272,7 @@ module ts { write("("); if (node) { var parameters = node.parameters; - var omitCount = compilerOptions.target < ScriptTarget.ES6 && hasRestParameters(node) ? 1 : 0; + var omitCount = languageVersion < ScriptTarget.ES6 && hasRestParameters(node) ? 1 : 0; emitList(parameters, 0, parameters.length - omitCount, /*multiLine*/ false, /*trailingComma*/ false); } write(")"); diff --git a/src/compiler/program.ts b/src/compiler/program.ts index fc3cc0682d1..06e63635232 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -146,7 +146,9 @@ module ts { function invokeEmitter(targetSourceFile?: SourceFile) { var resolver = getDiagnosticsProducingTypeChecker().getEmitResolver(); return emitFiles(resolver, getEmitHost(), targetSourceFile); - } function getSourceFile(filename: string) { + } + + function getSourceFile(filename: string) { filename = host.getCanonicalFileName(filename); return hasProperty(filesByName, filename) ? filesByName[filename] : undefined; } @@ -340,7 +342,7 @@ module ts { } var firstExternalModule = forEach(files, f => isExternalModule(f) ? f : undefined); - if (firstExternalModule && options.module === ModuleKind.None) { + if (firstExternalModule && !options.module) { // We cannot use createDiagnosticFromNode because nodes do not have parents yet var externalModuleErrorSpan = getErrorSpanForNode(firstExternalModule.externalModuleIndicator); var errorStart = skipTrivia(firstExternalModule.text, externalModuleErrorSpan.pos); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 2a0363f7f78..4aef773004b 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -224,15 +224,15 @@ module ts { } function isUnicodeIdentifierStart(code: number, languageVersion: ScriptTarget) { - return languageVersion === ScriptTarget.ES3 ? - lookupInUnicodeMap(code, unicodeES3IdentifierStart) : - lookupInUnicodeMap(code, unicodeES5IdentifierStart); + return languageVersion >= ScriptTarget.ES5 ? + lookupInUnicodeMap(code, unicodeES5IdentifierStart) : + lookupInUnicodeMap(code, unicodeES3IdentifierStart); } function isUnicodeIdentifierPart(code: number, languageVersion: ScriptTarget) { - return languageVersion === ScriptTarget.ES3 ? - lookupInUnicodeMap(code, unicodeES3IdentifierPart) : - lookupInUnicodeMap(code, unicodeES5IdentifierPart); + return languageVersion >= ScriptTarget.ES5 ? + lookupInUnicodeMap(code, unicodeES5IdentifierPart) : + lookupInUnicodeMap(code, unicodeES3IdentifierPart); } function makeReverseMap(source: Map): string[] { @@ -279,7 +279,7 @@ module ts { } export function getPositionFromLineAndCharacter(lineStarts: number[], line: number, character: number): number { - Debug.assert(line > 0); + Debug.assert(line > 0 && line <= lineStarts.length ); return lineStarts[line - 1] + character - 1; } diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts index 27a8c305c4b..5f10a747d42 100644 --- a/src/compiler/sys.ts +++ b/src/compiler/sys.ts @@ -1,3 +1,4 @@ +/// module ts { export interface System { @@ -14,6 +15,7 @@ module ts { createDirectory(directoryName: string): void; getExecutingFilePath(): string; getCurrentDirectory(): string; + readDirectory(path: string, extension?: string): string[]; getMemoryUsage? (): number; exit(exitCode?: number): void; } @@ -28,6 +30,13 @@ module ts { declare var global: any; declare var __filename: string; + declare class Enumerator { + public atEnd(): boolean; + public moveNext(): boolean; + public item(): any; + constructor(o: any); + } + export var sys: System = (function () { function getWScriptSystem(): System { @@ -100,6 +109,34 @@ module ts { } } + function getNames(collection: any): string[] { + var result: string[] = []; + for (var e = new Enumerator(collection); !e.atEnd(); e.moveNext()) { + result.push(e.item().Name); + } + return result.sort(); + } + + function readDirectory(path: string, extension?: string): string[] { + var result: string[] = []; + visitDirectory(path); + return result; + function visitDirectory(path: string) { + var folder = fso.GetFolder(path || "."); + var files = getNames(folder.files); + for (var i = 0; i < files.length; i++) { + var name = files[i]; + if (!extension || fileExtensionIs(name, extension)) { + result.push(combinePaths(path, name)); + } + } + var subfolders = getNames(folder.subfolders); + for (var i = 0; i < subfolders.length; i++) { + visitDirectory(combinePaths(path, subfolders[i])); + } + } + } + return { args, newLine: "\r\n", @@ -129,6 +166,7 @@ module ts { getCurrentDirectory() { return new ActiveXObject("WScript.Shell").CurrentDirectory; }, + readDirectory, exit(exitCode?: number): void { try { WScript.Quit(exitCode); @@ -185,6 +223,31 @@ module ts { _fs.writeFileSync(fileName, data, "utf8"); } + function readDirectory(path: string, extension?: string): string[] { + var result: string[] = []; + visitDirectory(path); + return result; + function visitDirectory(path: string) { + var files = _fs.readdirSync(path || ".").sort(); + var directories: string[] = []; + for (var i = 0; i < files.length; i++) { + var name = combinePaths(path, files[i]); + var stat = _fs.lstatSync(name); + if (stat.isFile()) { + if (!extension || fileExtensionIs(name, extension)) { + result.push(name); + } + } + else if (stat.isDirectory()) { + directories.push(name); + } + } + for (var i = 0; i < directories.length; i++) { + visitDirectory(directories[i]); + } + } + } + return { args: process.argv.slice(2), newLine: _os.EOL, @@ -231,6 +294,7 @@ module ts { getCurrentDirectory() { return process.cwd(); }, + readDirectory, getMemoryUsage() { if (global.gc) { global.gc(); diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts index 9d038920693..ee5dc5104ff 100644 --- a/src/compiler/tsc.ts +++ b/src/compiler/tsc.ts @@ -4,6 +4,10 @@ module ts { var version = "1.4.0.0"; + export interface SourceFile { + fileWatcher: FileWatcher; + } + /** * Checks to see if the locale is in the appropriate format, * and if it is, attempts to set the appropriate language. @@ -126,16 +130,43 @@ module ts { reportStatisticalValue(name, (time / 1000).toFixed(2) + "s"); } + function isJSONSupported() { + return typeof JSON === "object" && typeof JSON.parse === "function"; + } + + function findConfigFile(): string { + var searchPath = normalizePath(sys.getCurrentDirectory()); + var filename = "tsconfig.json"; + while (true) { + if (sys.fileExists(filename)) { + return filename; + } + var parentPath = getDirectoryPath(searchPath); + if (parentPath === searchPath) { + break; + } + searchPath = parentPath; + filename = "../" + filename; + } + return undefined; + } + export function executeCommandLine(args: string[]): void { var commandLine = parseCommandLine(args); - var compilerOptions = commandLine.options; + var configFilename: string; // Configuration file name (if any) + var configFileWatcher: FileWatcher; // Configuration file watcher + var cachedProgram: Program; // Program cached from last compilation + var rootFilenames: string[]; // Root filenames for compilation + var compilerOptions: CompilerOptions; // Compiler options for compilation + var compilerHost: CompilerHost; // Compiler host + var hostGetSourceFile: typeof compilerHost.getSourceFile; // getSourceFile method from default host + var timerHandle: number; // Handle for 0.25s wait timer - if (compilerOptions.locale) { - if (typeof JSON === "undefined") { + if (commandLine.options.locale) { + if (!isJSONSupported()) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--locale")); - return sys.exit(1); + return sys.exit(EmitReturnStatus.CompilerOptionsErrors); } - validateLocaleAndSetLanguage(commandLine.options.locale, commandLine.errors); } @@ -146,131 +177,153 @@ module ts { return sys.exit(EmitReturnStatus.CompilerOptionsErrors); } - if (compilerOptions.version) { + if (commandLine.options.version) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.Version_0, version)); return sys.exit(EmitReturnStatus.Succeeded); } - if (compilerOptions.help) { + if (commandLine.options.help) { printVersion(); printHelp(); return sys.exit(EmitReturnStatus.Succeeded); } - if (commandLine.filenames.length === 0) { + if (commandLine.options.project) { + if (!isJSONSupported()) { + reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--project")); + return sys.exit(EmitReturnStatus.CompilerOptionsErrors); + } + configFilename = normalizePath(combinePaths(commandLine.options.project, "tsconfig.json")); + if (commandLine.filenames.length !== 0) { + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Option_project_cannot_be_mixed_with_source_files_on_a_command_line)); + return sys.exit(EmitReturnStatus.CompilerOptionsErrors); + } + } + else if (commandLine.filenames.length === 0 && isJSONSupported()) { + configFilename = findConfigFile(); + } + + if (commandLine.filenames.length === 0 && !configFilename) { printVersion(); printHelp(); return sys.exit(EmitReturnStatus.CompilerOptionsErrors); } - var defaultCompilerHost = createCompilerHost(compilerOptions); - - if (compilerOptions.watch) { + if (commandLine.options.watch) { if (!sys.watchFile) { reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch")); return sys.exit(EmitReturnStatus.CompilerOptionsErrors); } - - watchProgram(commandLine, defaultCompilerHost); - } - else { - var result = compile(commandLine, defaultCompilerHost).exitStatus - return sys.exit(result); - } - } - - /** - * Compiles the program once, and then watches all given and referenced files for changes. - * Upon detecting a file change, watchProgram will queue up file modification events for the next - * 250ms and then perform a recompilation. The reasoning is that in some cases, an editor can - * save all files at once, and we'd like to just perform a single recompilation. - */ - function watchProgram(commandLine: ParsedCommandLine, compilerHost: CompilerHost): void { - var watchers: Map = {}; - var updatedFiles: Map = {}; - - // Compile the program the first time and watch all given/referenced files. - var program = compile(commandLine, compilerHost).program; - reportDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); - addWatchers(program); - return; - - function addWatchers(program: Program) { - forEach(program.getSourceFiles(), f => { - var filename = getCanonicalName(f.filename); - watchers[filename] = sys.watchFile(filename, fileUpdated); - }); - } - - function removeWatchers(program: Program) { - forEach(program.getSourceFiles(), f => { - var filename = getCanonicalName(f.filename); - if (hasProperty(watchers, filename)) { - watchers[filename].close(); - } - }); - - watchers = {}; - } - - // Fired off whenever a file is changed. - function fileUpdated(filename: string) { - var firstNotification = isEmpty(updatedFiles); - updatedFiles[getCanonicalName(filename)] = true; - - // Only start this off when the first file change comes in, - // so that we can batch up all further changes. - if (firstNotification) { - setTimeout(() => { - var changedFiles = updatedFiles; - updatedFiles = {}; - - recompile(changedFiles); - }, 250); + if (configFilename) { + configFileWatcher = sys.watchFile(configFilename, configFileChanged); } } - function recompile(changedFiles: Map) { - reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Compiling)); - // Remove all the watchers, as we may not be watching every file - // specified since the last compilation cycle. - removeWatchers(program); + performCompilation(); - // Reuse source files from the last compilation so long as they weren't changed. - var oldSourceFiles = arrayToMap( - filter(program.getSourceFiles(), file => !hasProperty(changedFiles, getCanonicalName(file.filename))), - file => getCanonicalName(file.filename)); + // Invoked to perform initial compilation or re-compilation in watch mode + function performCompilation() { - // We create a new compiler host for this compilation cycle. - // This new host is effectively the same except that 'getSourceFile' - // will try to reuse the SourceFiles from the last compilation cycle - // so long as they were not modified. - var newCompilerHost = clone(compilerHost); - newCompilerHost.getSourceFile = (fileName, languageVersion, onError) => { - fileName = getCanonicalName(fileName); - - var sourceFile = lookUp(oldSourceFiles, fileName); - if (sourceFile) { - return sourceFile; + if (!cachedProgram) { + if (configFilename) { + var configObject = readConfigFile(configFilename); + if (!configObject) { + reportDiagnostic(createCompilerDiagnostic(Diagnostics.Unable_to_open_file_0, configFilename)); + return sys.exit(EmitReturnStatus.CompilerOptionsErrors); + } + var configParseResult = parseConfigFile(configObject, getDirectoryPath(configFilename)); + if (configParseResult.errors.length > 0) { + reportDiagnostics(configParseResult.errors); + return sys.exit(EmitReturnStatus.CompilerOptionsErrors); + } + rootFilenames = configParseResult.filenames; + compilerOptions = extend(commandLine.options, configParseResult.options); } + else { + rootFilenames = commandLine.filenames; + compilerOptions = commandLine.options; + } + compilerHost = createCompilerHost(compilerOptions); + hostGetSourceFile = compilerHost.getSourceFile; + compilerHost.getSourceFile = getSourceFile; + } - return compilerHost.getSourceFile(fileName, languageVersion, onError); - }; + var compileResult = compile(rootFilenames, compilerOptions, compilerHost); - program = compile(commandLine, newCompilerHost).program; + if (!commandLine.options.watch) { + return sys.exit(compileResult.exitStatus); + } + + setCachedProgram(compileResult.program); reportDiagnostic(createCompilerDiagnostic(Diagnostics.Compilation_complete_Watching_for_file_changes)); - addWatchers(program); } - function getCanonicalName(fileName: string) { - return compilerHost.getCanonicalFileName(fileName); + function getSourceFile(filename: string, languageVersion: ScriptTarget, onError ?: (message: string) => void) { + // Return existing SourceFile object if one is available + if (cachedProgram) { + var sourceFile = cachedProgram.getSourceFile(filename); + // A modified source file has no watcher and should not be reused + if (sourceFile && sourceFile.fileWatcher) { + return sourceFile; + } + } + // Use default host function + var sourceFile = hostGetSourceFile(filename, languageVersion, onError); + if (sourceFile && commandLine.options.watch) { + // Attach a file watcher + sourceFile.fileWatcher = sys.watchFile(sourceFile.filename, () => sourceFileChanged(sourceFile)); + } + return sourceFile; + } + + // Change cached program to the given program + function setCachedProgram(program: Program) { + if (cachedProgram) { + var newSourceFiles = program ? program.getSourceFiles() : undefined; + forEach(cachedProgram.getSourceFiles(), sourceFile => { + if (!(newSourceFiles && contains(newSourceFiles, sourceFile))) { + if (sourceFile.fileWatcher) { + sourceFile.fileWatcher.close(); + sourceFile.fileWatcher = undefined; + } + } + }); + } + cachedProgram = program; + } + + // If a source file changes, mark it as unwatched and start the recompilation timer + function sourceFileChanged(sourceFile: SourceFile) { + sourceFile.fileWatcher = undefined; + startTimer(); + } + + // If the configuration file changes, forget cached program and start the recompilation timer + function configFileChanged() { + setCachedProgram(undefined); + startTimer(); + } + + // Upon detecting a file change, wait for 250ms and then perform a recompilation. This gives batch + // operations (such as saving all modified files in an editor) a chance to complete before we kick + // off a new compilation. + function startTimer() { + if (timerHandle) { + clearTimeout(timerHandle); + } + timerHandle = setTimeout(recompile, 250); + } + + function recompile() { + timerHandle = undefined; + reportDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation)); + performCompilation(); } } - function compile(commandLine: ParsedCommandLine, compilerHost: CompilerHost) { + function compile(filenames: string[], compilerOptions: CompilerOptions, compilerHost: CompilerHost) { var parseStart = new Date().getTime(); - var compilerOptions = commandLine.options; - var program = createProgram(commandLine.filenames, compilerOptions, compilerHost); + var program = createProgram(filenames, compilerOptions, compilerHost); var bindStart = new Date().getTime(); var errors: Diagnostic[] = program.getDiagnostics(); @@ -303,7 +356,14 @@ module ts { } reportDiagnostics(errors); - if (commandLine.options.diagnostics) { + + if (compilerOptions.listFiles) { + forEach(program.getSourceFiles(), file => { + sys.write(file.filename + sys.newLine); + }); + } + + if (compilerOptions.diagnostics) { var memoryUsed = sys.getMemoryUsage ? sys.getMemoryUsage() : -1; reportCountStatistic("Files", program.getSourceFiles().length); reportCountStatistic("Lines", countLines(program)); diff --git a/src/compiler/tsconfig.json b/src/compiler/tsconfig.json new file mode 100644 index 00000000000..fd541a8ca80 --- /dev/null +++ b/src/compiler/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "out": "../../built/local/tsc.js", + "sourceMap": true + }, + "files": [ + "core.ts", + "sys.ts", + "types.ts", + "scanner.ts", + "parser.ts", + "utilities.ts", + "binder.ts", + "checker.ts", + "emitter.ts", + "program.ts", + "commandLineParser.ts", + "tsc.ts", + "diagnosticInformationMap.generated.ts" + ] +} diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 9ebab8dc220..b8c842641d7 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1448,6 +1448,7 @@ module ts { diagnostics?: boolean; emitBOM?: boolean; help?: boolean; + listFiles?: boolean; locale?: string; mapRoot?: string; module?: ModuleKind; @@ -1461,6 +1462,7 @@ module ts { out?: string; outDir?: string; preserveConstEnums?: boolean; + project?: string; removeComments?: boolean; sourceMap?: boolean; sourceRoot?: string; @@ -1501,10 +1503,11 @@ module ts { export interface CommandLineOption { name: string; type: string | Map; // "string", "number", "boolean", or an object literal mapping named values to actual values - shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'. + isFilePath?: boolean; // True if option value is a path or filename + shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help' description?: DiagnosticMessage; // The message describing what the command line switch does - paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter. - error?: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'. + paramType?: DiagnosticMessage; // The name to be used for a non-boolean option's parameter + error?: DiagnosticMessage; // The error given when the argument does not fit a customized 'type' } export const enum CharacterCodes { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index ecae4ee47a4..df73e52a605 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -22,6 +22,7 @@ declare var require: any; declare var process: any; +var Buffer = require('buffer').Buffer; // this will work in the browser via browserify var _chai: typeof chai = require('chai'); @@ -1207,7 +1208,6 @@ module Harness { export function getErrorBaseline(inputFiles: { unitName: string; content: string }[], diagnostics: HarnessDiagnostic[]) { diagnostics.sort(compareDiagnostics); - var outputLines: string[] = []; // Count up all the errors we find so we don't miss any var totalErrorsReported = 0; @@ -1298,8 +1298,13 @@ module Harness { return diagnostic.filename && isLibraryFile(diagnostic.filename); }); + var numTest262HarnessDiagnostics = ts.countWhere(diagnostics, diagnostic => { + // Count an error generated from tests262-harness folder.This should only apply for test262 + return diagnostic.filename && diagnostic.filename.indexOf("test262-harness") >= 0; + }); + // Verify we didn't miss any errors in total - assert.equal(totalErrorsReported + numLibraryDiagnostics, diagnostics.length, 'total number of errors'); + assert.equal(totalErrorsReported + numLibraryDiagnostics + numTest262HarnessDiagnostics, diagnostics.length, 'total number of errors'); return minimalDiagnosticsToString(diagnostics) + ts.sys.newLine + ts.sys.newLine + outputLines.join('\r\n'); @@ -1642,7 +1647,8 @@ module Harness { } function writeComparison(expected: string, actual: string, relativeFilename: string, actualFilename: string, descriptionForDescribe: string) { - if (expected != actual) { + var encoded_actual = (new Buffer(actual)).toString('utf8') + if (expected != encoded_actual) { // Overwrite & issue error var errMsg = 'The baseline file ' + relativeFilename + ' has changed'; throw new Error(errMsg); diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts index 787c6fe3f46..cab7547557c 100644 --- a/src/services/formatting/formatting.ts +++ b/src/services/formatting/formatting.ts @@ -243,8 +243,18 @@ module ts.formatting { } var precedingToken = findPrecedingToken(originalRange.pos, sourceFile); - // no preceding token found - start from the beginning of enclosing node - return precedingToken ? precedingToken.end : enclosingNode.pos; + if (!precedingToken) { + // no preceding token found - start from the beginning of enclosing node + return enclosingNode.pos; + } + + // preceding token ends after the start of original range (i.e when originaRange.pos falls in the middle of literal) + // start from the beginning of enclosingNode to handle the entire 'originalRange' + if (precedingToken.end >= originalRange.pos) { + return enclosingNode.pos; + } + + return precedingToken.end; } /* diff --git a/src/services/formatting/formattingScanner.ts b/src/services/formatting/formattingScanner.ts index 7ddfecc17f2..e9485158aba 100644 --- a/src/services/formatting/formattingScanner.ts +++ b/src/services/formatting/formattingScanner.ts @@ -187,6 +187,9 @@ module ts.formatting { } // consume trailing trivia + if (trailingTrivia) { + trailingTrivia = undefined; + } while(scanner.getStartPos() < endPos) { currentToken = scanner.scan(); if (!isTrivia(currentToken)) { diff --git a/src/services/formatting/smartIndenter.ts b/src/services/formatting/smartIndenter.ts index ce240a95168..3aa97fe6ae6 100644 --- a/src/services/formatting/smartIndenter.ts +++ b/src/services/formatting/smartIndenter.ts @@ -12,10 +12,15 @@ module ts.formatting { return 0; } - // no indentation in string \regex literals - if ((precedingToken.kind === SyntaxKind.StringLiteral || precedingToken.kind === SyntaxKind.RegularExpressionLiteral) && - precedingToken.getStart(sourceFile) <= position && - precedingToken.end > position) { + // no indentation in string \regex\template literals + var precedingTokenIsLiteral = + precedingToken.kind === SyntaxKind.StringLiteral || + precedingToken.kind === SyntaxKind.RegularExpressionLiteral || + precedingToken.kind === SyntaxKind.NoSubstitutionTemplateLiteral || + precedingToken.kind === SyntaxKind.TemplateHead || + precedingToken.kind === SyntaxKind.TemplateMiddle || + precedingToken.kind === SyntaxKind.TemplateTail; + if (precedingTokenIsLiteral && precedingToken.getStart(sourceFile) <= position && precedingToken.end > position) { return 0; } diff --git a/src/services/services.ts b/src/services/services.ts index 1618fb6e276..84e5e7fefa5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -852,6 +852,7 @@ module ts { // export interface LanguageServiceHost extends Logger { getCompilationSettings(): CompilerOptions; + getNewLine?(): string; getScriptFileNames(): string[]; getScriptVersion(fileName: string): string; getScriptIsOpen(fileName: string): boolean; @@ -1962,7 +1963,9 @@ module ts { getCancellationToken: () => cancellationToken, getCanonicalFileName: (filename) => useCaseSensitivefilenames ? filename : filename.toLowerCase(), useCaseSensitiveFileNames: () => useCaseSensitivefilenames, - getNewLine: () => "\r\n", + getNewLine: () => { + return host.getNewLine ? host.getNewLine() : "\r\n"; + }, getDefaultLibFilename: (options): string => { return host.getDefaultLibFilename(options); }, diff --git a/src/services/tsconfig.json b/src/services/tsconfig.json new file mode 100644 index 00000000000..296e65965d5 --- /dev/null +++ b/src/services/tsconfig.json @@ -0,0 +1,47 @@ +{ + "compilerOptions": { + "module": "commonjs", + "noImplicitAny": true, + "removeComments": true, + "preserveConstEnums": true, + "out": "../../built/local/typescriptServices.js", + "sourceMap": true + }, + "files": [ + "../compiler/core.ts", + "../compiler/sys.ts", + "../compiler/types.ts", + "../compiler/scanner.ts", + "../compiler/parser.ts", + "../compiler/utilities.ts", + "../compiler/binder.ts", + "../compiler/checker.ts", + "../compiler/emitter.ts", + "../compiler/program.ts", + "../compiler/commandLineParser.ts", + "../compiler/diagnosticInformationMap.generated.ts", + "breakpoints.ts", + "navigationBar.ts", + "outliningElementsCollector.ts", + "services.ts", + "shims.ts", + "signatureHelp.ts", + "utilities.ts", + "formatting/formatting.ts", + "formatting/formattingContext.ts", + "formatting/formattingRequestKind.ts", + "formatting/formattingScanner.ts", + "formatting/references.ts", + "formatting/rule.ts", + "formatting/ruleAction.ts", + "formatting/ruleDescriptor.ts", + "formatting/ruleFlag.ts", + "formatting/ruleOperation.ts", + "formatting/ruleOperationContext.ts", + "formatting/rules.ts", + "formatting/rulesMap.ts", + "formatting/rulesProvider.ts", + "formatting/smartIndenter.ts", + "formatting/tokenRange.ts" + ] +} diff --git a/tests/baselines/reference/baseIndexSignatureResolution.js b/tests/baselines/reference/baseIndexSignatureResolution.js index 4c2d63bf2c9..4720e92b969 100644 --- a/tests/baselines/reference/baseIndexSignatureResolution.js +++ b/tests/baselines/reference/baseIndexSignatureResolution.js @@ -55,27 +55,4 @@ interface B extends A { } var b: B = null; var z: Derived = b.foo(); -class Base { private a: string; } -class Derived extends Base { private b: string; } - -// Note - commmenting "extends Foo" prevents the error -interface Foo { - [i: number]: Base; -} -interface FooOf extends Foo { - [i: number]: TBase; -} -var x: FooOf = null; -var y: Derived = x[0]; - -/* -// Note - the equivalent for normal interface methods works fine: -interface A { - foo(): Base; -} -interface B extends A { - foo(): TBase; -} -var b: B = null; -var z: Derived = b.foo(); - +*/ diff --git a/tests/baselines/reference/commentEmitWithCommentOnLastLine.js b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js new file mode 100644 index 00000000000..ffd4addb264 --- /dev/null +++ b/tests/baselines/reference/commentEmitWithCommentOnLastLine.js @@ -0,0 +1,11 @@ +//// [commentEmitWithCommentOnLastLine.ts] +var x: any; +/* +var bar; +*/ + +//// [commentEmitWithCommentOnLastLine.js] +var x; +/* +var bar; +*/ diff --git a/tests/baselines/reference/commentEmitWithCommentOnLastLine.types b/tests/baselines/reference/commentEmitWithCommentOnLastLine.types new file mode 100644 index 00000000000..d59c42d3795 --- /dev/null +++ b/tests/baselines/reference/commentEmitWithCommentOnLastLine.types @@ -0,0 +1,7 @@ +=== tests/cases/compiler/commentEmitWithCommentOnLastLine.ts === +var x: any; +>x : any + +/* +var bar; +*/ diff --git a/tests/baselines/reference/concatError.js b/tests/baselines/reference/concatError.js index 04c0a16b836..dee3d8a30e3 100644 --- a/tests/baselines/reference/concatError.js +++ b/tests/baselines/reference/concatError.js @@ -57,34 +57,4 @@ var c: C; var cc: C>; c = c.m(cc); -var n1: number[]; -/* -interface Array { - concat(...items: T[][]): T[]; // Note: This overload needs to be picked for arrays of arrays, even though both are applicable - concat(...items: T[]): T[]; -} -*/ -var fa: number[]; - -fa = fa.concat([0]); -fa = fa.concat(0); - - - - - -/* - - - - -declare class C { - public m(p1: C>): C; - //public p: T; -} - -var c: C; -var cc: C>; - -c = c.m(cc); - +*/ diff --git a/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/amd/mapRootSourceRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/amd/mapRootSourceRootWithNoSourceMapOption.errors.txt index 4f41f7523d7..0d3528b6dc3 100644 --- a/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/amd/mapRootSourceRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/amd/mapRootSourceRootWithNoSourceMapOption.errors.txt @@ -1,9 +1,9 @@ -error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. -error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. +error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. -!!! error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +!!! error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. +!!! error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/node/mapRootSourceRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/node/mapRootSourceRootWithNoSourceMapOption.errors.txt index 4f41f7523d7..0d3528b6dc3 100644 --- a/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/node/mapRootSourceRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/mapRootSourceRootWithNoSourceMapOption/node/mapRootSourceRootWithNoSourceMapOption.errors.txt @@ -1,9 +1,9 @@ -error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. -error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. +error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. -!!! error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +!!! error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. +!!! error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/project/mapRootWithNoSourceMapOption/amd/mapRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/mapRootWithNoSourceMapOption/amd/mapRootWithNoSourceMapOption.errors.txt index de6de5ecfc6..01a3526196c 100644 --- a/tests/baselines/reference/project/mapRootWithNoSourceMapOption/amd/mapRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/mapRootWithNoSourceMapOption/amd/mapRootWithNoSourceMapOption.errors.txt @@ -1,7 +1,7 @@ -error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +!!! error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/project/mapRootWithNoSourceMapOption/node/mapRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/mapRootWithNoSourceMapOption/node/mapRootWithNoSourceMapOption.errors.txt index de6de5ecfc6..01a3526196c 100644 --- a/tests/baselines/reference/project/mapRootWithNoSourceMapOption/node/mapRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/mapRootWithNoSourceMapOption/node/mapRootWithNoSourceMapOption.errors.txt @@ -1,7 +1,7 @@ -error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5038: Option mapRoot cannot be specified without specifying sourcemap option. +!!! error TS5038: Option 'mapRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/amd/sourceRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/amd/sourceRootWithNoSourceMapOption.errors.txt index 93a57bb27f5..b7abc0c2d52 100644 --- a/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/amd/sourceRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/amd/sourceRootWithNoSourceMapOption.errors.txt @@ -1,7 +1,7 @@ -error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. +error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. +!!! error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/node/sourceRootWithNoSourceMapOption.errors.txt b/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/node/sourceRootWithNoSourceMapOption.errors.txt index 93a57bb27f5..b7abc0c2d52 100644 --- a/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/node/sourceRootWithNoSourceMapOption.errors.txt +++ b/tests/baselines/reference/project/sourceRootWithNoSourceMapOption/node/sourceRootWithNoSourceMapOption.errors.txt @@ -1,7 +1,7 @@ -error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. +error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. -!!! error TS5039: Option sourceRoot cannot be specified without specifying sourcemap option. +!!! error TS5039: Option 'sourceRoot' cannot be specified without specifying 'sourcemap' option. ==== m1.ts (0 errors) ==== var m1_a1 = 10; class m1_c1 { diff --git a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js index dd8028b086a..c0abe985dbc 100644 --- a/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js +++ b/tests/baselines/reference/recursivelySpecializedConstructorDeclaration.js @@ -74,32 +74,4 @@ declare module MsPortal.Controls.Base.ItemList { class ViewModel extends ItemValue { } } -module MsPortal.Controls.Base.ItemList { - - export interface Interface { - // Removing this line fixes the constructor of ItemValue - options: ViewModel; - } - - export class ItemValue { - constructor(value: T) { - } - } - - export class ViewModel extends ItemValue { - } -} - -// Generates: -/* -declare module MsPortal.Controls.Base.ItemList { - interface Interface { - options: ViewModel; - } - class ItemValue { - constructor(value: T); - } - class ViewModel extends ItemValue { - } -} - +*/ diff --git a/tests/cases/compiler/commentEmitWithCommentOnLastLine.ts b/tests/cases/compiler/commentEmitWithCommentOnLastLine.ts new file mode 100644 index 00000000000..d148fbda6fa --- /dev/null +++ b/tests/cases/compiler/commentEmitWithCommentOnLastLine.ts @@ -0,0 +1,4 @@ +var x: any; +/* +var bar; +*/ \ No newline at end of file diff --git a/tests/cases/fourslash/formatTemplateLiteral.ts b/tests/cases/fourslash/formatTemplateLiteral.ts new file mode 100644 index 00000000000..a1f5ef963da --- /dev/null +++ b/tests/cases/fourslash/formatTemplateLiteral.ts @@ -0,0 +1,13 @@ +/// +////var x = `sadasdasdasdasfegsfd +/////*1*/rasdesgeryt35t35y35 e4 ergt er 35t 3535 `; +////var y = `1${2}/*2*/3`; + + +goTo.marker("1"); +edit.insert("\r\n"); // edit will trigger formatting - should succeeed + +goTo.marker("2"); +edit.insert("\r\n"); +verify.indentationIs(0); +verify.currentLineContentIs("3`;") \ No newline at end of file diff --git a/tests/cases/fourslash/getEmitOutputSingleFile2.ts b/tests/cases/fourslash/getEmitOutputSingleFile2.ts index bcb1012a6ea..8bf4f7f4af7 100644 --- a/tests/cases/fourslash/getEmitOutputSingleFile2.ts +++ b/tests/cases/fourslash/getEmitOutputSingleFile2.ts @@ -1,6 +1,7 @@ /// // @BaselineFile: getEmitOutputSingleFile2.baseline +// @module: CommonJS // @declaration: true // @out: declSingleFile.js // @outDir: tests/cases/fourslash/ diff --git a/tests/cases/fourslash/getEmitOutputWithDeclarationFile2.ts b/tests/cases/fourslash/getEmitOutputWithDeclarationFile2.ts index f80fa777296..ac68611246b 100644 --- a/tests/cases/fourslash/getEmitOutputWithDeclarationFile2.ts +++ b/tests/cases/fourslash/getEmitOutputWithDeclarationFile2.ts @@ -1,6 +1,7 @@ /// // @BaselineFile: getEmitOutputWithDeclarationFile2.baseline +// @module: CommonJS // @Filename: decl.d.ts // @emitThisFile: true diff --git a/tests/cases/fourslash/getSemanticDiagnosticForDeclaration.ts b/tests/cases/fourslash/getSemanticDiagnosticForDeclaration.ts index fbd086d191d..6345c464213 100644 --- a/tests/cases/fourslash/getSemanticDiagnosticForDeclaration.ts +++ b/tests/cases/fourslash/getSemanticDiagnosticForDeclaration.ts @@ -1,5 +1,6 @@ /// +// @module: CommonJS // @declaration: true //// interface privateInterface {} //// export class Bar implements /*1*/privateInterface/*2*/{ } diff --git a/tests/cases/fourslash/getSemanticDiagnosticForNoDeclaration.ts b/tests/cases/fourslash/getSemanticDiagnosticForNoDeclaration.ts index 57a490fb31c..dc351a21f2c 100644 --- a/tests/cases/fourslash/getSemanticDiagnosticForNoDeclaration.ts +++ b/tests/cases/fourslash/getSemanticDiagnosticForNoDeclaration.ts @@ -1,5 +1,7 @@ /// +// @module: CommonJS + //// interface privateInterface {} //// export class Bar implements /*1*/privateInterface/*2*/{ } diff --git a/tests/cases/fourslash/smartIndentTemplateLiterals.ts b/tests/cases/fourslash/smartIndentTemplateLiterals.ts new file mode 100644 index 00000000000..679978a515c --- /dev/null +++ b/tests/cases/fourslash/smartIndentTemplateLiterals.ts @@ -0,0 +1,17 @@ +/// +////var x0 = `sadasdasdasdas/*1*/fegsfdrasdesgeryt35t35y35 e4 ergt er 35t 3535 `; +////var x1 = `sadasdasdasdas/*2*/fegsfdr${0}asdesgeryt35t35y35 e4 ergt er 35t 3535 `; +////var x2 = `sadasdasdasdasfegsfdra${0}sdesge/*3*/ryt35t35y35 e4 ergt er 35t 3535 `; +////var x3 = `sadasdasdasdasfegsfdra${0}sdesge/*4*/ryt35${1}t35y35 e4 ergt er 35t 3535 `; +////var x2 = `sadasdasdasdasfegsfdra${0}sdesge${1}sf/*5*/ryt35t35y35 e4 ergt er 35t 3535 `; + +function verifyIndentation(marker: string): void { + goTo.marker(marker); + edit.insert("\r\n"); + verify.indentationIs(0); +} +verifyIndentation("1"); +verifyIndentation("2"); +verifyIndentation("3"); +verifyIndentation("4"); +verifyIndentation("5"); diff --git a/tests/cases/fourslash/underscoreTyping1.ts b/tests/cases/fourslash/underscoreTyping1.ts index d4556e07f74..fddafe5e88e 100644 --- a/tests/cases/fourslash/underscoreTyping1.ts +++ b/tests/cases/fourslash/underscoreTyping1.ts @@ -1,4 +1,6 @@ /// + +// @module: CommonJS //// interface Dictionary { //// [x: string]: T; diff --git a/tests/webhost/webtsc.ts b/tests/webhost/webtsc.ts index c88d2e8f512..ad3c06c8565 100644 --- a/tests/webhost/webtsc.ts +++ b/tests/webhost/webtsc.ts @@ -4,8 +4,12 @@ module TypeScript.WebTsc { declare var RealActiveXObject: { new (s: string): any }; - function getWScriptSystem(): System { + function getWScriptSystem() { var fso = new RealActiveXObject("Scripting.FileSystemObject"); + + var fileStream = new ActiveXObject("ADODB.Stream"); + fileStream.Type = 2 /*text*/; + var args: string[] = []; for (var i = 0; i < WScript.Arguments.length; i++) { args[i] = WScript.Arguments.Item(i); @@ -19,17 +23,35 @@ module TypeScript.WebTsc { writeErr(s: string): void { WScript.StdErr.Write(s); }, - readFile(fileName: string): string { + readFile(fileName: string, encoding?: string): string { + if (!fso.FileExists(fileName)) { + return undefined; + } + fileStream.Open(); try { - var f = fso.OpenTextFile(fileName, 1); - var s: string = f.ReadAll(); - // TODO: Properly handle byte order marks - if (s.length >= 3 && s.charCodeAt(0) === 0xEF && s.charCodeAt(1) === 0xBB && s.charCodeAt(2) === 0xBF) s = s.slice(3); - f.Close(); + if (encoding) { + fileStream.Charset = encoding; + fileStream.LoadFromFile(fileName); + } + else { + // Load file and read the first two bytes into a string with no interpretation + fileStream.Charset = "x-ansi"; + fileStream.LoadFromFile(fileName); + var bom = fileStream.ReadText(2) || ""; + // Position must be at 0 before encoding can be changed + fileStream.Position = 0; + // [0xFF,0xFE] and [0xFE,0xFF] mean utf-16 (little or big endian), otherwise default to utf-8 + fileStream.Charset = bom.length >= 2 && (bom.charCodeAt(0) === 0xFF && bom.charCodeAt(1) === 0xFE || bom.charCodeAt(0) === 0xFE && bom.charCodeAt(1) === 0xFF) ? "unicode" : "utf-8"; + } + // ReadText method always strips byte order mark from resulting string + return fileStream.ReadText(); } catch (e) { + throw e; + } + finally { + fileStream.Close(); } - return s; }, writeFile(fileName: string, data: string): boolean { var f = fso.CreateTextFile(fileName, true);