Merge branch 'master' of github.com:Microsoft/TypeScript into rest-param-destructuring

This commit is contained in:
Klaus Meinhardt committed 2018-08-01 10:05:11 +02:00
commit 5f3f6cc5aa
3966 files changed
+6840 -59992

No files matched your search

+1
View File
@@ -358,3 +358,4 @@ Vyacheslav Pukhanov <vyacheslav.pukhanov@gmail.com>
dangoo <daniel.gooss@sinnerschrader.com> # Daniel Gooss
krk <keremkat@gmail.com> # Kerem Kat
micnic <micnic90@gmail.com> # Nicu Micleușanu
rflorian <rflorian@users.noreply.github.com> # @rflorian
+1 -1
View File
@@ -61,7 +61,7 @@ Design changes will not be accepted at this time. If you have a design change pr
You will need to complete a Contributor License Agreement (CLA). Briefly, this agreement testifies that you are granting us permission to use the submitted change according to the terms of the project's license, and that the work being submitted is under appropriate copyright.
Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. Alternatively, download the agreement ([Microsoft Contribution License Agreement.docx](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=822190) or [Microsoft Contribution License Agreement.pdf](https://www.codeplex.com/Download?ProjectName=typescript&DownloadId=921298)), sign, scan, and email it back to <cla@microsoft.com>. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request.
Please submit a Contributor License Agreement (CLA) before submitting a pull request. You may visit https://cla.microsoft.com to sign digitally. Alternatively, download the agreement ([Microsoft Contribution License Agreement.pdf](https://opensource.microsoft.com/pdf/microsoft-contribution-license-agreement.pdf)), sign, scan, and email it back to <cla@microsoft.com>. Be sure to include your github user name along with the agreement. Once we have received the signed CLA, we'll review the request.
## Housekeeping
+4 -1
View File
@@ -2072,7 +2072,10 @@ namespace ts {
if (isSpecialPropertyDeclaration(node as PropertyAccessExpression)) {
bindSpecialPropertyDeclaration(node as PropertyAccessExpression);
}
if (isInJavaScriptFile(node) && isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression)) {
if (isInJavaScriptFile(node) &&
file.commonJsModuleIndicator &&
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
!lookupSymbolForNameWorker(container, "module" as __String)) {
declareSymbol(container.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes);
}
+352 -235
View File
@@ -198,13 +198,10 @@ namespace ts {
},
isContextSensitive,
getFullyQualifiedName,
getResolvedSignature: (nodeIn, candidatesOutArray, theArgumentCount) => {
const node = getParseTreeNode(nodeIn, isCallLikeExpression);
apparentArgumentCount = theArgumentCount;
const res = node ? getResolvedSignature(node, candidatesOutArray) : undefined;
apparentArgumentCount = undefined;
return res;
},
getResolvedSignature: (node, candidatesOutArray, agumentCount) =>
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ false),
getResolvedSignatureForSignatureHelp: (node, candidatesOutArray, agumentCount) =>
getResolvedSignatureWorker(node, candidatesOutArray, agumentCount, /*isForSignatureHelp*/ true),
getConstantValue: nodeIn => {
const node = getParseTreeNode(nodeIn, canHaveConstantValue);
return node ? getConstantValue(node) : undefined;
@@ -354,6 +351,14 @@ namespace ts {
}
};
function getResolvedSignatureWorker(nodeIn: CallLikeExpression, candidatesOutArray: Signature[] | undefined, argumentCount: number | undefined, isForSignatureHelp: boolean): Signature | undefined {
const node = getParseTreeNode(nodeIn, isCallLikeExpression);
apparentArgumentCount = argumentCount;
const res = node ? getResolvedSignature(node, candidatesOutArray, isForSignatureHelp) : undefined;
apparentArgumentCount = undefined;
return res;
}
const tupleTypes = createMap<GenericType>();
const unionTypes = createMap<UnionType>();
const intersectionTypes = createMap<IntersectionType>();
@@ -1834,7 +1839,7 @@ namespace ts {
if (symbol.flags & SymbolFlags.Variable) {
const typeAnnotation = (<VariableDeclaration>symbol.valueDeclaration).type;
if (typeAnnotation) {
return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name)); // TODO: GH#18217
return resolveSymbol(getPropertyOfType(getTypeFromTypeNode(typeAnnotation), name));
}
}
}
@@ -3883,14 +3888,15 @@ namespace ts {
const links = getSymbolLinks(symbol);
let specifier = links.specifierCache && links.specifierCache.get(contextFile.path);
if (!specifier) {
specifier = flatten(moduleSpecifiers.getModuleSpecifiers(
specifier = moduleSpecifiers.getModuleSpecifierForDeclarationFile(
symbol,
compilerOptions,
contextFile,
context.tracker.moduleResolverHost,
context.tracker.moduleResolverHost.getSourceFiles!(), // TODO: GH#18217
{ importModuleSpecifierPreference: "non-relative" }
))[0];
{ importModuleSpecifierPreference: "non-relative" },
host.redirectTargetsMap,
);
links.specifierCache = links.specifierCache || createMap();
links.specifierCache.set(contextFile.path, specifier);
}
@@ -4988,86 +4994,87 @@ namespace ts {
function getTypeOfVariableOrParameterOrProperty(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.type) {
// Handle prototype property
if (symbol.flags & SymbolFlags.Prototype) {
return links.type = getTypeOfPrototypeProperty(symbol);
}
// CommonsJS require and module both have type any.
if (symbol === requireSymbol) {
return links.type = anyType;
}
if (symbol.flags & SymbolFlags.ModuleExports) {
const fileSymbol = getSymbolOfNode(getSourceFileOfNode(symbol.valueDeclaration));
const members = createSymbolTable();
members.set("exports" as __String, fileSymbol);
return links.type = createAnonymousType(symbol, members, emptyArray, emptyArray, undefined, undefined);
}
// Handle catch clause variables
const declaration = symbol.valueDeclaration;
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
return links.type = anyType;
}
// Handle export default expressions
if (isSourceFile(declaration)) {
const jsonSourceFile = cast(declaration, isJsonSourceFile);
return links.type = jsonSourceFile.statements.length ? checkExpression(jsonSourceFile.statements[0].expression) : emptyObjectType;
}
if (declaration.kind === SyntaxKind.ExportAssignment) {
return links.type = checkExpression((<ExportAssignment>declaration).expression);
}
// Handle variable, parameter or property
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
let type = getJSSpecialType(symbol, declaration);
if (!type) {
if (isJSDocPropertyLikeTag(declaration)
|| isPropertyAccessExpression(declaration)
|| isIdentifier(declaration)
|| isClassDeclaration(declaration)
|| isFunctionDeclaration(declaration)
|| (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
|| isMethodSignature(declaration)) {
// Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
return getTypeOfFuncClassEnumModule(symbol);
}
type = tryGetTypeFromEffectiveTypeNode(declaration) || anyType;
}
else if (isPropertyAssignment(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration);
}
else if (isJsxAttribute(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration);
}
else if (isShorthandPropertyAssignment(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal);
}
else if (isObjectLiteralMethod(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal);
}
else if (isParameter(declaration)
|| isPropertyDeclaration(declaration)
|| isPropertySignature(declaration)
|| isVariableDeclaration(declaration)
|| isBindingElement(declaration)) {
type = getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
}
else {
return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
}
}
if (!popTypeResolution()) {
type = reportCircularityError(symbol);
}
links.type = type;
}
return links.type;
return links.type || (links.type = getTypeOfVariableOrParameterOrPropertyWorker(symbol));
}
function getTypeOfVariableOrParameterOrPropertyWorker(symbol: Symbol) {
// Handle prototype property
if (symbol.flags & SymbolFlags.Prototype) {
return getTypeOfPrototypeProperty(symbol);
}
// CommonsJS require and module both have type any.
if (symbol === requireSymbol) {
return anyType;
}
if (symbol.flags & SymbolFlags.ModuleExports) {
const fileSymbol = getSymbolOfNode(getSourceFileOfNode(symbol.valueDeclaration));
const members = createSymbolTable();
members.set("exports" as __String, fileSymbol);
return createAnonymousType(symbol, members, emptyArray, emptyArray, undefined, undefined);
}
// Handle catch clause variables
const declaration = symbol.valueDeclaration;
if (isCatchClauseVariableDeclarationOrBindingElement(declaration)) {
return anyType;
}
// Handle export default expressions
if (isSourceFile(declaration)) {
const jsonSourceFile = cast(declaration, isJsonSourceFile);
return jsonSourceFile.statements.length ? checkExpression(jsonSourceFile.statements[0].expression) : emptyObjectType;
}
if (declaration.kind === SyntaxKind.ExportAssignment) {
return checkExpression((<ExportAssignment>declaration).expression);
}
// Handle variable, parameter or property
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
let type = getJSSpecialType(symbol, declaration);
if (!type) {
if (isJSDocPropertyLikeTag(declaration)
|| isPropertyAccessExpression(declaration)
|| isIdentifier(declaration)
|| isClassDeclaration(declaration)
|| isFunctionDeclaration(declaration)
|| (isMethodDeclaration(declaration) && !isObjectLiteralMethod(declaration))
|| isMethodSignature(declaration)) {
// Symbol is property of some kind that is merged with something - should use `getTypeOfFuncClassEnumModule` and not `getTypeOfVariableOrParameterOrProperty`
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Method | SymbolFlags.Class | SymbolFlags.Enum | SymbolFlags.ValueModule)) {
return getTypeOfFuncClassEnumModule(symbol);
}
type = tryGetTypeFromEffectiveTypeNode(declaration) || anyType;
}
else if (isPropertyAssignment(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkPropertyAssignment(declaration);
}
else if (isJsxAttribute(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkJsxAttribute(declaration);
}
else if (isShorthandPropertyAssignment(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkExpressionForMutableLocation(declaration.name, CheckMode.Normal);
}
else if (isObjectLiteralMethod(declaration)) {
type = tryGetTypeFromEffectiveTypeNode(declaration) || checkObjectLiteralMethod(declaration, CheckMode.Normal);
}
else if (isParameter(declaration)
|| isPropertyDeclaration(declaration)
|| isPropertySignature(declaration)
|| isVariableDeclaration(declaration)
|| isBindingElement(declaration)) {
type = getWidenedTypeForVariableLikeDeclaration(declaration, /*includeOptionality*/ true);
}
else {
return Debug.fail("Unhandled declaration kind! " + Debug.showSyntaxKind(declaration) + " for " + Debug.showSymbol(symbol));
}
}
if (!popTypeResolution()) {
type = reportCircularityError(symbol);
}
return type;
}
function getJSSpecialType(symbol: Symbol, decl: Declaration): Type | undefined {
if (!isInJavaScriptFile(decl)) {
return undefined;
@@ -5118,20 +5125,25 @@ namespace ts {
}
}
function getAnnotatedAccessorType(accessor: AccessorDeclaration | undefined): Type | undefined {
function getAnnotatedAccessorTypeNode(accessor: AccessorDeclaration | undefined): TypeNode | undefined {
if (accessor) {
if (accessor.kind === SyntaxKind.GetAccessor) {
const getterTypeAnnotation = getEffectiveReturnTypeNode(accessor);
return getterTypeAnnotation && getTypeFromTypeNode(getterTypeAnnotation);
return getterTypeAnnotation;
}
else {
const setterTypeAnnotation = getEffectiveSetAccessorTypeAnnotationNode(accessor);
return setterTypeAnnotation && getTypeFromTypeNode(setterTypeAnnotation);
return setterTypeAnnotation;
}
}
return undefined;
}
function getAnnotatedAccessorType(accessor: AccessorDeclaration | undefined): Type | undefined {
const node = getAnnotatedAccessorTypeNode(accessor);
return node && getTypeFromTypeNode(node);
}
function getAnnotatedAccessorThisParameter(accessor: AccessorDeclaration): Symbol | undefined {
const parameter = getAccessorThisParameter(accessor);
return parameter && parameter.symbol;
@@ -5143,64 +5155,65 @@ namespace ts {
function getTypeOfAccessors(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.type) {
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
return links.type || (links.type = getTypeOfAccessorsWorker(symbol));
}
if (getter && isInJavaScriptFile(getter)) {
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
if (jsDocType) {
return links.type = jsDocType;
}
function getTypeOfAccessorsWorker(symbol: Symbol): Type {
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
const setter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.SetAccessor);
if (getter && isInJavaScriptFile(getter)) {
const jsDocType = getTypeForDeclarationFromJSDocComment(getter);
if (jsDocType) {
return jsDocType;
}
}
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
let type: Type;
let type: Type;
// First try to see if the user specified a return type on the get-accessor.
const getterReturnType = getAnnotatedAccessorType(getter);
if (getterReturnType) {
type = getterReturnType;
// First try to see if the user specified a return type on the get-accessor.
const getterReturnType = getAnnotatedAccessorType(getter);
if (getterReturnType) {
type = getterReturnType;
}
else {
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
const setterParameterType = getAnnotatedAccessorType(setter);
if (setterParameterType) {
type = setterParameterType;
}
else {
// If the user didn't specify a return type, try to use the set-accessor's parameter type.
const setterParameterType = getAnnotatedAccessorType(setter);
if (setterParameterType) {
type = setterParameterType;
// If there are no specified types, try to infer it from the body of the get accessor if it exists.
if (getter && getter.body) {
type = getReturnTypeFromBody(getter);
}
// Otherwise, fall back to 'any'.
else {
// If there are no specified types, try to infer it from the body of the get accessor if it exists.
if (getter && getter.body) {
type = getReturnTypeFromBody(getter);
}
// Otherwise, fall back to 'any'.
else {
if (noImplicitAny) {
if (setter) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
}
else {
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
}
if (noImplicitAny) {
if (setter) {
error(setter, Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation, symbolToString(symbol));
}
else {
Debug.assert(!!getter, "there must existed getter as we are current checking either setter or getter in this function");
error(getter, Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation, symbolToString(symbol));
}
type = anyType;
}
type = anyType;
}
}
if (!popTypeResolution()) {
type = anyType;
if (noImplicitAny) {
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
}
}
links.type = type;
}
return links.type;
if (!popTypeResolution()) {
type = anyType;
if (noImplicitAny) {
const getter = getDeclarationOfKind<AccessorDeclaration>(symbol, SyntaxKind.GetAccessor);
error(getter, Diagnostics._0_implicitly_has_return_type_any_because_it_does_not_have_a_return_type_annotation_and_is_referenced_directly_or_indirectly_in_one_of_its_return_expressions, symbolToString(symbol));
}
}
return type;
}
function getBaseTypeVariableOfClass(symbol: Symbol) {
@@ -5210,6 +5223,7 @@ namespace ts {
function getTypeOfFuncClassEnumModule(symbol: Symbol): Type {
let links = getSymbolLinks(symbol);
const originalLinks = links;
if (!links.type) {
const jsDeclaration = getDeclarationOfJSInitializer(symbol.valueDeclaration);
if (jsDeclaration) {
@@ -5228,48 +5242,47 @@ namespace ts {
}
}
}
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
links.type = anyType;
}
else if (symbol.valueDeclaration.kind === SyntaxKind.BinaryExpression ||
symbol.valueDeclaration.kind === SyntaxKind.PropertyAccessExpression && symbol.valueDeclaration.parent.kind === SyntaxKind.BinaryExpression) {
links.type = getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
}
else {
if (symbol.flags & SymbolFlags.ValueModule && symbol.valueDeclaration && isSourceFile(symbol.valueDeclaration) && symbol.valueDeclaration.commonJsModuleIndicator) {
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
const resolvedModule = resolveExternalModuleSymbol(symbol);
if (resolvedModule !== symbol) {
const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!);
links.type = getWidenedTypeFromJSSpecialPropertyDeclarations(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule);
}
if (!popTypeResolution()) {
links.type = reportCircularityError(symbol);
}
}
if (!links.type) {
const type = createObjectType(ObjectFlags.Anonymous, symbol);
if (symbol.flags & SymbolFlags.Class) {
const baseTypeVariable = getBaseTypeVariableOfClass(symbol);
links.type = baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type;
}
else {
links.type = strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type) : type;
}
}
}
originalLinks.type = links.type = getTypeOfFuncClassEnumModuleWorker(symbol);
}
return links.type;
}
function getTypeOfFuncClassEnumModuleWorker(symbol: Symbol): Type {
const declaration = symbol.valueDeclaration;
if (symbol.flags & SymbolFlags.Module && isShorthandAmbientModuleSymbol(symbol)) {
return anyType;
}
else if (declaration.kind === SyntaxKind.BinaryExpression ||
declaration.kind === SyntaxKind.PropertyAccessExpression && declaration.parent.kind === SyntaxKind.BinaryExpression) {
return getWidenedTypeFromJSSpecialPropertyDeclarations(symbol);
}
else if (symbol.flags & SymbolFlags.ValueModule && declaration && isSourceFile(declaration) && declaration.commonJsModuleIndicator) {
const resolvedModule = resolveExternalModuleSymbol(symbol);
if (resolvedModule !== symbol) {
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
}
const exportEquals = getMergedSymbol(symbol.exports!.get(InternalSymbolName.ExportEquals)!);
const type = getWidenedTypeFromJSSpecialPropertyDeclarations(exportEquals, exportEquals === resolvedModule ? undefined : resolvedModule);
if (!popTypeResolution()) {
return reportCircularityError(symbol);
}
return type;
}
}
const type = createObjectType(ObjectFlags.Anonymous, symbol);
if (symbol.flags & SymbolFlags.Class) {
const baseTypeVariable = getBaseTypeVariableOfClass(symbol);
return baseTypeVariable ? getIntersectionType([type, baseTypeVariable]) : type;
}
else {
return strictNullChecks && symbol.flags & SymbolFlags.Optional ? getOptionalType(type) : type;
}
}
function getTypeOfEnumMember(symbol: Symbol): Type {
const links = getSymbolLinks(symbol);
if (!links.type) {
links.type = getDeclaredTypeOfEnumMember(symbol);
}
return links.type;
return links.type || (links.type = getDeclaredTypeOfEnumMember(symbol));
}
function getTypeOfAlias(symbol: Symbol): Type {
@@ -5298,7 +5311,7 @@ namespace ts {
}
else {
if (!pushTypeResolution(symbol, TypeSystemPropertyName.Type)) {
return errorType;
return links.type = errorType;
}
symbolInstantiationDepth++;
let type = instantiateType(getTypeOfSymbol(links.target!), links.mapper!);
@@ -6853,11 +6866,7 @@ namespace ts {
return obj.properties.some(property => {
const name = property.name && getTextOfPropertyName(property.name);
const expected = name === undefined ? undefined : getTypeOfPropertyOfType(contextualType, name);
if (expected && typeIsLiteralType(expected)) {
const actual = getTypeOfNode(property);
return !!actual && !isTypeIdenticalTo(actual, expected);
}
return false;
return !!expected && typeIsLiteralType(expected) && !isTypeIdenticalTo(getTypeOfNode(property), expected);
});
}
@@ -8128,6 +8137,10 @@ namespace ts {
// TODO: GH#18217 (should the `|| assignedType` be at a lower precedence?)
return (referenceType && assignedType ? getIntersectionType([assignedType, referenceType]) : referenceType || assignedType)!;
}
const enumTag = getJSDocEnumTag(symbol.valueDeclaration);
if (enumTag && enumTag.typeExpression) {
return getTypeFromTypeNode(enumTag.typeExpression);
}
}
function getTypeReferenceTypeWorker(node: NodeWithTypeArguments, symbol: Symbol, typeArguments: Type[] | undefined): Type | undefined {
@@ -8185,7 +8198,7 @@ namespace ts {
}
function isJSDocTypeReference(node: Node): node is TypeReferenceNode {
return !!(node.flags & NodeFlags.JSDoc) && node.kind === SyntaxKind.TypeReference;
return !!(node.flags & NodeFlags.JSDoc) && (node.kind === SyntaxKind.TypeReference || node.kind === SyntaxKind.ImportType);
}
function checkNoTypeArguments(node: NodeWithTypeArguments, symbol?: Symbol) {
@@ -8432,6 +8445,10 @@ namespace ts {
return createTypeFromGenericGlobalType(globalArrayType, [elementType]);
}
function createReadonlyArrayType(elementType: Type): ObjectType {
return createTypeFromGenericGlobalType(globalReadonlyArrayType, [elementType]);
}
function getTypeFromArrayTypeNode(node: ArrayTypeNode): Type {
const links = getNodeLinks(node);
if (!links.resolvedType) {
@@ -9454,7 +9471,7 @@ namespace ts {
links.resolvedSymbol = unknownSymbol;
return links.resolvedType = errorType;
}
const targetMeaning = node.isTypeOf ? SymbolFlags.Value : SymbolFlags.Type;
const targetMeaning = node.isTypeOf ? SymbolFlags.Value : node.flags & NodeFlags.JSDoc ? SymbolFlags.Value | SymbolFlags.Type : SymbolFlags.Type;
// TODO: Future work: support unions/generics/whatever via a deferred import-type
const innerModuleSymbol = resolveExternalModuleName(node, node.argument.literal);
if (!innerModuleSymbol) {
@@ -9821,7 +9838,7 @@ namespace ts {
case SyntaxKind.Identifier:
case SyntaxKind.QualifiedName:
const symbol = getSymbolAtLocation(node);
return (symbol && getDeclaredTypeOfSymbol(symbol))!; // TODO: GH#18217
return symbol ? getDeclaredTypeOfSymbol(symbol) : errorType;
default:
return errorType;
}
@@ -10087,11 +10104,16 @@ namespace ts {
}
function instantiateMappedType(type: MappedType, mapper: TypeMapper): Type {
// Check if we have a homomorphic mapped type, i.e. a type of the form { [P in keyof T]: X } for some
// type variable T. If so, the mapped type is distributive over a union type and when T is instantiated
// to a union type A | B, we produce { [P in keyof A]: X } | { [P in keyof B]: X }. Furthermore, for
// homomorphic mapped types we leave primitive types alone. For example, when T is instantiated to a
// union type A | undefined, we produce { [P in keyof A]: X } | undefined.
// For a momomorphic mapped type { [P in keyof T]: X }, where T is some type variable, the mapping
// operation depends on T as follows:
// * If T is a primitive type no mapping is performed and the result is simply T.
// * If T is a union type we distribute the mapped type over the union.
// * If T is an array we map to an array where the element type has been transformed.
// * If T is a tuple we map to a tuple where the element types have been transformed.
// * Otherwise we map to an object type where the type of each property has been transformed.
// For example, when T is instantiated to a union type A | B, we produce { [P in keyof A]: X } |
// { [P in keyof B]: X }, and when when T is instantiated to a union type A | undefined, we produce
// { [P in keyof A]: X } | undefined.
const constraintType = getConstraintTypeFromMappedType(type);
if (constraintType.flags & TypeFlags.Index) {
const typeVariable = (<IndexType>constraintType).type;
@@ -10100,7 +10122,11 @@ namespace ts {
if (typeVariable !== mappedTypeVariable) {
return mapType(mappedTypeVariable, t => {
if (isMappableType(t)) {
return instantiateAnonymousType(type, createReplacementMapper(typeVariable, t, mapper));
const replacementMapper = createReplacementMapper(typeVariable, t, mapper);
return isArrayType(t) ? createArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
isReadonlyArrayType(t) ? createReadonlyArrayType(instantiateMappedTypeTemplate(type, numberType, /*isOptional*/ true, replacementMapper)) :
isTupleType(t) ? instantiateMappedTupleType(t, type, replacementMapper) :
instantiateAnonymousType(type, replacementMapper);
}
return t;
});
@@ -10114,6 +10140,26 @@ namespace ts {
return type.flags & (TypeFlags.AnyOrUnknown | TypeFlags.InstantiableNonPrimitive | TypeFlags.Object | TypeFlags.Intersection);
}
function instantiateMappedTupleType(tupleType: TupleTypeReference, mappedType: MappedType, mapper: TypeMapper) {
const minLength = tupleType.target.minLength;
const elementTypes = map(tupleType.typeArguments || emptyArray, (_, i) =>
instantiateMappedTypeTemplate(mappedType, getLiteralType("" + i), i >= minLength, mapper));
const modifiers = getMappedTypeModifiers(mappedType);
const newMinLength = modifiers & MappedTypeModifiers.IncludeOptional ? 0 :
modifiers & MappedTypeModifiers.ExcludeOptional ? getTypeReferenceArity(tupleType) - (tupleType.target.hasRestElement ? 1 : 0) :
minLength;
return createTupleType(elementTypes, newMinLength, tupleType.target.hasRestElement, tupleType.target.associatedNames);
}
function instantiateMappedTypeTemplate(type: MappedType, key: Type, isOptional: boolean, mapper: TypeMapper) {
const templateMapper = combineTypeMappers(mapper, createTypeMapper([getTypeParameterFromMappedType(type)], [key]));
const propType = instantiateType(getTemplateTypeFromMappedType(<MappedType>type.target || type), templateMapper);
const modifiers = getMappedTypeModifiers(type);
return strictNullChecks && modifiers & MappedTypeModifiers.IncludeOptional && !isTypeAssignableTo(undefinedType, propType) ? getOptionalType(propType) :
strictNullChecks && modifiers & MappedTypeModifiers.ExcludeOptional && isOptional ? getTypeWithFacts(propType, TypeFacts.NEUndefined) :
propType;
}
function instantiateAnonymousType(type: AnonymousType, mapper: TypeMapper): AnonymousType {
const result = <AnonymousType>createObjectType(type.objectFlags | ObjectFlags.Instantiated, type.symbol);
if (type.objectFlags & ObjectFlags.Mapped) {
@@ -12441,6 +12487,10 @@ namespace ts {
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (<TypeReference>type).target === globalArrayType;
}
function isReadonlyArrayType(type: Type): boolean {
return !!(getObjectFlags(type) & ObjectFlags.Reference) && (<TypeReference>type).target === globalReadonlyArrayType;
}
function isArrayLikeType(type: Type): boolean {
// A type is array-like if it is a reference to the global Array or global ReadonlyArray type,
// or if it is not the undefined or null type and if it is assignable to ReadonlyArray<any>
@@ -12996,6 +13046,22 @@ namespace ts {
return undefined;
}
}
// For arrays and tuples we infer new arrays and tuples where the reverse mapping has been
// applied to the element type(s).
if (isArrayType(source)) {
return createArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target));
}
if (isReadonlyArrayType(source)) {
return createReadonlyArrayType(inferReverseMappedType((<TypeReference>source).typeArguments![0], target));
}
if (isTupleType(source)) {
const elementTypes = map(source.typeArguments || emptyArray, t => inferReverseMappedType(t, target));
const minLength = getMappedTypeModifiers(target) & MappedTypeModifiers.IncludeOptional ?
getTypeReferenceArity(source) - (source.target.hasRestElement ? 1 : 0) : source.target.minLength;
return createTupleType(elementTypes, minLength, source.target.hasRestElement, source.target.associatedNames);
}
// For all other object types we infer a new object type where the reverse mapping has been
// applied to the type of each property.
const reversed = createObjectType(ObjectFlags.ReverseMapped | ObjectFlags.Anonymous, /*symbol*/ undefined) as ReverseMappedType;
reversed.source = source;
reversed.mappedType = target;
@@ -15340,8 +15406,8 @@ namespace ts {
(!isInParameterInitializerBeforeContainingFunction(node) || getThisParameter(container))) {
// Note: a parameter initializer should refer to class-this unless function-this is explicitly annotated.
// If this is a function in a JS file, it might be a class method. Check if it's the RHS
// of a x.prototype.y = function [name]() { .... }
// If this is a function in a JS file, it might be a class method.
// Check if it's the RHS of a x.prototype.y = function [name]() { .... }
if (container.kind === SyntaxKind.FunctionExpression &&
container.parent.kind === SyntaxKind.BinaryExpression &&
getSpecialPropertyAssignmentKind(container.parent as BinaryExpression) === SpecialPropertyAssignmentKind.PrototypeProperty) {
@@ -15355,6 +15421,17 @@ namespace ts {
return getFlowTypeOfReference(node, getInferredClassType(classSymbol));
}
}
// Check if it's a constructor definition, can be either a variable decl or function decl
// i.e.
// * /** @constructor */ function [name]() { ... }
// * /** @constructor */ var x = function() { ... }
else if ((container.kind === SyntaxKind.FunctionExpression || container.kind === SyntaxKind.FunctionDeclaration) &&
getJSDocClassTag(container)) {
const classType = getJavaScriptClassType(container.symbol);
if (classType) {
return getFlowTypeOfReference(node, classType);
}
}
const thisType = getThisTypeOfDeclaration(container) || getContextualThisParameterType(container);
if (thisType) {
@@ -16563,7 +16640,8 @@ namespace ts {
const contextualTypeHasPattern = contextualType && contextualType.pattern &&
(contextualType.pattern.kind === SyntaxKind.ObjectBindingPattern || contextualType.pattern.kind === SyntaxKind.ObjectLiteralExpression);
const isInJSFile = isInJavaScriptFile(node) && !isInJsonFile(node);
const isJSObjectLiteral = !contextualType && isInJSFile;
const enumTag = getJSDocEnumTag(node);
const isJSObjectLiteral = !contextualType && isInJSFile && !enumTag;
let typeFlags: TypeFlags = 0;
let patternWithComputedProperties = false;
let hasComputedStringProperty = false;
@@ -16588,6 +16666,9 @@ namespace ts {
checkTypeAssignableTo(type, jsDocType, memberDecl);
type = jsDocType;
}
else if (enumTag && enumTag.typeExpression) {
checkTypeAssignableTo(type, getTypeFromTypeNode(enumTag.typeExpression), memberDecl);
}
}
typeFlags |= type.flags;
const nameType = computedNameType && computedNameType.flags & TypeFlags.StringOrNumberLiteralOrUnique ?
@@ -16622,6 +16703,7 @@ namespace ts {
symbolToString(member), typeToString(contextualType!));
}
}
prop.declarations = member.declarations;
prop.parent = member.parent;
if (member.valueDeclaration) {
@@ -17132,7 +17214,7 @@ namespace ts {
const jsxStatelessElementType = getJsxStatelessElementTypeAt(openingLikeElement);
if (jsxStatelessElementType) {
// We don't call getResolvedSignature here because we have already resolve the type of JSX Element.
const callSignature = getResolvedJsxStatelessFunctionSignature(openingLikeElement, elementType, /*candidatesOutArray*/ undefined);
const callSignature = getResolvedJsxStatelessFunctionSignature(openingLikeElement, elementType, /*candidatesOutArray*/ undefined, /*isForSignatureHelp*/ false);
if (callSignature !== unknownSignature) {
const callReturnType = callSignature && getReturnTypeOfSignature(callSignature);
let paramType = callReturnType && (callSignature!.parameters.length === 0 ? emptyObjectType : getTypeOfSymbol(callSignature!.parameters[0]));
@@ -17169,7 +17251,7 @@ namespace ts {
if (jsxStatelessElementType) {
// We don't call getResolvedSignature because here we have already resolve the type of JSX Element.
const candidatesOutArray: Signature[] = [];
getResolvedJsxStatelessFunctionSignature(openingLikeElement, elementType, candidatesOutArray);
getResolvedJsxStatelessFunctionSignature(openingLikeElement, elementType, candidatesOutArray, /*isForSignatureHelp*/ false);
let result: Type | undefined;
let allMatchingAttributesType: Type | undefined;
for (const candidate of candidatesOutArray) {
@@ -19032,7 +19114,7 @@ namespace ts {
return createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length);
}
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, fallbackError?: DiagnosticMessage): Signature {
function resolveCall(node: CallLikeExpression, signatures: ReadonlyArray<Signature>, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean, fallbackError?: DiagnosticMessage): Signature {
const isTaggedTemplate = node.kind === SyntaxKind.TaggedTemplateExpression;
const isDecorator = node.kind === SyntaxKind.Decorator;
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
@@ -19118,7 +19200,7 @@ namespace ts {
// If we are in signature help, a trailing comma indicates that we intend to provide another argument,
// so we will only accept overloads with arity at least 1 higher than the current number of provided arguments.
const signatureHelpTrailingComma =
candidatesOutArray && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma;
isForSignatureHelp && node.kind === SyntaxKind.CallExpression && node.arguments.hasTrailingComma;
// Section 4.12.1:
// if the candidate list contains one or more signatures for which the type of each argument
@@ -19329,7 +19411,7 @@ namespace ts {
}
const typeArgumentNodes: ReadonlyArray<TypeNode> = callLikeExpressionMayHaveTypeArguments(node) ? node.typeArguments || emptyArray : emptyArray;
const typeArguments = typeArgumentNodes.map(n => getTypeOfNode(n) || anyType);
const typeArguments = typeArgumentNodes.map(getTypeOfNode);
while (typeArguments.length > typeParameters.length) {
typeArguments.pop();
}
@@ -19360,7 +19442,7 @@ namespace ts {
return maxParamsIndex;
}
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined): Signature {
function resolveCallExpression(node: CallExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
const superType = checkSuperExpression(node.expression);
if (isTypeAny(superType)) {
@@ -19375,7 +19457,7 @@ namespace ts {
const baseTypeNode = getEffectiveBaseTypeNode(getContainingClass(node)!);
if (baseTypeNode) {
const baseConstructors = getInstantiatedConstructorsForTypeArguments(superType, baseTypeNode.typeArguments, baseTypeNode);
return resolveCall(node, baseConstructors, candidatesOutArray);
return resolveCall(node, baseConstructors, candidatesOutArray, isForSignatureHelp);
}
}
return resolveUntypedCall(node);
@@ -19428,7 +19510,12 @@ namespace ts {
}
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray);
// If the function is explicitly marked with `@class`, then it must be constructed.
if (callSignatures.some(sig => isInJavaScriptFile(sig.declaration) && !!getJSDocClassTag(sig.declaration!))) {
error(node, Diagnostics.Value_of_type_0_is_not_callable_Did_you_mean_to_include_new, typeToString(funcType));
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
}
/**
@@ -19442,7 +19529,7 @@ namespace ts {
!numCallSignatures && !numConstructSignatures && !(apparentFuncType.flags & (TypeFlags.Union | TypeFlags.Never)) && isTypeAssignableTo(funcType, globalFunctionType);
}
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined): Signature {
function resolveNewExpression(node: NewExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
if (node.arguments && languageVersion < ScriptTarget.ES5) {
const spreadIndex = getSpreadArgumentIndex(node.arguments);
if (spreadIndex >= 0) {
@@ -19495,7 +19582,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, constructSignatures, candidatesOutArray);
return resolveCall(node, constructSignatures, candidatesOutArray, isForSignatureHelp);
}
// If expressionType's apparent type is an object type with no construct signatures but
@@ -19504,7 +19591,7 @@ namespace ts {
// operation is Any. It is an error to have a Void this type.
const callSignatures = getSignaturesOfType(expressionType, SignatureKind.Call);
if (callSignatures.length) {
const signature = resolveCall(node, callSignatures, candidatesOutArray);
const signature = resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
if (!isJavaScriptConstructor(signature.declaration) && getReturnTypeOfSignature(signature) !== voidType) {
error(node, Diagnostics.Only_a_void_function_can_be_called_with_the_new_keyword);
}
@@ -19611,7 +19698,7 @@ namespace ts {
}
}
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined): Signature {
function resolveTaggedTemplateExpression(node: TaggedTemplateExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
const tagType = checkExpression(node.tag);
const apparentType = getApparentType(tagType);
@@ -19632,7 +19719,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray);
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp);
}
/**
@@ -19663,7 +19750,7 @@ namespace ts {
/**
* Resolves a decorator as if it were a call expression.
*/
function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined): Signature {
function resolveDecorator(node: Decorator, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
const funcType = checkExpression(node.expression);
const apparentType = getApparentType(funcType);
if (apparentType === errorType) {
@@ -19692,7 +19779,7 @@ namespace ts {
return resolveErrorCall(node);
}
return resolveCall(node, callSignatures, candidatesOutArray, headMessage);
return resolveCall(node, callSignatures, candidatesOutArray, isForSignatureHelp, headMessage);
}
/**
@@ -19717,32 +19804,32 @@ namespace ts {
* @param candidatesOutArray an array of signature to be filled in by the function. It is passed by signature help in the language service;
* the function will fill it up with appropriate candidate signatures
*/
function getResolvedJsxStatelessFunctionSignature(openingLikeElement: JsxOpeningLikeElement, elementType: Type, candidatesOutArray: Signature[] | undefined): Signature | undefined {
function getResolvedJsxStatelessFunctionSignature(openingLikeElement: JsxOpeningLikeElement, elementType: Type, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature | undefined {
Debug.assert(!(elementType.flags & TypeFlags.Union));
const callSignatures = elementType && getSignaturesOfType(elementType, SignatureKind.Call);
if (callSignatures && callSignatures.length > 0) {
return resolveCall(openingLikeElement, callSignatures, candidatesOutArray);
return resolveCall(openingLikeElement, callSignatures, candidatesOutArray, isForSignatureHelp);
}
return undefined;
}
function resolveSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature {
function resolveSignature(node: CallLikeExpression, candidatesOutArray: Signature[] | undefined, isForSignatureHelp: boolean): Signature {
switch (node.kind) {
case SyntaxKind.CallExpression:
return resolveCallExpression(node, candidatesOutArray);
return resolveCallExpression(node, candidatesOutArray, isForSignatureHelp);
case SyntaxKind.NewExpression:
return resolveNewExpression(node, candidatesOutArray);
return resolveNewExpression(node, candidatesOutArray, isForSignatureHelp);
case SyntaxKind.TaggedTemplateExpression:
return resolveTaggedTemplateExpression(node, candidatesOutArray);
return resolveTaggedTemplateExpression(node, candidatesOutArray, isForSignatureHelp);
case SyntaxKind.Decorator:
return resolveDecorator(node, candidatesOutArray);
return resolveDecorator(node, candidatesOutArray, isForSignatureHelp);
case SyntaxKind.JsxOpeningElement:
case SyntaxKind.JsxSelfClosingElement:
// This code-path is called by language service
const exprTypes = checkExpression(node.tagName);
return forEachType(exprTypes, exprType => {
const sfcResult = getResolvedJsxStatelessFunctionSignature(node, exprType, candidatesOutArray);
const sfcResult = getResolvedJsxStatelessFunctionSignature(node, exprType, candidatesOutArray, isForSignatureHelp);
if (sfcResult && sfcResult !== unknownSignature) {
return sfcResult;
}
@@ -19763,7 +19850,7 @@ namespace ts {
* the function will fill it up with appropriate candidate signatures
* @return a signature of the call-like expression or undefined if one can't be found
*/
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[]): Signature {
function getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[] | undefined, isForSignatureHelp = false): Signature {
const links = getNodeLinks(node);
// If getResolvedSignature has already been called, we will have cached the resolvedSignature.
// However, it is possible that either candidatesOutArray was not passed in the first time,
@@ -19774,7 +19861,7 @@ namespace ts {
return cached;
}
links.resolvedSignature = resolvingSignature;
const result = resolveSignature(node, candidatesOutArray);
const result = resolveSignature(node, candidatesOutArray, isForSignatureHelp);
// If signature resolution originated in control flow type analysis (for example to compute the
// assigned type in a flow assignment) we don't cache the result as it may be based on temporary
// types from the control flow analysis.
@@ -22613,6 +22700,7 @@ namespace ts {
grammarErrorOnNode(node, Diagnostics.infer_declarations_are_only_permitted_in_the_extends_clause_of_a_conditional_type);
}
checkSourceElement(node.typeParameter);
registerForUnusedIdentifiersCheck(node);
}
function checkImportType(node: ImportTypeNode) {
@@ -23433,9 +23521,13 @@ namespace ts {
}
break;
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
const otherKind = node.kind === SyntaxKind.GetAccessor ? SyntaxKind.SetAccessor : SyntaxKind.GetAccessor;
const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(node as AccessorDeclaration), otherKind);
markDecoratorMedataDataTypeNodeAsReferenced(getAnnotatedAccessorTypeNode(node as AccessorDeclaration) || otherAccessor && getAnnotatedAccessorTypeNode(otherAccessor));
break;
case SyntaxKind.MethodDeclaration:
for (const parameter of (<FunctionLikeDeclaration>node).parameters) {
markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
}
@@ -23641,7 +23733,8 @@ namespace ts {
type PotentiallyUnusedIdentifier =
| SourceFile | ModuleDeclaration | ClassLikeDeclaration | InterfaceDeclaration
| Block | CaseBlock | ForStatement | ForInStatement | ForOfStatement
| Exclude<SignatureDeclaration, IndexSignatureDeclaration | JSDocFunctionType> | TypeAliasDeclaration;
| Exclude<SignatureDeclaration, IndexSignatureDeclaration | JSDocFunctionType> | TypeAliasDeclaration
| InferTypeNode;
function checkUnusedIdentifiers(potentiallyUnusedIdentifiers: ReadonlyArray<PotentiallyUnusedIdentifier>, addDiagnostic: AddUnusedDiagnostic) {
for (const node of potentiallyUnusedIdentifiers) {
@@ -23681,6 +23774,7 @@ namespace ts {
case SyntaxKind.FunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.TypeAliasDeclaration:
case SyntaxKind.InferType:
checkUnusedTypeParameters(node, addDiagnostic);
break;
default:
@@ -23734,21 +23828,48 @@ namespace ts {
}
}
function checkUnusedTypeParameters(
node: ClassDeclaration | ClassExpression | FunctionDeclaration | MethodDeclaration | FunctionExpression | ArrowFunction | ConstructorDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration,
addDiagnostic: AddUnusedDiagnostic,
): void {
function checkUnusedTypeParameters(node: ClassLikeDeclaration | SignatureDeclaration | InterfaceDeclaration | TypeAliasDeclaration | InferTypeNode, addDiagnostic: AddUnusedDiagnostic): void {
// Only report errors on the last declaration for the type parameter container;
// this ensures that all uses have been accounted for.
const typeParameters = getEffectiveTypeParameterDeclarations(node);
if (!(node.flags & NodeFlags.Ambient) && last(getSymbolOfNode(node).declarations) === node) {
if (node.flags & NodeFlags.Ambient || node.kind !== SyntaxKind.InferType && last(getSymbolOfNode(node).declarations) !== node) return;
if (node.kind === SyntaxKind.InferType) {
const { typeParameter } = node;
if (isTypeParameterUnused(typeParameter)) {
addDiagnostic(node, UnusedKind.Parameter, createDiagnosticForNode(node, Diagnostics._0_is_declared_but_its_value_is_never_read, idText(typeParameter.name)));
}
}
else {
const typeParameters = getEffectiveTypeParameterDeclarations(node);
const seenParentsWithEveryUnused = new NodeSet<DeclarationWithTypeParameterChildren>();
for (const typeParameter of typeParameters) {
if (!(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name)) {
addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter.name, Diagnostics._0_is_declared_but_its_value_is_never_read, symbolName(typeParameter.symbol)));
if (!isTypeParameterUnused(typeParameter)) continue;
const name = idText(typeParameter.name);
const { parent } = typeParameter;
if (parent.kind !== SyntaxKind.InferType && parent.typeParameters!.every(isTypeParameterUnused)) {
if (seenParentsWithEveryUnused.tryAdd(parent)) {
const range = isJSDocTemplateTag(parent)
// Whole @template tag
? rangeOfNode(parent)
// Include the `<>` in the error message
: rangeOfTypeParameters(parent.typeParameters!);
const only = typeParameters.length === 1;
const message = only ? Diagnostics._0_is_declared_but_its_value_is_never_read : Diagnostics.All_type_parameters_are_unused;
const arg0 = only ? name : undefined;
addDiagnostic(typeParameter, UnusedKind.Parameter, createFileDiagnostic(getSourceFileOfNode(parent), range.pos, range.end - range.pos, message, arg0));
}
}
else {
addDiagnostic(typeParameter, UnusedKind.Parameter, createDiagnosticForNode(typeParameter, Diagnostics._0_is_declared_but_its_value_is_never_read, name));
}
}
}
}
function isTypeParameterUnused(typeParameter: TypeParameterDeclaration): boolean {
return !(getMergedSymbol(typeParameter.symbol).isReferenced! & SymbolFlags.TypeParameter) && !isIdentifierThatStartsWithUnderscore(typeParameter.name);
}
function addToGroup<K, V>(map: Map<[K, V[]]>, key: K, value: V, getKey: (key: K) => number | string): void {
const keyString = String(getKey(key));
@@ -27143,7 +27264,7 @@ namespace ts {
grandParent.kind === SyntaxKind.ObjectBindingPattern &&
node === (<BindingElement>parent).propertyName) {
const typeOfPattern = getTypeOfNode(grandParent);
const propertyDeclaration = typeOfPattern && getPropertyOfType(typeOfPattern, (<Identifier>node).escapedText);
const propertyDeclaration = getPropertyOfType(typeOfPattern, (<Identifier>node).escapedText);
if (propertyDeclaration) {
return propertyDeclaration;
@@ -27243,7 +27364,7 @@ namespace ts {
if (isPartOfTypeNode(node)) {
let typeFromTypeNode = getTypeFromTypeNode(<TypeNode>node);
if (typeFromTypeNode && isExpressionWithTypeArgumentsInClassImplementsClause(node)) {
if (isExpressionWithTypeArgumentsInClassImplementsClause(node)) {
const containingClass = getContainingClass(node)!;
const classType = getTypeOfNode(containingClass) as InterfaceType;
typeFromTypeNode = getTypeWithThisArgument(typeFromTypeNode, classType.thisType);
@@ -27261,8 +27382,8 @@ namespace ts {
// extends clause of a class. We handle that case here.
const classNode = getContainingClass(node)!;
const classType = getDeclaredTypeOfSymbol(getSymbolOfNode(classNode)) as InterfaceType;
const baseType = getBaseTypes(classType)[0];
return baseType && getTypeWithThisArgument(baseType, classType.thisType);
const baseType = firstOrUndefined(getBaseTypes(classType));
return baseType ? getTypeWithThisArgument(baseType, classType.thisType) : errorType;
}
if (isTypeDeclaration(node)) {
@@ -27959,8 +28080,8 @@ namespace ts {
const otherAccessor = getDeclarationOfKind<AccessorDeclaration>(getSymbolOfNode(accessor), otherKind);
const firstAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? otherAccessor : accessor;
const secondAccessor = otherAccessor && (otherAccessor.pos < accessor.pos) ? accessor : otherAccessor;
const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor;
const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor;
const setAccessor = accessor.kind === SyntaxKind.SetAccessor ? accessor : otherAccessor as SetAccessorDeclaration;
const getAccessor = accessor.kind === SyntaxKind.GetAccessor ? accessor : otherAccessor as GetAccessorDeclaration;
return {
firstAccessor,
secondAccessor,
@@ -29184,10 +29305,6 @@ namespace ts {
}
checkGrammarForDisallowedTrailingComma(elements, Diagnostics.A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma);
if (node.name.kind === SyntaxKind.ArrayBindingPattern || node.name.kind === SyntaxKind.ObjectBindingPattern) {
return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_contain_a_binding_pattern);
}
if (node.propertyName) {
return grammarErrorOnNode(node.name, Diagnostics.A_rest_element_cannot_have_a_property_name);
}
+1 -1
View File
@@ -2093,7 +2093,7 @@ namespace ts {
return arg => f(arg) || g(arg);
}
export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty
export function assertType<T>(_: T): void { } // tslint:disable-line no-empty
export function singleElementArray<T>(t: T | undefined): T[] | undefined {
return t === undefined ? undefined : [t];
+28
View File
@@ -3655,6 +3655,10 @@
"category": "Message",
"code": 6204
},
"All type parameters are unused": {
"category": "Error",
"code": 6205
},
"Projects to reference": {
"category": "Message",
@@ -4208,6 +4212,14 @@
"category": "Message",
"code": 90010
},
"Remove template tag": {
"category": "Message",
"code": 90011
},
"Remove type parameters": {
"category": "Message",
"code": 90012
},
"Import '{0}' from module \"{1}\"": {
"category": "Message",
"code": 90013
@@ -4276,6 +4288,22 @@
"category": "Message",
"code": 90029
},
"Replace 'infer {0}' with 'unknown'": {
"category": "Message",
"code": 90030
},
"Replace all unused 'infer' with 'unknown'": {
"category": "Message",
"code": 90031
},
"Import default '{0}' from module \"{1}\"": {
"category": "Message",
"code": 90032
},
"Add default import '{0}' to existing import declaration from \"{1}\"": {
"category": "Message",
"code": 90033
},
"Convert function to an ES2015 class": {
"category": "Message",
"code": 95001
+13 -48
View File
@@ -1058,7 +1058,7 @@ namespace ts {
: node;
}
export function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ export function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
export function createTaggedTemplate(tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
/** @internal */
export function createTaggedTemplate(tag: Expression, typeArgumentsOrTemplate: ReadonlyArray<TypeNode> | TemplateLiteral | undefined, template?: TemplateLiteral): TaggedTemplateExpression;
@@ -1076,7 +1076,7 @@ namespace ts {
return node;
}
export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
export function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArgumentsOrTemplate: ReadonlyArray<TypeNode> | TemplateLiteral | undefined, template?: TemplateLiteral) {
return node.tag !== tag
@@ -1168,14 +1168,6 @@ namespace ts {
node.body = parenthesizeConciseBody(body);
return node;
}
/** @deprecated */ export function updateArrowFunction(
node: ArrowFunction,
modifiers: ReadonlyArray<Modifier> | undefined,
typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined,
parameters: ReadonlyArray<ParameterDeclaration>,
type: TypeNode | undefined,
body: ConciseBody): ArrowFunction;
export function updateArrowFunction(
node: ArrowFunction,
modifiers: ReadonlyArray<Modifier> | undefined,
@@ -1183,28 +1175,8 @@ namespace ts {
parameters: ReadonlyArray<ParameterDeclaration>,
type: TypeNode | undefined,
equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>,
body: ConciseBody): ArrowFunction;
export function updateArrowFunction(
node: ArrowFunction,
modifiers: ReadonlyArray<Modifier> | undefined,
typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined,
parameters: ReadonlyArray<ParameterDeclaration>,
type: TypeNode | undefined,
equalsGreaterThanTokenOrBody: Token<SyntaxKind.EqualsGreaterThanToken> | ConciseBody,
bodyOrUndefined?: ConciseBody,
body: ConciseBody
): ArrowFunction {
let equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>;
let body: ConciseBody;
if (bodyOrUndefined === undefined) {
equalsGreaterThanToken = node.equalsGreaterThanToken;
body = cast(equalsGreaterThanTokenOrBody, isConciseBody);
}
else {
equalsGreaterThanToken = cast(equalsGreaterThanTokenOrBody, (n): n is Token<SyntaxKind.EqualsGreaterThanToken> =>
n.kind === SyntaxKind.EqualsGreaterThanToken);
body = bodyOrUndefined;
}
return node.modifiers !== modifiers
|| node.typeParameters !== typeParameters
|| node.parameters !== parameters
@@ -1306,7 +1278,7 @@ namespace ts {
: node;
}
export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
/** @deprecated */ export function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
export function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
export function createConditional(condition: Expression, questionTokenOrWhenTrue: QuestionToken | Expression, whenTrueOrWhenFalse: Expression, colonToken?: ColonToken, whenFalse?: Expression) {
const node = <ConditionalExpression>createSynthesizedNode(SyntaxKind.ConditionalExpression);
@@ -1317,26 +1289,14 @@ namespace ts {
node.whenFalse = parenthesizeSubexpressionOfConditionalExpression(whenFalse ? whenFalse : whenTrueOrWhenFalse);
return node;
}
/** @deprecated */ export function updateConditional(
node: ConditionalExpression,
condition: Expression,
whenTrue: Expression,
whenFalse: Expression): ConditionalExpression;
export function updateConditional(
node: ConditionalExpression,
condition: Expression,
questionToken: Token<SyntaxKind.QuestionToken>,
whenTrue: Expression,
colonToken: Token<SyntaxKind.ColonToken>,
whenFalse: Expression): ConditionalExpression;
export function updateConditional(node: ConditionalExpression, condition: Expression, ...args: any[]) {
if (args.length === 2) {
const [whenTrue, whenFalse] = args;
return updateConditional(node, condition, node.questionToken, whenTrue, node.colonToken, whenFalse);
}
Debug.assert(args.length === 4);
const [questionToken, whenTrue, colonToken, whenFalse] = args;
whenFalse: Expression
): ConditionalExpression {
return node.condition !== condition
|| node.questionToken !== questionToken
|| node.whenTrue !== whenTrue
@@ -2231,7 +2191,7 @@ namespace ts {
export function createJsxSelfClosingElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray<TypeNode> | undefined, attributes: JsxAttributes) {
const node = <JsxSelfClosingElement>createSynthesizedNode(SyntaxKind.JsxSelfClosingElement);
node.tagName = tagName;
node.typeArguments = typeArguments && createNodeArray(typeArguments);
node.typeArguments = asNodeArray(typeArguments);
node.attributes = attributes;
return node;
}
@@ -2247,7 +2207,7 @@ namespace ts {
export function createJsxOpeningElement(tagName: JsxTagNameExpression, typeArguments: ReadonlyArray<TypeNode> | undefined, attributes: JsxAttributes) {
const node = <JsxOpeningElement>createSynthesizedNode(SyntaxKind.JsxOpeningElement);
node.tagName = tagName;
node.typeArguments = typeArguments && createNodeArray(typeArguments);
node.typeArguments = asNodeArray(typeArguments);
node.attributes = attributes;
return node;
}
@@ -4024,6 +3984,11 @@ namespace ts {
const binaryOperatorPrecedence = getOperatorPrecedence(SyntaxKind.BinaryExpression, binaryOperator);
const binaryOperatorAssociativity = getOperatorAssociativity(SyntaxKind.BinaryExpression, binaryOperator);
const emittedOperand = skipPartiallyEmittedExpressions(operand);
if (!isLeftSideOfBinary && operand.kind === SyntaxKind.ArrowFunction && binaryOperatorPrecedence > 4) {
// We need to parenthesize arrow functions on the right side to avoid it being
// parsed as parenthesized expression: `a && (() => {})`
return true;
}
const operandPrecedence = getExpressionPrecedence(emittedOperand);
switch (compareValues(operandPrecedence, binaryOperatorPrecedence)) {
case Comparison.LessThan:
+70 -50
View File
@@ -1,4 +1,4 @@
// Used by importFixes to synthesize import module specifiers.
// Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
/* @internal */
namespace ts.moduleSpecifiers {
export interface ModuleSpecifierPreferences {
@@ -14,13 +14,26 @@ namespace ts.moduleSpecifiers {
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences = {},
redirectTargetsMap: RedirectTargetsMap,
): string {
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFileName, host);
const modulePaths = getAllModulePaths(files, toFileName, info.getCanonicalFileName, host);
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
return firstDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)) ||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
}
export function getModuleSpecifierForDeclarationFile(
moduleSymbol: Symbol,
compilerOptions: CompilerOptions,
importingSourceFile: SourceFile,
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences,
redirectTargetsMap: RedirectTargetsMap,
): string {
return first(first(getModuleSpecifiers(moduleSymbol, compilerOptions, importingSourceFile, host, files, preferences, redirectTargetsMap)));
}
// For each symlink/original for a module, returns a list of ways to import that file.
export function getModuleSpecifiers(
moduleSymbol: Symbol,
@@ -29,6 +42,7 @@ namespace ts.moduleSpecifiers {
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences,
redirectTargetsMap: RedirectTargetsMap,
): ReadonlyArray<ReadonlyArray<string>> {
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
if (ambient) return [[ambient]];
@@ -37,7 +51,8 @@ namespace ts.moduleSpecifiers {
if (!files) {
return Debug.fail("Files list must be present to resolve symlinks in specifier resolution");
}
const modulePaths = getAllModulePaths(files, getSourceFileOfNode(moduleSymbol.valueDeclaration).fileName, info.getCanonicalFileName, host);
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration);
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
@@ -142,64 +157,69 @@ namespace ts.moduleSpecifiers {
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
}
function discoverProbableSymlinks(files: ReadonlyArray<SourceFile>, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost) {
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
return getCanonicalFileName(a) === getCanonicalFileName(b);
}
// KLUDGE: Don't assume one 'node_modules' links to another. More likely a single directory inside the node_modules is the symlink.
// ALso, don't assume that an `@foo` directory is linked. More likely the contents of that are linked.
function isNodeModulesOrScopedPackageDirectory(s: string, getCanonicalFileName: GetCanonicalFileName): boolean {
return getCanonicalFileName(s) === "node_modules" || startsWith(s, "@");
}
function guessDirectorySymlink(a: string, b: string, cwd: string, getCanonicalFileName: GetCanonicalFileName): [string, string] {
const aParts = getPathComponents(toPath(a, cwd, getCanonicalFileName));
const bParts = getPathComponents(toPath(b, cwd, getCanonicalFileName));
while (!isNodeModulesOrScopedPackageDirectory(aParts[aParts.length - 2], getCanonicalFileName) &&
!isNodeModulesOrScopedPackageDirectory(bParts[bParts.length - 2], getCanonicalFileName) &&
stringsEqual(aParts[aParts.length - 1], bParts[bParts.length - 1], getCanonicalFileName)) {
aParts.pop();
bParts.pop();
}
return [getPathFromPathComponents(aParts), getPathFromPathComponents(bParts)];
}
function discoverProbableSymlinks(files: ReadonlyArray<SourceFile>, getCanonicalFileName: GetCanonicalFileName, cwd: string): ReadonlyMap<string> {
const result = createMap<string>();
const symlinks = mapDefined(files, sf =>
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] : undefined));
const result = createMap<string>();
if (symlinks) {
const currentDirectory = host.getCurrentDirectory ? host.getCurrentDirectory() : "";
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
for (const [resolvedPath, originalPath] of symlinks) {
const resolvedParts = getPathComponents(toPath(resolvedPath, currentDirectory, getCanonicalFileName));
const originalParts = getPathComponents(toPath(originalPath, currentDirectory, getCanonicalFileName));
while (compareStrings(resolvedParts[resolvedParts.length - 1], originalParts[originalParts.length - 1]) === Comparison.EqualTo) {
resolvedParts.pop();
originalParts.pop();
}
result.set(getPathFromPathComponents(originalParts), getPathFromPathComponents(resolvedParts));
}
for (const [resolvedPath, originalPath] of symlinks) {
const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedPath, originalPath, cwd, getCanonicalFileName);
result.set(commonOriginal, commonResolved);
}
return result;
}
function getAllModulePathsUsingIndirectSymlinks(files: ReadonlyArray<SourceFile>, target: string, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost) {
const links = discoverProbableSymlinks(files, getCanonicalFileName, host);
const paths = arrayFrom(links.keys());
let options: string[] | undefined;
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
for (const path of paths) {
const resolved = links.get(path)!;
if (compareStrings(target.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo) {
const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName);
const option = resolvePath(path, relative);
if (!host.fileExists || host.fileExists(option)) {
if (!options) options = [];
options.push(option);
}
}
}
if (options) {
options.push(target); // Since these are speculative, we also include the original resolved name as a possibility
return options;
}
return [target];
}
/**
* Looks for existing imports that use symlinks to this module.
* Only if no symlink is available, the real path will be used.
* Symlinks will be returned first so they are preferred over the real path.
*/
function getAllModulePaths(files: ReadonlyArray<SourceFile>, importedFileName: string, getCanonicalFileName: (file: string) => string, host: ModuleSpecifierResolutionHost): ReadonlyArray<string> {
const symlinks = mapDefined(files, sf =>
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
res && res.resolvedFileName === importedFileName ? res.originalPath : undefined));
function getAllModulePaths(files: ReadonlyArray<SourceFile>, importingFileName: string, importedFileName: string, getCanonicalFileName: GetCanonicalFileName, host: ModuleSpecifierResolutionHost, redirectTargetsMap: RedirectTargetsMap): ReadonlyArray<string> {
const redirects = redirectTargetsMap.get(importedFileName);
const importedFileNames = redirects ? [...redirects, importedFileName] : [importedFileName];
const cwd = host.getCurrentDirectory ? host.getCurrentDirectory() : "";
const baseOptions = getAllModulePathsUsingIndirectSymlinks(files, getNormalizedAbsolutePath(importedFileName, cwd), getCanonicalFileName, host);
if (symlinks.length === 0) {
return baseOptions;
}
return deduplicate(concatenate(baseOptions, flatMap(symlinks, importedFileName => getAllModulePathsUsingIndirectSymlinks(files, getNormalizedAbsolutePath(importedFileName, cwd), getCanonicalFileName, host))));
const targets = importedFileNames.map(f => getNormalizedAbsolutePath(f, cwd));
const links = discoverProbableSymlinks(files, getCanonicalFileName, cwd);
const result: string[] = [];
const compareStrings = (!host.useCaseSensitiveFileNames || host.useCaseSensitiveFileNames()) ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
links.forEach((resolved, path) => {
if (startsWithDirectory(importingFileName, resolved, getCanonicalFileName)) {
return; // Don't want to a package to globally import from itself
}
const target = targets.find(t => compareStrings(t.slice(0, resolved.length + 1), resolved + "/") === Comparison.EqualTo);
if (target === undefined) return;
const relative = getRelativePathFromDirectory(resolved, target, getCanonicalFileName);
const option = resolvePath(path, relative);
if (!host.fileExists || host.fileExists(option)) {
result.push(option);
}
});
result.push(...targets);
return result;
}
function getRelativePathNParents(relativePath: string): number {
+20 -6
View File
@@ -491,6 +491,8 @@ namespace ts {
visitNode(cbNode, (node as JSDocCallbackTag).typeExpression);
case SyntaxKind.JSDocThisTag:
return visitNode(cbNode, (node as JSDocThisTag).typeExpression);
case SyntaxKind.JSDocEnumTag:
return visitNode(cbNode, (node as JSDocEnumTag).typeExpression);
case SyntaxKind.JSDocSignature:
return visitNodes(cbNode, cbNodes, node.decorators) ||
visitNodes(cbNode, cbNodes, node.modifiers) ||
@@ -6398,7 +6400,7 @@ namespace ts {
switch (token()) {
case SyntaxKind.AtToken:
if (state === JSDocState.BeginningOfLine || state === JSDocState.SawAsterisk) {
removeTrailingNewlines(comments);
removeTrailingWhitespace(comments);
addTag(parseTag(indent));
// NOTE: According to usejsdoc.org, a tag goes to end of line, except the last tag.
// Real-world comments may break this rule, so "BeginningOfLine" will not be a real line beginning
@@ -6458,7 +6460,7 @@ namespace ts {
nextJSDocToken();
}
removeLeadingNewlines(comments);
removeTrailingNewlines(comments);
removeTrailingWhitespace(comments);
return createJSDocComment();
});
@@ -6468,8 +6470,8 @@ namespace ts {
}
}
function removeTrailingNewlines(comments: string[]) {
while (comments.length && (comments[comments.length - 1] === "\n" || comments[comments.length - 1] === "\r")) {
function removeTrailingWhitespace(comments: string[]) {
while (comments.length && comments[comments.length - 1].trim() === "") {
comments.pop();
}
}
@@ -6527,6 +6529,9 @@ namespace ts {
case "this":
tag = parseThisTag(atToken, tagName);
break;
case "enum":
tag = parseEnumTag(atToken, tagName);
break;
case "arg":
case "argument":
case "param":
@@ -6627,7 +6632,7 @@ namespace ts {
}
removeLeadingNewlines(comments);
removeTrailingNewlines(comments);
removeTrailingWhitespace(comments);
return comments.length === 0 ? undefined : comments.join("");
}
@@ -6817,6 +6822,15 @@ namespace ts {
return finishNode(tag);
}
function parseEnumTag(atToken: AtToken, tagName: Identifier): JSDocEnumTag {
const tag = <JSDocEnumTag>createNode(SyntaxKind.JSDocEnumTag, atToken.pos);
tag.atToken = atToken;
tag.tagName = tagName;
tag.typeExpression = parseJSDocTypeExpression(/*mayOmitBraces*/ true);
skipWhitespace();
return finishNode(tag);
}
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
@@ -7030,8 +7044,8 @@ namespace ts {
skipWhitespace();
const typeParameter = <TypeParameterDeclaration>createNode(SyntaxKind.TypeParameter);
typeParameter.name = parseJSDocIdentifierName(Diagnostics.Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces);
skipWhitespace();
finishNode(typeParameter);
skipWhitespace();
typeParameters.push(typeParameter);
} while (parseOptionalJsdoc(SyntaxKind.CommaToken));
+11 -19
View File
@@ -634,7 +634,8 @@ namespace ts {
const packageIdToSourceFile = createMap<SourceFile>();
// Maps from a SourceFile's `.path` to the name of the package it was imported with.
let sourceFileToPackageName = createMap<string>();
let redirectTargetsSet = createMap<true>();
// Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it.
let redirectTargetsMap = createMultiMap<string>();
const filesByName = createMap<SourceFile | undefined>();
let missingFilePaths: ReadonlyArray<Path> | undefined;
@@ -752,7 +753,7 @@ namespace ts {
getSourceFileFromReference,
getLibFileFromReference,
sourceFileToPackageName,
redirectTargetsSet,
redirectTargetsMap,
isEmittedFile,
getConfigFileParsingDiagnostics,
getResolvedModuleWithFailedLookupLocationsFromCache,
@@ -1073,7 +1074,7 @@ namespace ts {
fileChanged = false;
newSourceFile = oldSourceFile; // Use the redirect.
}
else if (oldProgram.redirectTargetsSet.has(oldSourceFile.path)) {
else if (oldProgram.redirectTargetsMap.has(oldSourceFile.path)) {
// If a redirected-to source file changes, the redirect may be broken.
if (newSourceFile !== oldSourceFile) {
return oldProgram.structureIsReused = StructureIsReused.Not;
@@ -1220,7 +1221,7 @@ namespace ts {
resolvedProjectReferences = oldProgram.getProjectReferences();
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
redirectTargetsSet = oldProgram.redirectTargetsSet;
redirectTargetsMap = oldProgram.redirectTargetsMap;
return oldProgram.structureIsReused = StructureIsReused.Completely;
}
@@ -2079,7 +2080,7 @@ namespace ts {
// Some other SourceFile already exists with this package name and version.
// Instead of creating a duplicate, just redirect to the existing one.
const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path); // TODO: GH#18217
redirectTargetsSet.set(fileFromPackageId.path, true);
redirectTargetsMap.add(fileFromPackageId.path, fileName);
filesByName.set(path, dupFile);
sourceFileToPackageName.set(path, packageId.name);
processingOtherFiles!.push(dupFile);
@@ -2711,12 +2712,12 @@ namespace ts {
function createDiagnosticForReference(index: number, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number) {
const referencesSyntax = getProjectReferencesSyntax();
if (referencesSyntax) {
if (createOptionDiagnosticInArrayLiteralSyntax(referencesSyntax, index, message, arg0, arg1)) {
return;
}
if (referencesSyntax && referencesSyntax.elements.length > index) {
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, referencesSyntax.elements[index], message, arg0, arg1));
}
else {
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
}
programDiagnostics.add(createCompilerDiagnostic(message, arg0, arg1));
}
function createDiagnosticForOption(onKey: boolean, option1: string, option2: string | undefined, message: DiagnosticMessage, arg0: string | number, arg1?: string | number, arg2?: string | number) {
@@ -2769,15 +2770,6 @@ namespace ts {
return !!props.length;
}
function createOptionDiagnosticInArrayLiteralSyntax(arrayLiteral: ArrayLiteralExpression, index: number, message: DiagnosticMessage, arg0: string | number | undefined, arg1?: string | number, arg2?: string | number): boolean {
if (arrayLiteral.elements.length <= index) {
// Out-of-bounds
return false;
}
programDiagnostics.add(createDiagnosticForNodeInSourceFile(options.configFile!, arrayLiteral.elements[index], message, arg0, arg1, arg2));
return false; // TODO: GH#18217 This function always returns `false`!`
}
function blockEmittingOfFile(emitFileName: string, diag: Diagnostic) {
hasEmitBlockingDiagnostics.set(toPath(emitFileName), true);
programDiagnostics.add(diag);
+17 -6
View File
@@ -52,7 +52,7 @@ namespace ts {
getGlobalCache?(): string | undefined;
writeLog(s: string): void;
maxNumberOfFilesToIterateForInvalidation?: number;
getCurrentProgram(): Program;
getCurrentProgram(): Program | undefined;
}
interface DirectoryWatchesOfFailedLookup {
@@ -398,8 +398,17 @@ namespace ts {
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
// Always watch root directory recursively
return { dir: rootDir!, dirPath: rootPath }; // TODO: GH#18217
failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? failedLookupLocation : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory());
Debug.assert(failedLookupLocation.length === failedLookupLocationPath.length, `FailedLookup: ${failedLookupLocation} failedLookupLocationPath: ${failedLookupLocationPath}`); // tslint:disable-line
const subDirectoryInRoot = failedLookupLocationPath.indexOf(directorySeparator, rootPath.length + 1);
if (subDirectoryInRoot !== -1) {
// Instead of watching root, watch directory in root to avoid watching excluded directories not needed for module resolution
return { dir: failedLookupLocation.substr(0, subDirectoryInRoot), dirPath: failedLookupLocationPath.substr(0, subDirectoryInRoot) as Path };
}
else {
// Always watch root directory non recursively
return { dir: rootDir!, dirPath: rootPath, nonRecursive: false }; // TODO: GH#18217
}
}
return getDirectoryToWatchFromFailedLookupLocationDirectory(
@@ -478,6 +487,7 @@ namespace ts {
customFailedLookupPaths.set(failedLookupLocationPath, refCount + 1);
}
if (dirPath === rootPath) {
Debug.assert(!nonRecursive);
setAtRoot = true;
}
else {
@@ -487,8 +497,8 @@ namespace ts {
}
if (setAtRoot) {
// This is always recursive
setDirectoryWatcher(rootDir!, rootPath); // TODO: GH#18217
// This is always non recursive
setDirectoryWatcher(rootDir!, rootPath, /*nonRecursive*/ true); // TODO: GH#18217
}
}
@@ -497,7 +507,8 @@ namespace ts {
}
function watchFailedLookupLocationOfNonRelativeModuleResolutions(resolutions: ResolutionWithFailedLookupLocations[], name: string) {
const updateResolution = resolutionHost.getCurrentProgram().getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
const program = resolutionHost.getCurrentProgram();
const updateResolution = program && program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(name) ?
setRefCountToUndefined : watchFailedLookupLocationOfResolution;
resolutions.forEach(updateResolution);
}
+8 -2
View File
@@ -1752,6 +1752,12 @@ namespace ts {
type SerializedEntityNameAsExpression = Identifier | BinaryExpression | PropertyAccessExpression;
type SerializedTypeNode = SerializedEntityNameAsExpression | VoidExpression | ConditionalExpression;
function getAccessorTypeNode(node: AccessorDeclaration) {
const accessors = resolver.getAllAccessorDeclarations(node);
return accessors.setAccessor && getSetAccessorTypeAnnotationNode(accessors.setAccessor)
|| accessors.getAccessor && getEffectiveReturnTypeNode(accessors.getAccessor);
}
/**
* Serializes the type of a node for use with decorator type metadata.
*
@@ -1761,10 +1767,10 @@ namespace ts {
switch (node.kind) {
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.Parameter:
case SyntaxKind.GetAccessor:
return serializeTypeNode((<PropertyDeclaration | ParameterDeclaration | GetAccessorDeclaration>node).type);
case SyntaxKind.SetAccessor:
return serializeTypeNode(getSetAccessorTypeAnnotationNode(<SetAccessorDeclaration>node));
case SyntaxKind.GetAccessor:
return serializeTypeNode(getAccessorTypeNode(node as AccessorDeclaration));
case SyntaxKind.ClassDeclaration:
case SyntaxKind.ClassExpression:
case SyntaxKind.MethodDeclaration:
+1 -1
View File
@@ -1268,7 +1268,7 @@ namespace ts {
// Don't report status on "solution" projects
break;
default:
assertTypeIsNever(status);
assertType<never>(status);
}
}
}
+19 -5
View File
@@ -372,6 +372,7 @@ namespace ts {
JSDocAugmentsTag,
JSDocClassTag,
JSDocCallbackTag,
JSDocEnumTag,
JSDocParameterTag,
JSDocReturnTag,
JSDocThisTag,
@@ -581,6 +582,7 @@ namespace ts {
| FunctionTypeNode
| ConstructorTypeNode
| JSDocFunctionType
| ExportDeclaration
| EndOfFileToken;
export type HasType =
@@ -858,6 +860,7 @@ namespace ts {
name?: PropertyName;
}
/** Unlike ObjectLiteralElement, excludes JSXAttribute and JSXSpreadAttribute. */
export type ObjectLiteralElementLike
= PropertyAssignment
| ShorthandPropertyAssignment
@@ -2202,7 +2205,7 @@ namespace ts {
name: Identifier;
}
export interface ExportDeclaration extends DeclarationStatement {
export interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
@@ -2348,6 +2351,11 @@ namespace ts {
kind: SyntaxKind.JSDocClassTag;
}
export interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
export interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
@@ -2543,7 +2551,7 @@ namespace ts {
/**
* If two source files are for the same version of the same package, one will redirect to the other.
* (See `createRedirectSourceFile` in program.ts.)
* The redirect will have this set. The redirected-to source file will be in `redirectTargetsSet`.
* The redirect will have this set. The redirected-to source file will be in `redirectTargetsMap`.
*/
/* @internal */ redirectInfo?: RedirectInfo;
@@ -2790,7 +2798,7 @@ namespace ts {
/** Given a source file, get the name of the package it was imported from. */
/* @internal */ sourceFileToPackageName: Map<string>;
/** Set of all source files that some other source file redirects to. */
/* @internal */ redirectTargetsSet: Map<true>;
/* @internal */ redirectTargetsMap: MultiMap<string>;
/** Is the file emitted file */
/* @internal */ isEmittedFile(file: string): boolean;
@@ -2799,6 +2807,9 @@ namespace ts {
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
}
/* @internal */
export type RedirectTargetsMap = ReadonlyMap<ReadonlyArray<string>>;
export interface ResolvedProjectReference {
commandLine: ParsedCommandLine;
sourceFile: SourceFile;
@@ -2876,6 +2887,8 @@ namespace ts {
getSourceFiles(): ReadonlyArray<SourceFile>;
getSourceFile(fileName: string): SourceFile | undefined;
getResolvedTypeReferenceDirectives(): ReadonlyMap<ResolvedTypeReferenceDirective>;
readonly redirectTargetsMap: RedirectTargetsMap;
}
export interface TypeChecker {
@@ -2964,6 +2977,7 @@ namespace ts {
* @param argumentCount Apparent number of arguments, passed in case of a possibly incomplete call. This should come from an ArgumentListInfo. See `signatureHelp.ts`.
*/
getResolvedSignature(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
/* @internal */ getResolvedSignatureForSignatureHelp(node: CallLikeExpression, candidatesOutArray?: Signature[], argumentCount?: number): Signature | undefined;
getSignatureFromDeclaration(declaration: SignatureDeclaration): Signature | undefined;
isImplementationOfOverload(node: SignatureDeclaration): boolean | undefined;
isUndefinedSymbol(symbol: Symbol): boolean;
@@ -3306,8 +3320,8 @@ namespace ts {
export interface AllAccessorDeclarations {
firstAccessor: AccessorDeclaration;
secondAccessor: AccessorDeclaration | undefined;
getAccessor: AccessorDeclaration | undefined;
setAccessor: AccessorDeclaration | undefined;
getAccessor: GetAccessorDeclaration | undefined;
setAccessor: SetAccessorDeclaration | undefined;
}
/** Indicates how to serialize the name for a TypeReferenceNode when emitting decorator metadata */
+111 -26
View File
@@ -563,11 +563,6 @@ namespace ts {
return isString(value) ? '"' + escapeNonAsciiString(value) + '"' : "" + value;
}
// Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__'
export function escapeLeadingUnderscores(identifier: string): __String {
return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String;
}
// Make an identifier from an external module name by extracting the string after the last "/" and replacing
// all non-alphanumeric characters with underscores
export function makeIdentifierFromModuleName(moduleName: string): string {
@@ -676,6 +671,19 @@ namespace ts {
export function isDeclarationWithTypeParameters(node: Node): node is DeclarationWithTypeParameters;
export function isDeclarationWithTypeParameters(node: DeclarationWithTypeParameters): node is DeclarationWithTypeParameters {
switch (node.kind) {
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocSignature:
return true;
default:
assertType<DeclarationWithTypeParameterChildren>(node);
return isDeclarationWithTypeParameterChildren(node);
}
}
export function isDeclarationWithTypeParameterChildren(node: Node): node is DeclarationWithTypeParameterChildren;
export function isDeclarationWithTypeParameterChildren(node: DeclarationWithTypeParameterChildren): node is DeclarationWithTypeParameterChildren {
switch (node.kind) {
case SyntaxKind.CallSignature:
case SyntaxKind.ConstructSignature:
@@ -696,12 +704,9 @@ namespace ts {
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.JSDocCallbackTag:
case SyntaxKind.JSDocTypedefTag:
case SyntaxKind.JSDocSignature:
return true;
default:
assertTypeIsNever(node);
assertType<never>(node);
return false;
}
}
@@ -786,7 +791,7 @@ namespace ts {
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): DiagnosticWithLocation {
const start = skipTrivia(sourceFile.text, nodes.pos);
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2, arg3);
}
@@ -3305,8 +3310,8 @@ namespace ts {
// TODO: GH#18217
let firstAccessor!: AccessorDeclaration;
let secondAccessor!: AccessorDeclaration;
let getAccessor!: AccessorDeclaration;
let setAccessor!: AccessorDeclaration;
let getAccessor!: GetAccessorDeclaration;
let setAccessor!: SetAccessorDeclaration;
if (hasDynamicName(accessor)) {
firstAccessor = accessor;
if (accessor.kind === SyntaxKind.GetAccessor) {
@@ -3334,11 +3339,11 @@ namespace ts {
}
if (member.kind === SyntaxKind.GetAccessor && !getAccessor) {
getAccessor = <AccessorDeclaration>member;
getAccessor = <GetAccessorDeclaration>member;
}
if (member.kind === SyntaxKind.SetAccessor && !setAccessor) {
setAccessor = <AccessorDeclaration>member;
setAccessor = <SetAccessorDeclaration>member;
}
}
}
@@ -4794,6 +4799,11 @@ namespace ts {
return undefined;
}
/** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */
export function escapeLeadingUnderscores(identifier: string): __String {
return (identifier.length >= 2 && identifier.charCodeAt(0) === CharacterCodes._ && identifier.charCodeAt(1) === CharacterCodes._ ? "_" + identifier : identifier) as __String;
}
/**
* Remove extra underscore from escaped identifier text content.
*
@@ -4985,6 +4995,11 @@ namespace ts {
return getFirstJSDocTag(node, isJSDocClassTag);
}
/** Gets the JSDoc enum tag for the node if present */
export function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined {
return getFirstJSDocTag(node, isJSDocEnumTag);
}
/** Gets the JSDoc this tag for the node if present */
export function getJSDocThisTag(node: Node): JSDocThisTag | undefined {
return getFirstJSDocTag(node, isJSDocThisTag);
@@ -5749,6 +5764,10 @@ namespace ts {
return node.kind === SyntaxKind.JSDocClassTag;
}
export function isJSDocEnumTag(node: Node): node is JSDocEnumTag {
return node.kind === SyntaxKind.JSDocEnumTag;
}
export function isJSDocThisTag(node: Node): node is JSDocThisTag {
return node.kind === SyntaxKind.JSDocThisTag;
}
@@ -6622,18 +6641,7 @@ namespace ts {
}
export function isObjectLiteralElement(node: Node): node is ObjectLiteralElement {
switch (node.kind) {
case SyntaxKind.JsxAttribute:
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.PropertyAssignment:
case SyntaxKind.ShorthandPropertyAssignment:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return true;
default:
return false;
}
return node.kind === SyntaxKind.JsxAttribute || node.kind === SyntaxKind.JsxSpreadAttribute || isObjectLiteralElementLike(node);
}
/* @internal */
@@ -7149,6 +7157,12 @@ namespace ts {
return path.slice(0, Math.max(rootLength, path.lastIndexOf(directorySeparator)));
}
export function startsWithDirectory(fileName: string, directoryName: string, getCanonicalFileName: GetCanonicalFileName): boolean {
const canonicalFileName = getCanonicalFileName(fileName);
const canonicalDirectoryName = getCanonicalFileName(directoryName);
return startsWith(canonicalFileName, canonicalDirectoryName + "/") || startsWith(canonicalFileName, canonicalDirectoryName + "\\");
}
export function isUrl(path: string) {
return getEncodedRootLength(path) < 0;
}
@@ -8128,4 +8142,75 @@ namespace ts {
}
return { min, max };
}
export interface ReadonlyNodeSet<TNode extends Node> {
has(node: TNode): boolean;
forEach(cb: (node: TNode) => void): void;
some(pred: (node: TNode) => boolean): boolean;
}
export class NodeSet<TNode extends Node> implements ReadonlyNodeSet<TNode> {
private map = createMap<TNode>();
add(node: TNode): void {
this.map.set(String(getNodeId(node)), node);
}
tryAdd(node: TNode): boolean {
if (this.has(node)) return false;
this.add(node);
return true;
}
has(node: TNode): boolean {
return this.map.has(String(getNodeId(node)));
}
forEach(cb: (node: TNode) => void): void {
this.map.forEach(cb);
}
some(pred: (node: TNode) => boolean): boolean {
return forEachEntry(this.map, pred) || false;
}
}
export interface ReadonlyNodeMap<TNode extends Node, TValue> {
get(node: TNode): TValue | undefined;
has(node: TNode): boolean;
}
export class NodeMap<TNode extends Node, TValue> implements ReadonlyNodeMap<TNode, TValue> {
private map = createMap<{ node: TNode, value: TValue }>();
get(node: TNode): TValue | undefined {
const res = this.map.get(String(getNodeId(node)));
return res && res.value;
}
getOrUpdate(node: TNode, setValue: () => TValue): TValue {
const res = this.get(node);
if (res) return res;
const value = setValue();
this.set(node, value);
return value;
}
set(node: TNode, value: TValue): void {
this.map.set(String(getNodeId(node)), { node, value });
}
has(node: TNode): boolean {
return this.map.has(String(getNodeId(node)));
}
forEach(cb: (value: TValue, node: TNode) => void): void {
this.map.forEach(({ node, value }) => cb(value, node));
}
}
export function rangeOfNode(node: Node): TextRange {
return { pos: getTokenPosOfNode(node), end: node.end };
}
export function rangeOfTypeParameters(typeParameters: NodeArray<TypeParameterDeclaration>): TextRange {
// Include the `<>`
return { pos: typeParameters.pos - 1, end: typeParameters.end + 1 };
}
}
+2 -2
View File
@@ -1496,8 +1496,8 @@ Actual: ${stringify(fullActual)}`);
const actualTags = selectedItem.tags;
assert.equal(actualTags.length, (options.tags || ts.emptyArray).length, this.assertionMessageAtLastKnownMarker("signature help tags"));
ts.zipWith((options.tags || ts.emptyArray), actualTags, (expectedTag, actualTag) => {
assert.equal(expectedTag.name, actualTag.name);
assert.equal(expectedTag.text, actualTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name));
assert.equal(actualTag.name, expectedTag.name);
assert.equal(actualTag.text, expectedTag.text, this.assertionMessageAtLastKnownMarker("signature help tag " + actualTag.name));
});
const allKeys: ReadonlyArray<keyof FourSlashInterface.VerifySignatureHelpOptions> = [
+9 -2
View File
@@ -75,10 +75,17 @@ class TypeWriterWalker {
const sourceText = ts.getSourceTextOfNodeFromSourceFile(this.currentSourceFile, node);
if (!isSymbolWalk) {
// Don't try to get the type of something that's already a type.
// Exception for `T` in `type T = something` because that may evaluate to some interesting type.
if (ts.isPartOfTypeNode(node) || ts.isIdentifier(node) && !(ts.getMeaningFromDeclaration(node.parent) & ts.SemanticMeaning.Value) && !(ts.isTypeAlias(node.parent) && node.parent.name === node)) {
return undefined;
}
// Workaround to ensure we output 'C' instead of 'typeof C' for base class expressions
// let type = this.checker.getTypeAtLocation(node);
const type = node.parent && ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) && this.checker.getTypeAtLocation(node.parent) || this.checker.getTypeAtLocation(node);
const typeString = type ? this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType) : "No type information available!";
let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) ? this.checker.getTypeAtLocation(node.parent) : undefined;
if (!type || type.flags & ts.TypeFlags.Any) type = this.checker.getTypeAtLocation(node);
const typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType);
return {
line: lineAndCharacter.line,
syntaxKind: node.kind,
+6 -3
View File
@@ -583,6 +583,10 @@ interface Array<T> {}`
return;
}
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Created);
if (isFsFolder(fileOrDirectory)) {
this.invokeDirectoryWatcher(fileOrDirectory.fullPath, "");
this.invokeWatchedDirectoriesRecursiveCallback(fileOrDirectory.fullPath, "");
}
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
}
@@ -599,12 +603,11 @@ interface Array<T> {}`
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
if (isFsFolder(fileOrDirectory)) {
Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming);
const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
// Invoke directory and recursive directory watcher for the folder
// Here we arent invoking recursive directory watchers for the base folders
// since that is something we would want to do for both file as well as folder we are deleting
this.invokeWatchedDirectoriesCallback(fileOrDirectory.fullPath, relativePath);
this.invokeWatchedDirectoriesRecursiveCallback(fileOrDirectory.fullPath, relativePath);
this.invokeWatchedDirectoriesCallback(fileOrDirectory.fullPath, "");
this.invokeWatchedDirectoriesRecursiveCallback(fileOrDirectory.fullPath, "");
}
if (basePath !== fileOrDirectory.path) {
+2313 -1900
View File
File diff suppressed because it is too large. Load diff
+32 -4
View File
@@ -31,10 +31,13 @@ interface DOMStringList {
interface DOMTokenList {
[Symbol.iterator](): IterableIterator<string>;
entries(): IterableIterator<[number, string]>;
keys(): IterableIterator<number>;
values(): IterableIterator<string>;
}
interface DataTransferItemList {
[Symbol.iterator](): IterableIterator<File>;
[Symbol.iterator](): IterableIterator<DataTransferItem>;
}
interface FileList {
@@ -67,9 +70,10 @@ interface HTMLCollectionBase {
interface HTMLCollectionOf<T extends Element> {
[Symbol.iterator](): IterableIterator<T>;
entries(): IterableIterator<[number, T]>;
keys(): IterableIterator<number>;
values(): IterableIterator<T>;
}
interface HTMLFormElement {
[Symbol.iterator](): IterableIterator<Element>;
}
interface HTMLSelectElement {
@@ -147,10 +151,34 @@ interface PluginArray {
interface RTCStatsReport extends ReadonlyMap<string, any> {
}
interface SVGLengthList {
[Symbol.iterator](): IterableIterator<SVGLength>;
}
interface SVGNumberList {
[Symbol.iterator](): IterableIterator<SVGNumber>;
}
interface SVGStringList {
[Symbol.iterator](): IterableIterator<string>;
}
interface SourceBufferList {
[Symbol.iterator](): IterableIterator<SourceBuffer>;
}
interface SpeechGrammarList {
[Symbol.iterator](): IterableIterator<SpeechGrammar>;
}
interface SpeechRecognitionResult {
[Symbol.iterator](): IterableIterator<SpeechRecognitionAlternative>;
}
interface SpeechRecognitionResultList {
[Symbol.iterator](): IterableIterator<SpeechRecognitionResult>;
}
interface StyleSheetList {
[Symbol.iterator](): IterableIterator<StyleSheet>;
}
+477 -94
View File
File diff suppressed because it is too large. Load diff
+87 -32
View File
@@ -326,6 +326,13 @@ namespace ts.server {
syntaxOnly?: boolean;
}
interface OriginalFileInfo { fileName: NormalizedPath; path: Path; }
type OpenScriptInfoOrClosedFileInfo = ScriptInfo | OriginalFileInfo;
function isOpenScriptInfo(infoOrFileName: OpenScriptInfoOrClosedFileInfo): infoOrFileName is ScriptInfo {
return !!(infoOrFileName as ScriptInfo).containingProjects;
}
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
}
@@ -700,7 +707,7 @@ namespace ts.server {
/* @internal */
private forEachProject(cb: (project: Project) => void) {
for (const p of this.inferredProjects) cb(p);
this.inferredProjects.forEach(cb);
this.configuredProjects.forEach(cb);
this.externalProjects.forEach(cb);
}
@@ -1044,12 +1051,12 @@ namespace ts.server {
}
}
private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: string, info: ScriptInfo) {
private configFileExists(configFileName: NormalizedPath, canonicalConfigFilePath: string, info: OpenScriptInfoOrClosedFileInfo) {
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (configFileExistenceInfo) {
// By default the info would get impacted by presence of config file since its in the detection path
// Only adding the info as a root to inferred project will need the existence to be watched by file watcher
if (!configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
if (isOpenScriptInfo(info) && !configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
configFileExistenceInfo.openFilesImpactedByConfigFile.set(info.path, false);
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.OpenFilesImpactedByConfigFileAdd);
}
@@ -1066,9 +1073,11 @@ namespace ts.server {
// Or the whole chain of config files for the roots of the inferred projects
// Cache the host value of file exists and add the info to map of open files impacted by this config file
const openFilesImpactedByConfigFile = createMap<boolean>();
openFilesImpactedByConfigFile.set(info.path, false);
const exists = this.host.fileExists(configFileName);
const openFilesImpactedByConfigFile = createMap<boolean>();
if (isOpenScriptInfo(info)) {
openFilesImpactedByConfigFile.set(info.path, false);
}
configFileExistenceInfo = { exists, openFilesImpactedByConfigFile };
this.configFileExistenceInfoCache.set(canonicalConfigFilePath, configFileExistenceInfo);
this.logConfigFileWatchUpdate(configFileName, canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.OpenFilesImpactedByConfigFileAdd);
@@ -1180,7 +1189,7 @@ namespace ts.server {
*/
private stopWatchingConfigFilesForClosedScriptInfo(info: ScriptInfo) {
Debug.assert(!info.isScriptOpen());
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (configFileExistenceInfo) {
const infoIsRootOfInferredProject = configFileExistenceInfo.openFilesImpactedByConfigFile.get(info.path);
@@ -1214,7 +1223,7 @@ namespace ts.server {
/* @internal */
startWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
Debug.assert(info.isScriptOpen());
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
let configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (!configFileExistenceInfo) {
// Create the cache
@@ -1242,7 +1251,7 @@ namespace ts.server {
*/
/* @internal */
stopWatchingConfigFilesForInferredProjectRoot(info: ScriptInfo) {
this.forEachConfigFileLocation(info, /*infoShouldBeOpen*/ true, (configFileName, canonicalConfigFilePath) => {
this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) => {
const configFileExistenceInfo = this.configFileExistenceInfoCache.get(canonicalConfigFilePath);
if (configFileExistenceInfo && configFileExistenceInfo.openFilesImpactedByConfigFile.has(info.path)) {
Debug.assert(info.isScriptOpen());
@@ -1265,12 +1274,12 @@ namespace ts.server {
* The server must start searching from the directory containing
* the newly opened file.
*/
private forEachConfigFileLocation(info: ScriptInfo, infoShouldBeOpen: boolean, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
private forEachConfigFileLocation(info: OpenScriptInfoOrClosedFileInfo, action: (configFileName: NormalizedPath, canonicalConfigFilePath: string) => boolean | void) {
if (this.syntaxOnly) {
return undefined;
}
Debug.assert(!infoShouldBeOpen || this.openFiles.has(info.path));
Debug.assert(!isOpenScriptInfo(info) || this.openFiles.has(info.path));
const projectRootPath = this.openFiles.get(info.path);
let searchPath = asNormalizedPath(getDirectoryPath(info.fileName));
@@ -1309,11 +1318,13 @@ namespace ts.server {
* current directory (the directory in which tsc was invoked).
* The server must start searching from the directory containing
* the newly opened file.
* If script info is passed in, it is asserted to be open script info
* otherwise just file name
*/
private getConfigFileNameForFile(info: ScriptInfo, infoShouldBeOpen: boolean) {
if (infoShouldBeOpen) Debug.assert(info.isScriptOpen());
private getConfigFileNameForFile(info: OpenScriptInfoOrClosedFileInfo) {
if (isOpenScriptInfo(info)) Debug.assert(info.isScriptOpen());
this.logger.info(`Search path: ${getDirectoryPath(info.fileName)}`);
const configFileName = this.forEachConfigFileLocation(info, infoShouldBeOpen, (configFileName, canonicalConfigFilePath) =>
const configFileName = this.forEachConfigFileLocation(info, (configFileName, canonicalConfigFilePath) =>
this.configFileExists(configFileName, canonicalConfigFilePath, info));
if (configFileName) {
this.logger.info(`For info: ${info.fileName} :: Config file name: ${configFileName}`);
@@ -1683,10 +1694,12 @@ namespace ts.server {
if (!this.eventHandler || this.suppressDiagnosticEvents) {
return;
}
const diagnostics = project.getLanguageService().getCompilerOptionsDiagnostics();
diagnostics.push(...project.getAllProjectErrors());
this.eventHandler(<ConfigFileDiagEvent>{
eventName: ConfigFileDiagEvent,
data: { configFileName: project.getConfigFilePath(), diagnostics: project.getAllProjectErrors(), triggerFile }
data: { configFileName: project.getConfigFilePath(), diagnostics, triggerFile }
});
}
@@ -2003,7 +2016,7 @@ namespace ts.server {
// we first detect if there is already a configured project created for it: if so,
// we re- read the tsconfig file content and update the project only if we havent already done so
// otherwise we create a new one.
const configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
const configFileName = this.getConfigFileNameForFile(info);
if (configFileName) {
const project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
@@ -2091,17 +2104,40 @@ namespace ts.server {
return this.openClientFileWithNormalizedPath(toNormalizedPath(fileName), fileContent, scriptKind, /*hasMixedContent*/ false, projectRootPath ? toNormalizedPath(projectRootPath) : undefined);
}
/** @internal */
getProjectForFileWithoutOpening(fileName: NormalizedPath): { readonly scriptInfo: ScriptInfo, readonly projects: ReadonlyArray<Project> } | undefined {
const scriptInfo = this.filenameToScriptInfo.get(fileName) ||
this.getOrCreateScriptInfoNotOpenedByClientForNormalizedPath(fileName, this.currentDirectory, /*fileContent*/ undefined, /*scriptKind*/ undefined, /*hasMixedContent*/ undefined);
if (!scriptInfo) return undefined;
if (scriptInfo.containingProjects.length) {
return { scriptInfo, projects: scriptInfo.containingProjects };
/*@internal*/
getOriginalLocationEnsuringConfiguredProject(project: Project, location: sourcemaps.SourceMappableLocation): sourcemaps.SourceMappableLocation | undefined {
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
if (!originalLocation) return undefined;
const { fileName } = originalLocation;
if (!this.getScriptInfo(fileName) && !this.host.fileExists(fileName)) return undefined;
const originalFileInfo: OriginalFileInfo = { fileName: toNormalizedPath(fileName), path: this.toPath(fileName) };
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
if (!configFileName) return undefined;
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
updateProjectIfDirty(configuredProject);
// Keep this configured project as referenced from project
addOriginalConfiguredProject(configuredProject);
const originalScriptInfo = this.getScriptInfo(fileName);
if (!originalScriptInfo || !originalScriptInfo.containingProjects.length) return undefined;
// Add configured projects as referenced
originalScriptInfo.containingProjects.forEach(project => {
if (project.projectKind === ProjectKind.Configured) {
addOriginalConfiguredProject(project as ConfiguredProject);
}
});
return originalLocation;
function addOriginalConfiguredProject(originalProject: ConfiguredProject) {
if (!project.originalConfiguredProjects) {
project.originalConfiguredProjects = createMap<true>();
}
project.originalConfiguredProjects.set(originalProject.canonicalConfigFilePath, true);
}
const configFileName = this.getConfigFileNameForFile(scriptInfo, /*infoShouldBeOpen*/ false);
const project = configFileName === undefined ? undefined : this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
return project && project.containsScriptInfo(scriptInfo) ? { scriptInfo, projects: [project] } : undefined;
}
/** @internal */
@@ -2126,7 +2162,7 @@ namespace ts.server {
this.openFiles.set(info.path, projectRootPath);
let project: ConfiguredProject | ExternalProject | undefined = this.findExternalProjectContainingOpenScriptInfo(info);
if (!project && !this.syntaxOnly) { // Checking syntaxOnly is an optimization
configFileName = this.getConfigFileNameForFile(info, /*infoShouldBeOpen*/ true);
configFileName = this.getConfigFileNameForFile(info);
if (configFileName) {
project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
@@ -2164,14 +2200,9 @@ namespace ts.server {
}
Debug.assert(!info.isOrphan());
// Remove the configured projects that have zero references from open files.
// This was postponed from closeOpenFile to after opening next file,
// so that we can reuse the project if we need to right away
this.configuredProjects.forEach(project => {
if (!project.hasOpenRef()) {
this.removeProject(project);
}
});
this.removeOrphanConfiguredProjects();
// Remove orphan inferred projects now that we have reused projects
// We need to create a duplicate because we cant guarantee order after removal
@@ -2199,6 +2230,30 @@ namespace ts.server {
return { configFileName, configFileErrors };
}
private removeOrphanConfiguredProjects() {
const toRemoveConfiguredProjects = cloneMap(this.configuredProjects);
// Do not remove configured projects that are used as original projects of other
this.inferredProjects.forEach(markOriginalProjectsAsUsed);
this.externalProjects.forEach(markOriginalProjectsAsUsed);
this.configuredProjects.forEach(project => {
// If project has open ref (there are more than zero references from external project/open file), keep it alive as well as any project it references
if (project.hasOpenRef()) {
toRemoveConfiguredProjects.delete(project.canonicalConfigFilePath);
markOriginalProjectsAsUsed(project);
}
});
// Remove all the non marked projects
toRemoveConfiguredProjects.forEach(project => this.removeProject(project));
function markOriginalProjectsAsUsed(project: Project) {
if (!project.isOrphan() && project.originalConfiguredProjects) {
project.originalConfiguredProjects.forEach((_value, configuredProjectPath) => toRemoveConfiguredProjects.delete(configuredProjectPath));
}
}
}
private telemetryOnOpenFile(scriptInfo: ScriptInfo): void {
if (this.syntaxOnly || !this.eventHandler || !scriptInfo.isJavaScript() || !addToSeen(this.allJsFilesForOpenFileTelemetry, scriptInfo.path)) {
return;
+4 -1
View File
@@ -158,6 +158,9 @@ namespace ts.server {
/*@internal*/
typingFiles: SortedReadonlyArray<string> = emptyArray;
/*@internal*/
originalConfiguredProjects: Map<true> | undefined;
private readonly cancellationToken: ThrottledCancellationToken;
public isNonTsProject() {
@@ -711,7 +714,7 @@ namespace ts.server {
}
containsFile(filename: NormalizedPath, requireOpen?: boolean): boolean {
const info = this.projectService.getScriptInfoForPath(this.toPath(filename));
const info = this.projectService.getScriptInfoForNormalizedPath(filename);
if (info && (info.isScriptOpen() || !requireOpen)) {
return this.containsScriptInfo(info);
}
+25 -29
View File
@@ -258,10 +258,6 @@ namespace ts.server {
readonly symLinkedProjects: MultiMap<Project>;
};
function isProjectsArray(projects: Projects): projects is ReadonlyArray<Project> {
return !!(<ReadonlyArray<Project>>projects).length;
}
/**
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
*/
@@ -273,8 +269,8 @@ namespace ts.server {
comparer?: (a: U, b: U) => number,
areEqual?: (a: U, b: U) => boolean,
): U[] {
const outputs = flatMap(isProjectsArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
if (!isProjectsArray(projects) && projects.symLinkedProjects) {
const outputs = flatMap(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
if (!isArray(projects) && projects.symLinkedProjects) {
projects.symLinkedProjects.forEach((projects, path) => {
const value = getValue(path as Path);
outputs.push(...flatMap(projects, project => action(project, value)));
@@ -370,7 +366,7 @@ namespace ts.server {
}
function forEachProjectInProjects(projects: Projects, path: string | undefined, cb: (project: Project, path: string | undefined) => void): void {
for (const project of isProjectsArray(projects) ? projects : projects.projects) {
for (const project of isArray(projects) ? projects : projects.projects) {
cb(project, path);
}
if (!isArray(projects) && projects.symLinkedProjects) {
@@ -431,23 +427,20 @@ namespace ts.server {
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
cb(projectAndLocation, (project, location) => {
seenProjects.set(projectAndLocation.project.projectName, true);
const originalLocation = project.getSourceMapper().tryGetOriginalLocation(location);
const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, location);
if (!originalLocation) return false;
const originalProjectAndScriptInfo = projectService.getProjectForFileWithoutOpening(toNormalizedPath(originalLocation.fileName));
if (!originalProjectAndScriptInfo) return false;
if (originalProjectAndScriptInfo) {
toDo = toDo || [];
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!;
toDo = toDo || [];
for (const project of originalProjectAndScriptInfo.projects) {
addToTodo({ project, location: originalLocation as TLocation }, toDo, seenProjects);
}
const symlinkedProjectsMap = projectService.getSymlinkedProjects(originalProjectAndScriptInfo.scriptInfo);
if (symlinkedProjectsMap) {
symlinkedProjectsMap.forEach((symlinkedProjects) => {
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
});
}
for (const project of originalScriptInfo.containingProjects) {
addToTodo({ project, location: originalLocation as TLocation }, toDo, seenProjects);
}
const symlinkedProjectsMap = projectService.getSymlinkedProjects(originalScriptInfo);
if (symlinkedProjectsMap) {
symlinkedProjectsMap.forEach((symlinkedProjects) => {
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
});
}
return true;
});
@@ -1106,7 +1099,7 @@ namespace ts.server {
return project.getLanguageService().getRenameInfo(file, position);
}
private getProjects(args: protocol.FileRequestArgs): Projects {
private getProjects(args: protocol.FileRequestArgs, getScriptInfoEnsuringProjectsUptoDate?: boolean, ignoreNoProjectError?: boolean): Projects {
let projects: ReadonlyArray<Project> | undefined;
let symLinkedProjects: MultiMap<Project> | undefined;
if (args.projectFileName) {
@@ -1116,13 +1109,18 @@ namespace ts.server {
}
}
else {
const scriptInfo = this.projectService.getScriptInfo(args.file)!;
const scriptInfo = getScriptInfoEnsuringProjectsUptoDate ?
this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file) :
this.projectService.getScriptInfo(args.file);
if (!scriptInfo) {
return ignoreNoProjectError ? emptyArray : Errors.ThrowNoProject();
}
projects = scriptInfo.containingProjects;
symLinkedProjects = this.projectService.getSymlinkedProjects(scriptInfo);
}
// filter handles case when 'projects' is undefined
projects = filter(projects, p => p.languageServiceEnabled && !p.isOrphan());
if ((!projects || !projects.length) && !symLinkedProjects) {
if (!ignoreNoProjectError && (!projects || !projects.length) && !symLinkedProjects) {
return Errors.ThrowNoProject();
}
return symLinkedProjects ? { projects: projects!, symLinkedProjects } : projects!; // TODO: GH#18217
@@ -1465,18 +1463,16 @@ namespace ts.server {
}
private getCompileOnSaveAffectedFileList(args: protocol.FileRequestArgs): ReadonlyArray<protocol.CompileOnSaveAffectedFileListSingleProject> {
const info = this.projectService.getScriptInfoEnsuringProjectsUptoDate(args.file);
const projects = this.getProjects(args, /*getScriptInfoEnsuringProjectsUptoDate*/ true, /*ignoreNoProjectError*/ true);
const info = this.projectService.getScriptInfo(args.file);
if (!info) {
return emptyArray;
}
// if specified a project, we only return affected file list in this project
const projects = args.projectFileName ? [this.projectService.findProject(args.projectFileName)!] : info.containingProjects;
const symLinkedProjects = !args.projectFileName && this.projectService.getSymlinkedProjects(info);
return combineProjectOutput(
info,
path => this.projectService.getScriptInfoForPath(path)!,
symLinkedProjects ? { projects, symLinkedProjects } : projects,
projects,
(project, info) => {
let result: protocol.CompileOnSaveAffectedFileListSingleProject | undefined;
if (project.compileOnSaveEnabled && project.languageServiceEnabled && !project.isOrphan() && !project.getCompilationSettings().noEmit) {
+56 -13
View File
@@ -3,6 +3,7 @@ namespace ts.codefix {
const fixName = "unusedIdentifier";
const fixIdPrefix = "unusedIdentifier_prefix";
const fixIdDelete = "unusedIdentifier_delete";
const fixIdInfer = "unusedIdentifier_infer";
const errorCodes = [
Diagnostics._0_is_declared_but_its_value_is_never_read.code,
Diagnostics._0_is_declared_but_never_used.code,
@@ -10,6 +11,7 @@ namespace ts.codefix {
Diagnostics.All_imports_in_import_declaration_are_unused.code,
Diagnostics.All_destructured_elements_are_unused.code,
Diagnostics.All_variables_are_unused.code,
Diagnostics.All_type_parameters_are_unused.code,
];
registerCodeFix({
@@ -20,28 +22,42 @@ namespace ts.codefix {
const sourceFiles = program.getSourceFiles();
const token = getTokenAtPosition(sourceFile, context.span.start);
if (isJSDocTemplateTag(token)) {
return [createDeleteFix(textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, token)), Diagnostics.Remove_template_tag)];
}
if (token.kind === SyntaxKind.LessThanToken) {
const changes = textChanges.ChangeTracker.with(context, t => deleteTypeParameters(t, sourceFile, token));
return [createDeleteFix(changes, Diagnostics.Remove_type_parameters)];
}
const importDecl = tryGetFullImport(token);
if (importDecl) {
const changes = textChanges.ChangeTracker.with(context, t => t.delete(sourceFile, importDecl));
return [createCodeFixAction(fixName, changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)], fixIdDelete, Diagnostics.Delete_all_unused_declarations)];
return [createDeleteFix(changes, [Diagnostics.Remove_import_from_0, showModuleSpecifier(importDecl)])];
}
const delDestructure = textChanges.ChangeTracker.with(context, t =>
tryDeleteFullDestructure(token, t, sourceFile, checker, sourceFiles, /*isFixAll*/ false));
if (delDestructure.length) {
return [createCodeFixAction(fixName, delDestructure, Diagnostics.Remove_destructuring, fixIdDelete, Diagnostics.Delete_all_unused_declarations)];
return [createDeleteFix(delDestructure, Diagnostics.Remove_destructuring)];
}
const delVar = textChanges.ChangeTracker.with(context, t => tryDeleteFullVariableStatement(sourceFile, token, t));
if (delVar.length) {
return [createCodeFixAction(fixName, delVar, Diagnostics.Remove_variable_statement, fixIdDelete, Diagnostics.Delete_all_unused_declarations)];
return [createDeleteFix(delVar, Diagnostics.Remove_variable_statement)];
}
const result: CodeFixAction[] = [];
const deletion = textChanges.ChangeTracker.with(context, t =>
tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, /*isFixAll*/ false));
if (deletion.length) {
const name = isComputedPropertyName(token.parent) ? token.parent : token;
result.push(createCodeFixAction(fixName, deletion, [Diagnostics.Remove_declaration_for_Colon_0, name.getText(sourceFile)], fixIdDelete, Diagnostics.Delete_all_unused_declarations));
if (token.kind === SyntaxKind.InferKeyword) {
const changes = textChanges.ChangeTracker.with(context, t => changeInferToUnknown(t, sourceFile, token));
const name = cast(token.parent, isInferTypeNode).typeParameter.name.text;
result.push(createCodeFixAction(fixName, changes, [Diagnostics.Replace_infer_0_with_unknown, name], fixIdInfer, Diagnostics.Replace_all_unused_infer_with_unknown));
}
else {
const deletion = textChanges.ChangeTracker.with(context, t =>
tryDeleteDeclaration(sourceFile, token, t, checker, sourceFiles, /*isFixAll*/ false));
if (deletion.length) {
const name = isComputedPropertyName(token.parent) ? token.parent : token;
result.push(createDeleteFix(deletion, [Diagnostics.Remove_declaration_for_Colon_0, name.getText(sourceFile)]));
}
}
const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, errorCode, sourceFile, token));
@@ -51,7 +67,7 @@ namespace ts.codefix {
return result;
},
fixIds: [fixIdPrefix, fixIdDelete],
fixIds: [fixIdPrefix, fixIdDelete, fixIdInfer],
getAllCodeActions: context => {
const { sourceFile, program } = context;
const checker = program.getTypeChecker();
@@ -60,21 +76,31 @@ namespace ts.codefix {
const token = getTokenAtPosition(sourceFile, diag.start);
switch (context.fixId) {
case fixIdPrefix:
if (isIdentifier(token) && canPrefix(token)) {
tryPrefixDeclaration(changes, diag.code, sourceFile, token);
}
tryPrefixDeclaration(changes, diag.code, sourceFile, token);
break;
case fixIdDelete: {
if (token.kind === SyntaxKind.InferKeyword) break; // Can't delete
const importDecl = tryGetFullImport(token);
if (importDecl) {
changes.delete(sourceFile, importDecl);
}
else if (isJSDocTemplateTag(token)) {
changes.delete(sourceFile, token);
}
else if (token.kind === SyntaxKind.LessThanToken) {
deleteTypeParameters(changes, sourceFile, token);
}
else if (!tryDeleteFullDestructure(token, changes, sourceFile, checker, sourceFiles, /*isFixAll*/ true) &&
!tryDeleteFullVariableStatement(sourceFile, token, changes)) {
tryDeleteDeclaration(sourceFile, token, changes, checker, sourceFiles, /*isFixAll*/ true);
}
break;
}
case fixIdInfer:
if (token.kind === SyntaxKind.InferKeyword) {
changeInferToUnknown(changes, sourceFile, token);
}
break;
default:
Debug.fail(JSON.stringify(context.fixId));
}
@@ -82,6 +108,18 @@ namespace ts.codefix {
},
});
function changeInferToUnknown(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
changes.replaceNode(sourceFile, token.parent, createKeywordTypeNode(SyntaxKind.UnknownKeyword));
}
function createDeleteFix(changes: FileTextChanges[], diag: DiagnosticAndArguments): CodeFixAction {
return createCodeFixAction(fixName, changes, diag, fixIdDelete, Diagnostics.Delete_all_unused_declarations);
}
function deleteTypeParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
changes.delete(sourceFile, Debug.assertDefined(cast(token.parent, isDeclarationWithTypeParameterChildren).typeParameters));
}
// Sometimes the diagnostic span is an entire ImportDeclaration, so we should remove the whole thing.
function tryGetFullImport(token: Node): ImportDeclaration | undefined {
return token.kind === SyntaxKind.ImportKeyword ? tryCast(token.parent, isImportDeclaration) : undefined;
@@ -110,7 +148,11 @@ namespace ts.codefix {
function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
// Don't offer to prefix a property.
if (errorCode !== Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code && isIdentifier(token) && canPrefix(token)) {
if (errorCode === Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code) return;
if (token.kind === SyntaxKind.InferKeyword) {
token = cast(token.parent, isInferTypeNode).typeParameter.name;
}
if (isIdentifier(token) && canPrefix(token)) {
changes.replaceNode(sourceFile, token, createIdentifier(`_${token.text}`));
}
}
@@ -118,6 +160,7 @@ namespace ts.codefix {
function canPrefix(token: Identifier): boolean {
switch (token.parent.kind) {
case SyntaxKind.Parameter:
case SyntaxKind.TypeParameter:
return true;
case SyntaxKind.VariableDeclaration: {
const varDecl = token.parent as VariableDeclaration;
+3 -3
View File
@@ -275,7 +275,7 @@ namespace ts.codefix {
): ReadonlyArray<FixAddNewImport | FixUseImportType> {
const isJs = isSourceFileJavaScript(sourceFile);
const choicesForEachExportingModule = flatMap<SymbolExportInfo, ReadonlyArray<FixAddNewImport | FixUseImportType>>(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) => {
const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences);
const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap);
return modulePathsGroups.map(group => group.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
@@ -465,14 +465,14 @@ namespace ts.codefix {
const { importClause, importKind } = fix;
doAddExistingFix(changes, sourceFile, importClause, importKind === ImportKind.Default ? symbolName : undefined, importKind === ImportKind.Named ? [symbolName] : emptyArray);
const moduleSpecifierWithoutQuotes = stripQuotes(importClause.parent.moduleSpecifier.getText());
return [Diagnostics.Add_0_to_existing_import_declaration_from_1, symbolName, moduleSpecifierWithoutQuotes];
return [importKind === ImportKind.Default ? Diagnostics.Add_default_import_0_to_existing_import_declaration_from_1 : Diagnostics.Add_0_to_existing_import_declaration_from_1, symbolName, moduleSpecifierWithoutQuotes]; // you too!
}
case ImportFixKind.AddNew: {
const { importKind, moduleSpecifier } = fix;
addNewImports(changes, sourceFile, moduleSpecifier, quotePreference, importKind === ImportKind.Default ? { defaultImport: symbolName, namedImports: emptyArray, namespaceLikeImport: undefined }
: importKind === ImportKind.Named ? { defaultImport: undefined, namedImports: [symbolName], namespaceLikeImport: undefined }
: { defaultImport: undefined, namedImports: emptyArray, namespaceLikeImport: { importKind, name: symbolName } });
return [Diagnostics.Import_0_from_module_1, symbolName, moduleSpecifier];
return [importKind === ImportKind.Default ? Diagnostics.Import_default_0_from_module_1 : Diagnostics.Import_0_from_module_1, symbolName, moduleSpecifier];
}
default:
return Debug.assertNever(fix);
+1 -1
View File
@@ -28,7 +28,7 @@ namespace ts.DocumentHighlights {
const map = arrayToMultiMap(referenceEntries.map(FindAllReferences.toHighlightSpan), e => e.fileName, e => e.span);
return arrayFrom(map.entries(), ([fileName, highlightSpans]) => {
if (!sourceFilesSet.has(fileName)) {
Debug.assert(program.redirectTargetsSet.has(fileName));
Debug.assert(program.redirectTargetsMap.has(fileName));
const redirectTarget = program.getSourceFile(fileName);
const redirect = find(sourceFilesToSearch, f => !!f.redirectInfo && f.redirectInfo.redirectTarget === redirectTarget)!;
fileName = redirect.fileName;
+6 -3
View File
@@ -354,12 +354,15 @@ namespace ts.formatting {
case SyntaxKind.ClassExpression:
case SyntaxKind.InterfaceDeclaration:
case SyntaxKind.TypeAliasDeclaration:
return getListIfStartEndIsInListRange((<ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration>node.parent).typeParameters, node.getStart(sourceFile), end);
case SyntaxKind.JSDocTemplateTag: {
const { typeParameters } = <ClassDeclaration | ClassExpression | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag>node.parent;
return getListIfStartEndIsInListRange(typeParameters, node.getStart(sourceFile), end);
}
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression: {
const start = node.getStart(sourceFile);
return getListIfStartEndIsInListRange((<CallExpression>node.parent).typeArguments, start, end) ||
getListIfStartEndIsInListRange((<CallExpression>node.parent).arguments, start, end);
return getListIfStartEndIsInListRange((<CallExpression | NewExpression>node.parent).typeArguments, start, end) ||
getListIfStartEndIsInListRange((<CallExpression | NewExpression>node.parent).arguments, start, end);
}
case SyntaxKind.VariableDeclarationList:
return getListIfStartEndIsInListRange((<VariableDeclarationList>node.parent).declarations, node.getStart(sourceFile), end);
+1 -1
View File
@@ -156,7 +156,7 @@ namespace ts {
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text)))
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences)
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences, program.redirectTargetsMap)
: undefined;
});
}
+6 -4
View File
@@ -272,14 +272,16 @@ namespace ts.JsDoc {
*/
export function getDocCommentTemplateAtPosition(newLine: string, sourceFile: SourceFile, position: number): TextInsertion | undefined {
// Check if in a context where we don't want to perform any insertion
if (isInString(sourceFile, position) || isInComment(sourceFile, position) || hasDocComment(sourceFile, position)) {
const tokenAtPos = getTokenAtPosition(sourceFile, position);
const existingDocComment = findAncestor(tokenAtPos, isJSDoc);
if (existingDocComment && (existingDocComment.comment !== undefined || length(existingDocComment.tags))) {
// Non-empty comment already exists.
return undefined;
}
const tokenAtPos = getTokenAtPosition(sourceFile, position);
const tokenStart = tokenAtPos.getStart(sourceFile);
if (!tokenAtPos || tokenStart < position) {
// Don't provide a doc comment template based on a *previous* node. (But an existing empty jsdoc comment will likely start before `position`.)
if (!existingDocComment && tokenStart < position) {
return undefined;
}
+1 -1
View File
@@ -1240,7 +1240,7 @@ namespace ts.refactor.extractSymbol {
return scope.members;
}
else {
assertTypeIsNever(scope);
assertType<never>(scope);
}
return emptyArray;
+9 -24
View File
@@ -66,7 +66,7 @@ namespace ts.SignatureHelp {
return undefined;
}
const candidates: Signature[] = [];
const resolvedSignature = checker.getResolvedSignature(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
}
else if (invocation.kind === InvocationKind.TypeArgs) {
@@ -101,31 +101,16 @@ namespace ts.SignatureHelp {
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
// See if we can find some symbol with the call expression name that has call signatures.
const expression = getExpressionFromInvocation(argumentInfo.invocation);
const name = isIdentifier(expression) ? expression : isPropertyAccessExpression(expression) ? expression.name : undefined;
if (!name || !name.escapedText) {
return undefined;
}
const name = isIdentifier(expression) ? expression.text : isPropertyAccessExpression(expression) ? expression.name.text : undefined;
const typeChecker = program.getTypeChecker();
for (const sourceFile of program.getSourceFiles()) {
const nameToDeclarations = sourceFile.getNamedDeclarations();
const declarations = nameToDeclarations.get(name.text);
if (declarations) {
for (const declaration of declarations) {
const symbol = declaration.symbol;
if (symbol) {
const type = typeChecker.getTypeOfSymbolAtLocation(symbol, declaration);
if (type) {
const callSignatures = type.getCallSignatures();
if (callSignatures && callSignatures.length) {
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo, sourceFile, typeChecker));
}
}
}
return name === undefined ? undefined : firstDefined(program.getSourceFiles(), sourceFile =>
firstDefined(sourceFile.getNamedDeclarations().get(name), declaration => {
const type = declaration.symbol && typeChecker.getTypeOfSymbolAtLocation(declaration.symbol, declaration);
const callSignatures = type && type.getCallSignatures();
if (callSignatures && callSignatures.length) {
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(callSignatures, callSignatures[0], argumentInfo, sourceFile, typeChecker));
}
}
}
}));
}
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
+14 -39
View File
@@ -213,7 +213,7 @@ namespace ts.textChanges {
private readonly changes: Change[] = [];
private readonly newFiles: { readonly oldFile: SourceFile, readonly fileName: string, readonly statements: ReadonlyArray<Statement> }[] = [];
private readonly classesWithNodesInsertedAtStart = createMap<ClassDeclaration>(); // Set<ClassDeclaration> implemented as Map<node id, ClassDeclaration>
private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node }[] = [];
private readonly deletedNodes: { readonly sourceFile: SourceFile, readonly node: Node | NodeArray<TypeParameterDeclaration> }[] = [];
public static fromContext(context: TextChangesContext): ChangeTracker {
return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options), context.formatContext);
@@ -233,8 +233,8 @@ namespace ts.textChanges {
return this;
}
delete(sourceFile: SourceFile, node: Node): void {
this.deletedNodes.push({ sourceFile, node, });
delete(sourceFile: SourceFile, node: Node | NodeArray<TypeParameterDeclaration>): void {
this.deletedNodes.push({ sourceFile, node });
}
public deleteModifier(sourceFile: SourceFile, modifier: Modifier): void {
@@ -661,7 +661,12 @@ namespace ts.textChanges {
const deletedNodesInLists = new NodeSet(); // Stores ids of nodes in lists that we already deleted. Used to avoid deleting `, ` twice in `a, b`.
for (const { sourceFile, node } of this.deletedNodes) {
if (!this.deletedNodes.some(d => d.sourceFile === sourceFile && rangeContainsRangeExclusive(d.node, node))) {
deleteDeclaration.deleteDeclaration(this, deletedNodesInLists, sourceFile, node);
if (isArray(node)) {
this.deleteRange(sourceFile, rangeOfTypeParameters(node));
}
else {
deleteDeclaration.deleteDeclaration(this, deletedNodesInLists, sourceFile, node);
}
}
}
@@ -1001,7 +1006,7 @@ namespace ts.textChanges {
}
namespace deleteDeclaration {
export function deleteDeclaration(changes: ChangeTracker, deletedNodesInLists: NodeSet, sourceFile: SourceFile, node: Node): void {
export function deleteDeclaration(changes: ChangeTracker, deletedNodesInLists: NodeSet<Node>, sourceFile: SourceFile, node: Node): void {
switch (node.kind) {
case SyntaxKind.Parameter: {
const oldFunction = node.parent;
@@ -1052,33 +1057,9 @@ namespace ts.textChanges {
deleteVariableDeclaration(changes, deletedNodesInLists, sourceFile, node as VariableDeclaration);
break;
case SyntaxKind.TypeParameter: {
const typeParam = node as TypeParameterDeclaration;
switch (typeParam.parent.kind) {
case SyntaxKind.JSDocTemplateTag:
changes.deleteRange(sourceFile, getRangeToDeleteJsDocTag(typeParam.parent, sourceFile));
break;
case SyntaxKind.InferType:
// TODO: GH#25594
break;
default: {
const typeParameters = getEffectiveTypeParameterDeclarations(typeParam.parent);
if (typeParameters.length === 1) {
const { pos, end } = cast(typeParameters, isNodeArray);
const previousToken = getTokenAtPosition(sourceFile, pos - 1);
const nextToken = getTokenAtPosition(sourceFile, end);
Debug.assert(previousToken.kind === SyntaxKind.LessThanToken);
Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken);
changes.deleteNodeRange(sourceFile, previousToken, nextToken);
}
else {
deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
}
}
}
case SyntaxKind.TypeParameter:
deleteNodeInList(changes, deletedNodesInLists, sourceFile, node);
break;
}
case SyntaxKind.ImportSpecifier:
const namedImports = (node as ImportSpecifier).parent;
@@ -1144,7 +1125,7 @@ namespace ts.textChanges {
}
}
function deleteVariableDeclaration(changes: ChangeTracker, deletedNodesInLists: NodeSet, sourceFile: SourceFile, node: VariableDeclaration): void {
function deleteVariableDeclaration(changes: ChangeTracker, deletedNodesInLists: NodeSet<Node>, sourceFile: SourceFile, node: VariableDeclaration): void {
const { parent } = node;
if (parent.kind === SyntaxKind.CatchClause) {
@@ -1177,12 +1158,6 @@ namespace ts.textChanges {
Debug.assertNever(gp);
}
}
function getRangeToDeleteJsDocTag(node: JSDocTag, sourceFile: SourceFile): TextRange {
const { parent } = node;
const toDelete = parent.kind === SyntaxKind.JSDocComment && parent.comment === undefined && parent.tags!.length === 1 ? parent : node;
return createTextRangeFromNode(toDelete, sourceFile);
}
}
/** Warning: This deletes comments too. See `copyComments` in `convertFunctionToEs6Class`. */
@@ -1193,7 +1168,7 @@ namespace ts.textChanges {
changes.deleteRange(sourceFile, { pos: startPosition, end: endPosition });
}
function deleteNodeInList(changes: ChangeTracker, deletedNodesInLists: NodeSet, sourceFile: SourceFile, node: Node): void {
function deleteNodeInList(changes: ChangeTracker, deletedNodesInLists: NodeSet<Node>, sourceFile: SourceFile, node: Node): void {
const containingList = Debug.assertDefined(formatting.SmartIndenter.getContainingList(node, sourceFile));
const index = indexOfNode(containingList, node);
Debug.assert(index !== -1);
+1 -58
View File
@@ -374,7 +374,7 @@ namespace ts {
case SpecialPropertyAssignmentKind.Prototype:
return ScriptElementKind.localClassElement;
default: {
assertTypeIsNever(kind);
assertType<never>(kind);
return ScriptElementKind.unknown;
}
}
@@ -1358,63 +1358,6 @@ namespace ts {
return getPropertySymbolsFromBaseTypes(memberSymbol.parent!, memberSymbol.name, checker, _ => true) || false;
}
export interface ReadonlyNodeSet {
has(node: Node): boolean;
forEach(cb: (node: Node) => void): void;
some(pred: (node: Node) => boolean): boolean;
}
export class NodeSet implements ReadonlyNodeSet {
private map = createMap<Node>();
add(node: Node): void {
this.map.set(String(getNodeId(node)), node);
}
has(node: Node): boolean {
return this.map.has(String(getNodeId(node)));
}
forEach(cb: (node: Node) => void): void {
this.map.forEach(cb);
}
some(pred: (node: Node) => boolean): boolean {
return forEachEntry(this.map, pred) || false;
}
}
export interface ReadonlyNodeMap<TNode extends Node, TValue> {
get(node: TNode): TValue | undefined;
has(node: TNode): boolean;
}
export class NodeMap<TNode extends Node, TValue> implements ReadonlyNodeMap<TNode, TValue> {
private map = createMap<{ node: TNode, value: TValue }>();
get(node: TNode): TValue | undefined {
const res = this.map.get(String(getNodeId(node)));
return res && res.value;
}
getOrUpdate(node: TNode, setValue: () => TValue): TValue {
const res = this.get(node);
if (res) return res;
const value = setValue();
this.set(node, value);
return value;
}
set(node: TNode, value: TValue): void {
this.map.set(String(getNodeId(node)), { node, value });
}
has(node: TNode): boolean {
return this.map.has(String(getNodeId(node)));
}
forEach(cb: (value: TValue, node: TNode) => void): void {
this.map.forEach(({ node, value }) => cb(value, node));
}
}
export function getParentNodeInSpan(node: Node | undefined, file: SourceFile, span: TextSpan): Node | undefined {
if (!node) return undefined;
+30 -2
View File
@@ -1,5 +1,8 @@
namespace ts {
describe("FactoryAPI", () => {
function assertSyntaxKind(node: Node, expected: SyntaxKind) {
assert.strictEqual(node.kind, expected, `Actual: ${Debug.showSyntaxKind(node)} Expected: ${(ts as any).SyntaxKind[expected]}`);
}
describe("createExportAssignment", () => {
it("parenthesizes default export if necessary", () => {
function checkExpression(expression: Expression) {
@@ -9,7 +12,7 @@ namespace ts {
/*isExportEquals*/ false,
expression,
);
assert.strictEqual(node.expression.kind, SyntaxKind.ParenthesizedExpression);
assertSyntaxKind(node.expression, SyntaxKind.ParenthesizedExpression);
}
const clazz = createClassExpression(/*modifiers*/ undefined, "C", /*typeParameters*/ undefined, /*heritageClauses*/ undefined, [
@@ -39,7 +42,7 @@ namespace ts {
/*equalsGreaterThanToken*/ undefined,
body,
);
assert.strictEqual(node.body.kind, SyntaxKind.ParenthesizedExpression);
assertSyntaxKind(node.body, SyntaxKind.ParenthesizedExpression);
}
checkBody(createObjectLiteral());
@@ -50,5 +53,30 @@ namespace ts {
checkBody(createBinary(createLiteral("a"), SyntaxKind.CommaToken, createLiteral("b")));
});
});
describe("createBinaryExpression", () => {
it("parenthesizes arrow function in RHS if necessary", () => {
const lhs = createIdentifier("foo");
const rhs = createArrowFunction(
/*modifiers*/ undefined,
/*typeParameters*/ undefined,
[],
/*type*/ undefined,
/*equalsGreaterThanToken*/ undefined,
createBlock([]),
);
function checkRhs(operator: BinaryOperator, expectParens: boolean) {
const node = createBinary(lhs, operator, rhs);
assertSyntaxKind(node.right, expectParens ? SyntaxKind.ParenthesizedExpression : SyntaxKind.ArrowFunction);
}
checkRhs(SyntaxKind.CommaToken, /*expectParens*/ false);
checkRhs(SyntaxKind.EqualsToken, /*expectParens*/ false);
checkRhs(SyntaxKind.PlusEqualsToken, /*expectParens*/ false);
checkRhs(SyntaxKind.BarBarToken, /*expectParens*/ true);
checkRhs(SyntaxKind.AmpersandAmpersandToken, /*expectParens*/ true);
checkRhs(SyntaxKind.EqualsEqualsToken, /*expectParens*/ true);
});
});
});
}
+4 -1
View File
@@ -2262,8 +2262,11 @@ declare module "fs" {
const files = [file, module, libFile];
const host = createWatchedSystem(files, { currentDirectory });
const watch = createWatchOfFilesAndCompilerOptions([file.path], host);
checkProgramActualFiles(watch(), [file.path, libFile.path]);
checkOutputErrorsInitial(host, [getDiagnosticModuleNotFoundOfFile(watch(), file, "qqq")]);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectories(host, [`${currentDirectory}/node_modules`, `${currentDirectory}/node_modules/@types`], /*recursive*/ true);
host.renameFolder(`${currentDirectory}/node_modules2`, `${currentDirectory}/node_modules`);
host.runQueuedTimeoutCallbacks();
@@ -2622,7 +2625,7 @@ declare module "fs" {
createWatchOfConfigFile("tsconfig.json", host);
checkWatchedFilesDetailed(host, [libFile.path, mainFile.path, config.path, linkedPackageIndex.path, linkedPackageOther.path], 1);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, [mainPackageRoot, linkedPackageRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true);
checkWatchedDirectoriesDetailed(host, [`${mainPackageRoot}/@scoped`, `${mainPackageRoot}/node_modules`, linkedPackageRoot, `${mainPackageRoot}/node_modules/@types`, `${projectRoot}/node_modules/@types`], 1, /*recursive*/ true);
});
});
+385 -88
View File
@@ -176,6 +176,18 @@ namespace ts.projectSystem {
return { ts: 0, tsx: 0, dts: 0, js: 0, jsx: 0, deferred: 0, ...nonZeroStats };
}
export interface ConfigFileDiagnostic {
fileName: string | undefined;
start: number | undefined;
length: number | undefined;
messageText: string;
category: DiagnosticCategory;
code: number;
reportsUnnecessary?: {};
source?: string;
relatedInformation?: DiagnosticRelatedInformation[];
}
export class TestServerEventManager {
private events: server.ProjectServiceEvent[] = [];
readonly session: TestSession;
@@ -216,10 +228,14 @@ namespace ts.projectSystem {
this.events.forEach(event => assert.notEqual(event.eventName, eventName));
}
checkSingleConfigFileDiagEvent(configFileName: string, triggerFile: string) {
checkSingleConfigFileDiagEvent(configFileName: string, triggerFile: string, errors: ReadonlyArray<ConfigFileDiagnostic>) {
const eventData = this.getEvent<server.ConfigFileDiagEvent>(server.ConfigFileDiagEvent);
assert.equal(eventData.configFileName, configFileName);
assert.equal(eventData.triggerFile, triggerFile);
const actual = eventData.diagnostics.map(({ file, messageText, ...rest }) => ({ fileName: file && file.fileName, messageText: isString(messageText) ? messageText : "", ...rest }));
if (errors) {
assert.deepEqual(actual, errors);
}
}
assertProjectInfoTelemetryEvent(partial: Partial<server.ProjectInfoTelemetryEventData>, configFile = "/tsconfig.json"): void {
@@ -622,8 +638,8 @@ namespace ts.projectSystem {
const configFileLocations = ["/a/b/c/", "/a/b/", "/a/", "/"];
const configFiles = flatMap(configFileLocations, location => [location + "tsconfig.json", location + "jsconfig.json"]);
checkWatchedFiles(host, configFiles.concat(libFile.path, moduleFile.path));
checkWatchedDirectories(host, [], /*recursive*/ false);
checkWatchedDirectories(host, ["/a/b/c", combinePaths(getDirectoryPath(appFile.path), nodeModulesAtTypes)], /*recursive*/ true);
checkWatchedDirectories(host, ["/a/b/c"], /*recursive*/ false);
checkWatchedDirectories(host, [combinePaths(getDirectoryPath(appFile.path), nodeModulesAtTypes)], /*recursive*/ true);
});
it("can handle tsconfig file name with difference casing", () => {
@@ -3035,21 +3051,18 @@ namespace ts.projectSystem {
assert.isDefined(project);
checkProjectActualFiles(project, map(files, file => file.path));
checkWatchedFiles(host, mapDefined(files, file => file === file1 ? undefined : file.path));
checkWatchedDirectories(host, [], /*recursive*/ false);
const watchedRecursiveDirectories = ["/a/b/node_modules/@types"];
watchedRecursiveDirectories.push("/a/b");
checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true);
checkWatchedDirectoriesDetailed(host, ["/a/b"], 1, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, ["/a/b/node_modules/@types"], 1, /*recursive*/ true);
files.push(file2);
host.reloadFS(files);
host.runQueuedTimeoutCallbacks();
watchedRecursiveDirectories.pop();
checkNumberOfProjects(projectService, { configuredProjects: 1 });
assert.strictEqual(projectService.configuredProjects.get(configFile.path), project);
checkProjectActualFiles(project, mapDefined(files, file => file === file2a ? undefined : file.path));
checkWatchedFiles(host, mapDefined(files, file => file === file1 ? undefined : file.path));
checkWatchedDirectories(host, [], /*recursive*/ false);
checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, ["/a/b/node_modules/@types"], 1, /*recursive*/ true);
// On next file open the files file2a should be closed and not watched any more
projectService.openClientFile(file2.path);
@@ -3057,8 +3070,8 @@ namespace ts.projectSystem {
assert.strictEqual(projectService.configuredProjects.get(configFile.path), project);
checkProjectActualFiles(project, mapDefined(files, file => file === file2a ? undefined : file.path));
checkWatchedFiles(host, [libFile.path, configFile.path]);
checkWatchedDirectories(host, [], /*recursive*/ false);
checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true);
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, ["/a/b/node_modules/@types"], 1, /*recursive*/ true);
});
@@ -3098,7 +3111,7 @@ namespace ts.projectSystem {
checkWatchedFiles(host, [libFile.path, module1.path, module2.path, configFile.path]);
checkWatchedDirectories(host, [], /*recursive*/ false);
const watchedRecursiveDirectories = getTypeRootsFromLocation(root + "/a/b/src");
watchedRecursiveDirectories.push(`${root}/a/b/src`, `${root}/a/b/node_modules`);
watchedRecursiveDirectories.push(`${root}/a/b/src/node_modules`, `${root}/a/b/node_modules`);
checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true);
});
@@ -3479,6 +3492,102 @@ namespace ts.projectSystem {
openFilesForSession([{ file, projectRootPath }], session);
}
});
describe("CompileOnSaveAffectedFileListRequest with and without projectFileName in request", () => {
const projectRoot = "/user/username/projects/myproject";
const core: File = {
path: `${projectRoot}/core/core.ts`,
content: "let z = 10;"
};
const app1: File = {
path: `${projectRoot}/app1/app.ts`,
content: "let x = 10;"
};
const app2: File = {
path: `${projectRoot}/app2/app.ts`,
content: "let y = 10;"
};
const app1Config: File = {
path: `${projectRoot}/app1/tsconfig.json`,
content: JSON.stringify({
files: ["app.ts", "../core/core.ts"],
compilerOptions: { outFile : "build/output.js" },
compileOnSave: true
})
};
const app2Config: File = {
path: `${projectRoot}/app2/tsconfig.json`,
content: JSON.stringify({
files: ["app.ts", "../core/core.ts"],
compilerOptions: { outFile: "build/output.js" },
compileOnSave: true
})
};
const files = [libFile, core, app1, app2, app1Config, app2Config];
function insertString(session: TestSession, file: File) {
session.executeCommandSeq<protocol.ChangeRequest>({
command: protocol.CommandTypes.Change,
arguments: {
file: file.path,
line: 1,
offset: 1,
endLine: 1,
endOffset: 1,
insertString: "let k = 1"
}
});
}
function getSession() {
const host = createServerHost(files);
const session = createSession(host);
openFilesForSession([app1, app2, core], session);
const service = session.getProjectService();
checkNumberOfProjects(session.getProjectService(), { configuredProjects: 2 });
const project1 = service.configuredProjects.get(app1Config.path)!;
const project2 = service.configuredProjects.get(app2Config.path)!;
checkProjectActualFiles(project1, [libFile.path, app1.path, core.path, app1Config.path]);
checkProjectActualFiles(project2, [libFile.path, app2.path, core.path, app2Config.path]);
insertString(session, app1);
insertString(session, app2);
assert.equal(project1.dirty, true);
assert.equal(project2.dirty, true);
return session;
}
it("when projectFile is specified", () => {
const session = getSession();
const response = session.executeCommandSeq<protocol.CompileOnSaveAffectedFileListRequest>({
command: protocol.CommandTypes.CompileOnSaveAffectedFileList,
arguments: {
file: core.path,
projectFileName: app1Config.path
}
}).response;
assert.deepEqual(response, [
{ projectFileName: app1Config.path, fileNames: [core.path, app1.path], projectUsesOutFile: true }
]);
assert.equal(session.getProjectService().configuredProjects.get(app1Config.path)!.dirty, false);
assert.equal(session.getProjectService().configuredProjects.get(app2Config.path)!.dirty, true);
});
it("when projectFile is not specified", () => {
const session = getSession();
const response = session.executeCommandSeq<protocol.CompileOnSaveAffectedFileListRequest>({
command: protocol.CommandTypes.CompileOnSaveAffectedFileList,
arguments: {
file: core.path
}
}).response;
assert.deepEqual(response, [
{ projectFileName: app1Config.path, fileNames: [core.path, app1.path], projectUsesOutFile: true },
{ projectFileName: app2Config.path, fileNames: [core.path, app2.path], projectUsesOutFile: true }
]);
assert.equal(session.getProjectService().configuredProjects.get(app1Config.path)!.dirty, false);
assert.equal(session.getProjectService().configuredProjects.get(app2Config.path)!.dirty, false);
});
});
});
describe("tsserverProjectSystem Proper errors", () => {
@@ -4698,13 +4807,41 @@ namespace ts.projectSystem {
});
describe("tsserverProjectSystem Configure file diagnostics events", () => {
function getUnknownCompilerOptionDiagnostic(configFile: File, prop: string): ConfigFileDiagnostic {
const d = Diagnostics.Unknown_compiler_option_0;
const start = configFile.content.indexOf(prop) - 1; // start at "prop"
return {
fileName: configFile.path,
start,
length: prop.length + 2,
messageText: formatStringFromArgs(d.message, [prop]),
category: d.category,
code: d.code,
reportsUnnecessary: undefined
};
}
function getFileNotFoundDiagnostic(configFile: File, relativeFileName: string): ConfigFileDiagnostic {
const findString = `{"path":"./${relativeFileName}"}`;
const d = Diagnostics.File_0_does_not_exist;
const start = configFile.content.indexOf(findString);
return {
fileName: configFile.path,
start,
length: findString.length,
messageText: formatStringFromArgs(d.message, [`${getDirectoryPath(configFile.path)}/${relativeFileName}`]),
category: d.category,
code: d.code,
reportsUnnecessary: undefined
};
}
it("are generated when the config file has errors", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const configFile = {
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
@@ -4713,29 +4850,32 @@ namespace ts.projectSystem {
}
}`
};
const serverEventManager = new TestServerEventManager([file, configFile]);
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
openFilesForSession([file], serverEventManager.session);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, [
getUnknownCompilerOptionDiagnostic(configFile, "foo"),
getUnknownCompilerOptionDiagnostic(configFile, "allowJS")
]);
});
it("are generated when the config file doesn't have errors", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const configFile = {
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {}
}`
};
const serverEventManager = new TestServerEventManager([file, configFile]);
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
openFilesForSession([file], serverEventManager.session);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, emptyArray);
});
it("are generated when the config file changes", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
@@ -4746,37 +4886,40 @@ namespace ts.projectSystem {
}`
};
const serverEventManager = new TestServerEventManager([file, configFile]);
const files = [file, libFile, configFile];
const serverEventManager = new TestServerEventManager(files);
openFilesForSession([file], serverEventManager.session);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, emptyArray);
configFile.content = `{
"compilerOptions": {
"haha": 123
}
}`;
serverEventManager.host.reloadFS([file, configFile]);
serverEventManager.host.reloadFS(files);
serverEventManager.host.runQueuedTimeoutCallbacks();
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, [
getUnknownCompilerOptionDiagnostic(configFile, "haha")
]);
configFile.content = `{
"compilerOptions": {}
}`;
serverEventManager.host.reloadFS([file, configFile]);
serverEventManager.host.reloadFS(files);
serverEventManager.host.runQueuedTimeoutCallbacks();
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, configFile.path, emptyArray);
});
it("are not generated when the config file does not include file opened and config file has errors", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const file2 = {
const file2: File = {
path: "/a/b/test.ts",
content: "let x = 10"
};
const configFile = {
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
@@ -4792,11 +4935,11 @@ namespace ts.projectSystem {
});
it("are not generated when the config file has errors but suppressDiagnosticEvents is true", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const configFile = {
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"compilerOptions": {
@@ -4805,21 +4948,21 @@ namespace ts.projectSystem {
}
}`
};
const serverEventManager = new TestServerEventManager([file, configFile], /*suppressDiagnosticEvents*/ true);
const serverEventManager = new TestServerEventManager([file, libFile, configFile], /*suppressDiagnosticEvents*/ true);
openFilesForSession([file], serverEventManager.session);
serverEventManager.hasZeroEvent("configFileDiag");
});
it("are not generated when the config file does not include file opened and doesnt contain any errors", () => {
const file = {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const file2 = {
const file2: File = {
path: "/a/b/test.ts",
content: "let x = 10"
};
const configFile = {
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"files": ["app.ts"]
@@ -4830,6 +4973,27 @@ namespace ts.projectSystem {
openFilesForSession([file2], serverEventManager.session);
serverEventManager.hasZeroEvent("configFileDiag");
});
it("contains the project reference errors", () => {
const file: File = {
path: "/a/b/app.ts",
content: "let x = 10"
};
const noSuchTsconfig = "no-such-tsconfig.json";
const configFile: File = {
path: "/a/b/tsconfig.json",
content: `{
"files": ["app.ts"],
"references": [{"path":"./${noSuchTsconfig}"}]
}`
};
const serverEventManager = new TestServerEventManager([file, libFile, configFile]);
openFilesForSession([file], serverEventManager.session);
serverEventManager.checkSingleConfigFileDiagEvent(configFile.path, file.path, [
getFileNotFoundDiagnostic(configFile, noSuchTsconfig)
]);
});
});
describe("tsserverProjectSystem skipLibCheck", () => {
@@ -6780,7 +6944,7 @@ namespace ts.projectSystem {
const { configFileName } = projectService.openClientFile(file1.path);
assert.equal(configFileName, tsconfigFile.path as server.NormalizedPath, `should find config`); // tslint:disable-line no-unnecessary-type-assertion (TODO: GH#18217)
checkNumberOfConfiguredProjects(projectService, 1);
const watchingRecursiveDirectories = [`${canonicalFrontendDir}/src`, canonicalFrontendDir].concat(getNodeModuleDirectories(getDirectoryPath(canonicalFrontendDir)));
const watchingRecursiveDirectories = [`${canonicalFrontendDir}/src`, `${canonicalFrontendDir}/types`, `${canonicalFrontendDir}/node_modules`].concat(getNodeModuleDirectories(getDirectoryPath(canonicalFrontendDir)));
const project = projectService.configuredProjects.get(canonicalConfigPath)!;
verifyProjectAndWatchedDirectories();
@@ -6934,7 +7098,7 @@ namespace ts.projectSystem {
const projectService = createProjectService(host);
const { configFileName } = projectService.openClientFile(app.path);
assert.equal(configFileName, tsconfigJson.path as server.NormalizedPath, `should find config`); // TODO: GH#18217
const recursiveWatchedDirectories: string[] = [appFolder].concat(getNodeModuleDirectories(getDirectoryPath(appFolder)));
const recursiveWatchedDirectories: string[] = [`${appFolder}`, `${appFolder}/node_modules`].concat(getNodeModuleDirectories(getDirectoryPath(appFolder)));
verifyProject();
let timeoutAfterReloadFs = timeoutDuringPartialInstallation;
@@ -7014,7 +7178,7 @@ namespace ts.projectSystem {
const lodashIndexPath = root + "/a/b/node_modules/@types/lodash/index.d.ts";
projectFiles.push(find(filesAndFoldersToAdd, f => f.path === lodashIndexPath)!);
// we would now not have failed lookup in the parent of appFolder since lodash is available
recursiveWatchedDirectories.length = 1;
recursiveWatchedDirectories.length = 2;
// npm installation complete, timeout after reload fs
timeoutAfterReloadFs = true;
verifyAfterPartialOrCompleteNpmInstall(2);
@@ -7534,9 +7698,9 @@ namespace ts.projectSystem {
const openFiles = [file1.path];
const watchedRecursiveDirectories = useSlashRootAsSomeNotRootFolderInUserDirectory ?
// Folders of node_modules lookup not in changedRoot
["a/b/project", "a/b/node_modules", "a/node_modules", "node_modules"].map(v => rootFolder + v) :
["a/b/project", "a/b/project/node_modules", "a/b/node_modules", "a/node_modules", "node_modules"].map(v => rootFolder + v) :
// Folder of tsconfig
["/a/b/project"];
["/a/b/project", "/a/b/project/node_modules"];
const host = createServerHost(projectFiles);
const { session, verifyInitialOpen, verifyProjectsUpdatedInBackgroundEventHandler } = createSession(host);
const projectService = session.getProjectService();
@@ -7565,7 +7729,7 @@ namespace ts.projectSystem {
host.reloadFS(projectFiles);
host.runQueuedTimeoutCallbacks();
if (useSlashRootAsSomeNotRootFolderInUserDirectory) {
watchedRecursiveDirectories.length = 2;
watchedRecursiveDirectories.length = 3;
}
else {
// file2 addition wont be detected
@@ -7993,10 +8157,10 @@ new C();`
checkCompleteEvent(session, 2, expectedSequenceId);
}
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], recursiveDirectories: string[], nonRecursiveDirectories: string[]) {
function verifyWatchedFilesAndDirectories(host: TestServerHost, files: string[], recursiveDirectories: ReadonlyMap<number>, nonRecursiveDirectories: string[]) {
checkWatchedFilesDetailed(host, files.filter(f => f !== recognizersDateTimeSrcFile.path), 1);
checkWatchedDirectoriesDetailed(host, nonRecursiveDirectories, 1, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, recursiveDirectories, 1, /*recursive*/ true);
checkWatchedDirectoriesDetailed(host, nonRecursiveDirectories, 1, /*recursive*/ false);
checkWatchedDirectoriesDetailed(host, recursiveDirectories, /*recursive*/ true);
}
function createSessionAndOpenFile(host: TestServerHost) {
@@ -8017,8 +8181,16 @@ new C();`
const filesWithNodeModulesSetup = [...filesWithSources, nodeModulesRecorgnizersText];
const filesAfterCompilation = [...filesWithNodeModulesSetup, recongnizerTextDistTypingFile];
const watchedDirectoriesWithResolvedModule = [`${recognizersDateTime}/src`, ...(withPathMapping ? emptyArray : [recognizersDateTime]), ...getTypeRootsFromLocation(recognizersDateTime)];
const watchedDirectoriesWithUnresolvedModule = [recognizersDateTime, ...(withPathMapping ? [recognizersText] : emptyArray), ...watchedDirectoriesWithResolvedModule, ...getNodeModuleDirectories(packages)];
const watchedDirectoriesWithResolvedModule = arrayToMap(getTypeRootsFromLocation(recognizersDateTime), k => k, () => 1);
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/src`, withPathMapping ? 1 : 2); // wild card + failed lookups
if (!withPathMapping) {
watchedDirectoriesWithResolvedModule.set(`${recognizersDateTime}/node_modules`, 1); // failed lookups
}
const watchedDirectoriesWithUnresolvedModule = cloneMap(watchedDirectoriesWithResolvedModule);
watchedDirectoriesWithUnresolvedModule.set(`${recognizersDateTime}/src`, 2); // wild card + failed lookups
[`${recognizersDateTime}/node_modules`, ...(withPathMapping ? [recognizersText] : emptyArray), ...getNodeModuleDirectories(packages)].forEach(d => {
watchedDirectoriesWithUnresolvedModule.set(d, 1);
});
const nonRecursiveWatchedDirectories = withPathMapping ? [packages] : emptyArray;
function verifyProjectWithResolvedModule(session: TestSession) {
@@ -8251,11 +8423,10 @@ new C();`
return `Reusing resolution of module '${moduleName}' to file '${file.path}' from old program.`;
}
function verifyWatchesWithConfigFile(host: TestServerHost, files: File[], openFile: File) {
function verifyWatchesWithConfigFile(host: TestServerHost, files: File[], openFile: File, extraExpectedDirectories?: ReadonlyArray<string>) {
checkWatchedFiles(host, mapDefined(files, f => f === openFile ? undefined : f.path));
checkWatchedDirectories(host, [], /*recursive*/ false);
const configDirectory = getDirectoryPath(configFile.path);
checkWatchedDirectories(host, [configDirectory, `${configDirectory}/${nodeModulesAtTypes}`], /*recursive*/ true);
checkWatchedDirectories(host, [projectLocation, `${projectLocation}/${nodeModulesAtTypes}`, ...(extraExpectedDirectories || emptyArray)], /*recursive*/ true);
}
describe("from files in same folder", () => {
@@ -8299,6 +8470,7 @@ new C();`
});
it("non relative module name", () => {
const expectedNonRelativeDirectories = [`${projectLocation}/node_modules`, `${projectLocation}/src`];
const module1Name = "module1";
const module2Name = "module2";
const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`;
@@ -8312,7 +8484,7 @@ new C();`
const expectedTrace = getExpectedNonRelativeModuleResolutionTrace(host, file1, module1, module1Name);
getExpectedNonRelativeModuleResolutionTrace(host, file1, module2, module2Name, expectedTrace);
verifyTrace(resolutionTrace, expectedTrace);
verifyWatchesWithConfigFile(host, files, file1);
verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories);
file1.content += fileContent;
file2.content += fileContent;
@@ -8322,7 +8494,7 @@ new C();`
getExpectedReusingResolutionFromOldProgram(file1, module1Name),
getExpectedReusingResolutionFromOldProgram(file1, module2Name)
]);
verifyWatchesWithConfigFile(host, files, file1);
verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories);
});
});
@@ -8391,6 +8563,7 @@ new C();`
});
it("non relative module name", () => {
const expectedNonRelativeDirectories = [`${projectLocation}/node_modules`, `${projectLocation}/product`];
const module1Name = "module1";
const module2Name = "module2";
const fileContent = `import { module1 } from "${module1Name}";import { module2 } from "${module2Name}";`;
@@ -8410,7 +8583,7 @@ new C();`
getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module1, module1Name, getDirectoryPath(file4.path), expectedTrace);
getExpectedNonRelativeModuleResolutionFromCacheTrace(host, file3, module2, module2Name, getDirectoryPath(file4.path), expectedTrace);
verifyTrace(resolutionTrace, expectedTrace);
verifyWatchesWithConfigFile(host, files, file1);
verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories);
file1.content += fileContent;
file2.content += fileContent;
@@ -8423,7 +8596,7 @@ new C();`
getExpectedReusingResolutionFromOldProgram(file1, module1Name),
getExpectedReusingResolutionFromOldProgram(file1, module2Name)
]);
verifyWatchesWithConfigFile(host, files, file1);
verifyWatchesWithConfigFile(host, files, file1, expectedNonRelativeDirectories);
});
it("non relative module name from inferred project", () => {
@@ -8460,7 +8633,7 @@ new C();`
watchedFiles.push(combinePaths(d, "tsconfig.json"), combinePaths(d, "jsconfig.json"));
});
const watchedRecursiveDirectories = getTypeRootsFromLocation(currentDirectory).concat([
currentDirectory, `${projectLocation}/product/${nodeModules}`,
`${currentDirectory}/node_modules`, `${currentDirectory}/feature`, `${projectLocation}/product/${nodeModules}`,
`${projectLocation}/${nodeModules}`, `${projectLocation}/product/test/${nodeModules}`,
`${projectLocation}/product/test/src/${nodeModules}`
]);
@@ -8530,7 +8703,6 @@ export const x = 10;`
outDir: "../out",
baseUrl: "./",
typeRoots: ["typings"]
}
})
};
@@ -8546,13 +8718,15 @@ export const x = 10;`
checkWatchedDirectories(host, emptyArray, /*recursive*/ false); // since fs resolves to ambient module, shouldnt watch failed lookup
}
else {
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`], 1, /*recursive*/ false); // failed lookup for fs
checkWatchedDirectoriesDetailed(host, [`${projectRoot}`, `${projectRoot}/src`], 1, /*recursive*/ false); // failed lookup for fs
}
const expectedWatchedDirectories = createMap<number>();
expectedWatchedDirectories.set(`${projectRoot}/src`, 2); // Wild card and failed lookup
expectedWatchedDirectories.set(`${projectRoot}/src`, 1); // Wild card
expectedWatchedDirectories.set(`${projectRoot}/src/somefolder`, 1); // failedLookup for somefolder/module2
expectedWatchedDirectories.set(`${projectRoot}/src/node_modules`, 1); // failed lookup for somefolder/module2
expectedWatchedDirectories.set(`${projectRoot}/somefolder`, 1); // failed lookup for somefolder/module2
expectedWatchedDirectories.set(`${projectRoot}/node_modules`, 1); // failed lookup for with node_modules/@types/fs
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, 1); // typeroot directory
expectedWatchedDirectories.set(`${projectRoot}/src/typings`, useNodeFile ? 1 : 2); // typeroot directory + failed lookup if not using node file
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectories, /*recursive*/ true);
}
@@ -8943,7 +9117,7 @@ export function Test2() {
});
});
function makeSampleProjects() {
describe("tsserverProjectSystem project references", () => {
const aTs: File = {
path: "/a/a.ts",
content: "export function fnA() {}\nexport interface IfaceA {}\nexport const instanceA: IfaceA = {};",
@@ -8999,62 +9173,121 @@ export function Test2() {
content: `export declare function fnB(): void;\n//# source${""}MappingURL=b.d.ts.map`,
};
const dummyFile: File = {
path: "/dummy/dummy.ts",
content: "let a = 10;"
};
const userTs: File = {
path: "/user/user.ts",
content: 'import { fnA, instanceA } from "../a/bin/a";\nimport { fnB } from "../b/bin/b";\nexport function fnUser() { fnA(); fnB(); instanceA; }',
};
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, userTs]);
const session = createSession(host);
function makeSampleProjects() {
const host = createServerHost([aTs, aTsconfig, aDtsMap, aDts, bTsconfig, bTs, bDtsMap, bDts, userTs, dummyFile]);
const session = createSession(host);
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
checkDeclarationFiles(aTs, session, [aDtsMap, aDts]);
checkDeclarationFiles(bTs, session, [bDtsMap, bDts]);
// Testing what happens if we delete the original sources.
host.removeFile(bTs.path);
// Testing what happens if we delete the original sources.
host.removeFile(bTs.path);
openFilesForSession([userTs], session);
openFilesForSession([userTs], session);
const service = session.getProjectService();
checkNumberOfProjects(service, { inferredProjects: 1 });
return session;
}
return { session, aTs, bDts, userTs };
}
function verifyInferredProjectUnchanged(session: TestSession) {
checkProjectActualFiles(session.getProjectService().inferredProjects[0], [userTs.path, aDts.path, bDts.path]);
}
function verifyDummyProject(session: TestSession) {
checkProjectActualFiles(session.getProjectService().inferredProjects[0], [dummyFile.path]);
}
function verifyOnlyOrphanInferredProject(session: TestSession) {
openFilesForSession([dummyFile], session);
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
verifyDummyProject(session);
}
function verifySingleInferredProject(session: TestSession) {
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1 });
verifyInferredProjectUnchanged(session);
// Close user file should close all the projects after opening dummy file
closeFilesForSession([userTs], session);
verifyOnlyOrphanInferredProject(session);
}
function verifyATsConfigProject(session: TestSession) {
checkProjectActualFiles(session.getProjectService().configuredProjects.get(aTsconfig.path)!, [aTs.path, aTsconfig.path]);
}
function verifyATsConfigOriginalProject(session: TestSession) {
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
verifyInferredProjectUnchanged(session);
verifyATsConfigProject(session);
// Close user file should close all the projects
closeFilesForSession([userTs], session);
verifyOnlyOrphanInferredProject(session);
}
function verifyATsConfigWhenOpened(session: TestSession) {
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
verifyInferredProjectUnchanged(session);
verifyATsConfigProject(session);
closeFilesForSession([userTs], session);
openFilesForSession([dummyFile], session);
checkNumberOfProjects(session.getProjectService(), { inferredProjects: 1, configuredProjects: 1 });
verifyDummyProject(session);
verifyATsConfigProject(session); // ATsConfig should still be alive
}
describe("tsserverProjectSystem project references", () => {
it("goToDefinition", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, protocol.CommandTypes.Definition, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
verifySingleInferredProject(session);
});
it("getDefinitionAndBoundSpan", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionAndBoundSpanRequest, protocol.DefinitionAndBoundSpanResponse>(session, protocol.CommandTypes.DefinitionAndBoundSpan, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, {
textSpan: protocolTextSpanFromSubstring(userTs.content, "fnA", { index: 1 }),
definitions: [protocolFileSpanFromSubstring(aTs, "fnA")],
});
verifySingleInferredProject(session);
});
it("goToType", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.TypeDefinitionRequest, protocol.TypeDefinitionResponse>(session, protocol.CommandTypes.TypeDefinition, protocolFileLocationFromSubstring(userTs, "instanceA"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "IfaceA")]);
verifySingleInferredProject(session);
});
it("goToImplementation", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.ImplementationRequest, protocol.ImplementationResponse>(session, protocol.CommandTypes.Implementation, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual(response, [protocolFileSpanFromSubstring(aTs, "fnA")]);
verifySingleInferredProject(session);
});
it("goToDefinition -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.DefinitionRequest, protocol.DefinitionResponse>(session, CommandNames.Definition, protocolFileLocationFromSubstring(userTs, "fnB()"));
// bTs does not exist, so stick with bDts
assert.deepEqual(response, [protocolFileSpanFromSubstring(bDts, "fnB")]);
verifySingleInferredProject(session);
});
it("navigateTo", () => {
const { session, aTs, bDts, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.NavtoRequest, protocol.NavtoResponse>(session, CommandNames.Navto, { file: userTs.path, searchValue: "fn" });
assert.deepEqual<ReadonlyArray<protocol.NavtoItem> | undefined>(response, [
{
@@ -9082,6 +9315,8 @@ export function Test2() {
kindModifiers: "export",
},
]);
verifyATsConfigOriginalProject(session);
});
const referenceATs = (aTs: File): protocol.ReferencesResponseItem => makeReferenceItem(aTs, /*isDefinition*/ true, "fnA", "export function fnA() {}");
@@ -9091,7 +9326,7 @@ export function Test2() {
];
it("findAllReferences", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
@@ -9100,10 +9335,12 @@ export function Test2() {
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnA()").offset,
symbolDisplayString: "(alias) fnA(): void\nimport fnA",
});
verifyATsConfigOriginalProject(session);
});
it("findAllReferences -- starting at definition", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(aTs, "fnA"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
@@ -9112,10 +9349,11 @@ export function Test2() {
symbolStartOffset: protocolLocationFromSubstring(aTs.content, "fnA").offset,
symbolDisplayString: "function fnA(): void",
});
verifyATsConfigWhenOpened(session);
});
it("findAllReferencesFull", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
interface ReferencesFullRequest extends protocol.FileLocationRequest { command: protocol.CommandTypes.ReferencesFull; }
interface ReferencesFullResponse extends protocol.Response { body: ReadonlyArray<ReferencedSymbol>; }
@@ -9172,10 +9410,11 @@ export function Test2() {
],
}
]);
verifyATsConfigOriginalProject(session);
});
it("findAllReferences -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.ReferencesRequest, protocol.ReferencesResponse>(session, protocol.CommandTypes.References, protocolFileLocationFromSubstring(userTs, "fnB()"));
assert.deepEqual<protocol.ReferencesResponseBody | undefined>(response, {
@@ -9188,6 +9427,7 @@ export function Test2() {
symbolStartOffset: protocolLocationFromSubstring(userTs.content, "fnB()").offset,
symbolDisplayString: "(alias) fnB(): void\nimport fnB",
});
verifySingleInferredProject(session);
});
const renameATs = (aTs: File): protocol.SpanGroup => ({
@@ -9203,7 +9443,7 @@ export function Test2() {
});
it("renameLocations", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
@@ -9216,10 +9456,11 @@ export function Test2() {
},
locs: [renameUserTs(userTs), renameATs(aTs)],
});
verifyATsConfigOriginalProject(session);
});
it("renameLocations -- starting at definition", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
openFilesForSession([aTs], session); // If it's not opened, the reference isn't found.
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(aTs, "fnA"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
@@ -9233,20 +9474,22 @@ export function Test2() {
},
locs: [renameATs(aTs), renameUserTs(userTs)],
});
verifyATsConfigWhenOpened(session);
});
it("renameLocationsFull", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameFullRequest, protocol.RenameFullResponse>(session, protocol.CommandTypes.RenameLocationsFull, protocolFileLocationFromSubstring(userTs, "fnA()"));
assert.deepEqual<ReadonlyArray<RenameLocation>>(response, [
documentSpanFromSubstring(userTs, "fnA"),
documentSpanFromSubstring(userTs, "fnA", { index: 1 }),
documentSpanFromSubstring(aTs, "fnA"),
]);
verifyATsConfigOriginalProject(session);
});
it("renameLocations -- target does not exist", () => {
const { session, bDts, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.RenameRequest, protocol.RenameResponse>(session, protocol.CommandTypes.Rename, protocolFileLocationFromSubstring(userTs, "fnB()"));
assert.deepEqual<protocol.RenameResponseBody | undefined>(response, {
info: {
@@ -9271,11 +9514,11 @@ export function Test2() {
}
],
});
verifySingleInferredProject(session);
});
it("getEditsForFileRename", () => {
const { session, aTs, userTs } = makeSampleProjects();
const session = makeSampleProjects();
const response = executeSessionRequest<protocol.GetEditsForFileRenameRequest, protocol.GetEditsForFileRenameResponse>(session, protocol.CommandTypes.GetEditsForFileRename, {
oldFilePath: aTs.path,
newFilePath: "/a/aNew.ts",
@@ -9288,10 +9531,64 @@ export function Test2() {
],
},
]);
verifySingleInferredProject(session);
});
});
describe("Untitled files", () => {
describe("duplicate packages", () => {
// Tests that 'moduleSpecifiers.ts' will import from the redirecting file, and not from the file it redirects to, if that can provide a global module specifier.
it("works with import fixes", () => {
const packageContent = "export const foo: number;";
const packageJsonContent = JSON.stringify({ name: "foo", version: "1.2.3" });
const aFooIndex: File = { path: "/a/node_modules/foo/index.d.ts", content: packageContent };
const aFooPackage: File = { path: "/a/node_modules/foo/package.json", content: packageJsonContent };
const bFooIndex: File = { path: "/b/node_modules/foo/index.d.ts", content: packageContent };
const bFooPackage: File = { path: "/b/node_modules/foo/package.json", content: packageJsonContent };
const userContent = 'import("foo");\nfoo';
const aUser: File = { path: "/a/user.ts", content: userContent };
const bUser: File = { path: "/b/user.ts", content: userContent };
const tsconfig: File = {
path: "/tsconfig.json",
content: "{}",
};
const host = createServerHost([aFooIndex, aFooPackage, bFooIndex, bFooPackage, aUser, bUser, tsconfig]);
const session = createSession(host);
openFilesForSession([aUser, bUser], session);
for (const user of [aUser, bUser]) {
const response = executeSessionRequest<protocol.CodeFixRequest, protocol.CodeFixResponse>(session, protocol.CommandTypes.GetCodeFixes, {
file: user.path,
startLine: 2,
startOffset: 1,
endLine: 2,
endOffset: 4,
errorCodes: [Diagnostics.Cannot_find_name_0.code],
});
assert.deepEqual<ReadonlyArray<protocol.CodeFixAction> | undefined>(response, [
{
description: `Import 'foo' from module "foo"`,
fixName: "import",
fixId: "fixMissingImport",
fixAllDescription: "Add all missing imports",
changes: [{
fileName: user.path,
textChanges: [{
start: { line: 1, offset: 1 },
end: { line: 1, offset: 1 },
newText: 'import { foo } from "foo";\n\n',
}],
}],
commands: undefined,
},
]);
}
});
});
describe("tsserverProjectSystem Untitled files", () => {
it("Can convert positions to locations", () => {
const aTs: File = { path: "/proj/a.ts", content: "" };
const tsconfig: File = { path: "/proj/tsconfig.json", content: "{}" };
+4 -4
View File
@@ -146,8 +146,10 @@ namespace ts.projectSystem {
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
const expectedWatchedDirectoriesRecursive = createMap<number>();
expectedWatchedDirectoriesRecursive.set("/a/b", 2); // TypingInstaller and wild card
expectedWatchedDirectoriesRecursive.set("/a/b", 1); // wild card
expectedWatchedDirectoriesRecursive.set("/a/b/node_modules/@types", 1); // type root watch
expectedWatchedDirectoriesRecursive.set("/a/b/node_modules", 1); // TypingInstaller
expectedWatchedDirectoriesRecursive.set("/a/b/bower_components", 1); // TypingInstaller
checkWatchedDirectoriesDetailed(host, expectedWatchedDirectoriesRecursive, /*recursive*/ true);
installer.installAll(/*expectedCount*/ 1);
@@ -844,9 +846,7 @@ namespace ts.projectSystem {
checkWatchedDirectories(host, emptyArray, /*recursive*/ false);
const watchedRecursiveDirectoriesExpected = createMap<number>();
watchedRecursiveDirectoriesExpected.set("/", 2); // wild card + type installer
checkWatchedDirectoriesDetailed(host, watchedRecursiveDirectoriesExpected, /*recursive*/ true);
checkWatchedDirectoriesDetailed(host, ["/", "/node_modules", "/bower_components"], 1, /*recursive*/ true);
installer.installAll(/*expectedCount*/ 1);
+1 -1
View File
@@ -455,7 +455,7 @@ namespace ts.server {
break;
}
default:
assertTypeIsNever(response);
assertType<never>(response);
}
}
+66 -65
View File
@@ -64,18 +64,24 @@ namespace ts.server.typingsInstaller {
onRequestCompleted: RequestCompletedAction;
}
function isPackageOrBowerJson(fileName: string) {
const base = getBaseFileName(fileName);
return base === "package.json" || base === "bower.json";
function endsWith(str: string, suffix: string, caseSensitive: boolean): boolean {
const expectedPos = str.length - suffix.length;
return expectedPos >= 0 &&
(str.indexOf(suffix, expectedPos) === expectedPos ||
(!caseSensitive && compareStringsCaseInsensitive(str.substr(expectedPos), suffix) === Comparison.EqualTo));
}
function getDirectoryExcludingNodeModulesOrBowerComponents(f: string) {
const indexOfNodeModules = f.indexOf("/node_modules/");
const indexOfBowerComponents = f.indexOf("/bower_components/");
const subStrLength = indexOfNodeModules === -1 || indexOfBowerComponents === -1 ?
Math.max(indexOfNodeModules, indexOfBowerComponents) :
Math.min(indexOfNodeModules, indexOfBowerComponents);
return subStrLength === -1 ? f : f.substr(0, subStrLength);
function isPackageOrBowerJson(fileName: string, caseSensitive: boolean) {
return endsWith(fileName, "/package.json", caseSensitive) || endsWith(fileName, "/bower.json", caseSensitive);
}
function sameFiles(a: string, b: string, caseSensitive: boolean) {
return a === b || (!caseSensitive && compareStringsCaseInsensitive(a, b) === Comparison.EqualTo);
}
const enum ProjectWatcherType {
FileWatcher = "FileWatcher",
DirectoryWatcher = "DirectoryWatcher"
}
type ProjectWatchers = Map<FileWatcher> & { isInvoked?: boolean; };
@@ -88,7 +94,7 @@ namespace ts.server.typingsInstaller {
private safeList: JsTyping.SafeList | undefined;
readonly pendingRunRequests: PendingRequest[] = [];
private readonly toCanonicalFileName: GetCanonicalFileName;
private readonly globalCacheCanonicalPackageJsonPath: string;
private readonly globalCachePackageJsonPath: string;
private installRunCount = 1;
private inFlightRequestCount = 0;
@@ -103,7 +109,7 @@ namespace ts.server.typingsInstaller {
private readonly throttleLimit: number,
protected readonly log = nullLog) {
this.toCanonicalFileName = createGetCanonicalFileName(installTypingHost.useCaseSensitiveFileNames);
this.globalCacheCanonicalPackageJsonPath = combinePaths(this.toCanonicalFileName(globalCachePath), "package.json");
this.globalCachePackageJsonPath = combinePaths(globalCachePath, "package.json");
if (this.log.isEnabled()) {
this.log.writeLine(`Global cache location '${globalCachePath}', safe file path '${safeListPath}', types map path ${typesMapLocation}`);
}
@@ -406,84 +412,79 @@ namespace ts.server.typingsInstaller {
watchers.isInvoked = false;
const isLoggingEnabled = this.log.isEnabled();
const createProjectWatcher = (path: string, createWatch: (path: string) => FileWatcher) => {
toRemove.delete(path);
if (watchers.has(path)) {
const createProjectWatcher = (path: string, projectWatcherType: ProjectWatcherType) => {
const canonicalPath = this.toCanonicalFileName(path);
toRemove.delete(canonicalPath);
if (watchers.has(canonicalPath)) {
return;
}
watchers.set(path, createWatch(path));
};
const createProjectFileWatcher = (file: string): FileWatcher => {
if (isLoggingEnabled) {
this.log.writeLine(`FileWatcher:: Added:: WatchInfo: ${file}`);
this.log.writeLine(`${projectWatcherType}:: Added:: WatchInfo: ${path}`);
}
const watcher = this.installTypingHost.watchFile!(file, (f, eventKind) => { // TODO: GH#18217
if (isLoggingEnabled) {
this.log.writeLine(`FileWatcher:: Triggered with ${f} eventKind: ${FileWatcherEventKind[eventKind]}:: WatchInfo: ${file}:: handler is already invoked '${watchers.isInvoked}'`);
}
if (!watchers.isInvoked) {
watchers.isInvoked = true;
this.sendResponse({ projectName, kind: ActionInvalidate });
}
}, /*pollingInterval*/ 2000);
const watcher = projectWatcherType === ProjectWatcherType.FileWatcher ?
this.installTypingHost.watchFile!(path, (f, eventKind) => { // TODO: GH#18217
if (isLoggingEnabled) {
this.log.writeLine(`FileWatcher:: Triggered with ${f} eventKind: ${FileWatcherEventKind[eventKind]}:: WatchInfo: ${path}:: handler is already invoked '${watchers.isInvoked}'`);
}
if (!watchers.isInvoked) {
watchers.isInvoked = true;
this.sendResponse({ projectName, kind: ActionInvalidate });
}
}, /*pollingInterval*/ 2000) :
this.installTypingHost.watchDirectory!(path, f => { // TODO: GH#18217
if (isLoggingEnabled) {
this.log.writeLine(`DirectoryWatcher:: Triggered with ${f} :: WatchInfo: ${path} recursive :: handler is already invoked '${watchers.isInvoked}'`);
}
if (watchers.isInvoked || !fileExtensionIs(f, Extension.Json)) {
return;
}
return isLoggingEnabled ? {
if (isPackageOrBowerJson(f, this.installTypingHost.useCaseSensitiveFileNames) &&
!sameFiles(f, this.globalCachePackageJsonPath, this.installTypingHost.useCaseSensitiveFileNames)) {
watchers.isInvoked = true;
this.sendResponse({ projectName, kind: ActionInvalidate });
}
}, /*recursive*/ true);
watchers.set(canonicalPath, isLoggingEnabled ? {
close: () => {
this.log.writeLine(`FileWatcher:: Closed:: WatchInfo: ${file}`);
this.log.writeLine(`${projectWatcherType}:: Closed:: WatchInfo: ${path}`);
watcher.close();
}
} : watcher;
};
const createProjectDirectoryWatcher = (dir: string): FileWatcher => {
if (isLoggingEnabled) {
this.log.writeLine(`DirectoryWatcher:: Added:: WatchInfo: ${dir} recursive`);
}
const watcher = this.installTypingHost.watchDirectory!(dir, f => { // TODO: GH#18217
if (isLoggingEnabled) {
this.log.writeLine(`DirectoryWatcher:: Triggered with ${f} :: WatchInfo: ${dir} recursive :: handler is already invoked '${watchers.isInvoked}'`);
}
if (watchers.isInvoked) {
return;
}
f = this.toCanonicalFileName(f);
if (f !== this.globalCacheCanonicalPackageJsonPath && isPackageOrBowerJson(f)) {
watchers.isInvoked = true;
this.sendResponse({ projectName, kind: ActionInvalidate });
}
}, /*recursive*/ true);
return isLoggingEnabled ? {
close: () => {
this.log.writeLine(`DirectoryWatcher:: Closed:: WatchInfo: ${dir} recursive`);
watcher.close();
}
} : watcher;
} : watcher);
};
// Create watches from list of files
for (const file of files) {
const filePath = this.toCanonicalFileName(file);
if (isPackageOrBowerJson(filePath)) {
if (file.endsWith("/package.json") || file.endsWith("/bower.json")) {
// package.json or bower.json exists, watch the file to detect changes and update typings
createProjectWatcher(filePath, createProjectFileWatcher);
createProjectWatcher(file, ProjectWatcherType.FileWatcher);
continue;
}
// path in projectRoot, watch project root
if (containsPath(projectRootPath, filePath, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) {
createProjectWatcher(projectRootPath, createProjectDirectoryWatcher);
if (containsPath(projectRootPath, file, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) {
const subDirectory = file.indexOf(directorySeparator, projectRootPath.length + 1);
if (subDirectory !== -1) {
// Watch subDirectory
createProjectWatcher(file.substr(0, subDirectory), ProjectWatcherType.DirectoryWatcher);
}
else {
// Watch the directory itself
createProjectWatcher(file, ProjectWatcherType.DirectoryWatcher);
}
continue;
}
// path in global cache, watch global cache
if (containsPath(this.globalCachePath, filePath, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) {
createProjectWatcher(this.globalCachePath, createProjectDirectoryWatcher);
if (containsPath(this.globalCachePath, file, projectRootPath, !this.installTypingHost.useCaseSensitiveFileNames)) {
createProjectWatcher(this.globalCachePath, ProjectWatcherType.DirectoryWatcher);
continue;
}
// Get path without node_modules and bower_components
createProjectWatcher(getDirectoryExcludingNodeModulesOrBowerComponents(getDirectoryPath(filePath)), createProjectDirectoryWatcher);
// watch node_modules or bower_components
createProjectWatcher(file, ProjectWatcherType.DirectoryWatcher);
}
// Remove unused watches
@@ -103,8 +103,6 @@ declare function encodeURIComponent(uriComponent: string): string;
>uriComponent : string
interface PropertyDescriptor {
>PropertyDescriptor : PropertyDescriptor
configurable?: boolean;
>configurable : boolean
@@ -126,20 +124,14 @@ interface PropertyDescriptor {
}
interface PropertyDescriptorMap {
>PropertyDescriptorMap : PropertyDescriptorMap
[s: string]: PropertyDescriptor;
>s : string
>PropertyDescriptor : PropertyDescriptor
}
interface Object {
>Object : Object
/** The initial value of Object.prototype.constructor is the standard built-in Object constructor. */
constructor: Function;
>constructor : Function
>Function : Function
/** Returns a string representation of an object. */
toString(): string;
@@ -152,7 +144,6 @@ interface Object {
/** Returns the primitive value of the specified object. */
valueOf(): Object;
>valueOf : () => Object
>Object : Object
/**
* Determines whether an object has a property with the specified name.
@@ -169,7 +160,6 @@ interface Object {
isPrototypeOf(v: Object): boolean;
>isPrototypeOf : (v: Object) => boolean
>v : Object
>Object : Object
/**
* Determines whether a specified property is enumerable.
@@ -188,7 +178,6 @@ declare var Object: {
new (value?: any): Object;
>value : any
>Object : Object
(): any;
(value: any): any;
@@ -197,7 +186,6 @@ declare var Object: {
/** A reference to the prototype for a class of objects. */
prototype: Object;
>prototype : Object
>Object : Object
/**
* Returns the prototype of an object.
@@ -217,7 +205,6 @@ declare var Object: {
>getOwnPropertyDescriptor : (o: any, p: string) => PropertyDescriptor
>o : any
>p : string
>PropertyDescriptor : PropertyDescriptor
/**
* Returns the names of the own properties of an object. The own properties of an object are those that are defined directly
@@ -237,7 +224,6 @@ declare var Object: {
>create : (o: any, properties?: PropertyDescriptorMap) => any
>o : any
>properties : PropertyDescriptorMap
>PropertyDescriptorMap : PropertyDescriptorMap
/**
* Adds a property to an object, or modifies attributes of an existing property.
@@ -250,7 +236,6 @@ declare var Object: {
>o : any
>p : string
>attributes : PropertyDescriptor
>PropertyDescriptor : PropertyDescriptor
/**
* Adds one or more properties to an object, and/or modifies attributes of existing properties.
@@ -261,7 +246,6 @@ declare var Object: {
>defineProperties : (o: any, properties: PropertyDescriptorMap) => any
>o : any
>properties : PropertyDescriptorMap
>PropertyDescriptorMap : PropertyDescriptorMap
/**
* Prevents the modification of attributes of existing properties, and prevents the addition of new properties.
@@ -324,8 +308,6 @@ declare var Object: {
* Creates a new function.
*/
interface Function {
>Function : Function
/**
* Calls the function, substituting the specified object for the this value of the function, and the specified array for the arguments of the function.
* @param thisArg The object to be used as the this object.
@@ -369,7 +351,6 @@ interface Function {
caller: Function;
>caller : Function
>Function : Function
}
declare var Function: {
@@ -381,20 +362,15 @@ declare var Function: {
*/
new (...args: string[]): Function;
>args : string[]
>Function : Function
(...args: string[]): Function;
>args : string[]
>Function : Function
prototype: Function;
>prototype : Function
>Function : Function
}
interface IArguments {
>IArguments : IArguments
[index: number]: any;
>index : number
@@ -403,12 +379,9 @@ interface IArguments {
callee: Function;
>callee : Function
>Function : Function
}
interface String {
>String : String
/** Returns a string representation of a string. */
toString(): string;
>toString : () => string
@@ -480,7 +453,6 @@ interface String {
match(regexp: RegExp): string[];
>match : { (regexp: string): string[]; (regexp: RegExp): string[]; }
>regexp : RegExp
>RegExp : RegExp
/**
* Replaces text in a string, using a regular expression or search string.
@@ -512,7 +484,6 @@ interface String {
replace(searchValue: RegExp, replaceValue: string): string;
>replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replaceValue: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replaceValue: (substring: string, ...args: any[]) => string): string; }
>searchValue : RegExp
>RegExp : RegExp
>replaceValue : string
/**
@@ -523,7 +494,6 @@ interface String {
replace(searchValue: RegExp, replaceValue: (substring: string, ...args: any[]) => string): string;
>replace : { (searchValue: string, replaceValue: string): string; (searchValue: string, replaceValue: (substring: string, ...args: any[]) => string): string; (searchValue: RegExp, replaceValue: string): string; (searchValue: RegExp, replaceValue: (substring: string, ...args: any[]) => string): string; }
>searchValue : RegExp
>RegExp : RegExp
>replaceValue : (substring: string, ...args: any[]) => string
>substring : string
>args : any[]
@@ -543,7 +513,6 @@ interface String {
search(regexp: RegExp): number;
>search : { (regexp: string): number; (regexp: RegExp): number; }
>regexp : RegExp
>RegExp : RegExp
/**
* Returns a section of a string.
@@ -574,7 +543,6 @@ interface String {
split(separator: RegExp, limit?: number): string[];
>split : { (separator: string, limit?: number): string[]; (separator: RegExp, limit?: number): string[]; }
>separator : RegExp
>RegExp : RegExp
>limit : number
/**
@@ -635,14 +603,12 @@ declare var String: {
new (value?: any): String;
>value : any
>String : String
(value?: any): string;
>value : any
prototype: String;
>prototype : String
>String : String
fromCharCode(...codes: number[]): string;
>fromCharCode : (...codes: number[]) => string
@@ -650,26 +616,21 @@ declare var String: {
}
interface Boolean {
>Boolean : Boolean
}
declare var Boolean: {
>Boolean : { (value?: any): boolean; new (value?: any): Boolean; prototype: Boolean; }
new (value?: any): Boolean;
>value : any
>Boolean : Boolean
(value?: any): boolean;
>value : any
prototype: Boolean;
>prototype : Boolean
>Boolean : Boolean
}
interface Number {
>Number : Number
/**
* Returns a string representation of an object.
* @param radix Specifies a radix for converting numeric values to strings. This value is only used for numbers.
@@ -709,14 +670,12 @@ declare var Number: {
new (value?: any): Number;
>value : any
>Number : Number
(value?: any): number;
>value : any
prototype: Number;
>prototype : Number
>Number : Number
/** The largest number that can be represented in JavaScript. Equal to approximately 1.79E+308. */
MAX_VALUE: number;
@@ -749,8 +708,6 @@ declare var Number: {
}
interface Math {
>Math : Math
/** The mathematical constant e. This is Euler's number, the base of natural logarithms. */
E: number;
>E : number
@@ -931,12 +888,9 @@ interface Math {
/** An intrinsic object that provides basic mathematics functionality and constants. */
declare var Math: Math;
>Math : Math
>Math : Math
/** Enables basic storage and retrieval of dates and times. */
interface Date {
>Date : Date
/** Returns a string representation of a date. The format of the string depends on the locale. */
toString(): string;
>toString : () => string
@@ -1211,15 +1165,11 @@ declare var Date: {
>Date : { (): string; new (): Date; new (value: number): Date; new (value: string): Date; new (year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date; prototype: Date; parse(s: string): number; UTC(year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): number; now(): number; }
new (): Date;
>Date : Date
new (value: number): Date;
>value : number
>Date : Date
new (value: string): Date;
>value : string
>Date : Date
new (year: number, month: number, date?: number, hours?: number, minutes?: number, seconds?: number, ms?: number): Date;
>year : number
@@ -1229,12 +1179,10 @@ declare var Date: {
>minutes : number
>seconds : number
>ms : number
>Date : Date
(): string;
prototype: Date;
>prototype : Date
>Date : Date
/**
* Parses a string containing a date, and returns the number of milliseconds between that date and midnight, January 1, 1970.
@@ -1269,8 +1217,6 @@ declare var Date: {
}
interface RegExpExecArray {
>RegExpExecArray : RegExpExecArray
[index: number]: string;
>index : number
@@ -1406,8 +1352,6 @@ interface RegExpExecArray {
interface RegExp {
>RegExp : RegExp
/**
* Executes a search on a string using a regular expression pattern, and returns an array containing the results of that search.
* @param string The String object or string literal on which to perform the search.
@@ -1415,7 +1359,6 @@ interface RegExp {
exec(string: string): RegExpExecArray;
>exec : (string: string) => RegExpExecArray
>string : string
>RegExpExecArray : RegExpExecArray
/**
* Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@@ -1447,7 +1390,6 @@ interface RegExp {
// Non-standard extensions
compile(): RegExp;
>compile : () => RegExp
>RegExp : RegExp
}
declare var RegExp: {
>RegExp : { (pattern: string, flags?: string): RegExp; new (pattern: string, flags?: string): RegExp; $1: string; $2: string; $3: string; $4: string; $5: string; $6: string; $7: string; $8: string; $9: string; lastMatch: string; }
@@ -1455,12 +1397,10 @@ declare var RegExp: {
new (pattern: string, flags?: string): RegExp;
>pattern : string
>flags : string
>RegExp : RegExp
(pattern: string, flags?: string): RegExp;
>pattern : string
>flags : string
>RegExp : RegExp
// Non-standard extensions
$1: string;
@@ -1495,8 +1435,6 @@ declare var RegExp: {
}
interface Error {
>Error : Error
name: string;
>name : string
@@ -1508,140 +1446,105 @@ declare var Error: {
new (message?: string): Error;
>message : string
>Error : Error
(message?: string): Error;
>message : string
>Error : Error
prototype: Error;
>prototype : Error
>Error : Error
}
interface EvalError extends Error {
>EvalError : EvalError
>Error : Error
}
declare var EvalError: {
>EvalError : { (message?: string): EvalError; new (message?: string): EvalError; prototype: EvalError; }
new (message?: string): EvalError;
>message : string
>EvalError : EvalError
(message?: string): EvalError;
>message : string
>EvalError : EvalError
prototype: EvalError;
>prototype : EvalError
>EvalError : EvalError
}
interface RangeError extends Error {
>RangeError : RangeError
>Error : Error
}
declare var RangeError: {
>RangeError : { (message?: string): RangeError; new (message?: string): RangeError; prototype: RangeError; }
new (message?: string): RangeError;
>message : string
>RangeError : RangeError
(message?: string): RangeError;
>message : string
>RangeError : RangeError
prototype: RangeError;
>prototype : RangeError
>RangeError : RangeError
}
interface ReferenceError extends Error {
>ReferenceError : ReferenceError
>Error : Error
}
declare var ReferenceError: {
>ReferenceError : { (message?: string): ReferenceError; new (message?: string): ReferenceError; prototype: ReferenceError; }
new (message?: string): ReferenceError;
>message : string
>ReferenceError : ReferenceError
(message?: string): ReferenceError;
>message : string
>ReferenceError : ReferenceError
prototype: ReferenceError;
>prototype : ReferenceError
>ReferenceError : ReferenceError
}
interface SyntaxError extends Error {
>SyntaxError : SyntaxError
>Error : Error
}
declare var SyntaxError: {
>SyntaxError : { (message?: string): SyntaxError; new (message?: string): SyntaxError; prototype: SyntaxError; }
new (message?: string): SyntaxError;
>message : string
>SyntaxError : SyntaxError
(message?: string): SyntaxError;
>message : string
>SyntaxError : SyntaxError
prototype: SyntaxError;
>prototype : SyntaxError
>SyntaxError : SyntaxError
}
interface TypeError extends Error {
>TypeError : TypeError
>Error : Error
}
declare var TypeError: {
>TypeError : { (message?: string): TypeError; new (message?: string): TypeError; prototype: TypeError; }
new (message?: string): TypeError;
>message : string
>TypeError : TypeError
(message?: string): TypeError;
>message : string
>TypeError : TypeError
prototype: TypeError;
>prototype : TypeError
>TypeError : TypeError
}
interface URIError extends Error {
>URIError : URIError
>Error : Error
}
declare var URIError: {
>URIError : { (message?: string): URIError; new (message?: string): URIError; prototype: URIError; }
new (message?: string): URIError;
>message : string
>URIError : URIError
(message?: string): URIError;
>message : string
>URIError : URIError
prototype: URIError;
>prototype : URIError
>URIError : URIError
}
interface JSON {
>JSON : JSON
/**
* Converts a JavaScript Object Notation (JSON) string into an object.
* @param text A valid JSON string.
@@ -1716,7 +1619,6 @@ interface JSON {
*/
declare var JSON: JSON;
>JSON : JSON
>JSON : JSON
/////////////////////////////
@@ -1724,9 +1626,6 @@ declare var JSON: JSON;
/////////////////////////////
interface Array<T> {
>Array : T[]
>T : T
/**
* Returns a string representation of an array.
*/
@@ -1742,11 +1641,7 @@ interface Array<T> {
*/
concat<U extends T[]>(...items: U[]): T[];
>concat : { <U extends T[]>(...items: U[]): T[]; (...items: T[]): T[]; }
>U : U
>T : T
>items : U[]
>U : U
>T : T
/**
* Combines two or more arrays.
@@ -1755,8 +1650,6 @@ interface Array<T> {
concat(...items: T[]): T[];
>concat : { <U extends T[]>(...items: U[]): T[]; (...items: T[]): T[]; }
>items : T[]
>T : T
>T : T
/**
* Adds all the elements of an array separated by the specified separator string.
@@ -1771,7 +1664,6 @@ interface Array<T> {
*/
pop(): T;
>pop : () => T
>T : T
/**
* Appends new elements to an array, and returns the new length of the array.
@@ -1780,21 +1672,18 @@ interface Array<T> {
push(...items: T[]): number;
>push : (...items: T[]) => number
>items : T[]
>T : T
/**
* Reverses the elements in an Array.
*/
reverse(): T[];
>reverse : () => T[]
>T : T
/**
* Removes the first element from an array and returns it.
*/
shift(): T;
>shift : () => T
>T : T
/**
* Returns a section of an array.
@@ -1805,7 +1694,6 @@ interface Array<T> {
>slice : (start?: number, end?: number) => T[]
>start : number
>end : number
>T : T
/**
* Sorts an array.
@@ -1815,10 +1703,7 @@ interface Array<T> {
>sort : (compareFn?: (a: T, b: T) => number) => T[]
>compareFn : (a: T, b: T) => number
>a : T
>T : T
>b : T
>T : T
>T : T
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@@ -1827,7 +1712,6 @@ interface Array<T> {
splice(start: number): T[];
>splice : { (start: number): T[]; (start: number, deleteCount: number, ...items: T[]): T[]; }
>start : number
>T : T
/**
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
@@ -1840,8 +1724,6 @@ interface Array<T> {
>start : number
>deleteCount : number
>items : T[]
>T : T
>T : T
/**
* Inserts new elements at the start of an array.
@@ -1850,7 +1732,6 @@ interface Array<T> {
unshift(...items: T[]): number;
>unshift : (...items: T[]) => number
>items : T[]
>T : T
/**
* Returns the index of the first occurrence of a value in an array.
@@ -1860,7 +1741,6 @@ interface Array<T> {
indexOf(searchElement: T, fromIndex?: number): number;
>indexOf : (searchElement: T, fromIndex?: number) => number
>searchElement : T
>T : T
>fromIndex : number
/**
@@ -1871,7 +1751,6 @@ interface Array<T> {
lastIndexOf(searchElement: T, fromIndex?: number): number;
>lastIndexOf : (searchElement: T, fromIndex?: number) => number
>searchElement : T
>T : T
>fromIndex : number
/**
@@ -1883,10 +1762,8 @@ interface Array<T> {
>every : (callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any) => boolean
>callbackfn : (value: T, index: number, array: T[]) => boolean
>value : T
>T : T
>index : number
>array : T[]
>T : T
>thisArg : any
/**
@@ -1898,10 +1775,8 @@ interface Array<T> {
>some : (callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any) => boolean
>callbackfn : (value: T, index: number, array: T[]) => boolean
>value : T
>T : T
>index : number
>array : T[]
>T : T
>thisArg : any
/**
@@ -1913,10 +1788,8 @@ interface Array<T> {
>forEach : (callbackfn: (value: T, index: number, array: T[]) => void, thisArg?: any) => void
>callbackfn : (value: T, index: number, array: T[]) => void
>value : T
>T : T
>index : number
>array : T[]
>T : T
>thisArg : any
/**
@@ -1926,16 +1799,11 @@ interface Array<T> {
*/
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
>map : <U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any) => U[]
>U : U
>callbackfn : (value: T, index: number, array: T[]) => U
>value : T
>T : T
>index : number
>array : T[]
>T : T
>U : U
>thisArg : any
>U : U
/**
* Returns the elements of an array that meet the condition specified in a callback function.
@@ -1946,12 +1814,9 @@ interface Array<T> {
>filter : (callbackfn: (value: T, index: number, array: T[]) => boolean, thisArg?: any) => T[]
>callbackfn : (value: T, index: number, array: T[]) => boolean
>value : T
>T : T
>index : number
>array : T[]
>T : T
>thisArg : any
>T : T
/**
* Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@@ -1962,16 +1827,10 @@ interface Array<T> {
>reduce : { (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T; <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
>callbackfn : (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T
>previousValue : T
>T : T
>currentValue : T
>T : T
>currentIndex : number
>array : T[]
>T : T
>T : T
>initialValue : T
>T : T
>T : T
/**
* Calls the specified callback function for all the elements in an array. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@@ -1980,19 +1839,12 @@ interface Array<T> {
*/
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
>reduce : { (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T; <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
>U : U
>callbackfn : (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U
>previousValue : U
>U : U
>currentValue : T
>T : T
>currentIndex : number
>array : T[]
>T : T
>U : U
>initialValue : U
>U : U
>U : U
/**
* Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@@ -2003,16 +1855,10 @@ interface Array<T> {
>reduceRight : { (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T; <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
>callbackfn : (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T
>previousValue : T
>T : T
>currentValue : T
>T : T
>currentIndex : number
>array : T[]
>T : T
>T : T
>initialValue : T
>T : T
>T : T
/**
* Calls the specified callback function for all the elements in an array, in descending order. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
@@ -2021,19 +1867,12 @@ interface Array<T> {
*/
reduceRight<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U;
>reduceRight : { (callbackfn: (previousValue: T, currentValue: T, currentIndex: number, array: T[]) => T, initialValue?: T): T; <U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U, initialValue: U): U; }
>U : U
>callbackfn : (previousValue: U, currentValue: T, currentIndex: number, array: T[]) => U
>previousValue : U
>U : U
>currentValue : T
>T : T
>currentIndex : number
>array : T[]
>T : T
>U : U
>initialValue : U
>U : U
>U : U
/**
* Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.
@@ -2043,7 +1882,6 @@ interface Array<T> {
[n: number]: T;
>n : number
>T : T
}
declare var Array: {
>Array : { (arrayLength?: number): any[]; <T>(arrayLength: number): T[]; <T>(...items: T[]): T[]; new (arrayLength?: number): any[]; new <T>(arrayLength: number): T[]; new <T>(...items: T[]): T[]; isArray(arg: any): boolean; prototype: any[]; }
@@ -2052,29 +1890,19 @@ declare var Array: {
>arrayLength : number
new <T>(arrayLength: number): T[];
>T : T
>arrayLength : number
>T : T
new <T>(...items: T[]): T[];
>T : T
>items : T[]
>T : T
>T : T
(arrayLength?: number): any[];
>arrayLength : number
<T>(arrayLength: number): T[];
>T : T
>arrayLength : number
>T : T
<T>(...items: T[]): T[];
>T : T
>items : T[]
>T : T
>T : T
isArray(arg: any): boolean;
>isArray : (arg: any) => boolean
@@ -2082,5 +1910,4 @@ declare var Array: {
prototype: Array<any>;
>prototype : any[]
>Array : T[]
}
-2
View File
@@ -15,11 +15,9 @@ class Board {
ships: Ship[];
>ships : Ship[]
>Ship : Ship
cells: Cell[];
>cells : Cell[]
>Cell : Cell
private allShipsSunk() {
>allShipsSunk : () => boolean
@@ -3,6 +3,5 @@ var v = (a: ) => {
>v : (a: any) => void
>(a: ) => { } : (a: any) => void
>a : any
> : No type information available!
};
@@ -3,14 +3,12 @@
class clodule1<T>{
>clodule1 : clodule1<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
}
module clodule1 {
@@ -19,19 +17,16 @@ module clodule1 {
function f(x: T) { }
>f : (x: any) => void
>x : any
>T : No type information available!
}
class clodule2<T>{
>clodule2 : clodule2<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
}
module clodule2 {
@@ -39,32 +34,26 @@ module clodule2 {
var x: T;
>x : any
>T : No type information available!
class D<U extends T>{
>D : D<U>
>U : U
>T : No type information available!
id: string;
>id : string
value: U;
>value : U
>U : U
}
}
class clodule3<T>{
>clodule3 : clodule3<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
}
module clodule3 {
@@ -79,14 +68,12 @@ module clodule3 {
class clodule4<T>{
>clodule4 : clodule4<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
}
module clodule4 {
@@ -97,7 +84,6 @@ module clodule4 {
name: T;
>name : any
>T : No type information available!
}
}
@@ -1,20 +1,16 @@
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndGenericClassStaticFunctionOfTheSameName.ts ===
class clodule<T> {
>clodule : clodule<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
static fn<U>(id: U) { }
>fn : <U>(id: U) => void
>U : U
>id : U
>U : U
}
module clodule {
@@ -23,12 +19,8 @@ module clodule {
// error: duplicate identifier expected
export function fn<T>(x: T, y: T): T {
>fn : <T>(x: T, y: T) => T
>T : T
>x : T
>T : T
>y : T
>T : T
>T : T
return x;
>x : T
@@ -1,14 +1,12 @@
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedGenericFunctionAndNonGenericClassStaticFunctionOfTheSameName.ts ===
class clodule<T> {
>clodule : clodule<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
static fn(id: string) { }
>fn : (id: string) => void
@@ -21,12 +19,8 @@ module clodule {
// error: duplicate identifier expected
export function fn<T>(x: T, y: T): T {
>fn : <T>(x: T, y: T) => T
>T : T
>x : T
>T : T
>y : T
>T : T
>T : T
return x;
>x : T
@@ -1,14 +1,12 @@
=== tests/cases/conformance/internalModules/DeclarationMerging/ClassAndModuleThatMergeWithModulesExportedStaticFunctionUsingClassPrivateStatics.ts ===
class clodule<T> {
>clodule : clodule<T>
>T : T
id: string;
>id : string
value: T;
>value : T
>T : T
private static sfn(id: string) { return 42; }
>sfn : (id: string) => number
@@ -22,11 +20,8 @@ module clodule {
// error: duplicate identifier expected
export function fn<T>(x: T, y: T): number {
>fn : <T>(x: T, y: T) => number
>T : T
>x : T
>T : T
>y : T
>T : T
return clodule.sfn('a');
>clodule.sfn('a') : number
@@ -8,7 +8,6 @@ class Point {
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
>Origin : () => Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -37,7 +36,6 @@ module A {
static Origin(): Point { return { x: 0, y: 0 }; } // unexpected error here bug 840246
>Origin : () => Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -8,7 +8,6 @@ class Point {
static Origin(): Point { return { x: 0, y: 0 }; }
>Origin : () => Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -37,7 +36,6 @@ module A {
static Origin(): Point { return { x: 0, y: 0 }; }
>Origin : () => Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -8,7 +8,6 @@ class Point {
static Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -37,7 +36,6 @@ module A {
static Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -8,7 +8,6 @@ class Point {
static Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -37,7 +36,6 @@ module A {
static Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -1,24 +1,16 @@
=== tests/cases/compiler/ClassDeclaration25.ts ===
interface IList<T> {
>IList : IList<T>
>T : T
data(): T;
>data : () => T
>T : T
next(): string;
>next : () => string
}
class List<U> implements IList<U> {
>List : List<U>
>U : U
>IList : IList<T>
>U : U
data(): U;
>data : () => U
>U : U
next(): string;
>next : () => string
@@ -4,9 +4,6 @@ type T = { x : number }
>x : number
export interface I {
>I : I
f: T;
>f : T
>T : T
}
@@ -1,7 +1,6 @@
=== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck13.ts ===
const strSet: Set<string> = new Set()
>strSet : Set<string>
>Set : Set<T>
>new Set() : Set<string>
>Set : SetConstructor
@@ -1,7 +1,6 @@
=== tests/cases/conformance/statements/for-ofStatements/ES5For-ofTypeCheck14.ts ===
var union: string | Set<number>
>union : string | Set<number>
>Set : Set<T>
for (const e of union) { }
>e : string
@@ -1,13 +1,10 @@
=== tests/cases/conformance/Symbols/ES5SymbolProperty1.ts ===
interface SymbolConstructor {
>SymbolConstructor : SymbolConstructor
foo: string;
>foo : string
}
var Symbol: SymbolConstructor;
>Symbol : SymbolConstructor
>SymbolConstructor : SymbolConstructor
var obj = {
>obj : { [Symbol.foo]: number; }
@@ -21,7 +21,6 @@ module enumdule {
var x: enumdule;
>x : enumdule
>enumdule : enumdule
var x = enumdule.Red;
>x : enumdule
@@ -3,8 +3,6 @@ module A {
>A : typeof A
interface Point {
>Point : Point
x: number;
>x : number
@@ -14,12 +12,10 @@ module A {
fromOrigin(p: Point): number;
>fromOrigin : (p: Point) => number
>p : Point
>Point : Point
}
export class Point2d implements Point {
>Point2d : Point2d
>Point : Point
constructor(public x: number, public y: number) { }
>x : number
@@ -28,7 +24,6 @@ module A {
fromOrigin(p: Point) {
>fromOrigin : (p: Point) => number
>p : Point
>Point : Point
return 1;
>1 : 1
@@ -14,7 +14,6 @@ module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -31,7 +30,6 @@ module A {
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };
>Origin3d : Point3d
>Point3d : Point3d
>{ x: 0, y: 0, z: 0 } : { x: number; y: number; z: number; }
>x : number
>0 : 0
@@ -42,14 +40,10 @@ module A {
export class Line<TPoint extends Point>{
>Line : Line<TPoint>
>TPoint : TPoint
>Point : Point
constructor(public start: TPoint, public end: TPoint) { }
>start : TPoint
>TPoint : TPoint
>end : TPoint
>TPoint : TPoint
}
}
@@ -17,11 +17,9 @@ module A {
[idx: number]: Point;
>idx : number
>Point : Point
[idx: string]: Point;
>idx : string
>Point : Point
}
}
@@ -14,7 +14,6 @@ module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -31,7 +30,6 @@ module A {
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };
>Origin3d : Point3d
>Point3d : Point3d
>{ x: 0, y: 0, z: 0 } : { x: number; y: number; z: number; }
>x : number
>0 : 0
@@ -42,21 +40,14 @@ module A {
export class Line<TPoint extends Point>{
>Line : Line<TPoint>
>TPoint : TPoint
>Point : Point
constructor(public start: TPoint, public end: TPoint) { }
>start : TPoint
>TPoint : TPoint
>end : TPoint
>TPoint : TPoint
static fromorigin2d(p: Point): Line<Point>{
>fromorigin2d : (p: Point) => Line<Point>
>p : Point
>Point : Point
>Line : Line<TPoint>
>Point : Point
return null;
>null : null
@@ -17,16 +17,12 @@ module A {
constructor(public start: Point, public end: Point) { }
>start : Point
>Point : Point
>end : Point
>Point : Point
}
export function fromOrigin(p: Point): Line {
>fromOrigin : (p: Point) => Line
>p : Point
>Point : Point
>Line : Line
return new Line({ x: 0, y: 0 }, p);
>new Line({ x: 0, y: 0 }, p) : Line
@@ -17,16 +17,12 @@ module A {
constructor(public start: Point, public end: Point) { }
>start : Point
>Point : Point
>end : Point
>Point : Point
}
export function fromOrigin(p: Point): Line {
>fromOrigin : (p: Point) => Line
>p : Point
>Point : Point
>Line : Line
return new Line({ x: 0, y: 0 }, p);
>new Line({ x: 0, y: 0 }, p) : Line
@@ -17,16 +17,12 @@ module A {
constructor(public start: Point, public end: Point) { }
>start : Point
>Point : Point
>end : Point
>Point : Point
}
export function fromOrigin(p: Point): Line {
>fromOrigin : (p: Point) => Line
>p : Point
>Point : Point
>Line : Line
return new Line({ x: 0, y: 0 }, p);
>new Line({ x: 0, y: 0 }, p) : Line
@@ -3,8 +3,6 @@ module A {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -14,7 +12,6 @@ module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -22,16 +19,12 @@ module A {
>0 : 0
export interface Point3d extends Point {
>Point3d : Point3d
>Point : Point
z: number;
>z : number
}
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };
>Origin3d : Point3d
>Point3d : Point3d
>{ x: 0, y: 0, z: 0 } : { x: number; y: number; z: number; }
>x : number
>0 : 0
@@ -41,23 +34,15 @@ module A {
>0 : 0
export interface Line<TPoint extends Point>{
>Line : Line<TPoint>
>TPoint : TPoint
>Point : Point
new (start: TPoint, end: TPoint);
>start : TPoint
>TPoint : TPoint
>end : TPoint
>TPoint : TPoint
start: TPoint;
>start : TPoint
>TPoint : TPoint
end: TPoint;
>end : TPoint
>TPoint : TPoint
}
}
@@ -1,10 +1,7 @@
=== tests/cases/conformance/internalModules/exportDeclarations/ExportInterfaceWithInaccessibleTypeInIndexerTypeAnnotations.ts ===
module A {
>A : any
interface Point {
>Point : Point
x: number;
>x : number
@@ -13,15 +10,12 @@ module A {
}
export interface points {
>points : points
[idx: number]: Point;
>idx : number
>Point : Point
[idx: string]: Point;
>idx : string
>Point : Point
}
}
@@ -3,8 +3,6 @@ module A {
>A : typeof A
interface Point {
>Point : Point
x: number;
>x : number
@@ -14,7 +12,6 @@ module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -22,16 +19,12 @@ module A {
>0 : 0
export interface Point3d extends Point {
>Point3d : Point3d
>Point : Point
z: number;
>z : number
}
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };
>Origin3d : Point3d
>Point3d : Point3d
>{ x: 0, y: 0, z: 0 } : { x: number; y: number; z: number; }
>x : number
>0 : 0
@@ -41,23 +34,15 @@ module A {
>0 : 0
export interface Line<TPoint extends Point>{
>Line : Line<TPoint>
>TPoint : TPoint
>Point : Point
new (start: TPoint, end: TPoint);
>start : TPoint
>TPoint : TPoint
>end : TPoint
>TPoint : TPoint
start: TPoint;
>start : TPoint
>TPoint : TPoint
end: TPoint;
>end : TPoint
>TPoint : TPoint
}
}
@@ -15,7 +15,6 @@ module A {
export var Origin: Point = new Point(0, 0);
>Origin : Point
>Point : Point
>new Point(0, 0) : Point
>Point : typeof Point
>0 : 0
@@ -26,16 +25,13 @@ module A {
constructor(start: Point, end: Point) {
>start : Point
>Point : Point
>end : Point
>Point : Point
}
static fromOrigin(p: Point) {
>fromOrigin : (p: Point) => Line
>p : Point
>Point : Point
return new Line({ x: 0, y: 0 }, p);
>new Line({ x: 0, y: 0 }, p) : Line
@@ -12,7 +12,6 @@ module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -16,16 +16,12 @@ module A {
top: { left: Point, right: Point },
>top : { left: Point; right: Point; }
>left : Point
>Point : Point
>right : Point
>Point : Point
bottom: { left: Point, right: Point }
>bottom : { left: Point; right: Point; }
>left : Point
>Point : Point
>right : Point
>Point : Point
} = null;
>null : null
@@ -11,12 +11,9 @@ module A {
export var beez: Array<B>;
>beez : B[]
>Array : T[]
>B : B
export var beez2 = new Array<B>();
>beez2 : B[]
>new Array<B>() : B[]
>Array : ArrayConstructor
>B : B
}
@@ -3,8 +3,6 @@ module A {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -15,7 +13,6 @@ module A {
// valid since Point is exported
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -3,8 +3,6 @@ module A {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -15,7 +13,6 @@ module A {
// valid since Point is exported
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -23,9 +20,6 @@ module A {
>0 : 0
interface Point3d extends Point {
>Point3d : Point3d
>Point : Point
z: number;
>z : number
}
@@ -33,7 +27,6 @@ module A {
// invalid Point3d is not exported
export var Origin3d: Point3d = { x: 0, y: 0, z: 0 };
>Origin3d : Point3d
>Point3d : Point3d
>{ x: 0, y: 0, z: 0 } : { x: number; y: number; z: number; }
>x : number
>0 : 0
@@ -5,6 +5,5 @@ function * foo() {
// Legal to use 'yield' in a type context.
var v: yield;
>v : any
>yield : No type information available!
}
@@ -3,5 +3,4 @@ var v = { *<T>() { } }
>v : { (Missing)<T>(): IterableIterator<any>; }
>{ *<T>() { } } : { (Missing)<T>(): IterableIterator<any>; }
> : <T>() => IterableIterator<any>
>T : T
@@ -1,4 +1,4 @@
=== tests/cases/compiler/InterfaceDeclaration8.ts ===
interface string {
>string : string
}
No type information for this code.}
No type information for this code.
@@ -1,9 +1,6 @@
=== tests/cases/conformance/internalModules/moduleDeclarations/InvalidNonInstantiatedModule.ts ===
module M {
>M : any
export interface Point { x: number; y: number }
>Point : Point
>x : number
>y : number
}
@@ -2,5 +2,5 @@
"kind": "JSDocComment",
"pos": 0,
"end": 23,
"comment": "* @type {number} "
"comment": "* @type {number}"
}
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 20,
"end": 19,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 20,
"end": 19,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -22,7 +22,7 @@
"0": {
"kind": "TypeParameter",
"pos": 18,
"end": 20,
"end": 19,
"name": {
"kind": "Identifier",
"pos": 18,
@@ -33,7 +33,7 @@
"1": {
"kind": "TypeParameter",
"pos": 22,
"end": 24,
"end": 23,
"name": {
"kind": "Identifier",
"pos": 22,
@@ -2,5 +2,5 @@
"kind": "JSDocComment",
"pos": 0,
"end": 7,
"comment": "* "
"comment": "*"
}
@@ -4,5 +4,4 @@ class C {
*foo<T>() { }
>foo : <T>() => IterableIterator<any>
>T : T
}
@@ -21,7 +21,6 @@ enum enumdule {
var x: enumdule;
>x : enumdule
>enumdule : enumdule
var x = enumdule.Red;
>x : enumdule
@@ -14,16 +14,12 @@ module A {
export class AG<T, U>{
>AG : AG<T, U>
>T : T
>U : U
id: T;
>id : T
>T : T
name: U;
>name : U
>U : U
}
class A2 {
@@ -38,16 +34,12 @@ module A {
class AG2<T, U>{
>AG2 : AG2<T, U>
>T : T
>U : U
id: T;
>id : T
>T : T
name: U;
>name : U
>U : U
}
}
@@ -17,7 +17,6 @@ module A {
var a: A.Color = A.Color.Red;
>a : A.Color
>A : any
>Color : A.Color
>A.Color.Red : A.Color.Red
>A.Color : typeof A.Color
>A : typeof A
@@ -12,11 +12,7 @@ module A {
export function fng<T, U>(s: T): U {
>fng : <T, U>(s: T) => U
>T : T
>U : U
>s : T
>T : T
>U : U
return null;
>null : null
@@ -32,11 +28,7 @@ module A {
function fng2<T, U>(s: T): U {
>fng2 : <T, U>(s: T) => U
>T : T
>U : U
>s : T
>T : T
>U : U
return null;
>null : null
@@ -56,11 +48,7 @@ var fn = A.fn;
var fng: <T, U>(s: T) => U;
>fng : <T, U>(s: T) => U
>T : T
>U : U
>s : T
>T : T
>U : U
var fng = A.fng; // bug 838015
>fng : <T, U>(s: T) => U
@@ -1,10 +1,6 @@
=== tests/cases/conformance/internalModules/exportDeclarations/ModuleWithExportedAndNonExportedImportAlias.ts ===
module A {
>A : any
export interface Point {
>Point : Point
x: number;
>x : number
@@ -13,9 +9,6 @@ module A {
}
interface Point3d extends Point {
>Point3d : Point3d
>Point : Point
z: number;
>z : number
}
@@ -30,10 +23,8 @@ module B {
constructor(public start: A.Point, public end: A.Point) { }
>start : A.Point
>A : any
>Point : A.Point
>end : A.Point
>A : any
>Point : A.Point
}
}
@@ -51,7 +42,6 @@ module Geometry {
export var Origin: Points.Point = { x: 0, y: 0 };
>Origin : Points.Point
>Points : any
>Point : Points.Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -62,7 +52,6 @@ module Geometry {
export var Unit: Lines.Line = new Lines.Line(Origin, { x: 1, y: 0 });
>Unit : Lines.Line
>Lines : any
>Line : Lines.Line
>new Lines.Line(Origin, { x: 1, y: 0 }) : Lines.Line
>Lines.Line : typeof Lines.Line
>Lines : typeof Lines
@@ -85,7 +74,6 @@ var p: Geometry.Points.Point;
>p : { x: number; y: number; }
>Geometry : any
>Points : any
>Point : A.Point
var p = Geometry.Origin;
>p : { x: number; y: number; }
@@ -25,11 +25,9 @@ module Inner {
export var e: A;
>e : A
>A : A
export let f: A;
>f : A
>A : A
namespace B {
>B : typeof B
@@ -95,13 +93,11 @@ module Inner {
export var g1: D = new D;
>g1 : D
>D : D
>new D : D
>D : typeof D
export let h1: D = new D;
>h1 : D
>D : D
>new D : D
>D : typeof D
}
@@ -1,7 +1,5 @@
=== tests/cases/compiler/ParameterList13.ts ===
interface I {
>I : I
new (public x);
>x : any
}
@@ -2,5 +2,4 @@
function A(): (public B) => C {
>A : () => (B: any) => any
>B : any
>C : No type information available!
}
+2 -2
View File
@@ -1,4 +1,4 @@
=== tests/cases/conformance/parser/ecmascript5/Protected/Protected2.ts ===
protected module M {
>M : any
}
No type information for this code.}
No type information for this code.
@@ -1,7 +1,5 @@
=== tests/cases/conformance/parser/ecmascript5/Protected/Protected8.ts ===
interface I {
>I : I
protected
>protected : any
@@ -23,7 +23,6 @@ module A {
>fromCarthesian : (p: A.Point) => { x: number; y: number; }
>p : A.Point
>A : any
>Point : A.Point
return { x: p.x, y: p.y };
>{ x: p.x, y: p.y } : { x: number; y: number; }
@@ -48,7 +47,6 @@ var p: { x: number; y: number; };
var p: A.Point;
>p : { x: number; y: number; }
>A : any
>Point : A.Point
module X.Y.Z {
>X : typeof X
@@ -92,6 +90,5 @@ var l: X.Y.Z.Line;
>X : any
>Y : any
>Z : any
>Line : X.Y.Z.Line
@@ -1,10 +1,6 @@
=== tests/cases/conformance/internalModules/DeclarationMerging/TwoInternalModulesThatMergeEachWithExportedAndNonExportedInterfacesOfTheSameName.ts ===
module A {
>A : any
export interface Point {
>Point : Point
x: number;
>x : number
@@ -13,19 +9,13 @@ module A {
toCarth(): Point;
>toCarth : () => Point
>Point : Point
}
}
module A {
>A : any
interface Point {
>Point : Point
fromCarth(): Point;
>fromCarth : () => Point
>Point : Point
}
}
@@ -36,50 +26,31 @@ var p: { x: number; y: number; toCarth(): A.Point; };
>y : number
>toCarth : () => A.Point
>A : any
>Point : A.Point
var p: A.Point;
>p : { x: number; y: number; toCarth(): A.Point; }
>A : any
>Point : A.Point
module X.Y.Z {
>X : any
>Y : any
>Z : any
export interface Line {
>Line : Line
new (start: A.Point, end: A.Point);
>start : A.Point
>A : any
>Point : A.Point
>end : A.Point
>A : any
>Point : A.Point
}
}
module X {
>X : any
export module Y.Z {
>Y : any
>Z : any
interface Line {
>Line : Line
start: A.Point;
>start : A.Point
>A : any
>Point : A.Point
end: A.Point;
>end : A.Point
>A : any
>Point : A.Point
}
}
}
@@ -89,15 +60,12 @@ var l: { new (s: A.Point, e: A.Point); }
>l : new (s: A.Point, e: A.Point) => any
>s : A.Point
>A : any
>Point : A.Point
>e : A.Point
>A : any
>Point : A.Point
var l: X.Y.Z.Line;
>l : new (s: A.Point, e: A.Point) => any
>X : any
>Y : any
>Z : any
>Line : X.Y.Z.Line
@@ -3,8 +3,6 @@ module A {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -17,10 +15,7 @@ module A {
export function mirror<T extends Point>(p: T) {
>mirror : <T extends Point>(p: T) => { x: number; y: number; }
>T : T
>Point : Point
>p : T
>T : T
return { x: p.y, y: p.x };
>{ x: p.y, y: p.x } : { x: number; y: number; }
@@ -36,7 +31,6 @@ module A {
}
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -61,9 +55,7 @@ module A {
constructor(public tl: Point, public br: Point) { }
>tl : Point
>Point : Point
>br : Point
>Point : Point
}
}
}
@@ -79,7 +71,6 @@ var o: { x: number; y: number };
var o: A.Point;
>o : { x: number; y: number; }
>A : any
>Point : A.Point
var o = A.Origin;
>o : { x: number; y: number; }
@@ -101,16 +92,13 @@ var p: { tl: A.Point; br: A.Point };
>p : { tl: A.Point; br: A.Point; }
>tl : A.Point
>A : any
>Point : A.Point
>br : A.Point
>A : any
>Point : A.Point
var p: A.Utils.Plane;
>p : { tl: A.Point; br: A.Point; }
>A : any
>Utils : any
>Plane : A.Utils.Plane
var p = new A.Utils.Plane(o, { x: 1, y: 1 });
>p : { tl: A.Point; br: A.Point; }
@@ -1,10 +1,6 @@
=== tests/cases/conformance/internalModules/DeclarationMerging/TwoInternalModulesThatMergeEachWithExportedInterfacesOfTheSameName.ts ===
module A {
>A : any
export interface Point {
>Point : Point
x: number;
>x : number
@@ -13,19 +9,13 @@ module A {
toCarth(): Point;
>toCarth : () => Point
>Point : Point
}
}
module A {
>A : any
export interface Point {
>Point : Point
fromCarth(): Point;
>fromCarth : () => Point
>Point : Point
}
}
@@ -36,53 +26,33 @@ var p: { x: number; y: number; toCarth(): A.Point; fromCarth(): A.Point; };
>y : number
>toCarth : () => A.Point
>A : any
>Point : A.Point
>fromCarth : () => A.Point
>A : any
>Point : A.Point
var p: A.Point;
>p : { x: number; y: number; toCarth(): A.Point; fromCarth(): A.Point; }
>A : any
>Point : A.Point
module X.Y.Z {
>X : any
>Y : any
>Z : any
export interface Line {
>Line : Line
new (start: A.Point, end: A.Point);
>start : A.Point
>A : any
>Point : A.Point
>end : A.Point
>A : any
>Point : A.Point
}
}
module X {
>X : any
export module Y.Z {
>Y : any
>Z : any
export interface Line {
>Line : Line
start: A.Point;
>start : A.Point
>A : any
>Point : A.Point
end: A.Point;
>end : A.Point
>A : any
>Point : A.Point
}
}
}
@@ -92,21 +62,16 @@ var l: { start: A.Point; end: A.Point; new (s: A.Point, e: A.Point); }
>l : { new (s: A.Point, e: A.Point): any; start: A.Point; end: A.Point; }
>start : A.Point
>A : any
>Point : A.Point
>end : A.Point
>A : any
>Point : A.Point
>s : A.Point
>A : any
>Point : A.Point
>e : A.Point
>A : any
>Point : A.Point
var l: X.Y.Z.Line;
>l : { new (s: A.Point, e: A.Point): any; start: A.Point; end: A.Point; }
>X : any
>Y : any
>Z : any
>Line : X.Y.Z.Line
@@ -3,8 +3,6 @@ export module A {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -17,10 +15,7 @@ export module A {
export function mirror<T extends Point>(p: T) {
>mirror : <T extends Point>(p: T) => { x: number; y: number; }
>T : T
>Point : Point
>p : T
>T : T
return { x: p.y, y: p.x };
>{ x: p.y, y: p.x } : { x: number; y: number; }
@@ -37,7 +32,6 @@ export module A {
export var Origin: Point = { x: 0, y: 0 };
>Origin : Point
>Point : Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -52,7 +46,6 @@ export module A {
// collision with 'Origin' var in other part of merged module
export var Origin: Point = { x: 0, y: 0 };
>Origin : any
>Point : No type information available!
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -67,9 +60,7 @@ export module A {
constructor(public tl: Point, public br: Point) { }
>tl : any
>Point : No type information available!
>br : any
>Point : No type information available!
}
}
}
@@ -72,5 +72,4 @@ var l: X.Y.Z.Line;
>X : any
>Y : any
>Z : any
>Line : X.Y.Z.Line
@@ -6,8 +6,6 @@ module Root {
>A : typeof A
export interface Point {
>Point : Point
x: number;
>x : number
@@ -20,10 +18,7 @@ module Root {
export function mirror<T extends Point>(p: T) {
>mirror : <T extends Point>(p: T) => { x: number; y: number; }
>T : T
>Point : Point
>p : T
>T : T
return { x: p.y, y: p.x };
>{ x: p.y, y: p.x } : { x: number; y: number; }
@@ -52,7 +47,6 @@ module otherRoot {
>Origin : Root.A.Point
>Root : any
>A : any
>Point : Root.A.Point
>{ x: 0, y: 0 } : { x: number; y: number; }
>x : number
>0 : 0
@@ -69,11 +63,9 @@ module otherRoot {
>tl : Root.A.Point
>Root : any
>A : any
>Point : Root.A.Point
>br : Root.A.Point
>Root : any
>A : any
>Point : Root.A.Point
}
}
}
Loaded 100 of 3966 files, more files were not shown because too many files have changed in this diff. Show more