@zapier/zapier-sdk-cli 0.9.0 → 0.10.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.
- package/CHANGELOG.md +20 -0
- package/dist/cli.cjs +213 -100
- package/dist/cli.mjs +214 -101
- package/dist/index.cjs +15 -12
- package/dist/index.mjs +15 -12
- package/dist/package.json +1 -1
- package/dist/src/plugins/add/index.js +11 -13
- package/dist/src/utils/cli-generator-utils.d.ts +2 -1
- package/dist/src/utils/cli-generator-utils.js +11 -5
- package/dist/src/utils/cli-generator.js +50 -65
- package/dist/src/utils/parameter-resolver.d.ts +4 -1
- package/dist/src/utils/parameter-resolver.js +92 -15
- package/dist/src/utils/schema-formatter.d.ts +5 -1
- package/dist/src/utils/schema-formatter.js +48 -18
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/plugins/add/index.ts +15 -15
- package/src/utils/cli-generator-utils.ts +17 -5
- package/src/utils/cli-generator.ts +68 -79
- package/src/utils/parameter-resolver.ts +155 -21
- package/src/utils/schema-formatter.ts +68 -33
|
@@ -1,17 +1,59 @@
|
|
|
1
1
|
import inquirer from "inquirer";
|
|
2
2
|
import chalk from "chalk";
|
|
3
3
|
import { z } from "zod";
|
|
4
|
-
|
|
4
|
+
// ============================================================================
|
|
5
|
+
// Local Resolution Helper Functions
|
|
6
|
+
// ============================================================================
|
|
7
|
+
/**
|
|
8
|
+
* Resolve dependency chain for a parameter using local resolvers
|
|
9
|
+
* Returns parameters in the order they need to be resolved
|
|
10
|
+
*/
|
|
11
|
+
function getLocalResolutionOrder(paramName, resolvers, resolved = new Set()) {
|
|
12
|
+
const resolver = resolvers[paramName];
|
|
13
|
+
if (!resolver || resolver.type === "static") {
|
|
14
|
+
return [paramName];
|
|
15
|
+
}
|
|
16
|
+
const order = [];
|
|
17
|
+
if ("depends" in resolver && resolver.depends) {
|
|
18
|
+
for (const dependency of resolver.depends) {
|
|
19
|
+
if (!resolved.has(dependency)) {
|
|
20
|
+
order.push(...getLocalResolutionOrder(dependency, resolvers, resolved));
|
|
21
|
+
resolved.add(dependency);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
if (!resolved.has(paramName)) {
|
|
26
|
+
order.push(paramName);
|
|
27
|
+
resolved.add(paramName);
|
|
28
|
+
}
|
|
29
|
+
return order;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Get resolution order for multiple parameters using local resolvers
|
|
33
|
+
*/
|
|
34
|
+
function getLocalResolutionOrderForParams(paramNames, resolvers) {
|
|
35
|
+
const resolved = new Set();
|
|
36
|
+
const order = [];
|
|
37
|
+
for (const paramName of paramNames) {
|
|
38
|
+
const paramOrder = getLocalResolutionOrder(paramName, resolvers, resolved);
|
|
39
|
+
for (const param of paramOrder) {
|
|
40
|
+
if (!order.includes(param)) {
|
|
41
|
+
order.push(param);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return order;
|
|
46
|
+
}
|
|
5
47
|
// ============================================================================
|
|
6
48
|
// Schema Parameter Resolver
|
|
7
49
|
// ============================================================================
|
|
8
50
|
export class SchemaParameterResolver {
|
|
9
|
-
async resolveParameters(schema, providedParams, sdk) {
|
|
51
|
+
async resolveParameters(schema, providedParams, sdk, functionName) {
|
|
10
52
|
// 1. Try to parse with current parameters
|
|
11
53
|
const parseResult = schema.safeParse(providedParams);
|
|
12
54
|
// Get all schema parameters to check which ones have resolvers
|
|
13
55
|
const allParams = this.extractParametersFromSchema(schema);
|
|
14
|
-
const resolvableParams = allParams.filter((param) => hasResolver(param.name));
|
|
56
|
+
const resolvableParams = allParams.filter((param) => this.hasResolver(param.name, sdk, functionName));
|
|
15
57
|
// Get all missing parameters that have resolvers
|
|
16
58
|
const missingResolvable = resolvableParams.filter((param) => {
|
|
17
59
|
const hasValue = this.getNestedValue(providedParams, param.path) !== undefined;
|
|
@@ -61,10 +103,13 @@ export class SchemaParameterResolver {
|
|
|
61
103
|
sdk,
|
|
62
104
|
currentParams: providedParams,
|
|
63
105
|
resolvedParams,
|
|
106
|
+
functionName,
|
|
64
107
|
};
|
|
108
|
+
// Get local resolvers for this function
|
|
109
|
+
const localResolvers = this.getLocalResolvers(sdk, functionName);
|
|
65
110
|
if (functionallyRequired.length > 0) {
|
|
66
111
|
const requiredParamNames = functionallyRequired.map((p) => p.name);
|
|
67
|
-
const requiredResolutionOrder =
|
|
112
|
+
const requiredResolutionOrder = getLocalResolutionOrderForParams(requiredParamNames, localResolvers);
|
|
68
113
|
// Find all parameters that need to be resolved (including dependencies)
|
|
69
114
|
// from the available resolvable parameters
|
|
70
115
|
const orderedRequiredParams = requiredResolutionOrder
|
|
@@ -84,7 +129,7 @@ export class SchemaParameterResolver {
|
|
|
84
129
|
.filter((param) => param !== undefined);
|
|
85
130
|
for (const param of orderedRequiredParams) {
|
|
86
131
|
try {
|
|
87
|
-
const value = await this.resolveParameter(param, context);
|
|
132
|
+
const value = await this.resolveParameter(param, context, functionName);
|
|
88
133
|
this.setNestedValue(resolvedParams, param.path, value);
|
|
89
134
|
// Update context with newly resolved value
|
|
90
135
|
context.resolvedParams = resolvedParams;
|
|
@@ -105,13 +150,13 @@ export class SchemaParameterResolver {
|
|
|
105
150
|
// 3. Resolve parameters that should always be prompted for (but can be skipped)
|
|
106
151
|
if (alwaysPrompt.length > 0) {
|
|
107
152
|
const alwaysPromptNames = alwaysPrompt.map((p) => p.name);
|
|
108
|
-
const alwaysPromptResolutionOrder =
|
|
153
|
+
const alwaysPromptResolutionOrder = getLocalResolutionOrderForParams(alwaysPromptNames, localResolvers);
|
|
109
154
|
const orderedAlwaysPromptParams = alwaysPromptResolutionOrder
|
|
110
155
|
.map((paramName) => alwaysPrompt.find((p) => p.name === paramName))
|
|
111
156
|
.filter((param) => param !== undefined);
|
|
112
157
|
for (const param of orderedAlwaysPromptParams) {
|
|
113
158
|
try {
|
|
114
|
-
const value = await this.resolveParameter(param, context);
|
|
159
|
+
const value = await this.resolveParameter(param, context, functionName);
|
|
115
160
|
this.setNestedValue(resolvedParams, param.path, value);
|
|
116
161
|
// Update context with newly resolved value
|
|
117
162
|
context.resolvedParams = resolvedParams;
|
|
@@ -139,13 +184,13 @@ export class SchemaParameterResolver {
|
|
|
139
184
|
if (shouldResolveOptional.resolveOptional) {
|
|
140
185
|
// Resolve optional parameters using their resolvers
|
|
141
186
|
const optionalParamNames = trulyOptional.map((p) => p.name);
|
|
142
|
-
const optionalResolutionOrder =
|
|
187
|
+
const optionalResolutionOrder = getLocalResolutionOrderForParams(optionalParamNames, localResolvers);
|
|
143
188
|
const orderedOptionalParams = optionalResolutionOrder
|
|
144
189
|
.map((paramName) => trulyOptional.find((p) => p.name === paramName))
|
|
145
190
|
.filter((param) => param !== undefined);
|
|
146
191
|
for (const param of orderedOptionalParams) {
|
|
147
192
|
try {
|
|
148
|
-
const value = await this.resolveParameter(param, context);
|
|
193
|
+
const value = await this.resolveParameter(param, context, functionName);
|
|
149
194
|
this.setNestedValue(resolvedParams, param.path, value);
|
|
150
195
|
// Update context with newly resolved value
|
|
151
196
|
context.resolvedParams = resolvedParams;
|
|
@@ -208,8 +253,8 @@ export class SchemaParameterResolver {
|
|
|
208
253
|
isRequired,
|
|
209
254
|
};
|
|
210
255
|
}
|
|
211
|
-
async resolveParameter(param, context) {
|
|
212
|
-
const resolver = getResolver(param.name);
|
|
256
|
+
async resolveParameter(param, context, functionName) {
|
|
257
|
+
const resolver = this.getResolver(param.name, context.sdk, functionName);
|
|
213
258
|
if (!resolver) {
|
|
214
259
|
throw new Error(`No resolver found for parameter: ${param.name}`);
|
|
215
260
|
}
|
|
@@ -285,8 +330,8 @@ export class SchemaParameterResolver {
|
|
|
285
330
|
break;
|
|
286
331
|
}
|
|
287
332
|
// Separate new required and optional fields
|
|
288
|
-
const newRequiredFields = newFields.filter((field) => field.
|
|
289
|
-
const newOptionalFields = newFields.filter((field) => !field.
|
|
333
|
+
const newRequiredFields = newFields.filter((field) => field.is_required);
|
|
334
|
+
const newOptionalFields = newFields.filter((field) => !field.is_required);
|
|
290
335
|
// Prompt for new required fields
|
|
291
336
|
if (newRequiredFields.length > 0) {
|
|
292
337
|
console.log(chalk.blue(`\n📝 Please provide values for the following ${iteration === 1 ? "" : "additional "}input fields:`));
|
|
@@ -358,7 +403,7 @@ export class SchemaParameterResolver {
|
|
|
358
403
|
const fieldPrompt = {
|
|
359
404
|
type: fieldObj.type === "boolean" ? "confirm" : "input",
|
|
360
405
|
name: fieldObj.key,
|
|
361
|
-
message: `${fieldObj.label || fieldObj.key}${fieldObj.
|
|
406
|
+
message: `${fieldObj.label || fieldObj.key}${fieldObj.is_required ? " (required)" : " (optional)"}:`,
|
|
362
407
|
};
|
|
363
408
|
if (fieldObj.helpText) {
|
|
364
409
|
fieldPrompt.prefix = chalk.gray(`ℹ ${fieldObj.helpText}\n`);
|
|
@@ -381,7 +426,7 @@ export class SchemaParameterResolver {
|
|
|
381
426
|
if (answer[fieldObj.key] !== undefined && answer[fieldObj.key] !== "") {
|
|
382
427
|
inputs[fieldObj.key] = answer[fieldObj.key];
|
|
383
428
|
}
|
|
384
|
-
else if (fieldObj.
|
|
429
|
+
else if (fieldObj.is_required) {
|
|
385
430
|
throw new Error(`Required field ${fieldObj.key} cannot be empty`);
|
|
386
431
|
}
|
|
387
432
|
}
|
|
@@ -399,4 +444,36 @@ export class SchemaParameterResolver {
|
|
|
399
444
|
errorObj?.message?.includes("User force closed") ||
|
|
400
445
|
errorObj?.isTTYError === true);
|
|
401
446
|
}
|
|
447
|
+
hasResolver(paramName, sdk, functionName) {
|
|
448
|
+
// Check plugin-specific resolvers first
|
|
449
|
+
if (functionName && typeof sdk.getRegistry === "function") {
|
|
450
|
+
const registry = sdk.getRegistry();
|
|
451
|
+
const functionInfo = registry.functions.find((f) => f.name === functionName);
|
|
452
|
+
if (functionInfo && functionInfo.resolvers?.[paramName]) {
|
|
453
|
+
return true;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
// No global registry fallback
|
|
457
|
+
return false;
|
|
458
|
+
}
|
|
459
|
+
getResolver(paramName, sdk, functionName) {
|
|
460
|
+
// Check plugin-specific resolvers first
|
|
461
|
+
if (functionName && typeof sdk.getRegistry === "function") {
|
|
462
|
+
const registry = sdk.getRegistry();
|
|
463
|
+
const functionInfo = registry.functions.find((f) => f.name === functionName);
|
|
464
|
+
if (functionInfo && functionInfo.resolvers?.[paramName]) {
|
|
465
|
+
return functionInfo.resolvers[paramName];
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
// No global registry fallback
|
|
469
|
+
return null;
|
|
470
|
+
}
|
|
471
|
+
getLocalResolvers(sdk, functionName) {
|
|
472
|
+
if (!functionName || typeof sdk.getRegistry !== "function") {
|
|
473
|
+
return {};
|
|
474
|
+
}
|
|
475
|
+
const registry = sdk.getRegistry();
|
|
476
|
+
const functionInfo = registry.functions.find((f) => f.name === functionName);
|
|
477
|
+
return functionInfo?.resolvers || {};
|
|
478
|
+
}
|
|
402
479
|
}
|
|
@@ -1,2 +1,6 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
-
export declare function
|
|
2
|
+
export declare function formatJsonOutput(data: unknown): void;
|
|
3
|
+
export declare function formatItemsFromSchema(functionInfo: {
|
|
4
|
+
inputSchema: z.ZodType;
|
|
5
|
+
outputSchema?: z.ZodType;
|
|
6
|
+
}, items: unknown[], startingNumber?: number): void;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
|
+
import util from "util";
|
|
2
3
|
function getFormatMetadata(schema) {
|
|
3
4
|
return schema?._def
|
|
4
5
|
?.formatMeta;
|
|
@@ -7,11 +8,22 @@ function getOutputSchema(schema) {
|
|
|
7
8
|
return schema?._def?.outputSchema;
|
|
8
9
|
}
|
|
9
10
|
// ============================================================================
|
|
11
|
+
// JSON Formatting
|
|
12
|
+
// ============================================================================
|
|
13
|
+
export function formatJsonOutput(data) {
|
|
14
|
+
// Don't print anything for undefined results (commands that just perform actions)
|
|
15
|
+
if (data === undefined) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
// Use util.inspect for colored output
|
|
19
|
+
console.log(util.inspect(data, { colors: true, depth: null, breakLength: 80 }));
|
|
20
|
+
}
|
|
21
|
+
// ============================================================================
|
|
10
22
|
// Generic Schema-Driven Formatter
|
|
11
23
|
// ============================================================================
|
|
12
|
-
export function formatItemsFromSchema(
|
|
13
|
-
// Get the output schema
|
|
14
|
-
const outputSchema = getOutputSchema(inputSchema);
|
|
24
|
+
export function formatItemsFromSchema(functionInfo, items, startingNumber = 0) {
|
|
25
|
+
// Get the output schema from function info or fall back to input schema output schema
|
|
26
|
+
const outputSchema = functionInfo.outputSchema || getOutputSchema(functionInfo.inputSchema);
|
|
15
27
|
if (!outputSchema) {
|
|
16
28
|
// Fallback to generic formatting if no output schema
|
|
17
29
|
formatItemsGeneric(items, startingNumber);
|
|
@@ -25,18 +37,31 @@ export function formatItemsFromSchema(inputSchema, items, startingNumber = 0) {
|
|
|
25
37
|
}
|
|
26
38
|
// Format each item using the schema metadata
|
|
27
39
|
items.forEach((item, index) => {
|
|
28
|
-
|
|
40
|
+
const formatted = formatMeta.format(item);
|
|
41
|
+
formatSingleItem(formatted, startingNumber + index);
|
|
29
42
|
});
|
|
30
43
|
}
|
|
31
|
-
function formatSingleItem(
|
|
32
|
-
//
|
|
33
|
-
const formatted = formatMeta.format(item);
|
|
34
|
-
// Build the main title line
|
|
44
|
+
function formatSingleItem(formatted, itemNumber) {
|
|
45
|
+
// Build the main title line with optional subtitle
|
|
35
46
|
let titleLine = `${chalk.gray(`${itemNumber + 1}.`)} ${chalk.cyan(formatted.title)}`;
|
|
36
|
-
|
|
37
|
-
|
|
47
|
+
// Generate subtitle from id or key
|
|
48
|
+
if (formatted.id) {
|
|
49
|
+
titleLine += ` ${chalk.gray(`(ID: ${formatted.id})`)}`;
|
|
50
|
+
}
|
|
51
|
+
else if (formatted.key) {
|
|
52
|
+
titleLine += ` ${chalk.gray(`(${formatted.key})`)}`;
|
|
38
53
|
}
|
|
39
54
|
console.log(titleLine);
|
|
55
|
+
// Show description if available
|
|
56
|
+
if (formatted.description) {
|
|
57
|
+
console.log(` ${chalk.dim(formatted.description)}`);
|
|
58
|
+
}
|
|
59
|
+
// If data is provided, use JSON formatting instead of details
|
|
60
|
+
if (formatted.data !== undefined) {
|
|
61
|
+
formatJsonOutput(formatted.data);
|
|
62
|
+
console.log(); // Empty line between items
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
40
65
|
// Format detail lines
|
|
41
66
|
for (const detail of formatted.details) {
|
|
42
67
|
const styledText = applyStyle(detail.text, detail.style);
|
|
@@ -59,15 +84,20 @@ function applyStyle(value, style) {
|
|
|
59
84
|
return chalk.blue(value);
|
|
60
85
|
}
|
|
61
86
|
}
|
|
87
|
+
function convertGenericItemToFormattedItem(item) {
|
|
88
|
+
const itemObj = item;
|
|
89
|
+
return {
|
|
90
|
+
title: itemObj.title || itemObj.name || itemObj.key || itemObj.id || "Item",
|
|
91
|
+
id: itemObj.id,
|
|
92
|
+
key: itemObj.key,
|
|
93
|
+
description: itemObj.description,
|
|
94
|
+
details: [],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
62
97
|
function formatItemsGeneric(items, startingNumber = 0) {
|
|
63
|
-
//
|
|
98
|
+
// Convert generic items to FormattedItem and use formatSingleItem
|
|
64
99
|
items.forEach((item, index) => {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
console.log(`${chalk.gray(`${startingNumber + index + 1}.`)} ${chalk.cyan(name)}`);
|
|
68
|
-
if (itemObj.description) {
|
|
69
|
-
console.log(` ${chalk.dim(itemObj.description)}`);
|
|
70
|
-
}
|
|
71
|
-
console.log();
|
|
100
|
+
const formatted = convertGenericItemToFormattedItem(item);
|
|
101
|
+
formatSingleItem(formatted, startingNumber + index);
|
|
72
102
|
});
|
|
73
103
|
}
|