fullstack-lang / gong

Gong (go+ng) is a go sub-language that compiles to go and angular. All valid go is valid gong and vice versa. Gong enables fast development of web applications. Gong is model centric and by default, a UML diagram editor of the model is embedded in each application.
MIT License
13 stars 1 forks source link

Support package hierarchy in models #325

Open thomaspeugeot opened 1 year ago

thomaspeugeot commented 1 year ago

This is a recapitulative of the task of supporting multiple package.

Rationale

The rationale for this issue is to overcome a limitation of gong, namely, only the "models" package is compiled by gongc. Any subpackage is ignored. Therefore, more complex models cannot be compiled. For models like 15288 modelling or SySML, multiple packages are needed for complexity management (and for name collision avoidance).

Scope

It is understood that multipackage model won't need

To be abandonned (unless it is easy after all the rest has been done)

Remaining are:

Architecture

The manual example developed in test2 shows that the generated code could be very similar from one package to the other (except for the package modelsthat becomes package x or package ormthat becomes package x and the imports that need to be aliased contollers_x, orm_x, ...

Steps

De Weck Architecture Tool, with a concrete syntax would be ideal. But a model with a package "user" and another "product" seems more helpfull for a start

modifs goes the same depencecy way

Front:

Supporting hierarchy is key for complexity mngt. (for mimicking jointjs hierarchy for instance)

going from one stack is one package to one stack is many packages

There is per stack:

For marshalling, there is a need to convert the package path into a unique identifier

github.com/fullstack-lang/gong/test/go/models

what package alias can be automaticaly devised ?

Here's the updated implementation that uses the last three parts of the import path to generate unique aliases:

package main

import (
    "fmt"
    "strings"
)

func generateAliases(importPaths []string) map[string]string {
    aliases := make(map[string]string)
    counter := make(map[string]int)

    for _, path := range importPaths {
        parts := strings.Split(path, "/")

        // Generate an initial alias using the last three parts of the import path.
        var alias string
        if len(parts) >= 3 {
            alias = fmt.Sprintf("%s_%s_%s", parts[len(parts)-3], parts[len(parts)-2], parts[len(parts)-1])
        } else if len(parts) == 2 {
            alias = fmt.Sprintf("%s_%s", parts[len(parts)-2], parts[len(parts)-1])
        } else {
            alias = parts[len(parts)-1]
        }

        // If the alias has already been used, append a number to make it unique.
        for {
            count, exists := counter[alias]
            if exists {
                counter[alias]++
                alias = fmt.Sprintf("%s%d", alias, count)
            } else {
                counter[alias] = 1
                break
            }
        }

        aliases[path] = alias
    }

    return aliases
}

func main() {
    importPaths := []string{
        "github.com/fullstack-lang/gong/test/go/models",
        "github.com/anotheruser/anotherproject/test/go/models",
        "github.com/thirduser/thirdproject/test/go/models",
    }

    aliases := generateAliases(importPaths)

    for path, alias := range aliases {
        fmt.Printf("%s => %s\n", path, alias)
    }
}

$ time go run toto.go github.com/thirduser/thirdproject/test/go/models => test_go_models2 github.com/fullstack-lang/gong/test/go/models => test_go_models
github.com/anotheruser/anotherproject/test/go/models => test_go_models1

For go:

type BackRepoRoot struct {
    // insertion point for per struct back repo declarations
    BackRepoAstruct BackRepoAstructStruct

    BackRepoAstructBstruct2Use BackRepoAstructBstruct2UseStruct

    BackRepoAstructBstructUse BackRepoAstructBstructUseStruct

    BackRepoBstruct BackRepoBstructStruct

    BackRepoDstruct BackRepoDstructStruct
}

type BackRepo struct {
    BackRepoRoot

    CommitFromBackNb uint // records commit increments when performed by the back

    PushFromFrontNb uint // records commit increments when performed by the front

    stage *models.StageStruct
}

For ng:

$ ng generate component toto/titi --project=testspecific
CREATE projects/testspecific/src/lib/toto/titi/titi.component.html (19 bytes)
CREATE projects/testspecific/src/lib/toto/titi/titi.component.spec.ts (585 bytes)
CREATE projects/testspecific/src/lib/toto/titi/titi.component.ts (194 bytes)     
CREATE projects/testspecific/src/lib/toto/titi/titi.component.css (0 bytes)      
UPDATE projects/testspecific/src/lib/testspecific.module.ts (351 bytes)

still on front repo

thomaspeugeot commented 1 year ago

For the commit on a stage to be performed on all stages that are dependant of the stage, one need to apply the Depth First Search algorithm.


func DFS(node *Node, visited map[*Node]bool, fn func(*Node)) {
    if node == nil || visited[node] {
        return
    }

    visited[node] = true

    // Apply the given function to the current node
    fn(node)

    // Visit neighbors
    for _, neighbor := range node.Neighbors {
        DFS(neighbor, visited, fn)
    }
}