Skip to content

Commit

Permalink
do not generate custom types as empty records, respect the provided g…
Browse files Browse the repository at this point in the history
…o config and generate it as an alias
  • Loading branch information
giuseppemag committed Feb 24, 2025
1 parent ca5662b commit ff01818
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 20 deletions.
11 changes: 8 additions & 3 deletions backend/apps/automatic-tests/FormsValidator.fs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,12 @@ let WrongFormStructure() =
let actual5 = Ballerina.DSL.FormEngine.Runner.runSingle true FormsGenTarget.golang "./input-forms/with errors/wrong form structure 5.json" "./generated-output/models" null null "./input-forms/go-config.json"
let actual6 = Ballerina.DSL.FormEngine.Runner.runSingle true FormsGenTarget.golang "./input-forms/with errors/wrong form structure 6.json" "./generated-output/models" null null "./input-forms/go-config.json"
let actual7 = Ballerina.DSL.FormEngine.Runner.runSingle true FormsGenTarget.golang "./input-forms/with errors/wrong form structure 7.json" "./generated-output/models" null null "./input-forms/go-config.json"
match actual7 with
| Right err -> Errors.Print "wrong form structure" err
| _ -> ()
Assert.That(actual1.IsRight && actual2.IsRight && actual3.IsRight && actual4.IsRight && actual5.IsRight && actual6.IsRight && actual7.IsRight, Is.EqualTo(true))

[<Test>]
let WrongPredicateStructure() =
let actual1 = Ballerina.DSL.FormEngine.Runner.runSingle true FormsGenTarget.golang "./input-forms/with errors/wrong predicate structure 1.json" "./generated-output/models" null null "./input-forms/go-config.json"
match actual1 with
| Right err -> Errors.Print "wrong predicate structure" err
| _ -> ()
Assert.That(actual1.IsRight, Is.EqualTo(true))
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"types": {
"Person": {
"extends": [],
"fields": {
"Name": "string",
"Surname": "string"
}
}
},
"forms":{
"person": {
"type": "Person",
"fields": {
"Name": {
"renderer": "defaultString"
},
"Surname": {
"renderer": "defaultString"
}
},
"tabs": {
"main": {
"columns": {
"main": {
"groups": {
"main": [
"Name",
"Surname"
]
}
}
}
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,17 +78,16 @@ module TypeCheck =
}
) |> sum.All
match handlerTypes with
| [] -> return ()
| [] -> return! sum.Throw(Errors.Singleton $"Error: match-case {e} has no case handlers. One case handler is required for each possible case.")
| x::xs ->
do!
let! ``type`` =
xs |> List.fold (fun unifications expr ->
sum{
let! prevExpr,prevUnifications = unifications
let! newUnifications = ExprType.Unify Map.empty typeBindings prevExpr expr
return expr,newUnifications
}) (sum{ return x,UnificationConstraints.Zero() })
|> Sum.map ignore
return None,ExprType.PrimitiveType PrimitiveType.BoolType, vars'
return None,``type`` |> fst, vars'
| t->
return! sum.Throw(sprintf "Error: unexpected match-case on type %A when typechecking expression %A" t e |> Errors.Singleton)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ module Golang =
})
)
yield StringBuilder.One " }\n"
yield StringBuilder.One $$"""return result, {{codegenConfig.StreamNotFoundError.Constructor}}(streamName)"""
yield StringBuilder.One $$""" return result, {{codegenConfig.StreamNotFoundError.Constructor}}(streamName)"""
yield StringBuilder.One "\n}\n\n"
}

Expand All @@ -179,12 +179,21 @@ module Golang =
})
)
yield StringBuilder.One " }\n"
yield StringBuilder.One $$"""return result, {{codegenConfig.StreamNotFoundError.Constructor}}(streamName)"""
yield StringBuilder.One $$""" return result, {{codegenConfig.StreamNotFoundError.Constructor}}(streamName)"""
yield StringBuilder.One "\n}\n\n"
}

