shop-cli 0.1.2 → 0.1.3

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.
@@ -447,7 +447,7 @@ const runCollections = async ({
447
447
  const pos = Number(item.slice(idx + 1).trim());
448
448
  if (!productId) throw new import_errors.CliError("--move productId cannot be empty", 2);
449
449
  if (!Number.isFinite(pos) || pos < 0) throw new import_errors.CliError("--move newPosition must be a non-negative number", 2);
450
- parsedMoves.push({ id: (0, import_gid.coerceGid)(productId, "Product"), newPosition: Math.floor(pos) });
450
+ parsedMoves.push({ id: (0, import_gid.coerceGid)(productId, "Product"), newPosition: String(Math.floor(pos)) });
451
451
  }
452
452
  moves = parsedMoves;
453
453
  }
@@ -460,7 +460,7 @@ const runCollections = async ({
460
460
  if (typeof mid !== "string" || !mid.trim()) throw new import_errors.CliError(`moves[${i}].id is required`, 2);
461
461
  const pos = Number(newPosition);
462
462
  if (!Number.isFinite(pos) || pos < 0) throw new import_errors.CliError(`moves[${i}].newPosition must be a non-negative number`, 2);
463
- return { id: mid.startsWith("gid://") ? mid : (0, import_gid.coerceGid)(mid, "Product"), newPosition: Math.floor(pos) };
463
+ return { id: mid.startsWith("gid://") ? mid : (0, import_gid.coerceGid)(mid, "Product"), newPosition: String(Math.floor(pos)) };
464
464
  });
465
465
  const result = await (0, import_router.runMutation)(ctx, {
466
466
  collectionReorderProducts: {
@@ -2262,13 +2262,13 @@ Missing <verb> for "products ${verb}"`, 2);
2262
2262
  const raw = args.move;
2263
2263
  const parsedMoves = [];
2264
2264
  for (const item of raw) {
2265
- const parts = item.split(":");
2266
- if (parts.length !== 2) throw new import_errors.CliError("--move must be <mediaId>:<newPosition>", 2);
2267
- const mediaId = parts[0].trim();
2268
- const pos = Number(parts[1].trim());
2265
+ const idx = item.lastIndexOf(":");
2266
+ if (idx <= 0 || idx === item.length - 1) throw new import_errors.CliError("--move must be <mediaId>:<newPosition>", 2);
2267
+ const mediaId = item.slice(0, idx).trim();
2268
+ const pos = Number(item.slice(idx + 1).trim());
2269
2269
  if (!mediaId) throw new import_errors.CliError("--move mediaId cannot be empty", 2);
2270
2270
  if (!Number.isFinite(pos) || pos < 0) throw new import_errors.CliError("--move newPosition must be a non-negative number", 2);
2271
- parsedMoves.push({ id: normalizeMediaId(mediaId), newPosition: Math.floor(pos) });
2271
+ parsedMoves.push({ id: normalizeMediaId(mediaId), newPosition: String(Math.floor(pos)) });
2272
2272
  }
2273
2273
  moves = parsedMoves;
2274
2274
  }
@@ -2285,7 +2285,7 @@ Missing <verb> for "products ${verb}"`, 2);
2285
2285
  if (!Number.isFinite(pos) || pos < 0) {
2286
2286
  throw new import_errors.CliError(`moves[${i}].newPosition must be a non-negative number`, 2);
2287
2287
  }
2288
- return { id: normalizeMediaId(id2), newPosition: Math.floor(pos) };
2288
+ return { id: normalizeMediaId(id2), newPosition: String(Math.floor(pos)) };
2289
2289
  });
