├── .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 |
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 |
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 |
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 | setCount((count) => count + 1)}>
9 | Counter {count}
10 |
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 |
22 | Rendered to HTML.
23 |
24 | Interactive.
25 |
26 |
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 Increment
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 Decrement
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 |
--------------------------------------------------------------------------------