Go and Hybrid Packages
Register app-specific packages with app.AddPackage. Callers use the same import syntax whether the implementation is Go-only or combines Go and Nubo.
type Package struct { Source string Files fs.FS Funcs map[string]any}| Field | Meaning |
|---|---|
Source | Inline Nubo entry source. |
Files | Filesystem for an entry file and/or relative helper files. |
Funcs | Go functions using the reflection bridge’s supported signatures. |
The public registration API currently requires @std/... names. Use a name such as @std/myapp/text, not a bare Go module path or an @app prefix. Duplicate registrations and built-in name collisions are rejected.
Go-only packages
Section titled “Go-only packages”Inside a host with app := nubo.New():
err := app.AddPackage("@std/myapp/text", nubo.Package{ Funcs: map[string]any{ "upper": strings.ToUpper, },})Import strings in Go and check err. The registered function is a public package member:
import text from "@std/myapp/text"
println(text.upper("hello"))A Go-only package does not need a package.nubo file.
Hybrid packages
Section titled “Hybrid packages”Use Nubo to define public method names, signatures, defaults, validation, and structs. Keep the necessary host operations in Go.
package main
import ( "fmt" "log" "strings"
"github.com/nubolang/nubo")
func main() { app := nubo.New()
err := app.AddPackage("@std/myapp/text", nubo.Package{ Source: `import native from "@native"
fn shout(value: string, suffix: string = "!") string { return native.upper(value) + suffix}`, Funcs: map[string]any{ "upper": strings.ToUpper, }, }) if err != nil { log.Fatal(err) }
result, err := app.ExecString(`import text from "@std/myapp/text"return text.shout(value: "hello", suffix: "!!")`) if err != nil { log.Fatal(err) }
if result != nil { fmt.Println(result.Value()) }}This returns HELLO!!. Callers see shout; the Go upper binding is accessed through the module’s private @native namespace.
How entry source is selected
Section titled “How entry source is selected”| Registration | Entry |
|---|---|
Only Funcs | Go package; no source entry. |
Nonempty Source | Inline string served as virtual package.nubo. |
Only Files | package.nubo must exist in that filesystem. |
Both Source and Files | Inline entry, with relative helper files from Files. |
No disk file is created for inline source. To keep Nubo code in a real file during development, embed its contents:
//go:embed package.nubovar packageSource stringThis requires importing _ "embed". Then pass Source: packageSource. To embed several files, use embed.FS and pass the filesystem rooted at the package entry, using fs.Sub when needed.
Native ownership and initialization
Section titled “Native ownership and initialization”@native is available only to the owning registered source package and its relative helpers. Application scripts cannot import that namespace directly. Another source package has its own bindings. Native imports are omitted from normal package exports.
The runtime initializes a source package on its first import and caches successful exports. Failed initialization can be retried. Circular package initialization reports an error instead of waiting forever.
Public exports omit private declarations and interpreter bookkeeping names. Module initialization runs as dependent execution: __entry__ is false. File imports remain file imports; registering a hybrid package does not change their syntax.
For a real standard-library example, see internal/packages/hex in the Nubo repository.