Skip to content

feat(bloblang): Improve Bloblang playground with Go/WASM migration#570

Open
iamramtin wants to merge 24 commits intowarpstreamlabs:mainfrom
iamramtin:playground-v2
Open

feat(bloblang): Improve Bloblang playground with Go/WASM migration#570
iamramtin wants to merge 24 commits intowarpstreamlabs:mainfrom
iamramtin:playground-v2

Conversation

@iamramtin
Copy link
Copy Markdown
Contributor

@iamramtin iamramtin commented Nov 24, 2025

Summary

Improves the Bloblang playground by migrating core logic from JavaScript to Go/WASM.

The playground previously duplicated some of Bloblang logic in JavaScript, creating maintenance overhead and potential inconsistencies. By moving to Go/WASM, we:

  • Better align it with the rest of the codebase
  • Reuse existing Bloblang environment and validation logic directly
  • Eliminate duplication between Go and JS implementations
  • Improve type safety and error handling
  • Maintain a closer source of truth for Bloblang behavior

Changes

Go/WASM Migration:

  • Migrated execution, validation, formatting, autocompletion, and other utilities from JS to Go/WASM
  • Split blobl package into focused modules (core, editor, server, wasm, types)
  • Simplified WASM initialization and auto-register server/WASM handlers
  • Added elementary test suite for core playground functions (verifies playground-specific behavior without duplicating existing Bloblang tests)

JavaScript Simplification:

  • Extracted BloblangAPI abstraction layer for WASM/server routing
  • Removed unused code, dead methods, redundant functionality
  • Improved error handling and WASM initialization flow

Other Improvements:

  • Improved autocomplete with pre-rendered HTML docs and smarter context detection
  • Replaced hardcoded values with CSS variables and duplicate rules
  • Improved mobile responsive layout and overall UX

Testing

1. Run Unit Tests

make playground-test

2. Test Server Mode (Go backend via HTTP)

# Build and run playground server
go build -o bento ./cmd/bento/main.go
make playground
./bento blobl playground -p 3001 --no-open

Visit playground and verify:

  • Playground loads without errors
  • Execute mappings (try: root.name = this.name.uppercase())
  • Format mappings (Cmd/Ctrl+Shift+F or Format button)
  • Autocomplete works (type root = and trigger autocomplete)
  • Error messages display correctly for invalid input/mappings
  • Theme toggle works (light/dark mode)

3. Test WASM Mode (Client-side execution)

# Clean and rebuild
rm -rf website/static/playground
make docs
make playground
cd website && yarn start

Visit the playground in the docs and verify:

  • Playground loads in iframe without errors
  • All functionality from server mode works (execution, formatting, autocomplete)
  • Theme syncs with Docusaurus theme
  • Responsive layout works on mobile viewport (resize browser)
  • Full-screen mode works (click "Open in Full Screen" button)

Breaking Changes

None

- Replaced JavaScript integration with Go and WASM instead
- Improved WASM API exposure and updated JS integration
- Added full syntax support to formatter (operators, keywords, pipes)

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
…lidation API

- Moved documentation HTML generation from JS to Go
- Pre-generate docHTML for functions/methods
- Added validation function
- Added JSON utilities (format/minify/validate) with WASM and HTTP endpoints
- Updated JS to prioritise WASM with native fallbacks
- Centralized WASM function registration

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
  - Tests core functions: execute, validate, syntax, format, autocomplete
  - Tests JSON utilities: formatJSON, minifyJSON, validateJSON

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
- Replace hardcoded values with CSS variables
- Remove duplicate CSS rules
- Fix mobile responsive layout
- Add Bento-themed scrollbars to all editors

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Also simplified WASM initialization and auto-register server/WASM handlers.

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
- Remove redundant JSON utilities from Go/WASM (use native JS instead)
- Extract BloblangAPI abstraction layer for WASM/server routing
- Remove unused code and dead methods
- Improve error handling and WASM initialization flow
- Improve UX

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
@iamramtin iamramtin marked this pull request as ready for review November 25, 2025 03:54
- Fix type mismatch in getCompletions() for functionSpecWithHTML/methodSpecWithHTML
- Improve autocompletion suggestions for Bloblang keywords
- Add tests to verify completion types and structure

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
@iamramtin
Copy link
Copy Markdown
Contributor Author

Hey @gregfurman @jem-davies just a friendly ping to see if we can get this merged in?

@gregfurman
Copy link
Copy Markdown
Collaborator

