@zapier/zapier-sdk-cli 0.13.0 → 0.13.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.
- package/CHANGELOG.md +17 -0
- package/dist/cli.cjs +72 -67
- package/dist/cli.mjs +73 -68
- package/dist/index.cjs +71 -66
- package/dist/index.mjs +72 -67
- package/dist/package.json +1 -1
- package/dist/src/plugins/add/ast-generator.d.ts +8 -4
- package/dist/src/plugins/add/ast-generator.js +82 -66
- package/dist/src/plugins/add/index.js +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -4
- package/src/plugins/add/ast-generator.ts +103 -81
- package/src/plugins/add/index.ts +3 -2
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as ts from "typescript";
|
|
2
|
+
import { toSnakeCase } from "@zapier/zapier-sdk";
|
|
2
3
|
/**
|
|
3
4
|
* AST-based TypeScript type generator using the TypeScript Compiler API
|
|
4
5
|
*/
|
|
@@ -15,24 +16,19 @@ export class AstTypeGenerator {
|
|
|
15
16
|
* Generate TypeScript types using AST for a specific app
|
|
16
17
|
*/
|
|
17
18
|
async generateTypes(options) {
|
|
18
|
-
const {
|
|
19
|
-
//
|
|
20
|
-
const { app, version } = this.parseAppIdentifier(appKey);
|
|
21
|
-
// Fetch all actions for the app
|
|
19
|
+
const { app, authenticationId, sdk } = options;
|
|
20
|
+
// Fetch all actions for the app using implementation_id for correct versioning
|
|
22
21
|
const actionsResult = await sdk.listActions({
|
|
23
|
-
appKey: app,
|
|
22
|
+
appKey: app.implementation_id,
|
|
24
23
|
});
|
|
25
24
|
const actions = actionsResult.data;
|
|
26
|
-
if (actions.length === 0) {
|
|
27
|
-
return this.generateEmptyTypesFile(app, version);
|
|
28
|
-
}
|
|
29
25
|
// Fetch input fields for each action
|
|
30
26
|
const actionsWithFields = [];
|
|
31
27
|
if (authenticationId) {
|
|
32
28
|
for (const action of actions) {
|
|
33
29
|
try {
|
|
34
30
|
const fieldsResult = await sdk.listInputFields({
|
|
35
|
-
appKey:
|
|
31
|
+
appKey: app.implementation_id,
|
|
36
32
|
actionKey: action.key,
|
|
37
33
|
actionType: action.action_type,
|
|
38
34
|
authenticationId: authenticationId,
|
|
@@ -61,7 +57,7 @@ export class AstTypeGenerator {
|
|
|
61
57
|
...action,
|
|
62
58
|
inputFields: [],
|
|
63
59
|
name: action.title || action.key,
|
|
64
|
-
app_key: action.app_key ||
|
|
60
|
+
app_key: action.app_key || app.implementation_id,
|
|
65
61
|
action_type: action.action_type || "write",
|
|
66
62
|
title: action.title || action.key,
|
|
67
63
|
type: "action",
|
|
@@ -70,24 +66,17 @@ export class AstTypeGenerator {
|
|
|
70
66
|
});
|
|
71
67
|
}
|
|
72
68
|
// Generate TypeScript AST nodes
|
|
73
|
-
const sourceFile = this.createSourceFile(app, actionsWithFields
|
|
69
|
+
const sourceFile = this.createSourceFile(app, actionsWithFields);
|
|
74
70
|
// Print the AST to string
|
|
75
71
|
return this.printer.printFile(sourceFile);
|
|
76
72
|
}
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
};
|
|
83
|
-
}
|
|
84
|
-
createSourceFile(appKey, actions, version) {
|
|
85
|
-
const appName = this.capitalize(appKey);
|
|
86
|
-
const versionComment = version
|
|
87
|
-
? ` * Generated for ${appKey}@${version}`
|
|
88
|
-
: ` * Generated for ${appKey}`;
|
|
73
|
+
createSourceFile(app, actions) {
|
|
74
|
+
const appName = this.getPreferredAppName(app);
|
|
75
|
+
const versionComment = ` * Generated for ${app.implementation_id}`;
|
|
76
|
+
const preferredKey = this.getPreferredProgrammaticKey(app);
|
|
77
|
+
const myVariableName = `my${appName}`;
|
|
89
78
|
// Create header comment
|
|
90
|
-
const headerComment = `Auto-generated TypeScript types for Zapier ${
|
|
79
|
+
const headerComment = `Auto-generated TypeScript types for Zapier ${app.key} actions
|
|
91
80
|
${versionComment.slice(3)}
|
|
92
81
|
Generated on: ${new Date().toISOString()}
|
|
93
82
|
|
|
@@ -99,11 +88,11 @@ Usage:
|
|
|
99
88
|
|
|
100
89
|
const zapier = createZapierSdk();
|
|
101
90
|
// Types are automatically available:
|
|
102
|
-
await zapier.apps.${
|
|
91
|
+
await zapier.apps.${preferredKey}.search.user_by_email({ authenticationId: 123, inputs: { email } })
|
|
103
92
|
|
|
104
93
|
// Factory usage (pinned auth):
|
|
105
|
-
const
|
|
106
|
-
await
|
|
94
|
+
const ${myVariableName} = zapier.apps.${preferredKey}({ authenticationId: 123 })
|
|
95
|
+
await ${myVariableName}.search.user_by_email({ inputs: { email } })`;
|
|
107
96
|
const statements = [
|
|
108
97
|
// Import the SDK to activate module augmentation
|
|
109
98
|
this.createImportStatement(["@zapier/zapier-sdk"]),
|
|
@@ -138,7 +127,8 @@ Usage:
|
|
|
138
127
|
const appWithFactoryType = this.createAppWithFactoryType(appName);
|
|
139
128
|
statements.push(appWithFactoryType);
|
|
140
129
|
// Generate module augmentation for automatic type integration
|
|
141
|
-
const
|
|
130
|
+
const allKeys = this.getAllKeys(app);
|
|
131
|
+
const moduleAugmentation = this.createModuleAugmentation(allKeys, appName);
|
|
142
132
|
statements.push(moduleAugmentation);
|
|
143
133
|
// Add empty export to make this a module
|
|
144
134
|
statements.push(this.factory.createExportDeclaration(undefined, false, this.factory.createNamedExports([])));
|
|
@@ -280,13 +270,13 @@ Usage:
|
|
|
280
270
|
this.factory.createTypeReferenceNode(`${appName}AppProxy`),
|
|
281
271
|
]));
|
|
282
272
|
}
|
|
283
|
-
createModuleAugmentation(
|
|
273
|
+
createModuleAugmentation(appKeys, appName) {
|
|
284
274
|
// Create: declare module "@zapier/zapier-sdk" { interface ZapierSdkApps { [appKey]: AppWithFactory } }
|
|
285
275
|
// This creates a new interface that we can merge with ZapierSdk
|
|
276
|
+
// Create properties for all keys (main key + other_keys)
|
|
277
|
+
const properties = appKeys.map((appKey) => this.factory.createPropertySignature(undefined, this.createPropertyName(appKey), undefined, this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)));
|
|
286
278
|
return this.factory.createModuleDeclaration([this.factory.createToken(ts.SyntaxKind.DeclareKeyword)], this.factory.createStringLiteral("@zapier/zapier-sdk"), this.factory.createModuleBlock([
|
|
287
|
-
this.factory.createInterfaceDeclaration(undefined, "ZapierSdkApps", undefined, undefined,
|
|
288
|
-
this.factory.createPropertySignature(undefined, appKey, undefined, this.factory.createTypeReferenceNode(`${appName}AppWithFactory`)),
|
|
289
|
-
]),
|
|
279
|
+
this.factory.createInterfaceDeclaration(undefined, "ZapierSdkApps", undefined, undefined, properties),
|
|
290
280
|
]));
|
|
291
281
|
}
|
|
292
282
|
mapFieldTypeToTypeNode(field) {
|
|
@@ -324,40 +314,6 @@ Usage:
|
|
|
324
314
|
]);
|
|
325
315
|
}
|
|
326
316
|
}
|
|
327
|
-
generateEmptyTypesFile(appKey, version) {
|
|
328
|
-
const appName = this.capitalize(appKey);
|
|
329
|
-
const versionComment = version
|
|
330
|
-
? ` * Generated for ${appKey}@${version}`
|
|
331
|
-
: ` * Generated for ${appKey}`;
|
|
332
|
-
return `/* eslint-disable @typescript-eslint/naming-convention, @typescript-eslint/no-explicit-any */
|
|
333
|
-
/**
|
|
334
|
-
* Auto-generated TypeScript types for Zapier ${appKey} actions
|
|
335
|
-
${versionComment}
|
|
336
|
-
* Generated on: ${new Date().toISOString()}
|
|
337
|
-
*
|
|
338
|
-
* No actions found for this app.
|
|
339
|
-
*/
|
|
340
|
-
|
|
341
|
-
import type { ActionExecutionOptions, ActionExecutionResult, ZapierFetchInitOptions } from '@zapier/zapier-sdk'
|
|
342
|
-
|
|
343
|
-
interface ${appName}AppProxy {
|
|
344
|
-
/** Make authenticated HTTP requests through Zapier's Relay service */
|
|
345
|
-
fetch: (url: string | URL, init?: ZapierFetchInitOptions) => Promise<Response>
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
interface ${appName}AppFactory {
|
|
349
|
-
(options: { authenticationId: number }): ${appName}AppProxy
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
type ${appName}AppWithFactory = ${appName}AppFactory & ${appName}AppProxy
|
|
353
|
-
|
|
354
|
-
declare module "@zapier/zapier-sdk" {
|
|
355
|
-
interface ZapierSdkApps {
|
|
356
|
-
${appKey}: ${appName}AppWithFactory
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
`;
|
|
360
|
-
}
|
|
361
317
|
capitalize(str) {
|
|
362
318
|
return str.charAt(0).toUpperCase() + str.slice(1).replace(/[-_]/g, "");
|
|
363
319
|
}
|
|
@@ -383,4 +339,64 @@ declare module "@zapier/zapier-sdk" {
|
|
|
383
339
|
// Escape comment text to prevent breaking the JSDoc comment
|
|
384
340
|
return comment.replace(/\*\//g, "*\\/").replace(/\r?\n/g, " ");
|
|
385
341
|
}
|
|
342
|
+
createPropertyName(name) {
|
|
343
|
+
// Check if the name is a valid JavaScript identifier
|
|
344
|
+
if (this.isValidIdentifier(name)) {
|
|
345
|
+
return this.factory.createIdentifier(name);
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
// Use string literal for invalid identifiers (e.g., contains dashes)
|
|
349
|
+
return this.factory.createStringLiteral(name);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
isValidIdentifier(name) {
|
|
353
|
+
// JavaScript identifier rules: must start with letter, $, or _,
|
|
354
|
+
// followed by letters, digits, $, or _
|
|
355
|
+
return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(name);
|
|
356
|
+
}
|
|
357
|
+
getPreferredProgrammaticKey(app) {
|
|
358
|
+
// If we have a slug, convert it to snake_case as the preferred programmatic key
|
|
359
|
+
if (app.slug) {
|
|
360
|
+
const snakeCaseSlug = toSnakeCase(app.slug);
|
|
361
|
+
if (this.isValidIdentifier(snakeCaseSlug)) {
|
|
362
|
+
return snakeCaseSlug;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
// Otherwise, use the main key if it's a valid identifier
|
|
366
|
+
if (this.isValidIdentifier(app.key)) {
|
|
367
|
+
return app.key;
|
|
368
|
+
}
|
|
369
|
+
// Fallback: sanitize the key to make it a valid identifier
|
|
370
|
+
return this.sanitizeToIdentifier(app.key);
|
|
371
|
+
}
|
|
372
|
+
getPreferredAppName(app) {
|
|
373
|
+
const preferredKey = this.getPreferredProgrammaticKey(app);
|
|
374
|
+
// If it's snake_case, convert to PascalCase
|
|
375
|
+
if (preferredKey.includes("_")) {
|
|
376
|
+
return preferredKey
|
|
377
|
+
.split("_")
|
|
378
|
+
.map((word) => this.capitalize(word.toLowerCase()))
|
|
379
|
+
.join("");
|
|
380
|
+
}
|
|
381
|
+
// Otherwise, capitalize first letter for PascalCase
|
|
382
|
+
return this.capitalize(preferredKey);
|
|
383
|
+
}
|
|
384
|
+
sanitizeToIdentifier(name) {
|
|
385
|
+
// Convert any string to a valid JavaScript identifier
|
|
386
|
+
let sanitized = name.replace(/[^a-zA-Z0-9_$]/g, "_");
|
|
387
|
+
// If it starts with a number, prepend an underscore
|
|
388
|
+
if (/^[0-9]/.test(sanitized)) {
|
|
389
|
+
sanitized = "_" + sanitized;
|
|
390
|
+
}
|
|
391
|
+
return sanitized;
|
|
392
|
+
}
|
|
393
|
+
getAllKeys(app) {
|
|
394
|
+
// Return all possible keys for this app
|
|
395
|
+
const allKeys = new Set([app.key]);
|
|
396
|
+
if (app.slug) {
|
|
397
|
+
allKeys.add(app.slug);
|
|
398
|
+
allKeys.add(toSnakeCase(app.slug));
|
|
399
|
+
}
|
|
400
|
+
return Array.from(allKeys);
|
|
401
|
+
}
|
|
386
402
|
}
|