<commit_before><?php

namespace DrewM\Selecta;
 
class Selecta
{
	public static $single_tags    = array('img', 'br', 'hr', 'input');
	public static $pseudo_classes = array('disabled', 'checked');
	public static $meta_map       = array('.'=>'class', '#'=>'id');

	public static function build($selector, $contents='', $open_tags=true, $close_tags=true)
	{
		$parts = explode(' ', $selector);
		if (count($parts)) {
			$parts = array_reverse($parts);
			foreach($parts as $part) {
				$contents = self::tagify($part, $contents, $open_tags, $close_tags);
			}
		}
		return $contents;
	}

	public static function wrap($selector, $contents='')
	{
		return self::build($selector, $contents, true, true);
	}

	public static function open($selector)
	{
		return self::build($selector, '', true, false);
	}

	public static function close($selector)
	{
		return self::build($selector, '', false, true);
	}

	private static function tagify($selector='', $contents='', $open_tags=true, $close_tags=true)
	{
		$attrs = array();

		// replace dots within attribute selectors
		$selector = self::sanitise_attribute_dots($selector);

		$metas   = '\.\#\[\:';
		$pattern = '/(['.$metas.'])([^'.$metas.']*)?/';
		preg_match_all($pattern, $selector, $matches, PREG_SET_ORDER);

		if (count($matches)) {
			foreach($matches as $match) {
				$attrs = self::build_attributes($match[1], $match[2], $attrs);
			}

			// reduce selector to just tag name
			$parts    = preg_split('/['.$metas.']/', $selector);
			$selector = $parts[0];
		}

		return self::build_tag($selector, $attrs, $contents, $open_tags, $close_tags);
	}

	private static function build_attributes($meta_char, $value, $attrs)
	{
		$key = false;
		if (isset(self::$meta_map[$meta_char])) {
			$key = self::$meta_map[$meta_char];
		}else{
			switch ($meta_char) {
				
				// Attribute selectors
				case '[':
					$value = rtrim($value, ']');

					if (strpos($value, '=')) {
						$parts = explode('=', $value, 2);
						$key   = $parts[0];
						$value = self::unsanitise_attribute_dots($parts[1]);
					}else{
						$key   = $value;
						$value = false;
					}
					break;

				// Pseudo-class selectors
				case ':':
					list($key, $value) = self::build_pseudo_class_attribute($value);
					break;
			}
		}

		if ($key){
			if (isset($attrs[$key])) {
				$attrs[$key] .= ' '.$value;
			}else{
				$attrs[$key] = $value;
			}
		}

		return $attrs;<commit_msg>Refactoring<commit_after><?php

namespace DrewM\Selecta;
 
class Selecta
{
	public static $single_tags    = array('img', 'br', 'hr', 'input');
	public static $pseudo_classes = array('disabled', 'checked');
	public static $meta_map       = array('.'=>'class', '#'=>'id');

	public static function build($selector, $contents='', $open_tags=true, $close_tags=true)
	{
		$parts = explode(' ', $selector);
		if (count($parts)) {
			$parts = array_reverse($parts);
			foreach($parts as $part) {
				$contents = self::tagify($part, $contents, $open_tags, $close_tags);
			}
		}
		return $contents;
	}

	public static function wrap($selector, $contents='')
	{
		return self::build($selector, $contents, true, true);
	}

	public static function open($selector)
	{
		return self::build($selector, '', true, false);
	}

	public static function close($selector)
	{
		return self::build($selector, '', false, true);
	}

	private static function tagify($selector='', $contents='', $open_tags=true, $close_tags=true)
	{
		$attrs = array();

		// replace dots within attribute selectors
		$selector = self::sanitise_attribute_dots($selector);

		$metas   = '\.\#\[\:';
		$pattern = '/(['.$metas.'])([^'.$metas.']*)?/';
		preg_match_all($pattern, $selector, $matches, PREG_SET_ORDER);

		if (count($matches)) {
			foreach($matches as $match) {
				$attrs = self::build_attributes($match[1], $match[2], $attrs);
			}

			// reduce selector to just tag name
			$parts    = preg_split('/['.$metas.']/', $selector);
			$selector = $parts[0];
		}

		return self::build_tag($selector, $attrs, $contents, $open_tags, $close_tags);
	}

	private static function build_attributes($meta_char, $value, $attrs)
	{
		$key = false;
		if (isset(self::$meta_map[$meta_char])) {
			$key = self::$meta_map[$meta_char];
		}else{
			switch ($meta_char) {
				
				// Attribute selectors
				case '[':
					list($key, $value) = self::build_attribute_selector_attribute($value);
					break;

				// Pseudo-class selectors
				case ':':
					list($key, $value) = self::build_pseudo_class_attribute($value);
					break;
			}
		}

		if ($key){
			if (isset($attrs[$key])) {
				$attrs[$key] .= ' '.$value;
			}else{
				$attrs[$key] = $value;
			}
		}

		return $attrs;
	}

	private static function build_attribute_selector_attribute($value)
	{
		$value = rtrim($value, ']');

		if (strpos($value, '=')) {
			$parts = explode('=', $value, 2);
			$key   = $parts[0];
			$value = self::unsanitise_attribute_dots($parts[1]);
		}else{
			$key   = $value;
			$value = false;
		}

		return array($key, $value);
{'fraction_non_alphanumeric': 0.19742402897967398, 'fraction_numerical': 0.002414972831555645, 'mean_word_length': 3.839337877312561, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 7, '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': '604763', 'n_tokens_mistral': 1996, 'n_tokens_neox': 1716, 'n_words': 359}