pncat
Version:
A unified cli tool that enhances package managers catalogs feature.
1,388 lines (1,367 loc) • 60.4 kB
JavaScript
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?` });