%PDF- %PDF-
Direktori : /home/q/g/b/qgbqkvz/www/wp-content/plugins/wp-scss/scssphp/src/Ast/Sass/ |
Current File : /home/q/g/b/qgbqkvz/www/wp-content/plugins/wp-scss/scssphp/src/Ast/Sass/ArgumentDeclaration.php |
<?php /** * SCSSPHP * * @copyright 2012-2020 Leaf Corcoran * * @license http://opensource.org/licenses/MIT MIT * * @link http://scssphp.github.io/scssphp */ namespace ScssPhp\ScssPhp\Ast\Sass; use ScssPhp\ScssPhp\Exception\SassFormatException; use ScssPhp\ScssPhp\Exception\SassScriptException; use ScssPhp\ScssPhp\Logger\LoggerInterface; use ScssPhp\ScssPhp\Parser\ScssParser; use ScssPhp\ScssPhp\SourceSpan\FileSpan; /** * An argument declaration, as for a function or mixin definition. * * @internal */ final class ArgumentDeclaration implements SassNode { /** * @var list<Argument> * @readonly */ private $arguments; /** * @var string|null * @readonly */ private $restArgument; /** * @var FileSpan * @readonly */ private $span; /** * @param list<Argument> $arguments * @param FileSpan $span * @param string|null $restArgument */ public function __construct(array $arguments, FileSpan $span, ?string $restArgument = null) { $this->arguments = $arguments; $this->restArgument = $restArgument; $this->span = $span; } public static function createEmpty(FileSpan $span): ArgumentDeclaration { return new self([], $span); } /** * Parses an argument declaration from $contents, which should be of the * form `@rule name(args) {`. * * If passed, $url is the name of the file from which $contents comes. * * @throws SassFormatException if parsing fails. */ public static function parse(string $contents, ?LoggerInterface $logger = null, ?string $url = null): ArgumentDeclaration { return (new ScssParser($contents, $logger, $url))->parseArgumentDeclaration(); } public function isEmpty(): bool { return \count($this->arguments) === 0 && $this->restArgument === null; } /** * @return list<Argument> */ public function getArguments(): array { return $this->arguments; } public function getRestArgument(): ?string { return $this->restArgument; } public function getSpan(): FileSpan { return $this->span; } /** * @param int $positional * @param array<string, mixed> $names Only keys are relevant * * @throws SassScriptException if $positional and $names aren't valid for this argument declaration. */ public function verify(int $positional, array $names): void { $nameUsed = 0; foreach ($this->arguments as $i => $argument) { if ($i < $positional) { if (isset($names[$argument->getName()])) { $originalName = $this->originalArgumentName($argument->getName()); throw new SassScriptException(sprintf('Argument $%s was passed both by position and by name.', $originalName)); } } elseif (isset($names[$argument->getName()])) { $nameUsed++; } elseif ($argument->getDefaultValue() === null) { $originalName = $this->originalArgumentName($argument->getName()); throw new SassScriptException(sprintf('Missing argument $%s', $originalName)); } } if ($this->restArgument !== null) { return; } if ($positional > \count($this->arguments)) { $message = sprintf( 'Only %d %sargument%s allowed, but %d %s passed.', \count($this->arguments), empty($names) ? '' : 'positional ', \count($this->arguments) === 1 ? '' : 's', $positional, $positional === 1 ? 'was' : 'were' ); throw new SassScriptException($message); } if ($nameUsed < \count($names)) { $unknownNames = array_values(array_diff(array_keys($names), array_map(function ($argument) { return $argument->getName(); }, $this->arguments))); $lastName = array_pop($unknownNames); $message = sprintf( 'No argument%s named $%s%s.', $unknownNames ? 's' : '', $unknownNames ? implode(', $', $unknownNames) . ' or $' : '', $lastName ); throw new SassScriptException($message); } } private function originalArgumentName(string $name): string { if ($name === $this->restArgument) { $text = $this->span->getText(); $lastDollar = strrpos($text, '$'); assert($lastDollar !== false); $fromDollar = substr($text, $lastDollar); $dot = strrpos($fromDollar, '.'); assert($dot !== false); return substr($fromDollar, 0, $dot); } foreach ($this->arguments as $argument) { if ($argument->getName() === $name) { return $argument->getOriginalName(); } } throw new \InvalidArgumentException("This declaration has no argument named \"\$$name\"."); } /** * Returns whether $positional and $names are valid for this argument * declaration. * * @param int $positional * @param array<string, mixed> $names Only keys are relevant * * @return bool */ public function matches(int $positional, array $names): bool { $nameUsed = 0; foreach ($this->arguments as $i => $argument) { if ($i < $positional) { if (isset($names[$argument->getName()])) { return false; } } elseif (isset($names[$argument->getName()])) { $nameUsed++; } elseif ($argument->getDefaultValue() === null) { return false; } } if ($this->restArgument !== null) { return true; } if ($positional > \count($this->arguments)) { return false; } if ($nameUsed < \count($names)) { return false; } return true; } public function __toString(): string { $parts = []; foreach ($this->arguments as $arg) { $parts[] = "\$$arg"; } if ($this->restArgument !== null) { $parts[] = "\$$this->restArgument..."; } return implode(', ', $parts); } }