diff --git a/package.json b/package.json index fdb85ea764b..2de37b712ab 100644 --- a/package.json +++ b/package.json @@ -75,7 +75,7 @@ "through2": "latest", "travis-fold": "latest", "ts-node": "latest", - "tslint": "next", + "tslint": "4.0.0-dev.3", "typescript": "next" }, "scripts": { diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5246bbfc700..36b952dd046 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4612,8 +4612,8 @@ namespace ts { // the modifiers type is T. Otherwise, the modifiers type is {}. const declaredType = getTypeFromMappedTypeNode(type.declaration); const constraint = getConstraintTypeFromMappedType(declaredType); - const extendedConstraint = constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint) : constraint; - type.modifiersType = extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType; + const extendedConstraint = constraint && constraint.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(constraint) : constraint; + type.modifiersType = extendedConstraint && extendedConstraint.flags & TypeFlags.Index ? instantiateType((extendedConstraint).type, type.mapper || identityMapper) : emptyObjectType; } } return type.modifiersType; @@ -7730,8 +7730,11 @@ namespace ts { } } } - else if (relation !== identityRelation && isEmptyObjectType(resolveStructuredTypeMembers(target))) { - return Ternary.True; + else if (relation !== identityRelation) { + const resolved = resolveStructuredTypeMembers(target); + if (isEmptyObjectType(resolved) || resolved.stringIndexInfo && resolved.stringIndexInfo.type.flags & TypeFlags.Any) { + return Ternary.True; + } } return Ternary.False; } @@ -21845,8 +21848,13 @@ namespace ts { function checkGrammarNumericLiteral(node: NumericLiteral): boolean { // Grammar checking - if (node.isOctalLiteral && languageVersion >= ScriptTarget.ES5) { - return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher); + if (node.isOctalLiteral) { + if (languageVersion >= ScriptTarget.ES5) { + return grammarErrorOnNode(node, Diagnostics.Octal_literals_are_not_available_when_targeting_ECMAScript_5_and_higher_Use_the_syntax_0o_0, node.text); + } + if (isChildOfLiteralType(node)) { + return grammarErrorOnNode(node, Diagnostics.Octal_literal_types_must_use_ES2015_syntax_Use_the_syntax_0o_0, node.text); + } } } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index b59921c2948..6d19826e951 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -227,7 +227,7 @@ "category": "Error", "code": 1084 }, - "Octal literals are not available when targeting ECMAScript 5 and higher.": { + "Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o{0}'.": { "category": "Error", "code": 1085 }, @@ -2685,6 +2685,10 @@ "category": "Message", "code": 6080 }, + "File '{0}' has an unsupported extension, so skipping it.": { + "category": "Message", + "code": 6081 + }, "Only 'amd' and 'system' modules are supported alongside --{0}.": { "category": "Error", "code": 6082 @@ -2945,6 +2949,10 @@ "category": "Message", "code": 6146 }, + "Resolution for module '{0}' was found in cache": { + "category": "Message", + "code": 6147 + }, "Variable '{0}' implicitly has an '{1}' type.": { "category": "Error", "code": 7005 @@ -3234,5 +3242,9 @@ "Add {0} to existing import declaration from {1}": { "category": "Message", "code": 90015 + }, + "Octal literal types must use ES2015 syntax. Use the syntax '0o{0}'.": { + "category": "Error", + "code": 8017 } } diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 0daca9156d1..c2fcbddaa61 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -47,11 +47,6 @@ namespace ts { return resolved.path; } - /** Create Resolved from a file with unknown extension. */ - function resolvedFromAnyFile(path: string): Resolved | undefined { - return { path, extension: extensionFromPath(path) }; - } - /** Adds `isExernalLibraryImport` to a Resolved to get a ResolvedModule. */ function resolvedModuleFromResolved({ path, extension }: Resolved, isExternalLibraryImport: boolean): ResolvedModuleFull { return { resolvedFileName: path, extension, isExternalLibraryImport }; @@ -71,7 +66,8 @@ namespace ts { traceEnabled: boolean; } - function tryReadTypesSection(extensions: Extensions, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { + /** Reads from "main" or "types"/"typings" depending on `extensions`. */ + function tryReadPackageJsonMainOrTypes(extensions: Extensions, packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string { const jsonContent = readJson(packageJsonPath, state.host); switch (extensions) { @@ -293,33 +289,69 @@ namespace ts { return result; } - export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations { + /** + * Cached module resolutions per containing directory. + * This assumes that any module id will have the same resolution for sibling files located in the same folder. + */ + export interface ModuleResolutionCache { + getOrCreateCacheForDirectory(directoryName: string): Map; + } + + export function createModuleResolutionCache(currentDirectory: string, getCanonicalFileName: (s: string) => string) { + const map = createFileMap>(); + + return { getOrCreateCacheForDirectory }; + + function getOrCreateCacheForDirectory(directoryName: string) { + const path = toPath(directoryName, currentDirectory, getCanonicalFileName); + let perFolderCache = map.get(path); + if (!perFolderCache) { + perFolderCache = createMap(); + map.set(path, perFolderCache); + } + return perFolderCache; + } + } + + export function resolveModuleName(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations { const traceEnabled = isTraceEnabled(compilerOptions, host); if (traceEnabled) { trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile); } + const perFolderCache = cache && cache.getOrCreateCacheForDirectory(getDirectoryPath(containingFile)); + let result = perFolderCache && perFolderCache[moduleName]; - let moduleResolution = compilerOptions.moduleResolution; - if (moduleResolution === undefined) { - moduleResolution = getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic; + if (result) { if (traceEnabled) { - trace(host, Diagnostics.Module_resolution_kind_is_not_specified_using_0, ModuleResolutionKind[moduleResolution]); + trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache, moduleName); } } else { - if (traceEnabled) { - trace(host, Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, ModuleResolutionKind[moduleResolution]); + let moduleResolution = compilerOptions.moduleResolution; + if (moduleResolution === undefined) { + moduleResolution = getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS ? ModuleResolutionKind.NodeJs : ModuleResolutionKind.Classic; + if (traceEnabled) { + trace(host, Diagnostics.Module_resolution_kind_is_not_specified_using_0, ModuleResolutionKind[moduleResolution]); + } + } + else { + if (traceEnabled) { + trace(host, Diagnostics.Explicitly_specified_module_resolution_kind_Colon_0, ModuleResolutionKind[moduleResolution]); + } } - } - let result: ResolvedModuleWithFailedLookupLocations; - switch (moduleResolution) { - case ModuleResolutionKind.NodeJs: - result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host); - break; - case ModuleResolutionKind.Classic: - result = classicNameResolver(moduleName, containingFile, compilerOptions, host); - break; + switch (moduleResolution) { + case ModuleResolutionKind.NodeJs: + result = nodeModuleNameResolver(moduleName, containingFile, compilerOptions, host); + break; + case ModuleResolutionKind.Classic: + result = classicNameResolver(moduleName, containingFile, compilerOptions, host); + break; + } + + if (perFolderCache) { + perFolderCache[moduleName] = result; + } } if (traceEnabled) { @@ -678,18 +710,21 @@ namespace ts { if (state.traceEnabled) { trace(state.host, Diagnostics.Found_package_json_at_0, packageJsonPath); } - const typesFile = tryReadTypesSection(extensions, packageJsonPath, candidate, state); - if (typesFile) { - const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(typesFile), state.host); + const mainOrTypesFile = tryReadPackageJsonMainOrTypes(extensions, packageJsonPath, candidate, state); + if (mainOrTypesFile) { + const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(mainOrTypesFile), state.host); // A package.json "typings" may specify an exact filename, or may choose to omit an extension. - const fromFile = tryFile(typesFile, failedLookupLocations, onlyRecordFailures, state); - if (fromFile) { - // Note: this would allow a package.json to specify a ".js" file as typings. Maybe that should be forbidden. - return resolvedFromAnyFile(fromFile); + const fromExactFile = tryFile(mainOrTypesFile, failedLookupLocations, onlyRecordFailures, state); + if (fromExactFile) { + const resolved = fromExactFile && resolvedIfExtensionMatches(extensions, fromExactFile); + if (resolved) { + return resolved; + } + trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromExactFile); } - const x = tryAddingExtensions(typesFile, Extensions.TypeScript, failedLookupLocations, onlyRecordFailures, state); - if (x) { - return x; + const resolved = tryAddingExtensions(mainOrTypesFile, Extensions.TypeScript, failedLookupLocations, onlyRecordFailures, state); + if (resolved) { + return resolved; } } else { @@ -709,6 +744,24 @@ namespace ts { return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state); } + /** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */ + function resolvedIfExtensionMatches(extensions: Extensions, path: string): Resolved | undefined { + const extension = tryGetExtensionFromPath(path); + return extension !== undefined && extensionIsOk(extensions, extension) ? { path, extension } : undefined; + } + + /** True if `extension` is one of the supported `extensions`. */ + function extensionIsOk(extensions: Extensions, extension: Extension): boolean { + switch (extensions) { + case Extensions.JavaScript: + return extension === Extension.Js || extension === Extension.Jsx; + case Extensions.TypeScript: + return extension === Extension.Ts || extension === Extension.Tsx || extension === Extension.Dts; + case Extensions.DtsOnly: + return extension === Extension.Dts; + } + } + function pathToPackageJson(directory: string): string { return combinePaths(directory, "package.json"); } diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 73976d5d02e..4ab709d8455 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -325,6 +325,7 @@ namespace ts { // Map storing if there is emit blocking diagnostics for given input const hasEmitBlockingDiagnostics = createFileMap(getCanonicalFileName); + let moduleResolutionCache: ModuleResolutionCache; let resolveModuleNamesWorker: (moduleNames: string[], containingFile: string) => ResolvedModuleFull[]; if (host.resolveModuleNames) { resolveModuleNamesWorker = (moduleNames, containingFile) => host.resolveModuleNames(moduleNames, containingFile).map(resolved => { @@ -338,7 +339,8 @@ namespace ts { }); } else { - const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host).resolvedModule; + moduleResolutionCache = createModuleResolutionCache(currentDirectory, x => host.getCanonicalFileName(x)); + const loader = (moduleName: string, containingFile: string) => resolveModuleName(moduleName, containingFile, options, host, moduleResolutionCache).resolvedModule; resolveModuleNamesWorker = (moduleNames, containingFile) => loadWithLocalCache(moduleNames, containingFile, loader); } @@ -391,6 +393,9 @@ namespace ts { } } + // unconditionally set moduleResolutionCache to undefined to avoid unnecessary leaks + moduleResolutionCache = undefined; + // unconditionally set oldProgram to undefined to prevent it from being captured in closure oldProgram = undefined; diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 6f491f6708f..309236e01c1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -732,6 +732,16 @@ namespace ts { return false; } + export function isChildOfLiteralType(node: Node): boolean { + while (node) { + if (node.kind === SyntaxKind.LiteralType) { + return true; + } + node = node.parent; + } + return false; + } + // Warning: This has the same semantics as the forEach family of functions, // in that traversal terminates in the event that 'visitor' supplies a truthy value. export function forEachReturnStatement(body: Block, visitor: (stmt: ReturnStatement) => T): T { diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 7c7a06db0b6..653b87236fd 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -341,6 +341,7 @@ namespace FourSlash { insertSpaceAfterCommaDelimiter: true, insertSpaceAfterSemicolonInForStatements: true, insertSpaceBeforeAndAfterBinaryOperators: true, + insertSpaceAfterConstructor: false, insertSpaceAfterKeywordsInControlFlowStatements: true, insertSpaceAfterFunctionKeywordForAnonymousFunctions: false, insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false, diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 13d8a6bf824..d379b5bbf9c 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -1840,6 +1840,41 @@ namespace ts.projectSystem { assert.isFalse(service.externalProjects[0].languageServiceEnabled, "language service should be disabled - 2"); }); + it("files are properly detached when language service is disabled", () => { + const f1 = { + path: "/a/app.js", + content: "var x = 1" + }; + const f2 = { + path: "/a/largefile.js", + content: "" + }; + const f3 = { + path: "/a/lib.js", + content: "var x = 1" + }; + const config = { + path: "/a/tsconfig.json", + content: JSON.stringify({ compilerOptions: { allowJs: true } }) + }; + const host = createServerHost([f1, f2, f3, config]); + const originalGetFileSize = host.getFileSize; + host.getFileSize = (filePath: string) => + filePath === f2.path ? server.maxProgramSizeForNonTsFiles + 1 : originalGetFileSize.call(host, filePath); + + const projectService = createProjectService(host); + projectService.openClientFile(f1.path); + projectService.checkNumberOfProjects({ configuredProjects: 1 }); + + projectService.closeClientFile(f1.path); + projectService.checkNumberOfProjects({}); + + for (const f of [f2, f3]) { + const scriptInfo = projectService.getScriptInfoForNormalizedPath(server.toNormalizedPath(f.path)); + assert.equal(scriptInfo.containingProjects.length, 0, `expect 0 containing projects for '${f.path}'`) + } + }); + it("language service disabled events are triggered", () => { const f1 = { path: "/a/app.js", diff --git a/src/server/project.ts b/src/server/project.ts index 0037a470a49..6085ee05159 100644 --- a/src/server/project.ts +++ b/src/server/project.ts @@ -257,8 +257,9 @@ namespace ts.server { info.detachFromProject(this); } } - else { - // release all root files + if (!this.program || !this.languageServiceEnabled) { + // release all root files either if there is no program or language service is disabled. + // in the latter case set of root files can be larger than the set of files in program. for (const root of this.rootFiles) { root.detachFromProject(this); } diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 39012e49fcd..680b81dff99 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -2194,12 +2194,14 @@ namespace ts.server.protocol { insertSpaceAfterCommaDelimiter?: boolean; insertSpaceAfterSemicolonInForStatements?: boolean; insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterConstructor?: boolean; insertSpaceAfterKeywordsInControlFlowStatements?: boolean; insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets?: boolean; insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; + insertSpaceBeforeFunctionParenthesis?: boolean; placeOpenBraceOnNewLineForFunctions?: boolean; placeOpenBraceOnNewLineForControlBlocks?: boolean; } diff --git a/src/server/utilities.ts b/src/server/utilities.ts index 839e79268fa..641ca128e63 100644 --- a/src/server/utilities.ts +++ b/src/server/utilities.ts @@ -78,6 +78,7 @@ namespace ts.server { newLineCharacter: host.newLine || "\n", convertTabsToSpaces: true, indentStyle: ts.IndentStyle.Smart, + insertSpaceAfterConstructor: false, insertSpaceAfterCommaDelimiter: true, insertSpaceAfterSemicolonInForStatements: true, insertSpaceBeforeAndAfterBinaryOperators: true, @@ -87,6 +88,7 @@ namespace ts.server { insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false, insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false, insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false, + insertSpaceBeforeFunctionParenthesis: false, placeOpenBraceOnNewLineForFunctions: false, placeOpenBraceOnNewLineForControlBlocks: false, }; diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts index 408b4683fe9..db25ce0dcb8 100644 --- a/src/services/formatting/rules.ts +++ b/src/services/formatting/rules.ts @@ -87,6 +87,7 @@ namespace ts.formatting { public SpaceAfterLetConstInVariableDeclaration: Rule; public NoSpaceBeforeOpenParenInFuncCall: Rule; public SpaceAfterFunctionInFuncDecl: Rule; + public SpaceBeforeOpenParenInFuncDecl: Rule; public NoSpaceBeforeOpenParenInFuncDecl: Rule; public SpaceAfterVoidOperator: Rule; @@ -112,6 +113,7 @@ namespace ts.formatting { // TypeScript-specific rules // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + public SpaceAfterConstructor: Rule; public NoSpaceAfterConstructor: Rule; // Use of module as a function call. e.g.: import m2 = module("m2"); @@ -329,6 +331,7 @@ namespace ts.formatting { this.SpaceAfterLetConstInVariableDeclaration = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), RuleAction.Space)); this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), RuleAction.Delete)); this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space)); + this.SpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Space)); this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete)); this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space)); @@ -352,13 +355,14 @@ namespace ts.formatting { // TypeScript-specific higher priority rules // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses + this.SpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); // Use of module as a function call. e.g.: import m2 = module("m2"); this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete)); // Add a space around certain TypeScript keywords - this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); + this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.ReadonlyKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space)); // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" { @@ -437,7 +441,7 @@ namespace ts.formatting { this.NoSpaceBeforeEqualInJsxAttribute, this.NoSpaceAfterEqualInJsxAttribute, // TypeScript-specific rules - this.NoSpaceAfterConstructor, this.NoSpaceAfterModuleImport, + this.NoSpaceAfterModuleImport, this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords, this.SpaceAfterModuleName, this.SpaceBeforeArrow, this.SpaceAfterArrow, @@ -462,7 +466,6 @@ namespace ts.formatting { this.NoSpaceBeforeOpenBracket, this.NoSpaceAfterCloseBracket, this.SpaceAfterSemicolon, - this.NoSpaceBeforeOpenParenInFuncDecl, this.SpaceBetweenStatements, this.SpaceAfterTryFinally ]; diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts index 4a2c9d0f155..14e08e4857a 100644 --- a/src/services/formatting/rulesProvider.ts +++ b/src/services/formatting/rulesProvider.ts @@ -38,6 +38,13 @@ namespace ts.formatting { private createActiveRules(options: ts.FormatCodeSettings): Rule[] { let rules = this.globalRules.HighPriorityCommonRules.slice(0); + if (options.insertSpaceAfterConstructor) { + rules.push(this.globalRules.SpaceAfterConstructor); + } + else { + rules.push(this.globalRules.NoSpaceAfterConstructor); + } + if (options.insertSpaceAfterCommaDelimiter) { rules.push(this.globalRules.SpaceAfterComma); } @@ -128,6 +135,13 @@ namespace ts.formatting { rules.push(this.globalRules.NoSpaceAfterBinaryOperator); } + if (options.insertSpaceBeforeFunctionParenthesis) { + rules.push(this.globalRules.SpaceBeforeOpenParenInFuncDecl); + } + else { + rules.push(this.globalRules.NoSpaceBeforeOpenParenInFuncDecl); + } + if (options.placeOpenBraceOnNewLineForControlBlocks) { rules.push(this.globalRules.NewLineBeforeOpenBraceInControl); } diff --git a/src/services/types.ts b/src/services/types.ts index 3865fe7fac9..88ffe2950ce 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -418,6 +418,7 @@ namespace ts { InsertSpaceAfterCommaDelimiter: boolean; InsertSpaceAfterSemicolonInForStatements: boolean; InsertSpaceBeforeAndAfterBinaryOperators: boolean; + InsertSpaceAfterConstructor?: boolean; InsertSpaceAfterKeywordsInControlFlowStatements: boolean; InsertSpaceAfterFunctionKeywordForAnonymousFunctions: boolean; InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean; @@ -426,6 +427,7 @@ namespace ts { InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean; InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; InsertSpaceAfterTypeAssertion?: boolean; + InsertSpaceBeforeFunctionParenthesis?: boolean; PlaceOpenBraceOnNewLineForFunctions: boolean; PlaceOpenBraceOnNewLineForControlBlocks: boolean; } @@ -434,6 +436,7 @@ namespace ts { insertSpaceAfterCommaDelimiter?: boolean; insertSpaceAfterSemicolonInForStatements?: boolean; insertSpaceBeforeAndAfterBinaryOperators?: boolean; + insertSpaceAfterConstructor?: boolean; insertSpaceAfterKeywordsInControlFlowStatements?: boolean; insertSpaceAfterFunctionKeywordForAnonymousFunctions?: boolean; insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis?: boolean; @@ -442,6 +445,7 @@ namespace ts { insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces?: boolean; insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean; insertSpaceAfterTypeAssertion?: boolean; + insertSpaceBeforeFunctionParenthesis?: boolean; placeOpenBraceOnNewLineForFunctions?: boolean; placeOpenBraceOnNewLineForControlBlocks?: boolean; } diff --git a/tests/baselines/reference/cacheResolutions.js b/tests/baselines/reference/cacheResolutions.js new file mode 100644 index 00000000000..1d0f918bf98 --- /dev/null +++ b/tests/baselines/reference/cacheResolutions.js @@ -0,0 +1,27 @@ +//// [tests/cases/compiler/cacheResolutions.ts] //// + +//// [app.ts] + +export let x = 1; + +//// [lib1.ts] +export let x = 1; + +//// [lib2.ts] +export let x = 1; + +//// [app.js] +define(["require", "exports"], function (require, exports) { + "use strict"; + exports.x = 1; +}); +//// [lib1.js] +define(["require", "exports"], function (require, exports) { + "use strict"; + exports.x = 1; +}); +//// [lib2.js] +define(["require", "exports"], function (require, exports) { + "use strict"; + exports.x = 1; +}); diff --git a/tests/baselines/reference/cacheResolutions.symbols b/tests/baselines/reference/cacheResolutions.symbols new file mode 100644 index 00000000000..362ce5c308c --- /dev/null +++ b/tests/baselines/reference/cacheResolutions.symbols @@ -0,0 +1,13 @@ +=== /a/b/c/app.ts === + +export let x = 1; +>x : Symbol(x, Decl(app.ts, 1, 10)) + +=== /a/b/c/lib1.ts === +export let x = 1; +>x : Symbol(x, Decl(lib1.ts, 0, 10)) + +=== /a/b/c/lib2.ts === +export let x = 1; +>x : Symbol(x, Decl(lib2.ts, 0, 10)) + diff --git a/tests/baselines/reference/cacheResolutions.trace.json b/tests/baselines/reference/cacheResolutions.trace.json new file mode 100644 index 00000000000..8e7adfb9898 --- /dev/null +++ b/tests/baselines/reference/cacheResolutions.trace.json @@ -0,0 +1,43 @@ +[ + "======== Resolving module 'tslib' from '/a/b/c/app.ts'. ========", + "Module resolution kind is not specified, using 'Classic'.", + "File '/a/b/c/tslib.ts' does not exist.", + "File '/a/b/c/tslib.tsx' does not exist.", + "File '/a/b/c/tslib.d.ts' does not exist.", + "File '/a/b/tslib.ts' does not exist.", + "File '/a/b/tslib.tsx' does not exist.", + "File '/a/b/tslib.d.ts' does not exist.", + "File '/a/tslib.ts' does not exist.", + "File '/a/tslib.tsx' does not exist.", + "File '/a/tslib.d.ts' does not exist.", + "File '/tslib.ts' does not exist.", + "File '/tslib.tsx' does not exist.", + "File '/tslib.d.ts' does not exist.", + "File '/a/b/c/node_modules/@types/tslib.d.ts' does not exist.", + "File '/a/b/c/node_modules/@types/tslib/package.json' does not exist.", + "File '/a/b/c/node_modules/@types/tslib/index.d.ts' does not exist.", + "File '/a/b/node_modules/@types/tslib.d.ts' does not exist.", + "File '/a/b/node_modules/@types/tslib/package.json' does not exist.", + "File '/a/b/node_modules/@types/tslib/index.d.ts' does not exist.", + "File '/a/node_modules/@types/tslib.d.ts' does not exist.", + "File '/a/node_modules/@types/tslib/package.json' does not exist.", + "File '/a/node_modules/@types/tslib/index.d.ts' does not exist.", + "File '/node_modules/@types/tslib.d.ts' does not exist.", + "File '/node_modules/@types/tslib/package.json' does not exist.", + "File '/node_modules/@types/tslib/index.d.ts' does not exist.", + "File '/a/b/c/tslib.js' does not exist.", + "File '/a/b/c/tslib.jsx' does not exist.", + "File '/a/b/tslib.js' does not exist.", + "File '/a/b/tslib.jsx' does not exist.", + "File '/a/tslib.js' does not exist.", + "File '/a/tslib.jsx' does not exist.", + "File '/tslib.js' does not exist.", + "File '/tslib.jsx' does not exist.", + "======== Module name 'tslib' was not resolved. ========", + "======== Resolving module 'tslib' from '/a/b/c/lib1.ts'. ========", + "Resolution for module 'tslib' was found in cache", + "======== Module name 'tslib' was not resolved. ========", + "======== Resolving module 'tslib' from '/a/b/c/lib2.ts'. ========", + "Resolution for module 'tslib' was found in cache", + "======== Module name 'tslib' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/cacheResolutions.types b/tests/baselines/reference/cacheResolutions.types new file mode 100644 index 00000000000..fdcc0a6c46c --- /dev/null +++ b/tests/baselines/reference/cacheResolutions.types @@ -0,0 +1,16 @@ +=== /a/b/c/app.ts === + +export let x = 1; +>x : number +>1 : 1 + +=== /a/b/c/lib1.ts === +export let x = 1; +>x : number +>1 : 1 + +=== /a/b/c/lib2.ts === +export let x = 1; +>x : number +>1 : 1 + diff --git a/tests/baselines/reference/literals.errors.txt b/tests/baselines/reference/literals.errors.txt index d43e89bb4db..2920498bde4 100644 --- a/tests/baselines/reference/literals.errors.txt +++ b/tests/baselines/reference/literals.errors.txt @@ -2,8 +2,8 @@ tests/cases/conformance/expressions/literals/literals.ts(9,10): error TS2362: Th tests/cases/conformance/expressions/literals/literals.ts(9,17): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. tests/cases/conformance/expressions/literals/literals.ts(10,9): error TS2362: The left-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. tests/cases/conformance/expressions/literals/literals.ts(10,21): error TS2363: The right-hand side of an arithmetic operation must be of type 'any', 'number' or an enum type. -tests/cases/conformance/expressions/literals/literals.ts(20,9): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. -tests/cases/conformance/expressions/literals/literals.ts(25,10): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +tests/cases/conformance/expressions/literals/literals.ts(20,9): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o1'. +tests/cases/conformance/expressions/literals/literals.ts(25,10): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o3'. ==== tests/cases/conformance/expressions/literals/literals.ts (6 errors) ==== @@ -36,14 +36,14 @@ tests/cases/conformance/expressions/literals/literals.ts(25,10): error TS1085: O var n = 1e4; var n = 001; // Error in ES5 ~~~ -!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o1'. var n = 0x1; var n = -1; var n = -1.0; var n = -1e-4; var n = -003; // Error in ES5 ~~~ -!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o3'. var n = -0x1; var s: string; diff --git a/tests/baselines/reference/mappedTypeErrors.errors.txt b/tests/baselines/reference/mappedTypeErrors.errors.txt index f98a11dbaf9..94644a96af9 100644 --- a/tests/baselines/reference/mappedTypeErrors.errors.txt +++ b/tests/baselines/reference/mappedTypeErrors.errors.txt @@ -45,9 +45,11 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(130,5): error TS2322: T tests/cases/conformance/types/mapped/mappedTypeErrors.ts(131,5): error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: any; a?: number | undefined; }'. Types of property 'a' are incompatible. Type 'string' is not assignable to type 'number | undefined'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,16): error TS2322: Type '{}' is not assignable to type 'string'. +tests/cases/conformance/types/mapped/mappedTypeErrors.ts(137,21): error TS2536: Type 'P' cannot be used to index type 'T'. -==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (24 errors) ==== +==== tests/cases/conformance/types/mapped/mappedTypeErrors.ts (26 errors) ==== interface Shape { name: string; @@ -249,4 +251,22 @@ tests/cases/conformance/types/mapped/mappedTypeErrors.ts(131,5): error TS2322: T ~~ !!! error TS2322: Type '{ a: string; }' is not assignable to type '{ [x: string]: any; a?: number | undefined; }'. !!! error TS2322: Types of property 'a' are incompatible. -!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. \ No newline at end of file +!!! error TS2322: Type 'string' is not assignable to type 'number | undefined'. + + // Repro from #13044 + + type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T + ~ +!!! error TS2322: Type '{}' is not assignable to type 'string'. + ~~~~ +!!! error TS2536: Type 'P' cannot be used to index type 'T'. + }; + type O = {x: number, y: boolean}; + let o: O = {x: 5, y: false}; + let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, + }; + \ No newline at end of file diff --git a/tests/baselines/reference/mappedTypeErrors.js b/tests/baselines/reference/mappedTypeErrors.js index 83dc235c705..f194b6193fc 100644 --- a/tests/baselines/reference/mappedTypeErrors.js +++ b/tests/baselines/reference/mappedTypeErrors.js @@ -129,7 +129,21 @@ type T2 = { a?: number, [key: string]: any }; let x1: T2 = { a: 'no' }; // Error let x2: Partial = { a: 'no' }; // Error -let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error +let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error + +// Repro from #13044 + +type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T +}; +type O = {x: number, y: boolean}; +let o: O = {x: 5, y: false}; +let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, +}; + //// [mappedTypeErrors.js] function f1(x) { @@ -204,6 +218,11 @@ c.setState({ c: true }); // Error var x1 = { a: 'no' }; // Error var x2 = { a: 'no' }; // Error var x3 = { a: 'no' }; // Error +var o = { x: 5, y: false }; +var f = { + pf: { x: 7 }, + pt: { x: 7, y: false } +}; //// [mappedTypeErrors.d.ts] @@ -268,3 +287,17 @@ declare let x2: Partial; declare let x3: { [P in keyof T2]: T2[P]; }; +declare type Foo2 = { + pf: { + [P in F]?: T[P]; + }; + pt: { + [P in T]?: T[P]; + }; +}; +declare type O = { + x: number; + y: boolean; +}; +declare let o: O; +declare let f: Foo2; diff --git a/tests/baselines/reference/mappedTypesAndObjects.js b/tests/baselines/reference/mappedTypesAndObjects.js new file mode 100644 index 00000000000..53b39209693 --- /dev/null +++ b/tests/baselines/reference/mappedTypesAndObjects.js @@ -0,0 +1,72 @@ +//// [mappedTypesAndObjects.ts] + +function f1(x: Partial, y: Readonly) { + let obj: {}; + obj = x; + obj = y; +} + +function f2(x: Partial, y: Readonly) { + let obj: { [x: string]: any }; + obj = x; + obj = y; +} + +// Repro from #12900 + +interface Base { + foo: { [key: string]: any }; + bar: any; + baz: any; +} + +interface E1 extends Base { + foo: T; +} + +interface Something { name: string, value: string }; +interface E2 extends Base { + foo: Partial; // or other mapped type +} + +interface E3 extends Base { + foo: Partial; // or other mapped type +} + +//// [mappedTypesAndObjects.js] +function f1(x, y) { + var obj; + obj = x; + obj = y; +} +function f2(x, y) { + var obj; + obj = x; + obj = y; +} +; + + +//// [mappedTypesAndObjects.d.ts] +declare function f1(x: Partial, y: Readonly): void; +declare function f2(x: Partial, y: Readonly): void; +interface Base { + foo: { + [key: string]: any; + }; + bar: any; + baz: any; +} +interface E1 extends Base { + foo: T; +} +interface Something { + name: string; + value: string; +} +interface E2 extends Base { + foo: Partial; +} +interface E3 extends Base { + foo: Partial; +} diff --git a/tests/baselines/reference/mappedTypesAndObjects.symbols b/tests/baselines/reference/mappedTypesAndObjects.symbols new file mode 100644 index 00000000000..1690f1b6b04 --- /dev/null +++ b/tests/baselines/reference/mappedTypesAndObjects.symbols @@ -0,0 +1,98 @@ +=== tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts === + +function f1(x: Partial, y: Readonly) { +>f1 : Symbol(f1, Decl(mappedTypesAndObjects.ts, 0, 0)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 1, 12)) +>x : Symbol(x, Decl(mappedTypesAndObjects.ts, 1, 15)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 1, 12)) +>y : Symbol(y, Decl(mappedTypesAndObjects.ts, 1, 29)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 1, 12)) + + let obj: {}; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 2, 7)) + + obj = x; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 2, 7)) +>x : Symbol(x, Decl(mappedTypesAndObjects.ts, 1, 15)) + + obj = y; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 2, 7)) +>y : Symbol(y, Decl(mappedTypesAndObjects.ts, 1, 29)) +} + +function f2(x: Partial, y: Readonly) { +>f2 : Symbol(f2, Decl(mappedTypesAndObjects.ts, 5, 1)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 7, 12)) +>x : Symbol(x, Decl(mappedTypesAndObjects.ts, 7, 15)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 7, 12)) +>y : Symbol(y, Decl(mappedTypesAndObjects.ts, 7, 29)) +>Readonly : Symbol(Readonly, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 7, 12)) + + let obj: { [x: string]: any }; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 8, 7)) +>x : Symbol(x, Decl(mappedTypesAndObjects.ts, 8, 16)) + + obj = x; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 8, 7)) +>x : Symbol(x, Decl(mappedTypesAndObjects.ts, 7, 15)) + + obj = y; +>obj : Symbol(obj, Decl(mappedTypesAndObjects.ts, 8, 7)) +>y : Symbol(y, Decl(mappedTypesAndObjects.ts, 7, 29)) +} + +// Repro from #12900 + +interface Base { +>Base : Symbol(Base, Decl(mappedTypesAndObjects.ts, 11, 1)) + + foo: { [key: string]: any }; +>foo : Symbol(Base.foo, Decl(mappedTypesAndObjects.ts, 15, 16)) +>key : Symbol(key, Decl(mappedTypesAndObjects.ts, 16, 11)) + + bar: any; +>bar : Symbol(Base.bar, Decl(mappedTypesAndObjects.ts, 16, 31)) + + baz: any; +>baz : Symbol(Base.baz, Decl(mappedTypesAndObjects.ts, 17, 12)) +} + +interface E1 extends Base { +>E1 : Symbol(E1, Decl(mappedTypesAndObjects.ts, 19, 1)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 21, 13)) +>Base : Symbol(Base, Decl(mappedTypesAndObjects.ts, 11, 1)) + + foo: T; +>foo : Symbol(E1.foo, Decl(mappedTypesAndObjects.ts, 21, 30)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 21, 13)) +} + +interface Something { name: string, value: string }; +>Something : Symbol(Something, Decl(mappedTypesAndObjects.ts, 23, 1)) +>name : Symbol(Something.name, Decl(mappedTypesAndObjects.ts, 25, 21)) +>value : Symbol(Something.value, Decl(mappedTypesAndObjects.ts, 25, 35)) + +interface E2 extends Base { +>E2 : Symbol(E2, Decl(mappedTypesAndObjects.ts, 25, 52)) +>Base : Symbol(Base, Decl(mappedTypesAndObjects.ts, 11, 1)) + + foo: Partial; // or other mapped type +>foo : Symbol(E2.foo, Decl(mappedTypesAndObjects.ts, 26, 27)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>Something : Symbol(Something, Decl(mappedTypesAndObjects.ts, 23, 1)) +} + +interface E3 extends Base { +>E3 : Symbol(E3, Decl(mappedTypesAndObjects.ts, 28, 1)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 30, 13)) +>Base : Symbol(Base, Decl(mappedTypesAndObjects.ts, 11, 1)) + + foo: Partial; // or other mapped type +>foo : Symbol(E3.foo, Decl(mappedTypesAndObjects.ts, 30, 30)) +>Partial : Symbol(Partial, Decl(lib.d.ts, --, --)) +>T : Symbol(T, Decl(mappedTypesAndObjects.ts, 30, 13)) +} diff --git a/tests/baselines/reference/mappedTypesAndObjects.types b/tests/baselines/reference/mappedTypesAndObjects.types new file mode 100644 index 00000000000..e6f8e53f558 --- /dev/null +++ b/tests/baselines/reference/mappedTypesAndObjects.types @@ -0,0 +1,102 @@ +=== tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts === + +function f1(x: Partial, y: Readonly) { +>f1 : (x: Partial, y: Readonly) => void +>T : T +>x : Partial +>Partial : Partial +>T : T +>y : Readonly +>Readonly : Readonly +>T : T + + let obj: {}; +>obj : {} + + obj = x; +>obj = x : Partial +>obj : {} +>x : Partial + + obj = y; +>obj = y : Readonly +>obj : {} +>y : Readonly +} + +function f2(x: Partial, y: Readonly) { +>f2 : (x: Partial, y: Readonly) => void +>T : T +>x : Partial +>Partial : Partial +>T : T +>y : Readonly +>Readonly : Readonly +>T : T + + let obj: { [x: string]: any }; +>obj : { [x: string]: any; } +>x : string + + obj = x; +>obj = x : Partial +>obj : { [x: string]: any; } +>x : Partial + + obj = y; +>obj = y : Readonly +>obj : { [x: string]: any; } +>y : Readonly +} + +// Repro from #12900 + +interface Base { +>Base : Base + + foo: { [key: string]: any }; +>foo : { [key: string]: any; } +>key : string + + bar: any; +>bar : any + + baz: any; +>baz : any +} + +interface E1 extends Base { +>E1 : E1 +>T : T +>Base : Base + + foo: T; +>foo : T +>T : T +} + +interface Something { name: string, value: string }; +>Something : Something +>name : string +>value : string + +interface E2 extends Base { +>E2 : E2 +>Base : Base + + foo: Partial; // or other mapped type +>foo : Partial +>Partial : Partial +>Something : Something +} + +interface E3 extends Base { +>E3 : E3 +>T : T +>Base : Base + + foo: Partial; // or other mapped type +>foo : Partial +>Partial : Partial +>T : T +} diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.js b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.js new file mode 100644 index 00000000000..b5d4ae20a4d --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/moduleResolutionWithExtensions_unexpected.ts] //// + +//// [normalize.css] +// This tests that a package.json "main" with an unexpected extension is ignored. + +This file is not read. + +//// [package.json] +{ "main": "normalize.css" } + +//// [a.ts] +import "normalize.css"; + + +//// [a.js] +"use strict"; +require("normalize.css"); diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.symbols b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.symbols new file mode 100644 index 00000000000..a73d58fd7d8 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.symbols @@ -0,0 +1,4 @@ +=== /a.ts === +import "normalize.css"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json new file mode 100644 index 00000000000..84532e8db7b --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.trace.json @@ -0,0 +1,29 @@ +[ + "======== Resolving module 'normalize.css' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'normalize.css' from 'node_modules' folder.", + "File '/node_modules/normalize.css.ts' does not exist.", + "File '/node_modules/normalize.css.tsx' does not exist.", + "File '/node_modules/normalize.css.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/normalize.css/package.json'.", + "'package.json' does not have a 'types' or 'main' field.", + "File '/node_modules/normalize.css/index.ts' does not exist.", + "File '/node_modules/normalize.css/index.tsx' does not exist.", + "File '/node_modules/normalize.css/index.d.ts' does not exist.", + "File '/node_modules/@types/normalize.css.d.ts' does not exist.", + "File '/node_modules/@types/normalize.css/package.json' does not exist.", + "File '/node_modules/@types/normalize.css/index.d.ts' does not exist.", + "Loading module 'normalize.css' from 'node_modules' folder.", + "File '/node_modules/normalize.css.js' does not exist.", + "File '/node_modules/normalize.css.jsx' does not exist.", + "Found 'package.json' at '/node_modules/normalize.css/package.json'.", + "No types specified in 'package.json', so returning 'main' value of 'normalize.css'", + "File '/node_modules/normalize.css/normalize.css' exist - use it as a name resolution result.", + "File '/node_modules/normalize.css/normalize.css' has an unsupported extension, so skipping it.", + "File '/node_modules/normalize.css/normalize.css.ts' does not exist.", + "File '/node_modules/normalize.css/normalize.css.tsx' does not exist.", + "File '/node_modules/normalize.css/normalize.css.d.ts' does not exist.", + "File '/node_modules/normalize.css/index.js' does not exist.", + "File '/node_modules/normalize.css/index.jsx' does not exist.", + "======== Module name 'normalize.css' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.types b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.types new file mode 100644 index 00000000000..a73d58fd7d8 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected.types @@ -0,0 +1,4 @@ +=== /a.ts === +import "normalize.css"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.js b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.js new file mode 100644 index 00000000000..dc9df79e4df --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/moduleResolutionWithExtensions_unexpected2.ts] //// + +//// [foo.js] +// This tests that a package.json "types" with an unexpected extension is ignored. + +This file is not read. + +//// [package.json] +{ "types": "foo.js" } + +//// [a.ts] +import "foo"; + + +//// [a.js] +"use strict"; +require("foo"); diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.symbols b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.symbols new file mode 100644 index 00000000000..11c9c72cc69 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.symbols @@ -0,0 +1,4 @@ +=== /a.ts === +import "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json new file mode 100644 index 00000000000..27c9d2243e5 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.trace.json @@ -0,0 +1,29 @@ +[ + "======== Resolving module 'foo' from '/a.ts'. ========", + "Module resolution kind is not specified, using 'NodeJs'.", + "Loading module 'foo' from 'node_modules' folder.", + "File '/node_modules/foo.ts' does not exist.", + "File '/node_modules/foo.tsx' does not exist.", + "File '/node_modules/foo.d.ts' does not exist.", + "Found 'package.json' at '/node_modules/foo/package.json'.", + "'package.json' has 'types' field 'foo.js' that references '/node_modules/foo/foo.js'.", + "File '/node_modules/foo/foo.js' exist - use it as a name resolution result.", + "File '/node_modules/foo/foo.js' has an unsupported extension, so skipping it.", + "File '/node_modules/foo/foo.js.ts' does not exist.", + "File '/node_modules/foo/foo.js.tsx' does not exist.", + "File '/node_modules/foo/foo.js.d.ts' does not exist.", + "File '/node_modules/foo/index.ts' does not exist.", + "File '/node_modules/foo/index.tsx' does not exist.", + "File '/node_modules/foo/index.d.ts' does not exist.", + "File '/node_modules/@types/foo.d.ts' does not exist.", + "File '/node_modules/@types/foo/package.json' does not exist.", + "File '/node_modules/@types/foo/index.d.ts' does not exist.", + "Loading module 'foo' from 'node_modules' folder.", + "File '/node_modules/foo.js' does not exist.", + "File '/node_modules/foo.jsx' does not exist.", + "Found 'package.json' at '/node_modules/foo/package.json'.", + "'package.json' does not have a 'types' or 'main' field.", + "File '/node_modules/foo/index.js' does not exist.", + "File '/node_modules/foo/index.jsx' does not exist.", + "======== Module name 'foo' was not resolved. ========" +] \ No newline at end of file diff --git a/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.types b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.types new file mode 100644 index 00000000000..11c9c72cc69 --- /dev/null +++ b/tests/baselines/reference/moduleResolutionWithExtensions_unexpected2.types @@ -0,0 +1,4 @@ +=== /a.ts === +import "foo"; +No type information for this code. +No type information for this code. \ No newline at end of file diff --git a/tests/baselines/reference/objectLiteralErrors.errors.txt b/tests/baselines/reference/objectLiteralErrors.errors.txt index 234ac24a8fd..03b4b74eacd 100644 --- a/tests/baselines/reference/objectLiteralErrors.errors.txt +++ b/tests/baselines/reference/objectLiteralErrors.errors.txt @@ -12,7 +12,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(13,21) tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(14,19): error TS2300: Duplicate identifier '0'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(15,19): error TS2300: Duplicate identifier '0'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(16,19): error TS2300: Duplicate identifier '0x0'. -tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(17,19): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(17,19): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o0'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(17,19): error TS2300: Duplicate identifier '000'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(18,23): error TS2300: Duplicate identifier '1e2'. tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(19,22): error TS2300: Duplicate identifier '3.2e1'. @@ -125,7 +125,7 @@ tests/cases/conformance/expressions/objectLiterals/objectLiteralErrors.ts(45,55) !!! error TS2300: Duplicate identifier '0x0'. var e14 = { 0: 0, 000: 0 }; ~~~ -!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o0'. ~~~ !!! error TS2300: Duplicate identifier '000'. var e15 = { "100": 0, 1e2: 0 }; diff --git a/tests/baselines/reference/oldStyleOctalLiteralTypes.errors.txt b/tests/baselines/reference/oldStyleOctalLiteralTypes.errors.txt new file mode 100644 index 00000000000..4dc81f370a4 --- /dev/null +++ b/tests/baselines/reference/oldStyleOctalLiteralTypes.errors.txt @@ -0,0 +1,12 @@ +tests/cases/compiler/oldStyleOctalLiteralTypes.ts(1,8): error TS8017: Octal literal types must use ES2015 syntax. Use the syntax '0o10'. +tests/cases/compiler/oldStyleOctalLiteralTypes.ts(2,9): error TS8017: Octal literal types must use ES2015 syntax. Use the syntax '0o20'. + + +==== tests/cases/compiler/oldStyleOctalLiteralTypes.ts (2 errors) ==== + let x: 010; + ~~~ +!!! error TS8017: Octal literal types must use ES2015 syntax. Use the syntax '0o10'. + let y: -020; + ~~~ +!!! error TS8017: Octal literal types must use ES2015 syntax. Use the syntax '0o20'. + \ No newline at end of file diff --git a/tests/baselines/reference/oldStyleOctalLiteralTypes.js b/tests/baselines/reference/oldStyleOctalLiteralTypes.js new file mode 100644 index 00000000000..28b275774c3 --- /dev/null +++ b/tests/baselines/reference/oldStyleOctalLiteralTypes.js @@ -0,0 +1,8 @@ +//// [oldStyleOctalLiteralTypes.ts] +let x: 010; +let y: -020; + + +//// [oldStyleOctalLiteralTypes.js] +var x; +var y; diff --git a/tests/baselines/reference/scannerNumericLiteral2.errors.txt b/tests/baselines/reference/scannerNumericLiteral2.errors.txt index 5860be78c1b..faf5429f8b7 100644 --- a/tests/baselines/reference/scannerNumericLiteral2.errors.txt +++ b/tests/baselines/reference/scannerNumericLiteral2.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral2.ts(1,1): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral2.ts(1,1): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o1'. ==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral2.ts (1 errors) ==== 01 ~~ -!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. \ No newline at end of file +!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o1'. \ No newline at end of file diff --git a/tests/baselines/reference/scannerNumericLiteral8.errors.txt b/tests/baselines/reference/scannerNumericLiteral8.errors.txt index 94916626fe6..5aad01449f2 100644 --- a/tests/baselines/reference/scannerNumericLiteral8.errors.txt +++ b/tests/baselines/reference/scannerNumericLiteral8.errors.txt @@ -1,7 +1,7 @@ -tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral8.ts(1,2): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. +tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral8.ts(1,2): error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o3'. ==== tests/cases/conformance/scanner/ecmascript5/scannerNumericLiteral8.ts (1 errors) ==== -03 ~~ -!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. \ No newline at end of file +!!! error TS1085: Octal literals are not available when targeting ECMAScript 5 and higher. Use the syntax '0o3'. \ No newline at end of file diff --git a/tests/baselines/reference/typeReferenceDirectives12.trace.json b/tests/baselines/reference/typeReferenceDirectives12.trace.json index f232228a351..5f87ab7ea39 100644 --- a/tests/baselines/reference/typeReferenceDirectives12.trace.json +++ b/tests/baselines/reference/typeReferenceDirectives12.trace.json @@ -16,9 +16,7 @@ "Resolving real path for '/types/lib/index.d.ts', result '/types/lib/index.d.ts'", "======== Type reference directive 'lib' was successfully resolved to '/types/lib/index.d.ts', primary: true. ========", "======== Resolving module './main' from '/mod1.ts'. ========", - "Module resolution kind is not specified, using 'NodeJs'.", - "Loading module as file / folder, candidate module location '/main'.", - "File '/main.ts' exist - use it as a name resolution result.", + "Resolution for module './main' was found in cache", "======== Module name './main' was successfully resolved to '/main.ts'. ========", "======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========", "Resolving with primary search path '/types'", diff --git a/tests/baselines/reference/typeReferenceDirectives9.trace.json b/tests/baselines/reference/typeReferenceDirectives9.trace.json index f232228a351..5f87ab7ea39 100644 --- a/tests/baselines/reference/typeReferenceDirectives9.trace.json +++ b/tests/baselines/reference/typeReferenceDirectives9.trace.json @@ -16,9 +16,7 @@ "Resolving real path for '/types/lib/index.d.ts', result '/types/lib/index.d.ts'", "======== Type reference directive 'lib' was successfully resolved to '/types/lib/index.d.ts', primary: true. ========", "======== Resolving module './main' from '/mod1.ts'. ========", - "Module resolution kind is not specified, using 'NodeJs'.", - "Loading module as file / folder, candidate module location '/main'.", - "File '/main.ts' exist - use it as a name resolution result.", + "Resolution for module './main' was found in cache", "======== Module name './main' was successfully resolved to '/main.ts'. ========", "======== Resolving type reference directive 'lib', containing file '/__inferred type names__.ts', root directory '/types'. ========", "Resolving with primary search path '/types'", diff --git a/tests/cases/compiler/cacheResolutions.ts b/tests/cases/compiler/cacheResolutions.ts new file mode 100644 index 00000000000..c6962e25db6 --- /dev/null +++ b/tests/cases/compiler/cacheResolutions.ts @@ -0,0 +1,12 @@ +// @module: amd +// @importHelpers: true +// @traceResolution: true + +// @filename: /a/b/c/app.ts +export let x = 1; + +// @filename: /a/b/c/lib1.ts +export let x = 1; + +// @filename: /a/b/c/lib2.ts +export let x = 1; \ No newline at end of file diff --git a/tests/cases/compiler/moduleResolutionWithExtensions_unexpected.ts b/tests/cases/compiler/moduleResolutionWithExtensions_unexpected.ts new file mode 100644 index 00000000000..3af02eabb76 --- /dev/null +++ b/tests/cases/compiler/moduleResolutionWithExtensions_unexpected.ts @@ -0,0 +1,12 @@ +// @noImplicitReferences: true +// @traceResolution: true +// This tests that a package.json "main" with an unexpected extension is ignored. + +// @Filename: /node_modules/normalize.css/normalize.css +This file is not read. + +// @Filename: /node_modules/normalize.css/package.json +{ "main": "normalize.css" } + +// @Filename: /a.ts +import "normalize.css"; diff --git a/tests/cases/compiler/moduleResolutionWithExtensions_unexpected2.ts b/tests/cases/compiler/moduleResolutionWithExtensions_unexpected2.ts new file mode 100644 index 00000000000..1c960fa67e9 --- /dev/null +++ b/tests/cases/compiler/moduleResolutionWithExtensions_unexpected2.ts @@ -0,0 +1,12 @@ +// @noImplicitReferences: true +// @traceResolution: true +// This tests that a package.json "types" with an unexpected extension is ignored. + +// @Filename: /node_modules/foo/foo.js +This file is not read. + +// @Filename: /node_modules/foo/package.json +{ "types": "foo.js" } + +// @Filename: /a.ts +import "foo"; diff --git a/tests/cases/compiler/oldStyleOctalLiteralTypes.ts b/tests/cases/compiler/oldStyleOctalLiteralTypes.ts new file mode 100644 index 00000000000..c5a5475e300 --- /dev/null +++ b/tests/cases/compiler/oldStyleOctalLiteralTypes.ts @@ -0,0 +1,3 @@ +// @target: ES3 +let x: 010; +let y: -020; diff --git a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts index 458dbe9caa4..cec1fbf8395 100644 --- a/tests/cases/conformance/types/mapped/mappedTypeErrors.ts +++ b/tests/cases/conformance/types/mapped/mappedTypeErrors.ts @@ -130,4 +130,17 @@ type T2 = { a?: number, [key: string]: any }; let x1: T2 = { a: 'no' }; // Error let x2: Partial = { a: 'no' }; // Error -let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error \ No newline at end of file +let x3: { [P in keyof T2]: T2[P]} = { a: 'no' }; // Error + +// Repro from #13044 + +type Foo2 = { + pf: {[P in F]?: T[P]}, + pt: {[P in T]?: T[P]}, // note: should be in keyof T +}; +type O = {x: number, y: boolean}; +let o: O = {x: 5, y: false}; +let f: Foo2 = { + pf: {x: 7}, + pt: {x: 7, y: false}, +}; diff --git a/tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts b/tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts new file mode 100644 index 00000000000..8023f6e7d8d --- /dev/null +++ b/tests/cases/conformance/types/mapped/mappedTypesAndObjects.ts @@ -0,0 +1,35 @@ +// @strictNullChecks: true +// @declaration: true + +function f1(x: Partial, y: Readonly) { + let obj: {}; + obj = x; + obj = y; +} + +function f2(x: Partial, y: Readonly) { + let obj: { [x: string]: any }; + obj = x; + obj = y; +} + +// Repro from #12900 + +interface Base { + foo: { [key: string]: any }; + bar: any; + baz: any; +} + +interface E1 extends Base { + foo: T; +} + +interface Something { name: string, value: string }; +interface E2 extends Base { + foo: Partial; // or other mapped type +} + +interface E3 extends Base { + foo: Partial; // or other mapped type +} \ No newline at end of file diff --git a/tests/cases/fourslash/formattingReadonly.ts b/tests/cases/fourslash/formattingReadonly.ts new file mode 100644 index 00000000000..e9ec9860032 --- /dev/null +++ b/tests/cases/fourslash/formattingReadonly.ts @@ -0,0 +1,12 @@ +/// + +////class C { +//// readonly property1 {};/*1*/ +//// public readonly property2 {};/*2*/ +////} + +format.document(); +goTo.marker("1"); +verify.currentLineContentIs(" readonly property1 {};"); +goTo.marker("2"); +verify.currentLineContentIs(" public readonly property2 {};"); \ No newline at end of file diff --git a/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts new file mode 100644 index 00000000000..ce85521879e --- /dev/null +++ b/tests/cases/fourslash/formattingSpaceBeforeFunctionParen.ts @@ -0,0 +1,19 @@ +/// + +/////*1*/function foo() { } +/////*2*/function boo () { } +/////*3*/var bar = function foo() { }; +/////*4*/var foo = { bar() { } }; + +format.setOption("InsertSpaceBeforeFunctionParenthesis", true); + +format.document(); + +goTo.marker('1'); +verify.currentLineContentIs('function foo () { }'); +goTo.marker('2'); +verify.currentLineContentIs('function boo () { }'); +goTo.marker('3'); +verify.currentLineContentIs('var bar = function foo () { };'); +goTo.marker('4'); +verify.currentLineContentIs('var foo = { bar () { } };'); \ No newline at end of file diff --git a/tests/cases/fourslash/formattingSpacesAfterConstructor.ts b/tests/cases/fourslash/formattingSpacesAfterConstructor.ts index 8df762def20..2195d74adbc 100644 --- a/tests/cases/fourslash/formattingSpacesAfterConstructor.ts +++ b/tests/cases/fourslash/formattingSpacesAfterConstructor.ts @@ -3,4 +3,11 @@ /////*1*/class test { constructor () { } } format.document(); goTo.marker("1"); -verify.currentLineContentIs("class test { constructor() { } }"); \ No newline at end of file +verify.currentLineContentIs("class test { constructor() { } }"); + +/////*2*/class test { constructor () { } } +format.setOption("InsertSpaceAfterConstructor", true); + +format.document(); +goTo.marker("2"); +verify.currentLineContentIs("class test { constructor () { } }"); \ No newline at end of file