2542 Commits

Author SHA1 Message Date
Bjørn Erik Pedersen 7b5199fdef all: Run modernize -fix ./... 2026-08-20 21:56:40 +02:00
Bjørn Erik Pedersen e31ff547d2 Upgrade to Go 1.27
Closes #15228
2026-08-20 20:23:18 +02:00
Bjørn Erik Pedersen 8405b802cf tpl: Improve the return keyword in templates
Replace the partial return template rewriting with a sentinel error
trapped in the template executor:

* return now works in any template, not just partials.
* return can be used anywhere in the template, e.g. inside if/range;
  it stops execution of the current template, so a bare return in a
  block or template include ends just that template.
* {{ return <value> }} sets the return value of the enclosing partial;
  using it outside a partial is now an error (it was silently ignored).

The fork changes are limited to hugo_template.go plus one mechanical
rename (walkTemplate -> walkTemplateOld) mirrored in the fork script.

Closes #15212

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-19 16:21:11 +02:00
Bjørn Erik Pedersen 49dceb19f5 hugolib: Fix slice bounds panic when deleting multiple nodes at same path
The contentNodes cases in Delete/DeleteFunc spliced the slice inside a
forward range loop, panicking when a second deletion hit the last index,
and the shrunken slice was never written back to the tree. Let the
Shifter return the updated node and re-insert it on partial deletes.

Fixes #15207

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-15 20:42:57 +02:00
Joe Mooring 5e7099256e hugolib: Fix ReadingTime and FuzzyWordCount calculations
Closes #15206
2026-08-15 20:41:03 +02:00
Bjørn Erik Pedersen a808f6e40d Fix server errors when deleting static files or directories
Fixes #15174
2026-08-08 18:08:03 +02:00
Bjørn Erik Pedersen 70db201ed4 Add importContext option to css.Build, js.Build, css.Sass and css.TailwindCSS
This allows @import statements to be resolved in a set of user provided resources (e.g. from resources.FromString or css.ChromaStyles) before the assets filesystem.

The option also applies to css.PostCSS via the shared import inlining, and css.Sass requires the dartsass transpiler. The import context is part of the transformation cache key.

Fixes #15103

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-08-03 21:20:06 +02:00
Bjørn Erik Pedersen 8a468df065 Remove some old deprecations 2026-07-29 20:48:47 +02:00
Bjørn Erik Pedersen 6bf15241a1 Fix panic on server atomic save edits on MacOS
An atomic save (write temp file, rename into place) unlinks the inode the
watcher holds, so kqueue reports Remove for a file that's still on disk.
That took the delete branch and wiped the entire taxonomy subtree; the
following assemble then panicked in createMissingTaxonomies, where the
shifting tree.Get hit a not yet assembled *pageMetaSource.

Treat Remove of a path that still exists as an update, and use the
non-shifting GetRaw when checking for the auto created taxonomy node.

Fixes #15130

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-26 14:00:32 +02:00
Bjørn Erik Pedersen d83ce27ae0 tpl/tplimpl: Support sub paths in layouts passed to .Render
E.g. {{ .Render "foo/mylayout" }} matches mylayout templates in
<dir>/foo for every dir from the page's layout path up to the layouts root.

Closes #15056

Co-authored-by: Joe Mooring <joe.mooring@veriphor.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 20:14:32 +02:00
Bjørn Erik Pedersen 5a5f4a5495 all: Rewrite deprecated constructs in tests 2026-07-04 23:10:26 +02:00
sjh9714 499794d19e create: Keep new content placeholders buildable
Fixes #15078
2026-07-04 14:31:54 +02:00
hexbinoct feb3d494b9 hugolib: Use the output format's suffix for alias paths
Alias generation hardcoded "index.html" and only recognized a ".html"
suffix, so an alias with an explicit ".htm" extension (or any other
suffix configured for the html media type) was written to the wrong
path. For example "d.htm" produced the directory "d.htm/index.html"
instead of the file "d.htm".

Build the alias file name from the output format's BaseName and the
media type's first suffix, and detect an explicit file by matching the
alias extension against the configured suffixes. The same check now
drives the uglyURLs case in Aliases.

