Releases: PataphysicalSociety/soupault
5.2.0 release
Announcement: https://soupault.net/blog/soupault-5.2.0-release/
New features
New Lua API functions
Sys.strip_extension(str)for stripping only the last extension
from a file name.
Bug fixes
- Fixed a regression that caused errors when saving
pages generated by index processors
(GitHub issue #85, discovery by Yiming Xiang). - Fixed incorrect formatting of the log message
for plugins that are missing file/lua_source options.
5.1.0 release
5.1.0 (2025-06-17)
Release blog post: https://soupault.app/blog/soupault-5.1.0-release/
New features
- Target directories for page files are now guaranteed to exist when soupault starts processing widgets,
so that widgets can create new asset files in page directories. - Global data for Lua plugins is now reintroduced: the startup hook can add values to the
global_datatable
and all Lua plugins and hooks can retrieve them using the newPlugin.get_global_data(name)function.
Plugins and hooks cannot modify the global data, so it doesn't create a consistency problem. site_indexandindex_entryvariables are now available in the template environment of theelement_templatewidget.- New index field option
strip_tagsfor people who want to strip HTML tags from particular index fields.
New Lua API functions
There are now functions for case conversion. They only affect the case of ASCII characters,
Unicode characters are ignored because handling their case requires knowing their language.
String.lowercase_ascii(string)String.uppercase_ascii(string)String.capitalize_ascii(string)String.uncapitalize_ascii(string)
Behavior changes
- Index extraction is now always enabled in generator mode.
index.indexoption no longer has any effect.
5.0.0 release
Release post: https://soupault.app/blog/soupault-5.0.0-release/
Removed features
index.index_firstis no longer a valid configuration option.
If you use it, simply remove it from the config — index data is now always available to all pages
(more on that later).settings.process_pages_firstis no longer a valid option — there is no sequential page processing anymore
so the concept of "processing specific pages first" no longer applies.
It should have no effect on any websites.- There is no separate
post-savehook anymore. If you used it, move the code to thesavehook instead. - There is no way to make the
post-indexhook tell soupault to ignore a page
(previously that was possble to do by setting the undocumentedingore_pagevariable). persistent_dataandglobal_datavariables are no longer available in the plugin environment.
If you want to share data, place it in the page or in the index entry.
New features
Built-in Markdown support
Soupault now includes a built-in Markdown processor (compatible with CommonMark and popular extensions,
based on CMarkit).
Support for built-in Markdown needs to be explicitly enabled in the config:
[settings]
markdown_extensions = ["md"]If enabled, it takes priority over page preprocessors — if "md" (or another extension)
is in settings.markdown_extensions, soupault does not try to look up a preprocessor
and processed it using the built-in implementation right away.
element_template widget
The new element_template widget replaces an element with an HTML snippet produced by rendering
a template using attributed and content of the source element.
Its goal is to allow users to easily create "shortcodes" without writing Lua code.
os_family option for exec and preprocess_element widgets
Those widgets now support a new os_family option to limit them to only one OS family
and use different commands for those OSes. At the moment, it can be "unix" (any UNIX-like OS)
or "windows" (Microsoft Windows or compatibles, such as ReactOS).
New plugin functions
Table.sort(func, table)— sorts a table with numeric indices usingfuncfor value comparison.String.to_integer— converts a string to an integer (returnsnilif conversion fails).String.to_float— a clearer-named alias forString.to_number.
Deprecated options
settings.strictand--strict <true|false>options are not deprecated
and will be removed in future releases.
All built-in errors are now treated as fatal and cannot be ignored.
Behavior changes
- Site index is now available to all pages by default.
- If a website requires more RAM to process than the machine has available,
soupault now can run out or memory, like most other static site generators
(that's the compromise required to make index data available to all pages). - Metadata extraction now occurs as early as possible — just after all widgets listed in
index.extract_after_widgets. - Caching is now enabled by default.
Bug fixes
- Clean URL in rendered index views now include trailing slashes,
which reduces the number of unncessessary redirects (GitHub issue #81).
The old behavior can be restored withsettings.clean_url_trailing_slash = false. - Lists of selectors are now consistently supported in all built-in widgets (GitHub issue #77).
- If the
pre-processhook modifies the path of a leaf bundle,
its child asset paths are adjusted accordingly (GitHub issue #63). soupault --show-effective-confignow correctly updates values
that are overridden by commmand line options or internal processes.
4.11.0 release
Release post: https://soupault.app/blog/soupault-4.11.0-release/
New features
- It's now possible to use
:has()selector in options that accept CSS selectors (implemented in lambdasoup 1.1.0)
New plugin API functions
HTML.is_text(e)— checks if an HTML element tree node is a text node. Thanks to @jbhoot!
Bug fixes
HTML.is_document(e)now correctly returns true for values created withHTML.parse()andHTML.create_document().- Namespaces are now correctly preserved in HTML element attribute names (implemented in lambdasoup 1.1.1).
4.10.0 release
Release blog post: https://soupault.app/blog/soupault-4.10.0-release/
New features
Deleting only elements that do not have certain children
The delete_element widget has a new option: when_no_child.
For example, suppose you have footnotes container in your template that looks like this:
<div id="footnotes"> <hr class="footnotes-separator"> </div>. If a page has footnotes,
it would contain something like <p class="footnote">.... If not, it would only have the <hr> element in it.
Deleting it from pages that don't have any footnotes cannot be done with only_if_empty
because the container has that auxilliary element in it.
However, with the new option you can make the widget delete the container
only if nothing inside it matches the selector of actual footnotes.
[widgets.clean-up-footnote-containers]
after = "footnotes"
widget = "delete_element"
selector = "div#footnotes"
when_no_child = "p.footnote"Bug fixes
- Complete HTML pages work correctly in generator mode again (report by Auguste Baum)
- Config files with multiline strings and Windows newlines (CRLF) no longer cause parse errors
(report by Bohdan Kolesnikov) - Configs that consist of a single comment line followed by EOF no longer cause parse errors
(found thanks to the TOML test suite v1.4.0)
4.9.0
Release blog post: https://soupault.app/blog/soupault-4.9.0-release
New features and improvements
- New
startuphook that runs before soupault processes any pages and can modify theglobal_datavariable.
New plugin API functions
New Digest module offers functions for calculating cryptographic hash sums of strings.
All those functions return hex digests.
Digest.md5(str)Digest.sha1(str)Digest.sha256(str)Digest.sha512(str)Digest.blake2s(str)Digest.blake2b(str)
Other new functions:
Sys.basename_url(str)andSys.dirname_url(str)— aliases forSys.basename_unixandSys.dirname_unix, respectively.
4.8.0 release
Full announcement: https://soupault.app/blog/soupault-4.8.0-release (includes important information about future plans)
4.8.0 (2024-01-12)
New features and improvements
site_indexvariable is now available to the post-build hook.index_entryvariable (the complete site index entry for the current page) is now available to post-index, save and post-save hooks and to Lua index processors.- New options for ignoring certain paths in the sire dir:
settings.ignore_path_regexesandsettings.ignore_directories.
New plugin API functions
HTML.inner_text()— returns the text nodes from inside a node, stripped of all HTML tags.
Bug fixes
- In generator mode, page files are parsed as HTML fragments so
<style>tags and similar no longer call issues
with duplicate<body>tag inserted in the page (#58, report by Delan Azabani).
4.7.0 release
Release blog post: https://soupault.app/blog/soupault-4.7.0-release
New features and improvements
- New
max_itemsoption in index views allows limiting the number of displayed items. - New
settings.page_character_encodingoption for correctly loading pages in encodings other than ASCII and UTF-8. - New
post-buildhook that runs when all pages are processed and soupault is about to terminate. - Info logs to indicate the first and second passes in the
index_first = truemode. - Debug logs now tell why a page is included or excluded from an index view:
"page_included checks for %s: regex=%b, page=%b, section=%b"
New plugin API functions
CSV.from_string(str)— parses CSV data and returns it as a list (i.e., an int-indexed table) of lists.CSV.unsafe_from_string(str)— likeCSV.from_stringbut returnsnilon errors instead or raising an exception.CSV.to_list_of_tables(csv_data)— converts CSV data with a header returned byCSV.from_stringinto a list of string-indexed tables for easy rendering.HTML.swap(l, r)— swaps two elements in an element tree.HTML.wrap(node, elem)— wrapsnodeinelem.- New
global_datahash table for sharing data between plugins. - New
soupault_passplugin environment variable (0 whenindex_first = false, 1 and 2 for the first and the second pass respectively when it's true).
Bug fixes
- Fixed an unhandled exception on index entry sorting failures when
sort_strict = trueandsort_byis unspecified. - Fixed a typo in the comments of the config generated by
soupault --init(s/ULRs/URLs/).
Misc
New state record now holds both the settings record and the TOML config datastructure,
plus the new global_data and soupault_pass variables, and can be easily extended to support global state new variables.
Official binaries are now available for Linux on ARM64.
4.6.0 release
Release post: https://soupault.app/blog/soupault-4.6.0-release/
New features and improvements
New plugin API functions
Sys.getenv(name, default_value)function (default_valueis optional).String.ends_with(string, suffix).String.is_valid_utf8(string)andString.is_valid_ascii(string)functions.Table.length(table)— returns the number of items in a table.Table.for_all(func, table)— checks if boolean functionfuncis true for all items in a table.Table.for_any(func, table)— checks if boolean functionfuncis true for at least one item in a table.Table.is_empty(t)— returns true ifthas no items in it.Table.copy(t)— returns a copy of the tablet.HTML.is_empty(e)— returns true ifehas zero child nodes.HTML.is_root(e)— returns true ifehas no parent node.HTML.is_document(e)— returns true ifeis a soup (document) node rather than an element or a text.Value.is_html(v)— returns true isvis an HTML document or node.
Bug fixes
- Fixed an unhandled OTOML exception when loading configs with duplicate key names (such issues generate proper parse errors now).
4.5.0 release
Full announcement: https://soupault.app/blog/soupault-4.5.0-release
New features and improvements
--no-cachingoption allows the user to disable caching even ifsettings.cachingis true in the config.- [Plugin API] New
HTML.prepend_root(node, child)function for inserting new nodes in HTML documents before all existing nodes. - The name of the Lua index processor file and the index view that calls it are displayed in the logs now.
- Clearer breadcrumb template parse error message (mentions Jingoo now).
Bug fixes
soupault --versioncorrectly prints a trailing newline again.