Repository navigation
chore(alpha): pin Jess 2.0.0-alpha.29 - #4560
Conversation
… goldens use tests-unit/ had two root configs that disagreed. styles.config.ts set mathMode: 'always'; styles.config.cjs carried the options the Less 4.x runner used for `_main/` (relativeUrls, silent, javascriptEnabled). The Jess fixture runner reads the .ts first and test/alpha-fixtures.mjs reads the .cjs first, so the settings covering tests-unit depended on the runner. The goldens settle which settings are right: - calc/calc.css keeps `50vh / 2`, and operations/operations-advanced.css keeps `10px / 2` and `10 / 5`: a division outside parens is not evaluated, which is the default `parens-division` math. Under 'always' both fixtures change. The Less 4.x outputs in legacy/ agree: Less 4.x matches operations-advanced and color-functions/modern-syntax only under parens-division. - urls/urls.css keeps urls from imported files as written. With relativeUrls: true, Less 4.x rewrites eight of its lines. - javascriptEnabled matters only to javascript-REMOVED/legacy, which has its own config, and silent does not change output. - Flat output already comes from the corpus root styles.config.ts. Keep styles.config.cjs, which both runners load in full, set it to mathMode: 'parens-division', and delete styles.config.ts.
test(test-data): keep one tests-unit styles.config, with the math the goldens use
…is() `:is()` takes the specificity of its most specific argument, so grouping extenders of different specificity raises the weaker ones. An extend group now holds only extenders of equal specificity; the others are written as their own selectors: - extend-chaining: `.g` (0,1,0) and `:is(.i, .k).j` (0,2,0) are no longer grouped: `.g.h, :is(.i, .k).j.h`. - extend-nest: `.sidebar, .sidebar2` (0,1,0) split from `.type1 .sidebar3, .type2.sidebar4` (0,2,0). - extend, extend-selector: `.ext1 .ext2` (0,2,0) leaves the `.foo, .ext3, .ext4` (0,1,0) group. extend-nest also writes a leading `&` with its parent in place: `.amp-test-f&` under a multi-compound parent joins `.amp-test-f` to the parent's last compound instead of wrapping the parent in `:is()`. The `&` after `+` still refers to the whole parent and keeps its `:is()`.
…n place
selectors: a compound written before `&` (`.qux&`, `.active&`, `.tst&:hover`)
joins the last compound of the parent selector. `.qux&` under
`.foo .bar, .foo .baz` means `.qux:is(.foo .bar, .foo .baz)`, so it is written
`.foo .bar.qux, .foo .baz.qux`; the old golden put `.qux` on the ancestor
(`.qux.foo .bar`), which matches different elements. Likewise
`.first-level .second-level.active` and
`.foo:not(.only-nested .level2.tst:hover)`.
parse-interpolation: escaped text (`~'.a, .b, .c'`) interpolated into a
selector prints exactly as written rather than being reparsed into an
`:is()` group, so `.q@{classes-quoted}&:hover` gives `.q.a, .b, .c&:hover` and
`@{c-quoted}@{d-quoted}` gives `.a, .b.c, .d`. The header's own comma before
`baz-quoted` is a real selector-list separator, so that branch goes on its own
line like every other nested selector list.
Five kinds of change, all in the expected output only: - Extenders from another imported file: the `.input-group-sm/lg > ...` selectors that extend `.form-control-plaintext.form-control-lg` and `select.form-control-sm/lg:not([size]):not([multiple])` live in a different imported sheet. The golden was generated while those cross-import extenders were being dropped, so it lacked them. - `color-yiq()` text colour: on the `.btn-warning`/`.btn-light` hover and open-dropdown states the darkened background is still light, so the contrasting text colour is `#212529`, not `#fff`. The golden was generated while the darkened colour was read as black. - Nested rules under a multi-branch parent: a child selector without `&` combines with every branch of its parent. The golden kept only the first branch, dropping `.btn-group-toggle > .btn-group > .btn input[...]` and the `.input-group > .custom-select/.custom-file + ...` selectors. They are now written with the parent list in `:is()`. - Native nesting output folds a run of sibling children with equal specificity under one ancestor into `:is()`: `.table th, .table td` becomes `.table :is(th, td)`. The specificity is unchanged because every member is equal. - Extend groups keep specificity: `.btn-sm` (0,1,0) and `.btn-group-sm > .btn` (0,2,0), and each `.bs-tooltip-*`/`.bs-popover-*` pair (0,1,0 vs 0,2,0), are no longer joined in one `:is()`, which would raise the weaker member to the stronger specificity; each is written as its own selector. `&::before` under the two-compound parent `<owner> .arrow` writes the parent in place rather than in a one-item `:is()`.
…g slash loosest calc: parentheses written inside `calc()` are kept exactly as authored, around math and around a lone value alike: `calc(((10vh)) + calc((5vh)))` stays as written, and `calc(100% - (3 * 1))` keeps its parentheses. `calc()` is evaluated by the browser, and the parentheses are part of what the author wrote; the old golden kept only the ones that changed precedence. math/parens-division: under `math: parens-division` a `/` outside parentheses does not divide; it is the separator in `<a> / <b>`, as in `border-radius` or `font`. A separator binds more loosely than arithmetic, so each side is its own expression: `4px * (1 + 1) / @var + 3px` (with `@var: 4`) is `8px / (4 + 3px)`, and a unitless number takes the other operand's unit, so the result is `8px / 7px`. The old golden applied `+ 3px` to the whole slash and printed `8px / 4 + 3px`.
A sheet imported once is skipped on a later import only when that later copy
would land in the same output context, so it would print the same CSS twice.
An import inside `@media` or inside a rule block places the sheet's rules
somewhere else, so it is rendered there too.
- strict-imports: `imported.less` is imported at the root, inside
`@media (max-width: 768px)` and inside `.container`; `.imported` now appears
in all three places. The old golden applied import-once across the whole
document and dropped the two nested copies.
- import: `import-test-f.less` imports `import-test-e` at the root after an
`@import` inside `@media screen` already placed a copy; the root copy's
`body { width: 100%; }` is now in the output.
…s authored - media `and(max-width: 1280px)`, container `size(min-width: 60ch)`: with no space before `(`, `and(` and `size(` tokenize as a single function token (CSS Syntax 3, consume an ident-like token), so the condition is a `<general-enclosed>` function, not `and` or a container name followed by a parenthesized feature. Inserting a space changes what the query means (Media Queries 4, `<general-enclosed>`; CSS Conditional 5, `@container`), so the output keeps the authored bytes. - media `@page Test:first`: a `<page-selector>` allows no whitespace between the page name and its pseudo-page (CSS Paged Media 3), so `Test :first` matches no page. The authored `Test:first` is written as is.
…erty
A custom property's value is an arbitrary token sequence (CSS Custom
Properties 1, `<declaration-value>`), and Less 5 writes a bare `@value` inside
it as literal text, just as CSS would. Only `@{...}` interpolation substitutes
a value there. The fixture means to emit each map entry as a custom property,
so the source now writes `--@{key}: @{value};`. The expected output is
unchanged.
…moves The alpha fixture gate renders each fixture with the pinned Jess release, 2.0.0-alpha.27. The goldens for calc, container, extend, extend-chaining, extend-nest, extend-selector, selectors and strict-imports now record output that release predates, so they are listed as expected render failures, each with what the golden now records. The gate reports any of them that starts passing, so each entry is removed when the pin moves to a release that emits it.
…n-edits test(test-data): update goldens for v5 selector, calc, import-once and condition output
Moves every Jess dependency to 2.0.0-alpha.29 and brings the alpha test expectations in line with it: - 13 expected failures now pass and are removed (the eight goldens waiting on the pin, sourcemaps-url, and four mixed-unit error fixtures that now reject). - functions.css: length() of a ~( … ) list bound to a variable is the list's length (3): ~( … ) passes a list as one argument and is not part of the value. - ampersand-merge-template-invalid.less renders the escaped text as written and is listed as an accepted divergence. - Empty output gets neither a source map nor an annotation, and a source-mapped file ends with its annotation and no trailing newline. - collapseNesting 'native' keeps child branches of different specificity apart; 'compact' folds them into one :is().
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configuration
You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
[Medium impact] The update reaches Less 5 compilation and its test corpus. The PR appears safe to merge, with one non-blocking source-map test improvement.
|
| const { css, map } = await less.render('', { sourceMap: true }); | ||
| assert.equal(map, undefined, 'empty output gets no map'); | ||
| assert.doesNotMatch(css, /sourceMappingURL/, 'empty output gets no annotation'); |
There was a problem hiding this comment.
Empty-output annotations go unchecked
This test uses sourceMap: true without requesting an annotation. That option produces no annotation even for nonempty CSS, so this check cannot catch a regression in the new rule for empty output. Add empty-output cases with sourceMapURL and sourceMapFileInline: true, and assert that neither returns a map nor writes an annotation.
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
Good catch — sourceMap: true alone writes no annotation, so it couldn't catch a regression. Case 6 now also renders empty input with { sourceMapURL: 'empty.css.map' } and { sourceMapFileInline: true } and asserts neither returns a map nor writes an annotation (verified against Jess 2.0.0-alpha.29).
Pins Less 5 to Jess 2.0.0-alpha.29 and brings the alpha tests and test data in line with it.
Pin: every
@jesscss/*dependency inpackages/less/package.jsongoes from 2.0.0-alpha.27 to 2.0.0-alpha.29;pnpm-lock.yamlupdated.Test data that travels with the pin (these encode Jess behaviour newer than alpha.27, so they land together):
:is()grouping, import-once per output context, parent references and escaped selector text written in place, glued condition functions and page selectors, bootstrap4);tests-unitstyles.configwith the math the goldens use;parse-interpolation.lessspells selector captureselector(…), which replaced*[…]in Jess.Expectations updated for alpha.29:
sourcemaps-url, and the four mixed-unit error fixtures that now reject.functions.css:length()of a~( … )list bound to a variable is the list's length (3).~( … )passes a list as one argument; it is not part of the value. (~"1, 2, 3"is still one value.)ampersand-merge-template-invalid.lessnow renders the escaped text as written instead of erroring; listed as an accepted divergence.sourceMappingURLcomment and no trailing newline.collapseNesting: 'native'keeps child branches of different specificity apart (:is(.a, .b) .c, :is(.a, .b) #d);'compact'folds them (:is(.a, .b) :is(.c, #d)).pnpm testpasses locally, including the packed-consumer proof against Jess 2.0.0-alpha.29.