diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 3fadddc..49b3b62 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -4,7 +4,7 @@ on:
- main
pull_request:
branches:
- - '**'
+ - "**"
name: CI
@@ -15,32 +15,32 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- - uses: actions-rust-lang/audit@v1
- name: Audit Rust Dependencies
+ - name: "Generate Cargo.lock"
+ run: cargo generate-lockfile
+ - uses: rustsec/audit-check@v2
with:
- denyWarnings: true
- createIssues: false
+ token: ${{ secrets.GITHUB_TOKEN }}
licenses:
name: Licenses
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v4
- - uses: EmbarkStudios/cargo-deny-action@v2
+ - uses: actions/checkout@v4
+ - uses: EmbarkStudios/cargo-deny-action@v2
- - name: cargo-about cache
- id: cargo-about-cache
- uses: actions/cache@v4
- with:
- path: ~/.cargo/bin/cargo-about
- key: cargo-about-${{ runner.os }}
+ - name: cargo-about cache
+ id: cargo-about-cache
+ uses: actions/cache@v4
+ with:
+ path: ~/.cargo/bin/cargo-about
+ key: cargo-about-${{ runner.os }}
- - name: cargo-about install
- if: steps.cargo-about-cache.outputs.cache-hit != 'true'
- run: cargo install --locked cargo-about
+ - name: cargo-about install
+ if: steps.cargo-about-cache.outputs.cache-hit != 'true'
+ run: cargo install --locked cargo-about
- - name: cargo-about generate licenses
- run: cargo about generate --workspace --features "server_side_graphviz" about.hbs > doc/src/licenses.html
+ - name: cargo-about generate licenses
+ run: cargo about generate --workspace about.hbs > doc/src/licenses.html
fmt:
name: Rustfmt
@@ -82,14 +82,14 @@ jobs:
toolchain: nightly
components: clippy
- - name: 'Run clippy (client side graphviz)'
+ - name: "Run clippy (client side graphviz)"
run: |
cargo clippy --workspace -- -D warnings
- - name: 'Run clippy (server side graphviz)'
+ - name: "Run clippy (server side graphviz)"
# we cannot use `--all-features` because `dot_ix` has features that are mutually exclusive.
run: |
- cargo clippy --workspace --features "server_side_graphviz" -- -D warnings
+ cargo clippy --workspace -- -D warnings
coverage:
name: Coverage
@@ -104,14 +104,14 @@ jobs:
- uses: taiki-e/install-action@cargo-llvm-cov
- - name: 'Collect coverage'
+ - name: "Collect coverage"
run: ./coverage.sh
- - name: 'Print directory sizes'
+ - name: "Print directory sizes"
run: du -sh target/coverage target/llvm-cov-target
- name: Upload to codecov.io
- uses: codecov/codecov-action@v4
+ uses: codecov/codecov-action@v5
with:
files: ./target/coverage/lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
@@ -124,11 +124,11 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- - name: 'Build and test'
+ - name: "Build and test"
run: cargo test --workspace
- build_playground_linux:
- name: Build Playground (Linux)
+ build_playground_linux_leptos:
+ name: Build Playground (Linux) - cargo-leptos
# On `ubuntu-latest`, this job fails because the CI runner is CPU bound
# when `monaco` is built.
#
@@ -137,32 +137,82 @@ jobs:
# See
runs-on: ubuntu-22.04
timeout-minutes: 25
+ env:
+ # Seems to solve this issue:
+ #
+ # ```text
+ # 0: Unexpected token Semicolon at :1360:9
+ # ```
+ LEPTOS_TAILWIND_VERSION: "v4.1.4"
steps:
- uses: actions/checkout@v4
- - name: 'Install Rust'
+ - name: "Install Rust"
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: wasm32-unknown-unknown
- - name: cargo-leptos cache
- id: cargo-leptos-cache
- uses: actions/cache@v4
+ - name: cargo-leptos cache restore
+ id: cargo_leptos_cache_restore
+ uses: actions/cache/restore@v4
with:
path: ~/.cargo/bin/cargo-leptos
- key: cargo-leptos-${{ runner.os }}
+ key: ${{ runner.os }}-cargo-leptos
+
+ - run: cargo install cargo-leptos
+ if: steps.cargo_leptos_cache_restore.outputs.cache-hit != 'true'
- - name: cargo-leptos install
- if: steps.cargo-leptos-cache.outputs.cache-hit != 'true'
- run: cargo install cargo-leptos
+ - name: cargo-leptos cache save
+ id: cargo_leptos_cache_save
+ uses: actions/cache/save@v4
+ if: always() && steps.cargo_leptos_cache_restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.cargo/bin/cargo-leptos
+ key: ${{ runner.os }}-cargo-leptos
- - name: 'Build playground'
+ - name: "Build playground"
working-directory: ./playground
run: cargo leptos build -v
- - name: 'Build playground (server side graphviz)'
+ build_playground_linux_trunk:
+ name: Build Playground (Linux) - trunk
+ # On `ubuntu-latest`, this job fails because the CI runner is CPU bound
+ # when `monaco` is built.
+ #
+ # Trying 22.04 to see if it alleviates the problem.
+ #
+ # See
+ runs-on: ubuntu-22.04
+ timeout-minutes: 25
+ steps:
+ - uses: actions/checkout@v4
+ - name: "Install Rust"
+ uses: dtolnay/rust-toolchain@master
+ with:
+ toolchain: stable
+ targets: wasm32-unknown-unknown
+
+ - name: trunk cache restore
+ id: trunk_cache_restore
+ uses: actions/cache/restore@v4
+ with:
+ path: ~/.cargo/bin/trunk
+ key: ${{ runner.os }}-trunk
+
+ - run: cargo install trunk
+ if: steps.trunk_cache_restore.outputs.cache-hit != 'true'
+
+ - name: trunk cache save
+ id: trunk_cache_save
+ uses: actions/cache/save@v4
+ if: always() && steps.trunk_cache_restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.cargo/bin/trunk
+ key: ${{ runner.os }}-trunk
+
+ - name: "Build playground"
working-directory: ./playground
- run: cargo leptos build --features "server_side_graphviz" -v
+ run: trunk build -v
build_and_test_windows:
name: Build and Test (Windows)
@@ -175,11 +225,11 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- - name: 'Build and test'
+ - name: "Build and test"
run: cargo test --workspace
- build_playground_windows:
- name: Build Playground (Windows)
+ build_playground_windows_trunk:
+ name: Build Playground (Windows) - trunk
runs-on: windows-latest
timeout-minutes: 30
steps:
@@ -187,29 +237,30 @@ jobs:
run: git config --global core.symlinks true
- uses: actions/checkout@v4
- - name: 'Install Rust'
+ - name: "Install Rust"
uses: dtolnay/rust-toolchain@master
with:
toolchain: stable
targets: wasm32-unknown-unknown
- - name: cargo-leptos cache
- id: cargo-leptos-cache
- uses: actions/cache@v4
+ - name: trunk cache restore
+ id: trunk_cache_restore
+ uses: actions/cache/restore@v4
with:
- path: 'C:\Users\runneradmin\.cargo\bin\cargo-leptos.exe'
- key: cargo-leptos-${{ runner.os }}
+ path: 'C:\Users\runneradmin\.cargo\bin\trunk.exe'
+ key: ${{ runner.os }}-trunk
- - name: cargo-leptos install
- if: steps.cargo-leptos-cache.outputs.cache-hit != 'true'
- # --locked: fix is in-progress at https://github.com/leptos-rs/cargo-leptos/pull/274
- run: |-
- cargo install cargo-leptos --locked
+ - run: cargo install trunk
+ if: steps.trunk_cache_restore.outputs.cache-hit != 'true'
- - name: 'Build playground'
- working-directory: ./playground
- run: cargo leptos build -v
+ - name: trunk cache save
+ id: trunk_cache_save
+ uses: actions/cache/save@v4
+ if: always() && steps.trunk_cache_restore.outputs.cache-hit != 'true'
+ with:
+ path: 'C:\Users\runneradmin\.cargo\bin\trunk.exe'
+ key: ${{ runner.os }}-trunk
- - name: 'Build playground (server side graphviz)'
+ - name: "Build playground"
working-directory: ./playground
- run: cargo leptos build --features "server_side_graphviz" -v
+ run: trunk build -v
diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 261fc88..82463c3 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -32,29 +32,15 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- - name: 'Install Rust'
+ - name: "Install Rust"
uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
targets: wasm32-unknown-unknown
- - name: cargo-leptos cache
- id: cargo-leptos-cache
- uses: actions/cache@v4
- with:
- path: ~/.cargo/bin/cargo-leptos
- key: cargo-leptos-${{ runner.os }}
-
- - name: cargo-leptos install
- if: steps.cargo-leptos-cache.outputs.cache-hit != 'true'
- run: cargo install cargo-leptos
-
- name: Setup Pages
uses: actions/configure-pages@v5
- - name: Download and install tailwindcss binary
- run: npm install -D tailwindcss
-
- name: Download and install Trunk binary
run: wget -qO- https://github.com/thedodd/trunk/releases/latest/download/trunk-x86_64-unknown-linux-gnu.tar.gz | tar -xzf-
@@ -81,7 +67,7 @@ jobs:
uses: actions/upload-pages-artifact@v3
with:
# Upload playground/dist directory
- path: 'playground/dist'
+ path: "playground/dist"
- name: Deploy to GitHub Pages
id: deployment
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index ca2d860..c9bbca1 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,7 +1,7 @@
on:
push:
tags:
- - '*'
+ - "*"
name: Publish
@@ -12,11 +12,11 @@ jobs:
timeout-minutes: 10
steps:
- uses: actions/checkout@v4
- - uses: actions-rust-lang/audit@v1
- name: Audit Rust Dependencies
+ - name: "Generate Cargo.lock"
+ run: cargo generate-lockfile
+ - uses: rustsec/audit-check@v2
with:
- denyWarnings: true
- createIssues: false
+ token: ${{ secrets.GITHUB_TOKEN }}
build_and_test_linux:
name: Build and Test (Linux)
@@ -26,7 +26,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- - name: 'Build and test'
+ - name: "Build and test"
run: cargo test --workspace
build_and_test_windows:
@@ -40,7 +40,7 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- - name: 'Build and test'
+ - name: "Build and test"
run: cargo test --workspace
crates_io_publish:
@@ -56,34 +56,30 @@ jobs:
- uses: actions/checkout@v4
- uses: dtolnay/rust-toolchain@stable
- - name: cargo-release Cache
- id: cargo_release_cache
- uses: actions/cache@v4
+ - name: cargo-release cache restore
+ id: cargo_release_cache_restore
+ uses: actions/cache/restore@v4
with:
path: ~/.cargo/bin/cargo-release
key: ${{ runner.os }}-cargo-release
- run: cargo install cargo-release
- if: steps.cargo_release_cache.outputs.cache-hit != 'true'
+ if: steps.cargo_release_cache_restore.outputs.cache-hit != 'true'
+
+ - name: cargo-release cache save
+ id: cargo_release_cache_save
+ uses: actions/cache/save@v4
+ if: always() && steps.cargo_release_cache_restore.outputs.cache-hit != 'true'
+ with:
+ path: ~/.cargo/bin/cargo-release
+ key: ${{ runner.os }}-cargo-release
- name: cargo login
- run: cargo login ${{ secrets.CRATES_IO_API_TOKEN }}
+ run: |-
+ echo "${{ secrets.CRATES_IO_API_TOKEN }}" | cargo login
# allow-branch HEAD is because GitHub actions switches
# to the tag while building, which is a detached head
-
- # Publishing is currently messy, because:
- #
- # * `peace_rt_model_core` exports `NativeError` or `WebError` depending on the target.
- # * `peace_rt_model_web` fails to build when publishing the workspace for a native target.
- # * `peace_rt_model_web` still needs its dependencies to be published before it can be
- # published.
- # * `peace_rt_model_hack` needs `peace_rt_model_web` to be published before it can be
- # published.
- #
- # We *could* pass through `--no-verify` so `cargo` doesn't build the crate before publishing,
- # which is reasonable, since this job only runs after the Linux, Windows, and WASM builds
- # have passed.
- name: "cargo release publish"
run: |-
cargo release \
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 486a492..029d0ad 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
# Changelog
+## 0.10.0 (2025-04-18)
+
+* Update crate rust edition to 2024.
+* ***Breaking:*** Remove `"server_side_graphviz"` feature.
+* ***Breaking:*** Upgrade to `leptos 0.8.0-rc1`.
+
+
## 0.9.2 (2025-01-27)
* Update dependency versions and address `RUSTSEC-2024-0370`.
diff --git a/Cargo.toml b/Cargo.toml
index eccf3ee..a6e2165 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -24,27 +24,19 @@ dot_ix_rt = { workspace = true, optional = true }
dot_ix_web_components = { workspace = true, optional = true }
[features]
-default = [
- "rt",
- "web_components",
-]
+default = ["rt", "web_components"]
rt = ["dep:dot_ix_rt"]
web_components = ["dep:dot_ix_web_components"]
ssr = ["dot_ix_web_components?/ssr"]
-server_side_graphviz = ["dot_ix_web_components?/server_side_graphviz"]
[workspace]
-members = [
- "crate/*",
- "playground",
- "workspace_tests",
-]
+members = ["crate/*", "playground", "workspace_tests"]
[workspace.package]
-version = "0.9.2"
+version = "0.10.0"
authors = ["Azriel Hoh "]
-edition = "2021"
+edition = "2024"
homepage = "https://github.com/azriel91/dot_ix"
repository = "https://github.com/azriel91/dot_ix"
readme = "README.md"
@@ -54,44 +46,45 @@ license = "MIT OR Apache-2.0"
[workspace.dependencies]
# dot_ix crates
-dot_ix = { version = "0.9.2", path = "." }
-dot_ix_model = { version = "0.9.2", path = "crate/model" }
-dot_ix_rt = { version = "0.9.2", path = "crate/rt" }
-dot_ix_static_check_macros = { version = "0.9.2", path = "crate/static_check_macros" }
-dot_ix_web_components = { version = "0.9.2", path = "crate/web_components" }
+dot_ix = { version = "0.10.0", path = "." }
+dot_ix_model = { version = "0.10.0", path = "crate/model" }
+dot_ix_rt = { version = "0.10.0", path = "crate/rt" }
+dot_ix_static_check_macros = { version = "0.10.0", path = "crate/static_check_macros" }
+dot_ix_web_components = { version = "0.10.0", path = "crate/web_components" }
# external crates
-axum = "0.7.9"
+axum = "0.8.3"
cfg-if = "1"
console_error_panic_hook = "0.1"
console_log = "1"
gloo-net = "0.6.0"
-indexmap = "2.7.1"
-indoc = "2.0.5"
+id_newtype = "0.1.0"
+indexmap = "2.9.0"
+indoc = "2.0.6"
js-sys = "0.3.77"
web-sys = "0.3.77"
-leptos = { version = "0.7.4" }
-leptos_axum = "0.7.4"
-leptos_meta = { version = "0.7.4" }
-leptos_router = { version = "0.7.4" }
-leptos_router_macro = { version = "0.7.4" }
-leptos-use = "0.15.5"
+leptos = { version = "0.8.0-rc1" }
+leptos_axum = "0.8.0-rc1"
+leptos_meta = { version = "0.8.0-rc1" }
+leptos_router = { version = "0.8.0-rc1" }
+leptos_router_macro = { version = "0.8.0-rc1" }
+leptos-use = "0.16.0-beta"
log = "0.4"
log4rs = { version = "1.3.0", default-features = false }
monaco = "0.5.0"
-serde = "1.0.217"
-tempfile = "3.15.0"
-tokio = "1.43.0"
+serde = "1.0.219"
+tempfile = "3.19.1"
+tokio = "1.44.2"
tower = "0.5.2"
wasm-bindgen = "0.2.100"
tailwind-css = "0.13.0"
-thiserror = "2.0.11"
+thiserror = "2.0.12"
tracing = "0.1.41"
-http = "1.2.0"
-proc-macro2 = "1.0.93"
-quote = "1.0.38"
-reqwest = "0.12.12"
-syn = "2.0.96"
+http = "1.3.1"
+proc-macro2 = "1.0.95"
+quote = "1.0.40"
+reqwest = "0.12.15"
+syn = "2.0.100"
serde_yaml = "0.9.34"
[workspace.lints.rust]
diff --git a/README.md b/README.md
index b683ed1..b6a8091 100644
--- a/README.md
+++ b/README.md
@@ -27,14 +27,10 @@ https://user-images.githubusercontent.com/2993230/253878816-0729970f-651f-45ef-a
Add the following to `Cargo.toml`
```toml
-dot_ix = "0.9.2"
+dot_ix = "0.10.0"
# Enables the `FlexDiag` web component.
-dot_ix = { version = "0.9.2", features = ["flex_diag"] }
-
-# Enables server side dot generation.
-# Requires graphviz `dot` to be installed server side.
-dot_ix = { version = "0.9.2", features = ["server_side_graphviz"] }
+dot_ix = { version = "0.10.0", features = ["flex_diag"] }
```
@@ -46,20 +42,8 @@ cargo install cargo-leptos
# Then, one of:
# * client side rendering -- uses WASM compiled graphviz to generate the graph.
cargo leptos watch
-# * server side rendering -- runs `dot` on the server to generate the graph.
-# Requires `graphviz` to be installed.
-cargo leptos watch --features "server_side_graphviz" -v
```
-For server side rendering, the `"server_side_graphviz"` feature needs to be passed in separately because that feature still needs to be enabled for the lib compilation, i.e.
-
-* server side rendering:
- - lib features: `"server_side_graphviz"`
- - bin features: `"ssr,server_side_graphviz"`
-* client side rendering:
- - lib features: `""`
- - bin features: `""`
-
## To Do
diff --git a/crate/model/Cargo.toml b/crate/model/Cargo.toml
index 89c7729..74fd612 100644
--- a/crate/model/Cargo.toml
+++ b/crate/model/Cargo.toml
@@ -17,6 +17,7 @@ doctest = false
test = false
[dependencies]
+id_newtype = { workspace = true }
indexmap = { workspace = true, features = ["serde"] }
serde = { workspace = true, features = ["derive"] }
dot_ix_static_check_macros = { workspace = true }
diff --git a/crate/model/src/common.rs b/crate/model/src/common.rs
index 5323eb1..14d0d77 100644
--- a/crate/model/src/common.rs
+++ b/crate/model/src/common.rs
@@ -1,4 +1,3 @@
-pub(crate) use self::id_newtype::id_newtype;
pub use self::{
any_id::{AnyId, AnyIdInvalidFmt},
dot_src_and_styles::DotSrcAndStyles,
@@ -34,7 +33,6 @@ mod edge_descs;
mod edge_id;
mod edge_tags_set;
mod edges;
-mod id_newtype;
mod image_id;
mod images;
mod node_descs;
diff --git a/crate/model/src/common/any_id.rs b/crate/model/src/common/any_id.rs
index 630625d..6217df9 100644
--- a/crate/model/src/common/any_id.rs
+++ b/crate/model/src/common/any_id.rs
@@ -12,7 +12,7 @@ use crate::common::{EdgeId, NodeId, TagId};
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct AnyId(Cow<'static, str>);
-crate::common::id_newtype!(AnyId, AnyIdInvalidFmt, node_id);
+id_newtype::id_newtype!(AnyId, AnyIdInvalidFmt, node_id);
impl From for AnyId {
fn from(node_id: NodeId) -> Self {
diff --git a/crate/model/src/common/edge_id.rs b/crate/model/src/common/edge_id.rs
index 096252f..f1a3146 100644
--- a/crate/model/src/common/edge_id.rs
+++ b/crate/model/src/common/edge_id.rs
@@ -23,7 +23,7 @@ use crate::common::AnyId;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct EdgeId(Cow<'static, str>);
-crate::common::id_newtype!(EdgeId, EdgeIdInvalidFmt, edge_id);
+id_newtype::id_newtype!(EdgeId, EdgeIdInvalidFmt, edge_id);
impl From for EdgeId {
fn from(any_id: AnyId) -> Self {
diff --git a/crate/model/src/common/id_newtype.rs b/crate/model/src/common/id_newtype.rs
deleted file mode 100644
index c18c27d..0000000
--- a/crate/model/src/common/id_newtype.rs
+++ /dev/null
@@ -1,186 +0,0 @@
-/// Implements common behaviour for an ID type.
-///
-/// The implemented behaviour includes:
-///
-/// * `IdType::new`
-/// * `IdType::new_unchecked`
-/// * `IdType::is_valid_id`
-/// * `IdType::into_inner`
-/// * `std::ops::Deref`
-/// * `std::ops::DerefMut`
-/// * `std::fmt::Display`
-/// * `std::str::FromStr`
-/// * `TryFrom`
-/// * `TryFrom<&'static str>`
-///
-/// A separate error type is also generated, which indicates an invalid value
-/// when the ID type is instantiated with `new`.
-///
-/// # Usage
-///
-/// ```rust
-/// use std::borrow::Cow;
-///
-/// // replace this with your ID type's macro
-/// use dot_ix_static_check_macros::my_id_type;
-/// use serde::{Deserialize, Serialize};
-///
-/// // Rename your ID type
-/// #[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
-/// pub struct MyIdType(Cow<'static, str>);
-///
-/// crate::id_newtype!(
-/// MyIdType, // Name of the ID type
-/// MyIdTypeInvalidFmt, // Name of the invalid value error
-/// my_id_type, // Name of the static check macro
-/// );
-/// ```
-macro_rules! id_newtype {
- ($ty_name:ident, $ty_err_name:ident, $macro_name:ident) => {
- impl $ty_name {
- #[doc = concat!("Returns a new `", stringify!($ty_name), "` if the given `&str` is valid.")]
- ///
- #[doc = concat!("Most users should use the [`", stringify!($macro_name), "!`] macro as this provides")]
- /// compile time checks and returns a `const` value.
- ///
- #[doc = concat!("[`", stringify!($macro_name), "!`]: dot_ix_static_check_macros::profile")]
- pub fn new(s: &'static str) -> Result> {
- Self::try_from(s)
- }
-
- #[doc = concat!("Returns a new `", stringify!($ty_name), "`.")]
- ///
- #[doc = concat!("Most users should use the [`", stringify!($macro_name), "!`] macro as this provides")]
- /// compile time checks and returns a `const` value.
- ///
- #[doc = concat!("[`", stringify!($macro_name), "!`]: dot_ix_static_check_macros::profile")]
- #[doc(hidden)]
- pub const fn new_unchecked(s: &'static str) -> Self {
- Self(std::borrow::Cow::Borrowed(s))
- }
-
- /// Returns whether the provided `&str` is a valid station identifier.
- pub fn is_valid_id(proposed_id: &str) -> bool {
- let mut chars = proposed_id.chars();
- let first_char = chars.next();
- let first_char_valid = first_char
- .map(|c| c.is_ascii_alphabetic() || c == '_')
- .unwrap_or(false);
- let remainder_chars_valid =
- chars.all(|c| c.is_ascii_alphabetic() || c == '_' || c.is_ascii_digit());
-
- first_char_valid && remainder_chars_valid
- }
-
- /// Returns the inner `Cow<'static, str>`.
- pub fn into_inner(self) -> Cow<'static, str> {
- self.0
- }
-
- /// Returns the `&str` held by this ID.
- pub fn as_str(&self) -> &str {
- &self.0
- }
- }
-
- impl std::ops::Deref for $ty_name {
- type Target = std::borrow::Cow<'static, str>;
-
- fn deref(&self) -> &Self::Target {
- &self.0
- }
- }
-
- impl std::fmt::Display for $ty_name {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(f, "{}", self.0)
- }
- }
-
- impl TryFrom for $ty_name {
- type Error = $ty_err_name<'static>;
-
- fn try_from(s: String) -> Result<$ty_name, $ty_err_name<'static>> {
- if Self::is_valid_id(&s) {
- Ok($ty_name(std::borrow::Cow::Owned(s)))
- } else {
- let s = std::borrow::Cow::Owned(s);
- Err($ty_err_name::new(s))
- }
- }
- }
-
- impl TryFrom<&'static str> for $ty_name {
- type Error = $ty_err_name<'static>;
-
- fn try_from(s: &'static str) -> Result<$ty_name, $ty_err_name<'static>> {
- if Self::is_valid_id(s) {
- Ok($ty_name(std::borrow::Cow::Borrowed(s)))
- } else {
- let s = std::borrow::Cow::Borrowed(s);
- Err($ty_err_name::new(s))
- }
- }
- }
-
- impl std::str::FromStr for $ty_name {
- type Err = $ty_err_name<'static>;
-
- fn from_str(s: &str) -> Result<$ty_name, $ty_err_name<'static>> {
- if Self::is_valid_id(s) {
- Ok($ty_name(std::borrow::Cow::Owned(String::from(s))))
- } else {
- let s = std::borrow::Cow::Owned(String::from(s));
- Err($ty_err_name::new(s))
- }
- }
- }
-
- impl std::borrow::Borrow for $ty_name {
- fn borrow(&self) -> &str {
- &self.0
- }
- }
-
- impl<'s> std::borrow::Borrow for &'s $ty_name {
- fn borrow(&self) -> &str {
- &self.0
- }
- }
-
- #[doc = concat!("Error indicating `", stringify!($ty_name), "` provided is not in the correct format.")]
- #[derive(Debug, PartialEq, Eq)]
- pub struct $ty_err_name<'s> {
- /// String that was provided for the `$ty_name`.
- value: std::borrow::Cow<'s, str>,
- }
-
- impl<'s> $ty_err_name<'s> {
- #[doc = concat!("Returns a new `", stringify!($ty_err_name), "` error.")]
- pub fn new(value: std::borrow::Cow<'s, str>) -> Self {
- Self { value }
- }
-
- #[doc = concat!("Returns the value that failed to be parsed as a [`", stringify!($ty_name), "`].")]
- pub fn value(&self) -> &std::borrow::Cow<'s, str> {
- &self.value
- }
- }
-
- impl<'s> std::fmt::Display for $ty_err_name<'s> {
- fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
- write!(
- f,
- "`{value}` is not a valid `{ty_name}`.\n\
- `{ty_name}`s must begin with a letter or underscore, and contain only letters, numbers, or underscores.",
- ty_name = stringify!($ty_name),
- value = self.value
- )
- }
- }
-
- impl<'s> std::error::Error for $ty_err_name<'s> {}
- };
-}
-
-pub(crate) use id_newtype;
diff --git a/crate/model/src/common/image_id.rs b/crate/model/src/common/image_id.rs
index a6f209f..167e55c 100644
--- a/crate/model/src/common/image_id.rs
+++ b/crate/model/src/common/image_id.rs
@@ -23,7 +23,7 @@ use crate::common::AnyId;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct ImageId(Cow<'static, str>);
-crate::common::id_newtype!(ImageId, ImageIdInvalidFmt, image_id);
+id_newtype::id_newtype!(ImageId, ImageIdInvalidFmt, image_id);
impl From for ImageId {
fn from(any_id: AnyId) -> Self {
diff --git a/crate/model/src/common/node_id.rs b/crate/model/src/common/node_id.rs
index 7ef0c57..2e10ed4 100644
--- a/crate/model/src/common/node_id.rs
+++ b/crate/model/src/common/node_id.rs
@@ -23,7 +23,7 @@ use crate::common::AnyId;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct NodeId(Cow<'static, str>);
-crate::common::id_newtype!(NodeId, NodeIdInvalidFmt, node_id);
+id_newtype::id_newtype!(NodeId, NodeIdInvalidFmt, node_id);
impl From for NodeId {
fn from(any_id: AnyId) -> Self {
diff --git a/crate/model/src/common/tag_id.rs b/crate/model/src/common/tag_id.rs
index 55df28e..4929f94 100644
--- a/crate/model/src/common/tag_id.rs
+++ b/crate/model/src/common/tag_id.rs
@@ -23,7 +23,7 @@ use crate::common::AnyId;
#[derive(Clone, Debug, Hash, PartialEq, Eq, Deserialize, Serialize)]
pub struct TagId(Cow<'static, str>);
-crate::common::id_newtype!(TagId, TagIdInvalidFmt, tag_id);
+id_newtype::id_newtype!(TagId, TagIdInvalidFmt, tag_id);
impl From for TagId {
fn from(any_id: AnyId) -> Self {
diff --git a/crate/model/src/lib.rs b/crate/model/src/lib.rs
index 9ac577a..b362f24 100644
--- a/crate/model/src/lib.rs
+++ b/crate/model/src/lib.rs
@@ -129,6 +129,9 @@
//! - tag_2: "Tag 2"
//! ```
+#[macro_use]
+extern crate id_newtype;
+
// Re-exports
pub use dot_ix_static_check_macros::{edge_id, node_id, tag_id};
pub use indexmap::IndexMap;
diff --git a/crate/web_components/Cargo.toml b/crate/web_components/Cargo.toml
index 02d4c79..733714e 100644
--- a/crate/web_components/Cargo.toml
+++ b/crate/web_components/Cargo.toml
@@ -24,14 +24,11 @@ http = { workspace = true }
leptos = { workspace = true }
leptos_axum = { workspace = true, optional = true }
leptos_meta = { workspace = true }
-serde = { workspace = true, optional = true, features = ["derive"] }
tempfile = { workspace = true, optional = true }
-tokio = { workspace = true, optional = true }
thiserror = { workspace = true }
[target.'cfg(target_arch = "wasm32")'.dependencies]
js-sys = { workspace = true }
-serde = { workspace = true, optional = true, features = ["derive"] }
serde-wasm-bindgen = { version = "0.6.5" }
wasm-bindgen = { workspace = true }
web-sys = { workspace = true, features = ["Document", "Element", "HtmlElement", "Url", "UrlSearchParams", "Window"] }
@@ -44,7 +41,3 @@ ssr = [
"leptos/ssr",
"leptos_meta/ssr",
]
-server_side_graphviz = [
- "dep:serde",
- "dep:tokio",
-]
diff --git a/crate/web_components/src/dot_svg.rs b/crate/web_components/src/dot_svg.rs
index fee8b17..3a3e1b1 100644
--- a/crate/web_components/src/dot_svg.rs
+++ b/crate/web_components/src/dot_svg.rs
@@ -1,36 +1,18 @@
+use dot_ix_model::{common::DotSrcAndStyles, info_graph::InfoGraph};
use leptos::{
component,
- prelude::{ClassAttribute, ElementChild, Get, Signal},
+ html::Div,
+ prelude::{
+ ClassAttribute, Effect, ElementChild, Get, GlobalAttributes, GlobalOnAttributes, NodeRef,
+ NodeRefAttribute, Signal,
+ },
view, IntoView,
};
+use leptos_meta::Script;
-#[cfg(not(feature = "server_side_graphviz"))]
-use leptos::prelude::{Effect, NodeRef};
-
-use dot_ix_model::{common::DotSrcAndStyles, info_graph::InfoGraph};
-
-#[cfg(feature = "server_side_graphviz")]
-use leptos::{
- prelude::{InnerHtmlAttribute, Resource, ServerFnError},
- server,
- server_fn::error::NoCustomError,
- suspense::Suspense,
-};
-
-#[cfg(any(
- all(feature = "ssr", feature = "server_side_graphviz"),
- target_arch = "wasm32"
-))]
+#[cfg(target_arch = "wasm32")]
use dot_ix_model::common::{dot_src_and_styles::GraphvizImage, Images};
-#[cfg(not(feature = "server_side_graphviz"))]
-use leptos::prelude::{GlobalAttributes, GlobalOnAttributes, NodeRefAttribute};
-
-#[cfg(not(feature = "server_side_graphviz"))]
-use leptos::html::Div;
-#[cfg(not(feature = "server_side_graphviz"))]
-use leptos_meta::Script;
-
cfg_if::cfg_if! { if #[cfg(target_arch = "wasm32")] {
use wasm_bindgen::{prelude::wasm_bindgen, JsValue};
@@ -41,74 +23,14 @@ cfg_if::cfg_if! { if #[cfg(target_arch = "wasm32")] {
}
}}
-#[cfg(not(feature = "server_side_graphviz"))]
const SVG_WRITE_TO_CLIPBOARD: &str = include_str!("dot_svg/svg_write_to_clipboard.js");
-#[cfg(feature = "server_side_graphviz")]
-#[server]
-pub async fn dot_svg(
- info_graph: InfoGraph,
- dot_src_and_styles: DotSrcAndStyles,
-) -> Result<(String, String), ServerFnError> {
- use std::process::Stdio;
- use tokio::io::{AsyncReadExt, AsyncWriteExt};
-
- let DotSrcAndStyles {
- dot_src,
- styles: _,
- opts: _,
- theme_warnings: _,
- } = dot_src_and_styles;
-
- let mut dot_process = tokio::process::Command::new("dot")
- .arg("-Tsvg")
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- .expect("Failed to spawn dot command");
-
- if let Some(mut stdin) = dot_process.stdin.take() {
- stdin
- .write_all(dot_src.as_bytes())
- .await
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
- }
-
- let mut dot_svg = String::with_capacity(dot_src.len());
- if let Some(mut stdout) = dot_process.stdout.take() {
- stdout
- .read_to_string(&mut dot_svg)
- .await
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
- }
-
- let mut dot_stderr = String::new();
- if let Some(mut stderr) = dot_process.stderr.take() {
- stderr
- .read_to_string(&mut dot_stderr)
- .await
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
- }
-
- dot_process.wait().await.map_err(|error| {
- ServerFnError::::ServerError(format!("{dot_stderr}{error}"))
- })?;
-
- let styles = dot_svg_styles(&dot_src).await?;
-
- let images = info_graph.images();
- let image_defs = svg_image_defs(images);
- dot_svg = dot_svg_sanitize(&dot_svg, &styles, images, &image_defs);
- dot_svg = dot_svg_append_extra(&dot_svg, info_graph.svg_extra());
-
- Ok((dot_svg, dot_stderr))
+#[cfg(target_arch = "wasm32")]
+fn dot_svg_append_extra(dot_svg: &str, svg_extra: &str) -> String {
+ dot_svg.replacen(" String {
images
.iter()
@@ -138,10 +60,7 @@ fn svg_image_defs(images: &Images) -> String {
/// * `dot_svg`: The SVG generated by `dot`.
/// * `styles`: The CSS styles to include within the ``
/// element.
-#[cfg(any(
- all(feature = "ssr", feature = "server_side_graphviz"),
- target_arch = "wasm32"
-))]
+#[cfg(target_arch = "wasm32")]
fn dot_svg_sanitize(dot_svg: &str, styles: &str, images: &Images, images_defs: &str) -> String {
let dot_svg = dot_svg
.replacen("{styles}\n String {
- dot_svg.replacen(" Result> {
- use std::process::Stdio;
- use tokio::io::AsyncReadExt;
-
- let tempdir = tempfile::tempdir()
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
-
- let dot_path = tempdir.path().join("dot.dot");
- let dot_write = tokio::fs::write(&dot_path, dot_src);
-
- let tailwind_config_path = tempdir.path().join("tailwind.config.js");
- let tailwind_config_write = tokio::fs::write(
- &tailwind_config_path,
- b"/** @type {import('tailwindcss').Config} */\nmodule.exports = { content: ['./dot.dot'] }",
- );
-
- let tailwind_css_path = tempdir.path().join("tailwind.css");
- let tailwind_css_write = tokio::fs::write(
- &tailwind_css_path,
- b"\n@tailwind components;\n@tailwind utilities;\n",
- );
-
- let ((), (), ()) = tokio::try_join!(tailwind_config_write, dot_write, tailwind_css_write,)
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
-
- let mut tailwind_process = tokio::process::Command::new("tailwind")
- .current_dir(tempdir.path())
- .arg("-i")
- .arg(&tailwind_css_path)
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
-
- let mut svg_styles = String::with_capacity(dot_src.len());
- if let Some(mut stdout) = tailwind_process.stdout.take() {
- stdout
- .read_to_string(&mut svg_styles)
- .await
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
- }
-
- let mut tailwind_stderr = String::new();
- if let Some(mut stderr) = tailwind_process.stderr.take() {
- stderr
- .read_to_string(&mut tailwind_stderr)
- .await
- .map_err(|error| ServerFnError::::ServerError(format!("{error}")))?;
- }
-
- tailwind_process.wait().await.map_err(|error| {
- ServerFnError::::ServerError(format!("{tailwind_stderr}{error}"))
- })?;
-
- Ok(svg_styles)
-}
-
-/// Renders a graphviz graph as an SVG.
-#[cfg(feature = "server_side_graphviz")]
-#[component]
-pub fn DotSvg(
- info_graph: Signal,
- dot_src_and_styles: Signal>,
- #[prop(default = Signal::from(false))] diagram_only: Signal,
-) -> impl IntoView {
- let _diagram_only = diagram_only;
- let dot_svg_and_error_resource = Resource::new(
- move || dot_src_and_styles.get(),
- move |dot_src_and_styles| async move {
- if let Some(dot_src_and_styles) = dot_src_and_styles {
- if !dot_src_and_styles.dot_src.is_empty() {
- let info_graph = info_graph.get().clone();
- match dot_svg(info_graph, dot_src_and_styles).await {
- Ok((dot_svg, error_text)) => (dot_svg, error_text),
- Err(error) => (String::new(), format!("{error}")),
- }
- } else {
- (String::new(), String::new())
- }
- } else {
- (String::new(), String::new())
- }
- },
- );
-
- view! {
- "Loading..."
}
- >
- { move || {
- dot_svg_and_error_resource.get()
- .map(|(dot_svg, error_text)| {
- let error_text_empty = error_text.is_empty();
- view! {
-
- }
- })
- }}
-
- }
-}
-
/// Renders a graphviz graph as an SVG.
///
/// TODO: Use `postcss` to generate styles on the client side via function.
@@ -338,7 +117,6 @@ pub fn DotSvg(
///
/// const css = generateTailwindCss('HTML content
')
/// ```
-#[cfg(not(feature = "server_side_graphviz"))]
#[component]
pub fn DotSvg(
info_graph: Signal,
diff --git a/deny.toml b/deny.toml
index 8b38dad..f1ded20 100644
--- a/deny.toml
+++ b/deny.toml
@@ -46,7 +46,7 @@ all-features = true
no-default-features = false
# If set, these feature will be enabled when collecting metadata. If `--features`
# is specified on the cmd line they will take precedence over this option.
-features = ["server_side_graphviz"]
+features = []
[output]
# When outputting inclusion graphs in diagnostics that include features, this
@@ -70,11 +70,11 @@ yanked = "warn"
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
- # `derivative` is unmaintained.
+ # `paste` is unmaintained.
#
- # Transitive dependency of `log4rs`.
- # Pending .
- "RUSTSEC-2024-0388",
+ # Transitive dependency of `leptos` -> `either_of` -> `paste`.
+ # .
+ "RUSTSEC-2024-0436",
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
@@ -96,7 +96,7 @@ version = 2
allow = [
"Apache-2.0",
"BSD-2-Clause",
- "BSD-3-Clause", # wasm
+ "BSD-3-Clause", # wasm
"BSL-1.0",
"MIT",
"Unicode-DFS-2016",
@@ -137,8 +137,8 @@ exceptions = [
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
- # Each entry is a crate relative path, and the (opaque) hash of its contents
- #{ path = "LICENSE", hash = 0xbd0eed23 }
+# Each entry is a crate relative path, and the (opaque) hash of its contents
+#{ path = "LICENSE", hash = 0xbd0eed23 }
#]
[licenses.private]
diff --git a/playground/Cargo.toml b/playground/Cargo.toml
index 45ae046..45597de 100644
--- a/playground/Cargo.toml
+++ b/playground/Cargo.toml
@@ -20,7 +20,7 @@ axum = { workspace = true, optional = true }
console_error_panic_hook = { workspace = true }
console_log = { workspace = true }
cfg-if = { workspace = true }
-dot_ix = { version = "0.9.2", path = ".." }
+dot_ix = { version = "0.10.0", path = ".." }
gloo-net = { workspace = true, features = ["http"] }
leptos = { workspace = true }
leptos_axum = { workspace = true, optional = true }
@@ -69,7 +69,6 @@ ssr = [
csr = [
"leptos/csr",
]
-server_side_graphviz = ["dot_ix/server_side_graphviz"]
[package.metadata.cargo-all-features]
denylist = ["axum", "tokio", "tower", "tower-http", "leptos_axum"]
@@ -89,7 +88,7 @@ site-pkg-dir = "pkg"
# [Optional] The source CSS file. If it ends with .sass or .scss then it will be compiled by dart-sass into CSS. The CSS is optimized by Lightning CSS before being written to //app.css
# style-file = "style/main.scss"
tailwind-input-file = "style/tailwind.css"
-tailwind-config-file = "style/tailwind.config.js"
+# tailwind-config-file = "style/tailwind.config.js"
# Assets source dir. All files found here will be copied and synchronized to site-root.
# The assets-dir cannot have a sub directory with the same name/path as site-pkg-dir.
#
diff --git a/playground/Trunk.toml b/playground/Trunk.toml
deleted file mode 100644
index c790f43..0000000
--- a/playground/Trunk.toml
+++ /dev/null
@@ -1,6 +0,0 @@
-[[hooks]]
-stage = "pre_build"
-command = "cargo"
-command_arguments = ["leptos", "build", "-v"]
-# command = "sh"
-# command_arguments = ["-c", "npx tailwindcss -c style/tailwind.config.js -i style/tailwind.css -o target/site/pkg/dot_ix.css"]
diff --git a/playground/index.html b/playground/index.html
index 9b2f066..7b0f67a 100644
--- a/playground/index.html
+++ b/playground/index.html
@@ -13,11 +13,10 @@
Would be good if we can just specify `target/site`,
and `trunk` copies the contents of the `site` directory.
-->
-
-
-
-
-
+
+
+
+