function render_stylesheet(source, analysis, options) {
	const code = new MagicString(source);

	/** @type {State} */
	const state = {
		code,
		hash: analysis.css.hash,
		minify: analysis.inject_styles && !options.dev,
		selector: `.${analysis.css.hash}`,
		keyframes: analysis.css.keyframes,
		specificity: {
			bumped: false
		}
	};

	const ast = /** @type {AST.CSS.StyleSheet} */ (analysis.css.ast);

	walk(/** @type {AST.CSS.Node} */ (ast), state, visitors);

	code.remove(0, ast.content.start);
	code.remove(/** @type {number} */ (ast.content.end), source.length);
	if (state.minify) {
		remove_preceding_whitespace(ast.content.end, state);
	}

	const css = {
		code: code.toString(),
		map: code.generateMap({
			// include source content; makes it easier/more robust looking up the source map code
			includeContent: true,
			// generateMap takes care of calculating source relative to file
			source: options.filename,
			file: options.cssOutputFilename || options.filename
		}),
		hasGlobal: analysis.css.has_global
	};

	merge_with_preprocessor_map(css, options, css.map.sources[0]);

	if (dev && options.css === 'injected' && css.code) {
		css.code += `\n/*# sourceMappingURL=${css.map.toUrl()} */`;
	}

	return css;
}
@param {string} source
@param {ComponentAnalysis} analysis
@param {ValidatedCompileOptions} options