@zapier/zapier-sdk-cli 0.6.4 → 0.6.5

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zapier/zapier-sdk-cli",
3
- "version": "0.6.4",
3
+ "version": "0.6.5",
4
4
  "description": "Command line interface for Zapier SDK",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",
@@ -0,0 +1,93 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
2
+ import chalk from "chalk";
3
+
4
+ // We need to create a test for the formatItemsGeneric function that's defined in cli-generator.ts
5
+ // Since it's not exported, we'll create a simple test that verifies the numbering logic
6
+
7
+ interface TestItem {
8
+ name?: string;
9
+ key?: string;
10
+ id?: string;
11
+ }
12
+
13
+ describe("CLI Generator Pagination Numbering", () => {
14
+ let mockConsoleLog: ReturnType<typeof vi.spyOn>;
15
+
16
+ beforeEach(() => {
17
+ mockConsoleLog = vi.spyOn(console, "log").mockImplementation(() => {});
18
+ });
19
+
20
+ afterEach(() => {
21
+ mockConsoleLog.mockRestore();
22
+ });
23
+
24
+ // Since formatItemsGeneric is not exported, let's create a regression test
25
+ // that tests the key functionality we care about: continuous numbering
26
+ it("should prevent pagination numbering regression by testing chalk formatting", () => {
27
+ // Simulate what formatItemsGeneric does for pagination numbering
28
+ const simulateFormatting = (items: TestItem[], startingNumber: number) => {
29
+ const calls: string[] = [];
30
+ items.forEach((item, index) => {
31
+ const name = item.name || item.key || item.id || "Item";
32
+ const formatted = `${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`;
33
+ calls.push(formatted);
34
+ });
35
+ return calls;
36
+ };
37
+
38
+ // Test first page (items 1-3)
39
+ const page1Items = [
40
+ { name: "App 1", key: "app1" },
41
+ { name: "App 2", key: "app2" },
42
+ { name: "App 3", key: "app3" },
43
+ ];
44
+
45
+ const page2Items = [
46
+ { name: "App 4", key: "app4" },
47
+ { name: "App 5", key: "app5" },
48
+ ];
49
+
50
+ // Format first page starting from 0
51
+ const page1Output = simulateFormatting(page1Items, 0);
52
+
53
+ // Format second page starting from 3 (3 items shown already)
54
+ const page2Output = simulateFormatting(page2Items, 3);
55
+
56
+ // Check that page 1 contains 1., 2., 3.
57
+ expect(page1Output.some((line) => line.includes("1."))).toBe(true);
58
+ expect(page1Output.some((line) => line.includes("2."))).toBe(true);
59
+ expect(page1Output.some((line) => line.includes("3."))).toBe(true);
60
+
61
+ // Check that page 2 contains 4., 5. (continuing from page 1)
62
+ expect(page2Output.some((line) => line.includes("4."))).toBe(true);
63
+ expect(page2Output.some((line) => line.includes("5."))).toBe(true);
64
+
65
+ // Most importantly: page 2 should NOT restart at 1.
66
+ expect(page2Output.some((line) => line.includes("1."))).toBe(false);
67
+ expect(page2Output.some((line) => line.includes("2."))).toBe(false);
68
+ expect(page2Output.some((line) => line.includes("3."))).toBe(false);
69
+ });
70
+
71
+ it("should handle edge case of starting number 0", () => {
72
+ const simulateFormatting = (
73
+ items: TestItem[],
74
+ startingNumber: number = 0,
75
+ ) => {
76
+ const calls: string[] = [];
77
+ items.forEach((item, index) => {
78
+ const name = item.name || item.key || item.id || "Item";
79
+ const formatted = `${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`;
80
+ calls.push(formatted);
81
+ });
82
+ return calls;
83
+ };
84
+
85
+ const items = [{ name: "First Item" }, { name: "Second Item" }];
86
+
87
+ // Default startingNumber should be 0, resulting in 1. and 2.
88
+ const output = simulateFormatting(items, 0);
89
+
90
+ expect(output.some((line) => line.includes("1."))).toBe(true);
91
+ expect(output.some((line) => line.includes("2."))).toBe(true);
92
+ });
93
+ });
@@ -307,12 +307,12 @@ function createCommandConfig(
307
307
  !shouldUseJson &&
308
308
  !hasUserSpecifiedMaxItems
309
309
  ) {
310
- // Get the async iterator directly from the SDK method call
310
+ // Get the async iterable directly from the SDK method call (don't await it! that breaks the next page behavior)
311
311
  const sdkObj = sdk as unknown as Record<
312
312
  string,
313
- (params: unknown) => Promise<unknown>
313
+ (params: unknown) => Promise<unknown> & AsyncIterable<unknown>
314
314
  >;
315
- const sdkIterator = await sdkObj[sdkMethodName](resolvedParams);
315
+ const sdkIterator = sdkObj[sdkMethodName](resolvedParams);
316
316
  await handlePaginatedListWithAsyncIteration(
317
317
  sdkMethodName,
318
318
  sdkIterator,
@@ -577,9 +577,9 @@ async function handlePaginatedListWithAsyncIteration(
577
577
 
578
578
  // Format and display items using schema
579
579
  if (schema) {
580
- formatItemsFromSchema(schema as z.ZodType, items);
580
+ formatItemsFromSchema(schema as z.ZodType, items, totalShown);
581
581
  } else {
582
- formatItemsGeneric(items);
582
+ formatItemsGeneric(items, totalShown);
583
583
  }
584
584
 
585
585
  totalShown += items.length;
@@ -620,9 +620,9 @@ async function handlePaginatedListWithAsyncIteration(
620
620
  }
621
621
 
622
622
  if (schema) {
623
- formatItemsFromSchema(schema as z.ZodType, items);
623
+ formatItemsFromSchema(schema as z.ZodType, items, 0);
624
624
  } else {
625
- formatItemsGeneric(items);
625
+ formatItemsGeneric(items, 0);
626
626
  }
627
627
 
628
628
  console.log(chalk.green(`\n✅ Showing ${items.length} ${itemName}`));
@@ -683,12 +683,17 @@ function formatNonPaginatedResults(
683
683
  }
684
684
  }
685
685
 
686
- function formatItemsGeneric(items: unknown[]): void {
686
+ function formatItemsGeneric(
687
+ items: unknown[],
688
+ startingNumber: number = 0,
689
+ ): void {
687
690
  // Fallback formatting for items without schema metadata
688
691
  items.forEach((item, index) => {
689
692
  const itemObj = item as Record<string, unknown>;
690
693
  const name = itemObj?.name || itemObj?.key || itemObj?.id || "Item";
691
- console.log(`${chalk.gray(`${index + 1}.`)} ${chalk.cyan(String(name))}`);
694
+ console.log(
695
+ `${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(String(name))}`,
696
+ );
692
697
  if (itemObj?.description) {
693
698
  console.log(` ${chalk.dim(String(itemObj.description))}`);
694
699
  }
@@ -32,38 +32,39 @@ function getOutputSchema(schema: unknown): unknown {
32
32
  export function formatItemsFromSchema(
33
33
  inputSchema: z.ZodType,
34
34
  items: unknown[],
35
+ startingNumber: number = 0,
35
36
  ): void {
36
37
  // Get the output schema and its format metadata
37
38
  const outputSchema = getOutputSchema(inputSchema);
38
39
  if (!outputSchema) {
39
40
  // Fallback to generic formatting if no output schema
40
- formatItemsGeneric(items);
41
+ formatItemsGeneric(items, startingNumber);
41
42
  return;
42
43
  }
43
44
 
44
45
  const formatMeta = getFormatMetadata(outputSchema);
45
46
  if (!formatMeta) {
46
47
  // Fallback to generic formatting if no format metadata
47
- formatItemsGeneric(items);
48
+ formatItemsGeneric(items, startingNumber);
48
49
  return;
49
50
  }
50
51
 
51
52
  // Format each item using the schema metadata
52
53
  items.forEach((item, index) => {
53
- formatSingleItem(item, index, formatMeta);
54
+ formatSingleItem(item, startingNumber + index, formatMeta);
54
55
  });
55
56
  }
56
57
 
57
58
  function formatSingleItem(
58
59
  item: unknown,
59
- index: number,
60
+ itemNumber: number,
60
61
  formatMeta: FormatMetadata,
61
62
  ): void {
62
63
  // Get the formatted item from the format function
63
64
  const formatted = formatMeta.format(item);
64
65
 
65
66
  // Build the main title line
66
- let titleLine = `${chalk.gray(`${index + 1}.`)} ${chalk.cyan(formatted.title)}`;
67
+ let titleLine = `${chalk.gray(`${itemNumber + 1}.`)} ${chalk.cyan(formatted.title)}`;
67
68
  if (formatted.subtitle) {
68
69
  titleLine += ` ${chalk.gray(formatted.subtitle)}`;
69
70
  }
@@ -94,7 +95,10 @@ function applyStyle(value: string, style: string): string {
94
95
  }
95
96
  }
96
97
 
97
- function formatItemsGeneric(items: unknown[]): void {
98
+ function formatItemsGeneric(
99
+ items: unknown[],
100
+ startingNumber: number = 0,
101
+ ): void {
98
102
  // Fallback formatting for items without schema metadata
99
103
  items.forEach((item, index) => {
100
104
  const itemObj = item as {
@@ -106,7 +110,9 @@ function formatItemsGeneric(items: unknown[]): void {
106
110
  };
107
111
  const name =
108
112
  itemObj.title || itemObj.name || itemObj.key || itemObj.id || "Item";
109
- console.log(`${chalk.gray(`${index + 1}.`)} ${chalk.cyan(name)}`);
113
+ console.log(
114
+ `${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(name)}`,
115
+ );
110
116
  if (itemObj.description) {
111
117
  console.log(` ${chalk.dim(itemObj.description)}`);
112
118
  }