diff --git a/packages/ui/src/helpers.ts b/packages/ui/src/helpers.ts index 7c2cafa9..d0dc6ffa 100644 --- a/packages/ui/src/helpers.ts +++ b/packages/ui/src/helpers.ts @@ -24,7 +24,8 @@ import { import { ActionContext } from 'vuex' import { version } from '../../electron/package.json' import constants from '@/constants' -import { handleTags } from '@/utils/tag' +import { handleResponseTag } from '@/utils/tag' +import { handleTags } from '@/parsers/tag' // From: https://stackoverflow.com/a/67802481/4932305 export function toTree(array: CollectionItem[]): CollectionItem[] { @@ -101,7 +102,7 @@ export async function substituteEnvironmentVariables( substitutedString = substitutedString.replaceAll(`{{ ${objectPath} }}`, objectPathValue) }) - substitutedString = await handleTags(substitutedString, tagTrigger, cacheId, noError) + substitutedString = await handleTags(handleResponseTag, substitutedString, tagTrigger, cacheId, noError) return substitutedString } diff --git a/packages/ui/src/parsers/tag.spec.ts b/packages/ui/src/parsers/tag.spec.ts index 9beb613f..212745bf 100644 --- a/packages/ui/src/parsers/tag.spec.ts +++ b/packages/ui/src/parsers/tag.spec.ts @@ -1,5 +1,5 @@ import { test, expect } from 'vitest' -import { tagRegex, parseFunction, toFunctionString } from './tag' +import { tagRegex, parseFunction, toFunctionString, handleTags, ParsedResult } from './tag' const sumInput = 'sum(a=1, b=2)' const sumParsedResult = { @@ -67,3 +67,27 @@ test('tagRegex', async() => { expect(flattenedMatches).toEqual(expectedMatches) }) + +test('handleTags: #311', async() => { + const input = `{ + "a": "{% response(attribute='body', behavior='never', maxAge=60, request='JB-6w6Kp0YXPBU72__o2W', path='b64::YXJncy5h') %}", + "b": "{% response(attribute='body', behavior='never', maxAge=60, request='JB-6w6Kp0YXPBU72__o2W', path='b64::YXJncy5i') %}" + }` + + const expectedOutput = `{ + "a": "10", + "b": "20" + }` + + const handleResponseTag = (parsedResult: ParsedResult) => { + if (parsedResult.parameters.path === 'args.a') { + return '10' + } + + if (parsedResult.parameters.path === 'args.b') { + return '20' + } + } + + expect(await handleTags(handleResponseTag, input, false, undefined, true)).toEqual(expectedOutput) +}) diff --git a/packages/ui/src/parsers/tag.ts b/packages/ui/src/parsers/tag.ts index fd186378..f7b32c3d 100644 --- a/packages/ui/src/parsers/tag.ts +++ b/packages/ui/src/parsers/tag.ts @@ -74,3 +74,42 @@ export function toFunctionString(parsedResult: ParsedResult): string { const paramsString = paramsArray.join(', ') return `${functionName}(${paramsString})` } + +export async function handleTags(handleResponseTag: Function, string: string, tagTrigger: boolean, cacheId: string | undefined, noError: boolean) { + const regex = tagRegex + let matches = [...string.matchAll(regex)] + // Reverse matches to avoid shifting indexes when replacing text - cause of issue #311 + matches = matches.reverse() + + for(const match of matches) { + const fullMatch = match[0] + const start = match.index! + const end = start + fullMatch.length + + // console.log(`Match: ${fullMatch}, Start: ${start}, End: ${end}`) + + const parsedTag = parseFunction(match[1], true) + + let replacement = undefined + + if (parsedTag.functionName === 'response') { + replacement = await handleResponseTag(parsedTag, tagTrigger, cacheId) + } + + if (replacement === undefined) { + if (noError) { + replacement = '' + } else { + const at = `${string.slice(0, start)}━>${parsedTag.functionName}(...)<━${string.slice(end)}` + + throw new Error(`Could not resolve tag\n\n${toFunctionString(parsedTag)}\n\nat ${at}`, { + cause: 'display-error' + }) + } + } + + string = string.slice(0, start) + replacement + string.slice(end) + } + + return string +} diff --git a/packages/ui/src/utils/tag.ts b/packages/ui/src/utils/tag.ts index 92304822..d9b2fc18 100644 --- a/packages/ui/src/utils/tag.ts +++ b/packages/ui/src/utils/tag.ts @@ -63,7 +63,7 @@ async function getResponseForRequest( return latestResponse } -async function handleResponseTag(parsedTag: tagParser.ParsedResult, tagTrigger: boolean, cacheId: string | undefined) { +export async function handleResponseTag(parsedTag: tagParser.ParsedResult, tagTrigger: boolean, cacheId: string | undefined) { let returnValue = undefined const cacheKey = cacheId + JSON.stringify(parsedTag) @@ -124,40 +124,3 @@ async function handleResponseTag(parsedTag: tagParser.ParsedResult, tagTrigger: return returnValue } - -export async function handleTags(string: string, tagTrigger: boolean, cacheId: string | undefined, noError: boolean) { - const regex = tagParser.tagRegex - const matches = [...string.matchAll(regex)] - - for(const match of matches) { - const fullMatch = match[0] - const start = match.index! - const end = start + fullMatch.length - - // console.log(`Match: ${fullMatch}, Start: ${start}, End: ${end}`) - - const parsedTag = tagParser.parseFunction(match[1], true) - - let replacement = undefined - - if (parsedTag.functionName === 'response') { - replacement = await handleResponseTag(parsedTag, tagTrigger, cacheId) - } - - if (replacement === undefined) { - if (noError) { - replacement = '' - } else { - const at = `${string.slice(0, start)}━>${parsedTag.functionName}(...)<━${string.slice(end)}` - - throw new Error(`Could not resolve tag\n\n${tagParser.toFunctionString(parsedTag)}\n\nat ${at}`, { - cause: 'display-error' - }) - } - } - - string = string.slice(0, start) + replacement + string.slice(end) - } - - return string -}