# 3.26.0 (2026-05-20)

 * Document that the sandbox doesn't protect against resource exhaustion
 * Document `template_from_string` caveats when used in a sandboxed environment
 * Add docs on `Markup` about the goal of this class in the context of a sandbox
 * Pre-escape HTML input on the `spaceless` filter
 * Pre-escape HTML input on `inline_css` and `inky_to_html` filters
 * Fix XSS by adjusting `is_safe` annotation on HTML-emitting filters
 * [Profiler] Escape template and profile names in `HtmlDumper`
 * Fix unbounded memoisation of `IntlDateFormatter` / `NumberFormatter`
 * Fix sandbox bypass in the "column" filter
 * Fix sandbox bypass in the `{% sandbox %}` tag when including a preloaded template
 * Fix sandbox bypass: PHP code injection via `{% use %}` template name
 * Fix sandbox bypass: PHP code injection via `_self` / import macro reference
 * Fix sandbox bypass in object destructuring assignment
 * Fix sandbox bypass: propagate `Source` to `checkArrow` for source-policy sandboxing
 * Encode single quotes as `\x27` in `Compiler::string()` as a defense-in-depth measure
 * Fix sandbox `__toString` bypasses
 * Add `Twig\Node\CoercesChildrenToStringInterface` to let nodes declare which of their child nodes will be string-coerced at runtime so the sandbox wraps them with a `__toString` check

# 3.25.0 (2026-05-17)

 * Add a `needs_is_sandboxed` option for filters, functions, and tests
 * Use deterministic suffixes for generated embed classes
 * Lazy-load `EscaperRuntime` in `EscaperExtension`

# 3.24.0 (2026-03-17)

 * Deprecate not implementing the `getOperatorTokens()` method in `ExpressionParserInterface` implementations
 * Deprecate passing a non-`AbstractExpression` node to `Twig\Node\Expression\Binary\MatchesBinary` constructor
 * Deprecate passing a non-`AbstractExpression` node to `Parser::setParent()`
 * Add support for renaming variables in object destructuring (`{name: userName} = user`)
 * Add `html_attr_relaxed` escaping strategy that preserves :, @, [, and ] for front-end framework attribute names
 * Add support for short-circuiting in null-safe operator chains
 * Add the `html_attr` function and `html_attr_merge` as well as `html_attr_type` filters

# 3.23.0 (2026-01-23)

 * Add `=` assignment operator (allows to set variables in expression or to replace the short-form of the set tag)
 * Add sequence, mapping, and object destructuring
 * Add `?.` null-safe operator
 * Add `===` and `!==` operators (equivalent to the `same as` and `not same as` tests)
 * Fix opcache preload warning for unlinked anonymous class
 * Fix spread operator behavior

# 3.22.2 (2025-12-14)

 * Fix "cycle" with non-countable ArrayAccess + Traversable objects
 * Use "getShareDir" as an indicator of Symfony version in Symfony bundle
 * Fix escaper compatibility with PHP 8.5

# 3.22.1 (2025-11-16)

 * Add support for Symfony 8

# 3.22.0 (2025-10-29)

 * Add support for two words test in guard tag
 * Add `Environment::registerUndefinedTestCallback()`
 * Fix compatibility with Symfony 8
 * Fix accessing arrays with stringable objects as key
 * Avoid errors when failing to guess the template info for an error
 * Fix expression parser compatibility layer
 * Fix compiling 'index' with repr (not string) in EmbedNode
 * Update configuration keys + allow extra keys for CommonMark extensions
 * Allow usage of other Markdown converters than CommonMark in LeagueMarkdown

# 3.21.1 (2025-05-03)

 * Fix ExtensionSet usage of BinaryOperatorExpressionParser

