From f395eb103c81d760abeb2966368bc5acc8d7b1ce Mon Sep 17 00:00:00 2001 From: RoachxD Date: Wed, 19 Jul 2023 15:34:27 +0300 Subject: [PATCH 1/4] refactor(init): simplify code and update randomArrayValue options - Refactor imports to use absolute paths. - Use `join` as `pathJoin` for increased clarity. - Simplify the code by using optional chaining and destructuring assignment. - Update the list of `randomArrayValue` options. - Use `inquirer.prompt` with an array of questions to simplify the code. --- packages/create-suid/src/actions/init.ts | 146 ++++++++++++----------- 1 file changed, 78 insertions(+), 68 deletions(-) diff --git a/packages/create-suid/src/actions/init.ts b/packages/create-suid/src/actions/init.ts index 5fa32e432..6e670a5a1 100644 --- a/packages/create-suid/src/actions/init.ts +++ b/packages/create-suid/src/actions/init.ts @@ -1,18 +1,17 @@ +import appFile from "../files/appFile.js"; +import entryFile from "../files/entryFile.js"; +import htmlFile from "../files/htmlFile.js"; +import pkgFile from "../files/pkgFile.js"; +import tsconfigFile from "../files/tsconfigFile.js"; +import viteConfigFile from "../files/viteConfigFile.js"; import { randomArrayValue } from "../utils/array.js"; -import appFile from "./../files/appFile.js"; -import entryFile from "./../files/entryFile.js"; -import htmlFile from "./../files/htmlFile.js"; -import pkgFile from "./../files/pkgFile.js"; -import tsconfigFile from "./../files/tsconfigFile.js"; -import viteConfigFile from "./../files/viteConfigFile.js"; -import { createFiles, isEmptyDir } from "./../utils/fs.js"; +import { createFiles, isEmptyDir } from "../utils/fs.js"; import chalk from "chalk"; -import inquirer from "inquirer"; -import { basename, join } from "path"; +import inquirer, { Answers } from "inquirer"; +import { basename, join as pathJoin } from "path"; -export default async function init(defaultOutputDir?: string) { +export default async function init(outputDir?: string) { const cwd = process.cwd(); - let workingDir: string | undefined; const excluded = [ ".history", "node_modules", @@ -21,19 +20,20 @@ export default async function init(defaultOutputDir?: string) { "README.md", "LICENSE", ]; - if (!defaultOutputDir) - defaultOutputDir = (await isEmptyDir(cwd, excluded)) - ? "./" - : "./suid-project"; + outputDir ||= (await isEmptyDir(cwd, excluded)) ? "./" : "./suid-project"; - while (typeof workingDir !== "string") { - const answer: { value: string } = await inquirer.prompt({ - type: "input", - name: "value", - message: "Output dir", - default: defaultOutputDir, - }); - const path = join(cwd, (defaultOutputDir = answer.value)); + let workingDir: string | undefined; + while (!workingDir) { + outputDir = await inquirer + .prompt({ + type: "input", + name: "outputDir", + message: "Output dir", + default: outputDir, + }) + .then(({ outputDir }: Answers) => outputDir); + + const path = pathJoin(cwd, outputDir ?? ""); if (await isEmptyDir(path, excluded)) { workingDir = path; } else { @@ -41,55 +41,54 @@ export default async function init(defaultOutputDir?: string) { } } - const projectName = await inquirer.prompt({ - type: "input", - name: "value", - message: "Project name", - default: basename(workingDir), - }); - - const pkgManager = await inquirer.prompt({ - type: "list", - name: "value", - message: "Select a package manager", - default: "pnpm", - choices: [ - { - name: "npm", - }, - { - name: "pnpm", - }, - ], - }); - - const pkgs = await inquirer.prompt({ - type: "checkbox", - name: "value", - message: "Select the packages", - choices: [ - { - name: "@suid/material", - checked: true, - }, - { - name: "@suid/icons-material", - checked: true, - }, - ], - }); - + const { projectName, pkgManager, pkgs } = await inquirer.prompt([ + { + type: "input", + name: "projectName", + message: "Project name", + default: basename(workingDir), + }, + { + type: "list", + name: "pkgManager", + message: "Select a package manager", + default: "pnpm", + choices: [ + { + name: "npm", + }, + { + name: "pnpm", + }, + ], + }, + { + type: "checkbox", + name: "pkgs", + message: "Select the packages", + choices: [ + { + name: "@suid/material", + checked: true, + }, + { + name: "@suid/icons-material", + checked: true, + }, + ], + }, + ]); await createFiles( { "src/index.tsx": entryFile(), "src/App.tsx": appFile(), "index.html": htmlFile({ - title: projectName.value, + title: projectName, }), "tsconfig.json": tsconfigFile(), "package.json": await pkgFile({ - name: projectName.value, - deps: pkgs.value, + name: projectName, + deps: pkgs, devDeps: ["@suid/vite-plugin"], }), "vite.config.ts": viteConfigFile(), @@ -102,11 +101,22 @@ export default async function init(defaultOutputDir?: string) { console.info(); console.info("Run the next commands:"); console.info(); - console.info(chalk.cyan(` cd ${defaultOutputDir}`)); - console.info(chalk.cyan(` ${pkgManager.value} install`)); - console.info(chalk.cyan(` ${pkgManager.value} start`)); + console.info(chalk.cyan(` cd ${outputDir}`)); + console.info(chalk.cyan(` ${pkgManager} install`)); + console.info(chalk.cyan(` ${pkgManager} start`)); console.info(); console.info( - `And have a ${randomArrayValue(["happy", "good", "nice", "great"])} day! 😃` + `And have a ${randomArrayValue([ + "great", + "wonderful", + "fantastic", + "amazing", + "lovely", + "splendid", + "marvelous", + "fabulous", + "terrific", + "delightful", + ])} day! 😃` ); } From 4c2b664386195c12ccf54a92c31047242c684eed Mon Sep 17 00:00:00 2001 From: RoachxD Date: Wed, 19 Jul 2023 18:03:57 +0300 Subject: [PATCH 2/4] refactor(pkgFile): optimize package file generation code - `dependencies` and `devDependencies` objects are extracted from `siteManifest` and assigned default values of `{}` to avoid repeatedly accessing the same properties. - `reduce` calls in the `dependencies` and `devDependencies` properties have been replaced with `map` calls and the spread operator has been replaced with `Object.assign`. This avoids creating new objects on each iteration of the `reduce` function. - The optional chaining operator (`?.`) has been removed from the `options.deps` and `options.devDeps` properties and replaced with nullish coalescing operator (`??`) and an empty array. This ensures that the `map` function is always called on an array, even if the property is `undefined`. --- packages/create-suid/src/files/pkgFile.ts | 35 ++++++++++------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/packages/create-suid/src/files/pkgFile.ts b/packages/create-suid/src/files/pkgFile.ts index 24575d3fd..71263b418 100644 --- a/packages/create-suid/src/files/pkgFile.ts +++ b/packages/create-suid/src/files/pkgFile.ts @@ -6,12 +6,11 @@ export default async function pkgFile(options: { devDeps?: string[]; }) { const siteManifest = await fetchLatestManifest("@suid/site"); + const dependencies = siteManifest.dependencies ?? {}; + const devDependencies = siteManifest.devDependencies ?? {}; const dep = (name: string, caret?: boolean) => { - const ver = - siteManifest.dependencies?.[name] ?? - siteManifest.devDependencies?.[name] ?? - "*"; + const ver = dependencies[name] ?? devDependencies[name] ?? "*"; return { [name]: caret && /^\d/.test(ver) ? `^${ver}` : ver, }; @@ -26,22 +25,18 @@ export default async function pkgFile(options: { build: "vite build", start: "vite", }, - dependencies: { - ...options.deps?.reduce( - (deps, name) => ({ ...deps, ...dep(name, true) }), - {} as Record - ), - ...dep("solid-js"), - }, - devDependencies: { - ...options.devDeps?.reduce( - (deps, name) => ({ ...deps, ...dep(name, true) }), - {} as Record - ), - typescript: "^4.8.2", - ...dep("vite"), - ...dep("vite-plugin-solid"), - }, + dependencies: Object.assign( + {}, + ...(options.deps ?? []).map((name) => dep(name, true)), + dep("solid-js") + ), + devDependencies: Object.assign( + {}, + ...(options.devDeps ?? []).map((name) => dep(name, true)), + { typescript: "^4.8.2" }, + dep("vite"), + dep("vite-plugin-solid") + ), }, null, 2 From 67de8acb80881c977fb84da36fff20c95b7388f1 Mon Sep 17 00:00:00 2001 From: RoachxD Date: Wed, 19 Jul 2023 18:21:36 +0300 Subject: [PATCH 3/4] refactor(functions): optimize `isEmptyDir` and `createFiles` - Replace `for` loop with `every` method in `isEmptyDir`. - Replace `for` loop with `Promise.all` and `map` in `createFiles`. - Rename `join` import from `path` to `pathJoin` for increased clarity. - Add comment to `catch` block in `safeStat`. - Improve readability with line breaks and optional chaining. --- packages/create-suid/src/utils/fs.ts | 40 +++++++++++++++------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/packages/create-suid/src/utils/fs.ts b/packages/create-suid/src/utils/fs.ts index 78dbf9b77..858b65d65 100644 --- a/packages/create-suid/src/utils/fs.ts +++ b/packages/create-suid/src/utils/fs.ts @@ -1,36 +1,38 @@ import { mkdir, readdir, stat, writeFile } from "fs/promises"; -import { dirname, join } from "path"; +import { dirname, join as pathJoin } from "path"; export async function safeStat(path: string) { try { return await stat(path); - // eslint-disable-next-line no-empty - } catch (error) {} + } catch (error) { + // Do nothing + } } export async function isEmptyDir(path: string, exclude?: string[]) { const info = await safeStat(path); - if (!info) return true; - if (info.isFile()) return false; - const files = await readdir(path); - for (const file of files) { - if (exclude && exclude.includes(file)) { - continue; - } else { - return false; - } + if (!info) { + return true; + } + + if (info.isFile()) { + return false; } - return true; + + const files = await readdir(path); + return files.every((file) => exclude?.includes(file)); } export async function createFiles( files: Record, baseDir = process.cwd() ) { - for (const name in files) { - const path = join(baseDir, name); - const dir = dirname(path); - await mkdir(dir, { recursive: true }); - await writeFile(path, files[name]); - } + await Promise.all( + Object.entries(files).map(async ([name, content]) => { + const path = pathJoin(baseDir, name); + const dir = dirname(path); + await mkdir(dir, { recursive: true }); + await writeFile(path, content); + }) + ); } From 2067b93093d147bf36f2df62fdcba3c30e1f9b51 Mon Sep 17 00:00:00 2001 From: RoachxD Date: Thu, 20 Jul 2023 13:25:30 +0300 Subject: [PATCH 4/4] refactor(npm): use `get` instead of `request` - Use `get` method from `https` module instead of `request` to simplify the code. - Remove unnecessary `req.end()` call. - Change `close` event to `end` event for resolving the promise. --- packages/create-suid/src/utils/npm.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/packages/create-suid/src/utils/npm.ts b/packages/create-suid/src/utils/npm.ts index e00404917..7b5c5eeb9 100644 --- a/packages/create-suid/src/utils/npm.ts +++ b/packages/create-suid/src/utils/npm.ts @@ -1,4 +1,4 @@ -import { request } from "https"; +import { get } from "https"; export async function fetchLatestManifest(name: string) { const url = `https://registry.npmjs.org/${name}/latest`; @@ -8,13 +8,11 @@ export async function fetchLatestManifest(name: string) { dependencies?: Record; devDependencies?: Record; }>((resolve, reject) => { - let json = ""; - const req = request(url, (res) => { + get(url, (res) => { + let json = ""; res.on("data", (chunk) => (json += chunk)); - res.on("close", () => resolve(JSON.parse(json))); - }); - req.on("error", reject); - req.end(); + res.on("end", () => resolve(JSON.parse(json))); + }).on("error", reject); }); }