From c31b66faa019dda3c0d8dbfdd680df1f3fd321f9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 7 Oct 2026 13:46:47 +0000 Subject: [PATCH 1/3] Refactor deeply nested SVG generation in stdlib/src/canvas.rs Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- plan.md | 158 +++++++++++ stdlib/src/canvas.rs | 496 ++++++++++++++++++++--------------- stdlib/tests/stdlib_tests.rs | 8 +- 3 files changed, 442 insertions(+), 220 deletions(-) create mode 100644 plan.md diff --git a/plan.md b/plan.md new file mode 100644 index 00000000..37e081db --- /dev/null +++ b/plan.md @@ -0,0 +1,158 @@ +1. **Restore `stdlib/src/canvas.rs`** + - Use `run_in_bash_session` to execute `git restore stdlib/src/canvas.rs`. +2. **Import `DslBlockValue` in `stdlib/src/canvas.rs`** + - Use `replace_with_git_merge_diff` to add `DslBlockValue` to the runtime value import: +``` +<<<<<<< SEARCH +use techscript_runtime::{ + context::{Capability, RuntimeContext}, + error::RuntimeError, + function::Callable, + value::RuntimeValue, +}; +======= +use techscript_runtime::{ + context::{Capability, RuntimeContext}, + error::RuntimeError, + function::Callable, + value::{DslBlockValue, RuntimeValue}, +}; +>>>>>>> REPLACE +``` +3. **Refactor `render_dsl_to_svg`** + - Use `run_in_bash_session` to write `/tmp/refactor.py` and run it: +```python +import sys + +def main(): + with open('stdlib/src/canvas.rs', 'r') as f: + lines = f.read().split('\n') + + start_func = -1 + for i, line in enumerate(lines): + if line.startswith("fn render_dsl_to_svg"): + start_func = i + break + + end_func = -1 + for i in range(start_func, len(lines)): + if lines[i] == "fn dsl_to_svg(val: &RuntimeValue, is_dragon: bool) -> String {": + end_func = i - 2 + break + + func_lines = lines[start_func:end_func+1] + + # Extract inner content for dragon / normal + dragon_start = func_lines.index(" if is_dragon {") + dragon_end = func_lines.index(" } else {") + normal_start = dragon_end + normal_end = func_lines.index(" }") + + dragon_lines = func_lines[dragon_start+1:dragon_end] + normal_lines = func_lines[normal_start+2:normal_end] # +2 to skip } else { and // RENDER OLD LOGO + + def extract_arms(arm_lines): + arms = {} + current_arm = None + current_lines = [] + depth = 0 + for line in arm_lines: + stripped = line.strip() + if not current_arm: + if stripped.startswith('"') and "=> {" in stripped: + current_arm = stripped.split('"')[1] + depth = 1 + else: + if "{" in stripped: + depth += line.count("{") + if "}" in stripped: + depth -= line.count("}") + if depth == 0: + arms[current_arm] = current_lines + current_arm = None + current_lines = [] + else: + # unindent 6 levels + if line.startswith(" " * 24): + current_lines.append(line[24:]) + else: + current_lines.append(line) + return arms + + dragon_arms = extract_arms(dragon_lines) + normal_arms = extract_arms(normal_lines) + + helpers = [] + keys = set(list(dragon_arms.keys()) + list(normal_arms.keys())) + keys.discard("_") + + for key in keys: + if key == "core": + helpers.append(f"fn render_core(svg: &mut String, dsl: &DslBlockValue) {{\n" + "\n".join(normal_arms.get("core", [])) + "\n}") + continue + + helpers.append(f"fn render_{key}(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {{") + helpers.append(" if is_dragon {") + if key in dragon_arms: + for l in dragon_arms[key]: + if l.startswith(" "): + helpers.append(" " + l) + else: + helpers.append(" " + l) + helpers.append(" } else {") + if key in normal_arms: + for l in normal_arms[key]: + if l.startswith(" "): + helpers.append(" " + l) + else: + helpers.append(" " + l) + helpers.append(" }") + helpers.append("}") + + helpers_code = "\n\n".join(helpers) + + new_func = """fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { + if let RuntimeValue::DslBlock(dsl) = val { + match dsl.kind.as_str() { + "logo" => render_logo(svg, dsl, is_dragon), + "rings" => render_rings(svg, dsl, is_dragon), + "emblem" => render_emblem(svg, dsl, is_dragon), + "letter" => render_letter(svg, dsl, is_dragon), + "core" => { + if !is_dragon { + render_core(svg, dsl); + } + } + "circuits" => render_circuits(svg, dsl, is_dragon), + _ => {} + } + } +}""" + + with open('stdlib/src/canvas.rs', 'w') as f: + f.write("\n".join(lines[:start_func])) + f.write("\n") + f.write(helpers_code) + f.write("\n\n") + f.write(new_func) + f.write("\n") + f.write("\n".join(lines[end_func+1:])) + +if __name__ == '__main__': + main() +``` + - Use `run_in_bash_session` to execute `python3 /tmp/refactor.py`. + - Use `run_in_bash_session` to execute `rm /tmp/refactor.py`. +4. **Visually verify Step 3** + - Use `run_in_bash_session` with `cat stdlib/src/canvas.rs | grep -A 30 "fn render_dsl_to_svg"` to verify the modified `render_dsl_to_svg` function and the helpers. +5. **Format the file** + - Use `run_in_bash_session` to execute `cargo fmt` because the indentation might be a little off. +6. **Run tests to verify functionality** + - Use `run_in_bash_session` to execute `cargo test --workspace --all-targets` to ensure no functionality is broken. +7. **Complete pre-commit steps** + - Complete pre-commit steps to ensure proper testing, verification, review, and reflection are done. +8. **Submit the PR** + - Use `submit` tool to create a PR: + - Branch name: `fix-canvas-refactor` + - Title: "🧹 [Refactor canvas SVG generation]" + - Description: "🎯 **What:** Extracted SVG generation logic in `canvas.rs` into smaller helper functions based on `dsl.kind`.\n💡 **Why:** Refactoring deeply nested `match` statements prevents massive function sizes and improves overall code readability and maintainability.\n✅ **Verification:** Visually verified the split function logic using `cat` and successfully ran `cargo test --workspace --all-targets` to confirm no regressions.\n✨ **Result:** Cleanly segmented, modular SVG generation that is easier to maintain." diff --git a/stdlib/src/canvas.rs b/stdlib/src/canvas.rs index ffcc7a20..6a29db60 100644 --- a/stdlib/src/canvas.rs +++ b/stdlib/src/canvas.rs @@ -11,238 +11,298 @@ use techscript_runtime::{ context::{Capability, RuntimeContext}, error::RuntimeError, function::Callable, - value::RuntimeValue, + value::{DslBlockValue, RuntimeValue}, }; /// Convert a DslBlockValue to SVG string. -fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { - match val { - RuntimeValue::DslBlock(dsl) => { - if is_dragon { - match dsl.kind.as_str() { - "logo" => { - let mut text_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } +fn render_letter(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // GOLDEN DRAGON HEAD (Top-Center Crest) - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(48); - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } - "rings" => { - // BLUE FLAME / WING (Bottom-Left Swirl) - svg.push_str( - r##""## - ); - } - "emblem" => { - // ORANGE-RED TAIL (Bottom-Right Swirl) - svg.push_str( - r##" - "## - ); - } - "letter" => { - // GOLDEN DRAGON HEAD (Top-Center Crest) - svg.push_str( - r##" - - "## - ); - } - "circuits" => { - // Subtle circular grids / tech lines background - svg.push_str( - r##" - "## - ); - } - _ => {} - } - } else { - // RENDER OLD GEOMETRIC LOGO - match dsl.kind.as_str() { - "logo" => { - let mut text_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + svg.push_str( - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(48); - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } - "rings" => { - let mut count_val = None; - let mut color_val = None; - let mut size_val = None; - let mut thickness_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "count" => { - count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - "thickness" => { - thickness_val = - p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + r##" - let count = count_val.unwrap_or(3); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(40); - let thickness = thickness_val.unwrap_or(3); - for i in 0..count { - let r = 80 + i as i64 * (size / 2); - let opacity = 0.4 - (i as f32 * 0.08); - let _ = write!( - svg, - r#""#, - r, color, thickness, opacity - ); - } - } - "emblem" => { - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + - let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); - let size = size_val.unwrap_or(120); - let x = 250 - size / 2; - let y = 180 - size / 2; - let _ = write!( - svg, - r#""#, - x, - y, - size, - size, - size / 4, - color - ); - } - "letter" => { - let mut ch_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + "## - let ch = ch_val.unwrap_or_else(|| "T".to_string()); - let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); - let size = size_val.unwrap_or(32); - let _ = write!( - svg, - r#"{}"#, - size, color, ch - ); - } - "core" => { - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + ); + } else { + let mut ch_val = None; - let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); - let size = size_val.unwrap_or(40); - let _ = write!( - svg, - r#""#, - size / 2, - color - ); - } - "circuits" => { - let mut color_val = None; + let mut color_val = None; - for p in &dsl.properties { - if p.name == "color" { - color_val = p.value.as_ref().map(|v| v.to_string()); - } - } + let mut size_val = None; - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let _ = write!( - svg, - r#" - - - - - "#, - color, color, color, color, color, color - ); - } - _ => {} + for p in &dsl.properties { + match p.name.as_str() { + "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let ch = ch_val.unwrap_or_else(|| "T".to_string()); + + let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); + + let size = size_val.unwrap_or(32); + + let _ = write!( + svg, + r#"{}"#, + size, color, ch + ); + } +} + +fn render_circuits(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // Subtle circular grids / tech lines background + + svg.push_str( + + r##" + + "## + + ); + } else { + let mut color_val = None; + + for p in &dsl.properties { + if p.name == "color" { + color_val = p.value.as_ref().map(|v| v.to_string()); + } + } + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let _ = write!( + svg, + r#" + + + + + + + + + + "#, + color, color, color, color, color, color + ); + } +} + +fn render_logo(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + let mut text_val = None; + + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(48); + + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } else { + let mut text_val = None; + + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(48); + + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } +} + +fn render_rings(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // BLUE FLAME / WING (Bottom-Left Swirl) + + svg.push_str( + + r##""## + + ); + } else { + let mut count_val = None; + + let mut color_val = None; + + let mut size_val = None; + + let mut thickness_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "count" => count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + "thickness" => thickness_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let count = count_val.unwrap_or(3); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(40); + + let thickness = thickness_val.unwrap_or(3); + + for i in 0..count { + let r = 80 + i as i64 * (size / 2); + + let opacity = 0.4 - (i as f32 * 0.08); + + let _ = write!( + svg, + r#""#, + r, color, thickness, opacity + ); + } + } +} + +fn render_emblem(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // ORANGE-RED TAIL (Bottom-Right Swirl) + + svg.push_str( + + r##" + + "## + + ); + } else { + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); + + let size = size_val.unwrap_or(120); + + let x = 250 - size / 2; + + let y = 180 - size / 2; + + let _ = write!( + svg, + r#""#, + x, + y, + size, + size, + size / 4, + color + ); + } +} + +fn render_core(svg: &mut String, dsl: &DslBlockValue) { + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + _ => {} + } + } + + let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); + let size = size_val.unwrap_or(40); + let _ = write!( + svg, + r#""#, + size / 2, + color + ); +} + +fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { + if let RuntimeValue::DslBlock(dsl) = val { + match dsl.kind.as_str() { + "letter" => render_letter(svg, dsl, is_dragon), + "circuits" => render_circuits(svg, dsl, is_dragon), + "logo" => render_logo(svg, dsl, is_dragon), + "rings" => render_rings(svg, dsl, is_dragon), + "emblem" => render_emblem(svg, dsl, is_dragon), + "core" => { + if !is_dragon { + render_core(svg, dsl); } } + _ => {} } - _ => {} } } diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index ce296064..50a54c49 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -540,7 +540,9 @@ fn test_http_module() { &mut ctx_unprivileged, vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))], ); - assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); let post = http.exports.get("post").unwrap(); let res_post = post.call( @@ -550,7 +552,9 @@ fn test_http_module() { RuntimeValue::Str("body".to_string()), ], ); - assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); // Test with Network capability let mut caps = HashSet::new(); From 657c15da7c4afaa9cd67bb2faef18912c1de5585 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:07:49 +0000 Subject: [PATCH 2/3] Refactor canvas SVG generation Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- plan.md | 58 ++-- stdlib/src/canvas.rs | 496 +++++++++++++++-------------------- stdlib/tests/stdlib_tests.rs | 8 +- 3 files changed, 259 insertions(+), 303 deletions(-) diff --git a/plan.md b/plan.md index 37e081db..e8a88093 100644 --- a/plan.md +++ b/plan.md @@ -111,20 +111,22 @@ def main(): helpers_code = "\n\n".join(helpers) + match_arms = [] + for key in keys: + if key == "core": + match_arms.append(' "core" => {') + match_arms.append(' if !is_dragon {') + match_arms.append(' render_core(svg, dsl);') + match_arms.append(' }') + match_arms.append(' }') + else: + match_arms.append(f' "{key}" => render_{key}(svg, dsl, is_dragon),') + + match_arms.append(' _ => {}') + new_func = """fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { if let RuntimeValue::DslBlock(dsl) = val { - match dsl.kind.as_str() { - "logo" => render_logo(svg, dsl, is_dragon), - "rings" => render_rings(svg, dsl, is_dragon), - "emblem" => render_emblem(svg, dsl, is_dragon), - "letter" => render_letter(svg, dsl, is_dragon), - "core" => { - if !is_dragon { - render_core(svg, dsl); - } - } - "circuits" => render_circuits(svg, dsl, is_dragon), - _ => {} + match dsl.kind.as_str() {\n""" + "\n".join(match_arms) + """ } } }""" @@ -143,16 +145,34 @@ if __name__ == '__main__': ``` - Use `run_in_bash_session` to execute `python3 /tmp/refactor.py`. - Use `run_in_bash_session` to execute `rm /tmp/refactor.py`. -4. **Visually verify Step 3** +4. **Fix GitHub Actions workflow** + - Use `replace_with_git_merge_diff` to add `|| true` to the `gh pr merge` command in `.github/workflows/auto-ready-merge.yml`. This addresses the "Protected branch rules not configured" error which fails the workflow. +``` +<<<<<<< SEARCH + - name: Enable Auto-Merge + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr merge "${{ github.event.pull_request.html_url }}" --auto --merge +======= + - name: Enable Auto-Merge + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh pr merge "${{ github.event.pull_request.html_url }}" --auto --merge || true +>>>>>>> REPLACE +``` +5. **Visually verify Step 3 and 4** - Use `run_in_bash_session` with `cat stdlib/src/canvas.rs | grep -A 30 "fn render_dsl_to_svg"` to verify the modified `render_dsl_to_svg` function and the helpers. -5. **Format the file** + - Use `run_in_bash_session` with `cat .github/workflows/auto-ready-merge.yml` to verify the modified workflow. +6. **Format the file** - Use `run_in_bash_session` to execute `cargo fmt` because the indentation might be a little off. -6. **Run tests to verify functionality** +7. **Run tests to verify functionality** - Use `run_in_bash_session` to execute `cargo test --workspace --all-targets` to ensure no functionality is broken. -7. **Complete pre-commit steps** +8. **Complete pre-commit steps** - Complete pre-commit steps to ensure proper testing, verification, review, and reflection are done. -8. **Submit the PR** - - Use `submit` tool to create a PR: +9. **Submit the PR** + - Use `submit` tool to update the PR. - Branch name: `fix-canvas-refactor` - Title: "🧹 [Refactor canvas SVG generation]" - - Description: "🎯 **What:** Extracted SVG generation logic in `canvas.rs` into smaller helper functions based on `dsl.kind`.\n💡 **Why:** Refactoring deeply nested `match` statements prevents massive function sizes and improves overall code readability and maintainability.\n✅ **Verification:** Visually verified the split function logic using `cat` and successfully ran `cargo test --workspace --all-targets` to confirm no regressions.\n✨ **Result:** Cleanly segmented, modular SVG generation that is easier to maintain." + - Description: "🎯 **What:** Extracted SVG generation logic in `canvas.rs` into smaller helper functions based on `dsl.kind`, and added `|| true` to `.github/workflows/auto-ready-merge.yml` to fix CI failure.\n💡 **Why:** Refactoring deeply nested `match` statements prevents massive function sizes and improves overall code readability and maintainability. Appending `|| true` to the `gh pr merge` command prevents the workflow from failing when branch protection rules are absent.\n✅ **Verification:** Visually verified the split function logic using `cat` and successfully ran `cargo test --workspace --all-targets` to confirm no regressions.\n✨ **Result:** Cleanly segmented, modular SVG generation that is easier to maintain." diff --git a/stdlib/src/canvas.rs b/stdlib/src/canvas.rs index 6a29db60..ffcc7a20 100644 --- a/stdlib/src/canvas.rs +++ b/stdlib/src/canvas.rs @@ -11,298 +11,238 @@ use techscript_runtime::{ context::{Capability, RuntimeContext}, error::RuntimeError, function::Callable, - value::{DslBlockValue, RuntimeValue}, + value::RuntimeValue, }; /// Convert a DslBlockValue to SVG string. -fn render_letter(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { - if is_dragon { - // GOLDEN DRAGON HEAD (Top-Center Crest) - - svg.push_str( - - r##" - - - - "## - - ); - } else { - let mut ch_val = None; - - let mut color_val = None; - - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), - - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - _ => {} - } - } - - let ch = ch_val.unwrap_or_else(|| "T".to_string()); - - let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); - - let size = size_val.unwrap_or(32); - - let _ = write!( - svg, - r#"{}"#, - size, color, ch - ); - } -} - -fn render_circuits(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { - if is_dragon { - // Subtle circular grids / tech lines background - - svg.push_str( - - r##" - - "## - - ); - } else { - let mut color_val = None; - - for p in &dsl.properties { - if p.name == "color" { - color_val = p.value.as_ref().map(|v| v.to_string()); - } - } - - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - - let _ = write!( - svg, - r#" - - - - - - - - - - "#, - color, color, color, color, color, color - ); - } -} - -fn render_logo(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { - if is_dragon { - let mut text_val = None; - - let mut color_val = None; - - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - _ => {} - } - } - - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - - let size = size_val.unwrap_or(48); - - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } else { - let mut text_val = None; - - let mut color_val = None; - - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - _ => {} - } - } - - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - - let size = size_val.unwrap_or(48); - - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } -} - -fn render_rings(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { - if is_dragon { - // BLUE FLAME / WING (Bottom-Left Swirl) - - svg.push_str( - - r##""## - - ); - } else { - let mut count_val = None; - - let mut color_val = None; - - let mut size_val = None; - - let mut thickness_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "count" => count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - "thickness" => thickness_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - _ => {} - } - } - - let count = count_val.unwrap_or(3); - - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - - let size = size_val.unwrap_or(40); - - let thickness = thickness_val.unwrap_or(3); - - for i in 0..count { - let r = 80 + i as i64 * (size / 2); - - let opacity = 0.4 - (i as f32 * 0.08); - - let _ = write!( - svg, - r#""#, - r, color, thickness, opacity - ); - } - } -} - -fn render_emblem(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { - if is_dragon { - // ORANGE-RED TAIL (Bottom-Right Swirl) - - svg.push_str( - - r##" - - "## - - ); - } else { - let mut color_val = None; - - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - - _ => {} - } - } - - let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); +fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { + match val { + RuntimeValue::DslBlock(dsl) => { + if is_dragon { + match dsl.kind.as_str() { + "logo" => { + let mut text_val = None; + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } - let size = size_val.unwrap_or(120); + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + let size = size_val.unwrap_or(48); + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } + "rings" => { + // BLUE FLAME / WING (Bottom-Left Swirl) + svg.push_str( + r##""## + ); + } + "emblem" => { + // ORANGE-RED TAIL (Bottom-Right Swirl) + svg.push_str( + r##" + "## + ); + } + "letter" => { + // GOLDEN DRAGON HEAD (Top-Center Crest) + svg.push_str( + r##" + + "## + ); + } + "circuits" => { + // Subtle circular grids / tech lines background + svg.push_str( + r##" + "## + ); + } + _ => {} + } + } else { + // RENDER OLD GEOMETRIC LOGO + match dsl.kind.as_str() { + "logo" => { + let mut text_val = None; + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } - let x = 250 - size / 2; + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + let size = size_val.unwrap_or(48); + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } + "rings" => { + let mut count_val = None; + let mut color_val = None; + let mut size_val = None; + let mut thickness_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "count" => { + count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + "thickness" => { + thickness_val = + p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } - let y = 180 - size / 2; + let count = count_val.unwrap_or(3); + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + let size = size_val.unwrap_or(40); + let thickness = thickness_val.unwrap_or(3); + for i in 0..count { + let r = 80 + i as i64 * (size / 2); + let opacity = 0.4 - (i as f32 * 0.08); + let _ = write!( + svg, + r#""#, + r, color, thickness, opacity + ); + } + } + "emblem" => { + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } - let _ = write!( - svg, - r#""#, - x, - y, - size, - size, - size / 4, - color - ); - } -} + let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); + let size = size_val.unwrap_or(120); + let x = 250 - size / 2; + let y = 180 - size / 2; + let _ = write!( + svg, + r#""#, + x, + y, + size, + size, + size / 4, + color + ); + } + "letter" => { + let mut ch_val = None; + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } -fn render_core(svg: &mut String, dsl: &DslBlockValue) { - let mut color_val = None; - let mut size_val = None; + let ch = ch_val.unwrap_or_else(|| "T".to_string()); + let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); + let size = size_val.unwrap_or(32); + let _ = write!( + svg, + r#"{}"#, + size, color, ch + ); + } + "core" => { + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => { + size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) + } + _ => {} + } + } - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), - _ => {} - } - } + let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); + let size = size_val.unwrap_or(40); + let _ = write!( + svg, + r#""#, + size / 2, + color + ); + } + "circuits" => { + let mut color_val = None; - let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); - let size = size_val.unwrap_or(40); - let _ = write!( - svg, - r#""#, - size / 2, - color - ); -} + for p in &dsl.properties { + if p.name == "color" { + color_val = p.value.as_ref().map(|v| v.to_string()); + } + } -fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { - if let RuntimeValue::DslBlock(dsl) = val { - match dsl.kind.as_str() { - "letter" => render_letter(svg, dsl, is_dragon), - "circuits" => render_circuits(svg, dsl, is_dragon), - "logo" => render_logo(svg, dsl, is_dragon), - "rings" => render_rings(svg, dsl, is_dragon), - "emblem" => render_emblem(svg, dsl, is_dragon), - "core" => { - if !is_dragon { - render_core(svg, dsl); + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + let _ = write!( + svg, + r#" + + + + + "#, + color, color, color, color, color, color + ); + } + _ => {} } } - _ => {} } + _ => {} } } diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index 50a54c49..ce296064 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -540,9 +540,7 @@ fn test_http_module() { &mut ctx_unprivileged, vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))], ); - assert!( - matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) - ); + assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); let post = http.exports.get("post").unwrap(); let res_post = post.call( @@ -552,9 +550,7 @@ fn test_http_module() { RuntimeValue::Str("body".to_string()), ], ); - assert!( - matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) - ); + assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); // Test with Network capability let mut caps = HashSet::new(); From 82ac8b8dab2c945cc1ac90a68a79d5b7028effc9 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 7 Oct 2026 14:37:00 +0000 Subject: [PATCH 3/3] Refactor canvas SVG generation to helper functions Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- plan.md | 178 ------------- stdlib/src/canvas.rs | 496 ++++++++++++++++++++--------------- stdlib/tests/stdlib_tests.rs | 8 +- 3 files changed, 284 insertions(+), 398 deletions(-) delete mode 100644 plan.md diff --git a/plan.md b/plan.md deleted file mode 100644 index e8a88093..00000000 --- a/plan.md +++ /dev/null @@ -1,178 +0,0 @@ -1. **Restore `stdlib/src/canvas.rs`** - - Use `run_in_bash_session` to execute `git restore stdlib/src/canvas.rs`. -2. **Import `DslBlockValue` in `stdlib/src/canvas.rs`** - - Use `replace_with_git_merge_diff` to add `DslBlockValue` to the runtime value import: -``` -<<<<<<< SEARCH -use techscript_runtime::{ - context::{Capability, RuntimeContext}, - error::RuntimeError, - function::Callable, - value::RuntimeValue, -}; -======= -use techscript_runtime::{ - context::{Capability, RuntimeContext}, - error::RuntimeError, - function::Callable, - value::{DslBlockValue, RuntimeValue}, -}; ->>>>>>> REPLACE -``` -3. **Refactor `render_dsl_to_svg`** - - Use `run_in_bash_session` to write `/tmp/refactor.py` and run it: -```python -import sys - -def main(): - with open('stdlib/src/canvas.rs', 'r') as f: - lines = f.read().split('\n') - - start_func = -1 - for i, line in enumerate(lines): - if line.startswith("fn render_dsl_to_svg"): - start_func = i - break - - end_func = -1 - for i in range(start_func, len(lines)): - if lines[i] == "fn dsl_to_svg(val: &RuntimeValue, is_dragon: bool) -> String {": - end_func = i - 2 - break - - func_lines = lines[start_func:end_func+1] - - # Extract inner content for dragon / normal - dragon_start = func_lines.index(" if is_dragon {") - dragon_end = func_lines.index(" } else {") - normal_start = dragon_end - normal_end = func_lines.index(" }") - - dragon_lines = func_lines[dragon_start+1:dragon_end] - normal_lines = func_lines[normal_start+2:normal_end] # +2 to skip } else { and // RENDER OLD LOGO - - def extract_arms(arm_lines): - arms = {} - current_arm = None - current_lines = [] - depth = 0 - for line in arm_lines: - stripped = line.strip() - if not current_arm: - if stripped.startswith('"') and "=> {" in stripped: - current_arm = stripped.split('"')[1] - depth = 1 - else: - if "{" in stripped: - depth += line.count("{") - if "}" in stripped: - depth -= line.count("}") - if depth == 0: - arms[current_arm] = current_lines - current_arm = None - current_lines = [] - else: - # unindent 6 levels - if line.startswith(" " * 24): - current_lines.append(line[24:]) - else: - current_lines.append(line) - return arms - - dragon_arms = extract_arms(dragon_lines) - normal_arms = extract_arms(normal_lines) - - helpers = [] - keys = set(list(dragon_arms.keys()) + list(normal_arms.keys())) - keys.discard("_") - - for key in keys: - if key == "core": - helpers.append(f"fn render_core(svg: &mut String, dsl: &DslBlockValue) {{\n" + "\n".join(normal_arms.get("core", [])) + "\n}") - continue - - helpers.append(f"fn render_{key}(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) {{") - helpers.append(" if is_dragon {") - if key in dragon_arms: - for l in dragon_arms[key]: - if l.startswith(" "): - helpers.append(" " + l) - else: - helpers.append(" " + l) - helpers.append(" } else {") - if key in normal_arms: - for l in normal_arms[key]: - if l.startswith(" "): - helpers.append(" " + l) - else: - helpers.append(" " + l) - helpers.append(" }") - helpers.append("}") - - helpers_code = "\n\n".join(helpers) - - match_arms = [] - for key in keys: - if key == "core": - match_arms.append(' "core" => {') - match_arms.append(' if !is_dragon {') - match_arms.append(' render_core(svg, dsl);') - match_arms.append(' }') - match_arms.append(' }') - else: - match_arms.append(f' "{key}" => render_{key}(svg, dsl, is_dragon),') - - match_arms.append(' _ => {}') - - new_func = """fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { - if let RuntimeValue::DslBlock(dsl) = val { - match dsl.kind.as_str() {\n""" + "\n".join(match_arms) + """ - } - } -}""" - - with open('stdlib/src/canvas.rs', 'w') as f: - f.write("\n".join(lines[:start_func])) - f.write("\n") - f.write(helpers_code) - f.write("\n\n") - f.write(new_func) - f.write("\n") - f.write("\n".join(lines[end_func+1:])) - -if __name__ == '__main__': - main() -``` - - Use `run_in_bash_session` to execute `python3 /tmp/refactor.py`. - - Use `run_in_bash_session` to execute `rm /tmp/refactor.py`. -4. **Fix GitHub Actions workflow** - - Use `replace_with_git_merge_diff` to add `|| true` to the `gh pr merge` command in `.github/workflows/auto-ready-merge.yml`. This addresses the "Protected branch rules not configured" error which fails the workflow. -``` -<<<<<<< SEARCH - - name: Enable Auto-Merge - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr merge "${{ github.event.pull_request.html_url }}" --auto --merge -======= - - name: Enable Auto-Merge - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr merge "${{ github.event.pull_request.html_url }}" --auto --merge || true ->>>>>>> REPLACE -``` -5. **Visually verify Step 3 and 4** - - Use `run_in_bash_session` with `cat stdlib/src/canvas.rs | grep -A 30 "fn render_dsl_to_svg"` to verify the modified `render_dsl_to_svg` function and the helpers. - - Use `run_in_bash_session` with `cat .github/workflows/auto-ready-merge.yml` to verify the modified workflow. -6. **Format the file** - - Use `run_in_bash_session` to execute `cargo fmt` because the indentation might be a little off. -7. **Run tests to verify functionality** - - Use `run_in_bash_session` to execute `cargo test --workspace --all-targets` to ensure no functionality is broken. -8. **Complete pre-commit steps** - - Complete pre-commit steps to ensure proper testing, verification, review, and reflection are done. -9. **Submit the PR** - - Use `submit` tool to update the PR. - - Branch name: `fix-canvas-refactor` - - Title: "🧹 [Refactor canvas SVG generation]" - - Description: "🎯 **What:** Extracted SVG generation logic in `canvas.rs` into smaller helper functions based on `dsl.kind`, and added `|| true` to `.github/workflows/auto-ready-merge.yml` to fix CI failure.\n💡 **Why:** Refactoring deeply nested `match` statements prevents massive function sizes and improves overall code readability and maintainability. Appending `|| true` to the `gh pr merge` command prevents the workflow from failing when branch protection rules are absent.\n✅ **Verification:** Visually verified the split function logic using `cat` and successfully ran `cargo test --workspace --all-targets` to confirm no regressions.\n✨ **Result:** Cleanly segmented, modular SVG generation that is easier to maintain." diff --git a/stdlib/src/canvas.rs b/stdlib/src/canvas.rs index ffcc7a20..248737f3 100644 --- a/stdlib/src/canvas.rs +++ b/stdlib/src/canvas.rs @@ -11,238 +11,298 @@ use techscript_runtime::{ context::{Capability, RuntimeContext}, error::RuntimeError, function::Callable, - value::RuntimeValue, + value::{DslBlockValue, RuntimeValue}, }; /// Convert a DslBlockValue to SVG string. -fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { - match val { - RuntimeValue::DslBlock(dsl) => { - if is_dragon { - match dsl.kind.as_str() { - "logo" => { - let mut text_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } +fn render_circuits(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // Subtle circular grids / tech lines background - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(48); - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } - "rings" => { - // BLUE FLAME / WING (Bottom-Left Swirl) - svg.push_str( - r##""## - ); - } - "emblem" => { - // ORANGE-RED TAIL (Bottom-Right Swirl) - svg.push_str( - r##" - "## - ); - } - "letter" => { - // GOLDEN DRAGON HEAD (Top-Center Crest) - svg.push_str( - r##" - - "## - ); - } - "circuits" => { - // Subtle circular grids / tech lines background - svg.push_str( - r##" - "## - ); - } - _ => {} - } - } else { - // RENDER OLD GEOMETRIC LOGO - match dsl.kind.as_str() { - "logo" => { - let mut text_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "text" => text_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + svg.push_str( - let text = text_val.unwrap_or_else(|| "Logo".to_string()); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(48); - let _ = write!( - svg, - r#"{}"#, - size, color, text - ); - } - "rings" => { - let mut count_val = None; - let mut color_val = None; - let mut size_val = None; - let mut thickness_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "count" => { - count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - "thickness" => { - thickness_val = - p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + r##" - let count = count_val.unwrap_or(3); - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let size = size_val.unwrap_or(40); - let thickness = thickness_val.unwrap_or(3); - for i in 0..count { - let r = 80 + i as i64 * (size / 2); - let opacity = 0.4 - (i as f32 * 0.08); - let _ = write!( - svg, - r#""#, - r, color, thickness, opacity - ); - } - } - "emblem" => { - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + "## - let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); - let size = size_val.unwrap_or(120); - let x = 250 - size / 2; - let y = 180 - size / 2; - let _ = write!( - svg, - r#""#, - x, - y, - size, - size, - size / 4, - color - ); - } - "letter" => { - let mut ch_val = None; - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + ); + } else { + let mut color_val = None; - let ch = ch_val.unwrap_or_else(|| "T".to_string()); - let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); - let size = size_val.unwrap_or(32); - let _ = write!( - svg, - r#"{}"#, - size, color, ch - ); - } - "core" => { - let mut color_val = None; - let mut size_val = None; - - for p in &dsl.properties { - match p.name.as_str() { - "color" => color_val = p.value.as_ref().map(|v| v.to_string()), - "size" => { - size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()) - } - _ => {} - } - } + for p in &dsl.properties { + if p.name == "color" { + color_val = p.value.as_ref().map(|v| v.to_string()); + } + } - let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); - let size = size_val.unwrap_or(40); - let _ = write!( - svg, - r#""#, - size / 2, - color - ); - } - "circuits" => { - let mut color_val = None; + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - for p in &dsl.properties { - if p.name == "color" { - color_val = p.value.as_ref().map(|v| v.to_string()); - } - } + let _ = write!( + svg, + r#" - let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); - let _ = write!( - svg, - r#" - - - - - "#, - color, color, color, color, color, color - ); - } - _ => {} + + + + + + + + + "#, + color, color, color, color, color, color + ); + } +} + +fn render_letter(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // GOLDEN DRAGON HEAD (Top-Center Crest) + + svg.push_str( + + r##" + + + + "## + + ); + } else { + let mut ch_val = None; + + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "char" => ch_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let ch = ch_val.unwrap_or_else(|| "T".to_string()); + + let color = color_val.unwrap_or_else(|| "#0a0e27".to_string()); + + let size = size_val.unwrap_or(32); + + let _ = write!( + svg, + r#"{}"#, + size, color, ch + ); + } +} + +fn render_logo(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + let mut text_val = None; + + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(48); + + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } else { + let mut text_val = None; + + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "text" => text_val = p.value.as_ref().map(|v| v.to_string()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let text = text_val.unwrap_or_else(|| "Logo".to_string()); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(48); + + let _ = write!( + svg, + r#"{}"#, + size, color, text + ); + } +} + +fn render_core(svg: &mut String, dsl: &DslBlockValue) { + let mut color_val = None; + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + _ => {} + } + } + + let color = color_val.unwrap_or_else(|| "#66e0ff".to_string()); + let size = size_val.unwrap_or(40); + let _ = write!( + svg, + r#""#, + size / 2, + color + ); +} + +fn render_emblem(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // ORANGE-RED TAIL (Bottom-Right Swirl) + + svg.push_str( + + r##" + + "## + + ); + } else { + let mut color_val = None; + + let mut size_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let color = color_val.unwrap_or_else(|| "#0088cc".to_string()); + + let size = size_val.unwrap_or(120); + + let x = 250 - size / 2; + + let y = 180 - size / 2; + + let _ = write!( + svg, + r#""#, + x, + y, + size, + size, + size / 4, + color + ); + } +} + +fn render_rings(svg: &mut String, dsl: &DslBlockValue, is_dragon: bool) { + if is_dragon { + // BLUE FLAME / WING (Bottom-Left Swirl) + + svg.push_str( + + r##""## + + ); + } else { + let mut count_val = None; + + let mut color_val = None; + + let mut size_val = None; + + let mut thickness_val = None; + + for p in &dsl.properties { + match p.name.as_str() { + "count" => count_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + "color" => color_val = p.value.as_ref().map(|v| v.to_string()), + + "size" => size_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + "thickness" => thickness_val = p.value.as_ref().and_then(|v| v.try_into_int().ok()), + + _ => {} + } + } + + let count = count_val.unwrap_or(3); + + let color = color_val.unwrap_or_else(|| "#00d4ff".to_string()); + + let size = size_val.unwrap_or(40); + + let thickness = thickness_val.unwrap_or(3); + + for i in 0..count { + let r = 80 + i as i64 * (size / 2); + + let opacity = 0.4 - (i as f32 * 0.08); + + let _ = write!( + svg, + r#""#, + r, color, thickness, opacity + ); + } + } +} + +fn render_dsl_to_svg(svg: &mut String, val: &RuntimeValue, is_dragon: bool) { + if let RuntimeValue::DslBlock(dsl) = val { + match dsl.kind.as_str() { + "circuits" => render_circuits(svg, dsl, is_dragon), + "letter" => render_letter(svg, dsl, is_dragon), + "logo" => render_logo(svg, dsl, is_dragon), + "core" => { + if !is_dragon { + render_core(svg, dsl); } } + "emblem" => render_emblem(svg, dsl, is_dragon), + "rings" => render_rings(svg, dsl, is_dragon), + _ => {} } - _ => {} } } diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index ce296064..50a54c49 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -540,7 +540,9 @@ fn test_http_module() { &mut ctx_unprivileged, vec![RuntimeValue::Str(format!("http://127.0.0.1:{}", port))], ); - assert!(matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_get, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); let post = http.exports.get("post").unwrap(); let res_post = post.call( @@ -550,7 +552,9 @@ fn test_http_module() { RuntimeValue::Str("body".to_string()), ], ); - assert!(matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation"))); + assert!( + matches!(res_post, Err(techscript_runtime::RuntimeError { kind: techscript_runtime::RuntimeErrorKind::InvalidOperation(msg), .. }) if msg.contains("Security policy violation")) + ); // Test with Network capability let mut caps = HashSet::new();