cssstyle icon indicating copy to clipboard operation
cssstyle copied to clipboard

Values are not properly converted to DOMString

Open cdoublev opened this issue 3 years ago • 1 comments

I'm not sure that the following behavior tested in Chrome and Firefox is described in any specification:

// Case 1: toString() from prototype
class Prop {
  toString() {
    return 1 // Number
  }
}
style.setProperty('opacity', new Prop) // Ok, new value: 1

// Case 2: toString() from instance
const Prop = {
  toString() {
    return 1
  }
}
style.setProperty('opacity', Prop) // Ok, new value: 1

// Case 3: recursive toString()
class RecursiveProp {
  toString() {
    return new Prop()
  }
}
style.setProperty('opacity', new RecursiveProp) // Error

Ie. the value should be converted to String if it has a toString() method. cssstyle currently returns '' for all cases, ie. it results to an invalid value. Chrome and Firefox throw an error for case 3.

cdoublev avatar Apr 24 '21 13:04 cdoublev

From what I understand, a value is converted to a DOMString when passing from JavaScript to a DOM element style interface.

Interface CSSStyleDeclaration

void setProperty(in DOMString propertyName, in DOMString value, in DOMString priority) raises(DOMException);

https://www.w3.org/TR/DOM-Level-2-Style/css.html#CSS-CSSStyleDeclaration

ECMAScript values are converted to an IDL value when passed to a platform object expecting that type

https://heycam.github.io/webidl/#es-type-mapping

An ECMAScript value V is converted to an IDL DOMString value by running the following algorithm:

  1. If V is null and the conversion is to an IDL type associated with the LegacyNullToEmptyString extended attribute, then return the DOMString value that represents the empty string.
  2. Let x be ToString(V)
  3. Return the IDL DOMString value [...]

https://heycam.github.io/webidl/#es-DOMString

I renamed the title of this issue to handle the following cases that were also not handled correctly:

target.style.opacity = Symbol('1')                             // Error
target.style.opacity = { toString: () => [0] }                 // Error
target.style.opacity = BigInt(1)                               // '1'
target.style.setProperty('--custom', undefined)                // 'undefined'
target.style.setProperty('--custom', true)                     // 'true'
target.style.setProperty('--custom', { toString: () => null }) // 'null'

cdoublev avatar Apr 29 '21 12:04 cdoublev