Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added phpdocs #11

Merged
merged 1 commit into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ $rule = $matcher->match($relative_path);
## TODO

- [x] Add comments to the structure
- [ ] Complete phpdocs
- [x] Complete phpdocs
- [ ] Add error checking on `match` to normalize or reject impossible patterns (i.e. "" and "/...")
- [ ] Explain how `AutomataMatcher` works in this file.
- [x] Should I support whitespace escaping in patterns?
Expand All @@ -52,6 +52,7 @@ $rule = $matcher->match($relative_path);
- [x] Remove ext-json from requires.
- [x] Add ext-ctype to requires.
- [x] Convert json tests to PHP arrays.
- [ ] Add a command line tool for dot-renderer

## Author(s)

Expand Down
26 changes: 26 additions & 0 deletions src/AutomataMatcher.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,23 @@
use Kellegous\CodeOwners\AutomataMatcher\State;
use Kellegous\CodeOwners\AutomataMatcher\Token;

/**
* A RuleMatcher that combines all the patterns into a single automata.
*/
final class AutomataMatcher implements RuleMatcher
{
/**
* This is the start state for the automata.
*
* @var State
*/
private State $start;

/**
* The full collection of rules from the Owners instance. The NFA keeps the index of
* rules instead of a reference to the rules themselves since the index provides a straight-forward
* way to honor the last-match-wins rule (the largest of the matching indexes wins).
*
* @var Rule[]
*/
private array $rules;
Expand All @@ -27,6 +39,8 @@ private function __construct(
}

/**
* Builds a new AutomataMatcher from the given rules.
*
* @param iterable<Rule> $rules
* @return self
*/
Expand Down Expand Up @@ -76,6 +90,14 @@ private static function parsePattern(Pattern $pattern): array
return $tokens;
}

/**
* Strangely, a pattern is absolute not only if it starts with a slash,
* but also if it contains a wildcard.
*
* @param string $pattern
*
* @return bool
*/
private static function isAbsolute(string $pattern): bool
{
$ix = strpos($pattern, '/');
Expand Down Expand Up @@ -132,6 +154,8 @@ private static function parseToken(
}

/**
* @inerhitDoc
* @Override
* @param string $path
* @return Rule|null
*/
Expand All @@ -145,6 +169,8 @@ public function match(string $path): ?Rule
}

/**
* Used to return an internal representation of the automata for debugging purposes.
*
* @return array{nodes: array<string, int>, edges: array{from: string, to: string, label: string}[]}
*
* @internal
Expand Down
7 changes: 7 additions & 0 deletions src/AutomataMatcher/DotRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,16 @@

use Kellegous\CodeOwners\AutomataMatcher;

/**
* Intended for debugging, this class will emit a graphviz dot file to visualize
* the state machine used to match patterns in an AutomataMatcher.
*/
final class DotRenderer
{
/**
* Generate a graphviz dot file from the given AutomataMatcher. This can be
* rendered using the dot command.
*
* @param AutomataMatcher $matcher
* @return string
*/
Expand Down
24 changes: 24 additions & 0 deletions src/AutomataMatcher/State.php
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
<?php

declare(strict_types=1);

namespace Kellegous\CodeOwners\AutomataMatcher;

use InvalidArgumentException;

/**
* Represents a state in the NFA.
* @Internal
*/
final class State
{
/**
* The index of the rule. We call this priority because we choose the highest
* priority state (the last rule) to choose the best match.
*
* @var int
*/
private int $priority = -1;

/**
* The key is a regex pattern for the segment and the value is the next state.
*
* @var array<string, State>
*/
private array $edges = [];

/**
* A recursive state is a special ** state which is one that has a self-referencing
* epsilon state.
*
* @var bool
*/
private bool $isRecursive;

/**
* Create a new state. If the state is a terminating ** state, then it will
* be considered recursive.
*
* @param bool $isRecursive
*/
public function __construct(bool $isRecursive = false)
Expand All @@ -30,6 +47,8 @@ public function __construct(bool $isRecursive = false)
}

/**
* Add the states associated with the tokens of a parsed pattern.
*
* @param Token[] $tokens
* @param int $priority
* @return void
Expand Down Expand Up @@ -65,6 +84,9 @@ public function addTokens(
}

/**
* Find the highest priority match for the given path. Note that a return value
* of -1 indicates that no match was found.
*
* @param string[] $path
* @return int
*/
Expand Down Expand Up @@ -94,6 +116,8 @@ public function match(array $path): int
}

