package main
import "C"
import (
"encoding/json"
"fmt"
"runtime"
"strings"
"unsafe"
"cuelang.org/go/cue"
"cuelang.org/go/cue/build"
"cuelang.org/go/cue/cuecontext"
"cuelang.org/go/cue/load"
)
const BridgeVersion = "bridge/1"
const (
ErrorCodeInvalidInput = "INVALID_INPUT"
ErrorCodeLoadInstance = "LOAD_INSTANCE"
ErrorCodeBuildValue = "BUILD_VALUE"
ErrorCodeOrderedJSON = "ORDERED_JSON"
ErrorCodePanicRecover = "PANIC_RECOVER"
ErrorCodeJSONMarshal = "JSON_MARSHAL_ERROR"
)
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()
cfg := &load.Config{
Dir: goDir,
}
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
}
jsonStr, err := buildOrderedJSONString(v)
if err != nil {
msg := fmt.Sprintf("Failed to build ordered JSON: %v", err)
result = createErrorResponse(ErrorCodeOrderedJSON, msg, nil)
return result
}
result = createSuccessResponse(jsonStr)
return result
}
func buildOrderedJSONString(v cue.Value) (string, error) {
switch v.Kind() {
case cue.StructKind:
var parts []string
fields, err := v.Fields(cue.Optional(true))
if err != nil {
return "", fmt.Errorf("failed to get fields: %v", err)
}
for fields.Next() {
fieldName := fields.Label()
fieldValue := fields.Value()
keyJSON, err := json.Marshal(fieldName)
if err != nil {
return "", fmt.Errorf("failed to marshal field name %s: %v", fieldName, err)
}
valueJSON, err := buildOrderedJSONString(fieldValue)
if err != nil {
return "", fmt.Errorf("failed to build JSON for field %s: %v", fieldName, err)
}
parts = append(parts, string(keyJSON)+":"+valueJSON)
}
return "{" + strings.Join(parts, ",") + "}", nil
case cue.ListKind:
var parts []string
list, err := v.List()
if err != nil {
return "", fmt.Errorf("failed to get list: %v", err)
}
for list.Next() {
itemJSON, err := buildOrderedJSONString(list.Value())
if err != nil {
return "", err
}
parts = append(parts, itemJSON)
}
return "[" + strings.Join(parts, ",") + "]", nil
default:
var val interface{}
if err := v.Decode(&val); err != nil {
return "", fmt.Errorf("failed to decode primitive value: %v", err)
}
jsonBytes, err := json.Marshal(val)
if err != nil {
return "", fmt.Errorf("failed to marshal primitive value: %v", err)
}
return string(jsonBytes), nil
}
}
func main() {}