UNPKG

@fs-eire/wgsl-template

Version:

A powerful template system for generating WGSL (WebGPU Shading Language) code with support for parameters, conditionals, and multiple output formats including C++ code generation.

93 lines 3.75 kB
import * as fs from "fs/promises"; import * as path from "path"; import { resolveCodeGenerator } from "./code-generator-impl.js"; import { generator } from "./generator-impl.js"; import { loader } from "./loader-impl.js"; import { parser } from "./parser-impl.js"; import { WgslTemplateBuildError } from "./errors.js"; // Export error types export * from "./errors.js"; // Export loader functions export { loader } from "./loader-impl.js"; export const build = async (options) => { let pass0; let pass1; let pass2; let files; try { // Validate that sourceDirs is provided if (!options.sourceDirs || options.sourceDirs.length === 0) { throw new WgslTemplateBuildError("sourceDirs must be provided and cannot be empty", "invalid-options", {}); } // Load templates using the multi-directory loader pass0 = await loader.loadFromDirectories(options.sourceDirs, { ext: options.templateExt }); pass1 = parser.parse(pass0); const codeGenerator = resolveCodeGenerator(options.generator); pass2 = generator.generateDirectory(pass1, codeGenerator, { preserveCodeReference: options.preserveCodeReference, }); const files = codeGenerator.build(pass2, { templateExt: options.templateExt, includePathPrefix: options.includePathPrefix, }); // Write files to the output directory const basePath = path.resolve(options.outDir); for (const [filePath, result] of files.templates) { try { const fullPath = path.resolve(basePath, filePath); // Security check: ensure the resolved path is within the output directory if (!fullPath.startsWith(basePath + path.sep) && fullPath !== basePath) { throw new WgslTemplateBuildError(`Security violation: attempted to write file outside output directory: ${filePath}`, "path-security-violation", { filePath }); } const dirName = path.dirname(fullPath); // Create the directory if it doesn't exist await fs.mkdir(dirName, { recursive: true }); // Only write the file if content has changed let shouldWrite = true; try { const existingContent = await fs.readFile(fullPath, "utf8"); shouldWrite = existingContent !== result; } catch { // File doesn't exist or can't be read, so we should write it shouldWrite = true; } if (shouldWrite) { await fs.writeFile(fullPath, result, "utf8"); } // Record successful file write await fs.stat(fullPath); } catch (error) { return { status: "file-write-error", error: error instanceof Error ? error : new Error(String(error)), result: { pass0, pass1, pass2, files, }, }; } } return { status: "success", result: { pass0, pass1, pass2, files }, }; } catch (error) { const errorObj = error instanceof Error ? error : new Error(String(error)); return { status: "build-error", error: errorObj, result: { pass0, pass1, pass2, files, }, }; } }; //# sourceMappingURL=index.js.map