Repository: rollup/rollup
File: src/rollup/rollup.ts (TypeScript)

Code before:
			}
			try {
				await graph.pluginDriver.hookParallel('buildEnd', [error_]);
			} catch (buildEndError: any) {
				// Create a compound error object to include both errors, based on the original error
				// structuredClone cannot be used because properties might be non-enumerable
				const compoundError = getRollupError({
					binding: error_.binding,
					cause: error_.cause,
					code: error_.code,
					exporter: error_.exporter,
					frame: error_.frame,
					hook: error_.hook,
					id: error_.id,
					ids: error_.ids,
					loc: error_.loc,
					message: `There was an error during the build:\n  ${error_.message}\nAdditionally, handling the error in the 'buildEnd' hook caused the following error:\n  ${buildEndError.message}`,
					meta: error_.meta,
					names: error_.names,
					plugin: error_.plugin,
					pluginCode: error_.pluginCode,
					pos: error_.pos,
					reexporter: error_.reexporter,
					stack: error_.stack,
					url: error_.url
				});
				Object.defineProperty(compoundError, 'watchFiles', {
					value: error_.watchFiles,
					writable: true
				});
				await graph.pluginDriver.hookParallel('closeBundle', [compoundError]);
				throw compoundError;
			}
			await graph.pluginDriver.hookParallel('closeBundle', [error_]);
			throw error_;
		}
		try {
			await graph.pluginDriver.hookParallel('buildEnd', []);
		} catch (buildEndError: any) {
			await graph.pluginDriver.hookParallel('closeBundle', [buildEndError]);
			throw buildEndError;
		}
	});

	timeEnd('BUILD', 1);

	const result: RollupBuild = {
		cache: useCache ? graph.getCache() : undefined,
		async close() {
			if (result.closed) return;


Review comment (suggestion):
Any reason for not using a spread operator here? Otherwise, we need to touch this place whenever we define a new error type. Also, most of the time most of the properties will not be there.

```suggestion
				const compoundError = getRollupError({
					...error_,
					message: `There was an error during the build:\n  ${error_.message}\nAdditionally, handling the error in the 'buildEnd' hook caused the following error:\n  ${buildEndError.message}`
				});
```

Code after:
			}
			try {
				await graph.pluginDriver.hookParallel('buildEnd', [error_]);
			} catch (buildEndError: any) {
				// Create a compound error object to include both errors, based on the original error
				const compoundError = getRollupError({
					...error_,
					message: `There was an error during the build:\n  ${error_.message}\nAdditionally, handling the error in the 'buildEnd' hook caused the following error:\n  ${buildEndError.message}`
				});
				await graph.pluginDriver.hookParallel('closeBundle', [compoundError]);
				throw compoundError;
			}
			await graph.pluginDriver.hookParallel('closeBundle', [error_]);
			throw error_;
		}
		try {
			await graph.pluginDriver.hookParallel('buildEnd', []);
		} catch (buildEndError: any) {
			await graph.pluginDriver.hookParallel('closeBundle', [buildEndError]);
			throw buildEndError;
		}
	});

	timeEnd('BUILD', 1);

	const result: RollupBuild = {
		cache: useCache ? graph.getCache() : undefined,
		async close() {
			if (result.closed) return;

			result.closed = true;

			await graph.pluginDriver.hookParallel('closeBundle', []);
		},
		closed: false,
		async [Symbol.asyncDispose]() {
			await this.close();
		},
		async generate(rawOutputOptions: OutputOptions) {
			if (result.closed) return error(logAlreadyClosed());

			return handleGenerateWrite(false, inputOptions, unsetInputOptions, rawOutputOptions, graph);
		},
		get watchFiles() {
			return Object.keys(graph.watchFiles);
		},
		async write(rawOutputOptions: OutputOptions) {
			if (result.closed) return error(logAlreadyClosed());

			return handleGenerateWrite(true, inputOptions, unsetInputOptions, rawOutputOptions, graph);
		}