Skip to main content

Module quickjs_backend

Module quickjs_backend 

Source
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§

JsEditorApi
JavaScript-exposed Editor API using rquickjs class system This allows proper lifetime handling for methods returning JS values
PluginHandler
PluginTrackedState
Handler information for events and actions Tracks state created by a plugin for cleanup on unload.
QuickJsBackend
QuickJS-based JavaScript runtime for plugins
TsPluginInfo
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§

AsyncResourceOwners
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).
PendingResponses
Pending response senders type alias