|
1 | | -import * as path from "path"; |
2 | | -import fsExtra from "fs-extra"; |
3 | | - |
4 | 1 | import { Command, Flags } from "@oclif/core"; |
5 | | -import { SDKClient } from "../../client-utils/sdk-client.js"; |
6 | | -import { ApiError, Client, CodeGenerationExternalApisController } from "@apimatic/sdk"; |
| 2 | +import { DirectoryPath } from "../../types/file/directoryPath.js"; |
| 3 | +import { FlagsProvider } from "../../types/flags-provider.js"; |
| 4 | +import { SdkGeneratePrompts } from "../../prompts/sdk/generate.js"; |
| 5 | +import { GenerateAction } from "../../actions/sdk/generate.js"; |
| 6 | +import { Platforms } from "@apimatic/sdk"; |
| 7 | +import { LanguagePlatform } from "../../types/sdk/generate.js"; |
7 | 8 |
|
8 | | -import { replaceHTML, isJSONParsable, getFileNameFromPath } from "../../utils/utils.js"; |
9 | | -import { getSDKGenerationId, downloadGeneratedSDK } from "../../controllers/sdk/generate.js"; |
10 | | -import { DownloadSDKParams, SDKGenerateUnprocessableError } from "../../types/sdk/generate.js"; |
11 | | -import { AuthenticationError } from "../../types/utils.js"; |
| 9 | +const DEFAULT_WORKING_DIRECTORY = "./"; |
12 | 10 |
|
13 | 11 | export default class SdkGenerate extends Command { |
14 | | - static description = "Generate SDK for your APIs"; |
| 12 | + static description = "Generates SDK for your API"; |
15 | 13 | static flags = { |
16 | 14 | platform: Flags.string({ |
17 | | - parse: async (input) => input.toUpperCase(), |
18 | 15 | required: true, |
19 | | - description: `language platform for sdk |
20 | | -Simple: CSHARP|JAVA|PYTHON|RUBY|PHP|TYPESCRIPT|GO |
21 | | -Legacy: CS_NET_STANDARD_LIB|JAVA_ECLIPSE_JRE_LIB|PHP_GENERIC_LIB_V2|PYTHON_GENERIC_LIB|RUBY_GENERIC_LIB|TS_GENERIC_LIB|GO_GENERIC_LIB` |
22 | | - }), |
23 | | - file: Flags.string({ |
24 | | - parse: async (input) => path.resolve(input), |
25 | | - default: "", |
26 | | - description: "path to the API specification to generate SDKs for" |
| 16 | + options: Object.values(LanguagePlatform).map(p => p.toString()), |
| 17 | + description: `language platform for sdk` |
27 | 18 | }), |
28 | | - url: Flags.string({ |
29 | | - default: "", |
30 | | - description: |
31 | | - "URL to the API specification to generate SDKs for. Can be used in place of the --file option if the API specification is publicly available." |
| 19 | + spec: Flags.string({ |
| 20 | + description: "path to the folder containing the API specification file.", |
| 21 | + default: "./build/spec" |
32 | 22 | }), |
33 | 23 | destination: Flags.string({ |
34 | | - parse: async (input) => path.resolve(input), |
35 | | - default: path.resolve("./"), |
36 | | - description: "directory to download the generated SDK to" |
| 24 | + description: "[default: ./sdk] path where the sdk will be generated." |
37 | 25 | }), |
38 | | - force: Flags.boolean({ |
39 | | - char: "f", |
| 26 | + ...FlagsProvider.force, |
| 27 | + zip: Flags.boolean({ |
40 | 28 | default: false, |
41 | | - description: "overwrite if an SDK already exists in the destination" |
| 29 | + description: "download the generated SDK as a .zip archive" |
42 | 30 | }), |
43 | | - zip: Flags.boolean({ default: false, description: "download the generated SDK as a .zip archive" }), |
44 | | - "auth-key": Flags.string({ |
45 | | - default: "", |
46 | | - description: "override current authentication state with an authentication key" |
47 | | - }) |
| 31 | + ...FlagsProvider["auth-key"] |
48 | 32 | }; |
49 | 33 |
|
50 | 34 | static examples = [ |
51 | | - `$ apimatic sdk:generate --platform="CSHARP" --file="./specs/sample.json"`, |
52 | | - `$ apimatic sdk:generate --platform="CSHARP" --url=https://petstore.swagger.io/v2/swagger.json` |
| 35 | + `$ apimatic sdk:generate --platform="java"`, |
| 36 | + `$ apimatic sdk:generate --platform="csharp" --spec="./build/spec"` |
53 | 37 | ]; |
54 | 38 |
|
| 39 | + private readonly prompts: SdkGeneratePrompts = new SdkGeneratePrompts(); |
| 40 | + |
55 | 41 | async run() { |
56 | | - const { flags } = await this.parse(SdkGenerate); |
57 | | - const zip = flags.zip; |
58 | | - const fileName = flags.file ? getFileNameFromPath(flags.file) : getFileNameFromPath(flags.url); |
59 | | - const sdkFolderPath: string = path.join(flags.destination, `${fileName}_sdk_${flags.platform}`.toLowerCase()); |
60 | | - const zippedSDKPath: string = path.join(flags.destination, `${fileName}_sdk_${flags.platform}.zip`.toLowerCase()); |
| 42 | + const { flags: { platform, spec, destination, force, zip: zipSdk, "auth-key": authKey } } = await this.parse(SdkGenerate); |
61 | 43 |
|
62 | | - // Check if at destination, SDK already exists and throw error if force flag is not set for both zip and extracted |
63 | | - if (fsExtra.existsSync(sdkFolderPath) && !flags.force && !zip) { |
64 | | - throw new Error(`Can't download SDK to path ${sdkFolderPath}, because it already exists`); |
65 | | - } else if (fsExtra.existsSync(zippedSDKPath) && !flags.force && zip) { |
66 | | - throw new Error(`Can't download SDK to path ${zippedSDKPath}, because it already exists`); |
67 | | - } |
| 44 | + const workingDirectory = new DirectoryPath(DEFAULT_WORKING_DIRECTORY); |
| 45 | + const specDirectory = new DirectoryPath(spec); |
68 | 46 |
|
69 | | - try { |
70 | | - if (!(await fsExtra.pathExists(path.resolve(flags.destination)))) { |
71 | | - throw new Error(`Destination path ${flags.destination} does not exist`); |
72 | | - } else if (!(await fsExtra.pathExists(path.resolve(flags.file)))) { |
73 | | - throw new Error(`Specification file ${flags.file} does not exist`); |
74 | | - } |
| 47 | + const sdkPlatform = this.convertSimplePlatformToPlatform(platform as LanguagePlatform); |
| 48 | + const sdkDirectory = destination ? new DirectoryPath(destination) : workingDirectory.join("sdk").join(sdkPlatform); |
75 | 49 |
|
76 | | - const overrideAuthKey = flags["auth-key"] ? flags["auth-key"] : null; |
77 | | - const client: Client = await SDKClient.getInstance().getClient(overrideAuthKey, this.config.configDir); |
78 | | - const sdkGenerationController: CodeGenerationExternalApisController = new CodeGenerationExternalApisController( |
79 | | - client |
80 | | - ); |
| 50 | + var action = new GenerateAction(this.getConfigDir(), authKey); |
| 51 | + const result = await action.execute(specDirectory, sdkDirectory, sdkPlatform, force, zipSdk); |
| 52 | + result.mapAll( |
| 53 | + () => this.prompts.displayOutroMessage(sdkDirectory), |
| 54 | + (message) => this.prompts.logError(message) |
| 55 | + ); |
| 56 | + } |
81 | 57 |
|
82 | | - // Get generation id for the specification and platform |
83 | | - const codeGenId: string = await getSDKGenerationId(flags, sdkGenerationController); |
| 58 | + private getConfigDir = () => { |
| 59 | + return new DirectoryPath(this.config.configDir); |
| 60 | + }; |
84 | 61 |
|
85 | | - // If user wanted to download the SDK as well |
86 | | - const sdkDownloadParams: DownloadSDKParams = { |
87 | | - codeGenId, |
88 | | - zippedSDKPath, |
89 | | - sdkFolderPath, |
90 | | - zip |
91 | | - }; |
92 | | - const sdkPath: string = await downloadGeneratedSDK(sdkDownloadParams, sdkGenerationController); |
93 | | - this.log(`Success! Your SDK is located at ${sdkPath}`); |
94 | | - } catch (error) { |
95 | | - if ((error as ApiError).result) { |
96 | | - const apiError = error as ApiError; |
97 | | - const result = apiError.result as SDKGenerateUnprocessableError; |
98 | | - if (apiError.statusCode === 400 && isJSONParsable(result.message)) { |
99 | | - const errors = JSON.parse(result.message); |
100 | | - if (Array.isArray(errors.Errors) && apiError.statusCode === 400) { |
101 | | - this.error(replaceHTML(`${JSON.parse(result.message).Errors[0]}`)); |
102 | | - } |
103 | | - } else if (apiError.statusCode === 401 && apiError.body && typeof apiError.body === "string") { |
104 | | - this.error("You are not authorized to perform this action"); |
105 | | - } else if ( |
106 | | - apiError.statusCode === 500 && |
107 | | - apiError.body && |
108 | | - typeof apiError.body === "string" && |
109 | | - isJSONParsable(apiError.body) |
110 | | - ) { |
111 | | - this.error(JSON.parse(apiError.body).message); |
112 | | - } else if ( |
113 | | - apiError.statusCode === 422 && |
114 | | - apiError.body && |
115 | | - typeof apiError.body === "string" && |
116 | | - isJSONParsable(apiError.body) |
117 | | - ) { |
118 | | - this.error(JSON.parse(apiError.body)["dto.Url"][0]); |
119 | | - } else { |
120 | | - this.error(replaceHTML(result.message)); |
121 | | - } |
122 | | - } else if ((error as AuthenticationError).statusCode === 401) { |
123 | | - this.error("You are not authorized to perform this action"); |
124 | | - } else if ( |
125 | | - (error as AuthenticationError).statusCode === 402 && |
126 | | - (error as AuthenticationError).body && |
127 | | - typeof (error as AuthenticationError).body === "string" |
128 | | - ) { |
129 | | - this.error(replaceHTML((error as AuthenticationError).body)); |
130 | | - } else { |
131 | | - this.error(`${(error as Error).message}`); |
132 | | - } |
| 62 | + private convertSimplePlatformToPlatform(languagePlatform: LanguagePlatform): Platforms { |
| 63 | + switch (languagePlatform) { |
| 64 | + case LanguagePlatform.CSHARP: |
| 65 | + return Platforms.CsNetStandardLib; |
| 66 | + case LanguagePlatform.JAVA: |
| 67 | + return Platforms.JavaEclipseJreLib; |
| 68 | + case LanguagePlatform.PHP: |
| 69 | + return Platforms.PhpGenericLibV2; |
| 70 | + case LanguagePlatform.PYTHON: |
| 71 | + return Platforms.PythonGenericLib; |
| 72 | + case LanguagePlatform.RUBY: |
| 73 | + return Platforms.RubyGenericLib; |
| 74 | + case LanguagePlatform.TYPESCRIPT: |
| 75 | + return Platforms.TsGenericLib; |
| 76 | + case LanguagePlatform.GO: |
| 77 | + return Platforms.GoGenericLib; |
| 78 | + default: |
| 79 | + throw new Error(`Unknown LanguagePlatform: ${languagePlatform}`); |
133 | 80 | } |
134 | 81 | } |
135 | 82 | } |
0 commit comments