Skip to content

Commit 6e06b71

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

File tree

3 files changed

+121
-23
lines changed

3 files changed

+121
-23
lines changed

lib/CSSStyleDeclaration.js

Lines changed: 5 additions & 3 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,11 @@ 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+
value = toDOMString(value);
5253
if (value === undefined) {
5354
return;
5455
}
55-
if (value === null || value === '') {
56+
if (value === '') {
5657
this.removeProperty(name);
5758
return;
5859
}
@@ -70,10 +71,11 @@ CSSStyleDeclaration.prototype = {
7071
this._importants[lowercaseName] = priority;
7172
},
7273
_setProperty: function(name, value, priority) {
74+
value = toDOMString(value);
7375
if (value === undefined) {
7476
return;
7577
}
76-
if (value === null || value === '') {
78+
if (value === '') {
7779
this.removeProperty(name);
7880
return;
7981
}

lib/CSSStyleDeclaration.test.js

Lines changed: 82 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,86 @@ 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', () => {
358+
const style = new CSSStyleDeclaration();
359+
360+
style.setProperty('--custom', '1');
361+
expect(style.getPropertyValue('--custom')).toBe('1');
362+
363+
style.setProperty('--custom', undefined);
364+
expect(style.getPropertyValue('--custom')).toBe('1');
365+
366+
expect(() => {
367+
style.setProperty('--custom', Symbol('0'));
368+
}).toThrow('Cannot convert symbol to string');
369+
370+
expect(() => {
371+
style.setProperty('--custom', {
372+
toString() {
373+
return [0];
374+
},
375+
});
376+
}).toThrow('Cannot convert object to primitive value');
377+
});
378+
379+
test('setting a property with a value that can be converted to string', () => {
380+
const style = new CSSStyleDeclaration();
381+
382+
style.setProperty('--custom', '1');
383+
expect(style.getPropertyValue('--custom')).toBe('1');
384+
385+
style.setProperty('--custom', null);
386+
expect(style.getPropertyValue('--custom')).toBe('');
387+
style.setProperty('--custom', '1');
388+
389+
style.setProperty('--custom', false);
390+
expect(style.getPropertyValue('--custom')).toBe('false');
391+
392+
style.setProperty('--custom', 0);
393+
expect(style.getPropertyValue('--custom')).toBe('0');
394+
style.setProperty('--custom', '1');
395+
396+
style.setProperty('--custom', BigInt(0));
397+
expect(style.getPropertyValue('--custom')).toBe('0');
398+
style.setProperty('--custom', '1');
399+
400+
style.setProperty('--custom', [0]);
401+
expect(style.getPropertyValue('--custom')).toEqual('0');
402+
style.setProperty('--custom', '1');
403+
404+
style.setProperty('--custom', {
405+
toString() {
406+
return '0';
407+
},
408+
});
409+
expect(style.getPropertyValue('--custom')).toEqual('0');
410+
style.setProperty('--custom', '1');
411+
412+
style.setProperty('--custom', {
413+
toString() {
414+
return 0;
415+
},
416+
});
417+
expect(style.getPropertyValue('--custom')).toEqual('0');
418+
style.setProperty('--custom', '1');
419+
420+
style.setProperty('--custom', {
421+
toString() {
422+
return BigInt(0);
423+
},
424+
});
425+
expect(style.getPropertyValue('--custom')).toEqual('0');
426+
style.setProperty('--custom', '1');
427+
428+
style.setProperty('--custom', {
429+
toString() {
430+
return null;
431+
},
432+
});
433+
expect(style.getPropertyValue('--custom')).toBe('null');
434+
style.setProperty('--custom', '1');
435+
});
436+
355437
test('onchange callback should be called when the csstext changes', () => {
356438
var style = new CSSStyleDeclaration(function(cssText) {
357439
expect(cssText).toEqual('opacity: 0;');

lib/parsers.js

Lines changed: 34 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,33 @@ 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 (val === undefined) {
44+
return val;
4545
}
46-
47-
if (typeof val !== 'string') {
48-
return undefined;
46+
if (typeof val === 'string') {
47+
return val;
48+
}
49+
if (typeof val === 'symbol') {
50+
throw Error('Cannot convert symbol to string');
4951
}
52+
return String(val);
53+
};
54+
55+
// This will return one of the above types based on the passed in string
56+
exports.valueType = function valueType(val) {
57+
val = exports.toDOMString(val);
5058

59+
if (val === undefined) {
60+
return val;
61+
}
62+
if (val === '') {
63+
return exports.TYPES.EMPTY;
64+
}
5165
if (integerRegEx.test(val)) {
5266
return exports.TYPES.INTEGER;
5367
}
@@ -157,7 +171,7 @@ exports.valueType = function valueType(val) {
157171

158172
exports.parseInteger = function parseInteger(val) {
159173
var type = exports.valueType(val);
160-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
174+
if (type === exports.TYPES.EMPTY) {
161175
return val;
162176
}
163177
if (type !== exports.TYPES.INTEGER) {
@@ -168,7 +182,7 @@ exports.parseInteger = function parseInteger(val) {
168182

169183
exports.parseNumber = function parseNumber(val) {
170184
var type = exports.valueType(val);
171-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
185+
if (type === exports.TYPES.EMPTY) {
172186
return val;
173187
}
174188
if (type !== exports.TYPES.NUMBER && type !== exports.TYPES.INTEGER) {
@@ -182,7 +196,7 @@ exports.parseLength = function parseLength(val) {
182196
return '0px';
183197
}
184198
var type = exports.valueType(val);
185-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
199+
if (type === exports.TYPES.EMPTY) {
186200
return val;
187201
}
188202
if (type !== exports.TYPES.LENGTH) {
@@ -196,7 +210,7 @@ exports.parsePercent = function parsePercent(val) {
196210
return '0%';
197211
}
198212
var type = exports.valueType(val);
199-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
213+
if (type === exports.TYPES.EMPTY) {
200214
return val;
201215
}
202216
if (type !== exports.TYPES.PERCENT) {
@@ -221,7 +235,7 @@ exports.parseMeasurement = function parseMeasurement(val) {
221235

222236
exports.parseUrl = function parseUrl(val) {
223237
var type = exports.valueType(val);
224-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
238+
if (type === exports.TYPES.EMPTY) {
225239
return val;
226240
}
227241
var res = urlRegEx.exec(val);
@@ -260,7 +274,7 @@ exports.parseUrl = function parseUrl(val) {
260274

261275
exports.parseString = function parseString(val) {
262276
var type = exports.valueType(val);
263-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
277+
if (type === exports.TYPES.EMPTY) {
264278
return val;
265279
}
266280
if (type !== exports.TYPES.STRING) {
@@ -287,7 +301,7 @@ exports.parseString = function parseString(val) {
287301

288302
exports.parseColor = function parseColor(val) {
289303
var type = exports.valueType(val);
290-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
304+
if (type === exports.TYPES.EMPTY) {
291305
return val;
292306
}
293307
var red,
@@ -406,7 +420,7 @@ exports.parseColor = function parseColor(val) {
406420

407421
exports.parseAngle = function parseAngle(val) {
408422
var type = exports.valueType(val);
409-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
423+
if (type === exports.TYPES.EMPTY) {
410424
return val;
411425
}
412426
if (type !== exports.TYPES.ANGLE) {
@@ -431,7 +445,7 @@ exports.parseAngle = function parseAngle(val) {
431445

432446
exports.parseKeyword = function parseKeyword(val, valid_keywords) {
433447
var type = exports.valueType(val);
434-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
448+
if (type === exports.TYPES.EMPTY) {
435449
return val;
436450
}
437451
if (type !== exports.TYPES.KEYWORD) {
@@ -520,7 +534,7 @@ var getParts = function(str) {
520534
exports.shorthandParser = function parse(v, shorthand_for) {
521535
var obj = {};
522536
var type = exports.valueType(v);
523-
if (type === exports.TYPES.NULL_OR_EMPTY_STR) {
537+
if (type === exports.TYPES.EMPTY) {
524538
Object.keys(shorthand_for).forEach(function(property) {
525539
obj[property] = '';
526540
});

0 commit comments

Comments
 (0)