#browser-automation #testing #playwright #chromium

macro viewpoint-js

Compile-time validated JavaScript macro for Viewpoint

28 releases

Uses new Rust 2024

0.4.3 Jan 17, 2026
0.4.2 Jan 4, 2026
0.3.6 Jan 4, 2026
0.2.16 Jan 2, 2026
0.2.11 Dec 31, 2025

#24 in #playwright


Used in 2 crates

MIT license

100KB
2K SLoC

viewpoint-js

Compile-time validated JavaScript macro for Viewpoint.

This crate provides a js! macro that validates JavaScript syntax at compile time, similar to how serde_json::json! validates JSON. This catches JavaScript syntax errors early, before they reach the browser.

Features

  • Compile-time validation: JavaScript syntax errors are caught during compilation
  • Value interpolation: Embed Rust expressions using #{expr} syntax (quoted/escaped)
  • Raw interpolation: Inject pre-built JavaScript using @{expr} syntax (unquoted)
  • Zero runtime overhead: Static strings when no interpolation is used
  • Clear error messages: Points to the exact location of syntax errors
  • Full JavaScript syntax support: Single-quoted strings, template literals, regex literals, and more

Usage

Add to your Cargo.toml:

[dependencies]
viewpoint-js = "0.2"
viewpoint-js-core = "0.2"  # Required for interpolation

Simple Expressions

use viewpoint_js::js;

// Returns &'static str
let code = js!{ 1 + 2 };
let code = js!{ () => window.innerWidth };
let code = js!{
    (() => {
        const items = document.querySelectorAll('li');
        return items.length;
    })()
};

Value Interpolation

Use #{expr} to embed Rust values into JavaScript (properly quoted and escaped):

use viewpoint_js::js;
use viewpoint_js_core::ToJsValue;

let selector = ".my-class";
let code = js!{ document.querySelector(#{selector}) };
// Produces: "document.querySelector(\".my-class\")"

let count = 42;
let code = js!{ Array(#{count}).fill(0) };
// Produces: "Array(42).fill(0)"

Raw Interpolation

Use @{expr} to inject pre-built JavaScript expressions directly (without quoting):

use viewpoint_js::js;

// Inject a JavaScript expression as-is
let selector_expr = "document.querySelectorAll('.item')";
let code = js!{ Array.from(@{selector_expr}) };
// Produces: "Array.from(document.querySelectorAll('.item'))"

// Useful for building complex JS with dynamic parts
let frame_access = get_frame_access_code();
let code = js!{
    (function() {
        const doc = @{frame_access};
        return doc.title;
    })()
};

Mixing Both Interpolation Types

You can use both #{} and @{} in the same macro call:

use viewpoint_js::js;

let selector_expr = "document.body";
let attr_name = "data-id";
let code = js!{ @{selector_expr}.setAttribute(#{attr_name}, "value") };
// Produces: "document.body.setAttribute(\"data-id\", \"value\")"

JavaScript Syntax Support

The js! macro supports all JavaScript string and literal syntax:

use viewpoint_js::js;

// Single-quoted strings
let code = js!{ console.log('hello') };

// Template literals with JavaScript interpolation
let code = js!{ `Hello, ${userName}!` };

// Template literals with Rust interpolation
let name = "world";
let code = js!{ `Hello, #{name}!` };

// Regex literals
let code = js!{ /^test/.test(str) };

// XPath with mixed quotes
let code = js!{ document.evaluate("//div[@class='item']", doc) };

// CSS attribute selectors
let code = js!{ document.querySelector('[data-id="test"]') };

Compile-Time Errors

Invalid JavaScript produces compile-time errors:

use viewpoint_js::js;

// This won't compile!
let code = js!{ function( };

Supported Types for Interpolation

The following types implement ToJsValue:

  • Integers: i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize
  • Floats: f32, f64 (handles NaN, Infinity, -Infinity)
  • Boolean: bool
  • Strings: String, &str (properly escaped)
  • Option: Option<T> where T: ToJsValue (produces value or null)
  • JSON: serde_json::Value (with json feature)

Features

  • json - Enable serde_json::Value support for interpolation

License

MIT

Dependencies

~16–30MB
~331K SLoC