import cobble from ... import html_paths from .tokeniser import TokenType from .token_parser import parse_identifier, parse_string @cobble.data class _AttributeOrClassName(object): name = cobble.field() value = cobble.field() append = cobble.field() def parse_html_path(tokens): if tokens.try_skip(TokenType.SYMBOL, "!"): return html_paths.ignore else: return html_paths.path(_parse_html_path_elements(tokens)) def _parse_html_path_elements(tokens): elements = [] if tokens.peek_token_type() == TokenType.IDENTIFIER: elements.append(_parse_element(tokens)) while tokens.try_skip_many(((TokenType.WHITESPACE, None), (TokenType.SYMBOL, ">"))): tokens.skip(TokenType.WHITESPACE) elements.append(_parse_element(tokens)) return elements def _parse_element(tokens): tag_names = _parse_tag_names(tokens) attributes_list = _parse_attribute_or_class_names(tokens) is_fresh = _parse_is_fresh(tokens) separator = _parse_separator(tokens) attributes = {} for attribute in attributes_list: if attribute.append and attributes.get(attribute.name): attributes[attribute.name] += " " + attribute.value else: attributes[attribute.name] = attribute.value return html_paths.element( tag_names, attributes=attributes, fresh=is_fresh, separator=separator, ) def _parse_tag_names(tokens): tag_names = [parse_identifier(tokens)] while tokens.try_skip(TokenType.SYMBOL, "|"): tag_names.append(parse_identifier(tokens)) return tag_names def _parse_attribute_or_class_names(tokens): attribute_or_class_names = [] while True: attribute_or_class_name = _try_parse_attribute_or_class_name(tokens) if attribute_or_class_name is None: break else: attribute_or_class_names.append(attribute_or_class_name) return attribute_or_class_names def _try_parse_attribute_or_class_name(tokens): if tokens.is_next(TokenType.SYMBOL, "["): return _parse_attribute(tokens) if tokens.is_next(TokenType.SYMBOL, "."): return _parse_class_name(tokens) else: return None def _parse_attribute(tokens): tokens.skip(TokenType.SYMBOL, "[") name = parse_identifier(tokens) tokens.skip(TokenType.SYMBOL, "=") value = parse_string(tokens) tokens.skip(TokenType.SYMBOL, "]") return _AttributeOrClassName(name=name, value=value, append=False) def _parse_class_name(tokens): tokens.skip(TokenType.SYMBOL, ".") class_name = parse_identifier(tokens) return _AttributeOrClassName(name="class", value=class_name, append=True) def _parse_is_fresh(tokens): return tokens.try_skip_many(( (TokenType.SYMBOL, ":"), (TokenType.IDENTIFIER, "fresh"), )) def _parse_separator(tokens): is_separator = tokens.try_skip_many(( (TokenType.SYMBOL, ":"), (TokenType.IDENTIFIER, "separator"), )) if is_separator: tokens.skip(TokenType.SYMBOL, "(") value = parse_string(tokens) tokens.skip(TokenType.SYMBOL, ")") return value else: return None