| import { AsyncLocalStorage } from 'node:async_hooks'; | ||
| import { consola } from 'consola'; | ||
| import { resolve as resolve$1 } from 'pathe'; | ||
| import { existsSync } from 'node:fs'; | ||
| import fsp from 'node:fs/promises'; | ||
| import { findFile } from 'pkg-types'; | ||
| import * as nypm from 'nypm'; | ||
| function resolve(path) { | ||
| const ctx = useContext(); | ||
| return resolve$1(ctx.cwd, path); | ||
| } | ||
| async function exists(path, opts) { | ||
| if (opts?.withAnyExt) { | ||
| const ctx = useContext(); | ||
| const files = await fsp.readdir(ctx.cwd); | ||
| return files.some((file) => file.startsWith(path)); | ||
| } | ||
| const resolvedPath = resolve(path); | ||
| return existsSync(resolvedPath); | ||
| } | ||
| async function existsWithAnyExt(path) { | ||
| return exists(path, { withAnyExt: true }); | ||
| } | ||
| async function read(path) { | ||
| const resolvedPath = resolve(path); | ||
| try { | ||
| return await fsp.readFile(resolvedPath, "utf8"); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| async function readLines(path) { | ||
| const contents = await read(path); | ||
| return contents?.split("\n") || void 0; | ||
| } | ||
| async function write(path, contents, opts) { | ||
| const ctx = useContext(); | ||
| const resolvedPath = resolve(path); | ||
| if (opts?.skipIfExists && existsSync(resolvedPath)) | ||
| return; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Writing \`${path}\``); | ||
| } | ||
| await fsp.writeFile(resolvedPath, contents); | ||
| } | ||
| async function remove(path, opts) { | ||
| const ctx = useContext(); | ||
| const resolvedPath = resolve(path); | ||
| if (!existsSync(resolvedPath)) | ||
| return; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Removing \`${path}\``); | ||
| } | ||
| try { | ||
| await fsp.rm(resolvedPath, { recursive: true }); | ||
| } catch { | ||
| } | ||
| } | ||
| async function findUp(name) { | ||
| const ctx = useContext(); | ||
| try { | ||
| return await findFile(name, { startingFrom: ctx.cwd }); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| async function update(path, fn, opts) { | ||
| const ctx = useContext(); | ||
| const contents = await read(path); | ||
| if (!contents) | ||
| return contents; | ||
| const updatedContents = await fn(contents); | ||
| if (contents === updatedContents) | ||
| return contents; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Updating \`${path}\``); | ||
| } | ||
| await write(path, updatedContents, { log: false }); | ||
| return updatedContents; | ||
| } | ||
| async function append(path, contents, opts) { | ||
| const sep = opts?.newLine === false ? "" : "\n"; | ||
| return update(path, (existing) => existing + sep + contents); | ||
| } | ||
| const _fs = { | ||
| __proto__: null, | ||
| append: append, | ||
| exists: exists, | ||
| existsWithAnyExt: existsWithAnyExt, | ||
| findUp: findUp, | ||
| read: read, | ||
| readLines: readLines, | ||
| remove: remove, | ||
| resolve: resolve, | ||
| update: update, | ||
| write: write | ||
| }; | ||
| async function readJSON(path) { | ||
| const contents = await read(path); | ||
| return contents ? JSON.parse(contents) : void 0; | ||
| } | ||
| async function writeJSON(path, json, opts) { | ||
| await write(path, JSON.stringify(json, void 0, 2), opts); | ||
| } | ||
| async function updateJSON(path, updater) { | ||
| let updated; | ||
| await update(path, async (existing) => { | ||
| const json = JSON.parse(existing || "{}"); | ||
| updated = await updater(json) || json; | ||
| return JSON.stringify(updated, void 0, 2); | ||
| }); | ||
| return updated; | ||
| } | ||
| const _json = { | ||
| __proto__: null, | ||
| readJSON: readJSON, | ||
| updateJSON: updateJSON, | ||
| writeJSON: writeJSON | ||
| }; | ||
| async function readPackageJSON() { | ||
| const path = await findUp("package.json"); | ||
| if (!path) { | ||
| return void 0; | ||
| } | ||
| return readJSON(path); | ||
| } | ||
| async function updatePackageJSON(fn) { | ||
| const path = await findUp("package.json"); | ||
| if (!path) { | ||
| return; | ||
| } | ||
| await updateJSON(path, fn); | ||
| } | ||
| async function addDependency(name, opts) { | ||
| const context = useContext(); | ||
| if (opts?.log !== false) { | ||
| if (typeof name === "string") { | ||
| context.logger.info(`Adding ${name} dependency`); | ||
| } else { | ||
| context.logger.info(`Adding ${name.join(", ")} dependencies`); | ||
| } | ||
| } | ||
| await nypm.addDependency(name, { | ||
| cwd: context.cwd, | ||
| ...opts | ||
| }); | ||
| } | ||
| async function addDevDependency(name, opts) { | ||
| await addDependency(name, { dev: true, ...opts }); | ||
| } | ||
| async function removeDependency(name, opts) { | ||
| const context = useContext(); | ||
| if (opts?.log !== false) { | ||
| context.logger.info(`Removing ${name} dependency`); | ||
| } | ||
| await nypm.removeDependency(name, { | ||
| cwd: context.cwd, | ||
| ...opts | ||
| }); | ||
| } | ||
| async function runScript(name) { | ||
| const context = useContext(); | ||
| const pkgManager = await nypm.detectPackageManager(context.cwd); | ||
| try { | ||
| const { execa } = await import('execa'); | ||
| await execa(pkgManager?.name || "npm", ["run", ...name.split(" ")], { | ||
| cwd: useContext().cwd, | ||
| stdio: "inherit" | ||
| }); | ||
| } catch (error) { | ||
| context.logger.error(error); | ||
| } | ||
| } | ||
| const _pkg = { | ||
| __proto__: null, | ||
| addDependency: addDependency, | ||
| addDevDependency: addDevDependency, | ||
| readPackageJSON: readPackageJSON, | ||
| removeDependency: removeDependency, | ||
| runScript: runScript, | ||
| updatePackageJSON: updatePackageJSON | ||
| }; | ||
| const utils = Object.freeze({ | ||
| ..._fs, | ||
| ..._json, | ||
| ..._pkg | ||
| }); | ||
| const asyncContext = new AsyncLocalStorage(); | ||
| function useContext() { | ||
| const ctx = asyncContext.getStore(); | ||
| if (!ctx) { | ||
| return createContext(".", "codeup"); | ||
| } | ||
| return ctx; | ||
| } | ||
| function runWithContext(context, fn) { | ||
| return asyncContext.run(context, fn); | ||
| } | ||
| function createContext(cwd = ".", name) { | ||
| const context = { | ||
| cwd: resolve$1(cwd || "."), | ||
| utils, | ||
| logger: name ? consola.withTag(name) : consola | ||
| }; | ||
| return context; | ||
| } | ||
| export { utils as a, createContext as c, runWithContext as r, useContext as u }; |
| import fsp from 'node:fs/promises'; | ||
| import consola from 'consola'; | ||
| import createJiti from 'jiti'; | ||
| import { resolve, dirname, basename, join, extname } from 'pathe'; | ||
| import { filename } from 'pathe/utils'; | ||
| import { existsSync } from 'node:fs'; | ||
| import { homedir } from 'node:os'; | ||
| import { hash } from 'ohash'; | ||
| import { c as createContext, r as runWithContext } from './codeup.d746067e.mjs'; | ||
| const GIGET_PREFIXES = [ | ||
| "gh:", | ||
| "github:", | ||
| "gitlab:", | ||
| "bitbucket:", | ||
| "https://", | ||
| "http://" | ||
| ]; | ||
| async function resolveSourceDir(source, cwd, gigetOpts) { | ||
| if (!GIGET_PREFIXES.some((prefix) => source.startsWith(prefix))) { | ||
| return resolve(cwd, source); | ||
| } | ||
| const cloneName = `${source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_")}_${hash(source)}`; | ||
| let cloneDir; | ||
| const localNodeModules = resolve(cwd, "node_modules"); | ||
| const parentDir = dirname(cwd); | ||
| if (basename(parentDir) === ".giget") { | ||
| cloneDir = join(parentDir, cloneName); | ||
| } else if (existsSync(localNodeModules)) { | ||
| cloneDir = join(localNodeModules, ".giget", cloneName); | ||
| } else { | ||
| cloneDir = process.env.XDG_CACHE_HOME ? resolve(process.env.XDG_CACHE_HOME, "giget", cloneName) : resolve(homedir(), ".cache/giget", cloneName); | ||
| } | ||
| if (existsSync(cloneDir) && !gigetOpts?.install) { | ||
| await fsp.rm(cloneDir, { recursive: true }); | ||
| } | ||
| const { downloadTemplate } = await import('giget'); | ||
| const cloned = await downloadTemplate(source, { | ||
| dir: cloneDir, | ||
| ...gigetOpts | ||
| }); | ||
| return cloned.dir; | ||
| } | ||
| async function applyAction(action, cwd) { | ||
| const context = createContext(cwd || ".", action.meta?.name); | ||
| try { | ||
| const start = performance.now(); | ||
| await runWithContext(context, async () => { | ||
| if (action.filter && !await action.filter(context)) { | ||
| consola.info(`Skipping action \`${getActionName(action)}\`...`); | ||
| return; | ||
| } | ||
| consola.info(`Applying action \`${getActionName(action)}\``); | ||
| await action.apply(context); | ||
| consola.success( | ||
| `Action \`${getActionName(action)}\` applied in ${(performance.now() - start).toFixed(2)}ms` | ||
| ); | ||
| }); | ||
| } catch (error) { | ||
| consola.error( | ||
| `Failed to apply action \`${getActionName(action)}\`: | ||
| `, | ||
| error | ||
| ); | ||
| } | ||
| } | ||
| async function applyActions(actions, cwd, opts) { | ||
| const _actions = opts?.sort ? sortActions(actions) : actions; | ||
| const _cwd = resolve(cwd || "."); | ||
| consola.info( | ||
| `Applying ${_actions.length} action${actions.length > 1 ? "s" : ""} to \`${_cwd}\`: | ||
| ${_actions.map((a) => { | ||
| const name = a.meta?.name || a._path || a.apply?.name || "?"; | ||
| const parts = [ | ||
| `\`${name}\``, | ||
| a.meta?.description && `: ${a.meta?.description}`, | ||
| a.meta?.date && `(${a.meta?.date})` | ||
| ].filter(Boolean); | ||
| return ` - ${parts.join(" ")}`; | ||
| }).join("\n")} | ||
| ` | ||
| ); | ||
| for (const action of _actions) { | ||
| await applyAction(action, _cwd); | ||
| } | ||
| } | ||
| function sortActions(actions) { | ||
| return [...actions].sort((a, b) => { | ||
| if (a.meta?.date && b.meta?.date) { | ||
| return a.meta.date.localeCompare(b.meta.date); | ||
| } | ||
| const aName = a.meta?.name || a._path || a.apply?.name || ""; | ||
| const bName = b.meta?.name || b._path || b.apply?.name || ""; | ||
| return aName.localeCompare(bName); | ||
| }); | ||
| } | ||
| async function applyActionFromFile(path, workingDir) { | ||
| const _path = resolve(path); | ||
| let action; | ||
| try { | ||
| action = await loadActionFromFile(path); | ||
| } catch (error) { | ||
| consola.error(`Failed to load action from \`${_path}\`: | ||
| `, error); | ||
| return; | ||
| } | ||
| return await applyAction(action, workingDir); | ||
| } | ||
| async function loadActionFromFile(path) { | ||
| const _path = resolve(path); | ||
| const actionDir = dirname(_path); | ||
| const jiti = createJiti(actionDir, { interopDefault: true }); | ||
| const action = jiti(_path); | ||
| if (!action || typeof action.apply !== "function") { | ||
| throw new Error( | ||
| `File \`${_path}\` does not export a valid object with \`apply\` method!` | ||
| ); | ||
| } | ||
| action._path = _path; | ||
| return action; | ||
| } | ||
| const supportedExtensions = /* @__PURE__ */ new Set([".js", ".ts", ".mjs", ".cjs"]); | ||
| async function loadActionsFromDir(actionsDir) { | ||
| const actionFiles = (await fsp.readdir(actionsDir)).filter( | ||
| (path) => supportedExtensions.has(extname(path)) | ||
| ); | ||
| const actions = await Promise.all( | ||
| actionFiles.map( | ||
| async (actionFile) => loadActionFromFile(resolve(actionsDir, actionFile)) | ||
| ) | ||
| ); | ||
| return actions; | ||
| } | ||
| async function applyActionsFromDir(actionsDir, cwd) { | ||
| const actions = await loadActionsFromDir(actionsDir); | ||
| return await applyActions(actions, cwd, { sort: true }); | ||
| } | ||
| async function applyActionsFrom(source, cwd) { | ||
| const sourceDir = await resolveSourceDir(source, cwd); | ||
| return await applyActionsFromDir(sourceDir, cwd); | ||
| } | ||
| function getActionName(action) { | ||
| return action.meta?.name || action._path && filename(action._path) || action.apply?.name || ""; | ||
| } | ||
| export { applyAction as a, applyActions as b, applyActionFromFile as c, loadActionsFromDir as d, applyActionsFromDir as e, applyActionsFrom as f, getActionName as g, loadActionFromFile as l, sortActions as s }; |
| #!/usr/bin/env node | ||
| import { defineCommand } from 'citty'; | ||
| import { f as applyActionsFrom } from '../shared/codeup.59a34e27.mjs'; | ||
| import { f as applyActionsFrom } from '../shared/codeup.f0795b16.mjs'; | ||
| import 'node:fs/promises'; | ||
@@ -12,3 +12,3 @@ import 'consola'; | ||
| import 'ohash'; | ||
| import '../shared/codeup.79c210e4.mjs'; | ||
| import '../shared/codeup.d746067e.mjs'; | ||
| import 'node:async_hooks'; | ||
@@ -15,0 +15,0 @@ import 'pkg-types'; |
@@ -5,3 +5,3 @@ #!/usr/bin/env node | ||
| const name = "codeup"; | ||
| const version = "0.0.1"; | ||
| const version = "0.0.2"; | ||
| const description = "Automated Codebase Maintainer."; | ||
@@ -8,0 +8,0 @@ |
+2
-2
@@ -1,3 +0,3 @@ | ||
| export { c as createContext, r as runWithContext, u as useContext } from './shared/codeup.79c210e4.mjs'; | ||
| export { a as applyAction, c as applyActionFromFile, b as applyActions, f as applyActionsFrom, e as applyActionsFromDir, g as getActionName, l as loadActionFromFile, d as loadActionsFromDir, s as sortActions } from './shared/codeup.59a34e27.mjs'; | ||
| export { c as createContext, r as runWithContext, u as useContext } from './shared/codeup.d746067e.mjs'; | ||
| export { a as applyAction, c as applyActionFromFile, b as applyActions, f as applyActionsFrom, e as applyActionsFromDir, g as getActionName, l as loadActionFromFile, d as loadActionsFromDir, s as sortActions } from './shared/codeup.f0795b16.mjs'; | ||
| import 'node:async_hooks'; | ||
@@ -4,0 +4,0 @@ import 'consola'; |
@@ -1,2 +0,2 @@ | ||
| export { a as utils } from '../shared/codeup.79c210e4.mjs'; | ||
| export { a as utils } from '../shared/codeup.d746067e.mjs'; | ||
| import 'node:async_hooks'; | ||
@@ -3,0 +3,0 @@ import 'consola'; |
+1
-1
| { | ||
| "name": "codeup", | ||
| "version": "0.0.1", | ||
| "version": "0.0.2", | ||
| "description": "Automated Codebase Maintainer.", | ||
@@ -5,0 +5,0 @@ "repository": "unjs/codeup", |
+2
-2
@@ -71,5 +71,5 @@ # codeup | ||
| ignores: eslintignore.filter( | ||
| (i) => !["", "node_modules", "dist", "coverage"].includes(i) | ||
| (i) => !["", "node_modules", "dist", "coverage"].includes(i), | ||
| ), | ||
| }) | ||
| }), | ||
| ); | ||
@@ -76,0 +76,0 @@ |
| import fsp from 'node:fs/promises'; | ||
| import consola from 'consola'; | ||
| import createJiti from 'jiti'; | ||
| import { resolve, dirname, basename, join, extname } from 'pathe'; | ||
| import { filename } from 'pathe/utils'; | ||
| import { existsSync } from 'node:fs'; | ||
| import { homedir } from 'node:os'; | ||
| import { hash } from 'ohash'; | ||
| import { c as createContext, r as runWithContext } from './codeup.79c210e4.mjs'; | ||
| const GIGET_PREFIXES = [ | ||
| "gh:", | ||
| "github:", | ||
| "gitlab:", | ||
| "bitbucket:", | ||
| "https://", | ||
| "http://" | ||
| ]; | ||
| async function resolveSourceDir(source, cwd, gigetOpts) { | ||
| if (!GIGET_PREFIXES.some((prefix) => source.startsWith(prefix))) { | ||
| return resolve(cwd, source); | ||
| } | ||
| const cloneName = `${source.replace(/\W+/g, "_").split("_").splice(0, 3).join("_")}_${hash(source)}`; | ||
| let cloneDir; | ||
| const localNodeModules = resolve(cwd, "node_modules"); | ||
| const parentDir = dirname(cwd); | ||
| if (basename(parentDir) === ".giget") { | ||
| cloneDir = join(parentDir, cloneName); | ||
| } else if (existsSync(localNodeModules)) { | ||
| cloneDir = join(localNodeModules, ".giget", cloneName); | ||
| } else { | ||
| cloneDir = process.env.XDG_CACHE_HOME ? resolve(process.env.XDG_CACHE_HOME, "giget", cloneName) : resolve(homedir(), ".cache/giget", cloneName); | ||
| } | ||
| if (existsSync(cloneDir) && !gigetOpts?.install) { | ||
| await fsp.rm(cloneDir, { recursive: true }); | ||
| } | ||
| const { downloadTemplate } = await import('giget'); | ||
| const cloned = await downloadTemplate(source, { | ||
| dir: cloneDir, | ||
| ...gigetOpts | ||
| }); | ||
| return cloned.dir; | ||
| } | ||
| async function applyAction(action, cwd) { | ||
| const context = createContext(cwd || ".", action.meta?.name); | ||
| try { | ||
| const start = performance.now(); | ||
| await runWithContext(context, async () => { | ||
| if (action.filter && !await action.filter(context)) { | ||
| consola.info(`Skipping action \`${getActionName(action)}\`...`); | ||
| return; | ||
| } | ||
| consola.info(`Applying action \`${getActionName(action)}\``); | ||
| await action.apply(context); | ||
| consola.success( | ||
| `Action \`${getActionName(action)}\` applied in ${(performance.now() - start).toFixed(2)}ms` | ||
| ); | ||
| }); | ||
| } catch (error) { | ||
| consola.error( | ||
| `Failed to apply action \`${getActionName(action)}\`: | ||
| `, | ||
| error | ||
| ); | ||
| } | ||
| } | ||
| async function applyActions(actions, cwd, opts) { | ||
| const _actions = opts?.sort ? sortActions(actions) : actions; | ||
| const _cwd = resolve(cwd || "."); | ||
| consola.info( | ||
| `Applying ${_actions.length} action${actions.length > 1 ? "s" : ""} to \`${_cwd}\`: | ||
| ${_actions.map((a) => { | ||
| const name = a.meta?.name || a._path || a.apply?.name || "?"; | ||
| const parts = [ | ||
| `\`${name}\``, | ||
| a.meta?.description && `: ${a.meta?.description}`, | ||
| a.meta?.date && `(${a.meta?.date})` | ||
| ].filter(Boolean); | ||
| return ` - ${parts.join(" ")}`; | ||
| }).join("\n")} | ||
| ` | ||
| ); | ||
| for (const action of _actions) { | ||
| await applyAction(action, _cwd); | ||
| } | ||
| } | ||
| function sortActions(actions) { | ||
| return [...actions].sort((a, b) => { | ||
| if (a.meta?.date && b.meta?.date) { | ||
| return a.meta.date.localeCompare(b.meta.date); | ||
| } | ||
| const aName = a.meta?.name || a._path || a.apply?.name || ""; | ||
| const bName = b.meta?.name || b._path || b.apply?.name || ""; | ||
| return aName.localeCompare(bName); | ||
| }); | ||
| } | ||
| async function applyActionFromFile(path, workingDir) { | ||
| const _path = resolve(path); | ||
| let action; | ||
| try { | ||
| action = await loadActionFromFile(path); | ||
| } catch (error) { | ||
| consola.error(`Failed to load action from \`${_path}\`: | ||
| `, error); | ||
| return; | ||
| } | ||
| return await applyAction(action, workingDir); | ||
| } | ||
| async function loadActionFromFile(path) { | ||
| const _path = resolve(path); | ||
| const actionDir = dirname(_path); | ||
| const jiti = createJiti(actionDir, { interopDefault: true }); | ||
| const action = jiti(_path); | ||
| if (!action || typeof action.apply !== "function") { | ||
| throw new Error( | ||
| `File \`${_path}\` does not export a valid object with \`apply\` method!` | ||
| ); | ||
| } | ||
| action._path = _path; | ||
| return action; | ||
| } | ||
| const supportedExtensions = /* @__PURE__ */ new Set([".js", ".ts", ".mjs", ".cjs"]); | ||
| async function loadActionsFromDir(actionsDir) { | ||
| const actionFiles = (await fsp.readdir(actionsDir)).filter( | ||
| (path) => supportedExtensions.has(extname(path)) | ||
| ); | ||
| const actions = await Promise.all( | ||
| actionFiles.map( | ||
| async (actionFile) => loadActionFromFile(resolve(actionsDir, actionFile)) | ||
| ) | ||
| ); | ||
| return actions; | ||
| } | ||
| async function applyActionsFromDir(actionsDir, cwd) { | ||
| const actions = await loadActionsFromDir(actionsDir); | ||
| return await applyActions(actions, cwd, { sort: true }); | ||
| } | ||
| async function applyActionsFrom(source, cwd) { | ||
| const sourceDir = await resolveSourceDir(source, cwd); | ||
| return await applyActionsFromDir(sourceDir, cwd); | ||
| } | ||
| function getActionName(action) { | ||
| return action.meta?.name || action._path && filename(action._path) || action.apply?.name || ""; | ||
| } | ||
| export { applyAction as a, applyActions as b, applyActionFromFile as c, loadActionsFromDir as d, applyActionsFromDir as e, applyActionsFrom as f, getActionName as g, loadActionFromFile as l, sortActions as s }; |
| import { AsyncLocalStorage } from 'node:async_hooks'; | ||
| import { consola } from 'consola'; | ||
| import { resolve as resolve$1 } from 'pathe'; | ||
| import { existsSync } from 'node:fs'; | ||
| import fsp from 'node:fs/promises'; | ||
| import { findFile } from 'pkg-types'; | ||
| import nypm from 'nypm'; | ||
| function resolve(path) { | ||
| const ctx = useContext(); | ||
| return resolve$1(ctx.cwd, path); | ||
| } | ||
| async function exists(path, opts) { | ||
| if (opts?.withAnyExt) { | ||
| const ctx = useContext(); | ||
| const files = await fsp.readdir(ctx.cwd); | ||
| return files.some((file) => file.startsWith(path)); | ||
| } | ||
| const resolvedPath = resolve(path); | ||
| return existsSync(resolvedPath); | ||
| } | ||
| async function existsWithAnyExt(path) { | ||
| return exists(path, { withAnyExt: true }); | ||
| } | ||
| async function read(path) { | ||
| const resolvedPath = resolve(path); | ||
| try { | ||
| return await fsp.readFile(resolvedPath, "utf8"); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| async function readLines(path) { | ||
| const contents = await read(path); | ||
| return contents?.split("\n") || void 0; | ||
| } | ||
| async function write(path, contents, opts) { | ||
| const ctx = useContext(); | ||
| const resolvedPath = resolve(path); | ||
| if (opts?.skipIfExists && existsSync(resolvedPath)) | ||
| return; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Writing \`${path}\``); | ||
| } | ||
| await fsp.writeFile(resolvedPath, contents); | ||
| } | ||
| async function remove(path, opts) { | ||
| const ctx = useContext(); | ||
| const resolvedPath = resolve(path); | ||
| if (!existsSync(resolvedPath)) | ||
| return; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Removing \`${path}\``); | ||
| } | ||
| try { | ||
| await fsp.rm(resolvedPath, { recursive: true }); | ||
| } catch { | ||
| } | ||
| } | ||
| async function findUp(name) { | ||
| const ctx = useContext(); | ||
| try { | ||
| return await findFile(name, { startingFrom: ctx.cwd }); | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| async function update(path, fn, opts) { | ||
| const ctx = useContext(); | ||
| const contents = await read(path); | ||
| if (!contents) | ||
| return contents; | ||
| const updatedContents = await fn(contents); | ||
| if (contents === updatedContents) | ||
| return contents; | ||
| if (opts?.log !== false) { | ||
| ctx.logger.info(`Updating \`${path}\``); | ||
| } | ||
| await write(path, updatedContents, { log: false }); | ||
| return updatedContents; | ||
| } | ||
| async function append(path, contents, opts) { | ||
| const sep = opts?.newLine === false ? "" : "\n"; | ||
| return update(path, (existing) => existing + sep + contents); | ||
| } | ||
| const _fs = { | ||
| __proto__: null, | ||
| append: append, | ||
| exists: exists, | ||
| existsWithAnyExt: existsWithAnyExt, | ||
| findUp: findUp, | ||
| read: read, | ||
| readLines: readLines, | ||
| remove: remove, | ||
| resolve: resolve, | ||
| update: update, | ||
| write: write | ||
| }; | ||
| async function readJSON(path) { | ||
| const contents = await read(path); | ||
| return contents ? JSON.parse(contents) : void 0; | ||
| } | ||
| async function writeJSON(path, json, opts) { | ||
| await write(path, JSON.stringify(json, void 0, 2), opts); | ||
| } | ||
| async function updateJSON(path, updater) { | ||
| let updated; | ||
| await update(path, async (existing) => { | ||
| const json = JSON.parse(existing || "{}"); | ||
| updated = await updater(json) || json; | ||
| return JSON.stringify(updated, void 0, 2); | ||
| }); | ||
| return updated; | ||
| } | ||
| const _json = { | ||
| __proto__: null, | ||
| readJSON: readJSON, | ||
| updateJSON: updateJSON, | ||
| writeJSON: writeJSON | ||
| }; | ||
| async function readPackageJSON() { | ||
| const path = await findUp("package.json"); | ||
| if (!path) { | ||
| return void 0; | ||
| } | ||
| return readJSON(path); | ||
| } | ||
| async function updatePackageJSON(fn) { | ||
| const path = await findUp("package.json"); | ||
| if (!path) { | ||
| return; | ||
| } | ||
| await updateJSON(path, fn); | ||
| } | ||
| async function addDependency(name, opts) { | ||
| const context = useContext(); | ||
| if (opts?.log !== false) { | ||
| if (typeof name === "string") { | ||
| context.logger.info(`Adding ${name} dependency`); | ||
| } else { | ||
| context.logger.info(`Adding ${name.join(", ")} dependencies`); | ||
| } | ||
| } | ||
| await nypm.addDependency(name, { | ||
| cwd: context.cwd, | ||
| ...opts | ||
| }); | ||
| } | ||
| async function addDevDependency(name, opts) { | ||
| await addDependency(name, { dev: true, ...opts }); | ||
| } | ||
| async function removeDependency(name, opts) { | ||
| const context = useContext(); | ||
| if (opts?.log !== false) { | ||
| context.logger.info(`Removing ${name} dependency`); | ||
| } | ||
| await nypm.removeDependency(name, { | ||
| cwd: context.cwd, | ||
| ...opts | ||
| }); | ||
| } | ||
| async function runScript(name) { | ||
| const context = useContext(); | ||
| const pkgManager = await nypm.detectPackageManager(context.cwd); | ||
| try { | ||
| const { execa } = await import('execa'); | ||
| await execa(pkgManager?.name || "npm", ["run", ...name.split(" ")], { | ||
| cwd: useContext().cwd, | ||
| stdio: "inherit" | ||
| }); | ||
| } catch (error) { | ||
| context.logger.error(error); | ||
| } | ||
| } | ||
| const _pkg = { | ||
| __proto__: null, | ||
| addDependency: addDependency, | ||
| addDevDependency: addDevDependency, | ||
| readPackageJSON: readPackageJSON, | ||
| removeDependency: removeDependency, | ||
| runScript: runScript, | ||
| updatePackageJSON: updatePackageJSON | ||
| }; | ||
| const utils = Object.freeze({ | ||
| ..._fs, | ||
| ..._json, | ||
| ..._pkg | ||
| }); | ||
| const asyncContext = new AsyncLocalStorage(); | ||
| function useContext() { | ||
| const ctx = asyncContext.getStore(); | ||
| if (!ctx) { | ||
| return createContext(".", "codeup"); | ||
| } | ||
| return ctx; | ||
| } | ||
| function runWithContext(context, fn) { | ||
| return asyncContext.run(context, fn); | ||
| } | ||
| function createContext(cwd = ".", name) { | ||
| const context = { | ||
| cwd: resolve$1(cwd || "."), | ||
| utils, | ||
| logger: name ? consola.withTag(name) : consola | ||
| }; | ||
| return context; | ||
| } | ||
| export { utils as a, createContext as c, runWithContext as r, useContext as u }; |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
31871
0.02%