From bb245462cca765a09a1b2242b7f29c9152c7e072 Mon Sep 17 00:00:00 2001 From: YRM Date: Thu, 4 Jan 2024 23:11:54 +0800 Subject: [PATCH] feat: support create-solid --- README.md | 4 +- package.json | 45 +++- pnpm-lock.yaml | 378 ++++++++++++++++++++++++++++++++++ resources/solid.svg | 1 + src/commands/starter.ts | 166 ++++++++++++++- src/config.ts | 8 + src/lib.d.ts | 2 + src/shared/constants.ts | 31 +++ src/shared/utils/gitignore.ts | 93 +++++++++ tsup.config.ts | 2 +- 10 files changed, 719 insertions(+), 11 deletions(-) create mode 100644 resources/solid.svg create mode 100644 src/lib.d.ts create mode 100644 src/shared/utils/gitignore.ts diff --git a/README.md b/README.md index cf1f19b..7559df4 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,6 @@ Kickstart your project with a starter in VSCode Visual Studio Marketplace Version

- ## Motivation - As a front-end developer, everytime before I create a new project, I have to open a terminal, enter some commands recommended in the front-end framework documentation; sometimes I even forget these commands. This whole process apparently needs more efficiency. @@ -29,7 +28,6 @@ Kickstart your project with a starter in VSCode - Enable or disable automatic initialization of Git - Enable or disable automatic installation of dependencies - ## Usage

@@ -42,7 +40,6 @@ Kickstart your project with a starter in VSCode Preview 2

