diff --git a/packages/typescript/src/api/async/api.ts b/packages/typescript/src/api/async/api.ts index 29369a7392809..e7e20c2218681 100644 --- a/packages/typescript/src/api/async/api.ts +++ b/packages/typescript/src/api/async/api.ts @@ -2623,6 +2623,20 @@ export class Checker { return type.getNonNullableType(); } + /** + * Add `undefined` and/or `null` to a type, as indicated by `flags` (a combination of + * {@link TypeFlags.Undefined} and {@link TypeFlags.Null}). Always returns a type. + */ + async getNullableType(type: Type, flags: TypeFlags): Promise { + const data = await this.client.apiRequest("getNullableType", { + snapshot: this.snapshotId, + project: this.project.handle, + type: type.id, + flags, + }); + return this.objectRegistry.getOrCreateType(data); + } + /** * Get the type for a type node. Always returns a type; for type nodes whose * type cannot be determined the checker yields the error type (use @@ -2746,6 +2760,84 @@ export class Checker { async getNonPrimitiveType(): Promise { return this.getIntrinsicType("getNonPrimitiveType"); } + async getFalseType(): Promise { + return this.getIntrinsicType("getFalseType"); + } + async getTrueType(): Promise { + return this.getIntrinsicType("getTrueType"); + } + + /** Get (or create) the singleton type for a string literal value. Always returns a type. */ + async getStringLiteralType(value: string): Promise { + const data = await this.client.apiRequest("getStringLiteralType", { + snapshot: this.snapshotId, + project: this.project.handle, + value, + }); + return this.objectRegistry.getOrCreateType(data); + } + + /** Get (or create) the singleton type for a numeric literal value. Always returns a type. */ + async getNumberLiteralType(value: number): Promise { + const data = await this.client.apiRequest("getNumberLiteralType", { + snapshot: this.snapshotId, + project: this.project.handle, + value, + }); + return this.objectRegistry.getOrCreateType(data); + } + + /** Get (or create) the singleton type for a bigint literal value. Always returns a type. */ + async getBigIntLiteralType(value: bigint): Promise { + const negative = value < 0n; + const absValue = negative ? -value : value; + const base10Value = absValue === 0n ? "" : absValue.toString(); + const data = await this.client.apiRequest("getBigIntLiteralType", { + snapshot: this.snapshotId, + project: this.project.handle, + negative, + base10Value, + }); + return this.objectRegistry.getOrCreateType(data); + } + + /** + * Get the augmented properties of a type: its properties, plus (when the type has call or + * construct signatures) the properties of the global `CallableFunction`/`NewableFunction` + * interfaces not already present. + */ + async getAugmentedPropertiesOfType(type: Type): Promise { + const data = await this.client.apiRequest("getAugmentedPropertiesOfType", { + snapshot: this.snapshotId, + project: this.project.handle, + objectId: type.id, + }); + return data ? data.map(d => this.objectRegistry.getOrCreateSymbol(d)) : []; + } + + async getJsxIntrinsicTagNamesAt(location: Node): Promise { + const data = await this.client.apiRequest("getJsxIntrinsicTagNamesAt", { + snapshot: this.snapshotId, + project: this.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? data.map(d => this.objectRegistry.getOrCreateSymbol(d)) : []; + } + + /** + * Look up a private identifier (e.g. `"#foo"`, including the leading `#`) lexically in scope + * at `location`, and if found, return the corresponding property of `type`. + */ + async getPrivateIdentifierPropertyOfType(type: Type, name: string, location: Node): Promise { + const data = await this.client.apiRequest("getPrivateIdentifierPropertyOfType", { + snapshot: this.snapshotId, + project: this.project.handle, + type: type.id, + name, + location: getNodeRequestHandle(location), + }); + return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined; + } async typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: number): Promise { const binaryData = await this.client.apiRequestBinary("typeToTypeNode", { @@ -2825,6 +2917,41 @@ export class Checker { }); } + /** + * Returns `true` if the function-like declaration is the implementation + * signature of a set of overloads (i.e. it has a body and is not a + * get/set accessor). + */ + async isImplementationOfOverload(node: Node): Promise { + return this.client.apiRequest("isImplementationOfOverload", { + snapshot: this.snapshotId, + project: this.project.handle, + location: getNodeRequestHandle(node), + }); + } + + /** + * Get the property symbol corresponding to an identifier in a destructuring + * assignment or `for..of` statement, e.g. `a` in `({ property1: a } = obj)`. + */ + async getPropertySymbolOfDestructuringAssignment(location: Identifier): Promise { + const data = await this.client.apiRequest("getPropertySymbolOfDestructuringAssignment", { + snapshot: this.snapshotId, + project: this.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? this.objectRegistry.getOrCreateSymbol(data) : undefined; + } + + /** Get all ambient modules declared in the program (e.g. `declare module "foo" { ... }`). */ + async getAmbientModules(): Promise { + const data = await this.client.apiRequest("getAmbientModules", { + snapshot: this.snapshotId, + project: this.project.handle, + }); + return data ? data.map(d => this.objectRegistry.getOrCreateSymbol(d)) : []; + } + /** Get the return type of a signature. Always returns a type. */ async getReturnTypeOfSignature(signature: Signature): Promise { return signature.getReturnType(); diff --git a/packages/typescript/src/api/proto.generated.ts b/packages/typescript/src/api/proto.generated.ts index 51b1123b15634..9e95049747137 100644 --- a/packages/typescript/src/api/proto.generated.ts +++ b/packages/typescript/src/api/proto.generated.ts @@ -131,6 +131,15 @@ export interface APIMethodInfo { getAwaitedType: APIMethod; getBaseTypeOfLiteralType: APIMethod; getNonNullableType: APIMethod; + getNullableType: APIMethod; + getStringLiteralType: APIMethod; + getNumberLiteralType: APIMethod; + getBigIntLiteralType: APIMethod; + getFalseType: APIMethod; + getTrueType: APIMethod; + getAugmentedPropertiesOfType: APIMethod; + getJsxIntrinsicTagNamesAt: APIMethod; + getPrivateIdentifierPropertyOfType: APIMethod; getTypeFromTypeNode: APIMethod; getWidenedType: APIMethod; getParameterType: APIMethod; @@ -180,6 +189,9 @@ export interface APIMethodInfo { getDocumentationComment: APIMethod; isArrayType: APIMethod; isReadonlySymbol: APIMethod; + isImplementationOfOverload: APIMethod; + getPropertySymbolOfDestructuringAssignment: APIMethod; + getAmbientModules: APIMethod; getReferencesToSymbolInFile: APIMethod; getReferencedSymbolsForNode: APIMethod; getSignatureUsages: APIMethod; @@ -799,6 +811,61 @@ export interface GetBaseTypeOfLiteralTypeParams { type: number; } +/** GetNullableTypeParams are the parameters for the getNullableType method. */ +export interface GetNullableTypeParams { + snapshot: number; + project: number; + type: number; + flags: number; +} + +/** GetStringLiteralTypeParams are the parameters for the getStringLiteralType method. */ +export interface GetStringLiteralTypeParams { + snapshot: number; + project: number; + value: string; +} + +/** GetNumberLiteralTypeParams are the parameters for the getNumberLiteralType method. */ +export interface GetNumberLiteralTypeParams { + snapshot: number; + project: number; + value: number; +} + +/** + * GetBigIntLiteralTypeParams are the parameters for the getBigIntLiteralType method. + * Base10Value is the absolute value in base 10 with no leading zeros (empty for zero). + */ +export interface GetBigIntLiteralTypeParams { + snapshot: number; + project: number; + negative?: boolean | undefined; + base10Value?: string | undefined; +} + +/** GetIntrinsicTypeParams is used for intrinsic type getters (anyType, stringType, etc.). */ +export interface GetIntrinsicTypeParams { + snapshot: number; + project: number; +} + +/** CheckerNodeParams are parameters for checker methods that operate on a node location. */ +export interface CheckerNodeParams { + snapshot: number; + project: number; + location: string; +} + +/** GetPrivateIdentifierPropertyOfTypeParams are the parameters for the getPrivateIdentifierPropertyOfType method. */ +export interface GetPrivateIdentifierPropertyOfTypeParams { + snapshot: number; + project: number; + type: number; + name: string; + location: string; +} + /** GetTypeFromTypeNodeParams are the parameters for the getTypeFromTypeNode method. */ export interface GetTypeFromTypeNodeParams { snapshot: number; @@ -914,13 +981,6 @@ export interface TextEdit { newText: string; } -/** CheckerNodeParams are parameters for checker methods that operate on a node location. */ -export interface CheckerNodeParams { - snapshot: number; - project: number; - location: string; -} - export interface ConstantValueResponse { isNumber: boolean; value: unknown; @@ -1091,12 +1151,6 @@ export interface SelectedFilesEmitParams { files: readonly DocumentIdentifier[] | null; } -/** GetIntrinsicTypeParams is used for intrinsic type getters (anyType, stringType, etc.). */ -export interface GetIntrinsicTypeParams { - snapshot: number; - project: number; -} - /** * WellKnownSymbolsResponse carries the handle ids of the per-checker singleton * symbols (unknown, undefined, arguments) so the client can identify them by id @@ -1169,14 +1223,17 @@ export interface BatchRequest { | "getAliasSymbolOfType" | "getAliasTypeArgumentsOfType" | "getAliasedSymbol" + | "getAmbientModules" | "getAnyType" | "getApparentPropertiesOfType" | "getApparentType" + | "getAugmentedPropertiesOfType" | "getAwaitedType" | "getBaseConstraintOfType" | "getBaseTypeOfLiteralType" | "getBaseTypeOfType" | "getBaseTypes" + | "getBigIntLiteralType" | "getBigIntType" | "getBindDiagnostics" | "getBooleanType" @@ -1206,6 +1263,7 @@ export interface BatchRequest { | "getExportsOfModule" | "getExportsOfSymbol" | "getExtendsTypeOfType" + | "getFalseType" | "getFalseTypeOfConditionalType" | "getFreshTypeOfType" | "getFullyQualifiedName" @@ -1217,6 +1275,7 @@ export interface BatchRequest { | "getIndexTypeOfType" | "getJavaScriptEmit" | "getJsDocTags" + | "getJsxIntrinsicTagNamesAt" | "getLocalTypeParametersOfType" | "getMemberInModuleExports" | "getMembersOfSymbol" @@ -1229,6 +1288,8 @@ export interface BatchRequest { | "getNonNullableType" | "getNonPrimitiveType" | "getNullType" + | "getNullableType" + | "getNumberLiteralType" | "getNumberType" | "getObjectTypeOfType" | "getOuterTypeParametersOfType" @@ -1236,9 +1297,11 @@ export interface BatchRequest { | "getParametersOfSignature" | "getParentOfSymbol" | "getParentOfSymbolForChecker" + | "getPrivateIdentifierPropertyOfType" | "getProgramDiagnostics" | "getPropertiesOfType" | "getPropertyOfType" + | "getPropertySymbolOfDestructuringAssignment" | "getReducedType" | "getReferencedSymbolsForNode" | "getReferencesToSymbolInFile" @@ -1258,6 +1321,7 @@ export interface BatchRequest { | "getSourceFile" | "getSourceFileMetadata" | "getSourceFileNames" + | "getStringLiteralType" | "getStringType" | "getSuggestionDiagnostics" | "getSymbolAtLocation" @@ -1278,6 +1342,7 @@ export interface BatchRequest { | "getTemplateTypeOfMappedType" | "getThisParameterOfSignature" | "getThisTypeOfType" + | "getTrueType" | "getTrueTypeOfConditionalType" | "getTypeArguments" | "getTypeAtLocation" @@ -1305,6 +1370,7 @@ export interface BatchRequest { | "isArrayLikeType" | "isArrayType" | "isContextSensitive" + | "isImplementationOfOverload" | "isReadonlySymbol" | "isTypeAssignableTo" | "parseCommandLine" @@ -1351,14 +1417,17 @@ export interface BatchResponse { | "getAliasSymbolOfType" | "getAliasTypeArgumentsOfType" | "getAliasedSymbol" + | "getAmbientModules" | "getAnyType" | "getApparentPropertiesOfType" | "getApparentType" + | "getAugmentedPropertiesOfType" | "getAwaitedType" | "getBaseConstraintOfType" | "getBaseTypeOfLiteralType" | "getBaseTypeOfType" | "getBaseTypes" + | "getBigIntLiteralType" | "getBigIntType" | "getBindDiagnostics" | "getBooleanType" @@ -1388,6 +1457,7 @@ export interface BatchResponse { | "getExportsOfModule" | "getExportsOfSymbol" | "getExtendsTypeOfType" + | "getFalseType" | "getFalseTypeOfConditionalType" | "getFreshTypeOfType" | "getFullyQualifiedName" @@ -1399,6 +1469,7 @@ export interface BatchResponse { | "getIndexTypeOfType" | "getJavaScriptEmit" | "getJsDocTags" + | "getJsxIntrinsicTagNamesAt" | "getLocalTypeParametersOfType" | "getMemberInModuleExports" | "getMembersOfSymbol" @@ -1411,6 +1482,8 @@ export interface BatchResponse { | "getNonNullableType" | "getNonPrimitiveType" | "getNullType" + | "getNullableType" + | "getNumberLiteralType" | "getNumberType" | "getObjectTypeOfType" | "getOuterTypeParametersOfType" @@ -1418,9 +1491,11 @@ export interface BatchResponse { | "getParametersOfSignature" | "getParentOfSymbol" | "getParentOfSymbolForChecker" + | "getPrivateIdentifierPropertyOfType" | "getProgramDiagnostics" | "getPropertiesOfType" | "getPropertyOfType" + | "getPropertySymbolOfDestructuringAssignment" | "getReducedType" | "getReferencedSymbolsForNode" | "getReferencesToSymbolInFile" @@ -1440,6 +1515,7 @@ export interface BatchResponse { | "getSourceFile" | "getSourceFileMetadata" | "getSourceFileNames" + | "getStringLiteralType" | "getStringType" | "getSuggestionDiagnostics" | "getSymbolAtLocation" @@ -1460,6 +1536,7 @@ export interface BatchResponse { | "getTemplateTypeOfMappedType" | "getThisParameterOfSignature" | "getThisTypeOfType" + | "getTrueType" | "getTrueTypeOfConditionalType" | "getTypeArguments" | "getTypeAtLocation" @@ -1487,6 +1564,7 @@ export interface BatchResponse { | "isArrayLikeType" | "isArrayType" | "isContextSensitive" + | "isImplementationOfOverload" | "isReadonlySymbol" | "isTypeAssignableTo" | "parseCommandLine" diff --git a/packages/typescript/src/api/proto.ts b/packages/typescript/src/api/proto.ts index 322b3ff4b2bb8..c3093985c1d60 100644 --- a/packages/typescript/src/api/proto.ts +++ b/packages/typescript/src/api/proto.ts @@ -69,7 +69,7 @@ export type SymbolsPropertyMethod = APIMethodsReturning; export type TypePropertyMethod = Exclude, IntrinsicTypeMethod>; export type TypesPropertyMethod = APIMethodsReturning; -export type IntrinsicTypeMethod = "getAnyType" | "getBigIntType" | "getBooleanType" | "getESSymbolType" | "getNeverType" | "getNonPrimitiveType" | "getNullType" | "getNumberType" | "getStringType" | "getUndefinedType" | "getUnknownType" | "getVoidType"; +export type IntrinsicTypeMethod = "getAnyType" | "getBigIntType" | "getBooleanType" | "getESSymbolType" | "getFalseType" | "getNeverType" | "getNonPrimitiveType" | "getNullType" | "getNumberType" | "getStringType" | "getTrueType" | "getUndefinedType" | "getUnknownType" | "getVoidType"; type BatchableAPIMethod = Exclude; export type APIRequest = { [K in BatchableAPIMethod]: { method: K; params: APIMethodInfo[K]["params"]; }; }[BatchableAPIMethod]; diff --git a/packages/typescript/src/api/sync/api.ts b/packages/typescript/src/api/sync/api.ts index e271dafabaf7b..a532bcad9cddc 100644 --- a/packages/typescript/src/api/sync/api.ts +++ b/packages/typescript/src/api/sync/api.ts @@ -4954,6 +4954,39 @@ export class Checker { ); } + /** + * Add `undefined` and/or `null` to a type, as indicated by `flags` (a combination of + * {@link TypeFlags.Undefined} and {@link TypeFlags.Null}). Always returns a type. + */ + get getNullableType(): { + (type: Type, flags: TypeFlags): Type; + gen(type: Type, flags: TypeFlags): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getNullableType", + function (type: Type, flags: TypeFlags): Type { + const data = owner.client.apiRequest("getNullableType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + type: type.id, + flags, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + function* (type: Type, flags: TypeFlags): Generator { + const data = yield* apiRequest("getNullableType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + type: type.id, + flags, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + ); + } + /** * Get the type for a type node. Always returns a type; for type nodes whose * type cannot be determined the checker yields the error type (use @@ -5377,6 +5410,224 @@ export class Checker { }, ); } + get getFalseType(): { + (): Type; + gen(): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getFalseType", + function (): Type { + return owner.getIntrinsicType("getFalseType"); + }, + function* (): Generator { + return yield* owner.getIntrinsicType.gen("getFalseType"); + }, + ); + } + get getTrueType(): { + (): Type; + gen(): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getTrueType", + function (): Type { + return owner.getIntrinsicType("getTrueType"); + }, + function* (): Generator { + return yield* owner.getIntrinsicType.gen("getTrueType"); + }, + ); + } + + /** Get (or create) the singleton type for a string literal value. Always returns a type. */ + get getStringLiteralType(): { + (value: string): Type; + gen(value: string): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getStringLiteralType", + function (value: string): Type { + const data = owner.client.apiRequest("getStringLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + function* (value: string): Generator { + const data = yield* apiRequest("getStringLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + ); + } + + /** Get (or create) the singleton type for a numeric literal value. Always returns a type. */ + get getNumberLiteralType(): { + (value: number): Type; + gen(value: number): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getNumberLiteralType", + function (value: number): Type { + const data = owner.client.apiRequest("getNumberLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + function* (value: number): Generator { + const data = yield* apiRequest("getNumberLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + ); + } + + /** Get (or create) the singleton type for a bigint literal value. Always returns a type. */ + get getBigIntLiteralType(): { + (value: bigint): Type; + gen(value: bigint): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getBigIntLiteralType", + function (value: bigint): Type { + const negative = value < 0n; + const absValue = negative ? -value : value; + const base10Value = absValue === 0n ? "" : absValue.toString(); + const data = owner.client.apiRequest("getBigIntLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + negative, + base10Value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + function* (value: bigint): Generator { + const negative = value < 0n; + const absValue = negative ? -value : value; + const base10Value = absValue === 0n ? "" : absValue.toString(); + const data = yield* apiRequest("getBigIntLiteralType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + negative, + base10Value, + }); + return owner.objectRegistry.getOrCreateType(data); + }, + ); + } + + /** + * Get the augmented properties of a type: its properties, plus (when the type has call or + * construct signatures) the properties of the global `CallableFunction`/`NewableFunction` + * interfaces not already present. + */ + get getAugmentedPropertiesOfType(): { + (type: Type): readonly Symbol[]; + gen(type: Type): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getAugmentedPropertiesOfType", + function (type: Type): readonly Symbol[] { + const data = owner.client.apiRequest("getAugmentedPropertiesOfType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + objectId: type.id, + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + function* (type: Type): Generator { + const data = yield* apiRequest("getAugmentedPropertiesOfType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + objectId: type.id, + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + ); + } + + get getJsxIntrinsicTagNamesAt(): { + (location: Node): readonly Symbol[]; + gen(location: Node): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getJsxIntrinsicTagNamesAt", + function (location: Node): readonly Symbol[] { + const data = owner.client.apiRequest("getJsxIntrinsicTagNamesAt", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + function* (location: Node): Generator { + const data = yield* apiRequest("getJsxIntrinsicTagNamesAt", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + ); + } + + /** + * Look up a private identifier (e.g. `"#foo"`, including the leading `#`) lexically in scope + * at `location`, and if found, return the corresponding property of `type`. + */ + get getPrivateIdentifierPropertyOfType(): { + (type: Type, name: string, location: Node): Symbol | undefined; + gen(type: Type, name: string, location: Node): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getPrivateIdentifierPropertyOfType", + function (type: Type, name: string, location: Node): Symbol | undefined { + const data = owner.client.apiRequest("getPrivateIdentifierPropertyOfType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + type: type.id, + name, + location: getNodeRequestHandle(location), + }); + return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined; + }, + function* (type: Type, name: string, location: Node): Generator { + const data = yield* apiRequest("getPrivateIdentifierPropertyOfType", { + snapshot: owner.snapshotId, + project: owner.project.handle, + type: type.id, + name, + location: getNodeRequestHandle(location), + }); + return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined; + }, + ); + } get typeToTypeNode(): { (type: Type, enclosingDeclaration?: Node, flags?: number): TypeNode | undefined; @@ -5601,6 +5852,93 @@ export class Checker { ); } + /** + * Returns `true` if the function-like declaration is the implementation + * signature of a set of overloads (i.e. it has a body and is not a + * get/set accessor). + */ + get isImplementationOfOverload(): { + (node: Node): boolean; + gen(node: Node): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "isImplementationOfOverload", + function (node: Node): boolean { + return owner.client.apiRequest("isImplementationOfOverload", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(node), + }); + }, + function* (node: Node): Generator { + return yield* apiRequest("isImplementationOfOverload", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(node), + }); + }, + ); + } + + /** + * Get the property symbol corresponding to an identifier in a destructuring + * assignment or `for..of` statement, e.g. `a` in `({ property1: a } = obj)`. + */ + get getPropertySymbolOfDestructuringAssignment(): { + (location: Identifier): Symbol | undefined; + gen(location: Identifier): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getPropertySymbolOfDestructuringAssignment", + function (location: Identifier): Symbol | undefined { + const data = owner.client.apiRequest("getPropertySymbolOfDestructuringAssignment", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined; + }, + function* (location: Identifier): Generator { + const data = yield* apiRequest("getPropertySymbolOfDestructuringAssignment", { + snapshot: owner.snapshotId, + project: owner.project.handle, + location: getNodeRequestHandle(location), + }); + return data ? owner.objectRegistry.getOrCreateSymbol(data) : undefined; + }, + ); + } + + /** Get all ambient modules declared in the program (e.g. `declare module "foo" { ... }`). */ + get getAmbientModules(): { + (): readonly Symbol[]; + gen(): Generator; + } { + const owner = this; + return cacheGeneratorMethod( + owner, + "getAmbientModules", + function (): readonly Symbol[] { + const data = owner.client.apiRequest("getAmbientModules", { + snapshot: owner.snapshotId, + project: owner.project.handle, + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + function* (): Generator { + const data = yield* apiRequest("getAmbientModules", { + snapshot: owner.snapshotId, + project: owner.project.handle, + }); + return data ? data.map(d => owner.objectRegistry.getOrCreateSymbol(d)) : []; + }, + ); + } + /** Get the return type of a signature. Always returns a type. */ get getReturnTypeOfSignature(): { (signature: Signature): Type; diff --git a/packages/typescript/test/async/api.test.ts b/packages/typescript/test/async/api.test.ts index 9a37f0c38dfff..fae02de58bf64 100644 --- a/packages/typescript/test/async/api.test.ts +++ b/packages/typescript/test/async/api.test.ts @@ -7,6 +7,7 @@ import { getJSDocTags, getSynthesizedDeepClone, getTextOfJSDocComment, + type Identifier, InternalSymbolName, isCallExpression, isClassDeclaration, @@ -17,9 +18,12 @@ import { isInterfaceDeclaration, isJSDoc, isJSDocParameterTag, + isJsxSelfClosingElement, isModuleDeclaration, isNamedImports, isObjectLiteralExpression, + isPrivateIdentifier, + isPropertyAccessExpression, isPropertyAssignment, isPropertyDeclaration, isReturnStatement, @@ -4839,6 +4843,106 @@ describe("Checker - intrinsic type getters", { concurrency }, () => { }); }); +describe("Checker - literal and nullable type getters", { concurrency }, () => { + const intrinsicFiles = { + "/tsconfig.json": "{}", + "/src/main.ts": `export const x = 1;`, + }; + + test("getStringLiteralType returns a StringLiteral type with the given value", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const type = await project.checker.getStringLiteralType("hello"); + assert.ok(type); + assert.ok(type.flags & TypeFlags.StringLiteral); + assert.equal((type as LiteralType).value, "hello"); + + // The checker caches literal types, so asking for the same value twice should + // yield the same underlying type. + const type2 = await project.checker.getStringLiteralType("hello"); + assert.equal(type2.id, type.id); + }); + + test("getNumberLiteralType returns a NumberLiteral type with the given value", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const type = await project.checker.getNumberLiteralType(42); + assert.ok(type); + assert.ok(type.flags & TypeFlags.NumberLiteral); + assert.equal((type as NumberLiteralType).value, 42); + + const negType = await project.checker.getNumberLiteralType(-1.5); + assert.ok(negType.flags & TypeFlags.NumberLiteral); + assert.equal((negType as NumberLiteralType).value, -1.5); + }); + + test("getBigIntLiteralType returns a BigIntLiteral type with the given value (positive, negative, zero)", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const posType = await project.checker.getBigIntLiteralType(123n); + assert.ok(posType.flags & TypeFlags.BigIntLiteral); + assert.equal((posType as BigIntLiteralType).value, 123n); + + const negType = await project.checker.getBigIntLiteralType(-123n); + assert.ok(negType.flags & TypeFlags.BigIntLiteral); + assert.equal((negType as BigIntLiteralType).value, -123n); + + const zeroType = await project.checker.getBigIntLiteralType(0n); + assert.ok(zeroType.flags & TypeFlags.BigIntLiteral); + assert.equal((zeroType as BigIntLiteralType).value, 0n); + }); + + test("getNullableType adds Undefined and/or Null to a type", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const stringType = await project.checker.getStringType(); + + const withUndefined = await project.checker.getNullableType(stringType, TypeFlags.Undefined); + assert.ok(withUndefined.flags & TypeFlags.Union, `Expected union, got flags ${withUndefined.flags}`); + + const withNull = await project.checker.getNullableType(stringType, TypeFlags.Null); + assert.ok(withNull.flags & TypeFlags.Union, `Expected union, got flags ${withNull.flags}`); + + const withBoth = await project.checker.getNullableType(stringType, TypeFlags.Undefined | TypeFlags.Null); + assert.ok(withBoth.flags & TypeFlags.Union, `Expected union, got flags ${withBoth.flags}`); + + // Adding no flags should just return the original type unchanged. + const withNeither = await project.checker.getNullableType(stringType, 0 as TypeFlags); + assert.equal(withNeither.id, stringType.id); + }); + + test("getFalseType returns the false type", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const falseType = await project.checker.getFalseType(); + assert.ok(falseType.flags & TypeFlags.BooleanLiteral); + assert.equal((falseType as LiteralType).value, false); + }); + + test("getTrueType returns the true type", async () => { + await using api = spawnAPI(intrinsicFiles); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const trueType = await project.checker.getTrueType(); + assert.ok(trueType.flags & TypeFlags.BooleanLiteral); + assert.equal((trueType as LiteralType).value, true); + }); +}); + describe("Checker - multi-project type ID uniqueness", { concurrency }, () => { test("intrinsic types from 3 projects in the same snapshot have non-colliding IDs", async () => { await using api = spawnAPI({ @@ -5109,6 +5213,158 @@ export const obj = { name }; }); }); +describe("Checker - getAugmentedPropertiesOfType", { concurrency }, () => { + test("includes CallableFunction members for a function type", async () => { + await using api = spawnAPI({ + "/tsconfig.json": "{}", + "/src/main.ts": `export function foo(x: number): number { return x; }`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const pos = (await project.program.getSourceFile("/src/main.ts"))!.text.indexOf("foo"); + const symbol = await project.checker.getSymbolAtPosition("/src/main.ts", pos); + assert.ok(symbol); + const type = await project.checker.getTypeOfSymbol(symbol); + assert.ok(type); + + const props = await project.checker.getAugmentedPropertiesOfType(type); + const names = props.map(p => p.name); + assert.ok(names.includes("call"), `Expected augmented properties to include "call", got: ${names}`); + assert.ok(names.includes("apply"), `Expected augmented properties to include "apply", got: ${names}`); + assert.ok(names.includes("bind"), `Expected augmented properties to include "bind", got: ${names}`); + }); +}); + +describe("Checker - getJsxIntrinsicTagNamesAt", { concurrency }, () => { + test("returns the properties of the JSX.IntrinsicElements interface", async () => { + const src = `export const el =
;\n`; + const jsxTypes = ` +declare namespace JSX { + interface IntrinsicElements { + div: {}; + span: {}; + } + interface Element {} +} +`; + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { jsx: "react" } }), + "/src/jsx.d.ts": jsxTypes, + "/src/main.tsx": src, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.tsx"); + assert.ok(sourceFile); + + let jsxNode: import("@typescript/typescript/ast").Node | undefined; + sourceFile.forEachChild(function visit(node) { + if (isJsxSelfClosingElement(node)) { + jsxNode = node; + } + node.forEachChild(visit); + }); + assert.ok(jsxNode, "Should find a JSX self-closing element"); + + const tagNames = await project.checker.getJsxIntrinsicTagNamesAt(jsxNode); + const names = tagNames.map(s => s.name); + assert.ok(names.includes("div"), `Expected intrinsic tag names to include "div", got: ${names}`); + assert.ok(names.includes("span"), `Expected intrinsic tag names to include "span", got: ${names}`); + }); +}); + +describe("Checker - getPrivateIdentifierPropertyOfType", { concurrency }, () => { + test("resolves a private field lexically in scope at a location", async () => { + const src = ` +export class Cache { + #bar = 1; + getBar(): number { + return this.#bar; + } +} +`; + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, target: "esnext" } }), + "/src/main.ts": src, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + + let privateAccessNode: import("@typescript/typescript/ast").PropertyAccessExpression | undefined; + sourceFile.forEachChild(function visit(node) { + if (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)) { + privateAccessNode = node; + } + node.forEachChild(visit); + }); + assert.ok(privateAccessNode, "Should find `this.#bar`"); + + const thisType = await project.checker.getTypeAtLocation(privateAccessNode.expression); + assert.ok(thisType); + + const name = privateAccessNode.name.text; + assert.equal(name, "#bar"); + + const prop = await project.checker.getPrivateIdentifierPropertyOfType(thisType, name, privateAccessNode.name); + assert.ok(prop, "Should resolve the private field"); + // Private member symbol names are internally encoded (e.g. "__#1@#bar") to disambiguate + // same-named private members across different classes; they still end with the original text. + assert.ok(prop.name.endsWith("#bar"), `Expected symbol name to end with "#bar", got: ${prop.name}`); + }); + + test("returns undefined when the private identifier is not in scope", async () => { + const src = ` +export class Cache { + #bar = 1; +} +export class Other { + #baz = 2; + getBaz(): number { + return this.#baz; + } +} +`; + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, target: "esnext" } }), + "/src/main.ts": src, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + + let cacheClass: import("@typescript/typescript/ast").ClassDeclaration | undefined; + let privateAccessNode: import("@typescript/typescript/ast").PropertyAccessExpression | undefined; + sourceFile.forEachChild(function visit(node) { + if (isClassDeclaration(node) && node.name?.text === "Cache") { + cacheClass = node; + } + if (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)) { + privateAccessNode = node; + } + node.forEachChild(visit); + }); + assert.ok(cacheClass, "Should find class Cache"); + assert.ok(privateAccessNode, "Should find `this.#baz`"); + + const cacheSymbol = await project.checker.getSymbolAtPosition("/src/main.ts", cacheClass.name!.pos + 1); + assert.ok(cacheSymbol); + const cacheType = await project.checker.getDeclaredTypeOfSymbol(cacheSymbol); + assert.ok(cacheType); + + // "#baz" is lexically scoped to class Other, not Cache, so looking it up at Cache's + // location (the class declaration itself) should fail to resolve. + const prop = await project.checker.getPrivateIdentifierPropertyOfType(cacheType, "#baz", cacheClass); + assert.equal(prop, undefined); + }); +}); + describe("readFile callback semantics", { concurrency }, () => { test("callback configurations require every operation at runtime", () => { assert.throws( @@ -6304,6 +6560,46 @@ export type B = InstanceType; }); }); +describe("Checker - isImplementationOfOverload", { concurrency }, () => { + test("returns true only for the implementation signature of overloaded functions", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": ` +function f(x: number): number; +function f(x: string): string; +function f(x: number | string): number | string { + return x; +} +`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + const functions = sourceFile.statements.filter(isFunctionDeclaration); + assert.equal(functions.length, 3); + assert.equal(await project.checker.isImplementationOfOverload(functions[0]), false); + assert.equal(await project.checker.isImplementationOfOverload(functions[1]), false); + assert.equal(await project.checker.isImplementationOfOverload(functions[2]), true); + }); + + test("returns false for a non-overloaded function", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `function f(x: number): number { return x; }`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + const f = sourceFile.statements.find(isFunctionDeclaration); + assert.ok(f); + assert.equal(await project.checker.isImplementationOfOverload(f), false); + }); +}); + describe("Checker - getReturnTypeOfSignature", { concurrency }, () => { test("returns the return type of a function signature", async () => { await using api = spawnAPI({ @@ -7648,6 +7944,43 @@ export * from "./inner"; }); }); +describe("Checker - getAmbientModules", { concurrency }, () => { + test("returns declared ambient modules", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + // New ambient external modules can only be declared in a script file (not a module) or a `.d.ts` file. + "/src/ambient.d.ts": ` +declare module "foo" { + export const value: number; +} +declare module "bar" { + export const value: string; +} +`, + "/src/main.ts": `export {};`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const ambientModules = await project.checker.getAmbientModules(); + const names = ambientModules.map(m => m.name); + assert.ok(names.includes(`"foo"`), `Should include "foo", found: ${names.join(", ")}`); + assert.ok(names.includes(`"bar"`), `Should include "bar", found: ${names.join(", ")}`); + }); + + test("returns an empty array when there are no ambient modules", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `export const a = 1;`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const ambientModules = await project.checker.getAmbientModules(); + assert.deepEqual(ambientModules, []); + }); +}); + describe("Checker - getSymbolsInScope", { concurrency }, () => { const scopeFiles = { "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), @@ -8145,6 +8478,59 @@ describe("Checker - isContextSensitive", { concurrency }, () => { }); }); +describe("Checker - getPropertySymbolOfDestructuringAssignment", { concurrency }, () => { + test("returns the property symbol for an identifier in a destructuring assignment", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": ` +interface Point { x: number; y: number; } +declare const point: Point; +let x: number; +({ x } = point); +`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + // Find the identifier "x" within the destructuring assignment's left-hand pattern. + let destructuredX: Identifier | undefined; + sourceFile.forEachChild(function visit(node) { + if (isShorthandPropertyAssignment(node) && isIdentifier(node.name) && node.name.text === "x") { + destructuredX = node.name; + } + node.forEachChild(visit); + }); + assert.ok(destructuredX, "Should find the destructured identifier"); + const propertySymbol = await project.checker.getPropertySymbolOfDestructuringAssignment(destructuredX); + assert.ok(propertySymbol); + assert.equal(propertySymbol.name, "x"); + }); + + test("returns undefined for an identifier that is not part of a destructuring assignment", async () => { + await using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `declare const point: { x: number };\npoint;`, + }); + + const snapshot = await api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = await project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + let pointUsage: Identifier | undefined; + sourceFile.forEachChild(function visit(node) { + if (isExpressionStatement(node) && isIdentifier(node.expression) && node.expression.text === "point") { + pointUsage = node.expression; + } + node.forEachChild(visit); + }); + assert.ok(pointUsage, "Should find the standalone identifier"); + const propertySymbol = await project.checker.getPropertySymbolOfDestructuringAssignment(pointUsage); + assert.equal(propertySymbol, undefined); + }); +}); + describe("Checker - isTypeAssignableTo", { concurrency }, () => { test("returns true when source is assignable to target", async () => { await using api = spawnAPI({ diff --git a/packages/typescript/test/sync/api-generators.test.ts b/packages/typescript/test/sync/api-generators.test.ts index bae80333e1ba3..37f0f4e4e66ac 100644 --- a/packages/typescript/test/sync/api-generators.test.ts +++ b/packages/typescript/test/sync/api-generators.test.ts @@ -1728,6 +1728,18 @@ describe("API - generator batching", { concurrency: areTestsFiltered() }, () => parityCase("Checker", "getTypeArguments", checker.getTypeArguments, assertTypeArraysEquivalent, boxedType), parityCase("Checker", "getNonMissingTypeOfSymbol", checker.getNonMissingTypeOfSymbol, assertTypesEquivalent, boxedOptSymbol), parityCase("Checker", "isReadonlySymbol", checker.isReadonlySymbol, assertDeepEquivalent, boxedOptSymbol), + parityCase("Checker", "getNullableType", checker.getNullableType, assertTypesEquivalent, interfaceType, TypeFlags.Null), + parityCase("Checker", "getStringLiteralType", checker.getStringLiteralType, assertTypesEquivalent, "hello"), + parityCase("Checker", "getNumberLiteralType", checker.getNumberLiteralType, assertTypesEquivalent, 42), + parityCase("Checker", "getBigIntLiteralType", checker.getBigIntLiteralType, assertTypesEquivalent, 123n), + parityCase("Checker", "getFalseType", checker.getFalseType, assertTypesEquivalent), + parityCase("Checker", "getTrueType", checker.getTrueType, assertTypesEquivalent), + parityCase("Checker", "getAugmentedPropertiesOfType", checker.getAugmentedPropertiesOfType, assertSymbolArraysEquivalent, interfaceType), + parityCase("Checker", "getJsxIntrinsicTagNamesAt", checker.getJsxIntrinsicTagNamesAt, assertSymbolArraysEquivalent, combineDeclaration), + parityCase("Checker", "getPrivateIdentifierPropertyOfType", checker.getPrivateIdentifierPropertyOfType, assertOptionalSymbolsEquivalent, interfaceType, "#missing", combineDeclaration), + parityCase("Checker", "isImplementationOfOverload", checker.isImplementationOfOverload, assertDeepEquivalent, combineDeclaration), + parityCase("Checker", "getPropertySymbolOfDestructuringAssignment", checker.getPropertySymbolOfDestructuringAssignment, assertOptionalSymbolsEquivalent, importedDerived), + parityCase("Checker", "getAmbientModules", checker.getAmbientModules, assertSymbolArraysEquivalent), parityCase("Checker", "getTargetSymbol", checker.getTargetSymbol, assertOptionalSymbolsEquivalent, boxedOptSymbol), parityCase("Checker", "getExportSymbolOfSymbol", checker.getExportSymbolOfSymbol, assertSymbolsEquivalent, localCombineSymbol), diff --git a/packages/typescript/test/sync/api.test.ts b/packages/typescript/test/sync/api.test.ts index 6d25e0d691258..5c66c31cdc765 100644 --- a/packages/typescript/test/sync/api.test.ts +++ b/packages/typescript/test/sync/api.test.ts @@ -15,6 +15,7 @@ import { getJSDocTags, getSynthesizedDeepClone, getTextOfJSDocComment, + type Identifier, InternalSymbolName, isCallExpression, isClassDeclaration, @@ -25,9 +26,12 @@ import { isInterfaceDeclaration, isJSDoc, isJSDocParameterTag, + isJsxSelfClosingElement, isModuleDeclaration, isNamedImports, isObjectLiteralExpression, + isPrivateIdentifier, + isPropertyAccessExpression, isPropertyAssignment, isPropertyDeclaration, isReturnStatement, @@ -4664,6 +4668,106 @@ describe("Checker - intrinsic type getters", { concurrency }, () => { }); }); +describe("Checker - literal and nullable type getters", { concurrency }, () => { + const intrinsicFiles = { + "/tsconfig.json": "{}", + "/src/main.ts": `export const x = 1;`, + }; + + test("getStringLiteralType returns a StringLiteral type with the given value", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const type = project.checker.getStringLiteralType("hello"); + assert.ok(type); + assert.ok(type.flags & TypeFlags.StringLiteral); + assert.equal((type as LiteralType).value, "hello"); + + // The checker caches literal types, so asking for the same value twice should + // yield the same underlying type. + const type2 = project.checker.getStringLiteralType("hello"); + assert.equal(type2.id, type.id); + }); + + test("getNumberLiteralType returns a NumberLiteral type with the given value", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const type = project.checker.getNumberLiteralType(42); + assert.ok(type); + assert.ok(type.flags & TypeFlags.NumberLiteral); + assert.equal((type as NumberLiteralType).value, 42); + + const negType = project.checker.getNumberLiteralType(-1.5); + assert.ok(negType.flags & TypeFlags.NumberLiteral); + assert.equal((negType as NumberLiteralType).value, -1.5); + }); + + test("getBigIntLiteralType returns a BigIntLiteral type with the given value (positive, negative, zero)", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const posType = project.checker.getBigIntLiteralType(123n); + assert.ok(posType.flags & TypeFlags.BigIntLiteral); + assert.equal((posType as BigIntLiteralType).value, 123n); + + const negType = project.checker.getBigIntLiteralType(-123n); + assert.ok(negType.flags & TypeFlags.BigIntLiteral); + assert.equal((negType as BigIntLiteralType).value, -123n); + + const zeroType = project.checker.getBigIntLiteralType(0n); + assert.ok(zeroType.flags & TypeFlags.BigIntLiteral); + assert.equal((zeroType as BigIntLiteralType).value, 0n); + }); + + test("getNullableType adds Undefined and/or Null to a type", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const stringType = project.checker.getStringType(); + + const withUndefined = project.checker.getNullableType(stringType, TypeFlags.Undefined); + assert.ok(withUndefined.flags & TypeFlags.Union, `Expected union, got flags ${withUndefined.flags}`); + + const withNull = project.checker.getNullableType(stringType, TypeFlags.Null); + assert.ok(withNull.flags & TypeFlags.Union, `Expected union, got flags ${withNull.flags}`); + + const withBoth = project.checker.getNullableType(stringType, TypeFlags.Undefined | TypeFlags.Null); + assert.ok(withBoth.flags & TypeFlags.Union, `Expected union, got flags ${withBoth.flags}`); + + // Adding no flags should just return the original type unchanged. + const withNeither = project.checker.getNullableType(stringType, 0 as TypeFlags); + assert.equal(withNeither.id, stringType.id); + }); + + test("getFalseType returns the false type", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const falseType = project.checker.getFalseType(); + assert.ok(falseType.flags & TypeFlags.BooleanLiteral); + assert.equal((falseType as LiteralType).value, false); + }); + + test("getTrueType returns the true type", () => { + using api = spawnAPI(intrinsicFiles); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + + const trueType = project.checker.getTrueType(); + assert.ok(trueType.flags & TypeFlags.BooleanLiteral); + assert.equal((trueType as LiteralType).value, true); + }); +}); + describe("Checker - multi-project type ID uniqueness", { concurrency }, () => { test("intrinsic types from 3 projects in the same snapshot have non-colliding IDs", () => { using api = spawnAPI({ @@ -4934,6 +5038,158 @@ export const obj = { name }; }); }); +describe("Checker - getAugmentedPropertiesOfType", { concurrency }, () => { + test("includes CallableFunction members for a function type", () => { + using api = spawnAPI({ + "/tsconfig.json": "{}", + "/src/main.ts": `export function foo(x: number): number { return x; }`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const pos = (project.program.getSourceFile("/src/main.ts"))!.text.indexOf("foo"); + const symbol = project.checker.getSymbolAtPosition("/src/main.ts", pos); + assert.ok(symbol); + const type = project.checker.getTypeOfSymbol(symbol); + assert.ok(type); + + const props = project.checker.getAugmentedPropertiesOfType(type); + const names = props.map(p => p.name); + assert.ok(names.includes("call"), `Expected augmented properties to include "call", got: ${names}`); + assert.ok(names.includes("apply"), `Expected augmented properties to include "apply", got: ${names}`); + assert.ok(names.includes("bind"), `Expected augmented properties to include "bind", got: ${names}`); + }); +}); + +describe("Checker - getJsxIntrinsicTagNamesAt", { concurrency }, () => { + test("returns the properties of the JSX.IntrinsicElements interface", () => { + const src = `export const el =
;\n`; + const jsxTypes = ` +declare namespace JSX { + interface IntrinsicElements { + div: {}; + span: {}; + } + interface Element {} +} +`; + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { jsx: "react" } }), + "/src/jsx.d.ts": jsxTypes, + "/src/main.tsx": src, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.tsx"); + assert.ok(sourceFile); + + let jsxNode: import("@typescript/typescript/ast").Node | undefined; + sourceFile.forEachChild(function visit(node) { + if (isJsxSelfClosingElement(node)) { + jsxNode = node; + } + node.forEachChild(visit); + }); + assert.ok(jsxNode, "Should find a JSX self-closing element"); + + const tagNames = project.checker.getJsxIntrinsicTagNamesAt(jsxNode); + const names = tagNames.map(s => s.name); + assert.ok(names.includes("div"), `Expected intrinsic tag names to include "div", got: ${names}`); + assert.ok(names.includes("span"), `Expected intrinsic tag names to include "span", got: ${names}`); + }); +}); + +describe("Checker - getPrivateIdentifierPropertyOfType", { concurrency }, () => { + test("resolves a private field lexically in scope at a location", () => { + const src = ` +export class Cache { + #bar = 1; + getBar(): number { + return this.#bar; + } +} +`; + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, target: "esnext" } }), + "/src/main.ts": src, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + + let privateAccessNode: import("@typescript/typescript/ast").PropertyAccessExpression | undefined; + sourceFile.forEachChild(function visit(node) { + if (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)) { + privateAccessNode = node; + } + node.forEachChild(visit); + }); + assert.ok(privateAccessNode, "Should find `this.#bar`"); + + const thisType = project.checker.getTypeAtLocation(privateAccessNode.expression); + assert.ok(thisType); + + const name = privateAccessNode.name.text; + assert.equal(name, "#bar"); + + const prop = project.checker.getPrivateIdentifierPropertyOfType(thisType, name, privateAccessNode.name); + assert.ok(prop, "Should resolve the private field"); + // Private member symbol names are internally encoded (e.g. "__#1@#bar") to disambiguate + // same-named private members across different classes; they still end with the original text. + assert.ok(prop.name.endsWith("#bar"), `Expected symbol name to end with "#bar", got: ${prop.name}`); + }); + + test("returns undefined when the private identifier is not in scope", () => { + const src = ` +export class Cache { + #bar = 1; +} +export class Other { + #baz = 2; + getBaz(): number { + return this.#baz; + } +} +`; + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true, target: "esnext" } }), + "/src/main.ts": src, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + + let cacheClass: import("@typescript/typescript/ast").ClassDeclaration | undefined; + let privateAccessNode: import("@typescript/typescript/ast").PropertyAccessExpression | undefined; + sourceFile.forEachChild(function visit(node) { + if (isClassDeclaration(node) && node.name?.text === "Cache") { + cacheClass = node; + } + if (isPropertyAccessExpression(node) && isPrivateIdentifier(node.name)) { + privateAccessNode = node; + } + node.forEachChild(visit); + }); + assert.ok(cacheClass, "Should find class Cache"); + assert.ok(privateAccessNode, "Should find `this.#baz`"); + + const cacheSymbol = project.checker.getSymbolAtPosition("/src/main.ts", cacheClass.name!.pos + 1); + assert.ok(cacheSymbol); + const cacheType = project.checker.getDeclaredTypeOfSymbol(cacheSymbol); + assert.ok(cacheType); + + // "#baz" is lexically scoped to class Other, not Cache, so looking it up at Cache's + // location (the class declaration itself) should fail to resolve. + const prop = project.checker.getPrivateIdentifierPropertyOfType(cacheType, "#baz", cacheClass); + assert.equal(prop, undefined); + }); +}); + describe("readFile callback semantics", { concurrency }, () => { test("callback configurations require every operation at runtime", () => { assert.throws( @@ -6104,6 +6360,46 @@ export type B = InstanceType; }); }); +describe("Checker - isImplementationOfOverload", { concurrency }, () => { + test("returns true only for the implementation signature of overloaded functions", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": ` +function f(x: number): number; +function f(x: string): string; +function f(x: number | string): number | string { + return x; +} +`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + const functions = sourceFile.statements.filter(isFunctionDeclaration); + assert.equal(functions.length, 3); + assert.equal(project.checker.isImplementationOfOverload(functions[0]), false); + assert.equal(project.checker.isImplementationOfOverload(functions[1]), false); + assert.equal(project.checker.isImplementationOfOverload(functions[2]), true); + }); + + test("returns false for a non-overloaded function", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `function f(x: number): number { return x; }`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + const f = sourceFile.statements.find(isFunctionDeclaration); + assert.ok(f); + assert.equal(project.checker.isImplementationOfOverload(f), false); + }); +}); + describe("Checker - getReturnTypeOfSignature", { concurrency }, () => { test("returns the return type of a function signature", () => { using api = spawnAPI({ @@ -7448,6 +7744,43 @@ export * from "./inner"; }); }); +describe("Checker - getAmbientModules", { concurrency }, () => { + test("returns declared ambient modules", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + // New ambient external modules can only be declared in a script file (not a module) or a `.d.ts` file. + "/src/ambient.d.ts": ` +declare module "foo" { + export const value: number; +} +declare module "bar" { + export const value: string; +} +`, + "/src/main.ts": `export {};`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const ambientModules = project.checker.getAmbientModules(); + const names = ambientModules.map(m => m.name); + assert.ok(names.includes(`"foo"`), `Should include "foo", found: ${names.join(", ")}`); + assert.ok(names.includes(`"bar"`), `Should include "bar", found: ${names.join(", ")}`); + }); + + test("returns an empty array when there are no ambient modules", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `export const a = 1;`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const ambientModules = project.checker.getAmbientModules(); + assert.deepEqual(ambientModules, []); + }); +}); + describe("Checker - getSymbolsInScope", { concurrency }, () => { const scopeFiles = { "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), @@ -7945,6 +8278,59 @@ describe("Checker - isContextSensitive", { concurrency }, () => { }); }); +describe("Checker - getPropertySymbolOfDestructuringAssignment", { concurrency }, () => { + test("returns the property symbol for an identifier in a destructuring assignment", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": ` +interface Point { x: number; y: number; } +declare const point: Point; +let x: number; +({ x } = point); +`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + // Find the identifier "x" within the destructuring assignment's left-hand pattern. + let destructuredX: Identifier | undefined; + sourceFile.forEachChild(function visit(node) { + if (isShorthandPropertyAssignment(node) && isIdentifier(node.name) && node.name.text === "x") { + destructuredX = node.name; + } + node.forEachChild(visit); + }); + assert.ok(destructuredX, "Should find the destructured identifier"); + const propertySymbol = project.checker.getPropertySymbolOfDestructuringAssignment(destructuredX); + assert.ok(propertySymbol); + assert.equal(propertySymbol.name, "x"); + }); + + test("returns undefined for an identifier that is not part of a destructuring assignment", () => { + using api = spawnAPI({ + "/tsconfig.json": JSON.stringify({ compilerOptions: { strict: true } }), + "/src/main.ts": `declare const point: { x: number };\npoint;`, + }); + + const snapshot = api.createSnapshot({ openProjects: ["/tsconfig.json"] }); + const project = snapshot.getConfiguredProject("/tsconfig.json")!; + const sourceFile = project.program.getSourceFile("/src/main.ts"); + assert.ok(sourceFile); + let pointUsage: Identifier | undefined; + sourceFile.forEachChild(function visit(node) { + if (isExpressionStatement(node) && isIdentifier(node.expression) && node.expression.text === "point") { + pointUsage = node.expression; + } + node.forEachChild(visit); + }); + assert.ok(pointUsage, "Should find the standalone identifier"); + const propertySymbol = project.checker.getPropertySymbolOfDestructuringAssignment(pointUsage); + assert.equal(propertySymbol, undefined); + }); +}); + describe("Checker - isTypeAssignableTo", { concurrency }, () => { test("returns true when source is assignable to target", () => { using api = spawnAPI({ diff --git a/tsc/internal/api/proto.go b/tsc/internal/api/proto.go index 47b04cb15faec..da3a0f6a3f70f 100644 --- a/tsc/internal/api/proto.go +++ b/tsc/internal/api/proto.go @@ -165,60 +165,72 @@ const ( MethodGetTargetOfSignature Method = "getTargetOfSignature" // Checker methods - MethodGetContextualType Method = "getContextualType" - MethodGetContextualTypeForArgument Method = "getContextualTypeForArgument" - MethodGetAwaitedType Method = "getAwaitedType" - MethodGetBaseTypeOfLiteralType Method = "getBaseTypeOfLiteralType" - MethodGetNonNullableType Method = "getNonNullableType" - MethodGetTypeFromTypeNode Method = "getTypeFromTypeNode" - MethodGetWidenedType Method = "getWidenedType" - MethodGetParameterType Method = "getParameterType" - MethodGetTypeParameterAtPosition Method = "getTypeParameterAtPosition" - MethodIsArrayLikeType Method = "isArrayLikeType" - MethodIsTypeAssignableTo Method = "isTypeAssignableTo" - MethodGetShorthandAssignmentValueSymbol Method = "getShorthandAssignmentValueSymbol" - MethodGetTypeOfSymbolAtLocation Method = "getTypeOfSymbolAtLocation" - MethodTypeToTypeNode Method = "typeToTypeNode" - MethodSignatureToSignatureDeclaration Method = "signatureToSignatureDeclaration" - MethodTypeToString Method = "typeToString" - MethodIsContextSensitive Method = "isContextSensitive" - MethodGetReturnTypeOfSignature Method = "getReturnTypeOfSignature" - MethodGetRestTypeOfSignature Method = "getRestTypeOfSignature" - MethodGetTypePredicateOfSignature Method = "getTypePredicateOfSignature" - MethodGetBaseTypes Method = "getBaseTypes" - MethodGetPropertiesOfType Method = "getPropertiesOfType" - MethodGetApparentPropertiesOfType Method = "getApparentPropertiesOfType" - MethodGetApparentType Method = "getApparentType" - MethodGetReducedType Method = "getReducedType" - MethodGetPropertyOfType Method = "getPropertyOfType" - MethodGetTypeOfPropertyOfType Method = "getTypeOfPropertyOfType" - MethodGetIndexInfoOfType Method = "getIndexInfoOfType" - MethodGetIndexInfosOfType Method = "getIndexInfosOfType" - MethodGetConstraintOfTypeParameter Method = "getConstraintOfTypeParameter" - MethodGetDefaultFromTypeParameter Method = "getDefaultFromTypeParameter" - MethodGetBaseConstraintOfType Method = "getBaseConstraintOfType" - MethodGetTypeArguments Method = "getTypeArguments" - MethodGetImportAdderEdits Method = "getImportAdderEdits" - MethodGetTrueTypeOfConditionalType Method = "getTrueTypeOfConditionalType" - MethodGetFalseTypeOfConditionalType Method = "getFalseTypeOfConditionalType" - MethodGetConstantValue Method = "getConstantValue" - MethodGetSignatureFromDeclaration Method = "getSignatureFromDeclaration" - MethodGetExportSpecifierLocalTarget Method = "getExportSpecifierLocalTargetSymbol" - MethodGetAliasedSymbol Method = "getAliasedSymbol" - MethodGetImmediateAliasedSymbol Method = "getImmediateAliasedSymbol" - MethodGetTargetSymbol Method = "getTargetSymbol" - MethodGetMergedSymbol Method = "getMergedSymbol" - MethodGetSymbolOfNode Method = "getSymbolOfNode" - MethodGetSymbolOfDeclarationForChecker Method = "getSymbolOfDeclarationForChecker" - MethodGetParentOfSymbolForChecker Method = "getParentOfSymbolForChecker" - MethodGetExportSymbolOfSymbolForChecker Method = "getExportSymbolOfSymbolForChecker" - MethodGetFullyQualifiedName Method = "getFullyQualifiedName" - MethodGetExportsOfModule Method = "getExportsOfModule" - MethodGetMemberInModuleExports Method = "getMemberInModuleExports" - MethodGetJSDocTags Method = "getJsDocTags" - MethodGetDocumentationComment Method = "getDocumentationComment" - MethodIsArrayType Method = "isArrayType" - MethodIsReadonlySymbol Method = "isReadonlySymbol" + MethodGetContextualType Method = "getContextualType" + MethodGetContextualTypeForArgument Method = "getContextualTypeForArgument" + MethodGetAwaitedType Method = "getAwaitedType" + MethodGetBaseTypeOfLiteralType Method = "getBaseTypeOfLiteralType" + MethodGetNonNullableType Method = "getNonNullableType" + MethodGetNullableType Method = "getNullableType" + MethodGetStringLiteralType Method = "getStringLiteralType" + MethodGetNumberLiteralType Method = "getNumberLiteralType" + MethodGetBigIntLiteralType Method = "getBigIntLiteralType" + MethodGetFalseType Method = "getFalseType" + MethodGetTrueType Method = "getTrueType" + MethodGetAugmentedPropertiesOfType Method = "getAugmentedPropertiesOfType" + MethodGetJsxIntrinsicTagNamesAt Method = "getJsxIntrinsicTagNamesAt" + MethodGetPrivateIdentifierPropertyOfType Method = "getPrivateIdentifierPropertyOfType" + MethodGetTypeFromTypeNode Method = "getTypeFromTypeNode" + MethodGetWidenedType Method = "getWidenedType" + MethodGetParameterType Method = "getParameterType" + MethodGetTypeParameterAtPosition Method = "getTypeParameterAtPosition" + MethodIsArrayLikeType Method = "isArrayLikeType" + MethodIsTypeAssignableTo Method = "isTypeAssignableTo" + MethodGetShorthandAssignmentValueSymbol Method = "getShorthandAssignmentValueSymbol" + MethodGetTypeOfSymbolAtLocation Method = "getTypeOfSymbolAtLocation" + MethodTypeToTypeNode Method = "typeToTypeNode" + MethodSignatureToSignatureDeclaration Method = "signatureToSignatureDeclaration" + MethodTypeToString Method = "typeToString" + MethodIsContextSensitive Method = "isContextSensitive" + MethodGetReturnTypeOfSignature Method = "getReturnTypeOfSignature" + MethodGetRestTypeOfSignature Method = "getRestTypeOfSignature" + MethodGetTypePredicateOfSignature Method = "getTypePredicateOfSignature" + MethodGetBaseTypes Method = "getBaseTypes" + MethodGetPropertiesOfType Method = "getPropertiesOfType" + MethodGetApparentPropertiesOfType Method = "getApparentPropertiesOfType" + MethodGetApparentType Method = "getApparentType" + MethodGetReducedType Method = "getReducedType" + MethodGetPropertyOfType Method = "getPropertyOfType" + MethodGetTypeOfPropertyOfType Method = "getTypeOfPropertyOfType" + MethodGetIndexInfoOfType Method = "getIndexInfoOfType" + MethodGetIndexInfosOfType Method = "getIndexInfosOfType" + MethodGetConstraintOfTypeParameter Method = "getConstraintOfTypeParameter" + MethodGetDefaultFromTypeParameter Method = "getDefaultFromTypeParameter" + MethodGetBaseConstraintOfType Method = "getBaseConstraintOfType" + MethodGetTypeArguments Method = "getTypeArguments" + MethodGetImportAdderEdits Method = "getImportAdderEdits" + MethodGetTrueTypeOfConditionalType Method = "getTrueTypeOfConditionalType" + MethodGetFalseTypeOfConditionalType Method = "getFalseTypeOfConditionalType" + MethodGetConstantValue Method = "getConstantValue" + MethodGetSignatureFromDeclaration Method = "getSignatureFromDeclaration" + MethodGetExportSpecifierLocalTarget Method = "getExportSpecifierLocalTargetSymbol" + MethodGetAliasedSymbol Method = "getAliasedSymbol" + MethodGetImmediateAliasedSymbol Method = "getImmediateAliasedSymbol" + MethodGetTargetSymbol Method = "getTargetSymbol" + MethodGetMergedSymbol Method = "getMergedSymbol" + MethodGetSymbolOfNode Method = "getSymbolOfNode" + MethodGetSymbolOfDeclarationForChecker Method = "getSymbolOfDeclarationForChecker" + MethodGetParentOfSymbolForChecker Method = "getParentOfSymbolForChecker" + MethodGetExportSymbolOfSymbolForChecker Method = "getExportSymbolOfSymbolForChecker" + MethodGetFullyQualifiedName Method = "getFullyQualifiedName" + MethodGetExportsOfModule Method = "getExportsOfModule" + MethodGetMemberInModuleExports Method = "getMemberInModuleExports" + MethodGetJSDocTags Method = "getJsDocTags" + MethodGetDocumentationComment Method = "getDocumentationComment" + MethodIsArrayType Method = "isArrayType" + MethodIsReadonlySymbol Method = "isReadonlySymbol" + MethodIsImplementationOfOverload Method = "isImplementationOfOverload" + MethodGetPropertySymbolOfDestructuringAssignment Method = "getPropertySymbolOfDestructuringAssignment" + MethodGetAmbientModules Method = "getAmbientModules" // Reference methods MethodGetReferencesToSymbolInFile Method = "getReferencesToSymbolInFile" @@ -690,93 +702,105 @@ var unmarshalers = map[Method]func([]byte) (any, error){ MethodGetThisParameterOfSignature: unmarshallerFor[GetSignaturePropertyParams], MethodGetTargetOfSignature: unmarshallerFor[GetSignaturePropertyParams], - MethodGetContextualType: unmarshallerFor[GetContextualTypeParams], - MethodGetContextualTypeForArgument: unmarshallerFor[GetContextualTypeForArgumentParams], - MethodGetAwaitedType: unmarshallerFor[CheckerTypeParams], - MethodGetBaseTypeOfLiteralType: unmarshallerFor[GetBaseTypeOfLiteralTypeParams], - MethodGetNonNullableType: unmarshallerFor[GetTypePropertyParams], - MethodGetTypeFromTypeNode: unmarshallerFor[GetTypeFromTypeNodeParams], - MethodGetWidenedType: unmarshallerFor[GetWidenedTypeParams], - MethodGetParameterType: unmarshallerFor[GetParameterTypeParams], - MethodGetTypeParameterAtPosition: unmarshallerFor[GetParameterTypeParams], - MethodIsArrayLikeType: unmarshallerFor[IsArrayLikeTypeParams], - MethodIsTypeAssignableTo: unmarshallerFor[IsTypeAssignableToParams], - MethodGetShorthandAssignmentValueSymbol: unmarshallerFor[GetTypeAtLocationParams], - MethodGetTypeOfSymbolAtLocation: unmarshallerFor[GetTypeOfSymbolAtLocationParams], - MethodTypeToTypeNode: unmarshallerFor[TypeToTypeNodeParams], - MethodSignatureToSignatureDeclaration: unmarshallerFor[SignatureToSignatureDeclarationParams], - MethodTypeToString: unmarshallerFor[TypeToTypeNodeParams], - MethodIsContextSensitive: unmarshallerFor[GetContextualTypeParams], - MethodGetReturnTypeOfSignature: unmarshallerFor[GetSignaturePropertyParams], - MethodGetRestTypeOfSignature: unmarshallerFor[CheckerSignatureParams], - MethodGetTypePredicateOfSignature: unmarshallerFor[CheckerSignatureParams], - MethodGetBaseTypes: unmarshallerFor[CheckerTypeParams], - MethodGetPropertiesOfType: unmarshallerFor[CheckerTypeParams], - MethodGetApparentPropertiesOfType: unmarshallerFor[GetTypePropertyParams], - MethodGetApparentType: unmarshallerFor[GetTypePropertyParams], - MethodGetReducedType: unmarshallerFor[GetTypePropertyParams], - MethodGetPropertyOfType: unmarshallerFor[GetPropertyOfTypeParams], - MethodGetTypeOfPropertyOfType: unmarshallerFor[GetPropertyOfTypeParams], - MethodGetIndexInfoOfType: unmarshallerFor[GetIndexInfoOfTypeParams], - MethodGetIndexInfosOfType: unmarshallerFor[CheckerTypeParams], - MethodGetConstraintOfTypeParameter: unmarshallerFor[GetTypePropertyParams], - MethodGetBaseConstraintOfType: unmarshallerFor[CheckerTypeParams], - MethodGetDefaultFromTypeParameter: unmarshallerFor[GetTypePropertyParams], - MethodGetTypeArguments: unmarshallerFor[CheckerTypeParams], - MethodGetImportAdderEdits: unmarshallerFor[GetImportAdderEditsParams], - MethodGetConstantValue: unmarshallerFor[CheckerNodeParams], - MethodGetSignatureFromDeclaration: unmarshallerFor[CheckerNodeParams], - MethodGetExportSpecifierLocalTarget: unmarshallerFor[CheckerNodeParams], - MethodGetAliasedSymbol: unmarshallerFor[CheckerSymbolParams], - MethodGetImmediateAliasedSymbol: unmarshallerFor[CheckerSymbolParams], - MethodGetTargetSymbol: unmarshallerFor[CheckerSymbolParams], - MethodGetMergedSymbol: unmarshallerFor[CheckerSymbolParams], - MethodGetSymbolOfNode: unmarshallerFor[CheckerNodeParams], - MethodGetSymbolOfDeclarationForChecker: unmarshallerFor[CheckerNodeParams], - MethodGetParentOfSymbolForChecker: unmarshallerFor[CheckerSymbolParams], - MethodGetExportSymbolOfSymbolForChecker: unmarshallerFor[CheckerSymbolParams], - MethodGetFullyQualifiedName: unmarshallerFor[CheckerSymbolParams], - MethodGetExportsOfModule: unmarshallerFor[CheckerSymbolParams], - MethodGetMemberInModuleExports: unmarshallerFor[GetMemberInModuleExportsParams], - MethodGetJSDocTags: unmarshallerFor[CheckerSymbolParams], - MethodGetDocumentationComment: unmarshallerFor[CheckerSymbolParams], - MethodIsArrayType: unmarshallerFor[CheckerTypeParams], - MethodIsReadonlySymbol: unmarshallerFor[CheckerSymbolParams], - MethodGetReferencesToSymbolInFile: unmarshallerFor[GetReferencesToSymbolInFileParams], - MethodGetReferencedSymbolsForNode: unmarshallerFor[GetReferencedSymbolsForNodeParams], - MethodGetSignatureUsages: unmarshallerFor[GetSignatureUsagesParams], - MethodGetCompletionsAtPosition: unmarshallerFor[GetCompletionsAtPositionParams], - MethodFormatNodeForInsertion: unmarshallerFor[FormatNodeForInsertionParams], - MethodPrintNode: unmarshallerFor[PrintNodeParams], - MethodEmit: unmarshallerFor[EmitParams], - MethodEmitToString: unmarshallerFor[EmitParams], - MethodGetJavaScriptEmit: unmarshallerFor[SelectedFilesEmitParams], - MethodGetDeclarationEmit: unmarshallerFor[SelectedFilesEmitParams], - MethodGetAnyType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetStringType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetNumberType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetBooleanType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetVoidType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetUndefinedType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetNullType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetNeverType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetUnknownType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetBigIntType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetESSymbolType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetNonPrimitiveType: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetWellKnownSymbols: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetWellKnownSignatures: unmarshallerFor[GetIntrinsicTypeParams], - MethodGetSyntacticDiagnostics: unmarshallerFor[GetDiagnosticsParams], - MethodGetBindDiagnostics: unmarshallerFor[GetDiagnosticsParams], - MethodGetSemanticDiagnostics: unmarshallerFor[GetDiagnosticsParams], - MethodGetSuggestionDiagnostics: unmarshallerFor[GetDiagnosticsParams], - MethodGetDeclarationDiagnostics: unmarshallerFor[GetDiagnosticsParams], - MethodGetProgramDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], - MethodGetGlobalDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], - MethodGetConfigFileParsingDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], - MethodStartCPUProfile: unmarshallerFor[ProfileParams], - MethodStopCPUProfile: noParams, - MethodSaveHeapProfile: unmarshallerFor[ProfileParams], + MethodGetContextualType: unmarshallerFor[GetContextualTypeParams], + MethodGetContextualTypeForArgument: unmarshallerFor[GetContextualTypeForArgumentParams], + MethodGetAwaitedType: unmarshallerFor[CheckerTypeParams], + MethodGetBaseTypeOfLiteralType: unmarshallerFor[GetBaseTypeOfLiteralTypeParams], + MethodGetNonNullableType: unmarshallerFor[GetTypePropertyParams], + MethodGetNullableType: unmarshallerFor[GetNullableTypeParams], + MethodGetStringLiteralType: unmarshallerFor[GetStringLiteralTypeParams], + MethodGetNumberLiteralType: unmarshallerFor[GetNumberLiteralTypeParams], + MethodGetBigIntLiteralType: unmarshallerFor[GetBigIntLiteralTypeParams], + MethodGetFalseType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetTrueType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetAugmentedPropertiesOfType: unmarshallerFor[GetTypePropertyParams], + MethodGetJsxIntrinsicTagNamesAt: unmarshallerFor[CheckerNodeParams], + MethodGetPrivateIdentifierPropertyOfType: unmarshallerFor[GetPrivateIdentifierPropertyOfTypeParams], + MethodGetTypeFromTypeNode: unmarshallerFor[GetTypeFromTypeNodeParams], + MethodGetWidenedType: unmarshallerFor[GetWidenedTypeParams], + MethodGetParameterType: unmarshallerFor[GetParameterTypeParams], + MethodGetTypeParameterAtPosition: unmarshallerFor[GetParameterTypeParams], + MethodIsArrayLikeType: unmarshallerFor[IsArrayLikeTypeParams], + MethodIsTypeAssignableTo: unmarshallerFor[IsTypeAssignableToParams], + MethodGetShorthandAssignmentValueSymbol: unmarshallerFor[GetTypeAtLocationParams], + MethodGetTypeOfSymbolAtLocation: unmarshallerFor[GetTypeOfSymbolAtLocationParams], + MethodTypeToTypeNode: unmarshallerFor[TypeToTypeNodeParams], + MethodSignatureToSignatureDeclaration: unmarshallerFor[SignatureToSignatureDeclarationParams], + MethodTypeToString: unmarshallerFor[TypeToTypeNodeParams], + MethodIsContextSensitive: unmarshallerFor[GetContextualTypeParams], + MethodGetReturnTypeOfSignature: unmarshallerFor[GetSignaturePropertyParams], + MethodGetRestTypeOfSignature: unmarshallerFor[CheckerSignatureParams], + MethodGetTypePredicateOfSignature: unmarshallerFor[CheckerSignatureParams], + MethodGetBaseTypes: unmarshallerFor[CheckerTypeParams], + MethodGetPropertiesOfType: unmarshallerFor[CheckerTypeParams], + MethodGetApparentPropertiesOfType: unmarshallerFor[GetTypePropertyParams], + MethodGetApparentType: unmarshallerFor[GetTypePropertyParams], + MethodGetReducedType: unmarshallerFor[GetTypePropertyParams], + MethodGetPropertyOfType: unmarshallerFor[GetPropertyOfTypeParams], + MethodGetTypeOfPropertyOfType: unmarshallerFor[GetPropertyOfTypeParams], + MethodGetIndexInfoOfType: unmarshallerFor[GetIndexInfoOfTypeParams], + MethodGetIndexInfosOfType: unmarshallerFor[CheckerTypeParams], + MethodGetConstraintOfTypeParameter: unmarshallerFor[GetTypePropertyParams], + MethodGetBaseConstraintOfType: unmarshallerFor[CheckerTypeParams], + MethodGetDefaultFromTypeParameter: unmarshallerFor[GetTypePropertyParams], + MethodGetTypeArguments: unmarshallerFor[CheckerTypeParams], + MethodGetImportAdderEdits: unmarshallerFor[GetImportAdderEditsParams], + MethodGetConstantValue: unmarshallerFor[CheckerNodeParams], + MethodGetSignatureFromDeclaration: unmarshallerFor[CheckerNodeParams], + MethodGetExportSpecifierLocalTarget: unmarshallerFor[CheckerNodeParams], + MethodGetAliasedSymbol: unmarshallerFor[CheckerSymbolParams], + MethodGetImmediateAliasedSymbol: unmarshallerFor[CheckerSymbolParams], + MethodGetTargetSymbol: unmarshallerFor[CheckerSymbolParams], + MethodGetMergedSymbol: unmarshallerFor[CheckerSymbolParams], + MethodGetSymbolOfNode: unmarshallerFor[CheckerNodeParams], + MethodGetSymbolOfDeclarationForChecker: unmarshallerFor[CheckerNodeParams], + MethodGetParentOfSymbolForChecker: unmarshallerFor[CheckerSymbolParams], + MethodGetExportSymbolOfSymbolForChecker: unmarshallerFor[CheckerSymbolParams], + MethodGetFullyQualifiedName: unmarshallerFor[CheckerSymbolParams], + MethodGetExportsOfModule: unmarshallerFor[CheckerSymbolParams], + MethodGetMemberInModuleExports: unmarshallerFor[GetMemberInModuleExportsParams], + MethodGetJSDocTags: unmarshallerFor[CheckerSymbolParams], + MethodGetDocumentationComment: unmarshallerFor[CheckerSymbolParams], + MethodIsArrayType: unmarshallerFor[CheckerTypeParams], + MethodIsReadonlySymbol: unmarshallerFor[CheckerSymbolParams], + MethodIsImplementationOfOverload: unmarshallerFor[CheckerNodeParams], + MethodGetPropertySymbolOfDestructuringAssignment: unmarshallerFor[CheckerNodeParams], + MethodGetAmbientModules: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetReferencesToSymbolInFile: unmarshallerFor[GetReferencesToSymbolInFileParams], + MethodGetReferencedSymbolsForNode: unmarshallerFor[GetReferencedSymbolsForNodeParams], + MethodGetSignatureUsages: unmarshallerFor[GetSignatureUsagesParams], + MethodGetCompletionsAtPosition: unmarshallerFor[GetCompletionsAtPositionParams], + MethodPrintNode: unmarshallerFor[PrintNodeParams], + MethodFormatNodeForInsertion: unmarshallerFor[FormatNodeForInsertionParams], + MethodEmit: unmarshallerFor[EmitParams], + MethodEmitToString: unmarshallerFor[EmitParams], + MethodGetJavaScriptEmit: unmarshallerFor[SelectedFilesEmitParams], + MethodGetDeclarationEmit: unmarshallerFor[SelectedFilesEmitParams], + MethodGetAnyType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetStringType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetNumberType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetBooleanType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetVoidType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetUndefinedType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetNullType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetNeverType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetUnknownType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetBigIntType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetESSymbolType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetNonPrimitiveType: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetWellKnownSymbols: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetWellKnownSignatures: unmarshallerFor[GetIntrinsicTypeParams], + MethodGetSyntacticDiagnostics: unmarshallerFor[GetDiagnosticsParams], + MethodGetBindDiagnostics: unmarshallerFor[GetDiagnosticsParams], + MethodGetSemanticDiagnostics: unmarshallerFor[GetDiagnosticsParams], + MethodGetSuggestionDiagnostics: unmarshallerFor[GetDiagnosticsParams], + MethodGetDeclarationDiagnostics: unmarshallerFor[GetDiagnosticsParams], + MethodGetProgramDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], + MethodGetGlobalDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], + MethodGetConfigFileParsingDiagnostics: unmarshallerFor[GetProjectDiagnosticsParams], + MethodStartCPUProfile: unmarshallerFor[ProfileParams], + MethodStopCPUProfile: noParams, + MethodSaveHeapProfile: unmarshallerFor[ProfileParams], } type ParseConfigFileParams struct { @@ -1659,21 +1683,53 @@ type GetNonNullableTypeParams struct { Type TypeID `json:"type"` } -// GetTypeFromTypeNodeParams are the parameters for the getTypeFromTypeNode method. +type GetNullableTypeParams struct { + Snapshot SnapshotID `json:"snapshot"` + Project project.Handle `json:"project"` + Type TypeID `json:"type"` + Flags int32 `json:"flags"` +} + +type GetStringLiteralTypeParams struct { + Snapshot SnapshotID `json:"snapshot"` + Project project.Handle `json:"project"` + Value string `json:"value"` +} + +type GetNumberLiteralTypeParams struct { + Snapshot SnapshotID `json:"snapshot"` + Project project.Handle `json:"project"` + Value float64 `json:"value"` +} + +// Base10Value is the absolute value in base 10 with no leading zeros (empty for zero). +type GetBigIntLiteralTypeParams struct { + Snapshot SnapshotID `json:"snapshot"` + Project project.Handle `json:"project"` + Negative bool `json:"negative,omitempty"` + Base10Value string `json:"base10Value,omitempty"` +} + +type GetPrivateIdentifierPropertyOfTypeParams struct { + Snapshot SnapshotID `json:"snapshot"` + Project project.Handle `json:"project"` + Type TypeID `json:"type"` + Name string `json:"name"` + Location NodeHandle `json:"location"` +} + type GetTypeFromTypeNodeParams struct { Snapshot SnapshotID `json:"snapshot"` Project project.Handle `json:"project"` Location NodeHandle `json:"location"` } -// GetWidenedTypeParams are the parameters for the getWidenedType method. type GetWidenedTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project project.Handle `json:"project"` Type TypeID `json:"type"` } -// GetParameterTypeParams are the parameters for the getParameterType method. type GetParameterTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project project.Handle `json:"project"` @@ -1681,14 +1737,12 @@ type GetParameterTypeParams struct { Index int32 `json:"index"` } -// IsArrayLikeTypeParams checks whether a type is array-like. type IsArrayLikeTypeParams struct { Snapshot SnapshotID `json:"snapshot"` Project project.Handle `json:"project"` Type TypeID `json:"type"` } -// IsTypeAssignableToParams checks assignability between two types. type IsTypeAssignableToParams struct { Snapshot SnapshotID `json:"snapshot"` Project project.Handle `json:"project"` diff --git a/tsc/internal/api/session.go b/tsc/internal/api/session.go index a434123b2b54d..aa2187f6335e4 100644 --- a/tsc/internal/api/session.go +++ b/tsc/internal/api/session.go @@ -1077,6 +1077,20 @@ func (s *Session) HandleRequest(ctx context.Context, method string, params json. return s.handleGetBaseTypeOfLiteralType(ctx, parsed.(*GetBaseTypeOfLiteralTypeParams)) case string(MethodGetNonNullableType): return s.handleGetNonNullableType(ctx, parsed.(*GetTypePropertyParams)) + case string(MethodGetNullableType): + return s.handleGetNullableType(ctx, parsed.(*GetNullableTypeParams)) + case string(MethodGetStringLiteralType): + return s.handleGetStringLiteralType(ctx, parsed.(*GetStringLiteralTypeParams)) + case string(MethodGetNumberLiteralType): + return s.handleGetNumberLiteralType(ctx, parsed.(*GetNumberLiteralTypeParams)) + case string(MethodGetBigIntLiteralType): + return s.handleGetBigIntLiteralType(ctx, parsed.(*GetBigIntLiteralTypeParams)) + case string(MethodGetAugmentedPropertiesOfType): + return s.handleGetAugmentedPropertiesOfType(ctx, parsed.(*GetTypePropertyParams)) + case string(MethodGetJsxIntrinsicTagNamesAt): + return s.handleGetJsxIntrinsicTagNamesAt(ctx, parsed.(*CheckerNodeParams)) + case string(MethodGetPrivateIdentifierPropertyOfType): + return s.handleGetPrivateIdentifierPropertyOfType(ctx, parsed.(*GetPrivateIdentifierPropertyOfTypeParams)) case string(MethodGetTypeFromTypeNode): return s.handleGetTypeFromTypeNode(ctx, parsed.(*GetTypeFromTypeNodeParams)) case string(MethodGetWidenedType): @@ -1181,6 +1195,12 @@ func (s *Session) HandleRequest(ctx context.Context, method string, params json. return s.handleIsArrayType(ctx, parsed.(*CheckerTypeParams)) case string(MethodIsReadonlySymbol): return s.handleIsReadonlySymbol(ctx, parsed.(*CheckerSymbolParams)) + case string(MethodIsImplementationOfOverload): + return s.handleIsImplementationOfOverload(ctx, parsed.(*CheckerNodeParams)) + case string(MethodGetPropertySymbolOfDestructuringAssignment): + return s.handleGetPropertySymbolOfDestructuringAssignment(ctx, parsed.(*CheckerNodeParams)) + case string(MethodGetAmbientModules): + return s.handleGetAmbientModules(ctx, parsed.(*GetIntrinsicTypeParams)) case string(MethodGetAnyType): return s.handleGetIntrinsicType(ctx, parsed.(*GetIntrinsicTypeParams), (*checker.Checker).GetAnyType) case string(MethodGetStringType): @@ -1205,6 +1225,10 @@ func (s *Session) HandleRequest(ctx context.Context, method string, params json. return s.handleGetIntrinsicType(ctx, parsed.(*GetIntrinsicTypeParams), (*checker.Checker).GetESSymbolType) case string(MethodGetNonPrimitiveType): return s.handleGetIntrinsicType(ctx, parsed.(*GetIntrinsicTypeParams), (*checker.Checker).GetNonPrimitiveType) + case string(MethodGetFalseType): + return s.handleGetIntrinsicType(ctx, parsed.(*GetIntrinsicTypeParams), (*checker.Checker).GetFalseType) + case string(MethodGetTrueType): + return s.handleGetIntrinsicType(ctx, parsed.(*GetIntrinsicTypeParams), (*checker.Checker).GetTrueType) case string(MethodGetWellKnownSymbols): return s.handleGetWellKnownSymbols(ctx, parsed.(*GetIntrinsicTypeParams)) case string(MethodGetWellKnownSignatures): @@ -3682,7 +3706,6 @@ func (s *Session) handleGetAwaitedType(ctx context.Context, params *CheckerTypeP return setup.sd.newTypeResponse(setup.projectID, setup.checker.GetAwaitedType(t), setup.checker), nil } -// handleGetBaseTypeOfLiteralType returns the base type of a literal type (e.g. number for 42). func (s *Session) handleGetBaseTypeOfLiteralType(ctx context.Context, params *GetBaseTypeOfLiteralTypeParams) (*TypeResponse, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -3714,7 +3737,142 @@ func (s *Session) handleGetNonNullableType(ctx context.Context, params *GetTypeP return setup.sd.newTypeResponse(setup.projectID, setup.checker.GetNonNullableType(t), setup.checker), nil } -// handleGetTypeFromTypeNode returns the type for a type node. +func (s *Session) handleGetNullableType(ctx context.Context, params *GetNullableTypeParams) (*TypeResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + t, err := setup.resolveTypeHandle(params.Type) + if err != nil { + return nil, err + } + + result := setup.checker.GetNullableType(t, checker.TypeFlags(params.Flags)) + return setup.sd.newTypeResponse(setup.projectID, result, setup.checker), nil +} + +func (s *Session) handleGetStringLiteralType(ctx context.Context, params *GetStringLiteralTypeParams) (*TypeResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + t := setup.checker.GetStringLiteralType(params.Value) + return setup.sd.newTypeResponse(setup.projectID, t, setup.checker), nil +} + +func (s *Session) handleGetNumberLiteralType(ctx context.Context, params *GetNumberLiteralTypeParams) (*TypeResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + t := setup.checker.GetNumberLiteralType(jsnum.Number(params.Value)) + return setup.sd.newTypeResponse(setup.projectID, t, setup.checker), nil +} + +func (s *Session) handleGetBigIntLiteralType(ctx context.Context, params *GetBigIntLiteralTypeParams) (*TypeResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + value := jsnum.PseudoBigInt{Negative: params.Negative, Base10Value: params.Base10Value} + t := setup.checker.GetBigIntLiteralType(value) + return setup.sd.newTypeResponse(setup.projectID, t, setup.checker), nil +} + +// handleGetAugmentedPropertiesOfType returns the augmented properties of a type: its properties, +// plus (when the type has call or construct signatures) the properties of the global +// CallableFunction/NewableFunction interfaces not already present. +// @gen-proto-nullable +func (s *Session) handleGetAugmentedPropertiesOfType(ctx context.Context, params *GetTypePropertyParams) ([]*SymbolResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + t, err := setup.resolveTypeHandle(params.Type) + if err != nil { + return nil, err + } + + props := setup.checker.GetApparentProperties(t) + if len(props) == 0 { + return nil, nil + } + + results := make([]*SymbolResponse, len(props)) + for i, prop := range props { + results[i] = setup.newSymbolResponse(prop) + } + return results, nil +} + +// @gen-proto-nullable +func (s *Session) handleGetJsxIntrinsicTagNamesAt(ctx context.Context, params *CheckerNodeParams) ([]*SymbolResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + node, err := setup.sd.resolveNodeHandle(setup.program, params.Location) + if err != nil { + return nil, err + } + if node == nil { + return nil, nil + } + + props := setup.checker.GetJsxIntrinsicTagNamesAt(node) + if len(props) == 0 { + return nil, nil + } + + results := make([]*SymbolResponse, len(props)) + for i, prop := range props { + results[i] = setup.newSymbolResponse(prop) + } + return results, nil +} + +// handleGetPrivateIdentifierPropertyOfType looks up a private identifier (e.g. "#foo") lexically in +// scope at the given location, and if found, returns the corresponding property of the type. +func (s *Session) handleGetPrivateIdentifierPropertyOfType(ctx context.Context, params *GetPrivateIdentifierPropertyOfTypeParams) (*SymbolResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + t, err := setup.resolveTypeHandle(params.Type) + if err != nil { + return nil, err + } + + node, err := setup.sd.resolveNodeHandle(setup.program, params.Location) + if err != nil { + return nil, err + } + if node == nil { + return nil, nil + } + + symbol := setup.checker.GetPrivateIdentifierPropertyOfType(t, params.Name, node) + if symbol == nil { + return nil, nil + } + + return setup.newSymbolResponse(symbol), nil +} + func (s *Session) handleGetTypeFromTypeNode(ctx context.Context, params *GetTypeFromTypeNodeParams) (*TypeResponse, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -3730,7 +3888,6 @@ func (s *Session) handleGetTypeFromTypeNode(ctx context.Context, params *GetType return setup.sd.newTypeResponse(setup.projectID, setup.checker.GetTypeFromTypeNode(node), setup.checker), nil } -// handleGetWidenedType returns the widened type. func (s *Session) handleGetWidenedType(ctx context.Context, params *GetWidenedTypeParams) (*TypeResponse, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -3746,7 +3903,6 @@ func (s *Session) handleGetWidenedType(ctx context.Context, params *GetWidenedTy return setup.sd.newTypeResponse(setup.projectID, setup.checker.GetWidenedType(t), setup.checker), nil } -// handleGetParameterType returns the type of a parameter at a given index in a signature. func (s *Session) handleGetParameterType(ctx context.Context, params *GetParameterTypeParams) (*TypeResponse, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -3783,7 +3939,6 @@ func (s *Session) handleGetTypeParameterAtPosition(ctx context.Context, params * return setup.sd.newTypeResponse(setup.projectID, setup.checker.GetTypeParameterAtPosition(sig, int(params.Index)), setup.checker), nil } -// handleIsArrayLikeType returns whether a type is array-like. func (s *Session) handleIsArrayLikeType(ctx context.Context, params *IsArrayLikeTypeParams) (bool, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -3799,7 +3954,6 @@ func (s *Session) handleIsArrayLikeType(ctx context.Context, params *IsArrayLike return setup.checker.IsArrayLikeType(t), nil } -// handleIsTypeAssignableTo returns whether source is assignable to target. func (s *Session) handleIsTypeAssignableTo(ctx context.Context, params *IsTypeAssignableToParams) (bool, error) { setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) if err != nil { @@ -4386,6 +4540,72 @@ func (s *Session) handleIsReadonlySymbol(ctx context.Context, params *CheckerSym return setup.checker.IsReadonlySymbol(symbol), nil } +// handleIsImplementationOfOverload returns whether a function-like declaration is the implementation signature of a set of overloads. +func (s *Session) handleIsImplementationOfOverload(ctx context.Context, params *CheckerNodeParams) (bool, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return false, err + } + defer setup.done() + + node, err := setup.sd.resolveNodeHandle(setup.program, params.Location) + if err != nil { + return false, err + } + if node == nil { + return false, nil + } + + return setup.checker.NewEmitResolver(printer.NewEmitContext()).IsImplementationOfOverload(node), nil +} + +// @gen-proto-nullable +func (s *Session) handleGetPropertySymbolOfDestructuringAssignment(ctx context.Context, params *CheckerNodeParams) (*SymbolResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + node, err := setup.sd.resolveNodeHandle(setup.program, params.Location) + if err != nil { + return nil, err + } + if node == nil { + return nil, nil + } + + symbol := setup.checker.GetPropertySymbolOfDestructuringAssignment(node) + if symbol == nil { + return nil, nil + } + + return setup.newSymbolResponse(symbol), nil +} + +// handleGetAmbientModules returns all ambient modules declared in the program `declare module "foo" { ... }`. +// @gen-proto-nullable +func (s *Session) handleGetAmbientModules(ctx context.Context, params *GetIntrinsicTypeParams) ([]*SymbolResponse, error) { + setup, err := s.setupChecker(ctx, params.Snapshot, params.Project) + if err != nil { + return nil, err + } + defer setup.done() + + modules := setup.checker.GetAmbientModules() + if len(modules) == 0 { + return nil, nil + } + slices.SortFunc(modules, setup.checker.CompareSymbols) + + results := make([]*SymbolResponse, len(modules)) + for i, module := range modules { + results[i] = setup.newSymbolResponse(module) + } + + return results, nil +} + // handleGetBaseTypes returns the base types of an interface/class type. // @gen-proto-nullable func (s *Session) handleGetBaseTypes(ctx context.Context, params *CheckerTypeParams) ([]*TypeResponse, error) { diff --git a/tsc/internal/checker/exports.go b/tsc/internal/checker/exports.go index f03be066141dc..bf54fcaaa171f 100644 --- a/tsc/internal/checker/exports.go +++ b/tsc/internal/checker/exports.go @@ -5,6 +5,7 @@ import ( "github.com/microsoft/TypeScript/tsc/internal/ast" "github.com/microsoft/TypeScript/tsc/internal/diagnostics" + "github.com/microsoft/TypeScript/tsc/internal/jsnum" ) func (c *Checker) GetStringType() *Type { @@ -59,10 +60,45 @@ func (c *Checker) GetNonPrimitiveType() *Type { return c.nonPrimitiveType } +func (c *Checker) GetStringLiteralType(value string) *Type { + return c.getStringLiteralType(value) +} + +func (c *Checker) GetNumberLiteralType(value jsnum.Number) *Type { + return c.getNumberLiteralType(value) +} + +func (c *Checker) GetBigIntLiteralType(value jsnum.PseudoBigInt) *Type { + return c.getBigIntLiteralType(value) +} + +func (c *Checker) GetNullableType(t *Type, flags TypeFlags) *Type { + return c.getNullableType(t, flags) +} + +func (c *Checker) GetFalseType() *Type { + return c.regularFalseType +} + +func (c *Checker) GetTrueType() *Type { + return c.regularTrueType +} + func (c *Checker) GetBaseTypeOfLiteralType(t *Type) *Type { return c.getBaseTypeOfLiteralType(t) } +// GetPrivateIdentifierPropertyOfType looks up a private identifier named name (e.g. "#foo", including +// the leading '#') lexically in scope at location, and if it resolves to a symbol, returns the +// corresponding property of leftType (or nil if leftType has no such property). +func (c *Checker) GetPrivateIdentifierPropertyOfType(leftType *Type, name string, location *ast.Node) *ast.Symbol { + lexicallyScopedIdentifier := c.lookupSymbolForPrivateIdentifierDeclaration(name, location) + if lexicallyScopedIdentifier == nil { + return nil + } + return c.getPrivateIdentifierPropertyOfType(leftType, lexicallyScopedIdentifier) +} + func (c *Checker) GetUnknownSymbol() *ast.Symbol { return c.unknownSymbol }