Fixes #15066
2026-07-04 14:31:34 +02:00
Joe Mooring e46d37a984 tpl/tplimpl: Make template name lookup case-insensitive
Closes #15057

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-28 15:36:29 +02:00
Joe Mooring fe06735214 hugolib: Return error from .Render when template not found
Closes #15052
2026-06-25 12:09:52 +02:00
Joe Mooring f013346667 hugolib: Fix page/section name collision regression
Fixes #15046

When a regular page (e.g. content/s1.md) and a section (content/s1/)
share the same tree key, the assembler must not overwrite the real page
with a synthetic section. Restore the existence guard that was present
in v0.152.2.

The fix checks if a node already exists at the section key before
inserting a synthetic section during root section creation.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 16:20:34 +02:00
Joe Mooring 147f605f7d markup: Standardize behavior when external converters are missing
Closes #14222
2026-06-13 20:19:47 +02:00
Bjørn Erik Pedersen 95e5e9f4ab Fix multi --renderSegments merge behavior
Fixes #15024
2026-06-11 15:25:43 +02:00
anupamojha-eng 1d018ef857 pagesfromdata: Use relative path for content adapter template metrics
Fixes #14999
2026-06-08 15:56:47 +02:00
Bjørn Erik Pedersen 781fabf4e4 all: Run go fix ./... 2026-06-07 21:20:40 +02:00
Bjørn Erik Pedersen b89e7fe675 page: Add IsBranch and deprecate IsNode
IsNode's meaning was murky. Add IsBranch, defined as the set of branch
node kinds (home, section, taxonomy, term), and make IsNode a deprecated
alias for it.

Fixes #11574

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-05 16:18:57 +02:00
Bjørn Erik Pedersen 0f440460c8 tpl/tplimpl/embedded: Prevent leading newline in sitemap template
Fixes #14977
2026-06-04 11:03:03 +02:00
Bjørn Erik Pedersen 4e17421ec2 images: Recover from memory alloc errors in WASM image processors
Fixes #14985
2026-06-04 11:01:49 +02:00
Joe Mooring ca68936d61 all: Adjust tests for deprecated link and image render hook settings 2026-06-01 15:52:34 +02:00
Bjørn Erik Pedersen e41a06447d Disallow HTML content by default
For security reasons. Enable in security config, e.g.:

```toml
[security]
allowContent = ['.*']
```
2026-05-26 13:57:12 +02:00
Bjørn Erik Pedersen 90d9f812b2 Add image processing support for AVIF
The encode/decode is implemented in a WebAssembly module built from a
small C wrapper around libavif. Bundled libraries (statically linked,
compiled with the WASI SDK):

* libavif v1.4.1 (container + codec glue)
* libaom v3.14.1 (AV1 encoder + decoder)
* dav1d 1.5.3 (AV1 decoder)
* libyuv (Chromium pin) for color conversion
* parson for JSON message passing across the wasm boundary

HDR handling on the encoder:

* SDR images are written as BT.709 / sRGB / BT.601 (8-bit).
* 10-bit and up are written as BT.2020 primaries with PQ (SMPTE
  ST 2084) transfer and BT.2020-NCL matrix coefficients, signalled
  via CICP.
* Adobe-style SDR+gainmap inputs (e.g. Lightroom HDR exports) are
  baked into a single true-HDR image in BT.2020/PQ at 10-bit, with
  the CLLI (Content Light Level Information) box carried through so
  HDR-capable clients can tone-map correctly.

Limitations:

* Animated input (animated WebP/GIF) is collapsed to its first frame
  when re-encoded as AVIF; animated AVIF output is not yet supported.

Fixes #7837
2026-05-26 12:13:53 +02:00
Bjørn Erik Pedersen df5421918a hugolib: Fix Page.GitInfo for modules with go.mod in a repo subdirectory
Map content files using their path relative to the git repo root by
prepending the module's Origin.Subdir to the lookup key.

Fixes #14942
2026-05-26 00:28:22 +02:00
Bjørn Erik Pedersen aeb9a5cc02 hugolib: Merge existing hugo_stats.json when renderSegments is set
With renderSegments only a subset of pages is rendered, so the resulting
hugo_stats.json would no longer contain elements from the excluded pages,
causing tools like Tailwind to strip classes that are actually in use.

