phml.misc.component
1from pathlib import Path 2 3from phml.nodes import AST, All_Nodes, Element 4 5__all__ = [ 6 "tag_from_file", 7 "filename_from_path", 8 "parse_component", 9 "valid_component_dict", 10] 11 12 13def tag_from_file(filename: str | Path) -> str: 14 """Generates a tag name some-tag-name from a filename. 15 Assumes filenames of: 16 * snakecase - some_file_name 17 * camel case - someFileName 18 * pascal case - SomeFileName 19 """ 20 from re import finditer # pylint: disable=import-outside-toplevel 21 22 if isinstance(filename, Path): 23 if filename.is_file(): 24 filename = filename.name.replace(filename.suffix, "") 25 else: 26 raise TypeError("If filename is a path it must also be a valid file.") 27 28 tokens = [] 29 for token in finditer(r"(\b|[A-Z]|_|-)([a-z]+)|([A-Z]+)(?=[^a-z])", filename): 30 first, rest, cap = token.groups() 31 32 if first is not None and first.isupper(): 33 rest = first + rest 34 elif cap is not None and cap.isupper(): 35 rest = cap 36 tokens.append(rest.lower()) 37 38 return "-".join(tokens) 39 40 41def filename_from_path(file: Path) -> str: 42 """Get the filename without the suffix from a pathlib.Path.""" 43 44 if file.is_file(): 45 return file.name.replace(file.suffix, "") 46 47 raise TypeError("Path must also be a valid file.") 48 49 50def valid_component_dict(cmpt: dict) -> bool: 51 """Check if a component dict is valid.""" 52 return bool( 53 ("python" in cmpt and isinstance(cmpt["python"], list)) 54 and ("script" in cmpt and isinstance(cmpt["script"], list)) 55 and ("style" in cmpt and isinstance(cmpt["script"], list)) 56 and ("component" in cmpt and isinstance(cmpt["component"], All_Nodes)) 57 ) 58 59 60def parse_component(ast: AST) -> dict[str, Element]: 61 """Helper function to parse the components elements.""" 62 from phml import ( # pylint: disable=import-outside-toplevel 63 check, 64 is_css_style, 65 is_javascript, 66 visit_children, 67 ) 68 69 result = {"python": [], "script": [], "style": [], "component": None} 70 for node in visit_children(ast.tree): 71 if check(node, ["element", {"tag": "python"}]): 72 result["python"].append(node) 73 elif check(node, ["element", {"tag": "script"}]) and is_javascript(node): 74 result["script"].append(node) 75 elif check(node, ["element", {"tag": "style"}]) and is_css_style(node): 76 result["style"].append(node) 77 elif check(node, "element"): 78 if result["component"] is None: 79 result["component"] = node 80 else: 81 raise Exception( 82 """\ 83Components may only have one wrapping element. All other element in the root must be either a \ 84script, style, or python tag.\ 85""" 86 ) 87 88 if result["component"] is None: 89 raise Exception("Must have at least one element in a component.") 90 91 return result
def
tag_from_file(filename: str | pathlib.Path) -> str:
14def tag_from_file(filename: str | Path) -> str: 15 """Generates a tag name some-tag-name from a filename. 16 Assumes filenames of: 17 * snakecase - some_file_name 18 * camel case - someFileName 19 * pascal case - SomeFileName 20 """ 21 from re import finditer # pylint: disable=import-outside-toplevel 22 23 if isinstance(filename, Path): 24 if filename.is_file(): 25 filename = filename.name.replace(filename.suffix, "") 26 else: 27 raise TypeError("If filename is a path it must also be a valid file.") 28 29 tokens = [] 30 for token in finditer(r"(\b|[A-Z]|_|-)([a-z]+)|([A-Z]+)(?=[^a-z])", filename): 31 first, rest, cap = token.groups() 32 33 if first is not None and first.isupper(): 34 rest = first + rest 35 elif cap is not None and cap.isupper(): 36 rest = cap 37 tokens.append(rest.lower()) 38 39 return "-".join(tokens)
Generates a tag name some-tag-name from a filename. Assumes filenames of:
- snakecase - some_file_name
- camel case - someFileName
- pascal case - SomeFileName
def
filename_from_path(file: pathlib.Path) -> str:
42def filename_from_path(file: Path) -> str: 43 """Get the filename without the suffix from a pathlib.Path.""" 44 45 if file.is_file(): 46 return file.name.replace(file.suffix, "") 47 48 raise TypeError("Path must also be a valid file.")
Get the filename without the suffix from a pathlib.Path.
61def parse_component(ast: AST) -> dict[str, Element]: 62 """Helper function to parse the components elements.""" 63 from phml import ( # pylint: disable=import-outside-toplevel 64 check, 65 is_css_style, 66 is_javascript, 67 visit_children, 68 ) 69 70 result = {"python": [], "script": [], "style": [], "component": None} 71 for node in visit_children(ast.tree): 72 if check(node, ["element", {"tag": "python"}]): 73 result["python"].append(node) 74 elif check(node, ["element", {"tag": "script"}]) and is_javascript(node): 75 result["script"].append(node) 76 elif check(node, ["element", {"tag": "style"}]) and is_css_style(node): 77 result["style"].append(node) 78 elif check(node, "element"): 79 if result["component"] is None: 80 result["component"] = node 81 else: 82 raise Exception( 83 """\ 84Components may only have one wrapping element. All other element in the root must be either a \ 85script, style, or python tag.\ 86""" 87 ) 88 89 if result["component"] is None: 90 raise Exception("Must have at least one element in a component.") 91 92 return result
Helper function to parse the components elements.
def
valid_component_dict(cmpt: dict) -> bool:
51def valid_component_dict(cmpt: dict) -> bool: 52 """Check if a component dict is valid.""" 53 return bool( 54 ("python" in cmpt and isinstance(cmpt["python"], list)) 55 and ("script" in cmpt and isinstance(cmpt["script"], list)) 56 and ("style" in cmpt and isinstance(cmpt["script"], list)) 57 and ("component" in cmpt and isinstance(cmpt["component"], All_Nodes)) 58 )
Check if a component dict is valid.