coren has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/282525

Change subject: Linting and slight tweak to parser
......................................................................

Linting and slight tweak to parser

- add a tweak to the parser (keep the value tokens in a declaration
  separate in the parsed tree to ease matching at render time
- add error checking to encoding/decoding the templatestyles property
- pick some lint suggested by Brion and Bryan

Change-Id: If60b91e119102c0f0f559fe7e5a4c421c94b7ff4
---
M CSSParser.php
M CSSRenderer.php
M TemplateStyles.hooks.php
M composer.json
M i18n/en.json
M i18n/qqq.json
6 files changed, 72 insertions(+), 37 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/TemplateStyles 
refs/changes/25/282525/1

diff --git a/CSSParser.php b/CSSParser.php
index a43d802..5e0792a 100644
--- a/CSSParser.php
+++ b/CSSParser.php
@@ -27,31 +27,53 @@
        function __construct( $css ) {
                preg_match_all( '/(
                          [ \n\t]+
+                               (?# Sequences of whitespace )
                        | \/\* (?: [^*]+ | \*[^\/] )* \*\/ [ \n\t]*
+                               (?# Comments and any trailing whitespace )
                        | " (?: [^"\\\\\n]+ | \\\\\. )* ["\n]
+                               (?# Double-quoted string literals (to newline 
when unclosed )
                        | \' (?: [^\'\\\\\n]+ | \\\\\. )* [\'\n]
+                               (#? Single-quoted string literals (to newline 
when unclosed )
                        | [+-]? (?: [0-9]* \. )? [0-9]+ (?: [_a-z][_a-z0-9-]* | 
% )?
-                       | url [ \n\t]* \(
+                               (#? Numerical literals - including optional 
trailing units or percent sign )
                        | @? -? (?: [_a-z] | \\\\[0-9a-f]{1,6} [ \n\t]? )
-                               (?: [_a-z0-9-]+ | \\\\[0-9a-f]{1,6} [ \n\t]? | 
[^\0-\177] )*
+                               (?: [_a-z0-9-]+ | \\\\[0-9a-f]{1,6} [ \n\t]? | 
[^\0-\177] )* (?: [ \n\t]* \( )?
+                               (#? Identifiers - including leading `@` for 
at-rule blocks )
+                               (#? Trailing open captures are captured to 
match functional values )
                        | \# (?: [_a-z0-9-]+ | \\\\[0-9a-f]{1,6} [ \n\t]? | 
[^\0-\177] )*
+                               (#? So-called hatch literals )
                        | u\+ [0-9a-f]{1,6} (?: - [0-9a-f]{1,6} )?
+                               (#? Unicode range literals )
                        | u\+ [0-9a-f?]{1,6}
-                       | <!--
-                       | -->
-                       | .)/xis', $css, $match );
+                               (#? Unicode mask literals )
+                       | .)
+                               (#? Any unmatched token is reduced to single 
characters )
+                       /xis', $css, $match );
 
                $space = false;
                foreach ( $match[0] as $t ) {
-                       if ( preg_match( '/^(?:[ \n\t]|\/\*|<!--|-->)/', $t ) ) 
{
+                       if ( preg_match( '/^(?:[ \n\t]|\/\*)/', $t ) ) {
+
+                               // Fold any sequence of whitespace to a single 
space token
+
                                if ( !$space ) {
                                        $space = true;
                                        $this->tokens[] = ' ';
                                        continue;
                                }
+
                        } else {
+
+                               // decode any hexadecimal escape character into 
their corresponding UTF-8
+                               // sequence - our output is UTF-8 so the 
escaping is unnecessary and this
+                               // prevents trying to obfuscate ASCII in 
identifiers to prevent matches.
+
+                               $t = 
preg_replace_callback('/\\\\([0-9a-f]{1,6})[ \n\t]?/', function( $match ) {
+                                               return html_entity_decode( 
'&#'.$match[1].';', ENT_NOQUOTES, 'UTF-8' );
+                                       }, $t);
                                $space = false;
                                $this->tokens[] = $t;
+
                        }
                }
                $this->index = 0;
@@ -67,7 +89,7 @@
                if ( $num > 0 ) {
                        if ( $this->index+$num >= count( $this->tokens ) )
                                $num = count( $this->tokens ) - $this->index;
-                       $text = implode( array_slice( $this->tokens, 
$this->index, $num ) );
+                       $text = array_slice( $this->tokens, $this->index, $num 
);
                        $this->index += $num;
                        return $text;
                }
@@ -99,7 +121,7 @@
         */
        private function parseDecl() {
                $this->consumeWS();
-               $name = $this->consume();
+               $name = $this->consume()[0];
                $this->consumeWS();
                if ( $this->peek( 0 )!=':' ) {
                        $this->consumeTo( [';', '}', null] );
@@ -113,7 +135,7 @@
                $this->consumeWS();
                $value = $this->consumeTo( [';', '}', null] );
                if ( $this->peek( 0 ) == ';' ) {
-                       $value .= $this->consume();
+                       $this->consume();
                        $this->consumeWS();
                }
                return [ $name => $value ];
@@ -164,7 +186,7 @@
                                $this->consumeWS();
                                $text = '';
                        } else
-                               $text .= $this->consume();
+                               $text .= $this->consume()[0];
                }
                $selectors[] = $text;
                if ( $this->peek( 0 ) == '{' ) {
@@ -205,7 +227,7 @@
                                $this->consumeWS();
                                $text = '';
                                while ( !in_array( $this->peek( 0 ), ['{', ';', 
null] ) )
-                                       $text .= $this->consume();
+                                       $text .= $this->consume()[0];
                                if ( $this->peek( 0 ) == '{' ) {
                                        $this->consume();
                                        $r = $this->rules( [ '}', null ] );
@@ -218,7 +240,7 @@
                                $at = $this->consume();
                                $text = '';
                                while ( !in_array( $this->peek( 0 ), ['{', ';', 
null] ) )
-                                       $text .= $this->consume();
+                                       $text .= $this->consume()[0];
                                if ( $this->peek( 0 ) == '{' ) {
                                        $this->consume();
                                        $decl = $this->parseDecls();
diff --git a/CSSRenderer.php b/CSSRenderer.php
index f0e95e4..ce54f94 100644
--- a/CSSRenderer.php
+++ b/CSSRenderer.php
@@ -59,7 +59,7 @@
                        foreach ( $rules as $rule ) {
                                $css .= implode( ',', $rule['selectors'] ) . 
"{";
                                foreach ( $rule['decls'] as $key => $value ) {
-                                       $css .= "$key:$value";
+                                       $css .= "$key:" . implode( '', $value ) 
. ';';
                                }
                                $css .= "} ";
                        }
diff --git a/TemplateStyles.hooks.php b/TemplateStyles.hooks.php
index 7a4524d..57b2b3d 100644
--- a/TemplateStyles.hooks.php
+++ b/TemplateStyles.hooks.php
@@ -11,8 +11,19 @@
         * Register parser hooks
         */
        public static function onParserFirstCallInit( &$parser ) {
-               $parser->setHook( 'templatestyles', array( 
'TemplateStylesHooks', 'render' ) );
+               $parser->setHook( 'templatestyles', 
'TemplateStylesHooks::render' );
                return true;
+       }
+
+       private static function decodeFromBlob( $blob ) {
+               $tree = gzdecode( $blob );
+               if ( $tree )
+                       $tree = unserialize( $tree );
+               return $tree;
+       }
+
+       private static function encodeToBlob( $tree ) {
+               return gzencode( serialize( $tree ) );
        }
 
        public static function onOutputPageParserOutput( &$out, $parseroutput ) 
{
@@ -24,9 +35,6 @@
 
                $renderer = new CSSRenderer();
                $pages = [];
-
-               if ( $out->canUseWikiPage() )
-                       $pages[$out->getWikiPage()->getID()] = 'self';
 
                foreach ( $namespaces as $ns )
                        if ( array_key_exists( $ns, 
$parseroutput->getTemplates() ) )
@@ -43,16 +51,18 @@
                                [ 'ORDER BY', 'pp_page' ]
                        );
                        foreach ( $res as $row ) {
-                               $css = unserialize( gzdecode( $row->pp_value ) 
);
-                               $renderer->add( $css );
+                               $css = decodeFromBlob( $row->pp_value );
+                               if ( $css )
+                                       $renderer->add( $css );
                        }
 
                }
 
                $selfcss = $out->getProperty( 'templatestyles' );
                if ( $selfcss ) {
-                       $selfcss = unserialize( gzdecode( $selfcss ) );
-                       $renderer->add( $selfcss );
+                       $selfcss = decodeFromBlob( unserialize( gzdecode( 
$selfcss ) );
+                       if ( $selfcss )
+                               $renderer->add( $selfcss );
                }
 
                $css = $renderer->render();
@@ -78,8 +88,11 @@
                $css = new CSSParser( $input );
 
                if ( $css )
-                       $parser->getOutput()->setProperty( 'templatestyles', 
gzencode( serialize( $css->rules() ) ) );
+                       $parser->getOutput()->setProperty( 'templatestyles', 
encodeToBlob( $css->rules() ) );
 
+               // TODO: The UX would benefit from the CSS being run through the
+               // hook for syntax highlighting rather that simply being 
presented
+               // as a preformatted block.
                $html =
                        Html::openElement( 'div', [ 'class' => 
'mw-templatestyles-doc' ] )
                        . Html::rawElement(
diff --git a/composer.json b/composer.json
index d9fc29b..7b145a3 100644
--- a/composer.json
+++ b/composer.json
@@ -2,7 +2,7 @@
     "license": "LGPL-2.1+",
        "require-dev": {
                "jakub-onderka/php-parallel-lint": "0.9",
-               "mediawiki/mediawiki-codesniffer": "0.4.0"
+               "mediawiki/mediawiki-codesniffer": "0.5.0"
        },
        "scripts": {
                "test": [
diff --git a/i18n/en.json b/i18n/en.json
index 640383e..59eb4e0 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -1,10 +1,10 @@
 {
-    "@metadata": {
-        "authors": [
-            "Marc A. Pelletier"
-        ]
-    },
-    "templateStyles": "TemplateStyles",
-    "templateStyles-desc": "Implement per-template style sheets",
+       "@metadata": {
+               "authors": [
+                       "Marc A. Pelletier"
+               ]
+       },
+       "templateStyles": "TemplateStyles",
+       "templateStyles-desc": "Implement per-template style sheets",
        "templatestyles-doc-header": "Template-specific style sheet:"
 }
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 707c1dd..a0d33a4 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -1,10 +1,10 @@
 {
-    "@metadata": {
-        "authors": [
-            "Marc A. Pelletier"
-        ]
-    },
-    "templateStyles": "The name of the extension",
-    "templateStyles-desc": 
"{{desc|name=TemplateStyles|url=https://www.mediawiki.org/wiki/Extension:TemplateStyles}}";,
+       "@metadata": {
+               "authors": [
+                       "Marc A. Pelletier"
+               ]
+       },
+       "templateStyles": "The name of the extension",
+       "templateStyles-desc": 
"{{desc|name=TemplateStyles|url=https://www.mediawiki.org/wiki/Extension:TemplateStyles}}";,
        "templatestyles-doc-header": "Used as caption for the display of the 
style sheet of the current template."
 }

-- 
To view, visit https://gerrit.wikimedia.org/r/282525
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: If60b91e119102c0f0f559fe7e5a4c421c94b7ff4
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/TemplateStyles
Gerrit-Branch: master
Gerrit-Owner: coren <m...@uberbox.org>

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to