diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 82ca6ed4..40138a48 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,7 +1,8 @@ name: Lama2 Release on: - release: - types: [created] + push: + tags: + - 'v[0-9]+.[0-9]+.[0-9]+' jobs: releases-matrix: @@ -27,4 +28,4 @@ jobs: goversion: "https://dl.google.com/go/go1.19.3.linux-amd64.tar.gz" binary_name: "l2" extra_files: LICENSE README.md - ldflags: -X main.version=${{ github.event.release.tag_name }} \ No newline at end of file + ldflags: -X main.version=${{ github.ref_name }} \ No newline at end of file diff --git a/codegen/codegen.go b/codegen/codegen.go index 1982034e..efc76600 100644 --- a/codegen/codegen.go +++ b/codegen/codegen.go @@ -7,6 +7,7 @@ import ( "strings" "text/template" + "github.com/dop251/goja" "github.com/rs/zerolog/log" "github.com/HexmosTech/gabs/v2" @@ -25,6 +26,12 @@ type SnippetArgs struct { SnippetCore string } +var globalVM *goja.Runtime + +func initialize() { + globalVM = cmdexec.GetJSVm() +} + func PrepareHTTPSnippetGenerator(snippetArgs SnippetArgs) string { var templOutput bytes.Buffer templStr := `{{.SnippetCore}} @@ -89,79 +96,82 @@ func GetHARHeadersCookies(headers *gabs.Container) (*gabs.Container, *gabs.Conta return headersData, cookiesData } -func GetRequestHARString(parsedAPI *gabs.Container) string { +func GetRequestHARString(block *gabs.Container) string { + preprocess.ProcessVarsInBlock(block, globalVM) + httpv := block.S("verb", "value") + url := block.S("url", "value") + jsonObj := block.S("details", "ip_data") + headers := block.S("details", "headers") + /* + TODO: Handle multipart case + + multipart := block.S("multipart", "value") + multipartBool := false + if multipart != nil { + multipartBool = true + } + */ + harObj := gabs.New() + + if jsonObj != nil { + postData := gabs.New() + postData.Set("application/json", "mimeType") + postData.Set(jsonObj.String(), "text") + harObj.Set(postData, "postData") + } + + if headers != nil { + headersData, cookiesData := GetHARHeadersCookies(headers) + if cookiesData.String() != "[]" { + harObj.Set(cookiesData, "cookies") + } + harObj.Set(headersData, "headers") + } + + harObj.Set(httpv, "method") + harObj.Set(url, "url") + + res := harObj.String() + return res +} + +func GenerateTargetCode(targetLangLib string, parsedAPI *gabs.Container) { + initialize() parsedAPIblocks := parsedAPI.S("value").Data().(*gabs.Container).Children() - vm := cmdexec.GetJSVm() + convertedSnippetList := make([]string, 0) + for i, block := range parsedAPIblocks { log.Debug().Int("Block num", i).Msg("") log.Debug().Str("Block getting processed", block.String()).Msg("") blockType := block.S("type").Data().(string) if blockType == "processor" { - fmt.Println("Skipping processor block") + snippet := block.S("value").Data().(*gabs.Container).Data().(string) + convertedSnippetList = append(convertedSnippetList, snippet) } else if blockType == "Lama2File" { - preprocess.ProcessVarsInBlock(block, vm) - httpv := block.S("verb", "value") - url := block.S("url", "value") - jsonObj := block.S("details", "ip_data") - headers := block.S("details", "headers") - /* - TODO: Handle multipart case - - multipart := block.S("multipart", "value") - multipartBool := false - if multipart != nil { - multipartBool = true - } - */ - harObj := gabs.New() - - if jsonObj != nil { - postData := gabs.New() - postData.Set("application/json", "mimeType") - postData.Set(jsonObj.String(), "text") - harObj.Set(postData, "postData") + harRequest := GetRequestHARString(block) + snippetArgs := SnippetArgs{} + lang, lib := SplitLangLib(targetLangLib) + snippetArgs.Language = lang + snippetArgs.Library = lib + snippetArgs.HARRequest = harRequest + snippetArgs.SnippetCore = snippetcore + httpsnippetCode := PrepareHTTPSnippetGenerator(snippetArgs) + + vm := cmdexec.GetJSVm() + _, e := vm.RunString(httpsnippetCode) + if e != nil { + log.Fatal(). + Str("Type", "CodeGen"). + Str("Error", e.Error()). + Msg("Code generator error") } - - if headers != nil { - headersData, cookiesData := GetHARHeadersCookies(headers) - if cookiesData.String() != "[]" { - harObj.Set(cookiesData, "cookies") - } - harObj.Set(headersData, "headers") - } - - harObj.Set(httpv, "method") - harObj.Set(url, "url") - - res := harObj.String() - return res + // Init returns an error if the package is not ready for use. + convertedSnippet := vm.Get("convertedSnippet").String() + convertedSnippetList = append(convertedSnippetList, convertedSnippet) } } - // TODO: Handle multi-stage files properly - // Better exception handling - return "" -} - -func GenerateTargetCode(targetLangLib string, parsedAPI *gabs.Container) { - harRequest := GetRequestHARString(parsedAPI) - snippetArgs := SnippetArgs{} - lang, lib := SplitLangLib(targetLangLib) - snippetArgs.Language = lang - snippetArgs.Library = lib - snippetArgs.HARRequest = harRequest - snippetArgs.SnippetCore = snippetcore - httpsnippetCode := PrepareHTTPSnippetGenerator(snippetArgs) - vm := cmdexec.GetJSVm() - _, e := vm.RunString(httpsnippetCode) - if e != nil { - log.Fatal(). - Str("Type", "CodeGen"). - Str("Error", e.Error()). - Msg(fmt.Sprint("Code generator error")) - } - // Init returns an error if the package is not ready for use. - convertedSnippet := vm.Get("convertedSnippet").String() - fmt.Println(convertedSnippet) - clipboard.WriteAll(convertedSnippet) + convertedSnippetFinal := strings.Join(convertedSnippetList, "\n") + fmt.Println(convertedSnippetFinal) + clipboard.WriteAll(convertedSnippetFinal) fmt.Println("Code copied to clipboard") } diff --git a/controller/controller.go b/controller/controller.go index 5a9823f1..b7691e2d 100644 --- a/controller/controller.go +++ b/controller/controller.go @@ -139,7 +139,7 @@ func Process(version string) { Str("Type", "Controller"). Str("LamaFile", o.Positional.LamaAPIFile). Str("Error", e.Error()). - Msg(fmt.Sprint("Parse Error")) + Msg("Parse Error") } log.Debug().Str("Parsed API", parsedAPI.String()).Msg("") HandleParsedFile(parsedAPI, o, dir) diff --git a/docs/Lama2/docs/explanation/l2envOverideL2config.png b/docs/Lama2/docs/explanation/l2envOverideL2config.png deleted file mode 100644 index df8b877f..00000000 Binary files a/docs/Lama2/docs/explanation/l2envOverideL2config.png and /dev/null differ diff --git a/docs/Lama2/docs/explanation/l2format.md b/docs/Lama2/docs/explanation/l2format.md index 52067acd..7f3e4ce6 100644 --- a/docs/Lama2/docs/explanation/l2format.md +++ b/docs/Lama2/docs/explanation/l2format.md @@ -80,9 +80,12 @@ Cookies are specified in a `Cookie` header as follows: Cookie:'sessionid=foo;another-cookie=bar' ``` -### API variables can be defined in `apirequest.l2` -L2 uses the variables declared inside the `.l2` file and makes the request +### Environment Variables + +#### API variables can be defined in `apirequest.l2` +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`: @@ -103,41 +106,45 @@ ${REMOTE}/login Get [Source Files](https://github.com/HexmosTech/Lama2/tree/main/examples/0021_varjson_variable/0021_varjson_variable.l2) -### API environment variables can be defined locally in `l2.env` +#### API environment variables can be defined locally in `l2.env` +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). -`l2.env` is searched for, from the present directory and variables(local) are loaded from this file. +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. -Example `l2.env`: +![l2.env at API level](../tutorials/l2env.png) -``` -export PHOTO=`base64 aadhaarlarge.jpg` -export AHOST="http://localhost:8000" -``` +Go to [Example](../tutorials/examples.md#case-1-l2env-adjacent-to-an-api-file) -Get [Source Files](https://github.com/HexmosTech/Lama2/tree/main/examples/0004_env_switch_root) +Get [Source File](https://github.com/HexmosTech/Lama2/tree/main/examples/0023_l2env_declare) -### API environment variables can be defined at root using `l2config.env` -`l2config.env` is searched for, from the present directory to all its ancestors (upto `/`) and -variables(root) are loaded from this file. -Example `l2config.env`: -``` -export PHOTO=`base64 aadhaarsmall.jpg` -export AHOST="http://localhost:8001" -``` +#### API environment variables can be defined at project root using `l2config.env` +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. -Get [Source Files](https://github.com/HexmosTech/Lama2/tree/main/examples/0019_env_switch_global_root) +![l2config.env at Project root level](../tutorials/l2configAtRoot.png) -### If `l2config.env`(root) variables are redeclared in `l2.env`(local) +Go to [Example](../tutorials/examples.md#case-2-root-variables) -The local variable's value is taken into consideration regardless of both files residing in same directory +Get [Source File](https://github.com/HexmosTech/Lama2/tree/main/examples/0022_l2config_declare) -Get [Source Files](https://github.com/HexmosTech/Lama2/tree/main/examples/0020_override_project_root_local) -![Override of l2config.env with l2.env variable](l2envOverideL2config.png) +#### If `l2config.env`(root) variables are redeclared in `l2.env`(local) +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. -#### The environment file can load results of commands +![l2config.env at Project root level](../tutorials/l2envOverideL2config.png) + +Go to [Example](../tutorials/examples.md#case-3-override-root-variable-with-local-variable) + +Get [Source File](https://github.com/HexmosTech/Lama2/tree/main/examples/0020_override_project_root_local) + + +### The environment file can load results of commands Use the backtick notation `\`command\`` to place the results of commands into environment variables: @@ -148,6 +155,7 @@ export PHOTO=`base64 image.jpeg` One can load the `PHOTO` variable in API files. + ### Chain requests through Javascript blocks *Lama2* supports plain Javascript (JS) blocks diff --git a/docs/Lama2/docs/reference/architecture.md b/docs/Lama2/docs/reference/architecture.md index d04a042e..b355f1cc 100644 --- a/docs/Lama2/docs/reference/architecture.md +++ b/docs/Lama2/docs/reference/architecture.md @@ -44,12 +44,12 @@ From a high level, how does it work now? 3. Initialize Javascript VM for executing JS blocks 4. For each block 1. If block is JS Processor block - 1. Execute JS code in VM + 1. Execute JS code in VM 2. Else if block is Requestor block - 1. Replace variables with values in the following order - 1. Try fetch variable from Javascript VM - 2. If (1) fails, try fetch Local env variable from `l2.env` - 3. Try fetch root env variable from `l2config.env` - 2. Use the processed elements to create an httpie-go request - 3. Fetch response + 1. Replace variables with values in the following order + 1. Try fetch variable from Javascript VM + 2. If (1) fails, try fetch Local env variable from `l2.env` + 3. Try fetch root env variable from `l2config.env` + 2. Use the processed elements to create an httpie-go request + 3. Fetch response 5. If necessary, write the last transaction to `.json` file \ No newline at end of file diff --git a/docs/Lama2/docs/reference/parser.md b/docs/Lama2/docs/reference/parser.md index 5ef8ca8e..8002689c 100644 --- a/docs/Lama2/docs/reference/parser.md +++ b/docs/Lama2/docs/reference/parser.md @@ -82,7 +82,7 @@ var DataInputType string ``` -## func [CustomPairMerge]() +## func [CustomPairMerge]() ```go func CustomPairMerge(destination, source interface{}) interface{} @@ -122,7 +122,7 @@ 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]() +### func \(\*Lama2Parser\) [Boolean]() ```go func (p *Lama2Parser) Boolean() (*gabs.Container, error) @@ -320,7 +320,7 @@ func (p *Lama2Parser) Lama2File() (*gabs.Container, error) -### func \(\*Lama2Parser\) [List]() +### func \(\*Lama2Parser\) [List]() ```go func (p *Lama2Parser) List() (*gabs.Container, error) @@ -329,7 +329,7 @@ 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]() +### func \(\*Lama2Parser\) [Map]() ```go func (p *Lama2Parser) Map() (*gabs.Container, error) @@ -347,7 +347,7 @@ func (p *Lama2Parser) Multipart() (*gabs.Container, error) -### func \(\*Lama2Parser\) [Null]() +### func \(\*Lama2Parser\) [Null]() ```go func (p *Lama2Parser) Null() (*gabs.Container, error) @@ -374,7 +374,7 @@ func (p *Lama2Parser) OneNine() (*gabs.Container, error) -### func \(\*Lama2Parser\) [Pair]() +### func \(\*Lama2Parser\) [Pair]() ```go func (p *Lama2Parser) Pair() (*gabs.Container, error) diff --git a/docs/Lama2/docs/reference/preprocess.md b/docs/Lama2/docs/reference/preprocess.md index e839408e..b37ed095 100644 --- a/docs/Lama2/docs/reference/preprocess.md +++ b/docs/Lama2/docs/reference/preprocess.md @@ -70,7 +70,7 @@ func ExpandURL(block *gabs.Container, vm *goja.Runtime) -## func [GetL2EnvVariables]() +## func [GetL2EnvVariables]() ```go func GetL2EnvVariables(dir string) ([]byte, error) @@ -79,7 +79,7 @@ func GetL2EnvVariables(dir string) ([]byte, 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 c69f86d8..779f7c20 100644 --- a/docs/Lama2/docs/tutorials/editor.md +++ b/docs/Lama2/docs/tutorials/editor.md @@ -2,8 +2,9 @@ The `l2` command provides some helpful options for extension developers. The options are: -1. `--nocolor` or `-n` disables colored output in httpie-go (in CLI); -1. `--output=
  • + + Environment Variables + + +