From d8ef1525c10d23d21fb41067571cd03f2cf813fa Mon Sep 17 00:00:00 2001 From: Thierry Bela Nanga Date: Thu, 20 Jun 2024 00:26:43 -0400 Subject: [PATCH] incorrectly expand css nesting rules #38 --- CHANGELOG.md | 4 ++ dist/index-umd-web.js | 5 +- dist/index.cjs | 5 +- dist/lib/ast/expand.js | 3 +- dist/lib/renderer/color/rec2020.js | 2 +- package.json | 2 +- src/lib/ast/expand.ts | 10 ++-- test/specs/code/nesting.js | 81 +++++++++++++++++++++++++++++- tools/shorthand.ts | 1 - 9 files changed, 100 insertions(+), 13 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f5b62d..d8e32c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## V0.5.3 + +- [x] incorrectly expand css nesting rules + ## V0.5.1 - [x] failed to flatten @import when using url() syntax diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index 5977ec7..6420c09 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -1481,7 +1481,7 @@ return val / 4.5; } return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }).concat(a == null || a == 1 ? [] : [a]); + }).concat([] ); } function lrec20202rec2020(r, g, b, a) { // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 @@ -7264,7 +7264,8 @@ for (const t of walkValues(tokens)) { if (t.value.typ == exports.EnumToken.LiteralTokenType) { if (t.value.val == '&') { - t.value.val = replace; + const rule = splitRule(replace); + t.value.val = rule.length > 1 ? ':is(' + replace + ')' : replace; } else if (t.value.val.length > 1 && t.value.val.charAt(0) == '&') { t.value.val = replaceCompoundLiteral(t.value.val, replace); diff --git a/dist/index.cjs b/dist/index.cjs index 74c4c95..73d646f 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1479,7 +1479,7 @@ function rec20202lrec2020(r, g, b, a) { return val / 4.5; } return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }).concat(a == null || a == 1 ? [] : [a]); + }).concat([] ); } function lrec20202rec2020(r, g, b, a) { // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 @@ -7262,7 +7262,8 @@ function replaceCompound(input, replace) { for (const t of walkValues(tokens)) { if (t.value.typ == exports.EnumToken.LiteralTokenType) { if (t.value.val == '&') { - t.value.val = replace; + const rule = splitRule(replace); + t.value.val = rule.length > 1 ? ':is(' + replace + ')' : replace; } else if (t.value.val.length > 1 && t.value.val.charAt(0) == '&') { t.value.val = replaceCompoundLiteral(t.value.val, replace); diff --git a/dist/lib/ast/expand.js b/dist/lib/ast/expand.js index 091b3e0..8be98d9 100644 --- a/dist/lib/ast/expand.js +++ b/dist/lib/ast/expand.js @@ -121,7 +121,8 @@ function replaceCompound(input, replace) { for (const t of walkValues(tokens)) { if (t.value.typ == EnumToken.LiteralTokenType) { if (t.value.val == '&') { - t.value.val = replace; + const rule = splitRule(replace); + t.value.val = rule.length > 1 ? ':is(' + replace + ')' : replace; } else if (t.value.val.length > 1 && t.value.val.charAt(0) == '&') { t.value.val = replaceCompoundLiteral(t.value.val, replace); diff --git a/dist/lib/renderer/color/rec2020.js b/dist/lib/renderer/color/rec2020.js index 5d9f6d1..7087c76 100644 --- a/dist/lib/renderer/color/rec2020.js +++ b/dist/lib/renderer/color/rec2020.js @@ -28,7 +28,7 @@ function rec20202lrec2020(r, g, b, a) { return val / 4.5; } return sign * (Math.pow((abs + α - 1) / α, 1 / 0.45)); - }).concat(a == null || a == 1 ? [] : [a]); + }).concat([] ); } function lrec20202rec2020(r, g, b, a) { // convert an array of linear-light rec2020 RGB in the range 0.0-1.0 diff --git a/package.json b/package.json index 6c37fdf..8bea5e4 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tbela99/css-parser", "description": "CSS parser for node and the browser", - "version": "0.5.2", + "version": "0.5.3", "exports": { ".": "./dist/node/index.js", "./umd": "./dist/index-umd-web.js", diff --git a/src/lib/ast/expand.ts b/src/lib/ast/expand.ts index 64ef2bc..144696a 100644 --- a/src/lib/ast/expand.ts +++ b/src/lib/ast/expand.ts @@ -81,10 +81,10 @@ function expandRule(node: AstRule): Array { if (!rule.sel.includes('&')) { - const selRule = splitRule(rule.sel); + const selRule: string[][] = splitRule(rule.sel); selRule.forEach(arr => combinators.includes(arr[0].charAt(0)) ? arr.unshift(ast.sel) : arr.unshift(ast.sel, ' ')); - rule.sel = selRule.reduce((acc, curr) => { + rule.sel = selRule.reduce((acc: string[], curr: string[]) => { acc.push(curr.join('')); @@ -102,7 +102,7 @@ function expandRule(node: AstRule): Array { let astAtRule: AstAtRule = ast.chi[i]; - const values = >[]; + const values: Array = >[]; if (astAtRule.nam == 'scope') { @@ -171,7 +171,9 @@ export function replaceCompound(input: string, replace: string) { if (t.value.val == '&') { - t.value.val = replace; + const rule = splitRule(replace); + + t.value.val = rule.length > 1 ? ':is(' + replace + ')' : replace; } else if (t.value.val.length > 1 && t.value.val.charAt(0) == '&') { t.value.val = replaceCompoundLiteral(t.value.val, replace); diff --git a/test/specs/code/nesting.js b/test/specs/code/nesting.js index 38852e5..c6c44d0 100644 --- a/test/specs/code/nesting.js +++ b/test/specs/code/nesting.js @@ -333,7 +333,6 @@ export function run(describe, expect, transform, parse, render, dirname, readFil }).then((result) => expect(result.code).equals(`.nav-pills{.nav-link.active,.show>.nav-link{color:var(--bs-nav-pills-link-active-color);background-color:var(--bs-nav-pills-link-active-bg)}}`)); }); - it('merge selectors #16', function () { const file = ` @@ -356,6 +355,86 @@ a { }).then(result => expect(result.code).equals(`a{color:rgb(var(--bs-link-color-rgb) var(--bs-link-opacity,1));text-decoration:underline;:hover,& span{--bs-link-color-rgb:var(--bs-link-hover-color-rgb)}}`)); }); + it('merge selectors #17', function () { + const file = ` +table.colortable { + width: 100%; + text-shadow: none; + border-collapse: collapse; + & td { + text-align: center; + &.c { + text-transform: uppercase; + background: #ff0 + } + } + & th { + text-align: center; + color: green; + font-weight: 400; + padding: 2px 3px + } + & td,& th { + border: 1px solid #d9dadd; + padding: 5px + } +} +.foo { + color: blue; + & { + padding: 2ch; + color: blue; + && { + padding: 2ch + } + } +} +.error,#404 { + &:hover>.baz { + color: red + } +} +`; + return transform(file, { + expandNestingRules: true, + minify: false + }).then(result => expect(result.code).equals(`table.colortable { + width: 100%; + text-shadow: none; + border-collapse: collapse +} +table.colortable td { + text-align: center +} +table.colortable td.c { + text-transform: uppercase; + background: #ff0 +} +table.colortable th { + text-align: center; + color: green; + font-weight: 400; + padding: 2px 3px +} +table.colortable td,table.colortable th { + border: 1px solid #d9dadd; + padding: 5px +} +.foo { + color: blue +} +.foo { + padding: 2ch; + color: blue +} +.foo.foo { + padding: 2ch +} +:is(.error,#404):hover>.baz { + color: red +}`)); + }); + // see https://www.w3.org/TR/css-nesting-1/#conditionals /* .header { diff --git a/tools/shorthand.ts b/tools/shorthand.ts index 784697d..ae344af 100644 --- a/tools/shorthand.ts +++ b/tools/shorthand.ts @@ -13,7 +13,6 @@ function createProperties(data: ShorthandPropertyType) { return { [data.shorthand]: {...data}, ...data.properties.reduce((acc, property: string) => { - return Object.assign(acc, { [property]: { map,