diff --git a/package-lock.json b/package-lock.json index bff62fa5e0..5c9f9fa641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -74,6 +74,7 @@ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", "dev": true, + "optional": true, "requires": { "is-extendable": "^0.1.0" } @@ -111,7 +112,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -132,12 +134,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -152,17 +156,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -279,7 +286,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -291,6 +299,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -305,6 +314,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -312,12 +322,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -336,6 +348,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -416,7 +429,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -428,6 +442,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -513,7 +528,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -549,6 +565,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -568,6 +585,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -611,12 +629,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -647,7 +667,8 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true + "dev": true, + "optional": true }, "is-glob": { "version": "4.0.1", @@ -7550,7 +7571,7 @@ }, "callsites": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "resolved": "http://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", "dev": true }, @@ -9820,7 +9841,8 @@ "ansi-regex": { "version": "2.1.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "aproba": { "version": "1.2.0", @@ -9841,12 +9863,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9861,17 +9885,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -9988,7 +10015,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -10000,6 +10028,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -10014,6 +10043,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -10021,12 +10051,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.3.5", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.2", "yallist": "^3.0.0" @@ -10045,6 +10077,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -10125,7 +10158,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -10137,6 +10171,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -10222,7 +10257,8 @@ "safe-buffer": { "version": "5.1.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "safer-buffer": { "version": "2.1.2", @@ -10258,6 +10294,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -10277,6 +10314,7 @@ "version": "3.0.1", "bundled": true, "dev": true, + "optional": true, "requires": { "ansi-regex": "^2.0.0" } @@ -10320,12 +10358,14 @@ "wrappy": { "version": "1.0.2", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "yallist": { "version": "3.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true } } }, @@ -16131,7 +16171,8 @@ "version": "0.3.2", "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true + "dev": true, + "optional": true }, "braces": { "version": "2.3.2", @@ -16394,7 +16435,8 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true + "dev": true, + "optional": true }, "micromatch": { "version": "3.1.10", @@ -16622,7 +16664,7 @@ }, "resolve": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "resolved": "http://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", "dev": true }, @@ -17062,7 +17104,7 @@ }, "minimist": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "resolved": "http://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true } diff --git a/packages/insomnia-app/app/common/__tests__/render.test.js b/packages/insomnia-app/app/common/__tests__/render.test.js index 6914f1d322..5d7e9af0e8 100644 --- a/packages/insomnia-app/app/common/__tests__/render.test.js +++ b/packages/insomnia-app/app/common/__tests__/render.test.js @@ -31,6 +31,35 @@ describe('render()', () => { expect(err.message).toContain('expected variable end'); } }); + + it('handles variables using tag before tag is defined as expected (incorrect order)', async () => { + const rootEnvironment = { + type: models.environment.type, + data: { + consume: '{{ replaced }}', + hashed: "{% hash 'md5', 'hex', value %}", + replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}", + value: 'ThisIsATopSecretValue', + }, + dataPropertyOrder: { + '&': ['value', 'replaced', 'hashed', 'consume'], + }, + }; + + const context = await renderUtils.buildRenderContext([], rootEnvironment); + + expect(context).toEqual({ + value: 'ThisIsATopSecretValue', + hashed: 'f67565de946a899a534fd908e7eef872', + replaced: 'f67565de946a899a534fd908e7eef872', + consume: 'f67565de946a899a534fd908e7eef872', + }); + + // In runtime, this context is used to render, which re-evaluates the expression for replaced in the rootEnvironment by using the built context + // Regression test from issue 1917 - https://github.com/Kong/insomnia/issues/1917 + const renderExpression = await renderUtils.render(rootEnvironment.data.replaced, context); + expect(renderExpression).toBe('cat'); + }); }); describe('buildRenderContext()', () => { @@ -399,6 +428,30 @@ describe('buildRenderContext()', () => { }); }); + it('handles variables using tag after tag is defined as expected (correct order)', async () => { + const rootEnvironment = { + type: models.environment.type, + data: { + consume: '{{ replaced }}', + hashed: "{% hash 'md5', 'hex', value %}", + replaced: "{{ hashed | replace('f67565de946a899a534fd908e7eef872', 'cat') }}", + value: 'ThisIsATopSecretValue', + }, + dataPropertyOrder: { + '&': ['value', 'hashed', 'replaced', 'consume'], + }, + }; + + const context = await renderUtils.buildRenderContext([], rootEnvironment); + + expect(context).toEqual({ + value: 'ThisIsATopSecretValue', + hashed: 'f67565de946a899a534fd908e7eef872', + replaced: 'cat', + consume: 'cat', + }); + }); + it('handles variables being used in tags', async () => { const rootEnvironment = { type: models.environment.type, diff --git a/packages/insomnia-app/app/common/constants.js b/packages/insomnia-app/app/common/constants.js index c9f83a3e50..f61ca47991 100644 --- a/packages/insomnia-app/app/common/constants.js +++ b/packages/insomnia-app/app/common/constants.js @@ -177,6 +177,10 @@ export const AUTH_ASAP = 'asap'; export const HAWK_ALGORITHM_SHA256 = 'sha256'; export const HAWK_ALGORITHM_SHA1 = 'sha1'; +// json-order constants +export const JSON_ORDER_PREFIX = '&'; +export const JSON_ORDER_SEPARATOR = `~|`; + const authTypesMap = { [AUTH_BASIC]: ['Basic', 'Basic Auth'], [AUTH_DIGEST]: ['Digest', 'Digest Auth'], diff --git a/packages/insomnia-app/app/common/render.js b/packages/insomnia-app/app/common/render.js index 98268d3a6d..904beb2054 100644 --- a/packages/insomnia-app/app/common/render.js +++ b/packages/insomnia-app/app/common/render.js @@ -5,11 +5,12 @@ 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 { CONTENT_TYPE_GRAPHQL, JSON_ORDER_PREFIX } 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'; +import orderedJSON from 'json-order'; export const KEEP_ON_ERROR = 'keep'; export const THROW_ON_ERROR = 'throw'; @@ -36,23 +37,41 @@ export async function buildRenderContext( ): Object { const envObjects = []; + // Get root environment keys in correct order + // Then get sub environment keys in correct order + // Then get ancestor (folder) environment keys in correct order if (rootEnvironment) { - envObjects.push(rootEnvironment.data); + const ordered = orderedJSON.order( + rootEnvironment.data, + rootEnvironment.dataPropertyOrder, + JSON_ORDER_PREFIX, + ); + + envObjects.push(ordered); } if (subEnvironment) { - envObjects.push(subEnvironment.data); + const ordered = orderedJSON.order( + subEnvironment.data, + subEnvironment.dataPropertyOrder, + JSON_ORDER_PREFIX, + ); + + envObjects.push(ordered); } for (const doc of (ancestors || []).reverse()) { - const environment = (doc: any).environment; + const ancestor: any = doc; + const { environment, environmentPropertyOrder } = ancestor; if (typeof environment === 'object' && environment !== null) { - envObjects.push(environment); + const ordered = orderedJSON.order(environment, environmentPropertyOrder, JSON_ORDER_PREFIX); + envObjects.push(ordered); } } // At this point, environments is a list of environments ordered - // from top-most parent to bottom-most child + // from top-most parent to bottom-most child, and they keys in each environment + // ordered by its property map. // Do an Object.assign, but render each property as it overwrites. This // way we can keep same-name variables from the parent context. let renderContext = baseContext; @@ -437,13 +456,7 @@ export async function getRenderedRequest( * @returns {number} */ function _nunjucksSortValue(v) { - if (v && v.match && v.match(/({%)/)) { - return 3; - } else if (v && v.match && v.match(/({{)/)) { - return 2; - } else { - return 1; - } + return v && v.match && v.match(/({{|{%)/) ? 2 : 1; } function _getOrderedEnvironmentKeys(finalRenderContext: Object): Array { diff --git a/packages/insomnia-app/app/ui/components/editors/environment-editor.js b/packages/insomnia-app/app/ui/components/editors/environment-editor.js index 57af39c457..26891433f2 100644 --- a/packages/insomnia-app/app/ui/components/editors/environment-editor.js +++ b/packages/insomnia-app/app/ui/components/editors/environment-editor.js @@ -3,6 +3,7 @@ import * as React from 'react'; import autobind from 'autobind-decorator'; import CodeEditor from '../codemirror/code-editor'; import orderedJSON from 'json-order'; +import { JSON_ORDER_PREFIX, JSON_ORDER_SEPARATOR } from '../../../common/constants'; export type EnvironmentInfo = { object: Object, @@ -77,7 +78,11 @@ class EnvironmentEditor extends React.PureComponent { getValue(): EnvironmentInfo | null { if (this._editor) { - const data = orderedJSON.parse(this._editor.getValue(), '&', `~|`); + const data = orderedJSON.parse( + this._editor.getValue(), + JSON_ORDER_PREFIX, + JSON_ORDER_SEPARATOR, + ); return { object: data.object, @@ -111,7 +116,7 @@ class EnvironmentEditor extends React.PureComponent { const defaultValue = orderedJSON.stringify( environmentInfo.object, environmentInfo.propertyOrder || null, - '~|', + JSON_ORDER_SEPARATOR, ); return ( diff --git a/packages/insomnia-app/flow-typed/json-order.js b/packages/insomnia-app/flow-typed/json-order.js index dd8b3d198b..031b25d8c1 100644 --- a/packages/insomnia-app/flow-typed/json-order.js +++ b/packages/insomnia-app/flow-typed/json-order.js @@ -14,6 +14,11 @@ declare module 'json-order' { separator?: string, space?: number | void, ) => string, + order: ( + sourceObject: Object, + map: { [key: string]: Array } | null, + separator?: string, + ) => Object, }; declare module.exports: orderedJSON; diff --git a/packages/insomnia-app/package-lock.json b/packages/insomnia-app/package-lock.json index bcde0b8ba8..5c546dca87 100644 --- a/packages/insomnia-app/package-lock.json +++ b/packages/insomnia-app/package-lock.json @@ -8004,11 +8004,6 @@ "buffer-indexof": "^1.0.0" } }, - "docopt": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/docopt/-/docopt-0.6.2.tgz", - "integrity": "sha1-so6eIiDaXsSffqW7JKR3h0Be6xE=" - }, "doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -8088,15 +8083,6 @@ "domelementtype": "1" } }, - "dot-json": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/dot-json/-/dot-json-1.1.0.tgz", - "integrity": "sha512-PiQZW9/C8xILPYK2bOye/cbPZrakNEkt28jFb8RlPCwsoMAHYYw9T8JoACxgttHL9Y2AmdqVvibbZJHtLgeqTQ==", - "requires": { - "docopt": "~0.6.2", - "underscore-keypath": "~0.0.22" - } - }, "dot-prop": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.0.tgz", @@ -12000,11 +11986,10 @@ "dev": true }, "json-order": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/json-order/-/json-order-1.0.12.tgz", - "integrity": "sha512-MLopfzLoZ71XfI04Ox68N1PbIti2phuTyu4TvZaTok/Eq90iBq5e/3Bd9NbW+lXpe3GxdsijC/UsyAwTLmCoUA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/json-order/-/json-order-1.1.0.tgz", + "integrity": "sha512-xiULVQOg6+JbST7xwGvhoBUJJ6kOiBUM6zgeGSp5TisNpPd0iyqJDWPNi0Kd7K88A/I6784O+AXaczURK3SSLg==", "requires": { - "dot-json": "^1.1.0", "lodash.clonedeep": "^4.5.0" } }, @@ -18262,14 +18247,6 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.9.1.tgz", "integrity": "sha512-5/4etnCkd9c8gwgowi5/om/mYO5ajCaOgdzj/oW+0eQV9WxKBDZw5+ycmKmeaTXjInS/W0BzpGLo2xR2aBwZdg==" }, - "underscore-keypath": { - "version": "0.0.22", - "resolved": "https://registry.npmjs.org/underscore-keypath/-/underscore-keypath-0.0.22.tgz", - "integrity": "sha1-SKUoOSu278QkvhyqVtpLX6zPJk0=", - "requires": { - "underscore": "*" - } - }, "unfetch": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/unfetch/-/unfetch-4.1.0.tgz", diff --git a/packages/insomnia-app/package.json b/packages/insomnia-app/package.json index e27b41beba..efbdeed4ce 100644 --- a/packages/insomnia-app/package.json +++ b/packages/insomnia-app/package.json @@ -155,7 +155,7 @@ "insomnia-prettify": "^2.1.4", "insomnia-url": "^2.1.4", "insomnia-xpath": "^2.1.4", - "json-order": "^1.0.12", + "json-order": "^1.1.0", "jsonlint": "^1.6.3", "jsonpath": "^1.0.2", "jwt-authentication": "^0.4.0",