See #254 - adds system font support.
authorJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 5 Apr 2017 09:35:43 +0000 (11:35 +0200)
committerJakub Pawlowicz <contact@jakubpawlowicz.com>
Wed, 5 Apr 2017 09:50:16 +0000 (11:50 +0200)
Why:

* System fonts should not be mergeable with other types of fonts as such
  merging is not supported by browsers.

lib/optimizer/level-2/break-up.js
lib/optimizer/level-2/properties/is-mergeable-shorthand.js [new file with mode: 0644]
lib/optimizer/level-2/properties/override-properties.js
lib/optimizer/level-2/restore.js
lib/optimizer/validator.js
lib/tokenizer/marker.js
test/optimizer/level-2/break-up-test.js
test/optimizer/level-2/properties/override-properties-test.js
test/optimizer/level-2/restore-test.js

index e3e495d..ec86e03 100644 (file)
@@ -221,6 +221,12 @@ function font(property, compactable, validator) {
     throw new InvalidPropertyError('Missing font values at ' + formatPosition(property.all[property.position][1][2][0]) + '. Ignoring.');
   }
 
+  if (values.length == 1 && (validator.isFontKeyword(values[0][1]) || validator.isPrefixed(values[0][1]))) {
+    values[0][1] = Marker.INTERNAL + values[0][1];
+    style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values;
+    return components;
+  }
+
   if (values.length == 1 && values[0][1] == 'inherit') {
     style.value = variant.value = weight.value = stretch.value = size.value = height.value = family.value = values;
     return components;
diff --git a/lib/optimizer/level-2/properties/is-mergeable-shorthand.js b/lib/optimizer/level-2/properties/is-mergeable-shorthand.js
new file mode 100644 (file)
index 0000000..ee7191e
--- /dev/null
@@ -0,0 +1,11 @@
+var Marker = require('../../../tokenizer/marker');
+
+function isMergeableShorthand(shorthand) {
+  if (shorthand.name != 'font') {
+    return true;
+  }
+
+  return shorthand.value[0][1].indexOf(Marker.INTERNAL) == -1;
+}
+
+module.exports = isMergeableShorthand;
index c3ed366..035a257 100644 (file)
@@ -2,6 +2,7 @@ var hasInherit = require('./has-inherit');
 var everyValuesPair = require('./every-values-pair');
 var findComponentIn = require('./find-component-in');
 var isComponentOf = require('./is-component-of');
+var isMergeableShorthand = require('./is-mergeable-shorthand');
 var overridesNonComponentShorthand = require('./overrides-non-component-shorthand');
 var sameVendorPrefixesIn = require('./vendor-prefixes').same;
 
@@ -275,6 +276,11 @@ function overrideProperties(properties, withMerging, compatibility, validator) {
         if (!anyValue(validator.isFunction, left) && overridingFunction(right, validator))
           continue;
 
+        if (!isMergeableShorthand(right)) {
+          left.unused = true;
+          continue;
+        }
+
         component = findComponentIn(right, left);
         mayOverride = compactable[left.name].canOverride;
         if (everyValuesPair(mayOverride.bind(null, validator), left, component)) {
@@ -326,6 +332,9 @@ function overrideProperties(properties, withMerging, compatibility, validator) {
         if (overridingFunction(left, validator))
           continue;
 
+        if (!isMergeableShorthand(left))
+          continue;
+
         component = findComponentIn(left, right);
         if (everyValuesPair(mayOverride.bind(null, validator), component, right)) {
           var disabledBackgroundMerging =
@@ -368,6 +377,11 @@ function overrideProperties(properties, withMerging, compatibility, validator) {
           continue;
         }
 
+        if (!isMergeableShorthand(right)) {
+          left.unused = true;
+          continue;
+        }
+
         for (k = left.components.length - 1; k >= 0; k--) {
           var leftComponent = left.components[k];
           var rightComponent = right.components[k];
index 2f27ef5..13f12e4 100644 (file)
@@ -142,6 +142,11 @@ function font(property, compactable) {
   var componentIndex = 0;
   var fontFamilyIndex = 0;
 
+  if (property.value[0][1].indexOf(Marker.INTERNAL) === 0) {
+    property.value[0][1] = property.value[0][1].substring(Marker.INTERNAL.length);
+    return property.value;
+  }
+
   // first four components are optional
   while (componentIndex < 4) {
     component = components[componentIndex];
index 5fc69d0..a4b8b3d 100644 (file)
@@ -140,6 +140,14 @@ var Keywords = {
   'left': [
     'auto'
   ],
+  'font': [
+    'caption',
+    'icon',
+    'menu',
+    'message-box',
+    'small-caption',
+    'status-bar'
+  ],
   'font-size': [
     'large',
     'larger',
@@ -386,6 +394,7 @@ function validator(compatibility) {
     isColor: isColor,
     isColorFunction: isColorFunction,
     isDynamicUnit: isDynamicUnit,
+    isFontKeyword: isKeyword('font'),
     isFontSizeKeyword: isKeyword('font-size'),
     isFontStretchKeyword: isKeyword('font-stretch'),
     isFontStyleKeyword: isKeyword('font-style'),
index c3f6805..767a5f0 100644 (file)
@@ -10,6 +10,7 @@ var Marker = {
   DOUBLE_QUOTE: '"',
   EXCLAMATION: '!',
   FORWARD_SLASH: '/',
+  INTERNAL: '-clean-css-',
   NEW_LINE_NIX: '\n',
   NEW_LINE_WIN: '\r',
   OPEN_CURLY_BRACKET: '{',
index 34ad49a..2617203 100644 (file)
@@ -1071,6 +1071,90 @@ vows.describe(breakUp)
         'has 0 components': function (components) {
           assert.lengthOf(components, 0);
         }
+      },
+      'system font': {
+        'topic': function () {
+          return _breakUp([
+            [
+              'property',
+              ['property-name', 'font'],
+              ['property-value', 'icon']
+            ]
+          ]);
+        },
+        'has 7 components': function (components) {
+          assert.lengthOf(components, 7);
+        },
+        'has font-style': function (components) {
+          assert.equal(components[0].name, 'font-style');
+          assert.deepEqual(components[0].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has font-variant': function (components) {
+          assert.equal(components[1].name, 'font-variant');
+          assert.deepEqual(components[1].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has font-weight': function (components) {
+          assert.equal(components[2].name, 'font-weight');
+          assert.deepEqual(components[2].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has font-stretch': function (components) {
+          assert.equal(components[3].name, 'font-stretch');
+          assert.deepEqual(components[3].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has font-size': function (components) {
+          assert.equal(components[4].name, 'font-size');
+          assert.deepEqual(components[4].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has line-height': function (components) {
+          assert.equal(components[5].name, 'line-height');
+          assert.deepEqual(components[5].value, [['property-value', '-clean-css-icon']]);
+        },
+        'has font-family': function (components) {
+          assert.equal(components[6].name, 'font-family');
+          assert.deepEqual(components[6].value, [['property-value', '-clean-css-icon']]);
+        }
+      },
+      'system font with vendor prefix': {
+        'topic': function () {
+          return _breakUp([
+            [
+              'property',
+              ['property-name', 'font'],
+              ['property-value', '-moz-window']
+            ]
+          ]);
+        },
+        'has 7 components': function (components) {
+          assert.lengthOf(components, 7);
+        },
+        'has font-style': function (components) {
+          assert.equal(components[0].name, 'font-style');
+          assert.deepEqual(components[0].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has font-variant': function (components) {
+          assert.equal(components[1].name, 'font-variant');
+          assert.deepEqual(components[1].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has font-weight': function (components) {
+          assert.equal(components[2].name, 'font-weight');
+          assert.deepEqual(components[2].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has font-stretch': function (components) {
+          assert.equal(components[3].name, 'font-stretch');
+          assert.deepEqual(components[3].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has font-size': function (components) {
+          assert.equal(components[4].name, 'font-size');
+          assert.deepEqual(components[4].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has line-height': function (components) {
+          assert.equal(components[5].name, 'line-height');
+          assert.deepEqual(components[5].value, [['property-value', '-clean-css--moz-window']]);
+        },
+        'has font-family': function (components) {
+          assert.equal(components[6].name, 'font-family');
+          assert.deepEqual(components[6].value, [['property-value', '-clean-css--moz-window']]);
+        }
       }
     },
     'four values': {
index 1d85a85..6be1910 100644 (file)
@@ -1716,6 +1716,53 @@ vows.describe(optimizeProperties)
           ]
         ]);
       }
+    },
+    'system font shorthand before longhand': {
+      'topic': function () {
+        return _optimize('.block{font:icon;font-weight:bold}');
+      },
+      'into': function (properties) {
+        assert.deepEqual(properties, [
+          [
+            'property',
+            ['property-name', 'font', [[1, 7, undefined]]],
+            ['property-value', 'icon', [[1, 12, undefined]]]
+          ],
+          [
+            'property',
+            ['property-name', 'font-weight', [[1, 17, undefined]]],
+            ['property-value', 'bold', [[1, 29, undefined]]]
+          ]
+        ]);
+      }
+    },
+    'system font shorthand after longhand': {
+      'topic': function () {
+        return _optimize('.block{font-weight:bold;font:icon}');
+      },
+      'into': function (properties) {
+        assert.deepEqual(properties, [
+          [
+            'property',
+            ['property-name', 'font', [[1, 24, undefined]]],
+            ['property-value', 'icon', [[1, 29, undefined]]]
+          ]
+        ]);
+      }
+    },
+    'two system font shorthands': {
+      'topic': function () {
+        return _optimize('.block{font:status-bar;font:icon}');
+      },
+      'into': function (properties) {
+        assert.deepEqual(properties, [
+          [
+            'property',
+            ['property-name', 'font', [[1, 23, undefined]]],
+            ['property-value', 'icon', [[1, 28, undefined]]]
+          ]
+        ]);
+      }
     }
   })
   .addBatch({
index e7c8f79..b37c4bc 100644 (file)
@@ -806,6 +806,38 @@ vows.describe(restore)
           ]);
         }
       },
+      'system font with standard value': {
+        'topic': function () {
+          return _restore(
+            _breakUp([
+              'property',
+              ['property-name', 'font'],
+              ['property-value', 'icon']
+            ])
+          );
+        },
+        'gives right value back': function (restoredValue) {
+          assert.deepEqual(restoredValue, [
+            ['property-value', 'icon']
+          ]);
+        }
+      },
+      'system font with vendor-prefixed value': {
+        'topic': function () {
+          return _restore(
+            _breakUp([
+              'property',
+              ['property-name', 'font'],
+              ['property-value', '-moz-status']
+            ])
+          );
+        },
+        'gives right value back': function (restoredValue) {
+          assert.deepEqual(restoredValue, [
+            ['property-value', '-moz-status']
+          ]);
+        }
+      },
       'list with some values': {
         'topic': function () {
           return _restore(