02:40
<sideshowbarker>
I’m looking again at the input type=number WPT tests at https://github.com/web-platform-tests/wpt/blob/f5e542a731d61e302bc8048308963b6806620fb1/html/semantics/forms/the-input-element/number.html#L33C63-L33C72 and now wondering what part of the spec requires that the string value of HTMLInputElement.value must represent a number less than or equal to Number.MAX_VALUE.
02:41
<sideshowbarker>
{value: "2e308", expected: "", testname: "value >= Number.MAX_VALUE"} is the particular case I mean
02:45
<sideshowbarker>

The spec requirement at https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):valid-floating-point-number-4 just says:

If the value of the element is not a valid floating-point number, then set it to the empty string instead.

But it doesn’t seem like a strict implementation of the “valid floating-point number” checking algorithm can on its own determine whether the value represents a number less than or equal to Number.MAX_VALUE.

02:48
<sideshowbarker>
Instead, to pass that WPT test, an implementation needs to actually try to parse the value into a number
02:49
<sideshowbarker>
So I‘m wondering what spec requirement that WPT test is checking conformance for
06:28
<annevk>
Anyone remember why IDL integers go beyond the max safe integer values?
06:47
<annevk>
sideshowbarker: hmm, so what happens if parse and serialize gives a different value from the input, does that end up being invalid? Curious how this is implemented. As a matter of principle I'm not a big fan of grammar checks. They're almost never implemented that way and if they are would largely duplicate an existing parser of sorts.
06:55
<annevk>
Given https://software.hixie.ch/utilities/js/live-dom-viewer/?%3C!DOCTYPE%20html%3E%0A...%3Cinput%20type%3Dnumber%20value%3D0.1234567890123456789012345678901234567890123456789012345678901234567890%3E%0A%3Cscript%3E%0Aw(document.querySelector(%27input%27).validity.valid)%0A%3C%2Fscript%3E I guess I don't know how this works exactly without more exploration and reading the code.
07:09
<sideshowbarker>
sideshowbarker: hmm, so what happens if parse and serialize gives a different value from the input, does that end up being invalid? Curious how this is implemented. As a matter of principle I'm not a big fan of grammar checks. They're almost never implemented that way and if they are would largely duplicate an existing parser of sorts.
I’m also not a fan of grammar checks, and it’s not clear to me why this particular one is even in the spec to begin with
07:10
<sideshowbarker>
And as far as them never getting implemented as spec’d — yeah, I think that’s the case here
07:11
<sideshowbarker>
However, Ladybird has a default policy of implementing spec algorithms as spec’d — so I’m attempting to implement it that way
07:11
<sideshowbarker>
For the sake of comparison, the WebKit implementation looks nothing like the spec
07:11
<sideshowbarker>
lemme get a link
07:13
<sideshowbarker>
https://github.com/WebKit/WebKit/blob/f6fd2039015c4cbd575768f822ac036102dbc79c/Source/WebCore/html/parser/HTMLParserIdioms.cpp#L220-L232
07:14
<sideshowbarker>
    // parseDouble() allows the string to start with a '+' or to end with a '.' but those
    // are not valid floating point numbers as per HTML.
    if (characters.front() == '+' || characters.back() == '.')
        return std::nullopt;
    size_t parsedLength = 0;
    double number = parseDouble(characters, parsedLength);
    return parsedLength == characters.size() && std::isfinite(number) ? number : std::optional<double>();
07:15
<sideshowbarker>
So, in prose terms: it just checks that the string doesn’t start with + or -, and then it actually parses it into number and checks that the length of that number is the same length as the input string — and is the parsed number is finite
07:16
<sideshowbarker>
…and that passes all the WPT tests
07:19
<sideshowbarker>

My implementation for Ladybird looks like this:

bool is_valid_floating_point_number (StringView string)
{
    GenericLexer lexer { string };
    // 1. Optionally, a U+002D HYPHEN-MINUS character (-).
    lexer.consume_specific('-');
    // 2. One or both of the following, in the given order:
    // 2.1. A series of one or more ASCII digits.
    bool has_leading_digits = !lexer.consume_while(is_ascii_digit).is_empty();
    // 2.2. Both of the following, in the given order:
    // 2.2.1. A single U+002E FULL STOP character (.).
    if (lexer.consume_specific('.')) {
        // 2.2.2. A series of one or more ASCII digits.
        if (lexer.consume_while(is_ascii_digit).is_empty())
            return false;
    } else if (!has_leading_digits) {
        // Doesn’t begin with digits, doesn’t begin with a full stop followed by digits.
        return false;
    }
    // 3. Optionally:
    // 3.1. Either a U+0065 LATIN SMALL LETTER E character (e) or a U+0045 LATIN CAPITAL
    //      LETTER E character (E).
    if (lexer.consume_specific('e') || lexer.consume_specific('E')) {
        // 3.2. Optionally, a U+002D HYPHEN-MINUS character (-) or U+002B PLUS SIGN
        //      character (+).
        lexer.consume_specific('-') || lexer.consume_specific('+');
        // 3.3. A series of one or more ASCII digits.
        if (lexer.consume_while(is_ascii_digit).is_empty())
            return false;
    }
    return lexer.tell_remaining() == 0;
}
07:19
<sideshowbarker>
… but that on its own doesn’t pass the WPT tests
07:21
<sideshowbarker>

In order to pass the WPT tests, I need to call that is_valid_floating_point_number function and additionally parse the value:

    } else if (type_state() == HTMLInputElement::TypeAttributeState::Number) {
        // https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number):value-sanitization-algorithm
        // If the value of the element is not a valid floating-point number, then set it
        // to the empty string instead.
        if (!is_valid_floating_point_number(value))
            return String {};
        auto maybe_value = parse_floating_point_number(value);
        // AD-HOC: The spec doesn’t require these checks — but other engines do them, and
        // there’s a WPT case which tests that the value is less than Number.MAX_VALUE.
        if (!maybe_value.has_value() || !isfinite(maybe_value.value()))
            return String {};
07:25
<sideshowbarker>
I hope I’m misunderstanding something — or I have missed something — but as far as I can see, in order to have interop with the behavior in existing engines and with the WPT tests, it’s not sufficient to just strictly implement only the “valid floating-point number” checking algorithm; instead I also need to check that parsing the value returns an actual number rather than an error (for example, because the string value represents a number larger than Number.MAX_VALUE (e.g., 2e308).
07:30
<sideshowbarker>
Anyway, if that is in fact the case, then I guess to get the spec to match the implementation behavior in existing engines, we could add a step 4 to the algorithm, saying “Apply the rules for parsing floating-point number values to the string, and if the result is an error, then the string is not a valid floating-point number”.
12:27
<Domenic>
How would you expose a value larger than Number.MAX_VALUE to JS?
12:28
<Domenic>
I think there is an implicit step here you are skipping over where, when exposing numbers to JS, they have to be exposed as JS numbers... it's probably in Web IDL or something.
12:51
<zcorpan>
https://html.spec.whatwg.org/multipage/common-microsyntaxes.html#rules-for-parsing-floating-point-number-values step 16
15:34
<Gasim Gasimzada>
Hi, I recently created a PR about implementing the spec for console.table. I was told to use types not from the Whatwg infra but use types from Ecmascript. I wanted to ask, are those types the WebIDL ones?
16:45
<annevk>
Gasim Gasimzada: https://github.com/whatwg/console/pull/237#issuecomment-2306200273 is the advice you want to focus on and per zcorpan's comment it seems like the way forward is indeed to use ECMAScript operations on the passed in value
16:46
<Gasim Gasimzada>
I am new to the whatwg spec writing. What does ECMAScript operations mean in this case? Is it the IDLs?
16:48
<annevk>
It means operations defined in the ECMAScript specification. https://html.spec.whatwg.org/multipage/structured-data.html#structuredserializeinternal does this for instance as does https://tc39.es/ecma262/ (the ECMAScript specification)
16:49
<annevk>
It's unfortunate as this is quite hard and there's quite a few gotchas, but given everything that's stated in that thread thus far this seems like the way forward as implementers are unlikely to want to significantly refactor their code.
16:50
<Gasim Gasimzada>
No, it is okay, I just want to know what I need to convert my initial algorithm into :)
16:51
<annevk>
So you want to use operations like: Otherwise, for each key in ! EnumerableOwnProperties(value, key) and Let inputValue be ? value.[[Get]](key, value).
16:51
<annevk>
And you'll have to learn that ! is an assert of sorts that means the operation can't throw and ? means it can.
16:52
<Gasim Gasimzada>
Makes sense. I will try to convert my algorithm code into this and update my PR. Hopefully, I'll get it right :D
16:52
<annevk>
Best of luck! It's an adventure of sorts, but it's also kinda fun in a way. At least I remember not finding it completely miserable when I had to do it.
16:53
<Gasim Gasimzada>
Thanks! It is exciting and fun :)