├── .gitignore ├── .npmignore ├── .prettierrc ├── .vscode └── settings.json ├── LICENSE ├── README.md ├── examples ├── vite-react │ ├── .gitignore │ ├── .test-dev.test.ts │ ├── .test-preview.test.ts │ ├── .test-screenshot-fixture.png │ ├── .testCiJob.json │ ├── .testRun.ts │ ├── package-lock.json │ ├── package.json │ ├── pages │ │ ├── about │ │ │ └── index.page.jsx │ │ └── index │ │ │ ├── Counter.jsx │ │ │ ├── index.page.tsx │ │ │ └── some.js │ ├── readme.md │ ├── renderer │ │ ├── PageLayout.css │ │ ├── PageLayout.jsx │ │ ├── _default.page.client.jsx │ │ └── _default.page.server.jsx │ └── vite.config.js └── vite-solid │ ├── index.html │ ├── package-lock.json │ ├── package.json │ ├── pnpm-lock.yaml │ ├── src │ ├── App.tsx │ ├── CounterContext.tsx │ └── main.tsx │ ├── tsconfig.json │ └── vite.config.ts ├── media ├── autocomplete.png ├── gimmick.svg └── header.svg ├── package-lock.json ├── package.json ├── src ├── __tests__ │ ├── __snapshots__ │ │ └── index.test.js.snap │ ├── constant.js │ ├── index.test.js │ └── module.js ├── babel │ ├── cache.ts │ ├── eval.ts │ ├── module.ts │ ├── process.ts │ └── types.ts ├── index.ts ├── types.ts ├── utils │ ├── getFileIdx.ts │ ├── isBoxedPrimitive.ts │ ├── isSerializable.ts │ ├── numToChar.ts │ ├── stripLines.ts │ ├── throwIfInvalid.ts │ ├── toCSS.ts │ └── units.ts └── visitors │ └── taggedTemplateExpression.ts ├── tsconfig.json ├── vite-plugin.d.ts └── vite-plugin.js /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | 12 | # Runtime data 13 | pids 14 | *.pid 15 | *.seed 16 | *.pid.lock 17 | 18 | # Dependency directories 19 | node_modules/ 20 | 21 | # dotenv environment variables file 22 | .env 23 | .env.test 24 | 25 | # Next.js build output 26 | .next 27 | 28 | # Nuxt.js build / generate output 29 | .nuxt 30 | dist 31 | lib 32 | 33 | # Gatsby files 34 | .cache/ 35 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 36 | # https://nextjs.org/blog/next-9-1#public-directory-support 37 | # public 38 | 39 | # vuepress build output 40 | .vuepress/dist 41 | 42 | # cssed compilation artifacts 43 | .cssed 44 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .gitignore 2 | .vscode 3 | README.md 4 | src 5 | examples 6 | media 7 | tsconfig.json 8 | .eslintrc.js 9 | .eslintignore 10 | .prettierrc 11 | .yarn 12 | yarn.lock 13 | yarn-error.log 14 | .yarnrc.yml 15 | package-lock.json 16 | .cssed 17 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "none" 5 | } 6 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.tabSize": 2, 3 | "editor.defaultFormatter": "esbenp.prettier-vscode", 4 | "editor.formatOnSave": true, 5 | "editor.detectIndentation": false, 6 | "files.insertFinalNewline": true, 7 | "files.trimTrailingWhitespace": true, 8 | "editor.insertSpaces": true, 9 | "[markdown]": { 10 | "files.trimTrailingWhitespace": false 11 | }, 12 | "[typescript]": { 13 | "editor.formatOnSave": true, 14 | "editor.defaultFormatter": "esbenp.prettier-vscode" 15 | }, 16 | "[typescriptreact]": { 17 | "editor.formatOnSave": true 18 | }, 19 | "typescript.tsdk": "node_modules/typescript/lib" 20 | } 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Okotoki Software 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | cssed 2 | 3 | # cssed 4 | 5 | 🤷‍♂️ **CSS-in-JS modules** (via babel plugin): 6 | 7 | - lets you write CSS in JS, 8 | - plays nicely with Vite/NextJS/Webpack, 9 | - ⚡️ blazingly fast **zero-runtime** by accident 10 | - and **zero-configuration** by choice 11 | 12 | ## Rationale 13 | 14 | Why create another CSS-in-JS library? Well, I tried hard to avoid doing it, but couldn't find one which does what I want. And I don't want much: 15 | 16 | 1. Template literals syntax. 17 | 2. Write pure CSS/SASS/stylus but in JS. 18 | 3. Media queries and pseudoclasses support. 19 | 4. Seamless intergration with framework (~~NextJS~~Vite in my case). 20 | 21 | More on struggle finding existing solution [here](https://twitter.com/opudalo/status/1296793870697668612) 22 | 23 | ## Installation 24 | 25 | ```sh 26 | npm i cssed 27 | ``` 28 | 29 | ## Configuration 30 | 31 | ### With Vite 32 | 33 | `vite.config.js`: 34 | 35 | ```js 36 | import cssedVitePlugin from 'cssed/vite-plugin' 37 | 38 | export default { 39 | plugins: [ 40 | // ... 41 | cssedVitePlugin() 42 | // ... 43 | ] 44 | } 45 | ``` 46 | 47 | ### With webpack/next/babel 48 | 49 | No configuration required as long as you have enabled `module:cssed` in your `.babelrc`: 50 | 51 | ```json 52 | { 53 | "plugins": ["module:cssed"] 54 | } 55 | ``` 56 | 57 | Also, add compilation artifcats to `gitignore`: 58 | 59 | ```sh 60 | # cssed compilation artifacts 61 | .cssed 62 | ``` 63 | 64 | ## Usage 65 | 66 | ```jsx 67 | import { css } from 'cssed' 68 | import { dark, light } from './constants' 69 | 70 | const styles = css` 71 | .red { 72 | color: red; 73 | background: ${dark}; 74 | } 75 | 76 | .blue { 77 | color: blue; 78 | background: ${light}; 79 | } 80 | ` 81 | 82 | const Box = (props) => ( 83 |
84 | ) 85 | ``` 86 | 87 | That's it? That's it. 88 | 89 | ## How it works 90 | 91 | Babel plugin during compilation will extract content of `css` function call into a separate `.module.css` file and will place it in `.cssed` folder in the root of the project, rebasing URLs in `css`. 92 | 93 | Before: 94 | 95 | ```jsx 96 | // index.js – before compilation 97 | import { css } from 'cssed' 98 | const styles = css` 99 | .red { 100 | color: red; 101 | } 102 | ` 103 | 104 | const Box = (props) =>
105 | ``` 106 | 107 | After compilation with `cssed`: 108 | 109 | ```jsx 110 | // index.js – compiled with cssed 111 | import _a from '../.cssed/[hash].module.css' 112 | const styles = _a 113 | 114 | const Box = (props) =>
115 | ``` 116 | 117 | And file `[hash].module.css` contains extracted css: 118 | 119 | ```css 120 | /* [hash].module.css */ 121 | /* AUTO GENERATED FILE. DO NOT EDIT */ 122 | .red { 123 | color: red; 124 | } 125 | ``` 126 | 127 | From here Webpack will handle it as a regular file, which has imported CSS and will process it accordingly to configured pipeline. 128 | 129 | ## Syntax Highlight 130 | 131 | Same as for `styled-jsx` package. 132 | 133 | ### [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=blanu.vscode-styled-jsx) 134 | 135 | Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. 136 | 137 | ``` 138 | ext install vscode-styled-jsx 139 | ``` 140 | 141 | ### Autocomplete [Visual Studio Code Extension](https://marketplace.visualstudio.com/items?itemName=AndrewRazumovsky.vscode-styled-jsx-languageserver) 142 | 143 | Launch VS Code Quick Open (⌘+P), paste the following command, and press enter. 144 | 145 | ``` 146 | ext install vscode-styled-jsx-languageserver 147 | ``` 148 | 149 | Autocomplete 150 | 151 | ## Exmaples 152 | 153 | check `examples` for: 154 | 155 | - [vite-react](examples/vite-react) 156 | - [vite-solid](examples/vite-solid) 157 | 158 | ## Prior art 159 | 160 | This would not be possible, without [linaria](https://github.com/callstack/linaria). In fact inability to make it [work in NextJS](https://github.com/callstack/linaria/issues/667) pushed me over the line to create `cssed` 🙃. They did awesome job making evaluators for template literals. So you can write expressions like these: 161 | 162 | ```js 163 | import { light } from './theme' 164 | 165 | const cls = css` 166 | .some { 167 | color: ${light}; 168 | font-size: ${22 + 20}; 169 | } 170 | ` 171 | ``` 172 | 173 | Other notable projects: 174 | 175 | - [stylis.js](https://github.com/thysultan/stylis.js). Pretty much every CSS-in-JS project uses it for compilation. It is ultra fast and realiable, was considering using it, until idea with extracting css into file and letting bundler do all the hard lifting came to mind. 176 | - [css-zero](https://github.com/CraigCav/css-zero) was a good project to learn from. Craig added `atomic` layer to it, which is overkill for me. Also, syntax was not what I wanted: 177 | 178 | ```js 179 | // this will not generate `cls.red` and `cls.blue` you would expect 180 | const cls = css` 181 | .red { 182 | color: red; 183 | } 184 | .blue { 185 | color: blue; 186 | } 187 | ` 188 | ``` 189 | 190 | - [styled-jsx](https://github.com/vercel/styled-jsx) as with everything guys at Vercel do, it's tailored to awesome devx. Unfortunately, wasn't fit for my needs. This particular issue was super annoying ([codesandbox](https://codesandbox.io/s/mutable-wind-v04po?file=/pages/index.js)): 191 | 192 | ```jsx 193 | const Header = () => { 194 | // This will not be styled. It's frustrating as hell. 195 | const moreItems = ( 196 | <> 197 |
198 |
199 | 200 | ) 201 | 202 | return ( 203 | <> 204 |
205 | {moreItems} 206 | 213 | 214 | ) 215 | } 216 | ``` 217 | 218 | - [astroturf](https://github.com/4Catalyzer/astroturf/). Another awesome project to learn from. They went different direction and rely heavily on PostCSS. `css` api while what I need, didn't work in NextJS and also breaks when trying to use exported value like: 219 | 220 | ```js 221 | import { dark } from '../theme' 222 | 223 | // this will throw 224 | const styles = css` 225 | .red { 226 | border: 2px solid ${dark}; 227 | padding: 10px; 228 | } 229 | ` 230 | ``` 231 | 232 | - [csjs](https://github.com/rtsao/csjs) and [csstag](https://github.com/sgtpep/csstag). Two close to what I needed, gave up trying to make them work with NextJS. Also, additional setup required to make it zero-runtime. 👍to both for getting CSS syntax in JS. 233 | 234 | ## Gimmicks: 235 | 236 | CSSed is dead-simple CSS-in-JS implementation, without any gimmicks. Here is one if you need it:**[\*](https://en.wikipedia.org/wiki/ASCII_stereogram)** 237 | Can you read it? 🧐 238 | 239 | ## License 240 | 241 | MIT 242 | -------------------------------------------------------------------------------- /examples/vite-react/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules/ 2 | /dist/ 3 | -------------------------------------------------------------------------------- /examples/vite-react/.test-dev.test.ts: -------------------------------------------------------------------------------- 1 | import { testRun } from './.testRun' 2 | testRun('npm run dev') 3 | -------------------------------------------------------------------------------- /examples/vite-react/.test-preview.test.ts: -------------------------------------------------------------------------------- 1 | import { testRun } from './.testRun' 2 | testRun('npm run preview') 3 | -------------------------------------------------------------------------------- /examples/vite-react/.test-screenshot-fixture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okotoki/cssed/51951446f1cf0805f4f8b02838d0e34e1577bbec/examples/vite-react/.test-screenshot-fixture.png -------------------------------------------------------------------------------- /examples/vite-react/.testCiJob.json: -------------------------------------------------------------------------------- 1 | { "name": "Examples React" } 2 | -------------------------------------------------------------------------------- /examples/vite-react/.testRun.ts: -------------------------------------------------------------------------------- 1 | export { testRun } 2 | 3 | import { 4 | page, 5 | test, 6 | expect, 7 | run, 8 | partRegex, 9 | autoRetry, 10 | fetchHtml, 11 | getServerUrl, 12 | testScreenshotFixture 13 | } from '@brillout/test-e2e' 14 | import path from 'path' 15 | import url from 'url' 16 | import { createRequire } from 'module' 17 | 18 | function testRun(cmd: 'npm run dev' | 'npm run preview' | 'npm run prod') { 19 | run(cmd) 20 | 21 | test('page content is rendered to HTML', async () => { 22 | const html = await fetchHtml('/') 23 | expect(html).toContain('

Welcome

