Repository navigation
Math functions Chrome rejects at parse time are invalid CSS and dropped, as in Chrome 145 - #46
Merged
Merged
Conversation
…ne-width> in border, outline and column-rule widths, invalid in number properties (Chrome drops both), unsupported percentage gaps in gaps
…INVALID_VALUE and dropped, as Chrome drops them css/math.ts mathInvalidity ports Blink's CSSMathExpressionNodeParser type checking at 145.0.7632.6 (CSSMathType typed arithmetic, kAddSubtractResult, the math function rules, kMaxExpressionDepth, the consumers' category checks) as one predicate; parseValue returns 'invalid' with its reason and parseMath refuses with the same reason. A 3322-row corpus captured from Chrome (packages/parity/src/cli/math-validity-capture.ts) pins both directions; reject fixtures for a border width and flex-grow; values-reject-number-length now expects DRAGON_CSS_INVALID_VALUE.
…agon/test/math-validity-oracle/ (an ignored *-oracle/ shape for review)
ApprovabilityVerdict: Not approved Macroscope's review found this PR not approvable — This PR adds a substantial Chrome-compatible math-validity parser and wires it into production stylesheet parsing, changing which declarations survive and affect the cascade. Although supported by extensive oracle tests, the breadth and complexity of the runtime behavior warrant focused human review. You can add or adjust custom eligibility rules. Learn more. |
…NS; past it, or on a code point it does not tokenize, it decides nothing tokenize(source, true) returned an unbounded token array, so a calc() of millions of terms was tokenized whole before parseMath's own bound refused it. The bound now holds on both paths (validity returns null past it, and parseMath refuses with the token reason, as before T131); the character check moved into the bounded tokenizer, which in validity mode takes only css-syntax-3 white space.
thejackshelton
added a commit
that referenced
this pull request
Oct 1, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
css/math.tsaddsmathInvalidity, a port of Blink'sCSSMathExpressionNodeParsertype checking at 145.0.7632.6. It covers:CSSMathTypeadd, multiply and Category with percent hints, andkAddSubtractResult;sibling-index()/sibling-count();kMaxExpressionDepth100, unit categories, and the categories each consumer accepts.mathGrammarForpicks number,<line-width>length, length-percentage, or number-or-length-percentage per property.stylesheet.tsparseValuereturns invalid with the reason. Dragon now reportsDRAGON_CSS_INVALID_VALUEand drops the declaration, so an earlier valid declaration wins, as in Chrome.parseMathruns the same predicate first, so the two can't disagree.calc(5% / 5% * 1px). Those stay refused as unsupported, with a message that says so. Before, they all gave a misleading "percentage gaps" reason. The gap reason is unchanged, because the engine lacks percentage gaps and Chrome accepts them.anchor(),anchor-size(),calc-size()andprogress();sqrt()/exp()folding cases.Evidence
CSS.supportsrows (22 properties × 151 values), inpackages/dragon/test/math-validity-oracle/, which.macroscope/ignore.mdignores by the*-oracle/shape. They match in both directions, except 4 values the check doesn't decide.border-left-width: 3pxstays, andflex-grow: 2wins with a 2:1 width split, over the invalid declarations that follow.packages/parity/src/cli/math-validity-capture.ts. It lives in parity because dragon's tests may not launch a browser.Passed (macOS, at 1f5a930, which includes master through #42)
pnpm typecheckpnpm test: 135 files, 2948/2948parity:capture: 306/306 fixtures, including the 2 new reject fixturestw:sweep: snapshot unchanged, with no utility lostlanes.jsonunchanged, so no device run is neededTest changes, with reasons
values-reject-number-lengthnow expectsDRAGON_CSS_INVALID_VALUE, because Chrome rejectscalc(10px + 2).units.test.tscase with 100000 nested parentheses now expects the Chrome depth reason (Blink rejects past depth 100) instead of the token cap.values-reject-invalid-line-width-percentandvalues-reject-invalid-flex-grow-percent.The cascade outcome is proven by a Chrome capture and a unit test, not a layout fixture. An invalid value is an error that blocks every output, so a layout fixture containing one can't compile.
🤖 Generated with Claude Code
Round 1 (fa307d1): the validity check keeps MAX_MATH_TOKENS, so it is bounded and returns undecided past the limit; parseMath refuses with the token reason. The 100000-nested-parens test is back to expecting the token-limit reason (its earlier retarget in this PR only held because of the unbounded tokenizer). pnpm test 2949/2949.
Note
Drop declarations with math functions Chrome rejects at parse time, as in Chrome 145
parseMathand stylesheet value parsing. Declarations with math functions Chrome treats as invalid CSS are now dropped with a Chrome-compatible reason and fix, before Dragon's own support checks run.mathInvalidityand aValidityParserin math.ts that model Blink's math functions, units, argument counts, nesting depth, and typing. Unmodeled or substitution functions are left undecided and fall through to the existing paths.PercentRefusalobject, so line-width (border, outline, column-rule), number, and gap properties each report their own percentage refusal reason and suggested fix.flex-growandborder-left-width, a Chrome capture CLI in math-validity-capture.ts, and a test suite in math-validity.test.ts driven by a captured Chrome oracle.Macroscope summarized fa307d1.