0

First, I came from a .NET background so please excuse my lack of groovy lingo. Back when I was in a .NET shop, we were using TypeScript with C# to build web apps. In our controllers, we would always receive/respond with DTOs (data xfer objects). This got to be quite the headache every time you create/modify a DTO you had to update the TypeScript interface (the d.ts file) that corresponded to it.

So we created a little app (a simple exe) that loaded the dll from the webapp into it, then reflected over it to find the DTOs (filtering by specific namespaces), and parse through them to find each class name within, their properties, and their properties' data types, generate that information into a string, and finally saved as into a d.ts file.

This app was then configured to run on every build of the website. That way, when you go to run/debug/build the website, it would update your d.ts files automatically - which made working with TypeScript that much easier.

Long story short, how could I achieve this with a Grails Website if I were to write a simple groovy app to generate the d.ts that I want?

-- OR --

How do I get the IDE (ex IntelliJ) to run a groovy file (that is part of the app) that does this generation post-build?

I did find this but still need a way to run on compile:

Groovy property iteration

class Foo {
    def feck = "fe"
    def arse = "ar"
    def drink = "dr"    
}

class Foo2 {

    def feck = "fe2"
    def arse = "ar2"
    def drink = "dr2"
}


def f = new Foo()
def f2 = new Foo2()


f2.properties.each { prop, val ->
    if(prop in ["metaClass","class"]) return
    if(f.hasProperty(prop)) f[prop] = val
}

assert f.feck == "fe2"
assert f.arse == "ar2"
assert f.drink == "dr2"
Community
  • 1
  • 1
franzcatch
  • 169
  • 2
  • 15

2 Answers2

1

I've been able to extract the Domain Objects and their persistent fields via the following Gant script:

In scripts/Props.groovy:

import static groovy.json.JsonOutput.*

includeTargets << grailsScript("_GrailsBootstrap")

target(props: "Lists persistent properties for each domain class") {
    depends(loadApp)

    def propMap = [:].withDefault { [] }
    grailsApp.domainClasses.each {
        it?.persistentProperties?.each { prop ->
            if (prop.hasProperty('name') && prop.name) {
                propMap[it.clazz.name] << ["${prop.name}": "${prop.getType()?.name}"]
            }
        }
    }
    // do any necessary file I/O here (just printing it now as an example)
    println prettyPrint(toJson(propMap))
}

setDefaultTarget(props)

This can be run via the command line like so:

grails props

Which produces output like the following:

{
    "com.mycompany.User": [
        { "type": "java.lang.String" },
        { "username": "java.lang.String" },
        { "password": "java.lang.String" }
    ],
    "com.mycompany.Person": [
        { "name": "java.lang.String" },
        { "alive": "java.lang.Boolean" }
    ]
}

A couple of drawbacks to this approach is that we don't get any transient properties and I'm not exactly sure how to hook this into the _Events.groovy eventCompileEnd event.

0

Thanks Kevin! Just wanted to mention, in order to get this to run, here are a few steps I had to make sure to do in my case that I thought I would share:

-> Open up the grails BuildConfig.groovy

-> Change tomcat from build to compile like this:

plugins {
    compile ":tomcat:[version]"
}

-> Drop your Props.groovy into the scripts folder on the root (noting the path to the grails-app folder for reference)

[application root]/scripts/Props.groovy
[application root]/grails-app

-> Open Terminal

gvm use grails [version]
grails compile
grails Props

Note: I was using Grails 2.3.11 for the project I was running this on.

That gets everything in your script to run successfully for me. Now to modify the println portion to generate Typescript interfaces.

Will post a github link when it is ready so be sure to check back.

franzcatch
  • 169
  • 2
  • 15