@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
JavaScript
;
/* 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;