Skip to main content

opy_macro_js/
error.rs

1//! Structured errors carrying script/source provenance.
2
3use std::fmt;
4
5/// A JavaScript exception with engine-provided provenance.
6///
7/// The QuickJS error value's `message` and `stack` are captured. Stack frames
8/// that reference the invocation's script name are line-adjusted so line
9/// numbers refer to the user's script text (the injected argument / `content`
10/// prologue is subtracted), mirroring the OverPy reference behavior
11/// (`normalizeScriptError` in `src/quickjs.ts`).
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct ScriptError {
14    /// The exception message (e.g. `"kaboom"`). Resource-limit abort messages
15    /// are `"interrupted"`, `"out of memory"`, and
16    /// `"Maximum call stack size exceeded"`.
17    pub message: String,
18    /// The script name the invocation was attributed to.
19    pub source_name: Option<String>,
20    /// 1-based line in the user's script of the first stack frame matching
21    /// `source_name`, when the engine provided a stack.
22    pub line: Option<u32>,
23    /// 1-based column of that frame, when available.
24    pub column: Option<u32>,
25    /// The engine stack trace with line numbers adjusted to the user's script,
26    /// when the engine provided one.
27    pub stack: Option<String>,
28}
29
30impl fmt::Display for ScriptError {
31    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
32        f.write_str(&self.message)
33    }
34}
35
36/// Errors produced by macro or hook execution.
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub enum MacroError {
39    /// The script threw an exception.
40    Script(ScriptError),
41    /// The script completed without throwing, but its completion value is not
42    /// a string. `type_name` is the ECMAScript `typeof` of the value; the
43    /// rendered message matches the OverPy reference (`src/quickjs.ts`).
44    InvalidResult { type_name: String },
45    /// Engine setup failure (runtime/context creation, builtin helper install).
46    Internal(String),
47}
48
49impl fmt::Display for MacroError {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        match self {
52            MacroError::Script(e) => e.fmt(f),
53            MacroError::InvalidResult { type_name } => write!(
54                f,
55                "JavaScript macro returned value with type of {type_name}, expected string. Try using .toString()"
56            ),
57            MacroError::Internal(message) => f.write_str(message),
58        }
59    }
60}
61
62impl std::error::Error for MacroError {}