V2 csa only updates (#1859)

This commit is contained in:
Nik
2023-08-16 02:24:50 +10:00
committed by GitHub
parent 2bad89ea9c
commit c88f85ded9
39 changed files with 1233 additions and 616 deletions

View File

@@ -0,0 +1,10 @@
---
"create-skeleton-app": patch
---
CSA updates for V2
- Install vite-plugin-tailwind-purgecss to enable purging of unused component CSS
- mdsvex is an optional install
- No longer installs packages by default
- Templates can now specify additional packages to be installed
- Bug fixes and improvements all over

3
.gitignore vendored
View File

@@ -11,6 +11,8 @@ coverage
src/lib/tailwind/generated
*.tgz
vite.config.ts.timestamp-**.mjs
.vscode/launch.json
repos.json
/packages/*
!/packages/create-skeleton-app
@@ -18,3 +20,4 @@ vite.config.ts.timestamp-**.mjs
!/packages/plugin
/sites/*
!/sites/skeleton.dev
/templates/*

View File

@@ -31,6 +31,7 @@
"Codepen",
"colindex",
"colormatrix",
"columnify",
"combobox",
"Consolas",
"contenteditable",
@@ -77,6 +78,7 @@
"lightswitches",
"listbox",
"maiores",
"mdsvex",
"Menlo",
"minima",
"mininal",

View File

@@ -6,6 +6,9 @@ module.exports = {
sourceType: 'module',
ecmaVersion: 2020,
},
rules: {
'no-useless-escape': 'off',
},
env: {
browser: false,
es2017: true,

View File

@@ -2,4 +2,4 @@
node_modules
dist
package
.turbo
test

View File

@@ -1,18 +1,18 @@
# create-skeleton-app
This is a special multi-repo version of the site created by CSA.
This is a special multi-repo version of the app created by CSA.
Differences from a normal CSA site:
Differences from a normal CSA app:
- Vite alias to the @skeletonlabs/skeleton project
- Removed @skeletonlabs/skeleton from package.json
- @skeletonlabs/skeleton is a workspace link in package.json
- Added install script for the site that will swap dependencies from workspace links to what is defined in deployConfig of package.json
- Added Vercel deploy command to package.json
At this point it only supports deploying to Vercel.
## Reminder
Since you have just created this site with `pnpm site <foo>`, make sure to `git init`, `git add .`, `gh repo create` and run `pnpm dev` at least once so that the alias gets setup in .svelte-kit
Since you have just created this site with `pnpm csa <foo>`, make sure to `git init`, `git add .`, `gh repo create` and run `pnpm dev`.
## Deploying a site to Vercel
@@ -22,5 +22,3 @@ Repos that are not part of the main Skeleton repo will not work independently of
# ensure you have the vercel cli tool
pnpm i -g vercel
```
Two scripts have been added to package.json

View File

@@ -1,6 +1,6 @@
{
"name": "create-skeleton-app",
"version": "0.0.44",
"version": "0.0.46-beta.1",
"description": "Use this CLI app to setup a new Skeleton application in a new SvelteKit project.",
"keywords": [
"skeleton",
@@ -21,34 +21,36 @@
"bin": "./src/index.js",
"files": [
"src/**",
"templates/**"
"templates/**",
"fonts/**"
],
"engines": {
"node": ">=14.16"
},
"scripts": {
"dev": "node src/index.js",
"prep": "node scripts/prepare-templates.mjs && pnpm format",
"dev": "node src/index.js -p=../../../atest --skeletontemplatedir=../../templates/",
"long": "node src/index.js --types=typescript --prettier --eslint --playwright=false --vitest=false --codeblocks=true --popups=true --typography=false --forms=false -t crimson --skeletontemplate=welcome",
"pub:beta": "npm publish --tag beta",
"pub:next": "npm publish --tag next",
"pub:release": "npm publish",
"release": "npm publish",
"pub:beta": "pnpm prep && npm publish --tag beta",
"pub:next": "pnpm prep && npm publish --tag next",
"pub:release": "pnpm prep && npm publish",
"lint": "prettier --ignore-path .prettierignore --check --plugin-search-dir=. . && eslint --fix --ignore-path .gitignore .",
"format": "prettier --plugin-search-dir . --write ."
},
"dependencies": {
"@clack/prompts": "^0.6.3",
"create-svelte": "^4.2.0",
"columnify": "^1.6.0",
"create-svelte": "^5.0.5",
"fast-glob": "^3.3.1",
"fs-extra": "^11.1.1",
"got": "^12.6.0",
"got": "^13.0.0",
"kleur": "^4.1.5",
"mri": "^1.2.0",
"semver": "^7.5.1"
"semver": "^7.5.4"
},
"devDependencies": {
"eslint": "^8.41.0",
"eslint-config-prettier": "^8.8.0",
"prettier": "^2.8.8",
"svelte": "^3.59.1"
"archiver": "^5.3.1",
"eslint": "^8.46.0",
"eslint-config-prettier": "^8.10.0"
}
}

View File

@@ -1,4 +1,4 @@
lockfileVersion: '6.1'
lockfileVersion: '6.0'
settings:
autoInstallPeers: true
@@ -8,15 +8,21 @@ dependencies:
'@clack/prompts':
specifier: ^0.6.3
version: 0.6.3
columnify:
specifier: ^1.6.0
version: 1.6.0
create-svelte:
specifier: ^4.2.0
version: 4.2.0
specifier: ^5.0.5
version: 5.0.5
fast-glob:
specifier: ^3.3.1
version: 3.3.1
fs-extra:
specifier: ^11.1.1
version: 11.1.1
got:
specifier: ^12.6.0
version: 12.6.0
specifier: ^13.0.0
version: 13.0.0
kleur:
specifier: ^4.1.5
version: 4.1.5
@@ -24,27 +30,29 @@ dependencies:
specifier: ^1.2.0
version: 1.2.0
semver:
specifier: ^7.5.1
version: 7.5.1
specifier: ^7.5.4
version: 7.5.4
devDependencies:
archiver:
specifier: ^5.3.1
version: 5.3.1
eslint:
specifier: ^8.41.0
version: 8.41.0
specifier: ^8.46.0
version: 8.46.0
eslint-config-prettier:
specifier: ^8.8.0
version: 8.8.0(eslint@8.41.0)
prettier:
specifier: ^2.8.8
version: 2.8.8
svelte:
specifier: ^3.59.1
version: 3.59.1
specifier: ^8.10.0
version: 8.10.0(eslint@8.46.0)
packages:
/@clack/core@0.3.2:
resolution: {integrity: sha512-FZnsNynwGDIDktx6PEZK1EuCkFpY4ldEX6VYvfl0dqeoLPb9Jpw1xoUXaVcGR8ExmYNm1w2vdGdJkEUYD/2pqg==}
/@aashutoshrathi/word-wrap@1.2.6:
resolution: {integrity: sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==}
engines: {node: '>=0.10.0'}
dev: true
/@clack/core@0.3.3:
resolution: {integrity: sha512-5ZGyb75BUBjlll6eOa1m/IZBxwk91dooBWhPSL67sWcLS0zt9SnswRL0l26TVdBhb0wnWORRxUn//uH6n4z7+A==}
dependencies:
picocolors: 1.0.0
sisteransi: 1.0.5
@@ -53,35 +61,45 @@ packages:
/@clack/prompts@0.6.3:
resolution: {integrity: sha512-AM+kFmAHawpUQv2q9+mcB6jLKxXGjgu/r2EQjEwujgpCdzrST6BJqYw00GRn56/L/Izw5U7ImoLmy00X/r80Pw==}
dependencies:
'@clack/core': 0.3.2
'@clack/core': 0.3.3
picocolors: 1.0.0
sisteransi: 1.0.5
dev: false
bundledDependencies:
- is-unicode-supported
/@eslint-community/eslint-utils@4.4.0(eslint@8.41.0):
/@clack/prompts@0.7.0:
resolution: {integrity: sha512-0MhX9/B4iL6Re04jPrttDm+BsP8y6mS7byuv0BvXgdXhbV5PdlsHt55dvNsuBCPZ7xq1oTAOOuotR9NFbQyMSA==}
dependencies:
'@clack/core': 0.3.3
picocolors: 1.0.0
sisteransi: 1.0.5
dev: false
bundledDependencies:
- is-unicode-supported
/@eslint-community/eslint-utils@4.4.0(eslint@8.46.0):
resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^6.0.0 || ^7.0.0 || >=8.0.0
dependencies:
eslint: 8.41.0
eslint-visitor-keys: 3.4.1
eslint: 8.46.0
eslint-visitor-keys: 3.4.2
dev: true
/@eslint-community/regexpp@4.5.1:
resolution: {integrity: sha512-Z5ba73P98O1KUYCCJTUeVpja9RcGoMdncZ6T49FCUl2lN38JtCJ+3WgIDBv0AuY4WChU5PmtJmOCTlN6FZTFKQ==}
/@eslint-community/regexpp@4.6.2:
resolution: {integrity: sha512-pPTNuaAG3QMH+buKyBIGJs3g/S5y0caxw0ygM3YyE6yJFySwiGGSzA+mM3KJ8QQvzeLh3blwgSonkFjgQdxzMw==}
engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0}
dev: true
/@eslint/eslintrc@2.0.3:
resolution: {integrity: sha512-+5gy6OQfk+xx3q0d6jGZZC3f3KzAkXc/IanVxd1is/VIIziRqqt3ongQz0FiTUXqTk0c7aDB3OaFuKnuSoJicQ==}
/@eslint/eslintrc@2.1.1:
resolution: {integrity: sha512-9t7ZA7NGGK8ckelF0PQCfcxIUzs1Md5rrO6U/c+FIQNanea5UZC0wqKXH4vHBccmu4ZJgZ2idtPeW7+Q2npOEA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
ajv: 6.12.6
debug: 4.3.4
espree: 9.5.2
espree: 9.6.1
globals: 13.20.0
ignore: 5.2.4
import-fresh: 3.3.0
@@ -92,13 +110,13 @@ packages:
- supports-color
dev: true
/@eslint/js@8.41.0:
resolution: {integrity: sha512-LxcyMGxwmTh2lY9FwHPGWOHmYFCZvbrFCBZL4FzSSsxsRPuhrYUg/49/0KDfW8tnIEaEHtfmn6+NPN+1DqaNmA==}
/@eslint/js@8.46.0:
resolution: {integrity: sha512-a8TLtmPi8xzPkCbp/OGFUo5yhRkHM2Ko9kOWP4znJr0WAhWyThaw3PnwX4vOTWOAMsV2uRt32PPDcEz63esSaA==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@humanwhocodes/config-array@0.11.8:
resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==}
/@humanwhocodes/config-array@0.11.10:
resolution: {integrity: sha512-KVVjQmNUepDVGXNuoRRdmmEjruj0KfiGSbS8LVc12LMsWDQzRXJ0qdhN8L8uUigKpfEHRhlaQFY0ib1tnUbNeQ==}
engines: {node: '>=10.10.0'}
dependencies:
'@humanwhocodes/object-schema': 1.2.1
@@ -123,12 +141,10 @@ packages:
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==}
@@ -136,10 +152,9 @@ packages:
dependencies:
'@nodelib/fs.scandir': 2.1.5
fastq: 1.15.0
dev: true
/@sindresorhus/is@5.3.0:
resolution: {integrity: sha512-CX6t4SYQ37lzxicAqsBtxA3OseeoVrh9cSJ5PFYam0GksYlupRfy1A+Q4aYD3zvcfECLc0zO2u+ZnR2UYKvCrw==}
/@sindresorhus/is@5.6.0:
resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==}
engines: {node: '>=14.16'}
dev: false
@@ -154,16 +169,16 @@ packages:
resolution: {integrity: sha512-SZs7ekbP8CN0txVG2xVRH6EgKmEm31BOxA07vkFaETzZz1xh+cbt8BcI0slpymvwhx5dlFnQG2rTlPVQn+iRPQ==}
dev: false
/acorn-jsx@5.3.2(acorn@8.8.2):
/acorn-jsx@5.3.2(acorn@8.10.0):
resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==}
peerDependencies:
acorn: ^6.0.0 || ^7.0.0 || ^8.0.0
dependencies:
acorn: 8.8.2
acorn: 8.10.0
dev: true
/acorn@8.8.2:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
/acorn@8.10.0:
resolution: {integrity: sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: true
@@ -180,7 +195,6 @@ packages:
/ansi-regex@5.0.1:
resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==}
engines: {node: '>=8'}
dev: true
/ansi-styles@4.3.0:
resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==}
@@ -189,14 +203,59 @@ packages:
color-convert: 2.0.1
dev: true
/archiver-utils@2.1.0:
resolution: {integrity: sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==}
engines: {node: '>= 6'}
dependencies:
glob: 7.2.3
graceful-fs: 4.2.11
lazystream: 1.0.1
lodash.defaults: 4.2.0
lodash.difference: 4.5.0
lodash.flatten: 4.4.0
lodash.isplainobject: 4.0.6
lodash.union: 4.6.0
normalize-path: 3.0.0
readable-stream: 2.3.8
dev: true
/archiver@5.3.1:
resolution: {integrity: sha512-8KyabkmbYrH+9ibcTScQ1xCJC/CGcugdVIwB+53f5sZziXgwUh3iXlAlANMxcZyDEfTHMe6+Z5FofV8nopXP7w==}
engines: {node: '>= 10'}
dependencies:
archiver-utils: 2.1.0
async: 3.2.4
buffer-crc32: 0.2.13
readable-stream: 3.6.2
readdir-glob: 1.1.3
tar-stream: 2.2.0
zip-stream: 4.1.0
dev: true
/argparse@2.0.1:
resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==}
dev: true
/async@3.2.4:
resolution: {integrity: sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==}
dev: true
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base64-js@1.5.1:
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
dev: true
/bl@4.1.0:
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
dependencies:
buffer: 5.7.1
inherits: 2.0.4
readable-stream: 3.6.2
dev: true
/brace-expansion@1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
@@ -204,19 +263,43 @@ packages:
concat-map: 0.0.1
dev: true
/brace-expansion@2.0.1:
resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==}
dependencies:
balanced-match: 1.0.2
dev: true
/braces@3.0.2:
resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==}
engines: {node: '>=8'}
dependencies:
fill-range: 7.0.1
dev: false
/buffer-crc32@0.2.13:
resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==}
dev: true
/buffer@5.7.1:
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
dependencies:
base64-js: 1.5.1
ieee754: 1.2.1
dev: true
/cacheable-lookup@7.0.0:
resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==}
engines: {node: '>=14.16'}
dev: false
/cacheable-request@10.2.10:
resolution: {integrity: sha512-v6WB+Epm/qO4Hdlio/sfUn69r5Shgh39SsE9DSd4bIezP0mblOlObI+I0kUEM7J0JFc+I7pSeMeYaOYtX1N/VQ==}
/cacheable-request@10.2.13:
resolution: {integrity: sha512-3SD4rrMu1msNGEtNSt8Od6enwdo//U9s4ykmXfA2TD58kcLkCobtCDiby7kNyj7a/Q7lz/mAesAFI54rTdnvBA==}
engines: {node: '>=14.16'}
dependencies:
'@types/http-cache-semantics': 4.0.1
get-stream: 6.0.1
http-cache-semantics: 4.1.1
keyv: 4.5.2
keyv: 4.5.3
mimic-response: 4.0.0
normalize-url: 8.0.0
responselike: 3.0.0
@@ -235,6 +318,11 @@ packages:
supports-color: 7.2.0
dev: true
/clone@1.0.4:
resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==}
engines: {node: '>=0.8'}
dev: false
/color-convert@2.0.1:
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
engines: {node: '>=7.0.0'}
@@ -246,15 +334,51 @@ packages:
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
dev: true
/columnify@1.6.0:
resolution: {integrity: sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==}
engines: {node: '>=8.0.0'}
dependencies:
strip-ansi: 6.0.1
wcwidth: 1.0.1
dev: false
/compress-commons@4.1.1:
resolution: {integrity: sha512-QLdDLCKNV2dtoTorqgxngQCMA+gWXkM/Nwu7FpeBhk/RdkzimqC3jueb/FDmaZeXh+uby1jkBqE3xArsLBE5wQ==}
engines: {node: '>= 10'}
dependencies:
buffer-crc32: 0.2.13
crc32-stream: 4.0.2
normalize-path: 3.0.0
readable-stream: 3.6.2
dev: true
/concat-map@0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
/create-svelte@4.2.0:
resolution: {integrity: sha512-jngi/IOM4NIGL4A61fN6diilrxcNe1iH3pziK6QmsL95h3B2p8gFyc4xZ7Oi9UbxO74o/kivrd3cIwqefWd0bA==}
/core-util-is@1.0.3:
resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==}
dev: true
/crc-32@1.2.2:
resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==}
engines: {node: '>=0.8'}
hasBin: true
dev: true
/crc32-stream@4.0.2:
resolution: {integrity: sha512-DxFZ/Hk473b/muq1VJ///PMNLj0ZMnzye9thBpmjpJKCc5eMgB95aK8zCGrGfQ90cWo561Te6HK9D+j4KPdM6w==}
engines: {node: '>= 10'}
dependencies:
crc-32: 1.2.2
readable-stream: 3.6.2
dev: true
/create-svelte@5.0.5:
resolution: {integrity: sha512-+Pki3j1WjBy4FGxaoz5mrYNYDTFmVX6qLf7MLBEruPFCV1xVQAiUZozvABJneWQojjqTJOriksrDDdoiwTGUAg==}
hasBin: true
dependencies:
'@clack/prompts': 0.6.3
'@clack/prompts': 0.7.0
kleur: 4.1.5
dev: false
@@ -290,6 +414,12 @@ packages:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: true
/defaults@1.0.4:
resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==}
dependencies:
clone: 1.0.4
dev: false
/defer-to-connect@2.0.1:
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
engines: {node: '>=10'}
@@ -302,43 +432,49 @@ packages:
esutils: 2.0.3
dev: true
/end-of-stream@1.4.4:
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
dependencies:
once: 1.4.0
dev: true
/escape-string-regexp@4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: true
/eslint-config-prettier@8.8.0(eslint@8.41.0):
resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==}
/eslint-config-prettier@8.10.0(eslint@8.46.0):
resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==}
hasBin: true
peerDependencies:
eslint: '>=7.0.0'
dependencies:
eslint: 8.41.0
eslint: 8.46.0
dev: true
/eslint-scope@7.2.0:
resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==}
/eslint-scope@7.2.2:
resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
esrecurse: 4.3.0
estraverse: 5.3.0
dev: true
/eslint-visitor-keys@3.4.1:
resolution: {integrity: sha512-pZnmmLwYzf+kWaM/Qgrvpen51upAktaaiI01nsJD/Yr3lMOdNtq0cxkrrg16w64VtisN6okbs7Q8AfGqj4c9fA==}
/eslint-visitor-keys@3.4.2:
resolution: {integrity: sha512-8drBzUEyZ2llkpCA67iYrgEssKDUu68V8ChqqOfFupIaG/LCVPUT+CoGJpT77zJprs4T/W7p07LP7zAIMuweVw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/eslint@8.41.0:
resolution: {integrity: sha512-WQDQpzGBOP5IrXPo4Hc0814r4/v2rrIsB0rhT7jtunIalgg6gYXWhRMOejVO8yH21T/FGaxjmFjBMNqcIlmH1Q==}
/eslint@8.46.0:
resolution: {integrity: sha512-cIO74PvbW0qU8e0mIvk5IV3ToWdCq5FYG6gWPHHkx6gNdjlbAYvtfHmlCMXxjcoVaIdwy/IAt3+mDkZkfvb2Dg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
hasBin: true
dependencies:
'@eslint-community/eslint-utils': 4.4.0(eslint@8.41.0)
'@eslint-community/regexpp': 4.5.1
'@eslint/eslintrc': 2.0.3
'@eslint/js': 8.41.0
'@humanwhocodes/config-array': 0.11.8
'@eslint-community/eslint-utils': 4.4.0(eslint@8.46.0)
'@eslint-community/regexpp': 4.6.2
'@eslint/eslintrc': 2.1.1
'@eslint/js': 8.46.0
'@humanwhocodes/config-array': 0.11.10
'@humanwhocodes/module-importer': 1.0.1
'@nodelib/fs.walk': 1.2.8
ajv: 6.12.6
@@ -347,9 +483,9 @@ packages:
debug: 4.3.4
doctrine: 3.0.0
escape-string-regexp: 4.0.0
eslint-scope: 7.2.0
eslint-visitor-keys: 3.4.1
espree: 9.5.2
eslint-scope: 7.2.2
eslint-visitor-keys: 3.4.2
espree: 9.6.1
esquery: 1.5.0
esutils: 2.0.3
fast-deep-equal: 3.1.3
@@ -359,7 +495,6 @@ packages:
globals: 13.20.0
graphemer: 1.4.0
ignore: 5.2.4
import-fresh: 3.3.0
imurmurhash: 0.1.4
is-glob: 4.0.3
is-path-inside: 3.0.3
@@ -369,21 +504,20 @@ packages:
lodash.merge: 4.6.2
minimatch: 3.1.2
natural-compare: 1.4.0
optionator: 0.9.1
optionator: 0.9.3
strip-ansi: 6.0.1
strip-json-comments: 3.1.1
text-table: 0.2.0
transitivePeerDependencies:
- supports-color
dev: true
/espree@9.5.2:
resolution: {integrity: sha512-7OASN1Wma5fum5SrNhFMAMJxOUAbhyfQ8dQ//PJaJbNw0URTPWqIghHWt1MmAANKhHZIYOHruW4Kw4ruUWOdGw==}
/espree@9.6.1:
resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dependencies:
acorn: 8.8.2
acorn-jsx: 5.3.2(acorn@8.8.2)
eslint-visitor-keys: 3.4.1
acorn: 8.10.0
acorn-jsx: 5.3.2(acorn@8.10.0)
eslint-visitor-keys: 3.4.2
dev: true
/esquery@1.5.0:
@@ -414,6 +548,17 @@ packages:
resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==}
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: false
/fast-json-stable-stringify@2.1.0:
resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==}
dev: true
@@ -426,7 +571,6 @@ packages:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
reusify: 1.0.4
dev: true
/file-entry-cache@6.0.1:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
@@ -435,6 +579,13 @@ packages:
flat-cache: 3.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: false
/find-up@5.0.0:
resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==}
engines: {node: '>=10'}
@@ -460,6 +611,10 @@ packages:
engines: {node: '>= 14.17'}
dev: false
/fs-constants@1.0.0:
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
dev: true
/fs-extra@11.1.1:
resolution: {integrity: sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==}
engines: {node: '>=14.14'}
@@ -478,6 +633,13 @@ packages:
engines: {node: '>=10'}
dev: false
/glob-parent@5.1.2:
resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==}
engines: {node: '>= 6'}
dependencies:
is-glob: 4.0.3
dev: false
/glob-parent@6.0.2:
resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==}
engines: {node: '>=10.13.0'}
@@ -503,14 +665,14 @@ packages:
type-fest: 0.20.2
dev: true
/got@12.6.0:
resolution: {integrity: sha512-WTcaQ963xV97MN3x0/CbAriXFZcXCfgxVp91I+Ze6pawQOa7SgzwSx2zIJJsX+kTajMnVs0xcFD1TxZKFqhdnQ==}
engines: {node: '>=14.16'}
/got@13.0.0:
resolution: {integrity: sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==}
engines: {node: '>=16'}
dependencies:
'@sindresorhus/is': 5.3.0
'@sindresorhus/is': 5.6.0
'@szmarczak/http-timer': 5.0.1
cacheable-lookup: 7.0.0
cacheable-request: 10.2.10
cacheable-request: 10.2.13
decompress-response: 6.0.0
form-data-encoder: 2.1.4
get-stream: 6.0.1
@@ -522,7 +684,6 @@ packages:
/graceful-fs@4.2.11:
resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==}
dev: false
/graphemer@1.4.0:
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
@@ -545,6 +706,10 @@ packages:
resolve-alpn: 1.2.1
dev: false
/ieee754@1.2.1:
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
dev: true
/ignore@5.2.4:
resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==}
engines: {node: '>= 4'}
@@ -577,20 +742,27 @@ packages:
/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: false
/is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'}
dev: true
/isarray@1.0.0:
resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==}
dev: true
/isexe@2.0.0:
resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==}
dev: true
@@ -622,8 +794,8 @@ packages:
graceful-fs: 4.2.11
dev: false
/keyv@4.5.2:
resolution: {integrity: sha512-5MHbFaKn8cNSmVW7BYnijeAVlE4cYA/SVkifVgrh7yotnfhKmjuXpDKjrABLnT0SfHWV21P8ow07OGfRrNDg8g==}
/keyv@4.5.3:
resolution: {integrity: sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==}
dependencies:
json-buffer: 3.0.1
dev: false
@@ -633,6 +805,13 @@ packages:
engines: {node: '>=6'}
dev: false
/lazystream@1.0.1:
resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==}
engines: {node: '>= 0.6.3'}
dependencies:
readable-stream: 2.3.8
dev: true
/levn@0.4.1:
resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==}
engines: {node: '>= 0.8.0'}
@@ -648,10 +827,30 @@ packages:
p-locate: 5.0.0
dev: true
/lodash.defaults@4.2.0:
resolution: {integrity: sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==}
dev: true
/lodash.difference@4.5.0:
resolution: {integrity: sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==}
dev: true
/lodash.flatten@4.4.0:
resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==}
dev: true
/lodash.isplainobject@4.0.6:
resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==}
dev: true
/lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
dev: true
/lodash.union@4.6.0:
resolution: {integrity: sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==}
dev: true
/lowercase-keys@3.0.0:
resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==}
engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0}
@@ -664,6 +863,19 @@ packages:
yallist: 4.0.0
dev: false
/merge2@1.4.1:
resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==}
engines: {node: '>= 8'}
dev: false
/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: false
/mimic-response@3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
engines: {node: '>=10'}
@@ -680,6 +892,13 @@ packages:
brace-expansion: 1.1.11
dev: true
/minimatch@5.1.6:
resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==}
engines: {node: '>=10'}
dependencies:
brace-expansion: 2.0.1
dev: true
/mri@1.2.0:
resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==}
engines: {node: '>=4'}
@@ -693,6 +912,11 @@ packages:
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
dev: true
/normalize-path@3.0.0:
resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==}
engines: {node: '>=0.10.0'}
dev: true
/normalize-url@8.0.0:
resolution: {integrity: sha512-uVFpKhj5MheNBJRTiMZ9pE/7hD1QTeEvugSJW/OmLzAp78PB5O6adfMNTvmfKhXBkvCzC+rqifWcVYpGFwTjnw==}
engines: {node: '>=14.16'}
@@ -704,16 +928,16 @@ packages:
wrappy: 1.0.2
dev: true
/optionator@0.9.1:
resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==}
/optionator@0.9.3:
resolution: {integrity: sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==}
engines: {node: '>= 0.8.0'}
dependencies:
'@aashutoshrathi/word-wrap': 1.2.6
deep-is: 0.1.4
fast-levenshtein: 2.0.6
levn: 0.4.1
prelude-ls: 1.2.1
type-check: 0.4.0
word-wrap: 1.2.3
dev: true
/p-cancelable@3.0.0:
@@ -761,15 +985,18 @@ packages:
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
dev: false
/picomatch@2.3.1:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
dev: false
/prelude-ls@1.2.1:
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
engines: {node: '>= 0.8.0'}
dev: true
/prettier@2.8.8:
resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==}
engines: {node: '>=10.13.0'}
hasBin: true
/process-nextick-args@2.0.1:
resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==}
dev: true
/punycode@2.3.0:
@@ -779,13 +1006,39 @@ packages:
/queue-microtask@1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
/quick-lru@5.1.1:
resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==}
engines: {node: '>=10'}
dev: false
/readable-stream@2.3.8:
resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==}
dependencies:
core-util-is: 1.0.3
inherits: 2.0.4
isarray: 1.0.0
process-nextick-args: 2.0.1
safe-buffer: 5.1.2
string_decoder: 1.1.1
util-deprecate: 1.0.2
dev: true
/readable-stream@3.6.2:
resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==}
engines: {node: '>= 6'}
dependencies:
inherits: 2.0.4
string_decoder: 1.3.0
util-deprecate: 1.0.2
dev: true
/readdir-glob@1.1.3:
resolution: {integrity: sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==}
dependencies:
minimatch: 5.1.6
dev: true
/resolve-alpn@1.2.1:
resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==}
dev: false
@@ -805,7 +1058,6 @@ packages:
/reusify@1.0.4:
resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==}
engines: {iojs: '>=1.0.0', node: '>=0.10.0'}
dev: true
/rimraf@3.0.2:
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
@@ -818,10 +1070,17 @@ packages:
resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==}
dependencies:
queue-microtask: 1.2.3
/safe-buffer@5.1.2:
resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==}
dev: true
/semver@7.5.1:
resolution: {integrity: sha512-Wvss5ivl8TMRZXXESstBA4uR5iXgEN/VC5/sOcuXdVLzcdkz4HWetIoRfG5gb5X+ij/G9rw9YoGn3QoQ8OCSpw==}
/safe-buffer@5.2.1:
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
dev: true
/semver@7.5.4:
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
engines: {node: '>=10'}
hasBin: true
dependencies:
@@ -844,12 +1103,23 @@ packages:
resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==}
dev: false
/string_decoder@1.1.1:
resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==}
dependencies:
safe-buffer: 5.1.2
dev: true
/string_decoder@1.3.0:
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
dependencies:
safe-buffer: 5.2.1
dev: true
/strip-ansi@6.0.1:
resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==}
engines: {node: '>=8'}
dependencies:
ansi-regex: 5.0.1
dev: true
/strip-json-comments@3.1.1:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
@@ -863,15 +1133,28 @@ packages:
has-flag: 4.0.0
dev: true
/svelte@3.59.1:
resolution: {integrity: sha512-pKj8fEBmqf6mq3/NfrB9SLtcJcUvjYSWyePlfCqN9gujLB25RitWK8PvFzlwim6hD/We35KbPlRteuA6rnPGcQ==}
engines: {node: '>= 8'}
/tar-stream@2.2.0:
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
engines: {node: '>=6'}
dependencies:
bl: 4.1.0
end-of-stream: 1.4.4
fs-constants: 1.0.0
inherits: 2.0.4
readable-stream: 3.6.2
dev: true
/text-table@0.2.0:
resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==}
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: false
/type-check@0.4.0:
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
engines: {node: '>= 0.8.0'}
@@ -895,6 +1178,16 @@ packages:
punycode: 2.3.0
dev: true
/util-deprecate@1.0.2:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: true
/wcwidth@1.0.1:
resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==}
dependencies:
defaults: 1.0.4
dev: false
/which@2.0.2:
resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==}
engines: {node: '>= 8'}
@@ -903,11 +1196,6 @@ packages:
isexe: 2.0.0
dev: true
/word-wrap@1.2.3:
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
engines: {node: '>=0.10.0'}
dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
@@ -920,3 +1208,12 @@ packages:
resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==}
engines: {node: '>=10'}
dev: true
/zip-stream@4.1.0:
resolution: {integrity: sha512-zshzwQW7gG7hjpBlgeQP9RuyPGNxvJdzR8SUM3QhxCnLjWN2E7j3dOvpeDcQoETfHx0urRS7EtmVToql7YpU4A==}
engines: {node: '>= 10'}
dependencies:
archiver-utils: 2.1.0
compress-commons: 4.1.1
readable-stream: 3.6.2
dev: true

View File

@@ -0,0 +1,49 @@
// copy the src, static, csa-meta.json directories and files from templates/* directory to the local template directory
import fs from 'fs';
import { join } from 'path';
import { dist } from '../src/utils.js';
import fg from 'fast-glob';
import archiver from 'archiver';
async function copyTemplates() {
const basePath = dist('../../../templates');
const metaFiles = fg.sync(['**/csa-meta.json'], { cwd: basePath, deep: 2 });
metaFiles.forEach(async (metaFile) => {
const csaMeta = JSON.parse(fs.readFileSync(join(basePath, metaFile), 'utf8'));
if (!csaMeta.enabled) return;
if (csaMeta.type == 'premium') {
//zip up the template and put it in the dist directory
zipFolder(join(basePath, metaFile, '..'), join(basePath, metaFile.split('/')[0] + '.zip'));
} else {
//copy the folders that are specified in the csa-meta.json
csaMeta?.foldersToCopy?.forEach((folder) => {
fs.cpSync(join(basePath, metaFile, '..', folder), join('templates', metaFile.split('/')[0], folder), {
recursive: true,
});
});
//copy the csa-meta.json file
fs.cpSync(join(basePath, metaFile), join('templates', metaFile));
// remove the fonts folder and font css from app.postcss that was required for testing
fs.rmSync(join('templates', metaFile.split('/')[0], 'static', 'fonts'), { recursive: true });
let appPostcss = fs.readFileSync(join('templates', metaFile.split('/')[0], 'src', 'app.postcss'), 'utf8');
appPostcss = appPostcss.replace(/\/\*[\s\S]*?\*\/[\s\S]*$/g, '');
fs.writeFileSync(join('templates', metaFile.split('/')[0], 'src', 'app.postcss'), appPostcss);
}
});
}
function zipFolder(sourceFolder, outputFile) {
const output = fs.createWriteStream(outputFile);
output.on('close', function () {
console.log('done writing: ' + archive.pointer() + ' total bytes');
});
const archive = archiver('zip');
archive.on('error', function (err) {
throw err;
});
archive.glob('**/*', { cwd: sourceFolder, ignore: ['**/node_modules/**', '**/.git/**'] });
archive.pipe(output);
archive.finalize();
}
copyTemplates();

