id; } /** * The extension's heading, or the id when it has none to give: the * runner asks for it again to label a failed row, so it never throws. */ public function label(): string { try { $label = self::cut( $this->check->label(), self::MAX_LINE ); } catch ( Throwable ) { $label = ''; } return '' === $label ? $this->id : $label; } /** * The extension's findings, filed under this check. * * @return list * @throws UnexpectedValueException When the check answers with anything * but findings. */ public function run(): array { $findings = $this->check->run(); if ( count( $findings ) > self::MAX_FINDINGS ) { throw new UnexpectedValueException( 'The check reported more than ' . (int) self::MAX_FINDINGS . ' findings.' ); } $filed = array(); foreach ( $findings as $finding ) { if ( ! $finding instanceof Finding ) { throw new UnexpectedValueException( 'The check returned something other than a finding.' ); } $filed[] = $this->file( $finding ); } return $filed; } /** * One finding, filed under this check. * * @param Finding $finding As the extension reported it. */ private function file( Finding $finding ): Finding { $prefix = $this->id . ':'; $key = '' === $finding->key || str_starts_with( $finding->key, $prefix ) ? $finding->key : $prefix . $finding->key; $tab = null !== $finding->tab && Sections::has( $finding->tab ) ? $finding->tab : null; return new Finding( $this->id, $finding->severity, self::cut( $finding->title, self::MAX_LINE ), self::cut( $finding->detail, self::MAX_DETAIL ), self::cut( $finding->subject, self::MAX_LINE ), $tab, self::cut( $key, self::MAX_KEY ), self::cut( $finding->state, self::MAX_KEY ) ); } /** * A string cut to a length, so a noisy check cannot bloat the report or * the scan history that stores it. * * @param string $text Text. * @param int $length Most characters kept. */ private static function cut( string $text, int $length ): string { return mb_substr( $text, 0, $length ); } }