basic end-to-end building type nodes

This commit is contained in:
Arthur Ozga
2017-03-11 18:58:46 -08:00
parent fff531ca25
commit bf2acf1d2c
6 changed files with 159 additions and 62 deletions

View File

@@ -2190,7 +2190,7 @@ namespace ts {
}
function createTypeNode(type: Type) {
let encounteredError = false;
// let encounteredError = false;
let checkAlias = true;
return createTypeNodeWorker(type);
@@ -2224,9 +2224,17 @@ namespace ts {
if (type.flags & TypeFlags.Number) {
return createKeywordTypeNode(SyntaxKind.NumberKeyword);
}
if (type.flags & (TypeFlags.Boolean | TypeFlags.StringOrNumberLiteral)) {
if(type.flags & TypeFlags.Boolean) {
// TODO: this is probably x: boolean. How do we deal with x: true ?
return createKeywordTypeNode(SyntaxKind.BooleanKeyword);
}
if (type.flags & (TypeFlags.StringLiteral)) {
// TODO: check if this actually works with boolean.
return createLiteralTypeNode((<LiteralType>type).text);
return createLiteralTypeNode((createLiteral((<LiteralType>type).text)));
}
if (type.flags & (TypeFlags.NumberLiteral)) {
// TODO: check if this actually works with boolean.
return createLiteralTypeNode((createNumericLiteral((<LiteralType>type).text)));
}
if (type.flags & TypeFlags.Void) {
return createKeywordTypeNode(SyntaxKind.VoidKeyword);
@@ -2279,11 +2287,10 @@ namespace ts {
if (objectFlags & ObjectFlags.ClassOrInterface) {
Debug.assert(!!(type.flags & TypeFlags.Object));
// If type is a class or interface type that wasn't hit by the isSymbolAccessible check above,
// type must be an anonymous class or interface.
encounteredError = true;
return undefined;
const name = getNameOfSymbol(type.symbol);
// TODO: handle type arguments.
// TODO: handle anonymous classes.
return createTypeReferenceNode(name);
}
if (objectFlags & ObjectFlags.Reference) {

View File

@@ -234,23 +234,75 @@ namespace ts {
return <KeywordTypeNode>createSynthesizedNode(kind);
}
export function createLiteralTypeNode(value: string | number | boolean) {
const literal = createLiteral(value);
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;
}
// TODO: handle qualified names, ie EntityName's.
export function createTypeReferenceNode(typeName: string | Identifier, typeArguments?: NodeArray<TypeNode>) {
const typeReference = createSynthesizedNode(SyntaxKind.TypeReference) as TypeReferenceNode;
typeReference.typeName = asName(typeName);
typeReference.typeName.parent
typeReference.typeArguments = typeArguments;
return typeReference;
}
export function updateTypeReferenceNode(node: TypeReferenceNode, typeName: Identifier, typeArguments?: NodeArray<TypeNode>) {
return node.typeName !== typeName
|| node.typeArguments !== typeArguments
? updateNode(createTypeReferenceNode(typeName, typeArguments), 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[]): UnionOrIntersectionTypeNode {
const unionTypeNode = createSynthesizedNode(kind) as UnionTypeNode | IntersectionTypeNode;
unionTypeNode.types = asNodeArray(types);
return unionTypeNode;
}
export function updateUnionOrIntersectionTypeNode(node: UnionOrIntersectionTypeNode, kind: SyntaxKind.UnionType | SyntaxKind.IntersectionType, types: NodeArray<TypeNode>) {
return node.types !== types
|| node.kind !== kind
? updateNode(createUnionOrIntersectionTypeNode(kind, types), node)
: node;
}
export function createTypeLiteralNode(members: TypeElement[]) {
const typeLiteralNode = createSynthesizedNode(SyntaxKind.LiteralType) as TypeLiteralNode;
typeLiteralNode.members = asNodeArray(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 = asNodeArray(elementTypes);
return tupleTypeNode;
}
export function updateTypleTypeNode(node: TupleTypeNode, elementTypes: TypeNode[]) {
return node.elementTypes !== elementTypes
? updateNode(createTupleTypeNode(elementTypes), node)
: node;
}
// Type Declarations
export function createTypeParameterNode(name: string | Identifier, constraint?: TypeNode, defaultParameter?: TypeNode) {
const typeParameter = createSynthesizedNode(SyntaxKind.TypeParameter) as TypeParameterDeclaration;
typeParameter.name = asName(name);
@@ -260,31 +312,6 @@ namespace ts {
return typeParameter;
}
export function createUnionTypeNode(types: NodeArray<TypeNode>) {
const unionTypeNode = createSynthesizedNode(SyntaxKind.UnionType) as UnionTypeNode;
unionTypeNode.types = asNodeArray(types);
return unionTypeNode;
}
export function createIntersectionTypeNode(types: NodeArray<TypeNode>) {
const intersectionTypeNode = createSynthesizedNode(SyntaxKind.IntersectionType) as IntersectionTypeNode;
intersectionTypeNode.types = asNodeArray(types);
return intersectionTypeNode;
}
export function createTypeLiteralNode(typeElements: TypeElement[]) {
const typeLiteralNode = createSynthesizedNode(SyntaxKind.LiteralType) as TypeLiteralNode;
typeLiteralNode.members = asNodeArray(typeElements);
return typeLiteralNode;
}
export function createTupleTypeNode(types: NodeArray<TypeNode>) {
const tupleTypeNode = createSynthesizedNode(SyntaxKind.TupleType) as TupleTypeNode;
tupleTypeNode.elementTypes = asNodeArray(types);
return tupleTypeNode;
}
// Signature elements
/** Note, can also be used to construct index signatures. */
@@ -298,10 +325,11 @@ namespace ts {
}
// TODO: check usage of name...
export function createIndexSignature(parameter: ParameterDeclaration, type: TypeNode, decorators?: Decorator[], modifiers?: Modifier[]): IndexSignatureDeclaration {
// TODO: create entry in visitor.ts
export function createIndexSignatureDeclaration(parameters: ParameterDeclaration[], type: TypeNode, decorators?: Decorator[], modifiers?: Modifier[]): IndexSignatureDeclaration {
const indexSignature = createSignature(
SyntaxKind.IndexSignature
, asNodeArray([parameter])
, asNodeArray(parameters)
, /*name*/ undefined
, /*typeParameters*/undefined
, type) as IndexSignatureDeclaration;
@@ -310,6 +338,15 @@ namespace ts {
return indexSignature;
}
export function updateIndexSignatureDeclaration(node: IndexSignatureDeclaration, parameters: ParameterDeclaration[], type: TypeNode, decorators?: Decorator[], modifiers?: Modifier[]) {
return node.parameters !== parameters
|| node.type !== type
|| node.decorators !== decorators
|| node.modifiers !== modifiers
? updateNode(createIndexSignatureDeclaration(parameters, type, decorators, modifiers), node)
: node;
}
export function createParameter(decorators: Decorator[] | undefined, modifiers: Modifier[] | undefined, dotDotDotToken: DotDotDotToken | undefined, name: string | BindingName, questionToken?: QuestionToken, type?: TypeNode, initializer?: Expression) {
const node = <ParameterDeclaration>createSynthesizedNode(SyntaxKind.Parameter);
node.decorators = asNodeArray(decorators);

View File

@@ -673,7 +673,7 @@ namespace ts {
initializer?: Expression; // Optional initializer
}
export interface BindingElement extends Declaration {
export interface BindingElement extends Declaration {
kind: SyntaxKind.BindingElement;
parent?: BindingPattern;
propertyName?: PropertyName; // Binding property name (in object binding pattern)
@@ -849,19 +849,17 @@ namespace ts {
_typeNodeBrand: any;
}
export type KeywordKind = SyntaxKind.AnyKeyword
| SyntaxKind.NumberKeyword
| SyntaxKind.ObjectKeyword
| SyntaxKind.BooleanKeyword
| SyntaxKind.StringKeyword
| SyntaxKind.SymbolKeyword
| SyntaxKind.VoidKeyword
| SyntaxKind.UndefinedKeyword
| SyntaxKind.NullKeyword
| SyntaxKind.NeverKeyword;
export interface KeywordTypeNode extends TypeNode {
kind: KeywordKind;
kind: SyntaxKind.AnyKeyword
| SyntaxKind.NumberKeyword
| SyntaxKind.ObjectKeyword
| SyntaxKind.BooleanKeyword
| SyntaxKind.StringKeyword
| SyntaxKind.SymbolKeyword
| SyntaxKind.VoidKeyword
| SyntaxKind.UndefinedKeyword
| SyntaxKind.NullKeyword
| SyntaxKind.NeverKeyword;
}
export interface ThisTypeNode extends TypeNode {

View File

@@ -212,16 +212,12 @@ namespace ts {
}
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)) {
return node;
}
switch (node.kind) {
case SyntaxKind.SemicolonClassElement:
case SyntaxKind.EmptyStatement:
@@ -241,6 +237,13 @@ namespace ts {
visitNode((<ComputedPropertyName>node).expression, visitor, isExpression));
// Signature elements
case SyntaxKind.IndexSignature:
return updateIndexSignatureDeclaration(<IndexSignatureDeclaration>node
, nodesVisitor((<IndexSignatureDeclaration>node).parameters, visitor)
, visitNode((<IndexSignatureDeclaration>node).type, visitor)
, nodesVisitor((<IndexSignatureDeclaration>node).decorators, visitor, isDecorator)
, nodesVisitor((<IndexSignatureDeclaration>node).modifiers, visitor, isModifier));
case SyntaxKind.Parameter:
return updateParameter(<ParameterDeclaration>node,
nodesVisitor((<ParameterDeclaration>node).decorators, visitor, isDecorator),
@@ -254,7 +257,60 @@ namespace ts {
return updateDecorator(<Decorator>node,
visitNode((<Decorator>node).expression, visitor, isExpression));
// Type member
// Keyword Types
case SyntaxKind.AnyKeyword:
case SyntaxKind.NumberKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.StringKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.NeverKeyword:
case SyntaxKind.NeverKeyword:
return node;
// Types
case SyntaxKind.TypePredicate:
throw new Error("reached unsupported type.");
case SyntaxKind.TypeReference:
return updateTypeReferenceNode(<TypeReferenceNode>node
, visitNode((<TypeReferenceNode>node).typeName as Identifier, visitor)
, nodesVisitor((<TypeReferenceNode>node).typeArguments, visitor)
);
case SyntaxKind.FunctionType:
throw new Error("reached unsupported type.");
case SyntaxKind.ConstructorType:
throw new Error("reached unsupported type.");
case SyntaxKind.TypeQuery:
throw new Error("reached unsupported type.");
case SyntaxKind.TypeLiteral:
throw new Error("reached unsupported type.");
case SyntaxKind.ArrayType:
throw new Error("reached unsupported type.");
case SyntaxKind.TupleType:
throw new Error("reached unsupported type.");
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
throw new Error("reached unsupported type.");
case SyntaxKind.ParenthesizedType:
throw new Error("reached unsupported type.");
case SyntaxKind.ThisType:
throw new Error("reached unsupported type.");
case SyntaxKind.TypeOperator:
throw new Error("reached unsupported type.");
case SyntaxKind.IndexedAccessType:
throw new Error("reached unsupported type.");
case SyntaxKind.MappedType:
throw new Error("reached unsupported type.");
case SyntaxKind.LiteralType:
throw new Error("reached unsupported type.");
// Type members
case SyntaxKind.PropertyDeclaration:
return updateProperty(<PropertyDeclaration>node,
nodesVisitor((<PropertyDeclaration>node).decorators, visitor, isDecorator),

View File

@@ -62,13 +62,12 @@ namespace ts.codefix {
, "name"
, /*questionToken*/ undefined
, stringTypeNode);
const indexSignature = createIndexSignature(indexingParameter, typeNode);
const indexSignature = createIndexSignatureDeclaration([indexingParameter], typeNode);
// const startPos = classDeclaration.members.pos;
const indexSignatureChangeTracker = textChanges.ChangeTracker.fromCodeFixContext(context);
indexSignatureChangeTracker.insertNodeAfter(sourceFile, openBrace, indexSignature, { insertTrailingNewLine: true });
return [{
return [{
description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_declaration_for_missing_property_0), [token.getText()]),
changes: propertyChangeTracker.getChanges()
},

View File

@@ -1386,6 +1386,6 @@ namespace ts {
}
export function getOpenBraceOfClassLike(declaration: ClassLikeDeclaration, sourceFile: SourceFile) {
return getTokenAtPosition(sourceFile, declaration.members.pos);
return getTokenAtPosition(sourceFile, declaration.members.pos - 1);
}
}