Compare commits

..

3 Commits

Author SHA1 Message Date
AI Engineer
d667544d05 feat(document): 具名化 JS 导出并动态包裹错误(by AI) 2026-06-21 10:17:40 +08:00
AI Engineer
17900e0212 chore: align infrastructure to v1.5.x (by AI) 2026-06-11 20:39:00 +08:00
AI Engineer
cd65dee1b3 chore: align infrastructure to v1.5.2 (by AI) 2026-06-11 19:01:32 +08:00
4 changed files with 98 additions and 41 deletions

View File

@ -1,5 +1,12 @@
# CHANGELOG # CHANGELOG
## v1.5.3 (2026-06-21)
- **JS 对齐**: 重构 JS 导出为具名函数,并引入 `jsmod.MakeError` 动态包装错误以获取调用栈。
- **依赖更新**: 升级依赖 `jsmod``v1.5.3``cast``v1.5.3``rand``v1.5.3``encoding``v1.5.4``safe``v1.5.2``file``v1.5.5`
## v1.5.2 (2026-06-11)
- **版本对齐**: 基础设施全局对齐 v1.5.2。
## v1.5.1 (2026-06-08) ## v1.5.1 (2026-06-08)
- **JS 对齐 & 智能文档**: - **JS 对齐 & 智能文档**:
- 将所有注册到 `jsmod` 的方法名统一为 PascalCase。 - 将所有注册到 `jsmod` 的方法名统一为 PascalCase。

27
TEST.md Normal file
View File

@ -0,0 +1,27 @@
# Test Report: @go/document
## 📋 测试概览
- **测试时间**: 2026-06-21
- **测试环境**: darwin/amd64
- **Go 版本**: 1.25.0
## ✅ 功能测试 (Functional Tests)
| 场景 | 状态 | 描述 |
| :--- | :--- | :--- |
| `TestExcel_Basic` | PASS | Excel 基础单元格及公式读写测试。 |
| `TestExcel_Data` | PASS | Excel 对象数组及映射读写测试。 |
| `TestUnifiedAPI` | PASS | 统一的 Document 接口 Open/Create/Save 行为测试。 |
| `TestIDGeneration` | PASS | RAG 场景 ID 生成器及映射验证。 |
| `TestGraph_Basic` | PASS | Graph 关系型文档节点及关系建模测试。 |
| `TestGraph_Unified` | PASS | Graph 到 Markdown (Mermaid) 链路集成测试。 |
| `TestCSV` | PASS | CSV 文档对象及表格转换测试。 |
| `TestMarkdown` | PASS | Markdown 格式解析与重构测试。 |
## 🛡️ 鲁棒性防御 (Robustness)
- **可选参数提示**`Open``Save` 方法接受指针作为可选参数,结合最新的 `go/js` 引擎智能过滤空参数。
- **JS 错误调用栈**JS 桥接层改用具名导出并使用 `jsmod.MakeError` 包裹错误,确保 JS 抛出异常时携带准确的 Go 运行时堆栈。
## ⚡ 性能基准 (Benchmarks)
| 函数 | 平均耗时 | 性能分析 |
| :--- | :--- | :--- |
| `Excel_SetData` | **1874250 ns/op** | Excel 大量数据处理性能指标。 |

12
go.mod
View File

