diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e69de29 diff --git a/CHANGELOG.md b/CHANGELOG.md index 9ba1310..db2b043 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -67,6 +67,7 @@ This update introduces a refactored code-base, code quality improvements, and be - Updated Composer/Semver to 3.4.3 - Rename 'semver' directory to 'Semver' in composer package - Refactor project constants handling in NccCompiler + - Updated Symfony/Yaml to version 7.1.4 ### Fixed - Fixed Division by zero in PackageManager diff --git a/src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md b/src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md index 0c2021f..74b0a71 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md +++ b/src/ncc/ThirdParty/Symfony/Yaml/CHANGELOG.md @@ -1,6 +1,16 @@ CHANGELOG ========= +7.1 +--- + + * Add support for getting all the enum cases with `!php/enum Foo` + +7.0 +--- + + * Remove the `!php/const:` tag, use `!php/const` instead (without the colon) + 6.3 --- diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php b/src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php index 8833f9f..718f90d 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Command/LintCommand.php @@ -42,7 +42,7 @@ class LintCommand extends Command private ?\Closure $directoryIteratorProvider; private ?\Closure $isReadableProvider; - public function __construct(string $name = null, callable $directoryIteratorProvider = null, callable $isReadableProvider = null) + public function __construct(?string $name = null, ?callable $directoryIteratorProvider = null, ?callable $isReadableProvider = null) { parent::__construct($name); @@ -50,10 +50,7 @@ class LintCommand extends Command $this->isReadableProvider = null === $isReadableProvider ? null : $isReadableProvider(...); } - /** - * @return void - */ - protected function configure() + protected function configure(): void { $this ->addArgument('filename', InputArgument::IS_ARRAY, 'A file, a directory or "-" for reading from STDIN') @@ -127,7 +124,7 @@ EOF return $this->display($io, $filesInfo); } - private function validate(string $content, int $flags, string $file = null): array + private function validate(string $content, int $flags, ?string $file = null): array { $prevErrorHandler = set_error_handler(function ($level, $message, $file, $line) use (&$prevErrorHandler) { if (\E_USER_DEPRECATED === $level) { diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Dumper.php b/src/ncc/ThirdParty/Symfony/Yaml/Dumper.php index 6b4bb1e..d1be722 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Dumper.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Dumper.php @@ -51,10 +51,10 @@ class Dumper $dumpObjectAsInlineMap = true; if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($input instanceof \ArrayObject || $input instanceof \stdClass)) { - $dumpObjectAsInlineMap = empty((array) $input); + $dumpObjectAsInlineMap = !(array) $input; } - if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || empty($input)) { + if ($inline <= 0 || (!\is_array($input) && !$input instanceof TaggedValue && $dumpObjectAsInlineMap) || !$input) { $output .= $prefix.Inline::dump($input, $flags); } elseif ($input instanceof TaggedValue) { $output .= $this->dumpTaggedValue($input, $inline, $indent, $flags, $prefix); @@ -121,10 +121,10 @@ class Dumper $dumpObjectAsInlineMap = true; if (Yaml::DUMP_OBJECT_AS_MAP & $flags && ($value instanceof \ArrayObject || $value instanceof \stdClass)) { - $dumpObjectAsInlineMap = empty((array) $value); + $dumpObjectAsInlineMap = !(array) $value; } - $willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || empty($value); + $willBeInlined = $inline - 1 <= 0 || !\is_array($value) && $dumpObjectAsInlineMap || !$value; $output .= sprintf('%s%s%s%s', $prefix, @@ -169,7 +169,7 @@ class Dumper // http://www.yaml.org/spec/1.2/spec.html#id2793979 foreach ($lines as $line) { if ('' !== trim($line, ' ')) { - return (' ' === substr($line, 0, 1)) ? (string) $this->indentation : ''; + return str_starts_with($line, ' ') ? (string) $this->indentation : ''; } } diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Escaper.php b/src/ncc/ThirdParty/Symfony/Yaml/Escaper.php index 8cbfc1b..24a6bb7 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Escaper.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Escaper.php @@ -80,7 +80,7 @@ class Escaper // Determines if the PHP value contains any single characters that would // cause it to require single quoting in YAML. - return 0 < preg_match('/[ \s \' " \: \{ \} \[ \] , & \* \# \?] | \A[ \- ? | < > = ! % @ ` \p{Zs}]/xu', $value); + return 0 < preg_match('/[\s\'"\:\{\}\[\],&\*\#\?] | \A[\-?|<>=!%@`\p{Zs}]/xu', $value); } /** diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php b/src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php index 64b9397..8f56674 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Exception/ParseException.php @@ -18,24 +18,19 @@ namespace ncc\ThirdParty\Symfony\Yaml\Exception; */ class ParseException extends RuntimeException { - private ?string $parsedFile; - private int $parsedLine; - private ?string $snippet; - private string $rawMessage; - /** - * @param string $message The error message + * @param string $rawMessage The error message * @param int $parsedLine The line where the error occurred * @param string|null $snippet The snippet of code near the problem * @param string|null $parsedFile The file name where the error occurred */ - public function __construct(string $message, int $parsedLine = -1, string $snippet = null, string $parsedFile = null, \Throwable $previous = null) - { - $this->parsedFile = $parsedFile; - $this->parsedLine = $parsedLine; - $this->snippet = $snippet; - $this->rawMessage = $message; - + public function __construct( + private string $rawMessage, + private int $parsedLine = -1, + private ?string $snippet = null, + private ?string $parsedFile = null, + ?\Throwable $previous = null, + ) { $this->updateRepr(); parent::__construct($this->message, 0, $previous); @@ -51,10 +46,8 @@ class ParseException extends RuntimeException /** * Sets the snippet of code near the error. - * - * @return void */ - public function setSnippet(string $snippet) + public function setSnippet(string $snippet): void { $this->snippet = $snippet; @@ -73,10 +66,8 @@ class ParseException extends RuntimeException /** * Sets the filename where the error occurred. - * - * @return void */ - public function setParsedFile(string $parsedFile) + public function setParsedFile(string $parsedFile): void { $this->parsedFile = $parsedFile; @@ -93,10 +84,8 @@ class ParseException extends RuntimeException /** * Sets the line where the error occurred. - * - * @return void */ - public function setParsedLine(int $parsedLine) + public function setParsedLine(int $parsedLine): void { $this->parsedLine = $parsedLine; diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Inline.php b/src/ncc/ThirdParty/Symfony/Yaml/Inline.php index 9fd7306..5b7f3ff 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Inline.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Inline.php @@ -34,7 +34,7 @@ class Inline private static bool $objectForMap = false; private static bool $constantSupport = false; - public static function initialize(int $flags, int $parsedLineNumber = null, string $parsedFilename = null): void + public static function initialize(int $flags, ?int $parsedLineNumber = null, ?string $parsedFilename = null): void { self::$exceptionOnInvalidType = (bool) (Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE & $flags); self::$objectSupport = (bool) (Yaml::PARSE_OBJECT & $flags); @@ -55,7 +55,7 @@ class Inline * * @throws ParseException */ - public static function parse(string $value = null, int $flags = 0, array &$references = []): mixed + public static function parse(string $value, int $flags = 0, array &$references = []): mixed { self::initialize($flags); @@ -116,7 +116,7 @@ class Inline default => 'Y-m-d\TH:i:s.uP', }); case $value instanceof \UnitEnum: - return sprintf('!php/const %s::%s', $value::class, $value->name); + return sprintf('!php/enum %s::%s', $value::class, $value->name); case \is_object($value): if ($value instanceof TaggedValue) { return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags); @@ -157,7 +157,7 @@ class Inline } elseif (floor($value) == $value && $repr == $value) { // Preserve float data type since storing a whole number will result in integer value. if (!str_contains($repr, 'E')) { - $repr = $repr.'.0'; + $repr .= '.0'; } } } else { @@ -267,7 +267,7 @@ class Inline * * @throws ParseException When malformed inline YAML string is parsed */ - public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null): mixed + public static function parseScalar(string $scalar, int $flags = 0, ?array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], ?bool &$isQuoted = null): mixed { if (\in_array($scalar[$i], ['"', "'"], true)) { // quoted scalar @@ -353,11 +353,18 @@ class Inline ++$i; // [foo, bar, ...] + $lastToken = null; while ($i < $len) { if (']' === $sequence[$i]) { return $output; } if (',' === $sequence[$i] || ' ' === $sequence[$i]) { + if (',' === $sequence[$i] && (null === $lastToken || 'separator' === $lastToken)) { + $output[] = null; + } elseif (',' === $sequence[$i]) { + $lastToken = 'separator'; + } + ++$i; continue; @@ -401,6 +408,7 @@ class Inline $output[] = $value; + $lastToken = 'value'; ++$i; } @@ -527,7 +535,7 @@ class Inline if ('<<' === $key) { $output += $value; } elseif ($allowOverwrite || !isset($output[$key])) { - if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { + if (!$isValueQuoted && \is_string($value) && '' !== $value && '&' === $value[0] && !self::isBinaryString($value) && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { $references[$matches['ref']] = $matches['value']; $value = $matches['value']; } @@ -556,7 +564,7 @@ class Inline * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ - private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null): mixed + private static function evaluateScalar(string $scalar, int $flags, array &$references = [], ?bool &$isQuotedString = null): mixed { $isQuotedString = false; $scalar = trim($scalar); @@ -643,24 +651,31 @@ class Inline } $i = 0; - $enum = self::parseScalar(substr($scalar, 10), 0, null, $i, false); - if ($useValue = str_ends_with($enum, '->value')) { - $enum = substr($enum, 0, -7); - } - if (!\defined($enum)) { + $enumName = self::parseScalar(substr($scalar, 10), 0, null, $i, false); + $useName = str_contains($enumName, '::'); + $enum = $useName ? strstr($enumName, '::', true) : $enumName; + + if (!enum_exists($enum)) { throw new ParseException(sprintf('The enum "%s" is not defined.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } - - $value = \constant($enum); - - if (!$value instanceof \UnitEnum) { - throw new ParseException(sprintf('The string "%s" is not the name of a valid enum.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); + if (!$useName) { + return $enum::cases(); } + if ($useValue = str_ends_with($enumName, '->value')) { + $enumName = substr($enumName, 0, -7); + } + + if (!\defined($enumName)) { + throw new ParseException(sprintf('The string "%s" is not the name of a valid enum.', $enumName), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); + } + + $value = \constant($enumName); + if (!$useValue) { return $value; } if (!$value instanceof \BackedEnum) { - throw new ParseException(sprintf('The enum "%s" defines no value next to its name.', $enum), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); + throw new ParseException(sprintf('The enum "%s" defines no value next to its name.', $enumName), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); } return $value->value; @@ -709,8 +724,13 @@ class Inline case Parser::preg_match('/^(-|\+)?[0-9][0-9_]*(\.[0-9_]+)?$/', $scalar): return (float) str_replace('_', '', $scalar); case Parser::preg_match(self::getTimestampRegex(), $scalar): - // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. - $time = new \DateTimeImmutable($scalar, new \DateTimeZone('UTC')); + try { + // When no timezone is provided in the parsed date, YAML spec says we must assume UTC. + $time = new \DateTimeImmutable($scalar, new \DateTimeZone('UTC')); + } catch (\Exception $e) { + // Some dates accepted by the regex are not valid dates. + throw new ParseException(\sprintf('The date "%s" could not be parsed as it is an invalid date.', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename, $e); + } if (Yaml::PARSE_DATETIME & $flags) { return $time; diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Parser.php b/src/ncc/ThirdParty/Symfony/Yaml/Parser.php index 863375e..b70ccea 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Parser.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Parser.php @@ -182,9 +182,8 @@ class Parser || self::preg_match('#^(?P'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\{\[].*?) *\:(\s+(?P.+?))?\s*$#u', $this->trimTag($values['value']), $matches) ) ) { - // this is a compact notation element, add to next block and parse $block = $values['value']; - if ($this->isNextLineIndented()) { + if ($this->isNextLineIndented() || isset($matches['value']) && '>-' === $matches['value']) { $block .= "\n".$this->getNextEmbedBlock($this->getCurrentLineIndentation() + \strlen($values['leadspaces']) + 1); } @@ -198,14 +197,9 @@ class Parser array_pop($this->refsBeingParsed); } } elseif ( - // @todo in 7.0 remove legacy "(?:!?!php/const:)?" - self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(( |\t)++(?P.+))?$#u', rtrim($this->currentLine), $values) + self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|[^ \'"\[\{!].*?)) *\:(( |\t)++(?P.+))?$#u', rtrim($this->currentLine), $values) && (!str_contains($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"])) ) { - if (str_starts_with($values['key'], '!php/const:')) { - trigger_deprecation('symfony/yaml', '6.2', 'YAML syntax for key "%s" is deprecated and replaced by "!php/const %s".', $values['key'], substr($values['key'], 11)); - } - if ($context && 'sequence' == $context) { throw new ParseException('You cannot define a mapping item when in a sequence.', $this->currentLineNb + 1, $this->currentLine, $this->filename); } @@ -413,7 +407,7 @@ class Parser throw new ParseException('Multiple documents are not supported.', $this->currentLineNb + 1, $this->currentLine, $this->filename); } - if ($deprecatedUsage = (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1])) { + if (isset($this->currentLine[1]) && '?' === $this->currentLine[0] && ' ' === $this->currentLine[1]) { throw new ParseException('Complex mappings are not supported.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } @@ -443,7 +437,7 @@ class Parser continue; } // If the indentation is not consistent at offset 0, it is to be considered as a ParseError - if (0 === $this->offset && !$deprecatedUsage && isset($line[0]) && ' ' === $line[0]) { + if (0 === $this->offset && isset($line[0]) && ' ' === $line[0]) { throw new ParseException('Unable to parse.', $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); } @@ -500,7 +494,7 @@ class Parser $data = $object; } - return empty($data) ? null : $data; + return $data ?: null; } private function parseBlock(int $offset, string $yaml, int $flags): mixed @@ -562,7 +556,7 @@ class Parser * * @throws ParseException When indentation problem are detected */ - private function getNextEmbedBlock(int $indentation = null, bool $inSequence = false): string + private function getNextEmbedBlock(?int $indentation = null, bool $inSequence = false): string { $oldLineIndentation = $this->getCurrentLineIndentation(); @@ -639,12 +633,12 @@ class Parser } if ($this->isCurrentLineBlank()) { - $data[] = substr($this->currentLine, $newIndent); + $data[] = substr($this->currentLine, $newIndent ?? 0); continue; } if ($indent >= $newIndent) { - $data[] = substr($this->currentLine, $newIndent); + $data[] = substr($this->currentLine, $newIndent ?? 0); } elseif ($this->isCurrentLineComment()) { $data[] = $this->currentLine; } elseif (0 == $indent) { @@ -932,6 +926,10 @@ class Parser } while (!$EOF && ($this->isCurrentLineEmpty() || $this->isCurrentLineComment())); if ($EOF) { + for ($i = 0; $i < $movements; ++$i) { + $this->moveToPreviousLine(); + } + return false; } @@ -1040,7 +1038,7 @@ class Parser * * @internal */ - public static function preg_match(string $pattern, string $subject, array &$matches = null, int $flags = 0, int $offset = 0): int + public static function preg_match(string $pattern, string $subject, ?array &$matches = null, int $flags = 0, int $offset = 0): int { if (false === $ret = preg_match($pattern, $subject, $matches, $flags, $offset)) { throw new ParseException(preg_last_error_msg()); diff --git a/src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php b/src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php index 6fb607c..669bf60 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php +++ b/src/ncc/ThirdParty/Symfony/Yaml/Tag/TaggedValue.php @@ -17,13 +17,10 @@ namespace ncc\ThirdParty\Symfony\Yaml\Tag; */ final class TaggedValue { - private string $tag; - private mixed $value; - - public function __construct(string $tag, mixed $value) - { - $this->tag = $tag; - $this->value = $value; + public function __construct( + private string $tag, + private mixed $value, + ) { } public function getTag(): string diff --git a/src/ncc/ThirdParty/Symfony/Yaml/VERSION b/src/ncc/ThirdParty/Symfony/Yaml/VERSION index d9b300f..334b5ce 100644 --- a/src/ncc/ThirdParty/Symfony/Yaml/VERSION +++ b/src/ncc/ThirdParty/Symfony/Yaml/VERSION @@ -1 +1 @@ -6.3.3 \ No newline at end of file +7.1.4 \ No newline at end of file