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(/ /g, " ") 125 expect(result).toEqual(js) 126 }) 127 }) 128 }) 129 }