<commit_before>// @flow
import type { Request } from '../models/request';
import type { BaseModel } from '../models/index';

import { setDefaultProtocol } from 'insomnia-url';
import clone from 'clone';
import * as models from '../models';
import { CONTENT_TYPE_GRAPHQL } from '../common/constants';
import * as db from './database';
import * as templating from '../templating';
import type { CookieJar } from '../models/cookie-jar';
import type { Environment } from '../models/environment';

export const KEEP_ON_ERROR = 'keep';
export const THROW_ON_ERROR = 'throw';

export type RenderPurpose = 'send' | 'general' | 'no-render';

export const RENDER_PURPOSE_SEND: RenderPurpose = 'send';
export const RENDER_PURPOSE_GENERAL: RenderPurpose = 'general';
export const RENDER_PURPOSE_NO_RENDER: RenderPurpose = 'no-render';

/** Key/value pairs to be provided to the render context */
export type ExtraRenderInfo = Array<{ name: string, value: any }>;

export type RenderedRequest = Request & {
  cookies: Array<{ name: string, value: string, disabled?: boolean }>,
  cookieJar: CookieJar,
};

export async function buildRenderContext(
  ancestors: Array<BaseModel> | null,
  rootEnvironment: Environment | null,
  subEnvironment: Environment | null,
  baseContext: Object = {},
): Object {
  const envObjects = [];

  if (rootEnvironment) {
    envObjects.push(rootEnvironment.data);
  }

  if (subEnvironment) {
    envObjects.push(subEnvironment.data);
  }

  for (const doc of (ancestors || []).reverse()) {
    const environment = (doc: any).environment;
    if (typeof environment === 'object' && environment !== null) {
      envObjects.push(environment);
    }
  }

  // At this point, environments is a list of environments ordered
  // from top-most parent to bottom-most child
  // Do an Object.assign, but render each property as it overwrites. This
  // way we can keep same-name variables from the parent context.
  const renderContext = baseContext;
  for (const envObject: Object of envObjects) {
    const keys = _getOrderedEnvironmentKeys(envObject);
    for (const key of keys) {
      /*
       * If we're overwriting a string, try to render it first using the same key from the base
       * environment to support same-variable recursion. This allows for the following scenario:
       *
       * base:  { base_url: 'google.com' }
       * obj:   { base_url: '{{ base_url }}/foo' }
       * final: { base_url: 'google.com/foo' }
       *
       * A regular Object.assign would yield { base_url: '{{ base_url }}/foo' } and the
       * original base_url of google.com would be lost.
       */
      if (typeof renderContext[key] === 'string') {
        const isSelfRecursive = envObject[key].match(`{{ ?${key}[ |][^}]*}}`);

        if (isSelfRecursive) {
          // If we're overwriting a variable that contains itself, make sure we
          // render it first
          renderContext[key] = await render(
            envObject[key],
            renderContext, // Only render with key being overwritten
            null,
            KEEP_ON_ERROR,
            'Environment',
          );
        } else {
          // Otherwise it's just a regular replacement
          renderContext[key] = envObject[key];
        }
      } else {<commit_msg>Fix type check on render (Fixes #1786)<commit_after>// @flow
import type { Request } from '../models/request';
import type { BaseModel } from '../models/index';

import { setDefaultProtocol } from 'insomnia-url';
import clone from 'clone';
import * as models from '../models';
import { CONTENT_TYPE_GRAPHQL } from '../common/constants';
import * as db from './database';
import * as templating from '../templating';
import type { CookieJar } from '../models/cookie-jar';
import type { Environment } from '../models/environment';

export const KEEP_ON_ERROR = 'keep';
export const THROW_ON_ERROR = 'throw';

export type RenderPurpose = 'send' | 'general' | 'no-render';

export const RENDER_PURPOSE_SEND: RenderPurpose = 'send';
export const RENDER_PURPOSE_GENERAL: RenderPurpose = 'general';
export const RENDER_PURPOSE_NO_RENDER: RenderPurpose = 'no-render';

/** Key/value pairs to be provided to the render context */
export type ExtraRenderInfo = Array<{ name: string, value: any }>;

export type RenderedRequest = Request & {
  cookies: Array<{ name: string, value: string, disabled?: boolean }>,
  cookieJar: CookieJar,
};

export async function buildRenderContext(
  ancestors: Array<BaseModel> | null,
  rootEnvironment: Environment | null,
  subEnvironment: Environment | null,
  baseContext: Object = {},
): Object {
  const envObjects = [];

  if (rootEnvironment) {
    envObjects.push(rootEnvironment.data);
  }

  if (subEnvironment) {
    envObjects.push(subEnvironment.data);
  }

  for (const doc of (ancestors || []).reverse()) {
    const environment = (doc: any).environment;
    if (typeof environment === 'object' && environment !== null) {
      envObjects.push(environment);
    }
  }

  // At this point, environments is a list of environments ordered
  // from top-most parent to bottom-most child
  // Do an Object.assign, but render each property as it overwrites. This
  // way we can keep same-name variables from the parent context.
  const renderContext = baseContext;
  for (const envObject: Object of envObjects) {
    const keys = _getOrderedEnvironmentKeys(envObject);
    for (const key of keys) {
      /*
       * If we're overwriting a string, try to render it first using the same key from the base
       * environment to support same-variable recursion. This allows for the following scenario:
       *
       * base:  { base_url: 'google.com' }
       * obj:   { base_url: '{{ base_url }}/foo' }
       * final: { base_url: 'google.com/foo' }
       *
       * A regular Object.assign would yield { base_url: '{{ base_url }}/foo' } and the
       * original base_url of google.com would be lost.
       */
      if (typeof envObject[key] === 'string') {
        const isSelfRecursive = envObject[key].match(`{{ ?${key}[ |][^}]*}}`);

        if (isSelfRecursive) {
          // If we're overwriting a variable that contains itself, make sure we
          // render it first
          renderContext[key] = await render(
            envObject[key],
            renderContext, // Only render with key being overwritten
            null,
            KEEP_ON_ERROR,
            'Environment',
          );
        } else {
          // Otherwise it's just a regular replacement
          renderContext[key] = envObject[key];
        }
      } else {
{'fraction_non_alphanumeric': 0.1194508009153318, 'fraction_numerical': 0.0006102212051868803, 'mean_word_length': 3.019619865113427, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 9, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7380265', 'n_tokens_mistral': 1894, 'n_tokens_neox': 1866, 'n_words': 620}