vls-openapi-generator 1.3.3 → 1.4.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.
@@ -46,17 +46,18 @@ const HANDLERS_DIR = path.join(process.cwd(), 'dist', 'src', 'handlers');
46
46
  const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
47
47
  const OUTPUT_FILE = path.join(process.cwd(), 'openapi.json');
48
48
  const generateOpenAPI = async () => {
49
+ console.info('Generating Open API documentation...');
49
50
  const args = process.argv;
50
51
  const params = {};
51
52
  for (let i = 2; i < args.length; i += 2) {
52
53
  const key = args[i].replace('--', '');
53
54
  params[key] = args[i + 1];
54
55
  }
55
- console.info('Generating Open API documentation...');
56
56
  await (0, util_1.promisify)(child_process_1.exec)('rm -rf ./dist');
57
57
  await (0, util_1.promisify)(child_process_1.exec)('npx tsc');
58
58
  const handlerFiles = await fs_1.promises.readdir(HANDLERS_DIR);
59
59
  const existingOpenAPIFile = JSON.parse(await fs_1.promises.readFile(OPENAPI_FILE, 'utf-8'));
60
+ existingOpenAPIFile.paths = {};
60
61
  for (const handler of handlerFiles) {
61
62
  const fileName = path.parse(handler).name;
62
63
  const { bodySchema, queryParametersSchema, eventResponseParametersSchema, eventResponseModulesSchema, OPENAPI_CONFIG: openAPIConfig } = (await Promise.resolve(`${path.join(SCHEMAS_DIR, fileName + '.js')}`).then(s => __importStar(require(s))).catch(() => ({})));
@@ -117,5 +118,6 @@ const generateOpenAPI = async () => {
117
118
  };
118
119
  }
119
120
  await fs_1.promises.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
121
+ console.info('Open API documentation generated successfully');
120
122
  };
121
123
  exports.generateOpenAPI = generateOpenAPI;
package/dist/index.js CHANGED
@@ -21,21 +21,12 @@ __exportStar(require("./lambda-type"), exports);
21
21
  (async () => {
22
22
  try {
23
23
  await (0, generate_openapi_1.generateOpenAPI)();
24
- console.info('Open API documentation generated successfully');
24
+ if (process.argv.includes('--upload')) {
25
+ await (0, upload_openapi_js_1.uploadOpenAPI)();
26
+ }
25
27
  }
26
28
  catch (error) {
27
29
  console.error(error);
28
30
  process.exit(1);
29
31
  }
30
- if (process.argv.includes('--upload')) {
31
- console.info('Uploading Open API documentation to Postman...');
32
- try {
33
- await (0, upload_openapi_js_1.uploadOpenAPI)();
34
- console.info('Open API documentation uploaded successfully');
35
- }
36
- catch (error) {
37
- console.error(error);
38
- process.exit(1);
39
- }
40
- }
41
32
  })().catch(console.error);
