UNPKG

@next-boilerplate/cli-helpers

Version:
301 lines (293 loc) 9.87 kB
import { exec } from 'child_process'; import fs from 'fs-extra'; import { globby } from 'globby'; import path from 'path'; import * as tar from 'tar'; import { getStoreUID, storeConfigFileName, storeConfigSchema } from './stores/index.mjs'; let gchalk = null; const getChalk = () => { if (gchalk) return gchalk; throw new Error("Chalk not loaded"); }; const loadChalk = async () => { if (gchalk) return gchalk; const resolvedChalk = await import('./index-nKZYFKcq.mjs').then((_chalk) => _chalk.default); gchalk = resolvedChalk; return resolvedChalk; }; const console = globalThis.console; const black = "#000000"; const text = "#CDCDCD"; const yellow = "#F3F99D"; const orange = "#F9CB8F"; const red = "#F09393"; const green = "#7EE081"; const blue = "#7DCFEA"; const gray = "#686868"; const printColor = (bg, text2) => (...args) => { const data = args.map((arg) => { if (typeof arg === "object" && arg) { const str = arg.toString(); if (str === "[object Object]") { return JSON.stringify(arg, null, 2); } return str; } return arg; }).join(" "); if (isBrowser()) return data; try { const chalk = getChalk(); if (bg && text2) return chalk.bgHex(bg).hex(text2)(data); if (bg) return chalk.bgHex(bg)(data); if (text2) return chalk.hex(text2)(data); } catch (e) { return data; } return data; }; const _log = printColor(void 0, void 0); const log = printColor(void 0, text); const warn = printColor(yellow, black); const warnText = printColor(void 0, yellow); const debug = printColor(orange, black); const debugText = printColor(void 0, orange); const error = printColor(red, black); const errorText = printColor(void 0, red); const success = printColor(green, black); const successText = printColor(void 0, green); const info = printColor(blue, black); const infoText = printColor(void 0, blue); const subLog = printColor(void 0, gray); function addPrefixToArgs(prefix, ...args) { if (typeof prefix === "string") { return [log(prefix), ...args]; } if (typeof prefix === "function") { return [log(prefix()), ...args]; } return args; } const getLoggerEnv = () => process.env.LOGGER_ENV || "production"; const allowDebug = () => getLoggerEnv() === "development"; const isBrowser = () => typeof window !== "undefined"; var utils = /*#__PURE__*/Object.freeze({ __proto__: null, _log: _log, addPrefixToArgs: addPrefixToArgs, allowDebug: allowDebug, debug: debug, debugText: debugText, error: error, errorText: errorText, info: info, infoText: infoText, isBrowser: isBrowser, log: log, subLog: subLog, success: success, successText: successText, warn: warn, warnText: warnText }); const logger = { ...console, isInitialized: false, init: async () => { await loadChalk(); logger.isInitialized = true; }, allowDebug, _log: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, _log(...args)); console.log(...value); logger.onLog?.("log", value); }, log: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, log(...args)); console.log(...value); logger.onLog?.("log", value); }, debug: (...args) => { if (allowDebug()) { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, debug(" DEBUG "), debugText(...args)); console.debug(...value); logger.onLog?.("debug", value); } }, warn: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, warn(" WARN "), warnText(...args)); console.warn(...value); logger.onLog?.("warn", value); }, error: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, error(" ERROR "), errorText(...args)); console.error(...value); logger.onLog?.("error", value); }, trace: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, error(" ERROR "), errorText(...args)); console.trace(...value); logger.onLog?.("trace", value); }, success: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, success(" SUCCESS "), successText(...args)); console.log(...value); logger.onLog?.("success", value); }, info: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, info(" INFO "), infoText(...args)); console.log(...value); logger.onLog?.("info", value); }, subLog: (...args) => { warnIfNotInitialized(); const value = addPrefixToArgs(logger.prefix, subLog(...args)); console.log(...value); logger.onLog?.("subLog", value); }, utils }; logger.init(); let alreadyWarned = false; const warnIfNotInitialized = () => { if (!logger.isInitialized && !alreadyWarned) { console.warn("Logger is not initialized yet. Please call and await logger.init()"); alreadyWarned = true; } }; const getStoresDirectory = (assetsDirectory) => path.join(assetsDirectory, "stores"); const getStoreDataDirectory = ({ assetsDirectory, store }) => path.join(getStoresDirectory(assetsDirectory), encodeURIComponent(getStoreUID(store)), "data"); const loadStores = async ({ assetsDirectory }) => { const storesDirectory = getStoresDirectory(assetsDirectory); logger.debug(`Loading stores (${storesDirectory})`); await fs.ensureDir(storesDirectory); const formattedStoresDirectory = storesDirectory.replace(/\\/g, "/"); const globbyPath = path.join(formattedStoresDirectory, "*", storeConfigFileName).replace(/\\/g, "/"); const stores = await globby(globbyPath); logger.debug(`Found ${stores.length} stores in ${globbyPath}`); const storesFilled = []; for (const store of stores) { const { data: storeConfig, error } = storeConfigSchema.safeParse(await fs.readJson(store)); if (error) { logger.error(error); throw new Error(`The config of the store ${store} is invalid`); } const fullPath = path.dirname(store); storesFilled.push({ ...storeConfig, fullPath, uid: getStoreUID(storeConfig) }); } storesFilled.sort((a, b) => getStoreUID(a).localeCompare(getStoreUID(b))); return storesFilled; }; const getStores = async ({ assetsDirectory, search }) => { let stores = await loadStores({ assetsDirectory }); if (search) { stores = stores.filter((store) => { return getStoreUID(store).toLowerCase().includes(search.toLowerCase()); }); } return stores; }; const handleDownloadStores = async ({ assetsDirectory, config }) => { const stores = await getStores({ assetsDirectory }); const storeToDownload = config.stores?.filter((store) => !stores.some((s) => getStoreUID(s) === getStoreUID(store))); if (!storeToDownload || storeToDownload.length === 0) { return; } const npmVersion = await new Promise((resolve, reject) => { exec("npm --version", (error, stdout) => { if (error) { reject(error); return; } resolve(stdout); }); }).catch((e) => { logger.error(`Failed to get the npm version when downloading the stores`); throw e; }); logger.debug(`npm version: ${npmVersion}`); for (const store of storeToDownload) { await handleDownloadStore({ assetsDirectory, store }); } }; const handleDownloadStore = async ({ assetsDirectory, override, store }) => { const storesDirectory = getStoresDirectory(assetsDirectory); const storePath = path.join(storesDirectory, encodeURIComponent(getStoreUID(store))); const storeDataPath = path.join(storePath, "data"); const storeConfigPath = path.join(storePath, storeConfigFileName); await fs.ensureDir(storePath); await fs.writeJson(storeConfigPath, store); if (!override && await fs.exists(storeDataPath)) { const lockFile = path.join(storeDataPath, ".lock"); let i = 0; while (await fs.exists(lockFile) && i < 60) { await new Promise((resolve) => setTimeout(resolve, 1e3)); i++; } if (await fs.exists(lockFile)) { logger.warn(`The store ${store.name}@${store.version} installation is pending (may be stuck)`); return; } else { logger.warn(`The store ${store.name}@${store.version} is already installed at ${storeDataPath}`); return; } } logger.info(`Downloading the store ${store.name}@${store.version}`); await fs.ensureDir(storeDataPath); await fs.writeFile(path.join(storeDataPath, ".lock"), ""); await new Promise((resolve, reject) => { exec(`npm pack ${store.name}@${store.version}`, { cwd: storePath }, async (error, stdout) => { if (error) { reject(error); return; } try { const tarball = stdout.trim(); const tarballPath = path.join(storePath, tarball); await tar.x({ file: tarballPath, cwd: storeDataPath, strip: 1 }); await fs.remove(tarballPath); await fs.remove(path.join(storeDataPath, ".lock")); logger.debug(`Downloaded the store ${store.name}@${store.version}`); resolve(); } catch (e) { reject(e); } }); }).catch(async (e) => { logger.error(`Failed to download the store ${store.name}@${store.version}`); await fs.remove(storePath).catch((e2) => { logger.error(`Failed to remove the store folder ${storePath}`); throw e2; }); throw e; }); }; const handleDeleteStore = async ({ assetsDirectory, store }) => { const storesDirectory = getStoresDirectory(assetsDirectory); const storePath = path.join(storesDirectory, encodeURIComponent(getStoreUID(store))); await fs.remove(storePath); logger.info(`Deleted the store ${store.name}@${store.version}`); }; export { getStoresDirectory as a, getStores as b, handleDownloadStore as c, handleDeleteStore as d, getStoreDataDirectory as g, handleDownloadStores as h, logger as l };