From 2445ae54b28b6f15fdf7e23a24651467e3d5334c Mon Sep 17 00:00:00 2001 From: Lucas Pickering Date: Sat, 11 Nov 2023 05:47:36 -0500 Subject: [PATCH] Pre-parse template strings and switch to nom for parsing Wow it's a big refactor --- CHANGELOG.md | 8 + Cargo.lock | 2 +- Cargo.toml | 2 +- docs/src/SUMMARY.md | 2 +- docs/src/api/chain.md | 2 +- docs/src/api/request_recipe.md | 18 +- .../api/{template_string.md => template.md} | 6 +- docs/src/user_guide/templates.md | 4 +- src/collection.rs | 33 +- src/collection/insomnia.rs | 19 +- src/factory.rs | 8 +- src/http/record.rs | 6 + src/template.rs | 596 +++++------------- src/template/error.rs | 13 + src/template/parse.rs | 213 +++++++ src/template/render.rs | 346 ++++++++++ src/tui.rs | 4 +- src/tui/message.rs | 4 +- src/tui/view/component/request.rs | 4 +- src/tui/view/component/template_preview.rs | 83 ++- src/tui/view/util.rs | 12 +- src/util.rs | 2 +- 22 files changed, 843 insertions(+), 544 deletions(-) rename docs/src/api/{template_string.md => template.md} (58%) create mode 100644 src/template/parse.rs create mode 100644 src/template/render.rs diff --git a/CHANGELOG.md b/CHANGELOG.md index 9724bfda..1c035666 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +## [Unreleased] - ReleaseDate + +### Changed + +- Parse templates up front instead of during render +- Switch to nom for template parsing + - Parse errors should be better now + ## [0.6.0] - 2023-11-11 ### Added diff --git a/Cargo.lock b/Cargo.lock index cf902915..b5e07328 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1579,9 +1579,9 @@ dependencies = [ "futures", "indexmap 2.1.0", "itertools", + "nom", "notify", "ratatui", - "regex", "reqwest", "rmp-serde", "rstest", diff --git a/Cargo.toml b/Cargo.toml index e3d3c073..523f9352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,9 +22,9 @@ dirs = "^5.0.1" futures = "^0.3.28" indexmap = {version = "^2.0.1", features = ["serde"]} itertools = "^0.11.0" +nom = "7.1.3" notify = {version = "^6.1.1", default-features = false, features = ["macos_fsevent"]} ratatui = "^0.24.0" -regex = {version = "^1.9.5", features = ["pattern"]} reqwest = {version = "^0.11.20", default-features = false, features = ["rustls-tls"]} rmp-serde = "^1.1.2" rusqlite = {version = "^0.29.0", default-features = false, features = ["bundled", "chrono", "uuid"]} diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md index f75cc048..ab10c26c 100644 --- a/docs/src/SUMMARY.md +++ b/docs/src/SUMMARY.md @@ -18,4 +18,4 @@ - [Request Recipe](./api/request_recipe.md) - [Chain](./api/chain.md) - [Chain Source](./api/chain_source.md) - - [Template String](./api/template_string.md) + - [Template](./api/template.md) diff --git a/docs/src/api/chain.md b/docs/src/api/chain.md index a7cb05d9..b5207354 100644 --- a/docs/src/api/chain.md +++ b/docs/src/api/chain.md @@ -2,7 +2,7 @@ A chain is a intermediate data type to enable complex template values. Chains enable complex value sources and additional customization, such as much values as sensitive to be masked in the UI. -To use a chain in a template string, reference it as `{{chains.}}`. +To use a chain in a template, reference it as `{{chains.}}`. ## Fields diff --git a/docs/src/api/request_recipe.md b/docs/src/api/request_recipe.md index 33bdd755..e8ff346d 100644 --- a/docs/src/api/request_recipe.md +++ b/docs/src/api/request_recipe.md @@ -4,15 +4,15 @@ A request recipe defines how to make a particular request. For a REST API, you'l ## Fields -| Field | Type | Description | Default | -| --------- | --------------------------------------------------------- | --------------------------------- | ------------- | -| `id` | `string` | Unique identifier for this recipe | Required | -| `name` | `string` | Descriptive name to use in the UI | Value of `id` | -| `method` | [`TemplateString`](./template_string.md) | HTTP request method | Required | -| `url` | [`TemplateString`](./template_string.md) | HTTP request URL | Required | -| `query` | [`mapping[string, TemplateString]`](./template_string.md) | HTTP request query parameters | `{}` | -| `headers` | [`mapping[string, TemplateString]`](./template_string.md) | HTTP request headers | `{}` | -| `body` | [`TemplateString`](./template_string.md) | HTTP request body | `null` | +| Field | Type | Description | Default | +| --------- | -------------------------------------------- | --------------------------------- | ------------- | +| `id` | `string` | Unique identifier for this recipe | Required | +| `name` | `string` | Descriptive name to use in the UI | Value of `id` | +| `method` | `string` | HTTP request method | Required | +| `url` | [`Template`](./template.md) | HTTP request URL | Required | +| `query` | [`mapping[string, Template]`](./template.md) | HTTP request query parameters | `{}` | +| `headers` | [`mapping[string, Template]`](./template.md) | HTTP request headers | `{}` | +| `body` | [`Template`](./template.md) | HTTP request body | `null` | ## Examples diff --git a/docs/src/api/template_string.md b/docs/src/api/template.md similarity index 58% rename from docs/src/api/template_string.md rename to docs/src/api/template.md index 6f27dcf1..be7798e9 100644 --- a/docs/src/api/template_string.md +++ b/docs/src/api/template.md @@ -1,8 +1,8 @@ -# Template String +# Template -A template string is represented in YAML as a normal string, and thus supports [all of YAML's string syntaxes](https://www.educative.io/answers/how-to-represent-strings-in-yaml). Template strings receive post-processing that injects dynamic values into the string. A templated value is represented with `{{...}}`. +A template is represented in YAML as a normal string, and thus supports [all of YAML's string syntaxes](https://www.educative.io/answers/how-to-represent-strings-in-yaml). Templates receive post-processing that injects dynamic values into the string. A templated value is represented with `{{...}}`. -Template strings can generally be used in any _value_ in a request recipe (_not_ in keys). They _cannot_ be used in profiles or chains, to avoid the potential for recursive templating. If this feature would be useful to you, [le tme know](https://github.com/LucasPickering/slumber/issues/15). +Templates can generally be used in any _value_ in a request recipe (_not_ in keys). They _cannot_ be used in profiles or chains, to avoid the potential for recursive templating. If this feature would be useful to you, [le tme know](https://github.com/LucasPickering/slumber/issues/15). ## Template Sources diff --git a/docs/src/user_guide/templates.md b/docs/src/user_guide/templates.md index 0727428f..333a7317 100644 --- a/docs/src/user_guide/templates.md +++ b/docs/src/user_guide/templates.md @@ -2,10 +2,10 @@ Templates enable dynamic string construction. Slumber's template language is relatively simple, compared to complex HTML templating languages like Handlebars or Jinja. The goal is to be intuitive and unsurprising. It doesn't support complex features like for loops, conditionals, etc. -All string _values_ (i.e. _not_ keys) in a request collection are template strings, meaning they support templating. The syntax for templating a value into a string is double curly braces `{{...}}`. The contents inside the braces tell Slumber how to retrieve the dynamic value. +All string _values_ (i.e. _not_ keys) in a request collection are templates, meaning they support templating. The syntax for templating a value into a string is double curly braces `{{...}}`. The contents inside the braces tell Slumber how to retrieve the dynamic value. TODO add some more content here ## API Reference -For more detailed configuration info, see the [API reference docs](../api/template_string.md) on template strings. +For more detailed configuration info, see the [API reference docs](../api/template.md) on templates. diff --git a/src/collection.rs b/src/collection.rs index 3343bd64..bd0d6ab8 100644 --- a/src/collection.rs +++ b/src/collection.rs @@ -3,7 +3,7 @@ mod insomnia; -use crate::template::TemplateString; +use crate::template::Template; use anyhow::{anyhow, Context}; use derive_more::{Deref, Display, From}; use indexmap::IndexMap; @@ -86,12 +86,12 @@ pub struct RequestRecipe { /// *Not* a template string because the usefulness doesn't justify the /// complexity pub method: String, - pub url: TemplateString, - pub body: Option, + pub url: Template, + pub body: Option