UNPKG

kist

Version:

Package Pipeline Processor

177 lines (158 loc) 6.44 kB
// ============================================================================ // Import // ============================================================================ import fs from "fs/promises"; import path from "path"; import { Action } from "../../core/pipeline/Action"; import { ActionOptionsType } from "../../types/ActionOptionsType.js"; import packageConfig from "./package.config.js"; // ============================================================================ // Classes // ============================================================================ /** * PackageManagerAction handles reading, validating, and creating `package.json` * files, supporting custom configurations and merging with selected fields. */ export class PackageManagerAction extends Action { /** * Executes the package management action. * Reads an existing `package.json`, extracts selected fields, and writes a new one. * * @param options - Options specifying input path, output directory, and fields to export. * @returns A Promise that resolves when the action is completed successfully. * @throws {Error} Throws an error if neither `packageJsonPath` nor `outputDir` is provided. */ async execute(options: ActionOptionsType): Promise<void> { const { packageJsonPath, outputDir, fields = [], // Specify which fields to copy customConfig = {}, } = options; if (!packageJsonPath) { throw new Error("The 'packageJsonPath' option is required."); } if (!outputDir) { throw new Error("The 'outputDir' option is required."); } const existingConfig = await this.readPackageJson(packageJsonPath); const filteredConfig = this.filterFields(existingConfig, fields); await this.createPackageJson(outputDir, filteredConfig, customConfig); } /** * Reads and parses an existing `package.json`. * * @param packageJsonPath - Path to the `package.json` file. * @returns Parsed JSON object. * @throws {Error} If the file does not exist or contains invalid JSON. */ private async readPackageJson( packageJsonPath: string, ): Promise<Record<string, unknown>> { const fullPath = path.resolve(packageJsonPath); try { const fileContent = await fs.readFile(fullPath, "utf-8"); const parsedContent = JSON.parse(fileContent); this.logInfo(`Successfully read package.json from ${fullPath}`); return parsedContent; } catch (error: any) { if (error.code === "ENOENT") { throw new Error( `File not found at ${fullPath}. Please ensure the path is correct.`, ); } else if (error.name === "SyntaxError") { throw new Error( `Invalid JSON in ${fullPath}: ${error.message}`, ); } else { throw new Error( `Unexpected error while reading ${fullPath}: ${error.message}`, ); } } } /** * Filters specified fields from a `package.json` object. * * @param config - The original package.json object. * @param fields - List of fields to extract. * @returns A new object containing only the selected fields. */ private filterFields( config: Record<string, unknown>, fields: string[], ): Record<string, unknown> { if (!fields.length) { return config; // If no fields are specified, return the full config. } const filteredConfig: Record<string, unknown> = {}; for (const field of fields) { if (config[field] !== undefined) { filteredConfig[field] = config[field]; } } this.logInfo( `Filtered package.json fields: ${JSON.stringify(filteredConfig, null, 2)}`, ); return filteredConfig; } /** * Creates a `package.json` file with selected fields and custom overrides. * * @param outputDir - Directory where the new `package.json` will be created. * @param filteredConfig - The filtered package.json fields. * @param customConfig - Custom overrides to apply. * @returns A Promise that resolves when the file has been successfully created. * @throws {Error} If the file cannot be written. */ private async createPackageJson( outputDir: string, filteredConfig: Record<string, any>, customConfig: Record<string, any>, ): Promise<void> { const filePath = path.join(outputDir, "package.json"); // Merge default settings with filtered config and custom overrides const finalConfig = { ...packageConfig, ...filteredConfig, ...customConfig, }; const data = JSON.stringify(finalConfig, null, 2); try { await this.ensureDirectoryExists(outputDir); await fs.writeFile(filePath, data, "utf-8"); this.logInfo(`package.json successfully created at ${filePath}`); } catch (error) { this.logError("Error creating package.json", error); throw error; } } /** * Ensures that the specified directory exists, creating it if it does not. * * @param dirPath - The path of the directory to verify or create. * @returns A Promise that resolves once the directory is verified or created. * @throws {Error} If the directory cannot be created. */ private async ensureDirectoryExists(dirPath: string): Promise<void> { try { await fs.mkdir(dirPath, { recursive: true }); } catch (error) { if ((error as NodeJS.ErrnoException).code !== "EEXIST") { throw error; } } } /** * Provides a description of the action. * * @returns A string description of the action. */ describe(): string { return "Reads an existing package.json, extracts selected fields, and creates a new one."; } } // ============================================================================ // Export // ============================================================================ // export default PackageManagerAction;