Changeset 2912478
- Timestamp:
- 05/15/2023 12:35:28 PM (3 years ago)
- Location:
- torque/trunk
- Files:
-
- 25 edited
-
app.php (modified) (3 diffs)
-
assets.php (modified) (3 diffs)
-
overview.php (modified) (2 diffs)
-
packages.php (modified) (1 diff)
-
packages/cssdoc/cssdoc.php (modified) (21 diffs)
-
packages/cssdoc/tokens/directive.php (modified) (4 diffs)
-
packages/cssdoc/tokens/document.php (modified) (2 diffs)
-
packages/cssdoc/tokens/property.php (modified) (2 diffs)
-
packages/cssdoc/tokens/rule.php (modified) (5 diffs)
-
packages/cssdoc/tokens/selector.php (modified) (4 diffs)
-
packages/cssdoc/tokens/value.php (modified) (7 diffs)
-
packages/htmldoc/helpers/selector.php (modified) (1 diff)
-
packages/htmldoc/htmldoc.php (modified) (20 diffs)
-
packages/htmldoc/tokens/tag.php (modified) (7 diffs)
-
packages/htmldoc/tokens/text.php (modified) (2 diffs)
-
packages/jslite/jslite.php (modified) (10 diffs)
-
packages/jslite/tokens/brackets.php (modified) (4 diffs)
-
packages/jslite/tokens/expression.php (modified) (12 diffs)
-
packages/jslite/tokens/keyword.php (modified) (2 diffs)
-
packages/jslite/tokens/number.php (modified) (2 diffs)
-
packages/jslite/tokens/regexp.php (modified) (2 diffs)
-
packages/jslite/tokens/string.php (modified) (2 diffs)
-
packages/jslite/tokens/whitespace.php (modified) (7 diffs)
-
readme.txt (modified) (3 diffs)
-
torque.php (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
torque/trunk/app.php
r2823176 r2912478 118 118 if ($options['preloadstyle'] && $options['combinestyle']) { 119 119 $file = $this->config['output'].\md5(\implode(',', $options['combinestyle'])).'.css'; 120 $root = \dirname(\dirname(\dirname(__DIR__))).'/'; 121 $options['preload'][] = \str_replace('\\', '/', \mb_substr($file, \mb_strlen($root)).'?'.\filemtime($file)); 120 if (\file_exists($file)) { 121 $root = \dirname(\dirname(\dirname(__DIR__))).'/'; 122 $options['preload'][] = \str_replace('\\', '/', \mb_substr($file, \mb_strlen($root)).'?'.\filemtime($file)); 123 } 122 124 } 123 125 … … 167 169 if (\file_exists($file)) { 168 170 foreach ($options['combinestyle'] AS $item) { 169 $doc->remove('link[rel=stylesheet][href*="'.$item.'"]'); 171 $style = $doc->find('link[rel=stylesheet][href*="'.$item.'"]'); 172 if (($id = $style->attr("id")) !== null) { 173 $inline = \substr($id, 0, -3).'inline-css'; 174 $doc->find('style[id="'.$inline.'"]')->remove(); 175 } 176 $style->remove(); 170 177 } 171 178 $url = \mb_substr($file, \mb_strlen($_SERVER['DOCUMENT_ROOT'])).'?'.\filemtime($file); … … 225 232 // check etags 226 233 if (($options['etags'] ?? null) !== null && empty($_POST) && $this->matchesEtag($html)) { 227 \ http_response_code(304);234 \status_header(304); 228 235 return ''; 229 236 } -
torque/trunk/assets.php
r2823176 r2912478 244 244 $dir = \dirname(\dirname(\dirname(__DIR__))).'/'; // can't use get_home_path() here 245 245 foreach ($files AS $item) { 246 $item = $dir.$item; 247 if (\file_exists($item) && ($file = \file_get_contents($item)) !== false) { 248 $css .= \preg_replace_callback('/url\\([\'"]?+([^\\)"\':]++)[\'"]?\\)/i', function (array $match) use ($item) { 249 \chdir(\dirname($item)); 246 $url = $dir.$item; 247 if (\file_exists($url) && ($file = \file_get_contents($url)) !== false) { 248 249 // add before styles 250 if (($styles = self::getInlineStyles($item)) !== null && $styles['type'] === 'before') { 251 $css .= $styles['content']; 252 } 253 254 // extract and rework asset URLs 255 $css .= \preg_replace_callback('/url\\([\'"]?+([^\\)"\':]++)[\'"]?\\)/i', function (array $match) use ($url) : string { 256 \chdir(\dirname($url)); 250 257 $path = \realpath(\dirname($match[1])).'/'.\basename($match[1]); 251 258 return 'url('.\str_replace('\\', '/', \substr($path, \strlen($_SERVER['DOCUMENT_ROOT']))).')'; 252 259 }, $file); 260 261 // add after styles 262 if (($styles['type'] ?? '') === 'after') { 263 $css .= $styles['content']; 264 } 253 265 } 254 266 } … … 278 290 } 279 291 return false; 292 } 293 294 protected static function getStyleAssets() { 295 static $style = null; 296 if ($style === null) { 297 $doc = new \hexydec\html\htmldoc(); 298 $url = \home_url().'/?notorque'; 299 if (($html = self::getPage($url)) !== false && $doc->load($html)) { 300 $style = []; 301 foreach ($doc->find('link[rel=stylesheet][id],style[id]') AS $item) { 302 $style[$item->attr('id')] = [ 303 'href' => $item->attr('href'), 304 'content' => $item->html() 305 ]; 306 } 307 } 308 } 309 return $style; 310 } 311 312 protected static function getInlineStyles(string $url) : array|null { 313 if (($style = self::getStyleAssets()) !== null) { 314 $keys = \array_flip(\array_keys($style)); 315 foreach ($style AS $key => $item) { 316 $inline = \substr($key, 0, -3).'inline-css'; 317 if (\mb_strpos($item['href'] ?? '', $url) !== false && isset($style[$inline])) { 318 return [ 319 'content' => \mb_substr($style[$inline]['content'], \mb_strpos($style[$inline]['content'], '>') + 1, -9), 320 'type' => $keys[$key] > $keys[$inline] ? 'before' : 'after' 321 ]; 322 } 323 } 324 } 325 return null; 280 326 } 281 327 … … 355 401 } 356 402 357 protected static function getExtraScript(string $url) {403 protected static function getExtraScript(string $url) : array|null { 358 404 if (($scripts = self::getScriptAssets()) !== null) { 359 405 $keys = \array_flip(\array_keys($scripts)); 360 406 foreach ($scripts AS $key => $item) { 361 if (\mb_strpos($item['src'] , $url) !== false && isset($scripts[$key.'-extra'])) {407 if (\mb_strpos($item['src'] ?? '', $url) !== false && isset($scripts[$key.'-extra'])) { 362 408 return [ 363 409 'content' => \mb_substr($scripts[$key.'-extra']['content'], \mb_strpos($scripts[$key.'-extra']['content'], '>') + 1, -9), -
torque/trunk/overview.php
r2823176 r2912478 416 416 'title' => 'Prevent MIME Type Sniffing', 417 417 'badge' => function (array $data, bool &$status = null) : string { 418 $status = $data['x-content-type-options']=== 'nosniff';418 $status = ($data['x-content-type-options'] ?? '') === 'nosniff'; 419 419 return $status ? 'Enabled' : 'Not Enabled'; 420 420 }, … … 491 491 $assets = []; 492 492 if (!empty($link)) { 493 foreach (\explode(',', $link) AS $item) {493 foreach (\explode(',', \trim($link, ',; ')) AS $item) { 494 494 $props = []; 495 495 foreach (\explode(';', $item) AS $value) { -
torque/trunk/packages.php
r2823178 r2912478 17 17 * @var string VERSION The version number of the application, this is used in the cache key for CSS/Javascript that is minified 18 18 */ 19 public const VERSION = '0.7. 1';19 public const VERSION = '0.7.2'; 20 20 21 21 /** -
torque/trunk/packages/cssdoc/cssdoc.php
r2817597 r2912478 7 7 8 8 /** 9 * @var array<string> $tokens Regexp components keyed by their corresponding codename for tokenising HTML9 * @var array<string> $tokens Regexp components keyed by their corresponding codename for tokenising CSS 10 10 */ 11 11 protected static array $tokens = [ … … 35 35 protected array $config = [ 36 36 'nested' => ['@media', '@supports', '@keyframes', '@-webkit-keyframes', '@-moz-keyframes', '@-o-keyframes', '@document', '@-moz-document', '@container'], // directive that can have nested rules 37 'spaced' => ['calc' ], // values where spaces between operators must be retained37 'spaced' => ['calc', 'min', 'max', 'clamp'], // values where spaces between operators must be retained 38 38 'quoted' => ['content', 'format', 'counters', '@charset', 'syntax', 'font-feature-settings', '-webkit-font-feature-settings', '-moz-font-feature-settings', 'quotes', 'text-overflow'], // directives or properties where the contained values must be quoted 39 39 'casesensitive' => ['url'], // property values that should not be lowercased … … 215 215 */ 216 216 public function __construct(array $config = []) { 217 if ( $config) {217 if (!empty($config)) { 218 218 $this->config = \array_replace_recursive($this->config, $config); 219 219 } … … 226 226 * @return mixed The number of children in the object for length, the output config, or null if the parameter doesn't exist 227 227 */ 228 #[\ReturnTypeWillChange] 229 public function __get(string $var) { 228 public function __get(string $var) : mixed { 230 229 if ($var === 'length') { 231 230 return \count($this->document->rules ?? []); … … 251 250 * @param mixed $value The value of the array key in the children array to be updated 252 251 */ 253 public function offsetSet( $i,$value) : void {252 public function offsetSet(mixed $i, mixed $value) : void { 254 253 if (\is_null($i)) { 255 254 $this->document->rules[] = $value; … … 262 261 * Array access method allows you to check that a key exists in the configuration array 263 262 * 264 * @param string|integer $i The key to be checked, can be a string or integer263 * @param mixed $i The key to be checked 265 264 * @return bool Whether the key exists in the config array 266 265 */ 267 public function offsetExists( $i) : bool {266 public function offsetExists(mixed $i) : bool { 268 267 return isset($this->document->rules[$i]); 269 268 } … … 272 271 * Removes a key from the configuration array 273 272 * 274 * @param string|integer $i The key to be removed, can be a string or integer275 */ 276 public function offsetUnset( $i) : void {273 * @param mixed $i The key to be removed 274 */ 275 public function offsetUnset(mixed $i) : void { 277 276 unset($this->document->rules[$i]); 278 277 } … … 281 280 * Retrieves a value from the configuration array with the specified key 282 281 * 283 * @param string|integer$i The key to be accessed, can be a string or integer282 * @param mixed $i The key to be accessed, can be a string or integer 284 283 * @return mixed The requested value or null if the key doesn't exist 285 284 */ 286 #[\ReturnTypeWillChange] 287 public function offsetGet($i) { // return reference so you can set it like an array 285 public function offsetGet(mixed $i) : mixed { // return reference so you can set it like an array 288 286 return $this->document->rules[$i] ?? null; 289 287 } … … 294 292 * @return document|rule The child node at the current pointer position 295 293 */ 296 #[\ReturnTypeWillChange] 297 public function current() { 294 public function current() : mixed { 298 295 return $this->document->rules[$this->pointer] ?? null; 299 296 } … … 304 301 * @return mixed The current pointer position 305 302 */ 306 #[\ReturnTypeWillChange]307 303 public function key() : mixed { 308 304 return $this->pointer; … … 337 333 338 334 /** 339 * Open a n HTMLfile from a URL340 * 341 * @param string $url The address of the HTMLfile to retrieve335 * Open a CSS file from a URL 336 * 337 * @param string $url The address of the CSS file to retrieve 342 338 * @param resource $context A resource object made with stream_context_create() 343 339 * @param ?string &$error A reference to any user error that is generated 344 * @return mixed The loaded HTML, or false on error345 */ 346 public function open(string $url, mixed $context = null, ?string &$error = null){340 * @return string|false The loaded CSS, or false on error 341 */ 342 public function open(string $url, $context = null, ?string &$error = null) : string|false { 347 343 348 344 // check resource … … 355 351 356 352 // retrieve the stream contents 357 } elseif (($ html= \stream_get_contents($handle)) === false) {353 } elseif (($css = \stream_get_contents($handle)) === false) { 358 354 $error = 'Could not read file "'.$url.'"'; 359 355 … … 373 369 } 374 370 375 // load html376 if ($this->load($ html, $charset, $error)) {377 return $ html;371 // load CSS 372 if ($this->load($css, $charset, $error)) { 373 return $css; 378 374 } 379 375 } … … 382 378 383 379 /** 384 * Parse a n HTMLstring into the object380 * Parse a CSS string into the object 385 381 * 386 382 * @param string $css A string containing valid CSS 387 383 * @param string $charset The charset of the document 388 384 * @param ?string &$error A reference to any user error that is generated 389 * @return bool Whether the input HTMLwas parsed385 * @return bool Whether the input CSS was parsed 390 386 */ 391 387 public function load(string $css, string $charset = null, ?string &$error = null) : bool { … … 393 389 // detect the charset 394 390 if ($charset || ($charset = $this->getCharsetFromCss($css)) !== null) { 395 $css = \mb_convert_encoding($css, \mb_internal_encoding(), $charset);391 $css = \mb_convert_encoding($css, (string) \mb_internal_encoding(), $charset); 396 392 } 397 393 … … 410 406 411 407 /** 412 * Reads the charset defined in the Content-Type meta tag, or detects the charset from the HTMLcontent408 * Reads the charset defined in the Content-Type meta tag, or detects the charset from the CSS content 413 409 * 414 410 * @param string $css A string containing valid CSS … … 428 424 * 429 425 * @param string $css A string containing valid CSS 430 * @return document| boolA document object or false if the string could not be parsed431 */ 432 protected function parse(string $css) {426 * @return document|false A document object or false if the string could not be parsed 427 */ 428 protected function parse(string $css) : document|false { 433 429 434 430 // tokenise the input CSS … … 454 450 */ 455 451 public function minify(array $minify = []) : void { 456 $minify = \array_merge($this->config['minify'], $minify); 457 $this->document->minify($minify); 452 if ($this->document !== null) { 453 $minify = \array_merge($this->config['minify'], $minify); 454 $this->document->minify($minify); 455 } 458 456 } 459 457 … … 464 462 * @return string The document as a string 465 463 */ 466 public function compile(array $options = []) : string { 467 $options = \array_merge($this->config['output'], $options); 468 return $this->document->compile($options); 464 public function compile(array $options = []) : ?string { 465 if ($this->document !== null) { 466 $options = \array_merge($this->config['output'], $options); 467 return $this->document->compile($options); 468 } 469 return null; 469 470 } 470 471 … … 476 477 * @return string|false The compiled CSS, or false if the file could not be saved 477 478 */ 478 public function save(string $file = null, array $options = []) {479 public function save(string $file = null, array $options = []) : string|false { 479 480 $css = $this->compile($options); 480 481 … … 489 490 } 490 491 491 public function collection(array $rules) {492 $this->document = new document($this, $rules);493 }494 495 / **496 * Find rules in the document that match the specified criteria497 *498 * @param string $selector A string specifying the selectors to match, comma separate multiple selectors499 * @param array|string $hasProp A string or array specifying the properties that any rules must contain500 * @param array $media An array specifying how any media queries should be match, where the key is the property and the key the value. 'max-width' will match any rules where the value is lower that that specified, 'min-width' the value must be higher. Use 'media' to specify the media type501 * @param bool $exact Denotes whether to match selectors exactly, if false, selectors will be matched from the left502 * @return cssdoc A CSSdoc object503 */504 public function find(?string $selector, $hasProp = null, array $media = [], bool $exact = true) : cssdoc {505 506 // normalise selectors507 $selector = $selector === null ? null : \array_map('\\trim', \explode(',', $selector));508 if (!\is_array($hasProp)) {509 $hasProp = [$hasProp];510 }511 512 // find rules513 $rules = $this->document->find($selector, $hasProp, $media);514 515 // attach to a new document516 $obj = new cssdoc($this->config);517 $obj->collection($rules);518 return $obj;519 }492 // public function collection(array $rules) { 493 // $this->document = new document($this, $rules); 494 // } 495 496 // /** 497 // * Find rules in the document that match the specified criteria 498 // * 499 // * @param string $selector A string specifying the selectors to match, comma separate multiple selectors 500 // * @param array|string $hasProp A string or array specifying the properties that any rules must contain 501 // * @param array $media An array specifying how any media queries should be match, where the key is the property and the key the value. 'max-width' will match any rules where the value is lower that that specified, 'min-width' the value must be higher. Use 'media' to specify the media type 502 // * @param bool $exact Denotes whether to match selectors exactly, if false, selectors will be matched from the left 503 // * @return cssdoc A CSSdoc object 504 // */ 505 // public function find(?string $selector, $hasProp = null, array $media = [], bool $exact = true) : cssdoc { 506 507 // // normalise selectors 508 // $selector = $selector === null ? null : \array_map('\\trim', \explode(',', $selector)); 509 // if (!\is_array($hasProp)) { 510 // $hasProp = [$hasProp]; 511 // } 512 513 // // find rules 514 // $rules = $this->document->find($selector, $hasProp, $media); 515 516 // // attach to a new document 517 // $obj = new cssdoc($this->config); 518 // $obj->collection($rules); 519 // return $obj; 520 // } 520 521 521 522 // public function prop(string $prop, ?string $func = null) { -
torque/trunk/packages/cssdoc/tokens/directive.php
r2817597 r2912478 48 48 public function parse(tokenise $tokens) : bool { 49 49 if (($token = $tokens->current()) !== null) { 50 $directive = true;51 50 $properties = false; 52 51 $root = $this->root; … … 107 106 // minify properties 108 107 $props = $this->properties; 109 foreach ($props AS $ key => $item) {108 foreach ($props AS $item) { 110 109 $item->minify($minify); 111 110 } 112 111 113 if ($minify['semicolons'] && $props) {112 if ($minify['semicolons'] && !empty($props)) { 114 113 \end($props)->semicolon = false; 115 114 } 116 115 117 116 // minify document 118 if ($this->document ) {117 if ($this->document !== null) { 119 118 $this->document->minify($minify); 120 119 if ($minify['empty'] && !$this->document->rules) { … … 153 152 $join = $b ? ', ' : ','; 154 153 } 155 if ( !$this->properties && !$this->document) {154 if (empty($this->properties) && $this->document === null) { 156 155 $css .= ';'; 157 156 } 158 157 159 158 // compile properties 160 if ( $this->properties) {159 if (!empty($this->properties)) { 161 160 $css .= $b ? ' {' : '{'; 162 161 … … 170 169 171 170 // compile document 172 if ($this->document ) {171 if ($this->document !== null) { 173 172 $css .= $b ? ' {' : '{'; 174 173 $tab = $b ? "\n\t".$options['prefix'] : ''; -
torque/trunk/packages/cssdoc/tokens/document.php
r2817597 r2912478 19 19 * Constructs the comment object 20 20 * 21 * @param cssdoc $root The parent htmldoc object21 * @param cssdoc $root The parent cssdoc object 22 22 */ 23 23 public function __construct(cssdoc $root, array $rules = []) { … … 102 102 * @param array $media An array specifying how any media queries should be match, where the key is the property and the key the value. 'max-width' will match any rules where the value is lower that that specified, 'min-width' the value must be higher. Use 'media' to specify the media type 103 103 * @param bool $exact Denotes whether to match selectors exactly, if false, selectors will be matched from the left 104 * @return array A CSSdoc object104 * @return array An array of rule objects 105 105 */ 106 public function find(?array $selectors,$hasProp = null, array $media = [], bool $exact = true) {107 $rules = [];108 foreach ($this->rules AS $item) {109 if (\get_class($item) === '\\hexydec\\css\\cssdoc' && $item->matches($selectors, $hasProp, $exact)) {110 $rules[] = $item;111 }112 }113 return $rules;114 }106 // public function find(?array $selectors, array|string $hasProp = null, array $media = [], bool $exact = true) { 107 // $rules = []; 108 // foreach ($this->rules AS $item) { 109 // if (\get_class($item) === '\\hexydec\\css\\cssdoc' && $item->matches($selectors, $hasProp, $exact)) { 110 // $rules[] = $item; 111 // } 112 // } 113 // return $rules; 114 // } 115 115 } -
torque/trunk/packages/cssdoc/tokens/property.php
r2817597 r2912478 49 49 * 50 50 * @param string $var The name of the property to retrieve 51 * @return ?string The value of the requested property, or null if the porperty doesn't exist51 * @return mixed The value of the requested property, or null if the property doesn't exist 52 52 */ 53 public function __get(string $var) {53 public function __get(string $var) : mixed { 54 54 if ($var === 'name') { 55 55 return $this->name; … … 79 79 case 'string': 80 80 case 'colon': 81 $this->name = $prop; 81 $this->name = $prop; // set name if colon 82 82 case 'comma': 83 83 $item = new value($this->root, $this->name); -
torque/trunk/packages/cssdoc/tokens/rule.php
r2817597 r2912478 29 29 * Constructs the comment object 30 30 * 31 * @param cssdoc $root The parent htmldoc object31 * @param cssdoc $root The parent cssdoc object 32 32 */ 33 33 public function __construct(cssdoc $root) { … … 52 52 break; 53 53 case 'directive': 54 $tokens->prev(); 54 $tokens->prev(); // rewind the token and return 55 55 case 'curlyclose': 56 56 break 2; … … 76 76 } while (($token = $tokens->next()) !== null); 77 77 } 78 return $this->selectors && $this->properties;78 return !empty($this->selectors) && !empty($this->properties); 79 79 } 80 80 … … 98 98 99 99 // remove last semi-colon 100 if ( $this->properties&& $minify['semicolons']) {100 if (!empty($this->properties) && $minify['semicolons']) { 101 101 \end($this->properties)->semicolon = false; 102 102 } 103 103 } 104 104 105 public function isEmpty() {106 return !$this->properties;105 public function isEmpty() : bool { 106 return empty($this->properties); 107 107 } 108 108 … … 156 156 157 157 // check props 158 if ($matches && $hasProp) {158 if ($matches && !empty($hasProp)) { 159 159 foreach ($this->properties AS $item) { 160 160 if (!\in_array($item->name, $hasProp)) { -
torque/trunk/packages/cssdoc/tokens/selector.php
r2817597 r2912478 19 19 * Constructs the comment object 20 20 * 21 * @param cssdoc $root The parent htmldoc object21 * @param cssdoc $root The parent cssdoc object 22 22 */ 23 23 public function __construct(cssdoc $root) { … … 37 37 switch ($token['type']) { 38 38 case 'whitespace': 39 if (!$join && $this->selectors) {39 if (!$join && !empty($this->selectors)) { 40 40 $join = ' '; 41 41 } … … 45 45 $join = $token['value']; 46 46 break; 47 } 47 } // fall-through if not * 48 48 case 'string': 49 49 $this->selectors[] = [ … … 55 55 case 'colon': 56 56 $parts = ':'; 57 $brackets = false;58 57 while (($token = $tokens->next()) !== null) { 59 58 -
torque/trunk/packages/cssdoc/tokens/value.php
r2817597 r2912478 24 24 * @var array Properties 25 25 */ 26 protected $properties = [];26 protected array $properties = []; 27 27 28 28 /** … … 69 69 break; 70 70 case 'bracketopen': 71 $item = new value($this->root, !$this->brackets && $this->properties ? end($this->properties) : $this->name, true); 71 $name = !$this->brackets && !empty($this->properties) ? \end($this->properties) : $this->name; 72 $item = new value($this->root, $name, true); 72 73 if ($item->parse($tokens)) { 73 74 $this->properties[] = $item; … … 75 76 break; 76 77 case 'comment': 77 $comment = $token['value'];78 // $comment = $token['value']; 78 79 break; 79 80 case 'semicolon': … … 81 82 $this->properties[] = $token['value']; 82 83 } 84 // rewind pointer below 83 85 case 'curlyopen': 84 86 case 'curlyclose': 85 87 case 'important': 86 88 $tokens->prev(); 89 break 2; 87 90 case 'bracketclose': 88 91 break 2; … … 123 126 124 127 // shorten hex values 125 if (\preg_match('/^#(([a-f0-9])\\2)(([a-f0-9])\\4)(([a-f0-9])\\6) /i', $item, $match)) {128 if (\preg_match('/^#(([a-f0-9])\\2)(([a-f0-9])\\4)(([a-f0-9])\\6)$/i', $item, $match)) { 126 129 $item = '#'.$match[2].$match[4].$match[6]; 127 130 } … … 248 251 */ 249 252 public function compile(array $options) : string { 250 $b = $options['style'] !== 'minify';251 253 $css = $options['prefix']; 252 254 $join = ''; 253 255 $last = null; 256 $spaced = $this->root->config['spaced']; 254 257 foreach ($this->properties AS $item) { 255 258 if (\is_object($item)) { … … 259 262 $css .= '('.$item->compile($options).')'; 260 263 $join = ' '; 261 } elseif (\in_array($item, ['-', '+'], true) && !\in_array(\mb_strtolower($this->name ), $this->root->config['spaced'], true)) {264 } elseif (\in_array($item, ['-', '+'], true) && !\in_array(\mb_strtolower($this->name ?? ''), $spaced, true)) { 262 265 $css .= $item; 263 266 $join = ''; -
torque/trunk/packages/htmldoc/helpers/selector.php
r2817597 r2912478 110 110 $selectors[] = $parts; 111 111 $parts = []; 112 break ;112 break 2; 113 113 } 114 114 } while (($token = $tokens->next()) !== null); -
torque/trunk/packages/htmldoc/htmldoc.php
r2817597 r2912478 68 68 * @return mixed The number of children in the object for length, the output config, or null if the parameter doesn't exist 69 69 */ 70 #[\ReturnTypeWillChange] 71 public function __get(string $var) { 70 public function __get(string $var) : mixed { 72 71 if ($var === 'config') { 73 72 return $this->config; 74 73 } elseif ($var === 'length') { 75 74 return \count($this->children); 76 } 77 return null; 75 } else { 76 return $this->children[0]->{$var}; 77 } 78 78 } 79 79 … … 93 93 * @param mixed $value The value of the array key in the children array to be updated 94 94 */ 95 public function offsetSet( $i,$value) : void {95 public function offsetSet(mixed $i, mixed $value) : void { 96 96 $this->children[$i] = $value; 97 97 } … … 103 103 * @return bool Whether the key exists in the config array 104 104 */ 105 public function offsetExists( $i) : bool {105 public function offsetExists(mixed $i) : bool { 106 106 return isset($this->children[$i]); 107 107 } … … 112 112 * @param mixed $i The key to be removed 113 113 */ 114 public function offsetUnset( $i) : void {114 public function offsetUnset(mixed $i) : void { 115 115 unset($this->children[$i]); 116 116 } … … 122 122 * @return mixed An HTMLdoc object containing the child node at the requested position or null if there is no child at the requested position 123 123 */ 124 #[\ReturnTypeWillChange] 125 public function offsetGet($i) { // return reference so you can set it like an array 124 public function offsetGet(mixed $i) : mixed { // return reference so you can set it like an array 126 125 if (isset($this->children[$i])) { 127 126 $obj = new htmldoc($this->config); 128 $obj->collection([$this->children[$i]]); 129 return $obj; 127 return $obj->collection([$this->children[$i]]); 130 128 } 131 129 return null; … … 137 135 * @return mixed An HTMLdoc object containing the child node at the current pointer position or null if there are no children 138 136 */ 139 #[\ReturnTypeWillChange] 140 public function current() { 137 public function current() : mixed { 141 138 if (isset($this->children[$this->pointer])) { 142 139 $obj = new htmldoc($this->config); 143 $obj->collection([$this->children[$this->pointer]]); 144 return $obj; 140 return $obj->collection([$this->children[$this->pointer]]); 145 141 } 146 142 return null; … … 152 148 * @return mixed The current pointer position 153 149 */ 154 #[\ReturnTypeWillChange] 155 public function key() { 150 public function key() : mixed { 156 151 return $this->pointer; 157 152 } … … 192 187 * @return string|false The loaded HTML, or false on error 193 188 */ 194 public function open(string $url, $context = null, ?string &$error = null) {189 public function open(string $url, $context = null, ?string &$error = null) : string|false { 195 190 196 191 // check resource … … 296 291 * 297 292 * @param string|htmldoc $html A string of HTML, or an htmldoc object 298 * @return bool|arrayAn array of node objects or false on error299 */ 300 protected function parse( $html){293 * @return array|false An array of node objects or false on error 294 */ 295 protected function parse(string|htmldoc $html) : array|false { 301 296 302 297 // convert string to nodes … … 347 342 * 348 343 * @param int $index The index of the child tag to retrieve 349 * @return mixedA tag object if index is specified, or an array of tag objects, or null if the specified index doesn't exist or the object is empty350 */ 351 public function get(int $index = null) {344 * @return tag|array|null A tag object if index is specified, or an array of tag objects, or null if the specified index doesn't exist or the object is empty 345 */ 346 public function get(int $index = null) : tag|array|null { 352 347 353 348 // build children that are tags … … 362 357 if ($index === null) { 363 358 return $children; 364 } 365 366 // check if index is minus 367 if ($index < 0) { 368 $index = \count($children) + $index; 369 } 370 371 // return index if set 372 if (isset($children[$index])) { 373 return $children[$index]; 359 } else { 360 361 // check if index is minus 362 if ($index < 0) { 363 $index = \count($children) + $index; 364 } 365 366 // return index if set 367 if (isset($children[$index])) { 368 return $children[$index]; 369 } 374 370 } 375 371 return null; … … 448 444 */ 449 445 public function children() : htmldoc { 450 return $this->find('>*'); 446 return $this->find('*>*'); 447 } 448 449 /** 450 * Generate a new htmldoc object containing all the child tags of the parents 451 * 452 * @return htmldoc A new htmldoc object 453 */ 454 public function parent() : htmldoc { 455 $doc = new htmldoc($this->config); 456 $nodes = []; 457 foreach ($this->children AS $item) { 458 if (\get_class($item) === 'hexydec\\html\\tag' && ($parent = $this->children[0]->parent) !== null) { 459 $nodes[] = $parent; 460 } 461 } 462 return $doc->collection($nodes); 463 } 464 465 /** 466 * Retrieves the tag name from the first tag object in the collection 467 * 468 * @return ?string The name of the tag, or null if there are no tags in the collection 469 */ 470 public function tag() : ?string { 471 foreach ($this->children AS $item) { 472 if (\get_class($item) === 'hexydec\\html\\tag') { 473 return $item->tagName; 474 } 475 } 476 return null; 451 477 } 452 478 … … 456 482 * @param string $key The name of the attribute to retrieve 457 483 * @param string $value The value of the attribute to update 458 * @return string The value of the attribute or null if the attribute doesn't exist484 * @return ?string The value of the attribute or null if the attribute doesn't exist 459 485 */ 460 486 public function attr(string $key, ?string $value = null) : ?string { … … 492 518 * 493 519 * @param array $nodes An array of nodes to add to the collection 494 * @return void 495 */ 496 protected function collection(array $nodes) : void { 497 $this->children = $nodes; 520 * @return htmldoc The current instance of this object 521 */ 522 protected function collection(array $nodes) : htmldoc { 523 524 // only store unique nodes as some find operations can produce the same node multiple times 525 $unique = []; 526 foreach ($nodes AS $item) { 527 if (!\in_array($item, $unique, true)) { 528 $unique[] = $item; 529 } 530 } 531 $this->children = $unique; 532 return $this; 498 533 } 499 534 … … 600 635 * @return htmldoc The current htmldoc object with the nodes appended 601 636 */ 602 public function append( $html) : htmldoc {637 public function append(string|htmldoc $html) : htmldoc { 603 638 if (($nodes = $this->parse($html)) !== false) { 604 639 foreach ($this->children AS $item) { … … 617 652 * @return htmldoc The current htmldoc object with the nodes appended 618 653 */ 619 public function prepend( $html) : htmldoc {654 public function prepend(string|htmldoc $html) : htmldoc { 620 655 if (($nodes = $this->parse($html)) !== false) { 621 656 foreach ($this->children AS $item) { … … 634 669 * @return htmldoc The current htmldoc object with the nodes appended 635 670 */ 636 public function before( $html) : htmldoc {671 public function before(string|htmldoc $html) : htmldoc { 637 672 if (($nodes = $this->parse($html)) !== false) { 638 673 foreach ($this->children AS $item) { … … 651 686 * @return htmldoc The current htmldoc object with the nodes appended 652 687 */ 653 public function after( $html) : htmldoc {688 public function after(string|htmldoc $html) : htmldoc { 654 689 if (($nodes = $this->parse($html)) !== false) { 655 690 foreach ($this->children AS $item) { … … 665 700 * Removes all top level nodes, or if $selector is specified, the nodes matched by the selector 666 701 * 667 * @param string $selector A CSS selector to refine the nodes to delete or null to delete top level nodes702 * @param ?string $selector A CSS selector to refine the nodes to delete or null to delete top level nodes 668 703 * @return htmldoc The current htmldoc object with the requested nodes deleted 669 704 */ 670 public function remove( string $selector = null) : htmldoc {705 public function remove(?string $selector = null) : htmldoc { 671 706 $obj = $selector ? $this->find($selector) : $this; 672 707 foreach ($obj->children AS $item) { … … 683 718 * @param string|null $file The file location to save the document to, or null to just return the compiled code 684 719 * @param array $options An array indicating output options, this is merged with htmldoc::$output 685 * @return string| boolThe compiled HTML, or false if the file could not be saved686 */ 687 public function save( string $file = null, array $options = []){720 * @return string|false The compiled HTML, or false if the file could not be saved 721 */ 722 public function save(?string $file = null, array $options = []) : string|false { 688 723 689 724 // compile html -
torque/trunk/packages/htmldoc/tokens/tag.php
r2817597 r2912478 95 95 * @return void 96 96 */ 97 public function __clone() {97 public function __clone() : void { 98 98 foreach ($this->children AS &$item) { 99 99 $item = clone $item; … … 288 288 * Returns the parent of the current object 289 289 * 290 * @return tag The parent tag290 * @return ?tag The parent tag 291 291 */ 292 292 public function parent() : ?tag { … … 480 480 481 481 // use parent folders if it is shorter 482 if ($minify['urls']['parent'] && $dirs && \mb_strpos($attributes[$key], '/') === 0 && \mb_strpos($attributes[$key], '//') === false) {482 if ($minify['urls']['parent'] && $dirs && \mb_strpos($attributes[$key], '/') === 0 && !\str_contains($attributes[$key], '//')) { 483 483 $isDir = \mb_strrpos($attributes[$key], '/') === \mb_strlen($attributes[$key])-1; 484 484 $compare = \explode('/', \trim($isDir ? $attributes[$key] : \dirname($attributes[$key]), '/')); … … 507 507 if ($minify['attributes']) { 508 508 509 // cache attributes 510 $min = $minify['attributes']; 511 509 512 // trim attribute 510 if ($min ify['attributes']['trim'] && $attributes[$key]) {513 if ($min['trim'] && $attributes[$key]) { 511 514 $attributes[$key] = \trim($attributes[$key], " \r\n\t"); 512 515 } 513 516 514 517 // boolean attributes 515 if ($min ify['attributes']['boolean'] && \in_array($key, $attr['boolean'], true)) {518 if ($min['boolean'] && \in_array($key, $attr['boolean'], true)) { 516 519 $attributes[$key] = null; 517 520 521 // remove empty attributes 522 } elseif (\in_array($attributes[$key], ['', null], true) && $min['empty'] && \in_array($key, $attr['empty'], true)) { 523 unset($attributes[$key]); 524 518 525 // minify style tag 519 } elseif ($key === 'style' && $min ify['attributes']['style']) {526 } elseif ($key === 'style' && $min['style'] && $attributes[$key]) { 520 527 $attributes[$key] = \trim(\str_replace( 521 [ ' ', ' : ', ': ', ' :', ' ; ', ' ;', '; '],522 [' ', ' :', ':', ':', ';', ';', ';'],528 ["\t", "\r", "\n", ' ', ' : ', ': ', ' :', ' ; ', ' ;', '; '], 529 [' ', '', ' ', ' ', ':', ':', ':', ';', ';', ';'], 523 530 $attributes[$key] 524 531 ), '; '); 525 532 526 533 // trim classes 527 } elseif ($key === 'class' && $min ify['attributes']['class'] && \mb_strpos($attributes[$key], ' ') !== false) {534 } elseif ($key === 'class' && $min['class'] && \str_contains($attributes[$key] ?? '', ' ')) { 528 535 $attributes[$key] = \trim(\preg_replace('/\s+/', ' ', $attributes[$key])); 529 536 530 537 // minify option tag, always capture the tag to prevent it being removed as a default 531 538 } elseif ($key === 'value' && $tag === 'option') { 532 if ($min ify['attributes']['option'] && isset($this->children[0]) && $this->children[0]->text() === $attributes[$key]) {539 if ($min['option'] && isset($this->children[0]) && $this->children[0]->text() === $attributes[$key]) { 533 540 unset($attributes[$key]); 534 541 } 535 continue;536 542 537 543 // remove tag specific default attribute 538 } elseif ($min ify['attributes']['default'] && isset($attr['default'][$tag][$key]) && ($attr['default'][$tag][$key] === true || $attr['default'][$tag][$key] === $attributes[$key])) {544 } elseif ($min['default'] && isset($attr['default'][$tag][$key]) && ($attr['default'][$tag][$key] === true || $attr['default'][$tag][$key] === $attributes[$key])) { 539 545 unset($attributes[$key]); 540 continue;541 }542 543 // remove other attributes544 if ($attributes[$key] === '' && $minify['attributes']['empty'] && \in_array($key, $attr['empty'], true)) {545 unset($attributes[$key]);546 continue;547 546 } 548 547 } … … 643 642 644 643 // pass rest of selector to level below 645 if ( $item['join']&& $i) {644 if (\in_array($item['join'], [' ', '>'], true) && $i) { 646 645 $match = false; 646 $childselector = \array_slice($selector, $i); 647 647 foreach ($this->children AS $child) { 648 648 if (\get_class($child) === 'hexydec\\html\\tag') { 649 $found = \array_merge($found, $child->find(\array_slice($selector, $i))); 649 $found = \array_merge($found, $child->find($childselector)); 650 } 651 } 652 break; 653 654 // find siblings 655 } elseif (\in_array($item['join'], ['+', '~'], true) && $i) { 656 $match = false; 657 $siblingselector = \array_slice($selector, $i); 658 $search = false; 659 foreach ($this->parent->children AS $sibling) { 660 if (!$search && $sibling === $this) { 661 $search = true; 662 } elseif ($search && \get_class($sibling) === 'hexydec\\html\\tag') { 663 $found = \array_merge($found, $sibling->find($siblingselector)); 664 if ($item['join'] === '+') { 665 break; 666 } 650 667 } 651 668 } … … 863 880 864 881 // single quotes || swap when minimal and there are double quotes in the string 865 } elseif ($options['quotestyle'] === 'single' || ($options['quotestyle'] === 'minimal' && \ mb_strpos($value, '"') !== false)) {882 } elseif ($options['quotestyle'] === 'single' || ($options['quotestyle'] === 'minimal' && \str_contains($value, '"'))) { 866 883 $html .= "='".\str_replace(['&', "'", '<'], ['&', ''', '<'], $value)."'"; 867 884 … … 919 936 * @return mixed The value of the requested property 920 937 */ 921 #[\ReturnTypeWillChange] 922 public function __get(string $var) { 938 public function __get(string $var) : mixed { 923 939 return $this->$var; 924 940 } -
torque/trunk/packages/htmldoc/tokens/text.php
r2817597 r2912478 39 39 * @return void 40 40 */ 41 public function __set(string $name, $value) : void {41 public function __set(string $name, mixed $value) : void { 42 42 if ($name === 'parent' && \get_class($value) === 'hexydec\\html\\tag') { 43 43 $this->parent = $value; … … 118 118 } 119 119 120 protected function getIndex( $children){120 protected function getIndex(array $children) : int|false { 121 121 foreach ($children AS $key => $value) { 122 122 if ($value === $this) { -
torque/trunk/packages/jslite/jslite.php
r2823176 r2912478 4 4 use \hexydec\tokens\tokenise; 5 5 6 /** 7 * @property-read mixed Either the config array, or the length property 8 */ 9 6 10 class jslite { 7 11 8 12 /** 9 * @var array $tokens Regexp components keyed by their corresponding codename for tokenising HTML13 * @var array $tokens Regexp components keyed by their corresponding codename for tokenising Javascript 10 14 */ 11 15 protected static array $tokens = [ … … 23 27 24 28 // keywords number and variables 25 'keyword' => '\\b(?:let|break|case|catch|class|const|continue|debugger|default|delete|do|else|export|extends|finally|for|function|if|import|in|of|instanceof|new|return|super|switch|this|throw|try|typeof|var|void|while|with|yield|null|async|await|true|false|undefined )\\b',29 'keyword' => '\\b(?:let|break|case|catch|class|const|continue|debugger|default|delete|do|else|export|extends|finally|for|function|if|import|in|of|instanceof|new|return|super|switch|this|throw|try|typeof|var|void|while|with|yield|null|async|await|true|false|undefined|static)\\b', 26 30 'variable' => '[\\p{L}\\p{Nl}$_][\\p{L}\\p{Nl}\\p{Mn}\\p{Mc}\\p{Nd}\\p{Pc}$_]*+', 27 31 'number' => '(?:0[bB][01_]++n?|0[oO][0-7_]++n?|0[xX][a-f0-9_]|[0-9][0-9_]*+(?:\\.[0-9_]++)?+(?:e[+-]?[1-9][0-9]*+)?+)', … … 59 63 ] 60 64 ]; 61 protected ?array $expressions = null;65 protected array $expressions = []; 62 66 63 67 public function __construct(array $config = []) { 64 if ( $config) {68 if (!empty($config)) { 65 69 $this->config = \array_replace_recursive($this->config, $config); 66 70 } … … 73 77 * @return mixed The number of children in the object for length, the output config, or null if the parameter doesn't exist 74 78 */ 75 #[\ReturnTypeWillChange] 76 public function __get(string $var) { 79 public function __get(string $var) : mixed { 77 80 if ($var === 'config') { 78 81 return $this->config; … … 91 94 * @return string|false The loaded Javascript, or false on error 92 95 */ 93 public function open(string $url, $context = null, ?string &$error = null) {96 public function open(string $url, $context = null, ?string &$error = null) : string|false { 94 97 95 98 // check resource … … 113 116 * @param string $js A string containing valid Javascript 114 117 * @param ?string &$error A reference to any user error that is generated 115 * @return bool Whether the input HTMLwas parsed118 * @return bool Whether the input Javascript was parsed 116 119 */ 117 120 public function load(string $js, ?string &$error = null) : bool { … … 142 145 // generate expressions 143 146 $expressions = []; 144 while ( ($token = $tokens->next()) !== null) {147 while ($tokens->next() !== null) { 145 148 $obj = new expression(); 146 149 if ($obj->parse($tokens)) { … … 154 157 * Minifies the internal representation of the document 155 158 * 156 * @param array $minify An array indicating which minification operations to perform, this is merged with htmldoc::$config['minify']159 * @param array $minify An array indicating which minification operations to perform, this is merged with self::$config['minify'] 157 160 * @return void 158 161 */ … … 164 167 // minify expressions 165 168 $last = null; 166 $not = ['whitespace', 'comment'];167 169 foreach ($this->expressions AS $item) { 168 170 $item->minify($minify); … … 204 206 * @param string|null $file The file location to save the document to, or null to just return the compiled code 205 207 * @param array $options An array indicating output options 206 * @return string| boolThe compiled Javascript, or false if the file could not be saved207 */ 208 public function save(string $file = null, array $options = []) {208 * @return string|false The compiled Javascript, or false if the file could not be saved 209 */ 210 public function save(string $file = null, array $options = []) : string|false { 209 211 $js = $this->compile($options); 210 212 -
torque/trunk/packages/jslite/tokens/brackets.php
r2817597 r2912478 44 44 if (($token = $tokens->current()) !== null) { 45 45 $bracket = $this->bracket = \mb_substr($token['type'], 4); 46 while ( ($token = $tokens->next()) !== null) {46 while ($tokens->next() !== null) { 47 47 $obj = new expression($bracket); 48 48 if ($obj->parse($tokens)) { … … 60 60 * Minifies the internal representation of the document 61 61 * 62 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']62 * @param array $minify An array indicating which minification operations to perform 63 63 * @return void 64 64 */ … … 82 82 } 83 83 84 // other checks before we remove semi-colon 85 if ($last && $minify['semicolons']) { 86 $key = __NAMESPACE__.'\\keyword'; 87 $bra = __NAMESPACE__.'\\brackets'; 84 // remove last eol if not keyword-bracket or in for loop 85 if ($last !== null && !$this->isKeywordBracket($last) && !$this->isInForLoop($expressions)) { 86 $last->eol = null; 87 } 88 } 88 89 89 // don't remove semi-colon from keyword + brackets with no following commands 90 if ($this->bracket === 'curly') { 91 $sigcomms = []; 92 foreach ($last->commands AS $comm) { 93 if ($comm::significant) { 94 $sigcomms[] = $comm; 90 /** 91 * Checks to see if the last expression is a keyword followed by brackets, with no other commands - semi-colon must not be removed 92 * 93 * @param object $last The last JSlite object that is being checked for semi-colon removal 94 * @return bool Whether the object contains a keyword-bracket expression 95 */ 96 protected function isKeywordBracket(object $last) : bool { 97 $key = __NAMESPACE__.'\\keyword'; 98 $bra = __NAMESPACE__.'\\brackets'; 99 100 // don't remove semi-colon from keyword + brackets with no following commands 101 if ($this->bracket === 'curly') { 102 $sigcomms = []; 103 foreach ($last->commands AS $comm) { 104 if ($comm::significant) { 105 $sigcomms[] = $comm; 106 } 107 } 108 if (\count($sigcomms) === 2 && \get_class($sigcomms[0]) === $key && $sigcomms[0]->content !== 'return' && \get_class($sigcomms[1]) === $bra && $sigcomms[1]->bracket === 'bracket') { 109 return true; 110 } 111 } 112 return false; 113 } 114 115 /** 116 * Analyses the cirrent expression set to see if it is contained within a for loop with a specific pattern of semi-colons, where the final one should not be removed 117 * 118 * @param array $expressions An array containing the current expressesion set 119 * @return bool WHether the current expresiion set is wrapped in a for loop 120 */ 121 protected function isInForLoop(array $expressions) : bool { 122 $key = __NAMESPACE__.'\\keyword'; 123 124 // must not remove eol if for loop 125 $prev = null; 126 foreach ($this->root->commands AS $item) { 127 if ($item === $this) { 128 if (\is_object($prev) && \get_class($prev) === $key && $prev->content === 'for') { 129 130 // count expressions where the EOL is ; (Could be comma) 131 $count = 0; 132 foreach ($expressions AS $expr) { 133 if ($expr->eol === ';') { 134 $count++; 135 } 136 } 137 if ($count !== 3) { 138 return true; 95 139 } 96 140 } 97 if (count($sigcomms) === 2 && \get_class($sigcomms[0]) === $key && $sigcomms[0]->content !== 'return' && \get_class($sigcomms[1]) === $bra && $sigcomms[1]->bracket === 'bracket') { 98 return; 99 } 100 } 101 102 // must not remove eol if for loop 103 $prev = null; 104 foreach ($this->root->commands AS $i => $item) { 105 if ($item === $this) { 106 if ($prev && \get_class($prev) === $key && $prev->content === 'for') { 107 108 // count expressions where the EOL is ; (Could be comma) 109 $count = 0; 110 foreach ($expressions AS $expr) { 111 if ($expr->eol === ';') { 112 $count++; 113 } 114 } 115 if ($count !== 3) { 116 $last = null; 117 } 118 } 119 break; 120 } elseif ($item::significant) { 121 $prev = $item; 122 } 123 } 124 125 // remove last eol 126 if ($last) { 127 $last->eol = null; 141 break; 142 } elseif ($item::significant) { 143 $prev = $item; 128 144 } 129 145 } 146 return false; 130 147 } 131 148 … … 133 150 * Compile as Javascript 134 151 * 135 * @return string The compiled HTML152 * @return string The compiled Javascript 136 153 */ 137 154 public function compile() : string { -
torque/trunk/packages/jslite/tokens/expression.php
r2817597 r2912478 49 49 do { 50 50 switch ($token['type']) { 51 52 // comments 51 53 case 'commentsingle': 52 54 case 'commentmulti': 53 $obj = new comment(); 54 if ($obj->parse($tokens)) { 55 $commands[] = $obj; 56 } 57 break; 55 $commands = $this->getCommand('comment', $tokens, $commands); 56 break; 57 58 // operators 58 59 case 'operator': 59 60 $obj = new operator(); … … 65 66 } 66 67 break; 68 69 // variables, numbers, and increment 70 case 'variable': 71 case 'number': 67 72 case 'increment': 68 $obj = new increment(); 69 if ($obj->parse($tokens)) { 70 $commands[] = $obj; 71 } 72 break; 73 $commands = $this->getCommand($token['type'], $tokens, $commands); 74 break; 75 76 // keywords 73 77 case 'keyword': 74 if ($this->isKeyword($last, $token, $tokens)) { 75 $obj = new keyword(); 76 if ($obj->parse($tokens)) { 77 $commands[] = $obj; 78 } 79 break; 80 } 81 case 'variable': 82 $obj = new variable(); 83 if ($obj->parse($tokens)) { 84 $commands[] = $obj; 85 } 86 break; 87 case 'number': 88 $obj = new number(); 89 if ($obj->parse($tokens)) { 90 $commands[] = $obj; 91 } 92 break; 78 if ($this->isKeyword($last, $tokens)) { 79 $commands = $this->getCommand('keyword', $tokens, $commands); 80 break; // if not keyword then variable 81 } 82 83 // quoted strings 93 84 case 'doublequotes': 94 85 case 'singlequotes': 95 86 case 'templateliterals': 96 $obj = new jsstring(); 97 if ($obj->parse($tokens)) { 98 $commands[] = $obj; 99 } 100 break; 87 $commands = $this->getCommand('jsstring', $tokens, $commands); 88 break; 89 90 // regular expressions 101 91 case 'regexp': 102 92 103 93 // regexp is extremely awkward to capture, and because we only look ahead in the regexp, sometimes it can get it wrong 104 if (! $last|| $this->isRegexpAllowed($last, $beforelast)) {94 if (!\is_object($last) || $this->isRegexpAllowed($last, $beforelast)) { 105 95 106 96 // create regexp object 107 $obj = new regexp(); 108 if ($obj->parse($tokens)) { 109 $commands[] = $obj; 110 } 97 $commands = $this->getCommand('regexp', $tokens, $commands); 111 98 112 99 // if we have got it wrong then the first character will be a divide … … 118 105 } 119 106 break; 107 108 // whitespace 120 109 case 'whitespace': 121 110 $end = false; 122 111 123 112 // catch un-terminated line endings 124 if ( $last && \mb_strpos($token['value'], "\n") !== false) {113 if (\is_object($last) && \str_contains($token['value'], "\n")) { 125 114 $end = $this->isEol($tokens, $last, $beforelast, $assignment); 126 115 } 127 116 128 117 // create whitespace object 129 $obj = new whitespace($this); 130 if ($obj->parse($tokens)) { 131 $commands[] = $obj; 132 } 118 $commands = $this->getCommand('whitespace', $tokens, $commands); 133 119 if ($end) { 134 120 break 2; … … 136 122 break; 137 123 } 124 125 // brackets 138 126 case 'openbracket': 139 127 case 'opensquare': 140 128 case 'opencurly': 141 $obj = new brackets($this); 142 if ($obj->parse($tokens)) { 143 $commands[] = $obj; 144 } 145 break; 129 $commands = $this->getCommand('brackets', $tokens, $commands); 130 break; 131 132 // end of lines 146 133 case 'eol': 147 134 case 'comma': 148 135 $this->eol = $token['value']; 136 137 // close brackets 149 138 case 'closebracket': 150 139 case 'closesquare': … … 165 154 166 155 /** 156 * Create a token object and parse some tokens 157 * 158 * @param string $obj The name of the token object to create 159 * @param tokenise $tokens A tokenise object conaining th etokens to ve parsed 160 * @param array $commands The current array of commands 161 * @return array The input $commands, with the command object pushed on if anything was parsed 162 */ 163 protected function getCommand(string $obj, tokenise $tokens, array $commands) : array { 164 $cls = __NAMESPACE__.'\\'.$obj; 165 $obj = new $cls($this); 166 if ($obj->parse($tokens)) { 167 $commands[] = $obj; 168 } 169 return $commands; 170 } 171 172 /** 167 173 * Works out whether a keyword is legal in the current context 168 174 */ 169 protected function isKeyword( $prev, array $current, tokenise $tokens) {175 protected function isKeyword(?object $prev, tokenise $tokens) { 170 176 if (($next = $this->getNextSignificantToken($tokens)) !== null) { 171 177 172 178 // property name 173 if (\mb_strpos($next['value'], ':') === 0 || $next['value'] === '.') { 174 return false; 175 176 // var undefined 177 // } elseif ($current['value'] === 'undefined') { 178 // 179 // // is a variable definition 180 // if ($prev && \in_array($prev->content, ['const', 'let', 'var'])) { 181 // return false; 182 // 183 // // followed by an assignment, comma, or EOL 184 // } elseif (!$prev && \in_array($next['value'], ['=', ',', ';'])) { 185 // return false; 186 // } 187 } 188 } elseif ($prev && \get_class($prev) === __NAMESPACE__.'\\operator' && $prev->content === '.') { 179 return \mb_strpos($next['value'], ':') !== 0 && $next['value'] !== '.'; 180 181 // previous object is . 182 } elseif (\is_object($prev) && \get_class($prev) === __NAMESPACE__.'\\operator' && $prev->content === '.') { 189 183 return false; 190 184 } … … 194 188 /** 195 189 * Works out whether a regular expression is legal in the current context 196 */ 197 protected function isRegexpAllowed($prev, $beforeprev = null) : bool { 190 * 191 * @param object $prev The previous object 192 * @param ?object $beforeprev The bject before the previous object 193 * @return bool Whether RegExp is allowed in the current position 194 */ 195 protected function isRegexpAllowed(object $prev, ?object $beforeprev = null) : bool { 198 196 $key = __NAMESPACE__.'\\keyword'; 199 197 $bra = __NAMESPACE__.'\\brackets'; … … 216 214 * 217 215 * @param tokenise $tokens A tokenise object to get the next tokens from 218 * @param mixed$prev The previous command object219 * @param mixed$beforeprev The command object before the previous command object216 * @param object $prev The previous command object 217 * @param object $beforeprev The command object before the previous command object 220 218 * @return bool Whether the expression should end at the previous command 221 219 */ 222 protected function isEol(tokenise $tokens, $prev = null,$beforeprev = null, bool $assignment = false) : bool {220 protected function isEol(tokenise $tokens, object $prev, ?object $beforeprev = null, bool $assignment = false) : bool { 223 221 $prevtype = \get_class($prev); 224 222 $beforeprevtype = $beforeprev ? \get_class($beforeprev) : null; … … 236 234 // special case for keyword followed by bracket 237 235 } elseif ($prevtype === $bra && $beforeprevtype === $key && !\in_array($beforeprev->content, $keywords, true)) { 238 return false;239 236 240 237 // if prev is curly then expression will have already ended … … 244 241 // get next token 245 242 } elseif (($next = $this->getNextSignificantToken($tokens)) === null) { 246 return false;247 243 248 244 // if the previous expression is an operator, like + or =, then the expression must end if next not an operator 249 } elseif ($beforeprevtype === $op && !\in_array($next['type'], ['operator', 'openbracket', 'eol'])) {245 } elseif ($beforeprevtype === $op && $prevtype !== $op && !\in_array($next['type'], ['operator', 'openbracket', 'eol'])) { 250 246 return true; 251 247 … … 264 260 // see if the statement needs to be terminated 265 261 } else { 266 $end = [ // previous type => [next types] 267 'brackets' => ['variable', 'number', 'string', 'increment'], 268 'variable' => ['variable', 'string', 'number', 'regexp', 'opencurly', 'increment'], 269 'number' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 270 'string' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 271 'regexp' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 272 'increment' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'] 273 ]; 274 foreach ($end AS $key => $item) { 275 if ('hexydec\\jslite\\'.$key === $prevtype && \in_array($next['type'], $item, true)) { 276 return true; 277 } 262 return $this->matchesEolPattern($prevtype, $next['type']); 263 } 264 return false; 265 } 266 267 protected function matchesEolPattern(string $prevtype, string $nexttype) : bool { 268 $end = [ // previous type => [next types] 269 'brackets' => ['variable', 'number', 'string', 'increment'], 270 'variable' => ['variable', 'string', 'number', 'regexp', 'opencurly', 'increment'], 271 'number' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 272 'string' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 273 'regexp' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'], 274 'increment' => ['variable', 'number', 'string', 'regexp', 'openbracket', 'opensquare', 'opencurly', 'increment'] 275 ]; 276 foreach ($end AS $key => $item) { 277 if ('hexydec\\jslite\\'.$key === $prevtype && \in_array($nexttype, $item, true)) { 278 return true; 278 279 } 279 280 } … … 309 310 * Minifies the internal representation of the document 310 311 * 311 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']312 * @param array $minify An array indicating which minification operations to perform 312 313 * @return void 313 314 */ … … 323 324 * Compile as Javascript 324 325 * 325 * @return string The compiled HTML326 * @return string The compiled Javascript 326 327 */ 327 328 public function compile() : string { -
torque/trunk/packages/jslite/tokens/keyword.php
r2817597 r2912478 33 33 * Minifies the internal representation of the document 34 34 * 35 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']35 * @param array $minify An array indicating which minification operations to perform 36 36 * @return void 37 37 */ … … 59 59 * Compile as Javascript 60 60 * 61 * @return string The compiled HTML61 * @return string The compiled Javascript 62 62 */ 63 63 public function compile() : string { -
torque/trunk/packages/jslite/tokens/number.php
r2817597 r2912478 33 33 * Minifies the internal representation of the document 34 34 * 35 * @param array $minify An array indicating which minification operations to perform, this is merged with htmldoc::$config['minify']35 * @param array $minify An array indicating which minification operations to perform, this is merged with self::$config['minify'] 36 36 * @return void 37 37 */ … … 45 45 * Compile as Javascript 46 46 * 47 * @return string The compiled HTML47 * @return string The compiled Javascript 48 48 */ 49 49 public function compile() : string { -
torque/trunk/packages/jslite/tokens/regexp.php
r2817597 r2912478 33 33 * Minifies the internal representation of the document 34 34 * 35 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']35 * @param array $minify An array indicating which minification operations to perform 36 36 * @return void 37 37 */ … … 47 47 * Compile as Javascript 48 48 * 49 * @return string The compiled HTML49 * @return string The compiled Javascript 50 50 */ 51 51 public function compile() : string { -
torque/trunk/packages/jslite/tokens/string.php
r2817597 r2912478 48 48 * Minifies the internal representation of the document 49 49 * 50 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']50 * @param array $minify An array indicating which minification operations to perform 51 51 * @return void 52 52 */ … … 60 60 * Compile as Javascript 61 61 * 62 * @return string The compiled HTML62 * @return string The compiled Javascript 63 63 */ 64 64 public function compile() : string { -
torque/trunk/packages/jslite/tokens/whitespace.php
r2817597 r2912478 47 47 * Minifies the internal representation of the document 48 48 * 49 * @param array $minify An array indicating which minification operations to perform , this is merged with htmldoc::$config['minify']49 * @param array $minify An array indicating which minification operations to perform 50 50 * @return void 51 51 */ … … 55 55 $eol = $this->parent->eol; 56 56 $prev = null; 57 $beforeprev = null;58 57 $count = \count($commands); 59 $not = ['whitespace', 'comment'];60 58 61 59 // specify class names … … 73 71 74 72 // first item 75 if (!$i || !$prev) {73 if (!$i || $prev === null) { 76 74 $this->content = ''; 77 75 … … 91 89 92 90 // remove whitespace if last in the parent expression 93 if ( !$next) {91 if ($next === null) { 94 92 95 93 // terminate any statements that are not terminated 96 if (!$eol && \ mb_strpos($this->content, "\n") !== false) {94 if (!$eol && \str_contains($this->content, "\n")) { 97 95 98 96 // always terminate return … … 108 106 109 107 // handle operators next to an increment 110 } elseif ($prevtype === $op && $nexttype === $inc && \ mb_strpos($next->compile(), $prev->compile()) !== false) {108 } elseif ($prevtype === $op && $nexttype === $inc && \str_contains($next->compile(), $prev->compile())) { 111 109 $this->content = ' '; 112 110 … … 136 134 // record the previous significant objects 137 135 } elseif ($item::significant) { 138 $beforeprev = $prev;139 136 $prev = $item; 140 137 … … 159 156 * Compile as Javascript 160 157 * 161 * @param array $options An array indicating output options 162 * @return string The compiled HTML 158 * @return string The compiled Javascript 163 159 */ 164 public function compile( array $options = []) : string {160 public function compile() : string { 165 161 return $this->content; 166 162 } -
torque/trunk/readme.txt
r2823178 r2912478 2 2 Contributors: hexydec 3 3 Tags: minify,minification,performance,security,optimization 4 Requires at least: 5.95 Tested up to: 6. 16 Requires PHP: 7.47 Stable tag: 0.7. 14 Requires at least: 5 Tested up to: 6.2 6 Requires PHP: 8.0 7 Stable tag: 0.7.2 8 8 License: GPLv3 9 9 License URI: https://www.gnu.org/licenses/gpl-3.0.en.html … … 46 46 * Preload combined stylesheets 47 47 * Administration panel to control all features, including all minification optimisations 48 * Print minification stats in the console 48 49 49 50 See the [Torque Github homepage](https://github.com/hexydec/torque) for more information. … … 128 129 == Changelog == 129 130 131 = Version 0.7.2 = 132 133 * Fixed issue when combining CSS where any inline CSS attached to an external stylesheet was not combined, sometimes causing ordering issues 134 * Updated packages to latest versions 135 * Fixed bug where 304 headers were not set the Wordpress way, which caused Wordpress to overwrite it 136 * Fixed incorrectly loaded rebuild command 137 * Fixed minor PHP 8.1 data handling issues 138 130 139 = Version 0.7.1 = 131 140 -
torque/trunk/torque.php
r2823178 r2912478 10 10 Plugin URI: https://github.com/hexydec/torque 11 11 Description: Make your Wordpress website noticably faster by optimising how it is delivered. Analyse your website's performance and security, minify and combine your assets, and configure an array of performance and security settings quickly and easily with this comprehensive plugin. Achieves the best compression of any minification plugin. 12 Version: 0.7. 113 Requires PHP: 7.412 Version: 0.7.2 13 Requires PHP: 8.0 14 14 Author: Hexydec 15 15 Author URI: https://github.com/hexydec/ … … 57 57 // add rebuild command 58 58 if (\class_exists('WP_CLI')) { 59 \WP_CLI::add_command('torque rebuild', '\\hexydec\\torque\\packages::rebuildAssets', [ 59 \WP_CLI::add_command('torque rebuild', function () { 60 return \hexydec\torque\assets::rebuildAssets(); 61 }, [ 60 62 'shortdesc' => 'Rebuild the configured combined CSS and Javascript files' 61 63 ]);
Note: See TracChangeset
for help on using the changeset viewer.