Skip to content

Commit

Permalink
fix: upstream conversion of value to DOM String
Browse files Browse the repository at this point in the history
Fixes jsdom#129
  • Loading branch information
cdoublev committed Jun 8, 2021
1 parent bcf8334 commit 3255fea
Show file tree
Hide file tree
Showing 17 changed files with 67 additions and 115 deletions.
24 changes: 17 additions & 7 deletions lib/CSSStyleDeclaration.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
var CSSOM = require('cssom');
var allProperties = require('./allProperties');
var allExtraProperties = require('./allExtraProperties');
const { camelToDashed, dashedToCamelCase } = require('./parsers');
const { camelToDashed, dashedToCamelCase, toDOMString } = require('./parsers');
const fs = require('fs');
const path = require('path');
var getBasicPropertyDescriptor = require('./utils/getBasicPropertyDescriptor');
Expand Down Expand Up @@ -39,7 +39,7 @@ CSSStyleDeclaration.prototype = {
if (!this._values.hasOwnProperty(name)) {
return '';
}
return this._values[name].toString();
return this._values[name];
},

/**
Expand All @@ -50,10 +50,8 @@ CSSStyleDeclaration.prototype = {
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
*/
setProperty: function(name, value, priority) {
if (value === undefined) {
return;
}
if (value === null || value === '') {
value = toDOMString(value);
if (value === '') {
this.removeProperty(name);
return;
}
Expand All @@ -74,7 +72,7 @@ CSSStyleDeclaration.prototype = {
if (value === undefined) {
return;
}
if (value === null || value === '') {
if (value === '') {
this.removeProperty(name);
return;
}
Expand Down Expand Up @@ -240,12 +238,24 @@ Object.defineProperties(CSSStyleDeclaration.prototype, {
},
});

/**
* @param {function} setter
*
* This "higher order" setter converts value to a DOM String for all properties.
*/
function createSetter(setter) {
return function setProperty(v) {
return setter.call(this, toDOMString(v));
};
}

const implementedProperties = fs
.readdirSync(path.resolve(__dirname, 'properties'))
.reduce((props, filename) => {
const { definition } = require(`./properties/${filename}`);
const { name: camelCaseName } = path.parse(filename);
const dashedCaseName = camelToDashed(camelCaseName);
definition.set = createSetter(definition.set);
Object.defineProperty(CSSStyleDeclaration.prototype, camelCaseName, definition);
Object.defineProperty(CSSStyleDeclaration.prototype, dashedCaseName, definition);
return props.add(dashedCaseName);
Expand Down
101 changes: 33 additions & 68 deletions lib/parsers.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ exports.TYPES = {
STRING: 7,
ANGLE: 8,
KEYWORD: 9,
NULL_OR_EMPTY_STR: 10,
CALC: 11,
};

Expand All @@ -35,19 +34,18 @@ var calcRegEx = /^calc\(([^)]*)\)$/;
var colorRegEx4 = /^hsla?\(\s*(-?\d+|-?\d*.\d+)\s*,\s*(-?\d+|-?\d*.\d+)%\s*,\s*(-?\d+|-?\d*.\d+)%\s*(,\s*(-?\d+|-?\d*.\d+)\s*)?\)/;
var angleRegEx = /^([-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/;

// This will return one of the above types based on the passed in string
exports.valueType = function valueType(val) {
if (val === '' || val === null) {
return exports.TYPES.NULL_OR_EMPTY_STR;
}
if (typeof val === 'number') {
val = val.toString();
exports.toDOMString = function toDOMString(val) {
if (val === null) {
return '';
}

if (typeof val !== 'string') {
return undefined;
if (typeof val === 'symbol') {
throw Error('Cannot convert symbol to string');
}
return `${val}`;
};

// This will return one of the above types based on the passed in string
exports.valueType = function valueType(val) {
if (integerRegEx.test(val)) {
return exports.TYPES.INTEGER;
}
Expand Down Expand Up @@ -156,50 +154,47 @@ exports.valueType = function valueType(val) {
};

exports.parseInteger = function parseInteger(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.INTEGER) {
if (exports.valueType(val) !== exports.TYPES.INTEGER) {
return undefined;
}
return String(parseInt(val, 10));
};

exports.parseNumber = function parseNumber(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
var type = exports.valueType(val);
if (type !== exports.TYPES.NUMBER && type !== exports.TYPES.INTEGER) {
return undefined;
}
return String(parseFloat(val));
};

exports.parseLength = function parseLength(val) {
if (val === 0 || val === '0') {
return '0px';
}
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.LENGTH) {
if (val === '0') {
return '0px';
}
if (exports.valueType(val) !== exports.TYPES.LENGTH) {
return undefined;
}
return val;
};

exports.parsePercent = function parsePercent(val) {
if (val === 0 || val === '0') {
return '0%';
}
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.PERCENT) {
if (val === '0') {
return '0%';
}
if (exports.valueType(val) !== exports.TYPES.PERCENT) {
return undefined;
}
return val;
Expand All @@ -220,8 +215,7 @@ exports.parseMeasurement = function parseMeasurement(val) {
};

exports.parseUrl = function parseUrl(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
var res = urlRegEx.exec(val);
Expand Down Expand Up @@ -259,13 +253,9 @@ exports.parseUrl = function parseUrl(val) {
};

exports.parseString = function parseString(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.STRING) {
return undefined;
}
var i;
for (i = 1; i < val.length - 1; i++) {
switch (val[i]) {
Expand All @@ -286,8 +276,7 @@ exports.parseString = function parseString(val) {
};

exports.parseColor = function parseColor(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
var red,
Expand Down Expand Up @@ -398,18 +387,17 @@ exports.parseColor = function parseColor(val) {
return 'rgba(' + r + ', ' + g + ', ' + b + ', ' + alpha + ')';
}

if (type === exports.TYPES.COLOR) {
if (exports.valueType(val) === exports.TYPES.COLOR) {
return val;
}
return undefined;
};

exports.parseAngle = function parseAngle(val) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.ANGLE) {
if (exports.valueType(val) !== exports.TYPES.ANGLE) {
return undefined;
}
var res = angleRegEx.exec(val);
Expand All @@ -430,14 +418,13 @@ exports.parseAngle = function parseAngle(val) {
};

exports.parseKeyword = function parseKeyword(val, valid_keywords) {
var type = exports.valueType(val);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (val === '') {
return val;
}
if (type !== exports.TYPES.KEYWORD) {
if (exports.valueType(val) !== exports.TYPES.KEYWORD) {
return undefined;
}
val = val.toString().toLowerCase();
val = val.toLowerCase();
var i;
for (i = 0; i < valid_keywords.length; i++) {
if (valid_keywords[i].toLowerCase() === val) {
Expand Down Expand Up @@ -519,22 +506,12 @@ var getParts = function(str) {
*/
exports.shorthandParser = function parse(v, shorthand_for) {
var obj = {};
var type = exports.valueType(v);
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
if (v === '') {
Object.keys(shorthand_for).forEach(function(property) {
obj[property] = '';
});
return obj;
}

if (typeof v === 'number') {
v = v.toString();
}

if (typeof v !== 'string') {
return undefined;
}

if (v.toLowerCase() === 'inherit') {
return {};
}
Expand Down Expand Up @@ -623,12 +600,6 @@ exports.implicitSetter = function(property_before, property_after, isValid, pars
var part_names = ['top', 'right', 'bottom', 'left'];

return function(v) {
if (typeof v === 'number') {
v = v.toString();
}
if (typeof v !== 'string') {
return undefined;
}
var parts;
if (v.toLowerCase() === 'inherit' || v === '') {
parts = [v];
Expand Down Expand Up @@ -679,12 +650,6 @@ exports.subImplicitSetter = function(prefix, part, isValid, parser) {
var subparts = [prefix + '-top', prefix + '-right', prefix + '-bottom', prefix + '-left'];

return function(v) {
if (typeof v === 'number') {
v = v.toString();
}
if (typeof v !== 'string') {
return undefined;
}
if (!isValid(v)) {
return undefined;
}
Expand Down
2 changes: 1 addition & 1 deletion lib/properties/backgroundPosition.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var parsers = require('../parsers');
var valid_keywords = ['top', 'center', 'bottom', 'left', 'right'];

var parse = function parse(v) {
if (v === '' || v === null) {
if (v === '') {
return undefined;
}
var parts = v.split(/\s+/);
Expand Down
2 changes: 1 addition & 1 deletion lib/properties/border.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var myShorthandGetter = shorthandGetter('border', shorthand_for);

module.exports.definition = {
set: function(v) {
if (v.toString().toLowerCase() === 'none') {
if (v.toLowerCase() === 'none') {
v = '';
}
myShorthandSetter.call(this, v);
Expand Down
3 changes: 0 additions & 3 deletions lib/properties/borderColor.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,6 @@ var parsers = require('../parsers');
var implicitSetter = require('../parsers').implicitSetter;

module.exports.isValid = function parse(v) {
if (typeof v !== 'string') {
return false;
}
return (
v === '' || v.toLowerCase() === 'transparent' || parsers.valueType(v) === parsers.TYPES.COLOR
);
Expand Down
4 changes: 2 additions & 2 deletions lib/properties/borderSpacing.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ var parsers = require('../parsers');
// if two, the first applies to the horizontal and the second applies to vertical spacing

var parse = function parse(v) {
if (v === '' || v === null) {
if (v === '') {
return undefined;
}
if (v === 0) {
if (v === '0') {
return '0px';
}
if (v.toLowerCase() === 'inherit') {
Expand Down
2 changes: 1 addition & 1 deletion lib/properties/borderStyle.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ var styles = [
];

module.exports.isValid = function parse(v) {
return typeof v === 'string' && (v === '' || styles.indexOf(v) !== -1);
return v === '' || styles.indexOf(v) !== -1;
};
var isValid = module.exports.isValid;

Expand Down
3 changes: 0 additions & 3 deletions lib/properties/borderWidth.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ module.exports.isValid = function parse(v) {
if (length !== undefined) {
return true;
}
if (typeof v !== 'string') {
return false;
}
if (v === '') {
return true;
}
Expand Down
5 changes: 1 addition & 4 deletions lib/properties/clip.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,9 @@ var parseMeasurement = require('../parsers').parseMeasurement;
var shape_regex = /^rect\((.*)\)$/i;

var parse = function(val) {
if (val === '' || val === null) {
if (val === '') {
return val;
}
if (typeof val !== 'string') {
return undefined;
}
val = val.toLowerCase();
if (val === 'auto' || val === 'inherit') {
return val;
Expand Down
4 changes: 1 addition & 3 deletions lib/properties/flex.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,7 @@ module.exports.isValid = function isValid(v) {

module.exports.definition = {
set: function(v) {
var normalizedValue = String(v)
.trim()
.toLowerCase();
var normalizedValue = v.trim().toLowerCase();

if (normalizedValue === 'none') {
myShorthandSetter.call(this, '0 0 auto');
Expand Down
4 changes: 2 additions & 2 deletions lib/properties/flexBasis.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
var parseMeasurement = require('../parsers').parseMeasurement;

function parse(v) {
if (String(v).toLowerCase() === 'auto') {
if (v.toLowerCase() === 'auto') {
return 'auto';
}
if (String(v).toLowerCase() === 'inherit') {
if (v.toLowerCase() === 'inherit') {
return 'inherit';
}
return parseMeasurement(v);
Expand Down
2 changes: 1 addition & 1 deletion lib/properties/fontFamily.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var valueType = require('../parsers').valueType;

var partsRegEx = /\s*,\s*/;
module.exports.isValid = function isValid(v) {
if (v === '' || v === null) {
if (v === '') {
return true;
}
var parts = v.split(partsRegEx);
Expand Down
Loading

0 comments on commit 3255fea

Please sign in to comment.