- ## Support Templates - [Nuxt3 Minimal Starter](https://github.com/nuxt/starter/tree/v3) - Create a new Nuxt project. @@ -52,6 +49,7 @@ Kickstart your project with a starter in VSCode - [Vitesse Lite](https://github.com/antfu/vitesse-lite) - Lightweight version of Vitesse. - [Create Next App](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) - The easiest way to get started with Next.js. - [Create Svelte](https://github.com/sveltejs/kit/tree/main/packages/create-svelte) - Create new SvelteKit projects. +- [Create Solid](https://github.com/solidjs/solid-start/tree/main/packages/create-solid) - The easiest way to get started with Solid. - [Starter TS](https://github.com/antfu/starter-ts) - Starter template for TypeScript library. - [Starter VSCode](https://github.com/antfu/starter-vscode) - Starter template for VS Code Extension. - [Vitesse WebExt](https://github.com/antfu/vitesse-webext) - WebExtension Vite Starter Template. diff --git a/package.json b/package.json index c075f52..6a37144 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "publisher": "YRM", "name": "starter-templates", "displayName": "Starters", - "version": "0.9.0", + "version": "0.10.0", "description": "Kickstart your project with a starter in VSCode", "license": "MIT", "repository": { @@ -217,6 +217,42 @@ "scope": "window" } } + }, + { + "title": "Create Solid(Official Beta)", + "order": 5, + "properties": { + "starters.createSolid.whichTemplate": { + "enum": [ + "bare", + "basic", + "experiments", + "hackernews", + "todomvc", + "with-auth", + "with-mdx", + "with-prisma", + "with-solid-styled", + "with-tailwindcss", + "with-trpc" + ], + "default": "bare", + "description": "Which template do you want to use?", + "scope": "window" + }, + "starters.createSolid.needsSsr": { + "type": "boolean", + "default": true, + "markdownDescription": "Server Side Rendering?", + "scope": "window" + }, + "starters.createSolid.needsTypeScript": { + "type": "boolean", + "default": true, + "markdownDescription": "Use TypeScript?", + "scope": "window" + } + } } ] }, @@ -232,6 +268,11 @@ }, "devDependencies": { "@antfu/eslint-config": "^2.4.6", + "@babel/core": "^7.23.7", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/preset-typescript": "^7.23.3", + "@types/babel-plugin-syntax-jsx": "^6.18.2", + "@types/babel__core": "^7.20.5", "@types/degit": "^2.8.6", "@types/fs-extra": "^11.0.4", "@types/mocha": "^10.0.6", @@ -245,8 +286,10 @@ "degit": "^2.8.4", "eslint": "^8.54.0", "execa": "^8.0.1", + "fast-glob": "^3.3.2", "fs-extra": "^11.2.0", "nypm": "^0.3.3", + "prettier": "^3.1.1", "tsup": "^8.0.1", "typescript": "^5.3.2", "vscode-uri": "^3.0.8" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f0f6977..5abcc2a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -8,6 +8,21 @@ devDependencies: '@antfu/eslint-config': specifier: ^2.4.6 version: 2.6.1(@vue/compiler-sfc@3.3.13)(eslint@8.56.0)(typescript@5.3.3) + '@babel/core': + specifier: ^7.23.7 + version: 7.23.7 + '@babel/plugin-syntax-jsx': + specifier: ^7.23.3 + version: 7.23.3(@babel/core@7.23.7) + '@babel/preset-typescript': + specifier: ^7.23.3 + version: 7.23.3(@babel/core@7.23.7) + '@types/babel-plugin-syntax-jsx': + specifier: ^6.18.2 + version: 6.18.2 + '@types/babel__core': + specifier: ^7.20.5 + version: 7.20.5 '@types/degit': specifier: ^2.8.6 version: 2.8.6 @@ -47,12 +62,18 @@ devDependencies: execa: specifier: ^8.0.1 version: 8.0.1 + fast-glob: + specifier: ^3.3.2 + version: 3.3.2 fs-extra: specifier: ^11.2.0 version: 11.2.0 nypm: specifier: ^0.3.3 version: 0.3.3 + prettier: + specifier: ^3.1.1 + version: 3.1.1 tsup: specifier: ^8.0.1 version: 8.0.1(typescript@5.3.3) @@ -70,6 +91,14 @@ packages: engines: {node: '>=0.10.0'} dev: true + /@ampproject/remapping@2.2.1: + resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + dev: true + /@antfu/eslint-config@2.6.1(@vue/compiler-sfc@3.3.13)(eslint@8.56.0)(typescript@5.3.3): resolution: {integrity: sha512-hj7TTLXLLyk4YHp6SC0G3NTpGyn+5v9EHX3K8JMwz8qIQZnOSzpU8xQ4PcJW3wD3qePVoGDa1Q9QvYCKplIStQ==} hasBin: true @@ -165,6 +194,173 @@ packages: chalk: 2.4.2 dev: true + /@babel/compat-data@7.23.5: + resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/core@7.23.7: + resolution: {integrity: sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw==} + engines: {node: '>=6.9.0'} + dependencies: + '@ampproject/remapping': 2.2.1 + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-compilation-targets': 7.23.6 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helpers': 7.23.7 + '@babel/parser': 7.23.6 + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.7 + '@babel/types': 7.23.6 + convert-source-map: 2.0.0 + debug: 4.3.4(supports-color@8.1.1) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator@7.23.6: + resolution: {integrity: sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + '@jridgewell/gen-mapping': 0.3.3 + '@jridgewell/trace-mapping': 0.3.20 + jsesc: 2.5.2 + dev: true + + /@babel/helper-annotate-as-pure@7.22.5: + resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-compilation-targets@7.23.6: + resolution: {integrity: sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/compat-data': 7.23.5 + '@babel/helper-validator-option': 7.23.5 + browserslist: 4.22.2 + lru-cache: 5.1.1 + semver: 6.3.1 + dev: true + + /@babel/helper-create-class-features-plugin@7.23.7(@babel/core@7.23.7): + resolution: {integrity: sha512-xCoqR/8+BoNnXOY7RVSgv6X+o7pmT5q1d+gGcRlXYkI+9B31glE4jeejhKVpA04O1AtzOt7OSQ6VYKP5FcRl9g==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.7) + '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + semver: 6.3.1 + dev: true + + /@babel/helper-environment-visitor@7.22.20: + resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-function-name@7.23.0: + resolution: {integrity: sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-hoist-variables@7.22.5: + resolution: {integrity: sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-member-expression-to-functions@7.23.0: + resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-module-imports@7.22.15: + resolution: {integrity: sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-module-transforms@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-simple-access': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-validator-identifier': 7.22.20 + dev: true + + /@babel/helper-optimise-call-expression@7.22.5: + resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-plugin-utils@7.22.5: + resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.7): + resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-member-expression-to-functions': 7.23.0 + '@babel/helper-optimise-call-expression': 7.22.5 + dev: true + + /@babel/helper-simple-access@7.22.5: + resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-skip-transparent-expression-wrappers@7.22.5: + resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@babel/helper-split-export-declaration@7.22.6: + resolution: {integrity: sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.23.6 + dev: true + /@babel/helper-string-parser@7.23.4: resolution: {integrity: sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==} engines: {node: '>=6.9.0'} @@ -175,6 +371,22 @@ packages: engines: {node: '>=6.9.0'} dev: true + /@babel/helper-validator-option@7.23.5: + resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helpers@7.23.7: + resolution: {integrity: sha512-6AMnjCoC8wjqBzDHkuqpa7jAKwvMo4dC+lr/TFBz+ucfulO1XMpDnwWPGBNwClOKZ8h6xn5N81W/R5OrcKtCbQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/template': 7.22.15 + '@babel/traverse': 7.23.7 + '@babel/types': 7.23.6 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/highlight@7.23.4: resolution: {integrity: sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==} engines: {node: '>=6.9.0'} @@ -192,6 +404,92 @@ packages: '@babel/types': 7.23.6 dev: true + /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + dev: true + + /@babel/plugin-transform-modules-commonjs@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-module-transforms': 7.23.3(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-simple-access': 7.22.5 + dev: true + + /@babel/plugin-transform-typescript@7.23.6(@babel/core@7.23.7): + resolution: {integrity: sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-annotate-as-pure': 7.22.5 + '@babel/helper-create-class-features-plugin': 7.23.7(@babel/core@7.23.7) + '@babel/helper-plugin-utils': 7.22.5 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.7) + dev: true + + /@babel/preset-typescript@7.23.3(@babel/core@7.23.7): + resolution: {integrity: sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.23.7 + '@babel/helper-plugin-utils': 7.22.5 + '@babel/helper-validator-option': 7.23.5 + '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-modules-commonjs': 7.23.3(@babel/core@7.23.7) + '@babel/plugin-transform-typescript': 7.23.6(@babel/core@7.23.7) + dev: true + + /@babel/template@7.22.15: + resolution: {integrity: sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + dev: true + + /@babel/traverse@7.23.7: + resolution: {integrity: sha512-tY3mM8rH9jM0YHFGyfC0/xf+SB5eKUu7HPj7/k3fpi9dAlsMc5YbQvDi0Sh2QTPXqMhyaAtzAr807TIyfQrmyg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/code-frame': 7.23.5 + '@babel/generator': 7.23.6 + '@babel/helper-environment-visitor': 7.22.20 + '@babel/helper-function-name': 7.23.0 + '@babel/helper-hoist-variables': 7.22.5 + '@babel/helper-split-export-declaration': 7.22.6 + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + debug: 4.3.4(supports-color@8.1.1) + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /@babel/types@7.23.6: resolution: {integrity: sha512-+uarb83brBzPKN38NX1MkB6vb6+mwvR6amUulqAE7ccQw1pEl+bCia9TbdG1lsnFP7lZySvUn37CHyXQdfTwzg==} engines: {node: '>=6.9.0'} @@ -748,6 +1046,39 @@ packages: engines: {node: '>= 6'} dev: true + /@types/babel-plugin-syntax-jsx@6.18.2: + resolution: {integrity: sha512-o2JDgZbRyyLuFAT8QKxtF3uPkT6CDaShykLD9h085xSxesX/1RRhvHbVTSAq8bKpjtqoKb9RddM1q1pDLpVQfg==} + dev: true + + /@types/babel__core@7.20.5: + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + dependencies: + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + '@types/babel__generator': 7.6.8 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.5 + dev: true + + /@types/babel__generator@7.6.8: + resolution: {integrity: sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==} + dependencies: + '@babel/types': 7.23.6 + dev: true + + /@types/babel__template@7.4.4: + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + dependencies: + '@babel/parser': 7.23.6 + '@babel/types': 7.23.6 + dev: true + + /@types/babel__traverse@7.20.5: + resolution: {integrity: sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==} + dependencies: + '@babel/types': 7.23.6 + dev: true + /@types/degit@2.8.6: resolution: {integrity: sha512-y0M7sqzsnHB6cvAeTCBPrCQNQiZe8U4qdzf8uBVmOWYap5MMTN/gB2iEqrIqFiYcsyvP74GnGD5tgsHttielFw==} dev: true @@ -1313,6 +1644,10 @@ packages: engines: {node: ^14.18.0 || >=16.10.0} dev: true + /convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + dev: true + /core-js-compat@3.34.0: resolution: {integrity: sha512-4ZIyeNbW/Cn1wkMMDy+mvrRUxrwFNjKwbhCfQpDd+eLgYipDqp8oGFGtLmhh18EDPKA0g3VUBYOxQGGwvWLVpA==} dependencies: @@ -2050,6 +2385,11 @@ packages: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} dev: true + /gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + dev: true + /get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} @@ -2119,6 +2459,11 @@ packages: path-is-absolute: 1.0.1 dev: true + /globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + dev: true + /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -2374,6 +2719,12 @@ packages: hasBin: true dev: true + /jsesc@2.5.2: + resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} + engines: {node: '>=4'} + hasBin: true + dev: true + /jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -2396,6 +2747,12 @@ packages: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} dev: true + /json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + /jsonc-eslint-parser@2.4.0: resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -2518,6 +2875,12 @@ packages: engines: {node: 14 || >=16.14} dev: true + /lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: true + /lru-cache@6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -2949,6 +3312,12 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prettier@3.1.1: + resolution: {integrity: sha512-22UbSzg8luF4UuZtzgiUOfcGM8s4tjBv6dJRT7j275NXsy2jb4aJa4NNveul5x4eqlF1wuhuR2RElK71RvmVaw==} + engines: {node: '>=14'} + hasBin: true + dev: true + /process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true @@ -3106,6 +3475,11 @@ packages: hasBin: true dev: true + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: true + /semver@7.5.4: resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} engines: {node: '>=10'} @@ -3552,6 +3926,10 @@ packages: engines: {node: '>=10'} dev: true + /yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: true + /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true diff --git a/resources/solid.svg b/resources/solid.svg new file mode 100644 index 0000000..0f6fc65 --- /dev/null +++ b/resources/solid.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/commands/starter.ts b/src/commands/starter.ts index 0339d4a..7a8f593 100644 --- a/src/commands/starter.ts +++ b/src/commands/starter.ts @@ -1,12 +1,20 @@ import * as fs from 'node:fs' import * as path from 'node:path' import { chdir, cwd } from 'node:process' +import fsExtra from 'fs-extra' import type { InputBoxValidationMessage, QuickPickItem } from 'vscode' import { ProgressLocation, QuickPickItemKind, Uri, commands, window } from 'vscode' import { create } from 'create-svelte' import degit from 'degit' import { $ } from 'execa' +import fg from 'fast-glob' import { installDependencies } from 'nypm' +import { transformSync } from '@babel/core' +import pluginSyntaxJSX from '@babel/plugin-syntax-jsx' +import presetTypescript from '@babel/preset-typescript' +import prettierBabel from 'prettier/plugins/babel' +import * as prettier from 'prettier/standalone' +import * as prettierPluginEstree from 'prettier/plugins/estree' import type { Logger, ProjectTemplate, StarterCreateCommandArgs, StarterCreateTriggerData } from '../types' import { fsPath, nextAvailableFilename } from '../shared/utils/fs' import type { Context } from '../shared/vscode/workspace' @@ -14,6 +22,8 @@ import type { PickableSetting } from '../shared/vscode/input' import { showInputBoxWithSettings, showSimpleSettingsEditor } from '../shared/vscode/input' import { config } from '../config' import { getFolderToRunCommandIn, writeStarterTriggerFile } from '../shared/vscode/project' +import { gitIgnoreForCreateSolid } from '../shared/constants' +import { compile } from '../shared/utils/gitignore' import { BaseCommands } from './base' export class StarterCommands extends BaseCommands { @@ -66,6 +76,9 @@ export class StarterCommands extends BaseCommands { case 'create-svelte': await this.handleCreateSvelte(projectName, projectPath!) break + case 'create-solid': + await this.handleCreateSolid(projectName, projectPath!, dir) + break case 'starter-ts': await degit('antfu/starter-ts').clone(`${projectPath}`) break @@ -123,6 +136,84 @@ export class StarterCommands extends BaseCommands { } } + private async handleCreateSolid(projectName: string, projectPath: string, dir: string) { + const templateName = config.createSolidWhichTemplate + await degit(`solidjs/solid-start/examples/${templateName}`, { + force: true, + }).clone(`${projectPath}`) + + const gitignore = compile(gitIgnoreForCreateSolid) + const files = fg.sync('**/*', { cwd: projectPath }).filter(gitignore.accepts) + files.forEach(async (file) => { + const src = `${projectPath}/${file}` + if (src.endsWith('tsconfig.json') && !config.createSolidNeedsTypeScript) { + fsExtra.removeSync(src) + return fsExtra.writeFileSync( + `${projectPath}/jsconfig.json`, + JSON.stringify( + { + compilerOptions: { + jsx: 'preserve', + jsxImportSource: 'solid-js', + paths: { + '~/*': ['./src/*'], + }, + }, + }, + null, + 2, + ), + ) + } + + let code = fsExtra.readFileSync(src).toString() + if (src.includes('vite.config') && !code.includes('ssr: false') && !config.createSolidNeedsSsr) { + code = code + .replace(`start: {`, `start: { ssr: false, `) + .replace(`defineConfig({})`, `defineConfig({ start: { ssr: false } })`) + } + if (src.endsWith('.ts') || src.endsWith('.tsx')) { + if (!config.createSolidNeedsTypeScript) { + const compiledCode = transformSync(code, { + filename: src, + presets: [presetTypescript], + plugins: [pluginSyntaxJSX], + })?.code + + const formatCode = prettier.format(compiledCode ?? '', { + parser: 'babel', + plugins: [prettierBabel, prettierPluginEstree], + }) + fsExtra.removeSync(src) + fsExtra.writeFileSync(src.replace('.ts', '.js'), await formatCode) + } + else { + fsExtra.removeSync(src) + fsExtra.writeFileSync( + src, + await prettier.format(code, { parser: 'babel-ts', plugins: [prettierBabel, prettierPluginEstree] }), + ) + } + } + }) + fsExtra.writeFileSync(`${projectPath}/.gitignore`, gitIgnoreForCreateSolid) + + const pkgFile = path.join(projectPath, 'package.json') + const pkgJson = JSON.parse( + fs + .readFileSync(pkgFile, 'utf-8') + .replace(/"name": ".+"/, _m => `"name": "${projectName}"`) + .replace(/"(.+)": "workspace:.+"/g, (_m, projectName) => `"${projectName}": "next"`), + ) // TODO ^${versions[name]} + + if (!config.createSolidNeedsTypeScript && pkgJson.devDependencies) { + delete pkgJson.devDependencies['@types/node'] + delete pkgJson.devDependencies.typescript + } + + fsExtra.writeFileSync(pkgFile, JSON.stringify(pkgJson, null, 2)) + } + private async handleCreateSvelte(projectName: string, projectPath: string) { await create(projectPath, { name: projectName, @@ -168,9 +259,9 @@ export class StarterCommands extends BaseCommands { args.push(config.createNextAppCustomizeTheDefaultImportAlias) } if (config.globalPackageManager) - args.push(`--use-${config.globalPackageManager}`) + args.push(`--use - ${config.globalPackageManager}`) - await $`npx create-next-app ${projectName} ${args}` + await $`npx create - next - app@latest ${projectName} ${args}` } private async handleCreateVue(projectName: string, dir: string) { @@ -204,7 +295,7 @@ export class StarterCommands extends BaseCommands { else args.push('--eslint') } - await $`npx create-vue ${projectName} ${dir} ${args}` + await $`npx create - vue@latest ${projectName} ${dir} ${args}` } private async createProject() { @@ -303,6 +394,19 @@ export class StarterCommands extends BaseCommands { detail: 'Create new SvelteKit projects', template: { id: 'create-svelte', defaultProjectName: 'svelte-project' }, }, + { + kind: QuickPickItemKind.Separator, + label: 'Solid', + }, + { + label: 'Create Solid(Official Beta)', + iconPath: { + dark: Uri.file(this.context.asAbsolutePath('resources/solid.svg')), + light: Uri.file(this.context.asAbsolutePath('resources/solid.svg')), + }, + detail: 'SolidStart, the Solid app framework', + template: { id: 'create-solid', defaultProjectName: 'solid-project' }, + }, { kind: QuickPickItemKind.Separator, label: 'TypeScript Library', @@ -357,7 +461,7 @@ export class StarterCommands extends BaseCommands { const folderPath = fsPath(folders[0]) this.context.lastUsedNewProjectPath = folderPath - const defaultName = nextAvailableFilename(folderPath, `${template.defaultProjectName}-`) + const defaultName = nextAvailableFilename(folderPath, `${template.defaultProjectName} - `) const name = await this.promptForNameWithSettings(template, defaultName, folderPath) if (!name) return @@ -424,6 +528,9 @@ export class StarterCommands extends BaseCommands { return this.getCurrentCreateSettingsOfCreateNextApp() case 'create-svelte': return [...this.getCurrentCreateSettingsOfCreateSvelte(), ...this.getGlobalSettings()] + case 'create-solid': + return [...this.getCurrentCreateSettingsOfCreateSolid(), ...this.getGlobalSettings()] + default: return this.getGlobalSettings() } @@ -577,7 +684,7 @@ export class StarterCommands extends BaseCommands { currentValue: config.createNextAppNeedsSrcDirectory ? 'Yes' : 'No', description: config.createNextAppNeedsSrcDirectory ? 'Yes' : 'No', detail: '', - label: 'Would you like to use `src/` directory?', + label: 'Would you like to use `src / ` directory?', setValue: (newValue: boolean) => config.setCreateNextAppNeedsSrcDirectory(newValue), settingKind: 'BOOL', }, @@ -665,11 +772,58 @@ export class StarterCommands extends BaseCommands { label: 'Try the Svelte 5 preview (unstable!)?', setValue: (newValue: boolean) => config.setCreateSvelteTrySvelte5Preview(newValue), settingKind: 'BOOL', - } + }, ] return createSvelteSettings } + private getCurrentCreateSettingsOfCreateSolid() { + const createSolidSettings: PickableSetting[] = [ + { + kind: QuickPickItemKind.Separator, + label: 'Create Solid', + }, + { + currentValue: config.createSolidWhichTemplate || 'bare', + description: config.createSolidWhichTemplate || 'bare', + detail: '', + enumValues: [ + 'bare', + 'basic', + 'experiments', + 'hackernews', + 'todomvc', + 'with-auth', + 'with-mdx', + 'with-prisma', + 'with-solid-styled', + 'with-tailwindcss', + 'with-trpc', + ], + label: 'Which Svelte app template?', + setValue: (newValue: 'bare' | 'basic' | 'experiments' | 'hackernews' | 'todomvc' | 'with-auth' | 'with-mdx' | 'with-prisma' | 'with-solid-styled' | 'with-tailwindcss' | 'with-trpc') => config.setCreateSolidWhichTemplate(newValue), + settingKind: 'ENUM', + }, + { + currentValue: config.createSolidNeedsSsr ? 'Yes' : 'No', + description: config.createSolidNeedsSsr ? 'Yes' : 'No', + detail: '', + label: 'Server Side Rendering?', + setValue: (newValue: boolean) => config.setCreateSolidNeedsSsr(newValue), + settingKind: 'BOOL', + }, + { + currentValue: config.createSolidNeedsTypeScript ? 'Yes' : 'No', + description: config.createSolidNeedsTypeScript ? 'Yes' : 'No', + detail: '', + label: 'Use TypeScript?', + setValue: (newValue: boolean) => config.setCreateSolidNeedsTypeScript(newValue), + settingKind: 'BOOL', + }, + ] + return createSolidSettings + } + private validateCreateNextAppImportAlias(input: string): string | InputBoxValidationMessage | undefined | null | Thenable { if (!/^.+\/\*$/.test(input)) diff --git a/src/config.ts b/src/config.ts index a98e7ff..3716a8b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -62,6 +62,10 @@ class Config { get createSvelteNeedsPlaywright(): boolean { return this.getConfig('createSvelte.needsPlaywright', true) } get createSvelteNeedsVitest(): boolean { return this.getConfig('createSvelte.needsVitest', true) } get createSvelteTrySvelte5Preview(): boolean { return this.getConfig('createSvelte.trySvelte5Preview', true) } + // create solid + get createSolidWhichTemplate(): 'bare' | 'basic' | 'experiments' | 'hackernews' | 'todomvc' | 'with-auth' | 'with-mdx' | 'with-prisma' | 'with-solid-styled' | 'with-tailwindcss' | 'with-trpc' { return this.getConfig<'bare' | 'basic' | 'experiments' | 'hackernews' | 'todomvc' | 'with-auth' | 'with-mdx' | 'with-prisma' | 'with-solid-styled' | 'with-tailwindcss' | 'with-trpc'>('createSolid.whichTemplate', 'bare') } + get createSolidNeedsTypeScript(): boolean { return this.getConfig('createSolid.needsTypeScript', true) } + get createSolidNeedsSsr(): boolean { return this.getConfig('createSolid.needsSsr', true) } // global settings get globalNeedsGitInit(): boolean { return this.getConfig('globalSettings.needsGitInit', true) } get globalNeedsInstall(): boolean { return this.getConfig('globalSettings.needsInstall', true) } @@ -91,6 +95,10 @@ class Config { public setCreateSvelteNeedsPlaywright(value: boolean): Promise { return this.setConfig('createSvelte.needsPlaywright', value, ConfigurationTarget.Global) } public setCreateSvelteNeedsVitest(value: boolean): Promise { return this.setConfig('createSvelte.needsVitest', value, ConfigurationTarget.Global) } public setCreateSvelteTrySvelte5Preview(value: boolean): Promise { return this.setConfig('createSvelte.trySvelte5Preview', value, ConfigurationTarget.Global) } + // create solid + public setCreateSolidWhichTemplate(value: 'bare' | 'basic' | 'experiments' | 'hackernews' | 'todomvc' | 'with-auth' | 'with-mdx' | 'with-prisma' | 'with-solid-styled' | 'with-tailwindcss' | 'with-trpc'): Promise { return this.setConfig('createSolid.whichTemplate', value, ConfigurationTarget.Global) } + public setCreateSolidNeedsTypeScript(value: boolean): Promise { return this.setConfig('createSolid.needsTypeScript', value, ConfigurationTarget.Global) } + public setCreateSolidNeedsSsr(value: boolean): Promise { return this.setConfig('createSolid.needsSsr', value, ConfigurationTarget.Global) } // global settings public setGlobalNeedsGitInit(value: boolean): Promise { return this.setConfig('globalSettings.needsGitInit', value, ConfigurationTarget.Global) } public setGlobalNeedsInstall(value: boolean): Promise { return this.setConfig('globalSettings.needsInstall', value, ConfigurationTarget.Global) } diff --git a/src/lib.d.ts b/src/lib.d.ts new file mode 100644 index 0000000..3cc229b --- /dev/null +++ b/src/lib.d.ts @@ -0,0 +1,2 @@ +declare module '@babel/plugin-syntax-jsx' +declare module '@babel/preset-typescript' diff --git a/src/shared/constants.ts b/src/shared/constants.ts index 82274d3..78bfd44 100644 --- a/src/shared/constants.ts +++ b/src/shared/constants.ts @@ -5,3 +5,34 @@ export const projectSearchProgressText = 'Searching for projects...' export const projectSearchProgressNotificationDelayInMs = 2000 export const projectSearchCacheTimeInMs = fiveMinutesInMs export const STARTER_TEMPLATE_CREATE_PROJECT_TRIGGER_FILE = 'starters.create' +export const gitIgnoreForCreateSolid = ` +dist +.solid +.output +.vercel +.netlify +.vinxi +.nitro +netlify + +# Environment +.env +.env*.local + +# dependencies +/node_modules + +# IDEs and editors +/.idea +.project +.classpath +*.launch +.settings/ + +# Temp +gitignore + +# System Files +.DS_Store +Thumbs.db +` diff --git a/src/shared/utils/gitignore.ts b/src/shared/utils/gitignore.ts new file mode 100644 index 0000000..e0c8853 --- /dev/null +++ b/src/shared/utils/gitignore.ts @@ -0,0 +1,93 @@ +export function compile(content: string) { + const parsed = parse(content) + const positives = parsed[0] + const negatives = parsed[1] + return { + accepts(input: string) { + if (input[0] === '/') + input = input.slice(1) + return negatives[0].test(input) || !positives[0].test(input) + }, + denies(input: string) { + if (input[0] === '/') + input = input.slice(1) + return !(negatives[0].test(input) || !positives[0].test(input)) + }, + maybe(input: string) { + if (input[0] === '/') + input = input.slice(1) + return negatives[1].test(input) || !positives[1].test(input) + }, + } +} + +function parse(content: string) { + return content.split('\n') + .map((line) => { + line = line.trim() + return line + }) + .filter((line) => { + return line && line[0] !== '#' + }) + .reduce((lists, line) => { + const isNegative = line[0] === '!' + if (isNegative) + line = line.slice(1) + + if (line[0] === '/') + line = line.slice(1) + if (isNegative) + (lists[1] as string[]).push(line) + + else + (lists[0] as string[]).push(line) + + return lists + }, [[], []]) + .map((list) => { + return list + .sort() + .map(prepareRegexes) + .reduce((list, prepared) => { + (list[0] as string[]).push(prepared[0]); + (list[1] as string[]).push(prepared[1]) + return list + }, [[], [], []]) + }) + .map((item) => { + return [ + item[0].length > 0 ? new RegExp(`^((${item[0].join(')|(')}))`) : new RegExp('$^'), + item[1].length > 0 ? new RegExp(`^((${item[1].join(')|(')}))`) : new RegExp('$^'), + ] + }) +} + +function prepareRegexes(pattern: string) { + return [ + // exact regex + prepareRegexPattern(pattern), + // partial regex + preparePartialRegex(pattern), + ] +}; + +function prepareRegexPattern(pattern: string) { + return escapeRegex(pattern).replace('**', '(.+)').replace('*', '([^\\/]+)') +} + +function preparePartialRegex(pattern: string) { + return pattern + .split('/') + .map((item, index) => { + if (index) + return `([\\/]?(${prepareRegexPattern(item)}\\b|$))` + else + return `(${prepareRegexPattern(item)}\\b)` + }) + .join('') +} + +function escapeRegex(pattern: string) { + return pattern.replace(/[\-\[\]\/\{\}\(\)\+\?\.\\\^\$\|]/g, '\\$&') +} diff --git a/tsup.config.ts b/tsup.config.ts index a8123da..dcf3b00 100644 --- a/tsup.config.ts +++ b/tsup.config.ts @@ -12,6 +12,6 @@ export default defineConfig({ 'vscode', ], async onSuccess() { - fs.copySync('./node_modules/create-svelte/dist', './dist/dist', { overwrite: true }); + fs.copySync('./node_modules/create-svelte/dist', './dist/dist', { overwrite: true }) }, })