') 24 | expectHtmlCommon(html) 25 | }) 26 | 27 | test('page is rendered to the DOM and interactive', async () => { 28 | await page.goto(getServerUrl() + '/') 29 | await page.click('a[href="/"]') 30 | expect(await page.textContent('h1')).toBe('Welcome') 31 | expect(await page.textContent('button')).toBe('Counter 0') 32 | // `autoRetry` because browser-side code may not be loaded yet 33 | await autoRetry(async () => { 34 | await page.click('button') 35 | expect(await page.textContent('button')).toBe('Counter 1') 36 | }) 37 | }) 38 | 39 | test('screenshot fixture', async () => { 40 | { 41 | const { platform } = process 42 | if (!['linux', 'win32', 'darwin'].includes(platform)) 43 | throw new Error(`Unexpted platform operating system '${platform}'`) 44 | if (platform !== 'linux') return 45 | } 46 | { 47 | const dirname = path.dirname(url.fileURLToPath(import.meta.url)) 48 | // dirname isn't the directory of this file: because this file is bundled with the entry, e.g. dirname is the directory examples/react-17/ of the entry /examples/react-17/.test-dev.test.ts 49 | const repoRoot = path.join(dirname, `../../`) 50 | const screenshotFixturePathUnresolved = path.join(repoRoot, 'examples/react/.test-screenshot-fixture.png') 51 | const require = createRequire(import.meta.url) 52 | let screenshotFixturePath: string 53 | try { 54 | screenshotFixturePath = require.resolve(screenshotFixturePathUnresolved) 55 | } catch (err) { 56 | console.log('dirname:', dirname) 57 | console.log('repoRoot:', repoRoot) 58 | console.log('screenshotFixturePathUnresolved:', screenshotFixturePathUnresolved) 59 | throw err 60 | } 61 | await testScreenshotFixture({ screenshotFixturePath }) 62 | } 63 | }) 64 | 65 | test('about page', async () => { 66 | await page.click('a[href="/about"]') 67 | await autoRetry(async () => { 68 | expect(await page.textContent('h1')).toBe('About') 69 | }) 70 | expect(await page.textContent('p')).toBe('Example of using VPS.') 71 | const html = await fetchHtml('/about') 72 | expect(html).toContain('

About

') 73 | expectHtmlCommon(html) 74 | }) 75 | } 76 | 77 | function expectHtmlCommon(html: string) { 78 | // Vue injects: `!--[-->Home` 79 | expect(html).toMatch(partRegex`]+/}>${/.*/}Home${/[.\s]*/}`) 80 | expect(html).toMatch(partRegex`]+/}>${/.*/}About${/[.\s]*/}`) 81 | expect(html).toContain(' 8 |

About

9 |

Example of using VPS.

10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /examples/vite-react/pages/index/Counter.jsx: -------------------------------------------------------------------------------- 1 | export { Counter } 2 | 3 | import React, { useState } from 'react' 4 | 5 | function Counter() { 6 | const [count, setCount] = useState(0) 7 | return ( 8 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /examples/vite-react/pages/index/index.page.tsx: -------------------------------------------------------------------------------- 1 | export { Page } 2 | 3 | import { css } from 'cssed' 4 | import React from 'react' 5 | import { Counter } from './Counter' 6 | import { red } from './some' 7 | 8 | const a = (some: any) => '' 9 | const styles: any = css` 10 | .red { 11 | ${a('')} 12 | color: ${red}; 13 | } 14 | ` 15 | 16 | function Page() { 17 | return ( 18 | <> 19 |

Welcome

20 | This page is: 21 | 27 | 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /examples/vite-react/pages/index/some.js: -------------------------------------------------------------------------------- 1 | export const red = 'red' 2 | -------------------------------------------------------------------------------- /examples/vite-react/readme.md: -------------------------------------------------------------------------------- 1 | Example of using `vite-plugin-ssr` with React. 2 | 3 | ```bash 4 | git clone git@github.com:brillout/vite-plugin-ssr 5 | cd vite-plugin-ssr/examples/react/ 6 | npm install 7 | npm run dev 8 | ``` 9 | -------------------------------------------------------------------------------- /examples/vite-react/renderer/PageLayout.css: -------------------------------------------------------------------------------- 1 | /* This CSS is common to all pages */ 2 | 3 | body { 4 | margin: 0; 5 | font-family: sans-serif; 6 | } 7 | * { 8 | box-sizing: border-box; 9 | } 10 | a { 11 | text-decoration: none; 12 | } 13 | 14 | .navitem { 15 | padding: 3px; 16 | } 17 | -------------------------------------------------------------------------------- /examples/vite-react/renderer/PageLayout.jsx: -------------------------------------------------------------------------------- 1 | export { PageLayout } 2 | 3 | import React from 'react' 4 | import './PageLayout.css' 5 | 6 | function PageLayout({ children }) { 7 | return ( 8 | 9 | 10 | 11 | 12 | Home 13 | 14 | 15 | About 16 | 17 | 18 | {children} 19 | 20 | 21 | ) 22 | } 23 | 24 | function Layout({ children }) { 25 | return ( 26 |
33 | {children} 34 |
35 | ) 36 | } 37 | 38 | function Sidebar({ children }) { 39 | return ( 40 |
51 | {children} 52 |
53 | ) 54 | } 55 | 56 | function Content({ children }) { 57 | return ( 58 |
66 | {children} 67 |
68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /examples/vite-react/renderer/_default.page.client.jsx: -------------------------------------------------------------------------------- 1 | export { render } 2 | 3 | import React from 'react' 4 | import { hydrateRoot } from 'react-dom/client' 5 | import { PageLayout } from './PageLayout' 6 | 7 | async function render(pageContext) { 8 | const { Page } = pageContext 9 | hydrateRoot( 10 | document.getElementById('page-view'), 11 | 12 | 13 | 14 | ) 15 | } 16 | -------------------------------------------------------------------------------- /examples/vite-react/renderer/_default.page.server.jsx: -------------------------------------------------------------------------------- 1 | export { render } 2 | 3 | import React from 'react' 4 | import { renderToString } from 'react-dom/server' 5 | import { escapeInject, dangerouslySkipEscape } from 'vite-plugin-ssr/server' 6 | import { PageLayout } from './PageLayout' 7 | 8 | async function render(pageContext) { 9 | const { Page } = pageContext 10 | const viewHtml = dangerouslySkipEscape( 11 | renderToString( 12 | 13 | 14 | 15 | ) 16 | ) 17 | 18 | return escapeInject` 19 | 20 | 21 |
${viewHtml}
22 | 23 | ` 24 | } 25 | -------------------------------------------------------------------------------- /examples/vite-react/vite.config.js: -------------------------------------------------------------------------------- 1 | import react from '@vitejs/plugin-react' 2 | import ssr from 'vite-plugin-ssr/plugin' 3 | import cssedVitePlugin from 'cssed/vite-plugin' 4 | 5 | export default { 6 | plugins: [cssedVitePlugin(), react(), ssr()] 7 | } 8 | -------------------------------------------------------------------------------- /examples/vite-solid/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /examples/vite-solid/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "lockfileVersion": 3, 4 | "requires": true, 5 | "packages": { 6 | "": { 7 | "name": "example", 8 | "dependencies": { 9 | "cssed": "^3.0.6", 10 | "solid-js": "^1.4.10", 11 | "vite-plugin-solid": "^2.7.0" 12 | }, 13 | "devDependencies": { 14 | "vite": "^4.1.1" 15 | } 16 | }, 17 | "node_modules/@ampproject/remapping": { 18 | "version": "2.2.1", 19 | "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", 20 | "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", 21 | "dependencies": { 22 | "@jridgewell/gen-mapping": "^0.3.0", 23 | "@jridgewell/trace-mapping": "^0.3.9" 24 | }, 25 | "engines": { 26 | "node": ">=6.0.0" 27 | } 28 | }, 29 | "node_modules/@babel/code-frame": { 30 | "version": "7.21.4", 31 | "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", 32 | "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", 33 | "dependencies": { 34 | "@babel/highlight": "^7.18.6" 35 | }, 36 | "engines": { 37 | "node": ">=6.9.0" 38 | } 39 | }, 40 | "node_modules/@babel/compat-data": { 41 | "version": "7.22.3", 42 | "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.3.tgz", 43 | "integrity": "sha512-aNtko9OPOwVESUFp3MZfD8Uzxl7JzSeJpd7npIoxCasU37PFbAQRpKglkaKwlHOyeJdrREpo8TW8ldrkYWwvIQ==", 44 | "engines": { 45 | "node": ">=6.9.0" 46 | } 47 | }, 48 | "node_modules/@babel/core": { 49 | "version": "7.22.1", 50 | "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.22.1.tgz", 51 | "integrity": "sha512-Hkqu7J4ynysSXxmAahpN1jjRwVJ+NdpraFLIWflgjpVob3KNyK3/tIUc7Q7szed8WMp0JNa7Qtd1E9Oo22F9gA==", 52 | "dependencies": { 53 | "@ampproject/remapping": "^2.2.0", 54 | "@babel/code-frame": "^7.21.4", 55 | "@babel/generator": "^7.22.0", 56 | "@babel/helper-compilation-targets": "^7.22.1", 57 | "@babel/helper-module-transforms": "^7.22.1", 58 | "@babel/helpers": "^7.22.0", 59 | "@babel/parser": "^7.22.0", 60 | "@babel/template": "^7.21.9", 61 | "@babel/traverse": "^7.22.1", 62 | "@babel/types": "^7.22.0", 63 | "convert-source-map": "^1.7.0", 64 | "debug": "^4.1.0", 65 | "gensync": "^1.0.0-beta.2", 66 | "json5": "^2.2.2", 67 | "semver": "^6.3.0" 68 | }, 69 | "engines": { 70 | "node": ">=6.9.0" 71 | }, 72 | "funding": { 73 | "type": "opencollective", 74 | "url": "https://opencollective.com/babel" 75 | } 76 | }, 77 | "node_modules/@babel/generator": { 78 | "version": "7.22.3", 79 | "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.22.3.tgz", 80 | "integrity": "sha512-C17MW4wlk//ES/CJDL51kPNwl+qiBQyN7b9SKyVp11BLGFeSPoVaHrv+MNt8jwQFhQWowW88z1eeBx3pFz9v8A==", 81 | "dependencies": { 82 | "@babel/types": "^7.22.3", 83 | "@jridgewell/gen-mapping": "^0.3.2", 84 | "@jridgewell/trace-mapping": "^0.3.17", 85 | "jsesc": "^2.5.1" 86 | }, 87 | "engines": { 88 | "node": ">=6.9.0" 89 | } 90 | }, 91 | "node_modules/@babel/helper-annotate-as-pure": { 92 | "version": "7.18.6", 93 | "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz", 94 | "integrity": "sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==", 95 | "dependencies": { 96 | "@babel/types": "^7.18.6" 97 | }, 98 | "engines": { 99 | "node": ">=6.9.0" 100 | } 101 | }, 102 | "node_modules/@babel/helper-compilation-targets": { 103 | "version": "7.22.1", 104 | "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.22.1.tgz", 105 | "integrity": "sha512-Rqx13UM3yVB5q0D/KwQ8+SPfX/+Rnsy1Lw1k/UwOC4KC6qrzIQoY3lYnBu5EHKBlEHHcj0M0W8ltPSkD8rqfsQ==", 106 | "dependencies": { 107 | "@babel/compat-data": "^7.22.0", 108 | "@babel/helper-validator-option": "^7.21.0", 109 | "browserslist": "^4.21.3", 110 | "lru-cache": "^5.1.1", 111 | "semver": "^6.3.0" 112 | }, 113 | "engines": { 114 | "node": ">=6.9.0" 115 | }, 116 | "peerDependencies": { 117 | "@babel/core": "^7.0.0" 118 | } 119 | }, 120 | "node_modules/@babel/helper-create-class-features-plugin": { 121 | "version": "7.22.1", 122 | "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.22.1.tgz", 123 | "integrity": "sha512-SowrZ9BWzYFgzUMwUmowbPSGu6CXL5MSuuCkG3bejahSpSymioPmuLdhPxNOc9MjuNGjy7M/HaXvJ8G82Lywlw==", 124 | "dependencies": { 125 | "@babel/helper-annotate-as-pure": "^7.18.6", 126 | "@babel/helper-environment-visitor": "^7.22.1", 127 | "@babel/helper-function-name": "^7.21.0", 128 | "@babel/helper-member-expression-to-functions": "^7.22.0", 129 | "@babel/helper-optimise-call-expression": "^7.18.6", 130 | "@babel/helper-replace-supers": "^7.22.1", 131 | "@babel/helper-skip-transparent-expression-wrappers": "^7.20.0", 132 | "@babel/helper-split-export-declaration": "^7.18.6", 133 | "semver": "^6.3.0" 134 | }, 135 | "engines": { 136 | "node": ">=6.9.0" 137 | }, 138 | "peerDependencies": { 139 | "@babel/core": "^7.0.0" 140 | } 141 | }, 142 | "node_modules/@babel/helper-environment-visitor": { 143 | "version": "7.22.1", 144 | "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.1.tgz", 145 | "integrity": "sha512-Z2tgopurB/kTbidvzeBrc2To3PUP/9i5MUe+fU6QJCQDyPwSH2oRapkLw3KGECDYSjhQZCNxEvNvZlLw8JjGwA==", 146 | "engines": { 147 | "node": ">=6.9.0" 148 | } 149 | }, 150 | "node_modules/@babel/helper-function-name": { 151 | "version": "7.21.0", 152 | "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", 153 | "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", 154 | "dependencies": { 155 | "@babel/template": "^7.20.7", 156 | "@babel/types": "^7.21.0" 157 | }, 158 | "engines": { 159 | "node": ">=6.9.0" 160 | } 161 | }, 162 | "node_modules/@babel/helper-hoist-variables": { 163 | "version": "7.18.6", 164 | "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", 165 | "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", 166 | "dependencies": { 167 | "@babel/types": "^7.18.6" 168 | }, 169 | "engines": { 170 | "node": ">=6.9.0" 171 | } 172 | }, 173 | "node_modules/@babel/helper-member-expression-to-functions": { 174 | "version": "7.22.3", 175 | "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.22.3.tgz", 176 | "integrity": "sha512-Gl7sK04b/2WOb6OPVeNy9eFKeD3L6++CzL3ykPOWqTn08xgYYK0wz4TUh2feIImDXxcVW3/9WQ1NMKY66/jfZA==", 177 | "dependencies": { 178 | "@babel/types": "^7.22.3" 179 | }, 180 | "engines": { 181 | "node": ">=6.9.0" 182 | } 183 | }, 184 | "node_modules/@babel/helper-module-imports": { 185 | "version": "7.21.4", 186 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz", 187 | "integrity": "sha512-orajc5T2PsRYUN3ZryCEFeMDYwyw09c/pZeaQEZPH0MpKzSvn3e0uXsDBu3k03VI+9DBiRo+l22BfKTpKwa/Wg==", 188 | "dependencies": { 189 | "@babel/types": "^7.21.4" 190 | }, 191 | "engines": { 192 | "node": ">=6.9.0" 193 | } 194 | }, 195 | "node_modules/@babel/helper-module-transforms": { 196 | "version": "7.22.1", 197 | "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.22.1.tgz", 198 | "integrity": "sha512-dxAe9E7ySDGbQdCVOY/4+UcD8M9ZFqZcZhSPsPacvCG4M+9lwtDDQfI2EoaSvmf7W/8yCBkGU0m7Pvt1ru3UZw==", 199 | "dependencies": { 200 | "@babel/helper-environment-visitor": "^7.22.1", 201 | "@babel/helper-module-imports": "^7.21.4", 202 | "@babel/helper-simple-access": "^7.21.5", 203 | "@babel/helper-split-export-declaration": "^7.18.6", 204 | "@babel/helper-validator-identifier": "^7.19.1", 205 | "@babel/template": "^7.21.9", 206 | "@babel/traverse": "^7.22.1", 207 | "@babel/types": "^7.22.0" 208 | }, 209 | "engines": { 210 | "node": ">=6.9.0" 211 | } 212 | }, 213 | "node_modules/@babel/helper-optimise-call-expression": { 214 | "version": "7.18.6", 215 | "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz", 216 | "integrity": "sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==", 217 | "dependencies": { 218 | "@babel/types": "^7.18.6" 219 | }, 220 | "engines": { 221 | "node": ">=6.9.0" 222 | } 223 | }, 224 | "node_modules/@babel/helper-plugin-utils": { 225 | "version": "7.21.5", 226 | "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz", 227 | "integrity": "sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg==", 228 | "engines": { 229 | "node": ">=6.9.0" 230 | } 231 | }, 232 | "node_modules/@babel/helper-replace-supers": { 233 | "version": "7.22.1", 234 | "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.1.tgz", 235 | "integrity": "sha512-ut4qrkE4AuSfrwHSps51ekR1ZY/ygrP1tp0WFm8oVq6nzc/hvfV/22JylndIbsf2U2M9LOMwiSddr6y+78j+OQ==", 236 | "dependencies": { 237 | "@babel/helper-environment-visitor": "^7.22.1", 238 | "@babel/helper-member-expression-to-functions": "^7.22.0", 239 | "@babel/helper-optimise-call-expression": "^7.18.6", 240 | "@babel/template": "^7.21.9", 241 | "@babel/traverse": "^7.22.1", 242 | "@babel/types": "^7.22.0" 243 | }, 244 | "engines": { 245 | "node": ">=6.9.0" 246 | } 247 | }, 248 | "node_modules/@babel/helper-simple-access": { 249 | "version": "7.21.5", 250 | "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.21.5.tgz", 251 | "integrity": "sha512-ENPDAMC1wAjR0uaCUwliBdiSl1KBJAVnMTzXqi64c2MG8MPR6ii4qf7bSXDqSFbr4W6W028/rf5ivoHop5/mkg==", 252 | "dependencies": { 253 | "@babel/types": "^7.21.5" 254 | }, 255 | "engines": { 256 | "node": ">=6.9.0" 257 | } 258 | }, 259 | "node_modules/@babel/helper-skip-transparent-expression-wrappers": { 260 | "version": "7.20.0", 261 | "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.20.0.tgz", 262 | "integrity": "sha512-5y1JYeNKfvnT8sZcK9DVRtpTbGiomYIHviSP3OQWmDPU3DeH4a1ZlT/N2lyQ5P8egjcRaT/Y9aNqUxK0WsnIIg==", 263 | "dependencies": { 264 | "@babel/types": "^7.20.0" 265 | }, 266 | "engines": { 267 | "node": ">=6.9.0" 268 | } 269 | }, 270 | "node_modules/@babel/helper-split-export-declaration": { 271 | "version": "7.18.6", 272 | "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", 273 | "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", 274 | "dependencies": { 275 | "@babel/types": "^7.18.6" 276 | }, 277 | "engines": { 278 | "node": ">=6.9.0" 279 | } 280 | }, 281 | "node_modules/@babel/helper-string-parser": { 282 | "version": "7.21.5", 283 | "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.21.5.tgz", 284 | "integrity": "sha512-5pTUx3hAJaZIdW99sJ6ZUUgWq/Y+Hja7TowEnLNMm1VivRgZQL3vpBY3qUACVsvw+yQU6+YgfBVmcbLaZtrA1w==", 285 | "engines": { 286 | "node": ">=6.9.0" 287 | } 288 | }, 289 | "node_modules/@babel/helper-validator-identifier": { 290 | "version": "7.19.1", 291 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", 292 | "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", 293 | "engines": { 294 | "node": ">=6.9.0" 295 | } 296 | }, 297 | "node_modules/@babel/helper-validator-option": { 298 | "version": "7.21.0", 299 | "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz", 300 | "integrity": "sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ==", 301 | "engines": { 302 | "node": ">=6.9.0" 303 | } 304 | }, 305 | "node_modules/@babel/helpers": { 306 | "version": "7.22.3", 307 | "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.3.tgz", 308 | "integrity": "sha512-jBJ7jWblbgr7r6wYZHMdIqKc73ycaTcCaWRq4/2LpuPHcx7xMlZvpGQkOYc9HeSjn6rcx15CPlgVcBtZ4WZJ2w==", 309 | "dependencies": { 310 | "@babel/template": "^7.21.9", 311 | "@babel/traverse": "^7.22.1", 312 | "@babel/types": "^7.22.3" 313 | }, 314 | "engines": { 315 | "node": ">=6.9.0" 316 | } 317 | }, 318 | "node_modules/@babel/highlight": { 319 | "version": "7.18.6", 320 | "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", 321 | "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", 322 | "dependencies": { 323 | "@babel/helper-validator-identifier": "^7.18.6", 324 | "chalk": "^2.0.0", 325 | "js-tokens": "^4.0.0" 326 | }, 327 | "engines": { 328 | "node": ">=6.9.0" 329 | } 330 | }, 331 | "node_modules/@babel/parser": { 332 | "version": "7.22.4", 333 | "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.22.4.tgz", 334 | "integrity": "sha512-VLLsx06XkEYqBtE5YGPwfSGwfrjnyPP5oiGty3S8pQLFDFLaS8VwWSIxkTXpcvr5zeYLE6+MBNl2npl/YnfofA==", 335 | "bin": { 336 | "parser": "bin/babel-parser.js" 337 | }, 338 | "engines": { 339 | "node": ">=6.0.0" 340 | } 341 | }, 342 | "node_modules/@babel/plugin-syntax-jsx": { 343 | "version": "7.21.4", 344 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", 345 | "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", 346 | "dependencies": { 347 | "@babel/helper-plugin-utils": "^7.20.2" 348 | }, 349 | "engines": { 350 | "node": ">=6.9.0" 351 | }, 352 | "peerDependencies": { 353 | "@babel/core": "^7.0.0-0" 354 | } 355 | }, 356 | "node_modules/@babel/plugin-syntax-typescript": { 357 | "version": "7.21.4", 358 | "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", 359 | "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", 360 | "dependencies": { 361 | "@babel/helper-plugin-utils": "^7.20.2" 362 | }, 363 | "engines": { 364 | "node": ">=6.9.0" 365 | }, 366 | "peerDependencies": { 367 | "@babel/core": "^7.0.0-0" 368 | } 369 | }, 370 | "node_modules/@babel/plugin-transform-modules-commonjs": { 371 | "version": "7.21.5", 372 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.21.5.tgz", 373 | "integrity": "sha512-OVryBEgKUbtqMoB7eG2rs6UFexJi6Zj6FDXx+esBLPTCxCNxAY9o+8Di7IsUGJ+AVhp5ncK0fxWUBd0/1gPhrQ==", 374 | "dependencies": { 375 | "@babel/helper-module-transforms": "^7.21.5", 376 | "@babel/helper-plugin-utils": "^7.21.5", 377 | "@babel/helper-simple-access": "^7.21.5" 378 | }, 379 | "engines": { 380 | "node": ">=6.9.0" 381 | }, 382 | "peerDependencies": { 383 | "@babel/core": "^7.0.0-0" 384 | } 385 | }, 386 | "node_modules/@babel/plugin-transform-typescript": { 387 | "version": "7.22.3", 388 | "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.22.3.tgz", 389 | "integrity": "sha512-pyjnCIniO5PNaEuGxT28h0HbMru3qCVrMqVgVOz/krComdIrY9W6FCLBq9NWHY8HDGaUlan+UhmZElDENIfCcw==", 390 | "dependencies": { 391 | "@babel/helper-annotate-as-pure": "^7.18.6", 392 | "@babel/helper-create-class-features-plugin": "^7.22.1", 393 | "@babel/helper-plugin-utils": "^7.21.5", 394 | "@babel/plugin-syntax-typescript": "^7.21.4" 395 | }, 396 | "engines": { 397 | "node": ">=6.9.0" 398 | }, 399 | "peerDependencies": { 400 | "@babel/core": "^7.0.0-0" 401 | } 402 | }, 403 | "node_modules/@babel/preset-typescript": { 404 | "version": "7.21.5", 405 | "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.21.5.tgz", 406 | "integrity": "sha512-iqe3sETat5EOrORXiQ6rWfoOg2y68Cs75B9wNxdPW4kixJxh7aXQE1KPdWLDniC24T/6dSnguF33W9j/ZZQcmA==", 407 | "dependencies": { 408 | "@babel/helper-plugin-utils": "^7.21.5", 409 | "@babel/helper-validator-option": "^7.21.0", 410 | "@babel/plugin-syntax-jsx": "^7.21.4", 411 | "@babel/plugin-transform-modules-commonjs": "^7.21.5", 412 | "@babel/plugin-transform-typescript": "^7.21.3" 413 | }, 414 | "engines": { 415 | "node": ">=6.9.0" 416 | }, 417 | "peerDependencies": { 418 | "@babel/core": "^7.0.0-0" 419 | } 420 | }, 421 | "node_modules/@babel/template": { 422 | "version": "7.21.9", 423 | "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.21.9.tgz", 424 | "integrity": "sha512-MK0X5k8NKOuWRamiEfc3KEJiHMTkGZNUjzMipqCGDDc6ijRl/B7RGSKVGncu4Ro/HdyzzY6cmoXuKI2Gffk7vQ==", 425 | "dependencies": { 426 | "@babel/code-frame": "^7.21.4", 427 | "@babel/parser": "^7.21.9", 428 | "@babel/types": "^7.21.5" 429 | }, 430 | "engines": { 431 | "node": ">=6.9.0" 432 | } 433 | }, 434 | "node_modules/@babel/traverse": { 435 | "version": "7.22.4", 436 | "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.22.4.tgz", 437 | "integrity": "sha512-Tn1pDsjIcI+JcLKq1AVlZEr4226gpuAQTsLMorsYg9tuS/kG7nuwwJ4AB8jfQuEgb/COBwR/DqJxmoiYFu5/rQ==", 438 | "dependencies": { 439 | "@babel/code-frame": "^7.21.4", 440 | "@babel/generator": "^7.22.3", 441 | "@babel/helper-environment-visitor": "^7.22.1", 442 | "@babel/helper-function-name": "^7.21.0", 443 | "@babel/helper-hoist-variables": "^7.18.6", 444 | "@babel/helper-split-export-declaration": "^7.18.6", 445 | "@babel/parser": "^7.22.4", 446 | "@babel/types": "^7.22.4", 447 | "debug": "^4.1.0", 448 | "globals": "^11.1.0" 449 | }, 450 | "engines": { 451 | "node": ">=6.9.0" 452 | } 453 | }, 454 | "node_modules/@babel/types": { 455 | "version": "7.22.4", 456 | "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.22.4.tgz", 457 | "integrity": "sha512-Tx9x3UBHTTsMSW85WB2kphxYQVvrZ/t1FxD88IpSgIjiUJlCm9z+xWIDwyo1vffTwSqteqyznB8ZE9vYYk16zA==", 458 | "dependencies": { 459 | "@babel/helper-string-parser": "^7.21.5", 460 | "@babel/helper-validator-identifier": "^7.19.1", 461 | "to-fast-properties": "^2.0.0" 462 | }, 463 | "engines": { 464 | "node": ">=6.9.0" 465 | } 466 | }, 467 | "node_modules/@esbuild/android-arm": { 468 | "version": "0.17.19", 469 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.19.tgz", 470 | "integrity": "sha512-rIKddzqhmav7MSmoFCmDIb6e2W57geRsM94gV2l38fzhXMwq7hZoClug9USI2pFRGL06f4IOPHHpFNOkWieR8A==", 471 | "cpu": [ 472 | "arm" 473 | ], 474 | "optional": true, 475 | "os": [ 476 | "android" 477 | ], 478 | "engines": { 479 | "node": ">=12" 480 | } 481 | }, 482 | "node_modules/@esbuild/android-arm64": { 483 | "version": "0.17.19", 484 | "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.19.tgz", 485 | "integrity": "sha512-KBMWvEZooR7+kzY0BtbTQn0OAYY7CsiydT63pVEaPtVYF0hXbUaOyZog37DKxK7NF3XacBJOpYT4adIJh+avxA==", 486 | "cpu": [ 487 | "arm64" 488 | ], 489 | "optional": true, 490 | "os": [ 491 | "android" 492 | ], 493 | "engines": { 494 | "node": ">=12" 495 | } 496 | }, 497 | "node_modules/@esbuild/android-x64": { 498 | "version": "0.17.19", 499 | "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.19.tgz", 500 | "integrity": "sha512-uUTTc4xGNDT7YSArp/zbtmbhO0uEEK9/ETW29Wk1thYUJBz3IVnvgEiEwEa9IeLyvnpKrWK64Utw2bgUmDveww==", 501 | "cpu": [ 502 | "x64" 503 | ], 504 | "optional": true, 505 | "os": [ 506 | "android" 507 | ], 508 | "engines": { 509 | "node": ">=12" 510 | } 511 | }, 512 | "node_modules/@esbuild/darwin-arm64": { 513 | "version": "0.17.19", 514 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.19.tgz", 515 | "integrity": "sha512-80wEoCfF/hFKM6WE1FyBHc9SfUblloAWx6FJkFWTWiCoht9Mc0ARGEM47e67W9rI09YoUxJL68WHfDRYEAvOhg==", 516 | "cpu": [ 517 | "arm64" 518 | ], 519 | "optional": true, 520 | "os": [ 521 | "darwin" 522 | ], 523 | "engines": { 524 | "node": ">=12" 525 | } 526 | }, 527 | "node_modules/@esbuild/darwin-x64": { 528 | "version": "0.17.19", 529 | "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.19.tgz", 530 | "integrity": "sha512-IJM4JJsLhRYr9xdtLytPLSH9k/oxR3boaUIYiHkAawtwNOXKE8KoU8tMvryogdcT8AU+Bflmh81Xn6Q0vTZbQw==", 531 | "cpu": [ 532 | "x64" 533 | ], 534 | "optional": true, 535 | "os": [ 536 | "darwin" 537 | ], 538 | "engines": { 539 | "node": ">=12" 540 | } 541 | }, 542 | "node_modules/@esbuild/freebsd-arm64": { 543 | "version": "0.17.19", 544 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.19.tgz", 545 | "integrity": "sha512-pBwbc7DufluUeGdjSU5Si+P3SoMF5DQ/F/UmTSb8HXO80ZEAJmrykPyzo1IfNbAoaqw48YRpv8shwd1NoI0jcQ==", 546 | "cpu": [ 547 | "arm64" 548 | ], 549 | "optional": true, 550 | "os": [ 551 | "freebsd" 552 | ], 553 | "engines": { 554 | "node": ">=12" 555 | } 556 | }, 557 | "node_modules/@esbuild/freebsd-x64": { 558 | "version": "0.17.19", 559 | "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.19.tgz", 560 | "integrity": "sha512-4lu+n8Wk0XlajEhbEffdy2xy53dpR06SlzvhGByyg36qJw6Kpfk7cp45DR/62aPH9mtJRmIyrXAS5UWBrJT6TQ==", 561 | "cpu": [ 562 | "x64" 563 | ], 564 | "optional": true, 565 | "os": [ 566 | "freebsd" 567 | ], 568 | "engines": { 569 | "node": ">=12" 570 | } 571 | }, 572 | "node_modules/@esbuild/linux-arm": { 573 | "version": "0.17.19", 574 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.19.tgz", 575 | "integrity": "sha512-cdmT3KxjlOQ/gZ2cjfrQOtmhG4HJs6hhvm3mWSRDPtZ/lP5oe8FWceS10JaSJC13GBd4eH/haHnqf7hhGNLerA==", 576 | "cpu": [ 577 | "arm" 578 | ], 579 | "optional": true, 580 | "os": [ 581 | "linux" 582 | ], 583 | "engines": { 584 | "node": ">=12" 585 | } 586 | }, 587 | "node_modules/@esbuild/linux-arm64": { 588 | "version": "0.17.19", 589 | "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.19.tgz", 590 | "integrity": "sha512-ct1Tg3WGwd3P+oZYqic+YZF4snNl2bsnMKRkb3ozHmnM0dGWuxcPTTntAF6bOP0Sp4x0PjSF+4uHQ1xvxfRKqg==", 591 | "cpu": [ 592 | "arm64" 593 | ], 594 | "optional": true, 595 | "os": [ 596 | "linux" 597 | ], 598 | "engines": { 599 | "node": ">=12" 600 | } 601 | }, 602 | "node_modules/@esbuild/linux-ia32": { 603 | "version": "0.17.19", 604 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.19.tgz", 605 | "integrity": "sha512-w4IRhSy1VbsNxHRQpeGCHEmibqdTUx61Vc38APcsRbuVgK0OPEnQ0YD39Brymn96mOx48Y2laBQGqgZ0j9w6SQ==", 606 | "cpu": [ 607 | "ia32" 608 | ], 609 | "optional": true, 610 | "os": [ 611 | "linux" 612 | ], 613 | "engines": { 614 | "node": ">=12" 615 | } 616 | }, 617 | "node_modules/@esbuild/linux-loong64": { 618 | "version": "0.17.19", 619 | "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.19.tgz", 620 | "integrity": "sha512-2iAngUbBPMq439a+z//gE+9WBldoMp1s5GWsUSgqHLzLJ9WoZLZhpwWuym0u0u/4XmZ3gpHmzV84PonE+9IIdQ==", 621 | "cpu": [ 622 | "loong64" 623 | ], 624 | "optional": true, 625 | "os": [ 626 | "linux" 627 | ], 628 | "engines": { 629 | "node": ">=12" 630 | } 631 | }, 632 | "node_modules/@esbuild/linux-mips64el": { 633 | "version": "0.17.19", 634 | "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.19.tgz", 635 | "integrity": "sha512-LKJltc4LVdMKHsrFe4MGNPp0hqDFA1Wpt3jE1gEyM3nKUvOiO//9PheZZHfYRfYl6AwdTH4aTcXSqBerX0ml4A==", 636 | "cpu": [ 637 | "mips64el" 638 | ], 639 | "optional": true, 640 | "os": [ 641 | "linux" 642 | ], 643 | "engines": { 644 | "node": ">=12" 645 | } 646 | }, 647 | "node_modules/@esbuild/linux-ppc64": { 648 | "version": "0.17.19", 649 | "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.19.tgz", 650 | "integrity": "sha512-/c/DGybs95WXNS8y3Ti/ytqETiW7EU44MEKuCAcpPto3YjQbyK3IQVKfF6nbghD7EcLUGl0NbiL5Rt5DMhn5tg==", 651 | "cpu": [ 652 | "ppc64" 653 | ], 654 | "optional": true, 655 | "os": [ 656 | "linux" 657 | ], 658 | "engines": { 659 | "node": ">=12" 660 | } 661 | }, 662 | "node_modules/@esbuild/linux-riscv64": { 663 | "version": "0.17.19", 664 | "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.19.tgz", 665 | "integrity": "sha512-FC3nUAWhvFoutlhAkgHf8f5HwFWUL6bYdvLc/TTuxKlvLi3+pPzdZiFKSWz/PF30TB1K19SuCxDTI5KcqASJqA==", 666 | "cpu": [ 667 | "riscv64" 668 | ], 669 | "optional": true, 670 | "os": [ 671 | "linux" 672 | ], 673 | "engines": { 674 | "node": ">=12" 675 | } 676 | }, 677 | "node_modules/@esbuild/linux-s390x": { 678 | "version": "0.17.19", 679 | "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.19.tgz", 680 | "integrity": "sha512-IbFsFbxMWLuKEbH+7sTkKzL6NJmG2vRyy6K7JJo55w+8xDk7RElYn6xvXtDW8HCfoKBFK69f3pgBJSUSQPr+4Q==", 681 | "cpu": [ 682 | "s390x" 683 | ], 684 | "optional": true, 685 | "os": [ 686 | "linux" 687 | ], 688 | "engines": { 689 | "node": ">=12" 690 | } 691 | }, 692 | "node_modules/@esbuild/linux-x64": { 693 | "version": "0.17.19", 694 | "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.19.tgz", 695 | "integrity": "sha512-68ngA9lg2H6zkZcyp22tsVt38mlhWde8l3eJLWkyLrp4HwMUr3c1s/M2t7+kHIhvMjglIBrFpncX1SzMckomGw==", 696 | "cpu": [ 697 | "x64" 698 | ], 699 | "optional": true, 700 | "os": [ 701 | "linux" 702 | ], 703 | "engines": { 704 | "node": ">=12" 705 | } 706 | }, 707 | "node_modules/@esbuild/netbsd-x64": { 708 | "version": "0.17.19", 709 | "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.19.tgz", 710 | "integrity": "sha512-CwFq42rXCR8TYIjIfpXCbRX0rp1jo6cPIUPSaWwzbVI4aOfX96OXY8M6KNmtPcg7QjYeDmN+DD0Wp3LaBOLf4Q==", 711 | "cpu": [ 712 | "x64" 713 | ], 714 | "optional": true, 715 | "os": [ 716 | "netbsd" 717 | ], 718 | "engines": { 719 | "node": ">=12" 720 | } 721 | }, 722 | "node_modules/@esbuild/openbsd-x64": { 723 | "version": "0.17.19", 724 | "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.19.tgz", 725 | "integrity": "sha512-cnq5brJYrSZ2CF6c35eCmviIN3k3RczmHz8eYaVlNasVqsNY+JKohZU5MKmaOI+KkllCdzOKKdPs762VCPC20g==", 726 | "cpu": [ 727 | "x64" 728 | ], 729 | "optional": true, 730 | "os": [ 731 | "openbsd" 732 | ], 733 | "engines": { 734 | "node": ">=12" 735 | } 736 | }, 737 | "node_modules/@esbuild/sunos-x64": { 738 | "version": "0.17.19", 739 | "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.19.tgz", 740 | "integrity": "sha512-vCRT7yP3zX+bKWFeP/zdS6SqdWB8OIpaRq/mbXQxTGHnIxspRtigpkUcDMlSCOejlHowLqII7K2JKevwyRP2rg==", 741 | "cpu": [ 742 | "x64" 743 | ], 744 | "optional": true, 745 | "os": [ 746 | "sunos" 747 | ], 748 | "engines": { 749 | "node": ">=12" 750 | } 751 | }, 752 | "node_modules/@esbuild/win32-arm64": { 753 | "version": "0.17.19", 754 | "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.19.tgz", 755 | "integrity": "sha512-yYx+8jwowUstVdorcMdNlzklLYhPxjniHWFKgRqH7IFlUEa0Umu3KuYplf1HUZZ422e3NU9F4LGb+4O0Kdcaag==", 756 | "cpu": [ 757 | "arm64" 758 | ], 759 | "optional": true, 760 | "os": [ 761 | "win32" 762 | ], 763 | "engines": { 764 | "node": ">=12" 765 | } 766 | }, 767 | "node_modules/@esbuild/win32-ia32": { 768 | "version": "0.17.19", 769 | "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.19.tgz", 770 | "integrity": "sha512-eggDKanJszUtCdlVs0RB+h35wNlb5v4TWEkq4vZcmVt5u/HiDZrTXe2bWFQUez3RgNHwx/x4sk5++4NSSicKkw==", 771 | "cpu": [ 772 | "ia32" 773 | ], 774 | "optional": true, 775 | "os": [ 776 | "win32" 777 | ], 778 | "engines": { 779 | "node": ">=12" 780 | } 781 | }, 782 | "node_modules/@esbuild/win32-x64": { 783 | "version": "0.17.19", 784 | "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.19.tgz", 785 | "integrity": "sha512-lAhycmKnVOuRYNtRtatQR1LPQf2oYCkRGkSFnseDAKPl8lu5SOsK/e1sXe5a0Pc5kHIHe6P2I/ilntNv2xf3cA==", 786 | "cpu": [ 787 | "x64" 788 | ], 789 | "optional": true, 790 | "os": [ 791 | "win32" 792 | ], 793 | "engines": { 794 | "node": ">=12" 795 | } 796 | }, 797 | "node_modules/@jridgewell/gen-mapping": { 798 | "version": "0.3.3", 799 | "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", 800 | "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", 801 | "dependencies": { 802 | "@jridgewell/set-array": "^1.0.1", 803 | "@jridgewell/sourcemap-codec": "^1.4.10", 804 | "@jridgewell/trace-mapping": "^0.3.9" 805 | }, 806 | "engines": { 807 | "node": ">=6.0.0" 808 | } 809 | }, 810 | "node_modules/@jridgewell/resolve-uri": { 811 | "version": "3.1.0", 812 | "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", 813 | "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", 814 | "engines": { 815 | "node": ">=6.0.0" 816 | } 817 | }, 818 | "node_modules/@jridgewell/set-array": { 819 | "version": "1.1.2", 820 | "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", 821 | "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", 822 | "engines": { 823 | "node": ">=6.0.0" 824 | } 825 | }, 826 | "node_modules/@jridgewell/sourcemap-codec": { 827 | "version": "1.4.15", 828 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", 829 | "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" 830 | }, 831 | "node_modules/@jridgewell/trace-mapping": { 832 | "version": "0.3.18", 833 | "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", 834 | "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", 835 | "dependencies": { 836 | "@jridgewell/resolve-uri": "3.1.0", 837 | "@jridgewell/sourcemap-codec": "1.4.14" 838 | } 839 | }, 840 | "node_modules/@jridgewell/trace-mapping/node_modules/@jridgewell/sourcemap-codec": { 841 | "version": "1.4.14", 842 | "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", 843 | "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" 844 | }, 845 | "node_modules/@types/babel__core": { 846 | "version": "7.20.1", 847 | "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.1.tgz", 848 | "integrity": "sha512-aACu/U/omhdk15O4Nfb+fHgH/z3QsfQzpnvRZhYhThms83ZnAOZz7zZAWO7mn2yyNQaA4xTO8GLK3uqFU4bYYw==", 849 | "dependencies": { 850 | "@babel/parser": "^7.20.7", 851 | "@babel/types": "^7.20.7", 852 | "@types/babel__generator": "*", 853 | "@types/babel__template": "*", 854 | "@types/babel__traverse": "*" 855 | } 856 | }, 857 | "node_modules/@types/babel__generator": { 858 | "version": "7.6.4", 859 | "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", 860 | "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", 861 | "dependencies": { 862 | "@babel/types": "^7.0.0" 863 | } 864 | }, 865 | "node_modules/@types/babel__template": { 866 | "version": "7.4.1", 867 | "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", 868 | "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", 869 | "dependencies": { 870 | "@babel/parser": "^7.1.0", 871 | "@babel/types": "^7.0.0" 872 | } 873 | }, 874 | "node_modules/@types/babel__traverse": { 875 | "version": "7.20.1", 876 | "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.1.tgz", 877 | "integrity": "sha512-MitHFXnhtgwsGZWtT68URpOvLN4EREih1u3QtQiN4VdAxWKRVvGCSvw/Qth0M0Qq3pJpnGOu5JaM/ydK7OGbqg==", 878 | "dependencies": { 879 | "@babel/types": "^7.20.7" 880 | } 881 | }, 882 | "node_modules/ansi-styles": { 883 | "version": "3.2.1", 884 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", 885 | "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", 886 | "dependencies": { 887 | "color-convert": "^1.9.0" 888 | }, 889 | "engines": { 890 | "node": ">=4" 891 | } 892 | }, 893 | "node_modules/babel-plugin-jsx-dom-expressions": { 894 | "version": "0.36.10", 895 | "resolved": "https://registry.npmjs.org/babel-plugin-jsx-dom-expressions/-/babel-plugin-jsx-dom-expressions-0.36.10.tgz", 896 | "integrity": "sha512-QA2k/14WGw+RgcGGnEuLWwnu4em6CGhjeXtjvgOYyFHYS2a+CzPeaVQHDOlfuiBcjq/3hWMspHMIMnPEOIzdBg==", 897 | "dependencies": { 898 | "@babel/helper-module-imports": "7.18.6", 899 | "@babel/plugin-syntax-jsx": "^7.18.6", 900 | "@babel/types": "^7.20.7", 901 | "html-entities": "2.3.3", 902 | "validate-html-nesting": "^1.2.1" 903 | }, 904 | "peerDependencies": { 905 | "@babel/core": "^7.20.12" 906 | } 907 | }, 908 | "node_modules/babel-plugin-jsx-dom-expressions/node_modules/@babel/helper-module-imports": { 909 | "version": "7.18.6", 910 | "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz", 911 | "integrity": "sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==", 912 | "dependencies": { 913 | "@babel/types": "^7.18.6" 914 | }, 915 | "engines": { 916 | "node": ">=6.9.0" 917 | } 918 | }, 919 | "node_modules/babel-preset-solid": { 920 | "version": "1.7.4", 921 | "resolved": "https://registry.npmjs.org/babel-preset-solid/-/babel-preset-solid-1.7.4.tgz", 922 | "integrity": "sha512-0mbHNYkbOVYhH6L95VlHVkBEVQjOXSzUqLDiFxUcsg/tU4yTM/qx7FI8C+kmos9LHckQBSm3wtwoe1BZLNJR1w==", 923 | "dependencies": { 924 | "babel-plugin-jsx-dom-expressions": "^0.36.10" 925 | }, 926 | "peerDependencies": { 927 | "@babel/core": "^7.0.0" 928 | } 929 | }, 930 | "node_modules/browserslist": { 931 | "version": "4.21.7", 932 | "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.21.7.tgz", 933 | "integrity": "sha512-BauCXrQ7I2ftSqd2mvKHGo85XR0u7Ru3C/Hxsy/0TkfCtjrmAbPdzLGasmoiBxplpDXlPvdjX9u7srIMfgasNA==", 934 | "funding": [ 935 | { 936 | "type": "opencollective", 937 | "url": "https://opencollective.com/browserslist" 938 | }, 939 | { 940 | "type": "tidelift", 941 | "url": "https://tidelift.com/funding/github/npm/browserslist" 942 | }, 943 | { 944 | "type": "github", 945 | "url": "https://github.com/sponsors/ai" 946 | } 947 | ], 948 | "dependencies": { 949 | "caniuse-lite": "^1.0.30001489", 950 | "electron-to-chromium": "^1.4.411", 951 | "node-releases": "^2.0.12", 952 | "update-browserslist-db": "^1.0.11" 953 | }, 954 | "bin": { 955 | "browserslist": "cli.js" 956 | }, 957 | "engines": { 958 | "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" 959 | } 960 | }, 961 | "node_modules/caniuse-lite": { 962 | "version": "1.0.30001495", 963 | "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001495.tgz", 964 | "integrity": "sha512-F6x5IEuigtUfU5ZMQK2jsy5JqUUlEFRVZq8bO2a+ysq5K7jD6PPc9YXZj78xDNS3uNchesp1Jw47YXEqr+Viyg==", 965 | "funding": [ 966 | { 967 | "type": "opencollective", 968 | "url": "https://opencollective.com/browserslist" 969 | }, 970 | { 971 | "type": "tidelift", 972 | "url": "https://tidelift.com/funding/github/npm/caniuse-lite" 973 | }, 974 | { 975 | "type": "github", 976 | "url": "https://github.com/sponsors/ai" 977 | } 978 | ] 979 | }, 980 | "node_modules/chalk": { 981 | "version": "2.4.2", 982 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", 983 | "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", 984 | "dependencies": { 985 | "ansi-styles": "^3.2.1", 986 | "escape-string-regexp": "^1.0.5", 987 | "supports-color": "^5.3.0" 988 | }, 989 | "engines": { 990 | "node": ">=4" 991 | } 992 | }, 993 | "node_modules/color-convert": { 994 | "version": "1.9.3", 995 | "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 996 | "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", 997 | "dependencies": { 998 | "color-name": "1.1.3" 999 | } 1000 | }, 1001 | "node_modules/color-name": { 1002 | "version": "1.1.3", 1003 | "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", 1004 | "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" 1005 | }, 1006 | "node_modules/convert-source-map": { 1007 | "version": "1.9.0", 1008 | "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", 1009 | "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" 1010 | }, 1011 | "node_modules/cssed": { 1012 | "version": "3.0.6", 1013 | "resolved": "https://registry.npmjs.org/cssed/-/cssed-3.0.6.tgz", 1014 | "integrity": "sha512-cttrevNv4H/BqnDPdkInU8Rk9aLBvmE9Bf5nFg+XNd0mKkNpZODUl4u3eEcCL3Fq+MsOJA8oLILJka95zbMNag==", 1015 | "dependencies": { 1016 | "@babel/core": "^7.21.8", 1017 | "@babel/generator": "^7.21.5", 1018 | "@babel/helper-module-imports": "^7.21.4", 1019 | "@babel/types": "^7.21.5", 1020 | "debug": "^4.3.4" 1021 | } 1022 | }, 1023 | "node_modules/csstype": { 1024 | "version": "3.1.2", 1025 | "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", 1026 | "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==" 1027 | }, 1028 | "node_modules/debug": { 1029 | "version": "4.3.4", 1030 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1031 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1032 | "dependencies": { 1033 | "ms": "2.1.2" 1034 | }, 1035 | "engines": { 1036 | "node": ">=6.0" 1037 | }, 1038 | "peerDependenciesMeta": { 1039 | "supports-color": { 1040 | "optional": true 1041 | } 1042 | } 1043 | }, 1044 | "node_modules/electron-to-chromium": { 1045 | "version": "1.4.421", 1046 | "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.421.tgz", 1047 | "integrity": "sha512-wZOyn3s/aQOtLGAwXMZfteQPN68kgls2wDAnYOA8kCjBvKVrW5RwmWVspxJYTqrcN7Y263XJVsC66VCIGzDO3g==" 1048 | }, 1049 | "node_modules/esbuild": { 1050 | "version": "0.17.19", 1051 | "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.19.tgz", 1052 | "integrity": "sha512-XQ0jAPFkK/u3LcVRcvVHQcTIqD6E2H1fvZMA5dQPSOWb3suUbWbfbRf94pjc0bNzRYLfIrDRQXr7X+LHIm5oHw==", 1053 | "hasInstallScript": true, 1054 | "bin": { 1055 | "esbuild": "bin/esbuild" 1056 | }, 1057 | "engines": { 1058 | "node": ">=12" 1059 | }, 1060 | "optionalDependencies": { 1061 | "@esbuild/android-arm": "0.17.19", 1062 | "@esbuild/android-arm64": "0.17.19", 1063 | "@esbuild/android-x64": "0.17.19", 1064 | "@esbuild/darwin-arm64": "0.17.19", 1065 | "@esbuild/darwin-x64": "0.17.19", 1066 | "@esbuild/freebsd-arm64": "0.17.19", 1067 | "@esbuild/freebsd-x64": "0.17.19", 1068 | "@esbuild/linux-arm": "0.17.19", 1069 | "@esbuild/linux-arm64": "0.17.19", 1070 | "@esbuild/linux-ia32": "0.17.19", 1071 | "@esbuild/linux-loong64": "0.17.19", 1072 | "@esbuild/linux-mips64el": "0.17.19", 1073 | "@esbuild/linux-ppc64": "0.17.19", 1074 | "@esbuild/linux-riscv64": "0.17.19", 1075 | "@esbuild/linux-s390x": "0.17.19", 1076 | "@esbuild/linux-x64": "0.17.19", 1077 | "@esbuild/netbsd-x64": "0.17.19", 1078 | "@esbuild/openbsd-x64": "0.17.19", 1079 | "@esbuild/sunos-x64": "0.17.19", 1080 | "@esbuild/win32-arm64": "0.17.19", 1081 | "@esbuild/win32-ia32": "0.17.19", 1082 | "@esbuild/win32-x64": "0.17.19" 1083 | } 1084 | }, 1085 | "node_modules/escalade": { 1086 | "version": "3.1.1", 1087 | "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", 1088 | "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", 1089 | "engines": { 1090 | "node": ">=6" 1091 | } 1092 | }, 1093 | "node_modules/escape-string-regexp": { 1094 | "version": "1.0.5", 1095 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", 1096 | "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", 1097 | "engines": { 1098 | "node": ">=0.8.0" 1099 | } 1100 | }, 1101 | "node_modules/fsevents": { 1102 | "version": "2.3.2", 1103 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", 1104 | "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", 1105 | "hasInstallScript": true, 1106 | "optional": true, 1107 | "os": [ 1108 | "darwin" 1109 | ], 1110 | "engines": { 1111 | "node": "^8.16.0 || ^10.6.0 || >=11.0.0" 1112 | } 1113 | }, 1114 | "node_modules/gensync": { 1115 | "version": "1.0.0-beta.2", 1116 | "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", 1117 | "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", 1118 | "engines": { 1119 | "node": ">=6.9.0" 1120 | } 1121 | }, 1122 | "node_modules/globals": { 1123 | "version": "11.12.0", 1124 | "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", 1125 | "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", 1126 | "engines": { 1127 | "node": ">=4" 1128 | } 1129 | }, 1130 | "node_modules/has-flag": { 1131 | "version": "3.0.0", 1132 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", 1133 | "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", 1134 | "engines": { 1135 | "node": ">=4" 1136 | } 1137 | }, 1138 | "node_modules/html-entities": { 1139 | "version": "2.3.3", 1140 | "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.3.3.tgz", 1141 | "integrity": "sha512-DV5Ln36z34NNTDgnz0EWGBLZENelNAtkiFA4kyNOG2tDI6Mz1uSWiq1wAKdyjnJwyDiDO7Fa2SO1CTxPXL8VxA==" 1142 | }, 1143 | "node_modules/is-what": { 1144 | "version": "4.1.13", 1145 | "resolved": "https://registry.npmjs.org/is-what/-/is-what-4.1.13.tgz", 1146 | "integrity": "sha512-Aoe8pT24sWzyoO0S2PTDyutGp9l7qYHyFtzYlC8hMLshyqV/minljBANT4f2hiS5OxnWvcKMiA5io+VaLMJ1oA==", 1147 | "engines": { 1148 | "node": ">=12.13" 1149 | }, 1150 | "funding": { 1151 | "url": "https://github.com/sponsors/mesqueeb" 1152 | } 1153 | }, 1154 | "node_modules/js-tokens": { 1155 | "version": "4.0.0", 1156 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 1157 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" 1158 | }, 1159 | "node_modules/jsesc": { 1160 | "version": "2.5.2", 1161 | "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", 1162 | "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", 1163 | "bin": { 1164 | "jsesc": "bin/jsesc" 1165 | }, 1166 | "engines": { 1167 | "node": ">=4" 1168 | } 1169 | }, 1170 | "node_modules/json5": { 1171 | "version": "2.2.3", 1172 | "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", 1173 | "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", 1174 | "bin": { 1175 | "json5": "lib/cli.js" 1176 | }, 1177 | "engines": { 1178 | "node": ">=6" 1179 | } 1180 | }, 1181 | "node_modules/lru-cache": { 1182 | "version": "5.1.1", 1183 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", 1184 | "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", 1185 | "dependencies": { 1186 | "yallist": "^3.0.2" 1187 | } 1188 | }, 1189 | "node_modules/merge-anything": { 1190 | "version": "5.1.7", 1191 | "resolved": "https://registry.npmjs.org/merge-anything/-/merge-anything-5.1.7.tgz", 1192 | "integrity": "sha512-eRtbOb1N5iyH0tkQDAoQ4Ipsp/5qSR79Dzrz8hEPxRX10RWWR/iQXdoKmBSRCThY1Fh5EhISDtpSc93fpxUniQ==", 1193 | "dependencies": { 1194 | "is-what": "^4.1.8" 1195 | }, 1196 | "engines": { 1197 | "node": ">=12.13" 1198 | }, 1199 | "funding": { 1200 | "url": "https://github.com/sponsors/mesqueeb" 1201 | } 1202 | }, 1203 | "node_modules/ms": { 1204 | "version": "2.1.2", 1205 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1206 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1207 | }, 1208 | "node_modules/nanoid": { 1209 | "version": "3.3.6", 1210 | "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz", 1211 | "integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==", 1212 | "funding": [ 1213 | { 1214 | "type": "github", 1215 | "url": "https://github.com/sponsors/ai" 1216 | } 1217 | ], 1218 | "bin": { 1219 | "nanoid": "bin/nanoid.cjs" 1220 | }, 1221 | "engines": { 1222 | "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" 1223 | } 1224 | }, 1225 | "node_modules/node-releases": { 1226 | "version": "2.0.12", 1227 | "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.12.tgz", 1228 | "integrity": "sha512-QzsYKWhXTWx8h1kIvqfnC++o0pEmpRQA/aenALsL2F4pqNVr7YzcdMlDij5WBnwftRbJCNJL/O7zdKaxKPHqgQ==" 1229 | }, 1230 | "node_modules/picocolors": { 1231 | "version": "1.0.0", 1232 | "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", 1233 | "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" 1234 | }, 1235 | "node_modules/postcss": { 1236 | "version": "8.4.24", 1237 | "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.24.tgz", 1238 | "integrity": "sha512-M0RzbcI0sO/XJNucsGjvWU9ERWxb/ytp1w6dKtxTKgixdtQDq4rmx/g8W1hnaheq9jgwL/oyEdH5Bc4WwJKMqg==", 1239 | "funding": [ 1240 | { 1241 | "type": "opencollective", 1242 | "url": "https://opencollective.com/postcss/" 1243 | }, 1244 | { 1245 | "type": "tidelift", 1246 | "url": "https://tidelift.com/funding/github/npm/postcss" 1247 | }, 1248 | { 1249 | "type": "github", 1250 | "url": "https://github.com/sponsors/ai" 1251 | } 1252 | ], 1253 | "dependencies": { 1254 | "nanoid": "^3.3.6", 1255 | "picocolors": "^1.0.0", 1256 | "source-map-js": "^1.0.2" 1257 | }, 1258 | "engines": { 1259 | "node": "^10 || ^12 || >=14" 1260 | } 1261 | }, 1262 | "node_modules/rollup": { 1263 | "version": "3.23.1", 1264 | "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.23.1.tgz", 1265 | "integrity": "sha512-ybRdFVHOoljGEFILHLd2g/qateqUdjE6YS41WXq4p3C/WwD3xtWxV4FYWETA1u9TeXQc5K8L8zHE5d/scOvrOQ==", 1266 | "bin": { 1267 | "rollup": "dist/bin/rollup" 1268 | }, 1269 | "engines": { 1270 | "node": ">=14.18.0", 1271 | "npm": ">=8.0.0" 1272 | }, 1273 | "optionalDependencies": { 1274 | "fsevents": "~2.3.2" 1275 | } 1276 | }, 1277 | "node_modules/semver": { 1278 | "version": "6.3.0", 1279 | "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", 1280 | "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", 1281 | "bin": { 1282 | "semver": "bin/semver.js" 1283 | } 1284 | }, 1285 | "node_modules/seroval": { 1286 | "version": "0.5.1", 1287 | "resolved": "https://registry.npmjs.org/seroval/-/seroval-0.5.1.tgz", 1288 | "integrity": "sha512-ZfhQVB59hmIauJG5Ydynupy8KHyr5imGNtdDhbZG68Ufh1Ynkv9KOYOAABf71oVbQxJ8VkWnMHAjEHE7fWkH5g==", 1289 | "engines": { 1290 | "node": ">=10" 1291 | } 1292 | }, 1293 | "node_modules/solid-js": { 1294 | "version": "1.7.6", 1295 | "resolved": "https://registry.npmjs.org/solid-js/-/solid-js-1.7.6.tgz", 1296 | "integrity": "sha512-DXVOTjUh/bIAhE0fIqu3ezGLyQaez7v8EOw3uPLIi87DmLjg+hsuCAgKyNIZ+o4jUetOk3ZORccvJmE1yZUk8g==", 1297 | "dependencies": { 1298 | "csstype": "^3.1.0", 1299 | "seroval": "^0.5.0" 1300 | } 1301 | }, 1302 | "node_modules/solid-refresh": { 1303 | "version": "0.5.2", 1304 | "resolved": "https://registry.npmjs.org/solid-refresh/-/solid-refresh-0.5.2.tgz", 1305 | "integrity": "sha512-I69HmFj0LsGRJ3n8CEMVjyQFgVtuM2bSjznu2hCnsY+i5oOxh8ioWj00nnHBv0UYD3WpE/Sq4Q3TNw2IKmKN7A==", 1306 | "dependencies": { 1307 | "@babel/generator": "^7.21.1", 1308 | "@babel/helper-module-imports": "^7.18.6", 1309 | "@babel/types": "^7.21.2" 1310 | }, 1311 | "peerDependencies": { 1312 | "solid-js": "^1.3" 1313 | } 1314 | }, 1315 | "node_modules/source-map-js": { 1316 | "version": "1.0.2", 1317 | "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", 1318 | "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", 1319 | "engines": { 1320 | "node": ">=0.10.0" 1321 | } 1322 | }, 1323 | "node_modules/supports-color": { 1324 | "version": "5.5.0", 1325 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1326 | "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1327 | "dependencies": { 1328 | "has-flag": "^3.0.0" 1329 | }, 1330 | "engines": { 1331 | "node": ">=4" 1332 | } 1333 | }, 1334 | "node_modules/to-fast-properties": { 1335 | "version": "2.0.0", 1336 | "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", 1337 | "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", 1338 | "engines": { 1339 | "node": ">=4" 1340 | } 1341 | }, 1342 | "node_modules/update-browserslist-db": { 1343 | "version": "1.0.11", 1344 | "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", 1345 | "integrity": "sha512-dCwEFf0/oT85M1fHBg4F0jtLwJrutGoHSQXCh7u4o2t1drG+c0a9Flnqww6XUKSfQMPpJBRjU8d4RXB09qtvaA==", 1346 | "funding": [ 1347 | { 1348 | "type": "opencollective", 1349 | "url": "https://opencollective.com/browserslist" 1350 | }, 1351 | { 1352 | "type": "tidelift", 1353 | "url": "https://tidelift.com/funding/github/npm/browserslist" 1354 | }, 1355 | { 1356 | "type": "github", 1357 | "url": "https://github.com/sponsors/ai" 1358 | } 1359 | ], 1360 | "dependencies": { 1361 | "escalade": "^3.1.1", 1362 | "picocolors": "^1.0.0" 1363 | }, 1364 | "bin": { 1365 | "update-browserslist-db": "cli.js" 1366 | }, 1367 | "peerDependencies": { 1368 | "browserslist": ">= 4.21.0" 1369 | } 1370 | }, 1371 | "node_modules/validate-html-nesting": { 1372 | "version": "1.2.2", 1373 | "resolved": "https://registry.npmjs.org/validate-html-nesting/-/validate-html-nesting-1.2.2.tgz", 1374 | "integrity": "sha512-hGdgQozCsQJMyfK5urgFcWEqsSSrK63Awe0t/IMR0bZ0QMtnuaiHzThW81guu3qx9abLi99NEuiaN6P9gVYsNg==" 1375 | }, 1376 | "node_modules/vite": { 1377 | "version": "4.3.9", 1378 | "resolved": "https://registry.npmjs.org/vite/-/vite-4.3.9.tgz", 1379 | "integrity": "sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==", 1380 | "dependencies": { 1381 | "esbuild": "^0.17.5", 1382 | "postcss": "^8.4.23", 1383 | "rollup": "^3.21.0" 1384 | }, 1385 | "bin": { 1386 | "vite": "bin/vite.js" 1387 | }, 1388 | "engines": { 1389 | "node": "^14.18.0 || >=16.0.0" 1390 | }, 1391 | "optionalDependencies": { 1392 | "fsevents": "~2.3.2" 1393 | }, 1394 | "peerDependencies": { 1395 | "@types/node": ">= 14", 1396 | "less": "*", 1397 | "sass": "*", 1398 | "stylus": "*", 1399 | "sugarss": "*", 1400 | "terser": "^5.4.0" 1401 | }, 1402 | "peerDependenciesMeta": { 1403 | "@types/node": { 1404 | "optional": true 1405 | }, 1406 | "less": { 1407 | "optional": true 1408 | }, 1409 | "sass": { 1410 | "optional": true 1411 | }, 1412 | "stylus": { 1413 | "optional": true 1414 | }, 1415 | "sugarss": { 1416 | "optional": true 1417 | }, 1418 | "terser": { 1419 | "optional": true 1420 | } 1421 | } 1422 | }, 1423 | "node_modules/vite-plugin-solid": { 1424 | "version": "2.7.0", 1425 | "resolved": "https://registry.npmjs.org/vite-plugin-solid/-/vite-plugin-solid-2.7.0.tgz", 1426 | "integrity": "sha512-avp/Jl5zOp/Itfo67xtDB2O61U7idviaIp4mLsjhCa13PjKNasz+IID0jYTyqUp9SFx6/PmBr6v4KgDppqompg==", 1427 | "dependencies": { 1428 | "@babel/core": "^7.20.5", 1429 | "@babel/preset-typescript": "^7.18.6", 1430 | "@types/babel__core": "^7.1.20", 1431 | "babel-preset-solid": "^1.7.2", 1432 | "merge-anything": "^5.1.4", 1433 | "solid-refresh": "^0.5.0", 1434 | "vitefu": "^0.2.3" 1435 | }, 1436 | "peerDependencies": { 1437 | "solid-js": "^1.7.2", 1438 | "vite": "^3.0.0 || ^4.0.0" 1439 | } 1440 | }, 1441 | "node_modules/vitefu": { 1442 | "version": "0.2.4", 1443 | "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.4.tgz", 1444 | "integrity": "sha512-fanAXjSaf9xXtOOeno8wZXIhgia+CZury481LsDaV++lSvcU2R9Ch2bPh3PYFyoHW+w9LqAeYRISVQjUIew14g==", 1445 | "peerDependencies": { 1446 | "vite": "^3.0.0 || ^4.0.0" 1447 | }, 1448 | "peerDependenciesMeta": { 1449 | "vite": { 1450 | "optional": true 1451 | } 1452 | } 1453 | }, 1454 | "node_modules/yallist": { 1455 | "version": "3.1.1", 1456 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", 1457 | "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" 1458 | } 1459 | } 1460 | } 1461 | -------------------------------------------------------------------------------- /examples/vite-solid/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example", 3 | "private": "true", 4 | "type": "module", 5 | "scripts": { 6 | "dev": "vite", 7 | "build": "vite build" 8 | }, 9 | "devDependencies": { 10 | "vite": "^4.1.1" 11 | }, 12 | "dependencies": { 13 | "cssed": "^3.0.6", 14 | "solid-js": "^1.4.10", 15 | "vite-plugin-solid": "^2.7.0" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /examples/vite-solid/pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | solid-js: ^1.4.10 5 | vite: ^4.1.1 6 | vite-plugin-solid: link:.. 7 | 8 | dependencies: 9 | solid-js: 1.6.11 10 | 11 | devDependencies: 12 | vite: 4.1.1 13 | vite-plugin-solid: link:.. 14 | 15 | packages: 16 | 17 | /@esbuild/android-arm/0.16.17: 18 | resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} 19 | engines: {node: '>=12'} 20 | cpu: [arm] 21 | os: [android] 22 | requiresBuild: true 23 | dev: true 24 | optional: true 25 | 26 | /@esbuild/android-arm64/0.16.17: 27 | resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} 28 | engines: {node: '>=12'} 29 | cpu: [arm64] 30 | os: [android] 31 | requiresBuild: true 32 | dev: true 33 | optional: true 34 | 35 | /@esbuild/android-x64/0.16.17: 36 | resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} 37 | engines: {node: '>=12'} 38 | cpu: [x64] 39 | os: [android] 40 | requiresBuild: true 41 | dev: true 42 | optional: true 43 | 44 | /@esbuild/darwin-arm64/0.16.17: 45 | resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} 46 | engines: {node: '>=12'} 47 | cpu: [arm64] 48 | os: [darwin] 49 | requiresBuild: true 50 | dev: true 51 | optional: true 52 | 53 | /@esbuild/darwin-x64/0.16.17: 54 | resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} 55 | engines: {node: '>=12'} 56 | cpu: [x64] 57 | os: [darwin] 58 | requiresBuild: true 59 | dev: true 60 | optional: true 61 | 62 | /@esbuild/freebsd-arm64/0.16.17: 63 | resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} 64 | engines: {node: '>=12'} 65 | cpu: [arm64] 66 | os: [freebsd] 67 | requiresBuild: true 68 | dev: true 69 | optional: true 70 | 71 | /@esbuild/freebsd-x64/0.16.17: 72 | resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} 73 | engines: {node: '>=12'} 74 | cpu: [x64] 75 | os: [freebsd] 76 | requiresBuild: true 77 | dev: true 78 | optional: true 79 | 80 | /@esbuild/linux-arm/0.16.17: 81 | resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} 82 | engines: {node: '>=12'} 83 | cpu: [arm] 84 | os: [linux] 85 | requiresBuild: true 86 | dev: true 87 | optional: true 88 | 89 | /@esbuild/linux-arm64/0.16.17: 90 | resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} 91 | engines: {node: '>=12'} 92 | cpu: [arm64] 93 | os: [linux] 94 | requiresBuild: true 95 | dev: true 96 | optional: true 97 | 98 | /@esbuild/linux-ia32/0.16.17: 99 | resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} 100 | engines: {node: '>=12'} 101 | cpu: [ia32] 102 | os: [linux] 103 | requiresBuild: true 104 | dev: true 105 | optional: true 106 | 107 | /@esbuild/linux-loong64/0.16.17: 108 | resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} 109 | engines: {node: '>=12'} 110 | cpu: [loong64] 111 | os: [linux] 112 | requiresBuild: true 113 | dev: true 114 | optional: true 115 | 116 | /@esbuild/linux-mips64el/0.16.17: 117 | resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} 118 | engines: {node: '>=12'} 119 | cpu: [mips64el] 120 | os: [linux] 121 | requiresBuild: true 122 | dev: true 123 | optional: true 124 | 125 | /@esbuild/linux-ppc64/0.16.17: 126 | resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} 127 | engines: {node: '>=12'} 128 | cpu: [ppc64] 129 | os: [linux] 130 | requiresBuild: true 131 | dev: true 132 | optional: true 133 | 134 | /@esbuild/linux-riscv64/0.16.17: 135 | resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} 136 | engines: {node: '>=12'} 137 | cpu: [riscv64] 138 | os: [linux] 139 | requiresBuild: true 140 | dev: true 141 | optional: true 142 | 143 | /@esbuild/linux-s390x/0.16.17: 144 | resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} 145 | engines: {node: '>=12'} 146 | cpu: [s390x] 147 | os: [linux] 148 | requiresBuild: true 149 | dev: true 150 | optional: true 151 | 152 | /@esbuild/linux-x64/0.16.17: 153 | resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} 154 | engines: {node: '>=12'} 155 | cpu: [x64] 156 | os: [linux] 157 | requiresBuild: true 158 | dev: true 159 | optional: true 160 | 161 | /@esbuild/netbsd-x64/0.16.17: 162 | resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} 163 | engines: {node: '>=12'} 164 | cpu: [x64] 165 | os: [netbsd] 166 | requiresBuild: true 167 | dev: true 168 | optional: true 169 | 170 | /@esbuild/openbsd-x64/0.16.17: 171 | resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} 172 | engines: {node: '>=12'} 173 | cpu: [x64] 174 | os: [openbsd] 175 | requiresBuild: true 176 | dev: true 177 | optional: true 178 | 179 | /@esbuild/sunos-x64/0.16.17: 180 | resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} 181 | engines: {node: '>=12'} 182 | cpu: [x64] 183 | os: [sunos] 184 | requiresBuild: true 185 | dev: true 186 | optional: true 187 | 188 | /@esbuild/win32-arm64/0.16.17: 189 | resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} 190 | engines: {node: '>=12'} 191 | cpu: [arm64] 192 | os: [win32] 193 | requiresBuild: true 194 | dev: true 195 | optional: true 196 | 197 | /@esbuild/win32-ia32/0.16.17: 198 | resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} 199 | engines: {node: '>=12'} 200 | cpu: [ia32] 201 | os: [win32] 202 | requiresBuild: true 203 | dev: true 204 | optional: true 205 | 206 | /@esbuild/win32-x64/0.16.17: 207 | resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} 208 | engines: {node: '>=12'} 209 | cpu: [x64] 210 | os: [win32] 211 | requiresBuild: true 212 | dev: true 213 | optional: true 214 | 215 | /csstype/3.1.1: 216 | resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==} 217 | dev: false 218 | 219 | /esbuild/0.16.17: 220 | resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} 221 | engines: {node: '>=12'} 222 | hasBin: true 223 | requiresBuild: true 224 | optionalDependencies: 225 | '@esbuild/android-arm': 0.16.17 226 | '@esbuild/android-arm64': 0.16.17 227 | '@esbuild/android-x64': 0.16.17 228 | '@esbuild/darwin-arm64': 0.16.17 229 | '@esbuild/darwin-x64': 0.16.17 230 | '@esbuild/freebsd-arm64': 0.16.17 231 | '@esbuild/freebsd-x64': 0.16.17 232 | '@esbuild/linux-arm': 0.16.17 233 | '@esbuild/linux-arm64': 0.16.17 234 | '@esbuild/linux-ia32': 0.16.17 235 | '@esbuild/linux-loong64': 0.16.17 236 | '@esbuild/linux-mips64el': 0.16.17 237 | '@esbuild/linux-ppc64': 0.16.17 238 | '@esbuild/linux-riscv64': 0.16.17 239 | '@esbuild/linux-s390x': 0.16.17 240 | '@esbuild/linux-x64': 0.16.17 241 | '@esbuild/netbsd-x64': 0.16.17 242 | '@esbuild/openbsd-x64': 0.16.17 243 | '@esbuild/sunos-x64': 0.16.17 244 | '@esbuild/win32-arm64': 0.16.17 245 | '@esbuild/win32-ia32': 0.16.17 246 | '@esbuild/win32-x64': 0.16.17 247 | dev: true 248 | 249 | /fsevents/2.3.2: 250 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 251 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 252 | os: [darwin] 253 | requiresBuild: true 254 | dev: true 255 | optional: true 256 | 257 | /function-bind/1.1.1: 258 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 259 | dev: true 260 | 261 | /has/1.0.3: 262 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 263 | engines: {node: '>= 0.4.0'} 264 | dependencies: 265 | function-bind: 1.1.1 266 | dev: true 267 | 268 | /is-core-module/2.11.0: 269 | resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==} 270 | dependencies: 271 | has: 1.0.3 272 | dev: true 273 | 274 | /nanoid/3.3.4: 275 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} 276 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 277 | hasBin: true 278 | dev: true 279 | 280 | /path-parse/1.0.7: 281 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 282 | dev: true 283 | 284 | /picocolors/1.0.0: 285 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 286 | dev: true 287 | 288 | /postcss/8.4.21: 289 | resolution: {integrity: sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==} 290 | engines: {node: ^10 || ^12 || >=14} 291 | dependencies: 292 | nanoid: 3.3.4 293 | picocolors: 1.0.0 294 | source-map-js: 1.0.2 295 | dev: true 296 | 297 | /resolve/1.22.1: 298 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} 299 | hasBin: true 300 | dependencies: 301 | is-core-module: 2.11.0 302 | path-parse: 1.0.7 303 | supports-preserve-symlinks-flag: 1.0.0 304 | dev: true 305 | 306 | /rollup/3.15.0: 307 | resolution: {integrity: sha512-F9hrCAhnp5/zx/7HYmftvsNBkMfLfk/dXUh73hPSM2E3CRgap65orDNJbLetoiUFwSAk6iHPLvBrZ5iHYvzqsg==} 308 | engines: {node: '>=14.18.0', npm: '>=8.0.0'} 309 | hasBin: true 310 | optionalDependencies: 311 | fsevents: 2.3.2 312 | dev: true 313 | 314 | /solid-js/1.6.11: 315 | resolution: {integrity: sha512-JquQQHPArGq+i2PLURxJ99Pcz2/1docpbycSio/cKSA0SeI3z5zRjy0TNcH4NRYvbOLrcini+iovXwnexKabyw==} 316 | dependencies: 317 | csstype: 3.1.1 318 | dev: false 319 | 320 | /source-map-js/1.0.2: 321 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 322 | engines: {node: '>=0.10.0'} 323 | dev: true 324 | 325 | /supports-preserve-symlinks-flag/1.0.0: 326 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 327 | engines: {node: '>= 0.4'} 328 | dev: true 329 | 330 | /vite/4.1.1: 331 | resolution: {integrity: sha512-LM9WWea8vsxhr782r9ntg+bhSFS06FJgCvvB0+8hf8UWtvaiDagKYWXndjfX6kGl74keHJUcpzrQliDXZlF5yg==} 332 | engines: {node: ^14.18.0 || >=16.0.0} 333 | hasBin: true 334 | peerDependencies: 335 | '@types/node': '>= 14' 336 | less: '*' 337 | sass: '*' 338 | stylus: '*' 339 | sugarss: '*' 340 | terser: ^5.4.0 341 | peerDependenciesMeta: 342 | '@types/node': 343 | optional: true 344 | less: 345 | optional: true 346 | sass: 347 | optional: true 348 | stylus: 349 | optional: true 350 | sugarss: 351 | optional: true 352 | terser: 353 | optional: true 354 | dependencies: 355 | esbuild: 0.16.17 356 | postcss: 8.4.21 357 | resolve: 1.22.1 358 | rollup: 3.15.0 359 | optionalDependencies: 360 | fsevents: 2.3.2 361 | dev: true 362 | -------------------------------------------------------------------------------- /examples/vite-solid/src/App.tsx: -------------------------------------------------------------------------------- 1 | /* @refresh granular */ 2 | import { onCleanup, onMount } from 'solid-js' 3 | import { CounterProvider, useCounter } from './CounterContext' 4 | 5 | import { css } from 'cssed' 6 | const title = 'Count' 7 | 8 | const styles = css` 9 | .red { 10 | color: red; 11 | } 12 | ` 13 | 14 | function Count() { 15 | const counter = useCounter() 16 | onMount(() => { 17 | console.log('Mounted Count') 18 | }) 19 | onCleanup(() => { 20 | console.log('Unmounted Count') 21 | }) 22 | return ( 23 |

24 | {title}: {counter.value()} 25 |

26 | ) 27 | } 28 | 29 | function Increment() { 30 | const counter = useCounter() 31 | onMount(() => { 32 | console.log('Mounted Increment') 33 | }) 34 | onCleanup(() => { 35 | console.log('Unmounted Increment') 36 | }) 37 | return 38 | } 39 | 40 | function Decrement() { 41 | const counter = useCounter() 42 | onMount(() => { 43 | console.log('Mounted Decrement') 44 | }) 45 | onCleanup(() => { 46 | console.log('Unmounted Decrement') 47 | }) 48 | return 49 | } 50 | 51 | export default function App() { 52 | onMount(() => { 53 | console.log('Mounted App') 54 | }) 55 | onCleanup(() => { 56 | console.log('Unmounted App') 57 | }) 58 | 59 | return ( 60 | 61 | 62 | 63 | 64 | 65 | ) 66 | } 67 | -------------------------------------------------------------------------------- /examples/vite-solid/src/CounterContext.tsx: -------------------------------------------------------------------------------- 1 | import { createContext, createSignal, JSX, onCleanup, onMount, useContext } from "solid-js"; 2 | 3 | interface CounterContext { 4 | value(): number; 5 | increment(): void; 6 | decrement(): void; 7 | } 8 | 9 | 10 | const CounterContext = createContext(); 11 | 12 | export function useCounter() { 13 | const ctx = useContext(CounterContext); 14 | if (!ctx) { 15 | throw new Error('Missing CounterContext'); 16 | } 17 | return ctx; 18 | } 19 | 20 | export function CounterProvider(props: { children: JSX.Element }) { 21 | const [value, setValue] = createSignal(0); 22 | 23 | function increment() { 24 | setValue((c) => c + 1); 25 | } 26 | 27 | function decrement() { 28 | setValue((c) => c - 1); 29 | } 30 | onMount(() => { 31 | console.log('Mounted CounterProvider'); 32 | }); 33 | onCleanup(() => { 34 | console.log('Unmounted CounterProvider'); 35 | }); 36 | 37 | return ( 38 | 39 |

Counter

40 | {props.children} 41 |
42 | ); 43 | } 44 | -------------------------------------------------------------------------------- /examples/vite-solid/src/main.tsx: -------------------------------------------------------------------------------- 1 | import { render } from 'solid-js/web'; 2 | import App from './App'; 3 | 4 | const app = document.getElementById('app'); 5 | 6 | if (app) { 7 | render(() => , app); 8 | } -------------------------------------------------------------------------------- /examples/vite-solid/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "ESNext", 5 | "allowSyntheticDefaultImports": true, 6 | "esModuleInterop": true, 7 | "resolveJsonModule": true, 8 | "moduleResolution": "node", 9 | "jsx": "preserve", 10 | "jsxImportSource": "solid-js", 11 | "types": ["vite/client"], 12 | "baseUrl": ".", 13 | "paths": { 14 | "@/*": ["./pages/*"], 15 | "@@/*": ["./assets/*"] 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /examples/vite-solid/vite.config.ts: -------------------------------------------------------------------------------- 1 | import cssedPlugin from 'cssed/vite-plugin'; 2 | import { defineConfig } from 'vite'; 3 | import solidPlugin from 'vite-plugin-solid'; 4 | 5 | export default defineConfig({ 6 | plugins: [ 7 | solidPlugin(), 8 | cssedPlugin() 9 | ], 10 | }); 11 | -------------------------------------------------------------------------------- /media/autocomplete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/okotoki/cssed/51951446f1cf0805f4f8b02838d0e34e1577bbec/media/autocomplete.png -------------------------------------------------------------------------------- /media/header.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cssed", 3 | "version": "3.1.0", 4 | "description": "🤷‍♂️CSS-in-JS modules that just works", 5 | "main": "./lib/index.js", 6 | "scripts": { 7 | "watch": "tsc -w", 8 | "test": "tsc && jest", 9 | "build": "rm -rf ./lib && NODE_ENV=production tsc && jest", 10 | "prepublish": "npm run build" 11 | }, 12 | "repository": { 13 | "type": "git", 14 | "url": "git+https://github.com/okotoki/cssed.git" 15 | }, 16 | "keywords": [ 17 | "babel", 18 | "babel-plugin", 19 | "CSS-in-JS", 20 | "css", 21 | "cssed" 22 | ], 23 | "author": "Eugene", 24 | "license": "MIT", 25 | "bugs": { 26 | "url": "https://github.com/okotoki/cssed/issues" 27 | }, 28 | "homepage": "https://github.com/okotoki/cssed#readme", 29 | "devDependencies": { 30 | "@types/debug": "^4.1.7", 31 | "@types/node": "^20.1.2", 32 | "babel-jest": "^29.5.0", 33 | "babel-plugin-tester": "^11.0.4", 34 | "jest": "^29.5.0", 35 | "typescript": "^5.0.4", 36 | "vite": "^4.3.9" 37 | }, 38 | "dependencies": { 39 | "@babel/core": "^7.21.8", 40 | "@babel/generator": "^7.21.5", 41 | "@babel/helper-module-imports": "^7.21.4", 42 | "@babel/plugin-syntax-jsx": "^7.21.4", 43 | "@babel/plugin-syntax-typescript": "^7.21.4", 44 | "@babel/plugin-transform-typescript": "^7.22.3", 45 | "@babel/preset-env": "^7.22.4", 46 | "@babel/types": "^7.21.5", 47 | "debug": "^4.3.4" 48 | }, 49 | "jest": { 50 | "testMatch": [ 51 | "**/__tests__/**/*.test.[jt]s?(x)", 52 | "**/?(*.)+(spec|test).[jt]s?(x)" 53 | ], 54 | "testPathIgnorePatterns": [ 55 | "example" 56 | ] 57 | }, 58 | "babel": { 59 | "presets": [ 60 | "@babel/preset-env" 61 | ] 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/__tests__/__snapshots__/index.test.js.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`cssed 1. single call macro: 1. single call macro 1`] = ` 4 | 5 | 6 | import { css } from 'cssed'; 7 | 8 | const styles = css\` 9 | .box { 10 | color: blue 11 | } 12 | \` 13 | 14 | 15 | ↓ ↓ ↓ ↓ ↓ ↓ 16 | 17 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 18 | const styles = _cssed_a 19 | 20 | `; 21 | 22 | exports[`cssed 2. single call evaluation: 2. single call evaluation 1`] = ` 23 | 24 | 25 | import { css } from 'cssed'; 26 | 27 | const blue = 'blue' 28 | 29 | const styles = css\` 30 | .box { 31 | color: \${blue} 32 | } 33 | \` 34 | 35 | 36 | ↓ ↓ ↓ ↓ ↓ ↓ 37 | 38 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 39 | const blue = 'blue' 40 | const styles = _cssed_a 41 | 42 | `; 43 | 44 | exports[`cssed 3. multi call macro: 3. multi call macro 1`] = ` 45 | 46 | 47 | import { css } from 'cssed'; 48 | 49 | const blue = css\` 50 | .box { 51 | color: blue; 52 | } 53 | \`; 54 | 55 | const red = css\` 56 | .box { 57 | color: red; 58 | } 59 | \`; 60 | 61 | export default props => ( 62 |
63 | ); 64 | 65 | 66 | ↓ ↓ ↓ ↓ ↓ ↓ 67 | 68 | import _cssed_b from '../../.cssed/edb7e408acbb359c_b.module.css' 69 | import _cssed_a from '../../.cssed/edb7e408acbb359c_a.module.css' 70 | const blue = _cssed_a 71 | const red = _cssed_b 72 | export default (props) =>
73 | 74 | `; 75 | 76 | exports[`cssed 4. multi call with external dependency: 4. multi call with external dependency 1`] = ` 77 | 78 | 79 | import { css } from 'cssed'; 80 | import { light, dark } from './module' 81 | 82 | const btn = css\` 83 | .light { 84 | color: \${light}; 85 | } 86 | .dark { 87 | color: \${dark}; 88 | } 89 | \`; 90 | 91 | export default props => ( 92 | <> 93 |
94 |
95 | 96 | ); 97 | 98 | 99 | ↓ ↓ ↓ ↓ ↓ ↓ 100 | 101 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 102 | import { light, dark } from './module' 103 | const btn = _cssed_a 104 | export default (props) => ( 105 | <> 106 |
107 |
108 | 109 | ) 110 | 111 | `; 112 | 113 | exports[`cssed 5. multi call with external module dependency: 5. multi call with external module dependency 1`] = ` 114 | 115 | 116 | import { css } from 'cssed'; 117 | import { light, dark } from './module' 118 | 119 | const btn = css\` 120 | .light { 121 | color: \${light}; 122 | } 123 | .dark { 124 | color: \${dark}; 125 | } 126 | \`; 127 | 128 | export default props => ( 129 | <> 130 |
131 |
132 | 133 | ); 134 | 135 | 136 | ↓ ↓ ↓ ↓ ↓ ↓ 137 | 138 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 139 | import { light, dark } from './module' 140 | const btn = _cssed_a 141 | export default (props) => ( 142 | <> 143 |
144 |
145 | 146 | ) 147 | 148 | `; 149 | 150 | exports[`cssed 6. function call in expression: 6. function call in expression 1`] = ` 151 | 152 | 153 | import { css } from 'cssed'; 154 | import { light, dark } from './constant' 155 | 156 | const darkOrLight = (bool) => bool ? light : dark 157 | const btn = css\` 158 | .light { 159 | color: \${darkOrLight(true)}; 160 | } 161 | .dark { 162 | color: \${darkOrLight(false)}; 163 | } 164 | \`; 165 | 166 | export default props => ( 167 | <> 168 |
169 |
170 | 171 | ); 172 | 173 | 174 | ↓ ↓ ↓ ↓ ↓ ↓ 175 | 176 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 177 | import { light, dark } from './constant' 178 | const darkOrLight = (bool) => (bool ? light : dark) 179 | const btn = _cssed_a 180 | export default (props) => ( 181 | <> 182 |
183 |
184 | 185 | ) 186 | 187 | `; 188 | 189 | exports[`cssed 7. test url rebase: 7. test url rebase 1`] = ` 190 | 191 | 192 | import { css } from 'cssed'; 193 | 194 | const btn = css\` 195 | .light { 196 | background-image: url("star.gif"); 197 | list-style-image: url('../images/bullet.jpg'); 198 | font-family: 'Open Sans', sans-serif; 199 | border-image: url('border.png'); 200 | content: url('/content.png'); 201 | content: url(data:image/png;base64,iVBORw0KGgoAAAA); 202 | } 203 | \`; 204 | 205 | export default props => ( 206 | <> 207 |
208 |
209 | 210 | ); 211 | 212 | 213 | ↓ ↓ ↓ ↓ ↓ ↓ 214 | 215 | import _cssed_a from '../../.cssed/edb7e408acbb359c.module.css' 216 | const btn = _cssed_a 217 | export default (props) => ( 218 | <> 219 |
220 |
221 | 222 | ) 223 | 224 | `; 225 | -------------------------------------------------------------------------------- /src/__tests__/constant.js: -------------------------------------------------------------------------------- 1 | exports.dark = '#333' 2 | exports.light = '#ddd' 3 | -------------------------------------------------------------------------------- /src/__tests__/index.test.js: -------------------------------------------------------------------------------- 1 | import pluginTester from 'babel-plugin-tester' 2 | import plugin from '../../lib/index' 3 | 4 | pluginTester({ 5 | plugin, 6 | snapshot: true, 7 | babelOptions: { 8 | filename: __filename, 9 | parserOpts: { 10 | presets: [ 11 | [ 12 | 'env', 13 | { 14 | modules: 'commonjs' 15 | } 16 | ], 17 | 'react' 18 | ], 19 | plugins: ['jsx'] 20 | } 21 | }, 22 | tests: [ 23 | { 24 | title: 'single call macro', 25 | code: ` 26 | import { css } from 'cssed'; 27 | 28 | const styles = css\` 29 | .box { 30 | color: blue 31 | } 32 | \` 33 | ` 34 | }, 35 | { 36 | title: 'single call evaluation', 37 | code: ` 38 | import { css } from 'cssed'; 39 | 40 | const blue = 'blue' 41 | 42 | const styles = css\` 43 | .box { 44 | color: \${blue} 45 | } 46 | \` 47 | ` 48 | }, 49 | { 50 | title: 'multi call macro', 51 | code: ` 52 | import { css } from 'cssed'; 53 | 54 | const blue = css\` 55 | .box { 56 | color: blue; 57 | } 58 | \`; 59 | 60 | const red = css\` 61 | .box { 62 | color: red; 63 | } 64 | \`; 65 | 66 | export default props => ( 67 |
68 | ); 69 | ` 70 | }, 71 | { 72 | title: 'multi call with external dependency', 73 | code: ` 74 | import { css } from 'cssed'; 75 | import { light, dark } from './module' 76 | 77 | const btn = css\` 78 | .light { 79 | color: \${light}; 80 | } 81 | .dark { 82 | color: \${dark}; 83 | } 84 | \`; 85 | 86 | export default props => ( 87 | <> 88 |
89 |
90 | 91 | ); 92 | ` 93 | }, 94 | { 95 | title: 'multi call with external module dependency', 96 | code: ` 97 | import { css } from 'cssed'; 98 | import { light, dark } from './module' 99 | 100 | const btn = css\` 101 | .light { 102 | color: \${light}; 103 | } 104 | .dark { 105 | color: \${dark}; 106 | } 107 | \`; 108 | 109 | export default props => ( 110 | <> 111 |
112 |
113 | 114 | ); 115 | ` 116 | }, 117 | { 118 | title: 'function call in expression', 119 | code: ` 120 | import { css } from 'cssed'; 121 | import { light, dark } from './constant' 122 | 123 | const darkOrLight = (bool) => bool ? light : dark 124 | const btn = css\` 125 | .light { 126 | color: \${darkOrLight(true)}; 127 | } 128 | .dark { 129 | color: \${darkOrLight(false)}; 130 | } 131 | \`; 132 | 133 | export default props => ( 134 | <> 135 |
136 |
137 | 138 | ); 139 | ` 140 | }, 141 | { 142 | title: 'test url rebase', 143 | code: ` 144 | import { css } from 'cssed'; 145 | 146 | const btn = css\` 147 | .light { 148 | background-image: url("star.gif"); 149 | list-style-image: url('../images/bullet.jpg'); 150 | font-family: 'Open Sans', sans-serif; 151 | border-image: url('border.png'); 152 | content: url('/content.png'); 153 | content: url(data:image/png;base64,iVBORw0KGgoAAAA); 154 | } 155 | \`; 156 | 157 | export default props => ( 158 | <> 159 |
160 |
161 | 162 | ); 163 | ` 164 | } 165 | ] 166 | }) 167 | -------------------------------------------------------------------------------- /src/__tests__/module.js: -------------------------------------------------------------------------------- 1 | export const dark = '#333' 2 | export const light = '#ddd' 3 | -------------------------------------------------------------------------------- /src/babel/cache.ts: -------------------------------------------------------------------------------- 1 | import type Module from './module' 2 | import type { ITransformFileResult } from './types' 3 | 4 | export class TransformCacheCollection { 5 | constructor( 6 | public readonly resolveCache: Map = new Map(), 7 | public readonly codeCache: Map< 8 | string, 9 | { 10 | imports: Map | null 11 | only: string[] 12 | result: ITransformFileResult 13 | } 14 | > = new Map(), 15 | public readonly evalCache: Map = new Map() 16 | ) {} 17 | } 18 | -------------------------------------------------------------------------------- /src/babel/eval.ts: -------------------------------------------------------------------------------- 1 | import { types } from '@babel/core' 2 | import generator from '@babel/generator' 3 | 4 | import Module from './module' 5 | 6 | import type { NodePath } from '@babel/traverse' 7 | import type { Location, Value } from '../types' 8 | 9 | interface IRequirement { 10 | result: types.Node 11 | path: NodePath 12 | start: Location 13 | end: Location 14 | } 15 | 16 | const isAdded = (requirements: IRequirement[], path: NodePath): boolean => { 17 | if (requirements.some((req) => req.path === path)) { 18 | return true 19 | } 20 | 21 | if (path.parentPath) { 22 | return isAdded(requirements, path.parentPath) 23 | } 24 | 25 | return false 26 | } 27 | 28 | const resolve = ( 29 | path: NodePath, 30 | requirements: IRequirement[] 31 | ) => { 32 | const binding = path.scope.getBinding(path.node.name) 33 | 34 | if ( 35 | path.isReferenced() && 36 | binding && 37 | // Next condition it's always true because `params` isn't valid value 38 | (binding.kind as string) !== 'param' && 39 | !isAdded(requirements, binding.path) 40 | ) { 41 | let result 42 | 43 | switch (binding.kind) { 44 | case 'module': 45 | if (types.isImportSpecifier(binding.path as types.Node)) { 46 | const p = binding.path as NodePath 47 | result = types.importDeclaration( 48 | [p.node], 49 | (p.parentPath.node as types.ImportDeclaration).source 50 | ) 51 | } else { 52 | result = binding.path.parentPath!.node 53 | } 54 | break 55 | case 'const': 56 | case 'let': 57 | case 'var': { 58 | const { node } = binding.path as NodePath 59 | let decl 60 | 61 | // Replace SequenceExpressions (expr1, expr2, expr3, ...) with the last one 62 | if (types.isSequenceExpression(node.init)) { 63 | decl = types.variableDeclarator( 64 | node.id, 65 | node.init.expressions[node.init.expressions.length - 1] 66 | ) 67 | } else { 68 | decl = node 69 | } 70 | 71 | result = types.variableDeclaration(binding.kind, [decl]) 72 | break 73 | } 74 | default: 75 | result = binding.path.node 76 | break 77 | } 78 | 79 | const { loc } = binding.path.node 80 | 81 | requirements.push({ 82 | result, 83 | path: binding.path, 84 | start: loc!.start, 85 | end: loc!.end 86 | }) 87 | 88 | binding.path.traverse({ 89 | Identifier(p) { 90 | resolve(p, requirements) 91 | } 92 | }) 93 | } 94 | } 95 | 96 | export default function evaluate(path: any, t: any, filename: string) { 97 | if (t.isSequenceExpression(path)) { 98 | // We only need to evaluate the last item in a sequence expression, e.g. (a, b, c) 99 | // eslint-disable-next-line no-param-reassign 100 | path = path.get('expressions')[path.node.expressions.length - 1] 101 | } 102 | 103 | const requirements: IRequirement[] = [] 104 | 105 | if (t.isIdentifier(path)) { 106 | resolve(path, requirements) 107 | } else { 108 | path.traverse({ 109 | Identifier(p: NodePath) { 110 | resolve(p, requirements) 111 | } 112 | }) 113 | } 114 | 115 | const expression = t.expressionStatement( 116 | t.assignmentExpression( 117 | '=', 118 | t.memberExpression(t.identifier('module'), t.identifier('exports')), 119 | path.node 120 | ) 121 | ) 122 | 123 | // Preserve source order 124 | requirements.sort((a, b) => { 125 | if (a.start.line === b.start.line) { 126 | return a.start.column - b.start.column 127 | } 128 | 129 | return a.start.line - b.start.line 130 | }) 131 | 132 | // We'll wrap each code in a block to avoid collisions in variable names 133 | // We separate out the imports since they cannot be inside blocks 134 | const { imports, others } = requirements.reduce( 135 | (acc, curr) => { 136 | if (t.isImportDeclaration(curr.path.parentPath)) { 137 | acc.imports.push(curr.result) 138 | } else { 139 | // Add these in reverse because we'll need to wrap in block statements in reverse 140 | acc.others.unshift(curr.result) 141 | } 142 | 143 | return acc 144 | }, 145 | { imports: [] as types.Node[], others: [] as types.Node[] } 146 | ) 147 | 148 | const wrapped = others.reduce( 149 | (acc, curr) => t.blockStatement([curr, acc]), 150 | t.blockStatement([expression]) 151 | ) 152 | 153 | const m = new Module(filename, { 154 | extensions: ['.cjs', '.json', '.js', '.jsx', '.mjs', '.ts', '.tsx'], 155 | evaluate: true, 156 | babelOptions: {} 157 | }) 158 | 159 | m.dependencies = [] 160 | m.transform = function transform(this: Module, text) { 161 | return { code: text } 162 | } 163 | 164 | const code = [ 165 | imports.map((node) => String.raw`${generator(node, {}).code}`).join('\n'), 166 | String.raw`${generator(wrapped).code}` 167 | ].join('\n') 168 | 169 | m.evaluate(code) 170 | 171 | return { 172 | value: m.exports as Value, 173 | dependencies: m.dependencies 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /src/babel/module.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This is a custom implementation for the module system for evaluating code, 3 | * used for resolving values for dependencies interpolated in `css` or `styled`. 4 | * 5 | * This serves 2 purposes: 6 | * - Avoid leakage from evaluated code to module cache in current context, e.g. `babel-register` 7 | * - Allow us to invalidate the module cache without affecting other stuff, necessary for rebuilds 8 | * 9 | * We also use it to transpile the code with Babel by default. 10 | * We also store source maps for it to provide correct error stacktraces. 11 | * 12 | */ 13 | 14 | import fs from 'fs' 15 | import NativeModule from 'module' 16 | import path from 'path' 17 | import vm from 'vm' 18 | 19 | import { BabelFileResult, TransformOptions, transformSync } from '@babel/core' 20 | 21 | import getFileIdx from '../utils/getFileIdx' 22 | import type { StrictOptions } from './types' 23 | 24 | import debug from 'debug' 25 | 26 | import { TransformCacheCollection } from './cache' 27 | import * as process from './process' 28 | import type { ITransformFileResult } from './types' 29 | 30 | type HiddenModuleMembers = { 31 | _extensions: { [key: string]: () => void } 32 | _nodeModulePaths(filename: string): string[] 33 | _resolveFilename: ( 34 | id: string, 35 | options: { id: string; filename: string; paths: string[] } 36 | ) => string 37 | } 38 | 39 | const DefaultModuleImplementation = NativeModule as typeof NativeModule & 40 | HiddenModuleMembers 41 | 42 | // Supported node builtins based on the modules polyfilled by webpack 43 | // `true` means module is polyfilled, `false` means module is empty 44 | const builtins = { 45 | assert: true, 46 | buffer: true, 47 | child_process: false, 48 | cluster: false, 49 | console: true, 50 | constants: true, 51 | crypto: true, 52 | dgram: false, 53 | dns: false, 54 | domain: true, 55 | events: true, 56 | fs: false, 57 | http: true, 58 | https: true, 59 | module: false, 60 | net: false, 61 | os: true, 62 | path: true, 63 | punycode: true, 64 | process: true, 65 | querystring: true, 66 | readline: false, 67 | repl: false, 68 | stream: true, 69 | string_decoder: true, 70 | sys: true, 71 | timers: true, 72 | tls: false, 73 | tty: true, 74 | url: true, 75 | util: true, 76 | vm: true, 77 | zlib: true 78 | } 79 | 80 | const VALUES = Symbol('values') 81 | 82 | const isProxy = ( 83 | obj: unknown 84 | ): obj is { [VALUES]: Record } => 85 | typeof obj === 'object' && obj !== null && VALUES in obj 86 | 87 | const NOOP = () => {} 88 | 89 | const padStart = (num: number, len: number) => 90 | num.toString(10).padStart(len, '0') 91 | 92 | const hasKey = ( 93 | obj: unknown, 94 | key: TKey 95 | ): obj is Record => 96 | (typeof obj === 'object' || typeof obj === 'function') && 97 | obj !== null && 98 | key in obj 99 | 100 | class Module { 101 | #isEvaluated = false 102 | 103 | #exports: Record | unknown 104 | 105 | #lazyValues: Map unknown> 106 | 107 | readonly idx: number 108 | 109 | id: string 110 | 111 | filename: string 112 | 113 | options: StrictOptions 114 | 115 | imports: Map | null 116 | 117 | extensions: string[] 118 | 119 | dependencies: string[] | null 120 | 121 | transform: ((text: string) => BabelFileResult | null) | null 122 | 123 | debug: debug.Debugger 124 | 125 | readonly #resolveCache: Map 126 | 127 | readonly #codeCache: Map< 128 | string, 129 | { 130 | imports: Map | null 131 | only: string[] 132 | result: ITransformFileResult 133 | } 134 | > 135 | 136 | readonly #evalCache: Map 137 | 138 | constructor( 139 | filename: string, 140 | options: StrictOptions, 141 | cache = new TransformCacheCollection(), 142 | private debuggerDepth = 3, 143 | private parentModule?: Module, 144 | private moduleImpl: HiddenModuleMembers = DefaultModuleImplementation 145 | ) { 146 | this.idx = getFileIdx(filename) 147 | this.debug = debug('module:' + this.idx) 148 | this.debug.enabled = false 149 | 150 | this.id = filename 151 | this.filename = filename 152 | this.options = options 153 | this.imports = null 154 | this.dependencies = null 155 | this.transform = null 156 | this.#resolveCache = cache.resolveCache 157 | this.#codeCache = cache.codeCache 158 | this.#evalCache = cache.evalCache 159 | 160 | this.#lazyValues = new Map() 161 | 162 | const exports: Record = {} 163 | 164 | this.#exports = new Proxy(exports, { 165 | get: (target, key) => { 166 | if (key === VALUES) { 167 | const values: Record = {} 168 | this.#lazyValues.forEach((v, k) => { 169 | values[k] = v() 170 | }) 171 | 172 | return values 173 | } 174 | let value: unknown 175 | if (this.#lazyValues.has(key)) { 176 | value = this.#lazyValues.get(key)?.() 177 | } else { 178 | // Support Object.prototype methods on `exports` 179 | // e.g `exports.hasOwnProperty` 180 | value = Reflect.get(target, key) 181 | } 182 | 183 | if (value === undefined && this.#lazyValues.has('default')) { 184 | const defaultValue = this.#lazyValues.get('default')?.() 185 | if (hasKey(defaultValue, key)) { 186 | this.debug( 187 | 'evaluated', 188 | '⚠️ %s has been found in `default`. It indicates that ESM to CJS conversion of %s went wrong.', 189 | key, 190 | filename 191 | ) 192 | value = defaultValue[key] 193 | } 194 | } 195 | 196 | this.debug('evaluated', 'get %s: %o', key, value) 197 | return value 198 | }, 199 | has: (target, key) => { 200 | if (key === VALUES) return true 201 | return this.#lazyValues.has(key) 202 | }, 203 | ownKeys: () => { 204 | return Array.from(this.#lazyValues.keys()) 205 | }, 206 | set: (target, key, value) => { 207 | if (value !== undefined) { 208 | if (key !== '__esModule') { 209 | this.debug('evaluated', 'set %s: %o', key, value) 210 | } 211 | 212 | this.#lazyValues.set(key, () => value) 213 | } 214 | 215 | return true 216 | }, 217 | defineProperty: (target, key, descriptor) => { 218 | const { value } = descriptor 219 | if (value !== undefined) { 220 | this.#lazyValues.set(key, () => value) 221 | 222 | if (key !== '__esModule') { 223 | this.debug( 224 | 'evaluated', 225 | 'defineProperty %s with value %o', 226 | key, 227 | value 228 | ) 229 | } 230 | 231 | this.#lazyValues.set(key, () => value) 232 | 233 | return true 234 | } 235 | 236 | if ('get' in descriptor) { 237 | this.#lazyValues.set(key, descriptor.get!) 238 | this.debug('evaluated', 'defineProperty %s with getter', key) 239 | } 240 | 241 | return true 242 | }, 243 | getOwnPropertyDescriptor: (target, key) => { 244 | if (this.#lazyValues.has(key)) 245 | return { 246 | enumerable: true, 247 | configurable: true 248 | } 249 | 250 | return undefined 251 | } 252 | }) 253 | 254 | this.extensions = options.extensions 255 | this.debug('init', filename) 256 | } 257 | 258 | public get exports() { 259 | return this.#exports 260 | } 261 | 262 | public set exports(value) { 263 | if (isProxy(value)) { 264 | this.#exports = value[VALUES] 265 | } else { 266 | this.#exports = value 267 | } 268 | 269 | this.debug( 270 | 'evaluated', 271 | 'the whole exports was overridden with %O', 272 | this.#exports 273 | ) 274 | } 275 | 276 | resolve = (id: string) => { 277 | const resolveCacheKey = `${this.filename} -> ${id}` 278 | if (this.#resolveCache.has(resolveCacheKey)) { 279 | return this.#resolveCache.get(resolveCacheKey)! 280 | } 281 | 282 | const extensions = this.moduleImpl._extensions 283 | const added: string[] = [] 284 | 285 | try { 286 | // Check for supported extensions 287 | this.extensions.forEach((ext) => { 288 | if (ext in extensions) { 289 | return 290 | } 291 | 292 | // When an extension is not supported, add it 293 | // And keep track of it to clean it up after resolving 294 | // Use noop for the transform function since we handle it 295 | extensions[ext] = NOOP 296 | added.push(ext) 297 | }) 298 | 299 | const { filename } = this 300 | 301 | return this.moduleImpl._resolveFilename(id, { 302 | id: filename, 303 | filename, 304 | paths: this.moduleImpl._nodeModulePaths(path.dirname(filename)) 305 | }) 306 | } finally { 307 | // Cleanup the extensions we added to restore previous behaviour 308 | added.forEach((ext) => delete extensions[ext]) 309 | } 310 | } 311 | 312 | require: { 313 | (id: string): unknown 314 | resolve: (id: string) => string 315 | ensure: () => void 316 | } = Object.assign( 317 | (id: string) => { 318 | if (id in builtins) { 319 | // The module is in the allowed list of builtin node modules 320 | // Ideally we should prevent importing them, but webpack polyfills some 321 | // So we check for the list of polyfills to determine which ones to support 322 | if (builtins[id as keyof typeof builtins]) { 323 | this.debug('require', `builtin '${id}'`) 324 | return require(id) 325 | } 326 | 327 | return null 328 | } 329 | 330 | // Resolve module id (and filename) relatively to parent module 331 | const resolved = this.resolve(id) 332 | const [filename, onlyList] = resolved.split('\0') 333 | if (filename === id && !path.isAbsolute(id)) { 334 | // The module is a builtin node modules, but not in the allowed list 335 | throw new Error( 336 | `Unable to import "${id}". Importing Node builtins is not supported in the sandbox.` 337 | ) 338 | } 339 | 340 | this.dependencies?.push(id) 341 | 342 | let m: Module 343 | 344 | this.debug('require', `${id} -> ${filename}`) 345 | 346 | if (this.#evalCache.has(filename)) { 347 | m = this.#evalCache.get(filename)! 348 | this.debug('eval-cache', '✅ %r has been gotten from cache', { 349 | namespace: `module:${padStart(m.idx, 5)}` 350 | }) 351 | } else { 352 | this.debug('eval-cache', `➕ %r is going to be initialized`, { 353 | namespace: `module:${padStart(getFileIdx(filename), 5)}` 354 | }) 355 | // Create the module if cached module is not available 356 | m = new Module( 357 | filename, 358 | this.options, 359 | { 360 | codeCache: this.#codeCache, 361 | evalCache: this.#evalCache, 362 | resolveCache: this.#resolveCache 363 | }, 364 | this.debuggerDepth + 1, 365 | this 366 | ) 367 | m.transform = this.transform 368 | 369 | // Store it in cache at this point with, otherwise 370 | // we would end up in infinite loop with cyclic dependencies 371 | this.#evalCache.set(filename, m) 372 | } 373 | 374 | const extension = path.extname(filename) 375 | if (extension === '.json' || this.extensions.includes(extension)) { 376 | let code: string | undefined 377 | // Requested file can be already prepared for evaluation on the stage 1 378 | if (onlyList && this.#codeCache.has(filename)) { 379 | const cached = this.#codeCache.get(filename) 380 | const only = onlyList 381 | .split(',') 382 | .filter((token) => !m.#lazyValues.has(token)) 383 | const cachedOnly = new Set(cached?.only ?? []) 384 | const isMatched = 385 | cachedOnly.has('*') || 386 | (only && only.every((token) => cachedOnly.has(token))) 387 | if (cached && isMatched) { 388 | m.debug('code-cache', '✅') 389 | code = cached.result.code 390 | } else { 391 | m.debug( 392 | 'code-cache', 393 | '%o is missing (%o were cached)', 394 | only?.filter((token) => !cachedOnly.has(token)) ?? [], 395 | [...cachedOnly.values()] 396 | ) 397 | } 398 | } else if (m.#isEvaluated) { 399 | m.debug( 400 | 'code-cache', 401 | '✅ not in the code cache, but is already evaluated' 402 | ) 403 | } else { 404 | // If code wasn't extracted from cache, read it from the file system 405 | // TODO: transpile the file 406 | m.debug( 407 | 'code-cache', 408 | '❌ file has not been processed during prepare stage' 409 | ) 410 | code = fs.readFileSync(filename, 'utf-8') 411 | } 412 | 413 | if (code) { 414 | if (/\.json$/.test(filename)) { 415 | // For JSON files, parse it to a JS object similar to Node 416 | m.exports = JSON.parse(code) 417 | m.#isEvaluated = true 418 | } else { 419 | // For JS/TS files, evaluate the module 420 | m.evaluate(code) 421 | } 422 | } 423 | } else { 424 | // For non JS/JSON requires, just export the id 425 | // This is to support importing assets in webpack 426 | // The module will be resolved by css-loader 427 | m.exports = filename 428 | m.#isEvaluated = true 429 | } 430 | 431 | return m.exports 432 | }, 433 | { 434 | ensure: NOOP, 435 | resolve: this.resolve 436 | } 437 | ) 438 | 439 | evaluate(source: string): void { 440 | if (!source) { 441 | this.debug(`evaluate`, 'there is nothing to evaluate') 442 | } 443 | 444 | if (this.#isEvaluated) { 445 | this.debug('evaluate', `is already evaluated`) 446 | return 447 | } 448 | 449 | this.debug('evaluate', `\n${source}`) 450 | 451 | this.#isEvaluated = true 452 | 453 | const { filename } = this 454 | const context = vm.createContext({ 455 | clearImmediate: NOOP, 456 | clearInterval: NOOP, 457 | clearTimeout: NOOP, 458 | setImmediate: NOOP, 459 | setInterval: NOOP, 460 | setTimeout: NOOP, 461 | global, 462 | process, 463 | module: this, 464 | exports: this.#exports, 465 | require: this.require, 466 | __filename: filename, 467 | __dirname: path.dirname(filename) 468 | }) 469 | 470 | try { 471 | const opts: TransformOptions = { 472 | presets: ['@babel/preset-env'] 473 | } 474 | 475 | if (/\.tsx?$/.test(filename)) { 476 | opts.plugins = ['@babel/plugin-transform-typescript'] 477 | } 478 | 479 | const code = transformSync(source, opts) 480 | 481 | const script = new vm.Script(code!.code!, { 482 | filename 483 | }) 484 | 485 | script.runInContext(context) 486 | return 487 | } catch (e) { 488 | if (e instanceof EvalError) { 489 | throw e 490 | } 491 | 492 | const callstack: string[] = ['', filename] 493 | let module = this.parentModule 494 | while (module) { 495 | callstack.push(module.filename) 496 | module = module.parentModule 497 | } 498 | 499 | this.debug('evaluate:error', '%O\n%O', e, callstack) 500 | throw new EvalError( 501 | `${(e as Error).message} in${callstack.join('\n| ')}\n` 502 | ) 503 | } 504 | } 505 | } 506 | 507 | export default Module 508 | -------------------------------------------------------------------------------- /src/babel/process.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * It contains API for mocked process variable available in node environment used to evaluate scripts with node's `vm` in ./module.ts 3 | */ 4 | export const nextTick = (fn: (...args: unknown[]) => void) => setTimeout(fn, 0) 5 | 6 | export const platform = 'browser' 7 | export const arch = 'browser' 8 | export const execPath = 'browser' 9 | export const title = 'browser' 10 | export const pid = 1 11 | export const browser = true 12 | export const argv = [] 13 | 14 | export const binding = function binding() { 15 | throw new Error('No such module. (Possibly not yet loaded)') 16 | } 17 | 18 | export const cwd = () => '/' 19 | 20 | const noop = () => {} 21 | export const exit = noop 22 | export const kill = noop 23 | export const chdir = noop 24 | export const umask = noop 25 | export const dlopen = noop 26 | export const uptime = noop 27 | export const memoryUsage = noop 28 | export const uvCounters = noop 29 | export const features = {} 30 | 31 | export const { env } = process 32 | -------------------------------------------------------------------------------- /src/babel/types.ts: -------------------------------------------------------------------------------- 1 | import type { BabelFileMetadata, TransformOptions } from '@babel/core' 2 | 3 | export interface ITransformFileResult { 4 | metadata?: BabelFileMetadata 5 | code: string 6 | } 7 | 8 | export type StrictOptions = { 9 | babelOptions: TransformOptions 10 | evaluate: boolean 11 | extensions: string[] 12 | } 13 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import type babelCore from '@babel/core' 2 | import { createHash } from 'crypto' 3 | import { mkdirSync, readFileSync, writeFileSync } from 'fs' 4 | import { basename, dirname, join, relative, resolve } from 'path' 5 | import * as os from 'os' 6 | import TaggedTemplateExpression from './visitors/taggedTemplateExpression' 7 | const { addDefault } = require('@babel/helper-module-imports') 8 | 9 | type CSSProperties = { 10 | [key: string]: string | number | CSSProperties 11 | } 12 | 13 | // Exporting css function for proper typings when using it 14 | export function css( 15 | _strings: TemplateStringsArray, 16 | ..._exprs: Array 17 | ): { [ket: string]: string } { 18 | throw new Error( 19 | 'Using the "css" tag in runtime is not supported. Make sure you have set up the Babel plugin correctly.' 20 | ) 21 | } 22 | 23 | type VisitorState = { 24 | cssed: CSSed[] 25 | index: number 26 | } 27 | 28 | interface CSSed { 29 | importName: string 30 | cssText: string 31 | } 32 | 33 | const PACKAGE_NAME = 'cssed' 34 | 35 | const isWindows = os.platform() === 'win32' 36 | 37 | const normalizePath = (path: string): string => isWindows ? path.replace(/\\/g, '/') : path 38 | 39 | const CACHE_DIR = normalizePath(join(process.cwd(), '.cssed')) 40 | 41 | const createHashFn = (data: string, len: number) => { 42 | return createHash('shake256', { outputLength: len }) 43 | .update(data) 44 | .digest('hex') 45 | } 46 | 47 | const hash = (data: string) => createHashFn(data, 8) 48 | 49 | export default function cssedPlugin(): babelCore.PluginObj { 50 | mkdirSync(CACHE_DIR, { recursive: true }) 51 | const cwd = process.cwd() 52 | 53 | return { 54 | name: 'cssed', 55 | pre() { 56 | this.cssed = [] as CSSed[] 57 | this.index = 0 58 | }, 59 | post(file) { 60 | const filename = file.opts.filename 61 | // never 62 | if (!filename) return 63 | 64 | const dir = dirname(filename) 65 | const cleanFilename = basename(filename).replace(/\?.*$/, '') 66 | const relativeDirname = relative(cwd, dir) 67 | const relativeFilenamePath = normalizePath(join(relativeDirname, cleanFilename)) 68 | 69 | this.cssed.forEach(({ importName, cssText }, _, self) => { 70 | const multiple = self.length > 1 71 | 72 | // output css file 73 | const outFile = 74 | hash(relativeFilenamePath) + 75 | (multiple ? importName : '') + 76 | '.module.css' 77 | const outFilePath = normalizePath(join(CACHE_DIR, outFile)) 78 | const importFilePath = normalizePath(relative(dir, outFilePath)) 79 | 80 | /** 81 | * include this file as an import to the referenced module, 82 | * so that css-loader can pick it up at bundle - time. 83 | * 84 | * Macros runs in single file mode, so we can pass ['0'] reference. 85 | */ 86 | addDefault(file.path, importFilePath, { 87 | nameHint: '_cssed' + importName 88 | }) 89 | 90 | saveFileIfChanged(outFilePath, rebaseUrlInCss(cssText, dir, CACHE_DIR)) 91 | }) 92 | }, 93 | visitor: { 94 | ImportDeclaration(path) { 95 | if (path.node.source.value === PACKAGE_NAME) { 96 | path.remove() 97 | } 98 | }, 99 | TaggedTemplateExpression(path, state) { 100 | TaggedTemplateExpression(path, state as any) 101 | } 102 | } 103 | } 104 | } 105 | 106 | // Read the file first to compare the content 107 | // Write the new content only if it's changed 108 | // This will prevent unnecessary reloads 109 | const saveFileIfChanged = (filePath: string, cssText: string) => { 110 | let currentCssText 111 | 112 | try { 113 | currentCssText = readFileSync(filePath, 'utf-8') 114 | } catch (e) { 115 | // Ignore error 116 | } 117 | 118 | const warning = '/* AUTO GENERATED FILE. DO NOT EDIT */\n' 119 | const content = warning + cssText 120 | // if the files hasn't changed, nothing more to do 121 | 122 | if (currentCssText === content) return 123 | writeFileSync(filePath, content) 124 | } 125 | 126 | const rebaseUrlInCss = ( 127 | cssText: string, 128 | cssFileDir: string, 129 | cacheDir: string 130 | ) => { 131 | const regex = /url\((["']?)(.*?)\1\)/g 132 | 133 | const rebasedCSS = cssText.replace(regex, (match, quote, url) => { 134 | if (!/^(\/|data:|http[s]?)/i.test(url)) { 135 | const absolutePath = normalizePath(relative(cacheDir, resolve(cssFileDir, url))) 136 | // console.log('rebaseUrlInCss', resolve(cssFileDir, url), cacheDir, absolutePath, url) 137 | return `url(${quote}${absolutePath}${quote})` 138 | } 139 | return match 140 | }) 141 | 142 | return rebasedCSS 143 | } -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | export type Value = Function | string | number 2 | 3 | export type Location = { 4 | line: number 5 | column: number 6 | } 7 | 8 | interface JSONObject { 9 | [x: string]: JSONValue 10 | } 11 | 12 | type JSONArray = Array 13 | 14 | export type JSONValue = string | number | boolean | JSONObject | JSONArray 15 | 16 | export type Serializable = JSONArray | JSONObject 17 | -------------------------------------------------------------------------------- /src/utils/getFileIdx.ts: -------------------------------------------------------------------------------- 1 | let nextIdx = 1 2 | const processed = new Map() 3 | 4 | export default function getFileIdx(name: string): number { 5 | if (!processed.has(name)) { 6 | // eslint-disable-next-line no-plusplus 7 | processed.set(name, nextIdx++) 8 | } 9 | 10 | return processed.get(name)! 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/isBoxedPrimitive.ts: -------------------------------------------------------------------------------- 1 | // There is a problem with using boxed numbers and strings in TS, 2 | // so we cannot just use `instanceof` here 3 | 4 | const constructors = ['Number', 'String'] 5 | // eslint-disable-next-line @typescript-eslint/ban-types 6 | export default function isBoxedPrimitive(o: any): o is Number | String { 7 | return ( 8 | constructors.includes(o.constructor.name) && 9 | typeof o?.valueOf() !== 'object' 10 | ) 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/isSerializable.ts: -------------------------------------------------------------------------------- 1 | import type { Serializable } from '../types' 2 | 3 | import isBoxedPrimitive from './isBoxedPrimitive' 4 | 5 | export default function isSerializable(o: unknown): o is Serializable { 6 | if (Array.isArray(o)) { 7 | return o.every(isSerializable) 8 | } 9 | 10 | if (o === null) return true 11 | 12 | if (isBoxedPrimitive(o)) return true 13 | 14 | if (typeof o === 'object') { 15 | return Object.values(o).every(isSerializable) 16 | } 17 | 18 | return ( 19 | typeof o === 'string' || typeof o === 'number' || typeof o === 'boolean' 20 | ) 21 | } 22 | -------------------------------------------------------------------------------- /src/utils/numToChar.ts: -------------------------------------------------------------------------------- 1 | export default function numToChar(num: number) { 2 | var s = '', 3 | t 4 | 5 | while (num > 0) { 6 | t = (num - 1) % 26 7 | s = String.fromCharCode(97 + t) + s 8 | num = ((num - t) / 26) | 0 9 | } 10 | return s || undefined 11 | } 12 | -------------------------------------------------------------------------------- /src/utils/stripLines.ts: -------------------------------------------------------------------------------- 1 | import type { Location } from '../types' 2 | 3 | // Stripping away the new lines ensures that we preserve line numbers 4 | // This is useful in case of tools such as the stylelint pre-processor 5 | // This should be safe because strings cannot contain newline: https://www.w3.org/TR/CSS2/syndata.html#strings 6 | export default function stripLines( 7 | loc: { start: Location; end: Location }, 8 | text: string | number 9 | ) { 10 | let result = String(text) 11 | .replace(/[\r\n]+/g, ' ') 12 | .trim() 13 | 14 | // If the start and end line numbers aren't same, add new lines to span the text across multiple lines 15 | if (loc.start.line !== loc.end.line) { 16 | result += '\n'.repeat(loc.end.line - loc.start.line) 17 | 18 | // Add extra spaces to offset the column 19 | result += ' '.repeat(loc.end.column) 20 | } 21 | 22 | return result 23 | } 24 | -------------------------------------------------------------------------------- /src/utils/throwIfInvalid.ts: -------------------------------------------------------------------------------- 1 | import generator from '@babel/generator' 2 | 3 | import isSerializable from './isSerializable' 4 | 5 | import type { Serializable } from '../types' 6 | 7 | // Throw if we can't handle the interpolated value 8 | export default function throwIfInvalid( 9 | value: Error | Function | string | number | Serializable | undefined, 10 | ex: any 11 | ): void { 12 | if ( 13 | typeof value === 'function' || 14 | typeof value === 'string' || 15 | (typeof value === 'number' && Number.isFinite(value)) || 16 | isSerializable(value) 17 | ) { 18 | return 19 | } 20 | 21 | // We can't use instanceof here so let's use duck typing 22 | if (value && typeof value !== 'number' && value.stack && value.message) { 23 | throw ex.buildCodeFrameError( 24 | `An error occurred when evaluating the expression: 25 | 26 | > ${value.message}. 27 | 28 | Make sure you are not using a browser or Node specific API and all the variables are available in static context. 29 | Cssed have to extract pieces of your code to resolve the interpolated values. 30 | Defining styled component or class will not work inside: 31 | - function, 32 | - class, 33 | - method, 34 | - loop, 35 | because it cannot be statically determined in which context you use them. 36 | That's why some variables may be not defined during evaluation. 37 | ` 38 | ) 39 | } 40 | 41 | const stringified = 42 | typeof value === 'object' ? JSON.stringify(value) : String(value) 43 | 44 | throw ex.buildCodeFrameError( 45 | `The expression evaluated to '${stringified}', which is probably a mistake. If you want it to be inserted into CSS, explicitly cast or transform the value to a string, e.g. - 'String(${ 46 | generator(ex.node).code 47 | })'.` 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /src/utils/toCSS.ts: -------------------------------------------------------------------------------- 1 | // TypeScript Version: 3.2 2 | import isBoxedPrimitive from './isBoxedPrimitive' 3 | import isSerializable from './isSerializable' 4 | import { unitless } from './units' 5 | 6 | import type { JSONValue } from '../types' 7 | 8 | const hyphenate = (s: string) => 9 | s 10 | // Hyphenate CSS property names from camelCase version from JS string 11 | .replace(/([A-Z])/g, (match, p1) => `-${p1.toLowerCase()}`) 12 | // Special case for `-ms` because in JS it starts with `ms` unlike `Webkit` 13 | .replace(/^ms-/, '-ms-') 14 | 15 | // Some tools such as polished.js output JS objects 16 | // To support them transparently, we convert JS objects to CSS strings 17 | export default function toCSS(o: JSONValue): string { 18 | if (Array.isArray(o)) { 19 | return o.map(toCSS).join('\n') 20 | } 21 | 22 | if (isBoxedPrimitive(o)) { 23 | return o.valueOf().toString() 24 | } 25 | 26 | return Object.entries(o) 27 | .filter( 28 | ([, value]) => 29 | // Ignore all falsy values except numbers 30 | typeof value === 'number' || value 31 | ) 32 | .map(([key, value]) => { 33 | if (isSerializable(value)) { 34 | return `${key} { ${toCSS(value)} }` 35 | } 36 | 37 | return `${hyphenate(key)}: ${ 38 | typeof value === 'number' && 39 | value !== 0 && 40 | // Strip vendor prefixes when checking if the value is unitless 41 | !( 42 | key.replace( 43 | /^(Webkit|Moz|O|ms)([A-Z])(.+)$/, 44 | (match, p1, p2, p3) => `${p2.toLowerCase()}${p3}` 45 | ) in unitless 46 | ) 47 | ? `${value}px` 48 | : value 49 | };` 50 | }) 51 | .join(' ') 52 | } 53 | -------------------------------------------------------------------------------- /src/utils/units.ts: -------------------------------------------------------------------------------- 1 | // https://www.w3.org/TR/css-values-4/ 2 | export const units = [ 3 | // font relative lengths 4 | 'em', 5 | 'ex', 6 | 'cap', 7 | 'ch', 8 | 'ic', 9 | 'rem', 10 | 'lh', 11 | 'rlh', 12 | 13 | // viewport percentage lengths 14 | 'vw', 15 | 'vh', 16 | 'vi', 17 | 'vb', 18 | 'vmin', 19 | 'vmax', 20 | 21 | // absolute lengths 22 | 'cm', 23 | 'mm', 24 | 'Q', 25 | 'in', 26 | 'pc', 27 | 'pt', 28 | 'px', 29 | 30 | // angle units 31 | 'deg', 32 | 'grad', 33 | 'rad', 34 | 'turn', 35 | 36 | // duration units 37 | 's', 38 | 'ms', 39 | 40 | // frequency units 41 | 'Hz', 42 | 'kHz', 43 | 44 | // resolution units 45 | 'dpi', 46 | 'dpcm', 47 | 'dppx', 48 | 'x', 49 | 50 | // https://www.w3.org/TR/css-grid-1/#fr-unit 51 | 'fr', 52 | 53 | // percentages 54 | '%' 55 | ] 56 | 57 | export const unitless = { 58 | animationIterationCount: true, 59 | borderImageOutset: true, 60 | borderImageSlice: true, 61 | borderImageWidth: true, 62 | boxFlex: true, 63 | boxFlexGroup: true, 64 | boxOrdinalGroup: true, 65 | columnCount: true, 66 | columns: true, 67 | flex: true, 68 | flexGrow: true, 69 | flexPositive: true, 70 | flexShrink: true, 71 | flexNegative: true, 72 | flexOrder: true, 73 | gridRow: true, 74 | gridRowEnd: true, 75 | gridRowSpan: true, 76 | gridRowStart: true, 77 | gridColumn: true, 78 | gridColumnEnd: true, 79 | gridColumnSpan: true, 80 | gridColumnStart: true, 81 | fontWeight: true, 82 | lineClamp: true, 83 | lineHeight: true, 84 | opacity: true, 85 | order: true, 86 | orphans: true, 87 | tabSize: true, 88 | widows: true, 89 | zIndex: true, 90 | zoom: true, 91 | 92 | // SVG-related properties 93 | fillOpacity: true, 94 | floodOpacity: true, 95 | stopOpacity: true, 96 | strokeDasharray: true, 97 | strokeDashoffset: true, 98 | strokeMiterlimit: true, 99 | strokeOpacity: true, 100 | strokeWidth: true 101 | } 102 | -------------------------------------------------------------------------------- /src/visitors/taggedTemplateExpression.ts: -------------------------------------------------------------------------------- 1 | import { types } from '@babel/core' 2 | import { NodePath } from '@babel/traverse' 3 | 4 | import evaluate from '../babel/eval' 5 | import isSerializable from '../utils/isSerializable' 6 | import numToChar from '../utils/numToChar' 7 | import stripLines from '../utils/stripLines' 8 | import throwIfInvalid from '../utils/throwIfInvalid' 9 | import toCSS from '../utils/toCSS' 10 | import { units } from '../utils/units' 11 | 12 | // Match any valid CSS units followed by a separator such as ;, newline etc. 13 | const unitRegex = new RegExp(`^(${units.join('|')})(;|,|\n| |\\))`) 14 | 15 | type Interpolation = { 16 | id: string 17 | node: types.Expression 18 | source: string 19 | unit: string 20 | } 21 | 22 | interface CSSed { 23 | importName: string 24 | cssText: string 25 | } 26 | 27 | interface State extends babel.PluginPass { 28 | cssed: CSSed[] 29 | index: number 30 | } 31 | 32 | function isRef(path: NodePath) { 33 | let isReferenced = true 34 | 35 | const parent = path.findParent( 36 | (p) => 37 | types.isObjectProperty(p as types.Node) || 38 | types.isJSXOpeningElement(p as types.Node) || 39 | types.isVariableDeclarator(p as types.Node) 40 | ) 41 | 42 | if (parent) { 43 | const parentNode = parent.node 44 | if ( 45 | types.isVariableDeclarator(parentNode) && 46 | types.isIdentifier(parentNode.id) 47 | ) { 48 | const { referencePaths } = path.scope.getBinding(parentNode.id.name) || { 49 | referencePaths: [] 50 | } 51 | 52 | isReferenced = referencePaths.length !== 0 53 | } 54 | } 55 | 56 | return isReferenced 57 | } 58 | 59 | export default function TaggedTemplateExpression( 60 | path: NodePath, 61 | state: State 62 | ) { 63 | const { quasi } = path.node 64 | 65 | // Increment the index of the style we're processing 66 | // Used for style import variable name generation 67 | state.index++ 68 | 69 | const interpolations: Interpolation[] = [] 70 | 71 | // Check if the variable is referenced anywhere for basic DCE 72 | // Only works when it's assigned to a variable 73 | let isReferenced = isRef(path) 74 | 75 | // Serialize the tagged template literal to a string 76 | let cssText = '' 77 | 78 | const expressions = path.get('quasi').get('expressions') 79 | 80 | quasi.quasis.forEach((el, i, self) => { 81 | let appended = false 82 | 83 | if (i !== 0 && el.value.cooked) { 84 | // Check if previous expression was a CSS variable that we replaced 85 | // If it has a unit after it, we need to move the unit into the interpolation 86 | // e.g. `var(--size)px` should actually be `var(--size)` 87 | // So we check if the current text starts with a unit, and add the unit to the previous interpolation 88 | // Another approach would be `calc(var(--size) * 1px), but some browsers don't support all units 89 | // https://bugzilla.mozilla.org/show_bug.cgi?id=956573 90 | const matches = el.value.cooked.match(unitRegex) 91 | 92 | if (matches) { 93 | const last = interpolations[interpolations.length - 1] 94 | const [, unit] = matches 95 | 96 | if (last && cssText.endsWith(`var(--${last.id})`)) { 97 | last.unit = unit 98 | cssText += el.value.cooked.replace(unitRegex, '$2') 99 | appended = true 100 | } 101 | } 102 | } 103 | 104 | if (!appended) { 105 | cssText += el.value.cooked 106 | } 107 | 108 | const ex = expressions[i] 109 | 110 | if (ex) { 111 | const { end } = ex.node.loc! 112 | const result = ex.evaluate() 113 | 114 | // The location will be end of the current string to start of next string 115 | const next = self[i + 1] 116 | const loc = { 117 | // +1 because the expressions location always shows 1 column before 118 | start: { line: el.loc!.end.line, column: el.loc!.end.column + 1 }, 119 | end: next 120 | ? { line: next.loc!.start.line, column: next.loc!.start.column } 121 | : { line: end.line, column: end.column + 1 } 122 | } 123 | 124 | if (result.confident) { 125 | throwIfInvalid(result.value, ex) 126 | 127 | if (isSerializable(result.value)) { 128 | // If it's a plain object, convert it to a CSS string 129 | cssText += stripLines(loc, toCSS(result.value)) 130 | } else { 131 | cssText += stripLines(loc, result.value) 132 | } 133 | } else { 134 | // Try to preval the value 135 | if ( 136 | !( 137 | types.isFunctionExpression(ex as types.Node) || 138 | types.isArrowFunctionExpression(ex as types.Node) 139 | ) 140 | ) { 141 | let evaluation 142 | 143 | try { 144 | evaluation = evaluate(ex, types, state.file.opts.filename!) 145 | } catch (e) { 146 | throw ex.buildCodeFrameError( 147 | `An error occurred when evaluating the expression: ${ 148 | (e as Error).message 149 | }. Make sure you are not using a browser or Node specific API.` 150 | ) 151 | } 152 | 153 | const { value } = evaluation 154 | 155 | throwIfInvalid(value, ex) 156 | 157 | // Only insert text for non functions 158 | // We don't touch functions because they'll be interpolated at runtime 159 | if (typeof value !== 'function') { 160 | if (isSerializable(value)) { 161 | cssText += stripLines(loc, toCSS(value)) 162 | } else { 163 | // For anything else, assume it'll be stringified 164 | cssText += stripLines(loc, value) 165 | } 166 | return 167 | } 168 | } 169 | 170 | // CSS custom properties can't be used outside components 171 | throw ex.buildCodeFrameError( 172 | `The CSS cannot contain JavaScript expressions when using the 'css' tag. To evaluate the expressions at build time, pass 'evaluate: true' to the babel plugin.` 173 | ) 174 | } 175 | } 176 | }) 177 | 178 | const importName = `_${numToChar(state.index)}` 179 | path.replaceWith(types.identifier('_cssed' + importName)) 180 | 181 | state.cssed.push({ 182 | cssText, 183 | importName 184 | }) 185 | 186 | if (!isReferenced && !cssText.includes(':global')) { 187 | return 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "outDir": "./lib", 4 | "declarationDir": "./lib", 5 | "target": "esnext", 6 | "lib": ["esnext"], 7 | "sourceMap": true, 8 | "declaration": true, 9 | "module": "CommonJS", 10 | "strict": true, 11 | "experimentalDecorators": true, 12 | "allowSyntheticDefaultImports": true, 13 | "typeRoots": ["node_modules/@types"], 14 | "moduleResolution": "node", 15 | "skipLibCheck": true, 16 | "esModuleInterop": true, 17 | "skipDefaultLibCheck": true, 18 | "preserveWatchOutput": true 19 | }, 20 | "include": ["src"], 21 | "exclude": ["./lib/**/*", "node_modules"] 22 | } 23 | -------------------------------------------------------------------------------- /vite-plugin.d.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from 'vite' 2 | declare const cssedPlugin: () => Plugin 3 | export default cssedPlugin 4 | -------------------------------------------------------------------------------- /vite-plugin.js: -------------------------------------------------------------------------------- 1 | const { transformAsync } = require('@babel/core') 2 | 3 | const sourceRegex = /\.(j|t)sx?$/ 4 | const tsxRegex = /\.(j|t)sx$/ // all files are being interpreted as TS, so we'll treat JSX as TSX 5 | 6 | module.exports = function viteCssedPlugin() { 7 | return { 8 | name: 'cssed-plugin', 9 | enforce: 'pre', 10 | async transform(source, filename) { 11 | if (filename.includes('node_modules')) { 12 | return undefined 13 | } 14 | 15 | if (!sourceRegex.test(filename)) { 16 | return undefined 17 | } 18 | 19 | if (!source.includes('import { css } from')) return undefined 20 | 21 | const result = await transformAsync(source, { 22 | filename, 23 | plugins: [ 24 | require.resolve('@babel/plugin-syntax-jsx'), 25 | [ 26 | require.resolve('@babel/plugin-syntax-typescript'), 27 | { isTSX: tsxRegex.test(filename) } 28 | ], 29 | require.resolve('./lib/index.js') 30 | ], 31 | babelrc: false, 32 | configFile: false, 33 | sourceMaps: true 34 | }) 35 | 36 | return result 37 | } 38 | } 39 | } 40 | --------------------------------------------------------------------------------