PHPackages                             oliverthiele/typo3-fluid-linter - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. oliverthiele/typo3-fluid-linter

ActiveLibrary[Testing &amp; Quality](/categories/testing)

oliverthiele/typo3-fluid-linter
===============================

A linter for TYPO3 Fluid templates — catches typographic quotes, deprecated syntax, and Fluid 5 breaking changes

0.7.0(1mo ago)02GPL-2.0-or-laterPHPPHP &gt;=8.2

Since Jun 25Pushed 1mo agoCompare

[ Source](https://github.com/oliverthiele/typo3-fluid-linter)[ Packagist](https://packagist.org/packages/oliverthiele/typo3-fluid-linter)[ RSS](/packages/oliverthiele-typo3-fluid-linter/feed)WikiDiscussions main Synced 1w ago

READMEChangelogDependencies (3)Versions (7)Used By (0)

TYPO3 Fluid Linter — Static analysis for Fluid templates
========================================================

[](#typo3-fluid-linter--static-analysis-for-fluid-templates)

A CLI linter for TYPO3 Fluid templates that catches encoding errors, deprecated syntax, and Fluid 5 breaking changes before they reach production.

[![Packagist Version](https://camo.githubusercontent.com/450a9ae1db764bdd643d0f5e4f2675f5289d3f869670debbf4a20a23e82a66ed/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f6f6c69766572746869656c652f7479706f332d666c7569642d6c696e7465722e737667)](https://packagist.org/packages/oliverthiele/typo3-fluid-linter)[![PHP](https://camo.githubusercontent.com/f1947378769cbd047b631d733619c56c5df2c2949463485d13e6a8b8724b9726/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6f6c69766572746869656c652f7479706f332d666c7569642d6c696e7465722f7068702e737667)](https://php.net/)[![License](https://camo.githubusercontent.com/6771fab00fad1f9624016eff2f1c5a0f950112a2c0f1fef5bf045237e6d09d8a/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f6c2f6f6c69766572746869656c652f7479706f332d666c7569642d6c696e7465722e737667)](LICENSE)[![Changelog](https://camo.githubusercontent.com/6bc02a7bc61afc1cb3faaa53420df6d904b9940d7f3e2e11a463e1fdbb3cd52d/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4368616e67656c6f672d4348414e47454c4f472e6d642d626c75652e737667)](CHANGELOG.md)

---

Why TYPO3 Fluid Linter?
-----------------------

[](#why-typo3-fluid-linter)

Existing Fluid linters ([Fluid.Lint](https://github.com/NamelessCoder/fluid-lint), [fluid-lint](https://github.com/typo3fluid/fluid-lint)) take an AST-based approach: they parse templates using the Fluid engine itself, which requires `typo3fluid/fluid` as a dependency and catches structural syntax errors. This tool takes a different approach — **regex-based, zero dependency, no TYPO3 required** — and targets a different class of problems: encoding artifacts from AI-assisted development, deprecated ViewHelper usage across TYPO3 versions, and Fluid 5 breaking changes. Both approaches are complementary.

TYPO3 core itself ships an AST-based check, `typo3 fluid:analyze` (`TYPO3\CMS\Fluid\Command\AnalyzeCommand`, since TYPO3 v13): it parses `*.fluid.*` files with the real Fluid `TemplateParser` and reports genuine parse errors plus dynamically-triggered deprecation warnings. It requires a fully bootable TYPO3 instance and only covers `*.fluid.*` files, so it doesn't replace this linter in standalone extension repos or lightweight CI jobs without a TYPO3 install. Where a full install is available, run both: `fluid:analyze` for real syntax/AST errors, this linter for encoding artifacts, namespace/XML issues, and deprecations simulated for TYPO3 versions that aren't even installed (`--typo3-version=`).

### Designed for AI-assisted development

[](#designed-for-ai-assisted-development)

This tool was created to catch a specific class of errors that LLMs introduce when generating Fluid templates. Language models produce correct Fluid logic reliably, but they occasionally introduce Unicode encoding artifacts that are nearly invisible in most editors: a `"` (U+201C, left double quotation mark) instead of a straight `"`, a `″` (U+2033, double prime / inch mark) as an attribute delimiter, or `«value»` (angle quotation marks) as an attribute value. A human developer would never write `class=«container»` — but a language model can, especially when the surrounding context contains measurement data, quotation-heavy text, or content in languages that use these characters as standard punctuation.

The alternative — asking a second LLM to review every generated template for encoding errors — is slower, costs tokens, and is non-deterministic. A static linter is faster, deterministic, and integrates into CI with a single command.

---

Features
--------

[](#features)

- **Invalid attribute quote detection** — flags non-ASCII quote characters used as attribute value delimiters: typographic quotes (U+201C `"`, U+201D `"`, U+2018 `'`, U+2019 `'`, U+201A `‚`, U+201E `„`), backtick (U+0060 ```), prime/inch marks (U+2032 `′`, U+2033 `″`), angle quotes (U+00AB `«`, U+00BB `»`, U+2039 `‹`, U+203A `›`); text content between tags (e.g. `1/2″` inside ``) is not flagged
- **Missing namespace attribute** — detects `` tags with a Fluid xmlns declaration that are missing `data-namespace-typo3-fluid="true"`, which causes duplicate `` elements in the rendered output
- **Invalid namespace URI** — `https://typo3.org/ns/` throws a runtime exception; the correct prefix is `http://typo3.org/ns/`
- **Fluid 5 compatibility** — detects variable names starting with an underscore, which are forbidden in Fluid 5 (TYPO3 v14)
- **Deprecated syntax** — flags empty `parseFuncTSPath=""`, which causes a runtime error; use `{field -> f:format.html()}` instead
- **CDATA section detection** — flags `` inside `` blocks, the old pattern for safely commenting out Fluid code; deprecated in Fluid 4 and removed in Fluid 5; legitimate CDATA in XML/RSS templates and `{{{expression}}}` output syntax are not flagged
- **XML declaration warning** — flags the `` processing instruction, which is unnecessary in Fluid templates and may trigger Quirks Mode
- **Debug ViewHelper detection** — flags `` usage to prevent debug output from reaching production; configurable as `warning` (development) or `error` (live gate)
- **Deprecated ViewHelper detection** — flags ViewHelpers and arguments that were deprecated or removed in a specific TYPO3 version: all `` (removed v11), `getVars` on `` (deprecated v11), `` (deprecated v11.3), `` and `` (removed v12), `` and `` (removed v13), `` and `useNonce` on `` (deprecated v14.2); requires `--typo3-version=`
- **Config file support** — per-project `.fluid-lint.php` with rule severity overrides; separate live config for CI release gates
- **Version-aware rules** — pass `--typo3-version=14` to activate rules specific to a TYPO3 major version
- **Three severity levels** — `error` (exit code 1), `warning`, and `info` (both exit code 0)
- **GitHub Actions integration** — `--format=github` emits inline annotations with correct severity levels directly in pull request diffs
- **JSON output** — `--format=json` emits structured JSON for IDE plugins, pre-commit hooks, and custom tooling
- **Zero TYPO3 dependency** — runs standalone in any PHP 8.2+ environment; no TYPO3 core required

---

Requirements
------------

[](#requirements)

RequirementVersionPHP&gt;= 8.2---

Installation
------------

[](#installation)

```
composer require --dev oliverthiele/typo3-fluid-linter
```

---

Usage
-----

[](#usage)

Lint a directory recursively:

```
vendor/bin/fluid-lint packages/my_extension/Resources/Private/
```

Lint a single file:

```
vendor/bin/fluid-lint path/to/Template.html
```

Lint multiple paths:

```
vendor/bin/fluid-lint templates/ partials/ layouts/
```

Lint with TYPO3 version-specific rules:

```
vendor/bin/fluid-lint --typo3-version=14 packages/
```

### Config file

[](#config-file)

Copy `.fluid-lint.php` to your project root. The linter auto-detects it on every run:

```
vendor/bin/fluid-lint packages/
```

For a stricter live/release gate (e.g. block on `f:debug`):

```
vendor/bin/fluid-lint --config=.fluid-lint.live.php packages/
```

Example `.fluid-lint.php` (development — `f:debug` is a warning):

```

    ->disableRule('fluid-file-extension'); // ignore .html / .fluid.html coexistence
```

### Automatic fixes

[](#automatic-fixes)

The `--fix` flag applies safe fixes automatically. Destructive operations (deleting files) additionally require `--allow-risky`:

```
# Rename .html → .fluid.html for files in partially migrated directories (safe)
vendor/bin/fluid-lint --fix --typo3-version=14 packages/

# Also delete orphaned .html files where .fluid.html already exists (destructive)
vendor/bin/fluid-lint --fix --allow-risky --typo3-version=14 packages/
```

> **Warning:** `--allow-risky` permanently deletes files. Ensure your project is under version control before using it.

Currently fixable rules:

RuleFixRisky?`xml-declaration`Remove the `` processing instruction lineNo`parsefunc-tspath`Remove the empty `parseFuncTSPath=""` attribute from the tagNo`html-namespace-attribute`Insert `data-namespace-typo3-fluid="true"` into the `` opening tagNo`https-namespace`Replace `https://typo3.org/ns/` with `http://typo3.org/ns/` (all occurrences)No`fluid-file-extension` (info)Rename `Template.html` → `Template.fluid.html`No`fluid-file-extension` (warning)Delete `Template.html` (`.fluid.html` counterpart kept)Yes### GitHub Actions

[](#github-actions)

```
- name: Lint Fluid templates
  run: vendor/bin/fluid-lint --format=github --typo3-version=13 packages/
```

The `--format=github` flag emits `::error`, `::warning`, and `::notice` annotations that GitHub Actions renders as inline comments in pull requests.

For a release gate that also blocks on `f:debug`:

```
- name: Lint Fluid templates (live gate)
  run: vendor/bin/fluid-lint --format=github --config=.fluid-lint.live.php packages/
```

---

CLI
---

[](#cli)

```
Usage: fluid-lint [--format=github|json] [--fix [--allow-risky]] [--config=] [--typo3-version=]  [...]

Options:
  --format=github          Emit GitHub Actions annotation format instead of console output
  --format=json            Emit structured JSON (violations array + summary object)
  --fix                    Apply safe automatic fixes (rename .html → .fluid.html)
  --allow-risky            Also apply destructive fixes (delete files) — requires --fix
  --config=          Load rule configuration from a PHP file returning a LintConfig instance
  --typo3-version=  Activate version-specific rules (e.g. --typo3-version=14)

Config file resolution (first match wins):
  1. --config= (explicit path)
  2. .fluid-lint.php in the current working directory
  3. Built-in defaults (all rules enabled, default severities)

Exit codes:
  0    No errors (warnings and infos do not affect the exit code)
  1    One or more errors found, or path not found

```

---

Rules
-----

[](#rules)

RuleIDSeverityVersionInvalid quote character as attribute delimiter (typographic, backtick, prime/inch, angle)`typographic-quotes`errorallMissing `data-namespace-typo3-fluid="true"` on `` tag`html-namespace-attribute`errorall`https://` in Fluid namespace URI throws an exception`https-namespace`errorallFluid variable name starts with underscore (forbidden in Fluid 5)`underscore-variable`error14+Empty `parseFuncTSPath=""` causes a runtime error`parsefunc-tspath`errorall`` — deprecated in Fluid 4, removed in Fluid 5`cdata-section`errorall`` processing instruction is unnecessary in Fluid templates`xml-declaration`warningall`f:debug` ViewHelper found — remove before going live`debug-viewhelper`warningall`.html` file has a `.fluid.html` counterpart — conflict, TYPO3 v14 may load the wrong file`fluid-file-extension`warning14+`.html` file has no `.fluid.html` counterpart — migration hint for v14`fluid-file-extension`info14+Deprecated or removed ViewHelper/argument — `f:widget.*` (removed v11), `getVars` arg (deprecated v11), `f:be.container` (deprecated v11.3), `f:be.buttons.shortcut` + `f:base` (removed v12), `f:be.buttons.csh` + `f:be.labels.csh` (removed v13), `f:debug.render` + `useNonce` (deprecated v14.2)`deprecated-viewhelper`error / warning11+---

License
-------

[](#license)

GPL-2.0-or-later — see [LICENSE](LICENSE)

---

Author
------

[](#author)

Oliver Thiele — [oliver-thiele.de](https://www.oliver-thiele.de)

###  Health Score

36

—

LowBetter than 79% of packages

Maintenance90

Actively maintained with recent releases

Popularity2

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~1 days

Total

5

Last Release

48d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/5030298?v=4)[Oliver Thiele](/maintainers/oliverthiele)[@oliverthiele](https://github.com/oliverthiele)

---

Top Contributors

[![oliverthiele](https://avatars.githubusercontent.com/u/5030298?v=4)](https://github.com/oliverthiele "oliverthiele (24 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/oliverthiele-typo3-fluid-linter/health.svg)

```
[![Health](https://phpackages.com/badges/oliverthiele-typo3-fluid-linter/health.svg)](https://phpackages.com/packages/oliverthiele-typo3-fluid-linter)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
