Compare commits

...
Sign in to create a new pull request.

4 commits

Author SHA1 Message Date
Philipp Spiess
e3b943b4ae V2 2024-08-07 18:28:36 +02:00
Philipp Spiess
ea0f093c12 Vite Svelte Experiments 2024-07-30 17:15:15 +02:00
Philipp Spiess
b07832772a Add PostCSS plugin to fix relative @content and @plugin paths in @imported files (#14063)
We noticed an issue that happened when handling relative file imports in
the `@plugin` and the upcoming `@content` APIs. The problem arises from
relative files that are inside `@import`ed stylesheets. Take, for
example, the following folder structure:

```css
/* src/index.css */
@import "./dir/index.css";
```
```css
/* src/dir/index.css */
@plugin "../../plugin.ts";
```

It's expected that the path is relative to the CSS file that defined it.
However, right now, we use
[`postcss-import`](https://github.com/postcss/postcss-import) to flatten
the CSS file before running the tailwind build step. This causes these
custom-properties to be inlined in a flat file which removes the
information of which file is being referred:

```css
/* src/flat.css */
@plugin "../../plugin.ts"; /* <- This is now pointing to the wrong file */
```

There are generally two approaches that we can do to solve this:

1. **Handle `@import` flattening inside tailwindcss:** While generally
this would give us more freedom and less dependencies, this would
require some work to get all edge cases right. We need to support
layers/conditional imports and also handle all relative urls for
properties like `background-image`.
2. **Rewrite relative paths as a separate postcss visitor:** The
approach this PR takes is instead to implement a custom postcss plugin
that uses the AST to rewrite relative references inside `@plugin` and
`@content`. This has the benefit of requiring little changes to our
existing APIs. The rule is only enabled for relative references inside
`@plugin` and `@content`, so the surface of this rule is very small.

We can use this plugin inside all three current clients:

- `@tailwindcss/postcss` obviously already uses postcss
- `@tailwindcss/cli` also uses postcss to handle `@import` flattening
- `@tailwindcss/vite` allows us to add custom postcss rules via the CSS
pipeline. There are a few cases that we handle with care (e.g. in vite
you can pass a string to the postcss config which is supposed to load
the config from a file).

To validate the changes, we have added both a list of unit test cases to
the plugin itself as well as verified that all three clients are working
as expected:

- `@tailwindcss/postcss` now has an explicit test for this behavior
- `@tailwindcss/cli` and `@tailwindcss/vite` were manually tested by
updating the vite playground. The CLI was run with `--cwd
playgrounds/vite/ -i ./src/app.css -o foo.css`:
<img width="531" alt="Screenshot 2024-07-29 at 11 35 59"
src="https://github.com/user-attachments/assets/78f0acdc-a46c-4c6c-917a-2916417b1001">
2024-07-30 14:06:06 +02:00
Robin Malfait
744e43fc0e start of @content support 2024-07-30 14:06:06 +02:00
29 changed files with 761 additions and 118 deletions

View file

@ -12,7 +12,7 @@
"homepage": "https://tailwindcss.com",
"scripts": {
"lint": "tsc --noEmit",
"build": "tsup-node ./src/index.ts --format esm --minify --clean",
"build": "tsup-node",
"dev": "pnpm run build -- --watch"
},
"bin": {
@ -36,7 +36,8 @@
"picocolors": "^1.0.1",
"postcss": "8.4.24",
"postcss-import": "^16.1.0",
"tailwindcss": "workspace:^"
"tailwindcss": "workspace:^",
"internal-postcss-fix-relative-paths": "workspace:^"
},
"devDependencies": {
"@types/postcss-import": "^14.0.3"

View file

@ -1,5 +1,6 @@
import watcher from '@parcel/watcher'
import { IO, Parsing, scanDir, scanFiles, type ChangedContent } from '@tailwindcss/oxide'
import fixRelativePathsPlugin from 'internal-postcss-fix-relative-paths'
import { Features, transform } from 'lightningcss'
import { existsSync } from 'node:fs'
import fs from 'node:fs/promises'
@ -259,6 +260,7 @@ function handleImports(
return postcss()
.use(atImport())
.use(fixRelativePathsPlugin())
.process(input, { from: file })
.then((result) => [
result.css,

View file

@ -0,0 +1,9 @@
import { defineConfig } from 'tsup'
export default defineConfig({
format: ['esm'],
clean: true,
minify: true,
entry: ['src/index.ts'],
noExternal: ['internal-postcss-fix-relative-paths'],
})

View file

@ -12,7 +12,7 @@
"homepage": "https://tailwindcss.com",
"scripts": {
"lint": "tsc --noEmit",
"build": "tsup-node ./src/index.ts --format cjs,esm --dts --cjsInterop --splitting --minify --clean",
"build": "tsup-node",
"dev": "pnpm run build -- --watch"
},
"files": [
@ -33,7 +33,8 @@
"@tailwindcss/oxide": "workspace:^",
"lightningcss": "^1.25.1",
"postcss-import": "^16.1.0",
"tailwindcss": "workspace:^"
"tailwindcss": "workspace:^",
"internal-postcss-fix-relative-paths": "workspace:^"
},
"devDependencies": {
"@types/node": "^20.12.12",

View file

@ -0,0 +1 @@
@plugin '../plugin.js';

View file

@ -144,7 +144,7 @@ describe('plugins', () => {
let result = await processor.process(
css`
@import 'tailwindcss/utilities';
@plugin 'internal-example-plugin';
@plugin './plugin.js';
`,
{ from: INPUT_CSS_PATH },
)
@ -166,6 +166,36 @@ describe('plugins', () => {
`)
})
test('local CJS plugin from `@import`-ed file', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),
])
let result = await processor.process(
css`
@import 'tailwindcss/utilities';
@import '../example-project/src/relative-import.css';
`,
{ from: `${__dirname}/fixtures/another-project/input.css` },
)
expect(result.css.trim()).toMatchInlineSnapshot(`
".underline {
text-decoration-line: underline;
}
@media (inverted-colors: inverted) {
.inverted\\:flex {
display: flex;
}
}
.hocus\\:underline:focus, .hocus\\:underline:hover {
text-decoration-line: underline;
}"
`)
})
test('published CJS plugin', async () => {
let processor = postcss([
tailwindcss({ base: `${__dirname}/fixtures/example-project`, optimize: { minify: false } }),

View file

@ -2,9 +2,10 @@ import { scanDir } from '@tailwindcss/oxide'
import fs from 'fs'
import { Features, transform } from 'lightningcss'
import path from 'path'
import postcss, { type AcceptedPlugin, type PluginCreator } from 'postcss'
import postcss, { AtRule, type AcceptedPlugin, type PluginCreator } from 'postcss'
import postcssImport from 'postcss-import'
import { compile } from 'tailwindcss'
import fixRelativePathsPlugin from '../../internal-postcss-fix-relative-paths/src'
/**
* A Map that can generate default values for keys that don't exist.
@ -48,114 +49,118 @@ function tailwindcss(opts: PluginOptions = {}): AcceptedPlugin {
}
})
let hasApply: boolean, hasTailwind: boolean
return {
postcssPlugin: '@tailwindcss/postcss',
plugins: [
// We need to run `postcss-import` first to handle `@import` rules.
postcssImport(),
fixRelativePathsPlugin(),
(root, result) => {
let inputFile = result.opts.from ?? ''
let context = cache.get(inputFile)
let rebuildStrategy: 'full' | 'incremental' = 'incremental'
// Track file modification times to CSS files
{
let files = result.messages.flatMap((message) => {
if (message.type !== 'dependency') return []
return message.file
})
files.push(inputFile)
for (let file of files) {
let changedTime = fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? null
if (changedTime === null) {
if (file === inputFile) {
rebuildStrategy = 'full'
}
continue
}
let prevTime = context.mtimes.get(file)
if (prevTime === changedTime) continue
rebuildStrategy = 'full'
context.mtimes.set(file, changedTime)
}
}
let hasApply = false
let hasTailwind = false
root.walkAtRules((rule) => {
{
postcssPlugin: 'tailwindcss',
Once() {
// Reset some state between builds
hasApply = false
hasTailwind = false
},
AtRule(rule: AtRule) {
if (rule.name === 'apply') {
hasApply = true
} else if (rule.name === 'tailwind') {
hasApply = true
hasTailwind = true
// If we've found `@tailwind` then we already
// know we have to run a "full" build
return false
}
})
},
OnceExit(root, { result }) {
let inputFile = result.opts.from ?? ''
let context = cache.get(inputFile)
// Do nothing if neither `@tailwind` nor `@apply` is used
if (!hasTailwind && !hasApply) return
let rebuildStrategy: 'full' | 'incremental' = 'incremental'
let css = ''
// Look for candidates used to generate the CSS
let { candidates, files, globs } = scanDir({ base, globs: true })
// Add all found files as direct dependencies
for (let file of files) {
result.messages.push({
type: 'dependency',
plugin: '@tailwindcss/postcss',
file,
parent: result.opts.from,
})
}
// Register dependencies so changes in `base` cause a rebuild while
// giving tools like Vite or Parcel a glob that can be used to limit
// the files that cause a rebuild to only those that match it.
for (let { base, glob } of globs) {
result.messages.push({
type: 'dir-dependency',
plugin: '@tailwindcss/postcss',
dir: base,
glob,
parent: result.opts.from,
})
}
if (rebuildStrategy === 'full') {
let basePath = path.dirname(path.resolve(inputFile))
let { build } = compile(root.toString(), {
loadPlugin: (pluginPath) => {
if (pluginPath[0] === '.') {
return require(path.resolve(basePath, pluginPath))
// Track file modification times to CSS files
{
let files = result.messages.flatMap((message) => {
if (message.type !== 'dependency') return []
return message.file
})
files.push(inputFile)
for (let file of files) {
let changedTime = fs.statSync(file, { throwIfNoEntry: false })?.mtimeMs ?? null
if (changedTime === null) {
if (file === inputFile) {
rebuildStrategy = 'full'
}
continue
}
return require(pluginPath)
},
})
context.build = build
css = build(hasTailwind ? candidates : [])
} else if (rebuildStrategy === 'incremental') {
css = context.build!(candidates)
}
let prevTime = context.mtimes.get(file)
if (prevTime === changedTime) continue
// Replace CSS
if (css !== context.css && optimize) {
context.optimizedCss = optimizeCss(css, {
minify: typeof optimize === 'object' ? optimize.minify : true,
})
}
context.css = css
root.removeAll()
root.append(postcss.parse(optimize ? context.optimizedCss : context.css, result.opts))
rebuildStrategy = 'full'
context.mtimes.set(file, changedTime)
}
}
// Do nothing if neither `@tailwind` nor `@apply` is used
if (!hasTailwind && !hasApply) return
let css = ''
// Look for candidates used to generate the CSS
let { candidates, files, globs } = scanDir({ base, globs: true })
// Add all found files as direct dependencies
for (let file of files) {
result.messages.push({
type: 'dependency',
plugin: '@tailwindcss/postcss',
file,
parent: result.opts.from,
})
}
// Register dependencies so changes in `base` cause a rebuild while
// giving tools like Vite or Parcel a glob that can be used to limit
// the files that cause a rebuild to only those that match it.
for (let { base, glob } of globs) {
result.messages.push({
type: 'dir-dependency',
plugin: '@tailwindcss/postcss',
dir: base,
glob,
parent: result.opts.from,
})
}
if (rebuildStrategy === 'full') {
let basePath = path.dirname(path.resolve(inputFile))
let { build } = compile(root.toString(), {
loadPlugin: (pluginPath) => {
if (pluginPath[0] === '.') {
return require(path.resolve(basePath, pluginPath))
}
return require(pluginPath)
},
})
context.build = build
css = build(hasTailwind ? candidates : [])
} else if (rebuildStrategy === 'incremental') {
css = context.build!(candidates)
}
// Replace CSS
if (css !== context.css && optimize) {
context.optimizedCss = optimizeCss(css, {
minify: typeof optimize === 'object' ? optimize.minify : true,
})
}
context.css = css
root.removeAll()
root.append(postcss.parse(optimize ? context.optimizedCss : context.css, result.opts))
},
},
],
}

View file

@ -0,0 +1,12 @@
import { defineConfig } from 'tsup'
export default defineConfig({
format: ['esm', 'cjs'],
clean: true,
minify: true,
splitting: true,
cjsInterop: true,
dts: true,
entry: ['src/index.ts'],
noExternal: ['internal-postcss-fix-relative-paths'],
})

View file

@ -11,7 +11,7 @@
"bugs": "https://github.com/tailwindlabs/tailwindcss/issues",
"homepage": "https://tailwindcss.com",
"scripts": {
"build": "tsup-node ./src/index.ts --format esm --dts --minify --clean",
"build": "tsup-node",
"dev": "pnpm run build -- --watch"
},
"files": [
@ -30,10 +30,12 @@
"dependencies": {
"@tailwindcss/oxide": "workspace:^",
"lightningcss": "^1.25.1",
"postcss-load-config": "^6.0.1",
"tailwindcss": "workspace:^"
},
"devDependencies": {
"@types/node": "^20.12.12",
"internal-postcss-fix-relative-paths": "workspace:^",
"vite": "^5.2.11"
},
"peerDependencies": {

View file

@ -1,6 +1,8 @@
import { IO, Parsing, scanFiles } from '@tailwindcss/oxide'
import fixRelativePathsPlugin from 'internal-postcss-fix-relative-paths'
import { Features, transform } from 'lightningcss'
import path from 'path'
import postcssrc from 'postcss-load-config'
import { compile } from 'tailwindcss'
import type { Plugin, Rollup, Update, ViteDevServer } from 'vite'
@ -101,7 +103,7 @@ export default function tailwindcss(): Plugin[] {
for (let plugin of cssPlugins) {
if (!plugin.transform) continue
const transformHandler =
let transformHandler =
'handler' in plugin.transform! ? plugin.transform.handler : plugin.transform!
try {
@ -152,6 +154,56 @@ export default function tailwindcss(): Plugin[] {
})
},
// Append the postcss-fix-relative-paths plugin
async config(config) {
let postcssConfig = config.css?.postcss
if (typeof postcssConfig === 'string') {
// We expand string configs to their PostCSS config object similar to
// how Vite does it.
// See: https://github.com/vitejs/vite/blob/440783953a55c6c63cd09ec8d13728dc4693073d/packages/vite/src/node/plugins/css.ts#L1580
let searchPath = typeof postcssConfig === 'string' ? postcssConfig : config.root
let parsedConfig = await postcssrc({}, searchPath).catch((e: Error) => {
if (!e.message.includes('No PostCSS Config found')) {
if (e instanceof Error) {
let { name, message, stack } = e
e.name = 'Failed to load PostCSS config'
e.message = `Failed to load PostCSS config (searchPath: ${searchPath}): [${name}] ${message}\n${stack}`
e.stack = '' // add stack to message to retain stack
throw e
} else {
throw new Error(`Failed to load PostCSS config: ${e}`)
}
}
return null
})
if (parsedConfig !== null) {
postcssConfig = {
options: parsedConfig.options,
plugins: parsedConfig.plugins,
} as any
} else {
postcssConfig = {}
}
config.css = { postcss: postcssConfig }
}
// postcssConfig is no longer a string after the above. This test is to
// avoid TypeScript errors below.
if (typeof postcssConfig === 'string') {
return
}
if (!postcssConfig || !postcssConfig?.plugins) {
config.css = config.css || {}
config.css.postcss = postcssConfig || {}
config.css.postcss.plugins = [fixRelativePathsPlugin() as any, fixSvelte() as any]
} else {
postcssConfig.plugins.push(fixRelativePathsPlugin() as any)
postcssConfig.plugins.push(fixSvelte() as any)
}
},
// Scan index.html for candidates
transformIndexHtml(html) {
let updated = scan(html, 'html')
@ -244,7 +296,11 @@ function getExtension(id: string) {
function isTailwindCssFile(id: string, src: string) {
if (id.includes('/.vite/')) return
return getExtension(id) === 'css' && src.includes('@tailwind')
const extension = getExtension(id)
const isTailwind =
(extension === 'css' && src.includes('@tailwind')) ||
(extension === 'svelte' && id.endsWith('&lang.css'))
return isTailwind
}
function optimizeCss(
@ -270,3 +326,18 @@ function optimizeCss(
errorRecovery: true,
}).code.toString()
}
export function fixSvelte() {
return {
postcssPlugin: 'tailwindcss-postcss-fix-svelte',
OnceExit: (root: any) => {
const filename = root.source.input.file
if (!filename.endsWith('.svelte?svelte&type=style&lang.css')) {
return
}
const content = root.toString()
let compiled = compile(content.replace('@tailwind ', '@failwind '), {}).build([''])
root.replaceWith(compiled.replace('@failwind ', ' @tailwind '))
},
}
}

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'tsup'
export default defineConfig({
format: ['esm'],
clean: true,
minify: true,
dts: true,
entry: ['src/index.ts'],
noExternal: ['internal-postcss-fix-relative-paths'],
})

View file

@ -0,0 +1,27 @@
{
"name": "internal-postcss-fix-relative-paths",
"version": "0.0.0",
"private": true,
"scripts": {
"lint": "tsc --noEmit",
"build": "tsup-node ./src/index.ts --format cjs,esm --dts --cjsInterop --splitting --minify --clean",
"dev": "pnpm run build -- --watch"
},
"files": [
"dist/"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
}
},
"dependencies": {},
"devDependencies": {
"@types/node": "^20.12.12",
"@types/postcss-import": "^14.0.3",
"postcss": "8.4.24",
"postcss-import": "^16.1.0"
}
}

View file

@ -0,0 +1,3 @@
@content "./**/*.ts";
@plugin "./plugin.js";
@plugin "./what\"s-this.js";

View file

@ -0,0 +1,4 @@
@plugin "/absolute/paths";
@plugin "C:\Program Files\HAL 9000";
@plugin "\\Media\Pictures\Worth\1000 words";
@plugin "some-node-dep";

View file

@ -0,0 +1 @@
@import '../../example-project/src/index.css';

View file

@ -0,0 +1 @@
@import '../../example-project/src/invalid.css';

View file

@ -0,0 +1,5 @@
@import './plugins-in-sibling.css';
@plugin './plugin-in-root.ts';
@plugin '../plugin-in-root.ts';
@plugin 'plugin-in-root';

View file

@ -0,0 +1,3 @@
@plugin './plugin-in-sibling.ts';
@plugin '../plugin-in-sibling.ts';
@plugin 'plugin-in-sibling';

View file

@ -0,0 +1,56 @@
import fs from 'node:fs'
import postcss from 'postcss'
import atImport from 'postcss-import'
import { describe, expect, test } from 'vitest'
import fixRelativePathsPlugin from '.'
describe('fixRelativePathsPlugin', () => {
test('rewrites @content and @plugin to be relative to the initial css file', async () => {
let cssPath = `${__dirname}/fixtures/external-import/src/index.css`
let css = fs.readFileSync(cssPath, 'utf-8')
let processor = postcss([atImport(), fixRelativePathsPlugin()])
let result = await processor.process(css, { from: cssPath })
expect(result.css.trim()).toMatchInlineSnapshot(`
"@content "../../example-project/src/**/*.ts";
@plugin "../../example-project/src/plugin.js";
@plugin "../../example-project/src/what\\"s-this.js";"
`)
})
test('should not rewrite non-relative paths', async () => {
let cssPath = `${__dirname}/fixtures/external-import/src/invalid.css`
let css = fs.readFileSync(cssPath, 'utf-8')
let processor = postcss([atImport(), fixRelativePathsPlugin()])
let result = await processor.process(css, { from: cssPath })
expect(result.css.trim()).toMatchInlineSnapshot(`
"@plugin "/absolute/paths";
@plugin "C:\\Program Files\\HAL 9000";
@plugin "\\\\Media\\Pictures\\Worth\\1000 words";
@plugin "some-node-dep";"
`)
})
test('should return relative paths even if the file is resolved in the same basedir as the root stylesheet', async () => {
let cssPath = `${__dirname}/fixtures/external-import/src/plugins-in-root.css`
let css = fs.readFileSync(cssPath, 'utf-8')
let processor = postcss([atImport(), fixRelativePathsPlugin()])
let result = await processor.process(css, { from: cssPath })
expect(result.css.trim()).toMatchInlineSnapshot(`
"@plugin './plugin-in-sibling.ts';
@plugin '../plugin-in-sibling.ts';
@plugin 'plugin-in-sibling';
@plugin './plugin-in-root.ts';
@plugin '../plugin-in-root.ts';
@plugin 'plugin-in-root';"
`)
})
})

View file

@ -0,0 +1,101 @@
import path from 'node:path'
import type { AtRule, Container, Plugin } from 'postcss'
const SINGLE_QUOTE = "'"
const DOUBLE_QUOTE = '"'
export default function fixRelativePathsPlugin(): Plugin {
// Retain a list of touched at-rules to avoid infinite loops
let touched: WeakSet<AtRule> = new WeakSet()
function fixRelativePath(atRule: AtRule) {
let rootPath = getRoot(atRule)?.source?.input.file
if (!rootPath) {
return
}
let inputFilePath = atRule?.source?.input.file
if (!inputFilePath) {
return
}
if (touched.has(atRule)) {
return
}
let value = atRule.params[0]
let quote =
value[0] === DOUBLE_QUOTE && value[value.length - 1] === DOUBLE_QUOTE
? DOUBLE_QUOTE
: value[0] === SINGLE_QUOTE && value[value.length - 1] === SINGLE_QUOTE
? SINGLE_QUOTE
: null
if (!quote) {
return
}
let content = atRule.params.slice(1, -1)
// We only want to rewrite relative paths.
if (!content.startsWith('./') && !content.startsWith('../')) {
return
}
let rulePath = path.posix.join(path.posix.dirname(inputFilePath), content)
let relative = path.posix.relative(path.posix.dirname(rootPath), rulePath)
// If the path points to a file in the same directory, `path.relative` will
// remove the leading `./` and we need to add it back in order to still
// consider the path relative
if (!relative.startsWith('.')) {
relative = './' + relative
}
atRule.params = quote + relative + quote
touched.add(atRule)
}
function getRoot(node: AtRule | Container | undefined): Container | undefined {
if (node?.parent) {
return getRoot(node.parent as Container)
}
return node
}
return {
postcssPlugin: 'tailwindcss-postcss-fix-relative-paths',
AtRule: {
content: fixRelativePath,
plugin: fixRelativePath,
// theme: function (atRule: AtRule, { postcss }: { postcss: any }) {
// if (touched.has(atRule)) {
// return
// }
// }
// apply: function (atRule: AtRule, { postcss }: { postcss: any }) {
// if (touched.has(atRule)) {
// return
// }
// if(atRule.name)
// if (atRule.params[0] === "'") {
// return
// }
// atRule.params = `'${atRule.params}'`
// touched.add(atRule)
// // Convert atRule to a comment
// // atRule.replaceWith(
// // postcss.rule({
// // selector: '& .CUSTOM-foo-base476',
// // nodes: [],
// // }),
// // )
// // atRule.before(postcss.comment({ text: '! custom' + atRule.toString() }))
// // if (atRule.name === 'apply') {
// // atRule.name = 'comment'
// // atRule.params = 'tailwindcss-apply'
// // return
// // }
// },
},
}
}

View file

@ -0,0 +1,3 @@
{
"extends": "../tsconfig.base.json",
}

View file

@ -305,10 +305,15 @@ export function compile(
if (css.includes('@apply')) {
walk(ast, (node, { replaceWith }) => {
if (node.kind === 'rule' && node.selector[0] === '@' && node.selector.startsWith('@apply')) {
let candidates = node.selector
let candidates: any = node.selector
.slice(7 /* Ignore `@apply ` when parsing the selector */)
.trim()
.split(/\s+/g)
if (candidates[0] === "'" || candidates[0] === '"') {
candidates = candidates.slice(1, -1)
}
candidates = candidates.split(/\s+/g)
// Replace the `@apply` rule with the actual utility classes
{

View file

@ -435,7 +435,8 @@
--transition-timing-function-in: cubic-bezier(0.4, 0, 1, 1);
--transition-timing-function-out: cubic-bezier(0, 0, 0.2, 1);
--transition-timing-function-in-out: cubic-bezier(0.4, 0, 0.2, 1);
}
@theme {
@keyframes spin {
to {
transform: rotate(360deg);

View file

@ -9,10 +9,13 @@
"preview": "bun --bun vite preview"
},
"dependencies": {
"@sveltejs/vite-plugin-svelte": "^3.1.1",
"@tailwindcss/vite": "workspace:^",
"@vitejs/plugin-react": "^4.3.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"svelte": "^4.2.18",
"svelte-preprocess": "^6.0.2",
"tailwindcss": "workspace:^"
},
"devDependencies": {

View file

@ -0,0 +1,9 @@
<script>
let name = 'world'
</script>
<h1 class="foo any-hover:text-red-500 hover:underline">Hello {name}!</h1>
<style>
@tailwind utilities;
</style>

View file

@ -1,2 +0,0 @@
@import 'tailwindcss';
@plugin "./plugin.js";

View file

@ -1,9 +1,7 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import { App } from './app'
import App from './App.svelte'
ReactDOM.createRoot(document.getElementById('app')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
const app = new App({
target: document.getElementById('app'),
})
export default app

View file

@ -1,7 +1,35 @@
import { svelte, vitePreprocess } from '@sveltejs/vite-plugin-svelte'
import tailwindcss from '@tailwindcss/vite'
import react from '@vitejs/plugin-react'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
plugins: [
svelte({
preprocess: [
// sveltePreprocess({
// aliases: [
// ['tailwindcss', 'tailwindcss'],
// ['tailwind', 'tailwindcss'],
// ['postcss', 'tailwindcss'],
// ],
// /** Add a custom language preprocessor */
// tailwindcss({ content, filename, attributes }) {
// let compiled = compile(content.replace('@tailwind ', '@failwind '), {}).build(
// Array.from(['']),
// )
// console.log({ compiled, attributes })
// return Promise.resolve({
// code: compiled.replace('@failwind ', '@tailwind '),
// map: '',
// attributes,
// })
// },
// }),
vitePreprocess(),
],
}),
tailwindcss(),
],
})
// @tailwindcss/svelte

259
pnpm-lock.yaml generated
View file

@ -109,6 +109,9 @@ importers:
'@tailwindcss/oxide':
specifier: workspace:^
version: link:../../crates/node
internal-postcss-fix-relative-paths:
specifier: workspace:^
version: link:../internal-postcss-fix-relative-paths
lightningcss:
specifier: ^1.25.1
version: 1.25.1
@ -137,6 +140,9 @@ importers:
'@tailwindcss/oxide':
specifier: workspace:^
version: link:../../crates/node
internal-postcss-fix-relative-paths:
specifier: workspace:^
version: link:../internal-postcss-fix-relative-paths
lightningcss:
specifier: ^1.25.1
version: 1.25.1
@ -168,6 +174,9 @@ importers:
lightningcss:
specifier: ^1.25.1
version: 1.25.1
postcss-load-config:
specifier: ^6.0.1
version: 6.0.1(postcss@8.4.38)(yaml@2.4.2)
tailwindcss:
specifier: workspace:^
version: link:../tailwindcss
@ -175,12 +184,30 @@ importers:
'@types/node':
specifier: ^20.12.12
version: 20.12.12
internal-postcss-fix-relative-paths:
specifier: workspace:^
version: link:../internal-postcss-fix-relative-paths
vite:
specifier: ^5.2.11
version: 5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)
packages/internal-example-plugin: {}
packages/internal-postcss-fix-relative-paths:
devDependencies:
'@types/node':
specifier: ^20.12.12
version: 20.12.12
'@types/postcss-import':
specifier: ^14.0.3
version: 14.0.3
postcss:
specifier: 8.4.24
version: 8.4.24
postcss-import:
specifier: ^16.1.0
version: 16.1.0(postcss@8.4.24)
packages/tailwindcss:
devDependencies:
'@tailwindcss/oxide':
@ -235,6 +262,9 @@ importers:
playgrounds/vite:
dependencies:
'@sveltejs/vite-plugin-svelte':
specifier: ^3.1.1
version: 3.1.1(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))
'@tailwindcss/vite':
specifier: workspace:^
version: link:../../packages/@tailwindcss-vite
@ -247,6 +277,12 @@ importers:
react-dom:
specifier: ^18.3.1
version: 18.3.1(react@18.3.1)
svelte:
specifier: ^4.2.18
version: 4.2.18
svelte-preprocess:
specifier: ^6.0.2
version: 6.0.2(@babel/core@7.24.6)(postcss-load-config@6.0.1(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18)(typescript@5.4.5)
tailwindcss:
specifier: workspace:^
version: link:../../packages/tailwindcss
@ -1008,6 +1044,21 @@ packages:
'@sinclair/typebox@0.27.8':
resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==}
'@sveltejs/vite-plugin-svelte-inspector@2.1.0':
resolution: {integrity: sha512-9QX28IymvBlSCqsCll5t0kQVxipsfhFFL+L2t3nTWfXnddYwxBuAEtTtlaVQpRz9c37BhJjltSeY4AJSC03SSg==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
'@sveltejs/vite-plugin-svelte': ^3.0.0
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
'@sveltejs/vite-plugin-svelte@3.1.1':
resolution: {integrity: sha512-rimpFEAboBBHIlzISibg94iP09k/KYdHgVhJlcsTfn7KMBhc70jFX/GRWkRdFCc2fdnk+4+Bdfej23cMDnJS6A==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
'@swc/helpers@0.5.2':
resolution: {integrity: sha512-E4KcWTpoLHqwPHLxidpOqQbcrZVgi0rsmmZXUle1jXmJfuIf/UWpczUJ7MZZ5tlxytgJXyp0w4PGkkeLiuIdZw==}
@ -1213,6 +1264,10 @@ packages:
axobject-query@3.2.1:
resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==}
axobject-query@4.1.0:
resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==}
engines: {node: '>= 0.4'}
balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
@ -1237,6 +1292,7 @@ packages:
bun@1.1.10:
resolution: {integrity: sha512-qOJXrQZSzJ5DbJMt47GZGWtUSmIkbwD7fPSN/XS/T46D4cTTnPK46QDHlyC8VD+Anvs6uKNwuwKIyB31kUdHmQ==}
cpu: [arm64, x64]
os: [darwin, linux, win32]
hasBin: true
@ -1287,6 +1343,9 @@ packages:
client-only@0.0.1:
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
code-red@1.0.4:
resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==}
color-convert@1.9.3:
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
@ -1317,6 +1376,10 @@ packages:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
csstype@3.1.3:
resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
@ -1359,6 +1422,10 @@ packages:
deep-is@0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
deepmerge@4.3.1:
resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==}
engines: {node: '>=0.10.0'}
define-data-property@1.1.4:
resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==}
engines: {node: '>= 0.4'}
@ -1853,6 +1920,9 @@ packages:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
is-reference@3.0.2:
resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==}
is-regex@1.1.4:
resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==}
engines: {node: '>= 0.4'}
@ -1973,6 +2043,10 @@ packages:
keyv@4.5.4:
resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==}
kleur@4.1.5:
resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==}
engines: {node: '>=6'}
language-subtag-registry@0.3.23:
resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==}
@ -2057,6 +2131,9 @@ packages:
resolution: {integrity: sha512-ok6z3qlYyCDS4ZEU27HaU6x/xZa9Whf8jD4ptH5UZTQYZVYeb9bnZ3ojVhiJNLiXK1Hfc0GNbLXcmZ5plLDDBg==}
engines: {node: '>=14'}
locate-character@3.0.0:
resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==}
locate-path@6.0.0:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'}
@ -2091,6 +2168,9 @@ packages:
resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==}
engines: {node: '>=10'}
mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
merge-stream@2.0.0:
resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
@ -2288,6 +2368,9 @@ packages:
pathval@1.1.1:
resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==}
periscopic@3.1.0:
resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==}
picocolors@1.0.1:
resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==}
@ -2338,6 +2421,24 @@ packages:
ts-node:
optional: true
postcss-load-config@6.0.1:
resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==}
engines: {node: '>= 18'}
peerDependencies:
jiti: '>=1.21.0'
postcss: '>=8.0.9'
tsx: ^4.8.1
yaml: ^2.4.2
peerDependenciesMeta:
jiti:
optional: true
postcss:
optional: true
tsx:
optional: true
yaml:
optional: true
postcss-value-parser@4.2.0:
resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==}
@ -2618,6 +2719,53 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
svelte-hmr@0.16.0:
resolution: {integrity: sha512-Gyc7cOS3VJzLlfj7wKS0ZnzDVdv3Pn2IuVeJPk9m2skfhcu5bq3wtIZyQGggr7/Iim5rH5cncyQft/kRLupcnA==}
engines: {node: ^12.20 || ^14.13.1 || >= 16}
peerDependencies:
svelte: ^3.19.0 || ^4.0.0
svelte-preprocess@6.0.2:
resolution: {integrity: sha512-OvDTLfaOkkhjprbDKO0SOCkjNYuHy16dbD4SpqbIi6QiabOMHxRT4km5/dzbFFkmW1L0E2INF3MFltG2pgOyKQ==}
engines: {node: '>= 18.0.0'}
peerDependencies:
'@babel/core': ^7.10.2
coffeescript: ^2.5.1
less: ^3.11.3 || ^4.0.0
postcss: ^7 || ^8
postcss-load-config: '>=3'
pug: ^3.0.0
sass: ^1.26.8
stylus: '>=0.55'
sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0
svelte: ^4.0.0 || ^5.0.0-next.100 || ^5.0.0
typescript: ^5.0.0
peerDependenciesMeta:
'@babel/core':
optional: true
coffeescript:
optional: true
less:
optional: true
postcss:
optional: true
postcss-load-config:
optional: true
pug:
optional: true
sass:
optional: true
stylus:
optional: true
sugarss:
optional: true
typescript:
optional: true
svelte@4.2.18:
resolution: {integrity: sha512-d0FdzYIiAePqRJEb90WlJDkjUEx42xhivxN8muUBmfZnP+tzUgz12DJ2hRJi8sIHCME7jeK1PTMgKPSfTd8JrA==}
engines: {node: '>=16'}
tapable@2.2.1:
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
engines: {node: '>=6'}
@ -2822,6 +2970,14 @@ packages:
terser:
optional: true
vitefu@0.2.5:
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
peerDependencies:
vite: ^3.0.0 || ^4.0.0 || ^5.0.0
peerDependenciesMeta:
vite:
optional: true
vitest@1.6.0:
resolution: {integrity: sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==}
engines: {node: ^18.0.0 || >=20.0.0}
@ -3451,6 +3607,29 @@ snapshots:
'@sinclair/typebox@0.27.8': {}
'@sveltejs/vite-plugin-svelte-inspector@2.1.0(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)))(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))':
dependencies:
'@sveltejs/vite-plugin-svelte': 3.1.1(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))
debug: 4.3.4
svelte: 4.2.18
vite: 5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)
transitivePeerDependencies:
- supports-color
'@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))':
dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 2.1.0(@sveltejs/vite-plugin-svelte@3.1.1(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)))(svelte@4.2.18)(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))
debug: 4.3.4
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.10
svelte: 4.2.18
svelte-hmr: 0.16.0(svelte@4.2.18)
vite: 5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)
vitefu: 0.2.5(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1))
transitivePeerDependencies:
- supports-color
'@swc/helpers@0.5.2':
dependencies:
tslib: 2.6.2
@ -3732,6 +3911,8 @@ snapshots:
dependencies:
dequal: 2.0.3
axobject-query@4.1.0: {}
balanced-match@1.0.2: {}
binary-extensions@2.3.0: {}
@ -3829,6 +4010,14 @@ snapshots:
client-only@0.0.1: {}
code-red@1.0.4:
dependencies:
'@jridgewell/sourcemap-codec': 1.4.15
'@types/estree': 1.0.5
acorn: 8.11.3
estree-walker: 3.0.3
periscopic: 3.1.0
color-convert@1.9.3:
dependencies:
color-name: 1.1.3
@ -3855,6 +4044,11 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
css-tree@2.3.1:
dependencies:
mdn-data: 2.0.30
source-map-js: 1.2.0
csstype@3.1.3: {}
damerau-levenshtein@1.0.8: {}
@ -3891,6 +4085,8 @@ snapshots:
deep-is@0.1.4: {}
deepmerge@4.3.1: {}
define-data-property@1.1.4:
dependencies:
es-define-property: 1.0.0
@ -4092,7 +4288,7 @@ snapshots:
eslint: 8.57.0
eslint-import-resolver-node: 0.3.9
eslint-import-resolver-typescript: 3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
eslint-plugin-jsx-a11y: 6.8.0(eslint@8.57.0)
eslint-plugin-react: 7.34.1(eslint@8.57.0)
eslint-plugin-react-hooks: 4.6.2(eslint@8.57.0)
@ -4116,7 +4312,7 @@ snapshots:
enhanced-resolve: 5.16.1
eslint: 8.57.0
eslint-module-utils: 2.8.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0)
eslint-plugin-import: 2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0)
fast-glob: 3.3.2
get-tsconfig: 4.7.5
is-core-module: 2.13.1
@ -4138,7 +4334,7 @@ snapshots:
transitivePeerDependencies:
- supports-color
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.29.1(eslint@8.57.0))(eslint@8.57.0))(eslint@8.57.0):
eslint-plugin-import@2.29.1(@typescript-eslint/parser@6.21.0(eslint@8.57.0)(typescript@5.4.5))(eslint-import-resolver-typescript@3.6.1)(eslint@8.57.0):
dependencies:
array-includes: 3.1.8
array.prototype.findlastindex: 1.2.5
@ -4584,6 +4780,10 @@ snapshots:
is-path-inside@3.0.3: {}
is-reference@3.0.2:
dependencies:
'@types/estree': 1.0.5
is-regex@1.1.4:
dependencies:
call-bind: 1.0.7
@ -4702,6 +4902,8 @@ snapshots:
dependencies:
json-buffer: 3.0.1
kleur@4.1.5: {}
language-subtag-registry@0.3.23: {}
language-tags@1.0.9:
@ -4765,6 +4967,8 @@ snapshots:
mlly: 1.7.0
pkg-types: 1.1.1
locate-character@3.0.0: {}
locate-path@6.0.0:
dependencies:
p-locate: 5.0.0
@ -4801,6 +5005,8 @@ snapshots:
dependencies:
semver: 7.6.2
mdn-data@2.0.30: {}
merge-stream@2.0.0: {}
merge2@1.4.1: {}
@ -4996,6 +5202,12 @@ snapshots:
pathval@1.1.1: {}
periscopic@3.1.0:
dependencies:
'@types/estree': 1.0.5
estree-walker: 3.0.3
is-reference: 3.0.2
picocolors@1.0.1: {}
picomatch@2.3.1: {}
@ -5034,6 +5246,13 @@ snapshots:
optionalDependencies:
postcss: 8.4.24
postcss-load-config@6.0.1(postcss@8.4.38)(yaml@2.4.2):
dependencies:
lilconfig: 3.1.1
optionalDependencies:
postcss: 8.4.38
yaml: 2.4.2
postcss-value-parser@4.2.0: {}
postcss@8.4.24:
@ -5335,6 +5554,36 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
svelte-hmr@0.16.0(svelte@4.2.18):
dependencies:
svelte: 4.2.18
svelte-preprocess@6.0.2(@babel/core@7.24.6)(postcss-load-config@6.0.1(postcss@8.4.38))(postcss@8.4.38)(svelte@4.2.18)(typescript@5.4.5):
dependencies:
svelte: 4.2.18
optionalDependencies:
'@babel/core': 7.24.6
postcss: 8.4.38
postcss-load-config: 6.0.1(postcss@8.4.38)(yaml@2.4.2)
typescript: 5.4.5
svelte@4.2.18:
dependencies:
'@ampproject/remapping': 2.3.0
'@jridgewell/sourcemap-codec': 1.4.15
'@jridgewell/trace-mapping': 0.3.25
'@types/estree': 1.0.5
acorn: 8.11.3
aria-query: 5.3.0
axobject-query: 4.1.0
code-red: 1.0.4
css-tree: 2.3.1
estree-walker: 3.0.3
is-reference: 3.0.2
locate-character: 3.0.0
magic-string: 0.30.10
periscopic: 3.1.0
tapable@2.2.1: {}
test-exclude@6.0.0:
@ -5542,6 +5791,10 @@ snapshots:
fsevents: 2.3.3
lightningcss: 1.25.1
vitefu@0.2.5(vite@5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)):
optionalDependencies:
vite: 5.2.11(@types/node@20.12.12)(lightningcss@1.25.1)
vitest@1.6.0(@types/node@20.12.12)(lightningcss@1.25.1):
dependencies:
'@vitest/expect': 1.6.0