<commit_before>import { is_void, quote_prop_if_necessary, quote_name_if_necessary } from '../../../utils/names';
import Attribute from '../../nodes/Attribute';
import Class from '../../nodes/Class';
import { snip } from '../../utils/snip';
import { stringify_attribute } from '../../utils/stringify_attribute';
import { get_slot_scope } from './shared/get_slot_scope';
import Renderer, { RenderOptions } from '../Renderer';
import Element from '../../nodes/Element';
import Text from '../../nodes/Text';

// source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7
const boolean_attributes = new Set([
	'async',
	'autocomplete',
	'autofocus',
	'autoplay',
	'border',
	'challenge',
	'checked',
	'compact',
	'contenteditable',
	'controls',
	'default',
	'defer',
	'disabled',
	'formnovalidate',
	'frameborder',
	'hidden',
	'indeterminate',
	'ismap',
	'loop',
	'multiple',
	'muted',
	'nohref',
	'noresize',
	'noshade',
	'novalidate',
	'nowrap',
	'open',
	'readonly',
	'required',
	'reversed',
	'scoped',
	'scrolling',
	'seamless',
	'selected',
	'sortable',
	'spellcheck',
	'translate'
]);

export default function(node: Element, renderer: Renderer, options: RenderOptions & {
	slot_scopes: Map<any, any>;
}) {
	let opening_tag = `<${node.name}`;

	// awkward special case
	let node_contents;
	let value;

	const contenteditable = (
		node.name !== 'textarea' &&
		node.name !== 'input' &&
		node.attributes.some((attribute) => attribute.name === 'contenteditable')
	);

	const slot = node.get_static_attribute_value('slot');
	const component = node.find_nearest(/InlineComponent/);
	if (slot && component) {
		const slot = node.attributes.find((attribute) => attribute.name === 'slot');
		const slot_name = (slot.chunks[0] as Text).data;
		const target = renderer.targets[renderer.targets.length - 1];
		target.slot_stack.push(slot_name);
		target.slots[slot_name] = '';

		const lets = node.lets;
		const seen = new Set(lets.map(l => l.name));

		component.lets.forEach(l => {
			if (!seen.has(l.name)) lets.push(l);
		});

		options.slot_scopes.set(slot_name, get_slot_scope(node.lets));
	}

	const class_expression = node.classes.map((class_directive: Class) => {
		const { expression, name } = class_directive;
		const snippet = expression ? snip(expression) : `ctx${quote_prop_if_necessary(name)}`;
		return `${snippet} ? "${name}" : ""`;
	}).join(', ');

	let add_class_attribute = class_expression ? true : false;

	if (node.attributes.find(attr => attr.is_spread)) {
		// TODO dry this out
		const args = [];
		node.attributes.forEach(attribute => {
			if (attribute.is_spread) {
				args.push(snip(attribute.expression));
			} else {
				if (attribute.name === 'value' && node.name === 'textarea') {
					node_contents = stringify_attribute(attribute, true);
				} else if (attribute.is_true) {
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: true }`);
				} else if (
					boolean_attributes.has(attribute.name) &&
					attribute.chunks.length === 1 &&
					attribute.chunks[0].type !== 'Text'
				) {
					// a boolean attribute with one non-Text chunk
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: ${snip(attribute.chunks[0])} }`);
				} else {
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: \`${stringify_attribute(attribute, true)}\` }`);
				}
			}
		});

		opening_tag += "${@spread([" + args.join(', ') + "])}";
	} else {
		node.attributes.forEach((attribute: Attribute) => {
			if (attribute.type !== 'Attribute') return;

			if (attribute.name === 'value' && node.name === 'textarea') {
				node_contents = stringify_attribute(attribute, true);
			} else if (attribute.is_true) {
				opening_tag += ` ${attribute.name}`;
			} else if (
				boolean_attributes.has(attribute.name) &&
				attribute.chunks.length === 1 &&
				attribute.chunks[0].type !== 'Text'
			) {
				// a boolean attribute with one non-Text chunk
				opening_tag += '${' + snip(attribute.chunks[0]) + ' ? " ' + attribute.name + '" : "" }';
			} else if (attribute.name === 'class' && class_expression) {<commit_msg>[Element][SSR] Set class expression if spread is used<commit_after>import { is_void, quote_prop_if_necessary, quote_name_if_necessary } from '../../../utils/names';
import Attribute from '../../nodes/Attribute';
import Class from '../../nodes/Class';
import { snip } from '../../utils/snip';
import { stringify_attribute } from '../../utils/stringify_attribute';
import { get_slot_scope } from './shared/get_slot_scope';
import Renderer, { RenderOptions } from '../Renderer';
import Element from '../../nodes/Element';
import Text from '../../nodes/Text';

// source: https://gist.github.com/ArjanSchouten/0b8574a6ad7f5065a5e7
const boolean_attributes = new Set([
	'async',
	'autocomplete',
	'autofocus',
	'autoplay',
	'border',
	'challenge',
	'checked',
	'compact',
	'contenteditable',
	'controls',
	'default',
	'defer',
	'disabled',
	'formnovalidate',
	'frameborder',
	'hidden',
	'indeterminate',
	'ismap',
	'loop',
	'multiple',
	'muted',
	'nohref',
	'noresize',
	'noshade',
	'novalidate',
	'nowrap',
	'open',
	'readonly',
	'required',
	'reversed',
	'scoped',
	'scrolling',
	'seamless',
	'selected',
	'sortable',
	'spellcheck',
	'translate'
]);

export default function(node: Element, renderer: Renderer, options: RenderOptions & {
	slot_scopes: Map<any, any>;
}) {
	let opening_tag = `<${node.name}`;

	// awkward special case
	let node_contents;
	let value;

	const contenteditable = (
		node.name !== 'textarea' &&
		node.name !== 'input' &&
		node.attributes.some((attribute) => attribute.name === 'contenteditable')
	);

	const slot = node.get_static_attribute_value('slot');
	const component = node.find_nearest(/InlineComponent/);
	if (slot && component) {
		const slot = node.attributes.find((attribute) => attribute.name === 'slot');
		const slot_name = (slot.chunks[0] as Text).data;
		const target = renderer.targets[renderer.targets.length - 1];
		target.slot_stack.push(slot_name);
		target.slots[slot_name] = '';

		const lets = node.lets;
		const seen = new Set(lets.map(l => l.name));

		component.lets.forEach(l => {
			if (!seen.has(l.name)) lets.push(l);
		});

		options.slot_scopes.set(slot_name, get_slot_scope(node.lets));
	}

	const class_expression = node.classes.map((class_directive: Class) => {
		const { expression, name } = class_directive;
		const snippet = expression ? snip(expression) : `ctx${quote_prop_if_necessary(name)}`;
		return `${snippet} ? "${name}" : ""`;
	}).join(', ');

	let add_class_attribute = class_expression ? true : false;

	if (node.attributes.find(attr => attr.is_spread)) {
		// TODO dry this out
		const args = [];
		node.attributes.forEach(attribute => {
			if (attribute.is_spread) {
				args.push(snip(attribute.expression));
			} else {
				if (attribute.name === 'value' && node.name === 'textarea') {
					node_contents = stringify_attribute(attribute, true);
				} else if (attribute.is_true) {
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: true }`);
				} else if (
					boolean_attributes.has(attribute.name) &&
					attribute.chunks.length === 1 &&
					attribute.chunks[0].type !== 'Text'
				) {
					// a boolean attribute with one non-Text chunk
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: ${snip(attribute.chunks[0])} }`);
				} else if (attribute.name === 'class' && class_expression) {
					// Add class expression
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: [\`${stringify_attribute(attribute, true)}\`, \`\${${class_expression}}\`].join(' ').trim() }`);
				} else {
					args.push(`{ ${quote_name_if_necessary(attribute.name)}: \`${stringify_attribute(attribute, true)}\` }`);
				}
			}
		});

		opening_tag += "${@spread([" + args.join(', ') + "])}";
	} else {
		node.attributes.forEach((attribute: Attribute) => {
			if (attribute.type !== 'Attribute') return;

			if (attribute.name === 'value' && node.name === 'textarea') {
				node_contents = stringify_attribute(attribute, true);
			} else if (attribute.is_true) {
				opening_tag += ` ${attribute.name}`;
			} else if (
				boolean_attributes.has(attribute.name) &&
				attribute.chunks.length === 1 &&
				attribute.chunks[0].type !== 'Text'
			) {
				// a boolean attribute with one non-Text chunk
				opening_tag += '${' + snip(attribute.chunks[0]) + ' ? " ' + attribute.name + '" : "" }';
			} else if (attribute.name === 'class' && class_expression) {
{'fraction_non_alphanumeric': 0.1888611210282042, 'fraction_numerical': 0.004998214923241699, 'mean_word_length': 4.07487922705314, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 21, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6266161', 'n_tokens_mistral': 3119, 'n_tokens_neox': 2847, 'n_words': 557}