UNPKG

pncat

Version:

A unified cli tool that enhances package managers catalogs feature.

1,388 lines (1,367 loc) 60.4 kB
import { a as __toESM, i as __toDynamicImportESM } from "./chunk-6qLfnLNH.mjs"; import "./semver-Df1PSY8l.mjs"; import { A as CMD_BOOL_FLAGS, B as VERSION, D as sortSpecs, E as parseSpec, F as DEPS_FIELDS, I as DEPS_TYPE_SHORT_MAP, L as MODE_ALIASES, M as COMMON_DEPS_FIELDS, N as DEFAULT_CATALOG_OPTIONS, O as AGENTS, R as MODE_CHOICES, T as normalizeCatalogName, _ as updatePackageToSpecifier, b as inferCatalogName, c as require_lodash, f as containsESLint, g as updatePackageToCatalog, j as CMD_BOOL_SHORT_FLAGS, k as AGENT_CONFIG, l as detectWorkspaceRoot, m as getDepSource, o as readJSON, p as containsVSCodeExtension, s as writeJSON, u as toArray, v as createDepCatalogIndex, w as isDepMatched, x as isCatalogPackageName, z as NAME } from "./catalog-handler-C1GrDpDU.mjs"; import { n as require_cjs, r as DEFAULT_CATALOG_RULES, t as Workspace } from "./workspace-manager-C0ZBpw-G.mjs"; import { writeFile } from "node:fs/promises"; import { dirname, join } from "pathe"; import process from "node:process"; import { findUp } from "find-up-simple"; import * as p from "@clack/prompts"; import c from "ansis"; import { existsSync } from "node:fs"; import { cac } from "cac"; import pRetry from "p-retry"; import { resolveCommand } from "package-manager-detector"; import { x } from "tinyexec"; import path from "node:path"; import os from "node:os"; import { createConfigLoader } from "unconfig"; import { detect } from "package-manager-detector/detect"; //#region node_modules/.pnpm/ufo@1.6.1/node_modules/ufo/dist/index.mjs const r = String.fromCharCode; const TRAILING_SLASH_RE = /\/$|\/\?|\/#/; const JOIN_LEADING_SLASH_RE = /^\.?\//; function hasTrailingSlash(input = "", respectQueryAndFragment) { if (!respectQueryAndFragment) return input.endsWith("/"); return TRAILING_SLASH_RE.test(input); } function withTrailingSlash(input = "", respectQueryAndFragment) { if (!respectQueryAndFragment) return input.endsWith("/") ? input : input + "/"; if (hasTrailingSlash(input, true)) return input || "/"; let path$1 = input; let fragment = ""; const fragmentIndex = input.indexOf("#"); if (fragmentIndex !== -1) { path$1 = input.slice(0, fragmentIndex); fragment = input.slice(fragmentIndex); if (!path$1) return fragment; } const [s0, ...s] = path$1.split("?"); return s0 + "/" + (s.length > 0 ? `?${s.join("?")}` : "") + fragment; } function isNonEmptyURL(url) { return url && url !== "/"; } function joinURL(base, ...input) { let url = base || ""; for (const segment of input.filter((url2) => isNonEmptyURL(url2))) if (url) { const _segment = segment.replace(JOIN_LEADING_SLASH_RE, ""); url = withTrailingSlash(url) + _segment; } else url = segment; return url; } const protocolRelative = Symbol.for("ufo:protocolRelative"); //#endregion //#region src/utils/npm.ts async function _getNpmConfig() { const { default: NpmCliConfig } = await import("./lib-eG8UpxVe.mjs").then(__toDynamicImportESM(1)); const npmcliConfig = new NpmCliConfig({ definitions: {}, shorthands: [], npmPath: dirname(process.cwd()), flatten: (current, total) => { Object.assign(total, current); } }); const oldLoadDefaults = npmcliConfig.loadDefaults.bind(npmcliConfig); npmcliConfig.loadDefaults = () => { oldLoadDefaults(); const setCliOption = (key, value) => { const cli = npmcliConfig.data.get("cli"); if (cli) cli.data[key] = value; }; setCliOption("userconfig", join(npmcliConfig.home, ".npmrc")); setCliOption("globalconfig", join(npmcliConfig.globalPrefix, "etc", "npmrc")); }; const oldEnv = { ...process.env }; await npmcliConfig.load(); process.env = oldEnv; return npmcliConfig.flat; } let _cache; function getNpmConfig() { if (!_cache) _cache = _getNpmConfig(); return _cache; } async function _getLatestVersion(spec) { const npmConfigs = await getNpmConfig(); const { default: npa } = await import("./npa-Ch3Vg1fG.mjs").then(__toDynamicImportESM(1)); const { name, scope } = npa(spec); if (!name) throw new Error(`Invalid package name: ${name}`); const { pickRegistry, NPM_REGISTRY } = await import("./dist-DcYMGoDW.mjs"); if (pickRegistry(scope, npmConfigs) === NPM_REGISTRY) { const { getLatestVersion: getLatestVersion$1 } = await import("./dist-DcYMGoDW.mjs"); const { version } = await getLatestVersion$1(spec); return version; } const npmRegistryFetch = await import("./lib-D2CiT62e.mjs").then(__toDynamicImportESM(1)); const url = joinURL(npmRegistryFetch.pickRegistry(spec, npmConfigs), name); const { "dist-tags": { latest } } = await npmRegistryFetch.json(url, { ...npmConfigs, headers: { headers: { "user-agent": `pncat@npm node/${process.version}`, "accept": "application/vnd.npm.install-v1+json; q=1.0, application/json; q=0.8, */*", ...npmConfigs.headers } }, spec }); return latest; } async function getLatestVersion(spec) { return await pRetry(async () => { const version = await _getLatestVersion(spec); if (version) return version; throw new Error(`failed to resolve ${spec} from npm`); }, { retries: 3 }); } //#endregion //#region src/utils/process.ts function parseArgs(args) { const options = {}; const deps = []; let i = 0; while (i < args.length) { const arg = args[i]; if (arg === "--") { deps.push(...args.slice(i + 1)); break; } if (arg.startsWith("--")) { const key = arg.slice(2); if (key.startsWith("no-")) { options[key.slice(3)] = false; i++; } else if (CMD_BOOL_FLAGS.has(key)) { options[key] = true; i++; } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) { options[key] = args[i + 1]; i += 2; } else { options[key] = true; i++; } } else if (arg.startsWith("-") && arg.length === 2) { const key = arg.slice(1); if (CMD_BOOL_SHORT_FLAGS.has(key)) { options[key] = true; i++; } else if (i + 1 < args.length && !args[i + 1].startsWith("-")) { options[key] = args[i + 1]; i += 2; } else { options[key] = true; i++; } } else { deps.push(arg); i++; } } return { options, deps }; } function parseCommandOptions(args, options = {}) { const { deps } = parseArgs(args); const isRecursive = ["--recursive", "-r"].some((i) => args.includes(i)); const isProd = ["--save-prod", "-P"].some((i) => args.includes(i)); const isDev = ["--save-dev", "-D"].some((i) => args.includes(i)); const isOptional = ["--save-optional", "-O"].some((i) => args.includes(i)); const isPeer = ["--save-peer"].some((i) => args.includes(i)); const isExact = ["--save-exact", "-E"].some((i) => args.includes(i)); return { deps, isRecursive, isDev: !isProd && isDev, isOptional: !isProd && isOptional, isPeer: !isProd && isPeer, isExact: options.saveExact || isExact }; } /** * Execute install command */ async function runAgentInstall(options = {}) { const { agent = "pnpm", cwd = process.cwd(), stdio = "inherit", silent = false } = options; if (!silent) p.outro(`running ${agent} install`); const execOptions = { nodeOptions: { cwd, stdio } }; const execCommand = async () => await x(agent, ["install"], execOptions); try { const resolved = resolveCommand(agent, "install", []); if (resolved) await x(resolved.command, resolved.args, execOptions); else await execCommand(); } catch { await execCommand(); } } /** * Execute add command */ async function runAgentRemove(dependencies, options = {}) { const { agent = "pnpm", cwd = process.cwd(), recursive = false, stdio = "inherit" } = options; if (dependencies.length === 0) return; const args = [...dependencies]; if (recursive) args.push("--recursive"); const execOptions = { nodeOptions: { cwd, stdio } }; const execCommand = async () => await x(agent, ["remove", ...args], execOptions); try { const resolved = resolveCommand(agent, "uninstall", args); if (resolved) await x(resolved.command, resolved.args, execOptions); else await execCommand(); } catch { await execCommand(); } } async function runHooks(hooks, options = {}) { const { cwd = process.cwd() } = options; for (const hook of toArray(hooks)) try { if (typeof hook === "string") { p.log.info(`running hook: ${hook}`); await x(hook, [], { nodeOptions: { cwd, stdio: "inherit", shell: true } }); } else if (typeof hook === "function") { p.log.info("running custom hook function"); await hook(); } } catch { p.log.warn(`hook failed: ${typeof hook === "string" ? hook : "custom function"}`); } } //#endregion //#region node_modules/.pnpm/tildify@3.0.0/node_modules/tildify/index.js const homeDirectory = os.homedir(); function tildify(absolutePath) { const normalizedPath = path.normalize(absolutePath) + path.sep; return (normalizedPath.startsWith(homeDirectory) ? normalizedPath.replace(homeDirectory + path.sep, `~${path.sep}`) : normalizedPath).slice(0, -1); } //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/base.js var Diff = class { diff(oldStr, newStr, options = {}) { let callback; if (typeof options === "function") { callback = options; options = {}; } else if ("callback" in options) callback = options.callback; const oldString = this.castInput(oldStr, options); const newString = this.castInput(newStr, options); const oldTokens = this.removeEmpty(this.tokenize(oldString, options)); const newTokens = this.removeEmpty(this.tokenize(newString, options)); return this.diffWithOptionsObj(oldTokens, newTokens, options, callback); } diffWithOptionsObj(oldTokens, newTokens, options, callback) { var _a; const done = (value) => { value = this.postProcess(value, options); if (callback) { setTimeout(function() { callback(value); }, 0); return; } else return value; }; const newLen = newTokens.length, oldLen = oldTokens.length; let editLength = 1; let maxEditLength = newLen + oldLen; if (options.maxEditLength != null) maxEditLength = Math.min(maxEditLength, options.maxEditLength); const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity; const abortAfterTimestamp = Date.now() + maxExecutionTime; const bestPath = [{ oldPos: -1, lastComponent: void 0 }]; let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options); if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens)); let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity; const execEditLength = () => { for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) { let basePath; const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1]; if (removePath) bestPath[diagonalPath - 1] = void 0; let canAdd = false; if (addPath) { const addPathNewPos = addPath.oldPos - diagonalPath; canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen; } const canRemove = removePath && removePath.oldPos + 1 < oldLen; if (!canAdd && !canRemove) { bestPath[diagonalPath] = void 0; continue; } if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) basePath = this.addToPath(addPath, true, false, 0, options); else basePath = this.addToPath(removePath, false, true, 1, options); newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options); if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true; else { bestPath[diagonalPath] = basePath; if (basePath.oldPos + 1 >= oldLen) maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1); if (newPos + 1 >= newLen) minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1); } } editLength++; }; if (callback) (function exec() { setTimeout(function() { if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) return callback(void 0); if (!execEditLength()) exec(); }, 0); })(); else while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) { const ret = execEditLength(); if (ret) return ret; } } addToPath(path$1, added, removed, oldPosInc, options) { const last = path$1.lastComponent; if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) return { oldPos: path$1.oldPos + oldPosInc, lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent } }; else return { oldPos: path$1.oldPos + oldPosInc, lastComponent: { count: 1, added, removed, previousComponent: last } }; } extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) { const newLen = newTokens.length, oldLen = oldTokens.length; let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0; while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) { newPos++; oldPos++; commonCount++; if (options.oneChangePerToken) basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false }; } if (commonCount && !options.oneChangePerToken) basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false }; basePath.oldPos = oldPos; return newPos; } equals(left, right, options) { if (options.comparator) return options.comparator(left, right); else return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase(); } removeEmpty(array) { const ret = []; for (let i = 0; i < array.length; i++) if (array[i]) ret.push(array[i]); return ret; } castInput(value, options) { return value; } tokenize(value, options) { return Array.from(value); } join(chars) { return chars.join(""); } postProcess(changeObjects, options) { return changeObjects; } get useLongestToken() { return false; } buildValues(lastComponent, newTokens, oldTokens) { const components = []; let nextComponent; while (lastComponent) { components.push(lastComponent); nextComponent = lastComponent.previousComponent; delete lastComponent.previousComponent; lastComponent = nextComponent; } components.reverse(); const componentLen = components.length; let componentPos = 0, newPos = 0, oldPos = 0; for (; componentPos < componentLen; componentPos++) { const component = components[componentPos]; if (!component.removed) { if (!component.added && this.useLongestToken) { let value = newTokens.slice(newPos, newPos + component.count); value = value.map(function(value$1, i) { const oldValue = oldTokens[oldPos + i]; return oldValue.length > value$1.length ? oldValue : value$1; }); component.value = this.join(value); } else component.value = this.join(newTokens.slice(newPos, newPos + component.count)); newPos += component.count; if (!component.added) oldPos += component.count; } else { component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count)); oldPos += component.count; } } return components; } }; //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/character.js var CharacterDiff = class extends Diff {}; const characterDiff = new CharacterDiff(); //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/util/string.js function longestCommonPrefix(str1, str2) { let i; for (i = 0; i < str1.length && i < str2.length; i++) if (str1[i] != str2[i]) return str1.slice(0, i); return str1.slice(0, i); } function longestCommonSuffix(str1, str2) { let i; if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) return ""; for (i = 0; i < str1.length && i < str2.length; i++) if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) return str1.slice(-i); return str1.slice(-i); } function replacePrefix(string, oldPrefix, newPrefix) { if (string.slice(0, oldPrefix.length) != oldPrefix) throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`); return newPrefix + string.slice(oldPrefix.length); } function replaceSuffix(string, oldSuffix, newSuffix) { if (!oldSuffix) return string + newSuffix; if (string.slice(-oldSuffix.length) != oldSuffix) throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`); return string.slice(0, -oldSuffix.length) + newSuffix; } function removePrefix(string, oldPrefix) { return replacePrefix(string, oldPrefix, ""); } function removeSuffix(string, oldSuffix) { return replaceSuffix(string, oldSuffix, ""); } function maximumOverlap(string1, string2) { return string2.slice(0, overlapCount(string1, string2)); } function overlapCount(a, b) { let startA = 0; if (a.length > b.length) startA = a.length - b.length; let endB = b.length; if (a.length < b.length) endB = a.length; const map = Array(endB); let k = 0; map[0] = 0; for (let j = 1; j < endB; j++) { if (b[j] == b[k]) map[j] = map[k]; else map[j] = k; while (k > 0 && b[j] != b[k]) k = map[k]; if (b[j] == b[k]) k++; } k = 0; for (let i = startA; i < a.length; i++) { while (k > 0 && a[i] != b[k]) k = map[k]; if (a[i] == b[k]) k++; } return k; } function trailingWs(string) { let i; for (i = string.length - 1; i >= 0; i--) if (!string[i].match(/\s/)) break; return string.substring(i + 1); } function leadingWs(string) { const match = string.match(/^\s*/); return match ? match[0] : ""; } //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/word.js const extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}"; const tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug"); var WordDiff = class extends Diff { equals(left, right, options) { if (options.ignoreCase) { left = left.toLowerCase(); right = right.toLowerCase(); } return left.trim() === right.trim(); } tokenize(value, options = {}) { let parts; if (options.intlSegmenter) { const segmenter = options.intlSegmenter; if (segmenter.resolvedOptions().granularity != "word") throw new Error("The segmenter passed must have a granularity of \"word\""); parts = Array.from(segmenter.segment(value), (segment) => segment.segment); } else parts = value.match(tokenizeIncludingWhitespace) || []; const tokens = []; let prevPart = null; parts.forEach((part) => { if (/\s/.test(part)) if (prevPart == null) tokens.push(part); else tokens.push(tokens.pop() + part); else if (prevPart != null && /\s/.test(prevPart)) if (tokens[tokens.length - 1] == prevPart) tokens.push(tokens.pop() + part); else tokens.push(prevPart + part); else tokens.push(part); prevPart = part; }); return tokens; } join(tokens) { return tokens.map((token, i) => { if (i == 0) return token; else return token.replace(/^\s+/, ""); }).join(""); } postProcess(changes, options) { if (!changes || options.oneChangePerToken) return changes; let lastKeep = null; let insertion = null; let deletion = null; changes.forEach((change) => { if (change.added) insertion = change; else if (change.removed) deletion = change; else { if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change); lastKeep = change; insertion = null; deletion = null; } }); if (insertion || deletion) dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null); return changes; } }; const wordDiff = new WordDiff(); function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) { if (deletion && insertion) { const oldWsPrefix = leadingWs(deletion.value); const oldWsSuffix = trailingWs(deletion.value); const newWsPrefix = leadingWs(insertion.value); const newWsSuffix = trailingWs(insertion.value); if (startKeep) { const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix); startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix); deletion.value = removePrefix(deletion.value, commonWsPrefix); insertion.value = removePrefix(insertion.value, commonWsPrefix); } if (endKeep) { const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix); endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix); deletion.value = removeSuffix(deletion.value, commonWsSuffix); insertion.value = removeSuffix(insertion.value, commonWsSuffix); } } else if (insertion) { if (startKeep) { const ws = leadingWs(insertion.value); insertion.value = insertion.value.substring(ws.length); } if (endKeep) { const ws = leadingWs(endKeep.value); endKeep.value = endKeep.value.substring(ws.length); } } else if (startKeep && endKeep) { const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value); const newWsStart = longestCommonPrefix(newWsFull, delWsStart); deletion.value = removePrefix(deletion.value, newWsStart); const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd); deletion.value = removeSuffix(deletion.value, newWsEnd); endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd); startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length)); } else if (endKeep) { const endKeepWsPrefix = leadingWs(endKeep.value); const overlap = maximumOverlap(trailingWs(deletion.value), endKeepWsPrefix); deletion.value = removeSuffix(deletion.value, overlap); } else if (startKeep) { const overlap = maximumOverlap(trailingWs(startKeep.value), leadingWs(deletion.value)); deletion.value = removePrefix(deletion.value, overlap); } } var WordsWithSpaceDiff = class extends Diff { tokenize(value) { const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug"); return value.match(regex) || []; } }; const wordsWithSpaceDiff = new WordsWithSpaceDiff(); //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/line.js var LineDiff = class extends Diff { constructor() { super(...arguments); this.tokenize = tokenize; } equals(left, right, options) { if (options.ignoreWhitespace) { if (!options.newlineIsToken || !left.includes("\n")) left = left.trim(); if (!options.newlineIsToken || !right.includes("\n")) right = right.trim(); } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) { if (left.endsWith("\n")) left = left.slice(0, -1); if (right.endsWith("\n")) right = right.slice(0, -1); } return super.equals(left, right, options); } }; const lineDiff = new LineDiff(); function diffLines(oldStr, newStr, options) { return lineDiff.diff(oldStr, newStr, options); } function tokenize(value, options) { if (options.stripTrailingCr) value = value.replace(/\r\n/g, "\n"); const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/); if (!linesAndNewlines[linesAndNewlines.length - 1]) linesAndNewlines.pop(); for (let i = 0; i < linesAndNewlines.length; i++) { const line = linesAndNewlines[i]; if (i % 2 && !options.newlineIsToken) retLines[retLines.length - 1] += line; else retLines.push(line); } return retLines; } //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/sentence.js function isSentenceEndPunct(char) { return char == "." || char == "!" || char == "?"; } var SentenceDiff = class extends Diff { tokenize(value) { var _a; const result = []; let tokenStartI = 0; for (let i = 0; i < value.length; i++) { if (i == value.length - 1) { result.push(value.slice(tokenStartI)); break; } if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) { result.push(value.slice(tokenStartI, i + 1)); i = tokenStartI = i + 1; while ((_a = value[i + 1]) === null || _a === void 0 ? void 0 : _a.match(/\s/)) i++; result.push(value.slice(tokenStartI, i + 1)); tokenStartI = i + 1; } } return result; } }; const sentenceDiff = new SentenceDiff(); //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/css.js var CssDiff = class extends Diff { tokenize(value) { return value.split(/([{}:;,]|\s+)/); } }; const cssDiff = new CssDiff(); //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/json.js var JsonDiff = class extends Diff { constructor() { super(...arguments); this.tokenize = tokenize; } get useLongestToken() { return true; } castInput(value, options) { const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options; return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " "); } equals(left, right, options) { return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options); } }; const jsonDiff = new JsonDiff(); function canonicalize(obj, stack, replacementStack, replacer, key) { stack = stack || []; replacementStack = replacementStack || []; if (replacer) obj = replacer(key === void 0 ? "" : key, obj); let i; for (i = 0; i < stack.length; i += 1) if (stack[i] === obj) return replacementStack[i]; let canonicalizedObj; if ("[object Array]" === Object.prototype.toString.call(obj)) { stack.push(obj); canonicalizedObj = new Array(obj.length); replacementStack.push(canonicalizedObj); for (i = 0; i < obj.length; i += 1) canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, String(i)); stack.pop(); replacementStack.pop(); return canonicalizedObj; } if (obj && obj.toJSON) obj = obj.toJSON(); if (typeof obj === "object" && obj !== null) { stack.push(obj); canonicalizedObj = {}; replacementStack.push(canonicalizedObj); const sortedKeys = []; let key$1; for (key$1 in obj) /* istanbul ignore else */ if (Object.prototype.hasOwnProperty.call(obj, key$1)) sortedKeys.push(key$1); sortedKeys.sort(); for (i = 0; i < sortedKeys.length; i += 1) { key$1 = sortedKeys[i]; canonicalizedObj[key$1] = canonicalize(obj[key$1], stack, replacementStack, replacer, key$1); } stack.pop(); replacementStack.pop(); } else canonicalizedObj = obj; return canonicalizedObj; } //#endregion //#region node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/array.js var ArrayDiff = class extends Diff { tokenize(value) { return value.slice(); } join(value) { return value; } removeEmpty(value) { return value; } }; const arrayDiff = new ArrayDiff(); //#endregion //#region src/utils/diff.ts function highlight(content, indentSize = 2, highlight$1 = false) { if (content.trim() === "") return content; const currentIndent = content.search(/\S/); const indentLevel = Math.floor(currentIndent / indentSize); const colonIndex = content.indexOf(":"); if (colonIndex === -1) return content; const beforeColon = content.substring(0, colonIndex); const afterColon = content.substring(colonIndex); const ansi = highlight$1 ? c.cyan : c.reset; if (indentLevel === 0 || indentLevel === 1) { const propertyName = beforeColon.trim(); const leadingSpaces = content.substring(0, content.indexOf(propertyName)); const versionMatch = afterColon.match(/:\s*(.+)/); if (versionMatch && versionMatch[1].trim()) return leadingSpaces + ansi(propertyName) + c.dim(afterColon); else return leadingSpaces + ansi(propertyName) + c.dim(":"); } else { const versionMatch = afterColon.match(/:\s*(.+)/); if (versionMatch && versionMatch[1].trim()) return beforeColon + c.dim(afterColon); else return beforeColon + c.dim(":"); } } function diffHighlight(original, updated, options = {}) { const { indentSize = 2, verbose = false } = options; const changed = diffLines(original, updated, { ignoreNewlineAtEof: true }); const diffs = []; let lineNumber = 0; changed.forEach((part) => { const lines = part.value.split("\n"); if (lines[lines.length - 1] === "") lines.pop(); lines.forEach((line) => { diffs.push({ content: line, type: part.added ? "added" : part.removed ? "removed" : "unchanged", lineNumber: lineNumber++ }); }); }); const changedLines = /* @__PURE__ */ new Set(); diffs.forEach((line, index) => { if (line.type === "added" || line.type === "removed") changedLines.add(index); }); const lineHierarchy = []; diffs.forEach((line, index) => { const content = line.content; if (content.trim() === "") { lineHierarchy.push({ indentLevel: -1, parentIndices: [] }); return; } const currentIndent = content.search(/\S/); const indentLevel = Math.floor(currentIndent / indentSize); const parentIndices = []; for (let i = index - 1; i >= 0; i--) { const prevLine = diffs[i]; const prevHierarchy = lineHierarchy[i]; if (prevLine.content.trim() === "") continue; const prevIndent = prevLine.content.search(/\S/); const prevIndentLevel = Math.floor(prevIndent / indentSize); if (prevIndentLevel < indentLevel) { parentIndices.unshift(i); if (prevIndentLevel === indentLevel - 1) { parentIndices.unshift(...prevHierarchy.parentIndices); break; } } } lineHierarchy.push({ indentLevel, parentIndices }); }); const linesToKeep = /* @__PURE__ */ new Set(); if (verbose) diffs.forEach((_, index) => { linesToKeep.add(index); }); else changedLines.forEach((lineIndex) => { linesToKeep.add(lineIndex); lineHierarchy[lineIndex].parentIndices.forEach((parentIndex) => { linesToKeep.add(parentIndex); }); }); let addedCount = 0; let removedCount = 0; diffs.forEach((line) => { if (line.type === "added" || line.type === "removed") { const content = line.content; if (content.trim() === "") return; const currentIndent = content.search(/\S/); if (Math.floor(currentIndent / indentSize) >= 2 && content.includes(":")) { const colonIndex = content.indexOf(":"); const versionMatch = content.substring(colonIndex).match(/:\s*(.+)/); if (versionMatch && versionMatch[1].trim()) { if (line.type === "added") addedCount++; else if (line.type === "removed") removedCount++; } } } }); const summaryParts = []; if (addedCount > 0) summaryParts.push(`${c.yellow(addedCount)} added`); if (removedCount > 0) summaryParts.push(`${c.yellow(removedCount)} removed`); const result = []; let lastKeptIndex = -1; diffs.forEach((line, index) => { if (linesToKeep.has(index)) { if (!verbose && lastKeptIndex !== -1 && index > lastKeptIndex + 1) { const skippedCount = index - lastKeptIndex - 1; result.push(c.dim`${c.yellow(skippedCount)} unchanged line${skippedCount > 1 ? "s" : ""}`); } let coloredLine = line.content; if (line.type === "added") { const highlighted = highlight(line.content, indentSize, verbose); coloredLine = c.green(`+ ${highlighted}`); } else if (line.type === "removed") { const highlighted = highlight(line.content, indentSize, verbose); coloredLine = c.red(`- ${highlighted}`); } else coloredLine = ` ${highlight(line.content, indentSize, verbose)}`; result.push(coloredLine); lastKeptIndex = index; } }); if (summaryParts.length > 0) { result.push(""); result.push(summaryParts.join(" ")); } return result.join("\n"); } //#endregion //#region src/utils/workspace.ts async function confirmWorkspaceChanges(modifier, options) { const { workspace, updatedPackages, yes = false, verbose = false, bailout = true, confirmMessage = "continue?", completeMessage, showDiff = true } = options ?? {}; const catalogOptions = workspace.getOptions(); const filename = AGENT_CONFIG[catalogOptions.agent || "pnpm"].filename; const rawContent = await workspace.catalog.toString(); await modifier(); if (catalogOptions.agent === "pnpm") await workspace.catalog.updateWorkspaceOverrides?.(); const content = await workspace.catalog.toString(); if (rawContent === content) if (bailout) { p.outro(c.yellow(`no changes to ${filename}`)); process.exit(0); } else p.log.info(c.green(`no changes to ${filename}`)); const filepath = await workspace.catalog.getWorkspacePath(); const diff = diffHighlight(rawContent, content, { verbose }); if (showDiff && diff) { p.note(c.reset(diff), c.dim(tildify(filepath))); if (!yes) { const result = await p.confirm({ message: confirmMessage }); if (!result || p.isCancel(result)) { p.outro(c.red("aborting")); process.exit(1); } } } if (updatedPackages) await writePackageJSONs(updatedPackages); if (diff) { p.log.info(`writing ${filename}`); await workspace.catalog.writeWorkspace(); } if (catalogOptions.postRun) await runHooks(catalogOptions.postRun, { cwd: workspace.getCwd() }); if (completeMessage) if (catalogOptions.install) { p.log.info(c.green(completeMessage)); await runAgentInstall({ cwd: workspace.getCwd(), agent: catalogOptions.agent }); } else p.outro(c.green(completeMessage)); } async function readPackageJSON() { const pkgPath = join(process.cwd(), "package.json"); if (!existsSync(pkgPath)) { p.outro(c.red("no package.json found, aborting")); process.exit(1); } const pkgJson = await readJSON(pkgPath); if (typeof pkgJson.name !== "string") { p.outro(c.red("package.json is missing name, aborting")); process.exit(1); } return { pkgPath, pkgJson }; } async function writePackageJSONs(updatedPackages) { if (Object.keys(updatedPackages).length === 0) return; p.log.info("writing package.json"); await Promise.all(Object.values(updatedPackages).map((pkg) => writeJSON(pkg.filepath, cleanupPackageJSON(pkg.raw)))); } function cleanupPackageJSON(pkgJson) { for (const field of DEPS_FIELDS) { const deps = pkgJson[field]; if (!deps) continue; if (Object.keys(deps).length === 0) delete pkgJson[field]; } return pkgJson; } //#endregion //#region src/commands/add.ts async function addCommand(options) { const args = process.argv.slice(3); if (args.length === 0) { p.outro(c.red("no dependencies provided, aborting")); process.exit(1); } const { pkgJson, pkgPath } = await readPackageJSON(); const workspace = new Workspace(options); await workspace.catalog.ensureWorkspace(); const { isDev = false, isPeer = false, isOptional = false, dependencies = [] } = await resolveAdd({ args, options, workspace }); const depsSource = getDepSource(isDev, isOptional, isPeer); const deps = pkgJson[depsSource] ||= {}; for (const dep of dependencies) { COMMON_DEPS_FIELDS.forEach((field) => { if (pkgJson[field]?.[dep.name]) delete pkgJson[field][dep.name]; }); deps[dep.name] = dep.catalogName ? normalizeCatalogName(dep.catalogName) : dep.specifier || "^0.0.0"; } await confirmWorkspaceChanges(async () => { for (const dep of dependencies) if (dep.catalogName) await workspace.catalog.setPackage(dep.catalogName, dep.name, dep.specifier || "^0.0.0"); }, { workspace, updatedPackages: { [pkgJson.name]: { filepath: pkgPath, raw: pkgJson } }, yes: options.yes, verbose: options.verbose, bailout: false, completeMessage: "add complete" }); } async function resolveAdd(context) { const { args = [], options, workspace } = context; await workspace.loadPackages(); const { deps, isDev, isOptional, isPeer, isExact } = parseCommandOptions(args, options); if (!deps.length) { p.outro(c.red("no dependencies provided, aborting")); process.exit(1); } const parsed = deps.map((x$1) => x$1.trim()).filter(Boolean).map(parseSpec); const workspaceJson = await workspace.catalog.toJSON(); const workspacePackages = workspace.getWorkspacePackages(); const createDep = (dep) => { return { name: dep.name, specifier: dep.specifier, source: getDepSource(isDev, isOptional, isPeer), catalog: false, catalogable: true, catalogName: dep.catalogName }; }; for (const dep of parsed) { if (!dep.specifier && workspacePackages.includes(dep.name)) { dep.specifier = "workspace:*"; dep.specifierSource ||= "workspace"; continue; } if (options.catalog) dep.catalogName ||= options.catalog; if (dep.specifier) dep.specifierSource ||= "user"; if (!dep.specifier) { const catalogs = await workspace.catalog.getPackageCatalogs(dep.name); if (catalogs[0]) { dep.catalogName = catalogs[0]; dep.specifierSource ||= "catalog"; } } if (dep.catalogName && !dep.specifier) { const spec = dep.catalogName === "default" ? workspaceJson?.catalog?.[dep.name] : workspaceJson?.catalogs?.[dep.catalogName]?.[dep.name]; if (spec) dep.specifier = spec; } if (!dep.specifier) { const spinner = p.spinner({ indicator: "dots" }); spinner.start(`resolving ${c.cyan(dep.name)} from npm...`); const version = await getLatestVersion(dep.name); if (version) { dep.specifier = isExact ? version : `^${version}`; dep.specifierSource ||= "npm"; spinner.stop(`${c.dim("resolved")} ${c.cyan(dep.name)}${c.dim(`@${c.green(dep.specifier)}`)}`); } else { spinner.stop(`failed to resolve ${c.cyan(dep.name)} from npm`); p.outro(c.red("aborting")); process.exit(1); } } if (!dep.catalogName) dep.catalogName = options.catalog || workspace.inferCatalogName(createDep(dep)); } return { isDev, isPeer, isOptional, dependencies: parsed.map((i) => createDep(i)) }; } //#endregion //#region src/commands/clean.ts async function cleanCommand(options) { const workspace = new Workspace(options); if (!await workspace.catalog.findWorkspaceFile()) { p.outro(c.red("no workspace file found, aborting")); process.exit(1); } const { dependencies = [] } = await resolveClean({ options, workspace }); if (!dependencies.length) { p.outro(c.yellow("no dependencies to clean, aborting")); process.exit(0); } await workspace.catalog.ensureWorkspace(); p.log.info(`📦 Found ${c.yellow(dependencies.length)} dependencies not in package.json`); await confirmWorkspaceChanges(async () => { await workspace.catalog.removePackages(dependencies); }, { workspace, yes: options.yes, verbose: options.verbose, bailout: true, completeMessage: "clean complete" }); } async function resolveClean(context) { const { options, workspace } = context; const packages = await workspace.loadPackages(); const dependencies = []; for (const pkg of packages) { if (pkg.type === "package.json") continue; for (const dep of pkg.deps) { const resolvedDep = workspace.resolveDep(dep, false); if (!workspace.isDepInPackage(resolvedDep) && !workspace.isDepInPnpmOverrides(resolvedDep)) dependencies.push(resolvedDep); } } if (options.yes || !dependencies.length) return { dependencies }; const cache = /* @__PURE__ */ new Set(); const deps = []; for (const dep of dependencies) { const key = `${dep.name}.${dep.catalogName}.${dep.specifier}`; if (cache.has(key)) continue; cache.add(key); deps.push(dep); } const choices = await p.multiselect({ message: "please select the dependencies to clean", options: deps.map((dep, index) => ({ label: `${dep.name} (${dep.catalogName})`, value: index, hint: dep.specifier })), initialValues: Array.from({ length: deps.length }, (_, index) => index) }); if (p.isCancel(choices) || !choices) { p.outro(c.red("aborting")); process.exit(1); } return { dependencies: deps.filter((_, index) => choices.includes(index)) }; } //#endregion //#region src/utils/render.ts const MIN_DEP_NAME_WIDTH = 12; const MIN_DEP_TYPE_WIDTH = 6; const MIN_SPECIFIER_WIDTH = 10; const MIN_CATALOG_WIDTH = 10; function renderChanges(deps, updatedPackages) { if (!deps.length) return ""; let maxDepNameWidth = MIN_DEP_NAME_WIDTH; let maxDepTypeWidth = MIN_DEP_TYPE_WIDTH; let maxSpecifierWidth = MIN_SPECIFIER_WIDTH; let maxCatalogWidth = MIN_CATALOG_WIDTH; for (const dep of deps) { maxDepNameWidth = Math.max(maxDepNameWidth, dep.name.length); maxDepTypeWidth = Math.max(maxDepTypeWidth, DEPS_TYPE_SHORT_MAP[dep.source].length); maxSpecifierWidth = Math.max(maxSpecifierWidth, (dep.specifier || "").length); maxCatalogWidth = Math.max(maxCatalogWidth, dep.catalogName.length); } const depsByPackage = /* @__PURE__ */ new Map(); for (const dep of deps) for (const [pkgName$1, pkgMeta] of Object.entries(updatedPackages)) if (pkgMeta.deps.some((d) => d.name === dep.name && d.source === dep.source)) { if (!depsByPackage.has(pkgName$1)) depsByPackage.set(pkgName$1, []); depsByPackage.get(pkgName$1).push(dep); break; } const lines = []; for (const [pkgName$1, pkgMeta] of Object.entries(updatedPackages)) { const pkgDeps = depsByPackage.get(pkgName$1) || []; if (pkgDeps.length === 0) continue; lines.push(`${c.cyan(pkgName$1)} ${c.dim(pkgMeta.relative)}`); lines.push(""); for (const dep of pkgDeps) { const depName$1 = dep.name.padEnd(maxDepNameWidth); const depType = DEPS_TYPE_SHORT_MAP[dep.source].padEnd(maxDepTypeWidth); const depSpecifier = (dep.specifier || "").padStart(maxSpecifierWidth); const catalogRef = (dep.catalogName === "default" ? "" : dep.catalogName).padEnd(maxCatalogWidth); lines.push(` ${depName$1} ${c.dim(depType)} ${c.red(depSpecifier)} ${c.dim("→")} catalog:${c.reset(c.green(catalogRef))}`); } lines.push(""); } const pkgCount = Object.keys(updatedPackages).length; const pkgName = pkgCount === 1 ? "package" : "packages"; const depName = deps.length === 1 ? "dependency" : "dependencies"; lines.push(`${c.yellow(pkgCount)} ${pkgName} ${c.yellow(deps.length)} ${depName}`); return lines.join("\n"); } //#endregion //#region src/commands/migrate.ts var import_lodash$2 = /* @__PURE__ */ __toESM(require_lodash(), 1); async function migrateCommand(options) { const workspace = new Workspace(options); await workspace.catalog.ensureWorkspace(); const { dependencies = [], updatedPackages = {} } = await resolveMigrate({ options, workspace }); await confirmWorkspaceChanges(async () => { await workspace.catalog.generateCatalogs(dependencies); }, { workspace, updatedPackages, yes: options.yes, verbose: options.verbose, bailout: true, completeMessage: "migrate complete" }); } async function resolveMigrate(context) { const { options, workspace } = context; const packages = await workspace.loadPackages(); const dependencies = /* @__PURE__ */ new Map(); const updatedPackages = /* @__PURE__ */ new Map(); const setDep = (dep) => { if (!dependencies.has(dep.name)) dependencies.set(dep.name, /* @__PURE__ */ new Map()); const catalogDeps = dependencies.get(dep.name); if (!catalogDeps.has(dep.catalogName)) catalogDeps.set(dep.catalogName, []); catalogDeps.get(dep.catalogName).push(dep); }; const setPackage = async (dep, pkg) => { if (!updatedPackages.has(pkg.name)) updatedPackages.set(pkg.name, (0, import_lodash$2.default)(pkg)); await updatePackageToCatalog(dep, updatedPackages.get(pkg.name), workspace); }; for (const pkg of packages) { if (workspace.isCatalogPackage(pkg)) continue; for (const dep of pkg.deps) { if (!dep.catalogable) continue; const resolvedDep = workspace.resolveDep(dep); setDep(resolvedDep); if (resolvedDep.update) await setPackage(resolvedDep, pkg); } } await resolveConflict(dependencies, options); const deps = Array.from(dependencies.values()).flatMap((i) => Array.from(i.values()).flat()); const exists = new Set(deps.map((i) => i.name)); const catalogIndex = createDepCatalogIndex(await workspace.catalog.toJSON()); const preserved = []; for (const [depName, catalogs] of catalogIndex.entries()) { if (exists.has(depName)) continue; for (const catalog of catalogs) { const rawDep = { name: depName, specifier: catalog.specifier, catalog: true, catalogable: true, catalogName: catalog.catalogName, source: AGENT_CONFIG[options.agent || "pnpm"].depType }; if (options.force) rawDep.catalogName = inferCatalogName(rawDep, options); preserved.push(rawDep); } } return { dependencies: [...deps, ...preserved], updatedPackages: Object.fromEntries(updatedPackages.entries()) }; } async function resolveConflict(dependencies, options) { const conflicts = []; for (const [depName, catalogDeps] of dependencies) for (const [catalogName, deps] of catalogDeps) { const specs = [...new Set(deps.map((i) => i.specifier))]; if (specs.length > 1) { const specifiers = sortSpecs(specs); conflicts.push({ depName, catalogName, specifiers, resolvedSpecifier: specifiers[0] }); } else { const dep = deps[0]; dependencies.get(dep.name).set(dep.catalogName, [dep]); } } if (conflicts.length === 0) return; p.log.warn(`📦 Found ${c.yellow(conflicts.length)} dependencies that need manual version selection`); for (const item of conflicts) { if (options.yes) continue; const result = await p.select({ message: c.yellow(`${item.depName} (${item.catalogName}):`), options: item.specifiers.map((i) => ({ label: i, value: i })), initialValue: item.resolvedSpecifier }); if (!result || p.isCancel(result)) { p.outro(c.red("aborting")); process.exit(1); } item.resolvedSpecifier = result; } for (const conflict of conflicts) { const dep = dependencies.get(conflict.depName).get(conflict.catalogName).find((dep$1) => dep$1.specifier === conflict.resolvedSpecifier); dependencies.get(conflict.depName).set(conflict.catalogName, [dep]); } } //#endregion //#region src/commands/detect.ts async function detectCommand(options) { const { dependencies = [], updatedPackages = {} } = await resolveMigrate({ options, workspace: new Workspace(options) }); const deps = dependencies.filter((i) => i.update); if (!deps.length) { p.outro(c.yellow("no dependencies to migrate, aborting")); process.exit(0); } p.log.info(`📦 Found ${c.yellow(deps.length)} dependencies to migrate`); let result = renderChanges(deps, updatedPackages); if (result) { result += `\nrun ${c.green("pncat migrate")}${options.force ? c.green(" -f") : ""} to apply changes`; p.note(c.reset(result)); } p.outro(c.green("detect complete")); } //#endregion //#region src/commands/init.ts const ESLINT_FIX_PATTERNS = { pnpm: "\"**/package.json\" \"**/pnpm-workspace.yaml\"", yarn: "\"**/package.json\" \"**/.yarnrc.yml\"", bun: "\"**/package.json\"", vlt: "\"**/package.json\" \"**/vlt.json\"" }; function generateConfigContent(lines) { return lines.filter((line, index) => index === 1 || index === lines.length - 1 || Boolean(line)).join("\n"); } async function generateConfigLines(lines, workspace, results) { const { eslint = false } = results; const agent = workspace.getOptions().agent || "pnpm"; const packages = await workspace.loadPackages(); const start = lines.findIndex((line) => line === `export default defineConfig({`); const end = lines.findIndex((line) => line === `})`); if (eslint) lines.splice(end, 0, ` postRun: 'eslint --fix ${ESLINT_FIX_PATTERNS[agent]}',`); if (containsVSCodeExtension(packages)) lines.splice(start + 1, 0, ` exclude: ['@types/vscode'],`); return lines; } async function generateExtendConfig(workspace, results) { return generateConfigContent(await generateConfigLines([ `import { defineConfig, mergeCatalogRules } from 'pncat'`, ``, `export default defineConfig({`, ` catalogRules: mergeCatalogRules([]),`, `})`, `` ], workspace, results)); } async function genereateMinimalConfig(workspace, results) { const options = workspace.getOptions(); const deps = workspace.getDepNames(); const rulesMap = /* @__PURE__ */ new Map(); const rules = options.catalogRules?.length ? options.catalogRules : DEFAULT_CATALOG_RULES; for (const rule of rules) for (const dep of deps) toArray(rule.match).forEach((match) => { if (isDepMatched(dep, match)) { if (!rulesMap.has(rule.name)) rulesMap.set(rule.name, { ...rule, match: [] }); const storeMatch = toArray(rulesMap.get(rule.name).match ?? []); rulesMap.set(rule.name, { ...rule, match: [...new Set([...storeMatch, match])] }); } }); const catalogRules = Array.from(rulesMap.values()); const serializeMatch = (match) => { return `[${toArray(match).map((m) => { if (m instanceof RegExp) return m.toString(); return `'${m}'`; }).join(", ")}]`; }; const serializeSpecifierRules = (rules$1) => { return `[${rules$1.map((rule) => { const parts = [`specifier: '${rule.specifier}'`]; if (rule.match) parts.push(`match: ${serializeMatch(rule.match)}`); if (rule.name) parts.push(`name: '${rule.name}'`); if (rule.suffix) parts.push(`suffix: '${rule.suffix}'`); return `{ ${parts.join(", ")} }`; }).join(", ")}]`; }; const formatRuleObject = (fields) => { return [ " {", ...fields.map((field, index) => ` ${field}${index < fields.length - 1 ? "," : ""}`), " }" ].join("\n"); }; const lines = await generateConfigLines([ `import { defineConfig } from 'pncat'`, ``, `export default defineConfig({`, ` catalogRules: [`, catalogRules.map((rule) => { return formatRuleObject([ `name: '${rule.name}'`, `match: ${serializeMatch(rule.match)}`, rule.depFields ? `depFields: ${JSON.stringify(rule.depFields)}` : "", rule.priority ? `priority: ${rule.priority}` : "", rule.specifierRules ? `specifierRules: ${serializeSpecifierRules(rule.specifierRules)}` : "" ].filter(Boolean)); }).join(",\n"), ` ],`, `})`, `` ], workspace, results); p.note(c.reset(catalogRules.map((rule) => rule.name).join(", ")), `📋 Found ${c.yellow(catalogRules.length)} rules match current workspace`); if (!options.yes) { const result = await p.confirm({ message: `continue?` });