TYPO3 v15 dev-main snapshot ()

This commit is contained in:
2026-08-10 22:31:09 +02:00
commit af8cc155b5
6818 changed files with 642608 additions and 0 deletions
@@ -0,0 +1,41 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface;
/**
* Implement main LineInterface methods.
*
* @internal: Internal tokenizer structure.
*/
abstract class AbstractLine implements LineInterface
{
protected TokenStreamInterface $tokenStream;
public function setTokenStream(TokenStreamInterface $tokenStream): static
{
$this->tokenStream = $tokenStream;
return $this;
}
public function getTokenStream(): TokenStreamInterface
{
return $this->tokenStream;
}
}
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* A block close line, essentially "}".
*
* @internal: Internal tokenizer structure.
*/
final class BlockCloseLine extends AbstractLine {}
@@ -0,0 +1,29 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* A commented TypoScript line: Lines that start with "#", "//" and multiline comments "/* ... *\/"
*
* Note multiline comments often represent multiple source lines: An opening "/*" as
* first source line, then the comment body with one or more source lines, then finally
* the closing "*\/". These still create only one "CommentLine".
*
* @internal: Internal tokenizer structure.
*/
final class CommentLine extends AbstractLine {}
@@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* "[ELSE]" / "[else]": An else block after a starting ConditionLine.
*
* @internal: Internal tokenizer structure.
*/
final class ConditionElseLine extends AbstractLine {}
@@ -0,0 +1,45 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\Token;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenType;
/**
* A condition line: "[foo == bar]".
*
* @internal: Internal tokenizer structure.
*/
final class ConditionLine extends AbstractLine
{
private Token $valueToken;
public function setValueToken(Token $token): static
{
if ($token->getType() !== TokenType::T_VALUE) {
throw new \LogicException('Token must be of type T_VALUE', 1655823705);
}
$this->valueToken = $token;
return $this;
}
public function getTokenValue(): Token
{
return $this->valueToken;
}
}
@@ -0,0 +1,26 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* A line stopping current ConditionLine context:
* "[END]" / "[end]" / "[GLOBAL]" / "[global]".
*
* @internal: Internal tokenizer structure.
*/
final class ConditionStopLine extends AbstractLine {}
@@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* A completely empty line, or a line consisting of tabs or whitespaces only.
*
* This is not created when the TypoScript source line is within multiline "("
* assignments and multiline "/*" comments: The T_BLANK and T_NEWLINE tokens
* are part of the value steram in these contexts.
*
* Note the LossyTokenizers does not create these and just skips them since
* they have no semantic meaning for the resulting TypoScript tree.
*
* @internal: Internal tokenizer structure.
*/
final class EmptyLine extends AbstractLine {}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface;
/**
* Simple "=" assignments and multiline "(" assignments: "foo.bar = barValue".
*
* Each line has two additional token streams: $identifierTokenStream for the
* left side ("foo" and "bar" tokens) and $valueTokenStream for the right side
* ("barValue" token). Right side is often a single token only, but can be many
* tokens when constants and multiline assignments are involved.
*
* Neither the left, nor the right side streams can be empty: Even with "foo.bar ="
* a T_VALUE token with empty value is created for the right side.
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierAssignmentLine extends AbstractLine
{
private IdentifierTokenStream $identifierTokenStream;
private TokenStreamInterface $valueTokenStream;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655824257);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
return $this->identifierTokenStream;
}
public function setValueTokenStream(TokenStreamInterface $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Value token stream must not be empty', 1655824258);
}
$this->valueTokenStream = $tokenStream;
return $this;
}
public function getValueTokenStream(): TokenStreamInterface
{
return $this->valueTokenStream;
}
}
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
/**
* A block open line: "foo.bar {".
*
* $identifierTokenStream is a stream of tokens on the left side, "foo"
* and "bar" token in the example above. That stream must not be empty.
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierBlockOpenLine extends AbstractLine
{
private IdentifierTokenStream $identifierTokenStream;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655824621);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
return $this->identifierTokenStream;
}
}
@@ -0,0 +1,68 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
/**
* A line using the copy operator: "foo.bar < lib.myLib".
*
* Contains a stream of tokens for the left side ("foo" and "bar" tokens) and
* a stream of tokens for the right side ("lib" and "myLib"). None of these
* token streams can be empty, it's an InvalidLine otherwise.
*
* Note the right side TokenStreamIdentifier can be relative: "foo.bar < .baz".
* Flag $relative in TokenStreamIdentifier represents this start dot on the right side.
*
* None of the two streams can be empty.
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierCopyLine extends AbstractLine
{
private IdentifierTokenStream $identifierTokenStream;
private IdentifierTokenStream $valueTokenStream;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655824946);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
return $this->identifierTokenStream;
}
public function setValueTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Value token stream must not be empty', 1655824947);
}
$this->valueTokenStream = $tokenStream;
return $this;
}
public function getValueTokenStream(): IdentifierTokenStream
{
return $this->valueTokenStream;
}
}
@@ -0,0 +1,87 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\Token;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenType;
/**
* A line with a function assignment using the ":=" operator: "foo.bar := addToList(42)".
*
* Contains $identifierTokenStream for the left side ("foo" and "bar" token), a single
* token for the function name ("addToList"), and an optional token for the value ("42").
* Note the value token is optional since there are functions without values (eg. "uniqueList()").
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierFunctionLine extends AbstractLine
{
private ?IdentifierTokenStream $identifierTokenStream = null;
private ?Token $functionNameToken = null;
private ?TokenStreamInterface $functionValueTokenStream = null;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): IdentifierFunctionLine
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655825120);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
if ($this->identifierTokenStream === null) {
throw new \RuntimeException('Identifier token stream has not been set', 1717495444);
}
return $this->identifierTokenStream;
}
public function setFunctionNameToken(Token $token): IdentifierFunctionLine
{
if ($token->getType() !== TokenType::T_FUNCTION_NAME) {
throw new \LogicException('Function name token must be of type T_FUNCTION_NAME', 1655825121);
}
$this->functionNameToken = $token;
return $this;
}
public function getFunctionNameToken(): Token
{
if ($this->functionNameToken === null) {
throw new \RuntimeException('Function name token has not been set', 1717495576);
}
return $this->functionNameToken;
}
public function setFunctionValueTokenStream(TokenStreamInterface $tokenStream): IdentifierFunctionLine
{
$this->functionValueTokenStream = $tokenStream;
return $this;
}
public function getFunctionValueTokenStream(): TokenStreamInterface
{
if ($this->functionValueTokenStream === null) {
throw new \RuntimeException('Function value token stream has not been set', 1717495996);
}
return $this->functionValueTokenStream;
}
}
@@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
/**
* A line using the reference ("=<") operator: "foo.bar =< lib.myLib".
*
* Contains two non-empty token streams: One for the left side ("foo" and "bar" tokens),
* and one for the right side ("lib" and "myLib"). Both streams must not be empty.
*
* Note the AstBuilder does not directly resolve "=<" operators. This is
* not a language construct itself and is only resolved in some special cases
* in frontend. See ContentObjectRenderer->cObjGetSingle() for more details.
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierReferenceLine extends AbstractLine
{
private IdentifierTokenStream $identifierTokenStream;
private IdentifierTokenStream $valueTokenStream;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655825891);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
return $this->identifierTokenStream;
}
public function setValueTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Value token stream must not be empty', 1655825892);
}
$this->valueTokenStream = $tokenStream;
return $this;
}
public function getValueTokenStream(): IdentifierTokenStream
{
return $this->valueTokenStream;
}
}
@@ -0,0 +1,47 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\IdentifierTokenStream;
/**
* A line using the unset (">") operator: "foo.bar >".
*
* Has $identifierTokenStream for the stream of tokens on the left
* side ("foo" and "bar" tokens).
*
* @internal: Internal tokenizer structure.
*/
final class IdentifierUnsetLine extends AbstractLine
{
private IdentifierTokenStream $identifierTokenStream;
public function setIdentifierTokenStream(IdentifierTokenStream $tokenStream): static
{
if ($tokenStream->isEmpty()) {
throw new \LogicException('Identifier token stream must not be empty', 1655826025);
}
$this->identifierTokenStream = $tokenStream;
return $this;
}
public function getIdentifierTokenStream(): IdentifierTokenStream
{
return $this->identifierTokenStream;
}
}
@@ -0,0 +1,49 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\Token;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenType;
/**
* A line using the "@import" keyword: "@import 'EXT:my_extension/Configuration/TypoScript/randomfile.typoscript'"
*
* Contains the $valueToken ("EXT:my_extension/Configuration/TypoScript/randomfile.typoscript"), without the
* surrounding tick (') or doubletick ("). The value itself is not parsed further at this point, this
* is done by the IncludeTree classes.
*
* @internal: Internal tokenizer structure.
*/
final class ImportLine extends AbstractLine
{
private Token $valueToken;
public function setValueToken(Token $token): static
{
if ($token->getType() !== TokenType::T_VALUE) {
throw new \LogicException('Value token must be of type T_VALUE', 1655826193);
}
$this->valueToken = $token;
return $this;
}
public function getValueToken(): Token
{
return $this->valueToken;
}
}
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* A line that is syntactically invalid.
*
* This is created by LosslessTokenizer whenever a line does not make sense.
* Examples:
* "foo.bar" - no operator
* "foo.bar <" - right side empty
* "@import ''" - no import value
*
* Note only LosslessTokenizer creates these lines, LossyTokenizer just skips them.
*
* @internal: Internal tokenizer structure.
*/
final class InvalidLine extends AbstractLine {}
@@ -0,0 +1,42 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
use TYPO3\CMS\Core\TypoScript\Tokenizer\Token\TokenStreamInterface;
/**
* The TypoScript tokenizers deliver streams of lines. This is the main line interface.
*
* Each line is represented by a specific line type. For instance, "foo.bar {" creates
* an IdentifierBlockOpenLine and has the additional method getIdentifierTokenStream()
* to retrieve the "foo" and "bar" identifier tokens.
*
* @internal: Internal tokenizer structure.
*/
interface LineInterface
{
/**
* Set and get the token stream that represents the full line. This is mostly used
* in backend to for instance create a TypoScript string back from tokenized lines.
*
* Note: Only the LosslessTokenizer fills this 'full line' stream, LossyTokenizer
* does not for performance reasons.
*/
public function setTokenStream(TokenStreamInterface $tokenStream): static;
public function getTokenStream(): TokenStreamInterface;
}
@@ -0,0 +1,124 @@
<?php
declare(strict_types=1);
/*
* This file is part of the TYPO3 CMS project.
*
* It is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License, either version 2
* of the License, or any later version.
*
* For the full copyright and license information, please read the
* LICENSE.txt file that was distributed with this source code.
*
* The TYPO3 project - inspiring people to share!
*/
namespace TYPO3\CMS\Core\TypoScript\Tokenizer\Line;
/**
* Each TypoScript snippet is turned by the tokenizers into a
* stream of lines. Tokenizers return instances of this class.
*
* Iterate line streams in a foreach loop using getNextLine().
*
* @internal: Internal tokenizer structure.
*/
final class LineStream
{
/**
* @var LineInterface[]
*/
private array $lines = [];
private int $currentIndex = -1;
/**
* Create a source string from given token lines. This is used in backend
* to turn the "full" token streams of lines into strings for output.
*/
public function __toString(): string
{
$source = '';
foreach ($this->getNextLine() as $line) {
// We do *not* implement __toString() on lines since this is a
// backend thing only, and we do not want to accidentally stringify
// lines based on the full stream anywhere.
$source .= $line->getTokenStream()->reset();
}
return $source;
}
/**
* When storing to cache, we only store FE relevant properties and skip
* irrelevant things. In particular, $currentIndex should always initialize
* to -1 and does not need to be stored.
*/
final public function __serialize(): array
{
return [
'lines' => $this->lines,
];
}
/**
* Stream creation.
*/
public function append(LineInterface $line): self
{
$this->lines[] = $line;
return $this;
}
/**
* We sometimes create a line stream but don't add lines.
* This method returns true if lines have been added.
*/
public function isEmpty(): bool
{
return empty($this->lines);
}
/**
* @return iterable<LineInterface>
*/
public function getNextLine(): iterable
{
foreach ($this->lines as $child) {
yield $child;
}
}
/**
* Reset current pointer. Typically, call this before iterating with getNext().
*/
public function reset(): self
{
$this->currentIndex = -1;
return $this;
}
/**
* Get next line and raise pointer.
*
* Methods getNext(), peekNext() and reset() are an alternative to
* getNextLine() which allow peek of the next line, which getNextLine()
* does not. The disadvantage is that these methods create internal
* state in $this->currentIndex, which getNextLine() does not. Use
* getNext() iteration only if peekNext() is needed to avoid creating
* useless state.
*/
public function getNext(): ?LineInterface
{
$this->currentIndex++;
return $this->lines[$this->currentIndex] ?? null;
}
/**
* Get next line but do not raise pointer.
*/
public function peekNext(): ?LineInterface
{
return $this->lines[$this->currentIndex + 1] ?? null;
}
}