![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/old/vendor/magento/magento-coding-standard/PHP_CodeSniffer/Tokenizers/ |
<?php /** * Copyright © Magento, Inc. All rights reserved. * See COPYING.txt for license details. */ namespace PHP_CodeSniffer\Tokenizers; use GraphQL\Language\Lexer; use GraphQL\Language\Source; use GraphQL\Language\Token; /** * Implements a tokenizer for GraphQL files. */ class GRAPHQL extends Tokenizer { /** * Defines how GraphQL token types are mapped to PHP token types. * * This is a complete list of all token types supported by <kbd>webonyx/graphql-php</var>. <knd>null</kbd> values * are automatically mapped to <kbd>T_STRING</kbd> but are noted as <kbd>null</kbd> in this list to improve * maintenance at a glance. * * @var array */ private $tokenTypeMap = [ Token::AT => 'T_DOC_COMMENT_TAG', Token::BANG => 'T_BOOLEAN_NOT', Token::BLOCK_STRING => 'T_COMMENT', Token::BRACE_L => 'T_OPEN_CURLY_BRACKET', Token::BRACE_R => 'T_CLOSE_CURLY_BRACKET', Token::BRACKET_L => 'T_OPEN_SQUARE_BRACKET', Token::BRACKET_R => 'T_CLOSE_SQUARE_BRACKET', Token::COLON => 'T_COLON', Token::COMMENT => 'T_COMMENT', Token::DOLLAR => 'T_DOLLAR', Token::EOF => 'T_CLOSE_TAG', Token::EQUALS => 'T_EQUAL', Token::FLOAT => null, Token::INT => null, Token::NAME => 'T_STRING', Token::PAREN_L => 'T_OPEN_PARENTHESIS', Token::PAREN_R => 'T_CLOSE_PARENTHESIS', Token::PIPE => null, Token::SPREAD => 'T_ELLIPSIS', Token::SOF => 'T_OPEN_TAG', Token::STRING => 'T_STRING', ]; /** * Defines how special keywords are mapped to PHP token types * * @var array */ private $keywordTokenTypeMap = [ 'enum' => 'T_CLASS', 'extend' => 'T_EXTENDS', 'interface' => 'T_INTERFACE', 'implements' => 'T_IMPLEMENTS', 'type' => 'T_CLASS', 'union' => 'T_CLASS', 'query' => 'T_FUNCTION', 'mutation' => 'T_FUNCTION', ]; /** * @inheritDoc */ public function processAdditional() { $this->logVerbose('*** START ADDITIONAL GRAPHQL PROCESSING ***'); $this->fixErroneousKeywordTokens(); $this->processFields(); $this->logVerbose('*** END ADDITIONAL GRAPHQL PROCESSING ***'); } /** * @inheritDoc */ protected function tokenize($string) { $this->logVerbose('*** START GRAPHQL TOKENIZING ***'); $string = str_replace($this->eolChar, "\n", $string); $tokens = []; $source = new Source($string); $lexer = new Lexer($source); do { $kind = $lexer->token->kind; $value = $lexer->token->value ?: ''; //if we have encountered a keyword, we convert it //otherwise we translate the token or default it to T_STRING if ($kind === Token::NAME && isset($this->keywordTokenTypeMap[$value])) { $tokenType = $this->keywordTokenTypeMap[$value]; } elseif (isset($this->tokenTypeMap[$kind])) { $tokenType = $this->tokenTypeMap[$kind]; } else { $tokenType = 'T_STRING'; } //some GraphQL tokens need special handling switch ($kind) { case Token::AT: case Token::BRACE_L: case Token::BRACE_R: case Token::PAREN_L: case Token::PAREN_R: case Token::COLON: case Token::BRACKET_L: case Token::BRACKET_R: case Token::BANG: $value = $kind; break; default: //NOP } //finally we create the PHP token $token = [ 'code' => constant($tokenType), 'type' => $tokenType, 'content' => $value, ]; $line = $lexer->token->line; $lexer->advance(); //if line has changed (and we're not on start of file) we have to append at least one line break to current //token's content otherwise PHP_CodeSniffer will screw up line numbers if ($lexer->token->line !== $line && $kind !== Token::SOF) { $token['content'] .= $this->eolChar; } $tokens[] = $token; $tokens = array_merge( $tokens, $this->getNewLineTokens($line, $lexer->token->line) ); } while ($lexer->token->kind !== Token::EOF); $this->logVerbose('*** END GRAPHQL TOKENIZING ***'); return $tokens; } /** * Fixes that keywords may be used as field, argument etc. names and could thus have been marked as special tokens * while tokenizing. */ private function fixErroneousKeywordTokens() { $processingCodeBlock = false; $numTokens = count($this->tokens); for ($i = 0; $i < $numTokens; ++$i) { $tokenCode = $this->tokens[$i]['code']; $tokenContent = $this->tokens[$i]['content']; switch (true) { case $tokenCode === T_OPEN_CURLY_BRACKET: //we have hit the beginning of a code block $processingCodeBlock = true; break; case $tokenCode === T_CLOSE_CURLY_BRACKET: //we have hit the end of a code block $processingCodeBlock = false; break; case $processingCodeBlock && $tokenCode !== T_STRING && isset($this->keywordTokenTypeMap[$tokenContent]): //we have hit a keyword within a code block that is of wrong token type $this->tokens[$i]['code'] = T_STRING; $this->tokens[$i]['type'] = 'T_STRING'; break; default: //NOP All operations have already been executed } } } /** * Returns tokens of empty new lines for the range <var>$lineStart</var> to <var>$lineEnd</var> * * @param int $lineStart * @param int $lineEnd * @return array */ private function getNewLineTokens($lineStart, $lineEnd) { $amount = ($lineEnd - $lineStart) - 1; $tokens = []; for ($i = 0; $i < $amount; ++$i) { $tokens[] = [ 'code' => T_WHITESPACE, 'type' => 'T_WHITESPACE', 'content' => $this->eolChar, ]; } return $tokens; } /** * Returns whether the token under <var>$stackPointer</var> is a field. * * We consider a token to be a field if: * <ul> * <li>its direct successor is of type {@link T_COLON}</li> * <li>it has a list of arguments followed by a {@link T_COLON}</li> * </ul> * * @param int $stackPointer * @return bool */ private function isFieldToken($stackPointer) { //bail out if current token is nested in a parenthesis, since fields cannot be contained in parenthesises if (isset($this->tokens[$stackPointer]['nested_parenthesis'])) { return false; } $nextToken = $this->tokens[$stackPointer + 1]; //if next token is an opening parenthesis, we advance to the token after the closing parenthesis if ($nextToken['code'] === T_OPEN_PARENTHESIS) { $nextPointer = $nextToken['parenthesis_closer'] + 1; $nextToken = $this->tokens[$nextPointer]; } //return whether current token is a string and next token is a colon return $this->tokens[$stackPointer]['code'] === T_STRING && $nextToken['code'] === T_COLON; } /** * Logs <var>$message</var> if {@link PHP_CODESNIFFER_VERBOSITY} is greater than <var>$level</var>. * * @param string $message * @param int $level */ private function logVerbose($message, $level = 1) { if (PHP_CODESNIFFER_VERBOSITY > $level) { printf("\t%s" . PHP_EOL, $message); } } /** * Processes field tokens, setting their type to {@link T_VARIABLE}. */ private function processFields() { $processingEntity = false; $numTokens = count($this->tokens); $entityTypes = [T_CLASS, T_INTERFACE]; $skipTypes = [T_COMMENT, T_WHITESPACE]; for ($i = 0; $i < $numTokens; ++$i) { $tokenCode = $this->tokens[$i]['code']; //process current token switch (true) { case in_array($tokenCode, $skipTypes): //we have hit a token that needs to be skipped -> NOP break; case in_array($tokenCode, $entityTypes) && $this->tokens[$i]['content'] !== 'enum': //we have hit an entity declaration $processingEntity = true; break; case $tokenCode === T_CLOSE_CURLY_BRACKET: //we have hit the end of an entity declaration $processingEntity = false; break; case $processingEntity && $this->isFieldToken($i): //we have hit a field $this->tokens[$i]['code'] = T_VARIABLE; $this->tokens[$i]['type'] = 'T_VARIABLE'; break; default: //NOP All operations have already been executed } } } }