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 {}