package main
import "C"
import (
"encoding/json"
"fmt"
"os"
"path/filepath"
"runtime"
"unsafe"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
"cuelang.org/go/mod/modconfig"
)
const BridgeVersion = "bridge/1"
const (
ErrorCodeInvalidInput = "INVALID_INPUT"
ErrorCodeLoadInstance = "LOAD_INSTANCE"
ErrorCodeBuildValue = "BUILD_VALUE"
ErrorCodeOrderedJSON = "ORDERED_JSON"
ErrorCodePanicRecover = "PANIC_RECOVER"
ErrorCodeJSONMarshal = "JSON_MARSHAL_ERROR"
ErrorCodeRegistryInit = "REGISTRY_INIT"
)
type BridgeError struct {
Code string `json:"code"`
Message string `json:"message"`
Hint *string `json:"hint,omitempty"`
}
type BridgeResponse struct {
Version string `json:"version"`
Ok *json.RawMessage `json:"ok,omitempty"`
Error *BridgeError `json:"error,omitempty"`
}
func cue_free_string(s *C.char) {
C.free(unsafe.Pointer(s))
}
func cue_bridge_version() *C.char {
versionInfo := fmt.Sprintf("%s (Go %s)", BridgeVersion, runtime.Version())
return C.CString(versionInfo)
}
func createErrorResponse(code, message string, hint *string) *C.char {
error := &BridgeError{
Code: code,
Message: message,
Hint: hint,
}
response := &BridgeResponse{
Version: BridgeVersion,
Error: error,
}
responseBytes, err := json.Marshal(response)
if err != nil {
fallbackResponse := fmt.Sprintf(`{"version":"%s","error":{"code":"%s","message":"Failed to marshal error response: %s"}}`, BridgeVersion, ErrorCodeJSONMarshal, err.Error())
return C.CString(fallbackResponse)
}
return C.CString(string(responseBytes))
}
func createSuccessResponse(data string) *C.char {
rawData := json.RawMessage(data)
response := &BridgeResponse{
Version: BridgeVersion,
Ok: &rawData,
}
responseBytes, err := json.Marshal(response)
if err != nil {
msg := fmt.Sprintf("Failed to marshal success response: %s", err.Error())
return createErrorResponse(ErrorCodeJSONMarshal, msg, nil)
}
return C.CString(string(responseBytes))
}
func cue_eval_package(dirPath *C.char, packageName *C.char) *C.char {
var result *C.char
defer func() {
if r := recover(); r != nil {
panic_msg := fmt.Sprintf("Internal panic: %v", r)
result = createErrorResponse(ErrorCodePanicRecover, panic_msg, nil)
}
}()
goDir := C.GoString(dirPath)
goPackageName := C.GoString(packageName)
if goDir == "" {
result = createErrorResponse(ErrorCodeInvalidInput, "Directory path cannot be empty", nil)
return result
}
if goPackageName == "" {
result = createErrorResponse(ErrorCodeInvalidInput, "Package name cannot be empty", nil)
return result
}
ctx := cuecontext.New()
registry, err := modconfig.NewRegistry(nil)
if err != nil {
hint := "Check CUE registry configuration (CUE_REGISTRY env var) and network access"
result = createErrorResponse(ErrorCodeRegistryInit,
fmt.Sprintf("Failed to initialize CUE registry: %v", err), &hint)
return result
}
cfg := &load.Config{
Dir: goDir,
Registry: registry,
}
if moduleRoot := resolveCueModuleRoot(goDir); moduleRoot != "" {
cfg.ModuleRoot = moduleRoot
}
var instances []*build.Instance
packagePath := ".:" + goPackageName
instances = load.Instances([]string{packagePath}, cfg)
if len(instances) == 0 {
hint := "Check that the package name exists and CUE files are present"
result = createErrorResponse(ErrorCodeLoadInstance, "No CUE instances found", &hint)
return result
}
inst := instances[0]
if inst.Err != nil {
msg := fmt.Sprintf("Failed to load CUE instance: %v", inst.Err)
hint := "Check CUE syntax and import statements"
result = createErrorResponse(ErrorCodeLoadInstance, msg, &hint)
return result
}
v := ctx.BuildInstance(inst)
if v.Err() != nil {
msg := fmt.Sprintf("Failed to build CUE value: %v", v.Err())
hint := "Check CUE constraints and value definitions"
result = createErrorResponse(ErrorCodeBuildValue, msg, &hint)
return result
}
jsonBytes, err := v.MarshalJSON()
if err != nil {
msg := fmt.Sprintf("Failed to marshal JSON: %v", err)
result = createErrorResponse(ErrorCodeOrderedJSON, msg, nil)
return result
}
result = createSuccessResponse(string(jsonBytes))
return result
}
func resolveCueModuleRoot(startDir string) string {
if envRoot := os.Getenv("CUENV_CUE_MODULE_ROOT"); envRoot != "" {
if info, err := os.Stat(filepath.Join(envRoot, "cue.mod", "module.cue")); err == nil && !info.IsDir() {
return envRoot
}
}
dir, err := filepath.Abs(startDir)
if err != nil {
dir = startDir
}
for {
moduleFile := filepath.Join(dir, "cue.mod", "module.cue")
if info, err := os.Stat(moduleFile); err == nil && !info.IsDir() {
return dir
}
parent := filepath.Dir(dir)
if parent == dir {
break
}
dir = parent
}
return ""
}
func main() {}