@ -3,18 +3,18 @@ module apigo.cc/go/document
go 1.25.0 go 1.25.0
require ( require (
apigo.cc/go/cast v1.5.0 apigo.cc/go/cast v1.5.3
apigo.cc/go/file v1.5.0 apigo.cc/go/file v1.5.5
apigo.cc/go/jsmod v1.5.0 apigo.cc/go/jsmod v1.5.3
github.com/dslipak/pdf v0.0.2 github.com/dslipak/pdf v0.0.2
github.com/xuri/excelize/v2 v2.10.1 github.com/xuri/excelize/v2 v2.10.1
github.com/young2j/oxmltotext v1.0.3 github.com/young2j/oxmltotext v1.0.3
) )
require ( require (
apigo.cc/go/encoding v1.5.0 // indirect apigo.cc/go/encoding v1.5.4
apigo.cc/go/rand v1.5.0 // indirect apigo.cc/go/rand v1.5.3
apigo.cc/go/safe v1.5.0 // indirect apigo.cc/go/safe v1.5.2
github.com/andybalholm/brotli v1.0.5 // indirect github.com/andybalholm/brotli v1.0.5 // indirect
github.com/dgrr/quickxml v0.0.0-20201022091424-4977de546d6c // indirect github.com/dgrr/quickxml v0.0.0-20201022091424-4977de546d6c // indirect
github.com/klauspost/compress v1.17.0 // indirect github.com/klauspost/compress v1.17.0 // indirect

View File

@ -9,10 +9,17 @@ import (
func init() { func init() {
jsmod.Register("document", map[string]any{ jsmod.Register("document", map[string]any{
"Open": func(ctx context.Context, filename string, password *string) (*jsDocument, error) { "Open": jsOpen,
"Create": jsCreate,
"NewExcel": jsNewExcel,
"NewGraph": jsNewGraph,
})
}
func jsOpen(ctx context.Context, filename string, password *string) (*jsDocument, error) {
p, err := file.VerifyPathForSafeMode(ctx, filename) p, err := file.VerifyPathForSafeMode(ctx, filename)
if err != nil { if err != nil {
return nil, err return nil, jsmod.MakeError(err)
} }
var doc Document var doc Document
if password != nil { if password != nil {
@ -21,24 +28,25 @@ func init() {
doc, err = Open(p) doc, err = Open(p)
} }
if err != nil { if err != nil {
return nil, err return nil, jsmod.MakeError(err)
} }
return &jsDocument{ctx: ctx, d: doc}, nil return &jsDocument{ctx: ctx, d: doc}, nil
}, }
"Create": func(ctx context.Context, ext string) (*jsDocument, error) {
func jsCreate(ctx context.Context, ext string) (*jsDocument, error) {
doc, err := Create(ext) doc, err := Create(ext)
if err != nil { if err != nil {
return nil, err return nil, jsmod.MakeError(err)
} }
return &jsDocument{ctx: ctx, d: doc}, nil return &jsDocument{ctx: ctx, d: doc}, nil
}, }
"NewExcel": func(ctx context.Context) *jsDocument {
func jsNewExcel(ctx context.Context) *jsDocument {
return &jsDocument{ctx: ctx, d: NewExcel()} return &jsDocument{ctx: ctx, d: NewExcel()}
}, }
"NewGraph": func(ctx context.Context) *jsDocument {
func jsNewGraph(ctx context.Context) *jsDocument {
return &jsDocument{ctx: ctx, d: NewGraph()} return &jsDocument{ctx: ctx, d: NewGraph()}
},
})
} }
type jsDocument struct { type jsDocument struct {
@ -54,38 +62,53 @@ func (j *jsDocument) Save(filename *string) error {
if filename != nil && *filename != "" { if filename != nil && *filename != "" {
p, err := file.VerifyPathForSafeMode(j.ctx, *filename) p, err := file.VerifyPathForSafeMode(j.ctx, *filename)
if err != nil { if err != nil {
return err return jsmod.MakeError(err)
} }
targetPath = p targetPath = p
} }
return j.d.Save(targetPath) if err := j.d.Save(targetPath); err != nil {
return jsmod.MakeError(err)
}
return nil
} }
// Excel 增强方法 (如果底层是 Excel) // Excel 增强方法 (如果底层是 Excel)
func (j *jsDocument) Get(sheetName string, start, end string) ([][]any, error) { func (j *jsDocument) Get(sheetName string, start, end string) ([][]any, error) {
if x, ok := j.d.(*Excel); ok { if x, ok := j.d.(*Excel); ok {
return x.Get(sheetName, start, end) res, err := x.Get(sheetName, start, end)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
} }
return nil, nil return nil, nil
} }
func (j *jsDocument) GetData(sheetName string, start, end string) ([]map[string]any, error) { func (j *jsDocument) GetData(sheetName string, start, end string) ([]map[string]any, error) {
if x, ok := j.d.(*Excel); ok { if x, ok := j.d.(*Excel); ok {
return x.GetData(sheetName, start, end) res, err := x.GetData(sheetName, start, end)
if err != nil {
return nil, jsmod.MakeError(err)
}
return res, nil
} }
return nil, nil return nil, nil
} }
func (j *jsDocument) Set(sheetName string, table [][]any, start, end string) error { func (j *jsDocument) Set(sheetName string, table [][]any, start, end string) error {
if x, ok := j.d.(*Excel); ok { if x, ok := j.d.(*Excel); ok {
return x.Set(sheetName, table, start, end) if err := x.Set(sheetName, table, start, end); err != nil {
return jsmod.MakeError(err)
}
} }
return nil return nil
} }
func (j *jsDocument) SetData(sheetName string, data []map[string]any, start, end string) error { func (j *jsDocument) SetData(sheetName string, data []map[string]any, start, end string) error {
if x, ok := j.d.(*Excel); ok { if x, ok := j.d.(*Excel); ok {
return x.SetData(sheetName, data, start, end) if err := x.SetData(sheetName, data, start, end); err != nil {
return jsmod.MakeError(err)
}
} }
return nil return nil
} }