<commit_before>import MagicString from 'magic-string';
import { walk } from 'estree-walker';
import { getLocator } from 'locate-character';
import Selector from './Selector';
import getCodeFrame from '../utils/getCodeFrame';
import hash from '../utils/hash';
import Element from '../generators/nodes/Element';
import { Validator } from '../validate/index';
import { Node, Parsed, Warning } from '../interfaces';

class Rule {
	selectors: Selector[];
	declarations: Declaration[];
	node: Node;
	parent: Atrule;

	constructor(node: Node, parent?: Atrule) {
		this.node = node;
		this.parent = parent;
		this.selectors = node.selector.children.map((node: Node) => new Selector(node));
		this.declarations = node.block.children.map((node: Node) => new Declaration(node));
	}

	apply(node: Element, stack: Element[]) {
		this.selectors.forEach(selector => selector.apply(node, stack)); // TODO move the logic in here?
	}

	isUsed(dev: boolean) {
		if (this.parent && this.parent.node.type === 'Atrule' && this.parent.node.name === 'keyframes') return true;
		if (this.declarations.length === 0) return dev;
		return this.selectors.some(s => s.used);
	}

	minify(code: MagicString, cascade: boolean, dev: boolean) {
		let c = this.node.start;
		let started = false;

		this.selectors.forEach((selector, i) => {
			if (cascade || selector.used) {
				const separator = started ? ',' : '';
				if ((selector.node.start - c) > separator.length) {
					code.overwrite(c, selector.node.start, separator);
				}

				if (!cascade) selector.minify(code);
				c = selector.node.end;

				started = true;
			}
		});

		code.remove(c, this.node.block.start);

		c = this.node.block.start + 1;
		this.declarations.forEach((declaration, i) => {
			const separator = i > 0 ? ';' : '';
			if ((declaration.node.start - c) > separator.length) {
				code.overwrite(c, declaration.node.start, separator);
			}

			declaration.minify(code);

			c = declaration.node.end;
		});

		code.remove(c, this.node.block.end - 1);
	}

	transform(code: MagicString, id: string, keyframes: Map<string, string>, cascade: boolean) {
		if (this.parent && this.parent.node.type === 'Atrule' && this.parent.node.name === 'keyframes') return true;

		const attr = `[${id}]`;

		if (cascade) {
			this.selectors.forEach(selector => {
				// TODO disable cascading (without :global(...)) in v2
				const { start, end, children } = selector.node;

				const css = code.original;
				const selectorString = css.slice(start, end);

				const firstToken = children[0];

				let transformed;

				if (firstToken.type === 'TypeSelector') {
					const insert = firstToken.end;
					const head = firstToken.name === '*' ? '' : css.slice(start, insert);
					const tail = css.slice(insert, end);

					transformed = `${head}${attr}${tail},${attr} ${selectorString}`;
				} else {
					transformed = `${attr}${selectorString},${attr} ${selectorString}`;
				}

				code.overwrite(start, end, transformed);
			});
		} else {
			this.selectors.forEach(selector => selector.transform(code, attr));<commit_msg>generate a class selector instead of an attribute selector<commit_after>import MagicString from 'magic-string';
import { walk } from 'estree-walker';
import { getLocator } from 'locate-character';
import Selector from './Selector';
import getCodeFrame from '../utils/getCodeFrame';
import hash from '../utils/hash';
import Element from '../generators/nodes/Element';
import { Validator } from '../validate/index';
import { Node, Parsed, Warning } from '../interfaces';

class Rule {
	selectors: Selector[];
	declarations: Declaration[];
	node: Node;
	parent: Atrule;

	constructor(node: Node, parent?: Atrule) {
		this.node = node;
		this.parent = parent;
		this.selectors = node.selector.children.map((node: Node) => new Selector(node));
		this.declarations = node.block.children.map((node: Node) => new Declaration(node));
	}

	apply(node: Element, stack: Element[]) {
		this.selectors.forEach(selector => selector.apply(node, stack)); // TODO move the logic in here?
	}

	isUsed(dev: boolean) {
		if (this.parent && this.parent.node.type === 'Atrule' && this.parent.node.name === 'keyframes') return true;
		if (this.declarations.length === 0) return dev;
		return this.selectors.some(s => s.used);
	}

	minify(code: MagicString, cascade: boolean, dev: boolean) {
		let c = this.node.start;
		let started = false;

		this.selectors.forEach((selector, i) => {
			if (cascade || selector.used) {
				const separator = started ? ',' : '';
				if ((selector.node.start - c) > separator.length) {
					code.overwrite(c, selector.node.start, separator);
				}

				if (!cascade) selector.minify(code);
				c = selector.node.end;

				started = true;
			}
		});

		code.remove(c, this.node.block.start);

		c = this.node.block.start + 1;
		this.declarations.forEach((declaration, i) => {
			const separator = i > 0 ? ';' : '';
			if ((declaration.node.start - c) > separator.length) {
				code.overwrite(c, declaration.node.start, separator);
			}

			declaration.minify(code);

			c = declaration.node.end;
		});

		code.remove(c, this.node.block.end - 1);
	}

	transform(code: MagicString, id: string, keyframes: Map<string, string>, cascade: boolean) {
		if (this.parent && this.parent.node.type === 'Atrule' && this.parent.node.name === 'keyframes') return true;

		const attr = `.${id}`;

		if (cascade) {
			this.selectors.forEach(selector => {
				// TODO disable cascading (without :global(...)) in v2
				const { start, end, children } = selector.node;

				const css = code.original;
				const selectorString = css.slice(start, end);

				const firstToken = children[0];

				let transformed;

				if (firstToken.type === 'TypeSelector') {
					const insert = firstToken.end;
					const head = firstToken.name === '*' ? '' : css.slice(start, insert);
					const tail = css.slice(insert, end);

					transformed = `${head}${attr}${tail},${attr} ${selectorString}`;
				} else {
					transformed = `${attr}${selectorString},${attr} ${selectorString}`;
				}

				code.overwrite(start, end, transformed);
			});
		} else {
			this.selectors.forEach(selector => selector.transform(code, attr));
{'fraction_non_alphanumeric': 0.16899804814573846, 'fraction_numerical': 0.001951854261548471, 'mean_word_length': 3.665402124430956, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 27, 'https://': 0, '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': '1033280', 'n_tokens_mistral': 2262, 'n_tokens_neox': 1944, 'n_words': 469}