utils.ts
  1  import { getManifest } from "../src"
  2  import { getJsHelperList } from "../src/helpers"
  3  
  4  import { convertToJS, processStringSync, encodeJSBinding } from "../src/index"
  5  
  6  function tryParseJson(str: string) {
  7    if (typeof str !== "string") {
  8      return
  9    }
 10  
 11    try {
 12      return JSON.parse(str.replace(/'/g, '"'))
 13    } catch (e) {
 14      // do nothing
 15    }
 16  }
 17  
 18  type ExampleType = [
 19    string,
 20    {
 21      hbs: string
 22      js: string
 23      requiresHbsBody: boolean
 24    },
 25  ]
 26  
 27  export const getParsedManifest = () => {
 28    const manifest: any = getManifest()
 29    const collections = Object.keys(manifest)
 30  
 31    const examples = collections.reduce(
 32      (acc, collection) => {
 33        const functions = Object.entries<{
 34          example: string
 35          requiresBlock: boolean
 36        }>(manifest[collection])
 37          .filter(
 38            ([, details]) =>
 39              details.example?.split("->").map(x => x.trim()).length > 1
 40          )
 41          .map(([name, details]): ExampleType => {
 42            const example = details.example
 43            let [hbs, js] = example.split("->").map(x => x.trim())
 44  
 45            // Trim 's
 46            js = js.replace(/^'|'$/g, "")
 47            let parsedExpected: string
 48            if ((parsedExpected = tryParseJson(js))) {
 49              if (Array.isArray(parsedExpected)) {
 50                if (typeof parsedExpected[0] === "object") {
 51                  js = JSON.stringify(parsedExpected)
 52                } else {
 53                  js = parsedExpected.join(",")
 54                }
 55              }
 56            }
 57            const requiresHbsBody = details.requiresBlock
 58            return [name, { hbs, js, requiresHbsBody }]
 59          })
 60  
 61        if (functions.length) {
 62          acc[collection] = functions
 63        }
 64        return acc
 65      },
 66      {} as Record<string, ExampleType[]>
 67    )
 68  
 69    return examples
 70  }
 71  
 72  export const runJsHelpersTests = ({
 73    funcWrap,
 74    testsToSkip,
 75  }: {
 76    funcWrap?: any
 77    testsToSkip?: any
 78  } = {}) => {
 79    funcWrap = funcWrap || ((delegate: () => any) => delegate())
 80    const manifest = getParsedManifest()
 81  
 82    const processJS = (js: string, context: object | undefined) => {
 83      return funcWrap(() => processStringSync(encodeJSBinding(js), context))
 84    }
 85  
 86    function escapeRegExp(string: string) {
 87      return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&") // $& means the whole matched string
 88    }
 89  
 90    describe("can be parsed and run as js", () => {
 91      const jsHelpers = getJsHelperList()!
 92      const jsExamples = Object.keys(manifest).reduce(
 93        (acc, v) => {
 94          acc[v] = manifest[v].filter(([key]) => jsHelpers[key])
 95          return acc
 96        },
 97        {} as typeof manifest
 98      )
 99  
100      describe.each(Object.keys(jsExamples))("%s", collection => {
101        const examplesToRun = jsExamples[collection]
102          .filter(([, { requiresHbsBody }]) => !requiresHbsBody)
103          .filter(([key]) => !testsToSkip?.includes(key))
104  
105        examplesToRun.length &&
106          it.each(examplesToRun)("%s", async (_, { hbs, js }) => {
107            const context: any = {
108              double: (i: number) => i * 2,
109              isString: (x: any) => typeof x === "string",
110            }
111  
112            const arrays = hbs.match(/\[[^/\]]+\]/)
113            arrays?.forEach((arrayString, i) => {
114              hbs = hbs.replace(
115                new RegExp(escapeRegExp(arrayString)),
116                `array${i}`
117              )
118              context[`array${i}`] = JSON.parse(arrayString.replace(/'/g, '"'))
119            })
120  
121            let convertedJs = convertToJS(hbs)
122  
123            let result = await processJS(convertedJs, context)
124            result = result.replace(/&nbsp;/g, " ")
125            expect(result).toEqual(js)
126          })
127      })
128    })
129  }