diff --git a/packages/commands/src/handlers/add.ts b/packages/commands/src/handlers/add.ts index a3a479f..5b1f48c 100644 --- a/packages/commands/src/handlers/add.ts +++ b/packages/commands/src/handlers/add.ts @@ -43,9 +43,8 @@ const handleAutocompleteAdd = async () => { { label: t.NO, value: false }, { label: t.YES_FORCE, value: [true, "force"] }, ], - message: `${t.CONFIRM_INSTALL(a.length)} \n${color.red(S_BAR)} \n${color.red(S_BAR)} ${ - " " + color.yellow(a.map((opt) => opt.label).join(" ")) + " " - } \n${color.red(S_BAR)} `, + message: `${t.CONFIRM_INSTALL(a.length)} \n${color.red(S_BAR)} \n${color.red(S_BAR)} ${" " + color.yellow(a.map((opt) => opt.label).join(" ")) + " " + } \n${color.red(S_BAR)} `, }), ); @@ -114,16 +113,19 @@ export const handleAdd = async (packages?: string[], forceTransform: boolean = f for (let i = 0; i < configs.length; i++) { const config = configs[i]; - config.installs.forEach((p) => queueUpdate({ type: "package", name: p })); + config.installs.forEach((p) => queueUpdate({ type: "package", name: p, dev: false })); + config.installsDev?.forEach((p) => queueUpdate({ type: "package", name: p, dev: true })); } // Queue primitives for (const primitive of await transformPrimitives(possiblePrimitives)) { - queueUpdate({ type: "package", name: primitive.value }); + queueUpdate({ type: "package", name: primitive.value, dev: false }); } if (!configs.length) return; - - await spinnerify({ + const pluginOptions = configs.map((c) => c.pluginOptions).filter(Boolean) as PluginOptions[]; + if (pluginOptions.length) { + const appConfig = await getAppConfig(); + await spinnerify({ startText: "Processing config", finishText: "Config processed", fn: async () => { @@ -136,6 +138,7 @@ export const handleAdd = async (packages?: string[], forceTransform: boolean = f await writeFile(appConfig, code); }, }); + } p.log.info("Preparing post install steps for integrations"); @@ -174,8 +177,7 @@ export const handleAdd = async (packages?: string[], forceTransform: boolean = f if (fileUpdates.length) p.log.message([`${color.cyan("Modify")}`, ...fileUpdates.map((f) => ` - ${f}`)].join("\n")); if (packageUpdates.length) - p.log.message([`${color.cyan("Install")}`, ...packageUpdates.map((p) => ` - ${p}`)].join("\n")); - + p.log.message([`${color.cyan("Install")}`, ...packageUpdates.map((p) => ` - ${p.name}` + (p.dev ? " (dev)" : ""))].join("\n")); if (commandUpdates.length) p.log.message([`${color.cyan("Run commands")}`, ...commandUpdates.map((p) => ` - ${p}`)].join("\n")); @@ -192,8 +194,7 @@ export const handleAdd = async (packages?: string[], forceTransform: boolean = f if (postInstalls.length === 0) return; p.log.message( - `${postInstalls.length} ${ - postInstalls.length === 1 ? "package has" : "packages have" + `${postInstalls.length} ${postInstalls.length === 1 ? "package has" : "packages have" } post install steps that need to run.`, ); diff --git a/packages/commands/src/lib/integrations.ts b/packages/commands/src/lib/integrations.ts index 52c14a9..8aef2c8 100644 --- a/packages/commands/src/lib/integrations.ts +++ b/packages/commands/src/lib/integrations.ts @@ -7,8 +7,8 @@ import { createSignal } from "@solid-cli/reactivity"; import * as p from "@clack/prompts"; import color from "picocolors"; import { cancelable } from "@solid-cli/ui"; -import { PluginOptions } from "@chialab/esbuild-plugin-meta-url"; import { flushQueue } from "@solid-cli/utils/updates"; +import { PluginOptions } from "@solid-cli/utils/transform"; // All the integrations/packages that we support export type Supported = keyof typeof integrations; @@ -16,6 +16,7 @@ export type Supported = keyof typeof integrations; export type IntegrationsValue = { pluginOptions?: PluginOptions; installs: string[]; + installsDev?: string[]; additionalConfig?: () => Promise; postInstall?: () => Promise; }; @@ -24,7 +25,7 @@ export type Integrations = Record; export const [rootFile, setRootFile] = createSignal(undefined); -export const integrations = { +export const integrations: Record = { "tailwind": { installs: ["tailwindcss", "postcss", "autoprefixer"], postInstall: async () => { @@ -79,7 +80,8 @@ export const integrations = { isDefault: true, options: {}, }, - installs: ["unocss"], + installs: [""], + installsDev: ["unocss"], additionalConfig: async () => { const path = rootFile(); if (!path) return; @@ -110,7 +112,8 @@ export const integrations = { }, }, "vitest": { - installs: [ + installs: [], + installsDev: [ "vitest", "jsdom", "@solidjs/testing-library", @@ -119,7 +122,7 @@ export const integrations = { ], additionalConfig: async () => { try { - p.log.info("Adding test script to package.json"); + p.log.info("Adding test script to package.json"); const packageJsonString = await readFile("package.json", "utf8"); const packageJson = JSON.parse(packageJsonString); if (!/\bvitest\b/.test(packageJson.scripts.test || "")) { @@ -128,7 +131,7 @@ export const integrations = { } const hasTs = fileExists("tsconfig.json"); if (hasTs) { - p.log.info("Adding testing types to tsconfig.json"); + p.log.info("Adding testing types to tsconfig.json"); const tsConfigString = await readFile("tsconfig.json", "utf8"); const tsConfig = JSON.parse(tsConfigString); if (!tsConfig.compilerOptions) { @@ -145,8 +148,8 @@ export const integrations = { (suffix) => !fileExists(`vite.config.${suffix}`) && !fileExists(`vitest.config.${suffix}`), ) ) { - const suffix = hasTs ? "ts" : "mjs"; - p.log.info(`Adding vitest.config.${suffix}`); + const suffix = hasTs ? "ts" : "mjs"; + p.log.info(`Adding vitest.config.${suffix}`); await writeFile( `vitest.config.${suffix}`, `import solid from "vite-plugin-solid"; diff --git a/packages/commands/src/lib/utils/helpers.ts b/packages/commands/src/lib/utils/helpers.ts index ca27ccd..c56ac54 100644 --- a/packages/commands/src/lib/utils/helpers.ts +++ b/packages/commands/src/lib/utils/helpers.ts @@ -27,7 +27,12 @@ export function validateFilePath(path: string, lookingFor: string): string | und export function validateFilePath(path: string, lookingFor: string[]): string | undefined; export function validateFilePath(path: string, lookingFor: string | string[]): string | undefined { path = resolve(path); - const isDir = lstatSync(path).isDirectory(); + let isDir: boolean; + try { + console.log(path) + isDir = lstatSync(path).isDirectory(); + } + catch (e) { return undefined } if (isDir) { const files = readdirSync(path, { withFileTypes: true }); @@ -58,9 +63,11 @@ export async function findFiles( let { depth = Infinity, ignoreDirs = ["node_modules", "."], startsWith = true } = opts; startPath = resolve(startPath); - - const isDir = lstatSync(startPath).isDirectory(); - + let isDir: boolean; + try { + isDir = lstatSync(startPath).isDirectory(); + } + catch (e) { return [] }; if (!isDir) { startPath = resolve(startPath.slice(0, startPath.lastIndexOf("/"))); } diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 2ec94ff..c358bb3 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -95,17 +95,23 @@ const main = async () => { version, }); const args = process.argv.slice(2); + try { - if (args.length === 0) { - await provideSuggestions(); - return; - } + if (args.length === 0) { + await provideSuggestions(); + return; + } - if (args.length === 1 && args[0] === "start") { - await provideStartSuggestions(); - return; - } + if (args.length === 1 && args[0] === "start") { + await provideStartSuggestions(); + return; + } - await run(cli, args); + await run(cli, args); + } + catch (e) { + console.error(e); + process.exit(1); + } }; main(); diff --git a/packages/utils/src/updates/index.ts b/packages/utils/src/updates/index.ts index 749c841..e996680 100644 --- a/packages/utils/src/updates/index.ts +++ b/packages/utils/src/updates/index.ts @@ -7,13 +7,13 @@ declare global { // Batch all updates here, so we can confirm with the user then flush export const UPDATESQUEUE: Update[] = globalThis.UPDATESQUEUE ?? []; globalThis.UPDATESQUEUE = UPDATESQUEUE; -type PackageUpdate = { type: "package"; name: string }; +type PackageUpdate = { type: "package"; name: string; dev: boolean }; type CommandUpdate = { type: "command"; name: string }; type FileUpdate = { type: "file"; name: string; contents: string; checked: boolean }; // Don't bother explicitly handling plugin updates, since they're just a file update export type Update = PackageUpdate | CommandUpdate | FileUpdate; type UpdateSummary = { - packageUpdates: string[]; + packageUpdates: PackageUpdate[]; commandUpdates: string[]; fileUpdates: string[]; }; @@ -23,7 +23,7 @@ export const clearQueue = () => { }; export const summarizeUpdates = (): UpdateSummary => { const fileUpdates = UPDATESQUEUE.filter((u) => u.type === "file").map((s) => s.name); - const packageUpdates = UPDATESQUEUE.filter((u) => u.type === "package").map((s) => s.name); + const packageUpdates = UPDATESQUEUE.filter((u) => u.type === "package") as PackageUpdate[]; const commandUpdates = UPDATESQUEUE.filter((u) => u.type === "command").map((s) => s.name); return { packageUpdates, commandUpdates, fileUpdates }; }; @@ -64,7 +64,12 @@ export const flushPackageUpdates = async () => { const pM = detectPackageManager(); const instlCmd = getInstallCommand(pM); for (const update of packageUpdates) { - await $`${pM.name} ${instlCmd} ${update.name}`; + if (update.dev) { + await $`${pM.name} ${instlCmd} -D ${update.name}`; + } + else { + await $`${pM.name} ${instlCmd} ${update.name}`; + } } }; export const flushCommandUpdates = async () => {