Coverage for phml\misc\component.py: 100%

41 statements  

« prev     ^ index     » next       coverage.py v6.5.0, created at 2022-12-08 16:33 -0600

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