comze 0.3.1 → 0.4.0

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 (3) hide show
  1. package/README.md +23 -1
  2. package/dist/cli.mjs +439 -249
  3. package/package.json +4 -4
package/README.md CHANGED
@@ -47,6 +47,9 @@ comze --dry-run
47
47
 
48
48
  # Exclude packages
49
49
  comze --exclude vendor/package
50
+
51
+ # Exclude multiple packages
52
+ comze --exclude vendor/package-a,vendor/package-b
50
53
  ```
51
54
 
52
55
  ## Options
@@ -59,9 +62,28 @@ comze --exclude vendor/package
59
62
  | `--major` | Include major updates (default: false) |
60
63
  | `--minor` | Include minor updates (default: true) |
61
64
  | `--patch` | Include patch updates (default: true) |
62
- | `--exclude <pkgs>` | Exclude packages (comma-separated) |
65
+ | `--exclude <pkgs>` | Exclude packages (comma-separated, merged with `extra.comze.exclude`) |
63
66
  | `--dry-run` | Preview changes without writing |
64
67
 
68
+ ## Persistent Excludes
69
+
70
+ For packages that should always be ignored, store them in `composer.json` under `extra.comze.exclude`:
71
+
72
+ ```json
73
+ {
74
+ "extra": {
75
+ "comze": {
76
+ "exclude": [
77
+ "vendor/package-a",
78
+ "vendor/package-b"
79
+ ]
80
+ }
81
+ }
82
+ }
83
+ ```
84
+
85
+ `comze` merges this list with `--exclude`, so the flag remains useful for one-off runs while the file keeps repository-wide defaults.
86
+
65
87
  ## Composer Stability
66
88
 
67
89
  comze reads `minimum-stability` and `prefer-stable` from your `composer.json`:
package/dist/cli.mjs CHANGED
@@ -4,15 +4,29 @@ var __getProtoOf = Object.getPrototypeOf;
4
4
  var __defProp = Object.defineProperty;
5
5
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
6
  var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ function __accessProp(key) {
8
+ return this[key];
9
+ }
10
+ var __toESMCache_node;
11
+ var __toESMCache_esm;
7
12
  var __toESM = (mod, isNodeMode, target) => {
13
+ var canCache = mod != null && typeof mod === "object";
14
+ if (canCache) {
15
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
16
+ var cached = cache.get(mod);
17
+ if (cached)
18
+ return cached;
19
+ }
8
20
  target = mod != null ? __create(__getProtoOf(mod)) : {};
9
21
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
22
  for (let key of __getOwnPropNames(mod))
11
23
  if (!__hasOwnProp.call(to, key))
12
24
  __defProp(to, key, {
13
- get: () => mod[key],
25
+ get: __accessProp.bind(mod, key),
14
26
  enumerable: true
15
27
  });
28
+ if (canCache)
29
+ cache.set(mod, to);
16
30
  return to;
17
31
  };
18
32
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
@@ -2095,7 +2109,7 @@ var require_clear = __commonJS((exports, module) => {
2095
2109
  if (it)
2096
2110
  o = it;
2097
2111
  var i = 0;
2098
- var F = function F() {};
2112
+ var F = function F2() {};
2099
2113
  return { s: F, n: function n() {
2100
2114
  if (i >= o.length)
2101
2115
  return { done: true };
@@ -2310,13 +2324,13 @@ var require_prompt = __commonJS((exports, module) => {
2310
2324
  var readline = __require("readline");
2311
2325
  var _require = require_util();
2312
2326
  var action = _require.action;
2313
- var EventEmitter2 = __require("events");
2327
+ var EventEmitter = __require("events");
2314
2328
  var _require2 = require_src();
2315
2329
  var beep = _require2.beep;
2316
2330
  var cursor = _require2.cursor;
2317
2331
  var color = require_kleur();
2318
2332
 
2319
- class Prompt extends EventEmitter2 {
2333
+ class Prompt extends EventEmitter {
2320
2334
  constructor(opts = {}) {
2321
2335
  super();
2322
2336
  this.firstRender = true;
@@ -4427,7 +4441,7 @@ var require_dist = __commonJS((exports, module) => {
4427
4441
  if (it)
4428
4442
  o = it;
4429
4443
  var i = 0;
4430
- var F = function F() {};
4444
+ var F = function F2() {};
4431
4445
  return { s: F, n: function n() {
4432
4446
  if (i >= o.length)
4433
4447
  return { done: true };
@@ -4530,7 +4544,7 @@ In order to be iterable, non-array objects must have a [Symbol.iterator]() metho
4530
4544
  }
4531
4545
  return question2.format ? yield question2.format(answer2, answers) : answer2;
4532
4546
  });
4533
- return function getFormattedAnswer(_x, _x2) {
4547
+ return function getFormattedAnswer2(_x, _x2) {
4534
4548
  return _ref.apply(this, arguments);
4535
4549
  };
4536
4550
  }();
@@ -4818,11 +4832,11 @@ var require_util2 = __commonJS((exports, module) => {
4818
4832
  var require_prompt2 = __commonJS((exports, module) => {
4819
4833
  var readline = __require("readline");
4820
4834
  var { action } = require_util2();
4821
- var EventEmitter2 = __require("events");
4835
+ var EventEmitter = __require("events");
4822
4836
  var { beep, cursor } = require_src();
4823
4837
  var color = require_kleur();
4824
4838
 
4825
- class Prompt extends EventEmitter2 {
4839
+ class Prompt extends EventEmitter {
4826
4840
  constructor(opts = {}) {
4827
4841
  super();
4828
4842
  this.firstRender = true;
@@ -6788,8 +6802,7 @@ var require_prompts3 = __commonJS((exports, module) => {
6788
6802
  module.exports = isNodeLT("8.6.0") ? require_dist() : require_lib();
6789
6803
  });
6790
6804
 
6791
- // node_modules/cac/dist/index.mjs
6792
- import { EventEmitter } from "events";
6805
+ // node_modules/cac/dist/index.js
6793
6806
  function toArr(any) {
6794
6807
  return any == null ? [] : Array.isArray(any) ? any : [any];
6795
6808
  }
@@ -6797,7 +6810,7 @@ function toVal(out, key, val, opts) {
6797
6810
  var x, old = out[key], nxt = ~opts.string.indexOf(key) ? val == null || val === true ? "" : String(val) : typeof val === "boolean" ? val : ~opts.boolean.indexOf(key) ? val === "false" ? false : val === "true" || (out._.push((x = +val, x * 0 === 0) ? x : val), !!val) : (x = +val, x * 0 === 0) ? x : val;
6798
6811
  out[key] = old == null ? nxt : Array.isArray(old) ? old.concat(nxt) : [old, nxt];
6799
6812
  }
6800
- function mri2(args, opts) {
6813
+ function lib_default(args, opts) {
6801
6814
  args = args || [];
6802
6815
  opts = opts || {};
6803
6816
  var k, arr, arg, name, val, out = { _: [] };
@@ -6808,14 +6821,12 @@ function mri2(args, opts) {
6808
6821
  opts.alias = opts.alias || {};
6809
6822
  opts.string = toArr(opts.string);
6810
6823
  opts.boolean = toArr(opts.boolean);
6811
- if (alibi) {
6824
+ if (alibi)
6812
6825
  for (k in opts.alias) {
6813
6826
  arr = opts.alias[k] = toArr(opts.alias[k]);
6814
- for (i = 0;i < arr.length; i++) {
6827
+ for (i = 0;i < arr.length; i++)
6815
6828
  (opts.alias[arr[i]] = arr.concat(k)).splice(i, 1);
6816
- }
6817
6829
  }
6818
- }
6819
6830
  for (i = opts.boolean.length;i-- > 0; ) {
6820
6831
  arr = opts.alias[opts.boolean[i]] || [];
6821
6832
  for (j = arr.length;j-- > 0; )
@@ -6826,18 +6837,16 @@ function mri2(args, opts) {
6826
6837
  for (j = arr.length;j-- > 0; )
6827
6838
  opts.string.push(arr[j]);
6828
6839
  }
6829
- if (defaults) {
6840
+ if (defaults)
6830
6841
  for (k in opts.default) {
6831
6842
  name = typeof opts.default[k];
6832
6843
  arr = opts.alias[k] = opts.alias[k] || [];
6833
6844
  if (opts[name] !== undefined) {
6834
6845
  opts[name].push(k);
6835
- for (i = 0;i < arr.length; i++) {
6846
+ for (i = 0;i < arr.length; i++)
6836
6847
  opts[name].push(arr[i]);
6837
- }
6838
6848
  }
6839
6849
  }
6840
- }
6841
6850
  const keys = strict ? Object.keys(opts.alias) : [];
6842
6851
  for (i = 0;i < len; i++) {
6843
6852
  arg = args[i];
@@ -6845,25 +6854,22 @@ function mri2(args, opts) {
6845
6854
  out._ = out._.concat(args.slice(++i));
6846
6855
  break;
6847
6856
  }
6848
- for (j = 0;j < arg.length; j++) {
6857
+ for (j = 0;j < arg.length; j++)
6849
6858
  if (arg.charCodeAt(j) !== 45)
6850
6859
  break;
6851
- }
6852
- if (j === 0) {
6860
+ if (j === 0)
6853
6861
  out._.push(arg);
6854
- } else if (arg.substring(j, j + 3) === "no-") {
6862
+ else if (arg.substring(j, j + 3) === "no-") {
6855
6863
  name = arg.substring(j + 3);
6856
- if (strict && !~keys.indexOf(name)) {
6864
+ if (strict && !~keys.indexOf(name))
6857
6865
  return opts.unknown(arg);
6858
- }
6859
6866
  out[name] = false;
6860
6867
  } else {
6861
- for (idx = j + 1;idx < arg.length; idx++) {
6868
+ for (idx = j + 1;idx < arg.length; idx++)
6862
6869
  if (arg.charCodeAt(idx) === 61)
6863
6870
  break;
6864
- }
6865
6871
  name = arg.substring(j, idx);
6866
- val = arg.substring(++idx) || (i + 1 === len || ("" + args[i + 1]).charCodeAt(0) === 45 || args[++i]);
6872
+ val = arg.substring(++idx) || i + 1 === len || ("" + args[i + 1]).charCodeAt(0) === 45 || args[++i];
6867
6873
  arr = j === 2 ? [name] : name;
6868
6874
  for (idx = 0;idx < arr.length; idx++) {
6869
6875
  name = arr[idx];
@@ -6874,24 +6880,22 @@ function mri2(args, opts) {
6874
6880
  }
6875
6881
  }
6876
6882
  if (defaults) {
6877
- for (k in opts.default) {
6878
- if (out[k] === undefined) {
6883
+ for (k in opts.default)
6884
+ if (out[k] === undefined)
6879
6885
  out[k] = opts.default[k];
6880
- }
6881
- }
6882
6886
  }
6883
- if (alibi) {
6887
+ if (alibi)
6884
6888
  for (k in out) {
6885
6889
  arr = opts.alias[k] || [];
6886
- while (arr.length > 0) {
6890
+ while (arr.length > 0)
6887
6891
  out[arr.shift()] = out[k];
6888
- }
6889
6892
  }
6890
- }
6891
6893
  return out;
6892
6894
  }
6893
- var removeBrackets = (v) => v.replace(/[<[].+/, "").trim();
6894
- var findAllBrackets = (v) => {
6895
+ function removeBrackets(v) {
6896
+ return v.replace(/[<[].+/, "").trim();
6897
+ }
6898
+ function findAllBrackets(v) {
6895
6899
  const ANGLED_BRACKET_RE_GLOBAL = /<([^>]+)>/g;
6896
6900
  const SQUARE_BRACKET_RE_GLOBAL = /\[([^\]]+)\]/g;
6897
6901
  const res = [];
@@ -6909,98 +6913,101 @@ var findAllBrackets = (v) => {
6909
6913
  };
6910
6914
  };
6911
6915
  let angledMatch;
6912
- while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v)) {
6916
+ while (angledMatch = ANGLED_BRACKET_RE_GLOBAL.exec(v))
6913
6917
  res.push(parse(angledMatch));
6914
- }
6915
6918
  let squareMatch;
6916
- while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v)) {
6919
+ while (squareMatch = SQUARE_BRACKET_RE_GLOBAL.exec(v))
6917
6920
  res.push(parse(squareMatch));
6918
- }
6919
6921
  return res;
6920
- };
6921
- var getMriOptions = (options) => {
6922
- const result = { alias: {}, boolean: [] };
6922
+ }
6923
+ function getMriOptions(options) {
6924
+ const result = {
6925
+ alias: {},
6926
+ boolean: []
6927
+ };
6923
6928
  for (const [index, option] of options.entries()) {
6924
- if (option.names.length > 1) {
6929
+ if (option.names.length > 1)
6925
6930
  result.alias[option.names[0]] = option.names.slice(1);
6926
- }
6927
- if (option.isBoolean) {
6931
+ if (option.isBoolean)
6928
6932
  if (option.negated) {
6929
- const hasStringTypeOption = options.some((o, i) => {
6933
+ if (!options.some((o, i) => {
6930
6934
  return i !== index && o.names.some((name) => option.names.includes(name)) && typeof o.required === "boolean";
6931
- });
6932
- if (!hasStringTypeOption) {
6935
+ }))
6933
6936
  result.boolean.push(option.names[0]);
6934
- }
6935
- } else {
6937
+ } else
6936
6938
  result.boolean.push(option.names[0]);
6937
- }
6938
- }
6939
6939
  }
6940
6940
  return result;
6941
- };
6942
- var findLongest = (arr) => {
6941
+ }
6942
+ function findLongest(arr) {
6943
6943
  return arr.sort((a, b) => {
6944
6944
  return a.length > b.length ? -1 : 1;
6945
6945
  })[0];
6946
- };
6947
- var padRight = (str, length) => {
6946
+ }
6947
+ function padRight(str, length) {
6948
6948
  return str.length >= length ? str : `${str}${" ".repeat(length - str.length)}`;
6949
- };
6950
- var camelcase = (input) => {
6951
- return input.replace(/([a-z])-([a-z])/g, (_, p1, p2) => {
6949
+ }
6950
+ function camelcase(input) {
6951
+ return input.replaceAll(/([a-z])-([a-z])/g, (_, p1, p2) => {
6952
6952
  return p1 + p2.toUpperCase();
6953
6953
  });
6954
- };
6955
- var setDotProp = (obj, keys, val) => {
6956
- let i = 0;
6957
- let length = keys.length;
6958
- let t = obj;
6959
- let x;
6960
- for (;i < length; ++i) {
6961
- x = t[keys[i]];
6962
- t = t[keys[i]] = i === length - 1 ? val : x != null ? x : !!~keys[i + 1].indexOf(".") || !(+keys[i + 1] > -1) ? {} : [];
6954
+ }
6955
+ function setDotProp(obj, keys, val) {
6956
+ let current = obj;
6957
+ for (let i = 0;i < keys.length; i++) {
6958
+ const key = keys[i];
6959
+ if (i === keys.length - 1) {
6960
+ current[key] = val;
6961
+ return;
6962
+ }
6963
+ if (current[key] == null) {
6964
+ const nextKeyIsArrayIndex = +keys[i + 1] > -1;
6965
+ current[key] = nextKeyIsArrayIndex ? [] : {};
6966
+ }
6967
+ current = current[key];
6963
6968
  }
6964
- };
6965
- var setByType = (obj, transforms) => {
6969
+ }
6970
+ function setByType(obj, transforms) {
6966
6971
  for (const key of Object.keys(transforms)) {
6967
6972
  const transform = transforms[key];
6968
6973
  if (transform.shouldTransform) {
6969
- obj[key] = Array.prototype.concat.call([], obj[key]);
6970
- if (typeof transform.transformFunction === "function") {
6974
+ obj[key] = [obj[key]].flat();
6975
+ if (typeof transform.transformFunction === "function")
6971
6976
  obj[key] = obj[key].map(transform.transformFunction);
6972
- }
6973
6977
  }
6974
6978
  }
6975
- };
6976
- var getFileName = (input) => {
6977
- const m = /([^\\\/]+)$/.exec(input);
6979
+ }
6980
+ function getFileName(input) {
6981
+ const m = /([^\\/]+)$/.exec(input);
6978
6982
  return m ? m[1] : "";
6979
- };
6980
- var camelcaseOptionName = (name) => {
6983
+ }
6984
+ function camelcaseOptionName(name) {
6981
6985
  return name.split(".").map((v, i) => {
6982
6986
  return i === 0 ? camelcase(v) : v;
6983
6987
  }).join(".");
6984
- };
6985
-
6986
- class CACError extends Error {
6988
+ }
6989
+ var CACError = class extends Error {
6987
6990
  constructor(message) {
6988
6991
  super(message);
6989
- this.name = this.constructor.name;
6990
- if (typeof Error.captureStackTrace === "function") {
6991
- Error.captureStackTrace(this, this.constructor);
6992
- } else {
6992
+ this.name = "CACError";
6993
+ if (typeof Error.captureStackTrace !== "function")
6993
6994
  this.stack = new Error(message).stack;
6994
- }
6995
6995
  }
6996
- }
6997
-
6998
- class Option {
6996
+ };
6997
+ var Option = class {
6998
+ rawName;
6999
+ description;
7000
+ name;
7001
+ names;
7002
+ isBoolean;
7003
+ required;
7004
+ config;
7005
+ negated;
6999
7006
  constructor(rawName, description, config) {
7000
7007
  this.rawName = rawName;
7001
7008
  this.description = description;
7002
7009
  this.config = Object.assign({}, config);
7003
- rawName = rawName.replace(/\.\*/g, "");
7010
+ rawName = rawName.replaceAll(".*", "");
7004
7011
  this.negated = false;
7005
7012
  this.names = removeBrackets(rawName).split(",").map((v) => {
7006
7013
  let name = v.trim().replace(/^-{1,2}/, "");
@@ -7010,23 +7017,48 @@ class Option {
7010
7017
  }
7011
7018
  return camelcaseOptionName(name);
7012
7019
  }).sort((a, b) => a.length > b.length ? 1 : -1);
7013
- this.name = this.names[this.names.length - 1];
7014
- if (this.negated && this.config.default == null) {
7020
+ this.name = this.names.at(-1);
7021
+ if (this.negated && this.config.default == null)
7015
7022
  this.config.default = true;
7016
- }
7017
- if (rawName.includes("<")) {
7023
+ if (rawName.includes("<"))
7018
7024
  this.required = true;
7019
- } else if (rawName.includes("[")) {
7025
+ else if (rawName.includes("["))
7020
7026
  this.required = false;
7021
- } else {
7027
+ else
7022
7028
  this.isBoolean = true;
7023
- }
7024
7029
  }
7025
- }
7026
- var processArgs = process.argv;
7027
- var platformInfo = `${process.platform}-${process.arch} node-${process.version}`;
7028
-
7029
- class Command {
7030
+ };
7031
+ var runtimeProcessArgs;
7032
+ var runtimeInfo;
7033
+ if (typeof process !== "undefined") {
7034
+ let runtimeName;
7035
+ if (typeof Deno !== "undefined" && typeof Deno.version?.deno === "string")
7036
+ runtimeName = "deno";
7037
+ else if (typeof Bun !== "undefined" && typeof Bun.version === "string")
7038
+ runtimeName = "bun";
7039
+ else
7040
+ runtimeName = "node";
7041
+ runtimeInfo = `${process.platform}-${process.arch} ${runtimeName}-${process.version}`;
7042
+ runtimeProcessArgs = process.argv;
7043
+ } else if (typeof navigator === "undefined")
7044
+ runtimeInfo = `unknown`;
7045
+ else
7046
+ runtimeInfo = `${navigator.platform} ${navigator.userAgent}`;
7047
+ var Command = class {
7048
+ rawName;
7049
+ description;
7050
+ config;
7051
+ cli;
7052
+ options;
7053
+ aliasNames;
7054
+ name;
7055
+ args;
7056
+ commandAction;
7057
+ usageText;
7058
+ versionNumber;
7059
+ examples;
7060
+ helpCallback;
7061
+ globalCommand;
7030
7062
  constructor(rawName, description, config = {}, cli) {
7031
7063
  this.rawName = rawName;
7032
7064
  this.description = description;
@@ -7089,22 +7121,13 @@ class Command {
7089
7121
  }
7090
7122
  outputHelp() {
7091
7123
  const { name, commands } = this.cli;
7092
- const {
7093
- versionNumber,
7094
- options: globalOptions,
7095
- helpCallback
7096
- } = this.cli.globalCommand;
7097
- let sections = [
7098
- {
7099
- body: `${name}${versionNumber ? `/${versionNumber}` : ""}`
7100
- }
7101
- ];
7124
+ const { versionNumber, options: globalOptions, helpCallback } = this.cli.globalCommand;
7125
+ let sections = [{ body: `${name}${versionNumber ? `/${versionNumber}` : ""}` }];
7102
7126
  sections.push({
7103
7127
  title: "Usage",
7104
7128
  body: ` $ ${name} ${this.usageText || this.rawName}`
7105
7129
  });
7106
- const showCommands = (this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0;
7107
- if (showCommands) {
7130
+ if ((this.isGlobalCommand || this.isDefaultCommand) && commands.length > 0) {
7108
7131
  const longestCommandName = findLongest(commands.map((command) => command.rawName));
7109
7132
  sections.push({
7110
7133
  title: "Commands",
@@ -7112,17 +7135,15 @@ class Command {
7112
7135
  return ` ${padRight(command.rawName, longestCommandName.length)} ${command.description}`;
7113
7136
  }).join(`
