GitRoot

Craft your forge, Build your project, Grow your community freely
  1// SPDX-FileCopyrightText: 2026 Romain Maneschi <romain@gitroot.dev>
  2//
  3// SPDX-License-Identifier: EUPL-1.2
  4
  5package main
  6
  7import (
  8	"bytes"
  9	"fmt"
 10	"go/types"
 11	"os"
 12	"path/filepath"
 13	"slices"
 14	"strings"
 15)
 16
 17type LangToGenerate interface {
 18	Extension() string
 19	TemplateStruct(g *Generate, f *FileToGen, st Struct) (string, []string)
 20	TemplateEnum(en Enum, variants []string) string
 21	FormatFuncName(fn Func) string
 22	FormatParams(sig *types.Signature, isMethod bool, currentFile string, locations map[string]string) (string, []string)
 23	FormatReturnType(sig *types.Signature, currentFile string, locations map[string]string) string
 24	FormatExportFunc(wasmName string, funcName string) string
 25	FormatImportFunc(wasmName string, funcName string, paramsList string, returnType string) string
 26}
 27
 28func (g *Generate) generateFile(f *FileToGen, lang LangToGenerate, intoDir string) (string, string, error) {
 29	relativeSubPath := strings.TrimPrefix(f.OriginFilePath, g.fromDir)
 30	outputFile := filepath.Join(intoDir, "src", relativeSubPath)
 31	dirToCreate, filename := filepath.Split(outputFile)
 32	finalFile := filepath.Join(dirToCreate, strings.TrimSuffix(filename, ".go")+lang.Extension())
 33
 34	previousContent, err := os.ReadFile(finalFile)
 35	if err != nil {
 36		fmt.Printf("🐞 No previous content %s\n", finalFile)
 37		previousContent = []byte{}
 38	}
 39
 40	var fileContent strings.Builder
 41	var imports []string
 42
 43	for _, st := range f.Structs {
 44		content, localImports := lang.TemplateStruct(g, f, st)
 45		fileContent.WriteString(content + "\n")
 46		for _, imp := range localImports {
 47			if imp != "" && !slices.Contains(imports, imp) {
 48				imports = append(imports, imp)
 49			}
 50		}
 51	}
 52
 53	for _, en := range f.Enums {
 54		var variants []string
 55
 56		for _, val := range en.Values {
 57			cleanVariant := val
 58			if strings.HasPrefix(val, en.TypeName) && val != en.TypeName {
 59				cleanVariant = strings.TrimPrefix(val, en.TypeName)
 60			}
 61
 62			variants = append(variants, cleanVariant)
 63		}
 64
 65		fileContent.WriteString(lang.TemplateEnum(en, variants) + "\n")
 66	}
 67
 68	//TODO no method today because body is impossible but maybe find a way to add only that ?
 69	// methodsByStruct := make(map[string][]Method)
 70	// for _, m := range f.Methods {
 71	// 	methodsByStruct[m.StructName] = append(methodsByStruct[m.StructName], m)
 72	// }
 73
 74	// for structName, methods := range methodsByStruct {
 75	// 	cleanStructName := stringy.New(structName).PascalCase().Get()
 76	// 	fileContent.WriteString(fmt.Sprintf("impl %s {\n", cleanStructName))
 77
 78	// 	for _, m := range methods {
 79	// 		paramsList, extraImports := lang.FormatParams(m.Sig, true, f.OriginFilePath, g.structLocations)
 80	// 		for _, imp := range extraImports {
 81	// 			if imp != "" && !slices.Contains(imports, imp) {
 82	// 				imports = append(imports, imp)
 83	// 			}
 84	// 		}
 85
 86	// 		returnType := lang.FormatReturnType(m.Sig, f.OriginFilePath, g.structLocations)
 87
 88	// 		funcName := stringy.New(m.Name).SnakeCase().ToLower()
 89	// 		fileContent.WriteString(fmt.Sprintf("    pub fn %s(%s)%s {\n        unimplemented!();\n    }\n\n", funcName, paramsList, returnType))
 90	// 	}
 91	// 	fileContent.WriteString("}\n\n")
 92	// }
 93
 94	for _, fn := range f.Funcs {
 95		funcName := lang.FormatFuncName(fn)
 96		if fn.Wasm == WasmExport && !bytes.Contains(previousContent, []byte(funcName)) {
 97			exportTemplate := lang.FormatExportFunc(fn.Name, funcName)
 98			fileContent.WriteString(exportTemplate + "\n")
 99		} else if !bytes.Contains(previousContent, []byte(funcName)) {
100			paramsList, extraImports := lang.FormatParams(fn.Sig, false, f.OriginFilePath, g.structLocations)
101			for _, imp := range extraImports {
102				if imp != "" && !slices.Contains(imports, imp) {
103					imports = append(imports, imp)
104				}
105			}
106			returnType := lang.FormatReturnType(fn.Sig, f.OriginFilePath, g.structLocations)
107			fileContent.WriteString(lang.FormatImportFunc(fn.Name, funcName, paramsList, returnType))
108		}
109	}
110
111	if fileContent.Len() == 0 {
112		fmt.Printf("🟒 nothing to write %s\n", finalFile)
113		return "", "", nil
114	}
115
116	if err := os.MkdirAll(dirToCreate, os.ModePerm); err != nil {
117		return "", "", fmt.Errorf("impossible de crΓ©er le dossier %s: %w", dirToCreate, err)
118	}
119
120	slices.Sort(imports)
121
122	var finalBuffer strings.Builder
123	finalBuffer.WriteString(header)
124
125	for _, imp := range imports {
126		finalBuffer.WriteString(imp + "\n")
127	}
128
129	finalBuffer.WriteString("\n")
130	finalBuffer.WriteString(fileContent.String())
131
132	return finalFile, finalBuffer.String(), nil
133}