hugo

Unnamed repository; edit this file 'description' to name the repository.

git clone git://git.shimmy1996.com/hugo.git
commit 953f215f32ada15700cdd7d65471f55d72833c5c
parent 8e2fd55923a4da38eb2ddda51dc1b96943be0c56
Author: Joe Mooring <joe.mooring@veriphor.com>
Date:   Sat,  4 Jun 2022 13:40:32 -0700

tpl/path: Add path.BaseName function

Closes #9973

Diffstat:
Mdocs/content/en/functions/path.Base.md | 2+-
Adocs/content/en/functions/path.BaseName.md | 24++++++++++++++++++++++++
Mdocs/content/en/functions/path.Clean.md | 3++-
Mdocs/content/en/functions/path.Dir.md | 2+-
Mdocs/content/en/functions/path.Ext.md | 2+-
Mdocs/content/en/functions/path.Join.md | 2+-
Mdocs/content/en/functions/path.Split.md | 2+-
Mtpl/path/path.go | 16++++++++++++++++
Mtpl/path/path_test.go | 30++++++++++++++++++++++++++++++
9 files changed, 77 insertions(+), 6 deletions(-)
diff --git a/docs/content/en/functions/path.Base.md b/docs/content/en/functions/path.Base.md
@@ -12,7 +12,7 @@ keywords: [path, base]
 signature: ["path.Base PATH"]
 workson: []
 hugoversion: "0.40"
-relatedfuncs: [path.Dir, path.Ext, path.Split]
+relatedfuncs: [path.BaseName, path.Clean, path.Dir, path.Ext, path.Join, path.Split]
 deprecated: false
 ---
 
diff --git a/docs/content/en/functions/path.BaseName.md b/docs/content/en/functions/path.BaseName.md
@@ -0,0 +1,24 @@
+---
+title: path.BaseName
+description: BaseName returns the last element of a path, removing the extension if present.
+date: 2022-06-04
+categories: [functions]
+menu:
+  docs:
+    parent: "functions"
+keywords: [path, base]
+signature: ["path.BaseName PATH"]
+relatedfuncs: [path.Base, path.Clean, path.Dir, path.Ext, path.Join, path.Split]
+deprecated: false
+---
+
+If `PATH` is empty, `.` is returned.
+
+**Note:** On Windows, `PATH` is converted to slash (`/`) separators.
+
+```go-html-template
+{{ path.BaseName "a/news.html" }} → "news"
+{{ path.BaseName "news.html" }} → "news"
+{{ path.BaseName "a/b/c" }} → "c"
+{{ path.BaseName "/x/y/z/" }} → "z"
+```
diff --git a/docs/content/en/functions/path.Clean.md b/docs/content/en/functions/path.Clean.md
@@ -8,8 +8,9 @@ categories: [functions]
 menu:
   docs:
     parent: "functions"
-keywords: [path]
+keywords: [path, clean]
 signature: ["path.Clean PATH"]
+relatedfuncs: [path.Base, path.BaseName, path.Dir, path.Ext, path.Join, path.Split]
 ---
 
 `path.Clean` replaces path separators with slashes (`/`) and removes extraneous separators, including trailing separators.
diff --git a/docs/content/en/functions/path.Dir.md b/docs/content/en/functions/path.Dir.md
@@ -12,7 +12,7 @@ keywords: [path, dir]
 signature: ["path.Dir PATH"]
 workson: []
 hugoversion: "0.40"
-relatedfuncs: [path.Base, path.Ext, path.Split]
+relatedfuncs: [path.Base, path.BaseName, path.Clean, path.Ext, path.Join, path.Split]
 deprecated: false
 ---
 
diff --git a/docs/content/en/functions/path.Ext.md b/docs/content/en/functions/path.Ext.md
@@ -12,7 +12,7 @@ keywords: [path, ext, extension]
 signature: ["path.Ext PATH"]
 workson: []
 hugoversion: "0.40"
-relatedfuncs: [path.Base, path.Dir, path.Split]
+relatedfuncs: [path.Base, path.BaseName, path.Clean, path.Dir, path.Join, path.Split]
 deprecated: false
 ---
 
diff --git a/docs/content/en/functions/path.Join.md b/docs/content/en/functions/path.Join.md
@@ -12,7 +12,7 @@ keywords: [path, join]
 signature: ["path.Join ELEMENT..."]
 workson: []
 hugoversion: "0.39"
-relatedfuncs: [path.Split]
+relatedfuncs: [path.Base, path.BaseName, path.Clean, path.Dir, path.Ext, path.Split]
 deprecated: false
 ---
 
diff --git a/docs/content/en/functions/path.Split.md b/docs/content/en/functions/path.Split.md
@@ -12,7 +12,7 @@ keywords: [path, split]
 signature: ["path.Split PATH"]
 workson: []
 hugoversion: "0.39"
-relatedfuncs: [path.Split]
+relatedfuncs: [path.Base, path.BaseName, path.Clean, path.Dir, path.Ext, path.Join]
 deprecated: false
 ---
 
diff --git a/tpl/path/path.go b/tpl/path/path.go
@@ -18,6 +18,7 @@ import (
 	"fmt"
 	_path "path"
 	"path/filepath"
+	"strings"
 
 	"github.com/gohugoio/hugo/deps"
 	"github.com/spf13/cast"
@@ -94,6 +95,21 @@ func (ns *Namespace) Base(path any) (string, error) {
 	return _path.Base(spath), nil
 }
 
+// BaseName returns the last element of path, removing the extension if present.
+// Trailing slashes are removed before extracting the last element.
+// If the path is empty, Base returns ".".
+// If the path consists entirely of slashes, Base returns "/".
+// The input path is passed into filepath.ToSlash converting any Windows slashes
+// to forward slashes.
+func (ns *Namespace) BaseName(path any) (string, error) {
+	spath, err := cast.ToStringE(path)
+	if err != nil {
+		return "", err
+	}
+	spath = filepath.ToSlash(spath)
+	return strings.TrimSuffix(_path.Base(spath), _path.Ext(spath)), nil
+}
+
 // Split splits path immediately following the final slash,
 // separating it into a directory and file name component.
 // If there is no slash in path, Split returns an empty dir and
diff --git a/tpl/path/path_test.go b/tpl/path/path_test.go
@@ -56,6 +56,36 @@ func TestBase(t *testing.T) {
 	}
 }
 
+func TestBaseName(t *testing.T) {
+	t.Parallel()
+	c := qt.New(t)
+
+	for _, test := range []struct {
+		path   any
+		expect any
+	}{
+		{filepath.FromSlash(`foo/bar.txt`), `bar`},
+		{filepath.FromSlash(`foo/bar/txt `), `txt `},
+		{filepath.FromSlash(`foo/bar.t`), `bar`},
+		{`foo.bar.txt`, `foo.bar`},
+		{`.x`, ``},
+		{``, `.`},
+		// errors
+		{tstNoStringer{}, false},
+	} {
+
+		result, err := ns.BaseName(test.path)
+
+		if b, ok := test.expect.(bool); ok && !b {
+			c.Assert(err, qt.Not(qt.IsNil))
+			continue
+		}
+
+		c.Assert(err, qt.IsNil)
+		c.Assert(result, qt.Equals, test.expect)
+	}
+}
+
 func TestDir(t *testing.T) {
 	t.Parallel()
 	c := qt.New(t)