2290
2290
  const result = await (0, import_router.runMutation)(ctx, {
2291
2291
  productReorderMedia: {
@@ -60,7 +60,12 @@ const getReverseDeliverySelection = (view) => {
60
60
  return reverseDeliverySummarySelection;
61
61
  };
62
62
  const parseLineItem = (value) => {
63
- const [id, qtyRaw] = value.split(":");
63
+ const idx = value.lastIndexOf(":");
64
+ if (idx <= 0 || idx === value.length - 1) {
65
+ throw new import_errors.CliError("--line-item must be <reverseFulfillmentOrderLineItemId>:<quantity>", 2);
66
+ }
67
+ const id = value.slice(0, idx).trim();
68
+ const qtyRaw = value.slice(idx + 1).trim();
64
69
  if (!id || !qtyRaw) throw new import_errors.CliError("--line-item must be <reverseFulfillmentOrderLineItemId>:<quantity>", 2);
65
70
  const quantity = Number(qtyRaw);
66
71
  if (!Number.isFinite(quantity) || !Number.isInteger(quantity) || quantity <= 0) {
@@ -61,24 +61,49 @@ const getReverseFulfillmentOrderSelection = (view) => {
61
61
  return reverseFulfillmentOrderSummarySelection;
62
62
  };
63
63
  const parseDisposition = (value) => {
64
- const parts = value.split(":");
65
- if (parts.length < 3) {
66
- throw new import_errors.CliError("--disposition must be <reverseFulfillmentOrderLineItemId>:<quantity>:<dispositionType>[:<locationId>]", 2);
64
+ const raw = value.trim();
65
+ const usage = () => new import_errors.CliError("--disposition must be <reverseFulfillmentOrderLineItemId>:<quantity>:<dispositionType>[:<locationId>]", 2);
66
+ const splitOnLastColonOrThrow = (s) => {
67
+ const idx = s.lastIndexOf(":");
68
+ if (idx <= 0 || idx === s.length - 1) throw usage();
69
+ return [s.slice(0, idx), s.slice(idx + 1)];
70
+ };
71
+ const parseCore = (core) => {
72
+ const [rest, dispositionTypeRaw] = splitOnLastColonOrThrow(core);
73
+ const [idRaw, quantityRaw] = splitOnLastColonOrThrow(rest);
74
+ const reverseFulfillmentOrderLineItemId = idRaw.trim();
75
+ const dispositionType = dispositionTypeRaw.trim();
76
+ const quantity = Number(quantityRaw.trim());
77
+ if (!reverseFulfillmentOrderLineItemId || !dispositionType) throw usage();
78
+ if (!Number.isFinite(quantity) || !Number.isInteger(quantity) || quantity <= 0) {
79
+ throw new import_errors.CliError("--disposition quantity must be a positive integer", 2);
80
+ }
81
+ return { reverseFulfillmentOrderLineItemId, quantity, dispositionType };
82
+ };
83
+ let firstErr;
84
+ try {
85
+ return parseCore(raw);
86
+ } catch (err) {
87
+ firstErr = err;
67
88
  }
68
- const reverseFulfillmentOrderLineItemId = parts[0];
69
- const quantityRaw = parts[1];
70
- const dispositionType = parts[2];
71
- const locationId = parts[3];
72
- const quantity = Number(quantityRaw);
73
- if (!Number.isFinite(quantity) || !Number.isInteger(quantity) || quantity <= 0) {
74
- throw new import_errors.CliError("--disposition quantity must be a positive integer", 2);
89
+ const gidIdx = raw.lastIndexOf("gid://");
90
+ if (gidIdx > 0) {
91
+ const before = raw.slice(0, gidIdx);
92
+ const colonIdx = before.lastIndexOf(":");
93
+ if (colonIdx >= 0 && before.slice(colonIdx + 1).trim() === "") {
94
+ const core = raw.slice(0, colonIdx).trim();
95
+ const locationId = raw.slice(gidIdx).trim();
96
+ if (locationId) return { ...parseCore(core), locationId };
97
+ }
98
+ }
99
+ try {
100
+ const [core, locationIdRaw] = splitOnLastColonOrThrow(raw);
101
+ const locationId = locationIdRaw.trim();
102
+ if (!locationId) throw usage();
103
+ return { ...parseCore(core.trim()), locationId };
104
+ } catch {
105
+ throw firstErr;
75
106
  }
76
- return {
77
- reverseFulfillmentOrderLineItemId,
78
- quantity,
79
- dispositionType,
80
- ...locationId ? { locationId } : {}
81
- };
82
107
  };
83
108
  const runReverseFulfillmentOrders = async ({
84
109
  ctx,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shop-cli",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "An agent-friendly command-line interface for managing Shopify stores",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -63,4 +63,4 @@
63
63
  "typescript": "^5.9.3",
64
64
  "vitest": "^4.0.18"
65
65
  }
66
- }
66
+ }