UNPKG

zzapi

Version:

zzAPI is a REST API testing and documentation tool set. It is an open-source Postman alternative.

1,451 lines (1,437 loc) 48.6 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var __async = (__this, __arguments, generator) => { return new Promise((resolve2, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve2(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; // src/index.ts var index_exports = {}; __export(index_exports, { VarStore: () => VarStore, captureVariables: () => captureVariables, constructGotRequest: () => constructGotRequest, convertCollection: () => convertCollection, convertEnvironment: () => convertEnvironment, executeGotRequest: () => executeGotRequest, getAllRequestSpecs: () => getAllRequestSpecs, getCurlRequest: () => getCurlRequest, getEnvironments: () => getEnvironments, getRequestPositions: () => getRequestPositions, getRequestSpec: () => getRequestSpec, loadVariables: () => loadVariables, replaceVariablesInRequest: () => replaceVariablesInRequest, runAllTests: () => runAllTests }); module.exports = __toCommonJS(index_exports); // src/parseBundle.ts var YAML = __toESM(require("yaml")); // src/utils/typeUtils.ts function isArrayOrDict(obj) { return typeof obj == "object" && !(obj instanceof Date) && obj !== null; } function isDict(obj) { return isArrayOrDict(obj) && !Array.isArray(obj); } function getDescriptiveType(obj) { if (obj === null) return "null"; if (Array.isArray(obj)) return "array"; if (obj instanceof Date) return "instanceof Date"; if (typeof obj === "object") return "dict"; return typeof obj; } function getStringIfNotScalar(data) { if (typeof data !== "object") return data; return JSON.stringify(data); } function getStringValueIfDefined(value) { if (typeof value === "undefined") return void 0; if (typeof value === "object") return JSON.stringify(value); return value.toString(); } function getStrictStringValue(value) { if (typeof value === "undefined") return "undefined"; return getStringValueIfDefined(value); } function isString(value) { return typeof value === "string" || value instanceof String; } function isFilePath(value) { if (!isString(value)) { return false; } const fileRegex = /file:\/\/([^\s]+)/g; return fileRegex.test(value); } function hasFile(formValues) { if (!formValues) { return false; } for (const formValue of formValues) { if (isFilePath(formValue.value)) { return true; } } return false; } // src/mergeData.ts function paramObjectToArray(params) { const paramArray = []; Object.entries(params).forEach(([name, value]) => { if (Array.isArray(value)) { value.forEach((v) => { paramArray.push({ name, value: v }); }); } else { paramArray.push({ name, value }); } }); return paramArray; } function getMergedParams(commonParams, requestParams) { let mixedParams = []; if (commonParams) { if (Array.isArray(commonParams)) { mixedParams = mixedParams.concat(commonParams); } else { mixedParams = mixedParams.concat(paramObjectToArray(commonParams)); } } if (requestParams) { if (Array.isArray(requestParams)) { mixedParams = mixedParams.concat(requestParams); } else { mixedParams = mixedParams.concat(paramObjectToArray(requestParams)); } } return mixedParams; } function getMergedHeaders(commonHeaders, requestHeaders) { if (Array.isArray(commonHeaders)) { commonHeaders = getArrayHeadersAsObject(commonHeaders); } if (Array.isArray(requestHeaders)) { requestHeaders = getArrayHeadersAsObject(requestHeaders); } commonHeaders = withLowerCaseKeys(commonHeaders); requestHeaders = withLowerCaseKeys(requestHeaders); return Object.assign({}, commonHeaders, requestHeaders); } function getMergedOptions(cOptions = {}, rOptions = {}) { const options = Object.assign(cOptions, rOptions); const follow = options.follow === true; const verifySSL = options.verifySSL === true; const keepRawJSON = options.keepRawJSON === true; const showHeaders = options.showHeaders === true; const rawParams = options.rawParams === true; const stopOnFailure = options.stopOnFailure === true; return { follow, verifySSL, keepRawJSON, showHeaders, rawParams, stopOnFailure }; } function getMergedSetVars(setvars = {}, captures = {}) { const mergedVars = []; let hasJsonVars = false; if (captures.body) { mergedVars.push({ varName: captures.body, type: "body", spec: "" }); } if (captures.status) { mergedVars.push({ varName: captures.status, type: "status", spec: "" }); } if (captures.headers) { for (const header in captures.headers) { mergedVars.push({ varName: captures.headers[header], type: "header", spec: header }); } } if (captures.json) { for (const path3 in captures.json) { hasJsonVars = true; mergedVars.push({ varName: captures.json[path3], type: "json", spec: path3 }); } } for (const varName in setvars) { let spec = setvars[varName]; let type; if (spec.startsWith("$.")) { type = "json"; hasJsonVars = true; } else if (spec.startsWith("$h.")) { type = "header"; spec = spec.replace(/^\$h\./, ""); } else if (spec === "status" || spec === "body") { type = spec; } else { continue; } mergedVars.push({ varName, type, spec }); } return { mergedVars, hasJsonVars }; } function mergePrefixBasedTests(tests2) { if (!tests2.json) tests2.json = {}; if (!tests2.headers) tests2.headers = {}; for (const key of Object.keys(tests2)) { if (key.startsWith("$.")) { tests2.json[key] = tests2[key]; delete tests2[key]; } else if (key.startsWith("$h.")) { const headerName = key.replace(/^\$h\./, ""); tests2.headers[headerName] = tests2[key]; delete tests2[key]; } } } function getMergedTests(cTests = {}, rTests = {}) { mergePrefixBasedTests(cTests); mergePrefixBasedTests(rTests); cTests.headers = withLowerCaseKeys(cTests.headers); rTests.headers = withLowerCaseKeys(rTests.headers); let mergedData = { status: rTests.status || cTests.status, body: rTests.body || cTests.body, headers: Object.assign({}, cTests.headers, rTests.headers), json: Object.assign({}, cTests.json, rTests.json) }; return { mergedTests: mergedData, hasJsonTests: Object.keys(mergedData.json).length > 0 }; } function getArrayHeadersAsObject(objectSet) { if (!objectSet) return {}; let finalObject = {}; objectSet.forEach((currObj) => { const key = currObj.name; const value = currObj.value; finalObject[key] = value; }); return finalObject; } function withLowerCaseKeys(obj) { if (!obj) return {}; let newObj = {}; for (const key in obj) { newObj[key.toLowerCase()] = obj[key]; } return newObj; } function getMergedData(commonData, requestData) { const name = requestData.name; const method = requestData.method; const params = getMergedParams(commonData.params, requestData.params); const headers = getMergedHeaders(commonData.headers, requestData.headers); const body = requestData.body; const formValues = getMergedParams([], requestData.formValues); const options = getMergedOptions(commonData.options, requestData.options); const { mergedTests: tests2, hasJsonTests } = getMergedTests( commonData == null ? void 0 : commonData.tests, requestData.tests ); const { mergedVars: setvars, hasJsonVars } = getMergedSetVars( requestData.setvars, requestData.capture ); const mergedData = { name, httpRequest: { baseUrl: commonData == null ? void 0 : commonData.baseUrl, url: requestData.url, method, params, headers, body, formValues: formValues.length > 0 ? formValues : void 0 }, options, tests: tests2, setvars, expectJson: hasJsonTests || hasJsonVars }; return mergedData; } // src/checkTypes.ts function checkKey(obj, item, key, expectedTypes, optional) { if (!optional && !obj.hasOwnProperty(key)) { return `${key} key must be present in each ${item} item`; } else if (obj.hasOwnProperty(key)) { if (!expectedTypes.some((type) => type === "null" && obj[key] === null || typeof obj[key] === type)) { return `${key} of ${item} must have one of ${expectedTypes} value, found ${typeof obj[key]}`; } } return void 0; } function checkObjIsDict(obj, item) { if (!isDict(obj)) { return `${item} item must be a dict: found ${getDescriptiveType(obj)}`; } else { return void 0; } } function checkHeaderItem(obj) { let ret = checkObjIsDict(obj, "header"); if (ret !== void 0) return ret; ret = checkKey(obj, "header", "name", ["string"], false); if (ret !== void 0) return ret; ret = checkKey(obj, "header", "value", ["string", "number", "boolean", "null"], false); if (ret !== void 0) return ret; return void 0; } function checkParamItem(obj) { let ret = checkObjIsDict(obj, "param"); if (ret !== void 0) return ret; ret = checkKey(obj, "param", "name", ["string"], true); if (ret !== void 0) return ret; return void 0; } function checkHeadersParamsOptionsTestsCaptures(obj) { if (obj.hasOwnProperty("headers")) { const headers = obj.headers; if (!isArrayOrDict(headers)) { return `Headers must be an array or a dictionary: found ${typeof headers}`; } if (Array.isArray(headers)) { for (const header of headers) { const headerError = checkHeaderItem(header); if (headerError !== void 0) { return `error in header item ${getStrictStringValue(header)}: ${headerError}`; } } } else { for (const header in headers) { const headerError = checkHeaderItem({ name: header, value: headers[header] }); if (headerError !== void 0) { return `error in header item ${getStrictStringValue(header)}: ${headerError}`; } } } } if (obj.hasOwnProperty("params")) { const params = obj.params; if (!isArrayOrDict(params)) { return `Params must be an array or a dictionary: found ${typeof params}`; } if (Array.isArray(params)) { for (const param of params) { const paramError = checkParamItem(param); if (paramError !== void 0) { return `error in param item ${getStrictStringValue(param)}: ${paramError}`; } } } } if (obj.hasOwnProperty("options")) { const optionsError = checkOptions(obj.options); if (optionsError !== void 0) return `error in options: ${optionsError}`; } if (obj.hasOwnProperty("tests")) { const testsError = checkTests(obj.tests); if (testsError !== void 0) return `error in tests: ${testsError}`; } if (obj.hasOwnProperty("capture")) { const capturesError = checkCaptures(obj.capture); if (capturesError !== void 0) return `error in captures: ${capturesError}`; } return void 0; } function checkTests(obj) { let ret = checkObjIsDict(obj, "tests"); if (ret !== void 0) return ret; if (obj.hasOwnProperty("json")) { ret = checkObjIsDict(obj.json, "JSON tests"); if (ret !== void 0) return ret; } if (obj.hasOwnProperty("body") && !(isDict(obj.body) || typeof obj.body === "string")) { return `body tests item must be a dict or string: found ${getDescriptiveType(obj.body)}`; } if (obj.hasOwnProperty("status") && !(isDict(obj.status) || typeof obj.status === "number")) { return `status tests item must be a dict or number: found ${getDescriptiveType(obj.status)}`; } if (obj.hasOwnProperty("headers")) { ret = checkObjIsDict(obj.headers, "header tests"); if (ret !== void 0) return ret; } return void 0; } function checkCaptures(obj) { let ret = checkObjIsDict(obj, "captures"); if (ret !== void 0) return ret; if (obj.hasOwnProperty("json")) { ret = checkObjIsDict(obj.json, "JSON captures"); return ret; } ret = checkKey(obj, "captures", "body", ["string"], true); if (ret !== void 0) return ret; ret = checkKey(obj, "captures", "status", ["string"], true); if (ret !== void 0) return ret; if (obj.hasOwnProperty("headers")) { ret = checkObjIsDict(obj.headers, "header captures"); if (ret !== void 0) return ret; } return void 0; } var VALID_OPTIONS = { follow: true, verifySSL: true, keepRawJSON: true, showHeaders: true, rawParams: true, stopOnFailure: true }; function checkOptions(obj) { let ret = checkObjIsDict(obj, "options"); if (ret !== void 0) return ret; for (const key in obj) { if (VALID_OPTIONS[key]) { ret = checkKey(obj, "options", key, ["boolean"], true); if (ret !== void 0) return ret; } else { return `options must be among ${Object.keys(VALID_OPTIONS)}: found ${key}`; } } return void 0; } function checkCommonType(obj) { let ret = checkObjIsDict(obj, "common"); if (ret !== void 0) return ret; ret = checkKey(obj, "common", "baseUrl", ["string"], true); if (ret !== void 0) return ret; ret = checkHeadersParamsOptionsTestsCaptures(obj); if (ret !== void 0) return ret; return void 0; } var VALID_METHODS = { options: true, get: true, post: true, put: true, patch: true, head: true, delete: true, trace: true }; function validateRawRequest(obj) { let ret = checkObjIsDict(obj, "request"); if (ret !== void 0) return ret; ret = checkHeadersParamsOptionsTestsCaptures(obj); if (ret !== void 0) return ret; ret = checkKey(obj, "request", "url", ["string"], false); if (ret !== void 0) return ret; if (!obj.hasOwnProperty("method")) { return `method key must be present in each request item`; } else { if (typeof obj.method !== "string") { return `value of method key must be a string`; } else { const methodToPass = obj.method.toLowerCase(); if (!VALID_METHODS[methodToPass]) return `method key must have value among ${Object.keys(VALID_METHODS)}: found ${methodToPass}`; } } if (obj.hasOwnProperty("formValues") && obj.hasOwnProperty("body")) { return `both body and formValues can't be present in the same request.`; } if (obj.hasOwnProperty("method") && obj["method"] == "GET" && obj.hasOwnProperty("formValues")) { return `formValues can't be used with method GET`; } if (obj.hasOwnProperty("method") && obj["method"] == "GET" && obj.hasOwnProperty("body")) { return `body can't be used with method GET`; } return void 0; } function checkVariables(obj) { let ret = checkObjIsDict(obj, "variables"); if (ret !== void 0) return ret; for (const key in obj) { if (typeof key !== "string") return `Environment names must be a string: ${key} is not a string`; const variables = obj[key]; ret = checkObjIsDict(obj, `variables environment ${key}`); if (ret !== void 0) return ret; for (const varName in variables) { if (typeof varName !== "string") { return `variable name ${varName} in env ${key} is not a string`; } } } return void 0; } // src/parseBundle.ts var VALID_KEYS = { requests: true, common: true, variables: true }; function getRawRequests(doc) { let parsedData = YAML.parse(doc); if (!isDict(parsedData)) { throw new Error("Bundle could not be parsed. Is your bundle a valid YAML document?"); } for (const key in parsedData) { if (!VALID_KEYS[key]) { throw new Error(`Invalid key: ${key} in bundle. Only ${Object.keys(VALID_KEYS)} are allowed.`); } } let commonData = parsedData.common; if (commonData !== void 0) { const error = checkCommonType(commonData); if (error !== void 0) throw new Error(`error in common: ${error}`); } else { commonData = {}; } const allRequests = parsedData.requests; if (!isDict(allRequests)) { throw new Error("requests must be a dictionary in the bundle."); } return { rawRequests: allRequests, commonData }; } function checkAndMergeRequest(commonData, allRequests, name) { let request = allRequests[name]; if (request === void 0) throw new Error(`Request ${name} is not defined in this bundle`); request.name = name; const error = validateRawRequest(request); if (error !== void 0) throw new Error(`error in request '${name}': ${error}`); return getMergedData(commonData, request); } function getRequestPositions(document) { let positions = []; const lineCounter = new YAML.LineCounter(); let doc = YAML.parseDocument(document, { lineCounter }); if (!YAML.isMap(doc.contents)) { return positions; } let contents = doc.contents; function getPosition(key, name) { var _a, _b; const start = (_a = key.range) == null ? void 0 : _a[0]; const end = (_b = key.range) == null ? void 0 : _b[1]; const pos = { name, start: lineCounter.linePos(start), end: lineCounter.linePos(end) }; return pos; } contents.items.forEach((topLevelItem) => { if (!YAML.isMap(topLevelItem.value)) { return; } let key = topLevelItem.key; if (key.value !== "requests") { return; } positions.push(getPosition(key)); let requests = topLevelItem.value; requests.items.forEach((request) => { if (!YAML.isMap(request.value)) { return; } let key2 = request.key; const name = key2.value; positions.push(getPosition(key2, name)); }); }); return positions; } function getAllRequestSpecs(document) { const { rawRequests: allRequests, commonData } = getRawRequests(document); const requests = {}; for (const name in allRequests) { requests[name] = checkAndMergeRequest(commonData, allRequests, name); } return requests; } function getRequestSpec(document, name) { const { rawRequests: allRequests, commonData } = getRawRequests(document); return checkAndMergeRequest(commonData, allRequests, name); } // src/variables.ts var VarStore = class { constructor() { this.loadedVariables = {}; this.capturedVariables = {}; } getLoadedVariables() { return this.loadedVariables; } setLoadedVariables(vars) { this.loadedVariables = vars; } resetLoadedVariables(vars) { this.setLoadedVariables({}); } mergeLoadedVariables(vars) { Object.assign(this.loadedVariables, vars); } getCapturedVariables() { return this.capturedVariables; } setCapturedVariables(vars) { this.capturedVariables = vars; } resetCapturedVariables() { this.setCapturedVariables({}); } mergeCapturedVariables(vars) { Object.assign(this.capturedVariables, vars); } getAllVariables() { return Object.assign({}, this.loadedVariables, this.capturedVariables); } }; // src/variableParser.ts var YAML2 = __toESM(require("yaml")); function getBundleVariables(doc) { let parsedData = doc ? YAML2.parse(doc) : {}; if (!isDict(parsedData)) { throw new Error("Bundle could not be parsed. Is your bundle a valid YAML document?"); } const variables = parsedData.variables; if (variables !== void 0) { const error = checkVariables(variables); if (error !== void 0) throw new Error(`error in variables: ${error}`); return variables; } else { return {}; } } function getEnvironments(bundleContent, varFileContents) { const bundleEnvNames = Object.keys(getBundleVariables(bundleContent)); const fileEnvNames = []; varFileContents.forEach((fileContent) => { const envs = YAML2.parse(fileContent); if (isDict(envs)) { fileEnvNames.push(...Object.keys(envs)); } }); const uniqueNames = /* @__PURE__ */ new Set([...bundleEnvNames, ...fileEnvNames]); return [...uniqueNames]; } function replaceEnvironmentVariables(vars) { const PREFIX = "$env."; const getVal = (val) => { if (typeof val !== "string" || !val.startsWith(PREFIX)) return val; const envVarName = val.slice(PREFIX.length); return envVarName in process.env ? process.env[envVarName] : val; }; const replacedVars = {}; for (const key in vars) replacedVars[key] = getVal(vars[key]); return replacedVars; } function loadVariables(envName, bundleContent, varFileContents) { var _a; if (!envName) return {}; const allBundleVariables = getBundleVariables(bundleContent); const bundleVars = (_a = allBundleVariables[envName]) != null ? _a : {}; const envVars = {}; varFileContents.forEach((fileContents) => { const parsedData = YAML2.parse(fileContents); if (parsedData && isDict(parsedData[envName])) Object.assign(envVars, parsedData[envName]); }); const basicVars = Object.assign({}, envVars, bundleVars); const vars = replaceEnvironmentVariables(basicVars); return vars; } // src/replaceVars.ts function replaceVariablesInArray(data, variables) { let newData = []; let undefs = []; data.forEach((item) => { const { data: newItem, undefinedVars: newUndefs } = replaceVariables(item, variables); newData.push(newItem); undefs.push(...newUndefs); }); return { data: newData, undefinedVars: undefs }; } function replaceVariablesInDict(obj, variables) { let newData = {}; let undefs = []; for (const key in obj) { const { data: newItem, undefinedVars: newUndefs } = replaceVariables(obj[key], variables); newData[key] = newItem; undefs.push(...newUndefs); } return { data: newData, undefinedVars: undefs }; } function replaceVariablesInObject(data, variables) { if (Array.isArray(data)) { return replaceVariablesInArray(data, variables); } else { return replaceVariablesInDict(data, variables); } } var VAR_REGEX_WITH_BRACES = new RegExp("(?<!\\\\)\\$\\(([_a-zA-Z]\\w*)\\)", "g"); var VAR_REGEX_WITHOUT_BRACES = new RegExp("(?<!\\\\)\\$([_a-zA-Z]\\w*)(?=\\W|$)", "g"); function replaceVariablesInString(text, variables) { let valueInNativeType; let variableIsFullText = false; const undefs = []; function replaceVar(match, varName) { if (typeof varName === "string") { if (variables.hasOwnProperty(varName)) { const varVal = variables[varName]; if (text === match) { variableIsFullText = true; valueInNativeType = varVal; } return getStrictStringValue(varVal); } else { undefs.push(varName); } } return match; } const outputText = text.replace(VAR_REGEX_WITH_BRACES, (match, varName) => { return replaceVar(match, varName); }).replace(VAR_REGEX_WITHOUT_BRACES, (match) => { if (match.length <= 1) return match; const varName = match.slice(1); return replaceVar(match, varName); }); if (variableIsFullText) { return { data: valueInNativeType, undefinedVars: undefs }; } else { return { data: outputText, undefinedVars: undefs }; } } function replaceVariables(data, variables) { if (isArrayOrDict(data)) { return replaceVariablesInObject(data, variables); } else if (typeof data === "string") { return replaceVariablesInString(data, variables); } else { return { data, undefinedVars: [] }; } } function replaceVariablesInRequest(request, variables) { const undefs = []; const httpPropertiesToReplace = ["baseUrl", "url", "params", "headers", "body"]; httpPropertiesToReplace.forEach((prop) => { const httpKey = prop; const replacedData2 = replaceVariables(request.httpRequest[httpKey], variables); request.httpRequest[httpKey] = replacedData2.data; undefs.push(...replacedData2.undefinedVars); }); const replacedData = replaceVariables(request.tests, variables); request.tests = replacedData.data; undefs.push(...replacedData.undefinedVars); return undefs; } // src/executeRequest.ts var import_got = __toESM(require("got")); var import_file_from_path = require("formdata-node/file-from-path"); var import_form_data_encoder = require("form-data-encoder"); var import_formdata_node = require("formdata-node"); var import_stream = require("stream"); var path = __toESM(require("path")); function constructGotRequest(allData, workingDir) { const completeUrl = getURL( allData.httpRequest.baseUrl, allData.httpRequest.url, getParamsForUrl(allData.httpRequest.params, allData.options.rawParams) ); const options = { method: allData.httpRequest.method.toLowerCase(), body: getBody(allData, workingDir), headers: allData.httpRequest.headers, followRedirect: allData.options.follow, https: { rejectUnauthorized: allData.options.verifySSL }, retry: { limit: 0 } }; return (0, import_got.default)(completeUrl, options); } function getFileFromPath(filePath, workingDir) { if (workingDir) { filePath = path.resolve(workingDir, filePath.slice(7)); } else { filePath = path.resolve(filePath.slice(7)); } const fileName = path.basename(filePath); return (0, import_file_from_path.fileFromPathSync)(filePath, fileName); } function constructFormUrlEncoded(request) { const formValues = request.httpRequest.formValues; if (!formValues) return ""; const result = new URLSearchParams(); if (formValues) { request.httpRequest.headers["content-type"] = "application/x-www-form-urlencoded"; } for (const { name, value } of formValues) { result.append(name, value); } return result.toString(); } function constructFormData(request, workingDir) { const formValues = request.httpRequest.formValues; if (!formValues) return; const multipart = new import_formdata_node.FormData(); for (const fv of formValues) { if (isFilePath(fv.value)) { multipart.append(fv.name, getFileFromPath(fv.value, workingDir)); } else { multipart.append(fv.name, fv.value); } } const fde = new import_form_data_encoder.FormDataEncoder(multipart); request.httpRequest.headers["content-type"] = fde.contentType; return import_stream.Readable.from(fde); } function getBody(request, workingDir) { const body = request.httpRequest.body; const formValues = request.httpRequest.formValues; if (request.httpRequest.headers["content-type"] == "multipart/form-data" || hasFile(formValues)) { return constructFormData(request, workingDir); } if (formValues) { return constructFormUrlEncoded(request); } return getStringValueIfDefined(body); } function executeGotRequest(httpRequest) { return __async(this, null, function* () { const startTime = (/* @__PURE__ */ new Date()).getTime(); let responseObject; let size = 0; let error = ""; try { responseObject = yield httpRequest; size = Buffer.byteLength(responseObject.rawBody); } catch (e) { const res = e.response; if (res) { responseObject = res; size = res.body ? Buffer.byteLength(res.body) : 0; } else { responseObject = {}; if (e.code === "ERR_INVALID_URL") { error = `Invalid URL: ${e.input}`; } else if (e.name === "CancelError") { error = "Cancelled"; } else { error = e.message || e.code; } } } const executionTime = (/* @__PURE__ */ new Date()).getTime() - startTime; return { response: responseObject, executionTime, byteLength: size, error }; }); } function getParamsForUrl(params, rawParams) { if (!params || params.length < 1) return ""; let paramArray = []; params.forEach((param) => { const key = param.name; let value = param.value; if (value == void 0) { paramArray.push(key); } else if (rawParams) { paramArray.push(`${key}=${getStringValueIfDefined(value)}`); } else { paramArray.push(`${key}=${encodeURIComponent(getStringValueIfDefined(value))}`); } }); const paramString = paramArray.join("&"); return `?${paramString}`; } function getURL(baseUrl, url, paramsForUrl) { if (!baseUrl || !url.startsWith("/")) return url + paramsForUrl; return baseUrl + url + paramsForUrl; } // src/constructCurl.ts var import_path = __toESM(require("path")); function replaceSingleQuotes(value) { if (typeof value !== "string") return value; return value.replace(/'/g, "%27"); } function formatCurlFormField(key, value, workingDir) { if (isFilePath(value)) { return ` --form ${key}=@"${import_path.default.resolve(workingDir || "", value.slice(7))}"`; } return ` --form '${key}="${encodeURIComponent(value)}"'`; } function getFormDataUrlEncoded(request) { const formValues = request.httpRequest.formValues; if (!formValues) return ""; let result = ""; formValues.forEach((formValue) => { result += ` --data "${formValue.name}=${encodeURIComponent(formValue.value)}"`; }); return result; } function getFormDataCurlRequest(request, workingDir) { const formValues = request.httpRequest.formValues; if (!formValues) return ""; let result = ""; for (const { name, value } of formValues) { result += formatCurlFormField(name, value, workingDir); } return result; } function getCurlRequest(request, workingDir) { let curl = "curl"; if (request.httpRequest.headers["content-type"] == "multipart/form-data" || hasFile(request.httpRequest.formValues)) { curl += getFormDataCurlRequest(request, workingDir); curl += ` '${replaceSingleQuotes( getURL( request.httpRequest.baseUrl, request.httpRequest.url, getParamsForUrl(request.httpRequest.params, request.options.rawParams) ) )}'`; return curl; } else if (request.httpRequest.headers["content-type"] == "application/x-www-form-urlencoded" || request.httpRequest.formValues) { curl += getFormDataUrlEncoded(request); curl += ` '${replaceSingleQuotes( getURL( request.httpRequest.baseUrl, request.httpRequest.url, getParamsForUrl(request.httpRequest.params, request.options.rawParams) ) )}'`; return curl; } curl += ` -X ${request.httpRequest.method.toUpperCase()}`; if (request.httpRequest.headers !== void 0) { for (const header in request.httpRequest.headers) { curl += ` -H '${replaceSingleQuotes(`${header}: ${request.httpRequest.headers[header]}`)}'`; } } if (request.httpRequest.body !== void 0) { curl += ` -d '${replaceSingleQuotes(getStringValueIfDefined(request.httpRequest.body))}'`; } if (request.options.follow) curl += " -L"; if (!request.options.verifySSL) curl += " -k"; if (request.options.showHeaders) curl += " -i"; curl += ` '${replaceSingleQuotes( getURL( request.httpRequest.baseUrl, request.httpRequest.url, getParamsForUrl(request.httpRequest.params, request.options.rawParams) ) )}'`; return curl; } // src/runTests.ts var import_jsonpath = __toESM(require("jsonpath")); var SKIP_CLAUSE = "$skip"; var OPTIONS_CLAUSE = "$options"; var MULTI_CLAUSE = "$multi"; function hasFailure(res) { return res.results.some((r) => !r.pass) || res.subResults.some(hasFailure); } function runAllTests(tests2, responseData, stopOnFailure, rootSpec = null, skip) { const res = { spec: rootSpec, results: [], subResults: [] }; if (!tests2) return res; if (tests2.status) { const expected = tests2.status; const received = responseData.status; const statusResults = runTest("status", expected, received, skip); res.subResults.push(statusResults); } if (stopOnFailure && hasFailure(res)) return res; for (const spec in tests2.headers) { const expected = tests2.headers[spec]; const received = responseData.headers ? responseData.headers[spec] : ""; const headerResults = runTest(spec, expected, received, skip); res.subResults.push(headerResults); } res.subResults.push(...runJsonTests(tests2.json, responseData.json, skip)); if (tests2.body) { const expected = tests2.body; const received = responseData.body; const bodyResults = runTest("body", expected, received, skip); res.subResults.push(bodyResults); } return res; } function runJsonTests(tests2, jsonData, skip) { const results = []; for (const spec in tests2) { const expected = tests2[spec]; let received; try { received = getValueForJSONTests( jsonData, spec, typeof expected === "object" && expected !== null && expected[MULTI_CLAUSE] ); } catch (err) { results.push({ spec, skipped: skip || typeof expected === "object" && expected !== null && expected[SKIP_CLAUSE], results: [{ pass: false, expected, received: "", op: spec, message: err }], subResults: [] }); continue; } const jsonResults = runTest(spec, expected, received, skip); results.push(jsonResults); } return results; } function runTest(spec, expected, received, skip) { if (expected !== null && typeof expected === "object") return runObjectTests(expected, received, spec, skip); expected = getStringIfNotScalar(expected); received = getStringIfNotScalar(received); const pass = expected === received; return { spec, skipped: skip, results: [{ pass, expected, received, op: ":" }], subResults: [] }; } function getValueForJSONTests(responseContent, key, multi) { try { return multi ? import_jsonpath.default.query(responseContent, key) : import_jsonpath.default.value(responseContent, key); } catch (err) { throw new Error(`Error while evaluating JSONPath ${key}: ${err.description || err.message || err}`); } } function getType(data) { if (data === null) return "null"; if (Array.isArray(data)) return "array"; return typeof data; } var tests = { $eq: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received === expected, expected, received, op }] }; }, $ne: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received !== expected, expected, received, op }] }; }, $gt: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received > expected, expected, received, op }] }; }, $lt: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received < expected, expected, received, op }] }; }, $lte: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received <= expected, expected, received, op }] }; }, $gte: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: received >= expected, expected, received, op }] }; }, $size: function(expectedObj, receivedObj, spec, op, options) { const res = { spec, results: [], subResults: [] }; const receivedLen = typeof receivedObj === "object" && receivedObj !== null ? Object.keys(receivedObj).length : typeof receivedObj === "string" || Array.isArray(receivedObj) ? receivedObj.length : void 0; const received = getStringIfNotScalar(receivedObj); const expected = getStringIfNotScalar(expectedObj); if (typeof expectedObj === "number") { const compResult2 = { pass: expected === receivedLen, op, expected, received: `(length: ${receivedLen}) -> ${received}` }; res.results.push(compResult2); return res; } if (isDict(expectedObj)) { const compRes = runObjectTests(expectedObj, receivedLen, spec); res.results.push(...compRes.results); res.subResults.push(...compRes.subResults); return res; } const compResult = { pass: false, op, expected, received, message: "value for $size is not a number or valid JSON" }; res.results.push(compResult); return res; }, $exists: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); const exists = received !== void 0; return { spec, subResults: [], results: [{ pass: exists === expected, expected, received, op }] }; }, $type: function(expectedObj, receivedObj, spec, op, options) { const receivedType = getType(receivedObj); const receivedStr = `${getStringIfNotScalar(receivedObj)} (type ${receivedType})`; const expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [{ pass: expected === receivedType, expected, received: receivedStr, op }] }; }, $regex: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); const regexOpts = options[OPTIONS_CLAUSE]; const regex = new RegExp(expected, regexOpts); let pass = false, message = ""; try { pass = typeof received === "string" && regex.test(received); } catch (err) { message = err.message; } return { spec, subResults: [], results: [{ pass, expected, received, op, message }] }; }, $sw: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [ { pass: typeof received === "string" && received.startsWith(expected), expected, received, op } ] }; }, $ew: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [ { pass: typeof received === "string" && received.endsWith(expected), expected, received, op } ] }; }, $co: function(expectedObj, receivedObj, spec, op, options) { const received = getStringIfNotScalar(receivedObj), expected = getStringIfNotScalar(expectedObj); return { spec, subResults: [], results: [ { pass: typeof received === "string" && received.includes(expected), expected, received, op } ] }; }, [OPTIONS_CLAUSE]: function(expectedObj, receivedObj, spec, op, options) { return { spec, subResults: [], results: [] }; }, [SKIP_CLAUSE]: function(expectedObj, receivedObj, spec, op, options) { return { spec, subResults: [], results: [] }; }, [MULTI_CLAUSE]: function(expectedObj, receivedObj, spec, op, options) { return { spec, subResults: [], results: [] }; }, $tests: function(expectedObj, receivedObj, spec, op, options) { const res = { spec, results: [], subResults: [] }; const expected = getStringIfNotScalar(expectedObj); const received = getStringIfNotScalar(receivedObj); const recursiveTests = expectedObj; if (!isDict(recursiveTests)) { const compResult = { pass: false, op, expected, received, message: "recursive tests must be dicts" }; res.results.push(compResult); return res; } mergePrefixBasedTests(recursiveTests); const compRes = runJsonTests(recursiveTests.json, receivedObj, options[SKIP_CLAUSE]); res.subResults.push(...compRes); return res; } }; function runObjectTests(opVals, receivedObject, spec, skip) { const objRes = { spec, results: [], subResults: [], skipped: skip || opVals[SKIP_CLAUSE] }; const options = { [OPTIONS_CLAUSE]: opVals[OPTIONS_CLAUSE], [SKIP_CLAUSE]: objRes.skipped }; const testNames = Object.keys(tests); for (const op in opVals) { if (testNames.includes(op)) { const res = tests[op](opVals[op], receivedObject, spec, op, options); objRes.results.push(...res.results); objRes.subResults.push(...res.subResults); } else { objRes.results.push({ pass: false, expected: `one of ${testNames.join(", ")}`, received: op, op: "", message: "Note: use $eq to compare objects" }); } } return objRes; } // src/captureVars.ts var import_jsonpath2 = __toESM(require("jsonpath")); function captureVariables(requestData, responseData) { const setvars = requestData.setvars; const headers = responseData.headers; let captureOutput = ""; let capturedVariables = {}; for (const { varName, type, spec } of setvars) { let value = void 0; if (type === "json") { let errorInJP = void 0; try { value = import_jsonpath2.default.value(responseData.json, spec); } catch (err) { if (err.description !== void 0) { errorInJP = err.description; } } if (errorInJP !== void 0) { captureOutput += `Could not set "${varName}", error in jsonpath: ${errorInJP} `; } } else if (type === "header") { value = headers !== void 0 ? headers[spec.toLowerCase()] : void 0; } else if (type === "status") { value = responseData.status; } else if (type === "body") { value = requestData.expectJson ? responseData.json : responseData.body; } capturedVariables[varName] = value; } return { capturedVars: capturedVariables, captureErrors: captureOutput }; } // src/convertPostman.ts var fs = __toESM(require("fs")); var YAML3 = __toESM(require("yaml")); var re = /\{\{(\w+)\}\}/g; function reformatVariables(text) { return text.replace(re, "$($1)"); } function reformatVariablesInObject(object) { for (const key in object) { if (typeof object[key] === "string") { object[key] = reformatVariables(object[key]); } else if (typeof object[key] === "object") { reformatVariablesInObject(object[key]); } } } function addRequest(prefix, element, requests) { var _a, _b, _c; const request = {}; const name = `${prefix}${element.name}`; requests[name] = request; const r = element.request; request.method = r.method; if (r.url) { const protocol = r.url.protocol || ""; const host = (r.url.host || []).join("."); const path3 = (r.url.path || []).join("/"); if (protocol) { request.url = reformatVariables(`${protocol}://${host}/${path3}`); } else { request.url = reformatVariables(`${host}/${path3}`); } } let contentType = ""; if (r.header && r.header.length > 0) { request.headers = {}; for (const h of r.header) { request.headers[h.key] = reformatVariables(h.value); if (h.key.toLowerCase() === "content-type") { contentType = h.value; } } } if (r.url && r.url.query && r.url.query.length > 0) { request.params = {}; for (const q of r.url.query) { const { key, value } = q; if (request.params[key]) { if (!Array.isArray(request.params[key])) { request.params[key] = [request.params[key]]; } request.params[key].push(value); } else { request.params[key] = value; } } } if (r.body && r.body.mode === "raw") { if (((_c = (_b = (_a = r.body) == null ? void 0 : _a.options) == null ? void 0 : _b.raw) == null ? void 0 : _c.language) === "json" || contentType === "application/json") { try { request.body = JSON.parse(r.body.raw); reformatVariablesInObject(request.body); } catch (e) { request.body = reformatVariables(r.body.raw); } } else { request.body = reformatVariables(r.body.raw); } } else if (r.body) { request.body = `UNSUPPORTED body type ${r.body.mode}, could not convert.`; } } function addRequestsFromFolder(prefix, item, requests) { item.forEach((element) => { if (element.item) { const subPrefix = prefix ? `${prefix}${element.name}/` : `${element.name}/`; addRequestsFromFolder(subPrefix, element.item, requests); } else if (element.request) { addRequest(prefix, element, requests); } }); } function convertCollection(filePath) { var _a; const contents = fs.readFileSync(filePath, "utf-8"); const collection = JSON.parse(contents); if (((_a = collection == null ? void 0 : collection.info) == null ? void 0 : _a.schema) !== "https://schema.getpostman.com/json/collection/v2.1.0/collection.json") { throw Error("Not a Postman v2.1.0 collection. Cannot import"); } const bundle = { requests: {} }; addRequestsFromFolder("", collection.item, bundle.requests); const yamlDoc = new YAML3.Document(bundle); YAML3.visit(yamlDoc, { Pair(_, node) { var _a2, _b, _c; if (((_a2 = node == null ? void 0 : node.key) == null ? void 0 : _a2.value) === "requests") { node.key.spaceBefore = true; node.value.items.forEach((i) => { i.key.spaceBefore = true; }); } if (((_b = node == null ? void 0 : node.key) == null ? void 0 : _b.value) === "headers" || ((_c = node == null ? void 0 : node.key) == null ? void 0 : _c.value) === "params") { node.value.items.forEach((i) => { i.flow = true; }); } } }); return YAML3.stringify(yamlDoc); } function convertEnvironment(filePath) { const contents = fs.readFileSync(filePath, "utf-8"); const environment = JSON.parse(contents); const essentialKeys = ["name", "_postman_variable_scope", "values"]; essentialKeys.forEach((key) => { if (!environment.hasOwnProperty(key)) { throw Error(`Did you select an exported postman environment?`); } }); const name = environment.name; const variables = {}; variables[name] = {}; const postmanVars = environment.values; postmanVars.forEach((item) => { variables[name][item.key] = item.value; }); let env = ""; env += "# The variable set corresponding to the environment is below.\n# Save it as a .zzv file, or copy-paste it into an existing .zzv file,\n# or paste it into your bundle under the top level 'variables' object.\n"; if (environment._postman_variable_scope === "globals") { env += "# If these variables are intended to be global, add them to each env\n"; } env += "\n" + YAML3.stringify(variables); return env; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { VarStore, captureVariables, constructGotRequest, convertCollection, convertEnvironment, executeGotRequest, getAllRequestSpecs, getCurlRequest, getEnvironments, getRequestPositions, getRequestSpec, loadVariables, replaceVariablesInRequest, runAllTests }); //# sourceMappingURL=index.js.map