+156
| import fsp from 'node:fs/promises'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| 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 './_context.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 _pkgDir = fileURLToPath(new URL("..", import.meta.url)); | ||
| const jiti = createJiti(actionDir, { | ||
| interopDefault: true, | ||
| alias: { | ||
| codeup: join(_pkgDir, "dist/index.mjs"), | ||
| "codeup/utils": join(_pkgDir, "dist/utils/index.mjs") | ||
| } | ||
| }); | ||
| 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 './_action.mjs'; | ||
| import 'node:fs/promises'; | ||
| import 'node:url'; | ||
| import 'consola'; | ||
| import 'jiti'; | ||
| import 'pathe'; | ||
| import 'pathe/utils'; | ||
| import 'node:fs'; | ||
| import 'node:os'; | ||
| import 'ohash'; | ||
| import './_context.mjs'; | ||
| import 'node:async_hooks'; | ||
| import 'pkg-types'; | ||
| import 'nypm'; | ||
| const apply = defineCommand({ | ||
| meta: { | ||
| name: "apply", | ||
| description: "Apply code actions" | ||
| }, | ||
| args: { | ||
| cwd: { | ||
| type: "string", | ||
| description: "Project directory" | ||
| }, | ||
| actions: { | ||
| type: "string", | ||
| description: "Actions directory", | ||
| required: true | ||
| } | ||
| }, | ||
| async run({ args }) { | ||
| await applyActionsFrom(args.actions, args.cwd || "."); | ||
| } | ||
| }); | ||
| export { apply as default }; |
| 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 }; |
@@ -5,3 +5,3 @@ #!/usr/bin/env node | ||
| const name = "codeup"; | ||
| const version = "0.0.3"; | ||
| const version = "0.0.4"; | ||
| const description = "Automated Codebase Maintainer."; | ||
@@ -16,5 +16,5 @@ | ||
| subCommands: { | ||
| apply: () => import('../chunks/apply.mjs').then((m) => m.default) | ||
| apply: () => import('../_apply.mjs').then((m) => m.default) | ||
| } | ||
| }); | ||
| main(); |
+2
-2
@@ -1,3 +0,3 @@ | ||
| 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.cd1b3209.mjs'; | ||
| export { c as createContext, r as runWithContext, u as useContext } from './_context.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 './_action.mjs'; | ||
| import 'node:async_hooks'; | ||
@@ -4,0 +4,0 @@ import 'consola'; |
@@ -1,2 +0,2 @@ | ||
| export { a as utils } from '../shared/codeup.d746067e.mjs'; | ||
| export { a as utils } from '../_context.mjs'; | ||
| import 'node:async_hooks'; | ||
@@ -3,0 +3,0 @@ import 'consola'; |
+3
-3
| { | ||
| "name": "codeup", | ||
| "version": "0.0.3", | ||
| "version": "0.0.4", | ||
| "description": "Automated Codebase Maintainer.", | ||
@@ -26,3 +26,3 @@ "repository": "unjs/codeup", | ||
| "build": "unbuild", | ||
| "codeup": "jiti ./src/cli/index.ts", | ||
| "codeup": "jiti ./dist/cli/index.mjs", | ||
| "lint": "eslint . && biome check .", | ||
@@ -32,3 +32,3 @@ "lint:fix": "automd && eslint . --fix && biome check --apply .", | ||
| "play": "jiti playground", | ||
| "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags", | ||
| "release": "pnpm test && changelogen --release && npm publish && git push --follow-tags && pnpm build --stub", | ||
| "test": "pnpm lint && pnpm test:types", | ||
@@ -35,0 +35,0 @@ "test:types": "tsc --noEmit --skipLibCheck" |
+1
-1
@@ -135,3 +135,3 @@ # codeup | ||
| # Run actions from a github source | ||
| npx codeup apply --dir . --actions gh:unjs/codeup/actions/unjs | ||
| npx codeup apply --actions gh:unjs/codeup/actions/unjs | ||
| ``` | ||
@@ -138,0 +138,0 @@ |
| #!/usr/bin/env node | ||
| import { defineCommand } from 'citty'; | ||
| import { f as applyActionsFrom } from '../shared/codeup.cd1b3209.mjs'; | ||
| import 'node:fs/promises'; | ||
| import 'node:url'; | ||
| import 'consola'; | ||
| import 'jiti'; | ||
| import 'pathe'; | ||
| import 'pathe/utils'; | ||
| import 'node:fs'; | ||
| import 'node:os'; | ||
| import 'ohash'; | ||
| import '../shared/codeup.d746067e.mjs'; | ||
| import 'node:async_hooks'; | ||
| import 'pkg-types'; | ||
| import 'nypm'; | ||
| const apply = defineCommand({ | ||
| meta: { | ||
| name: "apply", | ||
| description: "Apply code actions" | ||
| }, | ||
| args: { | ||
| cwd: { | ||
| type: "string", | ||
| description: "Project directory" | ||
| }, | ||
| actions: { | ||
| type: "string", | ||
| description: "Actions directory", | ||
| required: true | ||
| } | ||
| }, | ||
| async run({ args }) { | ||
| await applyActionsFrom(args.actions, args.cwd || "."); | ||
| } | ||
| }); | ||
| export { apply as default }; |
| import fsp from 'node:fs/promises'; | ||
| import { fileURLToPath } from 'node:url'; | ||
| 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 _pkgDir = fileURLToPath(new URL("../..", import.meta.url)); | ||
| const jiti = createJiti(actionDir, { | ||
| interopDefault: true, | ||
| alias: { | ||
| codeup: join(_pkgDir, "dist/index.mjs"), | ||
| "codeup/utils": join(_pkgDir, "dist/utils/index.mjs") | ||
| } | ||
| }); | ||
| 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 * 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 }; |
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.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
32108
-0.23%1
Infinity%