From d667276fa1b49565709e035b28f52d551973e065 Mon Sep 17 00:00:00 2001
From: mike12345567 <me@michaeldrury.co.uk>
Date: Fri, 27 Jan 2023 15:15:07 +0000
Subject: [PATCH] Adding a onlyFound option to our handlebars system so that we
 can enrich only the parts we have and leave other components for further
 enrichment.

---
 .../src/sdk/app/datasources/datasources.ts    |  5 ++++-
 .../string-templates/src/helpers/index.js     |  6 +++++-
 packages/string-templates/src/index.js        | 21 ++++++++++++++++---
 packages/string-templates/test/basic.spec.js  |  6 ++++++
 4 files changed, 33 insertions(+), 5 deletions(-)

diff --git a/packages/server/src/sdk/app/datasources/datasources.ts b/packages/server/src/sdk/app/datasources/datasources.ts
index ed18e43928..8ad08ce980 100644
--- a/packages/server/src/sdk/app/datasources/datasources.ts
+++ b/packages/server/src/sdk/app/datasources/datasources.ts
@@ -11,6 +11,7 @@ import { getEnvironmentVariables } from "../../utils"
 import { getDefinitions } from "../../../integrations"
 
 const ENV_VAR_PREFIX = "env."
+const USER_PREFIX = "user"
 
 async function enrichDatasourceWithValues(datasource: Datasource) {
   const cloned = cloneDeep(datasource)
@@ -48,7 +49,9 @@ export async function getWithEnvVars(datasourceId: string) {
 
 export function isValid(datasource: Datasource) {
   const blocks = findHBSBlocks(JSON.stringify(datasource))
-  const validList = blocks.filter(block => block.includes(ENV_VAR_PREFIX))
+  const validList = blocks.filter(
+    block => block.includes(ENV_VAR_PREFIX) || block.includes(USER_PREFIX)
+  )
   return blocks.length === validList.length
 }
 
diff --git a/packages/string-templates/src/helpers/index.js b/packages/string-templates/src/helpers/index.js
index f04fa58399..bed3d0c3e3 100644
--- a/packages/string-templates/src/helpers/index.js
+++ b/packages/string-templates/src/helpers/index.js
@@ -32,11 +32,15 @@ const HELPERS = [
   // javascript helper
   new Helper(HelperFunctionNames.JS, processJS, false),
   // this help is applied to all statements
-  new Helper(HelperFunctionNames.ALL, (value, { __opts }) => {
+  new Helper(HelperFunctionNames.ALL, (value, inputs) => {
+    const { __opts } = inputs
     if (isObject(value)) {
       return new SafeString(JSON.stringify(value))
     }
     // null/undefined values produce bad results
+    if (__opts && __opts.onlyFound && value == null) {
+      return __opts.input
+    }
     if (value == null || typeof value !== "string") {
       return value == null ? "" : value
     }
diff --git a/packages/string-templates/src/index.js b/packages/string-templates/src/index.js
index ab7afc1dcc..26f44369b0 100644
--- a/packages/string-templates/src/index.js
+++ b/packages/string-templates/src/index.js
@@ -146,16 +146,31 @@ module.exports.processStringSync = (string, context, opts) => {
   if (typeof string !== "string") {
     throw "Cannot process non-string types."
   }
-  try {
-    const template = createTemplate(string, opts)
+  function process(stringPart) {
+    const template = createTemplate(stringPart, opts)
     const now = Math.floor(Date.now() / 1000) * 1000
     return processors.postprocess(
       template({
         now: new Date(now).toISOString(),
-        __opts: opts,
+        __opts: {
+          ...opts,
+          input: stringPart,
+        },
         ...context,
       })
     )
+  }
+  try {
+    if (opts && opts.onlyFound) {
+      const blocks = exports.findHBSBlocks(string)
+      for (let block of blocks) {
+        const outcome = process(block)
+        string = string.replace(block, outcome)
+      }
+      return string
+    } else {
+      return process(string)
+    }
   } catch (err) {
     return input
   }
diff --git a/packages/string-templates/test/basic.spec.js b/packages/string-templates/test/basic.spec.js
index 8dd1aeb394..3346a81ddd 100644
--- a/packages/string-templates/test/basic.spec.js
+++ b/packages/string-templates/test/basic.spec.js
@@ -221,3 +221,9 @@ describe("check find hbs blocks function", () => {
   })
 })
 
+describe("should leave HBS blocks if not found using option", () => {
+  it("should replace one, leave one", async () => {
+    const output = await processString("{{ a }}, {{ b }}", { b: 1 }, { onlyFound: true })
+    expect(output).toBe("{{ a }}, 1")
+  })
+})