diff --git a/cmd/cli.go b/cmd/cli.go index c73990d..d88acf4 100644 --- a/cmd/cli.go +++ b/cmd/cli.go @@ -91,6 +91,21 @@ func addEmbeddedFileCommands() { Use: strings.ReplaceAll(dirPath, string(os.PathSeparator), " "), Short: fmt.Sprintf("Commands for files in %s", dirPath), } + dirCmd.Run = func(_ *cobra.Command, _ []string) { + if daemon { + httpInput := httpserver.HTTPInput{ + BinaryName: filepath.Base(os.Args[0]), + EmbeddedFolder: &contracts, + EmbeddedPath: "contracts", + EmbeddedSubDir: dirPath, + } + if err := httpserver.StartHTTPServer(httpInput); err != nil { + log.Printf("Failed to start HTTP server: %v\n", err) + os.Exit(1) + } + return + } + } dirCommands[dirPath] = dirCmd parentCmd.AddCommand(dirCmd) } diff --git a/cmd/httpserver/http.go b/cmd/httpserver/http.go index 8f232f2..8d2215e 100644 --- a/cmd/httpserver/http.go +++ b/cmd/httpserver/http.go @@ -14,10 +14,29 @@ type HTTPInput struct { BinaryName string EmbeddedFolder *embed.FS EmbeddedPath string + EmbeddedSubDir string Path string FileName string } +const openapiCSS = ` + +` + // StartSHTTPrver starts an HTTP server that serves the OpenAPI documentation via Stoplight Elements. // The documentation is available at the `/slang` endpoint. func StartHTTPServer(input HTTPInput) error { @@ -48,11 +67,12 @@ func StartHTTPServer(input HTTPInput) error { %s + %s -`, input.BinaryName, apiDescriptionURL) +`, input.BinaryName, openapiCSS, apiDescriptionURL) if err != nil { fmt.Printf("Failed to write HTTP response: %v\n", err) } diff --git a/cmd/httpserver/http_test.go b/cmd/httpserver/http_test.go index 7641c4b..798db41 100644 --- a/cmd/httpserver/http_test.go +++ b/cmd/httpserver/http_test.go @@ -64,7 +64,7 @@ Then print the data bodycontent, err := io.ReadAll(body) require.NoError(t, err) - expected := `{"info":{"title":"TestBinary","version":"1.0.0"},"openapi":"3.0.0","paths":{"/example":{"get":{"description":"Rule unknown ignore\n\nGiven I have a 'string' named 'test'\n\nThen print the data\n\n","parameters":[{"description":"The test","in":"query","name":"test","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"output":{"items":{"type":"string"},"type":"array"}},"required":["output"],"type":"object"}}},"description":"The slangroom execution output, splitted by newline"},"500":{"content":{"application/json":{"schema":{"properties":{"message":{"items":{"type":"string"},"type":"array"}},"required":["message"],"type":"object"}}},"description":"Slangroom execution error"}},"tags":["📑 Zencodes"]},"post":{"description":"Rule unknown ignore\n\nGiven I have a 'string' named 'test'\n\nThen print the data\n\n","requestBody":{"content":{"application/json":{"schema":{"properties":{"test":{"type":"string"}},"required":["test"],"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"output":{"items":{"type":"string"},"type":"array"}},"required":["output"],"type":"object"}}},"description":"The slangroom execution output, split by newline"},"500":{"content":{"application/json":{"schema":{"properties":{"message":{"items":{"type":"string"},"type":"array"}},"required":["message"],"type":"object"}}},"description":"Slangroom execution error"}},"tags":["📑 Zencodes"]}}},"tags":[{"description":"Endpoints generated over the Zencode smart contracts","name":"📑 Zencodes"}]}` + expected := `{"info":{"title":"TestBinary","version":"1.0.0"},"openapi":"3.0.0","paths":{"/example":{"get":{"description":"Rule unknown ignore\nGiven I have a 'string' named 'test'\nThen print the data\n","parameters":[{"description":"The test","in":"query","name":"test","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"output":{"items":{"type":"string"},"type":"array"}},"required":["output"],"type":"object"}}},"description":"The slangroom execution output, splitted by newline"},"500":{"content":{"application/json":{"schema":{"properties":{"message":{"items":{"type":"string"},"type":"array"}},"required":["message"],"type":"object"}}},"description":"Slangroom execution error"}},"tags":["📑 Zencodes"]},"post":{"description":"Rule unknown ignore\nGiven I have a 'string' named 'test'\nThen print the data\n","requestBody":{"content":{"application/json":{"schema":{"properties":{"test":{"type":"string"}},"required":["test"],"type":"object"}}}},"responses":{"200":{"content":{"application/json":{"schema":{"properties":{"output":{"items":{"type":"string"},"type":"array"}},"required":["output"],"type":"object"}}},"description":"The slangroom execution output, split by newline"},"500":{"content":{"application/json":{"schema":{"properties":{"message":{"items":{"type":"string"},"type":"array"}},"required":["message"],"type":"object"}}},"description":"Slangroom execution error"}},"tags":["📑 Zencodes"]}}},"tags":[{"description":"Endpoints generated over the Zencode smart contracts","name":"📑 Zencodes"}]}` require.JSONEq(t, expected, string(bodycontent), "actual json data: %s", body) }) diff --git a/cmd/httpserver/openapi.go b/cmd/httpserver/openapi.go index 01959f5..5bbf3ef 100644 --- a/cmd/httpserver/openapi.go +++ b/cmd/httpserver/openapi.go @@ -48,7 +48,11 @@ func GenerateOpenAPIRouter(ctx context.Context, input HTTPInput) (*mux.Router, e }, }, }) - err := fouter.CreateFileRouter(input.Path, input.EmbeddedFolder, input.EmbeddedPath, func(file fouter.SlangFile) { + folderPath := input.EmbeddedPath + if input.EmbeddedSubDir != "" { + folderPath = input.EmbeddedPath + "/" + input.EmbeddedSubDir + } + err := fouter.CreateFileRouter(input.Path, input.EmbeddedFolder, folderPath, func(file fouter.SlangFile) { var filename string if input.FileName == "" { filename = strings.TrimSuffix(file.FileName, filepath.Ext(file.FileName)) @@ -103,7 +107,7 @@ func GenerateOpenAPIRouter(ctx context.Context, input HTTPInput) (*mux.Router, e Description: "Slangroom execution error", }, }, - Description: strings.ReplaceAll(file.Content, "\n", "\n\n"), + Description: file.Content, }) if err != nil { return @@ -168,7 +172,7 @@ func GenerateOpenAPIRouter(ctx context.Context, input HTTPInput) (*mux.Router, e Description: "Slangroom execution error", }, }, - Description: strings.ReplaceAll(file.Content, "\n", "\n\n"), + Description: file.Content, }) if err != nil { return diff --git a/go.mod b/go.mod index 14728a7..b4ace76 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/santhosh-tekuri/jsonschema/v5 v5.3.1 github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.9.0 - golang.org/x/text v0.20.0 + golang.org/x/text v0.21.0 ) require ( @@ -25,7 +25,7 @@ require ( github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/invopop/yaml v0.3.1 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.7 // indirect + github.com/mailru/easyjson v0.9.0 // indirect github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect github.com/perimeterx/marshmallow v1.1.5 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index ac89f48..1e4bfcc 100644 --- a/go.sum +++ b/go.sum @@ -9,9 +9,10 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davidebianchi/gswagger v0.10.0 h1:RrFeWwjAAewWNm3x4kqFzbg+KGZ5Ak2FRdOdY72ZJe8= github.com/davidebianchi/gswagger v0.10.0/go.mod h1:2Lra+xPka3Vu/FFvh24LgqfRPpbay5uFSffVKET5D5A= +github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241129112151-e8864edd2fb4 h1:uI3pec0COHw+TmneeDCg3qEFjdg5FpEAwrn+eTasktY= +github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241129112151-e8864edd2fb4/go.mod h1:OXlCZWI8XQ8suaNik1N6xmjoH0P6fJ9MH9AK1hxw/sw= github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241217152329-ff77cc681922 h1:darm4cfsmYK0TPxuSNItzZLmB/+JQ+VUZ535H+nJ/Bc= github.com/dyne/slangroom-exec/bindings/go v0.0.0-20241217152329-ff77cc681922/go.mod h1:OXlCZWI8XQ8suaNik1N6xmjoH0P6fJ9MH9AK1hxw/sw= - github.com/getkin/kin-openapi v0.128.0 h1:jqq3D9vC9pPq1dGcOCv7yOp1DaEe7c/T1vzcLbITSp4= github.com/getkin/kin-openapi v0.128.0/go.mod h1:OZrfXzUfGrNbsKj+xmFBx6E5c6yH3At/tAKSc2UszXM= github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= @@ -38,6 +39,8 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mailru/easyjson v0.9.0 h1:PrnmzHw7262yW8sTBwxi1PdJA3Iw/EKBa8psRf7d9a4= +github.com/mailru/easyjson v0.9.0/go.mod h1:1+xMtQp2MRNVL/V1bOzuP3aP8VNwRW55fQUto+XFtTU= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= github.com/perimeterx/marshmallow v1.1.5 h1:a2LALqQ1BlHM8PZblsDdidgv1mWi1DgC2UmX50IvK2s= @@ -61,6 +64,8 @@ github.com/wk8/go-ordered-map/v2 v2.1.8 h1:5h/BUHu93oj4gIdvHHHGsScSTMijfx5PeYkE/ github.com/wk8/go-ordered-map/v2 v2.1.8/go.mod h1:5nJHM5DyteebpVlHnWMV0rPz6Zp7+xBAnxjb1X5vnTw= golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug= golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=