diff --git a/index.ts b/index.ts index eebde46..b22f8b4 100644 --- a/index.ts +++ b/index.ts @@ -16,7 +16,7 @@ import { type Declaration, type Value, type Operator, -} from 'css-tree' +} from '@eslint/css-tree' const SPACE = ' ' const EMPTY_STRING = '' @@ -193,7 +193,10 @@ export function format(css: string, { minify = false, tab_size = undefined }: Fo } case 'Combinator': { // putting spaces around `child.name` (+ > ~ or ' '), unless the combinator is ' ' - buffer += SPACE + // and the combinator is not the first in a nested selectorlist + if (child !== children.first) { + buffer += SPACE + } if (child.name !== ' ') { buffer += child.name + SPACE diff --git a/package-lock.json b/package-lock.json index c235e0a..1a7b635 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,11 +9,10 @@ "version": "2.1.1", "license": "MIT", "dependencies": { - "css-tree": "^3.1.0" + "@eslint/css-tree": "^3.6.6" }, "devDependencies": { "@codecov/vite-plugin": "^1.9.1", - "@types/css-tree": "^2.3.11", "@vitest/coverage-v8": "^4.0.3", "c8": "^10.1.3", "oxlint": "^1.24.0", @@ -603,6 +602,19 @@ "node": ">=18" } }, + "node_modules/@eslint/css-tree": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/@eslint/css-tree/-/css-tree-3.6.6.tgz", + "integrity": "sha512-C3YiJMY9OZyZ/3vEMFWJIesdGaRY6DmIYvmtyxMT934CbrOKqRs+Iw7NWSRlJQEaK4dPYy2lZ2y1zkaj8z0p5A==", + "license": "MIT", + "dependencies": { + "mdn-data": "2.23.0", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/@fastify/busboy": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/@fastify/busboy/-/busboy-2.1.1.tgz", @@ -1636,13 +1648,6 @@ "assertion-error": "^2.0.1" } }, - "node_modules/@types/css-tree": { - "version": "2.3.11", - "resolved": "https://registry.npmjs.org/@types/css-tree/-/css-tree-2.3.11.tgz", - "integrity": "sha512-aEokibJOI77uIlqoBOkVbaQGC9zII0A+JH1kcTNKW2CwyYWD8KM6qdo+4c77wD3wZOQfJuNWAr9M4hdk+YhDIg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/deep-eql": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", @@ -2303,19 +2308,6 @@ "node": ">= 8" } }, - "node_modules/css-tree": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.1.0.tgz", - "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", - "license": "MIT", - "dependencies": { - "mdn-data": "2.12.2", - "source-map-js": "^1.0.1" - }, - "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" - } - }, "node_modules/de-indent": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz", @@ -2848,9 +2840,9 @@ } }, "node_modules/mdn-data": { - "version": "2.12.2", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", - "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", + "version": "2.23.0", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.23.0.tgz", + "integrity": "sha512-786vq1+4079JSeu2XdcDjrhi/Ry7BWtjDl9WtGPWLiIHb2T66GvIVflZTBoSNZ5JqTtJGYEVMuFA/lbQlMOyDQ==", "license": "CC0-1.0" }, "node_modules/minimatch": { diff --git a/package.json b/package.json index 6c61d77..09ad592 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,6 @@ }, "devDependencies": { "@codecov/vite-plugin": "^1.9.1", - "@types/css-tree": "^2.3.11", "@vitest/coverage-v8": "^4.0.3", "c8": "^10.1.3", "oxlint": "^1.24.0", @@ -41,9 +40,6 @@ "vite-plugin-dts": "^4.5.4", "vitest": "^4.0.3" }, - "dependencies": { - "css-tree": "^3.1.0" - }, "files": [ "dist" ], @@ -62,5 +58,8 @@ "useTabs": true, "printWidth": 140, "singleQuote": true + }, + "dependencies": { + "@eslint/css-tree": "^3.6.6" } } diff --git a/test/rules.test.ts b/test/rules.test.ts index 9524a2a..a2260e5 100644 --- a/test/rules.test.ts +++ b/test/rules.test.ts @@ -182,19 +182,21 @@ test('formats unknown stuff in curly braces', () => { expect(actual).toEqual(expected) }) -test('[check broken test] Relaxed nesting: formats nested rules with a selector with a &', () => { +test('Relaxed nesting: formats nested rules with a selector with a &', () => { let actual = format(` selector { a & { color:red } } `) let expected = `selector { - a & { color:red } + a & { + color: red; + } }` expect(actual).toEqual(expected) }) -test.skip('Relaxed nesting: formats nested rules with a selector with a &', () => { +test('Relaxed nesting: formats nested rules with a selector with a &', () => { let actual = format(` selector { a & { color:red } @@ -208,19 +210,21 @@ test.skip('Relaxed nesting: formats nested rules with a selector with a &', () = expect(actual).toEqual(expected) }) -test('[check broken test] Relaxed nesting: formats nested rules with a selector without a &', () => { +test('Relaxed nesting: formats nested rules with a selector without a &', () => { let actual = format(` selector { a { color:red } } `) let expected = `selector { - a { color:red } + a { + color: red; + } }` expect(actual).toEqual(expected) }) -test.skip('Relaxed nesting: formats nested rules with a selector without a &', () => { +test('Relaxed nesting: formats nested rules with a selector without a &', () => { let actual = format(` selector { a { color:red } @@ -234,23 +238,7 @@ test.skip('Relaxed nesting: formats nested rules with a selector without a &', ( expect(actual).toEqual(expected) }) -test('[check broken test] Relaxed nesting: formats nested rules with a selector starting with a selector combinator', () => { - let actual = format(` - selector { - > a { color:red } - ~ a { color:red } - + a { color:red } - } - `) - let expected = `selector { - > a { color:red } - ~ a { color:red } - + a { color:red } -}` - expect(actual).toEqual(expected) -}) - -test.skip('Relaxed nesting: formats nested rules with a selector starting with a selector combinator', () => { +test('Relaxed nesting: formats nested rules with a selector starting with a selector combinator', () => { let actual = format(` selector { > a { color:red } @@ -285,3 +273,26 @@ test('handles syntax errors: premature closed block', () => { let expected = 'a {\n\tmumblejumble: ;\n}' expect(actual).toEqual(expected) }) +test('Relaxed nesting: formats nested rules with a selector starting with a selector combinator and &', () => { + let actual = format(` + selector { + & > a { color:red } + & ~ a { color:red } + & + a { color:red } + } + `) + let expected = `selector { + & > a { + color: red; + } + + & ~ a { + color: red; + } + + & + a { + color: red; + } +}` + expect(actual).toEqual(expected) +}) diff --git a/vite.config.js b/vite.config.js index 54c661d..aa01964 100644 --- a/vite.config.js +++ b/vite.config.js @@ -13,7 +13,7 @@ export default defineConfig({ rollupOptions: { // make sure to externalize deps that shouldn't be bundled // into your library - external: ['css-tree'], + external: ['@eslint/css-tree'], }, }, plugins: [