Skip to content

Commit d377059

Browse files
committed
fix: convert value to DOMString
1 parent b527ed7 commit d377059

File tree

3 files changed

+82
-26
lines changed

3 files changed

+82
-26
lines changed

lib/CSSStyleDeclaration.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ var CSSOM = require('cssom');
77
var allProperties = require('./allProperties');
88
var allExtraProperties = require('./allExtraProperties');
99
var implementedProperties = require('./implementedProperties');
10-
var { dashedToCamelCase } = require('./parsers');
10+
var { dashedToCamelCase, toDOMString } = require('./parsers');
1111
var getBasicPropertyDescriptor = require('./utils/getBasicPropertyDescriptor');
1212

1313
/**
@@ -49,10 +49,8 @@ CSSStyleDeclaration.prototype = {
4949
* @see http://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration-setProperty
5050
*/
5151
setProperty: function(name, value, priority) {
52-
if (value === undefined) {
53-
return;
54-
}
55-
if (value === null || value === '') {
52+
value = toDOMString(value);
53+
if (value === '') {
5654
this.removeProperty(name);
5755
return;
5856
}
@@ -73,7 +71,8 @@ CSSStyleDeclaration.prototype = {
7371
if (value === undefined) {
7472
return;
7573
}
76-
if (value === null || value === '') {
74+
value = toDOMString(value);
75+
if (value === '') {
7776
this.removeProperty(name);
7877
return;
7978
}

lib/CSSStyleDeclaration.test.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ var allowedProperties = dashedProperties.map(parsers.dashedToCamelCase);
1212
implementedProperties = Array.from(implementedProperties).map(parsers.dashedToCamelCase);
1313
var invalidProperties = implementedProperties.filter(prop => !allowedProperties.includes(prop));
1414

15+
var BigInt = BigInt || Number;
16+
1517
describe('CSSStyleDeclaration', () => {
1618
test('has only valid properties implemented', () => {
1719
expect(invalidProperties.length).toEqual(0);
@@ -352,6 +354,53 @@ describe('CSSStyleDeclaration', () => {
352354
expect(style.fillOpacity).toEqual('0');
353355
});
354356

357+
test('setting a property with a value that can not be converted to string should throw an error', () => {
358+
const style = new CSSStyleDeclaration();
359+
360+
expect(() => (style.opacity = Symbol('0'))).toThrow('Cannot convert symbol to string');
361+
expect(() => (style.opacity = { toString: () => [0] })).toThrow(
362+
'Cannot convert object to primitive value'
363+
);
364+
});
365+
366+
test('setting a property with a value that can be converted to string should work', () => {
367+
const style = new CSSStyleDeclaration();
368+
369+
style.opacity = 1;
370+
expect(style.opacity).toBe('1');
371+
style.opacity = { toString: () => '0' };
372+
expect(style.opacity).toBe('0');
373+
374+
style.opacity = 1;
375+
expect(style.opacity).toBe('1');
376+
style.opacity = { toString: () => 0 };
377+
expect(style.opacity).toEqual('0');
378+
379+
style.opacity = BigInt(1);
380+
expect(style.opacity).toBe('1');
381+
style.opacity = { toString: () => BigInt(0) };
382+
expect(style.opacity).toEqual('0');
383+
384+
style.setProperty('--custom', [1]);
385+
expect(style.getPropertyValue('--custom')).toEqual('1');
386+
387+
style.setProperty('--custom', null);
388+
expect(style.getPropertyValue('--custom')).toBe('');
389+
style.setProperty('--custom', { toString: () => null });
390+
expect(style.getPropertyValue('--custom')).toBe('null');
391+
392+
style.setProperty('--custom', undefined);
393+
expect(style.getPropertyValue('--custom')).toBe('undefined');
394+
style.setProperty('--custom', null);
395+
style.setProperty('--custom', { toString: () => undefined });
396+
expect(style.getPropertyValue('--custom')).toBe('undefined');
397+
398+
style.setProperty('--custom', false);
399+
expect(style.getPropertyValue('--custom')).toBe('false');
400+
style.setProperty('--custom', { toString: () => true });
401+
expect(style.getPropertyValue('--custom')).toBe('true');
402+
});
403+
355404
test('onchange callback should be called when the csstext changes', () => {
356405
var style = new CSSStyleDeclaration(function(cssText) {
357406
expect(cssText).toEqual('opacity: 0;');

lib/parsers.js

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ exports.TYPES = {
1717
STRING: 7,
1818
ANGLE: 8,
1919
KEYWORD: 9,
20-
NULL_OR_EMPTY_STR: 10,
20+
EMPTY: 10,
2121
CALC: 11,
2222
};
2323

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

38-
// This will return one of the above types based on the passed in string
39-
exports.valueType = function valueType(val) {
40-
if (val === '' || val === null) {
41-
return exports.TYPES.NULL_OR_EMPTY_STR;
38+
// https://heycam.github.io/webidl/#es-DOMString
39+
exports.toDOMString = function toDOMString(val) {
40+
if (val === null) {
41+
return '';
4242
}
43-
if (typeof val === 'number') {
44-
val = val.toString();
43+
if (typeof val === 'string') {
44+
return val;
4545
}
46-
47-
if (typeof val !== 'string') {
48-
return undefined;
46+
if (typeof val === 'symbol') {
47+
throw Error('Cannot convert symbol to string');
4948
}
49+
return String(val);
50+
};
5051

52+
// This will return one of the above types based on the passed in string
53+
exports.valueType = function valueType(val) {
54+
val = exports.toDOMString(val);
55+
56+
if (val === '') {
57+
return exports.TYPES.EMPTY;
58+
}
5159
if (integerRegEx.test(val)) {
5260
return exports.TYPES.INTEGER;
5361
}
@@ -157,7 +165,7 @@ exports.valueType = function valueType(val) {
157165

158166
exports.parseInteger = function parseInteger(val) {
159167
var type = exports.valueType(val);
160-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
168+
if (type === exports.TYPES.EMPTY) {
161169
return val;
162170
}
163171
if (type !== exports.TYPES.INTEGER) {
@@ -168,7 +176,7 @@ exports.parseInteger = function parseInteger(val) {
168176

169177
exports.parseNumber = function parseNumber(val) {
170178
var type = exports.valueType(val);
171-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
179+
if (type === exports.TYPES.EMPTY) {
172180
return val;
173181
}
174182
if (type !== exports.TYPES.NUMBER && type !== exports.TYPES.INTEGER) {
@@ -182,7 +190,7 @@ exports.parseLength = function parseLength(val) {
182190
return '0px';
183191
}
184192
var type = exports.valueType(val);
185-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
193+
if (type === exports.TYPES.EMPTY) {
186194
return val;
187195
}
188196
if (type !== exports.TYPES.LENGTH) {
@@ -196,7 +204,7 @@ exports.parsePercent = function parsePercent(val) {
196204
return '0%';
197205
}
198206
var type = exports.valueType(val);
199-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
207+
if (type === exports.TYPES.EMPTY) {
200208
return val;
201209
}
202210
if (type !== exports.TYPES.PERCENT) {
@@ -221,7 +229,7 @@ exports.parseMeasurement = function parseMeasurement(val) {
221229

222230
exports.parseUrl = function parseUrl(val) {
223231
var type = exports.valueType(val);
224-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
232+
if (type === exports.TYPES.EMPTY) {
225233
return val;
226234
}
227235
var res = urlRegEx.exec(val);
@@ -260,7 +268,7 @@ exports.parseUrl = function parseUrl(val) {
260268

261269
exports.parseString = function parseString(val) {
262270
var type = exports.valueType(val);
263-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
271+
if (type === exports.TYPES.EMPTY) {
264272
return val;
265273
}
266274
if (type !== exports.TYPES.STRING) {
@@ -287,7 +295,7 @@ exports.parseString = function parseString(val) {
287295

288296
exports.parseColor = function parseColor(val) {
289297
var type = exports.valueType(val);
290-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
298+
if (type === exports.TYPES.EMPTY) {
291299
return val;
292300
}
293301
var red,
@@ -406,7 +414,7 @@ exports.parseColor = function parseColor(val) {
406414

407415
exports.parseAngle = function parseAngle(val) {
408416
var type = exports.valueType(val);
409-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
417+
if (type === exports.TYPES.EMPTY) {
410418
return val;
411419
}
412420
if (type !== exports.TYPES.ANGLE) {
@@ -431,7 +439,7 @@ exports.parseAngle = function parseAngle(val) {
431439

432440
exports.parseKeyword = function parseKeyword(val, valid_keywords) {
433441
var type = exports.valueType(val);
434-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
442+
if (type === exports.TYPES.EMPTY) {
435443
return val;
436444
}
437445
if (type !== exports.TYPES.KEYWORD) {
@@ -520,7 +528,7 @@ var getParts = function(str) {
520528
exports.shorthandParser = function parse(v, shorthand_for) {
521529
var obj = {};
522530
var type = exports.valueType(v);
523-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
531+
if (type === exports.TYPES.EMPTY) {
524532
Object.keys(shorthand_for).forEach(function(property) {
525533
obj[property] = '';
526534
});

0 commit comments

Comments
 (0)