mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into asyncGenerators
This commit is contained in:
@@ -3154,6 +3154,7 @@ namespace ts {
|
||||
case SyntaxKind.AnyKeyword:
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
@@ -3352,6 +3353,7 @@ namespace ts {
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.StringKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
|
||||
+295
-238
@@ -79,9 +79,11 @@ namespace ts {
|
||||
getDeclaredTypeOfSymbol,
|
||||
getPropertiesOfType,
|
||||
getPropertyOfType,
|
||||
getIndexInfoOfType,
|
||||
getSignaturesOfType,
|
||||
getIndexTypeOfType,
|
||||
getBaseTypes,
|
||||
getTypeFromTypeNode,
|
||||
getReturnTypeOfSignature,
|
||||
getNonNullableType,
|
||||
getSymbolsInScope,
|
||||
@@ -90,6 +92,7 @@ namespace ts {
|
||||
getExportSpecifierLocalTargetSymbol,
|
||||
getTypeAtLocation: getTypeOfNode,
|
||||
getPropertySymbolOfDestructuringAssignment,
|
||||
signatureToString,
|
||||
typeToString,
|
||||
getSymbolDisplayBuilder,
|
||||
symbolToString,
|
||||
@@ -105,6 +108,7 @@ namespace ts {
|
||||
getAliasedSymbol: resolveAlias,
|
||||
getEmitResolver,
|
||||
getExportsOfModule: getExportsOfModuleAsArray,
|
||||
getExportsAndPropertiesOfModule,
|
||||
getAmbientModules,
|
||||
getJsxElementAttributesType,
|
||||
getJsxIntrinsicTagNames,
|
||||
@@ -114,7 +118,8 @@ namespace ts {
|
||||
// we deliberately exclude augmentations
|
||||
// since we are only interested in declarations of the module itself
|
||||
return tryFindAmbientModule(moduleName, /*withAugmentations*/ false);
|
||||
}
|
||||
},
|
||||
getApparentType
|
||||
};
|
||||
|
||||
const tupleTypes: GenericType[] = [];
|
||||
@@ -144,6 +149,7 @@ namespace ts {
|
||||
const voidType = createIntrinsicType(TypeFlags.Void, "void");
|
||||
const neverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||
const silentNeverType = createIntrinsicType(TypeFlags.Never, "never");
|
||||
const nonPrimitiveType = createIntrinsicType(TypeFlags.NonPrimitive, "object");
|
||||
|
||||
const emptyObjectType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
|
||||
@@ -160,6 +166,7 @@ namespace ts {
|
||||
anyFunctionType.flags |= TypeFlags.ContainsAnyFunctionType;
|
||||
|
||||
const noConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
const circularConstraintType = createAnonymousType(undefined, emptySymbols, emptyArray, emptyArray, undefined, undefined);
|
||||
|
||||
const anySignature = createSignature(undefined, undefined, undefined, emptyArray, anyType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
const unknownSignature = createSignature(undefined, undefined, undefined, emptyArray, unknownType, /*typePredicate*/ undefined, 0, /*hasRestParameter*/ false, /*hasLiteralTypes*/ false);
|
||||
@@ -1357,7 +1364,9 @@ namespace ts {
|
||||
return symbol.parent ? getFullyQualifiedName(symbol.parent) + "." + symbolToString(symbol) : symbolToString(symbol);
|
||||
}
|
||||
|
||||
// Resolves a qualified name and any involved aliases
|
||||
/**
|
||||
* Resolves a qualified name and any involved aliases.
|
||||
*/
|
||||
function resolveEntityName(name: EntityNameOrEntityNameExpression, meaning: SymbolFlags, ignoreErrors?: boolean, dontResolveAlias?: boolean, location?: Node): Symbol | undefined {
|
||||
if (nodeIsMissing(name)) {
|
||||
return undefined;
|
||||
@@ -1508,6 +1517,15 @@ namespace ts {
|
||||
return symbolsToArray(getExportsOfModule(moduleSymbol));
|
||||
}
|
||||
|
||||
function getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[] {
|
||||
const exports = getExportsOfModuleAsArray(moduleSymbol);
|
||||
const exportEquals = resolveExternalModuleSymbol(moduleSymbol);
|
||||
if (exportEquals !== moduleSymbol) {
|
||||
addRange(exports, getPropertiesOfType(getTypeOfSymbol(exportEquals)));
|
||||
}
|
||||
return exports;
|
||||
}
|
||||
|
||||
function tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined {
|
||||
const symbolTable = getExportsOfModule(moduleSymbol);
|
||||
if (symbolTable) {
|
||||
@@ -2098,7 +2116,7 @@ namespace ts {
|
||||
return result || types;
|
||||
}
|
||||
|
||||
function visibilityToString(flags: ModifierFlags) {
|
||||
function visibilityToString(flags: ModifierFlags): string | undefined {
|
||||
if (flags === ModifierFlags.Private) {
|
||||
return "private";
|
||||
}
|
||||
@@ -2476,26 +2494,6 @@ namespace ts {
|
||||
buildSymbolDisplay(type.symbol, writer, enclosingDeclaration, SymbolFlags.Value, SymbolFormatFlags.None, typeFormatFlags);
|
||||
}
|
||||
|
||||
function writeIndexSignature(info: IndexInfo, keyword: SyntaxKind) {
|
||||
if (info) {
|
||||
if (info.isReadonly) {
|
||||
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
|
||||
writeSpace(writer);
|
||||
}
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeKeyword(writer, keyword);
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
writeType(info.type, TypeFormatFlags.None);
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
function writePropertyWithModifiers(prop: Symbol) {
|
||||
if (isReadonlySymbol(prop)) {
|
||||
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
|
||||
@@ -2583,8 +2581,8 @@ namespace ts {
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
writeIndexSignature(resolved.stringIndexInfo, SyntaxKind.StringKeyword);
|
||||
writeIndexSignature(resolved.numberIndexInfo, SyntaxKind.NumberKeyword);
|
||||
buildIndexSignatureDisplay(resolved.stringIndexInfo, writer, IndexKind.String, enclosingDeclaration, globalFlags, symbolStack);
|
||||
buildIndexSignatureDisplay(resolved.numberIndexInfo, writer, IndexKind.Number, enclosingDeclaration, globalFlags, symbolStack);
|
||||
for (const p of resolved.properties) {
|
||||
const t = getTypeOfSymbol(p);
|
||||
if (p.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(t).length) {
|
||||
@@ -2775,6 +2773,11 @@ namespace ts {
|
||||
}
|
||||
|
||||
function buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
const returnType = getReturnTypeOfSignature(signature);
|
||||
if (flags & TypeFormatFlags.SuppressAnyReturnType && isTypeAny(returnType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (flags & TypeFormatFlags.WriteArrowStyleSignature) {
|
||||
writeSpace(writer);
|
||||
writePunctuation(writer, SyntaxKind.EqualsGreaterThanToken);
|
||||
@@ -2788,7 +2791,6 @@ namespace ts {
|
||||
buildTypePredicateDisplay(signature.typePredicate, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
else {
|
||||
const returnType = getReturnTypeOfSignature(signature);
|
||||
buildTypeDisplay(returnType, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
}
|
||||
@@ -2813,6 +2815,34 @@ namespace ts {
|
||||
buildReturnTypeDisplay(signature, writer, enclosingDeclaration, flags, symbolStack);
|
||||
}
|
||||
|
||||
function buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]) {
|
||||
if (info) {
|
||||
if (info.isReadonly) {
|
||||
writeKeyword(writer, SyntaxKind.ReadonlyKeyword);
|
||||
writeSpace(writer);
|
||||
}
|
||||
writePunctuation(writer, SyntaxKind.OpenBracketToken);
|
||||
writer.writeParameter(info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : "x");
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
switch (kind) {
|
||||
case IndexKind.Number:
|
||||
writeKeyword(writer, SyntaxKind.NumberKeyword);
|
||||
break;
|
||||
case IndexKind.String:
|
||||
writeKeyword(writer, SyntaxKind.StringKeyword);
|
||||
break;
|
||||
}
|
||||
|
||||
writePunctuation(writer, SyntaxKind.CloseBracketToken);
|
||||
writePunctuation(writer, SyntaxKind.ColonToken);
|
||||
writeSpace(writer);
|
||||
buildTypeDisplay(info.type, writer, enclosingDeclaration, globalFlags, symbolStack);
|
||||
writePunctuation(writer, SyntaxKind.SemicolonToken);
|
||||
writer.writeLine();
|
||||
}
|
||||
}
|
||||
|
||||
return _displayBuilder || (_displayBuilder = {
|
||||
buildSymbolDisplay,
|
||||
buildTypeDisplay,
|
||||
@@ -2823,6 +2853,7 @@ namespace ts {
|
||||
buildDisplayForTypeParametersAndDelimiters,
|
||||
buildTypeParameterDisplayFromSymbol,
|
||||
buildSignatureDisplay,
|
||||
buildIndexSignatureDisplay,
|
||||
buildReturnTypeDisplay
|
||||
});
|
||||
}
|
||||
@@ -3093,9 +3124,8 @@ namespace ts {
|
||||
for (const prop of getPropertiesOfType(source)) {
|
||||
const inNamesToRemove = prop.name in names;
|
||||
const isPrivate = getDeclarationModifierFlagsFromSymbol(prop) & (ModifierFlags.Private | ModifierFlags.Protected);
|
||||
const isMethod = prop.flags & SymbolFlags.Method;
|
||||
const isSetOnlyAccessor = prop.flags & SymbolFlags.SetAccessor && !(prop.flags & SymbolFlags.GetAccessor);
|
||||
if (!inNamesToRemove && !isPrivate && !isMethod && !isSetOnlyAccessor) {
|
||||
if (!inNamesToRemove && !isPrivate && !isClassMethod(prop) && !isSetOnlyAccessor) {
|
||||
members[prop.name] = prop;
|
||||
}
|
||||
}
|
||||
@@ -3782,11 +3812,13 @@ namespace ts {
|
||||
return signatures;
|
||||
}
|
||||
|
||||
// The base constructor of a class can resolve to
|
||||
// undefinedType if the class has no extends clause,
|
||||
// unknownType if an error occurred during resolution of the extends expression,
|
||||
// nullType if the extends expression is the null value, or
|
||||
// an object type with at least one construct signature.
|
||||
/**
|
||||
* The base constructor of a class can resolve to
|
||||
* * undefinedType if the class has no extends clause,
|
||||
* * unknownType if an error occurred during resolution of the extends expression,
|
||||
* * nullType if the extends expression is the null value, or
|
||||
* * an object type with at least one construct signature.
|
||||
*/
|
||||
function getBaseConstructorTypeOfClass(type: InterfaceType): Type {
|
||||
if (!type.resolvedBaseConstructorType) {
|
||||
const baseTypeNode = getBaseTypeNodeOfClass(type);
|
||||
@@ -4111,9 +4143,6 @@ namespace ts {
|
||||
if (!links.declaredType) {
|
||||
const type = <TypeParameter>createType(TypeFlags.TypeParameter);
|
||||
type.symbol = symbol;
|
||||
if (!(<TypeParameterDeclaration>getDeclarationOfKind(symbol, SyntaxKind.TypeParameter)).constraint) {
|
||||
type.constraint = noConstraintType;
|
||||
}
|
||||
links.declaredType = type;
|
||||
}
|
||||
return <TypeParameter>links.declaredType;
|
||||
@@ -4172,6 +4201,7 @@ namespace ts {
|
||||
case SyntaxKind.NumberKeyword:
|
||||
case SyntaxKind.BooleanKeyword:
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
case SyntaxKind.VoidKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NullKeyword:
|
||||
@@ -4267,7 +4297,7 @@ namespace ts {
|
||||
return <InterfaceTypeWithDeclaredMembers>type;
|
||||
}
|
||||
|
||||
function getTypeWithThisArgument(type: Type, thisArgument?: Type) {
|
||||
function getTypeWithThisArgument(type: Type, thisArgument?: Type): Type {
|
||||
if (getObjectFlags(type) & ObjectFlags.Reference) {
|
||||
return createTypeReference((<TypeReference>type).target,
|
||||
concatenate((<TypeReference>type).typeArguments, [thisArgument || (<TypeReference>type).target.thisType]));
|
||||
@@ -4493,6 +4523,9 @@ namespace ts {
|
||||
setStructuredTypeMembers(type, emptySymbols, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an AnonymousType to a ResolvedType.
|
||||
*/
|
||||
function resolveAnonymousTypeMembers(type: AnonymousType) {
|
||||
const symbol = type.symbol;
|
||||
if (type.target) {
|
||||
@@ -4577,7 +4610,7 @@ namespace ts {
|
||||
// Create a mapper from T to the current iteration type constituent. Then, if the
|
||||
// mapped type is itself an instantiated type, combine the iteration mapper with the
|
||||
// instantiation mapper.
|
||||
const iterationMapper = createUnaryTypeMapper(typeParameter, t);
|
||||
const iterationMapper = createTypeMapper([typeParameter], [t]);
|
||||
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, iterationMapper) : iterationMapper;
|
||||
const propType = instantiateType(templateType, templateMapper);
|
||||
// If the current iteration type constituent is a string literal type, create a property.
|
||||
@@ -4636,10 +4669,6 @@ namespace ts {
|
||||
return type.modifiersType;
|
||||
}
|
||||
|
||||
function getErasedTemplateTypeFromMappedType(type: MappedType) {
|
||||
return instantiateType(getTemplateTypeFromMappedType(type), createUnaryTypeMapper(getTypeParameterFromMappedType(type), anyType));
|
||||
}
|
||||
|
||||
function isGenericMappedType(type: Type) {
|
||||
if (getObjectFlags(type) & ObjectFlags.Mapped) {
|
||||
const constraintType = getConstraintTypeFromMappedType(<MappedType>type);
|
||||
@@ -4727,19 +4756,79 @@ namespace ts {
|
||||
getPropertiesOfObjectType(type);
|
||||
}
|
||||
|
||||
function getConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type {
|
||||
return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>type) : getBaseConstraintOfType(type);
|
||||
}
|
||||
|
||||
function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type {
|
||||
return hasNonCircularBaseConstraint(typeParameter) ? getConstraintFromTypeParameter(typeParameter) : undefined;
|
||||
}
|
||||
|
||||
function getBaseConstraintOfType(type: TypeVariable | UnionOrIntersectionType): Type {
|
||||
const constraint = getResolvedBaseConstraint(type);
|
||||
return constraint !== noConstraintType && constraint !== circularConstraintType ? constraint : undefined;
|
||||
}
|
||||
|
||||
function hasNonCircularBaseConstraint(type: TypeVariable): boolean {
|
||||
return getResolvedBaseConstraint(type) !== circularConstraintType;
|
||||
}
|
||||
|
||||
/**
|
||||
* The apparent type of a type parameter is the base constraint instantiated with the type parameter
|
||||
* as the type argument for the 'this' type.
|
||||
* Return the resolved base constraint of a type variable. The noConstraintType singleton is returned if the
|
||||
* type variable has no constraint, and the circularConstraintType singleton is returned if the constraint
|
||||
* circularly references the type variable.
|
||||
*/
|
||||
function getApparentTypeOfTypeVariable(type: TypeVariable) {
|
||||
if (!type.resolvedApparentType) {
|
||||
let constraintType = getConstraintOfTypeVariable(type);
|
||||
while (constraintType && constraintType.flags & TypeFlags.TypeParameter) {
|
||||
constraintType = getConstraintOfTypeVariable(<TypeVariable>constraintType);
|
||||
function getResolvedBaseConstraint(type: TypeVariable | UnionOrIntersectionType): Type {
|
||||
let typeStack: Type[];
|
||||
let circular: boolean;
|
||||
if (!type.resolvedBaseConstraint) {
|
||||
typeStack = [];
|
||||
const constraint = getBaseConstraint(type);
|
||||
type.resolvedBaseConstraint = circular ? circularConstraintType : getTypeWithThisArgument(constraint || noConstraintType, type);
|
||||
}
|
||||
return type.resolvedBaseConstraint;
|
||||
|
||||
function getBaseConstraint(t: Type): Type {
|
||||
if (contains(typeStack, t)) {
|
||||
circular = true;
|
||||
return undefined;
|
||||
}
|
||||
type.resolvedApparentType = getTypeWithThisArgument(constraintType || emptyObjectType, type);
|
||||
typeStack.push(t);
|
||||
const result = computeBaseConstraint(t);
|
||||
typeStack.pop();
|
||||
return result;
|
||||
}
|
||||
|
||||
function computeBaseConstraint(t: Type): Type {
|
||||
if (t.flags & TypeFlags.TypeParameter) {
|
||||
const constraint = getConstraintFromTypeParameter(<TypeParameter>t);
|
||||
return (<TypeParameter>t).isThisType ? constraint :
|
||||
constraint ? getBaseConstraint(constraint) : undefined;
|
||||
}
|
||||
if (t.flags & TypeFlags.UnionOrIntersection) {
|
||||
const types = (<UnionOrIntersectionType>t).types;
|
||||
const baseTypes: Type[] = [];
|
||||
for (const type of types) {
|
||||
const baseType = getBaseConstraint(type);
|
||||
if (baseType) {
|
||||
baseTypes.push(baseType);
|
||||
}
|
||||
}
|
||||
return t.flags & TypeFlags.Union && baseTypes.length === types.length ? getUnionType(baseTypes) :
|
||||
t.flags & TypeFlags.Intersection && baseTypes.length ? getIntersectionType(baseTypes) :
|
||||
undefined;
|
||||
}
|
||||
if (t.flags & TypeFlags.Index) {
|
||||
return stringType;
|
||||
}
|
||||
if (t.flags & TypeFlags.IndexedAccess) {
|
||||
const baseObjectType = getBaseConstraint((<IndexedAccessType>t).objectType);
|
||||
const baseIndexType = getBaseConstraint((<IndexedAccessType>t).indexType);
|
||||
const baseIndexedAccess = baseObjectType && baseIndexType ? getIndexedAccessType(baseObjectType, baseIndexType) : undefined;
|
||||
return baseIndexedAccess && baseIndexedAccess !== unknownType ? getBaseConstraint(baseIndexedAccess) : undefined;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
return type.resolvedApparentType;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4748,11 +4837,12 @@ namespace ts {
|
||||
* type itself. Note that the apparent type of a union type is the union type itself.
|
||||
*/
|
||||
function getApparentType(type: Type): Type {
|
||||
const t = type.flags & TypeFlags.TypeVariable ? getApparentTypeOfTypeVariable(<TypeVariable>type) : type;
|
||||
const t = type.flags & TypeFlags.TypeVariable ? getBaseConstraintOfType(<TypeVariable>type) || emptyObjectType : type;
|
||||
return t.flags & TypeFlags.StringLike ? globalStringType :
|
||||
t.flags & TypeFlags.NumberLike ? globalNumberType :
|
||||
t.flags & TypeFlags.BooleanLike ? globalBooleanType :
|
||||
t.flags & TypeFlags.ESSymbol ? getGlobalESSymbolType(/*checked*/ languageVersion >= ScriptTarget.ES2015) :
|
||||
t.flags & TypeFlags.NonPrimitive ? globalObjectType :
|
||||
t;
|
||||
}
|
||||
|
||||
@@ -5028,9 +5118,10 @@ namespace ts {
|
||||
if (!links.resolvedSignature) {
|
||||
const parameters: Symbol[] = [];
|
||||
let hasLiteralTypes = false;
|
||||
let minArgumentCount = -1;
|
||||
let minArgumentCount = 0;
|
||||
let thisParameter: Symbol = undefined;
|
||||
let hasThisParameter: boolean;
|
||||
const iife = getImmediatelyInvokedFunctionExpression(declaration);
|
||||
const isJSConstructSignature = isJSDocConstructSignature(declaration);
|
||||
|
||||
// If this is a JSDoc construct signature, then skip the first parameter in the
|
||||
@@ -5057,14 +5148,12 @@ namespace ts {
|
||||
hasLiteralTypes = true;
|
||||
}
|
||||
|
||||
if (param.initializer || param.questionToken || param.dotDotDotToken || isJSDocOptionalParameter(param)) {
|
||||
if (minArgumentCount < 0) {
|
||||
minArgumentCount = i - (hasThisParameter ? 1 : 0);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// If we see any required parameters, it means the prior ones were not in fact optional.
|
||||
minArgumentCount = -1;
|
||||
// Record a new minimum argument count if this is not an optional parameter
|
||||
const isOptionalParameter = param.initializer || param.questionToken || param.dotDotDotToken ||
|
||||
iife && parameters.length > iife.arguments.length && !param.type ||
|
||||
isJSDocOptionalParameter(param);
|
||||
if (!isOptionalParameter) {
|
||||
minArgumentCount = parameters.length;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5079,13 +5168,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (minArgumentCount < 0) {
|
||||
minArgumentCount = declaration.parameters.length - (hasThisParameter ? 1 : 0);
|
||||
}
|
||||
if (isJSConstructSignature) {
|
||||
minArgumentCount--;
|
||||
}
|
||||
|
||||
const classType = declaration.kind === SyntaxKind.Constructor ?
|
||||
getDeclaredTypeOfClassOrInterface(getMergedSymbol((<ClassDeclaration>declaration.parent).symbol))
|
||||
: undefined;
|
||||
@@ -5302,20 +5384,7 @@ namespace ts {
|
||||
return (<TypeParameterDeclaration>getDeclarationOfKind(type.symbol, SyntaxKind.TypeParameter)).constraint;
|
||||
}
|
||||
|
||||
function hasConstraintReferenceTo(type: Type, target: TypeParameter): boolean {
|
||||
let checked: Type[];
|
||||
while (type && type.flags & TypeFlags.TypeParameter && !((type as TypeParameter).isThisType) && !contains(checked, type)) {
|
||||
if (type === target) {
|
||||
return true;
|
||||
}
|
||||
(checked || (checked = [])).push(type);
|
||||
const constraintDeclaration = getConstraintDeclaration(<TypeParameter>type);
|
||||
type = constraintDeclaration && getTypeFromTypeNode(constraintDeclaration);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function getConstraintOfTypeParameter(typeParameter: TypeParameter): Type {
|
||||
function getConstraintFromTypeParameter(typeParameter: TypeParameter): Type {
|
||||
if (!typeParameter.constraint) {
|
||||
if (typeParameter.target) {
|
||||
const targetConstraint = getConstraintOfTypeParameter(typeParameter.target);
|
||||
@@ -5323,23 +5392,12 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
const constraintDeclaration = getConstraintDeclaration(typeParameter);
|
||||
let constraint = getTypeFromTypeNode(constraintDeclaration);
|
||||
if (hasConstraintReferenceTo(constraint, typeParameter)) {
|
||||
error(constraintDeclaration, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
|
||||
constraint = unknownType;
|
||||
}
|
||||
typeParameter.constraint = constraint;
|
||||
typeParameter.constraint = constraintDeclaration ? getTypeFromTypeNode(constraintDeclaration) : noConstraintType;
|
||||
}
|
||||
}
|
||||
return typeParameter.constraint === noConstraintType ? undefined : typeParameter.constraint;
|
||||
}
|
||||
|
||||
function getConstraintOfTypeVariable(type: TypeVariable): Type {
|
||||
return type.flags & TypeFlags.TypeParameter ? getConstraintOfTypeParameter(<TypeParameter>type) :
|
||||
type.flags & TypeFlags.IndexedAccess ? (<IndexedAccessType>type).constraint :
|
||||
undefined;
|
||||
}
|
||||
|
||||
function getParentSymbolOfTypeParameter(typeParameter: TypeParameter): Symbol {
|
||||
return getSymbolOfNode(getDeclarationOfKind(typeParameter.symbol, SyntaxKind.TypeParameter).parent);
|
||||
}
|
||||
@@ -6072,24 +6130,6 @@ namespace ts {
|
||||
const type = <IndexedAccessType>createType(TypeFlags.IndexedAccess);
|
||||
type.objectType = objectType;
|
||||
type.indexType = indexType;
|
||||
// We eagerly compute the constraint of the indexed access type such that circularity
|
||||
// errors are immediately caught and reported. For example, class C { x: this["x"] }
|
||||
// becomes an error only when the constraint is eagerly computed.
|
||||
if (type.objectType.flags & TypeFlags.StructuredType) {
|
||||
// The constraint of T[K], where T is an object, union, or intersection type,
|
||||
// is the type of the string index signature of T, if any.
|
||||
type.constraint = getIndexTypeOfType(type.objectType, IndexKind.String);
|
||||
}
|
||||
else if (type.objectType.flags & TypeFlags.TypeVariable) {
|
||||
// The constraint of T[K], where T is a type variable, is A[K], where A is the
|
||||
// apparent type of T.
|
||||
const apparentType = getApparentTypeOfTypeVariable(<TypeVariable>type.objectType);
|
||||
if (apparentType !== emptyObjectType) {
|
||||
type.constraint = isTypeOfKind((<IndexedAccessType>type).indexType, TypeFlags.StringLike) ?
|
||||
getIndexedAccessType(apparentType, (<IndexedAccessType>type).indexType) :
|
||||
getIndexTypeOfType(apparentType, IndexKind.String);
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
@@ -6162,7 +6202,7 @@ namespace ts {
|
||||
error(accessExpression, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(type));
|
||||
return unknownType;
|
||||
}
|
||||
const mapper = createUnaryTypeMapper(getTypeParameterFromMappedType(type), indexType);
|
||||
const mapper = createTypeMapper([getTypeParameterFromMappedType(type)], [indexType]);
|
||||
const templateMapper = type.mapper ? combineTypeMappers(type.mapper, mapper) : mapper;
|
||||
return instantiateType(getTemplateTypeFromMappedType(type), templateMapper);
|
||||
}
|
||||
@@ -6180,13 +6220,6 @@ namespace ts {
|
||||
if (objectType.flags & TypeFlags.Any) {
|
||||
return objectType;
|
||||
}
|
||||
// We first check that the index type is assignable to 'keyof T' for the object type.
|
||||
if (accessNode) {
|
||||
if (!isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
return unknownType;
|
||||
}
|
||||
}
|
||||
// If the object type is a mapped type { [P in K]: E }, we instantiate E using a mapper that substitutes
|
||||
// the index type for P. For example, for an index access { [P in K]: Box<T[P]> }[X], we construct the
|
||||
// type Box<T[X]>.
|
||||
@@ -6268,7 +6301,7 @@ namespace ts {
|
||||
* this function should be called in a left folding style, with left = previous result of getSpreadType
|
||||
* and right = the new element to be spread.
|
||||
*/
|
||||
function getSpreadType(left: Type, right: Type, isFromObjectLiteral: boolean): Type {
|
||||
function getSpreadType(left: Type, right: Type): Type {
|
||||
if (left.flags & TypeFlags.Any || right.flags & TypeFlags.Any) {
|
||||
return anyType;
|
||||
}
|
||||
@@ -6281,10 +6314,10 @@ namespace ts {
|
||||
return left;
|
||||
}
|
||||
if (left.flags & TypeFlags.Union) {
|
||||
return mapType(left, t => getSpreadType(t, right, isFromObjectLiteral));
|
||||
return mapType(left, t => getSpreadType(t, right));
|
||||
}
|
||||
if (right.flags & TypeFlags.Union) {
|
||||
return mapType(right, t => getSpreadType(left, t, isFromObjectLiteral));
|
||||
return mapType(right, t => getSpreadType(left, t));
|
||||
}
|
||||
|
||||
const members = createMap<Symbol>();
|
||||
@@ -6303,18 +6336,18 @@ namespace ts {
|
||||
|
||||
for (const rightProp of getPropertiesOfType(right)) {
|
||||
// we approximate own properties as non-methods plus methods that are inside the object literal
|
||||
const isOwnProperty = !(rightProp.flags & SymbolFlags.Method) || isFromObjectLiteral;
|
||||
const isSetterWithoutGetter = rightProp.flags & SymbolFlags.SetAccessor && !(rightProp.flags & SymbolFlags.GetAccessor);
|
||||
if (getDeclarationModifierFlagsFromSymbol(rightProp) & (ModifierFlags.Private | ModifierFlags.Protected)) {
|
||||
skippedPrivateMembers[rightProp.name] = true;
|
||||
}
|
||||
else if (isOwnProperty && !isSetterWithoutGetter) {
|
||||
else if (!isClassMethod(rightProp) && !isSetterWithoutGetter) {
|
||||
members[rightProp.name] = rightProp;
|
||||
}
|
||||
}
|
||||
for (const leftProp of getPropertiesOfType(left)) {
|
||||
if (leftProp.flags & SymbolFlags.SetAccessor && !(leftProp.flags & SymbolFlags.GetAccessor)
|
||||
|| leftProp.name in skippedPrivateMembers) {
|
||||
|| leftProp.name in skippedPrivateMembers
|
||||
|| isClassMethod(leftProp)) {
|
||||
continue;
|
||||
}
|
||||
if (leftProp.name in members) {
|
||||
@@ -6339,6 +6372,10 @@ namespace ts {
|
||||
return createAnonymousType(undefined, members, emptyArray, emptyArray, stringIndexInfo, numberIndexInfo);
|
||||
}
|
||||
|
||||
function isClassMethod(prop: Symbol) {
|
||||
return prop.flags & SymbolFlags.Method && find(prop.declarations, decl => isClassLike(decl.parent));
|
||||
}
|
||||
|
||||
function createLiteralType(flags: TypeFlags, text: string) {
|
||||
const type = <LiteralType>createType(flags);
|
||||
type.text = text;
|
||||
@@ -6435,6 +6472,8 @@ namespace ts {
|
||||
return nullType;
|
||||
case SyntaxKind.NeverKeyword:
|
||||
return neverType;
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return nonPrimitiveType;
|
||||
case SyntaxKind.JSDocNullKeyword:
|
||||
return nullType;
|
||||
case SyntaxKind.JSDocUndefinedKeyword:
|
||||
@@ -6527,16 +6566,16 @@ namespace ts {
|
||||
return <T>instantiations[type.id] || (instantiations[type.id] = instantiator(type, mapper));
|
||||
}
|
||||
|
||||
function createUnaryTypeMapper(source: Type, target: Type): TypeMapper {
|
||||
return t => t === source ? target : t;
|
||||
function makeUnaryTypeMapper(source: Type, target: Type) {
|
||||
return (t: Type) => t === source ? target : t;
|
||||
}
|
||||
|
||||
function createBinaryTypeMapper(source1: Type, target1: Type, source2: Type, target2: Type): TypeMapper {
|
||||
return t => t === source1 ? target1 : t === source2 ? target2 : t;
|
||||
function makeBinaryTypeMapper(source1: Type, target1: Type, source2: Type, target2: Type) {
|
||||
return (t: Type) => t === source1 ? target1 : t === source2 ? target2 : t;
|
||||
}
|
||||
|
||||
function createArrayTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
|
||||
return t => {
|
||||
function makeArrayTypeMapper(sources: Type[], targets: Type[]) {
|
||||
return (t: Type) => {
|
||||
for (let i = 0; i < sources.length; i++) {
|
||||
if (t === sources[i]) {
|
||||
return targets ? targets[i] : anyType;
|
||||
@@ -6547,11 +6586,9 @@ namespace ts {
|
||||
}
|
||||
|
||||
function createTypeMapper(sources: Type[], targets: Type[]): TypeMapper {
|
||||
const count = sources.length;
|
||||
const mapper: TypeMapper =
|
||||
count == 1 ? createUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
|
||||
count == 2 ? createBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
|
||||
createArrayTypeMapper(sources, targets);
|
||||
const mapper: TypeMapper = sources.length === 1 ? makeUnaryTypeMapper(sources[0], targets ? targets[0] : anyType) :
|
||||
sources.length === 2 ? makeBinaryTypeMapper(sources[0], targets ? targets[0] : anyType, sources[1], targets ? targets[1] : anyType) :
|
||||
makeArrayTypeMapper(sources, targets);
|
||||
mapper.mappedTypes = sources;
|
||||
return mapper;
|
||||
}
|
||||
@@ -6585,7 +6622,13 @@ namespace ts {
|
||||
|
||||
function combineTypeMappers(mapper1: TypeMapper, mapper2: TypeMapper): TypeMapper {
|
||||
const mapper: TypeMapper = t => instantiateType(mapper1(t), mapper2);
|
||||
mapper.mappedTypes = mapper1.mappedTypes;
|
||||
mapper.mappedTypes = concatenate(mapper1.mappedTypes, mapper2.mappedTypes);
|
||||
return mapper;
|
||||
}
|
||||
|
||||
function createReplacementMapper(source: Type, target: Type, baseMapper: TypeMapper) {
|
||||
const mapper: TypeMapper = t => t === source ? target : baseMapper(t);
|
||||
mapper.mappedTypes = baseMapper.mappedTypes;
|
||||
return mapper;
|
||||
}
|
||||
|
||||
@@ -6682,17 +6725,16 @@ namespace ts {
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
if (constraintType.flags & TypeFlags.Index) {
|
||||
const typeVariable = (<IndexType>constraintType).type;
|
||||
const mappedTypeVariable = instantiateType(typeVariable, mapper);
|
||||
if (typeVariable !== mappedTypeVariable) {
|
||||
return mapType(mappedTypeVariable, t => {
|
||||
if (isMappableType(t)) {
|
||||
const replacementMapper = createUnaryTypeMapper(typeVariable, t);
|
||||
const combinedMapper = mapper.mappedTypes && mapper.mappedTypes.length === 1 ? replacementMapper : combineTypeMappers(replacementMapper, mapper);
|
||||
combinedMapper.mappedTypes = mapper.mappedTypes;
|
||||
return instantiateMappedObjectType(type, combinedMapper);
|
||||
}
|
||||
return t;
|
||||
});
|
||||
if (typeVariable.flags & TypeFlags.TypeParameter) {
|
||||
const mappedTypeVariable = instantiateType(typeVariable, mapper);
|
||||
if (typeVariable !== mappedTypeVariable) {
|
||||
return mapType(mappedTypeVariable, t => {
|
||||
if (isMappableType(t)) {
|
||||
return instantiateMappedObjectType(type, createReplacementMapper(typeVariable, t, mapper));
|
||||
}
|
||||
return t;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
return instantiateMappedObjectType(type, mapper);
|
||||
@@ -6948,7 +6990,7 @@ namespace ts {
|
||||
// subtype of T but not structurally identical to T. This specifically means that two distinct but
|
||||
// structurally identical types (such as two classes) are not considered instances of each other.
|
||||
function isTypeInstanceOf(source: Type, target: Type): boolean {
|
||||
return source === target || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target);
|
||||
return getTargetType(source) === getTargetType(target) || isTypeSubtypeOf(source, target) && !isTypeIdenticalTo(source, target);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7190,6 +7232,7 @@ namespace ts {
|
||||
if (source.flags & TypeFlags.Enum && target.flags & TypeFlags.Enum && isEnumTypeRelatedTo(<EnumType>source, <EnumType>target, errorReporter)) return true;
|
||||
if (source.flags & TypeFlags.Undefined && (!strictNullChecks || target.flags & (TypeFlags.Undefined | TypeFlags.Void))) return true;
|
||||
if (source.flags & TypeFlags.Null && (!strictNullChecks || target.flags & TypeFlags.Null)) return true;
|
||||
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.NonPrimitive) return true;
|
||||
if (relation === assignableRelation || relation === comparableRelation) {
|
||||
if (source.flags & TypeFlags.Any) return true;
|
||||
if ((source.flags & TypeFlags.Number | source.flags & TypeFlags.NumberLiteral) && target.flags & TypeFlags.EnumLike) return true;
|
||||
@@ -7225,7 +7268,7 @@ namespace ts {
|
||||
return related === RelationComparisonResult.Succeeded;
|
||||
}
|
||||
}
|
||||
if (source.flags & TypeFlags.StructuredOrTypeParameter || target.flags & TypeFlags.StructuredOrTypeParameter) {
|
||||
if (source.flags & TypeFlags.StructuredOrTypeVariable || target.flags & TypeFlags.StructuredOrTypeVariable) {
|
||||
return checkTypeRelatedTo(source, target, relation, undefined, undefined, undefined);
|
||||
}
|
||||
return false;
|
||||
@@ -7331,10 +7374,12 @@ namespace ts {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare two types and return
|
||||
// Ternary.True if they are related with no assumptions,
|
||||
// Ternary.Maybe if they are related with assumptions of other relationships, or
|
||||
// Ternary.False if they are not related.
|
||||
/**
|
||||
* Compare two types and return
|
||||
* * Ternary.True if they are related with no assumptions,
|
||||
* * Ternary.Maybe if they are related with assumptions of other relationships, or
|
||||
* * Ternary.False if they are not related.
|
||||
*/
|
||||
function isRelatedTo(source: Type, target: Type, reportErrors?: boolean, headMessage?: DiagnosticMessage): Ternary {
|
||||
let result: Ternary;
|
||||
if (source.flags & TypeFlags.StringOrNumberLiteral && source.flags & TypeFlags.FreshLiteral) {
|
||||
@@ -7423,16 +7468,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Given a type parameter K with a constraint keyof T, a type S is
|
||||
// assignable to K if S is assignable to keyof T.
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>target);
|
||||
if (constraint && constraint.flags & TypeFlags.Index) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (target.flags & TypeFlags.Index) {
|
||||
// A keyof S is related to a keyof T if T is related to S.
|
||||
@@ -7441,14 +7476,12 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
// Given a type variable T with a constraint C, a type S is assignable to
|
||||
// keyof T if S is assignable to keyof C.
|
||||
if ((<IndexType>target).type.flags & TypeFlags.TypeVariable) {
|
||||
const constraint = getConstraintOfTypeVariable(<TypeVariable>(<IndexType>target).type);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
// A type S is assignable to keyof T if S is assignable to keyof C, where C is the
|
||||
// constraint of T.
|
||||
const constraint = getConstraintOfType((<IndexType>target).type);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, getIndexType(constraint), reportErrors)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7462,8 +7495,9 @@ namespace ts {
|
||||
}
|
||||
// A type S is related to a type T[K] if S is related to A[K], where K is string-like and
|
||||
// A is the apparent type of S.
|
||||
if ((<IndexedAccessType>target).constraint) {
|
||||
if (result = isRelatedTo(source, (<IndexedAccessType>target).constraint, reportErrors)) {
|
||||
const constraint = getBaseConstraintOfType(<IndexedAccessType>target);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(source, constraint, reportErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
@@ -7482,27 +7516,28 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
let constraint = getConstraintOfTypeParameter(<TypeParameter>source);
|
||||
|
||||
if (!constraint || constraint.flags & TypeFlags.Any) {
|
||||
constraint = emptyObjectType;
|
||||
}
|
||||
|
||||
// The constraint may need to be further instantiated with its 'this' type.
|
||||
constraint = getTypeWithThisArgument(constraint, source);
|
||||
|
||||
// Report constraint errors only if the constraint is not the empty object type
|
||||
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
|
||||
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
// A type parameter with no constraint is not related to the non-primitive object type.
|
||||
if (constraint || !(target.flags & TypeFlags.NonPrimitive)) {
|
||||
if (!constraint || constraint.flags & TypeFlags.Any) {
|
||||
constraint = emptyObjectType;
|
||||
}
|
||||
// The constraint may need to be further instantiated with its 'this' type.
|
||||
constraint = getTypeWithThisArgument(constraint, source);
|
||||
// Report constraint errors only if the constraint is not the empty object type
|
||||
const reportConstraintErrors = reportErrors && constraint !== emptyObjectType;
|
||||
if (result = isRelatedTo(constraint, target, reportConstraintErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (source.flags & TypeFlags.IndexedAccess) {
|
||||
// A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
|
||||
// A is the apparent type of S.
|
||||
if ((<IndexedAccessType>source).constraint) {
|
||||
if (result = isRelatedTo((<IndexedAccessType>source).constraint, target, reportErrors)) {
|
||||
const constraint = getBaseConstraintOfType(<IndexedAccessType>source);
|
||||
if (constraint) {
|
||||
if (result = isRelatedTo(constraint, target, reportErrors)) {
|
||||
errorInfo = saveErrorInfo;
|
||||
return result;
|
||||
}
|
||||
@@ -7789,25 +7824,24 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
// A type [P in S]: X is related to a type [P in T]: Y if T is related to S and X is related to Y.
|
||||
// A type [P in S]: X is related to a type [Q in T]: Y if T is related to S and X' is
|
||||
// related to Y, where X' is an instantiation of X in which P is replaced with Q. Notice
|
||||
// that S and T are contra-variant whereas X and Y are co-variant.
|
||||
function mappedTypeRelatedTo(source: Type, target: Type, reportErrors: boolean): Ternary {
|
||||
if (isGenericMappedType(target)) {
|
||||
if (isGenericMappedType(source)) {
|
||||
let result: Ternary;
|
||||
if (relation === identityRelation) {
|
||||
const readonlyMatches = !(<MappedType>source).declaration.readonlyToken === !(<MappedType>target).declaration.readonlyToken;
|
||||
const optionalMatches = !(<MappedType>source).declaration.questionToken === !(<MappedType>target).declaration.questionToken;
|
||||
if (readonlyMatches && optionalMatches) {
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
return result & isRelatedTo(getErasedTemplateTypeFromMappedType(<MappedType>source), getErasedTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (relation === comparableRelation || !(<MappedType>source).declaration.questionToken || (<MappedType>target).declaration.questionToken) {
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
return result & isRelatedTo(getTemplateTypeFromMappedType(<MappedType>source), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
const sourceReadonly = !!(<MappedType>source).declaration.readonlyToken;
|
||||
const sourceOptional = !!(<MappedType>source).declaration.questionToken;
|
||||
const targetReadonly = !!(<MappedType>target).declaration.readonlyToken;
|
||||
const targetOptional = !!(<MappedType>target).declaration.questionToken;
|
||||
const modifiersRelated = relation === identityRelation ?
|
||||
sourceReadonly === targetReadonly && sourceOptional === targetOptional :
|
||||
relation === comparableRelation || !sourceOptional || targetOptional;
|
||||
if (modifiersRelated) {
|
||||
let result: Ternary;
|
||||
if (result = isRelatedTo(getConstraintTypeFromMappedType(<MappedType>target), getConstraintTypeFromMappedType(<MappedType>source), reportErrors)) {
|
||||
const mapper = createTypeMapper([getTypeParameterFromMappedType(<MappedType>source)], [getTypeParameterFromMappedType(<MappedType>target)]);
|
||||
return result & isRelatedTo(instantiateType(getTemplateTypeFromMappedType(<MappedType>source), mapper), getTemplateTypeFromMappedType(<MappedType>target), reportErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9301,6 +9335,9 @@ namespace ts {
|
||||
if (flags & TypeFlags.ESSymbol) {
|
||||
return strictNullChecks ? TypeFacts.SymbolStrictFacts : TypeFacts.SymbolFacts;
|
||||
}
|
||||
if (flags & TypeFlags.NonPrimitive) {
|
||||
return strictNullChecks ? TypeFacts.ObjectStrictFacts : TypeFacts.ObjectFacts;
|
||||
}
|
||||
if (flags & TypeFlags.TypeParameter) {
|
||||
const constraint = getConstraintOfTypeParameter(<TypeParameter>type);
|
||||
return getTypeFacts(constraint || emptyObjectType);
|
||||
@@ -10949,23 +10986,23 @@ namespace ts {
|
||||
const func = parameter.parent;
|
||||
if (isContextSensitiveFunctionOrObjectLiteralMethod(func)) {
|
||||
const iife = getImmediatelyInvokedFunctionExpression(func);
|
||||
if (iife) {
|
||||
if (iife && iife.arguments) {
|
||||
const indexOfParameter = indexOf(func.parameters, parameter);
|
||||
if (iife.arguments && indexOfParameter < iife.arguments.length) {
|
||||
if (parameter.dotDotDotToken) {
|
||||
const restTypes: Type[] = [];
|
||||
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
|
||||
restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i])));
|
||||
}
|
||||
return createArrayType(getUnionType(restTypes));
|
||||
if (parameter.dotDotDotToken) {
|
||||
const restTypes: Type[] = [];
|
||||
for (let i = indexOfParameter; i < iife.arguments.length; i++) {
|
||||
restTypes.push(getWidenedLiteralType(checkExpression(iife.arguments[i])));
|
||||
}
|
||||
const links = getNodeLinks(iife);
|
||||
const cached = links.resolvedSignature;
|
||||
links.resolvedSignature = anySignature;
|
||||
const type = getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter]));
|
||||
links.resolvedSignature = cached;
|
||||
return type;
|
||||
return restTypes.length ? createArrayType(getUnionType(restTypes)) : undefined;
|
||||
}
|
||||
const links = getNodeLinks(iife);
|
||||
const cached = links.resolvedSignature;
|
||||
links.resolvedSignature = anySignature;
|
||||
const type = indexOfParameter < iife.arguments.length ?
|
||||
getWidenedLiteralType(checkExpression(iife.arguments[indexOfParameter])) :
|
||||
parameter.initializer ? undefined : undefinedWideningType;
|
||||
links.resolvedSignature = cached;
|
||||
return type;
|
||||
}
|
||||
const contextualSignature = getContextualSignature(func);
|
||||
if (contextualSignature) {
|
||||
@@ -11678,7 +11715,7 @@ namespace ts {
|
||||
checkExternalEmitHelpers(memberDecl, ExternalEmitHelpers.Assign);
|
||||
}
|
||||
if (propertiesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
|
||||
spread = getSpreadType(spread, createObjectLiteralType());
|
||||
propertiesArray = [];
|
||||
propertiesTable = createMap<Symbol>();
|
||||
hasComputedStringProperty = false;
|
||||
@@ -11690,7 +11727,7 @@ namespace ts {
|
||||
error(memberDecl, Diagnostics.Spread_types_may_only_be_created_from_object_types);
|
||||
return unknownType;
|
||||
}
|
||||
spread = getSpreadType(spread, type, /*isFromObjectLiteral*/ false);
|
||||
spread = getSpreadType(spread, type);
|
||||
offset = i + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -11735,7 +11772,7 @@ namespace ts {
|
||||
|
||||
if (spread !== emptyObjectType) {
|
||||
if (propertiesArray.length > 0) {
|
||||
spread = getSpreadType(spread, createObjectLiteralType(), /*isFromObjectLiteral*/ true);
|
||||
spread = getSpreadType(spread, createObjectLiteralType());
|
||||
}
|
||||
if (spread.flags & TypeFlags.Object) {
|
||||
// only set the symbol and flags if this is a (fresh) object type
|
||||
@@ -12558,7 +12595,7 @@ namespace ts {
|
||||
return unknownType;
|
||||
}
|
||||
|
||||
return getIndexedAccessType(objectType, indexType, node);
|
||||
return checkIndexedAccessIndexType(getIndexedAccessType(objectType, indexType, node), node);
|
||||
}
|
||||
|
||||
function checkThatExpressionIsProperSymbolReference(expression: Expression, expressionType: Type, reportError: boolean): boolean {
|
||||
@@ -14625,14 +14662,18 @@ namespace ts {
|
||||
}
|
||||
// TypeScript 1.0 spec (April 2014): 4.15.4
|
||||
// The instanceof operator requires the left operand to be of type Any, an object type, or a type parameter type,
|
||||
// and the right operand to be of type Any or a subtype of the 'Function' interface type.
|
||||
// and the right operand to be of type Any, a subtype of the 'Function' interface type, or have a call or construct signature.
|
||||
// The result is always of the Boolean primitive type.
|
||||
// NOTE: do not raise error if leftType is unknown as related error was already reported
|
||||
if (isTypeOfKind(leftType, TypeFlags.Primitive)) {
|
||||
error(left, Diagnostics.The_left_hand_side_of_an_instanceof_expression_must_be_of_type_any_an_object_type_or_a_type_parameter);
|
||||
}
|
||||
// NOTE: do not raise error if right is unknown as related error was already reported
|
||||
if (!(isTypeAny(rightType) || isTypeSubtypeOf(rightType, globalFunctionType))) {
|
||||
if (!(isTypeAny(rightType) ||
|
||||
rightType.flags & TypeFlags.Nullable ||
|
||||
getSignaturesOfType(rightType, SignatureKind.Call).length ||
|
||||
getSignaturesOfType(rightType, SignatureKind.Construct).length ||
|
||||
isTypeSubtypeOf(rightType, globalFunctionType))) {
|
||||
error(right, Diagnostics.The_right_hand_side_of_an_instanceof_expression_must_be_of_type_any_or_of_a_type_assignable_to_the_Function_interface_type);
|
||||
}
|
||||
return booleanType;
|
||||
@@ -15256,14 +15297,14 @@ namespace ts {
|
||||
function isLiteralContextualType(contextualType: Type) {
|
||||
if (contextualType) {
|
||||
if (contextualType.flags & TypeFlags.TypeVariable) {
|
||||
const apparentType = getApparentTypeOfTypeVariable(<TypeVariable>contextualType);
|
||||
const constraint = getBaseConstraintOfType(<TypeVariable>contextualType) || emptyObjectType;
|
||||
// If the type parameter is constrained to the base primitive type we're checking for,
|
||||
// consider this a literal context. For example, given a type parameter 'T extends string',
|
||||
// this causes us to infer string literal types for T.
|
||||
if (apparentType.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean | TypeFlags.Enum)) {
|
||||
if (constraint.flags & (TypeFlags.String | TypeFlags.Number | TypeFlags.Boolean | TypeFlags.Enum)) {
|
||||
return true;
|
||||
}
|
||||
contextualType = apparentType;
|
||||
contextualType = constraint;
|
||||
}
|
||||
return maybeTypeOfKind(contextualType, (TypeFlags.Literal | TypeFlags.Index));
|
||||
}
|
||||
@@ -15461,6 +15502,10 @@ namespace ts {
|
||||
}
|
||||
|
||||
checkSourceElement(node.constraint);
|
||||
const typeParameter = getDeclaredTypeOfTypeParameter(getSymbolOfNode(node));
|
||||
if (!hasNonCircularBaseConstraint(typeParameter)) {
|
||||
error(node.constraint, Diagnostics.Type_parameter_0_has_a_circular_constraint, typeToString(typeParameter));
|
||||
}
|
||||
getConstraintOfTypeParameter(getDeclaredTypeOfTypeParameter(getSymbolOfNode(node)));
|
||||
if (produceDiagnostics) {
|
||||
checkTypeNameIsReserved(node.name, Diagnostics.Type_parameter_name_cannot_be_0);
|
||||
@@ -16089,8 +16134,20 @@ namespace ts {
|
||||
forEach(node.types, checkSourceElement);
|
||||
}
|
||||
|
||||
function checkIndexedAccessIndexType(type: Type, accessNode: ElementAccessExpression | IndexedAccessTypeNode) {
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
// Check that the index type is assignable to 'keyof T' for the object type.
|
||||
const objectType = (<IndexedAccessType>type).objectType;
|
||||
const indexType = (<IndexedAccessType>type).indexType;
|
||||
if (!isTypeAssignableTo(indexType, getIndexType(objectType))) {
|
||||
error(accessNode, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(indexType), typeToString(objectType));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
function checkIndexedAccessType(node: IndexedAccessTypeNode) {
|
||||
getTypeFromIndexedAccessTypeNode(node);
|
||||
checkIndexedAccessIndexType(getTypeFromIndexedAccessTypeNode(node), node);
|
||||
}
|
||||
|
||||
function checkMappedType(node: MappedTypeNode) {
|
||||
@@ -16098,8 +16155,7 @@ namespace ts {
|
||||
checkSourceElement(node.type);
|
||||
const type = <MappedType>getTypeFromMappedTypeNode(node);
|
||||
const constraintType = getConstraintTypeFromMappedType(type);
|
||||
const keyType = constraintType.flags & TypeFlags.TypeVariable ? getApparentTypeOfTypeVariable(<TypeVariable>constraintType) : constraintType;
|
||||
checkTypeAssignableTo(keyType, stringType, node.typeParameter.constraint);
|
||||
checkTypeAssignableTo(constraintType, stringType, node.typeParameter.constraint);
|
||||
}
|
||||
|
||||
function isPrivateWithinAmbient(node: Node): boolean {
|
||||
@@ -18196,27 +18252,27 @@ namespace ts {
|
||||
|
||||
if (func.kind === SyntaxKind.SetAccessor) {
|
||||
if (node.expression) {
|
||||
error(node.expression, Diagnostics.Setters_cannot_return_a_value);
|
||||
error(node, Diagnostics.Setters_cannot_return_a_value);
|
||||
}
|
||||
}
|
||||
else if (func.kind === SyntaxKind.Constructor) {
|
||||
if (node.expression && !checkTypeAssignableTo(exprType, returnType, node.expression)) {
|
||||
error(node.expression, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
|
||||
if (node.expression && !checkTypeAssignableTo(exprType, returnType, node)) {
|
||||
error(node, Diagnostics.Return_type_of_constructor_signature_must_be_assignable_to_the_instance_type_of_the_class);
|
||||
}
|
||||
}
|
||||
else if (func.type || isGetAccessorWithAnnotatedSetAccessor(func)) {
|
||||
if (functionFlags & FunctionFlags.Async) { // Async function
|
||||
const promisedType = getPromisedTypeOfPromise(returnType);
|
||||
const awaitedType = checkAwaitedType(exprType, node.expression || node);
|
||||
const awaitedType = checkAwaitedType(exprType, node);
|
||||
if (promisedType) {
|
||||
// If the function has a return type, but promisedType is
|
||||
// undefined, an error will be reported in checkAsyncFunctionReturnType
|
||||
// so we don't need to report one here.
|
||||
checkTypeAssignableTo(awaitedType, promisedType, node.expression || node);
|
||||
checkTypeAssignableTo(awaitedType, promisedType, node);
|
||||
}
|
||||
}
|
||||
else {
|
||||
checkTypeAssignableTo(exprType, returnType, node.expression || node);
|
||||
checkTypeAssignableTo(exprType, returnType, node);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18461,6 +18517,7 @@ namespace ts {
|
||||
case "string":
|
||||
case "symbol":
|
||||
case "void":
|
||||
case "object":
|
||||
error(name, message, (<Identifier>name).text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,8 +212,8 @@ namespace ts {
|
||||
shortName: "p",
|
||||
type: "string",
|
||||
isFilePath: true,
|
||||
description: Diagnostics.Compile_the_project_in_the_given_directory,
|
||||
paramType: Diagnostics.DIRECTORY
|
||||
description: Diagnostics.Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json,
|
||||
paramType: Diagnostics.FILE_OR_DIRECTORY
|
||||
},
|
||||
{
|
||||
name: "removeComments",
|
||||
@@ -524,7 +524,7 @@ namespace ts {
|
||||
include: typeAcquisition.include || [],
|
||||
exclude: typeAcquisition.exclude || []
|
||||
};
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
return typeAcquisition;
|
||||
}
|
||||
|
||||
@@ -1060,7 +1060,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function formatStringFromArgs(text: string, args: { [index: number]: string; }, baseIndex?: number): string {
|
||||
export function formatStringFromArgs(text: string, args: { [index: number]: string; }, baseIndex?: number): string {
|
||||
baseIndex = baseIndex || 0;
|
||||
|
||||
return text.replace(/{(\d+)}/g, (_match, index?) => args[+index + baseIndex]);
|
||||
|
||||
@@ -2537,7 +2537,7 @@
|
||||
"category": "Message",
|
||||
"code": 6019
|
||||
},
|
||||
"Compile the project in the given directory.": {
|
||||
"Compile the project given the path to its configuration file, or to a folder with a 'tsconfig.json'": {
|
||||
"category": "Message",
|
||||
"code": 6020
|
||||
},
|
||||
@@ -2597,6 +2597,10 @@
|
||||
"category": "Message",
|
||||
"code": 6039
|
||||
},
|
||||
"FILE OR DIRECTORY": {
|
||||
"category": "Message",
|
||||
"code": 6040
|
||||
},
|
||||
"Compilation complete. Watching for file changes.": {
|
||||
"category": "Message",
|
||||
"code": 6042
|
||||
@@ -3267,23 +3271,19 @@
|
||||
"category": "Message",
|
||||
"code": 90002
|
||||
},
|
||||
"Change 'extends' to 'implements'": {
|
||||
"Change 'extends' to 'implements'.": {
|
||||
"category": "Message",
|
||||
"code": 90003
|
||||
},
|
||||
"Remove unused identifiers": {
|
||||
"Remove declaration for: {0}": {
|
||||
"category": "Message",
|
||||
"code": 90004
|
||||
},
|
||||
"Implement interface on reference": {
|
||||
"category": "Message",
|
||||
"code": 90005
|
||||
},
|
||||
"Implement interface on class": {
|
||||
"Implement interface '{0}'.": {
|
||||
"category": "Message",
|
||||
"code": 90006
|
||||
},
|
||||
"Implement inherited abstract class": {
|
||||
"Implement inherited abstract class.": {
|
||||
"category": "Message",
|
||||
"code": 90007
|
||||
},
|
||||
|
||||
@@ -15,7 +15,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** Array that is only intended to be pushed to, never read. */
|
||||
interface Push<T> {
|
||||
export interface Push<T> {
|
||||
push(value: T): void;
|
||||
}
|
||||
|
||||
@@ -357,7 +357,7 @@ namespace ts {
|
||||
* Then it computes the set of parent folders for 'directory' that should have the same module resolution result
|
||||
* and for every parent folder in set it adds entry: parent -> module resolution. .
|
||||
* Lets say we first directory name: /a/b/c/d/e and resolution result is: /a/b/bar.ts.
|
||||
* Set of parent folders that should have the same result will be:
|
||||
* Set of parent folders that should have the same result will be:
|
||||
* [
|
||||
* /a/b/c/d, /a/b/c, /a/b
|
||||
* ]
|
||||
@@ -391,7 +391,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getCommonPrefix(directory: Path, resolution: string) {
|
||||
if (resolution === undefined) {
|
||||
return undefined;
|
||||
@@ -421,7 +421,7 @@ namespace ts {
|
||||
trace(host, Diagnostics.Resolving_module_0_from_1, moduleName, containingFile);
|
||||
}
|
||||
const containingDirectory = getDirectoryPath(containingFile);
|
||||
let perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory);
|
||||
const perFolderCache = cache && cache.getOrCreateCacheForDirectory(containingDirectory);
|
||||
let result = perFolderCache && perFolderCache[moduleName];
|
||||
|
||||
if (result) {
|
||||
@@ -1022,7 +1022,7 @@ namespace ts {
|
||||
|
||||
/**
|
||||
* Represents result of search. Normally when searching among several alternatives we treat value `undefined` as indicator
|
||||
* that search fails and we should try another option.
|
||||
* that search fails and we should try another option.
|
||||
* However this does not allow us to represent final result that should be used instead of further searching (i.e. a final result that was found in cache).
|
||||
* SearchResult is used to deal with this issue, its values represents following outcomes:
|
||||
* - undefined - not found, continue searching
|
||||
@@ -1030,7 +1030,7 @@ namespace ts {
|
||||
* - { value: <some-value> } - found - stop searching
|
||||
*/
|
||||
type SearchResult<T> = { value: T | undefined } | undefined;
|
||||
|
||||
|
||||
/**
|
||||
* Wraps value to SearchResult.
|
||||
* @returns undefined if value is undefined or { value } otherwise
|
||||
|
||||
@@ -2511,6 +2511,7 @@ namespace ts {
|
||||
case SyntaxKind.SymbolKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
// If these are followed by a dot, then parse these out as a dotted type reference instead.
|
||||
const node = tryParse(parseKeywordAndNoDot);
|
||||
return node || parseTypeReference();
|
||||
@@ -2569,6 +2570,7 @@ namespace ts {
|
||||
case SyntaxKind.NumericLiteral:
|
||||
case SyntaxKind.TrueKeyword:
|
||||
case SyntaxKind.FalseKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return true;
|
||||
case SyntaxKind.MinusToken:
|
||||
return lookAhead(nextTokenIsNumericLiteral);
|
||||
@@ -6040,6 +6042,7 @@ namespace ts {
|
||||
case SyntaxKind.NullKeyword:
|
||||
case SyntaxKind.UndefinedKeyword:
|
||||
case SyntaxKind.NeverKeyword:
|
||||
case SyntaxKind.ObjectKeyword:
|
||||
return parseTokenNode<JSDocType>();
|
||||
case SyntaxKind.StringLiteral:
|
||||
case SyntaxKind.NumericLiteral:
|
||||
|
||||
@@ -98,6 +98,7 @@ namespace ts {
|
||||
"new": SyntaxKind.NewKeyword,
|
||||
"null": SyntaxKind.NullKeyword,
|
||||
"number": SyntaxKind.NumberKeyword,
|
||||
"object": SyntaxKind.ObjectKeyword,
|
||||
"package": SyntaxKind.PackageKeyword,
|
||||
"private": SyntaxKind.PrivateKeyword,
|
||||
"protected": SyntaxKind.ProtectedKeyword,
|
||||
@@ -733,11 +734,11 @@ namespace ts {
|
||||
return comments;
|
||||
}
|
||||
|
||||
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] {
|
||||
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined {
|
||||
return reduceEachLeadingCommentRange(text, pos, appendCommentRange, undefined, undefined);
|
||||
}
|
||||
|
||||
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] {
|
||||
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined {
|
||||
return reduceEachTrailingCommentRange(text, pos, appendCommentRange, undefined, undefined);
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -18,7 +18,7 @@ namespace ts {
|
||||
getFileSize?(path: string): number;
|
||||
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
|
||||
/**
|
||||
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
|
||||
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
|
||||
* use native OS file watching
|
||||
*/
|
||||
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
|
||||
|
||||
@@ -927,7 +927,10 @@ namespace ts {
|
||||
|
||||
}
|
||||
|
||||
const superCaptureStatus = declareOrCaptureOrReturnThisForConstructorIfNeeded(statements, constructor, !!extendsClauseElement, hasSynthesizedSuper, statementOffset);
|
||||
// determine whether the class is known syntactically to be a derived class (e.g. a
|
||||
// class that extends a value that is not syntactically known to be `null`).
|
||||
const isDerivedClass = extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword;
|
||||
const superCaptureStatus = declareOrCaptureOrReturnThisForConstructorIfNeeded(statements, constructor, isDerivedClass, hasSynthesizedSuper, statementOffset);
|
||||
|
||||
// The last statement expression was replaced. Skip it.
|
||||
if (superCaptureStatus === SuperCaptureResult.ReplaceSuperCapture || superCaptureStatus === SuperCaptureResult.ReplaceWithReturn) {
|
||||
@@ -944,7 +947,7 @@ namespace ts {
|
||||
|
||||
// Return `_this` unless we're sure enough that it would be pointless to add a return statement.
|
||||
// If there's a constructor that we can tell returns in enough places, then we *do not* want to add a return.
|
||||
if (extendsClauseElement
|
||||
if (isDerivedClass
|
||||
&& superCaptureStatus !== SuperCaptureResult.ReplaceWithReturn
|
||||
&& !(constructor && isSufficientlyCoveredByReturnStatements(constructor.body))) {
|
||||
statements.push(
|
||||
@@ -1013,11 +1016,11 @@ namespace ts {
|
||||
function declareOrCaptureOrReturnThisForConstructorIfNeeded(
|
||||
statements: Statement[],
|
||||
ctor: ConstructorDeclaration | undefined,
|
||||
hasExtendsClause: boolean,
|
||||
isDerivedClass: boolean,
|
||||
hasSynthesizedSuper: boolean,
|
||||
statementOffset: number) {
|
||||
// If this isn't a derived class, just capture 'this' for arrow functions if necessary.
|
||||
if (!hasExtendsClause) {
|
||||
if (!isDerivedClass) {
|
||||
if (ctor) {
|
||||
addCaptureThisForNodeIfNeeded(statements, ctor);
|
||||
}
|
||||
@@ -1093,7 +1096,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
// Perform the capture.
|
||||
captureThisForNode(statements, ctor, superCallExpression, firstStatement);
|
||||
captureThisForNode(statements, ctor, superCallExpression || createActualThis(), firstStatement);
|
||||
|
||||
// If we're actually replacing the original statement, we need to signal this to the caller.
|
||||
if (superCallExpression) {
|
||||
@@ -1103,15 +1106,25 @@ namespace ts {
|
||||
return SuperCaptureResult.NoReplacement;
|
||||
}
|
||||
|
||||
function createActualThis() {
|
||||
return setEmitFlags(createThis(), EmitFlags.NoSubstitution);
|
||||
}
|
||||
|
||||
function createDefaultSuperCallOrThis() {
|
||||
const actualThis = createThis();
|
||||
setEmitFlags(actualThis, EmitFlags.NoSubstitution);
|
||||
const superCall = createFunctionApply(
|
||||
createIdentifier("_super"),
|
||||
actualThis,
|
||||
createIdentifier("arguments"),
|
||||
return createLogicalOr(
|
||||
createLogicalAnd(
|
||||
createStrictInequality(
|
||||
createIdentifier("_super"),
|
||||
createNull()
|
||||
),
|
||||
createFunctionApply(
|
||||
createIdentifier("_super"),
|
||||
createActualThis(),
|
||||
createIdentifier("arguments"),
|
||||
)
|
||||
),
|
||||
createActualThis()
|
||||
);
|
||||
return createLogicalOr(superCall, actualThis);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3747,10 +3760,15 @@ namespace ts {
|
||||
scoped: false,
|
||||
priority: 0,
|
||||
text: `
|
||||
var __extends = (this && this.__extends) || function (d, b) {
|
||||
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};`
|
||||
var __extends = (this && this.__extends) || (function () {
|
||||
var extendStatics = Object.setPrototypeOf ||
|
||||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
|
||||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
|
||||
return function (d, b) {
|
||||
extendStatics(d, b);
|
||||
function __() { this.constructor = d; }
|
||||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
|
||||
};
|
||||
})();`
|
||||
};
|
||||
}
|
||||
|
||||
@@ -145,6 +145,9 @@ namespace ts {
|
||||
return decoded ? createLiteral(decoded, /*location*/ node) : node;
|
||||
}
|
||||
else if (node.kind === SyntaxKind.JsxExpression) {
|
||||
if (node.expression === undefined) {
|
||||
return createLiteral(true);
|
||||
}
|
||||
return visitJsxExpression(<JsxExpression>node);
|
||||
}
|
||||
else {
|
||||
@@ -152,33 +155,50 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function visitJsxText(node: JsxText) {
|
||||
const text = getTextOfNode(node, /*includeTrivia*/ true);
|
||||
let parts: Expression[];
|
||||
function visitJsxText(node: JsxText): StringLiteral | undefined {
|
||||
const fixed = fixupWhitespaceAndDecodeEntities(getTextOfNode(node, /*includeTrivia*/ true));
|
||||
return fixed === undefined ? undefined : createLiteral(fixed);
|
||||
}
|
||||
|
||||
/**
|
||||
* JSX trims whitespace at the end and beginning of lines, except that the
|
||||
* start/end of a tag is considered a start/end of a line only if that line is
|
||||
* on the same line as the closing tag. See examples in
|
||||
* tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx
|
||||
* See also https://www.w3.org/TR/html4/struct/text.html#h-9.1 and https://www.w3.org/TR/CSS2/text.html#white-space-model
|
||||
*
|
||||
* An equivalent algorithm would be:
|
||||
* - If there is only one line, return it.
|
||||
* - If there is only whitespace (but multiple lines), return `undefined`.
|
||||
* - Split the text into lines.
|
||||
* - 'trimRight' the first line, 'trimLeft' the last line, 'trim' middle lines.
|
||||
* - Decode entities on each line (individually).
|
||||
* - Remove empty lines and join the rest with " ".
|
||||
*/
|
||||
function fixupWhitespaceAndDecodeEntities(text: string): string | undefined {
|
||||
let acc: string | undefined;
|
||||
// First non-whitespace character on this line.
|
||||
let firstNonWhitespace = 0;
|
||||
// Last non-whitespace character on this line.
|
||||
let lastNonWhitespace = -1;
|
||||
// These initial values are special because the first line is:
|
||||
// firstNonWhitespace = 0 to indicate that we want leading whitsepace,
|
||||
// but lastNonWhitespace = -1 as a special flag to indicate that we *don't* include the line if it's all whitespace.
|
||||
|
||||
// JSX trims whitespace at the end and beginning of lines, except that the
|
||||
// start/end of a tag is considered a start/end of a line only if that line is
|
||||
// on the same line as the closing tag. See examples in
|
||||
// tests/cases/conformance/jsx/tsxReactEmitWhitespace.tsx
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
const c = text.charCodeAt(i);
|
||||
if (isLineBreak(c)) {
|
||||
if (firstNonWhitespace !== -1 && (lastNonWhitespace - firstNonWhitespace + 1 > 0)) {
|
||||
const part = text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1);
|
||||
if (!parts) {
|
||||
parts = [];
|
||||
}
|
||||
|
||||
// We do not escape the string here as that is handled by the printer
|
||||
// when it emits the literal. We do, however, need to decode JSX entities.
|
||||
parts.push(createLiteral(decodeEntities(part)));
|
||||
// If we've seen any non-whitespace characters on this line, add the 'trim' of the line.
|
||||
// (lastNonWhitespace === -1 is a special flag to detect whether the first line is all whitespace.)
|
||||
if (firstNonWhitespace !== -1 && lastNonWhitespace !== -1) {
|
||||
acc = addLineOfJsxText(acc, text.substr(firstNonWhitespace, lastNonWhitespace - firstNonWhitespace + 1));
|
||||
}
|
||||
|
||||
// Reset firstNonWhitespace for the next line.
|
||||
// Don't bother to reset lastNonWhitespace because we ignore it if firstNonWhitespace = -1.
|
||||
firstNonWhitespace = -1;
|
||||
}
|
||||
else if (!isWhiteSpace(c)) {
|
||||
else if (!isWhiteSpaceSingleLine(c)) {
|
||||
lastNonWhitespace = i;
|
||||
if (firstNonWhitespace === -1) {
|
||||
firstNonWhitespace = i;
|
||||
@@ -186,29 +206,18 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
if (firstNonWhitespace !== -1) {
|
||||
const part = text.substr(firstNonWhitespace);
|
||||
if (!parts) {
|
||||
parts = [];
|
||||
}
|
||||
|
||||
// We do not escape the string here as that is handled by the printer
|
||||
// when it emits the literal. We do, however, need to decode JSX entities.
|
||||
parts.push(createLiteral(decodeEntities(part)));
|
||||
}
|
||||
|
||||
if (parts) {
|
||||
return reduceLeft(parts, aggregateJsxTextParts);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
return firstNonWhitespace !== -1
|
||||
// Last line had a non-whitespace character. Emit the 'trimLeft', meaning keep trailing whitespace.
|
||||
? addLineOfJsxText(acc, text.substr(firstNonWhitespace))
|
||||
// Last line was all whitespace, so ignore it
|
||||
: acc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Aggregates two expressions by interpolating them with a whitespace literal.
|
||||
*/
|
||||
function aggregateJsxTextParts(left: Expression, right: Expression) {
|
||||
return createAdd(createAdd(left, createLiteral(" ")), right);
|
||||
function addLineOfJsxText(acc: string | undefined, trimmedLine: string): string {
|
||||
// We do not escape the string here as that is handled by the printer
|
||||
// when it emits the literal. We do, however, need to decode JSX entities.
|
||||
const decoded = decodeEntities(trimmedLine);
|
||||
return acc === undefined ? decoded : acc + " " + decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,17 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"outFile": "../../built/local/tsc.js",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"stripInternal": true,
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"types": [ ]
|
||||
},
|
||||
"files": [
|
||||
|
||||
+31
-15
@@ -175,6 +175,7 @@ namespace ts {
|
||||
ReadonlyKeyword,
|
||||
RequireKeyword,
|
||||
NumberKeyword,
|
||||
ObjectKeyword,
|
||||
SetKeyword,
|
||||
StringKeyword,
|
||||
SymbolKeyword,
|
||||
@@ -823,6 +824,7 @@ namespace ts {
|
||||
export interface KeywordTypeNode extends TypeNode {
|
||||
kind: SyntaxKind.AnyKeyword
|
||||
| SyntaxKind.NumberKeyword
|
||||
| SyntaxKind.ObjectKeyword
|
||||
| SyntaxKind.BooleanKeyword
|
||||
| SyntaxKind.StringKeyword
|
||||
| SyntaxKind.SymbolKeyword
|
||||
@@ -1557,7 +1559,7 @@ namespace ts {
|
||||
name?: Identifier;
|
||||
}
|
||||
|
||||
export type BlockLike = SourceFile | Block | ModuleBlock | CaseClause;
|
||||
export type BlockLike = SourceFile | Block | ModuleBlock | CaseOrDefaultClause;
|
||||
|
||||
export interface Block extends Statement {
|
||||
kind: SyntaxKind.Block;
|
||||
@@ -2342,6 +2344,7 @@ namespace ts {
|
||||
getDeclaredTypeOfSymbol(symbol: Symbol): Type;
|
||||
getPropertiesOfType(type: Type): Symbol[];
|
||||
getPropertyOfType(type: Type, propertyName: string): Symbol;
|
||||
getIndexInfoOfType(type: Type, kind: IndexKind): IndexInfo;
|
||||
getSignaturesOfType(type: Type, kind: SignatureKind): Signature[];
|
||||
getIndexTypeOfType(type: Type, kind: IndexKind): Type;
|
||||
getBaseTypes(type: InterfaceType): ObjectType[];
|
||||
@@ -2355,6 +2358,8 @@ namespace ts {
|
||||
getExportSpecifierLocalTargetSymbol(location: ExportSpecifier): Symbol;
|
||||
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
getTypeFromTypeNode(node: TypeNode): Type;
|
||||
signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string;
|
||||
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
|
||||
symbolToString(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): string;
|
||||
getSymbolDisplayBuilder(): SymbolDisplayBuilder;
|
||||
@@ -2373,6 +2378,8 @@ namespace ts {
|
||||
isValidPropertyAccess(node: PropertyAccessExpression | QualifiedName, propertyName: string): boolean;
|
||||
getAliasedSymbol(symbol: Symbol): Symbol;
|
||||
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
|
||||
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
|
||||
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
|
||||
|
||||
getJsxElementAttributesType(elementNode: JsxOpeningLikeElement): Type;
|
||||
getJsxIntrinsicTagNames(): Symbol[];
|
||||
@@ -2380,6 +2387,7 @@ namespace ts {
|
||||
getAmbientModules(): Symbol[];
|
||||
|
||||
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
|
||||
getApparentType(type: Type): Type;
|
||||
|
||||
/* @internal */ tryFindAmbientModuleWithoutAugmentations(moduleName: string): Symbol;
|
||||
|
||||
@@ -2398,6 +2406,7 @@ namespace ts {
|
||||
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
|
||||
buildSignatureDisplay(signatures: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): void;
|
||||
buildIndexSignatureDisplay(info: IndexInfo, writer: SymbolWriter, kind: IndexKind, enclosingDeclaration?: Node, globalFlags?: TypeFormatFlags, symbolStack?: Symbol[]): void;
|
||||
buildParameterDisplay(parameter: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
@@ -2441,6 +2450,7 @@ namespace ts {
|
||||
InFirstTypeArgument = 0x00000100, // Writing first type argument of the instantiated type
|
||||
InTypeAlias = 0x00000200, // Writing type in type alias declaration
|
||||
UseTypeAliasValue = 0x00000400, // Serialize the type instead of using type-alias. This is needed when we emit declaration file.
|
||||
SuppressAnyReturnType = 0x00000800, // If the return type is any-like, don't offer a return type.
|
||||
}
|
||||
|
||||
export const enum SymbolFormatFlags {
|
||||
@@ -2787,6 +2797,7 @@ namespace ts {
|
||||
ContainsObjectLiteral = 1 << 22, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
ContainsAnyFunctionType = 1 << 23, // Type is or contains object literal type
|
||||
NonPrimitive = 1 << 24, // intrinsic object type
|
||||
|
||||
/* @internal */
|
||||
Nullable = Undefined | Null,
|
||||
@@ -2796,7 +2807,7 @@ namespace ts {
|
||||
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
|
||||
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
|
||||
/* @internal */
|
||||
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never,
|
||||
Intrinsic = Any | String | Number | Boolean | BooleanLiteral | ESSymbol | Void | Undefined | Null | Never | NonPrimitive,
|
||||
/* @internal */
|
||||
Primitive = String | Number | Boolean | Enum | ESSymbol | Void | Undefined | Null | Literal,
|
||||
StringLike = String | StringLiteral | Index,
|
||||
@@ -2805,13 +2816,13 @@ namespace ts {
|
||||
EnumLike = Enum | EnumLiteral,
|
||||
UnionOrIntersection = Union | Intersection,
|
||||
StructuredType = Object | Union | Intersection,
|
||||
StructuredOrTypeParameter = StructuredType | TypeParameter | Index,
|
||||
StructuredOrTypeVariable = StructuredType | TypeParameter | Index | IndexedAccess,
|
||||
TypeVariable = TypeParameter | IndexedAccess,
|
||||
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol,
|
||||
NotUnionOrUnit = Any | ESSymbol | Object,
|
||||
Narrowable = Any | StructuredType | TypeParameter | Index | IndexedAccess | StringLike | NumberLike | BooleanLike | ESSymbol | NonPrimitive,
|
||||
NotUnionOrUnit = Any | ESSymbol | Object | NonPrimitive,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
/* @internal */
|
||||
@@ -2865,6 +2876,7 @@ namespace ts {
|
||||
ObjectLiteral = 1 << 7, // Originates in an object literal
|
||||
EvolvingArray = 1 << 8, // Evolving array type
|
||||
ObjectLiteralPatternWithComputedProperties = 1 << 9, // Object literal pattern with computed properties
|
||||
NonPrimitive = 1 << 10, // NonPrimitive object type
|
||||
ClassOrInterface = Class | Interface
|
||||
}
|
||||
|
||||
@@ -2873,7 +2885,7 @@ namespace ts {
|
||||
objectFlags: ObjectFlags;
|
||||
}
|
||||
|
||||
// Class and interface types (TypeFlags.Class and TypeFlags.Interface)
|
||||
/** Class and interface types (TypeFlags.Class and TypeFlags.Interface). */
|
||||
export interface InterfaceType extends ObjectType {
|
||||
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
|
||||
outerTypeParameters: TypeParameter[]; // Outer type parameters (undefined if none)
|
||||
@@ -2893,14 +2905,16 @@ namespace ts {
|
||||
declaredNumberIndexInfo: IndexInfo; // Declared numeric indexing info
|
||||
}
|
||||
|
||||
// Type references (TypeFlags.Reference). When a class or interface has type parameters or
|
||||
// a "this" type, references to the class or interface are made using type references. The
|
||||
// typeArguments property specifies the types to substitute for the type parameters of the
|
||||
// class or interface and optionally includes an extra element that specifies the type to
|
||||
// substitute for "this" in the resulting instantiation. When no extra argument is present,
|
||||
// the type reference itself is substituted for "this". The typeArguments property is undefined
|
||||
// if the class or interface has no type parameters and the reference isn't specifying an
|
||||
// explicit "this" argument.
|
||||
/**
|
||||
* Type references (TypeFlags.Reference). When a class or interface has type parameters or
|
||||
* a "this" type, references to the class or interface are made using type references. The
|
||||
* typeArguments property specifies the types to substitute for the type parameters of the
|
||||
* class or interface and optionally includes an extra element that specifies the type to
|
||||
* substitute for "this" in the resulting instantiation. When no extra argument is present,
|
||||
* the type reference itself is substituted for "this". The typeArguments property is undefined
|
||||
* if the class or interface has no type parameters and the reference isn't specifying an
|
||||
* explicit "this" argument.
|
||||
*/
|
||||
export interface TypeReference extends ObjectType {
|
||||
target: GenericType; // Type reference target
|
||||
typeArguments: Type[]; // Type reference type arguments (undefined if none)
|
||||
@@ -2919,6 +2933,8 @@ namespace ts {
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
/* @internal */
|
||||
resolvedBaseConstraint: Type;
|
||||
/* @internal */
|
||||
couldContainTypeVariables: boolean;
|
||||
}
|
||||
|
||||
@@ -2987,7 +3003,7 @@ namespace ts {
|
||||
|
||||
export interface TypeVariable extends Type {
|
||||
/* @internal */
|
||||
resolvedApparentType: Type;
|
||||
resolvedBaseConstraint: Type;
|
||||
/* @internal */
|
||||
resolvedIndexType: IndexType;
|
||||
}
|
||||
|
||||
@@ -1830,7 +1830,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
export function getAncestor(node: Node, kind: SyntaxKind): Node {
|
||||
export function getAncestor(node: Node | undefined, kind: SyntaxKind): Node {
|
||||
while (node) {
|
||||
if (node.kind === kind) {
|
||||
return node;
|
||||
|
||||
+165
-73
@@ -44,6 +44,14 @@ namespace FourSlash {
|
||||
|
||||
markers: Marker[];
|
||||
|
||||
/**
|
||||
* Inserted in source files by surrounding desired text
|
||||
* in a range with `[|` and `|]`. For example,
|
||||
*
|
||||
* [|text in range|]
|
||||
*
|
||||
* is a range with `text in range` "selected".
|
||||
*/
|
||||
ranges: Range[];
|
||||
}
|
||||
|
||||
@@ -254,23 +262,12 @@ namespace FourSlash {
|
||||
// Initialize the language service with all the scripts
|
||||
let startResolveFileRef: FourSlashFile;
|
||||
|
||||
let configFileName: string;
|
||||
ts.forEach(testData.files, file => {
|
||||
// Create map between fileName and its content for easily looking up when resolveReference flag is specified
|
||||
this.inputFiles[file.fileName] = file.content;
|
||||
|
||||
if (ts.getBaseFileName(file.fileName).toLowerCase() === "tsconfig.json") {
|
||||
const configJson = ts.parseConfigFileTextToJson(file.fileName, file.content);
|
||||
assert.isTrue(configJson.config !== undefined);
|
||||
|
||||
// Extend our existing compiler options so that we can also support tsconfig only options
|
||||
if (configJson.config.compilerOptions) {
|
||||
const baseDirectory = ts.normalizePath(ts.getDirectoryPath(file.fileName));
|
||||
const tsConfig = ts.convertCompilerOptionsFromJson(configJson.config.compilerOptions, baseDirectory, file.fileName);
|
||||
|
||||
if (!tsConfig.errors || !tsConfig.errors.length) {
|
||||
compilationOptions = ts.extend(compilationOptions, tsConfig.options);
|
||||
}
|
||||
}
|
||||
configFileName = file.fileName;
|
||||
}
|
||||
|
||||
if (!startResolveFileRef && file.fileOptions[metadataOptionNames.resolveReference] === "true") {
|
||||
@@ -282,6 +279,21 @@ namespace FourSlash {
|
||||
}
|
||||
});
|
||||
|
||||
if (configFileName) {
|
||||
const baseDir = ts.normalizePath(ts.getDirectoryPath(configFileName));
|
||||
const host = new Utils.MockParseConfigHost(baseDir, /*ignoreCase*/ false, this.inputFiles);
|
||||
|
||||
const configJsonObj = ts.parseConfigFileTextToJson(configFileName, this.inputFiles[configFileName]);
|
||||
assert.isTrue(configJsonObj.config !== undefined);
|
||||
|
||||
const { options, errors } = ts.parseJsonConfigFileContent(configJsonObj.config, host, baseDir);
|
||||
|
||||
// Extend our existing compiler options so that we can also support tsconfig only options
|
||||
if (!errors || errors.length === 0) {
|
||||
compilationOptions = ts.extend(compilationOptions, options);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (compilationOptions.typeRoots) {
|
||||
compilationOptions.typeRoots = compilationOptions.typeRoots.map(p => ts.getNormalizedAbsolutePath(p, this.basePath));
|
||||
@@ -413,8 +425,7 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
private raiseError(message: string) {
|
||||
message = this.messageAtLastKnownMarker(message);
|
||||
throw new Error(message);
|
||||
throw new Error(this.messageAtLastKnownMarker(message));
|
||||
}
|
||||
|
||||
private messageAtLastKnownMarker(message: string) {
|
||||
@@ -528,53 +539,66 @@ namespace FourSlash {
|
||||
}
|
||||
|
||||
public verifyGoToDefinitionIs(endMarker: string | string[]) {
|
||||
this.verifyGoToDefinitionWorker(endMarker instanceof Array ? endMarker : [endMarker]);
|
||||
this.verifyGoToXWorker(endMarker instanceof Array ? endMarker : [endMarker], () => this.getGoToDefinition());
|
||||
}
|
||||
|
||||
public verifyGoToDefinition(arg0: any, endMarkerNames?: string | string[]) {
|
||||
this.verifyGoToX(arg0, endMarkerNames, () => this.getGoToDefinition());
|
||||
}
|
||||
|
||||
private getGoToDefinition(): ts.DefinitionInfo[] {
|
||||
return this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition)
|
||||
}
|
||||
|
||||
public verifyGoToType(arg0: any, endMarkerNames?: string | string[]) {
|
||||
this.verifyGoToX(arg0, endMarkerNames, () =>
|
||||
this.languageService.getTypeDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition));
|
||||
}
|
||||
|
||||
private verifyGoToX(arg0: any, endMarkerNames: string | string[] | undefined, getDefs: () => ts.DefinitionInfo[] | undefined) {
|
||||
if (endMarkerNames) {
|
||||
this.verifyGoToDefinitionPlain(arg0, endMarkerNames);
|
||||
this.verifyGoToXPlain(arg0, endMarkerNames, getDefs);
|
||||
}
|
||||
else if (arg0 instanceof Array) {
|
||||
const pairs: [string | string[], string | string[]][] = arg0;
|
||||
for (const [start, end] of pairs) {
|
||||
this.verifyGoToDefinitionPlain(start, end);
|
||||
this.verifyGoToXPlain(start, end, getDefs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const obj: { [startMarkerName: string]: string | string[] } = arg0;
|
||||
for (const startMarkerName in obj) {
|
||||
if (ts.hasProperty(obj, startMarkerName)) {
|
||||
this.verifyGoToDefinitionPlain(startMarkerName, obj[startMarkerName]);
|
||||
this.verifyGoToXPlain(startMarkerName, obj[startMarkerName], getDefs);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private verifyGoToDefinitionPlain(startMarkerNames: string | string[], endMarkerNames: string | string[]) {
|
||||
private verifyGoToXPlain(startMarkerNames: string | string[], endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
|
||||
if (startMarkerNames instanceof Array) {
|
||||
for (const start of startMarkerNames) {
|
||||
this.verifyGoToDefinitionSingle(start, endMarkerNames);
|
||||
this.verifyGoToXSingle(start, endMarkerNames, getDefs);
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.verifyGoToDefinitionSingle(startMarkerNames, endMarkerNames);
|
||||
this.verifyGoToXSingle(startMarkerNames, endMarkerNames, getDefs);
|
||||
}
|
||||
}
|
||||
|
||||
public verifyGoToDefinitionForMarkers(markerNames: string[]) {
|
||||
for (const markerName of markerNames) {
|
||||
this.verifyGoToDefinitionSingle(`${markerName}Reference`, `${markerName}Definition`);
|
||||
this.verifyGoToXSingle(`${markerName}Reference`, `${markerName}Definition`, () => this.getGoToDefinition());
|
||||
}
|
||||
}
|
||||
|
||||
private verifyGoToDefinitionSingle(startMarkerName: string, endMarkerNames: string | string[]) {
|
||||
private verifyGoToXSingle(startMarkerName: string, endMarkerNames: string | string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
|
||||
this.goToMarker(startMarkerName);
|
||||
this.verifyGoToDefinitionWorker(endMarkerNames instanceof Array ? endMarkerNames : [endMarkerNames]);
|
||||
this.verifyGoToXWorker(endMarkerNames instanceof Array ? endMarkerNames : [endMarkerNames], getDefs);
|
||||
}
|
||||
|
||||
private verifyGoToDefinitionWorker(endMarkers: string[]) {
|
||||
const definitions = this.languageService.getDefinitionAtPosition(this.activeFile.fileName, this.currentCaretPosition) || [];
|
||||
private verifyGoToXWorker(endMarkers: string[], getDefs: () => ts.DefinitionInfo[] | undefined) {
|
||||
const definitions = getDefs() || [];
|
||||
|
||||
if (endMarkers.length !== definitions.length) {
|
||||
this.raiseError(`goToDefinitions failed - expected to find ${endMarkers.length} definitions but got ${definitions.length}`);
|
||||
@@ -698,6 +722,27 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyCompletionsAt(markerName: string, expected: string[]) {
|
||||
this.goToMarker(markerName);
|
||||
|
||||
const actualCompletions = this.getCompletionListAtCaret();
|
||||
if (!actualCompletions) {
|
||||
this.raiseError(`No completions at position '${this.currentCaretPosition}'.`);
|
||||
}
|
||||
|
||||
const actual = actualCompletions.entries;
|
||||
|
||||
if (actual.length !== expected.length) {
|
||||
this.raiseError(`Expected ${expected.length} completions, got ${actual.map(a => a.name)}.`);
|
||||
}
|
||||
|
||||
ts.zipWith(actual, expected, (completion, expectedCompletion, index) => {
|
||||
if (completion.name !== expectedCompletion) {
|
||||
this.raiseError(`Expected completion at index ${index} to be ${expectedCompletion}, got ${completion.name}`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public verifyCompletionListContains(symbol: string, text?: string, documentation?: string, kind?: string, spanIndex?: number) {
|
||||
const completions = this.getCompletionListAtCaret();
|
||||
if (completions) {
|
||||
@@ -1533,7 +1578,8 @@ namespace FourSlash {
|
||||
let runningOffset = 0;
|
||||
edits = edits.sort((a, b) => a.span.start - b.span.start);
|
||||
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
|
||||
const oldContent = this.getFileContent(this.activeFile.fileName);
|
||||
const oldContent = this.getFileContent(fileName);
|
||||
|
||||
for (const edit of edits) {
|
||||
this.languageServiceAdapterHost.editScript(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
|
||||
this.updateMarkersForEdit(fileName, edit.span.start + runningOffset, ts.textSpanEnd(edit.span) + runningOffset, edit.newText);
|
||||
@@ -1970,54 +2016,93 @@ namespace FourSlash {
|
||||
});
|
||||
}
|
||||
|
||||
private getCodeFixes(errorCode?: number) {
|
||||
const fileName = this.activeFile.fileName;
|
||||
const diagnostics = this.getDiagnostics(fileName);
|
||||
|
||||
if (diagnostics.length === 0) {
|
||||
this.raiseError("Errors expected.");
|
||||
}
|
||||
|
||||
if (diagnostics.length > 1 && errorCode === undefined) {
|
||||
this.raiseError("When there's more than one error, you must specify the errror to fix.");
|
||||
}
|
||||
|
||||
const diagnostic = !errorCode ? diagnostics[0] : ts.find(diagnostics, d => d.code == errorCode);
|
||||
|
||||
return this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.start + diagnostic.length, [diagnostic.code]);
|
||||
}
|
||||
|
||||
public verifyCodeFixAtPosition(expectedText: string, errorCode?: number) {
|
||||
/**
|
||||
* Compares expected text to the text that would be in the sole range
|
||||
* (ie: [|...|]) in the file after applying the codefix sole codefix
|
||||
* in the source file.
|
||||
*
|
||||
* Because codefixes are only applied on the working file, it is unsafe
|
||||
* to apply this more than once (consider a refactoring across files).
|
||||
*/
|
||||
public verifyRangeAfterCodeFix(expectedText: string, errorCode?: number) {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges.length == 0) {
|
||||
this.raiseError("At least one range should be specified in the testfile.");
|
||||
if (ranges.length !== 1) {
|
||||
this.raiseError("Exactly one range should be specified in the testfile.");
|
||||
}
|
||||
|
||||
const actual = this.getCodeFixes(errorCode);
|
||||
const fileName = this.activeFile.fileName;
|
||||
|
||||
if (!actual || actual.length == 0) {
|
||||
this.raiseError("No codefixes returned.");
|
||||
}
|
||||
this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName, errorCode));
|
||||
|
||||
if (actual.length > 1) {
|
||||
this.raiseError("More than 1 codefix returned.");
|
||||
}
|
||||
|
||||
this.applyEdits(actual[0].changes[0].fileName, actual[0].changes[0].textChanges, /*isFormattingEdit*/ false);
|
||||
const actualText = this.rangeText(ranges[0]);
|
||||
|
||||
if (this.removeWhitespace(actualText) !== this.removeWhitespace(expectedText)) {
|
||||
this.raiseError(`Actual text doesn't match expected text. Actual: '${actualText}' Expected: '${expectedText}'`);
|
||||
this.raiseError(`Actual text doesn't match expected text. Actual:\n'${actualText}'\nExpected:\n'${expectedText}'`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies fixes for the errors in fileName and compares the results to
|
||||
* expectedContents after all fixes have been applied.
|
||||
|
||||
* Note: applying one codefix may generate another (eg: remove duplicate implements
|
||||
* may generate an extends -> interface conversion fix).
|
||||
* @param expectedContents The contents of the file after the fixes are applied.
|
||||
* @param fileName The file to check. If not supplied, the current open file is used.
|
||||
*/
|
||||
public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) {
|
||||
fileName = fileName ? fileName : this.activeFile.fileName;
|
||||
|
||||
this.applyCodeFixActions(fileName, this.getCodeFixActions(fileName));
|
||||
|
||||
const actualContents: string = this.getFileContent(fileName);
|
||||
if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) {
|
||||
this.raiseError(`Actual text doesn't match expected text. Actual:\n${actualContents}\n\nExpected:\n${expectedContents}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rerieves a codefix satisfying the parameters, or undefined if no such codefix is found.
|
||||
* @param fileName Path to file where error should be retrieved from.
|
||||
*/
|
||||
private getCodeFixActions(fileName: string, errorCode?: number): ts.CodeAction[] {
|
||||
const diagnostics: ts.Diagnostic[] = this.getDiagnostics(fileName);
|
||||
|
||||
let actions: ts.CodeAction[] = undefined;
|
||||
for (const diagnostic of diagnostics) {
|
||||
|
||||
if (errorCode && errorCode !== diagnostic.code) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newActions = this.languageService.getCodeFixesAtPosition(fileName, diagnostic.start, diagnostic.length, [diagnostic.code]);
|
||||
if (newActions && newActions.length) {
|
||||
actions = actions ? actions.concat(newActions) : newActions;
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
}
|
||||
|
||||
private applyCodeFixActions(fileName: string, actions: ts.CodeAction[]): void {
|
||||
if (!(actions && actions.length === 1)) {
|
||||
this.raiseError(`Should find exactly one codefix, but ${actions ? actions.length : "none"} found.`);
|
||||
}
|
||||
|
||||
const fileChanges = ts.find(actions[0].changes, change => change.fileName === fileName);
|
||||
if (!fileChanges) {
|
||||
this.raiseError("The CodeFix found doesn't provide any changes in this file.");
|
||||
}
|
||||
|
||||
this.applyEdits(fileChanges.fileName, fileChanges.textChanges, /*isFormattingEdit*/ false);
|
||||
}
|
||||
|
||||
public verifyImportFixAtPosition(expectedTextArray: string[], errorCode?: number) {
|
||||
const ranges = this.getRanges();
|
||||
if (ranges.length == 0) {
|
||||
this.raiseError("At least one range should be specified in the testfile.");
|
||||
}
|
||||
|
||||
const codeFixes = this.getCodeFixes(errorCode);
|
||||
const codeFixes = this.getCodeFixActions(this.activeFile.fileName, errorCode);
|
||||
|
||||
if (!codeFixes || codeFixes.length == 0) {
|
||||
this.raiseError("No codefixes returned.");
|
||||
@@ -2315,15 +2400,15 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyCodeFixAvailable(negative: boolean, errorCode?: number) {
|
||||
const fixes = this.getCodeFixes(errorCode);
|
||||
public verifyCodeFixAvailable(negative: boolean) {
|
||||
const codeFix = this.getCodeFixActions(this.activeFile.fileName);
|
||||
|
||||
if (negative && fixes && fixes.length > 0) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes, actual: ${fixes.length}`);
|
||||
if (negative && codeFix) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected no fixes but found one.`);
|
||||
}
|
||||
|
||||
if (!negative && (fixes === undefined || fixes.length === 0)) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes, actual: 0`);
|
||||
if (!(negative || codeFix)) {
|
||||
this.raiseError(`verifyCodeFixAvailable failed - expected code fixes but none found.`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2990,10 +3075,6 @@ namespace FourSlashInterface {
|
||||
this.state.goToEOF();
|
||||
}
|
||||
|
||||
public type(definitionIndex = 0) {
|
||||
this.state.goToTypeDefinition(definitionIndex);
|
||||
}
|
||||
|
||||
public implementation() {
|
||||
this.state.goToImplementation();
|
||||
}
|
||||
@@ -3095,8 +3176,8 @@ namespace FourSlashInterface {
|
||||
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
|
||||
}
|
||||
|
||||
public codeFixAvailable(errorCode?: number) {
|
||||
this.state.verifyCodeFixAvailable(this.negative, errorCode);
|
||||
public codeFixAvailable() {
|
||||
this.state.verifyCodeFixAvailable(this.negative);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3105,6 +3186,10 @@ namespace FourSlashInterface {
|
||||
super(state);
|
||||
}
|
||||
|
||||
public completionsAt(markerName: string, completions: string[]) {
|
||||
this.state.verifyCompletionsAt(markerName, completions);
|
||||
}
|
||||
|
||||
public quickInfoIs(expectedText: string, expectedDocumentation?: string) {
|
||||
this.state.verifyQuickInfoString(expectedText, expectedDocumentation);
|
||||
}
|
||||
@@ -3161,6 +3246,13 @@ namespace FourSlashInterface {
|
||||
this.state.verifyGoToDefinition(arg0, endMarkerName);
|
||||
}
|
||||
|
||||
public goToType(startMarkerName: string | string[], endMarkerName: string | string[]): void;
|
||||
public goToType(startsAndEnds: [string | string[], string | string[]][]): void;
|
||||
public goToType(startsAndEnds: { [startMarkerName: string]: string | string[] }): void;
|
||||
public goToType(arg0: any, endMarkerName?: string | string[]) {
|
||||
this.state.verifyGoToType(arg0, endMarkerName);
|
||||
}
|
||||
|
||||
public goToDefinitionForMarkers(...markerNames: string[]) {
|
||||
this.state.verifyGoToDefinitionForMarkers(markerNames);
|
||||
}
|
||||
@@ -3281,8 +3373,8 @@ namespace FourSlashInterface {
|
||||
this.DocCommentTemplate(/*expectedText*/ undefined, /*expectedOffset*/ undefined, /*empty*/ true);
|
||||
}
|
||||
|
||||
public codeFixAtPosition(expectedText: string, errorCode?: number): void {
|
||||
this.state.verifyCodeFixAtPosition(expectedText, errorCode);
|
||||
public rangeAfterCodeFix(expectedText: string, errorCode?: number): void {
|
||||
this.state.verifyRangeAfterCodeFix(expectedText, errorCode);
|
||||
}
|
||||
|
||||
public importFixAtPosition(expectedTextArray: string[], errorCode?: number): void {
|
||||
|
||||
+14
-10
@@ -1,19 +1,12 @@
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"pretty": true,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"outFile": "../../built/local/run.js",
|
||||
"sourceMap": true,
|
||||
"declaration": false,
|
||||
"stripInternal": true,
|
||||
"types": [
|
||||
"node", "mocha", "chai"
|
||||
],
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"../compiler/core.ts",
|
||||
@@ -74,7 +67,18 @@
|
||||
"../services/formatting/rulesProvider.ts",
|
||||
"../services/formatting/smartIndenter.ts",
|
||||
"../services/formatting/tokenRange.ts",
|
||||
"harness.ts",
|
||||
"../services/codeFixProvider.ts",
|
||||
"../services/codefixes/fixes.ts",
|
||||
"../services/codefixes/fixExtendsInterfaceBecomesImplements.ts",
|
||||
"../services/codefixes/fixClassIncorrectlyImplementsInterface.ts",
|
||||
"../services/codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
|
||||
"../services/codefixes/fixClassSuperMustPrecedeThisAccess.ts",
|
||||
"../services/codefixes/fixConstructorForDerivedNeedSuperCall.ts",
|
||||
"../services/codefixes/helpers.ts",
|
||||
"../services/codefixes/importFixes.ts",
|
||||
"../services/codefixes/unusedIdentifierFixes.ts",
|
||||
"../services/harness.ts",
|
||||
|
||||
"sourceMapRecorder.ts",
|
||||
"harnessLanguageService.ts",
|
||||
"fourslash.ts",
|
||||
|
||||
@@ -1620,7 +1620,7 @@ namespace ts.projectSystem {
|
||||
const configureHostRequest = makeSessionRequest<protocol.ConfigureRequestArguments>(CommandNames.Configure, { extraFileExtensions });
|
||||
session.executeCommand(configureHostRequest).response;
|
||||
|
||||
// HTML file still not included in the project as it is closed
|
||||
// HTML file still not included in the project as it is closed
|
||||
checkNumberOfProjects(projectService, { configuredProjects: 1 });
|
||||
checkProjectActualFiles(projectService.configuredProjects[0], [file1.path]);
|
||||
|
||||
@@ -3051,4 +3051,59 @@ namespace ts.projectSystem {
|
||||
service.checkNumberOfProjects({ externalProjects: 1 });
|
||||
});
|
||||
});
|
||||
|
||||
describe("maxNodeModuleJsDepth for inferred projects", () => {
|
||||
it("should be set to 2 if the project has js root files", () => {
|
||||
const file1: FileOrFolder = {
|
||||
path: "/a/b/file1.js",
|
||||
content: `var t = require("test"); t.`
|
||||
};
|
||||
const moduleFile: FileOrFolder = {
|
||||
path: "/a/b/node_modules/test/index.js",
|
||||
content: `var v = 10; module.exports = v;`
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, moduleFile]);
|
||||
const projectService = createProjectService(host);
|
||||
projectService.openClientFile(file1.path);
|
||||
|
||||
let project = projectService.inferredProjects[0];
|
||||
let options = project.getCompilerOptions();
|
||||
assert.isTrue(options.maxNodeModuleJsDepth === 2);
|
||||
|
||||
// Assert the option sticks
|
||||
projectService.setCompilerOptionsForInferredProjects({ target: ScriptTarget.ES2016 });
|
||||
project = projectService.inferredProjects[0];
|
||||
options = project.getCompilerOptions();
|
||||
assert.isTrue(options.maxNodeModuleJsDepth === 2);
|
||||
});
|
||||
|
||||
it("should return to normal state when all js root files are removed from project", () => {
|
||||
const file1 = {
|
||||
path: "/a/file1.ts",
|
||||
content: "let x =1;"
|
||||
};
|
||||
const file2 = {
|
||||
path: "/a/file2.js",
|
||||
content: "let x =1;"
|
||||
};
|
||||
|
||||
const host = createServerHost([file1, file2, libFile]);
|
||||
const projectService = createProjectService(host, { useSingleInferredProject: true });
|
||||
|
||||
projectService.openClientFile(file1.path);
|
||||
checkNumberOfInferredProjects(projectService, 1);
|
||||
let project = projectService.inferredProjects[0];
|
||||
assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth);
|
||||
|
||||
projectService.openClientFile(file2.path);
|
||||
project = projectService.inferredProjects[0];
|
||||
assert.isTrue(project.getCompilerOptions().maxNodeModuleJsDepth === 2);
|
||||
|
||||
projectService.closeClientFile(file2.path);
|
||||
project = projectService.inferredProjects[0];
|
||||
assert.isUndefined(project.getCompilerOptions().maxNodeModuleJsDepth);
|
||||
});
|
||||
});
|
||||
|
||||
}
|
||||
Vendored
+2
-1
@@ -1171,8 +1171,9 @@ interface Array<T> {
|
||||
/**
|
||||
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
|
||||
* @param start The zero-based location in the array from which to start removing elements.
|
||||
* @param deleteCount The number of elements to remove.
|
||||
*/
|
||||
splice(start: number): T[];
|
||||
splice(start: number, deleteCount?: number): T[];
|
||||
/**
|
||||
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
|
||||
* @param start The zero-based location in the array from which to start removing elements.
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"module": "commonjs",
|
||||
"sourceMap": true,
|
||||
"stripInternal": true,
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"cancellationToken.ts"
|
||||
|
||||
@@ -293,6 +293,7 @@ namespace ts.server {
|
||||
this.documentRegistry = createDocumentRegistry(host.useCaseSensitiveFileNames, host.getCurrentDirectory());
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
getChangedFiles_TestOnly() {
|
||||
return this.changedFiles;
|
||||
}
|
||||
@@ -1274,6 +1275,7 @@ namespace ts.server {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
synchronizeProjectList(knownProjects: protocol.ProjectVersionInfo[]): ProjectFilesWithTSDiagnostics[] {
|
||||
const files: ProjectFilesWithTSDiagnostics[] = [];
|
||||
this.collectChanges(knownProjects, this.externalProjects, files);
|
||||
@@ -1282,6 +1284,7 @@ namespace ts.server {
|
||||
return files;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
applyChangesInOpenFiles(openFiles: protocol.ExternalFile[], changedFiles: protocol.ChangedOpenFile[], closedFiles: string[]): void {
|
||||
const recordChangedFiles = changedFiles && !openFiles && !closedFiles;
|
||||
if (openFiles) {
|
||||
|
||||
+50
-9
@@ -58,6 +58,7 @@ namespace ts.server {
|
||||
return counts.ts === 0 && counts.tsx === 0;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface ProjectFilesWithTSDiagnostics extends protocol.ProjectFiles {
|
||||
projectErrors: Diagnostic[];
|
||||
}
|
||||
@@ -395,7 +396,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
removeFile(info: ScriptInfo, detachFromProject = true) {
|
||||
this.removeRootFileIfNecessary(info);
|
||||
if (this.isRoot(info)) {
|
||||
this.removeRoot(info);
|
||||
}
|
||||
this.lsHost.notifyFileRemoved(info);
|
||||
this.cachedUnresolvedImportsPerFile.remove(info.path);
|
||||
|
||||
@@ -566,9 +569,6 @@ namespace ts.server {
|
||||
|
||||
setCompilerOptions(compilerOptions: CompilerOptions) {
|
||||
if (compilerOptions) {
|
||||
if (this.projectKind === ProjectKind.Inferred) {
|
||||
compilerOptions.allowJs = true;
|
||||
}
|
||||
compilerOptions.allowNonTsExtensions = true;
|
||||
if (changesAffectModuleResolution(this.compilerOptions, compilerOptions)) {
|
||||
// reset cached unresolved imports if changes in compiler options affected module resolution
|
||||
@@ -593,6 +593,7 @@ namespace ts.server {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
|
||||
this.updateGraph();
|
||||
|
||||
@@ -696,11 +697,9 @@ namespace ts.server {
|
||||
}
|
||||
|
||||
// remove a root file from project
|
||||
private removeRootFileIfNecessary(info: ScriptInfo): void {
|
||||
if (this.isRoot(info)) {
|
||||
remove(this.rootFiles, info);
|
||||
this.rootFilesMap.remove(info.path);
|
||||
}
|
||||
protected removeRoot(info: ScriptInfo): void {
|
||||
remove(this.rootFiles, info);
|
||||
this.rootFilesMap.remove(info.path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -715,6 +714,32 @@ namespace ts.server {
|
||||
}
|
||||
})();
|
||||
|
||||
private _isJsInferredProject = false;
|
||||
|
||||
toggleJsInferredProject(isJsInferredProject: boolean) {
|
||||
if (isJsInferredProject !== this._isJsInferredProject) {
|
||||
this._isJsInferredProject = isJsInferredProject;
|
||||
this.setCompilerOptions();
|
||||
}
|
||||
}
|
||||
|
||||
setCompilerOptions(options?: CompilerOptions) {
|
||||
// Avoid manipulating the given options directly
|
||||
const newOptions = options ? clone(options) : this.getCompilerOptions();
|
||||
if (!newOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._isJsInferredProject && typeof newOptions.maxNodeModuleJsDepth !== "number") {
|
||||
newOptions.maxNodeModuleJsDepth = 2;
|
||||
}
|
||||
else if (!this._isJsInferredProject) {
|
||||
newOptions.maxNodeModuleJsDepth = undefined;
|
||||
}
|
||||
newOptions.allowJs = true;
|
||||
super.setCompilerOptions(newOptions);
|
||||
}
|
||||
|
||||
// Used to keep track of what directories are watched for this project
|
||||
directoriesWatchedForTsconfig: string[] = [];
|
||||
|
||||
@@ -729,6 +754,22 @@ namespace ts.server {
|
||||
/*compileOnSaveEnabled*/ false);
|
||||
}
|
||||
|
||||
addRoot(info: ScriptInfo) {
|
||||
if (!this._isJsInferredProject && info.isJavaScript()) {
|
||||
this.toggleJsInferredProject(/*isJsInferredProject*/ true);
|
||||
}
|
||||
super.addRoot(info);
|
||||
}
|
||||
|
||||
removeRoot(info: ScriptInfo) {
|
||||
if (this._isJsInferredProject && info.isJavaScript()) {
|
||||
if (filter(this.getRootScriptInfos(), info => info.isJavaScript()).length === 0) {
|
||||
this.toggleJsInferredProject(/*isJsInferredProject*/ false);
|
||||
}
|
||||
}
|
||||
super.removeRoot(info);
|
||||
}
|
||||
|
||||
getProjectRootPath() {
|
||||
// Single inferred project does not have a project root.
|
||||
if (this.projectService.useSingleInferredProject) {
|
||||
|
||||
@@ -355,5 +355,9 @@ namespace ts.server {
|
||||
positionToLineOffset(position: number): ILineInfo {
|
||||
return this.textStorage.positionToLineOffset(position);
|
||||
}
|
||||
|
||||
public isJavaScript() {
|
||||
return this.scriptKind === ScriptKind.JS || this.scriptKind === ScriptKind.JSX;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -88,50 +88,65 @@ namespace ts.server {
|
||||
|
||||
export namespace CommandNames {
|
||||
export const Brace: protocol.CommandTypes.Brace = "brace";
|
||||
/* @internal */
|
||||
export const BraceFull: protocol.CommandTypes.BraceFull = "brace-full";
|
||||
export const BraceCompletion: protocol.CommandTypes.BraceCompletion = "braceCompletion";
|
||||
export const Change: protocol.CommandTypes.Change = "change";
|
||||
export const Close: protocol.CommandTypes.Close = "close";
|
||||
export const Completions: protocol.CommandTypes.Completions = "completions";
|
||||
/* @internal */
|
||||
export const CompletionsFull: protocol.CommandTypes.CompletionsFull = "completions-full";
|
||||
export const CompletionDetails: protocol.CommandTypes.CompletionDetails = "completionEntryDetails";
|
||||
export const CompileOnSaveAffectedFileList: protocol.CommandTypes.CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList";
|
||||
export const CompileOnSaveEmitFile: protocol.CommandTypes.CompileOnSaveEmitFile = "compileOnSaveEmitFile";
|
||||
export const Configure: protocol.CommandTypes.Configure = "configure";
|
||||
export const Definition: protocol.CommandTypes.Definition = "definition";
|
||||
/* @internal */
|
||||
export const DefinitionFull: protocol.CommandTypes.DefinitionFull = "definition-full";
|
||||
export const Exit: protocol.CommandTypes.Exit = "exit";
|
||||
export const Format: protocol.CommandTypes.Format = "format";
|
||||
export const Formatonkey: protocol.CommandTypes.Formatonkey = "formatonkey";
|
||||
/* @internal */
|
||||
export const FormatFull: protocol.CommandTypes.FormatFull = "format-full";
|
||||
/* @internal */
|
||||
export const FormatonkeyFull: protocol.CommandTypes.FormatonkeyFull = "formatonkey-full";
|
||||
/* @internal */
|
||||
export const FormatRangeFull: protocol.CommandTypes.FormatRangeFull = "formatRange-full";
|
||||
export const Geterr: protocol.CommandTypes.Geterr = "geterr";
|
||||
export const GeterrForProject: protocol.CommandTypes.GeterrForProject = "geterrForProject";
|
||||
export const Implementation: protocol.CommandTypes.Implementation = "implementation";
|
||||
/* @internal */
|
||||
export const ImplementationFull: protocol.CommandTypes.ImplementationFull = "implementation-full";
|
||||
export const SemanticDiagnosticsSync: protocol.CommandTypes.SemanticDiagnosticsSync = "semanticDiagnosticsSync";
|
||||
export const SyntacticDiagnosticsSync: protocol.CommandTypes.SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
|
||||
export const NavBar: protocol.CommandTypes.NavBar = "navbar";
|
||||
/* @internal */
|
||||
export const NavBarFull: protocol.CommandTypes.NavBarFull = "navbar-full";
|
||||
export const NavTree: protocol.CommandTypes.NavTree = "navtree";
|
||||
export const NavTreeFull: protocol.CommandTypes.NavTreeFull = "navtree-full";
|
||||
export const Navto: protocol.CommandTypes.Navto = "navto";
|
||||
/* @internal */
|
||||
export const NavtoFull: protocol.CommandTypes.NavtoFull = "navto-full";
|
||||
export const Occurrences: protocol.CommandTypes.Occurrences = "occurrences";
|
||||
export const DocumentHighlights: protocol.CommandTypes.DocumentHighlights = "documentHighlights";
|
||||
/* @internal */
|
||||
export const DocumentHighlightsFull: protocol.CommandTypes.DocumentHighlightsFull = "documentHighlights-full";
|
||||
export const Open: protocol.CommandTypes.Open = "open";
|
||||
export const Quickinfo: protocol.CommandTypes.Quickinfo = "quickinfo";
|
||||
/* @internal */
|
||||
export const QuickinfoFull: protocol.CommandTypes.QuickinfoFull = "quickinfo-full";
|
||||
export const References: protocol.CommandTypes.References = "references";
|
||||
/* @internal */
|
||||
export const ReferencesFull: protocol.CommandTypes.ReferencesFull = "references-full";
|
||||
export const Reload: protocol.CommandTypes.Reload = "reload";
|
||||
export const Rename: protocol.CommandTypes.Rename = "rename";
|
||||
/* @internal */
|
||||
export const RenameInfoFull: protocol.CommandTypes.RenameInfoFull = "rename-full";
|
||||
/* @internal */
|
||||
export const RenameLocationsFull: protocol.CommandTypes.RenameLocationsFull = "renameLocations-full";
|
||||
export const Saveto: protocol.CommandTypes.Saveto = "saveto";
|
||||
export const SignatureHelp: protocol.CommandTypes.SignatureHelp = "signatureHelp";
|
||||
/* @internal */
|
||||
export const SignatureHelpFull: protocol.CommandTypes.SignatureHelpFull = "signatureHelp-full";
|
||||
export const TypeDefinition: protocol.CommandTypes.TypeDefinition = "typeDefinition";
|
||||
export const ProjectInfo: protocol.CommandTypes.ProjectInfo = "projectInfo";
|
||||
@@ -140,19 +155,28 @@ namespace ts.server {
|
||||
export const OpenExternalProject: protocol.CommandTypes.OpenExternalProject = "openExternalProject";
|
||||
export const OpenExternalProjects: protocol.CommandTypes.OpenExternalProjects = "openExternalProjects";
|
||||
export const CloseExternalProject: protocol.CommandTypes.CloseExternalProject = "closeExternalProject";
|
||||
/* @internal */
|
||||
export const SynchronizeProjectList: protocol.CommandTypes.SynchronizeProjectList = "synchronizeProjectList";
|
||||
/* @internal */
|
||||
export const ApplyChangedToOpenFiles: protocol.CommandTypes.ApplyChangedToOpenFiles = "applyChangedToOpenFiles";
|
||||
/* @internal */
|
||||
export const EncodedSemanticClassificationsFull: protocol.CommandTypes.EncodedSemanticClassificationsFull = "encodedSemanticClassifications-full";
|
||||
/* @internal */
|
||||
export const Cleanup: protocol.CommandTypes.Cleanup = "cleanup";
|
||||
/* @internal */
|
||||
export const OutliningSpans: protocol.CommandTypes.OutliningSpans = "outliningSpans";
|
||||
export const TodoComments: protocol.CommandTypes.TodoComments = "todoComments";
|
||||
export const Indentation: protocol.CommandTypes.Indentation = "indentation";
|
||||
export const DocCommentTemplate: protocol.CommandTypes.DocCommentTemplate = "docCommentTemplate";
|
||||
/* @internal */
|
||||
export const CompilerOptionsDiagnosticsFull: protocol.CommandTypes.CompilerOptionsDiagnosticsFull = "compilerOptionsDiagnostics-full";
|
||||
/* @internal */
|
||||
export const NameOrDottedNameSpan: protocol.CommandTypes.NameOrDottedNameSpan = "nameOrDottedNameSpan";
|
||||
/* @internal */
|
||||
export const BreakpointStatement: protocol.CommandTypes.BreakpointStatement = "breakpointStatement";
|
||||
export const CompilerOptionsForInferredProjects: protocol.CommandTypes.CompilerOptionsForInferredProjects = "compilerOptionsForInferredProjects";
|
||||
export const GetCodeFixes: protocol.CommandTypes.GetCodeFixes = "getCodeFixes";
|
||||
/* @internal */
|
||||
export const GetCodeFixesFull: protocol.CommandTypes.GetCodeFixesFull = "getCodeFixes-full";
|
||||
export const GetSupportedCodeFixes: protocol.CommandTypes.GetSupportedCodeFixes = "getSupportedCodeFixes";
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="types.d.ts" />
|
||||
/// <reference path="types.ts" />
|
||||
|
||||
namespace ts.server {
|
||||
export const ActionSet: ActionSet = "action::set";
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"outFile": "../../built/local/tsserver.js",
|
||||
"sourceMap": true,
|
||||
"stripInternal": true,
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"../services/shims.ts",
|
||||
|
||||
@@ -1,29 +1,30 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"removeComments": true,
|
||||
"noImplicitThis": true,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"outFile": "../../built/local/tsserverlibrary.js",
|
||||
"sourceMap": true,
|
||||
"stripInternal": true,
|
||||
"declaration": true,
|
||||
"types": [],
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
"noUnusedParameters": true,
|
||||
"declaration": true
|
||||
},
|
||||
"files": [
|
||||
"../services/shims.ts",
|
||||
"../services/utilities.ts",
|
||||
"shared.ts",
|
||||
"utilities.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"scriptInfo.ts",
|
||||
"lshost.ts",
|
||||
"typingsCache.ts",
|
||||
"project.ts",
|
||||
"editorServices.ts",
|
||||
"protocol.d.ts",
|
||||
"session.ts"
|
||||
"lsHost.ts",
|
||||
"project.ts",
|
||||
"protocol.ts",
|
||||
"scriptInfo.ts",
|
||||
"scriptVersionCache.ts",
|
||||
"session.ts",
|
||||
"shared.ts",
|
||||
"types.ts",
|
||||
"typingsCache.ts",
|
||||
"utilities.ts",
|
||||
"../services/shims.ts",
|
||||
"../services/utilities.ts"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -82,6 +82,7 @@ declare namespace ts.server {
|
||||
readonly installSuccess: boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface InstallTypingHost extends JsTyping.TypingResolutionHost {
|
||||
writeFile(path: string, content: string): void;
|
||||
createDirectory(path: string): void;
|
||||
@@ -1,22 +1,14 @@
|
||||
{
|
||||
"extends": "../../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"removeComments": true,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"outFile": "../../../built/local/typingsInstaller.js",
|
||||
"sourceMap": true,
|
||||
"stripInternal": true,
|
||||
"types": [
|
||||
"node"
|
||||
],
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"../types.d.ts",
|
||||
"../types.ts",
|
||||
"../shared.ts",
|
||||
"typingsInstaller.ts",
|
||||
"nodeTypingsInstaller.ts"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/// <reference path="../../compiler/core.ts" />
|
||||
/// <reference path="../../compiler/moduleNameResolver.ts" />
|
||||
/// <reference path="../../services/jsTyping.ts"/>
|
||||
/// <reference path="../types.d.ts"/>
|
||||
/// <reference path="../types.ts"/>
|
||||
/// <reference path="../shared.ts"/>
|
||||
|
||||
namespace ts.server.typingsInstaller {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/// <reference path="types.d.ts" />
|
||||
/// <reference path="types.ts" />
|
||||
/// <reference path="shared.ts" />
|
||||
|
||||
namespace ts.server {
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2.code],
|
||||
getCodeActions: getActionForClassLikeMissingAbstractMember
|
||||
});
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Non_abstract_class_expression_does_not_implement_inherited_abstract_member_0_from_class_1.code],
|
||||
getCodeActions: getActionForClassLikeMissingAbstractMember
|
||||
});
|
||||
|
||||
function getActionForClassLikeMissingAbstractMember(context: CodeFixContext): CodeAction[] | undefined {
|
||||
const sourceFile = context.sourceFile;
|
||||
const start = context.span.start;
|
||||
// This is the identifier in the case of a class declaration
|
||||
// or the class keyword token in the case of a class expression.
|
||||
const token = getTokenAtPosition(sourceFile, start);
|
||||
const checker = context.program.getTypeChecker();
|
||||
|
||||
if (isClassLike(token.parent)) {
|
||||
const classDecl = token.parent as ClassLikeDeclaration;
|
||||
const startPos = classDecl.members.pos;
|
||||
|
||||
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
|
||||
const instantiatedExtendsType = checker.getBaseTypes(classType)[0];
|
||||
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
// so duplicates cannot occur.
|
||||
const extendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType);
|
||||
const abstractAndNonPrivateExtendsSymbols = extendsSymbols.filter(symbolPointsToNonPrivateAndAbstractMember);
|
||||
|
||||
const insertion = getMissingMembersInsertion(classDecl, abstractAndNonPrivateExtendsSymbols, checker, context.newLineCharacter);
|
||||
|
||||
if (insertion.length) {
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: insertion
|
||||
}]
|
||||
}]
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
|
||||
}
|
||||
|
||||
function symbolPointsToNonPrivateAndAbstractMember(symbol: Symbol): boolean {
|
||||
const decls = symbol.getDeclarations();
|
||||
Debug.assert(!!(decls && decls.length > 0));
|
||||
const flags = getModifierFlags(decls[0]);
|
||||
return !(flags & ModifierFlags.Private) && !!(flags & ModifierFlags.Abstract);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Class_0_incorrectly_implements_interface_1.code],
|
||||
getCodeActions: getActionForClassLikeIncorrectImplementsInterface
|
||||
});
|
||||
|
||||
function getActionForClassLikeIncorrectImplementsInterface(context: CodeFixContext): CodeAction[] | undefined {
|
||||
const sourceFile = context.sourceFile;
|
||||
const start = context.span.start;
|
||||
const token = getTokenAtPosition(sourceFile, start);
|
||||
const checker = context.program.getTypeChecker();
|
||||
|
||||
const classDecl = getContainingClass(token);
|
||||
if (!classDecl) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const startPos: number = classDecl.members.pos;
|
||||
const classType = checker.getTypeAtLocation(classDecl);
|
||||
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
|
||||
|
||||
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
|
||||
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
|
||||
|
||||
const result: CodeAction[] = [];
|
||||
for (const implementedTypeNode of implementedTypeNodes) {
|
||||
const implementedType = checker.getTypeFromTypeNode(implementedTypeNode) as InterfaceType;
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
// so duplicates cannot occur.
|
||||
const implementedTypeSymbols = checker.getPropertiesOfType(implementedType);
|
||||
const nonPrivateMembers = implementedTypeSymbols.filter(symbol => !(getModifierFlags(symbol.valueDeclaration) & ModifierFlags.Private));
|
||||
|
||||
let insertion = getMissingIndexSignatureInsertion(implementedType, IndexKind.Number, classDecl, hasNumericIndexSignature);
|
||||
insertion += getMissingIndexSignatureInsertion(implementedType, IndexKind.String, classDecl, hasStringIndexSignature);
|
||||
insertion += getMissingMembersInsertion(classDecl, nonPrivateMembers, checker, context.newLineCharacter);
|
||||
|
||||
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
|
||||
if (insertion) {
|
||||
pushAction(result, insertion, message);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
function getMissingIndexSignatureInsertion(type: InterfaceType, kind: IndexKind, enclosingDeclaration: ClassLikeDeclaration, hasIndexSigOfKind: boolean) {
|
||||
if (!hasIndexSigOfKind) {
|
||||
const IndexInfoOfKind = checker.getIndexInfoOfType(type, kind);
|
||||
if (IndexInfoOfKind) {
|
||||
const writer = getSingleLineStringWriter();
|
||||
checker.getSymbolDisplayBuilder().buildIndexSignatureDisplay(IndexInfoOfKind, writer, kind, enclosingDeclaration);
|
||||
const result = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
function pushAction(result: CodeAction[], insertion: string, description: string): void {
|
||||
const newAction: CodeAction = {
|
||||
description: description,
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: insertion
|
||||
}]
|
||||
}]
|
||||
};
|
||||
result.push(newAction);
|
||||
}
|
||||
}
|
||||
}
|
||||
-23
@@ -1,28 +1,5 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) {
|
||||
// First token is the open curly, this is where we want to put the 'super' call.
|
||||
return constructor.body.getFirstToken(sourceFile).getEnd();
|
||||
}
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start);
|
||||
|
||||
if (token.kind !== SyntaxKind.ConstructorKeyword) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>token.parent, sourceFile);
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
|
||||
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }]
|
||||
}];
|
||||
}
|
||||
});
|
||||
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.super_must_be_called_before_accessing_this_in_the_constructor_of_a_derived_class.code],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
@@ -0,0 +1,20 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Constructors_for_derived_classes_must_contain_a_super_call.code],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const token = getTokenAtPosition(sourceFile, context.span.start);
|
||||
|
||||
if (token.kind !== SyntaxKind.ConstructorKeyword) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const newPosition = getOpenBraceEnd(<ConstructorDeclaration>token.parent, sourceFile);
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Add_missing_super_call),
|
||||
changes: [{ fileName: sourceFile.fileName, textChanges: [{ newText: "super();", span: { start: newPosition, length: 0 } }] }]
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
registerCodeFix({
|
||||
errorCodes: [Diagnostics.Cannot_extend_an_interface_0_Did_you_mean_implements.code],
|
||||
getCodeActions: (context: CodeFixContext) => {
|
||||
const sourceFile = context.sourceFile;
|
||||
const start = context.span.start;
|
||||
const token = getTokenAtPosition(sourceFile, start);
|
||||
const classDeclNode = getContainingClass(token);
|
||||
if (!(token.kind === SyntaxKind.Identifier && isClassLike(classDeclNode))) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const heritageClauses = classDeclNode.heritageClauses;
|
||||
if (!(heritageClauses && heritageClauses.length > 0)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const extendsToken = heritageClauses[0].getFirstToken();
|
||||
if (!(extendsToken && extendsToken.kind === SyntaxKind.ExtendsKeyword)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
let changeStart = extendsToken.getStart(sourceFile);
|
||||
let changeEnd = extendsToken.getEnd();
|
||||
const textChanges: TextChange[] = [{ newText: " implements", span: { start: changeStart, length: changeEnd - changeStart } }];
|
||||
|
||||
// We replace existing keywords with commas.
|
||||
for (let i = 1; i < heritageClauses.length; i++) {
|
||||
const keywordToken = heritageClauses[i].getFirstToken();
|
||||
if (keywordToken) {
|
||||
changeStart = keywordToken.getStart(sourceFile);
|
||||
changeEnd = keywordToken.getEnd();
|
||||
textChanges.push({ newText: ",", span: { start: changeStart, length: changeEnd - changeStart } });
|
||||
}
|
||||
}
|
||||
|
||||
const result = [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Change_extends_to_implements),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: textChanges
|
||||
}]
|
||||
}];
|
||||
|
||||
return result;
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -1,3 +1,9 @@
|
||||
///<reference path='superFixes.ts' />
|
||||
///<reference path='importFixes.ts' />
|
||||
///<reference path='unusedIdentifierFixes.ts' />
|
||||
/// <reference path="fixClassIncorrectlyImplementsInterface.ts" />
|
||||
/// <reference path="fixClassDoesntImplementInheritedAbstractMember.ts" />
|
||||
/// <reference path="fixClassSuperMustPrecedeThisAccess.ts" />
|
||||
/// <reference path="fixConstructorForDerivedNeedSuperCall.ts" />
|
||||
/// <reference path="fixExtendsInterfaceBecomesImplements.ts" />
|
||||
/// <reference path='unusedIdentifierFixes.ts' />
|
||||
/// <reference path='importFixes.ts' />
|
||||
/// <reference path='helpers.ts' />
|
||||
|
||||
|
||||
@@ -0,0 +1,156 @@
|
||||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
|
||||
/**
|
||||
* Finds members of the resolved type that are missing in the class pointed to by class decl
|
||||
* and generates source code for the missing members.
|
||||
* @param possiblyMissingSymbols The collection of symbols to filter and then get insertions for.
|
||||
* @returns Empty string iff there are no member insertions.
|
||||
*/
|
||||
export function getMissingMembersInsertion(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker, newlineChar: string): string {
|
||||
const classMembers = classDeclaration.symbol.members;
|
||||
const missingMembers = possiblyMissingSymbols.filter(symbol => !(symbol.getName() in classMembers));
|
||||
|
||||
let insertion = "";
|
||||
|
||||
for (const symbol of missingMembers) {
|
||||
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
|
||||
}
|
||||
return insertion;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns Empty string iff there we can't figure out a representation for `symbol` in `enclosingDeclaration`.
|
||||
*/
|
||||
function getInsertionForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker, newlineChar: string): string {
|
||||
// const name = symbol.getName();
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (!(declarations && declarations.length)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
const declaration = declarations[0] as Declaration;
|
||||
const name = declaration.name ? declaration.name.getText() : undefined;
|
||||
const visibility = getVisibilityPrefix(getModifierFlags(declaration));
|
||||
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.PropertySignature:
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
const typeString = checker.typeToString(type, enclosingDeclaration, TypeFormatFlags.None);
|
||||
return `${visibility}${name}: ${typeString};${newlineChar}`;
|
||||
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
// The signature for the implementation appears as an entry in `signatures` iff
|
||||
// there is only one signature.
|
||||
// If there are overloads and an implementation signature, it appears as an
|
||||
// extra declaration that isn't a signature for `type`.
|
||||
// If there is more than one overload but no implementation signature
|
||||
// (eg: an abstract method or interface declaration), there is a 1-1
|
||||
// correspondence of declarations and signatures.
|
||||
const signatures = checker.getSignaturesOfType(type, SignatureKind.Call);
|
||||
if (!(signatures && signatures.length > 0)) {
|
||||
return "";
|
||||
}
|
||||
if (declarations.length === 1) {
|
||||
Debug.assert(signatures.length === 1);
|
||||
const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
|
||||
}
|
||||
|
||||
let result = "";
|
||||
for (let i = 0; i < signatures.length; i++) {
|
||||
const sigString = checker.signatureToString(signatures[i], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
result += `${visibility}${name}${sigString};${newlineChar}`;
|
||||
}
|
||||
|
||||
// If there is a declaration with a body, it is the last declaration,
|
||||
// and it isn't caught by `getSignaturesOfType`.
|
||||
let bodySig: Signature | undefined = undefined;
|
||||
if (declarations.length > signatures.length) {
|
||||
bodySig = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
|
||||
}
|
||||
else {
|
||||
Debug.assert(declarations.length === signatures.length);
|
||||
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
|
||||
}
|
||||
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
result += `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
|
||||
|
||||
return result;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
function createBodySignatureWithAnyTypes(signatures: Signature[], enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Signature {
|
||||
const newSignatureDeclaration = createNode(SyntaxKind.CallSignature) as SignatureDeclaration;
|
||||
newSignatureDeclaration.parent = enclosingDeclaration;
|
||||
newSignatureDeclaration.name = signatures[0].getDeclaration().name;
|
||||
|
||||
let maxNonRestArgs = -1;
|
||||
let maxArgsIndex = 0;
|
||||
let minArgumentCount = signatures[0].minArgumentCount;
|
||||
let hasRestParameter = false;
|
||||
for (let i = 0; i < signatures.length; i++) {
|
||||
const sig = signatures[i];
|
||||
minArgumentCount = Math.min(sig.minArgumentCount, minArgumentCount);
|
||||
hasRestParameter = hasRestParameter || sig.hasRestParameter;
|
||||
const nonRestLength = sig.parameters.length - (sig.hasRestParameter ? 1 : 0);
|
||||
if (nonRestLength > maxNonRestArgs) {
|
||||
maxNonRestArgs = nonRestLength;
|
||||
maxArgsIndex = i;
|
||||
}
|
||||
}
|
||||
const maxArgsParameterSymbolNames = signatures[maxArgsIndex].getParameters().map(symbol => symbol.getName());
|
||||
|
||||
const optionalToken = createToken(SyntaxKind.QuestionToken);
|
||||
|
||||
newSignatureDeclaration.parameters = createNodeArray<ParameterDeclaration>();
|
||||
for (let i = 0; i < maxNonRestArgs; i++) {
|
||||
const newParameter = createParameterDeclarationWithoutType(i, minArgumentCount, newSignatureDeclaration);
|
||||
newSignatureDeclaration.parameters.push(newParameter);
|
||||
}
|
||||
|
||||
if (hasRestParameter) {
|
||||
const restParameter = createParameterDeclarationWithoutType(maxNonRestArgs, minArgumentCount, newSignatureDeclaration);
|
||||
restParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
|
||||
newSignatureDeclaration.parameters.push(restParameter);
|
||||
}
|
||||
|
||||
return checker.getSignatureFromDeclaration(newSignatureDeclaration);
|
||||
|
||||
function createParameterDeclarationWithoutType(index: number, minArgCount: number, enclosingSignatureDeclaration: SignatureDeclaration): ParameterDeclaration {
|
||||
const newParameter = createNode(SyntaxKind.Parameter) as ParameterDeclaration;
|
||||
|
||||
newParameter.symbol = new SymbolConstructor(SymbolFlags.FunctionScopedVariable, maxArgsParameterSymbolNames[index] || "rest");
|
||||
newParameter.symbol.valueDeclaration = newParameter;
|
||||
newParameter.symbol.declarations = [newParameter];
|
||||
newParameter.parent = enclosingSignatureDeclaration;
|
||||
if (index >= minArgCount) {
|
||||
newParameter.questionToken = optionalToken;
|
||||
}
|
||||
|
||||
return newParameter;
|
||||
}
|
||||
}
|
||||
|
||||
function getMethodBodyStub(newLineChar: string) {
|
||||
return ` {${newLineChar}throw new Error('Method not implemented.');${newLineChar}}${newLineChar}`;
|
||||
}
|
||||
|
||||
function getVisibilityPrefix(flags: ModifierFlags): string {
|
||||
if (flags & ModifierFlags.Public) {
|
||||
return "public ";
|
||||
}
|
||||
else if (flags & ModifierFlags.Protected) {
|
||||
return "protected ";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const SymbolConstructor = objectAllocator.getSymbolConstructor();
|
||||
}
|
||||
@@ -420,10 +420,10 @@ namespace ts.codefix {
|
||||
const options = context.program.getCompilerOptions();
|
||||
|
||||
return tryGetModuleNameFromAmbientModule() ||
|
||||
tryGetModuleNameFromBaseUrl() ||
|
||||
tryGetModuleNameFromRootDirs() ||
|
||||
tryGetModuleNameFromTypeRoots() ||
|
||||
tryGetModuleNameAsNodeModule() ||
|
||||
tryGetModuleNameFromBaseUrl() ||
|
||||
tryGetModuleNameFromRootDirs() ||
|
||||
removeFileExtension(getRelativePath(moduleFileName, sourceDirectory));
|
||||
|
||||
function tryGetModuleNameFromAmbientModule(): string {
|
||||
@@ -443,6 +443,7 @@ namespace ts.codefix {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const relativeNameWithIndex = removeFileExtension(relativeName);
|
||||
relativeName = removeExtensionAndIndexPostFix(relativeName);
|
||||
|
||||
if (options.paths) {
|
||||
@@ -462,7 +463,7 @@ namespace ts.codefix {
|
||||
return key.replace("\*", matchedStar);
|
||||
}
|
||||
}
|
||||
else if (pattern === relativeName) {
|
||||
else if (pattern === relativeName || pattern === relativeNameWithIndex) {
|
||||
return key;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +146,7 @@ namespace ts.codefix {
|
||||
|
||||
function createCodeFix(newText: string, start: number, length: number): CodeAction[] {
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Remove_unused_identifiers),
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), { 0: token.getText() }),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{ newText, span: { start, length } }]
|
||||
|
||||
+27
-26
@@ -1,8 +1,6 @@
|
||||
/// <reference path='../compiler/utilities.ts' />
|
||||
|
||||
/* @internal */
|
||||
namespace ts.Completions {
|
||||
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo {
|
||||
export function getCompletionsAtPosition(host: LanguageServiceHost, typeChecker: TypeChecker, log: (message: string) => void, compilerOptions: CompilerOptions, sourceFile: SourceFile, position: number): CompletionInfo | undefined {
|
||||
if (isInReferenceComment(sourceFile, position)) {
|
||||
return getTripleSlashReferenceCompletion(sourceFile, position);
|
||||
}
|
||||
@@ -134,7 +132,7 @@ namespace ts.Completions {
|
||||
return uniqueNames;
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number) {
|
||||
function getStringLiteralCompletionEntries(sourceFile: SourceFile, position: number): CompletionInfo | undefined {
|
||||
const node = findPrecedingToken(position, sourceFile);
|
||||
if (!node || node.kind !== SyntaxKind.StringLiteral) {
|
||||
return undefined;
|
||||
@@ -174,7 +172,7 @@ namespace ts.Completions {
|
||||
return getStringLiteralCompletionEntriesFromModuleNames(<StringLiteral>node);
|
||||
}
|
||||
else {
|
||||
const argumentInfo = SignatureHelp.getContainingArgumentInfo(node, position, sourceFile);
|
||||
const argumentInfo = SignatureHelp.getImmediatelyContainingArgumentInfo(node, position, sourceFile);
|
||||
if (argumentInfo) {
|
||||
// Get string literal completions from specialized signatures of the target
|
||||
// i.e. declare function f(a: 'A');
|
||||
@@ -188,7 +186,7 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement) {
|
||||
function getStringLiteralCompletionEntriesFromPropertyAssignment(element: ObjectLiteralElement): CompletionInfo | undefined {
|
||||
const type = typeChecker.getContextualType((<ObjectLiteralExpression>element.parent));
|
||||
const entries: CompletionEntry[] = [];
|
||||
if (type) {
|
||||
@@ -199,7 +197,7 @@ namespace ts.Completions {
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo) {
|
||||
function getStringLiteralCompletionEntriesFromCallExpression(argumentInfo: SignatureHelp.ArgumentListInfo): CompletionInfo | undefined {
|
||||
const candidates: Signature[] = [];
|
||||
const entries: CompletionEntry[] = [];
|
||||
|
||||
@@ -219,7 +217,7 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression) {
|
||||
function getStringLiteralCompletionEntriesFromElementAccess(node: ElementAccessExpression): CompletionInfo | undefined {
|
||||
const type = typeChecker.getTypeAtLocation(node.expression);
|
||||
const entries: CompletionEntry[] = [];
|
||||
if (type) {
|
||||
@@ -231,7 +229,7 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral) {
|
||||
function getStringLiteralCompletionEntriesFromContextualType(node: StringLiteral): CompletionInfo | undefined {
|
||||
const type = typeChecker.getContextualType(node);
|
||||
if (type) {
|
||||
const entries: CompletionEntry[] = [];
|
||||
@@ -243,23 +241,26 @@ namespace ts.Completions {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function addStringLiteralCompletionsFromType(type: Type, result: CompletionEntry[]): void {
|
||||
function addStringLiteralCompletionsFromType(type: Type, result: Push<CompletionEntry>): void {
|
||||
if (type && type.flags & TypeFlags.TypeParameter) {
|
||||
type = typeChecker.getApparentType(type);
|
||||
}
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
forEach((<UnionType>type).types, t => addStringLiteralCompletionsFromType(t, result));
|
||||
}
|
||||
else {
|
||||
if (type.flags & TypeFlags.StringLiteral) {
|
||||
result.push({
|
||||
name: (<LiteralType>type).text,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
kind: ScriptElementKind.variableElement,
|
||||
sortText: "0"
|
||||
});
|
||||
for (const t of (<UnionType>type).types) {
|
||||
addStringLiteralCompletionsFromType(t, result);
|
||||
}
|
||||
}
|
||||
else if (type.flags & TypeFlags.StringLiteral) {
|
||||
result.push({
|
||||
name: (<LiteralType>type).text,
|
||||
kindModifiers: ScriptElementKindModifier.none,
|
||||
kind: ScriptElementKind.variableElement,
|
||||
sortText: "0"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getStringLiteralCompletionEntriesFromModuleNames(node: StringLiteral): CompletionInfo {
|
||||
@@ -1317,14 +1318,14 @@ namespace ts.Completions {
|
||||
isMemberCompletion = true;
|
||||
isNewIdentifierLocation = false;
|
||||
|
||||
let exports: Symbol[];
|
||||
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(importOrExportDeclaration.moduleSpecifier);
|
||||
if (moduleSpecifierSymbol) {
|
||||
exports = typeChecker.getExportsOfModule(moduleSpecifierSymbol);
|
||||
const moduleSpecifierSymbol = typeChecker.getSymbolAtLocation(moduleSpecifier);
|
||||
if (!moduleSpecifierSymbol) {
|
||||
symbols = emptyArray;
|
||||
return true;
|
||||
}
|
||||
|
||||
symbols = exports ? filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements) : emptyArray;
|
||||
|
||||
const exports = typeChecker.getExportsAndPropertiesOfModule(moduleSpecifierSymbol);
|
||||
symbols = filterNamedImportOrExportCompletionItems(exports, namedImportsOrExports.elements);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -325,7 +325,7 @@ namespace ts.FindAllReferences {
|
||||
fileName: targetLabel.getSourceFile().fileName,
|
||||
kind: ScriptElementKind.label,
|
||||
name: labelName,
|
||||
textSpan: createTextSpanFromBounds(targetLabel.getStart(), targetLabel.getEnd()),
|
||||
textSpan: createTextSpanFromNode(targetLabel, sourceFile),
|
||||
displayParts: [displayPart(labelName, SymbolDisplayPartKind.text)]
|
||||
};
|
||||
|
||||
@@ -502,9 +502,8 @@ namespace ts.FindAllReferences {
|
||||
const result: Node[] = [];
|
||||
|
||||
for (const decl of classSymbol.members["__constructor"].declarations) {
|
||||
Debug.assert(decl.kind === SyntaxKind.Constructor);
|
||||
const ctrKeyword = decl.getChildAt(0);
|
||||
Debug.assert(ctrKeyword.kind === SyntaxKind.ConstructorKeyword);
|
||||
const ctrKeyword = ts.findChildOfKind(decl, ts.SyntaxKind.ConstructorKeyword, sourceFile)!
|
||||
Debug.assert(decl.kind === SyntaxKind.Constructor && !!ctrKeyword);
|
||||
result.push(ctrKeyword);
|
||||
}
|
||||
|
||||
@@ -871,7 +870,7 @@ namespace ts.FindAllReferences {
|
||||
fileName: node.getSourceFile().fileName,
|
||||
kind: ScriptElementKind.variableElement,
|
||||
name: "this",
|
||||
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
|
||||
textSpan: createTextSpanFromNode(node),
|
||||
displayParts
|
||||
},
|
||||
references: references
|
||||
@@ -942,7 +941,7 @@ namespace ts.FindAllReferences {
|
||||
fileName: node.getSourceFile().fileName,
|
||||
kind: ScriptElementKind.variableElement,
|
||||
name: type.text,
|
||||
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
|
||||
textSpan: createTextSpanFromNode(node),
|
||||
displayParts: [displayPart(getTextOfNode(node), SymbolDisplayPartKind.stringLiteral)]
|
||||
},
|
||||
references: references
|
||||
|
||||
@@ -15,10 +15,8 @@ namespace ts.GoToDefinition {
|
||||
const typeReferenceDirective = findReferenceInPosition(sourceFile.typeReferenceDirectives, position);
|
||||
if (typeReferenceDirective) {
|
||||
const referenceFile = program.getResolvedTypeReferenceDirectives()[typeReferenceDirective.fileName];
|
||||
if (referenceFile && referenceFile.resolvedFileName) {
|
||||
return [getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
|
||||
}
|
||||
return undefined;
|
||||
return referenceFile && referenceFile.resolvedFileName &&
|
||||
[getDefinitionInfoForFileReference(typeReferenceDirective.fileName, referenceFile.resolvedFileName)];
|
||||
}
|
||||
|
||||
const node = getTouchingPropertyName(sourceFile, position);
|
||||
@@ -30,7 +28,7 @@ namespace ts.GoToDefinition {
|
||||
if (isJumpStatementTarget(node)) {
|
||||
const labelName = (<Identifier>node).text;
|
||||
const label = getTargetLabel((<BreakOrContinueStatement>node.parent), (<Identifier>node).text);
|
||||
return label ? [createDefinitionInfo(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined;
|
||||
return label ? [createDefinitionInfoFromName(label, ScriptElementKind.label, labelName, /*containerName*/ undefined)] : undefined;
|
||||
}
|
||||
|
||||
const typeChecker = program.getTypeChecker();
|
||||
@@ -171,33 +169,38 @@ namespace ts.GoToDefinition {
|
||||
|
||||
function tryAddSignature(signatureDeclarations: Declaration[], selectConstructors: boolean, symbolKind: string, symbolName: string, containerName: string, result: DefinitionInfo[]) {
|
||||
const declarations: Declaration[] = [];
|
||||
let definition: Declaration;
|
||||
let definition: Declaration | undefined;
|
||||
|
||||
forEach(signatureDeclarations, d => {
|
||||
if ((selectConstructors && d.kind === SyntaxKind.Constructor) ||
|
||||
(!selectConstructors && (d.kind === SyntaxKind.FunctionDeclaration || d.kind === SyntaxKind.MethodDeclaration || d.kind === SyntaxKind.MethodSignature))) {
|
||||
for (const d of signatureDeclarations) {
|
||||
if (selectConstructors ? d.kind === SyntaxKind.Constructor : isSignatureDeclaration(d)) {
|
||||
declarations.push(d);
|
||||
if ((<FunctionLikeDeclaration>d).body) definition = d;
|
||||
}
|
||||
});
|
||||
|
||||
if (definition) {
|
||||
result.push(createDefinitionInfo(definition, symbolKind, symbolName, containerName));
|
||||
return true;
|
||||
}
|
||||
else if (declarations.length) {
|
||||
result.push(createDefinitionInfo(lastOrUndefined(declarations), symbolKind, symbolName, containerName));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (declarations.length) {
|
||||
result.push(createDefinitionInfo(definition || lastOrUndefined(declarations), symbolKind, symbolName, containerName));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function createDefinitionInfo(node: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
|
||||
function isSignatureDeclaration(node: Node): boolean {
|
||||
return node.kind === SyntaxKind.FunctionDeclaration || node.kind === SyntaxKind.MethodDeclaration || node.kind === SyntaxKind.MethodSignature
|
||||
}
|
||||
|
||||
/** Creates a DefinitionInfo from a Declaration, using the declaration's name if possible. */
|
||||
function createDefinitionInfo(node: Declaration, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
|
||||
return createDefinitionInfoFromName(node.name || node, symbolKind, symbolName, containerName);
|
||||
}
|
||||
|
||||
/** Creates a DefinitionInfo directly from the name of a declaration. */
|
||||
function createDefinitionInfoFromName(name: Node, symbolKind: string, symbolName: string, containerName: string): DefinitionInfo {
|
||||
const sourceFile = name.getSourceFile();
|
||||
return {
|
||||
fileName: node.getSourceFile().fileName,
|
||||
textSpan: createTextSpanFromBounds(node.getStart(), node.getEnd()),
|
||||
fileName: sourceFile.fileName,
|
||||
textSpan: createTextSpanFromNode(name, sourceFile),
|
||||
kind: symbolKind,
|
||||
name: symbolName,
|
||||
containerKind: undefined,
|
||||
|
||||
@@ -199,7 +199,7 @@ namespace ts.NavigateTo {
|
||||
matchKind: PatternMatchKind[rawItem.matchKind],
|
||||
isCaseSensitive: rawItem.isCaseSensitive,
|
||||
fileName: rawItem.fileName,
|
||||
textSpan: createTextSpanFromBounds(declaration.getStart(), declaration.getEnd()),
|
||||
textSpan: createTextSpanFromNode(declaration),
|
||||
// TODO(jfreeman): What should be the containerName when the container has a computed name?
|
||||
containerName: container && container.name ? (<Identifier>container.name).text : "",
|
||||
containerKind: container && container.name ? getNodeKind(container) : ""
|
||||
|
||||
@@ -514,7 +514,7 @@ namespace ts.NavigationBar {
|
||||
return {
|
||||
text: getItemName(n.node),
|
||||
kind: getNodeKind(n.node),
|
||||
kindModifiers: getNodeModifiers(n.node),
|
||||
kindModifiers: getModifiers(n.node),
|
||||
spans: getSpans(n),
|
||||
childItems: map(n.children, convertToTree)
|
||||
};
|
||||
@@ -524,7 +524,7 @@ namespace ts.NavigationBar {
|
||||
return {
|
||||
text: getItemName(n.node),
|
||||
kind: getNodeKind(n.node),
|
||||
kindModifiers: getNodeModifiers(n.node),
|
||||
kindModifiers: getModifiers(n.node),
|
||||
spans: getSpans(n),
|
||||
childItems: map(n.children, convertToChildItem) || emptyChildItemArray,
|
||||
indent: n.indent,
|
||||
@@ -591,7 +591,14 @@ namespace ts.NavigationBar {
|
||||
function getNodeSpan(node: Node): TextSpan {
|
||||
return node.kind === SyntaxKind.SourceFile
|
||||
? createTextSpanFromBounds(node.getFullStart(), node.getEnd())
|
||||
: createTextSpanFromBounds(node.getStart(curSourceFile), node.getEnd());
|
||||
: createTextSpanFromNode(node, curSourceFile);
|
||||
}
|
||||
|
||||
function getModifiers(node: ts.Node): string {
|
||||
if (node.parent && node.parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
node = node.parent;
|
||||
}
|
||||
return getNodeModifiers(node);
|
||||
}
|
||||
|
||||
function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string {
|
||||
@@ -626,15 +633,15 @@ namespace ts.NavigationBar {
|
||||
|
||||
/**
|
||||
* Matches all whitespace characters in a string. Eg:
|
||||
*
|
||||
*
|
||||
* "app.
|
||||
*
|
||||
*
|
||||
* onactivated"
|
||||
*
|
||||
*
|
||||
* matches because of the newline, whereas
|
||||
*
|
||||
*
|
||||
* "app.onactivated"
|
||||
*
|
||||
*
|
||||
* does not match.
|
||||
*/
|
||||
const whiteSpaceRegex = /\s+/g;
|
||||
|
||||
@@ -8,7 +8,7 @@ namespace ts.OutliningElementsCollector {
|
||||
if (hintSpanNode && startElement && endElement) {
|
||||
const span: OutliningSpan = {
|
||||
textSpan: createTextSpanFromBounds(startElement.pos, endElement.end),
|
||||
hintSpan: createTextSpanFromBounds(hintSpanNode.getStart(), hintSpanNode.end),
|
||||
hintSpan: createTextSpanFromNode(hintSpanNode, sourceFile),
|
||||
bannerText: collapseText,
|
||||
autoCollapse: autoCollapse
|
||||
};
|
||||
@@ -135,7 +135,7 @@ namespace ts.OutliningElementsCollector {
|
||||
|
||||
// Block was a standalone block. In this case we want to only collapse
|
||||
// the span of the block, independent of any parent span.
|
||||
const span = createTextSpanFromBounds(n.getStart(), n.end);
|
||||
const span = createTextSpanFromNode(n);
|
||||
elements.push({
|
||||
textSpan: span,
|
||||
hintSpan: span,
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
/// <reference path='transpile.ts' />
|
||||
/// <reference path='formatting\formatting.ts' />
|
||||
/// <reference path='formatting\smartIndenter.ts' />
|
||||
/// <reference path='codefixes\codeFixProvider.ts' />
|
||||
/// <reference path='codeFixProvider.ts' />
|
||||
/// <reference path='codefixes\fixes.ts' />
|
||||
|
||||
namespace ts {
|
||||
|
||||
@@ -260,7 +260,7 @@ namespace ts.SignatureHelp {
|
||||
* Returns relevant information for the argument list and the current argument if we are
|
||||
* in the argument of an invocation; returns undefined otherwise.
|
||||
*/
|
||||
function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
|
||||
export function getImmediatelyContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo {
|
||||
if (node.parent.kind === SyntaxKind.CallExpression || node.parent.kind === SyntaxKind.NewExpression) {
|
||||
const callExpression = <CallExpression>node.parent;
|
||||
// There are 3 cases to handle:
|
||||
|
||||
+12
-13
@@ -1,18 +1,9 @@
|
||||
{
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"pretty": true,
|
||||
"outFile": "../../built/local/typescriptServices.js",
|
||||
"sourceMap": true,
|
||||
"stripInternal": true,
|
||||
"noResolve": false,
|
||||
"declaration": true,
|
||||
"target": "es5",
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"types": []
|
||||
},
|
||||
"files": [
|
||||
@@ -87,7 +78,15 @@
|
||||
"formatting/rulesProvider.ts",
|
||||
"formatting/smartIndenter.ts",
|
||||
"formatting/tokenRange.ts",
|
||||
"codeFixes/codeFixProvider.ts",
|
||||
"codeFixes/fixes.ts"
|
||||
"codeFixProvider.ts",
|
||||
"codefixes/fixExtendsInterfaceBecomesImplements.ts",
|
||||
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
|
||||
"codefixes/fixClassDoesntImplementInheritedAbstractMember.ts",
|
||||
"codefixes/fixClassSuperMustPrecedeThisAccess.ts",
|
||||
"codefixes/fixConstructorForDerivedNeedSuperCall.ts",
|
||||
"codefixes/fixes.ts",
|
||||
"codefixes/helpers.ts",
|
||||
"codefixes/importFixes.ts",
|
||||
"codefixes/unusedIdentifierFixes.ts"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -600,7 +600,7 @@ namespace ts {
|
||||
return !!findChildOfKind(n, kind, sourceFile);
|
||||
}
|
||||
|
||||
export function findChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): Node {
|
||||
export function findChildOfKind(n: Node, kind: SyntaxKind, sourceFile?: SourceFile): Node | undefined {
|
||||
return forEach(n.getChildren(sourceFile), c => c.kind === kind && c);
|
||||
}
|
||||
|
||||
@@ -1112,6 +1112,10 @@ namespace ts {
|
||||
return !tripleSlashDirectivePrefixRegex.test(commentText);
|
||||
}
|
||||
}
|
||||
|
||||
export function createTextSpanFromNode(node: Node, sourceFile?: SourceFile): TextSpan {
|
||||
return createTextSpanFromBounds(node.getStart(sourceFile), node.getEnd());
|
||||
}
|
||||
}
|
||||
|
||||
// Display-part writer helpers
|
||||
@@ -1358,4 +1362,9 @@ namespace ts {
|
||||
diagnostics: error ? concatenate(diagnostics, [error]) : diagnostics
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function getOpenBraceEnd(constructor: ConstructorDeclaration, sourceFile: SourceFile) {
|
||||
// First token is the open curly, this is where we want to put the 'super' call.
|
||||
return constructor.body.getFirstToken(sourceFile).getEnd();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"noEmitOnError": true,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitThis": true,
|
||||
"noUnusedLocals": true,
|
||||
"noUnusedParameters": true,
|
||||
"pretty": true,
|
||||
"preserveConstEnums": true,
|
||||
"stripInternal": true,
|
||||
"sourceMap": true,
|
||||
"target": "es5"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user