Scrutinizer GitHub App not installed

We could not synchronize checks via GitHub's checks API since Scrutinizer's GitHub App is not installed for this repository.

Install GitHub App

GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Dewidow_Fix::dewidow()   B
last analyzed

Complexity

Conditions 7
Paths 2

Size

Total Lines 31
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 7

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 31
rs 8.8333
c 0
b 0
f 0
ccs 14
cts 14
cp 1
cc 7
nc 2
nop 6
crap 7
1
<?php
2
/**
3
 *  This file is part of PHP-Typography.
4
 *
5
 *  Copyright 2014-2019 Peter Putzer.
6
 *  Copyright 2009-2011 KINGdesk, LLC.
7
 *
8
 *  This program is free software; you can redistribute it and/or modify modify
9
 *  it under the terms of the GNU General Public License as published by
10
 *  the Free Software Foundation; either version 2 of the License, or
11
 *  (at your option) any later version.
12
 *
13
 *  This program is distributed in the hope that it will be useful,
14
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
15
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16
 *  GNU General Public License for more details.
17
 *
18
 *  You should have received a copy of the GNU General Public License along
19
 *  with this program; if not, write to the Free Software Foundation, Inc.,
20
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21
 *
22
 *  ***
23
 *
24
 *  @package mundschenk-at/php-typography
25
 *  @license http://www.gnu.org/licenses/gpl-2.0.html
26
 */
27
28
namespace PHP_Typography\Fixes\Node_Fixes;
29
30
use PHP_Typography\DOM;
31
use PHP_Typography\RE;
32
use PHP_Typography\Settings;
33
use PHP_Typography\Strings;
34
use PHP_Typography\U;
35
36
/**
37
 * Prevents widows (if enabled).
38
 *
39
 * @author Peter Putzer <[email protected]>
40
 *
41
 * @since 5.0.0
42
 */