# 3.21.0 (2025-05-02)

 * Fix wrong array index
 * Deprecate `Template::loadTemplate()`
 * Fix testing and expression when it evaluates to an instance of `Markup`
 * Add `ReturnPrimitiveTypeInterface` (and sub-interfaces for number, boolean, string, and array)
 * Add `SupportDefinedTestInterface` for expression nodes supporting the `defined` test
 * Deprecate using the `|` operator in an expression with `+` or `-` without using parentheses to clarify precedence
 * Deprecate operator precedence outside of the [0, 512] range
 * Introduce expression parser classes to describe operators and operands provided by extensions
   instead of arrays (it comes with many deprecations that are documented in
   the ``deprecated`` documentation chapter)
 * Deprecate the `Twig\ExpressionParser`, and `Twig\OperatorPrecedenceChange` classes
 * Add attributes `AsTwigFilter`, `AsTwigFunction`, and `AsTwigTest` to ease extension development

# 3.20.0 (2025-02-13)

 * Fix support for ignoring syntax errors in an undefined handler in guard
 * Add configuration for Commonmark
 * Fix wrong array index
 * Bump minimum PHP version to 8.1
 * Add support for registering callbacks for undefined functions, filters or token parsers in the IntegrationTestCase
 * Use correct line number for `ForElseNode`
 * Fix timezone conversion on strings

# 3.19.0 (2025-01-28)

 * Fix a security issue where escaping was missing when using `??`
 * Deprecate `Token::getType()`, use `Token::test()` instead
 * Add `Token::toEnglish()`
 * Add `ForElseNode`
 * Deprecate `Twig\ExpressionParser::parseOnlyArguments()` and
  `Twig\ExpressionParser::parseArguments()` (use
  `Twig\ExpressionParser::parseNamedArguments()` instead)
 * Fix `constant()` behavior when used with `??`
 * Add the `invoke` filter
 * Make `{}` optional for the `types` tag
 * Add `LastModifiedExtensionInterface` and implementation in `AbstractExtension` to track modification of runtime classes
 * Ignore static properties when using the dot operator

# 3.18.0 (2024-12-29)

 * Support for invoking closures
 * Fix unary operator precedence change
 * Ignore `SyntaxError` exceptions from undefined handlers when using the `guard` tag
 * Add a way to stream template rendering (`TemplateWrapper::stream()` and `TemplateWrapper::streamBlock()`)

# 3.17.1 (2024-12-12)

 * Fix the null coalescing operator when the test returns null
 * Fix the Elvis operator when used as '? :' instead of '?:'

# 3.17.0 (2024-12-10)

 * Fix ArrayAccess with objects as keys
 * Support underscores in number literals
 * Deprecate `ConditionalExpression` and `NullCoalesceExpression` (use `ConditionalTernary` and `NullCoalesceBinary` instead)

# 3.16.0 (2024-11-29)

 * Deprecate `InlinePrint`
 * Fix having macro variables starting with an underscore
 * Deprecate not passing a `Source` instance to `TokenStream`
 * Deprecate returning `null` from `TwigFilter::getSafe()` and `TwigFunction::getSafe()`, return `[]` instead