@@ -1,13 +1,50 @@
1
- import { OpenAPI } from './openapi-type';
2
1
  export declare class PostmanService {
3
2
  private client;
4
- constructor(apiKey: string);
3
+ private workspaceID;
4
+ constructor(apiKey: string, workspaceID: string);
5
5
  getCollections: () => Promise<{
6
6
  collections: {
7
7
  id: string;
8
8
  name: string;
9
9
  }[];
10
10
  }>;
11
- deleteCollection: (collectionID: string) => Promise<import("axios").AxiosResponse<any, any>>;
12
- createCollection: (payload: OpenAPI) => Promise<import("axios").AxiosResponse<any, any>>;
11
+ getCollection: (id: string) => Promise<{
12
+ collection: {
13
+ info: {
14
+ _postman_id: string;
15
+ name: string;
16
+ };
17
+ item: {
18
+ id: string;
19
+ name: "development" | "production";
20
+ item: object[];
21
+ }[];
22
+ variable: {
23
+ key: string;
24
+ value: string;
25
+ }[];
26
+ };
27
+ }>;
28
+ createCollection: (partnerName: string) => Promise<string>;
29
+ deleteFolder: (collectionID: string, folderID: string) => Promise<import("axios").AxiosResponse<any, any>>;
30
+ createFolder: (collectionID: string, folderName: string) => Promise<import("axios").AxiosResponse<any, any>>;
31
+ updateCollection: (collectionID: string, collection: object) => Promise<import("axios").AxiosResponse<any, any>>;
32
+ updateVariablesCollection: (collectionID: string, variables: {
33
+ key: string;
34
+ value: string;
35
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
36
+ getAllEnvironments: () => Promise<{
37
+ environments: {
38
+ id: string;
39
+ name: string;
40
+ }[];
41
+ }>;
42
+ createEnvironment: (name: string, values: {
43
+ key: string;
44
+ value: string;
45
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
46
+ updateEnvironment: (id: string, name: string, values: {
47
+ key: string;
48
+ value: string;
49
+ }[]) => Promise<import("axios").AxiosResponse<any, any>>;
13
50
  }
@@ -6,19 +6,58 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.PostmanService = void 0;
7
7
  const axios_1 = __importDefault(require("axios"));
8
8
  class PostmanService {
9
- constructor(apiKey) {
9
+ constructor(apiKey, workspaceID) {
10
10
  this.getCollections = async () => {
11
11
  return (await this.client.get('/collections')).data;
12
12
  };
13
- this.deleteCollection = async (collectionID) => {
14
- return await this.client.delete(`/collections/${collectionID}`);
13
+ this.getCollection = async (id) => {
14
+ return (await this.client.get(`/collections/${id}?workspace=${this.workspaceID}`)).data;
15
15
  };
16
- this.createCollection = async (payload) => {
17
- return await this.client.post('/import/openapi', {
18
- type: 'json',
19
- input: payload
16
+ this.createCollection = async (partnerName) => {
17
+ return (await this.client.post(`/collections?workspace=${this.workspaceID}`, {
18
+ collection: {
19
+ info: {
20
+ name: partnerName,
21
+ schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
22
+ },
23
+ item: []
24
+ }
25
+ })).data.collection.id;
26
+ };
27
+ this.deleteFolder = async (collectionID, folderID) => {
28
+ return await this.client.delete(`/collections/${collectionID}/folders/${folderID}`);
29
+ };
30
+ this.createFolder = async (collectionID, folderName) => {
31
+ return await this.client.post(`/collections/${collectionID}/folders`, {
32
+ name: folderName
33
+ });
34
+ };
35
+ this.updateCollection = async (collectionID, collection) => {
36
+ return await this.client.put(`/collections/${collectionID}`, collection);
37
+ };
38
+ this.updateVariablesCollection = async (collectionID, variables) => {
39
+ return await this.client.patch(`/collections/${collectionID}`, { collection: { variable: variables } });
40
+ };
41
+ this.getAllEnvironments = async () => {
42
+ return (await this.client.get(`/environments?workspace=${this.workspaceID}`)).data;
43
+ };
44
+ this.createEnvironment = async (name, values) => {
45
+ return await this.client.post(`/environments?workspace=${this.workspaceID}`, {
46
+ environment: {
47
+ name,
48
+ values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
49
+ }
50
+ });
51
+ };
52
+ this.updateEnvironment = async (id, name, values) => {
53
+ return await this.client.put(`/environments/${id}?workspace=${this.workspaceID}`, {
54
+ environment: {
55
+ name,
56
+ values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
57
+ }
20
58
  });
21
59
  };
60
+ this.workspaceID = workspaceID;
22
61
  this.client = axios_1.default.create({
23
62
  baseURL: 'https://api.getpostman.com',
24
63
  headers: {
@@ -36,15 +36,22 @@ Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.uploadOpenAPI = void 0;
37
37
  const fs_1 = require("fs");
38
38
  require("module-alias/register.js");
39
+ const openapi_to_postmanv2_1 = require("openapi-to-postmanv2");
39
40
  const path = __importStar(require("path"));
41
+ const util_1 = require("util");
40
42
  const postman_service_1 = require("./postman-service");
41
43
  const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
42
44
  const uploadOpenAPI = async () => {
45
+ console.info('Uploading Open API documentation to Postman...');
43
46
  const args = process.argv;
44
47
  const params = {};
45
48
  for (let i = 2; i < args.length;) {
46
49
  const key = args[i].replace('--', '');
47
50
  params[key] = args[i + 1];
51
+ if (!params[key]) {
52
+ i++;
53
+ continue;
54
+ }
48
55
  if (params[key].startsWith('--')) {
49
56
  i++;
50
57
  delete params[key];
@@ -61,12 +68,63 @@ const uploadOpenAPI = async () => {
61
68
  if (!params['stack-name']) {
62
69
  throw new Error('Stack name is missing.');
63
70
  }
64
- const postmanService = new postman_service_1.PostmanService(postmanToken);
65
- const stackCollection = (await postmanService.getCollections()).collections.find((x) => x.name === stackName);
66
- if (stackCollection) {
67
- await postmanService.deleteCollection(stackCollection.id);
71
+ const splitStackName = stackName.split('-');
72
+ const environment = splitStackName.pop();
73
+ const partnerName = splitStackName.join('-');
74
+ if (environment !== 'development' && environment !== 'production') {
75
+ throw new Error('Stack name should end with development or production. Example: example-development');
76
+ }
77
+ const postmanService = new postman_service_1.PostmanService(postmanToken, '489fad1b-5992-4ffe-8427-1f82f3ca0661');
78
+ const { collections } = await postmanService.getCollections();
79
+ let collectionID = '';
80
+ const stackCollection = collections.find((x) => x.name === partnerName);
81
+ if (!stackCollection) {
82
+ collectionID = await postmanService.createCollection(partnerName);
68
83
  }
84
+ else {
85
+ collectionID = stackCollection.id;
86
+ }
87
+ const { collection: { item } } = await postmanService.getCollection(collectionID);
88
+ const folder = item.find((x) => x.name === environment);
89
+ if (folder) {
90
+ await postmanService.deleteFolder(collectionID, folder.id);
91
+ }
92
+ await postmanService.createFolder(collectionID, environment);
93
+ const collection = await postmanService.getCollection(collectionID);
69
94
  const existingOpenAPIFile = JSON.parse(await fs_1.promises.readFile(OPENAPI_FILE, 'utf-8'));
70
- await postmanService.createCollection(existingOpenAPIFile);
95
+ const convertPromise = (0, util_1.promisify)(openapi_to_postmanv2_1.convert);
96
+ const converted = await convertPromise({
97
+ data: JSON.stringify(existingOpenAPIFile),
98
+ type: 'json'
99
+ }, {
100
+ folderStrategy: 'Tags'
101
+ });
102
+ if (!converted.result) {
103
+ throw new Error('Failed to convert Open API to Postman collection');
104
+ }
105
+ const convertedData = converted.output[0].data;
106
+ for (const item of collection.collection.item) {
107
+ if (item.name === environment) {
108
+ item.item = convertedData.item ?? [];
109
+ break;
110
+ }
111
+ }
112
+ await postmanService.updateCollection(collectionID, collection);
113
+ const baseUrl = existingOpenAPIFile.servers.find((x) => x.url.includes(environment))?.url;
114
+ if (!baseUrl) {
115
+ console.warn(`Base URL was not found with the given environment. Environment will not be updated. Given environment: ${environment}`);
116
+ return;
117
+ }
118
+ const environments = (await postmanService.getAllEnvironments()).environments;
119
+ const stackEnvironment = environments.find((x) => x.name === stackName);
120
+ if (!stackEnvironment) {
121
+ await postmanService.createEnvironment(stackName, [{ key: 'baseUrl', value: baseUrl }]);
122
+ }
123
+ else {
124
+ await postmanService.updateEnvironment(stackEnvironment.id, stackEnvironment.name, [
125
+ { key: 'baseUrl', value: baseUrl }
126
+ ]);
127
+ }
128
+ console.info('Open API documentation uploaded successfully');
71
129
  };
72
130
  exports.uploadOpenAPI = uploadOpenAPI;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vls-openapi-generator",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "scripts": {
@@ -17,7 +17,8 @@
17
17
  "dependencies": {
18
18
  "@anatine/zod-openapi": "^2.2.7",
19
19
  "axios": "^1.7.9",
20
- "module-alias": "^2.2.3"
20
+ "module-alias": "^2.2.3",
21
+ "openapi-to-postmanv2": "^4.25.0"
21
22
  },
22
23
  "devDependencies": {
23
24
  "@commitlint/config-conventional": "^19.5.0",
@@ -25,6 +26,7 @@
25
26
  "@semantic-release/git": "^10.0.1",
26
27
  "@semantic-release/npm": "^12.0.1",
27
28
  "@types/node": "^20.14.8",
29
+ "@types/openapi-to-postmanv2": "^3.2.4",
28
30
  "commitlint": "^19.5.0",
29
31
  "eslint": "^9.12.0",
30
32
  "husky": "^9.1.6",
@@ -14,6 +14,8 @@ const SCHEMAS_DIR = path.join(process.cwd(), 'dist', 'src', 'schemas');
14
14
  const OUTPUT_FILE = path.join(process.cwd(), 'openapi.json');
15
15
 
16
16
  export const generateOpenAPI = async (): Promise<void> => {
17
+ console.info('Generating Open API documentation...');
18
+
17
19
  const args = process.argv;
18
20
  const params: Record<string, string> = {};
19
21
 
@@ -22,14 +24,14 @@ export const generateOpenAPI = async (): Promise<void> => {
22
24
  params[key] = args[i + 1];
23
25
  }
24
26
 
25
- console.info('Generating Open API documentation...');
26
-
27
27
  await promisify(exec)('rm -rf ./dist');
28
28
  await promisify(exec)('npx tsc');
29
29
 
30
30
  const handlerFiles = await fs.readdir(HANDLERS_DIR);
31
31
  const existingOpenAPIFile = JSON.parse(await fs.readFile(OPENAPI_FILE, 'utf-8')) as OpenAPI;
32
32
 
33
+ existingOpenAPIFile.paths = {};
34
+
33
35
  for (const handler of handlerFiles) {
34
36
  const fileName = path.parse(handler).name;
35
37
 
@@ -114,4 +116,5 @@ export const generateOpenAPI = async (): Promise<void> => {
114
116
  }
115
117
 
116
118
  await fs.writeFile(OUTPUT_FILE, JSON.stringify(existingOpenAPIFile, undefined, 4));
119
+ console.info('Open API documentation generated successfully');
117
120
  };
package/src/index.ts CHANGED
@@ -9,24 +9,12 @@ export * from './lambda-type';
9
9
  try {
10
10
  await generateOpenAPI();
11
11
 
12
- console.info('Open API documentation generated successfully');
12
+ if (process.argv.includes('--upload')) {
13
+ await uploadOpenAPI();
14
+ }
13
15
  } catch (error) {
14
16
  console.error(error);
15
17
 
16
18
  process.exit(1);
17
19
  }
18
-
19
- if (process.argv.includes('--upload')) {
20
- console.info('Uploading Open API documentation to Postman...');
21
-
22
- try {
23
- await uploadOpenAPI();
24
-
25
- console.info('Open API documentation uploaded successfully');
26
- } catch (error) {
27
- console.error(error);
28
-
29
- process.exit(1);
30
- }
31
- }
32
20
  })().catch(console.error);
@@ -1,10 +1,11 @@
1
1
  import axios, { Axios } from 'axios';
2
- import { OpenAPI } from './openapi-type';
3
2
 
4
3
  export class PostmanService {
5
4
  private client: Axios;
5
+ private workspaceID: string;
6
6
 
7
- constructor(apiKey: string) {
7
+ constructor(apiKey: string, workspaceID: string) {
8
+ this.workspaceID = workspaceID;
8
9
  this.client = axios.create({
9
10
  baseURL: 'https://api.getpostman.com',
10
11
  headers: {
@@ -25,14 +26,80 @@ export class PostmanService {
25
26
  ).data;
26
27
  };
27
28
 
28
- public deleteCollection = async (collectionID: string) => {
29
- return await this.client.delete(`/collections/${collectionID}`);
29
+ public getCollection = async (id: string) => {
30
+ return (
31
+ await this.client.get<{
32
+ collection: {
33
+ info: {
34
+ _postman_id: string;
35
+ name: string;
36
+ };
37
+ item: { id: string; name: 'development' | 'production'; item: object[] }[];
38
+ variable: { key: string; value: string }[];
39
+ };
40
+ }>(`/collections/${id}?workspace=${this.workspaceID}`)
41
+ ).data;
42
+ };
43
+
44
+ public createCollection = async (partnerName: string) => {
45
+ return (
46
+ await this.client.post<{
47
+ collection: {
48
+ id: string;
49
+ };
50
+ }>(`/collections?workspace=${this.workspaceID}`, {
51
+ collection: {
52
+ info: {
53
+ name: partnerName,
54
+ schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json'
55
+ },
56
+ item: []
57
+ }
58
+ })
59
+ ).data.collection.id;
30
60
  };
31
61
 
32
- public createCollection = async (payload: OpenAPI) => {
33
- return await this.client.post('/import/openapi', {
34
- type: 'json',
35
- input: payload
62
+ public deleteFolder = async (collectionID: string, folderID: string) => {
63
+ return await this.client.delete(`/collections/${collectionID}/folders/${folderID}`);
64
+ };
65
+
66
+ public createFolder = async (collectionID: string, folderName: string) => {
67
+ return await this.client.post(`/collections/${collectionID}/folders`, {
68
+ name: folderName
69
+ });
70
+ };
71
+
72
+ public updateCollection = async (collectionID: string, collection: object) => {
73
+ return await this.client.put(`/collections/${collectionID}`, collection);
74
+ };
75
+
76
+ public updateVariablesCollection = async (collectionID: string, variables: { key: string; value: string }[]) => {
77
+ return await this.client.patch(`/collections/${collectionID}`, { collection: { variable: variables } });
78
+ };
79
+
80
+ public getAllEnvironments = async () => {
81
+ return (
82
+ await this.client.get<{ environments: { id: string; name: string }[] }>(
83
+ `/environments?workspace=${this.workspaceID}`
84
+ )
85
+ ).data;
86
+ };
87
+
88
+ public createEnvironment = async (name: string, values: { key: string; value: string }[]) => {
89
+ return await this.client.post(`/environments?workspace=${this.workspaceID}`, {
90
+ environment: {
91
+ name,
92
+ values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
93
+ }
94
+ });
95
+ };
96
+
97
+ public updateEnvironment = async (id: string, name: string, values: { key: string; value: string }[]) => {
98
+ return await this.client.put(`/environments/${id}?workspace=${this.workspaceID}`, {
99
+ environment: {
100
+ name,
101
+ values: values.map(({ key, value }) => ({ key, value, enabled: true, type: 'default' }))
102
+ }
36
103
  });
37
104
  };
38
105
  }
@@ -1,12 +1,16 @@
1
1
  import { promises as fs } from 'fs';
2
2
  import 'module-alias/register.js';
3
+ import { convert } from 'openapi-to-postmanv2';
3
4
  import * as path from 'path';
5
+ import { promisify } from 'util';
4
6
  import { OpenAPI } from './openapi-type';
5
7
  import { PostmanService } from './postman-service';
6
8
 
7
9
  const OPENAPI_FILE = path.join(process.cwd(), 'openapi.json');
8
10
 
9
11
  export const uploadOpenAPI = async (): Promise<void> => {
12
+ console.info('Uploading Open API documentation to Postman...');
13
+
10
14
  const args = process.argv;
11
15
  const params: Record<string, string> = {};
12
16
 
@@ -14,6 +18,11 @@ export const uploadOpenAPI = async (): Promise<void> => {
14
18
  const key = args[i].replace('--', '');
15
19
  params[key] = args[i + 1];
16
20
 
21
+ if (!params[key]) {
22
+ i++;
23
+ continue;
24
+ }
25
+
17
26
  if (params[key].startsWith('--')) {
18
27
  i++;
19
28
  delete params[key];
@@ -33,15 +42,92 @@ export const uploadOpenAPI = async (): Promise<void> => {
33
42
  throw new Error('Stack name is missing.');
34
43
  }
35
44
 
36
- const postmanService = new PostmanService(postmanToken);
45
+ const splitStackName = stackName.split('-');
46
+ const environment = splitStackName.pop();
47
+ const partnerName = splitStackName.join('-');
48
+
49
+ if (environment !== 'development' && environment !== 'production') {
50
+ throw new Error('Stack name should end with development or production. Example: example-development');
51
+ }
52
+
53
+ const postmanService = new PostmanService(postmanToken, '489fad1b-5992-4ffe-8427-1f82f3ca0661');
54
+
55
+ const { collections } = await postmanService.getCollections();
56
+
57
+ let collectionID = '';
37
58
 
38
- const stackCollection = (await postmanService.getCollections()).collections.find((x) => x.name === stackName);
59
+ const stackCollection = collections.find((x) => x.name === partnerName);
39
60
 
40
- if (stackCollection) {
41
- await postmanService.deleteCollection(stackCollection.id);
61
+ if (!stackCollection) {
62
+ collectionID = await postmanService.createCollection(partnerName);
63
+ } else {
64
+ collectionID = stackCollection.id;
42
65
  }
43
66
 
67
+ const {
68
+ collection: { item }
69
+ } = await postmanService.getCollection(collectionID);
70
+
71
+ const folder = item.find((x) => x.name === environment);
72
+
73
+ if (folder) {
74
+ await postmanService.deleteFolder(collectionID, folder.id);
75
+ }
76
+
77
+ await postmanService.createFolder(collectionID, environment);
78
+
79
+ const collection = await postmanService.getCollection(collectionID);
80
+
44
81
  const existingOpenAPIFile = JSON.parse(await fs.readFile(OPENAPI_FILE, 'utf-8')) as OpenAPI;
45
82
 
46
- await postmanService.createCollection(existingOpenAPIFile);
83
+ const convertPromise = promisify(convert);
84
+
85
+ const converted = await convertPromise(
86
+ {
87
+ data: JSON.stringify(existingOpenAPIFile),
88
+ type: 'json'
89
+ },
90
+ {
91
+ folderStrategy: 'Tags'
92
+ }
93
+ );
94
+
95
+ if (!converted.result) {
96
+ throw new Error('Failed to convert Open API to Postman collection');
97
+ }
98
+
99
+ const convertedData = converted.output[0].data;
100
+
101
+ for (const item of collection.collection.item) {
102
+ if (item.name === environment) {
103
+ item.item = convertedData.item ?? [];
104
+ break;
105
+ }
106
+ }
107
+
108
+ await postmanService.updateCollection(collectionID, collection);
109
+
110
+ const baseUrl = existingOpenAPIFile.servers.find((x) => x.url.includes(environment))?.url;
111
+
112
+ if (!baseUrl) {
113
+ console.warn(
114
+ `Base URL was not found with the given environment. Environment will not be updated. Given environment: ${environment}`
115
+ );
116
+
117
+ return;
118
+ }
119
+
120
+ const environments = (await postmanService.getAllEnvironments()).environments;
121
+
122
+ const stackEnvironment = environments.find((x) => x.name === stackName);
123
+
124
+ if (!stackEnvironment) {
125
+ await postmanService.createEnvironment(stackName, [{ key: 'baseUrl', value: baseUrl }]);
126
+ } else {
127
+ await postmanService.updateEnvironment(stackEnvironment.id, stackEnvironment.name, [
128
+ { key: 'baseUrl', value: baseUrl }
129
+ ]);
130
+ }
131
+
132
+ console.info('Open API documentation uploaded successfully');
47
133
  };