From 8df80152a4bea513b861348879145278139f5850 Mon Sep 17 00:00:00 2001 From: Vladimir Vagaytsev <10628074+vvagaytsev@users.noreply.github.com> Date: Wed, 28 Aug 2024 16:29:10 +0200 Subject: [PATCH] fix(template): fix template string escaping and resolution in Module configs (#6408) * fix(template): skip un-escaping while module vars resolution Patches commit 8df3a4f5fe2997495ff184e399d4b6bd0bdf9864 from #5680. Module variables are resolved in a standalone function `resolveVariables`. That function should also skip un-escaping. * fix(template): fix function definition Use its own argument instead of a closure. * refactor(template): pull function `shouldUnescape` up * fix(template): fix too greedy pattern for escaped string --- core/src/resolve-module.ts | 9 ++++++++- core/src/template-string/parser.pegjs | 2 +- core/src/template-string/template-string.ts | 18 +++++++++--------- 3 files changed, 18 insertions(+), 11 deletions(-) diff --git a/core/src/resolve-module.ts b/core/src/resolve-module.ts index ae27f69a22..430dd37d53 100644 --- a/core/src/resolve-module.ts +++ b/core/src/resolve-module.ts @@ -932,7 +932,14 @@ export class ModuleResolver { templateContextParams: ModuleConfigContextParams ): Promise { const moduleConfigContext = new ModuleConfigContext(templateContextParams) - const resolveOpts = { allowPartial: false } + const resolveOpts = { + allowPartial: false, + // Modules will be converted to actions later, and the actions will be properly unescaped. + // We avoid premature un-escaping here, + // because otherwise it will strip the escaped value in the module config + // to the normal template string in the converted action config. + unescape: false, + } let varfileVars: DeepPrimitiveMap = {} if (config.varfile) { diff --git a/core/src/template-string/parser.pegjs b/core/src/template-string/parser.pegjs index 770437b014..4df9f6602c 100644 --- a/core/src/template-string/parser.pegjs +++ b/core/src/template-string/parser.pegjs @@ -57,7 +57,7 @@ TemplateString / $(.*) { return text() === "" ? [] : [{ resolved: text() }] } FormatString - = EscapeStart SourceCharacter* FormatEndWithOptional { + = EscapeStart (!FormatEndWithOptional SourceCharacter)* FormatEndWithOptional { if (options.unescape) { return text().slice(1) } else { diff --git a/core/src/template-string/template-string.ts b/core/src/template-string/template-string.ts index 91524dbb92..dc4e5040cb 100644 --- a/core/src/template-string/template-string.ts +++ b/core/src/template-string/template-string.ts @@ -96,6 +96,15 @@ export class TemplateError extends GardenError { } } +const shouldUnescape = (ctxOpts: ContextResolveOpts) => { + // Explicit non-escaping takes the highest priority. + if (ctxOpts.unescape === false) { + return false + } + + return !!ctxOpts.unescape || !ctxOpts.allowPartial +} + /** * Parse and resolve a templated string, with the given context. The template format is similar to native JS templated * strings but only supports simple lookups from the given context, e.g. "prefix-${nested.key}-suffix", and not @@ -120,15 +129,6 @@ export const resolveTemplateString = profile(function resolveTemplateString({ return string } - const shouldUnescape = (ctxOpts: ContextResolveOpts) => { - // Explicit non-escaping takes the highest priority. - if (ctxOpts.unescape === false) { - return false - } - - return !!ctxOpts.unescape || !contextOpts.allowPartial - } - try { const parsed = parser.parse(string, { getKey: (key: string[], resolveOpts?: ContextResolveOpts) => {