@iamramtin hey! Thanks for the ping and sorry for delay, will give this a priority review 👍

Copy link
Copy Markdown
Collaborator

@gregfurman gregfurman left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll do another pass but have left some comments on structure and the pattern(s) used. Lmk thoughts!

Comment thread internal/cli/blobl/core.go Outdated
Comment thread internal/cli/blobl/core.go Outdated
Comment thread internal/cli/blobl/core.go Outdated
Comment thread Makefile Outdated
Comment thread internal/cli/blobl/wasm.go Outdated
Comment thread internal/cli/blobl/wasm.go Outdated
Comment thread internal/cli/blobl/types.go Outdated
type FormatMappingResponse struct {
Success bool `json:"success"`
Formatted string `json:"formatted"`
Error string `json:"error,omitempty"`
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can use the globally available Error function from the JS environment i.e

var errorResp FormatMappingResponse
err := js.Global().Get("Error").New(errorResp.Error)
panic(err) // or maybe ignore if error

Then we can treat the error case as a JS-level error and handle with a try-catch instead of this error payload approach.

Also, that way we don't need to pass around an error attribute and can focus on payload responses.

wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See 24c6fa92f2a9, lmk wyt!

Comment thread internal/cli/blobl/types.go Outdated

// FunctionSpecWrapper wraps query.FunctionSpec to implement Spec interface
type FunctionSpecWrapper struct {
query.FunctionSpec
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think the entire struct needs to be embedded here since you're just using some attributes. Consider

Suggested change
query.FunctionSpec
spec query.FunctionSpec

and then

func (f FunctionSpecWrapper) GetDescription() string { return f.spec.Description }

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call, I think this explicitness is much better 👍

Comment thread internal/cli/blobl/types.go Outdated
}

// Spec represents a unified interface for function and method specs
type Spec interface {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not use a dedicated Spec struct here instead with the attributes we need? Feels like 2 more structs + an interface is a bit of overkill.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How would you feel about me adding a BaseSpec to internal/bloblang/query/docs.go and having FunctionSpec and MethodSpec embed those shared attributes instead of duplicating all this logic in this file?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See commit 407ffa62b and LMK what you think, this is non-breaking and fully compatible and should let me not have to redeclare these shared attributes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And follow up 1da4e310a to see how it affects the current code

Comment thread internal/cli/blobl/wasm/wasm.go
…nd MethodSpec

Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
Signed-off-by: Ramtin Mesgari <26694963+iamramtin@users.noreply.github.com>
@iamramtin iamramtin requested a review from gregfurman January 25, 2026 05:55
@iamramtin
Copy link
Copy Markdown
Contributor Author

@gregfurman addressed comments, LMK WYT 🏁

Comment thread internal/cli/blobl/core_test.go Outdated
}
}

// Test validate (Bloblang validation)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// Test validate (Bloblang validation)

Comment thread internal/cli/blobl/core_test.go Outdated
Comment thread internal/cli/blobl/core_test.go
Comment thread internal/cli/blobl/core_test.go Outdated
Comment thread internal/cli/blobl/core.go Outdated
Comment thread internal/cli/blobl/editor.go
Comment thread internal/cli/blobl/editor.go Outdated
}

// formatBloblang formats Bloblang code with indentation and consistent spacing
func formatBloblang(originalMapping string) (string, error) {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok wow I can't pretend to say I understand much of what is happening here re: all of this parsing. How did we do it previously in the playground?

Comment thread internal/cli/blobl/server.go
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be possible to revert this refactor? I'm finding it a bit tough to see what was added versus what was refactored

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I understand the difficulty in reviewing this as a mixed change, but I'd prefer not to revert as most of the diff is structural rather than behavioural

The refactor separates server lifecycle, routing, and handlers into explicit types and methods, removes large inline closures, and centralises the state into a server type. This was necessary to make this file more idiomatic when adding the new endpoints cleanly without further growing what was previously essentially just a single function

Functionally, behaviuor is the same, main change is turning implicit structure into explicit structure so future additions don't compound the layout

I’m happy to walk through the structure or split follow-ups if that helps

// ------------------------------------------------------------------------------

// BaseSpec contains fields shared by function and method specifications.
type BaseSpec struct {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thoughts on just having a custom struct inside the blobl package that maps FunctionSpec or MethodSpec to a common single type? That way, the internal/bloblang functionality does not need to be touched at all and we can keep this unified approach logic where its needed

@iamramtin iamramtin requested a review from gregfurman March 14, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants