async function processTemplate()

in experimental/generation/generator/packages/library/src/dialogGenerator.ts [418:558]


async function processTemplate(
    templateName: string,
    templateDirs: string[],
    transforms: Transform[],
    globalTransforms: Transform[],
    outDir: string,
    scope: any,
    force: boolean,
    feedback: Feedback,
    ignorable: boolean): Promise<string> {
    let outPath = ''
    const oldDir = process.cwd()
    try {
        const ref = existingRef(templateName, scope.templates)
        if (ref) {
            // Simple file already existed
            feedback(FeedbackType.debug, `Reusing ${templateName}`)
            outPath = ppath.join(outDir, ref.relative)
        } else {
            const foundTemplate = await findTemplate(templateName, templateDirs)
            if (foundTemplate !== undefined) {
                const lgTemplate: lg.Templates | undefined = foundTemplate instanceof lg.Templates ? foundTemplate as lg.Templates : undefined
                const plainTemplate: Plain | undefined = !lgTemplate ? foundTemplate as Plain : undefined
                // Ignore templates that are defined, but are empty
                if (plainTemplate?.source || lgTemplate?.allTemplates.some(f => f.name === 'generator')) {
                    // Constant file or .lg template so output
                    feedback(FeedbackType.debug, `Using template ${plainTemplate ? plainTemplate.source : lgTemplate?.id}`)

                    let filename = addPrefix(scope.prefix, templateName)
                    if (lgTemplate?.allTemplates.some(t => t.name === 'filename')) {
                        try {
                            filename = lgTemplate.evaluate('filename', scope) as string
                        } catch (e) {
                            throw new Error(`${templateName}: ${(e as Error).message}`)
                        }
                    } else {
                        // Infer name
                        const locale = filename.includes(scope.locale) ? `${scope.locale}/` : ''
                        filename = `${assetDirectory(ppath.extname(filename))}${locale}${scope.property ?? 'form'}/${ppath.basename(filename)}`
                    }

                    outPath = ppath.join(outDir, filename)
                    const ref = addFileRef(outPath, outDir, scope.prefix, scope.templates)
                    if (ref) {
                        // This is a new file
                        if (force || !await fs.pathExists(outPath)) {
                            feedback(FeedbackType.info, `Generating ${outPath}`)
                            // Add prefix to constant imports
                            let result = plainTemplate ? addPrefixToImports(plainTemplate.template, scope) : undefined
                            if (lgTemplate) {
                                process.chdir(ppath.dirname(lgTemplate.allTemplates[0].sourceRange.source))
                                result = lgTemplate.evaluate('generator', scope) as string
                                process.chdir(oldDir)
                                if (Array.isArray(result)) {
                                    result = result.join(os.EOL)
                                }
                            }

                            // See if generated file has been overridden in templates
                            const existing = await findTemplate(filename, templateDirs) as Plain
                            if (existing && existing.source.endsWith(ppath.normalize(filename))) {
                                feedback(FeedbackType.info, `  Overridden by ${existing.source}`)
                                result = existing.template
                            }

                            // Ignore empty templates
                            if (result) {
                                if (transforms.length > 0 || globalTransforms.length > 0) {
                                    // Apply transforms
                                    let body = result
                                    let converted = false
                                    try {
                                        body = JSON.parse(result)
                                        converted = true
                                    } catch (e) {
                                    }
                                    for (const transform of [...transforms, ...globalTransforms]) {
                                        const newBody = transform.template.evaluate(transform.name, {...scope, ref, body})
                                        if (!compareObjects(newBody, body)) {
                                            feedback(FeedbackType.debug, `${transform.name} changed ${outPath}`)
                                            body = newBody
                                        }
                                    }
                                    result = converted ? stringify(body) : body
                                }
                                const resultString = result as string
                                if (resultString.includes('**MISSING**')) {
                                    feedback(FeedbackType.error, `${outPath} has **MISSING** data`)
                                } else {
                                    const match = resultString.match(/\*\*([^0-9\s]+)[0-9]+\*\*/)
                                    if (match) {
                                        feedback(FeedbackType.warning, `Replace **${match[1]}<N>** with values in ${outPath}`)
                                    }
                                }
                                await writeFile(outPath, resultString, feedback)
                                scope.templates[ref.extension].push(ref)
                            }
                        } else {
                            feedback(FeedbackType.warning, `Skipping already existing ${outPath}`)
                        }
                    }
                } else if (lgTemplate) {
                    // Pick up # transforms
                    if (lgTemplate.allTemplates.some(f => f.name == 'transforms')) {
                        let newTransforms = lgTemplate.evaluate('transforms', scope)
                        if (!Array.isArray(newTransforms)) {
                            newTransforms = [newTransforms]
                        }
                        for (const transform of newTransforms) {
                            feedback(FeedbackType.debug, `Adding transform ${transform}`)
                            transforms.push({name: transform, template: lgTemplate})
                        }
                    }

                    // Expand # generators
                    if (lgTemplate.allTemplates.some(f => f.name === 'generators')) {
                        feedback(FeedbackType.debug, `Expanding template ${lgTemplate.id}`)
                        let generated = lgTemplate.evaluate('generators', scope)
                        if (!Array.isArray(generated)) {
                            generated = [generated]
                        }
                        for (const generate of generated as any as string[]) {
                            feedback(FeedbackType.debug, `  ${generate}`)
                        }
                        for (const generate of generated as any as string[]) {
                            await processTemplate(generate, templateDirs, transforms, globalTransforms, outDir, scope, force, feedback, false)
                        }
                    }

                }
            } else if (!ignorable) {
                feedback(FeedbackType.error, `Missing template ${templateName}`)
            }
        }
    } catch (e) {
        feedback(FeedbackType.error, (e as Error).message)
    } finally {
        process.chdir(oldDir)
    }
    return outPath
}