let customTypes = codegenConfig.Custom.Keys |> Set.ofSeq
let typesToGenerate = ctx.Types |> Map.filter (fun k v -> customTypes |> Set.contains k |> not)
let customTypes =
codegenConfig.Custom |> Seq.map (fun t ->
StringBuilder.Many(seq{
yield StringBuilder.One "\n"
yield StringBuilder.One $"type {t.Key} = {t.Value.GeneratedTypeName}"
})
)
let! generatedTypes = state.All(
ctx.Types |> Seq.map(fun t ->
typesToGenerate |> Seq.map(fun t ->
state{
match t.Value.Type with
| ExprType.UnionType cases when cases |> Seq.forall (fun case -> case.Fields.IsUnitType) ->
Expand Down Expand Up @@ -293,7 +302,7 @@ module Golang =
| _ ->
let! fields = ExprType.GetFields t.Value.Type |> state.OfSum
let typeStart = $$"""type {{t.Value.TypeId.TypeName}} struct {
"""
"""
let! fieldTypes = state.All(fields |> Seq.map (snd >> ExprType.ToGolangTypeAnnotation) |> List.ofSeq)
let fieldDeclarations = Many (seq{
for fieldType,fieldName in fields |> Seq.map fst |> Seq.zip fieldTypes do
Expand All @@ -304,7 +313,7 @@ module Golang =
yield StringBuilder.One "\n"
})
let typeEnd = $$"""}
"""
"""

let consStart = $$"""func New{{t.Value.TypeId.TypeName}}("""
let consParams = Many (seq{
Expand All @@ -315,13 +324,13 @@ module Golang =
yield StringBuilder.One ", "
})
let consDeclEnd = $$""") {{t.Value.TypeId.TypeName}} {
res := new({{t.Value.TypeId.TypeName}})
"""
var res {{t.Value.TypeId.TypeName}}
"""

let consBodyEnd = $$""" return *res
}
let consBodyEnd = $$""" return res
}
"""
"""
let consFieldInits = StringBuilder.Many (seq{
for fieldType,fieldName in fields |> Seq.map fst |> Seq.zip fieldTypes do
yield StringBuilder.One " res."
Expand Down Expand Up @@ -357,6 +366,7 @@ module Golang =
// yield! entitiesOPSelector "DEFAULT" CrudMethod.Default
// yield! entitiesOPEnum "DEFAULT" CrudMethod.Default
yield! generatedTypes
yield! customTypes
})
}
let result = result |> state.WithErrorContext $"...when generating Go code"
Expand All @@ -371,6 +381,7 @@ module Golang =
let imports = if ctx.Apis.Streams |> Map.isEmpty |> not then imports + (codegenConfig.StreamNotFoundError.RequiredImport |> Option.toList |> Set.ofList) else imports
let imports = imports + (codegenConfig.Guid.RequiredImport |> Option.toList |> Set.ofList)
let imports = imports + (codegenConfig.Unit.RequiredImport |> Option.toList |> Set.ofList)
let imports = imports + (codegenConfig.Custom |> Map.values |> Seq.map (fun v -> v.RequiredImport |> Option.toList) |> List.concat |> Set.ofSeq)
let heading = StringBuilder.One $$"""package {{packageName}}
import (
Expand Down
15 changes: 12 additions & 3 deletions todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,17 @@ Todo (✅/❌)
✅ invalid tabs
✅ non-existing fields
❌ invalid predicates
❌ requires global config, APIs, and launcher
❌ wrong `root` type
❌ non-existing variables
❌ non-existing fields
❌ mismatched types (`10 == true`)
❌ mismatched enum case checks
❌ wrong pattern matching
❌ missing case handler
❌ non existing case name
❌ different types of the handlers
❌ same handler types but unexpected type of the whole match
❌ invalid launchers
❌ non-existing form
❌ missing entity API
Expand All @@ -84,8 +90,8 @@ Todo (✅/❌)
❌ validator
❌ the validator is now mature
✅ specialize the errors (stream not found, enum not found, etc.)
improve the generated whitespace
the Go type generator is now reasonably mature
improve the generated whitespace
the Go type generator is now reasonably mature
❌ add full support for unions, including generation
✅ parser
✅ validator
Expand All @@ -100,12 +106,15 @@ Todo (✅/❌)
✅ constructors for the whole thing - assume discriminator, accept specific value
❌ add renderer syntax for the selector of a different form depending on the case
❌ add renderer syntax for the union container
❌ implement renderer in FE
❌ extensions
❌ preprocessor plugins
❌ injected at specific times
❌ language generation as parameters
❌ define `include` command
❌ add homomorphic forms
❌ add multi-field renderers
❌ use tuples, meaning it's still just one single field
❌ define `include` command
❌ add paginated lists
❌ requires changes to the frontend
❌ add lazy fields
Expand Down

0 comments on commit ff01818

Please sign in to comment.