Home

tailwind-ctp-intellisense @master - refs - log -
-
https://git.jolheiser.com/tailwind-ctp-intellisense.git
Tailwind intellisense + Catppuccin
tree log patch
Add tests
Brad Cornes <hello@bradley.dev>
1 year ago
48 changed files, 7937 additions(+), 15 deletions(-)
M package-lock.json -> package-lock.json
diff --git a/package-lock.json b/package-lock.json
index 61709dc6c9f216cb7f78b950d9ec4409cce7c161..5f7e1239a92927b48d734442b907407af5e1f14c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -61,9 +61,11 @@ 				"tmp-cache": "1.1.0",
 				"tsdx": "0.14.1",
 				"tslib": "2.2.0",
 				"typescript": "4.6.4",
+				"vitest": "0.34.2",
 				"vsce": "2.15.0",
 				"vscode-css-languageservice": "5.4.1",
 				"vscode-emmet-helper-bundled": "0.0.1",
+				"vscode-jsonrpc": "8.1.0",
 				"vscode-languageclient": "8.0.2",
 				"vscode-languageserver": "8.0.2",
 				"vscode-languageserver-textdocument": "1.0.7",
@@ -1920,6 +1922,336 @@ 				"@csstools/css-parser-algorithms": "^2.1.1",
 				"@csstools/css-tokenizer": "^2.1.1"
 			}
 		},
+		"node_modules/@esbuild/android-arm": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+			"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+			"cpu": [
+				"arm"
+			],
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/android-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+			"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+			"cpu": [
+				"arm64"
+			],
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/android-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+			"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"android"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/darwin-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+			"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+			"cpu": [
+				"arm64"
+			],
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/darwin-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+			"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"darwin"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/freebsd-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+			"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+			"cpu": [
+				"arm64"
+			],
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/freebsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+			"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"freebsd"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-arm": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+			"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+			"cpu": [
+				"arm"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+			"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+			"cpu": [
+				"arm64"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-ia32": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+			"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+			"cpu": [
+				"ia32"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-loong64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+			"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+			"cpu": [
+				"loong64"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-mips64el": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+			"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+			"cpu": [
+				"mips64el"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-ppc64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+			"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+			"cpu": [
+				"ppc64"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-riscv64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+			"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+			"cpu": [
+				"riscv64"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-s390x": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+			"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+			"cpu": [
+				"s390x"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/linux-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+			"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"linux"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/netbsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+			"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"netbsd"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/openbsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+			"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"openbsd"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/sunos-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+			"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"sunos"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/win32-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+			"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+			"cpu": [
+				"arm64"
+			],
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/win32-ia32": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+			"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+			"cpu": [
+				"ia32"
+			],
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@esbuild/win32-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+			"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+			"cpu": [
+				"x64"
+			],
+			"optional": true,
+			"os": [
+				"win32"
+			],
+			"engines": {
+				"node": ">=12"
+			}
+		},
 		"node_modules/@evocateur/libnpmaccess": {
 			"version": "3.1.2",
 			"resolved": "https://registry.npmjs.org/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz",
@@ -2400,6 +2732,17 @@ 			"engines": {
 				"node": ">=8"
 			}
 		},
+		"node_modules/@jest/schemas": {
+			"version": "29.6.3",
+			"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+			"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+			"dependencies": {
+				"@sinclair/typebox": "^0.27.8"
+			},
+			"engines": {
+				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+			}
+		},
 		"node_modules/@jest/source-map": {
 			"version": "25.5.0",
 			"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.5.0.tgz",
@@ -2555,6 +2898,17 @@ 			"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
 			"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
 			"engines": {
 				"node": ">=6.0.0"
+			}
+		},
+		"node_modules/@jridgewell/source-map": {
+			"version": "0.3.5",
+			"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
+			"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
+			"optional": true,
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/gen-mapping": "^0.3.0",
+				"@jridgewell/trace-mapping": "^0.3.9"
 			}
 		},
 		"node_modules/@jridgewell/sourcemap-codec": {
@@ -4699,6 +5053,12 @@ 				"rollup": "^1.20.0||^2.0.0"
 			}
 		},
 {
+				"@babel/plugin-syntax-import-attributes": "^7.22.5",
+			"version": "0.27.8",
+			"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+			"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
+		},
+{
 			"resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.2.tgz",
 			"version": "1.8.6",
 			"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
@@ -4809,6 +5169,19 @@ 		"node_modules/@types/braces": {
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz",
 			"integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ=="
+		},
+		"node_modules/@types/chai": {
+			"version": "4.3.5",
+			"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
+			"integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng=="
+		},
+		"node_modules/@types/chai-subset": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz",
+			"integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==",
+			"dependencies": {
+				"@types/chai": "*"
+			}
 		},
 		"node_modules/@types/culori": {
 			"version": "2.0.0",
@@ -5079,6 +5452,172 @@ 				}
 			}
 		},
 {
+				"@babel/plugin-transform-async-generator-functions": "^7.22.10",
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.2.tgz",
+			"integrity": "sha512-EZm2dMNlLyIfDMha17QHSQcg2KjeAZaXd65fpPzXY5bvnfx10Lcaz3N55uEe8PhF+w4pw+hmrlHLLlRn9vkBJg==",
+			"dependencies": {
+				"@vitest/spy": "0.34.2",
+				"@vitest/utils": "0.34.2",
+				"chai": "^4.3.7"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/@vitest/runner": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.2.tgz",
+			"integrity": "sha512-8ydGPACVX5tK3Dl0SUwxfdg02h+togDNeQX3iXVFYgzF5odxvaou7HnquALFZkyVuYskoaHUOqOyOLpOEj5XTA==",
+			"dependencies": {
+				"@vitest/utils": "0.34.2",
+				"p-limit": "^4.0.0",
+				"pathe": "^1.1.1"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/@vitest/runner/node_modules/p-limit": {
+			"version": "4.0.0",
+			"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+			"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+			"dependencies": {
+				"yocto-queue": "^1.0.0"
+			},
+			"engines": {
+				"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@vitest/runner/node_modules/yocto-queue": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+			"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==",
+			"engines": {
+				"node": ">=12.20"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/sindresorhus"
+			}
+		},
+		"node_modules/@vitest/snapshot": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.2.tgz",
+			"integrity": "sha512-qhQ+xy3u4mwwLxltS4Pd4SR+XHv4EajiTPNY3jkIBLUApE6/ce72neJPSUQZ7bL3EBuKI+NhvzhGj3n5baRQUQ==",
+			"dependencies": {
+				"magic-string": "^0.30.1",
+				"pathe": "^1.1.1",
+				"pretty-format": "^29.5.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/@vitest/snapshot/node_modules/ansi-styles": {
+			"version": "5.2.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/@vitest/snapshot/node_modules/magic-string": {
+			"version": "0.30.3",
+			"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
+			"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.4.15"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/@vitest/snapshot/node_modules/pretty-format": {
+			"version": "29.6.3",
+			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+			"integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+			"dependencies": {
+				"@jest/schemas": "^29.6.3",
+				"ansi-styles": "^5.0.0",
+				"react-is": "^18.0.0"
+			},
+			"engines": {
+				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+			}
+		},
+		"node_modules/@vitest/snapshot/node_modules/react-is": {
+			"version": "18.2.0",
+			"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+			"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+		},
+		"node_modules/@vitest/spy": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.2.tgz",
+			"integrity": "sha512-yd4L9OhfH6l0Av7iK3sPb3MykhtcRN5c5K5vm1nTbuN7gYn+yvUVVsyvzpHrjqS7EWqn9WsPJb7+0c3iuY60tA==",
+			"dependencies": {
+				"tinyspy": "^2.1.1"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/@vitest/utils": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.2.tgz",
+			"integrity": "sha512-Lzw+kAsTPubhoQDp1uVAOP6DhNia1GMDsI9jgB0yMn+/nDaPieYQ88lKqz/gGjSHL4zwOItvpehec9OY+rS73w==",
+			"dependencies": {
+				"diff-sequences": "^29.4.3",
+				"loupe": "^2.3.6",
+				"pretty-format": "^29.5.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/@vitest/utils/node_modules/ansi-styles": {
+			"version": "5.2.0",
+			"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+			"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==",
+			"engines": {
+				"node": ">=10"
+			},
+			"funding": {
+				"url": "https://github.com/chalk/ansi-styles?sponsor=1"
+			}
+		},
+		"node_modules/@vitest/utils/node_modules/diff-sequences": {
+			"version": "29.6.3",
+			"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+			"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==",
+			"engines": {
+				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+			}
+		},
+		"node_modules/@vitest/utils/node_modules/pretty-format": {
+			"version": "29.6.3",
+			"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+			"integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+			"dependencies": {
+				"@jest/schemas": "^29.6.3",
+				"ansi-styles": "^5.0.0",
+				"react-is": "^18.0.0"
+			},
+			"engines": {
+				"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
+			}
+		},
+		"node_modules/@vitest/utils/node_modules/react-is": {
+			"version": "18.2.0",
+			"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+			"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+		},
+{
 			"integrity": "sha512-T48kZa6MK1Y6k4b89sexwmSF4YLeZS/Udqg3Jj3jG/cHH+N/sLFCEoXEDMOKugJQ9FxPN1osxIknvKkxt6MKyw==",
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz",
@@ -5533,6 +6072,14 @@ 			"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
 			"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=",
 			"engines": {
 				"node": ">=0.8"
+			}
+		},
+		"node_modules/assertion-error": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+			"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==",
+			"engines": {
+				"node": "*"
 			}
 		},
 		"node_modules/assign-symbols": {
@@ -6251,6 +6798,14 @@ 			"engines": {
 				"node": ">=6.0.0"
 			}
 		},
+		"node_modules/cac": {
+			"version": "6.7.14",
+			"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+			"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==",
+			"engines": {
+				"node": ">=8"
+			}
+		},
 		"node_modules/cacache": {
 			"version": "12.0.4",
 			"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
@@ -6440,6 +6995,23 @@ 			"version": "0.12.0",
 			"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
 			"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
 		},
+		"node_modules/chai": {
+			"version": "4.3.7",
+			"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+			"integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+			"dependencies": {
+				"assertion-error": "^1.1.0",
+				"check-error": "^1.0.2",
+				"deep-eql": "^4.1.2",
+				"get-func-name": "^2.0.0",
+				"loupe": "^2.3.1",
+				"pathval": "^1.1.1",
+				"type-detect": "^4.0.5"
+			},
+			"engines": {
+				"node": ">=4"
+			}
+		},
 		"node_modules/chalk": {
 			"version": "4.1.2",
 			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -6470,6 +7042,14 @@ 		"node_modules/chardet": {
 			"version": "0.7.0",
 			"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
 			"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+		},
+		"node_modules/check-error": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+			"integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA==",
+			"engines": {
+				"node": "*"
+			}
 		},
 		"node_modules/cheerio": {
 			"version": "1.0.0-rc.12",
@@ -7758,6 +8338,17 @@ 			"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
 			"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
 			"dev": true
 		},
+		"node_modules/deep-eql": {
+			"version": "4.1.3",
+			"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+			"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+			"dependencies": {
+				"type-detect": "^4.0.0"
+			},
+			"engines": {
+				"node": ">=6"
+			}
+		},
 		"node_modules/deep-extend": {
 			"version": "0.6.0",
 			"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -10308,6 +10899,14 @@ 			"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
 			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
 			"engines": {
 				"node": "6.* || 8.* || >= 10.*"
+			}
+		},
+		"node_modules/get-func-name": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+			"integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig==",
+			"engines": {
+				"node": "*"
 			}
 		},
 		"node_modules/get-intrinsic": {
@@ -14329,6 +14928,11 @@ 			"engines": {
 				"node": ">=6"
 			}
 		},
+		"node_modules/jsonc-parser": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+			"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
+		},
 		"node_modules/jsonfile": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -14767,6 +15371,17 @@ 			"engines": {
 				"node": ">=6"
 			}
 		},
+		"node_modules/local-pkg": {
+			"version": "0.4.3",
+			"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
+			"integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==",
+			"engines": {
+				"node": ">=14"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/antfu"
+			}
+		},
 		"node_modules/locate-path": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -14991,6 +15606,14 @@ 			"engines": {
 				"node": ">=0.10.0"
 			}
 		},
+		"node_modules/loupe": {
+			"version": "2.3.6",
+			"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+			"integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+			"dependencies": {
+				"get-func-name": "^2.0.0"
+			}
+		},
 		"node_modules/lower-case": {
 			"version": "2.0.2",
 			"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@@ -15498,6 +16121,28 @@ 				"mkdirp": "*"
 			},
 			"engines": {
 				"node": ">=4"
+			}
+		},
+		"node_modules/mlly": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz",
+			"integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==",
+			"dependencies": {
+				"acorn": "^8.9.0",
+				"pathe": "^1.1.1",
+				"pkg-types": "^1.0.3",
+				"ufo": "^1.1.2"
+			}
+		},
+		"node_modules/mlly/node_modules/acorn": {
+			"version": "8.10.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+			"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
 			}
 		},
 		"node_modules/modify-values": {
@@ -16789,6 +17434,19 @@ 			"engines": {
 				"node": ">=4"
 			}
 		},
+		"node_modules/pathe": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
+			"integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q=="
+		},
+		"node_modules/pathval": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+			"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==",
+			"engines": {
+				"node": "*"
+			}
+		},
 		"node_modules/pend": {
 			"version": "1.2.0",
 			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -16910,6 +17568,16 @@ 				"p-limit": "^2.2.0"
 			},
 			"engines": {
 				"node": ">=8"
+			}
+		},
+		"node_modules/pkg-types": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
+			"integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+			"dependencies": {
+				"jsonc-parser": "^3.2.0",
+				"mlly": "^1.2.0",
+				"pathe": "^1.1.0"
 			}
 		},
 		"node_modules/pkg-up": {
@@ -18882,6 +19550,11 @@ 			"version": "0.0.2",
 			"resolved": "https://registry.npmjs.org/sift-string/-/sift-string-0.0.2.tgz",
 			"integrity": "sha512-cOWdhRSgl6neRIgTCLdqsKgQQGnkF92+PzVKpRJEnVVZvFs/mLipRanroOO+2Lp6Kv4vWk/3wMnRylTne0jksQ=="
 		},
+		"node_modules/siginfo": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+			"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="
+		},
 		"node_modules/signal-exit": {
 			"version": "3.0.3",
 			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@@ -19459,6 +20132,11 @@ 			"engines": {
 				"node": ">=8"
 			}
 		},
+		"node_modules/stackback": {
+			"version": "0.0.2",
+			"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+			"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="
+		},
 		"node_modules/static-extend": {
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@@ -19546,6 +20224,11 @@ 			"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
 			"engines": {
 				"node": ">=0.10.0"
 			}
+		},
+		"node_modules/std-env": {
+			"version": "3.4.2",
+			"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.2.tgz",
+			"integrity": "sha512-Cw6eJDX9AxEEL0g5pYj8Zx9KXtDf60rxwS2ze0HBanS0aKhj1sBlzcsmg+R0qYy8byFa854/yR2X5ZmBSClVmg=="
 		},
 		"node_modules/stealthy-require": {
 			"version": "1.1.1",
@@ -19781,6 +20464,28 @@ 			"funding": {
 				"url": "https://github.com/sponsors/sindresorhus"
 			}
 		},
+		"node_modules/strip-literal": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
+			"integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==",
+			"dependencies": {
+				"acorn": "^8.10.0"
+			},
+			"funding": {
+				"url": "https://github.com/sponsors/antfu"
+			}
+		},
+		"node_modules/strip-literal/node_modules/acorn": {
+			"version": "8.10.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+			"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
 		"node_modules/strong-log-transformer": {
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz",
@@ -20433,6 +21138,27 @@ 				"globalyzer": "0.1.0",
 				"globrex": "^0.1.2"
 			}
 		},
+		"node_modules/tinybench": {
+			"version": "2.5.0",
+			"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz",
+			"integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA=="
+		},
+		"node_modules/tinypool": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
+			"integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww==",
+			"engines": {
+				"node": ">=14.0.0"
+			}
+		},
+		"node_modules/tinyspy": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz",
+			"integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w==",
+			"engines": {
+				"node": ">=14.0.0"
+			}
+		},
 		"node_modules/tmp": {
 			"version": "0.0.33",
 			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -20999,6 +21725,11 @@ 			"version": "1.0.6",
 			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
 			"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
 		},
+		"node_modules/ufo": {
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz",
+			"integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg=="
+		},
 		"node_modules/uglify-js": {
 			"version": "3.13.8",
 			"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.8.tgz",
@@ -21351,6 +22082,521 @@ 				"core-util-is": "1.0.2",
 				"extsprintf": "^1.2.0"
 			}
 		},
