diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..a012c35
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,2 @@
+# keep LF as-is even on Windows for consistent hash values across platforms
+* text=auto eol=lf
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b4b05b8..4261ad7 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -48,6 +48,9 @@ jobs:
- name: Install deps
run: pnpm install
+ - name: Install playwright
+ run: pnpm --filter examples exec playwright install chromium --with-deps
+
- name: Build
run: pnpm run build
@@ -77,6 +80,9 @@ jobs:
- name: Install deps
run: pnpm install --no-frozen-lockfile
+ - name: Install playwright
+ run: pnpm --filter examples exec playwright install chromium --with-deps
+
- name: Install @babel/core v7 types
run: pnpm add -Dw @types/babel__core@^7.20.5
diff --git a/.gitignore b/.gitignore
index 2aa8c99..f13f414 100644
--- a/.gitignore
+++ b/.gitignore
@@ -142,3 +142,8 @@ dist
vite.config.js.timestamp-*
vite.config.ts.timestamp-*
.vite/
+
+.swc
+
+/examples-temp-*
+output.swc.*
diff --git a/.oxfmtrc.json b/.oxfmtrc.json
index 282d97c..8b35b8c 100644
--- a/.oxfmtrc.json
+++ b/.oxfmtrc.json
@@ -2,5 +2,10 @@
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"semi": false,
"singleQuote": true,
- "ignorePatterns": ["**/dist/**", "packages/*/CHANGELOG.md"]
+ "ignorePatterns": [
+ "**/dist/**",
+ "packages/*/CHANGELOG.md",
+ "**/fixtures/**",
+ "**/fixtures-labels/**"
+ ]
}
diff --git a/.oxlintrc.json b/.oxlintrc.json
index 14244f4..8a7b1c5 100644
--- a/.oxlintrc.json
+++ b/.oxlintrc.json
@@ -4,5 +4,8 @@
"correctness": "error",
"suspicious": "error"
},
- "ignorePatterns": ["**/dist/**"]
+ "rules": {
+ "no-shadow": "off"
+ },
+ "ignorePatterns": ["**/dist/**", "**/fixtures/**", "**/fixtures-labels/**", "**/benchmark/**"]
}
diff --git a/README.md b/README.md
index cf3e43d..292b908 100644
--- a/README.md
+++ b/README.md
@@ -20,10 +20,13 @@ Official Rolldown plugins
## Packages
- [`@rolldown/plugin-babel`](https://github.com/rolldown/plugins/tree/main/packages/babel) ([![NPM version][badge-npm-version-babel]][url-npm-babel]): transform code with Babel
+- [`@rolldown/plugin-emotion`](https://github.com/rolldown/plugins/tree/main/packages/emotion) ([![NPM version][badge-npm-version-emotion]][url-npm-emotion]): minification and optimization of Emotion styles
## License
[MIT](https://github.com/rolldown/plugins/blob/main/LICENSE)
[badge-npm-version-babel]: https://img.shields.io/npm/v/@rolldown/plugin-babel/latest?color=brightgreen
+[badge-npm-version-emotion]: https://img.shields.io/npm/v/@rolldown/plugin-emotion/latest?color=brightgreen
[url-npm-babel]: https://npmx.dev/package/@rolldown/plugin-babel/v/latest
+[url-npm-emotion]: https://npmx.dev/package/@rolldown/plugin-emotion/v/latest
diff --git a/examples/emotion/emotion.test.ts b/examples/emotion/emotion.test.ts
new file mode 100644
index 0000000..3596caa
--- /dev/null
+++ b/examples/emotion/emotion.test.ts
@@ -0,0 +1,28 @@
+import { expect, test } from 'vitest'
+import { editFile, getBg, getColor, isServe, page } from '~utils'
+
+test('should render app', async () => {
+ expect(await page.textContent('.emotion-title')).toBe('Emotion Works!')
+})
+
+test('styled component should apply styles', async () => {
+ const title = page.locator('.emotion-title')
+ const color = await getColor(title)
+ expect(color).toBe('rgb(255, 105, 180)') // hotpink
+})
+
+test('css prop should work', async () => {
+ const button = page.locator('.emotion-button')
+ const bgColor = await getBg(button)
+ expect(bgColor).toBe('rgb(100, 108, 255)') // #646cff
+})
+
+test.runIf(isServe)('hmr works', async () => {
+ editFile('src/App.tsx', (code) => code.replace('hotpink', 'blue'))
+ await expect
+ .poll(async () => {
+ const title = page.locator('.emotion-title')
+ return getColor(title)
+ })
+ .toBe('rgb(0, 0, 255)') // blue
+})
diff --git a/examples/emotion/index.html b/examples/emotion/index.html
new file mode 100644
index 0000000..be91380
--- /dev/null
+++ b/examples/emotion/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Emotion Example
+
+
+
+
+
+
diff --git a/examples/emotion/package.json b/examples/emotion/package.json
new file mode 100644
index 0000000..077574a
--- /dev/null
+++ b/examples/emotion/package.json
@@ -0,0 +1,23 @@
+{
+ "name": "@rolldown/example-emotion",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4"
+ },
+ "devDependencies": {
+ "@rolldown/plugin-emotion": "workspace:*",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "@vitejs/plugin-react": "^6.0.1",
+ "vite": "8.0.0"
+ }
+}
diff --git a/examples/emotion/src/App.tsx b/examples/emotion/src/App.tsx
new file mode 100644
index 0000000..0e6f029
--- /dev/null
+++ b/examples/emotion/src/App.tsx
@@ -0,0 +1,42 @@
+/** @jsxImportSource @emotion/react */
+import { css } from '@emotion/react'
+import styled from '@emotion/styled'
+
+const Title = styled.h1`
+ color: hotpink;
+ font-size: 2rem;
+`
+
+const buttonStyle = css`
+ padding: 0.5rem 1rem;
+ background-color: #646cff;
+ color: white;
+ border: none;
+ border-radius: 4px;
+ cursor: pointer;
+
+ &:hover {
+ background-color: #535bf2;
+ }
+`
+
+const Card = styled.div`
+ padding: 2rem;
+ border: 1px solid #ccc;
+ border-radius: 8px;
+ margin: 1rem;
+`
+
+export default function App() {
+ return (
+
+
Emotion Works!
+
+ This is a styled card component.
+
+
+
+ )
+}
diff --git a/examples/emotion/src/main.tsx b/examples/emotion/src/main.tsx
new file mode 100644
index 0000000..feac8ee
--- /dev/null
+++ b/examples/emotion/src/main.tsx
@@ -0,0 +1,9 @@
+import { StrictMode } from 'react'
+import { createRoot } from 'react-dom/client'
+import App from './App'
+
+createRoot(document.getElementById('root')!).render(
+
+
+ ,
+)
diff --git a/examples/emotion/vite.config.ts b/examples/emotion/vite.config.ts
new file mode 100644
index 0000000..c5fc483
--- /dev/null
+++ b/examples/emotion/vite.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from 'vite'
+import react from '@vitejs/plugin-react'
+import emotion from '@rolldown/plugin-emotion'
+
+export default defineConfig({
+ plugins: [
+ emotion({
+ sourceMap: true,
+ autoLabel: 'always',
+ }),
+ react({
+ jsxImportSource: '@emotion/react',
+ }),
+ ],
+})
diff --git a/examples/package.json b/examples/package.json
new file mode 100644
index 0000000..818dbee
--- /dev/null
+++ b/examples/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "@rolldown/examples",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "test": "vitest --project=e2e:dev --project=e2e:build",
+ "test:dev": "vitest --project=e2e:dev",
+ "test:build": "vitest --project=e2e:build"
+ },
+ "devDependencies": {
+ "playwright-chromium": "^1.58.2",
+ "vite": "^8.0.0"
+ }
+}
diff --git a/examples/test-utils.ts b/examples/test-utils.ts
new file mode 100644
index 0000000..f61a52f
--- /dev/null
+++ b/examples/test-utils.ts
@@ -0,0 +1,25 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import type { Locator } from 'playwright-chromium'
+import { inject } from 'vitest'
+import { tempDir } from './vitestSetup'
+
+export { page } from './vitestSetup'
+
+export const isBuild = !!inject('isBuild')
+export const isServe = !isBuild
+
+export function editFile(file: string, callback: (content: string) => string): void {
+ const filePath = path.resolve(tempDir, file)
+ const content = fs.readFileSync(filePath, 'utf-8')
+ const modified = callback(content)
+ fs.writeFileSync(filePath, modified)
+}
+
+export async function getColor(locator: Locator): Promise {
+ return locator.evaluate((el) => getComputedStyle(el).color)
+}
+
+export async function getBg(locator: Locator): Promise {
+ return locator.evaluate((el) => getComputedStyle(el).backgroundColor)
+}
diff --git a/examples/tsconfig.json b/examples/tsconfig.json
new file mode 100644
index 0000000..a2357e4
--- /dev/null
+++ b/examples/tsconfig.json
@@ -0,0 +1,19 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "preserve",
+ "lib": ["es2023", "DOM"],
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "declaration": true,
+ "jsx": "react-jsx",
+ "paths": {
+ "~utils": ["./test-utils.ts"]
+ }
+ }
+}
diff --git a/examples/vitest.config.ts b/examples/vitest.config.ts
new file mode 100644
index 0000000..5133ec1
--- /dev/null
+++ b/examples/vitest.config.ts
@@ -0,0 +1,45 @@
+import { defineConfig } from 'vitest/config'
+import { resolve } from 'node:path'
+
+const timeout = process.env.CI ? 6000 : 3000
+
+export default defineConfig({
+ resolve: {
+ alias: {
+ '~utils': resolve(import.meta.dirname, './test-utils.ts'),
+ },
+ },
+ test: {
+ setupFiles: ['./vitestSetup.ts'],
+ globalSetup: ['./vitestGlobalSetup.ts'],
+ testTimeout: timeout,
+ hookTimeout: timeout,
+ reporters: 'dot',
+ fileParallelism: false,
+ projects: [
+ {
+ extends: true,
+ test: {
+ name: 'e2e:dev',
+ env: {
+ // set here to override Vitest's default `"test"`
+ NODE_ENV: 'development',
+ },
+ },
+ },
+ {
+ extends: true,
+ test: {
+ name: 'e2e:build',
+ provide: {
+ isBuild: '1',
+ },
+ env: {
+ // set here to override Vitest's default `"test"`
+ NODE_ENV: 'production',
+ },
+ },
+ },
+ ],
+ },
+})
diff --git a/examples/vitestGlobalSetup.ts b/examples/vitestGlobalSetup.ts
new file mode 100644
index 0000000..ca419c5
--- /dev/null
+++ b/examples/vitestGlobalSetup.ts
@@ -0,0 +1,31 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import type { TestProject } from 'vitest/node'
+import type { BrowserServer } from 'playwright-chromium'
+import { chromium } from 'playwright-chromium'
+
+let tempBaseDir: string | undefined
+let browserServer: BrowserServer | undefined
+
+export async function setup({ provide, config }: TestProject): Promise {
+ browserServer = await chromium.launchServer({
+ headless: !process.env.VITE_DEBUG_SERVE,
+ args: process.env.CI ? ['--no-sandbox', '--disable-setuid-sandbox'] : undefined,
+ })
+ provide('wsEndpoint', browserServer.wsEndpoint())
+
+ const isBuild = !!config.provide.isBuild
+ tempBaseDir = path.join(import.meta.dirname, `../examples-temp-${isBuild ? 'build' : 'dev'}`)
+
+ if (!fs.existsSync(tempBaseDir)) {
+ fs.mkdirSync(tempBaseDir, { recursive: true })
+ }
+ provide('tempBaseDir', tempBaseDir)
+}
+
+export async function teardown(): Promise {
+ await browserServer?.close()
+ if (fs.existsSync(tempBaseDir!)) {
+ fs.rmSync(tempBaseDir!, { recursive: true, force: true })
+ }
+}
diff --git a/examples/vitestSetup.ts b/examples/vitestSetup.ts
new file mode 100644
index 0000000..46e0468
--- /dev/null
+++ b/examples/vitestSetup.ts
@@ -0,0 +1,114 @@
+import fs from 'node:fs'
+import path from 'node:path'
+import type { Browser, Page } from 'playwright-chromium'
+import { chromium } from 'playwright-chromium'
+import type { InlineConfig, ViteDevServer } from 'vite'
+import { build, createServer, preview } from 'vite'
+import { beforeAll, afterAll, inject } from 'vitest'
+
+let server: ViteDevServer | { close: () => Promise; resolvedUrls: { local: string[] } }
+export let tempDir: string
+let browser: Browser
+export let page: Page
+let rootDir: string
+
+const isBuild = !!inject('isBuild')
+
+// oxlint-disable-next-line no-empty-pattern
+beforeAll(async ({}, suite) => {
+ const wsEndpoint = inject('wsEndpoint')
+ if (!wsEndpoint) {
+ throw new Error('WS_ENDPOINT not found')
+ }
+
+ browser = await chromium.connect(wsEndpoint)
+ page = await browser.newPage()
+
+ // Get the test file path to determine which example to run
+ const testFile = suite.file?.filepath
+ if (!testFile) {
+ throw new Error('Could not determine test file path')
+ }
+
+ // Extract example name from path: examples/{example}/xxx.spec.ts
+ const match = testFile.match(/examples[/\\]([^/\\]+)/)
+ if (!match) {
+ throw new Error(`Could not determine example from test file: ${testFile}`)
+ }
+ const exampleName = match[1]
+
+ // Set up root directory (the example directory)
+ rootDir = path.resolve(import.meta.dirname, exampleName)
+
+ // Create temp directory for this example to allow HMR edits
+ const tempBase = inject('tempBaseDir')
+ tempDir = path.join(tempBase, `${exampleName}-${Date.now()}`)
+
+ // Copy example to temp directory
+ fs.cpSync(rootDir, tempDir, {
+ recursive: true,
+ filter(file) {
+ file = file.replace(/\\/g, '/')
+ return !file.includes('__tests__') && !/dist(?:\/|$)/.test(file)
+ },
+ })
+
+ const testConfig: InlineConfig = {
+ root: tempDir,
+ logLevel: 'silent',
+ server: {
+ watch: {
+ usePolling: true,
+ interval: 100,
+ },
+ },
+ }
+
+ if (isBuild) {
+ await build(testConfig)
+ const previewServer = await preview({
+ ...testConfig,
+ preview: {
+ port: 0,
+ strictPort: false,
+ },
+ })
+ server = {
+ close: async () => {
+ previewServer.httpServer?.close()
+ },
+ resolvedUrls: {
+ local: [
+ // oxlint-disable-next-line no-unsafe-type-assertion -- address() returns AddressInfo for TCP server
+ `http://localhost:${(previewServer.httpServer?.address() as { port: number })?.port || 4173}/`,
+ ],
+ },
+ }
+ } else {
+ server = await createServer(testConfig)
+ await server.listen()
+ }
+
+ const url = server.resolvedUrls?.local[0]
+ if (!url) {
+ throw new Error('Could not get server URL')
+ }
+
+ await page.goto(url)
+})
+
+afterAll(async () => {
+ await page?.close()
+ await server?.close()
+ if (tempDir && tempDir !== rootDir && fs.existsSync(tempDir)) {
+ fs.rmSync(tempDir, { recursive: true, force: true })
+ }
+})
+
+declare module 'vitest' {
+ export interface ProvidedContext {
+ wsEndpoint: string
+ tempBaseDir: string
+ isBuild: string
+ }
+}
diff --git a/internal-packages/benchmark-utils/package.json b/internal-packages/benchmark-utils/package.json
new file mode 100644
index 0000000..cdf9291
--- /dev/null
+++ b/internal-packages/benchmark-utils/package.json
@@ -0,0 +1,12 @@
+{
+ "name": "@rolldown/benchmark-utils",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "exports": {
+ "./seeded-random": "./src/seeded-random.ts"
+ },
+ "devDependencies": {
+ "@oxc-node/core": "^0.0.35"
+ }
+}
diff --git a/internal-packages/benchmark-utils/src/seeded-random.ts b/internal-packages/benchmark-utils/src/seeded-random.ts
new file mode 100644
index 0000000..94eeeee
--- /dev/null
+++ b/internal-packages/benchmark-utils/src/seeded-random.ts
@@ -0,0 +1,42 @@
+/**
+ * Seeded random number generator for deterministic output.
+ * All benchmark generators use seed=42.
+ */
+export class SeededRandom {
+ private seed: number
+
+ constructor(seed: number) {
+ this.seed = seed
+ }
+
+ next(): number {
+ this.seed = (this.seed * 1103515245 + 12345) & 0x7fffffff
+ return this.seed / 0x7fffffff
+ }
+
+ nextInt(max: number): number {
+ return Math.floor(this.next() * max)
+ }
+
+ pick(arr: T[]): T {
+ return arr[this.nextInt(arr.length)]
+ }
+
+ shuffle(arr: T[]): T[] {
+ const result = [...arr]
+ for (let i = result.length - 1; i > 0; i--) {
+ const j = this.nextInt(i + 1)
+ ;[result[i], result[j]] = [result[j], result[i]]
+ }
+ return result
+ }
+
+ pickN(arr: T[], n: number): T[] {
+ const shuffled = [...arr]
+ for (let i = shuffled.length - 1; i > 0; i--) {
+ const j = this.nextInt(i + 1)
+ ;[shuffled[i], shuffled[j]] = [shuffled[j], shuffled[i]]
+ }
+ return shuffled.slice(0, n)
+ }
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/README.md b/internal-packages/oxc-unshadowed-visitor/README.md
new file mode 100644
index 0000000..fb150a7
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/README.md
@@ -0,0 +1,32 @@
+# @rolldown/oxc-unshadowed-visitor
+
+Scope-aware AST visitor that tracks references to specified names, filtering out those shadowed by local bindings. Performs single-pass analysis using Rolldown's built-in AST visitor.
+
+> **Note:** This is a private internal package used by other `@rolldown` plugins. It is not published to npm.
+
+## Usage
+
+```ts
+import { parseSync } from 'rolldown/utils'
+import { ScopedVisitor } from '@rolldown/oxc-unshadowed-visitor'
+
+const program = parseSync('app.tsx', code).program
+
+const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: node.name, node, data: 'jsx-ref' })
+ }
+ },
+ },
+})
+
+const records = sv.walk(program)
+// records contains only references where `React` is NOT shadowed
+```
+
+## How it works
+
+`ScopedVisitor` walks the AST once and maintains a scope stack internally. When your visitor calls `ctx.record()`, the record is kept only if the tracked name is not shadowed at that point. If a later `var` declaration hoists into scope, previously recorded references are retroactively invalidated.
diff --git a/internal-packages/oxc-unshadowed-visitor/package.json b/internal-packages/oxc-unshadowed-visitor/package.json
new file mode 100644
index 0000000..8ba1c6a
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@rolldown/oxc-unshadowed-visitor",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "exports": "./src/index.ts",
+ "scripts": {
+ "bench": "vitest bench --project oxc-unshadowed-visitor",
+ "test": "vitest --project oxc-unshadowed-visitor"
+ },
+ "devDependencies": {
+ "oxc-walker": "^0.7.0"
+ },
+ "peerDependencies": {
+ "rolldown": "^1.0.0-rc.9"
+ }
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/binding-names.ts b/internal-packages/oxc-unshadowed-visitor/src/binding-names.ts
new file mode 100644
index 0000000..b90ff04
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/binding-names.ts
@@ -0,0 +1,42 @@
+import type { ESTree } from 'rolldown/utils'
+
+/**
+ * Recursively extracts binding names from a pattern node.
+ */
+export function extractBindingNames(
+ pattern: ESTree.ParamPattern | ESTree.BindingPattern,
+ names: string[],
+): void {
+ switch (pattern.type) {
+ case 'Identifier':
+ names.push(pattern.name)
+ break
+
+ case 'ArrayPattern':
+ for (const element of pattern.elements) {
+ if (element != null) {
+ extractBindingNames(element, names)
+ }
+ }
+ break
+
+ case 'ObjectPattern':
+ for (const prop of pattern.properties) {
+ if (prop.type === 'RestElement') {
+ extractBindingNames(prop, names)
+ } else {
+ // Property node — the value holds the binding pattern
+ extractBindingNames(prop.value, names)
+ }
+ }
+ break
+
+ case 'AssignmentPattern':
+ extractBindingNames(pattern.left, names)
+ break
+
+ case 'RestElement':
+ extractBindingNames(pattern.argument, names)
+ break
+ }
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/index.test.ts b/internal-packages/oxc-unshadowed-visitor/src/index.test.ts
new file mode 100644
index 0000000..5b19610
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/index.test.ts
@@ -0,0 +1,322 @@
+import { describe, test, expect } from 'vitest'
+import { parseSync } from 'rolldown/utils'
+import { ScopedVisitor } from './index.ts'
+
+function parse(code: string) {
+ return parseSync('test.js', code).program
+}
+
+function collectRecords(code: string, trackedNames = ['React']) {
+ const program = parse(code)
+ const sv = new ScopedVisitor({
+ trackedNames,
+ visitor: {
+ Identifier(node, ctx) {
+ if (trackedNames.includes(node.name)) {
+ ctx.record({ name: node.name, node, data: 'ref' })
+ }
+ },
+ },
+ })
+ return sv.walk(program)
+}
+
+describe('ScopedVisitor', () => {
+ test('collects records for unshadowed references', () => {
+ const records = collectRecords(`React.createElement('div');`)
+ expect(records.length).toBe(1)
+ expect(records[0].name).toBe('React')
+ expect(records[0].data).toBe('ref')
+ })
+
+ test('ignores records for untracked names', () => {
+ const code = `foo(); bar();`
+ const program = parse(code)
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ ctx.record({ name: node.name, node, data: 'ref' })
+ },
+ },
+ })
+ const records = sv.walk(program)
+ expect(records.length).toBe(0)
+ })
+
+ test.each([
+ {
+ name: 'let shadows tracked name in block scope',
+ code: `
+ React.createElement('a');
+ { let React = 'local'; React.createElement('b'); }
+ React.createElement('c');
+ `,
+ expected: 2,
+ },
+ {
+ name: 'const shadows tracked name in block scope',
+ code: `
+ React.createElement('a');
+ { const React = 'local'; React.createElement('b'); }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'var shadows tracked name in function scope',
+ code: `
+ React.createElement('a');
+ function foo() { var React = 'local'; React.createElement('b'); }
+ React.createElement('c');
+ `,
+ expected: 2,
+ },
+ {
+ name: 'function declaration shadows tracked name at block scope',
+ code: `
+ React.createElement('x');
+ { function React() {} React(); }
+ React.createElement('y');
+ `,
+ expected: 2,
+ },
+ {
+ name: 'class declaration shadows tracked name at block scope',
+ code: `
+ React.createElement('x');
+ { class React {} new React(); }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'function parameters shadow tracked name',
+ code: `
+ React.createElement('outer');
+ function foo(React) { React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'arrow function parameters shadow tracked name',
+ code: `
+ React.createElement('outer');
+ const fn = (React) => React;
+ `,
+ expected: 1,
+ },
+ {
+ name: 'catch clause parameter shadows tracked name',
+ code: `
+ React.createElement('outer');
+ try {} catch (React) { React; }
+ React.createElement('after');
+ `,
+ expected: 2,
+ },
+ {
+ name: 'object destructuring shadows tracked name',
+ code: `
+ React;
+ { const { React } = obj; React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'array destructuring shadows tracked name',
+ code: `
+ React;
+ { const [React] = arr; React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'renamed destructuring shadows tracked name',
+ code: `
+ React;
+ { const { other: React } = obj; React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'destructured function params shadow tracked name',
+ code: `
+ React;
+ const fn = ({ React }) => React;
+ `,
+ expected: 1,
+ },
+ {
+ name: 'rest parameter shadows tracked name',
+ code: `
+ React;
+ function foo(...React) { React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'default parameter value shadows tracked name',
+ code: `
+ React;
+ function foo(React = 'x') { React; }
+ `,
+ expected: 1,
+ },
+ {
+ name: 'for-of loop variable shadows tracked name',
+ code: `
+ React;
+ for (const React of items) { React; }
+ React;
+ `,
+ expected: 2,
+ },
+ {
+ name: 'for-in loop variable shadows tracked name',
+ code: `
+ React;
+ for (const React in obj) { React; }
+ React;
+ `,
+ expected: 2,
+ },
+ {
+ name: 'for loop variable shadows tracked name',
+ code: `
+ React;
+ for (let React = 0; React < 10; React++) { React; }
+ React;
+ `,
+ expected: 2,
+ },
+ {
+ name: 'var declaration after reference retroactively invalidates records',
+ code: `
+ function foo() {
+ React.createElement('a');
+ var React = 'local';
+ }
+ `,
+ expected: 0,
+ },
+ {
+ name: 'var hoisting does not affect outer scope records',
+ code: `
+ React.createElement('outer-a');
+ function foo() {
+ React.createElement('inner');
+ var React = 'local';
+ }
+ React.createElement('outer-b');
+ `,
+ expected: 2,
+ },
+ {
+ name: 'var hoisting across nested blocks within function',
+ code: `
+ function foo() {
+ { React; }
+ if (true) { var React = 'local'; }
+ }
+ `,
+ expected: 0,
+ },
+ {
+ name: 'deeply nested shadowing only affects inner scope',
+ code: `
+ React;
+ { React; { let React = 'local'; React; } React; }
+ `,
+ expected: 3,
+ },
+ {
+ name: 'same name shadowed at multiple nesting levels',
+ code: `
+ React;
+ {
+ let React = 'level-1';
+ React;
+ { let React = 'level-2'; React; }
+ }
+ `,
+ expected: 1,
+ },
+ ])('$name', ({ code, expected }) => {
+ expect(collectRecords(code).length).toBe(expected)
+ })
+
+ test('partial shadowing: only some tracked names shadowed', () => {
+ const code = `
+ React;
+ process.env;
+ function foo() {
+ let React = 'local';
+ React;
+ process.env;
+ }
+ `
+ expect(collectRecords(code, ['React', 'process']).length).toBe(3)
+ })
+
+ test('var does not shadow at module level', () => {
+ const program = parseSync('test.js', `{ var React = 'still top-level'; }`, {
+ sourceType: 'script',
+ }).program
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: node.name, node, data: 'ref' })
+ }
+ },
+ },
+ })
+ const records = sv.walk(program)
+ expect(records.length).toBe(1)
+ })
+
+ test('user exit callbacks work correctly', () => {
+ const program = parse(`function foo() { React; }`)
+ const events: string[] = []
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ FunctionDeclaration(node, _ctx) {
+ events.push('enter:' + node.id!.name)
+ },
+ 'FunctionDeclaration:exit'(node, _ctx) {
+ events.push('exit:' + node.id!.name)
+ },
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: node.name, node, data: 'ref' })
+ }
+ },
+ },
+ })
+ const records = sv.walk(program)
+ expect(events).toEqual(['enter:foo', 'exit:foo'])
+ expect(records.length).toBe(1)
+ })
+
+ test('user exit callbacks fire after scope is still active', () => {
+ const program = parse(`function foo() { let React = 'local'; React; }`)
+ const exitShadowState: boolean[] = []
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: node.name, node, data: 'ref' })
+ }
+ },
+ 'FunctionDeclaration:exit'(_node, _ctx) {
+ exitShadowState.push(true)
+ },
+ },
+ })
+ const records = sv.walk(program)
+ expect(records.length).toBe(0)
+ expect(exitShadowState.length).toBe(1)
+ })
+})
diff --git a/internal-packages/oxc-unshadowed-visitor/src/index.ts b/internal-packages/oxc-unshadowed-visitor/src/index.ts
new file mode 100644
index 0000000..6f62f18
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/index.ts
@@ -0,0 +1,7 @@
+export { ScopedVisitor } from './scoped-visitor.ts'
+export type {
+ TransformRecord,
+ ScopedVisitorObject,
+ ScopedVisitorOptions,
+} from './scoped-visitor.ts'
+export type { VisitorContext } from './types.ts'
diff --git a/internal-packages/oxc-unshadowed-visitor/src/merge-visitors.ts b/internal-packages/oxc-unshadowed-visitor/src/merge-visitors.ts
new file mode 100644
index 0000000..ad64ee7
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/merge-visitors.ts
@@ -0,0 +1,66 @@
+import type { ESTree } from 'rolldown/utils'
+import type { VisitorContext } from './types'
+
+export type SimpleScopedVisitorObject = {
+ [key: string]: (node: ESTree.Node, ctx: VisitorContext) => void
+}
+export type SimpleVisitorObject = {
+ [key: string]: (node: ESTree.Node) => void
+}
+
+/**
+ * Merge user visitors with internal scope-tracking visitors.
+ * Enter: internal runs FIRST, then user.
+ * Exit: user runs FIRST, then internal.
+ */
+export function mergeVisitors(
+ userVisitor: SimpleScopedVisitorObject,
+ ctx: VisitorContext,
+ internalEnter: SimpleVisitorObject,
+ internalExit: SimpleVisitorObject,
+): SimpleVisitorObject {
+ const merged: SimpleVisitorObject = {}
+
+ // Process user visitor keys
+ for (const key of Object.keys(userVisitor)) {
+ const userFn = userVisitor[key]
+ const isExit = key.endsWith(':exit')
+ const baseKey = isExit ? key.slice(0, -5) : key
+
+ if (isExit) {
+ const internalExitFn = internalExit[key]
+ if (internalExitFn) {
+ merged[key] = (node) => {
+ userFn?.(node, ctx)
+ internalExitFn(node)
+ }
+ } else {
+ merged[key] = (node) => {
+ userFn?.(node, ctx)
+ }
+ }
+ } else {
+ const internalEnterFn = internalEnter[baseKey]
+ if (internalEnterFn) {
+ merged[key] = (node) => {
+ internalEnterFn(node)
+ userFn(node, ctx)
+ }
+ } else {
+ merged[key] = (node) => {
+ userFn(node, ctx)
+ }
+ }
+ }
+ }
+
+ // Add internal-only visitors that the user didn't define
+ for (const [key, fn] of Object.entries(internalEnter)) {
+ if (!(key in merged)) merged[key] = fn
+ }
+ for (const [key, fn] of Object.entries(internalExit)) {
+ if (!(key in merged)) merged[key] = fn
+ }
+
+ return merged
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/scope-tracker.ts b/internal-packages/oxc-unshadowed-visitor/src/scope-tracker.ts
new file mode 100644
index 0000000..c95cec0
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/scope-tracker.ts
@@ -0,0 +1,94 @@
+interface ScopeFrame {
+ kind: 'function' | 'block'
+ /** per tracked name, does THIS scope shadow it? */
+ shadows: boolean[]
+ /** index into records array when scope was pushed */
+ recordsStartIdx: number
+}
+
+export interface Invalidatable {
+ nameIdx: number
+ invalidated: boolean
+}
+
+export class ScopeTracker {
+ /** per tracked name, 0 = not shadowed */
+ private shadowDepth: number[]
+ private nameCount: number
+ private scopeStack: ScopeFrame[]
+
+ constructor(nameCount: number) {
+ this.nameCount = nameCount
+ this.shadowDepth = Array.from({ length: nameCount }).fill(0)
+ this.scopeStack = []
+ }
+
+ pushScope(kind: 'function' | 'block', recordsLength: number): void {
+ this.scopeStack.push({
+ kind,
+ shadows: Array.from({ length: this.nameCount }).fill(false),
+ recordsStartIdx: recordsLength,
+ })
+ }
+
+ popScope(): void {
+ const frame = this.scopeStack.pop()
+ if (!frame) return
+
+ // For each name shadowed by this scope, decrement the depth counter
+ for (let i = 0; i < this.nameCount; i++) {
+ if (frame.shadows[i]) {
+ this.shadowDepth[i]--
+ }
+ }
+ }
+
+ /**
+ * Declare a block-scoped binding (let, const, class, catch param).
+ * Declares at the top of the scope stack.
+ * If the stack is empty (module level), returns without shadowing.
+ */
+ declareBlock(nameIdx: number, records: Invalidatable[]): void {
+ if (this.scopeStack.length === 0) return // module level — not shadowing
+ const frame = this.scopeStack[this.scopeStack.length - 1]
+ this._declare(frame, nameIdx, records)
+ }
+
+ /**
+ * Declare a var-scoped binding.
+ * Walks up the scope stack to find the nearest 'function' scope.
+ * If none found (module level), returns without shadowing.
+ */
+ declareVar(nameIdx: number, records: Invalidatable[]): void {
+ // Walk up to find nearest function scope
+ for (let i = this.scopeStack.length - 1; i >= 0; i--) {
+ if (this.scopeStack[i].kind === 'function') {
+ this._declare(this.scopeStack[i], nameIdx, records)
+ return
+ }
+ }
+ // No function scope found — module level, no shadowing
+ }
+
+ isShadowed(nameIdx: number): boolean {
+ return this.shadowDepth[nameIdx] > 0
+ }
+
+ private _declare(frame: ScopeFrame, nameIdx: number, records: Invalidatable[]): void {
+ if (frame.shadows[nameIdx]) return // already shadowed in this scope
+
+ frame.shadows[nameIdx] = true
+ this.shadowDepth[nameIdx]++
+
+ // Retroactively invalidate records from this scope's start
+ this._retroactiveInvalidate(frame.recordsStartIdx, nameIdx, records)
+ }
+
+ private _retroactiveInvalidate(fromIdx: number, nameIdx: number, records: Invalidatable[]): void {
+ for (let i = fromIdx; i < records.length; i++) {
+ if (records[i].nameIdx === nameIdx) {
+ records[i].invalidated = true
+ }
+ }
+ }
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/scoped-visitor.ts b/internal-packages/oxc-unshadowed-visitor/src/scoped-visitor.ts
new file mode 100644
index 0000000..7438879
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/scoped-visitor.ts
@@ -0,0 +1,173 @@
+import { Visitor } from 'rolldown/utils'
+import type { ESTree, VisitorObject } from 'rolldown/utils'
+import { ScopeTracker, type Invalidatable } from './scope-tracker.ts'
+import { extractBindingNames } from './binding-names.ts'
+import type { VisitorContext } from './types.ts'
+import {
+ mergeVisitors,
+ type SimpleScopedVisitorObject,
+ type SimpleVisitorObject,
+} from './merge-visitors.ts'
+
+export interface TransformRecord {
+ name: string
+ node: object
+ data: T
+}
+
+interface InternalRecord extends TransformRecord, Invalidatable {
+ nameIdx: number
+ invalidated: boolean
+}
+
+type ScopedVisitorHandler = H extends (node: infer N) => void
+ ? (node: N, ctx: VisitorContext) => void
+ : H
+
+export type ScopedVisitorObject = {
+ [K in keyof VisitorObject]?:
+ | ScopedVisitorHandler, T>
+ | undefined
+}
+
+export interface ScopedVisitorOptions {
+ trackedNames: string[]
+ visitor: ScopedVisitorObject
+}
+
+export class ScopedVisitor {
+ private trackedNames: string[]
+ private userVisitor: ScopedVisitorObject
+
+ constructor(options: ScopedVisitorOptions) {
+ this.trackedNames = options.trackedNames
+ this.userVisitor = options.visitor
+ }
+
+ walk(program: ESTree.Program): TransformRecord[] {
+ const records: InternalRecord[] = []
+ const trackedNames = this.trackedNames
+ const tracker = new ScopeTracker(trackedNames.length)
+
+ const ctx: VisitorContext = {
+ record(opts) {
+ const nameIdx = trackedNames.indexOf(opts.name)
+ if (nameIdx === -1) return // not a tracked name
+
+ records.push({
+ name: opts.name,
+ node: opts.node,
+ data: opts.data,
+ nameIdx,
+ invalidated: tracker.isShadowed(nameIdx),
+ })
+ },
+ }
+
+ // Reusable temp array to avoid allocations per declaration
+ const tempNames: string[] = []
+
+ /**
+ * Declare all binding names from a pattern for a given declaration style.
+ */
+ const declarePattern = (
+ pattern: ESTree.ParamPattern | ESTree.BindingPattern,
+ mode: 'block' | 'var',
+ ): void => {
+ tempNames.length = 0
+ extractBindingNames(pattern, tempNames)
+ for (const name of tempNames) {
+ const idx = trackedNames.indexOf(name)
+ if (idx === -1) continue
+ if (mode === 'block') {
+ tracker.declareBlock(idx, records)
+ } else {
+ tracker.declareVar(idx, records)
+ }
+ }
+ }
+ /**
+ * Declare all function params as block-scoped bindings.
+ */
+ const declareParams = (params: ESTree.ParamPattern[]): void => {
+ for (const param of params) declarePattern(param, 'block')
+ }
+
+ const scopeEnter: VisitorObject = {
+ FunctionDeclaration(node) {
+ // Declare function name in OUTER block scope before pushing
+ if (node.id) declarePattern(node.id, 'block')
+ tracker.pushScope('function', records.length)
+ if (node.params) declareParams(node.params)
+ },
+ FunctionExpression(node) {
+ tracker.pushScope('function', records.length)
+ // Declare function name inside function scope (named function expression)
+ if (node.id) declarePattern(node.id, 'block')
+ if (node.params) declareParams(node.params)
+ },
+ ArrowFunctionExpression(node) {
+ tracker.pushScope('function', records.length)
+ if (node.params) declareParams(node.params)
+ },
+ BlockStatement(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ ForStatement(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ ForInStatement(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ ForOfStatement(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ SwitchStatement(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ StaticBlock(_node) {
+ tracker.pushScope('block', records.length)
+ },
+ CatchClause(node) {
+ tracker.pushScope('block', records.length)
+ if (node.param) {
+ declarePattern(node.param, 'block')
+ }
+ },
+ }
+ const scopeExit: SimpleVisitorObject = {}
+ for (const key of Object.keys(scopeEnter)) {
+ scopeExit[`${key}:exit`] = () => tracker.popScope()
+ }
+
+ const declarationOnlyEnter: VisitorObject = {
+ VariableDeclaration(node) {
+ const mode = node.kind === 'var' ? 'var' : 'block'
+ for (const declarator of node.declarations) {
+ declarePattern(declarator.id, mode)
+ }
+ },
+ ClassDeclaration(node) {
+ if (node.id) {
+ declarePattern(node.id, 'block')
+ }
+ },
+ }
+
+ const oxcVisitor = mergeVisitors(
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion --- TypeScript cannot handle these complex types
+ this.userVisitor as SimpleScopedVisitorObject,
+ ctx,
+ // oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion --- TypeScript cannot handle these complex types
+ { ...(scopeEnter as SimpleVisitorObject), ...(declarationOnlyEnter as SimpleVisitorObject) },
+ scopeExit,
+ )
+
+ const visitor = new Visitor(oxcVisitor)
+ visitor.visit(program)
+
+ return records
+ .filter((r) => !r.invalidated)
+ .map(({ name, node, data }) => ({ name, node, data }))
+ }
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/types.ts b/internal-packages/oxc-unshadowed-visitor/src/types.ts
new file mode 100644
index 0000000..fa873f1
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/types.ts
@@ -0,0 +1,3 @@
+export interface VisitorContext {
+ record(opts: { name: string; node: object; data: T }): void
+}
diff --git a/internal-packages/oxc-unshadowed-visitor/src/walk.bench.ts b/internal-packages/oxc-unshadowed-visitor/src/walk.bench.ts
new file mode 100644
index 0000000..4044fc9
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/src/walk.bench.ts
@@ -0,0 +1,133 @@
+import { bench, describe } from 'vitest'
+import { parseSync } from 'rolldown/utils'
+import { walk, ScopeTracker } from 'oxc-walker'
+import { ScopedVisitor } from './index.js'
+
+// Generate a realistic fixture with shadowed and unshadowed references
+function generateFixture(repetitions: number): string {
+ const blocks: string[] = []
+ blocks.push(`import something from 'somewhere';`)
+ for (let i = 0; i < repetitions; i++) {
+ blocks.push(`
+ React.createElement('div-${i}');
+ function fn${i}(x) {
+ const y = x + ${i};
+ if (y > 0) {
+ let React = 'shadow';
+ React.createElement('shadowed-${i}');
+ }
+ return React.createElement('unshadowed-inner-${i}');
+ }
+ {
+ const a${i} = React.createElement('block-${i}');
+ }
+ `)
+ }
+ return blocks.join('\n')
+}
+
+const smallProgram = parseSync('test.js', generateFixture(10)).program
+const mediumProgram = parseSync('test.js', generateFixture(100)).program
+const largeProgram = parseSync('test.js', generateFixture(500)).program
+
+describe('small (10)', () => {
+ bench('single-pass (ScopedVisitor)', () => {
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: 'React', node, data: 'ref' })
+ }
+ },
+ },
+ })
+ sv.walk(smallProgram)
+ })
+
+ bench('two-pass (oxc-walker)', () => {
+ const scopeTracker = new ScopeTracker({ preserveExitedScopes: true })
+ walk(smallProgram, { scopeTracker, enter() {} })
+ scopeTracker.freeze()
+ const results: { name: string; node: any }[] = []
+ walk(smallProgram, {
+ scopeTracker,
+ enter(node) {
+ if (node.type === 'Identifier' && 'name' in node && node.name === 'React') {
+ const decl = scopeTracker.getDeclaration('React')
+ if (!decl) {
+ results.push({ name: 'React', node })
+ }
+ }
+ },
+ })
+ })
+})
+
+describe('medium (100)', () => {
+ bench('single-pass (ScopedVisitor)', () => {
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: 'React', node, data: 'ref' })
+ }
+ },
+ },
+ })
+ sv.walk(mediumProgram)
+ })
+
+ bench('two-pass (oxc-walker)', () => {
+ const scopeTracker = new ScopeTracker({ preserveExitedScopes: true })
+ walk(mediumProgram, { scopeTracker, enter() {} })
+ scopeTracker.freeze()
+ const results: { name: string; node: any }[] = []
+ walk(mediumProgram, {
+ scopeTracker,
+ enter(node) {
+ if (node.type === 'Identifier' && 'name' in node && node.name === 'React') {
+ const decl = scopeTracker.getDeclaration('React')
+ if (!decl) {
+ results.push({ name: 'React', node })
+ }
+ }
+ },
+ })
+ })
+})
+
+describe('large (500)', () => {
+ bench('single-pass (ScopedVisitor)', () => {
+ const sv = new ScopedVisitor({
+ trackedNames: ['React'],
+ visitor: {
+ Identifier(node, ctx) {
+ if (node.name === 'React') {
+ ctx.record({ name: 'React', node, data: 'ref' })
+ }
+ },
+ },
+ })
+ sv.walk(largeProgram)
+ })
+
+ bench('two-pass (oxc-walker)', () => {
+ const scopeTracker = new ScopeTracker({ preserveExitedScopes: true })
+ walk(largeProgram, { scopeTracker, enter() {} })
+ scopeTracker.freeze()
+ const results: { name: string; node: any }[] = []
+ walk(largeProgram, {
+ scopeTracker,
+ enter(node) {
+ if (node.type === 'Identifier' && 'name' in node && node.name === 'React') {
+ const decl = scopeTracker.getDeclaration('React')
+ if (!decl) {
+ results.push({ name: 'React', node })
+ }
+ }
+ },
+ })
+ })
+})
diff --git a/internal-packages/oxc-unshadowed-visitor/vitest.config.ts b/internal-packages/oxc-unshadowed-visitor/vitest.config.ts
new file mode 100644
index 0000000..276ef99
--- /dev/null
+++ b/internal-packages/oxc-unshadowed-visitor/vitest.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ name: 'oxc-unshadowed-visitor',
+ },
+})
diff --git a/internal-packages/swc-output-gen/package.json b/internal-packages/swc-output-gen/package.json
new file mode 100644
index 0000000..527947e
--- /dev/null
+++ b/internal-packages/swc-output-gen/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "@rolldown/swc-output-gen",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "generate": "oxnode src/index.ts"
+ },
+ "dependencies": {
+ "@oxc-node/cli": "^0.0.35",
+ "@rollup/plugin-swc": "^0.4.0",
+ "@swc/core": "^1.15.18",
+ "@swc/plugin-emotion": "^14.7.0",
+ "rolldown": "^1.0.0-rc.9",
+ "tinyglobby": "^0.2.15"
+ }
+}
diff --git a/internal-packages/swc-output-gen/src/index.ts b/internal-packages/swc-output-gen/src/index.ts
new file mode 100644
index 0000000..ff58070
--- /dev/null
+++ b/internal-packages/swc-output-gen/src/index.ts
@@ -0,0 +1,220 @@
+/**
+ * Generate SWC plugin outputs for comparison with ported plugins.
+ *
+ * Usage:
+ * pnpm generate:swc-outputs # All plugins
+ * pnpm generate:swc-outputs --plugins emotion # Specific plugin(s)
+ * pnpm generate:swc-outputs --dry-run # Preview only
+ */
+
+import { readFile, writeFile } from 'node:fs/promises'
+import { basename, dirname, join, relative } from 'node:path'
+import { glob } from 'tinyglobby'
+import { pluginRegistry, getPluginFromDirectory, getPluginNames } from './plugin-registry.js'
+import { transformWithSwc } from './swc-transformer.js'
+
+interface CliOptions {
+ plugins: string[]
+ dryRun: boolean
+}
+
+function parseArgs(): CliOptions {
+ const args = process.argv.slice(2)
+ const options: CliOptions = {
+ plugins: [],
+ dryRun: false,
+ }
+
+ for (let i = 0; i < args.length; i++) {
+ const arg = args[i]
+ if (arg === '--dry-run') {
+ options.dryRun = true
+ } else if (arg === '--plugins') {
+ // Collect all following non-flag arguments as plugin names
+ i++
+ while (i < args.length && !args[i].startsWith('--')) {
+ options.plugins.push(args[i])
+ i++
+ }
+ i-- // Back up one since the loop will increment
+ }
+ }
+
+ // Validate plugin names
+ const validPlugins = getPluginNames()
+ for (const plugin of options.plugins) {
+ if (!validPlugins.includes(plugin)) {
+ console.error(`Unknown plugin: ${plugin}`)
+ console.error(`Available plugins: ${validPlugins.join(', ')}`)
+ process.exit(1)
+ }
+ }
+
+ return options
+}
+
+async function discoverFixtures(pluginFilter: string[]): Promise {
+ const packagesDir = join(import.meta.dirname, '..', '..', '..', 'packages')
+
+ // Find all input files in both fixtures and fixtures-labels directories
+ const inputFiles = await glob(
+ [
+ '*/tests/fixtures/**/input.{js,jsx,ts,tsx}',
+ '*/tests/fixtures-labels/*/input.{js,jsx,ts,tsx}',
+ ],
+ {
+ cwd: packagesDir,
+ absolute: true,
+ },
+ )
+
+ // Filter by plugin if specified
+ if (pluginFilter.length > 0) {
+ return inputFiles.filter((file) => {
+ const relativePath = relative(packagesDir, file)
+ const pluginDir = relativePath.split('/')[0]
+ const pluginName = getPluginFromDirectory(pluginDir)
+ return pluginName && pluginFilter.includes(pluginName)
+ })
+ }
+
+ return inputFiles
+}
+
+async function loadConfig(fixtureDir: string): Promise> {
+ const configPath = join(fixtureDir, 'config.json')
+ try {
+ const content = await readFile(configPath, 'utf-8')
+ return JSON.parse(content)
+ } catch {
+ // Config is optional, default to empty object
+ return {}
+ }
+}
+
+interface ProcessResult {
+ fixture: string
+ status: 'success' | 'skipped' | 'error'
+ message?: string
+}
+
+async function processFixture(inputPath: string, dryRun: boolean): Promise {
+ const fixtureDir = dirname(inputPath)
+ const packagesDir = join(import.meta.dirname, '..', '..', '..', 'packages')
+ const relativePath = relative(packagesDir, inputPath).replaceAll('\\', '/')
+ const pluginDir = relativePath.split('/')[0]
+ const pluginName = getPluginFromDirectory(pluginDir)
+
+ if (!pluginName) {
+ return {
+ fixture: relativePath,
+ status: 'skipped',
+ message: 'Unknown plugin',
+ }
+ }
+
+ const pluginConfig = pluginRegistry[pluginName]
+ const config = await loadConfig(fixtureDir)
+
+ // Check if we should skip this fixture
+ if (pluginConfig.shouldSkip?.(config, { fixtureDir })) {
+ return {
+ fixture: relativePath,
+ status: 'skipped',
+ message: 'Fixture uses unsupported options',
+ }
+ }
+
+ // Map config to SWC plugin options
+ const plugins = pluginConfig.mapOptions(config, { fixtureDir })
+
+ if (plugins.length === 0) {
+ return {
+ fixture: relativePath,
+ status: 'skipped',
+ message: 'No plugins to apply',
+ }
+ }
+
+ if (dryRun) {
+ return {
+ fixture: relativePath,
+ status: 'success',
+ message: `Would transform with: ${plugins.map(([pkg]) => pkg).join(', ')}`,
+ }
+ }
+
+ try {
+ // Read input file
+ const code = await readFile(inputPath, 'utf-8')
+ const filename = basename(inputPath)
+
+ // Transform with SWC
+ const output = await transformWithSwc(code, {
+ filename,
+ plugins,
+ })
+
+ // Write output
+ const outputPath = join(fixtureDir, 'output.swc.js')
+ await writeFile(outputPath, output, 'utf-8')
+
+ return {
+ fixture: relativePath,
+ status: 'success',
+ }
+ } catch (error) {
+ return {
+ fixture: relativePath,
+ status: 'error',
+ message: error instanceof Error ? error.message : String(error),
+ }
+ }
+}
+
+async function main() {
+ const options = parseArgs()
+
+ console.log('Discovering fixtures...')
+ const fixtures = await discoverFixtures(options.plugins)
+
+ if (fixtures.length === 0) {
+ console.log('No fixtures found.')
+ return
+ }
+
+ console.log(`Found ${fixtures.length} fixtures.`)
+ if (options.dryRun) {
+ console.log('(Dry run - no files will be written)\n')
+ } else {
+ console.log('')
+ }
+
+ const results: ProcessResult[] = []
+
+ for (const fixture of fixtures) {
+ const result = await processFixture(fixture, options.dryRun)
+ results.push(result)
+
+ // Print result
+ const icon = result.status === 'success' ? '✓' : result.status === 'skipped' ? '○' : '✗'
+ const message = result.message ? ` (${result.message})` : ''
+ console.log(`${icon} ${result.fixture}${message}`)
+ }
+
+ // Summary
+ const success = results.filter((r) => r.status === 'success').length
+ const skipped = results.filter((r) => r.status === 'skipped').length
+ const errors = results.filter((r) => r.status === 'error').length
+
+ console.log(`\nSummary: ${success} success, ${skipped} skipped, ${errors} errors`)
+
+ if (errors > 0) {
+ process.exit(1)
+ }
+}
+
+main().catch((error) => {
+ console.error('Fatal error:', error)
+ process.exit(1)
+})
diff --git a/internal-packages/swc-output-gen/src/plugin-registry.ts b/internal-packages/swc-output-gen/src/plugin-registry.ts
new file mode 100644
index 0000000..247b8cf
--- /dev/null
+++ b/internal-packages/swc-output-gen/src/plugin-registry.ts
@@ -0,0 +1,47 @@
+/**
+ * Plugin registry that maps our plugin names to their original SWC packages
+ * and provides option mappers for transforming fixture configs to SWC plugin options.
+ */
+
+export interface MapOptionsContext {
+ /** Path to the fixture directory */
+ fixtureDir: string
+}
+
+export interface PluginConfig {
+ /** Name of the original SWC plugin package(s) */
+ packages: string[]
+ /** Map fixture config to SWC plugin options. Returns array of [package, options] tuples */
+ mapOptions: (
+ config: Record,
+ ctx: MapOptionsContext,
+ ) => Array<[string, Record]>
+ /** Whether to skip this fixture based on config and context */
+ shouldSkip?: (config: Record, ctx: MapOptionsContext) => boolean
+}
+
+export const pluginRegistry: Record = {
+ emotion: {
+ packages: ['@swc/plugin-emotion'],
+ mapOptions: (config) => [['@swc/plugin-emotion', config]],
+ shouldSkip: () => false,
+ },
+}
+
+/** Get list of all supported plugin names */
+export function getPluginNames(): string[] {
+ return Object.keys(pluginRegistry)
+}
+
+/** Get plugin config by name, extracting from package directory name */
+export function getPluginFromDirectory(dirName: string): string | undefined {
+ // Directory name is the plugin name directly (e.g., "emotion")
+ if (pluginRegistry[dirName]) return dirName
+
+ // Also support "plugin-*" naming convention
+ const match = dirName.match(/^plugin-(.+)$/)
+ if (!match) return undefined
+
+ const pluginName = match[1]
+ return pluginRegistry[pluginName] ? pluginName : undefined
+}
diff --git a/internal-packages/swc-output-gen/src/swc-transformer.ts b/internal-packages/swc-output-gen/src/swc-transformer.ts
new file mode 100644
index 0000000..f65cf23
--- /dev/null
+++ b/internal-packages/swc-output-gen/src/swc-transformer.ts
@@ -0,0 +1,111 @@
+import { rolldown } from 'rolldown'
+import swc from '@rollup/plugin-swc'
+import type { JscTarget } from '@swc/core'
+
+export interface TransformOptions {
+ filename: string
+ plugins: Array<[string, Record]>
+ /** Source code - used to detect JSX in .js files */
+ code?: string
+}
+
+/**
+ * Check if code likely contains JSX syntax
+ */
+function containsJsx(code: string): boolean {
+ // Look for JSX patterns like {
+ const parserConfig = getParserConfig(options.filename, code)
+
+ // Use extension from original filename for virtual entry to ensure correct parsing
+ const ext = options.filename.match(/\.[jt]sx?$/)?.[0] ?? '.ts'
+ const virtualEntry = `virtual:entry${ext}`
+
+ const build = await rolldown({
+ input: virtualEntry,
+ plugins: [
+ {
+ name: 'virtual',
+ resolveId(id) {
+ if (id === virtualEntry) return id
+ // Mark transformed imports as external
+ return { id, external: true }
+ },
+ load(id) {
+ if (id === virtualEntry) return code
+ },
+ },
+ swc({
+ swc: {
+ jsc: {
+ parser: parserConfig,
+ target: 'esnext' as JscTarget,
+ transform: {
+ react: {
+ // Preserve JSX - don't transform it
+ runtime: 'preserve' as const,
+ },
+ },
+ experimental: {
+ plugins: options.plugins,
+ },
+ },
+ // Don't add source maps
+ sourceMaps: false,
+ },
+ }),
+ ],
+ })
+
+ const { output } = await build.generate({ format: 'esm' })
+ return normalizeSourceMap(stripRolldownRuntime(output[0].code))
+}
+
+function stripRolldownRuntime(code: string): string {
+ // Replace rolldown runtime regions with a stable comment
+ return code.replace(
+ /\/\/#region \\0rolldown\/runtime\.js[\s\S]*?\/\/#endregion\n*/g,
+ '// [rolldown runtime elided]\n',
+ )
+}
+
+function normalizeSourceMap(code: string): string {
+ return code.replace(
+ /\/\*# sourceMappingURL=data:application\/json;charset=utf-8;base64,[^*]+ \*\//g,
+ '/*# sourceMappingURL=[sourcemap] */',
+ )
+}
diff --git a/package.json b/package.json
index da92f42..a87de24 100644
--- a/package.json
+++ b/package.json
@@ -7,10 +7,12 @@
"format": "oxfmt .",
"lint": "oxlint --type-aware --type-check .",
"test": "vitest",
+ "test:e2e": "pnpm run --filter=./examples test",
"dev": "pnpm -r --parallel --filter=\"./packages/*\" run dev",
"build": "pnpm -r --filter=\"./packages/*\" run build",
"release": "pnpm run --filter=./scripts release",
- "ci-publish": "pnpm run --filter=./scripts ci-publish"
+ "ci-publish": "pnpm run --filter=./scripts ci-publish",
+ "generate:swc-outputs": "pnpm run --filter=@rolldown/swc-output-gen generate"
},
"devDependencies": {
"@typescript/native-preview": "7.0.0-dev.20260314.1",
diff --git a/packages/babel/tsdown.config.ts b/packages/babel/tsdown.config.ts
index 87d8936..a3a2720 100644
--- a/packages/babel/tsdown.config.ts
+++ b/packages/babel/tsdown.config.ts
@@ -3,6 +3,7 @@ import { defineConfig } from 'tsdown'
export default defineConfig({
entry: './src/index.ts',
dts: {
+ tsconfig: '../../tsconfig.common.json',
tsgo: true,
},
})
diff --git a/packages/emotion/LICENSE b/packages/emotion/LICENSE
new file mode 120000
index 0000000..30cff74
--- /dev/null
+++ b/packages/emotion/LICENSE
@@ -0,0 +1 @@
+../../LICENSE
\ No newline at end of file
diff --git a/packages/emotion/README.md b/packages/emotion/README.md
new file mode 100644
index 0000000..6514800
--- /dev/null
+++ b/packages/emotion/README.md
@@ -0,0 +1,129 @@
+# @rolldown/plugin-emotion [](https://npmx.dev/package/@rolldown/plugin-emotion)
+
+Rolldown plugin for minification and optimization of [Emotion](https://emotion.sh/) styles.
+
+This plugin utilizes Rolldown's [native magic string API](https://rolldown.rs/in-depth/native-magic-string) instead of Babel and is more performant than using [`@emotion/babel-plugin`](https://emotion.sh/docs/@emotion/babel-plugin) with [`@rolldown/plugin-babel`](https://npmx.dev/package/@rolldown/plugin-babel).
+
+## Install
+
+```bash
+pnpm add -D @rolldown/plugin-emotion
+```
+
+## Usage
+
+```js
+import emotion from '@rolldown/plugin-emotion'
+
+export default {
+ plugins: [
+ emotion({
+ // options
+ }),
+ ],
+}
+```
+
+### Supported Libraries
+
+The plugin handles imports from these Emotion packages out of the box:
+
+- `@emotion/css`
+- `@emotion/styled`
+- `@emotion/react`
+- `@emotion/primitives`
+- `@emotion/native`
+
+## Options
+
+### `sourceMap`
+
+- **Type:** `boolean`
+- **Default:** `true` in development, `false` otherwise
+
+Generate source maps for Emotion CSS. Source maps help trace styles back to their original source in browser DevTools.
+
+### `autoLabel`
+
+- **Type:** `'never' | 'dev-only' | 'always'`
+- **Default:** `'dev-only'`
+
+Controls when debug labels are added to styled components and `css` calls.
+
+- `'never'` — Never add labels
+- `'dev-only'` — Only add labels in development mode
+- `'always'` — Always add labels
+
+### `labelFormat`
+
+- **Type:** `string`
+- **Default:** `"[local]"`
+
+Defines the format of generated debug labels. Only relevant when `autoLabel` is not `'never'`.
+
+Supports placeholders:
+
+- `[local]` — The variable name that the result of `css` or `styled` call is assigned to
+- `[filename]` — The file name (without extension)
+- `[dirname]` — The directory name of the file
+
+```js
+emotion({
+ autoLabel: 'always',
+ labelFormat: '[dirname]--[filename]--[local]',
+})
+```
+
+### `importMap`
+
+- **Type:** `Record`
+
+Custom import mappings for non-standard Emotion packages. Maps package names to their export configurations, allowing the plugin to transform custom libraries that re-export Emotion utilities.
+
+```js
+emotion({
+ importMap: {
+ 'my-emotion-lib': {
+ myStyled: {
+ canonicalImport: ['@emotion/styled', 'default'],
+ },
+ myCss: {
+ canonicalImport: ['@emotion/react', 'css'],
+ },
+ },
+ },
+})
+```
+
+Each entry maps an export name to its canonical Emotion equivalent via `canonicalImport: [packageName, exportName]`.
+
+## Benchmark
+
+Results of the benchmark that can be run by `pnpm bench` in `./benchmark` directory:
+
+```
+ name hz min max mean p75 p99 p995 p999 rme samples
+· @rolldown/plugin-emotion 9.7954 98.4954 108.83 102.09 103.34 108.83 108.83 108.83 ±2.23% 10
+· @rolldown/plugin-babel 3.7139 254.48 295.01 269.26 277.63 295.01 295.01 295.01 ±3.49% 10
+· @rollup/plugin-swc 7.5542 128.56 139.14 132.38 134.82 139.14 139.14 139.14 ±1.78% 10
+
+@rolldown/plugin-emotion - bench/emotion.bench.ts > Emotion Benchmark
+ 1.30x faster than @rollup/plugin-swc
+ 2.64x faster than @rolldown/plugin-babel
+```
+
+The benchmark was ran on the following environment:
+
+```
+OS: macOS Tahoe 26.3
+CPU: Apple M4
+Memory: LPDDR5X-7500 32GB
+```
+
+## License
+
+MIT
+
+## Credits
+
+The implementation is based on [swc-project/plugins/packages/emotion](https://github.com/swc-project/plugins/tree/main/packages/emotion) ([Apache License 2.0](https://github.com/swc-project/plugins/blob/main/LICENSE)). Test cases are also adapted from it.
diff --git a/packages/emotion/benchmark/.gitignore b/packages/emotion/benchmark/.gitignore
new file mode 100644
index 0000000..8bab002
--- /dev/null
+++ b/packages/emotion/benchmark/.gitignore
@@ -0,0 +1,8 @@
+# Build outputs
+dist/
+
+# Generated components (regenerated with pnpm generate)
+shared-app/src/components/
+
+# SWC plugin cache
+.swc/
diff --git a/packages/emotion/benchmark/bench/emotion.bench.ts b/packages/emotion/benchmark/bench/emotion.bench.ts
new file mode 100644
index 0000000..373d192
--- /dev/null
+++ b/packages/emotion/benchmark/bench/emotion.bench.ts
@@ -0,0 +1,52 @@
+import { bench, describe } from 'vitest'
+import { execSync } from 'node:child_process'
+import { existsSync, rmSync } from 'node:fs'
+import { resolve } from 'node:path'
+
+const baseDir = resolve(import.meta.dirname, '..')
+const distBase = resolve(baseDir, 'dist')
+const componentsDir = resolve(baseDir, 'shared-app/src/components')
+
+if (!existsSync(componentsDir)) {
+ execSync('pnpm generate', { cwd: baseDir, stdio: 'inherit' })
+}
+
+function cleanDist(name: string) {
+ const dir = resolve(distBase, name)
+ if (existsSync(dir)) {
+ rmSync(dir, { recursive: true })
+ }
+}
+
+function runBuild(name: string) {
+ execSync(`rolldown -c configs/${name}.ts`, {
+ cwd: baseDir,
+ stdio: 'pipe',
+ })
+}
+
+describe('Emotion Benchmark', () => {
+ bench(
+ '@rolldown/plugin-emotion',
+ () => {
+ runBuild('custom')
+ },
+ { teardown: () => cleanDist('custom') },
+ )
+
+ bench(
+ '@rolldown/plugin-babel',
+ () => {
+ runBuild('babel')
+ },
+ { teardown: () => cleanDist('babel') },
+ )
+
+ bench(
+ '@rollup/plugin-swc',
+ () => {
+ runBuild('swc')
+ },
+ { teardown: () => cleanDist('swc') },
+ )
+})
diff --git a/packages/emotion/benchmark/configs/babel.ts b/packages/emotion/benchmark/configs/babel.ts
new file mode 100644
index 0000000..8969aaa
--- /dev/null
+++ b/packages/emotion/benchmark/configs/babel.ts
@@ -0,0 +1,27 @@
+import { defineConfig } from 'rolldown'
+import { resolve } from 'node:path'
+import babel, { defineRolldownBabelPreset } from '@rolldown/plugin-babel'
+
+const emotionPreset = defineRolldownBabelPreset({
+ preset: () => ({
+ plugins: [['@emotion/babel-plugin', { autoLabel: 'always', sourceMap: false }]],
+ }),
+ rolldown: {
+ filter: {
+ id: /\.[jt]sx?$/,
+ code: '@emotion',
+ },
+ },
+})
+
+export default defineConfig({
+ input: resolve(import.meta.dirname, '../shared-app/src/index.tsx'),
+ output: {
+ dir: resolve(import.meta.dirname, '../dist/babel'),
+ },
+ plugins: [
+ babel({
+ presets: [emotionPreset],
+ }),
+ ],
+})
diff --git a/packages/emotion/benchmark/configs/custom.ts b/packages/emotion/benchmark/configs/custom.ts
new file mode 100644
index 0000000..4606523
--- /dev/null
+++ b/packages/emotion/benchmark/configs/custom.ts
@@ -0,0 +1,11 @@
+import { defineConfig } from 'rolldown'
+import { resolve } from 'node:path'
+import emotion from '@rolldown/plugin-emotion'
+
+export default defineConfig({
+ input: resolve(import.meta.dirname, '../shared-app/src/index.tsx'),
+ output: {
+ dir: resolve(import.meta.dirname, '../dist/custom'),
+ },
+ plugins: [emotion({ autoLabel: 'always', sourceMap: false })],
+})
diff --git a/packages/emotion/benchmark/configs/swc.ts b/packages/emotion/benchmark/configs/swc.ts
new file mode 100644
index 0000000..e05e1fc
--- /dev/null
+++ b/packages/emotion/benchmark/configs/swc.ts
@@ -0,0 +1,39 @@
+import { defineConfig } from 'rolldown'
+import { resolve } from 'node:path'
+import { withFilter } from 'rolldown/filter'
+import swc from '@rollup/plugin-swc'
+
+export default defineConfig({
+ input: resolve(import.meta.dirname, '../shared-app/src/index.tsx'),
+ output: {
+ dir: resolve(import.meta.dirname, '../dist/swc'),
+ },
+ plugins: [
+ withFilter(
+ swc({
+ swc: {
+ jsc: {
+ parser: {
+ syntax: 'typescript',
+ tsx: true,
+ },
+ transform: {
+ react: {
+ runtime: 'preserve',
+ },
+ },
+ experimental: {
+ plugins: [['@swc/plugin-emotion', { autoLabel: 'always', sourceMap: false }]],
+ },
+ },
+ },
+ }),
+ {
+ transform: {
+ id: { include: /\.[jt]sx?$/ },
+ code: { include: '@emotion' },
+ },
+ },
+ ),
+ ],
+})
diff --git a/packages/emotion/benchmark/package.json b/packages/emotion/benchmark/package.json
new file mode 100644
index 0000000..dde5f43
--- /dev/null
+++ b/packages/emotion/benchmark/package.json
@@ -0,0 +1,34 @@
+{
+ "name": "@rolldown/benchmark-emotion",
+ "version": "0.0.0",
+ "private": true,
+ "type": "module",
+ "scripts": {
+ "generate": "oxnode scripts/generate-app.ts",
+ "bench": "vitest bench --run",
+ "build:custom": "rolldown -c configs/custom.ts",
+ "build:babel": "rolldown -c configs/babel.ts",
+ "build:swc": "rolldown -c configs/swc.ts"
+ },
+ "dependencies": {
+ "@emotion/react": "^11.14.0",
+ "@emotion/styled": "^11.14.1",
+ "react": "^19.2.4",
+ "react-dom": "^19.2.4"
+ },
+ "devDependencies": {
+ "@babel/core": "^7.29.0",
+ "@emotion/babel-plugin": "^11.13.5",
+ "@oxc-node/cli": "^0.0.35",
+ "@rolldown/benchmark-utils": "workspace:*",
+ "@rolldown/plugin-babel": "file:../../babel",
+ "@rolldown/plugin-emotion": "workspace:*",
+ "@rollup/plugin-swc": "^0.4.0",
+ "@swc/core": "^1.15.18",
+ "@swc/plugin-emotion": "^14.7.0",
+ "@types/node": "^24.10.13",
+ "@types/react": "^19.2.14",
+ "@types/react-dom": "^19.2.3",
+ "rolldown": "^1.0.0-rc.9"
+ }
+}
diff --git a/packages/emotion/benchmark/scripts/generate-app.ts b/packages/emotion/benchmark/scripts/generate-app.ts
new file mode 100644
index 0000000..b4884c8
--- /dev/null
+++ b/packages/emotion/benchmark/scripts/generate-app.ts
@@ -0,0 +1,302 @@
+/**
+ * Component generator for Emotion benchmark.
+ * Generates ~100 React components with varied Emotion styled patterns.
+ * Uses seeded random (seed=42) for deterministic generation.
+ */
+
+import { writeFileSync, mkdirSync, existsSync, rmSync } from 'node:fs'
+import { join } from 'node:path'
+
+import { SeededRandom } from '@rolldown/benchmark-utils/seeded-random'
+
+const rng = new SeededRandom(42)
+
+type ComponentType = 'StyledButton' | 'StyledCard' | 'CssComponent' | 'AnimatedBox' | 'ThemedPanel'
+const COMPONENT_TYPES: ComponentType[] = [
+ 'StyledButton',
+ 'StyledCard',
+ 'CssComponent',
+ 'AnimatedBox',
+ 'ThemedPanel',
+]
+
+const COLORS = [
+ '#ff6b6b',
+ '#4ecdc4',
+ '#45b7d1',
+ '#96ceb4',
+ '#ffeaa7',
+ '#dfe6e9',
+ '#6c5ce7',
+ '#fd79a8',
+]
+const SIZES = ['4px', '8px', '12px', '16px', '24px', '32px']
+const FONTS = ["'Inter'", "'Roboto'", "'system-ui'", "'monospace'"]
+
+function generateStyledButton(index: number): string {
+ const bg = rng.pick(COLORS)
+ const radius = rng.pick(SIZES)
+ const padding = rng.pick(SIZES)
+ const hasHover = rng.next() > 0.3
+
+ return `import React from 'react'
+import styled from '@emotion/styled'
+
+const Button = styled.button\`
+ background-color: ${bg};
+ border: none;
+ border-radius: ${radius};
+ padding: ${padding} \${parseInt('${padding}') * 2}px;
+ color: white;
+ font-size: 14px;
+ cursor: pointer;
+ transition: all 0.2s ease;
+${
+ hasHover
+ ? ` &:hover {
+ opacity: 0.8;
+ transform: scale(1.05);
+ }`
+ : ''
+}
+\`
+
+const Label = styled.span\`
+ font-weight: 600;
+ margin-right: 8px;
+\`
+
+export function StyledButton${index}({ children, onClick }: { children: React.ReactNode; onClick?: () => void }) {
+ return (
+
+ )
+}
+`
+}
+
+function generateStyledCard(index: number): string {
+ const bg = rng.pick(COLORS)
+ const shadow = rng.next() > 0.5
+ const border = rng.next() > 0.5
+
+ return `import React from 'react'
+import styled from '@emotion/styled'
+
+const Card = styled.div\`
+ background: ${bg}20;
+ border-radius: 12px;
+ padding: 24px;
+${shadow ? ' box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);' : ''}
+${border ? ` border: 1px solid ${bg}40;` : ''}
+\`
+
+const Title = styled.h3\`
+ margin: 0 0 12px;
+ font-size: 18px;
+ color: #333;
+\`
+
+const Content = styled.p\`
+ margin: 0;
+ color: #666;
+ line-height: 1.6;
+\`
+
+const Footer = styled.div\`
+ margin-top: 16px;
+ padding-top: 12px;
+ border-top: 1px solid #eee;
+ display: flex;
+ justify-content: space-between;
+\`
+
+export function StyledCard${index}({ title, content }: { title: string; content: string }) {
+ return (
+
+ {title}
+ {content}
+
+
+ )
+}
+`
+}
+
+function generateCssComponent(index: number): string {
+ const color = rng.pick(COLORS)
+ const font = rng.pick(FONTS)
+
+ return `/** @jsxImportSource @emotion/react */
+import React from 'react'
+import { css } from '@emotion/react'
+
+const containerStyle = css\`
+ padding: 16px;
+ font-family: ${font};
+ color: ${color};
+\`
+
+const headingStyle = css\`
+ font-size: 24px;
+ font-weight: bold;
+ margin-bottom: 8px;
+\`
+
+const textStyle = css\`
+ font-size: 14px;
+ line-height: 1.5;
+ opacity: 0.8;
+\`
+
+export function CssComponent${index}({ heading, text }: { heading: string; text: string }) {
+ return (
+
+ )
+}
+`
+}
+
+function generateAnimatedBox(index: number): string {
+ const color = rng.pick(COLORS)
+ const size = 40 + rng.nextInt(60)
+
+ return `import React from 'react'
+import styled from '@emotion/styled'
+import { keyframes } from '@emotion/react'
+
+const pulse = keyframes\`
+ 0% { transform: scale(1); }
+ 50% { transform: scale(1.1); }
+ 100% { transform: scale(1); }
+\`
+
+const rotate = keyframes\`
+ from { transform: rotate(0deg); }
+ to { transform: rotate(360deg); }
+\`
+
+const Box = styled.div\`
+ width: ${size}px;
+ height: ${size}px;
+ background: ${color};
+ border-radius: 8px;
+ animation: \${pulse} 2s ease-in-out infinite;
+\`
+
+const Spinner = styled.div\`
+ width: 24px;
+ height: 24px;
+ border: 3px solid ${color}40;
+ border-top-color: ${color};
+ border-radius: 50%;
+ animation: \${rotate} 1s linear infinite;
+\`
+
+export function AnimatedBox${index}({ loading }: { loading?: boolean }) {
+ return loading ? :
+}
+`
+}
+
+function generateThemedPanel(index: number): string {
+ const hasBorder = rng.next() > 0.5
+ const hasIcon = rng.next() > 0.5
+
+ return `import React from 'react'
+import styled from '@emotion/styled'
+
+interface PanelProps {
+ variant: 'primary' | 'secondary' | 'danger'
+}
+
+const colorMap = {
+ primary: '#4ecdc4',
+ secondary: '#95a5a6',
+ danger: '#e74c3c',
+}
+
+const Panel = styled.div\`
+ padding: 20px;
+ background: \${(props) => colorMap[props.variant]}15;
+ color: \${(props) => colorMap[props.variant]};
+${hasBorder ? ' border-left: 4px solid currentColor;' : ' border-radius: 8px;'}
+\`
+
+const PanelTitle = styled.h4\`
+ margin: 0 0 8px;
+ font-size: 16px;
+\`
+
+const PanelBody = styled.div\`
+ font-size: 14px;
+ opacity: 0.9;
+\`
+${
+ hasIcon
+ ? `
+const Icon = styled.span\`
+ margin-right: 8px;
+ font-size: 18px;
+\``
+ : ''
+}
+
+export function ThemedPanel${index}({ variant, title, children }: PanelProps & { title: string; children: React.ReactNode }) {
+ return (
+
+ ${hasIcon ? '*' : ''}{title}
+ {children}
+
+ )
+}
+`
+}
+
+const GENERATORS: Record string> = {
+ StyledButton: generateStyledButton,
+ StyledCard: generateStyledCard,
+ CssComponent: generateCssComponent,
+ AnimatedBox: generateAnimatedBox,
+ ThemedPanel: generateThemedPanel,
+}
+
+function main() {
+ const componentsDir = join(import.meta.dirname, '../shared-app/src/components')
+ if (existsSync(componentsDir)) rmSync(componentsDir, { recursive: true })
+ mkdirSync(componentsDir, { recursive: true })
+
+ const components: Array<{ type: ComponentType; index: number }> = []
+ const TOTAL = 100
+ const perType = Math.floor(TOTAL / COMPONENT_TYPES.length)
+ const remainder = TOTAL % COMPONENT_TYPES.length
+
+ for (let i = 0; i < COMPONENT_TYPES.length; i++) {
+ const type = COMPONENT_TYPES[i]
+ const count = perType + (i < remainder ? 1 : 0)
+ for (let j = 0; j < count; j++) {
+ const index = components.length + 1
+ components.push({ type, index })
+ writeFileSync(join(componentsDir, `${type}${index}.tsx`), GENERATORS[type](index))
+ }
+ }
+
+ const exports = components
+ .map(({ type, index }) => `export { ${type}${index} } from './${type}${index}.js'`)
+ .join('\n')
+ writeFileSync(join(componentsDir, 'index.ts'), exports + '\n')
+
+ console.log(`Generated ${components.length} components in ${componentsDir}`)
+ for (const type of COMPONENT_TYPES) {
+ console.log(` ${type}: ${components.filter((c) => c.type === type).length}`)
+ }
+}
+
+main()
diff --git a/packages/emotion/benchmark/shared-app/src/App.tsx b/packages/emotion/benchmark/shared-app/src/App.tsx
new file mode 100644
index 0000000..54c2397
--- /dev/null
+++ b/packages/emotion/benchmark/shared-app/src/App.tsx
@@ -0,0 +1,31 @@
+import React from 'react'
+import * as Components from './components/index.js'
+
+type AnyComponent = React.ComponentType>
+// oxlint-disable-next-line typescript-eslint/no-unsafe-type-assertion
+const componentEntries = Object.entries(Components) as unknown as [string, AnyComponent][]
+
+export function App() {
+ return (
+
+
Emotion Benchmark App
+
This app contains {componentEntries.length} components for benchmarking.
+
+ {componentEntries.map(([name, Component]) => (
+
+ {}}
+ title="Title"
+ content="Content text"
+ heading="Heading"
+ text="Body text"
+ loading={false}
+ variant="primary"
+ />
+
+ ))}
+
+
+ )
+}
diff --git a/packages/emotion/benchmark/shared-app/src/index.tsx b/packages/emotion/benchmark/shared-app/src/index.tsx
new file mode 100644
index 0000000..07c809b
--- /dev/null
+++ b/packages/emotion/benchmark/shared-app/src/index.tsx
@@ -0,0 +1,13 @@
+import React from 'react'
+import { createRoot } from 'react-dom/client'
+import { App } from './App.js'
+
+const container = document.getElementById('root')
+if (container) {
+ const root = createRoot(container)
+ root.render(
+
+
+ ,
+ )
+}
diff --git a/packages/emotion/benchmark/vitest.config.ts b/packages/emotion/benchmark/vitest.config.ts
new file mode 100644
index 0000000..f9cf58d
--- /dev/null
+++ b/packages/emotion/benchmark/vitest.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ name: 'benchmark-emotion',
+ },
+})
diff --git a/packages/emotion/package.json b/packages/emotion/package.json
new file mode 100644
index 0000000..d253756
--- /dev/null
+++ b/packages/emotion/package.json
@@ -0,0 +1,63 @@
+{
+ "name": "@rolldown/plugin-emotion",
+ "version": "0.1.0",
+ "description": "Rolldown plugin for Emotion CSS-in-JS",
+ "keywords": [
+ "css-in-js",
+ "emotion",
+ "plugin",
+ "rolldown",
+ "rolldown-plugin"
+ ],
+ "homepage": "https://github.com/rolldown/plugins/tree/main/packages/emotion#readme",
+ "bugs": {
+ "url": "https://github.com/rolldown/plugins/issues"
+ },
+ "license": "MIT",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/rolldown/plugins.git",
+ "directory": "packages/emotion"
+ },
+ "files": [
+ "dist"
+ ],
+ "type": "module",
+ "exports": "./dist/index.mjs",
+ "scripts": {
+ "dev": "tsdown --watch",
+ "build": "tsdown",
+ "test": "vitest --project emotion",
+ "prepublishOnly": "pnpm run build"
+ },
+ "dependencies": {
+ "@emotion/hash": "^0.9.2",
+ "@jridgewell/gen-mapping": "^0.3.13",
+ "rolldown-string": "^0.3.0"
+ },
+ "devDependencies": {
+ "@rolldown/oxc-unshadowed-visitor": "workspace:*",
+ "rolldown": "^1.0.0-rc.9",
+ "tinyglobby": "^0.2.15",
+ "vite": "^8.0.0"
+ },
+ "peerDependencies": {
+ "rolldown": "^1.0.0-rc.9",
+ "vite": "^8.0.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ },
+ "engines": {
+ "node": ">=22.12.0 || ^24.0.0"
+ },
+ "compatiblePackages": {
+ "schemaVersion": 1,
+ "rollup": {
+ "type": "incompatible",
+ "reason": "Uses Rolldown-specific APIs"
+ }
+ }
+}
diff --git a/packages/emotion/src/common.ts b/packages/emotion/src/common.ts
new file mode 100644
index 0000000..7aa89e1
--- /dev/null
+++ b/packages/emotion/src/common.ts
@@ -0,0 +1,65 @@
+export const ExprKind = {
+ Css: 0,
+ Styled: 1,
+ GlobalJSX: 2,
+} as const
+export type ExprKind = (typeof ExprKind)[keyof typeof ExprKind]
+
+export function regexEscape(str: string): string {
+ return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
+}
+
+/**
+ * Unescape template literal raw text to get the actual string value.
+ * Template literal raw text preserves escape sequences as written in source.
+ * We need to convert them to their actual characters.
+ */
+export function unescapeTemplateRaw(raw: string): string {
+ return raw
+ .replace(/\\`/g, '`')
+ .replace(/\\\$/g, '$')
+ .replace(/\\b/g, '\b')
+ .replace(/\\f/g, '\f')
+ .replace(/\\n/g, '\n')
+ .replace(/\\r/g, '\r')
+ .replace(/\\t/g, '\t')
+ .replace(/\\v/g, '\v')
+ .replace(/\\\\/g, '\\')
+}
+
+/**
+ * Escape a string for use inside a JS double-quoted string literal.
+ */
+export function escapeJSString(str: string): string {
+ return (
+ str
+ .replace(/\\/g, '\\\\')
+ .replace(/"/g, '\\"')
+ .replace(/\n/g, '\\n')
+ .replace(/\r/g, '\\r')
+ .replace(/\t/g, '\\t')
+ .replace(/\f/g, '\\f')
+ // oxlint-disable-next-line no-control-regex
+ .replace(/\u000b/g, '\\v')
+ .replace(/[\b]/g, '\\b')
+ )
+}
+
+const SPACE_REGEX = /\s/
+
+export function checkTrailingCommaExistence(str: string, endIndex: number): boolean {
+ for (let i = endIndex - 1; i >= 0; i--) {
+ const char = str[i]
+ if (char === ',') {
+ return true
+ }
+ if (!SPACE_REGEX.test(char)) {
+ break
+ }
+ }
+ return false
+}
+
+export function maybeComma(needed: boolean): string {
+ return needed ? ', ' : ''
+}
diff --git a/packages/emotion/src/css-minify.test.ts b/packages/emotion/src/css-minify.test.ts
new file mode 100644
index 0000000..7690eb1
--- /dev/null
+++ b/packages/emotion/src/css-minify.test.ts
@@ -0,0 +1,37 @@
+import { expect, test } from 'vitest'
+import { minifyCSSString } from './css-minify'
+
+const tests: Record<
+ string,
+ { input: { css: string; isFirst?: boolean; isLast?: boolean }; output: string }
+> = {
+ 'should not trim end space in first item': {
+ input: { css: '\nbox-shadow: inset 0px 0px 0px ', isFirst: true, isLast: false },
+ output: 'box-shadow:inset 0px 0px 0px ',
+ },
+ 'should minify single line comment correctly': {
+ input: { css: '//comment;\ncolor: red;//comment\nbackground-image:url(http://dummy-url)' },
+ output: 'color:red;background-image:url(http://dummy-url)',
+ },
+ 'should remove comments': {
+ input: {
+ css: 'color: red;/*comment\ncomments*/background-image:url(http://dummy-url).foo{/*comments\n*/\n}',
+ },
+ output: 'color:red;background-image:url(http://dummy-url).foo{}',
+ },
+ 'issue 258 should preserve url starting with two slashes 1': {
+ input: { css: "background-image: url('//domain.com/image.png');" },
+ output: "background-image:url('//domain.com/image.png');",
+ },
+ 'issue 258 should preserve url starting with two slashes 2': {
+ input: { css: 'background-image: url("//domain.com/image.png");' },
+ output: 'background-image:url("//domain.com/image.png");',
+ },
+}
+
+for (const [name, { input, output }] of Object.entries(tests)) {
+ test(name, () => {
+ const result = minifyCSSString(input.css, input.isFirst ?? true, input.isLast ?? false)
+ expect(result).toBe(output)
+ })
+}
diff --git a/packages/emotion/src/css-minify.ts b/packages/emotion/src/css-minify.ts
new file mode 100644
index 0000000..39c2022
--- /dev/null
+++ b/packages/emotion/src/css-minify.ts
@@ -0,0 +1,38 @@
+// Remove multi-line comments: /* ... */
+const MULTI_LINE_COMMENT = /\/\*[\s\S]*?\*\//g
+
+// Remove single-line comments: // ...
+// Preserves URLs like url('//...') and url("//...")
+// Group $1 captures the character before // (if any)
+const SINGLE_LINE_COMMENT = /(^|[^:'^"]|\s)\/\/.*$/gm
+
+// Collapse whitespace around CSS punctuation: : ; , { }
+const SPACE_AROUND_COLON = /\s*([:;,{}])\s*/g
+
+export function minifyCSSString(input: string, isFirst: boolean, isLast: boolean): string {
+ // Step 1: Remove multi-line comments
+ let result = input.replace(MULTI_LINE_COMMENT, '')
+
+ // Step 2: Remove single-line comments (preserving preceding char)
+ result = result.replace(SINGLE_LINE_COMMENT, '$1')
+
+ // Step 3: Trim leading/trailing whitespace
+ // First item: trim both spaces and newlines from start
+ // Middle items: only trim newlines from start/end
+ // Last item: trim both spaces and newlines from end
+ if (isFirst) {
+ result = result.replace(/^[\s]+/, '')
+ } else {
+ result = result.replace(/^\n+/, '')
+ }
+ if (isLast) {
+ result = result.replace(/[\s]+$/, '')
+ } else {
+ result = result.replace(/\n+$/, '')
+ }
+
+ // Step 4: Collapse whitespace around CSS punctuation
+ result = result.replace(SPACE_AROUND_COLON, '$1')
+
+ return result
+}
diff --git a/packages/emotion/src/import-map.ts b/packages/emotion/src/import-map.ts
new file mode 100644
index 0000000..3ff3abf
--- /dev/null
+++ b/packages/emotion/src/import-map.ts
@@ -0,0 +1,103 @@
+import type { ESTree } from 'rolldown/utils'
+import { ExprKind } from './common'
+import type { ImportMapConfig } from './types'
+
+export type EmotionImportMap = Record<
+ /* moduleName */ string,
+ Record* exportName */ string, ExprKind>
+>
+
+const EMOTION_OFFICIAL_LIBRARIES: EmotionImportMap = {
+ '@emotion/css': { css: ExprKind.Css, default: ExprKind.Css },
+ '@emotion/styled': { default: ExprKind.Styled },
+ '@emotion/react': { css: ExprKind.Css, keyframes: ExprKind.Css, Global: ExprKind.GlobalJSX },
+ '@emotion/primitives': { css: ExprKind.Css, default: ExprKind.Styled },
+ '@emotion/native': { css: ExprKind.Css, default: ExprKind.Styled },
+}
+
+export function expandImportMap(
+ importMap: Record | undefined,
+): EmotionImportMap {
+ const configs: EmotionImportMap = JSON.parse(JSON.stringify(EMOTION_OFFICIAL_LIBRARIES))
+ if (!importMap) return configs
+
+ for (const [importSource, exports] of Object.entries(importMap)) {
+ for (const [localExportName, entry] of Object.entries(exports)) {
+ const [packageName, exportName] = entry.canonicalImport
+ if (packageName === '@emotion/react' && exportName === 'jsx') continue
+
+ const canonicalConfig = EMOTION_OFFICIAL_LIBRARIES[packageName]
+ if (canonicalConfig === undefined) {
+ throw new Error(
+ `Import map entry for "${importSource}" references unknown package "${packageName}". ` +
+ `Must be one of: ${Object.keys(EMOTION_OFFICIAL_LIBRARIES).join(', ')}`,
+ )
+ }
+ const kind = canonicalConfig[exportName]
+ if (kind === undefined) {
+ throw new Error(
+ `Import map entry for "${importSource}" references unknown export "${exportName}" in package "${packageName}". ` +
+ `Must be one of: ${Object.keys(canonicalConfig).join(', ')}`,
+ )
+ }
+ configs[importSource] ??= {}
+ configs[importSource][localExportName] = kind
+ }
+ }
+ return configs
+}
+
+export type PackageMeta =
+ | { type: 'named'; kind: ExprKind }
+ | { type: 'namespace'; config: Record }
+
+export interface ImportMap {
+ addFromImportDecl(importDecl: ESTree.ImportDeclaration): void
+ get(importedName: string): PackageMeta | undefined
+ getTrackedNames(): string[]
+ isEmpty(): boolean
+}
+
+export function createImportMap(registeredImports: EmotionImportMap): ImportMap {
+ const importPackages = new Map()
+
+ return {
+ addFromImportDecl(importDecl) {
+ if (importDecl.importKind === 'type') return
+
+ const src = importDecl.source.value
+ const config = registeredImports[src]
+ if (!config) return
+
+ for (const spec of importDecl.specifiers) {
+ if (spec.type === 'ImportSpecifier') {
+ const importedName =
+ spec.imported.type === 'Identifier' ? spec.imported.name : spec.imported.value
+ const kind = config[importedName]
+ if (kind !== undefined) {
+ importPackages.set(spec.local.name, { type: 'named', kind })
+ }
+ } else if (spec.type === 'ImportDefaultSpecifier') {
+ const kind = config.default
+ if (kind !== undefined) {
+ importPackages.set(spec.local.name, { type: 'named', kind })
+ }
+ } else if (spec.type === 'ImportNamespaceSpecifier') {
+ importPackages.set(spec.local.name, {
+ type: 'namespace',
+ config,
+ })
+ }
+ }
+ },
+ get(importedName) {
+ return importPackages.get(importedName)
+ },
+ getTrackedNames() {
+ return [...importPackages.keys()]
+ },
+ isEmpty() {
+ return importPackages.size === 0
+ },
+ }
+}
diff --git a/packages/emotion/src/index.ts b/packages/emotion/src/index.ts
new file mode 100644
index 0000000..20afa96
--- /dev/null
+++ b/packages/emotion/src/index.ts
@@ -0,0 +1,702 @@
+import { withMagicString } from 'rolldown-string'
+import type { Plugin } from 'rolldown'
+import type { ESTree } from 'rolldown/utils'
+import { ScopedVisitor } from '@rolldown/oxc-unshadowed-visitor'
+import type { EmotionPluginOptions } from './types.js'
+import { minifyCSSString } from './css-minify.js'
+import { createSourceMap, getPos } from './source-map.js'
+import {
+ ExprKind,
+ regexEscape,
+ unescapeTemplateRaw,
+ escapeJSString,
+ checkTrailingCommaExistence,
+ maybeComma,
+} from './common.js'
+import { createImportMap, expandImportMap } from './import-map.js'
+import { createLabelWithInfo } from './label.js'
+import path from 'node:path'
+import hashString from '@emotion/hash'
+
+export type { EmotionPluginOptions } from './types.js'
+
+interface RecordData {
+ nodeStart: number
+ nodeEnd: number
+ isFullReplace: boolean
+ apply: (getTarget: () => string) => void
+}
+
+export default function emotionPlugin(options: EmotionPluginOptions = {}): Plugin {
+ const sourceMapEnabled = options.sourceMap
+ const autoLabel = options.autoLabel ?? 'dev-only'
+ const labelFormat = options.labelFormat ?? '[local]'
+ const registeredImports = expandImportMap(options.importMap)
+
+ let isDev = false
+
+ return {
+ name: 'rolldown-plugin-emotion',
+ // @ts-expect-error Vite-specific property
+ enforce: 'pre',
+
+ // @ts-expect-error Vite-specific hook
+ configResolved(config) {
+ isDev = !config.isProduction
+ },
+
+ outputOptions() {
+ if ('viteVersion' in this.meta) return
+ isDev = process.env.NODE_ENV === 'development'
+ },
+
+ transform: {
+ filter: {
+ id: /\.[jt]sx?$/,
+ code: new RegExp(Object.keys(registeredImports).map(regexEscape).join('|')),
+ },
+
+ handler: withMagicString(function (this, s, id, meta) {
+ const lang = id.endsWith('.tsx')
+ ? 'tsx'
+ : id.endsWith('.ts')
+ ? 'ts'
+ : id.endsWith('.jsx')
+ ? 'jsx'
+ : 'js'
+ const program = meta?.ast ?? this.parse(s.original, { lang })
+
+ const sourceContent = s.original
+ const srcFileHash = hashString(sourceContent)
+ const fileStem = path.basename(id, path.extname(id))
+ const dirName = path.basename(path.dirname(id))
+
+ let targetCount = 0
+ const importMap = createImportMap(registeredImports)
+
+ function shouldAddLabel(): boolean {
+ switch (autoLabel) {
+ case 'always':
+ return true
+ case 'never':
+ return false
+ case 'dev-only':
+ return isDev
+ default:
+ autoLabel satisfies never
+ return false
+ }
+ }
+
+ function createLabel(context: string | null, withPrefix: boolean): string {
+ return createLabelWithInfo(labelFormat, context, fileStem, dirName ?? '', withPrefix)
+ }
+
+ function makeSourceMap(offset: number): string | null {
+ if (!(sourceMapEnabled ?? isDev)) return null
+ const pos = getPos(sourceContent, offset)
+ return createSourceMap(sourceContent, id, pos)
+ }
+
+ function buildTaggedTemplateArgs(
+ quasi: ESTree.TemplateLiteral,
+ inJsx: boolean,
+ labelContext: string | null,
+ sourceMapOffset: number,
+ withLabelPrefix: boolean,
+ includeLabel: boolean = true,
+ ): string {
+ const quasis = quasi.quasis
+ const expressions = quasi.expressions
+ const argsLen = quasis.length + expressions.length
+ const parts: string[] = []
+
+ for (let index = 0; index < argsLen; index++) {
+ const i = Math.floor(index / 2)
+ if (index % 2 === 0) {
+ // Template quasi (static text)
+ const raw = quasis[i].value.raw
+ const unescaped = unescapeTemplateRaw(raw)
+ const minified = minifyCSSString(unescaped, index === 0, index === argsLen - 1)
+ // Compress one more spaces into one space
+ if (minified.replaceAll(' ', '') === '') {
+ if (index !== 0 && index !== argsLen - 1) {
+ parts.push('" "')
+ }
+ } else {
+ parts.push(`"${escapeJSString(minified)}"`)
+ }
+ } else {
+ // Expression (interpolation)
+ const expr = expressions[i]
+ parts.push(s.slice(expr.start, expr.end))
+ }
+ }
+
+ // Add label and source map (unless in JSX element context)
+ if (!inJsx) {
+ if (includeLabel && shouldAddLabel()) {
+ const label = createLabel(labelContext, withLabelPrefix)
+ parts.push(`"${escapeJSString(label)}"`)
+ }
+ const sm = makeSourceMap(sourceMapOffset)
+ if (sm) {
+ parts.push(`"${escapeJSString(sm)}"`)
+ }
+ }
+
+ return parts.join(', ')
+ }
+
+ for (const node of program.body) {
+ if (node.type === 'ImportDeclaration') {
+ importMap.addFromImportDecl(node)
+ }
+ }
+ const trackedNames = importMap.getTrackedNames()
+ if (trackedNames.length === 0) return
+
+ const labelContextStack: (string | null)[] = [null]
+ let inJsx = false
+ const sv = new ScopedVisitor({
+ trackedNames,
+ visitor: {
+ VariableDeclarator(node) {
+ let ctx = null
+ if (node.id.type === 'Identifier') {
+ ctx = node.id.name
+ }
+ // Named function expression overrides variable name
+ if (node.init?.type === 'FunctionExpression' && node.init.id) {
+ ctx = node.init.id.name
+ }
+ labelContextStack.push(ctx)
+ },
+ 'VariableDeclarator:exit'() {
+ labelContextStack.pop()
+ },
+
+ FunctionDeclaration(node) {
+ // Function declarations always have an id
+ labelContextStack.push(node.id!.name)
+ },
+ 'FunctionDeclaration:exit'() {
+ labelContextStack.pop()
+ },
+
+ Property(node) {
+ let ctx = null
+ if (!node.computed) {
+ if (node.key.type === 'Identifier') ctx = node.key.name
+ else if (node.key.type === 'Literal' && typeof node.key.value === 'string')
+ ctx = node.key.value
+ }
+ labelContextStack.push(ctx)
+ },
+ 'Property:exit'() {
+ labelContextStack.pop()
+ },
+
+ ClassDeclaration(node) {
+ const name = node.id?.name ?? labelContextStack[labelContextStack.length - 1]
+ labelContextStack.push(name)
+ },
+ 'ClassDeclaration:exit'() {
+ labelContextStack.pop()
+ },
+
+ PropertyDefinition(node) {
+ let ctx = labelContextStack[labelContextStack.length - 1]
+ if (node.key.type === 'Identifier' && !node.computed) {
+ ctx = node.key.name
+ }
+ labelContextStack.push(ctx)
+ },
+ 'PropertyDefinition:exit'() {
+ labelContextStack.pop()
+ },
+
+ JSXElement(node, ctx) {
+ const opening = node.openingElement
+ let isGlobal = false
+ let smOffset = node.start
+ let recordName: string | null = null
+
+ // Check if this is a component
+ if (opening.name.type === 'JSXIdentifier') {
+ const meta = importMap.get(opening.name.name)
+ if (meta?.type === 'named' && meta.kind === ExprKind.GlobalJSX) {
+ isGlobal = true
+ smOffset = opening.name.start
+ recordName = opening.name.name
+ }
+ }
+
+ // Check namespace:
+ if (!isGlobal && opening.name.type === 'JSXMemberExpression') {
+ const obj = opening.name.object
+ const prop = opening.name.property
+ if (obj.type === 'JSXIdentifier' && prop.type === 'JSXIdentifier') {
+ const meta = importMap.get(obj.name)
+ if (meta?.type === 'namespace' && meta.config[prop.name] === ExprKind.GlobalJSX) {
+ isGlobal = true
+ smOffset = obj.start
+ recordName = obj.name
+ }
+ }
+ }
+
+ if (isGlobal && recordName) {
+ const stylesAttr = opening.attributes.find(
+ (a): a is ESTree.JSXAttribute =>
+ a.type === 'JSXAttribute' &&
+ a.name.type === 'JSXIdentifier' &&
+ a.name.name === 'styles',
+ )
+ if (stylesAttr?.value) {
+ inJsx = true
+ const attrValue = stylesAttr.value
+ let exprStart: number
+ let exprEnd: number
+ if (attrValue.type === 'JSXExpressionContainer') {
+ exprStart = attrValue.expression.start
+ exprEnd = attrValue.expression.end
+ } else {
+ exprStart = attrValue.start
+ exprEnd = attrValue.end
+ }
+
+ const capturedSmOffset = smOffset
+ ctx.record({
+ name: recordName,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: false,
+ apply: () => {
+ const sm = makeSourceMap(capturedSmOffset)
+ if (sm) {
+ s.appendLeft(exprStart, '[')
+ s.appendRight(exprEnd, `, "${escapeJSString(sm)}"]`)
+ }
+ },
+ },
+ })
+ }
+ }
+ },
+ 'JSXElement:exit'() {
+ inJsx = false
+ },
+
+ TaggedTemplateExpression(node, ctx) {
+ const tag = node.tag
+ const quasi = node.quasi
+ const labelContext = labelContextStack[labelContextStack.length - 1]
+
+ // --- css`...` / keyframes`...` ---
+ if (tag.type === 'Identifier') {
+ const meta = importMap.get(tag.name)
+ if (meta?.type === 'named' && meta.kind === ExprKind.Css) {
+ let wasInJsx = inJsx
+ ctx.record({
+ name: tag.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: true,
+ apply: () => {
+ const args = buildTaggedTemplateArgs(
+ quasi,
+ wasInJsx,
+ labelContext,
+ node.start,
+ false,
+ )
+ const tagText = s.slice(tag.start, tag.end)
+ s.update(node.start, node.end, `${tagText}(${args})`)
+ if (!wasInJsx) {
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ }
+ },
+ },
+ })
+ return
+ }
+ }
+
+ // --- styled.div`...` / namespace.css`...` ---
+ if (
+ tag.type === 'MemberExpression' &&
+ !tag.computed &&
+ tag.object.type === 'Identifier'
+ ) {
+ const meta = importMap.get(tag.object.name)
+ if (meta?.type === 'named' && meta.kind === ExprKind.Styled) {
+ ctx.record({
+ name: tag.object.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: true,
+ apply: (getTarget) => {
+ let labelObj = `target: "${getTarget()}"`
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, false)
+ labelObj += `, label: "${escapeJSString(label)}"`
+ }
+
+ const styledArgs = buildTaggedTemplateArgs(
+ quasi,
+ false,
+ labelContext,
+ node.start,
+ false,
+ false,
+ )
+ const styledName = s.slice(tag.object.start, tag.object.end)
+ const propName = tag.property.name
+ s.update(
+ node.start,
+ node.end,
+ `${styledName}("${escapeJSString(propName)}", {\n${labelObj}\n})(${styledArgs})`,
+ )
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ },
+ },
+ })
+ return
+ }
+
+ // --- namespace.css`...` ---
+ if (meta?.type === 'namespace') {
+ const propName = tag.property.type === 'Identifier' ? tag.property.name : null
+ if (!propName || meta.config[propName] !== ExprKind.Css) return
+
+ let wasInJsx = inJsx
+ ctx.record({
+ name: tag.object.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: true,
+ apply: () => {
+ const tagText = s.slice(tag.start, tag.end)
+ const args = buildTaggedTemplateArgs(
+ quasi,
+ wasInJsx,
+ labelContext,
+ node.start,
+ true,
+ )
+ s.update(node.start, node.end, `${tagText}(${args})`)
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ },
+ },
+ })
+ return
+ }
+ }
+
+ // --- styled(Component)`...` ---
+ if (tag.type === 'CallExpression' && tag.callee.type === 'Identifier') {
+ const meta = importMap.get(tag.callee.name)
+ if (meta?.type === 'named' && meta.kind === ExprKind.Styled) {
+ ctx.record({
+ name: tag.callee.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: true,
+ apply: (getTarget) => {
+ const styledName = s.slice(tag.callee.start, tag.callee.end)
+ const target = getTarget()
+ let labelObj = `target: "${target}"`
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, false)
+ labelObj += `, label: "${escapeJSString(label)}"`
+ }
+
+ // Extract existing args from styled(Component, ...)
+ const existingArgs = tag.arguments
+ const firstArgText =
+ existingArgs.length > 0
+ ? s.slice(existingArgs[0].start, existingArgs[0].end)
+ : ''
+
+ let innerCallText: string
+ if (existingArgs.length <= 1) {
+ // styled(Component) → styled(Component, { target, label })
+ innerCallText = `${styledName}(${firstArgText}, {\n${labelObj}\n})`
+ } else {
+ // styled(Component, options) → need to merge options
+ const secondArg = existingArgs[1]
+ if (secondArg.type === 'ObjectExpression') {
+ // Merge target/label into existing object
+ const objText = s.slice(secondArg.start + 1, secondArg.end - 1)
+ const isEmpty = objText.trim() === ''
+ const hasTrailingComma = !isEmpty && objText.trimEnd().endsWith(',')
+ const prefix = isEmpty
+ ? ''
+ : `${objText}${maybeComma(!hasTrailingComma)} `
+ innerCallText = `${styledName}(${firstArgText}, { ${prefix}${labelObj} })`
+ } else {
+ // Wrap with spread
+ const secondArgText = s.slice(secondArg.start, secondArg.end)
+ innerCallText = `${styledName}(${firstArgText}, {\n${labelObj},\n\t...${secondArgText}\n})`
+ }
+ }
+
+ const styledArgs = buildTaggedTemplateArgs(
+ quasi,
+ false,
+ labelContext,
+ node.start,
+ false,
+ false,
+ )
+ s.update(node.start, node.end, `${innerCallText}(${styledArgs})`)
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ },
+ },
+ })
+ return
+ }
+ }
+ },
+
+ CallExpression(node, ctx) {
+ const callee = node.callee
+ const args = node.arguments
+ const labelContext = labelContextStack[labelContextStack.length - 1]
+
+ // --- css({...}) ---
+ if (callee.type === 'Identifier') {
+ const meta = importMap.get(callee.name)
+ if (
+ meta?.type === 'named' &&
+ meta.kind === ExprKind.Css &&
+ args.length > 0 &&
+ !inJsx
+ ) {
+ ctx.record({
+ name: callee.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: false,
+ apply: () => {
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ let hasTrailingComma = checkTrailingCommaExistence(s.original, node.end - 1)
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, true)
+ s.appendRight(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(label)}"`,
+ )
+ hasTrailingComma = false
+ }
+ const sm = makeSourceMap(node.start)
+ if (sm) {
+ s.appendRight(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(sm)}"`,
+ )
+ }
+ },
+ },
+ })
+ return
+ }
+ }
+
+ // --- styled('div')({...}) ---
+ if (callee.type === 'CallExpression') {
+ const innerCallee = callee.callee
+ if (innerCallee.type === 'Identifier') {
+ const meta = importMap.get(innerCallee.name)
+ if (
+ meta?.type === 'named' &&
+ meta.kind === ExprKind.Styled &&
+ callee.arguments.length > 0
+ ) {
+ ctx.record({
+ name: innerCallee.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: false,
+ apply: (getTarget) => {
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ let labelObj = `target: "${getTarget()}"`
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, false)
+ labelObj += `, label: "${escapeJSString(label)}"`
+ }
+ // Add { target, label } as second arg to inner call
+ if (callee.arguments.length === 1) {
+ // Insert before inner call's closing )
+ s.appendLeft(callee.end - 1, `, {\n\t${labelObj}\n}`)
+ } else if (callee.arguments.length >= 2) {
+ const secondArg = callee.arguments[1]
+ if (secondArg.type === 'ObjectExpression') {
+ // Insert before the closing } of the object
+ const isEmpty = secondArg.properties.length === 0
+ if (isEmpty) {
+ s.appendLeft(secondArg.end - 1, ` ${labelObj} `)
+ } else {
+ const hasTrailingComma = checkTrailingCommaExistence(
+ s.original,
+ secondArg.end - 1,
+ )
+ s.appendLeft(
+ secondArg.end - 1,
+ `${maybeComma(!hasTrailingComma)} ${labelObj}`,
+ )
+ }
+ } else {
+ // Wrap with spread
+ const secondArgText = s.slice(secondArg.start, secondArg.end)
+ s.update(
+ secondArg.start,
+ secondArg.end,
+ `{ ${labelObj}, ...${secondArgText} }`,
+ )
+ }
+ }
+ const sm = makeSourceMap(node.start)
+ if (sm) {
+ const hasTrailingComma = checkTrailingCommaExistence(
+ s.original,
+ node.end - 1,
+ )
+ s.appendLeft(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(sm)}"`,
+ )
+ }
+ },
+ },
+ })
+ return
+ }
+ }
+ }
+
+ // --- styled.div({...}) / namespace.css({...}) ---
+ if (
+ callee.type === 'MemberExpression' &&
+ !callee.computed &&
+ callee.object.type === 'Identifier'
+ ) {
+ const meta = importMap.get(callee.object.name)
+ if (meta?.type === 'named' && meta.kind === ExprKind.Styled) {
+ let wasInJsx = inJsx
+ ctx.record({
+ name: callee.object.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: false,
+ apply: (getTarget) => {
+ let labelObj = ''
+ if (!wasInJsx) {
+ labelObj += `target: "${getTarget()}"`
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, false)
+ labelObj += `, label: "${escapeJSString(label)}"`
+ }
+ }
+ const styledName = s.slice(callee.object.start, callee.object.end)
+ const propName = callee.property.name
+ // Replace callee styled.div with styled("div", { target, label })
+ s.update(
+ callee.start,
+ callee.end,
+ `${styledName}("${escapeJSString(propName)}"${labelObj ? `, { ${labelObj} }` : ''})`,
+ )
+ if (!wasInJsx) {
+ const sm = makeSourceMap(node.start)
+ if (sm) {
+ const hasTrailingComma = checkTrailingCommaExistence(
+ s.original,
+ node.end - 1,
+ )
+ s.appendLeft(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(sm)}"`,
+ )
+ }
+ }
+ },
+ },
+ })
+ return
+ }
+
+ // --- namespace.css({...}) ---
+ if (meta?.type === 'namespace') {
+ const propName =
+ callee.property.type === 'Identifier' ? callee.property.name : null
+ if (!propName || meta.config[propName] !== ExprKind.Css) return
+
+ ctx.record({
+ name: callee.object.name,
+ node,
+ data: {
+ nodeStart: node.start,
+ nodeEnd: node.end,
+ isFullReplace: false,
+ apply: () => {
+ s.appendLeft(node.start, '/* @__PURE__ */ ')
+ let hasTrailingComma = checkTrailingCommaExistence(s.original, node.end - 1)
+ if (shouldAddLabel()) {
+ const label = createLabel(labelContext, true)
+ s.appendRight(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(label)}"`,
+ )
+ hasTrailingComma = false
+ }
+ const sm = makeSourceMap(node.start)
+ if (sm) {
+ s.appendRight(
+ node.end - 1,
+ `${maybeComma(!hasTrailingComma)}"${escapeJSString(sm)}"`,
+ )
+ }
+ },
+ },
+ })
+ return
+ }
+ }
+ },
+ },
+ })
+
+ const records = sv.walk(program)
+ if (records.length === 0) return
+
+ const consumedRanges: [number, number][] = []
+ for (const record of records) {
+ const { nodeStart, nodeEnd, isFullReplace, apply } = record.data
+ // Skip records fully contained within an already-consumed range
+ // (e.g., inner tagged template inside an outer one that was replaced)
+ if (consumedRanges.some(([cs, ce]) => nodeStart >= cs && nodeEnd <= ce)) continue
+ apply(() => `e${srcFileHash}${targetCount++}`)
+ if (isFullReplace) consumedRanges.push([nodeStart, nodeEnd])
+ }
+ }),
+ },
+ }
+}
diff --git a/packages/emotion/src/label.ts b/packages/emotion/src/label.ts
new file mode 100644
index 0000000..1da25c0
--- /dev/null
+++ b/packages/emotion/src/label.ts
@@ -0,0 +1,32 @@
+const INVALID_LABEL_SPACES = /\s+/g
+
+const INVALID_CSS_CLASS_NAME_CHARS = /[!"#$%&'()*+,./:;<=>?@[\\\]^`|}~{]/g
+
+export function sanitizeLabelPart(part: string): string {
+ // Existing @emotion/babel-plugin behaviour is to replace all spaces
+ // with a single hyphen
+ return part.replace(INVALID_LABEL_SPACES, '-').replace(INVALID_CSS_CLASS_NAME_CHARS, '-')
+}
+
+export function createLabelWithInfo(
+ labelFormat: string,
+ context: string | null,
+ fileStem: string,
+ dirName: string,
+ withPrefix: boolean,
+): string {
+ // Existing @emotion/babel-plugin behaviour is to
+ // not provide a label if there is no available identifier
+ if (context == null) return ''
+
+ const prefix = withPrefix ? 'label:' : ''
+ let label = `${prefix}${labelFormat}`
+ label = label.replace('[local]', sanitizeLabelPart(context))
+ if (fileStem) {
+ label = label.replace('[filename]', sanitizeLabelPart(fileStem))
+ }
+ if (dirName) {
+ label = label.replace('[dirname]', sanitizeLabelPart(dirName))
+ }
+ return label
+}
diff --git a/packages/emotion/src/source-map.ts b/packages/emotion/src/source-map.ts
new file mode 100644
index 0000000..b37d2df
--- /dev/null
+++ b/packages/emotion/src/source-map.ts
@@ -0,0 +1,40 @@
+import { GenMapping, addSegment, setSourceContent, toEncodedMap } from '@jridgewell/gen-mapping'
+
+/**
+ * Create an inline source map comment string.
+ *
+ * @param sourceContent - The full original source code
+ * @param filename - The source filename (with extension stripped)
+ * @param pos - The 0-indexed line and column number of the expression in the original source
+ */
+export function createSourceMap(
+ sourceContent: string,
+ filename: string,
+ pos: { line: number; column: number },
+): string {
+ const map = new GenMapping({ file: filename })
+ setSourceContent(map, filename, sourceContent)
+ addSegment(map, 0, 0, filename, pos.line, pos.column)
+
+ const encoded = btoa(JSON.stringify(toEncodedMap(map)))
+ return `/*# sourceMappingURL=data:application/json;charset=utf-8;base64,${encoded} */`
+}
+
+const LF = '\n'.charCodeAt(0)
+
+/**
+ * Get the 0-indexed line number and column for a character offset in the source.
+ */
+export function getPos(source: string, offset: number): { line: number; column: number } {
+ let line = 0
+ let column = 0
+ for (let i = 0; i < offset && i < source.length; i++) {
+ if (source.charCodeAt(i) === LF) {
+ line++
+ column = 0
+ } else {
+ column++
+ }
+ }
+ return { line, column }
+}
diff --git a/packages/emotion/src/types.ts b/packages/emotion/src/types.ts
new file mode 100644
index 0000000..33c521f
--- /dev/null
+++ b/packages/emotion/src/types.ts
@@ -0,0 +1,76 @@
+/**
+ * Configuration for custom emotion-like packages
+ * Maps export names to their canonical emotion equivalents
+ */
+export interface ImportMapEntry {
+ /**
+ * The canonical emotion import this maps to
+ * @example ["@emotion/styled", "default"]
+ */
+ canonicalImport: [packageName: string, exportName: string]
+
+ /**
+ * The styled base import for this package
+ * @example ["package/base", "something"]
+ */
+ styledBaseImport?: [packageName: string, exportName: string]
+}
+
+export type ImportMapConfig = Record
+
+export interface EmotionPluginOptions {
+ /**
+ * Generate source maps for emotion CSS.
+ * @default true for development, otherwise false
+ */
+ sourceMap?: boolean
+
+ /**
+ * When to add debug labels to styled components.
+ * - 'never': Never add labels
+ * - 'dev-only': Only add labels in development mode (default)
+ * - 'always': Always add labels
+ * @default 'dev-only'
+ */
+ autoLabel?: 'never' | 'dev-only' | 'always'
+
+ /**
+ * Label format template.
+ *
+ * Defines the format of the generated debug labels.
+ * This option is only relevant if `autoLabel` is not set to 'never'.
+ *
+ * Supports placeholders:
+ * - [local]: The variable name that the result of `css` or `styled` call is assigned to
+ * - [filename]: The file name (without extension) that the `css` or `styled` call is in
+ * - [dirname]: The directory name of the file that the `css` or `styled` call is in
+ *
+ * @default "[local]"
+ * @example "[dirname]--[filename]--[local]"
+ */
+ labelFormat?: string
+
+ /**
+ * Custom import mappings for non-standard emotion packages.
+ * Maps package names to their export configurations.
+ *
+ * @example
+ * If you have a custom library "my-emotion-lib" that re-exports
+ * the default export of `@emotion/styled` as `myStyled` and
+ * the `css` export of `@emotion/react` as `myCss`,
+ * then you can configure it like this:
+ * ```
+ * {
+ * "my-emotion-lib": {
+ * "myStyled": {
+ * canonicalImport: ["@emotion/styled", "default"]
+ * },
+ * "myCss": {
+ * canonicalImport: ["@emotion/react", "css"]
+ * }
+ * }
+ * }
+ * ```
+ */
+ importMap?: Record
+}
diff --git a/packages/emotion/tests/fixtures-labels/basic/input.ts b/packages/emotion/tests/fixtures-labels/basic/input.ts
new file mode 100644
index 0000000..0beca57
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/basic/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/basic.js
+
+import { css } from '@emotion/react'
+
+export function doThing() {
+ return css`
+ display: flex;
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/basic/output.js b/packages/emotion/tests/fixtures-labels/basic/output.js
new file mode 100644
index 0000000..316d77a
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/basic/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+function doThing() {
+ return /* @__PURE__ */ css("display:flex;", "doThing", "/*# sourceMappingURL=[sourcemap] */");
+}
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/call-expression/input.ts b/packages/emotion/tests/fixtures-labels/call-expression/input.ts
new file mode 100644
index 0000000..603ca7d
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/call-expression/input.ts
@@ -0,0 +1,7 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/call-expression.js
+
+import { css } from '@emotion/react'
+
+export function doThing() {
+ return css({ color: 'hotpink' })
+}
diff --git a/packages/emotion/tests/fixtures-labels/call-expression/output.js b/packages/emotion/tests/fixtures-labels/call-expression/output.js
new file mode 100644
index 0000000..3974d32
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/call-expression/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+function doThing() {
+ return /* @__PURE__ */ css({ color: "hotpink" }, "label:doThing", "/*# sourceMappingURL=[sourcemap] */");
+}
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/call-inside-call/input.ts b/packages/emotion/tests/fixtures-labels/call-inside-call/input.ts
new file mode 100644
index 0000000..ceeea12
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/call-inside-call/input.ts
@@ -0,0 +1,12 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/call-inside-call.js
+
+import { css } from '@emotion/react'
+
+export const thing = css`
+ display: flex;
+ &:hover {
+ ${css`
+ color: hotpink;
+ `};
+ }
+`
diff --git a/packages/emotion/tests/fixtures-labels/call-inside-call/output.js b/packages/emotion/tests/fixtures-labels/call-inside-call/output.js
new file mode 100644
index 0000000..aa18235
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/call-inside-call/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = /* @__PURE__ */ css("display:flex;&:hover{", css`
+ color: hotpink;
+ `, ";}", "thing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/comment-with-interpolation/input.ts b/packages/emotion/tests/fixtures-labels/comment-with-interpolation/input.ts
new file mode 100644
index 0000000..93529f5
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/comment-with-interpolation/input.ts
@@ -0,0 +1,23 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/comment-with-interpolation.js
+
+import { css } from '@emotion/react'
+
+export const doThing = css`
+ // color: ${'green'};
+ /*
+
+ something: ${'something'};
+
+ */
+ color: hotpink;
+`
+
+export const doThing2 = css`
+ // color: ${'green'};
+ /*
+
+ something: ${'something'};
+
+ */
+ color: ${'hotpink'};
+`
diff --git a/packages/emotion/tests/fixtures-labels/comment-with-interpolation/output.js b/packages/emotion/tests/fixtures-labels/comment-with-interpolation/output.js
new file mode 100644
index 0000000..d71639f
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/comment-with-interpolation/output.js
@@ -0,0 +1,6 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const doThing = /* @__PURE__ */ css("green", ";/*\n\n something:", "something", ";*/\n color:hotpink;", "doThing", "/*# sourceMappingURL=[sourcemap] */");
+const doThing2 = /* @__PURE__ */ css("green", ";/*\n\n something:", "something", ";*/\n color:", "hotpink", ";", "doThing2", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { doThing, doThing2 };
diff --git a/packages/emotion/tests/fixtures-labels/css-inside-function/input.ts b/packages/emotion/tests/fixtures-labels/css-inside-function/input.ts
new file mode 100644
index 0000000..d22f460
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/css-inside-function/input.ts
@@ -0,0 +1,13 @@
+import { css } from '@emotion/css'
+
+const wrapFunction = (cb) => {
+ return cb()
+}
+
+export const classes = wrapFunction(() => {
+ const class1 = css({ color: 'red' })
+
+ return {
+ class1,
+ }
+})
diff --git a/packages/emotion/tests/fixtures-labels/css-inside-function/output.js b/packages/emotion/tests/fixtures-labels/css-inside-function/output.js
new file mode 100644
index 0000000..aa565c3
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/css-inside-function/output.js
@@ -0,0 +1,10 @@
+import { css } from "@emotion/css";
+//#region virtual:entry.ts
+const wrapFunction = (cb) => {
+ return cb();
+};
+const classes = wrapFunction(() => {
+ return { class1: /* @__PURE__ */ css({ color: "red" }, "label:class1", "/*# sourceMappingURL=[sourcemap] */") };
+});
+//#endregion
+export { classes };
diff --git a/packages/emotion/tests/fixtures-labels/impure/input.ts b/packages/emotion/tests/fixtures-labels/impure/input.ts
new file mode 100644
index 0000000..4806991
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/impure/input.ts
@@ -0,0 +1,11 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/impure.js
+
+import { css } from '@emotion/react'
+
+function thing() {}
+
+export function doThing() {
+ return css`
+ display: ${thing()};
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/impure/output.js b/packages/emotion/tests/fixtures-labels/impure/output.js
new file mode 100644
index 0000000..635de43
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/impure/output.js
@@ -0,0 +1,8 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+function thing() {}
+function doThing() {
+ return /* @__PURE__ */ css("display:", thing(), ";", "doThing", "/*# sourceMappingURL=[sourcemap] */");
+}
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/input.ts b/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/input.ts
new file mode 100644
index 0000000..6bd8557
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/inside-anonymous-arrow-function.js
+
+import { css } from '@emotion/react'
+
+export default () => {
+ return css`
+ color: hotpink;
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/output.js b/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/output.js
new file mode 100644
index 0000000..1555018
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/inside-anonymous-arrow-function/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+var virtual_entry_default = () => {
+ return /* @__PURE__ */ css("color:hotpink;", "", "/*# sourceMappingURL=[sourcemap] */");
+};
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures-labels/inside-anonymous-function/input.ts b/packages/emotion/tests/fixtures-labels/inside-anonymous-function/input.ts
new file mode 100644
index 0000000..31b7aae
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/inside-anonymous-function/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/inside-anonymous-function.js
+
+import { css } from '@emotion/react'
+
+export default () => {
+ return css`
+ color: hotpink;
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/inside-anonymous-function/output.js b/packages/emotion/tests/fixtures-labels/inside-anonymous-function/output.js
new file mode 100644
index 0000000..1555018
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/inside-anonymous-function/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+var virtual_entry_default = () => {
+ return /* @__PURE__ */ css("color:hotpink;", "", "/*# sourceMappingURL=[sourcemap] */");
+};
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures-labels/label-1/input.ts b/packages/emotion/tests/fixtures-labels/label-1/input.ts
new file mode 100644
index 0000000..6de3951
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-1/input.ts
@@ -0,0 +1,7 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-1.js
+
+import { css } from '@emotion/react'
+
+export const thing = css`
+ color: hotpink;
+`
diff --git a/packages/emotion/tests/fixtures-labels/label-1/output.js b/packages/emotion/tests/fixtures-labels/label-1/output.js
new file mode 100644
index 0000000..77397a4
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-1/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = /* @__PURE__ */ css("color:hotpink;", "thing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/input.ts b/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/input.ts
new file mode 100644
index 0000000..dc349a1
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-arrow-as-obj-property.js
+
+import { css } from '@emotion/react'
+
+export const styles = {
+ colorFn1: () => css`
+ color: hotpink;
+ `,
+}
diff --git a/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/output.js b/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/output.js
new file mode 100644
index 0000000..c331bc5
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-arrow-as-obj-property/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const styles = { colorFn1: () => /* @__PURE__ */ css("color:hotpink;", "colorFn1", "/*# sourceMappingURL=[sourcemap] */") };
+//#endregion
+export { styles };
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/input.ts b/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/input.ts
new file mode 100644
index 0000000..54424fe
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/input.ts
@@ -0,0 +1,11 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-function-expression-as-obj-property.js
+
+import { css } from '@emotion/react'
+
+export const styles = {
+ colorFn1: function () {
+ return css`
+ color: hotpink;
+ `
+ },
+}
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/output.js b/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/output.js
new file mode 100644
index 0000000..cc2efbc
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression-as-obj-property/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const styles = { colorFn1: function() {
+ return /* @__PURE__ */ css("color:hotpink;", "colorFn1", "/*# sourceMappingURL=[sourcemap] */");
+} };
+//#endregion
+export { styles };
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression-named/input.ts b/packages/emotion/tests/fixtures-labels/label-function-expression-named/input.ts
new file mode 100644
index 0000000..36837d6
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression-named/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-function-expression-named.js
+
+import { css } from '@emotion/react'
+
+export const thing = function someName() {
+ return css`
+ color: hotpink;
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression-named/output.js b/packages/emotion/tests/fixtures-labels/label-function-expression-named/output.js
new file mode 100644
index 0000000..47b4147
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression-named/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = function someName() {
+ return /* @__PURE__ */ css("color:hotpink;", "someName", "/*# sourceMappingURL=[sourcemap] */");
+};
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression/input.ts b/packages/emotion/tests/fixtures-labels/label-function-expression/input.ts
new file mode 100644
index 0000000..559261b
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-function-expression.js
+
+import { css } from '@emotion/react'
+
+export const thing = function () {
+ return css`
+ color: hotpink;
+ `
+}
diff --git a/packages/emotion/tests/fixtures-labels/label-function-expression/output.js b/packages/emotion/tests/fixtures-labels/label-function-expression/output.js
new file mode 100644
index 0000000..11243b7
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-function-expression/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = function() {
+ return /* @__PURE__ */ css("color:hotpink;", "thing", "/*# sourceMappingURL=[sourcemap] */");
+};
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/label-no-final-semi/input.ts b/packages/emotion/tests/fixtures-labels/label-no-final-semi/input.ts
new file mode 100644
index 0000000..c0ae7a7
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-no-final-semi/input.ts
@@ -0,0 +1,8 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-no-final-semi.js
+
+import { css } from '@emotion/react'
+
+// prettier-ignore
+export const thing = css`
+ color: hotpink
+`
diff --git a/packages/emotion/tests/fixtures-labels/label-no-final-semi/output.js b/packages/emotion/tests/fixtures-labels/label-no-final-semi/output.js
new file mode 100644
index 0000000..7bdd3b7
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-no-final-semi/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = /* @__PURE__ */ css("color:hotpink", "thing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/label-object/input.ts b/packages/emotion/tests/fixtures-labels/label-object/input.ts
new file mode 100644
index 0000000..ef8da08
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-object/input.ts
@@ -0,0 +1,13 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/label-object.js
+
+import { css } from '@emotion/react'
+
+export const thing = {
+ thisShouldBeTheLabel: css`
+ color: hotpink;
+ `,
+ // prettier-ignore
+ 'shouldBeAnotherLabel':css`
+ color:green;
+ `,
+}
diff --git a/packages/emotion/tests/fixtures-labels/label-object/output.js b/packages/emotion/tests/fixtures-labels/label-object/output.js
new file mode 100644
index 0000000..a7712cb
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/label-object/output.js
@@ -0,0 +1,8 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = {
+ thisShouldBeTheLabel: /* @__PURE__ */ css("color:hotpink;", "thisShouldBeTheLabel", "/*# sourceMappingURL=[sourcemap] */"),
+ "shouldBeAnotherLabel": /* @__PURE__ */ css("color:green;", "shouldBeAnotherLabel", "/*# sourceMappingURL=[sourcemap] */")
+};
+//#endregion
+export { thing };
diff --git a/packages/emotion/tests/fixtures-labels/multiple-calls/input.ts b/packages/emotion/tests/fixtures-labels/multiple-calls/input.ts
new file mode 100644
index 0000000..6bee597
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/multiple-calls/input.ts
@@ -0,0 +1,11 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/multiple-calls.js
+
+import { css } from '@emotion/react'
+
+export const thing = css`
+ color: hotpink;
+`
+
+export const otherThing = css`
+ color: green;
+`
diff --git a/packages/emotion/tests/fixtures-labels/multiple-calls/output.js b/packages/emotion/tests/fixtures-labels/multiple-calls/output.js
new file mode 100644
index 0000000..b1f3635
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/multiple-calls/output.js
@@ -0,0 +1,6 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const thing = /* @__PURE__ */ css("color:hotpink;", "thing", "/*# sourceMappingURL=[sourcemap] */");
+const otherThing = /* @__PURE__ */ css("color:green;", "otherThing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { otherThing, thing };
diff --git a/packages/emotion/tests/fixtures-labels/no-actual-import/input.ts b/packages/emotion/tests/fixtures-labels/no-actual-import/input.ts
new file mode 100644
index 0000000..a467480
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-actual-import/input.ts
@@ -0,0 +1,3 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/no-actual-import.js
+
+import '@emotion/react'
diff --git a/packages/emotion/tests/fixtures-labels/no-actual-import/output.js b/packages/emotion/tests/fixtures-labels/no-actual-import/output.js
new file mode 100644
index 0000000..a35bc4b
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-actual-import/output.js
@@ -0,0 +1 @@
+import "@emotion/react";
diff --git a/packages/emotion/tests/fixtures-labels/no-label-array-pattern/input.ts b/packages/emotion/tests/fixtures-labels/no-label-array-pattern/input.ts
new file mode 100644
index 0000000..292404f
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-label-array-pattern/input.ts
@@ -0,0 +1,11 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/no-label-array-pattern.js
+
+import { css } from '@emotion/react'
+
+const [weirdo] = [
+ css`
+ color: hotpink;
+ `,
+]
+
+export default weirdo
diff --git a/packages/emotion/tests/fixtures-labels/no-label-array-pattern/output.js b/packages/emotion/tests/fixtures-labels/no-label-array-pattern/output.js
new file mode 100644
index 0000000..c9f72cf
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-label-array-pattern/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const [weirdo] = [/* @__PURE__ */ css("color:hotpink;", "", "/*# sourceMappingURL=[sourcemap] */")];
+//#endregion
+export { weirdo as default };
diff --git a/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/input.ts b/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/input.ts
new file mode 100644
index 0000000..13c8662
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/input.ts
@@ -0,0 +1,13 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/no-label-obj-pattern-computed-property.js
+
+import { css } from '@emotion/react'
+
+const computed = 'weirdo'
+
+const { weirdo } = {
+ [computed]: css`
+ color: hotpink;
+ `,
+}
+
+export default weirdo
diff --git a/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/output.js b/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/output.js
new file mode 100644
index 0000000..49c34af
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/no-label-obj-pattern-computed-property/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const { weirdo } = { ["weirdo"]: /* @__PURE__ */ css("color:hotpink;", "", "/*# sourceMappingURL=[sourcemap] */") };
+//#endregion
+export { weirdo as default };
diff --git a/packages/emotion/tests/fixtures-labels/object-dynamic-property/input.ts b/packages/emotion/tests/fixtures-labels/object-dynamic-property/input.ts
new file mode 100644
index 0000000..4b13378
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/object-dynamic-property/input.ts
@@ -0,0 +1,9 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/object-dynamic-property.js
+
+import { css } from '@emotion/react'
+
+export function doThing() {
+ return {
+ [css({ color: 'hotpink' })]: 'coldblue',
+ }
+}
diff --git a/packages/emotion/tests/fixtures-labels/object-dynamic-property/output.js b/packages/emotion/tests/fixtures-labels/object-dynamic-property/output.js
new file mode 100644
index 0000000..55cb6ed
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/object-dynamic-property/output.js
@@ -0,0 +1,7 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+function doThing() {
+ return { [/* @__PURE__ */ css({ color: "hotpink" }, "", "/*# sourceMappingURL=[sourcemap] */")]: "coldblue" };
+}
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/config.json b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/config.json
new file mode 100644
index 0000000..fd3a9b2
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/config.json
@@ -0,0 +1 @@
+{ "labelFormat": "[dirname]-[filename]-[local]" }
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/input.tsx b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/input.tsx
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/input.tsx
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/output.js b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/output.js
new file mode 100644
index 0000000..299f3f8
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname-filename-local/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "--virtual-entry-StyledDiv"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname/config.json b/packages/emotion/tests/fixtures-labels/options-dirname/config.json
new file mode 100644
index 0000000..e603c4d
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname/config.json
@@ -0,0 +1 @@
+{ "labelFormat": "[dirname]" }
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname/input.tsx b/packages/emotion/tests/fixtures-labels/options-dirname/input.tsx
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname/input.tsx
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/options-dirname/output.js b/packages/emotion/tests/fixtures-labels/options-dirname/output.js
new file mode 100644
index 0000000..779847a
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-dirname/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "-"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/options-filename-local/config.json b/packages/emotion/tests/fixtures-labels/options-filename-local/config.json
new file mode 100644
index 0000000..0294810
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename-local/config.json
@@ -0,0 +1 @@
+{ "labelFormat": "[filename]-[local]" }
diff --git a/packages/emotion/tests/fixtures-labels/options-filename-local/input.tsx b/packages/emotion/tests/fixtures-labels/options-filename-local/input.tsx
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename-local/input.tsx
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/options-filename-local/output.js b/packages/emotion/tests/fixtures-labels/options-filename-local/output.js
new file mode 100644
index 0000000..0330cec
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename-local/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "virtual-entry-StyledDiv"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/options-filename/config.json b/packages/emotion/tests/fixtures-labels/options-filename/config.json
new file mode 100644
index 0000000..93ee80a
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename/config.json
@@ -0,0 +1 @@
+{ "labelFormat": "[filename]" }
diff --git a/packages/emotion/tests/fixtures-labels/options-filename/input.tsx b/packages/emotion/tests/fixtures-labels/options-filename/input.tsx
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename/input.tsx
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/options-filename/output.js b/packages/emotion/tests/fixtures-labels/options-filename/output.js
new file mode 100644
index 0000000..16f6b63
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-filename/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "virtual-entry"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/options-local/config.json b/packages/emotion/tests/fixtures-labels/options-local/config.json
new file mode 100644
index 0000000..9d133c3
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-local/config.json
@@ -0,0 +1 @@
+{ "labelFormat": "[local]" }
diff --git a/packages/emotion/tests/fixtures-labels/options-local/input.tsx b/packages/emotion/tests/fixtures-labels/options-local/input.tsx
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-local/input.tsx
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/options-local/output.js b/packages/emotion/tests/fixtures-labels/options-local/output.js
new file mode 100644
index 0000000..2917f19
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/options-local/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "StyledDiv"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/other-imports/input.ts b/packages/emotion/tests/fixtures-labels/other-imports/input.ts
new file mode 100644
index 0000000..81a73bc
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/other-imports/input.ts
@@ -0,0 +1,5 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/other-imports.js
+
+import { nonExistantImport } from '@emotion/react'
+
+nonExistantImport()
diff --git a/packages/emotion/tests/fixtures-labels/other-imports/output.js b/packages/emotion/tests/fixtures-labels/other-imports/output.js
new file mode 100644
index 0000000..fddc701
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/other-imports/output.js
@@ -0,0 +1,4 @@
+import { nonExistantImport } from "@emotion/react";
+//#region virtual:entry.ts
+nonExistantImport();
+//#endregion
diff --git a/packages/emotion/tests/fixtures-labels/remove-block-comments/input.ts b/packages/emotion/tests/fixtures-labels/remove-block-comments/input.ts
new file mode 100644
index 0000000..5356570
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/remove-block-comments/input.ts
@@ -0,0 +1,10 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/remove-block-comments.js
+
+import { css } from '@emotion/react'
+
+export const doThing = css`
+ /* color:green;
+ ddjfwjkng
+ */
+ color: hotpink;
+`
diff --git a/packages/emotion/tests/fixtures-labels/remove-block-comments/output.js b/packages/emotion/tests/fixtures-labels/remove-block-comments/output.js
new file mode 100644
index 0000000..cf38347
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/remove-block-comments/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const doThing = /* @__PURE__ */ css("color:hotpink;", "doThing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/remove-line-comments/input.ts b/packages/emotion/tests/fixtures-labels/remove-line-comments/input.ts
new file mode 100644
index 0000000..71ee998
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/remove-line-comments/input.ts
@@ -0,0 +1,8 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/remove-line-comments.js
+
+import { css } from '@emotion/react'
+
+export const doThing = css`
+ // color: green;
+ color: hotpink;
+`
diff --git a/packages/emotion/tests/fixtures-labels/remove-line-comments/output.js b/packages/emotion/tests/fixtures-labels/remove-line-comments/output.js
new file mode 100644
index 0000000..cf38347
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/remove-line-comments/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+const doThing = /* @__PURE__ */ css("color:hotpink;", "doThing", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { doThing };
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/input.ts b/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/input.ts
new file mode 100644
index 0000000..0d2e352
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/input.ts
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const Dollar$Div = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/output.js b/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/output.js
new file mode 100644
index 0000000..1ce42a8
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-bad.const.name/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.ts
+const Dollar$Div = /* @__PURE__ */ styled("div", {
+ target: "e1347i8e0",
+ label: "Dollar-Div"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { Dollar$Div };
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/input.ts b/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/input.ts
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/input.ts
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/output.js b/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/output.js
new file mode 100644
index 0000000..9059aa9
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-bad.name.---------.----------/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.ts
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "StyledDiv"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/input.ts b/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/input.ts
new file mode 100644
index 0000000..09c191e
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/input.ts
@@ -0,0 +1,5 @@
+import styled from '@emotion/styled'
+
+export const StyledDiv = styled.div`
+ background-color: black;
+`
diff --git a/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/output.js b/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/output.js
new file mode 100644
index 0000000..9059aa9
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/sanitisation-input.styles/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.ts
+const StyledDiv = /* @__PURE__ */ styled("div", {
+ target: "ee6yw5a0",
+ label: "StyledDiv"
+})("background-color:black;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { StyledDiv };
diff --git a/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/input.ts b/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/input.ts
new file mode 100644
index 0000000..862d016
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/input.ts
@@ -0,0 +1,15 @@
+// https://github.com/emotion-js/emotion/blob/main/packages/babel-plugin/__tests__/css-macro/__fixtures__/tagged-template-args-forwarded.js
+
+import { css } from '@emotion/react'
+
+function media(...args) {
+ return css`
+ @media (min-width: 100px) {
+ ${css(...args)};
+ }
+ `
+}
+
+export const test = css`
+ ${media`color: red;`};
+`
diff --git a/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/output.js b/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/output.js
new file mode 100644
index 0000000..4f0eae6
--- /dev/null
+++ b/packages/emotion/tests/fixtures-labels/tagged-template-args-forwarded/output.js
@@ -0,0 +1,8 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.ts
+function media(...args) {
+ return /* @__PURE__ */ css("@media (min-width:100px){", css(...args), ";}", "media", "/*# sourceMappingURL=[sourcemap] */");
+}
+const test = /* @__PURE__ */ css(media`color: red;`, ";", "test", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { test };
diff --git a/packages/emotion/tests/fixtures/comments/input.tsx b/packages/emotion/tests/fixtures/comments/input.tsx
new file mode 100644
index 0000000..cc8315d
--- /dev/null
+++ b/packages/emotion/tests/fixtures/comments/input.tsx
@@ -0,0 +1,13 @@
+import styled from "@emotion/styled";
+
+export default styled.div`
+ color: red;
+ .foo {
+ color: blue;
+ /**
+ multi line comments
+ */
+ }
+ /* /* */
+ width: 10px;
+`;
diff --git a/packages/emotion/tests/fixtures/comments/output.js b/packages/emotion/tests/fixtures/comments/output.js
new file mode 100644
index 0000000..f70a7de
--- /dev/null
+++ b/packages/emotion/tests/fixtures/comments/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+var virtual_entry_default = /* @__PURE__ */ styled("div", {
+ target: "eluin830",
+ label: ""
+})("color:red;.foo{color:blue;}width:10px;", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures/compress/input.tsx b/packages/emotion/tests/fixtures/compress/input.tsx
new file mode 100644
index 0000000..10219cc
--- /dev/null
+++ b/packages/emotion/tests/fixtures/compress/input.tsx
@@ -0,0 +1,24 @@
+import { css } from "@emotion/react";
+import styled from "@emotion/styled";
+
+const unitNormal = "1rem";
+const unitLarge = "2rem";
+
+export const Example = styled.div`
+ margin: ${unitNormal} ${unitLarge};
+`;
+
+export const Animated = styled.div`
+ & code {
+ background-color: linen;
+ }
+ animation: ${({ animation }) => animation} 0.2s infinite ease-in-out alternate;
+`;
+
+export const shadowBorder = ({ width = "1px", color }) => css`
+ box-shadow: inset 0px 0px 0px ${width} ${color};
+`;
+
+export const StyledInput = styled.input`
+ ${shadowBorder({ color: "red", width: "4px" })}
+`;
diff --git a/packages/emotion/tests/fixtures/compress/output.js b/packages/emotion/tests/fixtures/compress/output.js
new file mode 100644
index 0000000..3fcb404
--- /dev/null
+++ b/packages/emotion/tests/fixtures/compress/output.js
@@ -0,0 +1,20 @@
+import { css } from "@emotion/react";
+import styled from "@emotion/styled";
+const Example = /* @__PURE__ */ styled("div", {
+ target: "ejis9i80",
+ label: "Example"
+})("margin:", "1rem", " ", "2rem", ";", "/*# sourceMappingURL=[sourcemap] */");
+const Animated = /* @__PURE__ */ styled("div", {
+ target: "ejis9i81",
+ label: "Animated"
+})("& code{background-color:linen;}animation:", ({ animation }) => animation, " 0.2s infinite ease-in-out alternate;", "/*# sourceMappingURL=[sourcemap] */");
+const shadowBorder = ({ width = "1px", color }) => /* @__PURE__ */ css("box-shadow:inset 0px 0px 0px ", width, " ", color, ";", "shadowBorder", "/*# sourceMappingURL=[sourcemap] */");
+const StyledInput = /* @__PURE__ */ styled("input", {
+ target: "ejis9i82",
+ label: "StyledInput"
+})(shadowBorder({
+ color: "red",
+ width: "4px"
+}), "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { Animated, Example, StyledInput, shadowBorder };
diff --git a/packages/emotion/tests/fixtures/css-default-export/input.tsx b/packages/emotion/tests/fixtures/css-default-export/input.tsx
new file mode 100644
index 0000000..f07c3eb
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-default-export/input.tsx
@@ -0,0 +1,5 @@
+import css from "@emotion/css";
+
+export const styles = css`
+ color: red;
+`;
diff --git a/packages/emotion/tests/fixtures/css-default-export/output.js b/packages/emotion/tests/fixtures/css-default-export/output.js
new file mode 100644
index 0000000..0973846
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-default-export/output.js
@@ -0,0 +1,5 @@
+import css from "@emotion/css";
+//#region virtual:entry.tsx
+const styles = /* @__PURE__ */ css("color:red;", "styles", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { styles };
diff --git a/packages/emotion/tests/fixtures/css-in-callback/input.tsx b/packages/emotion/tests/fixtures/css-in-callback/input.tsx
new file mode 100644
index 0000000..17b6b85
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-in-callback/input.tsx
@@ -0,0 +1,86 @@
+import { css, Global } from "@emotion/react";
+import styled from "@emotion/styled";
+import { PureComponent } from "react";
+import ReactDOM from "react-dom";
+
+const stylesInCallback = (props: any) =>
+ css({
+ color: "red",
+ background: "yellow",
+ width: `${props.scale * 100}px`,
+ });
+
+export const styles = css({
+ color: "red",
+ width: "20px",
+});
+
+export const styles2 = css`
+ color: red;
+ width: 20px;
+`;
+
+const DivContainer = styled.div({
+ background: "red",
+});
+
+export const DivContainer2 = styled.div`
+ background: red;
+`;
+
+export const ContainerWithOptions = styled("div", {
+ shouldForwardProp: (propertyName: string) => !propertyName.startsWith("$"),
+})`
+ color: hotpink;
+`;
+
+export const SpanContainer = styled("span")({
+ background: "yellow",
+});
+
+export const DivContainerExtended = styled(DivContainer)``;
+export const DivContainerExtended2 = styled(DivContainer)({});
+
+const Container = styled("button")`
+ background: red;
+ ${stylesInCallback}
+ ${() =>
+ css({
+ background: "red",
+ })}
+ color: yellow;
+ font-size: 12px;
+`;
+
+export const Container2 = styled.div`
+ background: red;
+`;
+
+export class SimpleComponent extends PureComponent {
+ render() {
+ return (
+
+
+ hello
+
+ );
+ }
+}
+
+ReactDOM.render(, document.querySelector("#app"));
diff --git a/packages/emotion/tests/fixtures/css-in-callback/output.js b/packages/emotion/tests/fixtures/css-in-callback/output.js
new file mode 100644
index 0000000..4036c11
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-in-callback/output.js
@@ -0,0 +1,60 @@
+import { Global, css } from "@emotion/react";
+import styled from "@emotion/styled";
+import { PureComponent } from "react";
+import ReactDOM from "react-dom";
+import { jsx, jsxs } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+const stylesInCallback = (props) => /* @__PURE__ */ css({
+ color: "red",
+ background: "yellow",
+ width: `${props.scale * 100}px`
+}, "label:stylesInCallback", "/*# sourceMappingURL=[sourcemap] */");
+const styles = /* @__PURE__ */ css({
+ color: "red",
+ width: "20px"
+}, "label:styles", "/*# sourceMappingURL=[sourcemap] */");
+const styles2 = /* @__PURE__ */ css("color:red;width:20px;", "styles2", "/*# sourceMappingURL=[sourcemap] */");
+const DivContainer = /* @__PURE__ */ styled("div", {
+ target: "e1i4ntoh0",
+ label: "DivContainer"
+})({ background: "red" }, "/*# sourceMappingURL=[sourcemap] */");
+const DivContainer2 = /* @__PURE__ */ styled("div", {
+ target: "e1i4ntoh1",
+ label: "DivContainer2"
+})("background:red;", "/*# sourceMappingURL=[sourcemap] */");
+const ContainerWithOptions = /* @__PURE__ */ styled("div", {
+ shouldForwardProp: (propertyName) => !propertyName.startsWith("$"),
+ target: "e1i4ntoh2",
+ label: "ContainerWithOptions"
+})("color:hotpink;", "/*# sourceMappingURL=[sourcemap] */");
+const SpanContainer = /* @__PURE__ */ styled("span", {
+ target: "e1i4ntoh3",
+ label: "SpanContainer"
+})({ background: "yellow" }, "/*# sourceMappingURL=[sourcemap] */");
+const DivContainerExtended = /* @__PURE__ */ styled(DivContainer, {
+ target: "e1i4ntoh4",
+ label: "DivContainerExtended"
+})("/*# sourceMappingURL=[sourcemap] */");
+const DivContainerExtended2 = /* @__PURE__ */ styled(DivContainer, {
+ target: "e1i4ntoh5",
+ label: "DivContainerExtended2"
+})({}, "/*# sourceMappingURL=[sourcemap] */");
+const Container = /* @__PURE__ */ styled("button", {
+ target: "e1i4ntoh6",
+ label: "Container"
+})("background:red;", stylesInCallback, " ", () => css({ background: "red" }), " color:yellow;font-size:12px;", "/*# sourceMappingURL=[sourcemap] */");
+const Container2 = /* @__PURE__ */ styled("div", {
+ target: "e1i4ntoh7",
+ label: "Container2"
+})("background:red;", "/*# sourceMappingURL=[sourcemap] */");
+var SimpleComponent = class extends PureComponent {
+ render() {
+ return /* @__PURE__ */ jsxs(Container, {
+ css: /* @__PURE__ */ css("color:hotpink;", "SimpleComponent", "/*# sourceMappingURL=[sourcemap] */"),
+ children: [/* @__PURE__ */ jsx(Global, { styles: [css("html,body{padding:3rem 1rem;margin:0;background:papayawhip;min-height:100%;font-family:Helvetica,Arial,sans-serif;font-size:24px;}"), "/*# sourceMappingURL=[sourcemap] */"] }), /* @__PURE__ */ jsx("span", { children: "hello" })]
+ });
+ }
+};
+ReactDOM.render(/* @__PURE__ */ jsx(SimpleComponent, {}), document.querySelector("#app"));
+//#endregion
+export { Container2, ContainerWithOptions, DivContainer2, DivContainerExtended, DivContainerExtended2, SimpleComponent, SpanContainer, styles, styles2 };
diff --git a/packages/emotion/tests/fixtures/css-with-trailing-comma/input.tsx b/packages/emotion/tests/fixtures/css-with-trailing-comma/input.tsx
new file mode 100644
index 0000000..06843fc
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-with-trailing-comma/input.tsx
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+
+export const contents = css(
+ { position: "absolute" },
+);
diff --git a/packages/emotion/tests/fixtures/css-with-trailing-comma/output.js b/packages/emotion/tests/fixtures/css-with-trailing-comma/output.js
new file mode 100644
index 0000000..a7a39ef
--- /dev/null
+++ b/packages/emotion/tests/fixtures/css-with-trailing-comma/output.js
@@ -0,0 +1,5 @@
+import { css } from "@emotion/react";
+//#region virtual:entry.tsx
+const contents = /* @__PURE__ */ css({ position: "absolute" }, "label:contents", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { contents };
diff --git a/packages/emotion/tests/fixtures/global-styles/input.tsx b/packages/emotion/tests/fixtures/global-styles/input.tsx
new file mode 100644
index 0000000..c8f56a6
--- /dev/null
+++ b/packages/emotion/tests/fixtures/global-styles/input.tsx
@@ -0,0 +1,3 @@
+import { css, Global } from "@emotion/react";
+
+export default () => ;
diff --git a/packages/emotion/tests/fixtures/global-styles/output.js b/packages/emotion/tests/fixtures/global-styles/output.js
new file mode 100644
index 0000000..628f259
--- /dev/null
+++ b/packages/emotion/tests/fixtures/global-styles/output.js
@@ -0,0 +1,6 @@
+import { Global, css } from "@emotion/react";
+import { jsx } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+var virtual_entry_default = () => /* @__PURE__ */ jsx(Global, { styles: [css("body{margin:0;}"), "/*# sourceMappingURL=[sourcemap] */"] });
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures/import-map/global-needs-css/config.json b/packages/emotion/tests/fixtures/import-map/global-needs-css/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global-needs-css/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/global-needs-css/input.tsx b/packages/emotion/tests/fixtures/import-map/global-needs-css/input.tsx
new file mode 100644
index 0000000..a8f4a70
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global-needs-css/input.tsx
@@ -0,0 +1,8 @@
+import * as React from "react";
+import { SomeGlobalFromCore } from "package-two";
+
+const getBgColor = () => ({ backgroundColor: "#fff" });
+
+export default () => (
+
+);
diff --git a/packages/emotion/tests/fixtures/import-map/global-needs-css/output.js b/packages/emotion/tests/fixtures/import-map/global-needs-css/output.js
new file mode 100644
index 0000000..c0e75f8
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global-needs-css/output.js
@@ -0,0 +1,11 @@
+import "react";
+import { SomeGlobalFromCore } from "package-two";
+import { jsx } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+const getBgColor = () => ({ backgroundColor: "#fff" });
+var virtual_entry_default = () => /* @__PURE__ */ jsx(SomeGlobalFromCore, { styles: [{
+ color: "hotpink",
+ ...getBgColor()
+}, "/*# sourceMappingURL=[sourcemap] */"] });
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures/import-map/global/config.json b/packages/emotion/tests/fixtures/import-map/global/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/global/input.tsx b/packages/emotion/tests/fixtures/import-map/global/input.tsx
new file mode 100644
index 0000000..93e282c
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global/input.tsx
@@ -0,0 +1,4 @@
+import * as React from "react";
+import { SomeGlobalFromCore } from "package-two";
+
+export default () => ;
diff --git a/packages/emotion/tests/fixtures/import-map/global/output.js b/packages/emotion/tests/fixtures/import-map/global/output.js
new file mode 100644
index 0000000..16cfa47
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/global/output.js
@@ -0,0 +1,7 @@
+import "react";
+import { SomeGlobalFromCore } from "package-two";
+import { jsx } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+var virtual_entry_default = () => /* @__PURE__ */ jsx(SomeGlobalFromCore, { styles: [{ color: "hotpink" }, "/*# sourceMappingURL=[sourcemap] */"] });
+//#endregion
+export { virtual_entry_default as default };
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/config.json b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/input.tsx b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/input.tsx
new file mode 100644
index 0000000..5ae315e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/input.tsx
@@ -0,0 +1,3 @@
+import { nonDefaultStyled as someAlias } from "package-one";
+
+export let SomeComp = someAlias.div({ color: "hotpink" });
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/output.js b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/output.js
new file mode 100644
index 0000000..312b255
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled-aliased/output.js
@@ -0,0 +1,8 @@
+import { nonDefaultStyled } from "package-one";
+//#region virtual:entry.tsx
+let SomeComp = /* @__PURE__ */ nonDefaultStyled("div", {
+ target: "e1v42pg20",
+ label: "SomeComp"
+})({ color: "hotpink" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { SomeComp };
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled/config.json b/packages/emotion/tests/fixtures/import-map/non-default-styled/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled/input.tsx b/packages/emotion/tests/fixtures/import-map/non-default-styled/input.tsx
new file mode 100644
index 0000000..fc1d9c9
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled/input.tsx
@@ -0,0 +1,3 @@
+import { nonDefaultStyled } from "package-one";
+
+export let SomeComp = nonDefaultStyled.div({ color: "hotpink" });
diff --git a/packages/emotion/tests/fixtures/import-map/non-default-styled/output.js b/packages/emotion/tests/fixtures/import-map/non-default-styled/output.js
new file mode 100644
index 0000000..e7de109
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/non-default-styled/output.js
@@ -0,0 +1,8 @@
+import { nonDefaultStyled } from "package-one";
+//#region virtual:entry.tsx
+let SomeComp = /* @__PURE__ */ nonDefaultStyled("div", {
+ target: "e9npfi30",
+ label: "SomeComp"
+})({ color: "hotpink" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { SomeComp };
diff --git a/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/config.json b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/input.tsx b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/input.tsx
new file mode 100644
index 0000000..5bc57bd
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/input.tsx
@@ -0,0 +1,3 @@
+import { nonDefaultStyled } from "package-four";
+
+export let SomeComp = nonDefaultStyled.div({ color: "hotpink" });
diff --git a/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/output.js b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/output.js
new file mode 100644
index 0000000..eb1cfe5
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/styled-with-base-specified/output.js
@@ -0,0 +1,8 @@
+import { nonDefaultStyled } from "package-four";
+//#region virtual:entry.tsx
+let SomeComp = /* @__PURE__ */ nonDefaultStyled("div", {
+ target: "eivxod40",
+ label: "SomeComp"
+})({ color: "hotpink" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { SomeComp };
diff --git a/packages/emotion/tests/fixtures/import-map/vanilla/config.json b/packages/emotion/tests/fixtures/import-map/vanilla/config.json
new file mode 100644
index 0000000..0ecce9e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/vanilla/config.json
@@ -0,0 +1,20 @@
+{
+ "importMap": {
+ "package-one": {
+ "nonDefaultStyled": { "canonicalImport": ["@emotion/styled", "default"] }
+ },
+ "package-two": {
+ "someCssFromCore": { "canonicalImport": ["@emotion/react", "css"] },
+ "SomeGlobalFromCore": { "canonicalImport": ["@emotion/react", "Global"] }
+ },
+ "package-three": {
+ "something": { "canonicalImport": ["@emotion/css", "css"] }
+ },
+ "package-four": {
+ "nonDefaultStyled": {
+ "canonicalImport": ["@emotion/styled", "default"],
+ "styledBaseImport": ["package-four/base", "something"]
+ }
+ }
+ }
+}
diff --git a/packages/emotion/tests/fixtures/import-map/vanilla/input.tsx b/packages/emotion/tests/fixtures/import-map/vanilla/input.tsx
new file mode 100644
index 0000000..abd2194
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/vanilla/input.tsx
@@ -0,0 +1,3 @@
+import { something } from "package-three";
+
+export const foo = something({ color: "green" });
diff --git a/packages/emotion/tests/fixtures/import-map/vanilla/output.js b/packages/emotion/tests/fixtures/import-map/vanilla/output.js
new file mode 100644
index 0000000..3e4308b
--- /dev/null
+++ b/packages/emotion/tests/fixtures/import-map/vanilla/output.js
@@ -0,0 +1,5 @@
+import { something } from "package-three";
+//#region virtual:entry.tsx
+const foo = /* @__PURE__ */ something({ color: "green" }, "label:foo", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { foo };
diff --git a/packages/emotion/tests/fixtures/issue-258/input.tsx b/packages/emotion/tests/fixtures/issue-258/input.tsx
new file mode 100644
index 0000000..9d6cbd5
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issue-258/input.tsx
@@ -0,0 +1,5 @@
+import styled from "@emotion/styled";
+
+styled.div`
+ background-image: url("//domain.com/image.png");
+`;
diff --git a/packages/emotion/tests/fixtures/issue-258/output.js b/packages/emotion/tests/fixtures/issue-258/output.js
new file mode 100644
index 0000000..46c1e27
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issue-258/output.js
@@ -0,0 +1 @@
+import "@emotion/styled";
diff --git a/packages/emotion/tests/fixtures/issues/180/input.tsx b/packages/emotion/tests/fixtures/issues/180/input.tsx
new file mode 100644
index 0000000..e511466
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/180/input.tsx
@@ -0,0 +1,39 @@
+import { css } from "@emotion/react";
+import styled from "@emotion/styled";
+
+// Example 1
+function myStyled(Component) {
+ return styled(Component)`
+ background-color: red;
+ `;
+}
+
+function myCss(color) {
+ return css`
+ background-color: ${color};
+ `;
+}
+
+const myStyles = myCss("red");
+
+const Div = myStyled("div");
+
+function App() {
+ return (
+ <>
+ one
+ two
+ >
+ );
+}
+
+// Example 2
+const styles = {
+ keyA: css({
+ padding: 0,
+ }),
+ keyB: css({
+ margin: 0,
+ }),
+};
+const App2 = () => hello world
;
diff --git a/packages/emotion/tests/fixtures/issues/180/output.js b/packages/emotion/tests/fixtures/issues/180/output.js
new file mode 100644
index 0000000..77d82f6
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/180/output.js
@@ -0,0 +1,16 @@
+import { css } from "@emotion/react";
+import styled from "@emotion/styled";
+import "react/jsx-runtime";
+//#region virtual:entry.tsx
+function myStyled(Component) {
+ return /* @__PURE__ */ styled(Component, {
+ target: "e16jl22g0",
+ label: "myStyled"
+ })("background-color:red;", "/*# sourceMappingURL=[sourcemap] */");
+}
+function myCss(color) {
+ return /* @__PURE__ */ css("background-color:", color, ";", "myCss", "/*# sourceMappingURL=[sourcemap] */");
+}
+myCss("red");
+myStyled("div");
+//#endregion
diff --git a/packages/emotion/tests/fixtures/issues/201/input.tsx b/packages/emotion/tests/fixtures/issues/201/input.tsx
new file mode 100644
index 0000000..f841c13
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/201/input.tsx
@@ -0,0 +1,17 @@
+import styled from "@emotion/styled";
+
+function makeOptions() {
+ return {
+ shouldForwardProp: (propertyName: string) => !propertyName.startsWith("$"),
+ };
+}
+export const ContainerWithOptions = styled("div", makeOptions())`
+ color: hotpink;
+`;
+
+export const ContainerWithOptions2 = styled(
+ "div",
+ makeOptions(),
+)({
+ color: "hotpink",
+});
diff --git a/packages/emotion/tests/fixtures/issues/201/output.js b/packages/emotion/tests/fixtures/issues/201/output.js
new file mode 100644
index 0000000..99aa3c4
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/201/output.js
@@ -0,0 +1,17 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+function makeOptions() {
+ return { shouldForwardProp: (propertyName) => !propertyName.startsWith("$") };
+}
+const ContainerWithOptions = /* @__PURE__ */ styled("div", {
+ target: "e1mmxd2q0",
+ label: "ContainerWithOptions",
+ ...makeOptions()
+})("color:hotpink;", "/*# sourceMappingURL=[sourcemap] */");
+const ContainerWithOptions2 = /* @__PURE__ */ styled("div", {
+ target: "e1mmxd2q1",
+ label: "ContainerWithOptions2",
+ ...makeOptions()
+})({ color: "hotpink" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { ContainerWithOptions, ContainerWithOptions2 };
diff --git a/packages/emotion/tests/fixtures/issues/39672/input.tsx b/packages/emotion/tests/fixtures/issues/39672/input.tsx
new file mode 100644
index 0000000..9774f83
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/39672/input.tsx
@@ -0,0 +1,9 @@
+import styled from "@emotion/styled";
+
+const SelectedComponent = styled.p`
+ color: red;
+
+ &:after {
+ content: " | ";
+ }
+`;
diff --git a/packages/emotion/tests/fixtures/issues/39672/output.js b/packages/emotion/tests/fixtures/issues/39672/output.js
new file mode 100644
index 0000000..46c1e27
--- /dev/null
+++ b/packages/emotion/tests/fixtures/issues/39672/output.js
@@ -0,0 +1 @@
+import "@emotion/styled";
diff --git a/packages/emotion/tests/fixtures/keyframes/input.tsx b/packages/emotion/tests/fixtures/keyframes/input.tsx
new file mode 100644
index 0000000..9cd1213
--- /dev/null
+++ b/packages/emotion/tests/fixtures/keyframes/input.tsx
@@ -0,0 +1,6 @@
+import { keyframes } from "@emotion/react";
+
+export const fadeIn = keyframes`
+ from { opacity: 0; }
+ to { opacity: 1; }
+`;
diff --git a/packages/emotion/tests/fixtures/keyframes/output.js b/packages/emotion/tests/fixtures/keyframes/output.js
new file mode 100644
index 0000000..7bdab7f
--- /dev/null
+++ b/packages/emotion/tests/fixtures/keyframes/output.js
@@ -0,0 +1,5 @@
+import { keyframes } from "@emotion/react";
+//#region virtual:entry.tsx
+const fadeIn = /* @__PURE__ */ keyframes("from{opacity:0;}to{opacity:1;}", "fadeIn", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { fadeIn };
diff --git a/packages/emotion/tests/fixtures/namespace-css-trailing-comma/input.tsx b/packages/emotion/tests/fixtures/namespace-css-trailing-comma/input.tsx
new file mode 100644
index 0000000..71dddef
--- /dev/null
+++ b/packages/emotion/tests/fixtures/namespace-css-trailing-comma/input.tsx
@@ -0,0 +1,5 @@
+import * as emotionReact from "@emotion/react";
+
+export const styles = emotionReact.css(
+ { color: 'red' },
+);
diff --git a/packages/emotion/tests/fixtures/namespace-css-trailing-comma/output.js b/packages/emotion/tests/fixtures/namespace-css-trailing-comma/output.js
new file mode 100644
index 0000000..5c5a968
--- /dev/null
+++ b/packages/emotion/tests/fixtures/namespace-css-trailing-comma/output.js
@@ -0,0 +1,5 @@
+import * as emotionReact from "@emotion/react";
+//#region virtual:entry.tsx
+const styles = /* @__PURE__ */ emotionReact.css({ color: "red" }, "label:styles", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { styles };
diff --git a/packages/emotion/tests/fixtures/namespace-import/input.tsx b/packages/emotion/tests/fixtures/namespace-import/input.tsx
new file mode 100644
index 0000000..fc941c2
--- /dev/null
+++ b/packages/emotion/tests/fixtures/namespace-import/input.tsx
@@ -0,0 +1,32 @@
+import * as emotionReact from "@emotion/react";
+import { PureComponent } from "react";
+import ReactDOM from "react-dom";
+
+export const stylesInCallback = (props: any) =>
+ emotionReact.css({
+ color: "red",
+ background: "yellow",
+ width: `${props.scale * 100}px`,
+ });
+
+export const styles = emotionReact.css({
+ color: "red",
+ width: "20px",
+});
+
+export const styles2 = emotionReact.css`
+ color: red;
+ width: 20px;
+`;
+
+export class SimpleComponent extends PureComponent {
+ render() {
+ return (
+
+ hello
+
+ );
+ }
+}
+
+ReactDOM.render(, document.querySelector("#app"));
diff --git a/packages/emotion/tests/fixtures/namespace-import/output.js b/packages/emotion/tests/fixtures/namespace-import/output.js
new file mode 100644
index 0000000..d516962
--- /dev/null
+++ b/packages/emotion/tests/fixtures/namespace-import/output.js
@@ -0,0 +1,26 @@
+import * as emotionReact from "@emotion/react";
+import { PureComponent } from "react";
+import ReactDOM from "react-dom";
+import { jsx } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+const stylesInCallback = (props) => /* @__PURE__ */ emotionReact.css({
+ color: "red",
+ background: "yellow",
+ width: `${props.scale * 100}px`
+}, "label:stylesInCallback", "/*# sourceMappingURL=[sourcemap] */");
+const styles = /* @__PURE__ */ emotionReact.css({
+ color: "red",
+ width: "20px"
+}, "label:styles", "/*# sourceMappingURL=[sourcemap] */");
+const styles2 = /* @__PURE__ */ emotionReact.css("color:red;width:20px;", "label:styles2", "/*# sourceMappingURL=[sourcemap] */");
+var SimpleComponent = class extends PureComponent {
+ render() {
+ return /* @__PURE__ */ jsx("div", {
+ className: styles,
+ children: /* @__PURE__ */ jsx("span", { children: "hello" })
+ });
+ }
+};
+ReactDOM.render(/* @__PURE__ */ jsx(SimpleComponent, {}), document.querySelector("#app"));
+//#endregion
+export { SimpleComponent, styles, styles2, stylesInCallback };
diff --git a/packages/emotion/tests/fixtures/next/40385/1/input.tsx b/packages/emotion/tests/fixtures/next/40385/1/input.tsx
new file mode 100644
index 0000000..38b1c66
--- /dev/null
+++ b/packages/emotion/tests/fixtures/next/40385/1/input.tsx
@@ -0,0 +1,26 @@
+import styled from "@emotion/styled";
+
+export default function IndexPage() {
+ return (
+ <>
+ IndexPage
+
+
+ >
+ );
+}
+
+const IconWrapper = styled.div`
+ &[class^="icon-"],
+ [class*=" icon-"] {
+ color: red;
+ }
+
+ &.icon-chat:before {
+ content: "\\e904";
+ }
+
+ &.icon-check:before {
+ content: "\\e905";
+ }
+`;
diff --git a/packages/emotion/tests/fixtures/next/40385/1/output.js b/packages/emotion/tests/fixtures/next/40385/1/output.js
new file mode 100644
index 0000000..353ba1b
--- /dev/null
+++ b/packages/emotion/tests/fixtures/next/40385/1/output.js
@@ -0,0 +1,16 @@
+import styled from "@emotion/styled";
+import { Fragment, jsx, jsxs } from "react/jsx-runtime";
+//#region virtual:entry.tsx
+function IndexPage() {
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
+ /* @__PURE__ */ jsx("h1", { children: "IndexPage" }),
+ /* @__PURE__ */ jsx(IconWrapper, { className: "icon-chat" }),
+ /* @__PURE__ */ jsx(IconWrapper, { className: "icon-check" })
+ ] });
+}
+const IconWrapper = /* @__PURE__ */ styled("div", {
+ target: "eokgv1d0",
+ label: "IconWrapper"
+})("&[class^=\"icon-\"],[class*=\" icon-\"]{color:red;}&.icon-chat:before{content:\"\\e904\";}&.icon-check:before{content:\"\\e905\";}", "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { IndexPage as default };
diff --git a/packages/emotion/tests/fixtures/shadowed/input.tsx b/packages/emotion/tests/fixtures/shadowed/input.tsx
new file mode 100644
index 0000000..8bf793b
--- /dev/null
+++ b/packages/emotion/tests/fixtures/shadowed/input.tsx
@@ -0,0 +1,18 @@
+import styled from "@emotion/styled";
+
+export function foo() {
+ const a = styled.div`
+ color: red;
+ .foo {
+ color: blue;
+ /**
+ multi line comments
+ */
+ }
+ /* /* */
+ width: 10px;
+`;
+ console.log(a);
+
+ var styled;
+}
diff --git a/packages/emotion/tests/fixtures/shadowed/output.js b/packages/emotion/tests/fixtures/shadowed/output.js
new file mode 100644
index 0000000..039c5e3
--- /dev/null
+++ b/packages/emotion/tests/fixtures/shadowed/output.js
@@ -0,0 +1,18 @@
+//#region virtual:entry.tsx
+function foo() {
+ const a = styled.div`
+ color: red;
+ .foo {
+ color: blue;
+ /**
+ multi line comments
+ */
+ }
+ /* /* */
+ width: 10px;
+`;
+ console.log(a);
+ var styled;
+}
+//#endregion
+export { foo };
diff --git a/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/config.json b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/config.json
new file mode 100644
index 0000000..cd8fe2c
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/config.json
@@ -0,0 +1 @@
+{ "autoLabel": "never" }
diff --git a/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/input.tsx b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/input.tsx
new file mode 100644
index 0000000..9d9257f
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/input.tsx
@@ -0,0 +1,9 @@
+import styled from "@emotion/styled";
+
+// Tagged template with empty object, label disabled
+export const TaggedEmpty = styled(Component, {})`
+ color: red;
+`;
+
+// Call expression with empty object, label disabled
+export const CallEmpty = styled(Component, {})({ color: 'red' });
diff --git a/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/output.js b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/output.js
new file mode 100644
index 0000000..3add18c
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-empty-object-no-label/output.js
@@ -0,0 +1,6 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const TaggedEmpty = /* @__PURE__ */ styled(Component, { target: "eeip7ub0" })("color:red;", "/*# sourceMappingURL=[sourcemap] */");
+const CallEmpty = /* @__PURE__ */ styled(Component, { target: "eeip7ub1" })({ color: "red" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { CallEmpty, TaggedEmpty };
diff --git a/packages/emotion/tests/fixtures/styled-call-empty-object/input.tsx b/packages/emotion/tests/fixtures/styled-call-empty-object/input.tsx
new file mode 100644
index 0000000..4547898
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-empty-object/input.tsx
@@ -0,0 +1,9 @@
+import styled from "@emotion/styled";
+
+// Tagged template with empty object
+export const TaggedEmpty = styled(Component, {})`
+ color: red;
+`;
+
+// Call expression with empty object
+export const CallEmpty = styled(Component, {})({ color: 'red' });
diff --git a/packages/emotion/tests/fixtures/styled-call-empty-object/output.js b/packages/emotion/tests/fixtures/styled-call-empty-object/output.js
new file mode 100644
index 0000000..272cc54
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-empty-object/output.js
@@ -0,0 +1,12 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const TaggedEmpty = /* @__PURE__ */ styled(Component, {
+ target: "eh0js120",
+ label: "TaggedEmpty"
+})("color:red;", "/*# sourceMappingURL=[sourcemap] */");
+const CallEmpty = /* @__PURE__ */ styled(Component, {
+ target: "eh0js121",
+ label: "CallEmpty"
+})({ color: "red" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { CallEmpty, TaggedEmpty };
diff --git a/packages/emotion/tests/fixtures/styled-call-trailing-comma/input.tsx b/packages/emotion/tests/fixtures/styled-call-trailing-comma/input.tsx
new file mode 100644
index 0000000..aa42d0e
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-trailing-comma/input.tsx
@@ -0,0 +1,10 @@
+import styled from "@emotion/styled";
+
+export const MyComponent = styled('div')(
+ { color: 'red' },
+);
+
+export const MyComponent2 = styled('div')(
+ { color: 'red' },
+ { target: 'x', },
+);
diff --git a/packages/emotion/tests/fixtures/styled-call-trailing-comma/output.js b/packages/emotion/tests/fixtures/styled-call-trailing-comma/output.js
new file mode 100644
index 0000000..edcb6ea
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-call-trailing-comma/output.js
@@ -0,0 +1,12 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const MyComponent = /* @__PURE__ */ styled("div", {
+ target: "e1p2oxds0",
+ label: "MyComponent"
+})({ color: "red" }, "/*# sourceMappingURL=[sourcemap] */");
+const MyComponent2 = /* @__PURE__ */ styled("div", {
+ target: "e1p2oxds1",
+ label: "MyComponent2"
+})({ color: "red" }, { target: "x" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { MyComponent, MyComponent2 };
diff --git a/packages/emotion/tests/fixtures/styled-member-trailing-comma/input.tsx b/packages/emotion/tests/fixtures/styled-member-trailing-comma/input.tsx
new file mode 100644
index 0000000..1daa2ad
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-member-trailing-comma/input.tsx
@@ -0,0 +1,5 @@
+import styled from "@emotion/styled";
+
+export const MyComponent = styled.div(
+ { color: 'red' },
+);
diff --git a/packages/emotion/tests/fixtures/styled-member-trailing-comma/output.js b/packages/emotion/tests/fixtures/styled-member-trailing-comma/output.js
new file mode 100644
index 0000000..ab6d12a
--- /dev/null
+++ b/packages/emotion/tests/fixtures/styled-member-trailing-comma/output.js
@@ -0,0 +1,8 @@
+import styled from "@emotion/styled";
+//#region virtual:entry.tsx
+const MyComponent = /* @__PURE__ */ styled("div", {
+ target: "e3bpr110",
+ label: "MyComponent"
+})({ color: "red" }, "/*# sourceMappingURL=[sourcemap] */");
+//#endregion
+export { MyComponent };
diff --git a/packages/emotion/tests/transform.test.ts b/packages/emotion/tests/transform.test.ts
new file mode 100644
index 0000000..fe31127
--- /dev/null
+++ b/packages/emotion/tests/transform.test.ts
@@ -0,0 +1,107 @@
+import { describe, it, expect } from 'vitest'
+import { rolldown } from 'rolldown'
+import emotionPlugin from '../src/index.ts'
+import { globSync } from 'tinyglobby'
+import { readFileSync, existsSync } from 'node:fs'
+import { dirname, join } from 'node:path'
+import { fileURLToPath } from 'node:url'
+import type { EmotionPluginOptions } from '../src/types.ts'
+
+const fixturesDir = join(dirname(fileURLToPath(import.meta.url)), 'fixtures')
+const fixturesLabelsDir = join(dirname(fileURLToPath(import.meta.url)), 'fixtures-labels')
+
+// Get all fixture directories (input.tsx or input.js files)
+const fixturePaths = globSync(['*/input.tsx', '*/input.js', '**/*/input.tsx', '**/*/input.js'], {
+ cwd: fixturesDir,
+})
+
+describe('fixtures', () => {
+ for (const inputPath of fixturePaths) {
+ const fixtureName = dirname(inputPath)
+ const fullInputPath = join(fixturesDir, inputPath)
+ const input = readFileSync(fullInputPath, 'utf-8')
+
+ const configPath = join(fixturesDir, fixtureName, 'config.json')
+ const config: EmotionPluginOptions = existsSync(configPath)
+ ? JSON.parse(readFileSync(configPath, 'utf-8'))
+ : {}
+
+ it(fixtureName, async () => {
+ const result = await transform(input, config, fullInputPath)
+ await expect(result).toMatchFileSnapshot(join(fixturesDir, fixtureName, 'output.js'))
+ })
+ }
+})
+
+// Labels tests - test label extraction from various AST contexts
+const labelPaths = globSync(['*/input.ts', '*/input.tsx'], {
+ cwd: fixturesLabelsDir,
+})
+
+describe('fixtures-labels', () => {
+ for (const inputPath of labelPaths) {
+ const fixtureName = dirname(inputPath)
+ const fullInputPath = join(fixturesLabelsDir, inputPath)
+ const input = readFileSync(fullInputPath, 'utf-8')
+
+ const configPath = join(fixturesLabelsDir, fixtureName, 'config.json')
+ const config: EmotionPluginOptions = existsSync(configPath)
+ ? JSON.parse(readFileSync(configPath, 'utf-8'))
+ : {}
+
+ it(fixtureName, async () => {
+ const result = await transform(input, config, fullInputPath)
+ await expect(result).toMatchFileSnapshot(join(fixturesLabelsDir, fixtureName, 'output.js'))
+ })
+ }
+})
+
+async function transform(
+ code: string,
+ options: EmotionPluginOptions,
+ filename = 'virtual:entry.tsx',
+): Promise {
+ // Use extension from original filename for virtual entry to ensure correct parsing
+ const ext = filename.match(/\.[jt]sx?$/)?.[0] ?? '.ts'
+ const virtualEntry = `virtual:entry${ext}`
+
+ const build = await rolldown({
+ input: virtualEntry,
+ plugins: [
+ {
+ name: 'virtual',
+ resolveId(id) {
+ if (id === virtualEntry) return id
+ // Mark all other imports as external
+ return { id, external: true }
+ },
+ load(id) {
+ if (id === virtualEntry) return code
+ },
+ },
+ emotionPlugin({
+ sourceMap: true,
+ autoLabel: 'always',
+ ...options,
+ }),
+ ],
+ })
+
+ const { output } = await build.generate({ format: 'esm' })
+ return normalizeSourceMap(stripRolldownRuntime(output[0].code))
+}
+
+function stripRolldownRuntime(code: string): string {
+ // Replace rolldown runtime regions with a stable comment
+ return code.replace(
+ /\/\/#region \\0rolldown\/runtime\.js[\s\S]*?\/\/#endregion\n*/g,
+ '// [rolldown runtime elided]\n',
+ )
+}
+
+function normalizeSourceMap(code: string): string {
+ return code.replace(
+ /\/\*# sourceMappingURL=data:application\/json;charset=utf-8;base64,[^*]+ \*\//g,
+ '/*# sourceMappingURL=[sourcemap] */',
+ )
+}
diff --git a/packages/emotion/tsdown.config.ts b/packages/emotion/tsdown.config.ts
new file mode 100644
index 0000000..a3a2720
--- /dev/null
+++ b/packages/emotion/tsdown.config.ts
@@ -0,0 +1,9 @@
+import { defineConfig } from 'tsdown'
+
+export default defineConfig({
+ entry: './src/index.ts',
+ dts: {
+ tsconfig: '../../tsconfig.common.json',
+ tsgo: true,
+ },
+})
diff --git a/packages/emotion/vitest.config.ts b/packages/emotion/vitest.config.ts
new file mode 100644
index 0000000..36f4696
--- /dev/null
+++ b/packages/emotion/vitest.config.ts
@@ -0,0 +1,7 @@
+import { defineConfig } from 'vitest/config'
+
+export default defineConfig({
+ test: {
+ name: 'emotion',
+ },
+})
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index ffa6f11..160eddb 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -30,7 +30,84 @@ importers:
version: 0.21.2(@typescript/native-preview@7.0.0-dev.20260314.1)(publint@0.3.17)
vitest:
specifier: ^4.1.0
- version: 4.1.0(@types/node@22.19.15)(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3))
+ version: 4.1.0(@types/node@24.12.0)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))
+
+ examples:
+ devDependencies:
+ playwright-chromium:
+ specifier: ^1.58.2
+ version: 1.58.2
+ vite:
+ specifier: ^8.0.0
+ version: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+
+ examples/emotion:
+ dependencies:
+ '@emotion/react':
+ specifier: ^11.14.0
+ version: 11.14.0(@types/react@19.2.14)(react@19.2.4)
+ '@emotion/styled':
+ specifier: ^11.14.1
+ version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
+ react:
+ specifier: ^19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.4(react@19.2.4)
+ devDependencies:
+ '@rolldown/plugin-emotion':
+ specifier: workspace:*
+ version: link:../../packages/emotion
+ '@types/react':
+ specifier: ^19.2.14
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.14)
+ '@vitejs/plugin-react':
+ specifier: ^6.0.1
+ version: 6.0.1(@rolldown/plugin-babel@0.2.1(@babel/core@8.0.0-rc.2)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@8.0.0-rc.2))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3)))(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))
+ vite:
+ specifier: 8.0.0
+ version: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+
+ internal-packages/benchmark-utils:
+ devDependencies:
+ '@oxc-node/core':
+ specifier: ^0.0.35
+ version: 0.0.35
+
+ internal-packages/oxc-unshadowed-visitor:
+ dependencies:
+ rolldown:
+ specifier: ^1.0.0-rc.9
+ version: 1.0.0-rc.9
+ devDependencies:
+ oxc-walker:
+ specifier: ^0.7.0
+ version: 0.7.0(oxc-parser@0.119.0)
+
+ internal-packages/swc-output-gen:
+ dependencies:
+ '@oxc-node/cli':
+ specifier: ^0.0.35
+ version: 0.0.35
+ '@rollup/plugin-swc':
+ specifier: ^0.4.0
+ version: 0.4.0(@swc/core@1.15.18)
+ '@swc/core':
+ specifier: ^1.15.18
+ version: 1.15.18
+ '@swc/plugin-emotion':
+ specifier: ^14.7.0
+ version: 14.7.0
+ rolldown:
+ specifier: ^1.0.0-rc.9
+ version: 1.0.0-rc.9
+ tinyglobby:
+ specifier: ^0.2.15
+ version: 0.2.15
packages/babel:
dependencies:
@@ -63,6 +140,86 @@ importers:
specifier: ^8.0.0
version: 8.0.0(@types/node@22.19.15)(esbuild@0.27.3)
+ packages/emotion:
+ dependencies:
+ '@emotion/hash':
+ specifier: ^0.9.2
+ version: 0.9.2
+ '@jridgewell/gen-mapping':
+ specifier: ^0.3.13
+ version: 0.3.13
+ rolldown-string:
+ specifier: ^0.3.0
+ version: 0.3.0(rolldown@1.0.0-rc.9)
+ devDependencies:
+ '@rolldown/oxc-unshadowed-visitor':
+ specifier: workspace:*
+ version: link:../../internal-packages/oxc-unshadowed-visitor
+ rolldown:
+ specifier: ^1.0.0-rc.9
+ version: 1.0.0-rc.9
+ tinyglobby:
+ specifier: ^0.2.15
+ version: 0.2.15
+ vite:
+ specifier: ^8.0.0
+ version: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+
+ packages/emotion/benchmark:
+ dependencies:
+ '@emotion/react':
+ specifier: ^11.14.0
+ version: 11.14.0(@types/react@19.2.14)(react@19.2.4)
+ '@emotion/styled':
+ specifier: ^11.14.1
+ version: 11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)
+ react:
+ specifier: ^19.2.4
+ version: 19.2.4
+ react-dom:
+ specifier: ^19.2.4
+ version: 19.2.4(react@19.2.4)
+ devDependencies:
+ '@babel/core':
+ specifier: ^7.29.0
+ version: 7.29.0
+ '@emotion/babel-plugin':
+ specifier: ^11.13.5
+ version: 11.13.5
+ '@oxc-node/cli':
+ specifier: ^0.0.35
+ version: 0.0.35
+ '@rolldown/benchmark-utils':
+ specifier: workspace:*
+ version: link:../../../internal-packages/benchmark-utils
+ '@rolldown/plugin-babel':
+ specifier: file:../../babel
+ version: file:packages/babel(@babel/core@7.29.0)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@7.29.0))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))
+ '@rolldown/plugin-emotion':
+ specifier: workspace:*
+ version: link:..
+ '@rollup/plugin-swc':
+ specifier: ^0.4.0
+ version: 0.4.0(@swc/core@1.15.18)
+ '@swc/core':
+ specifier: ^1.15.18
+ version: 1.15.18
+ '@swc/plugin-emotion':
+ specifier: ^14.7.0
+ version: 14.7.0
+ '@types/node':
+ specifier: ^24.10.13
+ version: 24.12.0
+ '@types/react':
+ specifier: ^19.2.14
+ version: 19.2.14
+ '@types/react-dom':
+ specifier: ^19.2.3
+ version: 19.2.3(@types/react@19.2.14)
+ rolldown:
+ specifier: ^1.0.0-rc.9
+ version: 1.0.0-rc.9
+
scripts:
devDependencies:
'@vitejs/release-scripts':
@@ -77,14 +234,26 @@ importers:
packages:
+ '@babel/code-frame@7.29.0':
+ resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/code-frame@8.0.0-rc.2':
resolution: {integrity: sha512-zbPFBDbQdChkGN02WRc/BcOvZLDTctFJZVeWkciVr82T5V0GVBXztq4/Wi4Ca+ZKx7U+Kdt5b862cpFJ4Cjf1A==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/compat-data@7.29.0':
+ resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/compat-data@8.0.0-rc.2':
resolution: {integrity: sha512-zDrQeMrDVCkisxxjZmP+xeAyGfZCVOwP+7VECgOvMXttb+1pTUMpeEYI0LaozIzeES/Uvu7OqhHLb3oN1qo6Wg==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/core@7.29.0':
+ resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/core@8.0.0-rc.2':
resolution: {integrity: sha512-mlBJdKJJEZNGDE+w+P6B5w+FTMkht1liPkxtB4wk39EpGH01Am5tg1htaNlOU5rO9Ge3psMjAFycpc3ru5uaQw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -94,6 +263,10 @@ packages:
'@babel/preset-typescript':
optional: true
+ '@babel/generator@7.29.1':
+ resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/generator@8.0.0-rc.2':
resolution: {integrity: sha512-oCQ1IKPwkzCeJzAPb7Fv8rQ9k5+1sG8mf2uoHiMInPYvkRfrDJxbTIbH51U+jstlkghus0vAi3EBvkfvEsYNLQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -102,6 +275,10 @@ packages:
resolution: {integrity: sha512-KbQiXXTEGDdQo6SHaVafQowpPT+Kksqnq20zRY23pZgd63buryBA0dciIHs/04a86SxIsl1Ggvn82cWgdeq5nQ==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-compilation-targets@7.28.6':
+ resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-compilation-targets@8.0.0-rc.2':
resolution: {integrity: sha512-oMIhKru9gl3mj0eKDyKW6wBDAvyWoZd28d6V/m4JTeeiFsJLfOYnqu+s+cnK4jSo87cg/oj4hsATgkmZ3AzsDQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -112,6 +289,10 @@ packages:
peerDependencies:
'@babel/core': ^8.0.0-rc.2
+ '@babel/helper-globals@7.28.0':
+ resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-globals@8.0.0-rc.2':
resolution: {integrity: sha512-Q1AIOaW4EOxkI/8wYJKyLI59gfqTK3imFUfIqxuve0Q3GlOSrOTVmvHU6Gb3Y5GxtoS1hIzhO47k5GkfyGTQEQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -120,10 +301,20 @@ packages:
resolution: {integrity: sha512-LbzA3y4YgiVC8TlnOucMWLdsag1KPYijUmm9hmaHcU7srGNYfH9Qe6Y5I3FlJ/PjmWEvIKX2MX+NFMuCMrpkHQ==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-module-imports@7.28.6':
+ resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-module-imports@8.0.0-rc.2':
resolution: {integrity: sha512-9xSWdt/w6bA9sEcdxIDoNvnKZSGcUqeLQSWu0bh69xRV2Skj5vXSYXbFdYE4M8g/stEeNQ/9zSAs2OlSF3ZOOw==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-module-transforms@7.28.6':
+ resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==}
+ engines: {node: '>=6.9.0'}
+ peerDependencies:
+ '@babel/core': ^7.0.0
+
'@babel/helper-optimise-call-expression@8.0.0-rc.2':
resolution: {integrity: sha512-y1H1DXTPIR0yi/T9ervuo4f0zD1zCEn7FXnFBFU8DtCr3SMA0oS50jgt1PMCX5hg44RxvgG+dhAwHCP9mneZqg==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -144,22 +335,43 @@ packages:
resolution: {integrity: sha512-NO8HTg+G9V5R7HGkVX5jwanxZcjcj0FZ6TwUFZJmGVOxpWBty+zStju0PTkhah0A/npmRGwJPy8+RCCUtX8Qug==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-string-parser@7.27.1':
+ resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-string-parser@8.0.0-rc.2':
resolution: {integrity: sha512-noLx87RwlBEMrTzncWd/FvTxoJ9+ycHNg0n8yyYydIoDsLZuxknKgWRJUqcrVkNrJ74uGyhWQzQaS3q8xfGAhQ==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-validator-identifier@7.28.5':
+ resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-validator-identifier@8.0.0-rc.2':
resolution: {integrity: sha512-xExUBkuXWJjVuIbO7z6q7/BA9bgfJDEhVL0ggrggLMbg0IzCUWGT1hZGE8qUH7Il7/RD/a6cZ3AAFrrlp1LF/A==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helper-validator-option@7.27.1':
+ resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helper-validator-option@8.0.0-rc.2':
resolution: {integrity: sha512-EtxQopsocKue0ZdjnX5INoDiRN+RCBb1TDh3d0N8bM6aX0lyUhQfRNRQaKB+vCx+YvGjXWRf3JD6/YvTsf2qgQ==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/helpers@7.28.6':
+ resolution: {integrity: sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==}
+ engines: {node: '>=6.9.0'}
+
'@babel/helpers@8.0.0-rc.2':
resolution: {integrity: sha512-Cc2IpMRiu8PDBUxtQ6oSkML0etJ27kZGnf3XE+qqAJJFGtVl549kyfvDWLywCAFhq16kHUe2WMZMdFUtPz6kWw==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/parser@7.29.0':
+ resolution: {integrity: sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==}
+ engines: {node: '>=6.0.0'}
+ hasBin: true
+
'@babel/parser@8.0.0-rc.2':
resolution: {integrity: sha512-29AhEtcq4x8Dp3T72qvUMZHx0OMXCj4Jy/TEReQa+KWLln524Cj1fWb3QFi0l/xSpptQBR6y9RNEXuxpFvwiUQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -183,18 +395,34 @@ packages:
peerDependencies:
'@babel/core': ^8.0.0-rc.2
+ '@babel/runtime@7.28.6':
+ resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/runtime@8.0.0-rc.2':
resolution: {integrity: sha512-wI+xpmXzz8HwQflyWnjgWqBNSwSCloGq+f5/8MpWQ9XE+w8PMPl/g8fjh6KHZa4ub5/WAMZKaNTThvRWJnzVYA==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/template@7.28.6':
+ resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==}
+ engines: {node: '>=6.9.0'}
+
'@babel/template@8.0.0-rc.2':
resolution: {integrity: sha512-INp+KufeQpvU+V+gxR7xoiVzU6sRRQo8oOsCU/sTe0wtJ/Adrfgyet0i19qvXXSeuyiZ9+PV8IF/eEPzyJ527g==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/traverse@7.29.0':
+ resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==}
+ engines: {node: '>=6.9.0'}
+
'@babel/traverse@8.0.0-rc.2':
resolution: {integrity: sha512-H9ZChE8gRy4fSloEQaT17ijcFNoayS9JIyE0IUWkjYgldU+Czkg2h5XtuJmfIk6cbuHfDK/FFJox+g/TlmXB7g==}
engines: {node: ^20.19.0 || >=22.12.0}
+ '@babel/types@7.29.0':
+ resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==}
+ engines: {node: '>=6.9.0'}
+
'@babel/types@8.0.0-rc.2':
resolution: {integrity: sha512-91gAaWRznDwSX4E2tZ1YjBuIfnQVOFDCQ2r0Toby0gu4XEbyF623kXLMA8d4ZbCu+fINcrudkmEcwSUHgDDkNw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -220,6 +448,60 @@ packages:
'@emnapi/wasi-threads@1.1.0':
resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==}
+ '@emotion/babel-plugin@11.13.5':
+ resolution: {integrity: sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==}
+
+ '@emotion/cache@11.14.0':
+ resolution: {integrity: sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==}
+
+ '@emotion/hash@0.9.2':
+ resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==}
+
+ '@emotion/is-prop-valid@1.4.0':
+ resolution: {integrity: sha512-QgD4fyscGcbbKwJmqNvUMSE02OsHUa+lAWKdEUIJKgqe5IwRSKd7+KhibEWdaKwgjLj0DRSHA9biAIqGBk05lw==}
+
+ '@emotion/memoize@0.9.0':
+ resolution: {integrity: sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==}
+
+ '@emotion/react@11.14.0':
+ resolution: {integrity: sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==}
+ peerDependencies:
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/serialize@1.3.3':
+ resolution: {integrity: sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==}
+
+ '@emotion/sheet@1.4.0':
+ resolution: {integrity: sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==}
+
+ '@emotion/styled@11.14.1':
+ resolution: {integrity: sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==}
+ peerDependencies:
+ '@emotion/react': ^11.0.0-rc.0
+ '@types/react': '*'
+ react: '>=16.8.0'
+ peerDependenciesMeta:
+ '@types/react':
+ optional: true
+
+ '@emotion/unitless@0.10.0':
+ resolution: {integrity: sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0':
+ resolution: {integrity: sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==}
+ peerDependencies:
+ react: '>=16.8.0'
+
+ '@emotion/utils@1.4.2':
+ resolution: {integrity: sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==}
+
+ '@emotion/weak-memoize@0.4.0':
+ resolution: {integrity: sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==}
+
'@esbuild/aix-ppc64@0.27.3':
resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==}
engines: {node: '>=18'}
@@ -395,6 +677,231 @@ packages:
'@napi-rs/wasm-runtime@1.1.1':
resolution: {integrity: sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A==}
+ '@oxc-node/cli@0.0.35':
+ resolution: {integrity: sha512-FTsYtymv6E4tyV2kxQEFLjsi6ZLmtsBpirFnbv5l7JGmQj65TCGM/WJlkZW+mPAM/9QN+ZY6cIOpnTTl8Qc7uA==}
+ hasBin: true
+
+ '@oxc-node/core-android-arm-eabi@0.0.35':
+ resolution: {integrity: sha512-Vgw/DtArB1fZJ7LX4FX7YDpRvWzwv80lFNngTcamS+9Kbd83HpZb6Tg38t6f7Ubyc/+cL0TTMo55Kg8gwnQGHQ==}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-node/core-android-arm64@0.0.35':
+ resolution: {integrity: sha512-Z/2jKqkTybSDnx2lBb44K0TLD2eUgLMi0te0pp5p5GVnsOZ8A+qSnhZpsPAR8GAbGERdMNOWrDYqj0/VYQt7sQ==}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-node/core-darwin-arm64@0.0.35':
+ resolution: {integrity: sha512-aeEG/a1zj8pA6GC0P7NypzdDY0c6AbZOdbxaGl9UQlwGgHmw6sOtq5PJO+7rCvzxUKPxBH9VZOVg0laFcncIFw==}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-node/core-darwin-x64@0.0.35':
+ resolution: {integrity: sha512-MtxGaUR2LBcUmqINyxzSYdx5om9KlFjyvN8cx/NizH6U5nYs7Wh/XAIoGpcQmkK2snT1FsgJeGR9L01Q1oqmng==}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-node/core-freebsd-x64@0.0.35':
+ resolution: {integrity: sha512-xsZNqMeavNxi/WTxaQMZj6walhj7skCu36yff5q0RjsV7Dzp3RQ/SYK1t3ydw3cwPz2oZCx0AukAYJAj4i9vdw==}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-node/core-linux-arm-gnueabihf@0.0.35':
+ resolution: {integrity: sha512-F+d948mEzQMvcv0BQO3NN4DP0jsJwvvD5VGCFcR2mFa/z6L7UuRkS8yOKnP7tUfZjri7BwxXn37Szj0ZY7pEPA==}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-node/core-linux-arm64-gnu@0.0.35':
+ resolution: {integrity: sha512-wKbAstp6Ztq5UVBf/csnMTPMef+wGsrNykJCAtJuO/l88Okm4jn6wnhudeD3hf/426Vw93txBS8veqN2JSb6fg==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-node/core-linux-arm64-musl@0.0.35':
+ resolution: {integrity: sha512-IdLaYnFrDGRICQ86AoEQEv5Rfo//knhg4g9ABy7QE3C231C3YpbgwtY7YH7Qv+xHDuUHnTNo8Lo/iraSIY3tQA==}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-node/core-linux-ppc64-gnu@0.0.35':
+ resolution: {integrity: sha512-yxfWpG2as+al6G9epDvFk8AX1UWy76WlwCP3pUGtpEUGuoAO63JAHUMDSXv1sSd1YatJmRJ75ptexU6c/xMdXg==}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-node/core-linux-s390x-gnu@0.0.35':
+ resolution: {integrity: sha512-nH3mnP6ger1i4LaroWhvtk3coquNYBJD9eqG3OEuJEFGo1Ao80irFcFoktQCLLq47uomYuNQxNJw5covYNHvLw==}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-node/core-linux-x64-gnu@0.0.35':
+ resolution: {integrity: sha512-2VKErkkTxLViK/8xbdRoQ9+sid8ZGRROLkcmMtrggjQLU69EhL0wioUVztnDVjHfOPAN17lEAN7tUgxz+PAxCg==}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-node/core-linux-x64-musl@0.0.35':
+ resolution: {integrity: sha512-QDDZYWMbwB/1uyn0BPMYeqT6miWQBljzLCYESmsVcaHOps204yKHI1Ezp79n2BiYEghhu9RPWrOd4wZ7+Gqa7Q==}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-node/core-openharmony-arm64@0.0.35':
+ resolution: {integrity: sha512-ihb0W8mc0iM9SpfFwj9xY/1gVAPv2y7fGuW2w4jWOICCY2enJ8GnY2N9eYloPkHd2/2+S87M63H998psVZQquQ==}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-node/core-wasm32-wasi@0.0.35':
+ resolution: {integrity: sha512-GoT1X1Rw3MXbvU25rsqT6gLhl9AKBdLe1ss6pVHxzps0Va6qrSD/2H4alGglUX+qccKcw0kCgJbPKJphM/0CrQ==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-node/core-win32-arm64-msvc@0.0.35':
+ resolution: {integrity: sha512-ObSjUyRd5md+hKg4j8ufhjaeXHGm4f+9cz1y20mOHr/HOkBIY6CNoPM7x5JEzZNerVZ9Ye62G6t6HNQZttBjsg==}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-node/core-win32-ia32-msvc@0.0.35':
+ resolution: {integrity: sha512-ZE7/di30tfhh/2ItgcZim4aPLw1ve+TQrp6oJSqMRyYjq0k1AwFrxIqICbaAG9sk79ap9Sy1icFMfFgSkhnABQ==}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxc-node/core-win32-x64-msvc@0.0.35':
+ resolution: {integrity: sha512-9OyyjY/ECi1icwq32baG0Uct7RuAHbVxzGDffJzNhRtBABpQiIQauoaVuYiSlNecqnA8qFYxh2wxbKaVlsR1YA==}
+ cpu: [x64]
+ os: [win32]
+
+ '@oxc-node/core@0.0.35':
+ resolution: {integrity: sha512-PV46QRDI2wCDdaPzppEh4UfzFmmpSt+1dX32ooq8RWb0BuWX24+LKYicAmSrsk1ls8JRSkAqiWrjrYFHIGozGg==}
+
+ '@oxc-parser/binding-android-arm-eabi@0.119.0':
+ resolution: {integrity: sha512-e0ii/Tqwk5pAHZRY+ZyXOdKHNRNmE+dvTGQZ7xQ5XPH2Am59aktD30QvfcfwItGhNTLCj/5TYGH5RHvmvqaILQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [android]
+
+ '@oxc-parser/binding-android-arm64@0.119.0':
+ resolution: {integrity: sha512-ha0xQpiStuoBv7HGazNKQWa6IRxri2+PpeojdAyBGnHGzfioA1GcStNGEGOyXvF+OxDfWvPuw5QiRYRUMtmgbQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [android]
+
+ '@oxc-parser/binding-darwin-arm64@0.119.0':
+ resolution: {integrity: sha512-h/AIi5jfQz9WQUJJkkkHeXNYMhPtR72qnYZt0ZpM/LvlH/wpI5QkCPi7MWjjyY+m0JDorIXJyfOfccn8SbNSxQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@oxc-parser/binding-darwin-x64@0.119.0':
+ resolution: {integrity: sha512-15RwS/AawrgognvWsonI2eLKI5BqO0FzrpYXnzROysSR0x5RYsCc3UMFBwB1ph0UFFQzJy3ZbHHxfxp8RGr5Xg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [darwin]
+
+ '@oxc-parser/binding-freebsd-x64@0.119.0':
+ resolution: {integrity: sha512-iKaayTIDqEj0yyNPL+0t/spNAxMv7O32uY4eu/ir8BvFNgavoRmN8uqxRj8sxQDle89N/1Iw0dgRjS3tiWrqlA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [freebsd]
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.119.0':
+ resolution: {integrity: sha512-PDoOaOx8YWoxy19WNeMs6kOE0uFSb5EtA64Ye0wSp6sQpe+l8Gd+yjX2L+yNwd5MpDOvOy8KToa2bqCV4pf6iQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.119.0':
+ resolution: {integrity: sha512-AVxZ5Eo5squsUhpjnkCYuH20t5FCGV3HAP9UOKLxJQkmZW3kJvBGbfpH75ABxRrE2kGqmJW5FmS980u8v9Cepw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm]
+ os: [linux]
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.119.0':
+ resolution: {integrity: sha512-9vfdyT9gczSeSwsEkBHVjigI8SWo3iB9zxEzL+YMBUrN0ftCUkKQr27DaDZK4/cQ80t6KRB+g9sUmT2T2AGnOQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-arm64-musl@0.119.0':
+ resolution: {integrity: sha512-7BOq/tjSrtnp/ihw615uGcxMY3iya2qvVtwm15h2NvBZ6Jje+PC1GSUBOLfqGKJbUr9riSVV//a4iNhHI48Qdw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-linux-ppc64-gnu@0.119.0':
+ resolution: {integrity: sha512-PQIrLJwoAaNyNSWBF+2SSgv44Jp+xpKVUA+8+PuoMhyBQ6lFSbQdaxewdn11i3heTFMYd2xF339HWax4S6MPVA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ppc64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.119.0':
+ resolution: {integrity: sha512-spNh4YhT9K+Ya5hr6NmI1MazKSKORD8u5/06hFbzTslLnmmxiGaLqJXhNKIYUH39ne/JD5rkoRkUcOB2/LpC3A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-riscv64-musl@0.119.0':
+ resolution: {integrity: sha512-hFoCTRxSJAcrNBYVlgNDDQq6LyJLYyhnJDlPtK/mWrPYS3x5/fUR9jc6wo5VyxKIL/0dDJBBWp19v81q9heU/A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [riscv64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.119.0':
+ resolution: {integrity: sha512-bl7jHJZq3W5tYEvKG3yWZTUKTNb0/BtyYSnfMIrQ7t8hajCH4i1g0q+14s0KmQQl1UHxIX/Gx/Ps6e92qJQJmQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [s390x]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-gnu@0.119.0':
+ resolution: {integrity: sha512-m+DE7NhJIEGp4efSJnNfRf3swT25rbZ1FTIihV+pOLTI+k5yNguxvqT338mNu61OVSx0BfpV8QlO2nz43GR/Zg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@oxc-parser/binding-linux-x64-musl@0.119.0':
+ resolution: {integrity: sha512-pHhnXZHUfd5pYzFLQfvx1DH2HY+L8DPZeh6SsQrsmoaODm1+j8VPeWLwGSrXQSz5f1kfT/mnzm1iNLVOGIeuaw==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@oxc-parser/binding-openharmony-arm64@0.119.0':
+ resolution: {integrity: sha512-8Fthv9nOec0hQLX16yjYyYIU+u8ZFuQojdQ3vNgXN+PcqI/bDohGgCATrxO69gLf0IzkyOmKmurXOQCYK8BYpQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [openharmony]
+
+ '@oxc-parser/binding-wasm32-wasi@0.119.0':
+ resolution: {integrity: sha512-KpOU6fLqevFDP6ndkgE4BPoceELM4bOsEsAXjpe+FKYuUyEzHssYPBmxouGpXDQeAeWTBIjosw5yElLMRPuccw==}
+ engines: {node: '>=14.0.0'}
+ cpu: [wasm32]
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.119.0':
+ resolution: {integrity: sha512-omtTgAKIl6GQ40nG+wAWN8xMJLNtfmTdd0+wMIcrw1shX9y5TntAVIuiay3Du0wvUK9sgMpL07HYNphgHeZS0A==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [arm64]
+ os: [win32]
+
+ '@oxc-parser/binding-win32-ia32-msvc@0.119.0':
+ resolution: {integrity: sha512-+0kqoCfv4WFP3e4BqcVEtf1moUuG9Zv5lo1aKcw1JakqJo008TGG+C2LnVM4QucGSZVQ/Ii/H5XCvrRbkeLQfA==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [ia32]
+ os: [win32]
+
+ '@oxc-parser/binding-win32-x64-msvc@0.119.0':
+ resolution: {integrity: sha512-5kaKmBHD+OQjZzGAQQ9n8jWNvCRxu3MjElAjkCqsS3i2wiN3hqHlOPKwGDydYiB1gKdeYGlTjRYtuF4gBLDSxQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ cpu: [x64]
+ os: [win32]
+
'@oxc-project/runtime@0.115.0':
resolution: {integrity: sha512-Rg8Wlt5dCbXhQnsXPrkOjL1DTSvXLgb2R/KYfnf1/K+R0k6UMLEmbQXPM+kwrWqSmWA2t0B1EtHy2/3zikQpvQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -402,6 +909,9 @@ packages:
'@oxc-project/types@0.115.0':
resolution: {integrity: sha512-4n91DKnebUS4yjUHl2g3/b2T+IUdCfmoZGhmwsovZCDaJSs+QkVAM+0AqqTxHSsHfeiMuueT75cZaZcT/m0pSw==}
+ '@oxc-project/types@0.119.0':
+ resolution: {integrity: sha512-9SCGhodOxEicD2kblitu34fGHcpmqgI3beYw/E22ehVLHzccHRFH91NmKt0MhZEaAwLpei6OOA9aB6Vuks9qAg==}
+
'@oxfmt/binding-android-arm-eabi@0.40.0':
resolution: {integrity: sha512-S6zd5r1w/HmqR8t0CTnGjFTBLDq2QKORPwriCHxo4xFNuhmOTABGjPaNvCJJVnrKBLsohOeiDX3YqQfJPF+FXw==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -778,9 +1288,65 @@ packages:
cpu: [x64]
os: [win32]
+ '@rolldown/plugin-babel@0.2.1':
+ resolution: {integrity: sha512-pHDVHqFv26JNC8I500JZ0H4h1kvSyiE3V9gjEO9pRAgD1KrIdJvcHCokV6f7gG7Rx4vMOD11V8VUOpqdyGbKBw==}
+ engines: {node: '>=22.12.0 || ^24.0.0'}
+ peerDependencies:
+ '@babel/core': ^7.29.0 || ^8.0.0-rc.1
+ '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1
+ '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1
+ rolldown: ^1.0.0-rc.5
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@babel/plugin-transform-runtime':
+ optional: true
+ '@babel/runtime':
+ optional: true
+ vite:
+ optional: true
+
+ '@rolldown/plugin-babel@file:packages/babel':
+ resolution: {directory: packages/babel, type: directory}
+ engines: {node: '>=22.12.0 || ^24.0.0'}
+ peerDependencies:
+ '@babel/core': ^7.29.0 || ^8.0.0-rc.1
+ '@babel/plugin-transform-runtime': ^7.29.0 || ^8.0.0-rc.1
+ '@babel/runtime': ^7.27.0 || ^8.0.0-rc.1
+ rolldown: ^1.0.0-rc.5
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@babel/plugin-transform-runtime':
+ optional: true
+ '@babel/runtime':
+ optional: true
+ vite:
+ optional: true
+
+ '@rolldown/pluginutils@1.0.0-rc.7':
+ resolution: {integrity: sha512-qujRfC8sFVInYSPPMLQByRh7zhwkGFS4+tyMQ83srV1qrxL4g8E2tyxVVyxd0+8QeBM1mIk9KbWxkegRr76XzA==}
+
'@rolldown/pluginutils@1.0.0-rc.9':
resolution: {integrity: sha512-w6oiRWgEBl04QkFZgmW+jnU1EC9b57Oihi2ot3HNWIQRqgHp5PnYDia5iZ5FF7rpa4EQdiqMDXjlqKGXBhsoXw==}
+ '@rollup/plugin-swc@0.4.0':
+ resolution: {integrity: sha512-oAtqXa8rOl7BOK1Rz3rRxI+LIL53S9SqO2KSq2UUUzWgOgXg6492Jh5mL2mv/f9cpit8zFWdwILuVeozZ0C8mg==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ '@swc/core': ^1.3.0
+ rollup: ^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
+ '@rollup/pluginutils@5.3.0':
+ resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==}
+ engines: {node: '>=14.0.0'}
+ peerDependencies:
+ rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0
+ peerDependenciesMeta:
+ rollup:
+ optional: true
+
'@sec-ant/readable-stream@0.4.1':
resolution: {integrity: sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==}
@@ -799,6 +1365,88 @@ packages:
'@standard-schema/spec@1.1.0':
resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==}
+ '@swc/core-darwin-arm64@1.15.18':
+ resolution: {integrity: sha512-+mIv7uBuSaywN3C9LNuWaX1jJJ3SKfiJuE6Lr3bd+/1Iv8oMU7oLBjYMluX1UrEPzwN2qCdY6Io0yVicABoCwQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [darwin]
+
+ '@swc/core-darwin-x64@1.15.18':
+ resolution: {integrity: sha512-wZle0eaQhnzxWX5V/2kEOI6Z9vl/lTFEC6V4EWcn+5pDjhemCpQv9e/TDJ0GIoiClX8EDWRvuZwh+Z3dhL1NAg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [darwin]
+
+ '@swc/core-linux-arm-gnueabihf@1.15.18':
+ resolution: {integrity: sha512-ao61HGXVqrJFHAcPtF4/DegmwEkVCo4HApnotLU8ognfmU8x589z7+tcf3hU+qBiU1WOXV5fQX6W9Nzs6hjxDw==}
+ engines: {node: '>=10'}
+ cpu: [arm]
+ os: [linux]
+
+ '@swc/core-linux-arm64-gnu@1.15.18':
+ resolution: {integrity: sha512-3xnctOBLIq3kj8PxOCgPrGjBLP/kNOddr6f5gukYt/1IZxsITQaU9TDyjeX6jG+FiCIHjCuWuffsyQDL5Ew1bg==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-arm64-musl@1.15.18':
+ resolution: {integrity: sha512-0a+Lix+FSSHBSBOA0XznCcHo5/1nA6oLLjcnocvzXeqtdjnPb+SvchItHI+lfeiuj1sClYPDvPMLSLyXFaiIKw==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-linux-x64-gnu@1.15.18':
+ resolution: {integrity: sha512-wG9J8vReUlpaHz4KOD/5UE1AUgirimU4UFT9oZmupUDEofxJKYb1mTA/DrMj0s78bkBiNI+7Fo2EgPuvOJfuAA==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [glibc]
+
+ '@swc/core-linux-x64-musl@1.15.18':
+ resolution: {integrity: sha512-4nwbVvCphKzicwNWRmvD5iBaZj8JYsRGa4xOxJmOyHlMDpsvvJ2OR2cODlvWyGFH6BYL1MfIAK3qph3hp0Az6g==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [linux]
+ libc: [musl]
+
+ '@swc/core-win32-arm64-msvc@1.15.18':
+ resolution: {integrity: sha512-zk0RYO+LjiBCat2RTMHzAWaMky0cra9loH4oRrLKLLNuL+jarxKLFDA8xTZWEkCPLjUTwlRN7d28eDLLMgtUcQ==}
+ engines: {node: '>=10'}
+ cpu: [arm64]
+ os: [win32]
+
+ '@swc/core-win32-ia32-msvc@1.15.18':
+ resolution: {integrity: sha512-yVuTrZ0RccD5+PEkpcLOBAuPbYBXS6rslENvIXfvJGXSdX5QGi1ehC4BjAMl5FkKLiam4kJECUI0l7Hq7T1vwg==}
+ engines: {node: '>=10'}
+ cpu: [ia32]
+ os: [win32]
+
+ '@swc/core-win32-x64-msvc@1.15.18':
+ resolution: {integrity: sha512-7NRmE4hmUQNCbYU3Hn9Tz57mK9Qq4c97ZS+YlamlK6qG9Fb5g/BB3gPDe0iLlJkns/sYv2VWSkm8c3NmbEGjbg==}
+ engines: {node: '>=10'}
+ cpu: [x64]
+ os: [win32]
+
+ '@swc/core@1.15.18':
+ resolution: {integrity: sha512-z87aF9GphWp//fnkRsqvtY+inMVPgYW3zSlXH1kJFvRT5H/wiAn+G32qW5l3oEk63KSF1x3Ov0BfHCObAmT8RA==}
+ engines: {node: '>=10'}
+ peerDependencies:
+ '@swc/helpers': '>=0.5.17'
+ peerDependenciesMeta:
+ '@swc/helpers':
+ optional: true
+
+ '@swc/counter@0.1.3':
+ resolution: {integrity: sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==}
+
+ '@swc/plugin-emotion@14.7.0':
+ resolution: {integrity: sha512-RwYrsxia8GKh2qLHWwymcfCeP6C5gAkssB2YtBRhP/qlKCxXYfv808buEXkCYvyGIY+bN3XziKXCuAi+waA5pQ==}
+
+ '@swc/types@0.1.25':
+ resolution: {integrity: sha512-iAoY/qRhNH8a/hBvm3zKj9qQ4oc2+3w1unPJa2XvTK3XjeLXtzcCingVPw/9e5mn1+0yPqxcBGp9Jf0pkfMb1g==}
+
'@tybys/wasm-util@0.10.1':
resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==}
@@ -820,12 +1468,26 @@ packages:
'@types/node@22.19.15':
resolution: {integrity: sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==}
+ '@types/node@24.12.0':
+ resolution: {integrity: sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==}
+
'@types/normalize-package-data@2.4.4':
resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
+ '@types/parse-json@4.0.2':
+ resolution: {integrity: sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==}
+
'@types/picomatch@4.0.2':
resolution: {integrity: sha512-qHHxQ+P9PysNEGbALT8f8YOSHW0KJu6l2xU8DYY0fu/EmGxXdVnuTLvFUvBgPJMSqXq29SYHveejeAha+4AYgA==}
+ '@types/react-dom@19.2.3':
+ resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==}
+ peerDependencies:
+ '@types/react': ^19.2.0
+
+ '@types/react@19.2.14':
+ resolution: {integrity: sha512-ilcTH/UniCkMdtexkoCN0bI7pMcJDvmQFPvuPvmEaYA/NSfFTAgdUSLAoVjaRJm7+6PvcM+q1zYOwS4wTYMF9w==}
+
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20260314.1':
resolution: {integrity: sha512-PlDvhms3QsLOkXNnCoQGJXjcZG7G5QMnhpSOmtO5toZ93VhU1qaUdvDlxtbacCYxGXcs6qZiJnGUgcedfqn5cg==}
cpu: [arm64]
@@ -865,6 +1527,19 @@ packages:
resolution: {integrity: sha512-XOVmR59UL6r2dmcdZD6SV4nhX5u4e34onMv7XSz9zKBp9mb8/v8kKPgGy9adp9at24FpAeBYNN5HKIViSeHtpQ==}
hasBin: true
+ '@vitejs/plugin-react@6.0.1':
+ resolution: {integrity: sha512-l9X/E3cDb+xY3SWzlG1MOGt2usfEHGMNIaegaUGFsLkb3RCn/k8/TOXBcab+OndDI4TBtktT8/9BwwW8Vi9KUQ==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+ peerDependencies:
+ '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0
+ babel-plugin-react-compiler: ^1.0.0
+ vite: ^8.0.0
+ peerDependenciesMeta:
+ '@rolldown/plugin-babel':
+ optional: true
+ babel-plugin-react-compiler:
+ optional: true
+
'@vitejs/release-scripts@1.6.0':
resolution: {integrity: sha512-XV+w22Fvn+wqDtEkz8nQIJzvmRVSh90c2xvOO7cX9fkX8+39ZJpYRiXDIRJG1JRnF8khm1rHjulid+l+khc7TQ==}
@@ -897,6 +1572,11 @@ packages:
'@vitest/utils@4.1.0':
resolution: {integrity: sha512-XfPXT6a8TZY3dcGY8EdwsBulFCIw+BeeX0RZn2x/BtiY/75YGh8FeWGG8QISN/WhaqSrE2OrlDgtF8q5uhOTmw==}
+ acorn@8.16.0:
+ resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==}
+ engines: {node: '>=0.4.0'}
+ hasBin: true
+
ansis@4.2.0:
resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==}
engines: {node: '>=14'}
@@ -912,6 +1592,10 @@ packages:
resolution: {integrity: sha512-trmleAnZ2PxN/loHWVhhx1qeOHSRXq4TDsBBxq3GqeJitfk3+jTQ+v/C1km/KYq9M7wKqCewMh+/NAvVH7m+bw==}
engines: {node: '>=20.19.0'}
+ babel-plugin-macros@3.1.0:
+ resolution: {integrity: sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==}
+ engines: {node: '>=10', npm: '>=6'}
+
baseline-browser-mapping@2.10.0:
resolution: {integrity: sha512-lIyg0szRfYbiy67j9KN8IyeD7q7hcmqnJ1ddWmNt19ItGpNN64mnllmxUNFIOdOm6by97jlL6wfpTTJrmnjWAA==}
engines: {node: '>=6.0.0'}
@@ -929,6 +1613,10 @@ packages:
resolution: {integrity: sha512-tixWYgm5ZoOD+3g6UTea91eow5z6AAHaho3g0V9CNSNb45gM8SmflpAc+GRd1InC4AqN/07Unrgp56Y94N9hJQ==}
engines: {node: '>=20.19.0'}
+ callsites@3.1.0:
+ resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==}
+ engines: {node: '>=6'}
+
caniuse-lite@1.0.30001770:
resolution: {integrity: sha512-x/2CLQ1jHENRbHg5PSId2sXq1CIO1CISvwWAj027ltMVG2UNgW+w9oH2+HzgEIRFembL8bUlXtfbBHR1fCg2xw==}
@@ -939,6 +1627,9 @@ packages:
compare-func@2.0.0:
resolution: {integrity: sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA==}
+ confbox@0.1.8:
+ resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==}
+
conventional-changelog-conventionalcommits@9.1.0:
resolution: {integrity: sha512-MnbEysR8wWa8dAEvbj5xcBgJKQlX/m0lhS8DsyAAWDHdfs2faDJxTgzRYlRYpXSe7UiKrIIlB4TrBKU9q9DgkA==}
engines: {node: '>=18'}
@@ -966,13 +1657,32 @@ packages:
engines: {node: '>=18'}
hasBin: true
+ convert-source-map@1.9.0:
+ resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
+
convert-source-map@2.0.0:
resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==}
+ cosmiconfig@7.1.0:
+ resolution: {integrity: sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==}
+ engines: {node: '>=10'}
+
cross-spawn@7.0.6:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'}
+ csstype@3.2.3:
+ resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==}
+
+ debug@4.4.3:
+ resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
+ engines: {node: '>=6.0'}
+ peerDependencies:
+ supports-color: '*'
+ peerDependenciesMeta:
+ supports-color:
+ optional: true
+
defu@6.1.4:
resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==}
@@ -1000,6 +1710,9 @@ packages:
resolution: {integrity: sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==}
engines: {node: '>=14'}
+ error-ex@1.3.4:
+ resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==}
+
es-module-lexer@2.0.0:
resolution: {integrity: sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==}
@@ -1012,6 +1725,13 @@ packages:
resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==}
engines: {node: '>=6'}
+ escape-string-regexp@4.0.0:
+ resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
+ engines: {node: '>=10'}
+
+ estree-walker@2.0.2:
+ resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
+
estree-walker@3.0.3:
resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==}
@@ -1043,11 +1763,17 @@ packages:
resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==}
engines: {node: '>=18'}
+ find-root@1.1.0:
+ resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
+
fsevents@2.3.3:
resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
os: [darwin]
+ function-bind@1.1.2:
+ resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==}
+
gensync@1.0.0-beta.2:
resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==}
engines: {node: '>=6.9.0'}
@@ -1068,6 +1794,13 @@ packages:
engines: {node: '>=0.4.7'}
hasBin: true
+ hasown@2.0.2:
+ resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==}
+ engines: {node: '>= 0.4'}
+
+ hoist-non-react-statics@3.3.2:
+ resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==}
+
hookable@6.0.1:
resolution: {integrity: sha512-uKGyY8BuzN/a5gvzvA+3FVWo0+wUjgtfSdnmjtrOVwQCZPHpHDH2WRO3VZSOeluYrHoDCiXFffZXs8Dj1ULWtw==}
@@ -1083,6 +1816,10 @@ packages:
resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==}
engines: {node: '>=18.18.0'}
+ import-fresh@3.3.1:
+ resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==}
+ engines: {node: '>=6'}
+
import-meta-resolve@4.2.0:
resolution: {integrity: sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==}
@@ -1090,6 +1827,13 @@ packages:
resolution: {integrity: sha512-B6Lc2s6yApwnD2/pMzFh/d5AVjdsDXjgkeJ766FmFuJELIGHNycKRj+l3A39yZPM4CchqNCB4RITEAYB1KUM6A==}
engines: {node: '>=20.19.0'}
+ is-arrayish@0.2.1:
+ resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
+
+ is-core-module@2.16.1:
+ resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==}
+ engines: {node: '>= 0.4'}
+
is-obj@2.0.0:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
engines: {node: '>=8'}
@@ -1116,11 +1860,17 @@ packages:
js-tokens@10.0.0:
resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==}
+ js-tokens@4.0.0:
+ resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
+
jsesc@3.1.0:
resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==}
engines: {node: '>=6'}
hasBin: true
+ json-parse-even-better-errors@2.3.1:
+ resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==}
+
json5@2.2.3:
resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==}
engines: {node: '>=6'}
@@ -1204,13 +1954,22 @@ packages:
resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==}
engines: {node: '>= 12.0.0'}
+ lines-and-columns@1.2.4:
+ resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
+
lru-cache@10.4.3:
resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==}
+ lru-cache@5.1.1:
+ resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==}
+
lru-cache@7.18.3:
resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==}
engines: {node: '>=12'}
+ magic-regexp@0.10.0:
+ resolution: {integrity: sha512-Uly1Bu4lO1hwHUW0CQeSWuRtzCMNO00CmXtS8N6fyvB3B979GOEEeAkiTUDsmbYLAbvpUS/Kt5c4ibosAzVyVg==}
+
magic-string@0.30.21:
resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==}
@@ -1228,10 +1987,16 @@ packages:
minimist@1.2.8:
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
+ mlly@1.8.0:
+ resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==}
+
mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
+ ms@2.1.3:
+ resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
+
nanoid@3.3.11:
resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@@ -1262,6 +2027,15 @@ packages:
resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==}
engines: {node: '>=12'}
+ oxc-parser@0.119.0:
+ resolution: {integrity: sha512-fNiKvO0ZHSUmINQlVY2It+vGbHxCvhpqJi0rZYFFOESoOy3fs5E4erKYGZtB/J1aULkjtY06aWNil4JxMsKXGg==}
+ engines: {node: ^20.19.0 || >=22.12.0}
+
+ oxc-walker@0.7.0:
+ resolution: {integrity: sha512-54B4KUhrzbzc4sKvKwVYm7E2PgeROpGba0/2nlNZMqfDyca+yOor5IMb4WLGBatGDT0nkzYdYuzylg7n3YfB7A==}
+ peerDependencies:
+ oxc-parser: '>=0.98.0'
+
oxfmt@0.40.0:
resolution: {integrity: sha512-g0C3I7xUj4b4DcagevM9kgH6+pUHytikxUcn3/VUkvzTNaaXBeyZqb7IBsHwojeXm4mTBEC/aBjBTMVUkZwWUQ==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1284,6 +2058,14 @@ packages:
package-manager-detector@1.6.0:
resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==}
+ parent-module@1.0.1:
+ resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==}
+ engines: {node: '>=6'}
+
+ parse-json@5.2.0:
+ resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==}
+ engines: {node: '>=8'}
+
parse-ms@4.0.0:
resolution: {integrity: sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==}
engines: {node: '>=18'}
@@ -1296,6 +2078,13 @@ packages:
resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==}
engines: {node: '>=12'}
+ path-parse@1.0.7:
+ resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
+
+ path-type@4.0.0:
+ resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
+ engines: {node: '>=8'}
+
pathe@2.0.3:
resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==}
@@ -1306,6 +2095,23 @@ packages:
resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==}
engines: {node: '>=12'}
+ pirates@4.0.7:
+ resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==}
+ engines: {node: '>= 6'}
+
+ pkg-types@1.3.1:
+ resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==}
+
+ playwright-chromium@1.58.2:
+ resolution: {integrity: sha512-SCoQ3hjBs7FfO46CoOtgAUg77BuYwCni1bzQgm47IUyLBTipnGkLxLnaUNRKXvPYO4hAyt8++Z6wVShVnhrzmw==}
+ engines: {node: '>=18'}
+ hasBin: true
+
+ playwright-core@1.58.2:
+ resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==}
+ engines: {node: '>=18'}
+ hasBin: true
+
postcss@8.5.8:
resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==}
engines: {node: ^10 || ^12 || >=14}
@@ -1326,9 +2132,34 @@ packages:
quansync@1.0.0:
resolution: {integrity: sha512-5xZacEEufv3HSTPQuchrvV6soaiACMFnq1H8wkVioctoH3TRha9Sz66lOxRwPK/qZj7HPiSveih9yAyh98gvqA==}
+ react-dom@19.2.4:
+ resolution: {integrity: sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==}
+ peerDependencies:
+ react: ^19.2.4
+
+ react-is@16.13.1:
+ resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==}
+
+ react@19.2.4:
+ resolution: {integrity: sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==}
+ engines: {node: '>=0.10.0'}
+
+ regexp-tree@0.1.27:
+ resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
+ hasBin: true
+
+ resolve-from@4.0.0:
+ resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==}
+ engines: {node: '>=4'}
+
resolve-pkg-maps@1.0.0:
resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==}
+ resolve@1.22.11:
+ resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==}
+ engines: {node: '>= 0.4'}
+ hasBin: true
+
rolldown-plugin-dts@0.22.5:
resolution: {integrity: sha512-M/HXfM4cboo+jONx9Z0X+CUf3B5tCi7ni+kR5fUW50Fp9AlZk0oVLesibGWgCXDKFp5lpgQ9yhKoImUFjl3VZw==}
engines: {node: '>=20.19.0'}
@@ -1348,6 +2179,15 @@ packages:
vue-tsc:
optional: true
+ rolldown-string@0.3.0:
+ resolution: {integrity: sha512-qGhBPNSv/27uzFBQdO+Cs4YAXC/1PKznD7Jz5Fl7NIAIlteuTPBTBWBhCpJ2AFTqLsoKvvUr7wSjqSUip0Fkpg==}
+ engines: {node: '>=20.19.0'}
+ peerDependencies:
+ rolldown: '*'
+ peerDependenciesMeta:
+ rolldown:
+ optional: true
+
rolldown@1.0.0-rc.9:
resolution: {integrity: sha512-9EbgWge7ZH+yqb4d2EnELAntgPTWbfL8ajiTW+SyhJEC4qhBbkCKbqFV4Ge4zmu5ziQuVbWxb/XwLZ+RIO7E8Q==}
engines: {node: ^20.19.0 || >=22.12.0}
@@ -1357,6 +2197,13 @@ packages:
resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==}
engines: {node: '>=6'}
+ scheduler@0.27.0:
+ resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==}
+
+ semver@6.3.1:
+ resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==}
+ hasBin: true
+
semver@7.7.4:
resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==}
engines: {node: '>=10'}
@@ -1380,10 +2227,18 @@ packages:
sisteransi@1.0.5:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
+ smob@1.6.1:
+ resolution: {integrity: sha512-KAkBqZl3c2GvNgNhcoyJae1aKldDW0LO279wF9bk1PnluRTETKBq0WyzRXxEhoQLk56yHaOY4JCBEKDuJIET5g==}
+ engines: {node: '>=20.0.0'}
+
source-map-js@1.2.1:
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
engines: {node: '>=0.10.0'}
+ source-map@0.5.7:
+ resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==}
+ engines: {node: '>=0.10.0'}
+
source-map@0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
@@ -1414,6 +2269,13 @@ packages:
resolution: {integrity: sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==}
engines: {node: '>=18'}
+ stylis@4.2.0:
+ resolution: {integrity: sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==}
+
+ supports-preserve-symlinks-flag@1.0.0:
+ resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
+ engines: {node: '>= 0.4'}
+
tinybench@2.9.0:
resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==}
@@ -1468,6 +2330,12 @@ packages:
tslib@2.8.1:
resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==}
+ type-level-regexp@0.1.17:
+ resolution: {integrity: sha512-wTk4DH3cxwk196uGLK/E9pE45aLfeKJacKmcEgEOA/q5dnPGNxXt0cfYdFxb57L+sEpf1oJH4Dnx/pnRcku9jg==}
+
+ ufo@1.6.3:
+ resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==}
+
uglify-js@3.19.3:
resolution: {integrity: sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==}
engines: {node: '>=0.8.0'}
@@ -1479,10 +2347,17 @@ packages:
undici-types@6.21.0:
resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
+ undici-types@7.16.0:
+ resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
unicorn-magic@0.3.0:
resolution: {integrity: sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==}
engines: {node: '>=18'}
+ unplugin@2.3.11:
+ resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==}
+ engines: {node: '>=18.12.0'}
+
unrun@0.2.32:
resolution: {integrity: sha512-opd3z6791rf281JdByf0RdRQrpcc7WyzqittqIXodM/5meNWdTwrVxeyzbaCp4/Rgls/um14oUaif1gomO8YGg==}
engines: {node: '>=20.19.0'}
@@ -1584,6 +2459,9 @@ packages:
resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==}
engines: {node: 20 || >=22}
+ webpack-virtual-modules@0.6.2:
+ resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==}
+
which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -1597,19 +2475,54 @@ packages:
wordwrap@1.0.0:
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
+ yallist@3.1.1:
+ resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
+
+ yaml@1.10.2:
+ resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
+ engines: {node: '>= 6'}
+
yoctocolors@2.1.2:
resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==}
engines: {node: '>=18'}
snapshots:
+ '@babel/code-frame@7.29.0':
+ dependencies:
+ '@babel/helper-validator-identifier': 7.28.5
+ js-tokens: 4.0.0
+ picocolors: 1.1.1
+
'@babel/code-frame@8.0.0-rc.2':
dependencies:
'@babel/helper-validator-identifier': 8.0.0-rc.2
js-tokens: 10.0.0
+ '@babel/compat-data@7.29.0': {}
+
'@babel/compat-data@8.0.0-rc.2': {}
+ '@babel/core@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-compilation-targets': 7.28.6
+ '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0)
+ '@babel/helpers': 7.28.6
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/remapping': 2.3.5
+ convert-source-map: 2.0.0
+ debug: 4.4.3
+ gensync: 1.0.0-beta.2
+ json5: 2.2.3
+ semver: 6.3.1
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/core@8.0.0-rc.2':
dependencies:
'@babel/code-frame': 8.0.0-rc.2
@@ -1629,6 +2542,14 @@ snapshots:
obug: 2.1.1
semver: 7.7.4
+ '@babel/generator@7.29.1':
+ dependencies:
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+ '@jridgewell/gen-mapping': 0.3.13
+ '@jridgewell/trace-mapping': 0.3.31
+ jsesc: 3.1.0
+
'@babel/generator@8.0.0-rc.2':
dependencies:
'@babel/parser': 8.0.0-rc.2
@@ -1642,6 +2563,14 @@ snapshots:
dependencies:
'@babel/types': 8.0.0-rc.2
+ '@babel/helper-compilation-targets@7.28.6':
+ dependencies:
+ '@babel/compat-data': 7.29.0
+ '@babel/helper-validator-option': 7.27.1
+ browserslist: 4.28.1
+ lru-cache: 5.1.1
+ semver: 6.3.1
+
'@babel/helper-compilation-targets@8.0.0-rc.2':
dependencies:
'@babel/compat-data': 8.0.0-rc.2
@@ -1661,6 +2590,8 @@ snapshots:
'@babel/traverse': 8.0.0-rc.2
semver: 7.7.4
+ '@babel/helper-globals@7.28.0': {}
+
'@babel/helper-globals@8.0.0-rc.2': {}
'@babel/helper-member-expression-to-functions@8.0.0-rc.2':
@@ -1668,15 +2599,36 @@ snapshots:
'@babel/traverse': 8.0.0-rc.2
'@babel/types': 8.0.0-rc.2
+ '@babel/helper-module-imports@7.28.6':
+ dependencies:
+ '@babel/traverse': 7.29.0
+ '@babel/types': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/helper-module-imports@8.0.0-rc.2':
dependencies:
'@babel/traverse': 8.0.0-rc.2
'@babel/types': 8.0.0-rc.2
+ '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/helper-validator-identifier': 7.28.5
+ '@babel/traverse': 7.29.0
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/helper-optimise-call-expression@8.0.0-rc.2':
dependencies:
'@babel/types': 8.0.0-rc.2
+ '@babel/helper-plugin-utils@8.0.0-rc.2(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ optional: true
+
'@babel/helper-plugin-utils@8.0.0-rc.2(@babel/core@8.0.0-rc.2)':
dependencies:
'@babel/core': 8.0.0-rc.2
@@ -1693,17 +2645,32 @@ snapshots:
'@babel/traverse': 8.0.0-rc.2
'@babel/types': 8.0.0-rc.2
+ '@babel/helper-string-parser@7.27.1': {}
+
'@babel/helper-string-parser@8.0.0-rc.2': {}
+ '@babel/helper-validator-identifier@7.28.5': {}
+
'@babel/helper-validator-identifier@8.0.0-rc.2': {}
+ '@babel/helper-validator-option@7.27.1': {}
+
'@babel/helper-validator-option@8.0.0-rc.2': {}
+ '@babel/helpers@7.28.6':
+ dependencies:
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+
'@babel/helpers@8.0.0-rc.2':
dependencies:
'@babel/template': 8.0.0-rc.2
'@babel/types': 8.0.0-rc.2
+ '@babel/parser@7.29.0':
+ dependencies:
+ '@babel/types': 7.29.0
+
'@babel/parser@8.0.0-rc.2':
dependencies:
'@babel/types': 8.0.0-rc.2
@@ -1720,20 +2687,47 @@ snapshots:
'@babel/core': 8.0.0-rc.2
'@babel/helper-plugin-utils': 8.0.0-rc.2(@babel/core@8.0.0-rc.2)
+ '@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@7.29.0)':
+ dependencies:
+ '@babel/core': 7.29.0
+ '@babel/helper-module-imports': 8.0.0-rc.2
+ '@babel/helper-plugin-utils': 8.0.0-rc.2(@babel/core@7.29.0)
+ optional: true
+
'@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@8.0.0-rc.2)':
dependencies:
'@babel/core': 8.0.0-rc.2
'@babel/helper-module-imports': 8.0.0-rc.2
'@babel/helper-plugin-utils': 8.0.0-rc.2(@babel/core@8.0.0-rc.2)
+ '@babel/runtime@7.28.6': {}
+
'@babel/runtime@8.0.0-rc.2': {}
+ '@babel/template@7.28.6':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/parser': 7.29.0
+ '@babel/types': 7.29.0
+
'@babel/template@8.0.0-rc.2':
dependencies:
'@babel/code-frame': 8.0.0-rc.2
'@babel/parser': 8.0.0-rc.2
'@babel/types': 8.0.0-rc.2
+ '@babel/traverse@7.29.0':
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ '@babel/generator': 7.29.1
+ '@babel/helper-globals': 7.28.0
+ '@babel/parser': 7.29.0
+ '@babel/template': 7.28.6
+ '@babel/types': 7.29.0
+ debug: 4.4.3
+ transitivePeerDependencies:
+ - supports-color
+
'@babel/traverse@8.0.0-rc.2':
dependencies:
'@babel/code-frame': 8.0.0-rc.2
@@ -1744,6 +2738,11 @@ snapshots:
'@babel/types': 8.0.0-rc.2
obug: 2.1.1
+ '@babel/types@7.29.0':
+ dependencies:
+ '@babel/helper-string-parser': 7.27.1
+ '@babel/helper-validator-identifier': 7.28.5
+
'@babel/types@8.0.0-rc.2':
dependencies:
'@babel/helper-string-parser': 8.0.0-rc.2
@@ -1755,24 +2754,107 @@ snapshots:
'@simple-libs/stream-utils': 1.1.0
semver: 7.7.4
optionalDependencies:
- conventional-commits-filter: 5.0.0
- conventional-commits-parser: 6.2.1
+ conventional-commits-filter: 5.0.0
+ conventional-commits-parser: 6.2.1
+
+ '@emnapi/core@1.8.1':
+ dependencies:
+ '@emnapi/wasi-threads': 1.1.0
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/runtime@1.8.1':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emnapi/wasi-threads@1.1.0':
+ dependencies:
+ tslib: 2.8.1
+ optional: true
+
+ '@emotion/babel-plugin@11.13.5':
+ dependencies:
+ '@babel/helper-module-imports': 7.28.6
+ '@babel/runtime': 7.28.6
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/serialize': 1.3.3
+ babel-plugin-macros: 3.1.0
+ convert-source-map: 1.9.0
+ escape-string-regexp: 4.0.0
+ find-root: 1.1.0
+ source-map: 0.5.7
+ stylis: 4.2.0
+ transitivePeerDependencies:
+ - supports-color
+
+ '@emotion/cache@11.14.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+ '@emotion/sheet': 1.4.0
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ stylis: 4.2.0
+
+ '@emotion/hash@0.9.2': {}
+
+ '@emotion/is-prop-valid@1.4.0':
+ dependencies:
+ '@emotion/memoize': 0.9.0
+
+ '@emotion/memoize@0.9.0': {}
+
+ '@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4)':
+ dependencies:
+ '@babel/runtime': 7.28.6
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/cache': 11.14.0
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4)
+ '@emotion/utils': 1.4.2
+ '@emotion/weak-memoize': 0.4.0
+ hoist-non-react-statics: 3.3.2
+ react: 19.2.4
+ optionalDependencies:
+ '@types/react': 19.2.14
+ transitivePeerDependencies:
+ - supports-color
- '@emnapi/core@1.8.1':
+ '@emotion/serialize@1.3.3':
dependencies:
- '@emnapi/wasi-threads': 1.1.0
- tslib: 2.8.1
- optional: true
+ '@emotion/hash': 0.9.2
+ '@emotion/memoize': 0.9.0
+ '@emotion/unitless': 0.10.0
+ '@emotion/utils': 1.4.2
+ csstype: 3.2.3
- '@emnapi/runtime@1.8.1':
+ '@emotion/sheet@1.4.0': {}
+
+ '@emotion/styled@11.14.1(@emotion/react@11.14.0(@types/react@19.2.14)(react@19.2.4))(@types/react@19.2.14)(react@19.2.4)':
dependencies:
- tslib: 2.8.1
- optional: true
+ '@babel/runtime': 7.28.6
+ '@emotion/babel-plugin': 11.13.5
+ '@emotion/is-prop-valid': 1.4.0
+ '@emotion/react': 11.14.0(@types/react@19.2.14)(react@19.2.4)
+ '@emotion/serialize': 1.3.3
+ '@emotion/use-insertion-effect-with-fallbacks': 1.2.0(react@19.2.4)
+ '@emotion/utils': 1.4.2
+ react: 19.2.4
+ optionalDependencies:
+ '@types/react': 19.2.14
+ transitivePeerDependencies:
+ - supports-color
- '@emnapi/wasi-threads@1.1.0':
+ '@emotion/unitless@0.10.0': {}
+
+ '@emotion/use-insertion-effect-with-fallbacks@1.2.0(react@19.2.4)':
dependencies:
- tslib: 2.8.1
- optional: true
+ react: 19.2.4
+
+ '@emotion/utils@1.4.2': {}
+
+ '@emotion/weak-memoize@0.4.0': {}
'@esbuild/aix-ppc64@0.27.3':
optional: true
@@ -1878,10 +2960,153 @@ snapshots:
'@tybys/wasm-util': 0.10.1
optional: true
+ '@oxc-node/cli@0.0.35':
+ dependencies:
+ '@oxc-node/core': 0.0.35
+
+ '@oxc-node/core-android-arm-eabi@0.0.35':
+ optional: true
+
+ '@oxc-node/core-android-arm64@0.0.35':
+ optional: true
+
+ '@oxc-node/core-darwin-arm64@0.0.35':
+ optional: true
+
+ '@oxc-node/core-darwin-x64@0.0.35':
+ optional: true
+
+ '@oxc-node/core-freebsd-x64@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-arm-gnueabihf@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-arm64-gnu@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-arm64-musl@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-ppc64-gnu@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-s390x-gnu@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-x64-gnu@0.0.35':
+ optional: true
+
+ '@oxc-node/core-linux-x64-musl@0.0.35':
+ optional: true
+
+ '@oxc-node/core-openharmony-arm64@0.0.35':
+ optional: true
+
+ '@oxc-node/core-wasm32-wasi@0.0.35':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.1
+ optional: true
+
+ '@oxc-node/core-win32-arm64-msvc@0.0.35':
+ optional: true
+
+ '@oxc-node/core-win32-ia32-msvc@0.0.35':
+ optional: true
+
+ '@oxc-node/core-win32-x64-msvc@0.0.35':
+ optional: true
+
+ '@oxc-node/core@0.0.35':
+ dependencies:
+ pirates: 4.0.7
+ optionalDependencies:
+ '@oxc-node/core-android-arm-eabi': 0.0.35
+ '@oxc-node/core-android-arm64': 0.0.35
+ '@oxc-node/core-darwin-arm64': 0.0.35
+ '@oxc-node/core-darwin-x64': 0.0.35
+ '@oxc-node/core-freebsd-x64': 0.0.35
+ '@oxc-node/core-linux-arm-gnueabihf': 0.0.35
+ '@oxc-node/core-linux-arm64-gnu': 0.0.35
+ '@oxc-node/core-linux-arm64-musl': 0.0.35
+ '@oxc-node/core-linux-ppc64-gnu': 0.0.35
+ '@oxc-node/core-linux-s390x-gnu': 0.0.35
+ '@oxc-node/core-linux-x64-gnu': 0.0.35
+ '@oxc-node/core-linux-x64-musl': 0.0.35
+ '@oxc-node/core-openharmony-arm64': 0.0.35
+ '@oxc-node/core-wasm32-wasi': 0.0.35
+ '@oxc-node/core-win32-arm64-msvc': 0.0.35
+ '@oxc-node/core-win32-ia32-msvc': 0.0.35
+ '@oxc-node/core-win32-x64-msvc': 0.0.35
+
+ '@oxc-parser/binding-android-arm-eabi@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-android-arm64@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-arm64@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-darwin-x64@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-freebsd-x64@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-gnueabihf@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm-musleabihf@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-gnu@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-arm64-musl@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-ppc64-gnu@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-riscv64-gnu@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-riscv64-musl@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-s390x-gnu@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-gnu@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-linux-x64-musl@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-openharmony-arm64@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-wasm32-wasi@0.119.0':
+ dependencies:
+ '@napi-rs/wasm-runtime': 1.1.1
+ optional: true
+
+ '@oxc-parser/binding-win32-arm64-msvc@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-ia32-msvc@0.119.0':
+ optional: true
+
+ '@oxc-parser/binding-win32-x64-msvc@0.119.0':
+ optional: true
+
'@oxc-project/runtime@0.115.0': {}
'@oxc-project/types@0.115.0': {}
+ '@oxc-project/types@0.119.0': {}
+
'@oxfmt/binding-android-arm-eabi@0.40.0':
optional: true
@@ -2067,8 +3292,43 @@ snapshots:
'@rolldown/binding-win32-x64-msvc@1.0.0-rc.9':
optional: true
+ '@rolldown/plugin-babel@0.2.1(@babel/core@8.0.0-rc.2)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@8.0.0-rc.2))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))':
+ dependencies:
+ '@babel/core': 8.0.0-rc.2
+ picomatch: 4.0.3
+ rolldown: 1.0.0-rc.9
+ optionalDependencies:
+ '@babel/plugin-transform-runtime': 8.0.0-rc.2(@babel/core@8.0.0-rc.2)
+ '@babel/runtime': 8.0.0-rc.2
+ vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+ optional: true
+
+ '@rolldown/plugin-babel@file:packages/babel(@babel/core@7.29.0)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@7.29.0))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))':
+ dependencies:
+ '@babel/core': 7.29.0
+ picomatch: 4.0.3
+ rolldown: 1.0.0-rc.9
+ optionalDependencies:
+ '@babel/plugin-transform-runtime': 8.0.0-rc.2(@babel/core@7.29.0)
+ '@babel/runtime': 8.0.0-rc.2
+ vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+
+ '@rolldown/pluginutils@1.0.0-rc.7': {}
+
'@rolldown/pluginutils@1.0.0-rc.9': {}
+ '@rollup/plugin-swc@0.4.0(@swc/core@1.15.18)':
+ dependencies:
+ '@rollup/pluginutils': 5.3.0
+ '@swc/core': 1.15.18
+ smob: 1.6.1
+
+ '@rollup/pluginutils@5.3.0':
+ dependencies:
+ '@types/estree': 1.0.8
+ estree-walker: 2.0.2
+ picomatch: 4.0.3
+
'@sec-ant/readable-stream@0.4.1': {}
'@simple-libs/child-process-utils@1.0.1':
@@ -2084,6 +3344,62 @@ snapshots:
'@standard-schema/spec@1.1.0': {}
+ '@swc/core-darwin-arm64@1.15.18':
+ optional: true
+
+ '@swc/core-darwin-x64@1.15.18':
+ optional: true
+
+ '@swc/core-linux-arm-gnueabihf@1.15.18':
+ optional: true
+
+ '@swc/core-linux-arm64-gnu@1.15.18':
+ optional: true
+
+ '@swc/core-linux-arm64-musl@1.15.18':
+ optional: true
+
+ '@swc/core-linux-x64-gnu@1.15.18':
+ optional: true
+
+ '@swc/core-linux-x64-musl@1.15.18':
+ optional: true
+
+ '@swc/core-win32-arm64-msvc@1.15.18':
+ optional: true
+
+ '@swc/core-win32-ia32-msvc@1.15.18':
+ optional: true
+
+ '@swc/core-win32-x64-msvc@1.15.18':
+ optional: true
+
+ '@swc/core@1.15.18':
+ dependencies:
+ '@swc/counter': 0.1.3
+ '@swc/types': 0.1.25
+ optionalDependencies:
+ '@swc/core-darwin-arm64': 1.15.18
+ '@swc/core-darwin-x64': 1.15.18
+ '@swc/core-linux-arm-gnueabihf': 1.15.18
+ '@swc/core-linux-arm64-gnu': 1.15.18
+ '@swc/core-linux-arm64-musl': 1.15.18
+ '@swc/core-linux-x64-gnu': 1.15.18
+ '@swc/core-linux-x64-musl': 1.15.18
+ '@swc/core-win32-arm64-msvc': 1.15.18
+ '@swc/core-win32-ia32-msvc': 1.15.18
+ '@swc/core-win32-x64-msvc': 1.15.18
+
+ '@swc/counter@0.1.3': {}
+
+ '@swc/plugin-emotion@14.7.0':
+ dependencies:
+ '@swc/counter': 0.1.3
+
+ '@swc/types@0.1.25':
+ dependencies:
+ '@swc/counter': 0.1.3
+
'@tybys/wasm-util@0.10.1':
dependencies:
tslib: 2.8.1
@@ -2106,10 +3422,24 @@ snapshots:
dependencies:
undici-types: 6.21.0
+ '@types/node@24.12.0':
+ dependencies:
+ undici-types: 7.16.0
+
'@types/normalize-package-data@2.4.4': {}
+ '@types/parse-json@4.0.2': {}
+
'@types/picomatch@4.0.2': {}
+ '@types/react-dom@19.2.3(@types/react@19.2.14)':
+ dependencies:
+ '@types/react': 19.2.14
+
+ '@types/react@19.2.14':
+ dependencies:
+ csstype: 3.2.3
+
'@typescript/native-preview-darwin-arm64@7.0.0-dev.20260314.1':
optional: true
@@ -2141,6 +3471,13 @@ snapshots:
'@typescript/native-preview-win32-arm64': 7.0.0-dev.20260314.1
'@typescript/native-preview-win32-x64': 7.0.0-dev.20260314.1
+ '@vitejs/plugin-react@6.0.1(@rolldown/plugin-babel@0.2.1(@babel/core@8.0.0-rc.2)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@8.0.0-rc.2))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3)))(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))':
+ dependencies:
+ '@rolldown/pluginutils': 1.0.0-rc.7
+ vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
+ optionalDependencies:
+ '@rolldown/plugin-babel': 0.2.1(@babel/core@8.0.0-rc.2)(@babel/plugin-transform-runtime@8.0.0-rc.2(@babel/core@8.0.0-rc.2))(@babel/runtime@8.0.0-rc.2)(rolldown@1.0.0-rc.9)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))
+
'@vitejs/release-scripts@1.6.0(patch_hash=934d3ff41c551b1d73703bec99c2edbc3a91ec064c86cb21dad311a998354ced)(conventional-commits-filter@5.0.0)':
dependencies:
conventional-changelog: 7.1.1(conventional-commits-filter@5.0.0)
@@ -2163,13 +3500,13 @@ snapshots:
chai: 6.2.2
tinyrainbow: 3.0.3
- '@vitest/mocker@4.1.0(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3))':
+ '@vitest/mocker@4.1.0(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))':
dependencies:
'@vitest/spy': 4.1.0
estree-walker: 3.0.3
magic-string: 0.30.21
optionalDependencies:
- vite: 8.0.0(@types/node@22.19.15)(esbuild@0.27.3)
+ vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
'@vitest/pretty-format@4.1.0':
dependencies:
@@ -2195,6 +3532,8 @@ snapshots:
convert-source-map: 2.0.0
tinyrainbow: 3.0.3
+ acorn@8.16.0: {}
+
ansis@4.2.0: {}
array-ify@1.0.0: {}
@@ -2207,6 +3546,12 @@ snapshots:
estree-walker: 3.0.3
pathe: 2.0.3
+ babel-plugin-macros@3.1.0:
+ dependencies:
+ '@babel/runtime': 7.28.6
+ cosmiconfig: 7.1.0
+ resolve: 1.22.11
+
baseline-browser-mapping@2.10.0: {}
birpc@4.0.0: {}
@@ -2221,6 +3566,8 @@ snapshots:
cac@7.0.0: {}
+ callsites@3.1.0: {}
+
caniuse-lite@1.0.30001770: {}
chai@6.2.2: {}
@@ -2230,6 +3577,8 @@ snapshots:
array-ify: 1.0.0
dot-prop: 5.3.0
+ confbox@0.1.8: {}
+
conventional-changelog-conventionalcommits@9.1.0:
dependencies:
compare-func: 2.0.0
@@ -2262,14 +3611,30 @@ snapshots:
dependencies:
meow: 13.2.0
+ convert-source-map@1.9.0: {}
+
convert-source-map@2.0.0: {}
+ cosmiconfig@7.1.0:
+ dependencies:
+ '@types/parse-json': 4.0.2
+ import-fresh: 3.3.1
+ parse-json: 5.2.0
+ path-type: 4.0.0
+ yaml: 1.10.2
+
cross-spawn@7.0.6:
dependencies:
path-key: 3.1.1
shebang-command: 2.0.0
which: 2.0.2
+ csstype@3.2.3: {}
+
+ debug@4.4.3:
+ dependencies:
+ ms: 2.1.3
+
defu@6.1.4: {}
detect-libc@2.1.2: {}
@@ -2284,6 +3649,10 @@ snapshots:
empathic@2.0.0: {}
+ error-ex@1.3.4:
+ dependencies:
+ is-arrayish: 0.2.1
+
es-module-lexer@2.0.0: {}
esbuild@0.27.3:
@@ -2318,6 +3687,10 @@ snapshots:
escalade@3.2.0: {}
+ escape-string-regexp@4.0.0: {}
+
+ estree-walker@2.0.2: {}
+
estree-walker@3.0.3:
dependencies:
'@types/estree': 1.0.8
@@ -2363,9 +3736,13 @@ snapshots:
dependencies:
is-unicode-supported: 2.1.0
+ find-root@1.1.0: {}
+
fsevents@2.3.3:
optional: true
+ function-bind@1.1.2: {}
+
gensync@1.0.0-beta.2: {}
get-stream@8.0.1: {}
@@ -2388,6 +3765,14 @@ snapshots:
optionalDependencies:
uglify-js: 3.19.3
+ hasown@2.0.2:
+ dependencies:
+ function-bind: 1.1.2
+
+ hoist-non-react-statics@3.3.2:
+ dependencies:
+ react-is: 16.13.1
+
hookable@6.0.1: {}
hosted-git-info@8.1.0:
@@ -2398,10 +3783,21 @@ snapshots:
human-signals@8.0.1: {}
+ import-fresh@3.3.1:
+ dependencies:
+ parent-module: 1.0.1
+ resolve-from: 4.0.0
+
import-meta-resolve@4.2.0: {}
import-without-cache@0.2.5: {}
+ is-arrayish@0.2.1: {}
+
+ is-core-module@2.16.1:
+ dependencies:
+ hasown: 2.0.2
+
is-obj@2.0.0: {}
is-plain-obj@4.1.0: {}
@@ -2416,8 +3812,12 @@ snapshots:
js-tokens@10.0.0: {}
+ js-tokens@4.0.0: {}
+
jsesc@3.1.0: {}
+ json-parse-even-better-errors@2.3.1: {}
+
json5@2.2.3: {}
kleur@3.0.3: {}
@@ -2471,10 +3871,26 @@ snapshots:
lightningcss-win32-arm64-msvc: 1.32.0
lightningcss-win32-x64-msvc: 1.32.0
+ lines-and-columns@1.2.4: {}
+
lru-cache@10.4.3: {}
+ lru-cache@5.1.1:
+ dependencies:
+ yallist: 3.1.1
+
lru-cache@7.18.3: {}
+ magic-regexp@0.10.0:
+ dependencies:
+ estree-walker: 3.0.3
+ magic-string: 0.30.21
+ mlly: 1.8.0
+ regexp-tree: 0.1.27
+ type-level-regexp: 0.1.17
+ ufo: 1.6.3
+ unplugin: 2.3.11
+
magic-string@0.30.21:
dependencies:
'@jridgewell/sourcemap-codec': 1.5.5
@@ -2487,8 +3903,17 @@ snapshots:
minimist@1.2.8: {}
+ mlly@1.8.0:
+ dependencies:
+ acorn: 8.16.0
+ pathe: 2.0.3
+ pkg-types: 1.3.1
+ ufo: 1.6.3
+
mri@1.2.0: {}
+ ms@2.1.3: {}
+
nanoid@3.3.11: {}
neo-async@2.6.2: {}
@@ -2516,6 +3941,36 @@ snapshots:
dependencies:
mimic-fn: 4.0.0
+ oxc-parser@0.119.0:
+ dependencies:
+ '@oxc-project/types': 0.119.0
+ optionalDependencies:
+ '@oxc-parser/binding-android-arm-eabi': 0.119.0
+ '@oxc-parser/binding-android-arm64': 0.119.0
+ '@oxc-parser/binding-darwin-arm64': 0.119.0
+ '@oxc-parser/binding-darwin-x64': 0.119.0
+ '@oxc-parser/binding-freebsd-x64': 0.119.0
+ '@oxc-parser/binding-linux-arm-gnueabihf': 0.119.0
+ '@oxc-parser/binding-linux-arm-musleabihf': 0.119.0
+ '@oxc-parser/binding-linux-arm64-gnu': 0.119.0
+ '@oxc-parser/binding-linux-arm64-musl': 0.119.0
+ '@oxc-parser/binding-linux-ppc64-gnu': 0.119.0
+ '@oxc-parser/binding-linux-riscv64-gnu': 0.119.0
+ '@oxc-parser/binding-linux-riscv64-musl': 0.119.0
+ '@oxc-parser/binding-linux-s390x-gnu': 0.119.0
+ '@oxc-parser/binding-linux-x64-gnu': 0.119.0
+ '@oxc-parser/binding-linux-x64-musl': 0.119.0
+ '@oxc-parser/binding-openharmony-arm64': 0.119.0
+ '@oxc-parser/binding-wasm32-wasi': 0.119.0
+ '@oxc-parser/binding-win32-arm64-msvc': 0.119.0
+ '@oxc-parser/binding-win32-ia32-msvc': 0.119.0
+ '@oxc-parser/binding-win32-x64-msvc': 0.119.0
+
+ oxc-walker@0.7.0(oxc-parser@0.119.0):
+ dependencies:
+ magic-regexp: 0.10.0
+ oxc-parser: 0.119.0
+
oxfmt@0.40.0:
dependencies:
tinypool: 2.1.0
@@ -2574,18 +4029,47 @@ snapshots:
package-manager-detector@1.6.0: {}
+ parent-module@1.0.1:
+ dependencies:
+ callsites: 3.1.0
+
+ parse-json@5.2.0:
+ dependencies:
+ '@babel/code-frame': 7.29.0
+ error-ex: 1.3.4
+ json-parse-even-better-errors: 2.3.1
+ lines-and-columns: 1.2.4
+
parse-ms@4.0.0: {}
path-key@3.1.1: {}
path-key@4.0.0: {}
+ path-parse@1.0.7: {}
+
+ path-type@4.0.0: {}
+
pathe@2.0.3: {}
picocolors@1.1.1: {}
picomatch@4.0.3: {}
+ pirates@4.0.7: {}
+
+ pkg-types@1.3.1:
+ dependencies:
+ confbox: 0.1.8
+ mlly: 1.8.0
+ pathe: 2.0.3
+
+ playwright-chromium@1.58.2:
+ dependencies:
+ playwright-core: 1.58.2
+
+ playwright-core@1.58.2: {}
+
postcss@8.5.8:
dependencies:
nanoid: 3.3.11
@@ -2610,8 +4094,27 @@ snapshots:
quansync@1.0.0: {}
+ react-dom@19.2.4(react@19.2.4):
+ dependencies:
+ react: 19.2.4
+ scheduler: 0.27.0
+
+ react-is@16.13.1: {}
+
+ react@19.2.4: {}
+
+ regexp-tree@0.1.27: {}
+
+ resolve-from@4.0.0: {}
+
resolve-pkg-maps@1.0.0: {}
+ resolve@1.22.11:
+ dependencies:
+ is-core-module: 2.16.1
+ path-parse: 1.0.7
+ supports-preserve-symlinks-flag: 1.0.0
+
rolldown-plugin-dts@0.22.5(@typescript/native-preview@7.0.0-dev.20260314.1)(rolldown@1.0.0-rc.9):
dependencies:
'@babel/generator': 8.0.0-rc.2
@@ -2629,6 +4132,12 @@ snapshots:
transitivePeerDependencies:
- oxc-resolver
+ rolldown-string@0.3.0(rolldown@1.0.0-rc.9):
+ dependencies:
+ magic-string: 0.30.21
+ optionalDependencies:
+ rolldown: 1.0.0-rc.9
+
rolldown@1.0.0-rc.9:
dependencies:
'@oxc-project/types': 0.115.0
@@ -2654,6 +4163,10 @@ snapshots:
dependencies:
mri: 1.2.0
+ scheduler@0.27.0: {}
+
+ semver@6.3.1: {}
+
semver@7.7.4: {}
shebang-command@2.0.0:
@@ -2668,8 +4181,12 @@ snapshots:
sisteransi@1.0.5: {}
+ smob@1.6.1: {}
+
source-map-js@1.2.1: {}
+ source-map@0.5.7: {}
+
source-map@0.6.1: {}
spdx-correct@3.2.0:
@@ -2694,6 +4211,10 @@ snapshots:
strip-final-newline@4.0.0: {}
+ stylis@4.2.0: {}
+
+ supports-preserve-symlinks-flag@1.0.0: {}
+
tinybench@2.9.0: {}
tinyexec@1.0.2: {}
@@ -2739,6 +4260,10 @@ snapshots:
tslib@2.8.1:
optional: true
+ type-level-regexp@0.1.17: {}
+
+ ufo@1.6.3: {}
+
uglify-js@3.19.3:
optional: true
@@ -2749,8 +4274,17 @@ snapshots:
undici-types@6.21.0: {}
+ undici-types@7.16.0: {}
+
unicorn-magic@0.3.0: {}
+ unplugin@2.3.11:
+ dependencies:
+ '@jridgewell/remapping': 2.3.5
+ acorn: 8.16.0
+ picomatch: 4.0.3
+ webpack-virtual-modules: 0.6.2
+
unrun@0.2.32:
dependencies:
rolldown: 1.0.0-rc.9
@@ -2779,10 +4313,23 @@ snapshots:
esbuild: 0.27.3
fsevents: 2.3.3
- vitest@4.1.0(@types/node@22.19.15)(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3)):
+ vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3):
+ dependencies:
+ '@oxc-project/runtime': 0.115.0
+ lightningcss: 1.32.0
+ picomatch: 4.0.3
+ postcss: 8.5.8
+ rolldown: 1.0.0-rc.9
+ tinyglobby: 0.2.15
+ optionalDependencies:
+ '@types/node': 24.12.0
+ esbuild: 0.27.3
+ fsevents: 2.3.3
+
+ vitest@4.1.0(@types/node@24.12.0)(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3)):
dependencies:
'@vitest/expect': 4.1.0
- '@vitest/mocker': 4.1.0(vite@8.0.0(@types/node@22.19.15)(esbuild@0.27.3))
+ '@vitest/mocker': 4.1.0(vite@8.0.0(@types/node@24.12.0)(esbuild@0.27.3))
'@vitest/pretty-format': 4.1.0
'@vitest/runner': 4.1.0
'@vitest/snapshot': 4.1.0
@@ -2799,15 +4346,17 @@ snapshots:
tinyexec: 1.0.2
tinyglobby: 0.2.15
tinyrainbow: 3.0.3
- vite: 8.0.0(@types/node@22.19.15)(esbuild@0.27.3)
+ vite: 8.0.0(@types/node@24.12.0)(esbuild@0.27.3)
why-is-node-running: 2.3.0
optionalDependencies:
- '@types/node': 22.19.15
+ '@types/node': 24.12.0
transitivePeerDependencies:
- msw
walk-up-path@4.0.0: {}
+ webpack-virtual-modules@0.6.2: {}
+
which@2.0.2:
dependencies:
isexe: 2.0.0
@@ -2819,4 +4368,8 @@ snapshots:
wordwrap@1.0.0: {}
+ yallist@3.1.1: {}
+
+ yaml@1.10.2: {}
+
yoctocolors@2.1.2: {}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
index 53f6789..751345b 100644
--- a/pnpm-workspace.yaml
+++ b/pnpm-workspace.yaml
@@ -1,5 +1,9 @@
packages:
- packages/*
+ - packages/*/benchmark
+ - internal-packages/*
+ - examples
+ - examples/*
- scripts
catalogs:
diff --git a/tsconfig.common.json b/tsconfig.common.json
new file mode 100644
index 0000000..7808718
--- /dev/null
+++ b/tsconfig.common.json
@@ -0,0 +1,16 @@
+{
+ "compilerOptions": {
+ "target": "esnext",
+ "module": "preserve",
+ "lib": ["es2023"],
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true,
+ "allowImportingTsExtensions": true,
+ "isolatedModules": true,
+ "declaration": true
+ },
+ "exclude": ["./examples"]
+}
diff --git a/tsconfig.json b/tsconfig.json
index bea07d8..b67e615 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,15 +1,4 @@
{
- "compilerOptions": {
- "target": "esnext",
- "module": "preserve",
- "lib": ["es2023"],
- "strict": true,
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "noEmit": true,
- "allowImportingTsExtensions": true,
- "isolatedModules": true,
- "declaration": true
- }
+ "references": [{ "path": "./tsconfig.common.json" }, { "path": "./examples/tsconfig.json" }],
+ "include": []
}
diff --git a/vitest.config.ts b/vitest.config.ts
index 45eba40..3d65014 100644
--- a/vitest.config.ts
+++ b/vitest.config.ts
@@ -2,6 +2,6 @@ import { defineConfig } from 'vitest/config'
export default defineConfig({
test: {
- projects: ['packages/*'],
+ projects: ['packages/*', 'packages/*/benchmark', 'internal-packages/*', './examples'],
},
})