7114
7137
  `)
7115
- });
7116
- sections.push({
7138
+ }, {
7117
7139
  title: `For more info, run any command with the \`--help\` flag`,
7118
7140
  body: commands.map((command) => ` $ ${name}${command.name === "" ? "" : ` ${command.name}`} --help`).join(`
7119
7141
  `)
7120
7142
  });
7121
7143
  }
7122
7144
  let options = this.isGlobalCommand ? globalOptions : [...this.options, ...globalOptions || []];
7123
- if (!this.isGlobalCommand && !this.isDefaultCommand) {
7145
+ if (!this.isGlobalCommand && !this.isDefaultCommand)
7124
7146
  options = options.filter((option) => option.name !== "version");
7125
- }
7126
7147
  if (options.length > 0) {
7127
7148
  const longestOptionName = findLongest(options.map((option) => option.rawName));
7128
7149
  sections.push({
@@ -7133,22 +7154,19 @@ class Command {
7133
7154
  `)
7134
7155
  });
7135
7156
  }
7136
- if (this.examples.length > 0) {
7157
+ if (this.examples.length > 0)
7137
7158
  sections.push({
7138
7159
  title: "Examples",
7139
7160
  body: this.examples.map((example) => {
7140
- if (typeof example === "function") {
7161
+ if (typeof example === "function")
7141
7162
  return example(name);
7142
- }
7143
7163
  return example;
7144
7164
  }).join(`
7145
7165
  `)
7146
7166
  });
7147
- }
7148
- if (helpCallback) {
7167
+ if (helpCallback)
7149
7168
  sections = helpCallback(sections) || sections;
7150
- }
7151
- console.log(sections.map((section) => {
7169
+ console.info(sections.map((section) => {
7152
7170
  return section.title ? `${section.title}:
7153
7171
  ${section.body}` : section.body;
7154
7172
  }).join(`
@@ -7158,24 +7176,20 @@ ${section.body}` : section.body;
7158
7176
  outputVersion() {
7159
7177
  const { name } = this.cli;
7160
7178
  const { versionNumber } = this.cli.globalCommand;
7161
- if (versionNumber) {
7162
- console.log(`${name}/${versionNumber} ${platformInfo}`);
7163
- }
7179
+ if (versionNumber)
7180
+ console.info(`${name}/${versionNumber} ${runtimeInfo}`);
7164
7181
  }
7165
7182
  checkRequiredArgs() {
7166
7183
  const minimalArgsCount = this.args.filter((arg) => arg.required).length;
7167
- if (this.cli.args.length < minimalArgsCount) {
7184
+ if (this.cli.args.length < minimalArgsCount)
7168
7185
  throw new CACError(`missing required args for command \`${this.rawName}\``);
7169
- }
7170
7186
  }
7171
7187
  checkUnknownOptions() {
7172
7188
  const { options, globalCommand } = this.cli;
7173
7189
  if (!this.config.allowUnknownOptions) {
7174
- for (const name of Object.keys(options)) {
7175
- if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name)) {
7190
+ for (const name of Object.keys(options))
7191
+ if (name !== "--" && !this.hasOption(name) && !globalCommand.hasOption(name))
7176
7192
  throw new CACError(`Unknown option \`${name.length > 1 ? `--${name}` : `-${name}`}\``);
7177
- }
7178
- }
7179
7193
  }
