diff --git a/src/compiler/builder.ts b/src/compiler/builder.ts index bd35bac6c5f..f26791075c3 100644 --- a/src/compiler/builder.ts +++ b/src/compiler/builder.ts @@ -612,7 +612,8 @@ namespace ts { */ function getProgramBuildInfo(state: Readonly, getCanonicalFileName: GetCanonicalFileName): ProgramBuildInfo | undefined { if (state.compilerOptions.outFile || state.compilerOptions.out) return undefined; - const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(state.compilerOptions)!, Debug.assertDefined(state.program).getCurrentDirectory())); + const currentDirectory = Debug.assertDefined(state.program).getCurrentDirectory(); + const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(state.compilerOptions)!, currentDirectory)); const fileInfos: MapLike = {}; state.fileInfos.forEach((value, key) => { const signature = state.currentAffectedFilesSignatures && state.currentAffectedFilesSignatures.get(key); @@ -621,7 +622,7 @@ namespace ts { const result: ProgramBuildInfo = { fileInfos, - options: convertToReusableCompilerOptions(state.compilerOptions, relativeToBuildInfo) + options: convertToReusableCompilerOptions(state.compilerOptions, relativeToBuildInfoEnsuringAbsolutePath) }; if (state.referencedMap) { const referencedMap: MapLike = {}; @@ -661,6 +662,10 @@ namespace ts { return result; + function relativeToBuildInfoEnsuringAbsolutePath(path: string) { + return relativeToBuildInfo(getNormalizedAbsolutePath(path, currentDirectory)); + } + function relativeToBuildInfo(path: string) { return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName)); } diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 70c69063696..c4ffdd0240c 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -42,10 +42,10 @@ namespace ts { iterableCacheKey: "iterationTypesOfAsyncIterable" | "iterationTypesOfIterable"; iteratorCacheKey: "iterationTypesOfAsyncIterator" | "iterationTypesOfIterator"; iteratorSymbolName: "asyncIterator" | "iterator"; - getGlobalIteratorType: (reportErrors: boolean) => Type; - getGlobalIterableType: (reportErrors: boolean) => Type; - getGlobalIterableIteratorType: (reportErrors: boolean) => Type; - getGlobalGeneratorType: (reportErrors: boolean) => Type; + getGlobalIteratorType: (reportErrors: boolean) => GenericType; + getGlobalIterableType: (reportErrors: boolean) => GenericType; + getGlobalIterableIteratorType: (reportErrors: boolean) => GenericType; + getGlobalGeneratorType: (reportErrors: boolean) => GenericType; resolveIterationType: (type: Type, errorNode: Node | undefined) => Type | undefined; mustHaveANextMethodDiagnostic: DiagnosticMessage; mustBeAMethodDiagnostic: DiagnosticMessage; @@ -7247,9 +7247,11 @@ namespace ts { } function combineUnionParameters(left: Signature, right: Signature) { - const longest = getParameterCount(left) >= getParameterCount(right) ? left : right; + const leftCount = getParameterCount(left); + const rightCount = getParameterCount(right); + const longest = leftCount >= rightCount ? left : right; const shorter = longest === left ? right : left; - const longestCount = getParameterCount(longest); + const longestCount = longest === left ? leftCount : rightCount; const eitherHasEffectiveRest = (hasEffectiveRestParameter(left) || hasEffectiveRestParameter(right)); const needsExtraRestElement = eitherHasEffectiveRest && !hasEffectiveRestParameter(longest); const params = new Array(longestCount + (needsExtraRestElement ? 1 : 0)); @@ -7259,11 +7261,16 @@ namespace ts { const unionParamType = getIntersectionType([longestParamType, shorterParamType]); const isRestParam = eitherHasEffectiveRest && !needsExtraRestElement && i === (longestCount - 1); const isOptional = i >= getMinArgumentCount(longest) && i >= getMinArgumentCount(shorter); - const leftName = getParameterNameAtPosition(left, i); - const rightName = getParameterNameAtPosition(right, i); + const leftName = i >= leftCount ? undefined : getParameterNameAtPosition(left, i); + const rightName = i >= rightCount ? undefined : getParameterNameAtPosition(right, i); + + const paramName = leftName === rightName ? leftName : + !leftName ? rightName : + !rightName ? leftName : + undefined; const paramSymbol = createSymbol( SymbolFlags.FunctionScopedVariable | (isOptional && !isRestParam ? SymbolFlags.Optional : 0), - leftName === rightName ? leftName : `arg${i}` as __String + paramName || `arg${i}` as __String ); paramSymbol.type = isRestParam ? createArrayType(unionParamType) : unionParamType; params[i] = paramSymbol; @@ -9524,24 +9531,10 @@ namespace ts { return createTypeFromGenericGlobalType(getGlobalTypedPropertyDescriptorType(), [propertyType]); } - function createAsyncGeneratorType(yieldType: Type, returnType: Type, nextType: Type) { - const globalAsyncGeneratorType = getGlobalAsyncGeneratorType(/*reportErrors*/ true); - if (globalAsyncGeneratorType !== emptyGenericType) { - yieldType = getAwaitedType(yieldType) || unknownType; - returnType = getAwaitedType(returnType) || unknownType; - nextType = getAwaitedType(nextType) || unknownType; - } - return createTypeFromGenericGlobalType(globalAsyncGeneratorType, [yieldType, returnType, nextType]); - } - function createIterableType(iteratedType: Type): Type { return createTypeFromGenericGlobalType(getGlobalIterableType(/*reportErrors*/ true), [iteratedType]); } - function createGeneratorType(yieldType: Type, returnType: Type, nextType: Type) { - return createTypeFromGenericGlobalType(getGlobalGeneratorType(/*reportErrors*/ true), [yieldType, returnType, nextType]); - } - function createArrayType(elementType: Type, readonly?: boolean): ObjectType { return createTypeFromGenericGlobalType(readonly ? globalReadonlyArrayType : globalArrayType, [elementType]); } @@ -9897,7 +9890,7 @@ namespace ts { return links.resolvedType; } - function addTypeToIntersection(typeSet: Type[], includes: TypeFlags, type: Type) { + function addTypeToIntersection(typeSet: Map, includes: TypeFlags, type: Type) { const flags = type.flags; if (flags & TypeFlags.Intersection) { return addTypesToIntersection(typeSet, includes, (type).types); @@ -9905,20 +9898,20 @@ namespace ts { if (isEmptyAnonymousObjectType(type)) { if (!(includes & TypeFlags.IncludesEmptyObject)) { includes |= TypeFlags.IncludesEmptyObject; - typeSet.push(type); + typeSet.set(type.id.toString(), type); } } else { if (flags & TypeFlags.AnyOrUnknown) { if (type === wildcardType) includes |= TypeFlags.IncludesWildcard; } - else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !contains(typeSet, type)) { + else if ((strictNullChecks || !(flags & TypeFlags.Nullable)) && !typeSet.has(type.id.toString())) { if (type.flags & TypeFlags.Unit && includes & TypeFlags.Unit) { // We have seen two distinct unit types which means we should reduce to an // empty intersection. Adding TypeFlags.NonPrimitive causes that to happen. includes |= TypeFlags.NonPrimitive; } - typeSet.push(type); + typeSet.set(type.id.toString(), type); } includes |= flags & TypeFlags.IncludesMask; } @@ -9927,7 +9920,7 @@ namespace ts { // Add the given types to the given type set. Order is preserved, freshness is removed from literal // types, duplicates are removed, and nested types of the given kind are flattened into the set. - function addTypesToIntersection(typeSet: Type[], includes: TypeFlags, types: ReadonlyArray) { + function addTypesToIntersection(typeSet: Map, includes: TypeFlags, types: ReadonlyArray) { for (const type of types) { includes = addTypeToIntersection(typeSet, includes, getRegularTypeOfLiteralType(type)); } @@ -10034,8 +10027,9 @@ namespace ts { // Also, unlike union types, the order of the constituent types is preserved in order that overload resolution // for intersections of types with signatures can be deterministic. function getIntersectionType(types: ReadonlyArray, aliasSymbol?: Symbol, aliasTypeArguments?: ReadonlyArray): Type { - const typeSet: Type[] = []; - const includes = addTypesToIntersection(typeSet, 0, types); + const typeMembershipMap: Map = createMap(); + const includes = addTypesToIntersection(typeMembershipMap, 0, types); + const typeSet: Type[] = arrayFrom(typeMembershipMap.values()); // An intersection type is considered empty if it contains // the type never, or // more than one unit type or, @@ -13443,7 +13437,8 @@ namespace ts { if (includeOptional ? !(filteredByApplicability!.flags & TypeFlags.Never) : isRelatedTo(targetConstraint, sourceKeys)) { - const indexingType = filteredByApplicability || getTypeParameterFromMappedType(target); + const typeParameter = getTypeParameterFromMappedType(target); + const indexingType = filteredByApplicability ? getIntersectionType([filteredByApplicability, typeParameter]) : typeParameter; const indexedAccessType = getIndexedAccessType(source, indexingType); const templateType = getTemplateTypeFromMappedType(target); if (result = isRelatedTo(indexedAccessType, templateType, reportErrors)) { @@ -13545,6 +13540,9 @@ namespace ts { if (relation !== identityRelation) { source = getApparentType(source); } + else if (isGenericMappedType(source)) { + return Ternary.False; + } if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target && !(getObjectFlags(source) & ObjectFlags.MarkerType || getObjectFlags(target) & ObjectFlags.MarkerType)) { // We have type references to the same generic type, and the type references are not marker @@ -15258,8 +15256,8 @@ namespace ts { const inference = inferences[i]; if (t === inference.typeParameter) { if (fix && !inference.isFixed) { + clearCachedInferences(inferences); inference.isFixed = true; - inference.inferredType = undefined; } return getInferredType(context, i); } @@ -15267,6 +15265,14 @@ namespace ts { return t; } + function clearCachedInferences(inferences: InferenceInfo[]) { + for (const inference of inferences) { + if (!inference.isFixed) { + inference.inferredType = undefined; + } + } + } + function createInferenceInfo(typeParameter: TypeParameter): InferenceInfo { return { typeParameter, @@ -15453,9 +15459,11 @@ namespace ts { function inferTypes(inferences: InferenceInfo[], originalSource: Type, originalTarget: Type, priority: InferencePriority = 0, contravariant = false) { let symbolStack: Symbol[]; - let visited: Map; + let visited: Map; let bivariant = false; let propagationType: Type; + let inferenceCount = 0; + let inferenceIncomplete = false; let allowComplexConstraintInference = true; inferFromTypes(originalSource, originalTarget); @@ -15497,23 +15505,28 @@ namespace ts { // of all their possible values. let matchingTypes: Type[] | undefined; for (const t of (source).types) { - if (typeIdenticalToSomeType(t, (target).types)) { - (matchingTypes || (matchingTypes = [])).push(t); - inferFromTypes(t, t); - } - else if (t.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral)) { - const b = getBaseTypeOfLiteralType(t); - if (typeIdenticalToSomeType(b, (target).types)) { - (matchingTypes || (matchingTypes = [])).push(t, b); - } + const matched = findMatchedType(t, target); + if (matched) { + (matchingTypes || (matchingTypes = [])).push(matched); + inferFromTypes(matched, matched); } } // Next, to improve the quality of inferences, reduce the source and target types by // removing the identically matched constituents. For example, when inferring from // 'string | string[]' to 'string | T' we reduce the types to 'string[]' and 'T'. if (matchingTypes) { - source = removeTypesFromUnionOrIntersection(source, matchingTypes); - target = removeTypesFromUnionOrIntersection(target, matchingTypes); + const s = removeTypesFromUnionOrIntersection(source, matchingTypes); + const t = removeTypesFromUnionOrIntersection(target, matchingTypes); + if (!(s && t)) return; + source = s; + target = t; + } + } + else if (target.flags & TypeFlags.Union && !(target.flags & TypeFlags.EnumLiteral) || target.flags & TypeFlags.Intersection) { + const matched = findMatchedType(source, target); + if (matched) { + inferFromTypes(matched, matched); + return; } } else if (target.flags & (TypeFlags.IndexedAccess | TypeFlags.Substitution)) { @@ -15546,26 +15559,27 @@ namespace ts { if (contravariant && !bivariant) { if (!contains(inference.contraCandidates, candidate)) { inference.contraCandidates = append(inference.contraCandidates, candidate); - inference.inferredType = undefined; + clearCachedInferences(inferences); } } else if (!contains(inference.candidates, candidate)) { inference.candidates = append(inference.candidates, candidate); - inference.inferredType = undefined; + clearCachedInferences(inferences); } } if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && inference.topLevel && !isTypeParameterAtTopLevel(originalTarget, target)) { inference.topLevel = false; - inference.inferredType = undefined; + clearCachedInferences(inferences); } } + inferenceCount++; return; } else { // Infer to the simplified version of an indexed access, if possible, to (hopefully) expose more bare type parameters to the inference engine const simplified = getSimplifiedType(target, /*writing*/ false); if (simplified !== target) { - inferFromTypesOnce(source, simplified); + invokeOnce(source, simplified, inferFromTypes); } else if (target.flags & TypeFlags.IndexedAccess) { const indexType = getSimplifiedType((target as IndexedAccessType).indexType, /*writing*/ false); @@ -15574,13 +15588,14 @@ namespace ts { if (indexType.flags & TypeFlags.Instantiable) { const simplified = distributeIndexOverObjectType(getSimplifiedType((target as IndexedAccessType).objectType, /*writing*/ false), indexType, /*writing*/ false); if (simplified && simplified !== target) { - inferFromTypesOnce(source, simplified); + invokeOnce(source, simplified, inferFromTypes); } } } } } - if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && (source).target === (target).target) { + if (getObjectFlags(source) & ObjectFlags.Reference && getObjectFlags(target) & ObjectFlags.Reference && ( + (source).target === (target).target || isArrayType(source) && isArrayType(target))) { // If source and target are references to the same generic type, infer from type arguments inferFromTypeArguments((source).typeArguments || emptyArray, (target).typeArguments || emptyArray, getVariances((source).target)); } @@ -15610,10 +15625,10 @@ namespace ts { } else if (target.flags & TypeFlags.Conditional && !contravariant) { const targetTypes = [getTrueTypeFromConditionalType(target), getFalseTypeFromConditionalType(target)]; - inferToMultipleTypes(source, targetTypes, /*isIntersection*/ false); + inferToMultipleTypes(source, targetTypes, target.flags); } else if (target.flags & TypeFlags.UnionOrIntersection) { - inferToMultipleTypes(source, (target).types, !!(target.flags & TypeFlags.Intersection)); + inferToMultipleTypes(source, (target).types, target.flags); } else if (source.flags & TypeFlags.Union) { // Source is a union or intersection type, infer from each constituent type @@ -15642,39 +15657,22 @@ namespace ts { source = apparentSource; } if (source.flags & (TypeFlags.Object | TypeFlags.Intersection)) { - const key = source.id + "," + target.id; - if (visited && visited.get(key)) { - return; - } - (visited || (visited = createMap())).set(key, true); - // If we are already processing another target type with the same associated symbol (such as - // an instantiation of the same generic type), we do not explore this target as it would yield - // no further inferences. We exclude the static side of classes from this check since it shares - // its symbol with the instance side which would lead to false positives. - const isNonConstructorObject = target.flags & TypeFlags.Object && - !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); - const symbol = isNonConstructorObject ? target.symbol : undefined; - if (symbol) { - if (contains(symbolStack, symbol)) { - return; - } - (symbolStack || (symbolStack = [])).push(symbol); - inferFromObjectTypes(source, target); - symbolStack.pop(); - } - else { - inferFromObjectTypes(source, target); - } + invokeOnce(source, target, inferFromObjectTypes); } } + } - function inferFromTypesOnce(source: Type, target: Type) { - const key = source.id + "," + target.id; - if (!visited || !visited.get(key)) { - (visited || (visited = createMap())).set(key, true); - inferFromTypes(source, target); - } + function invokeOnce(source: Type, target: Type, action: (source: Type, target: Type) => void) { + const key = source.id + "," + target.id; + const count = visited && visited.get(key); + if (count !== undefined) { + inferenceCount += count; + return; } + (visited || (visited = createMap())).set(key, 0); + const startCount = inferenceCount; + action(source, target); + visited.set(key, inferenceCount - startCount); } function inferFromTypeArguments(sourceTypes: readonly Type[], targetTypes: readonly Type[], variances: readonly VarianceFlags[]) { @@ -15711,24 +15709,60 @@ namespace ts { return undefined; } - function inferToMultipleTypes(source: Type, targets: Type[], isIntersection: boolean) { - // We infer from types that are not naked type variables first so that inferences we - // make from nested naked type variables and given slightly higher priority by virtue - // of being first in the candidates array. + function inferToMultipleTypes(source: Type, targets: Type[], targetFlags: TypeFlags) { let typeVariableCount = 0; - for (const t of targets) { - if (getInferenceInfoForType(t)) { - typeVariableCount++; + if (targetFlags & TypeFlags.Union) { + let nakedTypeVariable: Type | undefined; + const sources = source.flags & TypeFlags.Union ? (source).types : [source]; + const matched = new Array(sources.length); + const saveInferenceIncomplete = inferenceIncomplete; + inferenceIncomplete = false; + // First infer to types that are not naked type variables. For each source type we + // track whether inferences were made from that particular type to some target. + for (const t of targets) { + if (getInferenceInfoForType(t)) { + nakedTypeVariable = t; + typeVariableCount++; + } + else { + for (let i = 0; i < sources.length; i++) { + const count = inferenceCount; + inferFromTypes(sources[i], t); + if (count !== inferenceCount) matched[i] = true; + } + } } - else { - inferFromTypes(source, t); + const inferenceComplete = !inferenceIncomplete; + inferenceIncomplete = inferenceIncomplete || saveInferenceIncomplete; + // If the target has a single naked type variable and inference completed (meaning we + // explored the types fully), create a union of the source types from which no inferences + // have been made so far and infer from that union to the naked type variable. + if (typeVariableCount === 1 && inferenceComplete) { + const unmatched = flatMap(sources, (s, i) => matched[i] ? undefined : s); + if (unmatched.length) { + inferFromTypes(getUnionType(unmatched), nakedTypeVariable!); + return; + } + } + } + else { + // We infer from types that are not naked type variables first so that inferences we + // make from nested naked type variables and given slightly higher priority by virtue + // of being first in the candidates array. + for (const t of targets) { + if (getInferenceInfoForType(t)) { + typeVariableCount++; + } + else { + inferFromTypes(source, t); + } } } // Inferences directly to naked type variables are given lower priority as they are // less specific. For example, when inferring from Promise to T | Promise, // we want to infer string for T, not Promise | string. For intersection types // we only infer to single naked type variables. - if (isIntersection ? typeVariableCount === 1 : typeVariableCount !== 0) { + if (targetFlags & TypeFlags.Intersection ? typeVariableCount === 1 : typeVariableCount > 0) { const savePriority = priority; priority |= InferencePriority.NakedTypeVariable; for (const t of targets) { @@ -15797,6 +15831,28 @@ namespace ts { } function inferFromObjectTypes(source: Type, target: Type) { + // If we are already processing another target type with the same associated symbol (such as + // an instantiation of the same generic type), we do not explore this target as it would yield + // no further inferences. We exclude the static side of classes from this check since it shares + // its symbol with the instance side which would lead to false positives. + const isNonConstructorObject = target.flags & TypeFlags.Object && + !(getObjectFlags(target) & ObjectFlags.Anonymous && target.symbol && target.symbol.flags & SymbolFlags.Class); + const symbol = isNonConstructorObject ? target.symbol : undefined; + if (symbol) { + if (contains(symbolStack, symbol)) { + inferenceIncomplete = true; + return; + } + (symbolStack || (symbolStack = [])).push(symbol); + inferFromObjectTypesWorker(source, target); + symbolStack.pop(); + } + else { + inferFromObjectTypesWorker(source, target); + } + } + + function inferFromObjectTypesWorker(source: Type, target: Type) { if (isGenericMappedType(source) && isGenericMappedType(target)) { // The source and target types are generic types { [P in S]: X } and { [P in T]: Y }, so we infer // from S to T and from X to Y. @@ -15899,15 +15955,35 @@ namespace ts { } } - function typeIdenticalToSomeType(type: Type, types: Type[]): boolean { + function isMatchableType(type: Type) { + // We exclude non-anonymous object types because some frameworks (e.g. Ember) rely on the ability to + // infer between types that don't witness their type variables. Such types would otherwise be eliminated + // because they appear identical. + return !(type.flags & TypeFlags.Object) || !!(getObjectFlags(type) & ObjectFlags.Anonymous); + } + + function typeMatchedBySomeType(type: Type, types: Type[]): boolean { for (const t of types) { - if (isTypeIdenticalTo(t, type)) { + if (t === type || isMatchableType(t) && isMatchableType(type) && isTypeIdenticalTo(t, type)) { return true; } } return false; } + function findMatchedType(type: Type, target: UnionOrIntersectionType) { + if (typeMatchedBySomeType(type, target.types)) { + return type; + } + if (type.flags & (TypeFlags.NumberLiteral | TypeFlags.StringLiteral) && target.flags & TypeFlags.Union) { + const base = getBaseTypeOfLiteralType(type); + if (typeMatchedBySomeType(base, target.types)) { + return base; + } + } + return undefined; + } + /** * Return a new union or intersection type computed by removing a given set of types * from a given union or intersection type. @@ -15915,11 +15991,11 @@ namespace ts { function removeTypesFromUnionOrIntersection(type: UnionOrIntersectionType, typesToRemove: Type[]) { const reducedTypes: Type[] = []; for (const t of type.types) { - if (!typeIdenticalToSomeType(t, typesToRemove)) { + if (!typeMatchedBySomeType(t, typesToRemove)) { reducedTypes.push(t); } } - return type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes); + return reducedTypes.length ? type.flags & TypeFlags.Union ? getUnionType(reducedTypes) : getIntersectionType(reducedTypes) : undefined; } function hasPrimitiveConstraint(type: TypeParameter): boolean { @@ -19043,7 +19119,7 @@ namespace ts { // If the given contextual type contains instantiable types and if a mapper representing // return type inferences is available, instantiate those types using that mapper. - function instantiateContextualType(contextualType: Type | undefined, node: Expression, contextFlags?: ContextFlags): Type | undefined { + function instantiateContextualType(contextualType: Type | undefined, node: Node, contextFlags?: ContextFlags): Type | undefined { if (contextualType && maybeTypeOfKind(contextualType, TypeFlags.Instantiable)) { const inferenceContext = getInferenceContext(node); // If no inferences have been made, nothing is gained from instantiating as type parameters @@ -20571,10 +20647,15 @@ namespace ts { } propType = getConstraintForLocation(getTypeOfSymbol(prop), node); } + return getFlowTypeOfAccessExpression(node, prop, propType, right); + } + + function getFlowTypeOfAccessExpression(node: ElementAccessExpression | PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, propType: Type, errorNode: Node) { // Only compute control flow type if this is a property access expression that isn't an // assignment target, and the referenced property was declared as a variable, property, // accessor, or optional method. - if (node.kind !== SyntaxKind.PropertyAccessExpression || + const assignmentKind = getAssignmentTargetKind(node); + if (node.kind !== SyntaxKind.ElementAccessExpression && node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite || prop && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) { return propType; @@ -20584,7 +20665,7 @@ namespace ts { // and if we are in a constructor of the same class as the property declaration, assume that // the property is uninitialized at the top of the control flow. let assumeUninitialized = false; - if (strictNullChecks && strictPropertyInitialization && left.kind === SyntaxKind.ThisKeyword) { + if (strictNullChecks && strictPropertyInitialization && node.expression.kind === SyntaxKind.ThisKeyword) { const declaration = prop && prop.valueDeclaration; if (declaration && isInstancePropertyWithoutInitializer(declaration)) { const flowContainer = getControlFlowContainer(node); @@ -20601,7 +20682,7 @@ namespace ts { } const flowType = getFlowTypeOfReference(node, propType, assumeUninitialized ? getOptionalType(propType) : propType); if (assumeUninitialized && !(getFalsyFlags(propType) & TypeFlags.Undefined) && getFalsyFlags(flowType) & TypeFlags.Undefined) { - error(right, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 + error(errorNode, Diagnostics.Property_0_is_used_before_being_assigned, symbolToString(prop!)); // TODO: GH#18217 // Return the declared type to reduce follow-on errors return propType; } @@ -20707,7 +20788,8 @@ namespace ts { else { const promisedType = getPromisedTypeOfPromise(containingType); if (promisedType && getPropertyOfType(promisedType, propNode.escapedText)) { - errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_forget_to_use_await, declarationNameToString(propNode), typeToString(containingType)); + errorInfo = chainDiagnosticMessages(errorInfo, Diagnostics.Property_0_does_not_exist_on_type_1, declarationNameToString(propNode), typeToString(containingType)); + relatedInfo = createDiagnosticForNode(propNode, Diagnostics.Did_you_forget_to_use_await); } else { const suggestion = getSuggestedSymbolForNonexistentProperty(propNode, containingType); @@ -20957,7 +21039,7 @@ namespace ts { AccessFlags.Writing | (isGenericObjectType(objectType) && !isThisTypeParameter(objectType) ? AccessFlags.NoIndexSignatures : 0) : AccessFlags.None; const indexedAccessType = getIndexedAccessTypeOrUndefined(objectType, effectiveIndexType, node, accessFlags) || errorType; - return checkIndexedAccessIndexType(indexedAccessType, node); + return checkIndexedAccessIndexType(getFlowTypeOfAccessExpression(node, indexedAccessType.symbol, indexedAccessType, indexExpression), node); } function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean { @@ -22741,7 +22823,7 @@ namespace ts { isVariableDeclaration(decl.parent) && getSymbolOfNode(decl.parent)); const prototype = assignmentSymbol && assignmentSymbol.exports && assignmentSymbol.exports.get("prototype" as __String); const init = prototype && prototype.valueDeclaration && getAssignedJSPrototype(prototype.valueDeclaration); - return init ? checkExpression(init) : undefined; + return init ? getWidenedType(checkExpressionCached(init)) : undefined; } function getAssignedJSPrototype(node: Node) { @@ -23354,7 +23436,7 @@ namespace ts { nextType && isUnitType(nextType)) { const contextualType = !contextualSignature ? undefined : contextualSignature === getSignatureFromDeclaration(func) ? isGenerator ? undefined : returnType : - getReturnTypeOfSignature(contextualSignature); + instantiateContextualType(getReturnTypeOfSignature(contextualSignature), func); if (isGenerator) { yieldType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(yieldType, contextualType, IterationTypeKind.Yield, isAsync); returnType = getWidenedLiteralLikeTypeForContextualIterationTypeIfNeeded(returnType, contextualType, IterationTypeKind.Return, isAsync); @@ -23384,9 +23466,36 @@ namespace ts { } function createGeneratorReturnType(yieldType: Type, returnType: Type, nextType: Type, isAsyncGenerator: boolean) { - return isAsyncGenerator - ? createAsyncGeneratorType(yieldType, returnType, nextType) - : createGeneratorType(yieldType, returnType, nextType); + const resolver = isAsyncGenerator ? asyncIterationTypesResolver : syncIterationTypesResolver; + const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false); + yieldType = resolver.resolveIterationType(yieldType, /*errorNode*/ undefined) || unknownType; + returnType = resolver.resolveIterationType(returnType, /*errorNode*/ undefined) || unknownType; + nextType = resolver.resolveIterationType(nextType, /*errorNode*/ undefined) || unknownType; + if (globalGeneratorType === emptyGenericType) { + // Fall back to the global IterableIterator if returnType is assignable to the expected return iteration + // type of IterableIterator, and the expected next iteration type of IterableIterator is assignable to + // nextType. + const globalType = resolver.getGlobalIterableIteratorType(/*reportErrors*/ false); + const iterationTypes = globalType !== emptyGenericType ? getIterationTypesOfGlobalIterableType(globalType, resolver) : undefined; + const iterableIteratorReturnType = iterationTypes ? iterationTypes.returnType : anyType; + const iterableIteratorNextType = iterationTypes ? iterationTypes.nextType : undefinedType; + if (isTypeAssignableTo(returnType, iterableIteratorReturnType) && + isTypeAssignableTo(iterableIteratorNextType, nextType)) { + if (globalType !== emptyGenericType) { + return createTypeFromGenericGlobalType(globalType, [yieldType]); + } + + // The global IterableIterator type doesn't exist, so report an error + resolver.getGlobalIterableIteratorType(/*reportErrors*/ true); + return emptyObjectType; + } + + // The global Generator type doesn't exist, so report an error + resolver.getGlobalGeneratorType(/*reportErrors*/ true); + return emptyObjectType; + } + + return createTypeFromGenericGlobalType(globalGeneratorType, [yieldType, returnType, nextType]); } function checkAndAggregateYieldOperandTypes(func: FunctionLikeDeclaration, checkMode: CheckMode | undefined) { @@ -24705,6 +24814,12 @@ namespace ts { || anyType; } + const contextualReturnType = getContextualReturnType(func); + if (contextualReturnType) { + return getIterationTypeOfGeneratorFunctionReturnType(IterationTypeKind.Next, contextualReturnType, isAsync) + || anyType; + } + return anyType; } @@ -26394,7 +26509,11 @@ namespace ts { * The runtime behavior of the `await` keyword. */ function checkAwaitedType(type: Type, errorNode: Node, diagnosticMessage: DiagnosticMessage, arg0?: string | number): Type { - return getAwaitedType(type, errorNode, diagnosticMessage, arg0) || errorType; + const awaitedType = getAwaitedType(type, errorNode, diagnosticMessage, arg0); + if (awaitedType === type && !(type.flags & TypeFlags.AnyOrUnknown)) { + addErrorOrSuggestion(/*isError*/ false, createDiagnosticForNode(errorNode, Diagnostics.await_has_no_effect_on_the_type_of_this_expression)); + } + return awaitedType || errorType; } function getAwaitedType(type: Type, errorNode?: Node, diagnosticMessage?: DiagnosticMessage, arg0?: string | number): Type | undefined { @@ -28219,6 +28338,13 @@ namespace ts { return (type as IterableOrIteratorType)[resolver.iterableCacheKey]; } + function getIterationTypesOfGlobalIterableType(globalType: Type, resolver: IterationTypesResolver) { + const globalIterationTypes = + getIterationTypesOfIterableCached(globalType, resolver) || + getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined); + return globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; + } + /** * Gets the *yield*, *return*, and *next* types of an `Iterable`-like or `AsyncIterable`-like * type from from common heuristics. @@ -28244,10 +28370,7 @@ namespace ts { // iteration types of their `[Symbol.iterator]()` method. The same is true for their async cousins. // While we define these as `any` and `undefined` in our libs by default, a custom lib *could* use // different definitions. - const globalIterationTypes = - getIterationTypesOfIterableCached(globalType, resolver) || - getIterationTypesOfIterableSlow(globalType, resolver, /*errorNode*/ undefined); - const { returnType, nextType } = globalIterationTypes === noIterationTypes ? defaultIterationTypes : globalIterationTypes; + const { returnType, nextType } = getIterationTypesOfGlobalIterableType(globalType, resolver); return (type as IterableOrIteratorType)[resolver.iterableCacheKey] = createIterationTypes(yieldType, returnType, nextType); } @@ -33004,9 +33127,6 @@ namespace ts { return grammarErrorAtPos(node, node.end - 1, ";".length, Diagnostics._0_expected, "{"); } } - else if (isClassLike(node.parent) && isStringLiteral(node.name) && node.name.text === "constructor" && (!compilerOptions.target || compilerOptions.target < ScriptTarget.ES5)) { - return grammarErrorOnNode(node.name, Diagnostics.Quoted_constructors_have_previously_been_interpreted_as_methods_which_is_incorrect_In_TypeScript_3_6_they_will_be_correctly_parsed_as_constructors_In_the_meantime_consider_using_constructor_to_write_a_constructor_or_constructor_to_write_a_method); - } if (checkGrammarForGenerator(node)) { return true; } diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json index 10c3fcb6095..2a5b825c6c8 100644 --- a/src/compiler/diagnosticMessages.json +++ b/src/compiler/diagnosticMessages.json @@ -2076,10 +2076,6 @@ "category": "Error", "code": 2569 }, - "Property '{0}' does not exist on type '{1}'. Did you forget to use 'await'?": { - "category": "Error", - "code": 2570 - }, "Object is of type 'unknown'.": { "category": "Error", "code": 2571 @@ -4643,6 +4639,11 @@ "category": "Suggestion", "code": 80006 }, + "'await' has no effect on the type of this expression.": { + "category": "Suggestion", + "code": 80007 + }, + "Add missing 'super()' call": { "category": "Message", "code": 90001 @@ -5091,14 +5092,31 @@ "category": "Message", "code": 95082 }, + "Add 'await'": { + "category": "Message", + "code": 95083 + }, + "Add 'await' to initializer for '{0}'": { + "category": "Message", + "code": 95084 + }, + "Fix all expressions possibly missing 'await'": { + "category": "Message", + "code": 95085 + }, + "Remove unnecessary 'await'": { + "category": "Message", + "code": 95086 + }, + "Remove all unnecessary uses of 'await'": { + "category": "Message", + "code": 95087 + }, + "No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": { "category": "Error", "code": 18004 }, - "Quoted constructors have previously been interpreted as methods, which is incorrect. In TypeScript 3.6, they will be correctly parsed as constructors. In the meantime, consider using 'constructor()' to write a constructor, or '[\"constructor\"]()' to write a method.": { - "category": "Error", - "code": 18005 - }, "Classes may not have a field named 'constructor'.": { "category": "Error", "code": 18006 diff --git a/src/compiler/emitter.ts b/src/compiler/emitter.ts index a1207c9b892..8681a452e2a 100644 --- a/src/compiler/emitter.ts +++ b/src/compiler/emitter.ts @@ -411,7 +411,11 @@ namespace ts { } ); if (emitOnlyDtsFiles && declarationTransform.transformed[0].kind === SyntaxKind.SourceFile) { - const sourceFile = declarationTransform.transformed[0] as SourceFile; + // Improved narrowing in master/3.6 makes this cast unnecessary, triggering a lint rule. + // But at the same time, the LKG (3.5) necessitates it because it doesn’t narrow. + // Once the LKG is updated to 3.6, this comment, the cast to `SourceFile`, and the + // tslint directive can be all be removed. + const sourceFile = declarationTransform.transformed[0] as SourceFile; // tslint:disable-line exportedModulesFromDeclarationEmit = sourceFile.exportedModulesFromDeclarationEmit; } } diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts index f88950f531a..1f0294423a5 100644 --- a/src/compiler/factory.ts +++ b/src/compiler/factory.ts @@ -4701,7 +4701,7 @@ namespace ts { } } - function getLeftmostExpression(node: Expression, stopAtCallExpressions: boolean) { + export function getLeftmostExpression(node: Expression, stopAtCallExpressions: boolean) { while (true) { switch (node.kind) { case SyntaxKind.PostfixUnaryExpression: diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts index f115d66951a..254be93000b 100644 --- a/src/compiler/parser.ts +++ b/src/compiler/parser.ts @@ -5656,12 +5656,27 @@ namespace ts { return finishNode(node); } - function parseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration { - node.kind = SyntaxKind.Constructor; - parseExpected(SyntaxKind.ConstructorKeyword); - fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); - node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); - return finishNode(node); + function parseConstructorName() { + if (token() === SyntaxKind.ConstructorKeyword) { + return parseExpected(SyntaxKind.ConstructorKeyword); + } + if (token() === SyntaxKind.StringLiteral && lookAhead(nextToken) === SyntaxKind.OpenParenToken) { + return tryParse(() => { + const literalNode = parseLiteralNode(); + return literalNode.text === "constructor" ? literalNode : undefined; + }); + } + } + + function tryParseConstructorDeclaration(node: ConstructorDeclaration): ConstructorDeclaration | undefined { + return tryParse(() => { + if (parseConstructorName()) { + node.kind = SyntaxKind.Constructor; + fillSignature(SyntaxKind.ColonToken, SignatureFlags.None, node); + node.body = parseFunctionBlockOrSemicolon(SignatureFlags.None, Diagnostics.or_expected); + return finishNode(node); + } + }); } function parseMethodDeclaration(node: MethodDeclaration, asteriskToken: AsteriskToken, diagnosticMessage?: DiagnosticMessage): MethodDeclaration { @@ -5867,8 +5882,11 @@ namespace ts { return parseAccessorDeclaration(node, SyntaxKind.SetAccessor); } - if (token() === SyntaxKind.ConstructorKeyword) { - return parseConstructorDeclaration(node); + if (token() === SyntaxKind.ConstructorKeyword || token() === SyntaxKind.StringLiteral) { + const constructorDeclaration = tryParseConstructorDeclaration(node); + if (constructorDeclaration) { + return constructorDeclaration; + } } if (isIndexSignature()) { diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts index 256e41629a1..f949893171a 100644 --- a/src/compiler/scanner.ts +++ b/src/compiler/scanner.ts @@ -197,6 +197,7 @@ namespace ts { "|=": SyntaxKind.BarEqualsToken, "^=": SyntaxKind.CaretEqualsToken, "@": SyntaxKind.AtToken, + "`": SyntaxKind.BacktickToken }); /* @@ -298,7 +299,6 @@ namespace ts { } const tokenStrings = makeReverseMap(textToToken); - export function tokenToString(t: SyntaxKind): string | undefined { return tokenStrings[t]; } diff --git a/src/compiler/transformers/es2017.ts b/src/compiler/transformers/es2017.ts index 8d20f94afed..9c2d5700d43 100644 --- a/src/compiler/transformers/es2017.ts +++ b/src/compiler/transformers/es2017.ts @@ -775,10 +775,11 @@ namespace ts { priority: 5, text: ` var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } - function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); };` diff --git a/src/compiler/transformers/es2018.ts b/src/compiler/transformers/es2018.ts index 89c43dcf599..50fb9f04d1a 100644 --- a/src/compiler/transformers/es2018.ts +++ b/src/compiler/transformers/es2018.ts @@ -229,14 +229,39 @@ namespace ts { if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) { // spread elements emit like so: // non-spread elements are chunked together into object literals, and then all are passed to __assign: - // { a, ...o, b } => __assign({a}, o, {b}); + // { a, ...o, b } => __assign(__assign({a}, o), {b}); // If the first element is a spread element, then the first argument to __assign is {}: - // { ...o, a, b, ...o2 } => __assign({}, o, {a, b}, o2) + // { ...o, a, b, ...o2 } => __assign(__assign(__assign({}, o), {a, b}), o2) + // + // We cannot call __assign with more than two elements, since any element could cause side effects. For + // example: + // var k = { a: 1, b: 2 }; + // var o = { a: 3, ...k, b: k.a++ }; + // // expected: { a: 1, b: 1 } + // If we translate the above to `__assign({ a: 3 }, k, { b: k.a++ })`, the `k.a++` will evaluate before + // `k` is spread and we end up with `{ a: 2, b: 1 }`. + // + // This also occurs for spread elements, not just property assignments: + // var k = { a: 1, get b() { l = { z: 9 }; return 2; } }; + // var l = { c: 3 }; + // var o = { ...k, ...l }; + // // expected: { a: 1, b: 2, z: 9 } + // If we translate the above to `__assign({}, k, l)`, the `l` will evaluate before `k` is spread and we + // end up with `{ a: 1, b: 2, c: 3 }` const objects = chunkObjectLiteralElements(node.properties); if (objects.length && objects[0].kind !== SyntaxKind.ObjectLiteralExpression) { objects.unshift(createObjectLiteral()); } - return createAssignHelper(context, objects); + let expression: Expression = objects[0]; + if (objects.length > 1) { + for (let i = 1; i < objects.length; i++) { + expression = createAssignHelper(context, [expression, objects[i]]); + } + return expression; + } + else { + return createAssignHelper(context, objects); + } } return visitEachChild(node, visitor, context); } diff --git a/src/compiler/types.ts b/src/compiler/types.ts index ce6d5764bf7..81f55dd6040 100644 --- a/src/compiler/types.ts +++ b/src/compiler/types.ts @@ -1882,6 +1882,7 @@ namespace ts { } export interface JsxAttributes extends ObjectLiteralExpressionBase { + kind: SyntaxKind.JsxAttributes; parent: JsxOpeningLikeElement; } @@ -4762,7 +4763,7 @@ namespace ts { UMD = 3, System = 4, ES2015 = 5, - ESNext = 6 + ESNext = 99 } export const enum JsxEmit { @@ -4810,7 +4811,7 @@ namespace ts { ES2018 = 5, ES2019 = 6, ES2020 = 7, - ESNext = 8, + ESNext = 99, JSON = 100, Latest = ESNext, } diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts index 9a86b0a31d7..006fea5a9b1 100644 --- a/src/compiler/utilities.ts +++ b/src/compiler/utilities.ts @@ -3150,6 +3150,23 @@ namespace ts { return s.replace(escapedCharsRegExp, getReplacement); } + /** + * Strip off existed single quotes or double quotes from a given string + * + * @return non-quoted string + */ + export function stripQuotes(name: string) { + const length = name.length; + if (length >= 2 && name.charCodeAt(0) === name.charCodeAt(length - 1) && startsWithQuote(name)) { + return name.substring(1, length - 1); + } + return name; + } + + export function startsWithQuote(name: string): boolean { + return isSingleOrDoubleQuote(name.charCodeAt(0)); + } + function getReplacement(c: string, offset: number, input: string) { if (c.charCodeAt(0) === CharacterCodes.nullCharacter) { const lookAhead = input.charCodeAt(offset + c.length); diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts index ffc0759e92e..f12506be2fb 100644 --- a/src/harness/fourslash.ts +++ b/src/harness/fourslash.ts @@ -797,7 +797,7 @@ namespace FourSlash { for (const include of toArray(options.includes)) { const name = typeof include === "string" ? include : include.name; const found = nameToEntries.get(name); - if (!found) throw this.raiseError(`No completion ${name} found`); + if (!found) throw this.raiseError(`Includes: completion '${name}' not found.`); assert(found.length === 1); // Must use 'exact' for multiple completions with same name this.verifyCompletionEntry(ts.first(found), include); } @@ -806,7 +806,7 @@ namespace FourSlash { for (const exclude of toArray(options.excludes)) { assert(typeof exclude === "string"); if (nameToEntries.has(exclude)) { - this.raiseError(`Did not expect to get a completion named ${exclude}`); + this.raiseError(`Excludes: unexpected completion '${exclude}' found.`); } } } @@ -865,7 +865,7 @@ namespace FourSlash { ts.zipWith(actual, expected, (completion, expectedCompletion, index) => { const name = typeof expectedCompletion === "string" ? expectedCompletion : expectedCompletion.name; if (completion.name !== name) { - this.raiseError(`${marker ? JSON.stringify(marker) : "" } Expected completion at index ${index} to be ${name}, got ${completion.name}`); + this.raiseError(`${marker ? JSON.stringify(marker) : ""} Expected completion at index ${index} to be ${name}, got ${completion.name}`); } this.verifyCompletionEntry(completion, expectedCompletion); }); @@ -948,7 +948,7 @@ namespace FourSlash { const actual = checker.typeToString(type); if (actual !== expected) { - this.raiseError(`Expected: '${expected}', actual: '${actual}'`); + this.raiseError(displayExpectedAndActualString(expected, actual)); } } @@ -1024,9 +1024,7 @@ namespace FourSlash { private assertObjectsEqual(fullActual: T, fullExpected: T, msgPrefix = ""): void { const recur = (actual: U, expected: U, path: string) => { const fail = (msg: string) => { - this.raiseError(`${msgPrefix} At ${path}: ${msg} -Expected: ${stringify(fullExpected)} -Actual: ${stringify(fullActual)}`); + this.raiseError(`${msgPrefix} At ${path}: ${msg} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); }; if ((actual === undefined) !== (expected === undefined)) { @@ -1058,9 +1056,7 @@ Actual: ${stringify(fullActual)}`); if (fullActual === fullExpected) { return; } - this.raiseError(`${msgPrefix} -Expected: ${stringify(fullExpected)} -Actual: ${stringify(fullActual)}`); + this.raiseError(`${msgPrefix} ${displayExpectedAndActualString(stringify(fullExpected), stringify(fullActual))}`); } recur(fullActual, fullExpected, ""); @@ -2111,9 +2107,7 @@ Actual: ${stringify(fullActual)}`); public verifyCurrentLineContent(text: string) { const actual = this.getCurrentLineContent(); if (actual !== text) { - throw new Error("verifyCurrentLineContent\n" + - "\tExpected: \"" + text + "\"\n" + - "\t Actual: \"" + actual + "\""); + throw new Error("verifyCurrentLineContent\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); } } @@ -2139,25 +2133,19 @@ Actual: ${stringify(fullActual)}`); public verifyTextAtCaretIs(text: string) { const actual = this.getFileContent(this.activeFile.fileName).substring(this.currentCaretPosition, this.currentCaretPosition + text.length); if (actual !== text) { - throw new Error("verifyTextAtCaretIs\n" + - "\tExpected: \"" + text + "\"\n" + - "\t Actual: \"" + actual + "\""); + throw new Error("verifyTextAtCaretIs\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); } } public verifyCurrentNameOrDottedNameSpanText(text: string) { const span = this.languageService.getNameOrDottedNameSpan(this.activeFile.fileName, this.currentCaretPosition, this.currentCaretPosition); if (!span) { - return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + - "\tExpected: \"" + text + "\"\n" + - "\t Actual: undefined"); + return this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString("\"" + text + "\"", "undefined")); } const actual = this.getFileContent(this.activeFile.fileName).substring(span.start, ts.textSpanEnd(span)); if (actual !== text) { - this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + - "\tExpected: \"" + text + "\"\n" + - "\t Actual: \"" + actual + "\""); + this.raiseError("verifyCurrentNameOrDottedNameSpanText\n" + displayExpectedAndActualString(text, actual, /* quoted */ true)); } } @@ -2828,11 +2816,28 @@ Actual: ${stringify(fullActual)}`); } } - public verifyCodeFixAvailable(negative: boolean, expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | undefined): void { - assert(!negative || !expected); + public verifyCodeFixAvailable(negative: boolean, expected: FourSlashInterface.VerifyCodeFixAvailableOptions[] | string | undefined): void { const codeFixes = this.getCodeFixes(this.activeFile.fileName); - const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ description: fix.description, commands: fix.commands })); - this.assertObjectsEqual(actuals, negative ? ts.emptyArray : expected); + if (negative) { + if (typeof expected === "undefined") { + this.assertObjectsEqual(codeFixes, ts.emptyArray); + } + else if (typeof expected === "string") { + if (codeFixes.some(fix => fix.fixName === expected)) { + this.raiseError(`Expected not to find a fix with the name '${expected}', but one exists.`); + } + } + else { + assert(typeof expected === "undefined" || typeof expected === "string", "With a negated assertion, 'expected' must be undefined or a string value of a codefix name."); + } + } + else if (typeof expected === "string") { + this.assertObjectsEqual(codeFixes.map(fix => fix.fixName), [expected]); + } + else { + const actuals = codeFixes.map((fix): FourSlashInterface.VerifyCodeFixAvailableOptions => ({ description: fix.description, commands: fix.commands })); + this.assertObjectsEqual(actuals, negative ? ts.emptyArray : expected); + } } public verifyApplicableRefactorAvailableAtMarker(negative: boolean, markerName: string) { @@ -3673,7 +3678,7 @@ ${code} expected = makeWhitespaceVisible(expected); actual = makeWhitespaceVisible(actual); } - return `Expected:\n${expected}\nActual:\n${actual}`; + return displayExpectedAndActualString(expected, actual); } function differOnlyByWhitespace(a: string, b: string) { @@ -3693,6 +3698,14 @@ ${code} } } } + + function displayExpectedAndActualString(expected: string, actual: string, quoted = false) { + const expectMsg = "\x1b[1mExpected\x1b[0m\x1b[31m"; + const actualMsg = "\x1b[1mActual\x1b[0m\x1b[31m"; + const expectedString = quoted ? "\"" + expected + "\"" : expected; + const actualString = quoted ? "\"" + actual + "\"" : actual; + return `\n${expectMsg}:\n${expectedString}\n\n${actualMsg}:\n${actualString}`; + } } namespace FourSlashInterface { @@ -3742,7 +3755,7 @@ namespace FourSlashInterface { } export class Plugins { - constructor (private state: FourSlash.TestState) { + constructor(private state: FourSlash.TestState) { } public configurePlugin(pluginName: string, configuration: any): void { @@ -4565,7 +4578,7 @@ namespace FourSlashInterface { export const keywords: ReadonlyArray = keywordsWithUndefined.filter(k => k.name !== "undefined"); export const typeKeywords: ReadonlyArray = - ["false", "null", "true", "void", "any", "boolean", "keyof", "never", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry); + ["false", "null", "true", "void", "any", "boolean", "keyof", "never", "readonly", "number", "object", "string", "symbol", "undefined", "unique", "unknown", "bigint"].map(keywordEntry); const globalTypeDecls: ReadonlyArray = [ interfaceEntry("Symbol"), @@ -4681,6 +4694,9 @@ namespace FourSlashInterface { ]; } + export const typeAssertionKeywords: ReadonlyArray = + globalTypesPlus([keywordEntry("const")]); + function getInJsKeywords(keywords: ReadonlyArray): ReadonlyArray { return keywords.filter(keyword => { switch (keyword.name) { @@ -4811,40 +4827,23 @@ namespace FourSlashInterface { "interface", "let", "package", - "private", - "protected", - "public", - "static", "yield", - "abstract", - "as", "any", "async", "await", "boolean", - "constructor", "declare", - "get", - "infer", - "is", "keyof", "module", - "namespace", "never", "readonly", - "require", "number", "object", - "set", "string", "symbol", - "type", "unique", "unknown", - "from", - "global", "bigint", - "of", ].map(keywordEntry); export const statementKeywords: ReadonlyArray = statementKeywordsWithTypes.filter(k => { @@ -5025,40 +5024,23 @@ namespace FourSlashInterface { "interface", "let", "package", - "private", - "protected", - "public", - "static", "yield", - "abstract", - "as", "any", "async", "await", "boolean", - "constructor", "declare", - "get", - "infer", - "is", "keyof", "module", - "namespace", "never", "readonly", - "require", "number", "object", - "set", "string", "symbol", - "type", "unique", "unknown", - "from", - "global", "bigint", - "of", ].map(keywordEntry); export const globalInJsKeywords = getInJsKeywords(globalKeywords); @@ -5111,11 +5093,6 @@ namespace FourSlashInterface { export const insideMethodInJsKeywords = getInJsKeywords(insideMethodKeywords); - export const globalKeywordsPlusUndefined: ReadonlyArray = (() => { - const i = ts.findIndex(globalKeywords, x => x.name === "unique"); - return [...globalKeywords.slice(0, i), keywordEntry("undefined"), ...globalKeywords.slice(i)]; - })(); - export const globals: ReadonlyArray = [ globalThisEntry, ...globalsVars, diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts index 23127f49aad..14813278351 100644 --- a/src/harness/virtualFileSystemWithWatch.ts +++ b/src/harness/virtualFileSystemWithWatch.ts @@ -30,7 +30,7 @@ interface Array {}` return combinePaths(getDirectoryPath(libFile.path), "tsc.js"); } - interface TestServerHostCreationParameters { + export interface TestServerHostCreationParameters { useCaseSensitiveFileNames?: boolean; executingFilePath?: string; currentDirectory?: string; diff --git a/src/jsTyping/jsTyping.ts b/src/jsTyping/jsTyping.ts index c2b2ad3f5b3..172d041cc01 100644 --- a/src/jsTyping/jsTyping.ts +++ b/src/jsTyping/jsTyping.ts @@ -289,9 +289,8 @@ namespace ts.JsTyping { } - export const enum PackageNameValidationResult { + export const enum NameValidationResult { Ok, - ScopedPackagesNotSupported, EmptyName, NameTooLong, NameStartsWithDot, @@ -301,49 +300,77 @@ namespace ts.JsTyping { const maxPackageNameLength = 214; + export interface ScopedPackageNameValidationResult { + name: string; + isScopeName: boolean; + result: NameValidationResult; + } + export type PackageNameValidationResult = NameValidationResult | ScopedPackageNameValidationResult; + /** * Validates package name using rules defined at https://docs.npmjs.com/files/package.json */ export function validatePackageName(packageName: string): PackageNameValidationResult { + return validatePackageNameWorker(packageName, /*supportScopedPackage*/ true); + } + + function validatePackageNameWorker(packageName: string, supportScopedPackage: false): NameValidationResult; + function validatePackageNameWorker(packageName: string, supportScopedPackage: true): PackageNameValidationResult; + function validatePackageNameWorker(packageName: string, supportScopedPackage: boolean): PackageNameValidationResult { if (!packageName) { - return PackageNameValidationResult.EmptyName; + return NameValidationResult.EmptyName; } if (packageName.length > maxPackageNameLength) { - return PackageNameValidationResult.NameTooLong; + return NameValidationResult.NameTooLong; } if (packageName.charCodeAt(0) === CharacterCodes.dot) { - return PackageNameValidationResult.NameStartsWithDot; + return NameValidationResult.NameStartsWithDot; } if (packageName.charCodeAt(0) === CharacterCodes._) { - return PackageNameValidationResult.NameStartsWithUnderscore; + return NameValidationResult.NameStartsWithUnderscore; } // check if name is scope package like: starts with @ and has one '/' in the middle // scoped packages are not currently supported - // TODO: when support will be added we'll need to split and check both scope and package name - if (/^@[^/]+\/[^/]+$/.test(packageName)) { - return PackageNameValidationResult.ScopedPackagesNotSupported; + if (supportScopedPackage) { + const matches = /^@([^/]+)\/([^/]+)$/.exec(packageName); + if (matches) { + const scopeResult = validatePackageNameWorker(matches[1], /*supportScopedPackage*/ false); + if (scopeResult !== NameValidationResult.Ok) { + return { name: matches[1], isScopeName: true, result: scopeResult }; + } + const packageResult = validatePackageNameWorker(matches[2], /*supportScopedPackage*/ false); + if (packageResult !== NameValidationResult.Ok) { + return { name: matches[2], isScopeName: false, result: packageResult }; + } + return NameValidationResult.Ok; + } } if (encodeURIComponent(packageName) !== packageName) { - return PackageNameValidationResult.NameContainsNonURISafeCharacters; + return NameValidationResult.NameContainsNonURISafeCharacters; } - return PackageNameValidationResult.Ok; + return NameValidationResult.Ok; } export function renderPackageNameValidationFailure(result: PackageNameValidationResult, typing: string): string { + return typeof result === "object" ? + renderPackageNameValidationFailureWorker(typing, result.result, result.name, result.isScopeName) : + renderPackageNameValidationFailureWorker(typing, result, typing, /*isScopeName*/ false); + } + + function renderPackageNameValidationFailureWorker(typing: string, result: NameValidationResult, name: string, isScopeName: boolean): string { + const kind = isScopeName ? "Scope" : "Package"; switch (result) { - case PackageNameValidationResult.EmptyName: - return `Package name '${typing}' cannot be empty`; - case PackageNameValidationResult.NameTooLong: - return `Package name '${typing}' should be less than ${maxPackageNameLength} characters`; - case PackageNameValidationResult.NameStartsWithDot: - return `Package name '${typing}' cannot start with '.'`; - case PackageNameValidationResult.NameStartsWithUnderscore: - return `Package name '${typing}' cannot start with '_'`; - case PackageNameValidationResult.ScopedPackagesNotSupported: - return `Package '${typing}' is scoped and currently is not supported`; - case PackageNameValidationResult.NameContainsNonURISafeCharacters: - return `Package name '${typing}' contains non URI safe characters`; - case PackageNameValidationResult.Ok: + case NameValidationResult.EmptyName: + return `'${typing}':: ${kind} name '${name}' cannot be empty`; + case NameValidationResult.NameTooLong: + return `'${typing}':: ${kind} name '${name}' should be less than ${maxPackageNameLength} characters`; + case NameValidationResult.NameStartsWithDot: + return `'${typing}':: ${kind} name '${name}' cannot start with '.'`; + case NameValidationResult.NameStartsWithUnderscore: + return `'${typing}':: ${kind} name '${name}' cannot start with '_'`; + case NameValidationResult.NameContainsNonURISafeCharacters: + return `'${typing}':: ${kind} name '${name}' contains non URI safe characters`; + case NameValidationResult.Ok: return Debug.fail(); // Shouldn't have called this. default: throw Debug.assertNever(result); diff --git a/src/lib/dom.generated.d.ts b/src/lib/dom.generated.d.ts index e284ae377c9..e29445f74fe 100644 --- a/src/lib/dom.generated.d.ts +++ b/src/lib/dom.generated.d.ts @@ -4450,53 +4450,53 @@ interface DocumentEventMap extends GlobalEventHandlersEventMap, DocumentAndEleme /** Any web page loaded in the browser and serves as an entry point into the web page's content, which is the DOM tree. */ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, ParentNode, XPathEvaluatorBase, GlobalEventHandlers, DocumentAndElementEventHandlers { - /** - * Sets or gets the URL for the current document. + /** + * Sets or gets the URL for the current document. */ readonly URL: string; - /** - * Gets the object that has the focus when the parent document has focus. + /** + * Gets the object that has the focus when the parent document has focus. */ readonly activeElement: Element | null; - /** - * Sets or gets the color of all active links in the document. + /** + * Sets or gets the color of all active links in the document. */ /** @deprecated */ alinkColor: string; - /** - * Returns a reference to the collection of elements contained by the object. + /** + * Returns a reference to the collection of elements contained by the object. */ /** @deprecated */ readonly all: HTMLAllCollection; - /** - * Retrieves a collection of all a objects that have a name and/or id property. Objects in this collection are in HTML source order. + /** + * Retrieves a collection of all a objects that have a name and/or id property. Objects in this collection are in HTML source order. */ /** @deprecated */ readonly anchors: HTMLCollectionOf; - /** - * Retrieves a collection of all applet objects in the document. + /** + * Retrieves a collection of all applet objects in the document. */ /** @deprecated */ readonly applets: HTMLCollectionOf; - /** - * Deprecated. Sets or retrieves a value that indicates the background color behind the object. + /** + * Deprecated. Sets or retrieves a value that indicates the background color behind the object. */ /** @deprecated */ bgColor: string; - /** - * Specifies the beginning and end of the document body. + /** + * Specifies the beginning and end of the document body. */ body: HTMLElement; /** * Returns document's encoding. */ readonly characterSet: string; - /** - * Gets or sets the character set used to encode the object. + /** + * Gets or sets the character set used to encode the object. */ readonly charset: string; - /** - * Gets a value that indicates whether standards-compliant mode is switched on for the object. + /** + * Gets a value that indicates whether standards-compliant mode is switched on for the object. */ readonly compatMode: string; /** @@ -4518,41 +4518,41 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par */ readonly currentScript: HTMLOrSVGScriptElement | null; readonly defaultView: WindowProxy | null; - /** - * Sets or gets a value that indicates whether the document can be edited. + /** + * Sets or gets a value that indicates whether the document can be edited. */ designMode: string; - /** - * Sets or retrieves a value that indicates the reading order of the object. + /** + * Sets or retrieves a value that indicates the reading order of the object. */ dir: string; - /** - * Gets an object representing the document type declaration associated with the current document. + /** + * Gets an object representing the document type declaration associated with the current document. */ readonly doctype: DocumentType | null; - /** - * Gets a reference to the root node of the document. + /** + * Gets a reference to the root node of the document. */ readonly documentElement: HTMLElement; /** * Returns document's URL. */ readonly documentURI: string; - /** - * Sets or gets the security domain of the document. + /** + * Sets or gets the security domain of the document. */ domain: string; - /** - * Retrieves a collection of all embed objects in the document. + /** + * Retrieves a collection of all embed objects in the document. */ readonly embeds: HTMLCollectionOf; - /** - * Sets or gets the foreground (text) color of the document. + /** + * Sets or gets the foreground (text) color of the document. */ /** @deprecated */ fgColor: string; - /** - * Retrieves a collection, in source order, of all form objects in the document. + /** + * Retrieves a collection, in source order, of all form objects in the document. */ readonly forms: HTMLCollectionOf; /** @deprecated */ @@ -4566,42 +4566,42 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par */ readonly head: HTMLHeadElement; readonly hidden: boolean; - /** - * Retrieves a collection, in source order, of img objects in the document. + /** + * Retrieves a collection, in source order, of img objects in the document. */ readonly images: HTMLCollectionOf; - /** - * Gets the implementation object of the current document. + /** + * Gets the implementation object of the current document. */ readonly implementation: DOMImplementation; - /** - * Returns the character encoding used to create the webpage that is loaded into the document object. + /** + * Returns the character encoding used to create the webpage that is loaded into the document object. */ readonly inputEncoding: string; - /** - * Gets the date that the page was last modified, if the page supplies one. + /** + * Gets the date that the page was last modified, if the page supplies one. */ readonly lastModified: string; - /** - * Sets or gets the color of the document links. + /** + * Sets or gets the color of the document links. */ /** @deprecated */ linkColor: string; - /** - * Retrieves a collection of all a objects that specify the href property and all area objects in the document. + /** + * Retrieves a collection of all a objects that specify the href property and all area objects in the document. */ readonly links: HTMLCollectionOf; - /** - * Contains information about the current URL. + /** + * Contains information about the current URL. */ location: Location; onfullscreenchange: ((this: Document, ev: Event) => any) | null; onfullscreenerror: ((this: Document, ev: Event) => any) | null; onpointerlockchange: ((this: Document, ev: Event) => any) | null; onpointerlockerror: ((this: Document, ev: Event) => any) | null; - /** - * Fires when the state of the object has changed. - * @param ev The event + /** + * Fires when the state of the object has changed. + * @param ev The event */ onreadystatechange: ((this: Document, ev: ProgressEvent) => any) | null; onvisibilitychange: ((this: Document, ev: Event) => any) | null; @@ -4613,27 +4613,27 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par * Return an HTMLCollection of the embed elements in the Document. */ readonly plugins: HTMLCollectionOf; - /** - * Retrieves a value that indicates the current state of the object. + /** + * Retrieves a value that indicates the current state of the object. */ readonly readyState: DocumentReadyState; - /** - * Gets the URL of the location that referred the user to the current page. + /** + * Gets the URL of the location that referred the user to the current page. */ readonly referrer: string; - /** - * Retrieves a collection of all script objects in the document. + /** + * Retrieves a collection of all script objects in the document. */ readonly scripts: HTMLCollectionOf; readonly scrollingElement: Element | null; readonly timeline: DocumentTimeline; - /** - * Contains the title of the document. + /** + * Contains the title of the document. */ title: string; readonly visibilityState: VisibilityState; - /** - * Sets or gets the color of the links that the user has visited. + /** + * Sets or gets the color of the links that the user has visited. */ /** @deprecated */ vlinkColor: string; @@ -4650,13 +4650,13 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par caretRangeFromPoint(x: number, y: number): Range; /** @deprecated */ clear(): void; - /** - * Closes an output stream and forces the sent data to display. + /** + * Closes an output stream and forces the sent data to display. */ close(): void; - /** - * Creates an attribute object with a specified name. - * @param name String that sets the attribute object's name. + /** + * Creates an attribute object with a specified name. + * @param name String that sets the attribute object's name. */ createAttribute(localName: string): Attr; createAttributeNS(namespace: string | null, qualifiedName: string): Attr; @@ -4664,18 +4664,18 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par * Returns a CDATASection node whose data is data. */ createCDATASection(data: string): CDATASection; - /** - * Creates a comment object with the specified data. - * @param data Sets the comment object's data. + /** + * Creates a comment object with the specified data. + * @param data Sets the comment object's data. */ createComment(data: string): Comment; - /** - * Creates a new document. + /** + * Creates a new document. */ createDocumentFragment(): DocumentFragment; - /** - * Creates an instance of the element for the specified tag. - * @param tagName The name of an element. + /** + * Creates an instance of the element for the specified tag. + * @param tagName The name of an element. */ createElement(tagName: K, options?: ElementCreationOptions): HTMLElementTagNameMap[K]; /** @deprecated */ @@ -4780,49 +4780,49 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par createEvent(eventInterface: "WebGLContextEvent"): WebGLContextEvent; createEvent(eventInterface: "WheelEvent"): WheelEvent; createEvent(eventInterface: string): Event; - /** - * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. - * @param root The root element or node to start traversing on. - * @param whatToShow The type of nodes or elements to appear in the node list - * @param filter A custom NodeFilter function to use. For more information, see filter. Use null for no filter. - * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. + /** + * Creates a NodeIterator object that you can use to traverse filtered lists of nodes or elements in a document. + * @param root The root element or node to start traversing on. + * @param whatToShow The type of nodes or elements to appear in the node list + * @param filter A custom NodeFilter function to use. For more information, see filter. Use null for no filter. + * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. */ createNodeIterator(root: Node, whatToShow?: number, filter?: NodeFilter | null): NodeIterator; /** * Returns a ProcessingInstruction node whose target is target and data is data. If target does not match the Name production an "InvalidCharacterError" DOMException will be thrown. If data contains "?>" an "InvalidCharacterError" DOMException will be thrown. */ createProcessingInstruction(target: string, data: string): ProcessingInstruction; - /** - * Returns an empty range object that has both of its boundary points positioned at the beginning of the document. + /** + * Returns an empty range object that has both of its boundary points positioned at the beginning of the document. */ createRange(): Range; - /** - * Creates a text string from the specified value. - * @param data String that specifies the nodeValue property of the text node. + /** + * Creates a text string from the specified value. + * @param data String that specifies the nodeValue property of the text node. */ createTextNode(data: string): Text; - /** - * Creates a TreeWalker object that you can use to traverse filtered lists of nodes or elements in a document. - * @param root The root element or node to start traversing on. - * @param whatToShow The type of nodes or elements to appear in the node list. For more information, see whatToShow. - * @param filter A custom NodeFilter function to use. - * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. + /** + * Creates a TreeWalker object that you can use to traverse filtered lists of nodes or elements in a document. + * @param root The root element or node to start traversing on. + * @param whatToShow The type of nodes or elements to appear in the node list. For more information, see whatToShow. + * @param filter A custom NodeFilter function to use. + * @param entityReferenceExpansion A flag that specifies whether entity reference nodes are expanded. */ createTreeWalker(root: Node, whatToShow?: number, filter?: NodeFilter | null): TreeWalker; /** @deprecated */ createTreeWalker(root: Node, whatToShow: number, filter: NodeFilter | null, entityReferenceExpansion?: boolean): TreeWalker; - /** - * Returns the element for the specified x coordinate and the specified y coordinate. - * @param x The x-offset - * @param y The y-offset + /** + * Returns the element for the specified x coordinate and the specified y coordinate. + * @param x The x-offset + * @param y The y-offset */ elementFromPoint(x: number, y: number): Element | null; elementsFromPoint(x: number, y: number): Element[]; - /** - * Executes a command on the current document, current selection, or the given range. - * @param commandId String that specifies the command to execute. This command can be any of the command identifiers that can be executed in script. - * @param showUI Display the user interface, defaults to false. - * @param value Value to assign. + /** + * Executes a command on the current document, current selection, or the given range. + * @param commandId String that specifies the command to execute. This command can be any of the command identifiers that can be executed in script. + * @param showUI Display the user interface, defaults to false. + * @param value Value to assign. */ execCommand(commandId: string, showUI?: boolean, value?: string): boolean; /** @@ -4831,23 +4831,23 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par exitFullscreen(): Promise; exitPointerLock(): void; getAnimations(): Animation[]; - /** - * Returns a reference to the first object with the specified value of the ID or NAME attribute. - * @param elementId String that specifies the ID value. Case-insensitive. + /** + * Returns a reference to the first object with the specified value of the ID or NAME attribute. + * @param elementId String that specifies the ID value. Case-insensitive. */ getElementById(elementId: string): HTMLElement | null; /** * Returns a HTMLCollection of the elements in the object on which the method was invoked (a document or an element) that have all the classes given by classNames. The classNames argument is interpreted as a space-separated list of classes. */ getElementsByClassName(classNames: string): HTMLCollectionOf; - /** - * Gets a collection of objects based on the value of the NAME or ID attribute. - * @param elementName Gets a collection of objects based on the value of the NAME or ID attribute. + /** + * Gets a collection of objects based on the value of the NAME or ID attribute. + * @param elementName Gets a collection of objects based on the value of the NAME or ID attribute. */ getElementsByName(elementName: string): NodeListOf; - /** - * Retrieves a collection of objects based on the specified element name. - * @param name Specifies the name of an element. + /** + * Retrieves a collection of objects based on the specified element name. + * @param name Specifies the name of an element. */ getElementsByTagName(qualifiedName: K): HTMLCollectionOf; getElementsByTagName(qualifiedName: K): HTMLCollectionOf; @@ -4864,12 +4864,12 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par getElementsByTagNameNS(namespaceURI: "http://www.w3.org/1999/xhtml", localName: string): HTMLCollectionOf; getElementsByTagNameNS(namespaceURI: "http://www.w3.org/2000/svg", localName: string): HTMLCollectionOf; getElementsByTagNameNS(namespaceURI: string, localName: string): HTMLCollectionOf; - /** - * Returns an object representing the current selection of the document that is loaded into the object displaying a webpage. + /** + * Returns an object representing the current selection of the document that is loaded into the object displaying a webpage. */ getSelection(): Selection | null; - /** - * Gets a value indicating whether the object currently has focus. + /** + * Gets a value indicating whether the object currently has focus. */ hasFocus(): boolean; /** @@ -4878,49 +4878,49 @@ interface Document extends Node, NonElementParentNode, DocumentOrShadowRoot, Par * If node is a document or a shadow root, throws a "NotSupportedError" DOMException. */ importNode(importedNode: T, deep: boolean): T; - /** - * Opens a new window and loads a document specified by a given URL. Also, opens a new window that uses the url parameter and the name parameter to collect the output of the write method and the writeln method. - * @param url Specifies a MIME type for the document. - * @param name Specifies the name of the window. This name is used as the value for the TARGET attribute on a form or an anchor element. - * @param features Contains a list of items separated by commas. Each item consists of an option and a value, separated by an equals sign (for example, "fullscreen=yes, toolbar=yes"). The following values are supported. - * @param replace Specifies whether the existing entry for the document is replaced in the history list. + /** + * Opens a new window and loads a document specified by a given URL. Also, opens a new window that uses the url parameter and the name parameter to collect the output of the write method and the writeln method. + * @param url Specifies a MIME type for the document. + * @param name Specifies the name of the window. This name is used as the value for the TARGET attribute on a form or an anchor element. + * @param features Contains a list of items separated by commas. Each item consists of an option and a value, separated by an equals sign (for example, "fullscreen=yes, toolbar=yes"). The following values are supported. + * @param replace Specifies whether the existing entry for the document is replaced in the history list. */ open(url?: string, name?: string, features?: string, replace?: boolean): Document; - /** - * Returns a Boolean value that indicates whether a specified command can be successfully executed using execCommand, given the current state of the document. - * @param commandId Specifies a command identifier. + /** + * Returns a Boolean value that indicates whether a specified command can be successfully executed using execCommand, given the current state of the document. + * @param commandId Specifies a command identifier. */ queryCommandEnabled(commandId: string): boolean; - /** - * Returns a Boolean value that indicates whether the specified command is in the indeterminate state. - * @param commandId String that specifies a command identifier. + /** + * Returns a Boolean value that indicates whether the specified command is in the indeterminate state. + * @param commandId String that specifies a command identifier. */ queryCommandIndeterm(commandId: string): boolean; - /** - * Returns a Boolean value that indicates the current state of the command. - * @param commandId String that specifies a command identifier. + /** + * Returns a Boolean value that indicates the current state of the command. + * @param commandId String that specifies a command identifier. */ queryCommandState(commandId: string): boolean; - /** - * Returns a Boolean value that indicates whether the current command is supported on the current range. - * @param commandId Specifies a command identifier. + /** + * Returns a Boolean value that indicates whether the current command is supported on the current range. + * @param commandId Specifies a command identifier. */ queryCommandSupported(commandId: string): boolean; - /** - * Returns the current value of the document, range, or current selection for the given command. - * @param commandId String that specifies a command identifier. + /** + * Returns the current value of the document, range, or current selection for the given command. + * @param commandId String that specifies a command identifier. */ queryCommandValue(commandId: string): string; /** @deprecated */ releaseEvents(): void; - /** - * Writes one or more HTML expressions to a document in the specified window. - * @param content Specifies the text and HTML tags to write. + /** + * Writes one or more HTML expressions to a document in the specified window. + * @param content Specifies the text and HTML tags to write. */ write(...text: string[]): void; - /** - * Writes one or more HTML expressions, followed by a carriage return, to a document in the specified window. - * @param content The text and HTML tags to write. + /** + * Writes one or more HTML expressions, followed by a carriage return, to a document in the specified window. + * @param content The text and HTML tags to write. */ writeln(...text: string[]): void; addEventListener(type: K, listener: (this: Document, ev: DocumentEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; @@ -5049,8 +5049,8 @@ interface DocumentOrShadowRoot { */ readonly fullscreenElement: Element | null; readonly pointerLockElement: Element | null; - /** - * Retrieves a collection of styleSheet objects representing the style sheets that correspond to each instance of a link or style object in the document. + /** + * Retrieves a collection of styleSheet objects representing the style sheets that correspond to each instance of a link or style object in the document. */ readonly styleSheets: StyleSheetList; caretPositionFromPoint(x: number, y: number): CaretPosition | null; @@ -5814,9 +5814,9 @@ interface GlobalEventHandlersEventMap { } interface GlobalEventHandlers { - /** - * Fires when the user aborts the download. - * @param ev The event. + /** + * Fires when the user aborts the download. + * @param ev The event. */ onabort: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null; onanimationcancel: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null; @@ -5824,177 +5824,177 @@ interface GlobalEventHandlers { onanimationiteration: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null; onanimationstart: ((this: GlobalEventHandlers, ev: AnimationEvent) => any) | null; onauxclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires when the object loses the input focus. - * @param ev The focus event. + /** + * Fires when the object loses the input focus. + * @param ev The focus event. */ onblur: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null; oncancel: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when playback is possible, but would require further buffering. - * @param ev The event. + /** + * Occurs when playback is possible, but would require further buffering. + * @param ev The event. */ oncanplay: ((this: GlobalEventHandlers, ev: Event) => any) | null; oncanplaythrough: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the contents of the object or selection have changed. - * @param ev The event. + /** + * Fires when the contents of the object or selection have changed. + * @param ev The event. */ onchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the user clicks the left mouse button on the object - * @param ev The mouse event. + /** + * Fires when the user clicks the left mouse button on the object + * @param ev The mouse event. */ onclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; onclose: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the user clicks the right mouse button in the client area, opening the context menu. - * @param ev The mouse event. + /** + * Fires when the user clicks the right mouse button in the client area, opening the context menu. + * @param ev The mouse event. */ oncontextmenu: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; oncuechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the user double-clicks the object. - * @param ev The mouse event. + /** + * Fires when the user double-clicks the object. + * @param ev The mouse event. */ ondblclick: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires on the source object continuously during a drag operation. - * @param ev The event. + /** + * Fires on the source object continuously during a drag operation. + * @param ev The event. */ ondrag: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; - /** - * Fires on the source object when the user releases the mouse at the close of a drag operation. - * @param ev The event. + /** + * Fires on the source object when the user releases the mouse at the close of a drag operation. + * @param ev The event. */ ondragend: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; - /** - * Fires on the target element when the user drags the object to a valid drop target. - * @param ev The drag event. + /** + * Fires on the target element when the user drags the object to a valid drop target. + * @param ev The drag event. */ ondragenter: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; ondragexit: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires on the target object when the user moves the mouse out of a valid drop target during a drag operation. - * @param ev The drag event. + /** + * Fires on the target object when the user moves the mouse out of a valid drop target during a drag operation. + * @param ev The drag event. */ ondragleave: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; - /** - * Fires on the target element continuously while the user drags the object over a valid drop target. - * @param ev The event. + /** + * Fires on the target element continuously while the user drags the object over a valid drop target. + * @param ev The event. */ ondragover: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; - /** - * Fires on the source object when the user starts to drag a text selection or selected object. - * @param ev The event. + /** + * Fires on the source object when the user starts to drag a text selection or selected object. + * @param ev The event. */ ondragstart: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; ondrop: ((this: GlobalEventHandlers, ev: DragEvent) => any) | null; - /** - * Occurs when the duration attribute is updated. - * @param ev The event. + /** + * Occurs when the duration attribute is updated. + * @param ev The event. */ ondurationchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the media element is reset to its initial state. - * @param ev The event. + /** + * Occurs when the media element is reset to its initial state. + * @param ev The event. */ onemptied: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the end of playback is reached. - * @param ev The event + /** + * Occurs when the end of playback is reached. + * @param ev The event */ onended: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when an error occurs during object loading. - * @param ev The event. + /** + * Fires when an error occurs during object loading. + * @param ev The event. */ onerror: OnErrorEventHandler; - /** - * Fires when the object receives focus. - * @param ev The event. + /** + * Fires when the object receives focus. + * @param ev The event. */ onfocus: ((this: GlobalEventHandlers, ev: FocusEvent) => any) | null; ongotpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; oninput: ((this: GlobalEventHandlers, ev: Event) => any) | null; oninvalid: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the user presses a key. - * @param ev The keyboard event + /** + * Fires when the user presses a key. + * @param ev The keyboard event */ onkeydown: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; - /** - * Fires when the user presses an alphanumeric key. - * @param ev The event. + /** + * Fires when the user presses an alphanumeric key. + * @param ev The event. */ onkeypress: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; - /** - * Fires when the user releases a key. - * @param ev The keyboard event + /** + * Fires when the user releases a key. + * @param ev The keyboard event */ onkeyup: ((this: GlobalEventHandlers, ev: KeyboardEvent) => any) | null; - /** - * Fires immediately after the browser loads the object. - * @param ev The event. + /** + * Fires immediately after the browser loads the object. + * @param ev The event. */ onload: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when media data is loaded at the current playback position. - * @param ev The event. + /** + * Occurs when media data is loaded at the current playback position. + * @param ev The event. */ onloadeddata: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the duration and dimensions of the media have been determined. - * @param ev The event. + /** + * Occurs when the duration and dimensions of the media have been determined. + * @param ev The event. */ onloadedmetadata: ((this: GlobalEventHandlers, ev: Event) => any) | null; onloadend: ((this: GlobalEventHandlers, ev: ProgressEvent) => any) | null; - /** - * Occurs when Internet Explorer begins looking for media data. - * @param ev The event. + /** + * Occurs when Internet Explorer begins looking for media data. + * @param ev The event. */ onloadstart: ((this: GlobalEventHandlers, ev: Event) => any) | null; onlostpointercapture: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; - /** - * Fires when the user clicks the object with either mouse button. - * @param ev The mouse event. + /** + * Fires when the user clicks the object with either mouse button. + * @param ev The mouse event. */ onmousedown: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; onmouseenter: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; onmouseleave: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires when the user moves the mouse over the object. - * @param ev The mouse event. + /** + * Fires when the user moves the mouse over the object. + * @param ev The mouse event. */ onmousemove: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires when the user moves the mouse pointer outside the boundaries of the object. - * @param ev The mouse event. + /** + * Fires when the user moves the mouse pointer outside the boundaries of the object. + * @param ev The mouse event. */ onmouseout: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires when the user moves the mouse pointer into the object. - * @param ev The mouse event. + /** + * Fires when the user moves the mouse pointer into the object. + * @param ev The mouse event. */ onmouseover: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Fires when the user releases a mouse button while the mouse is over the object. - * @param ev The mouse event. + /** + * Fires when the user releases a mouse button while the mouse is over the object. + * @param ev The mouse event. */ onmouseup: ((this: GlobalEventHandlers, ev: MouseEvent) => any) | null; - /** - * Occurs when playback is paused. - * @param ev The event. + /** + * Occurs when playback is paused. + * @param ev The event. */ onpause: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the play method is requested. - * @param ev The event. + /** + * Occurs when the play method is requested. + * @param ev The event. */ onplay: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the audio or video has started playing. - * @param ev The event. + /** + * Occurs when the audio or video has started playing. + * @param ev The event. */ onplaying: ((this: GlobalEventHandlers, ev: Event) => any) | null; onpointercancel: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; @@ -6005,59 +6005,59 @@ interface GlobalEventHandlers { onpointerout: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; onpointerover: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; onpointerup: ((this: GlobalEventHandlers, ev: PointerEvent) => any) | null; - /** - * Occurs to indicate progress while downloading media data. - * @param ev The event. + /** + * Occurs to indicate progress while downloading media data. + * @param ev The event. */ onprogress: ((this: GlobalEventHandlers, ev: ProgressEvent) => any) | null; - /** - * Occurs when the playback rate is increased or decreased. - * @param ev The event. + /** + * Occurs when the playback rate is increased or decreased. + * @param ev The event. */ onratechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the user resets a form. - * @param ev The event. + /** + * Fires when the user resets a form. + * @param ev The event. */ onreset: ((this: GlobalEventHandlers, ev: Event) => any) | null; onresize: ((this: GlobalEventHandlers, ev: UIEvent) => any) | null; - /** - * Fires when the user repositions the scroll box in the scroll bar on the object. - * @param ev The event. + /** + * Fires when the user repositions the scroll box in the scroll bar on the object. + * @param ev The event. */ onscroll: ((this: GlobalEventHandlers, ev: Event) => any) | null; onsecuritypolicyviolation: ((this: GlobalEventHandlers, ev: SecurityPolicyViolationEvent) => any) | null; - /** - * Occurs when the seek operation ends. - * @param ev The event. + /** + * Occurs when the seek operation ends. + * @param ev The event. */ onseeked: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the current playback position is moved. - * @param ev The event. + /** + * Occurs when the current playback position is moved. + * @param ev The event. */ onseeking: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Fires when the current selection changes. - * @param ev The event. + /** + * Fires when the current selection changes. + * @param ev The event. */ onselect: ((this: GlobalEventHandlers, ev: Event) => any) | null; onselectionchange: ((this: GlobalEventHandlers, ev: Event) => any) | null; onselectstart: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when the download has stopped. - * @param ev The event. + /** + * Occurs when the download has stopped. + * @param ev The event. */ onstalled: ((this: GlobalEventHandlers, ev: Event) => any) | null; onsubmit: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs if the load operation has been intentionally halted. - * @param ev The event. + /** + * Occurs if the load operation has been intentionally halted. + * @param ev The event. */ onsuspend: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs to indicate the current playback position. - * @param ev The event. + /** + * Occurs to indicate the current playback position. + * @param ev The event. */ ontimeupdate: ((this: GlobalEventHandlers, ev: Event) => any) | null; ontoggle: ((this: GlobalEventHandlers, ev: Event) => any) | null; @@ -6069,14 +6069,14 @@ interface GlobalEventHandlers { ontransitionend: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null; ontransitionrun: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null; ontransitionstart: ((this: GlobalEventHandlers, ev: TransitionEvent) => any) | null; - /** - * Occurs when the volume is changed, or playback is muted or unmuted. - * @param ev The event. + /** + * Occurs when the volume is changed, or playback is muted or unmuted. + * @param ev The event. */ onvolumechange: ((this: GlobalEventHandlers, ev: Event) => any) | null; - /** - * Occurs when playback stops because the next frame of a video resource is not available. - * @param ev The event. + /** + * Occurs when playback stops because the next frame of a video resource is not available. + * @param ev The event. */ onwaiting: ((this: GlobalEventHandlers, ev: Event) => any) | null; onwheel: ((this: GlobalEventHandlers, ev: WheelEvent) => any) | null; @@ -6113,49 +6113,49 @@ declare var HTMLAllCollection: { /** Hyperlink elements and provides special properties and methods (beyond those of the regular HTMLElement object interface that they inherit from) for manipulating the layout and presentation of such elements. */ interface HTMLAnchorElement extends HTMLElement, HTMLHyperlinkElementUtils { - /** - * Sets or retrieves the character set used to encode the object. + /** + * Sets or retrieves the character set used to encode the object. */ /** @deprecated */ charset: string; - /** - * Sets or retrieves the coordinates of the object. + /** + * Sets or retrieves the coordinates of the object. */ /** @deprecated */ coords: string; download: string; - /** - * Sets or retrieves the language code of the object. + /** + * Sets or retrieves the language code of the object. */ hreflang: string; - /** - * Sets or retrieves the shape of the object. + /** + * Sets or retrieves the shape of the object. */ /** @deprecated */ name: string; ping: string; referrerPolicy: string; - /** - * Sets or retrieves the relationship between the object and the destination of the link. + /** + * Sets or retrieves the relationship between the object and the destination of the link. */ rel: string; readonly relList: DOMTokenList; - /** - * Sets or retrieves the relationship between the object and the destination of the link. + /** + * Sets or retrieves the relationship between the object and the destination of the link. */ /** @deprecated */ rev: string; - /** - * Sets or retrieves the shape of the object. + /** + * Sets or retrieves the shape of the object. */ /** @deprecated */ shape: string; - /** - * Sets or retrieves the window or frame at which to target content. + /** + * Sets or retrieves the window or frame at which to target content. */ target: string; - /** - * Retrieves or sets the text of the object as a string. + /** + * Retrieves or sets the text of the object as a string. */ text: string; type: string; @@ -6173,33 +6173,33 @@ declare var HTMLAnchorElement: { interface HTMLAppletElement extends HTMLElement { /** @deprecated */ align: string; - /** - * Sets or retrieves a text alternative to the graphic. + /** + * Sets or retrieves a text alternative to the graphic. */ /** @deprecated */ alt: string; - /** - * Sets or retrieves a character string that can be used to implement your own archive functionality for the object. + /** + * Sets or retrieves a character string that can be used to implement your own archive functionality for the object. */ /** @deprecated */ archive: string; /** @deprecated */ code: string; - /** - * Sets or retrieves the URL of the component. + /** + * Sets or retrieves the URL of the component. */ /** @deprecated */ codeBase: string; readonly form: HTMLFormElement | null; - /** - * Sets or retrieves the height of the object. + /** + * Sets or retrieves the height of the object. */ /** @deprecated */ height: string; /** @deprecated */ hspace: number; - /** - * Sets or retrieves the shape of the object. + /** + * Sets or retrieves the shape of the object. */ /** @deprecated */ name: string; @@ -6222,17 +6222,17 @@ declare var HTMLAppletElement: { /** Provides special properties and methods (beyond those of the regular object HTMLElement interface it also has available to it by inheritance) for manipulating the layout and presentation of elements. */ interface HTMLAreaElement extends HTMLElement, HTMLHyperlinkElementUtils { - /** - * Sets or retrieves a text alternative to the graphic. + /** + * Sets or retrieves a text alternative to the graphic. */ alt: string; - /** - * Sets or retrieves the coordinates of the object. + /** + * Sets or retrieves the coordinates of the object. */ coords: string; download: string; - /** - * Sets or gets whether clicks in this region cause action. + /** + * Sets or gets whether clicks in this region cause action. */ /** @deprecated */ noHref: boolean; @@ -6240,12 +6240,12 @@ interface HTMLAreaElement extends HTMLElement, HTMLHyperlinkElementUtils { referrerPolicy: string; rel: string; readonly relList: DOMTokenList; - /** - * Sets or retrieves the shape of the object. + /** + * Sets or retrieves the shape of the object. */ shape: string; - /** - * Sets or retrieves the window or frame at which to target content. + /** + * Sets or retrieves the window or frame at which to target content. */ target: string; addEventListener(type: K, listener: (this: HTMLAreaElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; @@ -6274,8 +6274,8 @@ declare var HTMLAudioElement: { /** A HTML line break element (
). It inherits from HTMLElement. */ interface HTMLBRElement extends HTMLElement { - /** - * Sets or retrieves the side on which floating objects are not to be positioned when any IHTMLBlockElement is inserted into the document. + /** + * Sets or retrieves the side on which floating objects are not to be positioned when any IHTMLBlockElement is inserted into the document. */ /** @deprecated */ clear: string; @@ -6292,12 +6292,12 @@ declare var HTMLBRElement: { /** Contains the base URI for a document. This object inherits all of the properties and methods as described in the HTMLElement interface. */ interface HTMLBaseElement extends HTMLElement { - /** - * Gets or sets the baseline URL on which relative links are based. + /** + * Gets or sets the baseline URL on which relative links are based. */ href: string; - /** - * Sets or retrieves the window or frame at which to target content. + /** + * Sets or retrieves the window or frame at which to target content. */ target: string; addEventListener(type: K, listener: (this: HTMLBaseElement, ev: HTMLElementEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void; @@ -6313,13 +6313,13 @@ declare var HTMLBaseElement: { /** Provides special properties (beyond the regular HTMLElement interface it also has available to it by inheritance) for manipulating elements. */ interface HTMLBaseFontElement extends HTMLElement, DOML2DeprecatedColorProperty { - /** - * Sets or retrieves the current typeface family. + /** + * Sets or retrieves the current typeface family. */ /** @deprecated */ face: string; - /** - * Sets or retrieves the font size of the object. + /** + * Sets or retrieves the font size of the object. */ /** @deprecated */ size: number; @@ -6370,68 +6370,68 @@ declare var HTMLBodyElement: { /** Provides properties and methods (beyond the regular HTMLElement interface it also has available to it by inheritance) for manipulating