Coverage for phml\utils\misc\component.py: 90%
41 statements
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-08 11:07 -0600
« prev ^ index » next coverage.py v6.5.0, created at 2022-12-08 11:07 -0600
1# pylint: disable=missing-module-docstring
2from pathlib import Path
4from phml.nodes import AST, All_Nodes, Element
6__all__ = [
7 "tag_from_file",
8 "filename_from_path",
9 "parse_component",
10 "valid_component_dict",
11]
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
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.")
29 tokens = []
30 for token in finditer(r"(\b|[A-Z]|_|-)([a-z]+)|([A-Z]+)(?=[^a-z])", filename):
31 first, rest, cap = token.groups()
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())
39 return "-".join(tokens)
42def filename_from_path(file: Path) -> str:
43 """Get the filename without the suffix from a pathlib.Path."""
45 if file.is_file():
46 return file.name.replace(file.suffix, "")
48 raise TypeError(f"Expected {type(Path)} not {type(file)}")
51def valid_component_dict(cmpt: dict) -> bool:
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 )
60def parse_component(ast: AST) -> dict[str, Element]:
61 """Helper function to parse the components elements."""
62 from phml.utils import check, visit_children # pylint: disable=import-outside-toplevel
64 result = {"python": [], "script": [], "style": [], "component": None}
65 for node in visit_children(ast.tree):
66 if check(node, ["element", {"tag": "python"}]):
67 result["python"].append(node)
68 elif check(node, ["element", {"tag": "script"}]):
69 result["script"].append(node)
70 elif check(node, ["element", {"tag": "style"}]):
71 result["style"].append(node)
72 elif check(node, "element"):
73 if result["component"] is None:
74 result["component"] = node
75 else:
76 raise Exception(
77 """\
78Components may only have one wrapping element. All other element in the root must be either a \
79script, style, or python tag.\
80"""
81 )
83 if result["component"] is None:
84 raise Exception("Must have at least one element in a component.")
86 return result