UNPKG

@nimbella/postman-api

Version:

Postman Collection to Nimbella Project: Take your APIs seamlessly into Serverless world with this API

266 lines (265 loc) 13.5 kB
"use strict"; /* eslint-disable no-unused-expressions */ /* eslint-disable no-restricted-syntax */ /* * Copyright (c) 2019 - present Nimbella Corp. * * This file is licensed to you under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. You may obtain a copy * of the License at http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS * OF ANY KIND, either express or implied. See the License for the specific language * governing permissions and limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const fs_1 = require("fs"); const path_1 = require("path"); const chalk_1 = require("chalk"); const postman_collection_1 = require("postman-collection"); const reader_1 = require("./reader"); const stub_gen_1 = require("./generators/stub/stub-gen"); const test_gen_1 = require("./generators/test/test-gen"); const utils_1 = require("./utils"); const fetcher_1 = tslib_1.__importDefault(require("./fetcher")); const syncer_1 = tslib_1.__importDefault(require("./syncer")); const writer_1 = require("./writer"); const proj_gen_1 = tslib_1.__importDefault(require("./generators/proj-gen")); let langExt; let langVariant; let lang; let collectionName; let genInstance; let pm; let workDir; let collectionId; class Generate { constructor(options) { this.validate = async () => { lang = this.language; if (lang.includes(':')) { const langDetail = lang.split(':'); [lang, langVariant] = langDetail; } genInstance = stub_gen_1.getInstance(lang); if (!langVariant) langVariant = genInstance.variant; langExt = genInstance.ext; if (this.key) { const fetcher = new fetcher_1.default(this.key); if (!utils_1.isGuid(collectionId)) { const id = await fetcher.getCollectionGuid(collectionId); collectionId = id; } pm = await fetcher.getCollectionWithVersion(collectionId); } if (!pm.collection) { console.log(`Couldn't read collection ${chalk_1.blue(collectionId)}`); throw new Error(`Couldn't read collection ${collectionId}`); } if (pm.collection && !reader_1.isValid(pm.collection)) { console.log(`${chalk_1.blue(collectionId)} is not a valid Postman collection.`); throw new Error(`${collectionId} is not a valid Postman collection.`); } if (!pm.isVersion2X) { console.log(`${chalk_1.blue(collectionId)} is not in version 2.x format of postman collection. ${chalk_1.green('Attempting with a converted version.')}`); pm.collection = writer_1.upgrade(collectionId); } collectionName = utils_1.sanitizeFileName(pm.collection.name); if (fs_1.existsSync(collectionName) && !(this.overwrite || this.update)) { console.log(`Oops! a directory named ${chalk_1.blue(collectionName)} already exists.`); console.log(`Please move the directory or use ${chalk_1.blue('--overwrite')} to continue...`); console.log(`${chalk_1.red("'--overwrite or -o' will delete the directory.")}`); throw new Error(`Oops! a directory named ${collectionName} already exists.`); } }; this.generateActions = async () => { async function itemGroupOps(itemsOpsArray) { var e_1, _a; try { for (var itemsOpsArray_1 = tslib_1.__asyncValues(itemsOpsArray), itemsOpsArray_1_1; itemsOpsArray_1_1 = await itemsOpsArray_1.next(), !itemsOpsArray_1_1.done;) { const item = itemsOpsArray_1_1.value; item; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (itemsOpsArray_1_1 && !itemsOpsArray_1_1.done && (_a = itemsOpsArray_1.return)) await _a.call(itemsOpsArray_1); } finally { if (e_1) throw e_1.error; } } } const validationScripts = async (item, actionPath, itemName) => { if (item.events && item.events.members) { const validations = item.events.members.filter((i) => i.listen === 'prerequest'); if (validations.length > 0 && validations[0].script.exec) { const methodValidationStub = await stub_gen_1.getMethodValidationStub(test_gen_1.getMethodValidations(validations[0].script.exec)); writer_1.writeOrUpdateFile({ location: path_1.join(workDir, 'packages', actionPath, itemName), name: 'validation', ext: langExt, verbose: true, }, methodValidationStub, this.update); // write global validation const preRequest = validations[0].script.exec.join('/n'); if (preRequest.includes('pm.globals.set')) { const globalValidationStub = await stub_gen_1.getGlobalValidationStub(test_gen_1.getGlobalValidations(validations[0].script.exec)); writer_1.writeOrUpdateFile({ location: path_1.join(workDir, 'lib'), name: 'validations', ext: langExt, verbose: true, }, globalValidationStub, this.update); } if (preRequest.includes('pm.environment.set')) { writer_1.appendEnvFile(workDir, test_gen_1.getEnvVars(undefined, validations[0].script.exec)); } } } }; const testScripts = async (item, response, request) => { let testArray = item.events.members.filter((i) => i.listen === 'test'); let testSuite; if (!response || (response.code >= 200 && response.code < 300)) testSuite = test_gen_1.getSuccessSuite(request, response, pm.collection.variables); else testSuite = test_gen_1.getFailureSuite(); testSuite = testSuite.replace(/\n/g, '').split('*#!'); if (testArray.length > 0) { testArray[0].script.exec = testArray[0].script.exec.concat(testSuite); } else { testArray = [{ script: { exec: [] } }]; testArray[0].script.exec = testSuite; } }; const getURL = async (actionPath, isWebAction = false) => { // const namespace = '-' if (isWebAction) return `https://apigcp.nimbella.io/api/v1/web/${this.targetNamespace}/${actionPath}`; return `https://${this.targetNamespace}-apigcp.nimbella.io/api/${actionPath}`; }; const updateURL = async (item, modifiedUrl) => { if (item.request.url.variables && item.request.url.variables.members.length > 0) { modifiedUrl += `/${item.request.url.variables.members .map((q) => `:${q.key}`) .join('/')}`; } if (item.request.url.query && item.request.url.query.members.length > 0) { modifiedUrl += `?${item.request.url.query.members .map((q) => `${q.key}=${q.value}`) .join('&')}`; } item.request.url = new URL(modifiedUrl); for (const res of item.responses.members) { res.originalRequest.url = item.request.url; } return modifiedUrl; }; const itemOps = async (item) => { if (postman_collection_1.ItemGroup.isItemGroup(item)) { const itemsOpsArray = item.items.map(itemOps); itemGroupOps(itemsOpsArray); return; } const actionPath = utils_1.sanitizeFileName(item.parent().name); const itemName = utils_1.sanitizeFileName(item.name); // write root level actions in project.yml if (actionPath === collectionName) { this.projectGenerator.updateProjectYML(workDir, ` - name: ${itemName}\n`); } // create nimbella project if (!utils_1.isPublicApi(item.request.url.toString())) { const methodStub = await stub_gen_1.getMethodStub(item); writer_1.writeOrUpdateFile({ location: path_1.join(workDir, 'packages', actionPath, itemName), name: 'index', ext: langExt, verbose: true, }, methodStub, this.update); const originalUrl = item.request.url.toString(); let modifiedUrl = originalUrl; modifiedUrl = await getURL(`${actionPath}/${itemName}`); if (originalUrl !== modifiedUrl) { modifiedUrl = updateURL(item, modifiedUrl); } } const testStub = await stub_gen_1.getTestStub(item, workDir); writer_1.writeOrUpdateFile({ location: path_1.join(workDir, 'test', actionPath), name: `${itemName}.test`, ext: langExt, verbose: true, }, testStub, this.update); const { request } = item; const [response] = item.responses.members; // test generation await validationScripts(item, actionPath, itemName); await testScripts(item, response, request); }; const itemsOpsArray = pm.collection.items.map(itemOps, undefined); return itemGroupOps(itemsOpsArray); }; this.generatePackages = async () => { workDir = this.projectGenerator.generateSkeleton({ base: process.cwd(), dir: collectionName, collection: pm.collection, update: this.update, generator: genInstance.generator, }); let actionCount = 0; pm.collection.forEachItemGroup(async (itemGroup) => { // iteratively update project.yml const members = itemGroup.items.members; if (members.length > 0 && Object.prototype.hasOwnProperty.call(members[0], 'request')) { const groupName = utils_1.sanitizeFileName(itemGroup.name); this.projectGenerator.updateProjectYML(workDir, `\n - name: ${groupName}\n actions:\n`); itemGroup.forEachItem(async (item) => { actionCount += 1; if (!utils_1.isPublicApi(item.request.url.toString())) this.projectGenerator.updateProjectYML(workDir, ` - name: ${utils_1.sanitizeFileName(item.name)}\n`); }); } }); // write header and create package for root level actions, if there are any if (pm.collection.items.count() > actionCount) { this.projectGenerator.updateProjectYML(workDir, `\n - name: ${collectionName}\n actions:\n`); } }; this.generate = async () => { try { collectionId = this.id || ''; await this.validate(); await this.generatePackages(); await this.generateActions(); await writer_1.saveCollection(path_1.join(workDir, `${collectionName}.postman_collection.json`), pm.collection); if (this.key && this.updateSource) { await new syncer_1.default(this.key || '').updateCollection(collectionId, pm); } } catch (error) { console.error(error); console.log("Couldn't complete the process, some error occurred. Please try again!"); } }; this.id = options.id; this.key = options.key; this.language = options.language; this.overwrite = options.overwrite; this.update = options.update; this.init = options.init; this.deploy = options.deploy; this.deployForce = options.deployForce; this.updateSource = options.updateSource; this.clientCode = options.clientCode; this.targetNamespace = options.targetNamespace; this.projectGenerator = new proj_gen_1.default(); } } exports.default = Generate;