diff --git a/mod.ts b/mod.ts index 0dd9611..5116c4c 100644 --- a/mod.ts +++ b/mod.ts @@ -1,17 +1,20 @@ import { join } from "./src/path.ts" import { listLog } from "./src/log.ts" -import { cyan, green, yellow } from "./src/color.ts" +import { cyan, green, red, yellow } from "./src/color.ts" import { execa, normalFusing } from "./src/process.ts" import { isPackageManager, usePackageManager } from "./src/pm.ts" import { exist, findUpNodeModules, findUpPackageJson } from "./src/fs.ts" import { extractDeps, extractDepsFromPackageJson } from "./src/extract.ts" -const { - staging, - ref: pm, - getCommand, - select: selectPM, -} = usePackageManager() +const { staging, ref: pm, getCommand, select: selectPM } = usePackageManager() + +export function install(deps: string[]) { + return execa([ + pm.value ?? "npm", + pm.value === "yarn" ? "add" : "install", + ...deps, + ]) +} export async function hopeCreateProject() { if (Deno.args[0] !== "create") { @@ -34,11 +37,7 @@ export async function ensureProjectInit() { } const wantInited = confirm( - `🫣 ${ - yellow( - " package.json does not exist", - ) - }, whether to initialize?`, + `🫣 ${yellow(" package.json does not exist")}, whether to initialize?`, ) if (!wantInited) { @@ -93,11 +92,7 @@ async function refresh() { function here(see = Deno.args[0] === "here") { if (see) { console.log( - `🦖 The manager of the current directory is ${ - cyan( - pm.value ?? "null", - ) - }`, + `🦖 The manager of the current directory is ${cyan(pm.value ?? "null")}`, ) } @@ -111,10 +106,10 @@ async function autoInstall( } const baseDir = Deno.cwd() - const packageJsonPath = await findUpPackageJson(baseDir) || "" + const packageJsonPath = (await findUpPackageJson(baseDir)) || "" const depsInPackageJson = await extractDepsFromPackageJson(packageJsonPath) - const nodeModulesPath = await findUpNodeModules(baseDir) || "" + const nodeModulesPath = (await findUpNodeModules(baseDir)) || "" const depsNotInstalled = await Promise.all( depsInPackageJson.map(async (dep) => { @@ -124,44 +119,44 @@ async function autoInstall( const deps = await extractDeps(baseDir) - const depsNotInPackageJson = deps.filter((dep) => - !depsInPackageJson.includes(dep) + const depsNotInPackageJson = deps.filter( + (dep) => !depsInPackageJson.includes(dep), ) const depsToInstall = depsNotInPackageJson.concat(depsNotInstalled) if (depsToInstall.length) { - console.log( - `📂 The dependencies are detected from ${yellow("files")}`, - ) - console.log(listLog(depsNotInPackageJson)) + const filesText = yellow("files") + const packageText = green("package.json") + + const FL = depsNotInPackageJson.length + const PL = depsInPackageJson.length + if (FL) { + console.log(`📂 The dependencies are detected from ${filesText} (${FL})`) + console.log(listLog(depsNotInPackageJson)) + } - console.log( - `🌳 The dependencies are detected from ${green("package.json")}`, - ) - console.log(listLog(depsInPackageJson)) + if (PL) { + console.log( + `🌳 The dependencies are detected from ${packageText} (${PL})`, + ) + console.log(listLog(depsInPackageJson)) + } + + const TL = FL + PL const wantInstallDeps = confirm( - `📂 Whether to install dependencies from ${ - yellow( - "files", - ) - } and from ${ - green( - "package.json", - ) - } ?`, + `📂 Whether to install dependencies from ${filesText} or from ${packageText} ${TL}?`, ) if (wantInstallDeps) { - await execa([ - pm.value ?? "npm", - pm.value === "yarn" ? "add" : "install", - ...depsToInstall, - ]) + await install(depsToInstall) + console.log(`✅ Automatic install successfully`) + } else { + console.log(`❎ ${red("Automatic install failed")}`) } } - console.log(`✅ Automatic install successfully`) + return true } const tasks = [ diff --git a/src/extract.ts b/src/extract.ts index 865d8fc..3d02aae 100644 --- a/src/extract.ts +++ b/src/extract.ts @@ -16,27 +16,36 @@ export function uniqueDeps(...depsArray: string[][]) { return Array.from(new Set(depsArray.flat())) } +const dynamicSpecifiersReg = /(?<=(import|require)\( *?(['"]))\w*?(?=\2)/g +const staticSpecifiersReg = /(?<=(import|from) *?(["']))\w*?(?=\2)/g + export function extractSpecifier(code: string) { - return code.match( - /(?<=(require|import)\(|(from|import)\s+)(['"]).*?(?=\2)/g, - ) || [] + const dynamicSpecifiers = code.match(dynamicSpecifiersReg) || [] + const staticSpecifiers = code.match(staticSpecifiersReg) || [] + return [...dynamicSpecifiers, ...staticSpecifiers] } export function eliminateComments(code: string) { return code.replace(/\/\/.*|\/\*.*?\*\//g, "") } +const effectiveSpecifierReg = /^\w|@/ + export function filterDeps(specifiers: string[]) { - return specifiers.filter((specifier) => - !specifier.startsWith(".") && !isBuiltin(specifier) && - !specifier.startsWith("node:") && !specifier.startsWith("#") - ).map((specifier) => { - if (specifier.startsWith("@")) { - const [organization, pkg] = specifier.split("/") - return `${organization}/${pkg}` - } - return specifier.replace(/\/.*/, "") - }) + return specifiers + .filter( + (specifier) => + effectiveSpecifierReg.test(specifier) && + !isBuiltin(specifier) && + !specifier.startsWith("node:"), + ) + .map((specifier) => { + if (specifier.startsWith("@")) { + const [organization, pkg] = specifier.split("/") + return `${organization}/${pkg}` + } + return specifier.replace(/\/.*/, "") + }) } export async function readCodes(base: string) { @@ -68,7 +77,7 @@ export async function extractDeps(base: string) { } export async function extractDepsFromPackageJson(packageJsonPath: string) { - if (!await exist(packageJsonPath)) { + if (!(await exist(packageJsonPath))) { return [] } const packageJsonText = await Deno.readTextFile(packageJsonPath) diff --git a/src/pm.ts b/src/pm.ts index f1509d8..1232702 100644 --- a/src/pm.ts +++ b/src/pm.ts @@ -14,9 +14,9 @@ export function usePackageManager() { // Check if the value of ref exists if (ref.value) return // Set the value of ref based on the existence of certain files - ref.value = await exist("pnpm-lock.yaml") + ref.value = (await exist("pnpm-lock.yaml")) ? "pnpm" - : await exist("yarn.lock") + : (await exist("yarn.lock")) ? "yarn" : "npm" } @@ -41,10 +41,10 @@ export function usePackageManager() { } async function select() { - ref.value = await Select.prompt({ + ref.value = (await Select.prompt({ message: "select your package manager", options: pms, - }) as PackageManager + })) as PackageManager } return { ref, staging, getCommand, select }