mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into buildWatchCaching
This commit is contained in:
+355
-107
@@ -94,8 +94,6 @@ namespace ts {
|
||||
|
||||
const globalThisSymbol = createSymbol(SymbolFlags.Module, "globalThis" as __String, CheckFlags.Readonly);
|
||||
globalThisSymbol.exports = globals;
|
||||
globalThisSymbol.valueDeclaration = createNode(SyntaxKind.Identifier) as Identifier;
|
||||
(globalThisSymbol.valueDeclaration as Identifier).escapedText = "globalThis" as __String;
|
||||
globals.set(globalThisSymbol.escapedName, globalThisSymbol);
|
||||
|
||||
const argumentsSymbol = createSymbol(SymbolFlags.Property, "arguments" as __String);
|
||||
@@ -500,6 +498,7 @@ namespace ts {
|
||||
* This is only used if there is no exact match.
|
||||
*/
|
||||
let patternAmbientModules: PatternAmbientModule[];
|
||||
let patternAmbientModuleAugmentations: Map<Symbol> | undefined;
|
||||
|
||||
let globalObjectType: ObjectType;
|
||||
let globalFunctionType: ObjectType;
|
||||
@@ -890,7 +889,7 @@ namespace ts {
|
||||
* Note: if target is transient, then it is mutable, and mergeSymbol with both mutate and return it.
|
||||
* If target is not transient, mergeSymbol will produce a transient clone, mutate that and return it.
|
||||
*/
|
||||
function mergeSymbol(target: Symbol, source: Symbol): Symbol {
|
||||
function mergeSymbol(target: Symbol, source: Symbol, unidirectional = false): Symbol {
|
||||
if (!(target.flags & getExcludedSymbolFlags(source.flags)) ||
|
||||
(source.flags | target.flags) & SymbolFlags.Assignment) {
|
||||
Debug.assert(source !== target);
|
||||
@@ -917,16 +916,24 @@ namespace ts {
|
||||
addRange(target.declarations, source.declarations);
|
||||
if (source.members) {
|
||||
if (!target.members) target.members = createSymbolTable();
|
||||
mergeSymbolTable(target.members, source.members);
|
||||
mergeSymbolTable(target.members, source.members, unidirectional);
|
||||
}
|
||||
if (source.exports) {
|
||||
if (!target.exports) target.exports = createSymbolTable();
|
||||
mergeSymbolTable(target.exports, source.exports);
|
||||
mergeSymbolTable(target.exports, source.exports, unidirectional
|
||||
);
|
||||
}
|
||||
if (!unidirectional) {
|
||||
recordMergedSymbol(target, source);
|
||||
}
|
||||
recordMergedSymbol(target, source);
|
||||
}
|
||||
else if (target.flags & SymbolFlags.NamespaceModule) {
|
||||
error(getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target));
|
||||
// Do not report an error when merging `var globalThis` with the built-in `globalThis`,
|
||||
// as we will already report a "Declaration name conflicts..." error, and this error
|
||||
// won't make much sense.
|
||||
if (target !== globalThisSymbol) {
|
||||
error(getNameOfDeclaration(source.declarations[0]), Diagnostics.Cannot_augment_module_0_with_value_exports_because_it_resolves_to_a_non_module_entity, symbolToString(target));
|
||||
}
|
||||
}
|
||||
else { // error
|
||||
const isEitherEnum = !!(target.flags & SymbolFlags.Enum || source.flags & SymbolFlags.Enum);
|
||||
@@ -990,10 +997,10 @@ namespace ts {
|
||||
return combined;
|
||||
}
|
||||
|
||||
function mergeSymbolTable(target: SymbolTable, source: SymbolTable) {
|
||||
function mergeSymbolTable(target: SymbolTable, source: SymbolTable, unidirectional = false) {
|
||||
source.forEach((sourceSymbol, id) => {
|
||||
const targetSymbol = target.get(id);
|
||||
target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol) : sourceSymbol);
|
||||
target.set(id, targetSymbol ? mergeSymbol(targetSymbol, sourceSymbol, unidirectional) : sourceSymbol);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1023,7 +1030,22 @@ namespace ts {
|
||||
// obtain item referenced by 'export='
|
||||
mainModule = resolveExternalModuleSymbol(mainModule);
|
||||
if (mainModule.flags & SymbolFlags.Namespace) {
|
||||
mainModule = mergeSymbol(mainModule, moduleAugmentation.symbol);
|
||||
// If we’re merging an augmentation to a pattern ambient module, we want to
|
||||
// perform the merge unidirectionally from the augmentation ('a.foo') to
|
||||
// the pattern ('*.foo'), so that 'getMergedSymbol()' on a.foo gives you
|
||||
// all the exports both from the pattern and from the augmentation, but
|
||||
// 'getMergedSymbol()' on *.foo only gives you exports from *.foo.
|
||||
if (some(patternAmbientModules, module => mainModule === module.symbol)) {
|
||||
const merged = mergeSymbol(moduleAugmentation.symbol, mainModule, /*unidirectional*/ true);
|
||||
if (!patternAmbientModuleAugmentations) {
|
||||
patternAmbientModuleAugmentations = createMap();
|
||||
}
|
||||
// moduleName will be a StringLiteral since this is not `declare global`.
|
||||
patternAmbientModuleAugmentations.set((moduleName as StringLiteral).text, merged);
|
||||
}
|
||||
else {
|
||||
mergeSymbol(mainModule, moduleAugmentation.symbol);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// moduleName will be a StringLiteral since this is not `declare global`.
|
||||
@@ -2452,6 +2474,14 @@ namespace ts {
|
||||
if (patternAmbientModules) {
|
||||
const pattern = findBestPatternMatch(patternAmbientModules, _ => _.pattern, moduleReference);
|
||||
if (pattern) {
|
||||
// If the module reference matched a pattern ambient module ('*.foo') but there’s also a
|
||||
// module augmentation by the specific name requested ('a.foo'), we store the merged symbol
|
||||
// by the augmentation name ('a.foo'), because asking for *.foo should not give you exports
|
||||
// from a.foo.
|
||||
const augmentation = patternAmbientModuleAugmentations && patternAmbientModuleAugmentations.get(moduleReference);
|
||||
if (augmentation) {
|
||||
return getMergedSymbol(augmentation);
|
||||
}
|
||||
return getMergedSymbol(pattern.symbol);
|
||||
}
|
||||
}
|
||||
@@ -8562,7 +8592,7 @@ namespace ts {
|
||||
function getSignatureInstantiation(signature: Signature, typeArguments: Type[] | undefined, isJavascript: boolean, inferredTypeParameters?: ReadonlyArray<TypeParameter>): Signature {
|
||||
const instantiatedSignature = getSignatureInstantiationWithoutFillingInTypeArguments(signature, fillMissingTypeArguments(typeArguments, signature.typeParameters, getMinTypeArgumentCount(signature.typeParameters), isJavascript));
|
||||
if (inferredTypeParameters) {
|
||||
const returnSignature = getSingleCallSignature(getReturnTypeOfSignature(instantiatedSignature));
|
||||
const returnSignature = getSingleCallOrConstructSignature(getReturnTypeOfSignature(instantiatedSignature));
|
||||
if (returnSignature) {
|
||||
const newReturnSignature = cloneSignature(returnSignature);
|
||||
newReturnSignature.typeParameters = inferredTypeParameters;
|
||||
@@ -8638,7 +8668,8 @@ namespace ts {
|
||||
// object type literal or interface (using the new keyword). Each way of declaring a constructor
|
||||
// will result in a different declaration kind.
|
||||
if (!signature.isolatedSignatureType) {
|
||||
const isConstructor = signature.declaration!.kind === SyntaxKind.Constructor || signature.declaration!.kind === SyntaxKind.ConstructSignature; // TODO: GH#18217
|
||||
const kind = signature.declaration ? signature.declaration.kind : SyntaxKind.Unknown;
|
||||
const isConstructor = kind === SyntaxKind.Constructor || kind === SyntaxKind.ConstructSignature || kind === SyntaxKind.ConstructorType;
|
||||
const type = createObjectType(ObjectFlags.Anonymous);
|
||||
type.members = emptySymbols;
|
||||
type.properties = emptyArray;
|
||||
@@ -10080,7 +10111,7 @@ namespace ts {
|
||||
error(indexNode, Diagnostics.Type_0_cannot_be_used_as_an_index_type, typeToString(indexType));
|
||||
return indexInfo.type;
|
||||
}
|
||||
if (indexInfo.isReadonly && (accessFlags & AccessFlags.Writing || accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression)))) {
|
||||
if (indexInfo.isReadonly && accessExpression && (isAssignmentTarget(accessExpression) || isDeleteTarget(accessExpression))) {
|
||||
if (accessExpression) {
|
||||
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(objectType));
|
||||
return indexInfo.type;
|
||||
@@ -10114,7 +10145,13 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
else {
|
||||
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType));
|
||||
const suggestion = getSuggestionForNonexistentIndexSignature(objectType, accessExpression);
|
||||
if (suggestion !== undefined) {
|
||||
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature_Did_you_mean_to_call_1, typeToString(objectType), suggestion);
|
||||
}
|
||||
else {
|
||||
error(accessExpression, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(objectType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10383,11 +10420,11 @@ namespace ts {
|
||||
// We attempt to resolve the conditional type only when the check and extends types are non-generic
|
||||
if (!checkTypeInstantiable && !maybeTypeOfKind(inferredExtendsType, TypeFlags.Instantiable | TypeFlags.GenericMappedType)) {
|
||||
if (inferredExtendsType.flags & TypeFlags.AnyOrUnknown) {
|
||||
return trueType;
|
||||
return combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType;
|
||||
}
|
||||
// Return union of trueType and falseType for 'any' since it matches anything
|
||||
if (checkType.flags & TypeFlags.Any) {
|
||||
return getUnionType([instantiateType(root.trueType, combinedMapper || mapper), falseType]);
|
||||
return getUnionType([combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType, falseType]);
|
||||
}
|
||||
// Return falseType for a definitely false extends check. We check an instantiations of the two
|
||||
// types with type parameters mapped to the wildcard type, the most permissive instantiations
|
||||
@@ -10402,7 +10439,7 @@ namespace ts {
|
||||
// type Foo<T extends { x: any }> = T extends { x: string } ? string : number
|
||||
// doesn't immediately resolve to 'string' instead of being deferred.
|
||||
if (isTypeAssignableTo(getRestrictiveInstantiation(checkType), getRestrictiveInstantiation(inferredExtendsType))) {
|
||||
return instantiateType(root.trueType, combinedMapper || mapper);
|
||||
return combinedMapper ? instantiateType(root.trueType, combinedMapper) : trueType;
|
||||
}
|
||||
}
|
||||
// Return a deferred type for a check that is neither definitely true nor definitely false
|
||||
@@ -12319,6 +12356,15 @@ namespace ts {
|
||||
function reportRelationError(message: DiagnosticMessage | undefined, source: Type, target: Type) {
|
||||
const [sourceType, targetType] = getTypeNamesForErrorDisplay(source, target);
|
||||
|
||||
if (target.flags & TypeFlags.TypeParameter && target.immediateBaseConstraint !== undefined && isTypeAssignableTo(source, target.immediateBaseConstraint)) {
|
||||
reportError(
|
||||
Diagnostics._0_is_assignable_to_the_constraint_of_type_1_but_1_could_be_instantiated_with_a_different_subtype_of_constraint_2,
|
||||
sourceType,
|
||||
targetType,
|
||||
typeToString(target.immediateBaseConstraint),
|
||||
);
|
||||
}
|
||||
|
||||
if (!message) {
|
||||
if (relation === comparableRelation) {
|
||||
message = Diagnostics.Type_0_is_not_comparable_to_type_1;
|
||||
@@ -12482,7 +12528,7 @@ namespace ts {
|
||||
if (result && isPerformingExcessPropertyChecks) {
|
||||
// Validate against excess props using the original `source`
|
||||
const discriminantType = target.flags & TypeFlags.Union ? findMatchingDiscriminantType(source, target as UnionType) : undefined;
|
||||
if (!propertiesRelatedTo(source, discriminantType || target, reportErrors)) {
|
||||
if (!propertiesRelatedTo(source, discriminantType || target, reportErrors, /*excludedProperties*/ undefined)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
@@ -12492,7 +12538,7 @@ namespace ts {
|
||||
result = typeRelatedToEachType(getRegularTypeOfObjectLiteral(source), target as IntersectionType, reportErrors);
|
||||
if (result && isPerformingExcessPropertyChecks) {
|
||||
// Validate against excess props using the original `source`
|
||||
if (!propertiesRelatedTo(source, target, reportErrors)) {
|
||||
if (!propertiesRelatedTo(source, target, reportErrors, /*excludedProperties*/ undefined)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
@@ -13170,7 +13216,7 @@ namespace ts {
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Object) {
|
||||
// Report structural errors only if we haven't reported any errors yet
|
||||
const reportStructuralErrors = reportErrors && errorInfo === saveErrorInfo && !sourceIsPrimitive;
|
||||
result = propertiesRelatedTo(source, target, reportStructuralErrors);
|
||||
result = propertiesRelatedTo(source, target, reportStructuralErrors, /*excludedProperties*/ undefined);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, target, SignatureKind.Call, reportStructuralErrors);
|
||||
if (result) {
|
||||
@@ -13190,6 +13236,19 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// If S is an object type and T is a discriminated union, S may be related to T if
|
||||
// there exists a constituent of T for every combination of the discriminants of S
|
||||
// with respect to T. We do not report errors here, as we will use the existing
|
||||
// error result from checking each constituent of the union.
|
||||
if (source.flags & (TypeFlags.Object | TypeFlags.Intersection) && target.flags & TypeFlags.Union) {
|
||||
const objectOnlyTarget = extractTypesOfKind(target, TypeFlags.Object);
|
||||
if (objectOnlyTarget.flags & TypeFlags.Union) {
|
||||
const result = typeRelatedToDiscriminatedType(source, objectOnlyTarget as UnionType);
|
||||
if (result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
|
||||
@@ -13253,9 +13312,185 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
|
||||
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
function typeRelatedToDiscriminatedType(source: Type, target: UnionType) {
|
||||
// 1. Generate the combinations of discriminant properties & types 'source' can satisfy.
|
||||
// a. If the number of combinations is above a set limit, the comparison is too complex.
|
||||
// 2. Filter 'target' to the subset of types whose discriminants exist in the matrix.
|
||||
// a. If 'target' does not satisfy all discriminants in the matrix, 'source' is not related.
|
||||
// 3. For each type in the filtered 'target', determine if all non-discriminant properties of
|
||||
// 'target' are related to a property in 'source'.
|
||||
//
|
||||
// NOTE: See ~/tests/cases/conformance/types/typeRelationships/assignmentCompatibility/assignmentCompatWithDiscriminatedUnion.ts
|
||||
// for examples.
|
||||
|
||||
const sourceProperties = getPropertiesOfObjectType(source);
|
||||
const sourcePropertiesFiltered = findDiscriminantProperties(sourceProperties, target);
|
||||
if (!sourcePropertiesFiltered) return Ternary.False;
|
||||
|
||||
// Though we could compute the number of combinations as we generate
|
||||
// the matrix, this would incur additional memory overhead due to
|
||||
// array allocations. To reduce this overhead, we first compute
|
||||
// the number of combinations to ensure we will not surpass our
|
||||
// fixed limit before incurring the cost of any allocations:
|
||||
let numCombinations = 1;
|
||||
for (const sourceProperty of sourcePropertiesFiltered) {
|
||||
numCombinations *= countTypes(getTypeOfSymbol(sourceProperty));
|
||||
if (numCombinations > 25) {
|
||||
// We've reached the complexity limit.
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
|
||||
// Compute the set of types for each discriminant property.
|
||||
const sourceDiscriminantTypes: Type[][] = new Array<Type[]>(sourcePropertiesFiltered.length);
|
||||
const excludedProperties = createUnderscoreEscapedMap<true>();
|
||||
for (let i = 0; i < sourcePropertiesFiltered.length; i++) {
|
||||
const sourceProperty = sourcePropertiesFiltered[i];
|
||||
const sourcePropertyType = getTypeOfSymbol(sourceProperty);
|
||||
sourceDiscriminantTypes[i] = sourcePropertyType.flags & TypeFlags.Union
|
||||
? (sourcePropertyType as UnionType).types
|
||||
: [sourcePropertyType];
|
||||
excludedProperties.set(sourceProperty.escapedName, true);
|
||||
}
|
||||
|
||||
// Match each combination of the cartesian product of discriminant properties to one or more
|
||||
// constituents of 'target'. If any combination does not have a match then 'source' is not relatable.
|
||||
const discriminantCombinations = cartesianProduct(sourceDiscriminantTypes);
|
||||
const matchingTypes: Type[] = [];
|
||||
for (const combination of discriminantCombinations) {
|
||||
let hasMatch = false;
|
||||
outer: for (const type of target.types) {
|
||||
for (let i = 0; i < sourcePropertiesFiltered.length; i++) {
|
||||
const sourceProperty = sourcePropertiesFiltered[i];
|
||||
const targetProperty = getPropertyOfObjectType(type, sourceProperty.escapedName);
|
||||
if (!targetProperty) continue outer;
|
||||
if (sourceProperty === targetProperty) continue;
|
||||
// We compare the source property to the target in the context of a single discriminant type.
|
||||
const related = propertyRelatedTo(source, target, sourceProperty, targetProperty, _ => combination[i], /*reportErrors*/ false);
|
||||
// If the target property could not be found, or if the properties were not related,
|
||||
// then this constituent is not a match.
|
||||
if (!related) {
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
pushIfUnique(matchingTypes, type, equateValues);
|
||||
hasMatch = true;
|
||||
}
|
||||
if (!hasMatch) {
|
||||
// We failed to match any type for this combination.
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
|
||||
// Compare the remaining non-discriminant properties of each match.
|
||||
let result = Ternary.True;
|
||||
for (const type of matchingTypes) {
|
||||
result &= propertiesRelatedTo(source, type, /*reportErrors*/ false, excludedProperties);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, type, SignatureKind.Call, /*reportStructuralErrors*/ false);
|
||||
if (result) {
|
||||
result &= signaturesRelatedTo(source, type, SignatureKind.Construct, /*reportStructuralErrors*/ false);
|
||||
if (result) {
|
||||
result &= indexTypesRelatedTo(source, type, IndexKind.String, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false);
|
||||
if (result) {
|
||||
result &= indexTypesRelatedTo(source, type, IndexKind.Number, /*sourceIsPrimitive*/ false, /*reportStructuralErrors*/ false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function excludeProperties(properties: Symbol[], excludedProperties: UnderscoreEscapedMap<true> | undefined) {
|
||||
if (!excludedProperties || properties.length === 0) return properties;
|
||||
let result: Symbol[] | undefined;
|
||||
for (let i = 0; i < properties.length; i++) {
|
||||
if (!excludedProperties.has(properties[i].escapedName)) {
|
||||
if (result) {
|
||||
result.push(properties[i]);
|
||||
}
|
||||
}
|
||||
else if (!result) {
|
||||
result = properties.slice(0, i);
|
||||
}
|
||||
}
|
||||
return result || properties;
|
||||
}
|
||||
|
||||
function propertyRelatedTo(source: Type, target: Type, sourceProp: Symbol, targetProp: Symbol, getTypeOfSourceProperty: (sym: Symbol) => Type, reportErrors: boolean): Ternary {
|
||||
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
|
||||
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
|
||||
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
|
||||
const hasDifferingDeclarations = sourceProp.valueDeclaration !== targetProp.valueDeclaration;
|
||||
if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate && hasDifferingDeclarations) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_has_conflicting_declarations_and_is_inaccessible_in_type_1, symbolToString(sourceProp), typeToString(source));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
if (hasDifferingDeclarations) {
|
||||
if (reportErrors) {
|
||||
if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) {
|
||||
reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp));
|
||||
}
|
||||
else {
|
||||
reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp),
|
||||
typeToString(sourcePropFlags & ModifierFlags.Private ? source : target),
|
||||
typeToString(sourcePropFlags & ModifierFlags.Private ? target : source));
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (targetPropFlags & ModifierFlags.Protected) {
|
||||
if (!isValidOverrideOf(sourceProp, targetProp)) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp),
|
||||
typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (sourcePropFlags & ModifierFlags.Protected) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2,
|
||||
symbolToString(targetProp), typeToString(source), typeToString(target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
// If the target comes from a partial union prop, allow `undefined` in the target type
|
||||
const related = isRelatedTo(getTypeOfSourceProperty(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors);
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
// When checking for comparability, be more lenient with optional properties.
|
||||
if (relation !== comparableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
|
||||
// TypeScript 1.0 spec (April 2014): 3.8.3
|
||||
// S is a subtype of a type T, and T is a supertype of S if ...
|
||||
// S' and T are object types and, for each member M in T..
|
||||
// M is a property and S' contains a property N where
|
||||
// if M is a required property, N is also a required property
|
||||
// (M - property in T)
|
||||
// (N - property in S)
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2,
|
||||
symbolToString(targetProp), typeToString(source), typeToString(target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
return related;
|
||||
}
|
||||
|
||||
function propertiesRelatedTo(source: Type, target: Type, reportErrors: boolean, excludedProperties: UnderscoreEscapedMap<true> | undefined): Ternary {
|
||||
if (relation === identityRelation) {
|
||||
return propertiesIdenticalTo(source, target);
|
||||
return propertiesIdenticalTo(source, target, excludedProperties);
|
||||
}
|
||||
const requireOptionalProperties = relation === subtypeRelation && !isObjectLiteralType(source) && !isEmptyArrayLiteralType(source) && !isTupleType(source);
|
||||
const unmatchedProperty = getUnmatchedProperty(source, target, requireOptionalProperties, /*matchDiscriminantProperties*/ false);
|
||||
@@ -13285,7 +13520,7 @@ namespace ts {
|
||||
return Ternary.False;
|
||||
}
|
||||
if (isObjectLiteralType(target)) {
|
||||
for (const sourceProp of getPropertiesOfType(source)) {
|
||||
for (const sourceProp of excludeProperties(getPropertiesOfType(source), excludedProperties)) {
|
||||
if (!getPropertyOfObjectType(target, sourceProp.escapedName)) {
|
||||
const sourceType = getTypeOfSymbol(sourceProp);
|
||||
if (!(sourceType === undefinedType || sourceType === undefinedWideningType)) {
|
||||
@@ -13328,89 +13563,30 @@ namespace ts {
|
||||
// We only call this for union target types when we're attempting to do excess property checking - in those cases, we want to get _all possible props_
|
||||
// from the target union, across all members
|
||||
const properties = target.flags & TypeFlags.Union ? getPossiblePropertiesOfUnionType(target as UnionType) : getPropertiesOfType(target);
|
||||
for (const targetProp of properties) {
|
||||
for (const targetProp of excludeProperties(properties, excludedProperties)) {
|
||||
if (!(targetProp.flags & SymbolFlags.Prototype)) {
|
||||
const sourceProp = getPropertyOfType(source, targetProp.escapedName);
|
||||
if (sourceProp && sourceProp !== targetProp) {
|
||||
if (isIgnoredJsxProperty(source, sourceProp, getTypeOfSymbol(targetProp))) {
|
||||
continue;
|
||||
}
|
||||
const sourcePropFlags = getDeclarationModifierFlagsFromSymbol(sourceProp);
|
||||
const targetPropFlags = getDeclarationModifierFlagsFromSymbol(targetProp);
|
||||
if (sourcePropFlags & ModifierFlags.Private || targetPropFlags & ModifierFlags.Private) {
|
||||
const hasDifferingDeclarations = sourceProp.valueDeclaration !== targetProp.valueDeclaration;
|
||||
if (getCheckFlags(sourceProp) & CheckFlags.ContainsPrivate && hasDifferingDeclarations) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_has_conflicting_declarations_and_is_inaccessible_in_type_1, symbolToString(sourceProp), typeToString(source));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
if (hasDifferingDeclarations) {
|
||||
if (reportErrors) {
|
||||
if (sourcePropFlags & ModifierFlags.Private && targetPropFlags & ModifierFlags.Private) {
|
||||
reportError(Diagnostics.Types_have_separate_declarations_of_a_private_property_0, symbolToString(targetProp));
|
||||
}
|
||||
else {
|
||||
reportError(Diagnostics.Property_0_is_private_in_type_1_but_not_in_type_2, symbolToString(targetProp),
|
||||
typeToString(sourcePropFlags & ModifierFlags.Private ? source : target),
|
||||
typeToString(sourcePropFlags & ModifierFlags.Private ? target : source));
|
||||
}
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (targetPropFlags & ModifierFlags.Protected) {
|
||||
if (!isValidOverrideOf(sourceProp, targetProp)) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_protected_but_type_1_is_not_a_class_derived_from_2, symbolToString(targetProp),
|
||||
typeToString(getDeclaringClass(sourceProp) || source), typeToString(getDeclaringClass(targetProp) || target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
else if (sourcePropFlags & ModifierFlags.Protected) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_protected_in_type_1_but_public_in_type_2,
|
||||
symbolToString(targetProp), typeToString(source), typeToString(target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
// If the target comes from a partial union prop, allow `undefined` in the target type
|
||||
const related = isRelatedTo(getTypeOfSymbol(sourceProp), addOptionality(getTypeOfSymbol(targetProp), !!(getCheckFlags(targetProp) & CheckFlags.Partial)), reportErrors);
|
||||
const related = propertyRelatedTo(source, target, sourceProp, targetProp, getTypeOfSymbol, reportErrors);
|
||||
if (!related) {
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Types_of_property_0_are_incompatible, symbolToString(targetProp));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
result &= related;
|
||||
// When checking for comparability, be more lenient with optional properties.
|
||||
if (relation !== comparableRelation && sourceProp.flags & SymbolFlags.Optional && !(targetProp.flags & SymbolFlags.Optional)) {
|
||||
// TypeScript 1.0 spec (April 2014): 3.8.3
|
||||
// S is a subtype of a type T, and T is a supertype of S if ...
|
||||
// S' and T are object types and, for each member M in T..
|
||||
// M is a property and S' contains a property N where
|
||||
// if M is a required property, N is also a required property
|
||||
// (M - property in T)
|
||||
// (N - property in S)
|
||||
if (reportErrors) {
|
||||
reportError(Diagnostics.Property_0_is_optional_in_type_1_but_required_in_type_2,
|
||||
symbolToString(targetProp), typeToString(source), typeToString(target));
|
||||
}
|
||||
return Ternary.False;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function propertiesIdenticalTo(source: Type, target: Type): Ternary {
|
||||
function propertiesIdenticalTo(source: Type, target: Type, excludedProperties: UnderscoreEscapedMap<true> | undefined): Ternary {
|
||||
if (!(source.flags & TypeFlags.Object && target.flags & TypeFlags.Object)) {
|
||||
return Ternary.False;
|
||||
}
|
||||
const sourceProperties = getPropertiesOfObjectType(source);
|
||||
const targetProperties = getPropertiesOfObjectType(target);
|
||||
const sourceProperties = excludeProperties(getPropertiesOfObjectType(source), excludedProperties);
|
||||
const targetProperties = excludeProperties(getPropertiesOfObjectType(target), excludedProperties);
|
||||
if (sourceProperties.length !== targetProperties.length) {
|
||||
return Ternary.False;
|
||||
}
|
||||
@@ -15949,6 +16125,10 @@ namespace ts {
|
||||
return f(type) ? type : neverType;
|
||||
}
|
||||
|
||||
function countTypes(type: Type) {
|
||||
return type.flags & TypeFlags.Union ? (type as UnionType).types.length : 1;
|
||||
}
|
||||
|
||||
// Apply a mapping function to a type and return the resulting type. If the source type
|
||||
// is a union type, the mapping function is applied to each constituent type and a union
|
||||
// of the resulting types is returned.
|
||||
@@ -18433,7 +18613,7 @@ namespace ts {
|
||||
case SyntaxKind.ParenthesizedExpression: {
|
||||
// Like in `checkParenthesizedExpression`, an `/** @type {xyz} */` comment before a parenthesized expression acts as a type cast.
|
||||
const tag = isInJSFile(parent) ? getJSDocTypeTag(parent) : undefined;
|
||||
return tag ? getTypeFromTypeNode(tag.typeExpression!.type) : getContextualType(<ParenthesizedExpression>parent, contextFlags);
|
||||
return tag ? getTypeFromTypeNode(tag.typeExpression.type) : getContextualType(<ParenthesizedExpression>parent, contextFlags);
|
||||
}
|
||||
case SyntaxKind.JsxExpression:
|
||||
return getContextualTypeForJsxExpression(<JsxExpression>parent);
|
||||
@@ -20049,6 +20229,35 @@ namespace ts {
|
||||
return suggestion && symbolName(suggestion);
|
||||
}
|
||||
|
||||
function getSuggestionForNonexistentIndexSignature(objectType: Type, expr: ElementAccessExpression): string | undefined {
|
||||
// check if object type has setter or getter
|
||||
const hasProp = (name: "set" | "get", argCount = 1) => {
|
||||
const prop = getPropertyOfObjectType(objectType, <__String>name);
|
||||
if (prop) {
|
||||
const s = getSingleCallSignature(getTypeOfSymbol(prop));
|
||||
if (s && getMinArgumentCount(s) === argCount && typeToString(getTypeAtPosition(s, 0)) === "string") {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
const suggestedMethod = isAssignmentTarget(expr) ? "set" : "get";
|
||||
if (!hasProp(suggestedMethod)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let suggestion = tryGetPropertyAccessOrIdentifierToString(expr);
|
||||
if (suggestion === undefined) {
|
||||
suggestion = suggestedMethod;
|
||||
}
|
||||
else {
|
||||
suggestion += "." + suggestedMethod;
|
||||
}
|
||||
|
||||
return suggestion;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a name and a list of symbols whose names are *not* equal to the name, return a spelling suggestion if there is one that is close enough.
|
||||
* Names less than length 3 only check for case-insensitive equality, not levenshtein distance.
|
||||
@@ -20449,11 +20658,24 @@ namespace ts {
|
||||
|
||||
// If type has a single call signature and no other members, return that signature. Otherwise, return undefined.
|
||||
function getSingleCallSignature(type: Type): Signature | undefined {
|
||||
return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false);
|
||||
}
|
||||
|
||||
function getSingleCallOrConstructSignature(type: Type): Signature | undefined {
|
||||
return getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ false) ||
|
||||
getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ false);
|
||||
}
|
||||
|
||||
function getSingleSignature(type: Type, kind: SignatureKind, allowMembers: boolean): Signature | undefined {
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const resolved = resolveStructuredTypeMembers(<ObjectType>type);
|
||||
if (resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0 &&
|
||||
resolved.properties.length === 0 && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
|
||||
return resolved.callSignatures[0];
|
||||
if (allowMembers || resolved.properties.length === 0 && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
|
||||
if (kind === SignatureKind.Call && resolved.callSignatures.length === 1 && resolved.constructSignatures.length === 0) {
|
||||
return resolved.callSignatures[0];
|
||||
}
|
||||
if (kind === SignatureKind.Construct && resolved.constructSignatures.length === 1 && resolved.callSignatures.length === 0) {
|
||||
return resolved.constructSignatures[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
@@ -23795,16 +24017,18 @@ namespace ts {
|
||||
|
||||
function instantiateTypeWithSingleGenericCallSignature(node: Expression | MethodDeclaration | QualifiedName, type: Type, checkMode?: CheckMode) {
|
||||
if (checkMode && checkMode & (CheckMode.Inferential | CheckMode.SkipGenericFunctions)) {
|
||||
const signature = getSingleCallSignature(type);
|
||||
const callSignature = getSingleSignature(type, SignatureKind.Call, /*allowMembers*/ true);
|
||||
const constructSignature = getSingleSignature(type, SignatureKind.Construct, /*allowMembers*/ true);
|
||||
const signature = callSignature || constructSignature;
|
||||
if (signature && signature.typeParameters) {
|
||||
if (checkMode & CheckMode.SkipGenericFunctions) {
|
||||
skippedGenericFunction(node, checkMode);
|
||||
return anyFunctionType;
|
||||
}
|
||||
const contextualType = getApparentTypeOfContextualType(<Expression>node);
|
||||
if (contextualType) {
|
||||
const contextualSignature = getSingleCallSignature(getNonNullableType(contextualType));
|
||||
if (contextualType && !isMixinConstructorType(contextualType)) {
|
||||
const contextualSignature = getSingleSignature(getNonNullableType(contextualType), callSignature ? SignatureKind.Call : SignatureKind.Construct, /*allowMembers*/ false);
|
||||
if (contextualSignature && !contextualSignature.typeParameters) {
|
||||
if (checkMode & CheckMode.SkipGenericFunctions) {
|
||||
skippedGenericFunction(node, checkMode);
|
||||
return anyFunctionType;
|
||||
}
|
||||
const context = getInferenceContext(node)!;
|
||||
// We have an expression that is an argument of a generic function for which we are performing
|
||||
// type argument inference. The expression is of a function type with a single generic call
|
||||
@@ -23812,7 +24036,8 @@ namespace ts {
|
||||
// if the outer function returns a function type with a single non-generic call signature and
|
||||
// if some of the outer function type parameters have no inferences so far. If so, we can
|
||||
// potentially add inferred type parameters to the outer function return type.
|
||||
const returnSignature = context.signature && getSingleCallSignature(getReturnTypeOfSignature(context.signature));
|
||||
const returnType = context.signature && getReturnTypeOfSignature(context.signature);
|
||||
const returnSignature = returnType && getSingleCallOrConstructSignature(returnType);
|
||||
if (returnSignature && !returnSignature.typeParameters && !every(context.inferences, hasInferenceCandidates)) {
|
||||
// Instantiate the signature with its own type parameters as type arguments, possibly
|
||||
// renaming the type parameters to ensure they have unique names.
|
||||
@@ -24006,7 +24231,7 @@ namespace ts {
|
||||
function checkParenthesizedExpression(node: ParenthesizedExpression, checkMode?: CheckMode): Type {
|
||||
const tag = isInJSFile(node) ? getJSDocTypeTag(node) : undefined;
|
||||
if (tag) {
|
||||
return checkAssertionWorker(tag, tag.typeExpression!.type, node.expression, checkMode);
|
||||
return checkAssertionWorker(tag, tag.typeExpression.type, node.expression, checkMode);
|
||||
}
|
||||
return checkExpression(node.expression, checkMode);
|
||||
}
|
||||
@@ -26462,14 +26687,28 @@ namespace ts {
|
||||
}
|
||||
// For a binding pattern, validate the initializer and exit
|
||||
if (isBindingPattern(node.name)) {
|
||||
// Don't validate for-in initializer as it is already an error
|
||||
if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
|
||||
const initializerType = checkExpressionCached(node.initializer);
|
||||
if (strictNullChecks && node.name.elements.length === 0) {
|
||||
checkNonNullNonVoidType(initializerType, node);
|
||||
const needCheckInitializer = node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement;
|
||||
const needCheckWidenedType = node.name.elements.length === 0;
|
||||
if (needCheckInitializer || needCheckWidenedType) {
|
||||
// Don't validate for-in initializer as it is already an error
|
||||
const widenedType = getWidenedTypeForVariableLikeDeclaration(node);
|
||||
if (needCheckInitializer) {
|
||||
const initializerType = checkExpressionCached(node.initializer!);
|
||||
if (strictNullChecks && needCheckWidenedType) {
|
||||
checkNonNullNonVoidType(initializerType, node);
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableToAndOptionallyElaborate(initializerType, getWidenedTypeForVariableLikeDeclaration(node), node, node.initializer);
|
||||
// check the binding pattern with empty elements
|
||||
if (needCheckWidenedType) {
|
||||
if (isArrayBindingPattern(node.name)) {
|
||||
checkIteratedTypeOrElementType(widenedType, node, /* allowStringInput */ false, /* allowAsyncIterables */ false);
|
||||
}
|
||||
else if (strictNullChecks) {
|
||||
checkNonNullNonVoidType(widenedType, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
@@ -30442,6 +30681,14 @@ namespace ts {
|
||||
continue;
|
||||
}
|
||||
if (!isExternalOrCommonJsModule(file)) {
|
||||
// It is an error for a non-external-module (i.e. script) to declare its own `globalThis`.
|
||||
// We can't use `builtinGlobals` for this due to synthetic expando-namespace generation in JS files.
|
||||
const fileGlobalThisSymbol = file.locals!.get("globalThis" as __String);
|
||||
if (fileGlobalThisSymbol) {
|
||||
for (const declaration of fileGlobalThisSymbol.declarations) {
|
||||
diagnostics.add(createDiagnosticForNode(declaration, Diagnostics.Declaration_name_conflicts_with_built_in_global_identifier_0, "globalThis"));
|
||||
}
|
||||
}
|
||||
mergeSymbolTable(globals, file.locals!);
|
||||
}
|
||||
if (file.jsGlobalAugmentations) {
|
||||
@@ -30487,6 +30734,7 @@ namespace ts {
|
||||
getSymbolLinks(undefinedSymbol).type = undefinedWideningType;
|
||||
getSymbolLinks(argumentsSymbol).type = getGlobalType("IArguments" as __String, /*arity*/ 0, /*reportErrors*/ true);
|
||||
getSymbolLinks(unknownSymbol).type = errorType;
|
||||
getSymbolLinks(globalThisSymbol).type = createObjectType(ObjectFlags.Anonymous, globalThisSymbol);
|
||||
|
||||
// Initialize special types
|
||||
globalArrayType = getGlobalType("Array" as __String, /*arity*/ 1, /*reportErrors*/ true);
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace ts {
|
||||
["es2018.promise", "lib.es2018.promise.d.ts"],
|
||||
["es2018.regexp", "lib.es2018.regexp.d.ts"],
|
||||
["es2019.array", "lib.es2019.array.d.ts"],
|
||||
["es2019.object", "lib.es2019.object.d.ts"],
|
||||
["es2019.string", "lib.es2019.string.d.ts"],
|
||||
["es2019.symbol", "lib.es2019.symbol.d.ts"],
|
||||
["es2020.string", "lib.es2020.string.d.ts"],
|
||||
@@ -218,6 +219,7 @@ namespace ts {
|
||||
}),
|
||||
affectsSourceFile: true,
|
||||
affectsModuleResolution: true,
|
||||
affectsEmit: true,
|
||||
paramType: Diagnostics.VERSION,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -1345,7 +1347,12 @@ namespace ts {
|
||||
/**
|
||||
* Reads the config file, reports errors if any and exits if the config file cannot be found
|
||||
*/
|
||||
export function getParsedCommandLineOfConfigFile(configFileName: string, optionsToExtend: CompilerOptions, host: ParseConfigFileHost): ParsedCommandLine | undefined {
|
||||
export function getParsedCommandLineOfConfigFile(
|
||||
configFileName: string,
|
||||
optionsToExtend: CompilerOptions,
|
||||
host: ParseConfigFileHost,
|
||||
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
|
||||
): ParsedCommandLine | undefined {
|
||||
let configFileText: string | undefined;
|
||||
try {
|
||||
configFileText = host.readFile(configFileName);
|
||||
@@ -1366,7 +1373,16 @@ namespace ts {
|
||||
result.path = toPath(configFileName, cwd, createGetCanonicalFileName(host.useCaseSensitiveFileNames));
|
||||
result.resolvedPath = result.path;
|
||||
result.originalFileName = result.fileName;
|
||||
return parseJsonSourceFileConfigFileContent(result, host, getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd), optionsToExtend, getNormalizedAbsolutePath(configFileName, cwd));
|
||||
return parseJsonSourceFileConfigFileContent(
|
||||
result,
|
||||
host,
|
||||
getNormalizedAbsolutePath(getDirectoryPath(configFileName), cwd),
|
||||
optionsToExtend,
|
||||
getNormalizedAbsolutePath(configFileName, cwd),
|
||||
/*resolutionStack*/ undefined,
|
||||
/*extraFileExtension*/ undefined,
|
||||
extendedConfigCache
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1980,8 +1996,8 @@ namespace ts {
|
||||
* @param basePath A root directory to resolve relative path entries in the config
|
||||
* file to. e.g. outDir
|
||||
*/
|
||||
export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ParsedCommandLine {
|
||||
return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions);
|
||||
export function parseJsonSourceFileConfigFileContent(sourceFile: TsConfigSourceFile, host: ParseConfigHost, basePath: string, existingOptions?: CompilerOptions, configFileName?: string, resolutionStack?: Path[], extraFileExtensions?: ReadonlyArray<FileExtensionInfo>, /*@internal*/ extendedConfigCache?: Map<ExtendedConfigCacheEntry>): ParsedCommandLine {
|
||||
return parseJsonConfigFileContentWorker(/*json*/ undefined, sourceFile, host, basePath, existingOptions, configFileName, resolutionStack, extraFileExtensions, extendedConfigCache);
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -2020,11 +2036,12 @@ namespace ts {
|
||||
configFileName?: string,
|
||||
resolutionStack: Path[] = [],
|
||||
extraFileExtensions: ReadonlyArray<FileExtensionInfo> = [],
|
||||
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
|
||||
): ParsedCommandLine {
|
||||
Debug.assert((json === undefined && sourceFile !== undefined) || (json !== undefined && sourceFile === undefined));
|
||||
const errors: Diagnostic[] = [];
|
||||
|
||||
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors);
|
||||
const parsedConfig = parseConfig(json, sourceFile, host, basePath, configFileName, resolutionStack, errors, extendedConfigCache);
|
||||
const { raw } = parsedConfig;
|
||||
const options = extend(existingOptions, parsedConfig.options || {});
|
||||
options.configFilePath = configFileName && normalizeSlashes(configFileName);
|
||||
@@ -2172,7 +2189,7 @@ namespace ts {
|
||||
return existingErrors !== configParseDiagnostics.length;
|
||||
}
|
||||
|
||||
interface ParsedTsconfig {
|
||||
export interface ParsedTsconfig {
|
||||
raw: any;
|
||||
options?: CompilerOptions;
|
||||
typeAcquisition?: TypeAcquisition;
|
||||
@@ -2191,13 +2208,14 @@ namespace ts {
|
||||
* It does *not* resolve the included files.
|
||||
*/
|
||||
function parseConfig(
|
||||
json: any,
|
||||
sourceFile: TsConfigSourceFile | undefined,
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
configFileName: string | undefined,
|
||||
resolutionStack: string[],
|
||||
errors: Push<Diagnostic>,
|
||||
json: any,
|
||||
sourceFile: TsConfigSourceFile | undefined,
|
||||
host: ParseConfigHost,
|
||||
basePath: string,
|
||||
configFileName: string | undefined,
|
||||
resolutionStack: string[],
|
||||
errors: Push<Diagnostic>,
|
||||
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
|
||||
): ParsedTsconfig {
|
||||
basePath = normalizeSlashes(basePath);
|
||||
const resolvedPath = getNormalizedAbsolutePath(configFileName || "", basePath);
|
||||
@@ -2214,7 +2232,7 @@ namespace ts {
|
||||
if (ownConfig.extendedConfigPath) {
|
||||
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
|
||||
resolutionStack = resolutionStack.concat([resolvedPath]);
|
||||
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
|
||||
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors, extendedConfigCache);
|
||||
if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) {
|
||||
const baseRaw = extendedConfig.raw;
|
||||
const raw = ownConfig.raw;
|
||||
@@ -2358,6 +2376,11 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export interface ExtendedConfigCacheEntry {
|
||||
extendedResult: TsConfigSourceFile;
|
||||
extendedConfig: ParsedTsconfig | undefined;
|
||||
}
|
||||
|
||||
function getExtendedConfig(
|
||||
sourceFile: TsConfigSourceFile | undefined,
|
||||
extendedConfigPath: string,
|
||||
@@ -2365,40 +2388,53 @@ namespace ts {
|
||||
basePath: string,
|
||||
resolutionStack: string[],
|
||||
errors: Push<Diagnostic>,
|
||||
extendedConfigCache?: Map<ExtendedConfigCacheEntry>
|
||||
): ParsedTsconfig | undefined {
|
||||
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
|
||||
const path = host.useCaseSensitiveFileNames ? extendedConfigPath : toLowerCase(extendedConfigPath);
|
||||
let value: ExtendedConfigCacheEntry | undefined;
|
||||
let extendedResult: TsConfigSourceFile;
|
||||
let extendedConfig: ParsedTsconfig | undefined;
|
||||
if (extendedConfigCache && (value = extendedConfigCache.get(path))) {
|
||||
({ extendedResult, extendedConfig } = value);
|
||||
}
|
||||
else {
|
||||
extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
|
||||
if (!extendedResult.parseDiagnostics.length) {
|
||||
const extendedDirname = getDirectoryPath(extendedConfigPath);
|
||||
extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
|
||||
getBaseFileName(extendedConfigPath), resolutionStack, errors, extendedConfigCache);
|
||||
|
||||
if (isSuccessfulParsedTsconfig(extendedConfig)) {
|
||||
// Update the paths to reflect base path
|
||||
const relativeDifference = convertToRelativePath(extendedDirname, basePath, identity);
|
||||
const updatePath = (path: string) => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
|
||||
const mapPropertiesInRawIfNotUndefined = (propertyName: string) => {
|
||||
if (raw[propertyName]) {
|
||||
raw[propertyName] = map(raw[propertyName], updatePath);
|
||||
}
|
||||
};
|
||||
|
||||
const { raw } = extendedConfig;
|
||||
mapPropertiesInRawIfNotUndefined("include");
|
||||
mapPropertiesInRawIfNotUndefined("exclude");
|
||||
mapPropertiesInRawIfNotUndefined("files");
|
||||
}
|
||||
}
|
||||
if (extendedConfigCache) {
|
||||
extendedConfigCache.set(path, { extendedResult, extendedConfig });
|
||||
}
|
||||
}
|
||||
if (sourceFile) {
|
||||
sourceFile.extendedSourceFiles = [extendedResult.fileName];
|
||||
if (extendedResult.extendedSourceFiles) {
|
||||
sourceFile.extendedSourceFiles.push(...extendedResult.extendedSourceFiles);
|
||||
}
|
||||
}
|
||||
if (extendedResult.parseDiagnostics.length) {
|
||||
errors.push(...extendedResult.parseDiagnostics);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const extendedDirname = getDirectoryPath(extendedConfigPath);
|
||||
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
|
||||
getBaseFileName(extendedConfigPath), resolutionStack, errors);
|
||||
if (sourceFile && extendedResult.extendedSourceFiles) {
|
||||
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles);
|
||||
}
|
||||
|
||||
if (isSuccessfulParsedTsconfig(extendedConfig)) {
|
||||
// Update the paths to reflect base path
|
||||
const relativeDifference = convertToRelativePath(extendedDirname, basePath, identity);
|
||||
const updatePath = (path: string) => isRootedDiskPath(path) ? path : combinePaths(relativeDifference, path);
|
||||
const mapPropertiesInRawIfNotUndefined = (propertyName: string) => {
|
||||
if (raw[propertyName]) {
|
||||
raw[propertyName] = map(raw[propertyName], updatePath);
|
||||
}
|
||||
};
|
||||
|
||||
const { raw } = extendedConfig;
|
||||
mapPropertiesInRawIfNotUndefined("include");
|
||||
mapPropertiesInRawIfNotUndefined("exclude");
|
||||
mapPropertiesInRawIfNotUndefined("files");
|
||||
}
|
||||
|
||||
return extendedConfig;
|
||||
return extendedConfig!;
|
||||
}
|
||||
|
||||
function convertCompileOnSaveOptionFromJson(jsonOption: any, basePath: string, errors: Push<Diagnostic>): boolean {
|
||||
|
||||
@@ -2284,4 +2284,29 @@ namespace ts {
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function cartesianProduct<T>(arrays: readonly T[][]) {
|
||||
const result: T[][] = [];
|
||||
cartesianProductWorker(arrays, result, /*outer*/ undefined, 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
function cartesianProductWorker<T>(arrays: readonly (readonly T[])[], result: (readonly T[])[], outer: readonly T[] | undefined, index: number) {
|
||||
for (const element of arrays[index]) {
|
||||
let inner: T[];
|
||||
if (outer) {
|
||||
inner = outer.slice();
|
||||
inner.push(element);
|
||||
}
|
||||
else {
|
||||
inner = [element];
|
||||
}
|
||||
if (index === arrays.length - 1) {
|
||||
result.push(inner);
|
||||
}
|
||||
else {
|
||||
cartesianProductWorker(arrays, result, inner, index + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3096,6 +3096,10 @@
|
||||
"category": "Error",
|
||||
"code": 5074
|
||||
},
|
||||
"'{0}' is assignable to the constraint of type '{1}', but '{1}' could be instantiated with a different subtype of constraint '{2}'.": {
|
||||
"category": "Error",
|
||||
"code": 5075
|
||||
},
|
||||
|
||||
"Generates a sourcemap for each corresponding '.d.ts' file.": {
|
||||
"category": "Message",
|
||||
@@ -4272,7 +4276,10 @@
|
||||
"category": "Error",
|
||||
"code": 7051
|
||||
},
|
||||
|
||||
"Element implicitly has an 'any' type because type '{0}' has no index signature. Did you mean to call '{1}' ?": {
|
||||
"category": "Error",
|
||||
"code": 7052
|
||||
},
|
||||
"You cannot rename this element.": {
|
||||
"category": "Error",
|
||||
"code": 8000
|
||||
|
||||
@@ -2189,7 +2189,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocTypeTag(typeExpression?: JSDocTypeExpression, comment?: string): JSDocTypeTag {
|
||||
export function createJSDocTypeTag(typeExpression: JSDocTypeExpression, comment?: string): JSDocTypeTag {
|
||||
const tag = createJSDocTag<JSDocTypeTag>(SyntaxKind.JSDocTypeTag, "type");
|
||||
tag.typeExpression = typeExpression;
|
||||
tag.comment = comment;
|
||||
|
||||
+3
-18
@@ -6855,7 +6855,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseReturnTag(start: number, tagName: Identifier): JSDocReturnTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocReturnTag)) {
|
||||
if (some(tags, isJSDocReturnTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
}
|
||||
|
||||
@@ -6866,7 +6866,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
function parseTypeTag(start: number, tagName: Identifier): JSDocTypeTag {
|
||||
if (forEach(tags, t => t.kind === SyntaxKind.JSDocTypeTag)) {
|
||||
if (some(tags, isJSDocTypeTag)) {
|
||||
parseErrorAt(tagName.pos, scanner.getTokenPos(), Diagnostics._0_tag_already_specified, tagName.escapedText);
|
||||
}
|
||||
|
||||
@@ -7782,24 +7782,9 @@ namespace ts {
|
||||
|
||||
/*@internal*/
|
||||
export function processCommentPragmas(context: PragmaContext, sourceText: string): void {
|
||||
const triviaScanner = createScanner(context.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText);
|
||||
const pragmas: PragmaPseudoMapEntry[] = [];
|
||||
|
||||
// Keep scanning all the leading trivia in the file until we get to something that
|
||||
// isn't trivia. Any single line comment will be analyzed to see if it is a
|
||||
// reference comment.
|
||||
while (true) {
|
||||
const kind = triviaScanner.scan();
|
||||
if (!isTrivia(kind)) {
|
||||
break;
|
||||
}
|
||||
|
||||
const range = {
|
||||
kind: <SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia>triviaScanner.getToken(),
|
||||
pos: triviaScanner.getTokenPos(),
|
||||
end: triviaScanner.getTextPos(),
|
||||
};
|
||||
|
||||
for (const range of getLeadingCommentRanges(sourceText, 0) || emptyArray) {
|
||||
const comment = sourceText.substring(range.pos, range.end);
|
||||
extractPragmas(pragmas, range, comment);
|
||||
}
|
||||
|
||||
+25
-11
@@ -2678,18 +2678,32 @@ namespace ts {
|
||||
return fromCache || undefined;
|
||||
}
|
||||
|
||||
// An absolute path pointing to the containing directory of the config file
|
||||
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
|
||||
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
|
||||
addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
|
||||
if (sourceFile === undefined) {
|
||||
projectReferenceRedirects.set(sourceFilePath, false);
|
||||
return undefined;
|
||||
let commandLine: ParsedCommandLine | undefined;
|
||||
let sourceFile: JsonSourceFile | undefined;
|
||||
if (host.getParsedCommandLine) {
|
||||
commandLine = host.getParsedCommandLine(refPath);
|
||||
if (!commandLine) {
|
||||
addFileToFilesByName(/*sourceFile*/ undefined, sourceFilePath, /*redirectedPath*/ undefined);
|
||||
projectReferenceRedirects.set(sourceFilePath, false);
|
||||
return undefined;
|
||||
}
|
||||
sourceFile = Debug.assertDefined(commandLine.options.configFile);
|
||||
addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
|
||||
}
|
||||
else {
|
||||
// An absolute path pointing to the containing directory of the config file
|
||||
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
|
||||
sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
|
||||
addFileToFilesByName(sourceFile, sourceFilePath, /*redirectedPath*/ undefined);
|
||||
if (sourceFile === undefined) {
|
||||
projectReferenceRedirects.set(sourceFilePath, false);
|
||||
return undefined;
|
||||
}
|
||||
sourceFile.path = sourceFilePath;
|
||||
sourceFile.resolvedPath = sourceFilePath;
|
||||
sourceFile.originalFileName = refPath;
|
||||
commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
|
||||
}
|
||||
sourceFile.path = sourceFilePath;
|
||||
sourceFile.resolvedPath = sourceFilePath;
|
||||
sourceFile.originalFileName = refPath;
|
||||
const commandLine = parseJsonSourceFileConfigFileContent(sourceFile, configParsingHost, basePath, /*existingOptions*/ undefined, refPath);
|
||||
const resolvedRef: ResolvedProjectReference = { commandLine, sourceFile };
|
||||
projectReferenceRedirects.set(sourceFilePath, resolvedRef);
|
||||
if (commandLine.projectReferences) {
|
||||
|
||||
@@ -399,6 +399,7 @@ namespace ts {
|
||||
let projectCompilerOptions = baseCompilerOptions;
|
||||
const compilerHost = createCompilerHostFromProgramHost(host, () => projectCompilerOptions);
|
||||
setGetSourceFileAsHashVersioned(compilerHost, host);
|
||||
compilerHost.getParsedCommandLine = parseConfigFile;
|
||||
|
||||
compilerHost.resolveModuleNames = maybeBind(host, host.resolveModuleNames);
|
||||
compilerHost.resolveTypeReferenceDirectives = maybeBind(host, host.resolveTypeReferenceDirectives);
|
||||
@@ -415,6 +416,7 @@ namespace ts {
|
||||
} | undefined;
|
||||
|
||||
const buildInfoChecked = createFileMap<true>(toPath);
|
||||
const extendedConfigCache = createMap<ExtendedConfigCacheEntry>();
|
||||
|
||||
// Watch state
|
||||
const builderPrograms = createFileMap<T>(toPath);
|
||||
@@ -491,7 +493,7 @@ namespace ts {
|
||||
|
||||
let diagnostic: Diagnostic | undefined;
|
||||
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = d => diagnostic = d;
|
||||
const parsed = getParsedCommandLineOfConfigFile(configFilePath, baseCompilerOptions, parseConfigFileHost);
|
||||
const parsed = getParsedCommandLineOfConfigFile(configFilePath, baseCompilerOptions, parseConfigFileHost, extendedConfigCache);
|
||||
parseConfigFileHost.onUnRecoverableConfigFileDiagnostic = noop;
|
||||
configFileCache.setValue(configFilePath, parsed || diagnostic!);
|
||||
return parsed;
|
||||
@@ -1439,6 +1441,7 @@ namespace ts {
|
||||
compilerHost.getSourceFile = cacheState.originalGetSourceFile;
|
||||
readFileWithCache = cacheState.originalReadFileWithCache;
|
||||
compilerHost.resolveModuleNames = cacheState.originalResolveModuleNames;
|
||||
extendedConfigCache.clear();
|
||||
if (moduleResolutionCache) {
|
||||
moduleResolutionCache.directoryToModuleNameMap.clear();
|
||||
moduleResolutionCache.moduleNameToDirectoryMap.clear();
|
||||
|
||||
@@ -2482,7 +2482,7 @@ namespace ts {
|
||||
|
||||
export interface JSDocTypeTag extends JSDocTag {
|
||||
kind: SyntaxKind.JSDocTypeTag;
|
||||
typeExpression?: JSDocTypeExpression;
|
||||
typeExpression: JSDocTypeExpression;
|
||||
}
|
||||
|
||||
export interface JSDocTypedefTag extends JSDocTag, NamedDeclaration {
|
||||
@@ -5131,6 +5131,7 @@ namespace ts {
|
||||
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
|
||||
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
|
||||
createHash?(data: string): string;
|
||||
getParsedCommandLine?(fileName: string): ParsedCommandLine | undefined;
|
||||
|
||||
// TODO: later handle this in better way in builder host instead once the api for tsbuild finalizes and doesnt use compilerHost as base
|
||||
/*@internal*/createDirectory?(directory: string): void;
|
||||
|
||||
@@ -3960,6 +3960,16 @@ namespace ts {
|
||||
return isPropertyAccessExpression(node) && isEntityNameExpression(node.expression);
|
||||
}
|
||||
|
||||
export function tryGetPropertyAccessOrIdentifierToString(expr: Expression): string | undefined {
|
||||
if (isPropertyAccessExpression(expr)) {
|
||||
return tryGetPropertyAccessOrIdentifierToString(expr.expression) + "." + expr.name;
|
||||
}
|
||||
if (isIdentifier(expr)) {
|
||||
return unescapeLeadingUnderscores(expr.escapedText);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function isPrototypeAccess(node: Node): node is PropertyAccessExpression {
|
||||
return isPropertyAccessExpression(node) && node.name.escapedText === "prototype";
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user