import { resolve, join, parse, dirname, isAbsolute } from "node:path"; import figlet from "figlet"; import { normalizePath, version } from "vite"; import picocolors from "picocolors"; import crypto from "node:crypto"; import { inspect } from "node:util"; import { LogFactory, Level, PatternLayout } from "base-log-factory"; import { DebugAppender } from "blf-debug-appender"; import { readFileSync, statSync } from "node:fs"; const colorful = {}; Object.entries(picocolors).forEach(([key, value]) => { colorful[key] = (text) => { console.log(value(text)); }; }); const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding)); function getHash(text, length = 8) { const h = hash("sha256", text, "hex").substring(0, length); if (length <= 64) { return h; } return h.padEnd(length, "_"); } function getDepsCacheSuffix(config, ssr) { let suffix = ""; if (config.command === "build") { const { outDir } = config.build; const buildId = outDir.length > 8 || outDir.includes("/") ? getHash(outDir) : outDir; suffix += `_build-${buildId}`; } if (ssr) { suffix += "_ssr"; } return suffix; } function getDepsCacheDirPrefix(config) { return normalizePath(resolve(config.cacheDir, "deps")); } function getDepsCacheDir(config, ssr) { return getDepsCacheDirPrefix(config) + getDepsCacheSuffix(config, ssr); } const FLATTEN_ID_HASH_LENGTH = 8; const FLATTEN_ID_MAX_FILE_LENGTH = 170; const limitFlattenIdLength = (id, limit = FLATTEN_ID_MAX_FILE_LENGTH) => { if (id.length <= limit) { return id; } return `${id.slice(0, limit - (FLATTEN_ID_HASH_LENGTH + 1))}_${getHash(id)}`; }; const replaceSlashOrColonRE = /[/:]/g; const replaceDotRE = /\./g; const replaceNestedIdRE = /\s*>\s*/g; const replaceHashRE = /#/g; function flattenId(id) { const flatId = limitFlattenIdLength(id.replace(replaceSlashOrColonRE, "_").replace(replaceDotRE, "__").replace(replaceNestedIdRE, "___").replace(replaceHashRE, "____")); return flatId; } function isDevServer(server) { return "pluginContainer" in server; } const VOLUME_RE = /^[A-Z]:/i; const FS_PREFIX = "/@fs/"; function fsPathFromId(id) { const fsPath = normalizePath(id.startsWith(FS_PREFIX) ? id.slice(FS_PREFIX.length) : id); return fsPath.startsWith("/") || VOLUME_RE.test(fsPath) ? fsPath : `/${fsPath}`; } const postfixRE = /[?#].*$/; function cleanUrl(url) { return url.replace(postfixRE, ""); } function toPath(deepKey) { const result = []; const length = deepKey.length; if (length === 0) { return result; } let index = 0; let key = ""; let quoteChar = ""; let bracket = false; if (deepKey.charCodeAt(0) === 46) { result.push(""); index++; } while (index < length) { const char = deepKey[index]; if (quoteChar) { if (char === "\\" && index + 1 < length) { index++; key += deepKey[index]; } else if (char === quoteChar) { quoteChar = ""; } else { key += char; } } else if (bracket) { if (char === '"' || char === "'") { quoteChar = char; } else if (char === "]") { bracket = false; result.push(key); key = ""; } else { key += char; } } else if (char === "[") { bracket = true; if (key) { result.push(key); key = ""; } } else if (char === ".") { if (key) { result.push(key); key = ""; } } else { key += char; } index++; } if (key) { result.push(key); } return result; } function toKey(value) { const whatType = typeof value; if (whatType === "string" || whatType === "symbol") { return value; } if (Object.is(value.valueOf(), -0)) { return "-0"; } return value.toString(); } function isDeepKey(key) { switch (typeof key) { case "number": case "symbol": { return false; } case "string": { return key.includes(".") || key.includes("[") || key.includes("]"); } } } function getWithPath(object, path, defaultValue) { if (path.length === 0 || object == null) { return defaultValue; } const lastIndex = path.length - 1; let lastObject = object; let current = null; let cursor = 0; for (let prevPath; cursor <= lastIndex; cursor++) { prevPath = path[cursor]; current = lastObject[prevPath]; if (current == null) { current = cursor === lastIndex ? defaultValue : typeof prevPath === "number" ? [] : {}; lastObject[prevPath] = current; } lastObject = current; } return current; } function getValue(object, path, defaultValue) { if (object == null) { return defaultValue; } switch (typeof path) { case "string": { const result = object[path]; if (result === void 0) { if (isDeepKey(path)) { return getValue(object, toPath(path), defaultValue); } object[path] = defaultValue; return defaultValue; } return result; } case "number": case "symbol": { if (typeof path === "number") { path = toKey(path); } const result = object[path]; if (result === void 0) { object[path] = defaultValue; return defaultValue; } return result; } default: { if (Array.isArray(path)) { return getWithPath(object, path, defaultValue); } if (Object.is(path == null ? void 0 : path.valueOf(), -0)) { path = "-0"; } else { path = String(path); } const result = object[path]; if (result === void 0) { object[path] = defaultValue; return defaultValue; } return result; } } } function createConverter(specifier) { if (specifier === "m") { return (event) => { return event.message.map((msg) => { switch (typeof msg) { case "object": return inspect(msg); case "symbol": return msg.toString(); default: return msg; } }).join(" "); }; } } const logFactory = new LogFactory({ level: Level.WARN, appenders: [ new DebugAppender({ layout: new PatternLayout("%d{HH:mm:ss} [%p] - %m", createConverter) }) ] }); function displayTime(time) { if (time < 1e3) { return `${time}ms`; } time = time / 1e3; if (time < 60) { return `${time.toFixed(2)}s`; } const mins = Math.floor(time / 60); const seconds = Math.round(time % 60); if (seconds === 60) { return `${mins + 1}m`; } return `${mins}m${seconds < 1 ? "" : ` ${seconds}s`}`; } function getClosestFilePath(fileName, path) { if (!path) { path = process.cwd(); } const pathObj = parse(path); if (pathObj.root === path) { return null; } try { const state = statSync(path); if (state.isDirectory()) { const filePath = join(path, fileName); try { if (!statSync(filePath).isDirectory()) { return filePath; } } catch (e) { if (e.code === "ENOENT") { return getClosestFilePath(fileName, join(path, "..")); } return null; } return getClosestFilePath(fileName, join(path, "..")); } return getClosestFilePath(fileName, dirname(path)); } catch (e) { return null; } } function getClosestPkg(path) { const filePath = getClosestFilePath("package.json", path); if (filePath) { const pkg = readFileSync(filePath, "utf-8"); return JSON.parse(pkg); } return null; } function getRuntimeVersion() { const { argv } = process; let vitePath = argv[1]; if (!/(\\|\/)vite(\\|\/)/.test(vitePath)) { vitePath = join(process.cwd(), "node_modules", "vite"); } const pkg = getClosestPkg(vitePath); return pkg ? pkg.version : version; } const escapeRegexRE = /[-/\\^$*+?.()|[\]{}]/g; function escapeRegex(str) { return str.replace(escapeRegexRE, "\\$&"); } function banner(text, opts) { console.log(figlet.textSync(text, opts)); } function toAbsolutePath(pth, cwd) { if (!isAbsolute(pth)) { pth = join(cwd, pth); } return normalizePath(pth); } function sleep(ms) { return new Promise((resolve2) => { setTimeout(resolve2, ms); }); } export { FS_PREFIX, banner, cleanUrl, colorful, displayTime, escapeRegex, flattenId, fsPathFromId, getDepsCacheDir, getHash, getRuntimeVersion, getValue, isDeepKey, isDevServer, logFactory, sleep, toAbsolutePath };