Coverage for src/midgy/front_matter.py: 90%

103 statements  

« prev     ^ index     » next       coverage.py v6.4.4, created at 2022-10-04 10:04 -0700

1from enum import Enum 

2from re import compile 

3 

4__all__ = ("load",) 

5SHEBANG = compile("^#!(?P<interpreter>\S+)\s+(?P<command>\S*)") 

6 

7 

8FM = Enum("FM", {"yaml": "-", "toml": "+"}) 

9 

10 

11def strip_and_classifiy(x): 

12 x = x.strip() 

13 return FM(x[0]), "".join(x.splitlines(True)[1:-1]) 

14 

15 

16def load(x): 

17 """load front matter including the delimiters. 

18 

19 --- and +++ reference yaml and toml front matter respectively.""" 

20 kind, x = strip_and_classifiy(x) 

21 return {FM.toml: load_toml, FM.yaml: load_yaml}[kind](x) 

22 

23 

24def load_toml(x): 

25 from tomli import loads 

26 

27 return loads(x) 

28 

29 

30def load_yaml(x): 

31 return _get_yaml_loader()(x) 

32 

33 

34def _get_yaml_loader(): 

35 loader = getattr(_get_yaml_loader, "loader", None) 

36 if loader: 

37 return loader 

38 try: 

39 from ruamel.yaml import safe_load as load 

40 except ModuleNotFoundError: 

41 try: 

42 from yaml import safe_load as load 

43 except ModuleNotFoundError: 

44 from json import loads as load 

45 _get_yaml_loader.loader = load 

46 return load 

47 

48 

49def _shebang_lexer(state, startLine, endLine, silent): 

50 start = state.bMarks[startLine] + state.tShift[startLine] 

51 maximum = state.eMarks[startLine] 

52 

53 # our front matter allows for indents and can occur at positions 

54 # other than 0 

55 # this should filter out non-front matter 

56 if state.tokens: 

57 return False 

58 

59 m = SHEBANG.match(state.src[start:maximum]) 

60 if not m: 

61 return False 

62 

63 parent = state.parentType 

64 line_max = state.lineMax 

65 

66 # this will prevent lazy continuations from ever going past our end marker 

67 state.lineMax = startLine 

68 

69 token = state.push("shebang", "", 0) 

70 token.hidden = True 

71 token.content = state.getLines(startLine, startLine + 1, 0, True) 

72 token.block = True 

73 

74 state.parentType = parent 

75 state.lineMax = line_max 

76 state.line = startLine + 1 

77 token.map = [startLine, state.line] 

78 

79 return True 

80 

81 

82def _front_matter_lexer(state, startLine, endLine, silent): 

83 auto_closed = False 

84 start = state.bMarks[startLine] + state.tShift[startLine] 

85 maximum = state.eMarks[startLine] 

86 src_len = len(state.src) 

87 if state.tokens: 

88 if len(state.tokens) == 1: 

89 if state.tokens[0].type != "shebang": 

90 return False 

91 

92 # our front matter allows for indents and can occur at positions 

93 # other than 0 

94 # this should filter out non-front matter 

95 

96 if state.sCount[startLine]: 

97 return False 

98 

99 if state.tokens: 

100 if len(state.tokens) > 1: 

101 return False 

102 if state.tokens[-1].type != "shebang": 

103 return False 

104 

105 markup = None 

106 if state.srcCharCode[start] == ord("-"): 

107 markup = "-" 

108 elif state.srcCharCode[start] == ord("+"): 

109 markup = "+" 

110 else: 

111 return False 

112 

113 if state.srcCharCode[start + 1 : maximum] != tuple(map(ord, (markup, markup))): 

114 return False 

115 

116 # Search for the end of the block 

117 nextLine = startLine 

118 

119 while True: 

120 nextLine += 1 

121 if nextLine >= endLine: 

122 return False 

123 

124 start = state.bMarks[nextLine] + state.tShift[nextLine] 

125 maximum = state.eMarks[nextLine] 

126 

127 if start < maximum and state.sCount[nextLine] < state.blkIndent: 

128 break 

129 

130 if ord(markup) != state.srcCharCode[start]: 

131 continue 

132 

133 if state.sCount[nextLine] - state.blkIndent >= 4: 

134 continue 

135 

136 if state.srcCharCode[start + 1 : maximum] == tuple(map(ord, (markup, markup))): 

137 auto_closed = True 

138 nextLine += 1 

139 break 

140 

141 parent = state.parentType 

142 line_max = state.lineMax 

143 state.parentType = "container" 

144 

145 # this will prevent lazy continuations from ever going past our end marker 

146 state.lineMax = nextLine 

147 

148 token = state.push("front_matter", "", 0) 

149 token.hidden = True 

150 token.markup = markup 

151 token.content = state.getLines(startLine, nextLine, 0, True) 

152 token.block = True 

153 

154 state.parentType = parent 

155 state.lineMax = line_max 

156 state.line = nextLine 

157 token.map = [startLine, state.line] 

158 

159 return True