+		"node_modules/vite-node": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.2.tgz",
+			"integrity": "sha512-JtW249Zm3FB+F7pQfH56uWSdlltCo1IOkZW5oHBzeQo0iX4jtC7o1t9aILMGd9kVekXBP2lfJBEQt9rBh07ebA==",
+			"dependencies": {
+				"cac": "^6.7.14",
+				"debug": "^4.3.4",
+				"mlly": "^1.4.0",
+				"pathe": "^1.1.1",
+				"picocolors": "^1.0.0",
+				"vite": "^3.0.0 || ^4.0.0"
+			},
+			"bin": {
+				"vite-node": "vite-node.mjs"
+			},
+			"engines": {
+				"node": ">=v14.18.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			}
+		},
+		"node_modules/vite-node/node_modules/acorn": {
+			"version": "8.10.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+			"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+			"optional": true,
+			"peer": true,
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/vite-node/node_modules/commander": {
+			"version": "2.20.3",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"optional": true,
+			"peer": true
+		},
+		"node_modules/vite-node/node_modules/debug": {
+			"version": "4.3.4",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+			"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/vite-node/node_modules/esbuild": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+			"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+			"hasInstallScript": true,
+			"bin": {
+				"esbuild": "bin/esbuild"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"optionalDependencies": {
+				"@esbuild/android-arm": "0.18.20",
+				"@esbuild/android-arm64": "0.18.20",
+				"@esbuild/android-x64": "0.18.20",
+				"@esbuild/darwin-arm64": "0.18.20",
+				"@esbuild/darwin-x64": "0.18.20",
+				"@esbuild/freebsd-arm64": "0.18.20",
+				"@esbuild/freebsd-x64": "0.18.20",
+				"@esbuild/linux-arm": "0.18.20",
+				"@esbuild/linux-arm64": "0.18.20",
+				"@esbuild/linux-ia32": "0.18.20",
+				"@esbuild/linux-loong64": "0.18.20",
+				"@esbuild/linux-mips64el": "0.18.20",
+				"@esbuild/linux-ppc64": "0.18.20",
+				"@esbuild/linux-riscv64": "0.18.20",
+				"@esbuild/linux-s390x": "0.18.20",
+				"@esbuild/linux-x64": "0.18.20",
+				"@esbuild/netbsd-x64": "0.18.20",
+				"@esbuild/openbsd-x64": "0.18.20",
+				"@esbuild/sunos-x64": "0.18.20",
+				"@esbuild/win32-arm64": "0.18.20",
+				"@esbuild/win32-ia32": "0.18.20",
+				"@esbuild/win32-x64": "0.18.20"
+			}
+		},
+		"node_modules/vite-node/node_modules/picocolors": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+		},
+		"node_modules/vite-node/node_modules/postcss": {
+			"version": "8.4.28",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+			"integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/postcss/"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/postcss"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"dependencies": {
+				"nanoid": "^3.3.6",
+				"picocolors": "^1.0.0",
+				"source-map-js": "^1.0.2"
+			},
+			"engines": {
+				"node": "^10 || ^12 || >=14"
+			}
+		},
+		"node_modules/vite-node/node_modules/rollup": {
+			"version": "3.28.1",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
+			"integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==",
+			"bin": {
+				"rollup": "dist/bin/rollup"
+			},
+			"engines": {
+				"node": ">=14.18.0",
+				"npm": ">=8.0.0"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.2"
+			}
+		},
+		"node_modules/vite-node/node_modules/source-map-js": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+			"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/vite-node/node_modules/terser": {
+			"version": "5.19.2",
+			"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
+			"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
+			"optional": true,
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/source-map": "^0.3.3",
+				"acorn": "^8.8.2",
+				"commander": "^2.20.0",
+				"source-map-support": "~0.5.20"
+			},
+			"bin": {
+				"terser": "bin/terser"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/vite-node/node_modules/vite": {
+			"version": "4.4.9",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
+			"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
+			"dependencies": {
+				"esbuild": "^0.18.10",
+				"postcss": "^8.4.27",
+				"rollup": "^3.27.1"
+			},
+			"bin": {
+				"vite": "bin/vite.js"
+			},
+			"engines": {
+				"node": "^14.18.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/vitejs/vite?sponsor=1"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.2"
+			},
+			"peerDependencies": {
+				"@types/node": ">= 14",
+				"less": "*",
+				"lightningcss": "^1.21.0",
+				"sass": "*",
+				"stylus": "*",
+				"sugarss": "*",
+				"terser": "^5.4.0"
+			},
+			"peerDependenciesMeta": {
+				"@types/node": {
+					"optional": true
+				},
+				"less": {
+					"optional": true
+				},
+				"lightningcss": {
+					"optional": true
+				},
+				"sass": {
+					"optional": true
+				},
+				"stylus": {
+					"optional": true
+				},
+				"sugarss": {
+					"optional": true
+				},
+				"terser": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/vitest": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.2.tgz",
+			"integrity": "sha512-WgaIvBbjsSYMq/oiMlXUI7KflELmzM43BEvkdC/8b5CAod4ryAiY2z8uR6Crbi5Pjnu5oOmhKa9sy7uk6paBxQ==",
+			"dependencies": {
+				"@types/chai": "^4.3.5",
+				"@types/chai-subset": "^1.3.3",
+				"@types/node": "*",
+				"@vitest/expect": "0.34.2",
+				"@vitest/runner": "0.34.2",
+				"@vitest/snapshot": "0.34.2",
+				"@vitest/spy": "0.34.2",
+				"@vitest/utils": "0.34.2",
+				"acorn": "^8.9.0",
+				"acorn-walk": "^8.2.0",
+				"cac": "^6.7.14",
+				"chai": "^4.3.7",
+				"debug": "^4.3.4",
+				"local-pkg": "^0.4.3",
+				"magic-string": "^0.30.1",
+				"pathe": "^1.1.1",
+				"picocolors": "^1.0.0",
+				"std-env": "^3.3.3",
+				"strip-literal": "^1.0.1",
+				"tinybench": "^2.5.0",
+				"tinypool": "^0.7.0",
+				"vite": "^3.0.0 || ^4.0.0",
+				"vite-node": "0.34.2",
+				"why-is-node-running": "^2.2.2"
+			},
+			"bin": {
+				"vitest": "vitest.mjs"
+			},
+			"engines": {
+				"node": ">=v14.18.0"
+			},
+			"funding": {
+				"url": "https://opencollective.com/vitest"
+			},
+			"peerDependencies": {
+				"@edge-runtime/vm": "*",
+				"@vitest/browser": "*",
+				"@vitest/ui": "*",
+				"happy-dom": "*",
+				"jsdom": "*",
+				"playwright": "*",
+				"safaridriver": "*",
+				"webdriverio": "*"
+			},
+			"peerDependenciesMeta": {
+				"@edge-runtime/vm": {
+					"optional": true
+				},
+				"@vitest/browser": {
+					"optional": true
+				},
+				"@vitest/ui": {
+					"optional": true
+				},
+				"happy-dom": {
+					"optional": true
+				},
+				"jsdom": {
+					"optional": true
+				},
+				"playwright": {
+					"optional": true
+				},
+				"safaridriver": {
+					"optional": true
+				},
+				"webdriverio": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/vitest/node_modules/acorn": {
+			"version": "8.10.0",
+			"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+			"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+			"bin": {
+				"acorn": "bin/acorn"
+			},
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/vitest/node_modules/acorn-walk": {
+			"version": "8.2.0",
+			"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+			"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==",
+			"engines": {
+				"node": ">=0.4.0"
+			}
+		},
+		"node_modules/vitest/node_modules/commander": {
+			"version": "2.20.3",
+			"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+			"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+			"optional": true,
+			"peer": true
+		},
+		"node_modules/vitest/node_modules/debug": {
+			"version": "4.3.4",
+			"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+			"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+			"dependencies": {
+				"ms": "2.1.2"
+			},
+			"engines": {
+				"node": ">=6.0"
+			},
+			"peerDependenciesMeta": {
+				"supports-color": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/vitest/node_modules/esbuild": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+			"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+			"hasInstallScript": true,
+			"bin": {
+				"esbuild": "bin/esbuild"
+			},
+			"engines": {
+				"node": ">=12"
+			},
+			"optionalDependencies": {
+				"@esbuild/android-arm": "0.18.20",
+				"@esbuild/android-arm64": "0.18.20",
+				"@esbuild/android-x64": "0.18.20",
+				"@esbuild/darwin-arm64": "0.18.20",
+				"@esbuild/darwin-x64": "0.18.20",
+				"@esbuild/freebsd-arm64": "0.18.20",
+				"@esbuild/freebsd-x64": "0.18.20",
+				"@esbuild/linux-arm": "0.18.20",
+				"@esbuild/linux-arm64": "0.18.20",
+				"@esbuild/linux-ia32": "0.18.20",
+				"@esbuild/linux-loong64": "0.18.20",
+				"@esbuild/linux-mips64el": "0.18.20",
+				"@esbuild/linux-ppc64": "0.18.20",
+				"@esbuild/linux-riscv64": "0.18.20",
+				"@esbuild/linux-s390x": "0.18.20",
+				"@esbuild/linux-x64": "0.18.20",
+				"@esbuild/netbsd-x64": "0.18.20",
+				"@esbuild/openbsd-x64": "0.18.20",
+				"@esbuild/sunos-x64": "0.18.20",
+				"@esbuild/win32-arm64": "0.18.20",
+				"@esbuild/win32-ia32": "0.18.20",
+				"@esbuild/win32-x64": "0.18.20"
+			}
+		},
+		"node_modules/vitest/node_modules/magic-string": {
+			"version": "0.30.3",
+			"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
+			"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
+			"dependencies": {
+				"@jridgewell/sourcemap-codec": "^1.4.15"
+			},
+			"engines": {
+				"node": ">=12"
+			}
+		},
+		"node_modules/vitest/node_modules/picocolors": {
+			"version": "1.0.0",
+			"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+			"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+		},
+		"node_modules/vitest/node_modules/postcss": {
+			"version": "8.4.28",
+			"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+			"integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+			"funding": [
+				{
+					"type": "opencollective",
+					"url": "https://opencollective.com/postcss/"
+				},
+				{
+					"type": "tidelift",
+					"url": "https://tidelift.com/funding/github/npm/postcss"
+				},
+				{
+					"type": "github",
+					"url": "https://github.com/sponsors/ai"
+				}
+			],
+			"dependencies": {
+				"nanoid": "^3.3.6",
+				"picocolors": "^1.0.0",
+				"source-map-js": "^1.0.2"
+			},
+			"engines": {
+				"node": "^10 || ^12 || >=14"
+			}
+		},
+		"node_modules/vitest/node_modules/rollup": {
+			"version": "3.28.1",
+			"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
+			"integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==",
+			"bin": {
+				"rollup": "dist/bin/rollup"
+			},
+			"engines": {
+				"node": ">=14.18.0",
+				"npm": ">=8.0.0"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.2"
+			}
+		},
+		"node_modules/vitest/node_modules/source-map-js": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+			"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+			"engines": {
+				"node": ">=0.10.0"
+			}
+		},
+		"node_modules/vitest/node_modules/terser": {
+			"version": "5.19.2",
+			"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
+			"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
+			"optional": true,
+			"peer": true,
+			"dependencies": {
+				"@jridgewell/source-map": "^0.3.3",
+				"acorn": "^8.8.2",
+				"commander": "^2.20.0",
+				"source-map-support": "~0.5.20"
+			},
+			"bin": {
+				"terser": "bin/terser"
+			},
+			"engines": {
+				"node": ">=10"
+			}
+		},
+		"node_modules/vitest/node_modules/vite": {
+			"version": "4.4.9",
+			"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
+			"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
+			"dependencies": {
+				"esbuild": "^0.18.10",
+				"postcss": "^8.4.27",
+				"rollup": "^3.27.1"
+			},
+			"bin": {
+				"vite": "bin/vite.js"
+			},
+			"engines": {
+				"node": "^14.18.0 || >=16.0.0"
+			},
+			"funding": {
+				"url": "https://github.com/vitejs/vite?sponsor=1"
+			},
+			"optionalDependencies": {
+				"fsevents": "~2.3.2"
+			},
+			"peerDependencies": {
+				"@types/node": ">= 14",
+				"less": "*",
+				"lightningcss": "^1.21.0",
+				"sass": "*",
+				"stylus": "*",
+				"sugarss": "*",
+				"terser": "^5.4.0"
+			},
+			"peerDependenciesMeta": {
+				"@types/node": {
+					"optional": true
+				},
+				"less": {
+					"optional": true
+				},
+				"lightningcss": {
+					"optional": true
+				},
+				"sass": {
+					"optional": true
+				},
+				"stylus": {
+					"optional": true
+				},
+				"sugarss": {
+					"optional": true
+				},
+				"terser": {
+					"optional": true
+				}
+			}
+		},
 		"node_modules/vsce": {
 			"version": "2.15.0",
 			"resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz",
@@ -21537,13 +22783,13 @@ 			"resolved": "https://registry.npmjs.org/vscode-emmet-helper-bundled/-/vscode-emmet-helper-bundled-0.0.1.tgz",
 			"integrity": "sha512-EhZ0Wt8MbdrKF3NUMfaUDhFPTdRnl1tyqYS7KOcNtsSNTV285IV+XPDtNQyw5rwYsULEfb6n+fK1DRufJQlPYw=="
 		},
 		"node_modules/vscode-jsonrpc": {
-	"requires": true,
 	"lockfileVersion": 2,
+			"engines": {
 	"name": "root",
-			"name": "root",
+			"version": "1.9.3",
 	"packages": {
-				"latest-semver": "^4.0.0",
+				"@csstools/css-parser-algorithms": "2.1.1",
-			"integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
+			"integrity": "sha512-6TDy/abTQk+zDGYazgbIPc+4JoXdwC8NHU9Pbn4UJP1fehUyZmM4RHp5IthX7A6L5KS30PRui+j+tbbMMMafdw==",
 			"engines": {
 				"node": ">=14.0.0"
 			}
@@ -21600,6 +22847,14 @@ 				"vscode-jsonrpc": "8.0.2",
 				"vscode-languageserver-types": "3.17.2"
 			}
 		},
+		"node_modules/vscode-languageserver-protocol/node_modules/vscode-jsonrpc": {
+			"version": "8.0.2",
+			"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
+			"integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==",
+			"engines": {
+				"node": ">=14.0.0"
+			}
+		},
 		"node_modules/vscode-languageserver-protocol/node_modules/vscode-languageserver-types": {
 			"version": "3.17.2",
 			"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
@@ -21779,6 +23034,21 @@ 				"node": ">= 0.4"
 			},
 			"funding": {
 				"url": "https://github.com/sponsors/ljharb"
+			}
+		},
+		"node_modules/why-is-node-running": {
+			"version": "2.2.2",
+			"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
+			"integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+			"dependencies": {
+				"siginfo": "^2.0.0",
+				"stackback": "0.0.2"
+			},
+			"bin": {
+				"why-is-node-running": "cli.js"
+			},
+			"engines": {
+				"node": ">=8"
 			}
 		},
 		"node_modules/wide-align": {
@@ -23494,6 +24764,138 @@ 			"resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.0.4.tgz",
 			"integrity": "sha512-GyYot6jHgcSDZZ+tLSnrzkR7aJhF2ZW6d+CXH66mjy5WpAQhZD4HDke2OQ36SivGRWlZJpAz7TzbW6OKlEpxAA==",
 			"requires": {}
 		},
+		"@esbuild/android-arm": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.18.20.tgz",
+			"integrity": "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==",
+			"optional": true
+		},
+		"@esbuild/android-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz",
+			"integrity": "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==",
+			"optional": true
+		},
+		"@esbuild/android-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.18.20.tgz",
+			"integrity": "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==",
+			"optional": true
+		},
+		"@esbuild/darwin-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz",
+			"integrity": "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==",
+			"optional": true
+		},
+		"@esbuild/darwin-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz",
+			"integrity": "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==",
+			"optional": true
+		},
+		"@esbuild/freebsd-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz",
+			"integrity": "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==",
+			"optional": true
+		},
+		"@esbuild/freebsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz",
+			"integrity": "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==",
+			"optional": true
+		},
+		"@esbuild/linux-arm": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz",
+			"integrity": "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==",
+			"optional": true
+		},
+		"@esbuild/linux-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz",
+			"integrity": "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==",
+			"optional": true
+		},
+		"@esbuild/linux-ia32": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz",
+			"integrity": "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==",
+			"optional": true
+		},
+		"@esbuild/linux-loong64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz",
+			"integrity": "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==",
+			"optional": true
+		},
+		"@esbuild/linux-mips64el": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz",
+			"integrity": "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==",
+			"optional": true
+		},
+		"@esbuild/linux-ppc64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz",
+			"integrity": "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==",
+			"optional": true
+		},
+		"@esbuild/linux-riscv64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz",
+			"integrity": "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==",
+			"optional": true
+		},
+		"@esbuild/linux-s390x": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz",
+			"integrity": "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==",
+			"optional": true
+		},
+		"@esbuild/linux-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz",
+			"integrity": "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==",
+			"optional": true
+		},
+		"@esbuild/netbsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz",
+			"integrity": "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==",
+			"optional": true
+		},
+		"@esbuild/openbsd-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz",
+			"integrity": "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==",
+			"optional": true
+		},
+		"@esbuild/sunos-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz",
+			"integrity": "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==",
+			"optional": true
+		},
+		"@esbuild/win32-arm64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz",
+			"integrity": "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==",
+			"optional": true
+		},
+		"@esbuild/win32-ia32": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz",
+			"integrity": "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==",
+			"optional": true
+		},
+		"@esbuild/win32-x64": {
+			"version": "0.18.20",
+			"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz",
+			"integrity": "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==",
+			"optional": true
+		},
 		"@evocateur/libnpmaccess": {
 			"version": "3.1.2",
 			"resolved": "https://registry.npmjs.org/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz",
@@ -23888,6 +25290,14 @@ 					}
 				}
 			}
 		},
+		"@jest/schemas": {
+			"version": "29.6.3",
+			"resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz",
+			"integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==",
+			"requires": {
+				"@sinclair/typebox": "^0.27.8"
+			}
+		},
 		"@jest/source-map": {
 			"version": "25.5.0",
 			"resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-25.5.0.tgz",
@@ -24012,6 +25422,17 @@ 		"@jridgewell/set-array": {
 			"version": "1.1.2",
 			"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
 			"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
+		},
+		"@jridgewell/source-map": {
+			"version": "0.3.5",
+			"resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz",
+			"integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==",
+			"optional": true,
+			"peer": true,
+			"requires": {
+				"@jridgewell/gen-mapping": "^0.3.0",
+				"@jridgewell/trace-mapping": "^0.3.9"
+			}
 		},
 		"@jridgewell/sourcemap-codec": {
 			"version": "1.4.15",
@@ -25807,6 +27228,11 @@ 				"estree-walker": "^1.0.1",
 				"picomatch": "^2.2.2"
 			}
 		},
+		"@sinclair/typebox": {
+			"version": "0.27.8",
+			"resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz",
+			"integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA=="
+		},
 		"@sinonjs/commons": {
 			"version": "1.8.6",
 			"resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.6.tgz",
@@ -25904,6 +27330,19 @@ 		"@types/braces": {
 			"version": "3.0.1",
 			"resolved": "https://registry.npmjs.org/@types/braces/-/braces-3.0.1.tgz",
 			"integrity": "sha512-+euflG6ygo4bn0JHtn4pYqcXwRtLvElQ7/nnjDu7iYG56H0+OhCd7d6Ug0IE3WcFpZozBKW2+80FUbv5QGk5AQ=="
+		},
+		"@types/chai": {
+			"version": "4.3.5",
+			"resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.5.tgz",
+			"integrity": "sha512-mEo1sAde+UCE6b2hxn332f1g1E8WfYRu6p5SvTKr2ZKC1f7gFJXk4h5PyGP9Dt6gCaG8y8XhwnXWC6Iy2cmBng=="
+		},
+		"@types/chai-subset": {
+			"version": "1.3.3",
+			"resolved": "https://registry.npmjs.org/@types/chai-subset/-/chai-subset-1.3.3.tgz",
+			"integrity": "sha512-frBecisrNGz+F4T6bcc+NLeolfiojh5FxW2klu669+8BARtyQv2C/GkNW6FUodVe4BroGMP/wER/YDGc7rEllw==",
+			"requires": {
+				"@types/chai": "*"
+			}
 		},
 		"@types/culori": {
 			"version": "2.0.0",
@@ -26114,6 +27553,126 @@ 					}
 				}
 			}
 		},
+		"@vitest/expect": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-0.34.2.tgz",
+			"integrity": "sha512-EZm2dMNlLyIfDMha17QHSQcg2KjeAZaXd65fpPzXY5bvnfx10Lcaz3N55uEe8PhF+w4pw+hmrlHLLlRn9vkBJg==",
+			"requires": {
+				"@vitest/spy": "0.34.2",
+				"@vitest/utils": "0.34.2",
+				"chai": "^4.3.7"
+			}
+		},
+		"@vitest/runner": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-0.34.2.tgz",
+			"integrity": "sha512-8ydGPACVX5tK3Dl0SUwxfdg02h+togDNeQX3iXVFYgzF5odxvaou7HnquALFZkyVuYskoaHUOqOyOLpOEj5XTA==",
+			"requires": {
+				"@vitest/utils": "0.34.2",
+				"p-limit": "^4.0.0",
+				"pathe": "^1.1.1"
+			},
+			"dependencies": {
+				"p-limit": {
+					"version": "4.0.0",
+					"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+					"integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+					"requires": {
+						"yocto-queue": "^1.0.0"
+					}
+				},
+				"yocto-queue": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz",
+					"integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g=="
+				}
+			}
+		},
+		"@vitest/snapshot": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-0.34.2.tgz",
+			"integrity": "sha512-qhQ+xy3u4mwwLxltS4Pd4SR+XHv4EajiTPNY3jkIBLUApE6/ce72neJPSUQZ7bL3EBuKI+NhvzhGj3n5baRQUQ==",
+			"requires": {
+				"magic-string": "^0.30.1",
+				"pathe": "^1.1.1",
+				"pretty-format": "^29.5.0"
+			},
+			"dependencies": {
+				"ansi-styles": {
+					"version": "5.2.0",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+					"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
+				},
+				"magic-string": {
+					"version": "0.30.3",
+					"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
+					"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
+					"requires": {
+						"@jridgewell/sourcemap-codec": "^1.4.15"
+					}
+				},
+				"pretty-format": {
+					"version": "29.6.3",
+					"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+					"integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+					"requires": {
+						"@jest/schemas": "^29.6.3",
+						"ansi-styles": "^5.0.0",
+						"react-is": "^18.0.0"
+					}
+				},
+				"react-is": {
+					"version": "18.2.0",
+					"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+					"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+				}
+			}
+		},
+		"@vitest/spy": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-0.34.2.tgz",
+			"integrity": "sha512-yd4L9OhfH6l0Av7iK3sPb3MykhtcRN5c5K5vm1nTbuN7gYn+yvUVVsyvzpHrjqS7EWqn9WsPJb7+0c3iuY60tA==",
+			"requires": {
+				"tinyspy": "^2.1.1"
+			}
+		},
+		"@vitest/utils": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-0.34.2.tgz",
+			"integrity": "sha512-Lzw+kAsTPubhoQDp1uVAOP6DhNia1GMDsI9jgB0yMn+/nDaPieYQ88lKqz/gGjSHL4zwOItvpehec9OY+rS73w==",
+			"requires": {
+				"diff-sequences": "^29.4.3",
+				"loupe": "^2.3.6",
+				"pretty-format": "^29.5.0"
+			},
+			"dependencies": {
+				"ansi-styles": {
+					"version": "5.2.0",
+					"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz",
+					"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
+				},
+				"diff-sequences": {
+					"version": "29.6.3",
+					"resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz",
+					"integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q=="
+				},
+				"pretty-format": {
+					"version": "29.6.3",
+					"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.6.3.tgz",
+					"integrity": "sha512-ZsBgjVhFAj5KeK+nHfF1305/By3lechHQSMWCTl8iHSbfOm2TN5nHEtFc/+W7fAyUeCs2n5iow72gld4gW0xDw==",
+					"requires": {
+						"@jest/schemas": "^29.6.3",
+						"ansi-styles": "^5.0.0",
+						"react-is": "^18.0.0"
+					}
+				},
+				"react-is": {
+					"version": "18.2.0",
+					"resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz",
+					"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
+				}
+			}
+		},
 		"@zkochan/cmd-shim": {
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz",
@@ -26460,6 +28019,11 @@ 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
 			"integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
 		},
