diff --git a/packages/tailwindcss-language-server/package.json b/packages/tailwindcss-language-server/package.json index 3ba3bc37..689e0578 100644 --- a/packages/tailwindcss-language-server/package.json +++ b/packages/tailwindcss-language-server/package.json @@ -20,7 +20,7 @@ "create-notices-file": "node scripts/createNoticesFile.mjs", "prepublishOnly": "pnpm run build", "test": "vitest", - "pretest": "node tests/prepare.js" + "pretest": "node tests/prepare.mjs" }, "bin": { "tailwindcss-language-server": "./bin/tailwindcss-language-server" diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js index cd678845..203174cf 100644 --- a/packages/tailwindcss-language-server/tests/completions/completions.test.js +++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js @@ -310,8 +310,8 @@ withFixture('v4/basic', (c) => { let result = await completion({ lang, text, position, settings }) let textEdit = expect.objectContaining({ range: { start: position, end: position } }) - expect(result.items.length).toBe(12492) - expect(result.items.filter((item) => item.label.endsWith(':')).length).toBe(270) + expect(result.items.length).toBe(12319) + expect(result.items.filter((item) => item.label.endsWith(':')).length).toBe(306) expect(result).toEqual({ isIncomplete: false, items: expect.arrayContaining([ @@ -586,12 +586,24 @@ withFixture('v4/basic', (c) => { expect(resolved).toEqual({ ...item, - detail: - 'font-size: var(--font-size-sm, 0.875rem /* 8.75px */); line-height: var(--tw-leading, var(--font-size-sm--line-height, 1.25rem /* 12.5px */));', + detail: [ + 'font-size: 0.875rem /* 8.75px */;', + 'line-height: calc(1.25 / 0.875);', + 'letter-spacing: undefined;', + 'font-weight: undefined;', + ].join(' '), documentation: { kind: 'markdown', - value: - '```css\n.text-sm {\n font-size: var(--font-size-sm, 0.875rem /* 8.75px */);\n line-height: var(--tw-leading, var(--font-size-sm--line-height, 1.25rem /* 12.5px */));\n}\n```', + value: [ + '```css', + '.text-sm {', + ' font-size: var(--text-sm) /* 0.875rem = 8.75px */;', + ' line-height: var(--tw-leading, var(--text-sm--line-height) /* calc(1.25 / 0.875) ≈ 1.4286 */);', + ' letter-spacing: undefined;', + ' font-weight: undefined;', + '}', + '```', + ].join('\n'), }, }) }) @@ -613,7 +625,7 @@ withFixture('v4/basic', (c) => { expect(resolved).toEqual({ ...item, - detail: 'background-color: var(--color-red-500, oklch(0.637 0.237 25.331));', + detail: 'background-color: oklch(0.637 0.237 25.331);', documentation: '#fb2c36', }) }) @@ -642,19 +654,19 @@ withFixture('v4/workspaces', (c) => { expect(resolved[0]).toEqual({ ...items[0], - detail: 'background-color: var(--color-beet, #8e3b46);', + detail: 'background-color: #8e3b46;', documentation: '#8e3b46', }) expect(resolved[1]).toEqual({ ...items[1], - detail: 'background-color: var(--color-orangepeel, #ff9f00);', + detail: 'background-color: #ff9f00;', documentation: '#ff9f00', }) expect(resolved[2]).toEqual({ ...items[2], - detail: 'background-color: var(--color-style-main, #8e3b46);', + detail: 'background-color: #8e3b46;', documentation: '#8e3b46', }) }) diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package-lock.json index 1beb353d..6ae047ba 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package-lock.json @@ -5,34 +5,35 @@ "packages": { "": { "dependencies": { - "@tailwindcss/oxide": "^4.0.0-alpha.30", - "tailwindcss": "^4.0.0-alpha.30" + "@tailwindcss/oxide": "^4.0.0-beta.6", + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.30.tgz", - "integrity": "sha512-aH+q+sLQvO2t/mxQqhXlgjg+QOpvzzDlXDFVzT4V8jmUtPm3UpkVtUiZDF6AlxP6uyBSTmucnGOkQlIOyDf2+w==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-beta.6.tgz", + "integrity": "sha512-i/Fg/rXYwzV7OJEXbcwjNVkYPgnyfLdYXtduOX7Kvf686xn6jR/k6bhl9fVkQcDb/ujyKzNjD2POAjwhHAC8aw==", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.30", - "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.30", - "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.30", - "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.30", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.30" + "@tailwindcss/oxide-android-arm64": "4.0.0-beta.6", + "@tailwindcss/oxide-darwin-arm64": "4.0.0-beta.6", + "@tailwindcss/oxide-darwin-x64": "4.0.0-beta.6", + "@tailwindcss/oxide-freebsd-x64": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-x64-musl": "4.0.0-beta.6", + "@tailwindcss/oxide-win32-arm64-msvc": "4.0.0-beta.6", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-beta.6" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.30.tgz", - "integrity": "sha512-x28uMkZKYuFCcEZcBrInec5kSRlrd/GdjxA110esxHYtig7C0/cyIlwRI03m4jqS0IlO6eMj4LzLSlj1pgsMpg==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-beta.6.tgz", + "integrity": "sha512-yrUH/IfhkJWSYjF86UxpwrfaO866MjOhVQKG+wCgp0+YZGwirs8vX//a+8Y0SpEJrO0PVgmUU7xbsIM1EQWyTw==", "cpu": [ "arm64" ], @@ -45,9 +46,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.30.tgz", - "integrity": "sha512-MuNVa6+loTi39ET3HxVXonL47az62MX/S9TX4hSIXKOo84nB3hYascqUnB4ZuyQTQSvwzZPgjLc29TufcezxFw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-beta.6.tgz", + "integrity": "sha512-WqFHSD/kocp8rH3KYJow8zTatTEMfdrkZu2KL8nnKfuAEk+juJuUnOQaXDmfsYNQSkGjtnGdcB/fueq4UtUSvw==", "cpu": [ "arm64" ], @@ -60,9 +61,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.30.tgz", - "integrity": "sha512-+kj9hAbzZxq9bvMMNKh8A3FBV6mHS736Y8z4QcBNdZN6+0qBvs2wtACY5oa26E2VZ9ZhKs38NFI2gj1iOhTwjQ==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-beta.6.tgz", + "integrity": "sha512-zFc/TTBkDNLOKl/G9i1JOpg0AgrUOgBcSgURT/E0RsF0ZcKdiIjcyNswNThmjQnj+JAA8QL1Rct+04dH5j7Xjw==", "cpu": [ "x64" ], @@ -75,9 +76,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.30.tgz", - "integrity": "sha512-ThicD5q5uZnHW6sk4eQXDIwkAUhrHz93ELyZ9tB+0vhCim/wDQWRyhmjWDggRJ7yuUi9PDGqcQkY0JPHFDm/WA==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-beta.6.tgz", + "integrity": "sha512-J3+uiPmKTeyefQBy4F0fz5sBQOj9eUTke6W/do/CplM5zXORQVCOKnrY2CPyDpN9bh4TYutldoiI0BP0Yo2ShA==", "cpu": [ "x64" ], @@ -90,9 +91,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.30.tgz", - "integrity": "sha512-tG9MaQQ+wcRjy3EPpDzQu4/EXyE1JayxQHMOlfI23rrm7SmRToo9XAnweSAMdEbOHtaQHEzVPn3hb4rvCSY0Zw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-beta.6.tgz", + "integrity": "sha512-oWAwN6LjX2KH8ej0a/Uc1qnuy0ZSyAwOoJ1Fm2s38ipDmvxC8ARkNfWbYKN/D7dFhY7T3NMV4qjzamFKsrgchQ==", "cpu": [ "arm" ], @@ -105,9 +106,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.30.tgz", - "integrity": "sha512-/hjhV7dnk3iOhGrXA8sOZepG9UXdtc0kYy/jY56qQEk3O7BW97NFHDXdKbf3Devb2/2kq7u7iUsO8iULMxIlKA==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-beta.6.tgz", + "integrity": "sha512-p5jDtF6P3gOPl4eOH0YsN09yx/kXqLbgy4VMnOA9DB6Nlt+RVwM+JDa+RK/GAHL/qkAqO6YBEHeBURbWOeSuBw==", "cpu": [ "arm64" ], @@ -120,9 +121,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.30.tgz", - "integrity": "sha512-ATa4Sp8Q5PUbF3YTMsVOWAKnqGMQsfnpBcYfr6LCEStXl5ZR6cmYdcb6D8GJnWe7dnmiEss/7ou/X3N64Fr/YQ==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-beta.6.tgz", + "integrity": "sha512-ZI92S4LFuXx50gzkv98RXmybbRga183Y3NwBrQ+PfbRUOgDR0/tyT3Zh4CF/0eL9zzxa1mIE7cBbQjXNnejYqQ==", "cpu": [ "arm64" ], @@ -135,9 +136,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.30.tgz", - "integrity": "sha512-DW3FkPQ3qXL+3hV0i01KR7e0klvoJFUOTwdpw1cJnlLIEjHc1C7y5Etbe+t/DRbYf0rgD8bwUW4Iob0PwtPF+A==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-beta.6.tgz", + "integrity": "sha512-F0z48W0Yksrw+xg0GK54wUFa0KmFO9lpbKy2u/2yZtHs+ZwJ55PjdljjW1OJzEHpD81AT+8DT1PhNCkaqpOlqg==", "cpu": [ "x64" ], @@ -150,9 +151,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.30.tgz", - "integrity": "sha512-TEHzeAPrn81IgqSj4qfBONWRS5v0A+tEhK3MdagebNgypZeZYfIogNKEmEZ2hUA31hxpaSnIv8YBV64cj61rqw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-beta.6.tgz", + "integrity": "sha512-GQx5f3qzLuAO7s1NTGY8PDhiEvrRTgYQhGN8HzH1LhP+URSbwgysyHKWFacejWrZS2azr6jlE84usxk8yn/7Xg==", "cpu": [ "x64" ], @@ -164,10 +165,25 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0-beta.6.tgz", + "integrity": "sha512-DUs1A5rVK1Da7XvY2FzVgS+5vinwVDOeXgOsL6dblL8ag70wlwzZjyB3YRbxKRekPynwKdILgIv8/TYE3cv7AQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.30.tgz", - "integrity": "sha512-SmxTfm5Tluqhl9qOETsTM/tSk7LnV03lHMlgVXtHv8BUmqNKx1ZsJe/wnRHq2P0BvlfRrHiqTH/GRM5q9wewRw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-beta.6.tgz", + "integrity": "sha512-VRsHAs3QBZa88N2Bp+LOV1vxr6f82L3KtamLIhyNTYXnEQjJxazaGwVow0VzN9sru2MTvcXjVFwdd9hUbeBKbA==", "cpu": [ "x64" ], @@ -180,9 +196,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package.json index 86537681..941ed66b 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content-split/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30", - "@tailwindcss/oxide": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6", + "@tailwindcss/oxide": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package-lock.json index efc7eb1c..b231b615 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package-lock.json @@ -5,34 +5,35 @@ "packages": { "": { "dependencies": { - "@tailwindcss/oxide": "^4.0.0-alpha.30", - "tailwindcss": "^4.0.0-alpha.30" + "@tailwindcss/oxide": "^4.0.0-beta.6", + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/@tailwindcss/oxide": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-alpha.30.tgz", - "integrity": "sha512-aH+q+sLQvO2t/mxQqhXlgjg+QOpvzzDlXDFVzT4V8jmUtPm3UpkVtUiZDF6AlxP6uyBSTmucnGOkQlIOyDf2+w==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.0.0-beta.6.tgz", + "integrity": "sha512-i/Fg/rXYwzV7OJEXbcwjNVkYPgnyfLdYXtduOX7Kvf686xn6jR/k6bhl9fVkQcDb/ujyKzNjD2POAjwhHAC8aw==", "engines": { "node": ">= 10" }, "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.0.0-alpha.30", - "@tailwindcss/oxide-darwin-arm64": "4.0.0-alpha.30", - "@tailwindcss/oxide-darwin-x64": "4.0.0-alpha.30", - "@tailwindcss/oxide-freebsd-x64": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-alpha.30", - "@tailwindcss/oxide-linux-x64-musl": "4.0.0-alpha.30", - "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-alpha.30" + "@tailwindcss/oxide-android-arm64": "4.0.0-beta.6", + "@tailwindcss/oxide-darwin-arm64": "4.0.0-beta.6", + "@tailwindcss/oxide-darwin-x64": "4.0.0-beta.6", + "@tailwindcss/oxide-freebsd-x64": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm64-gnu": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-arm64-musl": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-x64-gnu": "4.0.0-beta.6", + "@tailwindcss/oxide-linux-x64-musl": "4.0.0-beta.6", + "@tailwindcss/oxide-win32-arm64-msvc": "4.0.0-beta.6", + "@tailwindcss/oxide-win32-x64-msvc": "4.0.0-beta.6" } }, "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-alpha.30.tgz", - "integrity": "sha512-x28uMkZKYuFCcEZcBrInec5kSRlrd/GdjxA110esxHYtig7C0/cyIlwRI03m4jqS0IlO6eMj4LzLSlj1pgsMpg==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.0.0-beta.6.tgz", + "integrity": "sha512-yrUH/IfhkJWSYjF86UxpwrfaO866MjOhVQKG+wCgp0+YZGwirs8vX//a+8Y0SpEJrO0PVgmUU7xbsIM1EQWyTw==", "cpu": [ "arm64" ], @@ -45,9 +46,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-alpha.30.tgz", - "integrity": "sha512-MuNVa6+loTi39ET3HxVXonL47az62MX/S9TX4hSIXKOo84nB3hYascqUnB4ZuyQTQSvwzZPgjLc29TufcezxFw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.0.0-beta.6.tgz", + "integrity": "sha512-WqFHSD/kocp8rH3KYJow8zTatTEMfdrkZu2KL8nnKfuAEk+juJuUnOQaXDmfsYNQSkGjtnGdcB/fueq4UtUSvw==", "cpu": [ "arm64" ], @@ -60,9 +61,9 @@ } }, "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-alpha.30.tgz", - "integrity": "sha512-+kj9hAbzZxq9bvMMNKh8A3FBV6mHS736Y8z4QcBNdZN6+0qBvs2wtACY5oa26E2VZ9ZhKs38NFI2gj1iOhTwjQ==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.0.0-beta.6.tgz", + "integrity": "sha512-zFc/TTBkDNLOKl/G9i1JOpg0AgrUOgBcSgURT/E0RsF0ZcKdiIjcyNswNThmjQnj+JAA8QL1Rct+04dH5j7Xjw==", "cpu": [ "x64" ], @@ -75,9 +76,9 @@ } }, "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-alpha.30.tgz", - "integrity": "sha512-ThicD5q5uZnHW6sk4eQXDIwkAUhrHz93ELyZ9tB+0vhCim/wDQWRyhmjWDggRJ7yuUi9PDGqcQkY0JPHFDm/WA==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.0.0-beta.6.tgz", + "integrity": "sha512-J3+uiPmKTeyefQBy4F0fz5sBQOj9eUTke6W/do/CplM5zXORQVCOKnrY2CPyDpN9bh4TYutldoiI0BP0Yo2ShA==", "cpu": [ "x64" ], @@ -90,9 +91,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-alpha.30.tgz", - "integrity": "sha512-tG9MaQQ+wcRjy3EPpDzQu4/EXyE1JayxQHMOlfI23rrm7SmRToo9XAnweSAMdEbOHtaQHEzVPn3hb4rvCSY0Zw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.0.0-beta.6.tgz", + "integrity": "sha512-oWAwN6LjX2KH8ej0a/Uc1qnuy0ZSyAwOoJ1Fm2s38ipDmvxC8ARkNfWbYKN/D7dFhY7T3NMV4qjzamFKsrgchQ==", "cpu": [ "arm" ], @@ -105,9 +106,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-alpha.30.tgz", - "integrity": "sha512-/hjhV7dnk3iOhGrXA8sOZepG9UXdtc0kYy/jY56qQEk3O7BW97NFHDXdKbf3Devb2/2kq7u7iUsO8iULMxIlKA==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.0.0-beta.6.tgz", + "integrity": "sha512-p5jDtF6P3gOPl4eOH0YsN09yx/kXqLbgy4VMnOA9DB6Nlt+RVwM+JDa+RK/GAHL/qkAqO6YBEHeBURbWOeSuBw==", "cpu": [ "arm64" ], @@ -120,9 +121,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-alpha.30.tgz", - "integrity": "sha512-ATa4Sp8Q5PUbF3YTMsVOWAKnqGMQsfnpBcYfr6LCEStXl5ZR6cmYdcb6D8GJnWe7dnmiEss/7ou/X3N64Fr/YQ==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.0.0-beta.6.tgz", + "integrity": "sha512-ZI92S4LFuXx50gzkv98RXmybbRga183Y3NwBrQ+PfbRUOgDR0/tyT3Zh4CF/0eL9zzxa1mIE7cBbQjXNnejYqQ==", "cpu": [ "arm64" ], @@ -135,9 +136,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-alpha.30.tgz", - "integrity": "sha512-DW3FkPQ3qXL+3hV0i01KR7e0klvoJFUOTwdpw1cJnlLIEjHc1C7y5Etbe+t/DRbYf0rgD8bwUW4Iob0PwtPF+A==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.0.0-beta.6.tgz", + "integrity": "sha512-F0z48W0Yksrw+xg0GK54wUFa0KmFO9lpbKy2u/2yZtHs+ZwJ55PjdljjW1OJzEHpD81AT+8DT1PhNCkaqpOlqg==", "cpu": [ "x64" ], @@ -150,9 +151,9 @@ } }, "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-alpha.30.tgz", - "integrity": "sha512-TEHzeAPrn81IgqSj4qfBONWRS5v0A+tEhK3MdagebNgypZeZYfIogNKEmEZ2hUA31hxpaSnIv8YBV64cj61rqw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.0.0-beta.6.tgz", + "integrity": "sha512-GQx5f3qzLuAO7s1NTGY8PDhiEvrRTgYQhGN8HzH1LhP+URSbwgysyHKWFacejWrZS2azr6jlE84usxk8yn/7Xg==", "cpu": [ "x64" ], @@ -164,10 +165,25 @@ "node": ">= 10" } }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.0.0-beta.6.tgz", + "integrity": "sha512-DUs1A5rVK1Da7XvY2FzVgS+5vinwVDOeXgOsL6dblL8ag70wlwzZjyB3YRbxKRekPynwKdILgIv8/TYE3cv7AQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-alpha.30.tgz", - "integrity": "sha512-SmxTfm5Tluqhl9qOETsTM/tSk7LnV03lHMlgVXtHv8BUmqNKx1ZsJe/wnRHq2P0BvlfRrHiqTH/GRM5q9wewRw==", + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.0.0-beta.6.tgz", + "integrity": "sha512-VRsHAs3QBZa88N2Bp+LOV1vxr6f82L3KtamLIhyNTYXnEQjJxazaGwVow0VzN9sru2MTvcXjVFwdd9hUbeBKbA==", "cpu": [ "x64" ], @@ -180,9 +196,9 @@ } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package.json index 86537681..941ed66b 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/auto-content/package.json @@ -1,6 +1,6 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30", - "@tailwindcss/oxide": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6", + "@tailwindcss/oxide": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package-lock.json index e07c8552..b7cf6cfe 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/basic/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package-lock.json index 99b3ec14..cfc406fd 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/css-loading-js/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package-lock.json index 3b9a0d30..331a30bb 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/custom-source/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package-lock.json index 7dad443a..9dfbf04e 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/dependencies/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package-lock.json index bb5e0a55..f5a1ba18 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/multi-config/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package-lock.json index 3dd65ed8..f1fef50b 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package-lock.json @@ -5,13 +5,13 @@ "packages": { "": { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" } } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package.json index 5e7c8cc9..960bfb88 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/with-prefix/package.json @@ -1,5 +1,5 @@ { "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package-lock.json index 405f63bd..6e7df736 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package-lock.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package-lock.json @@ -8,7 +8,7 @@ "packages/*" ], "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } }, "node_modules/@private/admin": { @@ -32,9 +32,9 @@ "link": true }, "node_modules/tailwindcss": { - "version": "4.0.0-alpha.30", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-alpha.30.tgz", - "integrity": "sha512-e6OsN8n1nRLca2X8ix1QSa+oZA1IYktHw+epLI07+CeQzbLbIDNJieRdbcctM32TAy3vHKvEgdp0rM1WUbpIMQ==" + "version": "4.0.0-beta.6", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.0.0-beta.6.tgz", + "integrity": "sha512-eCCuMk3H65w4J/QWkjxfeWoBSKbCD3E6Uj2LA6Xkkl4eMa1MXuwVpIU1RXcLIp+BVsXGEZMP7i7uJig7KxfAXQ==" }, "packages/admin": { "name": "@private/admin" diff --git a/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package.json b/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package.json index e7afda91..7b2737e9 100644 --- a/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package.json +++ b/packages/tailwindcss-language-server/tests/fixtures/v4/workspaces/package.json @@ -3,6 +3,6 @@ "packages/*" ], "dependencies": { - "tailwindcss": "^4.0.0-alpha.30" + "tailwindcss": "^4.0.0-beta.6" } } diff --git a/packages/tailwindcss-language-server/tests/hover/hover.test.js b/packages/tailwindcss-language-server/tests/hover/hover.test.js index 878fed21..8967ab40 100644 --- a/packages/tailwindcss-language-server/tests/hover/hover.test.js +++ b/packages/tailwindcss-language-server/tests/hover/hover.test.js @@ -194,7 +194,7 @@ withFixture('v4/basic', (c) => { text: '
', position: { line: 0, character: 13 }, expected: - '.bg-red-500 {\n background-color: var(--color-red-500, oklch(0.637 0.237 25.331));\n}', + '.bg-red-500 {\n background-color: var(--color-red-500) /* oklch(0.637 0.237 25.331) = #fb2c36 */;\n}', expectedRange: { start: { line: 0, character: 12 }, end: { line: 0, character: 22 }, diff --git a/packages/tailwindcss-language-server/tests/prepare.js b/packages/tailwindcss-language-server/tests/prepare.js deleted file mode 100644 index 751e3880..00000000 --- a/packages/tailwindcss-language-server/tests/prepare.js +++ /dev/null @@ -1,9 +0,0 @@ -const glob = require('fast-glob') -const path = require('path') -const childProcess = require('child_process') - -const fixtures = glob.sync(['tests/fixtures/*/package.json', 'tests/fixtures/v4/*/package.json']) - -for (let fixture of fixtures) { - childProcess.execSync('npm install', { cwd: path.dirname(fixture) }) -} diff --git a/packages/tailwindcss-language-server/tests/prepare.mjs b/packages/tailwindcss-language-server/tests/prepare.mjs new file mode 100644 index 00000000..19b2c6d5 --- /dev/null +++ b/packages/tailwindcss-language-server/tests/prepare.mjs @@ -0,0 +1,21 @@ +import { exec } from 'node:child_process' +import * as path from 'node:path' +import { fileURLToPath } from 'node:url' +import { promisify } from 'node:util' +import glob from 'fast-glob' + +const __dirname = path.dirname(fileURLToPath(import.meta.url)) + +const fixtures = glob.sync(['tests/fixtures/*/package.json', 'tests/fixtures/v4/*/package.json'], { + cwd: path.resolve(__dirname, '..'), +}) + +const execAsync = promisify(exec) + +await Promise.all( + fixtures.map(async (fixture) => { + console.log(`Installing dependencies for ${fixture}`) + + await execAsync('npm install', { cwd: path.dirname(fixture) }) + }), +) diff --git a/packages/tailwindcss-language-service/src/util/color.ts b/packages/tailwindcss-language-service/src/util/color.ts index 3c59f437..d0427bf9 100644 --- a/packages/tailwindcss-language-service/src/util/color.ts +++ b/packages/tailwindcss-language-service/src/util/color.ts @@ -8,7 +8,7 @@ import * as jit from './jit' import * as culori from 'culori' import namedColors from 'color-name' import postcss from 'postcss' -import { replaceCssVarsWithFallbacks } from './css-vars' +import { replaceCssVarsWithFallbacks } from './rewriting' const COLOR_PROPS = [ 'accent-color', @@ -100,9 +100,9 @@ function getColorFromDecls( const propsToCheck = areAllCustom ? props : nonCustomProps - const colors = propsToCheck.flatMap((prop) => ensureArray(decls[prop]).flatMap((str) => { - return getColorsInString(state, str) - })) + const colors = propsToCheck.flatMap((prop) => + ensureArray(decls[prop]).flatMap((str) => getColorsInString(state, str)), + ) // check that all of the values are valid colors // if (colors.some((color) => color instanceof TinyColor && !color.isValid)) { diff --git a/packages/tailwindcss-language-service/src/util/colorEquivalents.ts b/packages/tailwindcss-language-service/src/util/colorEquivalents.ts index 2cf0ba60..95ab47bc 100644 --- a/packages/tailwindcss-language-service/src/util/colorEquivalents.ts +++ b/packages/tailwindcss-language-service/src/util/colorEquivalents.ts @@ -6,6 +6,16 @@ import type { Comment } from './comments' let allowedFunctions = ['rgb', 'rgba', 'hsl', 'hsla', 'lch', 'lab', 'oklch', 'oklab'] +export function getEquivalentColor(value: string): string { + const color = getColorFromValue(value) + + if (!color) return value + if (typeof color === 'string') return value + if (!inGamut('rgb')(color)) return value + + return formatColor(color) +} + export function equivalentColorValues({ comments }: { comments: Comment[] }): Plugin { return { postcssPlugin: 'plugin', @@ -19,6 +29,10 @@ export function equivalentColorValues({ comments }: { comments: Comment[] }): Pl return true } + if (node.value === 'var') { + return true + } + if (!allowedFunctions.includes(node.value)) { return false } @@ -28,12 +42,11 @@ export function equivalentColorValues({ comments }: { comments: Comment[] }): Pl return false } - const color = getColorFromValue(`${node.value}(${values.join(' ')})`) - if (!inGamut('rgb')(color)) { - return false - } + let color = `${node.value}(${values.join(' ')})` + + let equivalent = getEquivalentColor(color) - if (!color || typeof color === 'string') { + if (equivalent === color) { return false } @@ -42,7 +55,7 @@ export function equivalentColorValues({ comments }: { comments: Comment[] }): Pl decl.source.start.offset + `${decl.prop}${decl.raws.between}`.length + node.sourceEndIndex, - value: formatColor(color), + value: equivalent, }) return false diff --git a/packages/tailwindcss-language-service/src/util/comments.ts b/packages/tailwindcss-language-service/src/util/comments.ts index 1a989643..301ea9fc 100644 --- a/packages/tailwindcss-language-service/src/util/comments.ts +++ b/packages/tailwindcss-language-service/src/util/comments.ts @@ -1,14 +1,14 @@ +import { spliceChangesIntoString } from './splice-changes-into-string' + export type Comment = { index: number; value: string } export function applyComments(str: string, comments: Comment[]): string { - let offset = 0 - - for (let comment of comments) { - let index = comment.index + offset - let commentStr = ` /* ${comment.value} */` - str = str.slice(0, index) + commentStr + str.slice(index) - offset += commentStr.length - } - - return str + return spliceChangesIntoString( + str, + comments.map((c) => ({ + start: c.index, + end: c.index, + replacement: ` /* ${c.value} */`, + })), + ) } diff --git a/packages/tailwindcss-language-service/src/util/css-vars.test.ts b/packages/tailwindcss-language-service/src/util/css-vars.test.ts deleted file mode 100644 index 3b531fd4..00000000 --- a/packages/tailwindcss-language-service/src/util/css-vars.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -import { expect, test } from 'vitest' -import { replaceCssVarsWithFallbacks } from './css-vars' -import { State } from './state' -import { DesignSystem } from './v4' - -test('replacing CSS variables with their fallbacks (when they have them)', () => { - let map = new Map([ - ['--known', 'blue'], - ]) - - let state: State = { - enabled: true, - designSystem: { - resolveThemeValue: (name) => map.get(name) ?? null, - } as DesignSystem, - } - - expect(replaceCssVarsWithFallbacks(state, 'var(--foo, red)')).toBe(' red') - expect(replaceCssVarsWithFallbacks(state, 'var(--foo, )')).toBe(' ') - - expect(replaceCssVarsWithFallbacks(state, 'rgb(var(--foo, 255 0 0))')).toBe('rgb( 255 0 0)') - expect(replaceCssVarsWithFallbacks(state, 'rgb(var(--foo, var(--bar)))')).toBe('rgb( var(--bar))') - - expect( - replaceCssVarsWithFallbacks( - state, - 'rgb(var(var(--bar, var(--baz), var(--qux), var(--thing))))', - ), - ).toBe('rgb(var(var(--bar, var(--baz), var(--qux), var(--thing))))') - - expect( - replaceCssVarsWithFallbacks( - state, - 'rgb(var(--one, var(--bar, var(--baz), var(--qux), var(--thing))))', - ), - ).toBe('rgb( var(--baz), var(--qux), var(--thing))') - - expect( - replaceCssVarsWithFallbacks( - state, - 'color-mix(in srgb, var(--color-primary, oklch(0 0 0 / 2.5)), var(--color-secondary, oklch(0 0 0 / 2.5)), 50%)', - ), - ).toBe('color-mix(in srgb, oklch(0 0 0 / 2.5), oklch(0 0 0 / 2.5), 50%)') - - // Known theme keys are replaced with their values - expect(replaceCssVarsWithFallbacks(state, 'var(--known)')).toBe('blue') - - // Values from the theme take precedence over fallbacks - expect(replaceCssVarsWithFallbacks(state, 'var(--known, red)')).toBe('blue') - - // Unknown theme keys use a fallback if provided - expect(replaceCssVarsWithFallbacks(state, 'var(--unknown, red)')).toBe(' red') - - // Unknown theme keys without fallbacks are not replaced - expect(replaceCssVarsWithFallbacks(state, 'var(--unknown)')).toBe('var(--unknown)') -}) diff --git a/packages/tailwindcss-language-service/src/util/css-vars.ts b/packages/tailwindcss-language-service/src/util/css-vars.ts deleted file mode 100644 index 032153fe..00000000 --- a/packages/tailwindcss-language-service/src/util/css-vars.ts +++ /dev/null @@ -1,70 +0,0 @@ -import type { State } from './state' - -export function replaceCssVarsWithFallbacks(state: State, str: string): string { - return replaceCssVars(str, (name, fallback) => { - // Replace with the value from the design system first. The design system - // take precedences over other sources as that emulates the behavior of a - // browser where the fallback is only used if the variable is defined. - if (state.designSystem && name.startsWith('--')) { - let value = state.designSystem.resolveThemeValue?.(name) ?? null - if (value !== null) return value - } - - if (fallback) { - return fallback - } - - // Don't touch it since there's no suitable replacement - return null - }) -} - -type CssVarReplacer = (name: string, fallback: string | null) => string | null - -function replaceCssVars(str: string, replace: CssVarReplacer): string { - for (let i = 0; i < str.length; ++i) { - if (!str.startsWith('var(', i)) continue - - let depth = 0 - let fallbackStart = null - - for (let j = i + 4; i < str.length; ++j) { - if (str[j] === '(') { - depth++ - } else if (str[j] === ')' && depth > 0) { - depth-- - } else if (str[j] === ',' && depth === 0 && fallbackStart === null) { - fallbackStart = j + 1 - } else if (str[j] === ')' && depth === 0) { - let varName: string - let fallback: string | null - - if (fallbackStart === null) { - varName = str.slice(i + 4, j) - fallback = null - } else { - varName = str.slice(i + 4, fallbackStart - 1) - fallback = str.slice(fallbackStart, j) - } - - let replacement = replace(varName, fallback) - - if (replacement !== null) { - str = str.slice(0, i) + replacement + str.slice(j + 1) - - // We don't want to skip past anything here because `replacement` - // might contain more var(…) calls in which case `i` will already - // be pointing at the right spot to start looking for them - break - } - - // It can't be replaced so we can avoid unncessary work by skipping over - // the entire var(…) call. - i = j + 1 - break - } - } - } - - return str -} diff --git a/packages/tailwindcss-language-service/src/util/jit.ts b/packages/tailwindcss-language-service/src/util/jit.ts index 450cc01a..ca95df7f 100644 --- a/packages/tailwindcss-language-service/src/util/jit.ts +++ b/packages/tailwindcss-language-service/src/util/jit.ts @@ -2,6 +2,7 @@ import type { State } from './state' import type { Container, Document, Root, Rule, Node, AtRule } from 'postcss' import { addPixelEquivalentsToValue } from './pixelEquivalents' import { addEquivalents } from './equivalents' +import { addThemeValues, inlineThemeValues } from './rewriting' export function bigSign(bigIntValue) { // @ts-ignore @@ -44,6 +45,7 @@ export async function stringifyRoot(state: State, root: Root, uri?: string): Pro let css = clone.toString() + css = addThemeValues(css, state, settings.tailwindCSS) css = addEquivalents(css, settings.tailwindCSS) let identSize = state.v4 ? 2 : 4 @@ -67,12 +69,18 @@ export async function stringifyDecls(state: State, rule: Rule, uri?: string): Pr let settings = await state.editor.getConfiguration(uri) let result = [] + rule.walkDecls(({ prop, value }) => { + // In v4 we inline theme values into declarations (this is a no-op in v3) + value = inlineThemeValues(value, state).trim() + if (settings.tailwindCSS.showPixelEquivalents) { value = addPixelEquivalentsToValue(value, settings.tailwindCSS.rootFontSize) } + result.push(`${prop}: ${value};`) }) + return result.join(' ') } diff --git a/packages/tailwindcss-language-service/src/util/pixelEquivalents.ts b/packages/tailwindcss-language-service/src/util/pixelEquivalents.ts index 1901923c..ca5441bc 100644 --- a/packages/tailwindcss-language-service/src/util/pixelEquivalents.ts +++ b/packages/tailwindcss-language-service/src/util/pixelEquivalents.ts @@ -5,7 +5,11 @@ import { isTokenNode } from '@csstools/css-parser-algorithms' import type { Comment } from './comments' import { applyComments } from './comments' -export function addPixelEquivalentsToValue(value: string, rootFontSize: number): string { +export function addPixelEquivalentsToValue( + value: string, + rootFontSize: number, + inComment = true, +): string { if (!value.includes('rem')) { return value } @@ -20,8 +24,15 @@ export function addPixelEquivalentsToValue(value: string, rootFontSize: number): return false } - let commentStr = ` /* ${parseFloat(unit.number) * rootFontSize}px */` - value = value.slice(0, node.sourceEndIndex) + commentStr + value.slice(node.sourceEndIndex) + if (inComment) { + let commentStr = ` /* ${parseFloat(unit.number) * rootFontSize}px */` + value = value.slice(0, node.sourceEndIndex) + commentStr + value.slice(node.sourceEndIndex) + + return false + } + + let commentStr = `${parseFloat(unit.number) * rootFontSize}px` + value = value.slice(0, node.sourceIndex) + commentStr + value.slice(node.sourceEndIndex) return false }) diff --git a/packages/tailwindcss-language-service/src/util/rewriting/add-theme-values.ts b/packages/tailwindcss-language-service/src/util/rewriting/add-theme-values.ts new file mode 100644 index 00000000..6dc10537 --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/add-theme-values.ts @@ -0,0 +1,114 @@ +import type { State, TailwindCssSettings } from '../state' + +import { evaluateExpression } from './calc' +import { replaceCssVars, replaceCssCalc, Range } from './replacements' +import { addPixelEquivalentsToValue } from '../pixelEquivalents' +import { applyComments, Comment } from '../comments' +import { getEquivalentColor } from '../colorEquivalents' + +export function addThemeValues(css: string, state: State, settings: TailwindCssSettings) { + if (!state.designSystem) return css + + let comments: Comment[] = [] + let replaced: Range[] = [] + + css = replaceCssCalc(css, (expr) => { + let inlined = replaceCssVars(expr.value, ({ name }) => { + if (!name.startsWith('--')) return null + + let value = state.designSystem.resolveThemeValue?.(name) ?? null + if (value === null) return null + + // Inline CSS calc expressions in theme values + value = replaceCssCalc(value, (expr) => evaluateExpression(expr.value)) + + return value + }) + + let evaluated = evaluateExpression(inlined) + + // No changes were made so we can just return the original expression + if (expr.value === evaluated) return null + if (!evaluated) return null + + replaced.push(expr.range) + + let px = addPixelEquivalentsToValue(evaluated, settings.rootFontSize, false) + if (px !== evaluated) { + comments.push({ + index: expr.range.end + 1, + value: `${evaluated} = ${px}`, + }) + + return null + } + + let color = getEquivalentColor(evaluated) + if (color !== evaluated) { + comments.push({ + index: expr.range.end + 1, + value: `${evaluated} = ${color}`, + }) + + return null + } + + comments.push({ + index: expr.range.end + 1, + value: evaluated, + }) + + return null + }) + + css = replaceCssVars(css, ({ name, range }) => { + if (!name.startsWith('--')) return null + + for (let r of replaced) { + if (r.start <= range.start && r.end >= range.end) { + return null + } + } + + let value = state.designSystem.resolveThemeValue?.(name) ?? null + if (value === null) return null + + let px = addPixelEquivalentsToValue(value, settings.rootFontSize, false) + if (px !== value) { + comments.push({ + index: range.end + 1, + value: `${value} = ${px}`, + }) + + return null + } + + let color = getEquivalentColor(value) + if (color !== value) { + comments.push({ + index: range.end + 1, + value: `${value} = ${color}`, + }) + + return null + } + + // Inline CSS calc expressions in theme values + value = replaceCssCalc(value, (expr) => { + let evaluated = evaluateExpression(expr.value) + if (!evaluated) return null + if (evaluated === expr.value) return null + + return `calc(${expr.value}) ≈ ${evaluated}` + }) + + comments.push({ + index: range.end + 1, + value, + }) + + return null + }) + + return applyComments(css, comments) +} diff --git a/packages/tailwindcss-language-service/src/util/rewriting/calc.ts b/packages/tailwindcss-language-service/src/util/rewriting/calc.ts new file mode 100644 index 00000000..2420800f --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/calc.ts @@ -0,0 +1,56 @@ +function parseLength(length: string): [number, string] | null { + let regex = /^(-?\d*\.?\d+)([a-z%]*)$/i + let match = length.match(regex) + + if (!match) return null + + let numberPart = parseFloat(match[1]) + if (isNaN(numberPart)) return null + + return [numberPart, match[2]] +} + +function round(n: number, precision: number): number { + return Math.round(n * Math.pow(10, precision)) / Math.pow(10, precision) +} + +export function evaluateExpression(str: string): string | null { + // We're only interested simple calc expressions of the form + // A + B, A - B, A * B, A / B + + let parts = str.split(/\s+([+*/-])\s+/) + + if (parts.length === 1) return null + if (parts.length !== 3) return null + + let a = parseLength(parts[0]) + let b = parseLength(parts[2]) + + // Not parsable + if (!a || !b) { + return null + } + + // Addition and subtraction require the same units + if ((parts[1] === '+' || parts[1] === '-') && a[1] !== b[1]) { + return null + } + + // Multiplication and division require at least one unit to be empty + if ((parts[1] === '*' || parts[1] === '/') && a[1] !== '' && b[1] !== '') { + return null + } + + switch (parts[1]) { + case '+': + return round(a[0] + b[0], 4).toString() + a[1] + case '*': + return round(a[0] * b[0], 4).toString() + a[1] + case '-': + return round(a[0] - b[0], 4).toString() + a[1] + case '/': + return round(a[0] / b[0], 4).toString() + a[1] + } + + return null +} diff --git a/packages/tailwindcss-language-service/src/util/rewriting/index.test.ts b/packages/tailwindcss-language-service/src/util/rewriting/index.test.ts new file mode 100644 index 00000000..67fee890 --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/index.test.ts @@ -0,0 +1,125 @@ +import { expect, test } from 'vitest' +import { + addThemeValues, + evaluateExpression, + replaceCssCalc, + replaceCssVarsWithFallbacks, +} from './index' +import { State, TailwindCssSettings } from '../state' +import { DesignSystem } from '../v4' + +test('replacing CSS variables with their fallbacks (when they have them)', () => { + let map = new Map([['--known', 'blue']]) + + let state: State = { + enabled: true, + designSystem: { + resolveThemeValue: (name) => map.get(name) ?? null, + } as DesignSystem, + } + + expect(replaceCssVarsWithFallbacks(state, 'var(--foo, red)')).toBe(' red') + expect(replaceCssVarsWithFallbacks(state, 'var(--foo, )')).toBe(' ') + + expect(replaceCssVarsWithFallbacks(state, 'rgb(var(--foo, 255 0 0))')).toBe('rgb( 255 0 0)') + expect(replaceCssVarsWithFallbacks(state, 'rgb(var(--foo, var(--bar)))')).toBe('rgb( var(--bar))') + + expect( + replaceCssVarsWithFallbacks( + state, + 'rgb(var(var(--bar, var(--baz), var(--qux), var(--thing))))', + ), + ).toBe('rgb(var( var(--baz), var(--qux), var(--thing)))') + + expect( + replaceCssVarsWithFallbacks( + state, + 'rgb(var(--one, var(--bar, var(--baz), var(--qux), var(--thing))))', + ), + ).toBe('rgb( var(--baz), var(--qux), var(--thing))') + + expect( + replaceCssVarsWithFallbacks( + state, + 'color-mix(in srgb, var(--color-primary, oklch(0 0 0 / 2.5)), var(--color-secondary, oklch(0 0 0 / 2.5)), 50%)', + ), + ).toBe('color-mix(in srgb, oklch(0 0 0 / 2.5), oklch(0 0 0 / 2.5), 50%)') + + // Known theme keys are replaced with their values + expect(replaceCssVarsWithFallbacks(state, 'var(--known)')).toBe('blue') + + // Values from the theme take precedence over fallbacks + expect(replaceCssVarsWithFallbacks(state, 'var(--known, red)')).toBe('blue') + + // Unknown theme keys use a fallback if provided + expect(replaceCssVarsWithFallbacks(state, 'var(--unknown, red)')).toBe(' red') + + // Unknown theme keys without fallbacks are not replaced + expect(replaceCssVarsWithFallbacks(state, 'var(--unknown)')).toBe('var(--unknown)') +}) + +test('Evaluating CSS calc expressions', () => { + expect(replaceCssCalc('calc(1px + 1px)', (node) => evaluateExpression(node.value))).toBe('2px') + expect(replaceCssCalc('calc(1px * 4)', (node) => evaluateExpression(node.value))).toBe('4px') + expect(replaceCssCalc('calc(1px / 4)', (node) => evaluateExpression(node.value))).toBe('0.25px') + expect(replaceCssCalc('calc(1rem + 1px)', (node) => evaluateExpression(node.value))).toBe( + 'calc(1rem + 1px)', + ) + + expect(replaceCssCalc('calc(1.25 / 0.875)', (node) => evaluateExpression(node.value))).toBe( + '1.4286', + ) +}) + +test('Inlining calc expressions using the design system', () => { + let map = new Map([ + ['--spacing', '0.25rem'], + ['--color-red-500', 'oklch(0.637 0.237 25.331)'], + ]) + + let state: State = { + enabled: true, + designSystem: { + resolveThemeValue: (name) => map.get(name) ?? null, + } as DesignSystem, + } + + let settings: TailwindCssSettings = { + rootFontSize: 10, + } as any + + // Inlining calc expressions + // + pixel equivalents + expect(addThemeValues('calc(var(--spacing) * 4)', state, settings)).toBe( + 'calc(var(--spacing) * 4) /* 1rem = 10px */', + ) + + expect(addThemeValues('calc(var(--spacing) / 4)', state, settings)).toBe( + 'calc(var(--spacing) / 4) /* 0.0625rem = 0.625px */', + ) + + expect(addThemeValues('calc(var(--spacing) * 1)', state, settings)).toBe( + 'calc(var(--spacing) * 1) /* 0.25rem = 2.5px */', + ) + + expect(addThemeValues('calc(var(--spacing) * -1)', state, settings)).toBe( + 'calc(var(--spacing) * -1) /* -0.25rem = -2.5px */', + ) + + expect(addThemeValues('calc(var(--spacing) + 1rem)', state, settings)).toBe( + 'calc(var(--spacing) + 1rem) /* 1.25rem = 12.5px */', + ) + + expect(addThemeValues('calc(var(--spacing) - 1rem)', state, settings)).toBe( + 'calc(var(--spacing) - 1rem) /* -0.75rem = -7.5px */', + ) + + expect(addThemeValues('calc(var(--spacing) + 1px)', state, settings)).toBe( + 'calc(var(--spacing) /* 0.25rem = 2.5px */ + 1px)', + ) + + // Color equivalents + expect(addThemeValues('var(--color-red-500)', state, settings)).toBe( + 'var(--color-red-500) /* oklch(0.637 0.237 25.331) = #fb2c36 */', + ) +}) diff --git a/packages/tailwindcss-language-service/src/util/rewriting/index.ts b/packages/tailwindcss-language-service/src/util/rewriting/index.ts new file mode 100644 index 00000000..391449af --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/index.ts @@ -0,0 +1,5 @@ +export * from './replacements' +export * from './var-fallbacks' +export * from './calc' +export * from './add-theme-values' +export * from './inline-theme-values' diff --git a/packages/tailwindcss-language-service/src/util/rewriting/inline-theme-values.ts b/packages/tailwindcss-language-service/src/util/rewriting/inline-theme-values.ts new file mode 100644 index 00000000..a630de46 --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/inline-theme-values.ts @@ -0,0 +1,32 @@ +import type { State, TailwindCssSettings } from '../state' + +import { evaluateExpression } from './calc' +import { replaceCssVars, replaceCssCalc } from './replacements' + +export function inlineThemeValues(css: string, state: State) { + if (!state.designSystem) return css + + css = replaceCssCalc(css, (expr) => { + let inlined = replaceCssVars(expr.value, ({ name, fallback }) => { + if (!name.startsWith('--')) return null + + let value = state.designSystem.resolveThemeValue?.(name) ?? null + if (value === null) return fallback + + return value + }) + + return evaluateExpression(inlined) + }) + + css = replaceCssVars(css, ({ name, fallback }) => { + if (!name.startsWith('--')) return null + + let value = state.designSystem.resolveThemeValue?.(name) ?? null + if (value === null) return fallback + + return value + }) + + return css +} diff --git a/packages/tailwindcss-language-service/src/util/rewriting/replacements.ts b/packages/tailwindcss-language-service/src/util/rewriting/replacements.ts new file mode 100644 index 00000000..dd3d0bb4 --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/replacements.ts @@ -0,0 +1,122 @@ +/** + * A var(…) expression which may have an optional fallback value + */ +export interface CssVariable { + kind: 'css-variable' + range: Range + name: string + fallback: string | null +} + +export interface Range { + /** The zero-based offset where this node starts */ + start: number + + /** The zero-based offset where this node ends */ + end: number +} + +export type CssVarReplacer = (node: CssVariable) => string | null + +/** + * Replace all var expressions in a string using the replacer function + */ +export function replaceCssVars(str: string, replace: CssVarReplacer): string { + for (let i = 0; i < str.length; ++i) { + if (!str.startsWith('var(', i)) continue + + let depth = 0 + let fallbackStart = null + + for (let j = i + 4; i < str.length; ++j) { + if (str[j] === '(') { + depth++ + } else if (str[j] === ')' && depth > 0) { + depth-- + } else if (str[j] === ',' && depth === 0 && fallbackStart === null) { + fallbackStart = j + 1 + } else if (str[j] === ')' && depth === 0) { + let varName: string + let fallback: string | null + + if (fallbackStart === null) { + varName = str.slice(i + 4, j) + fallback = null + } else { + varName = str.slice(i + 4, fallbackStart - 1) + fallback = str.slice(fallbackStart, j) + } + + let replacement = replace({ + kind: 'css-variable', + name: varName, + fallback, + range: { start: i, end: j }, + }) + + if (replacement !== null) { + str = str.slice(0, i) + replacement + str.slice(j + 1) + } + + // We don't want to skip past anything here because `replacement` + // might contain more var(…) calls in which case `i` will already + // be pointing at the right spot to start looking for them + break + } + } + } + + return str +} + +/** + * A calc(…) expression in a CSS value + */ +export interface CalcExpression { + kind: 'calc-expression' + range: Range + value: string +} + +export type CssCalcReplacer = (node: CalcExpression) => string | null + +/** + * Replace all calc expression in a string using the replacer function + */ +export function replaceCssCalc(str: string, replace: CssCalcReplacer): string { + for (let i = 0; i < str.length; ++i) { + if (!str.startsWith('calc(', i)) continue + + let depth = 0 + + for (let j = i + 5; i < str.length; ++j) { + if (str[j] === '(') { + depth++ + } else if (str[j] === ')' && depth > 0) { + depth-- + } else if (str[j] === ')' && depth === 0) { + let expr = str.slice(i + 5, j) + + let replacement = replace({ + kind: 'calc-expression', + value: expr, + range: { + start: i, + end: j, + }, + }) + + if (replacement !== null) { + str = str.slice(0, i) + replacement + str.slice(j + 1) + } + + // We don't want to skip past anything here because `replacement` + // might contain more var(…) calls in which case `i` will already + // be pointing at the right spot to start looking for them + break + } + } + } + + return str +} diff --git a/packages/tailwindcss-language-service/src/util/rewriting/var-fallbacks.ts b/packages/tailwindcss-language-service/src/util/rewriting/var-fallbacks.ts new file mode 100644 index 00000000..0361f6e2 --- /dev/null +++ b/packages/tailwindcss-language-service/src/util/rewriting/var-fallbacks.ts @@ -0,0 +1,21 @@ +import type { State } from '../state' +import { replaceCssVars } from './replacements' + +export function replaceCssVarsWithFallbacks(state: State, str: string): string { + return replaceCssVars(str, ({ name, fallback }) => { + // Replace with the value from the design system first. The design system + // take precedences over other sources as that emulates the behavior of a + // browser where the fallback is only used if the variable is defined. + if (state.designSystem && name.startsWith('--')) { + let value = state.designSystem.resolveThemeValue?.(name) ?? null + if (value !== null) return value + } + + if (fallback) { + return fallback + } + + // Don't touch it since there's no suitable replacement + return null + }) +} diff --git a/packages/vscode-tailwindcss/CHANGELOG.md b/packages/vscode-tailwindcss/CHANGELOG.md index 4c764cd9..793939e1 100644 --- a/packages/vscode-tailwindcss/CHANGELOG.md +++ b/packages/vscode-tailwindcss/CHANGELOG.md @@ -2,7 +2,7 @@ ## Prerelease -- Nothing yet! +- Show theme values in comments in later v4 betas ([#1092](https://github.com/tailwindlabs/tailwindcss-intellisense/pull/1092)) ## 0.12.16