Skip to content

Commit

Permalink
feat: add new conventional commit parser
Browse files Browse the repository at this point in the history
  • Loading branch information
marcocesarato committed Jan 19, 2021
1 parent 5997ecf commit 603f724
Show file tree
Hide file tree
Showing 7 changed files with 349 additions and 0 deletions.
23 changes: 23 additions & 0 deletions src/Commit/Body.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Type\Stringable;

class Body implements Stringable
{
/**
* @var string
*/
public $content;

public function __construct(string $content)
{
$this->content = $content;
}

public function __toString(): string
{
return $this->content;
}
}
23 changes: 23 additions & 0 deletions src/Commit/Description.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Type\Stringable;

class Description implements Stringable
{
/**
* @var string
*/
public $content;

public function __construct(string $content)
{
$this->content = $content;
}

public function __toString(): string
{
return $this->content;
}
}
33 changes: 33 additions & 0 deletions src/Commit/Footer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Type\Stringable;

class Footer implements Stringable
{
/**
* Token.
*
* @var string
*/
public $token;

/**
* Value.
*
* @var string
*/
public $value;

public function __construct(string $token, string $value)
{
$this->token = $token;
$this->value = $value;
}

public function __toString(): string
{
return $this->token . ': ' . $this->value;
}
}
203 changes: 203 additions & 0 deletions src/Commit/Parser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Helper\Format;
use ConventionalChangelog\Type\Stringable;

class Parser implements Stringable
{
protected const PATTERN_HEADER = "/^(?'type'[a-z]+)(\((?'scope'.+)\))?(?'important'[!]?)[:][[:blank:]](?'description'.+)/iums";
protected const PATTERN_FOOTER = "/(?'token'^([a-z0-9_-]+|BREAKING[[:blank:]]CHANGES?))(?'value'([:][[:blank:]]|[[:blank:]]\#(?=\w)).*?)$/iums";

/**
* Raw content.
*
* @var string
*/
protected $raw;

/**
* Sha hash.
*
* @var string
*/
protected $hash;

/**
* Type.
*
* @var Type
*/
protected $type;

/**
* Scope.
*
* @var Scope
*/
protected $scope;

/**
* Important.
*
* @var bool
*/
protected $important = false;

/**
* Description.
*
* @var Description
*/
protected $description;

/**
* @var Body
*/
protected $body;

/**
* Footers.
*
* @var Footer[]
*/
protected $footers = [];

public function __construct(string $commit)
{
$this->raw = Format::clean($commit);

if (!$this->isValid()) {
return;
}

$rows = explode("\n", $commit);
$count = count($rows);
// Commit info
$this->hash = $rows[$count - 1];
$header = $rows[0];
$message = '';
// Get message
foreach ($rows as $i => $row) {
if ($i !== 0 && $i !== $count) {
$message .= $row . "\n";
}
}
$this->parseHeader($header);
$this->parseMessage($message);
}

/**
* Parse header.
*/
protected function parseHeader(string $header)
{
preg_match(self::PATTERN_HEADER, $header, $matches);
$this->type = new Type($matches['type']);
$this->scope = new Scope($matches['scope']);
$this->important = !empty($matches['important']) ? true : false;
$this->description = new Description($matches['description']);
}

/**
* Parse message.
*/
protected function parseMessage(string $message)
{
$body = Format::clean($message);
if (preg_match_all(self::PATTERN_FOOTER, $body, $matches, PREG_SET_ORDER, 0)) {
foreach ($matches as $match) {
$footer = $match[0];
$body = str_replace($footer, '', $body);
$value = ltrim($match['value'], ':');
$this->footers[] = new Footer($match['token'], $value);
}
}
$body = Format::clean($body);
$this->body = new Body($body);
}

public function isValid(): bool
{
return preg_match(self::PATTERN_HEADER, $this->raw);
}

public function getRaw(): string
{
return $this->raw;
}

public function getHash(): string
{
return $this->hash;
}

public function getShortHash(): string
{
return substr($this->hash, 0, 6);
}

public function getType(): Type
{
return $this->type;
}

public function getScope(): Scope
{
return $this->scope;
}

public function isImportant(): bool
{
return $this->important;
}

public function getDescription(): Description
{
return $this->description;
}

public function getBody(): Body
{
return $this->body;
}

/**
* @return Footer[]
*/
public function getFooters(): array
{
return $this->footers;
}

public function getHeader()
{
$header = $this->type;
if (!empty((string)$this->scope)) {
$header .= '(' . $this->scope . ')';
}
if ($this->important) {
$header .= '!';
}
$header .= ': ' . $this->description;

return $header;
}

public function getMessage()
{
$footer = implode("\n", $this->footers);

return $this->body . "\n\n" . $footer;
}

public function __toString(): string
{
$header = $this->getHeader();
$message = $this->getMessage();
$string = $header . "\n\n" . $message;

return Format::clean($string);
}
}
31 changes: 31 additions & 0 deletions src/Commit/Scope.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Helper\Format;
use ConventionalChangelog\Type\Stringable;

class Scope implements Stringable
{
/**
* @var string
*/
public $content;

public function __construct(string $content)
{
$this->content = $content;
}

public function __toString(): string
{
$string = $this->content;
$string = preg_replace('/[_]+/m', ' ', $string);
$string = ucfirst($string);
$string = preg_replace('/((?<=\p{Ll})\p{Lu})|((?!\A)\p{Lu}(?>\p{Ll}))/u', ' $0', $string);
$string = preg_replace('/\.(php|md|json|txt|csv|js)($|\s)/', '', $string);
$string = Format::clean($string);

return $string;
}
}
23 changes: 23 additions & 0 deletions src/Commit/Type.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace ConventionalChangelog\Commit;

use ConventionalChangelog\Type\Stringable;

class Type implements Stringable
{
/**
* @var string
*/
public $content;

public function __construct(string $content)
{
$this->content = strtolower($content);
}

public function __toString(): string
{
return $this->content;
}
}
13 changes: 13 additions & 0 deletions src/Type/Stringable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace ConventionalChangelog\Type;

/**
* Convertible to string.
*
* @internal
*/
interface Stringable
{
public function __toString(): string;
}

0 comments on commit 603f724

Please sign in to comment.