"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.uuid = exports.createEmptyRequest = exports.PRE_REQUEST_LISTEN = exports.ASSERT_TYPES = exports.ASSERT_TARGETS = exports.COLLECTION_WITH_FOLDERS_ERROR = exports.DEFAULT_OAUTH2_GRANT_TYPE = exports.DEFAULT_OAUTH2_CLIENT_CREDENTIALS_LOCATION = exports.HMAC_SHA1_SIGNATURE = exports.DEFAULT_ADD_OAUTH1_TO_HEADER_VALUE = exports.DEFAULT_OAUTH1_VERSION = exports.OAUTH2_AUTH = exports.OAUTH1_AUTH = exports.NO_AUTH = exports.BEARER_TOKEN_AUTH = exports.BASIC_AUTH = exports.API_KEY_AUTH = exports.INHERIT_AUTH_FROM_PARENT_VALUE = exports.MABL_GENERATED_COMMENT = exports.MABL_GENERATED_ASSERTION_TOKEN = exports.TEST_LISTEN = void 0;
exports.compareStringsCaseInsensitive = compareStringsCaseInsensitive;
exports.caseInsensitiveEquals = caseInsensitiveEquals;
exports.getAssertionTypesForTarget = getAssertionTypesForTarget;
exports.humanizeAssertionType = humanizeAssertionType;
exports.createEmptyAssertion = createEmptyAssertion;
exports.createEmptyVariable = createEmptyVariable;
exports.restoreCustomRequestFields = restoreCustomRequestFields;
exports.findFirstMatchingEvent = findFirstMatchingEvent;
exports.createEmptyRequestEvent = createEmptyRequestEvent;
exports.removeMablGeneratedScripts = removeMablGeneratedScripts;
exports.isValidMablVariableAssignment = isValidMablVariableAssignment;
exports.filterValidMablVariableAssignments = filterValidMablVariableAssignments;
exports.filterValidMablAssertions = filterValidMablAssertions;
exports.assertionRequiresValue = assertionRequiresValue;
exports.normalizeAssertionValue = normalizeAssertionValue;
exports.normalizeExpectedValue = normalizeExpectedValue;
exports.normalizeRegExpExpectedValue = normalizeRegExpExpectedValue;
exports.isValidMablAssertion = isValidMablAssertion;
exports.assertionHasTest = assertionHasTest;
exports.getAssertionTargetArgument = getAssertionTargetArgument;
exports.humanizeAssertion = humanizeAssertion;
exports.assertionTargetSupportsCaseSensitivity = assertionTargetSupportsCaseSensitivity;
exports.assertionTypeSupportsCaseSensitivity = assertionTypeSupportsCaseSensitivity;
exports.valueToUnquotedString = valueToUnquotedString;
exports.getResponseContentType = getResponseContentType;
exports.readBody = readBody;
exports.getActualValue = getActualValue;
exports.replaceVariables = replaceVariables;
exports.toPostmanScript = toPostmanScript;
exports.createMablGeneratedScripts = createMablGeneratedScripts;
exports.convertMablVariableAssignmentsToExecArray = convertMablVariableAssignmentsToExecArray;
exports.convertMablAssertionsToExecArray = convertMablAssertionsToExecArray;
exports.splitLines = splitLines;
exports.createEmptyRequestEventArray = createEmptyRequestEventArray;
exports.processPostmanItems = processPostmanItems;
exports.generateRawScriptField = generateRawScriptField;
exports.validateCollectionFeaturesForApiTestEditor = validateCollectionFeaturesForApiTestEditor;
exports.isFolder = isFolder;
exports.isItemGroupDefinition = isItemGroupDefinition;
exports.isCollectionDefinition = isCollectionDefinition;
exports.isItemDefinition = isItemDefinition;
exports.isSupportedAuthType = isSupportedAuthType;
exports.isJson = isJson;
exports.isXML = isXML;
exports.isText = isText;
exports.isBinary = isBinary;
exports.getFormDataArray = getFormDataArray;
exports.getRequestMode = getRequestMode;
exports.formatContent = formatContent;
exports.mablAuthToPostman = mablAuthToPostman;
exports.processItemAuth = processItemAuth;
exports.processItemGroupAuth = processItemGroupAuth;
exports.removeInvalidHeaders = removeInvalidHeaders;
exports.replaceRawScriptWithExecArray = replaceRawScriptWithExecArray;
exports.processPostmanItem = processPostmanItem;
exports.insertMablAuthIntoCollection = insertMablAuthIntoCollection;
exports.insertMablScriptsIntoCollection = insertMablScriptsIntoCollection;
exports.createPostmanScript = createPostmanScript;
exports.convertMablSnippetsToExecArray = convertMablSnippetsToExecArray;
exports.createCommentForApiTestSnippet = createCommentForApiTestSnippet;
exports.insertTestConfigurationIntoFlow = insertTestConfigurationIntoFlow;
exports.apiTestAuthToMablAuth = apiTestAuthToMablAuth;
exports.executableSnippetsToPostmanEvent = executableSnippetsToPostmanEvent;
exports.executableSnippetToApiTestSnippet = executableSnippetToApiTestSnippet;
exports.oauth2ConfigurationToPostmanEvent = oauth2ConfigurationToPostmanEvent;
exports.getValueFromAuthVariables = getValueFromAuthVariables;
exports.postmanAuthToApiTestAuth = postmanAuthToApiTestAuth;
exports.mablAuthToApiAuthentication = mablAuthToApiAuthentication;
exports.resolveMablAuth = resolveMablAuth;
exports.postmanEventToExecutableSnippets = postmanEventToExecutableSnippets;
exports.getSnippetReferencesInCollection = getSnippetReferencesInCollection;
exports.getSnippetReferencesInTest = getSnippetReferencesInTest;
exports.fetchSnippetsForApiTestAndFlows = fetchSnippetsForApiTestAndFlows;
exports.exportPostmanTestAsCollection = exportPostmanTestAsCollection;
exports.exportPostmanFlowAsCollection = exportPostmanFlowAsCollection;
exports.insertTestVariablesIntoFlow = insertTestVariablesIntoFlow;
exports.filterDisabledStepsFromJourney = filterDisabledStepsFromJourney;
exports.filterDisabledStepsFromFlows = filterDisabledStepsFromFlows;
exports.itemToItemNameOrUrl = itemToItemNameOrUrl;
exports.itemToStepTitle = itemToStepTitle;
exports.buildVariableStepSources = buildVariableStepSources;
const newman_types_1 = require("./newman-types");
const uuid_1 = require("uuid");
const mablApi_1 = require("../../mablApi");
const encodingUtil_1 = require("../../util/encodingUtil");
const stepValidation_1 = require("../entityValidation/stepValidation");
const lodash_get_1 = __importDefault(require("lodash.get"));
const object_hash_1 = __importDefault(require("object-hash"));
const mablscriptFind_1 = require("@mablhq/test-model/mablscriptFind");
const VariableUtils_1 = require("./VariableUtils");
exports.TEST_LISTEN = 'test';
exports.MABL_GENERATED_ASSERTION_TOKEN = '__MABL_GENERATED__';
exports.MABL_GENERATED_COMMENT = `// ${exports.MABL_GENERATED_ASSERTION_TOKEN} Do not edit below this line`;
exports.INHERIT_AUTH_FROM_PARENT_VALUE = 'inherit_from_parent';
exports.API_KEY_AUTH = 'apikey';
exports.BASIC_AUTH = 'basic';
exports.BEARER_TOKEN_AUTH = 'bearer';
exports.NO_AUTH = 'noauth';
exports.OAUTH1_AUTH = 'oauth1';
exports.OAUTH2_AUTH = 'oauth2';
exports.DEFAULT_OAUTH1_VERSION = '1.0';
const ADD_OAUTH1_TO_HEADER = true;
const ADD_OAUTH1_TO_HEADER_VALUE = `${ADD_OAUTH1_TO_HEADER}`;
exports.DEFAULT_ADD_OAUTH1_TO_HEADER_VALUE = ADD_OAUTH1_TO_HEADER_VALUE;
exports.HMAC_SHA1_SIGNATURE = 'HMAC-SHA1';
exports.DEFAULT_OAUTH2_CLIENT_CREDENTIALS_LOCATION = mablApi_1.OAuth2Authentication.ClientCredentialsLocationEnum.BasicAuthHeader;
exports.DEFAULT_OAUTH2_GRANT_TYPE = mablApi_1.OAuth2Authentication.GrantTypeEnum.ClientCredentials;
exports.COLLECTION_WITH_FOLDERS_ERROR = 'Collections with folders are not supported';
const RESPONSE_PROPERTIES = {
    Size: 'size().body',
    Status: 'code',
    TextBody: 'text()',
};
exports.ASSERT_TARGETS = [
    { label: 'Header', value: newman_types_1.AssertionTarget.Header },
    { label: 'Status', value: newman_types_1.AssertionTarget.Status },
    { label: 'Size (bytes)', value: newman_types_1.AssertionTarget.Size },
    { label: 'JSON Body', value: newman_types_1.AssertionTarget.JSONBody },
    { label: 'Text Body', value: newman_types_1.AssertionTarget.TextBody },
];
exports.ASSERT_TYPES = [
    { label: 'Equals', value: newman_types_1.AssertionType.Equals },
    { label: 'Not equals', value: newman_types_1.AssertionType.NotEquals },
    { label: 'Contains', value: newman_types_1.AssertionType.Contains },
    { label: 'Not contains', value: newman_types_1.AssertionType.DoesNotContain },
    { label: 'Is present', value: newman_types_1.AssertionType.Present },
    { label: 'Not present', value: newman_types_1.AssertionType.NotPresent },
    { label: 'Greater than', value: newman_types_1.AssertionType.GreaterThan },
    {
        label: 'Greater than or equal to',
        value: newman_types_1.AssertionType.GreaterThanOrEqualTo,
    },
    { label: 'Less than', value: newman_types_1.AssertionType.LessThan },
    { label: 'Less than or equal to', value: newman_types_1.AssertionType.LessThanOrEqualTo },
    { label: 'Starts with', value: newman_types_1.AssertionType.StartsWith },
    { label: 'Ends with', value: newman_types_1.AssertionType.EndsWith },
    { label: 'Matches regular expression', value: newman_types_1.AssertionType.MatchesRegExp },
];
const EXPECTED_VALUE_TOKEN = '!!EXPECTED_VALUE!!';
const EXPECT_FUNCTIONS = {
    Equals: `eql(${EXPECTED_VALUE_TOKEN})`,
    NotEquals: `not.eql(${EXPECTED_VALUE_TOKEN})`,
    Contains: `include(${EXPECTED_VALUE_TOKEN})`,
    DoesNotContain: `not.include(${EXPECTED_VALUE_TOKEN})`,
    Present: `not.be.undefined`,
    NotPresent: `be.undefined`,
    GreaterThan: `be.above(${EXPECTED_VALUE_TOKEN})`,
    GreaterThanOrEqualTo: `be.at.least(${EXPECTED_VALUE_TOKEN})`,
    LessThan: `be.below(${EXPECTED_VALUE_TOKEN})`,
    LessThanOrEqualTo: `be.at.most(${EXPECTED_VALUE_TOKEN})`,
    StartsWith: `satisfy(value => value.startsWith(${EXPECTED_VALUE_TOKEN}))`,
    EndsWith: `satisfy(value => value.endsWith(${EXPECTED_VALUE_TOKEN}))`,
    MatchesRegExp: `match(${EXPECTED_VALUE_TOKEN})`,
};
const MEDIA_TYPE_TOKEN = "[0-9A-Za-z!#$%&'*+.^_`|~-]+";
function compareStringsCaseInsensitive(a, b) {
    a = a?.toUpperCase().toLowerCase();
    b = b?.toUpperCase().toLowerCase();
    if (!a) {
        return -1;
    }
    if (!b) {
        return 1;
    }
    return a.localeCompare(b, undefined, { sensitivity: 'base' });
}
function caseInsensitiveEquals(a, b) {
    return compareStringsCaseInsensitive(a, b) === 0;
}
function getAssertionTypesForTarget(target) {
    switch (target) {
        case newman_types_1.AssertionTarget.Size:
        case newman_types_1.AssertionTarget.Status:
            return exports.ASSERT_TYPES.filter((assertType) => [
                newman_types_1.AssertionType.Equals,
                newman_types_1.AssertionType.NotEquals,
                newman_types_1.AssertionType.GreaterThan,
                newman_types_1.AssertionType.GreaterThanOrEqualTo,
                newman_types_1.AssertionType.LessThan,
                newman_types_1.AssertionType.LessThanOrEqualTo,
            ].includes(assertType.value));
        case newman_types_1.AssertionTarget.Header:
        case newman_types_1.AssertionTarget.JSONBody:
        case newman_types_1.AssertionTarget.TextBody:
        default:
            return exports.ASSERT_TYPES;
    }
}
function humanizeAssertionType(assertionType) {
    switch (assertionType) {
        case 'NotEquals':
            return 'not equals';
        case 'DoesNotContain':
            return 'does not contain';
        case 'Present':
            return 'is present';
        case 'NotPresent':
            return 'is not present';
        case 'GreaterThan':
            return 'greater than';
        case 'GreaterThanOrEqualTo':
            return 'greater than or equal to';
        case 'LessThan':
            return 'less than';
        case 'LessThanOrEqualTo':
            return 'less than or equal to';
        case 'StartsWith':
            return 'starts with';
        case 'EndsWith':
            return 'ends with';
        case 'MatchesRegExp':
            return 'matches regular expression';
        default:
            return assertionType.toString().toLowerCase();
    }
}
function createEmptyAssertion(contentType) {
    const isJsonContent = !contentType || isJson(contentType);
    return {
        id: (0, uuid_1.v4)(),
        assertTarget: isJsonContent
            ? newman_types_1.AssertionTarget.JSONBody
            : isText(contentType) || isXML(contentType)
                ? newman_types_1.AssertionTarget.TextBody
                : newman_types_1.AssertionTarget.Header,
        assertType: newman_types_1.AssertionType.Present,
        description: '',
    };
}
function createEmptyVariable(contentType) {
    const isJsonContent = !contentType || isJson(contentType);
    return {
        id: (0, uuid_1.v4)(),
        assertTarget: isJsonContent
            ? newman_types_1.AssertionTarget.JSONBody
            : isText(contentType) || isXML(contentType)
                ? newman_types_1.AssertionTarget.TextBody
                : newman_types_1.AssertionTarget.Header,
        variableName: '',
        description: '',
    };
}
function restoreCustomRequestFields(postmanResult, collection) {
    const requestItemsById = collection.item.reduce((collectionSet, itemDefinition) => {
        collectionSet[itemDefinition.id] = itemDefinition;
        return collectionSet;
    }, {});
    postmanResult.run.executions.forEach((execution) => {
        const requestItemDefinition = requestItemsById[execution.id];
        if (execution.request.body?.mode === 'formdata' &&
            requestItemDefinition?.request) {
            restoreFormDataFileMetadata(execution.request, requestItemDefinition.request);
        }
    });
    return postmanResult;
}
function restoreFormDataFileMetadata(resultRequest, collectionRequest) {
    if (resultRequest.body?.formdata) {
        const requestFormDataBySrc = collectionRequest?.body?.formdata?.reduce((set, formData) => {
            if (formData.src) {
                set[formData.src] = formData;
            }
            return set;
        }, {});
        if (!Array.isArray(resultRequest.body?.formdata)) {
            resultRequest.body.formdata = resultRequest.body.formdata
                .all()
                .map((formParam) => formParam);
        }
        for (const resultFormParam of resultRequest.body.formdata) {
            if (resultFormParam.type === 'file' &&
                resultFormParam.src &&
                !resultFormParam.mablFile) {
                resultFormParam.mablFile =
                    requestFormDataBySrc[resultFormParam.src]?.mablFile;
            }
        }
    }
}
function findFirstMatchingEvent(eventDefinition, listen) {
    if (!eventDefinition) {
        return { eventIndex: -1 };
    }
    const eventIndex = eventDefinition.findIndex((def) => def.listen === listen);
    let eventValue;
    if (eventIndex !== -1) {
        eventValue = eventDefinition?.[eventIndex];
    }
    return { eventIndex, eventValue };
}
function createEmptyRequestEvent(includeDefaultAssertion = true) {
    const defaultAssertion = [
        {
            id: (0, uuid_1.v4)(),
            assertTarget: newman_types_1.AssertionTarget.Status,
            assertType: newman_types_1.AssertionType.Equals,
            value: '200',
        },
    ];
    return {
        listen: exports.TEST_LISTEN,
        id: (0, exports.uuid)(),
        script: {
            exec: [],
            raw: '',
            type: 'text/javascript',
        },
        mablAssertions: includeDefaultAssertion ? defaultAssertion : [],
        mablVariables: [],
        mablSnippets: [],
    };
}
function removeMablGeneratedScriptsFromLines(lines) {
    const mablGeneratedIndex = lines.findIndex((line) => line.includes(exports.MABL_GENERATED_ASSERTION_TOKEN));
    if (mablGeneratedIndex >= 0) {
        return lines.slice(0, mablGeneratedIndex);
    }
    return lines;
}
function removeMablGeneratedScripts(eventDefinition) {
    eventDefinition.script.exec = removeMablGeneratedScriptsFromLines(eventDefinition.script?.exec ?? []);
}
function isValidMablVariableAssignment(variable) {
    return !!variable.assertTarget && !!variable.variableName;
}
function filterValidMablVariableAssignments(variables) {
    return variables?.filter(isValidMablVariableAssignment);
}
function filterValidMablAssertions(assertions) {
    return assertions?.filter(isValidMablAssertion);
}
function assertionRequiresValue(assertion) {
    switch (assertion.assertType) {
        case newman_types_1.AssertionType.Present:
        case newman_types_1.AssertionType.NotPresent:
            return false;
        default:
            return true;
    }
}
function normalizeAssertionValue(assertion) {
    switch (assertion.assertType) {
        case 'MatchesRegExp':
            return normalizeRegExpExpectedValue(assertion.value);
        default:
            return normalizeExpectedValue(assertion.value);
    }
}
function normalizeExpectedValue(value) {
    if (value === undefined) {
        return;
    }
    value = value.trim();
    if (value.match(/".*"/)) {
        return `pm.variables.replaceIn(${value})`;
    }
    const lower = value.toUpperCase().toLowerCase();
    if (lower === 'true' || lower === 'false' || !Number.isNaN(Number(value))) {
        return JSON.stringify(value);
    }
    return `pm.variables.replaceIn(${JSON.stringify(value)})`;
}
function normalizeRegExpExpectedValue(value) {
    if (value === undefined) {
        return;
    }
    value = value.trim();
    if (value.match(stepValidation_1.REGEXP_LITERAL_PATTERN)) {
        return value;
    }
    return `new RegExp(${JSON.stringify(value)})`;
}
function isValidMablAssertion(assertion) {
    if (!assertion.assertType) {
        return false;
    }
    const assertTarget = assertion.assertTarget;
    const requiresValue = assertionRequiresValue(assertion);
    const expectedValue = normalizeAssertionValue(assertion);
    const hasExpectedValue = !!expectedValue;
    const hasRequiredValue = !requiresValue || hasExpectedValue;
    let valid = false;
    switch (assertTarget) {
        case 'JSONBody':
            const hasBodyPath = (assertion.bodyPath?.trim()?.length ?? 0) > 0;
            valid = hasBodyPath && hasRequiredValue;
            break;
        case 'Status':
            valid = hasExpectedValue;
            break;
        case 'Header':
            const hasHeaderName = (assertion.headerName?.length ?? 0) > 0;
            valid = hasHeaderName && hasRequiredValue;
            break;
        case 'Size':
            valid =
                isValidSizeAssertionType(assertion.assertType) && hasExpectedValue;
            break;
        case 'TextBody':
            valid = hasExpectedValue;
            break;
    }
    return valid;
}
function isValidSizeAssertionType(assertType) {
    switch (assertType) {
        case newman_types_1.AssertionType.Equals:
        case newman_types_1.AssertionType.NotEquals:
        case newman_types_1.AssertionType.GreaterThan:
        case newman_types_1.AssertionType.GreaterThanOrEqualTo:
        case newman_types_1.AssertionType.LessThan:
        case newman_types_1.AssertionType.LessThanOrEqualTo:
            return true;
    }
    return false;
}
function assertionHasTest(assertion) {
    if (!assertion.assertTarget || !assertion.assertType) {
        return false;
    }
    switch (assertion.assertTarget) {
        case 'Header':
            return !!assertion.headerName;
        case 'JSONBody':
            return !!assertion.bodyPath;
        default:
            return !!assertion.assertType && !!assertion.value;
    }
}
function getAssertionTargetArgument(assertion) {
    switch (assertion.assertTarget) {
        case 'JSONBody':
            return assertion.bodyPath;
        case 'Header':
            return assertion.headerName;
        default:
            return;
    }
}
function humanizeAssertion(assertion) {
    const { assertTarget, assertType, value, description } = assertion;
    if (description && description !== '') {
        return description;
    }
    const humanizedAssertTarget = exports.ASSERT_TARGETS.filter((target) => target.value === assertTarget)?.[0]?.label;
    if (assertionHasTest(assertion)) {
        const assertionTargetArgument = getAssertionTargetArgument(assertion);
        const humanized = `${humanizedAssertTarget}${assertionTargetArgument ? ` ${assertionTargetArgument}` : ''} ${humanizeAssertionType(assertType)}`;
        return assertionRequiresValue(assertion)
            ? `${humanized} ${value}`
            : humanized;
    }
    if (assertType && humanizedAssertTarget) {
        return `${humanizedAssertTarget} ${humanizeAssertionType(assertType)}`;
    }
    return '';
}
function generateAssertionScript(assertion) {
    if (!assertion.assertType) {
        return;
    }
    const assertTarget = assertion.assertTarget;
    const assertType = assertion.assertType;
    const description = humanizeAssertion(assertion);
    const requiresValue = assertionRequiresValue(assertion);
    const expectedValue = normalizeAssertionValue(assertion);
    const caseSensitive = assertion.caseSensitive !== false;
    switch (assertTarget) {
        case 'JSONBody':
            return generateJsonBodyAssertion(description, assertType, requiresValue, assertion.bodyPath, expectedValue, caseSensitive);
        case 'Status':
            return generateStatusAssertion(description, assertType, expectedValue);
        case 'Header':
            return generateHeaderAssertion(description, assertType, assertion.headerName, expectedValue, caseSensitive);
        case 'Size':
            return generateSizeAssertion(description, assertTarget, assertType, expectedValue);
        case 'TextBody':
            return generateTextBodyAssertion(description, assertType, expectedValue, caseSensitive);
    }
    return;
}
function generateVariableAssignmentScript(variable) {
    if (!variable.variableName) {
        return;
    }
    const assertTarget = variable.assertTarget;
    switch (assertTarget) {
        case 'JSONBody':
            return generateJsonBodyVariableAssignment(variable.variableName, variable.bodyPath);
        case 'Header':
            return generateHeaderVariableAssignment(variable.variableName, variable.headerName);
        default:
            return generateSimpleVariableAssignment(variable.variableName, assertTarget);
    }
}
function generateJsonBodyAssertion(description, assertType, requiresValues, path, expectedValue, caseSensitive) {
    if (!path?.trim().length || (requiresValues && !expectedValue?.length)) {
        return;
    }
    let propertyAccessor = getJsonBodyProperty(path);
    if (requiresValues) {
        propertyAccessor = valueToUnquotedString(propertyAccessor);
    }
    switch (assertType) {
        case 'Present':
        case 'NotPresent':
        case 'Equals':
        case 'NotEquals':
        case 'Contains':
        case 'DoesNotContain':
        case 'StartsWith':
        case 'EndsWith':
        case 'MatchesRegExp':
            break;
        case 'GreaterThan':
        case 'GreaterThanOrEqualTo':
        case 'LessThan':
        case 'LessThanOrEqualTo':
            propertyAccessor = `parseFloat(${propertyAccessor})`;
            expectedValue = `parseFloat(${expectedValue})`;
            break;
        default:
            throw new Error(`Unexpected header assert type: ${assertType}`);
    }
    return generatePostmanAssertion(description, propertyAccessor, assertType, expectedValue, caseSensitive);
}
function generateJsonBodyVariableAssignment(variableName, path) {
    return generatePostmanVariableAssignment(variableName, getJsonBodyProperty(path));
}
function getJsonBodyProperty(path) {
    const jsonBodyAccessor = 'pm.response.json()';
    return path
        ? `_.get(${jsonBodyAccessor}, pm.variables.replaceIn('${path}'))`
        : jsonBodyAccessor;
}
function generateHeaderVariableAssignment(variableName, headerName) {
    if (!headerName) {
        return;
    }
    return generatePostmanVariableAssignment(variableName, generateGetHeaderValue(headerName));
}
function generateGetHeaderValue(headerName) {
    return `pm.response.headers.get(${JSON.stringify(headerName)})`;
}
function generateStatusAssertion(description, assertType, expectedValue) {
    if (!expectedValue?.length) {
        return;
    }
    let expect;
    let target = 'pm.response.code';
    switch (assertType) {
        case 'Equals':
            expect = `pm.response.to.have.status(parseInt(${expectedValue}))`;
            break;
        case 'NotEquals':
            expect = `pm.response.to.not.have.status(parseInt(${expectedValue}))`;
            break;
        case 'Contains':
        case 'DoesNotContain':
        case 'StartsWith':
        case 'EndsWith':
        case 'MatchesRegExp':
            target += '.toString()';
            break;
        case 'GreaterThan':
        case 'GreaterThanOrEqualTo':
        case 'LessThan':
        case 'LessThanOrEqualTo':
            expectedValue = `parseInt(${expectedValue})`;
            break;
        default:
            throw new Error(`Unexpected status assert type: ${assertType}`);
    }
    return generatePostmanTest(description, expect ?? generatePostmanExpect(target, assertType, expectedValue));
}
function generateHeaderAssertion(description, assertType, headerName, expectedValue, caseSensitive) {
    if (!headerName) {
        return;
    }
    const normalizedHeaderName = JSON.stringify(headerName);
    let test;
    let target = `pm.response.headers.get(${normalizedHeaderName})`;
    switch (assertType) {
        case 'Present':
            test = `pm.response.to.have.header(${normalizedHeaderName})`;
            break;
        case 'NotPresent':
            test = `pm.response.to.not.have.header(${normalizedHeaderName})`;
            break;
        case 'Equals':
        case 'NotEquals':
        case 'Contains':
        case 'DoesNotContain':
        case 'StartsWith':
        case 'EndsWith':
        case 'MatchesRegExp':
            break;
        case 'GreaterThan':
        case 'GreaterThanOrEqualTo':
        case 'LessThan':
        case 'LessThanOrEqualTo':
            target = `parseFloat(${target})`;
            expectedValue = `parseFloat(${expectedValue})`;
            break;
        default:
            throw new Error(`Unexpected header assert type: ${assertType}`);
    }
    return generatePostmanTest(description, test ??
        generatePostmanExpect(target, assertType, expectedValue, caseSensitive));
}
function generateSizeAssertion(description, target, type, expectedValue) {
    if (!expectedValue?.length) {
        return;
    }
    if (type !== newman_types_1.AssertionType.MatchesRegExp) {
        expectedValue = `parseInt(${expectedValue})`;
    }
    return generateSimpleAssertion(description, target, type, expectedValue);
}
function generateTextBodyAssertion(description, assertType, expectedValue, caseSensitive) {
    let target = 'pm.response.text()';
    switch (assertType) {
        case 'Present':
        case 'NotPresent':
        case 'Equals':
        case 'NotEquals':
        case 'Contains':
        case 'DoesNotContain':
        case 'StartsWith':
        case 'EndsWith':
        case 'MatchesRegExp':
            break;
        case 'GreaterThan':
        case 'GreaterThanOrEqualTo':
        case 'LessThan':
        case 'LessThanOrEqualTo':
            target = `parseFloat(${target})`;
            expectedValue = `parseFloat(${expectedValue})`;
            break;
        default:
            throw new Error(`Unexpected header assert type: ${assertType}`);
    }
    return generatePostmanAssertion(description, target, assertType, expectedValue, caseSensitive);
}
function generateSimpleAssertion(description, target, type, expectedValue, caseSensitive = true) {
    return generatePostmanTest(description, generatePostmanExpect(getResponseProperty(target), type, expectedValue, caseSensitive));
}
function generateSimpleVariableAssignment(name, target) {
    return generatePostmanVariableAssignment(name, getResponseProperty(target));
}
function getResponseProperty(target) {
    const property = RESPONSE_PROPERTIES[target];
    if (!property) {
        throw new Error(`No response property found for target [${target}]`);
    }
    return `pm.response.${property}`;
}
function generatePostmanAssertion(description, target, assertType, expectedValue, caseSensitive) {
    return generatePostmanTest(description, generatePostmanExpect(target, assertType, expectedValue, caseSensitive));
}
function generatePostmanExpect(target, assertType, expectedValue, caseSensitive = true) {
    if (!caseSensitive && assertionTypeSupportsCaseSensitivity(assertType)) {
        target += '?.toUpperCase().toLowerCase()';
        expectedValue = `${expectedValue ?? ''}.toUpperCase().toLowerCase()`;
    }
    return `pm.expect(${target}).to.${EXPECT_FUNCTIONS[assertType].replace(EXPECTED_VALUE_TOKEN, () => expectedValue ?? '')}`;
}
function assertionTargetSupportsCaseSensitivity(assertTarget) {
    switch (assertTarget) {
        case 'Header':
        case 'JSONBody':
        case 'TextBody':
            return true;
        default:
            return false;
    }
}
function assertionTypeSupportsCaseSensitivity(assertionType) {
    switch (assertionType) {
        case 'Contains':
        case 'DoesNotContain':
        case 'StartsWith':
        case 'EndsWith':
        case 'Equals':
        case 'NotEquals':
            return true;
        default:
            return false;
    }
}
function generatePostmanTest(description, test) {
    return `pm.test(${JSON.stringify(description)}, function () { ${test}; });`;
}
function generatePostmanVariableAssignment(name, value) {
    return `pm.environment.set(${JSON.stringify(name)}, ${valueToUnquotedString(value)});`;
}
function valueToUnquotedString(value) {
    return `JSON.stringify(${value})?.replace(/^"(.+(?="$))"$/, '$1')`;
}
function getResponseContentType(response) {
    const contentType = response?.header?.find((header) => header.key.toLowerCase() === 'content-type')?.value;
    return contentType?.toLowerCase();
}
function readBody(body, contentType) {
    const bodyLength = body?.data?.length;
    if (!body || !bodyLength) {
        return;
    }
    if (!contentType) {
        return `${bodyLength} bytes of data with unknown type`;
    }
    else if (isJson(contentType)) {
        let bodyAsString = `${bodyLength} bytes of data`;
        try {
            bodyAsString = Buffer.from(body.data).toString();
        }
        catch (e) {
            console.error('Unable to convert body.data to string', e);
            return bodyAsString;
        }
        try {
            return JSON.parse(bodyAsString);
        }
        catch (e) {
            console.error('Unable to parse body into JSON object.', e);
            return bodyAsString;
        }
    }
    else {
        try {
            return Buffer.from(body.data).toString();
        }
        catch (e) {
            console.error('Unable to convert body.data to string', e);
            return `${bodyLength} bytes of data`;
        }
    }
}
function getActualValue(assertion, apiStepExecutionResult, variables) {
    const { assertTarget, bodyPath, headerName } = assertion;
    const contentType = getResponseContentType(apiStepExecutionResult.response);
    switch (assertTarget) {
        case newman_types_1.AssertionTarget.Header:
            return (apiStepExecutionResult.response?.header ?? []).find((header) => caseInsensitiveEquals(header.key, headerName));
        case newman_types_1.AssertionTarget.JSONBody:
            const content = readBody(apiStepExecutionResult.response?.stream, contentType);
            return bodyPath
                ? (0, lodash_get_1.default)(content, replaceVariables(bodyPath, variables))
                : content;
        case newman_types_1.AssertionTarget.Size:
            return apiStepExecutionResult.response?.responseSize;
        case newman_types_1.AssertionTarget.Status:
            return apiStepExecutionResult.response?.code;
        case newman_types_1.AssertionTarget.TextBody:
            return readBody(apiStepExecutionResult.response?.stream, contentType);
    }
    return null;
}
function replaceVariables(value, variables) {
    let toReplace = value;
    let matches;
    while ((matches = toReplace.match(new RegExp('{{@(?<name>[^{}]+)}}')))) {
        const variableName = matches.groups?.name;
        const variableValue = (variableName && variables[variableName]) ?? '';
        toReplace = toReplace.replace(new RegExp(`{{@${variableName}}}`, 'g'), variableValue);
    }
    return toReplace;
}
function toPostmanScript(assertion) {
    return [
        generateAssertionScript(assertion),
        generateVariableAssignmentScript(assertion),
    ]
        .filter((script) => script)
        .map((script) => script);
}
function createMablGeneratedScripts(event) {
    const mablVariables = convertMablVariableAssignmentsToExecArray(event);
    const mablAssertions = convertMablAssertionsToExecArray(event);
    if (mablVariables.length || mablAssertions.length) {
        return [exports.MABL_GENERATED_COMMENT, ...mablVariables, ...mablAssertions];
    }
    return [];
}
function convertMablVariableAssignmentsToExecArray(event) {
    return (filterValidMablVariableAssignments(event.mablVariables)
        ?.map((variable) => toPostmanScript(variable))
        .flat() ?? []);
}
function convertMablAssertionsToExecArray(event) {
    return (filterValidMablAssertions(event.mablAssertions)
        ?.map((assertion) => toPostmanScript(assertion))
        .flat() ?? []);
}
exports.PRE_REQUEST_LISTEN = 'prerequest';
function splitLines(value) {
    return value.length ? value.split(/\r?\n/) : [];
}
function createEmptyRequestEventArray(includeDefaultAssertion = true) {
    return [createEmptyRequestEvent(includeDefaultAssertion)];
}
const createEmptyRequest = (id = (0, uuid_1.v4)(), includeDefaultAssertion = true) => ({
    id,
    name: '',
    mablAuth: {
        type: exports.INHERIT_AUTH_FROM_PARENT_VALUE,
    },
    request: {
        body: {
            mode: 'none',
            raw: '',
            file: '',
            graphql: '',
            formdata: [],
            urlencoded: [],
        },
        header: [],
        method: 'GET',
        url: '',
    },
    event: createEmptyRequestEventArray(includeDefaultAssertion),
});
exports.createEmptyRequest = createEmptyRequest;
function processPostmanItems(items, handleItem, handleFolder) {
    items?.forEach((item) => {
        if (isItemGroupDefinition(item) || isCollectionDefinition(item)) {
            handleFolder?.(item);
            if (isItemGroupDefinition(item)) {
                processPostmanItems(item.item, handleItem, handleFolder);
            }
        }
        else if (isItemDefinition(item)) {
            handleItem?.(item);
        }
    });
}
function generateRawScriptField(eventValue) {
    if (eventValue.script) {
        eventValue.script.raw = eventValue.script.exec.join('\n');
    }
}
function validateCollectionFeaturesForApiTestEditor(collection) {
    let hasFolders = false;
    const handleFolder = (_item) => {
        hasFolders = true;
    };
    processPostmanItems(collection.item, () => { }, handleFolder);
    if (hasFolders) {
        return exports.COLLECTION_WITH_FOLDERS_ERROR;
    }
    return undefined;
}
function isFolder(item) {
    return 'item' in item && !!item.item;
}
function isItemGroupDefinition(item) {
    return isFolder(item) && !isCollectionDefinition(item);
}
function isCollectionDefinition(item) {
    return isFolder(item) && 'info' in item;
}
function isItemDefinition(item) {
    return !isFolder(item) && !isCollectionDefinition(item);
}
function isSupportedAuthType(authDefinition) {
    if (!authDefinition.type) {
        return false;
    }
    return (newman_types_1.MablSupportedPostmanAuthTypes.includes(authDefinition.type) || authDefinition.type === 'noauth');
}
function isJson(contentType) {
    return contentTypeMatches(contentType, (ct) => ct.startsWith('application/json'), (ct) => ct.match(new RegExp(`${MEDIA_TYPE_TOKEN}\/${MEDIA_TYPE_TOKEN}\\+json.*`, 'i')));
}
function isXML(contentType) {
    return contentTypeMatches(contentType, (ct) => ct.startsWith('application/xml'), (ct) => ct.startsWith('text/xml'), (ct) => ct.match(new RegExp(`${MEDIA_TYPE_TOKEN}\/${MEDIA_TYPE_TOKEN}\\+xml.*`, 'i')));
}
function isText(contentType) {
    return contentTypeMatches(contentType, (ct) => ct.startsWith('text/'));
}
function isBinary(contentType) {
    return contentTypeMatches(contentType, (ct) => ct.startsWith('image/'), (ct) => ct.startsWith('audio/'), (ct) => ct.startsWith('video/'), (ct) => ct.startsWith('application/octet-stream'), (ct) => ct.startsWith('application/zip'), (ct) => ct.startsWith('application/gzip'), (ct) => ct.startsWith('application/x-gzip'), (ct) => ct.startsWith('application/x-tar'), (ct) => ct.startsWith('application/x-rar-compressed'), (ct) => ct.startsWith('application/x-7z-compressed'), (ct) => ct.startsWith('application/x-bzip'), (ct) => ct.startsWith('application/x-rar'));
}
function contentTypeMatches(contentType, ...predicates) {
    if (!contentType) {
        return false;
    }
    return predicates.some((predicate) => predicate(contentType));
}
function getFormDataArray(item) {
    if (getRequestMode(item) === 'formdata') {
        const formdata = item?.request?.body?.formdata;
        if (Array.isArray(formdata)) {
            return formdata;
        }
        return formdata?.all() ?? [];
    }
    return [];
}
function getRequestMode(item) {
    return item?.request?.body?.mode;
}
function formatContent(contentContainer) {
    if (contentContainer?.hasOwnProperty('content')) {
        return contentContainer.content;
    }
    return contentContainer;
}
function processMablProtocolProfileBehavior(item) {
    const mablProtocolProfileBehavior = item.mablTemporaryStorage?.mablProtocolProfileBehavior ?? [];
    if (mablProtocolProfileBehavior.length === 0) {
        delete item.protocolProfileBehavior;
        return;
    }
    item.protocolProfileBehavior = {};
    mablProtocolProfileBehavior?.forEach((setting) => {
        if (setting.key && setting.value) {
            let valueToSet;
            try {
                valueToSet = JSON.parse(setting.value);
            }
            catch (error) {
                valueToSet = setting.value;
            }
            item.protocolProfileBehavior[setting.key] = valueToSet;
        }
    });
}
function createOptionalVariable(key, type, value, defaultValue) {
    if (value === undefined && defaultValue === undefined) {
        return;
    }
    let parsedValue = value ?? defaultValue;
    if (type === 'boolean') {
        parsedValue = parsedValue === 'true';
    }
    return { key, type, value: parsedValue };
}
function mablAuthToPostman(mablAuth, undefinedType) {
    let auth;
    if (mablAuth) {
        const { apikey, basic, bearer, oauth1, oauth2 } = mablAuth;
        const type = mablAuth.type;
        if (type === undefinedType) {
            return;
        }
        else if (type === exports.NO_AUTH) {
            auth = { type };
        }
        else if (type === exports.API_KEY_AUTH) {
            auth = {
                type,
                apikey: [
                    {
                        key: 'key',
                        value: apikey?.key,
                        type: 'string',
                    },
                    {
                        key: 'value',
                        value: apikey?.value,
                        type: 'string',
                    },
                    {
                        key: 'in',
                        value: apikey?.in,
                        type: 'string',
                    },
                ],
            };
        }
        else if (type === exports.BASIC_AUTH) {
            auth = {
                type,
                basic: [
                    {
                        key: 'username',
                        value: basic?.username,
                        type: 'string',
                    },
                    {
                        key: 'password',
                        value: basic?.password,
                        type: 'string',
                    },
                ],
            };
        }
        else if (type === exports.BEARER_TOKEN_AUTH) {
            auth = {
                type,
                bearer: [
                    {
                        key: 'token',
                        value: bearer?.token,
                        type: 'string',
                    },
                ],
            };
        }
        else if (type === exports.OAUTH1_AUTH) {
            auth = {
                type,
                oauth1: [
                    createOptionalVariable('addParamsToHeader', 'boolean', oauth1?.addParamsToHeader, exports.DEFAULT_ADD_OAUTH1_TO_HEADER_VALUE),
                    createOptionalVariable('addEmptyParamsToSign', 'boolean', oauth1?.addEmptyParamsToSign),
                    createOptionalVariable('callback', 'string', oauth1?.callback),
                    createOptionalVariable('consumerKey', 'string', oauth1?.consumerKey),
                    createOptionalVariable('consumerSecret', 'string', oauth1?.consumerSecret),
                    createOptionalVariable('includeBodyHash', 'boolean', oauth1?.includeBodyHash),
                    createOptionalVariable('nonce', 'string', oauth1?.nonce),
                    createOptionalVariable('realm', 'string', oauth1?.realm),
                    createOptionalVariable('signatureMethod', 'string', oauth1?.signatureMethod, exports.HMAC_SHA1_SIGNATURE),
                    createOptionalVariable('timestamp', 'string', oauth1?.timestamp),
                    createOptionalVariable('token', 'string', oauth1?.token),
                    createOptionalVariable('tokenSecret', 'string', oauth1?.tokenSecret),
                    createOptionalVariable('verifier', 'string', oauth1?.verifier),
                    createOptionalVariable('version', 'string', oauth1?.version, exports.DEFAULT_OAUTH1_VERSION),
                ].filter((variable) => variable),
            };
        }
        else if (type === exports.OAUTH2_AUTH) {
            auth = {
                type: exports.BEARER_TOKEN_AUTH,
                bearer: [
                    {
                        key: 'token',
                        value: `{{${oauth2?.tokenVariable}}}`,
                        type: 'string',
                    },
                ],
            };
        }
    }
    return auth;
}
function processItemAuth(item) {
    const mablAuth = item.mablTemporaryStorage?.mablAuth ?? item.mablAuth;
    const itemAuth = mablAuthToPostman(mablAuth, exports.INHERIT_AUTH_FROM_PARENT_VALUE);
    item.mablAuth = mablAuth;
    if (itemAuth) {
        item.request.auth = itemAuth;
        if (mablAuth?.oauth2) {
            const { oauth2 } = mablAuth;
            item.event = item.event ?? [];
            item.event.push(oauth2ConfigurationToPostmanEvent({
                access_token_url: oauth2.accessTokenUrl,
                client_credentials_location: oauth2.clientCredentialsLocation,
                client_id: oauth2.clientId,
                client_secret: oauth2.clientSecret,
                grant_type: oauth2.grantType,
                scope: oauth2.scope,
                token_variable: oauth2.tokenVariable,
            }));
        }
    }
}
function processItemGroupAuth(item) {
    const { mablAuth } = item;
    const itemAuth = mablAuthToPostman(mablAuth, exports.INHERIT_AUTH_FROM_PARENT_VALUE);
    if (itemAuth) {
        item.auth = itemAuth;
        if (mablAuth?.oauth2) {
            const { oauth2 } = mablAuth;
            item.event = item.event ?? [];
            item.event.push(oauth2ConfigurationToPostmanEvent({
                access_token_url: oauth2.accessTokenUrl,
                client_credentials_location: oauth2.clientCredentialsLocation,
                client_id: oauth2.clientId,
                client_secret: oauth2.clientSecret,
                grant_type: oauth2.grantType,
                scope: oauth2.scope,
                token_variable: oauth2.tokenVariable,
            }));
        }
    }
}
function removeInvalidHeaders(item) {
    if (item.request?.header) {
        item.request.header = item.request.header.filter((header) => header.key?.trim()?.length);
    }
}
function replaceRawScriptWithExecArray(eventsContainer, processingForRepair) {
    eventsContainer.event?.forEach((event) => {
        if (event.script) {
            if (!processingForRepair) {
                event.script.exec = splitLines(event.script.raw ?? '');
            }
            else if (event.script.raw && event.script.raw.length > 0) {
                event.script.exec = splitLines(event.script.raw);
            }
            delete event.script.raw;
        }
    });
}
function processPostmanItem(item) {
    if (!item.id) {
        item.id = (0, uuid_1.v4)();
    }
    processMablProtocolProfileBehavior(item);
    removeInvalidHeaders(item);
}
function insertMablAuthIntoCollection(items) {
    processPostmanItems([items, ...(items.item ?? [])], processItemAuth, processItemGroupAuth);
}
function insertMablScriptsIntoCollection(itemGroup, getSnippet) {
    itemGroup.event?.forEach((event) => insertMablScriptsIntoEvent(event, getSnippet));
    itemGroup.item?.forEach((item) => insertMablScriptsIntoCollection(item, getSnippet));
}
function insertMablScriptsIntoEvent(event, getSnippet) {
    removeMablGeneratedScripts(event);
    const mablScripts = createPostmanScript(convertMablSnippetsToExecArray(event, getSnippet), createMablGeneratedScripts(event));
    if (!event.mablSnippets) {
        mablScripts.exec = [...event.script.exec, ...mablScripts.exec];
    }
    event.script = mablScripts;
    delete event.mablAssertions;
    delete event.mablSnippets;
    delete event.mablVariables;
}
function wrapScriptInTryCatch(scriptLines, snippetName) {
    const escapedSnippetName = (0, mablscriptFind_1.escapeMablscriptString)(snippetName);
    return [
        `try {`,
        ...scriptLines,
        `} catch (mablSnippetError) {`,
        `  console.error("Error executing snippet:", mablSnippetError);`,
        `  pm.expect.fail("Snippet '${escapedSnippetName}' execution failed");`,
        `}`,
    ];
}
function createPostmanScript(...scripts) {
    return {
        id: (0, exports.uuid)(),
        exec: scripts.flatMap((lines) => lines),
        type: 'text/javascript',
    };
}
function convertMablSnippetsToExecArray(event, getSnippetFromInvariantId) {
    if (!event.mablSnippets) {
        return [];
    }
    const snippetBodies = event.mablSnippets.map((apiTestSnippet) => {
        const snippet = apiTestSnippet.reusable
            ? getSnippetFromInvariantId(apiTestSnippet.invariantId)
            : apiTestSnippet;
        if (!snippet?.body) {
            if (apiTestSnippet.reusable) {
                throw new Error(`Unable to find reusable snippet with invariant ID ${apiTestSnippet.invariantId}`);
            }
            return '';
        }
        const body = (0, encodingUtil_1.b64DecodeUnicodeNodeOrBrowser)(snippet.body);
        return wrapScriptInTryCatch([
            createCommentForApiTestSnippet(snippet, 'start'),
            body,
            createCommentForApiTestSnippet(snippet, 'end'),
            '',
        ], snippet.name ?? 'Unnamed snippet').join('\n');
    });
    return snippetBodies.flatMap((body) => body.split('\n'));
}
function createCommentForApiTestSnippet(snippet, position) {
    if (snippet.reusable) {
        return `// ${position} of reusable snippet "${snippet.name ?? snippet.id}"`;
    }
    return `// ${position} of one-time snippet "${snippet.name ?? snippet.id}"`;
}
function insertTestConfigurationIntoFlow(test, flow) {
    const collection = flow.api_steps;
    const testConfiguration = test.api_configuration;
    if (!testConfiguration) {
        return;
    }
    const { authentication, pre_request_snippets: preRequestSnippets, post_request_snippets: postRequestSnippets, } = testConfiguration;
    if ((!authentication || authentication.type === exports.NO_AUTH) &&
        !preRequestSnippets?.length &&
        !postRequestSnippets?.length) {
        return;
    }
    const folder = {
        name: flow.id ?? 'Flow',
        item: collection.item,
    };
    folder.auth = collection.auth;
    folder.mablAuth = collection.mablAuth;
    folder.event = collection.event;
    delete collection.auth;
    delete collection.mablAuth;
    delete collection.event;
    collection.item = [folder];
    if (authentication) {
        collection.mablAuth = apiTestAuthToMablAuth(authentication);
    }
    const event = [];
    if (preRequestSnippets?.length) {
        event.push(executableSnippetsToPostmanEvent(preRequestSnippets, 'prerequest'));
    }
    if (test.api_configuration?.authentication?.oauth2) {
        event.push(oauth2ConfigurationToPostmanEvent(test.api_configuration.authentication.oauth2));
    }
    if (postRequestSnippets?.length) {
        event.push(executableSnippetsToPostmanEvent(postRequestSnippets, 'test'));
    }
    if (event.length) {
        collection.event = event;
    }
}
function apiTestAuthToMablAuth(apiTestAuth) {
    const mablAuth = {
        type: apiTestAuth.type,
    };
    switch (apiTestAuth.type) {
        case 'apikey':
            mablAuth.apikey = {
                key: apiTestAuth.api_key?.key,
                value: apiTestAuth.api_key?.value,
                in: apiTestAuth.api_key?.location,
            };
            break;
        case 'basic':
            mablAuth.basic = {
                username: apiTestAuth.basic?.username,
                password: apiTestAuth.basic?.password,
            };
            break;
        case 'bearer':
            mablAuth.bearer = {
                token: apiTestAuth.bearer?.token,
            };
            break;
        case 'oauth1':
            mablAuth.oauth1 = {
                addParamsToHeader: apiTestAuth.oauth1?.add_parameters_to_header,
                addEmptyParamsToSign: apiTestAuth.oauth1?.add_empty_parameters_to_signature,
                callback: apiTestAuth.oauth1?.callback_url,
                consumerKey: apiTestAuth.oauth1?.consumer_key,
                consumerSecret: apiTestAuth.oauth1?.consumer_secret,
                includeBodyHash: apiTestAuth.oauth1?.include_body_hash,
                nonce: apiTestAuth.oauth1?.nonce,
                realm: apiTestAuth.oauth1?.realm,
                signatureMethod: apiTestAuth.oauth1?.signature_method,
                timestamp: apiTestAuth.oauth1?.timestamp,
                token: apiTestAuth.oauth1?.token,
                tokenSecret: apiTestAuth.oauth1?.token_secret,
                verifier: apiTestAuth.oauth1?.verifier,
                version: apiTestAuth.oauth1?.version,
            };
            break;
        case 'oauth2':
            mablAuth.oauth2 = {
                accessTokenUrl: apiTestAuth.oauth2.access_token_url,
                clientCredentialsLocation: apiTestAuth.oauth2.client_credentials_location,
                clientId: apiTestAuth.oauth2.client_id,
                clientSecret: apiTestAuth.oauth2.client_secret,
                grantType: apiTestAuth.oauth2.grant_type,
                scope: apiTestAuth.oauth2?.scope,
                tokenVariable: apiTestAuth.oauth2.token_variable,
            };
            break;
        case 'noauth':
            break;
    }
    return mablAuth;
}
function executableSnippetsToPostmanEvent(snippets, type) {
    return {
        id: (0, exports.uuid)(),
        listen: type,
        mablSnippets: snippets.map((snippet) => executableSnippetToApiTestSnippet(snippet)),
        script: {
            exec: [],
            id: (0, exports.uuid)(),
            type: 'text/javascript',
        },
    };
}
function executableSnippetToApiTestSnippet(executableSnippet) {
    const { invariant_id: invariantId, ...snippet } = { ...executableSnippet };
    if (executableSnippet.reusable) {
        return {
            invariantId: invariantId,
            reusable: true,
        };
    }
    return {
        ...snippet,
        reusable: false,
    };
}
function oauth2ConfigurationToPostmanEvent(auth) {
    return {
        id: (0, exports.uuid)(),
        listen: 'prerequest',
        script: {
            exec: [exports.MABL_GENERATED_COMMENT, ...generateOAuth2Script(auth).split('\n')],
            id: (0, exports.uuid)(),
            type: 'text/javascript',
        },
    };
}
function generateOAuth2Script(auth) {
    const { access_token_url: tokenUrl, client_credentials_location: clientCredentialsLocation, client_id: clientId, client_secret: clientSecret, token_variable: tokenVariable, } = auth;
    return `
    const tokenUrl = pm.variables.replaceIn('${tokenUrl}');
    const clientId = pm.variables.replaceIn('${clientId}');
    const clientSecret = pm.variables.replaceIn('${clientSecret}');
    const tokenVariable = pm.variables.replaceIn('${tokenVariable}');
    const expiresAtVariable = tokenVariable + '_expiresAtMillis';
    try {
      // Check if previously obtained token is still valid:
      if (pm.variables.has(tokenVariable) && pm.variables.get(tokenVariable)) { // Token exists and is not blank
        if (pm.variables.has(expiresAtVariable)) {
          const expiresAtMillis = Number.parseInt(pm.variables.get(expiresAtVariable));
          if (expiresAtMillis > Date.now()) {
            // Token is still valid
            console.log('Re-using existing token stored in variable ' + tokenVariable + ' which expires at ' + new Date(expiresAtMillis).toISOString());
            return;
          } else {
            console.log('Token stored in variable ' + tokenVariable + ' has expired');
          }
        } else {
          // We have a token but no expiration time, so we assume the token is still valid
          console.log('Re-using existing token stored in variable ' + tokenVariable + ' with no known expiration time');
          return;
        }
      }
      
      // Need to request a new token
      console.log('Requesting OAuth2 token from ' + tokenUrl + ' with client id ' + clientId + ' and storing obtained token in variable ' + tokenVariable);
      const tokenRequest = {
        method: 'POST',
        url: tokenUrl,
        auth: ${clientCredentialsLocation ===
        mablApi_1.OAuth2Authentication.ClientCredentialsLocationEnum.BasicAuthHeader
        ? `{
          type: 'basic',
          basic: {
            username: clientId,
            password: clientSecret
          }
        }`
        : 'undefined'},
        header: {
          Accept: 'application/json',
          'Content-Type': 'application/x-www-form-urlencoded'
        },
        body: {
          mode: 'urlencoded',
          urlencoded: JSON.parse(pm.variables.replaceIn(JSON.stringify(${generateOAuth2TokenRequestBodyParameters(auth)})))
        }
      };
      pm.sendRequest(tokenRequest, function (err, response) {
        // Check for errors:
        if (err) {
          pm.environment.unset(tokenVariable);
          pm.environment.unset(expiresAtVariable);
          console.error('Error requesting OAuth2 token:', err);
          pm.expect.fail('Error requesting OAuth2 token');
          return;
        }
        
        // Check for successful response:
        if (response.code !== 200) {
          pm.environment.unset(tokenVariable);
          pm.environment.unset(expiresAtVariable);
          console.error('Error requesting OAuth2 token: Response had unexpected status ' + response.code);
          ${generatePostmanTest('OAuth2 Token Request: Status code is 200', 'pm.expect(response.code).to.equal(200)')}
          return;
        }
        
        // Validate response, then extract and store access token and expiration time:
        let responseBody;
        try {
          responseBody = JSON.parse(response.text());
        } catch (e) {
          pm.environment.unset(tokenVariable);
          pm.environment.unset(expiresAtVariable);
          console.error('OAuth2 Token Request: Failed to parse response body as JSON:', e, response.text());
          pm.expect.fail('OAuth2 response body could not be parsed as JSON.');
          return;
        }
        
        if (!responseBody || typeof responseBody !== 'object') {
          pm.expect(responseBody, "OAuth2 response body should be a JSON object").to.be.an('object');
          return;
        }

        // Validate/extract/store access_token:
        if (responseBody.access_token) {
          pm.environment.set(tokenVariable, responseBody.access_token);
          console.log('OAuth2 Token successfully extracted and set to ' + tokenVariable + ' environment variable.');
        } else {
          pm.environment.unset(tokenVariable);
          pm.environment.unset(expiresAtVariable);
          console.error("OAuth2 Token Request: 'access_token' property was not found or was empty");
          pm.expect(responseBody.access_token, "OAuth2 response should have an 'access_token' property").to.exist;
          pm.expect(responseBody.access_token, "OAuth2 'access_token' should be a string").to.be.a('string');
          pm.expect(responseBody.access_token, "OAuth2 'access_token' should not be empty").to.not.be.empty;
          return;
        }
        
        // Check for optional expires_in and parse/store if found:
        if (responseBody.expires_in !== undefined) {
          if (!Number.parseInt(responseBody.expires_in)) {
            pm.expect(responseBody.expires_in, "OAuth2 'expires_in' should be a number").to.be.a('number');
            pm.expect(responseBody.expires_in, "OAuth2 'expires_in' should be greater than 0").to.be.greaterThan(0);
            console.error("OAuth2 Token Request: 'expires_in' property was defined but invalid: " + responseBody.expires_in);
            pm.environment.unset(expiresAtVariable);
            return;
          }
          const expiresAtMillis = Date.now() + (responseBody.expires_in * 1000);
          pm.environment.set(expiresAtVariable, expiresAtMillis);
          console.log('OAuth2 token stored in ' + tokenVariable + ' will expire at ' + new Date(expiresAtMillis).toISOString());
        } else {
          console.warn("OAuth2 Token Request: 'expires_in' property was not found in the response; assuming token does not expire");
          pm.environment.unset(expiresAtVariable);
        }
      });
    } catch (error) {
      console.error('Error obtaining OAuth2 token:', error);
      pm.environment.unset(tokenVariable);
      pm.environment.unset(expiresAtVariable);
    }
  `;
}
function generateOAuth2TokenRequestBodyParameters(auth) {
    const { client_credentials_location: clientCredentialsLocation, client_id: clientId, client_secret: clientSecret, grant_type: grantType, scope, } = auth;
    const parameters = [
        { key: 'grant_type', value: `${grantType}` },
    ];
    switch (clientCredentialsLocation) {
        case mablApi_1.OAuth2Authentication.ClientCredentialsLocationEnum.BasicAuthHeader:
            break;
        case mablApi_1.OAuth2Authentication.ClientCredentialsLocationEnum.Body:
            parameters.push({ key: 'client_id', value: `${clientId}` });
            parameters.push({ key: 'client_secret', value: `${clientSecret}` });
            break;
        default:
            throw new Error(`Unsupported client credentials location: [${clientCredentialsLocation}]`);
    }
    const trimmedScope = scope?.trim();
    if (trimmedScope) {
        parameters.push({ key: 'scope', value: trimmedScope });
    }
    return JSON.stringify(parameters);
}
function getValueFromAuthVariables(authVariables, variableName) {
    return authVariables?.find((variable) => variable.key === variableName)
        ?.value;
}
function postmanAuthToApiTestAuth(auth) {
    const { type: authType } = auth || {};
    if (!authType || authType === 'noauth') {
        return undefined;
    }
    const apiTestAuth = {
        type: authType,
    };
    const getValueFromVariablesForAuthType = (variableName) => getValueFromAuthVariables(auth[authType], variableName);
    switch (authType) {
        case 'apikey':
            apiTestAuth.api_key = {
                location: getValueFromVariablesForAuthType('in'),
                key: getValueFromVariablesForAuthType('key'),
                value: getValueFromVariablesForAuthType('value'),
            };
            break;
        case 'basic':
            apiTestAuth.basic = {
                username: getValueFromVariablesForAuthType('username'),
                password: getValueFromVariablesForAuthType('password'),
            };
            break;
        case 'bearer':
            apiTestAuth.bearer = {
                token: getValueFromVariablesForAuthType('token'),
            };
            break;
        case 'oauth1':
            apiTestAuth.oauth1 = {
                consumer_key: getValueFromVariablesForAuthType('consumerKey'),
                consumer_secret: getValueFromVariablesForAuthType('consumerSecret'),
                token: getValueFromVariablesForAuthType('token'),
                token_secret: getValueFromVariablesForAuthType('tokenSecret'),
                signature_method: getValueFromVariablesForAuthType('signatureMethod'),
                nonce: getValueFromVariablesForAuthType('nonce'),
                timestamp: getValueFromVariablesForAuthType('timestamp'),
                version: getValueFromVariablesForAuthType('version'),
                realm: getValueFromVariablesForAuthType('realm'),
                add_parameters_to_header: getValueFromVariablesForAuthType('addParamsToHeader'),
                add_empty_parameters_to_signature: getValueFromVariablesForAuthType('addEmptyParamsToSignature'),
                callback_url: getValueFromVariablesForAuthType('callbackUrl'),
                include_body_hash: getValueFromVariablesForAuthType('includeBodyHash'),
                verifier: getValueFromVariablesForAuthType('verifier'),
            };
            break;
        default:
            return undefined;
    }
    return apiTestAuth;
}
function mablAuthToApiAuthentication(mablAuth) {
    const resolvedAuth = resolveMablAuth(mablAuth, exports.NO_AUTH);
    const authType = newman_types_1.MABL_AUTH_TYPES.filter((auth) => auth !== exports.INHERIT_AUTH_FROM_PARENT_VALUE).find((auth) => auth === resolvedAuth.type) ?? exports.NO_AUTH;
    const apiAuthentication = {
        type: authType,
    };
    if (!mablAuth) {
        return apiAuthentication;
    }
    switch (authType) {
        case 'noauth':
            return apiAuthentication;
        case 'apikey':
            apiAuthentication.api_key = {
                key: resolvedAuth.apikey?.key,
                location: resolvedAuth.apikey?.in,
                value: resolvedAuth.apikey?.value,
            };
            break;
        case 'basic':
            apiAuthentication.basic = {
                username: resolvedAuth.basic?.username,
                password: resolvedAuth.basic?.password,
            };
            break;
        case 'bearer':
            apiAuthentication.bearer = {
                token: resolvedAuth.bearer?.token,
            };
            break;
        case 'oauth1':
            apiAuthentication.oauth1 = {
                add_parameters_to_header: resolvedAuth.oauth1?.addParamsToHeader,
                add_empty_parameters_to_signature: mablAuth.oauth1?.addEmptyParamsToSign,
                callback_url: resolvedAuth.oauth1?.callback,
                consumer_key: resolvedAuth.oauth1?.consumerKey,
                consumer_secret: resolvedAuth.oauth1?.consumerSecret,
                include_body_hash: resolvedAuth.oauth1?.includeBodyHash,
                nonce: resolvedAuth.oauth1?.nonce,
                realm: resolvedAuth.oauth1?.realm,
                signature_method: resolvedAuth.oauth1
                    ?.signatureMethod,
                timestamp: resolvedAuth.oauth1?.timestamp,
                token: resolvedAuth.oauth1?.token,
                token_secret: resolvedAuth.oauth1?.tokenSecret,
                verifier: resolvedAuth.oauth1?.verifier,
                version: resolvedAuth.oauth1?.version,
            };
            break;
        case 'oauth2':
            apiAuthentication.oauth2 = {
                access_token_url: resolvedAuth.oauth2?.accessTokenUrl,
                client_id: resolvedAuth.oauth2?.clientId,
                client_secret: resolvedAuth.oauth2?.clientSecret,
                client_credentials_location: resolvedAuth.oauth2?.clientCredentialsLocation ??
                    exports.DEFAULT_OAUTH2_CLIENT_CREDENTIALS_LOCATION,
                grant_type: resolvedAuth.oauth2?.grantType ?? exports.DEFAULT_OAUTH2_GRANT_TYPE,
                scope: resolvedAuth.oauth2?.scope,
                token_variable: resolvedAuth.oauth2?.tokenVariable,
            };
            break;
        default:
            throw new Error(`Unsupported authentication type: ${resolvedAuth.type}`);
    }
    return apiAuthentication;
}
function resolveMablAuth(mablAuth, defaultMablAuthType = exports.INHERIT_AUTH_FROM_PARENT_VALUE) {
    if (!mablAuth || !newman_types_1.MABL_AUTH_TYPES.includes(mablAuth.type)) {
        return { type: defaultMablAuthType };
    }
    if (mablAuth.oauth2) {
        if (!mablAuth.oauth2.clientCredentialsLocation) {
            mablAuth.oauth2.clientCredentialsLocation =
                mablApi_1.OAuth2Authentication.ClientCredentialsLocationEnum.BasicAuthHeader;
        }
        if (!mablAuth.oauth2.grantType) {
            mablAuth.oauth2.grantType =
                mablApi_1.OAuth2Authentication.GrantTypeEnum.ClientCredentials;
        }
        if (!mablAuth.oauth2.tokenVariable) {
            mablAuth.oauth2.tokenVariable = `oauth2Token_${(0, object_hash_1.default)(mablAuth.oauth2)}`;
        }
    }
    return mablAuth;
}
function postmanEventToExecutableSnippets(event) {
    if (!event) {
        return [];
    }
    return (event.mablSnippets?.map((snippet) => {
        if (snippet.reusable) {
            const executableSnippet = {
                invariant_id: snippet.invariantId,
                reusable: true,
            };
            return executableSnippet;
        }
        const executableSnippet = {
            reusable: false,
            body: snippet.body,
            description: snippet.description,
            name: snippet.name,
            snippet_type: snippet.snippet_type,
            workspace_id: snippet.workspace_id,
        };
        return executableSnippet;
    }) ?? []);
}
const uuid = () => (0, uuid_1.v4)();
exports.uuid = uuid;
function getSnippetReferencesInCollection(collection) {
    const referencesFromEvents = (collection.event ?? [])
        .flatMap((event) => event.mablSnippets ?? [])
        .filter((snippet) => snippet.reusable)
        .map((snippet) => ({
        id: snippet.invariantId,
        snippetType: mablApi_1.SnippetTypeEnum.Postman,
    }));
    const referencesFromItems = (collection.item ?? []).flatMap((item) => {
        const itemEventRefs = (item.event ?? [])
            .flatMap((event) => event.mablSnippets ?? [])
            .filter((snippet) => snippet.reusable)
            .map((snippet) => ({
            id: snippet.invariantId,
            snippetType: mablApi_1.SnippetTypeEnum.Postman,
        }));
        if (isItemGroupDefinition(item)) {
            return [...itemEventRefs, ...getSnippetReferencesInCollection(item)];
        }
        return itemEventRefs;
    });
    return [...referencesFromItems, ...referencesFromEvents];
}
function getSnippetReferencesInTest(test) {
    return (test.api_configuration?.pre_request_snippets ?? [])
        .concat(test.api_configuration?.post_request_snippets ?? [])
        .filter((snippet) => snippet.reusable)
        .map(({ invariant_id: invariantId }) => ({
        id: invariantId,
        snippetType: mablApi_1.SnippetTypeEnum.Postman,
    }));
}
async function fetchSnippetsForApiTestAndFlows(test, flows, getSnippet) {
    const snippetReferencesInFlows = flows.flatMap((flow) => getSnippetReferencesInCollection(flow.api_steps));
    const snippetReferencesInTest = getSnippetReferencesInTest(test);
    const snippetReferences = snippetReferencesInFlows.concat(snippetReferencesInTest);
    const snippetPromises = snippetReferences.map(async ({ id }) => getSnippet(id));
    const snippets = (await Promise.all(snippetPromises)).reduce((snippetsById, snippet) => {
        snippetsById[snippet.invariant_id] = snippet;
        return snippetsById;
    }, {});
    return snippets;
}
async function exportPostmanTestAsCollection(test, flows, getSnippet, nestedFlows) {
    const allFlows = [...flows, ...(nestedFlows ?? [])];
    const flowInvariantIdToFlow = allFlows.reduce((mappings, flow) => {
        mappings[flow.invariant_id] = flow;
        return mappings;
    }, {});
    const collection = wrapItemsInCollection(test.name ?? test.invariant_id ?? test.id ?? 'mabl API Test', await Promise.all(test.flows
        ?.map((id) => id.split(':')[0])
        .map((invariant) => flowInvariantIdToFlow[invariant])
        .map((flow) => exportPostmanFlow(flow, getSnippet, test)) ?? []));
    return collection;
}
async function exportPostmanFlowAsCollection(flow, getSnippet, test) {
    const collection = wrapItemsInCollection(flow.description ?? flow.invariant_id ?? flow.id ?? 'mabl API Flow', [await exportPostmanFlow(flow, getSnippet, test)]);
    return collection;
}
async function exportPostmanFlow(flow, getSnippet, test) {
    const apiSteps = flow.api_steps;
    processPostmanItems(apiSteps?.item, (item) => {
        processPostmanItem(item);
        if (!item.name) {
            item.name = `${item.request?.method} ${item.request?.url?.host.join('.')}/${item.request?.url?.path.join('/')}`;
        }
    });
    if (test) {
        insertTestConfigurationIntoFlow(test, flow);
        insertTestVariablesIntoFlow(test, flow);
    }
    const snippets = await fetchSnippetsForApiTestAndFlows(test ?? {}, [flow], getSnippet);
    const idToSnippet = (id) => snippets[id];
    insertMablScriptsIntoCollection(apiSteps, idToSnippet);
    return apiSteps.item;
}
function insertTestVariablesIntoFlow(test, flow) {
    const testVariables = test.variables?.inputs ?? [];
    flow.api_steps.variable = testVariables.map(convertTestVariableToCollectionVariable);
}
function convertTestVariableToCollectionVariable(variable) {
    return {
        key: variable.name,
        value: variable.default_value,
    };
}
function wrapItemsInCollection(name, items) {
    const flattenedItems = items
        .flatMap((item) => item.item ?? item)
        .filter((item) => item);
    return {
        info: {
            name,
            schema: 'https://schema.getpostman.com/json/collection/v2.1.0/collection.json',
        },
        item: flattenedItems,
    };
}
function filterDisabledStepsFromJourney(journey, flows) {
    const survivingIndices = [];
    const filteredFlows = flows.filter((flow, index) => {
        const hasEnabledSteps = (flow.api_steps?.item ?? []).some((step) => !step.disabled);
        if (hasEnabledSteps) {
            survivingIndices.push(index);
        }
        return hasEnabledSteps;
    });
    let remappedFlowConfiguration = journey.flow_configuration;
    if (journey.flow_configuration && survivingIndices.length !== flows.length) {
        remappedFlowConfiguration = {};
        survivingIndices.forEach((originalIndex, newIndex) => {
            const config = journey.flow_configuration?.[originalIndex];
            if (config) {
                remappedFlowConfiguration[newIndex] = config;
            }
        });
    }
    return {
        ...journey,
        flows: filteredFlows.map((flow) => flow.id),
        flow_configuration: remappedFlowConfiguration,
    };
}
function filterDisabledStepsFromFlows(flows) {
    return flows
        .map((flow) => {
        if (!flow.api_steps) {
            return flow;
        }
        const filteredSteps = (flow.api_steps.item ?? []).filter((step) => !step.disabled);
        return {
            ...flow,
            api_steps: {
                ...flow.api_steps,
                item: filteredSteps,
            },
        };
    })
        .filter((flow) => flow.flow_type !== 'api' || flow.api_steps.item.length > 0);
}
function itemToItemNameOrUrl(item) {
    return (item.name || item.request?.url?.raw) ?? '';
}
function itemToStepTitle(item) {
    const name = itemToItemNameOrUrl(item);
    return `${item.request?.method} ${name}`;
}
function buildVariableStepSources(items, nextStepNumberToExecute, isReusable) {
    const stepSources = {};
    items.forEach((item, index) => {
        const stepNumber = isReusable
            ? `${nextStepNumberToExecute}.${index + 1}`
            : `${nextStepNumberToExecute + index}`;
        item.event?.forEach((event) => {
            event.mablVariables?.forEach((variable) => {
                if (variable.variableName) {
                    stepSources[(0, VariableUtils_1.addUserNamespace)(variable.variableName)] = {
                        stepId: item.id,
                        stepNumber,
                    };
                }
            });
        });
    });
    return stepSources;
}