7180
7194
  }
7181
7195
  checkOptionValue() {
@@ -7185,22 +7199,33 @@ ${section.body}` : section.body;
7185
7199
  const value = parsedOptions[option.name.split(".")[0]];
7186
7200
  if (option.required) {
7187
7201
  const hasNegated = options.some((o) => o.negated && o.names.includes(option.name));
7188
- if (value === true || value === false && !hasNegated) {
7202
+ if (value === true || value === false && !hasNegated)
7189
7203
  throw new CACError(`option \`${option.rawName}\` value is missing`);
7190
- }
7191
7204
  }
7192
7205
  }
7193
7206
  }
7194
- }
7195
-
7196
- class GlobalCommand extends Command {
7207
+ checkUnusedArgs() {
7208
+ const maximumArgsCount = this.args.some((arg) => arg.variadic) ? Infinity : this.args.length;
7209
+ if (maximumArgsCount < this.cli.args.length)
7210
+ throw new CACError(`Unused args: ${this.cli.args.slice(maximumArgsCount).map((arg) => `\`${arg}\``).join(", ")}`);
7211
+ }
7212
+ };
7213
+ var GlobalCommand = class extends Command {
7197
7214
  constructor(cli) {
7198
7215
  super("@@global@@", "", {}, cli);
7199
7216
  }
7200
- }
7201
- var __assign = Object.assign;
7202
-
7203
- class CAC extends EventEmitter {
7217
+ };
7218
+ var CAC = class extends EventTarget {
7219
+ name;
7220
+ commands;
7221
+ globalCommand;
7222
+ matchedCommand;
7223
+ matchedCommandName;
7224
+ rawArgs;
7225
+ args;
7226
+ options;
7227
+ showHelpOnExit;
7228
+ showVersionOnExit;
7204
7229
  constructor(name = "") {
7205
7230
  super();
7206
7231
  this.name = name;
@@ -7241,11 +7266,10 @@ class CAC extends EventEmitter {
7241
7266
  return this;
7242
7267
  }
7243
7268
  outputHelp() {
7244
- if (this.matchedCommand) {
7269
+ if (this.matchedCommand)
7245
7270
  this.matchedCommand.outputHelp();
7246
- } else {
7271
+ else
7247
7272
  this.globalCommand.outputHelp();
7248
- }
7249
7273
  }
7250
7274
  outputVersion() {
7251
7275
  this.globalCommand.outputVersion();
@@ -7253,47 +7277,47 @@ class CAC extends EventEmitter {
7253
7277
  setParsedInfo({ args, options }, matchedCommand, matchedCommandName) {
7254
7278
  this.args = args;
7255
7279
  this.options = options;
7256
- if (matchedCommand) {
7280
+ if (matchedCommand)
7257
7281
  this.matchedCommand = matchedCommand;
7258
- }
7259
- if (matchedCommandName) {
7282
+ if (matchedCommandName)
7260
7283
  this.matchedCommandName = matchedCommandName;
7261
- }
7262
7284
  return this;
7263
7285
  }
7264
7286
  unsetMatchedCommand() {
7265
7287
  this.matchedCommand = undefined;
7266
7288
  this.matchedCommandName = undefined;
7267
7289
  }
7268
- parse(argv = processArgs, {
7269
- run = true
7270
- } = {}) {
7290
+ parse(argv, { run = true } = {}) {
7291
+ if (!argv) {
7292
+ if (!runtimeProcessArgs)
7293
+ throw new Error("No argv provided and runtime process argv is not available.");
7294
+ argv = runtimeProcessArgs;
7295
+ }
7271
7296
  this.rawArgs = argv;
7272
- if (!this.name) {
7297
+ if (!this.name)
7273
7298
  this.name = argv[1] ? getFileName(argv[1]) : "cli";
7274
- }
7275
7299
  let shouldParse = true;
7276
7300
  for (const command of this.commands) {
7277
7301
  const parsed = this.mri(argv.slice(2), command);
7278
7302
  const commandName = parsed.args[0];
7279
7303
  if (command.isMatched(commandName)) {
7280
7304
  shouldParse = false;
7281
- const parsedInfo = __assign(__assign({}, parsed), {
7305
+ const parsedInfo = {
7306
+ ...parsed,
7282
7307
  args: parsed.args.slice(1)
7283
- });
7308
+ };
7284
7309
  this.setParsedInfo(parsedInfo, command, commandName);
7285
- this.emit(`command:${commandName}`, command);
7310
+ this.dispatchEvent(new CustomEvent(`command:${commandName}`, { detail: command }));
7286
7311
  }
7287
7312
  }
7288
7313
  if (shouldParse) {
7289
- for (const command of this.commands) {
7290
- if (command.name === "") {
7314
+ for (const command of this.commands)
7315
+ if (command.isDefaultCommand) {
7291
7316
  shouldParse = false;
7292
7317
  const parsed = this.mri(argv.slice(2), command);
7293
7318
  this.setParsedInfo(parsed, command);
7294
- this.emit(`command:!`, command);
7319
+ this.dispatchEvent(new CustomEvent("command:!", { detail: command }));
7295
7320
  }
7296
- }
7297
7321
  }
7298
7322
  if (shouldParse) {
7299
7323
  const parsed = this.mri(argv.slice(2));
@@ -7309,60 +7333,51 @@ class CAC extends EventEmitter {
7309
7333
  run = false;
7310
7334
  this.unsetMatchedCommand();
7311
7335
  }
7312
- const parsedArgv = { args: this.args, options: this.options };
7313
- if (run) {
7336
+ const parsedArgv = {
7337
+ args: this.args,
7338
+ options: this.options
7339
+ };
7340
+ if (run)
7314
7341
  this.runMatchedCommand();
7315
- }
7316
- if (!this.matchedCommand && this.args[0]) {
7317
- this.emit("command:*");
7318
- }
7342
+ if (!this.matchedCommand && this.args[0])
7343
+ this.dispatchEvent(new CustomEvent("command:*", { detail: this.args[0] }));
7319
7344
  return parsedArgv;
7320
7345
  }
7321
7346
  mri(argv, command) {
7322
- const cliOptions = [
7323
- ...this.globalCommand.options,
7324
- ...command ? command.options : []
7325
- ];
7347
+ const cliOptions = [...this.globalCommand.options, ...command ? command.options : []];
7326
7348
  const mriOptions = getMriOptions(cliOptions);
7327
7349
  let argsAfterDoubleDashes = [];
7328
7350
  const doubleDashesIndex = argv.indexOf("--");
7329
- if (doubleDashesIndex > -1) {
7351
+ if (doubleDashesIndex !== -1) {
7330
7352
  argsAfterDoubleDashes = argv.slice(doubleDashesIndex + 1);
7331
7353
  argv = argv.slice(0, doubleDashesIndex);
7332
7354
  }
7333
- let parsed = mri2(argv, mriOptions);
7355
+ let parsed = lib_default(argv, mriOptions);
7334
7356
  parsed = Object.keys(parsed).reduce((res, name) => {
7335
- return __assign(__assign({}, res), {
7357
+ return {
7358
+ ...res,
7336
7359
  [camelcaseOptionName(name)]: parsed[name]
7337
- });
7360
+ };
7338
7361
  }, { _: [] });
7339
7362
  const args = parsed._;
7340
- const options = {
7341
- "--": argsAfterDoubleDashes
7342
- };
7363
+ const options = { "--": argsAfterDoubleDashes };
7343
7364
  const ignoreDefault = command && command.config.ignoreOptionDefaultValue ? command.config.ignoreOptionDefaultValue : this.globalCommand.config.ignoreOptionDefaultValue;
7344
- let transforms = Object.create(null);
7365
+ const transforms = Object.create(null);
7345
7366
  for (const cliOption of cliOptions) {
7346
- if (!ignoreDefault && cliOption.config.default !== undefined) {
7347
- for (const name of cliOption.names) {
7367
+ if (!ignoreDefault && cliOption.config.default !== undefined)
7368
+ for (const name of cliOption.names)
7348
7369
  options[name] = cliOption.config.default;
7349
- }
7350
- }
7351
- if (Array.isArray(cliOption.config.type)) {
7352
- if (transforms[cliOption.name] === undefined) {
7353
- transforms[cliOption.name] = Object.create(null);
7354
- transforms[cliOption.name]["shouldTransform"] = true;
7355
- transforms[cliOption.name]["transformFunction"] = cliOption.config.type[0];
7356
- }
7370
+ if (Array.isArray(cliOption.config.type) && transforms[cliOption.name] === undefined) {
7371
+ transforms[cliOption.name] = Object.create(null);
7372
+ transforms[cliOption.name].shouldTransform = true;
7373
+ transforms[cliOption.name].transformFunction = cliOption.config.type[0];
7357
7374
  }
7358
7375
  }
7359
- for (const key of Object.keys(parsed)) {
7376
+ for (const key of Object.keys(parsed))
7360
7377
  if (key !== "_") {
7361
- const keys = key.split(".");
7362
- setDotProp(options, keys, parsed[key]);
7378
+ setDotProp(options, key.split("."), parsed[key]);
7363
7379
  setByType(options, transforms);
7364
7380
  }
7365
- }
7366
7381
  return {
7367
7382
  args,
7368
7383
  options
@@ -7375,27 +7390,26 @@ class CAC extends EventEmitter {
7375
7390
  command.checkUnknownOptions();
7376
7391
  command.checkOptionValue();
7377
7392
  command.checkRequiredArgs();
7393
+ command.checkUnusedArgs();
7378
7394
  const actionArgs = [];
7379
7395
  command.args.forEach((arg, index) => {
7380
- if (arg.variadic) {
7396
+ if (arg.variadic)
7381
7397
  actionArgs.push(args.slice(index));
7382
- } else {
7398
+ else
7383
7399
  actionArgs.push(args[index]);
7384
- }
7385
7400
  });
7386
7401
  actionArgs.push(options);
7387
7402
  return command.commandAction.apply(this, actionArgs);
7388
7403
  }
7389
- }
7404
+ };
7390
7405
  var cac = (name = "") => new CAC(name);
7391
- var dist_default = cac;
7392
7406
 
7393
7407
  // src/index.ts
7394
7408
  var import_picocolors2 = __toESM(require_picocolors(), 1);
7395
7409
  import { resolve } from "path";
7396
7410
 
7397
7411
  // src/fetcher.ts
7398
- var import_semver2 = __toESM(require_semver2(), 1);
7412
+ var import_semver3 = __toESM(require_semver2(), 1);
7399
7413
 
7400
7414
  // src/types.ts
7401
7415
  var STABILITY_ORDER = {
@@ -7546,7 +7560,8 @@ function formatNewVersion(originalConstraint, newVersion) {
7546
7560
  return `${startPart} - ${cleaned}`;
7547
7561
  }
7548
7562
  if (parsed.type === "range") {
7549
- return `^${cleaned}`;
7563
+ const updatedConstraint = originalConstraint.replace(/([><!=]+\s*)v?\d+(?:\.\d+)*(?:-[\w.]+)?/i, `$1${cleaned}`);
7564
+ return updatedConstraint || originalConstraint;
7550
7565
  }
7551
7566
  return `${parsed.prefix}${cleaned}`;
7552
7567
  }
@@ -7570,23 +7585,29 @@ function getCacheDir() {
7570
7585
  }
7571
7586
  return path.join(process.env.XDG_CACHE_HOME || path.join(home, ".cache"), "comze");
7572
7587
  }
7573
- async function getCacheEntry(key) {
7588
+ function getCacheFilePath(key) {
7589
+ return path.join(getCacheDir(), `${key}.json`);
7590
+ }
7591
+ async function getCacheEntry(key, expectedVersion) {
7574
7592
  try {
7575
- const cacheDir = getCacheDir();
7576
- const filePath = path.join(cacheDir, `${key}.json`);
7593
+ const filePath = getCacheFilePath(key);
7577
7594
  const content = await fs.readFile(filePath, "utf-8");
7578
7595
  const data = JSON.parse(content);
7596
+ if (data.version !== expectedVersion) {
7597
+ return null;
7598
+ }
7579
7599
  return data;
7580
7600
  } catch {
7581
7601
  return null;
7582
7602
  }
7583
7603
  }
7584
- async function setCache(key, value, meta = {}) {
7604
+ async function setCache(key, value, version, meta = {}) {
7585
7605
  try {
7586
7606
  const cacheDir = getCacheDir();
7587
7607
  await fs.mkdir(cacheDir, { recursive: true });
7588
- const filePath = path.join(cacheDir, `${key}.json`);
7608
+ const filePath = getCacheFilePath(key);
7589
7609
  const data = {
7610
+ version,
7590
7611
  timestamp: Date.now(),
7591
7612
  value,
7592
7613
  lastModified: meta.lastModified,
@@ -7595,37 +7616,133 @@ async function setCache(key, value, meta = {}) {
7595
7616
  await fs.writeFile(filePath, JSON.stringify(data), "utf-8");
7596
7617
  } catch {}
7597
7618
  }
7598
- async function touchCache(key) {
7619
+ async function touchCache(key, version) {
7599
7620
  try {
7600
- const entry = await getCacheEntry(key);
7621
+ const entry = await getCacheEntry(key, version);
7601
7622
  if (entry) {
7602
- await setCache(key, entry.value, { lastModified: entry.lastModified, etag: entry.etag });
7623
+ const now = new Date;
7624
+ await fs.utimes(getCacheFilePath(key), now, now);
7603
7625
  }
7604
7626
  } catch {}
7605
7627
  }
7606
7628
 
7629
+ // src/utils/php.ts
7630
+ var import_semver2 = __toESM(require_semver2(), 1);
7631
+ function normalizeComposerConstraint(constraint) {
7632
+ if (!constraint)
7633
+ return "*";
7634
+ let normalized = constraint.trim();
7635
+ normalized = normalized.replace(/\|\|/g, "<<<OR>>>");
7636
+ normalized = normalized.replace(/\|/g, "<<<OR>>>");
7637
+ normalized = normalized.replace(/<<<OR>>>/g, " || ");
7638
+ normalized = normalized.replace(/\s*\|\|\s*/g, " || ");
7639
+ normalized = normalized.replace(/,\s*/g, " ");
7640
+ normalized = normalized.replace(/@(dev|alpha|beta|rc|stable)/gi, "");
7641
+ if (normalized === "*" || normalized.startsWith("ext-")) {
7642
+ return "*";
7643
+ }
7644
+ return normalized;
7645
+ }
7646
+ function extractMinVersion(constraint) {
7647
+ const normalized = normalizeComposerConstraint(constraint);
7648
+ if (normalized === "*")
7649
+ return null;
7650
+ const orParts = normalized.split(/\s*\|\|\s*/);
7651
+ let minVersion = null;
7652
+ for (const part of orParts) {
7653
+ const coerced = import_semver2.default.coerce(part.trim());
7654
+ if (coerced) {
7655
+ if (!minVersion || import_semver2.default.lt(coerced.version, minVersion)) {
7656
+ minVersion = coerced.version;
7657
+ }
7658
+ }
7659
+ }
7660
+ return minVersion;
7661
+ }
7662
+ function extractMaxVersion(constraint) {
7663
+ const normalized = normalizeComposerConstraint(constraint);
7664
+ if (normalized === "*")
7665
+ return null;
7666
+ const upperBoundMatch = normalized.match(/<(=?)\s*(\d+(?:\.\d+)*)/);
7667
+ if (upperBoundMatch) {
7668
+ const coerced = import_semver2.default.coerce(upperBoundMatch[2]);
7669
+ return coerced ? coerced.version : null;
7670
+ }
7671
+ const caretMatch = normalized.match(/\^(\d+)(?:\.(\d+))?(?:\.(\d+))?/);
7672
+ if (caretMatch) {
7673
+ const major = parseInt(caretMatch[1], 10);
7674
+ return `${major + 1}.0.0`;
7675
+ }
7676
+ return null;
7677
+ }
7678
+ function checkPhpCompatibility(projectPhp, packagePhp) {
7679
+ if (!packagePhp || packagePhp === "*")
7680
+ return { satisfied: true };
7681
+ if (!projectPhp)
7682
+ return { satisfied: true };
7683
+ const projectMin = extractMinVersion(projectPhp);
7684
+ if (!projectMin)
7685
+ return { satisfied: true };
7686
+ const packageNorm = normalizeComposerConstraint(packagePhp);
7687
+ const packageParts = packageNorm.split(/\s*\|\|\s*/).filter((p) => p.trim());
7688
+ for (const part of packageParts) {
7689
+ const partMax = extractMaxVersion(part);
7690
+ if (partMax && import_semver2.default.gte(projectMin, partMax))
7691
+ continue;
7692
+ try {
7693
+ const range = import_semver2.default.validRange(part.trim());
7694
+ if (range && import_semver2.default.satisfies(projectMin, range))
7695
+ return { satisfied: true };
7696
+ } catch {}
7697
+ const partMin = extractMinVersion(part);
7698
+ if (partMin) {
7699
+ const partMajor = import_semver2.default.major(partMin);
7700
+ const projectMajor = import_semver2.default.major(projectMin);
7701
+ if (part.trim().startsWith("^")) {
7702
+ if (projectMajor === partMajor && import_semver2.default.gte(projectMin, partMin)) {
7703
+ return { satisfied: true };
7704
+ }
7705
+ } else if (import_semver2.default.gte(projectMin, partMin) && !partMax) {
7706
+ return { satisfied: true };
7707
+ }
7708
+ }
7709
+ }
7710
+ return { satisfied: false, reason: `requires php ${packagePhp}` };
7711
+ }
7712
+
7607
7713
  // src/fetcher.ts
7608
7714
  var PACKAGIST_API = "https://repo.packagist.org/p2";
7609
- async function fetchPackage(packageName, minStability = "stable", preferStable = true, currentVersion, allowMajor = true, noCache = false) {
7715
+ var CACHE_VERSION = 1;
7716
+ async function fetchPackage(packageName, minStability = "stable", preferStable = true, currentVersion, allowMajor = true, noCache = false, projectPhp) {
7610
7717
  const cacheKey = packageName.replace("/", "_");
7611
7718
  let cachedEntry = null;
7612
7719
  const headers = {};
7613
7720
  if (!noCache) {
7614
- cachedEntry = await getCacheEntry(cacheKey);
7721
+ cachedEntry = await getCacheEntry(cacheKey, CACHE_VERSION);
7615
7722
  if (cachedEntry?.lastModified) {
7616
7723
  headers["If-Modified-Since"] = cachedEntry.lastModified;
7617
7724
  }
7725
+ if (cachedEntry?.etag) {
7726
+ headers["If-None-Match"] = cachedEntry.etag;
7727
+ }
7618
7728
  }
7729
+ let data;
7619
7730
  try {
7620
7731
  const url = `${PACKAGIST_API}/${packageName}.json`;
7621
7732
  const response = await fetch(url, { headers });
7622
7733
  if (response.status === 304 && cachedEntry) {
7623
- await touchCache(cacheKey);
7624
- return cachedEntry.value;
7625
- }
7626
- if (!response.ok)
7734
+ await touchCache(cacheKey, CACHE_VERSION);
7735
+ data = cachedEntry.value;
7736
+ } else if (response.ok) {
7737
+ data = await response.json();
7738
+ if (!noCache) {
7739
+ const lastModified = response.headers.get("Last-Modified") || undefined;
7740
+ const etag = response.headers.get("ETag") || undefined;
7741
+ await setCache(cacheKey, data, CACHE_VERSION, { lastModified, etag });
7742
+ }
7743
+ } else {
7627
7744
  return null;
7628
- const data = await response.json();
7745
+ }
7629
7746
  const versions = data.packages?.[packageName] ?? [];
7630
7747
  if (versions.length === 0)
7631
7748
  return null;
@@ -7653,21 +7770,39 @@ async function fetchPackage(packageName, minStability = "stable", preferStable =
7653
7770
  }
7654
7771
  if (!selectedVersion)
7655
7772
  return null;
7773
+ let phpIncompatible = false;
7774
+ let skippedVersion;
7775
+ if (projectPhp && selectedVersion.require?.php) {
7776
+ const phpCheck = checkPhpCompatibility(projectPhp, selectedVersion.require.php);
7777
+ if (!phpCheck.satisfied) {
7778
+ phpIncompatible = true;
7779
+ skippedVersion = selectedVersion.version;
7780
+ const versionsToCheck = preferStable ? eligibleVersions.filter((v) => getVersionStability(v.version) === "stable") : eligibleVersions;
7781
+ const compatibleVersion = versionsToCheck.find((v) => {
7782
+ if (!v.require?.php)
7783
+ return true;
7784
+ return checkPhpCompatibility(projectPhp, v.require.php).satisfied;
7785
+ });
7786
+ if (compatibleVersion && compatibleVersion !== selectedVersion) {
7787
+ selectedVersion = compatibleVersion;
7788
+ }
7789
+ }
7790
+ }
7656
7791
  const phpRequirement = selectedVersion.require?.php;
7657
7792
  let majorDetected;
7658
7793
  if (currentVersion) {
7659
7794
  const currentNorm = normalizeVersion(currentVersion);
7660
7795
  const selectedNorm = normalizeVersion(selectedVersion.version);
7661
7796
  if (currentNorm && selectedNorm) {
7662
- const currentMajor = import_semver2.default.major(currentNorm);
7663
- const selectedMajor = import_semver2.default.major(selectedNorm);
7797
+ const currentMajor = import_semver3.default.major(currentNorm);
7798
+ const selectedMajor = import_semver3.default.major(selectedNorm);
7664
7799
  if (selectedMajor > currentMajor) {
7665
7800
  majorDetected = selectedVersion.version;
7666
7801
  if (!allowMajor) {
7667
7802
  const versionsToCheck = preferStable ? eligibleVersions.filter((v) => getVersionStability(v.version) === "stable") : eligibleVersions;
7668
7803
  const sameMajorVersion = versionsToCheck.find((v) => {
7669
7804
  const norm = normalizeVersion(v.version);
7670
- return norm && import_semver2.default.major(norm) === currentMajor;
7805
+ return norm && import_semver3.default.major(norm) === currentMajor;
7671
7806
  });
7672
7807
  if (sameMajorVersion) {
7673
7808
  selectedVersion = sameMajorVersion;
@@ -7689,25 +7824,24 @@ async function fetchPackage(packageName, minStability = "stable", preferStable =
7689
7824
  phpRequirement: selectedVersion.require?.php ?? phpRequirement,
7690
7825
  majorVersion: majorDetected,
7691
7826
  deprecated: deprecatedInfo.deprecated,
7692
- replacement: deprecatedInfo.replacement
7827
+ replacement: deprecatedInfo.replacement,
7828
+ phpIncompatible: phpIncompatible || undefined,
7829
+ skippedVersion,
7830
+ require: selectedVersion.require
7693
7831
  };
7694
- if (!noCache) {
7695
- const lastModified = response.headers.get("Last-Modified") || undefined;
7696
- await setCache(cacheKey, result, { lastModified });
7697
- }
7698
7832
  return result;
7699
7833
  } catch {
7700
7834
  return null;
7701
7835
  }
7702
7836
  }
7703
- async function fetchAllPackages(packages, minStability = "stable", preferStable = true, allowMajor = true, noCache = false) {
7837
+ async function fetchAllPackages(packages, minStability = "stable", preferStable = true, allowMajor = true, noCache = false, projectPhp) {
7704
7838
  const results = new Map;
7705
7839
  const entries = Object.entries(packages);
7706
7840
  const CONCURRENCY = 5;
7707
7841
  for (let i = 0;i < entries.length; i += CONCURRENCY) {
7708
7842
  const batch = entries.slice(i, i + CONCURRENCY);
7709
7843
  const promises = batch.map(async ([name, version]) => {
7710
- const result = await fetchPackage(name, minStability, preferStable, version, allowMajor, noCache);
7844
+ const result = await fetchPackage(name, minStability, preferStable, version, allowMajor, noCache, projectPhp);
7711
7845
  if (result)
7712
7846
  results.set(name, result);
7713
7847
  });
@@ -7717,9 +7851,10 @@ async function fetchAllPackages(packages, minStability = "stable", preferStable
7717
7851
  }
7718
7852
 
7719
7853
  // src/writer.ts
7720
- import { readFile, writeFile } from "fs/promises";
7854
+ import { readFile, rename, rm, writeFile } from "fs/promises";
7721
7855
  import { existsSync } from "fs";
7722
7856
  import { spawn } from "child_process";
7857
+ import { basename, dirname, join } from "path";
7723
7858
 
7724
7859
  // node_modules/detect-indent/index.js
7725
7860
  var INDENT_REGEX = /^(?:( )+|\t+)/;
@@ -7859,12 +7994,17 @@ async function writeComposerJson(path2, updates, dryRun = false) {
7859
7994
  console.log("");
7860
7995
  return true;
7861
7996
  }
7997
+ const tempPath = join(dirname(path2), `.${basename(path2)}.${process.pid}.${Date.now()}.tmp`);
7862
7998
  try {
7863
7999
  const newContent = JSON.stringify(content, null, indent) + `
7864
8000
  `;
7865
- await writeFile(path2, newContent, "utf-8");
8001
+ await writeFile(tempPath, newContent, "utf-8");
8002
+ await rename(tempPath, path2);
7866
8003
  return true;
7867
8004
  } catch {
8005
+ try {
8006
+ await rm(tempPath, { force: true });
8007
+ } catch {}
7868
8008
  return false;
7869
8009
  }
7870
8010
  }
@@ -7964,6 +8104,9 @@ function renderTable(packages) {
7964
8104
  if (pkg.phpRequirement) {
7965
8105
  extra += import_picocolors.default.gray(` php ${pkg.phpRequirement}`);
7966
8106
  }
8107
+ if (pkg.phpIncompatible && pkg.skippedVersion) {
8108
+ extra += import_picocolors.default.yellow(` ${pkg.skippedVersion} skipped (php)`);
8109
+ }
7967
8110
  if (pkg.deprecated) {
7968
8111
  extra += import_picocolors.default.red(" deprecated");
7969
8112
  if (pkg.replacement) {
@@ -7972,6 +8115,15 @@ function renderTable(packages) {
7972
8115
  }
7973
8116
  console.log(` ${name} ${oldVer} ${arrow} ${coloredNewVer} ${diffLabel} ${age}${extra}`);
7974
8117
  }
8118
+ const skippedPackages = packages.filter((p) => p.phpIncompatible && p.skippedVersion);
8119
+ if (skippedPackages.length > 0) {
8120
+ console.log(import_picocolors.default.yellow(`
8121
+ Some versions skipped due to PHP constraints:`));
8122
+ for (const pkg of skippedPackages) {
8123
+ console.log(` ${import_picocolors.default.bold(pkg.name)} ${pkg.skippedVersion} requires higher PHP version`);
8124
+ }
8125
+ console.log(import_picocolors.default.gray(" Update the php constraint in composer.json to use these versions."));
8126
+ }
7975
8127
  console.log("");
7976
8128
  }
7977
8129
  function renderHeader(version) {
@@ -8012,6 +8164,9 @@ function formatPackageChoice(pkg) {
8012
8164
  if (pkg.phpRequirement) {
8013
8165
  extra += import_picocolors.default.gray(` php ${pkg.phpRequirement}`);
8014
8166
  }
8167
+ if (pkg.phpIncompatible && pkg.skippedVersion) {
8168
+ extra += import_picocolors.default.yellow(` ${pkg.skippedVersion} skipped`);
8169
+ }
8015
8170
  if (pkg.deprecated) {
8016
8171
  extra += import_picocolors.default.red(" deprecated");
8017
8172
  if (pkg.replacement) {
@@ -8054,10 +8209,40 @@ async function selectPackages(packages) {
8054
8209
  const selectedNames = new Set(response.selected);
8055
8210
  return packages.filter((pkg) => selectedNames.has(pkg.name));
8056
8211
  }
8212
+
8213
+ // src/config.ts
8214
+ function normalizeExcludeList(excludes) {
8215
+ return [...new Set(excludes.map((value) => value.trim().toLowerCase()).filter(Boolean))];
8216
+ }
8217
+ function getComposerExcludeList(composer) {
8218
+ const excludes = composer.extra?.comze?.exclude;
8219
+ if (!Array.isArray(excludes))
8220
+ return [];
8221
+ const validExcludes = excludes.filter((value) => typeof value === "string");
8222
+ return normalizeExcludeList(validExcludes);
8223
+ }
8224
+ function mergeExcludeLists(fileExcludes, cliExcludes) {
8225
+ return normalizeExcludeList([...fileExcludes, ...cliExcludes]);
8226
+ }
8227
+ function filterComposerPackages(allPackages, excludes) {
8228
+ const excludeSet = new Set(normalizeExcludeList(excludes));
8229
+ const filteredPackages = {};
8230
+ const ignoredPackages = [];
8231
+ for (const [name, version] of Object.entries(allPackages)) {
8232
+ if (name === "php" || name.startsWith("ext-"))
8233
+ continue;
8234
+ if (excludeSet.has(name.toLowerCase())) {
8235
+ ignoredPackages.push(name);
8236
+ continue;
8237
+ }
8238
+ filteredPackages[name] = version;
8239
+ }
8240
+ return { filteredPackages, ignoredPackages };
8241
+ }
8057
8242
  // package.json
8058
8243
  var package_default = {
8059
8244
  name: "comze",
8060
- version: "0.3.1",
8245
+ version: "0.4.0",
8061
8246
  description: "A taze-like CLI for updating composer.json dependencies",
8062
8247
  author: "qoqn",
8063
8248
  license: "MIT",
@@ -8096,14 +8281,14 @@ var package_default = {
8096
8281
  "@types/bun": "latest",
8097
8282
  "@types/prompts": "^2.4.9",
8098
8283
  "@types/semver": "^7.7.1",
8099
- typescript: "^5"
8284
+ typescript: "^6.0.2"
8100
8285
  },
8101
8286
  dependencies: {
8102
- cac: "^6.7.14",
8287
+ cac: "^7.0.0",
8103
8288
  "detect-indent": "^7.0.2",
8104
8289
  picocolors: "^1.1.1",
8105
8290
  prompts: "^2.4.2",
8106
- semver: "^7.7.3"
8291
+ semver: "^7.7.4"
8107
8292
  }
8108
8293
  };
8109
8294
 
@@ -8117,23 +8302,22 @@ async function run(options) {
8117
8302
  process.exit(1);
8118
8303
  }
8119
8304
  const minStability = composer.content["minimum-stability"] ?? "stable";
8120
- const preferStable = composer.content["prefer-stable"] ?? true;
8305
+ const preferStable = composer.content["prefer-stable"] === true;
8121
8306
  const allPackages = {
8122
8307
  ...composer.content.require,
8123
8308
  ...composer.content["require-dev"]
8124
8309
  };
8125
- const filteredPackages = {};
8126
- for (const [name, version] of Object.entries(allPackages)) {
8127
- if (name === "php" || name.startsWith("ext-"))
8128
- continue;
8129
- if (options.exclude.includes(name))
8130
- continue;
8131
- filteredPackages[name] = version;
8132
- }
8310
+ const fileExcludes = getComposerExcludeList(composer.content);
8311
+ const excludes = mergeExcludeLists(fileExcludes, options.exclude);
8312
+ const { filteredPackages, ignoredPackages } = filterComposerPackages(allPackages, excludes);
8133
8313
  console.log(import_picocolors2.default.gray(` Checking ${Object.keys(filteredPackages).length} packages...`));
8314
+ if (ignoredPackages.length > 0) {
8315
+ console.log(import_picocolors2.default.gray(` Ignoring ${ignoredPackages.length} package${ignoredPackages.length === 1 ? "" : "s"} from exclude list...`));
8316
+ }
8134
8317
  console.log(import_picocolors2.default.gray(` Stability: ${minStability}${preferStable ? " (prefer-stable)" : ""}
8135
8318
  `));
8136
- const results = await fetchAllPackages(filteredPackages, minStability, preferStable, options.major, options.noCache);
8319
+ const projectPhp = allPackages["php"];
8320
+ const results = await fetchAllPackages(filteredPackages, minStability, preferStable, options.major, options.noCache, projectPhp);
8137
8321
  const updates = [];
8138
8322
  const deprecatedPackages = [];
8139
8323
  for (const [name, currentVersion] of Object.entries(filteredPackages)) {
@@ -8168,7 +8352,9 @@ async function run(options) {
8168
8352
  majorAvailable,
8169
8353
  phpRequirement: result.phpRequirement,
8170
8354
  deprecated: result.deprecated,
8171
- replacement: result.replacement
8355
+ replacement: result.replacement,
8356
+ phpIncompatible: result.phpIncompatible,
8357
+ skippedVersion: result.skippedVersion
8172
8358
  });
8173
8359
  }
8174
8360
  const order = { major: 0, minor: 1, patch: 2 };
@@ -8188,7 +8374,11 @@ async function run(options) {
8188
8374
  }
8189
8375
  if (options.write || options.install) {
8190
8376
  const success = await writeComposerJson(composerPath, selectedUpdates, options.dryRun);
8191
- if (success && !options.dryRun) {
8377
+ if (!success) {
8378
+ console.error(import_picocolors2.default.red(" ✗ Failed to update composer.json"));
8379
+ process.exit(1);
8380
+ }
8381
+ if (!options.dryRun) {
8192
8382
  console.log(import_picocolors2.default.green(" ✓ Updated composer.json"));
8193
8383
  if (options.write && !options.install) {
8194
8384
  console.log(import_picocolors2.default.gray(`
@@ -8220,10 +8410,10 @@ async function run(options) {
8220
8410
  }
8221
8411
 
8222
8412
  // src/cli.ts
8223
- var cli = dist_default("comze");
8413
+ var cli = cac("comze");
8224
8414
  cli.option("-w, --write", "Write changes to composer.json", { default: false }).option("-i, --install", "Write changes and run composer update", {
8225
8415
  default: false
8226
- }).option("-I, --interactive", "Select updates manually", { default: false }).option("--major", "Include major updates", { default: false }).option("--minor", "Include minor updates", { default: true }).option("--patch", "Include patch updates", { default: true }).option("--exclude <packages>", "Exclude packages (comma-separated)", {
8416
+ }).option("-I, --interactive", "Select updates manually", { default: false }).option("--major", "Include major updates", { default: false }).option("--minor", "Include minor updates", { default: true }).option("--patch", "Include patch updates", { default: true }).option("--exclude <packages>", "Exclude packages (comma-separated, merged with composer.json extra.comze.exclude)", {
8227
8417
  default: ""
8228
8418
  }).option("--dry-run", "Run without making changes", { default: false }).option("--no-cache", "Bypass cache and force fetch from network", { default: false });
8229
8419
  cli.help();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "comze",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "A taze-like CLI for updating composer.json dependencies",
5
5
  "author": "qoqn",
6
6
  "license": "MIT",
@@ -39,13 +39,13 @@
39
39
  "@types/bun": "latest",
40
40
  "@types/prompts": "^2.4.9",
41
41
  "@types/semver": "^7.7.1",
42
- "typescript": "^5"
42
+ "typescript": "^6.0.2"
43
43
  },
44
44
  "dependencies": {
45
- "cac": "^6.7.14",
45
+ "cac": "^7.0.0",
46
46
  "detect-indent": "^7.0.2",
47
47
  "picocolors": "^1.1.1",
48
48
  "prompts": "^2.4.2",
49
- "semver": "^7.7.3"
49
+ "semver": "^7.7.4"
50
50
  }
51
51
  }