Fixes #14939
2026-05-25 17:00:52 +02:00
Bjørn Erik Pedersen c4bbc2805c all: Replace RWMutex struct caches with ConcurrentMap 2026-05-24 15:29:47 +02:00
Joe Mooring d8c70218b7 tpl/tplimpl: Consolidate and improve embedded template integration tests
Closes #14932
2026-05-24 15:29:33 +02:00
Bjørn Erik Pedersen 4ed7600fd6 hugolib: Use AllTranslated in IsTranslated
Which makes it faster:

```
                           │ benchcmp.bench │   feat-speedupistranslated.bench    │
                           │     sec/op     │    sec/op     vs base               │
IsTranslatedOneLanguage-10     996.2n ± ∞ ¹   685.6n ± ∞ ¹  -31.18% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95

                           │ benchcmp.bench │   feat-speedupistranslated.bench   │
                           │      B/op      │    B/op      vs base               │
IsTranslatedOneLanguage-10      832.0 ± ∞ ¹   536.0 ± ∞ ¹  -35.58% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95

                           │ benchcmp.bench │   feat-speedupistranslated.bench   │
                           │   allocs/op    │  allocs/op   vs base               │
IsTranslatedOneLanguage-10      18.00 ± ∞ ¹   13.00 ± ∞ ¹  -27.78% (p=0.029 n=4)
¹ need >= 6 samples for confidence interval at level 0.95
````
2026-05-22 14:11:50 +02:00
Bjørn Erik Pedersen 6475d308ec tpl: Use AllTranslations in sitemap template
Closes #14912
Closes #14917
2026-05-21 19:44:23 +02:00
Joe Mooring 5d51b82a7e resources: Fix the :counter placeholder
Closes #14921

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-21 09:45:11 +02:00
Alexandre Vaz 2f361a8e25 hugolib: Allow empty params front matter
Treat an empty front matter params key as an empty params map instead of failing while decoding page metadata.

Fixes #14886
2026-05-17 19:59:44 +02:00
Joe Mooring 5559263326 common/hmaps: Merge slice-valued module config into site config
When a module provides a config key whose value is a slice (e.g.
cascade or permalinks), and the site config declares the same key as a
map with only a merge strategy marker (_merge = 'deep'), the types do
not match and Params.merge silently dropped the module's value, leaving
the site with no effective cascade or permalink config from the module.

Fix Params.merge so that when the destination value is an empty Params
(IsZero — only the _merge key is present) and the source value is a
non-Params type, the source value is used provided the user-declared
merge strategy is not 'none'. This honours the explicit _merge
directive regardless of the surrounding shallow-merge context.

Closes #13869

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-15 19:50:42 +02:00
Bjørn Erik Pedersen ba5d812673 config: Allow repeating the root key in /config files
If a non-default-name file in the config folder parses to a map with a
single top-level key matching the file's basename, unwrap it. This lets
TOML/YAML express slice-typed roots (cascade, permalinks), which can't
have a headless top-level array, and also lets users copy-paste docs
examples that include the root container (e.g. params.yaml with a
top-level params: block).

Fixes #12899
Fixes #14882

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-13 18:22:01 +02:00
Bjørn Erik Pedersen 28147cb040 Fall back to hugo.buildDate in hugo.BuildDate() in non-vcs builds
Fixes #14862
2026-05-11 12:26:13 +02:00
Bjørn Erik Pedersen e51e761d9c css: Make css.Build's file-loader URLs absolute to web context root
When CSS imports assets via the file loader (fonts, images), the emitted
URLs were relative to the CSS output directory. That broke when the CSS
was inlined into HTML, since browsers then resolved the URLs against the
page rather than the CSS file.

Set esbuild's PublicPath to the CSS output directory joined with the
site base path so URLs work whether the CSS is published as a file or
inlined.

Fixes #14849
2026-05-10 19:08:08 +02:00
Bjørn Erik Pedersen 7011239205 hugolib: Don't warn about lang/kind/path coming from cascade.params
These keys are reserved at the top level of front matter, but are
legitimate user params under cascade.params. Only fire the deprecation
when the key was actually set at the top level of the original front
matter.

Fixes #14848
2026-05-09 11:54:20 +02:00
Joe Mooring 8920d56e95 hugolib: Do not render aliases if the page is not rendered
Closes #14807
2026-04-25 18:41:27 +02:00
Joe Mooring 633cc772e0 langs/i18n: Improve default content language fallback
The fallback order for translations is now:

1. Current language's locale (e.g., pt-BR → pt-br.toml)
2. Current language's key (e.g., pt → pt.toml)
3. Default language's locale (e.g., es-AR → es-ar.toml) ← new
4. Default language's key (e.g., es → es.toml)

Closes #14243

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 10:43:37 +02:00
Bjørn Erik Pedersen 90d8bf34ae Replace deprecated .Site.Sites/.Page.Sites with hugo.Sites intests 2026-04-24 19:02:46 +02:00
Bjørn Erik Pedersen 79f030be5b config/security: Add "! " negation to Whitelist, harden default http.urls
Whitelist now treats any pattern prefixed with "! " (the same negation
prefix used by hglob/predicate) as a deny rule. Deny matches take
precedence over allow, and a whitelist made up exclusively of deny
rules implicitly allows everything it does not deny.

The default security.http.urls now reads:

    urls = ['(?i)^https?://[a-z]', '! (?i)localhost', '! @']

i.e. allow URLs whose host starts with a letter (the common
"https://example.com" shape), deny anything that looks like localhost,
and deny URLs with userinfo to foil "http://user@127.0.0.1/" bypasses.
Public IP literals are collateral blocks; users who need them (or their
own private hosts) override security.http.urls as before, mixing allow
and deny rules with the same "! " prefix, e.g.

    [security.http]
    urls = ['.*', '! ^https?://evil\.example\.com']

Fixes #14792
2026-04-22 20:15:19 +02:00
Bjørn Erik Pedersen a54c398b93 Harden Node tool execution with --permission flag
Add security.node.permissions config to run Node tools (PostCSS, Babel,
TailwindCSS) under Node's permission model, restricting file system access
to the working directory by default.

The binary resolution is simplified to node_modules/.bin → PATH (npx removed).
For both locations, the actual JS entry point is resolved via symlinks (macOS/Linux)
or by parsing npm wrapper scripts (Windows .cmd), then executed as
"node --permission --allow-fs-read=<path> --allow-fs-write=<path> <script>".

Users can opt out by removing "node" from security.exec.allow.

Closes #7287
2026-04-22 15:47:34 +02:00
Bjørn Erik Pedersen 7574e35b40 Replace the concurrent map with an identical upstream version 2026-04-20 18:33:59 +02:00
Bjørn Erik Pedersen 017a7cd63a Add slice-based permalinks config with PageMatcher target
Closes #14744
Clses #4641

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 19:45:45 +02:00
Bjørn Erik Pedersen 8d6145f3c3 Fix filename dimension identifiers (_role_X_, _version_X_) to replace mount config
Filename identifiers for roles and versions were parsed but never applied
to the SitesMatrix. Now they replace the mount's configuration for that
dimension, matching how language identifiers already worked.

Fixes #14756

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 20:34:34 +02:00
Bjørn Erik Pedersen ce2a156a4e Add a more flexible filename identifier scheme that also allows setting roles and versions (#14754)
Fixes #14750
2026-04-15 16:44:19 +02:00
Bjørn Erik Pedersen 9747724222 Fix it so we never auto-fallback to page resources in other roles/versions
This is some logic that's left behind from when we had only one dimension (language) where the common case would be to have one resource set (e.g. an image) and many content translation.

After this commit:

* For sites matrix defined in the content filename (e.g. data.en.js) or in its mount definition, we may use that as a fallback for e.g. German languages if we don't find a better match.
* For content adapters, this is not relevant: Here you must be explicit about this.
* We never auto-fallback on resources from a role/version to another.
* When a page bundle spans multiple roles (e.g. via roles = "*"), we clone its resources to all roles so each gets role-specific paths.

Fixes #14749
Fixes #14752
2026-04-14 16:33:38 +02:00
Bjørn Erik Pedersen c48551677c Fix panic on edit of legacy mapped template names that's also a valid path in the new setup
This mapping was added in Hugo `v0.146.0`.

Fixes #14740
2026-04-08 13:19:45 +02:00