gl-website-deployer/vendor/doctrine/rst-parser/lib/Environment.php
2024-11-19 08:02:04 +01:00

475 lines
12 KiB
PHP

<?php
declare(strict_types=1);
namespace Doctrine\RST;
use Doctrine\RST\Meta\MetaEntry;
use Doctrine\RST\Meta\Metas;
use Doctrine\RST\NodeFactory\NodeFactory;
use Doctrine\RST\References\Reference;
use Doctrine\RST\References\ResolvedReference;
use Doctrine\RST\Templates\TemplateRenderer;
use InvalidArgumentException;
use Symfony\Component\String\Slugger\AsciiSlugger;
use function array_shift;
use function dirname;
use function implode;
use function in_array;
use function sprintf;
use function strtolower;
use function trim;
class Environment
{
/** @var Configuration */
private $configuration;
/** @var ErrorManager */
private $errorManager;
/** @var UrlGenerator */
private $urlGenerator;
/** @var int */
private $currentTitleLevel = 0;
/** @var string[] */
private $titleLetters = [];
/** @var string */
private $currentFileName = '';
/** @var string */
private $currentDirectory = '.';
/** @var string */
private $targetDirectory = '.';
/** @var string|null */
private $url = null;
/** @var Reference[] */
private $references = [];
/** @var Metas */
private $metas;
/** @var string[] */
private $dependencies = [];
/** @var string[] */
private $unresolvedDependencies = [];
/** @var string[] */
private $originalDependencyNames = [];
/** @var string[] */
private $variables = [];
/** @var string[] */
private $links = [];
/** @var int[] */
private $levels = [];
/** @var int[] */
private $counters = [];
/** @var string[] */
private $anonymous = [];
/** @var InvalidLink[] */
private $invalidLinks = [];
public function __construct(Configuration $configuration)
{
$this->configuration = $configuration;
$this->errorManager = new ErrorManager($this->configuration);
$this->urlGenerator = new UrlGenerator(
$this->configuration
);
$this->metas = new Metas();
$this->reset();
}
public function reset(): void
{
$this->titleLetters = [];
$this->currentTitleLevel = 0;
$this->levels = [];
$this->counters = [];
for ($level = 0; $level < 16; $level++) {
$this->levels[$level] = 1;
$this->counters[$level] = 0;
}
}
public function getConfiguration(): Configuration
{
return $this->configuration;
}
public function getErrorManager(): ErrorManager
{
return $this->errorManager;
}
public function setErrorManager(ErrorManager $errorManager): void
{
$this->errorManager = $errorManager;
}
public function setMetas(Metas $metas): void
{
$this->metas = $metas;
}
public function getNodeFactory(): NodeFactory
{
return $this->configuration->getNodeFactory($this);
}
public function getTemplateRenderer(): TemplateRenderer
{
return $this->configuration->getTemplateRenderer();
}
public function registerReference(Reference $reference): void
{
$this->references[$reference->getName()] = $reference;
}
public function resolve(string $section, string $data): ?ResolvedReference
{
if (! isset($this->references[$section])) {
$this->addMissingReferenceSectionError($section);
return null;
}
$reference = $this->references[$section];
$resolvedReference = $reference->resolve($this, $data);
if ($resolvedReference === null) {
$this->addInvalidLink(new InvalidLink($data));
if ($this->getMetaEntry() !== null) {
$this->getMetaEntry()->removeDependency(
// use the original name
$this->originalDependencyNames[$data] ?? $data
);
}
return null;
}
if (isset($this->unresolvedDependencies[$data]) && $this->getMetaEntry() !== null) {
$this->getMetaEntry()->resolveDependency(
// use the unique, unresolved name
$this->unresolvedDependencies[$data],
$resolvedReference->getFile()
);
}
return $resolvedReference;
}
public function addInvalidLink(InvalidLink $invalidLink): void
{
$this->invalidLinks[] = $invalidLink;
}
/** @return InvalidLink[] */
public function getInvalidLinks(): array
{
return $this->invalidLinks;
}
/** @return string[]|null */
public function found(string $section, string $data): ?array
{
if (isset($this->references[$section])) {
$reference = $this->references[$section];
$reference->found($this, $data);
return null;
}
$this->addMissingReferenceSectionError($section);
return null;
}
/** @param mixed $value */
public function setVariable(string $variable, $value): void
{
$this->variables[$variable] = $value;
}
public function createTitle(int $level): string
{
for ($currentLevel = 0; $currentLevel < 16; $currentLevel++) {
if ($currentLevel <= $level) {
continue;
}
$this->levels[$currentLevel] = 1;
$this->counters[$currentLevel] = 0;
}
$this->levels[$level] = 1;
$this->counters[$level]++;
$token = ['title'];
for ($i = 1; $i <= $level; $i++) {
$token[] = $this->counters[$i];
}
return implode('.', $token);
}
public function getNumber(int $level): int
{
return $this->levels[$level]++;
}
/**
* @param mixed|null $default
*
* @return mixed
*/
public function getVariable(string $variable, $default = null)
{
if (isset($this->variables[$variable])) {
return $this->variables[$variable];
}
return $default;
}
public function setLink(string $name, string $url): void
{
$name = trim(strtolower($name));
if ($name === '_') {
$name = array_shift($this->anonymous);
}
$this->links[$name] = trim($url);
}
public function resetAnonymousStack(): void
{
$this->anonymous = [];
}
public function pushAnonymous(string $name): void
{
$this->anonymous[] = trim(strtolower($name));
}
/** @return string[] */
public function getLinks(): array
{
return $this->links;
}
public function getLink(string $name, bool $relative = true): string
{
$name = trim(strtolower($name));
if (isset($this->links[$name])) {
$link = $this->links[$name];
if ($relative) {
return (string) $this->relativeUrl($link);
}
return $link;
}
return '';
}
public function addDependency(string $dependency, bool $requiresResolving = false): void
{
if ($requiresResolving) {
// a hack to avoid collisions between resolved and unresolved dependencies
$dependencyName = 'UNRESOLVED__' . $dependency;
$this->unresolvedDependencies[$dependency] = $dependencyName;
// map the original dependency name to the one that will be stored
$this->originalDependencyNames[$dependency] = $dependencyName;
} else {
// the dependency is already a filename, probably a :doc:
// or from a toc-tree - change it to the canonical URL
$canonicalDependency = $this->canonicalUrl($dependency);
if ($canonicalDependency === null) {
throw new InvalidArgumentException(sprintf(
'Could not get canonical url for dependency %s',
$dependency
));
}
$dependencyName = $canonicalDependency;
// map the original dependency name to the one that will be stored
$this->originalDependencyNames[$dependency] = $canonicalDependency;
}
if (in_array($dependencyName, $this->dependencies, true)) {
return;
}
$this->dependencies[] = $dependencyName;
}
/** @return string[] */
public function getDependencies(): array
{
return $this->dependencies;
}
public function relativeUrl(?string $url): ?string
{
return $this->urlGenerator->relativeUrl($url, $this->currentFileName);
}
public function absoluteUrl(string $url): string
{
return $this->urlGenerator->absoluteUrl($this->getDirName(), $url);
}
public function canonicalUrl(string $url): ?string
{
return $this->urlGenerator->canonicalUrl($this->getDirName(), $url);
}
public function generateUrl(string $path): string
{
return $this->urlGenerator->generateUrl(
$path,
$this->currentFileName,
$this->getDirName()
);
}
public function getDirName(): string
{
$dirname = dirname($this->currentFileName);
if ($dirname === '.') {
return '';
}
return $dirname;
}
public function setCurrentFileName(string $filename): void
{
$this->currentFileName = $filename;
}
/**
* Returns the currently-parsed filename.
*
* This is relative to the root source directory and without
* the extension (e.g. "index" or "subdir/file")
*/
public function getCurrentFileName(): string
{
return $this->currentFileName;
}
public function setCurrentDirectory(string $directory): void
{
$this->currentDirectory = $directory;
}
public function getCurrentDirectory(): string
{
return $this->currentDirectory;
}
public function absoluteRelativePath(string $url): string
{
return $this->currentDirectory . '/' . $this->getDirName() . '/' . $this->relativeUrl($url);
}
public function setTargetDirectory(string $directory): void
{
$this->targetDirectory = $directory;
}
public function getTargetDirectory(): string
{
return $this->targetDirectory;
}
public function getUrl(): string
{
if ($this->url !== null) {
return $this->url;
}
return $this->currentFileName;
}
public function setUrl(string $url): void
{
if ($this->getDirName() !== '') {
$url = $this->getDirName() . '/' . $url;
}
$this->url = $url;
}
public function getMetas(): Metas
{
return $this->metas;
}
public function getMetaEntry(): ?MetaEntry
{
return $this->metas->get($this->currentFileName);
}
public function getLevel(string $letter): int
{
foreach ($this->titleLetters as $level => $titleLetter) {
if ($letter === $titleLetter) {
return $level;
}
}
$this->currentTitleLevel++;
$this->titleLetters[$this->currentTitleLevel] = $letter;
return $this->currentTitleLevel;
}
/** @return string[] */
public function getTitleLetters(): array
{
return $this->titleLetters;
}
public static function slugify(string $text): string
{
return (new AsciiSlugger('en', []))->slug($text)->lower()->toString();
}
private function addMissingReferenceSectionError(string $section): void
{
$this->errorManager->error(
sprintf('Unknown reference section "%s"', $section),
$this->getCurrentFileName()
);
}
}