View File

@@ -1,26 +1,25 @@
// Types
import { create } from 'create-svelte';
import fs from 'fs-extra';
import { readFileSync, writeFileSync, cpSync, appendFileSync, existsSync } from 'fs';
import got from 'got';
import { bold, cyan, red } from 'kleur/colors';
import { spawnSync } from 'node:child_process';
import path from 'path';
import process from 'process';
import { dist, mkdirp, removeFilesExceptSync, whichPMRuns } from './utils.js';
import * as url from 'url';
const __dirname = url.fileURLToPath(new URL('.', import.meta.url));
import { join, resolve } from 'path';
import { cwd, chdir } from 'process';
import { mkdirp, setNestedValue, checkIfDirSafeToInstall, iit } from './utils.js';
import { fileURLToPath } from 'url';
const __dirname = fileURLToPath(new URL('.', import.meta.url));
export const presetThemes = ['skeleton', 'modern', 'hamlindigo', 'rocket', 'sahara', 'gold-nouveau', 'vintage', 'seafoam', 'crimson'];
// NOTE: Any changes here must also be reflected in the --help output in utils.js and shortcut expansions in index.js.
// Probably a good idea to do a search on the values you are changing to catch any other areas they are used in
export class SkeletonOptions {
// svelte-create expects these options, do not change the names or values.
constructor() {
this.name = 'new-skel-app';
this.template = 'skeleton';
this.types = 'typescript';
this.prettier = true;
this.eslint = true;
// svelte-create expects these options, do not change the names or values.
this.name = 'skeleton-app'; // only used for the name field in the package.json
this.template = 'skeleton'; // 'default' | 'skeleton' | 'skeletonlib' has nothing to do with Skeleton
this.types = 'typescript'; //'typescript' | 'checkjs' | null;
this.prettier = false;
this.eslint = false;
this.playwright = false;
this.vitest = false;
@@ -32,112 +31,141 @@ export class SkeletonOptions {
this.forms = false;
this.typography = false;
this.codeblocks = false;
this.popups = true;
this.popups = false;
this.mdsvex = false;
this.inspector = false;
this.skeletontheme = 'skeleton';
this.skeletontemplate = 'bare';
this.packagemanager = 'pnpm';
this.packages = [];
this.skeletontheme = ['skeleton'];
this.skeletontemplate = 'skeleton-template-bare';
this.skeletontemplatedir = '../templates';
this.packagemanager = 'npm';
this.devDependencies = new Map([
['postcss', 'latest'],
['autoprefixer', 'latest'],
['tailwindcss', 'latest'],
['@skeletonlabs/skeleton', 'latest'],
]);
// props below are private to the Skeleton team
this.verbose = false;
this.monorepo = false;
this.packages = [];
this.skeletontemplatedir = '../templates';
this.workspace = '';
this.monorepo = false; // Adds additional config for installing into a pnpm monorepo
this.library = false; // allows forcing of a library install (could be forced by directly setting template to skeletonlib)
this.test = false; // adjusts tests to a common parent directory for monorepo testing, API only, set by testing scripts
this.meta = undefined; // holds the csa-meta.json data
}
set metaObject(value) {
this.meta = value;
if (this.meta.requiredFeatures) {
this.meta.requiredFeatures.forEach((val) => {
Object.assign(this, val);
});
}
}
}
export async function createSkeleton(opts) {
const startPath = process.cwd();
// When being run multiple times in a row, we need to make sure we return to this current directory
// and not the newly created projects subdir
const startPath = cwd();
// Hidden option to change the install type to be a Svelte-Kit library project
if (opts?.library) {
if (opts.library) {
opts.template = 'skeletonlib';
}
// We could have been called directly as an API, so we still need to check if the directory is safe to install into
checkIfDirSafeToInstall(opts.path);
//create-svelte will build the base install for us
// create-svelte will build the base install for us
await create(opts.path, opts);
process.chdir(opts.path);
// install packages
opts.packagemanager = whichPMRuns()?.name || 'npm';
// the order matters due to dependency resolution, because yarn
let packages = ['postcss', 'autoprefixer', 'tailwindcss', '@skeletonlabs/skeleton'];
// Extra packages for a monorepo install
if (opts?.monorepo) {
packages.push('@sveltejs/adapter-vercel');
packages.push('is-ci');
chdir(opts.path);
if (opts.meta == undefined) {
if (existsSync(opts.skeletontemplate)) {
opts.metaObject = JSON.parse(readFileSync(opts.skeletontemplate, 'utf8'));
} else {
const err = new Error(`Could not find skeleton template meta file at ${opts.skeletontemplate}`);
throw err;
}
}
// Tailwind Packages
if (opts?.typography) packages.push('@tailwindcss/typography');
if (opts?.forms) packages.push('@tailwindcss/forms');
// Component dependencies
if (opts?.codeblocks) packages.push('highlight.js');
if (opts?.popups) packages.push('@floating-ui/dom');
let result = spawnSync(opts.packagemanager, ['add', '-D', ...packages], {
shell: true,
});
// Capture any errors from stderr and display for the user to report it to us
if (result?.stderr.toString().length) {
console.log(
red(
bold(
'The following was reported to stderr - please read carefully to determine whether it actually affects your install:\n',
),
),
result?.stderr.toString(),
);
}
// Just to help with any user error reports
if (opts.verbose) {
const stdout = result?.stdout.toString();
if (stdout.length) console.log(bold(cyan('stdout:')), stdout);
const stderr = result?.stderr.toString();
if (stderr.length) console.log(bold(red('stderr:')), stderr);
// mri may only receive a single template and pass it to us as a string
if (typeof opts.skeletontheme === 'string') {
opts.skeletontheme = [opts.skeletontheme];
}
await modifyPackageJson(opts);
// write out config files
out('svelte.config.js', createSvelteConfig(opts));
out('.vscode/settings.json', await createVSCodeSettings());
out('tailwind.config.cjs', createTailwindConfig(opts));
out('postcss.config.cjs', createPostCssConfig());
createSvelteConfig(opts);
createViteConfig(opts);
await createVSCodeSettings();
createTailwindConfig(opts);
createPostCssConfig();
copyTemplate(opts);
// Monorepo additions
if (opts?.monorepo) {
fs.copySync(__dirname + '../README-MONO.md', process.cwd() + '/README.md', { overwrite: true });
mkdirp('scripts');
fs.copySync(__dirname + './swapdeps.mjs', process.cwd() + '/scripts/swapdeps.mjs', { overwrite: true });
let pkg = JSON.parse(fs.readFileSync('package.json'));
pkg.scripts['install'] = 'node ./scripts/swapdeps.mjs';
pkg.scripts['dep'] = 'vercel build && vercel deploy --prebuilt';
pkg.scripts['prod'] = 'vercel build --prod && vercel deploy --prebuilt --prod';
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
}
// copy over selected template
copyTemplate(opts);
// creating the missing lib folder...
mkdirp(path.join('src', 'lib'));
if (opts.monorepo) cpSync(resolve(__dirname, '../README-MONO.md'), resolve(cwd(), 'README.md'), { force: true });
if (opts.test) createTestConfig(opts);
// go back to starting location in case we get called again to create another template
process.chdir(startPath);
chdir(startPath);
opts.meta = undefined;
return opts;
}
async function createVSCodeSettings() {
try {
mkdirp('.vscode');
const data = await got('https://raw.githubusercontent.com/skeletonlabs/skeleton/master/scripts/tw-settings.json').text();
return data;
} catch (error) {
console.error(
'Unable to download settings file for VSCode, please read manual instructions at https://skeleton.dev/guides/install',
);
async function modifyPackageJson(opts) {
const pkgPath = join(cwd(), 'package.json');
let pkgJson = JSON.parse(readFileSync(pkgPath));
// add required packages
for (const pkg of [
'postcss',
'autoprefixer',
'tailwindcss',
'@skeletonlabs/skeleton',
'@skeletonlabs/tw-plugin',
'vite-plugin-tailwind-purgecss',
]) {
setNestedValue(pkgJson, ['devDependencies', pkg], 'latest');
}
// Extra packages and scripts for a monorepo install
if (opts.monorepo) {
['@sveltejs/adapter-vercel'].forEach((pkg) => (pkg.devDependencies[pkg] = opts.devDependencies.get(pkg)));
// TODO copy over github workflows for deploying to CF
// TODO auto-detect if we are in a mono from '@pnpm/find-workspace-dir';
pkgJson['deployConfig'] = { '@skeletonlabs/skeleton': '^1.0.0' };
}
// Optional packages
if (opts.mdsvex) pkgJson.devDependencies['mdsvex'] = 'latest';
if (opts.typography) pkgJson.devDependencies['@tailwindcss/typography'] = 'latest';
if (opts.forms) pkgJson.devDependencies['@tailwindcss/forms'] = 'latest';
if (opts.types == 'typescript') pkgJson.devDependencies['@types/node'] = 'latest';
if (opts.codeblocks) setNestedValue(pkgJson, ['dependencies', 'highlight.js'], 'latest');
if (opts.popups) setNestedValue(pkgJson, ['dependencies', '@floating-ui/dom'], 'latest');
// Template specific packages
if (opts.meta?.dependencies) {
pkgJson.dependencies = { ...pkgJson.dependencies, ...opts.meta.dependencies };
}
if (opts.meta?.devDependencies) {
pkgJson.devDependencies = { ...pkgJson.devDependencies, ...opts.meta.devDependencies };
}
await getLatestPackageVersions(pkgJson);
writeFileSync(pkgPath, JSON.stringify(pkgJson, null, 2));
}
async function getLatestPackageVersions(pkgJson) {
const devDeps = Object.keys(pkgJson.devDependencies);
for await (const pkg of devDeps) {
if (pkgJson.devDependencies[pkg] == 'latest') {
const data = await got(`https://registry.npmjs.org/${pkg}/latest`).json();
pkgJson.devDependencies[pkg] = data.version;
}
}
const deps = pkgJson.dependencies == undefined ? [] : Object.keys(pkgJson.dependencies);
for await (const pkg of deps) {
if (pkgJson.dependencies[pkg] == 'latest') {
const data = await got(`https://registry.npmjs.org/${pkg}/latest`).json();
pkgJson.dependencies[pkg] = data.version;
}
}
}
@@ -145,30 +173,28 @@ function createSvelteConfig(opts) {
// For some reason create-svelte will turn off preprocessing for jsdoc and no type checking
// this will break the using of all CSS preprocessing as well, which is undesirable.
// Here we will just return the typescript default setup
let str = '';
if (opts?.monorepo) {
str += `import adapter from '@sveltejs/adapter-vercel';\n`;
} else {
str += `import adapter from '@sveltejs/adapter-auto';\n`;
}
str += `import { vitePreprocess } from '@sveltejs/kit/vite';`;
if (opts?.monorepo) {
str += `\nimport path from 'path';`;
}
str += `
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
${
opts?.inspector
? `
const mdsvexConfig = `import { mdsvex } from 'mdsvex'
/** @type {import('mdsvex').MdsvexOptions} */
const mdsvexOptions = {
extensions: ['.md'],
}`;
const inspectorConfig = `
vitePlugin: {
inspector: true,
},`
: ''
}
},`;
let str = `import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/kit/vite';
${iit(opts.mdsvex, mdsvexConfig)}
/** @type {import('@sveltejs/kit').Config} */
const config = {
extensions: ['.svelte'${iit(opts.mdsvex, `, '.md'`)}],
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: [${iit(opts.mdsvex, 'mdsvex(mdsvexOptions),')} vitePreprocess()],
${iit(opts.inspector, inspectorConfig)}
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
@@ -177,7 +203,34 @@ const config = {
}
};
export default config;`;
return str;
writeFileSync(join(cwd(), 'svelte.config.js'), str);
}
function createViteConfig(opts) {
const filename = join(cwd(), opts.types == 'typescript' ? 'vite.config.ts' : 'vite.config.js');
let contents = `import { purgeCss } from 'vite-plugin-tailwind-purgecss';
import { sveltekit } from '@sveltejs/kit/vite';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [sveltekit(), purgeCss()]
});
`;
writeFileSync(filename, contents);
}
async function createVSCodeSettings() {
try {
mkdirp(join(cwd(), '.vscode'));
const data = await got(
'https://raw.githubusercontent.com/skeletonlabs/skeleton/master/packages/skeleton/scripts/tw-settings.json',
).text();
writeFileSync(join(cwd(), '.vscode', 'settings.json'), data);
} catch (error) {
console.error(
'Unable to download settings file for VSCode, please read manual instructions at https://skeleton.dev/guides/install',
);
}
}
function createTailwindConfig(opts) {
@@ -192,10 +245,25 @@ function createTailwindConfig(opts) {
pluginImports.push(`import typography from '@tailwindcss/typography'`);
plugins.push(`typography`);
}
pluginImports.push(`import skeleton from '@skeletonlabs/skeleton/tailwind/skeleton.cjs'`);
plugins.push(`...skeleton()`);
pluginImports.push(`import { skeleton } from '@skeletonlabs/tw-plugin'`);
// Can't use JSON.stringify because we node code literals in there without everything being coerced to quoted strings
// space on the end is important
let presetConfig = '{ themes: { preset: [ ';
let customConfig = '';
for (const theme of opts.skeletontheme) {
if (typeof theme === 'string') {
presetConfig += `{ name: "${theme}", enhancements: true },`;
} else {
pluginImports.push(`import { ${theme.custom} } from './src/${theme.custom}.js'`);
customConfig = `, custom:[${theme.custom}]`;
createCustomTheme(opts, theme.custom);
}
}
const finalConfig = presetConfig.slice(0, -1) + ']' + customConfig + '}}';
plugins.push(`skeleton(${finalConfig})`);
const str = `import { join } from 'path'
${iit(opts.types == 'typescript', `import type { Config } from 'tailwindcss'`)}
${pluginImports.join('\n')}
/** @type {import('tailwindcss').Config} */
@@ -206,11 +274,116 @@ module.exports = {
extend: {},
},
plugins: [${plugins.join(',')}],
}
}${iit(opts.types == 'typescript', ' satisfies Config')};
`;
return str;
writeFileSync(join(cwd(), `tailwind.config.${iit(opts.types == 'typescript', 'ts', 'js')}`), str);
}
function createCustomTheme(opts, name) {
const str = `// You can also use the generator at https://skeleton.dev/docs/generator to create these values for you
${iit(opts.types == 'typescript', `import type { CustomThemeConfig } from '@skeletonlabs/tw-plugin';`)}
export const ${name}${iit(opts.types == 'typescript', ': CustomThemeConfig')} = {
name: '${name}',
properties: {
// =~= Theme Properties =~=
"--theme-font-family-base": "system-ui",
"--theme-font-family-heading": "system-ui",
"--theme-font-color-base": "0 0 0",
"--theme-font-color-dark": "255 255 255",
"--theme-rounded-base": "9999px",
"--theme-rounded-container": "8px",
"--theme-border-base": "1px",
// =~= Theme On-X Colors =~=
"--on-primary": "0 0 0",
"--on-secondary": "255 255 255",
"--on-tertiary": "0 0 0",
"--on-success": "0 0 0",
"--on-warning": "0 0 0",
"--on-error": "255 255 255",
"--on-surface": "255 255 255",
// =~= Theme Colors =~=
// primary | #0FBA81
"--color-primary-50": "219 245 236", // #dbf5ec
"--color-primary-100": "207 241 230", // #cff1e6
"--color-primary-200": "195 238 224", // #c3eee0
"--color-primary-300": "159 227 205", // #9fe3cd
"--color-primary-400": "87 207 167", // #57cfa7
"--color-primary-500": "15 186 129", // #0FBA81
"--color-primary-600": "14 167 116", // #0ea774
"--color-primary-700": "11 140 97", // #0b8c61
"--color-primary-800": "9 112 77", // #09704d
"--color-primary-900": "7 91 63", // #075b3f
// secondary | #4F46E5
"--color-secondary-50": "229 227 251", // #e5e3fb
"--color-secondary-100": "220 218 250", // #dcdafa
"--color-secondary-200": "211 209 249", // #d3d1f9
"--color-secondary-300": "185 181 245", // #b9b5f5
"--color-secondary-400": "132 126 237", // #847eed
"--color-secondary-500": "79 70 229", // #4F46E5
"--color-secondary-600": "71 63 206", // #473fce
"--color-secondary-700": "59 53 172", // #3b35ac
"--color-secondary-800": "47 42 137", // #2f2a89
"--color-secondary-900": "39 34 112", // #272270
// tertiary | #0EA5E9
"--color-tertiary-50": "219 242 252", // #dbf2fc
"--color-tertiary-100": "207 237 251", // #cfedfb
"--color-tertiary-200": "195 233 250", // #c3e9fa
"--color-tertiary-300": "159 219 246", // #9fdbf6
"--color-tertiary-400": "86 192 240", // #56c0f0
"--color-tertiary-500": "14 165 233", // #0EA5E9
"--color-tertiary-600": "13 149 210", // #0d95d2
"--color-tertiary-700": "11 124 175", // #0b7caf
"--color-tertiary-800": "8 99 140", // #08638c
"--color-tertiary-900": "7 81 114", // #075172
// success | #84cc16
"--color-success-50": "237 247 220", // #edf7dc
"--color-success-100": "230 245 208", // #e6f5d0
"--color-success-200": "224 242 197", // #e0f2c5
"--color-success-300": "206 235 162", // #ceeba2
"--color-success-400": "169 219 92", // #a9db5c
"--color-success-500": "132 204 22", // #84cc16
"--color-success-600": "119 184 20", // #77b814
"--color-success-700": "99 153 17", // #639911
"--color-success-800": "79 122 13", // #4f7a0d
"--color-success-900": "65 100 11", // #41640b
// warning | #EAB308
"--color-warning-50": "252 244 218", // #fcf4da
"--color-warning-100": "251 240 206", // #fbf0ce
"--color-warning-200": "250 236 193", // #faecc1
"--color-warning-300": "247 225 156", // #f7e19c
"--color-warning-400": "240 202 82", // #f0ca52
"--color-warning-500": "234 179 8", // #EAB308
"--color-warning-600": "211 161 7", // #d3a107
"--color-warning-700": "176 134 6", // #b08606
"--color-warning-800": "140 107 5", // #8c6b05
"--color-warning-900": "115 88 4", // #735804
// error | #D41976
"--color-error-50": "249 221 234", // #f9ddea
"--color-error-100": "246 209 228", // #f6d1e4
"--color-error-200": "244 198 221", // #f4c6dd
"--color-error-300": "238 163 200", // #eea3c8
"--color-error-400": "225 94 159", // #e15e9f
"--color-error-500": "212 25 118", // #D41976
"--color-error-600": "191 23 106", // #bf176a
"--color-error-700": "159 19 89", // #9f1359
"--color-error-800": "127 15 71", // #7f0f47
"--color-error-900": "104 12 58", // #680c3a
// surface | #495a8f
"--color-surface-50": "228 230 238", // #e4e6ee
"--color-surface-100": "219 222 233", // #dbdee9
"--color-surface-200": "210 214 227", // #d2d6e3
"--color-surface-300": "182 189 210", // #b6bdd2
"--color-surface-400": "128 140 177", // #808cb1
"--color-surface-500": "73 90 143", // #495a8f
"--color-surface-600": "66 81 129", // #425181
"--color-surface-700": "55 68 107", // #37446b
"--color-surface-800": "44 54 86", // #2c3656
"--color-surface-900": "36 44 70", // #242c46
}
}`;
let filename = name + iit(opts.types == 'typescript', '.ts', '.js');
writeFileSync(join('src', filename), str);
}
function createPostCssConfig() {
const str = `module.exports = {
plugins: {
@@ -218,68 +391,71 @@ function createPostCssConfig() {
autoprefixer: {},
},
}`;
return str;
writeFileSync(join(cwd(), 'postcss.config.cjs'), str);
}
function copyTemplate(opts) {
const src = path.resolve(dist(opts.skeletontemplatedir), opts.skeletontemplate);
if (opts.meta == null) {
opts.meta = JSON.parse(readFileSync(opts.skeletontemplate, 'utf8'));
}
fs.copySync(src + '/src', './src', { overwrite: true });
fs.copySync(src + '/static', './static', { overwrite: true });
opts.meta.foldersToCopy.forEach((folder) => {
cpSync(resolve(opts.skeletontemplatedir, folder), resolve(opts.path, folder), { force: true, recursive: true });
});
// All fonts are in the template static folder, so we need to remove the ones that are not relevant to the theme
// Determine which font is used by the theme, copy it over to the static folder
// and then update the app.postcss file to include the correct font
// Themes can by applied to any template, so we can't have the fonts as part of the templates themselves.
let fontFamily = '';
let fontFile = '';
switch (opts.skeletontheme) {
case 'gold-nouveau':
case 'modern':
case 'seasonal':
fontFamily = 'Quicksand';
fontFile = ['Quicksand.ttf'];
break;
case 'rocket':
fontFamily = 'Space Grotesk';
fontFile = ['SpaceGrotesk.ttf'];
break;
case 'seafoam':
fontFamily = 'Playfair Display';
fontFile = ['PlayfairDisplay-Italic.ttf'];
break;
case 'vintage':
fontFamily = 'Abril Fatface';
fontFile = ['AbrilFatface.ttf'];
break;
default:
fontFamily = '';
fontFile = '';
}
if (fontFamily !== '') {
fs.appendFileSync(
'./src/app.postcss',
`
let addedFontConfig = '';
for (const theme of opts.skeletontheme) {
switch (theme) {
case 'gold-nouveau':
case 'modern':
case 'seasonal':
fontFamily = 'Quicksand';
fontFile = 'Quicksand.ttf';
break;
case 'rocket':
fontFamily = 'Space Grotesk';
fontFile = 'SpaceGrotesk.ttf';
break;
case 'seafoam':
fontFamily = 'Playfair Display';
fontFile = 'PlayfairDisplay-Italic.ttf';
break;
case 'vintage':
fontFamily = 'Abril Fatface';
fontFile = 'AbrilFatface.ttf';
break;
default:
fontFamily = '';
fontFile = '';
}
if (fontFamily !== '') {
addedFontConfig += `
/* ${theme} theme */
@font-face {
font-family: '${fontFamily}';
src: url('/fonts/${fontFile}');
font-display: swap;
}`,
);
removeFilesExceptSync('./static/fonts/', fontFile);
} else {
fs.removeSync('./static/fonts');
}`;
cpSync(resolve(__dirname, '../fonts/', fontFile), join(cwd(), 'static', 'fonts', fontFile));
}
}
appendFileSync(join(cwd(), 'src', 'app.postcss'), addedFontConfig);
const layoutFile = resolve(cwd(), 'src/routes/+layout.svelte');
// patch back in their theme choice - it may have been replaced by the theme template, it may still be the correct auto-genned one, depends on the template - we don't care, this fixes it.
let content = fs.readFileSync('./src/routes/+layout.svelte', {
encoding: 'utf8',
flag: 'r',
});
const themeReg = /theme-.*\.css';$/gim;
content = content.replace(themeReg, `theme-${opts.skeletontheme}.css';`);
content = (opts.types === 'typescript' ? "<script lang='ts'>" : '<script>') + content.substring(content.indexOf('\n'));
let content = readFileSync(layoutFile, { encoding: 'utf8' });
// Set the script ype depending on their choice of typescript or checkjs
content = (opts.types === 'typescript' ? `<script lang="ts">` : '<script>') + content.substring(content.indexOf('\n'));
// Add in the basic boilerplate for codeblocks and popups if they were selected and do a basic check for the import name to avoid duplicates
const scriptEndReg = /<\/script>/g;
if (opts?.highlightjs) {
if (opts.codeblocks && content.indexOf('highlight.js') === -1) {
content = content.replace(
scriptEndReg,
`
@@ -292,7 +468,7 @@ function copyTemplate(opts) {
);
}
if (opts?.highlightjs) {
if (opts?.popups && content.indexOf('@floating-ui/dom') === -1) {
content = content.replace(
scriptEndReg,
`
@@ -304,20 +480,33 @@ function copyTemplate(opts) {
);
}
fs.writeFileSync('./src/routes/+layout.svelte', content);
writeFileSync(layoutFile, content);
// update the <body> to have the data-theme
content = fs.readFileSync('./src/app.html', {
encoding: 'utf8',
flag: 'r',
});
fs.writeFileSync(
'./src/app.html',
content.replace('<body>', `<body data-sveltekit-preload-data="hover" data-theme="${opts.skeletontheme}">`),
);
// Update the data-theme attribute in the app.html file
content = readFileSync(resolve(opts.path, 'src/app.html'), { encoding: 'utf8' });
const dataThemeRegex = /data-theme=".*"/gim;
let activeTheme = 'skeleton';
if (typeof opts.skeletontheme[0] === 'string') {
activeTheme = opts.skeletontheme[0];
} else {
activeTheme = opts.skeletontheme[0].custom;
}
writeFileSync(resolve(opts.path, 'src/app.html'), content.replace(dataThemeRegex, `data-theme="${activeTheme}"`));
}
function out(filename, data) {
if (data == undefined) return;
fs.writeFileSync(filename, data);
function createTestConfig() {
const str = `import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
webServer: {
command: 'pnpm build && pnpm preview',
port: 4173
},
testDir: '../../../tests/',
testMatch: /(.+\.)?(test|spec)\.[jt]s/
};
export default config;
`;
writeFileSync('playwright.config.ts', str);
}

View File

@@ -4,10 +4,11 @@ import fs from 'fs-extra';
import mri from 'mri';
import { bold, cyan, gray, grey, red } from 'kleur/colors';
import { intro, text, select, multiselect, spinner } from '@clack/prompts';
import events from 'events';
import { dist, getHelpText, goodbye } from './utils.js';
import path from 'path';
import { dist, getHelpText, goodbye, whichPMRuns, checkIfDirSafeToInstall } from './utils.js';
import path, { resolve, join } from 'path';
import semver from 'semver';
import fg from 'fast-glob';
// Minimum version required for Svelte Kit
const requiredVersion = '16.14.0';
@@ -17,35 +18,56 @@ async function main() {
process.exit(1);
}
// This is required to handle spawning processes
events.EventEmitter.defaultMaxListeners = 15;
const startPath = process.cwd();
let defaults = new SkeletonOptions();
// grab any passed arguments from the command line
let opts = await parseArgs();
if ('quiet' in opts) {
// in quiet mode we prefill the defaults, then overlay the passed options and bypass all of askForMissingParams so that it
// doesn't have to constantly check for quietmode all the time.
let defaults = new SkeletonOptions();
opts = Object.assign(defaults, opts);
// need to set some defaults if they are not passed in
if (!('quiet' in opts)) opts.quiet = false;
// if no templatedir is provided we have to account for the dist location
if (!('skeletontemplatedir' in opts)) {
opts.skeletontemplatedir = resolve(dist('.'), '../templates');
} else {
// in interactive mode we ask the user to fill anything not passed in
// Resolve can handle multiple absolute paths so passing in a relative or absolute path is fine
opts.skeletontemplatedir = resolve(process.cwd(), opts.skeletontemplatedir);
}
try {
checkIfDirSafeToInstall(opts.path);
} catch (e) {
console.error(red(`\n${e.message}`));
process.exit(1);
}
if (!opts.quiet) {
opts = await askForMissingParams(opts);
}
opts = Object.assign(defaults, opts);
opts.packagemanager = whichPMRuns()?.name;
// Now that we have all of the options, lets create it.
const s = spinner();
s.start('Installing');
await createSkeleton(opts);
s.stop('Done installing');
// And give the user some final information on what to do Next
if (!opts?.quiet) {
if (!opts.quiet) {
s.start('Installing');
}
try {
await createSkeleton(opts);
} catch (e) {
console.error(red(`\n${e.message}`));
process.exit(1);
}
if (!opts.quiet) {
s.stop('Done installing');
// And give the user some final information on what to do Next
const pm = opts.packagemanager;
let runString = `${pm} dev\n`;
let runString = `${pm} install\n${pm} dev\n`;
if (pm == 'npm') {
runString = 'npm run dev\n';
runString = 'npm install\nnpm run dev\n';
}
let finalInstructions = bold(cyan(`\nDone! You can now:\n\n`));
if (startPath != opts.path) {
@@ -66,7 +88,6 @@ async function parseArgs() {
const opts = mri(argv, {
alias: {
h: 'help',
n: 'name',
p: 'path',
t: 'skeletontheme',
m: 'monorepo',
@@ -77,7 +98,6 @@ async function parseArgs() {
'help',
'quiet',
'monorepo',
'skeletonui',
'library',
'prettier',
'eslint',
@@ -88,15 +108,15 @@ async function parseArgs() {
'popups',
'forms',
'typography',
'verbose',
'mdsvex',
],
});
// If a user invokes 'create-app blah foo', it falls into the _ catch all list, the best we can do is take the first one and use that as the name
// If a user invokes 'create-app blah foo', it falls into the _ catch all list, the best we can do is take the first one and use that as the path
// if args are passed in incorrectly such as --prettier=0 instead of --prettier=false then a 0 will be added to the _ collection, we check that the
// first one isn't a bungled arg set to 0
if (opts._.length && opts._[0] != 0) {
opts.name = opts._[0];
opts.path = opts._[0];
}
// Show help if specified regardless of how many other options are specified, have fun updating the text string in utils.ts :(
if ('help' in opts) {
@@ -106,37 +126,6 @@ async function parseArgs() {
return opts;
}
function checkIfDirSafeToInstall(path) {
// Check if the directory already exists.
if (!fs.existsSync(path)) return;
//lets see whats in there
const conflicts = fs
.readdirSync(path)
.filter((file) =>
/^(package.json|svelte.config.js|tailwind.config.cjs|pnpm-lock.yaml|postcss.config.cjs|vite.config.ts)$/.test(file),
);
if (conflicts.length > 0) {
console.log("create-skeleton-app doesn't support updating an existing project, it needs a new empty directory to install into");
console.log(`The directory ${path} contains files that could conflict:`);
console.log();
for (const file of conflicts) {
try {
const stats = fs.lstatSync(path + '/' + file);
if (stats.isDirectory()) {
console.log(` ${red(file)}/`);
} else {
console.log(` ${red(file)}`);
}
} catch {
console.log(` ${red(file)}`);
}
}
console.log('Either try using a new directory name, or remove the files listed above.');
process.exit(1);
}
}
/**
* @param {SkeletonOptions} opts
*/
@@ -150,21 +139,154 @@ ${bold(cyan('Welcome to Skeleton 💀! A UI toolkit for Svelte + Tailwind'))}
Problems? Open an issue on ${cyan('https://github.com/skeletonlabs/skeleton/issues')} if none exists already.`);
//NOTE: When doing checks here, make sure to test for the presence of the prop, not the prop value as it may be set to false deliberately.
if (!('name' in opts)) {
opts.name = await text({
message: 'Name for your new project:?',
placeholder: 'my-app',
if (!('path' in opts)) {
opts.path = await text({
message: 'Where should we install your project (Enter for current directory) ?',
placeholder: '',
validate(value) {
if (value.length === 0) return `App name is required!`;
if (value.length === 0) value = '.';
try {
checkIfDirSafeToInstall(resolve(process.cwd(), value));
} catch (e) {
return e.message;
}
},
});
goodbye(opts.name);
goodbye(opts.path);
}
// name to set in package.json
opts.name = opts.path;
// Skeleton Template Selection
// We have to ask for the template first as it may dictate things like required packages and typechecking
// skeletontemplatedir is the path to the templates directory, it's either passed in as an arg or set to cwd
// it may be a single directory with a csa-meta in the root,
// or it holds multiple directories with csa-meta files in them and skeletontemplate selects that sub folder.
let templateFound = false;
if (opts?.skeletontemplate) {
// they have asked for a specific template within the folder
opts.skeletontemplate = resolve(opts.skeletontemplatedir, opts.skeletontemplate, 'csa-meta.json');
//check that it exists
if (!fs.existsSync(opts.skeletontemplate)) {
console.error(`The template ${opts.skeletontemplate} does not exist`);
process.exit(1);
}
templateFound = true;
}
// no template specified, so scan the templatedir for csa-meta files
if (!templateFound) {
const metaFiles = fg.sync(['**/csa-meta.json'], { cwd: opts.skeletontemplatedir, deep: 2 });
if (metaFiles.length === 0) {
console.error(`No templates found in ${opts.skeletontemplatedir}`);
process.exit(1);
}
let parsedChoices = [];
metaFiles.forEach((meta_file) => {
const path = join(opts.skeletontemplatedir, meta_file);
const { position, label, description, enabled } = JSON.parse(fs.readFileSync(path, 'utf8'));
if (enabled) {
parsedChoices.push({ position, label, hint: description, value: path });
}
});
parsedChoices.sort((a, b) => a.position - b.position);
opts.skeletontemplate = await select({
message: 'Which Skeleton app template?',
options: parsedChoices,
});
goodbye(opts.skeletontemplate);
}
// Now that we have the template, lets get the meta data from it and the base path
opts.meta = JSON.parse(fs.readFileSync(opts.skeletontemplate, 'utf8'));
if (opts.meta.requiredFeatures) {
opts.meta.requiredFeatures.forEach((val) => {
Object.assign(opts, val);
});
}
opts.skeletontemplatedir = path.dirname(opts.skeletontemplate);
// If it's a premium template, wording needs to be change to indicate that there is a theme already built in
// Skeleton Theme Selection
if (!('skeletontheme' in opts)) {
let themeChoices = [
{ label: 'Skeleton', value: 'skeleton' },
{ label: 'Modern', value: 'modern' },
{ label: 'Hamlindigo', value: 'hamlindigo' },
{ label: 'Rocket', value: 'rocket' },
{ label: 'Sahara', value: 'sahara' },
{ label: 'Gold Nouveau', value: 'gold-nouveau' },
{ label: 'Vintage', value: 'vintage' },
{ label: 'Seafoam', value: 'seafoam' },
{ label: 'Crimson', value: 'crimson' },
{ label: cyan('Custom'), value: 'custom', hint: 'Will ask for a name next' },
];
if (opts.meta.type === 'premium') {
themeChoices.unshift({ label: 'Use templates built in theme', value: 'builtin' });
}
opts.skeletontheme = await multiselect({
message: 'Select a theme (top most selection will be default):',
options: themeChoices,
required: true,
});
goodbye(opts.skeletontheme);
}
if (opts.skeletontheme.includes('custom')) {
let customName = await text({
message: 'Enter a name for your custom theme:',
placeholder: 'theme_name',
validate(value) {
if (value.length === 0) {
return 'Please enter a name for your custom theme';
}
// regex to check if value can be used as a variable name, it cannot allow hyphens
if (!/^[a-zA-Z_$][a-zA-Z_$0-9]*$/.test(value)) {
return 'Name for theme must be a valid syntax for a Javascript variable name';
}
},
});
opts.skeletontheme.pop('custom');
opts.skeletontheme.push({ custom: customName });
goodbye();
}
// Additional packages to install - these can be influenced by the template selected
let packages = [
{ value: 'forms', label: 'Add Tailwind forms ?', package: '@tailwindcss/forms', force: false },
{ value: 'typography', label: 'Add Tailwind typography ?', package: '@tailwindcss/typography', force: false },
{ value: 'codeblocks', label: 'Add CodeBlock (installs highlight.js) ?', package: 'highlight.js', force: false },
{ value: 'popups', label: 'Add Popups (installs floating-ui) ?', package: '@floating-ui/dom', force: false },
// { value: 'mdsvex', label: 'Add Markdown support (installs mdsvex) ?', package: 'mdsvex', force: false },
];
// Force the packages that are required by the template
packages.forEach((pkg) => {
if (opts[pkg.value] != undefined) pkg.force = true;
});
// Now we can ask the user about any options that are not forced to be installed
let optionalPackages = packages.filter((pkg) => !pkg.force);
// Get list of forced packages to display to the user
let msg = '';
packages.forEach((p) => {
if (p.force) msg += p.package + '\n';
});
if (msg.length > 0) {
msg = `\nThe following packages will be installed because they are required by the template:\n\n${msg}\nWhat other packages would you like to install:`;
} else {
msg = `\nWhat other packages would you like to install:`;
}
if (optionalPackages.length > 0) {
// check which options are set and fill the initialValues array
const packageChoices = await multiselect({
message: msg,
options: optionalPackages,
required: false,
});
goodbye(packages);
if (Array.isArray(packageChoices)) {
packageChoices.forEach((value) => (opts[value] = true));
}
}
// test the path to make sure it is safe to install
if (opts.path === undefined) opts.path = process.cwd();
opts.name = opts.name.replace(/\s+/g, '-').toLowerCase();
opts.path = path.resolve(opts.path, opts.name);
checkIfDirSafeToInstall(opts.path);
if (!('types' in opts)) {
opts.types = await select({
@@ -200,79 +322,9 @@ Problems? Open an issue on ${cyan('https://github.com/skeletonlabs/skeleton/issu
required: false,
});
goodbye(optionalInstalls);
optionalInstalls.every((value) => (opts[value] = true));
optionalInstalls.forEach((value) => (opts[value] = true));
}
// Additional packages to install
if (
!['forms', 'typography', 'codeblocks', 'popups'].every((value) => {
return Object.keys(opts).includes(value);
})
) {
const packages = await multiselect({
message: 'What other packages would you like to install:',
initialValues: ['forms', 'typography', 'codeblocks', 'popups'].filter((value) => {
return Object.keys(opts).includes(value);
}),
options: [
{ value: 'forms', label: 'Add Tailwind forms ?' },
{ value: 'typography', label: 'Add Tailwind typography ?' },
{ value: 'codeblocks', label: 'Add CodeBlock (installs highlight.js) ?' },
{ value: 'popups', label: 'Add Popups (installs floating-ui) ?' },
],
required: false,
});
goodbye(packages);
packages.every((value) => (opts[value] = true));
}
// Skeleton Theme Selection
if (!('skeletontheme' in opts)) {
opts.skeletontheme = await select({
message: 'Select a theme:',
options: [
{ label: 'Skeleton', value: 'skeleton' },
{ label: 'Modern', value: 'modern' },
{ label: 'Hamlindigo', value: 'hamlindigo' },
{ label: 'Rocket', value: 'rocket' },
{ label: 'Sahara', value: 'sahara' },
{ label: 'Gold Nouveau', value: 'gold-nouveau' },
{ label: 'Vintage', value: 'vintage' },
{ label: 'Seafoam', value: 'seafoam' },
{ label: 'Crimson', value: 'crimson' },
],
});
goodbye(opts.skeletontheme);
}
//Skeleton Template Selection
if (!('skeletontemplate' in opts)) {
// need to check whether a templatedir has been passed in (might be from a script in package.json pointing to real template projects)
const templateDir = opts.skeletontemplatedir || '../templates';
let parsedChoices = [];
fs.readdirSync(dist(templateDir)).forEach((dir) => {
const meta_file = dist(`${templateDir}/${dir}/csa-meta.json`);
const { position, label, description, enabled } = JSON.parse(fs.readFileSync(meta_file, 'utf8'));
if (enabled) {
parsedChoices.push({
position,
label,
description,
value: dir,
});
}
});
parsedChoices.sort((a, b) => a.position - b.position);
opts.skeletontemplate = await select({
message: 'Which Skeleton app template?',
options: parsedChoices,
});
goodbye(opts.skeletontemplate);
}
const skelOpts = new SkeletonOptions();
Object.assign(skelOpts, opts);
return skelOpts;
return opts;
}
main();

View File

@@ -1,94 +0,0 @@
#!/usr/bin/env node
import isCI from 'is-ci';
import { readFileSync, writeFileSync } from 'fs';
import { execSync } from 'child_process';
// no it can't be run on preinstall
// no it can't be a nice little npm package
// yes it's running install twice
// yes it's a hack
// but it works (on Vercel at least)
export function makeWorkspacePackageLinks(pkg) {
if (pkg?.deployConfig?.dependencies != undefined) {
for (const [dep, version] of Object.entries(pkg.deployConfig.dependencies)) {
pkg.dependencies[dep] = 'workspace:^';
}
}
if (pkg?.deployConfig?.devDependencies != undefined) {
for (const [devDep, version] of Object.entries(pkg.deployConfig.devDependencies)) {
pkg.devDependencies[devDep] = 'workspace:^';
}
}
if (pkg?.deployConfig?.peerDependencies != undefined) {
for (const [peerDep, version] of Object.entries(pkg.deployConfig.dependencies)) {
pkg.peerDependencies[peerDep] = 'workspace:^';
}
}
}
export function makeVersionedPackageLinks(pkg) {
let clean = true;
if (pkg?.deployConfig?.dependencies != undefined) {
for (const [dep, version] of Object.entries(pkg.deployConfig.dependencies)) {
if (pkg.dependencies[dep] !== version) {
pkg.dependencies[dep] = version;
clean = false;
}
}
}
if (pkg?.deployConfig?.devDependencies != undefined) {
for (const [devDep, version] of Object.entries(pkg?.deployConfig?.devDependencies)) {
if (pkg?.devDependencies[devDep] !== version) {
pkg.devDependencies[devDep] = version;
clean = false;
}
}
}
if (pkg?.deployConfig?.peerDependencies != undefined) {
for (const [peerDep, version] of Object.entries(pkg?.deployConfig?.devDependencies)) {
if (pkg?.peerDependencies[peerDep] !== version) {
pkg.peerDependencies[peerDep] = version;
clean = false;
}
}
}
return { pkg: pkg, clean: clean };
}
export function swapdeps() {
let pkg = JSON.parse(readFileSync('./package.json', 'utf8'));
let clean = true;
switch (process.argv.slice(2)[0]) {
case 'workspace':
console.log('Setting dependencies to workspace:^');
makeWorkspacePackageLinks(pkg);
break;
case 'versioned':
console.log('Setting dependencies to versioned');
makeVersionedPackageLinks(pkg);
break;
case '-h':
case 'h':
case '--help':
case 'help':
console.log(
'swapdeps [workspace|versioned] or no args for auto-change to versioned if in a CI environment or workspace links if not',
);
break;
default:
if (isCI) {
({ pkg, clean } = makeVersionedPackageLinks(pkg));
} else {
console.log('No CI detected, setting dependencies to workspace:^');
makeWorkspacePackageLinks(pkg);
}
}
writeFileSync('./package.json', JSON.stringify(pkg, null, 2), 'utf8');
if (clean === false) {
execSync('pnpm install --no-frozen-lockfile');
}
}
swapdeps();

View File

@@ -1,21 +1,33 @@
import { fileURLToPath } from 'url';
import { fileURLToPath } from 'node:url';
import { cancel, isCancel } from '@clack/prompts';
import path from 'path';
import path from 'node:path';
import fs from 'fs-extra';
import columnify from 'columnify';
export function whichPMRuns() {
const userAgent = process.env.npm_config_user_agent;
if (!userAgent) {
return undefined;
return 'npm';
}
const pmSpec = userAgent.split(' ')[0] || '';
const separatorPos = pmSpec.lastIndexOf('/');
const name = pmSpec?.substring(0, separatorPos);
return {
name: name === 'npminstall' ? 'cnpm' : name,
name: name === 'npminstall' ? 'npm' : name,
version: pmSpec?.substring(separatorPos + 1),
};
}
// Set a JSON value when the parent keys may not exist
export function setNestedValue(obj, path, value) {
let current = obj;
for (let i = 0; i < path.length - 1; i++) {
if (current[path[i]] === undefined) {
current[path[i]] = {};
}
current = current[path[i]];
}
current[path[path.length - 1]] = value;
}
/** @param {string} dir */
export function mkdirp(dir) {
@@ -26,6 +38,18 @@ export function mkdirp(dir) {
throw e;
}
}
// Insert If True
export function iit(valToBeTruthy, valToReturnIfTruthy, valToReturnIfFalsy) {
if (valToBeTruthy) {
return valToReturnIfTruthy;
} else {
if (valToReturnIfFalsy === undefined) {
return '';
} else {
return valToReturnIfFalsy;
}
}
}
export function dist(pathToFind) {
let pathAdjust = '';
@@ -54,41 +78,124 @@ export function goodbye(option) {
}
}
export function checkIfDirSafeToInstall(path) {
// no dir, no conflicts
if (!fs.existsSync(path)) {
return true;
}
let conflicts = fs.readdirSync(path);
conflicts = conflicts.filter((file) =>
/^(package.json|svelte.config.js|tailwind.config.cjs|postcss.config.cjs|vite.config.ts)$/.test(file),
);
if (conflicts.length > 0) {
const err = new Error(
`The directory ${path} contains files that could conflict:\n${conflicts.join(
'\n',
)}\n\nPlease provide a clean directory to install into.`,
);
throw err;
}
// 10 was picked because if it's in something like a ~/projects directory and it would be annoying to strip out the added files and folders
if (conflicts.length > 10) {
const err = new Error(`The directory ${path} contains too many files/folders to safely install.`);
throw err;
}
return true;
}
export function getHelpText() {
// Must use spaces for adjustments as output can get very wonky with tab output
// Why not array of arrays, TBH it's more readable in source like this and easy to edit with column selection etc.
// But the advantage would be that padEnd could be adjusted to the console.width... will wait for feedback.
return `
Option Short Quiet Default Values Description
--help -h This help screen
--quiet -q Quiet mode - see below
--verbose -v Show shell output for troubleshooting
--name -n new-skel-app string, no spaces Name of the directory for the project
--types typescript typescript|checkjs TypeScript or JavaScript with JSDoc
--prettier true true|false Whether Prettier is added
--eslint true true|false Whether ESLint is added
--playwright false true|false Whether Playwright is added
--vitest false true|false Whether Vitest is added
--codeblocks false true|false Install codeblock optional dependencies
--popups true true|false Install popups dependencies
--path -p '' relative or absolute path Location to install, name is appended
--forms false true|false Add Tailwinds Forms plugin
--typography false true|false Add Tailwinds Typography plugin
--skeletontheme -t skeleton skeleton Choose one for the Skeleton theme
modern
hamlindigo
rocket
sahara
gold-nouveau
vintage
seafoam
crimson
--skeletontemplate bare bare The Skeleton template to use
welcome
// TODO: Ensure options are up to date
const data = [
{ Option: '--help', Short: '-h', 'Quiet Default': '', Value: '', Description: 'This help screen' },
{ Option: '--quiet', Short: '-q', 'Quiet Default': '', Value: '', Description: 'Quiet mode - see below' },
{
Option: '--name',
Short: '-n',
'Quiet Default': 'skeleton-app',
Value: 'skeleton-app',
Description: 'Name of the directory for the project',
},
{
Option: '--path',
Short: '-p',
'Quiet Default': "''",
Value: 'relative or absolute path',
Description: 'Location to install, name is appended',
},
{
Option: '--types',
Short: '',
'Quiet Default': 'typescript',
Value: 'typescript|checkjs',
Description: 'TypeScript or JavaScript with JSDoc',
},
{ Option: '--prettier', Short: '', 'Quiet Default': 'true', Value: 'true|false', Description: 'Whether Prettier is added' },
{ Option: '--eslint', Short: '', 'Quiet Default': 'true', Value: 'true|false', Description: 'Whether ESLint is added' },
{ Option: '--playwright', Short: '', 'Quiet Default': 'false', Value: 'true|false', Description: 'Whether Playwright is added' },
{ Option: '--vitest', Short: '', 'Quiet Default': 'false', Value: 'true|false', Description: 'Whether Vitest is added' },
{
Option: '--codeblocks',
Short: '',
'Quiet Default': 'false',
Value: 'true|false',
Description: 'Install codeblock optional dependencies',
},
{ Option: '--popups', Short: '', 'Quiet Default': 'false', Value: 'true|false', Description: 'Install popups dependencies' },
{
Option: '--mdsvex',
Short: '',
'Quiet Default': 'false',
Value: 'true|false',
Description: 'Install mdsvex for markdown processing',
},
{ Option: '--forms', Short: '', 'Quiet Default': 'false', Value: 'true|false', Description: 'Install Tailwinds Forms plugin' },
{
Option: '--typography',
Short: '',
'Quiet Default': 'false',
Value: 'true|false',
Description: 'Install Tailwinds Typography plugin',
},
{
Option: '--skeletontemplatedir',
Short: '',
'Quiet Default': '',
Value: '',
Description: 'Path to directory containing templates',
},
{
Option: '--skeletontheme',
Short: '-t',
'Quiet Default': 'skeleton',
Value: 'skeleton',
Description: 'Choose one for the Skeleton theme',
},
{ Option: '', Short: '', 'Quiet Default': 'modern', Value: 'modern', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'hamlindigo', Value: 'hamlindigo', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'rocket', Value: 'rocket', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'sahara', Value: 'sahara', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'gold-nouveau', Value: 'gold-nouveau', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'vintage', Value: 'vintage', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'seafoam', Value: 'seafoam', Description: '' },
{ Option: '', Short: '', 'Quiet Default': 'crimson', Value: 'crimson', Description: '' },
{
Option: '--skeletontemplate',
Short: '',
'Quiet Default': 'bare',
Value: 'bare',
Description: 'Name of built in template to use',
},
{ Option: '', Short: '', 'Quiet Default': 'welcome', Value: 'welcome', Description: '' },
];
return (
columnify(data, { columns: ['Option', 'Short', 'Default', 'Value', 'Description'] }) +
`
Quiet mode is for automated installs for testing, CI/CD. It will take all of the default values in the
Quiet Default column, but you can provide any other flags to override as you see fit. If you just want
to generate a new project but still ask for a name, you need to provide all the other args except the
ones to be filled in by the user.
`;
ones to be filled in by the user.\n`
);
}

View File

@@ -1,5 +0,0 @@
/*place global styles here */
html,
body {
@apply h-full;
}

View File

@@ -1,10 +0,0 @@
<script>
// The ordering of these imports is critical to your app working properly
import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
import '@skeletonlabs/skeleton/styles/skeleton.css';
// Most of your app wide CSS should be put in this file
import '../app.postcss';
</script>
<slot />

View File

@@ -0,0 +1,8 @@
{
"position": 10,
"label": "AppShell starter",
"description": "Starter site with AppShell and AppBar",
"enabled": true,
"type": "built-in",
"foldersToCopy": ["src", "static"]
}

View File

@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body>
<body data-sveltekit-preload-data="hover" data-theme="skeleton">
<div style="display: contents" class="h-full overflow-hidden">%sveltekit.body%</div>
</body>
</html>

View File

@@ -0,0 +1,9 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;
html,
body {
@apply h-full overflow-hidden;
}

View File

@@ -1,9 +1,4 @@
<script>
// The ordering of these imports is critical to your app working properly
import '@skeletonlabs/skeleton/themes/theme-skeleton.css';
// If you have source.organizeImports set to true in VSCode, then it will auto change this ordering
import '@skeletonlabs/skeleton/styles/skeleton.css';
// Most of your app wide CSS should be put in this file
<script lang='ts'>
import '../app.postcss';
import { AppShell, AppBar } from '@skeletonlabs/skeleton';
</script>

View File

@@ -2,5 +2,7 @@
"position": 5,
"label": "Bare Bones",
"description": "A blank slate for you to create your app",
"enabled": true
"enabled": true,
"type": "built-in",
"foldersToCopy": ["src", "static"]
}

View File

@@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width" />
%sveltekit.head%
</head>
<body>
<body data-sveltekit-preload-data="hover" data-theme="skeleton">
<div style="display: contents">%sveltekit.body%</div>
</body>
</html>

View File

@@ -0,0 +1,4 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind variants;

View File

@@ -0,0 +1,5 @@
<script lang="ts">
import '../app.postcss';
</script>
<slot />

View File

@@ -5,9 +5,11 @@
<h1 class="h1">Let's get cracking bones!</h1>
<p>Start by exploring:</p>
<ul>
<li><code class="code">/src/routes/+layout.svelte</code> - barebones layout, the CSS import order is critical!</li>
<li><code class="code">/src/app.postcss</code> - minimal css to make the page full screen, may not be relevant for your project</li>
<li><code class="code">/src/routes/+page.svelte</code> - this page, you can replace the contents</li>
<li><code class="code">/src/routes/+layout.svelte</code> - barebones layout</li>
<li><code class="code">/src/app.postcss</code> - app wide css</li>
<li>
<code class="code">/src/routes/+page.svelte</code> - this page, you can replace the contents
</li>
</ul>
</div>
</div>

View File

@@ -1,6 +0,0 @@
{
"position": 10,
"label": "Skeleton Welcome",
"description": "A single page to welcome you to Skeleton",
"enabled": true
}

View File

@@ -1,5 +0,0 @@
/*place global styles here */
html,
body {
@apply h-full overflow-hidden;
}