Skip to content

Commit

Permalink
feat: add undefined type and identifier to some types
Browse files Browse the repository at this point in the history
  • Loading branch information
svenliebig committed Sep 4, 2023
1 parent 01f00d7 commit cdcef7d
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 42 deletions.
7 changes: 4 additions & 3 deletions src/models/ArrayType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,17 @@ export class ArrayType extends Type {
super()

// TODO this should not be necessary
this.arrayType = new StringType()
// TODO add declarion to this later
this.arrayType = new StringType(undefined as any)

if (isTypeReferenceNode(node)) {
if (node.typeArguments) {
for (const argument of node.typeArguments) {
this.arrayType = TypeFactory.create(argument)
this.arrayType = TypeFactory.create(argument, "") // TODO
}
}
} else {
this.arrayType = TypeFactory.create(node.elementType)
this.arrayType = TypeFactory.create(node.elementType, "") // TODO
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/models/IntersectionType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { Type } from "./Type"
export class IntersectionType extends Type {
public types: Array<Type>

constructor(node: IntersectionTypeNode) {
constructor(node: IntersectionTypeNode, public identifier: string) {
super()
this.types = node.types.map(TypeFactory.create)
this.types = node.types.map((t) => TypeFactory.create(t, identifier))
}

toString(): string {
Expand Down
17 changes: 8 additions & 9 deletions src/models/IntersectionTypeDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { IntersectionTypeNode } from "typescript";
import { IntersectionType } from "./IntersectionType";
import { DeclarationMeta } from "../parser";
import { TypeDeclaration } from "./TypeDeclaration";

import { IntersectionTypeNode } from "typescript"
import { IntersectionType } from "./IntersectionType"
import { DeclarationMeta } from "../parser"
import { TypeDeclaration } from "./TypeDeclaration"

export class IntersectionTypeDeclaration extends TypeDeclaration {
public type: IntersectionType;
public type: IntersectionType

constructor(meta: DeclarationMeta, node: IntersectionTypeNode) {
super(meta);
this.type = new IntersectionType(node);
super(meta)
this.type = new IntersectionType(node, this.identifier)
}

typeToString(): string {
return this.type.toString();
return this.type.toString()
}
}
6 changes: 6 additions & 0 deletions src/models/StringType.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { StringTypeDeclaration } from "./StringTypeDeclaration"
import { Type } from "./Type"
import { TypeDeclaration } from "./TypeDeclaration"

export class StringType extends Type {
constructor(public identifier: string) {
super()
}

toString() {
return "string"
}
Expand Down
13 changes: 6 additions & 7 deletions src/models/StringTypeDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import { DeclarationMeta } from "../parser";
import { TypeDeclaration } from "./TypeDeclaration";
import { StringType } from "./StringType";

import { DeclarationMeta } from "../parser"
import { TypeDeclaration } from "./TypeDeclaration"
import { StringType } from "./StringType"

export class StringTypeDeclaration extends TypeDeclaration {
public type: StringType = new StringType();
public type: StringType = new StringType(this.identifier)

constructor(meta: DeclarationMeta) {
super(meta);
super(meta)
}

typeToString(): string {
return "string";
return "string"
}
}
2 changes: 1 addition & 1 deletion src/models/TypeLiteral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export class TypeLiteral extends Type {
if (isPropertySignature(member)) {
if (isIdentifier(member.name)) {
if (member.type) {
this.properties.set(member.name.text, TypeFactory.create(member.type))
this.properties.set(member.name.text, TypeFactory.create(member.type, member.name.text))
} else {
throw new Error(`Member has no type node: ${member.name.text}`)
}
Expand Down
7 changes: 7 additions & 0 deletions src/models/UndefinedType.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Type } from "./Type"

export class UndefinedType extends Type {
toString() {
return "undefined"
}
}
4 changes: 2 additions & 2 deletions src/models/UnionType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ export class UnionType extends Type {
public types: Array<Type>

// TODO these `types` should be a parameter instead of creating a dependency to the `typescript` lib here
constructor(node: UnionTypeNode) {
constructor(node: UnionTypeNode, public identifier: string) {
super()
this.types = node.types.map(TypeFactory.create)
this.types = node.types.map((t) => TypeFactory.create(t, this.identifier))
}

toString(): string {
Expand Down
17 changes: 8 additions & 9 deletions src/models/UnionTypeDeclaration.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
import { UnionTypeNode } from "typescript";
import { UnionType } from "./UnionType";
import { DeclarationMeta } from "../parser";
import { TypeDeclaration } from "./TypeDeclaration";

import { UnionTypeNode } from "typescript"
import { UnionType } from "./UnionType"
import { DeclarationMeta } from "../parser"
import { TypeDeclaration } from "./TypeDeclaration"

export class UnionTypeDeclaration extends TypeDeclaration {
public type: UnionType;
public type: UnionType

constructor(meta: DeclarationMeta, node: UnionTypeNode) {
super(meta);
this.type = new UnionType(node);
super(meta)
this.type = new UnionType(node, this.identifier)
}

typeToString(): string {
return this.type.toString();
return this.type.toString()
}
}
11 changes: 9 additions & 2 deletions src/rewrite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { StringType } from "./models/StringType"
import { Type } from "./models/Type"
import { TypeLiteral } from "./models/TypeLiteral"
import { TypeReference } from "./models/TypeReference"
import { UndefinedType } from "./models/UndefinedType"
import { UnionType } from "./models/UnionType"
import { UnknownType } from "./models/UnknownType"

Expand All @@ -20,6 +21,7 @@ export type TypeTransformers = {
string?(type: StringType): string
number?(type: NumberType): string
reference?(type: TypeReference): string
undefined?(type: UndefinedType): string
}

export function rewrite(type: Type, transformers: TypeTransformers): string {
Expand Down Expand Up @@ -47,6 +49,10 @@ export function rewrite(type: Type, transformers: TypeTransformers): string {
return transformers.reference?.(type) ?? type.toString()
}

if (type instanceof UndefinedType) {
return transformers.undefined?.(type) ?? type.toString()
}

if (type instanceof IntersectionType) {
return type.types
.filter(filterUnknown)
Expand All @@ -62,7 +68,8 @@ export function rewrite(type: Type, transformers: TypeTransformers): string {
if (isOnlyBasicTypes(type.types)) {
return rewrite(type.types[0], transformers)
}
return "Union..."

return rewrite(type.types[0], transformers) // + " | " + rewrite(type.types[1], transformers)
}

if (type instanceof TypeLiteral) {
Expand All @@ -79,5 +86,5 @@ export function rewrite(type: Type, transformers: TypeTransformers): string {
}

function isOnlyBasicTypes(types: Array<Type>) {
return types.every((type) => [BooleanType, StringType, UnknownType, NumberType, LiteralType].some((basic) => type instanceof basic))
return types.every((type) => [BooleanType, StringType, UnknownType, NumberType, LiteralType, UndefinedType].some((basic) => type instanceof basic))
}
2 changes: 1 addition & 1 deletion src/utils/DeclarationFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export class DeclarationFactory {
return new TypeLiteralDeclaration(meta, statement.type)
}

throw new Error(`Unknown TypeNode kind: ${statement.type.kind}`)
throw new Error(`DeclarationFactory: Unknown TypeNode kind '${statement.type.kind}'`)
}

public static createMeta(statement: TypeAliasDeclaration | EnumDeclaration): DeclarationMeta {
Expand Down
18 changes: 13 additions & 5 deletions src/utils/TypeFactory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,19 @@ import { IntersectionType } from "../models/IntersectionType"
import { LiteralType } from "../models/LiteralType"
import { NumberType } from "../models/NumberType"
import { StringType } from "../models/StringType"
import { TypeDeclaration } from "../models/TypeDeclaration"
import { TypeLiteral } from "../models/TypeLiteral"
import { TypeReference } from "../models/TypeReference"
import { UnionType } from "../models/UnionType"
import { isBooleanKeywordTypeNode } from "./isBooleanKeywordTypeNode"
import { isNumberKeywordTypeNode } from "./isNumberKeywordTypeNode"
import { isStringKeywordTypeNode } from "./isStringKeywordTypeNode"
import { L } from "./logger"
import { isUndefinedKeywordTypeNode } from "./isUndefinedKeywordTypeNode"
import { UndefinedType } from "../models/UndefinedType"

export class TypeFactory {
static create(node: TypeNode) {
static create(node: TypeNode, identifier: string) {
L.d(`<TypeFactory.create>`, node.kind)

if (isArrayTypeNode(node)) {
Expand All @@ -35,15 +38,16 @@ export class TypeFactory {
}

if (isUnionTypeNode(node)) {
return new UnionType(node)
// TODO identifier is not resolved yet
return new UnionType(node, identifier)
}

if (isIntersectionTypeNode(node)) {
return new IntersectionType(node)
return new IntersectionType(node, identifier)
}

if (isStringKeywordTypeNode(node)) {
return new StringType()
return new StringType(identifier)
}

if (isNumberKeywordTypeNode(node)) {
Expand All @@ -66,6 +70,10 @@ export class TypeFactory {
return new BooleanType()
}

throw new Error(`Unknown TypeNode kind: ${node.kind}`)
if (isUndefinedKeywordTypeNode(node)) {
return new UndefinedType()
}

throw new Error(`TypeFactory: Unknown TypeNode kind '${node.kind}'`)
}
}
5 changes: 5 additions & 0 deletions src/utils/isUndefinedKeywordTypeNode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { KeywordTypeNode, SyntaxKind, TypeNode } from "typescript"

export function isUndefinedKeywordTypeNode(node: TypeNode): node is KeywordTypeNode<SyntaxKind.UndefinedKeyword> {
return node.kind === SyntaxKind.UndefinedKeyword
}
14 changes: 13 additions & 1 deletion tests/fixtures/typeLiteral.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,16 @@ export type ExportedComplexNestedTypeLiteralWithImports = {
nested: {
object: BasicTypeLiteral
}
}
}

type WithUndefined = {
undefined: undefined
}

type WithUnionUndefinedAndString = {
union: undefined | string
}

type WithNull = {
null: null
}
18 changes: 18 additions & 0 deletions tests/typeLiteralDeclaration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,21 @@ test("toString for ComplexNestedTypeLiteralWithImports after resolve", (t) => {
const type = "{ union: string | number, nested: { object: { str: string, num: number } } }"
t.is(str, `type ComplexNestedTypeLiteralWithImports = ${type}`)
})

test("toString for WithNull after resolve", (t) => {
const str = parser.resolve("WithNull")?.toString()
const type = "{ null: null }"
t.is(str, `type WithNull = ${type}`)
})

test("toString for WithUndefined after resolve", (t) => {
const str = parser.resolve("WithUndefined")?.toString()
const type = "{ undefined: undefined }"
t.is(str, `type WithUndefined = ${type}`)
})

test("toString for WithUnionUndefinedAndString after resolve", (t) => {
const str = parser.resolve("WithUnionUndefinedAndString")?.toString()
const type = "{ union: undefined | string }"
t.is(str, `type WithUnionUndefinedAndString = ${type}`)
})

0 comments on commit cdcef7d

Please sign in to comment.