diff --git a/.github/workflows/push.yml b/.github/workflows/push.yml
index 38013d0..a356eef 100644
--- a/.github/workflows/push.yml
+++ b/.github/workflows/push.yml
@@ -1,175 +1,52 @@
-on:
- push:
- branches:
- - master
- pull_request:
-name: Qa workflow
-env:
- extensions: mbstring, intl, iconv, libxml, dom, json, simplexml, zlib, fileinfo
- key: cache-v1 # can be any string, change to clear the extension cache.
- defaultPHPVersion: '7.3'
-jobs:
- phpunit-with-coverage:
- runs-on: ubuntu-latest
- name: Unit tests
- steps:
- - uses: actions/checkout@v2
-
- - name: Install graphviz
- run: sudo apt-get update && sudo apt-get install -y graphviz
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ env.defaultPHPVersion }}
- ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
- tools: phive
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache composer dependencies
- uses: actions/cache@v2
- with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: composer-${{ hashFiles('**/composer.lock') }}
- restore-keys: composer-
-
- - name: Install Composer dependencies
- run: |
- composer install --no-progress --prefer-dist --optimize-autoloader
-
- - name: Run PHPUnit
- run: php vendor/bin/phpunit
-
- phpunit:
- runs-on: ${{ matrix.operating-system }}
- strategy:
- matrix:
- operating-system:
- - ubuntu-latest
- php-versions: ['7.2', '7.3', '7.4', '8.0', '8.1']
- name: Unit tests for PHP version ${{ matrix.php-versions }} on ${{ matrix.operating-system }}
- needs:
- - phpunit-with-coverage
- steps:
- - uses: actions/checkout@v2
-
- - name: Install graphviz
- run: sudo apt-get update && sudo apt-get install -y graphviz
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ matrix.php-versions }}
- extension-csv: mbstring, simplexml
- ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache composer dependencies
- uses: actions/cache@v2
- with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: composer-${{ hashFiles('**/composer.lock') }}
- restore-keys: composer-
+# https://docs.github.com/en/actions
- - name: Install Composer dependencies
- run: |
- composer install --no-progress --prefer-dist --optimize-autoloader
+name: "Integrate"
- - name: Run PHPUnit
- run: php vendor/bin/phpunit
-
- codestyle:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Restore/cache vendor folder
- uses: actions/cache@v1
- with:
- path: vendor
- key: all-build-${{ hashFiles('**/composer.lock') }}
- restore-keys: |
- all-build-${{ hashFiles('**/composer.lock') }}
- all-build-
- - name: Restore/cache tools folder
- uses: actions/cache@v1
- with:
- path: tools
- key: all-tools-${{ github.sha }}
- restore-keys: |
- all-tools-${{ github.sha }}-
- all-tools-
- - name: Code style check
- uses: docker://phpdoc/phpcs-ga:latest
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- args: -d memory_limit=1024M
-
- phpstan:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: ${{ env.defaultPHPVersion }}
- ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
- tools: pecl
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache composer dependencies
- uses: actions/cache@v2
- with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: composer-${{ hashFiles('**/composer.lock') }}
- restore-keys: composer-
-
- - name: Install Composer dependencies
- run: |
- composer install --no-progress --prefer-dist --optimize-autoloader
-
- - name: PHPStan
- uses: phpDocumentor/phpstan-ga@master
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- with:
- args: analyse src tests --configuration phpstan.neon
-
- psalm:
- runs-on: ubuntu-latest
- steps:
- - uses: actions/checkout@v2
-
- - name: Setup PHP
- uses: shivammathur/setup-php@v2
- with:
- php-version: 7.3
- ini-values: memory_limit=2G, display_errors=On, error_reporting=-1
- tools: pecl, psalm
-
- - name: Get composer cache directory
- id: composer-cache
- run: echo "::set-output name=dir::$(composer config cache-files-dir)"
-
- - name: Cache composer dependencies
- uses: actions/cache@v2
- with:
- path: ${{ steps.composer-cache.outputs.dir }}
- key: composer-${{ hashFiles('**/composer.lock') }}
- restore-keys: composer-
-
- - name: Install Composer dependencies
- run: |
- composer install --no-progress --prefer-dist --optimize-autoloader
+on: # yamllint disable-line rule:truthy
+ push:
+ branches:
+ - "master"
+ pull_request: null
+ schedule:
+ - cron: "0 14 * * 1"
+ # Allow manually triggering the workflow.
+ workflow_dispatch: true
- - name: Psalm
- run: vendor/bin/psalm.phar --output-format=github
+jobs:
+ code-coverage:
+ name: "Code Coverage"
+ uses: "phpDocumentor/.github/.github/workflows/code-coverage.yml@main"
+ with:
+ composer-root-version: "1.x-dev"
+
+ coding-standards:
+ name: "Coding Standards"
+ uses: "phpDocumentor/.github/.github/workflows/coding-standards.yml@v0.8"
+ with:
+ composer-root-version: "1.x-dev"
+
+ dependency-analysis:
+ name: "Dependency analysis"
+ uses: "phpDocumentor/.github/.github/workflows/dependency-analysis.yml@v0.8"
+ with:
+ composer-root-version: "1.x-dev"
+
+ lint-root:
+ name: "Lint root"
+ uses: "phpDocumentor/.github/.github/workflows/lint.yml@main"
+ with:
+ composer-options: "--no-check-publish --ansi"
+
+ static-analysis:
+ name: "Static analysis"
+ uses: "phpDocumentor/.github/.github/workflows/static-analysis.yml@v0.8"
+ with:
+ php-extensions: "none, ctype, dom, json, mbstring, phar, simplexml, tokenizer, xml, xmlwriter, fileinfo, pcntl, posix"
+ composer-root-version: "1.x-dev"
+
+ unit-tests:
+ name: "Unit test"
+ uses: "phpDocumentor/.github/.github/workflows/continuous-integration.yml@v0.8"
+ with:
+ composer-root-version: "1.x-dev"
+ upcoming-releases: true
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 0cd7a08..172d1ab 100644
--- a/Makefile
+++ b/Makefile
@@ -14,21 +14,26 @@ setup: install-phive
phpcbf:
docker run -it --rm -v${CURDIR}:/opt/project -w /opt/project phpdoc/phpcs-ga:latest phpcbf ${ARGS}
+
+.PHONY: build-test-image
+build-test-image:
+ docker build -t php-graphviz -f tests/Resources/Dockerfile tests/Resources
+
.PHONY: phpcs
-phpcs:
- docker run -it --rm -v${PWD}:/opt/project -w /opt/project phpdoc/phpcs-ga:latest -d memory_limit=1024M -s
+phpcs: build-test-image
+ docker run -it --rm -v${CURDIR}:/data -w /data php-graphviz vendor/bin/phpcs
.PHONY: phpstan
-phpstan:
- docker run -it --rm -v${CURDIR}:/opt/project -w /opt/project phpdoc/phpstan-ga:latest analyse src tests --configuration phpstan.neon ${ARGS}
+phpstan: build-test-image
+ docker run -it --rm -v${CURDIR}:/data -w /data php-graphviz ./vendor/phpstan/phpstan/phpstan analyse src ${ARGS}
.PHONY: psalm
-psalm:
- docker run -it --rm -v${CURDIR}:/data -w /data php:7.3 vendor/bin/psalm.phar
+psalm: build-test-image
+ docker run -it --rm -v${CURDIR}:/data -w /data php-graphviz vendor/bin/psalm.phar
.PHONY: test
-test:
- docker run -it --rm -v${PWD}:/opt/project -w /opt/project php:7.3 vendor/bin/phpunit
+test: build-test-image
+ docker run -it --rm -v${PWD}:/opt/project -w /opt/project php-graphviz ./vendor/bin/phpunit
.PHONY: pre-commit-test
pre-commit-test: phpcs phpstan psalm test
diff --git a/README.md b/README.md
index 57d9ab6..3e3f898 100644
--- a/README.md
+++ b/README.md
@@ -13,15 +13,3 @@ GraphViz
GraphViz is a library meant for generating .dot files for GraphViz with a
fluent interface.
-
-
-### PHPStan extension
-
-This library contains a number of magic methods to set attributes on `Node`, `Graph` and `Edge`
-this will result in errors when using the library with checks by PHPStan. For your convenience this
-library provides an phpStan extension so your code can be checked correctly by phpstan.
-
-```
-includes:
- - vendor/phpdocumentor/graphviz/extension.neon
-```
diff --git a/composer.json b/composer.json
index 82fbbb8..72302f6 100644
--- a/composer.json
+++ b/composer.json
@@ -10,30 +10,35 @@
}
],
"require": {
- "php": "^7.2 || ^8.0"
+ "php": "^8.2"
},
"autoload": {
"psr-4": {
- "phpDocumentor\\GraphViz\\": "src/phpDocumentor/GraphViz",
- "phpDocumentor\\GraphViz\\PHPStan\\": "./src/phpDocumentor/PHPStan"
+ "phpDocumentor\\GraphViz\\": "src/phpDocumentor/GraphViz"
}
},
"autoload-dev": {
"psr-4": {
- "phpDocumentor\\GraphViz\\Test\\": "./tests/phpDocumentor/GraphViz/Test",
- "phpDocumentor\\GraphViz\\PHPStan\\": "./tests/phpDocumentor/PHPStan"
+ "phpDocumentor\\GraphViz\\Test\\": "./tests/phpDocumentor/GraphViz/Test"
}
},
"require-dev": {
- "phpunit/phpunit": "^8.2 || ^9.2",
- "mockery/mockery": "^1.2",
- "phpstan/phpstan": "^0.12",
+ "phpunit/phpunit": "^11.0",
+ "mockery/mockery": "@stable",
+ "phpstan/phpstan": "@stable",
"ext-simplexml": "*",
- "psalm/phar": "^4.15 || ^5.0"
+ "psalm/phar": "@stable",
+ "squizlabs/php_codesniffer": "@stable",
+ "phpstan/phpstan-mockery": "@stable"
},
"extra": {
"branch-alias": {
- "dev-master": "2.x-dev"
+ "dev-master": "3.x-dev"
+ }
+ },
+ "config": {
+ "allow-plugins": {
+ "ondrejmirtes/composer-attribute-collector": true
}
}
}
diff --git a/extension.neon b/extension.neon
deleted file mode 100644
index 5f52740..0000000
--- a/extension.neon
+++ /dev/null
@@ -1,9 +0,0 @@
-services:
- -
- class: phpDocumentor\GraphViz\PHPStan\MethodReflectionExtension
- tags:
- - phpstan.broker.methodsClassReflectionExtension
- -
- class: phpDocumentor\GraphViz\PHPStan\GraphNodeReflectionExtension
- tags:
- - phpstan.broker.propertiesClassReflectionExtension
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index 9d79b69..cf20d87 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -6,9 +6,6 @@
tests
-
-
-
tests/phpDocumentor/GraphViz/Test/GraphTest\.php
diff --git a/phpstan.neon b/phpstan.neon
index b9e02dd..4ee6ecc 100644
--- a/phpstan.neon
+++ b/phpstan.neon
@@ -1,12 +1,8 @@
includes:
- - /composer/vendor/phpstan/phpstan-mockery/extension.neon
- - ./extension.neon
+ - ./vendor/phpstan/phpstan-mockery/extension.neon
parameters:
level: max
ignoreErrors:
#We have some runtime protection that needs to be tested. Ignore these errors
- - '#Call to an undefined method phpDocumentor\\GraphViz\\Edge::someNonExcistingMethod\(\)\.#'
- - '#Call to an undefined method phpDocumentor\\GraphViz\\Graph::MyMethod\(\)\.#'
- - '#Call to an undefined method phpDocumentor\\GraphViz\\Graph::getNotExisting\(\)\.#'
- - '#Call to an undefined method phpDocumentor\\GraphViz\\Node::someNonExistingMethod\(\)\.#'
+ - '#Cannot cast mixed to string#'
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 98c74be..2650a22 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -16,9 +16,6 @@
./tests/phpDocumentor/GraphViz
-
- ./tests/phpDocumentor/PHPStan
-
diff --git a/psalm.xml b/psalm.xml
index 18636c6..d8c8cae 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -1,6 +1,5 @@
+
+
diff --git a/src/phpDocumentor/GraphViz/Attribute.php b/src/phpDocumentor/GraphViz/Attribute.php
index d55f35a..a6257e2 100644
--- a/src/phpDocumentor/GraphViz/Attribute.php
+++ b/src/phpDocumentor/GraphViz/Attribute.php
@@ -21,14 +21,16 @@
* Class representing a single GraphViz attribute.
*
* @link http://phpdoc.org
+ *
+ * @psalm-suppress ClassMustBeFinal
*/
class Attribute
{
- /** @var string The name of this attribute */
- protected $key = '';
+ /** The name of this attribute */
+ protected string $key = '';
- /** @var string The value of this attribute */
- protected $value = '';
+ /** The value of this attribute */
+ protected string $value = '';
/**
* Creating a new attribute.
diff --git a/src/phpDocumentor/GraphViz/AttributeNotFound.php b/src/phpDocumentor/GraphViz/AttributeNotFound.php
index fe6b568..a6b782a 100644
--- a/src/phpDocumentor/GraphViz/AttributeNotFound.php
+++ b/src/phpDocumentor/GraphViz/AttributeNotFound.php
@@ -15,6 +15,9 @@
use function sprintf;
+/**
+ * @psalm-suppress ClassMustBeFinal
+ */
class AttributeNotFound extends Exception
{
public function __construct(string $name)
diff --git a/src/phpDocumentor/GraphViz/Attributes.php b/src/phpDocumentor/GraphViz/Attributes.php
index 4b42896..005d1d0 100644
--- a/src/phpDocumentor/GraphViz/Attributes.php
+++ b/src/phpDocumentor/GraphViz/Attributes.php
@@ -18,11 +18,11 @@
trait Attributes
{
/** @var Attribute[] */
- protected $attributes = [];
+ protected array $attributes = [];
- public function setAttribute(string $name, string $value): self
+ public function setAttribute(string $name, string|int|float|\Stringable $value): self
{
- $this->attributes[$name] = new Attribute($name, $value);
+ $this->attributes[$name] = new Attribute($name, (string) $value);
return $this;
}
@@ -38,4 +38,41 @@ public function getAttribute(string $name): Attribute
return $this->attributes[$name];
}
+
+ /**
+ * Magic method to provide a getter/setter to add attributes on the Node.
+ *
+ * Using this method we make sure that we support any attribute without
+ * too much hassle. If the name for this method does not start with get or
+ * set we return null.
+ *
+ * Set methods return this graph (fluent interface) whilst get methods
+ * return the attribute value.
+ *
+ * @param string $name Method name; either getX or setX is expected.
+ * @param mixed[] $arguments List of arguments; only 1 is expected for setX.
+ *
+ * @throws AttributeNotFound
+ *
+ * @psalm-suppress PossiblyUnusedReturnValue
+ */
+ public function __call(string $name, array $arguments): mixed
+ {
+ $key = $this->normalizeKey(substr($name, 3));
+ $action = strtolower(substr($name, 0, 3));
+ if ($action === 'set') {
+ return $this->setAttribute($key, (string) $arguments[0]);
+ }
+
+ if ($action === 'get') {
+ return $this->getAttribute($key);
+ }
+
+ return null;
+ }
+
+ private function normalizeKey(string $key): string
+ {
+ return lcfirst($key);
+ }
}
diff --git a/src/phpDocumentor/GraphViz/Edge.php b/src/phpDocumentor/GraphViz/Edge.php
index 0606087..82116dd 100644
--- a/src/phpDocumentor/GraphViz/Edge.php
+++ b/src/phpDocumentor/GraphViz/Edge.php
@@ -22,16 +22,18 @@
* Class representing an edge (arrow, line).
*
* @link http://phpdoc.org
+ *
+ * @psalm-suppress ClassMustBeFinal
*/
-class Edge
+class Edge implements \Stringable
{
use Attributes;
- /** @var Node Node from where to link */
- private $from;
+ /** Node from where to link */
+ private Node $from;
- /** @var Node Node where to to link */
- private $to;
+ /** Node where to link */
+ private Node $to;
/**
* Creates a new Edge / Link between the given nodes.
@@ -76,38 +78,6 @@ public function getTo(): Node
return $this->to;
}
- /**
- * Magic method to provide a getter/setter to add attributes on the edge.
- *
- * Using this method we make sure that we support any attribute without too
- * much hassle. If the name for this method does not start with get or set
- * we return null.
- *
- * Set methods return this graph (fluent interface) whilst get methods
- * return the attribute value.
- *
- * @param string $name name of the invoked method, expect it to be
- * setX or getX.
- * @param mixed[] $arguments Arguments for the setter, only 1 is expected: value
- *
- * @return Attribute|Edge|null
- *
- * @throws AttributeNotFound
- */
- public function __call(string $name, array $arguments)
- {
- $key = strtolower(substr($name, 3));
- if (strtolower(substr($name, 0, 3)) === 'set') {
- return $this->setAttribute($key, (string) $arguments[0]);
- }
-
- if (strtolower(substr($name, 0, 3)) === 'get') {
- return $this->getAttribute($key);
- }
-
- return null;
- }
-
/**
* Returns the edge definition as is requested by GraphViz.
*/
@@ -124,8 +94,8 @@ public function __toString(): string
$toName = addslashes($this->getTo()->getName());
return << "${toName}" [
-${attributes}
+"{$fromName}" -> "{$toName}" [
+{$attributes}
]
DOT;
}
diff --git a/src/phpDocumentor/GraphViz/Graph.php b/src/phpDocumentor/GraphViz/Graph.php
index f848d06..212be28 100644
--- a/src/phpDocumentor/GraphViz/Graph.php
+++ b/src/phpDocumentor/GraphViz/Graph.php
@@ -45,31 +45,33 @@
* @method Graph setRankDir(string $rankDir)
* @method Graph setSplines(string $splines)
* @method Graph setConcentrate(string $concentrate)
+ *
+ * @psalm-suppress ClassMustBeFinal
*/
-class Graph
+class Graph implements \Stringable
{
use Attributes;
- /** @var string Name of this graph */
- protected $name = 'G';
+ /** Name of this graph */
+ protected string $name = 'G';
- /** @var string Type of this graph; may be digraph, graph or subgraph */
- protected $type = 'digraph';
+ /** Type of this graph; may be digraph, graph or subgraph */
+ protected string $type = 'digraph';
- /** @var bool If the graph is strict then multiple edges are not allowed between the same pairs of nodes */
- protected $strict = false;
+ /** If the graph is strict then multiple edges are not allowed between the same pairs of nodes */
+ protected bool $strict = false;
/** @var Graph[] A list of subgraphs for this Graph */
- protected $graphs = [];
+ protected array $graphs = [];
/** @var Node[] A list of nodes for this Graph */
- protected $nodes = [];
+ protected array $nodes = [];
/** @var Edge[] A list of edges / arrows for this Graph */
- protected $edges = [];
+ protected array $edges = [];
- /** @var string The path to execute dot from */
- protected $path = '';
+ /** The path to execute dot from */
+ protected string $path = '';
/**
* Factory method to instantiate a Graph so that you can use fluent coding
@@ -174,37 +176,6 @@ public function isStrict(): bool
return $this->strict;
}
- /**
- * Magic method to provide a getter/setter to add attributes on the Graph.
- *
- * Using this method we make sure that we support any attribute without
- * too much hassle. If the name for this method does not start with get
- * or set we return null.
- *
- * Set methods return this graph (fluent interface) whilst get methods
- * return the attribute value.
- *
- * @param string $name Name of the method including get/set
- * @param mixed[] $arguments The arguments, should be 1: the value
- *
- * @return Attribute|Graph|null
- *
- * @throws AttributeNotFound
- */
- public function __call(string $name, array $arguments)
- {
- $key = strtolower(substr($name, 3));
- if (strtolower(substr($name, 0, 3)) === 'set') {
- return $this->setAttribute($key, (string) $arguments[0]);
- }
-
- if (strtolower(substr($name, 0, 3)) === 'get') {
- return $this->getAttribute($key);
- }
-
- return null;
- }
-
/**
* Adds a subgraph to this graph; automatically changes the type to subgraph.
*
@@ -262,6 +233,15 @@ public function setNode(Node $node): self
return $this;
}
+ public function getNode(string $name): Node
+ {
+ if (!isset($this->nodes[$name])) {
+ throw new \LogicException("Node with name '$name' does not exist in this graph.");
+ }
+
+ return $this->nodes[$name];
+ }
+
/**
* Finds a node in this graph or any of its subgraphs.
*
@@ -351,7 +331,7 @@ public function export(string $type, string $filename): self
// create the dot output
$output = [];
$code = 0;
- exec($this->path . "dot -T${type} -o${filename} < ${tmpfileArg} 2>&1", $output, $code);
+ exec($this->path . "dot -T{$type} -o{$filename} < {$tmpfileArg} 2>&1", $output, $code);
unlink($tmpfile);
if ($code !== 0) {
@@ -390,7 +370,7 @@ public function __toString(): string
return <<getType()} "{$this->getName()}" {
-${attributes}
+{$attributes}
}
DOT;
}
diff --git a/src/phpDocumentor/GraphViz/Node.php b/src/phpDocumentor/GraphViz/Node.php
index 4956802..5a446d1 100644
--- a/src/phpDocumentor/GraphViz/Node.php
+++ b/src/phpDocumentor/GraphViz/Node.php
@@ -24,13 +24,15 @@
* @link http://phpdoc.org
*
* @method void setLabel(string $name) Sets the label for this node.
+ *
+ * @psalm-suppress ClassMustBeFinal
*/
-class Node
+class Node implements \Stringable
{
use Attributes;
- /** @var string Name for this node */
- protected $name = '';
+ /** Name for this node */
+ protected string $name = '';
/**
* Creates a new node with name and optional label.
@@ -83,37 +85,6 @@ public function getName(): string
return $this->name;
}
- /**
- * Magic method to provide a getter/setter to add attributes on the Node.
- *
- * Using this method we make sure that we support any attribute without
- * too much hassle. If the name for this method does not start with get or
- * set we return null.
- *
- * Set methods return this graph (fluent interface) whilst get methods
- * return the attribute value.
- *
- * @param string $name Method name; either getX or setX is expected.
- * @param mixed[] $arguments List of arguments; only 1 is expected for setX.
- *
- * @return Attribute|Node|null
- *
- * @throws AttributeNotFound
- */
- public function __call(string $name, array $arguments)
- {
- $key = strtolower(substr($name, 3));
- if (strtolower(substr($name, 0, 3)) === 'set') {
- return $this->setAttribute($key, (string) $arguments[0]);
- }
-
- if (strtolower(substr($name, 0, 3)) === 'get') {
- return $this->getAttribute($key);
- }
-
- return null;
- }
-
/**
* Returns the node definition as is requested by GraphViz.
*/
@@ -130,7 +101,7 @@ public function __toString(): string
return <<classReflection = $classReflection;
- $this->name = $name;
- }
-
- public function getDeclaringClass(): ClassReflection
- {
- return $this->classReflection;
- }
-
- public function isStatic(): bool
- {
- return false;
- }
-
- public function isPrivate(): bool
- {
- return false;
- }
-
- public function isPublic(): bool
- {
- return true;
- }
-
- public function getName(): string
- {
- return $this->name;
- }
-
- public function getPrototype(): ClassMemberReflection
- {
- return $this;
- }
-
- /**
- * @return ParametersAcceptor[]
- */
- public function getVariants(): array
- {
- return [
- new FunctionVariant(
- TemplateTypeMap::createEmpty(),
- null,
- [],
- false,
- new ObjectType(Attribute::class)
- ),
- ];
- }
-
- public function getDocComment(): ?string
- {
- return null;
- }
-
- public function isDeprecated(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function getDeprecatedDescription(): ?string
- {
- return null;
- }
-
- public function isFinal(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function isInternal(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function getThrowType(): ?Type
- {
- return new ObjectType(AttributeNotFound::class);
- }
-
- public function hasSideEffects(): TrinaryLogic
- {
- return TrinaryLogic::createMaybe();
- }
-}
diff --git a/src/phpDocumentor/PHPStan/AttributeSetterMethodReflection.php b/src/phpDocumentor/PHPStan/AttributeSetterMethodReflection.php
deleted file mode 100644
index 961150a..0000000
--- a/src/phpDocumentor/PHPStan/AttributeSetterMethodReflection.php
+++ /dev/null
@@ -1,127 +0,0 @@
-classReflection = $classReflection;
- $this->name = $name;
- $this->attributeType = $attributeType;
- }
-
- public function getDeclaringClass(): ClassReflection
- {
- return $this->classReflection;
- }
-
- public function isStatic(): bool
- {
- return false;
- }
-
- public function isPrivate(): bool
- {
- return false;
- }
-
- public function isPublic(): bool
- {
- return true;
- }
-
- public function getName(): string
- {
- return $this->name;
- }
-
- public function getPrototype(): ClassMemberReflection
- {
- return $this;
- }
-
- /**
- * @return ParametersAcceptor[]
- */
- public function getVariants(): array
- {
- return [
- new FunctionVariant(
- TemplateTypeMap::createEmpty(),
- TemplateTypeMap::createEmpty(),
- [
- new DummyParameter('value', $this->attributeType, false, null, false, null),
- ],
- false,
- new ObjectType($this->classReflection->getName())
- ),
- ];
- }
-
- public function getDocComment(): ?string
- {
- return null;
- }
-
- public function isDeprecated(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function getDeprecatedDescription(): ?string
- {
- return null;
- }
-
- public function isFinal(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function isInternal(): TrinaryLogic
- {
- return TrinaryLogic::createNo();
- }
-
- public function getThrowType(): ?Type
- {
- return new ObjectType(AttributeNotFound::class);
- }
-
- public function hasSideEffects(): TrinaryLogic
- {
- return TrinaryLogic::createYes();
- }
-}
diff --git a/src/phpDocumentor/PHPStan/GraphNodeReflectionExtension.php b/src/phpDocumentor/PHPStan/GraphNodeReflectionExtension.php
deleted file mode 100644
index b6793e4..0000000
--- a/src/phpDocumentor/PHPStan/GraphNodeReflectionExtension.php
+++ /dev/null
@@ -1,40 +0,0 @@
-getName() === Graph::class;
- }
-
- public function getProperty(ClassReflection $classReflection, string $propertyName): PropertyReflection
- {
- return new AnnotationPropertyReflection(
- $classReflection,
- new ObjectType(Node::class),
- true,
- true
- );
- }
-}
diff --git a/src/phpDocumentor/PHPStan/MethodReflectionExtension.php b/src/phpDocumentor/PHPStan/MethodReflectionExtension.php
deleted file mode 100644
index 951b3b8..0000000
--- a/src/phpDocumentor/PHPStan/MethodReflectionExtension.php
+++ /dev/null
@@ -1,143 +0,0 @@
- 'node',
- Graph::class => 'graph',
- Edge::class => 'edge',
- ];
-
- public function hasMethod(ClassReflection $classReflection, string $methodName): bool
- {
- if (!array_key_exists($classReflection->getName(), self::SUPPORTED_CLASSES)) {
- return false;
- }
-
- $methods = $this->getMethodsFromSpec(self::SUPPORTED_CLASSES[$classReflection->getName()]);
- $expectedAttribute = $this->getAttributeFromMethodName($methodName);
-
- return in_array($expectedAttribute, $methods, true);
- }
-
- public function getMethod(ClassReflection $classReflection, string $methodName): MethodReflection
- {
- if (stripos($methodName, 'get') === 0) {
- return new AttributeGetterMethodReflection($classReflection, $methodName);
- }
-
- $attributeName = $this->getAttributeFromMethodName($methodName);
-
- return new AttributeSetterMethodReflection(
- $classReflection,
- $methodName,
- $this->getAttributeInputType($attributeName)
- );
- }
-
- /**
- * @return string[]
- */
- private function getMethodsFromSpec(string $className): array
- {
- $simpleXml = $this->getAttributesXmlDoc();
-
- $elements = $simpleXml->xpath(sprintf("xsd:complexType[@name='%s']/xsd:attribute", $className));
-
- if ($elements === false) {
- throw new InvalidArgumentException(
- sprintf('Class "%s" does not exist in Graphviz spec', $className)
- );
- }
-
- return array_map(
- static function (SimpleXMLElement $attribute): string {
- return strtolower((string) $attribute['ref']);
- },
- $elements
- );
- }
-
- private function getAttributeInputType(string $ref): Type
- {
- $simpleXml = $this->getAttributesXmlDoc();
- $attributes = $simpleXml->xpath(sprintf("xsd:attribute[@name='%s']", $ref));
-
- if (empty($attributes)) {
- return new StringType();
- }
-
- $type = $attributes[0]['type'];
- $type = str_replace('xsd:', '', (string) $type);
- switch ($type) {
- case 'boolean':
- return new BooleanType();
-
- case 'decimal':
- return new FloatType();
-
- case 'string':
- default:
- return new StringType();
- }
- }
-
- private function getAttributesXmlDoc(): SimpleXMLElement
- {
- $fileContent = file_get_contents(__DIR__ . '/assets/attributes.xml');
-
- if ($fileContent === false) {
- throw new RuntimeException('Cannot read attributes spec');
- }
-
- $xml = simplexml_load_string($fileContent);
- if ($xml === false) {
- throw new RuntimeException('Cannot read attributes spec');
- }
-
- return $xml;
- }
-
- private function getAttributeFromMethodName(string $methodName): string
- {
- return strtolower(substr($methodName, 3));
- }
-}
diff --git a/src/phpDocumentor/PHPStan/assets/attributes.xml b/src/phpDocumentor/PHPStan/assets/attributes.xml
deleted file mode 100644
index 0d63e45..0000000
--- a/src/phpDocumentor/PHPStan/assets/attributes.xml
+++ /dev/null
@@ -1,2656 +0,0 @@
-
-
-
-
-
-
-
-
-
-
- All Graphviz attributes are specified by name-value pairs. Thus, to
- set the fillcolor of a node abc, one would use
-
-
- abc [fillcolor = red]
-
-
- Similarly, to set the arrowhead style of an edge abc -> def,
- one would use
-
-
- abc -> def [arrowhead = diamond]
-
-
- Further details concerning the setting of attributes can be found
- in the description of the
- DOT language.
-
-
-
-
-
-
- At present, most device-independent units are either inches or
- points,
- which we take as 72 points per inch.
-
-
-
-
-
-
-
-
- Some attributes, such as
- dir or arrowtail, are
- ambiguous when used in
- DOT
- with an undirected graph since the head and tail of an edge are meaningless.
- As a convention, the first time an undirected edge appears, the
- DOT
- parser will assign the left node as the tail node and the right node as
- the head. For example, the edge A -- B will have tail A
- and head B. It is the user's responsibility to handle such
- edges consistently. If the edge appears later, in the format
-
-
- B -- A [taillabel = "tail"]
-
-
- the drawing will attach the tail label to node A.
- To avoid possible confusion when such attributes are required, the user
- is encouraged to use a directed graph.
- If it is important to make the graph appear undirected, this can be
- done using the dir, arrowtail
- or arrowhead attributes.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- For undirected edges T -- H;, one of the nodes, usually
- the righthand one, is treated as the head for the purpose of
- interpreting forward and back.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- String allowing escape sequences which are replaced according
- to the context.
- For node attributes, the substring \N is replaced by the name of the node,
- and the substring \G by the name of the graph.
- For graph or cluster attributes, the substring \G is replaced by the
- name of the graph or cluster.
- For edge attributes, the substring \E is replaced by the name of the edge,
- the substring \G is replaced by the name of the graph or cluster,
- and the substrings \T and \H by the names of
- the tail and head nodes, respectively.
- The name of an edge is the string formed from the name of the
- tail node, the appropriate edge operator (-- or ->) and the name of the
- head node.
-
-
- In addition, if the associated attribute is
- label,
- headlabel or taillabel,
- the escape sequences \n, \l and \r
- divide the label into lines, centered, left-justified, and right-justified,
- respectively.
-
-
-
-
-
-
-
-
-
-
-
- These specify the order in which nodes and edges are drawn in concrete
- output. The default breadthfirst is the simplest, but when the graph
- layout does not avoid edge-node overlap, this mode will sometimes have
- edges drawn over nodes and sometimes on top of nodes. If the mode
- nodesfirst is chosen, all nodes are drawn first, followed by the
- edges. This guarantees an edge-node overlap will not be mistaken for
- an edge ending at a node. On the other hand, usually for aesthetic
- reasons, it may be desirable that all edges appear beneath nodes, even
- if the resulting drawing is ambiguous. This can be achieved by choosing
- edgesfirst.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- These specify the granularity of packing connected components when
- the pack attribute is true. A value of node causes
- packing at the node and edge label, with no overlapping of these objects.
- This produces a layout with the least area, but it also allows interleaving,
- where a node of one component may lie between two nodes in another
- component. A value of graph does a packing using the bounding box of the
- component. Thus, there will be a rectangular region around a component
- free of elements of any other component.
- A value of clust guarantees that top-level clusters are kept intact.
- What effect a value has also depends on the layout algorithm. For
- example, neato does not support clusters, so a value of clust will
- have the same effect as the default node value.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- These specify the 8 row or column major orders for traversing a
- rectangular array, the first character corresponding to the major
- order and the second to the minor order. Thus, for "BL", the
- major order is from bottom to top, and the minor order is from left
- to right. This means the bottom row is traversed first, from left
- to right, then the next row up, from left to right, and so on,
- until the topmost row is traversed.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- List of pointf, separated by spaces.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Corresponding to directed graphs drawn
- from top to bottom, from left to right, from bottom to top, and from
- right to left, respectively.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Specifies the path to images referenced within the graph.
-
-
-
-
-
-
-
-
-
- Factor damping force motions. On each iteration, a nodes movement
- is limited to this factor of its potential motion. By being less than
- 1.0, the system tends to "cool", thereby preventing cycling.
-
-
-
-
-
-
-
-
-
- Spring constant used in virtual physical model. It roughly corresponds
- to an ideal edge length (in inches), in that increasing K tends to
- increase the distance between nodes.
- Note that the edge attribute len can be used to
- override this value for adjacent nodes.
-
-
-
-
-
-
-
-
-
- Hyperlinks incorporated into device-dependent output.
- At present, used in ps2, cmap, i*map and svg formats.
- For all these formats, URLs can be attached to nodes, edges and
- clusters. URL attributes can also be attached to the root graph in ps2,
- cmap and i*map formats. This serves as the base URL for relative URLs in the
- former, and as the default image map file in the latter.
-
-
- For svg, cmapx and imap output, the active area for a node is its
- visible image.
- For example, an unfilled node with no drawn boundary will only be active on its label.
- For other output, the active area is its bounding box.
- The active area for a cluster is its bounding box.
- For edges, the active areas are small circles where the edge contacts its head
- and tail nodes. In addition, for svg, cmapx and imap, the active area
- includes a thin polygon approximating the edge. The circles may
- overlap the related node, and the edge URL dominates.
- If the edge has a label, this will also be active.
- Finally, if the edge has a head or tail label, this will also be active.
-
-
- Note that, for edges, the attributes headURL,
- tailURL, labelURL and
- edgeURL allow control of various parts of an
- edge. Also note that, if active areas of two edges overlap, it is unspecified
- which area dominates.
-
-
-
-
-
-
-
-
-
- Style of arrowhead on the head node of an edge.
- See also the dir attribute,
- and the undirected note.
-
-
-
-
-
-
-
-
-
- Multiplicative scale factor for arrowheads.
-
-
-
-
-
-
-
-
-
- Style of arrowhead on the tail node of an edge.
- See also the dir attribute,
- and the undirected note.
-
-
-
-
-
-
-
-
-
- Bounding box of drawing in integer points.
-
-
-
-
-
-
-
-
-
- When attached to the root graph, this color is used as the background for
- entire canvas. When a cluster attribute, it is used as the initial
- background for the cluster. If a cluster has a filled
- style, the
- cluster's fillcolor will overlay the
- background color.
-
-
- If no background color is specified for the root graph, no graphics
- operation are performed on the background. This works fine for
- PostScript but for bitmap output, all bits are initialized to something.
- This means that when the bitmap output is included in some other
- document, all of the bits within the bitmap's bounding box will be
- set, overwriting whatever color or graphics where already on the page.
- If this effect is not desired, and you only want to set bits explicitly
- assigned in drawing the graph, set bgcolor="transparent".
-
-
-
-
-
-
-
-
-
- If true, the drawing is centered in the output canvas.
-
-
-
-
-
-
-
-
-
- Specifies the character encoding used when interpreting string input
- as a text label. The default value is UTF-8.
- The other legal value is iso-8859-1 or,
- equivalently,
- Latin1. The charset attribute is case-insensitive.
- Note that if the character encoding used in the input does not
- match the charset value, the resulting output may be very strange.
-
-
-
-
-
-
-
-
-
- Mode used for handling clusters. If clusterrank is local, a
- subgraph whose name begins with "cluster" is given special treatment.
- The subgraph is laid out separately, and then integrated as a unit into
- its parent graph, with a bounding rectangle drawn about it.
- If the cluster has a label parameter, this label
- is displayed within the rectangle.
- Note also that there can be clusters within clusters.
- At present, the modes global and none
- appear to be identical, both turning off the special cluster processing.
-
-
-
-
-
-
-
-
-
- Basic drawing color for graphics, not text. For the latter, use the
- fontcolor attribute.
-
-
- For edges, the value
- can either be a single color or a colorList.
- In the latter case, the edge is drawn using parallel splines or lines,
- one for each color in the list, in the order given.
- The head arrow, if any, is drawn using the first color in the list,
- and the tail arrow, if any, the second color. This supports the common
- case of drawing opposing edges, but using parallel splines instead of
- separately routed multiedges.
-
-
-
-
-
-
-
-
-
- This attribute specifies a color scheme namespace. If defined, it specifies
- the context for interpreting color names. In particular, if a
- color value has form xxx or //xxx,
- then the color xxx will be evaluated according to the current color scheme.
- If no color scheme is set, the standard X11 naming is used.
- For example, if colorscheme=bugn9, then color=7
- is interpreted as /bugn9/7.
-
-
-
-
-
-
-
-
-
- Comments are inserted into output. Device-dependent.
-
-
-
-
-
-
-
-
-
- If true, allow edges between clusters. (See lhead and ltail below.)
-
-
-
-
-
-
-
-
-
- If true, use edge concentrators.
-
-
-
-
-
-
-
-
-
- If false, the edge is not used in ranking the nodes.
-
-
-
-
-
-
-
-
-
- If true, attach edge label to edge by a 2-segment
- polyline, underlining the label, then going to the closest point of spline.
-
-
-
-
-
-
-
-
-
- This specifies the distance between nodes in separate connected
- components. If set too small, connected components may overlap.
- Only applicable if pack=false.
-
-
-
-
-
-
-
-
-
- Set the number of dimensions used for the layout. The maximum value
- allowed is 10.
-
-
-
-
-
-
-
-
-
- Set edge type for drawing arrowheads. This indicates which ends of the
- edge should be decorated with an arrowhead. The actual style of the
- arrowhead can be specified using the arrowhead
- and arrowtail attributes.
- See undirected.
-
-
-
-
-
-
-
-
-
- Only valid when mode="ipsep".
- If true, constraints are generated for each edge in the largest (heuristic)
- directed acyclic subgraph such that the edge must point downwards.
- If hier, generates level constraints similar to those used with
- mode="hier". The main difference is that, in the latter
- case, only these constraints are involved, so a faster solver can be used.
-
-
-
-
-
-
-
-
-
- Distortion factor for shape=polygon.
- Positive values cause top part to
- be larger than bottom; negative values do the opposite.
-
-
-
-
-
-
-
-
-
- This specifies the expected number of pixels per inch on a display device.
- For bitmap output, this guarantees that text rendering will be
- done more accurately, both in size and in placement. For SVG output,
- it is used to guarantee that the dimensions in the output correspond to
- the correct number of points or inches.
-
-
-
-
-
-
-
-
-
- If edgeURL is defined, this is the link used for the non-label
- parts of an edge. This value overrides any URL
- defined for the edge.
- Also, this value is used near the head or tail node unless overridden
- by a headURL or tailURL value,
- respectively.
- See undirected.
-
-
-
-
-
-
-
-
-
- Synonym for edgeURL.
-
-
-
-
-
-
-
-
-
- If the edge has a URL or edgeURL
- attribute, this attribute determines which window of the
- browser is used
- for the URL attached to the non-label part of the edge.
- Setting it to "_graphviz" will open a new window if it
- doesn't already exist, or reuse it if it does.
- If undefined, the value of the target is used.
-
-
-
-
-
-
-
-
-
- Tooltip annotation attached to the non-label part of an edge.
- This is used only if the edge has a URL
- or edgeURL attribute.
-
-
-
-
-
-
-
-
-
- Terminating condition. If the length squared of all energy gradients are
- < epsilon, the algorithm stops.
-
-
-
-
-
-
-
-
-
- Fraction to increase polygons (multiply
- coordinates by 1 + esep) for purposes of spline edge routing.
- This should normally be strictly less than
- sep.
-
-
-
-
-
-
-
-
-
- Color used to fill the background of a node or cluster
- assuming style=filled.
- If fillcolor is not defined, color is
- used. (For clusters, if color is not defined,
- bgcolor is used.) If this is not defined,
- the default is used, except for
- shape=point or when the output
- format is MIF,
- which use black by default.
-
-
- Note that a cluster inherits the root graph's attributes if defined.
- Thus, if the root graph has defined a fillcolor, this will override a
- color or bgcolor attribute set for the cluster.
-
-
-
-
-
-
-
-
-
- If true, the node size is specified by the values of the
- width
- and height attributes only
- and is not expanded to contain the text label.
-
-
-
-
-
-
-
-
-
- Color used for text.
-
-
-
-
-
-
-
-
-
- Font used for text. This very much depends on the output format and, for
- non-bitmap output such as PostScript or SVG, the availability of the font
- when the graph is displayed or printed. As such, it is best to rely on
- font faces that are generally available, such as Times-Roman, Helvetica or
- Courier.
-
-
- If Graphviz was built using the
- fontconfig library, the latter library
- will be used to search for the font. However, if the fontname string
- contains a slash character "/", it is treated as a pathname for the font
- file, though font lookup will append the usual font suffixes.
-
-
- If Graphviz does not use fontconfig, fontname will be
- considered the name of a Type 1 or True Type font file.
- If you specify fontname=schlbk, the tool will look for a
- file named schlbk.ttf or schlbk.pfa or schlbk.pfb
- in one of the directories specified by
- the fontpath attribute.
- The lookup does support various aliases for the common fonts.
-
-
-
-
-
-
-
-
-
- Allows user control of how basic fontnames are represented in SVG output.
- If fontnames is undefined or svg,
- the output will try to use known SVG fontnames. For example, the
- default font Times-Roman will be mapped to the
- basic SVG font serif. This can be overridden by setting
- fontnames to ps or gd.
- In the former case, known PostScript font names such as
- Times-Roman will be used in the output.
- In the latter case, the fontconfig font conventions
- are used. Thus, Times-Roman would be treated as
- Nimbus Roman No9 L. These last two options are useful
- with SVG viewers that support these richer fontname spaces.
-
-
-
-
-
-
-
-
-
- Directory list used by libgd to search for bitmap fonts if Graphviz
- was not built with the fontconfig library.
- If fontpath is not set, the environment
- variable DOTFONTPATH is checked.
- If that is not set, GDFONTPATH is checked.
- If not set, libgd uses its compiled-in font path.
- Note that fontpath is an attribute of the root graph.
-
-
-
-
-
-
-
-
-
- Font size, in points, used for text.
-
-
-
-
-
-
-
-
-
- If the end points of an edge belong to the same group, i.e., have the
- same group attribute, parameters are set to avoid crossings and keep
- the edges straight.
-
-
-
-
-
-
-
-
-
- If headURL is defined, it is
- output as part of the head label of the edge.
- Also, this value is used near the head node, overriding any
- URL value.
- See undirected.
-
-
-
-
-
-
-
-
-
- If true, the head of an edge is clipped to the boundary of the head node;
- otherwise, the end of the edge goes to the center of the node, or the
- center of a port, if applicable.
-
-
-
-
-
-
-
-
-
- Synonym for headURL.
-
-
-
-
-
-
-
-
-
- Text label to be placed near head of edge.
- See undirected.
-
-
-
-
-
-
-
-
-
- Indicates where on the head node to attach the head of the edge.
- In the default case, the edge is aimed towards the center of the node,
- and then clipped at the node boundary.
- See undirected.
-
-
-
-
-
-
-
-
-
- If the edge has a headURL,
- this attribute determines which window of the
- browser is used
- for the URL. Setting it to "_graphviz" will open a new window if it
- doesn't already exist, or reuse it if it does.
- If undefined, the value of the target is used.
-
-
-
-
-
-
-
-
-
- Tooltip annotation attached to the head of an edge. This is used only
- if the edge has a headURL attribute.
-
-
-
-
-
-
-
-
-
- Height of node, in inches. This is taken as the initial, minimum height
- of the node. If fixedsize is true, this
- will be the final height of the node. Otherwise, if the node label
- requires more height to fit, the node's height will be increased to
- contain the label. Note also that, if the output format is dot, the
- value given to height will be the final value.
-
-
-
-
-
-
-
-
-
- Synonym for URL.
-
-
-
-
-
-
-
-
-
- Gives the name of a file containing an image to be displayed inside
- a node. The image file must be in one of the recognized formats,
- typically JPEG, PNG, GIF or Postscript, and be able to be converted
- into the desired output format.
-
-
- Unlike with the shapefile attribute,
- the image is treated as node
- content rather than the entire node. In particular, an image can
- be contained in a node of any shape, not just a rectangle.
-
-
-
-
-
-
-
-
-
- Attribute controlling how an image fills its
- containing node. In general, the image is given its natural size,
- (cf. dpi),
- and the node size is made large enough to contain its image, its
- label, its margin, and its peripheries.
- Its width and height will also be at least as large as its
- minimum width and height.
- If, however, fixedsize=true,
- the width and height attributes specify the exact size of the node.
-
-
- During rendering, in the default case (imagescale=false),
- the image retains its natural size.
- If true,
- the image is uniformly scaled (i.e., its aspect ratio is
- preserved) to fit inside the node.
- At least one dimension of the image will be as large as possible
- given the size of the node.
- When width,
- the width of the image is scaled to fill the node width.
- The corresponding property holds when imagescale=height.
- When both,
- both the height and the width are scaled separately to fill the node.
-
-
- In all cases, if a dimension of the image is larger than the
- corresponding dimension of the node, that dimension of the
- image is scaled down to fit the node. As with the case of
- expansion, if imagescale=true, width and height are
- scaled uniformly.
-
-
-
-
-
-
-
-
-
- Text label attached to objects.
- If a node's shape is record, then the label can
- have a special format
- which describes the record layout.
-
-
-
-
-
-
-
-
-
- If labelURL is defined, this is the link used for the label
- of an edge. This value overrides any URL
- defined for the edge.
-
-
-
-
-
-
-
-
-
- This, along with labeldistance, determine
- where the
- headlabel (taillabel) are placed with respect to the head (tail)
- in polar coordinates. The origin in the coordinate system is
- the point where the edge touches the node. The ray of 0 degrees
- goes from the origin back along the edge, parallel to the edge
- at the origin.
-
-
- The angle, in degrees, specifies the rotation from the 0 degree ray,
- with positive angles moving counterclockwise and negative angles
- moving clockwise.
-
-
-
-
-
-
-
-
-
- Multiplicative scaling factor adjusting the distance that
- the headlabel (taillabel) is from the head (tail) node.
- The default distance is 10 points. See labelangle
- for more details.
-
-
-
-
-
-
-
-
-
- If true, allows edge labels to be less constrained in position.
- In particular, it may appear on top of other edges.
-
-
-
-
-
-
-
-
-
- Color used for headlabel and taillabel.
- If not set, defaults to edge's fontcolor.
-
-
-
-
-
-
-
-
-
- Font used for headlabel and taillabel.
- If not set, defaults to edge's fontname.
-
-
-
-
-
-
-
-
-
- Font size, in points, used for headlabel and taillabel.
- If not set, defaults to edge's fontsize.
-
-
-
-
-
-
-
-
-
- Synonym for labelURL.
-
-
-
-
-
-
-
-
-
- Justification for cluster labels. If r, the label
- is right-justified within bounding rectangle; if l, left-justified;
- else the label is centered.
- Note that a subgraph inherits attributes from its parent. Thus, if
- the root graph sets labeljust to l, the subgraph inherits
- this value.
-
-
-
-
-
-
-
-
-
- Top/bottom placement of graph and cluster labels.
- If the attribute is t, place label at the top;
- if the attribute is b, place label at the bottom.
- By default, root
- graph labels go on the bottom and cluster labels go on the top.
- Note that a subgraph inherits attributes from its parent. Thus, if
- the root graph sets labelloc to b, the subgraph inherits
- this value.
-
-
-
-
-
-
-
-
-
- If the edge has a URL or labelURL
- attribute, this attribute determines which window of the
- browser is used
- for the URL attached to the label.
- Setting it to "_graphviz" will open a new window if it
- doesn't already exist, or reuse it if it does.
- If undefined, the value of the target is used.
-
-
-
-
-
-
-
-
-
- Tooltip annotation attached to label of an edge.
- This is used only if the edge has a URL
- or labelURL attribute.
-
-
-
-
-
-
-
-
-
- If true, the graph is rendered in landscape mode. Synonymous with
- rotate=90 or
- orientation=landscape.
-
-
-
-
-
-
-
-
-
- Specifies layers in which the node or edge is present.
-
-
-
-
-
-
-
-
-
- Specifies a linearly ordered list of layer names attached to the graph
- The graph is then output in separate layers. Only those components
- belonging to the current output layer appear. For more information,
- see the page How to use drawing layers (overlays).
-
-
-
-
-
-
-
-
-
- Specifies the separator characters used to split the
- layers attribute into a list of layer names.
-
-
-
-
-
-
-
-
-
- Specifies the name of the layout algorithm to use, such as dot
- or neato. Normally, graphs should be kept independent of a type of
- layout. In some cases, however, it can be convenient to embed the type
- of layout desired within the graph. For example, a graph containing
- position information from a layout might want to record what the
- associated layout algorithm was.
-
-
- This attribute takes precedence over
- the -K flag
- or the actual command name used.
-
-
-
-
-
-
-
-
-
- Preferred edge length, in inches.
-
-
-
-
-
-
-
-
-
- Specifies strictness of level constraints in neato
- when mode="ipsep" or "hier".
- Larger positive values mean stricter constraints, which demand more
- separation between levels. On the other hand, negative values will relax
- the constraints by allowing some overlap between the levels.
-
-
-
-
-
-
-
-
-
- Logical head of an edge. When compound is true,
- if lhead is defined and is the name of a cluster containing
- the real head,
- the edge is clipped to the boundary of the cluster.
- See undirected.
-
-
-
-
-
-
-
-
-
- Label position, in points.
- The position indicates the center of the label.
-
-
-
-
-
-
-
-
-
- Logical tail of an edge. When compound is true,
- if ltail is defined and is the name of a cluster
- containing the real tail,
- the edge is clipped to the boundary of the cluster.
- See undirected.
-
-
-
-
-
-
-
-
-
- For graphs, this sets x and y margins of canvas, in inches. If the margin
- is a single double, both margins are set equal to the given value.
-
-
- Note that the margin is not part of the drawing but just empty space
- left around the drawing. It basically corresponds to a translation of
- drawing, as would be necessary to center a drawing on a page. Nothing
- is actually drawn in the margin. To actually extend the background of
- a drawing, see the pad attribute.
-
-
- For nodes, this attribute specifies space left around the node's label.
- By default, the value is 0.11,0.055.
-
-
-
-
-
-
-
-
-
- Sets the number of iterations used.
-
-
-
-
-
-
-
-
-
- Multiplicative scale factor used to alter the MinQuit (default = 8)
- and MaxIter (default = 24) parameters used during crossing
- minimization. These correspond to the
- number of tries without improvement before quitting and the
- maximum number of iterations in each pass.
-
-
-
-
-
-
-
-
-
- Specifies the minimum separation between all nodes.
-
-
-
-
-
-
-
-
-
- Minimum edge length (rank difference between head and tail).
-
-
-
-
-
-
-
-
-
- Technique for optimizing the layout. If mode is major,
- neato uses stress majorization. If mode is KK,
- neato uses a version of the gradient descent method. The only advantage
- to the latter technique is that it is sometimes appreciably faster for
- small (number of nodes < 100) graphs. A significant disadvantage is that
- it may cycle.
-
-
- There are two new, experimental modes in neato, hier, which adds a top-down
- directionality similar to the layout used in dot, and ipsep, which
- allows the graph to specify minimum vertical and horizontal distances
- between nodes. (See the sep attribute.)
-
-
-
-
-
-
-
-
-
- This value specifies how the distance matrix is computed for the input
- graph. The distance matrix specifies the ideal distance between every
- pair of nodes. neato attemps to find a layout which best achieves
- these distances. By default, it uses the length of the shortest path,
- where the length of each edge is given by its len
- attribute. If model is circuit, neato uses the
- circuit resistance
- model to compute the distances. This tends to emphasize clusters. If
- model is subset, neato uses the subset model. This sets the
- edge length to be the number of nodes that are neighbors of exactly one
- of the end points, and then calculates the shortest paths. This helps
- to separate nodes with high degree.
-
-
-
-
-
-
-
-
-
- If Graphviz is built with MOSEK defined, mode=ipsep and mosek=true,
- the Mosek software (www.mosek.com) is use to solve the ipsep constraints.
-
-
-
-
-
-
-
-
-
- Minimum space between two adjacent nodes in the same rank, in inches.
-
-
-
-
-
-
-
-
-
- By default, the justification of multi-line labels is done within the
- largest context that makes sense. Thus, in the label of a polygonal
- node, a left-justified line will align with the left side of the node
- (shifted by the prescribed margin).
- In record nodes, left-justified
- line will line up with the left side of the enclosing column of fields.
- If nojustify is true, multi-line labels will be justified
- in the context of itself. For example, if the attribute is set,
- the first label line is long, and the second is shorter and left-justified,
- the second will align with the left-most character in the first line,
- regardless of how large the node might be.
-
-
-
-
-
-
-
-
-
- If set, normalize coordinates of final
- layout so that the first point is at the origin, and then rotate the
- layout so that the first edge is horizontal.
-
-
-
-
-
-
-
-
-
- Used to set number of iterations in
- network simplex applications, used in
- computing node x coordinates.
- If defined, # iterations = nslimit * # nodes;
- otherwise, # iterations = MAXINT.
-
-
-
-
-
-
-
-
-
- Used to set number of iterations in
- network simplex applications, used for ranking nodes.
- If defined, # iterations = nslimit1 * # nodes;
- otherwise, # iterations = MAXINT.
-
-
-
-
-
-
-
-
-
- If "out" for a graph G, and n is a node in G, then edges n->* appear
- left-to-right in the same order in which they are defined.
- If "in", the edges *->n appear
- left-to-right in the same order in which they are defined for all
- nodes n.
-
-
-
-
-
-
-
-
-
-
-
- Specify order in which nodes and edges are drawn.
-
-
-
-
-
-
-
-
-
- Determines if and how node overlaps should be removed. Nodes are first
- enlarged using the sep attribute.
- If true, overlaps are retained.
- If the value is scale, overlaps are removed by uniformly scaling in x and y.
- If the value converts to false, node overlaps are removed by a
- Voronoi-based technique.
- If the value is scalexy, x and y are separately
- scaled to remove overlaps.
- If the value is orthoxy or orthoyx, overlaps
- are moved by optimizing two constraint problems, one for the x axis and
- one for the y. The suffix indicates which axis is processed first.
- If the value is ortho, the technique is similar to orthoxy except a
- heuristic is used to reduce the bias between the two passes.
- If the value is ortho_yx, the technique is the same as ortho, except
- the roles of x and y are reversed.
- The values portho, porthoxy, porthoxy, and portho_yx are similar
- to the previous four, except only pseudo-orthogonal ordering is
- enforced.
-
-
- If the value is compress, the layout will be scaled down as much as
- possible without introducing any overlaps, obviously assuming there are
- none to begin with.
-
-
- If the value is ipsep, and the layout is done by neato with
- mode="ipsep", the overlap removal constraints are
- incorporated into the layout algorithm itself.
- N.B. At present, this only supports one level of clustering.
-
-
- If the value is vpsc, overlap removal is similarly to ortho, except
- quadratic optimization is used to minimize node displacement.
- N.B. At present, this mode only works when mode="ipsep".
-
-
- Except for fdp, the layouts assume overlap="true" as the default.
- Fdp first uses a number of passes using built-in, force-directed technique
- to remove overlaps. Thus, fdp accepts overlap with an integer
- prefix followed by a colon, specifying the number of tries. If there is
- no prefix, no initial tries will be performed. If there is nothing following
- a colon, none of the above methods will be attempted. By default, fdp
- uses overlap="9:portho". Note that overlap="true",
- overlap="0:true" and overlap="0:" all turn off all overlap
- removal.
-
-
- Except for the Voronoi method, all of these transforms preserve the
- orthogonal ordering of the original layout. That is, if the x coordinates
- of two nodes are originally the same, they will remain the same, and if
- the x coordinate of one node is originally less than the x coordinate of
- another, this relation will still hold in the transformed layout. The
- similar properties hold for the y coordinates.
- This is not quite true for the "porth*" cases. For these, orthogonal
- ordering is only preserved among nodes related by an edge.
-
-
- NOTEThe methods orthoxy and orthoyx are still evolving. The semantics of these may change, or these methods may disappear altogether.
-
-
-
-
-
-
-
-
-
- This is true if the value of pack is true (case-insensitive) or a
- non-negative integer. If true, each connected component of the graph is
- laid out separately, and then the graphs are packed tightly.
- If pack has an integral value, this is used as the size,
- in points, of
- a margin around each part; otherwise, a default margin of 8 is used.
- If pack is interpreted as false, the entire graph is laid out together.
- The granularity and method of packing is influenced by the
- packmode attribute.
-
-
- For layouts which always do packing, such a twopi, the pack
- attribute is just used to set the margin.
-
-
-
-
-
-
-
-
-
- This indicates the granularity and method used for packing
- (cf. packMode). Note that defining
- packmode will automatically turn on packing as though one had
- set pack=true.
-
-
-
-
-
-
-
-
-
- The pad attribute specifies how much, in inches, to extend the
- drawing area around the minimal area needed to draw the graph.
- If the pad is a single double, both the x and y pad values are set
- equal to the given value. This area is part of the
- drawing and will be filled with the background color, if appropriate.
-
-
- Normally, a small pad is used for aesthetic reasons, especially when
- a background color is used, to avoid having nodes and edges abutting
- the boundary of the drawn region.
-
-
-
-
-
-
-
-
-
- Width and height of output pages, in inches. If this is set and is
- smaller than the size of the layout, a rectangular array of pages of
- the specified page size is overlaid on the layout, with origins
- aligned in the lower-left corner, thereby partitioning the layout
- into pages. The pages are then produced one at a time, in
- pagedir order.
-
-
- At present, this only works for PostScript output. For other types of
- output, one should use another tool to split the output into multiple
- output files. Or use the viewport to generate
- multiple files.
-
-
-
-
-
-
-
-
-
- If the page attribute is set and applicable,
- this attribute specifies the order in which the pages are emitted.
- This is limited to one of the 8 row or column major orders.
-
-
-
-
-
-
-
-
-
- Color used to draw the bounding box around a cluster.
- If pencolor is not defined, color is
- used. If this is not defined, bgcolor is used.
- If this is not defined, the default is used.
-
-
- Note that a cluster inherits the root graph's attributes if defined.
- Thus, if the root graph has defined a pencolor, this will override a
- color or bgcolor attribute set for the cluster.
-
-
-
-
-
-
-
-
-
- Set number of peripheries used in polygonal shapes and cluster
- boundaries. Note that
- user-defined shapes are treated as a
- form of box shape, so the default
- peripheries value is 1 and the user-defined shape will be drawn in
- a bounding rectangle. Setting peripheries=0 will turn this off.
- Also, 1 is the maximum peripheries value for clusters.
-
-
-
-
-
-
-
-
-
- If true and the node has a pos attribute on input, neato prevents the
- node from moving from the input position. This property can also be specified
- in the pos attribute itself (cf. the point type).
-
-
-
-
-
-
-
-
-
- Position of node, or spline control points.
- For nodes, the position indicates the center of the node.
- On output, the coordinates are in points.
-
-
- In neato and fdp, pos can be used to set the initial position of a node.
- By default, the coordinates are assumed to be in inches. However, the
- -s command line flag can be used to specify
- different units.
-
-
- When the -n command line flag is used with
- neato, it is assumed the positions have been set by one of the layout
- programs, and are therefore in points. Thus, neato -n can accept
- input correctly without requiring a -s flag and, in fact,
- ignores any such flag.
-
-
-
-
-
-
-
-
-
- If quantum > 0.0, node label dimensions
- will be rounded to integral multiples of the quantum.
-
-
-
-
-
-
-
-
-
- Rank constraints on the nodes in a subgraph.
- If same, all nodes are placed on the same rank.
- If min, all nodes are placed on the minimum rank.
- If source, all nodes are placed on the minimum rank, and
- the only nodes on the minimum rank belong to some subgraph whose
- rank attribute is "source" or "min".
- Analogous criteria hold for rank=max and rank=sink.
- (Note: the
- minimum rank is topmost or leftmost, and the maximum rank is bottommost
- or rightmost.)
-
-
-
-
-
-
-
-
-
- Sets direction of graph layout. For example, if rankdir="LR",
- and barring cycles, an edge T -> H; will go
- from left to right. By default, graphs are laid out from top to bottom.
-
-
-
-
-
-
-
-
-
- In dot, this gives the desired rank separation, in inches. This is
- the minimum vertical distance between the bottom of the nodes in one
- rank and the tops of nodes in the next. If the value
- contains "equally", the centers of all ranks are spaced equally apart.
- Note that both
- settings are possible, e.g., ranksep = "1.2 equally".
- In twopi, specifies radial separation of concentric circles.
-
-
-
-
-
-
-
-
-
- Sets the aspect ratio (drawing height/drawing width) for the drawing.
- Note that this is adjusted before
- the size attribute constraints are enforced.
-
-
- If ratio is numeric, it is taken as the desired aspect ratio.
- Then, if the actual aspect ratio is less than the desired ratio,
- the drawing height is scaled up to achieve the
- desired ratio; if the actual ratio is greater than that desired ratio,
- the drawing width is scaled up.
-
-
- If ratio = fill and the size
- attribute is set, node positions are scaled, separately in both x
- and y, so that the final drawing exactly fills the specified size.
-
-
- If ratio = compress and the size
- attribute is set, dot attempts to compress the initial layout to fit
- in the given size. This achieves a tighter packing of nodes but
- reduces the balance and symmetry. This feature only works in dot.
-
-
- If ratio = expand, the size
- attribute is set, and both the width and the height of the graph are
- less than the value in size, node positions are scaled
- uniformly until at least
- one dimension fits size exactly.
- Note that this is distinct from using size as the
- desired size, as here the drawing is expanded before edges are generated and
- all node and text sizes remain unchanged.
-
-
- If ratio = auto, the page
- attribute is set and the graph cannot be drawn on a single page,
- then size is set to an ``ideal'' value.
- In particular, the size in a given dimension will be the smallest integral
- multiple of the page size in that dimension which is at least half the
- current size. The two dimensions are then scaled independently to the
- new size. This feature only works in dot.
-
-
-
-
-
-
-
-
-
- Rectangles for fields of records, in points.
-
-
-
-
-
-
-
-
-
- If true, force polygon to be regular.
-
-
-
-
-
-
-
-
-
- If true and there are multiple clusters, run cross
- minimization a second time.
-
-
-
-
-
-
-
-
-
- This is a synonym for the dpi attribute.
-
-
-
-
-
-
-
-
-
- This specifies nodes to be used as the center of the
- layout and the root of the generated spanning tree. As a graph attribute,
- this gives the name of the node. As a node attribute (circo only), it
- specifies that the node should be used as a central node. In twopi,
- this will actually be the central node. In circo, the block containing
- the node will be central in the drawing of its connected component.
- If not defined,
- twopi will pick a most central node, and circo will pick a random node.
-
-
-
-
-
-
-
-
-
- If 90, set drawing orientation to landscape.
-
-
-
-
-
-
-
-
-
- Edges with the same head and the same samehead value are aimed
- at the same point on the head.
- See undirected.
-
-
-
-
-
-
-
-
-
- Edges with the same tail and the same sametail value are aimed
- at the same point on the tail.
- See undirected.
-
-
-
-
-
-
-
-
-
- If the input graph defines the vertices
- attribute, and output is dot or xdot, this gives
- the number of points used for a node whose shape is a circle or ellipse.
- It plays the same role in neato, when adjusting the layout to avoid
- overlapping nodes, and in image maps.
-
-
-
-
-
-
-
-
-
- During network simplex, maximum number of edges with negative cut values
- to search when looking for one with minimum cut value.
-
-
-
-
-
-
-
-
-
- Fraction to increase polygons (multiply
- coordinates by 1 + sep) for purposes of determining overlap. Guarantees
- a minimal non-zero distance between nodes.
- If unset but esep is defined, sep will be
- set to esep/0.8. If esep is unset, the default value
- is used.
-
-
- When overlap="ipsep" or "vpsc",
- sep gives a minimum distance, in inches, to be left between nodes.
- In this case, if sep is a pointf, the x and y separations can be
- specified separately.
-
-
-
-
-
-
-
-
-
- Set the shape of a node.
-
-
-
-
-
-
-
-
-
- (Deprecated) If defined, shapefile specifies a file containing user-supplied node content.
- The shape of the node is set to box.
- The image in the shapefile must be
- rectangular. The image formats supported as well as the precise semantics of
- how the file is used depends on the
- output format. For further details, see
- External PostScript files.
-
-
- There is one exception to this usage.
- If shape is set to "epsf", shapefile gives
- a filename containing a definition of the node in PostScript.
- The graphics defined must be contain all of the
- node content, including any desired boundaries.
- For further details, see
-
- External PostScript files.
-
-
-
-
-
-
-
-
-
- Print guide boxes in PostScript at the beginning of
- routesplines if 1, or at the end if 2. (Debugging)
-
-
-
-
-
-
-
-
-
- Number of sides if shape=polygon.
-
-
-
-
-
-
-
-
-
- Maximum width and height of drawing, in inches.
- If defined and the drawing is too large, the drawing is uniformly
- scaled down so that it fits within the given size.
-
-
- If size ends in an exclamation point (!),
- then it is taken to be
- the desired size. In this case, if both dimensions of the drawing are
- less than size, the drawing is scaled up uniformly until at
- least one dimension equals its dimension in size.
-
-
- Note that there is some interaction between the size and
- ratio attributes.
-
-
-
-
-
-
-
-
-
- Skew factor for shape=polygon. Positive values
- skew top of polygon to right; negative to left.
-
-
-
-
-
-
-
-
-
- Controls how, and if, edges are represented. If true, edges are drawn as
- splines routed around nodes; if false, edges are drawn as line segments.
- If set to "", no edges are drawn at all.
-
-
- (1 March 2007) The values line and spline can be
- used as synonyms for false and true, respectively.
- In addition, the value polyline specifies that edges should be
- drawn as polylines.
-
-
- By default, the attribute is unset. How this is interpreted depends on
- the layout. For dot, the default is to draw edges as splines. For all
- other layouts, the default is to draw edges as line segments. Note that
- for these latter layouts, if splines="true", this
- requires non-overlapping nodes (cf. overlap).
- If fdp is used for layout and splines="compound", then the edges are
- drawn to avoid clusters as well as nodes.
-
-
-
-
-
-
-
-
-
- Parameter used to determine the initial layout of nodes. If unset, the
- nodes are randomly placed in a unit square with
- the same seed is always used for the random number generator, so the
- initial placement is repeatable.
-
-
-
-
-
-
-
-
-
- Set style for node or edge. For cluster subgraph, if "filled", the
- cluster box's background is filled.
-
-
-
-
-
-
-
-
-
- A URL or pathname specifying an XML style sheet, used in SVG output.
-
-
-
-
-
-
-
-
-
- If tailURL is defined, it is
- output as part of the tail label of the edge.
- Also, this value is used near the tail node, overriding any
- URL value.
- See undirected.
-
-
-
-
-
-
-
-
-
- If true, the tail of an edge is clipped to the boundary of the tail node;
- otherwise, the end of the edge goes to the center of the node, or the
- center of a port, if applicable.
-
-
-
-
-
-
-
-
-
- Synonym for tailURL.
-
-
-
-
-
-
-
-
-
- Text label to be placed near tail of edge.
- See undirected.
-
-
-
-
-
-
-
-
-
- Indicates where on the tail node to attach the tail of the edge.
- See undirected.
-
-
-
-
-
-
-
-
-
- If the edge has a tailURL,
- this attribute determines which window of the
- browser is used
- for the URL. Setting it to "_graphviz" will open a new window if it
- doesn't already exist, or reuse it if it does.
- If undefined, the value of the target is used.
-
-
-
-
-
-
-
-
-
- Tooltip annotation attached to the tail of an edge. This is used only
- if the edge has a tailURL attribute.
-
-
-
-
-
-
-
-
-
- If the object has a URL, this attribute determines which window
- of the browser is used for the URL.
- See W3C documentation.
-
-
-
-
-
-
-
-
-
- Tooltip annotation attached to the node or edge. If unset, Graphviz
- will use the object's label if defined.
- Note that if the label is a record specification or an HTML-like
- label, the resulting tooltip may be unhelpful. In this case, if
- tooltips will be generated, the user should set a tooltip
- attribute explicitly.
-
-
-
-
-
-
-
-
-
- If set explicitly to true or false, the value determines whether or not
- internal bitmap rendering relies on a truecolor color model or uses
- a color palette.
- If the attribute is unset, truecolor is not used
- unless there is a shapefile property
- for some node in the graph.
- The output model will use the input model when possible.
-
-
- Use of color palettes results in less memory usage during creation of the
- bitmaps and smaller output files.
-
-
- Usually, the only time it is necessary to specify the truetype model
- is if the graph uses more than 256 colors.
- However, if one uses bgcolor=transparent with
- a color palette, font
- antialiasing can show up as a fuzzy white area around characters.
- Using truecolor=true avoids this problem.
-
-
-
-
-
-
-
-
-
- If the input graph defines this attribute, the node is polygonal,
- and output is dot or xdot, this attribute provides the
- coordinates of the vertices of the node's polygon, in inches.
- If the node is an ellipse or circle, the
- samplepoints attribute affects
- the output.
-
-
-
-
-
-
-
-
-
- Clipping window on final drawing.
-
-
-
-
-
-
-
-
-
- Factor to scale up drawing to allow margin for expansion in
- Voronoi technique. dim' = (1+2*margin)*dim.
-
-
-
-
-
-
-
-
-
- Weight of edge. In dot, the heavier the weight, the shorter,
- straighter and more vertical the edge is. In neato, the heavier the
- weight, the more neato will try to place the end points so that the
- length of the edge is len.
-
-
-
-
-
-
-
-
-
- Width of node, in inches. This is taken as the initial, minimum width
- of the node. If fixedsize is true, this
- will be the final width of the node. Otherwise, if the node label
- requires more width to fit, the node's width will be increased to
- contain the label. Note also that, if the output format is dot, the
- value given to width will be the final value.
-
-
-
-
-
-
-
-
-
- Provides z coordinate value for 3D layouts and displays. If the
- graph has dim set to 3 (or more),
- neato will use a node's z value
- for the z coordinate of its initial position if
- its pos attribute is also defined.
-
-
- Even if no z values are specified in the input, it is necessary to
- declare a z attribute for nodes, e.g, using node[z=""]
- in order to get z values on output.
- Thus, setting dim=3 but not declaring z will
- cause neato -Tvrml to
- layout the graph in 3D but project the layout onto the xy-plane
- for the rendering. If the z attribute is declared, the final rendering
- will be in 3D.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/tests/Resources/Dockerfile b/tests/Resources/Dockerfile
new file mode 100644
index 0000000..cf9f4d6
--- /dev/null
+++ b/tests/Resources/Dockerfile
@@ -0,0 +1,7 @@
+FROM php:8.2
+
+RUN apt-get update \
+ && apt-get install -y graphviz \
+ && rm -rf /var/lib/apt/lists/*
+
+WORKDIR /opt/project
diff --git a/tests/phpDocumentor/GraphViz/Test/AttributeTest.php b/tests/phpDocumentor/GraphViz/Test/AttributeTest.php
index 3c1d5a4..de02e1f 100644
--- a/tests/phpDocumentor/GraphViz/Test/AttributeTest.php
+++ b/tests/phpDocumentor/GraphViz/Test/AttributeTest.php
@@ -21,8 +21,7 @@
*/
class AttributeTest extends TestCase
{
- /** @var Attribute */
- protected $fixture = null;
+ protected Attribute $fixture;
/**
* Initializes the fixture for this test.
diff --git a/tests/phpDocumentor/GraphViz/Test/AttributesTest.php b/tests/phpDocumentor/GraphViz/Test/AttributesTest.php
new file mode 100644
index 0000000..464b461
--- /dev/null
+++ b/tests/phpDocumentor/GraphViz/Test/AttributesTest.php
@@ -0,0 +1,110 @@
+setAttribute('color', 'red');
+ $attribute = $obj->getAttribute('color');
+
+ $this->assertSame('color', $attribute->getKey());
+ $this->assertSame('red', $attribute->getValue());
+ }
+
+ public function testGetAttributeThrowsExceptionIfNotFound(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+
+ $this->expectException(AttributeNotFound::class);
+ $obj->getAttribute('missing');
+ }
+
+ public function testMagicSet(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+
+ $result = $obj->setColor('blue');
+
+ $this->assertSame($obj, $result);
+ }
+
+ public function testMagicGet(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+ $obj->setColor('blue');
+
+ $attribute = $obj->getColor();
+
+ $this->assertInstanceOf(Attribute::class, $attribute);
+ $this->assertSame('color', $attribute->getKey());
+ $this->assertSame('blue', $attribute->getValue());
+ }
+
+ public function testMagicCallReturnsNullForUnknownMethod(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+
+ $this->assertNull($obj->fooBar('baz'));
+ }
+
+ public function testSetAttributeThenMagicGet(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+
+ $obj->setAttribute('mainShape', 'box');
+ $attribute = $obj->getMainShape();
+
+ $this->assertInstanceOf(Attribute::class, $attribute);
+ $this->assertSame('mainShape', $attribute->getKey());
+ $this->assertSame('box', $attribute->getValue());
+ }
+
+ public function testMagicSetThenGetAttribute(): void
+ {
+ $obj = new class() {
+ use Attributes;
+ };
+
+ $obj->setMainShape('box');
+ $attribute = $obj->getAttribute('mainShape');
+
+ $this->assertInstanceOf(Attribute::class, $attribute);
+ $this->assertSame('mainShape', $attribute->getKey());
+ $this->assertSame('box', $attribute->getValue());
+ }
+}
diff --git a/tests/phpDocumentor/GraphViz/Test/EdgeTest.php b/tests/phpDocumentor/GraphViz/Test/EdgeTest.php
index 4145e0a..584bf00 100644
--- a/tests/phpDocumentor/GraphViz/Test/EdgeTest.php
+++ b/tests/phpDocumentor/GraphViz/Test/EdgeTest.php
@@ -110,8 +110,8 @@ public function testCall(): void
{
$label = 'my label';
$fixture = new Edge(new Node('from'), new Node('to'));
- $this->assertInstanceOf(Edge::class, $fixture->setLabel($label));
- $this->assertSame($label, $fixture->getLabel()->getValue());
+ $this->assertInstanceOf(Edge::class, $fixture->setAttribute('label', $label));
+ $this->assertSame($label, $fixture->getAttribute('label')->getValue());
$this->assertNull($fixture->someNonExcistingMethod());
}
@@ -126,7 +126,7 @@ public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
$this->expectException(AttributeNotFound::class);
$this->expectExceptionMessage('Attribute with name "label" was not found');
- $fixture->getLabel();
+ $fixture->getAttribute('label');
}
/**
@@ -138,8 +138,8 @@ public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
public function testToString(): void
{
$fixture = new Edge(new Node('from'), new Node('to'));
- $fixture->setLabel('MyLabel');
- $fixture->setWeight(45);
+ $fixture->setAttribute('label', 'MyLabel');
+ $fixture->setAttribute('weight', 45);
$dot = << "to" [
diff --git a/tests/phpDocumentor/GraphViz/Test/GraphTest.php b/tests/phpDocumentor/GraphViz/Test/GraphTest.php
index 242d01d..7e56151 100644
--- a/tests/phpDocumentor/GraphViz/Test/GraphTest.php
+++ b/tests/phpDocumentor/GraphViz/Test/GraphTest.php
@@ -31,12 +31,11 @@
use const PHP_EOL;
/**
- * Test for the the class representing a GraphViz graph.
+ * Test for the class representing a GraphViz graph.
*/
class GraphTest extends TestCase
{
- /** @var Graph */
- protected $fixture;
+ protected Graph $fixture;
/**
* Sets up the fixture, for example, opens a network connection.
@@ -207,8 +206,8 @@ public function testSetPath(): void
public function test__call(): void
{
$this->assertNull($this->fixture->MyMethod());
- $this->assertSame($this->fixture, $this->fixture->setBgColor('black'));
- $this->assertSame('black', $this->fixture->getBgColor()->getValue());
+ $this->assertSame($this->fixture, $this->fixture->setAttribute('bgColor', 'black'));
+ $this->assertSame('black', $this->fixture->getAttribute('bgColor')->getValue());
}
/**
@@ -218,7 +217,7 @@ public function test__call(): void
public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
{
$this->expectException(AttributeNotFound::class);
- $this->expectExceptionMessage('Attribute with name "notexisting" was not found');
+ $this->expectExceptionMessage('Attribute with name "notExisting" was not found');
$this->fixture->getNotExisting();
}
@@ -312,29 +311,29 @@ public function testFindNode(): void
}
/**
- * @covers \phpDocumentor\GraphViz\Graph::__set
+ * @covers \phpDocumentor\GraphViz\Graph::getNode
*/
- public function test__set(): void
+ public function testGetNode(): void
{
- $mock = m::mock(Node::class);
-
- $this->fixture->__set('myNode', $mock);
+ $node = new Node('My');
+ $this->fixture->setNode($node);
- self::assertSame($mock, $this->fixture->myNode);
+ $this->assertSame(
+ $node,
+ $this->fixture->getNode('My'),
+ );
}
/**
- * @covers \phpDocumentor\GraphViz\Graph::__get
+ * @covers \phpDocumentor\GraphViz\Graph::getNode
*/
- public function test__get(): void
+ public function testGetNodeNodeDoesNotExist(): void
{
- $mock = m::mock(Node::class);
+ $node = new Node('My');
+ $this->fixture->setNode($node);
- $this->fixture->myNode = $mock;
- $this->assertSame(
- $mock,
- $this->fixture->myNode
- );
+ $this->expectException(\LogicException::class);
+ $this->fixture->getNode('Alien');
}
/**
@@ -400,7 +399,7 @@ public function test__toString(): void
$this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . PHP_EOL . '}'))
);
- $graph->setLabel('PigeonPost');
+ $graph->setAttribute('label', 'PigeonPost');
$this->assertSame(
$this->normalizeLineEndings((string) $graph),
$this->normalizeLineEndings(('digraph "My First Graph" {' . PHP_EOL . 'label="PigeonPost"' . PHP_EOL . '}'))
diff --git a/tests/phpDocumentor/GraphViz/Test/NodeTest.php b/tests/phpDocumentor/GraphViz/Test/NodeTest.php
index 5fe1316..1a7ba83 100644
--- a/tests/phpDocumentor/GraphViz/Test/NodeTest.php
+++ b/tests/phpDocumentor/GraphViz/Test/NodeTest.php
@@ -22,8 +22,7 @@
*/
class NodeTest extends TestCase
{
- /** @var Node */
- protected $fixture = null;
+ protected Node $fixture;
/**
* Initializes the fixture for this test.
@@ -47,7 +46,7 @@ public function testConstruct(): void
$fixture
);
$this->assertSame('MyName', $fixture->getName());
- $this->assertSame('MyLabel', $fixture->getLabel()->getValue());
+ $this->assertSame('MyLabel', $fixture->getAttribute('label')->getValue());
}
/**
@@ -101,8 +100,8 @@ public function testName(): void
public function testCall(): void
{
$fontname = 'Bitstream Vera Sans';
- $this->assertInstanceOf(Node::class, $this->fixture->setfontname($fontname));
- $this->assertSame($fontname, $this->fixture->getfontname()->getValue());
+ $this->assertInstanceOf(Node::class, $this->fixture->setAttribute('fontname', $fontname));
+ $this->assertSame($fontname, $this->fixture->getAttribute('fontname')->getValue());
$this->assertNull($this->fixture->someNonExistingMethod());
}
@@ -115,7 +114,7 @@ public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
$this->expectException(AttributeNotFound::class);
$this->expectExceptionMessage('Attribute with name "fontname" was not found');
- $this->fixture->getFontname();
+ $this->fixture->getAttribute('fontname');
}
/**
@@ -126,8 +125,8 @@ public function testGetNonExistingAttributeThrowsAttributeNotFound(): void
*/
public function testToString(): void
{
- $this->fixture->setfontsize(12);
- $this->fixture->setfontname('Bitstream Vera Sans');
+ $this->fixture->setAttribute('fontsize', 12);
+ $this->fixture->setAttribute('fontname', 'Bitstream Vera Sans');
$dot = <<fixture->setfontsize(12);
- $this->fixture->setfontname('Bitstream Vera Sans');
+ $this->fixture->setAttribute('fontsize', 12);
+ $this->fixture->setAttribute('fontname', 'Bitstream Vera Sans');
$this->fixture->setLabel('\phpDocumentor\Descriptor\ProjectDescriptor');
$dot = <<fixture = new MethodReflectionExtension();
- }
-
- /**
- * @dataProvider existingMethodProvider
- */
- public function testNodeHasMethodReturnsTrue(string $className, string $methodName): void
- {
- $classReflection = m::mock(ClassReflection::class);
- $classReflection->shouldReceive('getName')->andReturn($className);
-
- $this->assertTrue($this->fixture->hasMethod($classReflection, $methodName));
- }
-
- /**
- * @return array>
- */
- public function existingMethodProvider(): array
- {
- return [
- 'node::getLabel' => [
- 'className' => Node::class,
- 'methodName' => 'getLabel',
- ],
- 'node::setLabel' => [
- 'className' => Node::class,
- 'methodName' => 'setLabel',
- ],
- 'graph::setFontSize' => [
- 'className' => Graph::class,
- 'methodName' => 'setFontSize',
- ],
- 'graph::getFontSize' => [
- 'className' => Graph::class,
- 'methodName' => 'getFontSize',
- ],
- ];
- }
-
- public function testAttributeType(): void
- {
- $classReflection = m::mock(ClassReflection::class);
- $classReflection->shouldReceive('getName')->andReturn(Node::class);
-
- $method = $this->fixture->getMethod($classReflection, 'setFontSize');
-
- $this->assertInstanceOf(FloatType::class, $method->getVariants()[0]->getParameters()[0]->getType());
- }
-
- public function testAttributeTypeOfNoneExisting(): void
- {
- $classReflection = m::mock(ClassReflection::class);
- $classReflection->shouldReceive('getName')->andReturn(Node::class);
-
- $method = $this->fixture->getMethod($classReflection, 'setColor');
-
- $this->assertInstanceOf(StringType::class, $method->getVariants()[0]->getParameters()[0]->getType());
- }
-}