Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add suport for typealias types (and never type) #13

Merged
merged 3 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion codegen/snippet-tests/input/01-primitiveTypes.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ float: Float
bool: Boolean
nullType: Null
anyType: Any

nothingType: nothing
12 changes: 12 additions & 0 deletions codegen/snippet-tests/input/06-withTypeAlias.pkl
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
typealias MyStringAlias = String

x: MyStringAlias

class MyClassToBeAliased {
a: String
b: Int
}

typealias MyAliasedClass = MyClassToBeAliased

y: MyAliasedClass
2 changes: 2 additions & 0 deletions codegen/snippet-tests/output/01_primitive_types.pkl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface N01PrimitiveTypes {
nullType: null

anyType: any

nothingType: never
}

// LoadFromPath loads the pkl module at the given path and evaluates it into a N01PrimitiveTypes
Expand Down
35 changes: 35 additions & 0 deletions codegen/snippet-tests/output/06_with_type_alias.pkl.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// This file was generated by `pkl-typescript` from Pkl module `06-withTypeAlias`.
// DO NOT EDIT.
import * as pklTypescript from "@pkl-community/pkl-typescript"

// Ref: Module root.
export interface N06WithTypeAlias {
x: MyStringAlias

y: MyAliasedClass
}

// Ref: Pkl class `06-withTypeAlias.MyClassToBeAliased`.
export interface MyClassToBeAliased {
a: string

b: number
}

type MyStringAlias = string

type MyAliasedClass = MyClassToBeAliased

// LoadFromPath loads the pkl module at the given path and evaluates it into a N06WithTypeAlias
export const loadFromPath = async (path: string): Promise<N06WithTypeAlias> => {
const evaluator = await pklTypescript.newEvaluator(pklTypescript.PreconfiguredOptions);
try {
const result = await load(evaluator, pklTypescript.FileSource(path));
return result
} finally {
evaluator.close()
}
};

export const load = (evaluator: pklTypescript.Evaluator, source: pklTypescript.ModuleSource): Promise<N06WithTypeAlias> =>
evaluator.evaluateModule(source) as Promise<N06WithTypeAlias>;
24 changes: 23 additions & 1 deletion codegen/src/Generator.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,33 @@ function gatherClasses(decl: List<reflect.TypeDeclaration>): Mixin<List<Typescri
seenMappings = accum
}))

function isEnumLike(decl: reflect.TypeDeclaration) =
decl is reflect.TypeAlias
&&
let (referent = decl.referent)
referent is reflect.UnionType
&& referent.members.every((t) -> t is EnumMember)
&&
if (referent.members is List<reflect.StringLiteralType>)
hasDistinctEnumNames(referent.members)
else true

function gatherTypeAliases(decl: List<reflect.TypeDeclaration>): Mixin<List<TypescriptMapping>> =
(acc) ->
decl
.filter((it) -> it is reflect.TypeAlias && !isEnumLike(it))
.fold(acc, (accum, it) -> accum.add(new TypescriptMapping.TypeAlias {
typescriptModule = getTypescriptModuleName(it)
source = it
seenMappings = accum
}))

local allMappings: List<TypescriptMapping> =
let (clazz = reflect.Module(moduleToGenerate).moduleClass)
let (declarations = gatherer.gatherTypeDeclarations(clazz, List()))
List() |>
gatherClasses(declarations)
gatherClasses(declarations) |>
gatherTypeAliases(declarations)

local modules = allMappings
.groupBy((it) -> it.typescriptModule)
Expand Down
2 changes: 2 additions & 0 deletions codegen/src/internal/Gen.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ mappings: List<TypescriptMapping>

/// The TypeScript contents
contents: String

typescriptModule: String?
13 changes: 13 additions & 0 deletions codegen/src/internal/TypeAliasGen.pkl
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module pkl.typescript.internal.TypeAliasGen

extends "Gen.pkl"

import "typegen.pkl"
import "Type.pkl"
import "pkl:reflect"

typealiaz: reflect.TypeAlias = mapping.source as reflect.TypeAlias

type: Type = typegen.generateType(typealiaz.referent, typealiaz, mappings)

contents = "type \(mapping.name) = \(type.render(typescriptModule))"
15 changes: 15 additions & 0 deletions codegen/src/internal/TypescriptMapping.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,21 @@ class Enum extends TypescriptMapping {
)
}

class TypeAlias extends TypescriptMapping {
local self = this

alias: reflect.TypeAlias = self.source as reflect.TypeAlias

name = utils.toTypescriptName(self.source)

names = List(name)

type = new Type.Declared {
typeName = name
`module` = self.typescriptModule
}
}

class Class extends TypescriptMapping {
local self = this

Expand Down
18 changes: 12 additions & 6 deletions codegen/src/internal/TypescriptModule.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import "pkl:reflect"
import "TypescriptMapping.pkl"
import "Gen.pkl"
import "ClassGen.pkl"
import "TypeAliasGen.pkl"
import "utils.pkl"

`module`: reflect.Module
Expand Down Expand Up @@ -48,12 +49,17 @@ local function hasUniqueNames(): Boolean =

local generated: List<Gen>(hasUniqueNames()) =
moduleMappings.map((it) ->
// if (it is TypescriptMapping.Class)
new ClassGen {
mappings = module.mappings
mapping = it
})
// }
if (it is TypescriptMapping.TypeAlias)
new TypeAliasGen {
mappings = module.mappings
mapping = it
}
else
new ClassGen {
mappings = module.mappings
mapping = it
}
)
// If not a class, what then?

contents: String = new Listing {
Expand Down
1 change: 1 addition & 0 deletions codegen/src/internal/typegen.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ mappedTypes: Mapping<Class|TypeAlias, Type> = new {
[Boolean] = new Type.Declared { typeName = "boolean" }
[Null] = new Type.Declared { typeName = "null" }
[Any] = anyType
[Char] = new Type.Declared { typeName = "string" }
[Duration] = new Type.Declared {
`module` = "pkl-types"
typeName = "Duration"
Expand Down
9 changes: 9 additions & 0 deletions codegen/src/tests/typegen.test.pkl
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ local class Pairs {

local reflectedPairs = reflect.Class(Pairs)

local class Nothing {
res1: nothing
}

local nothingType: reflect.Type = reflect.Class(Nothing).properties["res1"].type

local mod = reflect.Module(module).moduleClass

local function generateType(typ: reflect.Type) = typegen.generateType(typ, mod, List()).render("")
Expand All @@ -67,6 +73,9 @@ facts {
generateType(reflect.dynamicType) == "PklTypes.Dynamic"
generateType(reflect.dataSizeType) == "PklTypes.DataSize"
generateType(reflect.durationType) == "PklTypes.Duration"
generateType(nothingType) == "never"
generateType(reflect.DeclaredType(reflect.TypeAlias(Char))) == "string"
generateType(reflect.DeclaredType(reflect.Class(Null))) == "null"
}
["maps"] {
generateType(reflectedMaps.properties["res1"].type) == "Map<string, string>"
Expand Down
Loading