From d94e88b397d181574c9a5f4cd8380ebf26ba4849 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Sat, 12 Aug 2023 15:32:13 +0530 Subject: [PATCH 01/13] Env suggesting with more revelance Adding go-autocomplete-trie --- controller/controller.go | 30 ++++++++++++++++++++++++++---- go.mod | 1 + go.sum | 9 +++++++++ lama2cmd/lama2cmd.go | 4 ++-- preprocess/preprocess.go | 8 ++------ 5 files changed, 40 insertions(+), 12 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index 3a8111a6..5a9823f1 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -5,6 +5,7 @@ package contoller import ( + "encoding/json" "fmt" "os" @@ -19,6 +20,7 @@ import ( "github.com/HexmosTech/lama2/preprocess" "github.com/HexmosTech/lama2/prettify" "github.com/HexmosTech/lama2/utils" + trie "github.com/Vivino/go-autocomplete-trie" "github.com/dop251/goja" "github.com/rs/zerolog/log" ) @@ -87,14 +89,34 @@ func Process(version string) { oldDir, _ := os.Getwd() utils.ChangeWorkingDir(dir) - if o.Env { - jsonEnvs, err := preprocess.GetL2EnvVariables(dir) + if len(o.Env) > 0 { + envMap, err := preprocess.GetL2EnvVariables(dir) if err != nil { log.Error().Str("Type", "Preprocess").Msg(err.Error()) return } - // Frontend can read the stdout for this command and get the JSON of all the env's - fmt.Println(string(jsonEnvs)) + + envTrie := trie.New() + for key := range envMap { + envTrie.Insert(key) + } + + searchQuery := o.Env + suggestions := envTrie.SearchAll(searchQuery) + filteredEnvs := make(map[string]interface{}) + for _, suggestion := range suggestions { + if env, found := envMap[suggestion]; found { + filteredEnvs[suggestion] = env + } + } + + filteredJSON, err := json.MarshalIndent(filteredEnvs, "", " ") + if err != nil { + log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal filtered env's to JSON: %v", err)) + return + } + + fmt.Println(string(filteredJSON)) return } diff --git a/go.mod b/go.mod index 92aa82b4..35d96237 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/HexmosTech/gabs/v2 v2.6.5 github.com/HexmosTech/godotenv v0.0.0-20230327154318-72e1f3d32ed3 github.com/HexmosTech/httpie-go v1.0.8 + github.com/Vivino/go-autocomplete-trie v0.0.0-20230301121706-da951497d081 github.com/atotto/clipboard v0.1.4 github.com/dop251/goja v0.0.0-20230216180835-5937a312edda github.com/dop251/goja_nodejs v0.0.0-20230207183254-2229640ea097 diff --git a/go.sum b/go.sum index ca8f65e3..c4a107bf 100644 --- a/go.sum +++ b/go.sum @@ -9,6 +9,8 @@ github.com/HexmosTech/httpie-go v1.0.8/go.mod h1:U2lyp7l8mHMJUBR3DAsa79A2eY1b/Ft github.com/VividCortex/ewma v1.1.1/go.mod h1:2Tkkvm3sRDVXaiyucHiACn4cqf7DpdyLvmxzcbUokwA= github.com/VividCortex/ewma v1.2.0 h1:f58SaIzcDXrSy3kWaHNvuJgJ3Nmz59Zji6XoJR/q1ow= github.com/VividCortex/ewma v1.2.0/go.mod h1:nz4BbCtbLyFDeC9SUHbtcT5644juEuWfUAUnGx7j5l4= +github.com/Vivino/go-autocomplete-trie v0.0.0-20230301121706-da951497d081 h1:CgfvELsx826xvyUI3te9pUu6K/9xc7INVm6QwdbbH6A= +github.com/Vivino/go-autocomplete-trie v0.0.0-20230301121706-da951497d081/go.mod h1:cknpiHPHiypnmvUq1EAV3M0SQQeVY2rPjGt32hNCEDs= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= @@ -16,6 +18,7 @@ github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn github.com/coreos/go-systemd/v22 v22.3.3-0.20220203105225-a9a7ef127534/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +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/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= @@ -87,6 +90,7 @@ github.com/pborman/getopt v1.1.0 h1:eJ3aFZroQqq0bWmraivjQNt6Dmm5M0h2JcDW38/Azb0= github.com/pborman/getopt v1.1.0/go.mod h1:FxXoW1Re00sQG/+KIkuSqRL/LwQgSkv7uyac+STFsbk= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.3 h1:utMvzDsuh3suAEnhH0RdHmoPbU648o6CvXxTx4SBMOw= @@ -97,6 +101,8 @@ github.com/rs/zerolog v1.29.0 h1:Zes4hju04hjbvkVkOhdl2HpZa+0PmVwigmo8XoORE5w= github.com/rs/zerolog v1.29.0/go.mod h1:NILgTygv/Uej1ra5XxGf82ZFSLk58MFGAUS2o6usyD0= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/vbauerster/mpb/v5 v5.4.0 h1:n8JPunifvQvh6P1D1HAl2Ur9YcmKT1tpoUuiea5mlmg= github.com/vbauerster/mpb/v5 v5.4.0/go.mod h1:fi4wVo7BVQ22QcvFObm+VwliQXlV1eBT8JDaKXR4JGI= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= @@ -154,6 +160,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= @@ -185,3 +192,5 @@ gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lama2cmd/lama2cmd.go b/lama2cmd/lama2cmd.go index e264b302..1ddfa487 100644 --- a/lama2cmd/lama2cmd.go +++ b/lama2cmd/lama2cmd.go @@ -26,7 +26,7 @@ type Opts struct { PostmanFile string `short:"p" long:"postmanfile" description:"JSON export from Postman (Settings -> Data -> Export Data)"` LamaDir string `short:"l" long:"lama2dir" description:"Output directory to put .l2 files after conversion from Postman format"` Help bool `short:"h" long:"help" group:"AddHelp" description:"Usage help for Lama2"` - Env bool `short:"e" long:"env" description:"Get a JSON of environment variables"` + Env string `short:"e" long:"env" description:"Get a JSON of environment variables revelant to input arg"` Version bool `long:"version" description:"Print Lama2 binary version"` Positional struct { @@ -51,7 +51,7 @@ func getParsedInput(argList []string) (Opts, []string) { log.Fatal(). Str("Type", "Preprocess"). Strs("arglist", argList). - Msg(fmt.Sprint("Couldn't parse argument list")) + Msg("Couldn't parse argument list") } switch len(o.Verbose) { diff --git a/preprocess/preprocess.go b/preprocess/preprocess.go index 952cfab2..740a6feb 100644 --- a/preprocess/preprocess.go +++ b/preprocess/preprocess.go @@ -167,7 +167,7 @@ func combineEnvMaps(envMaps ...map[string]map[string]interface{}) map[string]map return finalEnvMap } -func GetL2EnvVariables(dir string) ([]byte, error) { +func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error) { l2ConfigEnvMap := make(map[string]map[string]interface{}) l2ConfigPath, err := SearchL2ConfigEnv(dir) @@ -191,11 +191,7 @@ func GetL2EnvVariables(dir string) ([]byte, error) { finalEnvMap := combineEnvMaps(l2ConfigEnvMap, l2EnvMap) - jsonEnvs, err := json.MarshalIndent(finalEnvMap, "", " ") - if err != nil { - return nil, fmt.Errorf("Failed to marshal map env's to JSON: %v", err) - } - return jsonEnvs, nil + return finalEnvMap, nil } func GetLamaFileAsString(path string) string { From a137b34df2637c895cda4bb24b0e7e317dea7031 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Sat, 12 Aug 2023 20:28:53 +0530 Subject: [PATCH 02/13] Extracting common functionalities --- controller/controller.go | 53 ++++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 18 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index b7691e2d..b3f0feca 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -89,34 +89,25 @@ func Process(version string) { oldDir, _ := os.Getwd() utils.ChangeWorkingDir(dir) - if len(o.Env) > 0 { + if (o.Env) == "" { envMap, err := preprocess.GetL2EnvVariables(dir) if err != nil { log.Error().Str("Type", "Preprocess").Msg(err.Error()) return } + marshalAndPrintJSON(envMap) + return + } - envTrie := trie.New() - for key := range envMap { - envTrie.Insert(key) - } - - searchQuery := o.Env - suggestions := envTrie.SearchAll(searchQuery) - filteredEnvs := make(map[string]interface{}) - for _, suggestion := range suggestions { - if env, found := envMap[suggestion]; found { - filteredEnvs[suggestion] = env - } - } - - filteredJSON, err := json.MarshalIndent(filteredEnvs, "", " ") + if len(o.Env) > 0 { + envMap, err := preprocess.GetL2EnvVariables(dir) if err != nil { - log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal filtered env's to JSON: %v", err)) + log.Error().Str("Type", "Preprocess").Msg(err.Error()) return } - fmt.Println(string(filteredJSON)) + filteredEnvs := getRelevantEnvs(envMap, o) + marshalAndPrintJSON(filteredEnvs) return } @@ -144,3 +135,29 @@ func Process(version string) { log.Debug().Str("Parsed API", parsedAPI.String()).Msg("") HandleParsedFile(parsedAPI, o, dir) } + +func marshalAndPrintJSON(data interface{}) { + filteredJSON, err := json.MarshalIndent(data, "", " ") + if err != nil { + log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal JSON: %v", err)) + return + } + fmt.Println(string(filteredJSON)) +} + +func getRelevantEnvs(envMap map[string]map[string]interface{}, o *lama2cmd.Opts) map[string]interface{} { + envTrie := trie.New() + for key := range envMap { + envTrie.Insert(key) + } + + searchQuery := o.Env + suggestions := envTrie.SearchAll(searchQuery) + filteredEnvs := make(map[string]interface{}) + for _, suggestion := range suggestions { + if env, found := envMap[suggestion]; found { + filteredEnvs[suggestion] = env + } + } + return filteredEnvs +} From a11245ad1fc20df0278258c3125596bb4466a1a8 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Sun, 13 Aug 2023 20:07:25 +0530 Subject: [PATCH 03/13] Adding tests to verify trie's functionalities, testing --- tests/env_command_test.go | 61 +++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/tests/env_command_test.go b/tests/env_command_test.go index 74913992..c7387304 100644 --- a/tests/env_command_test.go +++ b/tests/env_command_test.go @@ -17,37 +17,68 @@ type EnvData struct { } func TestL2EnvCommand(t *testing.T) { - cmdArgs := []string{"-e", "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2"} + fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" + cmdArgs := []string{"-e=", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) - // Check the "AHOST" key + + // Check the "AHOST" key is present checkAHost(t, envMap) // Check the "BHOST" key checkBHost(t, envMap) } +func TestL2EnvForAHOenv(t *testing.T) { + fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" + cmdArgs := []string{"-e=A", fpath} + envMap := runL2CommandAndParseJSON(t, cmdArgs...) + + // Check the "AHOST" key is present + checkAHost(t, envMap) + + // Check the "BHOST" key is absent + checkBHostDoesNotExist(t, envMap) +} + +func TestL2EnvForBHOenv(t *testing.T) { + fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" + cmdArgs := []string{"-e=B", fpath} + envMap := runL2CommandAndParseJSON(t, cmdArgs...) + + // Check the "BHOST" key is present + checkBHost(t, envMap) + + // Check the "AHOST" key is absent + checkAHostDoesNotExist(t, envMap) +} + func TestL2EnvCommandVerbose(t *testing.T) { - cmdArgs := []string{"-ev", "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2"} + fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" + cmdArgs := []string{"-e=", "-v", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) - // Check the "AHOST" key + + // Check the "AHOST" key is present checkAHost(t, envMap) - // Check the "BHOST" key + // Check the "BHOST" key is present checkBHost(t, envMap) } func TestL2EnvWithoutL2config(t *testing.T) { - cmdArgs := []string{"-ev", "../elfparser/ElfTestSuite/no_l2config/api/y_0021_no_l2config.l2"} + fpath := "../elfparser/ElfTestSuite/no_l2config/api/y_0021_no_l2config.l2" + cmdArgs := []string{"-e=", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) - // Check the "AHOST" key + + // Check the "AHOST" key is present checkAHost(t, envMap) } func TestL2EnvWithoutL2env(t *testing.T) { - cmdArgs := []string{"-ev", "../elfparser/ElfTestSuite/no_l2env/api/y_0022_no_l2env.l2"} + fpath := "../elfparser/ElfTestSuite/no_l2env/api/y_0022_no_l2env.l2" + cmdArgs := []string{"-e=", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) - // Check the "BHOST" key + // Check the "BHOST" key is present checkBHost(t, envMap) } @@ -130,3 +161,15 @@ func checkBHost(t *testing.T, envMap map[string]EnvData) { } } } + +func checkBHostDoesNotExist(t *testing.T, envMap map[string]EnvData) { + if _, ok := envMap["BHOST"]; ok { + t.Error("Expected 'BHOST' key not to be present in the JSON, but it was found") + } +} + +func checkAHostDoesNotExist(t *testing.T, envMap map[string]EnvData) { + if _, ok := envMap["AHOST"]; ok { + t.Error("Expected 'AHOST' key not to be present in the JSON, but it was found") + } +} From 5a0bd893e88c9984a40774b329804e9b58e81fd0 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Sun, 13 Aug 2023 20:29:50 +0530 Subject: [PATCH 04/13] Adding more condition for empty env suggestion checking --- controller/controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/controller.go b/controller/controller.go index b3f0feca..94813a09 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -89,7 +89,7 @@ func Process(version string) { oldDir, _ := os.Getwd() utils.ChangeWorkingDir(dir) - if (o.Env) == "" { + if (o.Env) == "" && len(o.Output) == 0 { envMap, err := preprocess.GetL2EnvVariables(dir) if err != nil { log.Error().Str("Type", "Preprocess").Msg(err.Error()) From ca5fc33fc2414dffb32974052cfea59287b30d24 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Mon, 14 Aug 2023 19:57:23 +0530 Subject: [PATCH 05/13] Adding about relevant string, docuemntation --- docs/Lama2/docs/reference/controller.md | 10 ++-- docs/Lama2/docs/reference/lama2cmd.md | 2 +- docs/Lama2/docs/reference/preprocess.md | 8 ++-- docs/Lama2/docs/tutorials/editor.md | 23 +++++---- docs/Lama2/docs/tutorials/installation.md | 23 +++++---- docs/Lama2/site/reference/controller.html | 10 ++-- docs/Lama2/site/reference/lama2cmd.html | 2 +- docs/Lama2/site/reference/preprocess.html | 8 ++-- docs/Lama2/site/search/search_index.json | 2 +- docs/Lama2/site/sitemap.xml | 50 ++++++++++---------- docs/Lama2/site/sitemap.xml.gz | Bin 403 -> 402 bytes docs/Lama2/site/tutorials/editor.html | 14 +++--- docs/Lama2/site/tutorials/installation.html | 10 ++-- 13 files changed, 83 insertions(+), 79 deletions(-) diff --git a/docs/Lama2/docs/reference/controller.md b/docs/Lama2/docs/reference/controller.md index f3d79f68..6566b1d2 100644 --- a/docs/Lama2/docs/reference/controller.md +++ b/docs/Lama2/docs/reference/controller.md @@ -18,7 +18,7 @@ Package controller coordinates all the other components in the \`Lama2\` project -## func [ExecuteProcessorBlock]() +## func [ExecuteProcessorBlock]() ```go func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) @@ -27,7 +27,7 @@ func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) -## func [ExecuteRequestorBlock]() +## func [ExecuteRequestorBlock]() ```go func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse @@ -36,7 +36,7 @@ func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2c -## func [GetParsedAPIBlocks]() +## func [GetParsedAPIBlocks]() ```go func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container @@ -45,7 +45,7 @@ func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container -## func [HandleParsedFile]() +## func [HandleParsedFile]() ```go func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) @@ -54,7 +54,7 @@ func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) -## func [Process]() +## func [Process]() ```go func Process(version string) diff --git a/docs/Lama2/docs/reference/lama2cmd.md b/docs/Lama2/docs/reference/lama2cmd.md index f530d414..f41d0825 100644 --- a/docs/Lama2/docs/reference/lama2cmd.md +++ b/docs/Lama2/docs/reference/lama2cmd.md @@ -41,7 +41,7 @@ type Opts struct { PostmanFile string `short:"p" long:"postmanfile" description:"JSON export from Postman (Settings -> Data -> Export Data)"` LamaDir string `short:"l" long:"lama2dir" description:"Output directory to put .l2 files after conversion from Postman format"` Help bool `short:"h" long:"help" group:"AddHelp" description:"Usage help for Lama2"` - Env bool `short:"e" long:"env" description:"Get a JSON of environment variables"` + Env string `short:"e" long:"env" description:"Get a JSON of environment variables revelant to input arg"` Version bool `long:"version" description:"Print Lama2 binary version"` Positional struct { diff --git a/docs/Lama2/docs/reference/preprocess.md b/docs/Lama2/docs/reference/preprocess.md index b37ed095..4c79e917 100644 --- a/docs/Lama2/docs/reference/preprocess.md +++ b/docs/Lama2/docs/reference/preprocess.md @@ -15,7 +15,7 @@ Package preprocess provides facilities to expand environment variables in \`.l2\ - [func ExpandHeaders\(block \*gabs.Container, vm \*goja.Runtime\)](<#ExpandHeaders>) - [func ExpandJSON\(block \*gabs.Container, vm \*goja.Runtime\)](<#ExpandJSON>) - [func ExpandURL\(block \*gabs.Container, vm \*goja.Runtime\)](<#ExpandURL>) -- [func GetL2EnvVariables\(dir string\) \(\[\]byte, error\)](<#GetL2EnvVariables>) +- [func GetL2EnvVariables\(dir string\) \(map\[string\]map\[string\]interface\{\}, error\)](<#GetL2EnvVariables>) - [func GetLamaFileAsString\(path string\) string](<#GetLamaFileAsString>) - [func LamaFile\(inputFile string\) \(string, string\)](<#LamaFile>) - [func LoadEnvFile\(l2path string\)](<#LoadEnvFile>) @@ -73,13 +73,13 @@ func ExpandURL(block *gabs.Container, vm *goja.Runtime) ## func [GetL2EnvVariables]() ```go -func GetL2EnvVariables(dir string) ([]byte, error) +func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error) ``` -## func [GetLamaFileAsString]() +## func [GetLamaFileAsString]() ```go func GetLamaFileAsString(path string) string @@ -88,7 +88,7 @@ func GetLamaFileAsString(path string) string -## func [LamaFile]() +## func [LamaFile]() ```go func LamaFile(inputFile string) (string, string) diff --git a/docs/Lama2/docs/tutorials/editor.md b/docs/Lama2/docs/tutorials/editor.md index 779f7c20..4c6e0b85 100644 --- a/docs/Lama2/docs/tutorials/editor.md +++ b/docs/Lama2/docs/tutorials/editor.md @@ -1,12 +1,13 @@ -## Useful Options +## Useful Options + The `l2` command provides some helpful options for extension developers. The options are: -1. `--env` or `-e` outputs a JSON of environment variables (in CLI); +1. `--env=` or `-e` outputs a JSON of environment variables (in CLI); 2. `--nocolor` or `-n` disables colored output in httpie-go (in CLI); 3. `--output=Index&
  • func Process(version string)
  • -

    func ExecuteProcessorBlock

    +

    func ExecuteProcessorBlock

    func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime)
     

    -

    func ExecuteRequestorBlock

    +

    func ExecuteRequestorBlock

    func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse
     

    -

    func GetParsedAPIBlocks

    +

    func GetParsedAPIBlocks

    func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container
     

    -

    func HandleParsedFile

    +

    func HandleParsedFile

    func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string)
     

    -

    func Process

    +

    func Process

    func Process(version string)
     

    Process initiates the following tasks in the given order: 1. Parse command line arguments 2. Read API file contents 3. Expand environment variables in API file 4. Parse the API contents 5. Generate API request command 6. Execute command & retrieve results 7. Optionally, post-process and write results to a JSON file

    diff --git a/docs/Lama2/site/reference/lama2cmd.html b/docs/Lama2/site/reference/lama2cmd.html index 007d0bc4..9325ea3a 100644 --- a/docs/Lama2/site/reference/lama2cmd.html +++ b/docs/Lama2/site/reference/lama2cmd.html @@ -752,7 +752,7 @@

    type PostmanFile string `short:"p" long:"postmanfile" description:"JSON export from Postman (Settings -> Data -> Export Data)"` LamaDir string `short:"l" long:"lama2dir" description:"Output directory to put .l2 files after conversion from Postman format"` Help bool `short:"h" long:"help" group:"AddHelp" description:"Usage help for Lama2"` - Env bool `short:"e" long:"env" description:"Get a JSON of environment variables"` + Env string `short:"e" long:"env" description:"Get a JSON of environment variables revelant to input arg"` Version bool `long:"version" description:"Print Lama2 binary version"` Positional struct { diff --git a/docs/Lama2/site/reference/preprocess.html b/docs/Lama2/site/reference/preprocess.html index 809bdfb5..878c6527 100644 --- a/docs/Lama2/site/reference/preprocess.html +++ b/docs/Lama2/site/reference/preprocess.html @@ -792,7 +792,7 @@

    Index&
  • func ExpandHeaders(block *gabs.Container, vm *goja.Runtime)
  • func ExpandJSON(block *gabs.Container, vm *goja.Runtime)
  • func ExpandURL(block *gabs.Container, vm *goja.Runtime)
  • -
  • func GetL2EnvVariables(dir string) ([]byte, error)
  • +
  • func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error)
  • func GetLamaFileAsString(path string) string
  • func LamaFile(inputFile string) (string, string)
  • func LoadEnvFile(l2path string)
  • @@ -824,14 +824,14 @@

    func

    func GetL2EnvVariables

    -
    func GetL2EnvVariables(dir string) ([]byte, error)
    +
    func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error)
     

    -

    func GetLamaFileAsString

    +

    func GetLamaFileAsString

    func GetLamaFileAsString(path string) string
     

    -

    func LamaFile

    +

    func LamaFile

    func LamaFile(inputFile string) (string, string)
     

    LamaFile takes in a path to an API file. It moves into the API file directory, reads the API contents, loads the `l2.env` file if available, and finally substitutes environment vars in the API contents Once done, it reverts back to the original directory, and returns the processed l2 file.

    diff --git a/docs/Lama2/site/search/search_index.json b/docs/Lama2/site/search/search_index.json index 1d38c0f8..7c0521b3 100644 --- a/docs/Lama2/site/search/search_index.json +++ b/docs/Lama2/site/search/search_index.json @@ -1 +1 @@ -{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"index.html","text":"Lama2 : Plain-Text Powered REST API Client for Teams \u00b6 About \u00b6 Lama2 is a Plain-Text powered REST API client & manager built for serious engineering teams. Lama2 specifies the .l2 syntax for describing APIs, and implements a CLI to execute .l2 files. Engineers collaborate on .l2 files using version control. Lama2 integrates nicely with IDEs and text-editors as well. Think of Lama2 as Markdown for APIs. Benefits \u00b6 Plain-Text files: Store APIs in the Plain-Text .l2 API files. Simple and human-friendly syntax. Learn basics within minutes! Simple CLI: Launch the CLI tool l2 on API files to make REST API requests. Editor support: Invoke Lama2 from your favorite text editor or IDE. Helpful documentation and tool support to build editor extensions included. Longevity & track-ability: Commit .l2 files to git or other version control for long life & change tracking. Collaboration: Share API repo with teammates and colleagues to collaborate Code generation: Convert l2 API definitions into your preferred language/library, be it Python, Javascript, Java or many other options. Powerful chaining: Chain multiple l2 requests through embedded Javascript blocks Documentation: Explore examples, how-tos, explanations, references, FAQ/RAQs, and diagrams. Documentation is a priority, so that you never have to get lost. Extensibility: .l2 syntax is implemented as a recursive descent parser , based on a formal grammar . Dig into details and implement new syntax (ex: to support websockets ) Tip Coming from postman? Let Lama2 help you convert Postman data dumps into a nice Plain-Text Lama2 repo. Terminal Demo: A POST request \u00b6 basic_post.l2 : POST https://httpbin.org/post { \"hello\" : \"world\" } Execute: l2 basic_post.l2 VSCode Demo: The same POST request \u00b6 Community and Support \u00b6 Full documentation @hexmos.com/lama2 Report issues and propose improvements at Github issues Discuss with the community at Discord","title":"Home"},{"location":"index.html#lama2-plain-text-powered-rest-api-client-for-teams","text":"","title":"Lama2: Plain-Text Powered REST API Client for Teams"},{"location":"index.html#about","text":"Lama2 is a Plain-Text powered REST API client & manager built for serious engineering teams. Lama2 specifies the .l2 syntax for describing APIs, and implements a CLI to execute .l2 files. Engineers collaborate on .l2 files using version control. Lama2 integrates nicely with IDEs and text-editors as well. Think of Lama2 as Markdown for APIs.","title":"About"},{"location":"index.html#benefits","text":"Plain-Text files: Store APIs in the Plain-Text .l2 API files. Simple and human-friendly syntax. Learn basics within minutes! Simple CLI: Launch the CLI tool l2 on API files to make REST API requests. Editor support: Invoke Lama2 from your favorite text editor or IDE. Helpful documentation and tool support to build editor extensions included. Longevity & track-ability: Commit .l2 files to git or other version control for long life & change tracking. Collaboration: Share API repo with teammates and colleagues to collaborate Code generation: Convert l2 API definitions into your preferred language/library, be it Python, Javascript, Java or many other options. Powerful chaining: Chain multiple l2 requests through embedded Javascript blocks Documentation: Explore examples, how-tos, explanations, references, FAQ/RAQs, and diagrams. Documentation is a priority, so that you never have to get lost. Extensibility: .l2 syntax is implemented as a recursive descent parser , based on a formal grammar . Dig into details and implement new syntax (ex: to support websockets ) Tip Coming from postman? Let Lama2 help you convert Postman data dumps into a nice Plain-Text Lama2 repo.","title":"Benefits"},{"location":"index.html#terminal-demo-a-post-request","text":"basic_post.l2 : POST https://httpbin.org/post { \"hello\" : \"world\" } Execute: l2 basic_post.l2","title":"Terminal Demo: A POST request"},{"location":"index.html#vscode-demo-the-same-post-request","text":"","title":"VSCode Demo: The same POST request"},{"location":"index.html#community-and-support","text":"Full documentation @hexmos.com/lama2 Report issues and propose improvements at Github issues Discuss with the community at Discord","title":"Community and Support"},{"location":"about/contact.html","text":"Discord \u00b6 Join Hexmos Lama2 discord server to discuss with the community Email \u00b6 Drop an email to shrijith 'at' hexmos.com Github Issues & Discussions \u00b6 Report issues and propose improvements at Github Issues and Github Discussions","title":"Talk to us"},{"location":"about/contact.html#discord","text":"Join Hexmos Lama2 discord server to discuss with the community","title":" Discord"},{"location":"about/contact.html#email","text":"Drop an email to shrijith 'at' hexmos.com","title":" Email"},{"location":"about/contact.html#github-issues-discussions","text":"Report issues and propose improvements at Github Issues and Github Discussions","title":" Github Issues & Discussions"},{"location":"about/hexmos.html","text":"We at Hexmos are deeply concerned about the state of organizations all across the world. We possess firm convictions and aspiration towards improving organizational health across the world . Through deep R&D, good software, relevant tools and techniques, we work to improve organizational health. For a sample of our R&D, check these resources out: Turnover and Other Organizational Ailments : A deeply research-backed exploration into the roots of organizational troubles and their cures, this book assimilates 80+ longitudinal and empirical studies to provide recommendations to improve organizational health. Hexmos Feedback , a tool to provide continuous feedback to your colleagues, so that not a single beneficial thing said or done goes unnoticed","title":"Hexmos"},{"location":"explanation/faq.html","text":"FAQs/RAQs \u00b6 Why pick Javascript as the scripting/glue language? \u00b6 Lama2's design philosophy advocates \"delegate to mature and preferably open tools\". After analysis, we finally picked JS due to following reasons: Most people working with APIs probably already know JS Easy to support XPath/JSONPath or even JQ clones right into JS Even if you don't know any of (2), simple JS object notation + good old loops will take you far Native support for JSON (and dom manipulation is common too, for xml type responses) Good amount of power for implementation effort exerted For simple use cases, one barely has to understand any serious JS. Object/map notation is quite intuitive. Ultimately, we believe JS passes our \"Intern Test\" for usability. What is the Intern Test ? \u00b6 Lama2 API files must remain easy for interns to get used with minimal handholding from more experienced engineers. If it doesn't work for interns, then it doesn't work for our teams at Hexmos as well. Why did you create Lama2 ? \u00b6 At Hexmos , our engineering infrastructure is split into dozens of self-contained software services. We deal with 100s of internal APIs, and so felt a need for a robust workflow for defining, sharing and updating APIs within our teams. Traditional solutions such as Postman/Insomnia implement the collaboration features within their applications, and also tend to charge a fee for collaboration. We felt using git is the right way to collaborate on APIs, rather than any custom built solution. So, in a matter of 2-days we got a regex-based prototype DSL language to store API files. Lots of issues cropped up over time, but we kept making improvements to Lama2 as needs arose. Hexmos accumulated 100s of APIS over time. Then, we decided that the tool deserves to be out there, benefitting teams that want to collaborate on APIs over git . So, to make it happen, first we invested into formalizing the grammar, and implementing the DSL as a hand-written recursive descent parser. Then we invested into helpful documentation, demos and so on. Once we had the basics, we released Lama2 into the world.","title":"FAQ/RAQ"},{"location":"explanation/faq.html#faqsraqs","text":"","title":"FAQs/RAQs"},{"location":"explanation/faq.html#why-pick-javascript-as-the-scriptingglue-language","text":"Lama2's design philosophy advocates \"delegate to mature and preferably open tools\". After analysis, we finally picked JS due to following reasons: Most people working with APIs probably already know JS Easy to support XPath/JSONPath or even JQ clones right into JS Even if you don't know any of (2), simple JS object notation + good old loops will take you far Native support for JSON (and dom manipulation is common too, for xml type responses) Good amount of power for implementation effort exerted For simple use cases, one barely has to understand any serious JS. Object/map notation is quite intuitive. Ultimately, we believe JS passes our \"Intern Test\" for usability.","title":"Why pick Javascript as the scripting/glue language?"},{"location":"explanation/faq.html#what-is-the-intern-test","text":"Lama2 API files must remain easy for interns to get used with minimal handholding from more experienced engineers. If it doesn't work for interns, then it doesn't work for our teams at Hexmos as well.","title":"What is the Intern Test?"},{"location":"explanation/faq.html#why-did-you-create-lama2","text":"At Hexmos , our engineering infrastructure is split into dozens of self-contained software services. We deal with 100s of internal APIs, and so felt a need for a robust workflow for defining, sharing and updating APIs within our teams. Traditional solutions such as Postman/Insomnia implement the collaboration features within their applications, and also tend to charge a fee for collaboration. We felt using git is the right way to collaborate on APIs, rather than any custom built solution. So, in a matter of 2-days we got a regex-based prototype DSL language to store API files. Lots of issues cropped up over time, but we kept making improvements to Lama2 as needs arose. Hexmos accumulated 100s of APIS over time. Then, we decided that the tool deserves to be out there, benefitting teams that want to collaborate on APIs over git . So, to make it happen, first we invested into formalizing the grammar, and implementing the DSL as a hand-written recursive descent parser. Then we invested into helpful documentation, demos and so on. Once we had the basics, we released Lama2 into the world.","title":"Why did you create Lama2?"},{"location":"explanation/l2format.html","text":"Find in this page an informal description of the rules for authoring .l2 API files. This document expects some familiarity with Lama2 . To quickly get started with Lama2 , head over to Examples . On the other hand, if you are a developer and wish to learn more about the formal grammar underlying l2 , visit the Grammar section. Comments start with # \u00b6 Lines starting with # are comments and hence ignored altogether All HTTP Verbs supported - including the common GET/POST/PUT \u00b6 Fully supported: GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH JSON is the default submission type, but MULTIPART is supported too \u00b6 varjson is a simpler syntax to specify flat JSONs \u00b6 varjson values are defined as follows: hello=world foo=bar The above results in a JSON submission of the form: { \"hello\": \"world\", \"foo\": \"bar\" } Nested JSON can simply be dumped at the end of the document \u00b6 The JSON recognition engine is quite lenient. It can deal with minor errors in the format (such as having single quotes instead of double quotes, trailing garbage, or an extra comma after the last element in an array,). POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } MULTIPART allows both file uploads & the usual fields \u00b6 Example: POST MULTIPART http://localhost:8000/register userid=lince5 file@./helloworld.jpg Note The file path is relative to the request file. Cookies are sent as headers \u00b6 Cookies are specified in a Cookie header as follows: Cookie:'sessionid=foo;another-cookie=bar' Environment Variables \u00b6 API variables can be defined in apirequest.l2 \u00b6 Variables are declared within the JS processor block and serve as dynamic placeholders for data used in API requests. By utilizing these variables, L2 enables flexibility and reusability in defining API endpoints and data payloads. Example login.l2 : let REMOTE = \"httpbin.org\" let EMAIL = \"customer1@gmail.com\" --- POST ${REMOTE}/login { \"email\": \"${EMAIL}\", \"password\": \"customer1@gmail.com\" } Get Source Files API environment variables can be defined locally in l2.env \u00b6 L2 provides a convenient way to define environment variables through the l2.env file. This file is automatically searched for in the present directory, and its contents are loaded to create a set of variables (local). In the l2.env file, you can specify environment-specific values for variables used in your L2 scripts, such as URLs, authentication tokens, or any other data that may vary depending on the environment in which the API requests are executed. Go to Example Get Source File API environment variables can be defined at project root using l2config.env \u00b6 The l2config.env file serves as a centralized storage for environment variables located at the project root, streamlining the management of configuration settings across all L2 scripts. With this file present, every L2 script within the project automatically inherits the defined variables, effectively eliminating the necessity to duplicate configurations in individual subdirectories using l2.env . The search for l2config.env extends from the present directory up to the root directory ( / ). During this process, the variables defined in the root file are loaded and made available for use in all relevant scripts. This approach significantly enhances efficiency and maintainability, as it ensures consistent settings throughout the project while reducing redundancy in configuration data. Go to Example Get Source File If l2config.env (root) variables are redeclared in l2.env (local) \u00b6 In situations where both root and local variables share the same variable name, the local variable takes precedence over the root variable. This behavior remains consistent, even if both l2config.env (root) and l2.env (local) files reside in the same directory. The local variable's value will always be considered over the root variable, ensuring that specific configurations defined at the local level effectively override any corresponding settings present in the root file. This approach provides developers with granular control and flexibility in tailoring environment variables to suit specific needs within different parts of the project while maintaining the overall structure and organization of configuration settings. Go to Example Get Source File The environment file can load results of commands \u00b6 Use the backtick notation \\ command`` to place the results of commands into environment variables: export PHOTO=`base64 image.jpeg` One can load the PHOTO variable in API files. Chain requests through Javascript blocks \u00b6 Lama2 supports plain Javascript (JS) blocks as a glue for manipulating responses and passing on values to later stages. At a higher level, a chain of requests may look like: Javascript 1 --- L2 Request 1 --- Javscript 2 --- L2 Request 2 The triple-dash ( --- ) separator is mandatory. The special variable result contains the response from previous stages. For example, in the above case, Javascript 2 can access the response from L2 Request 1 through the result variable. Learn more about request chaining in Examples .","title":"The l2 Format"},{"location":"explanation/l2format.html#comments-start-with","text":"Lines starting with # are comments and hence ignored altogether","title":"Comments start with #"},{"location":"explanation/l2format.html#all-http-verbs-supported-including-the-common-getpostput","text":"Fully supported: GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH","title":"All HTTP Verbs supported - including the common GET/POST/PUT"},{"location":"explanation/l2format.html#json-is-the-default-submission-type-but-multipart-is-supported-too","text":"","title":"JSON is the default submission type, but MULTIPART is supported too"},{"location":"explanation/l2format.html#varjson-is-a-simpler-syntax-to-specify-flat-jsons","text":"varjson values are defined as follows: hello=world foo=bar The above results in a JSON submission of the form: { \"hello\": \"world\", \"foo\": \"bar\" }","title":"varjson is a simpler syntax to specify flat JSONs"},{"location":"explanation/l2format.html#nested-json-can-simply-be-dumped-at-the-end-of-the-document","text":"The JSON recognition engine is quite lenient. It can deal with minor errors in the format (such as having single quotes instead of double quotes, trailing garbage, or an extra comma after the last element in an array,). POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" }","title":"Nested JSON can simply be dumped at the end of the document"},{"location":"explanation/l2format.html#multipart-allows-both-file-uploads-the-usual-fields","text":"Example: POST MULTIPART http://localhost:8000/register userid=lince5 file@./helloworld.jpg Note The file path is relative to the request file.","title":"MULTIPART allows both file uploads & the usual fields"},{"location":"explanation/l2format.html#cookies-are-sent-as-headers","text":"Cookies are specified in a Cookie header as follows: Cookie:'sessionid=foo;another-cookie=bar'","title":"Cookies are sent as headers"},{"location":"explanation/l2format.html#environment-variables","text":"","title":"Environment Variables"},{"location":"explanation/l2format.html#api-variables-can-be-defined-in-apirequestl2","text":"Variables are declared within the JS processor block and serve as dynamic placeholders for data used in API requests. By utilizing these variables, L2 enables flexibility and reusability in defining API endpoints and data payloads. Example login.l2 : let REMOTE = \"httpbin.org\" let EMAIL = \"customer1@gmail.com\" --- POST ${REMOTE}/login { \"email\": \"${EMAIL}\", \"password\": \"customer1@gmail.com\" } Get Source Files","title":"API variables can be defined in apirequest.l2"},{"location":"explanation/l2format.html#api-environment-variables-can-be-defined-locally-in-l2env","text":"L2 provides a convenient way to define environment variables through the l2.env file. This file is automatically searched for in the present directory, and its contents are loaded to create a set of variables (local). In the l2.env file, you can specify environment-specific values for variables used in your L2 scripts, such as URLs, authentication tokens, or any other data that may vary depending on the environment in which the API requests are executed. Go to Example Get Source File","title":"API environment variables can be defined locally in l2.env"},{"location":"explanation/l2format.html#api-environment-variables-can-be-defined-at-project-root-using-l2configenv","text":"The l2config.env file serves as a centralized storage for environment variables located at the project root, streamlining the management of configuration settings across all L2 scripts. With this file present, every L2 script within the project automatically inherits the defined variables, effectively eliminating the necessity to duplicate configurations in individual subdirectories using l2.env . The search for l2config.env extends from the present directory up to the root directory ( / ). During this process, the variables defined in the root file are loaded and made available for use in all relevant scripts. This approach significantly enhances efficiency and maintainability, as it ensures consistent settings throughout the project while reducing redundancy in configuration data. Go to Example Get Source File","title":"API environment variables can be defined at project root using l2config.env"},{"location":"explanation/l2format.html#if-l2configenvroot-variables-are-redeclared-in-l2envlocal","text":"In situations where both root and local variables share the same variable name, the local variable takes precedence over the root variable. This behavior remains consistent, even if both l2config.env (root) and l2.env (local) files reside in the same directory. The local variable's value will always be considered over the root variable, ensuring that specific configurations defined at the local level effectively override any corresponding settings present in the root file. This approach provides developers with granular control and flexibility in tailoring environment variables to suit specific needs within different parts of the project while maintaining the overall structure and organization of configuration settings. Go to Example Get Source File","title":"If l2config.env(root) variables are redeclared in l2.env(local)"},{"location":"explanation/l2format.html#the-environment-file-can-load-results-of-commands","text":"Use the backtick notation \\ command`` to place the results of commands into environment variables: export PHOTO=`base64 image.jpeg` One can load the PHOTO variable in API files.","title":"The environment file can load results of commands"},{"location":"explanation/l2format.html#chain-requests-through-javascript-blocks","text":"Lama2 supports plain Javascript (JS) blocks as a glue for manipulating responses and passing on values to later stages. At a higher level, a chain of requests may look like: Javascript 1 --- L2 Request 1 --- Javscript 2 --- L2 Request 2 The triple-dash ( --- ) separator is mandatory. The special variable result contains the response from previous stages. For example, in the above case, Javascript 2 can access the response from L2 Request 1 through the result variable. Learn more about request chaining in Examples .","title":"Chain requests through Javascript blocks"},{"location":"explanation/syntax.html","text":"The following is the recommended flow for a simple .l2 file. The grammar offers some additional flexibilities in ordering the various components, but it is preferable to stick to the following ordering to help with consistency. Also, for chaining requests , one needs a little bit more syntax -- See Examples %%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD Z(Start) Z --> A A[\"HTTP Verb (get/post/put/delete)\"] --> B[Multipart] C[\"URL (http://blah.com)\"] A --> C B --> C D[\"Headers (header_key: header_value)\"] E{Payload} C --> D D --> E F[\"VarJSON (key=value)\"] G[\"JSON {'key': 'value'}\"] H[\"Multipart files (filename@filepath)\"] E --> F F --> H E --> G I(\"End\") H --> I G --> I","title":"Syntax Guidance"},{"location":"reference/api.html","text":"parser cmdexec cmdgen controller lama2cmd outputmanager preprocess utils","title":"API Reference"},{"location":"reference/architecture.html","text":"Diagram \u00b6 %%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD K[\"Controller Entry
    (controller)\"] A[\"Parse CLI
    (lama2cmd)\"] B[\"Parser
    (parser)\"] D[\"Request Executor
    (cmdexec)\"] E[\"Output Format Manager
    (outputmanager)\"] F[\"Error Reporting (TODO)\"] G[\"Load input & environment vars
    (preprocess)\"] H[\"Request Command Generator
    (cmdgen)\"] I[\"Lama2 Prettifier\"] J[\"Data Importer (importer)\"] L[\"Iterate over blocks
    (controller)\"] M[\"Init Javascript processor VM
    (cmdexec)\"] N[\"Execute JS
    (cmdexec)\"] P[\"Variable expansion (JS + env)
    (preprocess)\"] A --> G A --> J G --> B H --> D K --> A B --> M M --> L L --> |Requestor| P L --> |Processor| N N --> E D --> E B --> F A --> I P --> H L --> L Description \u00b6 From a high level, how does it work now? Read API file Create a tree-like structure based on *gabs.Container Initialize Javascript VM for executing JS blocks For each block If block is JS Processor block Execute JS code in VM Else if block is Requestor block Replace variables with values in the following order Try fetch variable from Javascript VM If (1) fails, try fetch Local env variable from l2.env Try fetch root env variable from l2config.env Use the processed elements to create an httpie-go request Fetch response If necessary, write the last transaction to .json file","title":"Architecture"},{"location":"reference/architecture.html#diagram","text":"%%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD K[\"Controller Entry
    (controller)\"] A[\"Parse CLI
    (lama2cmd)\"] B[\"Parser
    (parser)\"] D[\"Request Executor
    (cmdexec)\"] E[\"Output Format Manager
    (outputmanager)\"] F[\"Error Reporting (TODO)\"] G[\"Load input & environment vars
    (preprocess)\"] H[\"Request Command Generator
    (cmdgen)\"] I[\"Lama2 Prettifier\"] J[\"Data Importer (importer)\"] L[\"Iterate over blocks
    (controller)\"] M[\"Init Javascript processor VM
    (cmdexec)\"] N[\"Execute JS
    (cmdexec)\"] P[\"Variable expansion (JS + env)
    (preprocess)\"] A --> G A --> J G --> B H --> D K --> A B --> M M --> L L --> |Requestor| P L --> |Processor| N N --> E D --> E B --> F A --> I P --> H L --> L","title":"Diagram"},{"location":"reference/architecture.html#description","text":"From a high level, how does it work now? Read API file Create a tree-like structure based on *gabs.Container Initialize Javascript VM for executing JS blocks For each block If block is JS Processor block Execute JS code in VM Else if block is Requestor block Replace variables with values in the following order Try fetch variable from Javascript VM If (1) fails, try fetch Local env variable from l2.env Try fetch root env variable from l2config.env Use the processed elements to create an httpie-go request Fetch response If necessary, write the last transaction to .json file","title":"Description"},{"location":"reference/cmdexec.html","text":"cmdexec \u00b6 import \"github.com/HexmosTech/lama2/cmdexec\" Package `cmdexec` provides a facility to execute l2 commands, stream output to stdout, while also providing ability to retrieve the command output as a string. Index \u00b6 func ExecCommand(cmdSlice []string, stdinBody string, apiDir string) (httpie.ExResponse, error) func GenerateChainCode(httpRespBody string) string func GetJSVm() *goja.Runtime func RunVMCode(jsCode string, vm *goja.Runtime) func ExecCommand \u00b6 func ExecCommand ( cmdSlice [] string , stdinBody string , apiDir string ) ( httpie . ExResponse , error ) ExecCommand changes directory to the given `apiDir` and then executes the command specified in `cmdStr` During command execution, ExecCommand streams output to stdout. Once execution finishes, previous CWD is restored, and the command output is returned as a string func GenerateChainCode \u00b6 func GenerateChainCode ( httpRespBody string ) string GenerateChainCode takes in an HTTP response body and comes up with some JS code to define the \"magic variable\" result. What does the code do? The result is stored as a JS object, if the input value can be parsed as JSON. Otherwise the value is stored as a simple string. func GetJSVm \u00b6 func GetJSVm () * goja . Runtime GetJSVm creates a new goja runtime instance with console.log enabled func RunVMCode \u00b6 func RunVMCode ( jsCode string , vm * goja . Runtime ) RunVMCode takes in a JS snippet as a string, executes the code in a JS VM, finally checks whether there are any errors, and if yes, logs the problem. Note: the vm runtime remains modified; so if you reuse the vm for other operations, the state from previous invocations carry over Generated by gomarkdoc","title":"Cmdexec"},{"location":"reference/cmdexec.html#cmdexec","text":"import \"github.com/HexmosTech/lama2/cmdexec\" Package `cmdexec` provides a facility to execute l2 commands, stream output to stdout, while also providing ability to retrieve the command output as a string.","title":"cmdexec"},{"location":"reference/cmdexec.html#index","text":"func ExecCommand(cmdSlice []string, stdinBody string, apiDir string) (httpie.ExResponse, error) func GenerateChainCode(httpRespBody string) string func GetJSVm() *goja.Runtime func RunVMCode(jsCode string, vm *goja.Runtime)","title":"Index"},{"location":"reference/cmdexec.html#func-execcommand","text":"func ExecCommand ( cmdSlice [] string , stdinBody string , apiDir string ) ( httpie . ExResponse , error ) ExecCommand changes directory to the given `apiDir` and then executes the command specified in `cmdStr` During command execution, ExecCommand streams output to stdout. Once execution finishes, previous CWD is restored, and the command output is returned as a string","title":"func ExecCommand"},{"location":"reference/cmdexec.html#func-generatechaincode","text":"func GenerateChainCode ( httpRespBody string ) string GenerateChainCode takes in an HTTP response body and comes up with some JS code to define the \"magic variable\" result. What does the code do? The result is stored as a JS object, if the input value can be parsed as JSON. Otherwise the value is stored as a simple string.","title":"func GenerateChainCode"},{"location":"reference/cmdexec.html#func-getjsvm","text":"func GetJSVm () * goja . Runtime GetJSVm creates a new goja runtime instance with console.log enabled","title":"func GetJSVm"},{"location":"reference/cmdexec.html#func-runvmcode","text":"func RunVMCode ( jsCode string , vm * goja . Runtime ) RunVMCode takes in a JS snippet as a string, executes the code in a JS VM, finally checks whether there are any errors, and if yes, logs the problem. Note: the vm runtime remains modified; so if you reuse the vm for other operations, the state from previous invocations carry over Generated by gomarkdoc","title":"func RunVMCode"},{"location":"reference/cmdgen.html","text":"cmdgen \u00b6 import \"github.com/HexmosTech/lama2/cmdgen\" Package `cmdgen` provides an API to generate API request commands (by default based on HTTPie) based on the parsed API file contents and the `l2` command invocation parameters Index \u00b6 func ConstructCommand(parsedInput *gabs.Container, o *lama2cmd.Opts) ([]string, string) func ConstructCommand \u00b6 func ConstructCommand ( parsedInput * gabs . Container , o * lama2cmd . Opts ) ([] string , string ) ConstructCommand extracts the HTTP verb, url and other API file inputs, figures out the type of target command and finally generates a string representing the generated command Generated by gomarkdoc","title":"Cmdgen"},{"location":"reference/cmdgen.html#cmdgen","text":"import \"github.com/HexmosTech/lama2/cmdgen\" Package `cmdgen` provides an API to generate API request commands (by default based on HTTPie) based on the parsed API file contents and the `l2` command invocation parameters","title":"cmdgen"},{"location":"reference/cmdgen.html#index","text":"func ConstructCommand(parsedInput *gabs.Container, o *lama2cmd.Opts) ([]string, string)","title":"Index"},{"location":"reference/cmdgen.html#func-constructcommand","text":"func ConstructCommand ( parsedInput * gabs . Container , o * lama2cmd . Opts ) ([] string , string ) ConstructCommand extracts the HTTP verb, url and other API file inputs, figures out the type of target command and finally generates a string representing the generated command Generated by gomarkdoc","title":"func ConstructCommand"},{"location":"reference/controller.html","text":"contoller \u00b6 import \"github.com/HexmosTech/lama2/controller\" Package controller coordinates all the other components in the `Lama2` project. The high level overview of command execution is easily understood from this package Index \u00b6 func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) func Process(version string) func ExecuteProcessorBlock \u00b6 func ExecuteProcessorBlock ( block * gabs . Container , vm * goja . Runtime ) func ExecuteRequestorBlock \u00b6 func ExecuteRequestorBlock ( block * gabs . Container , vm * goja . Runtime , opts * lama2cmd . Opts , dir string ) httpie . ExResponse func GetParsedAPIBlocks \u00b6 func GetParsedAPIBlocks ( parsedAPI * gabs . Container ) [] * gabs . Container func HandleParsedFile \u00b6 func HandleParsedFile ( parsedAPI * gabs . Container , o * lama2cmd . Opts , dir string ) func Process \u00b6 func Process ( version string ) Process initiates the following tasks in the given order: 1. Parse command line arguments 2. Read API file contents 3. Expand environment variables in API file 4. Parse the API contents 5. Generate API request command 6. Execute command & retrieve results 7. Optionally, post-process and write results to a JSON file Generated by gomarkdoc","title":"Controller"},{"location":"reference/controller.html#contoller","text":"import \"github.com/HexmosTech/lama2/controller\" Package controller coordinates all the other components in the `Lama2` project. The high level overview of command execution is easily understood from this package","title":"contoller"},{"location":"reference/controller.html#index","text":"func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) func Process(version string)","title":"Index"},{"location":"reference/controller.html#func-executeprocessorblock","text":"func ExecuteProcessorBlock ( block * gabs . Container , vm * goja . Runtime )","title":"func ExecuteProcessorBlock"},{"location":"reference/controller.html#func-executerequestorblock","text":"func ExecuteRequestorBlock ( block * gabs . Container , vm * goja . Runtime , opts * lama2cmd . Opts , dir string ) httpie . ExResponse","title":"func ExecuteRequestorBlock"},{"location":"reference/controller.html#func-getparsedapiblocks","text":"func GetParsedAPIBlocks ( parsedAPI * gabs . Container ) [] * gabs . Container","title":"func GetParsedAPIBlocks"},{"location":"reference/controller.html#func-handleparsedfile","text":"func HandleParsedFile ( parsedAPI * gabs . Container , o * lama2cmd . Opts , dir string )","title":"func HandleParsedFile"},{"location":"reference/controller.html#func-process","text":"func Process ( version string ) Process initiates the following tasks in the given order: 1. Parse command line arguments 2. Read API file contents 3. Expand environment variables in API file 4. Parse the API contents 5. Generate API request command 6. Execute command & retrieve results 7. Optionally, post-process and write results to a JSON file Generated by gomarkdoc","title":"func Process"},{"location":"reference/grammar.html","text":"Grammar \u00b6 What follows is a rough rendition of the Lama2 grammar, followed by a visual exploration of the grammar in the railroad diagram format (thanks to Railroad Diagram Generator ) EBNF Description \u00b6 Lama2File ::= (Proceessor Separator)? Requestor (Separator Processor Separator Requestor)* Separator ::= `^---$` Processor ::= `(?!(get|post|head|put|delete|connect|trace|patch))` Requestor ::= HTTPVerb Multipart? TheURL Details? HTTPVerb ::= \"get\" | \"head\" | \"post\" | \"put\" | \"delete\" | \"connect\" | \"trace\" | \"patch\" Multipart ::= \"multipart\" TheURL ::= \"http\" \"s\"? \"://\" [A-Za-z0-9-._~:/?#[@!$&'()*+,;%=]+ /* ws: explicit */ Details ::= HeaderData | DataHeader HeaderData ::= Headers DataInput? DataHeader ::= DataInput Headers? Headers ::= HeaderPair HeaderPair* HeaderPair ::= (QuotedString | Unquoted) \":\" (QuotedString | Unquoted) DataInput ::= VarJSON | JSONType VarJSON ::= VarJSONPair VarJSONPair* FilesPair? VarJSONPair ::= (QuotedString | VarJSONUnquoted) \"=\" (QuotedString | VarJSONUnquoted) FilesPair ::= FilesPair FilesPair* FilesPair ::= (QuotedString | FilesUnquoted) \"@\" (QuotedString | FilesUnquoted) VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ QuotedString ::= ['\"] Char* ['\"] Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~-]+ /* ws: explicit */ JSONType ::= ComplexType | PrimitiveType ComplexType ::= List | Map PrimitiveType ::= Null | Boolean | QuotedString | Number Map ::= \"{\" Pair? (Pair \",\")* \"}\" List ::= \"[\" JSONType? (JSONType \",\")* \"]\" Pair ::= QuotedString \":\" JSONType Boolean ::= \"true\" | \"false\" Null ::= \"null\" Number ::= Integer Fraction? Exponent? Exponent ::= [eE] Sign? Digits Fraction ::= \".\" Digits Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 IntegerRule1 ::= Digit IntegerRule2 ::= OneNine Digits IntegerRule3 ::= Sign IntegerRule1 IntegerRule4 ::= Sign IntegerRule2 Digits ::= Digit Digit* Digit ::= \"0\"? OneNine OneNine ::= [1-9] Sign ::= [-+] Railroad Diagram \u00b6 ::-moz-selection { color: #FFFCF0; background: #0F0C00; } ::selection { color: #FFFCF0; background: #0F0C00; } .ebnf a, .grammar a { text-decoration: none; } .ebnf a:hover, .grammar a:hover { color: #050400; text-decoration: underline; } .signature { color: #806600; font-size: 11px; text-align: right; } body { font: normal 12px Verdana, sans-serif; color: #0F0C00; background: #FFFCF0; } a:link, a:visited { color: #0F0C00; } a:link.signature, a:visited.signature { color: #806600; } a.button, #tabs li a { padding: 0.25em 0.5em; border: 1px solid #806600; background: #F1E8C6; color: #806600; text-decoration: none; font-weight: bold; } a.button:hover, #tabs li a:hover { color: #050400; background: #FFF6D1; border-color: #050400; } #tabs { padding: 3px 10px; margin-left: 0; margin-top: 58px; border-bottom: 1px solid #0F0C00; } #tabs li { list-style: none; margin-left: 5px; display: inline; } #tabs li a { border-bottom: 1px solid #0F0C00; } #tabs li a.active { color: #0F0C00; background: #FFFCF0; border-color: #0F0C00; border-bottom: 1px solid #FFFCF0; outline: none; } #divs div { display: none; overflow:auto; } #divs div.active { display: block; } #text { border-color: #806600; background: #FFFEFA; color: #050400; } .small { vertical-align: top; text-align: right; font-size: 9px; font-weight: normal; line-height: 120%; } td.small { padding-top: 0px; } .hidden { visibility: hidden; } td:hover .hidden { visibility: visible; } div.download { display: none; background: #FFFCF0; position: absolute; right: 34px; top: 94px; padding: 10px; border: 1px dotted #0F0C00; } #divs div.ebnf, .ebnf code { display: block; padding: 10px; background: #FFF6D1; width: 992px; } #divs div.grammar { display: block; padding-left: 16px; padding-top: 2px; padding-bottom: 2px; background: #FFF6D1; } pre { margin: 0px; } .ebnf div { padding-left: 13ch; text-indent: -13ch; } .ebnf code, .grammar code, textarea, pre { font:12px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; } tr.option-line td:first-child { text-align: right } tr.option-text td { padding-bottom: 10px } table.palette { border-top: 1px solid #050400; border-right: 1px solid #050400; margin-bottom: 4px } td.palette { border-bottom: 1px solid #050400; border-left: 1px solid #050400; } a.palette { padding: 2px 3px 2px 10px; text-decoration: none; } .palette { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; } @namespace \"http://www.w3.org/2000/svg\"; .line {fill: none; stroke: #332900; stroke-width: 1;} .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2;} .thin-line {stroke: #1F1800; shape-rendering: crispEdges} .filled {fill: #332900; stroke: none;} text.terminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #141000; font-weight: bold; } text.nonterminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1A1400; font-weight: normal; } text.regexp {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1F1800; font-weight: normal; } rect, circle, polygon {fill: #332900; stroke: #332900;} rect.terminal {fill: #FFDB4D; stroke: #332900; stroke-width: 1;} rect.nonterminal {fill: #FFEC9E; stroke: #332900; stroke-width: 1;} rect.text {fill: none; stroke: none;} polygon.regexp {fill: #FFF4C7; stroke: #332900; stroke-width: 1;} Lama2File: Proceessor Separator Requestor Separator Processor Separator Lama2File ::= ( Proceessor Separator )? Requestor ( Separator Processor Separator Requestor )* no references Separator: --- Separator ::= '---' referenced by: Lama2File Processor: (?!(get|post|head|put|delete|connect|trace|patch)) Processor ::= '(?!(get|post|head|put|delete|connect|trace|patch))' referenced by: Lama2File Requestor: HTTPVerb Multipart TheURL Details Requestor ::= HTTPVerb Multipart ? TheURL Details ? referenced by: Lama2File HTTPVerb: get head post put delete connect trace patch HTTPVerb ::= 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'trace' | 'patch' referenced by: Requestor Multipart: multipart Multipart ::= 'multipart' referenced by: Requestor TheURL: http s :// [A-Z] [a-z] [0-9] - . _ ~ : / ? # [ @ ! $ & ' ( ) * + , ; % = TheURL ::= 'http' 's'? '://' [A-Za-z0-9._~:/?[@!$&'()*+,;%=#x2D#x23]+ /* ws: explicit */ referenced by: Requestor Details: HeaderData DataHeader Details ::= HeaderData | DataHeader referenced by: Requestor HeaderData: Headers DataInput HeaderData ::= Headers DataInput ? referenced by: Details DataHeader: DataInput Headers DataHeader ::= DataInput Headers ? referenced by: Details Headers: HeaderPair Headers ::= HeaderPair HeaderPair * referenced by: DataHeader HeaderData HeaderPair: QuotedString Unquoted : QuotedString Unquoted HeaderPair ::= ( QuotedString | Unquoted ) ':' ( QuotedString | Unquoted ) referenced by: Headers DataInput: VarJSON JSONType DataInput ::= VarJSON | JSONType referenced by: DataHeader HeaderData VarJSON: VarJSONPair FilesPair VarJSON ::= VarJSONPair VarJSONPair * FilesPair ? referenced by: DataInput VarJSONPair: QuotedString VarJSONUnquoted = QuotedString VarJSONUnquoted VarJSONPair ::= ( QuotedString | VarJSONUnquoted ) '=' ( QuotedString | VarJSONUnquoted ) referenced by: VarJSON FilesPair: FilesPair QuotedString FilesUnquoted @ QuotedString FilesUnquoted FilesPair ::= FilesPair FilesPair * | ( QuotedString | FilesUnquoted ) '@' ( QuotedString | FilesUnquoted ) referenced by: FilesPair VarJSON VarJSONUnquoted: @ [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: VarJSONPair FilesUnquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: FilesPair QuotedString: ' \" Char ' \" QuotedString ::= ['\"] Char * ['\"] referenced by: FilesPair HeaderPair Pair PrimitiveType VarJSONPair Unquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < = > ? ^ _ ` | ~ - Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~#x2D]+ /* ws: explicit */ referenced by: HeaderPair JSONType: ComplexType PrimitiveType JSONType ::= ComplexType | PrimitiveType referenced by: DataInput List Pair ComplexType: List Map ComplexType ::= List | Map referenced by: JSONType PrimitiveType: Null Boolean QuotedString Number PrimitiveType ::= Null | Boolean | QuotedString | Number referenced by: JSONType Map: { Pair Pair , } Map ::= '{' Pair ? ( Pair ',' )* '}' referenced by: ComplexType List: [ JSONType JSONType , ] List ::= '[' JSONType ? ( JSONType ',' )* ']' referenced by: ComplexType Pair: QuotedString : JSONType Pair ::= QuotedString ':' JSONType referenced by: Map Boolean: true false Boolean ::= 'true' | 'false' referenced by: PrimitiveType Null: null Null ::= 'null' referenced by: PrimitiveType Number: Integer Fraction Exponent Number ::= Integer Fraction ? Exponent ? referenced by: PrimitiveType Exponent: e E Sign Digits Exponent ::= [eE] Sign ? Digits referenced by: Number Fraction: . Digits Fraction ::= '.' Digits referenced by: Number Integer: IntegerRule4 IntegerRule3 IntegerRule2 IntegerRule1 Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 referenced by: Number IntegerRule1: Digit IntegerRule1 ::= Digit referenced by: Integer IntegerRule3 IntegerRule2: OneNine Digits IntegerRule2 ::= OneNine Digits referenced by: Integer IntegerRule4 IntegerRule3: Sign IntegerRule1 IntegerRule3 ::= Sign IntegerRule1 referenced by: Integer IntegerRule4: Sign IntegerRule2 IntegerRule4 ::= Sign IntegerRule2 referenced by: Integer Digits: Digit Digits ::= Digit Digit * referenced by: Exponent Fraction IntegerRule2 Digit: 0 OneNine Digit ::= '0'? OneNine referenced by: Digits IntegerRule1 OneNine: [1-9] OneNine ::= [1-9] referenced by: Digit IntegerRule2 Sign: - + Sign ::= [-+] referenced by: Exponent IntegerRule3 IntegerRule4 ... generated by RR - Railroad Diagram Generator R R","title":"Formal Grammar"},{"location":"reference/grammar.html#grammar","text":"What follows is a rough rendition of the Lama2 grammar, followed by a visual exploration of the grammar in the railroad diagram format (thanks to Railroad Diagram Generator )","title":"Grammar"},{"location":"reference/grammar.html#ebnf-description","text":"Lama2File ::= (Proceessor Separator)? Requestor (Separator Processor Separator Requestor)* Separator ::= `^---$` Processor ::= `(?!(get|post|head|put|delete|connect|trace|patch))` Requestor ::= HTTPVerb Multipart? TheURL Details? HTTPVerb ::= \"get\" | \"head\" | \"post\" | \"put\" | \"delete\" | \"connect\" | \"trace\" | \"patch\" Multipart ::= \"multipart\" TheURL ::= \"http\" \"s\"? \"://\" [A-Za-z0-9-._~:/?#[@!$&'()*+,;%=]+ /* ws: explicit */ Details ::= HeaderData | DataHeader HeaderData ::= Headers DataInput? DataHeader ::= DataInput Headers? Headers ::= HeaderPair HeaderPair* HeaderPair ::= (QuotedString | Unquoted) \":\" (QuotedString | Unquoted) DataInput ::= VarJSON | JSONType VarJSON ::= VarJSONPair VarJSONPair* FilesPair? VarJSONPair ::= (QuotedString | VarJSONUnquoted) \"=\" (QuotedString | VarJSONUnquoted) FilesPair ::= FilesPair FilesPair* FilesPair ::= (QuotedString | FilesUnquoted) \"@\" (QuotedString | FilesUnquoted) VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ QuotedString ::= ['\"] Char* ['\"] Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~-]+ /* ws: explicit */ JSONType ::= ComplexType | PrimitiveType ComplexType ::= List | Map PrimitiveType ::= Null | Boolean | QuotedString | Number Map ::= \"{\" Pair? (Pair \",\")* \"}\" List ::= \"[\" JSONType? (JSONType \",\")* \"]\" Pair ::= QuotedString \":\" JSONType Boolean ::= \"true\" | \"false\" Null ::= \"null\" Number ::= Integer Fraction? Exponent? Exponent ::= [eE] Sign? Digits Fraction ::= \".\" Digits Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 IntegerRule1 ::= Digit IntegerRule2 ::= OneNine Digits IntegerRule3 ::= Sign IntegerRule1 IntegerRule4 ::= Sign IntegerRule2 Digits ::= Digit Digit* Digit ::= \"0\"? OneNine OneNine ::= [1-9] Sign ::= [-+]","title":"EBNF Description"},{"location":"reference/grammar.html#railroad-diagram","text":"::-moz-selection { color: #FFFCF0; background: #0F0C00; } ::selection { color: #FFFCF0; background: #0F0C00; } .ebnf a, .grammar a { text-decoration: none; } .ebnf a:hover, .grammar a:hover { color: #050400; text-decoration: underline; } .signature { color: #806600; font-size: 11px; text-align: right; } body { font: normal 12px Verdana, sans-serif; color: #0F0C00; background: #FFFCF0; } a:link, a:visited { color: #0F0C00; } a:link.signature, a:visited.signature { color: #806600; } a.button, #tabs li a { padding: 0.25em 0.5em; border: 1px solid #806600; background: #F1E8C6; color: #806600; text-decoration: none; font-weight: bold; } a.button:hover, #tabs li a:hover { color: #050400; background: #FFF6D1; border-color: #050400; } #tabs { padding: 3px 10px; margin-left: 0; margin-top: 58px; border-bottom: 1px solid #0F0C00; } #tabs li { list-style: none; margin-left: 5px; display: inline; } #tabs li a { border-bottom: 1px solid #0F0C00; } #tabs li a.active { color: #0F0C00; background: #FFFCF0; border-color: #0F0C00; border-bottom: 1px solid #FFFCF0; outline: none; } #divs div { display: none; overflow:auto; } #divs div.active { display: block; } #text { border-color: #806600; background: #FFFEFA; color: #050400; } .small { vertical-align: top; text-align: right; font-size: 9px; font-weight: normal; line-height: 120%; } td.small { padding-top: 0px; } .hidden { visibility: hidden; } td:hover .hidden { visibility: visible; } div.download { display: none; background: #FFFCF0; position: absolute; right: 34px; top: 94px; padding: 10px; border: 1px dotted #0F0C00; } #divs div.ebnf, .ebnf code { display: block; padding: 10px; background: #FFF6D1; width: 992px; } #divs div.grammar { display: block; padding-left: 16px; padding-top: 2px; padding-bottom: 2px; background: #FFF6D1; } pre { margin: 0px; } .ebnf div { padding-left: 13ch; text-indent: -13ch; } .ebnf code, .grammar code, textarea, pre { font:12px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; } tr.option-line td:first-child { text-align: right } tr.option-text td { padding-bottom: 10px } table.palette { border-top: 1px solid #050400; border-right: 1px solid #050400; margin-bottom: 4px } td.palette { border-bottom: 1px solid #050400; border-left: 1px solid #050400; } a.palette { padding: 2px 3px 2px 10px; text-decoration: none; } .palette { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; } @namespace \"http://www.w3.org/2000/svg\"; .line {fill: none; stroke: #332900; stroke-width: 1;} .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2;} .thin-line {stroke: #1F1800; shape-rendering: crispEdges} .filled {fill: #332900; stroke: none;} text.terminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #141000; font-weight: bold; } text.nonterminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1A1400; font-weight: normal; } text.regexp {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1F1800; font-weight: normal; } rect, circle, polygon {fill: #332900; stroke: #332900;} rect.terminal {fill: #FFDB4D; stroke: #332900; stroke-width: 1;} rect.nonterminal {fill: #FFEC9E; stroke: #332900; stroke-width: 1;} rect.text {fill: none; stroke: none;} polygon.regexp {fill: #FFF4C7; stroke: #332900; stroke-width: 1;} Lama2File: Proceessor Separator Requestor Separator Processor Separator Lama2File ::= ( Proceessor Separator )? Requestor ( Separator Processor Separator Requestor )* no references Separator: --- Separator ::= '---' referenced by: Lama2File Processor: (?!(get|post|head|put|delete|connect|trace|patch)) Processor ::= '(?!(get|post|head|put|delete|connect|trace|patch))' referenced by: Lama2File Requestor: HTTPVerb Multipart TheURL Details Requestor ::= HTTPVerb Multipart ? TheURL Details ? referenced by: Lama2File HTTPVerb: get head post put delete connect trace patch HTTPVerb ::= 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'trace' | 'patch' referenced by: Requestor Multipart: multipart Multipart ::= 'multipart' referenced by: Requestor TheURL: http s :// [A-Z] [a-z] [0-9] - . _ ~ : / ? # [ @ ! $ & ' ( ) * + , ; % = TheURL ::= 'http' 's'? '://' [A-Za-z0-9._~:/?[@!$&'()*+,;%=#x2D#x23]+ /* ws: explicit */ referenced by: Requestor Details: HeaderData DataHeader Details ::= HeaderData | DataHeader referenced by: Requestor HeaderData: Headers DataInput HeaderData ::= Headers DataInput ? referenced by: Details DataHeader: DataInput Headers DataHeader ::= DataInput Headers ? referenced by: Details Headers: HeaderPair Headers ::= HeaderPair HeaderPair * referenced by: DataHeader HeaderData HeaderPair: QuotedString Unquoted : QuotedString Unquoted HeaderPair ::= ( QuotedString | Unquoted ) ':' ( QuotedString | Unquoted ) referenced by: Headers DataInput: VarJSON JSONType DataInput ::= VarJSON | JSONType referenced by: DataHeader HeaderData VarJSON: VarJSONPair FilesPair VarJSON ::= VarJSONPair VarJSONPair * FilesPair ? referenced by: DataInput VarJSONPair: QuotedString VarJSONUnquoted = QuotedString VarJSONUnquoted VarJSONPair ::= ( QuotedString | VarJSONUnquoted ) '=' ( QuotedString | VarJSONUnquoted ) referenced by: VarJSON FilesPair: FilesPair QuotedString FilesUnquoted @ QuotedString FilesUnquoted FilesPair ::= FilesPair FilesPair * | ( QuotedString | FilesUnquoted ) '@' ( QuotedString | FilesUnquoted ) referenced by: FilesPair VarJSON VarJSONUnquoted: @ [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: VarJSONPair FilesUnquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: FilesPair QuotedString: ' \" Char ' \" QuotedString ::= ['\"] Char * ['\"] referenced by: FilesPair HeaderPair Pair PrimitiveType VarJSONPair Unquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < = > ? ^ _ ` | ~ - Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~#x2D]+ /* ws: explicit */ referenced by: HeaderPair JSONType: ComplexType PrimitiveType JSONType ::= ComplexType | PrimitiveType referenced by: DataInput List Pair ComplexType: List Map ComplexType ::= List | Map referenced by: JSONType PrimitiveType: Null Boolean QuotedString Number PrimitiveType ::= Null | Boolean | QuotedString | Number referenced by: JSONType Map: { Pair Pair , } Map ::= '{' Pair ? ( Pair ',' )* '}' referenced by: ComplexType List: [ JSONType JSONType , ] List ::= '[' JSONType ? ( JSONType ',' )* ']' referenced by: ComplexType Pair: QuotedString : JSONType Pair ::= QuotedString ':' JSONType referenced by: Map Boolean: true false Boolean ::= 'true' | 'false' referenced by: PrimitiveType Null: null Null ::= 'null' referenced by: PrimitiveType Number: Integer Fraction Exponent Number ::= Integer Fraction ? Exponent ? referenced by: PrimitiveType Exponent: e E Sign Digits Exponent ::= [eE] Sign ? Digits referenced by: Number Fraction: . Digits Fraction ::= '.' Digits referenced by: Number Integer: IntegerRule4 IntegerRule3 IntegerRule2 IntegerRule1 Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 referenced by: Number IntegerRule1: Digit IntegerRule1 ::= Digit referenced by: Integer IntegerRule3 IntegerRule2: OneNine Digits IntegerRule2 ::= OneNine Digits referenced by: Integer IntegerRule4 IntegerRule3: Sign IntegerRule1 IntegerRule3 ::= Sign IntegerRule1 referenced by: Integer IntegerRule4: Sign IntegerRule2 IntegerRule4 ::= Sign IntegerRule2 referenced by: Integer Digits: Digit Digits ::= Digit Digit * referenced by: Exponent Fraction IntegerRule2 Digit: 0 OneNine Digit ::= '0'? OneNine referenced by: Digits IntegerRule1 OneNine: [1-9] OneNine ::= [1-9] referenced by: Digit IntegerRule2 Sign: - + Sign ::= [-+] referenced by: Exponent IntegerRule3 IntegerRule4 ... generated by RR - Railroad Diagram Generator R R","title":"Railroad Diagram"},{"location":"reference/lama2cmd.html","text":"lama2cmd \u00b6 import \"github.com/HexmosTech/lama2/lama2cmd\" Package `lama2cmd` provides CLI argument parsing facilities. It hosts the `Opts` structure to record user intentions Index \u00b6 func ArgParsing(o *Opts, version string) type Opts func GetAndValidateCmd(ipArgs []string) *Opts func ArgParsing \u00b6 func ArgParsing ( o * Opts , version string ) type Opts \u00b6 The Opts structure stores user preferences, and is used throughout the module to make various decisions. type Opts struct { Output string `short:\"o\" long:\"output\" description:\"Path to output JSON file to store logs, headers and result\"` Verbose [] bool `short:\"v\" long:\"verbose\" description:\"Show verbose debug information\"` Prettify bool `short:\"b\" long:\"prettify\" description:\"Prettify specified .l2 file\"` // Sort bool `short:\"s\" long:\"sort\" description:\"Sort specification into recommended order\"` Convert string `short:\"c\" long:\"convert\" description:\"Generate code in given language and library (ex: python.requests); reference: tinyurl.com/l2codegen\"` Nocolor bool `short:\"n\" long:\"nocolor\" description:\"Disable color in httpie output\"` Update bool `short:\"u\" long:\"update\" description:\"Update l2 binary to the latest released version (Linux/MacOS only)\"` PostmanFile string `short:\"p\" long:\"postmanfile\" description:\"JSON export from Postman (Settings -> Data -> Export Data)\"` LamaDir string `short:\"l\" long:\"lama2dir\" description:\"Output directory to put .l2 files after conversion from Postman format\"` Help bool `short:\"h\" long:\"help\" group:\"AddHelp\" description:\"Usage help for Lama2\"` Env bool `short:\"e\" long:\"env\" description:\"Get a JSON of environment variables\"` Version bool `long:\"version\" description:\"Print Lama2 binary version\"` Positional struct { LamaAPIFile string } `positional-args:\"yes\"` } func GetAndValidateCmd \u00b6 func GetAndValidateCmd ( ipArgs [] string ) * Opts GetAndValidateCmd takes in the user's CLI input, and checks for validity. If not OK, displays a help message in stdout. Otherwise, fills the Opts structure and returns it Moreover, based on user input, the outputManager gets configured (whether user prefers trace/debug/info level) Generated by gomarkdoc","title":"Lama2cmd"},{"location":"reference/lama2cmd.html#lama2cmd","text":"import \"github.com/HexmosTech/lama2/lama2cmd\" Package `lama2cmd` provides CLI argument parsing facilities. It hosts the `Opts` structure to record user intentions","title":"lama2cmd"},{"location":"reference/lama2cmd.html#index","text":"func ArgParsing(o *Opts, version string) type Opts func GetAndValidateCmd(ipArgs []string) *Opts","title":"Index"},{"location":"reference/lama2cmd.html#func-argparsing","text":"func ArgParsing ( o * Opts , version string )","title":"func ArgParsing"},{"location":"reference/lama2cmd.html#type-opts","text":"The Opts structure stores user preferences, and is used throughout the module to make various decisions. type Opts struct { Output string `short:\"o\" long:\"output\" description:\"Path to output JSON file to store logs, headers and result\"` Verbose [] bool `short:\"v\" long:\"verbose\" description:\"Show verbose debug information\"` Prettify bool `short:\"b\" long:\"prettify\" description:\"Prettify specified .l2 file\"` // Sort bool `short:\"s\" long:\"sort\" description:\"Sort specification into recommended order\"` Convert string `short:\"c\" long:\"convert\" description:\"Generate code in given language and library (ex: python.requests); reference: tinyurl.com/l2codegen\"` Nocolor bool `short:\"n\" long:\"nocolor\" description:\"Disable color in httpie output\"` Update bool `short:\"u\" long:\"update\" description:\"Update l2 binary to the latest released version (Linux/MacOS only)\"` PostmanFile string `short:\"p\" long:\"postmanfile\" description:\"JSON export from Postman (Settings -> Data -> Export Data)\"` LamaDir string `short:\"l\" long:\"lama2dir\" description:\"Output directory to put .l2 files after conversion from Postman format\"` Help bool `short:\"h\" long:\"help\" group:\"AddHelp\" description:\"Usage help for Lama2\"` Env bool `short:\"e\" long:\"env\" description:\"Get a JSON of environment variables\"` Version bool `long:\"version\" description:\"Print Lama2 binary version\"` Positional struct { LamaAPIFile string } `positional-args:\"yes\"` }","title":"type Opts"},{"location":"reference/lama2cmd.html#func-getandvalidatecmd","text":"func GetAndValidateCmd ( ipArgs [] string ) * Opts GetAndValidateCmd takes in the user's CLI input, and checks for validity. If not OK, displays a help message in stdout. Otherwise, fills the Opts structure and returns it Moreover, based on user input, the outputManager gets configured (whether user prefers trace/debug/info level) Generated by gomarkdoc","title":"func GetAndValidateCmd"},{"location":"reference/outputmanager.html","text":"outputmanager \u00b6 import \"github.com/HexmosTech/lama2/outputManager\" Package `outputmanager` provides facilities for controlling the logging library as well as capabilities to post-process API execution results (such as store results as a JSON file) Index \u00b6 Variables func ConfigureZeroLog(level string) func ResponseToJSON(resp httpie.ExResponse) (*gabs.Container, error) func WriteJSONOutput(resp httpie.ExResponse, targetPath string) Variables \u00b6 LogBuff is used to append various log statements into memory. If the user toggles the `Output (-o)` option, then the contents of LogBuff is pushed into a JSON file var LogBuff bytes . Buffer func ConfigureZeroLog \u00b6 func ConfigureZeroLog ( level string ) ConfigureZeroLog provides global log level setting. By default, ZeroLog uses the DEBUG level; however, the function makes the desired level more explicit func ResponseToJSON \u00b6 func ResponseToJSON ( resp httpie . ExResponse ) ( * gabs . Container , error ) func WriteJSONOutput \u00b6 func WriteJSONOutput ( resp httpie . ExResponse , targetPath string ) WriteJSONOutput is primarily built for helping with Extension/Integration building with external tools. Extension writers may simply call `l2 -n -o /tmp/lama2.json ...` to invoke WriteJSONOutput; the generated json file contains three keys: `logs`, `headers`, `body` Generated by gomarkdoc","title":"Outputmanager"},{"location":"reference/outputmanager.html#outputmanager","text":"import \"github.com/HexmosTech/lama2/outputManager\" Package `outputmanager` provides facilities for controlling the logging library as well as capabilities to post-process API execution results (such as store results as a JSON file)","title":"outputmanager"},{"location":"reference/outputmanager.html#index","text":"Variables func ConfigureZeroLog(level string) func ResponseToJSON(resp httpie.ExResponse) (*gabs.Container, error) func WriteJSONOutput(resp httpie.ExResponse, targetPath string)","title":"Index"},{"location":"reference/outputmanager.html#variables","text":"LogBuff is used to append various log statements into memory. If the user toggles the `Output (-o)` option, then the contents of LogBuff is pushed into a JSON file var LogBuff bytes . Buffer","title":"Variables"},{"location":"reference/outputmanager.html#func-configurezerolog","text":"func ConfigureZeroLog ( level string ) ConfigureZeroLog provides global log level setting. By default, ZeroLog uses the DEBUG level; however, the function makes the desired level more explicit","title":"func ConfigureZeroLog"},{"location":"reference/outputmanager.html#func-responsetojson","text":"func ResponseToJSON ( resp httpie . ExResponse ) ( * gabs . Container , error )","title":"func ResponseToJSON"},{"location":"reference/outputmanager.html#func-writejsonoutput","text":"func WriteJSONOutput ( resp httpie . ExResponse , targetPath string ) WriteJSONOutput is primarily built for helping with Extension/Integration building with external tools. Extension writers may simply call `l2 -n -o /tmp/lama2.json ...` to invoke WriteJSONOutput; the generated json file contains three keys: `logs`, `headers`, `body` Generated by gomarkdoc","title":"func WriteJSONOutput"},{"location":"reference/parser.html","text":"parser \u00b6 import \"github.com/HexmosTech/lama2/parser\" The `parser` package provides primitives that help with writing recursive descent parsers. This version is a golang port of the original Python implementation from https://tinyurl.com/rdescent The `Parser` struct is supposed to be extended to support parsing a new language. Take a look at `lama2parser.go` for an example. Essentially the actual parsing begins from the `Start()` method. Index \u00b6 Variables func CustomPairMerge(destination, source interface{}) interface{} type Lama2Parser func NewLama2Parser() *Lama2Parser func (p *Lama2Parser) AnyType() (*gabs.Container, error) func (p *Lama2Parser) Boolean() (*gabs.Container, error) func (p *Lama2Parser) ComplexType() (*gabs.Container, error) func (p *Lama2Parser) DataHeader() (*gabs.Container, error) func (p *Lama2Parser) DataInput() (*gabs.Container, error) func (p *Lama2Parser) Details() (*gabs.Container, error) func (p *Lama2Parser) Digit() (*gabs.Container, error) func (p *Lama2Parser) Digits() (*gabs.Container, error) func (p *Lama2Parser) Exponent() (*gabs.Container, error) func (p *Lama2Parser) FilesPair() (*gabs.Container, error) func (p *Lama2Parser) FilesUnquoted() (*gabs.Container, error) func (p *Lama2Parser) Fraction() (*gabs.Container, error) func (p *Lama2Parser) FractionRule1() (*gabs.Container, error) func (p *Lama2Parser) HTTPVerb() (*gabs.Container, error) func (p *Lama2Parser) HeaderData() (*gabs.Container, error) func (p *Lama2Parser) HeaderPair() (*gabs.Container, error) func (p *Lama2Parser) Headers() (*gabs.Container, error) func (p *Lama2Parser) Integer() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule1() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule2() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule3() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule4() (*gabs.Container, error) func (p *Lama2Parser) Lama2File() (*gabs.Container, error) func (p *Lama2Parser) List() (*gabs.Container, error) func (p *Lama2Parser) Map() (*gabs.Container, error) func (p *Lama2Parser) Multipart() (*gabs.Container, error) func (p *Lama2Parser) Null() (*gabs.Container, error) func (p *Lama2Parser) Number() (*gabs.Container, error) func (p *Lama2Parser) OneNine() (*gabs.Container, error) func (p *Lama2Parser) Pair() (*gabs.Container, error) func (p *Lama2Parser) PrimitiveType() (*gabs.Container, error) func (p *Lama2Parser) Processor() (*gabs.Container, error) func (p *Lama2Parser) QuotedString() (*gabs.Container, error) func (p *Lama2Parser) Requester() (*gabs.Container, error) func (p *Lama2Parser) Separator() (*gabs.Container, error) func (p *Lama2Parser) Sign() (*gabs.Container, error) func (p *Lama2Parser) Start() (*gabs.Container, error) func (p *Lama2Parser) TheURL() (*gabs.Container, error) func (p *Lama2Parser) Unquoted() (*gabs.Container, error) func (p *Lama2Parser) VarJSON() (*gabs.Container, error) func (p *Lama2Parser) VarJSONPair() (*gabs.Container, error) func (p *Lama2Parser) VarJSONUnquoted() (*gabs.Container, error) type MinimalParser type Parser func (p *Parser) Char() (rune, error) func (p *Parser) CharClass(charClass string) (rune, error) func (p *Parser) Init() func (p *Parser) Keyword(kw string, eatWsStart bool, eatWsEnd bool, caseInsensitive bool) ([]rune, error) func (p *Parser) LookAhead(rules []string) bool func (p *Parser) Match(rules []string) (*gabs.Container, error) func (p *Parser) MatchUntil(end string) (*gabs.Container, error) func (p *Parser) Parse(text string) (*gabs.Container, error) func (p *Parser) SetText(text string) func (p *Parser) SplitCharRanges(charClass string) ([]string, error) func (p *Parser) Start() *gabs.Container Variables \u00b6 var DataInputType string func CustomPairMerge \u00b6 func CustomPairMerge ( destination , source interface {}) interface {} CustomPairMerge uses a gabs feature to deal with merge conflicts. More here: https://github.com/HexmosTech/gabs/blob/master/gabs.go#L511 type Lama2Parser \u00b6 type Lama2Parser struct { * Parser Context map [ string ] bool MarkRange map [ string ] int } func NewLama2Parser \u00b6 func NewLama2Parser () * Lama2Parser NewLama2Parser creates a new Lama2Parser and initializes it properly func (*Lama2Parser) AnyType \u00b6 func ( p * Lama2Parser ) AnyType () ( * gabs . Container , error ) AnyType is the top-most element of a JSON structure It consists of Complex and Primitive Types func (*Lama2Parser) Boolean \u00b6 func ( p * Lama2Parser ) Boolean () ( * gabs . Container , error ) func (*Lama2Parser) ComplexType \u00b6 func ( p * Lama2Parser ) ComplexType () ( * gabs . Container , error ) func (*Lama2Parser) DataHeader \u00b6 func ( p * Lama2Parser ) DataHeader () ( * gabs . Container , error ) func (*Lama2Parser) DataInput \u00b6 func ( p * Lama2Parser ) DataInput () ( * gabs . Container , error ) func (*Lama2Parser) Details \u00b6 func ( p * Lama2Parser ) Details () ( * gabs . Container , error ) func (*Lama2Parser) Digit \u00b6 func ( p * Lama2Parser ) Digit () ( * gabs . Container , error ) func (*Lama2Parser) Digits \u00b6 func ( p * Lama2Parser ) Digits () ( * gabs . Container , error ) func (*Lama2Parser) Exponent \u00b6 func ( p * Lama2Parser ) Exponent () ( * gabs . Container , error ) An Exponent consists of mandatory 'e' or 'E', optional Sign, followed by Digits func (*Lama2Parser) FilesPair \u00b6 func ( p * Lama2Parser ) FilesPair () ( * gabs . Container , error ) FilesPair tries to match key and value separated by `@`. The key and value can either be a quoted string, or an unquoted Files Unquoted String. If there is no match for either, a ParseError is returned. func (*Lama2Parser) FilesUnquoted \u00b6 func ( p * Lama2Parser ) FilesUnquoted () ( * gabs . Container , error ) FilesUnquoted matches a string of characters other than `@` and returns them as a String func (*Lama2Parser) Fraction \u00b6 func ( p * Lama2Parser ) Fraction () ( * gabs . Container , error ) func (*Lama2Parser) FractionRule1 \u00b6 func ( p * Lama2Parser ) FractionRule1 () ( * gabs . Container , error ) A Fraction consists of mandatory \".\" (dot), followed by Digits. func (*Lama2Parser) HTTPVerb \u00b6 func ( p * Lama2Parser ) HTTPVerb () ( * gabs . Container , error ) func (*Lama2Parser) HeaderData \u00b6 func ( p * Lama2Parser ) HeaderData () ( * gabs . Container , error ) func (*Lama2Parser) HeaderPair \u00b6 func ( p * Lama2Parser ) HeaderPair () ( * gabs . Container , error ) func (*Lama2Parser) Headers \u00b6 func ( p * Lama2Parser ) Headers () ( * gabs . Container , error ) Headers detects HTTP headers; essentially strings separated by \":\" character func (*Lama2Parser) Integer \u00b6 func ( p * Lama2Parser ) Integer () ( * gabs . Container , error ) func (*Lama2Parser) IntegerRule1 \u00b6 func ( p * Lama2Parser ) IntegerRule1 () ( * gabs . Container , error ) InterRule1 matches a Digit func (*Lama2Parser) IntegerRule2 \u00b6 func ( p * Lama2Parser ) IntegerRule2 () ( * gabs . Container , error ) IntegerRule2 matches 1-9 mandatorily, and then tries to follow it with Digits func (*Lama2Parser) IntegerRule3 \u00b6 func ( p * Lama2Parser ) IntegerRule3 () ( * gabs . Container , error ) IntegerRule3 starts with a mandatory Sign, and follows with IntegerRule1 (Digit) func (*Lama2Parser) IntegerRule4 \u00b6 func ( p * Lama2Parser ) IntegerRule4 () ( * gabs . Container , error ) IntegerRule4 starts with a mandatory Sign, and follows with IntegerRule2 func (*Lama2Parser) Lama2File \u00b6 func ( p * Lama2Parser ) Lama2File () ( * gabs . Container , error ) func (*Lama2Parser) List \u00b6 func ( p * Lama2Parser ) List () ( * gabs . Container , error ) List is a slightly lenient version of standard JSON list. In Lama2 List, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma) func (*Lama2Parser) Map \u00b6 func ( p * Lama2Parser ) Map () ( * gabs . Container , error ) Map is a slightly lenient version of standard JSON map. In Lama2 Map, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma) func (*Lama2Parser) Multipart \u00b6 func ( p * Lama2Parser ) Multipart () ( * gabs . Container , error ) func (*Lama2Parser) Null \u00b6 func ( p * Lama2Parser ) Null () ( * gabs . Container , error ) func (*Lama2Parser) Number \u00b6 func ( p * Lama2Parser ) Number () ( * gabs . Container , error ) A Number consists of a mandatory integer part, and optional Fraction and Exponent parts. The Number method \"collects\" these three elements, converts them into a json.Number() type, and finally returns the Number wrapped within a gabs Container func (*Lama2Parser) OneNine \u00b6 func ( p * Lama2Parser ) OneNine () ( * gabs . Container , error ) func (*Lama2Parser) Pair \u00b6 func ( p * Lama2Parser ) Pair () ( * gabs . Container , error ) func (*Lama2Parser) PrimitiveType \u00b6 func ( p * Lama2Parser ) PrimitiveType () ( * gabs . Container , error ) func (*Lama2Parser) Processor \u00b6 func ( p * Lama2Parser ) Processor () ( * gabs . Container , error ) func (*Lama2Parser) QuotedString \u00b6 func ( p * Lama2Parser ) QuotedString () ( * gabs . Container , error ) QuotedString accepts both single-quoted and double-quoted types of strings. Moreover, it can deal with unicode escape characters, control characters appropriately Ultimately, we get a string wrapped in a gabs container func (*Lama2Parser) Requester \u00b6 func ( p * Lama2Parser ) Requester () ( * gabs . Container , error ) Requester applies the rule: HTTPVerb Multipart? TheURL Details? func (*Lama2Parser) Separator \u00b6 func ( p * Lama2Parser ) Separator () ( * gabs . Container , error ) func (*Lama2Parser) Sign \u00b6 func ( p * Lama2Parser ) Sign () ( * gabs . Container , error ) func (*Lama2Parser) Start \u00b6 func ( p * Lama2Parser ) Start () ( * gabs . Container , error ) Start primarily calls the Lama2File method func (*Lama2Parser) TheURL \u00b6 func ( p * Lama2Parser ) TheURL () ( * gabs . Container , error ) func (*Lama2Parser) Unquoted \u00b6 func ( p * Lama2Parser ) Unquoted () ( * gabs . Container , error ) func (*Lama2Parser) VarJSON \u00b6 func ( p * Lama2Parser ) VarJSON () ( * gabs . Container , error ) Method VarJSON behaves in two ways depending on whether `multipart` is true or not. If there is no multipart, then VarJSON tries to match one or more VarJSONPairs However, if there is multipart, we try to match zero or more VarJSON, followed by zero or more file fields (separated by `@`). If there is no match at all, we return a ParseError; otherwise the we return the parsed data. func (*Lama2Parser) VarJSONPair \u00b6 func ( p * Lama2Parser ) VarJSONPair () ( * gabs . Container , error ) VarJSONPair tries to match key and value separated by `=`. The key and value can either be a quoted string, or an unquoted VarJSON unquoted string. If there is no match for either, a ParseError is returned. func (*Lama2Parser) VarJSONUnquoted \u00b6 func ( p * Lama2Parser ) VarJSONUnquoted () ( * gabs . Container , error ) VarJSONUnquoted matches a string of characters other than `=` and returns them as a String type MinimalParser \u00b6 MinimalParser enforces concrete Types to have a Start() method, from which parsing process begins. In the present case, `Lama2Parser` adds up dozens of of methods to implement `.l2` syntax type MinimalParser interface { Start () ( * gabs . Container , error ) } type Parser \u00b6 Struct Parser stores information about the parsing process throughout. 1. Text: Incoming text is stored as an array of runes, to correctly handle unicode characters 2. Pos: Indicates the index position in Text which has already been scanned; starts with -1 3. TotalLen: Number of runes in the input 4. Pm: Composing an external MinimalParser (such as Lama2Parser) which builds upon Parser to provide the new language recognition capabilities 5. ruleMethodMap: Scans through Pm, and creates a mapping from method name to method value through reflection 6. LineNum: Number of normalized newlines found till now. Used in providing useful context in error messages type Parser struct { Text [] rune Pos int TotalLen int Pm MinimalParser LineNum int // contains filtered or unexported fields } func (*Parser) Char \u00b6 func ( p * Parser ) Char () ( rune , error ) func (*Parser) CharClass \u00b6 func ( p * Parser ) CharClass ( charClass string ) ( rune , error ) CharClass implements the familiar regex syntax for specifying ranges of characters that are deemed acceptable. A good description of CharClass is available here: Read the section \"Processing Character Ranges\" at https://www.booleanworld.com/building-recursive-descent-parsers-definitive-guide/ func (*Parser) Init \u00b6 func ( p * Parser ) Init () Method Init creates the most important data stucture for parsing: ruleMethodMap. We use reflection to create a mapping of each Pm.\\ to \\ func (*Parser) Keyword \u00b6 func ( p * Parser ) Keyword ( kw string , eatWsStart bool , eatWsEnd bool , caseInsensitive bool ) ([] rune , error ) Method Keyword is a versatile; it can eat whitespace before/after the expected string, and it can do an optionally case insensitive match for the keyword func (*Parser) LookAhead \u00b6 func ( p * Parser ) LookAhead ( rules [] string ) bool func (*Parser) Match \u00b6 func ( p * Parser ) Match ( rules [] string ) ( * gabs . Container , error ) Method Match is the most important of all in the parser package. Match takes in a slice of rules (essentially method names), and then executes them one by one. On successful match, we return a gabs Container with `error` set to `nil` When a rule fails to match, we reset the scan position to initial position; moreover, we keep a continuous track of the farthest/longest match till present. The farthest match error is potentially the most useful error message to the user; thus, for error report, Match returns the farthest matching error func (*Parser) MatchUntil \u00b6 func ( p * Parser ) MatchUntil ( end string ) ( * gabs . Container , error ) func (*Parser) Parse \u00b6 func ( p * Parser ) Parse ( text string ) ( * gabs . Container , error ) Method Parse normalizes newlines and then creates a rune version of the input data. The Start() method proceeds to process the rune version of data func (*Parser) SetText \u00b6 func ( p * Parser ) SetText ( text string ) Method SetText is a utility used primarily in testing, when we don't want to call Start() automatically as in Parse func (*Parser) SplitCharRanges \u00b6 func ( p * Parser ) SplitCharRanges ( charClass string ) ([] string , error ) func (*Parser) Start \u00b6 func ( p * Parser ) Start () * gabs . Container Start() in Parser provides a dummy default implementation; the expectation is that the higher level Struct (Pm) will implement its own version Generated by gomarkdoc","title":"Parser"},{"location":"reference/parser.html#parser","text":"import \"github.com/HexmosTech/lama2/parser\" The `parser` package provides primitives that help with writing recursive descent parsers. This version is a golang port of the original Python implementation from https://tinyurl.com/rdescent The `Parser` struct is supposed to be extended to support parsing a new language. Take a look at `lama2parser.go` for an example. Essentially the actual parsing begins from the `Start()` method.","title":"parser"},{"location":"reference/parser.html#index","text":"Variables func CustomPairMerge(destination, source interface{}) interface{} type Lama2Parser func NewLama2Parser() *Lama2Parser func (p *Lama2Parser) AnyType() (*gabs.Container, error) func (p *Lama2Parser) Boolean() (*gabs.Container, error) func (p *Lama2Parser) ComplexType() (*gabs.Container, error) func (p *Lama2Parser) DataHeader() (*gabs.Container, error) func (p *Lama2Parser) DataInput() (*gabs.Container, error) func (p *Lama2Parser) Details() (*gabs.Container, error) func (p *Lama2Parser) Digit() (*gabs.Container, error) func (p *Lama2Parser) Digits() (*gabs.Container, error) func (p *Lama2Parser) Exponent() (*gabs.Container, error) func (p *Lama2Parser) FilesPair() (*gabs.Container, error) func (p *Lama2Parser) FilesUnquoted() (*gabs.Container, error) func (p *Lama2Parser) Fraction() (*gabs.Container, error) func (p *Lama2Parser) FractionRule1() (*gabs.Container, error) func (p *Lama2Parser) HTTPVerb() (*gabs.Container, error) func (p *Lama2Parser) HeaderData() (*gabs.Container, error) func (p *Lama2Parser) HeaderPair() (*gabs.Container, error) func (p *Lama2Parser) Headers() (*gabs.Container, error) func (p *Lama2Parser) Integer() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule1() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule2() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule3() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule4() (*gabs.Container, error) func (p *Lama2Parser) Lama2File() (*gabs.Container, error) func (p *Lama2Parser) List() (*gabs.Container, error) func (p *Lama2Parser) Map() (*gabs.Container, error) func (p *Lama2Parser) Multipart() (*gabs.Container, error) func (p *Lama2Parser) Null() (*gabs.Container, error) func (p *Lama2Parser) Number() (*gabs.Container, error) func (p *Lama2Parser) OneNine() (*gabs.Container, error) func (p *Lama2Parser) Pair() (*gabs.Container, error) func (p *Lama2Parser) PrimitiveType() (*gabs.Container, error) func (p *Lama2Parser) Processor() (*gabs.Container, error) func (p *Lama2Parser) QuotedString() (*gabs.Container, error) func (p *Lama2Parser) Requester() (*gabs.Container, error) func (p *Lama2Parser) Separator() (*gabs.Container, error) func (p *Lama2Parser) Sign() (*gabs.Container, error) func (p *Lama2Parser) Start() (*gabs.Container, error) func (p *Lama2Parser) TheURL() (*gabs.Container, error) func (p *Lama2Parser) Unquoted() (*gabs.Container, error) func (p *Lama2Parser) VarJSON() (*gabs.Container, error) func (p *Lama2Parser) VarJSONPair() (*gabs.Container, error) func (p *Lama2Parser) VarJSONUnquoted() (*gabs.Container, error) type MinimalParser type Parser func (p *Parser) Char() (rune, error) func (p *Parser) CharClass(charClass string) (rune, error) func (p *Parser) Init() func (p *Parser) Keyword(kw string, eatWsStart bool, eatWsEnd bool, caseInsensitive bool) ([]rune, error) func (p *Parser) LookAhead(rules []string) bool func (p *Parser) Match(rules []string) (*gabs.Container, error) func (p *Parser) MatchUntil(end string) (*gabs.Container, error) func (p *Parser) Parse(text string) (*gabs.Container, error) func (p *Parser) SetText(text string) func (p *Parser) SplitCharRanges(charClass string) ([]string, error) func (p *Parser) Start() *gabs.Container","title":"Index"},{"location":"reference/parser.html#variables","text":"var DataInputType string","title":"Variables"},{"location":"reference/parser.html#func-custompairmerge","text":"func CustomPairMerge ( destination , source interface {}) interface {} CustomPairMerge uses a gabs feature to deal with merge conflicts. More here: https://github.com/HexmosTech/gabs/blob/master/gabs.go#L511","title":"func CustomPairMerge"},{"location":"reference/parser.html#type-lama2parser","text":"type Lama2Parser struct { * Parser Context map [ string ] bool MarkRange map [ string ] int }","title":"type Lama2Parser"},{"location":"reference/parser.html#func-newlama2parser","text":"func NewLama2Parser () * Lama2Parser NewLama2Parser creates a new Lama2Parser and initializes it properly","title":"func NewLama2Parser"},{"location":"reference/parser.html#func-lama2parser-anytype","text":"func ( p * Lama2Parser ) AnyType () ( * gabs . Container , error ) AnyType is the top-most element of a JSON structure It consists of Complex and Primitive Types","title":"func (*Lama2Parser) AnyType"},{"location":"reference/parser.html#func-lama2parser-boolean","text":"func ( p * Lama2Parser ) Boolean () ( * gabs . Container , error )","title":"func (*Lama2Parser) Boolean"},{"location":"reference/parser.html#func-lama2parser-complextype","text":"func ( p * Lama2Parser ) ComplexType () ( * gabs . Container , error )","title":"func (*Lama2Parser) ComplexType"},{"location":"reference/parser.html#func-lama2parser-dataheader","text":"func ( p * Lama2Parser ) DataHeader () ( * gabs . Container , error )","title":"func (*Lama2Parser) DataHeader"},{"location":"reference/parser.html#func-lama2parser-datainput","text":"func ( p * Lama2Parser ) DataInput () ( * gabs . Container , error )","title":"func (*Lama2Parser) DataInput"},{"location":"reference/parser.html#func-lama2parser-details","text":"func ( p * Lama2Parser ) Details () ( * gabs . Container , error )","title":"func (*Lama2Parser) Details"},{"location":"reference/parser.html#func-lama2parser-digit","text":"func ( p * Lama2Parser ) Digit () ( * gabs . Container , error )","title":"func (*Lama2Parser) Digit"},{"location":"reference/parser.html#func-lama2parser-digits","text":"func ( p * Lama2Parser ) Digits () ( * gabs . Container , error )","title":"func (*Lama2Parser) Digits"},{"location":"reference/parser.html#func-lama2parser-exponent","text":"func ( p * Lama2Parser ) Exponent () ( * gabs . Container , error ) An Exponent consists of mandatory 'e' or 'E', optional Sign, followed by Digits","title":"func (*Lama2Parser) Exponent"},{"location":"reference/parser.html#func-lama2parser-filespair","text":"func ( p * Lama2Parser ) FilesPair () ( * gabs . Container , error ) FilesPair tries to match key and value separated by `@`. The key and value can either be a quoted string, or an unquoted Files Unquoted String. If there is no match for either, a ParseError is returned.","title":"func (*Lama2Parser) FilesPair"},{"location":"reference/parser.html#func-lama2parser-filesunquoted","text":"func ( p * Lama2Parser ) FilesUnquoted () ( * gabs . Container , error ) FilesUnquoted matches a string of characters other than `@` and returns them as a String","title":"func (*Lama2Parser) FilesUnquoted"},{"location":"reference/parser.html#func-lama2parser-fraction","text":"func ( p * Lama2Parser ) Fraction () ( * gabs . Container , error )","title":"func (*Lama2Parser) Fraction"},{"location":"reference/parser.html#func-lama2parser-fractionrule1","text":"func ( p * Lama2Parser ) FractionRule1 () ( * gabs . Container , error ) A Fraction consists of mandatory \".\" (dot), followed by Digits.","title":"func (*Lama2Parser) FractionRule1"},{"location":"reference/parser.html#func-lama2parser-httpverb","text":"func ( p * Lama2Parser ) HTTPVerb () ( * gabs . Container , error )","title":"func (*Lama2Parser) HTTPVerb"},{"location":"reference/parser.html#func-lama2parser-headerdata","text":"func ( p * Lama2Parser ) HeaderData () ( * gabs . Container , error )","title":"func (*Lama2Parser) HeaderData"},{"location":"reference/parser.html#func-lama2parser-headerpair","text":"func ( p * Lama2Parser ) HeaderPair () ( * gabs . Container , error )","title":"func (*Lama2Parser) HeaderPair"},{"location":"reference/parser.html#func-lama2parser-headers","text":"func ( p * Lama2Parser ) Headers () ( * gabs . Container , error ) Headers detects HTTP headers; essentially strings separated by \":\" character","title":"func (*Lama2Parser) Headers"},{"location":"reference/parser.html#func-lama2parser-integer","text":"func ( p * Lama2Parser ) Integer () ( * gabs . Container , error )","title":"func (*Lama2Parser) Integer"},{"location":"reference/parser.html#func-lama2parser-integerrule1","text":"func ( p * Lama2Parser ) IntegerRule1 () ( * gabs . Container , error ) InterRule1 matches a Digit","title":"func (*Lama2Parser) IntegerRule1"},{"location":"reference/parser.html#func-lama2parser-integerrule2","text":"func ( p * Lama2Parser ) IntegerRule2 () ( * gabs . Container , error ) IntegerRule2 matches 1-9 mandatorily, and then tries to follow it with Digits","title":"func (*Lama2Parser) IntegerRule2"},{"location":"reference/parser.html#func-lama2parser-integerrule3","text":"func ( p * Lama2Parser ) IntegerRule3 () ( * gabs . Container , error ) IntegerRule3 starts with a mandatory Sign, and follows with IntegerRule1 (Digit)","title":"func (*Lama2Parser) IntegerRule3"},{"location":"reference/parser.html#func-lama2parser-integerrule4","text":"func ( p * Lama2Parser ) IntegerRule4 () ( * gabs . Container , error ) IntegerRule4 starts with a mandatory Sign, and follows with IntegerRule2","title":"func (*Lama2Parser) IntegerRule4"},{"location":"reference/parser.html#func-lama2parser-lama2file","text":"func ( p * Lama2Parser ) Lama2File () ( * gabs . Container , error )","title":"func (*Lama2Parser) Lama2File"},{"location":"reference/parser.html#func-lama2parser-list","text":"func ( p * Lama2Parser ) List () ( * gabs . Container , error ) List is a slightly lenient version of standard JSON list. In Lama2 List, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma)","title":"func (*Lama2Parser) List"},{"location":"reference/parser.html#func-lama2parser-map","text":"func ( p * Lama2Parser ) Map () ( * gabs . Container , error ) Map is a slightly lenient version of standard JSON map. In Lama2 Map, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma)","title":"func (*Lama2Parser) Map"},{"location":"reference/parser.html#func-lama2parser-multipart","text":"func ( p * Lama2Parser ) Multipart () ( * gabs . Container , error )","title":"func (*Lama2Parser) Multipart"},{"location":"reference/parser.html#func-lama2parser-null","text":"func ( p * Lama2Parser ) Null () ( * gabs . Container , error )","title":"func (*Lama2Parser) Null"},{"location":"reference/parser.html#func-lama2parser-number","text":"func ( p * Lama2Parser ) Number () ( * gabs . Container , error ) A Number consists of a mandatory integer part, and optional Fraction and Exponent parts. The Number method \"collects\" these three elements, converts them into a json.Number() type, and finally returns the Number wrapped within a gabs Container","title":"func (*Lama2Parser) Number"},{"location":"reference/parser.html#func-lama2parser-onenine","text":"func ( p * Lama2Parser ) OneNine () ( * gabs . Container , error )","title":"func (*Lama2Parser) OneNine"},{"location":"reference/parser.html#func-lama2parser-pair","text":"func ( p * Lama2Parser ) Pair () ( * gabs . Container , error )","title":"func (*Lama2Parser) Pair"},{"location":"reference/parser.html#func-lama2parser-primitivetype","text":"func ( p * Lama2Parser ) PrimitiveType () ( * gabs . Container , error )","title":"func (*Lama2Parser) PrimitiveType"},{"location":"reference/parser.html#func-lama2parser-processor","text":"func ( p * Lama2Parser ) Processor () ( * gabs . Container , error )","title":"func (*Lama2Parser) Processor"},{"location":"reference/parser.html#func-lama2parser-quotedstring","text":"func ( p * Lama2Parser ) QuotedString () ( * gabs . Container , error ) QuotedString accepts both single-quoted and double-quoted types of strings. Moreover, it can deal with unicode escape characters, control characters appropriately Ultimately, we get a string wrapped in a gabs container","title":"func (*Lama2Parser) QuotedString"},{"location":"reference/parser.html#func-lama2parser-requester","text":"func ( p * Lama2Parser ) Requester () ( * gabs . Container , error ) Requester applies the rule: HTTPVerb Multipart? TheURL Details?","title":"func (*Lama2Parser) Requester"},{"location":"reference/parser.html#func-lama2parser-separator","text":"func ( p * Lama2Parser ) Separator () ( * gabs . Container , error )","title":"func (*Lama2Parser) Separator"},{"location":"reference/parser.html#func-lama2parser-sign","text":"func ( p * Lama2Parser ) Sign () ( * gabs . Container , error )","title":"func (*Lama2Parser) Sign"},{"location":"reference/parser.html#func-lama2parser-start","text":"func ( p * Lama2Parser ) Start () ( * gabs . Container , error ) Start primarily calls the Lama2File method","title":"func (*Lama2Parser) Start"},{"location":"reference/parser.html#func-lama2parser-theurl","text":"func ( p * Lama2Parser ) TheURL () ( * gabs . Container , error )","title":"func (*Lama2Parser) TheURL"},{"location":"reference/parser.html#func-lama2parser-unquoted","text":"func ( p * Lama2Parser ) Unquoted () ( * gabs . Container , error )","title":"func (*Lama2Parser) Unquoted"},{"location":"reference/parser.html#func-lama2parser-varjson","text":"func ( p * Lama2Parser ) VarJSON () ( * gabs . Container , error ) Method VarJSON behaves in two ways depending on whether `multipart` is true or not. If there is no multipart, then VarJSON tries to match one or more VarJSONPairs However, if there is multipart, we try to match zero or more VarJSON, followed by zero or more file fields (separated by `@`). If there is no match at all, we return a ParseError; otherwise the we return the parsed data.","title":"func (*Lama2Parser) VarJSON"},{"location":"reference/parser.html#func-lama2parser-varjsonpair","text":"func ( p * Lama2Parser ) VarJSONPair () ( * gabs . Container , error ) VarJSONPair tries to match key and value separated by `=`. The key and value can either be a quoted string, or an unquoted VarJSON unquoted string. If there is no match for either, a ParseError is returned.","title":"func (*Lama2Parser) VarJSONPair"},{"location":"reference/parser.html#func-lama2parser-varjsonunquoted","text":"func ( p * Lama2Parser ) VarJSONUnquoted () ( * gabs . Container , error ) VarJSONUnquoted matches a string of characters other than `=` and returns them as a String","title":"func (*Lama2Parser) VarJSONUnquoted"},{"location":"reference/parser.html#type-minimalparser","text":"MinimalParser enforces concrete Types to have a Start() method, from which parsing process begins. In the present case, `Lama2Parser` adds up dozens of of methods to implement `.l2` syntax type MinimalParser interface { Start () ( * gabs . Container , error ) }","title":"type MinimalParser"},{"location":"reference/parser.html#type-parser","text":"Struct Parser stores information about the parsing process throughout. 1. Text: Incoming text is stored as an array of runes, to correctly handle unicode characters 2. Pos: Indicates the index position in Text which has already been scanned; starts with -1 3. TotalLen: Number of runes in the input 4. Pm: Composing an external MinimalParser (such as Lama2Parser) which builds upon Parser to provide the new language recognition capabilities 5. ruleMethodMap: Scans through Pm, and creates a mapping from method name to method value through reflection 6. LineNum: Number of normalized newlines found till now. Used in providing useful context in error messages type Parser struct { Text [] rune Pos int TotalLen int Pm MinimalParser LineNum int // contains filtered or unexported fields }","title":"type Parser"},{"location":"reference/parser.html#func-parser-char","text":"func ( p * Parser ) Char () ( rune , error )","title":"func (*Parser) Char"},{"location":"reference/parser.html#func-parser-charclass","text":"func ( p * Parser ) CharClass ( charClass string ) ( rune , error ) CharClass implements the familiar regex syntax for specifying ranges of characters that are deemed acceptable. A good description of CharClass is available here: Read the section \"Processing Character Ranges\" at https://www.booleanworld.com/building-recursive-descent-parsers-definitive-guide/","title":"func (*Parser) CharClass"},{"location":"reference/parser.html#func-parser-init","text":"func ( p * Parser ) Init () Method Init creates the most important data stucture for parsing: ruleMethodMap. We use reflection to create a mapping of each Pm.\\ to \\","title":"func (*Parser) Init"},{"location":"reference/parser.html#func-parser-keyword","text":"func ( p * Parser ) Keyword ( kw string , eatWsStart bool , eatWsEnd bool , caseInsensitive bool ) ([] rune , error ) Method Keyword is a versatile; it can eat whitespace before/after the expected string, and it can do an optionally case insensitive match for the keyword","title":"func (*Parser) Keyword"},{"location":"reference/parser.html#func-parser-lookahead","text":"func ( p * Parser ) LookAhead ( rules [] string ) bool","title":"func (*Parser) LookAhead"},{"location":"reference/parser.html#func-parser-match","text":"func ( p * Parser ) Match ( rules [] string ) ( * gabs . Container , error ) Method Match is the most important of all in the parser package. Match takes in a slice of rules (essentially method names), and then executes them one by one. On successful match, we return a gabs Container with `error` set to `nil` When a rule fails to match, we reset the scan position to initial position; moreover, we keep a continuous track of the farthest/longest match till present. The farthest match error is potentially the most useful error message to the user; thus, for error report, Match returns the farthest matching error","title":"func (*Parser) Match"},{"location":"reference/parser.html#func-parser-matchuntil","text":"func ( p * Parser ) MatchUntil ( end string ) ( * gabs . Container , error )","title":"func (*Parser) MatchUntil"},{"location":"reference/parser.html#func-parser-parse","text":"func ( p * Parser ) Parse ( text string ) ( * gabs . Container , error ) Method Parse normalizes newlines and then creates a rune version of the input data. The Start() method proceeds to process the rune version of data","title":"func (*Parser) Parse"},{"location":"reference/parser.html#func-parser-settext","text":"func ( p * Parser ) SetText ( text string ) Method SetText is a utility used primarily in testing, when we don't want to call Start() automatically as in Parse","title":"func (*Parser) SetText"},{"location":"reference/parser.html#func-parser-splitcharranges","text":"func ( p * Parser ) SplitCharRanges ( charClass string ) ([] string , error )","title":"func (*Parser) SplitCharRanges"},{"location":"reference/parser.html#func-parser-start","text":"func ( p * Parser ) Start () * gabs . Container Start() in Parser provides a dummy default implementation; the expectation is that the higher level Struct (Pm) will implement its own version Generated by gomarkdoc","title":"func (*Parser) Start"},{"location":"reference/philosophy.html","text":"Lama2 takes inspiration from Markdown . Think of our approach as Markdown for APIs . In particular, we strive to: Delegate subtasks to mature and preferably open tools: API Collaboration - git API Organization - OS file manager + IDEs API Editing - VSCode/IDEs API Requests - HTTPie ( httpie-go , to be specific) Request Chaining - Embedded Javascript Adhere to a continuous language formalization effort from the beginning (learning from Markdown history) Keep language syntax simple; don't sacrifice readability for tiny functionality gains. Invest into good documentation; however, ensure users can perform competently without referencing documentation as much as possible. Keep components decoupled","title":"Design Philosophy"},{"location":"reference/preprocess.html","text":"preprocess \u00b6 import \"github.com/HexmosTech/lama2/preprocess\" Package preprocess provides facilities to expand environment variables in `.l2` API files and return the contents Index \u00b6 func Expand(s string, vm *goja.Runtime, mapping map[string]string) string func ExpandEnv(s string, vm *goja.Runtime) string func ExpandHeaders(block *gabs.Container, vm *goja.Runtime) func ExpandJSON(block *gabs.Container, vm *goja.Runtime) func ExpandURL(block *gabs.Container, vm *goja.Runtime) func GetL2EnvVariables(dir string) ([]byte, error) func GetLamaFileAsString(path string) string func LamaFile(inputFile string) (string, string) func LoadEnvFile(l2path string) func LoadEnvironments(dir string) func ProcessVarsInBlock(block *gabs.Container, vm *goja.Runtime) func SearchL2ConfigEnv(dir string) (string, error) func Expand \u00b6 func Expand ( s string , vm * goja . Runtime , mapping map [ string ] string ) string Expand replaces ${var} or $var in the string based on the mapping function. For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv). func ExpandEnv \u00b6 func ExpandEnv ( s string , vm * goja . Runtime ) string ExpandEnv replaces ${var} or $var in the string according to the values of the current environment variables. References to undefined variables are replaced by the empty string. func ExpandHeaders \u00b6 func ExpandHeaders ( block * gabs . Container , vm * goja . Runtime ) func ExpandJSON \u00b6 func ExpandJSON ( block * gabs . Container , vm * goja . Runtime ) func ExpandURL \u00b6 func ExpandURL ( block * gabs . Container , vm * goja . Runtime ) func GetL2EnvVariables \u00b6 func GetL2EnvVariables ( dir string ) ([] byte , error ) func GetLamaFileAsString \u00b6 func GetLamaFileAsString ( path string ) string func LamaFile \u00b6 func LamaFile ( inputFile string ) ( string , string ) LamaFile takes in a path to an API file. It moves into the API file directory, reads the API contents, loads the `l2.env` file if available, and finally substitutes environment vars in the API contents Once done, it reverts back to the original directory, and returns the processed l2 file. func LoadEnvFile \u00b6 func LoadEnvFile ( l2path string ) func LoadEnvironments \u00b6 func LoadEnvironments ( dir string ) func ProcessVarsInBlock \u00b6 func ProcessVarsInBlock ( block * gabs . Container , vm * goja . Runtime ) func SearchL2ConfigEnv \u00b6 func SearchL2ConfigEnv ( dir string ) ( string , error ) Generated by gomarkdoc","title":"Preprocess"},{"location":"reference/preprocess.html#preprocess","text":"import \"github.com/HexmosTech/lama2/preprocess\" Package preprocess provides facilities to expand environment variables in `.l2` API files and return the contents","title":"preprocess"},{"location":"reference/preprocess.html#index","text":"func Expand(s string, vm *goja.Runtime, mapping map[string]string) string func ExpandEnv(s string, vm *goja.Runtime) string func ExpandHeaders(block *gabs.Container, vm *goja.Runtime) func ExpandJSON(block *gabs.Container, vm *goja.Runtime) func ExpandURL(block *gabs.Container, vm *goja.Runtime) func GetL2EnvVariables(dir string) ([]byte, error) func GetLamaFileAsString(path string) string func LamaFile(inputFile string) (string, string) func LoadEnvFile(l2path string) func LoadEnvironments(dir string) func ProcessVarsInBlock(block *gabs.Container, vm *goja.Runtime) func SearchL2ConfigEnv(dir string) (string, error)","title":"Index"},{"location":"reference/preprocess.html#func-expand","text":"func Expand ( s string , vm * goja . Runtime , mapping map [ string ] string ) string Expand replaces ${var} or $var in the string based on the mapping function. For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv).","title":"func Expand"},{"location":"reference/preprocess.html#func-expandenv","text":"func ExpandEnv ( s string , vm * goja . Runtime ) string ExpandEnv replaces ${var} or $var in the string according to the values of the current environment variables. References to undefined variables are replaced by the empty string.","title":"func ExpandEnv"},{"location":"reference/preprocess.html#func-expandheaders","text":"func ExpandHeaders ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandHeaders"},{"location":"reference/preprocess.html#func-expandjson","text":"func ExpandJSON ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandJSON"},{"location":"reference/preprocess.html#func-expandurl","text":"func ExpandURL ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandURL"},{"location":"reference/preprocess.html#func-getl2envvariables","text":"func GetL2EnvVariables ( dir string ) ([] byte , error )","title":"func GetL2EnvVariables"},{"location":"reference/preprocess.html#func-getlamafileasstring","text":"func GetLamaFileAsString ( path string ) string","title":"func GetLamaFileAsString"},{"location":"reference/preprocess.html#func-lamafile","text":"func LamaFile ( inputFile string ) ( string , string ) LamaFile takes in a path to an API file. It moves into the API file directory, reads the API contents, loads the `l2.env` file if available, and finally substitutes environment vars in the API contents Once done, it reverts back to the original directory, and returns the processed l2 file.","title":"func LamaFile"},{"location":"reference/preprocess.html#func-loadenvfile","text":"func LoadEnvFile ( l2path string )","title":"func LoadEnvFile"},{"location":"reference/preprocess.html#func-loadenvironments","text":"func LoadEnvironments ( dir string )","title":"func LoadEnvironments"},{"location":"reference/preprocess.html#func-processvarsinblock","text":"func ProcessVarsInBlock ( block * gabs . Container , vm * goja . Runtime )","title":"func ProcessVarsInBlock"},{"location":"reference/preprocess.html#func-searchl2configenv","text":"func SearchL2ConfigEnv ( dir string ) ( string , error ) Generated by gomarkdoc","title":"func SearchL2ConfigEnv"},{"location":"reference/utils.html","text":"utils \u00b6 import \"github.com/HexmosTech/lama2/utils\" Package `utils` provides useful functions for simplifying various programming tasks Index \u00b6 func ChangeWorkingDir(dir string) func ContainsRune(s []rune, e rune) bool func ContainsString(s []string, e string) bool func ContainsStringPartial(s []string, e string) bool func GetFilePathComponents(name string) (string, string, string) func PrettyPrint(i interface{}) string func SetJSON(parentObj *gabs.Container, childObj *gabs.Container, key string) *gabs.Container func UnicodeCategory(r rune) string func UpdateSelf() type ParseError func NewParseError(pos int, line int, msg string, args []string) *ParseError func (p ParseError) Error() string func ChangeWorkingDir \u00b6 func ChangeWorkingDir ( dir string ) ChangeWorkingDirectory tries to set the CWD; on failure it exits with a log error message func ContainsRune \u00b6 func ContainsRune ( s [] rune , e rune ) bool ContainsRune searches for rune `e` in a slice of runes `s`; returns a boolean func ContainsString \u00b6 func ContainsString ( s [] string , e string ) bool ContainsString searches for string `e` in a slice of strings `s`; returns a boolean func ContainsStringPartial \u00b6 func ContainsStringPartial ( s [] string , e string ) bool ContainsStringPartial substring-searches for string `e` in a slice of strings `s`; returns a boolean func GetFilePathComponents \u00b6 func GetFilePathComponents ( name string ) ( string , string , string ) GetFilePathComponent returns absolute path, directory, and filename given a filepath func PrettyPrint \u00b6 func PrettyPrint ( i interface {}) string PrettyPrint takes in a generic interface{} objects and uses standard JSON capabilities to try to print with indentation func SetJSON \u00b6 func SetJSON ( parentObj * gabs . Container , childObj * gabs . Container , key string ) * gabs . Container SetJSON is a helper function to work with the `gabs` library, which in turn is an API on top of the standard JSON library The function helps us create `parentObj.key = childObj` through using the `Merge` primitive available in `gabs` func UnicodeCategory \u00b6 func UnicodeCategory ( r rune ) string UnicodeCategory returns the Unicode Character Category of the given rune. func UpdateSelf \u00b6 func UpdateSelf () UpdateSelf downloads the installation script from the official repository, and executes it to update the l2 binary to the latest version type ParseError \u00b6 type ParseError struct { Pos int LineNum int // contains filtered or unexported fields } func NewParseError \u00b6 func NewParseError ( pos int , line int , msg string , args [] string ) * ParseError func (ParseError) Error \u00b6 func ( p ParseError ) Error () string Generated by gomarkdoc","title":"Utils"},{"location":"reference/utils.html#utils","text":"import \"github.com/HexmosTech/lama2/utils\" Package `utils` provides useful functions for simplifying various programming tasks","title":"utils"},{"location":"reference/utils.html#index","text":"func ChangeWorkingDir(dir string) func ContainsRune(s []rune, e rune) bool func ContainsString(s []string, e string) bool func ContainsStringPartial(s []string, e string) bool func GetFilePathComponents(name string) (string, string, string) func PrettyPrint(i interface{}) string func SetJSON(parentObj *gabs.Container, childObj *gabs.Container, key string) *gabs.Container func UnicodeCategory(r rune) string func UpdateSelf() type ParseError func NewParseError(pos int, line int, msg string, args []string) *ParseError func (p ParseError) Error() string","title":"Index"},{"location":"reference/utils.html#func-changeworkingdir","text":"func ChangeWorkingDir ( dir string ) ChangeWorkingDirectory tries to set the CWD; on failure it exits with a log error message","title":"func ChangeWorkingDir"},{"location":"reference/utils.html#func-containsrune","text":"func ContainsRune ( s [] rune , e rune ) bool ContainsRune searches for rune `e` in a slice of runes `s`; returns a boolean","title":"func ContainsRune"},{"location":"reference/utils.html#func-containsstring","text":"func ContainsString ( s [] string , e string ) bool ContainsString searches for string `e` in a slice of strings `s`; returns a boolean","title":"func ContainsString"},{"location":"reference/utils.html#func-containsstringpartial","text":"func ContainsStringPartial ( s [] string , e string ) bool ContainsStringPartial substring-searches for string `e` in a slice of strings `s`; returns a boolean","title":"func ContainsStringPartial"},{"location":"reference/utils.html#func-getfilepathcomponents","text":"func GetFilePathComponents ( name string ) ( string , string , string ) GetFilePathComponent returns absolute path, directory, and filename given a filepath","title":"func GetFilePathComponents"},{"location":"reference/utils.html#func-prettyprint","text":"func PrettyPrint ( i interface {}) string PrettyPrint takes in a generic interface{} objects and uses standard JSON capabilities to try to print with indentation","title":"func PrettyPrint"},{"location":"reference/utils.html#func-setjson","text":"func SetJSON ( parentObj * gabs . Container , childObj * gabs . Container , key string ) * gabs . Container SetJSON is a helper function to work with the `gabs` library, which in turn is an API on top of the standard JSON library The function helps us create `parentObj.key = childObj` through using the `Merge` primitive available in `gabs`","title":"func SetJSON"},{"location":"reference/utils.html#func-unicodecategory","text":"func UnicodeCategory ( r rune ) string UnicodeCategory returns the Unicode Character Category of the given rune.","title":"func UnicodeCategory"},{"location":"reference/utils.html#func-updateself","text":"func UpdateSelf () UpdateSelf downloads the installation script from the official repository, and executes it to update the l2 binary to the latest version","title":"func UpdateSelf"},{"location":"reference/utils.html#type-parseerror","text":"type ParseError struct { Pos int LineNum int // contains filtered or unexported fields }","title":"type ParseError"},{"location":"reference/utils.html#func-newparseerror","text":"func NewParseError ( pos int , line int , msg string , args [] string ) * ParseError","title":"func NewParseError"},{"location":"reference/utils.html#func-parseerror-error","text":"func ( p ParseError ) Error () string Generated by gomarkdoc","title":"func (ParseError) Error"},{"location":"tutorials/codegen.html","text":"Lama2 is capable of converting .l2 files into functional code of your preferred language and library. For example, to generate code in python requests , use the following command: l2 -c python.requests myfile.l2 To pick the default library in a language, omit the library as follows: l2 -c python myfile.l2 Languages and libraries supported \u00b6 shell curl (default) httpie wget powershell webrequest (default) restmethod ocaml cohttp (default) csharp restsharp (default) httpclient r httr (default) php curl (default) guzzle http1 http2 ruby native (default) clojure clj_http (default) java unirest (default) asynchttp nethttp okhttp http 1.1 (default) http1.1 swift nsurlsession (default) node native (default) request unirest axios fetch c libcurl (default) go native (default) python python3 (default) requests kotlin okhttp (default) javascript xhr (default) axios fetch jquery objc nsurlsession (default)","title":"Code Generation"},{"location":"tutorials/codegen.html#languages-and-libraries-supported","text":"shell curl (default) httpie wget powershell webrequest (default) restmethod ocaml cohttp (default) csharp restsharp (default) httpclient r httr (default) php curl (default) guzzle http1 http2 ruby native (default) clojure clj_http (default) java unirest (default) asynchttp nethttp okhttp http 1.1 (default) http1.1 swift nsurlsession (default) node native (default) request unirest axios fetch c libcurl (default) go native (default) python python3 (default) requests kotlin okhttp (default) javascript xhr (default) axios fetch jquery objc nsurlsession (default)","title":"Languages and libraries supported"},{"location":"tutorials/collaboration.html","text":"At Hexmos , we use a git repository called APIHub for collaborating on API files. Here is a description of how the workflow functions for us: The new engineer clones APIHub repository If necessary, create a folder for organizing the new API (ex: my_new_service ) Start defining *.l2 files for each service specific API. Use l2 file.l2 to test the newly defined APIs (or execute from VSCode). Push the API files once ready into APIHub repo On the rare merge conflict, the engineer uses standard git conflict resolution mechanisms","title":"Collaboration"},{"location":"tutorials/editor.html","text":"Useful Options \u00b6 The l2 command provides some helpful options for extension developers. The options are: --env or -e outputs a JSON of environment variables (in CLI); --nocolor or -n disables colored output in httpie-go (in CLI); --output=.l2 You can also clone the repo and open it up in VSCode, install the Lama2 extension and fire requests from there. GET request \u00b6 GET https://httpbin.org/get Get Source File JSON POST request \u00b6 One can dump the JSON body at the end of an .l2 file to create a POST request: POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } Get Source File JSON POST in VarJSON format \u00b6 Make a POST request with JSON body specified as key=value . Lama2 converts the input into a corresponding JSON value {\"a\": \"b\", \"c\": \"d\"} . We call the key=value format VarJSON . This example produces an effect identical to the previous one POST https://httpbin.org/post a=b c=d Get Source File Comments \u00b6 One can start a comment anywhere in the file with the # character. # Pound symbol signifies a comment POST https://httpbin.org/post a=b # Comments may start at the end of lines as well c=d # Comments work even after the payload Get Source File Environment Variables: Switch base URL \u00b6 Case 1: l2.env adjacent to an API file \u00b6 For any given .l2 file, one can place an l2.env file to store relevant variables. These variables will be available to be used within the API file project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Case 2: Root variables \u00b6 In Lama2, you can have a large number of API files stored in a hierarchical folder configuration. The root of such a project can be signified through l2config.env : Within such a structure, you can have an API file anywhere, which can use variables defined in the root variables: project_folder/l2config.env export AHOST=\"https://httpbin.org\" export BHOST=\"https://google.com\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Case 3: Override Root variable with local variable \u00b6 In this structure, if a variable is declared in both l2config.env and l2.env, the value from l2.env takes precedence. project_folder/l2config.env export AHOST=`echo NO URL` export BHOST=\"https://httpbin.org\" project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Headers \u00b6 Use key:value format to specify headers. Specify strings for key/value in three ways: Double quoted ( \"hello\" ) Single quoted ( 'hello' ) Unquoted ( hello ) POST https://httpbin.org/post # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings Get Source File Note The data section may appear before headers as well (see below) POST https://httpbin.org/post # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" Send cookies in header \u00b6 Headers represent cookies in Lama2 . Just specify cookie key value pairs separated by = within the header value as shown. POST https://httpbin.org/post # HEADERS Cookie:\"sessionid=foo;another-cookie=bar\" # DATA hello=world Get Source File Fill forms & attach files with MULTIPART \u00b6 Use the MULTIPART keyword after the HTTP verb to enable forms and file attachments. The data section may contain any number of form inputs using the key=value syntax. Following the data section, one can specify any number of files in the form of @ . The file path is relative to the API file. POST MULTIPART http://httpbin.org/post 'X-Parse-Application-Id':hello X-Parse-REST-API-Key:\"world\" # DATA first=second # FILES myfile@./image.jpeg Get Source Files Image as Base64 encoded JSON field \u00b6 We can embed images (or other files) as base64 strings in JSON using Lama2 . First, we define a PHOTO variable, loaded up with the results of the base64 command. l2.env export PHOTO=`base64 -w 0 image.jpeg` Next, we refer to the PHOTO variable in the API file. Pay special attention to the quoting mechanism \"'{PHOTO}'\" . Warning The quoting must look exactly as shown in the following template for the request to work correctly. base64_embed.l2 POST http://httpbin.org/post { \"imageb64_field\": \"'${PHOTO}'\", } Get Source Files Chain requests using Javascript \u00b6 In Lama2, we have alternating requestor and processor (JS) blocks, separated by --- . Each processor (JS) block has a special variable result , storing the response from previous requestor block. If possible, result is automatically stored as a JS object through JSON.parse() . Otherwise, result is stored as a regular string . url = \"http://google.com\" REMOTE_COORD = \"https://httpbing.org\" --- # stage 1 POST ${REMOTE_COORD}/anything { \"username\": \"admin\", \"password\": \"Password@123\", \"from\": \"${LOCAL_COORD}/anything\", \"url\": \"${url}\", \"Token\": \"MySuperSecretToken\" } --- // filtering, store in var console.log(\"@@Result\", result) let TOKEN = result[\"json\"][\"Token\"] console.log(TOKEN) --- # stage 2 GET ${REMOTE_COORD}/bearer Authorization: 'Bearer ${TOKEN}' {} Get Source Files","title":"Examples"},{"location":"tutorials/examples.html#examples","text":"The following examples provide a sampling of the various types of requests Lama2 handles presently. Execute each file as: l2 .l2 You can also clone the repo and open it up in VSCode, install the Lama2 extension and fire requests from there.","title":"Examples"},{"location":"tutorials/examples.html#get-request","text":"GET https://httpbin.org/get Get Source File","title":"GET request"},{"location":"tutorials/examples.html#json-post-request","text":"One can dump the JSON body at the end of an .l2 file to create a POST request: POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } Get Source File","title":"JSON POST request"},{"location":"tutorials/examples.html#json-post-in-varjson-format","text":"Make a POST request with JSON body specified as key=value . Lama2 converts the input into a corresponding JSON value {\"a\": \"b\", \"c\": \"d\"} . We call the key=value format VarJSON . This example produces an effect identical to the previous one POST https://httpbin.org/post a=b c=d Get Source File","title":"JSON POST in VarJSON format"},{"location":"tutorials/examples.html#comments","text":"One can start a comment anywhere in the file with the # character. # Pound symbol signifies a comment POST https://httpbin.org/post a=b # Comments may start at the end of lines as well c=d # Comments work even after the payload Get Source File","title":"Comments"},{"location":"tutorials/examples.html#environment-variables-switch-base-url","text":"","title":"Environment Variables: Switch base URL"},{"location":"tutorials/examples.html#case-1-l2env-adjacent-to-an-api-file","text":"For any given .l2 file, one can place an l2.env file to store relevant variables. These variables will be available to be used within the API file project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 1: l2.env adjacent to an API file"},{"location":"tutorials/examples.html#case-2-root-variables","text":"In Lama2, you can have a large number of API files stored in a hierarchical folder configuration. The root of such a project can be signified through l2config.env : Within such a structure, you can have an API file anywhere, which can use variables defined in the root variables: project_folder/l2config.env export AHOST=\"https://httpbin.org\" export BHOST=\"https://google.com\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 2: Root variables"},{"location":"tutorials/examples.html#case-3-override-root-variable-with-local-variable","text":"In this structure, if a variable is declared in both l2config.env and l2.env, the value from l2.env takes precedence. project_folder/l2config.env export AHOST=`echo NO URL` export BHOST=\"https://httpbin.org\" project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 3: Override Root variable with local variable"},{"location":"tutorials/examples.html#headers","text":"Use key:value format to specify headers. Specify strings for key/value in three ways: Double quoted ( \"hello\" ) Single quoted ( 'hello' ) Unquoted ( hello ) POST https://httpbin.org/post # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings Get Source File Note The data section may appear before headers as well (see below) POST https://httpbin.org/post # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\"","title":"Headers"},{"location":"tutorials/examples.html#send-cookies-in-header","text":"Headers represent cookies in Lama2 . Just specify cookie key value pairs separated by = within the header value as shown. POST https://httpbin.org/post # HEADERS Cookie:\"sessionid=foo;another-cookie=bar\" # DATA hello=world Get Source File","title":"Send cookies in header"},{"location":"tutorials/examples.html#fill-forms-attach-files-with-multipart","text":"Use the MULTIPART keyword after the HTTP verb to enable forms and file attachments. The data section may contain any number of form inputs using the key=value syntax. Following the data section, one can specify any number of files in the form of @ . The file path is relative to the API file. POST MULTIPART http://httpbin.org/post 'X-Parse-Application-Id':hello X-Parse-REST-API-Key:\"world\" # DATA first=second # FILES myfile@./image.jpeg Get Source Files","title":"Fill forms & attach files with MULTIPART"},{"location":"tutorials/examples.html#image-as-base64-encoded-json-field","text":"We can embed images (or other files) as base64 strings in JSON using Lama2 . First, we define a PHOTO variable, loaded up with the results of the base64 command. l2.env export PHOTO=`base64 -w 0 image.jpeg` Next, we refer to the PHOTO variable in the API file. Pay special attention to the quoting mechanism \"'{PHOTO}'\" . Warning The quoting must look exactly as shown in the following template for the request to work correctly. base64_embed.l2 POST http://httpbin.org/post { \"imageb64_field\": \"'${PHOTO}'\", } Get Source Files","title":"Image as Base64 encoded JSON field"},{"location":"tutorials/examples.html#chain-requests-using-javascript","text":"In Lama2, we have alternating requestor and processor (JS) blocks, separated by --- . Each processor (JS) block has a special variable result , storing the response from previous requestor block. If possible, result is automatically stored as a JS object through JSON.parse() . Otherwise, result is stored as a regular string . url = \"http://google.com\" REMOTE_COORD = \"https://httpbing.org\" --- # stage 1 POST ${REMOTE_COORD}/anything { \"username\": \"admin\", \"password\": \"Password@123\", \"from\": \"${LOCAL_COORD}/anything\", \"url\": \"${url}\", \"Token\": \"MySuperSecretToken\" } --- // filtering, store in var console.log(\"@@Result\", result) let TOKEN = result[\"json\"][\"Token\"] console.log(TOKEN) --- # stage 2 GET ${REMOTE_COORD}/bearer Authorization: 'Bearer ${TOKEN}' {} Get Source Files","title":"Chain requests using Javascript"},{"location":"tutorials/installation.html","text":"Getting Started \u00b6 Installation/Update \u00b6 One-line install/update in Linux/MacOS \u00b6 To install/update Lama2 and its dependencies automatically, run the following: curl -s https://hexmos.com/lama2/install.sh | bash -s One-line install/update in Windows \u00b6 To install/update Lama2 and its dependencies automatically, run the following as Administrator : choco install lama2 --version=1.0.0 --force -y (Optional) Import your collections from Postman \u00b6 Follow guide to import your existing Postman collections into a Plain-Text Lama2 repository. Self update \u00b6 An easier way to update the binary to latest release is through: l2 -u Note Install the VSCode extension to launch requests from within your editor Manual install \u00b6 Step 1: Install HTTPie \u00b6 Lama2 depends on HTTPie for Terminal . Use their official instructions to get the http command functional in your local system. Step 2: Download & install Lama2 binary packages \u00b6 Head over to Lama2 releases . Check under the Assets head to find various packages. Download the relevant package for your operating system and CPU architecture. Once you have the package, run the following: tar --overwrite -xvzf .tar.gz mv l2 /usr/local/bin Build from source \u00b6 Run make in the project root. You'll need to have the following tools in your PATH : go (v1.17+) golangcli-lint gofumpt Also, you'll need to install mkdocs the first time; for that run these: cd docs/Lama2 poetry install # get poetry from https://python-poetry.org/ Once make finishes, find the binary at ./build/l2 . Moreover, you can launch the documentation locally through make serve . Read makefile to find other useful helper commands. How to use \u00b6 From the terminal \u00b6 Type l2 into the terminal. You should get something like: Usage: l2 [OPTIONS] [LamaAPIFile] Application Options: -o, --output= Path to output JSON file to store logs, headers and result -v, --verbose Show verbose debug information -n, --nocolor Disable color in httpie output -e --env Get a JSON of environment variables -h, --help Usage help for Lama2 --version Print Lama2 binary version Help Options: -h, --help Show this help message From VS Code \u00b6 Find Lama2 for VSCode at the VSCode Marketplace . The extension requires the l2 command available (usually at /usr/local/bin/l2 for Linux/MacOS and C:\\ProgramData\\chocolatey\\bin for Windows). Once the extension is installed, open the command palette (ctrl + shift + p) and search for Execute current file to execute the file","title":"Installation"},{"location":"tutorials/installation.html#getting-started","text":"","title":"Getting Started"},{"location":"tutorials/installation.html#installationupdate","text":"","title":"Installation/Update"},{"location":"tutorials/installation.html#one-line-installupdate-in-linuxmacos","text":"To install/update Lama2 and its dependencies automatically, run the following: curl -s https://hexmos.com/lama2/install.sh | bash -s","title":"One-line install/update in Linux/MacOS"},{"location":"tutorials/installation.html#one-line-installupdate-in-windows","text":"To install/update Lama2 and its dependencies automatically, run the following as Administrator : choco install lama2 --version=1.0.0 --force -y","title":"One-line install/update in Windows"},{"location":"tutorials/installation.html#optional-import-your-collections-from-postman","text":"Follow guide to import your existing Postman collections into a Plain-Text Lama2 repository.","title":"(Optional) Import your collections from Postman"},{"location":"tutorials/installation.html#self-update","text":"An easier way to update the binary to latest release is through: l2 -u Note Install the VSCode extension to launch requests from within your editor","title":"Self update"},{"location":"tutorials/installation.html#manual-install","text":"","title":"Manual install"},{"location":"tutorials/installation.html#step-1-install-httpie","text":"Lama2 depends on HTTPie for Terminal . Use their official instructions to get the http command functional in your local system.","title":"Step 1: Install HTTPie"},{"location":"tutorials/installation.html#step-2-download-install-lama2-binary-packages","text":"Head over to Lama2 releases . Check under the Assets head to find various packages. Download the relevant package for your operating system and CPU architecture. Once you have the package, run the following: tar --overwrite -xvzf .tar.gz mv l2 /usr/local/bin","title":"Step 2: Download & install Lama2 binary packages"},{"location":"tutorials/installation.html#build-from-source","text":"Run make in the project root. You'll need to have the following tools in your PATH : go (v1.17+) golangcli-lint gofumpt Also, you'll need to install mkdocs the first time; for that run these: cd docs/Lama2 poetry install # get poetry from https://python-poetry.org/ Once make finishes, find the binary at ./build/l2 . Moreover, you can launch the documentation locally through make serve . Read makefile to find other useful helper commands.","title":"Build from source"},{"location":"tutorials/installation.html#how-to-use","text":"","title":"How to use"},{"location":"tutorials/installation.html#from-the-terminal","text":"Type l2 into the terminal. You should get something like: Usage: l2 [OPTIONS] [LamaAPIFile] Application Options: -o, --output= Path to output JSON file to store logs, headers and result -v, --verbose Show verbose debug information -n, --nocolor Disable color in httpie output -e --env Get a JSON of environment variables -h, --help Usage help for Lama2 --version Print Lama2 binary version Help Options: -h, --help Show this help message","title":"From the terminal"},{"location":"tutorials/installation.html#from-vs-code","text":"Find Lama2 for VSCode at the VSCode Marketplace . The extension requires the l2 command available (usually at /usr/local/bin/l2 for Linux/MacOS and C:\\ProgramData\\chocolatey\\bin for Windows). Once the extension is installed, open the command palette (ctrl + shift + p) and search for Execute current file to execute the file","title":"From VS Code"},{"location":"tutorials/misc.html","text":"Prettify JSON in l2 files \u00b6 Common experience suggests that l2 files tend to be messy when dealing with larger JSON files. So we have developed a targeted prettifier which fixes the JSON portions of an l2 file (if it exists) Usage: l2 -b targetFile.l2","title":"Misc"},{"location":"tutorials/misc.html#prettify-json-in-l2-files","text":"Common experience suggests that l2 files tend to be messy when dealing with larger JSON files. So we have developed a targeted prettifier which fixes the JSON portions of an l2 file (if it exists) Usage: l2 -b targetFile.l2","title":"Prettify JSON in l2 files"},{"location":"tutorials/postman.html","text":"Lama2 ships with a rudimentary converter from Postman to a Plain-Text Lama2 API repository. The converter presently is in an embryonic state and may merely produce approximate results. 1. Export from Postman \u00b6 1.1 Access Settings \u00b6 1.2 Data Export \u00b6 Warning Although postman offers more selective exporting (collection, folder, request levels), Lama2 presently supports only the whole-data export depicted above. The above step must produce a .json file. 2. Convert Postman .json dump into Lama2 API repo \u00b6 Run the following to convert the postman data dump into a Lama2 API structure. l2 -p postman_dump.json -l my_l2output_dir The command will prompt for an environment. Select the environment which you wish to export. Once you pick the option, Lama2 will produce the my_l2output_dir directory filled with the original organizational hierarchy and a bunch of .l2 and l2.env files.","title":"Import Postman"},{"location":"tutorials/postman.html#1-export-from-postman","text":"","title":"1. Export from Postman"},{"location":"tutorials/postman.html#11-access-settings","text":"","title":"1.1 Access Settings"},{"location":"tutorials/postman.html#12-data-export","text":"Warning Although postman offers more selective exporting (collection, folder, request levels), Lama2 presently supports only the whole-data export depicted above. The above step must produce a .json file.","title":"1.2 Data Export"},{"location":"tutorials/postman.html#2-convert-postman-json-dump-into-lama2-api-repo","text":"Run the following to convert the postman data dump into a Lama2 API structure. l2 -p postman_dump.json -l my_l2output_dir The command will prompt for an environment. Select the environment which you wish to export. Once you pick the option, Lama2 will produce the my_l2output_dir directory filled with the original organizational hierarchy and a bunch of .l2 and l2.env files.","title":"2. Convert Postman .json dump into Lama2 API repo"}]} \ No newline at end of file +{"config":{"indexing":"full","lang":["en"],"min_search_length":3,"prebuild_index":false,"separator":"[\\s\\-]+"},"docs":[{"location":"index.html","text":"Lama2 : Plain-Text Powered REST API Client for Teams \u00b6 About \u00b6 Lama2 is a Plain-Text powered REST API client & manager built for serious engineering teams. Lama2 specifies the .l2 syntax for describing APIs, and implements a CLI to execute .l2 files. Engineers collaborate on .l2 files using version control. Lama2 integrates nicely with IDEs and text-editors as well. Think of Lama2 as Markdown for APIs. Benefits \u00b6 Plain-Text files: Store APIs in the Plain-Text .l2 API files. Simple and human-friendly syntax. Learn basics within minutes! Simple CLI: Launch the CLI tool l2 on API files to make REST API requests. Editor support: Invoke Lama2 from your favorite text editor or IDE. Helpful documentation and tool support to build editor extensions included. Longevity & track-ability: Commit .l2 files to git or other version control for long life & change tracking. Collaboration: Share API repo with teammates and colleagues to collaborate Code generation: Convert l2 API definitions into your preferred language/library, be it Python, Javascript, Java or many other options. Powerful chaining: Chain multiple l2 requests through embedded Javascript blocks Documentation: Explore examples, how-tos, explanations, references, FAQ/RAQs, and diagrams. Documentation is a priority, so that you never have to get lost. Extensibility: .l2 syntax is implemented as a recursive descent parser , based on a formal grammar . Dig into details and implement new syntax (ex: to support websockets ) Tip Coming from postman? Let Lama2 help you convert Postman data dumps into a nice Plain-Text Lama2 repo. Terminal Demo: A POST request \u00b6 basic_post.l2 : POST https://httpbin.org/post { \"hello\" : \"world\" } Execute: l2 basic_post.l2 VSCode Demo: The same POST request \u00b6 Community and Support \u00b6 Full documentation @hexmos.com/lama2 Report issues and propose improvements at Github issues Discuss with the community at Discord","title":"Home"},{"location":"index.html#lama2-plain-text-powered-rest-api-client-for-teams","text":"","title":"Lama2: Plain-Text Powered REST API Client for Teams"},{"location":"index.html#about","text":"Lama2 is a Plain-Text powered REST API client & manager built for serious engineering teams. Lama2 specifies the .l2 syntax for describing APIs, and implements a CLI to execute .l2 files. Engineers collaborate on .l2 files using version control. Lama2 integrates nicely with IDEs and text-editors as well. Think of Lama2 as Markdown for APIs.","title":"About"},{"location":"index.html#benefits","text":"Plain-Text files: Store APIs in the Plain-Text .l2 API files. Simple and human-friendly syntax. Learn basics within minutes! Simple CLI: Launch the CLI tool l2 on API files to make REST API requests. Editor support: Invoke Lama2 from your favorite text editor or IDE. Helpful documentation and tool support to build editor extensions included. Longevity & track-ability: Commit .l2 files to git or other version control for long life & change tracking. Collaboration: Share API repo with teammates and colleagues to collaborate Code generation: Convert l2 API definitions into your preferred language/library, be it Python, Javascript, Java or many other options. Powerful chaining: Chain multiple l2 requests through embedded Javascript blocks Documentation: Explore examples, how-tos, explanations, references, FAQ/RAQs, and diagrams. Documentation is a priority, so that you never have to get lost. Extensibility: .l2 syntax is implemented as a recursive descent parser , based on a formal grammar . Dig into details and implement new syntax (ex: to support websockets ) Tip Coming from postman? Let Lama2 help you convert Postman data dumps into a nice Plain-Text Lama2 repo.","title":"Benefits"},{"location":"index.html#terminal-demo-a-post-request","text":"basic_post.l2 : POST https://httpbin.org/post { \"hello\" : \"world\" } Execute: l2 basic_post.l2","title":"Terminal Demo: A POST request"},{"location":"index.html#vscode-demo-the-same-post-request","text":"","title":"VSCode Demo: The same POST request"},{"location":"index.html#community-and-support","text":"Full documentation @hexmos.com/lama2 Report issues and propose improvements at Github issues Discuss with the community at Discord","title":"Community and Support"},{"location":"about/contact.html","text":"Discord \u00b6 Join Hexmos Lama2 discord server to discuss with the community Email \u00b6 Drop an email to shrijith 'at' hexmos.com Github Issues & Discussions \u00b6 Report issues and propose improvements at Github Issues and Github Discussions","title":"Talk to us"},{"location":"about/contact.html#discord","text":"Join Hexmos Lama2 discord server to discuss with the community","title":" Discord"},{"location":"about/contact.html#email","text":"Drop an email to shrijith 'at' hexmos.com","title":" Email"},{"location":"about/contact.html#github-issues-discussions","text":"Report issues and propose improvements at Github Issues and Github Discussions","title":" Github Issues & Discussions"},{"location":"about/hexmos.html","text":"We at Hexmos are deeply concerned about the state of organizations all across the world. We possess firm convictions and aspiration towards improving organizational health across the world . Through deep R&D, good software, relevant tools and techniques, we work to improve organizational health. For a sample of our R&D, check these resources out: Turnover and Other Organizational Ailments : A deeply research-backed exploration into the roots of organizational troubles and their cures, this book assimilates 80+ longitudinal and empirical studies to provide recommendations to improve organizational health. Hexmos Feedback , a tool to provide continuous feedback to your colleagues, so that not a single beneficial thing said or done goes unnoticed","title":"Hexmos"},{"location":"explanation/faq.html","text":"FAQs/RAQs \u00b6 Why pick Javascript as the scripting/glue language? \u00b6 Lama2's design philosophy advocates \"delegate to mature and preferably open tools\". After analysis, we finally picked JS due to following reasons: Most people working with APIs probably already know JS Easy to support XPath/JSONPath or even JQ clones right into JS Even if you don't know any of (2), simple JS object notation + good old loops will take you far Native support for JSON (and dom manipulation is common too, for xml type responses) Good amount of power for implementation effort exerted For simple use cases, one barely has to understand any serious JS. Object/map notation is quite intuitive. Ultimately, we believe JS passes our \"Intern Test\" for usability. What is the Intern Test ? \u00b6 Lama2 API files must remain easy for interns to get used with minimal handholding from more experienced engineers. If it doesn't work for interns, then it doesn't work for our teams at Hexmos as well. Why did you create Lama2 ? \u00b6 At Hexmos , our engineering infrastructure is split into dozens of self-contained software services. We deal with 100s of internal APIs, and so felt a need for a robust workflow for defining, sharing and updating APIs within our teams. Traditional solutions such as Postman/Insomnia implement the collaboration features within their applications, and also tend to charge a fee for collaboration. We felt using git is the right way to collaborate on APIs, rather than any custom built solution. So, in a matter of 2-days we got a regex-based prototype DSL language to store API files. Lots of issues cropped up over time, but we kept making improvements to Lama2 as needs arose. Hexmos accumulated 100s of APIS over time. Then, we decided that the tool deserves to be out there, benefitting teams that want to collaborate on APIs over git . So, to make it happen, first we invested into formalizing the grammar, and implementing the DSL as a hand-written recursive descent parser. Then we invested into helpful documentation, demos and so on. Once we had the basics, we released Lama2 into the world.","title":"FAQ/RAQ"},{"location":"explanation/faq.html#faqsraqs","text":"","title":"FAQs/RAQs"},{"location":"explanation/faq.html#why-pick-javascript-as-the-scriptingglue-language","text":"Lama2's design philosophy advocates \"delegate to mature and preferably open tools\". After analysis, we finally picked JS due to following reasons: Most people working with APIs probably already know JS Easy to support XPath/JSONPath or even JQ clones right into JS Even if you don't know any of (2), simple JS object notation + good old loops will take you far Native support for JSON (and dom manipulation is common too, for xml type responses) Good amount of power for implementation effort exerted For simple use cases, one barely has to understand any serious JS. Object/map notation is quite intuitive. Ultimately, we believe JS passes our \"Intern Test\" for usability.","title":"Why pick Javascript as the scripting/glue language?"},{"location":"explanation/faq.html#what-is-the-intern-test","text":"Lama2 API files must remain easy for interns to get used with minimal handholding from more experienced engineers. If it doesn't work for interns, then it doesn't work for our teams at Hexmos as well.","title":"What is the Intern Test?"},{"location":"explanation/faq.html#why-did-you-create-lama2","text":"At Hexmos , our engineering infrastructure is split into dozens of self-contained software services. We deal with 100s of internal APIs, and so felt a need for a robust workflow for defining, sharing and updating APIs within our teams. Traditional solutions such as Postman/Insomnia implement the collaboration features within their applications, and also tend to charge a fee for collaboration. We felt using git is the right way to collaborate on APIs, rather than any custom built solution. So, in a matter of 2-days we got a regex-based prototype DSL language to store API files. Lots of issues cropped up over time, but we kept making improvements to Lama2 as needs arose. Hexmos accumulated 100s of APIS over time. Then, we decided that the tool deserves to be out there, benefitting teams that want to collaborate on APIs over git . So, to make it happen, first we invested into formalizing the grammar, and implementing the DSL as a hand-written recursive descent parser. Then we invested into helpful documentation, demos and so on. Once we had the basics, we released Lama2 into the world.","title":"Why did you create Lama2?"},{"location":"explanation/l2format.html","text":"Find in this page an informal description of the rules for authoring .l2 API files. This document expects some familiarity with Lama2 . To quickly get started with Lama2 , head over to Examples . On the other hand, if you are a developer and wish to learn more about the formal grammar underlying l2 , visit the Grammar section. Comments start with # \u00b6 Lines starting with # are comments and hence ignored altogether All HTTP Verbs supported - including the common GET/POST/PUT \u00b6 Fully supported: GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH JSON is the default submission type, but MULTIPART is supported too \u00b6 varjson is a simpler syntax to specify flat JSONs \u00b6 varjson values are defined as follows: hello=world foo=bar The above results in a JSON submission of the form: { \"hello\": \"world\", \"foo\": \"bar\" } Nested JSON can simply be dumped at the end of the document \u00b6 The JSON recognition engine is quite lenient. It can deal with minor errors in the format (such as having single quotes instead of double quotes, trailing garbage, or an extra comma after the last element in an array,). POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } MULTIPART allows both file uploads & the usual fields \u00b6 Example: POST MULTIPART http://localhost:8000/register userid=lince5 file@./helloworld.jpg Note The file path is relative to the request file. Cookies are sent as headers \u00b6 Cookies are specified in a Cookie header as follows: Cookie:'sessionid=foo;another-cookie=bar' Environment Variables \u00b6 API variables can be defined in apirequest.l2 \u00b6 Variables are declared within the JS processor block and serve as dynamic placeholders for data used in API requests. By utilizing these variables, L2 enables flexibility and reusability in defining API endpoints and data payloads. Example login.l2 : let REMOTE = \"httpbin.org\" let EMAIL = \"customer1@gmail.com\" --- POST ${REMOTE}/login { \"email\": \"${EMAIL}\", \"password\": \"customer1@gmail.com\" } Get Source Files API environment variables can be defined locally in l2.env \u00b6 L2 provides a convenient way to define environment variables through the l2.env file. This file is automatically searched for in the present directory, and its contents are loaded to create a set of variables (local). In the l2.env file, you can specify environment-specific values for variables used in your L2 scripts, such as URLs, authentication tokens, or any other data that may vary depending on the environment in which the API requests are executed. Go to Example Get Source File API environment variables can be defined at project root using l2config.env \u00b6 The l2config.env file serves as a centralized storage for environment variables located at the project root, streamlining the management of configuration settings across all L2 scripts. With this file present, every L2 script within the project automatically inherits the defined variables, effectively eliminating the necessity to duplicate configurations in individual subdirectories using l2.env . The search for l2config.env extends from the present directory up to the root directory ( / ). During this process, the variables defined in the root file are loaded and made available for use in all relevant scripts. This approach significantly enhances efficiency and maintainability, as it ensures consistent settings throughout the project while reducing redundancy in configuration data. Go to Example Get Source File If l2config.env (root) variables are redeclared in l2.env (local) \u00b6 In situations where both root and local variables share the same variable name, the local variable takes precedence over the root variable. This behavior remains consistent, even if both l2config.env (root) and l2.env (local) files reside in the same directory. The local variable's value will always be considered over the root variable, ensuring that specific configurations defined at the local level effectively override any corresponding settings present in the root file. This approach provides developers with granular control and flexibility in tailoring environment variables to suit specific needs within different parts of the project while maintaining the overall structure and organization of configuration settings. Go to Example Get Source File The environment file can load results of commands \u00b6 Use the backtick notation \\ command`` to place the results of commands into environment variables: export PHOTO=`base64 image.jpeg` One can load the PHOTO variable in API files. Chain requests through Javascript blocks \u00b6 Lama2 supports plain Javascript (JS) blocks as a glue for manipulating responses and passing on values to later stages. At a higher level, a chain of requests may look like: Javascript 1 --- L2 Request 1 --- Javscript 2 --- L2 Request 2 The triple-dash ( --- ) separator is mandatory. The special variable result contains the response from previous stages. For example, in the above case, Javascript 2 can access the response from L2 Request 1 through the result variable. Learn more about request chaining in Examples .","title":"The l2 Format"},{"location":"explanation/l2format.html#comments-start-with","text":"Lines starting with # are comments and hence ignored altogether","title":"Comments start with #"},{"location":"explanation/l2format.html#all-http-verbs-supported-including-the-common-getpostput","text":"Fully supported: GET|HEAD|POST|PUT|DELETE|CONNECT|OPTIONS|TRACE|PATCH","title":"All HTTP Verbs supported - including the common GET/POST/PUT"},{"location":"explanation/l2format.html#json-is-the-default-submission-type-but-multipart-is-supported-too","text":"","title":"JSON is the default submission type, but MULTIPART is supported too"},{"location":"explanation/l2format.html#varjson-is-a-simpler-syntax-to-specify-flat-jsons","text":"varjson values are defined as follows: hello=world foo=bar The above results in a JSON submission of the form: { \"hello\": \"world\", \"foo\": \"bar\" }","title":"varjson is a simpler syntax to specify flat JSONs"},{"location":"explanation/l2format.html#nested-json-can-simply-be-dumped-at-the-end-of-the-document","text":"The JSON recognition engine is quite lenient. It can deal with minor errors in the format (such as having single quotes instead of double quotes, trailing garbage, or an extra comma after the last element in an array,). POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" }","title":"Nested JSON can simply be dumped at the end of the document"},{"location":"explanation/l2format.html#multipart-allows-both-file-uploads-the-usual-fields","text":"Example: POST MULTIPART http://localhost:8000/register userid=lince5 file@./helloworld.jpg Note The file path is relative to the request file.","title":"MULTIPART allows both file uploads & the usual fields"},{"location":"explanation/l2format.html#cookies-are-sent-as-headers","text":"Cookies are specified in a Cookie header as follows: Cookie:'sessionid=foo;another-cookie=bar'","title":"Cookies are sent as headers"},{"location":"explanation/l2format.html#environment-variables","text":"","title":"Environment Variables"},{"location":"explanation/l2format.html#api-variables-can-be-defined-in-apirequestl2","text":"Variables are declared within the JS processor block and serve as dynamic placeholders for data used in API requests. By utilizing these variables, L2 enables flexibility and reusability in defining API endpoints and data payloads. Example login.l2 : let REMOTE = \"httpbin.org\" let EMAIL = \"customer1@gmail.com\" --- POST ${REMOTE}/login { \"email\": \"${EMAIL}\", \"password\": \"customer1@gmail.com\" } Get Source Files","title":"API variables can be defined in apirequest.l2"},{"location":"explanation/l2format.html#api-environment-variables-can-be-defined-locally-in-l2env","text":"L2 provides a convenient way to define environment variables through the l2.env file. This file is automatically searched for in the present directory, and its contents are loaded to create a set of variables (local). In the l2.env file, you can specify environment-specific values for variables used in your L2 scripts, such as URLs, authentication tokens, or any other data that may vary depending on the environment in which the API requests are executed. Go to Example Get Source File","title":"API environment variables can be defined locally in l2.env"},{"location":"explanation/l2format.html#api-environment-variables-can-be-defined-at-project-root-using-l2configenv","text":"The l2config.env file serves as a centralized storage for environment variables located at the project root, streamlining the management of configuration settings across all L2 scripts. With this file present, every L2 script within the project automatically inherits the defined variables, effectively eliminating the necessity to duplicate configurations in individual subdirectories using l2.env . The search for l2config.env extends from the present directory up to the root directory ( / ). During this process, the variables defined in the root file are loaded and made available for use in all relevant scripts. This approach significantly enhances efficiency and maintainability, as it ensures consistent settings throughout the project while reducing redundancy in configuration data. Go to Example Get Source File","title":"API environment variables can be defined at project root using l2config.env"},{"location":"explanation/l2format.html#if-l2configenvroot-variables-are-redeclared-in-l2envlocal","text":"In situations where both root and local variables share the same variable name, the local variable takes precedence over the root variable. This behavior remains consistent, even if both l2config.env (root) and l2.env (local) files reside in the same directory. The local variable's value will always be considered over the root variable, ensuring that specific configurations defined at the local level effectively override any corresponding settings present in the root file. This approach provides developers with granular control and flexibility in tailoring environment variables to suit specific needs within different parts of the project while maintaining the overall structure and organization of configuration settings. Go to Example Get Source File","title":"If l2config.env(root) variables are redeclared in l2.env(local)"},{"location":"explanation/l2format.html#the-environment-file-can-load-results-of-commands","text":"Use the backtick notation \\ command`` to place the results of commands into environment variables: export PHOTO=`base64 image.jpeg` One can load the PHOTO variable in API files.","title":"The environment file can load results of commands"},{"location":"explanation/l2format.html#chain-requests-through-javascript-blocks","text":"Lama2 supports plain Javascript (JS) blocks as a glue for manipulating responses and passing on values to later stages. At a higher level, a chain of requests may look like: Javascript 1 --- L2 Request 1 --- Javscript 2 --- L2 Request 2 The triple-dash ( --- ) separator is mandatory. The special variable result contains the response from previous stages. For example, in the above case, Javascript 2 can access the response from L2 Request 1 through the result variable. Learn more about request chaining in Examples .","title":"Chain requests through Javascript blocks"},{"location":"explanation/syntax.html","text":"The following is the recommended flow for a simple .l2 file. The grammar offers some additional flexibilities in ordering the various components, but it is preferable to stick to the following ordering to help with consistency. Also, for chaining requests , one needs a little bit more syntax -- See Examples %%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD Z(Start) Z --> A A[\"HTTP Verb (get/post/put/delete)\"] --> B[Multipart] C[\"URL (http://blah.com)\"] A --> C B --> C D[\"Headers (header_key: header_value)\"] E{Payload} C --> D D --> E F[\"VarJSON (key=value)\"] G[\"JSON {'key': 'value'}\"] H[\"Multipart files (filename@filepath)\"] E --> F F --> H E --> G I(\"End\") H --> I G --> I","title":"Syntax Guidance"},{"location":"reference/api.html","text":"parser cmdexec cmdgen controller lama2cmd outputmanager preprocess utils","title":"API Reference"},{"location":"reference/architecture.html","text":"Diagram \u00b6 %%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD K[\"Controller Entry
    (controller)\"] A[\"Parse CLI
    (lama2cmd)\"] B[\"Parser
    (parser)\"] D[\"Request Executor
    (cmdexec)\"] E[\"Output Format Manager
    (outputmanager)\"] F[\"Error Reporting (TODO)\"] G[\"Load input & environment vars
    (preprocess)\"] H[\"Request Command Generator
    (cmdgen)\"] I[\"Lama2 Prettifier\"] J[\"Data Importer (importer)\"] L[\"Iterate over blocks
    (controller)\"] M[\"Init Javascript processor VM
    (cmdexec)\"] N[\"Execute JS
    (cmdexec)\"] P[\"Variable expansion (JS + env)
    (preprocess)\"] A --> G A --> J G --> B H --> D K --> A B --> M M --> L L --> |Requestor| P L --> |Processor| N N --> E D --> E B --> F A --> I P --> H L --> L Description \u00b6 From a high level, how does it work now? Read API file Create a tree-like structure based on *gabs.Container Initialize Javascript VM for executing JS blocks For each block If block is JS Processor block Execute JS code in VM Else if block is Requestor block Replace variables with values in the following order Try fetch variable from Javascript VM If (1) fails, try fetch Local env variable from l2.env Try fetch root env variable from l2config.env Use the processed elements to create an httpie-go request Fetch response If necessary, write the last transaction to .json file","title":"Architecture"},{"location":"reference/architecture.html#diagram","text":"%%{init: {'securityLevel': 'loose', 'theme':'base'}}%% graph TD K[\"Controller Entry
    (controller)\"] A[\"Parse CLI
    (lama2cmd)\"] B[\"Parser
    (parser)\"] D[\"Request Executor
    (cmdexec)\"] E[\"Output Format Manager
    (outputmanager)\"] F[\"Error Reporting (TODO)\"] G[\"Load input & environment vars
    (preprocess)\"] H[\"Request Command Generator
    (cmdgen)\"] I[\"Lama2 Prettifier\"] J[\"Data Importer (importer)\"] L[\"Iterate over blocks
    (controller)\"] M[\"Init Javascript processor VM
    (cmdexec)\"] N[\"Execute JS
    (cmdexec)\"] P[\"Variable expansion (JS + env)
    (preprocess)\"] A --> G A --> J G --> B H --> D K --> A B --> M M --> L L --> |Requestor| P L --> |Processor| N N --> E D --> E B --> F A --> I P --> H L --> L","title":"Diagram"},{"location":"reference/architecture.html#description","text":"From a high level, how does it work now? Read API file Create a tree-like structure based on *gabs.Container Initialize Javascript VM for executing JS blocks For each block If block is JS Processor block Execute JS code in VM Else if block is Requestor block Replace variables with values in the following order Try fetch variable from Javascript VM If (1) fails, try fetch Local env variable from l2.env Try fetch root env variable from l2config.env Use the processed elements to create an httpie-go request Fetch response If necessary, write the last transaction to .json file","title":"Description"},{"location":"reference/cmdexec.html","text":"cmdexec \u00b6 import \"github.com/HexmosTech/lama2/cmdexec\" Package `cmdexec` provides a facility to execute l2 commands, stream output to stdout, while also providing ability to retrieve the command output as a string. Index \u00b6 func ExecCommand(cmdSlice []string, stdinBody string, apiDir string) (httpie.ExResponse, error) func GenerateChainCode(httpRespBody string) string func GetJSVm() *goja.Runtime func RunVMCode(jsCode string, vm *goja.Runtime) func ExecCommand \u00b6 func ExecCommand ( cmdSlice [] string , stdinBody string , apiDir string ) ( httpie . ExResponse , error ) ExecCommand changes directory to the given `apiDir` and then executes the command specified in `cmdStr` During command execution, ExecCommand streams output to stdout. Once execution finishes, previous CWD is restored, and the command output is returned as a string func GenerateChainCode \u00b6 func GenerateChainCode ( httpRespBody string ) string GenerateChainCode takes in an HTTP response body and comes up with some JS code to define the \"magic variable\" result. What does the code do? The result is stored as a JS object, if the input value can be parsed as JSON. Otherwise the value is stored as a simple string. func GetJSVm \u00b6 func GetJSVm () * goja . Runtime GetJSVm creates a new goja runtime instance with console.log enabled func RunVMCode \u00b6 func RunVMCode ( jsCode string , vm * goja . Runtime ) RunVMCode takes in a JS snippet as a string, executes the code in a JS VM, finally checks whether there are any errors, and if yes, logs the problem. Note: the vm runtime remains modified; so if you reuse the vm for other operations, the state from previous invocations carry over Generated by gomarkdoc","title":"Cmdexec"},{"location":"reference/cmdexec.html#cmdexec","text":"import \"github.com/HexmosTech/lama2/cmdexec\" Package `cmdexec` provides a facility to execute l2 commands, stream output to stdout, while also providing ability to retrieve the command output as a string.","title":"cmdexec"},{"location":"reference/cmdexec.html#index","text":"func ExecCommand(cmdSlice []string, stdinBody string, apiDir string) (httpie.ExResponse, error) func GenerateChainCode(httpRespBody string) string func GetJSVm() *goja.Runtime func RunVMCode(jsCode string, vm *goja.Runtime)","title":"Index"},{"location":"reference/cmdexec.html#func-execcommand","text":"func ExecCommand ( cmdSlice [] string , stdinBody string , apiDir string ) ( httpie . ExResponse , error ) ExecCommand changes directory to the given `apiDir` and then executes the command specified in `cmdStr` During command execution, ExecCommand streams output to stdout. Once execution finishes, previous CWD is restored, and the command output is returned as a string","title":"func ExecCommand"},{"location":"reference/cmdexec.html#func-generatechaincode","text":"func GenerateChainCode ( httpRespBody string ) string GenerateChainCode takes in an HTTP response body and comes up with some JS code to define the \"magic variable\" result. What does the code do? The result is stored as a JS object, if the input value can be parsed as JSON. Otherwise the value is stored as a simple string.","title":"func GenerateChainCode"},{"location":"reference/cmdexec.html#func-getjsvm","text":"func GetJSVm () * goja . Runtime GetJSVm creates a new goja runtime instance with console.log enabled","title":"func GetJSVm"},{"location":"reference/cmdexec.html#func-runvmcode","text":"func RunVMCode ( jsCode string , vm * goja . Runtime ) RunVMCode takes in a JS snippet as a string, executes the code in a JS VM, finally checks whether there are any errors, and if yes, logs the problem. Note: the vm runtime remains modified; so if you reuse the vm for other operations, the state from previous invocations carry over Generated by gomarkdoc","title":"func RunVMCode"},{"location":"reference/cmdgen.html","text":"cmdgen \u00b6 import \"github.com/HexmosTech/lama2/cmdgen\" Package `cmdgen` provides an API to generate API request commands (by default based on HTTPie) based on the parsed API file contents and the `l2` command invocation parameters Index \u00b6 func ConstructCommand(parsedInput *gabs.Container, o *lama2cmd.Opts) ([]string, string) func ConstructCommand \u00b6 func ConstructCommand ( parsedInput * gabs . Container , o * lama2cmd . Opts ) ([] string , string ) ConstructCommand extracts the HTTP verb, url and other API file inputs, figures out the type of target command and finally generates a string representing the generated command Generated by gomarkdoc","title":"Cmdgen"},{"location":"reference/cmdgen.html#cmdgen","text":"import \"github.com/HexmosTech/lama2/cmdgen\" Package `cmdgen` provides an API to generate API request commands (by default based on HTTPie) based on the parsed API file contents and the `l2` command invocation parameters","title":"cmdgen"},{"location":"reference/cmdgen.html#index","text":"func ConstructCommand(parsedInput *gabs.Container, o *lama2cmd.Opts) ([]string, string)","title":"Index"},{"location":"reference/cmdgen.html#func-constructcommand","text":"func ConstructCommand ( parsedInput * gabs . Container , o * lama2cmd . Opts ) ([] string , string ) ConstructCommand extracts the HTTP verb, url and other API file inputs, figures out the type of target command and finally generates a string representing the generated command Generated by gomarkdoc","title":"func ConstructCommand"},{"location":"reference/controller.html","text":"contoller \u00b6 import \"github.com/HexmosTech/lama2/controller\" Package controller coordinates all the other components in the `Lama2` project. The high level overview of command execution is easily understood from this package Index \u00b6 func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) func Process(version string) func ExecuteProcessorBlock \u00b6 func ExecuteProcessorBlock ( block * gabs . Container , vm * goja . Runtime ) func ExecuteRequestorBlock \u00b6 func ExecuteRequestorBlock ( block * gabs . Container , vm * goja . Runtime , opts * lama2cmd . Opts , dir string ) httpie . ExResponse func GetParsedAPIBlocks \u00b6 func GetParsedAPIBlocks ( parsedAPI * gabs . Container ) [] * gabs . Container func HandleParsedFile \u00b6 func HandleParsedFile ( parsedAPI * gabs . Container , o * lama2cmd . Opts , dir string ) func Process \u00b6 func Process ( version string ) Process initiates the following tasks in the given order: 1. Parse command line arguments 2. Read API file contents 3. Expand environment variables in API file 4. Parse the API contents 5. Generate API request command 6. Execute command & retrieve results 7. Optionally, post-process and write results to a JSON file Generated by gomarkdoc","title":"Controller"},{"location":"reference/controller.html#contoller","text":"import \"github.com/HexmosTech/lama2/controller\" Package controller coordinates all the other components in the `Lama2` project. The high level overview of command execution is easily understood from this package","title":"contoller"},{"location":"reference/controller.html#index","text":"func ExecuteProcessorBlock(block *gabs.Container, vm *goja.Runtime) func ExecuteRequestorBlock(block *gabs.Container, vm *goja.Runtime, opts *lama2cmd.Opts, dir string) httpie.ExResponse func GetParsedAPIBlocks(parsedAPI *gabs.Container) []*gabs.Container func HandleParsedFile(parsedAPI *gabs.Container, o *lama2cmd.Opts, dir string) func Process(version string)","title":"Index"},{"location":"reference/controller.html#func-executeprocessorblock","text":"func ExecuteProcessorBlock ( block * gabs . Container , vm * goja . Runtime )","title":"func ExecuteProcessorBlock"},{"location":"reference/controller.html#func-executerequestorblock","text":"func ExecuteRequestorBlock ( block * gabs . Container , vm * goja . Runtime , opts * lama2cmd . Opts , dir string ) httpie . ExResponse","title":"func ExecuteRequestorBlock"},{"location":"reference/controller.html#func-getparsedapiblocks","text":"func GetParsedAPIBlocks ( parsedAPI * gabs . Container ) [] * gabs . Container","title":"func GetParsedAPIBlocks"},{"location":"reference/controller.html#func-handleparsedfile","text":"func HandleParsedFile ( parsedAPI * gabs . Container , o * lama2cmd . Opts , dir string )","title":"func HandleParsedFile"},{"location":"reference/controller.html#func-process","text":"func Process ( version string ) Process initiates the following tasks in the given order: 1. Parse command line arguments 2. Read API file contents 3. Expand environment variables in API file 4. Parse the API contents 5. Generate API request command 6. Execute command & retrieve results 7. Optionally, post-process and write results to a JSON file Generated by gomarkdoc","title":"func Process"},{"location":"reference/grammar.html","text":"Grammar \u00b6 What follows is a rough rendition of the Lama2 grammar, followed by a visual exploration of the grammar in the railroad diagram format (thanks to Railroad Diagram Generator ) EBNF Description \u00b6 Lama2File ::= (Proceessor Separator)? Requestor (Separator Processor Separator Requestor)* Separator ::= `^---$` Processor ::= `(?!(get|post|head|put|delete|connect|trace|patch))` Requestor ::= HTTPVerb Multipart? TheURL Details? HTTPVerb ::= \"get\" | \"head\" | \"post\" | \"put\" | \"delete\" | \"connect\" | \"trace\" | \"patch\" Multipart ::= \"multipart\" TheURL ::= \"http\" \"s\"? \"://\" [A-Za-z0-9-._~:/?#[@!$&'()*+,;%=]+ /* ws: explicit */ Details ::= HeaderData | DataHeader HeaderData ::= Headers DataInput? DataHeader ::= DataInput Headers? Headers ::= HeaderPair HeaderPair* HeaderPair ::= (QuotedString | Unquoted) \":\" (QuotedString | Unquoted) DataInput ::= VarJSON | JSONType VarJSON ::= VarJSONPair VarJSONPair* FilesPair? VarJSONPair ::= (QuotedString | VarJSONUnquoted) \"=\" (QuotedString | VarJSONUnquoted) FilesPair ::= FilesPair FilesPair* FilesPair ::= (QuotedString | FilesUnquoted) \"@\" (QuotedString | FilesUnquoted) VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ QuotedString ::= ['\"] Char* ['\"] Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~-]+ /* ws: explicit */ JSONType ::= ComplexType | PrimitiveType ComplexType ::= List | Map PrimitiveType ::= Null | Boolean | QuotedString | Number Map ::= \"{\" Pair? (Pair \",\")* \"}\" List ::= \"[\" JSONType? (JSONType \",\")* \"]\" Pair ::= QuotedString \":\" JSONType Boolean ::= \"true\" | \"false\" Null ::= \"null\" Number ::= Integer Fraction? Exponent? Exponent ::= [eE] Sign? Digits Fraction ::= \".\" Digits Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 IntegerRule1 ::= Digit IntegerRule2 ::= OneNine Digits IntegerRule3 ::= Sign IntegerRule1 IntegerRule4 ::= Sign IntegerRule2 Digits ::= Digit Digit* Digit ::= \"0\"? OneNine OneNine ::= [1-9] Sign ::= [-+] Railroad Diagram \u00b6 ::-moz-selection { color: #FFFCF0; background: #0F0C00; } ::selection { color: #FFFCF0; background: #0F0C00; } .ebnf a, .grammar a { text-decoration: none; } .ebnf a:hover, .grammar a:hover { color: #050400; text-decoration: underline; } .signature { color: #806600; font-size: 11px; text-align: right; } body { font: normal 12px Verdana, sans-serif; color: #0F0C00; background: #FFFCF0; } a:link, a:visited { color: #0F0C00; } a:link.signature, a:visited.signature { color: #806600; } a.button, #tabs li a { padding: 0.25em 0.5em; border: 1px solid #806600; background: #F1E8C6; color: #806600; text-decoration: none; font-weight: bold; } a.button:hover, #tabs li a:hover { color: #050400; background: #FFF6D1; border-color: #050400; } #tabs { padding: 3px 10px; margin-left: 0; margin-top: 58px; border-bottom: 1px solid #0F0C00; } #tabs li { list-style: none; margin-left: 5px; display: inline; } #tabs li a { border-bottom: 1px solid #0F0C00; } #tabs li a.active { color: #0F0C00; background: #FFFCF0; border-color: #0F0C00; border-bottom: 1px solid #FFFCF0; outline: none; } #divs div { display: none; overflow:auto; } #divs div.active { display: block; } #text { border-color: #806600; background: #FFFEFA; color: #050400; } .small { vertical-align: top; text-align: right; font-size: 9px; font-weight: normal; line-height: 120%; } td.small { padding-top: 0px; } .hidden { visibility: hidden; } td:hover .hidden { visibility: visible; } div.download { display: none; background: #FFFCF0; position: absolute; right: 34px; top: 94px; padding: 10px; border: 1px dotted #0F0C00; } #divs div.ebnf, .ebnf code { display: block; padding: 10px; background: #FFF6D1; width: 992px; } #divs div.grammar { display: block; padding-left: 16px; padding-top: 2px; padding-bottom: 2px; background: #FFF6D1; } pre { margin: 0px; } .ebnf div { padding-left: 13ch; text-indent: -13ch; } .ebnf code, .grammar code, textarea, pre { font:12px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; } tr.option-line td:first-child { text-align: right } tr.option-text td { padding-bottom: 10px } table.palette { border-top: 1px solid #050400; border-right: 1px solid #050400; margin-bottom: 4px } td.palette { border-bottom: 1px solid #050400; border-left: 1px solid #050400; } a.palette { padding: 2px 3px 2px 10px; text-decoration: none; } .palette { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; } @namespace \"http://www.w3.org/2000/svg\"; .line {fill: none; stroke: #332900; stroke-width: 1;} .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2;} .thin-line {stroke: #1F1800; shape-rendering: crispEdges} .filled {fill: #332900; stroke: none;} text.terminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #141000; font-weight: bold; } text.nonterminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1A1400; font-weight: normal; } text.regexp {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1F1800; font-weight: normal; } rect, circle, polygon {fill: #332900; stroke: #332900;} rect.terminal {fill: #FFDB4D; stroke: #332900; stroke-width: 1;} rect.nonterminal {fill: #FFEC9E; stroke: #332900; stroke-width: 1;} rect.text {fill: none; stroke: none;} polygon.regexp {fill: #FFF4C7; stroke: #332900; stroke-width: 1;} Lama2File: Proceessor Separator Requestor Separator Processor Separator Lama2File ::= ( Proceessor Separator )? Requestor ( Separator Processor Separator Requestor )* no references Separator: --- Separator ::= '---' referenced by: Lama2File Processor: (?!(get|post|head|put|delete|connect|trace|patch)) Processor ::= '(?!(get|post|head|put|delete|connect|trace|patch))' referenced by: Lama2File Requestor: HTTPVerb Multipart TheURL Details Requestor ::= HTTPVerb Multipart ? TheURL Details ? referenced by: Lama2File HTTPVerb: get head post put delete connect trace patch HTTPVerb ::= 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'trace' | 'patch' referenced by: Requestor Multipart: multipart Multipart ::= 'multipart' referenced by: Requestor TheURL: http s :// [A-Z] [a-z] [0-9] - . _ ~ : / ? # [ @ ! $ & ' ( ) * + , ; % = TheURL ::= 'http' 's'? '://' [A-Za-z0-9._~:/?[@!$&'()*+,;%=#x2D#x23]+ /* ws: explicit */ referenced by: Requestor Details: HeaderData DataHeader Details ::= HeaderData | DataHeader referenced by: Requestor HeaderData: Headers DataInput HeaderData ::= Headers DataInput ? referenced by: Details DataHeader: DataInput Headers DataHeader ::= DataInput Headers ? referenced by: Details Headers: HeaderPair Headers ::= HeaderPair HeaderPair * referenced by: DataHeader HeaderData HeaderPair: QuotedString Unquoted : QuotedString Unquoted HeaderPair ::= ( QuotedString | Unquoted ) ':' ( QuotedString | Unquoted ) referenced by: Headers DataInput: VarJSON JSONType DataInput ::= VarJSON | JSONType referenced by: DataHeader HeaderData VarJSON: VarJSONPair FilesPair VarJSON ::= VarJSONPair VarJSONPair * FilesPair ? referenced by: DataInput VarJSONPair: QuotedString VarJSONUnquoted = QuotedString VarJSONUnquoted VarJSONPair ::= ( QuotedString | VarJSONUnquoted ) '=' ( QuotedString | VarJSONUnquoted ) referenced by: VarJSON FilesPair: FilesPair QuotedString FilesUnquoted @ QuotedString FilesUnquoted FilesPair ::= FilesPair FilesPair * | ( QuotedString | FilesUnquoted ) '@' ( QuotedString | FilesUnquoted ) referenced by: FilesPair VarJSON VarJSONUnquoted: @ [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: VarJSONPair FilesUnquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: FilesPair QuotedString: ' \" Char ' \" QuotedString ::= ['\"] Char * ['\"] referenced by: FilesPair HeaderPair Pair PrimitiveType VarJSONPair Unquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < = > ? ^ _ ` | ~ - Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~#x2D]+ /* ws: explicit */ referenced by: HeaderPair JSONType: ComplexType PrimitiveType JSONType ::= ComplexType | PrimitiveType referenced by: DataInput List Pair ComplexType: List Map ComplexType ::= List | Map referenced by: JSONType PrimitiveType: Null Boolean QuotedString Number PrimitiveType ::= Null | Boolean | QuotedString | Number referenced by: JSONType Map: { Pair Pair , } Map ::= '{' Pair ? ( Pair ',' )* '}' referenced by: ComplexType List: [ JSONType JSONType , ] List ::= '[' JSONType ? ( JSONType ',' )* ']' referenced by: ComplexType Pair: QuotedString : JSONType Pair ::= QuotedString ':' JSONType referenced by: Map Boolean: true false Boolean ::= 'true' | 'false' referenced by: PrimitiveType Null: null Null ::= 'null' referenced by: PrimitiveType Number: Integer Fraction Exponent Number ::= Integer Fraction ? Exponent ? referenced by: PrimitiveType Exponent: e E Sign Digits Exponent ::= [eE] Sign ? Digits referenced by: Number Fraction: . Digits Fraction ::= '.' Digits referenced by: Number Integer: IntegerRule4 IntegerRule3 IntegerRule2 IntegerRule1 Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 referenced by: Number IntegerRule1: Digit IntegerRule1 ::= Digit referenced by: Integer IntegerRule3 IntegerRule2: OneNine Digits IntegerRule2 ::= OneNine Digits referenced by: Integer IntegerRule4 IntegerRule3: Sign IntegerRule1 IntegerRule3 ::= Sign IntegerRule1 referenced by: Integer IntegerRule4: Sign IntegerRule2 IntegerRule4 ::= Sign IntegerRule2 referenced by: Integer Digits: Digit Digits ::= Digit Digit * referenced by: Exponent Fraction IntegerRule2 Digit: 0 OneNine Digit ::= '0'? OneNine referenced by: Digits IntegerRule1 OneNine: [1-9] OneNine ::= [1-9] referenced by: Digit IntegerRule2 Sign: - + Sign ::= [-+] referenced by: Exponent IntegerRule3 IntegerRule4 ... generated by RR - Railroad Diagram Generator R R","title":"Formal Grammar"},{"location":"reference/grammar.html#grammar","text":"What follows is a rough rendition of the Lama2 grammar, followed by a visual exploration of the grammar in the railroad diagram format (thanks to Railroad Diagram Generator )","title":"Grammar"},{"location":"reference/grammar.html#ebnf-description","text":"Lama2File ::= (Proceessor Separator)? Requestor (Separator Processor Separator Requestor)* Separator ::= `^---$` Processor ::= `(?!(get|post|head|put|delete|connect|trace|patch))` Requestor ::= HTTPVerb Multipart? TheURL Details? HTTPVerb ::= \"get\" | \"head\" | \"post\" | \"put\" | \"delete\" | \"connect\" | \"trace\" | \"patch\" Multipart ::= \"multipart\" TheURL ::= \"http\" \"s\"? \"://\" [A-Za-z0-9-._~:/?#[@!$&'()*+,;%=]+ /* ws: explicit */ Details ::= HeaderData | DataHeader HeaderData ::= Headers DataInput? DataHeader ::= DataInput Headers? Headers ::= HeaderPair HeaderPair* HeaderPair ::= (QuotedString | Unquoted) \":\" (QuotedString | Unquoted) DataInput ::= VarJSON | JSONType VarJSON ::= VarJSONPair VarJSONPair* FilesPair? VarJSONPair ::= (QuotedString | VarJSONUnquoted) \"=\" (QuotedString | VarJSONUnquoted) FilesPair ::= FilesPair FilesPair* FilesPair ::= (QuotedString | FilesUnquoted) \"@\" (QuotedString | FilesUnquoted) VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~-]+ /* ws: explicit */ QuotedString ::= ['\"] Char* ['\"] Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~-]+ /* ws: explicit */ JSONType ::= ComplexType | PrimitiveType ComplexType ::= List | Map PrimitiveType ::= Null | Boolean | QuotedString | Number Map ::= \"{\" Pair? (Pair \",\")* \"}\" List ::= \"[\" JSONType? (JSONType \",\")* \"]\" Pair ::= QuotedString \":\" JSONType Boolean ::= \"true\" | \"false\" Null ::= \"null\" Number ::= Integer Fraction? Exponent? Exponent ::= [eE] Sign? Digits Fraction ::= \".\" Digits Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 IntegerRule1 ::= Digit IntegerRule2 ::= OneNine Digits IntegerRule3 ::= Sign IntegerRule1 IntegerRule4 ::= Sign IntegerRule2 Digits ::= Digit Digit* Digit ::= \"0\"? OneNine OneNine ::= [1-9] Sign ::= [-+]","title":"EBNF Description"},{"location":"reference/grammar.html#railroad-diagram","text":"::-moz-selection { color: #FFFCF0; background: #0F0C00; } ::selection { color: #FFFCF0; background: #0F0C00; } .ebnf a, .grammar a { text-decoration: none; } .ebnf a:hover, .grammar a:hover { color: #050400; text-decoration: underline; } .signature { color: #806600; font-size: 11px; text-align: right; } body { font: normal 12px Verdana, sans-serif; color: #0F0C00; background: #FFFCF0; } a:link, a:visited { color: #0F0C00; } a:link.signature, a:visited.signature { color: #806600; } a.button, #tabs li a { padding: 0.25em 0.5em; border: 1px solid #806600; background: #F1E8C6; color: #806600; text-decoration: none; font-weight: bold; } a.button:hover, #tabs li a:hover { color: #050400; background: #FFF6D1; border-color: #050400; } #tabs { padding: 3px 10px; margin-left: 0; margin-top: 58px; border-bottom: 1px solid #0F0C00; } #tabs li { list-style: none; margin-left: 5px; display: inline; } #tabs li a { border-bottom: 1px solid #0F0C00; } #tabs li a.active { color: #0F0C00; background: #FFFCF0; border-color: #0F0C00; border-bottom: 1px solid #FFFCF0; outline: none; } #divs div { display: none; overflow:auto; } #divs div.active { display: block; } #text { border-color: #806600; background: #FFFEFA; color: #050400; } .small { vertical-align: top; text-align: right; font-size: 9px; font-weight: normal; line-height: 120%; } td.small { padding-top: 0px; } .hidden { visibility: hidden; } td:hover .hidden { visibility: visible; } div.download { display: none; background: #FFFCF0; position: absolute; right: 34px; top: 94px; padding: 10px; border: 1px dotted #0F0C00; } #divs div.ebnf, .ebnf code { display: block; padding: 10px; background: #FFF6D1; width: 992px; } #divs div.grammar { display: block; padding-left: 16px; padding-top: 2px; padding-bottom: 2px; background: #FFF6D1; } pre { margin: 0px; } .ebnf div { padding-left: 13ch; text-indent: -13ch; } .ebnf code, .grammar code, textarea, pre { font:12px SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace; } tr.option-line td:first-child { text-align: right } tr.option-text td { padding-bottom: 10px } table.palette { border-top: 1px solid #050400; border-right: 1px solid #050400; margin-bottom: 4px } td.palette { border-bottom: 1px solid #050400; border-left: 1px solid #050400; } a.palette { padding: 2px 3px 2px 10px; text-decoration: none; } .palette { -webkit-user-select: none; -khtml-user-select: none; -moz-user-select: none; -o-user-select: none; -ms-user-select: none; } @namespace \"http://www.w3.org/2000/svg\"; .line {fill: none; stroke: #332900; stroke-width: 1;} .bold-line {stroke: #141000; shape-rendering: crispEdges; stroke-width: 2;} .thin-line {stroke: #1F1800; shape-rendering: crispEdges} .filled {fill: #332900; stroke: none;} text.terminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #141000; font-weight: bold; } text.nonterminal {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1A1400; font-weight: normal; } text.regexp {font-family: Verdana, Sans-serif; font-size: 12px; fill: #1F1800; font-weight: normal; } rect, circle, polygon {fill: #332900; stroke: #332900;} rect.terminal {fill: #FFDB4D; stroke: #332900; stroke-width: 1;} rect.nonterminal {fill: #FFEC9E; stroke: #332900; stroke-width: 1;} rect.text {fill: none; stroke: none;} polygon.regexp {fill: #FFF4C7; stroke: #332900; stroke-width: 1;} Lama2File: Proceessor Separator Requestor Separator Processor Separator Lama2File ::= ( Proceessor Separator )? Requestor ( Separator Processor Separator Requestor )* no references Separator: --- Separator ::= '---' referenced by: Lama2File Processor: (?!(get|post|head|put|delete|connect|trace|patch)) Processor ::= '(?!(get|post|head|put|delete|connect|trace|patch))' referenced by: Lama2File Requestor: HTTPVerb Multipart TheURL Details Requestor ::= HTTPVerb Multipart ? TheURL Details ? referenced by: Lama2File HTTPVerb: get head post put delete connect trace patch HTTPVerb ::= 'get' | 'head' | 'post' | 'put' | 'delete' | 'connect' | 'trace' | 'patch' referenced by: Requestor Multipart: multipart Multipart ::= 'multipart' referenced by: Requestor TheURL: http s :// [A-Z] [a-z] [0-9] - . _ ~ : / ? # [ @ ! $ & ' ( ) * + , ; % = TheURL ::= 'http' 's'? '://' [A-Za-z0-9._~:/?[@!$&'()*+,;%=#x2D#x23]+ /* ws: explicit */ referenced by: Requestor Details: HeaderData DataHeader Details ::= HeaderData | DataHeader referenced by: Requestor HeaderData: Headers DataInput HeaderData ::= Headers DataInput ? referenced by: Details DataHeader: DataInput Headers DataHeader ::= DataInput Headers ? referenced by: Details Headers: HeaderPair Headers ::= HeaderPair HeaderPair * referenced by: DataHeader HeaderData HeaderPair: QuotedString Unquoted : QuotedString Unquoted HeaderPair ::= ( QuotedString | Unquoted ) ':' ( QuotedString | Unquoted ) referenced by: Headers DataInput: VarJSON JSONType DataInput ::= VarJSON | JSONType referenced by: DataHeader HeaderData VarJSON: VarJSONPair FilesPair VarJSON ::= VarJSONPair VarJSONPair * FilesPair ? referenced by: DataInput VarJSONPair: QuotedString VarJSONUnquoted = QuotedString VarJSONUnquoted VarJSONPair ::= ( QuotedString | VarJSONUnquoted ) '=' ( QuotedString | VarJSONUnquoted ) referenced by: VarJSON FilesPair: FilesPair QuotedString FilesUnquoted @ QuotedString FilesUnquoted FilesPair ::= FilesPair FilesPair * | ( QuotedString | FilesUnquoted ) '@' ( QuotedString | FilesUnquoted ) referenced by: FilesPair VarJSON VarJSONUnquoted: @ [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - VarJSONUnquoted ::= [@0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: VarJSONPair FilesUnquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < > ? ^ _ ` | ~ - FilesUnquoted ::= [0-9A-Za-z \\t!$%&()*+./;<>?^_`|~#x2D]+ /* ws: explicit */ referenced by: FilesPair QuotedString: ' \" Char ' \" QuotedString ::= ['\"] Char * ['\"] referenced by: FilesPair HeaderPair Pair PrimitiveType VarJSONPair Unquoted: [0-9] [A-Z] [a-z] \\ t ! $ % & ( ) * + . / ; < = > ? ^ _ ` | ~ - Unquoted ::= [0-9A-Za-z \\t!$%&()*+./;<=>?^_`|~#x2D]+ /* ws: explicit */ referenced by: HeaderPair JSONType: ComplexType PrimitiveType JSONType ::= ComplexType | PrimitiveType referenced by: DataInput List Pair ComplexType: List Map ComplexType ::= List | Map referenced by: JSONType PrimitiveType: Null Boolean QuotedString Number PrimitiveType ::= Null | Boolean | QuotedString | Number referenced by: JSONType Map: { Pair Pair , } Map ::= '{' Pair ? ( Pair ',' )* '}' referenced by: ComplexType List: [ JSONType JSONType , ] List ::= '[' JSONType ? ( JSONType ',' )* ']' referenced by: ComplexType Pair: QuotedString : JSONType Pair ::= QuotedString ':' JSONType referenced by: Map Boolean: true false Boolean ::= 'true' | 'false' referenced by: PrimitiveType Null: null Null ::= 'null' referenced by: PrimitiveType Number: Integer Fraction Exponent Number ::= Integer Fraction ? Exponent ? referenced by: PrimitiveType Exponent: e E Sign Digits Exponent ::= [eE] Sign ? Digits referenced by: Number Fraction: . Digits Fraction ::= '.' Digits referenced by: Number Integer: IntegerRule4 IntegerRule3 IntegerRule2 IntegerRule1 Integer ::= IntegerRule4 | IntegerRule3 | IntegerRule2 | IntegerRule1 referenced by: Number IntegerRule1: Digit IntegerRule1 ::= Digit referenced by: Integer IntegerRule3 IntegerRule2: OneNine Digits IntegerRule2 ::= OneNine Digits referenced by: Integer IntegerRule4 IntegerRule3: Sign IntegerRule1 IntegerRule3 ::= Sign IntegerRule1 referenced by: Integer IntegerRule4: Sign IntegerRule2 IntegerRule4 ::= Sign IntegerRule2 referenced by: Integer Digits: Digit Digits ::= Digit Digit * referenced by: Exponent Fraction IntegerRule2 Digit: 0 OneNine Digit ::= '0'? OneNine referenced by: Digits IntegerRule1 OneNine: [1-9] OneNine ::= [1-9] referenced by: Digit IntegerRule2 Sign: - + Sign ::= [-+] referenced by: Exponent IntegerRule3 IntegerRule4 ... generated by RR - Railroad Diagram Generator R R","title":"Railroad Diagram"},{"location":"reference/lama2cmd.html","text":"lama2cmd \u00b6 import \"github.com/HexmosTech/lama2/lama2cmd\" Package `lama2cmd` provides CLI argument parsing facilities. It hosts the `Opts` structure to record user intentions Index \u00b6 func ArgParsing(o *Opts, version string) type Opts func GetAndValidateCmd(ipArgs []string) *Opts func ArgParsing \u00b6 func ArgParsing ( o * Opts , version string ) type Opts \u00b6 The Opts structure stores user preferences, and is used throughout the module to make various decisions. type Opts struct { Output string `short:\"o\" long:\"output\" description:\"Path to output JSON file to store logs, headers and result\"` Verbose [] bool `short:\"v\" long:\"verbose\" description:\"Show verbose debug information\"` Prettify bool `short:\"b\" long:\"prettify\" description:\"Prettify specified .l2 file\"` // Sort bool `short:\"s\" long:\"sort\" description:\"Sort specification into recommended order\"` Convert string `short:\"c\" long:\"convert\" description:\"Generate code in given language and library (ex: python.requests); reference: tinyurl.com/l2codegen\"` Nocolor bool `short:\"n\" long:\"nocolor\" description:\"Disable color in httpie output\"` Update bool `short:\"u\" long:\"update\" description:\"Update l2 binary to the latest released version (Linux/MacOS only)\"` PostmanFile string `short:\"p\" long:\"postmanfile\" description:\"JSON export from Postman (Settings -> Data -> Export Data)\"` LamaDir string `short:\"l\" long:\"lama2dir\" description:\"Output directory to put .l2 files after conversion from Postman format\"` Help bool `short:\"h\" long:\"help\" group:\"AddHelp\" description:\"Usage help for Lama2\"` Env string `short:\"e\" long:\"env\" description:\"Get a JSON of environment variables revelant to input arg\"` Version bool `long:\"version\" description:\"Print Lama2 binary version\"` Positional struct { LamaAPIFile string } `positional-args:\"yes\"` } func GetAndValidateCmd \u00b6 func GetAndValidateCmd ( ipArgs [] string ) * Opts GetAndValidateCmd takes in the user's CLI input, and checks for validity. If not OK, displays a help message in stdout. Otherwise, fills the Opts structure and returns it Moreover, based on user input, the outputManager gets configured (whether user prefers trace/debug/info level) Generated by gomarkdoc","title":"Lama2cmd"},{"location":"reference/lama2cmd.html#lama2cmd","text":"import \"github.com/HexmosTech/lama2/lama2cmd\" Package `lama2cmd` provides CLI argument parsing facilities. It hosts the `Opts` structure to record user intentions","title":"lama2cmd"},{"location":"reference/lama2cmd.html#index","text":"func ArgParsing(o *Opts, version string) type Opts func GetAndValidateCmd(ipArgs []string) *Opts","title":"Index"},{"location":"reference/lama2cmd.html#func-argparsing","text":"func ArgParsing ( o * Opts , version string )","title":"func ArgParsing"},{"location":"reference/lama2cmd.html#type-opts","text":"The Opts structure stores user preferences, and is used throughout the module to make various decisions. type Opts struct { Output string `short:\"o\" long:\"output\" description:\"Path to output JSON file to store logs, headers and result\"` Verbose [] bool `short:\"v\" long:\"verbose\" description:\"Show verbose debug information\"` Prettify bool `short:\"b\" long:\"prettify\" description:\"Prettify specified .l2 file\"` // Sort bool `short:\"s\" long:\"sort\" description:\"Sort specification into recommended order\"` Convert string `short:\"c\" long:\"convert\" description:\"Generate code in given language and library (ex: python.requests); reference: tinyurl.com/l2codegen\"` Nocolor bool `short:\"n\" long:\"nocolor\" description:\"Disable color in httpie output\"` Update bool `short:\"u\" long:\"update\" description:\"Update l2 binary to the latest released version (Linux/MacOS only)\"` PostmanFile string `short:\"p\" long:\"postmanfile\" description:\"JSON export from Postman (Settings -> Data -> Export Data)\"` LamaDir string `short:\"l\" long:\"lama2dir\" description:\"Output directory to put .l2 files after conversion from Postman format\"` Help bool `short:\"h\" long:\"help\" group:\"AddHelp\" description:\"Usage help for Lama2\"` Env string `short:\"e\" long:\"env\" description:\"Get a JSON of environment variables revelant to input arg\"` Version bool `long:\"version\" description:\"Print Lama2 binary version\"` Positional struct { LamaAPIFile string } `positional-args:\"yes\"` }","title":"type Opts"},{"location":"reference/lama2cmd.html#func-getandvalidatecmd","text":"func GetAndValidateCmd ( ipArgs [] string ) * Opts GetAndValidateCmd takes in the user's CLI input, and checks for validity. If not OK, displays a help message in stdout. Otherwise, fills the Opts structure and returns it Moreover, based on user input, the outputManager gets configured (whether user prefers trace/debug/info level) Generated by gomarkdoc","title":"func GetAndValidateCmd"},{"location":"reference/outputmanager.html","text":"outputmanager \u00b6 import \"github.com/HexmosTech/lama2/outputManager\" Package `outputmanager` provides facilities for controlling the logging library as well as capabilities to post-process API execution results (such as store results as a JSON file) Index \u00b6 Variables func ConfigureZeroLog(level string) func ResponseToJSON(resp httpie.ExResponse) (*gabs.Container, error) func WriteJSONOutput(resp httpie.ExResponse, targetPath string) Variables \u00b6 LogBuff is used to append various log statements into memory. If the user toggles the `Output (-o)` option, then the contents of LogBuff is pushed into a JSON file var LogBuff bytes . Buffer func ConfigureZeroLog \u00b6 func ConfigureZeroLog ( level string ) ConfigureZeroLog provides global log level setting. By default, ZeroLog uses the DEBUG level; however, the function makes the desired level more explicit func ResponseToJSON \u00b6 func ResponseToJSON ( resp httpie . ExResponse ) ( * gabs . Container , error ) func WriteJSONOutput \u00b6 func WriteJSONOutput ( resp httpie . ExResponse , targetPath string ) WriteJSONOutput is primarily built for helping with Extension/Integration building with external tools. Extension writers may simply call `l2 -n -o /tmp/lama2.json ...` to invoke WriteJSONOutput; the generated json file contains three keys: `logs`, `headers`, `body` Generated by gomarkdoc","title":"Outputmanager"},{"location":"reference/outputmanager.html#outputmanager","text":"import \"github.com/HexmosTech/lama2/outputManager\" Package `outputmanager` provides facilities for controlling the logging library as well as capabilities to post-process API execution results (such as store results as a JSON file)","title":"outputmanager"},{"location":"reference/outputmanager.html#index","text":"Variables func ConfigureZeroLog(level string) func ResponseToJSON(resp httpie.ExResponse) (*gabs.Container, error) func WriteJSONOutput(resp httpie.ExResponse, targetPath string)","title":"Index"},{"location":"reference/outputmanager.html#variables","text":"LogBuff is used to append various log statements into memory. If the user toggles the `Output (-o)` option, then the contents of LogBuff is pushed into a JSON file var LogBuff bytes . Buffer","title":"Variables"},{"location":"reference/outputmanager.html#func-configurezerolog","text":"func ConfigureZeroLog ( level string ) ConfigureZeroLog provides global log level setting. By default, ZeroLog uses the DEBUG level; however, the function makes the desired level more explicit","title":"func ConfigureZeroLog"},{"location":"reference/outputmanager.html#func-responsetojson","text":"func ResponseToJSON ( resp httpie . ExResponse ) ( * gabs . Container , error )","title":"func ResponseToJSON"},{"location":"reference/outputmanager.html#func-writejsonoutput","text":"func WriteJSONOutput ( resp httpie . ExResponse , targetPath string ) WriteJSONOutput is primarily built for helping with Extension/Integration building with external tools. Extension writers may simply call `l2 -n -o /tmp/lama2.json ...` to invoke WriteJSONOutput; the generated json file contains three keys: `logs`, `headers`, `body` Generated by gomarkdoc","title":"func WriteJSONOutput"},{"location":"reference/parser.html","text":"parser \u00b6 import \"github.com/HexmosTech/lama2/parser\" The `parser` package provides primitives that help with writing recursive descent parsers. This version is a golang port of the original Python implementation from https://tinyurl.com/rdescent The `Parser` struct is supposed to be extended to support parsing a new language. Take a look at `lama2parser.go` for an example. Essentially the actual parsing begins from the `Start()` method. Index \u00b6 Variables func CustomPairMerge(destination, source interface{}) interface{} type Lama2Parser func NewLama2Parser() *Lama2Parser func (p *Lama2Parser) AnyType() (*gabs.Container, error) func (p *Lama2Parser) Boolean() (*gabs.Container, error) func (p *Lama2Parser) ComplexType() (*gabs.Container, error) func (p *Lama2Parser) DataHeader() (*gabs.Container, error) func (p *Lama2Parser) DataInput() (*gabs.Container, error) func (p *Lama2Parser) Details() (*gabs.Container, error) func (p *Lama2Parser) Digit() (*gabs.Container, error) func (p *Lama2Parser) Digits() (*gabs.Container, error) func (p *Lama2Parser) Exponent() (*gabs.Container, error) func (p *Lama2Parser) FilesPair() (*gabs.Container, error) func (p *Lama2Parser) FilesUnquoted() (*gabs.Container, error) func (p *Lama2Parser) Fraction() (*gabs.Container, error) func (p *Lama2Parser) FractionRule1() (*gabs.Container, error) func (p *Lama2Parser) HTTPVerb() (*gabs.Container, error) func (p *Lama2Parser) HeaderData() (*gabs.Container, error) func (p *Lama2Parser) HeaderPair() (*gabs.Container, error) func (p *Lama2Parser) Headers() (*gabs.Container, error) func (p *Lama2Parser) Integer() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule1() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule2() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule3() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule4() (*gabs.Container, error) func (p *Lama2Parser) Lama2File() (*gabs.Container, error) func (p *Lama2Parser) List() (*gabs.Container, error) func (p *Lama2Parser) Map() (*gabs.Container, error) func (p *Lama2Parser) Multipart() (*gabs.Container, error) func (p *Lama2Parser) Null() (*gabs.Container, error) func (p *Lama2Parser) Number() (*gabs.Container, error) func (p *Lama2Parser) OneNine() (*gabs.Container, error) func (p *Lama2Parser) Pair() (*gabs.Container, error) func (p *Lama2Parser) PrimitiveType() (*gabs.Container, error) func (p *Lama2Parser) Processor() (*gabs.Container, error) func (p *Lama2Parser) QuotedString() (*gabs.Container, error) func (p *Lama2Parser) Requester() (*gabs.Container, error) func (p *Lama2Parser) Separator() (*gabs.Container, error) func (p *Lama2Parser) Sign() (*gabs.Container, error) func (p *Lama2Parser) Start() (*gabs.Container, error) func (p *Lama2Parser) TheURL() (*gabs.Container, error) func (p *Lama2Parser) Unquoted() (*gabs.Container, error) func (p *Lama2Parser) VarJSON() (*gabs.Container, error) func (p *Lama2Parser) VarJSONPair() (*gabs.Container, error) func (p *Lama2Parser) VarJSONUnquoted() (*gabs.Container, error) type MinimalParser type Parser func (p *Parser) Char() (rune, error) func (p *Parser) CharClass(charClass string) (rune, error) func (p *Parser) Init() func (p *Parser) Keyword(kw string, eatWsStart bool, eatWsEnd bool, caseInsensitive bool) ([]rune, error) func (p *Parser) LookAhead(rules []string) bool func (p *Parser) Match(rules []string) (*gabs.Container, error) func (p *Parser) MatchUntil(end string) (*gabs.Container, error) func (p *Parser) Parse(text string) (*gabs.Container, error) func (p *Parser) SetText(text string) func (p *Parser) SplitCharRanges(charClass string) ([]string, error) func (p *Parser) Start() *gabs.Container Variables \u00b6 var DataInputType string func CustomPairMerge \u00b6 func CustomPairMerge ( destination , source interface {}) interface {} CustomPairMerge uses a gabs feature to deal with merge conflicts. More here: https://github.com/HexmosTech/gabs/blob/master/gabs.go#L511 type Lama2Parser \u00b6 type Lama2Parser struct { * Parser Context map [ string ] bool MarkRange map [ string ] int } func NewLama2Parser \u00b6 func NewLama2Parser () * Lama2Parser NewLama2Parser creates a new Lama2Parser and initializes it properly func (*Lama2Parser) AnyType \u00b6 func ( p * Lama2Parser ) AnyType () ( * gabs . Container , error ) AnyType is the top-most element of a JSON structure It consists of Complex and Primitive Types func (*Lama2Parser) Boolean \u00b6 func ( p * Lama2Parser ) Boolean () ( * gabs . Container , error ) func (*Lama2Parser) ComplexType \u00b6 func ( p * Lama2Parser ) ComplexType () ( * gabs . Container , error ) func (*Lama2Parser) DataHeader \u00b6 func ( p * Lama2Parser ) DataHeader () ( * gabs . Container , error ) func (*Lama2Parser) DataInput \u00b6 func ( p * Lama2Parser ) DataInput () ( * gabs . Container , error ) func (*Lama2Parser) Details \u00b6 func ( p * Lama2Parser ) Details () ( * gabs . Container , error ) func (*Lama2Parser) Digit \u00b6 func ( p * Lama2Parser ) Digit () ( * gabs . Container , error ) func (*Lama2Parser) Digits \u00b6 func ( p * Lama2Parser ) Digits () ( * gabs . Container , error ) func (*Lama2Parser) Exponent \u00b6 func ( p * Lama2Parser ) Exponent () ( * gabs . Container , error ) An Exponent consists of mandatory 'e' or 'E', optional Sign, followed by Digits func (*Lama2Parser) FilesPair \u00b6 func ( p * Lama2Parser ) FilesPair () ( * gabs . Container , error ) FilesPair tries to match key and value separated by `@`. The key and value can either be a quoted string, or an unquoted Files Unquoted String. If there is no match for either, a ParseError is returned. func (*Lama2Parser) FilesUnquoted \u00b6 func ( p * Lama2Parser ) FilesUnquoted () ( * gabs . Container , error ) FilesUnquoted matches a string of characters other than `@` and returns them as a String func (*Lama2Parser) Fraction \u00b6 func ( p * Lama2Parser ) Fraction () ( * gabs . Container , error ) func (*Lama2Parser) FractionRule1 \u00b6 func ( p * Lama2Parser ) FractionRule1 () ( * gabs . Container , error ) A Fraction consists of mandatory \".\" (dot), followed by Digits. func (*Lama2Parser) HTTPVerb \u00b6 func ( p * Lama2Parser ) HTTPVerb () ( * gabs . Container , error ) func (*Lama2Parser) HeaderData \u00b6 func ( p * Lama2Parser ) HeaderData () ( * gabs . Container , error ) func (*Lama2Parser) HeaderPair \u00b6 func ( p * Lama2Parser ) HeaderPair () ( * gabs . Container , error ) func (*Lama2Parser) Headers \u00b6 func ( p * Lama2Parser ) Headers () ( * gabs . Container , error ) Headers detects HTTP headers; essentially strings separated by \":\" character func (*Lama2Parser) Integer \u00b6 func ( p * Lama2Parser ) Integer () ( * gabs . Container , error ) func (*Lama2Parser) IntegerRule1 \u00b6 func ( p * Lama2Parser ) IntegerRule1 () ( * gabs . Container , error ) InterRule1 matches a Digit func (*Lama2Parser) IntegerRule2 \u00b6 func ( p * Lama2Parser ) IntegerRule2 () ( * gabs . Container , error ) IntegerRule2 matches 1-9 mandatorily, and then tries to follow it with Digits func (*Lama2Parser) IntegerRule3 \u00b6 func ( p * Lama2Parser ) IntegerRule3 () ( * gabs . Container , error ) IntegerRule3 starts with a mandatory Sign, and follows with IntegerRule1 (Digit) func (*Lama2Parser) IntegerRule4 \u00b6 func ( p * Lama2Parser ) IntegerRule4 () ( * gabs . Container , error ) IntegerRule4 starts with a mandatory Sign, and follows with IntegerRule2 func (*Lama2Parser) Lama2File \u00b6 func ( p * Lama2Parser ) Lama2File () ( * gabs . Container , error ) func (*Lama2Parser) List \u00b6 func ( p * Lama2Parser ) List () ( * gabs . Container , error ) List is a slightly lenient version of standard JSON list. In Lama2 List, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma) func (*Lama2Parser) Map \u00b6 func ( p * Lama2Parser ) Map () ( * gabs . Container , error ) Map is a slightly lenient version of standard JSON map. In Lama2 Map, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma) func (*Lama2Parser) Multipart \u00b6 func ( p * Lama2Parser ) Multipart () ( * gabs . Container , error ) func (*Lama2Parser) Null \u00b6 func ( p * Lama2Parser ) Null () ( * gabs . Container , error ) func (*Lama2Parser) Number \u00b6 func ( p * Lama2Parser ) Number () ( * gabs . Container , error ) A Number consists of a mandatory integer part, and optional Fraction and Exponent parts. The Number method \"collects\" these three elements, converts them into a json.Number() type, and finally returns the Number wrapped within a gabs Container func (*Lama2Parser) OneNine \u00b6 func ( p * Lama2Parser ) OneNine () ( * gabs . Container , error ) func (*Lama2Parser) Pair \u00b6 func ( p * Lama2Parser ) Pair () ( * gabs . Container , error ) func (*Lama2Parser) PrimitiveType \u00b6 func ( p * Lama2Parser ) PrimitiveType () ( * gabs . Container , error ) func (*Lama2Parser) Processor \u00b6 func ( p * Lama2Parser ) Processor () ( * gabs . Container , error ) func (*Lama2Parser) QuotedString \u00b6 func ( p * Lama2Parser ) QuotedString () ( * gabs . Container , error ) QuotedString accepts both single-quoted and double-quoted types of strings. Moreover, it can deal with unicode escape characters, control characters appropriately Ultimately, we get a string wrapped in a gabs container func (*Lama2Parser) Requester \u00b6 func ( p * Lama2Parser ) Requester () ( * gabs . Container , error ) Requester applies the rule: HTTPVerb Multipart? TheURL Details? func (*Lama2Parser) Separator \u00b6 func ( p * Lama2Parser ) Separator () ( * gabs . Container , error ) func (*Lama2Parser) Sign \u00b6 func ( p * Lama2Parser ) Sign () ( * gabs . Container , error ) func (*Lama2Parser) Start \u00b6 func ( p * Lama2Parser ) Start () ( * gabs . Container , error ) Start primarily calls the Lama2File method func (*Lama2Parser) TheURL \u00b6 func ( p * Lama2Parser ) TheURL () ( * gabs . Container , error ) func (*Lama2Parser) Unquoted \u00b6 func ( p * Lama2Parser ) Unquoted () ( * gabs . Container , error ) func (*Lama2Parser) VarJSON \u00b6 func ( p * Lama2Parser ) VarJSON () ( * gabs . Container , error ) Method VarJSON behaves in two ways depending on whether `multipart` is true or not. If there is no multipart, then VarJSON tries to match one or more VarJSONPairs However, if there is multipart, we try to match zero or more VarJSON, followed by zero or more file fields (separated by `@`). If there is no match at all, we return a ParseError; otherwise the we return the parsed data. func (*Lama2Parser) VarJSONPair \u00b6 func ( p * Lama2Parser ) VarJSONPair () ( * gabs . Container , error ) VarJSONPair tries to match key and value separated by `=`. The key and value can either be a quoted string, or an unquoted VarJSON unquoted string. If there is no match for either, a ParseError is returned. func (*Lama2Parser) VarJSONUnquoted \u00b6 func ( p * Lama2Parser ) VarJSONUnquoted () ( * gabs . Container , error ) VarJSONUnquoted matches a string of characters other than `=` and returns them as a String type MinimalParser \u00b6 MinimalParser enforces concrete Types to have a Start() method, from which parsing process begins. In the present case, `Lama2Parser` adds up dozens of of methods to implement `.l2` syntax type MinimalParser interface { Start () ( * gabs . Container , error ) } type Parser \u00b6 Struct Parser stores information about the parsing process throughout. 1. Text: Incoming text is stored as an array of runes, to correctly handle unicode characters 2. Pos: Indicates the index position in Text which has already been scanned; starts with -1 3. TotalLen: Number of runes in the input 4. Pm: Composing an external MinimalParser (such as Lama2Parser) which builds upon Parser to provide the new language recognition capabilities 5. ruleMethodMap: Scans through Pm, and creates a mapping from method name to method value through reflection 6. LineNum: Number of normalized newlines found till now. Used in providing useful context in error messages type Parser struct { Text [] rune Pos int TotalLen int Pm MinimalParser LineNum int // contains filtered or unexported fields } func (*Parser) Char \u00b6 func ( p * Parser ) Char () ( rune , error ) func (*Parser) CharClass \u00b6 func ( p * Parser ) CharClass ( charClass string ) ( rune , error ) CharClass implements the familiar regex syntax for specifying ranges of characters that are deemed acceptable. A good description of CharClass is available here: Read the section \"Processing Character Ranges\" at https://www.booleanworld.com/building-recursive-descent-parsers-definitive-guide/ func (*Parser) Init \u00b6 func ( p * Parser ) Init () Method Init creates the most important data stucture for parsing: ruleMethodMap. We use reflection to create a mapping of each Pm.\\ to \\ func (*Parser) Keyword \u00b6 func ( p * Parser ) Keyword ( kw string , eatWsStart bool , eatWsEnd bool , caseInsensitive bool ) ([] rune , error ) Method Keyword is a versatile; it can eat whitespace before/after the expected string, and it can do an optionally case insensitive match for the keyword func (*Parser) LookAhead \u00b6 func ( p * Parser ) LookAhead ( rules [] string ) bool func (*Parser) Match \u00b6 func ( p * Parser ) Match ( rules [] string ) ( * gabs . Container , error ) Method Match is the most important of all in the parser package. Match takes in a slice of rules (essentially method names), and then executes them one by one. On successful match, we return a gabs Container with `error` set to `nil` When a rule fails to match, we reset the scan position to initial position; moreover, we keep a continuous track of the farthest/longest match till present. The farthest match error is potentially the most useful error message to the user; thus, for error report, Match returns the farthest matching error func (*Parser) MatchUntil \u00b6 func ( p * Parser ) MatchUntil ( end string ) ( * gabs . Container , error ) func (*Parser) Parse \u00b6 func ( p * Parser ) Parse ( text string ) ( * gabs . Container , error ) Method Parse normalizes newlines and then creates a rune version of the input data. The Start() method proceeds to process the rune version of data func (*Parser) SetText \u00b6 func ( p * Parser ) SetText ( text string ) Method SetText is a utility used primarily in testing, when we don't want to call Start() automatically as in Parse func (*Parser) SplitCharRanges \u00b6 func ( p * Parser ) SplitCharRanges ( charClass string ) ([] string , error ) func (*Parser) Start \u00b6 func ( p * Parser ) Start () * gabs . Container Start() in Parser provides a dummy default implementation; the expectation is that the higher level Struct (Pm) will implement its own version Generated by gomarkdoc","title":"Parser"},{"location":"reference/parser.html#parser","text":"import \"github.com/HexmosTech/lama2/parser\" The `parser` package provides primitives that help with writing recursive descent parsers. This version is a golang port of the original Python implementation from https://tinyurl.com/rdescent The `Parser` struct is supposed to be extended to support parsing a new language. Take a look at `lama2parser.go` for an example. Essentially the actual parsing begins from the `Start()` method.","title":"parser"},{"location":"reference/parser.html#index","text":"Variables func CustomPairMerge(destination, source interface{}) interface{} type Lama2Parser func NewLama2Parser() *Lama2Parser func (p *Lama2Parser) AnyType() (*gabs.Container, error) func (p *Lama2Parser) Boolean() (*gabs.Container, error) func (p *Lama2Parser) ComplexType() (*gabs.Container, error) func (p *Lama2Parser) DataHeader() (*gabs.Container, error) func (p *Lama2Parser) DataInput() (*gabs.Container, error) func (p *Lama2Parser) Details() (*gabs.Container, error) func (p *Lama2Parser) Digit() (*gabs.Container, error) func (p *Lama2Parser) Digits() (*gabs.Container, error) func (p *Lama2Parser) Exponent() (*gabs.Container, error) func (p *Lama2Parser) FilesPair() (*gabs.Container, error) func (p *Lama2Parser) FilesUnquoted() (*gabs.Container, error) func (p *Lama2Parser) Fraction() (*gabs.Container, error) func (p *Lama2Parser) FractionRule1() (*gabs.Container, error) func (p *Lama2Parser) HTTPVerb() (*gabs.Container, error) func (p *Lama2Parser) HeaderData() (*gabs.Container, error) func (p *Lama2Parser) HeaderPair() (*gabs.Container, error) func (p *Lama2Parser) Headers() (*gabs.Container, error) func (p *Lama2Parser) Integer() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule1() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule2() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule3() (*gabs.Container, error) func (p *Lama2Parser) IntegerRule4() (*gabs.Container, error) func (p *Lama2Parser) Lama2File() (*gabs.Container, error) func (p *Lama2Parser) List() (*gabs.Container, error) func (p *Lama2Parser) Map() (*gabs.Container, error) func (p *Lama2Parser) Multipart() (*gabs.Container, error) func (p *Lama2Parser) Null() (*gabs.Container, error) func (p *Lama2Parser) Number() (*gabs.Container, error) func (p *Lama2Parser) OneNine() (*gabs.Container, error) func (p *Lama2Parser) Pair() (*gabs.Container, error) func (p *Lama2Parser) PrimitiveType() (*gabs.Container, error) func (p *Lama2Parser) Processor() (*gabs.Container, error) func (p *Lama2Parser) QuotedString() (*gabs.Container, error) func (p *Lama2Parser) Requester() (*gabs.Container, error) func (p *Lama2Parser) Separator() (*gabs.Container, error) func (p *Lama2Parser) Sign() (*gabs.Container, error) func (p *Lama2Parser) Start() (*gabs.Container, error) func (p *Lama2Parser) TheURL() (*gabs.Container, error) func (p *Lama2Parser) Unquoted() (*gabs.Container, error) func (p *Lama2Parser) VarJSON() (*gabs.Container, error) func (p *Lama2Parser) VarJSONPair() (*gabs.Container, error) func (p *Lama2Parser) VarJSONUnquoted() (*gabs.Container, error) type MinimalParser type Parser func (p *Parser) Char() (rune, error) func (p *Parser) CharClass(charClass string) (rune, error) func (p *Parser) Init() func (p *Parser) Keyword(kw string, eatWsStart bool, eatWsEnd bool, caseInsensitive bool) ([]rune, error) func (p *Parser) LookAhead(rules []string) bool func (p *Parser) Match(rules []string) (*gabs.Container, error) func (p *Parser) MatchUntil(end string) (*gabs.Container, error) func (p *Parser) Parse(text string) (*gabs.Container, error) func (p *Parser) SetText(text string) func (p *Parser) SplitCharRanges(charClass string) ([]string, error) func (p *Parser) Start() *gabs.Container","title":"Index"},{"location":"reference/parser.html#variables","text":"var DataInputType string","title":"Variables"},{"location":"reference/parser.html#func-custompairmerge","text":"func CustomPairMerge ( destination , source interface {}) interface {} CustomPairMerge uses a gabs feature to deal with merge conflicts. More here: https://github.com/HexmosTech/gabs/blob/master/gabs.go#L511","title":"func CustomPairMerge"},{"location":"reference/parser.html#type-lama2parser","text":"type Lama2Parser struct { * Parser Context map [ string ] bool MarkRange map [ string ] int }","title":"type Lama2Parser"},{"location":"reference/parser.html#func-newlama2parser","text":"func NewLama2Parser () * Lama2Parser NewLama2Parser creates a new Lama2Parser and initializes it properly","title":"func NewLama2Parser"},{"location":"reference/parser.html#func-lama2parser-anytype","text":"func ( p * Lama2Parser ) AnyType () ( * gabs . Container , error ) AnyType is the top-most element of a JSON structure It consists of Complex and Primitive Types","title":"func (*Lama2Parser) AnyType"},{"location":"reference/parser.html#func-lama2parser-boolean","text":"func ( p * Lama2Parser ) Boolean () ( * gabs . Container , error )","title":"func (*Lama2Parser) Boolean"},{"location":"reference/parser.html#func-lama2parser-complextype","text":"func ( p * Lama2Parser ) ComplexType () ( * gabs . Container , error )","title":"func (*Lama2Parser) ComplexType"},{"location":"reference/parser.html#func-lama2parser-dataheader","text":"func ( p * Lama2Parser ) DataHeader () ( * gabs . Container , error )","title":"func (*Lama2Parser) DataHeader"},{"location":"reference/parser.html#func-lama2parser-datainput","text":"func ( p * Lama2Parser ) DataInput () ( * gabs . Container , error )","title":"func (*Lama2Parser) DataInput"},{"location":"reference/parser.html#func-lama2parser-details","text":"func ( p * Lama2Parser ) Details () ( * gabs . Container , error )","title":"func (*Lama2Parser) Details"},{"location":"reference/parser.html#func-lama2parser-digit","text":"func ( p * Lama2Parser ) Digit () ( * gabs . Container , error )","title":"func (*Lama2Parser) Digit"},{"location":"reference/parser.html#func-lama2parser-digits","text":"func ( p * Lama2Parser ) Digits () ( * gabs . Container , error )","title":"func (*Lama2Parser) Digits"},{"location":"reference/parser.html#func-lama2parser-exponent","text":"func ( p * Lama2Parser ) Exponent () ( * gabs . Container , error ) An Exponent consists of mandatory 'e' or 'E', optional Sign, followed by Digits","title":"func (*Lama2Parser) Exponent"},{"location":"reference/parser.html#func-lama2parser-filespair","text":"func ( p * Lama2Parser ) FilesPair () ( * gabs . Container , error ) FilesPair tries to match key and value separated by `@`. The key and value can either be a quoted string, or an unquoted Files Unquoted String. If there is no match for either, a ParseError is returned.","title":"func (*Lama2Parser) FilesPair"},{"location":"reference/parser.html#func-lama2parser-filesunquoted","text":"func ( p * Lama2Parser ) FilesUnquoted () ( * gabs . Container , error ) FilesUnquoted matches a string of characters other than `@` and returns them as a String","title":"func (*Lama2Parser) FilesUnquoted"},{"location":"reference/parser.html#func-lama2parser-fraction","text":"func ( p * Lama2Parser ) Fraction () ( * gabs . Container , error )","title":"func (*Lama2Parser) Fraction"},{"location":"reference/parser.html#func-lama2parser-fractionrule1","text":"func ( p * Lama2Parser ) FractionRule1 () ( * gabs . Container , error ) A Fraction consists of mandatory \".\" (dot), followed by Digits.","title":"func (*Lama2Parser) FractionRule1"},{"location":"reference/parser.html#func-lama2parser-httpverb","text":"func ( p * Lama2Parser ) HTTPVerb () ( * gabs . Container , error )","title":"func (*Lama2Parser) HTTPVerb"},{"location":"reference/parser.html#func-lama2parser-headerdata","text":"func ( p * Lama2Parser ) HeaderData () ( * gabs . Container , error )","title":"func (*Lama2Parser) HeaderData"},{"location":"reference/parser.html#func-lama2parser-headerpair","text":"func ( p * Lama2Parser ) HeaderPair () ( * gabs . Container , error )","title":"func (*Lama2Parser) HeaderPair"},{"location":"reference/parser.html#func-lama2parser-headers","text":"func ( p * Lama2Parser ) Headers () ( * gabs . Container , error ) Headers detects HTTP headers; essentially strings separated by \":\" character","title":"func (*Lama2Parser) Headers"},{"location":"reference/parser.html#func-lama2parser-integer","text":"func ( p * Lama2Parser ) Integer () ( * gabs . Container , error )","title":"func (*Lama2Parser) Integer"},{"location":"reference/parser.html#func-lama2parser-integerrule1","text":"func ( p * Lama2Parser ) IntegerRule1 () ( * gabs . Container , error ) InterRule1 matches a Digit","title":"func (*Lama2Parser) IntegerRule1"},{"location":"reference/parser.html#func-lama2parser-integerrule2","text":"func ( p * Lama2Parser ) IntegerRule2 () ( * gabs . Container , error ) IntegerRule2 matches 1-9 mandatorily, and then tries to follow it with Digits","title":"func (*Lama2Parser) IntegerRule2"},{"location":"reference/parser.html#func-lama2parser-integerrule3","text":"func ( p * Lama2Parser ) IntegerRule3 () ( * gabs . Container , error ) IntegerRule3 starts with a mandatory Sign, and follows with IntegerRule1 (Digit)","title":"func (*Lama2Parser) IntegerRule3"},{"location":"reference/parser.html#func-lama2parser-integerrule4","text":"func ( p * Lama2Parser ) IntegerRule4 () ( * gabs . Container , error ) IntegerRule4 starts with a mandatory Sign, and follows with IntegerRule2","title":"func (*Lama2Parser) IntegerRule4"},{"location":"reference/parser.html#func-lama2parser-lama2file","text":"func ( p * Lama2Parser ) Lama2File () ( * gabs . Container , error )","title":"func (*Lama2Parser) Lama2File"},{"location":"reference/parser.html#func-lama2parser-list","text":"func ( p * Lama2Parser ) List () ( * gabs . Container , error ) List is a slightly lenient version of standard JSON list. In Lama2 List, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma)","title":"func (*Lama2Parser) List"},{"location":"reference/parser.html#func-lama2parser-map","text":"func ( p * Lama2Parser ) Map () ( * gabs . Container , error ) Map is a slightly lenient version of standard JSON map. In Lama2 Map, it is OK to have a trailing comma after the last element (whereas in strict JSON, it is not OK to have trailing comma)","title":"func (*Lama2Parser) Map"},{"location":"reference/parser.html#func-lama2parser-multipart","text":"func ( p * Lama2Parser ) Multipart () ( * gabs . Container , error )","title":"func (*Lama2Parser) Multipart"},{"location":"reference/parser.html#func-lama2parser-null","text":"func ( p * Lama2Parser ) Null () ( * gabs . Container , error )","title":"func (*Lama2Parser) Null"},{"location":"reference/parser.html#func-lama2parser-number","text":"func ( p * Lama2Parser ) Number () ( * gabs . Container , error ) A Number consists of a mandatory integer part, and optional Fraction and Exponent parts. The Number method \"collects\" these three elements, converts them into a json.Number() type, and finally returns the Number wrapped within a gabs Container","title":"func (*Lama2Parser) Number"},{"location":"reference/parser.html#func-lama2parser-onenine","text":"func ( p * Lama2Parser ) OneNine () ( * gabs . Container , error )","title":"func (*Lama2Parser) OneNine"},{"location":"reference/parser.html#func-lama2parser-pair","text":"func ( p * Lama2Parser ) Pair () ( * gabs . Container , error )","title":"func (*Lama2Parser) Pair"},{"location":"reference/parser.html#func-lama2parser-primitivetype","text":"func ( p * Lama2Parser ) PrimitiveType () ( * gabs . Container , error )","title":"func (*Lama2Parser) PrimitiveType"},{"location":"reference/parser.html#func-lama2parser-processor","text":"func ( p * Lama2Parser ) Processor () ( * gabs . Container , error )","title":"func (*Lama2Parser) Processor"},{"location":"reference/parser.html#func-lama2parser-quotedstring","text":"func ( p * Lama2Parser ) QuotedString () ( * gabs . Container , error ) QuotedString accepts both single-quoted and double-quoted types of strings. Moreover, it can deal with unicode escape characters, control characters appropriately Ultimately, we get a string wrapped in a gabs container","title":"func (*Lama2Parser) QuotedString"},{"location":"reference/parser.html#func-lama2parser-requester","text":"func ( p * Lama2Parser ) Requester () ( * gabs . Container , error ) Requester applies the rule: HTTPVerb Multipart? TheURL Details?","title":"func (*Lama2Parser) Requester"},{"location":"reference/parser.html#func-lama2parser-separator","text":"func ( p * Lama2Parser ) Separator () ( * gabs . Container , error )","title":"func (*Lama2Parser) Separator"},{"location":"reference/parser.html#func-lama2parser-sign","text":"func ( p * Lama2Parser ) Sign () ( * gabs . Container , error )","title":"func (*Lama2Parser) Sign"},{"location":"reference/parser.html#func-lama2parser-start","text":"func ( p * Lama2Parser ) Start () ( * gabs . Container , error ) Start primarily calls the Lama2File method","title":"func (*Lama2Parser) Start"},{"location":"reference/parser.html#func-lama2parser-theurl","text":"func ( p * Lama2Parser ) TheURL () ( * gabs . Container , error )","title":"func (*Lama2Parser) TheURL"},{"location":"reference/parser.html#func-lama2parser-unquoted","text":"func ( p * Lama2Parser ) Unquoted () ( * gabs . Container , error )","title":"func (*Lama2Parser) Unquoted"},{"location":"reference/parser.html#func-lama2parser-varjson","text":"func ( p * Lama2Parser ) VarJSON () ( * gabs . Container , error ) Method VarJSON behaves in two ways depending on whether `multipart` is true or not. If there is no multipart, then VarJSON tries to match one or more VarJSONPairs However, if there is multipart, we try to match zero or more VarJSON, followed by zero or more file fields (separated by `@`). If there is no match at all, we return a ParseError; otherwise the we return the parsed data.","title":"func (*Lama2Parser) VarJSON"},{"location":"reference/parser.html#func-lama2parser-varjsonpair","text":"func ( p * Lama2Parser ) VarJSONPair () ( * gabs . Container , error ) VarJSONPair tries to match key and value separated by `=`. The key and value can either be a quoted string, or an unquoted VarJSON unquoted string. If there is no match for either, a ParseError is returned.","title":"func (*Lama2Parser) VarJSONPair"},{"location":"reference/parser.html#func-lama2parser-varjsonunquoted","text":"func ( p * Lama2Parser ) VarJSONUnquoted () ( * gabs . Container , error ) VarJSONUnquoted matches a string of characters other than `=` and returns them as a String","title":"func (*Lama2Parser) VarJSONUnquoted"},{"location":"reference/parser.html#type-minimalparser","text":"MinimalParser enforces concrete Types to have a Start() method, from which parsing process begins. In the present case, `Lama2Parser` adds up dozens of of methods to implement `.l2` syntax type MinimalParser interface { Start () ( * gabs . Container , error ) }","title":"type MinimalParser"},{"location":"reference/parser.html#type-parser","text":"Struct Parser stores information about the parsing process throughout. 1. Text: Incoming text is stored as an array of runes, to correctly handle unicode characters 2. Pos: Indicates the index position in Text which has already been scanned; starts with -1 3. TotalLen: Number of runes in the input 4. Pm: Composing an external MinimalParser (such as Lama2Parser) which builds upon Parser to provide the new language recognition capabilities 5. ruleMethodMap: Scans through Pm, and creates a mapping from method name to method value through reflection 6. LineNum: Number of normalized newlines found till now. Used in providing useful context in error messages type Parser struct { Text [] rune Pos int TotalLen int Pm MinimalParser LineNum int // contains filtered or unexported fields }","title":"type Parser"},{"location":"reference/parser.html#func-parser-char","text":"func ( p * Parser ) Char () ( rune , error )","title":"func (*Parser) Char"},{"location":"reference/parser.html#func-parser-charclass","text":"func ( p * Parser ) CharClass ( charClass string ) ( rune , error ) CharClass implements the familiar regex syntax for specifying ranges of characters that are deemed acceptable. A good description of CharClass is available here: Read the section \"Processing Character Ranges\" at https://www.booleanworld.com/building-recursive-descent-parsers-definitive-guide/","title":"func (*Parser) CharClass"},{"location":"reference/parser.html#func-parser-init","text":"func ( p * Parser ) Init () Method Init creates the most important data stucture for parsing: ruleMethodMap. We use reflection to create a mapping of each Pm.\\ to \\","title":"func (*Parser) Init"},{"location":"reference/parser.html#func-parser-keyword","text":"func ( p * Parser ) Keyword ( kw string , eatWsStart bool , eatWsEnd bool , caseInsensitive bool ) ([] rune , error ) Method Keyword is a versatile; it can eat whitespace before/after the expected string, and it can do an optionally case insensitive match for the keyword","title":"func (*Parser) Keyword"},{"location":"reference/parser.html#func-parser-lookahead","text":"func ( p * Parser ) LookAhead ( rules [] string ) bool","title":"func (*Parser) LookAhead"},{"location":"reference/parser.html#func-parser-match","text":"func ( p * Parser ) Match ( rules [] string ) ( * gabs . Container , error ) Method Match is the most important of all in the parser package. Match takes in a slice of rules (essentially method names), and then executes them one by one. On successful match, we return a gabs Container with `error` set to `nil` When a rule fails to match, we reset the scan position to initial position; moreover, we keep a continuous track of the farthest/longest match till present. The farthest match error is potentially the most useful error message to the user; thus, for error report, Match returns the farthest matching error","title":"func (*Parser) Match"},{"location":"reference/parser.html#func-parser-matchuntil","text":"func ( p * Parser ) MatchUntil ( end string ) ( * gabs . Container , error )","title":"func (*Parser) MatchUntil"},{"location":"reference/parser.html#func-parser-parse","text":"func ( p * Parser ) Parse ( text string ) ( * gabs . Container , error ) Method Parse normalizes newlines and then creates a rune version of the input data. The Start() method proceeds to process the rune version of data","title":"func (*Parser) Parse"},{"location":"reference/parser.html#func-parser-settext","text":"func ( p * Parser ) SetText ( text string ) Method SetText is a utility used primarily in testing, when we don't want to call Start() automatically as in Parse","title":"func (*Parser) SetText"},{"location":"reference/parser.html#func-parser-splitcharranges","text":"func ( p * Parser ) SplitCharRanges ( charClass string ) ([] string , error )","title":"func (*Parser) SplitCharRanges"},{"location":"reference/parser.html#func-parser-start","text":"func ( p * Parser ) Start () * gabs . Container Start() in Parser provides a dummy default implementation; the expectation is that the higher level Struct (Pm) will implement its own version Generated by gomarkdoc","title":"func (*Parser) Start"},{"location":"reference/philosophy.html","text":"Lama2 takes inspiration from Markdown . Think of our approach as Markdown for APIs . In particular, we strive to: Delegate subtasks to mature and preferably open tools: API Collaboration - git API Organization - OS file manager + IDEs API Editing - VSCode/IDEs API Requests - HTTPie ( httpie-go , to be specific) Request Chaining - Embedded Javascript Adhere to a continuous language formalization effort from the beginning (learning from Markdown history) Keep language syntax simple; don't sacrifice readability for tiny functionality gains. Invest into good documentation; however, ensure users can perform competently without referencing documentation as much as possible. Keep components decoupled","title":"Design Philosophy"},{"location":"reference/preprocess.html","text":"preprocess \u00b6 import \"github.com/HexmosTech/lama2/preprocess\" Package preprocess provides facilities to expand environment variables in `.l2` API files and return the contents Index \u00b6 func Expand(s string, vm *goja.Runtime, mapping map[string]string) string func ExpandEnv(s string, vm *goja.Runtime) string func ExpandHeaders(block *gabs.Container, vm *goja.Runtime) func ExpandJSON(block *gabs.Container, vm *goja.Runtime) func ExpandURL(block *gabs.Container, vm *goja.Runtime) func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error) func GetLamaFileAsString(path string) string func LamaFile(inputFile string) (string, string) func LoadEnvFile(l2path string) func LoadEnvironments(dir string) func ProcessVarsInBlock(block *gabs.Container, vm *goja.Runtime) func SearchL2ConfigEnv(dir string) (string, error) func Expand \u00b6 func Expand ( s string , vm * goja . Runtime , mapping map [ string ] string ) string Expand replaces ${var} or $var in the string based on the mapping function. For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv). func ExpandEnv \u00b6 func ExpandEnv ( s string , vm * goja . Runtime ) string ExpandEnv replaces ${var} or $var in the string according to the values of the current environment variables. References to undefined variables are replaced by the empty string. func ExpandHeaders \u00b6 func ExpandHeaders ( block * gabs . Container , vm * goja . Runtime ) func ExpandJSON \u00b6 func ExpandJSON ( block * gabs . Container , vm * goja . Runtime ) func ExpandURL \u00b6 func ExpandURL ( block * gabs . Container , vm * goja . Runtime ) func GetL2EnvVariables \u00b6 func GetL2EnvVariables ( dir string ) ( map [ string ] map [ string ] interface {}, error ) func GetLamaFileAsString \u00b6 func GetLamaFileAsString ( path string ) string func LamaFile \u00b6 func LamaFile ( inputFile string ) ( string , string ) LamaFile takes in a path to an API file. It moves into the API file directory, reads the API contents, loads the `l2.env` file if available, and finally substitutes environment vars in the API contents Once done, it reverts back to the original directory, and returns the processed l2 file. func LoadEnvFile \u00b6 func LoadEnvFile ( l2path string ) func LoadEnvironments \u00b6 func LoadEnvironments ( dir string ) func ProcessVarsInBlock \u00b6 func ProcessVarsInBlock ( block * gabs . Container , vm * goja . Runtime ) func SearchL2ConfigEnv \u00b6 func SearchL2ConfigEnv ( dir string ) ( string , error ) Generated by gomarkdoc","title":"Preprocess"},{"location":"reference/preprocess.html#preprocess","text":"import \"github.com/HexmosTech/lama2/preprocess\" Package preprocess provides facilities to expand environment variables in `.l2` API files and return the contents","title":"preprocess"},{"location":"reference/preprocess.html#index","text":"func Expand(s string, vm *goja.Runtime, mapping map[string]string) string func ExpandEnv(s string, vm *goja.Runtime) string func ExpandHeaders(block *gabs.Container, vm *goja.Runtime) func ExpandJSON(block *gabs.Container, vm *goja.Runtime) func ExpandURL(block *gabs.Container, vm *goja.Runtime) func GetL2EnvVariables(dir string) (map[string]map[string]interface{}, error) func GetLamaFileAsString(path string) string func LamaFile(inputFile string) (string, string) func LoadEnvFile(l2path string) func LoadEnvironments(dir string) func ProcessVarsInBlock(block *gabs.Container, vm *goja.Runtime) func SearchL2ConfigEnv(dir string) (string, error)","title":"Index"},{"location":"reference/preprocess.html#func-expand","text":"func Expand ( s string , vm * goja . Runtime , mapping map [ string ] string ) string Expand replaces ${var} or $var in the string based on the mapping function. For example, os.ExpandEnv(s) is equivalent to os.Expand(s, os.Getenv).","title":"func Expand"},{"location":"reference/preprocess.html#func-expandenv","text":"func ExpandEnv ( s string , vm * goja . Runtime ) string ExpandEnv replaces ${var} or $var in the string according to the values of the current environment variables. References to undefined variables are replaced by the empty string.","title":"func ExpandEnv"},{"location":"reference/preprocess.html#func-expandheaders","text":"func ExpandHeaders ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandHeaders"},{"location":"reference/preprocess.html#func-expandjson","text":"func ExpandJSON ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandJSON"},{"location":"reference/preprocess.html#func-expandurl","text":"func ExpandURL ( block * gabs . Container , vm * goja . Runtime )","title":"func ExpandURL"},{"location":"reference/preprocess.html#func-getl2envvariables","text":"func GetL2EnvVariables ( dir string ) ( map [ string ] map [ string ] interface {}, error )","title":"func GetL2EnvVariables"},{"location":"reference/preprocess.html#func-getlamafileasstring","text":"func GetLamaFileAsString ( path string ) string","title":"func GetLamaFileAsString"},{"location":"reference/preprocess.html#func-lamafile","text":"func LamaFile ( inputFile string ) ( string , string ) LamaFile takes in a path to an API file. It moves into the API file directory, reads the API contents, loads the `l2.env` file if available, and finally substitutes environment vars in the API contents Once done, it reverts back to the original directory, and returns the processed l2 file.","title":"func LamaFile"},{"location":"reference/preprocess.html#func-loadenvfile","text":"func LoadEnvFile ( l2path string )","title":"func LoadEnvFile"},{"location":"reference/preprocess.html#func-loadenvironments","text":"func LoadEnvironments ( dir string )","title":"func LoadEnvironments"},{"location":"reference/preprocess.html#func-processvarsinblock","text":"func ProcessVarsInBlock ( block * gabs . Container , vm * goja . Runtime )","title":"func ProcessVarsInBlock"},{"location":"reference/preprocess.html#func-searchl2configenv","text":"func SearchL2ConfigEnv ( dir string ) ( string , error ) Generated by gomarkdoc","title":"func SearchL2ConfigEnv"},{"location":"reference/utils.html","text":"utils \u00b6 import \"github.com/HexmosTech/lama2/utils\" Package `utils` provides useful functions for simplifying various programming tasks Index \u00b6 func ChangeWorkingDir(dir string) func ContainsRune(s []rune, e rune) bool func ContainsString(s []string, e string) bool func ContainsStringPartial(s []string, e string) bool func GetFilePathComponents(name string) (string, string, string) func PrettyPrint(i interface{}) string func SetJSON(parentObj *gabs.Container, childObj *gabs.Container, key string) *gabs.Container func UnicodeCategory(r rune) string func UpdateSelf() type ParseError func NewParseError(pos int, line int, msg string, args []string) *ParseError func (p ParseError) Error() string func ChangeWorkingDir \u00b6 func ChangeWorkingDir ( dir string ) ChangeWorkingDirectory tries to set the CWD; on failure it exits with a log error message func ContainsRune \u00b6 func ContainsRune ( s [] rune , e rune ) bool ContainsRune searches for rune `e` in a slice of runes `s`; returns a boolean func ContainsString \u00b6 func ContainsString ( s [] string , e string ) bool ContainsString searches for string `e` in a slice of strings `s`; returns a boolean func ContainsStringPartial \u00b6 func ContainsStringPartial ( s [] string , e string ) bool ContainsStringPartial substring-searches for string `e` in a slice of strings `s`; returns a boolean func GetFilePathComponents \u00b6 func GetFilePathComponents ( name string ) ( string , string , string ) GetFilePathComponent returns absolute path, directory, and filename given a filepath func PrettyPrint \u00b6 func PrettyPrint ( i interface {}) string PrettyPrint takes in a generic interface{} objects and uses standard JSON capabilities to try to print with indentation func SetJSON \u00b6 func SetJSON ( parentObj * gabs . Container , childObj * gabs . Container , key string ) * gabs . Container SetJSON is a helper function to work with the `gabs` library, which in turn is an API on top of the standard JSON library The function helps us create `parentObj.key = childObj` through using the `Merge` primitive available in `gabs` func UnicodeCategory \u00b6 func UnicodeCategory ( r rune ) string UnicodeCategory returns the Unicode Character Category of the given rune. func UpdateSelf \u00b6 func UpdateSelf () UpdateSelf downloads the installation script from the official repository, and executes it to update the l2 binary to the latest version type ParseError \u00b6 type ParseError struct { Pos int LineNum int // contains filtered or unexported fields } func NewParseError \u00b6 func NewParseError ( pos int , line int , msg string , args [] string ) * ParseError func (ParseError) Error \u00b6 func ( p ParseError ) Error () string Generated by gomarkdoc","title":"Utils"},{"location":"reference/utils.html#utils","text":"import \"github.com/HexmosTech/lama2/utils\" Package `utils` provides useful functions for simplifying various programming tasks","title":"utils"},{"location":"reference/utils.html#index","text":"func ChangeWorkingDir(dir string) func ContainsRune(s []rune, e rune) bool func ContainsString(s []string, e string) bool func ContainsStringPartial(s []string, e string) bool func GetFilePathComponents(name string) (string, string, string) func PrettyPrint(i interface{}) string func SetJSON(parentObj *gabs.Container, childObj *gabs.Container, key string) *gabs.Container func UnicodeCategory(r rune) string func UpdateSelf() type ParseError func NewParseError(pos int, line int, msg string, args []string) *ParseError func (p ParseError) Error() string","title":"Index"},{"location":"reference/utils.html#func-changeworkingdir","text":"func ChangeWorkingDir ( dir string ) ChangeWorkingDirectory tries to set the CWD; on failure it exits with a log error message","title":"func ChangeWorkingDir"},{"location":"reference/utils.html#func-containsrune","text":"func ContainsRune ( s [] rune , e rune ) bool ContainsRune searches for rune `e` in a slice of runes `s`; returns a boolean","title":"func ContainsRune"},{"location":"reference/utils.html#func-containsstring","text":"func ContainsString ( s [] string , e string ) bool ContainsString searches for string `e` in a slice of strings `s`; returns a boolean","title":"func ContainsString"},{"location":"reference/utils.html#func-containsstringpartial","text":"func ContainsStringPartial ( s [] string , e string ) bool ContainsStringPartial substring-searches for string `e` in a slice of strings `s`; returns a boolean","title":"func ContainsStringPartial"},{"location":"reference/utils.html#func-getfilepathcomponents","text":"func GetFilePathComponents ( name string ) ( string , string , string ) GetFilePathComponent returns absolute path, directory, and filename given a filepath","title":"func GetFilePathComponents"},{"location":"reference/utils.html#func-prettyprint","text":"func PrettyPrint ( i interface {}) string PrettyPrint takes in a generic interface{} objects and uses standard JSON capabilities to try to print with indentation","title":"func PrettyPrint"},{"location":"reference/utils.html#func-setjson","text":"func SetJSON ( parentObj * gabs . Container , childObj * gabs . Container , key string ) * gabs . Container SetJSON is a helper function to work with the `gabs` library, which in turn is an API on top of the standard JSON library The function helps us create `parentObj.key = childObj` through using the `Merge` primitive available in `gabs`","title":"func SetJSON"},{"location":"reference/utils.html#func-unicodecategory","text":"func UnicodeCategory ( r rune ) string UnicodeCategory returns the Unicode Character Category of the given rune.","title":"func UnicodeCategory"},{"location":"reference/utils.html#func-updateself","text":"func UpdateSelf () UpdateSelf downloads the installation script from the official repository, and executes it to update the l2 binary to the latest version","title":"func UpdateSelf"},{"location":"reference/utils.html#type-parseerror","text":"type ParseError struct { Pos int LineNum int // contains filtered or unexported fields }","title":"type ParseError"},{"location":"reference/utils.html#func-newparseerror","text":"func NewParseError ( pos int , line int , msg string , args [] string ) * ParseError","title":"func NewParseError"},{"location":"reference/utils.html#func-parseerror-error","text":"func ( p ParseError ) Error () string Generated by gomarkdoc","title":"func (ParseError) Error"},{"location":"tutorials/codegen.html","text":"Lama2 is capable of converting .l2 files into functional code of your preferred language and library. For example, to generate code in python requests , use the following command: l2 -c python.requests myfile.l2 To pick the default library in a language, omit the library as follows: l2 -c python myfile.l2 Languages and libraries supported \u00b6 shell curl (default) httpie wget powershell webrequest (default) restmethod ocaml cohttp (default) csharp restsharp (default) httpclient r httr (default) php curl (default) guzzle http1 http2 ruby native (default) clojure clj_http (default) java unirest (default) asynchttp nethttp okhttp http 1.1 (default) http1.1 swift nsurlsession (default) node native (default) request unirest axios fetch c libcurl (default) go native (default) python python3 (default) requests kotlin okhttp (default) javascript xhr (default) axios fetch jquery objc nsurlsession (default)","title":"Code Generation"},{"location":"tutorials/codegen.html#languages-and-libraries-supported","text":"shell curl (default) httpie wget powershell webrequest (default) restmethod ocaml cohttp (default) csharp restsharp (default) httpclient r httr (default) php curl (default) guzzle http1 http2 ruby native (default) clojure clj_http (default) java unirest (default) asynchttp nethttp okhttp http 1.1 (default) http1.1 swift nsurlsession (default) node native (default) request unirest axios fetch c libcurl (default) go native (default) python python3 (default) requests kotlin okhttp (default) javascript xhr (default) axios fetch jquery objc nsurlsession (default)","title":"Languages and libraries supported"},{"location":"tutorials/collaboration.html","text":"At Hexmos , we use a git repository called APIHub for collaborating on API files. Here is a description of how the workflow functions for us: The new engineer clones APIHub repository If necessary, create a folder for organizing the new API (ex: my_new_service ) Start defining *.l2 files for each service specific API. Use l2 file.l2 to test the newly defined APIs (or execute from VSCode). Push the API files once ready into APIHub repo On the rare merge conflict, the engineer uses standard git conflict resolution mechanisms","title":"Collaboration"},{"location":"tutorials/editor.html","text":"Useful Options \u00b6 The l2 command provides some helpful options for extension developers. The options are: --env= or -e outputs a JSON of environment variables (in CLI); --nocolor or -n disables colored output in httpie-go (in CLI); --output= or -e outputs a JSON of environment variables (in CLI); --nocolor or -n disables colored output in httpie-go (in CLI); --output=.l2 You can also clone the repo and open it up in VSCode, install the Lama2 extension and fire requests from there. GET request \u00b6 GET https://httpbin.org/get Get Source File JSON POST request \u00b6 One can dump the JSON body at the end of an .l2 file to create a POST request: POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } Get Source File JSON POST in VarJSON format \u00b6 Make a POST request with JSON body specified as key=value . Lama2 converts the input into a corresponding JSON value {\"a\": \"b\", \"c\": \"d\"} . We call the key=value format VarJSON . This example produces an effect identical to the previous one POST https://httpbin.org/post a=b c=d Get Source File Comments \u00b6 One can start a comment anywhere in the file with the # character. # Pound symbol signifies a comment POST https://httpbin.org/post a=b # Comments may start at the end of lines as well c=d # Comments work even after the payload Get Source File Environment Variables: Switch base URL \u00b6 Case 1: l2.env adjacent to an API file \u00b6 For any given .l2 file, one can place an l2.env file to store relevant variables. These variables will be available to be used within the API file project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Case 2: Root variables \u00b6 In Lama2, you can have a large number of API files stored in a hierarchical folder configuration. The root of such a project can be signified through l2config.env : Within such a structure, you can have an API file anywhere, which can use variables defined in the root variables: project_folder/l2config.env export AHOST=\"https://httpbin.org\" export BHOST=\"https://google.com\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Case 3: Override Root variable with local variable \u00b6 In this structure, if a variable is declared in both l2config.env and l2.env, the value from l2.env takes precedence. project_folder/l2config.env export AHOST=`echo NO URL` export BHOST=\"https://httpbin.org\" project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File Headers \u00b6 Use key:value format to specify headers. Specify strings for key/value in three ways: Double quoted ( \"hello\" ) Single quoted ( 'hello' ) Unquoted ( hello ) POST https://httpbin.org/post # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings Get Source File Note The data section may appear before headers as well (see below) POST https://httpbin.org/post # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" Send cookies in header \u00b6 Headers represent cookies in Lama2 . Just specify cookie key value pairs separated by = within the header value as shown. POST https://httpbin.org/post # HEADERS Cookie:\"sessionid=foo;another-cookie=bar\" # DATA hello=world Get Source File Fill forms & attach files with MULTIPART \u00b6 Use the MULTIPART keyword after the HTTP verb to enable forms and file attachments. The data section may contain any number of form inputs using the key=value syntax. Following the data section, one can specify any number of files in the form of @ . The file path is relative to the API file. POST MULTIPART http://httpbin.org/post 'X-Parse-Application-Id':hello X-Parse-REST-API-Key:\"world\" # DATA first=second # FILES myfile@./image.jpeg Get Source Files Image as Base64 encoded JSON field \u00b6 We can embed images (or other files) as base64 strings in JSON using Lama2 . First, we define a PHOTO variable, loaded up with the results of the base64 command. l2.env export PHOTO=`base64 -w 0 image.jpeg` Next, we refer to the PHOTO variable in the API file. Pay special attention to the quoting mechanism \"'{PHOTO}'\" . Warning The quoting must look exactly as shown in the following template for the request to work correctly. base64_embed.l2 POST http://httpbin.org/post { \"imageb64_field\": \"'${PHOTO}'\", } Get Source Files Chain requests using Javascript \u00b6 In Lama2, we have alternating requestor and processor (JS) blocks, separated by --- . Each processor (JS) block has a special variable result , storing the response from previous requestor block. If possible, result is automatically stored as a JS object through JSON.parse() . Otherwise, result is stored as a regular string . url = \"http://google.com\" REMOTE_COORD = \"https://httpbing.org\" --- # stage 1 POST ${REMOTE_COORD}/anything { \"username\": \"admin\", \"password\": \"Password@123\", \"from\": \"${LOCAL_COORD}/anything\", \"url\": \"${url}\", \"Token\": \"MySuperSecretToken\" } --- // filtering, store in var console.log(\"@@Result\", result) let TOKEN = result[\"json\"][\"Token\"] console.log(TOKEN) --- # stage 2 GET ${REMOTE_COORD}/bearer Authorization: 'Bearer ${TOKEN}' {} Get Source Files","title":"Examples"},{"location":"tutorials/examples.html#examples","text":"The following examples provide a sampling of the various types of requests Lama2 handles presently. Execute each file as: l2 .l2 You can also clone the repo and open it up in VSCode, install the Lama2 extension and fire requests from there.","title":"Examples"},{"location":"tutorials/examples.html#get-request","text":"GET https://httpbin.org/get Get Source File","title":"GET request"},{"location":"tutorials/examples.html#json-post-request","text":"One can dump the JSON body at the end of an .l2 file to create a POST request: POST https://httpbin.org/post { \"a\": \"b\", \"c\": \"d\" } Get Source File","title":"JSON POST request"},{"location":"tutorials/examples.html#json-post-in-varjson-format","text":"Make a POST request with JSON body specified as key=value . Lama2 converts the input into a corresponding JSON value {\"a\": \"b\", \"c\": \"d\"} . We call the key=value format VarJSON . This example produces an effect identical to the previous one POST https://httpbin.org/post a=b c=d Get Source File","title":"JSON POST in VarJSON format"},{"location":"tutorials/examples.html#comments","text":"One can start a comment anywhere in the file with the # character. # Pound symbol signifies a comment POST https://httpbin.org/post a=b # Comments may start at the end of lines as well c=d # Comments work even after the payload Get Source File","title":"Comments"},{"location":"tutorials/examples.html#environment-variables-switch-base-url","text":"","title":"Environment Variables: Switch base URL"},{"location":"tutorials/examples.html#case-1-l2env-adjacent-to-an-api-file","text":"For any given .l2 file, one can place an l2.env file to store relevant variables. These variables will be available to be used within the API file project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 1: l2.env adjacent to an API file"},{"location":"tutorials/examples.html#case-2-root-variables","text":"In Lama2, you can have a large number of API files stored in a hierarchical folder configuration. The root of such a project can be signified through l2config.env : Within such a structure, you can have an API file anywhere, which can use variables defined in the root variables: project_folder/l2config.env export AHOST=\"https://httpbin.org\" export BHOST=\"https://google.com\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 2: Root variables"},{"location":"tutorials/examples.html#case-3-override-root-variable-with-local-variable","text":"In this structure, if a variable is declared in both l2config.env and l2.env, the value from l2.env takes precedence. project_folder/l2config.env export AHOST=`echo NO URL` export BHOST=\"https://httpbin.org\" project_folder/api/l2.env export AHOST=\"http://127.0.0.1:8000\" project_folder/api/get_users.l2 GET ${AHOST}/users Get Source File","title":"Case 3: Override Root variable with local variable"},{"location":"tutorials/examples.html#headers","text":"Use key:value format to specify headers. Specify strings for key/value in three ways: Double quoted ( \"hello\" ) Single quoted ( 'hello' ) Unquoted ( hello ) POST https://httpbin.org/post # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\" # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings Get Source File Note The data section may appear before headers as well (see below) POST https://httpbin.org/post # DATA a=\"b\" # double-quoted string 'c'=d # single-quoted & unquoted strings # HEADERS X-Parse-Application-Id:'helloworld' X-Parse-REST-API-Key:\"byeworld\"","title":"Headers"},{"location":"tutorials/examples.html#send-cookies-in-header","text":"Headers represent cookies in Lama2 . Just specify cookie key value pairs separated by = within the header value as shown. POST https://httpbin.org/post # HEADERS Cookie:\"sessionid=foo;another-cookie=bar\" # DATA hello=world Get Source File","title":"Send cookies in header"},{"location":"tutorials/examples.html#fill-forms-attach-files-with-multipart","text":"Use the MULTIPART keyword after the HTTP verb to enable forms and file attachments. The data section may contain any number of form inputs using the key=value syntax. Following the data section, one can specify any number of files in the form of @ . The file path is relative to the API file. POST MULTIPART http://httpbin.org/post 'X-Parse-Application-Id':hello X-Parse-REST-API-Key:\"world\" # DATA first=second # FILES myfile@./image.jpeg Get Source Files","title":"Fill forms & attach files with MULTIPART"},{"location":"tutorials/examples.html#image-as-base64-encoded-json-field","text":"We can embed images (or other files) as base64 strings in JSON using Lama2 . First, we define a PHOTO variable, loaded up with the results of the base64 command. l2.env export PHOTO=`base64 -w 0 image.jpeg` Next, we refer to the PHOTO variable in the API file. Pay special attention to the quoting mechanism \"'{PHOTO}'\" . Warning The quoting must look exactly as shown in the following template for the request to work correctly. base64_embed.l2 POST http://httpbin.org/post { \"imageb64_field\": \"'${PHOTO}'\", } Get Source Files","title":"Image as Base64 encoded JSON field"},{"location":"tutorials/examples.html#chain-requests-using-javascript","text":"In Lama2, we have alternating requestor and processor (JS) blocks, separated by --- . Each processor (JS) block has a special variable result , storing the response from previous requestor block. If possible, result is automatically stored as a JS object through JSON.parse() . Otherwise, result is stored as a regular string . url = \"http://google.com\" REMOTE_COORD = \"https://httpbing.org\" --- # stage 1 POST ${REMOTE_COORD}/anything { \"username\": \"admin\", \"password\": \"Password@123\", \"from\": \"${LOCAL_COORD}/anything\", \"url\": \"${url}\", \"Token\": \"MySuperSecretToken\" } --- // filtering, store in var console.log(\"@@Result\", result) let TOKEN = result[\"json\"][\"Token\"] console.log(TOKEN) --- # stage 2 GET ${REMOTE_COORD}/bearer Authorization: 'Bearer ${TOKEN}' {} Get Source Files","title":"Chain requests using Javascript"},{"location":"tutorials/installation.html","text":"Getting Started \u00b6 Installation/Update \u00b6 One-line install/update in Linux/MacOS \u00b6 To install/update Lama2 and its dependencies automatically, run the following: curl -s https://hexmos.com/lama2/install.sh | bash -s One-line install/update in Windows \u00b6 To install/update Lama2 and its dependencies automatically, run the following as Administrator : choco install lama2 --version=1.0.0 --force -y (Optional) Import your collections from Postman \u00b6 Follow guide to import your existing Postman collections into a Plain-Text Lama2 repository. Self update \u00b6 An easier way to update the binary to latest release is through: l2 -u Note Install the VSCode extension to launch requests from within your editor Manual install \u00b6 Step 1: Install HTTPie \u00b6 Lama2 depends on HTTPie for Terminal . Use their official instructions to get the http command functional in your local system. Step 2: Download & install Lama2 binary packages \u00b6 Head over to Lama2 releases . Check under the Assets head to find various packages. Download the relevant package for your operating system and CPU architecture. Once you have the package, run the following: tar --overwrite -xvzf .tar.gz mv l2 /usr/local/bin Build from source \u00b6 Run make in the project root. You'll need to have the following tools in your PATH : go (v1.17+) golangcli-lint gofumpt Also, you'll need to install mkdocs the first time; for that run these: cd docs/Lama2 poetry install # get poetry from https://python-poetry.org/ Once make finishes, find the binary at ./build/l2 . Moreover, you can launch the documentation locally through make serve . Read makefile to find other useful helper commands. How to use \u00b6 From the terminal \u00b6 Type l2 into the terminal. You should get something like: Usage: l2 [OPTIONS] [LamaAPIFile] Application Options: -o, --output= Path to output JSON file to store logs, headers and result -v, --verbose Show verbose debug information -n, --nocolor Disable color in httpie output -e --env= Get a JSON of environment variables revelant to input arg -h, --help Usage help for Lama2 --version Print Lama2 binary version Help Options: -h, --help Show this help message From VS Code \u00b6 Find Lama2 for VSCode at the VSCode Marketplace . The extension requires the l2 command available (usually at /usr/local/bin/l2 for Linux/MacOS and C:\\ProgramData\\chocolatey\\bin for Windows). Once the extension is installed, open the command palette (ctrl + shift + p) and search for Execute current file to execute the file","title":"Installation"},{"location":"tutorials/installation.html#getting-started","text":"","title":"Getting Started"},{"location":"tutorials/installation.html#installationupdate","text":"","title":"Installation/Update"},{"location":"tutorials/installation.html#one-line-installupdate-in-linuxmacos","text":"To install/update Lama2 and its dependencies automatically, run the following: curl -s https://hexmos.com/lama2/install.sh | bash -s","title":"One-line install/update in Linux/MacOS"},{"location":"tutorials/installation.html#one-line-installupdate-in-windows","text":"To install/update Lama2 and its dependencies automatically, run the following as Administrator : choco install lama2 --version=1.0.0 --force -y","title":"One-line install/update in Windows"},{"location":"tutorials/installation.html#optional-import-your-collections-from-postman","text":"Follow guide to import your existing Postman collections into a Plain-Text Lama2 repository.","title":"(Optional) Import your collections from Postman"},{"location":"tutorials/installation.html#self-update","text":"An easier way to update the binary to latest release is through: l2 -u Note Install the VSCode extension to launch requests from within your editor","title":"Self update"},{"location":"tutorials/installation.html#manual-install","text":"","title":"Manual install"},{"location":"tutorials/installation.html#step-1-install-httpie","text":"Lama2 depends on HTTPie for Terminal . Use their official instructions to get the http command functional in your local system.","title":"Step 1: Install HTTPie"},{"location":"tutorials/installation.html#step-2-download-install-lama2-binary-packages","text":"Head over to Lama2 releases . Check under the Assets head to find various packages. Download the relevant package for your operating system and CPU architecture. Once you have the package, run the following: tar --overwrite -xvzf .tar.gz mv l2 /usr/local/bin","title":"Step 2: Download & install Lama2 binary packages"},{"location":"tutorials/installation.html#build-from-source","text":"Run make in the project root. You'll need to have the following tools in your PATH : go (v1.17+) golangcli-lint gofumpt Also, you'll need to install mkdocs the first time; for that run these: cd docs/Lama2 poetry install # get poetry from https://python-poetry.org/ Once make finishes, find the binary at ./build/l2 . Moreover, you can launch the documentation locally through make serve . Read makefile to find other useful helper commands.","title":"Build from source"},{"location":"tutorials/installation.html#how-to-use","text":"","title":"How to use"},{"location":"tutorials/installation.html#from-the-terminal","text":"Type l2 into the terminal. You should get something like: Usage: l2 [OPTIONS] [LamaAPIFile] Application Options: -o, --output= Path to output JSON file to store logs, headers and result -v, --verbose Show verbose debug information -n, --nocolor Disable color in httpie output -e --env= Get a JSON of environment variables revelant to input arg -h, --help Usage help for Lama2 --version Print Lama2 binary version Help Options: -h, --help Show this help message","title":"From the terminal"},{"location":"tutorials/installation.html#from-vs-code","text":"Find Lama2 for VSCode at the VSCode Marketplace . The extension requires the l2 command available (usually at /usr/local/bin/l2 for Linux/MacOS and C:\\ProgramData\\chocolatey\\bin for Windows). Once the extension is installed, open the command palette (ctrl + shift + p) and search for Execute current file to execute the file","title":"From VS Code"},{"location":"tutorials/misc.html","text":"Prettify JSON in l2 files \u00b6 Common experience suggests that l2 files tend to be messy when dealing with larger JSON files. So we have developed a targeted prettifier which fixes the JSON portions of an l2 file (if it exists) Usage: l2 -b targetFile.l2","title":"Misc"},{"location":"tutorials/misc.html#prettify-json-in-l2-files","text":"Common experience suggests that l2 files tend to be messy when dealing with larger JSON files. So we have developed a targeted prettifier which fixes the JSON portions of an l2 file (if it exists) Usage: l2 -b targetFile.l2","title":"Prettify JSON in l2 files"},{"location":"tutorials/postman.html","text":"Lama2 ships with a rudimentary converter from Postman to a Plain-Text Lama2 API repository. The converter presently is in an embryonic state and may merely produce approximate results. 1. Export from Postman \u00b6 1.1 Access Settings \u00b6 1.2 Data Export \u00b6 Warning Although postman offers more selective exporting (collection, folder, request levels), Lama2 presently supports only the whole-data export depicted above. The above step must produce a .json file. 2. Convert Postman .json dump into Lama2 API repo \u00b6 Run the following to convert the postman data dump into a Lama2 API structure. l2 -p postman_dump.json -l my_l2output_dir The command will prompt for an environment. Select the environment which you wish to export. Once you pick the option, Lama2 will produce the my_l2output_dir directory filled with the original organizational hierarchy and a bunch of .l2 and l2.env files.","title":"Import Postman"},{"location":"tutorials/postman.html#1-export-from-postman","text":"","title":"1. Export from Postman"},{"location":"tutorials/postman.html#11-access-settings","text":"","title":"1.1 Access Settings"},{"location":"tutorials/postman.html#12-data-export","text":"Warning Although postman offers more selective exporting (collection, folder, request levels), Lama2 presently supports only the whole-data export depicted above. The above step must produce a .json file.","title":"1.2 Data Export"},{"location":"tutorials/postman.html#2-convert-postman-json-dump-into-lama2-api-repo","text":"Run the following to convert the postman data dump into a Lama2 API structure. l2 -p postman_dump.json -l my_l2output_dir The command will prompt for an environment. Select the environment which you wish to export. Once you pick the option, Lama2 will produce the my_l2output_dir directory filled with the original organizational hierarchy and a bunch of .l2 and l2.env files.","title":"2. Convert Postman .json dump into Lama2 API repo"}]} \ No newline at end of file diff --git a/docs/Lama2/site/sitemap.xml b/docs/Lama2/site/sitemap.xml index cd487ab8..2812cea3 100644 --- a/docs/Lama2/site/sitemap.xml +++ b/docs/Lama2/site/sitemap.xml @@ -2,127 +2,127 @@ http://hexmos.com/lama2/index.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/about/contact.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/about/hexmos.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/explanation/faq.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/explanation/l2format.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/explanation/syntax.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/api.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/architecture.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/cmdexec.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/cmdgen.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/controller.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/grammar.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/lama2cmd.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/outputmanager.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/parser.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/philosophy.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/preprocess.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/reference/utils.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/codegen.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/collaboration.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/editor.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/examples.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/installation.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/misc.html - 2023-07-23 + 2023-08-14 daily http://hexmos.com/lama2/tutorials/postman.html - 2023-07-23 + 2023-08-14 daily \ No newline at end of file diff --git a/docs/Lama2/site/sitemap.xml.gz b/docs/Lama2/site/sitemap.xml.gz index 2cca7bb95f1952e8d9b5dede8a4792c434da473f..19a54a34f2640c2fb11f77852c968bb3e2660111 100644 GIT binary patch literal 402 zcmV;D0d4*tiwFplHriwY|8r?{Wo=<_E_iKh0M*vdPV+Df0Ps6cG4;M?3=Vvsx^m+Q z-~mkPwUP1<+hyI`9If(a_Og+|AI(gnLq&~4g(O@Fu2aoXT}b{<_U zzQ61;;gSlsz9bhR!PbR5;L=W#V&_hI*RKIfDnq~BY#-K}r}h1#rd(oIX?}t{;-2uM zA0WhI=dL2(9`^(K4GrGQEY6oK;KefW5;iHsrAEjgdg9z3KI|joc3&ug*q8EAPo~jt zhj5Riy#*cAV4g^R(kA9*CbVw#N&6-G8(@x@%`3IHQ;8ADx^yH+3CuIkYpuO?r~WnT zEJ-`*XutLqh;KkSg;==M>1bX`SgCkqwl19|M59QVrBHy#+C&F5+v~5HG3s@h&UYv4 wSR8^*%_|p3HKO?w8ZrxL^>3l_DX_P0tc6ei&c9)vAB@s}0jSi2D!vc^0J&JnPXGV_ literal 403 zcmV;E0c`#siwFo7#Jpqz|8r?{Wo=<_E_iKh0M*vbZrd;n0N{I{BJe#{>K?icj(h79 zbPvGFj4eQaA?e0>`!Q)S&Z0w z?GPT2w6~yx8q5>P&)USiEQHprK54&1{{YMhvw5ZVb}BI(Bb*;6x?$p0# zT_kBIo$S}X0`UVV=MW2*I-ku;2`d$k%+{rgglH5gixdhFS)1sHW_$fTGe*5G)AjCT x9gAbosd?oJsYWz^LPKT&t^OlaJ_YvHjkWOQ-}!%-*9W5ve*lVo6&t<~008`2%9;QG diff --git a/docs/Lama2/site/tutorials/editor.html b/docs/Lama2/site/tutorials/editor.html index 56d4cea1..14b2670b 100644 --- a/docs/Lama2/site/tutorials/editor.html +++ b/docs/Lama2/site/tutorials/editor.html @@ -806,11 +806,11 @@

    Useful Options
    {
         "logs": ...,
    @@ -833,15 +833,15 @@ 

    Execute current file
    l2 -n -o /tmp/lama2.json my_api.l2
     

    The command mentioned above disables HTTPie colors, -writes the whole transaction to a structured JSON, +writes the whole transaction to a structured JSON, while also printing details into stdout.

    The extension author can simply read the file, and display the contents to users appropriately. For an example, see Lama2 for VSCode (also see Marketplace page).

    Providing environment variable autocompletion

    -

    To obtain a combined JSON representation of environment variables from l2.env and l2config.env, use option -e or --env. This will output the result to stdout. -

    l2 -e  /path/to/my_api.l2
    +

    To obtain a combined JSON representation of environment variables from l2.env and l2config.env, use option -e or --env. This will output the result to stdout.

    +
    l2 -e=''  /path/to/my_api.l2
     
    {
       "AHOST": {
    @@ -854,7 +854,7 @@ 

    Providing environment var } }

    -The extension author can simply read the stdout after executing the command, and display the variables to users appropriately.

    +

    The extension author can simply read the stdout after executing the command, and display the variables to users appropriately.

    l2envvariable variable

    l2configvariable variable

    Go to Example

    diff --git a/docs/Lama2/site/tutorials/installation.html b/docs/Lama2/site/tutorials/installation.html index f32a3d07..c7a78ad7 100644 --- a/docs/Lama2/site/tutorials/installation.html +++ b/docs/Lama2/site/tutorials/installation.html @@ -952,8 +952,8 @@

    One-line install/update in Windows

    (Optional) Import your collections from Postman

    Follow guide - to import your existing Postman collections into a Plain-Text - Lama2 repository.

    +to import your existing Postman collections into a Plain-Text +Lama2 repository.

    Self update

    An easier way to update the binary to latest release is through:

    l2 -u
    @@ -966,10 +966,10 @@ 

    Manual installStep 1: Install HTTPie

    Lama2 depends on HTTPie for Terminal. Use their official instructions to get the http command functional in -your local system.

    +your local system.

    Step 2: Download & install Lama2 binary packages

    Head over to Lama2 releases. Check under -the Assets head to find various packages. Download the relevant package for your +the Assets head to find various packages. Download the relevant package for your operating system and CPU architecture. Once you have the package, run the following:

    tar --overwrite -xvzf <download>.tar.gz
     mv l2 /usr/local/bin
    @@ -998,7 +998,7 @@ 

    From the terminal 0 { - envMap, err := preprocess.GetL2EnvVariables(dir) - if err != nil { - log.Error().Str("Type", "Preprocess").Msg(err.Error()) - return - } - - filteredEnvs := getRelevantEnvs(envMap, o) - marshalAndPrintJSON(filteredEnvs) - return - } + processEnvironmentVariables(o, dir) preprocess.LoadEnvironments(dir) utils.ChangeWorkingDir(oldDir) @@ -136,13 +116,28 @@ func Process(version string) { HandleParsedFile(parsedAPI, o, dir) } +func processEnvironmentVariables(o *lama2cmd.Opts, directory string) { + envMap, err := preprocess.GetL2EnvVariables(directory) + if err != nil { + log.Error().Str("Type", "Preprocess").Msg(err.Error()) + os.Exit(0) + } + if o.Env == "" { // -e='' + marshalAndPrintJSON(envMap) + } else if o.Env != "UNSET" { // -e=any non-empty string + relevantEnvs := getRelevantEnvs(envMap, o) + marshalAndPrintJSON(relevantEnvs) + } +} + func marshalAndPrintJSON(data interface{}) { filteredJSON, err := json.MarshalIndent(data, "", " ") if err != nil { log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal JSON: %v", err)) - return + os.Exit(0) } fmt.Println(string(filteredJSON)) + os.Exit(0) } func getRelevantEnvs(envMap map[string]map[string]interface{}, o *lama2cmd.Opts) map[string]interface{} { diff --git a/lama2cmd/lama2cmd.go b/lama2cmd/lama2cmd.go index 1ddfa487..aa94eb11 100644 --- a/lama2cmd/lama2cmd.go +++ b/lama2cmd/lama2cmd.go @@ -26,7 +26,7 @@ type Opts struct { PostmanFile string `short:"p" long:"postmanfile" description:"JSON export from Postman (Settings -> Data -> Export Data)"` LamaDir string `short:"l" long:"lama2dir" description:"Output directory to put .l2 files after conversion from Postman format"` Help bool `short:"h" long:"help" group:"AddHelp" description:"Usage help for Lama2"` - Env string `short:"e" long:"env" description:"Get a JSON of environment variables revelant to input arg"` + Env string `short:"e" long:"env" default:"UNSET" description:"Get a JSON of environment variables revelant to input arg"` Version bool `long:"version" description:"Print Lama2 binary version"` Positional struct { From e1fab898c2a70b3c85fa37adae1ad086c05a5c56 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Tue, 15 Aug 2023 19:21:48 +0530 Subject: [PATCH 07/13] Updating basic get test, testing --- elfparser/ElfTestSuite/y_0000_basic_get.l2 | 2 +- tests/cli_test.go | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/elfparser/ElfTestSuite/y_0000_basic_get.l2 b/elfparser/ElfTestSuite/y_0000_basic_get.l2 index c521a662..ae5913c8 100644 --- a/elfparser/ElfTestSuite/y_0000_basic_get.l2 +++ b/elfparser/ElfTestSuite/y_0000_basic_get.l2 @@ -1,2 +1,2 @@ GET -https://google.com \ No newline at end of file +http://httpbin.org/get \ No newline at end of file diff --git a/tests/cli_test.go b/tests/cli_test.go index 75f1fa96..e62ba480 100644 --- a/tests/cli_test.go +++ b/tests/cli_test.go @@ -16,12 +16,15 @@ func TestCmdBasic(t *testing.T) { o := *lama2cmd.GetAndValidateCmd(ipArgs) expected := lama2cmd.Opts{ - Verbose: []bool{true}, Nocolor: false, Positional: struct { + Verbose: []bool{true}, + Nocolor: false, + Env: "UNSET", + Positional: struct { LamaAPIFile string }{LamaAPIFile: "../elfparser/ElfTestSuite/y_0000_basic_get.l2"}, } if !reflect.DeepEqual(o, expected) { - t.Errorf("Unsuccessful parsing basic CLI options") + t.Errorf("Unsuccessful parsing basic CLI options.\nExpected:\n%v\nGot:\n%v", expected, o) } } From da128e08b68153ebdc4a856550182405d12a2059 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Tue, 15 Aug 2023 20:56:26 +0530 Subject: [PATCH 08/13] Adding basic command, testing --- tests/basic_commands_test.go | 56 ++++++++++++++++++++++++++++++++++++ tests/env_command_test.go | 5 ++-- 2 files changed, 59 insertions(+), 2 deletions(-) create mode 100644 tests/basic_commands_test.go diff --git a/tests/basic_commands_test.go b/tests/basic_commands_test.go new file mode 100644 index 00000000..2f44d7f8 --- /dev/null +++ b/tests/basic_commands_test.go @@ -0,0 +1,56 @@ +// basic_commands_test.go +package tests + +import ( + "bytes" + "os/exec" + "strings" + "testing" + + "github.com/rs/zerolog/log" +) + +func runL2CommandAndGetOutput(t *testing.T, cmdArgs ...string) string { + + // Get the full path to the l2 binary + l2BinPath := "../build/l2" + + // Check if the l2 binary file exists + if err := checkL2BinaryExists(l2BinPath); err != nil { + t.Error(err) + return "" + } + + // Code to run the l2 command + cmd := exec.Command(l2BinPath, cmdArgs...) + + var stdout bytes.Buffer + cmd.Stdout = &stdout + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + // Execute the command + err := cmd.Run() + if err != nil { + log.Error().Str("Error", stderr.String()).Msg("Error running l2 command") + t.Errorf("Error running l2 command: %v\n", err) + return "" + } + + // Retrieve the captured stdout + stdoutOutput := stdout.String() + log.Info().Str("Test env_command", stdoutOutput).Msg("output from command") + return stdoutOutput +} + +func TestNormalExecution(t *testing.T) { + fpath := "../elfparser/ElfTestSuite/y_0000_basic_get.l2" + cmdArgs := []string{fpath} + output := runL2CommandAndGetOutput(t, cmdArgs...) + + expectedOutputPart := "\"url\": \"http://httpbin.org/get\"" + if !strings.Contains(output, expectedOutputPart) { + t.Errorf("Expected output to contain %q, but got %q", expectedOutputPart, output) + } +} diff --git a/tests/env_command_test.go b/tests/env_command_test.go index c7387304..bdfa93bc 100644 --- a/tests/env_command_test.go +++ b/tests/env_command_test.go @@ -1,3 +1,4 @@ +// env_command_test.go package tests import ( @@ -28,7 +29,7 @@ func TestL2EnvCommand(t *testing.T) { checkBHost(t, envMap) } -func TestL2EnvForAHOenv(t *testing.T) { +func TestL2RelevantEnvForAString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=A", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) @@ -40,7 +41,7 @@ func TestL2EnvForAHOenv(t *testing.T) { checkBHostDoesNotExist(t, envMap) } -func TestL2EnvForBHOenv(t *testing.T) { +func TestL2RelevantEnvForBString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=B", fpath} envMap := runL2CommandAndParseJSON(t, cmdArgs...) From 4e04ebbc29f8dcaefd97763447e9825751b5c9c7 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Wed, 16 Aug 2023 10:04:49 +0530 Subject: [PATCH 09/13] Extracting env related functions, coderefactor --- Env/env.go | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 Env/env.go diff --git a/Env/env.go b/Env/env.go new file mode 100644 index 00000000..981034c7 --- /dev/null +++ b/Env/env.go @@ -0,0 +1,48 @@ +package env + +import ( + "os" + + "github.com/HexmosTech/lama2/lama2cmd" + "github.com/HexmosTech/lama2/preprocess" + "github.com/HexmosTech/lama2/utils" + trie "github.com/Vivino/go-autocomplete-trie" + "github.com/rs/zerolog/log" +) + +func ProcessEnvironmentVariables(o *lama2cmd.Opts, directory string) { + envMap, err := preprocess.GetL2EnvVariables(directory) + if err != nil { + // Potential Errors: + // - JSON marshalling errors. + log.Error().Str("Type", "Preprocess").Msg(err.Error()) + os.Exit(0) + } + // Check if it's an -e invocation + if o.Env != "UNSET_VU5TRVQ" { + if o.Env == "" { // Handle empty -e='' + utils.MarshalAndPrintJSON(envMap) + } else { // Handle non-empty -e + relevantEnvs := GetRelevantEnvs(envMap, o) + utils.MarshalAndPrintJSON(relevantEnvs) + } + } + // If not an -e invocation, the function just continues. +} + +func GetRelevantEnvs(envMap map[string]map[string]interface{}, o *lama2cmd.Opts) map[string]interface{} { + envTrie := trie.New() + for key := range envMap { + envTrie.Insert(key) + } + + searchQuery := o.Env + suggestions := envTrie.SearchAll(searchQuery) + filteredEnvs := make(map[string]interface{}) + for _, suggestion := range suggestions { + if env, found := envMap[suggestion]; found { + filteredEnvs[suggestion] = env + } + } + return filteredEnvs +} From 5a0227cdabb1bb9e713ec7c48dde429f80e06675 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Wed, 16 Aug 2023 10:05:42 +0530 Subject: [PATCH 10/13] Extracting utils related functions, coderefactor --- controller/controller.go | 47 ++-------------------------------------- lama2cmd/lama2cmd.go | 2 +- utils/utils.go | 10 +++++++++ 3 files changed, 13 insertions(+), 46 deletions(-) diff --git a/controller/controller.go b/controller/controller.go index bca08f7e..d215fdc1 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -5,12 +5,11 @@ package contoller import ( - "encoding/json" - "fmt" "os" "github.com/HexmosTech/gabs/v2" "github.com/HexmosTech/httpie-go" + env "github.com/HexmosTech/lama2/Env" "github.com/HexmosTech/lama2/cmdexec" "github.com/HexmosTech/lama2/cmdgen" "github.com/HexmosTech/lama2/codegen" @@ -20,7 +19,6 @@ import ( "github.com/HexmosTech/lama2/preprocess" "github.com/HexmosTech/lama2/prettify" "github.com/HexmosTech/lama2/utils" - trie "github.com/Vivino/go-autocomplete-trie" "github.com/dop251/goja" "github.com/rs/zerolog/log" ) @@ -89,7 +87,7 @@ func Process(version string) { oldDir, _ := os.Getwd() utils.ChangeWorkingDir(dir) - processEnvironmentVariables(o, dir) + env.ProcessEnvironmentVariables(o, dir) preprocess.LoadEnvironments(dir) utils.ChangeWorkingDir(oldDir) @@ -115,44 +113,3 @@ func Process(version string) { log.Debug().Str("Parsed API", parsedAPI.String()).Msg("") HandleParsedFile(parsedAPI, o, dir) } - -func processEnvironmentVariables(o *lama2cmd.Opts, directory string) { - envMap, err := preprocess.GetL2EnvVariables(directory) - if err != nil { - log.Error().Str("Type", "Preprocess").Msg(err.Error()) - os.Exit(0) - } - if o.Env == "" { // -e='' - marshalAndPrintJSON(envMap) - } else if o.Env != "UNSET" { // -e=any non-empty string - relevantEnvs := getRelevantEnvs(envMap, o) - marshalAndPrintJSON(relevantEnvs) - } -} - -func marshalAndPrintJSON(data interface{}) { - filteredJSON, err := json.MarshalIndent(data, "", " ") - if err != nil { - log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal JSON: %v", err)) - os.Exit(0) - } - fmt.Println(string(filteredJSON)) - os.Exit(0) -} - -func getRelevantEnvs(envMap map[string]map[string]interface{}, o *lama2cmd.Opts) map[string]interface{} { - envTrie := trie.New() - for key := range envMap { - envTrie.Insert(key) - } - - searchQuery := o.Env - suggestions := envTrie.SearchAll(searchQuery) - filteredEnvs := make(map[string]interface{}) - for _, suggestion := range suggestions { - if env, found := envMap[suggestion]; found { - filteredEnvs[suggestion] = env - } - } - return filteredEnvs -} diff --git a/lama2cmd/lama2cmd.go b/lama2cmd/lama2cmd.go index aa94eb11..a1e4cafe 100644 --- a/lama2cmd/lama2cmd.go +++ b/lama2cmd/lama2cmd.go @@ -26,7 +26,7 @@ type Opts struct { PostmanFile string `short:"p" long:"postmanfile" description:"JSON export from Postman (Settings -> Data -> Export Data)"` LamaDir string `short:"l" long:"lama2dir" description:"Output directory to put .l2 files after conversion from Postman format"` Help bool `short:"h" long:"help" group:"AddHelp" description:"Usage help for Lama2"` - Env string `short:"e" long:"env" default:"UNSET" description:"Get a JSON of environment variables revelant to input arg"` + Env string `short:"e" long:"env" default:"UNSET_VU5TRVQ" description:"Get a JSON of environment variables revelant to input arg"` Version bool `long:"version" description:"Print Lama2 binary version"` Positional struct { diff --git a/utils/utils.go b/utils/utils.go index 36c412ac..1704eab9 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -138,3 +138,13 @@ func UpdateSelf() { cmd.Stderr = os.Stderr _ = cmd.Run() } + +func MarshalAndPrintJSON(data interface{}) { + filteredJSON, err := json.MarshalIndent(data, "", " ") + if err != nil { + log.Error().Str("Type", "Preprocess").Msg(fmt.Sprintf("Failed to marshal JSON: %v", err)) + os.Exit(0) + } + fmt.Println(string(filteredJSON)) + os.Exit(0) +} From 2b6e35e4543be10e042d7d9fe9ac809894d9a992 Mon Sep 17 00:00:00 2001 From: lovestaco Date: Wed, 16 Aug 2023 10:06:29 +0530 Subject: [PATCH 11/13] Extracting test common functions, coderefactor --- tests/basic_commands_test.go | 40 +------------- tests/cli_test.go | 2 +- tests/env_command_test.go | 82 ++++------------------------ tests/utils/test_utils.go | 100 +++++++++++++++++++++++++++++++++++ 4 files changed, 114 insertions(+), 110 deletions(-) create mode 100644 tests/utils/test_utils.go diff --git a/tests/basic_commands_test.go b/tests/basic_commands_test.go index 2f44d7f8..0364241b 100644 --- a/tests/basic_commands_test.go +++ b/tests/basic_commands_test.go @@ -2,52 +2,16 @@ package tests import ( - "bytes" - "os/exec" "strings" "testing" - "github.com/rs/zerolog/log" + testutils "github.com/HexmosTech/lama2/tests/utils" ) -func runL2CommandAndGetOutput(t *testing.T, cmdArgs ...string) string { - - // Get the full path to the l2 binary - l2BinPath := "../build/l2" - - // Check if the l2 binary file exists - if err := checkL2BinaryExists(l2BinPath); err != nil { - t.Error(err) - return "" - } - - // Code to run the l2 command - cmd := exec.Command(l2BinPath, cmdArgs...) - - var stdout bytes.Buffer - cmd.Stdout = &stdout - - var stderr bytes.Buffer - cmd.Stderr = &stderr - - // Execute the command - err := cmd.Run() - if err != nil { - log.Error().Str("Error", stderr.String()).Msg("Error running l2 command") - t.Errorf("Error running l2 command: %v\n", err) - return "" - } - - // Retrieve the captured stdout - stdoutOutput := stdout.String() - log.Info().Str("Test env_command", stdoutOutput).Msg("output from command") - return stdoutOutput -} - func TestNormalExecution(t *testing.T) { fpath := "../elfparser/ElfTestSuite/y_0000_basic_get.l2" cmdArgs := []string{fpath} - output := runL2CommandAndGetOutput(t, cmdArgs...) + output := testutils.RunL2CommandAndGetOutput(t, cmdArgs...) expectedOutputPart := "\"url\": \"http://httpbin.org/get\"" if !strings.Contains(output, expectedOutputPart) { diff --git a/tests/cli_test.go b/tests/cli_test.go index e62ba480..179b6d36 100644 --- a/tests/cli_test.go +++ b/tests/cli_test.go @@ -18,7 +18,7 @@ func TestCmdBasic(t *testing.T) { expected := lama2cmd.Opts{ Verbose: []bool{true}, Nocolor: false, - Env: "UNSET", + Env: "UNSET_VU5TRVQ", Positional: struct { LamaAPIFile string }{LamaAPIFile: "../elfparser/ElfTestSuite/y_0000_basic_get.l2"}, diff --git a/tests/env_command_test.go b/tests/env_command_test.go index bdfa93bc..65dddf33 100644 --- a/tests/env_command_test.go +++ b/tests/env_command_test.go @@ -2,25 +2,15 @@ package tests import ( - "bytes" - "encoding/json" - "fmt" - "os" - "os/exec" "testing" - "github.com/rs/zerolog/log" + testutils "github.com/HexmosTech/lama2/tests/utils" ) -type EnvData struct { - Src string `json:"src"` - Val string `json:"val"` -} - func TestL2EnvCommand(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -32,7 +22,7 @@ func TestL2EnvCommand(t *testing.T) { func TestL2RelevantEnvForAString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=A", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -44,7 +34,7 @@ func TestL2RelevantEnvForAString(t *testing.T) { func TestL2RelevantEnvForBString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=B", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "BHOST" key is present checkBHost(t, envMap) @@ -56,7 +46,7 @@ func TestL2RelevantEnvForBString(t *testing.T) { func TestL2EnvCommandVerbose(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=", "-v", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -68,7 +58,7 @@ func TestL2EnvCommandVerbose(t *testing.T) { func TestL2EnvWithoutL2config(t *testing.T) { fpath := "../elfparser/ElfTestSuite/no_l2config/api/y_0021_no_l2config.l2" cmdArgs := []string{"-e=", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -77,64 +67,14 @@ func TestL2EnvWithoutL2config(t *testing.T) { func TestL2EnvWithoutL2env(t *testing.T) { fpath := "../elfparser/ElfTestSuite/no_l2env/api/y_0022_no_l2env.l2" cmdArgs := []string{"-e=", fpath} - envMap := runL2CommandAndParseJSON(t, cmdArgs...) + envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) // Check the "BHOST" key is present checkBHost(t, envMap) } -func runL2CommandAndParseJSON(t *testing.T, cmdArgs ...string) map[string]EnvData { - // Get the full path to the l2 binary - l2BinPath := "../build/l2" - - // Check if the l2 binary file exists - if err := checkL2BinaryExists(l2BinPath); err != nil { - t.Error(err) - return make(map[string]EnvData) - } - - // Your existing code to run the l2 command and parse JSON - cmd := exec.Command(l2BinPath, cmdArgs...) - - var stdout bytes.Buffer - cmd.Stdout = &stdout - - // Execute the command - err := cmd.Run() - if err != nil { - // Handle the error if needed - t.Errorf("Error running l2 command: %v\n", err) - return make(map[string]EnvData) - } - - // Retrieve the captured stdout - stdoutOutput := stdout.String() - - log.Debug().Str("Test env_command", stdoutOutput).Msg("output from command") - - // Convert the stdoutOutput string to []byte slice - outputBytes := []byte(stdoutOutput) - - envMap := make(map[string]EnvData) - err = json.Unmarshal(outputBytes, &envMap) - if err != nil { - t.Fatalf("Error unmarshaling JSON env: %v\nOutput:\n%s", err, stdoutOutput) - } - - return envMap -} - -// checkL2BinaryExists checks if the l2 binary file exists in the specified path -func checkL2BinaryExists(l2BinPath string) error { - // Check if the l2 binary file exists - if _, err := os.Stat(l2BinPath); os.IsNotExist(err) { - return fmt.Errorf("l2 binary not found in the build folder %s, please change the path", l2BinPath) - } - return nil -} - // checkAHost checks the "AHOST" key in the JSON map -func checkAHost(t *testing.T, envMap map[string]EnvData) { +func checkAHost(t *testing.T, envMap map[string]testutils.EnvData) { if ahost, ok := envMap["AHOST"]; !ok { t.Error("Expected 'AHOST' key in the JSON, but it was not found") } else { @@ -149,7 +89,7 @@ func checkAHost(t *testing.T, envMap map[string]EnvData) { } // checkBHost checks the "BHOST" key in the JSON map -func checkBHost(t *testing.T, envMap map[string]EnvData) { +func checkBHost(t *testing.T, envMap map[string]testutils.EnvData) { if bhost, ok := envMap["BHOST"]; !ok { t.Error("Expected 'BHOST' key in the JSON, but it was not found") } else { @@ -163,13 +103,13 @@ func checkBHost(t *testing.T, envMap map[string]EnvData) { } } -func checkBHostDoesNotExist(t *testing.T, envMap map[string]EnvData) { +func checkBHostDoesNotExist(t *testing.T, envMap map[string]testutils.EnvData) { if _, ok := envMap["BHOST"]; ok { t.Error("Expected 'BHOST' key not to be present in the JSON, but it was found") } } -func checkAHostDoesNotExist(t *testing.T, envMap map[string]EnvData) { +func checkAHostDoesNotExist(t *testing.T, envMap map[string]testutils.EnvData) { if _, ok := envMap["AHOST"]; ok { t.Error("Expected 'AHOST' key not to be present in the JSON, but it was found") } diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go new file mode 100644 index 00000000..94db4f7d --- /dev/null +++ b/tests/utils/test_utils.go @@ -0,0 +1,100 @@ +package testutils + +import ( + "bytes" + "encoding/json" + "fmt" + "os" + "os/exec" + "testing" + + "github.com/rs/zerolog/log" +) + +type EnvData struct { + Src string `json:"src"` + Val string `json:"val"` +} + +func RunL2CommandAndGetOutput(t *testing.T, cmdArgs ...string) string { + + // Get the full path to the l2 binary + l2BinPath := "../build/l2" + + // Check if the l2 binary file exists + if err := checkL2BinaryExists(l2BinPath); err != nil { + t.Error(err) + return "" + } + + // Code to run the l2 command + cmd := exec.Command(l2BinPath, cmdArgs...) + + var stdout bytes.Buffer + cmd.Stdout = &stdout + + var stderr bytes.Buffer + cmd.Stderr = &stderr + + // Execute the command + err := cmd.Run() + if err != nil { + log.Error().Str("Error", stderr.String()).Msg("Error running l2 command") + t.Errorf("Error running l2 command: %v\n", err) + return "" + } + + // Retrieve the captured stdout + stdoutOutput := stdout.String() + log.Info().Str("Test env_command", stdoutOutput).Msg("output from command") + return stdoutOutput +} + +func RunL2CommandAndParseJSON(t *testing.T, cmdArgs ...string) map[string]EnvData { + // Get the full path to the l2 binary + l2BinPath := "../build/l2" + + // Check if the l2 binary file exists + if err := checkL2BinaryExists(l2BinPath); err != nil { + t.Error(err) + return make(map[string]EnvData) + } + + // Your existing code to run the l2 command and parse JSON + cmd := exec.Command(l2BinPath, cmdArgs...) + + var stdout bytes.Buffer + cmd.Stdout = &stdout + + // Execute the command + err := cmd.Run() + if err != nil { + // Handle the error if needed + t.Errorf("Error running l2 command: %v\n", err) + return make(map[string]EnvData) + } + + // Retrieve the captured stdout + stdoutOutput := stdout.String() + + log.Debug().Str("Test env_command", stdoutOutput).Msg("output from command") + + // Convert the stdoutOutput string to []byte slice + outputBytes := []byte(stdoutOutput) + + envMap := make(map[string]EnvData) + err = json.Unmarshal(outputBytes, &envMap) + if err != nil { + t.Fatalf("Error unmarshaling JSON env: %v\nOutput:\n%s", err, stdoutOutput) + } + + return envMap +} + +func checkL2BinaryExists(l2BinPath string) error { + // Check if the l2 binary file exists + if _, err := os.Stat(l2BinPath); os.IsNotExist(err) { + return fmt.Errorf("l2 binary not found in the build folder %s, please change the path", l2BinPath) + } + return nil +} From c9a2bc10cb61f5f42869abd2b6b0583bc9a7ee7f Mon Sep 17 00:00:00 2001 From: lovestaco Date: Wed, 16 Aug 2023 20:04:15 +0530 Subject: [PATCH 12/13] Making compose functions and extracting repeated func, coderefactor --- tests/basic_commands_test.go | 8 +++- tests/env_command_test.go | 21 +++++--- tests/utils/test_utils.go | 93 ++++++++++++++---------------------- 3 files changed, 56 insertions(+), 66 deletions(-) diff --git a/tests/basic_commands_test.go b/tests/basic_commands_test.go index 0364241b..1af2d6aa 100644 --- a/tests/basic_commands_test.go +++ b/tests/basic_commands_test.go @@ -1,4 +1,3 @@ -// basic_commands_test.go package tests import ( @@ -11,7 +10,12 @@ import ( func TestNormalExecution(t *testing.T) { fpath := "../elfparser/ElfTestSuite/y_0000_basic_get.l2" cmdArgs := []string{fpath} - output := testutils.RunL2CommandAndGetOutput(t, cmdArgs...) + + output, err := testutils.RunL2CommandAndGetOutput(cmdArgs...) + if err != nil { + t.Errorf("Error running L2 command: %v", err) + return + } expectedOutputPart := "\"url\": \"http://httpbin.org/get\"" if !strings.Contains(output, expectedOutputPart) { diff --git a/tests/env_command_test.go b/tests/env_command_test.go index 65dddf33..10b041ea 100644 --- a/tests/env_command_test.go +++ b/tests/env_command_test.go @@ -1,4 +1,3 @@ -// env_command_test.go package tests import ( @@ -7,10 +6,18 @@ import ( testutils "github.com/HexmosTech/lama2/tests/utils" ) +func runL2Command(t *testing.T, cmdArgs ...string) map[string]testutils.EnvData { + envMap, err := testutils.RunL2CommandAndParseJSON(cmdArgs...) + if err != nil { + t.Fatalf("Error running L2 command: %v", err) + } + return envMap +} + func TestL2EnvCommand(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -22,7 +29,7 @@ func TestL2EnvCommand(t *testing.T) { func TestL2RelevantEnvForAString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=A", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -34,7 +41,7 @@ func TestL2RelevantEnvForAString(t *testing.T) { func TestL2RelevantEnvForBString(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=B", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "BHOST" key is present checkBHost(t, envMap) @@ -46,7 +53,7 @@ func TestL2RelevantEnvForBString(t *testing.T) { func TestL2EnvCommandVerbose(t *testing.T) { fpath := "../elfparser/ElfTestSuite/root_variable_override/api/y_0020_root_override.l2" cmdArgs := []string{"-e=", "-v", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -58,7 +65,7 @@ func TestL2EnvCommandVerbose(t *testing.T) { func TestL2EnvWithoutL2config(t *testing.T) { fpath := "../elfparser/ElfTestSuite/no_l2config/api/y_0021_no_l2config.l2" cmdArgs := []string{"-e=", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "AHOST" key is present checkAHost(t, envMap) @@ -67,7 +74,7 @@ func TestL2EnvWithoutL2config(t *testing.T) { func TestL2EnvWithoutL2env(t *testing.T) { fpath := "../elfparser/ElfTestSuite/no_l2env/api/y_0022_no_l2env.l2" cmdArgs := []string{"-e=", fpath} - envMap := testutils.RunL2CommandAndParseJSON(t, cmdArgs...) + envMap := runL2Command(t, cmdArgs...) // Check the "BHOST" key is present checkBHost(t, envMap) diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 94db4f7d..65607390 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -6,7 +6,6 @@ import ( "fmt" "os" "os/exec" - "testing" "github.com/rs/zerolog/log" ) @@ -16,85 +15,65 @@ type EnvData struct { Val string `json:"val"` } -func RunL2CommandAndGetOutput(t *testing.T, cmdArgs ...string) string { +func checkL2BinaryExists(l2BinPath string) error { + if _, err := os.Stat(l2BinPath); os.IsNotExist(err) { + return fmt.Errorf("l2 binary not found in the build folder %s, please change the path", l2BinPath) + } + return nil +} - // Get the full path to the l2 binary +func getL2BinaryPath() (string, error) { l2BinPath := "../build/l2" - - // Check if the l2 binary file exists - if err := checkL2BinaryExists(l2BinPath); err != nil { - t.Error(err) - return "" + err := checkL2BinaryExists(l2BinPath) + if err != nil { + return "", err } + return l2BinPath, nil +} - // Code to run the l2 command - cmd := exec.Command(l2BinPath, cmdArgs...) +func runCommand(binPath string, cmdArgs ...string) (string, error) { + cmd := exec.Command(binPath, cmdArgs...) - var stdout bytes.Buffer + var stdout, stderr bytes.Buffer cmd.Stdout = &stdout - - var stderr bytes.Buffer cmd.Stderr = &stderr - // Execute the command err := cmd.Run() if err != nil { - log.Error().Str("Error", stderr.String()).Msg("Error running l2 command") - t.Errorf("Error running l2 command: %v\n", err) - return "" + log.Error().Str("Error", stderr.String()).Msg("Error running command") + return "", fmt.Errorf("error running command: %v", err) } - // Retrieve the captured stdout - stdoutOutput := stdout.String() - log.Info().Str("Test env_command", stdoutOutput).Msg("output from command") - return stdoutOutput + output := stdout.String() + log.Debug().Str("Test env_command", output).Msg("Output from command") + return output, nil } -func RunL2CommandAndParseJSON(t *testing.T, cmdArgs ...string) map[string]EnvData { - // Get the full path to the l2 binary - l2BinPath := "../build/l2" - - // Check if the l2 binary file exists - if err := checkL2BinaryExists(l2BinPath); err != nil { - t.Error(err) - return make(map[string]EnvData) +func RunL2CommandAndGetOutput(cmdArgs ...string) (string, error) { + l2BinPath, err := getL2BinaryPath() + if err != nil { + return "", err } - // Your existing code to run the l2 command and parse JSON - cmd := exec.Command(l2BinPath, cmdArgs...) - - var stdout bytes.Buffer - cmd.Stdout = &stdout + return runCommand(l2BinPath, cmdArgs...) +} - // Execute the command - err := cmd.Run() +func RunL2CommandAndParseJSON(cmdArgs ...string) (map[string]EnvData, error) { + l2BinPath, err := getL2BinaryPath() if err != nil { - // Handle the error if needed - t.Errorf("Error running l2 command: %v\n", err) - return make(map[string]EnvData) + return nil, err } - // Retrieve the captured stdout - stdoutOutput := stdout.String() - - log.Debug().Str("Test env_command", stdoutOutput).Msg("output from command") - - // Convert the stdoutOutput string to []byte slice - outputBytes := []byte(stdoutOutput) + output, err := runCommand(l2BinPath, cmdArgs...) + if err != nil { + return nil, err + } envMap := make(map[string]EnvData) - err = json.Unmarshal(outputBytes, &envMap) + err = json.Unmarshal([]byte(output), &envMap) if err != nil { - t.Fatalf("Error unmarshaling JSON env: %v\nOutput:\n%s", err, stdoutOutput) + return nil, fmt.Errorf("Error unmarshaling JSON env: %v\nOutput:\n%s", err, output) } - return envMap -} - -func checkL2BinaryExists(l2BinPath string) error { - // Check if the l2 binary file exists - if _, err := os.Stat(l2BinPath); os.IsNotExist(err) { - return fmt.Errorf("l2 binary not found in the build folder %s, please change the path", l2BinPath) - } - return nil + return envMap, nil } From 66897114910b93b54138cae0d93cb48192c6080b Mon Sep 17 00:00:00 2001 From: lovestaco Date: Wed, 16 Aug 2023 20:18:00 +0530 Subject: [PATCH 13/13] Renaming packeges, functions, coderefactor --- controller/controller.go | 2 +- Env/env.go => l2env/l2env.go | 1 + tests/utils/test_utils.go | 12 ++++++------ utils/utils.go | 1 - 4 files changed, 8 insertions(+), 8 deletions(-) rename Env/env.go => l2env/l2env.go (98%) diff --git a/controller/controller.go b/controller/controller.go index d215fdc1..404c47db 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -9,10 +9,10 @@ import ( "github.com/HexmosTech/gabs/v2" "github.com/HexmosTech/httpie-go" - env "github.com/HexmosTech/lama2/Env" "github.com/HexmosTech/lama2/cmdexec" "github.com/HexmosTech/lama2/cmdgen" "github.com/HexmosTech/lama2/codegen" + env "github.com/HexmosTech/lama2/l2env" "github.com/HexmosTech/lama2/lama2cmd" outputmanager "github.com/HexmosTech/lama2/outputManager" "github.com/HexmosTech/lama2/parser" diff --git a/Env/env.go b/l2env/l2env.go similarity index 98% rename from Env/env.go rename to l2env/l2env.go index 981034c7..a781ea63 100644 --- a/Env/env.go +++ b/l2env/l2env.go @@ -26,6 +26,7 @@ func ProcessEnvironmentVariables(o *lama2cmd.Opts, directory string) { relevantEnvs := GetRelevantEnvs(envMap, o) utils.MarshalAndPrintJSON(relevantEnvs) } + os.Exit(0) } // If not an -e invocation, the function just continues. } diff --git a/tests/utils/test_utils.go b/tests/utils/test_utils.go index 65607390..5321dc14 100644 --- a/tests/utils/test_utils.go +++ b/tests/utils/test_utils.go @@ -15,16 +15,16 @@ type EnvData struct { Val string `json:"val"` } -func checkL2BinaryExists(l2BinPath string) error { +func checkLocalL2BinaryExists(l2BinPath string) error { if _, err := os.Stat(l2BinPath); os.IsNotExist(err) { return fmt.Errorf("l2 binary not found in the build folder %s, please change the path", l2BinPath) } return nil } -func getL2BinaryPath() (string, error) { +func getLocalL2BinaryPath() (string, error) { l2BinPath := "../build/l2" - err := checkL2BinaryExists(l2BinPath) + err := checkLocalL2BinaryExists(l2BinPath) if err != nil { return "", err } @@ -50,7 +50,7 @@ func runCommand(binPath string, cmdArgs ...string) (string, error) { } func RunL2CommandAndGetOutput(cmdArgs ...string) (string, error) { - l2BinPath, err := getL2BinaryPath() + l2BinPath, err := getLocalL2BinaryPath() if err != nil { return "", err } @@ -59,7 +59,7 @@ func RunL2CommandAndGetOutput(cmdArgs ...string) (string, error) { } func RunL2CommandAndParseJSON(cmdArgs ...string) (map[string]EnvData, error) { - l2BinPath, err := getL2BinaryPath() + l2BinPath, err := getLocalL2BinaryPath() if err != nil { return nil, err } @@ -72,7 +72,7 @@ func RunL2CommandAndParseJSON(cmdArgs ...string) (map[string]EnvData, error) { envMap := make(map[string]EnvData) err = json.Unmarshal([]byte(output), &envMap) if err != nil { - return nil, fmt.Errorf("Error unmarshaling JSON env: %v\nOutput:\n%s", err, output) + return nil, fmt.Errorf("error unmarshaling JSON env: %v\nOutput:\n%s", err, output) } return envMap, nil diff --git a/utils/utils.go b/utils/utils.go index 1704eab9..9a1d7a24 100644 --- a/utils/utils.go +++ b/utils/utils.go @@ -146,5 +146,4 @@ func MarshalAndPrintJSON(data interface{}) { os.Exit(0) } fmt.Println(string(filteredJSON)) - os.Exit(0) }