diff --git a/.gitignore b/.gitignore index 2c17577e..d754ef7f 100644 --- a/.gitignore +++ b/.gitignore @@ -19,10 +19,11 @@ dist # project .apidoc.yaml .apidoc.yml -/.vscode apidoc.json apidoc.yaml apidoc.xml .vscode .idea + +.testdata diff --git a/CHANGELOG.md b/CHANGELOG.md index 850941a7..123c170c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,14 @@ # CHANGELOG -## [Unreleased] +## [v5.2.1] + +### Changed + +- favicon 现在只支持 SVG 格式的图片; + +### Fixed + +- 修正 Pack 可能将二进制等文件进行打包的错误; ## [v5.2.0] diff --git a/apidoc.go b/apidoc.go index b1b5f6b2..794e01c3 100644 --- a/apidoc.go +++ b/apidoc.go @@ -106,7 +106,7 @@ func Pack(h *message.Handler, url string, contentType, pkgName, varName, path st contentType = http.DetectContentType(data) } - return static.Pack("./docs", pkgName, varName, path, t, nil, &static.FileInfo{ + return static.Pack("./docs", pkgName, varName, path, t, &static.FileInfo{ Name: url, Content: data, ContentType: contentType, diff --git a/config.go b/config.go index e42615d3..025a39cb 100644 --- a/config.go +++ b/config.go @@ -48,7 +48,7 @@ type Config struct { // LoadConfig 加载指定目录下的配置文件 // -// 所有的错误信息会输出到 h +// 所有的错误信息会输出到 h,在出错时,会返回 nil func LoadConfig(h *message.Handler, wd string) *Config { for _, filename := range vars.AllowConfigFilenames { p := filepath.Join(wd, filename) diff --git a/config_test.go b/config_test.go index 8f7855b0..60907474 100644 --- a/config_test.go +++ b/config_test.go @@ -5,7 +5,6 @@ package apidoc import ( "bytes" "path/filepath" - "strconv" "testing" "time" @@ -14,15 +13,40 @@ import ( "github.com/caixw/apidoc/v5/input" "github.com/caixw/apidoc/v5/internal/vars" "github.com/caixw/apidoc/v5/message" + "github.com/caixw/apidoc/v5/static" ) -func buildMessageHandle() (*bytes.Buffer, message.HandlerFunc) { - buf := new(bytes.Buffer) - - return buf, func(msg *message.Message) { - buf.WriteString(strconv.Itoa(int(msg.Type))) - buf.WriteString(msg.Message) +func buildMessageHandle() (erro, succ *bytes.Buffer, h *message.Handler) { + erro = new(bytes.Buffer) + succ = new(bytes.Buffer) + + f := func(msg *message.Message) { + switch msg.Type { + case message.Erro: + erro.WriteString(msg.Message) + default: + succ.WriteString(msg.Message) + } } + + return erro, succ, message.NewHandler(f) +} + +func TestLoadConfig(t *testing.T) { + a := assert.New(t) + + erro, succ, h := buildMessageHandle() + cfg := LoadConfig(h, "./") + a.NotNil(cfg). + Empty(erro.String()) + + erro, succ, h = buildMessageHandle() + cfg = LoadConfig(h, "./docs") // 不存在 apidoc 的配置文件 + + h.Stop() + a.Nil(cfg). + NotEmpty(erro.String()). + Empty(succ.String()) } func TestLoadFile(t *testing.T) { @@ -42,9 +66,9 @@ func TestDetect_Load(t *testing.T) { a.NotError(err).NotEmpty(wd) a.NotError(Detect(wd, true)) - out, f := buildMessageHandle() - cfg := LoadConfig(message.NewHandler(f), wd) - a.Empty(out.String()).NotNil(cfg) + erro, _, h := buildMessageHandle() + cfg := LoadConfig(h, wd) + a.Empty(erro.String()).NotNil(cfg) a.Equal(cfg.Version, vars.Version()). Equal(cfg.Inputs[0].Lang, "go") @@ -78,21 +102,55 @@ func TestConfig_sanitize(t *testing.T) { Equal(err.Field, "output") } +func TestConfig_Test(t *testing.T) { + a := assert.New(t) + + erro, succ, h := buildMessageHandle() + cfg := LoadConfig(h, "./docs/example") + a.NotNil(cfg) + cfg.Test() + + h.Stop() + a.Empty(erro.String()). + NotEmpty(succ.String()) // 有成功提示 +} + +func TestConfig_Pack(t *testing.T) { + a := assert.New(t) + + erro, succ, h := buildMessageHandle() + cfg := LoadConfig(h, "./docs/example") + a.NotNil(cfg) + cfg.Pack("testdata", "Data", "./.testdata", "apidoc.xml", "application/xml", static.TypeAll) + + h.Stop() + a.Empty(erro.String()). + Empty(succ.String()) +} + func TestConfig_Do(t *testing.T) { a := assert.New(t) - out, f := buildMessageHandle() - h := message.NewHandler(f) - LoadConfig(h, "./docs/example").Do(time.Now()) - a.Empty(out.String()) + erro, succ, h := buildMessageHandle() + cfg := LoadConfig(h, "./docs/example") + a.NotNil(cfg) + cfg.Do(time.Now()) + + h.Stop() + a.NotEmpty(succ.String()). // 有成功提示 + Empty(erro.String()) } func TestConfig_Buffer(t *testing.T) { a := assert.New(t) - out, f := buildMessageHandle() - h := message.NewHandler(f) - buf := LoadConfig(h, "./docs/example").Buffer() - a.Empty(out.String()). + erro, succ, h := buildMessageHandle() + cfg := LoadConfig(h, "./docs/example") + a.NotNil(cfg) + + buf := cfg.Buffer() + h.Stop() + a.Empty(erro.String()). + Empty(succ.String()). True(buf.Len() > 0) } diff --git a/docs/example/.apidoc.yaml b/docs/example/.apidoc.yaml index f4ec2640..5460b4a2 100755 --- a/docs/example/.apidoc.yaml +++ b/docs/example/.apidoc.yaml @@ -1,4 +1,4 @@ -version: 5.0.0 +version: 5.2.0 inputs: - lang: c++ dir: . diff --git a/docs/example/index.xml b/docs/example/index.xml index e16a5bac..d90e3947 100755 --- a/docs/example/index.xml +++ b/docs/example/index.xml @@ -1,7 +1,7 @@ - + 示例文档

