Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/tinycss2/serializer.py: 35%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

43 statements  

1import re 

2 

3 

4def serialize(nodes): 

5 """Serialize nodes to CSS syntax. 

6 

7 This should be used for :term:`component values` 

8 instead of just :meth:`tinycss2.ast.Node.serialize` on each node 

9 as it takes care of corner cases such as ``;`` between declarations, 

10 and consecutive identifiers 

11 that would otherwise parse back as the same token. 

12 

13 :type nodes: :term:`iterable` 

14 :param nodes: An iterable of :class:`tinycss2.ast.Node` objects. 

15 :returns: A :obj:`string <str>` representing the nodes. 

16 

17 """ 

18 chunks = [] 

19 _serialize_to(nodes, chunks.append) 

20 return ''.join(chunks) 

21 

22 

23def serialize_identifier(value): 

24 """Serialize any string as a CSS identifier 

25 

26 :type value: :obj:`str` 

27 :param value: A string representing a CSS value. 

28 :returns: 

29 A :obj:`string <str>` that would parse as an 

30 :class:`tinycss2.ast.IdentToken` whose 

31 :attr:`tinycss2.ast.IdentToken.value` attribute equals the passed 

32 ``value`` argument. 

33 

34 """ 

35 if value == '-': 

36 return r'\-' 

37 

38 if value[:2] == '--': 

39 return '--' + serialize_name(value[2:]) 

40 

41 if value[0] == '-': 

42 result = '-' 

43 value = value[1:] 

44 else: 

45 result = '' 

46 c = value[0] 

47 result += ( 

48 c if c in ('abcdefghijklmnopqrstuvwxyz_' 

49 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') or ord(c) > 0x7F else 

50 r'\A ' if c == '\n' else 

51 r'\D ' if c == '\r' else 

52 r'\C ' if c == '\f' else 

53 '\\%X ' % ord(c) if c in '0123456789' else 

54 '\\' + c 

55 ) 

56 result += serialize_name(value[1:]) 

57 return result 

58 

59 

60def serialize_name(value): 

61 return ''.join( 

62 c if c in ('abcdefghijklmnopqrstuvwxyz-_0123456789' 

63 'ABCDEFGHIJKLMNOPQRSTUVWXYZ') or ord(c) > 0x7F else 

64 r'\A ' if c == '\n' else 

65 r'\D ' if c == '\r' else 

66 r'\C ' if c == '\f' else 

67 '\\' + c 

68 for c in value 

69 ) 

70 

71 

72_replacement_string_value = { 

73 '"': r'\"', 

74 '\\': r'\\', 

75 '\n': r'\A ', 

76 '\r': r'\D ', 

77 '\f': r'\C ', 

78} 

79_re_string_value = ''.join(re.escape(char) for char in _replacement_string_value) 

80_re_string_value = re.compile(f'[{_re_string_value}]', re.MULTILINE) 

81def _serialize_string_value_match(match): 

82 return _replacement_string_value[match.group(0)] 

83def serialize_string_value(value): 

84 return _re_string_value.sub(_serialize_string_value_match, value) 

85 

86 

87def serialize_url(value): 

88 return ''.join( 

89 r"\'" if c == "'" else 

90 r'\"' if c == '"' else 

91 r'\\' if c == '\\' else 

92 r'\ ' if c == ' ' else 

93 r'\9 ' if c == '\t' else 

94 r'\A ' if c == '\n' else 

95 r'\D ' if c == '\r' else 

96 r'\C ' if c == '\f' else 

97 r'\(' if c == '(' else 

98 r'\)' if c == ')' else 

99 c 

100 for c in value 

101 ) 

102 

103 

104# https://drafts.csswg.org/css-syntax/#serialization-tables 

105def _serialize_to(nodes, write): 

106 """Serialize an iterable of nodes to CSS syntax. 

107 

108 White chunks as a string by calling the provided :obj:`write` callback. 

109 

110 """ 

111 bad_pairs = BAD_PAIRS 

112 previous_type = None 

113 for node in nodes: 

114 serialization_type = (node.type if node.type != 'literal' 

115 else node.value) 

116 if (previous_type, serialization_type) in bad_pairs: 

117 write('/**/') 

118 elif previous_type == '\\' and not ( 

119 serialization_type == 'whitespace' and 

120 node.value.startswith('\n')): 

121 write('\n') 

122 node._serialize_to(write) 

123 if serialization_type == 'declaration': 

124 write(';') 

125 previous_type = serialization_type 

126 

127 

128BAD_PAIRS = set( 

129 [(a, b) 

130 for a in ('ident', 'at-keyword', 'hash', 'dimension', '#', '-', 'number') 

131 for b in ('ident', 'function', 'url', 'number', 'percentage', 

132 'dimension', 'unicode-range')] + 

133 [(a, b) 

134 for a in ('ident', 'at-keyword', 'hash', 'dimension') 

135 for b in ('-', '-->')] + 

136 [(a, b) 

137 for a in ('#', '-', 'number', '@') 

138 for b in ('ident', 'function', 'url')] + 

139 [(a, b) 

140 for a in ('unicode-range', '.', '+') 

141 for b in ('number', 'percentage', 'dimension')] + 

142 [('@', b) for b in ('ident', 'function', 'url', 'unicode-range', '-')] + 

143 [('unicode-range', b) for b in ('ident', 'function', '?')] + 

144 [(a, '=') for a in '$*^~|'] + 

145 [('ident', '() block'), ('|', '|'), ('/', '*')] 

146)