43
class Dewidow_Fix extends Abstract_Node_Fix {
44
	const SPACE_BETWEEN = '[\s]+'; // \s includes all special spaces (but not ZWSP) with the u flag.
45
	const WIDOW         = '[\w\p{M}\-' . U::HYPHEN . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+?'; // \w includes all alphanumeric Unicode characters but not composed characters.
46
47
	// Mandatory UTF-8 modifer.
48
	const REGEX_START = '/
49
		(?:
50
			\A
51
			|
52
			(?:
53
				(?<space_before>            # subpattern 1: space before (note: ZWSP is not a space)
54
					[\s' . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+
55
				)
56
				(?<neighbor>                # subpattern 2: neighbors widow (short as possible)
57
					[^\s' . U::ZERO_WIDTH_SPACE . U::SOFT_HYPHEN . ']+?
58
				)
59
			)
60
		)
61
		(?<space_between>                   # subpattern 3: space between
62
			' . self::SPACE_BETWEEN . '
63
		)
64
		(?<widow>                           # subpattern 4: widow
65
			' . self::WIDOW . '
66
			(?:
67
				' . self::SPACE_BETWEEN . self::WIDOW . '
68
			){0,'; // The maximum number of repetitions is missing.
69
70
	const REGEX_END =
71
		'})
72
		(?<trailing>                       # subpattern 5: any trailing punctuation or spaces
73
			[^\w\p{M}]*
74
		)
75
		\Z
76
	/Sxu';
77
78
	const MASKED_NARROW_SPACE = '__NO_BREAK_NARROW_SPACE__';
79
80
	/**
81
	 * Apply the fix to a given textnode.
82
	 *
83
	 * @param \DOMText $textnode Required.
84
	 * @param Settings $settings Required.
85
	 * @param bool     $is_title Optional. Default false.
86
	 */
87 56
	public function apply( \DOMText $textnode, Settings $settings, $is_title = false ) {
88
		// Intervening inline tags may interfere with widow identification, but that is a sacrifice of using the parser.
89
		// Intervening tags will only interfere if they separate the widow from previous or preceding whitespace.
90 56
		if ( empty( $settings[ Settings::DEWIDOW ] ) || empty( $settings[ Settings::DEWIDOW_MAX_PULL ] ) || empty( $settings[ Settings::DEWIDOW_MAX_LENGTH ] ) ) {
91 28
			return;
92
		}
93
94 28
		if ( '' === DOM::get_next_chr( $textnode ) ) {
95
			// We have the last type "text" child of a block level element.
96 28
			$textnode->data = $this->dewidow( $textnode->data, Strings::functions( $textnode->data ), $settings[ Settings::DEWIDOW_MAX_PULL ], $settings[ Settings::DEWIDOW_MAX_LENGTH ], $settings[ Settings::DEWIDOW_WORD_NUMBER ], U::NO_BREAK_NARROW_SPACE );
97
		}
98 28
	}
99
100
	/**
101
	 * Dewidow a given text fragment.
102
	 *
103
	 * @since 6.5.0 Parameter $narrow_space has been deprecated.
104
	 *
105
	 * @param  string $text         The text fragment to dewidow.
106
	 * @param  array  $func         An array of string functions.
107
	 * @param  int    $max_pull     Maximum number of characters pulled from previous line.
108
	 * @param  int    $max_length   Maximum widow length.
109
	 * @param  int    $word_number  Maximum number of words allowed in widow.
110
	 * @param  string $deprecated   Ignored.
111
	 *
112
	 * @return string
113
	 */
114 28
	protected function dewidow( $text, array $func, $max_pull, $max_length, $word_number, $deprecated ) {
115 28
		if ( $word_number < 1 ) {
116 5
			return $text; // We are done.
117
		}
118
119
		// Do what we have to do.
120 28
		return \preg_replace_callback(
121 28
			self::REGEX_START . ( $word_number - 1 ) . self::REGEX_END,
122
			function( array $widow ) use ( $func, $max_pull, $max_length, $word_number ) {
123
124
				// If we are here, we know that widows are being protected in some fashion
125
				// with that, we will assert that widows should never be hyphenated or wrapped
126
				// as such, we will strip soft hyphens and zero-width-spaces.
127 27
				$widow['widow']    = self::strip_breaking_characters( $widow['widow'] );
128 27
				$widow['trailing'] = self::strip_breaking_characters( self::make_space_nonbreaking( $widow['trailing'], U::NO_BREAK_NARROW_SPACE, $func['u'] ) );
129
130
				if (
131
					// Eject if widows neighbor is proceeded by a no break space (the pulled text would be too long).
132 27
					'' === $widow['space_before'] || false !== \strpos( $widow['space_before'], U::NO_BREAK_SPACE ) ||
133
					// Eject if widows neighbor length exceeds the max allowed or widow length exceeds max allowed.
134 26
					$func['strlen']( $widow['neighbor'] ) > $max_pull || $func['strlen']( $widow['widow'] ) > $max_length ||
135
					// Never replace thin and hair spaces with &nbsp;.
136 27
					self::is_narrow_space( $widow['space_between'] )
137
				) {
138 7
					return $widow['space_before'] . $widow['neighbor'] . $this->dewidow( $widow['space_between'] . $widow['widow'] . $widow['trailing'], $func, $max_pull, $max_length, $word_number - 1, U::NO_BREAK_NARROW_SPACE );
139
				}
140
141
				// Let's protect some widows!
142 22
				return $widow['space_before'] . $widow['neighbor'] . U::NO_BREAK_SPACE . self::make_space_nonbreaking( $widow['widow'], U::NO_BREAK_NARROW_SPACE, $func['u'] ) . $widow['trailing'];
143 28
			},
144 28
			$text
145
		);
146
	}
147
148
	/**
149
	 * Strip zero-width space and soft hyphens from the given string.
150
	 *
151
	 * @param  string $string Required.
152
	 *
153
	 * @return string
154
	 */
155 1
	protected static function strip_breaking_characters( $string ) {
156 1
		return \str_replace( [ U::ZERO_WIDTH_SPACE, U::SOFT_HYPHEN ], '', $string );
157
	}
158
159
	/**
160
	 * Is the given string one of the narrow space characters?
161
	 *
162
	 * @since 6.0.0
163
	 *
164
	 * @param  string $string The whitespace to test.
165
	 *
166
	 * @return bool
167
	 */
168 1
	protected static function is_narrow_space( $string ) {
169 1
		return U::THIN_SPACE === $string || U::HAIR_SPACE === $string || U::NO_BREAK_NARROW_SPACE === $string;
170
	}
171
172
	/**
173
	 * Strip zero-width space and soft hyphens from the given string.
174
	 *
175
	 * @since 6.5.0 Parameter $narrow_space has been deprecated.
176
	 *
177
	 * @param  string $string     Required.
178
	 * @param  string $deprecated Ignored.
179
	 * @param  string $u          Either 'u' or the empty string.
180
	 *
181
	 * @return string
182
	 */
183 1
	protected static function make_space_nonbreaking( $string, $deprecated, $u ) {
184 1
		return \preg_replace(
185
			[
186 1
				'/\s*(?:' . U::THIN_SPACE . '|' . U::NO_BREAK_NARROW_SPACE . ')\s*/Su',
187 1
				"/\\s+/S$u",
188 1
				'/' . self::MASKED_NARROW_SPACE . "/S$u",
189
			],
190
			[
191 1
				self::MASKED_NARROW_SPACE,
192
				U::NO_BREAK_SPACE,
193
				U::NO_BREAK_NARROW_SPACE,
194
			],
195 1
			$string
196
		);
197
	}
198
}
199