UNPKG

zotero-plugin-scaffold

Version:
258 lines (251 loc) 7.2 kB
import { readFile, writeFile } from 'node:fs/promises'; import { glob } from 'tinyglobby'; import process from 'node:process'; import readline from 'node:readline'; import { isPlainObject } from 'es-toolkit'; import util from 'node:util'; import { isDebug } from 'std-env'; const factory = (...formats) => new Proxy(util.styleText.bind(util, formats), { get: (_, format) => util.inspect.colors[format] && factory(...formats, format), }); const styleText = factory(); var LOG_LEVEL = /* @__PURE__ */ ((LOG_LEVEL2) => { LOG_LEVEL2[LOG_LEVEL2["TRACE"] = 0] = "TRACE"; LOG_LEVEL2[LOG_LEVEL2["DEBUG"] = 1] = "DEBUG"; LOG_LEVEL2[LOG_LEVEL2["INFO"] = 2] = "INFO"; LOG_LEVEL2[LOG_LEVEL2["WARN"] = 3] = "WARN"; LOG_LEVEL2[LOG_LEVEL2["ERROR"] = 4] = "ERROR"; return LOG_LEVEL2; })(LOG_LEVEL || {}); const SYMBOLS = { SUCCESS: styleText.green("\u2714"), INFO: styleText.blue("\u2139"), FAIL: styleText.red("\u2716"), TIP: styleText.blue("\u2192"), ERROR: styleText.bgRed(" ERROR "), WARN: styleText.bgYellow(" WARN "), DEBUG: styleText.grey("\u2699"), NONE: "" }; const DEFAULT_OPTIONS = { SPACE: 0, NEW_LINE: false }; const LOG_METHODS_CONFIG = { error: { level: 4 /* ERROR */, symbol: SYMBOLS.ERROR, wrapNewLine: true }, warn: { level: 3 /* WARN */, symbol: SYMBOLS.WARN, wrapNewLine: true }, tip: { level: 2 /* INFO */, symbol: SYMBOLS.TIP }, info: { level: 2 /* INFO */, symbol: SYMBOLS.INFO }, debug: { level: 1 /* DEBUG */, symbol: SYMBOLS.DEBUG }, success: { level: 2 /* INFO */, symbol: SYMBOLS.SUCCESS }, fail: { level: 4 /* ERROR */, symbol: SYMBOLS.FAIL }, log: { level: 2 /* INFO */, symbol: SYMBOLS.NONE } }; class Logger { static instance; currentLogLevel; constructor(level) { this.currentLogLevel = this.determineLogLevel(level); } /** * Determine the appropriate log level */ determineLogLevel(level) { if (isDebug) return 0 /* TRACE */; const envLevel = process.env.ZOTERO_PLUGIN_LOG_LEVEL; return envLevel ? LOG_LEVEL[envLevel] : level ?? 2 /* INFO */; } static getInstance() { if (!Logger.instance) { Logger.instance = new Logger(); } return Logger.instance; } setLogLevel(level) { this.currentLogLevel = LOG_LEVEL[level]; } get level() { return this.currentLogLevel; } /** * Generic log formatting logic */ formatContent(content) { if (typeof content === "string") return content; if (content instanceof Error) return this.formatError(content); if (isPlainObject(content)) return JSON.stringify(content, null, 2); return String(content); } formatError(error) { return `${styleText.red(error.name)}: ${styleText.red(error.message)} ${error.stack}`; } /** * Core logging method */ logInternal(content, config, options = {}) { if (this.currentLogLevel > config.level) return; const { space = DEFAULT_OPTIONS.SPACE, newLine = DEFAULT_OPTIONS.NEW_LINE } = options; const formattedContent = this.formatContent(content); const output = [ " ".repeat(space), config.symbol, formattedContent ].join(" "); if (config.wrapNewLine) this.newLine(); console.log(output); if (newLine || config.wrapNewLine) this.newLine(); } // Public API methods error(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.error, options); } warn(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.warn, options); } tip(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.tip, options); } info(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.info, options); } debug(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.debug, options); } success(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.success, options); } fail(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.fail, options); } ready(content) { this.logInternal(styleText.green(content), LOG_METHODS_CONFIG.success); } log(content, options) { this.logInternal(content, LOG_METHODS_CONFIG.log, options); } clear() { const blank = process.stdout.rows > 2 ? "\n".repeat(process.stdout.rows - 2) : ""; console.log(blank); readline.cursorTo(process.stdout, 0, 0); readline.clearScreenDown(process.stdout); } newLine() { console.log(); } } const logger = Logger.getInstance(); function dateFormat(fmt, date) { let ret; const opt = { "Y+": date.getFullYear().toString(), "m+": (date.getMonth() + 1).toString(), "d+": date.getDate().toString(), "H+": date.getHours().toString(), "M+": date.getMinutes().toString(), "S+": date.getSeconds().toString() }; for (const k in opt) { ret = new RegExp(`(${k})`).exec(fmt); if (ret) { fmt = fmt.replace( ret[1], ret[1].length === 1 ? opt[k] : opt[k].padStart(ret[1].length, "0") ); } } return fmt; } function toArray(value) { return Array.isArray(value) ? value : [value]; } function template(str, data, regex = /\{\{(.+?)\}\}/g) { return Array.from(str.matchAll(regex)).reduce((acc, match) => { return acc.replace(match[0], data[match[1]]); }, str); } function parseRepoUrl(url) { if (!url) throw new Error("Parse repository URL failed."); const match = url.match(/:\/\/.+com\/([^/]+)\/([^.]+)\.git$/); if (!match) { throw new Error("Parse repository URL failed."); } const [, owner, repo] = match; return { owner, repo }; } function replace(contents, from, to) { const froms = Array.isArray(from) ? from : [from]; const tos = Array.isArray(to) ? to : Array.from({ length: froms.length }, () => to); if (froms.length !== tos.length) { throw new Error("The lengths of 'from' and 'to' must be equal"); } return froms.reduce((result, pattern, index) => result.replace(pattern, tos[index]), contents); } async function replaceInFile({ files, from, to, isGlob = true }) { const paths = isGlob ? await glob(files) : toArray(files); await Promise.all(paths.map(async (path) => { const contents = await readFile(path, "utf-8"); const newContents = replace(contents, from, to); if (contents !== newContents) await writeFile(path, newContents); })); } async function replaceDefine(dist, define) { const replaceMap = new Map( Object.keys(define).map((key) => [ new RegExp(`__${key}__`, "g"), define[key] ]) ); logger.debug(`replace map: ${replaceMap}`); await replaceInFile({ files: `${dist}/addon/**/*`, // files: [ // `${dist}/addon/**/*.html`, // `${dist}/addon/**/*.xhtml`, // `${dist}/addon/**/*.ftl`, // `${dist}/addon/**/*.css`, // `${dist}/addon/**/*.json`, // ], from: Array.from(replaceMap.keys()), to: Array.from(replaceMap.values()) // isGlob: false, }); } export { LOG_LEVEL as L, replaceInFile as a, toArray as b, replaceDefine as c, dateFormat as d, logger as l, parseRepoUrl as p, replace as r, styleText as s, template as t };