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

1# pylint: disable=missing-module-docstring 

2from pathlib import Path 

3 

4from phml.nodes import AST, All_Nodes, Element 

5 

6__all__ = [ 

7 "tag_from_file", 

8 "filename_from_path", 

9 "parse_component", 

10 "valid_component_dict", 

11] 

12 

13 

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) 

40 

41 

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(f"Expected {type(Path)} not {type(file)}") 

49 

50 

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 ) 

58 

59 

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 

63 

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 ) 

82 

83 if result["component"] is None: 

84 raise Exception("Must have at least one element in a component.") 

85 

86 return result