diff --git a/Jakefile.js b/Jakefile.js index 439fced0720..900859f033a 100644 --- a/Jakefile.js +++ b/Jakefile.js @@ -802,7 +802,8 @@ function runConsoleTests(defaultReporter, runInParallel) { var debug = process.env.debug || process.env.d; var inspect = process.env.inspect; - tests = process.env.test || process.env.tests || process.env.t; + var testTimeout = process.env.timeout || defaultTestTimeout; + var tests = process.env.test || process.env.tests || process.env.t; var light = process.env.light || false; var stackTraceLimit = process.env.stackTraceLimit; var testConfigFile = 'test.config'; @@ -820,7 +821,7 @@ function runConsoleTests(defaultReporter, runInParallel) { } while (fs.existsSync(taskConfigsFolder)); fs.mkdirSync(taskConfigsFolder); - workerCount = process.env.workerCount || os.cpus().length; + workerCount = process.env.workerCount || process.env.p || os.cpus().length; } if (tests || light || taskConfigsFolder) { @@ -925,7 +926,7 @@ function runConsoleTests(defaultReporter, runInParallel) { } } -var testTimeout = 20000; +var defaultTestTimeout = 22000; desc("Runs all the tests in parallel using the built run.js file. Optional arguments are: t[ests]=category1|category2|... d[ebug]=true."); task("runtests-parallel", ["build-rules", "tests", builtLocalDirectory], function () { runConsoleTests('min', /*runInParallel*/ true); diff --git a/scripts/buildProtocol.ts b/scripts/buildProtocol.ts index 37ebd0105ae..e03338bf60d 100644 --- a/scripts/buildProtocol.ts +++ b/scripts/buildProtocol.ts @@ -113,7 +113,7 @@ class DeclarationsWalker { } } -function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string): string { +function writeProtocolFile(outputFile: string, protocolTs: string, typeScriptServicesDts: string) { const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: true, types: [], stripInternal: true }; /** @@ -163,14 +163,17 @@ function generateProtocolFile(protocolTs: string, typeScriptServicesDts: string) protocolDts += "\nimport protocol = ts.server.protocol;"; protocolDts += "\nexport = protocol;"; protocolDts += "\nexport as namespace protocol;"; + // do sanity check and try to compile generated text as standalone program const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false); const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()]; + + ts.sys.writeFile(outputFile, protocolDts); + if (diagnostics.length) { const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file.fileName} line ${d.start}`).join("\n"); throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`); } - return protocolDts; } if (process.argv.length < 5) { @@ -181,5 +184,4 @@ if (process.argv.length < 5) { const protocolTs = process.argv[2]; const typeScriptServicesDts = process.argv[3]; const outputFile = process.argv[4]; -const generatedProtocolDts = generateProtocolFile(protocolTs, typeScriptServicesDts); -ts.sys.writeFile(outputFile, generatedProtocolDts); +writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts); diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f1aca672c52..cb855969ea8 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -1473,8 +1473,15 @@ namespace ts { } } + /** + * Indicates that a symbol is an alias that does not merge with a local declaration. + */ + function isNonLocalAlias(symbol: Symbol, excludes = SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace) { + return symbol && (symbol.flags & (SymbolFlags.Alias | excludes)) === SymbolFlags.Alias; + } + function resolveSymbol(symbol: Symbol, dontResolveAlias?: boolean): Symbol { - const shouldResolve = !dontResolveAlias && symbol && symbol.flags & SymbolFlags.Alias && !(symbol.flags & (SymbolFlags.Value | SymbolFlags.Type | SymbolFlags.Namespace)); + const shouldResolve = !dontResolveAlias && isNonLocalAlias(symbol); return shouldResolve ? resolveAlias(symbol) : symbol; } @@ -2825,6 +2832,17 @@ namespace ts { function symbolToParameterDeclaration(parameterSymbol: Symbol, context: NodeBuilderContext): ParameterDeclaration { const parameterDeclaration = getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter); + if (isTransientSymbol(parameterSymbol) && parameterSymbol.isRestParameter) { + // special-case synthetic rest parameters in JS files + return createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + parameterSymbol.isRestParameter ? createToken(SyntaxKind.DotDotDotToken) : undefined, + "args", + /*questionToken*/ undefined, + typeToTypeNodeHelper(anyArrayType, context), + /*initializer*/ undefined); + } const modifiers = parameterDeclaration.modifiers && parameterDeclaration.modifiers.map(getSynthesizedClone); const dotDotDotToken = isRestParameter(parameterDeclaration) ? createToken(SyntaxKind.DotDotDotToken) : undefined; const name = parameterDeclaration.name ? @@ -6384,8 +6402,17 @@ namespace ts { const typePredicate = declaration.type && declaration.type.kind === SyntaxKind.TypePredicate ? createTypePredicateFromTypePredicateNode(declaration.type as TypePredicateNode) : undefined; + // JS functions get a free rest parameter if they reference `arguments` + let hasRestLikeParameter = hasRestParameter(declaration); + if (!hasRestLikeParameter && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration) && containsArgumentsReference(declaration)) { + hasRestLikeParameter = true; + const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args"); + syntheticArgsSymbol.type = anyArrayType; + syntheticArgsSymbol.isRestParameter = true; + parameters.push(syntheticArgsSymbol); + } - links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, hasRestParameter(declaration), hasLiteralTypes); + links.resolvedSignature = createSignature(declaration, typeParameters, thisParameter, parameters, returnType, typePredicate, minArgumentCount, hasRestLikeParameter, hasLiteralTypes); } return links.resolvedSignature; } @@ -6420,14 +6447,14 @@ namespace ts { } } - function containsArgumentsReference(declaration: FunctionLikeDeclaration): boolean { + function containsArgumentsReference(declaration: SignatureDeclaration): boolean { const links = getNodeLinks(declaration); if (links.containsArgumentsReference === undefined) { if (links.flags & NodeCheckFlags.CaptureArguments) { links.containsArgumentsReference = true; } else { - links.containsArgumentsReference = traverse(declaration.body); + links.containsArgumentsReference = traverse((declaration as FunctionLikeDeclaration).body); } } return links.containsArgumentsReference; @@ -7642,11 +7669,9 @@ namespace ts { if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) { return anyType; } - left = filterType(left, t => !(t.flags & TypeFlags.Nullable)); if (left.flags & TypeFlags.Never) { return right; } - right = filterType(right, t => !(t.flags & TypeFlags.Nullable)); if (right.flags & TypeFlags.Never) { return left; } @@ -8599,6 +8624,7 @@ namespace ts { function isEmptyObjectType(type: Type): boolean { return type.flags & TypeFlags.Object ? isEmptyResolvedType(resolveStructuredTypeMembers(type)) : + type.flags & TypeFlags.NonPrimitive ? true : type.flags & TypeFlags.Union ? forEach((type).types, isEmptyObjectType) : type.flags & TypeFlags.Intersection ? !forEach((type).types, t => !isEmptyObjectType(t)) : false; @@ -10255,7 +10281,7 @@ namespace ts { const objectFlags = getObjectFlags(type); return !!(type.flags & TypeFlags.TypeVariable || objectFlags & ObjectFlags.Reference && forEach((type).typeArguments, couldContainTypeVariables) || - objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || + objectFlags & ObjectFlags.Anonymous && type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.TypeLiteral | SymbolFlags.Class) || objectFlags & ObjectFlags.Mapped || type.flags & TypeFlags.UnionOrIntersection && couldUnionOrIntersectionContainTypeVariables(type)); } @@ -12021,7 +12047,9 @@ namespace ts { return getTypeOfSymbol(symbol); } - if (symbol.flags & SymbolFlags.Alias && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) { + // We should only mark aliases as referenced if there isn't a local value declaration + // for the symbol. + if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value) && !isInTypeQuery(node) && !isConstEnumOrConstEnumOnlyModule(resolveAlias(symbol))) { markAliasSymbolAsReferenced(symbol); } @@ -13058,13 +13086,13 @@ namespace ts { return node ? node.contextualMapper : identityMapper; } - // If the given type is an object or union type, if that type has a single signature, and if - // that signature is non-generic, return the signature. Otherwise return undefined. - function getNonGenericSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature { + // If the given type is an object or union type with a single signature, and if that signature has at + // least as many parameters as the given function, return the signature. Otherwise return undefined. + function getContextualCallSignature(type: Type, node: FunctionExpression | ArrowFunction | MethodDeclaration): Signature { const signatures = getSignaturesOfStructuredType(type, SignatureKind.Call); if (signatures.length === 1) { const signature = signatures[0]; - if (!signature.typeParameters && !isAritySmaller(signature, node)) { + if (!isAritySmaller(signature, node)) { return signature; } } @@ -13115,12 +13143,12 @@ namespace ts { return undefined; } if (!(type.flags & TypeFlags.Union)) { - return getNonGenericSignature(type, node); + return getContextualCallSignature(type, node); } let signatureList: Signature[]; const types = (type).types; for (const current of types) { - const signature = getNonGenericSignature(current, node); + const signature = getContextualCallSignature(current, node); if (signature) { if (!signatureList) { // This signature will contribute to contextual union signature @@ -14980,11 +15008,21 @@ namespace ts { // We clone the contextual mapper to avoid disturbing a resolution in progress for an // outer call expression. Effectively we just want a snapshot of whatever has been // inferred for any outer call expression so far. - const mapper = cloneTypeMapper(getContextualMapper(node)); - const instantiatedType = instantiateType(contextualType, mapper); - const returnType = getReturnTypeOfSignature(signature); - // Inferences made from return types have lower priority than all other inferences. - inferTypes(context.inferences, instantiatedType, returnType, InferencePriority.ReturnType); + const instantiatedType = instantiateType(contextualType, cloneTypeMapper(getContextualMapper(node))); + // If the contextual type is a generic pure function type, we instantiate the type with + // its own type parameters and type arguments. This ensures that the type parameters are + // not erased to type any during type inference such that they can be inferred as actual + // types from the contextual type. For example: + // declare function arrayMap(f: (x: T) => U): (a: T[]) => U[]; + // const boxElements: (a: A[]) => { value: A }[] = arrayMap(value => ({ value })); + // Above, the type of the 'value' parameter is inferred to be 'A'. + const contextualSignature = getSingleCallSignature(instantiatedType); + const inferenceSourceType = contextualSignature && contextualSignature.typeParameters ? + getOrCreateTypeFromSignature(getSignatureInstantiation(contextualSignature, contextualSignature.typeParameters)) : + instantiatedType; + const inferenceTargetType = getReturnTypeOfSignature(signature); + // Inferences made from return types have lower priority than all other inferences. + inferTypes(context.inferences, inferenceSourceType, inferenceTargetType, InferencePriority.ReturnType); } } @@ -15483,21 +15521,6 @@ namespace ts { } } - if (signatures.length === 1) { - const declaration = signatures[0].declaration; - if (declaration && isInJavaScriptFile(declaration) && !hasJSDocParameterTags(declaration)) { - if (containsArgumentsReference(declaration)) { - const signatureWithRest = cloneSignature(signatures[0]); - const syntheticArgsSymbol = createSymbol(SymbolFlags.Variable, "args"); - syntheticArgsSymbol.type = anyArrayType; - syntheticArgsSymbol.isRestParameter = true; - signatureWithRest.parameters = concatenate(signatureWithRest.parameters, [syntheticArgsSymbol]); - signatureWithRest.hasRestParameter = true; - signatures = [signatureWithRest]; - } - } - } - const candidates = candidatesOutArray || []; // reorderCandidates fills up the candidates array directly reorderCandidates(signatures, candidates); @@ -15891,7 +15914,7 @@ namespace ts { const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call); if (callSignatures.length) { const signature = resolveCall(node, callSignatures, candidatesOutArray); - if (getReturnTypeOfSignature(signature) !== voidType) { + if (!isJavaScriptConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) { error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword); } if (getThisTypeOfSignature(signature) === voidType) { @@ -16118,10 +16141,30 @@ namespace ts { return getNodeLinks(node).resolvedSignature === resolvingSignature ? resolvingSignature : getResolvedSignature(node); } + /** + * Indicates whether a declaration can be treated as a constructor in a JavaScript + * file. + */ + function isJavaScriptConstructor(node: Declaration): boolean { + if (isInJavaScriptFile(node)) { + // If the node has a @class tag, treat it like a constructor. + if (getJSDocClassTag(node)) return true; + + // If the symbol of the node has members, treat it like a constructor. + const symbol = isFunctionDeclaration(node) || isFunctionExpression(node) ? getSymbolOfNode(node) : + isVariableDeclaration(node) && isFunctionExpression(node.initializer) ? getSymbolOfNode(node.initializer) : + undefined; + + return symbol && symbol.members !== undefined; + } + + return false; + } + function getInferredClassType(symbol: Symbol) { const links = getSymbolLinks(symbol); if (!links.inferredClassType) { - links.inferredClassType = createAnonymousType(symbol, symbol.members, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); + links.inferredClassType = createAnonymousType(symbol, symbol.members || emptySymbols, emptyArray, emptyArray, /*stringIndexType*/ undefined, /*numberIndexType*/ undefined); } return links.inferredClassType; } @@ -16161,7 +16204,7 @@ namespace ts { if (funcSymbol && isDeclarationOfFunctionOrClassExpression(funcSymbol)) { funcSymbol = getSymbolOfNode((funcSymbol.valueDeclaration).initializer); } - if (funcSymbol && funcSymbol.members && funcSymbol.flags & SymbolFlags.Function) { + if (funcSymbol && funcSymbol.flags & SymbolFlags.Function && (funcSymbol.members || getJSDocClassTag(funcSymbol.valueDeclaration))) { return getInferredClassType(funcSymbol); } else if (noImplicitAny) { @@ -16793,8 +16836,9 @@ namespace ts { (expr as PropertyAccessExpression | ElementAccessExpression).expression.kind === SyntaxKind.ThisKeyword) { // Look for if this is the constructor for the class that `symbol` is a property of. const func = getContainingFunction(expr); - if (!(func && func.kind === SyntaxKind.Constructor)) + if (!(func && func.kind === SyntaxKind.Constructor)) { return true; + } // If func.parent is a class and symbol is a (readonly) property of that class, or // if func is a constructor and symbol is a (readonly) parameter property declared in it, // then symbol is writeable here. @@ -21826,6 +21870,10 @@ namespace ts { if (moduleSymbol && hasExportAssignmentSymbol(moduleSymbol)) { error(node.moduleSpecifier, Diagnostics.Module_0_uses_export_and_cannot_be_used_with_export_Asterisk, symbolToString(moduleSymbol)); } + + if (modulekind !== ModuleKind.System && modulekind !== ModuleKind.ES2015) { + checkExternalEmitHelpers(node, ExternalEmitHelpers.ExportStar); + } } } } @@ -22907,7 +22955,9 @@ namespace ts { node = getParseTreeNode(node, isIdentifier); if (node) { const symbol = getReferencedValueSymbol(node); - if (symbol && symbol.flags & SymbolFlags.Alias) { + // We should only get the declaration of an alias if there isn't a local value + // declaration for the symbol + if (isNonLocalAlias(symbol, /*excludes*/ SymbolFlags.Value)) { return getDeclarationOfAliasSymbol(symbol); } } @@ -23498,7 +23548,8 @@ namespace ts { case ExternalEmitHelpers.AsyncGenerator: return "__asyncGenerator"; case ExternalEmitHelpers.AsyncDelegator: return "__asyncDelegator"; case ExternalEmitHelpers.AsyncValues: return "__asyncValues"; - default: Debug.fail("Unrecognized helper."); + case ExternalEmitHelpers.ExportStar: return "__exportStar"; + default: Debug.fail("Unrecognized helper"); } } diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts index 23efd047e46..2488ad68101 100644 --- a/src/compiler/commandLineParser.ts +++ b/src/compiler/commandLineParser.ts @@ -1626,10 +1626,12 @@ namespace ts { } // Remove any subpaths under an existing recursively watched directory. - for (const key in wildcardDirectories) if (hasProperty(wildcardDirectories, key)) { - for (const recursiveKey of recursiveKeys) { - if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) { - delete wildcardDirectories[key]; + for (const key in wildcardDirectories) { + if (hasProperty(wildcardDirectories, key)) { + for (const recursiveKey of recursiveKeys) { + if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) { + delete wildcardDirectories[key]; + } } } } @@ -1717,10 +1719,12 @@ namespace ts { /* @internal */ export function convertCompilerOptionsForTelemetry(opts: ts.CompilerOptions): ts.CompilerOptions { const out: ts.CompilerOptions = {}; - for (const key in opts) if (opts.hasOwnProperty(key)) { - const type = getOptionFromName(key); - if (type !== undefined) { // Ignore unknown options - out[key] = getOptionValueWithEmptyStrings(opts[key], type); + for (const key in opts) { + if (opts.hasOwnProperty(key)) { + const type = getOptionFromName(key); + if (type !== undefined) { // Ignore unknown options + out[key] = getOptionValueWithEmptyStrings(opts[key], type); + } } } return out; diff --git a/src/compiler/core.ts b/src/compiler/core.ts index 1792a393234..6ca99c2d086 100644 --- a/src/compiler/core.ts +++ b/src/compiler/core.ts @@ -51,8 +51,10 @@ namespace ts { // Copies keys/values from template. Note that for..in will not throw if // template is undefined, and instead will just exit the loop. - for (const key in template) if (hasOwnProperty.call(template, key)) { - map.set(key, template[key]); + for (const key in template) { + if (hasOwnProperty.call(template, key)) { + map.set(key, template[key]); + } } return map; @@ -521,8 +523,8 @@ namespace ts { return result || array; } - export function mapDefined(array: ReadonlyArray, mapFn: (x: T, i: number) => T | undefined): ReadonlyArray { - const result: T[] = []; + export function mapDefined(array: ReadonlyArray, mapFn: (x: T, i: number) => U | undefined): U[] { + const result: U[] = []; for (let i = 0; i < array.length; i++) { const item = array[i]; const mapped = mapFn(item, i); @@ -977,9 +979,12 @@ namespace ts { */ export function getOwnKeys(map: MapLike): string[] { const keys: string[] = []; - for (const key in map) if (hasOwnProperty.call(map, key)) { - keys.push(key); + for (const key in map) { + if (hasOwnProperty.call(map, key)) { + keys.push(key); + } } + return keys; } @@ -1042,8 +1047,10 @@ namespace ts { export function assign>(t: T1, ...args: any[]): any; export function assign>(t: T1, ...args: any[]) { for (const arg of args) { - for (const p in arg) if (hasProperty(arg, p)) { - t[p] = arg[p]; + for (const p in arg) { + if (hasProperty(arg, p)) { + t[p] = arg[p]; + } } } return t; @@ -1058,13 +1065,19 @@ namespace ts { export function equalOwnProperties(left: MapLike, right: MapLike, equalityComparer?: (left: T, right: T) => boolean) { if (left === right) return true; if (!left || !right) return false; - for (const key in left) if (hasOwnProperty.call(left, key)) { - if (!hasOwnProperty.call(right, key) === undefined) return false; - if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false; + for (const key in left) { + if (hasOwnProperty.call(left, key)) { + if (!hasOwnProperty.call(right, key) === undefined) return false; + if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false; + } } - for (const key in right) if (hasOwnProperty.call(right, key)) { - if (!hasOwnProperty.call(left, key)) return false; + + for (const key in right) { + if (hasOwnProperty.call(right, key)) { + if (!hasOwnProperty.call(left, key)) return false; + } } + return true; } @@ -1106,12 +1119,18 @@ namespace ts { export function extend(first: T1, second: T2): T1 & T2 { const result: T1 & T2 = {}; - for (const id in second) if (hasOwnProperty.call(second, id)) { - (result as any)[id] = (second as any)[id]; + for (const id in second) { + if (hasOwnProperty.call(second, id)) { + (result as any)[id] = (second as any)[id]; + } } - for (const id in first) if (hasOwnProperty.call(first, id)) { - (result as any)[id] = (first as any)[id]; + + for (const id in first) { + if (hasOwnProperty.call(first, id)) { + (result as any)[id] = (first as any)[id]; + } } + return result; } @@ -2249,6 +2268,7 @@ namespace ts { getSymbolConstructor(): new (flags: SymbolFlags, name: string) => Symbol; getTypeConstructor(): new (checker: TypeChecker, flags: TypeFlags) => Type; getSignatureConstructor(): new (checker: TypeChecker) => Signature; + getSourceMapSourceConstructor(): new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; } function Symbol(this: Symbol, flags: SymbolFlags, name: string) { @@ -2279,6 +2299,12 @@ namespace ts { this.original = undefined; } + function SourceMapSource(this: SourceMapSource, fileName: string, text: string, skipTrivia?: (pos: number) => number) { + this.fileName = fileName; + this.text = text; + this.skipTrivia = skipTrivia || (pos => pos); + } + export let objectAllocator: ObjectAllocator = { getNodeConstructor: () => Node, getTokenConstructor: () => Node, @@ -2286,7 +2312,8 @@ namespace ts { getSourceFileConstructor: () => Node, getSymbolConstructor: () => Symbol, getTypeConstructor: () => Type, - getSignatureConstructor: () => Signature + getSignatureConstructor: () => Signature, + getSourceMapSourceConstructor: () => SourceMapSource, }; export const enum AssertionLevel { diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index 1e6cc3b12db..a788bf6a4d0 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -959,7 +959,7 @@ namespace ts { function emitConstructorType(node: ConstructorTypeNode) { write("new "); emitTypeParameters(node, node.typeParameters); - emitParametersForArrow(node, node.parameters); + emitParameters(node, node.parameters); write(" => "); emit(node.type); } @@ -2283,11 +2283,25 @@ namespace ts { emitList(parentNode, parameters, ListFormat.Parameters); } - function emitParametersForArrow(parentNode: Node, parameters: NodeArray) { - if (parameters && - parameters.length === 1 && - parameters[0].type === undefined && - parameters[0].pos === parentNode.pos) { + function canEmitSimpleArrowHead(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + const parameter = singleOrUndefined(parameters); + return parameter + && parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter + && !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation + && !some(parentNode.decorators) // parent may not have decorators + && !some(parentNode.modifiers) // parent may not have modifiers + && !some(parentNode.typeParameters) // parent may not have type parameters + && !some(parameter.decorators) // parameter may not have decorators + && !some(parameter.modifiers) // parameter may not have modifiers + && !parameter.dotDotDotToken // parameter may not be rest + && !parameter.questionToken // parameter may not be optional + && !parameter.type // parameter may not have a type annotation + && !parameter.initializer // parameter may not have an initializer + && isIdentifier(parameter.name); // parameter name must be identifier + } + + function emitParametersForArrow(parentNode: FunctionTypeNode | ArrowFunction, parameters: NodeArray) { + if (canEmitSimpleArrowHead(parentNode, parameters)) { emit(parameters[0]); } else { diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index 12e8110e7be..32244a86792 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -228,7 +228,7 @@ namespace ts { // Signature elements - export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) { + export function createTypeParameterDeclaration(name: string | Identifier, constraint?: TypeNode, defaultType?: TypeNode) { const node = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration; node.name = asName(name); node.constraint = constraint; @@ -2314,15 +2314,24 @@ namespace ts { /** * Sets a custom text range to use when emitting source maps. */ - export function setSourceMapRange(node: T, range: TextRange | undefined) { + export function setSourceMapRange(node: T, range: SourceMapRange | undefined) { getOrCreateEmitNode(node).sourceMapRange = range; return node; } + let SourceMapSource: new (fileName: string, text: string, skipTrivia?: (pos: number) => number) => SourceMapSource; + + /** + * Create an external source map source file reference + */ + export function createSourceMapSource(fileName: string, text: string, skipTrivia?: (pos: number) => number): SourceMapSource { + return new (SourceMapSource || (SourceMapSource = objectAllocator.getSourceMapSourceConstructor()))(fileName, text, skipTrivia); + } + /** * Gets the TextRange to use for source maps for a token of a node. */ - export function getTokenSourceMapRange(node: Node, token: SyntaxKind): TextRange | undefined { + export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined { const emitNode = node.emitNode; const tokenSourceMapRanges = emitNode && emitNode.tokenSourceMapRanges; return tokenSourceMapRanges && tokenSourceMapRanges[token]; @@ -2331,7 +2340,7 @@ namespace ts { /** * Sets the TextRange to use for source maps for a token of a node. */ - export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: TextRange | undefined) { + export function setTokenSourceMapRange(node: T, token: SyntaxKind, range: SourceMapRange | undefined) { const emitNode = getOrCreateEmitNode(node); const tokenSourceMapRanges = emitNode.tokenSourceMapRanges || (emitNode.tokenSourceMapRanges = []); tokenSourceMapRanges[token] = range; @@ -3841,23 +3850,34 @@ namespace ts { return emitNode && emitNode.externalHelpersModuleName; } - export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions) { - if (compilerOptions.importHelpers && (isExternalModule(node) || compilerOptions.isolatedModules)) { + export function getOrCreateExternalHelpersModuleNameIfNeeded(node: SourceFile, compilerOptions: CompilerOptions, hasExportStarsToExportValues?: boolean) { + if (compilerOptions.importHelpers && isEffectiveExternalModule(node, compilerOptions)) { const externalHelpersModuleName = getExternalHelpersModuleName(node); if (externalHelpersModuleName) { return externalHelpersModuleName; } - const helpers = getEmitHelpers(node); - if (helpers) { - for (const helper of helpers) { - if (!helper.scoped) { - const parseNode = getOriginalNode(node, isSourceFile); - const emitNode = getOrCreateEmitNode(parseNode); - return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText)); + const moduleKind = getEmitModuleKind(compilerOptions); + let create = hasExportStarsToExportValues + && moduleKind !== ModuleKind.System + && moduleKind !== ModuleKind.ES2015; + if (!create) { + const helpers = getEmitHelpers(node); + if (helpers) { + for (const helper of helpers) { + if (!helper.scoped) { + create = true; + break; + } } } } + + if (create) { + const parseNode = getOriginalNode(node, isSourceFile); + const emitNode = getOrCreateEmitNode(parseNode); + return emitNode.externalHelpersModuleName || (emitNode.externalHelpersModuleName = createUniqueName(externalHelpersModuleNameText)); + } } } @@ -4240,17 +4260,6 @@ namespace ts { let exportEquals: ExportAssignment = undefined; let hasExportStarsToExportValues = false; - const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions); - const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration( - /*decorators*/ undefined, - /*modifiers*/ undefined, - createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)), - createLiteral(externalHelpersModuleNameText)); - - if (externalHelpersImportDeclaration) { - externalImports.push(externalHelpersImportDeclaration); - } - for (const node of sourceFile.statements) { switch (node.kind) { case SyntaxKind.ImportDeclaration: @@ -4361,6 +4370,17 @@ namespace ts { } } + const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues); + const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)), + createLiteral(externalHelpersModuleNameText)); + + if (externalHelpersImportDeclaration) { + externalImports.unshift(externalHelpersImportDeclaration); + } + return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration }; } diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index 84306cd81d8..8002709f3f6 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -6533,6 +6533,10 @@ namespace ts { case "augments": tag = parseAugmentsTag(atToken, tagName); break; + case "class": + case "constructor": + tag = parseClassTag(atToken, tagName); + break; case "arg": case "argument": case "param": @@ -6659,14 +6663,12 @@ namespace ts { }); } - function parseBracketNameInPropertyAndParamTag() { - let name: Identifier; - let isBracketed: boolean; + function parseBracketNameInPropertyAndParamTag(): { name: Identifier, isBracketed: boolean } { // Looking for something like '[foo]' or 'foo' - if (parseOptionalToken(SyntaxKind.OpenBracketToken)) { - name = parseJSDocIdentifierName(); + const isBracketed = parseOptional(SyntaxKind.OpenBracketToken); + const name = parseJSDocIdentifierName(/*createIfMissing*/ true); + if (isBracketed) { skipWhitespace(); - isBracketed = true; // May have an optional default, e.g. '[foo = 42]' if (parseOptionalToken(SyntaxKind.EqualsToken)) { @@ -6675,9 +6677,7 @@ namespace ts { parseExpected(SyntaxKind.CloseBracketToken); } - else if (tokenIsIdentifierOrKeyword(token())) { - name = parseJSDocIdentifierName(); - } + return { name, isBracketed }; } @@ -6688,11 +6688,6 @@ namespace ts { const { name, isBracketed } = parseBracketNameInPropertyAndParamTag(); skipWhitespace(); - if (!name) { - parseErrorAtPosition(scanner.getStartPos(), 0, Diagnostics.Identifier_expected); - return undefined; - } - let preName: Identifier, postName: Identifier; if (typeExpression) { postName = name; @@ -6752,6 +6747,13 @@ namespace ts { return finishNode(result); } + function parseClassTag(atToken: AtToken, tagName: Identifier): JSDocClassTag { + const tag = createNode(SyntaxKind.JSDocClassTag, atToken.pos); + tag.atToken = atToken; + tag.tagName = tagName; + return finishNode(tag); + } + function parseTypedefTag(atToken: AtToken, tagName: Identifier): JSDocTypedefTag { const typeExpression = tryParseTypeExpression(); skipWhitespace(); @@ -6936,14 +6938,19 @@ namespace ts { return currentToken = scanner.scanJSDocToken(); } - function parseJSDocIdentifierName(): Identifier { - return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token())); + function parseJSDocIdentifierName(createIfMissing = false): Identifier { + return createJSDocIdentifier(tokenIsIdentifierOrKeyword(token()), createIfMissing); } - function createJSDocIdentifier(isIdentifier: boolean): Identifier { + function createJSDocIdentifier(isIdentifier: boolean, createIfMissing: boolean): Identifier { if (!isIdentifier) { - parseErrorAtCurrentToken(Diagnostics.Identifier_expected); - return undefined; + if (createIfMissing) { + return createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics.Identifier_expected); + } + else { + parseErrorAtCurrentToken(Diagnostics.Identifier_expected); + return undefined; + } } const pos = scanner.getTokenPos(); diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 68a36c40a80..dd43b3c8263 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -363,7 +363,7 @@ namespace ts { }; } - export function getLineAndCharacterOfPosition(sourceFile: SourceFile, position: number): LineAndCharacter { + export function getLineAndCharacterOfPosition(sourceFile: SourceFileLike, position: number): LineAndCharacter { return computeLineAndCharacterOfPosition(getLineStarts(sourceFile), position); } diff --git a/src/compiler/sourcemap.ts b/src/compiler/sourcemap.ts index d743f488e75..ffef485581b 100644 --- a/src/compiler/sourcemap.ts +++ b/src/compiler/sourcemap.ts @@ -22,7 +22,7 @@ namespace ts { * * @param sourceFile The source file. */ - setSourceFile(sourceFile: SourceFile): void; + setSourceFile(sourceFile: SourceMapSource): void; /** * Emits a mapping. @@ -81,7 +81,7 @@ namespace ts { export function createSourceMapWriter(host: EmitHost, writer: EmitTextWriter): SourceMapWriter { const compilerOptions = host.getCompilerOptions(); const extendedDiagnostics = compilerOptions.extendedDiagnostics; - let currentSourceFile: SourceFile; + let currentSource: SourceMapSource; let currentSourceText: string; let sourceMapDir: string; // The directory in which sourcemap will be @@ -109,6 +109,13 @@ namespace ts { getSourceMappingURL, }; + /** + * Skips trivia such as comments and white-space that can optionally overriden by the source map source + */ + function skipSourceTrivia(pos: number): number { + return currentSource.skipTrivia ? currentSource.skipTrivia(pos) : skipTrivia(currentSourceText, pos); + } + /** * Initialize the SourceMapWriter for a new output file. * @@ -125,7 +132,7 @@ namespace ts { reset(); } - currentSourceFile = undefined; + currentSource = undefined; currentSourceText = undefined; // Current source map file and its index in the sources list @@ -192,7 +199,7 @@ namespace ts { return; } - currentSourceFile = undefined; + currentSource = undefined; sourceMapDir = undefined; sourceMapSourceIndex = undefined; lastRecordedSourceMapSpan = undefined; @@ -263,7 +270,7 @@ namespace ts { performance.mark("beforeSourcemap"); } - const sourceLinePos = getLineAndCharacterOfPosition(currentSourceFile, pos); + const sourceLinePos = getLineAndCharacterOfPosition(currentSource, pos); // Convert the location to be one-based. sourceLinePos.line++; @@ -320,14 +327,22 @@ namespace ts { if (node) { const emitNode = node.emitNode; const emitFlags = emitNode && emitNode.flags; - const { pos, end } = emitNode && emitNode.sourceMapRange || node; + const range = emitNode && emitNode.sourceMapRange; + const { pos, end } = range || node; + let source = range && range.source; + const oldSource = currentSource; + if (source === oldSource) source = undefined; + + if (source) setSourceFile(source); if (node.kind !== SyntaxKind.NotEmittedStatement && (emitFlags & EmitFlags.NoLeadingSourceMap) === 0 && pos >= 0) { - emitPos(skipTrivia(currentSourceText, pos)); + emitPos(skipSourceTrivia(pos)); } + if (source) setSourceFile(oldSource); + if (emitFlags & EmitFlags.NoNestedSourceMaps) { disabled = true; emitCallback(hint, node); @@ -337,11 +352,15 @@ namespace ts { emitCallback(hint, node); } + if (source) setSourceFile(source); + if (node.kind !== SyntaxKind.NotEmittedStatement && (emitFlags & EmitFlags.NoTrailingSourceMap) === 0 && end >= 0) { emitPos(end); } + + if (source) setSourceFile(oldSource); } } @@ -362,7 +381,7 @@ namespace ts { const emitFlags = emitNode && emitNode.flags; const range = emitNode && emitNode.tokenSourceMapRanges && emitNode.tokenSourceMapRanges[token]; - tokenPos = skipTrivia(currentSourceText, range ? range.pos : tokenPos); + tokenPos = skipSourceTrivia(range ? range.pos : tokenPos); if ((emitFlags & EmitFlags.NoTokenLeadingSourceMaps) === 0 && tokenPos >= 0) { emitPos(tokenPos); } @@ -382,13 +401,13 @@ namespace ts { * * @param sourceFile The source file. */ - function setSourceFile(sourceFile: SourceFile) { + function setSourceFile(sourceFile: SourceMapSource) { if (disabled) { return; } - currentSourceFile = sourceFile; - currentSourceText = currentSourceFile.text; + currentSource = sourceFile; + currentSourceText = currentSource.text; // Add the file to tsFilePaths // If sourceroot option: Use the relative path corresponding to the common directory path @@ -396,7 +415,7 @@ namespace ts { const sourcesDirectoryPath = compilerOptions.sourceRoot ? host.getCommonSourceDirectory() : sourceMapDir; const source = getRelativePathToDirectoryOrUrl(sourcesDirectoryPath, - currentSourceFile.fileName, + currentSource.fileName, host.getCurrentDirectory(), host.getCanonicalFileName, /*isAbsolutePathAnUrl*/ true); @@ -407,10 +426,10 @@ namespace ts { sourceMapData.sourceMapSources.push(source); // The one that can be used from program to get the actual source file - sourceMapData.inputSourceFileNames.push(currentSourceFile.fileName); + sourceMapData.inputSourceFileNames.push(currentSource.fileName); if (compilerOptions.inlineSources) { - sourceMapData.sourceMapSourcesContent.push(currentSourceFile.text); + sourceMapData.sourceMapSourcesContent.push(currentSource.text); } } } diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts index b2e1c1c70a9..bf0c7dbf7b9 100644 --- a/src/compiler/transformers/module/module.ts +++ b/src/compiler/transformers/module/module.ts @@ -103,7 +103,7 @@ namespace ts { addRange(statements, endLexicalEnvironment()); const updated = updateSourceFileNode(node, setTextRange(createNodeArray(statements), node.statements)); - if (currentModuleInfo.hasExportStarsToExportValues) { + if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) { // If we have any `export * from ...` declarations // we need to inform the emitter to add the __export helper. addEmitHelper(updated, exportStarHelper); @@ -408,7 +408,7 @@ namespace ts { addRange(statements, endLexicalEnvironment()); const body = createBlock(statements, /*multiLine*/ true); - if (currentModuleInfo.hasExportStarsToExportValues) { + if (currentModuleInfo.hasExportStarsToExportValues && !compilerOptions.importHelpers) { // If we have any `export * from ...` declarations // we need to inform the emitter to add the __export helper. addEmitHelper(body, exportStarHelper); @@ -833,15 +833,7 @@ namespace ts { // export * from "mod"; return setTextRange( createStatement( - createCall( - createIdentifier("__export"), - /*typeArguments*/ undefined, - [ - moduleKind !== ModuleKind.AMD - ? createRequireCall(node) - : generatedName - ] - ) + createExportStarHelper(context, moduleKind !== ModuleKind.AMD ? createRequireCall(node) : generatedName) ), node ); @@ -1598,9 +1590,17 @@ namespace ts { text: ` function __export(m) { for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; - }` + } + ` }; + function createExportStarHelper(context: TransformationContext, module: Expression) { + const compilerOptions = context.getCompilerOptions(); + return compilerOptions.importHelpers + ? createCall(getHelperName("__exportStar"), /*typeArguments*/ undefined, [module, createIdentifier("exports")]) + : createCall(createIdentifier("__export"), /*typeArguments*/ undefined, [module]); + } + // emit helper for dynamic import const dynamicImportUMDHelper: EmitHelper = { name: "typescript:dynamicimport-sync-require", diff --git a/src/compiler/types.ts b/src/compiler/types.ts index 1c7f36bb27b..8833fbb9d08 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -374,6 +374,7 @@ namespace ts { JSDocComment, JSDocTag, JSDocAugmentsTag, + JSDocClassTag, JSDocParameterTag, JSDocReturnTag, JSDocTypeTag, @@ -424,7 +425,7 @@ namespace ts { FirstNode = QualifiedName, FirstJSDocNode = JSDocTypeExpression, LastJSDocNode = JSDocLiteralType, - FirstJSDocTagNode = JSDocComment, + FirstJSDocTagNode = JSDocTag, LastJSDocTagNode = JSDocLiteralType } @@ -2132,6 +2133,10 @@ namespace ts { typeExpression: JSDocTypeExpression; } + export interface JSDocClassTag extends JSDocTag { + kind: SyntaxKind.JSDocClassTag; + } + export interface JSDocTemplateTag extends JSDocTag { kind: SyntaxKind.JSDocTemplateTag; typeParameters: NodeArray; @@ -4008,18 +4013,29 @@ namespace ts { ES2015FunctionSyntaxMask = ContainsCapturedLexicalThis | ContainsDefaultValueAssignments, } + export interface SourceMapRange extends TextRange { + source?: SourceMapSource; + } + + export interface SourceMapSource { + fileName: string; + text: string; + /* @internal */ lineMap: number[]; + skipTrivia?: (pos: number) => number; + } + /* @internal */ export interface EmitNode { - annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup. - flags?: EmitFlags; // Flags that customize emit - leadingComments?: SynthesizedComment[]; // Synthesized leading comments + annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup. + flags?: EmitFlags; // Flags that customize emit + leadingComments?: SynthesizedComment[]; // Synthesized leading comments trailingComments?: SynthesizedComment[]; // Synthesized trailing comments - commentRange?: TextRange; // The text range to use when emitting leading or trailing comments - sourceMapRange?: TextRange; // The text range to use when emitting leading or trailing source mappings - tokenSourceMapRanges?: TextRange[]; // The text range to use when emitting source mappings for tokens - constantValue?: string | number; // The constant value of an expression - externalHelpersModuleName?: Identifier; // The local name for an imported helpers module - helpers?: EmitHelper[]; // Emit helpers for the node + commentRange?: TextRange; // The text range to use when emitting leading or trailing comments + sourceMapRange?: SourceMapRange; // The text range to use when emitting leading or trailing source mappings + tokenSourceMapRanges?: SourceMapRange[]; // The text range to use when emitting source mappings for tokens + constantValue?: string | number; // The constant value of an expression + externalHelpersModuleName?: Identifier; // The local name for an imported helpers module + helpers?: EmitHelper[]; // Emit helpers for the node } export const enum EmitFlags { @@ -4081,6 +4097,7 @@ namespace ts { AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation) AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation) AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation) + ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation) // Helpers included by ES2015 for..of ForOfIncludes = Values, @@ -4098,7 +4115,7 @@ namespace ts { SpreadIncludes = Read | Spread, FirstEmitHelper = Extends, - LastEmitHelper = AsyncValues + LastEmitHelper = ExportStar } export const enum EmitHint { diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 30f7e0a52f9..77f1e43c9cb 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -1562,6 +1562,10 @@ namespace ts { return getFirstJSDocTag(node, SyntaxKind.JSDocAugmentsTag) as JSDocAugmentsTag; } + export function getJSDocClassTag(node: Node): JSDocClassTag { + return getFirstJSDocTag(node, SyntaxKind.JSDocClassTag) as JSDocClassTag; + } + export function getJSDocReturnTag(node: Node): JSDocReturnTag { return getFirstJSDocTag(node, SyntaxKind.JSDocReturnTag) as JSDocReturnTag; } diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index 07aacf3c8a7..f40d63709cb 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -1036,21 +1036,27 @@ namespace FourSlash { fail(`Expected ${expected}, got ${actual}`); } - for (const key in actual) if (ts.hasProperty(actual as any, key)) { - const ak = actual[key], ek = expected[key]; - if (typeof ak === "object" && typeof ek === "object") { - recur(ak, ek, path ? path + "." + key : key); - } - else if (ak !== ek) { - fail(`Expected '${key}' to be '${ek}', got '${ak}'`); + for (const key in actual) { + if (ts.hasProperty(actual as any, key)) { + const ak = actual[key], ek = expected[key]; + if (typeof ak === "object" && typeof ek === "object") { + recur(ak, ek, path ? path + "." + key : key); + } + else if (ak !== ek) { + fail(`Expected '${key}' to be '${ek}', got '${ak}'`); + } } } - for (const key in expected) if (ts.hasProperty(expected as any, key)) { - if (!ts.hasProperty(actual as any, key)) { - fail(`${msgPrefix}Missing property '${key}'`); + + for (const key in expected) { + if (ts.hasProperty(expected as any, key)) { + if (!ts.hasProperty(actual as any, key)) { + fail(`${msgPrefix}Missing property '${key}'`); + } } } }; + if (fullActual === undefined || fullExpected === undefined) { if (fullActual === fullExpected) { return; @@ -1132,15 +1138,17 @@ namespace FourSlash { } public verifyQuickInfos(namesAndTexts: { [name: string]: string | [string, string] }) { - for (const name in namesAndTexts) if (ts.hasProperty(namesAndTexts, name)) { - const text = namesAndTexts[name]; - if (ts.isArray(text)) { - assert(text.length === 2); - const [expectedText, expectedDocumentation] = text; - this.verifyQuickInfoAt(name, expectedText, expectedDocumentation); - } - else { - this.verifyQuickInfoAt(name, text); + for (const name in namesAndTexts) { + if (ts.hasProperty(namesAndTexts, name)) { + const text = namesAndTexts[name]; + if (ts.isArray(text)) { + assert(text.length === 2); + const [expectedText, expectedDocumentation] = text; + this.verifyQuickInfoAt(name, expectedText, expectedDocumentation); + } + else { + this.verifyQuickInfoAt(name, text); + } } } } @@ -1149,7 +1157,6 @@ namespace FourSlash { if (expectedDocumentation === "") { throw new Error("Use 'undefined' instead"); } - const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition); const actualQuickInfoText = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.displayParts) : ""; const actualQuickInfoDocumentation = actualQuickInfo ? ts.displayPartsToString(actualQuickInfo.documentation) : ""; @@ -1595,16 +1602,19 @@ namespace FourSlash { } private printMembersOrCompletions(info: ts.CompletionInfo) { + if (info === undefined) { return "No completion info."; } + const { entries } = info; + function pad(s: string, length: number) { return s + new Array(length - s.length + 1).join(" "); } function max(arr: T[], selector: (x: T) => number): number { return arr.reduce((prev, x) => Math.max(prev, selector(x)), 0); } - const longestNameLength = max(info.entries, m => m.name.length); - const longestKindLength = max(info.entries, m => m.kind.length); - info.entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0); - const membersString = info.entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n"); + const longestNameLength = max(entries, m => m.name.length); + const longestKindLength = max(entries, m => m.kind.length); + entries.sort((m, n) => m.sortText > n.sortText ? 1 : m.sortText < n.sortText ? -1 : m.name > n.name ? 1 : m.name < n.name ? -1 : 0); + const membersString = entries.map(m => `${pad(m.name, longestNameLength)} ${pad(m.kind, longestKindLength)} ${m.kindModifiers}`).join("\n"); Harness.IO.log(membersString); } @@ -2156,7 +2166,7 @@ namespace FourSlash { Harness.IO.log(this.spanInfoToString(this.getNameOrDottedNameSpan(pos), "**")); } - private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[]) { + private verifyClassifications(expected: { classificationType: string; text: string; textSpan?: TextSpan }[], actual: ts.ClassifiedSpan[], sourceFileText: string) { if (actual.length !== expected.length) { this.raiseError("verifyClassifications failed - expected total classifications to be " + expected.length + ", but was " + actual.length + @@ -2196,9 +2206,11 @@ namespace FourSlash { }); function jsonMismatchString() { + const showActual = actual.map(({ classificationType, textSpan }) => + ({ classificationType, text: sourceFileText.slice(textSpan.start, textSpan.start + textSpan.length) })); return Harness.IO.newLine() + "expected: '" + Harness.IO.newLine() + stringify(expected) + "'" + Harness.IO.newLine() + - "actual: '" + Harness.IO.newLine() + stringify(actual) + "'"; + "actual: '" + Harness.IO.newLine() + stringify(showActual) + "'"; } } @@ -2221,14 +2233,14 @@ namespace FourSlash { const actual = this.languageService.getSemanticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length)); - this.verifyClassifications(expected, actual); + this.verifyClassifications(expected, actual, this.activeFile.content); } public verifySyntacticClassifications(expected: { classificationType: string; text: string }[]) { const actual = this.languageService.getSyntacticClassifications(this.activeFile.fileName, ts.createTextSpan(0, this.activeFile.content.length)); - this.verifyClassifications(expected, actual); + this.verifyClassifications(expected, actual, this.activeFile.content); } public verifyOutliningSpans(spans: TextSpan[]) { @@ -2741,6 +2753,7 @@ namespace FourSlash { markerName: string, expectedContent: string, refactorNameToApply: string, + actionName: string, formattingOptions?: ts.FormatCodeSettings) { formattingOptions = formattingOptions || this.formatCodeSettings; @@ -2753,9 +2766,11 @@ namespace FourSlash { this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`); } - const codeActions = this.languageService.getRefactorCodeActions(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply); + const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName); - this.applyCodeActions(codeActions); + for (const edit of editInfo.edits) { + this.applyEdits(edit.fileName, edit.textChanges); + } const actualContent = this.getFileContent(this.activeFile.fileName); if (this.normalizeNewlines(actualContent) !== this.normalizeNewlines(expectedContent)) { @@ -3798,8 +3813,8 @@ namespace FourSlashInterface { this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index); } - public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: ts.FormatCodeSettings): void { - this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, formattingOptions); + public fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: ts.FormatCodeSettings): void { + this.state.verifyFileAfterApplyingRefactorAtMarker(markerName, expectedContent, refactorNameToApply, actionName, formattingOptions); } public rangeIs(expectedText: string, includeWhiteSpace?: boolean): void { diff --git a/src/harness/harness.ts b/src/harness/harness.ts index 9bf4591112d..d61ba6e953b 100644 --- a/src/harness/harness.ts +++ b/src/harness/harness.ts @@ -259,8 +259,9 @@ namespace Utils { return true; } else if ((f & v) > 0) { - if (result.length) + if (result.length) { result += " | "; + } result += flags[v]; return false; } diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts index 7aefb0f3a1f..132db1e53eb 100644 --- a/src/harness/harnessLanguageService.ts +++ b/src/harness/harnessLanguageService.ts @@ -492,7 +492,7 @@ namespace Harness.LanguageService { getCodeFixDiagnostics(): ts.Diagnostic[] { throw new Error("Not supported on the shim."); } - getRefactorCodeActions(): ts.CodeAction[] { + getEditsForRefactor(): ts.RefactorEditInfo { throw new Error("Not supported on the shim."); } getApplicableRefactors(): ts.ApplicableRefactorInfo[] { diff --git a/src/harness/unittests/printer.ts b/src/harness/unittests/printer.ts index 4bdafe04ba1..23e301f3669 100644 --- a/src/harness/unittests/printer.ts +++ b/src/harness/unittests/printer.ts @@ -81,63 +81,136 @@ namespace ts { describe("printNode", () => { const printsCorrectly = makePrintsCorrectly("printsNodeCorrectly"); - let sourceFile: SourceFile; - before(() => sourceFile = createSourceFile("source.ts", "", ScriptTarget.ES2015)); - // tslint:disable boolean-trivia - const syntheticNode = createClassDeclaration( - undefined, - undefined, - /*name*/ createIdentifier("C"), - undefined, - undefined, - createNodeArray([ - createProperty( - undefined, + printsCorrectly("class", {}, printer => printer.printNode( + EmitHint.Unspecified, + createClassDeclaration( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*name*/ createIdentifier("C"), + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [createProperty( + /*decorators*/ undefined, createNodeArray([createToken(SyntaxKind.PublicKeyword)]), createIdentifier("prop"), - undefined, - undefined, - undefined - ) - ]) - ); + /*questionToken*/ undefined, + /*type*/ undefined, + /*initializer*/ undefined + )] + ), + createSourceFile("source.ts", "", ScriptTarget.ES2015) + )); + + printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode( + EmitHint.Unspecified, + createNamespaceExportDeclaration("B"), + createSourceFile("source.ts", "", ScriptTarget.ES2015) + )); // https://github.com/Microsoft/TypeScript/issues/15971 - const classWithOptionalMethodAndProperty = createClassDeclaration( - undefined, - /* modifiers */ createNodeArray([createToken(SyntaxKind.DeclareKeyword)]), - /* name */ createIdentifier("X"), - undefined, - undefined, - createNodeArray([ - createMethod( - undefined, - undefined, - undefined, - /* name */ createIdentifier("method"), - /* questionToken */ createToken(SyntaxKind.QuestionToken), - undefined, - undefined, - /* type */ createKeywordTypeNode(SyntaxKind.VoidKeyword), - undefined + printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode( + EmitHint.Unspecified, + createClassDeclaration( + /*decorators*/ undefined, + /*modifiers*/ [createToken(SyntaxKind.DeclareKeyword)], + /*name*/ createIdentifier("X"), + /*typeParameters*/ undefined, + /*heritageClauses*/ undefined, + [ + createMethod( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*asteriskToken*/ undefined, + /*name*/ createIdentifier("method"), + /*questionToken*/ createToken(SyntaxKind.QuestionToken), + /*typeParameters*/ undefined, + [], + /*type*/ createKeywordTypeNode(SyntaxKind.VoidKeyword), + /*body*/ undefined + ), + createProperty( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*name*/ createIdentifier("property"), + /*questionToken*/ createToken(SyntaxKind.QuestionToken), + /*type*/ createKeywordTypeNode(SyntaxKind.StringKeyword), + /*initializer*/ undefined + ), + ] + ), + createSourceFile("source.ts", "", ScriptTarget.ES2015) + )); + + // https://github.com/Microsoft/TypeScript/issues/15651 + printsCorrectly("functionTypes", {}, printer => printer.printNode( + EmitHint.Unspecified, + createTupleTypeNode([ + createFunctionTypeNode( + /*typeArguments*/ undefined, + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + createIdentifier("args") + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) ), - createProperty( - undefined, - undefined, - /* name */ createIdentifier("property"), - /* questionToken */ createToken(SyntaxKind.QuestionToken), - /* type */ createKeywordTypeNode(SyntaxKind.StringKeyword), - undefined + createFunctionTypeNode( + [createTypeParameterDeclaration("T")], + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + createIdentifier("args") + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) ), - ]) - ); - - // tslint:enable boolean-trivia - printsCorrectly("class", {}, printer => printer.printNode(EmitHint.Unspecified, syntheticNode, sourceFile)); - - printsCorrectly("namespaceExportDeclaration", {}, printer => printer.printNode(EmitHint.Unspecified, createNamespaceExportDeclaration("B"), sourceFile)); - - printsCorrectly("classWithOptionalMethodAndProperty", {}, printer => printer.printNode(EmitHint.Unspecified, classWithOptionalMethodAndProperty, sourceFile)); + createFunctionTypeNode( + /*typeArguments*/ undefined, + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + createToken(SyntaxKind.DotDotDotToken), + createIdentifier("args") + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) + ), + createFunctionTypeNode( + /*typeArguments*/ undefined, + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + createIdentifier("args"), + createToken(SyntaxKind.QuestionToken) + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) + ), + createFunctionTypeNode( + /*typeArguments*/ undefined, + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + createIdentifier("args"), + /*questionToken*/ undefined, + createKeywordTypeNode(SyntaxKind.AnyKeyword) + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) + ), + createFunctionTypeNode( + /*typeArguments*/ undefined, + [createParameter( + /*decorators*/ undefined, + /*modifiers*/ undefined, + /*dotDotDotToken*/ undefined, + createObjectBindingPattern([]) + )], + createKeywordTypeNode(SyntaxKind.AnyKeyword) + ), + ]), + createSourceFile("source.ts", "", ScriptTarget.ES2015) + )); }); }); } diff --git a/src/harness/unittests/session.ts b/src/harness/unittests/session.ts index db33d87f087..efc769efeca 100644 --- a/src/harness/unittests/session.ts +++ b/src/harness/unittests/session.ts @@ -240,8 +240,8 @@ namespace ts.server { CommandNames.GetCodeFixesFull, CommandNames.GetSupportedCodeFixes, CommandNames.GetApplicableRefactors, - CommandNames.GetRefactorCodeActions, - CommandNames.GetRefactorCodeActionsFull, + CommandNames.GetEditsForRefactor, + CommandNames.GetEditsForRefactorFull, ]; it("should not throw when commands are executed with invalid arguments", () => { diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts index 6f898e7f4a6..7a19aa9167f 100644 --- a/src/harness/unittests/tsserverProjectSystem.ts +++ b/src/harness/unittests/tsserverProjectSystem.ts @@ -13,7 +13,8 @@ namespace ts.projectSystem { express: "express", jquery: "jquery", lodash: "lodash", - moment: "moment" + moment: "moment", + chroma: "chroma-js" }) }; @@ -61,7 +62,6 @@ namespace ts.projectSystem { super(installTypingHost, globalTypingsCacheLocation, safeList.path, throttleLimit, log); } - safeFileList = safeList.path; protected postExecActions: PostExecAction[] = []; executePendingCommands() { diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts index 699b1807428..c356d0941c0 100644 --- a/src/harness/unittests/typingsInstaller.ts +++ b/src/harness/unittests/typingsInstaller.ts @@ -1009,6 +1009,26 @@ namespace ts.projectSystem { }); describe("discover typings", () => { + it("should use mappings from safe list", () => { + const app = { + path: "/a/b/app.js", + content: "" + }; + const jquery = { + path: "/a/b/jquery.js", + content: "" + }; + const chroma = { + path: "/a/b/chroma.min.js", + content: "" + }; + const cache = createMap(); + + const host = createServerHost([app, jquery, chroma]); + const result = JsTyping.discoverTypings(host, [app.path, jquery.path, chroma.path], getDirectoryPath(app.path), /*safeListPath*/ undefined, cache, { enable: true }, []); + assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]); + }); + it("should return node for core modules", () => { const f = { path: "/a/b/app.js", @@ -1016,6 +1036,7 @@ namespace ts.projectSystem { }; const host = createServerHost([f]); const cache = createMap(); + for (const name of JsTyping.nodeCoreModuleList) { const result = JsTyping.discoverTypings(host, [f.path], getDirectoryPath(f.path), /*safeListPath*/ undefined, cache, { enable: true }, [name, "somename"]); assert.deepEqual(result.newTypingNames.sort(), ["node", "somename"]); @@ -1040,7 +1061,7 @@ namespace ts.projectSystem { }); describe("telemetry events", () => { - it ("should be received", () => { + it("should be received", () => { const f1 = { path: "/a/app.js", content: "" @@ -1089,7 +1110,7 @@ namespace ts.projectSystem { }); describe("progress notifications", () => { - it ("should be sent for success", () => { + it("should be sent for success", () => { const f1 = { path: "/a/app.js", content: "" @@ -1140,7 +1161,7 @@ namespace ts.projectSystem { checkProjectActualFiles(projectService.inferredProjects[0], [f1.path, commander.path]); }); - it ("should be sent for error", () => { + it("should be sent for error", () => { const f1 = { path: "/a/app.js", content: "" diff --git a/src/server/client.ts b/src/server/client.ts index aca52422e44..2cfe32f521a 100644 --- a/src/server/client.ts +++ b/src/server/client.ts @@ -719,20 +719,49 @@ namespace ts.server { return response.body; } - getRefactorCodeActions( + getEditsForRefactor( fileName: string, _formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, - refactorName: string) { + refactorName: string, + actionName: string): RefactorEditInfo { - const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetRefactorCodeActionsRequestArgs; - args.refactorName = refactorName; + const args = this.createFileLocationOrRangeRequestArgs(positionOrRange, fileName) as protocol.GetEditsForRefactorRequestArgs; + args.refactor = refactorName; + args.action = actionName; - const request = this.processRequest(CommandNames.GetRefactorCodeActions, args); - const response = this.processResponse(request); - const codeActions = response.body.actions; + const request = this.processRequest(CommandNames.GetEditsForRefactor, args); + const response = this.processResponse(request); - return map(codeActions, codeAction => this.convertCodeActions(codeAction, fileName)); + if (!response.body) { + return { + edits: [] + }; + } + + const edits: FileTextChanges[] = this.convertCodeEditsToTextChanges(response.body.edits); + + const renameFilename: string | undefined = response.body.renameFilename; + let renameLocation: number | undefined = undefined; + if (renameFilename !== undefined) { + renameLocation = this.lineOffsetToPosition(renameFilename, response.body.renameLocation); + } + + return { + edits, + renameFilename, + renameLocation + }; + } + + private convertCodeEditsToTextChanges(edits: ts.server.protocol.FileCodeEdits[]): FileTextChanges[] { + return edits.map(edit => { + const fileName = edit.fileName; + return { + fileName, + textChanges: edit.textChanges.map(t => this.convertTextChangeToCodeEdit(t, fileName)) + }; + }); } convertCodeActions(entry: protocol.CodeAction, fileName: string): CodeAction { diff --git a/src/server/protocol.ts b/src/server/protocol.ts index 4e474edd0c4..f79774abf20 100644 --- a/src/server/protocol.ts +++ b/src/server/protocol.ts @@ -98,8 +98,11 @@ namespace ts.server.protocol { GetSupportedCodeFixes = "getSupportedCodeFixes", GetApplicableRefactors = "getApplicableRefactors", - GetRefactorCodeActions = "getRefactorCodeActions", - GetRefactorCodeActionsFull = "getRefactorCodeActions-full", + GetEditsForRefactor = "getEditsForRefactor", + /* @internal */ + GetEditsForRefactorFull = "getEditsForRefactor-full", + + // NOTE: If updating this, be sure to also update `allCommandNames` in `harness/unittests/session.ts`. } /** @@ -401,52 +404,98 @@ namespace ts.server.protocol { export type FileLocationOrRangeRequestArgs = FileLocationRequestArgs | FileRangeRequestArgs; + /** + * Request refactorings at a given position or selection area. + */ export interface GetApplicableRefactorsRequest extends Request { command: CommandTypes.GetApplicableRefactors; arguments: GetApplicableRefactorsRequestArgs; } - export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs; - export interface ApplicableRefactorInfo { - name: string; - description: string; - } - + /** + * Response is a list of available refactorings. + * Each refactoring exposes one or more "Actions"; a user selects one action to invoke a refactoring + */ export interface GetApplicableRefactorsResponse extends Response { body?: ApplicableRefactorInfo[]; } - export interface GetRefactorCodeActionsRequest extends Request { - command: CommandTypes.GetRefactorCodeActions; - arguments: GetRefactorCodeActionsRequestArgs; + /** + * A set of one or more available refactoring actions, grouped under a parent refactoring. + */ + export interface ApplicableRefactorInfo { + /** + * The programmatic name of the refactoring + */ + name: string; + /** + * A description of this refactoring category to show to the user. + * If the refactoring gets inlined (see below), this text will not be visible. + */ + description: string; + /** + * Inlineable refactorings can have their actions hoisted out to the top level + * of a context menu. Non-inlineanable refactorings should always be shown inside + * their parent grouping. + * + * If not specified, this value is assumed to be 'true' + */ + inlineable?: boolean; + + actions: RefactorActionInfo[]; } - export type GetRefactorCodeActionsRequestArgs = FileLocationOrRangeRequestArgs & { - /* The kind of the applicable refactor */ - refactorName: string; + /** + * Represents a single refactoring action - for example, the "Extract Method..." refactor might + * offer several actions, each corresponding to a surround class or closure to extract into. + */ + export type RefactorActionInfo = { + /** + * The programmatic name of the refactoring action + */ + name: string; + + /** + * A description of this refactoring action to show to the user. + * If the parent refactoring is inlined away, this will be the only text shown, + * so this description should make sense by itself if the parent is inlineable=true + */ + description: string; }; - export type RefactorCodeActions = { - actions: protocol.CodeAction[]; - renameLocation?: number - }; - - /* @internal */ - export type RefactorCodeActionsFull = { - actions: ts.CodeAction[]; - renameLocation?: number - }; - - export interface GetRefactorCodeActionsResponse extends Response { - body: RefactorCodeActions; + export interface GetEditsForRefactorRequest extends Request { + command: CommandTypes.GetEditsForRefactor; + arguments: GetEditsForRefactorRequestArgs; } - /* @internal */ - export interface GetRefactorCodeActionsFullResponse extends Response { - body: RefactorCodeActionsFull; + /** + * Request the edits that a particular refactoring action produces. + * Callers must specify the name of the refactor and the name of the action. + */ + export type GetEditsForRefactorRequestArgs = FileLocationOrRangeRequestArgs & { + /* The 'name' property from the refactoring that offered this action */ + refactor: string; + /* The 'name' property from the refactoring action */ + action: string; + }; + + + export interface GetEditsForRefactorResponse extends Response { + body?: RefactorEditInfo; } + export type RefactorEditInfo = { + edits: FileCodeEdits[]; + + /** + * An optional location where the editor should start a rename operation once + * the refactoring edits have been applied + */ + renameLocation?: Location; + renameFilename?: string; + }; + /** * Request for the available codefixes at a specific position. */ diff --git a/src/server/server.ts b/src/server/server.ts index 7e1ee683c8c..fa90e8df88d 100644 --- a/src/server/server.ts +++ b/src/server/server.ts @@ -526,7 +526,7 @@ namespace ts.server { watchedFile.callback(watchedFile.fileName); } else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) { - watchedFile.mtime = getModifiedTime(watchedFile.fileName); + watchedFile.mtime = stats.mtime; watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0); } }); diff --git a/src/server/session.ts b/src/server/session.ts index 6ec234952db..828bcdce1ac 100644 --- a/src/server/session.ts +++ b/src/server/session.ts @@ -1425,29 +1425,40 @@ namespace ts.server { return project.getLanguageService().getApplicableRefactors(file, position || textRange); } - private getRefactorCodeActions(args: protocol.GetRefactorCodeActionsRequestArgs, simplifiedResult: boolean): protocol.RefactorCodeActions | protocol.RefactorCodeActionsFull { + private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): ts.RefactorEditInfo | protocol.RefactorEditInfo { const { file, project } = this.getFileAndProjectWithoutRefreshingInferredProjects(args); const scriptInfo = project.getScriptInfoForNormalizedPath(file); const { position, textRange } = this.extractPositionAndRange(args, scriptInfo); - const result: ts.CodeAction[] = project.getLanguageService().getRefactorCodeActions( + const result = project.getLanguageService().getEditsForRefactor( file, this.projectService.getFormatCodeOptions(), position || textRange, - args.refactorName + args.refactor, + args.action ); - if (simplifiedResult) { - // Not full + if (result === undefined) { return { - actions: result.map(action => this.mapCodeAction(action, scriptInfo)) + edits: [] + }; + } + + if (simplifiedResult) { + const file = result.renameFilename; + let location: ILineInfo | undefined = undefined; + if (file !== undefined && result.renameLocation !== undefined) { + const renameScriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(file)); + location = renameScriptInfo.positionToLineOffset(result.renameLocation); + } + return { + renameLocation: location, + renameFilename: file, + edits: result.edits.map(change => this.mapTextChangesToCodeEdits(project, change)) }; } else { - // Full - return { - actions: result - }; + return result; } } @@ -1505,6 +1516,14 @@ namespace ts.server { }; } + private mapTextChangesToCodeEdits(project: Project, textChanges: FileTextChanges): protocol.FileCodeEdits { + const scriptInfo = project.getScriptInfoForNormalizedPath(toNormalizedPath(textChanges.fileName)); + return { + fileName: textChanges.fileName, + textChanges: textChanges.textChanges.map(textChange => this.convertTextChangeToCodeEdit(textChange, scriptInfo)) + }; + } + private convertTextChangeToCodeEdit(change: ts.TextChange, scriptInfo: ScriptInfo): protocol.CodeEdit { return { start: scriptInfo.positionToLineOffset(change.span.start), @@ -1544,18 +1563,22 @@ namespace ts.server { const normalizedFileName = toNormalizedPath(fileName); const project = this.projectService.getDefaultProjectForFile(normalizedFileName, /*refreshInferredProjects*/ true); for (const fileNameInProject of fileNamesInProject) { - if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName)) + if (this.getCanonicalFileName(fileNameInProject) === this.getCanonicalFileName(fileName)) { highPriorityFiles.push(fileNameInProject); + } else { const info = this.projectService.getScriptInfo(fileNameInProject); if (!info.isScriptOpen()) { - if (fileNameInProject.indexOf(".d.ts") > 0) + if (fileNameInProject.indexOf(".d.ts") > 0) { veryLowPriorityFiles.push(fileNameInProject); - else + } + else { lowPriorityFiles.push(fileNameInProject); + } } - else + else { mediumPriorityFiles.push(fileNameInProject); + } } } @@ -1833,11 +1856,11 @@ namespace ts.server { [CommandNames.GetApplicableRefactors]: (request: protocol.GetApplicableRefactorsRequest) => { return this.requiredResponse(this.getApplicableRefactors(request.arguments)); }, - [CommandNames.GetRefactorCodeActions]: (request: protocol.GetRefactorCodeActionsRequest) => { - return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ true)); + [CommandNames.GetEditsForRefactor]: (request: protocol.GetEditsForRefactorRequest) => { + return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ true)); }, - [CommandNames.GetRefactorCodeActionsFull]: (request: protocol.GetRefactorCodeActionsRequest) => { - return this.requiredResponse(this.getRefactorCodeActions(request.arguments, /*simplifiedResult*/ false)); + [CommandNames.GetEditsForRefactorFull]: (request: protocol.GetEditsForRefactorRequest) => { + return this.requiredResponse(this.getEditsForRefactor(request.arguments, /*simplifiedResult*/ false)); } }); diff --git a/src/services/classifier.ts b/src/services/classifier.ts index beeddda434e..ca8cf52a09b 100644 --- a/src/services/classifier.ts +++ b/src/services/classifier.ts @@ -814,7 +814,7 @@ namespace ts { * False will mean that node is not classified and traverse routine should recurse into node contents. */ function tryClassifyNode(node: Node): boolean { - if (isJSDocTag(node)) { + if (isJSDocNode(node)) { return true; } diff --git a/src/services/completions.ts b/src/services/completions.ts index 71fe4ce1c78..99560ffb4d8 100644 --- a/src/services/completions.ts +++ b/src/services/completions.ts @@ -18,7 +18,7 @@ namespace ts.Completions { return undefined; } - const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords } = completionData; + const { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, request, hasFilteredClassMemberKeywords } = completionData; if (sourceFile.languageVariant === LanguageVariant.JSX && location && location.parent && location.parent.kind === SyntaxKind.JsxClosingElement) { @@ -36,14 +36,15 @@ namespace ts.Completions { }]}; } - if (requestJsDocTagName) { - // If the current position is a jsDoc tag name, only tag names should be provided for completion - return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagNameCompletions() }; - } - - if (requestJsDocTag) { - // If the current position is a jsDoc tag, only tags should be provided for completion - return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries: JsDoc.getJSDocTagCompletions() }; + if (request) { + const entries = request.kind === "JsDocTagName" + // If the current position is a jsDoc tag name, only tag names should be provided for completion + ? JsDoc.getJSDocTagNameCompletions() + : request.kind === "JsDocTag" + // If the current position is a jsDoc tag, only tags should be provided for completion + ? JsDoc.getJSDocTagCompletions() + : JsDoc.getJSDocParameterNameCompletions(request.tag); + return { isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, entries }; } const entries: CompletionEntry[] = []; @@ -66,7 +67,7 @@ namespace ts.Completions { addRange(entries, classMemberKeywordCompletions); } // Add keywords if this is not a member completion list - else if (!isMemberCompletion && !requestJsDocTag && !requestJsDocTagName) { + else if (!isMemberCompletion) { addRange(entries, keywordCompletions); } @@ -347,16 +348,27 @@ namespace ts.Completions { return undefined; } - function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number) { + interface CompletionData { + symbols: Symbol[]; + isGlobalCompletion: boolean; + isMemberCompletion: boolean; + isNewIdentifierLocation: boolean; + location: Node; + isRightOfDot: boolean; + request?: Request; + hasFilteredClassMemberKeywords: boolean; + } + type Request = { kind: "JsDocTagName" } | { kind: "JsDocTag" } | { kind: "JsDocParameterName", tag: JSDocParameterTag }; + + function getCompletionData(typeChecker: TypeChecker, log: (message: string) => void, sourceFile: SourceFile, position: number): CompletionData { const isJavaScriptFile = isSourceFileJavaScript(sourceFile); - // JsDoc tag-name is just the name of the JSDoc tagname (exclude "@") - let requestJsDocTagName = false; - // JsDoc tag includes both "@" and tag-name - let requestJsDocTag = false; + let request: Request | undefined; let start = timestamp(); - const currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); // TODO: GH#15853 + const currentToken = getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); + // We will check for jsdoc comments with insideComment and getJsDocTagAtPosition. (TODO: that seems rather inefficient to check the same thing so many times.) + log("getCompletionData: Get current token: " + (timestamp() - start)); start = timestamp(); @@ -366,10 +378,10 @@ namespace ts.Completions { if (insideComment) { if (hasDocComment(sourceFile, position)) { - // The current position is next to the '@' sign, when no tag name being provided yet. - // Provide a full list of tag names if (sourceFile.text.charCodeAt(position - 1) === CharacterCodes.at) { - requestJsDocTagName = true; + // The current position is next to the '@' sign, when no tag name being provided yet. + // Provide a full list of tag names + request = { kind: "JsDocTagName" }; } else { // When completion is requested without "@", we will have check to make sure that @@ -389,7 +401,9 @@ namespace ts.Completions { // * |c| // */ const lineStart = getLineStartPositionForPosition(position, sourceFile); - requestJsDocTag = !(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/)); + if (!(sourceFile.text.substring(lineStart, position).match(/[^\*|\s|(/\*\*)]/))) { + request = { kind: "JsDocTag" }; + } } } @@ -397,10 +411,10 @@ namespace ts.Completions { // /** @type {number | string} */ // Completion should work in the brackets let insideJsDocTagExpression = false; - const tag = getJsDocTagAtPosition(sourceFile, position); + const tag = getJsDocTagAtPosition(currentToken, position); if (tag) { if (tag.tagName.pos <= position && position <= tag.tagName.end) { - requestJsDocTagName = true; + request = { kind: "JsDocTagName" }; } switch (tag.kind) { @@ -408,15 +422,18 @@ namespace ts.Completions { case SyntaxKind.JSDocParameterTag: case SyntaxKind.JSDocReturnTag: const tagWithExpression = tag; - if (tagWithExpression.typeExpression) { - insideJsDocTagExpression = tagWithExpression.typeExpression.pos < position && position < tagWithExpression.typeExpression.end; + if (tagWithExpression.typeExpression && tagWithExpression.typeExpression.pos < position && position < tagWithExpression.typeExpression.end) { + insideJsDocTagExpression = true; + } + else if (isJSDocParameterTag(tag) && (nodeIsMissing(tag.name) || tag.name.pos <= position && position <= tag.name.end)) { + request = { kind: "JsDocParameterName", tag }; } break; } } - if (requestJsDocTagName || requestJsDocTag) { - return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords: false }; + if (request) { + return { symbols: undefined, isGlobalCompletion: false, isMemberCompletion: false, isNewIdentifierLocation: false, location: undefined, isRightOfDot: false, request, hasFilteredClassMemberKeywords: false }; } if (!insideJsDocTagExpression) { @@ -553,7 +570,7 @@ namespace ts.Completions { log("getCompletionData: Semantic work: " + (timestamp() - semanticStart)); - return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), requestJsDocTagName, requestJsDocTag, hasFilteredClassMemberKeywords }; + return { symbols, isGlobalCompletion, isMemberCompletion, isNewIdentifierLocation, location, isRightOfDot: (isRightOfDot || isRightOfOpenTag), request, hasFilteredClassMemberKeywords }; function getTypeScriptMemberSymbols(): void { // Right of dot member completion list @@ -1518,4 +1535,34 @@ namespace ts.Completions { kind === SyntaxKind.EqualsEqualsEqualsToken || kind === SyntaxKind.ExclamationEqualsEqualsToken; } + + /** Get the corresponding JSDocTag node if the position is in a jsDoc comment */ + function getJsDocTagAtPosition(node: Node, position: number): JSDocTag | undefined { + const { jsDoc } = getJsDocHavingNode(node); + if (!jsDoc) return undefined; + + for (const { pos, end, tags } of jsDoc) { + if (!tags || position < pos || position > end) continue; + for (let i = tags.length - 1; i >= 0; i--) { + const tag = tags[i]; + if (position >= tag.pos) { + return tag; + } + } + } + } + + function getJsDocHavingNode(node: Node): Node { + if (!isToken(node)) return node; + + switch (node.kind) { + case SyntaxKind.VarKeyword: + case SyntaxKind.LetKeyword: + case SyntaxKind.ConstKeyword: + // if the current token is var, let or const, skip the VariableDeclarationList + return node.parent.parent; + default: + return node.parent; + } + } } diff --git a/src/services/findAllReferences.ts b/src/services/findAllReferences.ts index c1a7408fae7..67a967ec8b9 100644 --- a/src/services/findAllReferences.ts +++ b/src/services/findAllReferences.ts @@ -496,11 +496,10 @@ namespace ts.FindAllReferences.Core { const { text = stripQuotes(getDeclaredName(this.checker, symbol, location)), allSearchSymbols = undefined } = searchOptions; const escapedText = escapeIdentifier(text); const parents = this.options.implementations && getParentSymbolsOfPropertyAccess(location, symbol, this.checker); - return { location, symbol, comingFrom, text, escapedText, parents, includes }; - - function includes(referenceSymbol: Symbol): boolean { - return allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol; - } + return { + location, symbol, comingFrom, text, escapedText, parents, + includes: referenceSymbol => allSearchSymbols ? contains(allSearchSymbols, referenceSymbol) : referenceSymbol === symbol, + }; } private readonly symbolIdToReferences: Entry[][] = []; diff --git a/src/services/importTracker.ts b/src/services/importTracker.ts index 585af7ebd31..5e8e7b8b3a7 100644 --- a/src/services/importTracker.ts +++ b/src/services/importTracker.ts @@ -73,54 +73,56 @@ namespace ts.FindAllReferences { function handleDirectImports(exportingModuleSymbol: Symbol): void { const theseDirectImports = getDirectImports(exportingModuleSymbol); - if (theseDirectImports) for (const direct of theseDirectImports) { - if (!markSeenDirectImport(direct)) { - continue; - } + if (theseDirectImports) { + for (const direct of theseDirectImports) { + if (!markSeenDirectImport(direct)) { + continue; + } - cancellationToken.throwIfCancellationRequested(); + cancellationToken.throwIfCancellationRequested(); - switch (direct.kind) { - case SyntaxKind.CallExpression: - if (!isAvailableThroughGlobal) { - const parent = direct.parent!; - if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) { - const { name } = parent as ts.VariableDeclaration; - if (name.kind === SyntaxKind.Identifier) { - directImports.push(name); - break; + switch (direct.kind) { + case SyntaxKind.CallExpression: + if (!isAvailableThroughGlobal) { + const parent = direct.parent!; + if (exportKind === ExportKind.ExportEquals && parent.kind === SyntaxKind.VariableDeclaration) { + const { name } = parent as ts.VariableDeclaration; + if (name.kind === SyntaxKind.Identifier) { + directImports.push(name); + break; + } } + + // Don't support re-exporting 'require()' calls, so just add a single indirect user. + addIndirectUser(direct.getSourceFile()); } + break; - // Don't support re-exporting 'require()' calls, so just add a single indirect user. - addIndirectUser(direct.getSourceFile()); - } - break; + case SyntaxKind.ImportEqualsDeclaration: + handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export)); + break; - case SyntaxKind.ImportEqualsDeclaration: - handleNamespaceImport(direct, direct.name, hasModifier(direct, ModifierFlags.Export)); - break; + case SyntaxKind.ImportDeclaration: + const namedBindings = direct.importClause && direct.importClause.namedBindings; + if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { + handleNamespaceImport(direct, namedBindings.name); + } + else { + directImports.push(direct); + } + break; - case SyntaxKind.ImportDeclaration: - const namedBindings = direct.importClause && direct.importClause.namedBindings; - if (namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport) { - handleNamespaceImport(direct, namedBindings.name); - } - else { - directImports.push(direct); - } - break; - - case SyntaxKind.ExportDeclaration: - if (!direct.exportClause) { - // This is `export * from "foo"`, so imports of this module may import the export too. - handleDirectImports(getContainingModuleSymbol(direct, checker)); - } - else { - // This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports. - directImports.push(direct); - } - break; + case SyntaxKind.ExportDeclaration: + if (!direct.exportClause) { + // This is `export * from "foo"`, so imports of this module may import the export too. + handleDirectImports(getContainingModuleSymbol(direct, checker)); + } + else { + // This is `export { foo } from "foo"` and creates an alias symbol, so recursive search will get handle re-exports. + directImports.push(direct); + } + break; + } } } } @@ -160,8 +162,10 @@ namespace ts.FindAllReferences { const moduleSymbol = checker.getMergedSymbol(sourceFileLike.symbol); Debug.assert(!!(moduleSymbol.flags & SymbolFlags.Module)); const directImports = getDirectImports(moduleSymbol); - if (directImports) for (const directImport of directImports) { - addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport)); + if (directImports) { + for (const directImport of directImports) { + addIndirectUsers(getSourceFileLikeForImportDeclaration(directImport)); + } } } @@ -183,8 +187,10 @@ namespace ts.FindAllReferences { importSearches.push([location, symbol]); } - if (directImports) for (const decl of directImports) { - handleImport(decl); + if (directImports) { + for (const decl of directImports) { + handleImport(decl); + } } return { importSearches, singleReferences }; @@ -258,25 +264,27 @@ namespace ts.FindAllReferences { } function searchForNamedImport(namedBindings: NamedImportsOrExports | undefined): void { - if (namedBindings) for (const element of namedBindings.elements) { - const { name, propertyName } = element; - if ((propertyName || name).text !== exportName) { - continue; - } - - if (propertyName) { - // This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference. - singleReferences.push(propertyName); - if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`. - // Search locally for `bar`. - addSearch(name, checker.getSymbolAtLocation(name)); + if (namedBindings) { + for (const element of namedBindings.elements) { + const { name, propertyName } = element; + if ((propertyName || name).text !== exportName) { + continue; + } + + if (propertyName) { + // This is `import { foo as bar } from "./a"` or `export { foo as bar } from "./a"`. `foo` isn't a local in the file, so just add it as a single reference. + singleReferences.push(propertyName); + if (!isForRename) { // If renaming `foo`, don't touch `bar`, just `foo`. + // Search locally for `bar`. + addSearch(name, checker.getSymbolAtLocation(name)); + } + } + else { + const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName + ? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol. + : checker.getSymbolAtLocation(name); + addSearch(name, localSymbol); } - } - else { - const localSymbol = element.kind === SyntaxKind.ExportSpecifier && element.propertyName - ? checker.getExportSpecifierLocalTargetSymbol(element) // For re-exporting under a different name, we want to get the re-exported symbol. - : checker.getSymbolAtLocation(name); - addSearch(name, localSymbol); } } } @@ -436,8 +444,8 @@ namespace ts.FindAllReferences { if (parent.kind === SyntaxKind.PropertyAccessExpression) { // When accessing an export of a JS module, there's no alias. The symbol will still be flagged as an export even though we're at the use. // So check that we are at the declaration. - return symbol.declarations.some(d => d === parent) && parent.parent.kind === ts.SyntaxKind.BinaryExpression - ? getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ false) + return symbol.declarations.some(d => d === parent) && isBinaryExpression(parent.parent) + ? getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ false) : undefined; } else { @@ -449,31 +457,41 @@ namespace ts.FindAllReferences { else { const exportNode = getExportNode(parent); if (exportNode && hasModifier(exportNode, ModifierFlags.Export)) { - if (exportNode.kind === SyntaxKind.ImportEqualsDeclaration && (exportNode as ImportEqualsDeclaration).moduleReference === node) { + if (isImportEqualsDeclaration(exportNode) && exportNode.moduleReference === node) { // We're at `Y` in `export import X = Y`. This is not the exported symbol, the left-hand-side is. So treat this as an import statement. if (comingFromExport) { return undefined; } - const lhsSymbol = checker.getSymbolAtLocation((exportNode as ImportEqualsDeclaration).name); + const lhsSymbol = checker.getSymbolAtLocation(exportNode.name); return { kind: ImportExport.Import, symbol: lhsSymbol, isNamedImport: false }; } else { return exportInfo(symbol, getExportKindForDeclaration(exportNode)); } } - else if (parent.kind === SyntaxKind.ExportAssignment) { - // Get the symbol for the `export =` node; its parent is the module it's the export of. - const exportingModuleSymbol = parent.symbol.parent; - Debug.assert(!!exportingModuleSymbol); - return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } }; + // If we are in `export = a;`, `parent` is the export assignment. + else if (isExportAssignment(parent)) { + return getExportAssignmentExport(parent); } - else if (parent.kind === ts.SyntaxKind.BinaryExpression) { - return getSpecialPropertyExport(parent as ts.BinaryExpression, /*useLhsSymbol*/ true); + // If we are in `export = class A {};` at `A`, `parent.parent` is the export assignment. + else if (isExportAssignment(parent.parent)) { + return getExportAssignmentExport(parent.parent); } - else if (parent.parent.kind === SyntaxKind.BinaryExpression) { - return getSpecialPropertyExport(parent.parent as ts.BinaryExpression, /*useLhsSymbol*/ true); + // Similar for `module.exports =` and `exports.A =`. + else if (isBinaryExpression(parent)) { + return getSpecialPropertyExport(parent, /*useLhsSymbol*/ true); } + else if (isBinaryExpression(parent.parent)) { + return getSpecialPropertyExport(parent.parent, /*useLhsSymbol*/ true); + } + } + + function getExportAssignmentExport(ex: ExportAssignment): ExportedSymbol { + // Get the symbol for the `export =` node; its parent is the module it's the export of. + const exportingModuleSymbol = ex.symbol.parent; + Debug.assert(!!exportingModuleSymbol); + return { kind: ImportExport.Export, symbol, exportInfo: { exportingModuleSymbol, exportKind: ExportKind.ExportEquals } }; } function getSpecialPropertyExport(node: ts.BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined { @@ -496,21 +514,21 @@ namespace ts.FindAllReferences { function getImport(): ImportedSymbol | undefined { const isImport = isNodeImport(node); - if (!isImport) return; + if (!isImport) return undefined; // A symbol being imported is always an alias. So get what that aliases to find the local symbol. let importedSymbol = checker.getImmediateAliasedSymbol(symbol); - if (importedSymbol) { - // Search on the local symbol in the exporting module, not the exported symbol. - importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker); - // Similarly, skip past the symbol for 'export =' - if (importedSymbol.name === "export=") { - importedSymbol = checker.getImmediateAliasedSymbol(importedSymbol); - } + if (!importedSymbol) return undefined; - if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching. - return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport }; - } + // Search on the local symbol in the exporting module, not the exported symbol. + importedSymbol = skipExportSpecifierSymbol(importedSymbol, checker); + // Similarly, skip past the symbol for 'export =' + if (importedSymbol.name === "export=") { + importedSymbol = getExportEqualsLocalSymbol(importedSymbol, checker); + } + + if (symbolName(importedSymbol) === symbol.name) { // If this is a rename import, do not continue searching. + return { kind: ImportExport.Import, symbol: importedSymbol, ...isImport }; } } @@ -525,6 +543,22 @@ namespace ts.FindAllReferences { } } + function getExportEqualsLocalSymbol(importedSymbol: Symbol, checker: TypeChecker): Symbol { + if (importedSymbol.flags & SymbolFlags.Alias) { + return checker.getImmediateAliasedSymbol(importedSymbol); + } + + const decl = importedSymbol.valueDeclaration; + if (isExportAssignment(decl)) { // `export = class {}` + return decl.expression.symbol; + } + else if (isBinaryExpression(decl)) { // `module.exports = class {}` + return decl.right.symbol; + } + Debug.fail(); + } + + // If a reference is a class expression, the exported node would be its parent. // If a reference is a variable declaration, the exported node would be the variable statement. function getExportNode(parent: Node): Node | undefined { if (parent.kind === SyntaxKind.VariableDeclaration) { @@ -578,12 +612,13 @@ namespace ts.FindAllReferences { /** If at an export specifier, go to the symbol it refers to. */ function skipExportSpecifierSymbol(symbol: Symbol, checker: TypeChecker): Symbol { // For `export { foo } from './bar", there's nothing to skip, because it does not create a new alias. But `export { foo } does. - if (symbol.declarations) for (const declaration of symbol.declarations) { - if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) { - return checker.getExportSpecifierLocalTargetSymbol(declaration); + if (symbol.declarations) { + for (const declaration of symbol.declarations) { + if (isExportSpecifier(declaration) && !(declaration as ExportSpecifier).propertyName && !(declaration as ExportSpecifier).parent.parent.moduleSpecifier) { + return checker.getExportSpecifierLocalTargetSymbol(declaration); + } } } - return symbol; } diff --git a/src/services/jsDoc.ts b/src/services/jsDoc.ts index 8ca55029603..5d03ad03b0c 100644 --- a/src/services/jsDoc.ts +++ b/src/services/jsDoc.ts @@ -132,6 +132,25 @@ namespace ts.JsDoc { })); } + export function getJSDocParameterNameCompletions(tag: JSDocParameterTag): CompletionEntry[] { + const nameThusFar = tag.name.text; + const jsdoc = tag.parent; + const fn = jsdoc.parent; + if (!ts.isFunctionLike(fn)) return []; + + return mapDefined(fn.parameters, param => { + if (!isIdentifier(param.name)) return undefined; + + const name = param.name.text; + if (jsdoc.tags.some(t => t !== tag && isJSDocParameterTag(t) && t.name.text === name) + || nameThusFar !== undefined && !startsWith(name, nameThusFar)) { + return undefined; + } + + return { name, kind: ScriptElementKind.parameterElement, kindModifiers: "", sortText: "0" }; + }); + } + /** * Checks if position points to a valid position to add JSDoc comments, and if so, * returns the appropriate template. Otherwise returns an empty string. diff --git a/src/services/jsTyping.ts b/src/services/jsTyping.ts index f601c9604de..5e31d6a0190 100644 --- a/src/services/jsTyping.ts +++ b/src/services/jsTyping.ts @@ -143,7 +143,7 @@ namespace ts.JsTyping { /** * Merge a given list of typingNames to the inferredTypings map */ - function mergeTypings(typingNames: string[]) { + function mergeTypings(typingNames: ReadonlyArray) { if (!typingNames) { return; } @@ -192,7 +192,7 @@ namespace ts.JsTyping { const cleanedTypingNames = map(inferredTypingNames, f => f.replace(/((?:\.|-)min(?=\.|$))|((?:-|\.)\d+)/g, "")); if (safeList !== EmptySafeList) { - mergeTypings(filter(cleanedTypingNames, f => safeList.has(f))); + mergeTypings(ts.mapDefined(cleanedTypingNames, f => safeList.get(f))); } const hasJsxFile = forEach(fileNames, f => ensureScriptKind(f, getScriptKindFromFileName(f)) === ScriptKind.JSX); diff --git a/src/services/refactorProvider.ts b/src/services/refactorProvider.ts index 1058f9c2ca6..3c02ddf671c 100644 --- a/src/services/refactorProvider.ts +++ b/src/services/refactorProvider.ts @@ -8,10 +8,10 @@ namespace ts { description: string; /** Compute the associated code actions */ - getCodeActions(context: RefactorContext): CodeAction[]; + getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined; - /** A fast syntactic check to see if the refactor is applicable at given position. */ - isApplicable(context: RefactorContext): boolean; + /** Compute (quickly) which actions are available here */ + getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined; } export interface RefactorContext { @@ -34,7 +34,6 @@ namespace ts { } export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] | undefined { - let results: ApplicableRefactorInfo[]; const refactorList: Refactor[] = []; refactors.forEach(refactor => { @@ -44,16 +43,17 @@ namespace ts { if (context.cancellationToken && context.cancellationToken.isCancellationRequested()) { return results; } - if (refactor.isApplicable(context)) { - (results || (results = [])).push({ name: refactor.name, description: refactor.description }); + const infos = refactor.getAvailableActions(context); + if (infos && infos.length) { + (results || (results = [])).push(...infos); } } return results; } - export function getRefactorCodeActions(context: RefactorContext, refactorName: string): CodeAction[] | undefined { + export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined { const refactor = refactors.get(refactorName); - return refactor && refactor.getCodeActions(context); + return refactor && refactor.getEditsForAction(context, actionName); } } } diff --git a/src/services/refactors/convertFunctionToEs6Class.ts b/src/services/refactors/convertFunctionToEs6Class.ts index a34e0ccca2f..d275924b76a 100644 --- a/src/services/refactors/convertFunctionToEs6Class.ts +++ b/src/services/refactors/convertFunctionToEs6Class.ts @@ -1,16 +1,18 @@ /* @internal */ namespace ts.refactor { + const actionName = "convert"; + const convertFunctionToES6Class: Refactor = { name: "Convert to ES2015 class", description: Diagnostics.Convert_function_to_an_ES2015_class.message, - getCodeActions, - isApplicable + getEditsForAction, + getAvailableActions }; registerRefactor(convertFunctionToES6Class); - function isApplicable(context: RefactorContext): boolean { + function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] { const start = context.startPosition; const node = getTokenAtPosition(context.file, start, /*includeJsDocComment*/ false); const checker = context.program.getTypeChecker(); @@ -20,10 +22,28 @@ namespace ts.refactor { symbol = (symbol.valueDeclaration as VariableDeclaration).initializer.symbol; } - return symbol && symbol.flags & SymbolFlags.Function && symbol.members && symbol.members.size > 0; + if (symbol && (symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) { + return [ + { + name: convertFunctionToES6Class.name, + description: convertFunctionToES6Class.description, + actions: [ + { + description: convertFunctionToES6Class.description, + name: actionName + } + ] + } + ]; + } } - function getCodeActions(context: RefactorContext): CodeAction[] | undefined { + function getEditsForAction(context: RefactorContext, action: string): RefactorEditInfo | undefined { + // Somehow wrong action got invoked? + if (actionName !== action) { + return undefined; + } + const start = context.startPosition; const sourceFile = context.file; const checker = context.program.getTypeChecker(); @@ -35,7 +55,7 @@ namespace ts.refactor { const deletes: (() => any)[] = []; if (!(ctorSymbol.flags & (SymbolFlags.Function | SymbolFlags.Variable))) { - return []; + return undefined; } const ctorDeclaration = ctorSymbol.valueDeclaration; @@ -63,7 +83,7 @@ namespace ts.refactor { } if (!newClassDeclaration) { - return []; + return undefined; } // Because the preceding node could be touched, we need to insert nodes before delete nodes. @@ -72,10 +92,9 @@ namespace ts.refactor { deleteCallback(); } - return [{ - description: formatStringFromArgs(Diagnostics.Convert_function_0_to_class.message, [ctorSymbol.name]), - changes: changeTracker.getChanges() - }]; + return { + edits: changeTracker.getChanges() + }; function deleteNode(node: Node, inList = false) { if (deletedNodes.some(n => isNodeDescendantOf(node, n))) { diff --git a/src/services/services.ts b/src/services/services.ts index 21c756a9acc..22fa67dd1c5 100644 --- a/src/services/services.ts +++ b/src/services/services.ts @@ -136,7 +136,7 @@ namespace ts { } private createChildren(sourceFile?: SourceFileLike) { - if (isJSDocTag(this)) { + if (this.kind === SyntaxKind.JSDocComment || isJSDocTag(this)) { /** Don't add trivia for "tokens" since this is in a comment. */ const children: Node[] = []; this.forEachChild(child => { children.push(child); }); @@ -146,9 +146,9 @@ namespace ts { const children: Node[] = []; scanner.setText((sourceFile || this.getSourceFile()).text); let pos = this.pos; - const useJSDocScanner = this.kind >= SyntaxKind.FirstJSDocTagNode && this.kind <= SyntaxKind.LastJSDocTagNode; + const useJSDocScanner = isJSDocNode(this); const processNode = (node: Node) => { - const isJSDocTagNode = isJSDocTag(node); + const isJSDocTagNode = isJSDocNode(node); if (!isJSDocTagNode && pos < node.pos) { pos = this.addSyntheticNodes(children, pos, node.pos, useJSDocScanner); } @@ -684,8 +684,9 @@ namespace ts { forEachChild(decl.name, visit); break; } - if (decl.initializer) + if (decl.initializer) { visit(decl.initializer); + } } // falls through case SyntaxKind.EnumMember: @@ -732,6 +733,15 @@ namespace ts { } } + class SourceMapSourceObject implements SourceMapSource { + lineMap: number[]; + constructor (public fileName: string, public text: string, public skipTrivia?: (pos: number) => number) {} + + public getLineAndCharacterOfPosition(pos: number): LineAndCharacter { + return ts.getLineAndCharacterOfPosition(this, pos); + } + } + function getServicesObjectAllocator(): ObjectAllocator { return { getNodeConstructor: () => NodeObject, @@ -742,6 +752,7 @@ namespace ts { getSymbolConstructor: () => SymbolObject, getTypeConstructor: () => TypeObject, getSignatureConstructor: () => SignatureObject, + getSourceMapSourceConstructor: () => SourceMapSourceObject, }; } @@ -1989,15 +2000,16 @@ namespace ts { return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange)); } - function getRefactorCodeActions( + function getEditsForRefactor( fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, - refactorName: string): CodeAction[] | undefined { + refactorName: string, + actionName: string): RefactorEditInfo { synchronizeHostData(); const file = getValidSourceFile(fileName); - return refactor.getRefactorCodeActions(getRefactorContext(file, positionOrRange, formatOptions), refactorName); + return refactor.getEditsForRefactor(getRefactorContext(file, positionOrRange, formatOptions), refactorName, actionName); } return { @@ -2005,8 +2017,6 @@ namespace ts { cleanupSemanticCache, getSyntacticDiagnostics, getSemanticDiagnostics, - getApplicableRefactors, - getRefactorCodeActions, getCompilerOptionsDiagnostics, getSyntacticClassifications, getSemanticClassifications, @@ -2044,7 +2054,9 @@ namespace ts { getEmitOutput, getNonBoundSourceFile, getSourceFile, - getProgram + getProgram, + getApplicableRefactors, + getEditsForRefactor, }; } diff --git a/src/services/symbolDisplay.ts b/src/services/symbolDisplay.ts index 910c31c36b3..345f0718fe3 100644 --- a/src/services/symbolDisplay.ts +++ b/src/services/symbolDisplay.ts @@ -4,8 +4,10 @@ namespace ts.SymbolDisplay { export function getSymbolKind(typeChecker: TypeChecker, symbol: Symbol, location: Node): ScriptElementKind { const { flags } = symbol; - if (flags & SymbolFlags.Class) return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? + if (flags & SymbolFlags.Class) { + return getDeclarationOfKind(symbol, SyntaxKind.ClassExpression) ? ScriptElementKind.localClassElement : ScriptElementKind.classElement; + } if (flags & SymbolFlags.Enum) return ScriptElementKind.enumElement; if (flags & SymbolFlags.TypeAlias) return ScriptElementKind.typeElement; if (flags & SymbolFlags.Interface) return ScriptElementKind.interfaceElement; diff --git a/src/services/types.ts b/src/services/types.ts index e042276e650..2d47da2fd1d 100644 --- a/src/services/types.ts +++ b/src/services/types.ts @@ -71,6 +71,10 @@ namespace ts { getLineAndCharacterOfPosition(pos: number): LineAndCharacter; } + export interface SourceMapSource { + getLineAndCharacterOfPosition(pos: number): LineAndCharacter; + } + /** * Represents an immutable snapshot of a script at a specified time.Once acquired, the * snapshot is observably immutable. i.e. the same calls with the same parameters will return @@ -261,8 +265,9 @@ namespace ts { isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean; getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: number[], formatOptions: FormatCodeSettings): CodeAction[]; + getApplicableRefactors(fileName: string, positionOrRaneg: number | TextRange): ApplicableRefactorInfo[]; - getRefactorCodeActions(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string): CodeAction[] | undefined; + getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string): RefactorEditInfo | undefined; getEmitOutput(fileName: string, emitOnlyDtsFiles?: boolean): EmitOutput; @@ -353,11 +358,60 @@ namespace ts { changes: FileTextChanges[]; } + /** + * A set of one or more available refactoring actions, grouped under a parent refactoring. + */ export interface ApplicableRefactorInfo { + /** + * The programmatic name of the refactoring + */ name: string; + /** + * A description of this refactoring category to show to the user. + * If the refactoring gets inlined (see below), this text will not be visible. + */ description: string; + /** + * Inlineable refactorings can have their actions hoisted out to the top level + * of a context menu. Non-inlineanable refactorings should always be shown inside + * their parent grouping. + * + * If not specified, this value is assumed to be 'true' + */ + inlineable?: boolean; + + actions: RefactorActionInfo[]; } + /** + * Represents a single refactoring action - for example, the "Extract Method..." refactor might + * offer several actions, each corresponding to a surround class or closure to extract into. + */ + export type RefactorActionInfo = { + /** + * The programmatic name of the refactoring action + */ + name: string; + + /** + * A description of this refactoring action to show to the user. + * If the parent refactoring is inlined away, this will be the only text shown, + * so this description should make sense by itself if the parent is inlineable=true + */ + description: string; + }; + + /** + * A set of edits to make in response to a refactor action, plus an optional + * location where renaming should be invoked from + */ + export type RefactorEditInfo = { + edits: FileTextChanges[]; + renameFilename?: string; + renameLocation?: number; + }; + + export interface TextInsertion { newText: string; /** The position in newText the caret should point to after the insertion. */ diff --git a/src/services/utilities.ts b/src/services/utilities.ts index 7a87c0939c7..ab958099c11 100644 --- a/src/services/utilities.ts +++ b/src/services/utilities.ts @@ -615,18 +615,21 @@ namespace ts { return getTouchingToken(sourceFile, position, includeJsDocComment, n => isPropertyName(n.kind)); } - /** Returns the token if position is in [start, end) or if position === end and includeItemAtEndPosition(token) === true */ - export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeItemAtEndPosition?: (n: Node) => boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includeItemAtEndPosition, includeJsDocComment); + /** + * Returns the token if position is in [start, end). + * If position === end, returns the preceding token if includeItemAtEndPosition(previousToken) === true + */ + export function getTouchingToken(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includePrecedingTokenAtEndPosition?: (n: Node) => boolean): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ false, includePrecedingTokenAtEndPosition, /*includeEndPosition*/ false, includeJsDocComment); } /** Returns a token if position is in [start-of-leading-trivia, end) */ - export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean): Node { - return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includeItemAtEndPosition*/ undefined, includeJsDocComment); + export function getTokenAtPosition(sourceFile: SourceFile, position: number, includeJsDocComment: boolean, includeEndPosition?: boolean): Node { + return getTokenAtPositionWorker(sourceFile, position, /*allowPositionInLeadingTrivia*/ true, /*includePrecedingTokenAtEndPosition*/ undefined, includeEndPosition, includeJsDocComment); } /** Get the token whose text contains the position */ - function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includeItemAtEndPosition: (n: Node) => boolean, includeJsDocComment: boolean): Node { + function getTokenAtPositionWorker(sourceFile: SourceFile, position: number, allowPositionInLeadingTrivia: boolean, includePrecedingTokenAtEndPosition: (n: Node) => boolean, includeEndPosition: boolean, includeJsDocComment: boolean): Node { let current: Node = sourceFile; outer: while (true) { if (isToken(current)) { @@ -636,7 +639,7 @@ namespace ts { // find the child that contains 'position' for (const child of current.getChildren()) { - if (isJSDocNode(child) && !includeJsDocComment) { + if (!includeJsDocComment && isJSDocNode(child)) { continue; } @@ -646,13 +649,13 @@ namespace ts { } const end = child.getEnd(); - if (position < end || (position === end && child.kind === SyntaxKind.EndOfFileToken)) { + if (position < end || (position === end && (child.kind === SyntaxKind.EndOfFileToken || includeEndPosition))) { current = child; continue outer; } - else if (includeItemAtEndPosition && end === position) { + else if (includePrecedingTokenAtEndPosition && end === position) { const previousToken = findPrecedingToken(position, sourceFile, child); - if (previousToken && includeItemAtEndPosition(previousToken)) { + if (previousToken && includePrecedingTokenAtEndPosition(previousToken)) { return previousToken; } } @@ -901,42 +904,6 @@ namespace ts { } } - /** - * Get the corresponding JSDocTag node if the position is in a jsDoc comment - */ - export function getJsDocTagAtPosition(sourceFile: SourceFile, position: number): JSDocTag { - let node = ts.getTokenAtPosition(sourceFile, position, /*includeJsDocComment*/ false); - if (isToken(node)) { - switch (node.kind) { - case SyntaxKind.VarKeyword: - case SyntaxKind.LetKeyword: - case SyntaxKind.ConstKeyword: - // if the current token is var, let or const, skip the VariableDeclarationList - node = node.parent === undefined ? undefined : node.parent.parent; - break; - default: - node = node.parent; - break; - } - } - - if (node) { - if (node.jsDoc) { - for (const jsDoc of node.jsDoc) { - if (jsDoc.tags) { - for (const tag of jsDoc.tags) { - if (tag.pos <= position && position <= tag.end) { - return tag; - } - } - } - } - } - } - - return undefined; - } - function nodeHasTokens(n: Node): boolean { // If we have a token or node that has a non-zero width, it must have tokens. // Note, that getWidth() does not take trivia into account. diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argSynonymForParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argSynonymForParamTag.json index 92b9cb450e6..b47a07e8487 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argSynonymForParamTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argSynonymForParamTag.json @@ -40,6 +40,7 @@ "end": 27, "text": "name1" }, + "isBracketed": false, "comment": "Description" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argumentSynonymForParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argumentSynonymForParamTag.json index f398fb3af41..cf86fda872e 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argumentSynonymForParamTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.argumentSynonymForParamTag.json @@ -40,6 +40,7 @@ "end": 32, "text": "name1" }, + "isBracketed": false, "comment": "Description" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json index e70fc95367f..506487232e0 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.oneParamTag.json @@ -40,6 +40,7 @@ "end": 29, "text": "name1" }, + "isBracketed": false, "comment": "" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json index 0dbdd83d2ba..abc116d7452 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTag1.json @@ -40,6 +40,7 @@ "end": 29, "text": "name1" }, + "isBracketed": false, "comment": "Description text follows" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json index 204d94779b3..9d66ca3dd55 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType1.json @@ -40,6 +40,7 @@ "end": 20, "text": "name1" }, + "isBracketed": false, "comment": "" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json index 7c79459768b..01d08a103c1 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramTagNameThenType2.json @@ -40,6 +40,7 @@ "end": 20, "text": "name1" }, + "isBracketed": false, "comment": "Description" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json index 2ff182483d9..ab15d24f618 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.paramWithoutType.json @@ -30,6 +30,7 @@ "end": 18, "text": "foo" }, + "isBracketed": false, "comment": "" }, "length": 1, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json index b51ab3598e6..5ba60030f1b 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTag2.json @@ -40,6 +40,7 @@ "end": 29, "text": "name1" }, + "isBracketed": false, "comment": "" }, "1": { @@ -79,6 +80,7 @@ "end": 55, "text": "name2" }, + "isBracketed": false, "comment": "" }, "length": 2, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json index 3c20d5edcbc..7d26097bb34 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.twoParamTagOnSameLine.json @@ -40,6 +40,7 @@ "end": 29, "text": "name1" }, + "isBracketed": false, "comment": "" }, "1": { @@ -79,6 +80,7 @@ "end": 51, "text": "name2" }, + "isBracketed": false, "comment": "" }, "length": 2, diff --git a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json index 7a8f9c4bcc9..13826b63d9c 100644 --- a/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json +++ b/tests/baselines/reference/JSDocParsing/DocComments.parsesCorrectly.typedefTagWithChildrenTags.json @@ -103,7 +103,8 @@ "pos": 66, "end": 69, "text": "age" - } + }, + "isBracketed": false }, { "kind": "JSDocPropertyTag", @@ -141,7 +142,8 @@ "pos": 93, "end": 97, "text": "name" - } + }, + "isBracketed": false } ] }, diff --git a/tests/baselines/reference/argumentsObjectCreatesRestForJs.symbols b/tests/baselines/reference/argumentsObjectCreatesRestForJs.symbols new file mode 100644 index 00000000000..6a95dbc86d8 --- /dev/null +++ b/tests/baselines/reference/argumentsObjectCreatesRestForJs.symbols @@ -0,0 +1,44 @@ +=== tests/cases/compiler/main.js === +function allRest() { arguments; } +>allRest : Symbol(allRest, Decl(main.js, 0, 0)) +>arguments : Symbol(arguments) + +allRest(); +>allRest : Symbol(allRest, Decl(main.js, 0, 0)) + +allRest(1, 2, 3); +>allRest : Symbol(allRest, Decl(main.js, 0, 0)) + +function someRest(x, y) { arguments; } +>someRest : Symbol(someRest, Decl(main.js, 2, 17)) +>x : Symbol(x, Decl(main.js, 3, 18)) +>y : Symbol(y, Decl(main.js, 3, 20)) +>arguments : Symbol(arguments) + +someRest(); // x and y are still optional because they are in a JS file +>someRest : Symbol(someRest, Decl(main.js, 2, 17)) + +someRest(1, 2, 3); +>someRest : Symbol(someRest, Decl(main.js, 2, 17)) + +/** + * @param {number} x - a thing + */ +function jsdocced(x) { arguments; } +>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18)) +>x : Symbol(x, Decl(main.js, 10, 18)) +>arguments : Symbol(arguments) + +jsdocced(1); +>jsdocced : Symbol(jsdocced, Decl(main.js, 5, 18)) + +function dontDoubleRest(x, ...y) { arguments; } +>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12)) +>x : Symbol(x, Decl(main.js, 13, 24)) +>y : Symbol(y, Decl(main.js, 13, 26)) +>arguments : Symbol(arguments) + +dontDoubleRest(1, 2, 3); +>dontDoubleRest : Symbol(dontDoubleRest, Decl(main.js, 11, 12)) + + diff --git a/tests/baselines/reference/argumentsObjectCreatesRestForJs.types b/tests/baselines/reference/argumentsObjectCreatesRestForJs.types new file mode 100644 index 00000000000..10596fb10c7 --- /dev/null +++ b/tests/baselines/reference/argumentsObjectCreatesRestForJs.types @@ -0,0 +1,60 @@ +=== tests/cases/compiler/main.js === +function allRest() { arguments; } +>allRest : (...args: any[]) => void +>arguments : IArguments + +allRest(); +>allRest() : void +>allRest : (...args: any[]) => void + +allRest(1, 2, 3); +>allRest(1, 2, 3) : void +>allRest : (...args: any[]) => void +>1 : 1 +>2 : 2 +>3 : 3 + +function someRest(x, y) { arguments; } +>someRest : (x: any, y: any, ...args: any[]) => void +>x : any +>y : any +>arguments : IArguments + +someRest(); // x and y are still optional because they are in a JS file +>someRest() : void +>someRest : (x: any, y: any, ...args: any[]) => void + +someRest(1, 2, 3); +>someRest(1, 2, 3) : void +>someRest : (x: any, y: any, ...args: any[]) => void +>1 : 1 +>2 : 2 +>3 : 3 + +/** + * @param {number} x - a thing + */ +function jsdocced(x) { arguments; } +>jsdocced : (x: number) => void +>x : number +>arguments : IArguments + +jsdocced(1); +>jsdocced(1) : void +>jsdocced : (x: number) => void +>1 : 1 + +function dontDoubleRest(x, ...y) { arguments; } +>dontDoubleRest : (x: any, ...y: any[]) => void +>x : any +>y : any[] +>arguments : IArguments + +dontDoubleRest(1, 2, 3); +>dontDoubleRest(1, 2, 3) : void +>dontDoubleRest : (x: any, ...y: any[]) => void +>1 : 1 +>2 : 2 +>3 : 3 + + diff --git a/tests/baselines/reference/constructorFunctions.symbols b/tests/baselines/reference/constructorFunctions.symbols new file mode 100644 index 00000000000..f55075794ab --- /dev/null +++ b/tests/baselines/reference/constructorFunctions.symbols @@ -0,0 +1,76 @@ +=== tests/cases/conformance/salsa/index.js === +function C1() { +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + + if (!(this instanceof C1)) return new C1(); +>C1 : Symbol(C1, Decl(index.js, 0, 0)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + + this.x = 1; +>x : Symbol(C1.x, Decl(index.js, 1, 47)) +} + +const c1_v1 = C1(); +>c1_v1 : Symbol(c1_v1, Decl(index.js, 5, 5)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + +const c1_v2 = new C1(); +>c1_v2 : Symbol(c1_v2, Decl(index.js, 6, 5)) +>C1 : Symbol(C1, Decl(index.js, 0, 0)) + +var C2 = function () { +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + + if (!(this instanceof C2)) return new C2(); +>C2 : Symbol(C2, Decl(index.js, 8, 3)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + + this.x = 1; +>x : Symbol(C2.x, Decl(index.js, 9, 47)) + +}; + +const c2_v1 = C2(); +>c2_v1 : Symbol(c2_v1, Decl(index.js, 13, 5)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + +const c2_v2 = new C2(); +>c2_v2 : Symbol(c2_v2, Decl(index.js, 14, 5)) +>C2 : Symbol(C2, Decl(index.js, 8, 3)) + +/** @class */ +function C3() { +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + + if (!(this instanceof C3)) return new C3(); +>C3 : Symbol(C3, Decl(index.js, 14, 23)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +}; + +const c3_v1 = C3(); +>c3_v1 : Symbol(c3_v1, Decl(index.js, 21, 5)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +const c3_v2 = new C3(); +>c3_v2 : Symbol(c3_v2, Decl(index.js, 22, 5)) +>C3 : Symbol(C3, Decl(index.js, 14, 23)) + +/** @class */ +var C4 = function () { +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + + if (!(this instanceof C4)) return new C4(); +>C4 : Symbol(C4, Decl(index.js, 25, 3)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + +}; + +const c4_v1 = C4(); +>c4_v1 : Symbol(c4_v1, Decl(index.js, 29, 5)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + +const c4_v2 = new C4(); +>c4_v2 : Symbol(c4_v2, Decl(index.js, 30, 5)) +>C4 : Symbol(C4, Decl(index.js, 25, 3)) + diff --git a/tests/baselines/reference/constructorFunctions.types b/tests/baselines/reference/constructorFunctions.types new file mode 100644 index 00000000000..3429758b017 --- /dev/null +++ b/tests/baselines/reference/constructorFunctions.types @@ -0,0 +1,114 @@ +=== tests/cases/conformance/salsa/index.js === +function C1() { +>C1 : () => typeof C1 + + if (!(this instanceof C1)) return new C1(); +>!(this instanceof C1) : boolean +>(this instanceof C1) : boolean +>this instanceof C1 : boolean +>this : any +>C1 : () => typeof C1 +>new C1() : { x: number; } +>C1 : () => typeof C1 + + this.x = 1; +>this.x = 1 : 1 +>this.x : any +>this : any +>x : any +>1 : 1 +} + +const c1_v1 = C1(); +>c1_v1 : { x: number; } +>C1() : { x: number; } +>C1 : () => typeof C1 + +const c1_v2 = new C1(); +>c1_v2 : { x: number; } +>new C1() : { x: number; } +>C1 : () => typeof C1 + +var C2 = function () { +>C2 : () => any +>function () { if (!(this instanceof C2)) return new C2(); this.x = 1;} : () => any + + if (!(this instanceof C2)) return new C2(); +>!(this instanceof C2) : boolean +>(this instanceof C2) : boolean +>this instanceof C2 : boolean +>this : any +>C2 : () => any +>new C2() : { x: number; } +>C2 : () => any + + this.x = 1; +>this.x = 1 : 1 +>this.x : any +>this : any +>x : any +>1 : 1 + +}; + +const c2_v1 = C2(); +>c2_v1 : { x: number; } +>C2() : { x: number; } +>C2 : () => any + +const c2_v2 = new C2(); +>c2_v2 : { x: number; } +>new C2() : { x: number; } +>C2 : () => any + +/** @class */ +function C3() { +>C3 : () => typeof C3 + + if (!(this instanceof C3)) return new C3(); +>!(this instanceof C3) : boolean +>(this instanceof C3) : boolean +>this instanceof C3 : boolean +>this : any +>C3 : () => typeof C3 +>new C3() : {} +>C3 : () => typeof C3 + +}; + +const c3_v1 = C3(); +>c3_v1 : {} +>C3() : {} +>C3 : () => typeof C3 + +const c3_v2 = new C3(); +>c3_v2 : {} +>new C3() : {} +>C3 : () => typeof C3 + +/** @class */ +var C4 = function () { +>C4 : () => any +>function () { if (!(this instanceof C4)) return new C4();} : () => any + + if (!(this instanceof C4)) return new C4(); +>!(this instanceof C4) : boolean +>(this instanceof C4) : boolean +>this instanceof C4 : boolean +>this : any +>C4 : () => any +>new C4() : {} +>C4 : () => any + +}; + +const c4_v1 = C4(); +>c4_v1 : {} +>C4() : {} +>C4 : () => any + +const c4_v2 = new C4(); +>c4_v2 : {} +>new C4() : {} +>C4 : () => any + diff --git a/tests/baselines/reference/contextualTypingWithGenericSignature.types b/tests/baselines/reference/contextualTypingWithGenericSignature.types index 68c5f3c422d..e662f2c4192 100644 --- a/tests/baselines/reference/contextualTypingWithGenericSignature.types +++ b/tests/baselines/reference/contextualTypingWithGenericSignature.types @@ -16,10 +16,10 @@ var f2: { }; f2 = (x, y) => { return x } ->f2 = (x, y) => { return x } : (x: any, y: any) => any +>f2 = (x, y) => { return x } : (x: T, y: U) => T >f2 : (x: T, y: U) => T ->(x, y) => { return x } : (x: any, y: any) => any ->x : any ->y : any ->x : any +>(x, y) => { return x } : (x: T, y: U) => T +>x : T +>y : U +>x : T diff --git a/tests/baselines/reference/genericContextualTypes1.js b/tests/baselines/reference/genericContextualTypes1.js new file mode 100644 index 00000000000..94724123330 --- /dev/null +++ b/tests/baselines/reference/genericContextualTypes1.js @@ -0,0 +1,107 @@ +//// [genericContextualTypes1.ts] +type Box = { value: T }; + +declare function wrap(f: (a: A) => B): (a: A) => B; + +declare function compose(f: (a: A) => B, g: (b: B) => C): (a: A) => C; + +declare function list(a: T): T[]; + +declare function unlist(a: T[]): T; + +declare function box(x: V): Box; + +declare function unbox(x: Box): W; + +declare function map(a: T[], f: (x: T) => U): U[]; + +declare function identity(x: T): T; + +declare function zip(a: A, b: B): [A, B]; + +declare function flip(f: (x: X, y: Y) => Z): (y: Y, x: X) => Z; + +const f00: (x: A) => A[] = list; +const f01: (x: A) => A[] = x => [x]; +const f02: (x: A) => A[] = wrap(list); +const f03: (x: A) => A[] = wrap(x => [x]); + +const f10: (x: T) => Box = compose(a => list(a), b => box(b)); +const f11: (x: T) => Box = compose(list, box); +const f12: (x: Box) => T = compose(a => unbox(a), b => unlist(b)); +const f13: (x: Box) => T = compose(unbox, unlist); + +const arrayMap = (f: (x: T) => U) => (a: T[]) => a.map(f); +const arrayFilter = (f: (x: T) => boolean) => (a: T[]) => a.filter(f); + +const f20: (a: string[]) => number[] = arrayMap(x => x.length); +const f21: (a: A[]) => A[][] = arrayMap(x => [x]); +const f22: (a: A[]) => A[] = arrayMap(identity); +const f23: (a: A[]) => Box[] = arrayMap(value => ({ value })); + +const f30: (a: string[]) => string[] = arrayFilter(x => x.length > 10); +const f31: >(a: T[]) => T[] = arrayFilter(x => x.value > 10); + +const f40: (b: B, a: A) => [A, B] = flip(zip); + +// Repro from #16293 + +type fn = (a: A) => A; +const fn: fn = a => a; + + +//// [genericContextualTypes1.js] +"use strict"; +var f00 = list; +var f01 = function (x) { return [x]; }; +var f02 = wrap(list); +var f03 = wrap(function (x) { return [x]; }); +var f10 = compose(function (a) { return list(a); }, function (b) { return box(b); }); +var f11 = compose(list, box); +var f12 = compose(function (a) { return unbox(a); }, function (b) { return unlist(b); }); +var f13 = compose(unbox, unlist); +var arrayMap = function (f) { return function (a) { return a.map(f); }; }; +var arrayFilter = function (f) { return function (a) { return a.filter(f); }; }; +var f20 = arrayMap(function (x) { return x.length; }); +var f21 = arrayMap(function (x) { return [x]; }); +var f22 = arrayMap(identity); +var f23 = arrayMap(function (value) { return ({ value: value }); }); +var f30 = arrayFilter(function (x) { return x.length > 10; }); +var f31 = arrayFilter(function (x) { return x.value > 10; }); +var f40 = flip(zip); +var fn = function (a) { return a; }; + + +//// [genericContextualTypes1.d.ts] +declare type Box = { + value: T; +}; +declare function wrap(f: (a: A) => B): (a: A) => B; +declare function compose(f: (a: A) => B, g: (b: B) => C): (a: A) => C; +declare function list(a: T): T[]; +declare function unlist(a: T[]): T; +declare function box(x: V): Box; +declare function unbox(x: Box): W; +declare function map(a: T[], f: (x: T) => U): U[]; +declare function identity(x: T): T; +declare function zip(a: A, b: B): [A, B]; +declare function flip(f: (x: X, y: Y) => Z): (y: Y, x: X) => Z; +declare const f00: (x: A) => A[]; +declare const f01: (x: A) => A[]; +declare const f02: (x: A) => A[]; +declare const f03: (x: A) => A[]; +declare const f10: (x: T) => Box; +declare const f11: (x: T) => Box; +declare const f12: (x: Box) => T; +declare const f13: (x: Box) => T; +declare const arrayMap: (f: (x: T) => U) => (a: T[]) => U[]; +declare const arrayFilter: (f: (x: T) => boolean) => (a: T[]) => T[]; +declare const f20: (a: string[]) => number[]; +declare const f21: (a: A[]) => A[][]; +declare const f22: (a: A[]) => A[]; +declare const f23: (a: A[]) => Box[]; +declare const f30: (a: string[]) => string[]; +declare const f31: >(a: T[]) => T[]; +declare const f40: (b: B, a: A) => [A, B]; +declare type fn = (a: A) => A; +declare const fn: fn; diff --git a/tests/baselines/reference/genericContextualTypes1.symbols b/tests/baselines/reference/genericContextualTypes1.symbols new file mode 100644 index 00000000000..29d8766abca --- /dev/null +++ b/tests/baselines/reference/genericContextualTypes1.symbols @@ -0,0 +1,318 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/genericContextualTypes1.ts === +type Box = { value: T }; +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 0, 9)) +>value : Symbol(value, Decl(genericContextualTypes1.ts, 0, 15)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 0, 9)) + +declare function wrap(f: (a: A) => B): (a: A) => B; +>wrap : Symbol(wrap, Decl(genericContextualTypes1.ts, 0, 27)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 2, 22)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 2, 24)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 2, 28)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 2, 32)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 2, 22)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 2, 24)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 2, 46)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 2, 22)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 2, 24)) + +declare function compose(f: (a: A) => B, g: (b: B) => C): (a: A) => C; +>compose : Symbol(compose, Decl(genericContextualTypes1.ts, 2, 57)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 4, 25)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 4, 27)) +>C : Symbol(C, Decl(genericContextualTypes1.ts, 4, 30)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 4, 34)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 4, 38)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 4, 25)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 4, 27)) +>g : Symbol(g, Decl(genericContextualTypes1.ts, 4, 49)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 4, 54)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 4, 27)) +>C : Symbol(C, Decl(genericContextualTypes1.ts, 4, 30)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 4, 68)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 4, 25)) +>C : Symbol(C, Decl(genericContextualTypes1.ts, 4, 30)) + +declare function list(a: T): T[]; +>list : Symbol(list, Decl(genericContextualTypes1.ts, 4, 79)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 6, 22)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 6, 25)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 6, 22)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 6, 22)) + +declare function unlist(a: T[]): T; +>unlist : Symbol(unlist, Decl(genericContextualTypes1.ts, 6, 36)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 8, 24)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 8, 27)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 8, 24)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 8, 24)) + +declare function box(x: V): Box; +>box : Symbol(box, Decl(genericContextualTypes1.ts, 8, 38)) +>V : Symbol(V, Decl(genericContextualTypes1.ts, 10, 21)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 10, 24)) +>V : Symbol(V, Decl(genericContextualTypes1.ts, 10, 21)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>V : Symbol(V, Decl(genericContextualTypes1.ts, 10, 21)) + +declare function unbox(x: Box): W; +>unbox : Symbol(unbox, Decl(genericContextualTypes1.ts, 10, 38)) +>W : Symbol(W, Decl(genericContextualTypes1.ts, 12, 23)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 12, 26)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>W : Symbol(W, Decl(genericContextualTypes1.ts, 12, 23)) +>W : Symbol(W, Decl(genericContextualTypes1.ts, 12, 23)) + +declare function map(a: T[], f: (x: T) => U): U[]; +>map : Symbol(map, Decl(genericContextualTypes1.ts, 12, 40)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 14, 21)) +>U : Symbol(U, Decl(genericContextualTypes1.ts, 14, 23)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 14, 27)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 14, 21)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 14, 34)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 14, 39)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 14, 21)) +>U : Symbol(U, Decl(genericContextualTypes1.ts, 14, 23)) +>U : Symbol(U, Decl(genericContextualTypes1.ts, 14, 23)) + +declare function identity(x: T): T; +>identity : Symbol(identity, Decl(genericContextualTypes1.ts, 14, 56)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 16, 26)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 16, 29)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 16, 26)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 16, 26)) + +declare function zip(a: A, b: B): [A, B]; +>zip : Symbol(zip, Decl(genericContextualTypes1.ts, 16, 38)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 18, 21)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 18, 23)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 18, 27)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 18, 21)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 18, 32)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 18, 23)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 18, 21)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 18, 23)) + +declare function flip(f: (x: X, y: Y) => Z): (y: Y, x: X) => Z; +>flip : Symbol(flip, Decl(genericContextualTypes1.ts, 18, 47)) +>X : Symbol(X, Decl(genericContextualTypes1.ts, 20, 22)) +>Y : Symbol(Y, Decl(genericContextualTypes1.ts, 20, 24)) +>Z : Symbol(Z, Decl(genericContextualTypes1.ts, 20, 27)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 20, 31)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 20, 35)) +>X : Symbol(X, Decl(genericContextualTypes1.ts, 20, 22)) +>y : Symbol(y, Decl(genericContextualTypes1.ts, 20, 40)) +>Y : Symbol(Y, Decl(genericContextualTypes1.ts, 20, 24)) +>Z : Symbol(Z, Decl(genericContextualTypes1.ts, 20, 27)) +>y : Symbol(y, Decl(genericContextualTypes1.ts, 20, 55)) +>Y : Symbol(Y, Decl(genericContextualTypes1.ts, 20, 24)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 20, 60)) +>X : Symbol(X, Decl(genericContextualTypes1.ts, 20, 22)) +>Z : Symbol(Z, Decl(genericContextualTypes1.ts, 20, 27)) + +const f00: (x: A) => A[] = list; +>f00 : Symbol(f00, Decl(genericContextualTypes1.ts, 22, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 22, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 22, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 22, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 22, 12)) +>list : Symbol(list, Decl(genericContextualTypes1.ts, 4, 79)) + +const f01: (x: A) => A[] = x => [x]; +>f01 : Symbol(f01, Decl(genericContextualTypes1.ts, 23, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 23, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 23, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 23, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 23, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 23, 29)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 23, 29)) + +const f02: (x: A) => A[] = wrap(list); +>f02 : Symbol(f02, Decl(genericContextualTypes1.ts, 24, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 24, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 24, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 24, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 24, 12)) +>wrap : Symbol(wrap, Decl(genericContextualTypes1.ts, 0, 27)) +>list : Symbol(list, Decl(genericContextualTypes1.ts, 4, 79)) + +const f03: (x: A) => A[] = wrap(x => [x]); +>f03 : Symbol(f03, Decl(genericContextualTypes1.ts, 25, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 25, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 25, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 25, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 25, 12)) +>wrap : Symbol(wrap, Decl(genericContextualTypes1.ts, 0, 27)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 25, 35)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 25, 35)) + +const f10: (x: T) => Box = compose(a => list(a), b => box(b)); +>f10 : Symbol(f10, Decl(genericContextualTypes1.ts, 27, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 27, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 27, 15)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 27, 12)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 27, 12)) +>compose : Symbol(compose, Decl(genericContextualTypes1.ts, 2, 57)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 27, 43)) +>list : Symbol(list, Decl(genericContextualTypes1.ts, 4, 79)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 27, 43)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 27, 56)) +>box : Symbol(box, Decl(genericContextualTypes1.ts, 8, 38)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 27, 56)) + +const f11: (x: T) => Box = compose(list, box); +>f11 : Symbol(f11, Decl(genericContextualTypes1.ts, 28, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 28, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 28, 15)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 28, 12)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 28, 12)) +>compose : Symbol(compose, Decl(genericContextualTypes1.ts, 2, 57)) +>list : Symbol(list, Decl(genericContextualTypes1.ts, 4, 79)) +>box : Symbol(box, Decl(genericContextualTypes1.ts, 8, 38)) + +const f12: (x: Box) => T = compose(a => unbox(a), b => unlist(b)); +>f12 : Symbol(f12, Decl(genericContextualTypes1.ts, 29, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 29, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 29, 15)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 29, 12)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 29, 12)) +>compose : Symbol(compose, Decl(genericContextualTypes1.ts, 2, 57)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 29, 43)) +>unbox : Symbol(unbox, Decl(genericContextualTypes1.ts, 10, 38)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 29, 43)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 29, 57)) +>unlist : Symbol(unlist, Decl(genericContextualTypes1.ts, 6, 36)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 29, 57)) + +const f13: (x: Box) => T = compose(unbox, unlist); +>f13 : Symbol(f13, Decl(genericContextualTypes1.ts, 30, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 30, 12)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 30, 15)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 30, 12)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 30, 12)) +>compose : Symbol(compose, Decl(genericContextualTypes1.ts, 2, 57)) +>unbox : Symbol(unbox, Decl(genericContextualTypes1.ts, 10, 38)) +>unlist : Symbol(unlist, Decl(genericContextualTypes1.ts, 6, 36)) + +const arrayMap = (f: (x: T) => U) => (a: T[]) => a.map(f); +>arrayMap : Symbol(arrayMap, Decl(genericContextualTypes1.ts, 32, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 32, 18)) +>U : Symbol(U, Decl(genericContextualTypes1.ts, 32, 20)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 32, 24)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 32, 28)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 32, 18)) +>U : Symbol(U, Decl(genericContextualTypes1.ts, 32, 20)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 32, 44)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 32, 18)) +>a.map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 32, 44)) +>map : Symbol(Array.map, Decl(lib.d.ts, --, --)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 32, 24)) + +const arrayFilter = (f: (x: T) => boolean) => (a: T[]) => a.filter(f); +>arrayFilter : Symbol(arrayFilter, Decl(genericContextualTypes1.ts, 33, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 33, 21)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 33, 24)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 33, 28)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 33, 21)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 33, 50)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 33, 21)) +>a.filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 33, 50)) +>filter : Symbol(Array.filter, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +>f : Symbol(f, Decl(genericContextualTypes1.ts, 33, 24)) + +const f20: (a: string[]) => number[] = arrayMap(x => x.length); +>f20 : Symbol(f20, Decl(genericContextualTypes1.ts, 35, 5)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 35, 12)) +>arrayMap : Symbol(arrayMap, Decl(genericContextualTypes1.ts, 32, 5)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 35, 48)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 35, 48)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +const f21: (a: A[]) => A[][] = arrayMap(x => [x]); +>f21 : Symbol(f21, Decl(genericContextualTypes1.ts, 36, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 36, 12)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 36, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 36, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 36, 12)) +>arrayMap : Symbol(arrayMap, Decl(genericContextualTypes1.ts, 32, 5)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 36, 43)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 36, 43)) + +const f22: (a: A[]) => A[] = arrayMap(identity); +>f22 : Symbol(f22, Decl(genericContextualTypes1.ts, 37, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 37, 12)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 37, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 37, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 37, 12)) +>arrayMap : Symbol(arrayMap, Decl(genericContextualTypes1.ts, 32, 5)) +>identity : Symbol(identity, Decl(genericContextualTypes1.ts, 14, 56)) + +const f23: (a: A[]) => Box[] = arrayMap(value => ({ value })); +>f23 : Symbol(f23, Decl(genericContextualTypes1.ts, 38, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 38, 12)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 38, 15)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 38, 12)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 38, 12)) +>arrayMap : Symbol(arrayMap, Decl(genericContextualTypes1.ts, 32, 5)) +>value : Symbol(value, Decl(genericContextualTypes1.ts, 38, 46)) +>value : Symbol(value, Decl(genericContextualTypes1.ts, 38, 57)) + +const f30: (a: string[]) => string[] = arrayFilter(x => x.length > 10); +>f30 : Symbol(f30, Decl(genericContextualTypes1.ts, 40, 5)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 40, 12)) +>arrayFilter : Symbol(arrayFilter, Decl(genericContextualTypes1.ts, 33, 5)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 40, 51)) +>x.length : Symbol(String.length, Decl(lib.d.ts, --, --)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 40, 51)) +>length : Symbol(String.length, Decl(lib.d.ts, --, --)) + +const f31: >(a: T[]) => T[] = arrayFilter(x => x.value > 10); +>f31 : Symbol(f31, Decl(genericContextualTypes1.ts, 41, 5)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 41, 12)) +>Box : Symbol(Box, Decl(genericContextualTypes1.ts, 0, 0)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 41, 35)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 41, 12)) +>T : Symbol(T, Decl(genericContextualTypes1.ts, 41, 12)) +>arrayFilter : Symbol(arrayFilter, Decl(genericContextualTypes1.ts, 33, 5)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 41, 64)) +>x.value : Symbol(value, Decl(genericContextualTypes1.ts, 0, 15)) +>x : Symbol(x, Decl(genericContextualTypes1.ts, 41, 64)) +>value : Symbol(value, Decl(genericContextualTypes1.ts, 0, 15)) + +const f40: (b: B, a: A) => [A, B] = flip(zip); +>f40 : Symbol(f40, Decl(genericContextualTypes1.ts, 43, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 43, 12)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 43, 14)) +>b : Symbol(b, Decl(genericContextualTypes1.ts, 43, 18)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 43, 14)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 43, 23)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 43, 12)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 43, 12)) +>B : Symbol(B, Decl(genericContextualTypes1.ts, 43, 14)) +>flip : Symbol(flip, Decl(genericContextualTypes1.ts, 18, 47)) +>zip : Symbol(zip, Decl(genericContextualTypes1.ts, 16, 38)) + +// Repro from #16293 + +type fn = (a: A) => A; +>fn : Symbol(fn, Decl(genericContextualTypes1.ts, 43, 52), Decl(genericContextualTypes1.ts, 48, 5)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 47, 11)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 47, 14)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 47, 11)) +>A : Symbol(A, Decl(genericContextualTypes1.ts, 47, 11)) + +const fn: fn = a => a; +>fn : Symbol(fn, Decl(genericContextualTypes1.ts, 43, 52), Decl(genericContextualTypes1.ts, 48, 5)) +>fn : Symbol(fn, Decl(genericContextualTypes1.ts, 43, 52), Decl(genericContextualTypes1.ts, 48, 5)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 48, 14)) +>a : Symbol(a, Decl(genericContextualTypes1.ts, 48, 14)) + diff --git a/tests/baselines/reference/genericContextualTypes1.types b/tests/baselines/reference/genericContextualTypes1.types new file mode 100644 index 00000000000..4aedcd6e81b --- /dev/null +++ b/tests/baselines/reference/genericContextualTypes1.types @@ -0,0 +1,362 @@ +=== tests/cases/conformance/types/typeRelationships/typeInference/genericContextualTypes1.ts === +type Box = { value: T }; +>Box : Box +>T : T +>value : T +>T : T + +declare function wrap(f: (a: A) => B): (a: A) => B; +>wrap : (f: (a: A) => B) => (a: A) => B +>A : A +>B : B +>f : (a: A) => B +>a : A +>A : A +>B : B +>a : A +>A : A +>B : B + +declare function compose(f: (a: A) => B, g: (b: B) => C): (a: A) => C; +>compose : (f: (a: A) => B, g: (b: B) => C) => (a: A) => C +>A : A +>B : B +>C : C +>f : (a: A) => B +>a : A +>A : A +>B : B +>g : (b: B) => C +>b : B +>B : B +>C : C +>a : A +>A : A +>C : C + +declare function list(a: T): T[]; +>list : (a: T) => T[] +>T : T +>a : T +>T : T +>T : T + +declare function unlist(a: T[]): T; +>unlist : (a: T[]) => T +>T : T +>a : T[] +>T : T +>T : T + +declare function box(x: V): Box; +>box : (x: V) => Box +>V : V +>x : V +>V : V +>Box : Box +>V : V + +declare function unbox(x: Box): W; +>unbox : (x: Box) => W +>W : W +>x : Box +>Box : Box +>W : W +>W : W + +declare function map(a: T[], f: (x: T) => U): U[]; +>map : (a: T[], f: (x: T) => U) => U[] +>T : T +>U : U +>a : T[] +>T : T +>f : (x: T) => U +>x : T +>T : T +>U : U +>U : U + +declare function identity(x: T): T; +>identity : (x: T) => T +>T : T +>x : T +>T : T +>T : T + +declare function zip(a: A, b: B): [A, B]; +>zip : (a: A, b: B) => [A, B] +>A : A +>B : B +>a : A +>A : A +>b : B +>B : B +>A : A +>B : B + +declare function flip(f: (x: X, y: Y) => Z): (y: Y, x: X) => Z; +>flip : (f: (x: X, y: Y) => Z) => (y: Y, x: X) => Z +>X : X +>Y : Y +>Z : Z +>f : (x: X, y: Y) => Z +>x : X +>X : X +>y : Y +>Y : Y +>Z : Z +>y : Y +>Y : Y +>x : X +>X : X +>Z : Z + +const f00: (x: A) => A[] = list; +>f00 : (x: A) => A[] +>A : A +>x : A +>A : A +>A : A +>list : (a: T) => T[] + +const f01: (x: A) => A[] = x => [x]; +>f01 : (x: A) => A[] +>A : A +>x : A +>A : A +>A : A +>x => [x] : (x: A) => A[] +>x : A +>[x] : A[] +>x : A + +const f02: (x: A) => A[] = wrap(list); +>f02 : (x: A) => A[] +>A : A +>x : A +>A : A +>A : A +>wrap(list) : (a: A) => A[] +>wrap : (f: (a: A) => B) => (a: A) => B +>list : (a: T) => T[] + +const f03: (x: A) => A[] = wrap(x => [x]); +>f03 : (x: A) => A[] +>A : A +>x : A +>A : A +>A : A +>wrap(x => [x]) : (a: A) => A[] +>wrap : (f: (a: A) => B) => (a: A) => B +>x => [x] : (x: A) => A[] +>x : A +>[x] : A[] +>x : A + +const f10: (x: T) => Box = compose(a => list(a), b => box(b)); +>f10 : (x: T) => Box +>T : T +>x : T +>T : T +>Box : Box +>T : T +>compose(a => list(a), b => box(b)) : (a: T) => Box +>compose : (f: (a: A) => B, g: (b: B) => C) => (a: A) => C +>a => list(a) : (a: T) => T[] +>a : T +>list(a) : T[] +>list : (a: T) => T[] +>a : T +>b => box(b) : (b: T[]) => Box +>b : T[] +>box(b) : Box +>box : (x: V) => Box +>b : T[] + +const f11: (x: T) => Box = compose(list, box); +>f11 : (x: T) => Box +>T : T +>x : T +>T : T +>Box : Box +>T : T +>compose(list, box) : (a: T) => Box +>compose : (f: (a: A) => B, g: (b: B) => C) => (a: A) => C +>list : (a: T) => T[] +>box : (x: V) => Box + +const f12: (x: Box) => T = compose(a => unbox(a), b => unlist(b)); +>f12 : (x: Box) => T +>T : T +>x : Box +>Box : Box +>T : T +>T : T +>compose(a => unbox(a), b => unlist(b)) : (a: Box) => T +>compose : (f: (a: A) => B, g: (b: B) => C) => (a: A) => C +>a => unbox(a) : (a: Box) => T[] +>a : Box +>unbox(a) : T[] +>unbox : (x: Box) => W +>a : Box +>b => unlist(b) : (b: T[]) => T +>b : T[] +>unlist(b) : T +>unlist : (a: T[]) => T +>b : T[] + +const f13: (x: Box) => T = compose(unbox, unlist); +>f13 : (x: Box) => T +>T : T +>x : Box +>Box : Box +>T : T +>T : T +>compose(unbox, unlist) : (a: Box) => T +>compose : (f: (a: A) => B, g: (b: B) => C) => (a: A) => C +>unbox : (x: Box) => W +>unlist : (a: T[]) => T + +const arrayMap = (f: (x: T) => U) => (a: T[]) => a.map(f); +>arrayMap : (f: (x: T) => U) => (a: T[]) => U[] +>(f: (x: T) => U) => (a: T[]) => a.map(f) : (f: (x: T) => U) => (a: T[]) => U[] +>T : T +>U : U +>f : (x: T) => U +>x : T +>T : T +>U : U +>(a: T[]) => a.map(f) : (a: T[]) => U[] +>a : T[] +>T : T +>a.map(f) : U[] +>a.map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +>a : T[] +>map : (callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[] +>f : (x: T) => U + +const arrayFilter = (f: (x: T) => boolean) => (a: T[]) => a.filter(f); +>arrayFilter : (f: (x: T) => boolean) => (a: T[]) => T[] +>(f: (x: T) => boolean) => (a: T[]) => a.filter(f) : (f: (x: T) => boolean) => (a: T[]) => T[] +>T : T +>f : (x: T) => boolean +>x : T +>T : T +>(a: T[]) => a.filter(f) : (a: T[]) => T[] +>a : T[] +>T : T +>a.filter(f) : T[] +>a.filter : { (callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; } +>a : T[] +>filter : { (callbackfn: (value: T, index: number, array: T[]) => value is S, thisArg?: any): S[]; (callbackfn: (value: T, index: number, array: T[]) => any, thisArg?: any): T[]; } +>f : (x: T) => boolean + +const f20: (a: string[]) => number[] = arrayMap(x => x.length); +>f20 : (a: string[]) => number[] +>a : string[] +>arrayMap(x => x.length) : (a: string[]) => number[] +>arrayMap : (f: (x: T) => U) => (a: T[]) => U[] +>x => x.length : (x: string) => number +>x : string +>x.length : number +>x : string +>length : number + +const f21: (a: A[]) => A[][] = arrayMap(x => [x]); +>f21 : (a: A[]) => A[][] +>A : A +>a : A[] +>A : A +>A : A +>arrayMap(x => [x]) : (a: A[]) => A[][] +>arrayMap : (f: (x: T) => U) => (a: T[]) => U[] +>x => [x] : (x: A) => A[] +>x : A +>[x] : A[] +>x : A + +const f22: (a: A[]) => A[] = arrayMap(identity); +>f22 : (a: A[]) => A[] +>A : A +>a : A[] +>A : A +>A : A +>arrayMap(identity) : (a: A[]) => A[] +>arrayMap : (f: (x: T) => U) => (a: T[]) => U[] +>identity : (x: T) => T + +const f23: (a: A[]) => Box[] = arrayMap(value => ({ value })); +>f23 : (a: A[]) => Box[] +>A : A +>a : A[] +>A : A +>Box : Box +>A : A +>arrayMap(value => ({ value })) : (a: A[]) => { value: A; }[] +>arrayMap : (f: (x: T) => U) => (a: T[]) => U[] +>value => ({ value }) : (value: A) => { value: A; } +>value : A +>({ value }) : { value: A; } +>{ value } : { value: A; } +>value : A + +const f30: (a: string[]) => string[] = arrayFilter(x => x.length > 10); +>f30 : (a: string[]) => string[] +>a : string[] +>arrayFilter(x => x.length > 10) : (a: string[]) => string[] +>arrayFilter : (f: (x: T) => boolean) => (a: T[]) => T[] +>x => x.length > 10 : (x: string) => boolean +>x : string +>x.length > 10 : boolean +>x.length : number +>x : string +>length : number +>10 : 10 + +const f31: >(a: T[]) => T[] = arrayFilter(x => x.value > 10); +>f31 : >(a: T[]) => T[] +>T : T +>Box : Box +>a : T[] +>T : T +>T : T +>arrayFilter(x => x.value > 10) : (a: T[]) => T[] +>arrayFilter : (f: (x: T) => boolean) => (a: T[]) => T[] +>x => x.value > 10 : (x: T) => boolean +>x : T +>x.value > 10 : boolean +>x.value : number +>x : T +>value : number +>10 : 10 + +const f40: (b: B, a: A) => [A, B] = flip(zip); +>f40 : (b: B, a: A) => [A, B] +>A : A +>B : B +>b : B +>B : B +>a : A +>A : A +>A : A +>B : B +>flip(zip) : (y: B, x: A) => [A, B] +>flip : (f: (x: X, y: Y) => Z) => (y: Y, x: X) => Z +>zip : (a: A, b: B) => [A, B] + +// Repro from #16293 + +type fn = (a: A) => A; +>fn : fn +>A : A +>a : A +>A : A +>A : A + +const fn: fn = a => a; +>fn : fn +>fn : fn +>a => a : (a: A) => A +>a : A +>a : A + diff --git a/tests/baselines/reference/genericFunctionHasFreshTypeArgs.types b/tests/baselines/reference/genericFunctionHasFreshTypeArgs.types index 3a3afebb9ac..d6f64bdc933 100644 --- a/tests/baselines/reference/genericFunctionHasFreshTypeArgs.types +++ b/tests/baselines/reference/genericFunctionHasFreshTypeArgs.types @@ -9,13 +9,13 @@ function f(p: (x: T) => void) { }; f(x => f(y => x = y)); >f(x => f(y => x = y)) : void >f : (p: (x: T) => void) => void ->x => f(y => x = y) : (x: any) => void ->x : any +>x => f(y => x = y) : (x: T) => void +>x : T >f(y => x = y) : void >f : (p: (x: T) => void) => void ->y => x = y : (y: any) => any ->y : any ->x = y : any ->x : any ->y : any +>y => x = y : (y: T) => T +>y : T +>x = y : T +>x : T +>y : T diff --git a/tests/baselines/reference/genericTypeAssertions3.types b/tests/baselines/reference/genericTypeAssertions3.types index 9f7facc8d47..e46dd4aaa4e 100644 --- a/tests/baselines/reference/genericTypeAssertions3.types +++ b/tests/baselines/reference/genericTypeAssertions3.types @@ -6,9 +6,9 @@ var r = < (x: T) => T > ((x) => { return null; }); // bug was 'could not find >x : T >T : T >T : T ->((x) => { return null; }) : (x: any) => any ->(x) => { return null; } : (x: any) => any ->x : any +>((x) => { return null; }) : (x: T) => any +>(x) => { return null; } : (x: T) => any +>x : T >null : null var s = < (x: T) => T > ((x: any) => { return null; }); // no error diff --git a/tests/baselines/reference/implicitAnyGenericTypeInference.errors.txt b/tests/baselines/reference/implicitAnyGenericTypeInference.errors.txt deleted file mode 100644 index 0c64c3e6125..00000000000 --- a/tests/baselines/reference/implicitAnyGenericTypeInference.errors.txt +++ /dev/null @@ -1,16 +0,0 @@ -tests/cases/compiler/implicitAnyGenericTypeInference.ts(6,19): error TS7006: Parameter 'x' implicitly has an 'any' type. -tests/cases/compiler/implicitAnyGenericTypeInference.ts(6,22): error TS7006: Parameter 'y' implicitly has an 'any' type. - - -==== tests/cases/compiler/implicitAnyGenericTypeInference.ts (2 errors) ==== - interface Comparer { - compareTo(x: T, y: U): U; - } - - var c: Comparer; - c = { compareTo: (x, y) => { return y; } }; - ~ -!!! error TS7006: Parameter 'x' implicitly has an 'any' type. - ~ -!!! error TS7006: Parameter 'y' implicitly has an 'any' type. - var r = c.compareTo(1, ''); \ No newline at end of file diff --git a/tests/baselines/reference/implicitAnyGenericTypeInference.symbols b/tests/baselines/reference/implicitAnyGenericTypeInference.symbols new file mode 100644 index 00000000000..e56b68a7134 --- /dev/null +++ b/tests/baselines/reference/implicitAnyGenericTypeInference.symbols @@ -0,0 +1,32 @@ +=== tests/cases/compiler/implicitAnyGenericTypeInference.ts === +interface Comparer { +>Comparer : Symbol(Comparer, Decl(implicitAnyGenericTypeInference.ts, 0, 0)) +>T : Symbol(T, Decl(implicitAnyGenericTypeInference.ts, 0, 19)) + + compareTo(x: T, y: U): U; +>compareTo : Symbol(Comparer.compareTo, Decl(implicitAnyGenericTypeInference.ts, 0, 23)) +>U : Symbol(U, Decl(implicitAnyGenericTypeInference.ts, 1, 14)) +>x : Symbol(x, Decl(implicitAnyGenericTypeInference.ts, 1, 17)) +>T : Symbol(T, Decl(implicitAnyGenericTypeInference.ts, 0, 19)) +>y : Symbol(y, Decl(implicitAnyGenericTypeInference.ts, 1, 22)) +>U : Symbol(U, Decl(implicitAnyGenericTypeInference.ts, 1, 14)) +>U : Symbol(U, Decl(implicitAnyGenericTypeInference.ts, 1, 14)) +} + +var c: Comparer; +>c : Symbol(c, Decl(implicitAnyGenericTypeInference.ts, 4, 3)) +>Comparer : Symbol(Comparer, Decl(implicitAnyGenericTypeInference.ts, 0, 0)) + +c = { compareTo: (x, y) => { return y; } }; +>c : Symbol(c, Decl(implicitAnyGenericTypeInference.ts, 4, 3)) +>compareTo : Symbol(compareTo, Decl(implicitAnyGenericTypeInference.ts, 5, 5)) +>x : Symbol(x, Decl(implicitAnyGenericTypeInference.ts, 5, 18)) +>y : Symbol(y, Decl(implicitAnyGenericTypeInference.ts, 5, 20)) +>y : Symbol(y, Decl(implicitAnyGenericTypeInference.ts, 5, 20)) + +var r = c.compareTo(1, ''); +>r : Symbol(r, Decl(implicitAnyGenericTypeInference.ts, 6, 3)) +>c.compareTo : Symbol(Comparer.compareTo, Decl(implicitAnyGenericTypeInference.ts, 0, 23)) +>c : Symbol(c, Decl(implicitAnyGenericTypeInference.ts, 4, 3)) +>compareTo : Symbol(Comparer.compareTo, Decl(implicitAnyGenericTypeInference.ts, 0, 23)) + diff --git a/tests/baselines/reference/implicitAnyGenericTypeInference.types b/tests/baselines/reference/implicitAnyGenericTypeInference.types new file mode 100644 index 00000000000..4124c729f14 --- /dev/null +++ b/tests/baselines/reference/implicitAnyGenericTypeInference.types @@ -0,0 +1,38 @@ +=== tests/cases/compiler/implicitAnyGenericTypeInference.ts === +interface Comparer { +>Comparer : Comparer +>T : T + + compareTo(x: T, y: U): U; +>compareTo : (x: T, y: U) => U +>U : U +>x : T +>T : T +>y : U +>U : U +>U : U +} + +var c: Comparer; +>c : Comparer +>Comparer : Comparer + +c = { compareTo: (x, y) => { return y; } }; +>c = { compareTo: (x, y) => { return y; } } : { compareTo: (x: any, y: U) => U; } +>c : Comparer +>{ compareTo: (x, y) => { return y; } } : { compareTo: (x: any, y: U) => U; } +>compareTo : (x: any, y: U) => U +>(x, y) => { return y; } : (x: any, y: U) => U +>x : any +>y : U +>y : U + +var r = c.compareTo(1, ''); +>r : string +>c.compareTo(1, '') : "" +>c.compareTo : (x: any, y: U) => U +>c : Comparer +>compareTo : (x: any, y: U) => U +>1 : 1 +>'' : "" + diff --git a/tests/baselines/reference/importHelpersAmd.js b/tests/baselines/reference/importHelpersAmd.js index b756355921d..3d74b2277fb 100644 --- a/tests/baselines/reference/importHelpersAmd.js +++ b/tests/baselines/reference/importHelpersAmd.js @@ -5,16 +5,19 @@ export class A { } //// [b.ts] import { A } from "./a"; +export * from "./a"; export class B extends A { } //// [tslib.d.ts] export declare function __extends(d: Function, b: Function): void; export declare function __assign(t: any, ...sources: any[]): any; +export declare function __rest(t: any, propertyNames: string[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; - +export declare function __generator(thisArg: any, body: Function): any; +export declare function __exportStar(m: any, exports: any): void; //// [a.js] define(["require", "exports"], function (require, exports) { @@ -28,9 +31,10 @@ define(["require", "exports"], function (require, exports) { exports.A = A; }); //// [b.js] -define(["require", "exports", "tslib", "./a"], function (require, exports, tslib_1, a_1) { +define(["require", "exports", "tslib", "./a", "./a"], function (require, exports, tslib_1, a_1, a_2) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); + tslib_1.__exportStar(a_2, exports); var B = (function (_super) { tslib_1.__extends(B, _super); function B() { diff --git a/tests/baselines/reference/importHelpersAmd.symbols b/tests/baselines/reference/importHelpersAmd.symbols index 47528a8bba6..68506b4c353 100644 --- a/tests/baselines/reference/importHelpersAmd.symbols +++ b/tests/baselines/reference/importHelpersAmd.symbols @@ -6,8 +6,9 @@ export class A { } import { A } from "./a"; >A : Symbol(A, Decl(b.ts, 0, 8)) +export * from "./a"; export class B extends A { } ->B : Symbol(B, Decl(b.ts, 0, 24)) +>B : Symbol(B, Decl(b.ts, 1, 20)) >A : Symbol(A, Decl(b.ts, 0, 8)) === tests/cases/compiler/tslib.d.ts === @@ -23,6 +24,11 @@ export declare function __assign(t: any, ...sources: any[]): any; >t : Symbol(t, Decl(tslib.d.ts, --, --)) >sources : Symbol(sources, Decl(tslib.d.ts, --, --)) +export declare function __rest(t: any, propertyNames: string[]): any; +>__rest : Symbol(__rest, Decl(tslib.d.ts, --, --)) +>t : Symbol(t, Decl(tslib.d.ts, --, --)) +>propertyNames : Symbol(propertyNames, Decl(tslib.d.ts, --, --)) + export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --)) >decorators : Symbol(decorators, Decl(tslib.d.ts, --, --)) @@ -53,3 +59,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge >generator : Symbol(generator, Decl(tslib.d.ts, --, --)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +export declare function __generator(thisArg: any, body: Function): any; +>__generator : Symbol(__generator, Decl(tslib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(tslib.d.ts, --, --)) +>body : Symbol(body, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +export declare function __exportStar(m: any, exports: any): void; +>__exportStar : Symbol(__exportStar, Decl(tslib.d.ts, --, --)) +>m : Symbol(m, Decl(tslib.d.ts, --, --)) +>exports : Symbol(exports, Decl(tslib.d.ts, --, --)) + diff --git a/tests/baselines/reference/importHelpersAmd.types b/tests/baselines/reference/importHelpersAmd.types index 9ff756ffaab..23456ae2333 100644 --- a/tests/baselines/reference/importHelpersAmd.types +++ b/tests/baselines/reference/importHelpersAmd.types @@ -6,6 +6,7 @@ export class A { } import { A } from "./a"; >A : typeof A +export * from "./a"; export class B extends A { } >B : B >A : A @@ -23,6 +24,11 @@ export declare function __assign(t: any, ...sources: any[]): any; >t : any >sources : any[] +export declare function __rest(t: any, propertyNames: string[]): any; +>__rest : (t: any, propertyNames: string[]) => any +>t : any +>propertyNames : string[] + export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any >decorators : Function[] @@ -53,3 +59,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge >generator : Function >Function : Function +export declare function __generator(thisArg: any, body: Function): any; +>__generator : (thisArg: any, body: Function) => any +>thisArg : any +>body : Function +>Function : Function + +export declare function __exportStar(m: any, exports: any): void; +>__exportStar : (m: any, exports: any) => void +>m : any +>exports : any + diff --git a/tests/baselines/reference/importHelpersInAmbientContext.js b/tests/baselines/reference/importHelpersInAmbientContext.js index c1c00705951..c15bff36782 100644 --- a/tests/baselines/reference/importHelpersInAmbientContext.js +++ b/tests/baselines/reference/importHelpersInAmbientContext.js @@ -48,11 +48,13 @@ declare namespace N { //// [tslib.d.ts] export declare function __extends(d: Function, b: Function): void; export declare function __assign(t: any, ...sources: any[]): any; +export declare function __rest(t: any, propertyNames: string[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; - +export declare function __generator(thisArg: any, body: Function): any; +export declare function __exportStar(m: any, exports: any): void; //// [b.js] "use strict"; diff --git a/tests/baselines/reference/importHelpersInAmbientContext.symbols b/tests/baselines/reference/importHelpersInAmbientContext.symbols index 172eea3037f..9dd7d30390f 100644 --- a/tests/baselines/reference/importHelpersInAmbientContext.symbols +++ b/tests/baselines/reference/importHelpersInAmbientContext.symbols @@ -98,6 +98,11 @@ export declare function __assign(t: any, ...sources: any[]): any; >t : Symbol(t, Decl(tslib.d.ts, --, --)) >sources : Symbol(sources, Decl(tslib.d.ts, --, --)) +export declare function __rest(t: any, propertyNames: string[]): any; +>__rest : Symbol(__rest, Decl(tslib.d.ts, --, --)) +>t : Symbol(t, Decl(tslib.d.ts, --, --)) +>propertyNames : Symbol(propertyNames, Decl(tslib.d.ts, --, --)) + export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : Symbol(__decorate, Decl(tslib.d.ts, --, --)) >decorators : Symbol(decorators, Decl(tslib.d.ts, --, --)) @@ -128,3 +133,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge >generator : Symbol(generator, Decl(tslib.d.ts, --, --)) >Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) +export declare function __generator(thisArg: any, body: Function): any; +>__generator : Symbol(__generator, Decl(tslib.d.ts, --, --)) +>thisArg : Symbol(thisArg, Decl(tslib.d.ts, --, --)) +>body : Symbol(body, Decl(tslib.d.ts, --, --)) +>Function : Symbol(Function, Decl(lib.d.ts, --, --), Decl(lib.d.ts, --, --)) + +export declare function __exportStar(m: any, exports: any): void; +>__exportStar : Symbol(__exportStar, Decl(tslib.d.ts, --, --)) +>m : Symbol(m, Decl(tslib.d.ts, --, --)) +>exports : Symbol(exports, Decl(tslib.d.ts, --, --)) + diff --git a/tests/baselines/reference/importHelpersInAmbientContext.types b/tests/baselines/reference/importHelpersInAmbientContext.types index 5f01f5b1617..9ae97effd8a 100644 --- a/tests/baselines/reference/importHelpersInAmbientContext.types +++ b/tests/baselines/reference/importHelpersInAmbientContext.types @@ -98,6 +98,11 @@ export declare function __assign(t: any, ...sources: any[]): any; >t : any >sources : any[] +export declare function __rest(t: any, propertyNames: string[]): any; +>__rest : (t: any, propertyNames: string[]) => any +>t : any +>propertyNames : string[] + export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; >__decorate : (decorators: Function[], target: any, key?: string | symbol, desc?: any) => any >decorators : Function[] @@ -128,3 +133,14 @@ export declare function __awaiter(thisArg: any, _arguments: any, P: Function, ge >generator : Function >Function : Function +export declare function __generator(thisArg: any, body: Function): any; +>__generator : (thisArg: any, body: Function) => any +>thisArg : any +>body : Function +>Function : Function + +export declare function __exportStar(m: any, exports: any): void; +>__exportStar : (m: any, exports: any) => void +>m : any +>exports : any + diff --git a/tests/baselines/reference/importHelpersNoHelpers.errors.txt b/tests/baselines/reference/importHelpersNoHelpers.errors.txt index a0c089a9ddc..4034fbc649b 100644 --- a/tests/baselines/reference/importHelpersNoHelpers.errors.txt +++ b/tests/baselines/reference/importHelpersNoHelpers.errors.txt @@ -1,12 +1,16 @@ -tests/cases/compiler/external.ts(2,16): error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'. -tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'. -tests/cases/compiler/external.ts(6,1): error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'. -tests/cases/compiler/external.ts(8,12): error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'. -tests/cases/compiler/external.ts(13,13): error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'. -tests/cases/compiler/external.ts(14,12): error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'. +tests/cases/compiler/external.ts(1,1): error TS2343: This syntax requires an imported helper named '__exportStar', but module 'tslib' has no exported member '__exportStar'. +tests/cases/compiler/external.ts(3,16): error TS2343: This syntax requires an imported helper named '__extends', but module 'tslib' has no exported member '__extends'. +tests/cases/compiler/external.ts(7,1): error TS2343: This syntax requires an imported helper named '__decorate', but module 'tslib' has no exported member '__decorate'. +tests/cases/compiler/external.ts(7,1): error TS2343: This syntax requires an imported helper named '__metadata', but module 'tslib' has no exported member '__metadata'. +tests/cases/compiler/external.ts(9,12): error TS2343: This syntax requires an imported helper named '__param', but module 'tslib' has no exported member '__param'. +tests/cases/compiler/external.ts(14,13): error TS2343: This syntax requires an imported helper named '__assign', but module 'tslib' has no exported member '__assign'. +tests/cases/compiler/external.ts(15,12): error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'. -==== tests/cases/compiler/external.ts (6 errors) ==== +==== tests/cases/compiler/external.ts (7 errors) ==== + export * from "./other"; + ~~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2343: This syntax requires an imported helper named '__exportStar', but module 'tslib' has no exported member '__exportStar'. export class A { } export class B extends A { } ~~~~~~~~~ @@ -34,6 +38,9 @@ tests/cases/compiler/external.ts(14,12): error TS2343: This syntax requires an i ~ !!! error TS2343: This syntax requires an imported helper named '__rest', but module 'tslib' has no exported member '__rest'. +==== tests/cases/compiler/other.ts (0 errors) ==== + export const x = 1; + ==== tests/cases/compiler/script.ts (0 errors) ==== class A { } class B extends A { } diff --git a/tests/baselines/reference/importHelpersNoHelpers.js b/tests/baselines/reference/importHelpersNoHelpers.js index 9e20fc13543..ec1b21d797c 100644 --- a/tests/baselines/reference/importHelpersNoHelpers.js +++ b/tests/baselines/reference/importHelpersNoHelpers.js @@ -1,6 +1,7 @@ //// [tests/cases/compiler/importHelpersNoHelpers.ts] //// //// [external.ts] +export * from "./other"; export class A { } export class B extends A { } @@ -16,6 +17,9 @@ const o = { a: 1 }; const y = { ...o }; const { ...x } = y; +//// [other.ts] +export const x = 1; + //// [script.ts] class A { } class B extends A { } @@ -32,10 +36,15 @@ class C { export {} +//// [other.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.x = 1; //// [external.js] "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); +tslib_1.__exportStar(require("./other"), exports); var A = (function () { function A() { } diff --git a/tests/baselines/reference/importHelpersSystem.js b/tests/baselines/reference/importHelpersSystem.js index b7c10ee3c34..fbd0f5e589f 100644 --- a/tests/baselines/reference/importHelpersSystem.js +++ b/tests/baselines/reference/importHelpersSystem.js @@ -5,6 +5,7 @@ export class A { } //// [b.ts] import { A } from "./a"; +export * from "./a"; export class B extends A { } //// [tslib.d.ts] @@ -38,6 +39,16 @@ System.register(["tslib", "./a"], function (exports_1, context_1) { "use strict"; var __moduleName = context_1 && context_1.id; var tslib_1, a_1, B; + var exportedNames_1 = { + "B": true + }; + function exportStar_1(m) { + var exports = {}; + for (var n in m) { + if (n !== "default" && !exportedNames_1.hasOwnProperty(n)) exports[n] = m[n]; + } + exports_1(exports); + } return { setters: [ function (tslib_1_1) { @@ -45,6 +56,7 @@ System.register(["tslib", "./a"], function (exports_1, context_1) { }, function (a_1_1) { a_1 = a_1_1; + exportStar_1(a_1_1); } ], execute: function () { diff --git a/tests/baselines/reference/importHelpersSystem.symbols b/tests/baselines/reference/importHelpersSystem.symbols index 47528a8bba6..d7d588a67ef 100644 --- a/tests/baselines/reference/importHelpersSystem.symbols +++ b/tests/baselines/reference/importHelpersSystem.symbols @@ -6,8 +6,9 @@ export class A { } import { A } from "./a"; >A : Symbol(A, Decl(b.ts, 0, 8)) +export * from "./a"; export class B extends A { } ->B : Symbol(B, Decl(b.ts, 0, 24)) +>B : Symbol(B, Decl(b.ts, 1, 20)) >A : Symbol(A, Decl(b.ts, 0, 8)) === tests/cases/compiler/tslib.d.ts === diff --git a/tests/baselines/reference/importHelpersSystem.types b/tests/baselines/reference/importHelpersSystem.types index 9ff756ffaab..de9ef3e9446 100644 --- a/tests/baselines/reference/importHelpersSystem.types +++ b/tests/baselines/reference/importHelpersSystem.types @@ -6,6 +6,7 @@ export class A { } import { A } from "./a"; >A : typeof A +export * from "./a"; export class B extends A { } >B : B >A : A diff --git a/tests/baselines/reference/jsSelfReferencingArgumentsFunction.symbols b/tests/baselines/reference/jsSelfReferencingArgumentsFunction.symbols new file mode 100644 index 00000000000..e4fe336575c --- /dev/null +++ b/tests/baselines/reference/jsSelfReferencingArgumentsFunction.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/foo.js === +// Test #16139 +function Foo() { +>Foo : Symbol(Foo, Decl(foo.js, 0, 0)) + + arguments; +>arguments : Symbol(arguments) + + return new Foo(); +>Foo : Symbol(Foo, Decl(foo.js, 0, 0)) +} + diff --git a/tests/baselines/reference/jsSelfReferencingArgumentsFunction.types b/tests/baselines/reference/jsSelfReferencingArgumentsFunction.types new file mode 100644 index 00000000000..cab51cbafc1 --- /dev/null +++ b/tests/baselines/reference/jsSelfReferencingArgumentsFunction.types @@ -0,0 +1,13 @@ +=== tests/cases/compiler/foo.js === +// Test #16139 +function Foo() { +>Foo : (...args: any[]) => any + + arguments; +>arguments : IArguments + + return new Foo(); +>new Foo() : any +>Foo : (...args: any[]) => any +} + diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt index 5fb1e89c2e3..5aad982dc20 100644 --- a/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.errors.txt @@ -1,18 +1,32 @@ tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(1,5): error TS2322: Type '""' is not assignable to type 'object & string'. Type '""' is not assignable to type 'object'. -tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(3,1): error TS2322: Type 'string' is not assignable to type 'object & string'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(3,5): error TS2322: Type '123' is not assignable to type 'object & {}'. + Type '123' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(4,1): error TS2322: Type 'string' is not assignable to type 'object & string'. Type 'string' is not assignable to type 'object'. +tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts(8,38): error TS2322: Type '{ bar: string; }' is not assignable to type 'object & { err: string; }'. + Object literal may only specify known properties, and 'bar' does not exist in type 'object & { err: string; }'. -==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts (2 errors) ==== +==== tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts (4 errors) ==== var a: object & string = ""; // error ~ !!! error TS2322: Type '""' is not assignable to type 'object & string'. !!! error TS2322: Type '""' is not assignable to type 'object'. var b: object | string = ""; // ok + var c: object & {} = 123; // error + ~ +!!! error TS2322: Type '123' is not assignable to type 'object & {}'. +!!! error TS2322: Type '123' is not assignable to type 'object'. a = b; // error ~ !!! error TS2322: Type 'string' is not assignable to type 'object & string'. !!! error TS2322: Type 'string' is not assignable to type 'object'. b = a; // ok + + const foo: object & {} = {bar: 'bar'}; // ok + const bar: object & {err: string} = {bar: 'bar'}; // error + ~~~~~~~~~~ +!!! error TS2322: Type '{ bar: string; }' is not assignable to type 'object & { err: string; }'. +!!! error TS2322: Object literal may only specify known properties, and 'bar' does not exist in type 'object & { err: string; }'. \ No newline at end of file diff --git a/tests/baselines/reference/nonPrimitiveUnionIntersection.js b/tests/baselines/reference/nonPrimitiveUnionIntersection.js index 7f4b46c42ed..771024f15e6 100644 --- a/tests/baselines/reference/nonPrimitiveUnionIntersection.js +++ b/tests/baselines/reference/nonPrimitiveUnionIntersection.js @@ -1,17 +1,29 @@ //// [nonPrimitiveUnionIntersection.ts] var a: object & string = ""; // error var b: object | string = ""; // ok +var c: object & {} = 123; // error a = b; // error b = a; // ok + +const foo: object & {} = {bar: 'bar'}; // ok +const bar: object & {err: string} = {bar: 'bar'}; // error //// [nonPrimitiveUnionIntersection.js] var a = ""; // error var b = ""; // ok +var c = 123; // error a = b; // error b = a; // ok +var foo = { bar: 'bar' }; // ok +var bar = { bar: 'bar' }; // error //// [nonPrimitiveUnionIntersection.d.ts] declare var a: object & string; declare var b: object | string; +declare var c: object & {}; +declare const foo: object & {}; +declare const bar: object & { + err: string; +}; diff --git a/tests/baselines/reference/printerApi/printsNodeCorrectly.functionTypes.js b/tests/baselines/reference/printerApi/printsNodeCorrectly.functionTypes.js new file mode 100644 index 00000000000..5bfda3ba7c9 --- /dev/null +++ b/tests/baselines/reference/printerApi/printsNodeCorrectly.functionTypes.js @@ -0,0 +1 @@ +[args => any, (args) => any, (...args) => any, (args?) => any, (args: any) => any, ({}) => any] \ No newline at end of file diff --git a/tests/baselines/reference/spreadUnion.symbols b/tests/baselines/reference/spreadUnion.symbols index 40a63d56d49..bef8f5522d7 100644 --- a/tests/baselines/reference/spreadUnion.symbols +++ b/tests/baselines/reference/spreadUnion.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/spreadUnion.ts === +=== tests/cases/conformance/types/spread/spreadUnion.ts === var union: { a: number } | { b: string }; >union : Symbol(union, Decl(spreadUnion.ts, 0, 3)) >a : Symbol(a, Decl(spreadUnion.ts, 0, 12)) diff --git a/tests/baselines/reference/spreadUnion.types b/tests/baselines/reference/spreadUnion.types index 9e5ac1cffd5..fb1ef5f2018 100644 --- a/tests/baselines/reference/spreadUnion.types +++ b/tests/baselines/reference/spreadUnion.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/spreadUnion.ts === +=== tests/cases/conformance/types/spread/spreadUnion.ts === var union: { a: number } | { b: string }; >union : { a: number; } | { b: string; } >a : number diff --git a/tests/baselines/reference/spreadUnion2.js b/tests/baselines/reference/spreadUnion2.js index b98046463c3..6e49770617a 100644 --- a/tests/baselines/reference/spreadUnion2.js +++ b/tests/baselines/reference/spreadUnion2.js @@ -3,25 +3,25 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; -var o1: { a: number }; +var o1: {} | { a: number }; var o1 = { ...undefinedUnion }; -var o2: { b: number }; +var o2: {} | { b: number }; var o2 = { ...nullUnion }; -var o3: { a: number, b: number }; +var o3: {} | { b: number } | { a: number } | { a: number, b: number }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: { a: number }; +var o4: {} | { a: number }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: { b: number }; +var o5: {} | { b: number }; var o5 = { ...nullUnion, ...nullUnion }; -var o6: { }; var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; -var o6 = { ...nullAndUndefinedUnion }; +var o7 = { ...nullAndUndefinedUnion }; + //// [spreadUnion2.js] var __assign = (this && this.__assign) || Object.assign || function(t) { @@ -43,6 +43,5 @@ var o4; var o4 = __assign({}, undefinedUnion, undefinedUnion); var o5; var o5 = __assign({}, nullUnion, nullUnion); -var o6; var o6 = __assign({}, nullAndUndefinedUnion, nullAndUndefinedUnion); -var o6 = __assign({}, nullAndUndefinedUnion); +var o7 = __assign({}, nullAndUndefinedUnion); diff --git a/tests/baselines/reference/spreadUnion2.symbols b/tests/baselines/reference/spreadUnion2.symbols index 05703fc32bd..c4d1f19b6d9 100644 --- a/tests/baselines/reference/spreadUnion2.symbols +++ b/tests/baselines/reference/spreadUnion2.symbols @@ -1,4 +1,4 @@ -=== tests/cases/compiler/spreadUnion2.ts === +=== tests/cases/conformance/types/spread/spreadUnion2.ts === declare const undefinedUnion: { a: number } | undefined; >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >a : Symbol(a, Decl(spreadUnion2.ts, 0, 31)) @@ -10,26 +10,28 @@ declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; >nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) -var o1: { a: number }; +var o1: {} | { a: number }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 4, 9)) +>a : Symbol(a, Decl(spreadUnion2.ts, 4, 14)) var o1 = { ...undefinedUnion }; >o1 : Symbol(o1, Decl(spreadUnion2.ts, 4, 3), Decl(spreadUnion2.ts, 5, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o2: { b: number }; +var o2: {} | { b: number }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 7, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 7, 14)) var o2 = { ...nullUnion }; >o2 : Symbol(o2, Decl(spreadUnion2.ts, 7, 3), Decl(spreadUnion2.ts, 8, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) -var o3: { a: number, b: number }; +var o3: {} | { b: number } | { a: number } | { a: number, b: number }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 10, 9)) ->b : Symbol(b, Decl(spreadUnion2.ts, 10, 20)) +>b : Symbol(b, Decl(spreadUnion2.ts, 10, 14)) +>a : Symbol(a, Decl(spreadUnion2.ts, 10, 30)) +>a : Symbol(a, Decl(spreadUnion2.ts, 10, 46)) +>b : Symbol(b, Decl(spreadUnion2.ts, 10, 57)) var o3 = { ...undefinedUnion, ...nullUnion }; >o3 : Symbol(o3, Decl(spreadUnion2.ts, 10, 3), Decl(spreadUnion2.ts, 11, 3), Decl(spreadUnion2.ts, 12, 3)) @@ -41,33 +43,30 @@ var o3 = { ...nullUnion, ...undefinedUnion }; >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o4: { a: number }; +var o4: {} | { a: number }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) ->a : Symbol(a, Decl(spreadUnion2.ts, 14, 9)) +>a : Symbol(a, Decl(spreadUnion2.ts, 14, 14)) var o4 = { ...undefinedUnion, ...undefinedUnion }; >o4 : Symbol(o4, Decl(spreadUnion2.ts, 14, 3), Decl(spreadUnion2.ts, 15, 3)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) >undefinedUnion : Symbol(undefinedUnion, Decl(spreadUnion2.ts, 0, 13)) -var o5: { b: number }; +var o5: {} | { b: number }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) ->b : Symbol(b, Decl(spreadUnion2.ts, 17, 9)) +>b : Symbol(b, Decl(spreadUnion2.ts, 17, 14)) var o5 = { ...nullUnion, ...nullUnion }; >o5 : Symbol(o5, Decl(spreadUnion2.ts, 17, 3), Decl(spreadUnion2.ts, 18, 3)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) >nullUnion : Symbol(nullUnion, Decl(spreadUnion2.ts, 1, 13)) -var o6: { }; ->o6 : Symbol(o6, Decl(spreadUnion2.ts, 20, 3), Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3)) - var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ->o6 : Symbol(o6, Decl(spreadUnion2.ts, 20, 3), Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3)) +>o6 : Symbol(o6, Decl(spreadUnion2.ts, 20, 3)) >nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) >nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) -var o6 = { ...nullAndUndefinedUnion }; ->o6 : Symbol(o6, Decl(spreadUnion2.ts, 20, 3), Decl(spreadUnion2.ts, 21, 3), Decl(spreadUnion2.ts, 22, 3)) +var o7 = { ...nullAndUndefinedUnion }; +>o7 : Symbol(o7, Decl(spreadUnion2.ts, 21, 3)) >nullAndUndefinedUnion : Symbol(nullAndUndefinedUnion, Decl(spreadUnion2.ts, 2, 13)) diff --git a/tests/baselines/reference/spreadUnion2.types b/tests/baselines/reference/spreadUnion2.types index 97fbb9838c7..ea3364f296b 100644 --- a/tests/baselines/reference/spreadUnion2.types +++ b/tests/baselines/reference/spreadUnion2.types @@ -1,4 +1,4 @@ -=== tests/cases/compiler/spreadUnion2.ts === +=== tests/cases/conformance/types/spread/spreadUnion2.ts === declare const undefinedUnion: { a: number } | undefined; >undefinedUnion : { a: number; } | undefined >a : number @@ -12,72 +12,71 @@ declare const nullAndUndefinedUnion: null | undefined; >nullAndUndefinedUnion : null | undefined >null : null -var o1: { a: number }; ->o1 : { a: number; } +var o1: {} | { a: number }; +>o1 : {} | { a: number; } >a : number var o1 = { ...undefinedUnion }; ->o1 : { a: number; } ->{ ...undefinedUnion } : { a: number; } +>o1 : {} | { a: number; } +>{ ...undefinedUnion } : {} | { a: number; } >undefinedUnion : { a: number; } | undefined -var o2: { b: number }; ->o2 : { b: number; } +var o2: {} | { b: number }; +>o2 : {} | { b: number; } >b : number var o2 = { ...nullUnion }; ->o2 : { b: number; } ->{ ...nullUnion } : { b: number; } +>o2 : {} | { b: number; } +>{ ...nullUnion } : {} | { b: number; } >nullUnion : { b: number; } | null -var o3: { a: number, b: number }; ->o3 : { a: number; b: number; } +var o3: {} | { b: number } | { a: number } | { a: number, b: number }; +>o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } +>b : number +>a : number >a : number >b : number var o3 = { ...undefinedUnion, ...nullUnion }; ->o3 : { a: number; b: number; } ->{ ...undefinedUnion, ...nullUnion } : { b: number; a: number; } +>o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } +>{ ...undefinedUnion, ...nullUnion } : {} | { b: number; } | { a: number; } | { b: number; a: number; } >undefinedUnion : { a: number; } | undefined >nullUnion : { b: number; } | null var o3 = { ...nullUnion, ...undefinedUnion }; ->o3 : { a: number; b: number; } ->{ ...nullUnion, ...undefinedUnion } : { a: number; b: number; } +>o3 : {} | { b: number; } | { a: number; } | { a: number; b: number; } +>{ ...nullUnion, ...undefinedUnion } : {} | { a: number; } | { b: number; } | { a: number; b: number; } >nullUnion : { b: number; } | null >undefinedUnion : { a: number; } | undefined -var o4: { a: number }; ->o4 : { a: number; } +var o4: {} | { a: number }; +>o4 : {} | { a: number; } >a : number var o4 = { ...undefinedUnion, ...undefinedUnion }; ->o4 : { a: number; } ->{ ...undefinedUnion, ...undefinedUnion } : { a: number; } +>o4 : {} | { a: number; } +>{ ...undefinedUnion, ...undefinedUnion } : {} | { a: number; } | { a: number; } | { a: number; } >undefinedUnion : { a: number; } | undefined >undefinedUnion : { a: number; } | undefined -var o5: { b: number }; ->o5 : { b: number; } +var o5: {} | { b: number }; +>o5 : {} | { b: number; } >b : number var o5 = { ...nullUnion, ...nullUnion }; ->o5 : { b: number; } ->{ ...nullUnion, ...nullUnion } : { b: number; } +>o5 : {} | { b: number; } +>{ ...nullUnion, ...nullUnion } : {} | { b: number; } | { b: number; } | { b: number; } >nullUnion : { b: number; } | null >nullUnion : { b: number; } | null -var o6: { }; ->o6 : {} - var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; ->o6 : {} ->{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} +>o6 : {} | {} | {} | {} +>{ ...nullAndUndefinedUnion, ...nullAndUndefinedUnion } : {} | {} | {} | {} >nullAndUndefinedUnion : null | undefined >nullAndUndefinedUnion : null | undefined -var o6 = { ...nullAndUndefinedUnion }; ->o6 : {} ->{ ...nullAndUndefinedUnion } : {} +var o7 = { ...nullAndUndefinedUnion }; +>o7 : {} | {} +>{ ...nullAndUndefinedUnion } : {} | {} >nullAndUndefinedUnion : null | undefined diff --git a/tests/baselines/reference/spreadUnion3.errors.txt b/tests/baselines/reference/spreadUnion3.errors.txt new file mode 100644 index 00000000000..5f5b620685c --- /dev/null +++ b/tests/baselines/reference/spreadUnion3.errors.txt @@ -0,0 +1,31 @@ +tests/cases/conformance/types/spread/spreadUnion3.ts(2,5): error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. + Type '{ y: number; }' is not assignable to type '{ y: string; }'. + Types of property 'y' are incompatible. + Type 'number' is not assignable to type 'string'. +tests/cases/conformance/types/spread/spreadUnion3.ts(9,23): error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. + Property 'a' does not exist on type '{}'. + + +==== tests/cases/conformance/types/spread/spreadUnion3.ts (2 errors) ==== + function f(x: { y: string } | undefined): { y: string } { + return { y: 123, ...x } // y: string | number + ~~~~~~~~~~~~~~~~~~~~~~~ +!!! error TS2322: Type '{ y: number; } | { y: string; }' is not assignable to type '{ y: string; }'. +!!! error TS2322: Type '{ y: number; }' is not assignable to type '{ y: string; }'. +!!! error TS2322: Types of property 'y' are incompatible. +!!! error TS2322: Type 'number' is not assignable to type 'string'. + } + f(undefined) + + + function g(t?: { a: number } | null): void { + let b = { ...t }; + let c: number = b.a; // might not have 'a' + ~ +!!! error TS2339: Property 'a' does not exist on type '{} | {} | { a: number; }'. +!!! error TS2339: Property 'a' does not exist on type '{}'. + } + g() + g(undefined) + g(null) + \ No newline at end of file diff --git a/tests/baselines/reference/spreadUnion3.js b/tests/baselines/reference/spreadUnion3.js new file mode 100644 index 00000000000..2aaf9efeb78 --- /dev/null +++ b/tests/baselines/reference/spreadUnion3.js @@ -0,0 +1,36 @@ +//// [spreadUnion3.ts] +function f(x: { y: string } | undefined): { y: string } { + return { y: 123, ...x } // y: string | number +} +f(undefined) + + +function g(t?: { a: number } | null): void { + let b = { ...t }; + let c: number = b.a; // might not have 'a' +} +g() +g(undefined) +g(null) + + +//// [spreadUnion3.js] +var __assign = (this && this.__assign) || Object.assign || function(t) { + for (var s, i = 1, n = arguments.length; i < n; i++) { + s = arguments[i]; + for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) + t[p] = s[p]; + } + return t; +}; +function f(x) { + return __assign({ y: 123 }, x); // y: string | number +} +f(undefined); +function g(t) { + var b = __assign({}, t); + var c = b.a; // might not have 'a' +} +g(); +g(undefined); +g(null); diff --git a/tests/baselines/reference/symbolMergeValueAndImportedType.js b/tests/baselines/reference/symbolMergeValueAndImportedType.js new file mode 100644 index 00000000000..70da47268d5 --- /dev/null +++ b/tests/baselines/reference/symbolMergeValueAndImportedType.js @@ -0,0 +1,17 @@ +//// [tests/cases/compiler/symbolMergeValueAndImportedType.ts] //// + +//// [main.ts] +import { X } from "./other"; +const X = 42; +console.log('X is ' + X); +//// [other.ts] +export type X = {}; + +//// [other.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +//// [main.js] +"use strict"; +Object.defineProperty(exports, "__esModule", { value: true }); +const X = 42; +console.log('X is ' + X); diff --git a/tests/baselines/reference/symbolMergeValueAndImportedType.symbols b/tests/baselines/reference/symbolMergeValueAndImportedType.symbols new file mode 100644 index 00000000000..7e1422faa46 --- /dev/null +++ b/tests/baselines/reference/symbolMergeValueAndImportedType.symbols @@ -0,0 +1,17 @@ +=== tests/cases/compiler/main.ts === +import { X } from "./other"; +>X : Symbol(X, Decl(main.ts, 0, 8), Decl(main.ts, 1, 5)) + +const X = 42; +>X : Symbol(X, Decl(main.ts, 0, 8), Decl(main.ts, 1, 5)) + +console.log('X is ' + X); +>console.log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>console : Symbol(console, Decl(lib.dom.d.ts, --, --)) +>log : Symbol(Console.log, Decl(lib.dom.d.ts, --, --)) +>X : Symbol(X, Decl(main.ts, 0, 8), Decl(main.ts, 1, 5)) + +=== tests/cases/compiler/other.ts === +export type X = {}; +>X : Symbol(X, Decl(other.ts, 0, 0)) + diff --git a/tests/baselines/reference/symbolMergeValueAndImportedType.types b/tests/baselines/reference/symbolMergeValueAndImportedType.types new file mode 100644 index 00000000000..a7dc72ab0b6 --- /dev/null +++ b/tests/baselines/reference/symbolMergeValueAndImportedType.types @@ -0,0 +1,21 @@ +=== tests/cases/compiler/main.ts === +import { X } from "./other"; +>X : 42 + +const X = 42; +>X : 42 +>42 : 42 + +console.log('X is ' + X); +>console.log('X is ' + X) : void +>console.log : (message?: any, ...optionalParams: any[]) => void +>console : Console +>log : (message?: any, ...optionalParams: any[]) => void +>'X is ' + X : string +>'X is ' : "X is " +>X : 42 + +=== tests/cases/compiler/other.ts === +export type X = {}; +>X : X + diff --git a/tests/cases/compiler/argumentsObjectCreatesRestForJs.ts b/tests/cases/compiler/argumentsObjectCreatesRestForJs.ts new file mode 100644 index 00000000000..4c3ca335d1d --- /dev/null +++ b/tests/cases/compiler/argumentsObjectCreatesRestForJs.ts @@ -0,0 +1,20 @@ +// @checkJs: true +// @allowJs: true +// @Filename: main.js +// @noemit: true +function allRest() { arguments; } +allRest(); +allRest(1, 2, 3); +function someRest(x, y) { arguments; } +someRest(); // x and y are still optional because they are in a JS file +someRest(1, 2, 3); + +/** + * @param {number} x - a thing + */ +function jsdocced(x) { arguments; } +jsdocced(1); + +function dontDoubleRest(x, ...y) { arguments; } +dontDoubleRest(1, 2, 3); + diff --git a/tests/cases/compiler/importHelpersAmd.ts b/tests/cases/compiler/importHelpersAmd.ts index bef63328d52..38b02424b96 100644 --- a/tests/cases/compiler/importHelpersAmd.ts +++ b/tests/cases/compiler/importHelpersAmd.ts @@ -6,12 +6,16 @@ export class A { } // @filename: b.ts import { A } from "./a"; +export * from "./a"; export class B extends A { } // @filename: tslib.d.ts export declare function __extends(d: Function, b: Function): void; export declare function __assign(t: any, ...sources: any[]): any; +export declare function __rest(t: any, propertyNames: string[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +export declare function __generator(thisArg: any, body: Function): any; +export declare function __exportStar(m: any, exports: any): void; \ No newline at end of file diff --git a/tests/cases/compiler/importHelpersInAmbientContext.ts b/tests/cases/compiler/importHelpersInAmbientContext.ts index 8bfa5b25404..340961802a3 100644 --- a/tests/cases/compiler/importHelpersInAmbientContext.ts +++ b/tests/cases/compiler/importHelpersInAmbientContext.ts @@ -49,7 +49,10 @@ declare namespace N { // @filename: tslib.d.ts export declare function __extends(d: Function, b: Function): void; export declare function __assign(t: any, ...sources: any[]): any; +export declare function __rest(t: any, propertyNames: string[]): any; export declare function __decorate(decorators: Function[], target: any, key?: string | symbol, desc?: any): any; export declare function __param(paramIndex: number, decorator: Function): Function; export declare function __metadata(metadataKey: any, metadataValue: any): Function; export declare function __awaiter(thisArg: any, _arguments: any, P: Function, generator: Function): any; +export declare function __generator(thisArg: any, body: Function): any; +export declare function __exportStar(m: any, exports: any): void; \ No newline at end of file diff --git a/tests/cases/compiler/importHelpersNoHelpers.ts b/tests/cases/compiler/importHelpersNoHelpers.ts index 4ab48aba7df..787058890a2 100644 --- a/tests/cases/compiler/importHelpersNoHelpers.ts +++ b/tests/cases/compiler/importHelpersNoHelpers.ts @@ -5,6 +5,7 @@ // @experimentalDecorators: true // @emitDecoratorMetadata: true // @filename: external.ts +export * from "./other"; export class A { } export class B extends A { } @@ -20,6 +21,9 @@ const o = { a: 1 }; const y = { ...o }; const { ...x } = y; +// @filename: other.ts +export const x = 1; + // @filename: script.ts class A { } class B extends A { } diff --git a/tests/cases/compiler/importHelpersSystem.ts b/tests/cases/compiler/importHelpersSystem.ts index 5b6081f17f3..87e62785708 100644 --- a/tests/cases/compiler/importHelpersSystem.ts +++ b/tests/cases/compiler/importHelpersSystem.ts @@ -6,6 +6,7 @@ export class A { } // @filename: b.ts import { A } from "./a"; +export * from "./a"; export class B extends A { } // @filename: tslib.d.ts diff --git a/tests/cases/compiler/jsSelfReferencingArgumentsFunction.ts b/tests/cases/compiler/jsSelfReferencingArgumentsFunction.ts new file mode 100644 index 00000000000..386b88c9cd1 --- /dev/null +++ b/tests/cases/compiler/jsSelfReferencingArgumentsFunction.ts @@ -0,0 +1,8 @@ +// @Filename: foo.js +// @noEmit: true +// @allowJs: true +// Test #16139 +function Foo() { + arguments; + return new Foo(); +} diff --git a/tests/cases/compiler/symbolMergeValueAndImportedType.ts b/tests/cases/compiler/symbolMergeValueAndImportedType.ts new file mode 100644 index 00000000000..4779ff22e9d --- /dev/null +++ b/tests/cases/compiler/symbolMergeValueAndImportedType.ts @@ -0,0 +1,9 @@ +// @target: es2015 +// @module: commonjs +// @lib: es2015,dom +// @filename: main.ts +import { X } from "./other"; +const X = 42; +console.log('X is ' + X); +// @filename: other.ts +export type X = {}; \ No newline at end of file diff --git a/tests/cases/conformance/salsa/constructorFunctions.ts b/tests/cases/conformance/salsa/constructorFunctions.ts new file mode 100644 index 00000000000..4f1a0368244 --- /dev/null +++ b/tests/cases/conformance/salsa/constructorFunctions.ts @@ -0,0 +1,36 @@ +// @allowJs: true +// @checkJs: true +// @noEmit: true +// @filename: index.js + +function C1() { + if (!(this instanceof C1)) return new C1(); + this.x = 1; +} + +const c1_v1 = C1(); +const c1_v2 = new C1(); + +var C2 = function () { + if (!(this instanceof C2)) return new C2(); + this.x = 1; +}; + +const c2_v1 = C2(); +const c2_v2 = new C2(); + +/** @class */ +function C3() { + if (!(this instanceof C3)) return new C3(); +}; + +const c3_v1 = C3(); +const c3_v2 = new C3(); + +/** @class */ +var C4 = function () { + if (!(this instanceof C4)) return new C4(); +}; + +const c4_v1 = C4(); +const c4_v2 = new C4(); \ No newline at end of file diff --git a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts index a9d5872705c..55c1acb03b3 100644 --- a/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts +++ b/tests/cases/conformance/types/nonPrimitive/nonPrimitiveUnionIntersection.ts @@ -1,5 +1,9 @@ // @declaration: true var a: object & string = ""; // error var b: object | string = ""; // ok +var c: object & {} = 123; // error a = b; // error b = a; // ok + +const foo: object & {} = {bar: 'bar'}; // ok +const bar: object & {err: string} = {bar: 'bar'}; // error diff --git a/tests/cases/compiler/spreadUnion.ts b/tests/cases/conformance/types/spread/spreadUnion.ts similarity index 100% rename from tests/cases/compiler/spreadUnion.ts rename to tests/cases/conformance/types/spread/spreadUnion.ts diff --git a/tests/cases/compiler/spreadUnion2.ts b/tests/cases/conformance/types/spread/spreadUnion2.ts similarity index 67% rename from tests/cases/compiler/spreadUnion2.ts rename to tests/cases/conformance/types/spread/spreadUnion2.ts index 25dba81c0df..e2f72879915 100644 --- a/tests/cases/compiler/spreadUnion2.ts +++ b/tests/cases/conformance/types/spread/spreadUnion2.ts @@ -4,22 +4,21 @@ declare const undefinedUnion: { a: number } | undefined; declare const nullUnion: { b: number } | null; declare const nullAndUndefinedUnion: null | undefined; -var o1: { a: number }; +var o1: {} | { a: number }; var o1 = { ...undefinedUnion }; -var o2: { b: number }; +var o2: {} | { b: number }; var o2 = { ...nullUnion }; -var o3: { a: number, b: number }; +var o3: {} | { b: number } | { a: number } | { a: number, b: number }; var o3 = { ...undefinedUnion, ...nullUnion }; var o3 = { ...nullUnion, ...undefinedUnion }; -var o4: { a: number }; +var o4: {} | { a: number }; var o4 = { ...undefinedUnion, ...undefinedUnion }; -var o5: { b: number }; +var o5: {} | { b: number }; var o5 = { ...nullUnion, ...nullUnion }; -var o6: { }; var o6 = { ...nullAndUndefinedUnion, ...nullAndUndefinedUnion }; -var o6 = { ...nullAndUndefinedUnion }; \ No newline at end of file +var o7 = { ...nullAndUndefinedUnion }; diff --git a/tests/cases/conformance/types/spread/spreadUnion3.ts b/tests/cases/conformance/types/spread/spreadUnion3.ts new file mode 100644 index 00000000000..c16acbdf7d3 --- /dev/null +++ b/tests/cases/conformance/types/spread/spreadUnion3.ts @@ -0,0 +1,14 @@ +// @strictNullChecks: true +function f(x: { y: string } | undefined): { y: string } { + return { y: 123, ...x } // y: string | number +} +f(undefined) + + +function g(t?: { a: number } | null): void { + let b = { ...t }; + let c: number = b.a; // might not have 'a' +} +g() +g(undefined) +g(null) diff --git a/tests/cases/conformance/types/typeRelationships/typeInference/genericContextualTypes1.ts b/tests/cases/conformance/types/typeRelationships/typeInference/genericContextualTypes1.ts new file mode 100644 index 00000000000..6d937adcbf6 --- /dev/null +++ b/tests/cases/conformance/types/typeRelationships/typeInference/genericContextualTypes1.ts @@ -0,0 +1,52 @@ +// @strict: true +// @declaration: true + +type Box = { value: T }; + +declare function wrap(f: (a: A) => B): (a: A) => B; + +declare function compose(f: (a: A) => B, g: (b: B) => C): (a: A) => C; + +declare function list(a: T): T[]; + +declare function unlist(a: T[]): T; + +declare function box(x: V): Box; + +declare function unbox(x: Box): W; + +declare function map(a: T[], f: (x: T) => U): U[]; + +declare function identity(x: T): T; + +declare function zip(a: A, b: B): [A, B]; + +declare function flip(f: (x: X, y: Y) => Z): (y: Y, x: X) => Z; + +const f00: (x: A) => A[] = list; +const f01: (x: A) => A[] = x => [x]; +const f02: (x: A) => A[] = wrap(list); +const f03: (x: A) => A[] = wrap(x => [x]); + +const f10: (x: T) => Box = compose(a => list(a), b => box(b)); +const f11: (x: T) => Box = compose(list, box); +const f12: (x: Box) => T = compose(a => unbox(a), b => unlist(b)); +const f13: (x: Box) => T = compose(unbox, unlist); + +const arrayMap = (f: (x: T) => U) => (a: T[]) => a.map(f); +const arrayFilter = (f: (x: T) => boolean) => (a: T[]) => a.filter(f); + +const f20: (a: string[]) => number[] = arrayMap(x => x.length); +const f21: (a: A[]) => A[][] = arrayMap(x => [x]); +const f22: (a: A[]) => A[] = arrayMap(identity); +const f23: (a: A[]) => Box[] = arrayMap(value => ({ value })); + +const f30: (a: string[]) => string[] = arrayFilter(x => x.length > 10); +const f31: >(a: T[]) => T[] = arrayFilter(x => x.value > 10); + +const f40: (b: B, a: A) => [A, B] = flip(zip); + +// Repro from #16293 + +type fn = (a: A) => A; +const fn: fn = a => a; diff --git a/tests/cases/fourslash/commentsCommentParsing.ts b/tests/cases/fourslash/commentsCommentParsing.ts index ce80fd519dd..f26d2f569f8 100644 --- a/tests/cases/fourslash/commentsCommentParsing.ts +++ b/tests/cases/fourslash/commentsCommentParsing.ts @@ -160,8 +160,8 @@ ////fo/*37q*/oBar(/*37*/"foo",/*38*/"bar"); /////** This is a comment */ ////var x; -/////** -//// * This is a comment +/////** +//// * This is a comment //// */ ////var y; /////** this is jsdoc style function with param tag as well as inline parameter help @@ -173,7 +173,7 @@ ////} /////*44*/jsD/*40q*/ocParamTest(/*40*/30, /*41*/40, /*42*/50, /*43*/60); /////** This is function comment -//// * And properly aligned comment +//// * And properly aligned comment //// */ ////function jsDocCommentAlignmentTest1() { ////} @@ -334,39 +334,40 @@ goTo.marker('27'); verify.completionListContains("multiply", "function multiply(a: number, b: number, c?: number, d?: any, e?: any): void", "This is multiplication function"); verify.completionListContains("f1", "function f1(a: number): any (+1 overload)", "fn f1 with number"); +const subtractDoc = "This is subtract function"; goTo.marker('28'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfos({ "28q": [ "function subtract(a: number, b: number, c?: () => string, d?: () => string, e?: () => string, f?: () => string): void", - "This is subtract function{ () => string; } } f this is optional param f" + subtractDoc, ], "28aq": "(parameter) a: number" }); goTo.marker('29'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs("this is about b"); verify.quickInfoAt("29aq", "(parameter) b: number", "this is about b"); goTo.marker('30'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs("this is optional param c"); verify.quickInfoAt("30aq", "(parameter) c: () => string", "this is optional param c"); goTo.marker('31'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs("this is optional param d"); verify.quickInfoAt("31aq", "(parameter) d: () => string", "this is optional param d"); goTo.marker('32'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs("this is optional param e"); verify.quickInfoAt("32aq", "(parameter) e: () => string", "this is optional param e"); goTo.marker('33'); -verify.currentSignatureHelpDocCommentIs("This is subtract function{ () => string; } } f this is optional param f"); +verify.currentSignatureHelpDocCommentIs(subtractDoc); verify.currentParameterHelpArgumentDocCommentIs(""); verify.quickInfoAt("33aq", "(parameter) f: () => string"); @@ -454,11 +455,11 @@ verify.quickInfoAt("43aq", "(parameter) d: number"); goTo.marker('44'); verify.completionListContains("jsDocParamTest", "function jsDocParamTest(a: number, b: number, c: number, d: number): number", "this is jsdoc style function with param tag as well as inline parameter help"); verify.completionListContains("x", "var x: any", "This is a comment "); -verify.completionListContains("y", "var y: any", "This is a comment "); +verify.completionListContains("y", "var y: any", "This is a comment"); goTo.marker('45'); -verify.currentSignatureHelpDocCommentIs("This is function comment\nAnd properly aligned comment "); -verify.quickInfoAt("45q", "function jsDocCommentAlignmentTest1(): void", "This is function comment\nAnd properly aligned comment "); +verify.currentSignatureHelpDocCommentIs("This is function comment\nAnd properly aligned comment"); +verify.quickInfoAt("45q", "function jsDocCommentAlignmentTest1(): void", "This is function comment\nAnd properly aligned comment"); goTo.marker('46'); verify.currentSignatureHelpDocCommentIs("This is function comment\n And aligned with 4 space char margin"); diff --git a/tests/cases/fourslash/contextualTypingOfGenericCallSignatures2.ts b/tests/cases/fourslash/contextualTypingOfGenericCallSignatures2.ts index 0f610a2a539..efb26cb3af1 100644 --- a/tests/cases/fourslash/contextualTypingOfGenericCallSignatures2.ts +++ b/tests/cases/fourslash/contextualTypingOfGenericCallSignatures2.ts @@ -7,5 +7,5 @@ ////// x should not be contextually typed so this should be an error ////f6(/**/x => x()) -verify.quickInfoAt("", "(parameter) x: any"); +verify.quickInfoAt("", "(parameter) x: T extends I"); verify.numberOfErrorsInCurrentFile(1); diff --git a/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts b/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts index a33e2cc5e7a..bfc4d7ea6fd 100644 --- a/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts +++ b/tests/cases/fourslash/contextuallyTypedFunctionExpressionGeneric1.ts @@ -1,17 +1,17 @@ /// ////interface Comparable { -//// compareTo(other: T): T; +//// compareTo(other: T): T; ////} ////interface Comparer { -//// >(x: T, y: T): T; +//// >(x: T, y: T): T; ////} ////var max2: Comparer = (x/*1*/x, y/*2*/y) => { return x/*3*/x.compareTo(y/*4*/y) }; verify.quickInfos({ - 1: "(parameter) xx: any", - 2: "(parameter) yy: any", - 3: "(parameter) xx: any", - 4: "(parameter) yy: any" + 1: "(parameter) xx: T extends Comparable", + 2: "(parameter) yy: T extends Comparable", + 3: "(parameter) xx: T extends Comparable", + 4: "(parameter) yy: T extends Comparable" }); diff --git a/tests/cases/fourslash/convertFunctionToEs6Class1.ts b/tests/cases/fourslash/convertFunctionToEs6Class1.ts index 6275e48e627..51cc73fd64a 100644 --- a/tests/cases/fourslash/convertFunctionToEs6Class1.ts +++ b/tests/cases/fourslash/convertFunctionToEs6Class1.ts @@ -23,4 +23,4 @@ verify.fileAfterApplyingRefactorAtMarker('1', foo.prototype.instanceProp1 = "hello"; foo.prototype.instanceProp2 = undefined; foo.staticProp = "world"; -`, 'Convert to ES2015 class'); \ No newline at end of file +`, 'Convert to ES2015 class', 'convert'); \ No newline at end of file diff --git a/tests/cases/fourslash/convertFunctionToEs6Class2.ts b/tests/cases/fourslash/convertFunctionToEs6Class2.ts index 5d9a9f32585..d5ed277b452 100644 --- a/tests/cases/fourslash/convertFunctionToEs6Class2.ts +++ b/tests/cases/fourslash/convertFunctionToEs6Class2.ts @@ -24,4 +24,4 @@ verify.fileAfterApplyingRefactorAtMarker('4', foo.instanceProp1 = "hello"; foo.instanceProp2 = undefined; foo.staticProp = "world"; -`, 'Convert to ES2015 class'); +`, 'Convert to ES2015 class', 'convert'); diff --git a/tests/cases/fourslash/convertFunctionToEs6Class3.ts b/tests/cases/fourslash/convertFunctionToEs6Class3.ts index af8955dcb71..bb48ffadec2 100644 --- a/tests/cases/fourslash/convertFunctionToEs6Class3.ts +++ b/tests/cases/fourslash/convertFunctionToEs6Class3.ts @@ -25,4 +25,4 @@ class foo { foo.prototype.instanceProp1 = "hello"; foo.prototype.instanceProp2 = undefined; foo.staticProp = "world"; -`, 'Convert to ES2015 class'); \ No newline at end of file +`, 'Convert to ES2015 class', 'convert'); \ No newline at end of file diff --git a/tests/cases/fourslash/findAllRefsClassExpression0.ts b/tests/cases/fourslash/findAllRefsClassExpression0.ts new file mode 100644 index 00000000000..50abfae0230 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsClassExpression0.ts @@ -0,0 +1,16 @@ +/// + +// @Filename: /a.ts +////export = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] { +//// m() { [|A|]; } +////}; + +// @Filename: /b.ts +////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a"); +////[|A|]; + +const [r0, r1, r2, r3] = test.ranges(); +const defs = { definition: "(local class) A", ranges: [r0, r1] }; +const imports = { definition: 'import A = require("./a")', ranges: [r2, r3] }; +verify.referenceGroups([r0, r1], [defs, imports]); +verify.referenceGroups([r2, r3], [imports, defs]); diff --git a/tests/cases/fourslash/findAllRefsClassExpression1.ts b/tests/cases/fourslash/findAllRefsClassExpression1.ts new file mode 100644 index 00000000000..bd581871842 --- /dev/null +++ b/tests/cases/fourslash/findAllRefsClassExpression1.ts @@ -0,0 +1,17 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +////module.exports = class [|{| "isWriteAccess": true, "isDefinition": true |}A|] {}; + +// @Filename: /b.js +////import [|{| "isWriteAccess": true, "isDefinition": true |}A|] = require("./a"); +////[|A|]; + +const [r0, r1, r2] = test.ranges(); +const defs = { definition: "(local class) A", ranges: [r0] }; +const imports = { definition: 'import A = require("./a")', ranges: [r1, r2] }; +verify.referenceGroups([r0], [defs, imports]); +verify.referenceGroups([r1, r2], [imports, defs]); + diff --git a/tests/cases/fourslash/findAllRefsClassExpression2.ts b/tests/cases/fourslash/findAllRefsClassExpression2.ts new file mode 100644 index 00000000000..ce2fc8bbf3d --- /dev/null +++ b/tests/cases/fourslash/findAllRefsClassExpression2.ts @@ -0,0 +1,16 @@ +/// + +// @allowJs: true + +// @Filename: /a.js +////exports.[|{| "isWriteAccess": true, "isDefinition": true |}A|] = class {}; + +// @Filename: /b.js +////import { [|{| "isWriteAccess": true, "isDefinition": true |}A|] } from "./a"; +////[|A|]; + +const [r0, r1, r2] = test.ranges(); +const defs = { definition: "(property) A: typeof (Anonymous class)", ranges: [r0] }; +const imports = { definition: "import A", ranges: [r1, r2] }; +verify.referenceGroups([r0], [defs, imports]); +verify.referenceGroups([r1, r2], [imports, defs]); diff --git a/tests/cases/fourslash/fourslash.ts b/tests/cases/fourslash/fourslash.ts index 3e80b005625..928a9f0a0cd 100644 --- a/tests/cases/fourslash/fourslash.ts +++ b/tests/cases/fourslash/fourslash.ts @@ -236,8 +236,8 @@ declare namespace FourSlashInterface { noMatchingBracePositionInCurrentFile(bracePosition: number): void; DocCommentTemplate(expectedText: string, expectedOffset: number, empty?: boolean): void; noDocCommentTemplate(): void; - rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void - getAndApplyCodeFix(errorCode?: number, index?: number): void; + rangeAfterCodeFix(expectedText: string, includeWhiteSpace?: boolean, errorCode?: number, index?: number): void; + fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, actionName: string, formattingOptions?: FormatCodeOptions): void; rangeIs(expectedText: string, includeWhiteSpace?: boolean): void; fileAfterApplyingRefactorAtMarker(markerName: string, expectedContent: string, refactorNameToApply: string, formattingOptions?: FormatCodeOptions): void; importFixAtPosition(expectedTextArray: string[], errorCode?: number): void; diff --git a/tests/cases/fourslash/jsdocParameterNameCompletion.ts b/tests/cases/fourslash/jsdocParameterNameCompletion.ts new file mode 100644 index 00000000000..b379cb77135 --- /dev/null +++ b/tests/cases/fourslash/jsdocParameterNameCompletion.ts @@ -0,0 +1,29 @@ +/// + +/////** +//// * @param /*0*/ +//// */ +////function f(foo, bar) {} + +/////** +//// * @param foo +//// * @param /*1*/ +//// */ +////function g(foo, bar) {} + +/////** +//// * @param can/*2*/ +//// * @param cantaloupe +//// */ +////function h(cat, canary, canoodle, cantaloupe, zebra) {} + +/////** +//// * @param /*3*/ {string} /*4*/ +//// */ +////function i(foo, bar) {} + +verify.completionsAt("0", ["foo", "bar"]); +verify.completionsAt("1", ["bar"]); +verify.completionsAt("2", ["canary", "canoodle"]); +verify.completionsAt("3", ["foo", "bar"]); +verify.completionsAt("4", ["foo", "bar"]); diff --git a/tests/cases/fourslash/server/convertFunctionToEs6Class-server.ts b/tests/cases/fourslash/server/convertFunctionToEs6Class-server.ts index 9ab47086f20..5782b4a1f41 100644 --- a/tests/cases/fourslash/server/convertFunctionToEs6Class-server.ts +++ b/tests/cases/fourslash/server/convertFunctionToEs6Class-server.ts @@ -22,4 +22,4 @@ class fn { console.log('hello world'); } } -`, 'Convert to ES2015 class'); +`, 'Convert to ES2015 class', 'convert'); diff --git a/tests/cases/fourslash/signatureHelpCallExpressionJs.ts b/tests/cases/fourslash/signatureHelpCallExpressionJs.ts index e425196bd07..17045a74717 100644 --- a/tests/cases/fourslash/signatureHelpCallExpressionJs.ts +++ b/tests/cases/fourslash/signatureHelpCallExpressionJs.ts @@ -4,14 +4,25 @@ // @allowJs: true // @Filename: main.js -////function fnTest() { arguments; } -////fnTest(/*1*/); -////fnTest(1, 2, 3); +////function allOptional() { arguments; } +////allOptional(/*1*/); +////allOptional(1, 2, 3); +////function someOptional(x, y) { arguments; } +////someOptional(/*2*/); +////someOptional(1, 2, 3); +////someOptional(); // no error here; x and y are optional in JS goTo.marker('1'); verify.signatureHelpCountIs(1); verify.currentSignatureParameterCountIs(1); -verify.currentSignatureHelpIs('fnTest(...args: any[]): void'); +verify.currentSignatureHelpIs('allOptional(...args: any[]): void'); verify.currentParameterHelpArgumentNameIs('args'); verify.currentParameterSpanIs("...args: any[]"); -verify.numberOfErrorsInCurrentFile(0); \ No newline at end of file + +goTo.marker('2'); +verify.signatureHelpCountIs(1); +verify.currentSignatureParameterCountIs(3); +verify.currentSignatureHelpIs('someOptional(x: any, y: any, ...args: any[]): void'); +verify.currentParameterHelpArgumentNameIs('x'); +verify.currentParameterSpanIs("x: any"); +verify.numberOfErrorsInCurrentFile(0); diff --git a/tslint.json b/tslint.json index d3178915fe4..58106e52f0f 100644 --- a/tslint.json +++ b/tslint.json @@ -6,6 +6,7 @@ "comment-format": [true, "check-space" ], + "curly":[true, "ignore-same-line"], "indent": [true, "spaces" ],