Repository: symfony/symfony
File: src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php (PHP)

Code before:
            preg_match('/^(\d+)\.(\d+)\.(\d+)/', InstalledVersions::getVersion($package) ?? '', $m);
        }

        return $this->attribute('docUrl', strtr($uri, [
            '{package}' => $package ?? '',
            '{version:major}' => $m[1] ?? '',
            '{version:minor}' => $m[2] ?? '',
        ]));
    }

    /**
     * Sets an attribute on the node.
     *
     * @return $this
     */
    public function attribute(string $key, mixed $value): static
    {
        $this->attributes[$key] = $value;

        return $this;
    }

    /**
     * Returns the parent node.
     *
     * @return TParent&NodeParentInterface
     */
    public function end(): NodeParentInterface
    {
        return $this->parent;
    }

    /**
     * Creates the node.
     */
    public function getNode(bool $forceRootNode = false): NodeInterface
    {
        if ($forceRootNode) {
            $this->parent = null;
        }

        if (isset($this->normalization)) {
            $allowedTypes = [];
            foreach ($this->normalization->before as $expr) {
                $allowedTypes[] = $expr->allowedTypes;
            }
            $allowedTypes = array_unique($allowedTypes);
            $this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
            $this->normalization->declaredTypes = $allowedTypes;
        }


Review comment (bug):
You code is actually broken in case you call `->end()` on a node without parent, but with a TypeError instead of a proper exception, because the property is nullable.
In 6.4, the return type was properly nullable: https://github.com/symfony/symfony/blob/4a758887c4cfd091d3e0edc51605770332aa578a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php#L94
Logically, we should be returning `TParent` here.

Code after:
    {
        if ($package) {
            preg_match('/^(\d+)\.(\d+)\.(\d+)/', InstalledVersions::getVersion($package) ?? '', $m);
        }

        return $this->attribute('docUrl', strtr($uri, [
            '{package}' => $package ?? '',
            '{version:major}' => $m[1] ?? '',
            '{version:minor}' => $m[2] ?? '',
        ]));
    }

    /**
     * Sets an attribute on the node.
     *
     * @return $this
     */
    public function attribute(string $key, mixed $value): static
    {
        $this->attributes[$key] = $value;

        return $this;
    }

    /**
     * Returns the parent node.
     *
     * @return TParent
     */
    public function end(): ?NodeParentInterface
    {
        return $this->parent;
    }

    /**
     * Creates the node.
     */
    public function getNode(bool $forceRootNode = false): NodeInterface
    {
        if ($forceRootNode) {
            $this->parent = null;
        }

        if (isset($this->normalization)) {
            $allowedTypes = [];
            foreach ($this->normalization->before as $expr) {
                $allowedTypes[] = $expr->allowedTypes;
            }
            $allowedTypes = array_unique($allowedTypes);
            $this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
            $this->normalization->declaredTypes = $allowedTypes;