用于描述整个文档的相关内容,只能出现一次。

文档的版本 内容的本地化 ID,比如 zh-hans 等。 - 图标 + 图标,默认采用官网的 https://apidoc.tools/icon.svg,同时作用于 favicon 和 logo,只支持 SVG 格式。 文档的生成时间 文档的标题 文档的整体介绍,可以是使用 HTML 内容。 diff --git a/docs/index.xsl b/docs/index.xsl index f6fd1df0..7c3fa42d 100644 --- a/docs/index.xsl +++ b/docs/index.xsl @@ -32,7 +32,8 @@ - + + diff --git a/docs/index.zh-hant.xml b/docs/index.zh-hant.xml index 72af14ec..da5f0b88 100644 --- a/docs/index.zh-hant.xml +++ b/docs/index.zh-hant.xml @@ -121,7 +121,7 @@

用於描述整個文檔的相關內容,只能出現壹次。

文檔的版本 內容的本地化 ID,比如 zh-hans 等。 - 圖標 + 圖標,默認采用官網的 https://apidoc.tools/icon.svg,同時作用於 favicon 和 logo,只支持 SVG 格式。 文檔的生成時間 文檔的標題 文檔的整體介紹,可以是使用 HTML 內容。 diff --git a/docs/v5/apidoc.xsl b/docs/v5/apidoc.xsl index 3db15837..0cb7499f 100644 --- a/docs/v5/apidoc.xsl +++ b/docs/v5/apidoc.xsl @@ -17,7 +17,8 @@ - + + @@ -509,7 +510,7 @@ - + diff --git a/internal/vars/version.go b/internal/vars/version.go index 52264a19..6d3903d6 100644 --- a/internal/vars/version.go +++ b/internal/vars/version.go @@ -8,7 +8,7 @@ import "strings" // // 遵守 https://semver.org/lang/zh-CN/ 规则。 // 程序不兼容或是文档格式不兼容时,需要提升主版本号。 -const version = "5.2.0" +const version = "5.2.1" var ( fullVersion = version diff --git a/static/pack.go b/static/pack.go index 215cd863..865bb3b4 100644 --- a/static/pack.go +++ b/static/pack.go @@ -3,25 +3,24 @@ package static import ( - "bufio" "bytes" "io/ioutil" "net/http" "os" "path/filepath" - "strings" - "unicode" "github.com/issue9/utils" - - "github.com/caixw/apidoc/v5/internal/locale" - "github.com/caixw/apidoc/v5/message" ) -const goModPath = "../go.mod" +const modulePath = "github.com/caixw/apidoc/v5/static" const header = "// 当前文件由工具自动生成,请勿手动修改!\n\n" +var allowPackExts = []string{ + ".xml", ".xsl", ".svg", + ".css", ".js", ".html", ".htm", +} + // FileInfo 被打包文件的信息 type FileInfo struct { // 相对于打包根目录的地址,同时也会被作为路由地址 @@ -39,6 +38,8 @@ type FileInfo struct { // path 内容保存的文件名; // t 打包的文件类型,如果为 TypeNone,则只打包 addTo 的内容; // addTo 追加的打包内容; +// +// NOTE: 隐藏文件不会被打包 func Pack(root, pkgName, varName, path string, t Type, addTo ...*FileInfo) error { fis, err := getFileInfos(root, t) if err != nil { @@ -58,11 +59,7 @@ func Pack(root, pkgName, varName, path string, t Type, addTo ...*FileInfo) error ws("package ", pkgName, "\n\n") - goMod, err := getPkgPath(goModPath) - if err != nil { - return err - } - ws("import \"", goMod+"/static", "\"\n\n") + ws("import \"", modulePath, "\"\n\n") ws("var ", varName, "= []*static.FileInfo{") for _, info := range fis { @@ -82,24 +79,25 @@ func getFileInfos(root string, t Type) ([]*FileInfo, error) { return nil, nil } - paths := []string{} + var paths []string walk := func(path string, info os.FileInfo, err error) error { if err != nil { return err } - if info.IsDir() { + // 过滤各类未知的隐藏文件 + if info.IsDir() || !isAllowPackFile(filepath.Ext(info.Name())) { return nil } - relpath, err := filepath.Rel(root, path) + relPath, err := filepath.Rel(root, path) if err != nil { return err } - if t != TypeStylesheet || isStylesheetFile(relpath) { - paths = append(paths, relpath) + if t != TypeStylesheet || isStylesheetFile(relPath) { + paths = append(paths, relPath) } return nil @@ -144,30 +142,11 @@ func dump(buf *bytes.Buffer, file *FileInfo) (err error) { return err } -const modulePrefix = "module" - -// 分析 go.mod 文件,获取其中的 module 值 -func getPkgPath(path string) (string, error) { - file, err := os.Open(path) - if err != nil { - return "", err - } - - s := bufio.NewScanner(bufio.NewReader(file)) - s.Split(bufio.ScanLines) - for s.Scan() { - line := strings.TrimSpace(s.Text()) - if !strings.HasPrefix(line, modulePrefix) { - continue +func isAllowPackFile(ext string) bool { + for _, e := range allowPackExts { + if e == ext { + return true } - - line = line[len(modulePrefix):] - if line == "" || !unicode.IsSpace(rune(line[0])) { - continue - } - - return strings.TrimSpace(line), nil } - - return "", message.NewLocaleError(goModPath, "", 0, locale.ErrInvalidFormat) + return false } diff --git a/static/pack_test.go b/static/pack_test.go index 8ded8bf1..724956a1 100644 --- a/static/pack_test.go +++ b/static/pack_test.go @@ -3,12 +3,24 @@ package static import ( + "path" "path/filepath" + "strings" "testing" "github.com/issue9/assert" + + "github.com/caixw/apidoc/v5/internal/vars" ) +// 保证 modulePath 的值正确性 +func TestModulePath(t *testing.T) { + a := assert.New(t) + + suffix := path.Join(vars.DocVersion(), "static") + a.True(strings.HasSuffix(modulePath, suffix)) +} + func TestPack(t *testing.T) { a := assert.New(t) a.NotError(Pack("./testdir", "testdata", "Data", "./testdata/testdata.go", TypeAll)) @@ -19,14 +31,14 @@ func TestGetFileInfos(t *testing.T) { info, err := getFileInfos("./testdir", TypeAll) a.NotError(err).NotNil(info) - a.Equal(6, len(info)) + a.Equal(3, len(info)) - // 采有绝对路径 + // 采用绝对路径 dir, err := filepath.Abs("./testdir") a.NotError(err).NotEmpty(dir) info, err = getFileInfos(dir, TypeAll) a.NotError(err).NotNil(info) - a.Equal(6, len(info)) + a.Equal(3, len(info)) } func TestGetFileInfos_TypeStylesheet(t *testing.T) { @@ -45,19 +57,3 @@ func TestGetFileInfos_TypeNone(t *testing.T) { a.NotError(err).Nil(info) a.Equal(0, len(info)) } - -func TestGetPkgPath(t *testing.T) { - a := assert.New(t) - - p, err := getPkgPath("") - a.Error(err).Empty(p) - - p, err = getPkgPath("./testdir/go.mod1") - a.NotError(err).Equal(p, "test/v6") - - p, err = getPkgPath("./testdir/go.mod2") - a.Error(err).Empty(p) - - p, err = getPkgPath("./testdir/go.mod3") - a.Error(err).Empty(p) -} diff --git a/static/static.go b/static/static.go index 3a5e2cff..38fabf61 100644 --- a/static/static.go +++ b/static/static.go @@ -13,20 +13,20 @@ import ( "github.com/caixw/apidoc/v5/internal/vars" ) -// Type 表示文件的类型 +// Type 表示对打包文件的分类 type Type int8 // 几种文件类型的定义 const ( - TypeNone = iota - TypeAll - TypeStylesheet + TypeNone Type = iota // 不包含任何文件 + TypeAll // 所有文件 + TypeStylesheet // 仅与 xsl 相关的文件 ) // 默认页面 const indexPage = "index.xml" -// 指定了 xml 文档所需的 xsl 内容。 +// 指定在 TypeStylesheet 下需要的文件列表。 // // 可以以前缀的方式指定,比如:v5/ 表示以 v5/ 开头的所有文件。 var styles = []string{ diff --git a/static/testdir/testdir1/file1 b/static/testdir/testdir1/file1.xml similarity index 100% rename from static/testdir/testdir1/file1 rename to static/testdir/testdir1/file1.xml diff --git a/static/testdir/testdir2/file2 b/static/testdir/testdir2/file2.xsl similarity index 100% rename from static/testdir/testdir2/file2 rename to static/testdir/testdir2/file2.xsl