tidos_macro 0.7.2

Procedural macros for the Tidos component framework.
Documentation
use proc_macro2::{Delimiter, TokenTree};
use syn::buffer::Cursor;

pub fn matches_corresponding_command_tag(cursor: Cursor, target_tag: &str) -> bool {
	if let Some((a, _, _)) = cursor.group(Delimiter::Brace) {
		let peeked: Vec<TokenTree> = a.token_stream().into_iter().take(2).collect();

		peeked.len() == 2
			&& matches!(peeked[0], TokenTree::Punct(ref punct) if punct.as_char() == '/')
			&& matches!(peeked[1], TokenTree::Ident(ref ident) if ident.to_string() == target_tag)
	} else {
		false
	}
}

pub fn matches_case_statement(cursor: Cursor) -> bool {
	if let Some((a, _, _)) = cursor.group(Delimiter::Brace) {
		let peeked: Vec<TokenTree> = a.token_stream().into_iter().take(3).collect();

		peeked.len() >= 3
			&& matches!(peeked[0], TokenTree::Punct(ref punct) if punct.as_char() == ':')
			&& matches!(peeked[1], TokenTree::Ident(ref ident) if ident.to_string().as_str() == "case")
	} else {
		false
	}
}

pub fn is_cursor_on_new_if_branch(cursor: &Cursor) -> bool {
	is_cursor_on_else_if_branch(cursor)
		|| is_cursor_on_else_branch(cursor)
		|| is_cursor_on_end_of_if_branch(cursor)
}

pub fn is_cursor_on_else_if_branch(cursor: &Cursor) -> bool {
	if let Some((a, _, _)) = cursor.group(Delimiter::Brace) {
		let peeked: Vec<TokenTree> = a.token_stream().into_iter().take(3).collect();

		peeked.len() >= 3
			&& matches!(&peeked[0], TokenTree::Punct(p) if p.as_char() == ':')
			&& matches!(&peeked[1], TokenTree::Ident(i) if i.to_string() == "else")
			&& matches!(&peeked[2], TokenTree::Ident(i) if i.to_string() == "if")
	} else {
		false
	}
}

pub fn is_cursor_on_else_branch(cursor: &Cursor) -> bool {
	if let Some((a, _, _)) = cursor.group(Delimiter::Brace) {
		let peeked: Vec<TokenTree> = a.token_stream().into_iter().take(2).collect();

		peeked.len() >= 2
			&& matches!(&peeked[0], TokenTree::Punct(p) if p.as_char() == ':')
			&& matches!(&peeked[1], TokenTree::Ident(i) if i.to_string() == "else")
	} else {
		false
	}
}

pub fn is_cursor_on_end_of_if_branch(cursor: &Cursor) -> bool {
	if let Some((a, _, _)) = cursor.group(Delimiter::Brace) {
		let peeked: Vec<TokenTree> = a.token_stream().into_iter().take(2).collect();

		peeked.len() >= 2
			&& matches!(&peeked[0], TokenTree::Punct(p) if p.as_char() == '/')
			&& matches!(&peeked[1], TokenTree::Ident(i) if i.to_string() == "if")
	} else {
		false
	}
}

pub fn matches_tag(cursor: Cursor, target_tag: &String) -> bool {
	let mut rest = cursor;
	if !matches!(rest.punct(), Some((punct, _)) if punct.as_char() == '<') {
		return false;
	}
	let (_, next) = rest.punct().unwrap();
	rest = next;

	if !matches!(rest.punct(), Some((punct, _)) if punct.as_char() == '/') {
		return false;
	}
	let (_, next) = rest.punct().unwrap();
	rest = next;

	let mut right_hand_side = String::new();
	let (ident, next) = rest
		.ident()
		.expect("Expected an html like <p> or <custom-element>");
	right_hand_side.push_str(ident.to_string().as_str());

	rest = next;

	while matches!(rest.punct(), Some((p, _)) if p.as_char() == '-') {
		let next = rest.punct().unwrap().1;
		rest = next;

		right_hand_side.push('-');
		let (ident, next) = rest
			.ident()
			.expect("Expected an html like <p> or <custom-element>");

		right_hand_side.push_str(ident.to_string().as_str());
		rest = next;
	}

	if right_hand_side != *target_tag {
		return false;
	}

	if !matches!(rest.punct(), Some((punct, _)) if punct.as_char() == '>') {
		return false;
	}

	true
}