Skip to main content

just_engine/runner/plugin/
mod.rs

1//! Plugin architecture and super-global scope.
2//!
3//! This module implements the **super-global scope** - a key architectural feature
4//! that provides lazy, dynamic resolution of built-in and plugin-provided objects.
5//!
6//! ## Super-Global Scope Concept
7//!
8//! The super-global scope sits outside the normal lexical environment chain and
9//! provides objects that are available globally but resolved on-demand:
10//!
11//! ```text
12//! Variable Lookup Order:
13//! 1. Local scope (function/block)
14//! 2. Outer scopes (lexical chain)
15//! 3. Global scope
16//! 4. Super-global scope ← Built-ins and plugins live here
17//! ```
18//!
19//! ### Key Components
20//!
21//! - **[`PluginResolver`]**: Trait for providing objects and methods dynamically
22//! - **[`SuperGlobalEnvironment`]**: Container holding multiple resolvers with caching
23//! - **[`CorePluginResolver`]**: Adapter wrapping [`BuiltInRegistry`] as a resolver
24//! - **[`EvalContext`](types::EvalContext)**: Execution context with super-global integration
25//!
26//! ### Resolution Flow
27//!
28//! When JavaScript code references a name (e.g., `Math`):
29//!
30//! 1. **Check cache**: Has this name been resolved before?
31//! 2. **Query resolvers**: Ask each resolver in registration order
32//! 3. **Cache result**: Store the resolved value for future lookups
33//! 4. **Return value**: Provide the object to JavaScript code
34//!
35//! ### Method Calls
36//!
37//! Method calls (e.g., `Math.abs(-5)`) are handled specially:
38//!
39//! 1. **Direct dispatch**: Resolvers can handle method calls directly without
40//!    materializing the object
41//! 2. **Fallback**: If no resolver handles it, fall back to property lookup
42//!
43//! This allows efficient built-in method calls without creating intermediate objects.
44//!
45//! ## Example: Custom Plugin
46//!
47//! ```
48//! use just::runner::plugin::resolver::PluginResolver;
49//! use just::runner::plugin::types::EvalContext;
50//! use just::runner::ds::value::{JsValue, JsNumberType};
51//! use just::runner::ds::error::JErrorType;
52//!
53//! struct UtilsPlugin;
54//!
55//! impl PluginResolver for UtilsPlugin {
56//!     fn has_binding(&self, name: &str) -> bool {
57//!         name == "Utils"
58//!     }
59//!     
60//!     fn resolve(&self, _name: &str, _ctx: &mut EvalContext) -> Result<JsValue, JErrorType> {
61//!         Ok(JsValue::Undefined) // Sentinel
62//!     }
63//!     
64//!     fn call_method(&self, obj: &str, method: &str, _ctx: &mut EvalContext,
65//!                    _this: JsValue, args: Vec<JsValue>) -> Option<Result<JsValue, JErrorType>> {
66//!         if obj == "Utils" && method == "double" {
67//!             let n = match args.first() {
68//!                 Some(JsValue::Number(JsNumberType::Integer(n))) => *n,
69//!                 _ => 0,
70//!             };
71//!             Some(Ok(JsValue::Number(JsNumberType::Integer(n * 2))))
72//!         } else {
73//!             None
74//!         }
75//!     }
76//!     
77//!     fn name(&self) -> &str { "utils_plugin" }
78//! }
79//!
80//! // Register the plugin
81//! let mut ctx = EvalContext::new();
82//! ctx.add_resolver(Box::new(UtilsPlugin));
83//! // Now Utils.double(21) returns 42
84//! ```
85//!
86//! ## Design Rationale
87//!
88//! ### Why Not Preload Everything?
89//!
90//! Traditional approach:
91//! - Load all built-ins at startup
92//! - High memory usage
93//! - Slow startup time
94//! - Hard to extend
95//!
96//! Super-global approach:
97//! - Load on first use (lazy)
98//! - Lower memory footprint
99//! - Fast startup
100//! - Easy to add plugins
101//!
102//! ### Why Not Use Global Scope?
103//!
104//! Keeping built-ins in a separate super-global scope:
105//! - Prevents accidental mutation from JavaScript
106//! - Allows local variables to shadow built-ins
107//! - Maintains clean separation of concerns
108//! - Enables efficient caching and dispatch
109
110pub mod types;
111pub mod registry;
112pub mod config;
113pub mod resolver;
114pub mod core_resolver;
115pub mod super_global;
116
117pub use types::{BuiltInFn, BuiltInObject, NativeFn, PluginInfo};
118pub use registry::BuiltInRegistry;
119pub use config::PluginConfig;
120pub use resolver::PluginResolver;
121pub use core_resolver::CorePluginResolver;
122pub use super_global::SuperGlobalEnvironment;