diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 357d2cb..d530241 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -8,7 +8,10 @@ on:
jobs:
build:
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
+ strategy:
+ matrix:
+ os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v4
@@ -19,7 +22,7 @@ jobs:
- name: Setup Node.js environment
uses: actions/setup-node@v4
with:
- node-version: 20
+ node-version: 24
- name: Install dependencies
run: pnpm install --ignore-scripts
@@ -28,3 +31,5 @@ jobs:
run: pnpm build
- name: Test all packages
run: pnpm test
+ env:
+ BEGIT_GH_API_KEY: ${{ secrets.GITHUB_TOKEN }}
diff --git a/.gitignore b/.gitignore
index b1d8509..ba04bab 100644
--- a/.gitignore
+++ b/.gitignore
@@ -135,5 +135,8 @@ dist
.yarn/install-state.gz
.pnp.*
-# Testing directory
-testing
\ No newline at end of file
+# Test directory
+test
+
+# Build output
+types
\ No newline at end of file
diff --git a/README.md b/README.md
index 3e4293c..aa0e49a 100644
--- a/README.md
+++ b/README.md
@@ -2,64 +2,19 @@
-> [!WARNING]
-> This project is under heavy development and is not yet complete. More features coming soon!
-
# Solid CLI
[](https://github.com/solidjs-community/solid-cli/actions/workflows/tests.yml)
[](https://app.netlify.com/sites/solid-cli/deploys)
-A custom-built CLI for creating and managing SolidJS apps and projects.
-
-## Roadmap/Features
-
-- [x] Templates
- - [x] From Degit
-- [x] Docs
-- [ ] Primitives
- - [ ] Add/remove/update primitives
- - [x] Search list of primitives
-- [ ] Integrations
- - [ ] Auth.js
- - [x] Tailwind
- - [ ] PandaCSS
- - [ ] Cypress
- - [ ] PostCSS
- - [x] UnoCSS
- - [ ] Vanilla Extract
- - [x] Vitest
- - [x] Tauri
- - [ ] Playwright
-- [ ] Utilities
- - [ ] eslint-plugin-solid
- - [x] solid-devtools
-- [ ] Misc
- - [x] Launch new Stackblitz
- - [ ] Launch new CodeSandBox
-- [x] SolidStart
- - [x] New route
- - [x] New data file
- - [x] Enable Adapters
- - [x] Enable SSR/CSR/SSG mode
-
-## Structure
+A CLI for creating and managing SolidJS apps and projects.
-The CLI is invoked with `solid`. The commands then cascade, where actions are grouped with other similar actions. The actions will be:
+## Commands
-- `version`: Displays a changelog of recent Solid versions
- - `start`: Specific command for Start versions
-- `docs`: List a `man`-like page for versioned docs or link out to the docs
-- `primitives`: Potential integration with Solid Primitives
-- `add`, `remove`: Used for adding and installing integrations/packages ie. `solid add tailwind`
-- `config`: For enabling a certain features ie. `solid config vite _____`
-- `start`: Special keyword for SolidStart commands
- - `mode`: Changes the Start serving mode (ssr/csr/ssg) `solid mode ssr`
- - `route`: Creates a new route ie. `solid start route login`
-- `new`: Opens your browser to a new template via CSB/SB ie. `solid new bare --stackblitz` opens
-- `ecosystem`
- - `add`: Starts the process of submitting your current project to our ecosystem listing (Solidex) ie. `solid ecosystem publish`
- - `search`: Initializes an ecosystem search result `solid ecosystem search auth`
+- `sd create`: See [create-solid](./packages/create-solid)
+- `sd docs`: Opens the Solid docs in the browser
+- `sd start`: Special keyword for SolidStart commands
+ - `route`: Creates a new route ie. `sd start route login`
## Contributing
diff --git a/docs/.gitignore b/docs/.gitignore
deleted file mode 100644
index f3c937e..0000000
--- a/docs/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-vitepress_docs/.vitepress/cache
\ No newline at end of file
diff --git a/docs/package.json b/docs/package.json
deleted file mode 100644
index fc7fb0a..0000000
--- a/docs/package.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "private": true,
- "type": "module",
- "scripts": {
- "docs:dev": "vitepress dev vitepress_docs",
- "docs:build": "vitepress build vitepress_docs",
- "docs:preview": "vitepress preview vitepress_docs"
- },
- "devDependencies": {
- "flexsearch": "^0.7.43",
- "vitepress": "1.1.3",
- "vitepress-plugin-search": "1.0.4-alpha.22",
- "vue": "^3.4.23"
- }
-}
diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml
deleted file mode 100644
index 37323a0..0000000
--- a/docs/pnpm-lock.yaml
+++ /dev/null
@@ -1,1135 +0,0 @@
-lockfileVersion: '6.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-importers:
-
- .:
- devDependencies:
- flexsearch:
- specifier: ^0.7.43
- version: 0.7.43
- vitepress:
- specifier: 1.1.3
- version: 1.1.3(@algolia/client-search@4.22.1)(search-insights@2.13.0)
- vitepress-plugin-search:
- specifier: 1.0.4-alpha.22
- version: 1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.1.3)(vue@3.4.23)
- vue:
- specifier: ^3.4.23
- version: 3.4.23
-
-packages:
-
- /@algolia/autocomplete-core@1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0):
- resolution: {integrity: sha512-009HdfugtGCdC4JdXUbVJClA0q0zh24yyePn+KUGk3rP7j8FEe/m5Yo/z65gn6nP/cM39PxpzqKrL7A6fP6PPw==}
- dependencies:
- '@algolia/autocomplete-plugin-algolia-insights': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0)
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)
- transitivePeerDependencies:
- - '@algolia/client-search'
- - algoliasearch
- - search-insights
- dev: true
-
- /@algolia/autocomplete-plugin-algolia-insights@1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0):
- resolution: {integrity: sha512-a/yTUkcO/Vyy+JffmAnTWbr4/90cLzw+CC3bRbhnULr/EM0fGNvM13oQQ14f2moLMcVDyAx/leczLlAOovhSZg==}
- peerDependencies:
- search-insights: '>= 1 < 3'
- dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)
- search-insights: 2.13.0
- transitivePeerDependencies:
- - '@algolia/client-search'
- - algoliasearch
- dev: true
-
- /@algolia/autocomplete-preset-algolia@1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1):
- resolution: {integrity: sha512-d4qlt6YmrLMYy95n5TB52wtNDr6EgAIPH81dvvvW8UmuWRgxEtY0NJiPwl/h95JtG2vmRM804M0DSwMCNZlzRA==}
- peerDependencies:
- '@algolia/client-search': '>= 4.9.1 < 6'
- algoliasearch: '>= 4.9.1 < 6'
- dependencies:
- '@algolia/autocomplete-shared': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)
- '@algolia/client-search': 4.22.1
- algoliasearch: 4.22.1
- dev: true
-
- /@algolia/autocomplete-shared@1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1):
- resolution: {integrity: sha512-Wnm9E4Ye6Rl6sTTqjoymD+l8DjSTHsHboVRYrKgEt8Q7UHm9nYbqhN/i0fhUYA3OAEH7WA8x3jfpnmJm3rKvaQ==}
- peerDependencies:
- '@algolia/client-search': '>= 4.9.1 < 6'
- algoliasearch: '>= 4.9.1 < 6'
- dependencies:
- '@algolia/client-search': 4.22.1
- algoliasearch: 4.22.1
- dev: true
-
- /@algolia/cache-browser-local-storage@4.22.1:
- resolution: {integrity: sha512-Sw6IAmOCvvP6QNgY9j+Hv09mvkvEIDKjYW8ow0UDDAxSXy664RBNQk3i/0nt7gvceOJ6jGmOTimaZoY1THmU7g==}
- dependencies:
- '@algolia/cache-common': 4.22.1
- dev: true
-
- /@algolia/cache-common@4.22.1:
- resolution: {integrity: sha512-TJMBKqZNKYB9TptRRjSUtevJeQVXRmg6rk9qgFKWvOy8jhCPdyNZV1nB3SKGufzvTVbomAukFR8guu/8NRKBTA==}
- dev: true
-
- /@algolia/cache-in-memory@4.22.1:
- resolution: {integrity: sha512-ve+6Ac2LhwpufuWavM/aHjLoNz/Z/sYSgNIXsinGofWOysPilQZPUetqLj8vbvi+DHZZaYSEP9H5SRVXnpsNNw==}
- dependencies:
- '@algolia/cache-common': 4.22.1
- dev: true
-
- /@algolia/client-account@4.22.1:
- resolution: {integrity: sha512-k8m+oegM2zlns/TwZyi4YgCtyToackkOpE+xCaKCYfBfDtdGOaVZCM5YvGPtK+HGaJMIN/DoTL8asbM3NzHonw==}
- dependencies:
- '@algolia/client-common': 4.22.1
- '@algolia/client-search': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /@algolia/client-analytics@4.22.1:
- resolution: {integrity: sha512-1ssi9pyxyQNN4a7Ji9R50nSdISIumMFDwKNuwZipB6TkauJ8J7ha/uO60sPJFqQyqvvI+px7RSNRQT3Zrvzieg==}
- dependencies:
- '@algolia/client-common': 4.22.1
- '@algolia/client-search': 4.22.1
- '@algolia/requester-common': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /@algolia/client-common@4.22.1:
- resolution: {integrity: sha512-IvaL5v9mZtm4k4QHbBGDmU3wa/mKokmqNBqPj0K7lcR8ZDKzUorhcGp/u8PkPC/e0zoHSTvRh7TRkGX3Lm7iOQ==}
- dependencies:
- '@algolia/requester-common': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /@algolia/client-personalization@4.22.1:
- resolution: {integrity: sha512-sl+/klQJ93+4yaqZ7ezOttMQ/nczly/3GmgZXJ1xmoewP5jmdP/X/nV5U7EHHH3hCUEHeN7X1nsIhGPVt9E1cQ==}
- dependencies:
- '@algolia/client-common': 4.22.1
- '@algolia/requester-common': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /@algolia/client-search@4.22.1:
- resolution: {integrity: sha512-yb05NA4tNaOgx3+rOxAmFztgMTtGBi97X7PC3jyNeGiwkAjOZc2QrdZBYyIdcDLoI09N0gjtpClcackoTN0gPA==}
- dependencies:
- '@algolia/client-common': 4.22.1
- '@algolia/requester-common': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /@algolia/logger-common@4.22.1:
- resolution: {integrity: sha512-OnTFymd2odHSO39r4DSWRFETkBufnY2iGUZNrMXpIhF5cmFE8pGoINNPzwg02QLBlGSaLqdKy0bM8S0GyqPLBg==}
- dev: true
-
- /@algolia/logger-console@4.22.1:
- resolution: {integrity: sha512-O99rcqpVPKN1RlpgD6H3khUWylU24OXlzkavUAMy6QZd1776QAcauE3oP8CmD43nbaTjBexZj2nGsBH9Tc0FVA==}
- dependencies:
- '@algolia/logger-common': 4.22.1
- dev: true
-
- /@algolia/requester-browser-xhr@4.22.1:
- resolution: {integrity: sha512-dtQGYIg6MteqT1Uay3J/0NDqD+UciHy3QgRbk7bNddOJu+p3hzjTRYESqEnoX/DpEkaNYdRHUKNylsqMpgwaEw==}
- dependencies:
- '@algolia/requester-common': 4.22.1
- dev: true
-
- /@algolia/requester-common@4.22.1:
- resolution: {integrity: sha512-dgvhSAtg2MJnR+BxrIFqlLtkLlVVhas9HgYKMk2Uxiy5m6/8HZBL40JVAMb2LovoPFs9I/EWIoFVjOrFwzn5Qg==}
- dev: true
-
- /@algolia/requester-node-http@4.22.1:
- resolution: {integrity: sha512-JfmZ3MVFQkAU+zug8H3s8rZ6h0ahHZL/SpMaSasTCGYR5EEJsCc8SI5UZ6raPN2tjxa5bxS13BRpGSBUens7EA==}
- dependencies:
- '@algolia/requester-common': 4.22.1
- dev: true
-
- /@algolia/transporter@4.22.1:
- resolution: {integrity: sha512-kzWgc2c9IdxMa3YqA6TN0NW5VrKYYW/BELIn7vnLyn+U/RFdZ4lxxt9/8yq3DKV5snvoDzzO4ClyejZRdV3lMQ==}
- dependencies:
- '@algolia/cache-common': 4.22.1
- '@algolia/logger-common': 4.22.1
- '@algolia/requester-common': 4.22.1
- dev: true
-
- /@babel/helper-string-parser@7.23.4:
- resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==}
- engines: {node: '>=6.9.0'}
- dev: true
-
- /@babel/helper-validator-identifier@7.22.20:
- resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==}
- engines: {node: '>=6.9.0'}
- dev: true
-
- /@babel/parser@7.24.4:
- resolution: {integrity: sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==}
- engines: {node: '>=6.0.0'}
- hasBin: true
- dependencies:
- '@babel/types': 7.24.0
- dev: true
-
- /@babel/types@7.24.0:
- resolution: {integrity: sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==}
- engines: {node: '>=6.9.0'}
- dependencies:
- '@babel/helper-string-parser': 7.23.4
- '@babel/helper-validator-identifier': 7.22.20
- to-fast-properties: 2.0.0
- dev: true
-
- /@docsearch/css@3.6.0:
- resolution: {integrity: sha512-+sbxb71sWre+PwDK7X2T8+bhS6clcVMLwBPznX45Qu6opJcgRjAp7gYSDzVFp187J+feSj5dNBN1mJoi6ckkUQ==}
- dev: true
-
- /@docsearch/js@3.6.0(@algolia/client-search@4.22.1)(search-insights@2.13.0):
- resolution: {integrity: sha512-QujhqINEElrkIfKwyyyTfbsfMAYCkylInLYMRqHy7PHc8xTBQCow73tlo/Kc7oIwBrCLf0P3YhjlOeV4v8hevQ==}
- dependencies:
- '@docsearch/react': 3.6.0(@algolia/client-search@4.22.1)(search-insights@2.13.0)
- preact: 10.19.6
- transitivePeerDependencies:
- - '@algolia/client-search'
- - '@types/react'
- - react
- - react-dom
- - search-insights
- dev: true
-
- /@docsearch/react@3.6.0(@algolia/client-search@4.22.1)(search-insights@2.13.0):
- resolution: {integrity: sha512-HUFut4ztcVNmqy9gp/wxNbC7pTOHhgVVkHVGCACTuLhUKUhKAF9KYHJtMiLUJxEqiFLQiuri1fWF8zqwM/cu1w==}
- peerDependencies:
- '@types/react': '>= 16.8.0 < 19.0.0'
- react: '>= 16.8.0 < 19.0.0'
- react-dom: '>= 16.8.0 < 19.0.0'
- search-insights: '>= 1 < 3'
- peerDependenciesMeta:
- '@types/react':
- optional: true
- react:
- optional: true
- react-dom:
- optional: true
- search-insights:
- optional: true
- dependencies:
- '@algolia/autocomplete-core': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)(search-insights@2.13.0)
- '@algolia/autocomplete-preset-algolia': 1.9.3(@algolia/client-search@4.22.1)(algoliasearch@4.22.1)
- '@docsearch/css': 3.6.0
- algoliasearch: 4.22.1
- search-insights: 2.13.0
- transitivePeerDependencies:
- - '@algolia/client-search'
- dev: true
-
- /@esbuild/aix-ppc64@0.20.2:
- resolution: {integrity: sha512-D+EBOJHXdNZcLJRBkhENNG8Wji2kgc9AZ9KiPr1JuZjsNtyHzrsfLRrY0tk2H2aoFu6RANO1y1iPPUCDYWkb5g==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [aix]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm64@0.20.2:
- resolution: {integrity: sha512-mRzjLacRtl/tWU0SvD8lUEwb61yP9cqQo6noDZP/O8VkwafSYwZ4yWy24kan8jE/IMERpYncRt2dw438LP3Xmg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm@0.20.2:
- resolution: {integrity: sha512-t98Ra6pw2VaDhqNWO2Oph2LXbz/EJcnLmKLGBJwEwXX/JAN83Fym1rU8l0JUWK6HkIbWONCSSatf4sf2NBRx/w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-x64@0.20.2:
- resolution: {integrity: sha512-btzExgV+/lMGDDa194CcUQm53ncxzeBrWJcncOBxuC6ndBkKxnHdFJn86mCIgTELsooUmwUm9FkhSp5HYu00Rg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-arm64@0.20.2:
- resolution: {integrity: sha512-4J6IRT+10J3aJH3l1yzEg9y3wkTDgDk7TSDFX+wKFiWjqWp/iCfLIYzGyasx9l0SAFPT1HwSCR+0w/h1ES/MjA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-x64@0.20.2:
- resolution: {integrity: sha512-tBcXp9KNphnNH0dfhv8KYkZhjc+H3XBkF5DKtswJblV7KlT9EI2+jeA8DgBjp908WEuYll6pF+UStUCfEpdysA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-arm64@0.20.2:
- resolution: {integrity: sha512-d3qI41G4SuLiCGCFGUrKsSeTXyWG6yem1KcGZVS+3FYlYhtNoNgYrWcvkOoaqMhwXSMrZRl69ArHsGJ9mYdbbw==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-x64@0.20.2:
- resolution: {integrity: sha512-d+DipyvHRuqEeM5zDivKV1KuXn9WeRX6vqSqIDgwIfPQtwMP4jaDsQsDncjTDDsExT4lR/91OLjRo8bmC1e+Cw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm64@0.20.2:
- resolution: {integrity: sha512-9pb6rBjGvTFNira2FLIWqDk/uaf42sSyLE8j1rnUpuzsODBq7FvpwHYZxQ/It/8b+QOS1RYfqgGFNLRI+qlq2A==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm@0.20.2:
- resolution: {integrity: sha512-VhLPeR8HTMPccbuWWcEUD1Az68TqaTYyj6nfE4QByZIQEQVWBB8vup8PpR7y1QHL3CpcF6xd5WVBU/+SBEvGTg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ia32@0.20.2:
- resolution: {integrity: sha512-o10utieEkNPFDZFQm9CoP7Tvb33UutoJqg3qKf1PWVeeJhJw0Q347PxMvBgVVFgouYLGIhFYG0UGdBumROyiig==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-loong64@0.20.2:
- resolution: {integrity: sha512-PR7sp6R/UC4CFVomVINKJ80pMFlfDfMQMYynX7t1tNTeivQ6XdX5r2XovMmha/VjR1YN/HgHWsVcTRIMkymrgQ==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-mips64el@0.20.2:
- resolution: {integrity: sha512-4BlTqeutE/KnOiTG5Y6Sb/Hw6hsBOZapOVF6njAESHInhlQAghVVZL1ZpIctBOoTFbQyGW+LsVYZ8lSSB3wkjA==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ppc64@0.20.2:
- resolution: {integrity: sha512-rD3KsaDprDcfajSKdn25ooz5J5/fWBylaaXkuotBDGnMnDP1Uv5DLAN/45qfnf3JDYyJv/ytGHQaziHUdyzaAg==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-riscv64@0.20.2:
- resolution: {integrity: sha512-snwmBKacKmwTMmhLlz/3aH1Q9T8v45bKYGE3j26TsaOVtjIag4wLfWSiZykXzXuE1kbCE+zJRmwp+ZbIHinnVg==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-s390x@0.20.2:
- resolution: {integrity: sha512-wcWISOobRWNm3cezm5HOZcYz1sKoHLd8VL1dl309DiixxVFoFe/o8HnwuIwn6sXre88Nwj+VwZUvJf4AFxkyrQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-x64@0.20.2:
- resolution: {integrity: sha512-1MdwI6OOTsfQfek8sLwgyjOXAu+wKhLEoaOLTjbijk6E2WONYpH9ZU2mNtR+lZ2B4uwr+usqGuVfFT9tMtGvGw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/netbsd-x64@0.20.2:
- resolution: {integrity: sha512-K8/DhBxcVQkzYc43yJXDSyjlFeHQJBiowJ0uVL6Tor3jGQfSGHNNJcWxNbOI8v5k82prYqzPuwkzHt3J1T1iZQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/openbsd-x64@0.20.2:
- resolution: {integrity: sha512-eMpKlV0SThJmmJgiVyN9jTPJ2VBPquf6Kt/nAoo6DgHAoN57K15ZghiHaMvqjCye/uU4X5u3YSMgVBI1h3vKrQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/sunos-x64@0.20.2:
- resolution: {integrity: sha512-2UyFtRC6cXLyejf/YEld4Hajo7UHILetzE1vsRcGL3earZEW77JxrFjH4Ez2qaTiEfMgAXxfAZCm1fvM/G/o8w==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-arm64@0.20.2:
- resolution: {integrity: sha512-GRibxoawM9ZCnDxnP3usoUDO9vUkpAxIIZ6GQI+IlVmr5kP3zUq+l17xELTHMWTWzjxa2guPNyrpq1GWmPvcGQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-ia32@0.20.2:
- resolution: {integrity: sha512-HfLOfn9YWmkSKRQqovpnITazdtquEW8/SoHW7pWpuEeguaZI4QnCRW6b+oZTztdBnZOS2hqJ6im/D5cPzBTTlQ==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-x64@0.20.2:
- resolution: {integrity: sha512-N49X4lJX27+l9jbLKSqZ6bKNjzQvHaT8IIFUy+YIqmXQdjYCToGWwOItDrfby14c78aDd5NHQl29xingXfCdLQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@jridgewell/sourcemap-codec@1.4.15:
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
- dev: true
-
- /@rollup/rollup-android-arm-eabi@4.13.0:
- resolution: {integrity: sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-android-arm64@4.13.0:
- resolution: {integrity: sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-arm64@4.13.0:
- resolution: {integrity: sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-darwin-x64@4.13.0:
- resolution: {integrity: sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm-gnueabihf@4.13.0:
- resolution: {integrity: sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-gnu@4.13.0:
- resolution: {integrity: sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-arm64-musl@4.13.0:
- resolution: {integrity: sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-riscv64-gnu@4.13.0:
- resolution: {integrity: sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-gnu@4.13.0:
- resolution: {integrity: sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-linux-x64-musl@4.13.0:
- resolution: {integrity: sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-arm64-msvc@4.13.0:
- resolution: {integrity: sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-ia32-msvc@4.13.0:
- resolution: {integrity: sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@rollup/rollup-win32-x64-msvc@4.13.0:
- resolution: {integrity: sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@shikijs/core@1.3.0:
- resolution: {integrity: sha512-7fedsBfuILDTBmrYZNFI8B6ATTxhQAasUHllHmjvSZPnoq4bULWoTpHwmuQvZ8Aq03/tAa2IGo6RXqWtHdWaCA==}
- dev: true
-
- /@shikijs/transformers@1.3.0:
- resolution: {integrity: sha512-3mlpg2I9CjhjE96dEWQOGeCWoPcyTov3s4aAsHmgvnTHa8MBknEnCQy8/xivJPSpD+olqOqIEoHnLfbNJK29AA==}
- dependencies:
- shiki: 1.3.0
- dev: true
-
- /@types/estree@1.0.5:
- resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
- dev: true
-
- /@types/flexsearch@0.7.6:
- resolution: {integrity: sha512-H5IXcRn96/gaDmo+rDl2aJuIJsob8dgOXDqf8K0t8rWZd1AFNaaspmRsElESiU+EWE33qfbFPgI0OC/B1g9FCA==}
- dev: true
-
- /@types/linkify-it@3.0.5:
- resolution: {integrity: sha512-yg6E+u0/+Zjva+buc3EIb+29XEg4wltq7cSmd4Uc2EE/1nUVmxyzpX6gUXD0V8jIrG0r7YeOGVIbYRkxeooCtw==}
- dev: true
-
- /@types/markdown-it@12.2.3:
- resolution: {integrity: sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==}
- dependencies:
- '@types/linkify-it': 3.0.5
- '@types/mdurl': 1.0.5
- dev: true
-
- /@types/markdown-it@14.0.1:
- resolution: {integrity: sha512-6WfOG3jXR78DW8L5cTYCVVGAsIFZskRHCDo5tbqa+qtKVt4oDRVH7hyIWu1SpDQJlmIoEivNQZ5h+AGAOrgOtQ==}
- dependencies:
- '@types/linkify-it': 3.0.5
- '@types/mdurl': 1.0.5
- dev: true
-
- /@types/mdurl@1.0.5:
- resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==}
- dev: true
-
- /@types/web-bluetooth@0.0.20:
- resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==}
- dev: true
-
- /@vitejs/plugin-vue@5.0.4(vite@5.2.10)(vue@3.4.23):
- resolution: {integrity: sha512-WS3hevEszI6CEVEx28F8RjTX97k3KsrcY6kvTg7+Whm5y3oYvcqzVeGCU3hxSAn4uY2CLCkeokkGKpoctccilQ==}
- engines: {node: ^18.0.0 || >=20.0.0}
- peerDependencies:
- vite: ^5.0.0
- vue: ^3.2.25
- dependencies:
- vite: 5.2.10
- vue: 3.4.23
- dev: true
-
- /@vue/compiler-core@3.4.23:
- resolution: {integrity: sha512-HAFmuVEwNqNdmk+w4VCQ2pkLk1Vw4XYiiyxEp3z/xvl14aLTUBw2OfVH3vBcx+FtGsynQLkkhK410Nah1N2yyQ==}
- dependencies:
- '@babel/parser': 7.24.4
- '@vue/shared': 3.4.23
- entities: 4.5.0
- estree-walker: 2.0.2
- source-map-js: 1.2.0
- dev: true
-
- /@vue/compiler-dom@3.4.23:
- resolution: {integrity: sha512-t0b9WSTnCRrzsBGrDd1LNR5HGzYTr7LX3z6nNBG+KGvZLqrT0mY6NsMzOqlVMBKKXKVuusbbB5aOOFgTY+senw==}
- dependencies:
- '@vue/compiler-core': 3.4.23
- '@vue/shared': 3.4.23
- dev: true
-
- /@vue/compiler-sfc@3.4.23:
- resolution: {integrity: sha512-fSDTKTfzaRX1kNAUiaj8JB4AokikzStWgHooMhaxyjZerw624L+IAP/fvI4ZwMpwIh8f08PVzEnu4rg8/Npssw==}
- dependencies:
- '@babel/parser': 7.24.4
- '@vue/compiler-core': 3.4.23
- '@vue/compiler-dom': 3.4.23
- '@vue/compiler-ssr': 3.4.23
- '@vue/shared': 3.4.23
- estree-walker: 2.0.2
- magic-string: 0.30.8
- postcss: 8.4.38
- source-map-js: 1.2.0
- dev: true
-
- /@vue/compiler-ssr@3.4.23:
- resolution: {integrity: sha512-hb6Uj2cYs+tfqz71Wj6h3E5t6OKvb4MVcM2Nl5i/z1nv1gjEhw+zYaNOV+Xwn+SSN/VZM0DgANw5TuJfxfezPg==}
- dependencies:
- '@vue/compiler-dom': 3.4.23
- '@vue/shared': 3.4.23
- dev: true
-
- /@vue/devtools-api@7.0.27(vue@3.4.23):
- resolution: {integrity: sha512-BFCFCusSDcw2UcOFD/QeK7OxD1x2C/m+uAN30Q7jLKECSW53hmz0urzJmX834GuWDZX/hIxkyUKnLLfEIP1c/w==}
- dependencies:
- '@vue/devtools-kit': 7.0.27(vue@3.4.23)
- transitivePeerDependencies:
- - vue
- dev: true
-
- /@vue/devtools-kit@7.0.27(vue@3.4.23):
- resolution: {integrity: sha512-/A5xM38pPCFX5Yhl/lRFAzjyK6VNsH670nww2WbjFKWqlu3I+lMxWKzQkCW6A1V8bduITgl2kHORfg2gTw6QaA==}
- peerDependencies:
- vue: ^3.0.0
- dependencies:
- '@vue/devtools-shared': 7.0.27
- hookable: 5.5.3
- mitt: 3.0.1
- perfect-debounce: 1.0.0
- speakingurl: 14.0.1
- vue: 3.4.23
- dev: true
-
- /@vue/devtools-shared@7.0.27:
- resolution: {integrity: sha512-4VxtmZ6yjhiSloqZZq2UYU0TBGxOJ8GxWvp5OlAH70zYqi0FIAyWGPkOhvfoZ7DKQyv2UU0mmKzFHjsEkelGyQ==}
- dependencies:
- rfdc: 1.3.1
- dev: true
-
- /@vue/reactivity@3.4.23:
- resolution: {integrity: sha512-GlXR9PL+23fQ3IqnbSQ8OQKLodjqCyoCrmdLKZk3BP7jN6prWheAfU7a3mrltewTkoBm+N7qMEb372VHIkQRMQ==}
- dependencies:
- '@vue/shared': 3.4.23
- dev: true
-
- /@vue/runtime-core@3.4.23:
- resolution: {integrity: sha512-FeQ9MZEXoFzFkFiw9MQQ/FWs3srvrP+SjDKSeRIiQHIhtkzoj0X4rWQlRNHbGuSwLra6pMyjAttwixNMjc/xLw==}
- dependencies:
- '@vue/reactivity': 3.4.23
- '@vue/shared': 3.4.23
- dev: true
-
- /@vue/runtime-dom@3.4.23:
- resolution: {integrity: sha512-RXJFwwykZWBkMiTPSLEWU3kgVLNAfActBfWFlZd0y79FTUxexogd0PLG4HH2LfOktjRxV47Nulygh0JFXe5f9A==}
- dependencies:
- '@vue/runtime-core': 3.4.23
- '@vue/shared': 3.4.23
- csstype: 3.1.3
- dev: true
-
- /@vue/server-renderer@3.4.23(vue@3.4.23):
- resolution: {integrity: sha512-LDwGHtnIzvKFNS8dPJ1SSU5Gvm36p2ck8wCZc52fc3k/IfjKcwCyrWEf0Yag/2wTFUBXrqizfhK9c/mC367dXQ==}
- peerDependencies:
- vue: 3.4.23
- dependencies:
- '@vue/compiler-ssr': 3.4.23
- '@vue/shared': 3.4.23
- vue: 3.4.23
- dev: true
-
- /@vue/shared@3.4.23:
- resolution: {integrity: sha512-wBQ0gvf+SMwsCQOyusNw/GoXPV47WGd1xB5A1Pgzy0sQ3Bi5r5xm3n+92y3gCnB3MWqnRDdvfkRGxhKtbBRNgg==}
- dev: true
-
- /@vueuse/core@10.9.0(vue@3.4.23):
- resolution: {integrity: sha512-/1vjTol8SXnx6xewDEKfS0Ra//ncg4Hb0DaZiwKf7drgfMsKFExQ+FnnENcN6efPen+1kIzhLQoGSy0eDUVOMg==}
- dependencies:
- '@types/web-bluetooth': 0.0.20
- '@vueuse/metadata': 10.9.0
- '@vueuse/shared': 10.9.0(vue@3.4.23)
- vue-demi: 0.14.7(vue@3.4.23)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /@vueuse/integrations@10.9.0(focus-trap@7.5.4)(vue@3.4.23):
- resolution: {integrity: sha512-acK+A01AYdWSvL4BZmCoJAcyHJ6EqhmkQEXbQLwev1MY7NBnS+hcEMx/BzVoR9zKI+UqEPMD9u6PsyAuiTRT4Q==}
- peerDependencies:
- async-validator: '*'
- axios: '*'
- change-case: '*'
- drauu: '*'
- focus-trap: '*'
- fuse.js: '*'
- idb-keyval: '*'
- jwt-decode: '*'
- nprogress: '*'
- qrcode: '*'
- sortablejs: '*'
- universal-cookie: '*'
- peerDependenciesMeta:
- async-validator:
- optional: true
- axios:
- optional: true
- change-case:
- optional: true
- drauu:
- optional: true
- focus-trap:
- optional: true
- fuse.js:
- optional: true
- idb-keyval:
- optional: true
- jwt-decode:
- optional: true
- nprogress:
- optional: true
- qrcode:
- optional: true
- sortablejs:
- optional: true
- universal-cookie:
- optional: true
- dependencies:
- '@vueuse/core': 10.9.0(vue@3.4.23)
- '@vueuse/shared': 10.9.0(vue@3.4.23)
- focus-trap: 7.5.4
- vue-demi: 0.14.7(vue@3.4.23)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /@vueuse/metadata@10.9.0:
- resolution: {integrity: sha512-iddNbg3yZM0X7qFY2sAotomgdHK7YJ6sKUvQqbvwnf7TmaVPxS4EJydcNsVejNdS8iWCtDk+fYXr7E32nyTnGA==}
- dev: true
-
- /@vueuse/shared@10.9.0(vue@3.4.23):
- resolution: {integrity: sha512-Uud2IWncmAfJvRaFYzv5OHDli+FbOzxiVEQdLCKQKLyhz94PIyFC3CHcH7EDMwIn8NPtD06+PNbC/PiO0LGLtw==}
- dependencies:
- vue-demi: 0.14.7(vue@3.4.23)
- transitivePeerDependencies:
- - '@vue/composition-api'
- - vue
- dev: true
-
- /algoliasearch@4.22.1:
- resolution: {integrity: sha512-jwydKFQJKIx9kIZ8Jm44SdpigFwRGPESaxZBaHSV0XWN2yBJAOT4mT7ppvlrpA4UGzz92pqFnVKr/kaZXrcreg==}
- dependencies:
- '@algolia/cache-browser-local-storage': 4.22.1
- '@algolia/cache-common': 4.22.1
- '@algolia/cache-in-memory': 4.22.1
- '@algolia/client-account': 4.22.1
- '@algolia/client-analytics': 4.22.1
- '@algolia/client-common': 4.22.1
- '@algolia/client-personalization': 4.22.1
- '@algolia/client-search': 4.22.1
- '@algolia/logger-common': 4.22.1
- '@algolia/logger-console': 4.22.1
- '@algolia/requester-browser-xhr': 4.22.1
- '@algolia/requester-common': 4.22.1
- '@algolia/requester-node-http': 4.22.1
- '@algolia/transporter': 4.22.1
- dev: true
-
- /argparse@2.0.1:
- resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
- dev: true
-
- /csstype@3.1.3:
- resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==}
- dev: true
-
- /entities@3.0.1:
- resolution: {integrity: sha512-WiyBqoomrwMdFG1e0kqvASYfnlb0lp8M5o5Fw2OFq1hNZxxcNk8Ik0Xm7LxzBhuidnZB/UtBqVCgUz3kBOP51Q==}
- engines: {node: '>=0.12'}
- dev: true
-
- /entities@4.5.0:
- resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==}
- engines: {node: '>=0.12'}
- dev: true
-
- /esbuild@0.20.2:
- resolution: {integrity: sha512-WdOOppmUNU+IbZ0PaDiTst80zjnrOkyJNHoKupIcVyU8Lvla3Ugx94VzkQ32Ijqd7UhHJy75gNWDMUekcrSJ6g==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- '@esbuild/aix-ppc64': 0.20.2
- '@esbuild/android-arm': 0.20.2
- '@esbuild/android-arm64': 0.20.2
- '@esbuild/android-x64': 0.20.2
- '@esbuild/darwin-arm64': 0.20.2
- '@esbuild/darwin-x64': 0.20.2
- '@esbuild/freebsd-arm64': 0.20.2
- '@esbuild/freebsd-x64': 0.20.2
- '@esbuild/linux-arm': 0.20.2
- '@esbuild/linux-arm64': 0.20.2
- '@esbuild/linux-ia32': 0.20.2
- '@esbuild/linux-loong64': 0.20.2
- '@esbuild/linux-mips64el': 0.20.2
- '@esbuild/linux-ppc64': 0.20.2
- '@esbuild/linux-riscv64': 0.20.2
- '@esbuild/linux-s390x': 0.20.2
- '@esbuild/linux-x64': 0.20.2
- '@esbuild/netbsd-x64': 0.20.2
- '@esbuild/openbsd-x64': 0.20.2
- '@esbuild/sunos-x64': 0.20.2
- '@esbuild/win32-arm64': 0.20.2
- '@esbuild/win32-ia32': 0.20.2
- '@esbuild/win32-x64': 0.20.2
- dev: true
-
- /estree-walker@2.0.2:
- resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
- dev: true
-
- /flexsearch@0.7.43:
- resolution: {integrity: sha512-c5o/+Um8aqCSOXGcZoqZOm+NqtVwNsvVpWv6lfmSclU954O3wvQKxxK8zj74fPaSJbXpSLTs4PRhh+wnoCXnKg==}
- dev: true
-
- /focus-trap@7.5.4:
- resolution: {integrity: sha512-N7kHdlgsO/v+iD/dMoJKtsSqs5Dz/dXZVebRgJw23LDk+jMi/974zyiOYDziY2JPp8xivq9BmUGwIJMiuSBi7w==}
- dependencies:
- tabbable: 6.2.0
- dev: true
-
- /fsevents@2.3.3:
- resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /glob-to-regexp@0.4.1:
- resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==}
- dev: true
-
- /hookable@5.5.3:
- resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
- dev: true
-
- /linkify-it@4.0.1:
- resolution: {integrity: sha512-C7bfi1UZmoj8+PQx22XyeXCuBlokoyWQL5pWSP+EI6nzRylyThouddufc2c1NDIcP9k5agmN9fLpA7VNJfIiqw==}
- dependencies:
- uc.micro: 1.0.6
- dev: true
-
- /magic-string@0.30.8:
- resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==}
- engines: {node: '>=12'}
- dependencies:
- '@jridgewell/sourcemap-codec': 1.4.15
- dev: true
-
- /mark.js@8.11.1:
- resolution: {integrity: sha512-1I+1qpDt4idfgLQG+BNWmrqku+7/2bi5nLf4YwF8y8zXvmfiTBY3PV3ZibfrjBueCByROpuBjLLFCajqkgYoLQ==}
- dev: true
-
- /markdown-it@13.0.2:
- resolution: {integrity: sha512-FtwnEuuK+2yVU7goGn/MJ0WBZMM9ZPgU9spqlFs7/A/pDIUNSOQZhUgOqYCficIuR2QaFnrt8LHqBWsbTAoI5w==}
- hasBin: true
- dependencies:
- argparse: 2.0.1
- entities: 3.0.1
- linkify-it: 4.0.1
- mdurl: 1.0.1
- uc.micro: 1.0.6
- dev: true
-
- /mdurl@1.0.1:
- resolution: {integrity: sha512-/sKlQJCBYVY9Ers9hqzKou4H6V5UWc/M59TH2dvkt+84itfnq7uFOMLpOiOS4ujvHP4etln18fmIxA5R5fll0g==}
- dev: true
-
- /minisearch@6.3.0:
- resolution: {integrity: sha512-ihFnidEeU8iXzcVHy74dhkxh/dn8Dc08ERl0xwoMMGqp4+LvRSCgicb+zGqWthVokQKvCSxITlh3P08OzdTYCQ==}
- dev: true
-
- /mitt@3.0.1:
- resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==}
- dev: true
-
- /nanoid@3.3.7:
- resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==}
- engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
- hasBin: true
- dev: true
-
- /perfect-debounce@1.0.0:
- resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==}
- dev: true
-
- /picocolors@1.0.0:
- resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
- dev: true
-
- /postcss@8.4.38:
- resolution: {integrity: sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==}
- engines: {node: ^10 || ^12 || >=14}
- dependencies:
- nanoid: 3.3.7
- picocolors: 1.0.0
- source-map-js: 1.2.0
- dev: true
-
- /preact@10.19.6:
- resolution: {integrity: sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==}
- dev: true
-
- /rfdc@1.3.1:
- resolution: {integrity: sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==}
- dev: true
-
- /rollup@4.13.0:
- resolution: {integrity: sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==}
- engines: {node: '>=18.0.0', npm: '>=8.0.0'}
- hasBin: true
- dependencies:
- '@types/estree': 1.0.5
- optionalDependencies:
- '@rollup/rollup-android-arm-eabi': 4.13.0
- '@rollup/rollup-android-arm64': 4.13.0
- '@rollup/rollup-darwin-arm64': 4.13.0
- '@rollup/rollup-darwin-x64': 4.13.0
- '@rollup/rollup-linux-arm-gnueabihf': 4.13.0
- '@rollup/rollup-linux-arm64-gnu': 4.13.0
- '@rollup/rollup-linux-arm64-musl': 4.13.0
- '@rollup/rollup-linux-riscv64-gnu': 4.13.0
- '@rollup/rollup-linux-x64-gnu': 4.13.0
- '@rollup/rollup-linux-x64-musl': 4.13.0
- '@rollup/rollup-win32-arm64-msvc': 4.13.0
- '@rollup/rollup-win32-ia32-msvc': 4.13.0
- '@rollup/rollup-win32-x64-msvc': 4.13.0
- fsevents: 2.3.3
- dev: true
-
- /search-insights@2.13.0:
- resolution: {integrity: sha512-Orrsjf9trHHxFRuo9/rzm0KIWmgzE8RMlZMzuhZOJ01Rnz3D0YBAe+V6473t6/H6c7irs6Lt48brULAiRWb3Vw==}
- dev: true
-
- /shiki@1.3.0:
- resolution: {integrity: sha512-9aNdQy/etMXctnPzsje1h1XIGm9YfRcSksKOGqZWXA/qP9G18/8fpz5Bjpma8bOgz3tqIpjERAd6/lLjFyzoww==}
- dependencies:
- '@shikijs/core': 1.3.0
- dev: true
-
- /source-map-js@1.2.0:
- resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /speakingurl@14.0.1:
- resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /tabbable@6.2.0:
- resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==}
- dev: true
-
- /to-fast-properties@2.0.0:
- resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
- engines: {node: '>=4'}
- dev: true
-
- /uc.micro@1.0.6:
- resolution: {integrity: sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==}
- dev: true
-
- /vite@5.2.10:
- resolution: {integrity: sha512-PAzgUZbP7msvQvqdSD+ErD5qGnSFiGOoWmV5yAKUEI0kdhjbH6nMWVyZQC/hSc4aXwc0oJ9aEdIiF9Oje0JFCw==}
- engines: {node: ^18.0.0 || >=20.0.0}
- hasBin: true
- peerDependencies:
- '@types/node': ^18.0.0 || >=20.0.0
- less: '*'
- lightningcss: ^1.21.0
- sass: '*'
- stylus: '*'
- sugarss: '*'
- terser: ^5.4.0
- peerDependenciesMeta:
- '@types/node':
- optional: true
- less:
- optional: true
- lightningcss:
- optional: true
- sass:
- optional: true
- stylus:
- optional: true
- sugarss:
- optional: true
- terser:
- optional: true
- dependencies:
- esbuild: 0.20.2
- postcss: 8.4.38
- rollup: 4.13.0
- optionalDependencies:
- fsevents: 2.3.3
- dev: true
-
- /vitepress-plugin-search@1.0.4-alpha.22(flexsearch@0.7.43)(vitepress@1.1.3)(vue@3.4.23):
- resolution: {integrity: sha512-IAOEJu+kjVY+0pb6/PeRjIbr175HFFbnMdLmLjqcy7VWxkabIRZbLoQL1VUYDZl804o/Or+GaX02gsiMOnVxFA==}
- engines: {node: ^14.13.1 || ^16.7.0 || >=18}
- peerDependencies:
- flexsearch: ^0.7.31
- vitepress: ^1.0.0-rc.35
- vue: '3'
- dependencies:
- '@types/flexsearch': 0.7.6
- '@types/markdown-it': 12.2.3
- flexsearch: 0.7.43
- glob-to-regexp: 0.4.1
- markdown-it: 13.0.2
- vitepress: 1.1.3(@algolia/client-search@4.22.1)(search-insights@2.13.0)
- vue: 3.4.23
- dev: true
-
- /vitepress@1.1.3(@algolia/client-search@4.22.1)(search-insights@2.13.0):
- resolution: {integrity: sha512-hGrIYN0w9IHWs0NQSnlMjKV/v/HLfD+Ywv5QdvCSkiT32mpNOOwUrZjnqZv/JL/WBPpUc94eghTUvmipxw0xrA==}
- hasBin: true
- peerDependencies:
- markdown-it-mathjax3: ^4
- postcss: ^8
- peerDependenciesMeta:
- markdown-it-mathjax3:
- optional: true
- postcss:
- optional: true
- dependencies:
- '@docsearch/css': 3.6.0
- '@docsearch/js': 3.6.0(@algolia/client-search@4.22.1)(search-insights@2.13.0)
- '@shikijs/core': 1.3.0
- '@shikijs/transformers': 1.3.0
- '@types/markdown-it': 14.0.1
- '@vitejs/plugin-vue': 5.0.4(vite@5.2.10)(vue@3.4.23)
- '@vue/devtools-api': 7.0.27(vue@3.4.23)
- '@vueuse/core': 10.9.0(vue@3.4.23)
- '@vueuse/integrations': 10.9.0(focus-trap@7.5.4)(vue@3.4.23)
- focus-trap: 7.5.4
- mark.js: 8.11.1
- minisearch: 6.3.0
- shiki: 1.3.0
- vite: 5.2.10
- vue: 3.4.23
- transitivePeerDependencies:
- - '@algolia/client-search'
- - '@types/node'
- - '@types/react'
- - '@vue/composition-api'
- - async-validator
- - axios
- - change-case
- - drauu
- - fuse.js
- - idb-keyval
- - jwt-decode
- - less
- - lightningcss
- - nprogress
- - qrcode
- - react
- - react-dom
- - sass
- - search-insights
- - sortablejs
- - stylus
- - sugarss
- - terser
- - typescript
- - universal-cookie
- dev: true
-
- /vue-demi@0.14.7(vue@3.4.23):
- resolution: {integrity: sha512-EOG8KXDQNwkJILkx/gPcoL/7vH+hORoBaKgGe+6W7VFMvCYJfmF2dGbvgDroVnI8LU7/kTu8mbjRZGBU1z9NTA==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
- peerDependencies:
- '@vue/composition-api': ^1.0.0-rc.1
- vue: ^3.0.0-0 || ^2.6.0
- peerDependenciesMeta:
- '@vue/composition-api':
- optional: true
- dependencies:
- vue: 3.4.23
- dev: true
-
- /vue@3.4.23:
- resolution: {integrity: sha512-X1y6yyGJ28LMUBJ0k/qIeKHstGd+BlWQEOT40x3auJFTmpIhpbKLgN7EFsqalnJXq1Km5ybDEsp6BhuWKciUDg==}
- peerDependencies:
- typescript: '*'
- peerDependenciesMeta:
- typescript:
- optional: true
- dependencies:
- '@vue/compiler-dom': 3.4.23
- '@vue/compiler-sfc': 3.4.23
- '@vue/runtime-dom': 3.4.23
- '@vue/server-renderer': 3.4.23(vue@3.4.23)
- '@vue/shared': 3.4.23
- dev: true
diff --git a/docs/pnpm-workspace.yaml b/docs/pnpm-workspace.yaml
deleted file mode 100644
index e69de29..0000000
diff --git a/docs/vitepress_docs/.vitepress/config.ts b/docs/vitepress_docs/.vitepress/config.ts
deleted file mode 100644
index 754f6c0..0000000
--- a/docs/vitepress_docs/.vitepress/config.ts
+++ /dev/null
@@ -1,34 +0,0 @@
-import { defineConfig } from "vitepress";
-import { SearchPlugin } from "vitepress-plugin-search";
-// https://vitepress.dev/reference/site-config
-export default defineConfig({
- title: "Solid-CLI Docs",
- description: "Documentation for the Solid CLI",
- themeConfig: {
- // https://vitepress.dev/reference/default-theme-config
- nav: [
- { text: "Home", link: "/" },
- { text: "Guide", link: "/about" },
- ],
-
- sidebar: [
- {
- text: "Getting started",
- items: [
- { text: "About", link: "/about" },
- { text: "Installation", link: "/installation" },
- { text: "Basic Commands", link: "/basic-commands" },
- { text: "SolidStart Commands", link: "/start-commands" },
- ],
- },
- { text: "Supported Integrations", link: "/supported-integrations" },
- ],
- socialLinks: [
- {
- icon: "github",
- link: "https://github.com/solidjs-community/solid-cli",
- },
- ],
- },
- vite: { plugins: [SearchPlugin()] },
-});
diff --git a/docs/vitepress_docs/.vitepress/theme/index.ts b/docs/vitepress_docs/.vitepress/theme/index.ts
deleted file mode 100644
index 09d0a1a..0000000
--- a/docs/vitepress_docs/.vitepress/theme/index.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-// https://vitepress.dev/guide/custom-theme
-import { h } from "vue";
-import Theme from "vitepress/theme";
-import "./style.css";
-
-export default {
- extends: Theme,
- Layout: () => {
- return h(Theme.Layout, null, {
- // https://vitepress.dev/guide/extending-default-theme#layout-slots
- });
- },
- enhanceApp({ app, router, siteData }) {
- // ...
- },
-};
diff --git a/docs/vitepress_docs/.vitepress/theme/style.css b/docs/vitepress_docs/.vitepress/theme/style.css
deleted file mode 100644
index bab0266..0000000
--- a/docs/vitepress_docs/.vitepress/theme/style.css
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * Customize default theme styling by overriding CSS variables:
- * https://github.com/vuejs/vitepress/blob/main/src/client/theme-default/styles/vars.css
- */
-
-/**
- * Colors
- * -------------------------------------------------------------------------- */
-
-:root {
- --vp-c-brand: #646cff;
- --vp-c-brand-light: #747bff;
- --vp-c-brand-lighter: #9499ff;
- --vp-c-brand-lightest: #bcc0ff;
- --vp-c-brand-dark: #535bf2;
- --vp-c-brand-darker: #454ce1;
- --vp-c-brand-dimm: rgba(100, 108, 255, 0.08);
-}
-
-/**
- * Component: Button
- * -------------------------------------------------------------------------- */
-
-:root {
- --vp-button-brand-border: var(--vp-c-brand-light);
- --vp-button-brand-text: var(--vp-c-white);
- --vp-button-brand-bg: var(--vp-c-brand);
- --vp-button-brand-hover-border: var(--vp-c-brand-light);
- --vp-button-brand-hover-text: var(--vp-c-white);
- --vp-button-brand-hover-bg: var(--vp-c-brand-light);
- --vp-button-brand-active-border: var(--vp-c-brand-light);
- --vp-button-brand-active-text: var(--vp-c-white);
- --vp-button-brand-active-bg: var(--vp-button-brand-bg);
-}
-
-/**
- * Component: Home
- * -------------------------------------------------------------------------- */
-
-:root {
- --vp-home-hero-name-color: transparent;
- --vp-home-hero-name-background: -webkit-linear-gradient(120deg, #bd34fe 30%, #41d1ff);
-
- --vp-home-hero-image-background-image: linear-gradient(-45deg, #bd34fe 50%, #47caff 50%);
- --vp-home-hero-image-filter: blur(40px);
-}
-
-@media (min-width: 640px) {
- :root {
- --vp-home-hero-image-filter: blur(56px);
- }
-}
-
-@media (min-width: 960px) {
- :root {
- --vp-home-hero-image-filter: blur(72px);
- }
-}
-
-/**
- * Component: Custom Block
- * -------------------------------------------------------------------------- */
-
-:root {
- --vp-custom-block-tip-border: var(--vp-c-brand);
- --vp-custom-block-tip-text: var(--vp-c-brand-darker);
- --vp-custom-block-tip-bg: var(--vp-c-brand-dimm);
-}
-
-.dark {
- --vp-custom-block-tip-border: var(--vp-c-brand);
- --vp-custom-block-tip-text: var(--vp-c-brand-lightest);
- --vp-custom-block-tip-bg: var(--vp-c-brand-dimm);
-}
-
-/**
- * Component: Algolia
- * -------------------------------------------------------------------------- */
-
-.DocSearch {
- --docsearch-primary-color: var(--vp-c-brand) !important;
-}
diff --git a/docs/vitepress_docs/about.md b/docs/vitepress_docs/about.md
deleted file mode 100644
index 504eb5c..0000000
--- a/docs/vitepress_docs/about.md
+++ /dev/null
@@ -1,17 +0,0 @@
-# About
-
-The Solid CLI is a tool aiming to make the Solid development experience easier, faster, and less error prone.
-
-## Features
-
-### Automatic Config manipulation
-
-Can automatically update your config to enable solid features, such as toggling SSR, or adding adapters.
-
-### Adding integrations
-
-Can automatically install and configure supported packages.
-
-### Project creation
-
-Provides an easy way to create new projects, whether that be locally, or on a platform such as stackblitz or codesandbox.
diff --git a/docs/vitepress_docs/basic-commands.md b/docs/vitepress_docs/basic-commands.md
deleted file mode 100644
index 8fe045c..0000000
--- a/docs/vitepress_docs/basic-commands.md
+++ /dev/null
@@ -1,84 +0,0 @@
-# Basic Commands
-
-### `Add`
-
-```sh
-solid add
-```
-
-Used to add packages and setup integrations.
-
-::: info
-By default, when no arguments or flags are passed, this command will open up a searchable multiselect for you to be able to search through
-all supported integrations and packages. You can select the ones you want to use through there.
-:::
-
-**Options**
-
-| Option | Description |
-| --------------- | ------------------------------------------------------------------------------------------------------ |
-| `` | List of integrations you want to add to your project (ie. unocss, vitepwa, solid-devtools) |
-| `--force` | Force apply any changes to the config to add the integration(s) even if they already exist `(boolean)` |
-
----
-
-### `New`
-
-```sh
-solid new
-```
-
-Creates a new solid project with the selected variation and name.
-
-This can also be used to spin up a new stackblitz or codesandbox instance.
-
-**Options**
-
-| Option | Description |
-| -------------------------- | ------------------------------------------------------------------------------------------- |
-| `` | The variation you want to start the project from. One of the following: "bare", "js", "ts". |
-| `` | The name of the project and the folder to create it in. |
-| `--stackblitz (short: -s)` | Create the project with the variation in a stackblitz instance. `(boolean)` |
-
----
-
-### `Docs`
-
-```sh
-solid docs
-```
-
-Searches for a given keyword within the main solid documentation sites
-
-**Options**
-
-| Option | Description |
-| ----------- | ---------------------------------------------- |
-| `` | The keyword to search within the docs websites |
-
----
-
-### `Set`
-
-```sh
-solid set
-```
-
-Sets a specified config parameter to a specified value
-
-**Options**
-
-| Option | Description |
-| --------- | -------------------------------- |
-| `` | The key within the config to set |
-| `` | The value to set that key to |
-
----
-
-### `Playground`
-
-```sh
-solid playground
-```
-
-Attempts to open the [Solid Playground](https://playground.solidjs.com) in the browser
diff --git a/docs/vitepress_docs/index.md b/docs/vitepress_docs/index.md
deleted file mode 100644
index 551ee49..0000000
--- a/docs/vitepress_docs/index.md
+++ /dev/null
@@ -1,23 +0,0 @@
----
-# https://vitepress.dev/reference/default-theme-home-page
-layout: home
-
-hero:
- name: "Solid-CLI Docs"
- text: "Documentation for the Solid CLI"
- tagline: A solid cli
- actions:
- - theme: brand
- text: Get started
- link: /about
-features:
- - title: Package manager
- icon: 📦
- details: Installs solid related packages, and automatically configures them in your project.
- - title: Customisable
- details: Plugins can be used to extend or manipulate existing functionality
- icon: 🎨
- - title: Automatic configuration
- icon: ♻
- details: Can automatically enable or disable features within solid, such as automatically enabling SSR
----
diff --git a/docs/vitepress_docs/installation.md b/docs/vitepress_docs/installation.md
deleted file mode 100644
index 4729ad2..0000000
--- a/docs/vitepress_docs/installation.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# Installation
-
-The CLI can be installed locally to your project via
-
-```sh
-npm install @solid-cli/core
-```
-
-Or installed globally:
-
-### UNIX/MacOS/Linux
-
-In order to install global packages on Unix based systems you will need to grant npm special system permissions using the `sudo` command, suffixed by the command you would like to run.
-
-```sh
-sudo npm install -g @solid-cli/core
-```
-
-### Windows
-
-```sh
-npm install -g @solid-cli/core
-```
-
-It can then be invoked via the keyword `solid`, and the help page can be displayed with `solid --help`
-
-```txt
-┌ Solid-CLI
-solid
-
-where can be one of:
-
-- add - Can add and install integrations: `solid add unocss`.
-- docs
-- new - Creates a new solid project
-- set
-- start - Commands specific to solid start
-- playground
-
-For more help, try running `solid --help`
-```
diff --git a/docs/vitepress_docs/start-commands.md b/docs/vitepress_docs/start-commands.md
deleted file mode 100644
index 28bfffd..0000000
--- a/docs/vitepress_docs/start-commands.md
+++ /dev/null
@@ -1,64 +0,0 @@
-# SolidStart Commands
-
-### `Mode`
-
-```sh
-solid start mode
-```
-
-Set the rendering mode for solid to build for and use (ie. Client-Side Rendering (CSR), Server-Side Rendering (SSR), Static-Site Generation (SSG))
-
-**Options**
-
-| Option | Description |
-| -------- | -------------------------------------------------------------- |
-| `` | The rendering mode to use. One of the following: csr, ssr, ssg |
-
----
-
-### `Route`
-
-```sh
-solid start route
-```
-
-Creates a new route file in the file routes directory.
-
-**Options**
-
-| Option | Description |
-| -------- | ------------------------------------------- |
-| `` | The path to the new route |
-| `` | The name of the `.tsx` file to be generated |
-
----
-
-### `Adapter`
-
-```sh
-solid start adapter
-```
-
-Used to setup a SolidStart specific adapter.
-
-**Options**
-
-| Option | Description |
-| --------- | -------------------------------- |
-| `` | The name of the adapter `string` |
-| `--force` | Force setup the adapater |
-
-### `Data`
-
-```sh
-solid start data
-```
-
-Creates a new data file at the given path
-
-**Options**
-
-| Option | Description |
-| -------- | ----------------------------------------------- |
-| `` | The path to the new data file |
-| `` | The name of the `.data.ts` file to be generated |
diff --git a/docs/vitepress_docs/supported-integrations.md b/docs/vitepress_docs/supported-integrations.md
deleted file mode 100644
index 934ee99..0000000
--- a/docs/vitepress_docs/supported-integrations.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Supported Integrations
-
-## Adapters
-
-- [AWS](https://github.com/solidjs/solid-start/tree/main/packages/start-aws)
-- [Cloudflare-pages](https://github.com/solidjs/solid-start/tree/main/packages/start-cloudflare-pages)
-- [Cloudflare-workers](https://github.com/solidjs/solid-start/tree/main/packages/start-cloudflare-workers)
-- [Deno](https://github.com/solidjs/solid-start/tree/main/packages/start-deno)
-- [Netlify](https://github.com/solidjs/solid-start/tree/main/packages/start-netlify)
-- [Node](https://github.com/solidjs/solid-start/tree/main/packages/start-node)
-- [Static](https://github.com/solidjs/solid-start/tree/main/packages/start-static)
-- [Vercel](https://github.com/solidjs/solid-start/tree/main/packages/start-vercel)
-
-## Packages
-
-These packages will be automatically installed and configured with sensible defaults:
-
-- [UnoCSS](https://unocss.dev/)
-- [Tailwind CSS](https://tailwindcss.com/)
-- [Solid Devtools](https://github.com/thetarnav/solid-devtools)
-- [VitePWA](https://vite-pwa-org.netlify.app)
diff --git a/examples/README.md b/examples/README.md
deleted file mode 100644
index bde8a57..0000000
--- a/examples/README.md
+++ /dev/null
@@ -1 +0,0 @@
-# Example plugins for the CLI
diff --git a/examples/plugin_template/package.json b/examples/plugin_template/package.json
deleted file mode 100644
index 4f9cffc..0000000
--- a/examples/plugin_template/package.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "name": "test_plugin",
- "version": "1.0.0",
- "description": "",
- "module": "./dist/index.mjs",
- "scripts": {
- "test": "echo \"Error: no test specified\" && exit 1",
- "build": "tsup"
- },
- "keywords": [],
- "author": "",
- "license": "ISC",
- "dependencies": {
- "cmd-ts": "^0.13.0"
- },
- "devDependencies": {
- "tsup": "^7.2.0"
- }
-}
diff --git a/examples/plugin_template/pnpm-lock.yaml b/examples/plugin_template/pnpm-lock.yaml
deleted file mode 100644
index b437238..0000000
--- a/examples/plugin_template/pnpm-lock.yaml
+++ /dev/null
@@ -1,930 +0,0 @@
-lockfileVersion: '6.0'
-
-settings:
- autoInstallPeers: true
- excludeLinksFromLockfile: false
-
-dependencies:
- cmd-ts:
- specifier: ^0.13.0
- version: 0.13.0
-
-devDependencies:
- tsup:
- specifier: ^7.2.0
- version: 7.2.0
-
-packages:
-
- /@esbuild/android-arm64@0.18.19:
- resolution: {integrity: sha512-4+jkUFQxZkQfQOOxfGVZB38YUWHMJX2ihZwF+2nh8m7bHdWXpixiurgGRN3c/KMSwlltbYI0/i929jwBRMFzbA==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-arm@0.18.19:
- resolution: {integrity: sha512-1uOoDurJYh5MNqPqpj3l/TQCI1V25BXgChEldCB7D6iryBYqYKrbZIhYO5AI9fulf66sM8UJpc3UcCly2Tv28w==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/android-x64@0.18.19:
- resolution: {integrity: sha512-ae5sHYiP/Ogj2YNrLZbWkBmyHIDOhPgpkGvFnke7XFGQldBDWvc/AyYwSLpNuKw9UNkgnLlB/jPpnBmlF3G9Bg==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [android]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-arm64@0.18.19:
- resolution: {integrity: sha512-HIpQvNQWFYROmWDANMRL+jZvvTQGOiTuwWBIuAsMaQrnStedM+nEKJBzKQ6bfT9RFKH2wZ+ej+DY7+9xHBTFPg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/darwin-x64@0.18.19:
- resolution: {integrity: sha512-m6JdvXJQt0thNLIcWOeG079h2ivhYH4B5sVCgqb/B29zTcFd7EE8/J1nIUHhdtwGeItdUeqKaqqb4towwxvglQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-arm64@0.18.19:
- resolution: {integrity: sha512-G0p4EFMPZhGn/xVNspUyMQbORH3nlKTV0bFNHPIwLraBuAkTeMyxNviTe0ZXUbIXQrR1lrwniFjNFU4s+x7veQ==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/freebsd-x64@0.18.19:
- resolution: {integrity: sha512-hBxgRlG42+W+j/1/cvlnSa+3+OBKeDCyO7OG2ICya1YJaSCYfSpuG30KfOnQHI7Ytgu4bRqCgrYXxQEzy0zM5Q==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [freebsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm64@0.18.19:
- resolution: {integrity: sha512-X8g33tczY0GsJq3lhyBrjnFtaKjWVpp1gMq5IlF9BQJ3TUfSK74nQnz9mRIEejmcV+OIYn6bkOJeUaU1Knrljg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-arm@0.18.19:
- resolution: {integrity: sha512-qtWyoQskfJlb9MD45mvzCEKeO4uCnDZ7lPFeNqbfaaJHqBiH9qA5Vu2EuckqYZuFMJWy1l4dxTf9NOulCVfUjg==}
- engines: {node: '>=12'}
- cpu: [arm]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ia32@0.18.19:
- resolution: {integrity: sha512-SAkRWJgb+KN+gOhmbiE6/wu23D6HRcGQi15cB13IVtBZZgXxygTV5GJlUAKLQ5Gcx0gtlmt+XIxEmSqA6sZTOw==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-loong64@0.18.19:
- resolution: {integrity: sha512-YLAslaO8NsB9UOxBchos82AOMRDbIAWChwDKfjlGrHSzS3v1kxce7dGlSTsrb0PJwo1KYccypN3VNjQVLtz7LA==}
- engines: {node: '>=12'}
- cpu: [loong64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-mips64el@0.18.19:
- resolution: {integrity: sha512-vSYFtlYds/oTI8aflEP65xo3MXChMwBOG1eWPGGKs/ev9zkTeXVvciU+nifq8J1JYMz+eQ4J9JDN0O2RKF8+1Q==}
- engines: {node: '>=12'}
- cpu: [mips64el]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-ppc64@0.18.19:
- resolution: {integrity: sha512-tgG41lRVwlzqO9tv9l7aXYVw35BxKXLtPam1qALScwSqPivI8hjkZLNH0deaaSCYCFT9cBIdB+hUjWFlFFLL9A==}
- engines: {node: '>=12'}
- cpu: [ppc64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-riscv64@0.18.19:
- resolution: {integrity: sha512-EgBZFLoN1S5RuB4cCJI31pBPsjE1nZ+3+fHRjguq9Ibrzo29bOLSBcH1KZJvRNh5qtd+fcYIGiIUia8Jw5r1lQ==}
- engines: {node: '>=12'}
- cpu: [riscv64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-s390x@0.18.19:
- resolution: {integrity: sha512-q1V1rtHRojAzjSigZEqrcLkpfh5K09ShCoIsdTakozVBnM5rgV58PLFticqDp5UJ9uE0HScov9QNbbl8HBo6QQ==}
- engines: {node: '>=12'}
- cpu: [s390x]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/linux-x64@0.18.19:
- resolution: {integrity: sha512-D0IiYjpZRXxGZLQfsydeAD7ZWqdGyFLBj5f2UshJpy09WPs3qizDCsEr8zyzcym6Woj/UI9ZzMIXwvoXVtyt0A==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [linux]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/netbsd-x64@0.18.19:
- resolution: {integrity: sha512-3tt3SOS8L3D54R8oER41UdDshlBIAjYhdWRPiZCTZ1E41+shIZBpTjaW5UaN/jD1ENE/Ok5lkeqhoNMbxstyxw==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [netbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/openbsd-x64@0.18.19:
- resolution: {integrity: sha512-MxbhcuAYQPlfln1EMc4T26OUoeg/YQc6wNoEV8xvktDKZhLtBxjkoeESSo9BbPaGKhAPzusXYj5n8n5A8iZSrA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [openbsd]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/sunos-x64@0.18.19:
- resolution: {integrity: sha512-m0/UOq1wj25JpWqOJxoWBRM9VWc3c32xiNzd+ERlYstUZ6uwx5SZsQUtkiFHaYmcaoj+f6+Tfcl7atuAz3idwQ==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [sunos]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-arm64@0.18.19:
- resolution: {integrity: sha512-L4vb6pcoB1cEcXUHU6EPnUhUc4+/tcz4OqlXTWPcSQWxegfmcOprhmIleKKwmMNQVc4wrx/+jB7tGkjjDmiupg==}
- engines: {node: '>=12'}
- cpu: [arm64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-ia32@0.18.19:
- resolution: {integrity: sha512-rQng7LXSKdrDlNDb7/v0fujob6X0GAazoK/IPd9C3oShr642ri8uIBkgM37/l8B3Rd5sBQcqUXoDdEy75XC/jg==}
- engines: {node: '>=12'}
- cpu: [ia32]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@esbuild/win32-x64@0.18.19:
- resolution: {integrity: sha512-z69jhyG20Gq4QL5JKPLqUT+eREuqnDAFItLbza4JCmpvUnIlY73YNjd5djlO7kBiiZnvTnJuAbOjIoZIOa1GjA==}
- engines: {node: '>=12'}
- cpu: [x64]
- os: [win32]
- requiresBuild: true
- dev: true
- optional: true
-
- /@jridgewell/gen-mapping@0.3.3:
- resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==}
- engines: {node: '>=6.0.0'}
- dependencies:
- '@jridgewell/set-array': 1.1.2
- '@jridgewell/sourcemap-codec': 1.4.15
- '@jridgewell/trace-mapping': 0.3.18
- dev: true
-
- /@jridgewell/resolve-uri@3.1.0:
- resolution: {integrity: sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==}
- engines: {node: '>=6.0.0'}
- dev: true
-
- /@jridgewell/set-array@1.1.2:
- resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==}
- engines: {node: '>=6.0.0'}
- dev: true
-
- /@jridgewell/sourcemap-codec@1.4.14:
- resolution: {integrity: sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==}
- dev: true
-
- /@jridgewell/sourcemap-codec@1.4.15:
- resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==}
- dev: true
-
- /@jridgewell/trace-mapping@0.3.18:
- resolution: {integrity: sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==}
- dependencies:
- '@jridgewell/resolve-uri': 3.1.0
- '@jridgewell/sourcemap-codec': 1.4.14
- dev: true
-
- /@nodelib/fs.scandir@2.1.5:
- resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==}
- engines: {node: '>= 8'}
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- run-parallel: 1.2.0
- dev: true
-
- /@nodelib/fs.stat@2.0.5:
- resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==}
- engines: {node: '>= 8'}
- dev: true
-
- /@nodelib/fs.walk@1.2.8:
- resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==}
- engines: {node: '>= 8'}
- dependencies:
- '@nodelib/fs.scandir': 2.1.5
- fastq: 1.15.0
- dev: true
-
- /ansi-regex@5.0.1:
- resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
- engines: {node: '>=8'}
- dev: false
-
- /ansi-styles@4.3.0:
- resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
- engines: {node: '>=8'}
- dependencies:
- color-convert: 2.0.1
- dev: false
-
- /any-promise@1.3.0:
- resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==}
- dev: true
-
- /anymatch@3.1.3:
- resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==}
- engines: {node: '>= 8'}
- dependencies:
- normalize-path: 3.0.0
- picomatch: 2.3.1
- dev: true
-
- /array-union@2.1.0:
- resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==}
- engines: {node: '>=8'}
- dev: true
-
- /balanced-match@1.0.2:
- resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
- dev: true
-
- /binary-extensions@2.2.0:
- resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==}
- engines: {node: '>=8'}
- dev: true
-
- /brace-expansion@1.1.11:
- resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
- dependencies:
- balanced-match: 1.0.2
- concat-map: 0.0.1
- dev: true
-
- /braces@3.0.2:
- resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
- engines: {node: '>=8'}
- dependencies:
- fill-range: 7.0.1
- dev: true
-
- /bundle-require@4.0.1(esbuild@0.18.19):
- resolution: {integrity: sha512-9NQkRHlNdNpDBGmLpngF3EFDcwodhMUuLz9PaWYciVcQF9SE4LFjM2DB/xV1Li5JiuDMv7ZUWuC3rGbqR0MAXQ==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- peerDependencies:
- esbuild: '>=0.17'
- dependencies:
- esbuild: 0.18.19
- load-tsconfig: 0.2.5
- dev: true
-
- /cac@6.7.14:
- resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
- engines: {node: '>=8'}
- dev: true
-
- /chalk@4.1.2:
- resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==}
- engines: {node: '>=10'}
- dependencies:
- ansi-styles: 4.3.0
- supports-color: 7.2.0
- dev: false
-
- /chokidar@3.5.3:
- resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
- engines: {node: '>= 8.10.0'}
- dependencies:
- anymatch: 3.1.3
- braces: 3.0.2
- glob-parent: 5.1.2
- is-binary-path: 2.1.0
- is-glob: 4.0.3
- normalize-path: 3.0.0
- readdirp: 3.6.0
- optionalDependencies:
- fsevents: 2.3.2
- dev: true
-
- /cmd-ts@0.13.0:
- resolution: {integrity: sha512-nsnxf6wNIM/JAS7T/x/1JmbEsjH0a8tezXqqpaL0O6+eV0/aDEnRxwjxpu0VzDdRcaC1ixGSbRlUuf/IU59I4g==}
- dependencies:
- chalk: 4.1.2
- debug: 4.3.4
- didyoumean: 1.2.2
- strip-ansi: 6.0.1
- transitivePeerDependencies:
- - supports-color
- dev: false
-
- /color-convert@2.0.1:
- resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
- engines: {node: '>=7.0.0'}
- dependencies:
- color-name: 1.1.4
- dev: false
-
- /color-name@1.1.4:
- resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
- dev: false
-
- /commander@4.1.1:
- resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==}
- engines: {node: '>= 6'}
- dev: true
-
- /concat-map@0.0.1:
- resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
- dev: true
-
- /cross-spawn@7.0.3:
- resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
- engines: {node: '>= 8'}
- dependencies:
- path-key: 3.1.1
- shebang-command: 2.0.0
- which: 2.0.2
- dev: true
-
- /debug@4.3.4:
- resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
- engines: {node: '>=6.0'}
- peerDependencies:
- supports-color: '*'
- peerDependenciesMeta:
- supports-color:
- optional: true
- dependencies:
- ms: 2.1.2
-
- /didyoumean@1.2.2:
- resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==}
- dev: false
-
- /dir-glob@3.0.1:
- resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==}
- engines: {node: '>=8'}
- dependencies:
- path-type: 4.0.0
- dev: true
-
- /esbuild@0.18.19:
- resolution: {integrity: sha512-ra3CaIKCzJp5bU5BDfrCc0FRqKj71fQi+gbld0aj6lN0ifuX2fWJYPgLVLGwPfA+ruKna+OWwOvf/yHj6n+i0g==}
- engines: {node: '>=12'}
- hasBin: true
- requiresBuild: true
- optionalDependencies:
- '@esbuild/android-arm': 0.18.19
- '@esbuild/android-arm64': 0.18.19
- '@esbuild/android-x64': 0.18.19
- '@esbuild/darwin-arm64': 0.18.19
- '@esbuild/darwin-x64': 0.18.19
- '@esbuild/freebsd-arm64': 0.18.19
- '@esbuild/freebsd-x64': 0.18.19
- '@esbuild/linux-arm': 0.18.19
- '@esbuild/linux-arm64': 0.18.19
- '@esbuild/linux-ia32': 0.18.19
- '@esbuild/linux-loong64': 0.18.19
- '@esbuild/linux-mips64el': 0.18.19
- '@esbuild/linux-ppc64': 0.18.19
- '@esbuild/linux-riscv64': 0.18.19
- '@esbuild/linux-s390x': 0.18.19
- '@esbuild/linux-x64': 0.18.19
- '@esbuild/netbsd-x64': 0.18.19
- '@esbuild/openbsd-x64': 0.18.19
- '@esbuild/sunos-x64': 0.18.19
- '@esbuild/win32-arm64': 0.18.19
- '@esbuild/win32-ia32': 0.18.19
- '@esbuild/win32-x64': 0.18.19
- dev: true
-
- /execa@5.1.1:
- resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==}
- engines: {node: '>=10'}
- dependencies:
- cross-spawn: 7.0.3
- get-stream: 6.0.1
- human-signals: 2.1.0
- is-stream: 2.0.1
- merge-stream: 2.0.0
- npm-run-path: 4.0.1
- onetime: 5.1.2
- signal-exit: 3.0.7
- strip-final-newline: 2.0.0
- dev: true
-
- /fast-glob@3.3.1:
- resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==}
- engines: {node: '>=8.6.0'}
- dependencies:
- '@nodelib/fs.stat': 2.0.5
- '@nodelib/fs.walk': 1.2.8
- glob-parent: 5.1.2
- merge2: 1.4.1
- micromatch: 4.0.5
- dev: true
-
- /fastq@1.15.0:
- resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
- dependencies:
- reusify: 1.0.4
- dev: true
-
- /fill-range@7.0.1:
- resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
- engines: {node: '>=8'}
- dependencies:
- to-regex-range: 5.0.1
- dev: true
-
- /fs.realpath@1.0.0:
- resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
- dev: true
-
- /fsevents@2.3.2:
- resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
- engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
- os: [darwin]
- requiresBuild: true
- dev: true
- optional: true
-
- /get-stream@6.0.1:
- resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==}
- engines: {node: '>=10'}
- dev: true
-
- /glob-parent@5.1.2:
- resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
- engines: {node: '>= 6'}
- dependencies:
- is-glob: 4.0.3
- dev: true
-
- /glob@7.1.6:
- resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==}
- dependencies:
- fs.realpath: 1.0.0
- inflight: 1.0.6
- inherits: 2.0.4
- minimatch: 3.1.2
- once: 1.4.0
- path-is-absolute: 1.0.1
- dev: true
-
- /globby@11.1.0:
- resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==}
- engines: {node: '>=10'}
- dependencies:
- array-union: 2.1.0
- dir-glob: 3.0.1
- fast-glob: 3.3.1
- ignore: 5.2.4
- merge2: 1.4.1
- slash: 3.0.0
- dev: true
-
- /has-flag@4.0.0:
- resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
- engines: {node: '>=8'}
- dev: false
-
- /human-signals@2.1.0:
- resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==}
- engines: {node: '>=10.17.0'}
- dev: true
-
- /ignore@5.2.4:
- resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
- engines: {node: '>= 4'}
- dev: true
-
- /inflight@1.0.6:
- resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
- dependencies:
- once: 1.4.0
- wrappy: 1.0.2
- dev: true
-
- /inherits@2.0.4:
- resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
- dev: true
-
- /is-binary-path@2.1.0:
- resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==}
- engines: {node: '>=8'}
- dependencies:
- binary-extensions: 2.2.0
- dev: true
-
- /is-extglob@2.1.1:
- resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /is-glob@4.0.3:
- resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==}
- engines: {node: '>=0.10.0'}
- dependencies:
- is-extglob: 2.1.1
- dev: true
-
- /is-number@7.0.0:
- resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
- engines: {node: '>=0.12.0'}
- dev: true
-
- /is-stream@2.0.1:
- resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==}
- engines: {node: '>=8'}
- dev: true
-
- /isexe@2.0.0:
- resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
- dev: true
-
- /joycon@3.1.1:
- resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==}
- engines: {node: '>=10'}
- dev: true
-
- /lilconfig@2.1.0:
- resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==}
- engines: {node: '>=10'}
- dev: true
-
- /lines-and-columns@1.2.4:
- resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==}
- dev: true
-
- /load-tsconfig@0.2.5:
- resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==}
- engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
- dev: true
-
- /lodash.sortby@4.7.0:
- resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==}
- dev: true
-
- /merge-stream@2.0.0:
- resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==}
- dev: true
-
- /merge2@1.4.1:
- resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
- engines: {node: '>= 8'}
- dev: true
-
- /micromatch@4.0.5:
- resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==}
- engines: {node: '>=8.6'}
- dependencies:
- braces: 3.0.2
- picomatch: 2.3.1
- dev: true
-
- /mimic-fn@2.1.0:
- resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==}
- engines: {node: '>=6'}
- dev: true
-
- /minimatch@3.1.2:
- resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
- dependencies:
- brace-expansion: 1.1.11
- dev: true
-
- /ms@2.1.2:
- resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
-
- /mz@2.7.0:
- resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
- dependencies:
- any-promise: 1.3.0
- object-assign: 4.1.1
- thenify-all: 1.6.0
- dev: true
-
- /normalize-path@3.0.0:
- resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /npm-run-path@4.0.1:
- resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==}
- engines: {node: '>=8'}
- dependencies:
- path-key: 3.1.1
- dev: true
-
- /object-assign@4.1.1:
- resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /once@1.4.0:
- resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
- dependencies:
- wrappy: 1.0.2
- dev: true
-
- /onetime@5.1.2:
- resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
- engines: {node: '>=6'}
- dependencies:
- mimic-fn: 2.1.0
- dev: true
-
- /path-is-absolute@1.0.1:
- resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
- engines: {node: '>=0.10.0'}
- dev: true
-
- /path-key@3.1.1:
- resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==}
- engines: {node: '>=8'}
- dev: true
-
- /path-type@4.0.0:
- resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==}
- engines: {node: '>=8'}
- dev: true
-
- /picomatch@2.3.1:
- resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
- engines: {node: '>=8.6'}
- dev: true
-
- /pirates@4.0.6:
- resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==}
- engines: {node: '>= 6'}
- dev: true
-
- /postcss-load-config@4.0.1:
- resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==}
- engines: {node: '>= 14'}
- peerDependencies:
- postcss: '>=8.0.9'
- ts-node: '>=9.0.0'
- peerDependenciesMeta:
- postcss:
- optional: true
- ts-node:
- optional: true
- dependencies:
- lilconfig: 2.1.0
- yaml: 2.3.1
- dev: true
-
- /punycode@2.3.0:
- resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
- engines: {node: '>=6'}
- dev: true
-
- /queue-microtask@1.2.3:
- resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
- dev: true
-
- /readdirp@3.6.0:
- resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==}
- engines: {node: '>=8.10.0'}
- dependencies:
- picomatch: 2.3.1
- dev: true
-
- /resolve-from@5.0.0:
- resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==}
- engines: {node: '>=8'}
- dev: true
-
- /reusify@1.0.4:
- resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
- engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
- dev: true
-
- /rollup@3.27.2:
- resolution: {integrity: sha512-YGwmHf7h2oUHkVBT248x0yt6vZkYQ3/rvE5iQuVBh3WO8GcJ6BNeOkpoX1yMHIiBm18EMLjBPIoUDkhgnyxGOQ==}
- engines: {node: '>=14.18.0', npm: '>=8.0.0'}
- hasBin: true
- optionalDependencies:
- fsevents: 2.3.2
- dev: true
-
- /run-parallel@1.2.0:
- resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
- dependencies:
- queue-microtask: 1.2.3
- dev: true
-
- /shebang-command@2.0.0:
- resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
- engines: {node: '>=8'}
- dependencies:
- shebang-regex: 3.0.0
- dev: true
-
- /shebang-regex@3.0.0:
- resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==}
- engines: {node: '>=8'}
- dev: true
-
- /signal-exit@3.0.7:
- resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==}
- dev: true
-
- /slash@3.0.0:
- resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==}
- engines: {node: '>=8'}
- dev: true
-
- /source-map@0.8.0-beta.0:
- resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
- engines: {node: '>= 8'}
- dependencies:
- whatwg-url: 7.1.0
- dev: true
-
- /strip-ansi@6.0.1:
- resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
- engines: {node: '>=8'}
- dependencies:
- ansi-regex: 5.0.1
- dev: false
-
- /strip-final-newline@2.0.0:
- resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==}
- engines: {node: '>=6'}
- dev: true
-
- /sucrase@3.34.0:
- resolution: {integrity: sha512-70/LQEZ07TEcxiU2dz51FKaE6hCTWC6vr7FOk3Gr0U60C3shtAN+H+BFr9XlYe5xqf3RA8nrc+VIwzCfnxuXJw==}
- engines: {node: '>=8'}
- hasBin: true
- dependencies:
- '@jridgewell/gen-mapping': 0.3.3
- commander: 4.1.1
- glob: 7.1.6
- lines-and-columns: 1.2.4
- mz: 2.7.0
- pirates: 4.0.6
- ts-interface-checker: 0.1.13
- dev: true
-
- /supports-color@7.2.0:
- resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==}
- engines: {node: '>=8'}
- dependencies:
- has-flag: 4.0.0
- dev: false
-
- /thenify-all@1.6.0:
- resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==}
- engines: {node: '>=0.8'}
- dependencies:
- thenify: 3.3.1
- dev: true
-
- /thenify@3.3.1:
- resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==}
- dependencies:
- any-promise: 1.3.0
- dev: true
-
- /to-regex-range@5.0.1:
- resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==}
- engines: {node: '>=8.0'}
- dependencies:
- is-number: 7.0.0
- dev: true
-
- /tr46@1.0.1:
- resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==}
- dependencies:
- punycode: 2.3.0
- dev: true
-
- /tree-kill@1.2.2:
- resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==}
- hasBin: true
- dev: true
-
- /ts-interface-checker@0.1.13:
- resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
- dev: true
-
- /tsup@7.2.0:
- resolution: {integrity: sha512-vDHlczXbgUvY3rWvqFEbSqmC1L7woozbzngMqTtL2PGBODTtWlRwGDDawhvWzr5c1QjKe4OAKqJGfE1xeXUvtQ==}
- engines: {node: '>=16.14'}
- hasBin: true
- peerDependencies:
- '@swc/core': ^1
- postcss: ^8.4.12
- typescript: '>=4.1.0'
- peerDependenciesMeta:
- '@swc/core':
- optional: true
- postcss:
- optional: true
- typescript:
- optional: true
- dependencies:
- bundle-require: 4.0.1(esbuild@0.18.19)
- cac: 6.7.14
- chokidar: 3.5.3
- debug: 4.3.4
- esbuild: 0.18.19
- execa: 5.1.1
- globby: 11.1.0
- joycon: 3.1.1
- postcss-load-config: 4.0.1
- resolve-from: 5.0.0
- rollup: 3.27.2
- source-map: 0.8.0-beta.0
- sucrase: 3.34.0
- tree-kill: 1.2.2
- transitivePeerDependencies:
- - supports-color
- - ts-node
- dev: true
-
- /webidl-conversions@4.0.2:
- resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==}
- dev: true
-
- /whatwg-url@7.1.0:
- resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==}
- dependencies:
- lodash.sortby: 4.7.0
- tr46: 1.0.1
- webidl-conversions: 4.0.2
- dev: true
-
- /which@2.0.2:
- resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
- engines: {node: '>= 8'}
- hasBin: true
- dependencies:
- isexe: 2.0.0
- dev: true
-
- /wrappy@1.0.2:
- resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
- dev: true
-
- /yaml@2.3.1:
- resolution: {integrity: sha512-2eHWfjaoXgTBC2jNM1LRef62VQa0umtvRiDSk6HSzW7RvS5YtkabJrwYLLEKWBc8a5U2PTSCs+dJjUTJdlHsWQ==}
- engines: {node: '>= 14'}
- dev: true
diff --git a/examples/plugin_template/src/index.ts b/examples/plugin_template/src/index.ts
deleted file mode 100644
index dd44b62..0000000
--- a/examples/plugin_template/src/index.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { command } from "cmd-ts";
-
-export default command({
- name: "custom",
- description: "A completely custom command dynamically imported at runtime!",
- args: {},
- handler() {
- console.log("CUSTOM COMMAND WORKS!!");
- },
-});
diff --git a/examples/plugin_template/tsconfig.json b/examples/plugin_template/tsconfig.json
deleted file mode 100644
index 71dfb43..0000000
--- a/examples/plugin_template/tsconfig.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "compilerOptions": {
- "jsx": "preserve",
- "noEmit": true,
- "module": "ESNext",
- "target": "ESNext",
- "moduleResolution": "node",
- "strict": true,
- "esModuleInterop": true,
- "forceConsistentCasingInFileNames": true,
- "skipLibCheck": true,
- "resolveJsonModule": true
- }
-}
diff --git a/examples/plugin_template/tsup.config.ts b/examples/plugin_template/tsup.config.ts
deleted file mode 100644
index d80d441..0000000
--- a/examples/plugin_template/tsup.config.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { defineConfig } from "tsup";
-
-export default defineConfig({
- entry: ["src/index.ts"],
- target: "esnext",
- format: "esm",
- splitting: false,
- sourcemap: true,
- clean: true,
-});
diff --git a/package.json b/package.json
index 04c27b1..d897b76 100644
--- a/package.json
+++ b/package.json
@@ -10,17 +10,14 @@
"url": "https://github.com/solidjs-community/solid-cli"
},
"scripts": {
- "test": "vitest",
+ "test": "vitest run",
"test:all": "turbo run test",
"build": "turbo run build",
"release": "pnpm build && changeset publish",
- "watch:all": "nodemon --no-stdin -q --watch packages/core/src -e ts --exec 'turbo run build --scope=core' --watch packages/reactivity/src -e ts --exec 'turbo run build --scope=reactivity' --watch packages/ui/src -e ts --exec 'turbo run build --scope=ui' --watch packages/utils/src -e ts --exec 'turbo run build --scope=utils'",
- "watch:core": "nodemon --watch packages/core/src -e ts --exec 'turbo run build --scope=core'",
- "watch:reactivity": "nodemon --watch packages/reactivity/src -e ts --exec 'turbo run build --scope=reactivity'",
- "watch:ui": "nodemon --watch packages/ui/src -e ts --exec 'turbo run build --scope=ui'",
- "watch:utils": "nodemon --watch packages/utils/src -e ts --exec 'turbo run build --scope=utils'",
- "start": "cd packages/core && pnpm start",
- "format": "prettier --write ."
+ "start": "pnpm build && cd packages/create-solid && pnpm start",
+ "format": "prettier --write .",
+ "watch:build": "turbo watch build",
+ "update-deps": "ncu -u --packageFile packages/**/package.json"
},
"contributors": [
{
@@ -34,11 +31,14 @@
"./packages/*"
],
"devDependencies": {
- "@changesets/cli": "2.27.9",
- "nodemon": "^3.1.7",
- "prettier": "^3.3.3",
- "turbo": "^2.2.3",
- "vitest": "^2.1.5"
+ "@changesets/cli": "2.31.1",
+ "@types/node": "26.1.1",
+ "jiti": "^2.7.0",
+ "prettier": "^3.9.6",
+ "tsup": "^8.5.1",
+ "turbo": "^2.10.6",
+ "typescript": "^7.0.2",
+ "vitest": "^4.1.10"
},
- "packageManager": "pnpm@9.6.0"
+ "packageManager": "pnpm@11.15.1"
}
diff --git a/packages/commands/.gitignore b/packages/commands/.gitignore
deleted file mode 100644
index fbf0622..0000000
--- a/packages/commands/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-types
\ No newline at end of file
diff --git a/packages/commands/package.json b/packages/commands/package.json
deleted file mode 100644
index 916076c..0000000
--- a/packages/commands/package.json
+++ /dev/null
@@ -1,54 +0,0 @@
-{
- "name": "@solid-cli/commands",
- "version": "0.0.24",
- "description": "The main command handlers for the Solid CLI",
- "license": "MIT",
- "homepage": "https://solid-cli.netlify.app",
- "repository": {
- "type": "git",
- "url": "https://github.com/solidjs-community/solid-cli"
- },
- "files": [
- "dist",
- "types"
- ],
- "main": "./dist/index.mjs",
- "module": "./dist/index.mjs",
- "types": "./types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/index.mjs",
- "require": "./dist/index.mjs",
- "types": "./types/index.d.ts"
- },
- "./new": {
- "import": "./dist/handlers/new.mjs",
- "require": "./dist/handlers/new.mjs",
- "types": "./types/handlers/new.d.ts"
- }
- },
- "scripts": {
- "test": "vitest run",
- "build": "tsc && tsup"
- },
- "devDependencies": {
- "@chialab/esbuild-plugin-meta-url": "^0.18.2",
- "@types/node": "^22.9.0",
- "prettier": "^3.3.3",
- "tsup": "^8.3.5",
- "typescript": "^5.6.3"
- },
- "publishConfig": {
- "access": "public"
- },
- "dependencies": {
- "@begit/core": "^0.0.19",
- "@clack/prompts": "0.7.0",
- "@solid-cli/reactivity": "workspace:*",
- "@solid-cli/ui": "workspace:*",
- "@solid-cli/utils": "workspace:*",
- "execa": "^8.0.1",
- "picocolors": "^1.1.1",
- "sucrase": "^3.35.0"
- }
-}
diff --git a/packages/commands/src/handlers/add.ts b/packages/commands/src/handlers/add.ts
deleted file mode 100644
index 5c8a4e6..0000000
--- a/packages/commands/src/handlers/add.ts
+++ /dev/null
@@ -1,222 +0,0 @@
-import { autocomplete } from "@solid-cli/ui";
-import { S_BAR, cancelable, spinnerify } from "@solid-cli/ui";
-import { Integrations, Supported, integrations, setRootFile } from "../lib/integrations";
-import * as p from "@clack/prompts";
-import color from "picocolors";
-import { primitives, loadPrimitives } from "@solid-cli/utils/primitives";
-import { isSolidStart, t } from "@solid-cli/utils";
-import { fileExists, getRootFile, getConfigFile, validateFilePath } from "../lib/utils/helpers";
-import { writeFile, readFile } from "@solid-cli/utils/fs";
-import { transformPlugins, type PluginOptions } from "@solid-cli/utils/transform";
-import {
- UPDATESQUEUE,
- clearQueue,
- flushCommandUpdates,
- flushFileUpdates,
- flushPackageUpdates,
- queueUpdate,
- summarizeUpdates,
-} from "@solid-cli/utils/updates";
-
-const handleAutocompleteAdd = async () => {
- const supportedIntegrations = (Object.keys(integrations) as Supported[]).map((value) => ({ label: value, value }));
- const opts = () => [...supportedIntegrations, ...primitives()];
-
- loadPrimitives().catch((e) => p.log.error(e));
-
- const a = await cancelable(
- autocomplete({
- message: t.ADD_PACKAGES,
- options: opts,
- }),
- );
-
- if (a.length === 0) {
- p.log.warn(t.NOTHING_SELECTED);
- return;
- }
-
- const shouldInstall = await cancelable(
- p.select({
- options: [
- { label: t.YES, value: true },
- { label: t.NO, value: false },
- { label: t.YES_FORCE, value: [true, "force"] },
- ],
- message: `${t.CONFIRM_INSTALL(a.length)} \n${color.red(S_BAR)} \n${color.red(S_BAR)} ${
- " " + color.yellow(a.map((opt) => opt.label).join(" ")) + " "
- } \n${color.red(S_BAR)} `,
- }),
- );
-
- if (!shouldInstall) return;
-
- let forceTransform = false;
- if (Array.isArray(shouldInstall) && shouldInstall[1] === "force") {
- forceTransform = true;
- }
- const packages = a.map((opt) => opt.value as Supported);
-
- return { packages, forceTransform };
-};
-const isIntegration = (str: string) => {
- if (Object.keys(integrations).includes(str)) return true;
- return false;
-};
-/**
- * Transforms a list containing primitives, either by name or full package name, and returns the corresponding primitive objects
- */
-const transformPrimitives = async (ps: string[]) => {
- if (!ps.length) return [];
-
- if (!primitives().length) {
- await spinnerify({
- startText: t.LOADING_PRIMITIVES,
- finishText: t.PRIMITIVES_LOADED,
- fn: loadPrimitives,
- });
- }
-
- const mappedInput = ps.map((p) => p.replace("@solid-primitives/", ""));
-
- return primitives().filter((p) => mappedInput.includes(p.value.replace("@solid-primitives/", "")));
-};
-
-type Configs = Integrations[keyof Integrations][];
-
-export const handleAdd = async (packages?: string[], forceTransform: boolean = false) => {
- if (!packages?.length) {
- const autocompleted = await handleAutocompleteAdd();
-
- if (!autocompleted) return;
-
- packages = autocompleted.packages;
- forceTransform = autocompleted.forceTransform;
- }
- const possiblePrimitives: string[] = [];
- const configs: Configs = packages
- .map((n) => {
- if (!n) return;
- if (!isIntegration(n)) {
- possiblePrimitives.push(n);
- return;
- }
- const res = integrations[n as Supported];
- if (!res) {
- p.log.error(t.NO_SUPPORT(n));
- return;
- }
- return res;
- })
- .filter((p) => p) as Configs;
-
- const configType = (await isSolidStart()) ? "app" : "vite";
-
- const configFile = await getConfigFile(configType);
-
- for (let i = 0; i < configs.length; i++) {
- const config = configs[i];
- config.installs.forEach((p) => queueUpdate({ type: "package", name: p, dev: false }));
- config.installsDev?.forEach((p) => queueUpdate({ type: "package", name: p, dev: true }));
- }
- // Queue primitives
- for (const primitive of await transformPrimitives(possiblePrimitives)) {
- queueUpdate({ type: "package", name: primitive.value, dev: false });
- }
-
- if (!configs.length) return;
- const pluginOptions = configs.map((c) => c.pluginOptions).filter(Boolean) as PluginOptions[];
- if (pluginOptions.length) {
- await spinnerify({
- startText: "Processing config",
- finishText: "Config processed",
- fn: async () => {
- const code = await transformPlugins(
- configs.map((c) => c.pluginOptions).filter(Boolean) as PluginOptions[],
- { type: configType, name: configFile, contents: (await readFile(configFile)).toString() },
- forceTransform,
- undefined,
- );
- await writeFile(configFile, code);
- },
- });
- }
-
- p.log.info("Preparing post install steps for integrations");
-
- let projectRoot = await getRootFile();
- setRootFile(projectRoot);
-
- if (!fileExists(projectRoot)) {
- p.log.error(color.red(`Can't find root file \`${projectRoot.split("/")[1]}\`.`));
- await cancelable(
- p.text({
- message: `Type path to root: `,
- validate(value) {
- if (!value.length) return `Path can not be empty`;
- const path = validateFilePath(value, ["app.tsx", "index.tsx"]);
- if (!path) return `File at \`${value}\` not found. Please try again`;
- else setRootFile(path);
- },
- }),
- );
- }
- // Run our additional configs
- await spinnerify({
- startText: "Running additional config steps",
- finishText: "Additional config steps complete",
- fn: async () => {
- for (const cfg of configs) {
- await cfg.additionalConfig?.();
- }
- },
- });
- if (UPDATESQUEUE.length === 0) return;
-
- const { fileUpdates, packageUpdates, commandUpdates } = summarizeUpdates();
-
- // Inspired by Qwik's CLI
- if (fileUpdates.length) p.log.message([`${color.cyan("Modify")}`, ...fileUpdates.map((f) => ` - ${f}`)].join("\n"));
-
- if (packageUpdates.length)
- p.log.message([`${color.cyan("Install")}`, ...packageUpdates.map((p) => ` - ${p.name}` + (p.dev ? " (dev)" : ""))].join("\n"));
- if (commandUpdates.length)
- p.log.message([`${color.cyan("Run commands")}`, ...commandUpdates.map((p) => ` - ${p}`)].join("\n"));
-
- const confirmed = await p.confirm({ message: "Do you wish to continue?" });
- if (!confirmed || p.isCancel(confirmed)) return;
-
- await spinnerify({ startText: "Writing files...", finishText: "Updates written", fn: flushFileUpdates });
- await spinnerify({ startText: "Installing packages...", finishText: "Packages installed", fn: flushPackageUpdates });
- await spinnerify({ startText: "Running setup commands", finishText: "Setup commands ran", fn: flushCommandUpdates });
-
- clearQueue();
-
- const postInstalls = configs.filter((c) => c.postInstall);
- if (postInstalls.length === 0) return;
-
- p.log.message(
- `${postInstalls.length} ${postInstalls.length === 1 ? "package has" : "packages have"
- } post install steps that need to run.`,
- );
-
- const pInstallConfirmed = await p.confirm({ message: "Do you wish to continue?" });
- if (!pInstallConfirmed || p.isCancel(pInstallConfirmed)) return;
-
- p.log.info("Running post installs");
- // Run postInstalls
- for (const cfg of configs) {
- await cfg.postInstall?.();
- }
-
- p.log.success("Post install steps complete!");
- // await spinnerify({
- // startText: t.POST_INSTALL,
- // finishText: t.POST_INSTALL_COMPLETE,
- // fn: async () => {
- // for (const cfg of configs) {
- // await cfg.postInstall?.();
- // }
- // },
- // });
-};
diff --git a/packages/commands/src/handlers/new.ts b/packages/commands/src/handlers/new.ts
deleted file mode 100644
index ae03fe5..0000000
--- a/packages/commands/src/handlers/new.ts
+++ /dev/null
@@ -1,246 +0,0 @@
-import * as p from "@clack/prompts";
-import { openInBrowser } from "@solid-cli/utils";
-import { cancelable, spinnerify } from "@solid-cli/ui";
-import { t } from "@solid-cli/utils";
-import { insertAtEnd, readFileToString } from "@solid-cli/utils/fs";
-import { flushQueue } from "@solid-cli/utils/updates";
-import { rm } from "fs/promises";
-import { join, resolve } from "path";
-import { Dirent, copyFileSync, existsSync, mkdirSync, readdirSync, writeFileSync } from "fs";
-import { downloadRepo } from "@begit/core";
-import { transform } from "sucrase";
-import { detectPackageManager } from "@solid-cli/utils/package-manager";
-const gitIgnore = `
-dist
-.solid
-.output
-.vercel
-.netlify
-.vinxi
-app.config.timestamp_*.js
-
-# Environment
-.env
-.env*.local
-
-# dependencies
-/node_modules
-
-# IDEs and editors
-/.idea
-.project
-.classpath
-*.launch
-.settings/
-
-# Temp
-gitignore
-
-# System Files
-.DS_Store
-Thumbs.db
-`;
-
-const startSupported = [
- "basic",
- "bare",
- "hackernews",
- "notes",
- "todomvc",
- "with-auth",
- "with-authjs",
- "with-drizzle",
- "with-mdx",
- "with-prisma",
- "with-solid-styled",
- "with-tailwindcss",
- "with-trpc",
- "with-unocss",
- "with-vitest",
- "experiments",
-] as const;
-const localSupported = ["ts", "js"] as const;
-const stackblitzSupported = ["bare"] as const;
-
-export type AllSupported = (typeof localSupported)[number] | (typeof stackblitzSupported)[number];
-export const isSupported = (template: string): template is AllSupported => {
- return localSupported.indexOf(template as any) !== -1;
-};
-const modifyReadme = async (name: string) => {
- await insertAtEnd(
- `${name}/README.md`,
- "\n## This project was created with the [Solid CLI](https://solid-cli.netlify.app)\n",
- );
- await flushQueue();
-};
-
-const recurseFiles = (startPath: string, cb: (file: Dirent, startPath: string) => void) => {
- startPath = resolve(startPath);
-
- const files = readdirSync(startPath, { withFileTypes: true });
-
- for (const file of files) {
- cb(file, startPath);
- }
-};
-
-const convertToJS = async (file: Dirent, startPath: string) => {
- const src = join(startPath, file.name);
- const dest = resolve(startPath.replace(".solid-start", ""), file.name);
- if (file.isDirectory()) {
- mkdirSync(dest, { recursive: true });
- recurseFiles(resolve(startPath, file.name), convertToJS);
- } else if (file.isFile()) {
- if (src.endsWith(".ts") || src.endsWith(".tsx")) {
- let { code } = transform(await readFileToString(src), {
- transforms: ["typescript", "jsx"],
- jsxRuntime: "preserve",
- });
-
- writeFileSync(dest.replace(".ts", ".js"), code, { flag: "wx" });
- } else {
- copyFileSync(src, dest);
- }
- }
-};
-
-const handleTSConversion = async (tempDir: string, projectName: string) => {
- await rm(resolve(tempDir, "tsconfig.json"));
- writeFileSync(
- resolve(projectName, "jsconfig.json"),
- JSON.stringify(
- {
- compilerOptions: {
- jsx: "preserve",
- jsxImportSource: "solid-js",
- paths: {
- "~/*": ["./src/*"],
- },
- },
- },
- null,
- 2,
- ),
- { flag: "wx" },
- );
-
- // Convert all ts files in temp directory into js
- recurseFiles(tempDir, convertToJS);
-
- // Remove temp directory
- await rm(join(process.cwd(), tempDir), {
- recursive: true,
- force: true,
- });
-};
-
-const handleNewStartProject = async (projectName: string, variation?: AllSupported) => {
- const template = await cancelable(
- p.select({
- message: t.NEW_START,
- initialValue: "ts",
- options: startSupported.map((s) => ({ label: s, value: s })),
- maxItems: process.stdout.rows - 4,
- }),
- );
-
- const withTs = variation ? variation !== "ts" : await cancelable(p.confirm({ message: "Use Typescript?" }));
-
- // If the user does not want ts, we create the project in a temp directory inside the project directory
- const tempDir = withTs ? projectName : join(projectName, ".solid-start");
- const readmeAlreadyExists = existsSync(join(projectName, "README.md"));
- await spinnerify({
- startText: t.CREATING_PROJECT,
- finishText: t.PROJECT_CREATED,
- fn: async () => {
- await downloadRepo({
- repo: { owner: "solidjs", name: "solid-start", subdir: `examples/${template}` },
- dest: tempDir,
- });
- },
- });
-
- if (!withTs) await handleTSConversion(tempDir, projectName);
-
- // Add .gitignore
- writeFileSync(join(projectName, ".gitignore"), gitIgnore);
- if (!readmeAlreadyExists) await modifyReadme(projectName);
- const pM = detectPackageManager();
- p.note(
- `cd ${projectName}
-${pM.name} install
-${pM.name} ${pM.runScriptCommand("dev")}`,
- t.GET_STARTED,
- );
-};
-
-const handleAutocompleteNew = async (name: string, isStart?: boolean) => {
- isStart ??= await cancelable(p.confirm({ message: t.IS_START_PROJECT }));
-
- if (isStart) {
- handleNewStartProject(name);
- return;
- }
-
- const template = (await cancelable(
- p.select({
- message: t.TEMPLATE,
- initialValue: "ts",
- options: localSupported.map((s) => ({ label: s, value: s })),
- }),
- )) as unknown as AllSupported;
-
- await handleNew(template, name);
-};
-export const handleNew = async (
- variation?: AllSupported,
- name?: string,
- stackblitz: boolean = false,
- isStart?: boolean,
-) => {
- name ??= await cancelable(
- p.text({ message: t.PROJECT_NAME, placeholder: "solid-project", defaultValue: "solid-project" }),
- );
-
- if (!variation) {
- await handleAutocompleteNew(name, isStart);
- return;
- }
-
- if (stackblitz) {
- await spinnerify({
- startText: t.OPENING_IN_BROWSER(variation),
- finishText: t.OPENED_IN_BROWSER,
- fn: () => openInBrowser(`https://solid.new/${variation}`),
- });
- return;
- }
-
- const withTs = variation.startsWith("ts") ? await cancelable(p.confirm({ message: "Use Typescript?" })) : false;
-
- // If the user does not want ts, we create the project in a temp directory inside the project directory
- // If project is already JS don't bother transpiling
- const tempDir = withTs || variation.startsWith("js") ? name : join(name, ".solid-start");
- const readmeAlreadyExists = existsSync(join(name, "README.md"));
-
- await spinnerify({
- startText: t.CREATING_PROJECT,
- finishText: t.PROJECT_CREATED,
- fn: async () => {
- await downloadRepo({ repo: { owner: "solidjs", name: "templates", subdir: variation }, dest: tempDir });
- },
- });
- // Don't try to convert to ts if the template used is JS
- if (!withTs && !variation.startsWith("js")) await handleTSConversion(tempDir, name);
-
- // Add .gitignore
- writeFileSync(join(name, ".gitignore"), gitIgnore);
- if (!readmeAlreadyExists) await modifyReadme(name ?? variation);
- const pM = detectPackageManager();
- p.note(
- `cd ${name}
-${pM.name} install
-${pM.name} ${pM.runScriptCommand("dev")}`,
- t.GET_STARTED,
- );
-};
diff --git a/packages/commands/src/handlers/start/adapter.ts b/packages/commands/src/handlers/start/adapter.ts
deleted file mode 100644
index f2b6ef3..0000000
--- a/packages/commands/src/handlers/start/adapter.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { readFile, writeFile } from "@solid-cli/utils/fs";
-import { transformPlugins } from "@solid-cli/utils/transform";
-import * as p from "@clack/prompts";
-import { cancelable } from "@solid-cli/ui";
-
-export const supportedAdapters = [
- "aws",
- "cloudflare-pages",
- "cloudflare-workers",
- "deno",
- "netlify",
- "node",
- "static",
- "vercel",
-] as const;
-
-type SupportedAdapters = (typeof supportedAdapters)[number];
-
-const handleAutocompleteAdapter = async () => {
- const name = (await cancelable(
- p.select({
- message: "Select an adapter",
- options: supportedAdapters.map((a) => ({ value: a, label: a })),
- }),
- )) as SupportedAdapters;
- await handleAdapter(name, true);
-};
-
-export const handleAdapter = async (name?: string, forceTransform = false) => {
- if (!name) {
- await handleAutocompleteAdapter();
- return;
- }
- const sym = Symbol(name).toString();
- let code = await transformPlugins(
- [],
- { type: "app", name: "app.config.ts", contents: (await readFile("app.config.ts")).toString() },
- forceTransform,
- );
- code = `import ${name} from "solid-start-${name}";\n` + code;
- code = code.replace(`"${sym}"`, `${name}({})`);
- await writeFile("app.config.ts", code);
-};
diff --git a/packages/commands/src/handlers/start/api.ts b/packages/commands/src/handlers/start/api.ts
deleted file mode 100644
index 79dd2bb..0000000
--- a/packages/commands/src/handlers/start/api.ts
+++ /dev/null
@@ -1,41 +0,0 @@
-import { isSolidStart, createApi } from "@solid-cli/utils";
-import * as p from "@clack/prompts";
-import { cancelable, spinnerify } from "@solid-cli/ui";
-
-const handleAutocompleteApi = async () => {
- const path = await cancelable(
- p.text({
- message: "Enter the path in which the api file will be created",
- placeholder: "/user",
- validate(value) {
- if (!value.length) return "Path is required";
- },
- }),
- );
-
- const name = await cancelable(
- p.text({
- message: "Enter the name for the api file (required)",
- validate(value) {
- if (!value.length) return "Name is required";
- },
- }),
- );
-
- await handleApi(path, name);
-};
-export const handleApi = async (path?: string, name?: string) => {
- if (!(await isSolidStart())) {
- p.log.error("Cannot run command. Your project doesn't include solid-start");
- return;
- }
- if (!path) {
- await handleAutocompleteApi();
- return;
- }
- await spinnerify({
- startText: "Creating new api file",
- finishText: "Api file created",
- fn: () => createApi(path, name),
- });
-};
diff --git a/packages/commands/src/handlers/start/data.ts b/packages/commands/src/handlers/start/data.ts
deleted file mode 100644
index 380bb1b..0000000
--- a/packages/commands/src/handlers/start/data.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { isSolidStart, createData } from "@solid-cli/utils";
-import * as p from "@clack/prompts";
-import { cancelable, spinnerify } from "@solid-cli/ui";
-
-const handleAutocompleteData = async () => {
- const path = await cancelable(
- p.text({
- message: "Enter the path in which the data file will be created",
- placeholder: "/user/login",
- validate(value) {
- if (!value.length) return "Path is required";
- },
- }),
- );
-
- const name = await cancelable(
- p.text({
- message: "Enter the name for the data file (leave this blank for the default)",
- }),
- );
-
- await handleData(path, name);
-};
-
-export const handleData = async (path?: string, name?: string) => {
- if (!(await isSolidStart())) {
- p.log.error("Cannot run command. Your project doesn't include solid-start");
- return;
- }
- if (!path) {
- await handleAutocompleteData();
- return;
- }
- await spinnerify({
- startText: "Creating new data file",
- finishText: "Data file created",
- fn: () => createData(path, name),
- });
-};
diff --git a/packages/commands/src/handlers/start/index.ts b/packages/commands/src/handlers/start/index.ts
deleted file mode 100644
index 2145bbb..0000000
--- a/packages/commands/src/handlers/start/index.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-export * from "./adapter";
-export * from "./api";
-export * from "./data";
-export * from "./mode";
-export * from "./route";
diff --git a/packages/commands/src/handlers/start/mode.ts b/packages/commands/src/handlers/start/mode.ts
deleted file mode 100644
index c3e5a2b..0000000
--- a/packages/commands/src/handlers/start/mode.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-import { writeFile, readFile } from "@solid-cli/utils/fs";
-import { transformPlugins } from "@solid-cli/utils/transform";
-import { isSolidStart } from "@solid-cli/utils";
-import * as p from "@clack/prompts";
-import { cancelable } from "@solid-cli/ui";
-
-export const supportedModes = ["csr", "ssr", "ssg"] as const;
-type SupportedModes = (typeof supportedModes)[number];
-
-const handleAutocompleteMode = async () => {
- const mode = (await cancelable(
- p.select({
- message: "Select a mode",
- options: supportedModes.map((a) => ({ value: a, label: a.toUpperCase() })),
- }),
- )) as SupportedModes;
- await handleMode(mode);
-};
-
-export const handleMode = async (mode?: SupportedModes) => {
- if (!(await isSolidStart())) {
- p.log.error("Cannot run command. Your project doesn't include solid-start");
- return;
- }
- if (!mode) {
- handleAutocompleteMode();
- return;
- }
- p.log.info("Updating config");
- if (mode != "ssg") {
- const newConfig = await transformPlugins(
- [],
- { type: "app", name: "app.config.ts", contents: (await readFile("app.config.ts")).toString() },
- true,
- true,
- );
- await writeFile("app.config.ts", newConfig);
- }
-};
diff --git a/packages/commands/src/handlers/start/route.ts b/packages/commands/src/handlers/start/route.ts
deleted file mode 100644
index 6e1ea45..0000000
--- a/packages/commands/src/handlers/start/route.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import * as p from "@clack/prompts";
-import { isSolidStart, createRoute } from "@solid-cli/utils";
-import { cancelable, spinnerify } from "@solid-cli/ui";
-const handleAutocompleteRoute = async () => {
- const path = await cancelable(
- p.text({
- message: "Please provide a path for the route",
- placeholder: "/user/login",
- validate(value) {
- if (!value.length) return "Path is required";
- },
- }),
- );
- const name = await cancelable(
- p.text({
- message: "Please provide a name for the route",
-
- validate(value) {
- if (!value.length) return "Name for route is required";
- },
- }),
- );
-
- await handleRoute(path, name);
-};
-export const handleRoute = async (path?: string, name?: string) => {
- if (!(await isSolidStart())) {
- p.log.error("Cannot run command. Your project doesn't include solid-start");
- return;
- }
- if (!path) {
- await handleAutocompleteRoute();
- return;
- }
- await spinnerify({
- startText: "Creating new route",
- finishText: "Route created",
- fn: () => createRoute(path, name),
- });
-};
diff --git a/packages/commands/src/index.ts b/packages/commands/src/index.ts
deleted file mode 100644
index 32fff0a..0000000
--- a/packages/commands/src/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export * from "./handlers/add";
-export * from "./handlers/new";
-export * from "./handlers/start";
diff --git a/packages/commands/src/lib/integrations.ts b/packages/commands/src/lib/integrations.ts
deleted file mode 100644
index 04b2049..0000000
--- a/packages/commands/src/lib/integrations.ts
+++ /dev/null
@@ -1,221 +0,0 @@
-import { insertAfter, insertAtBeginning } from "@solid-cli/utils/fs";
-import { writeFile } from "fs/promises";
-import { fileExists, manipulateJsonFile, validateFilePath } from "./utils/helpers";
-import { $ } from "execa";
-import { getRunnerCommand, detectPackageManager } from "@solid-cli/utils/package-manager";
-import { createSignal } from "@solid-cli/reactivity";
-import * as p from "@clack/prompts";
-import color from "picocolors";
-import { cancelable } from "@solid-cli/ui";
-import { flushQueue } from "@solid-cli/utils/updates";
-import { PluginOptions } from "@solid-cli/utils/transform";
-
-// All the integrations/packages that we support
-export type Supported = keyof typeof integrations;
-
-export type IntegrationsValue = {
- pluginOptions?: PluginOptions;
- installs: string[];
- installsDev?: string[];
- additionalConfig?: () => Promise;
- postInstall?: () => Promise;
-};
-
-export type Integrations = Record;
-
-export const [rootFile, setRootFile] = createSignal(undefined);
-
-export const integrations: Record = {
- "tailwind": {
- installs: ["tailwindcss", "postcss", "autoprefixer"],
- postInstall: async () => {
- const pM = detectPackageManager();
- await $`${getRunnerCommand(pM)} tailwindcss init -p`;
- let tailwindConfig = "tailwind.config.js";
- if (!fileExists(tailwindConfig)) {
- p.log.error(color.red(`Can't find tailwind config file`));
- await cancelable(
- p.text({
- message: `Type path to tailwind config: `,
- validate(value) {
- if (!value.length) return `Path can not be empty`;
- const path = validateFilePath(value, "tailwind.config");
- if (!path) return `Tailwind config at \`${value}\` not found. Please try again`;
- else {
- tailwindConfig = path;
- }
- },
- }),
- );
- }
-
- let indexCss = "./src/index.css";
- if (!fileExists(indexCss)) {
- p.log.error(color.red(`Can't find index.css`));
- await cancelable(
- p.text({
- message: `Type path to index.css: `,
- validate(value) {
- if (!value.length) return `Path can not be empty`;
- const path = validateFilePath(value, "index.css");
- if (!path) return `index.css at \`${value}\` not found. Please try again`;
- else {
- indexCss = path;
- }
- },
- }),
- );
- }
- p.log.info("Updating tailwind config");
- await insertAfter(tailwindConfig, "content: [", '"./index.html", "./src/**/*.{js,ts,jsx,tsx}"');
- await insertAtBeginning(indexCss, "@tailwind base;\n@tailwind components;\n@tailwind utilities;\n");
- // Instantly flush queue
- await flushQueue();
- },
- },
- "unocss": {
- pluginOptions: {
- importName: "UnoCss",
- importSource: "unocss/vite",
- isDefault: true,
- options: {},
- },
- installs: [""],
- installsDev: ["unocss"],
- additionalConfig: async () => {
- const path = rootFile();
- if (!path) return;
- await insertAtBeginning(path, `import "virtual:uno.css";\n`);
- },
- },
- "vitepwa": {
- pluginOptions: {
- importName: "VitePWA",
- importSource: "vite-plugin-pwa",
- isDefault: false,
- options: {},
- },
- installs: ["vite-plugin-pwa"],
- },
- "solid-devtools": {
- pluginOptions: {
- importName: "devtools",
- importSource: "solid-devtools/vite",
- isDefault: true,
- options: {},
- },
- installs: ["solid-devtools"],
- additionalConfig: async () => {
- const path = rootFile();
- if (!path) return;
- await insertAtBeginning(path, `import "solid-devtools";\n`);
- },
- },
- "vitest": {
- installs: [],
- installsDev: [
- "vitest",
- "jsdom",
- "@solidjs/testing-library",
- "@testing-library/user-event",
- "@testing-library/jest-dom",
- ],
- additionalConfig: async () => {
- try {
- p.log.info("Adding test script to package.json");
- let hasStart = false;
- manipulateJsonFile("package.json", (packageJson) => {
- if (!packageJson.scripts) { packageJson.scripts = {}; }
- if (!/\bvitest\b/.test(packageJson.scripts.test || "")) {
- packageJson.scripts.test = "vitest";
- }
- hasStart = packageJson.dependencies["@solidjs/start"]
- return packageJson;
- });
- const hasTs = fileExists("tsconfig.json");
- if (hasTs) {
- p.log.info("Adding testing types to tsconfig.json");
- manipulateJsonFile("tsconfig.json", (tsConfig) => {
- if (!tsConfig.compilerOptions) {
- tsConfig.compilerOptions = {};
- }
- tsConfig.compilerOptions.types = [
- ...new Set([...(tsConfig.compilerOptions.types || []), "vite/client", "@testing-library/jest-dom"]),
- ];
- return tsConfig;
- });
- }
- if (
- hasStart &&
- ["ts", "mjs", "cjs", "js"].every(
- (suffix) => !fileExists(`vite.config.${suffix}`) && !fileExists(`vitest.config.${suffix}`),
- )
- ) {
- const suffix = hasTs ? "ts" : "mjs";
- p.log.info(`Adding vitest.config.${suffix}`);
- await writeFile(
- `vitest.config.${suffix}`,
- `import solid from "vite-plugin-solid";
-import { defineConfig } from "vitest/config";
-
-export default defineConfig({
- plugins: [solid()],
- resolve: {
- conditions: ["development", "browser"],
- },
-});
-`,
- "utf-8",
- );
- }
- } catch (err) {
- console.error(err);
- }
- },
- },
- "tauri-v1.x": {
- installs: ["@tauri-apps/cli"],
- postInstall: async () => {
- try {
- let name = "";
- manipulateJsonFile("package.json", (packageJson) => {
- if (!packageJson.scripts) { packageJson.scripts = {}; }
- packageJson.scripts.tauri = "tauri";
- name = packageJson.name;
- return packageJson;
- });
- await flushQueue();
- const pM = detectPackageManager();
- await $`${getRunnerCommand(pM)} tauri init --ci -A ${name} -W ${name} -D ../dist -P http://localhost:3000`;
- p.note(`Make sure you have installed all prerequisites: https://tauri.app/v1/guides/getting-started/prerequisites
-
- Start tauri development with ${color.bold(pM.name)} ${color.bold(pM.runScriptCommand("tauri dev"))}`);
- } catch (err) {
- console.error(err);
- }
- },
- },
- "tauri-v2.x": {
- installs: ["@tauri-apps/cli@next"],
- postInstall: async () => {
- try {
- let name = "";
- manipulateJsonFile("package.json", (packageJson) => {
- if (!packageJson.scripts) { packageJson.scripts = {}; }
- packageJson.scripts.tauri = "tauri";
- name = packageJson.name;
- return packageJson;
- })
- await flushQueue();
- const pM = detectPackageManager();
- await $`${getRunnerCommand(pM)} tauri init --ci -A ${name} -W ${name} -D ../dist -P http://localhost:3000`;
- p.note(`Make sure you have installed all prerequisites: https://v2.tauri.app/start/prerequisites/
-
- Start tauri development with ${color.bold(pM.name)} ${color.bold(pM.runScriptCommand("tauri dev"))}`);
- } catch (err) {
- console.error(err);
- }
- },
- },
-};
-
diff --git a/packages/commands/src/lib/utils/helpers.ts b/packages/commands/src/lib/utils/helpers.ts
deleted file mode 100644
index b910217..0000000
--- a/packages/commands/src/lib/utils/helpers.ts
+++ /dev/null
@@ -1,152 +0,0 @@
-import { existsSync, lstatSync, readdirSync } from "fs";
-import { readFile, writeFile } from "fs/promises";
-import { isSolidStart } from "@solid-cli/utils";
-import { join, resolve } from "path";
-import { $ } from "execa";
-import { cancelable } from "@solid-cli/ui";
-import * as p from "@clack/prompts";
-import color from "picocolors";
-
-export const getProjectRoot = async () => {
- const { stdout } = await $`npm root`;
-
- return stdout.slice(0, stdout.lastIndexOf("/"));
-};
-
-export const getRootFile = async () => {
- if (await isSolidStart()) {
- return "src/app.tsx";
- }
- return "src/index.tsx";
-};
-
-export const fileExists = (path: string) => {
- return existsSync(path);
-};
-
-export function validateFilePath(path: string, lookingFor: string): string | undefined;
-export function validateFilePath(path: string, lookingFor: string[]): string | undefined;
-export function validateFilePath(path: string, lookingFor: string | string[]): string | undefined {
- path = resolve(path);
- let isDir: boolean;
- try {
- console.log(path);
- isDir = lstatSync(path).isDirectory();
- } catch (e) {
- return undefined;
- }
- if (isDir) {
- const files = readdirSync(path, { withFileTypes: true });
-
- const config = files.find((file) => {
- if (Array.isArray(lookingFor)) {
- return lookingFor.some((s) => file.name.startsWith(s));
- }
-
- return file.name.startsWith(lookingFor);
- });
- return config ? join(path, config.name) : undefined;
- }
-
- const pathIsValid = Array.isArray(lookingFor)
- ? lookingFor.some((s) => path.startsWith(s))
- : path.startsWith(lookingFor);
-
- const exists = fileExists(path) && pathIsValid;
-
- return exists ? path : undefined;
-}
-
-export async function findFiles(
- startPath: string,
- lookingFor: string | string[],
- opts: { depth?: number; ignoreDirs?: string[]; startsWith?: boolean },
-): Promise {
- let { depth = Infinity, ignoreDirs = ["node_modules", "."], startsWith = true } = opts;
-
- startPath = resolve(startPath);
- let isDir: boolean;
- try {
- isDir = lstatSync(startPath).isDirectory();
- } catch (e) {
- return [];
- }
- if (!isDir) {
- startPath = resolve(startPath.slice(0, startPath.lastIndexOf("/")));
- }
-
- let filePaths: string[] = [];
-
- const files = readdirSync(startPath, { withFileTypes: true });
-
- for (const file of files) {
- if (file.isDirectory() && !ignoreDirs.some((s) => file.name.includes(s))) {
- if (Number.isFinite(depth) && depth-- <= 0) continue;
- filePaths = filePaths.concat(await findFiles(resolve(startPath, file.name), lookingFor, opts));
- continue;
- }
-
- if (file.isFile()) {
- const fileMatch = Array.isArray(lookingFor)
- ? lookingFor.some((s) => (startsWith ? file.name.startsWith(s) : file.name.endsWith(s)))
- : startsWith
- ? file.name.startsWith(lookingFor)
- : file.name.endsWith(lookingFor);
-
- if (fileMatch) {
- filePaths.push(resolve(startPath, file.name));
- }
- }
- }
-
- return filePaths;
-}
-
-export const getConfigFile = async (file: "app" | "vite" = "app") => {
- let configFile = `${file}.config.ts`;
-
- const existsHere = fileExists(configFile);
-
- if (!existsHere) {
- const root = await getProjectRoot();
- const existsInRoot = validateFilePath(root, `${file}.config`);
- if (existsInRoot) {
- const correctConfig = await cancelable(
- p.confirm({
- message: `Could not find ${file} config in current directory, but found ${file} config in \`${root}\`. Is this the correct ${file} config?`,
- }),
- );
- if (correctConfig) return existsInRoot;
- }
-
- p.log.error(color.red(`Can't find ${file}.config file`));
- await cancelable(
- p.text({
- message: `Type path to ${file} config: `,
- validate(value) {
- const path = validateFilePath(value, `${file}.config`);
- if (!path) return `${file} config not found. Please try again`;
- else {
- configFile = path;
- }
- },
- }),
- );
- }
-
- return configFile;
-};
-
-export async function manipulateJsonFile(name: string, manipulate: (obj: Record) => Record) {
- try {
- const jsonString = await readFile(name, "utf8");
- const jsonObj = JSON.parse(jsonString);
- await writeFile(
- name,
- JSON.stringify(manipulate(jsonObj), null, /^(\t|\s+)/m.exec(jsonString)?.[0] || 2) + "\n",
- "utf8",
- );
- } catch (error) {
- p.log.error(color.red(error ? error.toString() : `unknown error when manipulating ${name}`));
- }
-}
diff --git a/packages/commands/tests/assets/sample_app_config.txt b/packages/commands/tests/assets/sample_app_config.txt
deleted file mode 100644
index 50315ba..0000000
--- a/packages/commands/tests/assets/sample_app_config.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-import { defineConfig } from "@solidjs/start/config";
-// Simulates an app config
-export default defineConfig({
- vite: {
- plugins: [solid()]
- }
-});
diff --git a/packages/commands/tests/assets/sample_unocss_app_result.txt b/packages/commands/tests/assets/sample_unocss_app_result.txt
deleted file mode 100644
index 90217f1..0000000
--- a/packages/commands/tests/assets/sample_unocss_app_result.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-import UnoCss from "unocss/vite";
-import { defineConfig } from "@solidjs/start/config";
-// Simulates an app config
-export default defineConfig({
- vite: {
- plugins: [
- solid(),
- UnoCss({})
- ]
- }
-});
diff --git a/packages/commands/tests/assets/sample_unocss_vite_result.txt b/packages/commands/tests/assets/sample_unocss_vite_result.txt
deleted file mode 100644
index c5d2c91..0000000
--- a/packages/commands/tests/assets/sample_unocss_vite_result.txt
+++ /dev/null
@@ -1,9 +0,0 @@
-import UnoCss from "unocss/vite";
-import { defineConfig } from "vite";
-// Simulates an app config
-export default defineConfig({
- plugins: [
- solid(),
- UnoCss({})
- ]
-});
diff --git a/packages/commands/tests/assets/sample_vite_config.txt b/packages/commands/tests/assets/sample_vite_config.txt
deleted file mode 100644
index 0faac72..0000000
--- a/packages/commands/tests/assets/sample_vite_config.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-import { defineConfig } from "vite";
-// Simulates an app config
-export default defineConfig({
- plugins: [solid()]
-});
diff --git a/packages/commands/tests/config_manipulation.test.ts b/packages/commands/tests/config_manipulation.test.ts
deleted file mode 100644
index aec0f98..0000000
--- a/packages/commands/tests/config_manipulation.test.ts
+++ /dev/null
@@ -1,93 +0,0 @@
-import { describe, expect, it, vi } from "vitest";
-import { handleAdd } from "../src/handlers/add";
-import { readFile as readFile1 } from "fs";
-import { UPDATESQUEUE } from "../../utils/src/updates";
-
-const readFile = async (path: string): Promise => {
- return await new Promise((res) =>
- // Can't use readFile from fs/promises because we've mocked it
- readFile1(path, (_, data) => res(data.toString())),
- );
-};
-
-const removeWhitespace = (str: string) => str.replace(/\s/g, "");
-
-vi.mock("fs/promises", () => {
- return {
- readFile: async (name: string) => {
- if (name === "app.config.ts") {
- const sampleConfig: string = await readFile("./packages/commands/tests/assets/sample_app_config.txt");
- return sampleConfig;
- }
- if (name === "vite.config.ts") {
- const sampleConfig: string = await readFile("./packages/commands/tests/assets/sample_vite_config.txt");
- return sampleConfig;
- }
-
- return "{}";
- },
- writeFile: async (_, contents: string) => {
- return contents;
- },
- };
-});
-vi.mock("execa", () => {
- return { $: async () => ({ stdout: "" }) };
-});
-
-vi.mock("@clack/prompts", async () => {
- const actual: object = await vi.importActual("@clack/prompts");
- return {
- ...actual,
- confirm: async ({ message }: { message: string }) => true,
- };
-});
-
-vi.mock("@solid-cli/utils/updates", async () => {
- const actual: object = await vi.importActual("@solid-cli/utils/updates");
- return {
- ...actual,
- clearQueue: async () => {},
- };
-});
-
-vi.mock("../src/lib/utils/helpers.ts", async () => {
- return {
- getConfigFile: async (file: string): Promise => new Promise((r) => r(`${file}.config.ts`)),
- fileExists: (path: string) =>
- path.includes("vite_config") ||
- path.includes("app_config") ||
- path.includes("app.tsx") ||
- path.includes("index.tsx"),
- getRootFile: async (): Promise => new Promise((r) => r("./src/app.tsx")),
- };
-});
-
-let testingSolidStart = false;
-
-vi.mock("@solid-cli/utils", async () => {
- return {
- isSolidStart: async () => new Promise((r) => r(testingSolidStart)),
- };
-});
-
-describe("Update config", () => {
- it("Adds a plugin properly to the app config", { timeout: 50000 }, async () => {
- testingSolidStart = true;
- await handleAdd(["unocss"]);
-
- const expected = await readFile("./packages/commands/tests/assets/sample_unocss_app_result.txt");
- // @ts-ignore
- const newConfig = UPDATESQUEUE.find((u) => u.name === "app.config.ts")?.contents;
- expect(removeWhitespace(newConfig)).toBe(removeWhitespace(expected));
- });
- it("Adds a plugin properly to the vite config", { timeout: 50000 }, async () => {
- testingSolidStart = false;
- await handleAdd(["unocss"]);
-
- const expected = await readFile("./packages/commands/tests/assets/sample_unocss_vite_result.txt");
- // @ts-ignore
- const newConfig = UPDATESQUEUE.find((u) => u.name === "vite.config.ts")?.contents;
- expect(removeWhitespace(newConfig)).toBe(removeWhitespace(expected));
- });
-});
diff --git a/packages/commands/tests/package_installs.test.ts b/packages/commands/tests/package_installs.test.ts
deleted file mode 100644
index c0eff16..0000000
--- a/packages/commands/tests/package_installs.test.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { expect, describe, it } from "vitest";
-
-describe("Package Installs", () => {
- it("should install packages correctly", () => {
- expect(true).toBe(true);
- });
-});
diff --git a/packages/commands/tsconfig.json b/packages/commands/tsconfig.json
deleted file mode 100644
index ecaf1e3..0000000
--- a/packages/commands/tsconfig.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
- "module": "ESNext",
- "skipLibCheck": true,
- "declaration": true,
- "emitDeclarationOnly": true,
- "moduleResolution": "Bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- // "noUnusedLocals": true,
- // "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- "outDir": "types"
- },
- "include": ["src/*"]
-}
diff --git a/packages/commands/tsup.config.ts b/packages/commands/tsup.config.ts
deleted file mode 100644
index 0e6978c..0000000
--- a/packages/commands/tsup.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { defineConfig } from "tsup";
-import metaUrlPlugin from "@chialab/esbuild-plugin-meta-url";
-
-export default defineConfig({
- entry: ["src/index.ts", "src/handlers/new.ts"],
- target: "esnext",
- format: "esm",
- splitting: false,
- sourcemap: true,
- clean: true,
- minify: true,
- esbuildPlugins: [metaUrlPlugin()],
-});
diff --git a/packages/core/.gitignore b/packages/core/.gitignore
deleted file mode 100644
index bf96551..0000000
--- a/packages/core/.gitignore
+++ /dev/null
@@ -1,133 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-lerna-debug.log*
-.pnpm-debug.log*
-
-# Diagnostic reports (https://nodejs.org/api/report.html)
-report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
-
-# Runtime data
-pids
-*.pid
-*.seed
-*.pid.lock
-
-# Directory for instrumented libs generated by jscoverage/JSCover
-lib-cov
-
-# Coverage directory used by tools like istanbul
-coverage
-*.lcov
-
-# nyc test coverage
-.nyc_output
-
-# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
-.grunt
-
-# Bower dependency directory (https://bower.io/)
-bower_components
-
-# node-waf configuration
-.lock-wscript
-
-# Compiled binary addons (https://nodejs.org/api/addons.html)
-build/Release
-
-# Dependency directories
-node_modules/
-jspm_packages/
-
-# Snowpack dependency directory (https://snowpack.dev/)
-web_modules/
-
-# TypeScript cache
-*.tsbuildinfo
-
-# Optional npm cache directory
-.npm
-
-# Optional swc cache
-.swc
-
-# Optional eslint cache
-.eslintcache
-
-# Optional stylelint cache
-.stylelintcache
-
-# Microbundle cache
-.rpt2_cache/
-.rts2_cache_cjs/
-.rts2_cache_es/
-.rts2_cache_umd/
-
-# Optional REPL history
-.node_repl_history
-
-# Output of 'npm pack'
-*.tgz
-
-# Yarn Integrity file
-.yarn-integrity
-
-# dotenv environment variable files
-.env
-.env.development.local
-.env.test.local
-.env.production.local
-.env.local
-
-# parcel-bundler cache (https://parceljs.org/)
-.cache
-.parcel-cache
-
-# Next.js build output
-.next
-out
-
-# Nuxt.js build / generate output
-.nuxt
-dist
-
-# Gatsby files
-.cache/
-# Comment in the public line in if your project uses Gatsby and not Next.js
-# https://nextjs.org/blog/next-9-1#public-directory-support
-# public
-
-# vuepress build output
-.vuepress/dist
-
-# vuepress v2.x temp and cache directory
-.temp
-.cache
-
-# Docusaurus cache and generated files
-.docusaurus
-
-# Serverless directories
-.serverless/
-
-# FuseBox cache
-.fusebox/
-
-# DynamoDB Local files
-.dynamodb/
-
-# TernJS port file
-.tern-port
-
-# Stores VSCode versions used for testing VSCode extensions
-.vscode-test
-
-# yarn v2
-.yarn/cache
-.yarn/unplugged
-.yarn/build-state.yml
-.yarn/install-state.gz
-.pnp.*
diff --git a/packages/core/README.md b/packages/core/README.md
deleted file mode 100644
index c922b0e..0000000
--- a/packages/core/README.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# @solid-cli/core
-
-The main package for the SolidJS CLI tool.
-
-## Installation
-
-Run the following command to install the CLI tool globally:
-
-```bash
-npm i -g @solid-cli/core
-```
-
-## Usage
-
-For a full list of commands and how to use them, you can invoke the help command like so:
-
-```bash
-solid --help
-```
-
-Which should print this:
-
-```bash
-solid
-
-where can be one of:
-
-- add - Can add and install integrations: `solid add unocss`.
-- docs
-- new - Creates a new solid project
-- set
-- start - Commands specific to solid start
-- playground
-
-For more help, try running `solid --help`
-```
-
-## Documentation
-
-Visit our [official documentation](https://solid-cli.netlify.app/)
-
-## Support
-
-Reach out to us on the official [SolidJS discord](https://discord.gg/solidjs)
-
-## Contributing
-
-If you would like to contribute or keep up to date with the package, come join the effort over on [our GitHub](https://github.com/solidjs-community/solid-cli)
diff --git a/packages/core/package.json b/packages/core/package.json
deleted file mode 100644
index e961d0c..0000000
--- a/packages/core/package.json
+++ /dev/null
@@ -1,51 +0,0 @@
-{
- "name": "@solid-cli/core",
- "version": "0.0.26",
- "description": "A CLI for Solid",
- "author": "Thomas Beer & Rahul Batra",
- "license": "MIT",
- "homepage": "https://solid-cli.netlify.app",
- "repository": {
- "type": "git",
- "url": "https://github.com/solidjs-community/solid-cli"
- },
- "keywords": [
- "solidjs",
- "solid",
- "cli"
- ],
- "main": "dist/index.mjs",
- "bin": {
- "solid": "./dist/index.mjs"
- },
- "files": [
- "dist"
- ],
- "dependencies": {
- "@clack/core": "0.3.4",
- "@clack/prompts": "0.7.0",
- "@solid-cli/commands": "workspace:*",
- "@solid-cli/reactivity": "workspace:*",
- "@solid-cli/ui": "workspace:*",
- "@solid-cli/utils": "workspace:*",
- "cmd-ts": "^0.13.0",
- "execa": "^8.0.1",
- "picocolors": "^1.1.1",
- "smol-toml": "^1.3.0",
- "tiny-updater": "^3.5.2"
- },
- "scripts": {
- "start": "jiti ./src/index.ts",
- "build": "tsc && tsup"
- },
- "devDependencies": {
- "@chialab/esbuild-plugin-meta-url": "^0.18.2",
- "@types/node": "^22.9.0",
- "jiti": "^2.4.0",
- "tsup": "^8.3.5",
- "typescript": "^5.6.3"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/packages/core/src/commands/index.ts b/packages/core/src/commands/index.ts
deleted file mode 100644
index 8d4bcaf..0000000
--- a/packages/core/src/commands/index.ts
+++ /dev/null
@@ -1,114 +0,0 @@
-import { openInBrowser } from "@solid-cli/utils";
-import { startCommands } from "./start";
-import * as p from "@clack/prompts";
-import { boolean, command, flag, optional, positional, restPositionals, string } from "cmd-ts";
-import { oneOf } from "@solid-cli/utils";
-import { cancelable } from "@solid-cli/ui";
-import { PossibleFields, setField, t } from "@solid-cli/utils";
-import { spinnerify } from "@solid-cli/ui";
-import { handleNew, handleAdd } from "@solid-cli/commands";
-
-const add = command({
- name: "add",
- description: t.ADD_DESC,
- args: {
- packages: restPositionals({
- type: string,
- displayName: "Package Name",
- }),
- forceTransform: flag({ type: boolean, long: "force", short: "f" }),
- },
- handler: async ({ packages, forceTransform }) => {
- await handleAdd(packages, forceTransform);
- },
-});
-
-const new_ = command({
- name: "new",
- description: t.NEW_DESC,
- args: {
- variation: positional({
- type: optional(oneOf(["bare", "ts", "js"] as const)),
- displayName: t.NEW_VARIATION_DESC,
- description: "",
- }),
- name: positional({
- type: optional(string),
- displayName: t.PROJECT_NAME,
- description: t.NEW_NAME_DESC,
- }),
- stackblitz: flag({ type: boolean, long: "stackblitz", short: "s" }),
- },
- async handler({ variation, name, stackblitz }) {
- if (!name && variation) {
- const _name = await cancelable(
- p.text({
- message: t.PROJECT_NAME,
- placeholder: `solid-${variation}`,
- defaultValue: `solid-${variation}`,
- }),
- );
- name = _name;
- }
- await handleNew(variation, name, stackblitz);
- },
-});
-
-const docs = command({
- name: "docs",
- args: {
- keyword: positional({ type: optional(string), displayName: "Keyword" }),
- open: flag({ type: boolean, long: "open", short: "o" }),
- },
- async handler({ keyword, open }) {
- if (!keyword) {
- if (open) {
- await spinnerify({
- startText: "Opening",
- finishText: "Opened",
- fn: () => openInBrowser("https://docs.solidjs.com"),
- });
- return;
- }
- p.log.message("The solid documentation is available at https://docs.solidjs.com");
- return;
- }
- await spinnerify({
- startText: "Opening",
- finishText: "Opened",
- fn: () =>
- openInBrowser(
- `https://www.google.com/search?q=${keyword}+site:docs.solidjs.com+OR+site:start.solidjs.com+OR+site:solidjs.com`,
- ),
- });
- },
-});
-
-const set = command({
- name: "set",
- args: { field: positional({ type: oneOf(PossibleFields) }), value: positional({ type: string }) },
- async handler({ field, value }) {
- await setField(field, value);
- },
-});
-
-const playground = command({
- name: "playground",
- args: {},
- async handler() {
- await spinnerify({
- startText: "Opening",
- finishText: "Opened",
- fn: () => openInBrowser("https://playground.solidjs.com"),
- });
- },
-});
-
-export default {
- add,
- docs,
- new: new_,
- set,
- start: startCommands,
- playground,
-};
diff --git a/packages/core/src/commands/start.ts b/packages/core/src/commands/start.ts
deleted file mode 100644
index 8f2640c..0000000
--- a/packages/core/src/commands/start.ts
+++ /dev/null
@@ -1,97 +0,0 @@
-import { command, flag, optional, positional, string, subcommands } from "cmd-ts";
-import { oneOf } from "@solid-cli/utils";
-import { t } from "@solid-cli/utils";
-import {
- handleAdapter,
- handleApi,
- handleData,
- handleMode,
- handleRoute,
- supportedAdapters,
- supportedModes,
-} from "@solid-cli/commands";
-
-const mode = command({
- name: "mode",
- args: {
- mode: positional({
- type: optional(oneOf(supportedModes)),
- displayName: "Mode",
- description: t.START_MODE_DESC,
- }),
- },
- async handler({ mode }) {
- await handleMode(mode);
- },
-});
-
-const route = command({
- name: "route",
- args: {
- path: positional({ type: optional(string), displayName: "Route Path" }),
- name: positional({
- type: optional(string),
- displayName: "Route name",
- description: t.START_ROUTE_DESC,
- }),
- },
- async handler({ path, name }) {
- await handleRoute(path, name);
- },
-});
-
-const data = command({
- name: "data",
- args: {
- path: positional({ type: optional(string), displayName: "Data Path" }),
- name: positional({
- type: optional(string),
- displayName: "Data name",
- description: t.START_DATA_DESC,
- }),
- },
- async handler({ path, name }) {
- await handleData(path, name);
- },
-});
-
-const adapter = command({
- name: "adapter",
- args: {
- name: positional({
- type: optional(oneOf(supportedAdapters)),
- displayName: t.START_ADAPTER_DISPLAYNAME,
- }),
- forceTransform: flag({ short: "f", long: "force" }),
- },
- async handler({ name, forceTransform }) {
- await handleAdapter(name, forceTransform);
- },
-});
-
-const api = command({
- name: "api",
- args: {
- path: positional({ type: optional(string), displayName: "Api Path" }),
- name: positional({
- type: optional(string),
- displayName: t.START_API_DISPLAYNAME,
- description: t.START_API_HINT,
- }),
- },
- async handler({ path, name }) {
- await handleApi(path, name);
- },
-});
-
-export const startCommands = subcommands({
- name: "start",
- description: "Commands specific to solid start",
- cmds: {
- mode,
- route,
- data,
- adapter,
- api,
- },
-});
diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts
deleted file mode 100644
index c358bb3..0000000
--- a/packages/core/src/index.ts
+++ /dev/null
@@ -1,117 +0,0 @@
-#! /usr/bin/env node
-import { run, subcommands } from "cmd-ts";
-import * as p from "@clack/prompts";
-import color from "picocolors";
-import { t, setLocale, getField } from "@solid-cli/utils";
-import { name, version } from "../package.json";
-import { readConfig } from "@solid-cli/utils";
-import loadCommands from "./plugins/plugins_entry";
-import updater from "tiny-updater";
-import { createAsync } from "@solid-cli/reactivity";
-import {
- handleAdapter,
- handleAdd,
- handleApi,
- handleData,
- handleMode,
- handleNew,
- handleRoute,
-} from "@solid-cli/commands";
-
-const possibleActions = () =>
- [
- { value: "add", label: t.ACTION_ADD, hint: "solid add ..." },
- { value: "new", label: t.ACTION_NEW, hint: "solid new ..." },
- { value: "start", label: t.ACTION_START, hint: "solid start ..." },
- ] as const;
-
-export const provideStartSuggestions = async () => {
- let startAction = await p.select({
- message: t.SELECT_START_ACTION,
- options: [
- { value: "mode", label: t.START_MODE, hint: t.START_MODE_HINT },
- { value: "route", label: t.START_ROUTE, hint: t.START_ROUTE_HINT },
- { value: "data", label: t.START_DATA, hint: t.START_DATA_HINT },
- {
- value: "adapter",
- label: t.START_ADAPTER,
- hint: t.START_ADAPTER_HINT,
- },
- {
- value: "api",
- label: t.START_API,
- hint: t.START_API_HINT,
- },
- ],
- });
- switch (startAction) {
- case "mode":
- await handleMode();
- break;
- case "route":
- await handleRoute();
- break;
- case "data":
- await handleData();
- break;
- case "adapter":
- await handleAdapter();
- break;
- case "api":
- await handleApi();
- break;
- }
-};
-
-const provideSuggestions = async () => {
- type ActionType = ReturnType[number]["value"];
- let action = (await p.select({
- message: t.SELECT_ACTION,
- // This thing really doesn't like `as const` things
- options: possibleActions() as any,
- })) as ActionType;
- if (!action) return;
- switch (action) {
- case "add":
- await handleAdd();
- break;
- case "new":
- await handleNew();
- break;
- case "start":
- await provideStartSuggestions();
- break;
- }
-};
-
-const main = async () => {
- p.intro(`\n${color.bgCyan(color.black(" Solid-CLI "))}`);
- await readConfig();
- const needsUpdate = createAsync(async () => await updater({ name, version, ttl: 86_400_000 }));
- setLocale(getField("lang"));
- const cli = subcommands({
- name: "solid",
- cmds: await loadCommands(),
- version,
- });
- const args = process.argv.slice(2);
- try {
-
- if (args.length === 0) {
- await provideSuggestions();
- return;
- }
-
- if (args.length === 1 && args[0] === "start") {
- await provideStartSuggestions();
- return;
- }
-
- await run(cli, args);
- }
- catch (e) {
- console.error(e);
- process.exit(1);
- }
-};
-main();
diff --git a/packages/core/src/plugins/plugins_entry.ts b/packages/core/src/plugins/plugins_entry.ts
deleted file mode 100644
index f1aec75..0000000
--- a/packages/core/src/plugins/plugins_entry.ts
+++ /dev/null
@@ -1,28 +0,0 @@
-import { join } from "path";
-import { config } from "@solid-cli/utils";
-import defaultCommands from "../commands";
-
-const resolveImport = async (packagePath: string) => {
- const packageJson = await import(join(packagePath, "package.json"));
- return await import(join(packagePath, packageJson.module));
-};
-const loadUserCommands = async () => {
- const pluginPaths = config()["plugins"] as string[];
- if (!pluginPaths) return null;
- const imports = await Promise.all(pluginPaths.map((p) => resolveImport(p)));
- const importedCommands = imports.map((i) => i.default);
- let commands = {} as any;
- importedCommands.forEach((c) => {
- const name = c.name;
- commands[name] = c;
- });
- return commands;
-};
-const loadCommands = async () => {
- const cmds = {
- ...defaultCommands,
- ...(await loadUserCommands()),
- };
- return cmds;
-};
-export default loadCommands;
diff --git a/packages/core/tsup.config.ts b/packages/core/tsup.config.ts
deleted file mode 100644
index 75f3240..0000000
--- a/packages/core/tsup.config.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { defineConfig } from "tsup";
-import metaUrlPlugin from "@chialab/esbuild-plugin-meta-url";
-
-export default defineConfig({
- entry: ["src/index.ts"],
- target: "esnext",
- format: "esm",
- splitting: false,
- sourcemap: true,
- clean: true,
- minify: true,
- esbuildPlugins: [metaUrlPlugin()],
-});
diff --git a/packages/create-solid/CHANGELOG.md b/packages/create-solid/CHANGELOG.md
new file mode 100644
index 0000000..cc52156
--- /dev/null
+++ b/packages/create-solid/CHANGELOG.md
@@ -0,0 +1,115 @@
+# create-solid
+
+## 0.10.0
+
+### Minor Changes
+
+- Always scaffold from the latest templates
+
+ - Template downloads are no longer pinned to a baked-in solidjs/templates commit. Scaffolds come from live HEAD of the default branch, matching the `templates.json` manifest, so upstream template changes and dependency repins reach users without a CLI release.
+ - Removed the `SOLID_CLI_TEMPLATES_REF` environment override that shipped in 0.9.0, along with the pin it existed to escape.
+ - HEAD is resolved to a commit sha before downloading so the tarball can be cached under it and reused by later scaffolds. That lookup goes through api.github.com, which is rate limited to 60 requests/hour for unauthenticated users, so any failure — rate limited, offline, slow — falls back to fetching HEAD from the archive endpoint directly, uncached.
+ - Solid 2.0 is labelled "Solid 2.0 (RC)" in the project picker now that Solid 2.0 core is a release candidate. It stays listed first but not preselected.
+
+## 0.9.0
+
+### Minor Changes
+
+- 68caa9f: Solid 2.0 template support
+
+ - New "Solid 2.0" top-level project type scaffolding the `solid-v2/*` templates from solidjs/templates (basic, bare, fullstack, fullstack-tanstack, with-\*). Listed first but not preselected while Solid 2.0 core is in beta; existing flags (`-s`, `-v`, `-l`, `--v2`) keep their meaning, plus new `--solid` and `--ssr` flags.
+ - Optional streaming SSR on templates that support it (currently `basic`): a scaffold-time flip that sets `ssr: true` in `vite.config.ts`, adds the generic production `server.js`, and points the `start` script at it. Defaults to No.
+ - JavaScript variants of the Solid 2.0 templates via the existing sucrase TS→JS conversion (no `index.html` rewrite; `.ts`/`.tsx` references inside `vite.config` are retargeted, `.d.ts` files dropped, minimal `jsconfig.json`).
+ - Template lists, subdir paths and per-template flags are now read from a `templates.json` manifest at the templates repo HEAD (2s timeout), with silent fallback to the baked-in lists — so new templates and future repo reorganizations no longer require a CLI release.
+
+## 0.8.1
+
+### Patch Changes
+
+- make start v2 stable
+
+## 0.8.0
+
+### Minor Changes
+
+- support fetching without the github API (so fetching should no work when hitting the github api limit)
+
+## 0.6.14
+
+### Patch Changes
+
+- update dependencies and add to solid start v2 templates list
+
+## 0.6.13
+
+### Patch Changes
+
+- Keep showing `pnpm install` & `pnpm dev` commands when initialising a project in the current working directory
+
+## 0.6.12
+
+### Patch Changes
+
+- Update dependencies, add new template, and remove `cd` command if project is created in working directory
+
+## 0.6.11
+
+### Patch Changes
+
+- Rename `with-pages-router-file-based` to `with-vite-plugin-pages`
+
+## 0.6.10
+
+### Patch Changes
+
+- Fetch Vanilla templates from /vanilla subdirectory of solidjs/templates, rather than from repo root
+
+## 0.6.9
+
+### Patch Changes
+
+- Fetch Start templates from solidjs/templates, rather than the Start repo
+
+## 0.6.8
+
+### Patch Changes
+
+- Correctly perform TS->JS conversion by disabling ES transforms and preserving dynamic imports
+
+## 0.6.7
+
+### Patch Changes
+
+- Add `with-strict-csp` template to Start
+
+## 0.6.6
+
+### Patch Changes
+
+- Add CLI flags for creating `vanilla` and `library` projects
+
+## 0.6.5
+
+### Patch Changes
+
+- Don't add "Created with Solid CLI" text to README if it's already there
+
+## 0.6.4
+
+### Patch Changes
+
+- Update link in text added to project READMEs
+
+## 0.6.3
+
+### Patch Changes
+
+- Add more command line arguments
+
+## 0.6.1
+
+### Patch Changes
+
+- Fix regression from 0.5.x (.gitignore wasn't being written to new projects)
+
+## 0.6.0
diff --git a/packages/create-solid/package.json b/packages/create-solid/package.json
index ba9ac57..bb67865 100644
--- a/packages/create-solid/package.json
+++ b/packages/create-solid/package.json
@@ -1,6 +1,6 @@
{
"name": "create-solid",
- "version": "0.5.13",
+ "version": "0.10.0",
"description": "Create Solid apps with low configuration",
"author": "Thomas Beer",
"contributors": [
@@ -17,26 +17,24 @@
"solid",
"cli"
],
- "main": "dist/index.mjs",
+ "main": "./dist/index.mjs",
+ "module": "./dist/index.mjs",
"bin": {
- "create-solid": "./dist/index.mjs"
+ "create-solid": "./dist/bin.mjs"
},
"files": [
"dist"
],
"scripts": {
- "start": "jiti ./src/index.ts",
- "build": "tsc && tsup"
+ "start": "jiti ./src/bin.ts",
+ "build": "tsc && tsup",
+ "test": "vitest run"
},
"devDependencies": {
- "@clack/prompts": "0.7.0",
- "@solid-cli/commands": "workspace:*",
- "@types/node": "^22.9.0",
- "cmd-ts": "^0.13.0",
- "jiti": "^2.4.0",
+ "@clack/prompts": "1.7.0",
"picocolors": "^1.1.1",
- "tsup": "^8.3.5",
- "typescript": "^5.6.3"
+ "citty": "^0.2.2",
+ "@solid-cli/create": "workspace:*"
},
"publishConfig": {
"access": "public"
diff --git a/packages/create-solid/src/bin.ts b/packages/create-solid/src/bin.ts
new file mode 100644
index 0000000..5b848bd
--- /dev/null
+++ b/packages/create-solid/src/bin.ts
@@ -0,0 +1,11 @@
+#! /usr/bin/env node
+
+import { runMain } from "citty";
+import { createSolid } from "@solid-cli/create";
+import { intro } from "@clack/prompts";
+import color from "picocolors";
+import packageJson from "../package.json" with { type: "json" };
+
+intro(`\n${color.bgCyan(color.black(` Create-Solid v${packageJson.version}`))}`);
+
+runMain(createSolid(packageJson.version));
diff --git a/packages/create-solid/src/index.ts b/packages/create-solid/src/index.ts
deleted file mode 100644
index c094406..0000000
--- a/packages/create-solid/src/index.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-#! /usr/bin/env node
-import { AllSupported, handleNew, isSupported } from "@solid-cli/commands/new";
-import color from "picocolors";
-import { intro } from "@clack/prompts";
-import packageJson from "../package.json" with { type: "json" };
-import { command, run, option, string, boolean, flag, optional, positional } from "cmd-ts";
-
-intro(`\n${color.bgCyan(color.black(` Create-Solid v${packageJson.version}`))}`);
-
-const app = command({
- name: "create-solid",
- description: "Create a new Solid project",
- args: {
- projectNamePositional: positional({
- type: optional(string),
- displayName: "Project Name",
- description: "The name of the project to be generated",
- }),
- templatePositional: positional({
- type: optional(string),
- displayName: "Template name",
- description: "Name of template to be initialised",
- }),
- projectNameOption: option({
- type: optional(string),
- long: "project-name",
- short: "p",
- description: "Name of your project",
- }),
- solidStart: flag({
- type: optional(boolean),
- long: "solid-start",
- short: "s",
- description: "Create a SolidStart project",
- }),
- },
- handler: async ({ projectNameOption, solidStart, projectNamePositional, templatePositional }) => {
- if (templatePositional && !isSupported(templatePositional)) {
- console.error(`Template "${templatePositional}" is not supported`);
- process.exit(0);
- }
- try {
- await handleNew(
- templatePositional as AllSupported,
- projectNamePositional ?? projectNameOption,
- false,
- solidStart,
- );
- } catch (e) {
- console.error(e);
- process.exit(1);
- }
- },
-});
-run(app, process.argv.slice(2));
diff --git a/packages/create-solid/tsconfig.json b/packages/create-solid/tsconfig.json
index 55a0135..1115998 100644
--- a/packages/create-solid/tsconfig.json
+++ b/packages/create-solid/tsconfig.json
@@ -1,7 +1,5 @@
{
"compilerOptions": {
- "baseUrl": ".",
- "noEmit": true,
"module": "ESNext",
"target": "ESNext",
"moduleResolution": "Bundler",
@@ -9,7 +7,8 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
- "resolveJsonModule": true
+ "resolveJsonModule": true,
+ "noEmit": true
},
"include": ["src/*"]
}
diff --git a/packages/create-solid/tsup.config.ts b/packages/create-solid/tsup.config.ts
index e0ff30c..ed15cdf 100644
--- a/packages/create-solid/tsup.config.ts
+++ b/packages/create-solid/tsup.config.ts
@@ -1,14 +1,13 @@
import { defineConfig } from "tsup";
export default defineConfig({
- entry: ["src/index.ts"],
+ entry: ["src/bin.ts"],
target: "esnext",
format: "esm",
- splitting: false,
+ splitting: true,
bundle: true,
sourcemap: false,
clean: true,
- noExternal: ["@solid-cli/commands"],
treeshake: true,
minify: true,
banner: {
diff --git a/packages/create/CHANGELOG.md b/packages/create/CHANGELOG.md
new file mode 100644
index 0000000..80a8250
--- /dev/null
+++ b/packages/create/CHANGELOG.md
@@ -0,0 +1,128 @@
+# @solid-cli/create
+
+## 0.10.0
+
+### Minor Changes
+
+- Always scaffold from the latest templates
+
+ - Template downloads are no longer pinned to a baked-in solidjs/templates commit. Scaffolds come from live HEAD of the default branch, matching the `templates.json` manifest, so upstream template changes and dependency repins reach users without a CLI release.
+ - Removed the `SOLID_CLI_TEMPLATES_REF` environment override that shipped in 0.9.0, along with the pin it existed to escape.
+ - HEAD is resolved to a commit sha before downloading so the tarball can be cached under it and reused by later scaffolds. That lookup goes through api.github.com, which is rate limited to 60 requests/hour for unauthenticated users, so any failure — rate limited, offline, slow — falls back to fetching HEAD from the archive endpoint directly, uncached.
+ - Solid 2.0 is labelled "Solid 2.0 (RC)" in the project picker now that Solid 2.0 core is a release candidate. It stays listed first but not preselected.
+
+## 0.9.0
+
+### Minor Changes
+
+- 68caa9f: Solid 2.0 template support
+
+ - New "Solid 2.0" top-level project type scaffolding the `solid-v2/*` templates from solidjs/templates (basic, bare, fullstack, fullstack-tanstack, with-\*). Listed first but not preselected while Solid 2.0 core is in beta; existing flags (`-s`, `-v`, `-l`, `--v2`) keep their meaning, plus new `--solid` and `--ssr` flags.
+ - Optional streaming SSR on templates that support it (currently `basic`): a scaffold-time flip that sets `ssr: true` in `vite.config.ts`, adds the generic production `server.js`, and points the `start` script at it. Defaults to No.
+ - JavaScript variants of the Solid 2.0 templates via the existing sucrase TS→JS conversion (no `index.html` rewrite; `.ts`/`.tsx` references inside `vite.config` are retargeted, `.d.ts` files dropped, minimal `jsconfig.json`).
+ - Template lists, subdir paths and per-template flags are now read from a `templates.json` manifest at the templates repo HEAD (2s timeout), with silent fallback to the baked-in lists — so new templates and future repo reorganizations no longer require a CLI release.
+
+## 0.8.1
+
+### Patch Changes
+
+- 5621942: SolidStart v2 is now Stable
+
+## 0.8.0
+
+### Minor Changes
+
+- support fetching without the github API (so fetching should no work when hitting the github api limit)
+
+### Patch Changes
+
+- Updated dependencies
+ - @solid-cli/utils@0.7.0
+
+## 0.6.14
+
+### Patch Changes
+
+- update dependencies and add to solid start v2 templates list
+- Updated dependencies
+ - @solid-cli/utils@0.6.3
+
+## 0.6.13
+
+### Patch Changes
+
+- Keep showing `pnpm install` & `pnpm dev` commands when initialising a project in the current working directory
+
+## 0.6.12
+
+### Patch Changes
+
+- Update dependencies, add new template, and remove `cd` command if project is created in working directory
+- Updated dependencies
+ - @solid-cli/utils@0.6.2
+
+## 0.6.11
+
+### Patch Changes
+
+- Rename `with-pages-router-file-based` to `with-vite-plugin-pages`
+
+## 0.6.10
+
+### Patch Changes
+
+- Fetch Vanilla templates from /vanilla subdirectory of solidjs/templates, rather than from repo root
+
+## 0.6.9
+
+### Patch Changes
+
+- Fetch Start templates from solidjs/templates, rather than the Start repo
+
+## 0.6.8
+
+### Patch Changes
+
+- Correctly perform TS->JS conversion by disabling ES transforms and preserving dynamic imports
+
+## 0.6.7
+
+### Patch Changes
+
+- Add `with-strict-csp` template to Start
+
+## 0.6.6
+
+### Patch Changes
+
+- Add CLI flags for creating `vanilla` and `library` projects
+
+## 0.6.5
+
+### Patch Changes
+
+- Don't add "Created with Solid CLI" text to README if it's already there
+
+## 0.6.4
+
+### Patch Changes
+
+- Update link in text added to project READMEs
+
+## 0.6.3
+
+### Patch Changes
+
+- Add more command line arguments
+
+## 0.6.1
+
+### Patch Changes
+
+- Fix regression from 0.5.x (.gitignore wasn't being written to new projects)
+
+## 0.6.0
+
+### Patch Changes
+
+- @solid-cli/utils@0.6.0
diff --git a/packages/create/README.md b/packages/create/README.md
new file mode 100644
index 0000000..74c4b75
--- /dev/null
+++ b/packages/create/README.md
@@ -0,0 +1,26 @@
+# @solid-cli/create
+
+A library for easily initialising Solid projects
+
+## Usage
+
+### Initialising a Vanilla project
+
+```ts
+import { createVanilla } from "@solid-cli/create";
+createVanilla({ template: "ts", destination: "./ts" });
+```
+
+### Initialising a Start project
+
+```ts
+import { createStart } from "@solid-cli/create";
+createStart({ template: "basic", destination: "./basic" });
+```
+
+### Initialising a Library project
+
+```ts
+import { createLibrary } from "@solid-cli/create";
+createLibrary({ destination: "./library-project" });
+```
diff --git a/packages/ui/package.json b/packages/create/package.json
similarity index 51%
rename from packages/ui/package.json
rename to packages/create/package.json
index 39b8a9a..e745e00 100644
--- a/packages/ui/package.json
+++ b/packages/create/package.json
@@ -1,44 +1,50 @@
{
- "name": "@solid-cli/ui",
- "version": "0.0.13",
+ "name": "@solid-cli/create",
+ "version": "0.10.0",
+ "description": "Create Solid apps with low configuration",
+ "author": "Thomas Beer",
+ "contributors": [
+ "Rahul Batra"
+ ],
"license": "MIT",
"homepage": "https://solid-cli.netlify.app",
"repository": {
"type": "git",
"url": "https://github.com/solidjs-community/solid-cli"
},
- "files": [
- "dist",
- "types"
+ "keywords": [
+ "solidjs",
+ "solid",
+ "cli"
],
- "description": "A collection of UI utilities for the Solid CLI",
"main": "./dist/index.mjs",
"module": "./dist/index.mjs",
"types": "./types/index.d.ts",
"exports": {
".": {
+ "types": "./types/index.d.ts",
"import": "./dist/index.mjs",
- "require": "./dist/index.mjs",
- "types": "./types/index.d.ts"
+ "require": "./dist/index.mjs"
}
},
+ "files": [
+ "dist",
+ "types"
+ ],
"scripts": {
- "test": "vitest run",
- "build": "tsc && tsup"
- },
- "devDependencies": {
- "tsup": "^8.3.5",
- "typescript": "^5.6.3",
- "@types/node": "22.9.0"
+ "start": "jiti ./src/bin.ts",
+ "build": "tsc && tsup",
+ "test": "vitest run"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
- "@clack/core": "0.3.4",
- "@clack/prompts": "0.7.0",
+ "@clack/prompts": "1.7.0",
"picocolors": "^1.1.1",
- "@solid-cli/reactivity": "workspace:*",
+ "@begit/core": "^0.4.0",
+ "citty": "^0.2.2",
+ "sucrase": "^3.35.1",
"@solid-cli/utils": "workspace:*"
}
}
diff --git a/packages/create/src/create-library.ts b/packages/create/src/create-library.ts
new file mode 100644
index 0000000..0366d98
--- /dev/null
+++ b/packages/create/src/create-library.ts
@@ -0,0 +1,14 @@
+import { downloadRepo, GithubFetcher } from "@begit/core";
+
+export type CreateLibraryArgs = {
+ destination: string;
+};
+export const createLibrary = ({ destination }: CreateLibraryArgs) => {
+ return downloadRepo(
+ {
+ repo: { owner: "solidjs-community", name: "solid-lib-starter" },
+ dest: destination,
+ },
+ GithubFetcher,
+ );
+};
diff --git a/packages/create/src/create-solid-v2.ts b/packages/create/src/create-solid-v2.ts
new file mode 100644
index 0000000..cfac554
--- /dev/null
+++ b/packages/create/src/create-solid-v2.ts
@@ -0,0 +1,63 @@
+import { join } from "node:path";
+import { existsSync, writeFileSync } from "node:fs";
+import { readFile, writeFile } from "node:fs/promises";
+import { handleTSConversion } from "./utils/ts-conversion";
+import { GIT_IGNORE, JS_CONFIG_SOLID_V2, SolidV2Template } from "./utils/constants";
+import { downloadTemplate } from "./utils/download";
+import { applySsrFlip } from "./utils/ssr-flip";
+
+export type CreateSolidV2Args = {
+ template: SolidV2Template | (string & {});
+ destination: string;
+ /** Subdir prefix inside the templates repo (from templates.json), defaults to "solid-v2" */
+ path?: string;
+};
+
+export const createSolidV2 = (args: CreateSolidV2Args, transpile?: boolean, ssr?: boolean) => {
+ if (transpile) {
+ return createSolidV2JS(args, ssr);
+ }
+ return createSolidV2TS(args, ssr);
+};
+
+export const createSolidV2TS = async ({ template, destination, path = "solid-v2" }: CreateSolidV2Args, ssr?: boolean) => {
+ await downloadTemplate(`${path}/${template}`, destination);
+ if (ssr) await applySsrFlip(destination);
+};
+
+/**
+ * Retarget `.ts`/`.tsx` filename mentions in converted text (vite config,
+ * README) to the transpiled `.js`/`.jsx` output. `.d.ts` files are deleted
+ * (not transpiled) by the conversion, so their mentions are left alone.
+ */
+export const retargetTSFilenames = (text: string) =>
+ text
+ .replace(/\.tsx\b/g, ".jsx")
+ .replace(/(? {
+ const deduped = [...new Set(entries.split(",").map((entry) => entry.trim()).filter(Boolean))];
+ return `extensions: [${deduped.join(", ")}]`;
+ });
+
+export const createSolidV2JS = async (args: CreateSolidV2Args, ssr?: boolean) => {
+ // Create typescript project in `/.project`
+ // then transpile this to javascript and clean up.
+ // The SSR flip runs inside the temp dir, before conversion, so the config
+ // edit happens on the `.ts` source (server.js is already plain JS).
+ const tempDir = join(args.destination, ".project");
+ await createSolidV2TS({ ...args, destination: tempDir }, ssr);
+ await handleTSConversion(tempDir, args.destination, JS_CONFIG_SOLID_V2);
+ // Solid 2.0 templates have no `index.html` (turnkey entries), but their vite
+ // config and README reference `.ts`/`.tsx` files (setup files, comments,
+ // route examples) — retarget those to the transpiled `.js`/`.jsx` output
+ for (const file of ["vite.config.js", "README.md"]) {
+ const filePath = join(args.destination, file);
+ if (existsSync(filePath)) {
+ await writeFile(filePath, retargetTSFilenames((await readFile(filePath)).toString()));
+ }
+ }
+ // Add .gitignore
+ writeFileSync(join(args.destination, ".gitignore"), GIT_IGNORE);
+};
diff --git a/packages/create/src/create-start.ts b/packages/create/src/create-start.ts
new file mode 100644
index 0000000..0b4bc29
--- /dev/null
+++ b/packages/create/src/create-start.ts
@@ -0,0 +1,33 @@
+import { join } from "path";
+import { writeFileSync } from "fs";
+import { handleTSConversion } from "./utils/ts-conversion";
+import { GIT_IGNORE, StartTemplate, StartTemplateV2 } from "./utils/constants";
+import { downloadTemplate } from "./utils/download";
+export type CreateStartArgs = {
+ template: StartTemplate | StartTemplateV2 | (string & {});
+ destination: string;
+ /** Subdir prefix inside the templates repo (from templates.json), defaults to "solid-start-v2"/"solid-start-v1" */
+ path?: string;
+};
+
+export const createStartTS = ({ template, destination, path }: CreateStartArgs, v2?: boolean) => {
+ const prefix = path ?? (v2 ? "solid-start-v2" : "solid-start-v1");
+ return downloadTemplate(`${prefix}/${template}`, destination);
+};
+
+export const createStartJS = async ({ template, destination, path }: CreateStartArgs, v2?: boolean) => {
+ // Create typescript project in `/.project`
+ // then transpile this to javascript and clean up
+ const tempDir = join(destination, ".project");
+ await createStartTS({ template, destination: tempDir, path }, v2);
+ await handleTSConversion(tempDir, destination);
+ // Add .gitignore
+ writeFileSync(join(destination, ".gitignore"), GIT_IGNORE);
+};
+
+export const createStart = (args: CreateStartArgs, transpile?: boolean, v2?: boolean) => {
+ if (transpile) {
+ return createStartJS(args, v2);
+ }
+ return createStartTS(args, v2);
+};
diff --git a/packages/create/src/create-vanilla.ts b/packages/create/src/create-vanilla.ts
new file mode 100644
index 0000000..a27d564
--- /dev/null
+++ b/packages/create/src/create-vanilla.ts
@@ -0,0 +1,36 @@
+import { join } from "node:path";
+import { writeFileSync } from "node:fs";
+import { readFile } from "node:fs/promises";
+import { handleTSConversion } from "./utils/ts-conversion";
+import { GIT_IGNORE, VanillaTemplate } from "./utils/constants";
+import { downloadTemplate } from "./utils/download";
+
+export type CreateVanillaArgs = {
+ template: VanillaTemplate | (string & {});
+ destination: string;
+ /** Subdir prefix inside the templates repo (from templates.json), defaults to "vanilla" */
+ path?: string;
+};
+export const createVanilla = (args: CreateVanillaArgs, transpile?: boolean) => {
+ if (transpile) {
+ return createVanillaJS(args);
+ }
+ return createVanillaTS(args);
+};
+
+export const createVanillaTS = async ({ template, destination, path = "vanilla" }: CreateVanillaArgs) => {
+ return await downloadTemplate(`${path}/${template}`, destination);
+};
+
+export const createVanillaJS = async ({ template, destination, path }: CreateVanillaArgs) => {
+ // Create typescript project in `/.project`
+ // then transpile this to javascript and clean up
+ const tempDir = join(destination, ".project");
+ await createVanillaTS({ template, destination: tempDir, path });
+ await handleTSConversion(tempDir, destination);
+ // Replace `index.tsx` with `index.jsx` in `index.html`
+ const indexPath = join(destination, "index.html");
+ writeFileSync(indexPath, (await readFile(indexPath)).toString().replace("index.tsx", "index.jsx"));
+ // Add .gitignore
+ writeFileSync(join(destination, ".gitignore"), GIT_IGNORE);
+};
diff --git a/packages/create/src/create.ts b/packages/create/src/create.ts
new file mode 100644
index 0000000..1fe7984
--- /dev/null
+++ b/packages/create/src/create.ts
@@ -0,0 +1,12 @@
+import { createStart, CreateStartArgs } from "./create-start";
+import { createVanilla, CreateVanillaArgs } from "./create-vanilla";
+
+export async function create(args: CreateVanillaArgs, js: boolean, isStart: false): Promise;
+export async function create(args: CreateStartArgs, js: boolean, isStart: true): Promise;
+export async function create(args: CreateVanillaArgs | CreateStartArgs, js: boolean, isStart: boolean) {
+ if (isStart) {
+ return createStart(args as CreateStartArgs, js);
+ } else {
+ return createVanilla(args as CreateVanillaArgs, js);
+ }
+}
diff --git a/packages/create/src/index.ts b/packages/create/src/index.ts
new file mode 100644
index 0000000..dadf851
--- /dev/null
+++ b/packages/create/src/index.ts
@@ -0,0 +1,259 @@
+import { defineCommand } from "citty";
+import { createVanilla } from "./create-vanilla";
+import * as p from "@clack/prompts";
+import { cancelable, spinnerify } from "@solid-cli/utils/ui";
+import { createStart } from "./create-start";
+import { createSolidV2 } from "./create-solid-v2";
+import { GIT_IGNORE, isValidTemplate, LIBRARY_TEMPLATES, PROJECT_TYPES, ProjectType } from "./utils/constants";
+import { fetchTemplatesManifest, groupKeyFor, ManifestTemplate, resolveGroup } from "./utils/manifest";
+import { fuzzyScore, rankedOptionsFn } from "./utils/fuzzy";
+import { detectPackageManager } from "@solid-cli/utils/package-manager";
+import { existsSync, writeFileSync } from "node:fs";
+import { join } from "node:path";
+import { createLibrary } from "./create-library";
+import { readFile, writeFile } from "node:fs/promises";
+export { createVanilla, createStart, createLibrary, createSolidV2 };
+
+const PROJECT_TYPE_LABELS: Record = {
+ solid: "Solid 2.0 (RC)",
+ start: "SolidStart (Solid 1.x)",
+ vanilla: "SolidJS + Vite (Solid 1.x)",
+ library: "Library",
+};
+
+export const createSolid = (version: string) =>
+ defineCommand({
+ meta: {
+ name: "create-solid",
+ description: "A CLI for scaffolding new Solid projects",
+ version: version,
+ },
+ args: {
+ "projectNamePositional": {
+ type: "positional",
+ required: false,
+ description: "Project name",
+ },
+ "templatePositional": {
+ type: "positional",
+ required: false,
+ description: "Template name",
+ },
+ "project-name": {
+ type: "string",
+ required: false,
+ alias: "p",
+ description: "Project name",
+ },
+ "template": {
+ type: "string",
+ required: false,
+ alias: "t",
+ description: "Template name",
+ },
+ "solid": {
+ type: "boolean",
+ required: false,
+ description: "Create a Solid 2.0 project",
+ },
+ "solidstart": {
+ type: "boolean",
+ required: false,
+ alias: "s",
+ description: "Create a SolidStart project",
+ },
+ "v2": {
+ type: "boolean",
+ required: false,
+ description: "Create a SolidStart v2 project",
+ },
+ "library": {
+ type: "boolean",
+ required: false,
+ alias: "l",
+ description: "Create a Library project",
+ },
+ "vanilla": {
+ type: "boolean",
+ required: false,
+ alias: "v",
+ description: "Create a vanilla (SolidJS + Vite) project",
+ },
+ "ssr": {
+ type: "boolean",
+ required: false,
+ description: "Enable server-side rendering (Solid 2.0 templates that support it)",
+ },
+ "ts": {
+ type: "boolean",
+ required: false,
+ description: "Use typescript",
+ },
+ "js": {
+ type: "boolean",
+ required: false,
+ description: "Use javascript",
+ },
+ },
+ async run({
+ args: {
+ projectNamePositional,
+ templatePositional,
+ "project-name": projectNameOptional,
+ "template": templateOptional,
+ solid,
+ solidstart,
+ library,
+ vanilla,
+ ssr,
+ ts,
+ js,
+ v2,
+ },
+ }) {
+ // Show prompts for any unknown arguments
+ let projectName = projectNamePositional ?? projectNameOptional;
+ let template = templatePositional ?? templateOptional;
+ let projectType: ProjectType | undefined = solid
+ ? "solid"
+ : solidstart
+ ? "start"
+ : vanilla
+ ? "vanilla"
+ : library
+ ? "library"
+ : undefined;
+ // False if user has selected ts, true if they have selected js, and undefined if they've done neither
+ let useJS = ts ? !ts : js ? js : undefined;
+ // Live template lists/paths from the templates repo; undefined falls back to the baked-in lists
+ const manifest = await fetchTemplatesManifest();
+ projectName ??= await cancelable(
+ p.text({ message: "Project Name", placeholder: "solid-project", defaultValue: "solid-project" }),
+ );
+ projectType ??= await cancelable(
+ p.select({
+ message: "What type of project would you like to create?",
+ // Solid 2.0 is listed first but not preselected while core is a release candidate
+ initialValue: "start",
+ options: PROJECT_TYPES.map((t) => ({
+ value: t,
+ label: PROJECT_TYPE_LABELS[t],
+ })),
+ }),
+ );
+ if (!projectType) return;
+
+ let useV2: string | undefined;
+ if (projectType === "start") {
+ useV2 = v2
+ ? "v2"
+ : await cancelable(
+ p.select({
+ message: "Which version of SolidStart?",
+ initialValue: "v2",
+ options: [
+ { value: "v2", label: "2 (Stable)" },
+ { value: "v1", label: "1 (Legacy)" },
+ ],
+ }),
+ );
+ }
+ const isV2 = useV2 === "v2";
+
+ // Don't offer javascript if `projectType` is library
+ useJS ??= projectType === "library" ? false : !(await cancelable(p.confirm({ message: "Use Typescript?" })));
+
+ if (!projectType) return;
+ const group = projectType === "library" ? undefined : resolveGroup(manifest, groupKeyFor(projectType, isV2));
+ const template_opts: ManifestTemplate[] = group
+ ? group.templates
+ : LIBRARY_TEMPLATES.map((name) => ({ name }));
+ const availableTemplates = template_opts.filter((t) => (useJS ? t : !t.name.startsWith("js")));
+ // clack's autocomplete always focuses options[0] when the search box is empty (it only
+ // honors `initialValue` for multi-select), so the manifest's `default`-flagged template
+ // has to be sorted to the front to keep it preselected, same as the old `p.select` did.
+ const defaultTemplate = availableTemplates.find((t) => t.default);
+ const orderedTemplates = defaultTemplate
+ ? [defaultTemplate, ...availableTemplates.filter((t) => t !== defaultTemplate)]
+ : availableTemplates;
+ template ??= await cancelable(
+ p.autocomplete({
+ message: "Which template would you like to use?",
+ placeholder: "Type to search...",
+ // clack's default substring filter would re-filter our fuzzy-ranked options and break
+ // non-contiguous matches (e.g. "wath" -> "with-auth") and the placeholder Tab-fill guard,
+ // so supply an equivalent fuzzy filter (asserted in tests/cli.test.ts).
+ filter: (search, option) => fuzzyScore(search, option.label ?? String(option.value)) > 0,
+ validate: (value) => (value === undefined ? "No matching template." : undefined),
+ options: rankedOptionsFn(orderedTemplates.map((t) => ({ label: t.name, value: t.name }))),
+ }),
+ );
+
+ if (!template) return;
+ const chosenTemplate = template_opts.find((t) => t.name === template);
+
+ // SSR flip: only offered on Solid 2.0 templates that support it (e.g. "basic")
+ let enableSSR = false;
+ if (projectType === "solid" && chosenTemplate?.ssrToggle) {
+ enableSSR =
+ ssr ??
+ (await cancelable(
+ p.confirm({ message: "Enable server-side rendering (streaming SSR)?", initialValue: false }),
+ ));
+ } else if (ssr) {
+ p.log.warn(`--ssr is not supported for this template and will be ignored`);
+ }
+
+ // Need to transpile if the user wants Jabascript, but their selected template isn't Javascript
+ const transpileToJS = useJS && !template.startsWith("js");
+ if (projectType === "solid" && chosenTemplate) {
+ await spinnerify({
+ startText: "Creating project",
+ finishText: "Project created 🎉",
+ fn: () => createSolidV2({ template, destination: projectName, path: group?.path }, transpileToJS, enableSSR),
+ });
+ } else if (projectType === "start" && chosenTemplate) {
+ await spinnerify({
+ startText: "Creating project",
+ finishText: "Project created 🎉",
+ fn: () => createStart({ template, destination: projectName, path: group?.path }, transpileToJS, isV2),
+ });
+ } else if (projectType === "library" && isValidTemplate("library", template)) {
+ await spinnerify({
+ startText: "Creating project",
+ finishText: "Project created 🎉",
+ fn: () => createLibrary({ destination: projectName }),
+ });
+ } else if (projectType === "vanilla" && chosenTemplate) {
+ await spinnerify({
+ startText: "Creating project",
+ finishText: "Project created 🎉",
+ fn: () => createVanilla({ template, destination: projectName, path: group?.path }, transpileToJS),
+ });
+ } else {
+ p.log.error(`Template ${template} is not valid for project type ${projectType}`);
+ process.exit(0);
+ }
+ // Add .gitignore
+ writeFileSync(join(projectName, ".gitignore"), GIT_IGNORE);
+ // Add "Created with Solid CLI" text to bottom of README
+ const readmePath = `${projectName}/README.md`;
+ if (existsSync(readmePath)) {
+ const contents = (await readFile(readmePath)).toString();
+ if (!contents.includes("This project was created with the [Solid CLI]"))
+ await writeFile(
+ readmePath,
+ contents +
+ "\n## This project was created with the [Solid CLI](https://github.com/solidjs-community/solid-cli)\n",
+ );
+ }
+ // Next steps..
+ const pM = detectPackageManager();
+ p.note(
+ (projectName === "." ? "" : `cd ${projectName}\n`) +
+ `${pM.name} install
+${pM.name} ${pM.runScriptCommand("dev")}`,
+ "To get started, run:",
+ );
+ },
+ });
diff --git a/packages/create/src/utils/constants.ts b/packages/create/src/utils/constants.ts
new file mode 100644
index 0000000..6a0ecb6
--- /dev/null
+++ b/packages/create/src/utils/constants.ts
@@ -0,0 +1,184 @@
+export const GIT_IGNORE = `dist
+.wrangler
+.output
+.vercel
+.netlify
+.vinxi
+app.config.timestamp_*.js
+
+# Environment
+.env
+.env*.local
+
+# dependencies
+/node_modules
+
+# IDEs and editors
+/.idea
+.project
+.classpath
+*.launch
+.settings/
+
+# Temp
+gitignore
+
+# System Files
+.DS_Store
+Thumbs.db
+`;
+
+export const JS_CONFIG = {
+ compilerOptions: {
+ jsx: "preserve",
+ jsxImportSource: "solid-js",
+ paths: {
+ "~/*": ["./src/*"],
+ },
+ },
+};
+
+// The solid-v2 templates don't use the `~/*` path alias, and Solid 2.0's JSX
+// runtime lives in `@solidjs/web` (matches the templates' tsconfig.json)
+export const JS_CONFIG_SOLID_V2 = {
+ compilerOptions: {
+ jsx: "preserve",
+ jsxImportSource: "@solidjs/web",
+ },
+};
+
+// Supported templates
+
+/**Supported Vanilla Templates */
+export const VANILLA_TEMPLATES = [
+ "basic",
+ "bare",
+ "with-vitest",
+ "with-uvu",
+ "with-unocss",
+ "with-tailwindcss",
+ "with-sass",
+ "with-solid-router",
+ "with-vite-plugin-pages",
+ "with-tanstack-router-config-based",
+ "with-tanstack-router-file-based",
+ "with-tanstack-start",
+ "with-jest",
+ "with-bootstrap",
+] as const satisfies string[];
+export type VanillaTemplate = (typeof VANILLA_TEMPLATES)[number];
+
+/**
+ * @description This list is hardcoded. But templates are fetched from another github repo.
+ * @see https://github.com/solidjs/templates/tree/main/solid-start
+ */
+export const START_TEMPLATES = [
+ "basic",
+ "bare",
+ "with-solidbase",
+ "with-auth",
+ "with-authjs",
+ "with-drizzle",
+ "with-mdx",
+ "with-prisma",
+ "with-solid-styled",
+ "with-tailwindcss",
+ "with-tanstack-router",
+ "with-trpc",
+ "with-unocss",
+ "with-vitest",
+ "with-strict-csp",
+] as const satisfies string[];
+
+export type StartTemplate = (typeof START_TEMPLATES)[number];
+
+export const START_TEMPLATES_V2 = [
+ "basic",
+ "bare",
+ "with-auth",
+ "with-authjs",
+ "with-drizzle",
+ "with-mdx",
+ "with-prisma",
+ "with-solid-styled",
+ "with-solidbase",
+ "with-strict-csp",
+ "with-tailwindcss",
+ "with-trpc",
+ "with-unocss",
+ "with-vitest",
+] as const satisfies string[];
+
+export type StartTemplateV2 = (typeof START_TEMPLATES_V2)[number];
+
+/**
+ * Solid 2.0 templates (templates repo: `solid-v2/`)
+ * @see https://github.com/solidjs/templates/tree/main/solid-v2
+ */
+export const SOLID_V2_TEMPLATES = [
+ "basic",
+ "bare",
+ "fullstack",
+ "fullstack-tanstack",
+ "with-bootstrap",
+ "with-sass",
+ "with-tailwindcss",
+ "with-tanstack-router",
+ "with-unocss",
+ "with-vitest-browser-mode",
+] as const satisfies string[];
+export type SolidV2Template = (typeof SOLID_V2_TEMPLATES)[number];
+
+/**Supported Library Templates */
+export const LIBRARY_TEMPLATES = ["solid-lib-starter"] as const satisfies string[];
+export type LibraryTemplate = (typeof LIBRARY_TEMPLATES)[number];
+
+// "solid" (Solid 2.0) is listed first, but "start" remains the preselected
+// default while Solid 2.0 core is a release candidate
+export const PROJECT_TYPES = ["solid", "start", "vanilla", "library"] as const satisfies string[];
+export type ProjectType = (typeof PROJECT_TYPES)[number];
+
+/**
+ * Fetches the template list for the project type given
+ * @param projectType type of project
+ */
+export function getTemplatesList(projectType: "vanilla", v2?: boolean): VanillaTemplate[];
+export function getTemplatesList(projectType: "solid", v2?: boolean): SolidV2Template[];
+export function getTemplatesList(projectType: "start", v2?: boolean): StartTemplate[] | StartTemplateV2[];
+export function getTemplatesList(projectType: "library", v2?: boolean): LibraryTemplate[];
+export function getTemplatesList(
+ projectType: ProjectType,
+ v2?: boolean,
+): VanillaTemplate[] | SolidV2Template[] | StartTemplate[] | StartTemplateV2[] | LibraryTemplate[];
+export function getTemplatesList(projectType: ProjectType, v2?: boolean) {
+ if (projectType === "solid") {
+ return SOLID_V2_TEMPLATES as unknown as SolidV2Template[];
+ } else if (projectType === "start") {
+ if (v2) {
+ return START_TEMPLATES_V2 as unknown as StartTemplateV2[];
+ }
+ return START_TEMPLATES as StartTemplate[];
+ } else if (projectType === "library") {
+ return LIBRARY_TEMPLATES as LibraryTemplate[];
+ }
+ return VANILLA_TEMPLATES as VanillaTemplate[];
+}
+
+/**
+ * Tests is the template given is a valid template, and returns it as a template if it is
+ * @param type expected type of the template
+ * @param maybe_template the template string to test
+ * @returns the template string if it is valid, undefined if not
+ */
+export function isValidTemplate(type: "vanilla", maybe_template: string): maybe_template is VanillaTemplate;
+export function isValidTemplate(type: "solid", maybe_template: string): maybe_template is SolidV2Template;
+export function isValidTemplate(
+ type: "start",
+ maybe_template: string,
+ v2?: boolean,
+): maybe_template is StartTemplate | StartTemplateV2;
+export function isValidTemplate(type: "library", maybe_template: string): maybe_template is LibraryTemplate;
+export function isValidTemplate(type: ProjectType, maybe_template: string, v2?: boolean) {
+ const templates = getTemplatesList(type, v2);
+ return templates.find((t) => t === maybe_template) !== undefined;
+}
diff --git a/packages/create/src/utils/download.ts b/packages/create/src/utils/download.ts
new file mode 100644
index 0000000..93fc918
--- /dev/null
+++ b/packages/create/src/utils/download.ts
@@ -0,0 +1,54 @@
+import { downloadRepo, GithubFetcher } from "@begit/core";
+
+export const TEMPLATES_REPO = { owner: "solidjs", name: "templates" } as const;
+
+/** A slow commit lookup must not hold up a scaffold — it is only there to enable caching */
+const LATEST_COMMIT_TIMEOUT_MS = 2000;
+
+/**
+ * Resolves HEAD of the templates repo to a commit sha, so begit can key its
+ * tarball cache on it and reuse the download across scaffolds.
+ *
+ * This goes through api.github.com, which is rate limited to 60 requests/hour
+ * for unauthenticated users (the archive endpoint the tarball itself comes from
+ * is not). Every failure — rate limited, offline, timeout, unexpected payload —
+ * resolves to `undefined`, and the caller falls back to fetching HEAD directly.
+ */
+export const latestTemplatesCommit = async (): Promise => {
+ const lookup = (async () => {
+ try {
+ return await GithubFetcher.fetchLatestCommit(TEMPLATES_REPO);
+ } catch {
+ return undefined;
+ }
+ })();
+ let timer: ReturnType;
+ const timeout = new Promise((resolve) => {
+ timer = setTimeout(() => resolve(undefined), LATEST_COMMIT_TIMEOUT_MS);
+ });
+ return Promise.race([lookup, timeout]).finally(() => clearTimeout(timer));
+};
+
+/**
+ * Downloads `subdir` of the solidjs/templates repo into `destination`.
+ *
+ * No ref is pinned: scaffolds always come from live HEAD of the default branch,
+ * matching the `templates.json` manifest, so template updates reach users
+ * without a CLI release. HEAD is resolved to a sha first so begit can cache the
+ * tarball under it and skip the download next time; when that lookup fails we
+ * fetch HEAD directly instead, uncached — slower, but never a broken scaffold.
+ */
+export const downloadTemplate = async (subdir: string, destination: string) => {
+ const hash = await latestTemplatesCommit();
+ return downloadRepo(
+ {
+ repo: { ...TEMPLATES_REPO, subdir, hash },
+ dest: destination,
+ // HEAD is already resolved (or deliberately left unresolved) above, so begit
+ // must not call the API itself. Without a sha there is nothing to key a cache
+ // entry on, so the tarball is discarded rather than left behind unkeyed.
+ opts: { cache: !!hash, fetch_latest_commit: false },
+ },
+ GithubFetcher,
+ );
+};
diff --git a/packages/create/src/utils/file-system.ts b/packages/create/src/utils/file-system.ts
new file mode 100644
index 0000000..c17c0f9
--- /dev/null
+++ b/packages/create/src/utils/file-system.ts
@@ -0,0 +1,17 @@
+import { Dirent, readdirSync } from "node:fs";
+import { readFile } from "node:fs/promises";
+import { resolve } from "node:path";
+
+export const recurseFiles = (startPath: string, cb: (file: Dirent, startPath: string) => void) => {
+ startPath = resolve(startPath);
+
+ const files = readdirSync(startPath, { withFileTypes: true });
+
+ for (const file of files) {
+ cb(file, startPath);
+ }
+};
+
+export const readFileToString = async (path: string) => {
+ return (await readFile(path)).toString();
+};
diff --git a/packages/create/src/utils/fuzzy.ts b/packages/create/src/utils/fuzzy.ts
new file mode 100644
index 0000000..d55c7c4
--- /dev/null
+++ b/packages/create/src/utils/fuzzy.ts
@@ -0,0 +1,98 @@
+const CHARACTER_SCORE = 1;
+const CONTIGUOUS_BONUS = 1;
+
+type FuzzyMatch = {
+ score: number;
+ startIndex: number;
+};
+
+const NO_MATCH: FuzzyMatch = { score: 0, startIndex: Number.POSITIVE_INFINITY };
+
+function betterMatch(a?: FuzzyMatch, b?: FuzzyMatch): FuzzyMatch | undefined {
+ if (!a) return b;
+ if (!b) return a;
+ if (a.score !== b.score) return a.score > b.score ? a : b;
+ return a.startIndex <= b.startIndex ? a : b;
+}
+
+/**
+ * Matches `input` against `target` in order. Each matched character is worth
+ * one point, with one additional point for every contiguous pair.
+ */
+function findBestMatch(input: string, target: string): FuzzyMatch {
+ if (!input) return { score: CHARACTER_SCORE, startIndex: 0 };
+
+ const query = input.toLowerCase();
+ const candidate = target.toLowerCase();
+ if (query.length > candidate.length) return NO_MATCH;
+
+ const matches: Array> = Array.from(
+ { length: query.length },
+ () => new Array(candidate.length),
+ );
+
+ for (let queryIndex = 0; queryIndex < query.length; queryIndex++) {
+ let bestWithGap: FuzzyMatch | undefined;
+
+ for (let candidateIndex = queryIndex; candidateIndex < candidate.length; candidateIndex++) {
+ if (queryIndex > 0 && candidateIndex >= 2) {
+ bestWithGap = betterMatch(bestWithGap, matches[queryIndex - 1][candidateIndex - 2]);
+ }
+ if (candidate[candidateIndex] !== query[queryIndex]) continue;
+
+ if (queryIndex === 0) {
+ matches[queryIndex][candidateIndex] = {
+ score: CHARACTER_SCORE,
+ startIndex: candidateIndex,
+ };
+ continue;
+ }
+
+ const previous = matches[queryIndex - 1][candidateIndex - 1];
+ const contiguous = previous && {
+ score: previous.score + CHARACTER_SCORE + CONTIGUOUS_BONUS,
+ startIndex: previous.startIndex,
+ };
+ const withGap = bestWithGap && {
+ score: bestWithGap.score + CHARACTER_SCORE,
+ startIndex: bestWithGap.startIndex,
+ };
+
+ matches[queryIndex][candidateIndex] = betterMatch(contiguous, withGap);
+ }
+ }
+
+ return matches.at(-1)?.reduce((best, match) => betterMatch(best, match), undefined) ?? NO_MATCH;
+}
+
+export function fuzzyScore(input: string, target: string): number {
+ return findBestMatch(input, target).score;
+}
+
+type OptionLike = { label?: string; value: string };
+
+/**
+ * Ranks matches by score, earliest match position, then label. An empty query
+ * preserves the original option order.
+ */
+export function rankedOptionsFn(options: T[]) {
+ return function (this: { userInput?: string }): T[] {
+ const input = this?.userInput ?? "";
+ if (!input) return options;
+
+ return options
+ .map((option, index) => {
+ const label = option.label ?? String(option.value);
+ return { option, index, label, match: findBestMatch(input, label) };
+ })
+ .filter(({ match }) => match.score > 0)
+ .sort(
+ (a, b) =>
+ b.match.score - a.match.score ||
+ a.match.startIndex - b.match.startIndex ||
+ a.label.localeCompare(b.label) ||
+ a.index - b.index,
+ )
+ .map(({ option }) => option);
+ };
+}
diff --git a/packages/create/src/utils/manifest.ts b/packages/create/src/utils/manifest.ts
new file mode 100644
index 0000000..6855e68
--- /dev/null
+++ b/packages/create/src/utils/manifest.ts
@@ -0,0 +1,119 @@
+import {
+ SOLID_V2_TEMPLATES,
+ START_TEMPLATES,
+ START_TEMPLATES_V2,
+ VANILLA_TEMPLATES,
+ ProjectType,
+} from "./constants";
+
+/**
+ * `templates.json` manifest published at the root of the solidjs/templates repo.
+ * When reachable, it is the source of truth for template names, subdir paths and
+ * per-template flags, so the templates repo can add/reorganize templates without
+ * requiring a CLI release. The baked-in lists in `constants.ts` are the fallback.
+ */
+export type ManifestTemplate = {
+ name: string;
+ /** Preselected in the template prompt */
+ default?: boolean;
+ /** Offer the "Enable server-side rendering?" prompt for this template */
+ ssrToggle?: boolean;
+};
+
+export type ManifestGroup = {
+ label?: string;
+ /** Subdir prefix inside the templates repo, e.g. "solid-v2" */
+ path: string;
+ status?: string;
+ templates: ManifestTemplate[];
+};
+
+export type TemplatesManifest = {
+ version: number;
+ groups: Record;
+};
+
+/** Manifest groups the CLI understands (library comes from a different repo and stays baked-in) */
+export type ManifestGroupKey = "solid" | "start-v2" | "start-v1" | "vanilla";
+
+export const MANIFEST_URL = "https://raw.githubusercontent.com/solidjs/templates/HEAD/templates.json";
+const MANIFEST_TIMEOUT_MS = 2000;
+
+const asTemplates = (names: readonly string[], defaultName?: string, ssrToggle?: string): ManifestTemplate[] =>
+ names.map((name) => ({
+ name,
+ ...(name === defaultName ? { default: true } : {}),
+ ...(name === ssrToggle ? { ssrToggle: true } : {}),
+ }));
+
+/** Baked-in fallback, used whenever the manifest can't be fetched or parsed */
+export const BAKED_GROUPS: Record = {
+ "solid": {
+ label: "Solid 2.0",
+ path: "solid-v2",
+ templates: asTemplates(SOLID_V2_TEMPLATES, "basic", "basic"),
+ },
+ "start-v2": {
+ label: "SolidStart 2",
+ path: "solid-start-v2",
+ templates: asTemplates(START_TEMPLATES_V2, "basic"),
+ },
+ "start-v1": {
+ label: "SolidStart 1",
+ path: "solid-start-v1",
+ templates: asTemplates(START_TEMPLATES, "basic"),
+ },
+ "vanilla": {
+ label: "SolidJS + Vite",
+ path: "vanilla",
+ templates: asTemplates(VANILLA_TEMPLATES, "basic"),
+ },
+};
+
+/**
+ * Validates an untrusted parsed JSON value into a `TemplatesManifest`.
+ * Returns `undefined` for anything unusable (unknown major version, wrong shape),
+ * dropping malformed groups/entries rather than failing outright.
+ */
+export const parseManifest = (raw: unknown): TemplatesManifest | undefined => {
+ if (!raw || typeof raw !== "object") return undefined;
+ const manifest = raw as TemplatesManifest;
+ if (manifest.version !== 1) return undefined;
+ if (!manifest.groups || typeof manifest.groups !== "object") return undefined;
+ const groups: Record = {};
+ for (const [key, group] of Object.entries(manifest.groups)) {
+ if (!group || typeof group !== "object") continue;
+ if (typeof group.path !== "string" || !Array.isArray(group.templates)) continue;
+ const templates = group.templates.filter(
+ (t): t is ManifestTemplate => !!t && typeof t === "object" && typeof t.name === "string",
+ );
+ if (templates.length === 0) continue;
+ groups[key] = { ...group, templates };
+ }
+ if (Object.keys(groups).length === 0) return undefined;
+ return { version: 1, groups };
+};
+
+/**
+ * Fetches the live manifest from the templates repo (HEAD, small file, short timeout).
+ * Any failure — offline, timeout, 404, malformed JSON, unknown version — resolves to
+ * `undefined` so callers silently fall back to the baked-in lists.
+ */
+export const fetchTemplatesManifest = async (): Promise => {
+ try {
+ const url = process.env.SOLID_CLI_TEMPLATES_MANIFEST_URL || MANIFEST_URL;
+ const res = await fetch(url, { signal: AbortSignal.timeout(MANIFEST_TIMEOUT_MS) });
+ if (!res.ok) return undefined;
+ return parseManifest(await res.json());
+ } catch {
+ return undefined;
+ }
+};
+
+/** Maps the CLI's project type (+ SolidStart version) to a manifest group key */
+export const groupKeyFor = (projectType: Exclude, startV2?: boolean): ManifestGroupKey =>
+ projectType === "start" ? (startV2 ? "start-v2" : "start-v1") : projectType;
+
+/** Resolves a group from the manifest, falling back to the baked-in lists */
+export const resolveGroup = (manifest: TemplatesManifest | undefined, key: ManifestGroupKey): ManifestGroup =>
+ manifest?.groups[key] ?? BAKED_GROUPS[key];
diff --git a/packages/create/src/utils/ssr-flip.ts b/packages/create/src/utils/ssr-flip.ts
new file mode 100644
index 0000000..08b59d6
--- /dev/null
+++ b/packages/create/src/utils/ssr-flip.ts
@@ -0,0 +1,133 @@
+import { existsSync } from "node:fs";
+import { readFile, writeFile } from "node:fs/promises";
+import { join } from "node:path";
+import { log } from "@clack/prompts";
+
+/**
+ * Flips a client-mode Solid 2.0 template (e.g. `solid-v2/basic`) into streaming SSR.
+ * The delta to the `solid-v2/fullstack` template's server posture is exactly three files:
+ * 1. `vite.config.ts` — add `ssr: true` to the `solid({ start: true, ... })` call
+ * 2. `server.js` — the generic production node server (verbatim from `solid-v2/fullstack`)
+ * 3. `package.json` — point the `start` script at that server
+ */
+
+export const SSR_ANCHOR = "solid({ start: true";
+/** The template documents the flip with this hint; drop it once the flip is applied */
+export const SSR_HINT_COMMENT = " // add `ssr: true` for streaming SSR";
+export const SSR_START_SCRIPT = "node --env-file-if-exists=.env server.js";
+
+/**
+ * Production node server for turnkey SSR apps. Verbatim copy of
+ * `solid-v2/fullstack/server.js` from the templates repo — fully generic: it only
+ * imports node builtins plus the built server bundle's `handleRequest`.
+ * Regenerate with `node scripts/gen-ssr-flip-server.mjs `
+ * when the template changes.
+ */
+// @generated-server-js-start
+export const SERVER_JS = `// The entire production server for a turnkey SSR app: static client assets
+// plus one import — the built server bundle's \`handleRequest\`, an
+// adapter-agnostic web \`Request -> Response\` handler that streams the SSR
+// render, resolves hashed client assets through the build manifest, and
+// (with serverFunctions enabled) serves the \`/_server\` endpoint too. The
+// node <-> web plumbing below is the only glue; on a web-native platform
+// (workers, Deno, Bun.serve) \`handleRequest\` is used directly.
+import { createServer } from 'node:http';
+import { readFileSync } from 'node:fs';
+import { Readable } from 'node:stream';
+import { fileURLToPath } from 'node:url';
+import path from 'node:path';
+import { handleRequest } from './dist/server/server.js';
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const port = process.env.PORT || 3000;
+
+const MIME = {
+ '.js': 'application/javascript',
+ '.css': 'text/css',
+ '.html': 'text/html',
+ '.json': 'application/json',
+ '.ico': 'image/x-icon',
+ '.svg': 'image/svg+xml',
+};
+
+function webRequest(req) {
+ const url = new URL(req.url || '/', \`http://\${req.headers.host || \`localhost:\${port}\`}\`);
+ const method = req.method || 'GET';
+ const body = method === 'GET' || method === 'HEAD' ? undefined : Readable.toWeb(req);
+ return new Request(url, {
+ method,
+ headers: req.headers,
+ body,
+ ...(body ? { duplex: 'half' } : {}),
+ });
+}
+
+const server = createServer(async (req, res) => {
+ const url = req.url || '/';
+
+ // Static client assets first.
+ if (url !== '/' && !url.includes('..')) {
+ try {
+ const content = readFileSync(path.resolve(__dirname, 'dist/client' + url.split('?')[0]));
+ res.setHeader('Content-Type', MIME[path.extname(url)] || 'application/octet-stream');
+ res.end(content);
+ return;
+ } catch {
+ // Fall through to the handler (SSR routes, /_server, ...).
+ }
+ }
+
+ try {
+ const response = await handleRequest(webRequest(req));
+ res.statusCode = response.status;
+ const cookies = response.headers.getSetCookie?.();
+ response.headers.forEach((value, key) => {
+ if (key !== 'set-cookie') res.setHeader(key, value);
+ });
+ if (cookies?.length) res.setHeader('set-cookie', cookies);
+ if (response.body) {
+ for await (const chunk of response.body) res.write(chunk);
+ }
+ res.end();
+ } catch (e) {
+ console.error(e);
+ res.statusCode = 500;
+ res.end(e.message);
+ }
+});
+
+server.listen(port, () => {
+ console.log(\`Server running at http://localhost:\${port}\`);
+});
+`;
+// @generated-server-js-end
+
+/**
+ * Applies the SSR flip to a scaffolded template directory (before any TS→JS conversion,
+ * so the config edit happens on the `.ts` source).
+ *
+ * If the `vite.config.ts` anchor is missing (template drifted), the flip is aborted
+ * with a warning instead of writing a broken config, leaving a working client-mode app.
+ */
+export const applySsrFlip = async (dir: string): Promise => {
+ const viteConfigPath = join(dir, "vite.config.ts");
+ const abort = (reason: string) => {
+ log.warn(`Skipping SSR setup: ${reason}. The project was created in client mode.`);
+ return false;
+ };
+ if (!existsSync(viteConfigPath)) return abort("no vite.config.ts found");
+ const viteConfig = (await readFile(viteConfigPath)).toString();
+ if (!viteConfig.includes(SSR_ANCHOR)) return abort("unrecognized vite.config.ts");
+
+ await writeFile(
+ viteConfigPath,
+ viteConfig.replace(SSR_ANCHOR, `${SSR_ANCHOR}, ssr: true`).replace(SSR_HINT_COMMENT, ""),
+ );
+ await writeFile(join(dir, "server.js"), SERVER_JS);
+
+ const packageJsonPath = join(dir, "package.json");
+ const packageJson = JSON.parse((await readFile(packageJsonPath)).toString());
+ packageJson.scripts = { ...packageJson.scripts, start: SSR_START_SCRIPT };
+ await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2) + "\n");
+ return true;
+};
diff --git a/packages/create/src/utils/ts-conversion.ts b/packages/create/src/utils/ts-conversion.ts
new file mode 100644
index 0000000..e0bd5a0
--- /dev/null
+++ b/packages/create/src/utils/ts-conversion.ts
@@ -0,0 +1,43 @@
+import { copyFileSync, Dirent, mkdirSync, writeFileSync } from "node:fs";
+import { readFileToString, recurseFiles } from "./file-system";
+import { join, resolve } from "node:path";
+import { transform } from "sucrase";
+import { rm } from "node:fs/promises";
+import { JS_CONFIG } from "./constants";
+
+const convertToJS = async (file: Dirent, startPath: string) => {
+ const src = join(startPath, file.name);
+ const dest = resolve(startPath.replace(".project", ""), file.name);
+ if (file.isDirectory()) {
+ mkdirSync(dest, { recursive: true });
+ recurseFiles(resolve(startPath, file.name), convertToJS);
+ } else if (file.isFile()) {
+ if (src.endsWith(".d.ts")) {
+ // Type declarations have no JS counterpart
+ } else if (src.endsWith(".ts") || src.endsWith(".tsx")) {
+ let { code } = transform(await readFileToString(src), {
+ transforms: ["typescript", "jsx"],
+ jsxRuntime: "preserve",
+ disableESTransforms: true,
+ preserveDynamicImport: true,
+ });
+
+ writeFileSync(dest.replace(".ts", ".js"), code, { flag: "wx" });
+ } else {
+ copyFileSync(src, dest);
+ }
+ }
+};
+export const handleTSConversion = async (tempDir: string, projectName: string, jsConfig: object = JS_CONFIG) => {
+ await rm(resolve(tempDir, "tsconfig.json"));
+ writeFileSync(resolve(projectName, "jsconfig.json"), JSON.stringify(jsConfig, null, 2), { flag: "wx" });
+
+ // Convert all ts files in temp directory into js
+ recurseFiles(tempDir, convertToJS);
+
+ // Remove temp directory
+ await rm(join(process.cwd(), tempDir), {
+ recursive: true,
+ force: true,
+ });
+};
diff --git a/packages/create/tests/cli.test.ts b/packages/create/tests/cli.test.ts
new file mode 100644
index 0000000..bb61538
--- /dev/null
+++ b/packages/create/tests/cli.test.ts
@@ -0,0 +1,56 @@
+import { runCommand } from "citty";
+import { afterEach, beforeEach, expect, it, vi } from "vitest";
+
+const { autocomplete } = vi.hoisted(() => ({ autocomplete: vi.fn() }));
+
+vi.mock("@clack/prompts", async (importOriginal) => ({
+ ...(await importOriginal()),
+ autocomplete,
+}));
+
+import { createSolid } from "../src";
+
+// Unroutable address: fetchTemplatesManifest fails fast and falls back to the
+// baked-in template lists, same trick used in manifest.test.ts.
+beforeEach(() => {
+ process.env.SOLID_CLI_TEMPLATES_MANIFEST_URL = "http://127.0.0.1:1/templates.json";
+});
+afterEach(() => {
+ delete process.env.SOLID_CLI_TEMPLATES_MANIFEST_URL;
+});
+
+it("uses an autocomplete prompt when selecting a template", async () => {
+ autocomplete.mockResolvedValueOnce(undefined);
+
+ await runCommand(createSolid("test"), { rawArgs: ["test-app", "--vanilla", "--ts"] });
+
+ const { options, filter, validate, placeholder } = autocomplete.mock.calls[0][0];
+ expect(autocomplete).toHaveBeenCalledWith({
+ message: "Which template would you like to use?",
+ placeholder: "Type to search...",
+ filter: expect.any(Function),
+ validate: expect.any(Function),
+ options,
+ });
+ expect(options.call({ userInput: "tail" })[0].value).toBe("with-tailwindcss");
+
+ // clack's autocomplete always focuses options[0] on an empty search box (it ignores a
+ // scalar `initialValue`), so the manifest's default-flagged template must be first.
+ expect(options.call({ userInput: "" })[0].value).toBe("basic");
+
+ // The filter must use the same fuzzy scoring as the ranking fn: a substring filter
+ // would reject "wath" against "with-auth" and re-filter out the ranked results.
+ expect(filter("wath", { label: "with-auth", value: "with-auth" })).toBe(true);
+
+ // clack copies its `placeholder` into the search box on Tab whenever `filter` matches
+ // it against any option in the current (unfiltered) list; none may match, or Tab
+ // would fill the search with unmatched text and trigger the "no match" error.
+ expect(options.call({ userInput: "" }).some((o: { label: string; value: string }) => filter(placeholder, o))).toBe(
+ false,
+ );
+
+ // An empty autocomplete search resolves to `value: undefined`; validate must
+ // reject that with an error message instead of letting the CLI exit silently.
+ expect(validate(undefined)).toEqual(expect.any(String));
+ expect(validate("with-auth")).toBeUndefined();
+});
diff --git a/packages/create/tests/download.test.ts b/packages/create/tests/download.test.ts
new file mode 100644
index 0000000..703e386
--- /dev/null
+++ b/packages/create/tests/download.test.ts
@@ -0,0 +1,38 @@
+import { afterEach, expect, it, vi } from "vitest";
+import { GithubFetcher } from "@begit/core";
+import { latestTemplatesCommit } from "../src/utils/download";
+
+afterEach(() => {
+ vi.restoreAllMocks();
+ vi.useRealTimers();
+});
+
+it("resolves HEAD to a sha so begit can cache the tarball under it", async () => {
+ vi.spyOn(GithubFetcher, "fetchLatestCommit").mockResolvedValue("c3032d9");
+
+ expect(await latestTemplatesCommit()).toBe("c3032d9");
+});
+
+it("falls back to no sha when the commit lookup throws", async () => {
+ // Offline, DNS failure, or a non-JSON response from the API
+ vi.spyOn(GithubFetcher, "fetchLatestCommit").mockRejectedValue(new Error("fetch failed"));
+
+ expect(await latestTemplatesCommit()).toBeUndefined();
+});
+
+it("falls back to no sha when the API answers without one", async () => {
+ // What a rate-limited response looks like by the time begit is done with it
+ vi.spyOn(GithubFetcher, "fetchLatestCommit").mockResolvedValue(undefined);
+
+ expect(await latestTemplatesCommit()).toBeUndefined();
+});
+
+it("falls back to no sha rather than letting a hanging lookup block the scaffold", async () => {
+ vi.useFakeTimers();
+ vi.spyOn(GithubFetcher, "fetchLatestCommit").mockReturnValue(new Promise(() => {}));
+
+ const resolved = latestTemplatesCommit();
+ await vi.advanceTimersByTimeAsync(2000);
+
+ expect(await resolved).toBeUndefined();
+});
diff --git a/packages/create/tests/fixtures/solid-v2-basic/package.json b/packages/create/tests/fixtures/solid-v2-basic/package.json
new file mode 100644
index 0000000..8e3b105
--- /dev/null
+++ b/packages/create/tests/fixtures/solid-v2-basic/package.json
@@ -0,0 +1,30 @@
+{
+ "name": "example-basic",
+ "version": "0.0.0",
+ "description": "",
+ "type": "module",
+ "scripts": {
+ "start": "vite",
+ "dev": "vite",
+ "build": "vite build",
+ "serve": "vite preview",
+ "test": "vitest"
+ },
+ "license": "MIT",
+ "devDependencies": {
+ "@solidjs/testing-library": "1.0.0-beta.2",
+ "@solidjs/vite-plugin": "^3.0.0-next.28",
+ "@testing-library/jest-dom": "^6.6.3",
+ "filesystem-routing": "0.2.1",
+ "jsdom": "^25.0.1",
+ "typescript": "^5.9.2",
+ "vite": "^8.1.5",
+ "vitest": "^4.0.0"
+ },
+ "dependencies": {
+ "@solidjs/meta": "^1.0.0-next.2",
+ "@solidjs/router": "^2.0.0-next.16",
+ "@solidjs/web": "^2.0.0-rc.0",
+ "solid-js": "^2.0.0-rc.0"
+ }
+}
diff --git a/packages/create/tests/fixtures/solid-v2-basic/vite.config.ts b/packages/create/tests/fixtures/solid-v2-basic/vite.config.ts
new file mode 100644
index 0000000..683f1c7
--- /dev/null
+++ b/packages/create/tests/fixtures/solid-v2-basic/vite.config.ts
@@ -0,0 +1,32 @@
+import { fileRoutes } from 'filesystem-routing/vite';
+import { defineConfig } from 'vitest/config';
+import solid from '@solidjs/vite-plugin';
+
+export default defineConfig({
+ // Turnkey client mode: no index.html and no mount file — the plugin
+ // generates the entries around src/App.tsx, wrapped in src/Document.tsx
+ // (or a built-in shell). `vite build` prerenders the shell into
+ // dist/client/index.html and emits a purely static dist/client.
+ plugins: [
+ // `extensions` makes @solidjs/vite-plugin also compile the `?pick=` route
+ // modules the fileRoutes plugin emits (their ids end in a query string).
+ solid({ start: true, extensions: ['.jsx', '.tsx'] }), // add `ssr: true` for streaming SSR
+ fileRoutes(),
+ ],
+ server: {
+ port: 3000,
+ },
+ test: {
+ environment: 'jsdom',
+ globals: false,
+ setupFiles: ['./vitest-setup.ts'],
+ // if you have few tests, try commenting this
+ // out to improve performance:
+ isolate: false,
+ },
+ build: {
+ target: 'esnext',
+ // Keep images as asset files instead of inlining them into the JS bundle.
+ assetsInlineLimit: 0,
+ },
+});
diff --git a/packages/create/tests/fuzzy.test.ts b/packages/create/tests/fuzzy.test.ts
new file mode 100644
index 0000000..058843a
--- /dev/null
+++ b/packages/create/tests/fuzzy.test.ts
@@ -0,0 +1,167 @@
+import { describe, expect, it } from "vitest";
+import { fuzzyScore, rankedOptionsFn } from "../src/utils/fuzzy";
+
+// Representative template names drawn from src/utils/constants.ts
+const TEMPLATES = [
+ "basic",
+ "bare",
+ "with-auth",
+ "with-authjs",
+ "with-drizzle",
+ "with-mdx",
+ "with-prisma",
+ "with-solid-styled",
+ "with-solidbase",
+ "with-solid-router",
+ "with-strict-csp",
+ "with-tailwindcss",
+ "with-tanstack-router-config-based",
+ "with-tanstack-router-file-based",
+ "with-tanstack-start",
+ "with-trpc",
+ "with-unocss",
+ "with-vitest",
+] as const;
+
+const matches = (query: string) => TEMPLATES.filter((template) => fuzzyScore(query, template) > 0);
+
+describe("fuzzyScore — against real template names", () => {
+ it("still matches plain substrings: 'auth' -> with-auth, with-authjs", () => {
+ expect(matches("auth")).toEqual(["with-auth", "with-authjs"]);
+ });
+
+ it("matches non-contiguous chars in order: 'wath' -> with-auth(+)", () => {
+ // w…a…t…h — the headline fuzzy case
+ expect(matches("wath")).toEqual(expect.arrayContaining(["with-auth", "with-authjs"]));
+ expect(matches("wath")).not.toContain("bare");
+ expect(matches("wath")).not.toContain("with-trpc");
+ });
+
+ it("'drz' -> with-drizzle only (d…r…z)", () => {
+ expect(matches("drz")).toEqual(["with-drizzle"]);
+ });
+
+ it("'tail' matches tailwindcss (and, as a fuzzy side-effect, the file-based router)", () => {
+ // 'tail' = t…a…i…l: the same sequence also appears in-order inside
+ // "...tanstack-router-fi[l]e-based" (t/a from tanstack, i/l from file),
+ // which is the inherent permissiveness of fuzzy matching.
+ expect(matches("tail")).toEqual(["with-tailwindcss", "with-tanstack-router-file-based"]);
+ });
+
+ it("'csp' -> with-strict-csp only", () => {
+ expect(matches("csp")).toEqual(["with-strict-csp"]);
+ });
+
+ it("'router' -> all router templates", () => {
+ expect(matches("router")).toEqual([
+ "with-solid-router",
+ "with-tanstack-router-config-based",
+ "with-tanstack-router-file-based",
+ ]);
+ });
+
+ it("'tanstack' -> all tanstack templates", () => {
+ expect(matches("tanstack")).toEqual([
+ "with-tanstack-router-config-based",
+ "with-tanstack-router-file-based",
+ "with-tanstack-start",
+ ]);
+ });
+
+ it("returns empty for impossible queries", () => {
+ expect(matches("xyz")).toEqual([]);
+ expect(matches("q")).toEqual([]);
+ expect(matches("zzz")).toEqual([]);
+ });
+
+ it("empty query matches all templates", () => {
+ expect(matches("")).toEqual([...TEMPLATES]);
+ });
+
+ it("is case-insensitive: 'WATH' matches the same templates as 'wath'", () => {
+ expect(matches("WATH")).toEqual(matches("wath"));
+ });
+});
+
+describe("fuzzyScore — match-quality ranking", () => {
+ it("contiguous match beats scattered match", () => {
+ // "tail" aligns as a tight run in tailwindcss, but scatters through tanstack
+ expect(fuzzyScore("tail", "with-tailwindcss")).toBeGreaterThan(
+ fuzzyScore("tail", "with-tanstack-router-file-based"),
+ );
+ });
+
+ it("adds one point for each contiguous pair", () => {
+ expect(fuzzyScore("auth", "with-auth")).toBe(7);
+ expect(fuzzyScore("wath", "with-auth")).toBe(5);
+ });
+
+ it("does not award word-boundary or prefix bonuses", () => {
+ expect(fuzzyScore("tail", "detail")).toBe(fuzzyScore("tail", "with-tailwindcss"));
+ });
+
+ it("returns 0 when input cannot be matched in order", () => {
+ expect(fuzzyScore("xyz", "with-auth")).toBe(0);
+ expect(fuzzyScore("with-auth", "auth")).toBe(0);
+ });
+
+ it("empty input ties everything at a positive score", () => {
+ expect(fuzzyScore("", "with-auth")).toBeGreaterThan(0);
+ expect(fuzzyScore("", "bare")).toBeGreaterThan(0);
+ });
+
+ it("scores case-insensitively: uppercase query matches lowercase target the same", () => {
+ expect(fuzzyScore("AUTH", "with-auth")).toBe(fuzzyScore("auth", "with-auth"));
+ });
+});
+
+describe("rankedOptionsFn — ordering for clack autocomplete", () => {
+ const opts = TEMPLATES.map((t) => ({ label: t, value: t }));
+ // Simulate clack calling the options fn with the prompt's `this.userInput`.
+ const ranked = (query: string) =>
+ (rankedOptionsFn(opts).call({ userInput: query }) as typeof opts).map((o) => o.label);
+
+ it("ranks an exact substring above a fuzzy scatter: 'tail'", () => {
+ // tailwindcss contains "tail" verbatim; file-based only matches it fuzzily
+ expect(ranked("tail")).toEqual(["with-tailwindcss", "with-tanstack-router-file-based"]);
+ });
+
+ it("keeps prefix/substring winners first: 'auth'", () => {
+ expect(ranked("auth")).toEqual(["with-auth", "with-authjs"]);
+ });
+
+ it("resolves the headline fuzzy case with stable order: 'wath'", () => {
+ // both match fuzzily with equal scores and starts → alphabetical order
+ expect(ranked("wath")).toEqual(["with-auth", "with-authjs"]);
+ });
+
+ it("lands early-typing queries on the strongest contiguous match", () => {
+ const r = ranked("ta");
+ expect(r[0]).toBe("with-tailwindcss");
+ expect(r.indexOf("with-tailwindcss")).toBeLessThan(r.indexOf("with-auth"));
+ });
+
+ it("breaks score ties by earliest match start", () => {
+ const options = ["zz-tail", "tail-zz"].map((label) => ({ label, value: label }));
+ const result = rankedOptionsFn(options).call({ userInput: "tail" });
+ expect(result.map(({ label }) => label)).toEqual(["tail-zz", "zz-tail"]);
+ });
+
+ it("breaks score and start ties alphabetically", () => {
+ const options = ["cat", "car"].map((label) => ({ label, value: label }));
+ const result = rankedOptionsFn(options).call({ userInput: "ca" });
+ expect(result.map(({ label }) => label)).toEqual(["car", "cat"]);
+ });
+
+ it("narrows to a single best match: 'drz'", () => {
+ expect(ranked("drz")).toEqual(["with-drizzle"]);
+ });
+
+ it("returns nothing for impossible queries", () => {
+ expect(ranked("xyz")).toEqual([]);
+ });
+
+ it("empty input preserves the original option order", () => {
+ expect(ranked("")).toEqual([...TEMPLATES]);
+ });
+});
diff --git a/packages/create/tests/manifest.test.ts b/packages/create/tests/manifest.test.ts
new file mode 100644
index 0000000..ae78e1b
--- /dev/null
+++ b/packages/create/tests/manifest.test.ts
@@ -0,0 +1,80 @@
+import { afterEach, expect, it } from "vitest";
+import { fetchTemplatesManifest, parseManifest, resolveGroup } from "../src/utils/manifest";
+
+const validManifest = {
+ version: 1,
+ groups: {
+ solid: {
+ label: "Solid 2.0",
+ path: "solid-v2",
+ templates: [{ name: "basic", default: true, ssrToggle: true }, { name: "bare" }],
+ },
+ },
+};
+
+it("parses a valid manifest", () => {
+ const manifest = parseManifest(validManifest);
+ expect(manifest).toBeDefined();
+ expect(manifest!.groups["solid"].path).toBe("solid-v2");
+ expect(manifest!.groups["solid"].templates.map((t) => t.name)).toEqual(["basic", "bare"]);
+});
+
+it("rejects unknown manifest versions and malformed documents", () => {
+ expect(parseManifest({ ...validManifest, version: 2 })).toBeUndefined();
+ expect(parseManifest(null)).toBeUndefined();
+ expect(parseManifest("nonsense")).toBeUndefined();
+ expect(parseManifest({ version: 1 })).toBeUndefined();
+ expect(parseManifest({ version: 1, groups: { solid: { templates: "not-an-array" } } })).toBeUndefined();
+});
+
+it("drops malformed groups and template entries but keeps the rest", () => {
+ const manifest = parseManifest({
+ version: 1,
+ groups: {
+ solid: { path: "solid-v2", templates: [{ name: "basic" }, { notAName: true }, "bare"] },
+ broken: { path: 42, templates: [{ name: "x" }] },
+ },
+ });
+ expect(manifest).toBeDefined();
+ expect(Object.keys(manifest!.groups)).toEqual(["solid"]);
+ expect(manifest!.groups["solid"].templates).toEqual([{ name: "basic" }]);
+});
+
+it("resolves groups from the manifest, falling back to baked-in lists", () => {
+ const manifest = parseManifest(validManifest);
+ expect(resolveGroup(manifest, "solid").templates.map((t) => t.name)).toEqual(["basic", "bare"]);
+
+ // Groups missing from the manifest fall back per-group
+ expect(resolveGroup(manifest, "vanilla").path).toBe("vanilla");
+
+ // No manifest at all: everything comes from the baked-in lists
+ const baked = resolveGroup(undefined, "solid");
+ expect(baked.path).toBe("solid-v2");
+ expect(baked.templates.map((t) => t.name)).toEqual([
+ "basic",
+ "bare",
+ "fullstack",
+ "fullstack-tanstack",
+ "with-bootstrap",
+ "with-sass",
+ "with-tailwindcss",
+ "with-tanstack-router",
+ "with-unocss",
+ "with-vitest-browser-mode",
+ ]);
+ const basic = baked.templates.find((t) => t.name === "basic")!;
+ expect(basic.default).toBe(true);
+ expect(basic.ssrToggle).toBe(true);
+ expect(resolveGroup(undefined, "start-v2").path).toBe("solid-start-v2");
+ expect(resolveGroup(undefined, "start-v1").path).toBe("solid-start-v1");
+});
+
+afterEach(() => {
+ delete process.env.SOLID_CLI_TEMPLATES_MANIFEST_URL;
+});
+
+it("silently returns undefined when the manifest fetch fails", async () => {
+ // Unroutable address: connection is refused immediately
+ process.env.SOLID_CLI_TEMPLATES_MANIFEST_URL = "http://127.0.0.1:1/templates.json";
+ expect(await fetchTemplatesManifest()).toBeUndefined();
+});
diff --git a/packages/create/tests/ssr-flip.test.ts b/packages/create/tests/ssr-flip.test.ts
new file mode 100644
index 0000000..bdaa739
--- /dev/null
+++ b/packages/create/tests/ssr-flip.test.ts
@@ -0,0 +1,48 @@
+import { beforeEach, expect, it } from "vitest";
+import { mkdtempSync, copyFileSync, existsSync, readFileSync, writeFileSync } from "node:fs";
+import { tmpdir } from "node:os";
+import { join } from "node:path";
+import { fileURLToPath } from "node:url";
+import { applySsrFlip, SERVER_JS, SSR_HINT_COMMENT, SSR_START_SCRIPT } from "../src/utils/ssr-flip";
+
+const fixtures = fileURLToPath(new URL("./fixtures/solid-v2-basic/", import.meta.url));
+
+let dir: string;
+beforeEach(() => {
+ dir = mkdtempSync(join(tmpdir(), "ssr-flip-"));
+ copyFileSync(join(fixtures, "vite.config.ts"), join(dir, "vite.config.ts"));
+ copyFileSync(join(fixtures, "package.json"), join(dir, "package.json"));
+});
+
+it("flips the basic template to streaming SSR", async () => {
+ expect(await applySsrFlip(dir)).toBe(true);
+
+ const viteConfig = readFileSync(join(dir, "vite.config.ts")).toString();
+ expect(viteConfig).toContain("solid({ start: true, ssr: true");
+ expect(viteConfig).not.toContain(SSR_HINT_COMMENT);
+
+ // The production server is a verbatim copy of solid-v2/fullstack/server.js
+ expect(readFileSync(join(dir, "server.js")).toString()).toBe(SERVER_JS);
+
+ const packageJson = JSON.parse(readFileSync(join(dir, "package.json")).toString());
+ expect(packageJson.scripts.start).toBe(SSR_START_SCRIPT);
+ // The other scripts are untouched
+ expect(packageJson.scripts.dev).toBe("vite");
+ expect(packageJson.scripts.build).toBe("vite build");
+});
+
+it("aborts without writing anything when the vite config anchor is missing", async () => {
+ const drifted = `import { defineConfig } from "vite";\nexport default defineConfig({});\n`;
+ writeFileSync(join(dir, "vite.config.ts"), drifted);
+ const packageJsonBefore = readFileSync(join(dir, "package.json")).toString();
+
+ expect(await applySsrFlip(dir)).toBe(false);
+
+ expect(readFileSync(join(dir, "vite.config.ts")).toString()).toBe(drifted);
+ expect(existsSync(join(dir, "server.js"))).toBe(false);
+ expect(readFileSync(join(dir, "package.json")).toString()).toBe(packageJsonBefore);
+});
+
+it("aborts when there is no vite.config.ts", async () => {
+ expect(await applySsrFlip(mkdtempSync(join(tmpdir(), "ssr-flip-empty-")))).toBe(false);
+});
diff --git a/packages/create/tests/template.test.ts b/packages/create/tests/template.test.ts
new file mode 100644
index 0000000..179b2ee
--- /dev/null
+++ b/packages/create/tests/template.test.ts
@@ -0,0 +1,77 @@
+import { afterEach, expect, it } from "vitest";
+import { existsSync, readdirSync, readFileSync, rmSync } from "node:fs";
+import { join } from "node:path";
+import { createSolidV2, createVanilla } from "../src";
+import { fetchTemplatesManifest, resolveGroup, type ManifestGroupKey } from "../src/utils/manifest";
+
+/**
+ * These download from live solidjs/templates HEAD, so they assert the plumbing —
+ * that the right subdir was fetched and extracted into a usable project — rather
+ * than specific files or dependency versions. Template contents, pins and file
+ * layout all change upstream without a CLI release, and must not fail CI here.
+ */
+
+/** Template name + subdir the CLI would actually use, from the live manifest (baked-in fallback) */
+const liveTarget = async (key: ManifestGroupKey) => {
+ const group = resolveGroup(await fetchTemplatesManifest(), key);
+ const template = group.templates.find((t) => t.default) ?? group.templates[0];
+ return { path: group.path, template: template.name };
+};
+
+// begit resolves the destination against `process.cwd()`, so scaffold targets have to be
+// repo-relative. `test/` is gitignored; each run starts from a clean directory so a
+// leftover scaffold can never satisfy the assertions on its own.
+const destinations: string[] = [];
+const scratch = (name: string) => {
+ const destination = join("test", name);
+ rmSync(destination, { recursive: true, force: true });
+ destinations.push(destination);
+ return destination;
+};
+
+afterEach(() => {
+ for (const destination of destinations.splice(0)) rmSync(destination, { recursive: true, force: true });
+});
+
+const expectScaffold = (destination: string) => {
+ const packageJsonPath = join(destination, "package.json");
+ expect(existsSync(packageJsonPath)).toBe(true);
+
+ const packageJson = JSON.parse(readFileSync(packageJsonPath).toString());
+ expect(typeof packageJson.name).toBe("string");
+ expect(Object.keys(packageJson.scripts ?? {}).length).toBeGreaterThan(0);
+ expect(Object.keys(packageJson.dependencies ?? {}).length).toBeGreaterThan(0);
+
+ // Some source to build, whatever the entry files happen to be called
+ expect(readdirSync(join(destination, "src")).length).toBeGreaterThan(0);
+};
+
+// A cold begit cache means pulling the whole templates tarball (~3MB), which does not
+// reliably fit in vitest's 5s default on a slow or contended connection
+const DOWNLOAD_TIMEOUT_MS = 60_000;
+
+it(
+ "downloads and extracts the vanilla template",
+ async () => {
+ const destination = scratch("vanilla");
+ const { path, template } = await liveTarget("vanilla");
+
+ await createVanilla({ template, destination, path }, false);
+
+ expectScaffold(destination);
+ },
+ DOWNLOAD_TIMEOUT_MS,
+);
+
+it(
+ "downloads and extracts the solid-v2 template",
+ async () => {
+ const destination = scratch("solid-v2");
+ const { path, template } = await liveTarget("solid");
+
+ await createSolidV2({ template, destination, path }, false);
+
+ expectScaffold(destination);
+ },
+ DOWNLOAD_TIMEOUT_MS,
+);
diff --git a/packages/create/tests/ts-retarget.test.ts b/packages/create/tests/ts-retarget.test.ts
new file mode 100644
index 0000000..cabb70b
--- /dev/null
+++ b/packages/create/tests/ts-retarget.test.ts
@@ -0,0 +1,28 @@
+import { expect, it } from "vitest";
+import { readFileSync } from "node:fs";
+import { fileURLToPath } from "node:url";
+import { retargetTSFilenames } from "../src/create-solid-v2";
+
+const fixtureConfig = fileURLToPath(new URL("./fixtures/solid-v2-basic/vite.config.ts", import.meta.url));
+
+it("dedupes the extensions array instead of writing ['.jsx', '.jsx']", () => {
+ const converted = retargetTSFilenames(readFileSync(fixtureConfig).toString());
+
+ expect(converted).toContain("extensions: ['.jsx']");
+ expect(converted).not.toContain("'.tsx'");
+ expect(converted).not.toContain("'.jsx', '.jsx'");
+ // Setup files are transpiled alongside the rest of the template
+ expect(converted).toContain("./vitest-setup.js");
+});
+
+it("retargets filename mentions in comments and prose", () => {
+ const converted = retargetTSFilenames(
+ "// generates the entries around src/App.tsx\nSee `vite.config.ts` and `src/routes/users/[id].tsx`. Type declarations stay in `global.d.ts`.",
+ );
+
+ expect(converted).toContain("src/App.jsx");
+ expect(converted).toContain("`vite.config.js`");
+ expect(converted).toContain("[id].jsx");
+ // `.d.ts` files are deleted by the conversion, not renamed
+ expect(converted).toContain("global.d.ts");
+});
diff --git a/packages/ui/tsconfig.json b/packages/create/tsconfig.json
similarity index 57%
rename from packages/ui/tsconfig.json
rename to packages/create/tsconfig.json
index ecaf1e3..e8c3977 100644
--- a/packages/ui/tsconfig.json
+++ b/packages/create/tsconfig.json
@@ -1,19 +1,17 @@
{
"compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
"module": "ESNext",
+ "target": "ESNext",
+ "moduleResolution": "Bundler",
+ "strict": true,
+ "esModuleInterop": true,
+ "forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
+ "resolveJsonModule": true,
+ "types": ["node"],
"declaration": true,
"emitDeclarationOnly": true,
- "moduleResolution": "Bundler",
- "resolveJsonModule": true,
- "isolatedModules": true,
- "allowSyntheticDefaultImports": true,
- "strict": true,
- // "noUnusedLocals": true,
- // "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
+ "rootDir": "./src",
"outDir": "types"
},
"include": ["src/*"]
diff --git a/packages/create/tsup.config.ts b/packages/create/tsup.config.ts
new file mode 100644
index 0000000..4a06abf
--- /dev/null
+++ b/packages/create/tsup.config.ts
@@ -0,0 +1,15 @@
+import { defineConfig } from "tsup";
+
+export default defineConfig({
+ entry: ["src/index.ts"],
+ target: "esnext",
+ format: "esm",
+ splitting: true,
+ sourcemap: false,
+ clean: true,
+ treeshake: true,
+ banner: {
+ js: `import { createRequire } from "module";
+ const require = createRequire(import.meta.url);`,
+ },
+});
diff --git a/packages/full-solid/CHANGELOG.md b/packages/full-solid/CHANGELOG.md
new file mode 100644
index 0000000..95f2d0e
--- /dev/null
+++ b/packages/full-solid/CHANGELOG.md
@@ -0,0 +1,27 @@
+# @solid-cli/full
+
+## 0.8.0
+
+### Minor Changes
+
+- support fetching without the github API (so fetching should no work when hitting the github api limit)
+
+## 0.6.4
+
+### Patch Changes
+
+- update dependencies and add to solid start v2 templates list
+
+## 0.6.3
+
+### Patch Changes
+
+- Update dependencies, add new template, and remove `cd` command if project is created in working directory
+
+## 0.6.1
+
+### Patch Changes
+
+- Fix regression from 0.5.x (.gitignore wasn't being written to new projects)
+
+## 0.6.0
diff --git a/packages/full-solid/README.md b/packages/full-solid/README.md
new file mode 100644
index 0000000..0a9a706
--- /dev/null
+++ b/packages/full-solid/README.md
@@ -0,0 +1 @@
+# Full Solid
diff --git a/packages/full-solid/package.json b/packages/full-solid/package.json
new file mode 100644
index 0000000..bc95197
--- /dev/null
+++ b/packages/full-solid/package.json
@@ -0,0 +1,42 @@
+{
+ "name": "@solid-cli/full",
+ "version": "0.8.0",
+ "description": "Create Solid apps with low configuration",
+ "author": "Thomas Beer",
+ "contributors": [
+ "Rahul Batra"
+ ],
+ "license": "MIT",
+ "homepage": "https://solid-cli.netlify.app",
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/solidjs-community/solid-cli"
+ },
+ "keywords": [
+ "solidjs",
+ "solid",
+ "cli"
+ ],
+ "main": "dist/index.mjs",
+ "bin": {
+ "sd": "./dist/bin.mjs"
+ },
+ "files": [
+ "dist"
+ ],
+ "scripts": {
+ "start": "jiti ./src/bin.ts",
+ "build": "tsc && tsup",
+ "test": "vitest run"
+ },
+ "devDependencies": {
+ "@clack/prompts": "1.7.0",
+ "picocolors": "^1.1.1",
+ "citty": "^0.2.2",
+ "@solid-cli/create": "workspace:*",
+ "@solid-cli/utils": "workspace:*"
+ },
+ "publishConfig": {
+ "access": "public"
+ }
+}
diff --git a/packages/full-solid/src/bin.ts b/packages/full-solid/src/bin.ts
new file mode 100644
index 0000000..5f2c97c
--- /dev/null
+++ b/packages/full-solid/src/bin.ts
@@ -0,0 +1,32 @@
+#! /usr/bin/env node
+
+import { defineCommand, runMain } from "citty";
+import { createSolid } from "@solid-cli/create";
+import packageJson from "../package.json" with { type: "json" };
+import { intro } from "@clack/prompts";
+import * as color from "picocolors";
+import * as p from "@clack/prompts";
+import { debuginfo } from "./debug";
+import { startCommands } from "./start";
+import { openInBrowser } from "@solid-cli/utils";
+intro(`\n${color.bgCyan(color.black(` Solid CLI v${packageJson.version}`))}`);
+
+const main = defineCommand({
+ meta: {
+ description: "The full Solid CLI",
+ },
+ subCommands: {
+ create: createSolid(packageJson.version),
+ debug: debuginfo,
+ start: startCommands,
+ docs: defineCommand({
+ meta: { description: "Open the Solid Docs in your browser" },
+ async run() {
+ openInBrowser("https://docs.solidjs.com");
+ p.log.success("Opened successfully");
+ },
+ }),
+ },
+});
+
+runMain(main);
diff --git a/packages/full-solid/src/debug/index.ts b/packages/full-solid/src/debug/index.ts
new file mode 100644
index 0000000..77e8c14
--- /dev/null
+++ b/packages/full-solid/src/debug/index.ts
@@ -0,0 +1,58 @@
+/// This subcommand prints useful debug info to stdout
+import { readFile } from "fs/promises";
+import os from "os";
+import { defineCommand } from "citty";
+import { detectRuntime } from "./runtime-detector";
+import * as p from "@clack/prompts";
+type DebugInfo = {
+ runtime: { name: string; version: string };
+ os: { platform: string; release: string };
+ packages: Record;
+};
+const getPackageJSON = async () => {
+ const f = await readFile("package.json");
+ const parsed = JSON.parse(f.toString());
+ return parsed;
+};
+const prettyPrintRecord = (record: Record) => {
+ let str = "";
+ for (const key in record) {
+ const value = record[key];
+ str += ` ${key}: ${value}\n`;
+ }
+ return str;
+};
+
+export const prettyPrint = (info: DebugInfo) => {
+ return `System:
+ OS: ${info.os.platform} ${info.os.release}
+Runtime:
+ ${info.runtime.name}: ${info.runtime.version}
+${
+ Object.keys(info.packages).length !== 0
+ ? `Dependencies:
+${prettyPrintRecord(info.packages)}`
+ : ""
+}`;
+};
+export const fetchDebugInfo = async (): Promise => {
+ const parsed = await getPackageJSON();
+ const packages: Record = parsed.dependencies ?? {};
+ const runtime = detectRuntime();
+ return {
+ runtime,
+ os: {
+ platform: os.platform(),
+ release: os.release(),
+ },
+ packages,
+ };
+};
+
+export const debuginfo = defineCommand({
+ meta: { description: "Print important debug info" },
+ async run(_ctx) {
+ const info = await fetchDebugInfo();
+ p.log.info(prettyPrint(info));
+ },
+});
diff --git a/packages/full-solid/src/debug/runtime-detector.ts b/packages/full-solid/src/debug/runtime-detector.ts
new file mode 100644
index 0000000..014cc4b
--- /dev/null
+++ b/packages/full-solid/src/debug/runtime-detector.ts
@@ -0,0 +1,20 @@
+type RuntimeName = "Bun" | "Node" | "Deno";
+type Runtime = { name: RuntimeName; version: string };
+declare global {
+ var Bun: { version: string } | undefined;
+ var Deno: { version: { deno: string } } | undefined;
+}
+export const detectRuntime = (): Runtime => {
+ if (globalThis.Bun) {
+ return { name: "Bun", version: globalThis.Bun?.version };
+ }
+ if (globalThis.Deno) {
+ return { name: "Deno", version: globalThis.Deno?.version?.deno };
+ }
+ // @ts-ignore
+ if (typeof process !== undefined && !!process.versions?.node) {
+ // @ts-ignore
+ return { name: "Node", version: process?.version };
+ }
+ throw new Error("Unable to detect");
+};
diff --git a/packages/full-solid/src/start/index.ts b/packages/full-solid/src/start/index.ts
new file mode 100644
index 0000000..520876a
--- /dev/null
+++ b/packages/full-solid/src/start/index.ts
@@ -0,0 +1,42 @@
+import { createApi, createRoute } from "@solid-cli/utils";
+import { defineCommand } from "citty";
+import * as p from "@clack/prompts";
+import { green } from "picocolors";
+import { cancelable } from "@solid-cli/utils/ui";
+export const startCommands = defineCommand({
+ meta: { description: "Start-specific commands" },
+ subCommands: {
+ route: defineCommand({
+ meta: { description: "Creates a new route" },
+ args: {
+ path: {
+ type: "positional",
+ required: false,
+ description: "Route path",
+ },
+ api: {
+ type: "boolean",
+ required: false,
+ default: false,
+ alias: "a",
+ },
+ },
+ async run({ args: { path, api } }) {
+ path ||= await cancelable(
+ p.text({
+ message: "Route path",
+ validate(value) {
+ if (!value || value.length === 0) return "A route path is required";
+ },
+ }),
+ );
+ if (api) {
+ await createApi(path as string);
+ } else {
+ await createRoute(path as string);
+ }
+ p.log.success(`Route ${green(path as string)} successfully created!`);
+ },
+ }),
+ },
+});
diff --git a/packages/full-solid/tests/debuginfo.test.ts b/packages/full-solid/tests/debuginfo.test.ts
new file mode 100644
index 0000000..6bbe6cf
--- /dev/null
+++ b/packages/full-solid/tests/debuginfo.test.ts
@@ -0,0 +1,8 @@
+import { expect, it } from "vitest";
+import { fetchDebugInfo, prettyPrint } from "../src/debug";
+
+it("Runs", async () => {
+ const output = prettyPrint(await fetchDebugInfo());
+
+ expect(output).contains("Runtime", "System");
+});
diff --git a/packages/core/tsconfig.json b/packages/full-solid/tsconfig.json
similarity index 75%
rename from packages/core/tsconfig.json
rename to packages/full-solid/tsconfig.json
index b6d4e3a..b354b62 100644
--- a/packages/core/tsconfig.json
+++ b/packages/full-solid/tsconfig.json
@@ -1,6 +1,5 @@
{
"compilerOptions": {
- "baseUrl": ".",
"noEmit": true,
"module": "ESNext",
"target": "ESNext",
@@ -9,6 +8,8 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true,
- "resolveJsonModule": true
- }
+ "resolveJsonModule": true,
+ "types": ["node"]
+ },
+ "include": ["src/*"]
}
diff --git a/packages/full-solid/tsup.config.ts b/packages/full-solid/tsup.config.ts
new file mode 100644
index 0000000..ed15cdf
--- /dev/null
+++ b/packages/full-solid/tsup.config.ts
@@ -0,0 +1,17 @@
+import { defineConfig } from "tsup";
+
+export default defineConfig({
+ entry: ["src/bin.ts"],
+ target: "esnext",
+ format: "esm",
+ splitting: true,
+ bundle: true,
+ sourcemap: false,
+ clean: true,
+ treeshake: true,
+ minify: true,
+ banner: {
+ js: `import { createRequire } from "module";
+ const require = createRequire(import.meta.url);`,
+ },
+});
diff --git a/packages/reactivity/.gitignore b/packages/reactivity/.gitignore
deleted file mode 100644
index fbf0622..0000000
--- a/packages/reactivity/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-types
\ No newline at end of file
diff --git a/packages/reactivity/README.md b/packages/reactivity/README.md
deleted file mode 100644
index d46f097..0000000
--- a/packages/reactivity/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-# @solid-cli/reactivity
-
-A lightweight reactivity system which powers some of the CLI. It is an eager system (derived state is updated immediately when the sources change)
diff --git a/packages/reactivity/package.json b/packages/reactivity/package.json
deleted file mode 100644
index 948af8f..0000000
--- a/packages/reactivity/package.json
+++ /dev/null
@@ -1,37 +0,0 @@
-{
- "name": "@solid-cli/reactivity",
- "version": "0.0.11",
- "description": "The minimal, eager reactive system that powers the Solid CLI",
- "license": "MIT",
- "homepage": "https://solid-cli.netlify.app",
- "repository": {
- "type": "git",
- "url": "https://github.com/solidjs-community/solid-cli"
- },
- "files": [
- "dist",
- "types"
- ],
- "main": "./dist/index.mjs",
- "module": "./dist/index.mjs",
- "types": "./types/index.d.ts",
- "exports": {
- ".": {
- "import": "./dist/index.mjs",
- "require": "./dist/index.mjs",
- "types": "./types/index.d.ts"
- }
- },
- "scripts": {
- "test": "vitest run",
- "build": "tsc && tsup"
- },
- "author": "Thomas Beer",
- "devDependencies": {
- "tsup": "^8.3.5",
- "typescript": "^5.6.3"
- },
- "publishConfig": {
- "access": "public"
- }
-}
diff --git a/packages/reactivity/src/api/index.ts b/packages/reactivity/src/api/index.ts
deleted file mode 100644
index ffedb90..0000000
--- a/packages/reactivity/src/api/index.ts
+++ /dev/null
@@ -1,59 +0,0 @@
-import { Computation, Getter, Signal, batch, runWithListener } from "../core";
-export { batch, getListener, type Getter, type Setter, type Signal } from "../core";
-type OnOptions = { defer: boolean };
-export function on(deps: Getter, fn: (val: G) => T, options?: OnOptions): () => T | undefined;
-export function on(deps: Getter[] | Getter, fn: (val: any) => T, options?: OnOptions) {
- let shouldDefer = options?.defer ?? false;
- return () => {
- // Track all getters on call
- let args: any[] = [];
- Array.isArray(deps) ? deps.forEach((d) => args.push(d())) : args.push(deps());
- if (shouldDefer) {
- shouldDefer = false;
- return;
- }
- // Ensure that the function isn't tracked
- return untrack(() => fn(args.length === 1 ? args[0] : args));
- };
-}
-export function createSignal(val: T) {
- const comp = new Computation(() => val);
- const set = (fnOrVal: T | ((val: T | null) => T) | null) => {
- if (typeof fnOrVal === "function") {
- let fn = fnOrVal as (val: T | null) => T;
- const newVal = fn(untrack(comp.get));
- comp.set(newVal);
- } else {
- comp.set(fnOrVal as T);
- }
- };
- return [comp.get, set] as Signal;
-}
-export function createEffect(fn: () => T) {
- new Computation(fn);
-}
-export function createMemo(fn: () => T) {
- const comp = new Computation(fn);
- return comp.get;
-}
-export function createAsync(fn: () => Promise) {
- const [get, set] = createSignal(null);
- const [loading, setLoading] = createSignal(true);
- fn().then((val) => {
- batch(() => {
- set(val);
- setLoading(false);
- });
- });
- Object.defineProperties(get, {
- loading: {
- get() {
- return loading();
- },
- },
- });
- return get as Getter & { loading: boolean };
-}
-export function untrack(fn: () => T) {
- return runWithListener(null, fn);
-}
diff --git a/packages/reactivity/src/core/index.ts b/packages/reactivity/src/core/index.ts
deleted file mode 100644
index 63e923a..0000000
--- a/packages/reactivity/src/core/index.ts
+++ /dev/null
@@ -1,104 +0,0 @@
-export type Getter = () => T;
-export type Setter = (val: T | ((val: T | null) => T)) => void;
-export type Signal = [Getter, Setter];
-let OBSERVER: Computation | null = null;
-let BATCHING = false;
-const UPDATEQUEUE: Computation[] = [];
-export class Computation {
- fn: () => T;
- value: T | null = null;
- state: number = 0;
- queueSlot: number = -1;
- sources: Set> = new Set();
- observers: Set> = new Set();
- constructor(fn: () => T) {
- this.fn = fn;
- this.update();
- }
- track() {
- if (!OBSERVER) return;
- this.observers.add(OBSERVER);
- OBSERVER.sources.add(this);
- }
- get = () => {
- // We need to make sure memos update if they're accessed during a `batch`
- if (this.queueSlot != -1) {
- UPDATEQUEUE.splice(this.queueSlot, 1);
- const prev = BATCHING;
- BATCHING = false;
- this.update();
- BATCHING = prev;
- this.queueSlot = -1;
- }
- this.track();
- return this.value;
- };
- set = (newVal: T) => {
- if (newVal === this.value) return;
- this.value = newVal;
- this.notifyObservers();
- };
- removeParentObservers() {
- if (!this.sources) return;
- this.sources.forEach((s) => s.observers.delete(this));
- this.sources.clear();
- }
- pullSourceUpdates() {
- if (!this.sources) return;
- this.sources.forEach((s) => s.update());
- }
- update() {
- if (BATCHING) {
- if (this.queueSlot != -1) return;
- this.queueSlot = UPDATEQUEUE.length;
- UPDATEQUEUE.push(this);
- return;
- }
- // this.removeParentObservers();
- const prev = OBSERVER;
- OBSERVER = this;
- const newVal = this.fn();
- OBSERVER = prev;
- if (newVal === this.value) return;
- this.value = newVal;
- }
- increment() {
- this.state++;
- // Only increment children if the state has increased to 1, as we don't want to repeatedly re-increment if this node has multiple parents that need updating
- if (this.state === 1) {
- this.observers.forEach((o) => o.increment());
- }
- }
- decrement() {
- this.state--;
- if (this.state === 0) {
- this.update();
- this.observers.forEach((o) => o.decrement());
- }
- }
- notifyObservers() {
- this.observers.forEach((o) => o.increment());
- this.observers.forEach((o) => o.decrement());
- }
-}
-function stabilize() {
- UPDATEQUEUE.forEach((u) => u.update());
- UPDATEQUEUE.length = 0;
-}
-export function batch(fn: () => T) {
- BATCHING = true;
- const res = fn();
- BATCHING = false;
- stabilize();
- return res;
-}
-export function getListener() {
- return OBSERVER;
-}
-export function runWithListener(listener: Computation | null, fn: () => T) {
- const prev = OBSERVER;
- OBSERVER = listener;
- const res = fn();
- OBSERVER = prev;
- return res;
-}
diff --git a/packages/reactivity/src/index.ts b/packages/reactivity/src/index.ts
deleted file mode 100644
index d158c57..0000000
--- a/packages/reactivity/src/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./api";
diff --git a/packages/reactivity/test/async.test.ts b/packages/reactivity/test/async.test.ts
deleted file mode 100644
index 481fd75..0000000
--- a/packages/reactivity/test/async.test.ts
+++ /dev/null
@@ -1,24 +0,0 @@
-import { describe, expect, test } from "vitest";
-import { createAsync, createEffect } from "../src";
-
-describe("createAsync", () => {
- test("An async function resolves to a value", async () => {
- const asyncFn = createAsync(async () => {
- return 123;
- });
- const res = await new Promise((res) => {
- createEffect(() => {
- const result = asyncFn();
- if (result) res(result);
- });
- });
- expect(res).toBe(123);
- });
- test("An async function has a loading state", async () => {
- const asyncFn = createAsync(async () => {
- return 123;
- });
- expect(asyncFn.loading).toBe(true);
- queueMicrotask(() => expect(asyncFn.loading).toBe(false));
- });
-});
diff --git a/packages/reactivity/test/batch.test.ts b/packages/reactivity/test/batch.test.ts
deleted file mode 100644
index 4a9f647..0000000
--- a/packages/reactivity/test/batch.test.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import { test, expect } from "vitest";
-import { describe } from "vitest";
-import { batch, createAsync, createEffect, createMemo, createSignal } from "../src";
-
-describe("batch", () => {
- test("Multiple updates should only trigger an effect once", () => {
- const [get, set] = createSignal(0);
- let updates = 0;
- createEffect(() => {
- get();
- updates++;
- });
- batch(() => {
- set(1);
- set(2);
- });
- expect(updates).toBe(2);
- expect(get()).toBe(2);
- });
- test("A memo called within a batch should get its value updated", () => {
- const [get, set] = createSignal(0);
- const memo = createMemo(() => get() * 2);
- batch(() => {
- set(1);
- expect(memo()).toBe(2);
- });
- });
- test("An effect depending on both loading and data should only run once when the async resolves", async () => {
- const data = createAsync(async () => {
- return 123;
- });
- let updates = 0;
- await new Promise((res) =>
- createEffect(() => {
- // We track both the data itself and the loading signal
- const d = data();
- const loading = data.loading;
- updates++;
- if (d === 123 && loading === false) res(d);
- }),
- );
- expect(updates).toBe(2);
- });
- test("A derived memo accessed within a batch should resolve to the correct value", () => {
- const [get, set] = createSignal(0);
- const memo = createMemo(() => get() * 2);
- let updates = 0;
- // First update on initial run
- const derived = createMemo(() => {
- updates++;
- return memo()! * 2;
- });
- batch(() => {
- set(1);
- set(2);
- // 2nd Update on access
- expect(derived()).toBe(8);
- set(3);
- // 3rd update on access
- expect(derived()).toBe(12);
- });
- expect(updates).toBe(3);
- });
- test.skip("Diamond problem with memos accessed in a batch", () => {
- const [get, set] = createSignal(0);
- let updates = 0;
- const A = createMemo(() => {
- updates++;
- get();
- });
- const B = createMemo(() => A()! * 2);
- const C = createMemo(() => A()! * 3);
- const D = createMemo(() => B()! + C()!);
- batch(() => {
- set(2);
- });
- // Actually currently get 3 here
- expect(updates).toBe(2);
- });
-});
diff --git a/packages/reactivity/test/effects.test.ts b/packages/reactivity/test/effects.test.ts
deleted file mode 100644
index 735f405..0000000
--- a/packages/reactivity/test/effects.test.ts
+++ /dev/null
@@ -1,54 +0,0 @@
-import { describe, test, expect } from "vitest";
-import { createEffect, createSignal } from "../src";
-describe("createEffect", () => {
- test("An effect executes once when created", () => {
- let updates = 0;
- createEffect(() => {
- updates++;
- });
- expect(updates).toBe(1);
- });
- test("An effect re-executes when a dependency changes", () => {
- let updates = 0;
- const [value, setValue] = createSignal(0);
- createEffect(() => {
- value();
- updates++;
- });
- expect(updates).toBe(1);
- setValue(1);
- expect(updates).toBe(2);
- });
- test("Changes propagate correctly", () => {
- const [get, set] = createSignal(0);
- let updates = 0;
- createEffect(() => {
- get();
- updates++;
- });
- expect(updates).toBe(1);
- set(1);
- expect(updates).toBe(2);
- set(2);
- expect(updates).toBe(3);
- });
- test("Nested effects", () => {
- const [A, setA] = createSignal(0);
- let updates = 0;
- createEffect(() => {
- A();
- updates++;
- let nestedUpdates = 0;
- const [get, set] = createSignal(0);
- createEffect(() => {
- get();
- nestedUpdates++;
- });
- expect(nestedUpdates).toBe(1);
- set(1);
- expect(nestedUpdates).toBe(2);
- });
- setA(1);
- expect(updates).toBe(2);
- });
-});
diff --git a/packages/reactivity/test/memos.test.ts b/packages/reactivity/test/memos.test.ts
deleted file mode 100644
index e18c764..0000000
--- a/packages/reactivity/test/memos.test.ts
+++ /dev/null
@@ -1,55 +0,0 @@
-import { describe, test, expect } from "vitest";
-import { createMemo, createSignal } from "../src";
-describe("createMemo", () => {
- test("A memo is executed once on creation", () => {
- let updates = 0;
- createMemo(() => {
- updates++;
- });
- expect(updates).toBe(1);
- });
- test("A memo updates when its dependencies change", () => {
- const [value, setValue] = createSignal(0);
- let updates = 0;
- createMemo(() => {
- value();
- updates++;
- });
- expect(updates).toBe(1);
- setValue(1);
- expect(updates).toBe(2);
- });
- test("Memos don't overexecute if a dependency doesn't change", () => {
- const [value, setValue] = createSignal(0);
- const memo1 = createMemo(() => {
- value();
- return 1;
- });
- let updates = 0;
- const memo2 = createMemo(() => {
- updates++;
- return memo1();
- });
- expect(memo2()).toBe(1);
- setValue(0);
- expect(updates).toBe(1);
- });
- test("Memos don't overexecute in a diamond (The diamond problem)", () => {
- const [A, setA] = createSignal(0);
- const B = createMemo(() => {
- return A() * 2;
- });
- const C = createMemo(() => {
- return A() + 2;
- });
- let updates = 0;
- const D = createMemo(() => {
- updates++;
- return B()! + C()!;
- });
- expect(D()).toBe(2);
- setA(1);
- expect(D()).toBe(5);
- expect(updates).toBe(2);
- });
-});
diff --git a/packages/reactivity/test/signals.test.ts b/packages/reactivity/test/signals.test.ts
deleted file mode 100644
index c227cfe..0000000
--- a/packages/reactivity/test/signals.test.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { describe, test, expect } from "vitest";
-import { createSignal } from "../src";
-describe("createSignal", () => {
- test("A signal should hold a value that can be updated", () => {
- const [value, setValue] = createSignal(0);
- expect(value()).toBe(0);
- setValue(1);
- expect(value()).toBe(1);
- });
-});
diff --git a/packages/reactivity/tsconfig.json b/packages/reactivity/tsconfig.json
deleted file mode 100644
index 1bd37fb..0000000
--- a/packages/reactivity/tsconfig.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "compilerOptions": {
- "target": "ESNext",
- "useDefineForClassFields": true,
- "module": "ESNext",
- "skipLibCheck": true,
- "declaration": true,
- "emitDeclarationOnly": true,
- /* Bundler mode */
- "moduleResolution": "bundler",
- // "allowImportingTsExtensions": true,
- "resolveJsonModule": true,
- "isolatedModules": true,
- // "noEmit": true,
-
- /* Linting */
- "strict": true,
- "noUnusedLocals": true,
- "noUnusedParameters": true,
- "noFallthroughCasesInSwitch": true,
- "outDir": "types"
- },
- "include": ["src/*"]
-}
diff --git a/packages/reactivity/tsup.config.ts b/packages/reactivity/tsup.config.ts
deleted file mode 100644
index aaf7a65..0000000
--- a/packages/reactivity/tsup.config.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { defineConfig } from "tsup";
-
-export default defineConfig({
- entry: ["src/index.ts"],
- target: "esnext",
- format: ["esm", "cjs"],
- splitting: false,
- sourcemap: true,
- minify: true,
- clean: true,
-});
diff --git a/packages/ui/.gitignore b/packages/ui/.gitignore
deleted file mode 100644
index fbf0622..0000000
--- a/packages/ui/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-types
\ No newline at end of file
diff --git a/packages/ui/src/components/autocomplete/index.ts b/packages/ui/src/components/autocomplete/index.ts
deleted file mode 100644
index 739ab93..0000000
--- a/packages/ui/src/components/autocomplete/index.ts
+++ /dev/null
@@ -1,304 +0,0 @@
-import { Key } from "node:readline";
-import { Prompt } from "@clack/core";
-import { TextOptions } from "@clack/prompts";
-import { S_CHECKBOX_ACTIVE, S_CHECKBOX_SELECTED, S_CHECKBOX_INACTIVE, S_BAR, S_BAR_END, box, S_INFO } from "./utils";
-import color from "picocolors";
-import { createEffect } from "@solid-cli/reactivity";
-import { t } from "@solid-cli/utils";
-import { Option } from "@solid-cli/utils/util-types";
-
-const buildRegex = (str: string) => {
- let s = "";
-
- for (let i = 0; i < str.length; i++) {
- s += str[i] + ".*";
- }
-
- s = ".*" + s;
-
- return RegExp(s);
-};
-
-const search = (values: T[], lookFor: string) => {
- const group = lookFor.match(/(\w+)\/(\w+)?/);
-
- if (group) {
- const groupData = values.filter((option) => option.group && option.group.includes(group[1]));
-
- const sp = group[2];
-
- if (!sp) return groupData;
-
- const r = buildRegex(sp);
- return groupData.filter((v) => r.test((v.label ?? v.value).toLowerCase()));
- }
-
- const r = buildRegex(lookFor);
-
- return !lookFor.length ? values : values.filter((v) => r.test((v.label ?? v.value).toLowerCase()));
-};
-
-const sortByGroup = (options: T[]) => {
- return [...options].sort((a, b) => {
- if (a.group && b.group) return 0;
-
- if (a.group && !b.group) return 1;
-
- return -1;
- });
-};
-
-const opt = (
- option: any,
- state: "inactive" | "active" | "selected" | "active-selected" | "submitted" | "cancelled",
-) => {
- const label = option.label ?? String(option.value);
- if (state === "active") {
- return `${color.cyan(S_CHECKBOX_ACTIVE)} ${label} ${option.hint ? color.dim(`(${option.hint})`) : ""}`;
- } else if (state === "selected") {
- return `${color.green(S_CHECKBOX_SELECTED)} ${color.dim(label)}`;
- } else if (state === "cancelled") {
- return `${color.strikethrough(color.dim(label))}`;
- } else if (state === "active-selected") {
- return `${color.green(S_CHECKBOX_SELECTED)} ${label} ${option.hint ? color.dim(`(${option.hint})`) : ""}`;
- } else if (state === "submitted") {
- return `${color.dim(label)}`;
- }
- return `${color.dim(S_CHECKBOX_INACTIVE)} ${color.dim(label)}`;
-};
-
-const aliases = new Map([
- ["k", "up"],
- ["j", "down"],
- ["h", "left"],
- ["l", "right"],
-]);
-
-interface AutocompleteTextOptions extends TextOptions {
- options: () => T[];
- render: (this: Omit, "prompt">) => string | void;
-}
-
-class AutocompleteText extends Prompt {
- valueWithCursor = "";
- options: T[];
-
- get __cursor() {
- return this._cursor;
- }
- cursor: number = 0;
-
- filteredOptions: T[];
- selected: T[];
-
- mode: "search" | "explore" = "explore";
-
- private toggleValue() {
- const cursorOption = this.filteredOptions[this.cursor];
- const selected = this.selected.find((v) => v.value === cursorOption.value) !== undefined;
-
- this.selected = selected
- ? this.selected.filter((v) => v.value !== cursorOption.value)
- : [...this.selected, cursorOption];
- }
-
- constructor(opts: AutocompleteTextOptions) {
- super(opts);
-
- // // @ts-ignore
- // this.rl?.clearLine();
- this.options = opts.options();
- this.filteredOptions = opts.options();
- this.selected = [];
-
- if (this.mode === "explore") this.value = this.options;
-
- createEffect(() => {
- this.options = opts.options();
- this.filteredOptions = sortByGroup(search(opts.options(), ""));
- this.value = this.options;
- // @ts-ignore
- this.render();
- });
-
- this.customKeyPress = this.customKeyPress.bind(this);
-
- this.on("finalize", () => {
- if (!this.value) {
- this.value = opts.defaultValue;
- }
- this.valueWithCursor = this.value;
- this.value = this.selected;
- });
-
- this.on("value", () => {
- if (this.value[this.value.length - 1] === "/" && this.mode === "explore") {
- // @ts-ignore
- this.rl.clearLine();
- this.value = "";
- this.mode = "search";
- return;
- }
- if (this.mode === "explore") return;
- const value = this.value as string;
- if (this._cursor >= value.length) {
- this.valueWithCursor = `${value}${color.inverse(color.hidden("_"))}`;
- } else {
- const s1 = value.slice(0, this._cursor);
- const s2 = value.slice(this._cursor);
- this.valueWithCursor = `${s1}${color.inverse(s2)}${s2.slice(1)}`;
- }
-
- const indexSelector = value.match(/:(\d+)/);
- // if (!indexSelector) this.cursor = 0;
-
- const last = value[value.length - 1];
- if (last === ":") {
- const tillSelector = value.slice(0, value.length - 1);
-
- if (tillSelector.length > 0) {
- this.filteredOptions = sortByGroup(search(this.options, tillSelector));
- } else {
- this.filteredOptions = sortByGroup(this.options);
- }
-
- return;
- }
-
- if (indexSelector && indexSelector[1]) {
- const index = Number(indexSelector[1]);
-
- if (this.filteredOptions.length > 1 && index > this.filteredOptions.length - 1) {
- this.state = "error";
- return;
- }
- this.cursor = index;
- return;
- }
-
- const before = this.filteredOptions.length;
- this.filteredOptions = sortByGroup(search(this.options, value.toLowerCase()));
- const after = this.filteredOptions.length;
-
- if (before !== after) {
- this.cursor = 0;
- }
- });
- this.on("cursor", (key) => {
- if (this.mode === "explore" && key === "/") return;
- switch (key) {
- case "left":
- case "up":
- this.cursor = this.cursor === 0 ? this.filteredOptions.length - 1 : this.cursor - 1;
- break;
- case "down":
- case "right":
- this.cursor = this.cursor === this.filteredOptions.length - 1 ? 0 : this.cursor + 1;
- break;
- case "tab":
- this.toggleValue();
- break;
- }
- });
- this.input.on("keypress", this.customKeyPress);
- }
-
- private customKeyPress(char: string, key?: Key) {
- if (this.mode === "explore" && key?.name && aliases.has(key.name)) {
- this.emit("cursor", aliases.get(key.name));
- }
- if (key?.name === "tab") {
- const focusedOption = this.filteredOptions[this.cursor];
- const selected = this.selected.find((v) => v?.value === focusedOption?.value) !== undefined;
- if (selected) {
- this.selected = this.selected.filter((v) => v !== focusedOption);
- } else {
- this.selected = this.filteredOptions?.length === 0 ? this.selected : [...this.selected, focusedOption];
- }
- // @ts-ignore
- this.rl.clearLine();
- } else if (key?.name === "escape") {
- if (this.mode === "search") {
- this.mode = "explore";
- return;
- }
- }
- }
-}
-
-const BULLET = "•";
-
-const instructions = color.gray(
- `↓/j down ${BULLET} ↑/k up ${BULLET} tab select ${BULLET} Ctrl-C cancel ${BULLET} / filter`,
-);
-
-const searchInstructions = color.gray(
- `tab select ${BULLET} ESC cancel filter ${BULLET} : to highlight by index`,
-);
-
-export const autocomplete = (opts: Omit, "render">) => {
- return new AutocompleteText({
- options: opts.options,
- message: opts.message,
- validate: opts.validate,
- placeholder: opts.placeholder,
- defaultValue: opts.defaultValue,
- initialValue: opts.initialValue,
- render() {
- const selected =
- this.selected.length === 0
- ? color.gray(t.NOTHING_SELECTED)
- : this.selected.map((option, i) => `${color.yellow(option.label)}`).join(" ");
- const placeholder = opts.placeholder
- ? color.inverse(opts.placeholder[0]) + color.dim(opts.placeholder.slice(1))
- : color.inverse(color.hidden("_"));
-
- const value = typeof this.value === "string" ? (!this.value ? placeholder : this.valueWithCursor) : "";
-
- const textView = `${color.cyan("?")} Filter: ` + value + "\n";
-
- const noResults = color.red(t.AUTOCOMPLETE_NO_RESULTS);
-
- let uniqueGroups = new Set();
- let start = Math.max(0, this.cursor - 11);
- const filteredOptions = this.filteredOptions
- .map((option, i) => {
- if (i < start || i > start + 11) return;
-
- const selected = this.selected.find((v) => v.value === option.value) !== undefined;
- const has = option.group && uniqueGroups.has(option.group);
- if (!has && option.group) {
- uniqueGroups.add(option.group);
- }
-
- const isFocused = this.cursor === i;
-
- const active = (i === 0 && this.mode === "search") || (this.mode === "explore" && isFocused);
- const state = selected ? "selected" : active ? "active" : "inactive";
-
- const spacing = i > 9 ? " " : " ";
-
- const groupView = `${
- has || !option.group ? "" : `\n${color.cyan(S_BAR)}${color.bgBlue(color.black(option.group))}`
- } ${!has && option.group ? `\n${color.cyan(S_BAR)} ` : ""}`;
-
- return groupView + `${i}:${spacing}` + (isFocused ? color.bgBlack(opt(option, state)) : opt(option, state));
- })
- .filter(Boolean)
- .join(`\n${color.cyan(S_BAR)} `);
-
- // prettier-ignore
- const options = `${color.cyan(S_BAR)} ${this.filteredOptions.length ? filteredOptions : noResults}\n${color.cyan(S_BAR_END,)}\n`;
-
- return (
- `${color.cyan(S_BAR)} \n ${color.cyan(S_BAR)} ${color.yellow(S_CHECKBOX_SELECTED)} ${
- t.AUTOCOMPLETE_SELECTED
- }: ${selected}\n${color.cyan(S_BAR)} \n` +
- (this.mode === "search" ? `${color.cyan(S_BAR)} ` + textView : "") +
- options +
- "\n" +
- (this.mode === "search" ? searchInstructions : instructions)
- );
- },
- }).prompt() as Promise;
-};
diff --git a/packages/ui/src/components/autocomplete/utils.ts b/packages/ui/src/components/autocomplete/utils.ts
deleted file mode 100644
index 78c579f..0000000
--- a/packages/ui/src/components/autocomplete/utils.ts
+++ /dev/null
@@ -1,95 +0,0 @@
-import { log } from "@clack/prompts";
-import color from "picocolors";
-// Taken from https://github.com/natemoo-re/clack/blob/main/packages/prompts/src/index.ts#L642
-const S_STEP_ACTIVE = "◆";
-const S_STEP_CANCEL = "■";
-const S_STEP_ERROR = "▲";
-const S_STEP_SUBMIT = "◇";
-
-const S_BAR_START = "┌";
-const S_BAR = "│";
-const S_BAR_END = "└";
-
-const S_RADIO_ACTIVE = "●";
-const S_RADIO_INACTIVE = "○";
-const S_CHECKBOX_ACTIVE = "◻";
-const S_CHECKBOX_SELECTED = "◼";
-const S_CHECKBOX_INACTIVE = "◻";
-const S_PASSWORD_MASK = "▪";
-
-const S_BAR_H = "─";
-const S_CORNER_TOP_RIGHT = "╮";
-const S_CONNECT_LEFT = "├";
-const S_CORNER_BOTTOM_RIGHT = "╯";
-
-const S_INFO = "●";
-const S_SUCCESS = "◆";
-const S_WARN = "▲";
-const S_ERROR = "■";
-
-// Adapted from https://github.com/chalk/ansi-regex
-// @see LICENSE
-function ansiRegex() {
- const pattern = [
- "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)",
- "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-nq-uy=><~]))",
- ].join("|");
-
- return new RegExp(pattern, "g");
-}
-
-const strip = (str: string) => str.replace(ansiRegex(), "");
-const box = (message = "", title = "") => {
- const lines = `\n${message}\n`.split("\n");
- const len =
- Math.max(
- lines.reduce((sum, ln) => {
- ln = strip(ln);
- return ln.length > sum ? ln.length : sum;
- }, 0),
- strip(title).length,
- ) + 2;
- const msg = lines
- .map((ln) => `${color.gray(S_BAR)} ${color.dim(ln)}${" ".repeat(len - strip(ln).length)}${color.gray(S_BAR)}`)
- .join("\n");
- return `${color.gray(S_BAR)}\n${color.green(S_STEP_SUBMIT)} ${color.reset(title)} ${color.gray(
- S_BAR_H.repeat(Math.max(len - title.length - 1, 1)) + S_CORNER_TOP_RIGHT,
- )}\n${msg}\n${color.gray(S_CONNECT_LEFT + S_BAR_H.repeat(len + 2) + S_CORNER_BOTTOM_RIGHT)}\n`;
-};
-
-export {
- S_CONNECT_LEFT,
- S_CORNER_BOTTOM_RIGHT,
- S_CORNER_TOP_RIGHT,
- S_BAR,
- S_BAR_START,
- S_BAR_END,
- S_BAR_H,
- S_INFO,
- S_ERROR,
- S_WARN,
- S_SUCCESS,
- S_RADIO_ACTIVE,
- S_RADIO_INACTIVE,
- S_PASSWORD_MASK,
- S_CHECKBOX_ACTIVE,
- S_CHECKBOX_INACTIVE,
- S_CHECKBOX_SELECTED,
- S_STEP_ACTIVE,
- S_STEP_ERROR,
- S_STEP_CANCEL,
- S_STEP_SUBMIT,
-};
-
-const cancelable = async (prompt: Promise, cancelMessage: string = "Canceled"): Promise => {
- const value = await prompt;
-
- if (typeof value === "symbol") {
- log.warn(cancelMessage);
- process.exit(0);
- }
-
- return value;
-};
-
-export { strip, box, cancelable };
diff --git a/packages/ui/src/components/form/index.ts b/packages/ui/src/components/form/index.ts
deleted file mode 100644
index fc11479..0000000
--- a/packages/ui/src/components/form/index.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { TextOptions, text } from "@clack/prompts";
-
-interface Field extends TextOptions {
- name: string;
- render?: (this: Field) => Promise;
-}
-
-export const form = async (fields: Field[]) => {
- let returns: { name: string; value: any }[] = [];
-
- for (const field of fields) {
- if (field.render) {
- const r = await field.render.bind(field)();
- if (r) {
- returns.push({ name: field.name, value: r });
- }
- continue;
- }
-
- const r = await text({ ...field });
-
- returns.push({ name: field.name, value: r });
- }
-
- return returns;
-};
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts
deleted file mode 100644
index 083c425..0000000
--- a/packages/ui/src/index.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-export * from "./components/autocomplete";
-export * from "./components/form";
-export * from "./components/autocomplete/utils";
-export * from "./components/spinnerify";
diff --git a/packages/ui/tsup.config.ts b/packages/ui/tsup.config.ts
deleted file mode 100644
index aaf7a65..0000000
--- a/packages/ui/tsup.config.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { defineConfig } from "tsup";
-
-export default defineConfig({
- entry: ["src/index.ts"],
- target: "esnext",
- format: ["esm", "cjs"],
- splitting: false,
- sourcemap: true,
- minify: true,
- clean: true,
-});
diff --git a/packages/utils/CHANGELOG.md b/packages/utils/CHANGELOG.md
new file mode 100644
index 0000000..544c42c
--- /dev/null
+++ b/packages/utils/CHANGELOG.md
@@ -0,0 +1,21 @@
+# @solid-cli/utils
+
+## 0.7.0
+
+### Minor Changes
+
+- support fetching without the github API (so fetching should no work when hitting the github api limit)
+
+## 0.6.3
+
+### Patch Changes
+
+- update dependencies and add to solid start v2 templates list
+
+## 0.6.2
+
+### Patch Changes
+
+- Update dependencies
+
+## 0.6.0
diff --git a/packages/utils/package.json b/packages/utils/package.json
index 95e521f..f1f0e3d 100644
--- a/packages/utils/package.json
+++ b/packages/utils/package.json
@@ -1,6 +1,6 @@
{
"name": "@solid-cli/utils",
- "version": "0.0.15",
+ "version": "0.7.0",
"description": "A collection of utilities for the Solid CLI",
"license": "MIT",
"homepage": "https://solid-cli.netlify.app",
@@ -17,44 +17,49 @@
"types": "./types/index.d.ts",
"exports": {
".": {
+ "types": "./types/index.d.ts",
"import": "./dist/index.mjs",
- "require": "./dist/index.mjs",
- "types": "./types/index.d.ts"
+ "require": "./dist/index.mjs"
},
"./paths": {
+ "types": "./types/paths/index.d.ts",
"import": "./dist/paths/index.mjs",
- "require": "./dist/paths/index.mjs",
- "types": "./types/paths/index.d.ts"
+ "require": "./dist/paths/index.mjs"
},
"./transform": {
+ "types": "./types/transform/index.d.ts",
"import": "./dist/transform/index.mjs",
- "require": "./dist/transform/index.mjs",
- "types": "./types/transform/index.d.ts"
+ "require": "./dist/transform/index.mjs"
},
"./updates": {
+ "types": "./types/updates/index.d.ts",
"import": "./dist/updates/index.mjs",
- "require": "./dist/updates/index.mjs",
- "types": "./types/updates/index.d.ts"
+ "require": "./dist/updates/index.mjs"
},
"./fs": {
+ "types": "./types/fs/index.d.ts",
"import": "./dist/fs/index.mjs",
- "require": "./dist/fs/index.mjs",
- "types": "./types/fs/index.d.ts"
+ "require": "./dist/fs/index.mjs"
},
"./util-types": {
+ "types": "./types/util-types/index.d.ts",
"import": "./dist/util-types/index.mjs",
- "require": "./dist/util-types/index.mjs",
- "types": "./types/util-types/index.d.ts"
+ "require": "./dist/util-types/index.mjs"
},
"./primitives": {
+ "types": "./types/primitives/index.d.ts",
"import": "./dist/primitives/index.mjs",
- "require": "./dist/primitives/index.mjs",
- "types": "./types/primitives/index.d.ts"
+ "require": "./dist/primitives/index.mjs"
},
"./package-manager": {
+ "types": "./types/package-manager/index.d.ts",
"import": "./dist/package-manager/index.mjs",
- "require": "./dist/package-manager/index.mjs",
- "types": "./types/package-manager/index.d.ts"
+ "require": "./dist/package-manager/index.mjs"
+ },
+ "./ui": {
+ "types": "./types/ui/index.d.ts",
+ "import": "./dist/ui/index.mjs",
+ "require": "./dist/ui/index.mjs"
}
},
"scripts": {
@@ -62,24 +67,15 @@
"build": "tsc && tsup"
},
"devDependencies": {
- "@chialab/esbuild-plugin-meta-url": "^0.18.2",
- "@types/node": "22.9.0",
- "jiti": "^2.4.0",
- "magicast": "^0.3.5",
- "tsup": "^8.3.5",
- "typescript": "^5.6.3",
- "vitest": "^2.1.5"
+ "magicast": "^0.5.3"
},
"publishConfig": {
"access": "public"
},
"dependencies": {
- "@clack/core": "0.3.4",
- "@clack/prompts": "0.7.0",
- "@solid-cli/reactivity": "workspace:*",
- "cmd-ts": "^0.13.0",
- "execa": "^8.0.1",
- "picocolors": "^1.1.1",
- "smol-toml": "^1.3.0"
+ "@clack/core": "1.4.3",
+ "@clack/prompts": "1.7.0",
+ "execa": "^10.0.0",
+ "picocolors": "^1.1.1"
}
}
diff --git a/packages/utils/src/cmd-ts/index.ts b/packages/utils/src/cmd-ts/index.ts
deleted file mode 100644
index 1896305..0000000
--- a/packages/utils/src/cmd-ts/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from "./oneOf";
diff --git a/packages/utils/src/cmd-ts/oneOf.ts b/packages/utils/src/cmd-ts/oneOf.ts
deleted file mode 100644
index 79fabcb..0000000
--- a/packages/utils/src/cmd-ts/oneOf.ts
+++ /dev/null
@@ -1,16 +0,0 @@
-import { Type } from "cmd-ts";
-import { inspect } from "util";
-
-export function oneOf(literals: readonly T[], case_sensitive: boolean = false): Type {
- const examples = literals.map((x) => inspect(x)).join(", ");
- return {
- async from(str) {
- const value = literals.find((x) => (case_sensitive ? x === str : x.toLowerCase() === str.toLowerCase()));
- if (!value) {
- throw new Error(`Invalid value '${str}'. Expected one of: ${examples}`);
- }
- return value;
- },
- description: `One of ${examples}`,
- };
-}
diff --git a/packages/utils/src/config/index.ts b/packages/utils/src/config/index.ts
deleted file mode 100644
index 9f095d2..0000000
--- a/packages/utils/src/config/index.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { readFile, writeFile } from "fs/promises";
-import { homedir } from "../paths";
-import { join } from "path";
-import { parse, stringify } from "smol-toml";
-import { createSignal } from "@solid-cli/reactivity";
-
-export const PossibleFields = ["lang"] as const;
-
-const defaultConfig = {
- lang: Intl.DateTimeFormat().resolvedOptions().locale.split("-")[0],
-} as Record;
-
-type Field = (typeof PossibleFields)[number];
-
-const configPath: string = join(homedir(), "/solid-cli.config.toml");
-
-export const [config, setConfig] = createSignal(defaultConfig);
-
-export const readConfig = async () => {
- try {
- const file = await readFile(configPath, "utf-8");
- setConfig(parse(file));
- } catch {
- await writeConfig();
- }
-};
-
-export const writeConfig = async () => {
- await writeFile(configPath, stringify(config()));
-};
-
-export const setField = async (field: Field, value: any) => {
- if (!(field in defaultConfig)) {
- throw new Error(`Field ${field} does not exist`);
- }
- setConfig((prev) => ({ ...prev, [field]: value }));
- await writeConfig();
-};
-
-export const getField = (field: Field) => {
- if (!config()[field] && defaultConfig[field]) setField(field, defaultConfig[field]);
- return config()[field];
-};
diff --git a/packages/utils/src/fs/index.ts b/packages/utils/src/fs/index.ts
index 8f992b3..2f064d0 100644
--- a/packages/utils/src/fs/index.ts
+++ b/packages/utils/src/fs/index.ts
@@ -1,21 +1,24 @@
-import { readFile as readFile1 } from "fs/promises";
-import { queueUpdate, readQueuedFile, unqueueUpdate } from "../updates";
-export const writeFile = (path: string, data: string, checked: boolean = false) => {
- // First, unqueue all previous updates to this file
- unqueueUpdate(path, "file");
- queueUpdate({ type: "file", name: path, contents: data, checked });
-};
-export const readFile = async (path: string) => {
- const queued = readQueuedFile(path);
- if (queued) return queued.contents;
- return await readFile1(path);
-};
+import { readFile, writeFile } from "fs/promises";
+// import { queueUpdate, readQueuedFile, unqueueUpdate } from "../updates";
+// export const writeFile = (path: string, data: string, checked: boolean = false) => {
+// // First, unqueue all previous updates to this file
+// unqueueUpdate(path, "file");
+// queueUpdate({ type: "file", name: path, contents: data, checked });
+// };
+// export const readFile = async (path: string) => {
+// const queued = readQueuedFile(path);
+// if (queued) return queued.contents;
+// return await readFile1(path);
+// };
export const readFileToString = async (path: string) => {
return (await readFile(path)).toString();
};
+// export const writeChecked = async (path: string, contents: string) => {
+// unqueueUpdate(path, "file");
+// queueUpdate({ type: "file", name: path, contents, checked: true });
+// };
export const writeChecked = async (path: string, contents: string) => {
- unqueueUpdate(path, "file");
- queueUpdate({ type: "file", name: path, contents, checked: true });
+ await writeFile(path, contents);
};
export const insertAtBeginning = async (path: string, text: string) => {
const contents = await readFileToString(path);
diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts
index 1310c11..b8f0dc1 100644
--- a/packages/utils/src/index.ts
+++ b/packages/utils/src/index.ts
@@ -1,5 +1,2 @@
-export * from "./translations";
-export * from "./config";
export * from "./start";
export * from "./open";
-export * from "./cmd-ts";
diff --git a/packages/utils/src/open/index.ts b/packages/utils/src/open/index.ts
index 68ce0da..b946650 100644
--- a/packages/utils/src/open/index.ts
+++ b/packages/utils/src/open/index.ts
@@ -1,5 +1,4 @@
// Taken verbatim from https://github.com/withastro/astro/blob/main/packages/astro/src/cli/docs/open.ts
-import type { ExecaChildProcess } from "execa";
import { execa } from "execa";
/**
@@ -27,7 +26,7 @@ const getPlatformSpecificCommand = (): [string] | [string, string[]] => {
}
};
-export async function openInBrowser(url: string): Promise {
+export async function openInBrowser(url: string) {
const [command, args = []] = getPlatformSpecificCommand();
return execa(command, [...args, encodeURI(url)]);
}
diff --git a/packages/utils/src/package-manager/index.ts b/packages/utils/src/package-manager/index.ts
index a1720e5..d7c6230 100644
--- a/packages/utils/src/package-manager/index.ts
+++ b/packages/utils/src/package-manager/index.ts
@@ -40,6 +40,15 @@ export const detectPackageManager = (): PackageManager => {
return `task ${s}`;
},
};
+ case userAgent.startsWith("nub"):
+ return {
+ name: "nub",
+ runner: "nubx",
+ installCommand: "add",
+ runScriptCommand(s) {
+ return `run ${s}`;
+ },
+ };
default:
return {
name: "npm",
diff --git a/packages/utils/src/primitives/index.ts b/packages/utils/src/primitives/index.ts
deleted file mode 100644
index 571269a..0000000
--- a/packages/utils/src/primitives/index.ts
+++ /dev/null
@@ -1,62 +0,0 @@
-import { tmpdir } from "../paths";
-import type { Option } from "../util-types";
-import { createSignal } from "@solid-cli/reactivity";
-import { readFile, writeFile } from "fs/promises";
-export const [primitives, setPrimitives] = createSignal