Repository navigation
Refactor: remove apps/templates, add examples/, restructure extension… - #3
Conversation
… crates - Remove apps/ directory (moved to examples/) - Remove templates/ directory - Add examples/ with example-deno-app, react-app, svelte-app, nextjs-app, system-monitor, text-editor, todo-app, wasm-forge-example, weather-app - Refactor extension crates: move js/init.ts to ts/init.ts - Add forge-weld and forge-weld-macro crates - Replace resolver.js with resolver.ts - Remove sdk/preload.js - Add new documentation for host-ipc, host-window, and crate docs - Update build.rs files across extension crates - Update site docs and configuration
Reviewer's GuideRefactors Forge’s extension build and docs around a new forge-weld codegen pipeline, replaces the old CLI templating/init flow with example-based onboarding, introduces new host:window and host:ipc documentation and crate docs, and updates paths and CI to use an examples/ directory instead of apps/ while modernizing extension build.rs and resolver/preload handling. Sequence diagram for renderer–Deno IPC via host:ipcsequenceDiagram
actor Renderer
participant WebView
participant ForgeHost
participant ext_ipc
participant DenoApp
Renderer->>WebView: window.host.send("button-click", payload)
WebView->>ForgeHost: IPC message
ForgeHost->>ext_ipc: op_ipc_recv (enqueue IpcEvent)
ext_ipc->>DenoApp: windowEvents()/onChannel yields event
DenoApp->>DenoApp: Handle "button-click" event
DenoApp->>ext_ipc: sendToWindow(windowId, "button-response", payload)
ext_ipc->>ForgeHost: op_ipc_send
ForgeHost->>WebView: dispatch to window.__host_dispatch
WebView->>Renderer: window.host.on("button-response", callback)
Class diagram for forge-weld IR and ExtensionBuilderclassDiagram
class WeldPrimitive {
<<enum>>
+U8
+U16
+U32
+U64
+Usize
+I8
+I16
+I32
+I64
+Isize
+F32
+F64
+Bool
+String
+Str
+Char
+Unit
+to_typescript() str
}
class WeldType {
<<enum_like>>
+Primitive(WeldPrimitive)
+Option(WeldType)
+Vec(WeldType)
+Bytes
+Result(ok:WeldType, err:WeldType)
+HashMap(key:WeldType, value:WeldType)
+BTreeMap(key:WeldType, value:WeldType)
+HashSet(WeldType)
+BTreeSet(WeldType)
+Tuple(elements:WeldType[])
+Array(element:WeldType, size:int)
+Generic(base:str, params:WeldType[])
+Struct(name:str)
+Enum(name:str)
+JsonValue
+OpState
+Box(WeldType)
+Arc(WeldType)
+Rc(WeldType)
+RefCell(WeldType)
+Mutex(WeldType)
+RwLock(WeldType)
+Reference(inner:WeldType, mutable:bool)
+Pointer(inner:WeldType, mutable:bool)
+Never
+Unknown
+to_typescript() str
+is_async_result() bool
+is_op_state() bool
}
class ParamAttr {
<<enum>>
+None
+String
+Serde
+Buffer
+Global
+State
}
class Op2Attrs {
+is_fast: bool
+string_return: bool
+serde_return: bool
+is_async: bool
+rename: str
}
class OpParam {
+rust_name: str
+ts_name: str
+ty: WeldType
+attr: ParamAttr
+doc: str
+optional: bool
+to_typescript_param() str
}
class OpSymbol {
+rust_name: str
+ts_name: str
+is_async: bool
+params: OpParam[]
+return_type: WeldType
+doc: str
+op2_attrs: Op2Attrs
+module: str
+visible_params() OpParam[]
+ts_return_type() str
+to_typescript_signature() str
}
class StructField {
+rust_name: str
+ts_name: str
+ty: WeldType
+optional: bool
+doc: str
+readonly: bool
+to_typescript_field() str
}
class WeldStruct {
+rust_name: str
+ts_name: str
+fields: StructField[]
+doc: str
+is_type_alias: bool
+type_params: str[]
+to_typescript_interface() str
}
class EnumVariant {
+name: str
+value: str
+data: WeldType
+doc: str
}
class WeldEnum {
+rust_name: str
+ts_name: str
+variants: EnumVariant[]
+doc: str
+to_typescript_type() str
}
class WeldModule {
+name: str
+specifier: str
+ops: OpSymbol[]
+structs: WeldStruct[]
+enums: WeldEnum[]
+esm_entry_point: str
+doc: str
+error_type: str
+error_code_start: int
+op_names() str[]
+deno_core_ops_declaration() str
+validate() ModuleValidationError
}
class ExtensionBuilder {
-module: WeldModule
-ts_path: Path
-sdk_path: Path
-additional_watch: Path[]
-dts_generator: fn() str
+ts_path(path: Path) ExtensionBuilder
+ops(names: str[]) ExtensionBuilder
+generate_sdk_types(sdk_rel: Path) ExtensionBuilder
+dts_generator(gen: fn() str) ExtensionBuilder
+build() Result~void,ExtensionBuilderError~
}
WeldPrimitive <.. WeldType
WeldType <.. OpParam
WeldType <.. OpSymbol
WeldType <.. StructField
WeldType <.. WeldEnum
ParamAttr <.. OpParam
Op2Attrs <.. OpSymbol
OpParam "*" --> "1" OpSymbol
StructField "*" --> "1" WeldStruct
EnumVariant "*" --> "1" WeldEnum
OpSymbol "*" --> "1" WeldModule
WeldStruct "*" --> "1" WeldModule
WeldEnum "*" --> "1" WeldModule
WeldModule <.. ExtensionBuilder
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey there - I've reviewed your changes and found some issues that need to be addressed.
- In forge-host you now copy and inject
sdk/preload.tsdirectly viawith_initialization_script, but WebView engines expect JavaScript, so you should transpile this to JS in build.rs and embed the JS source instead of the TypeScript. - The new
crates/forge-host/src/resolver.tsreplacesresolver.jsbut there’s no corresponding build step to transpile it; make sure the runtime either loads the.tsfile via a TS-aware pipeline or you generate a.jsartifact like before. - The forge-weld macros currently default many parameter and field types to
WeldType::Unknown; if these generated definitions are meant to drive the SDK typings, it would be helpful to start populating real type mappings (or clearly mark the generated d.ts as partial) to avoid misleading consumers.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- In forge-host you now copy and inject `sdk/preload.ts` directly via `with_initialization_script`, but WebView engines expect JavaScript, so you should transpile this to JS in build.rs and embed the JS source instead of the TypeScript.
- The new `crates/forge-host/src/resolver.ts` replaces `resolver.js` but there’s no corresponding build step to transpile it; make sure the runtime either loads the `.ts` file via a TS-aware pipeline or you generate a `.js` artifact like before.
- The forge-weld macros currently default many parameter and field types to `WeldType::Unknown`; if these generated definitions are meant to drive the SDK typings, it would be helpful to start populating real type mappings (or clearly mark the generated d.ts as partial) to avoid misleading consumers.
## Individual Comments
### Comment 1
<location> `crates/forge-weld-macro/Cargo.toml:11` </location>
<code_context>
-deno_ast = { version = "*", features = ["transpiling"] }
+forge-weld = { path = "../forge-weld" }
[dependencies]
anyhow = "1"
</code_context>
<issue_to_address>
**issue (bug_risk):** The macro crate references `forge_weld` types/macros but does not declare a dependency on the `forge-weld` crate.
The macros in `weld_op.rs` and `weld_struct.rs` expand to code that uses `forge_weld::OpSymbol`, `forge_weld::WeldStruct`, `forge_weld::StructField`, `forge_weld::WeldType`, and `forge_weld::register_*` macros. Without declaring `forge-weld` as a dependency, these paths will not resolve when compiling the proc-macro crate. Please add `forge-weld` as a dependency (with a compatible version) so this crate builds successfully.
</issue_to_address>
### Comment 2
<location> `crates/forge-weld-macro/src/weld_op.rs:147-152` </location>
<code_context>
+ let metadata_fn_name = format_ident!("__{}_weld_metadata", fn_name);
+
+ // Generate parameter metadata
+ let param_tokens: Vec<_> = params
+ .iter()
+ .map(|(name, _ty, optional)| {
+ let ts_param_name = to_camel_case(name);
+ quote! {
+ forge_weld::OpParam {
+ rust_name: #name.to_string(),
+ ts_name: #ts_param_name.to_string(),
</code_context>
<issue_to_address>
**issue (bug_risk):** `weld_op` macro generates struct initializers that don’t match the `forge_weld` IR types (e.g. `attr: None`, `op2_attrs: None`).
In `symbol.rs`, `OpParam.attr` is `ParamAttr` (not `Option<ParamAttr>`), and `OpSymbol.op2_attrs` is `Op2Attrs` (not `Option<_>`), so using `attr: None` / `op2_attrs: None` will not compile. Please construct concrete values instead (e.g. `ParamAttr::None`, `Op2Attrs::default()`). Also verify the `forge_weld::register_op!` path resolves correctly when this macro is invoked.
</issue_to_address>
### Comment 3
<location> `crates/forge-host/src/main.rs:61-63` </location>
<code_context>
}
-fn preload_js() -> &'static str {
+fn preload_ts() -> &'static str {
// Generated from sdk/preload.ts at build time
- include_str!(concat!(env!("OUT_DIR"), "/preload.js"))
+ include_str!(concat!(env!("OUT_DIR"), "/preload.ts"))
}
</code_context>
<issue_to_address>
**issue (bug_risk):** Injecting `preload.ts` as the WebView initialization script will likely fail because the WebView expects JavaScript, not TypeScript.
This now embeds the raw TypeScript source (`preload.ts`) instead of the transpiled JS that was previously produced at build time, and that string is passed directly to `with_initialization_script`. Unless the WebView layer transpiles TS at runtime (which is very unlikely), the preload will no longer execute. Please restore a build step that outputs JS (e.g., `preload.js` in `OUT_DIR`) and reference that JS file here instead of the TS source.
</issue_to_address>
### Comment 4
<location> `crates/forge-weld/README.md:3` </location>
<code_context>
+# Forge Weld
+
+This Module provides the glue/bindings for the forge framework, it glues the rust/deno methods and generates the code that is output by the framework.
+
+## How the Binding/Glue works
</code_context>
<issue_to_address>
**suggestion (typo):** Polish grammar and capitalization in this sentence for readability.
This sentence is a comma splice and uses inconsistent capitalization (e.g., "Module", "rust/deno"). Consider something like: `This module provides the glue/bindings for the Forge framework. It connects Rust and Deno methods and generates the code that the framework exposes.` Also ensure proper names (Rust, Deno, Forge) are capitalized consistently.
```suggestion
This module provides the glue/bindings for the Forge framework. It connects Rust and Deno methods and generates the code that the framework exposes.
```
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| [lib] | ||
| proc-macro = true | ||
|
|
||
| [dependencies] |
There was a problem hiding this comment.
issue (bug_risk): The macro crate references forge_weld types/macros but does not declare a dependency on the forge-weld crate.
The macros in weld_op.rs and weld_struct.rs expand to code that uses forge_weld::OpSymbol, forge_weld::WeldStruct, forge_weld::StructField, forge_weld::WeldType, and forge_weld::register_* macros. Without declaring forge-weld as a dependency, these paths will not resolve when compiling the proc-macro crate. Please add forge-weld as a dependency (with a compatible version) so this crate builds successfully.
| fn preload_ts() -> &'static str { | ||
| // Generated from sdk/preload.ts at build time | ||
| include_str!(concat!(env!("OUT_DIR"), "/preload.js")) | ||
| include_str!(concat!(env!("OUT_DIR"), "/preload.ts")) |
There was a problem hiding this comment.
issue (bug_risk): Injecting preload.ts as the WebView initialization script will likely fail because the WebView expects JavaScript, not TypeScript.
This now embeds the raw TypeScript source (preload.ts) instead of the transpiled JS that was previously produced at build time, and that string is passed directly to with_initialization_script. Unless the WebView layer transpiles TS at runtime (which is very unlikely), the preload will no longer execute. Please restore a build step that outputs JS (e.g., preload.js in OUT_DIR) and reference that JS file here instead of the TS source.
| @@ -0,0 +1,12 @@ | |||
| # Forge Weld | |||
|
|
|||
| This Module provides the glue/bindings for the forge framework, it glues the rust/deno methods and generates the code that is output by the framework. | |||
There was a problem hiding this comment.
suggestion (typo): Polish grammar and capitalization in this sentence for readability.
This sentence is a comma splice and uses inconsistent capitalization (e.g., "Module", "rust/deno"). Consider something like: This module provides the glue/bindings for the Forge framework. It connects Rust and Deno methods and generates the code that the framework exposes. Also ensure proper names (Rust, Deno, Forge) are capitalized consistently.
| This Module provides the glue/bindings for the forge framework, it glues the rust/deno methods and generates the code that is output by the framework. | |
| This module provides the glue/bindings for the Forge framework. It connects Rust and Deno methods and generates the code that the framework exposes. |
…ge-weld - Add forge-weld dependency to forge-weld-macro Cargo.toml - Fix weld_op macro to use ParamAttr::default() and Op2Attrs::default() - Implement rust_type_to_weld_type() for proper Rust→TypeScript type mappings - Add comprehensive type inference for primitives, generics, and collections - Fix GTK window type mismatch using upcast_ref() for context menus - Add preload.ts transpilation to JS in forge-host build.rs - Write comprehensive README documentation for forge-weld - Fix flaky transpile tests to handle quote style variations
…e X11 XID function
Changes
Code Review Fixes
ParamAttr::default()andOp2Attrs::default()rust_type_to_weld_type()for proper Rust → TypeScript type mappingsupcast_ref()for context menus on LinuxCompiler Warning Fixes
windowvariable on Linux: implement native handle retrieval using GDK window pointer_app_menuunused assignment warning: properly reference variable in log messagelet _ =unit value binding: remove unnecessary binding fromshow_context_menu_for_gtk_window()Build Fixes
gdk::ffi::gdk_x11_window_get_xidfunctionSummary by Sourcery
Refactor the Forge framework to use a new forge-weld-based extension build system, replace CLI templates with example apps, and expand documentation and APIs around window management and IPC.
New Features:
Enhancements:
Build:
CI:
Documentation:
forge init, and to highlight new example applications.Chores: