commit
5e4b8d66ff
|
@ -61,6 +61,7 @@ namespace ts {
|
|||
const noImplicitThis = compilerOptions.noImplicitThis === undefined ? compilerOptions.strict : compilerOptions.noImplicitThis;
|
||||
|
||||
const emitResolver = createResolver();
|
||||
const nodeBuilder = createNodeBuilder();
|
||||
|
||||
const undefinedSymbol = createSymbol(SymbolFlags.Property, "undefined");
|
||||
undefinedSymbol.declarations = [];
|
||||
|
@ -106,6 +107,9 @@ namespace ts {
|
|||
getParameterType: getTypeAtPosition,
|
||||
getReturnTypeOfSignature,
|
||||
getNonNullableType,
|
||||
typeToTypeNode: nodeBuilder.typeToTypeNode,
|
||||
indexInfoToIndexSignatureDeclaration: nodeBuilder.indexInfoToIndexSignatureDeclaration,
|
||||
signatureToSignatureDeclaration: nodeBuilder.signatureToSignatureDeclaration,
|
||||
getSymbolsInScope: (location, meaning) => {
|
||||
location = getParseTreeNode(location);
|
||||
return location ? getSymbolsInScope(location, meaning) : [];
|
||||
|
@ -2198,6 +2202,584 @@ namespace ts {
|
|||
return result;
|
||||
}
|
||||
|
||||
function createNodeBuilder() {
|
||||
let context: NodeBuilderContext;
|
||||
|
||||
return {
|
||||
typeToTypeNode: (type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
|
||||
context = createNodeBuilderContext(enclosingDeclaration, flags);
|
||||
const resultingNode = typeToTypeNodeHelper(type);
|
||||
const result = context.encounteredError ? undefined : resultingNode;
|
||||
return result;
|
||||
},
|
||||
indexInfoToIndexSignatureDeclaration: (indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
|
||||
context = createNodeBuilderContext(enclosingDeclaration, flags);
|
||||
const resultingNode = indexInfoToIndexSignatureDeclarationHelper(indexInfo, kind);
|
||||
const result = context.encounteredError ? undefined : resultingNode;
|
||||
return result;
|
||||
},
|
||||
signatureToSignatureDeclaration: (signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags) => {
|
||||
context = createNodeBuilderContext(enclosingDeclaration, flags);
|
||||
const resultingNode = signatureToSignatureDeclarationHelper(signature, kind);
|
||||
const result = context.encounteredError ? undefined : resultingNode;
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
interface NodeBuilderContext {
|
||||
readonly enclosingDeclaration: Node | undefined;
|
||||
readonly flags: NodeBuilderFlags | undefined;
|
||||
encounteredError: boolean;
|
||||
inObjectTypeLiteral: boolean;
|
||||
checkAlias: boolean;
|
||||
symbolStack: Symbol[] | undefined;
|
||||
}
|
||||
|
||||
function createNodeBuilderContext(enclosingDeclaration: Node | undefined, flags: NodeBuilderFlags | undefined): NodeBuilderContext {
|
||||
return {
|
||||
enclosingDeclaration,
|
||||
flags,
|
||||
encounteredError: false,
|
||||
inObjectTypeLiteral: false,
|
||||
checkAlias: true,
|
||||
symbolStack: undefined
|
||||
};
|
||||
}
|
||||
|
||||
function typeToTypeNodeHelper(type: Type): TypeNode {
|
||||
if (!type) {
|
||||
context.encounteredError = true;
|
||||
// TODO(aozgaa): should we return implict any (undefined) or explicit any (keywordtypenode)?
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.Any) {
|
||||
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.String) {
|
||||
return createKeywordTypeNode(SyntaxKind.StringKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Number) {
|
||||
return createKeywordTypeNode(SyntaxKind.NumberKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Boolean) {
|
||||
return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Enum) {
|
||||
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
|
||||
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
|
||||
}
|
||||
if (type.flags & (TypeFlags.StringLiteral)) {
|
||||
return createLiteralTypeNode((createLiteral((<LiteralType>type).text)));
|
||||
}
|
||||
if (type.flags & (TypeFlags.NumberLiteral)) {
|
||||
return createLiteralTypeNode((createNumericLiteral((<LiteralType>type).text)));
|
||||
}
|
||||
if (type.flags & TypeFlags.BooleanLiteral) {
|
||||
return (<IntrinsicType>type).intrinsicName === "true" ? createTrue() : createFalse();
|
||||
}
|
||||
if (type.flags & TypeFlags.EnumLiteral) {
|
||||
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
|
||||
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
|
||||
}
|
||||
if (type.flags & TypeFlags.Void) {
|
||||
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Undefined) {
|
||||
return createKeywordTypeNode(SyntaxKind.UndefinedKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Null) {
|
||||
return createKeywordTypeNode(SyntaxKind.NullKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.Never) {
|
||||
return createKeywordTypeNode(SyntaxKind.NeverKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.ESSymbol) {
|
||||
return createKeywordTypeNode(SyntaxKind.SymbolKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.NonPrimitive) {
|
||||
return createKeywordTypeNode(SyntaxKind.ObjectKeyword);
|
||||
}
|
||||
if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
|
||||
if (context.inObjectTypeLiteral) {
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowThisInObjectLiteral)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
}
|
||||
return createThis();
|
||||
}
|
||||
|
||||
const objectFlags = getObjectFlags(type);
|
||||
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
return typeReferenceToTypeNode(<TypeReference>type);
|
||||
}
|
||||
if (objectFlags & ObjectFlags.ClassOrInterface) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
|
||||
// TODO(aozgaa): handle type arguments.
|
||||
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
|
||||
}
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
const name = symbolToName(type.symbol, /*expectsIdentifier*/ false);
|
||||
// Ignore constraint/default when creating a usage (as opposed to declaration) of a type parameter.
|
||||
return createTypeReferenceNode(name, /*typeArguments*/ undefined);
|
||||
}
|
||||
|
||||
if (context.checkAlias && type.aliasSymbol) {
|
||||
const name = symbolToName(type.aliasSymbol, /*expectsIdentifier*/ false);
|
||||
const typeArgumentNodes = type.aliasTypeArguments && mapToTypeNodeArray(type.aliasTypeArguments);
|
||||
return createTypeReferenceNode(name, typeArgumentNodes);
|
||||
}
|
||||
context.checkAlias = false;
|
||||
|
||||
if (type.flags & TypeFlags.Union) {
|
||||
const formattedUnionTypes = formatUnionTypes((<UnionType>type).types);
|
||||
const unionTypeNodes = formattedUnionTypes && mapToTypeNodeArray(formattedUnionTypes);
|
||||
if (unionTypeNodes && unionTypeNodes.length > 0) {
|
||||
return createUnionOrIntersectionTypeNode(SyntaxKind.UnionType, unionTypeNodes);
|
||||
}
|
||||
else {
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyUnionOrIntersection)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.Intersection) {
|
||||
return createUnionOrIntersectionTypeNode(SyntaxKind.IntersectionType, mapToTypeNodeArray((type as UnionType).types));
|
||||
}
|
||||
|
||||
if (objectFlags & (ObjectFlags.Anonymous | ObjectFlags.Mapped)) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
// The type is an object literal type.
|
||||
return createAnonymousTypeNode(<ObjectType>type);
|
||||
}
|
||||
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
const indexedType = (<IndexType>type).type;
|
||||
const indexTypeNode = typeToTypeNodeHelper(indexedType);
|
||||
return createTypeOperatorNode(indexTypeNode);
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
const objectTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).objectType);
|
||||
const indexTypeNode = typeToTypeNodeHelper((<IndexedAccessType>type).indexType);
|
||||
return createIndexedAccessTypeNode(objectTypeNode, indexTypeNode);
|
||||
}
|
||||
|
||||
Debug.fail("Should be unreachable.");
|
||||
|
||||
function mapToTypeNodeArray(types: Type[]): TypeNode[] {
|
||||
const result = [];
|
||||
for (const type of types) {
|
||||
const typeNode = typeToTypeNodeHelper(type);
|
||||
if (typeNode) {
|
||||
result.push(typeNode);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function createMappedTypeNodeFromType(type: MappedType) {
|
||||
Debug.assert(!!(type.flags & TypeFlags.Object));
|
||||
const typeParameter = getTypeParameterFromMappedType(type);
|
||||
const typeParameterNode = typeParameterToDeclaration(typeParameter);
|
||||
|
||||
const templateType = getTemplateTypeFromMappedType(type);
|
||||
const templateTypeNode = typeToTypeNodeHelper(templateType);
|
||||
const readonlyToken = type.declaration && type.declaration.readonlyToken ? createToken(SyntaxKind.ReadonlyKeyword) : undefined;
|
||||
const questionToken = type.declaration && type.declaration.questionToken ? createToken(SyntaxKind.QuestionToken) : undefined;
|
||||
|
||||
return createMappedTypeNode(readonlyToken, typeParameterNode, questionToken, templateTypeNode);
|
||||
}
|
||||
|
||||
function createAnonymousTypeNode(type: ObjectType): TypeNode {
|
||||
const symbol = type.symbol;
|
||||
if (symbol) {
|
||||
// Always use 'typeof T' for type of class, enum, and module objects
|
||||
if (symbol.flags & SymbolFlags.Class && !getBaseTypeVariableOfClass(symbol) ||
|
||||
symbol.flags & (SymbolFlags.Enum | SymbolFlags.ValueModule) ||
|
||||
shouldWriteTypeOfFunctionSymbol()) {
|
||||
return createTypeQueryNodeFromSymbol(symbol);
|
||||
}
|
||||
else if (contains(context.symbolStack, symbol)) {
|
||||
// If type is an anonymous type literal in a type alias declaration, use type alias name
|
||||
const typeAlias = getTypeAliasForTypeLiteral(type);
|
||||
if (typeAlias) {
|
||||
// The specified symbol flags need to be reinterpreted as type flags
|
||||
const entityName = symbolToName(typeAlias, /*expectsIdentifier*/ false);
|
||||
return createTypeReferenceNode(entityName, /*typeArguments*/ undefined);
|
||||
}
|
||||
else {
|
||||
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Since instantiations of the same anonymous type have the same symbol, tracking symbols instead
|
||||
// of types allows us to catch circular references to instantiations of the same anonymous type
|
||||
if (!context.symbolStack) {
|
||||
context.symbolStack = [];
|
||||
}
|
||||
context.symbolStack.push(symbol);
|
||||
const result = createTypeNodeFromObjectType(type);
|
||||
context.symbolStack.pop();
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Anonymous types without a symbol are never circular.
|
||||
return createTypeNodeFromObjectType(type);
|
||||
}
|
||||
|
||||
function shouldWriteTypeOfFunctionSymbol() {
|
||||
const isStaticMethodSymbol = !!(symbol.flags & SymbolFlags.Method && // typeof static method
|
||||
forEach(symbol.declarations, declaration => getModifierFlags(declaration) & ModifierFlags.Static));
|
||||
const isNonLocalFunctionSymbol = !!(symbol.flags & SymbolFlags.Function) &&
|
||||
(symbol.parent || // is exported function symbol
|
||||
forEach(symbol.declarations, declaration =>
|
||||
declaration.parent.kind === SyntaxKind.SourceFile || declaration.parent.kind === SyntaxKind.ModuleBlock));
|
||||
if (isStaticMethodSymbol || isNonLocalFunctionSymbol) {
|
||||
// typeof is allowed only for static/non local functions
|
||||
return contains(context.symbolStack, symbol); // it is type of the symbol uses itself recursively
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function createTypeNodeFromObjectType(type: ObjectType): TypeNode {
|
||||
if (type.objectFlags & ObjectFlags.Mapped) {
|
||||
if (getConstraintTypeFromMappedType(<MappedType>type).flags & (TypeFlags.TypeParameter | TypeFlags.Index)) {
|
||||
return createMappedTypeNodeFromType(<MappedType>type);
|
||||
}
|
||||
}
|
||||
|
||||
const resolved = resolveStructuredTypeMembers(type);
|
||||
if (!resolved.properties.length && !resolved.stringIndexInfo && !resolved.numberIndexInfo) {
|
||||
if (!resolved.callSignatures.length && !resolved.constructSignatures.length) {
|
||||
return createTypeLiteralNode(/*members*/ undefined);
|
||||
}
|
||||
|
||||
if (resolved.callSignatures.length === 1 && !resolved.constructSignatures.length) {
|
||||
const signature = resolved.callSignatures[0];
|
||||
return <FunctionTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.FunctionType);
|
||||
}
|
||||
if (resolved.constructSignatures.length === 1 && !resolved.callSignatures.length) {
|
||||
const signature = resolved.constructSignatures[0];
|
||||
return <ConstructorTypeNode>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructorType);
|
||||
}
|
||||
}
|
||||
|
||||
const saveInObjectTypeLiteral = context.inObjectTypeLiteral;
|
||||
context.inObjectTypeLiteral = true;
|
||||
const members = createTypeNodesFromResolvedType(resolved);
|
||||
context.inObjectTypeLiteral = saveInObjectTypeLiteral;
|
||||
return createTypeLiteralNode(members);
|
||||
}
|
||||
|
||||
function createTypeQueryNodeFromSymbol(symbol: Symbol) {
|
||||
const entityName = symbolToName(symbol, /*expectsIdentifier*/ false);
|
||||
return createTypeQueryNode(entityName);
|
||||
}
|
||||
|
||||
function typeReferenceToTypeNode(type: TypeReference) {
|
||||
const typeArguments: Type[] = type.typeArguments || emptyArray;
|
||||
if (type.target === globalArrayType) {
|
||||
const elementType = typeToTypeNodeHelper(typeArguments[0]);
|
||||
return createArrayTypeNode(elementType);
|
||||
}
|
||||
else if (type.target.objectFlags & ObjectFlags.Tuple) {
|
||||
if (typeArguments.length > 0) {
|
||||
const tupleConstituentNodes = mapToTypeNodeArray(typeArguments.slice(0, getTypeReferenceArity(type)));
|
||||
if (tupleConstituentNodes && tupleConstituentNodes.length > 0) {
|
||||
return createTupleTypeNode(tupleConstituentNodes);
|
||||
}
|
||||
}
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowEmptyTuple)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
const outerTypeParameters = type.target.outerTypeParameters;
|
||||
let i = 0;
|
||||
let qualifiedName: QualifiedName | undefined = undefined;
|
||||
if (outerTypeParameters) {
|
||||
const length = outerTypeParameters.length;
|
||||
while (i < length) {
|
||||
// Find group of type arguments for type parameters with the same declaring container.
|
||||
const start = i;
|
||||
const parent = getParentSymbolOfTypeParameter(outerTypeParameters[i]);
|
||||
do {
|
||||
i++;
|
||||
} while (i < length && getParentSymbolOfTypeParameter(outerTypeParameters[i]) === parent);
|
||||
// When type parameters are their own type arguments for the whole group (i.e. we have
|
||||
// the default outer type arguments), we don't show the group.
|
||||
if (!rangeEquals(outerTypeParameters, typeArguments, start, i)) {
|
||||
const qualifiedNamePart = symbolToName(parent, /*expectsIdentifier*/ true);
|
||||
if (!qualifiedName) {
|
||||
qualifiedName = createQualifiedName(qualifiedNamePart, /*right*/ undefined);
|
||||
}
|
||||
else {
|
||||
Debug.assert(!qualifiedName.right);
|
||||
qualifiedName.right = qualifiedNamePart;
|
||||
qualifiedName = createQualifiedName(qualifiedName, /*right*/ undefined);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let entityName: EntityName = undefined;
|
||||
const nameIdentifier = symbolToName(type.symbol, /*expectsIdentifier*/ true);
|
||||
if (qualifiedName) {
|
||||
Debug.assert(!qualifiedName.right);
|
||||
qualifiedName.right = nameIdentifier;
|
||||
entityName = qualifiedName;
|
||||
}
|
||||
else {
|
||||
entityName = nameIdentifier;
|
||||
}
|
||||
const typeParameterCount = (type.target.typeParameters || emptyArray).length;
|
||||
const typeArgumentNodes = some(typeArguments) ? mapToTypeNodeArray(typeArguments.slice(i, typeParameterCount - i)) : undefined;
|
||||
return createTypeReferenceNode(entityName, typeArgumentNodes);
|
||||
}
|
||||
}
|
||||
|
||||
function createTypeNodesFromResolvedType(resolvedType: ResolvedType): TypeElement[] {
|
||||
const typeElements: TypeElement[] = [];
|
||||
for (const signature of resolvedType.callSignatures) {
|
||||
typeElements.push(<CallSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.CallSignature));
|
||||
}
|
||||
for (const signature of resolvedType.constructSignatures) {
|
||||
typeElements.push(<ConstructSignatureDeclaration>signatureToSignatureDeclarationHelper(signature, SyntaxKind.ConstructSignature));
|
||||
}
|
||||
if (resolvedType.stringIndexInfo) {
|
||||
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.stringIndexInfo, IndexKind.String));
|
||||
}
|
||||
if (resolvedType.numberIndexInfo) {
|
||||
typeElements.push(indexInfoToIndexSignatureDeclarationHelper(resolvedType.numberIndexInfo, IndexKind.Number));
|
||||
}
|
||||
|
||||
const properties = resolvedType.properties;
|
||||
if (!properties) {
|
||||
return typeElements;
|
||||
}
|
||||
|
||||
for (const propertySymbol of properties) {
|
||||
const propertyType = getTypeOfSymbol(propertySymbol);
|
||||
const oldDeclaration = propertySymbol.declarations && propertySymbol.declarations[0] as TypeElement;
|
||||
if (!oldDeclaration) {
|
||||
return;
|
||||
}
|
||||
const propertyName = oldDeclaration.name;
|
||||
const optionalToken = propertySymbol.flags & SymbolFlags.Optional ? createToken(SyntaxKind.QuestionToken) : undefined;
|
||||
if (propertySymbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && !getPropertiesOfObjectType(propertyType).length) {
|
||||
const signatures = getSignaturesOfType(propertyType, SignatureKind.Call);
|
||||
for (const signature of signatures) {
|
||||
const methodDeclaration = <MethodSignature>signatureToSignatureDeclarationHelper(signature, SyntaxKind.MethodSignature);
|
||||
methodDeclaration.name = propertyName;
|
||||
methodDeclaration.questionToken = optionalToken;
|
||||
typeElements.push(methodDeclaration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
||||
// TODO(aozgaa): should we create a node with explicit or implict any?
|
||||
const propertyTypeNode = propertyType ? typeToTypeNodeHelper(propertyType) : createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
typeElements.push(createPropertySignature(
|
||||
propertyName,
|
||||
optionalToken,
|
||||
propertyTypeNode,
|
||||
/*initializer*/undefined));
|
||||
}
|
||||
}
|
||||
return typeElements.length ? typeElements : undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function indexInfoToIndexSignatureDeclarationHelper(indexInfo: IndexInfo, kind: IndexKind): IndexSignatureDeclaration {
|
||||
const indexerTypeNode = createKeywordTypeNode(kind === IndexKind.String ? SyntaxKind.StringKeyword : SyntaxKind.NumberKeyword);
|
||||
const name = getNameFromIndexInfo(indexInfo);
|
||||
|
||||
const indexingParameter = createParameter(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
/*dotDotDotToken*/ undefined,
|
||||
name,
|
||||
/*questionToken*/ undefined,
|
||||
indexerTypeNode,
|
||||
/*initializer*/ undefined);
|
||||
const typeNode = typeToTypeNodeHelper(indexInfo.type);
|
||||
return createIndexSignatureDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
indexInfo.isReadonly ? [createToken(SyntaxKind.ReadonlyKeyword)] : undefined,
|
||||
[indexingParameter],
|
||||
typeNode);
|
||||
}
|
||||
|
||||
function signatureToSignatureDeclarationHelper(signature: Signature, kind: SyntaxKind): SignatureDeclaration {
|
||||
|
||||
const typeParameters = signature.typeParameters && signature.typeParameters.map(parameter => typeParameterToDeclaration(parameter));
|
||||
const parameters = signature.parameters.map(parameter => symbolToParameterDeclaration(parameter));
|
||||
let returnTypeNode: TypeNode | TypePredicate;
|
||||
if (signature.typePredicate) {
|
||||
const typePredicate = signature.typePredicate;
|
||||
const parameterName = typePredicate.kind === TypePredicateKind.Identifier ? createIdentifier((<IdentifierTypePredicate>typePredicate).parameterName) : createThisTypeNode();
|
||||
const typeNode = typeToTypeNodeHelper(typePredicate.type);
|
||||
returnTypeNode = createTypePredicateNode(parameterName, typeNode);
|
||||
}
|
||||
else {
|
||||
const returnType = getReturnTypeOfSignature(signature);
|
||||
returnTypeNode = returnType && typeToTypeNodeHelper(returnType);
|
||||
}
|
||||
const returnTypeNodeExceptAny = returnTypeNode && returnTypeNode.kind !== SyntaxKind.AnyKeyword ? returnTypeNode : undefined;
|
||||
|
||||
return createSignatureDeclaration(kind, typeParameters, parameters, returnTypeNodeExceptAny);
|
||||
}
|
||||
|
||||
function typeParameterToDeclaration(type: TypeParameter): TypeParameterDeclaration {
|
||||
const constraint = getConstraintFromTypeParameter(type);
|
||||
const constraintNode = constraint && typeToTypeNodeHelper(constraint);
|
||||
const defaultParameter = getDefaultFromTypeParameter(type);
|
||||
const defaultParameterNode = defaultParameter && typeToTypeNodeHelper(defaultParameter);
|
||||
const name = symbolToName(type.symbol, /*expectsIdentifier*/ true);
|
||||
return createTypeParameterDeclaration(name, constraintNode, defaultParameterNode);
|
||||
}
|
||||
|
||||
function symbolToParameterDeclaration(parameterSymbol: Symbol): ParameterDeclaration {
|
||||
const parameterDeclaration = <ParameterDeclaration>getDeclarationOfKind(parameterSymbol, SyntaxKind.Parameter);
|
||||
const parameterType = getTypeOfSymbol(parameterSymbol);
|
||||
const parameterTypeNode = typeToTypeNodeHelper(parameterType);
|
||||
// TODO(aozgaa): In the future, check initializer accessibility.
|
||||
const parameterNode = createParameter(
|
||||
parameterDeclaration.decorators,
|
||||
parameterDeclaration.modifiers,
|
||||
parameterDeclaration.dotDotDotToken && createToken(SyntaxKind.DotDotDotToken),
|
||||
// Clone name to remove trivia.
|
||||
getSynthesizedClone(parameterDeclaration.name),
|
||||
parameterDeclaration.questionToken && createToken(SyntaxKind.QuestionToken),
|
||||
parameterTypeNode,
|
||||
parameterDeclaration.initializer);
|
||||
return parameterNode;
|
||||
}
|
||||
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: true): Identifier;
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: false): EntityName;
|
||||
function symbolToName(symbol: Symbol, expectsIdentifier: boolean): EntityName {
|
||||
|
||||
// Try to get qualified name if the symbol is not a type parameter and there is an enclosing declaration.
|
||||
let chain: Symbol[];
|
||||
const isTypeParameter = symbol.flags & SymbolFlags.TypeParameter;
|
||||
if (!isTypeParameter && context.enclosingDeclaration) {
|
||||
chain = getSymbolChain(symbol, SymbolFlags.None, /*endOfChain*/ true);
|
||||
Debug.assert(chain && chain.length > 0);
|
||||
}
|
||||
else {
|
||||
chain = [symbol];
|
||||
}
|
||||
|
||||
if (expectsIdentifier && chain.length !== 1
|
||||
&& !context.encounteredError
|
||||
&& !(context.flags & NodeBuilderFlags.allowQualifedNameInPlaceOfIdentifier)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
return createEntityNameFromSymbolChain(chain, chain.length - 1);
|
||||
|
||||
function createEntityNameFromSymbolChain(chain: Symbol[], index: number): EntityName {
|
||||
Debug.assert(chain && 0 <= index && index < chain.length);
|
||||
// const parentIndex = index - 1;
|
||||
const symbol = chain[index];
|
||||
let typeParameterString = "";
|
||||
if (index > 0) {
|
||||
|
||||
const parentSymbol = chain[index - 1];
|
||||
let typeParameters: TypeParameter[];
|
||||
if (getCheckFlags(symbol) & CheckFlags.Instantiated) {
|
||||
typeParameters = getTypeParametersOfClassOrInterface(parentSymbol);
|
||||
}
|
||||
else {
|
||||
const targetSymbol = getTargetSymbol(parentSymbol);
|
||||
if (targetSymbol.flags & (SymbolFlags.Class | SymbolFlags.Interface | SymbolFlags.TypeAlias)) {
|
||||
typeParameters = getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
|
||||
}
|
||||
}
|
||||
if (typeParameters && typeParameters.length > 0) {
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowTypeParameterInQualifiedName)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
const writer = getSingleLineStringWriter();
|
||||
const displayBuilder = getSymbolDisplayBuilder();
|
||||
displayBuilder.buildDisplayForTypeParametersAndDelimiters(typeParameters, writer, context.enclosingDeclaration, 0);
|
||||
typeParameterString = writer.string();
|
||||
releaseStringWriter(writer);
|
||||
|
||||
}
|
||||
}
|
||||
const symbolName = getNameOfSymbol(symbol);
|
||||
const symbolNameWithTypeParameters = typeParameterString.length > 0 ? `${symbolName}<${typeParameterString}>` : symbolName;
|
||||
const identifier = createIdentifier(symbolNameWithTypeParameters);
|
||||
|
||||
return index > 0 ? createQualifiedName(createEntityNameFromSymbolChain(chain, index - 1), identifier) : identifier;
|
||||
}
|
||||
|
||||
/** @param endOfChain Set to false for recursive calls; non-recursive calls should always output something. */
|
||||
function getSymbolChain(symbol: Symbol, meaning: SymbolFlags, endOfChain: boolean): Symbol[] | undefined {
|
||||
let accessibleSymbolChain = getAccessibleSymbolChain(symbol, context.enclosingDeclaration, meaning, /*useOnlyExternalAliasing*/false);
|
||||
let parentSymbol: Symbol;
|
||||
|
||||
if (!accessibleSymbolChain ||
|
||||
needsQualification(accessibleSymbolChain[0], context.enclosingDeclaration, accessibleSymbolChain.length === 1 ? meaning : getQualifiedLeftMeaning(meaning))) {
|
||||
|
||||
// Go up and add our parent.
|
||||
const parent = getParentOfSymbol(accessibleSymbolChain ? accessibleSymbolChain[0] : symbol);
|
||||
if (parent) {
|
||||
const parentChain = getSymbolChain(parent, getQualifiedLeftMeaning(meaning), /*endOfChain*/ false);
|
||||
if (parentChain) {
|
||||
parentSymbol = parent;
|
||||
accessibleSymbolChain = parentChain.concat(accessibleSymbolChain || [symbol]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (accessibleSymbolChain) {
|
||||
return accessibleSymbolChain;
|
||||
}
|
||||
if (
|
||||
// If this is the last part of outputting the symbol, always output. The cases apply only to parent symbols.
|
||||
endOfChain ||
|
||||
// If a parent symbol is an external module, don't write it. (We prefer just `x` vs `"foo/bar".x`.)
|
||||
!(!parentSymbol && ts.forEach(symbol.declarations, hasExternalModuleSymbol)) &&
|
||||
// If a parent symbol is an anonymous type, don't write it.
|
||||
!(symbol.flags & (SymbolFlags.TypeLiteral | SymbolFlags.ObjectLiteral))) {
|
||||
|
||||
return [symbol];
|
||||
}
|
||||
}
|
||||
|
||||
function getNameOfSymbol(symbol: Symbol): string {
|
||||
const declaration = firstOrUndefined(symbol.declarations);
|
||||
if (declaration) {
|
||||
if (declaration.name) {
|
||||
return declarationNameToString(declaration.name);
|
||||
}
|
||||
if (declaration.parent && declaration.parent.kind === SyntaxKind.VariableDeclaration) {
|
||||
return declarationNameToString((<VariableDeclaration>declaration.parent).name);
|
||||
}
|
||||
if (!context.encounteredError && !(context.flags & NodeBuilderFlags.allowAnonymousIdentifier)) {
|
||||
context.encounteredError = true;
|
||||
}
|
||||
switch (declaration.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
return "(Anonymous class)";
|
||||
case SyntaxKind.FunctionExpression:
|
||||
case SyntaxKind.ArrowFunction:
|
||||
return "(Anonymous function)";
|
||||
}
|
||||
}
|
||||
return symbol.name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function typePredicateToString(typePredicate: TypePredicate, enclosingDeclaration?: Declaration, flags?: TypeFormatFlags): string {
|
||||
const writer = getSingleLineStringWriter();
|
||||
getSymbolDisplayBuilder().buildTypePredicateDisplay(typePredicate, writer, enclosingDeclaration, flags);
|
||||
|
@ -2466,6 +3048,7 @@ namespace ts {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
function writeTypeList(types: Type[], delimiter: SyntaxKind) {
|
||||
for (let i = 0; i < types.length; i++) {
|
||||
if (i > 0) {
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace ts {
|
|||
* Creates a shallow, memberwise clone of a node with no source map location.
|
||||
*/
|
||||
/* @internal */
|
||||
export function getSynthesizedClone<T extends Node>(node: T): T {
|
||||
export function getSynthesizedClone<T extends Node>(node: T | undefined): T {
|
||||
// We don't use "clone" from core.ts here, as we need to preserve the prototype chain of
|
||||
// the original node. We also need to exclude specific properties and only include own-
|
||||
// properties (to skip members already defined on the shared prototype).
|
||||
|
@ -166,23 +166,23 @@ namespace ts {
|
|||
// Reserved words
|
||||
|
||||
export function createSuper() {
|
||||
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.SuperKeyword);
|
||||
return <SuperExpression>createSynthesizedNode(SyntaxKind.SuperKeyword);
|
||||
}
|
||||
|
||||
export function createThis() {
|
||||
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.ThisKeyword);
|
||||
return <ThisExpression & Token<SyntaxKind.ThisKeyword>>createSynthesizedNode(SyntaxKind.ThisKeyword);
|
||||
}
|
||||
|
||||
export function createNull() {
|
||||
return <PrimaryExpression>createSynthesizedNode(SyntaxKind.NullKeyword);
|
||||
return <NullLiteral & Token<SyntaxKind.NullKeyword>>createSynthesizedNode(SyntaxKind.NullKeyword);
|
||||
}
|
||||
|
||||
export function createTrue() {
|
||||
return <BooleanLiteral>createSynthesizedNode(SyntaxKind.TrueKeyword);
|
||||
return <BooleanLiteral & Token<SyntaxKind.TrueKeyword>>createSynthesizedNode(SyntaxKind.TrueKeyword);
|
||||
}
|
||||
|
||||
export function createFalse() {
|
||||
return <BooleanLiteral>createSynthesizedNode(SyntaxKind.FalseKeyword);
|
||||
return <BooleanLiteral & Token<SyntaxKind.FalseKeyword>>createSynthesizedNode(SyntaxKind.FalseKeyword);
|
||||
}
|
||||
|
||||
// Names
|
||||
|
@ -213,6 +213,284 @@ namespace ts {
|
|||
: node;
|
||||
}
|
||||
|
||||
// Type Elements
|
||||
|
||||
export function createSignatureDeclaration(kind: SyntaxKind, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
|
||||
const signatureDeclaration = createSynthesizedNode(kind) as SignatureDeclaration;
|
||||
signatureDeclaration.typeParameters = asNodeArray(typeParameters);
|
||||
signatureDeclaration.parameters = asNodeArray(parameters);
|
||||
signatureDeclaration.type = type;
|
||||
return signatureDeclaration;
|
||||
}
|
||||
|
||||
function updateSignatureDeclaration(node: SignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
|
||||
return node.typeParameters !== typeParameters
|
||||
|| node.parameters !== parameters
|
||||
|| node.type !== type
|
||||
? updateNode(createSignatureDeclaration(node.kind, typeParameters, parameters, type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createFunctionTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
|
||||
return createSignatureDeclaration(SyntaxKind.FunctionType, typeParameters, parameters, type) as FunctionTypeNode;
|
||||
}
|
||||
|
||||
export function updateFunctionTypeNode(node: FunctionTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
|
||||
return <FunctionTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
|
||||
}
|
||||
|
||||
export function createConstructorTypeNode(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
|
||||
return createSignatureDeclaration(SyntaxKind.ConstructorType, typeParameters, parameters, type) as ConstructorTypeNode;
|
||||
}
|
||||
|
||||
export function updateConstructorTypeNode(node: ConstructorTypeNode, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
|
||||
return <ConstructorTypeNode>updateSignatureDeclaration(node, typeParameters, parameters, type);
|
||||
}
|
||||
|
||||
export function createCallSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
|
||||
return createSignatureDeclaration(SyntaxKind.CallSignature, typeParameters, parameters, type) as CallSignatureDeclaration;
|
||||
}
|
||||
|
||||
export function updateCallSignatureDeclaration(node: CallSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
|
||||
return <CallSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
|
||||
}
|
||||
|
||||
export function createConstructSignatureDeclaration(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined) {
|
||||
return createSignatureDeclaration(SyntaxKind.ConstructSignature, typeParameters, parameters, type) as ConstructSignatureDeclaration;
|
||||
}
|
||||
|
||||
export function updateConstructSignatureDeclaration(node: ConstructSignatureDeclaration, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined) {
|
||||
return <ConstructSignatureDeclaration>updateSignatureDeclaration(node, typeParameters, parameters, type);
|
||||
}
|
||||
|
||||
export function createMethodSignature(typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined) {
|
||||
const methodSignature = createSignatureDeclaration(SyntaxKind.MethodSignature, typeParameters, parameters, type) as MethodSignature;
|
||||
methodSignature.name = asName(name);
|
||||
methodSignature.questionToken = questionToken;
|
||||
return methodSignature;
|
||||
}
|
||||
|
||||
export function updateMethodSignature(node: MethodSignature, typeParameters: NodeArray<TypeParameterDeclaration> | undefined, parameters: NodeArray<ParameterDeclaration>, type: TypeNode | undefined, name: PropertyName, questionToken: QuestionToken | undefined) {
|
||||
return node.typeParameters !== typeParameters
|
||||
|| node.parameters !== parameters
|
||||
|| node.type !== type
|
||||
|| node.name !== name
|
||||
|| node.questionToken !== questionToken
|
||||
? updateNode(createMethodSignature(typeParameters, parameters, type, name, questionToken), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
// Types
|
||||
|
||||
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]) {
|
||||
return <KeywordTypeNode>createSynthesizedNode(kind);
|
||||
}
|
||||
|
||||
export function createThisTypeNode() {
|
||||
return <ThisTypeNode>createSynthesizedNode(SyntaxKind.ThisType);
|
||||
}
|
||||
|
||||
export function createLiteralTypeNode(literal: Expression) {
|
||||
const literalTypeNode = createSynthesizedNode(SyntaxKind.LiteralType) as LiteralTypeNode;
|
||||
literalTypeNode.literal = literal;
|
||||
return literalTypeNode;
|
||||
}
|
||||
|
||||
export function updateLiteralTypeNode(node: LiteralTypeNode, literal: Expression) {
|
||||
return node.literal !== literal
|
||||
? updateNode(createLiteralTypeNode(literal), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypeReferenceNode(typeName: string | EntityName, typeArguments: TypeNode[] | undefined) {
|
||||
const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
|
||||
typeReference.typeName = asName(typeName);
|
||||
typeReference.typeArguments = asNodeArray(typeArguments);
|
||||
return typeReference;
|
||||
}
|
||||
|
||||
export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: EntityName, typeArguments: NodeArray<TypeNode> | undefined) {
|
||||
return node.typeName !== typeName
|
||||
|| node.typeArguments !== typeArguments
|
||||
? updateNode(createTypeReferenceNode(typeName, typeArguments), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypePredicateNode(parameterName: Identifier | ThisTypeNode | string, type: TypeNode) {
|
||||
const typePredicateNode = createSynthesizedNode(SyntaxKind.TypePredicate) as TypePredicateNode;
|
||||
typePredicateNode.parameterName = asName(parameterName);
|
||||
typePredicateNode.type = type;
|
||||
return typePredicateNode;
|
||||
}
|
||||
|
||||
export function updateTypePredicateNode(node: TypePredicateNode, parameterName: Identifier | ThisTypeNode, type: TypeNode) {
|
||||
return node.parameterName !== parameterName
|
||||
|| node.type !== type
|
||||
? updateNode(createTypePredicateNode(parameterName, type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypeQueryNode(exprName: EntityName) {
|
||||
const typeQueryNode = createSynthesizedNode(SyntaxKind.TypeQuery) as TypeQueryNode;
|
||||
typeQueryNode.exprName = exprName;
|
||||
return typeQueryNode;
|
||||
}
|
||||
|
||||
export function updateTypeQueryNode(node: TypeQueryNode, exprName: EntityName) {
|
||||
return node.exprName !== exprName ? updateNode(createTypeQueryNode(exprName), node) : node;
|
||||
}
|
||||
|
||||
export function createArrayTypeNode(elementType: TypeNode) {
|
||||
const arrayTypeNode = createSynthesizedNode(SyntaxKind.ArrayType) as ArrayTypeNode;
|
||||
arrayTypeNode.elementType = elementType;
|
||||
return arrayTypeNode;
|
||||
}
|
||||
|
||||
export function updateArrayTypeNode(node: ArrayTypeNode, elementType: TypeNode): ArrayTypeNode {
|
||||
return node.elementType !== elementType
|
||||
? updateNode(createArrayTypeNode(elementType), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType, types: TypeNode[]): UnionTypeNode;
|
||||
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.IntersectionType, types: TypeNode[]): IntersectionTypeNode;
|
||||
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]): UnionOrIntersectionTypeNode;
|
||||
export function createUnionOrIntersectionTypeNode(kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: TypeNode[]) {
|
||||
const unionTypeNode = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
|
||||
unionTypeNode.types = createNodeArray(types);
|
||||
return unionTypeNode;
|
||||
}
|
||||
|
||||
export function updateUnionOrIntersectionTypeNode(node: UnionOrIntersectionTypeNode, types: NodeArray<TypeNode>) {
|
||||
return node.types !== types
|
||||
? updateNode(createUnionOrIntersectionTypeNode(node.kind, types), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypeLiteralNode(members: TypeElement[]) {
|
||||
const typeLiteralNode = createSynthesizedNode(SyntaxKind.TypeLiteral) as TypeLiteralNode;
|
||||
typeLiteralNode.members = createNodeArray(members);
|
||||
return typeLiteralNode;
|
||||
}
|
||||
|
||||
export function updateTypeLiteralNode(node: TypeLiteralNode, members: NodeArray<TypeElement>) {
|
||||
return node.members !== members
|
||||
? updateNode(createTypeLiteralNode(members), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTupleTypeNode(elementTypes: TypeNode[]) {
|
||||
const tupleTypeNode = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
|
||||
tupleTypeNode.elementTypes = createNodeArray(elementTypes);
|
||||
return tupleTypeNode;
|
||||
}
|
||||
|
||||
export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: TypeNode[]) {
|
||||
return node.elementTypes !== elementTypes
|
||||
? updateNode(createTupleTypeNode(elementTypes), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createMappedTypeNode(readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
const mappedTypeNode = createSynthesizedNode(SyntaxKind.MappedType) as MappedTypeNode;
|
||||
mappedTypeNode.readonlyToken = readonlyToken;
|
||||
mappedTypeNode.typeParameter = typeParameter;
|
||||
mappedTypeNode.questionToken = questionToken;
|
||||
mappedTypeNode.type = type;
|
||||
return mappedTypeNode;
|
||||
}
|
||||
|
||||
export function updateMappedTypeNode(node: MappedTypeNode, readonlyToken: ReadonlyToken | undefined, typeParameter: TypeParameterDeclaration, questionToken: QuestionToken | undefined, type: TypeNode | undefined): MappedTypeNode {
|
||||
return node.readonlyToken !== readonlyToken
|
||||
|| node.typeParameter !== typeParameter
|
||||
|| node.questionToken !== questionToken
|
||||
|| node.type !== type
|
||||
? updateNode(createMappedTypeNode(readonlyToken, typeParameter, questionToken, type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createTypeOperatorNode(type: TypeNode) {
|
||||
const typeOperatorNode = createSynthesizedNode(SyntaxKind.TypeOperator) as TypeOperatorNode;
|
||||
typeOperatorNode.operator = SyntaxKind.KeyOfKeyword;
|
||||
typeOperatorNode.type = type;
|
||||
return typeOperatorNode;
|
||||
}
|
||||
|
||||
export function updateTypeOperatorNode(node: TypeOperatorNode, type: TypeNode) {
|
||||
return node.type !== type ? updateNode(createTypeOperatorNode(type), node) : node;
|
||||
}
|
||||
|
||||
export function createIndexedAccessTypeNode(objectType: TypeNode, indexType: TypeNode) {
|
||||
const indexedAccessTypeNode = createSynthesizedNode(SyntaxKind.IndexedAccessType) as IndexedAccessTypeNode;
|
||||
indexedAccessTypeNode.objectType = objectType;
|
||||
indexedAccessTypeNode.indexType = indexType;
|
||||
return indexedAccessTypeNode;
|
||||
}
|
||||
|
||||
export function updateIndexedAccessTypeNode(node: IndexedAccessTypeNode, objectType: TypeNode, indexType: TypeNode) {
|
||||
return node.objectType !== objectType
|
||||
|| node.indexType !== indexType
|
||||
? updateNode(createIndexedAccessTypeNode(objectType, indexType), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
// Type Declarations
|
||||
|
||||
export function createTypeParameterDeclaration(name: string | Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
|
||||
const typeParameter = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
|
||||
typeParameter.name = asName(name);
|
||||
typeParameter.constraint = constraint;
|
||||
typeParameter.default = defaultType;
|
||||
|
||||
return typeParameter;
|
||||
}
|
||||
|
||||
export function updateTypeParameterDeclaration(node: TypeParameterDeclaration, name: Identifier, constraint: TypeNode | undefined, defaultType: TypeNode | undefined) {
|
||||
return node.name !== name
|
||||
|| node.constraint !== constraint
|
||||
|| node.default !== defaultType
|
||||
? updateNode(createTypeParameterDeclaration(name, constraint, defaultType), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
// Signature elements
|
||||
|
||||
export function createPropertySignature(name: PropertyName | string, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined): PropertySignature {
|
||||
const propertySignature = createSynthesizedNode(SyntaxKind.PropertySignature) as PropertySignature;
|
||||
propertySignature.name = asName(name);
|
||||
propertySignature.questionToken = questionToken;
|
||||
propertySignature.type = type;
|
||||
propertySignature.initializer = initializer;
|
||||
return propertySignature;
|
||||
}
|
||||
|
||||
export function updatePropertySignature(node: PropertySignature, name: PropertyName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
|
||||
return node.name !== name
|
||||
|| node.questionToken !== questionToken
|
||||
|| node.type !== type
|
||||
|| node.initializer !== initializer
|
||||
? updateNode(createPropertySignature(name, questionToken, type, initializer), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
export function createIndexSignatureDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode): IndexSignatureDeclaration {
|
||||
const indexSignature = createSynthesizedNode(SyntaxKind.IndexSignature) as IndexSignatureDeclaration;
|
||||
indexSignature.decorators = asNodeArray(decorators);
|
||||
indexSignature.modifiers = asNodeArray(modifiers);
|
||||
indexSignature.parameters = createNodeArray(parameters);
|
||||
indexSignature.type = type;
|
||||
return indexSignature;
|
||||
}
|
||||
|
||||
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, parameters: ParameterDeclaration[], type: TypeNode) {
|
||||
return node.parameters !== parameters
|
||||
|| node.type !== type
|
||||
|| node.decorators !== decorators
|
||||
|| node.modifiers !== modifiers
|
||||
? updateNode(createIndexSignatureDeclaration(decorators, modifiers, parameters, type), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
// Signature elements
|
||||
|
||||
export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) {
|
||||
|
@ -227,11 +505,12 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: BindingName, type: TypeNode | undefined, initializer: Expression | undefined) {
|
||||
export function updateParameter(node: ParameterDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken: QuestionToken | undefined, type: TypeNode | undefined, initializer: Expression | undefined) {
|
||||
return node.decorators !== decorators
|
||||
|| node.modifiers !== modifiers
|
||||
|| node.dotDotDotToken !== dotDotDotToken
|
||||
|| node.name !== name
|
||||
|| node.questionToken !== questionToken
|
||||
|| node.type !== type
|
||||
|| node.initializer !== initializer
|
||||
? updateNode(createParameter(decorators, modifiers, dotDotDotToken, name, node.questionToken, type, initializer), node)
|
||||
|
@ -273,12 +552,13 @@ namespace ts {
|
|||
: node;
|
||||
}
|
||||
|
||||
export function createMethod(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
export function createMethodDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
const node = <MethodDeclaration>createSynthesizedNode(SyntaxKind.MethodDeclaration);
|
||||
node.decorators = asNodeArray(decorators);
|
||||
node.modifiers = asNodeArray(modifiers);
|
||||
node.asteriskToken = asteriskToken;
|
||||
node.name = asName(name);
|
||||
node.questionToken = questionToken;
|
||||
node.typeParameters = asNodeArray(typeParameters);
|
||||
node.parameters = createNodeArray(parameters);
|
||||
node.type = type;
|
||||
|
@ -286,7 +566,7 @@ namespace ts {
|
|||
return node;
|
||||
}
|
||||
|
||||
export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
export function updateMethod(node: MethodDeclaration, decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: PropertyName, questionToken: QuestionToken | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
return node.decorators !== decorators
|
||||
|| node.modifiers !== modifiers
|
||||
|| node.asteriskToken !== asteriskToken
|
||||
|
@ -295,7 +575,7 @@ namespace ts {
|
|||
|| node.parameters !== parameters
|
||||
|| node.type !== type
|
||||
|| node.body !== body
|
||||
? updateNode(createMethod(decorators, modifiers, asteriskToken, name, typeParameters, parameters, type, body), node)
|
||||
? updateNode(createMethodDeclaration(decorators, modifiers, asteriskToken, name, questionToken, typeParameters, parameters, type, body), node)
|
||||
: node;
|
||||
}
|
||||
|
||||
|
@ -1099,10 +1379,6 @@ namespace ts {
|
|||
: node;
|
||||
}
|
||||
|
||||
export function createKeywordTypeNode(kind: KeywordTypeNode["kind"]): KeywordTypeNode {
|
||||
return <KeywordTypeNode>createSynthesizedNode(kind);
|
||||
}
|
||||
|
||||
export function createFunctionDeclaration(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], type: TypeNode | undefined, body: Block | undefined) {
|
||||
const node = <FunctionDeclaration>createSynthesizedNode(SyntaxKind.FunctionDeclaration);
|
||||
node.decorators = asNodeArray(decorators);
|
||||
|
@ -1793,7 +2069,9 @@ namespace ts {
|
|||
function asName(name: string | Identifier): Identifier;
|
||||
function asName(name: string | BindingName): BindingName;
|
||||
function asName(name: string | PropertyName): PropertyName;
|
||||
function asName(name: string | Identifier | BindingName | PropertyName) {
|
||||
function asName(name: string | EntityName): EntityName;
|
||||
function asName(name: string | Identifier | ThisTypeNode): Identifier | ThisTypeNode;
|
||||
function asName(name: string | Identifier | BindingName | PropertyName | QualifiedName | ThisTypeNode) {
|
||||
return typeof name === "string" ? createIdentifier(name) : name;
|
||||
}
|
||||
|
||||
|
|
|
@ -125,6 +125,7 @@ namespace ts {
|
|||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
/*questionToken*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
|
|
|
@ -475,6 +475,7 @@ namespace ts {
|
|||
/*modifiers*/ undefined,
|
||||
node.dotDotDotToken,
|
||||
getGeneratedNameForNode(node),
|
||||
/*questionToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
visitNode(node.initializer, visitor, isExpression)
|
||||
);
|
||||
|
@ -540,6 +541,7 @@ namespace ts {
|
|||
? undefined
|
||||
: node.asteriskToken,
|
||||
visitNode(node.name, visitor, isPropertyName),
|
||||
visitNode(/*questionToken*/ undefined, visitor, isToken),
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
|
|
|
@ -2049,6 +2049,7 @@ namespace ts {
|
|||
visitNodes(node.modifiers, modifierVisitor, isModifier),
|
||||
node.asteriskToken,
|
||||
visitPropertyNameOfClassElement(node),
|
||||
/*questionToken*/ undefined,
|
||||
/*typeParameters*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
/*type*/ undefined,
|
||||
|
|
|
@ -819,7 +819,7 @@ namespace ts {
|
|||
body?: FunctionBody;
|
||||
}
|
||||
|
||||
// For when we encounter a semicolon in a class declaration. ES6 allows these as class elements.
|
||||
/** For when we encounter a semicolon in a class declaration. ES6 allows these as class elements.*/
|
||||
export interface SemicolonClassElement extends ClassElement {
|
||||
kind: SyntaxKind.SemicolonClassElement;
|
||||
parent?: ClassDeclaration | ClassExpression;
|
||||
|
@ -861,7 +861,11 @@ namespace ts {
|
|||
| SyntaxKind.BooleanKeyword
|
||||
| SyntaxKind.StringKeyword
|
||||
| SyntaxKind.SymbolKeyword
|
||||
| SyntaxKind.VoidKeyword;
|
||||
| SyntaxKind.ThisKeyword
|
||||
| SyntaxKind.VoidKeyword
|
||||
| SyntaxKind.UndefinedKeyword
|
||||
| SyntaxKind.NullKeyword
|
||||
| SyntaxKind.NeverKeyword;
|
||||
}
|
||||
|
||||
export interface ThisTypeNode extends TypeNode {
|
||||
|
@ -1030,15 +1034,15 @@ namespace ts {
|
|||
_primaryExpressionBrand: any;
|
||||
}
|
||||
|
||||
export interface NullLiteral extends PrimaryExpression {
|
||||
export interface NullLiteral extends PrimaryExpression, TypeNode {
|
||||
kind: SyntaxKind.NullKeyword;
|
||||
}
|
||||
|
||||
export interface BooleanLiteral extends PrimaryExpression {
|
||||
export interface BooleanLiteral extends PrimaryExpression, TypeNode {
|
||||
kind: SyntaxKind.TrueKeyword | SyntaxKind.FalseKeyword;
|
||||
}
|
||||
|
||||
export interface ThisExpression extends PrimaryExpression {
|
||||
export interface ThisExpression extends PrimaryExpression, KeywordTypeNode {
|
||||
kind: SyntaxKind.ThisKeyword;
|
||||
}
|
||||
|
||||
|
@ -2472,6 +2476,14 @@ namespace ts {
|
|||
/* @internal */ getParameterType(signature: Signature, parameterIndex: number): Type;
|
||||
getNonNullableType(type: Type): Type;
|
||||
|
||||
/** Note that the resulting nodes cannot be checked. */
|
||||
|
||||
typeToTypeNode(type: Type, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): TypeNode;
|
||||
/** Note that the resulting nodes cannot be checked. */
|
||||
signatureToSignatureDeclaration(signature: Signature, kind: SyntaxKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): SignatureDeclaration;
|
||||
/** Note that the resulting nodes cannot be checked. */
|
||||
indexInfoToIndexSignatureDeclaration(indexInfo: IndexInfo, kind: IndexKind, enclosingDeclaration?: Node, flags?: NodeBuilderFlags): IndexSignatureDeclaration;
|
||||
|
||||
getSymbolsInScope(location: Node, meaning: SymbolFlags): Symbol[];
|
||||
getSymbolAtLocation(node: Node): Symbol;
|
||||
getSymbolsOfParameterPropertyDeclaration(parameter: ParameterDeclaration, parameterName: string): Symbol[];
|
||||
|
@ -2523,6 +2535,16 @@ namespace ts {
|
|||
/* @internal */ getTypeCount(): number;
|
||||
}
|
||||
|
||||
export enum NodeBuilderFlags {
|
||||
None = 0,
|
||||
allowThisInObjectLiteral = 1 << 0,
|
||||
allowQualifedNameInPlaceOfIdentifier = 1 << 1,
|
||||
allowTypeParameterInQualifiedName = 1 << 2,
|
||||
allowAnonymousIdentifier = 1 << 3,
|
||||
allowEmptyUnionOrIntersection = 1 << 4,
|
||||
allowEmptyTuple = 1 << 5
|
||||
}
|
||||
|
||||
export interface SymbolDisplayBuilder {
|
||||
buildTypeDisplay(type: Type, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
|
||||
buildSymbolDisplay(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, meaning?: SymbolFlags, flags?: SymbolFormatFlags): void;
|
||||
|
@ -4073,7 +4095,7 @@ namespace ts {
|
|||
export type Transformer<T extends Node> = (node: T) => T;
|
||||
|
||||
/**
|
||||
* A function that accepts and possible transforms a node.
|
||||
* A function that accepts and possibly transforms a node.
|
||||
*/
|
||||
export type Visitor = (node: Node) => VisitResult<Node>;
|
||||
|
||||
|
|
|
@ -525,6 +525,10 @@ namespace ts {
|
|||
return getFullWidth(name) === 0 ? "(Missing)" : getTextOfNode(name);
|
||||
}
|
||||
|
||||
export function getNameFromIndexInfo(info: IndexInfo) {
|
||||
return info.declaration ? declarationNameToString(info.declaration.parameters[0].name) : undefined;
|
||||
}
|
||||
|
||||
export function getTextOfPropertyName(name: PropertyName): string {
|
||||
switch (name.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
|
@ -740,8 +744,8 @@ namespace ts {
|
|||
//
|
||||
// let a: A.B.C;
|
||||
//
|
||||
// Calling isPartOfTypeNode would consider the qualified name A.B a type node. Only C or
|
||||
// A.B.C is a type node.
|
||||
// Calling isPartOfTypeNode would consider the qualified name A.B a type node.
|
||||
// Only C and A.B.C are type nodes.
|
||||
if (SyntaxKind.FirstTypeNode <= parent.kind && parent.kind <= SyntaxKind.LastTypeNode) {
|
||||
return true;
|
||||
}
|
||||
|
@ -3713,10 +3717,14 @@ namespace ts {
|
|||
return (kind >= SyntaxKind.FirstTypeNode && kind <= SyntaxKind.LastTypeNode)
|
||||
|| kind === SyntaxKind.AnyKeyword
|
||||
|| kind === SyntaxKind.NumberKeyword
|
||||
|| kind === SyntaxKind.ObjectKeyword
|
||||
|| kind === SyntaxKind.BooleanKeyword
|
||||
|| kind === SyntaxKind.StringKeyword
|
||||
|| kind === SyntaxKind.SymbolKeyword
|
||||
|| kind === SyntaxKind.ThisKeyword
|
||||
|| kind === SyntaxKind.VoidKeyword
|
||||
|| kind === SyntaxKind.UndefinedKeyword
|
||||
|| kind === SyntaxKind.NullKeyword
|
||||
|| kind === SyntaxKind.NeverKeyword
|
||||
|| kind === SyntaxKind.ExpressionWithTypeArguments;
|
||||
}
|
||||
|
|
|
@ -204,21 +204,17 @@ namespace ts {
|
|||
* @param visitor The callback used to visit each child.
|
||||
* @param context A lexical environment context for the visitor.
|
||||
*/
|
||||
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes): T | undefined;
|
||||
export function visitEachChild<T extends Node>(node: T | undefined, visitor: Visitor, context: TransformationContext, nodesVisitor?: typeof visitNodes, tokenVisitor?: Visitor): T | undefined;
|
||||
|
||||
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes): Node {
|
||||
export function visitEachChild(node: Node, visitor: Visitor, context: TransformationContext, nodesVisitor = visitNodes, tokenVisitor?: Visitor): Node {
|
||||
if (node === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const kind = node.kind;
|
||||
// No need to visit nodes with no children.
|
||||
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// We do not yet support types.
|
||||
if ((kind >= SyntaxKind.TypePredicate && kind <= SyntaxKind.LiteralType)) {
|
||||
// No need to visit nodes with no children.
|
||||
if ((kind > SyntaxKind.FirstToken && kind <= SyntaxKind.LastToken) || kind === SyntaxKind.ThisType) {
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -227,6 +223,8 @@ namespace ts {
|
|||
case SyntaxKind.EmptyStatement:
|
||||
case SyntaxKind.OmittedExpression:
|
||||
case SyntaxKind.DebuggerStatement:
|
||||
case SyntaxKind.EndOfDeclarationMarker:
|
||||
case SyntaxKind.MissingDeclaration:
|
||||
// No need to visit nodes with no children.
|
||||
return node;
|
||||
|
||||
|
@ -240,13 +238,53 @@ namespace ts {
|
|||
return updateComputedPropertyName(<ComputedPropertyName>node,
|
||||
visitNode((<ComputedPropertyName>node).expression, visitor, isExpression));
|
||||
|
||||
// Signature elements
|
||||
// Signatures and Signature Elements
|
||||
case SyntaxKind.FunctionType:
|
||||
return updateFunctionTypeNode(<FunctionTypeNode>node,
|
||||
nodesVisitor((<FunctionTypeNode>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionTypeNode>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<FunctionTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ConstructorType:
|
||||
return updateConstructorTypeNode(<ConstructorTypeNode>node,
|
||||
nodesVisitor((<ConstructorTypeNode>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<ConstructorTypeNode>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<ConstructorTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
return updateCallSignatureDeclaration(<CallSignatureDeclaration>node,
|
||||
nodesVisitor((<CallSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<CallSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<CallSignatureDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ConstructSignature:
|
||||
return updateConstructSignatureDeclaration(<ConstructSignatureDeclaration>node,
|
||||
nodesVisitor((<ConstructSignatureDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<ConstructSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<ConstructSignatureDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.MethodSignature:
|
||||
return updateMethodSignature(<MethodSignature>node,
|
||||
nodesVisitor((<MethodSignature>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<MethodSignature>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<MethodSignature>node).type, visitor, isTypeNode),
|
||||
visitNode((<MethodSignature>node).name, visitor, isPropertyName),
|
||||
visitNode((<MethodSignature>node).questionToken, tokenVisitor, isToken));
|
||||
|
||||
case SyntaxKind.IndexSignature:
|
||||
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node,
|
||||
nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier),
|
||||
visitParameterList((<IndexSignatureDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<IndexSignatureDeclaration>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.Parameter:
|
||||
return updateParameter(<ParameterDeclaration>node,
|
||||
nodesVisitor((<ParameterDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<ParameterDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<ParameterDeclaration>node).dotDotDotToken,
|
||||
visitNode((<ParameterDeclaration>node).dotDotDotToken, tokenVisitor, isToken),
|
||||
visitNode((<ParameterDeclaration>node).name, visitor, isBindingName),
|
||||
visitNode((<ParameterDeclaration>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<ParameterDeclaration>node).type, visitor, isTypeNode),
|
||||
visitNode((<ParameterDeclaration>node).initializer, visitor, isExpression));
|
||||
|
||||
|
@ -254,7 +292,74 @@ namespace ts {
|
|||
return updateDecorator(<Decorator>node,
|
||||
visitNode((<Decorator>node).expression, visitor, isExpression));
|
||||
|
||||
// Type member
|
||||
// Types
|
||||
|
||||
case SyntaxKind.TypeReference:
|
||||
return updateTypeReferenceNode(<TypeReferenceNode>node,
|
||||
visitNode((<TypeReferenceNode>node).typeName, visitor, isEntityName),
|
||||
nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.TypePredicate:
|
||||
return updateTypePredicateNode(<TypePredicateNode>node,
|
||||
visitNode((<TypePredicateNode>node).parameterName, visitor),
|
||||
visitNode((<TypePredicateNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.TypeQuery:
|
||||
return updateTypeQueryNode((<TypeQueryNode>node), visitNode((<TypeQueryNode>node).exprName, visitor, isEntityName));
|
||||
|
||||
case SyntaxKind.TypeLiteral:
|
||||
return updateTypeLiteralNode((<TypeLiteralNode>node), nodesVisitor((<TypeLiteralNode>node).members, visitor));
|
||||
|
||||
case SyntaxKind.ArrayType:
|
||||
return updateArrayTypeNode(<ArrayTypeNode>node, visitNode((<ArrayTypeNode>node).elementType, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.TupleType:
|
||||
return updateTypleTypeNode((<TupleTypeNode>node), nodesVisitor((<TupleTypeNode>node).elementTypes, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.UnionType:
|
||||
case SyntaxKind.IntersectionType:
|
||||
return updateUnionOrIntersectionTypeNode(<UnionOrIntersectionTypeNode>node,
|
||||
nodesVisitor((<UnionOrIntersectionTypeNode>node).types, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.ParenthesizedType:
|
||||
Debug.fail("not implemented.");
|
||||
|
||||
case SyntaxKind.TypeOperator:
|
||||
return updateTypeOperatorNode(<TypeOperatorNode>node, visitNode((<TypeOperatorNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.IndexedAccessType:
|
||||
return updateIndexedAccessTypeNode((<IndexedAccessTypeNode>node),
|
||||
visitNode((<IndexedAccessTypeNode>node).objectType, visitor, isTypeNode),
|
||||
visitNode((<IndexedAccessTypeNode>node).indexType, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.MappedType:
|
||||
return updateMappedTypeNode((<MappedTypeNode>node),
|
||||
visitNode((<MappedTypeNode>node).readonlyToken, tokenVisitor, isToken),
|
||||
visitNode((<MappedTypeNode>node).typeParameter, visitor, isTypeParameter),
|
||||
visitNode((<MappedTypeNode>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<MappedTypeNode>node).type, visitor, isTypeNode));
|
||||
|
||||
case SyntaxKind.LiteralType:
|
||||
return updateLiteralTypeNode(<LiteralTypeNode>node,
|
||||
visitNode((<LiteralTypeNode>node).literal, visitor, isExpression));
|
||||
|
||||
// Type Declarations
|
||||
|
||||
case SyntaxKind.TypeParameter:
|
||||
return updateTypeParameterDeclaration(<TypeParameterDeclaration>node,
|
||||
visitNode((<TypeParameterDeclaration>node).name, visitor, isIdentifier),
|
||||
visitNode((<TypeParameterDeclaration>node).constraint, visitor, isTypeNode),
|
||||
visitNode((<TypeParameterDeclaration>node).default, visitor, isTypeNode));
|
||||
|
||||
// Type members
|
||||
|
||||
case SyntaxKind.PropertySignature:
|
||||
return updatePropertySignature((<PropertySignature>node),
|
||||
visitNode((<PropertySignature>node).name, visitor, isPropertyName),
|
||||
visitNode((<PropertySignature>node).questionToken, tokenVisitor, isToken),
|
||||
visitNode((<PropertySignature>node).type, visitor, isTypeNode),
|
||||
visitNode((<PropertySignature>node).initializer, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return updateProperty(<PropertyDeclaration>node,
|
||||
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),
|
||||
|
@ -267,8 +372,9 @@ namespace ts {
|
|||
return updateMethod(<MethodDeclaration>node,
|
||||
nodesVisitor((<MethodDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<MethodDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<MethodDeclaration>node).asteriskToken,
|
||||
visitNode((<MethodDeclaration>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<MethodDeclaration>node).name, visitor, isPropertyName),
|
||||
visitNode((<MethodDeclaration>node).questionToken, tokenVisitor, isToken),
|
||||
nodesVisitor((<MethodDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<MethodDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
visitNode((<MethodDeclaration>node).type, visitor, isTypeNode),
|
||||
|
@ -309,7 +415,7 @@ namespace ts {
|
|||
|
||||
case SyntaxKind.BindingElement:
|
||||
return updateBindingElement(<BindingElement>node,
|
||||
(<BindingElement>node).dotDotDotToken,
|
||||
visitNode((<BindingElement>node).dotDotDotToken, tokenVisitor, isToken),
|
||||
visitNode((<BindingElement>node).propertyName, visitor, isPropertyName),
|
||||
visitNode((<BindingElement>node).name, visitor, isBindingName),
|
||||
visitNode((<BindingElement>node).initializer, visitor, isExpression));
|
||||
|
@ -362,7 +468,7 @@ namespace ts {
|
|||
case SyntaxKind.FunctionExpression:
|
||||
return updateFunctionExpression(<FunctionExpression>node,
|
||||
nodesVisitor((<FunctionExpression>node).modifiers, visitor, isModifier),
|
||||
(<FunctionExpression>node).asteriskToken,
|
||||
visitNode((<FunctionExpression>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<FunctionExpression>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<FunctionExpression>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionExpression>node).parameters, visitor, context, nodesVisitor),
|
||||
|
@ -419,7 +525,7 @@ namespace ts {
|
|||
|
||||
case SyntaxKind.YieldExpression:
|
||||
return updateYield(<YieldExpression>node,
|
||||
(<YieldExpression>node).asteriskToken,
|
||||
visitNode((<YieldExpression>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<YieldExpression>node).expression, visitor, isExpression));
|
||||
|
||||
case SyntaxKind.SpreadElement:
|
||||
|
@ -555,7 +661,7 @@ namespace ts {
|
|||
return updateFunctionDeclaration(<FunctionDeclaration>node,
|
||||
nodesVisitor((<FunctionDeclaration>node).decorators, visitor, isDecorator),
|
||||
nodesVisitor((<FunctionDeclaration>node).modifiers, visitor, isModifier),
|
||||
(<FunctionDeclaration>node).asteriskToken,
|
||||
visitNode((<FunctionDeclaration>node).asteriskToken, tokenVisitor, isToken),
|
||||
visitNode((<FunctionDeclaration>node).name, visitor, isIdentifier),
|
||||
nodesVisitor((<FunctionDeclaration>node).typeParameters, visitor, isTypeParameter),
|
||||
visitParameterList((<FunctionDeclaration>node).parameters, visitor, context, nodesVisitor),
|
||||
|
|
|
@ -31,37 +31,55 @@ namespace ts.codefix {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
let typeString = "any";
|
||||
let typeNode: TypeNode;
|
||||
|
||||
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
|
||||
const binaryExpression = token.parent.parent as BinaryExpression;
|
||||
|
||||
const checker = context.program.getTypeChecker();
|
||||
const widenedType = checker.getWidenedType(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(binaryExpression.right)));
|
||||
typeString = checker.typeToString(widenedType);
|
||||
typeNode = checker.typeToTypeNode(widenedType, classDeclaration) || typeNode;
|
||||
}
|
||||
|
||||
const startPos = classDeclaration.members.pos;
|
||||
typeNode = typeNode ? typeNode : createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
|
||||
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
|
||||
|
||||
const property = createProperty(
|
||||
/*decorators*/undefined,
|
||||
/*modifiers*/ undefined,
|
||||
token.getText(sourceFile),
|
||||
/*questionToken*/ undefined,
|
||||
typeNode,
|
||||
/*initializer*/ undefined);
|
||||
const propertyChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
propertyChangeTracker.insertNodeAfter(sourceFile, openBrace, property, { suffix: context.newLineCharacter });
|
||||
|
||||
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
|
||||
const indexingParameter = createParameter(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
/*dotDotDotToken*/ undefined,
|
||||
"x",
|
||||
/*questionToken*/ undefined,
|
||||
stringTypeNode,
|
||||
/*initializer*/ undefined);
|
||||
const indexSignature = createIndexSignatureDeclaration(
|
||||
/*decorators*/undefined,
|
||||
/*modifiers*/ undefined,
|
||||
[indexingParameter],
|
||||
typeNode);
|
||||
|
||||
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { suffix: context.newLineCharacter });
|
||||
|
||||
return [{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `${token.getFullText(sourceFile)}: ${typeString};`
|
||||
}]
|
||||
}]
|
||||
changes: propertyChangeTracker.getChanges()
|
||||
},
|
||||
{
|
||||
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_missing_property_0), [token.getText()]),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: `[name: string]: ${typeString};`
|
||||
}]
|
||||
}]
|
||||
changes: indexSignatureChangeTracker.getChanges()
|
||||
}];
|
||||
}
|
||||
}
|
|
@ -19,10 +19,9 @@ namespace ts.codefix {
|
|||
const checker = context.program.getTypeChecker();
|
||||
|
||||
if (isClassLike(token.parent)) {
|
||||
const classDecl = token.parent as ClassLikeDeclaration;
|
||||
const startPos = classDecl.members.pos;
|
||||
const classDeclaration = token.parent as ClassLikeDeclaration;
|
||||
|
||||
const extendsNode = getClassExtendsHeritageClauseElement(classDecl);
|
||||
const extendsNode = getClassExtendsHeritageClauseElement(classDeclaration);
|
||||
const instantiatedExtendsType = checker.getTypeAtLocation(extendsNode);
|
||||
|
||||
// Note that this is ultimately derived from a map indexed by symbol names,
|
||||
|
@ -30,18 +29,12 @@ namespace ts.codefix {
|
|||
const extendsSymbols = checker.getPropertiesOfType(instantiatedExtendsType);
|
||||
const abstractAndNonPrivateExtendsSymbols = extendsSymbols.filter(symbolPointsToNonPrivateAndAbstractMember);
|
||||
|
||||
const insertion = getMissingMembersInsertion(classDecl, abstractAndNonPrivateExtendsSymbols, checker, context.newLineCharacter);
|
||||
|
||||
if (insertion.length) {
|
||||
const newNodes = createMissingMemberNodes(classDeclaration, abstractAndNonPrivateExtendsSymbols, checker);
|
||||
const changes = newNodesToChanges(newNodes, getOpenBraceOfClassLike(classDeclaration, sourceFile), context);
|
||||
if (changes && changes.length > 0) {
|
||||
return [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Implement_inherited_abstract_class),
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: insertion
|
||||
}]
|
||||
}]
|
||||
changes
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,14 +11,14 @@ namespace ts.codefix {
|
|||
const token = getTokenAtPosition(sourceFile, start);
|
||||
const checker = context.program.getTypeChecker();
|
||||
|
||||
const classDecl = getContainingClass(token);
|
||||
if (!classDecl) {
|
||||
const classDeclaration = getContainingClass(token);
|
||||
if (!classDeclaration) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const startPos: number = classDecl.members.pos;
|
||||
const classType = checker.getTypeAtLocation(classDecl) as InterfaceType;
|
||||
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDecl);
|
||||
const openBrace = getOpenBraceOfClassLike(classDeclaration, sourceFile);
|
||||
const classType = checker.getTypeAtLocation(classDeclaration) as InterfaceType;
|
||||
const implementedTypeNodes = getClassImplementsHeritageClauseElements(classDeclaration);
|
||||
|
||||
const hasNumericIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.Number);
|
||||
const hasStringIndexSignature = !!checker.getIndexTypeOfType(classType, IndexKind.String);
|
||||
|
@ -31,43 +31,36 @@ namespace ts.codefix {
|
|||
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);
|
||||
|
||||
let newNodes: Node[] = [];
|
||||
createAndAddMissingIndexSignatureDeclaration(implementedType, IndexKind.Number, hasNumericIndexSignature, newNodes);
|
||||
createAndAddMissingIndexSignatureDeclaration(implementedType, IndexKind.String, hasStringIndexSignature, newNodes);
|
||||
newNodes = newNodes.concat(createMissingMemberNodes(classDeclaration, nonPrivateMembers, checker));
|
||||
const message = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Implement_interface_0), [implementedTypeNode.getText()]);
|
||||
if (insertion) {
|
||||
pushAction(result, insertion, message);
|
||||
if (newNodes.length > 0) {
|
||||
pushAction(result, newNodes, 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 createAndAddMissingIndexSignatureDeclaration(type: InterfaceType, kind: IndexKind, hasIndexSigOfKind: boolean, newNodes: Node[]): void {
|
||||
if (hasIndexSigOfKind) {
|
||||
return;
|
||||
}
|
||||
|
||||
function pushAction(result: CodeAction[], insertion: string, description: string): void {
|
||||
const indexInfoOfKind = checker.getIndexInfoOfType(type, kind);
|
||||
|
||||
if (!indexInfoOfKind) {
|
||||
return;
|
||||
}
|
||||
const newIndexSignatureDeclaration = checker.indexInfoToIndexSignatureDeclaration(indexInfoOfKind, kind, classDeclaration);
|
||||
newNodes.push(newIndexSignatureDeclaration);
|
||||
}
|
||||
|
||||
function pushAction(result: CodeAction[], newNodes: Node[], description: string): void {
|
||||
const newAction: CodeAction = {
|
||||
description: description,
|
||||
changes: [{
|
||||
fileName: sourceFile.fileName,
|
||||
textChanges: [{
|
||||
span: { start: startPos, length: 0 },
|
||||
newText: insertion
|
||||
}]
|
||||
}]
|
||||
changes: newNodesToChanges(newNodes, openBrace, context)
|
||||
};
|
||||
result.push(newAction);
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace ts.codefix {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
// figure out if the this access is actuall inside the supercall
|
||||
// figure out if the `this` access is actually inside the supercall
|
||||
// i.e. super(this.a), since in that case we won't suggest a fix
|
||||
if (superCall.expression && superCall.expression.kind == SyntaxKind.CallExpression) {
|
||||
const arguments = (<CallExpression>superCall.expression).arguments;
|
||||
|
|
|
@ -1,47 +1,88 @@
|
|||
/* @internal */
|
||||
namespace ts.codefix {
|
||||
|
||||
export function newNodesToChanges(newNodes: Node[], insertAfter: Node, context: CodeFixContext) {
|
||||
const sourceFile = context.sourceFile;
|
||||
|
||||
const changeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
|
||||
|
||||
for (const newNode of newNodes) {
|
||||
changeTracker.insertNodeAfter(sourceFile, insertAfter, newNode, { suffix: context.newLineCharacter });
|
||||
}
|
||||
|
||||
const changes = changeTracker.getChanges();
|
||||
if (!some(changes)) {
|
||||
return changes;
|
||||
}
|
||||
|
||||
Debug.assert(changes.length === 1);
|
||||
const consolidatedChanges: FileTextChanges[] = [{
|
||||
fileName: changes[0].fileName,
|
||||
textChanges: [{
|
||||
span: changes[0].textChanges[0].span,
|
||||
newText: changes[0].textChanges.reduce((prev, cur) => prev + cur.newText, "")
|
||||
}]
|
||||
|
||||
}];
|
||||
return consolidatedChanges;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 {
|
||||
export function createMissingMemberNodes(classDeclaration: ClassLikeDeclaration, possiblyMissingSymbols: Symbol[], checker: TypeChecker): Node[] {
|
||||
const classMembers = classDeclaration.symbol.members;
|
||||
const missingMembers = possiblyMissingSymbols.filter(symbol => !classMembers.has(symbol.getName()));
|
||||
|
||||
let insertion = "";
|
||||
|
||||
let newNodes: Node[] = [];
|
||||
for (const symbol of missingMembers) {
|
||||
insertion = insertion.concat(getInsertionForMemberSymbol(symbol, classDeclaration, checker, newlineChar));
|
||||
const newNode = createNewNodeForMemberSymbol(symbol, classDeclaration, checker);
|
||||
if (newNode) {
|
||||
if (Array.isArray(newNode)) {
|
||||
newNodes = newNodes.concat(newNode);
|
||||
}
|
||||
return insertion;
|
||||
else {
|
||||
newNodes.push(newNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newNodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 {
|
||||
function createNewNodeForMemberSymbol(symbol: Symbol, enclosingDeclaration: ClassLikeDeclaration, checker: TypeChecker): Node[] | Node | undefined {
|
||||
const declarations = symbol.getDeclarations();
|
||||
if (!(declarations && declarations.length)) {
|
||||
return "";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const declaration = declarations[0] as Declaration;
|
||||
const name = declaration.name ? declaration.name.getText() : undefined;
|
||||
const visibility = getVisibilityPrefixWithSpace(getModifierFlags(declaration));
|
||||
|
||||
const type = checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration);
|
||||
// Clone name to remove leading trivia.
|
||||
const name = getSynthesizedClone(<PropertyName>declaration.name);
|
||||
const visibilityModifier = createVisibilityModifier(getModifierFlags(declaration));
|
||||
const modifiers = visibilityModifier ? createNodeArray([visibilityModifier]) : undefined;
|
||||
const type = checker.getWidenedType(checker.getTypeOfSymbolAtLocation(symbol, enclosingDeclaration));
|
||||
const optional = !!(symbol.flags & SymbolFlags.Optional);
|
||||
|
||||
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}`;
|
||||
|
||||
const typeNode = checker.typeToTypeNode(type, enclosingDeclaration);
|
||||
const property = createProperty(
|
||||
/*decorators*/undefined,
|
||||
modifiers,
|
||||
name,
|
||||
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
typeNode,
|
||||
/*initializer*/ undefined);
|
||||
return property;
|
||||
case SyntaxKind.MethodSignature:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
// The signature for the implementation appears as an entry in `signatures` iff
|
||||
|
@ -52,109 +93,142 @@ namespace ts.codefix {
|
|||
// (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 (!some(signatures)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (declarations.length === 1) {
|
||||
Debug.assert(signatures.length === 1);
|
||||
const sigString = checker.signatureToString(signatures[0], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
return getStubbedMethod(visibility, name, sigString, newlineChar);
|
||||
const signature = signatures[0];
|
||||
return signatureToMethodDeclaration(signature, enclosingDeclaration, createStubbedMethodBody());
|
||||
}
|
||||
|
||||
let result = "";
|
||||
const signatureDeclarations: MethodDeclaration[] = [];
|
||||
for (let i = 0; i < signatures.length; i++) {
|
||||
const sigString = checker.signatureToString(signatures[i], enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
result += `${visibility}${name}${sigString};${newlineChar}`;
|
||||
const signature = signatures[i];
|
||||
const methodDeclaration = signatureToMethodDeclaration(signature, enclosingDeclaration);
|
||||
if (methodDeclaration) {
|
||||
signatureDeclarations.push(methodDeclaration);
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
const signature = checker.getSignatureFromDeclaration(declarations[declarations.length - 1] as SignatureDeclaration);
|
||||
const methodDeclaration = signatureToMethodDeclaration(signature, enclosingDeclaration, createStubbedMethodBody());
|
||||
if (methodDeclaration) {
|
||||
signatureDeclarations.push(methodDeclaration);
|
||||
}
|
||||
}
|
||||
else {
|
||||
Debug.assert(declarations.length === signatures.length);
|
||||
bodySig = createBodySignatureWithAnyTypes(signatures, enclosingDeclaration, checker);
|
||||
const methodImplementingSignatures = createMethodImplementingSignatures(signatures, name, optional, modifiers);
|
||||
signatureDeclarations.push(methodImplementingSignatures);
|
||||
}
|
||||
const sigString = checker.signatureToString(bodySig, enclosingDeclaration, TypeFormatFlags.SuppressAnyReturnType, SignatureKind.Call);
|
||||
result += getStubbedMethod(visibility, name, sigString, newlineChar);
|
||||
|
||||
return result;
|
||||
return signatureDeclarations;
|
||||
default:
|
||||
return "";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function signatureToMethodDeclaration(signature: Signature, enclosingDeclaration: Node, body?: Block) {
|
||||
const signatureDeclaration = <MethodDeclaration>checker.signatureToSignatureDeclaration(signature, SyntaxKind.MethodDeclaration, enclosingDeclaration);
|
||||
if (signatureDeclaration) {
|
||||
signatureDeclaration.decorators = undefined;
|
||||
signatureDeclaration.modifiers = modifiers;
|
||||
signatureDeclaration.name = name;
|
||||
signatureDeclaration.questionToken = optional ? createToken(SyntaxKind.QuestionToken) : undefined;
|
||||
signatureDeclaration.body = body;
|
||||
}
|
||||
return signatureDeclaration;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
function createMethodImplementingSignatures(signatures: Signature[], name: PropertyName, optional: boolean, modifiers: Modifier[] | undefined): MethodDeclaration {
|
||||
/** This is *a* signature with the maximal number of arguments,
|
||||
* such that if there is a "maximal" signature without rest arguments,
|
||||
* this is one of them.
|
||||
*/
|
||||
let maxArgsSignature = signatures[0];
|
||||
let minArgumentCount = signatures[0].minArgumentCount;
|
||||
let hasRestParameter = false;
|
||||
let someSigHasRestParameter = 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;
|
||||
if (sig.hasRestParameter) {
|
||||
someSigHasRestParameter = true;
|
||||
}
|
||||
if (sig.parameters.length >= maxArgsSignature.parameters.length && (!sig.hasRestParameter || maxArgsSignature.hasRestParameter)) {
|
||||
maxArgsSignature = sig;
|
||||
}
|
||||
}
|
||||
const maxArgsParameterSymbolNames = signatures[maxArgsIndex].getParameters().map(symbol => symbol.getName());
|
||||
const maxNonRestArgs = maxArgsSignature.parameters.length - (maxArgsSignature.hasRestParameter ? 1 : 0);
|
||||
const maxArgsParameterSymbolNames = maxArgsSignature.parameters.map(symbol => symbol.getName());
|
||||
|
||||
const optionalToken = createToken(SyntaxKind.QuestionToken);
|
||||
|
||||
newSignatureDeclaration.parameters = createNodeArray<ParameterDeclaration>();
|
||||
const parameters: ParameterDeclaration[] = [];
|
||||
for (let i = 0; i < maxNonRestArgs; i++) {
|
||||
const newParameter = createParameterDeclarationWithoutType(i, minArgumentCount, newSignatureDeclaration);
|
||||
newSignatureDeclaration.parameters.push(newParameter);
|
||||
const anyType = createKeywordTypeNode(SyntaxKind.AnyKeyword);
|
||||
const newParameter = createParameter(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
/*dotDotDotToken*/ undefined,
|
||||
maxArgsParameterSymbolNames[i],
|
||||
/*questionToken*/ i >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
anyType,
|
||||
/*initializer*/ undefined);
|
||||
parameters.push(newParameter);
|
||||
}
|
||||
|
||||
if (hasRestParameter) {
|
||||
const restParameter = createParameterDeclarationWithoutType(maxNonRestArgs, minArgumentCount, newSignatureDeclaration);
|
||||
restParameter.dotDotDotToken = createToken(SyntaxKind.DotDotDotToken);
|
||||
newSignatureDeclaration.parameters.push(restParameter);
|
||||
if (someSigHasRestParameter) {
|
||||
const anyArrayType = createArrayTypeNode(createKeywordTypeNode(SyntaxKind.AnyKeyword));
|
||||
const restParameter = createParameter(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
createToken(SyntaxKind.DotDotDotToken),
|
||||
maxArgsParameterSymbolNames[maxNonRestArgs] || "rest",
|
||||
/*questionToken*/ maxNonRestArgs >= minArgumentCount ? createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
anyArrayType,
|
||||
/*initializer*/ undefined);
|
||||
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 createStubbedMethod(
|
||||
modifiers,
|
||||
name,
|
||||
optional,
|
||||
/*typeParameters*/undefined,
|
||||
parameters,
|
||||
/*returnType*/ undefined);
|
||||
}
|
||||
|
||||
return newParameter;
|
||||
}
|
||||
export function createStubbedMethod(modifiers: Modifier[], name: PropertyName, optional: boolean, typeParameters: TypeParameterDeclaration[] | undefined, parameters: ParameterDeclaration[], returnType: TypeNode | undefined) {
|
||||
return createMethodDeclaration(
|
||||
/*decorators*/ undefined,
|
||||
modifiers,
|
||||
/*asteriskToken*/ undefined,
|
||||
name,
|
||||
optional ? createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
typeParameters,
|
||||
parameters,
|
||||
returnType,
|
||||
createStubbedMethodBody());
|
||||
}
|
||||
|
||||
export function getStubbedMethod(visibility: string, name: string, sigString = "()", newlineChar: string): string {
|
||||
return `${visibility}${name}${sigString}${getMethodBodyStub(newlineChar)}`;
|
||||
function createStubbedMethodBody() {
|
||||
return createBlock(
|
||||
[createThrow(
|
||||
createNew(
|
||||
createIdentifier("Error"),
|
||||
/*typeArguments*/undefined,
|
||||
[createLiteral("Method not implemented.")]))],
|
||||
/*multiline*/true);
|
||||
}
|
||||
|
||||
function getMethodBodyStub(newlineChar: string) {
|
||||
return ` {${newlineChar}throw new Error('Method not implemented.');${newlineChar}}${newlineChar}`;
|
||||
}
|
||||
|
||||
function getVisibilityPrefixWithSpace(flags: ModifierFlags): string {
|
||||
function createVisibilityModifier(flags: ModifierFlags) {
|
||||
if (flags & ModifierFlags.Public) {
|
||||
return "public ";
|
||||
return createToken(SyntaxKind.PublicKeyword);
|
||||
}
|
||||
else if (flags & ModifierFlags.Protected) {
|
||||
return "protected ";
|
||||
return createToken(SyntaxKind.ProtectedKeyword);
|
||||
}
|
||||
return "";
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const SymbolConstructor = objectAllocator.getSymbolConstructor();
|
||||
}
|
|
@ -275,8 +275,8 @@ namespace ts.textChanges {
|
|||
|
||||
/**
|
||||
* This function should be used to insert nodes in lists when nodes don't carry separators as the part of the node range,
|
||||
* i.e. arguments in arguments lists, parameters in parameter lists etc. Statements or class elements are different in sense that
|
||||
* for them separators are treated as the part of the node.
|
||||
* i.e. arguments in arguments lists, parameters in parameter lists etc.
|
||||
* Note that separators are part of the node in statements and class elements.
|
||||
*/
|
||||
public insertNodeInListAfter(sourceFile: SourceFile, after: Node, newNode: Node) {
|
||||
const containingList = formatting.SmartIndenter.getContainingList(after, sourceFile);
|
||||
|
@ -484,7 +484,7 @@ namespace ts.textChanges {
|
|||
private static normalize(changes: Change[]) {
|
||||
// order changes by start position
|
||||
const normalized = stableSort(changes, (a, b) => a.range.pos - b.range.pos);
|
||||
// verify that end position of the change is less than start position of the next change
|
||||
// verify that change intervals do not overlap, except possibly at end points.
|
||||
for (let i = 0; i < normalized.length - 2; i++) {
|
||||
Debug.assert(normalized[i].range.end <= normalized[i + 1].range.pos);
|
||||
}
|
||||
|
@ -549,7 +549,7 @@ namespace ts.textChanges {
|
|||
};
|
||||
|
||||
function assignPositionsToNode(node: Node): Node {
|
||||
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray);
|
||||
const visited = visitEachChild(node, assignPositionsToNode, nullTransformationContext, assignPositionsToNodeArray, assignPositionsToNode);
|
||||
// create proxy node for non synthesized nodes
|
||||
const newNode = nodeIsSynthesized(visited)
|
||||
? visited
|
||||
|
|
|
@ -1384,4 +1384,8 @@ namespace ts {
|
|||
// First token is the open curly, this is where we want to put the 'super' call.
|
||||
return constructor.body.getFirstToken(sourceFile);
|
||||
}
|
||||
|
||||
export function getOpenBraceOfClassLike(declaration: ClassLikeDeclaration, sourceFile: SourceFile) {
|
||||
return getTokenAtPosition(sourceFile, declaration.members.pos - 1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(): void{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
//// abstract f(a: number, b: string): this;
|
||||
//// abstract f(a: string, b: number): Function;
|
||||
//// abstract f(a: string): Function;
|
||||
//// abstract foo(): number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]}
|
||||
|
@ -15,6 +16,9 @@ verify.rangeAfterCodeFix(`
|
|||
f(a: string, b: number): Function;
|
||||
f(a: string): Function;
|
||||
f(a: any, b?: any) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
foo(): number {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(): this {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -4,10 +4,9 @@
|
|||
//// abstract f(x: T): T;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A<number> {[|
|
||||
//// |]}
|
||||
//// class C extends A<number> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f(x: number): number{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -4,10 +4,9 @@
|
|||
//// abstract f(x: T): T;
|
||||
//// }
|
||||
////
|
||||
//// class C<U> extends A<U> {[|
|
||||
//// |]}
|
||||
//// class C<U> extends A<U> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f(x: U): U{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -4,8 +4,7 @@
|
|||
//// private abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
// We don't know how to fix this problem. We can:
|
||||
// 1) Make x protected, and then insert.
|
||||
|
|
|
@ -4,17 +4,12 @@
|
|||
//// abstract x: number;
|
||||
//// abstract y: this;
|
||||
//// abstract z: A;
|
||||
//// abstract foo(): number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
y: this;
|
||||
z: A;
|
||||
foo(): number {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -4,8 +4,7 @@
|
|||
//// protected abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
protected x: number;
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
//// public abstract x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[|
|
||||
//// |]}
|
||||
//// class C extends A {[| |]}
|
||||
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
public x: number;
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
//// abstract z: number;
|
||||
//// }
|
||||
////
|
||||
//// class C extends A {[| |]
|
||||
//// constructor(public x: number) { super(); }
|
||||
//// class C extends A {[|
|
||||
//// |]constructor(public x: number) { super(); }
|
||||
//// y: number;
|
||||
//// }
|
||||
|
||||
|
|
|
@ -8,6 +8,6 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(): void{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// class A {
|
||||
//// foo() {
|
||||
//// return class { x: number; }
|
||||
//// }
|
||||
//// bar() {
|
||||
//// return new class { x: number; }
|
||||
//// }
|
||||
//// }
|
||||
//// class C implements A {[| |]}
|
||||
|
||||
verify.not.codeFixAvailable();
|
|
@ -13,6 +13,6 @@
|
|||
//// }
|
||||
|
||||
verify.rangeAfterCodeFix(`f1(): void{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -9,6 +9,6 @@
|
|||
verify.rangeAfterCodeFix(`
|
||||
method(a: number, b: string): boolean;
|
||||
method(a: string | number, b?: string | number): boolean | Function {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
|
|||
method(a: string, b: number): Function;
|
||||
method(a: string): Function;
|
||||
method(a: string | number, b?: string | number): boolean | Function {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// class A {
|
||||
//// A: typeof A;
|
||||
//// }
|
||||
//// class D implements A {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
A: typeof A;
|
||||
`);
|
|
@ -24,8 +24,7 @@
|
|||
//// }
|
||||
////
|
||||
//// interface I6 extends C4 {}
|
||||
//// class C5 implements I6 {[|
|
||||
//// |]}
|
||||
//// class C5 implements I6 {[| |]}
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,20 +0,0 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class C1 {
|
||||
////
|
||||
//// }
|
||||
////
|
||||
//// abstract class C2 {
|
||||
//// abstract f1<T extends number>();
|
||||
//// }
|
||||
////
|
||||
//// interface I1 extends C1, C2 {}
|
||||
////
|
||||
//// class C3 implements I1 {[|
|
||||
////
|
||||
//// |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f1<T extends number>(){
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
`);
|
|
@ -0,0 +1,15 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// x: number[];
|
||||
//// y: Array<number>;
|
||||
//// z: [number, string, I];
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number[];
|
||||
y: number[];
|
||||
z: [number, string, I];
|
||||
`);
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// (x: number, b: string): number;
|
||||
//// }
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @lib: es2017
|
||||
|
||||
//// namespace N {
|
||||
//// /**enum prefix */
|
||||
//// export enum /**enum identifier prefix */ E /**open-brace prefix*/ {
|
||||
//// /* literal prefix */ a /** comma prefix */,
|
||||
//// /* literal prefix */ b /** comma prefix */,
|
||||
//// /* literal prefix */ c
|
||||
//// /** close brace prefix */ }
|
||||
//// /** interface prefix */
|
||||
//// export interface /**interface name prefix */ I /**open-brace prefix*/ {
|
||||
//// /** property prefix */ a /** colon prefix */: /** enum literal prefix 1*/ E /** dot prefix */. /** enum literal prefix 2*/a;
|
||||
//// /** property prefix */ b /** colon prefix */: /** enum prefix */ E;
|
||||
//// /**method signature prefix */foo /**open angle prefix */< /**type parameter name prefix */ X /** closing angle prefix */> /**open paren prefix */(/** parameter prefix */ a/** colon prefix */: /** parameter type prefix */ X /** close paren prefix */) /** colon prefix */: /** return type prefix */ string /** semicolon prefix */;
|
||||
//// /**close-brace prefix*/ }
|
||||
//// /**close-brace prefix*/ }
|
||||
//// class C implements N.I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
a: N.E.a;
|
||||
b: N.E;
|
||||
foo<X>(a: X): string {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -11,11 +11,11 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
["foo"](o: any): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
["x"]: boolean;
|
||||
[1](): string {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[2]: boolean;
|
||||
`);
|
|
@ -17,35 +17,34 @@
|
|||
//// [Symbol.toStringTag]: string;
|
||||
//// [Symbol.unscopables]: any;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I<number> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
[Symbol.hasInstance](o: any): boolean {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.isConcatSpreadable]: boolean;
|
||||
[Symbol.iterator]() {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.match]: boolean;
|
||||
[Symbol.replace](...args: {}) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.search](str: string): number {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.species](): number {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.split](str: string, limit?: number): {} {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.toPrimitive](hint: "number"): number;
|
||||
[Symbol.toPrimitive](hint: "default"): number;
|
||||
[Symbol.toPrimitive](hint: "string"): string;
|
||||
[Symbol.toPrimitive](hint: any) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
[Symbol.toStringTag]: string;
|
||||
[Symbol.unscopables]: any;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// new (x: number, b: string);
|
||||
//// }
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
//// x: number;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// |]}
|
||||
//// class C implements I1,I2 {[| |]}
|
||||
|
||||
verify.codeFixAvailable();
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// x: {};
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[|
|
||||
//// |]constructor() { }
|
||||
//// }
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: {};
|
||||
`);
|
|
@ -9,10 +9,9 @@
|
|||
//// f1();
|
||||
//// }
|
||||
////
|
||||
//// class C1 implements N1.I1 {[|
|
||||
//// |]}
|
||||
//// class C1 implements N1.I1 {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f1(): string{
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -3,9 +3,7 @@
|
|||
//// interface I {
|
||||
//// [x: number]: I;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[|
|
||||
//// |]}
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
[x: number]: I;
|
||||
|
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<X> {
|
||||
//// x: keyof X;
|
||||
//// }
|
||||
//// class C<Y> implements I<Y> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: keyof Y;
|
||||
`);
|
|
@ -0,0 +1,13 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// abstract class C1 { }
|
||||
//// abstract class C2 {
|
||||
//// abstract f1<T extends number>();
|
||||
//// }
|
||||
//// interface I1 extends C1, C2 { }
|
||||
//// class C3 implements I1 {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f1<T extends number>(){
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -0,0 +1,10 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I<X> {
|
||||
//// x: { readonly [K in keyof X]: X[K] };
|
||||
//// }
|
||||
//// class C<Y> implements I<Y> {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: { readonly [K in keyof X]: Y[K]; };
|
||||
`);
|
|
@ -0,0 +1,58 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @lib: es2017
|
||||
|
||||
//// /** asdf */
|
||||
//// interface I {
|
||||
//// 1;
|
||||
//// 2;
|
||||
//// 3;
|
||||
//// 4;
|
||||
//// 5;
|
||||
//// 6;
|
||||
//// 7;
|
||||
//// 8;
|
||||
//// 9;
|
||||
//// 10;
|
||||
//// 11;
|
||||
//// 12;
|
||||
//// 13;
|
||||
//// 14;
|
||||
//// 15;
|
||||
//// 16;
|
||||
//// 17;
|
||||
//// 18;
|
||||
//// 19;
|
||||
//// 20;
|
||||
//// 21;
|
||||
//// 22;
|
||||
//// /** a nice safe prime */
|
||||
//// 23;
|
||||
//// }
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
1: any;
|
||||
2: any;
|
||||
3: any;
|
||||
4: any;
|
||||
5: any;
|
||||
6: any;
|
||||
7: any;
|
||||
8: any;
|
||||
9: any;
|
||||
10: any;
|
||||
11: any;
|
||||
12: any;
|
||||
13: any;
|
||||
14: any;
|
||||
15: any;
|
||||
16: any;
|
||||
17: any;
|
||||
18: any;
|
||||
19: any;
|
||||
20: any;
|
||||
21: any;
|
||||
22: any;
|
||||
23: any;
|
||||
`);
|
|
@ -4,11 +4,10 @@
|
|||
//// f(x: number, y: this): I
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[|
|
||||
//// |]}
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(x: number,y: this): I {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// f(i: any): i is I;
|
||||
//// f(): this is I;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
f(i: any): i is I;
|
||||
f(): this is I;
|
||||
f(i?: any) {
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -8,12 +8,11 @@
|
|||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// y: number;
|
||||
//// |]}
|
||||
//// |]y: number;
|
||||
//// }
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
y: number;
|
||||
`);
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
|
|
|
@ -8,12 +8,11 @@
|
|||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// x: number;
|
||||
//// |]}
|
||||
//// |]x: number;
|
||||
//// }
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
y: number;
|
||||
x: number;
|
||||
`);
|
||||
|
||||
verify.not.codeFixAvailable();
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
//// x: string;
|
||||
//// }
|
||||
////
|
||||
//// class C implements I1,I2 {[|
|
||||
//// |]}
|
||||
//// class C implements I1,I2 {[| |]}
|
||||
|
||||
verify.codeFixAvailable();
|
|
@ -9,20 +9,19 @@
|
|||
//// h();
|
||||
//// }
|
||||
////
|
||||
//// class C1 implements I1 {[|
|
||||
//// |]}
|
||||
//// class C1 implements I1 {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
y: number;
|
||||
z: number;
|
||||
f() {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
g() {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
h() {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
|
|||
method(a: string, b: number): Function;
|
||||
method(a: string): Function;
|
||||
method(a: any, b?: any) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
|
|||
method(a: string, ...b: number[]): Function;
|
||||
method(a: string): Function;
|
||||
method(a: any, ...b?: any[]) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -13,6 +13,6 @@ verify.rangeAfterCodeFix(`
|
|||
method(a: string, b: number): Function;
|
||||
method(a: string): Function;
|
||||
method(a: any, b?: any, ...rest?: any[]) {
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
||||
|
|
|
@ -8,9 +8,7 @@
|
|||
//// interface I1 {
|
||||
//// f1();
|
||||
//// }
|
||||
////
|
||||
//// class C1 implements N1.I1 {[|
|
||||
//// |]}
|
||||
//// class C1 implements N1.I1 {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: number;
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
// @lib: es2017
|
||||
|
||||
//// enum E { a,b,c }
|
||||
//// interface I {
|
||||
//// x: E;
|
||||
//// y: E.a
|
||||
//// z: symbol;
|
||||
//// w: object;
|
||||
//// }
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
x: E;
|
||||
y: E.a;
|
||||
z: symbol;
|
||||
w: object;
|
||||
`);
|
|
@ -0,0 +1,34 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// interface I {
|
||||
//// a0: {};
|
||||
//// a1: { (b1: number, c1: string): number; };
|
||||
//// a2: (b2: number, c2: string) => number;
|
||||
//// a3: { (b3: number, c3: string): number, x: number };
|
||||
////
|
||||
//// a4: { new (b1: number, c1: string): number; };
|
||||
//// a5: new (b2: number, c2: string) => number;
|
||||
//// a6: { new (b3: number, c3: string): number, x: number };
|
||||
////
|
||||
//// a7: { foo(b7: number, c7: string): number };
|
||||
////
|
||||
//// a8: { (b81: number, c81: string): number, new (b82: number, c82: string): number; };
|
||||
////
|
||||
//// a9: { (b9: number, c9: string): number; [d9: number]: I };
|
||||
//// a10: { (b10: number, c10: string): number; [d10: string]: I };
|
||||
//// }
|
||||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
a0: {};
|
||||
a1: (b1: number, c1: string) => number;
|
||||
a2: (b2: number, c2: string) => number;
|
||||
a3: { (b3: number, c3: string): number; x: number; };
|
||||
a4: new (b1: number, c1: string) => number;
|
||||
a5: new (b2: number, c2: string) => number;
|
||||
a6: { new (b3: number, c3: string): number; x: number; };
|
||||
a7: { foo(b7: number, c7: string): number; };
|
||||
a8: { (b81: number, c81: string): number; new (b82: number, c82: string): number; };
|
||||
a9: { (b9: number, c9: string): number; [d9: number]: I; };
|
||||
a10: { (b10: number, c10: string): number; [d10: string]: I; };
|
||||
`);
|
|
@ -0,0 +1,12 @@
|
|||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// namespace N {
|
||||
//// export interface I {
|
||||
//// y: I;
|
||||
//// }
|
||||
//// }
|
||||
//// class C1 implements N.I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`
|
||||
y: N.I;
|
||||
`);
|
|
@ -6,8 +6,8 @@
|
|||
//// z: number & { __iBrand: any };
|
||||
//// }
|
||||
////
|
||||
//// class C implements I {[| |]
|
||||
//// constructor(public x: number) { }
|
||||
//// class C implements I {[|
|
||||
//// |]constructor(public x: number) { }
|
||||
//// y: number;
|
||||
//// }
|
||||
|
||||
|
|
|
@ -7,6 +7,6 @@
|
|||
//// class C implements I {[| |]}
|
||||
|
||||
verify.rangeAfterCodeFix(`f<T extends number>(x: T){
|
||||
throw new Error('Method not implemented.');
|
||||
throw new Error("Method not implemented.");
|
||||
}
|
||||
`);
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
verify.rangeAfterCodeFix(`
|
||||
class A {
|
||||
[name: string]: number;
|
||||
[x: string]: number;
|
||||
|
||||
constructor() {
|
||||
this.x = 10;
|
||||
|
|
Loading…
Reference in a new issue