Skip to main content

schemaorg_rs/
wasm.rs

1//! WASM bindings for `schemaorg-rs`.
2//!
3//! Exposes three functions to JavaScript:
4//!
5//! - [`extract`] -- parse HTML and return structured data as JSON
6//! - [`validate_html`] -- full pipeline: extract -> validate -> profile evaluate
7//! - [`schema_version`] -- returns the Schema.org vocabulary version
8//!
9//! All functions return JSON strings. The JS wrapper in `wasm/index.js`
10//! calls `JSON.parse()` on the results.
11
12use wasm_bindgen::prelude::*;
13
14use crate::graph;
15use crate::profiles::ProfileRegistry;
16use crate::validation;
17
18/// Initializes the WASM module. Call once before other functions.
19/// Sets up a panic hook that logs to `console.error`.
20#[wasm_bindgen(start)]
21pub fn wasm_start() {
22    std::panic::set_hook(Box::new(|info| {
23        let msg = info.to_string();
24        log_error(&msg);
25    }));
26}
27
28#[wasm_bindgen]
29extern "C" {
30    #[wasm_bindgen(js_namespace = console, js_name = error)]
31    fn log_error(s: &str);
32}
33
34/// Extracts structured data from HTML and returns it as a JSON string.
35///
36/// The returned JSON contains an array of `SchemaNode` objects with their
37/// types, properties, source format, and source location.
38///
39/// # Returns
40///
41/// JSON string: `{ "nodes": [...], "warnings": [...] }` on success,
42/// or `{ "error": "..." }` on failure.
43#[wasm_bindgen]
44pub fn extract(html: &str) -> String {
45    match graph::extract_all(html) {
46        Ok(graph) => {
47            let result = serde_json::json!({
48                "nodes": graph.nodes,
49                "warnings": graph.warnings,
50            });
51            serde_json::to_string(&result)
52                .unwrap_or_else(|e| serde_json::json!({ "error": e.to_string() }).to_string())
53        }
54        Err(e) => serde_json::json!({ "error": e.to_string() }).to_string(),
55    }
56}
57
58/// Full validation pipeline: extract -> vocab validate -> profile evaluate.
59///
60/// Runs extraction, Schema.org vocabulary validation, and profile evaluation
61/// in a single call. Returns a combined JSON result.
62///
63/// # Arguments
64///
65/// - `html` -- the HTML document to analyze
66/// - `profile` -- the profile name to evaluate against (`"google"` or `"baseline"`)
67///
68/// # Returns
69///
70/// JSON string containing:
71/// ```json
72/// {
73/// "extraction": { "nodes": [...], "warnings": [...] },
74/// "validation": { "diagnostics": [...], "has_errors": bool },
75/// "profile": { "eligibility": "...", "type_results": [...], "diagnostics": [...] }
76/// }
77/// ```
78///
79/// Or `{ "error": "..." }` on extraction failure.
80#[wasm_bindgen]
81pub fn validate_html(html: &str, profile: &str) -> String {
82    // Step 1: Extract
83    let graph = match graph::extract_all(html) {
84        Ok(g) => g,
85        Err(e) => return serde_json::json!({ "error": e.to_string() }).to_string(),
86    };
87
88    // Step 2: Vocabulary validation
89    let vocab_result = validation::validate(&graph);
90
91    // Step 3: Profile evaluation
92    let registry = match profile {
93        "baseline" => ProfileRegistry::with_baseline(),
94        _ => ProfileRegistry::with_google(),
95    };
96
97    let profile_result = registry.evaluate(profile, &graph, &vocab_result.diagnostics);
98
99    let profile_json = match profile_result {
100        Ok(r) => serde_json::json!({
101            "eligibility": r.eligibility.to_string(),
102            "type_results": r.type_results,
103            "diagnostics": r.diagnostics,
104        }),
105        Err(e) => serde_json::json!({
106            "eligibility": "NotEligible",
107            "type_results": [],
108            "diagnostics": [],
109            "note": e.to_string(),
110        }),
111    };
112
113    let result = serde_json::json!({
114        "extraction": {
115            "nodes": graph.nodes,
116            "warnings": graph.warnings,
117        },
118        "validation": {
119            "diagnostics": vocab_result.diagnostics,
120            "has_errors": vocab_result.has_errors(),
121        },
122        "profile": profile_json,
123    });
124
125    serde_json::to_string(&result)
126        .unwrap_or_else(|e| serde_json::json!({ "error": e.to_string() }).to_string())
127}
128
129/// Returns the Schema.org vocabulary version used by this build.
130#[wasm_bindgen]
131pub fn schema_version() -> String {
132    crate::vocabulary::schema_version().to_string()
133}