Files
jscriptx/extension.go
what 7e1893b246 refactor: 文件按主类型划分,一个 struct 一个功能
约定:文件名 = 主类型名;同一个类型要拆多个文件时用 类型_子项.go。

  engine.go          355 → 231 行。原来混了三件不相干的事
  engine_globals.go  ← bind / lazyGlobal / freeze / defineReadOnly(96 行)
                       它是「Go 值 → 只读 JS 全局」的转换层,跟脚本缓存毫无关系
  engine_console.go  ← console.go,跟上面是同一主题
  script.go          325 → 100 行,只留公开方法
  script_vm.go       ← VM 的取、还、装载。上个 commit 合一的三条路径现在住一起
  script_static.go   ← static.go
  errors.go          364 → 150 行
  errors_goja.go     ← goja 错误的翻译层
  errors_hints.go    ← missingGlobalHint,一份 JS 运行时知识库,跟错误分类是
                       两回事;拆出来之后 missing_global_test.go 才有对应源文件
  bundle_finalize.go ← esmwrap.go
  bundle.go          收下 validIdent / hashVersion(原来住在 engine.go)

Engine.New 原来排在所有私有函数之后,挪到导出方法那一段。

classify 83 → 54 行:四个 errors.As 分支各手搓一个 8 字段的 &Error{},脚本上下文
那三行重复了 4 遍,抽出 gojaError 构造器。

顺带修四处注释漂移:

  Session/会话   代码里叫 Instance,注释里大面积残留。engine_globals.go 那条
                 「注入会话全局对象失败」还是用户可见文案,而公开 API 里根本
                 没有「会话」这个概念
  Extension      文档示例写 Module() string,接口是 Module() (path, source string)。
                 这是唯一一段教人写扩展的文档,照抄编译不过
  doc.go 的 freeze  说白名单「逐层拷贝成只读对象,不会跨 VM 共享可变的 Go map」,
                 但那只对 map[string]any 成立。结构体指针和 slice 是**共享同一个
                 对象**的——扩展走的正是这条路,不该被当成隔离保证
2026-09-10 15:28:59 +08:00

49 lines
2.0 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package jscriptx
// Extension 是一个作用域级扩展:给脚本添一个全局对象。
//
// 扩展实例由调用方自己创建,跟着 ctx 走:
//
// st := jscriptx.NewStore()
// tx := myTx(db)
// ctx = jscriptx.WithScope(ctx, jscriptx.ScopeExtensions(st, tx))
//
// obj, err := ctrl.New(ctx) // 脚本里能用 store 和 tx
// defer obj.Close()
//
// st.Get("count") // Go 侧拿的就是同一份,不用再取回
//
// 同一个 ctx 下 New 出来的所有实例共享同一份扩展对象——这就是多个 controller
// 共享数据的方式:共享的是 Go 侧对象,不是共用 Runtime。
//
// 业务写自己的扩展只要实现这三个方法:
//
// type tx struct{ conn *sql.Tx }
//
// func (t *tx) Name() string { return "tx" }
// func (t *tx) Bindings() map[string]any {
// return map[string]any{"commit": t.conn.Commit, "rollback": t.conn.Rollback}
// }
// func (t *tx) Module() (path, source string) { return "@fsdpf/tx", txTypings }
type Extension interface {
// Name 是它在脚本里的全局名,必须是合法的 JS 标识符。
// 跟白名单(WithGlobals)同名时以白名单为准。
Name() string
// Bindings 是暴露给脚本的方法集。方法名**大写开头**,跟脚本里能碰到的
// 其它东西保持一致——传进来的 Go 对象(m.GetCode()、res.GetDBTable()
// 用的都是 Go 的方法名,扩展再用小写的话,同一行代码里两种风格混着写。
Bindings() map[string]any
// Module 返回配套 TypeScript 模块的 import 路径和源码,让脚本能拿到类型:
//
// import store from "@jscriptx/store"
//
// 路径要加 scope 前缀,免得跟 node_modules 里的包撞名。用什么 scope 自己定,
// 框架层那套用的是 @jscriptx/,业务自己的可以用 @fsdpf/ 之类。
// 路径返回空字符串表示不提供模块,脚本只能用全局变量的写法。
//
// 模块本身只是个门面:把全局对象转发出来,附上类型声明。真正的实现在 Go 侧。
Module() (path, source string)
}