diff --git a/ph-css/src/main/java/com/helger/css/handler/CSSNodeToDomainObject.java b/ph-css/src/main/java/com/helger/css/handler/CSSNodeToDomainObject.java
index d2d64485..4bbb33f5 100644
--- a/ph-css/src/main/java/com/helger/css/handler/CSSNodeToDomainObject.java
+++ b/ph-css/src/main/java/com/helger/css/handler/CSSNodeToDomainObject.java
@@ -644,6 +644,12 @@ private CSSDeclaration _createDeclaration (@Nonnull final CSSNode aNode)
}
final String sProperty = aNode.jjtGetChild (0).getText ();
+ if (sProperty == null)
+ {
+ // Syntax error with deprecated property name (see #84)
+ return null;
+ }
+
final CSSExpression aExpression = _createExpression (aNode.jjtGetChild (1));
boolean bImportant = false;
if (nChildCount == 3)
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/CSSParseError.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/CSSParseError.java
index 69e167fd..5f5ab404 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/CSSParseError.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/CSSParseError.java
@@ -149,6 +149,12 @@ public static CSSParseError createUnexpectedRule (@Nonnull final Token aCurrentT
return new CSSParseError (LoggingCSSParseErrorHandler.createLoggingStringUnexpectedRule (aCurrentToken, sRule, sMsg));
}
+ @Nonnull
+ public static CSSParseError createDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken)
+ {
+ return new CSSParseError (LoggingCSSParseErrorHandler.createLoggingStringDeprecatedProperty (aPrefixToken, aIdentifierToken));
+ }
+
@Nonnull
public static CSSParseError createBrowserCompliantSkip (@Nullable final ParseException ex,
@Nonnull final Token aFromToken,
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/CollectingCSSParseErrorHandler.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/CollectingCSSParseErrorHandler.java
index 61a14877..11250c23 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/CollectingCSSParseErrorHandler.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/CollectingCSSParseErrorHandler.java
@@ -62,20 +62,25 @@ public void onCSSUnexpectedRule (@Nonnull final Token aCurrentToken,
@Nonnull @Nonempty final String sRule,
@Nonnull @Nonempty final String sMsg) throws ParseException
{
- m_aRWLock.writeLockedBoolean ( () -> m_aErrors.add (CSSParseError.createUnexpectedRule (aCurrentToken, sRule, sMsg)));
+ m_aRWLock.writeLocked ( () -> m_aErrors.add (CSSParseError.createUnexpectedRule (aCurrentToken, sRule, sMsg)));
+ }
+
+ public void onCSSDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken)
+ {
+ m_aRWLock.writeLocked ( () -> m_aErrors.add (CSSParseError.createDeprecatedProperty (aPrefixToken, aIdentifierToken)));
}
public void onCSSBrowserCompliantSkip (@Nullable final ParseException ex,
@Nonnull final Token aFromToken,
@Nonnull final Token aToToken) throws ParseException
{
- m_aRWLock.writeLockedBoolean ( () -> m_aErrors.add (CSSParseError.createBrowserCompliantSkip (ex, aFromToken, aToToken)));
+ m_aRWLock.writeLocked ( () -> m_aErrors.add (CSSParseError.createBrowserCompliantSkip (ex, aFromToken, aToToken)));
}
@Override
public void onIllegalCharacter (final char cIllegalChar)
{
- m_aRWLock.writeLockedBoolean ( () -> m_aErrors.add (CSSParseError.createIllegalCharacter (cIllegalChar)));
+ m_aRWLock.writeLocked ( () -> m_aErrors.add (CSSParseError.createIllegalCharacter (cIllegalChar)));
}
/**
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/DoNothingCSSParseErrorHandler.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/DoNothingCSSParseErrorHandler.java
index fe192143..519a2222 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/DoNothingCSSParseErrorHandler.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/DoNothingCSSParseErrorHandler.java
@@ -35,21 +35,24 @@ public class DoNothingCSSParseErrorHandler implements ICSSParseErrorHandler
public DoNothingCSSParseErrorHandler ()
{}
- public void onCSSParseError (@Nonnull final ParseException aParseEx, @Nullable final Token aLastSkippedToken) throws ParseException
+ public void onCSSParseError (@Nonnull final ParseException aParseEx, @Nullable final Token aLastSkippedToken)
{
/* really do nothing :) */
}
public void onCSSUnexpectedRule (@Nonnull final Token aCurrentToken,
@Nonnull @Nonempty final String sRule,
- @Nonnull @Nonempty final String sMsg) throws ParseException
+ @Nonnull @Nonempty final String sMsg)
{
/* really do nothing :) */
}
- public void onCSSBrowserCompliantSkip (@Nullable final ParseException ex,
- @Nonnull final Token aFromToken,
- @Nonnull final Token aToToken) throws ParseException
+ public void onCSSDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken)
+ {
+ /* really do nothing :) */
+ }
+
+ public void onCSSBrowserCompliantSkip (@Nullable final ParseException ex, @Nonnull final Token aFromToken, @Nonnull final Token aToToken)
{
/* really do nothing :) */
}
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/ICSSParseErrorHandler.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/ICSSParseErrorHandler.java
index 496088e9..ce69e919 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/ICSSParseErrorHandler.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/ICSSParseErrorHandler.java
@@ -64,6 +64,19 @@ void onCSSUnexpectedRule (@Nonnull Token aCurrentToken,
@Nonnull @Nonempty String sRule,
@Nonnull @Nonempty String sMsg) throws ParseException;
+ /**
+ * To be called, if a deprecated old IE 6/7 property is found.
+ *
+ * @param aPrefixToken
+ * The prefix token found (like '$' or '*'). Never null
.
+ * @param aIdentifierToken
+ * The identifier token found. Never null
.
+ * @throws ParseException
+ * In case the error is fatal and should be propagated.
+ * @since 6.4.5
+ */
+ void onCSSDeprecatedProperty (@Nonnull Token aPrefixToken, @Nonnull Token aIdentifierToken) throws ParseException;
+
/**
* This method is only called in browser compliant mode if a certain part of
* the CSS is skipped.
@@ -75,7 +88,7 @@ void onCSSUnexpectedRule (@Nonnull Token aCurrentToken,
* Original token that caused the error and was skipped (inclusive).
* Never null
.
* @param aToToken
- * The end token until which was skipped(exclusive). Never
+ * The end token until which was skipped (exclusive). Never
* null
.
* @throws ParseException
* In case the error is fatal and should be propagated.
@@ -124,6 +137,12 @@ public void onCSSUnexpectedRule (@Nonnull final Token aCurrentToken,
aOther.onCSSUnexpectedRule (aCurrentToken, sRule, sMsg);
}
+ public void onCSSDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken) throws ParseException
+ {
+ aThis.onCSSDeprecatedProperty (aPrefixToken, aIdentifierToken);
+ aOther.onCSSDeprecatedProperty (aPrefixToken, aIdentifierToken);
+ }
+
public void onCSSBrowserCompliantSkip (@Nullable final ParseException ex,
@Nonnull final Token aFromToken,
@Nonnull final Token aToToken) throws ParseException
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/LoggingCSSParseErrorHandler.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/LoggingCSSParseErrorHandler.java
index cbdd491b..c3f2d015 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/LoggingCSSParseErrorHandler.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/LoggingCSSParseErrorHandler.java
@@ -150,6 +150,38 @@ public void onCSSUnexpectedRule (@Nonnull final Token aCurrentToken,
LOGGER.warn (createLoggingStringUnexpectedRule (aCurrentToken, sRule, sMsg));
}
+ /**
+ * Create a common string to be used for deprecated properties. To be called,
+ * if a deprecated old IE 6/7 property is found.
+ *
+ * @param aPrefixToken
+ * The prefix token found (like '$' or '*'). Never null
.
+ * @param aIdentifierToken
+ * The identifier token found. Never null
.
+ * @throws ParseException
+ * In case the error is fatal and should be propagated.
+ * @return The concatenated string with source location, etc. May neither be
+ * null
nor empty.
+ */
+ @Nonnull
+ @Nonempty
+ public static String createLoggingStringDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken)
+ {
+ return "[" +
+ aPrefixToken.beginLine +
+ ":" +
+ aPrefixToken.beginColumn +
+ "] Deprecated property name '" +
+ aPrefixToken.image +
+ aIdentifierToken.image +
+ "'";
+ }
+
+ public void onCSSDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken)
+ {
+ LOGGER.warn (createLoggingStringDeprecatedProperty (aPrefixToken, aIdentifierToken));
+ }
+
@Nonnull
@Nonempty
public static String createLoggingStringBrowserCompliantSkip (@Nullable final ParseException ex,
diff --git a/ph-css/src/main/java/com/helger/css/reader/errorhandler/ThrowingCSSParseErrorHandler.java b/ph-css/src/main/java/com/helger/css/reader/errorhandler/ThrowingCSSParseErrorHandler.java
index 5fee6db4..9e49bbd6 100644
--- a/ph-css/src/main/java/com/helger/css/reader/errorhandler/ThrowingCSSParseErrorHandler.java
+++ b/ph-css/src/main/java/com/helger/css/reader/errorhandler/ThrowingCSSParseErrorHandler.java
@@ -51,6 +51,11 @@ public void onCSSUnexpectedRule (@Nonnull final Token aCurrentToken,
throw new ParseException (LoggingCSSParseErrorHandler.createLoggingStringUnexpectedRule (aCurrentToken, sRule, sMsg));
}
+ public void onCSSDeprecatedProperty (@Nonnull final Token aPrefixToken, @Nonnull final Token aIdentifierToken) throws ParseException
+ {
+ throw new ParseException (LoggingCSSParseErrorHandler.createLoggingStringDeprecatedProperty (aPrefixToken, aIdentifierToken));
+ }
+
public void onCSSBrowserCompliantSkip (@Nullable final ParseException ex,
@Nonnull final Token aFromToken,
@Nonnull final Token aToToken) throws ParseException
diff --git a/ph-css/src/main/jjtree/ParserCSS30.jjt b/ph-css/src/main/jjtree/ParserCSS30.jjt
index f2502e3b..c1c70f8e 100644
--- a/ph-css/src/main/jjtree/ParserCSS30.jjt
+++ b/ph-css/src/main/jjtree/ParserCSS30.jjt
@@ -18,9 +18,7 @@ options {
// JavaCC options
// LOOKAHEAD = 2;
CHOICE_AMBIGUITY_CHECK = 5;
- // DEBUG_PARSER = true;
- // DEBUG_LOOKAHEAD = true;
- // DEBUG_TOKEN_MANAGER = true;
+ // DEBUG_PARSER = true; DEBUG_LOOKAHEAD = true; DEBUG_TOKEN_MANAGER = true;
// ERROR_REPORTING = false;
JAVA_UNICODE_ESCAPE = true;
UNICODE_INPUT = true;
@@ -346,9 +344,24 @@ SPECIAL_TOKEN :
}
JAVACODE
-private void errorDeprecated(final Token tok, final int... aKinds) throws ParseException #void {
- int expectedSeq[][] = { aKinds };
- throw new ParseException(tok, expectedSeq, tokenImage);
+private void errorDeprecatedProperty(final Token aPrefixToken) throws ParseException #void
+{
+ if (m_bBrowserCompliantMode)
+ {
+ if (m_aCustomErrorHandler != null)
+ m_aCustomErrorHandler.onCSSDeprecatedProperty (aPrefixToken, token);
+ else
+ LOGGER.warn("[" + aPrefixToken.beginLine + ":" + aPrefixToken.beginColumn + "] Deprecated property name '" + aPrefixToken.image + token.image + "'");
+ }
+ else
+ {
+ final ParseException ex = new ParseException (aPrefixToken, new int[][] { new int[] { IDENT } },
+ tokenImage, token_source == null ? null : ParserCSS30TokenManager.lexStateNames[token_source.curLexState]);
+ // javaSkipToClosingBraceOrSemicolon (1);
+ // LOGGER.warn ("Skipped now '"+s+"'");
+ // if (m_aCustomErrorHandler != null) m_aCustomErrorHandler.onCSSParseError (ex, token);
+ throw ex;
+ }
}
JAVACODE
@@ -510,7 +523,7 @@ JAVACODE
* @param ex The source ParseException. May not be null
* @throws ParseEOFException If EOF occurs while skipping
*/
-private void browserCompliantSkip(final ParseException ex) throws ParseEOFException #void {
+private void browserCompliantSkipInRule(final ParseException ex) throws ParseEOFException #void {
javaSkipToClosingBrace (1);
// push back last token (char count!!)
token_source.backup(1);
@@ -524,7 +537,7 @@ JAVACODE
* @param ex The source ParseException. May not be null
* @throws ParseEOFException If EOF occurs while skipping
*/
-private void browserCompliantSkipSelector(final ParseException ex) throws ParseEOFException #void {
+private void browserCompliantSkipInSelector(final ParseException ex) throws ParseEOFException #void {
javaSkipToClosingBrace (0);
// push back last token (char count!!)
token_source.backup(1);
@@ -1134,15 +1147,17 @@ void selector() : {}
void property() :
{
- Token save;
+ Token aPrefixToken;
}
{
( { jjtThis.setText (token.image); }
( )*
- )
- | LOOKAHEAD(2, ( | ) )
- { save = token; }
- ( | ) { errorDeprecated(save, IDENT); }
+ | LOOKAHEAD(2, ( | ) )
+ ( | ) { aPrefixToken = token; }
+ { errorDeprecatedProperty (aPrefixToken); }
+ /* leaving jjtThis.text null is handled inside the code */
+ ( )*
+ )
}
void important() : {}
@@ -1190,25 +1205,34 @@ void styleDeclarationOrRule() #void : {}
CSSNode styleDeclarationList() : {}
{
+try {
( )*
( styleDeclarationOrRule() )?
(
( )*
( styleDeclarationOrRule() )?
)*
+} catch (/*final*/ ParseException ex) {
+ if (m_bBrowserCompliantMode)
+ browserCompliantSkipDecl (ex);
+ else {
+ errorSkipTo (ex, RBRACE);
+ token_source.backup(1);
+ }
+}
{ return jjtThis; }
}
void styleDeclarationBlock() #void : {}
{
-try{
+try {
styleDeclarationList()
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
browserCompliantSkipDecl (ex);
- else
+ else
errorSkipTo (ex, RBRACE);
}
}
@@ -1226,7 +1250,7 @@ try{
styleDeclarationBlock()
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
- browserCompliantSkipSelector (ex);
+ browserCompliantSkipInSelector (ex);
else
throw ex;
}
@@ -1327,7 +1351,7 @@ try{
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
- browserCompliantSkip (ex);
+ browserCompliantSkipInRule (ex);
else
errorSkipTo (ex, RBRACE);
}
@@ -1412,7 +1436,7 @@ try{
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
- browserCompliantSkip (ex);
+ browserCompliantSkipInRule (ex);
else
errorSkipTo (ex, RBRACE);
}
@@ -1488,7 +1512,7 @@ try{
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
- browserCompliantSkip (ex);
+ browserCompliantSkipInRule (ex);
else
errorSkipTo (ex, RBRACE);
}
@@ -1575,7 +1599,7 @@ try{
} catch (/*final*/ ParseException ex) {
if (m_bBrowserCompliantMode)
- browserCompliantSkip (ex);
+ browserCompliantSkipInRule (ex);
else
errorSkipTo (ex, RBRACE);
}
diff --git a/ph-css/src/test/java/com/helger/css/supplementary/issues/Issue84Test.java b/ph-css/src/test/java/com/helger/css/supplementary/issues/Issue84Test.java
new file mode 100644
index 00000000..9f6dca38
--- /dev/null
+++ b/ph-css/src/test/java/com/helger/css/supplementary/issues/Issue84Test.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014-2022 Philip Helger (www.helger.com)
+ * philip[at]helger[dot]com
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.helger.css.supplementary.issues;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import org.junit.Test;
+
+import com.helger.css.ECSSVersion;
+import com.helger.css.decl.CSSStyleRule;
+import com.helger.css.decl.CascadingStyleSheet;
+import com.helger.css.reader.CSSReader;
+import com.helger.css.reader.CSSReaderSettings;
+import com.helger.css.writer.CSSWriter;
+import com.helger.css.writer.CSSWriterSettings;
+
+/**
+ * Test for https://github.com/phax/ph-css/issues/84
+ *
+ * @author Philip Helger
+ */
+public final class Issue84Test
+{
+ @Test
+ public void testBasicStarBrowserCompliant ()
+ {
+ final String sCSS = "div {\n" + "a: 100px;\n" + "*b: 1;\n" + "c:d;\n" + "}";
+ final CascadingStyleSheet aCSS = CSSReader.readFromStringReader (sCSS,
+ new CSSReaderSettings ().setCSSVersion (ECSSVersion.LATEST)
+ .setBrowserCompliantMode (true));
+ assertNotNull (aCSS);
+ assertEquals (1, aCSS.getStyleRuleCount ());
+
+ final CSSStyleRule aSR = aCSS.getStyleRuleAtIndex (0);
+ assertEquals (2, aSR.getDeclarationCount ());
+
+ assertEquals ("div{a:100px;c:d}",
+ new CSSWriter (new CSSWriterSettings ().setOptimizedOutput (true)).setWriteHeaderText (false).getCSSAsString (aCSS));
+ }
+
+ @Test
+ public void testBasicStarNotBrowserCompliant ()
+ {
+ final String sCSS = "div {\n" + "a: 100px;\n" + "*b: 1;\n" + "c:d;\n" + "}";
+ final CascadingStyleSheet aCSS = CSSReader.readFromStringReader (sCSS,
+ new CSSReaderSettings ().setCSSVersion (ECSSVersion.LATEST)
+ .setBrowserCompliantMode (false));
+ assertNotNull (aCSS);
+ assertEquals (1, aCSS.getStyleRuleCount ());
+
+ final CSSStyleRule aSR = aCSS.getStyleRuleAtIndex (0);
+ assertEquals (1, aSR.getDeclarationCount ());
+
+ assertEquals ("div{a:100px}",
+ new CSSWriter (new CSSWriterSettings ().setOptimizedOutput (true)).setWriteHeaderText (false).getCSSAsString (aCSS));
+ }
+}
diff --git a/ph-css/src/test/resources/testfiles/css30/good/issue84.css b/ph-css/src/test/resources/testfiles/css30/good/issue84.css
new file mode 100644
index 00000000..f30119d2
--- /dev/null
+++ b/ph-css/src/test/resources/testfiles/css30/good/issue84.css
@@ -0,0 +1,11 @@
+div {
+ max-width: 100px;
+ *zoom: 1;
+ position: relative;
+}
+
+div {
+ max-width: 100px;
+ $zoom: 1;
+ position: relative;
+}