UNPKG

@baseplate-dev/sync

Version:

Library for syncing Baseplate descriptions

139 lines 4.81 kB
import { promises as fs } from 'node:fs'; import path from 'node:path'; /** * Builder for the output of a generator task that collects the files and * commands that need to be run */ export class GeneratorTaskOutputBuilder { /** * The output of the generator */ output; /** * The info of the current generator */ generatorInfo; /** * The id of the current generator */ generatorId; /** * The dynamic tasks that have been added to the output */ dynamicTasks = []; /** * Options for template metadata */ metadataOptions; constructor(context) { this.output = { files: new Map(), postWriteCommands: [], globalFormatters: [], }; this.generatorInfo = context.generatorInfo; this.generatorId = context.generatorId; this.metadataOptions = context.templateMetadataOptions ?? { includeTemplateMetadata: false, shouldGenerateMetadata: () => false, }; } /** * Reads a template file from the generator base directory * * @param templatePath The path to the template file relative to the templates directory * @returns The contents of the template file */ readTemplate(templatePath) { const fullPath = path.join(this.generatorInfo.baseDirectory, 'templates', templatePath); return fs.readFile(fullPath, 'utf8'); } /** * Writes a file to the output * * @param payload The payload for the file to write */ writeFile({ id, destination: filePath, contents, options, generatorName, templateInfo, }) { // normalize all paths to POSIX style / paths and remove any preceding @/ const fullPath = filePath .replaceAll(path.sep, path.posix.sep) .replace(/^(@\/)?/, ''); if (this.output.files.has(fullPath)) { throw new Error(`Cannot overwrite file ${fullPath}`); } if (contents instanceof Buffer && !options?.skipFormatting) { throw new Error(`Cannot format Buffer contents for ${fullPath}`); } this.output.files.set(fullPath, { id: `${generatorName ?? this.generatorInfo.name}:${id}`, contents, options: this.metadataOptions.includeTemplateMetadata && templateInfo ? { ...options, templateInfo, } : options, }); } /** * Adds a post write command to the output * * @param command The command to run * @param commandType The type of the command * @param options The options for the command */ addPostWriteCommand(command, options) { this.output.postWriteCommands.push({ command, options }); } /** * Applies one or more actions to the builder * * @param actions The actions to apply */ async apply(...actions) { for (const action of actions) { await action.execute(this); } } /** * Adds a formatter to the output that will be applied to all files depending on their extension * * @param formatter The formatter to add */ addGlobalFormatter(formatter) { // check if formatter already exists for given extensions const existingFormatter = this.output.globalFormatters.find((f) => f.fileExtensions?.some((ext) => formatter.fileExtensions?.includes(ext))); if (existingFormatter) { throw new Error(`Formatter ${formatter.name} already exists for file extensions ${formatter.fileExtensions?.join(', ')}`); } if (formatter.fileNames) { const existingFormatter = this.output.globalFormatters.find((f) => f.fileNames?.some((name) => formatter.fileNames?.includes(name))); if (existingFormatter) { throw new Error(`Formatter ${formatter.name} already exists for file names ${formatter.fileNames.join(', ')}`); } } this.output.globalFormatters.push(formatter); } /** * Adds a dynamic task to the output * * @param name The name of the task * @param task The task to add */ addDynamicTask(name, task) { if (this.dynamicTasks.some((t) => t.name === name)) { throw new Error(`Dynamic task ${name} already exists`); } if (!task.phase) { throw new Error(`Dynamic task ${name} must have a phase`); } this.dynamicTasks.push({ id: `${this.generatorId}#${name}`, name, task, generatorId: this.generatorId, generatorInfo: this.generatorInfo, }); } } //# sourceMappingURL=generator-task-output.js.map