comze 0.3.1 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.mjs +159 -26
  2. package/package.json +1 -1
package/dist/cli.mjs CHANGED
@@ -7395,7 +7395,7 @@ var import_picocolors2 = __toESM(require_picocolors(), 1);
7395
7395
  import { resolve } from "path";
7396
7396
 
7397
7397
  // src/fetcher.ts
7398
- var import_semver2 = __toESM(require_semver2(), 1);
7398
+ var import_semver3 = __toESM(require_semver2(), 1);
7399
7399
 
7400
7400
  // src/types.ts
7401
7401
  var STABILITY_ORDER = {
@@ -7570,23 +7570,27 @@ function getCacheDir() {
7570
7570
  }
7571
7571
  return path.join(process.env.XDG_CACHE_HOME || path.join(home, ".cache"), "comze");
7572
7572
  }
7573
- async function getCacheEntry(key) {
7573
+ async function getCacheEntry(key, expectedVersion) {
7574
7574
  try {
7575
7575
  const cacheDir = getCacheDir();
7576
7576
  const filePath = path.join(cacheDir, `${key}.json`);
7577
7577
  const content = await fs.readFile(filePath, "utf-8");
7578
7578
  const data = JSON.parse(content);
7579
+ if (data.version !== expectedVersion) {
7580
+ return null;
7581
+ }
7579
7582
  return data;
7580
7583
  } catch {
7581
7584
  return null;
7582
7585
  }
7583
7586
  }
7584
- async function setCache(key, value, meta = {}) {
7587
+ async function setCache(key, value, version, meta = {}) {
7585
7588
  try {
7586
7589
  const cacheDir = getCacheDir();
7587
7590
  await fs.mkdir(cacheDir, { recursive: true });
7588
7591
  const filePath = path.join(cacheDir, `${key}.json`);
7589
7592
  const data = {
7593
+ version,
7590
7594
  timestamp: Date.now(),
7591
7595
  value,
7592
7596
  lastModified: meta.lastModified,
@@ -7595,37 +7599,131 @@ async function setCache(key, value, meta = {}) {
7595
7599
  await fs.writeFile(filePath, JSON.stringify(data), "utf-8");
7596
7600
  } catch {}
7597
7601
  }
7598
- async function touchCache(key) {
7602
+ async function touchCache(key, version) {
7599
7603
  try {
7600
- const entry = await getCacheEntry(key);
7604
+ const entry = await getCacheEntry(key, version);
7601
7605
  if (entry) {
7602
- await setCache(key, entry.value, { lastModified: entry.lastModified, etag: entry.etag });
7606
+ await setCache(key, entry.value, version, {
7607
+ lastModified: entry.lastModified,
7608
+ etag: entry.etag
7609
+ });
7603
7610
  }
7604
7611
  } catch {}
7605
7612
  }
7606
7613
 
7614
+ // src/utils/php.ts
7615
+ var import_semver2 = __toESM(require_semver2(), 1);
7616
+ function normalizeComposerConstraint(constraint) {
7617
+ if (!constraint)
7618
+ return "*";
7619
+ let normalized = constraint.trim();
7620
+ normalized = normalized.replace(/\|\|/g, "<<<OR>>>");
7621
+ normalized = normalized.replace(/\|/g, "<<<OR>>>");
7622
+ normalized = normalized.replace(/<<<OR>>>/g, " || ");
7623
+ normalized = normalized.replace(/\s*\|\|\s*/g, " || ");
7624
+ normalized = normalized.replace(/,\s*/g, " ");
7625
+ normalized = normalized.replace(/@(dev|alpha|beta|rc|stable)/gi, "");
7626
+ if (normalized === "*" || normalized.startsWith("ext-")) {
7627
+ return "*";
7628
+ }
7629
+ return normalized;
7630
+ }
7631
+ function extractMinVersion(constraint) {
7632
+ const normalized = normalizeComposerConstraint(constraint);
7633
+ if (normalized === "*")
7634
+ return null;
7635
+ const orParts = normalized.split(/\s*\|\|\s*/);
7636
+ let minVersion = null;
7637
+ for (const part of orParts) {
7638
+ const coerced = import_semver2.default.coerce(part.trim());
7639
+ if (coerced) {
7640
+ if (!minVersion || import_semver2.default.lt(coerced.version, minVersion)) {
7641
+ minVersion = coerced.version;
7642
+ }
7643
+ }
7644
+ }
7645
+ return minVersion;
7646
+ }
7647
+ function extractMaxVersion(constraint) {
7648
+ const normalized = normalizeComposerConstraint(constraint);
7649
+ if (normalized === "*")
7650
+ return null;
7651
+ const upperBoundMatch = normalized.match(/<(=?)\s*(\d+(?:\.\d+)*)/);
7652
+ if (upperBoundMatch) {
7653
+ const coerced = import_semver2.default.coerce(upperBoundMatch[2]);
7654
+ return coerced ? coerced.version : null;
7655
+ }
7656
+ const caretMatch = normalized.match(/\^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
7657
+ if (caretMatch) {
7658
+ const major = parseInt(caretMatch[1], 10);
7659
+ return `${major + 1}.0.0`;
7660
+ }
7661
+ return null;
7662
+ }
7663
+ function checkPhpCompatibility(projectPhp, packagePhp) {
7664
+ if (!packagePhp || packagePhp === "*")
7665
+ return { satisfied: true };
7666
+ if (!projectPhp)
7667
+ return { satisfied: true };
7668
+ const projectMin = extractMinVersion(projectPhp);
7669
+ if (!projectMin)
7670
+ return { satisfied: true };
7671
+ const packageNorm = normalizeComposerConstraint(packagePhp);
7672
+ const packageParts = packageNorm.split(/\s*\|\|\s*/).filter((p) => p.trim());
7673
+ for (const part of packageParts) {
7674
+ const partMax = extractMaxVersion(part);
7675
+ if (partMax && import_semver2.default.gte(projectMin, partMax))
7676
+ continue;
7677
+ try {
7678
+ const range = import_semver2.default.validRange(part.trim());
7679
+ if (range && import_semver2.default.satisfies(projectMin, range))
7680
+ return { satisfied: true };
7681
+ } catch {}
7682
+ const partMin = extractMinVersion(part);
7683
+ if (partMin) {
7684
+ const partMajor = import_semver2.default.major(partMin);
7685
+ const projectMajor = import_semver2.default.major(projectMin);
7686
+ if (part.trim().startsWith("^")) {
7687
+ if (projectMajor === partMajor && import_semver2.default.gte(projectMin, partMin)) {
7688
+ return { satisfied: true };
7689
+ }
7690
+ } else if (import_semver2.default.gte(projectMin, partMin) && !partMax) {
7691
+ return { satisfied: true };
7692
+ }
7693
+ }
7694
+ }
7695
+ return { satisfied: false, reason: `requires php ${packagePhp}` };
7696
+ }
7697
+
7607
7698
  // src/fetcher.ts
7608
7699
  var PACKAGIST_API = "https://repo.packagist.org/p2";
7609
- async function fetchPackage(packageName, minStability = "stable", preferStable = true, currentVersion, allowMajor = true, noCache = false) {
7700
+ var CACHE_VERSION = 1;
7701
+ async function fetchPackage(packageName, minStability = "stable", preferStable = true, currentVersion, allowMajor = true, noCache = false, projectPhp) {
7610
7702
  const cacheKey = packageName.replace("/", "_");
7611
7703
  let cachedEntry = null;
7612
7704
  const headers = {};
7613
7705
  if (!noCache) {
7614
- cachedEntry = await getCacheEntry(cacheKey);
7706
+ cachedEntry = await getCacheEntry(cacheKey, CACHE_VERSION);
7615
7707
  if (cachedEntry?.lastModified) {
7616
7708
  headers["If-Modified-Since"] = cachedEntry.lastModified;
7617
7709
  }
7618
7710
  }
7711
+ let data;
7619
7712
  try {
7620
7713
  const url = `${PACKAGIST_API}/${packageName}.json`;
7621
7714
  const response = await fetch(url, { headers });
7622
7715
  if (response.status === 304 && cachedEntry) {
7623
- await touchCache(cacheKey);
7624
- return cachedEntry.value;
7625
- }
7626
- if (!response.ok)
7716
+ await touchCache(cacheKey, CACHE_VERSION);
7717
+ data = cachedEntry.value;
7718
+ } else if (response.ok) {
7719
+ data = await response.json();
7720
+ if (!noCache) {
7721
+ const lastModified = response.headers.get("Last-Modified") || undefined;
7722
+ await setCache(cacheKey, data, CACHE_VERSION, { lastModified });
7723
+ }
7724
+ } else {
7627
7725
  return null;
7628
- const data = await response.json();
7726
+ }
7629
7727
  const versions = data.packages?.[packageName] ?? [];
7630
7728
  if (versions.length === 0)
7631
7729
  return null;
@@ -7653,21 +7751,39 @@ async function fetchPackage(packageName, minStability = "stable", preferStable =
7653
7751
  }
7654
7752
  if (!selectedVersion)
7655
7753
  return null;
7754
+ let phpIncompatible = false;
7755
+ let skippedVersion;
7756
+ if (projectPhp && selectedVersion.require?.php) {
7757
+ const phpCheck = checkPhpCompatibility(projectPhp, selectedVersion.require.php);
7758
+ if (!phpCheck.satisfied) {
7759
+ phpIncompatible = true;
7760
+ skippedVersion = selectedVersion.version;
7761
+ const versionsToCheck = preferStable ? eligibleVersions.filter((v) => getVersionStability(v.version) === "stable") : eligibleVersions;
7762
+ const compatibleVersion = versionsToCheck.find((v) => {
7763
+ if (!v.require?.php)
7764
+ return true;
7765
+ return checkPhpCompatibility(projectPhp, v.require.php).satisfied;
7766
+ });
7767
+ if (compatibleVersion && compatibleVersion !== selectedVersion) {
7768
+ selectedVersion = compatibleVersion;
7769
+ }
7770
+ }
7771
+ }
7656
7772
  const phpRequirement = selectedVersion.require?.php;
7657
7773
  let majorDetected;
7658
7774
  if (currentVersion) {
7659
7775
  const currentNorm = normalizeVersion(currentVersion);
7660
7776
  const selectedNorm = normalizeVersion(selectedVersion.version);
7661
7777
  if (currentNorm && selectedNorm) {
7662
- const currentMajor = import_semver2.default.major(currentNorm);
7663
- const selectedMajor = import_semver2.default.major(selectedNorm);
7778
+ const currentMajor = import_semver3.default.major(currentNorm);
7779
+ const selectedMajor = import_semver3.default.major(selectedNorm);
7664
7780
  if (selectedMajor > currentMajor) {
7665
7781
  majorDetected = selectedVersion.version;
7666
7782
  if (!allowMajor) {
7667
7783
  const versionsToCheck = preferStable ? eligibleVersions.filter((v) => getVersionStability(v.version) === "stable") : eligibleVersions;
7668
7784
  const sameMajorVersion = versionsToCheck.find((v) => {
7669
7785
  const norm = normalizeVersion(v.version);
7670
- return norm && import_semver2.default.major(norm) === currentMajor;
7786
+ return norm && import_semver3.default.major(norm) === currentMajor;
7671
7787
  });
7672
7788
  if (sameMajorVersion) {
7673
7789
  selectedVersion = sameMajorVersion;
@@ -7689,25 +7805,24 @@ async function fetchPackage(packageName, minStability = "stable", preferStable =
7689
7805
  phpRequirement: selectedVersion.require?.php ?? phpRequirement,
7690
7806
  majorVersion: majorDetected,
7691
7807
  deprecated: deprecatedInfo.deprecated,
7692
- replacement: deprecatedInfo.replacement
7808
+ replacement: deprecatedInfo.replacement,
7809
+ phpIncompatible: phpIncompatible || undefined,
7810
+ skippedVersion,
7811
+ require: selectedVersion.require
7693
7812
  };
7694
- if (!noCache) {
7695
- const lastModified = response.headers.get("Last-Modified") || undefined;
7696
- await setCache(cacheKey, result, { lastModified });
7697
- }
7698
7813
  return result;
7699
7814
  } catch {
7700
7815
  return null;
7701
7816
  }
7702
7817
  }
7703
- async function fetchAllPackages(packages, minStability = "stable", preferStable = true, allowMajor = true, noCache = false) {
7818
+ async function fetchAllPackages(packages, minStability = "stable", preferStable = true, allowMajor = true, noCache = false, projectPhp) {
7704
7819
  const results = new Map;
7705
7820
  const entries = Object.entries(packages);
7706
7821
  const CONCURRENCY = 5;
7707
7822
  for (let i = 0;i < entries.length; i += CONCURRENCY) {
7708
7823
  const batch = entries.slice(i, i + CONCURRENCY);
7709
7824
  const promises = batch.map(async ([name, version]) => {
7710
- const result = await fetchPackage(name, minStability, preferStable, version, allowMajor, noCache);
7825
+ const result = await fetchPackage(name, minStability, preferStable, version, allowMajor, noCache, projectPhp);
7711
7826
  if (result)
7712
7827
  results.set(name, result);
7713
7828
  });
@@ -7964,6 +8079,9 @@ function renderTable(packages) {
7964
8079
  if (pkg.phpRequirement) {
7965
8080
  extra += import_picocolors.default.gray(` php ${pkg.phpRequirement}`);
7966
8081
  }
8082
+ if (pkg.phpIncompatible && pkg.skippedVersion) {
8083
+ extra += import_picocolors.default.yellow(` ${pkg.skippedVersion} skipped (php)`);
8084
+ }
7967
8085
  if (pkg.deprecated) {
7968
8086
  extra += import_picocolors.default.red(" deprecated");
7969
8087
  if (pkg.replacement) {
@@ -7972,6 +8090,15 @@ function renderTable(packages) {
7972
8090
  }
7973
8091
  console.log(` ${name} ${oldVer} ${arrow} ${coloredNewVer} ${diffLabel} ${age}${extra}`);
7974
8092
  }
8093
+ const skippedPackages = packages.filter((p) => p.phpIncompatible && p.skippedVersion);
8094
+ if (skippedPackages.length > 0) {
8095
+ console.log(import_picocolors.default.yellow(`
8096
+ Some versions skipped due to PHP constraints:`));
8097
+ for (const pkg of skippedPackages) {
8098
+ console.log(` ${import_picocolors.default.bold(pkg.name)} ${pkg.skippedVersion} requires higher PHP version`);
8099
+ }
8100
+ console.log(import_picocolors.default.gray(" Update the php constraint in composer.json to use these versions."));
8101
+ }
7975
8102
  console.log("");
7976
8103
  }
7977
8104
  function renderHeader(version) {
@@ -8012,6 +8139,9 @@ function formatPackageChoice(pkg) {
8012
8139
  if (pkg.phpRequirement) {
8013
8140
  extra += import_picocolors.default.gray(` php ${pkg.phpRequirement}`);
8014
8141
  }
8142
+ if (pkg.phpIncompatible && pkg.skippedVersion) {
8143
+ extra += import_picocolors.default.yellow(` ${pkg.skippedVersion} skipped`);
8144
+ }
8015
8145
  if (pkg.deprecated) {
8016
8146
  extra += import_picocolors.default.red(" deprecated");
8017
8147
  if (pkg.replacement) {
@@ -8057,7 +8187,7 @@ async function selectPackages(packages) {
8057
8187
  // package.json
8058
8188
  var package_default = {
8059
8189
  name: "comze",
8060
- version: "0.3.1",
8190
+ version: "0.3.2",
8061
8191
  description: "A taze-like CLI for updating composer.json dependencies",
8062
8192
  author: "qoqn",
8063
8193
  license: "MIT",
@@ -8133,7 +8263,8 @@ async function run(options) {
8133
8263
  console.log(import_picocolors2.default.gray(` Checking ${Object.keys(filteredPackages).length} packages...`));
8134
8264
  console.log(import_picocolors2.default.gray(` Stability: ${minStability}${preferStable ? " (prefer-stable)" : ""}
8135
8265
  `));
8136
- const results = await fetchAllPackages(filteredPackages, minStability, preferStable, options.major, options.noCache);
8266
+ const projectPhp = allPackages["php"];
8267
+ const results = await fetchAllPackages(filteredPackages, minStability, preferStable, options.major, options.noCache, projectPhp);
8137
8268
  const updates = [];
8138
8269
  const deprecatedPackages = [];
8139
8270
  for (const [name, currentVersion] of Object.entries(filteredPackages)) {
@@ -8168,7 +8299,9 @@ async function run(options) {
8168
8299
  majorAvailable,
8169
8300
  phpRequirement: result.phpRequirement,
8170
8301
  deprecated: result.deprecated,
8171
- replacement: result.replacement
8302
+ replacement: result.replacement,
8303
+ phpIncompatible: result.phpIncompatible,
8304
+ skippedVersion: result.skippedVersion
8172
8305
  });
8173
8306
  }
8174
8307
  const order = { major: 0, minor: 1, patch: 2 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comze",
3
- "version": "0.3.1",
3
+ "version": "0.3.2",
4
4
  "description": "A taze-like CLI for updating composer.json dependencies",
5
5
  "author": "qoqn",
6
6
  "license": "MIT",