# 3.15.0 (2024-11-17)

 * [BC BREAK] Add support for accessing class constants with the dot operator;
   this can be a BC break if you don't use UPPERCASE constant names
 * Add Spanish inflector support for the `plural` and `singular` filters in the String extension
 * Deprecate `TempNameExpression` in favor of `LocalVariable`
 * Deprecate `NameExpression` in favor of `ContextVariable`
 * Deprecate `AssignNameExpression` in favor of `AssignContextVariable`
 * Remove `MacroAutoImportNodeVisitor`
 * Deprecate `MethodCallExpression` in favor of `MacroReferenceExpression`
 * Fix support for the "is defined" test on `_self.xxx` (auto-imported) macros
 * Fix support for the "is defined" test on inherited macros
 * Add named arguments support for the dot operator arguments (`foo.bar(some: arg)`)
 * Add named arguments support for macros
 * Add a new `guard` tag that allows to test if some Twig callables are available at compilation time
 * Allow arrow functions everywhere
 * Deprecate passing a string or an array to Twig callable arguments accepting arrow functions (pass a `\Closure`)
 * Add support for triggering deprecations for future operator precedence changes
 * Deprecate using the `not` unary operator in an expression with ``*``, ``/``, ``//``, or ``%`` without using explicit parentheses to clarify precedence
 * Deprecate using the `??` binary operator without explicit parentheses
 * Deprecate using the `~` binary operator in an expression with `+` or `-` without using parentheses to clarify precedence
 * Deprecate not passing `AbstractExpression` args to most constructor arguments for classes extending `AbstractExpression`
 * Fix `power` expressions with a negative number in parenthesis (`(-1) ** 2`)
 * Deprecate instantiating `Node` directly. Use `EmptyNode` or `Nodes` instead.
 * Add support for inline comments
 * Add `Profile::getStartTime()` and `Profile::getEndTime()`
 * Fix "ignore missing" when used on an "embed" tag
 * Fix the possibility to override an aliased block (via use)
 * Add template cache hot reload
 * Allow Twig callable argument names to be free-form (snake-case or camelCase) independently of the PHP callable signature
   They were automatically converted to snake-cased before
 * Deprecate the `attribute` function; use the `.` notation and wrap the name with parenthesis instead
 * Add support for argument unpackaging
 * Add JSON support for the file extension escaping strategy
 * Support Markup instances (and any other \Stringable) as dynamic mapping keys
 * Deprecate the `sandbox` tag
 * Improve the way one can deprecate a Twig callable (use `deprecation_info` instead of the other callable options)
 * Add the `enum` function
 * Add support for logical `xor` operator

# 3.14.2 (2024-11-07)

 * Fix an infinite recursion in the sandbox code

