Change:
On the first render it works, but then the update silently fails. Expected would be the semicolon being removed, or an error/warning in the development build. Tested on Chrome latest, Firefox latest, with 0.12.1 and master. Minimal: ran into (on IRC).
My first instinct is to put a warning in DEV so we don't incur any costs in prod. This would be similar to our other style key warning ("you used background-color but probably meant backgroundColor" or whatever it is we say).
sounds reasonable, I don't think there's any valid reason to have a semicolon there.
It's only a warning, but it's worth considering that is valid CSS IIRC.
so that wouldn't warn :)
Oh right :), but I've seen plenty of invalid , but perhaps that's an exercise for some other time. Anyway, you might want to ignore white-space after the as well.
I'm working on this issue. I've a warning, but thinking that it may be a good idea to trim any semicolons as well. The warning will serve to let developers know it's invalid syntax, but try and fix the problem while we're at it.

Discussion:
// 'msTransform' is correct, but the other prefixes should be capitalized var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; <ins> // style values shouldn't contain a semicolon var badStyleValueWithSemicolonPattern = /;s*$/; </ins> var warnedStyleNames = {}; <ins> var warnedStyleValues = {}; </ins> var warnHyphenatedStyleName = function(name) { if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) {

name.charAt(0).toUpperCase() + name.slice(1) + '?' ); }; <ins> var warnStyleValueWithSemicolon = function(name, value) { if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { return; } warnedStyleValues[value] = true; warning( false, 'Style property values shouldn't contain a semicolon. ' + 'Try "%s: %s" instead.', name, value.replace(badStyleValueWithSemicolonPattern, '') ); }; /** * @param {string} name * @param {*} value */ var warnValidStyle = function(name, value) { if (name.indexOf('-') > -1) { warnHyphenatedStyleName(name); } else if (badVendoredStyleNamePattern.test(name)) { warnBadVendoredStyleName(name); } else if (badStyleValueWithSemicolonPattern.test(value)) { warnStyleValueWithSemicolon(name, value); } }; </ins> } /**

if (!styles.hasOwnProperty(styleName)) { continue; } <ins> var styleValue = styles[styleName]; </ins> if (__DEV__) { <del> if (styleName.indexOf('-') > -1) { warnHyphenatedStyleName(styleName); } else if (badVendoredStyleNamePattern.test(styleName)) { warnBadVendoredStyleName(styleName); } </del> <ins> warnValidStyle(styleName, styleValue); </ins> } <del> var styleValue = styles[styleName]; </del> if (styleValue != null) { serialized += processStyleName(styleName) + ':'; serialized += dangerousStyleValue(styleName, styleValue) + ';';

continue; } if (__DEV__) { <del> if (styleName.indexOf('-') > -1) { warnHyphenatedStyleName(styleName); } else if (badVendoredStyleNamePattern.test(styleName)) { warnBadVendoredStyleName(styleName); } </del> <ins> warnValidStyle(styleName, styles[styleName]); </ins> } var styleValue = dangerousStyleValue(styleName, styles[styleName]); if (styleName === 'float') {

expect(console.warn.argsForCall[1][0]).toContain('WebkitTransform'); }); <ins> it('should warn about style having a trailing semicolon', function() { spyOn(console, 'warn'); CSSPropertyOperations.createMarkupForStyles({ fontFamily: 'Helvetica, arial', backgroundImage: 'url(foo;bar)', backgroundColor: 'blue;', color: 'red;   ' }); expect(console.warn.callCount).toBe(2); expect(console.warn.argsForCall[0][0]).toContain('Try "backgroundColor: blue" instead'); expect(console.warn.argsForCall[1][0]).toContain('Try "color: red" instead'); }); </ins> });