/**
* Used to return an internal representation of the automata for debugging purposes.
*
* @param array<string, int> $nodes
* @param array{from:int, to: int, label:string}[] $edges
* @return void
Expand Down
24 changes: 24 additions & 0 deletions src/AutomataMatcher/Token.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,30 @@

namespace Kellegous\CodeOwners\AutomataMatcher;

/**
* Represents a "segment" of a pattern. Each pattern consists of a number of
* tokens separated by "/" characters. This class holds the raw string
* representation of that segment as well as the regular expression that matches
* that segment.
*
* @internal
*/
final class Token
{
/**
* @var string
*/
private string $pattern;

/**
* @var string
*/
private string $regex;

/**
* @param string $pattern
* @param string $regex
*/
public function __construct(
string $pattern,
string $regex
Expand All @@ -18,11 +36,17 @@ public function __construct(
$this->regex = $regex;
}

/**
* @return string
*/
public function getPattern(): string
{
return $this->pattern;
}

/**
* @return string
*/
public function getRegex(): string
{
return $this->regex;
Expand Down
3 changes: 3 additions & 0 deletions src/Blank.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@

namespace Kellegous\CodeOwners;

/**
* Represents a blank line in the code owners file.
*/
final class Blank implements Entry
{
private SourceInfo $sourceInfo;
Expand Down
16 changes: 16 additions & 0 deletions src/Comment.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,26 @@

namespace Kellegous\CodeOwners;

/**
* Represents a comment in the code owners file.
*/
final class Comment implements Entry
{
/**
* The text of the comment including the leading `#`.
* @var string
*/
private string $text;

/**
* @var SourceInfo
*/
private SourceInfo $sourceInfo;

/**
* @param string $text
* @param SourceInfo $sourceInfo
*/
public function __construct(
string $text,
SourceInfo $sourceInfo
Expand All @@ -19,6 +33,7 @@ public function __construct(
}

/**
* @inheritDoc
* @Override
* @return SourceInfo
*/
Expand All @@ -28,6 +43,7 @@ public function getSourceInfo(): SourceInfo
}

/**
* #inheritDoc
* @Override
* @return string
*/
Expand Down
12 changes: 12 additions & 0 deletions src/Owners.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Iterator;

/**
* Represents the contents of a code owners file.
*/
final class Owners
{
/**
Expand All @@ -23,6 +26,8 @@ private function __construct(
}

/**
* Parse the contents of a code owners file.
*
* @param string $filename
* @return self
* @throws ParseException
Expand Down Expand Up @@ -109,6 +114,8 @@ private static function readLinesFrom(string $filename): iterable
}

/**
* Parse the contents of a code owners file as a string.
*
* @param string $content
* @param string|null $filename
* @return self
Expand All @@ -129,6 +136,9 @@ public static function fromString(
}

/**
* Get only the rules that are present in the code owners structure. This omits
* blank lines and comments.
*
* @return iterable<Rule>
*/
public function getRules(): iterable
Expand All @@ -141,6 +151,8 @@ public function getRules(): iterable
}

/**
* Get all entries from the code owners file.
*
* @return iterable<Entry>
*/
public function getEntries(): iterable
Expand Down
3 changes: 3 additions & 0 deletions src/ParseException.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@

use Exception;

/**
* Thrown when the contents of an owners file cannot be parsed.
*/
final class ParseException extends Exception
{
}
26 changes: 26 additions & 0 deletions src/Pattern.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,31 @@

use Closure;

/**
* Represents a file pattern part of a rule in a code owners file.
*/
final class Pattern
{
/**
* @var string
*/
private string $pattern;

/**
* @param string $pattern
*/
private function __construct(string $pattern)
{
$this->pattern = $pattern;
}

/**
* Parse the pattern from a string to a Pattern instance.
*
* @param string $pattern
* @return self
* @throws ParseException
*/
public static function parse(string $pattern): self
{
if (strpos($pattern, '***') !== false || $pattern === '') {
Expand All @@ -26,12 +39,19 @@ public static function parse(string $pattern): self
return new self($pattern);
}

/**
* Get the string representation of the pattern.
*
* @return string
*/
public function toString(): string
{
return $this->pattern;
}

/**
* Get a matcher function for the pattern.
*
* @return Closure(string):bool
*/
public function getMatcher(): Closure
Expand All @@ -46,6 +66,12 @@ public function getMatcher(): Closure
};
}

/**
* Create a regular expression from a pattern.
*
* @param string $pattern
* @return string
*/
private static function toRegexp(string $pattern): string
{
if ($pattern === '/') {
Expand Down
Loading
Loading