+		"assertion-error": {
+			"version": "1.1.0",
+			"resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz",
+			"integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw=="
+		},
 		"assign-symbols": {
 			"version": "1.0.0",
 			"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
@@ -26991,6 +28555,11 @@ 			"resolved": "https://registry.npmjs.org/byte-size/-/byte-size-5.0.1.tgz",
 			"integrity": "sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw==",
 			"dev": true
 		},
+		"cac": {
+			"version": "6.7.14",
+			"resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz",
+			"integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="
+		},
 		"cacache": {
 			"version": "12.0.4",
 			"resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.4.tgz",
@@ -27133,6 +28702,20 @@ 			"version": "0.12.0",
 			"resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
 			"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
 		},
+		"chai": {
+			"version": "4.3.7",
+			"resolved": "https://registry.npmjs.org/chai/-/chai-4.3.7.tgz",
+			"integrity": "sha512-HLnAzZ2iupm25PlN0xFreAlBA5zaBSv3og0DdeGA4Ar6h6rJ3A0rolRUKJhSF2V10GZKDgWF/VmAEsNWjCRB+A==",
+			"requires": {
+				"assertion-error": "^1.1.0",
+				"check-error": "^1.0.2",
+				"deep-eql": "^4.1.2",
+				"get-func-name": "^2.0.0",
+				"loupe": "^2.3.1",
+				"pathval": "^1.1.1",
+				"type-detect": "^4.0.5"
+			}
+		},
 		"chalk": {
 			"version": "4.1.2",
 			"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
@@ -27156,6 +28739,11 @@ 		"chardet": {
 			"version": "0.7.0",
 			"resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz",
 			"integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA=="
+		},
+		"check-error": {
+			"version": "1.0.2",
+			"resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz",
+			"integrity": "sha512-BrgHpW9NURQgzoNyjfq0Wu6VFO6D7IZEmJNdtgNqpzGG8RuNFHt2jQxWlAs4HMe119chBnv+34syEZtc6IhLtA=="
 		},
 		"cheerio": {
 			"version": "1.0.0-rc.12",
@@ -28168,6 +29756,14 @@ 			"resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz",
 			"integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=",
 			"dev": true
 		},
+		"deep-eql": {
+			"version": "4.1.3",
+			"resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz",
+			"integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==",
+			"requires": {
+				"type-detect": "^4.0.0"
+			}
+		},
 		"deep-extend": {
 			"version": "0.6.0",
 			"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
@@ -30099,6 +31695,11 @@ 		"get-caller-file": {
 			"version": "2.0.5",
 			"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
 			"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+		},
+		"get-func-name": {
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.0.tgz",
+			"integrity": "sha512-Hm0ixYtaSZ/V7C8FJrtZIuBBI+iSgL+1Aq82zSu8VQNB4S3Gk8e7Qs3VwBDJAhmRZcFqkl3tQu36g/Foh5I5ig=="
 		},
 		"get-intrinsic": {
 			"version": "1.2.1",
@@ -33185,6 +34786,11 @@ 			"version": "2.2.3",
 			"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
 			"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg=="
 		},
+		"jsonc-parser": {
+			"version": "3.2.0",
+			"resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz",
+			"integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w=="
+		},
 		"jsonfile": {
 			"version": "4.0.0",
 			"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
@@ -33525,6 +35131,11 @@ 					"dev": true
 				}
 			}
 		},
+		"local-pkg": {
+			"version": "0.4.3",
+			"resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.4.3.tgz",
+			"integrity": "sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g=="
+		},
 		"locate-path": {
 			"version": "6.0.0",
 			"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz",
@@ -33720,6 +35331,14 @@ 				"currently-unhandled": "^0.4.1",
 				"signal-exit": "^3.0.0"
 			}
 		},
+		"loupe": {
+			"version": "2.3.6",
+			"resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.6.tgz",
+			"integrity": "sha512-RaPMZKiMy8/JruncMU5Bt6na1eftNoo++R4Y+N2FrxkDVTrGvcyzFTsaGif4QTeKESheMGegbhw6iUAq+5A8zA==",
+			"requires": {
+				"get-func-name": "^2.0.0"
+			}
+		},
 		"lower-case": {
 			"version": "2.0.2",
 			"resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz",
@@ -34120,6 +35739,24 @@ 			"integrity": "sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE=",
 			"dev": true,
 			"requires": {
 				"mkdirp": "*"
+			}
+		},
+		"mlly": {
+			"version": "1.4.0",
+			"resolved": "https://registry.npmjs.org/mlly/-/mlly-1.4.0.tgz",
+			"integrity": "sha512-ua8PAThnTwpprIaU47EPeZ/bPUVp2QYBbWMphUQpVdBI3Lgqzm5KZQ45Agm3YJedHXaIHl6pBGabaLSUPPSptg==",
+			"requires": {
+				"acorn": "^8.9.0",
+				"pathe": "^1.1.1",
+				"pkg-types": "^1.0.3",
+				"ufo": "^1.1.2"
+			},
+			"dependencies": {
+				"acorn": {
+					"version": "8.10.0",
+					"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+					"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw=="
+				}
 			}
 		},
 		"modify-values": {
@@ -35154,6 +36791,16 @@ 					"dev": true
 				}
 			}
 		},
+		"pathe": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.1.tgz",
+			"integrity": "sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q=="
+		},
+		"pathval": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz",
+			"integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ=="
+		},
 		"pend": {
 			"version": "1.2.0",
 			"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
@@ -35243,6 +36890,16 @@ 					}
 				}
 			}
 		},
+		"pkg-types": {
+			"version": "1.0.3",
+			"resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.0.3.tgz",
+			"integrity": "sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==",
+			"requires": {
+				"jsonc-parser": "^3.2.0",
+				"mlly": "^1.2.0",
+				"pathe": "^1.1.0"
+			}
+		},
 		"pkg-up": {
 			"version": "3.1.0",
 			"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
@@ -36749,6 +38406,12 @@ 			"resolved": "https://registry.npmjs.org/sift-string/-/sift-string-0.0.2.tgz",
 			"integrity": "sha512-cOWdhRSgl6neRIgTCLdqsKgQQGnkF92+PzVKpRJEnVVZvFs/mLipRanroOO+2Lp6Kv4vWk/3wMnRylTne0jksQ=="
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+				"source-map": "^0.6.1",
+			"version": "2.0.0",
+			"resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz",
+			"integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 				"line-column": "1.0.2",
 			"version": "3.0.3",
 			"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
@@ -37204,6 +38867,12 @@ 				}
 			}
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+				"write-file-atomic": "^3.0.0"
+			"version": "0.0.2",
+			"resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz",
+			"integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 			"version": "1.9.3",
 			"version": "0.1.2",
 			"resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
@@ -37273,6 +38942,11 @@ 					"resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
 					"integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw=="
 				}
 			}
+		},
+		"std-env": {
+			"version": "3.4.2",
+			"resolved": "https://registry.npmjs.org/std-env/-/std-env-3.4.2.tgz",
+			"integrity": "sha512-Cw6eJDX9AxEEL0g5pYj8Zx9KXtDf60rxwS2ze0HBanS0aKhj1sBlzcsmg+R0qYy8byFa854/yR2X5ZmBSClVmg=="
 		},
 		"stealthy-require": {
 			"version": "1.1.1",
@@ -37442,6 +39116,22 @@ 			"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
 			"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+		"node_modules/@jest/transform/node_modules/supports-color": {
+			"version": "1.3.0",
+			"resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-1.3.0.tgz",
+			"integrity": "sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==",
+			"requires": {
+				"acorn": "^8.10.0"
+			},
+			"dependencies": {
+				"acorn": {
+					"version": "8.10.0",
+					"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+					"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw=="
+				}
+			}
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 				"@babel/parser": "^7.22.10",
 			"version": "2.1.0",
 			"resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz",
@@ -37919,6 +39609,22 @@ 				"globrex": "^0.1.2"
 			}
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+		"node_modules/@jest/types": {
+			"version": "2.5.0",
+			"resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.5.0.tgz",
+			"integrity": "sha512-kRwSG8Zx4tjF9ZiyH4bhaebu+EDz1BOx9hOigYHlUW4xxI/wKIUQUqo018UlU4ar6ATPBsaMrdbKZ+tmPdohFA=="
+		},
+		"tinypool": {
+			"version": "0.7.0",
+			"resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.7.0.tgz",
+			"integrity": "sha512-zSYNUlYSMhJ6Zdou4cJwo/p7w5nmAH17GRfU/ui3ctvjXFErXXkruT4MWW6poDeXgCaIBlGLrfU6TbTXxyGMww=="
+		},
+		"tinyspy": {
+			"version": "2.1.1",
+			"resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.1.1.tgz",
+			"integrity": "sha512-XPJL2uSzcOyBMky6OFrusqWlzfFrXtE0hPuMgW8A2HmaqrPo4ZQHRN/V0QXN3FSjKxpsbRrFc5LI7KOwBsT1/w=="
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 			"integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
 			"version": "0.0.33",
 			"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -38349,6 +40055,12 @@ 			"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
 			"integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+				"chalk": "^3.0.0"
+			"version": "1.2.0",
+			"resolved": "https://registry.npmjs.org/ufo/-/ufo-1.2.0.tgz",
+			"integrity": "sha512-RsPyTbqORDNDxqAdQPQBpgqhWle1VcTSou/FraClYlHf6TZnQcGslpLcAphNR+sQW4q5lLWLbOsRlh9j24baQg=="
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 			"integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==",
 			"version": "3.13.8",
 			"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.13.8.tgz",
@@ -38624,6 +40336,272 @@ 				"extsprintf": "^1.2.0"
 			}
 		},
 				"@csstools/css-tokenizer": "2.1.1",
+		"node_modules/@jest/types/node_modules/chalk": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/vite-node/-/vite-node-0.34.2.tgz",
+			"integrity": "sha512-JtW249Zm3FB+F7pQfH56uWSdlltCo1IOkZW5oHBzeQo0iX4jtC7o1t9aILMGd9kVekXBP2lfJBEQt9rBh07ebA==",
+			"requires": {
+				"cac": "^6.7.14",
+				"debug": "^4.3.4",
+				"mlly": "^1.4.0",
+				"pathe": "^1.1.1",
+				"picocolors": "^1.0.0",
+				"vite": "^3.0.0 || ^4.0.0"
+			},
+			"dependencies": {
+				"acorn": {
+					"version": "8.10.0",
+					"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+					"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==",
+					"optional": true,
+					"peer": true
+				},
+				"commander": {
+					"version": "2.20.3",
+					"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+					"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+					"optional": true,
+					"peer": true
+				},
+				"debug": {
+					"version": "4.3.4",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+					"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"esbuild": {
+					"version": "0.18.20",
+					"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+					"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+					"requires": {
+						"@esbuild/android-arm": "0.18.20",
+						"@esbuild/android-arm64": "0.18.20",
+						"@esbuild/android-x64": "0.18.20",
+						"@esbuild/darwin-arm64": "0.18.20",
+						"@esbuild/darwin-x64": "0.18.20",
+						"@esbuild/freebsd-arm64": "0.18.20",
+						"@esbuild/freebsd-x64": "0.18.20",
+						"@esbuild/linux-arm": "0.18.20",
+						"@esbuild/linux-arm64": "0.18.20",
+						"@esbuild/linux-ia32": "0.18.20",
+						"@esbuild/linux-loong64": "0.18.20",
+						"@esbuild/linux-mips64el": "0.18.20",
+						"@esbuild/linux-ppc64": "0.18.20",
+						"@esbuild/linux-riscv64": "0.18.20",
+						"@esbuild/linux-s390x": "0.18.20",
+						"@esbuild/linux-x64": "0.18.20",
+						"@esbuild/netbsd-x64": "0.18.20",
+						"@esbuild/openbsd-x64": "0.18.20",
+						"@esbuild/sunos-x64": "0.18.20",
+						"@esbuild/win32-arm64": "0.18.20",
+						"@esbuild/win32-ia32": "0.18.20",
+						"@esbuild/win32-x64": "0.18.20"
+					}
+				},
+				"picocolors": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+					"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+				},
+				"postcss": {
+					"version": "8.4.28",
+					"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+					"integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+					"requires": {
+						"nanoid": "^3.3.6",
+						"picocolors": "^1.0.0",
+						"source-map-js": "^1.0.2"
+					}
+				},
+				"rollup": {
+					"version": "3.28.1",
+					"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
+					"integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==",
+					"requires": {
+						"fsevents": "~2.3.2"
+					}
+				},
+				"source-map-js": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+					"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
+				},
+				"terser": {
+					"version": "5.19.2",
+					"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
+					"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
+					"optional": true,
+					"peer": true,
+					"requires": {
+						"@jridgewell/source-map": "^0.3.3",
+						"acorn": "^8.8.2",
+						"commander": "^2.20.0",
+						"source-map-support": "~0.5.20"
+					}
+				},
+				"vite": {
+					"version": "4.4.9",
+					"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
+					"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
+					"requires": {
+						"esbuild": "^0.18.10",
+						"fsevents": "~2.3.2",
+						"postcss": "^8.4.27",
+						"rollup": "^3.27.1"
+					}
+				}
+			}
+		},
+		"vitest": {
+			"version": "0.34.2",
+			"resolved": "https://registry.npmjs.org/vitest/-/vitest-0.34.2.tgz",
+			"integrity": "sha512-WgaIvBbjsSYMq/oiMlXUI7KflELmzM43BEvkdC/8b5CAod4ryAiY2z8uR6Crbi5Pjnu5oOmhKa9sy7uk6paBxQ==",
+			"requires": {
+				"@types/chai": "^4.3.5",
+				"@types/chai-subset": "^1.3.3",
+				"@types/node": "*",
+				"@vitest/expect": "0.34.2",
+				"@vitest/runner": "0.34.2",
+				"@vitest/snapshot": "0.34.2",
+				"@vitest/spy": "0.34.2",
+				"@vitest/utils": "0.34.2",
+				"acorn": "^8.9.0",
+				"acorn-walk": "^8.2.0",
+				"cac": "^6.7.14",
+				"chai": "^4.3.7",
+				"debug": "^4.3.4",
+				"local-pkg": "^0.4.3",
+				"magic-string": "^0.30.1",
+				"pathe": "^1.1.1",
+				"picocolors": "^1.0.0",
+				"std-env": "^3.3.3",
+				"strip-literal": "^1.0.1",
+				"tinybench": "^2.5.0",
+				"tinypool": "^0.7.0",
+				"vite": "^3.0.0 || ^4.0.0",
+				"vite-node": "0.34.2",
+				"why-is-node-running": "^2.2.2"
+			},
+			"dependencies": {
+				"acorn": {
+					"version": "8.10.0",
+					"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz",
+					"integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw=="
+				},
+				"acorn-walk": {
+					"version": "8.2.0",
+					"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz",
+					"integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA=="
+				},
+				"commander": {
+					"version": "2.20.3",
+					"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+					"integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+					"optional": true,
+					"peer": true
+				},
+				"debug": {
+					"version": "4.3.4",
+					"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
+					"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
+					"requires": {
+						"ms": "2.1.2"
+					}
+				},
+				"esbuild": {
+					"version": "0.18.20",
+					"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.18.20.tgz",
+					"integrity": "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==",
+					"requires": {
+						"@esbuild/android-arm": "0.18.20",
+						"@esbuild/android-arm64": "0.18.20",
+						"@esbuild/android-x64": "0.18.20",
+						"@esbuild/darwin-arm64": "0.18.20",
+						"@esbuild/darwin-x64": "0.18.20",
+						"@esbuild/freebsd-arm64": "0.18.20",
+						"@esbuild/freebsd-x64": "0.18.20",
+						"@esbuild/linux-arm": "0.18.20",
+						"@esbuild/linux-arm64": "0.18.20",
+						"@esbuild/linux-ia32": "0.18.20",
+						"@esbuild/linux-loong64": "0.18.20",
+						"@esbuild/linux-mips64el": "0.18.20",
+						"@esbuild/linux-ppc64": "0.18.20",
+						"@esbuild/linux-riscv64": "0.18.20",
+						"@esbuild/linux-s390x": "0.18.20",
+						"@esbuild/linux-x64": "0.18.20",
+						"@esbuild/netbsd-x64": "0.18.20",
+						"@esbuild/openbsd-x64": "0.18.20",
+						"@esbuild/sunos-x64": "0.18.20",
+						"@esbuild/win32-arm64": "0.18.20",
+						"@esbuild/win32-ia32": "0.18.20",
+						"@esbuild/win32-x64": "0.18.20"
+					}
+				},
+				"magic-string": {
+					"version": "0.30.3",
+					"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.3.tgz",
+					"integrity": "sha512-B7xGbll2fG/VjP+SWg4sX3JynwIU0mjoTc6MPpKNuIvftk6u6vqhDnk1R80b8C2GBR6ywqy+1DcKBrevBg+bmw==",
+					"requires": {
+						"@jridgewell/sourcemap-codec": "^1.4.15"
+					}
+				},
+				"picocolors": {
+					"version": "1.0.0",
+					"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+					"integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+				},
+				"postcss": {
+					"version": "8.4.28",
+					"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+					"integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+					"requires": {
+						"nanoid": "^3.3.6",
+						"picocolors": "^1.0.0",
+						"source-map-js": "^1.0.2"
+					}
+				},
+				"rollup": {
+					"version": "3.28.1",
+					"resolved": "https://registry.npmjs.org/rollup/-/rollup-3.28.1.tgz",
+					"integrity": "sha512-R9OMQmIHJm9znrU3m3cpE8uhN0fGdXiawME7aZIpQqvpS/85+Vt1Hq1/yVIcYfOmaQiHjvXkQAoJukvLpau6Yw==",
+					"requires": {
+						"fsevents": "~2.3.2"
+					}
+				},
+				"source-map-js": {
+					"version": "1.0.2",
+					"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+					"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw=="
+				},
+				"terser": {
+					"version": "5.19.2",
+					"resolved": "https://registry.npmjs.org/terser/-/terser-5.19.2.tgz",
+					"integrity": "sha512-qC5+dmecKJA4cpYxRa5aVkKehYsQKc+AHeKl0Oe62aYjBL8ZA33tTljktDHJSaxxMnbI5ZYw+o/S2DxxLu8OfA==",
+					"optional": true,
+					"peer": true,
+					"requires": {
+						"@jridgewell/source-map": "^0.3.3",
+						"acorn": "^8.8.2",
+						"commander": "^2.20.0",
+						"source-map-support": "~0.5.20"
+					}
+				},
+				"vite": {
+					"version": "4.4.9",
+					"resolved": "https://registry.npmjs.org/vite/-/vite-4.4.9.tgz",
+					"integrity": "sha512-2mbUn2LlUmNASWwSCNSJ/EG2HuSRTnVNaydp6vMCm5VIqJsjMfbIWtbH2kDuwUVW5mMUKKZvGPX/rqeqVvv1XA==",
+					"requires": {
+						"esbuild": "^0.18.10",
+						"fsevents": "~2.3.2",
+						"postcss": "^8.4.27",
+						"rollup": "^3.27.1"
+					}
+				}
+			}
+		},
+				"@csstools/css-tokenizer": "2.1.1",
 				"@babel/helper-remap-async-to-generator": "^7.22.5"
 			"version": "2.15.0",
 			"resolved": "https://registry.npmjs.org/vsce/-/vsce-2.15.0.tgz",