# 3.14.1 (2024-11-06)

 * [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
   They are now checked via the property policy
 * Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
   under some circumstances on an object even if the `__toString()` method is not allowed by the security policy

# 3.14.0 (2024-09-09)

 * Fix a security issue when an included sandboxed template has been loaded before without the sandbox context
 * Add the possibility to reset globals via `Environment::resetGlobals()`
 * Deprecate `Environment::mergeGlobals()`

# 3.13.0 (2024-09-07)

 * Add the `types` tag (experimental)
 * Deprecate the `Twig\Test\NodeTestCase::getTests()` data provider, override `provideTests()` instead.
 * Mark `Twig\Test\NodeTestCase::getEnvironment()` as final, override `createEnvironment()` instead.
 * Deprecate `Twig\Test\NodeTestCase::getVariableGetter()`, call `createVariableGetter()` instead.
 * Deprecate `Twig\Test\NodeTestCase::getAttributeGetter()`, call `createAttributeGetter()` instead.
 * Deprecate not overriding `Twig\Test\IntegrationTestCase::getFixturesDirectory()`, this method will be abstract in 4.0
 * Marked `Twig\Test\IntegrationTestCase::getTests()` and `getLegacyTests()` as final

# 3.12.0 (2024-08-29)

 * Deprecate the fact that the `extends` and `use` tags are always allowed in a sandboxed template.
   This behavior will change in 4.0 where these tags will need to be explicitly allowed like any other tag.
 * Deprecate the "tag" constructor argument of the "Twig\Node\Node" class as the tag is now automatically set by the Parser when needed
 * Fix precedence of two-word tests when the first word is a valid test
 * Deprecate the `spaceless` filter
 * Deprecate some internal methods from `Parser`: `getBlockStack()`, `hasBlock()`, `getBlock()`, `hasMacro()`, `hasTraits()`, `getParent()`
 * Deprecate passing `null` to `Twig\Parser::setParent()`
 * Update `Node::__toString()` to include the node tag if set
 * Add support for integers in methods of `Twig\Node\Node` that take a Node name
 * Deprecate not passing a `BodyNode` instance as the body of a `ModuleNode` or `MacroNode` constructor
 * Deprecate returning "null" from "TokenParserInterface::parse()".
 * Deprecate `OptimizerNodeVisitor::OPTIMIZE_TEXT_NODES`
 * Fix performance regression when `use_yield` is `false` (which is the default)
 * Improve compatibility when `use_yield` is `false` (as extensions still using `echo` will work as is)
 * Accept colons (`:`) in addition to equals (`=`) to separate argument names and values in named arguments
 * Add the `html_cva` function (in the HTML extra package)
 * Add support for named arguments to the `block` and `attribute` functions
 * Throw a SyntaxError exception at compile time when a Twig callable has not the minimum number of required arguments
 * Add a `CallableArgumentsExtractor` class
 * Deprecate passing a name to `FunctionExpression`, `FilterExpression`, and `TestExpression`;
   pass a `TwigFunction`, `TwigFilter`, or `TestFilter` instead
 * Deprecate all Twig callable attributes on `FunctionExpression`, `FilterExpression`, and `TestExpression`
 * Deprecate the `filter` node of `FilterExpression`
 * Add the notion of Twig callables (functions, filters, and tests)
 * Bump minimum PHP version to 8.0
 * Fix integration tests when a test has more than one data/expect section and deprecations
 * Add the `enum_cases` function

# 3.11.2 (2024-11-06)

 * [BC BREAK] Fix a security issue in the sandbox mode allowing an attacker to call attributes on Array-like objects
   They are now checked via the property policy
 * Fix a security issue in the sandbox mode allowing an attacker to be able to call `toString()`
   under some circumstances on an object even if the `__toString()` method is not allowed by the security policy

# 3.11.1 (2024-09-10)

 * Fix a security issue when an included sandboxed template has been loaded before without the sandbox context

# 3.11.0 (2024-08-08)

 * Deprecate `OptimizerNodeVisitor::OPTIMIZE_RAW_FILTER`
 * Add `Twig\Cache\ChainCache` and `Twig\Cache\ReadOnlyFilesystemCache`
 * Add the possibility to deprecate attributes and nodes on `Node`
 * Add the possibility to add a package and a version to the `deprecated` tag
 * Add the possibility to add a package for filter/function/test deprecations
 * Mark `ConstantExpression` as being `@final`
 * Add the `find` filter
 * Fix optimizer mode validation in `OptimizerNodeVisitor`
 * Add the possibility to yield from a generator in `PrintNode`
 * Add the `shuffle` filter
 * Add the `singular` and `plural` filters in `StringExtension`
 * Deprecate the second argument of `Twig\Node\Expression\CallExpression::compileArguments()`
 * Deprecate `Twig\ExpressionParser\parseHashExpression()` in favor of
   `Twig\ExpressionParser::parseMappingExpression()`
 * Deprecate `Twig\ExpressionParser\parseArrayExpression()` in favor of
   `Twig\ExpressionParser::parseSequenceExpression()`
 * Add `sequence` and `mapping` tests
 * Deprecate `Twig\Node\Expression\NameExpression::isSimple()` and
    `Twig\Node\Expression\NameExpression::isSpecial()`

# 3.10.3 (2024-05-16)

 * Fix missing ; in generated code

# 3.10.2 (2024-05-14)

 * Fix support for the deprecated escaper signature

# 3.10.1 (2024-05-12)

 * Fix BC break on escaper extension
 * Fix constant return type

# 3.10.0 (2024-05-11)

 * Make `CoreExtension::formatDate`, `CoreExtension::convertDate`, and
   `CoreExtension::formatNumber` part of the public API
 * Add `needs_charset` option for filters and functions
 * Extract the escaping logic from the `EscaperExtension` class to a new
   `EscaperRuntime` class.

   The following methods from ``Twig\\Extension\\EscaperExtension`` are
   deprecated: ``setEscaper()``, ``getEscapers()``, ``setSafeClasses``,
   ``addSafeClasses()``. Use the same methods on the
   ``Twig\\Runtime\\EscaperRuntime`` class instead.
  * Fix capturing output from extensions that still use echo
  * Fix a PHP warning in the Lexer on malformed templates
  * Fix blocks not available under some circumstances
  * Synchronize source context in templates when setting a Node on a Node

# 3.9.3 (2024-04-18)

 * Add missing `twig_escape_filter_is_safe` deprecated function
 * Fix yield usage with CaptureNode
 * Add missing unwrap call when using a TemplateWrapper instance internally
 * Ensure Lexer is initialized early on

# 3.9.2 (2024-04-17)

 * Fix usage of display_end hook

# 3.9.1 (2024-04-17)

 * Fix missing `$blocks` variable in `CaptureNode`

# 3.9.0 (2024-04-16)

 * Add support for PHP 8.4
 * Deprecate AbstractNodeVisitor
 * Deprecate passing Template to Environment::resolveTemplate(), Environment::load(), and Template::loadTemplate()
 * Add a new "yield" mode for output generation;
   Node implementations that use "echo" or "print" should use "yield" instead;
   all Node implementations should be flagged with `#[YieldReady]` once they've been made ready for "yield";
   the "use_yield" Environment option can be turned on when all nodes have been made `#[YieldReady]`;
   "yield" will be the only strategy supported in the next major version
 * Add return type for Symfony 7 compatibility
 * Fix premature loop exit in Security Policy lookup of allowed methods/properties
 * Deprecate all internal extension functions in favor of methods on the extension classes
 * Mark all extension functions as @internal
 * Add SourcePolicyInterface to selectively enable the Sandbox based on a template's Source
 * Throw a proper Twig exception when using cycle on an empty array

# 3.8.0 (2023-11-21)

 * Catch errors thrown during template rendering
 * Fix IntlExtension::formatDateTime use of date formatter prototype
 * Fix premature loop exit in Security Policy lookup of allowed methods/properties
 * Remove NumberFormatter::TYPE_CURRENCY (deprecated in PHP 8.3)
 * Restore return type annotations
 * Allow Symfony 7 packages to be installed
 * Deprecate `twig_test_iterable` function. Use the native `is_iterable` instead.

# 3.7.1 (2023-08-28)

 * Fix some phpdocs

# 3.7.0 (2023-07-26)

 * Add support for the ...spread operator on arrays and hashes

# 3.6.1 (2023-06-08)

 * Suppress some native return type deprecation messages

# 3.6.0 (2023-05-03)

 * Allow psr/container 2.0
 * Add the new PHP 8.0 IntlDateFormatter::RELATIVE_* constants for date formatting
 * Make the Lexer initialize itself lazily

# 3.5.1 (2023-02-08)

 * Arrow functions passed to the "reduce" filter now accept the current key as a third argument
 * Restores the leniency of the matches twig comparison
 * Fix error messages in sandboxed mode for "has some" and "has every"

# 3.5.0 (2022-12-27)

 * Make Twig\ExpressionParser non-internal
 * Add "has some" and "has every" operators
 * Add Compile::reset()
 * Throw a better runtime error when the "matches" regexp is not valid
 * Add "twig *_names" intl functions
 * Fix optimizing closures callbacks
 * Add a better exception when getting an undefined constant via `constant`
 * Fix `if` nodes when outside of a block and with an empty body

# 3.4.3 (2022-09-28)

 * Fix a security issue on filesystem loader (possibility to load a template outside a configured directory)

# 3.4.2 (2022-08-12)

 * Allow inherited magic method to still run with calling class
 * Fix CallExpression::reflectCallable() throwing TypeError
 * Fix typo in naming (currency_code)

# 3.4.1 (2022-05-17)

* Fix optimizing non-public named closures

# 3.4.0 (2022-05-22)

 * Add support for named closures

# 3.3.10 (2022-04-06)

 * Enable bytecode invalidation when auto_reload is enabled

# 3.3.9 (2022-03-25)

 * Fix custom escapers when using multiple Twig environments
 * Add support for "constant('class', object)"
 * Do not reuse internally generated variable names during parsing

# 3.3.8 (2022-02-04)

 * Fix a security issue when in a sandbox: the `sort` filter must require a Closure for the `arrow` parameter
 * Fix deprecation notice on `round`
 * Fix call to deprecated `convertToHtml` method

# 3.3.7 (2022-01-03)

* Allow more null support when Twig expects a string (for better 8.1 support)
* Only use Commonmark extensions if markdown enabled

# 3.3.6 (2022-01-03)

* Only use Commonmark extensions if markdown enabled

# 3.3.5 (2022-01-03)

* Allow CommonMark extensions to easily be added
* Allow null when Twig expects a string (for better 8.1 support)
* Make some performance optimizations
* Allow Symfony translation contract v3+

# 3.3.4 (2021-11-25)

 * Bump minimum supported Symfony component versions
 * Fix a deprecated message

# 3.3.3 (2021-09-17)

 * Allow Symfony 6
 * Improve compatibility with PHP 8.1
 * Explicitly specify the encoding for mb_ord in JS escaper

# 3.3.2 (2021-05-16)

 * Revert "Throw a proper exception when a template name is an absolute path (as it has never been supported)"

# 3.3.1 (2021-05-12)

 * Fix PHP 8.1 compatibility
 * Throw a proper exception when a template name is an absolute path (as it has never been supported)

# 3.3.0 (2021-02-08)

 * Fix macro calls in a "cache" tag
 * Add the slug filter
 * Allow extra bundle to be compatible with Twig 2

# 3.2.1 (2021-01-05)

 * Fix extra bundle compat with older versions of Symfony

# 3.2.0 (2021-01-05)

 * Add the Cache extension in the "extra" repositories: "cache" tag
 * Add "registerUndefinedTokenParserCallback"
 * Mark built-in node visitors as @internal
 * Fix "odd" not working for negative numbers

# 3.1.1 (2020-10-27)

 * Fix "include(template_from_string())"

# 3.1.0 (2020-10-21)

 * Fix sandbox support when using "include(template_from_string())"
 * Make round brackets optional for one argument tests like "same as" or "divisible by"
 * Add support for ES2015 style object initialisation shortcut { a } is the same as { 'a': a }

# 3.0.5 (2020-08-05)

 * Fix twig_compare w.r.t. whitespace trimming
 * Fix sandbox not disabled if syntax error occurs within {% sandbox %} tag
 * Fix a regression when not using a space before an operator
 * Restrict callables to closures in filters
 * Allow trailing commas in argument lists (in calls as well as definitions)

# 3.0.4 (2020-07-05)

 * Fix comparison operators
 * Fix options not taken into account when using "Michelf\MarkdownExtra"
 * Fix "Twig\Extra\Intl\IntlExtension::getCountryName()" to accept "null" as a first argument
 * Throw exception in case non-Traversable data is passed to "filter"
 * Fix context optimization on PHP 7.4
 * Fix PHP 8 compatibility
 * Fix ambiguous syntax parsing

# 3.0.3 (2020-02-11)

 * Add a check to ensure that iconv() is defined

# 3.0.2 (2020-02-11)

 * Avoid exceptions when an intl resource is not found
 * Fix implementation of case-insensitivity for method names

# 3.0.1 (2019-12-28)

 * fixed Symfony 5.0 support for the HTML extra extension

# 3.0.0 (2019-11-15)

 * fixed number formatter in Intl extra extension when using a formatter prototype

# 3.0.0-BETA1 (2019-11-11)

 * removed the "if" condition support on the "for" tag
 * made the in, <, >, <=, >=, ==, and != operators more strict when comparing strings and integers/floats
 * removed the "filter" tag
 * added type hints everywhere
 * changed Environment::resolveTemplate() to always return a TemplateWrapper instance
 * removed Template::__toString()
 * removed Parser::isReservedMacroName()
 * removed SanboxedPrintNode
 * removed Node::setTemplateName()
 * made classes marked as "@final" final
 * removed InitRuntimeInterface, ExistsLoaderInterface, and SourceContextLoaderInterface
 * removed the "spaceless" tag
 * removed Twig\Environment::getBaseTemplateClass() and Twig\Environment::setBaseTemplateClass()
 * removed the "base_template_class" option on Twig\Environment
 * bumped minimum PHP version to 7.2
 * removed PSR-0 classes
