Expand description
QuickJS JavaScript runtime backend for TypeScript plugins
This module provides a JavaScript runtime using QuickJS for executing TypeScript plugins. TypeScript is transpiled to JavaScript using oxc.
§Adding New API Methods
When adding a new method to JsEditorApi, follow these steps for full type safety:
§1. Define Types in fresh-core/src/api.rs
If your method needs custom types (parameters or return values), define them with:
#[derive(Debug, Clone, Serialize, Deserialize, TS)]
#[serde(rename_all = "camelCase")] // Match JS naming conventions
#[ts(export)] // Generates TypeScript type definition
pub struct MyConfig {
pub field: String,
}§2. Add PluginCommand Variant
In fresh-core/src/api.rs, add the command variant using typed structs:
pub enum PluginCommand {
MyCommand {
language: String,
config: MyConfig, // Use typed struct, not JsonValue
},
}§3. Implement the API Method
In JsEditorApi, use typed parameters for automatic deserialization:
/// Description of what this method does
pub fn my_method(&self, language: String, config: MyConfig) -> bool {
self.command_sender
.send(PluginCommand::MyCommand { language, config })
.is_ok()
}For methods returning complex types, use #[plugin_api(ts_return = "Type")]:
#[plugin_api(ts_return = "MyResult | null")]
pub fn get_data<'js>(&self, ctx: rquickjs::Ctx<'js>) -> rquickjs::Result<Value<'js>> {
// Serialize result to JS value
}For async methods:
#[plugin_api(async_promise, js_name = "myAsyncMethod", ts_return = "MyResult")]
#[qjs(rename = "_myAsyncMethodStart")]
pub fn my_async_method_start(&self, param: String) -> u64 {
// Return callback ID, actual result sent via PluginResponse
}§4. Register Types for Export
In ts_export.rs, add your types to get_type_decl():
"MyConfig" => Some(MyConfig::decl()),And import them at the top of the file.
§5. Handle the Command
In fresh-editor/src/app/plugin_commands.rs, add the handler:
pub(super) fn handle_my_command(&mut self, language: String, config: MyConfig) {
// Process the command
}And dispatch it in fresh-editor/src/app/mod.rs.
§6. Regenerate TypeScript Definitions
Run: cargo test -p fresh-plugin-runtime write_fresh_dts_file -- --ignored
This validates TypeScript syntax and writes plugins/lib/fresh.d.ts.
Structs§
- JsEditor
Api - JavaScript-exposed Editor API using rquickjs class system This allows proper lifetime handling for methods returning JS values
- Plugin
Handler - Plugin
Tracked State - Handler information for events and actions Tracks state created by a plugin for cleanup on unload.
- Quick
JsBackend - QuickJS-based JavaScript runtime for plugins
- TsPlugin
Info - Information about a loaded plugin
Constants§
- JSEDITORAPI_
JS_ METHODS - List of all JavaScript method names exposed in the API
- JSEDITORAPI_
REFERENCED_ TYPES - List of TypeScript types referenced in method signatures
- JSEDITORAPI_
TS_ EDITOR_ API - TypeScript EditorAPI interface (methods only)
- JSEDITORAPI_
TS_ PREAMBLE - TypeScript preamble (header, getEditor, ProcessHandle, BufferId, SplitId)
Functions§
- has_
fatal_ js_ error - Check if a fatal JS error has occurred
- set_
panic_ on_ js_ errors - Enable panicking on JS errors (call this from test setup)
- take_
fatal_ js_ error - Get and clear the fatal JS error message (returns None if no error)
Type Aliases§
- Async
Resource Owners - Type alias for the shared async resource owner map. Maps request_id → plugin_name for pending async resource creations (virtual buffers, composite buffers, terminals). Shared between QuickJsBackend (plugin thread) and PluginThreadHandle (main thread).
- Pending
Responses - Pending response senders type alias