@@ -38777,16 +40755,16 @@ 			"resolved": "https://registry.npmjs.org/vscode-emmet-helper-bundled/-/vscode-emmet-helper-bundled-0.0.1.tgz",
 			"integrity": "sha512-EhZ0Wt8MbdrKF3NUMfaUDhFPTdRnl1tyqYS7KOcNtsSNTV285IV+XPDtNQyw5rwYsULEfb6n+fK1DRufJQlPYw=="
 		},
 		"vscode-jsonrpc": {
-	"requires": true,
 	"lockfileVersion": 2,
+			"engines": {
 	"name": "root",
-			"name": "root",
+			"version": "1.9.3",
 	"packages": {
-				"latest-semver": "^4.0.0",
+				"@csstools/css-parser-algorithms": "2.1.1",
+{
 				"@csstools/css-tokenizer": "2.1.1",
-	"requires": true,
 {
-	"name": "root",
+	"lockfileVersion": 2,
 		},
 		"vscode-languageclient": {
 			"version": "8.0.2",
@@ -38833,6 +40812,11 @@ 				"vscode-jsonrpc": "8.0.2",
 				"vscode-languageserver-types": "3.17.2"
 			},
 			"dependencies": {
+				"vscode-jsonrpc": {
+					"version": "8.0.2",
+					"resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz",
+					"integrity": "sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ=="
+				},
 				"vscode-languageserver-types": {
 					"version": "3.17.2",
 					"resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz",
@@ -38994,6 +40978,15 @@ 				"call-bind": "^1.0.2",
 				"for-each": "^0.3.3",
 				"gopd": "^1.0.1",
 				"has-tostringtag": "^1.0.0"
+			}
+		},
+		"why-is-node-running": {
+			"version": "2.2.2",
+			"resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.2.2.tgz",
+			"integrity": "sha512-6tSwToZxTOcotxHeA+qGCq1mVzKR3CwcJGmVcY+QE8SHy6TnpFnh8PAvPNHYr7EcuVeG0QSMxtYCuO1ta/G/oA==",
+			"requires": {
+				"siginfo": "^2.0.0",
+				"stackback": "0.0.2"
 			}
 		},
 		"wide-align": {
M packages/tailwindcss-language-server/package.json -> packages/tailwindcss-language-server/package.json
diff --git a/packages/tailwindcss-language-server/package.json b/packages/tailwindcss-language-server/package.json
index 0590728254d14f657c56cb4ac844ca4269c5c6be..eadd57b9da04cc629e47a5d2772e26b36f77fe28 100644
--- a/packages/tailwindcss-language-server/package.json
+++ b/packages/tailwindcss-language-server/package.json
@@ -18,7 +18,9 @@     "_esbuild": "node ../../esbuild.js src/server.ts --outfile=bin/tailwindcss-language-server --external=pnpapi --external=lightningcss --external=@tailwindcss/oxide --minify",
     "clean": "rimraf bin",
     "hashbang": "node scripts/hashbang.mjs",
     "create-notices-file": "node scripts/createNoticesFile.mjs",
-  "name": "@tailwindcss/language-server",
+    "type": "git",
+    "test": "vitest",
+    "test:prepare": "node tests/prepare.js"
   },
   "bin": {
     "tailwindcss-language-server": "./bin/tailwindcss-language-server"
@@ -65,7 +67,10 @@     "rimraf": "3.0.2",
     "stack-trace": "0.0.10",
     "tailwindcss": "3.3.0",
     "typescript": "4.6.4",
+    "vitest": "0.34.2",
   "repository": {
+  "license": "MIT",
+    "type": "git",
   "license": "MIT",
     "vscode-languageserver": "8.0.2",
     "vscode-languageserver-textdocument": "1.0.7",
M packages/tailwindcss-language-server/src/server.ts -> packages/tailwindcss-language-server/src/server.ts
diff --git a/packages/tailwindcss-language-server/src/server.ts b/packages/tailwindcss-language-server/src/server.ts
index 24a191e8c652296f238d4fd9413f05f12233e8d1..721a37b4cf41b06187ffa8e580559f0e1d6c366f 100644
--- a/packages/tailwindcss-language-server/src/server.ts
+++ b/packages/tailwindcss-language-server/src/server.ts
@@ -1200,15 +1200,18 @@       return getDocumentLinks(state, document, (linkPath) =>
         URI.file(path.resolve(path.dirname(URI.parse(document.uri).fsPath), linkPath)).toString()
       )
     },
-    provideDiagnostics: debounce((document: TextDocument) => {
+    provideDiagnostics: debounce(
+      (document: TextDocument) => {
-  DocumentColorParams,
+  enable: () => void
   CompletionList,
-  ColorInformation,
-  DocumentColorParams,
+  enable: () => void
   CompletionParams,
+      },
-  DocumentColorParams,
+import './lib/env'
   CompletionParams,
+import { provideDiagnostics } from './lsp/diagnosticsProvider'
 import './lib/env'
+            generateRules: {
     provideDiagnosticsForce: (document: TextDocument) => {
       if (!state.enabled) return
       provideDiagnostics(state, document)
I packages/tailwindcss-language-server/tests/code-actions/code-actions.test.js
diff --git a/packages/tailwindcss-language-server/tests/code-actions/code-actions.test.js b/packages/tailwindcss-language-server/tests/code-actions/code-actions.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..505e2960534bc31eb3ad54470526da0e9ef89e39
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/code-actions.test.js
@@ -0,0 +1,38 @@
+import { test, expect } from 'vitest'
+import * as fs from 'node:fs/promises'
+import { withFixture } from '../common'
+
+withFixture('basic', (c) => {
+  function testFixture(fixture) {
+    test(fixture, async () => {
+      fixture = await fs.readFile(`tests/code-actions/${fixture}.json`, 'utf8')
+
+      let { code, expected, language = 'html' } = JSON.parse(fixture)
+
+      let promise = new Promise((resolve) => {
+        c.onNotification('textDocument/publishDiagnostics', ({ diagnostics }) => {
+          resolve(diagnostics)
+        })
+      })
+
+      let textDocument = await c.openDocument({ text: code, lang: language })
+      let diagnostics = await promise
+
+      let res = await c.sendRequest('textDocument/codeAction', {
+        textDocument,
+        context: {
+          diagnostics,
+        },
+      })
+      // console.log(JSON.stringify(res))
+
+      expected = JSON.parse(JSON.stringify(expected).replaceAll('{{URI}}', textDocument.uri))
+
+      expect(res).toEqual(expected)
+    })
+  }
+
+  testFixture('conflict')
+  testFixture('invalid-theme')
+  testFixture('invalid-screen')
+})
I packages/tailwindcss-language-server/tests/code-actions/code-actions.v2-jit.test.js
diff --git a/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2-jit.test.js b/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2-jit.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..52941e20a22ad2cdfabaa5549d6a7b19a584725c
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2-jit.test.js
@@ -0,0 +1,36 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+import * as fs from 'node:fs/promises'
+
+withFixture('v2-jit', (c) => {
+  function testFixture(fixture) {
+    test(fixture, async () => {
+      fixture = await fs.readFile(`tests/code-actions/${fixture}.json`, 'utf8')
+
+      let { code, expected, language = 'html' } = JSON.parse(fixture)
+
+      let promise = new Promise((resolve) => {
+        c.onNotification('textDocument/publishDiagnostics', ({ diagnostics }) => {
+          resolve(diagnostics)
+        })
+      })
+
+      let textDocument = await c.openDocument({ text: code, lang: language })
+      let diagnostics = await promise
+
+      let res = await c.sendRequest('textDocument/codeAction', {
+        textDocument,
+        context: {
+          diagnostics,
+        },
+      })
+      // console.log(JSON.stringify(res))
+
+      expected = JSON.parse(JSON.stringify(expected).replaceAll('{{URI}}', textDocument.uri))
+
+      expect(res).toEqual(expected)
+    })
+  }
+
+  testFixture('variant-order')
+})
I packages/tailwindcss-language-server/tests/code-actions/code-actions.v2.test.js
diff --git a/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2.test.js b/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..d16d0c407b4e5adae322d314a62a8b25a8f3c920
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/code-actions.v2.test.js
@@ -0,0 +1,39 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+import * as fs from 'node:fs/promises'
+
+withFixture('v2', (c) => {
+  function testFixture(fixture) {
+    test(fixture, async () => {
+      fixture = await fs.readFile(`tests/code-actions/${fixture}.json`, 'utf8')
+
+      let { code, expected, language = 'html' } = JSON.parse(fixture)
+
+      let promise = new Promise((resolve) => {
+        c.onNotification('textDocument/publishDiagnostics', ({ diagnostics }) => {
+          resolve(diagnostics)
+        })
+      })
+
+      let textDocument = await c.openDocument({ text: code, lang: language })
+      let diagnostics = await promise
+
+      let res = await c.sendRequest('textDocument/codeAction', {
+        textDocument,
+        context: {
+          diagnostics,
+        },
+      })
+      // console.log(JSON.stringify(res))
+
+      expected = JSON.parse(JSON.stringify(expected).replaceAll('{{URI}}', textDocument.uri))
+
+      expect(res).toEqual(expected)
+    })
+  }
+
+  // testFixture('conflict')
+  testFixture('invalid-theme')
+  testFixture('invalid-screen')
+  testFixture('invalid-variant')
+})
I packages/tailwindcss-language-server/tests/code-actions/conflict.json
diff --git a/packages/tailwindcss-language-server/tests/code-actions/conflict.json b/packages/tailwindcss-language-server/tests/code-actions/conflict.json
new file mode 100644
index 0000000000000000000000000000000000000000..eccb1446419582fc5070cfb628998b7ff5be96dd
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/conflict.json
@@ -0,0 +1,161 @@
+{
+  "code": "<div class=\"lowercase uppercase\">",
+  "expected": [
+    {
+      "title": "Delete 'uppercase'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "cssConflict",
+          "className": {
+            "className": "lowercase",
+            "classList": {
+              "classList": "lowercase uppercase",
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 31 }
+              }
+            },
+            "relativeRange": {
+              "start": { "line": 0, "character": 0 },
+              "end": { "line": 0, "character": 9 }
+            },
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 21 }
+            }
+          },
+          "otherClassNames": [
+            {
+              "className": "uppercase",
+              "classList": {
+                "classList": "lowercase uppercase",
+                "range": {
+                  "start": { "line": 0, "character": 12 },
+                  "end": { "line": 0, "character": 31 }
+                }
+              },
+              "relativeRange": {
+                "start": { "line": 0, "character": 10 },
+                "end": { "line": 0, "character": 19 }
+              },
+              "range": {
+                "start": { "line": 0, "character": 22 },
+                "end": { "line": 0, "character": 31 }
+              }
+            }
+          ],
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 21 }
+          },
+          "severity": 2,
+          "message": "'lowercase' applies the same CSS properties as 'uppercase'.",
+          "relatedInformation": [
+            {
+              "message": "uppercase",
+              "location": {
+                "uri": "{{URI}}",
+                "range": {
+                  "start": { "line": 0, "character": 22 },
+                  "end": { "line": 0, "character": 31 }
+                }
+              }
+            }
+          ]
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 31 }
+              },
+              "newText": "lowercase"
+            }
+          ]
+        }
+      }
+    },
+    {
+      "title": "Delete 'lowercase'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "cssConflict",
+          "className": {
+            "className": "uppercase",
+            "classList": {
+              "classList": "lowercase uppercase",
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 31 }
+              }
+            },
+            "relativeRange": {
+              "start": { "line": 0, "character": 10 },
+              "end": { "line": 0, "character": 19 }
+            },
+            "range": {
+              "start": { "line": 0, "character": 22 },
+              "end": { "line": 0, "character": 31 }
+            }
+          },
+          "otherClassNames": [
+            {
+              "className": "lowercase",
+              "classList": {
+                "classList": "lowercase uppercase",
+                "range": {
+                  "start": { "line": 0, "character": 12 },
+                  "end": { "line": 0, "character": 31 }
+                }
+              },
+              "relativeRange": {
+                "start": { "line": 0, "character": 0 },
+                "end": { "line": 0, "character": 9 }
+              },
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 21 }
+              }
+            }
+          ],
+          "range": {
+            "start": { "line": 0, "character": 22 },
+            "end": { "line": 0, "character": 31 }
+          },
+          "severity": 2,
+          "message": "'uppercase' applies the same CSS properties as 'lowercase'.",
+          "relatedInformation": [
+            {
+              "message": "lowercase",
+              "location": {
+                "uri": "{{URI}}",
+                "range": {
+                  "start": { "line": 0, "character": 12 },
+                  "end": { "line": 0, "character": 21 }
+                }
+              }
+            }
+          ]
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 31 }
+              },
+              "newText": "uppercase"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/code-actions/invalid-screen.json
diff --git a/packages/tailwindcss-language-server/tests/code-actions/invalid-screen.json b/packages/tailwindcss-language-server/tests/code-actions/invalid-screen.json
new file mode 100644
index 0000000000000000000000000000000000000000..9c49c1b92cc888622a8d55aa08a3910c3607fb4e
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/invalid-screen.json
@@ -0,0 +1,35 @@
+{
+  "code": "@screen small",
+  "language": "css",
+  "expected": [
+    {
+      "title": "Replace with 'sm'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "invalidScreen",
+          "range": {
+            "start": { "line": 0, "character": 8 },
+            "end": { "line": 0, "character": 13 }
+          },
+          "severity": 1,
+          "message": "The screen 'small' does not exist in your theme config. Did you mean 'sm'?",
+          "suggestions": ["sm"]
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 8 },
+                "end": { "line": 0, "character": 13 }
+              },
+              "newText": "sm"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/code-actions/invalid-theme.json
diff --git a/packages/tailwindcss-language-server/tests/code-actions/invalid-theme.json b/packages/tailwindcss-language-server/tests/code-actions/invalid-theme.json
new file mode 100644
index 0000000000000000000000000000000000000000..7aceb38eadf1beebcb7dac73a7bd4c93bd39ce9f
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/invalid-theme.json
@@ -0,0 +1,35 @@
+{
+  "code": ".test { color: theme(colors.red.901) }",
+  "language": "css",
+  "expected": [
+    {
+      "title": "Replace with 'colors.red.900'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "invalidConfigPath",
+          "range": {
+            "start": { "line": 0, "character": 21 },
+            "end": { "line": 0, "character": 35 }
+          },
+          "severity": 1,
+          "message": "'colors.red.901' does not exist in your theme config. Did you mean 'colors.red.900'?",
+          "suggestions": ["colors.red.900"]
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 21 },
+                "end": { "line": 0, "character": 35 }
+              },
+              "newText": "colors.red.900"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/code-actions/invalid-variant.json
diff --git a/packages/tailwindcss-language-server/tests/code-actions/invalid-variant.json b/packages/tailwindcss-language-server/tests/code-actions/invalid-variant.json
new file mode 100644
index 0000000000000000000000000000000000000000..5fbd5a7a6b8d2d31d610b9d5c7f4a0a9297a8e22
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/invalid-variant.json
@@ -0,0 +1,35 @@
+{
+  "code": "@variants hoover",
+  "language": "css",
+  "expected": [
+    {
+      "title": "Replace with 'hover'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "invalidVariant",
+          "range": {
+            "start": { "line": 0, "character": 10 },
+            "end": { "line": 0, "character": 16 }
+          },
+          "severity": 1,
+          "message": "The variant 'hoover' does not exist. Did you mean 'hover'?",
+          "suggestions": ["hover"]
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 10 },
+                "end": { "line": 0, "character": 16 }
+              },
+              "newText": "hover"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/code-actions/variant-order.json
diff --git a/packages/tailwindcss-language-server/tests/code-actions/variant-order.json b/packages/tailwindcss-language-server/tests/code-actions/variant-order.json
new file mode 100644
index 0000000000000000000000000000000000000000..6d44068fa4c3437b8803ea3fa1be542aaff397e2
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/code-actions/variant-order.json
@@ -0,0 +1,34 @@
+{
+  "code": "<div class=\"hover:focus:uppercase\">",
+  "expected": [
+    {
+      "title": "Replace with 'focus:hover:uppercase'",
+      "kind": "quickfix",
+      "diagnostics": [
+        {
+          "code": "recommendedVariantOrder",
+          "suggestions": ["focus:hover:uppercase"],
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 33 }
+          },
+          "severity": 2,
+          "message": "Variants are not in the recommended order, which may cause unexpected CSS output."
+        }
+      ],
+      "edit": {
+        "changes": {
+          "{{URI}}": [
+            {
+              "range": {
+                "start": { "line": 0, "character": 12 },
+                "end": { "line": 0, "character": 33 }
+              },
+              "newText": "focus:hover:uppercase"
+            }
+          ]
+        }
+      }
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/colors/colors.test.js
diff --git a/packages/tailwindcss-language-server/tests/colors/colors.test.js b/packages/tailwindcss-language-server/tests/colors/colors.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..9c3b5717cfc4d40bd25779062e13ded9d6d22165
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/colors/colors.test.js
@@ -0,0 +1,75 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('basic', (c) => {
+  async function testColors(name, { text, expected }) {
+    test.concurrent(name, async () => {
+      let textDocument = await c.openDocument({ text })
+      let res = await c.sendRequest('textDocument/documentColor', {
+        textDocument,
+      })
+
+      expect(res).toEqual(expected)
+    })
+  }
+
+  testColors('simple', {
+    text: '<div class="bg-red-500">',
+    expected: [
+      {
+        range: { start: { line: 0, character: 12 }, end: { line: 0, character: 22 } },
+        color: {
+          red: 0.9372549019607843,
+          green: 0.26666666666666666,
+          blue: 0.26666666666666666,
+          alpha: 1,
+        },
+      },
+    ],
+  })
+
+  testColors('opacity modifier', {
+    text: '<div class="bg-red-500/20">',
+    expected: [
+      {
+        range: { start: { line: 0, character: 12 }, end: { line: 0, character: 25 } },
+        color: {
+          red: 0.9372549019607843,
+          green: 0.26666666666666666,
+          blue: 0.26666666666666666,
+          alpha: 0.2,
+        },
+      },
+    ],
+  })
+
+  testColors('arbitrary value', {
+    text: '<div class="bg-[red]">',
+    expected: [
+      {
+        range: { start: { line: 0, character: 12 }, end: { line: 0, character: 20 } },
+        color: {
+          red: 1,
+          green: 0,
+          blue: 0,
+          alpha: 1,
+        },
+      },
+    ],
+  })
+
+  testColors('arbitrary value and opacity modifier', {
+    text: '<div class="bg-[red]/[0.33]">',
+    expected: [
+      {
+        range: { start: { line: 0, character: 12 }, end: { line: 0, character: 27 } },
+        color: {
+          red: 1,
+          green: 0,
+          blue: 0,
+          alpha: 0.33,
+        },
+      },
+    ],
+  })
+})
I packages/tailwindcss-language-server/tests/colors/presentation.test.js
diff --git a/packages/tailwindcss-language-server/tests/colors/presentation.test.js b/packages/tailwindcss-language-server/tests/colors/presentation.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..4a261c927d85097b9ae9168542772ca67c16f125
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/colors/presentation.test.js
@@ -0,0 +1,108 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('basic', (c) => {
+  test.concurrent('theme color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-red-500">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 22 },
+      },
+    })
+
+    expect(res).toEqual([])
+  })
+
+  test.concurrent('arbitrary named color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-[red]">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 20 },
+      },
+    })
+
+    expect(res).toEqual([
+      { label: 'bg-[#ff0000]' },
+      { label: 'bg-[rgb(255,0,0)]' },
+      { label: 'bg-[hsl(0,100%,50%)]' },
+    ])
+  })
+
+  test.concurrent('arbitrary short hex color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-[#f00]">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 21 },
+      },
+    })
+
+    expect(res).toEqual([
+      { label: 'bg-[#f00]' },
+      { label: 'bg-[rgb(255,0,0)]' },
+      { label: 'bg-[hsl(0,100%,50%)]' },
+    ])
+  })
+
+  test.concurrent('arbitrary hex color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-[#ff0000]">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 24 },
+      },
+    })
+
+    expect(res).toEqual([
+      { label: 'bg-[#ff0000]' },
+      { label: 'bg-[rgb(255,0,0)]' },
+      { label: 'bg-[hsl(0,100%,50%)]' },
+    ])
+  })
+
+  test.concurrent('arbitrary rgb color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-[rgb(255,0,0)]">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 29 },
+      },
+    })
+
+    expect(res).toEqual([
+      { label: 'bg-[#ff0000]' },
+      { label: 'bg-[rgb(255,0,0)]' },
+      { label: 'bg-[hsl(0,100%,50%)]' },
+    ])
+  })
+
+  test.concurrent('arbitrary hsl color', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-[hsl(0,100%,50%)]">' })
+    let res = await c.sendRequest('textDocument/colorPresentation', {
+      color: { red: 1, green: 0, blue: 0, alpha: 1 },
+      textDocument,
+      range: {
+        start: { line: 0, character: 12 },
+        end: { line: 0, character: 32 },
+      },
+    })
+
+    expect(res).toEqual([
+      { label: 'bg-[#ff0000]' },
+      { label: 'bg-[rgb(255,0,0)]' },
+      { label: 'bg-[hsl(0,100%,50%)]' },
+    ])
+  })
+})
I packages/tailwindcss-language-server/tests/common.js
diff --git a/packages/tailwindcss-language-server/tests/common.js b/packages/tailwindcss-language-server/tests/common.js
new file mode 100644
index 0000000000000000000000000000000000000000..7202e736a7d31cb032fa0295db23003b992b7b38
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/common.js
@@ -0,0 +1,231 @@
+import * as path from 'node:path'
+import * as cp from 'node:child_process'
+import * as rpc from 'vscode-jsonrpc'
+import { beforeAll } from 'vitest'
+
+let settings = {}
+let initPromise
+let childProcess
+let docSettings = new Map()
+
+async function init(fixture) {
+  childProcess = cp.fork('./bin/tailwindcss-language-server', { silent: true })
+
+  const capabilities = {
+    textDocument: {
+      codeAction: { dynamicRegistration: true },
+      codeLens: { dynamicRegistration: true },
+      colorProvider: { dynamicRegistration: true },
+      completion: {
+        completionItem: {
+          commitCharactersSupport: true,
+          documentationFormat: ['markdown', 'plaintext'],
+          snippetSupport: true,
+        },
+        completionItemKind: {
+          valueSet: [
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+            25,
+          ],
+        },
+        contextSupport: true,
+        dynamicRegistration: true,
+      },
+      definition: { dynamicRegistration: true },
+      documentHighlight: { dynamicRegistration: true },
+      documentLink: { dynamicRegistration: true },
+      documentSymbol: {
+        dynamicRegistration: true,
+        symbolKind: {
+          valueSet: [
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+            25, 26,
+          ],
+        },
+      },
+      formatting: { dynamicRegistration: true },
+      hover: {
+        contentFormat: ['markdown', 'plaintext'],
+        dynamicRegistration: true,
+      },
+      implementation: { dynamicRegistration: true },
+      onTypeFormatting: { dynamicRegistration: true },
+      publishDiagnostics: { relatedInformation: true },
+      rangeFormatting: { dynamicRegistration: true },
+      references: { dynamicRegistration: true },
+      rename: { dynamicRegistration: true },
+      signatureHelp: {
+        dynamicRegistration: true,
+        signatureInformation: { documentationFormat: ['markdown', 'plaintext'] },
+      },
+      synchronization: {
+        didSave: true,
+        dynamicRegistration: true,
+        willSave: true,
+        willSaveWaitUntil: true,
+      },
+      typeDefinition: { dynamicRegistration: true },
+    },
+    workspace: {
+      applyEdit: true,
+      configuration: true,
+      didChangeConfiguration: { dynamicRegistration: true },
+      didChangeWatchedFiles: { dynamicRegistration: true },
+      executeCommand: { dynamicRegistration: true },
+      symbol: {
+        dynamicRegistration: true,
+        symbolKind: {
+          valueSet: [
+            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
+            25, 26,
+          ],
+        },
+      },
+      workspaceEdit: { documentChanges: true },
+      workspaceFolders: true,
+    },
+  }
+
+  let connection = rpc.createMessageConnection(
+    new rpc.StreamMessageReader(childProcess.stdout),
+    new rpc.StreamMessageWriter(childProcess.stdin)
+  )
+
+  connection.listen()
+
+  await connection.sendRequest(new rpc.RequestType('initialize'), {
+    processId: -1,
+    // rootPath: '.',
+    rootUri: `file://${path.resolve('./tests/fixtures/', fixture)}`,
+    capabilities,
+    trace: 'off',
+    workspaceFolders: [],
+    initializationOptions: {
+      testMode: true,
+    },
+  })
+
+  await connection.sendNotification(new rpc.NotificationType('initialized'))
+
+  connection.onRequest(new rpc.RequestType('workspace/configuration'), (params) => {
+    return params.items.map((item) => {
+      if (docSettings.has(item.scopeUri)) {
+        return docSettings.get(item.scopeUri)[item.section] ?? {}
+      }
+      return settings[item.section] ?? {}
+    })
+  })
+
+  initPromise = new Promise((resolve) => {
+    connection.onRequest(new rpc.RequestType('client/registerCapability'), ({ registrations }) => {
+      if (registrations.findIndex((r) => r.method === 'textDocument/completion') > -1) {
+        resolve()
+      }
+      return null
+    })
+  })
+
+  let counter = 0
+
+  return {
+    connection,
+    sendRequest(type, params) {
+      return connection.sendRequest(new rpc.RequestType(type), params)
+    },
+    onNotification(type, callback) {
+      return connection.onNotification(new rpc.RequestType(type), callback)
+    },
+    async openDocument({ text, lang = 'html', dir = '', settings = {} }) {
+      let uri = `file://${path.resolve('./tests/fixtures', fixture, dir, `file-${counter++}`)}`
+      docSettings.set(uri, settings)
+      await connection.sendNotification(new rpc.NotificationType('textDocument/didOpen'), {
+        textDocument: {
+          uri,
+          languageId: lang,
+          version: 1,
+          text,
+        },
+      })
+
+      await initPromise
+
+      return {
+        uri,
+        async updateSettings(settings) {
+          docSettings.set(uri, settings)
+          await connection.sendNotification(
+            new rpc.NotificationType('workspace/didChangeConfiguration')
+          )
+        },
+      }
+    },
+    async updateSettings(newSettings) {
+      settings = newSettings
+      await connection.sendNotification(
+        new rpc.NotificationType('workspace/didChangeConfiguration')
+      )
+    },
+    async updateFile(file, text) {
+      let uri = `file://${path.resolve('./tests/fixtures', fixture, file)}`
+
+      await connection.sendNotification(new rpc.NotificationType('textDocument/didChange'), {
+        textDocument: { uri, version: counter++ },
+        contentChanges: [{ text }],
+      })
+    },
+  }
+}
+
+export function withFixture(fixture, callback) {
+  let c
+
+  beforeAll(async () => {
+    c = await init(fixture)
+    return () => c.connection.end()
+  })
+
+  callback({
+    get connection() {
+      return c.connection
+    },
+    get sendRequest() {
+      return c.sendRequest
+    },
+    get onNotification() {
+      return c.onNotification
+    },
+    get openDocument() {
+      return c.openDocument
+    },
+    get updateSettings() {
+      return c.updateSettings
+    },
+    get updateFile() {
+      return c.updateFile
+    },
+  })
+}
+
+// let counter = 0
+
+// export async function openDocument(connection, fixture, languageId, text) {
+//   let uri = `file://${path.resolve('./tests/fixtures', fixture, `file-${counter++}`)}`
+
+//   await connection.sendNotification(new rpc.NotificationType('textDocument/didOpen'), {
+//     textDocument: {
+//       uri,
+//       languageId,
+//       version: 1,
+//       text,
+//     },
+//   })
+
+//   await initPromise
+
+//   return uri
+// }
+
+// export async function updateSettings(connection, newSettings) {
+//   settings = newSettings
+//   await connection.sendNotification(new rpc.NotificationType('workspace/didChangeConfiguration'))
+// }
I packages/tailwindcss-language-server/tests/completions/at-config.test.js
diff --git a/packages/tailwindcss-language-server/tests/completions/at-config.test.js b/packages/tailwindcss-language-server/tests/completions/at-config.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..5cbd283ce0fc30083043b13937771538a081b041
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/completions/at-config.test.js
@@ -0,0 +1,84 @@
+import { expect, test } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('dependencies', (c) => {
+  async function completion({
+    lang,
+    text,
+    position,
+    context = {
+      triggerKind: 1,
+    },
+    settings,
+  }) {
+    let textDocument = await c.openDocument({ text, lang, settings })
+
+    return c.sendRequest('textDocument/completion', {
+      textDocument,
+      position,
+      context,
+    })
+  }
+
+  test.concurrent('@config', async () => {
+    let result = await completion({
+      text: '@config "',
+      lang: 'css',
+      position: {
+        line: 0,
+        character: 9,
+      },
+    })
+
+    expect(result).toEqual({
+      isIncomplete: false,
+      items: [
+        {
+          label: 'sub-dir/',
+          kind: 19,
+          command: { command: 'editor.action.triggerSuggest', title: '' },
+          data: expect.anything(),
+          textEdit: {
+            newText: 'sub-dir/',
+            range: { start: { line: 0, character: 9 }, end: { line: 0, character: 9 } },
+          },
+        },
+        {
+          label: 'tailwind.config.js',
+          kind: 17,
+          data: expect.anything(),
+          textEdit: {
+            newText: 'tailwind.config.js',
+            range: { start: { line: 0, character: 9 }, end: { line: 0, character: 9 } },
+          },
+        },
+      ],
+    })
+  })
+
+  test.concurrent('@config directory', async () => {
+    let result = await completion({
+      text: '@config "./sub-dir/',
+      lang: 'css',
+      position: {
+        line: 0,
+        character: 19,
+      },
+    })
+
+    expect(result).toEqual({
+      isIncomplete: false,
+      items: [
+        {
+          label: 'colors.js',
+          kind: 17,
+          data: expect.anything(),
+          textEdit: {
+            newText: 'colors.js',
+            range: { start: { line: 0, character: 19 }, end: { line: 0, character: 19 } },
+          },
+        },
+      ],
+    })
+  })
+})
I packages/tailwindcss-language-server/tests/completions/completions.test.js
diff --git a/packages/tailwindcss-language-server/tests/completions/completions.test.js b/packages/tailwindcss-language-server/tests/completions/completions.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..df64d38d3d4285aa53282b62302226b8406d93ca
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/completions/completions.test.js
@@ -0,0 +1,121 @@
+import { expect, test } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('basic', (c) => {
+  async function completion({
+    lang,
+    text,
+    position,
+    context = {
+      triggerKind: 1,
+    },
+    settings,
+  }) {
+    let textDocument = await c.openDocument({ text, lang, settings })
+
+    return c.sendRequest('textDocument/completion', {
+      textDocument,
+      position,
+      context,
+    })
+  }
+
+  async function expectCompletions({ lang, text, position, settings }) {
+    let result = await completion({ lang, text, position, settings })
+    let textEdit = expect.objectContaining({ range: { start: position, end: position } })
+
+    expect(result.items.length).toBe(11175)
+    expect(result.items.filter((item) => item.label.endsWith(':')).length).toBe(157)
+    expect(result).toEqual({
+      isIncomplete: false,
+      items: expect.arrayContaining([
+        expect.objectContaining({ label: 'hover:', textEdit }),
+        expect.objectContaining({ label: 'uppercase', textEdit }),
+      ]),
+    })
+  }
+
+  test.concurrent('HTML', async () => {
+    await expectCompletions({ text: '<div class=""></div>', position: { line: 0, character: 12 } })
+  })
+
+  test.concurrent('JSX', async () => {
+    await expectCompletions({
+      lang: 'javascriptreact',
+      text: "<div className={''}></div>",
+      position: {
+        line: 0,
+        character: 17,
+      },
+    })
+  })
+
+  test.concurrent('JSX concatination', async () => {
+    await expectCompletions({
+      lang: 'javascriptreact',
+      text: "<div className={'' + ''}></div>",
+      position: {
+        line: 0,
+        character: 22,
+      },
+    })
+  })
+
+  test.concurrent('JSX outside strings', async () => {
+    let result = await completion({
+      lang: 'javascriptreact',
+      text: "<div className={'' + ''}></div>",
+      position: {
+        line: 0,
+        character: 18,
+      },
+    })
+    expect(result).toBe(null)
+  })
+
+  test.concurrent('classRegex simple', async () => {
+    await expectCompletions({
+      text: 'test ',
+      position: {
+        line: 0,
+        character: 5,
+      },
+      settings: { tailwindCSS: { experimental: { classRegex: ['test (\\S*)'] } } },
+    })
+  })
+
+  test.concurrent('classRegex nested', async () => {
+    await expectCompletions({
+      text: 'test ""',
+      position: {
+        line: 0,
+        character: 6,
+      },
+      settings: {
+        tailwindCSS: { experimental: { classRegex: [['test (\\S*)', '"([^"]*)"']] } },
+      },
+    })
+  })
+
+  test.concurrent('resolve', async () => {
+    let result = await completion({
+      text: '<div class="">',
+      position: {
+        line: 0,
+        character: 12,
+      },
+    })
+
+    let item = result.items.find((item) => item.label === 'uppercase')
+    let resolved = await c.sendRequest('completionItem/resolve', item)
+
+    expect(resolved).toEqual({
+      ...item,
+      detail: 'text-transform: uppercase;',
+      documentation: {
+        kind: 'markdown',
+        value: '```css\n.uppercase {\n  text-transform: uppercase;\n}\n```',
+      },
+    })
+  })
+})
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-prop.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-prop.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-prop.json
new file mode 100644
index 0000000000000000000000000000000000000000..8737ed083261df0c346727c7aa490642fdb53426
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-prop.json
@@ -0,0 +1,5 @@
+{
+  "code": ".test { @apply uppercase; color: red; @apply lowercase }",
+  "language": "css",
+  "expected": []
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-rule.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-rule.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-rule.json
new file mode 100644
index 0000000000000000000000000000000000000000..0b5934cf859351e7bb21955ddda00598541a5797
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css-multi-rule.json
@@ -0,0 +1,5 @@
+{
+  "code": ".test { @apply uppercase }\n.test { @apply lowercase }",
+  "language": "css",
+  "expected": []
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css.json
new file mode 100644
index 0000000000000000000000000000000000000000..da506bf12c36fb183ea52d82472c4114d119449d
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/css.json
@@ -0,0 +1,116 @@
+{
+  "code": ".test { @apply uppercase lowercase }",
+  "language": "css",
+  "expected": [
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "uppercase",
+        "classList": {
+          "classList": "uppercase lowercase",
+          "range": {
+            "start": { "line": 0, "character": 15 },
+            "end": { "line": 0, "character": 34 }
+          },
+          "important": false
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 9 }
+        },
+        "range": { "start": { "line": 0, "character": 15 }, "end": { "line": 0, "character": 24 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "lowercase",
+          "classList": {
+            "classList": "uppercase lowercase",
+            "range": {
+              "start": { "line": 0, "character": 15 },
+              "end": { "line": 0, "character": 34 }
+            },
+            "important": false
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 10 },
+            "end": { "line": 0, "character": 19 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 25 },
+            "end": { "line": 0, "character": 34 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 15 }, "end": { "line": 0, "character": 24 } },
+      "severity": 2,
+      "message": "'uppercase' applies the same CSS properties as 'lowercase'.",
+      "relatedInformation": [
+        {
+          "message": "lowercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 25 },
+              "end": { "line": 0, "character": 34 }
+            }
+          }
+        }
+      ]
+    },
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "lowercase",
+        "classList": {
+          "classList": "uppercase lowercase",
+          "range": {
+            "start": { "line": 0, "character": 15 },
+            "end": { "line": 0, "character": 34 }
+          },
+          "important": false
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 10 },
+          "end": { "line": 0, "character": 19 }
+        },
+        "range": { "start": { "line": 0, "character": 25 }, "end": { "line": 0, "character": 34 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "uppercase",
+          "classList": {
+            "classList": "uppercase lowercase",
+            "range": {
+              "start": { "line": 0, "character": 15 },
+              "end": { "line": 0, "character": 34 }
+            },
+            "important": false
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 0 },
+            "end": { "line": 0, "character": 9 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 15 },
+            "end": { "line": 0, "character": 24 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 25 }, "end": { "line": 0, "character": 34 } },
+      "severity": 2,
+      "message": "'lowercase' applies the same CSS properties as 'uppercase'.",
+      "relatedInformation": [
+        {
+          "message": "uppercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 15 },
+              "end": { "line": 0, "character": 24 }
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-negative.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-negative.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-negative.json
new file mode 100644
index 0000000000000000000000000000000000000000..981fba6e218d35881729f7142985f68c402bd61a
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-negative.json
@@ -0,0 +1,5 @@
+{
+  "code": "<div className={'lowercase' + 'uppercase'}>",
+  "language": "javascriptreact",
+  "expected": []
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-positive.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-positive.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-positive.json
new file mode 100644
index 0000000000000000000000000000000000000000..39cbb515a8e35ab2e72faff0daad15c0345d5296
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/jsx-concat-positive.json
@@ -0,0 +1,112 @@
+{
+  "code": "<div className={'lowercase uppercase' + 'uppercase'}>",
+  "language": "javascriptreact",
+  "expected": [
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "lowercase",
+        "classList": {
+          "classList": "lowercase uppercase",
+          "range": {
+            "start": { "line": 0, "character": 17 },
+            "end": { "line": 0, "character": 36 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 9 }
+        },
+        "range": { "start": { "line": 0, "character": 17 }, "end": { "line": 0, "character": 26 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "uppercase",
+          "classList": {
+            "classList": "lowercase uppercase",
+            "range": {
+              "start": { "line": 0, "character": 17 },
+              "end": { "line": 0, "character": 36 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 10 },
+            "end": { "line": 0, "character": 19 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 27 },
+            "end": { "line": 0, "character": 36 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 17 }, "end": { "line": 0, "character": 26 } },
+      "severity": 2,
+      "message": "'lowercase' applies the same CSS properties as 'uppercase'.",
+      "relatedInformation": [
+        {
+          "message": "uppercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 27 },
+              "end": { "line": 0, "character": 36 }
+            }
+          }
+        }
+      ]
+    },
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "uppercase",
+        "classList": {
+          "classList": "lowercase uppercase",
+          "range": {
+            "start": { "line": 0, "character": 17 },
+            "end": { "line": 0, "character": 36 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 10 },
+          "end": { "line": 0, "character": 19 }
+        },
+        "range": { "start": { "line": 0, "character": 27 }, "end": { "line": 0, "character": 36 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "lowercase",
+          "classList": {
+            "classList": "lowercase uppercase",
+            "range": {
+              "start": { "line": 0, "character": 17 },
+              "end": { "line": 0, "character": 36 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 0 },
+            "end": { "line": 0, "character": 9 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 17 },
+            "end": { "line": 0, "character": 26 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 27 }, "end": { "line": 0, "character": 36 } },
+      "severity": 2,
+      "message": "'uppercase' applies the same CSS properties as 'lowercase'.",
+      "relatedInformation": [
+        {
+          "message": "lowercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 17 },
+              "end": { "line": 0, "character": 26 }
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/simple.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/simple.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/simple.json
new file mode 100644
index 0000000000000000000000000000000000000000..c98280a1128496d3dc636c8e5fab969a3377a0fb
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/simple.json
@@ -0,0 +1,111 @@
+{
+  "code": "<div class=\"uppercase lowercase\"></div>",
+  "expected": [
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "uppercase",
+        "classList": {
+          "classList": "uppercase lowercase",
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 31 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 9 }
+        },
+        "range": { "start": { "line": 0, "character": 12 }, "end": { "line": 0, "character": 21 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "lowercase",
+          "classList": {
+            "classList": "uppercase lowercase",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 31 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 10 },
+            "end": { "line": 0, "character": 19 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 22 },
+            "end": { "line": 0, "character": 31 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 12 }, "end": { "line": 0, "character": 21 } },
+      "severity": 2,
+      "message": "'uppercase' applies the same CSS properties as 'lowercase'.",
+      "relatedInformation": [
+        {
+          "message": "lowercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 22 },
+              "end": { "line": 0, "character": 31 }
+            }
+          }
+        }
+      ]
+    },
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "lowercase",
+        "classList": {
+          "classList": "uppercase lowercase",
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 31 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 10 },
+          "end": { "line": 0, "character": 19 }
+        },
+        "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 31 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "uppercase",
+          "classList": {
+            "classList": "uppercase lowercase",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 31 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 0 },
+            "end": { "line": 0, "character": 9 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 21 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 22 }, "end": { "line": 0, "character": 31 } },
+      "severity": 2,
+      "message": "'lowercase' applies the same CSS properties as 'uppercase'.",
+      "relatedInformation": [
+        {
+          "message": "uppercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 21 }
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-negative.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-negative.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-negative.json
new file mode 100644
index 0000000000000000000000000000000000000000..a0d291861534e3b7a8163c150b91373f13883392
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-negative.json
@@ -0,0 +1,4 @@
+{
+  "code": "<div class=\"uppercase sm:lowercase\"></div>",
+  "expected": []
+}
I packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-positive.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-positive.json b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-positive.json
new file mode 100644
index 0000000000000000000000000000000000000000..15fcb45721459c129ce18cabb61b0e5cca506972
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/css-conflict/variants-positive.json
@@ -0,0 +1,111 @@
+{
+  "code": "<div class=\"sm:uppercase sm:lowercase\"></div>",
+  "expected": [
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "sm:uppercase",
+        "classList": {
+          "classList": "sm:uppercase sm:lowercase",
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 37 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 0 },
+          "end": { "line": 0, "character": 12 }
+        },
+        "range": { "start": { "line": 0, "character": 12 }, "end": { "line": 0, "character": 24 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "sm:lowercase",
+          "classList": {
+            "classList": "sm:uppercase sm:lowercase",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 37 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 13 },
+            "end": { "line": 0, "character": 25 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 25 },
+            "end": { "line": 0, "character": 37 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 12 }, "end": { "line": 0, "character": 24 } },
+      "severity": 2,
+      "message": "'sm:uppercase' applies the same CSS properties as 'sm:lowercase'.",
+      "relatedInformation": [
+        {
+          "message": "sm:lowercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 25 },
+              "end": { "line": 0, "character": 37 }
+            }
+          }
+        }
+      ]
+    },
+    {
+      "code": "cssConflict",
+      "className": {
+        "className": "sm:lowercase",
+        "classList": {
+          "classList": "sm:uppercase sm:lowercase",
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 37 }
+          }
+        },
+        "relativeRange": {
+          "start": { "line": 0, "character": 13 },
+          "end": { "line": 0, "character": 25 }
+        },
+        "range": { "start": { "line": 0, "character": 25 }, "end": { "line": 0, "character": 37 } }
+      },
+      "otherClassNames": [
+        {
+          "className": "sm:uppercase",
+          "classList": {
+            "classList": "sm:uppercase sm:lowercase",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 37 }
+            }
+          },
+          "relativeRange": {
+            "start": { "line": 0, "character": 0 },
+            "end": { "line": 0, "character": 12 }
+          },
+          "range": {
+            "start": { "line": 0, "character": 12 },
+            "end": { "line": 0, "character": 24 }
+          }
+        }
+      ],
+      "range": { "start": { "line": 0, "character": 25 }, "end": { "line": 0, "character": 37 } },
+      "severity": 2,
+      "message": "'sm:lowercase' applies the same CSS properties as 'sm:uppercase'.",
+      "relatedInformation": [
+        {
+          "message": "sm:uppercase",
+          "location": {
+            "uri": "{{URI}}",
+            "range": {
+              "start": { "line": 0, "character": 12 },
+              "end": { "line": 0, "character": 24 }
+            }
+          }
+        }
+      ]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js b/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..c53390e3aa7e2c735b62369269d3980e87485309
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/diagnostics.test.js
@@ -0,0 +1,37 @@
+import { expect, test } from 'vitest'
+import { withFixture } from '../common'
+import * as fs from 'node:fs/promises'
+
+withFixture('basic', (c) => {
+  function testFixture(fixture) {
+    test(fixture, async () => {
+      fixture = await fs.readFile(`tests/diagnostics/${fixture}.json`, 'utf8')
+
+      let { code, expected, language = 'html' } = JSON.parse(fixture)
+
+      let promise = new Promise((resolve) => {
+        c.onNotification('textDocument/publishDiagnostics', ({ diagnostics }) => {
+          resolve(diagnostics)
+        })
+      })
+
+      let doc = await c.openDocument({ text: code, lang: language })
+      let diagnostics = await promise
+
+      expected = JSON.parse(JSON.stringify(expected).replaceAll('{{URI}}', doc.uri))
+
+      expect(diagnostics).toEqual(expected)
+    })
+  }
+
+  testFixture('css-conflict/simple')
+  testFixture('css-conflict/variants-negative')
+  testFixture('css-conflict/variants-positive')
+  testFixture('css-conflict/jsx-concat-negative')
+  testFixture('css-conflict/jsx-concat-positive')
+  testFixture('css-conflict/css')
+  testFixture('css-conflict/css-multi-rule')
+  testFixture('css-conflict/css-multi-prop')
+  testFixture('invalid-screen/simple')
+  testFixture('invalid-theme/simple')
+})
I packages/tailwindcss-language-server/tests/diagnostics/invalid-screen/simple.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/invalid-screen/simple.json b/packages/tailwindcss-language-server/tests/diagnostics/invalid-screen/simple.json
new file mode 100644
index 0000000000000000000000000000000000000000..61974b86e468f0553b2b818b4a6f41db5a041aa3
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/invalid-screen/simple.json
@@ -0,0 +1,13 @@
+{
+  "code": "@screen small",
+  "language": "css",
+  "expected": [
+    {
+      "code": "invalidScreen",
+      "range": { "start": { "line": 0, "character": 8 }, "end": { "line": 0, "character": 13 } },
+      "severity": 1,
+      "message": "The screen 'small' does not exist in your theme config. Did you mean 'sm'?",
+      "suggestions": ["sm"]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/diagnostics/invalid-theme/simple.json
diff --git a/packages/tailwindcss-language-server/tests/diagnostics/invalid-theme/simple.json b/packages/tailwindcss-language-server/tests/diagnostics/invalid-theme/simple.json
new file mode 100644
index 0000000000000000000000000000000000000000..861a8b4eae6ca35055692b3b5a507ac37a8005dd
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/diagnostics/invalid-theme/simple.json
@@ -0,0 +1,13 @@
+{
+  "code": ".test { color: theme(colors.red.901) }",
+  "language": "css",
+  "expected": [
+    {
+      "code": "invalidConfigPath",
+      "range": { "start": { "line": 0, "character": 21 }, "end": { "line": 0, "character": 35 } },
+      "severity": 1,
+      "message": "'colors.red.901' does not exist in your theme config. Did you mean 'colors.red.900'?",
+      "suggestions": ["colors.red.900"]
+    }
+  ]
+}
I packages/tailwindcss-language-server/tests/document-links/document-links.test.js
diff --git a/packages/tailwindcss-language-server/tests/document-links/document-links.test.js b/packages/tailwindcss-language-server/tests/document-links/document-links.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..b1ee825ffdcf3bfd2ded228108c78614f6d26361
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/document-links/document-links.test.js
@@ -0,0 +1,42 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+import * as path from 'path'
+
+withFixture('basic', (c) => {
+  async function testDocumentLinks(name, { text, lang, expected }) {
+    test.concurrent(name, async () => {
+      let textDocument = await c.openDocument({ text, lang })
+      let res = await c.sendRequest('textDocument/documentLink', {
+        textDocument,
+      })
+
+      expect(res).toEqual(expected)
+    })
+  }
+
+  testDocumentLinks('file exists', {
+    text: '@config "tailwind.config.js";',
+    lang: 'css',
+    expected: [
+      {
+        target: `file://${path
+          .resolve('./tests/fixtures/basic/tailwind.config.js')
+          .replace(/@/g, '%40')}`,
+        range: { start: { line: 0, character: 8 }, end: { line: 0, character: 28 } },
+      },
+    ],
+  })
+
+  testDocumentLinks('file does not exist', {
+    text: '@config "does-not-exist.js";',
+    lang: 'css',
+    expected: [
+      {
+        target: `file://${path
+          .resolve('./tests/fixtures/basic/does-not-exist.js')
+          .replace(/@/g, '%40')}`,
+        range: { start: { line: 0, character: 8 }, end: { line: 0, character: 27 } },
+      },
+    ],
+  })
+})
I packages/tailwindcss-language-server/tests/env/multi-config-content.test.js
diff --git a/packages/tailwindcss-language-server/tests/env/multi-config-content.test.js b/packages/tailwindcss-language-server/tests/env/multi-config-content.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..a237bc3d4fff63a5df0c7782e179381123f211de
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/env/multi-config-content.test.js
@@ -0,0 +1,38 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('multi-config-content', (c) => {
+  test.concurrent('multi-config with content config - 1', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-foo">', dir: 'one' })
+    let res = await c.sendRequest('textDocument/hover', {
+      textDocument,
+      position: { line: 0, character: 13 },
+    })
+
+    expect(res).toEqual({
+      contents: {
+        language: 'css',
+        value:
+          '.bg-foo {\n  --tw-bg-opacity: 1;\n  background-color: rgb(255 0 0 / var(--tw-bg-opacity));\n}',
+      },
+      range: { start: { line: 0, character: 12 }, end: { line: 0, character: 18 } },
+    })
+  })
+
+  test.concurrent('multi-config with content config - 2', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-foo">', dir: 'two' })
+    let res = await c.sendRequest('textDocument/hover', {
+      textDocument,
+      position: { line: 0, character: 13 },
+    })
+
+    expect(res).toEqual({
+      contents: {
+        language: 'css',
+        value:
+          '.bg-foo {\n  --tw-bg-opacity: 1;\n  background-color: rgb(0 0 255 / var(--tw-bg-opacity));\n}',
+      },
+      range: { start: { line: 0, character: 12 }, end: { line: 0, character: 18 } },
+    })
+  })
+})
I packages/tailwindcss-language-server/tests/env/multi-config.test.js
diff --git a/packages/tailwindcss-language-server/tests/env/multi-config.test.js b/packages/tailwindcss-language-server/tests/env/multi-config.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..77799b3904b0fb7cbf90ed6226de114c4fc2ae6b
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/env/multi-config.test.js
@@ -0,0 +1,38 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('multi-config', (c) => {
+  test.concurrent('multi-config 1', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-foo">', dir: 'one' })
+    let res = await c.sendRequest('textDocument/hover', {
+      textDocument,
+      position: { line: 0, character: 13 },
+    })
+
+    expect(res).toEqual({
+      contents: {
+        language: 'css',
+        value:
+          '.bg-foo {\n  --tw-bg-opacity: 1;\n  background-color: rgb(255 0 0 / var(--tw-bg-opacity));\n}',
+      },
+      range: { start: { line: 0, character: 12 }, end: { line: 0, character: 18 } },
+    })
+  })
+
+  test.concurrent('multi-config 2', async () => {
+    let textDocument = await c.openDocument({ text: '<div class="bg-foo">', dir: 'two' })
+    let res = await c.sendRequest('textDocument/hover', {
+      textDocument,
+      position: { line: 0, character: 13 },
+    })
+
+    expect(res).toEqual({
+      contents: {
+        language: 'css',
+        value:
+          '.bg-foo {\n  --tw-bg-opacity: 1;\n  background-color: rgb(0 0 255 / var(--tw-bg-opacity));\n}',
+      },
+      range: { start: { line: 0, character: 12 }, end: { line: 0, character: 18 } },
+    })
+  })
+})
I packages/tailwindcss-language-server/tests/fixtures/basic/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/basic/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/basic/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ba52ba2c8df6758685c8f65f490306b5c44eb76
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/basic/tailwind.config.js
@@ -0,0 +1 @@
+module.exports = {}
I packages/tailwindcss-language-server/tests/fixtures/dependencies/sub-dir/colors.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/dependencies/sub-dir/colors.js b/packages/tailwindcss-language-server/tests/fixtures/dependencies/sub-dir/colors.js
new file mode 100644
index 0000000000000000000000000000000000000000..45baae148122fcd9bfa04e7f7a36d4db8bd391ef
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/dependencies/sub-dir/colors.js
@@ -0,0 +1,3 @@
+module.exports = {
+  foo: 'red',
+}
I packages/tailwindcss-language-server/tests/fixtures/dependencies/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/dependencies/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/dependencies/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..d37dff6cdb806bf07e44f157c357719fae08f853
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/dependencies/tailwind.config.js
@@ -0,0 +1,9 @@
+const colors = require('./sub-dir/colors')
+
+module.exports = {
+  theme: {
+    extend: {
+      colors,
+    },
+  },
+}
I packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.one.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.one.js b/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.one.js
new file mode 100644
index 0000000000000000000000000000000000000000..8dcd917501a563480f23e51f421718fe61c8b192
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.one.js
@@ -0,0 +1,10 @@
+module.exports = {
+  content: ['./one/**/*'],
+  theme: {
+    extend: {
+      colors: {
+        foo: 'red',
+      },
+    },
+  },
+}
I packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.two.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.two.js b/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.two.js
new file mode 100644
index 0000000000000000000000000000000000000000..5bb40c5787aef9af0ba1bd5df9779137404443e7
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/multi-config-content/tailwind.config.two.js
@@ -0,0 +1,10 @@
+module.exports = {
+  content: ['./two/**/*'],
+  theme: {
+    extend: {
+      colors: {
+        foo: 'blue',
+      },
+    },
+  },
+}
I packages/tailwindcss-language-server/tests/fixtures/multi-config/one/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/multi-config/one/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/multi-config/one/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..7a8b9df54ce613643f0b88a83cd2069c78428e97
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/multi-config/one/tailwind.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+  theme: {
+    extend: {
+      colors: {
+        foo: 'red',
+      },
+    },
+  },
+}
I packages/tailwindcss-language-server/tests/fixtures/multi-config/two/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/multi-config/two/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/multi-config/two/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..8a7355619a484f1f6a2c2ede54e68818fca49baa
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/multi-config/two/tailwind.config.js
@@ -0,0 +1,9 @@
+module.exports = {
+  theme: {
+    extend: {
+      colors: {
+        foo: 'blue',
+      },
+    },
+  },
+}
I packages/tailwindcss-language-server/tests/fixtures/v1/package-lock.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v1/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v1/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..136cc562db444f4556aebbdff876fceda3c365c6
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v1/package-lock.json
@@ -0,0 +1,1003 @@
+{
+  "name": "v1",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "tailwindcss": "1.9.6"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-2.3.0.tgz",
+      "integrity": "sha512-qnKm5dIOyPGJ70kPZ5jiz0I9foVOic0j+cOzNDoo8KoCf6HjicIZ99UfO2OmE7vCYSKAAepEwJtNzpiiZAh9xw==",
+      "dependencies": {
+        "postcss": "7.0.32",
+        "purgecss": "^2.3.0"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/chalk/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/postcss": {
+      "version": "7.0.32",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
+      "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+      "dependencies": {
+        "chalk": "^2.4.2",
+        "source-map": "^0.6.1",
+        "supports-color": "^6.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "tidelift",
+        "url": "https://tidelift.com/funding/github/npm/postcss"
+      }
+    },
+    "node_modules/@fullhuman/postcss-purgecss/node_modules/supports-color": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+      "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dependencies": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/autoprefixer": {
+      "version": "9.8.8",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.8.8.tgz",
+      "integrity": "sha512-eM9d/swFopRt5gdJ7jrpCwgvEMIayITpojhkkSMRsFHYuH5bkSQ4p/9qTEHtmNudUZh22Tehu7I6CxAW0IXTKA==",
+      "dependencies": {
+        "browserslist": "^4.12.0",
+        "caniuse-lite": "^1.0.30001109",
+        "normalize-range": "^0.1.2",
+        "num2fraction": "^1.2.2",
+        "picocolors": "^0.2.1",
+        "postcss": "^7.0.32",
+        "postcss-value-parser": "^4.1.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "funding": {
+        "type": "tidelift",
+        "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
+        "update-browserslist-db": "^1.0.11"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001523",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz",
+      "integrity": "sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ]
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/color": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+      "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+      "dependencies": {
+        "color-convert": "^1.9.3",
+        "color-string": "^1.6.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "node_modules/color/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/color/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/commander": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-5.1.0.tgz",
+      "integrity": "sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/css-unit-converter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+      "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/defined": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
+      "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/detective": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
+      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+      "dependencies": {
+        "acorn-node": "^1.8.2",
+        "defined": "^1.0.0",
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "detective": "bin/detective.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.502",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz",
+      "integrity": "sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw=="
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "8.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz",
+      "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^4.0.0",
+        "universalify": "^0.1.0"
+      },
+      "engines": {
+        "node": ">=6 <7 || >=8"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/html-tags": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+      "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+    },
+    "node_modules/is-core-module": {
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/jsonfile": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
+      "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==",
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/node-emoji": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
+      "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ=="
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize.css": {
+      "version": "8.0.1",
+      "resolved": "https://registry.npmjs.org/normalize.css/-/normalize.css-8.0.1.tgz",
+      "integrity": "sha512-qizSNPO93t1YUuUhP22btGOo3chcvDFqFaj2TRybP0DMxkHOCTYwp3n34fel4a31ORXy4m1Xq0Gyqpb5m33qIg=="
+    },
+    "node_modules/num2fraction": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
+      "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg=="
+    },
+    "node_modules/object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "node_modules/picocolors": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-0.2.1.tgz",
+      "integrity": "sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA=="
+    },
+    "node_modules/postcss": {
+      "version": "7.0.39",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.39.tgz",
+      "integrity": "sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA==",
+      "dependencies": {
+        "picocolors": "^0.2.1",
+        "source-map": "^0.6.1"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-functions": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/postcss-functions/-/postcss-functions-3.0.0.tgz",
+      "integrity": "sha512-N5yWXWKA+uhpLQ9ZhBRl2bIAdM6oVJYpDojuI1nF2SzXBimJcdjFwiAouBVbO5VuOF3qA6BSFWFc3wXbbj72XQ==",
+      "dependencies": {
+        "glob": "^7.1.2",
+        "object-assign": "^4.1.1",
+        "postcss": "^6.0.9",
+        "postcss-value-parser": "^3.3.0"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/postcss-functions/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/postcss": {
+      "version": "6.0.23",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
+      "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
+      "dependencies": {
+        "chalk": "^2.4.1",
+        "source-map": "^0.6.1",
+        "supports-color": "^5.4.0"
+      },
+      "engines": {
+        "node": ">=4.0.0"
+      }
+    },
+    "node_modules/postcss-functions/node_modules/postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+    },
+    "node_modules/postcss-functions/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-js": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-2.0.3.tgz",
+      "integrity": "sha512-zS59pAk3deu6dVHyrGqmC3oDXBdNdajk4k1RyxeVXCrcEDBUBHoIhE4QTsmhxgzXxsaqFDAkUZfmMa5f/N/79w==",
+      "dependencies": {
+        "camelcase-css": "^2.0.1",
+        "postcss": "^7.0.18"
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-4.2.3.tgz",
+      "integrity": "sha512-rOv0W1HquRCamWy2kFl3QazJMMe1ku6rCFoAAH+9AcxdbpDeBr6k968MLWuLjvjMcGEip01ak09hKOEgpK9hvw==",
+      "dependencies": {
+        "postcss": "^7.0.32",
+        "postcss-selector-parser": "^6.0.2"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.0.13",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+      "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+    },
+    "node_modules/pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/purgecss": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-2.3.0.tgz",
+      "integrity": "sha512-BE5CROfVGsx2XIhxGuZAT7rTH9lLeQx/6M0P7DTXQH4IUc3BBzs9JUzt4yzGf3JrH9enkeq6YJBe9CTtkm1WmQ==",
+      "dependencies": {
+        "commander": "^5.0.0",
+        "glob": "^7.0.0",
+        "postcss": "7.0.32",
+        "postcss-selector-parser": "^6.0.2"
+      },
+      "bin": {
+        "purgecss": "bin/purgecss"
+      }
+    },
+    "node_modules/purgecss/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/purgecss/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/purgecss/node_modules/chalk/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/purgecss/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/purgecss/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/purgecss/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/purgecss/node_modules/postcss": {
+      "version": "7.0.32",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.32.tgz",
+      "integrity": "sha512-03eXong5NLnNCD05xscnGKGDZ98CyzoqPSMjOe6SuoQY7Z2hIj0Ld1g/O/UQRuOle2aRtiIRDg9tDcTGAkLfKw==",
+      "dependencies": {
+        "chalk": "^2.4.2",
+        "source-map": "^0.6.1",
+        "supports-color": "^6.1.0"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      },
+      "funding": {
+        "type": "tidelift",
+        "url": "https://tidelift.com/funding/github/npm/postcss"
+      }
+    },
+    "node_modules/purgecss/node_modules/supports-color": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz",
+      "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/reduce-css-calc": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+      "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+      "dependencies": {
+        "css-unit-converter": "^1.1.1",
+        "postcss-value-parser": "^3.3.0"
+      }
+    },
+    "node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+    },
+    "node_modules/resolve": {
+      "version": "1.22.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+      "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/source-map": {
+      "version": "0.6.1",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+      "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "1.9.6",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-1.9.6.tgz",
+      "integrity": "sha512-nY8WYM/RLPqGsPEGEV2z63riyQPcHYZUJpAwdyBzVpxQHOHqHE+F/fvbCeXhdF1+TA5l72vSkZrtYCB9hRcwkQ==",
+      "dependencies": {
+        "@fullhuman/postcss-purgecss": "^2.1.2",
+        "autoprefixer": "^9.4.5",
+        "browserslist": "^4.12.0",
+        "bytes": "^3.0.0",
+        "chalk": "^3.0.0 || ^4.0.0",
+        "color": "^3.1.2",
+        "detective": "^5.2.0",
+        "fs-extra": "^8.0.0",
+        "html-tags": "^3.1.0",
+        "lodash": "^4.17.20",
+        "node-emoji": "^1.8.1",
+        "normalize.css": "^8.0.1",
+        "object-hash": "^2.0.3",
+        "postcss": "^7.0.11",
+        "postcss-functions": "^3.0.0",
+        "postcss-js": "^2.0.0",
+        "postcss-nested": "^4.1.1",
+        "postcss-selector-parser": "^6.0.0",
+        "postcss-value-parser": "^4.1.0",
+        "pretty-hrtime": "^1.0.3",
+        "reduce-css-calc": "^2.1.6",
+        "resolve": "^1.14.2"
+      },
+      "bin": {
+        "tailwind": "lib/cli.js",
+        "tailwindcss": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=8.9.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
+      "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==",
+      "engines": {
+        "node": ">= 4.0.0"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/update-browserslist-db/node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "engines": {
+        "node": ">=0.4"
+      }
+    }
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v1/package.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v1/package.json b/packages/tailwindcss-language-server/tests/fixtures/v1/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..d45472f7d1328322119289b202d2ffad3f5cb9c3
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v1/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "tailwindcss": "1.9.6"
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v1/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v1/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/v1/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ba52ba2c8df6758685c8f65f490306b5c44eb76
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v1/tailwind.config.js
@@ -0,0 +1 @@
+module.exports = {}
I packages/tailwindcss-language-server/tests/fixtures/v2-jit/package-lock.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..1cf4c6d814492d19e9fc7e302ef3e1734234efa6
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package-lock.json
@@ -0,0 +1,1540 @@
+{
+  "name": "v2",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "tailwindcss": "2.2.19"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
+      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
+      "dependencies": {
+        "@babel/highlight": "^7.22.10",
+        "chalk": "^2.4.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/@babel/code-frame/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
+      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
+      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.22.5",
+        "chalk": "^2.4.2",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/@babel/highlight/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
+    },
+    "node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dependencies": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.15",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
+      "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.21.10",
+        "caniuse-lite": "^1.0.30001520",
+        "fraction.js": "^4.2.0",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
+        "update-browserslist-db": "^1.0.11"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001523",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz",
+      "integrity": "sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chokidar/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/color": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+      "dependencies": {
+        "color-convert": "^2.0.1",
+        "color-string": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=12.5.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "node_modules/commander": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+      "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/cosmiconfig": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+      "dependencies": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/css-color-names": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+      "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/css-unit-converter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+      "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/defined": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
+      "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/detective": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
+      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+      "dependencies": {
+        "acorn-node": "^1.8.2",
+        "defined": "^1.0.0",
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "detective": "bin/detective.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/didyoumean": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+    },
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.502",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz",
+      "integrity": "sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw==",
+      "peer": true
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.1.tgz",
+      "integrity": "sha512-/KxoyCnPM0GwYI4NN0Iag38Tqt+od3/mLuguepLgCAKPn0ZhC544nssAW0tG2/00zXEYl9W+7hwAIpLHo6Oc7Q==",
+      "peer": true,
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://www.patreon.com/infusion"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/hex-color-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
+      "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
+    },
+    "node_modules/hsl-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
+      "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A=="
+    },
+    "node_modules/hsla-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
+      "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA=="
+    },
+    "node_modules/html-tags": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+      "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-color-stop": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
+      "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==",
+      "dependencies": {
+        "css-color-names": "^0.0.4",
+        "hex-color-regex": "^1.1.0",
+        "hsl-regex": "^1.0.0",
+        "hsla-regex": "^1.0.0",
+        "rgb-regex": "^1.0.1",
+        "rgba-regex": "^1.0.0"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+    },
+    "node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/lilconfig": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+      "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lodash.topath": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
+      "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg=="
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/modern-normalize": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
+      "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/node-emoji": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
+      "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
+      "peer": true
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.28",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+      "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.6",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-js": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz",
+      "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==",
+      "dependencies": {
+        "camelcase-css": "^2.0.1",
+        "postcss": "^8.1.6"
+      },
+      "engines": {
+        "node": ">=10.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-load-config": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+      "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+      "dependencies": {
+        "lilconfig": "^2.0.5",
+        "yaml": "^1.10.2"
+      },
+      "engines": {
+        "node": ">= 10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": ">=8.0.9",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "postcss": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "5.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz",
+      "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==",
+      "dependencies": {
+        "postcss-selector-parser": "^6.0.6"
+      },
+      "engines": {
+        "node": ">=12.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": "^8.2.14"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.0.13",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+      "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+    },
+    "node_modules/pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/purgecss": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz",
+      "integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==",
+      "dependencies": {
+        "commander": "^8.0.0",
+        "glob": "^7.1.7",
+        "postcss": "^8.3.5",
+        "postcss-selector-parser": "^6.0.6"
+      },
+      "bin": {
+        "purgecss": "bin/purgecss.js"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/reduce-css-calc": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+      "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+      "dependencies": {
+        "css-unit-converter": "^1.1.1",
+        "postcss-value-parser": "^3.3.0"
+      }
+    },
+    "node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+    },
+    "node_modules/resolve": {
+      "version": "1.22.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+      "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rgb-regex": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
+      "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w=="
+    },
+    "node_modules/rgba-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
+      "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg=="
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/simple-swizzle/node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+    },
+    "node_modules/source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "2.2.19",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.19.tgz",
+      "integrity": "sha512-6Ui7JSVtXadtTUo2NtkBBacobzWiQYVjYW0ZnKaP9S1ZCKQ0w7KVNz+YSDI/j7O7KCMHbOkz94ZMQhbT9pOqjw==",
+      "dependencies": {
+        "arg": "^5.0.1",
+        "bytes": "^3.0.0",
+        "chalk": "^4.1.2",
+        "chokidar": "^3.5.2",
+        "color": "^4.0.1",
+        "cosmiconfig": "^7.0.1",
+        "detective": "^5.2.0",
+        "didyoumean": "^1.2.2",
+        "dlv": "^1.1.3",
+        "fast-glob": "^3.2.7",
+        "fs-extra": "^10.0.0",
+        "glob-parent": "^6.0.1",
+        "html-tags": "^3.1.0",
+        "is-color-stop": "^1.1.0",
+        "is-glob": "^4.0.1",
+        "lodash": "^4.17.21",
+        "lodash.topath": "^4.5.2",
+        "modern-normalize": "^1.1.0",
+        "node-emoji": "^1.11.0",
+        "normalize-path": "^3.0.0",
+        "object-hash": "^2.2.0",
+        "postcss-js": "^3.0.3",
+        "postcss-load-config": "^3.1.0",
+        "postcss-nested": "5.0.6",
+        "postcss-selector-parser": "^6.0.6",
+        "postcss-value-parser": "^4.1.0",
+        "pretty-hrtime": "^1.0.3",
+        "purgecss": "^4.0.3",
+        "quick-lru": "^5.1.1",
+        "reduce-css-calc": "^2.1.8",
+        "resolve": "^1.20.0",
+        "tmp": "^0.2.1"
+      },
+      "bin": {
+        "tailwind": "lib/cli.js",
+        "tailwindcss": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=12.13.0"
+      },
+      "peerDependencies": {
+        "autoprefixer": "^10.0.2",
+        "postcss": "^8.0.9"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "dependencies": {
+        "rimraf": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8.17.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "engines": {
+        "node": ">= 6"
+      }
+    }
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v2-jit/package.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package.json b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..62fab22d0e3d6a2a10b778f03231df910f11d303
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "tailwindcss": "2.2.19"
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v2-jit/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2-jit/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..066c240c906ba33eb03740a5181307f22bb204aa
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2-jit/tailwind.config.js
@@ -0,0 +1,3 @@
+module.exports = {
+  mode: 'jit',
+}
I packages/tailwindcss-language-server/tests/fixtures/v2/package-lock.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2/package-lock.json b/packages/tailwindcss-language-server/tests/fixtures/v2/package-lock.json
new file mode 100644
index 0000000000000000000000000000000000000000..1cf4c6d814492d19e9fc7e302ef3e1734234efa6
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2/package-lock.json
@@ -0,0 +1,1540 @@
+{
+  "name": "v2",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "dependencies": {
+        "tailwindcss": "2.2.19"
+      }
+    },
+    "node_modules/@babel/code-frame": {
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.10.tgz",
+      "integrity": "sha512-/KKIMG4UEL35WmI9OlvMhurwtytjvXoFcGNrOvyG9zIzA8YmPjVtIZUf7b05+TPO7G7/GEmLHDaoCgACHl9hhA==",
+      "dependencies": {
+        "@babel/highlight": "^7.22.10",
+        "chalk": "^2.4.2"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/@babel/code-frame/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/code-frame/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.22.5",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.5.tgz",
+      "integrity": "sha512-aJXu+6lErq8ltp+JhkJUfk1MTGyuA4v7f3pA+BJ5HLfNC6nAQ0Cpi9uOquUj8Hehg0aUiHzWQbOVJGao6ztBAQ==",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight": {
+      "version": "7.22.10",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.10.tgz",
+      "integrity": "sha512-78aUtVcT7MUscr0K5mIEnkwxPE0MaxkR5RxRwuHaQ+JuU5AmTPhY+do2mdzVTnIJJpyBglql2pehuBIWHug+WQ==",
+      "dependencies": {
+        "@babel/helper-validator-identifier": "^7.22.5",
+        "chalk": "^2.4.2",
+        "js-tokens": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dependencies": {
+        "color-convert": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dependencies": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dependencies": {
+        "color-name": "1.1.3"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
+    },
+    "node_modules/@babel/highlight/node_modules/has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@babel/highlight/node_modules/supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dependencies": {
+        "has-flag": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/@nodelib/fs.scandir": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
+      "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==",
+      "dependencies": {
+        "@nodelib/fs.stat": "2.0.5",
+        "run-parallel": "^1.1.9"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.stat": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz",
+      "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@nodelib/fs.walk": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz",
+      "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==",
+      "dependencies": {
+        "@nodelib/fs.scandir": "2.1.5",
+        "fastq": "^1.6.0"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/@types/parse-json": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz",
+      "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
+    },
+    "node_modules/acorn": {
+      "version": "7.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
+      "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
+      "bin": {
+        "acorn": "bin/acorn"
+      },
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/acorn-node": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
+      "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
+      "dependencies": {
+        "acorn": "^7.0.0",
+        "acorn-walk": "^7.0.0",
+        "xtend": "^4.0.2"
+      }
+    },
+    "node_modules/acorn-walk": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+      "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
+      "engines": {
+        "node": ">=0.4.0"
+      }
+    },
+    "node_modules/ansi-styles": {
+      "version": "4.3.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+      "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+      "dependencies": {
+        "color-convert": "^2.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+      }
+    },
+    "node_modules/anymatch": {
+      "version": "3.1.3",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+      "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+      "dependencies": {
+        "normalize-path": "^3.0.0",
+        "picomatch": "^2.0.4"
+      },
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/arg": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
+      "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+    },
+    "node_modules/autoprefixer": {
+      "version": "10.4.15",
+      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.15.tgz",
+      "integrity": "sha512-KCuPB8ZCIqFdA4HwKXsvz7j6gvSDNhDP7WnUjBleRkKjPdvCmHFuQ77ocavI8FT6NdvlBnE2UFr2H4Mycn8Vew==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/autoprefixer"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "browserslist": "^4.21.10",
+        "caniuse-lite": "^1.0.30001520",
+        "fraction.js": "^4.2.0",
+        "normalize-range": "^0.1.2",
+        "picocolors": "^1.0.0",
+        "postcss-value-parser": "^4.2.0"
+      },
+      "bin": {
+        "autoprefixer": "bin/autoprefixer"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      },
+      "peerDependencies": {
+        "postcss": "^8.1.0"
+      }
+    },
+    "node_modules/balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+    },
+    "node_modules/binary-extensions": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
+      "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dependencies": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "node_modules/braces": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz",
+      "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
+      "dependencies": {
+        "fill-range": "^7.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/browserslist": {
+      "version": "4.21.10",
+      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.10.tgz",
+      "integrity": "sha512-bipEBdZfVH5/pwrvqc+Ub0kUPVfGUhlKxbvfD+z1BDnPEO/X98ruXGA1WP5ASpAFKan7Qr6j736IacbZQuAlKQ==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "caniuse-lite": "^1.0.30001517",
+        "electron-to-chromium": "^1.4.477",
+        "node-releases": "^2.0.13",
+        "update-browserslist-db": "^1.0.11"
+      },
+      "bin": {
+        "browserslist": "cli.js"
+      },
+      "engines": {
+        "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7"
+      }
+    },
+    "node_modules/bytes": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+      "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/callsites": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
+      "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/camelcase-css": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
+      "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/caniuse-lite": {
+      "version": "1.0.30001523",
+      "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001523.tgz",
+      "integrity": "sha512-I5q5cisATTPZ1mc588Z//pj/Ox80ERYDfR71YnvY7raS/NOk8xXlZcB0sF7JdqaV//kOaa6aus7lRfpdnt1eBA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/caniuse-lite"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true
+    },
+    "node_modules/chalk": {
+      "version": "4.1.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+      "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+      "dependencies": {
+        "ansi-styles": "^4.1.0",
+        "supports-color": "^7.1.0"
+      },
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/chalk/chalk?sponsor=1"
+      }
+    },
+    "node_modules/chokidar": {
+      "version": "3.5.3",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
+      "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
+      "funding": [
+        {
+          "type": "individual",
+          "url": "https://paulmillr.com/funding/"
+        }
+      ],
+      "dependencies": {
+        "anymatch": "~3.1.2",
+        "braces": "~3.0.2",
+        "glob-parent": "~5.1.2",
+        "is-binary-path": "~2.1.0",
+        "is-glob": "~4.0.1",
+        "normalize-path": "~3.0.0",
+        "readdirp": "~3.6.0"
+      },
+      "engines": {
+        "node": ">= 8.10.0"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/chokidar/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/color": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+      "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+      "dependencies": {
+        "color-convert": "^2.0.1",
+        "color-string": "^1.9.0"
+      },
+      "engines": {
+        "node": ">=12.5.0"
+      }
+    },
+    "node_modules/color-convert": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+      "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+      "dependencies": {
+        "color-name": "~1.1.4"
+      },
+      "engines": {
+        "node": ">=7.0.0"
+      }
+    },
+    "node_modules/color-name": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+    },
+    "node_modules/color-string": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+      "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+      "dependencies": {
+        "color-name": "^1.0.0",
+        "simple-swizzle": "^0.2.2"
+      }
+    },
+    "node_modules/commander": {
+      "version": "8.3.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz",
+      "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==",
+      "engines": {
+        "node": ">= 12"
+      }
+    },
+    "node_modules/concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+    },
+    "node_modules/cosmiconfig": {
+      "version": "7.1.0",
+      "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
+      "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==",
+      "dependencies": {
+        "@types/parse-json": "^4.0.0",
+        "import-fresh": "^3.2.1",
+        "parse-json": "^5.0.0",
+        "path-type": "^4.0.0",
+        "yaml": "^1.10.0"
+      },
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/css-color-names": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
+      "integrity": "sha512-zj5D7X1U2h2zsXOAM8EyUREBnnts6H+Jm+d1M2DbiQQcUtnqgQsMrdo8JW9R80YFUmIdBZeMu5wvYM7hcgWP/Q==",
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/css-unit-converter": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
+      "integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
+    },
+    "node_modules/cssesc": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
+      "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
+      "bin": {
+        "cssesc": "bin/cssesc"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/defined": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.1.tgz",
+      "integrity": "sha512-hsBd2qSVCRE+5PmNdHt1uzyrFu5d3RwmFDKzyNZMFq/EwDNJF7Ee5+D5oEKF0hU6LhtoUF1macFvOe4AskQC1Q==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/detective": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.1.tgz",
+      "integrity": "sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==",
+      "dependencies": {
+        "acorn-node": "^1.8.2",
+        "defined": "^1.0.0",
+        "minimist": "^1.2.6"
+      },
+      "bin": {
+        "detective": "bin/detective.js"
+      },
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/didyoumean": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
+      "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+    },
+    "node_modules/dlv": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
+      "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+    },
+    "node_modules/electron-to-chromium": {
+      "version": "1.4.502",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.502.tgz",
+      "integrity": "sha512-xqeGw3Gr6o3uyHy/yKjdnDQHY2RQvXcGC2cfHjccK1IGkH6cX1WQBN8EeC/YpwPhGkBaikDTecJ8+ssxSVRQlw==",
+      "peer": true
+    },
+    "node_modules/error-ex": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
+      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
+      "dependencies": {
+        "is-arrayish": "^0.2.1"
+      }
+    },
+    "node_modules/escalade": {
+      "version": "3.1.1",
+      "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
+      "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==",
+      "peer": true,
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+      "engines": {
+        "node": ">=0.8.0"
+      }
+    },
+    "node_modules/fast-glob": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+      "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+      "dependencies": {
+        "@nodelib/fs.stat": "^2.0.2",
+        "@nodelib/fs.walk": "^1.2.3",
+        "glob-parent": "^5.1.2",
+        "merge2": "^1.3.0",
+        "micromatch": "^4.0.4"
+      },
+      "engines": {
+        "node": ">=8.6.0"
+      }
+    },
+    "node_modules/fast-glob/node_modules/glob-parent": {
+      "version": "5.1.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+      "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+      "dependencies": {
+        "is-glob": "^4.0.1"
+      },
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/fastq": {
+      "version": "1.15.0",
+      "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz",
+      "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==",
+      "dependencies": {
+        "reusify": "^1.0.4"
+      }
+    },
+    "node_modules/fill-range": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
+      "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
+      "dependencies": {
+        "to-regex-range": "^5.0.1"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/fraction.js": {
+      "version": "4.2.1",
+      "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.2.1.tgz",
+      "integrity": "sha512-/KxoyCnPM0GwYI4NN0Iag38Tqt+od3/mLuguepLgCAKPn0ZhC544nssAW0tG2/00zXEYl9W+7hwAIpLHo6Oc7Q==",
+      "peer": true,
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "type": "patreon",
+        "url": "https://www.patreon.com/infusion"
+      }
+    },
+    "node_modules/fs-extra": {
+      "version": "10.1.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
+      "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
+      "dependencies": {
+        "graceful-fs": "^4.2.0",
+        "jsonfile": "^6.0.1",
+        "universalify": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "hasInstallScript": true,
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "node_modules/glob": {
+      "version": "7.2.3",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+      "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+      "dependencies": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.1.1",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      },
+      "engines": {
+        "node": "*"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/glob-parent": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+      "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+      "dependencies": {
+        "is-glob": "^4.0.3"
+      },
+      "engines": {
+        "node": ">=10.13.0"
+      }
+    },
+    "node_modules/graceful-fs": {
+      "version": "4.2.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+      "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
+    },
+    "node_modules/has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dependencies": {
+        "function-bind": "^1.1.1"
+      },
+      "engines": {
+        "node": ">= 0.4.0"
+      }
+    },
+    "node_modules/has-flag": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+      "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/hex-color-regex": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/hex-color-regex/-/hex-color-regex-1.1.0.tgz",
+      "integrity": "sha512-l9sfDFsuqtOqKDsQdqrMRk0U85RZc0RtOR9yPI7mRVOa4FsR/BVnZ0shmQRM96Ji99kYZP/7hn1cedc1+ApsTQ=="
+    },
+    "node_modules/hsl-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsl-regex/-/hsl-regex-1.0.0.tgz",
+      "integrity": "sha512-M5ezZw4LzXbBKMruP+BNANf0k+19hDQMgpzBIYnya//Al+fjNct9Wf3b1WedLqdEs2hKBvxq/jh+DsHJLj0F9A=="
+    },
+    "node_modules/hsla-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/hsla-regex/-/hsla-regex-1.0.0.tgz",
+      "integrity": "sha512-7Wn5GMLuHBjZCb2bTmnDOycho0p/7UVaAeqXZGbHrBCl6Yd/xDhQJAXe6Ga9AXJH2I5zY1dEdYw2u1UptnSBJA=="
+    },
+    "node_modules/html-tags": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.3.1.tgz",
+      "integrity": "sha512-ztqyC3kLto0e9WbNp0aeP+M3kTt+nbaIveGmUxAtZa+8iFgKLUOD4YKM5j+f3QD89bra7UeumolZHKuOXnTmeQ==",
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/import-fresh": {
+      "version": "3.3.0",
+      "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
+      "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
+      "dependencies": {
+        "parent-module": "^1.0.0",
+        "resolve-from": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+      "dependencies": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "node_modules/inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "node_modules/is-arrayish": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
+      "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg=="
+    },
+    "node_modules/is-binary-path": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+      "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+      "dependencies": {
+        "binary-extensions": "^2.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/is-color-stop": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-color-stop/-/is-color-stop-1.1.0.tgz",
+      "integrity": "sha512-H1U8Vz0cfXNujrJzEcvvwMDW9Ra+biSYA3ThdQvAnMLJkEHQXn6bWzLkxHtVYJ+Sdbx0b6finn3jZiaVe7MAHA==",
+      "dependencies": {
+        "css-color-names": "^0.0.4",
+        "hex-color-regex": "^1.1.0",
+        "hsl-regex": "^1.0.0",
+        "hsla-regex": "^1.0.0",
+        "rgb-regex": "^1.0.1",
+        "rgba-regex": "^1.0.0"
+      }
+    },
+    "node_modules/is-core-module": {
+      "version": "2.13.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.0.tgz",
+      "integrity": "sha512-Z7dk6Qo8pOCp3l4tsX2C5ZVas4V+UxwQodwZhLopL91TX8UyyHEXafPcyoeeWuLrwzHcr3igO78wNLwHJHsMCQ==",
+      "dependencies": {
+        "has": "^1.0.3"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-number": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+      "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+      "engines": {
+        "node": ">=0.12.0"
+      }
+    },
+    "node_modules/js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+    },
+    "node_modules/json-parse-even-better-errors": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
+      "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+    },
+    "node_modules/jsonfile": {
+      "version": "6.1.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz",
+      "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
+      "dependencies": {
+        "universalify": "^2.0.0"
+      },
+      "optionalDependencies": {
+        "graceful-fs": "^4.1.6"
+      }
+    },
+    "node_modules/lilconfig": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
+      "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+      "engines": {
+        "node": ">=10"
+      }
+    },
+    "node_modules/lines-and-columns": {
+      "version": "1.2.4",
+      "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
+      "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+    },
+    "node_modules/lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "node_modules/lodash.topath": {
+      "version": "4.5.2",
+      "resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
+      "integrity": "sha512-1/W4dM+35DwvE/iEd1M9ekewOSTlpFekhw9mhAtrwjVqUr83/ilQiyAvmg4tVX7Unkcfl1KC+i9WdaT4B6aQcg=="
+    },
+    "node_modules/merge2": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
+      "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+      "engines": {
+        "node": ">= 8"
+      }
+    },
+    "node_modules/micromatch": {
+      "version": "4.0.5",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
+      "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
+      "dependencies": {
+        "braces": "^3.0.2",
+        "picomatch": "^2.3.1"
+      },
+      "engines": {
+        "node": ">=8.6"
+      }
+    },
+    "node_modules/minimatch": {
+      "version": "3.1.2",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+      "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+      "dependencies": {
+        "brace-expansion": "^1.1.7"
+      },
+      "engines": {
+        "node": "*"
+      }
+    },
+    "node_modules/minimist": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+      "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/modern-normalize": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
+      "integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
+      "engines": {
+        "node": ">=6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.6",
+      "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
+      "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "bin": {
+        "nanoid": "bin/nanoid.cjs"
+      },
+      "engines": {
+        "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+      }
+    },
+    "node_modules/node-emoji": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.11.0.tgz",
+      "integrity": "sha512-wo2DpQkQp7Sjm2A0cq+sN7EHKO6Sl0ctXeBdFZrL9T9+UywORbufTcTZxom8YqpLQt/FqNMUkOpkZrJVYSKD3A==",
+      "dependencies": {
+        "lodash": "^4.17.21"
+      }
+    },
+    "node_modules/node-releases": {
+      "version": "2.0.13",
+      "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz",
+      "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==",
+      "peer": true
+    },
+    "node_modules/normalize-path": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+      "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/normalize-range": {
+      "version": "0.1.2",
+      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
+      "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==",
+      "peer": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/object-hash": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
+      "integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
+      "engines": {
+        "node": ">= 6"
+      }
+    },
+    "node_modules/once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+      "dependencies": {
+        "wrappy": "1"
+      }
+    },
+    "node_modules/parent-module": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
+      "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==",
+      "dependencies": {
+        "callsites": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=6"
+      }
+    },
+    "node_modules/parse-json": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
+      "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
+      "dependencies": {
+        "@babel/code-frame": "^7.0.0",
+        "error-ex": "^1.3.1",
+        "json-parse-even-better-errors": "^2.3.0",
+        "lines-and-columns": "^1.1.6"
+      },
+      "engines": {
+        "node": ">=8"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+    },
+    "node_modules/path-type": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
+      "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/picocolors": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
+      "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+    },
+    "node_modules/picomatch": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+      "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+      "engines": {
+        "node": ">=8.6"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.4.28",
+      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz",
+      "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/postcss/"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/postcss"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "dependencies": {
+        "nanoid": "^3.3.6",
+        "picocolors": "^1.0.0",
+        "source-map-js": "^1.0.2"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/postcss-js": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz",
+      "integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==",
+      "dependencies": {
+        "camelcase-css": "^2.0.1",
+        "postcss": "^8.1.6"
+      },
+      "engines": {
+        "node": ">=10.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      }
+    },
+    "node_modules/postcss-load-config": {
+      "version": "3.1.4",
+      "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz",
+      "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==",
+      "dependencies": {
+        "lilconfig": "^2.0.5",
+        "yaml": "^1.10.2"
+      },
+      "engines": {
+        "node": ">= 10"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": ">=8.0.9",
+        "ts-node": ">=9.0.0"
+      },
+      "peerDependenciesMeta": {
+        "postcss": {
+          "optional": true
+        },
+        "ts-node": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/postcss-nested": {
+      "version": "5.0.6",
+      "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.6.tgz",
+      "integrity": "sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==",
+      "dependencies": {
+        "postcss-selector-parser": "^6.0.6"
+      },
+      "engines": {
+        "node": ">=12.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/postcss/"
+      },
+      "peerDependencies": {
+        "postcss": "^8.2.14"
+      }
+    },
+    "node_modules/postcss-selector-parser": {
+      "version": "6.0.13",
+      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz",
+      "integrity": "sha512-EaV1Gl4mUEV4ddhDnv/xtj7sxwrwxdetHdWUGnT4VJQf+4d05v6lHYZr8N573k5Z0BViss7BDhfWtKS3+sfAqQ==",
+      "dependencies": {
+        "cssesc": "^3.0.0",
+        "util-deprecate": "^1.0.2"
+      },
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/postcss-value-parser": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
+      "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+    },
+    "node_modules/pretty-hrtime": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
+      "integrity": "sha512-66hKPCr+72mlfiSjlEB1+45IjXSqvVAIy6mocupoww4tBFE9R9IhwwUGoI4G++Tc9Aq+2rxOt0RFU6gPcrte0A==",
+      "engines": {
+        "node": ">= 0.8"
+      }
+    },
+    "node_modules/purgecss": {
+      "version": "4.1.3",
+      "resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.1.3.tgz",
+      "integrity": "sha512-99cKy4s+VZoXnPxaoM23e5ABcP851nC2y2GROkkjS8eJaJtlciGavd7iYAw2V84WeBqggZ12l8ef44G99HmTaw==",
+      "dependencies": {
+        "commander": "^8.0.0",
+        "glob": "^7.1.7",
+        "postcss": "^8.3.5",
+        "postcss-selector-parser": "^6.0.6"
+      },
+      "bin": {
+        "purgecss": "bin/purgecss.js"
+      }
+    },
+    "node_modules/queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ]
+    },
+    "node_modules/quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
+      "engines": {
+        "node": ">=10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/sindresorhus"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+      "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+      "dependencies": {
+        "picomatch": "^2.2.1"
+      },
+      "engines": {
+        "node": ">=8.10.0"
+      }
+    },
+    "node_modules/reduce-css-calc": {
+      "version": "2.1.8",
+      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
+      "integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
+      "dependencies": {
+        "css-unit-converter": "^1.1.1",
+        "postcss-value-parser": "^3.3.0"
+      }
+    },
+    "node_modules/reduce-css-calc/node_modules/postcss-value-parser": {
+      "version": "3.3.1",
+      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
+      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
+    },
+    "node_modules/resolve": {
+      "version": "1.22.4",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.4.tgz",
+      "integrity": "sha512-PXNdCiPqDqeUou+w1C2eTQbNfxKSuMxqTCuvlmmMsk1NWHL5fRrhY6Pl0qEYYc6+QqGClco1Qj8XnjPego4wfg==",
+      "dependencies": {
+        "is-core-module": "^2.13.0",
+        "path-parse": "^1.0.7",
+        "supports-preserve-symlinks-flag": "^1.0.0"
+      },
+      "bin": {
+        "resolve": "bin/resolve"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/resolve-from": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
+      "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
+      "engines": {
+        "node": ">=4"
+      }
+    },
+    "node_modules/reusify": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+      "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+      "engines": {
+        "iojs": ">=1.0.0",
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/rgb-regex": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/rgb-regex/-/rgb-regex-1.0.1.tgz",
+      "integrity": "sha512-gDK5mkALDFER2YLqH6imYvK6g02gpNGM4ILDZ472EwWfXZnC2ZEpoB2ECXTyOVUKuk/bPJZMzwQPBYICzP+D3w=="
+    },
+    "node_modules/rgba-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/rgba-regex/-/rgba-regex-1.0.0.tgz",
+      "integrity": "sha512-zgn5OjNQXLUTdq8m17KdaicF6w89TZs8ZU8y0AYENIU6wG8GG6LLm0yLSiPY8DmaYmHdgRW8rnApjoT0fQRfMg=="
+    },
+    "node_modules/rimraf": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
+      "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
+      "dependencies": {
+        "glob": "^7.1.3"
+      },
+      "bin": {
+        "rimraf": "bin.js"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/isaacs"
+      }
+    },
+    "node_modules/run-parallel": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
+      "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==",
+      "funding": [
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/feross"
+        },
+        {
+          "type": "patreon",
+          "url": "https://www.patreon.com/feross"
+        },
+        {
+          "type": "consulting",
+          "url": "https://feross.org/support"
+        }
+      ],
+      "dependencies": {
+        "queue-microtask": "^1.2.2"
+      }
+    },
+    "node_modules/simple-swizzle": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+      "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+      "dependencies": {
+        "is-arrayish": "^0.3.1"
+      }
+    },
+    "node_modules/simple-swizzle/node_modules/is-arrayish": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+      "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
+    },
+    "node_modules/source-map-js": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
+      "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/supports-color": {
+      "version": "7.2.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+      "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+      "dependencies": {
+        "has-flag": "^4.0.0"
+      },
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/supports-preserve-symlinks-flag": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+      "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+      "engines": {
+        "node": ">= 0.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/ljharb"
+      }
+    },
+    "node_modules/tailwindcss": {
+      "version": "2.2.19",
+      "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.19.tgz",
+      "integrity": "sha512-6Ui7JSVtXadtTUo2NtkBBacobzWiQYVjYW0ZnKaP9S1ZCKQ0w7KVNz+YSDI/j7O7KCMHbOkz94ZMQhbT9pOqjw==",
+      "dependencies": {
+        "arg": "^5.0.1",
+        "bytes": "^3.0.0",
+        "chalk": "^4.1.2",
+        "chokidar": "^3.5.2",
+        "color": "^4.0.1",
+        "cosmiconfig": "^7.0.1",
+        "detective": "^5.2.0",
+        "didyoumean": "^1.2.2",
+        "dlv": "^1.1.3",
+        "fast-glob": "^3.2.7",
+        "fs-extra": "^10.0.0",
+        "glob-parent": "^6.0.1",
+        "html-tags": "^3.1.0",
+        "is-color-stop": "^1.1.0",
+        "is-glob": "^4.0.1",
+        "lodash": "^4.17.21",
+        "lodash.topath": "^4.5.2",
+        "modern-normalize": "^1.1.0",
+        "node-emoji": "^1.11.0",
+        "normalize-path": "^3.0.0",
+        "object-hash": "^2.2.0",
+        "postcss-js": "^3.0.3",
+        "postcss-load-config": "^3.1.0",
+        "postcss-nested": "5.0.6",
+        "postcss-selector-parser": "^6.0.6",
+        "postcss-value-parser": "^4.1.0",
+        "pretty-hrtime": "^1.0.3",
+        "purgecss": "^4.0.3",
+        "quick-lru": "^5.1.1",
+        "reduce-css-calc": "^2.1.8",
+        "resolve": "^1.20.0",
+        "tmp": "^0.2.1"
+      },
+      "bin": {
+        "tailwind": "lib/cli.js",
+        "tailwindcss": "lib/cli.js"
+      },
+      "engines": {
+        "node": ">=12.13.0"
+      },
+      "peerDependencies": {
+        "autoprefixer": "^10.0.2",
+        "postcss": "^8.0.9"
+      }
+    },
+    "node_modules/tmp": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
+      "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
+      "dependencies": {
+        "rimraf": "^3.0.0"
+      },
+      "engines": {
+        "node": ">=8.17.0"
+      }
+    },
+    "node_modules/to-regex-range": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+      "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+      "dependencies": {
+        "is-number": "^7.0.0"
+      },
+      "engines": {
+        "node": ">=8.0"
+      }
+    },
+    "node_modules/universalify": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
+      "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
+      "engines": {
+        "node": ">= 10.0.0"
+      }
+    },
+    "node_modules/update-browserslist-db": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz",
+      "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==",
+      "funding": [
+        {
+          "type": "opencollective",
+          "url": "https://opencollective.com/browserslist"
+        },
+        {
+          "type": "tidelift",
+          "url": "https://tidelift.com/funding/github/npm/browserslist"
+        },
+        {
+          "type": "github",
+          "url": "https://github.com/sponsors/ai"
+        }
+      ],
+      "peer": true,
+      "dependencies": {
+        "escalade": "^3.1.1",
+        "picocolors": "^1.0.0"
+      },
+      "bin": {
+        "update-browserslist-db": "cli.js"
+      },
+      "peerDependencies": {
+        "browserslist": ">= 4.21.0"
+      }
+    },
+    "node_modules/util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
+    },
+    "node_modules/wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+    },
+    "node_modules/xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
+      "engines": {
+        "node": ">=0.4"
+      }
+    },
+    "node_modules/yaml": {
+      "version": "1.10.2",
+      "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
+      "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+      "engines": {
+        "node": ">= 6"
+      }
+    }
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v2/package.json
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2/package.json b/packages/tailwindcss-language-server/tests/fixtures/v2/package.json
new file mode 100644
index 0000000000000000000000000000000000000000..62fab22d0e3d6a2a10b778f03231df910f11d303
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2/package.json
@@ -0,0 +1,5 @@
+{
+  "dependencies": {
+    "tailwindcss": "2.2.19"
+  }
+}
I packages/tailwindcss-language-server/tests/fixtures/v2/tailwind.config.js
diff --git a/packages/tailwindcss-language-server/tests/fixtures/v2/tailwind.config.js b/packages/tailwindcss-language-server/tests/fixtures/v2/tailwind.config.js
new file mode 100644
index 0000000000000000000000000000000000000000..4ba52ba2c8df6758685c8f65f490306b5c44eb76
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/fixtures/v2/tailwind.config.js
@@ -0,0 +1 @@
+module.exports = {}
I packages/tailwindcss-language-server/tests/hover/hover.test.js
diff --git a/packages/tailwindcss-language-server/tests/hover/hover.test.js b/packages/tailwindcss-language-server/tests/hover/hover.test.js
new file mode 100644
index 0000000000000000000000000000000000000000..30b28ad5f619892caae12ff6973181cf3ec321ba
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/hover/hover.test.js
@@ -0,0 +1,78 @@
+import { test, expect } from 'vitest'
+import { withFixture } from '../common'
+
+withFixture('basic', (c) => {
+  async function testHover(name, { text, lang, position, expected, expectedRange, settings }) {
+    test.concurrent(name, async () => {
+      let textDocument = await c.openDocument({ text, lang, settings })
+      let res = await c.sendRequest('textDocument/hover', {
+        textDocument,
+        position,
+      })
+
+      expect(res).toEqual(
+        expected
+          ? {
+              contents: {
+                language: 'css',
+                value: expected,
+              },
+              range: expectedRange,
+            }
+          : expected
+      )
+    })
+  }
+
+  testHover('disabled', {
+    text: '<div class="bg-red-500">',
+    settings: {
+      tailwindCSS: { hovers: false },
+    },
+    expected: null,
+  })
+
+  testHover('hover', {
+    text: '<div class="bg-red-500">',
+    position: { line: 0, character: 13 },
+    expected:
+      '.bg-red-500 {\n' +
+      '  --tw-bg-opacity: 1;\n' +
+      '  background-color: rgb(239 68 68 / var(--tw-bg-opacity));\n' +
+      '}',
+    expectedRange: {
+      start: { line: 0, character: 12 },
+      end: { line: 0, character: 22 },
+    },
+  })
+
+  testHover('arbitrary value', {
+    text: '<div class="p-[3px]">',
+    position: { line: 0, character: 13 },
+    expected: '.p-\\[3px\\] {\n' + '  padding: 3px;\n' + '}',
+    expectedRange: {
+      start: { line: 0, character: 12 },
+      end: { line: 0, character: 19 },
+    },
+  })
+
+  testHover('arbitrary value with theme function', {
+    text: '<div class="p-[theme(spacing.4)]">',
+    position: { line: 0, character: 13 },
+    expected: '.p-\\[theme\\(spacing\\.4\\)\\] {\n' + '  padding: 1rem/* 16px */;\n' + '}',
+    expectedRange: {
+      start: { line: 0, character: 12 },
+      end: { line: 0, character: 32 },
+    },
+  })
+
+  testHover('arbitrary property', {
+    text: '<div class="[text-wrap:balance]">',
+    position: { line: 0, character: 13 },
+    expected: '.\\[text-wrap\\:balance\\] {\n' + '  text-wrap: balance;\n' + '}',
+    expectedRange: {
+      start: { line: 0, character: 12 },
+      end: { line: 0, character: 31 },
+    },
+  })
+})
I packages/tailwindcss-language-server/tests/prepare.js
diff --git a/packages/tailwindcss-language-server/tests/prepare.js b/packages/tailwindcss-language-server/tests/prepare.js
new file mode 100644
index 0000000000000000000000000000000000000000..2c75346c37271434908799208adfaf622e96d9f9
--- /dev/null
+++ b/packages/tailwindcss-language-server/tests/prepare.js
@@ -0,0 +1,9 @@
+const glob = require('fast-glob')
+const path = require('path')
+const childProcess = require('child_process')
+
+const fixtures = glob.sync('tests/fixtures/*/package.json')
+
+for (let fixture of fixtures) {
+  childProcess.execSync('npm install', { cwd: path.dirname(fixture) })
+}