From 451205b24670cc3d61b71e4342fea5c7411a9243 Mon Sep 17 00:00:00 2001 From: Patrik Oldsberg Date: Sat, 8 Feb 2025 21:09:11 +0100 Subject: [PATCH] cli/new: refactor templater to make it stateful Signed-off-by: Patrik Oldsberg --- .../lib/new/execution/PortableTemplater.ts | 51 +++++++++++-------- .../execution/executePluginPackageTemplate.ts | 29 ++++------- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/packages/cli/src/lib/new/execution/PortableTemplater.ts b/packages/cli/src/lib/new/execution/PortableTemplater.ts index bce0d211af..8e5e9251d4 100644 --- a/packages/cli/src/lib/new/execution/PortableTemplater.ts +++ b/packages/cli/src/lib/new/execution/PortableTemplater.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import handlebars, { HelperDeclareSpec } from 'handlebars'; +import handlebars from 'handlebars'; import { PortableTemplateParams } from '../types'; import camelCase from 'lodash/camelCase'; import kebabCase from 'lodash/kebabCase'; @@ -39,12 +39,13 @@ const builtInHelpers = { lowerFirst, }; -type CreateTemplaterOptions = { - helpers?: HelperDeclareSpec; +type CreatePortableTemplaterOptions = { + values?: PortableTemplateParams; + templatedValues?: Record; }; export class PortableTemplater { - static async create() { + static async create(options: CreatePortableTemplaterOptions = {}) { let lockfile: Lockfile | undefined; try { lockfile = await Lockfile.load(paths.resolveTargetRoot('yarn.lock')); @@ -54,8 +55,8 @@ export class PortableTemplater { const versionProvider = createPackageVersionProvider(lockfile); - return new PortableTemplater({ - helpers: { + const templater = new PortableTemplater( + { versionQuery(name: string, versionHint: string | unknown) { return versionProvider( name, @@ -63,36 +64,44 @@ export class PortableTemplater { ); }, }, - }); + options.values ?? {}, + ); + + if (options.templatedValues) { + templater.appendTemplatedValues(options.templatedValues); + } + + return templater; } readonly #templater: typeof handlebars; + #values: PortableTemplateParams; - private constructor(options: CreateTemplaterOptions = {}) { + private constructor( + helpers: handlebars.HelperDeclareSpec, + values: PortableTemplateParams, + ) { this.#templater = handlebars.create(); this.#templater.registerHelper(builtInHelpers); - if (options.helpers) { - this.#templater.registerHelper(options.helpers); + if (helpers) { + this.#templater.registerHelper(helpers); } + + this.#values = values; } - template(content: string, values: PortableTemplateParams): string { + template(content: string): string { return this.#templater.compile(content, { strict: true, - })(values); + })(this.#values); } - templateRecord( - record: Record, - values: PortableTemplateParams, - ): Record { - return Object.fromEntries( - Object.entries(record).map(([key, value]) => [ - key, - this.template(value, values), - ]), + appendTemplatedValues(record: Record): void { + const newValues = Object.fromEntries( + Object.entries(record).map(([key, value]) => [key, this.template(value)]), ); + this.#values = { ...this.#values, ...newValues }; } } diff --git a/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts b/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts index 885684b627..30f0de1488 100644 --- a/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts +++ b/packages/cli/src/lib/new/execution/executePluginPackageTemplate.ts @@ -49,12 +49,11 @@ export async function executePluginPackageTemplate( try { const tempDir = await tmpDirManager.createDir('backstage-create'); const isMonoRepo = await getIsMonoRepo(); - const templater = await PortableTemplater.create(); - const templatedValues = templater.templateRecord( - template.templateValues, - input.params, - ); + const templater = await PortableTemplater.create({ + values: input.params, + templatedValues: template.templateValues, + }); for (const file of template.files) { if (isMonoRepo && file.path === 'tsconfig.json') { @@ -64,20 +63,14 @@ export async function executePluginPackageTemplate( const destPath = resolvePath(tempDir, file.path); await fs.ensureDir(dirname(destPath)); - if (file.syntax === 'handlebars') { - let content = file.content; + const content = + file.syntax === 'handlebars' + ? templater.template(file.content) + : file.content; - if (file.syntax === 'handlebars') { - content = templater.template(file.content, { - ...input.params, - ...templatedValues, - }); - } - - await fs.writeFile(destPath, content).catch(error => { - throw new ForwardedError(`Failed to copy file to ${destPath}`, error); - }); - } + await fs.writeFile(destPath, content).catch(error => { + throw new ForwardedError(`Failed to copy file to ${destPath}`, error); + }); } // Format package.json if it exists