canon 0.3.57 → 0.3.58
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/canon/tree_diff/core/node_signature.rb +2 -41
- data/lib/canon/tree_diff/core/tree_node.rb +40 -0
- data/lib/canon/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: c1b3bba3210fd3ca95a66a4a3e439f6b9e1a0f95b30ddf4d90f4069a2b5a6d8b
|
|
4
|
+
data.tar.gz: fadf6bdf8fb892fbb3998d53754f599b17fac80b099936d77a7dae0881e4f5c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e551b02b98c802c3d2593c1f684c89d271b223892fb32dbd20f186fe6cb13e06d18bd079839298325eb1d8a798b962876af9c95177763268ae291fc503828552
|
|
7
|
+
data.tar.gz: 8485c2e7e3049386ff977fca9c4162b44d439a2c218067f3aefe4a3b596d0f351b60c0c18a7f9fd0d5bcbf77192a0525c84dac7c1b35fe7f92369737f6dc2308
|
|
@@ -106,50 +106,11 @@ module Canon
|
|
|
106
106
|
if node.label.nil? || label_str.empty? || label_str == "#text" || label_str == "text"
|
|
107
107
|
"#text"
|
|
108
108
|
else
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
# Include sorted attributes to distinguish nodes with same label
|
|
112
|
-
# but different attributes (while ignoring attribute order)
|
|
113
|
-
# Only include attributes if requested (for hash matching)
|
|
114
|
-
if @include_attributes && !node.attributes.empty?
|
|
115
|
-
sorted_attrs = node.attributes.sort.to_h
|
|
116
|
-
attrs_str = sorted_attrs.map { |k, v| "#{k}=#{v}" }.join(",")
|
|
117
|
-
component += "{#{attrs_str}}"
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# CRITICAL: For whitespace-sensitive HTML elements, include the text value
|
|
121
|
-
# in the signature to prevent incorrect matching of nodes with different whitespace
|
|
122
|
-
if @include_attributes && whitespace_sensitive?(node) && node.value
|
|
123
|
-
# Include text value in signature for whitespace-sensitive elements
|
|
124
|
-
# Use inspect to make whitespace visible and handle special characters
|
|
125
|
-
component += "[text=#{node.value.inspect}]"
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
component
|
|
109
|
+
# Memoized on the node — see TreeNode#signature_component.
|
|
110
|
+
node.signature_component(include_attributes: @include_attributes)
|
|
129
111
|
end
|
|
130
112
|
end
|
|
131
113
|
|
|
132
|
-
# Check if a node is in a whitespace-sensitive context
|
|
133
|
-
#
|
|
134
|
-
# HTML elements where whitespace is significant: <pre>, <code>, <textarea>, <script>, <style>
|
|
135
|
-
#
|
|
136
|
-
# @param node [TreeNode] Node to check
|
|
137
|
-
# @return [Boolean] True if node is whitespace-sensitive
|
|
138
|
-
def whitespace_sensitive?(node)
|
|
139
|
-
return false unless node
|
|
140
|
-
|
|
141
|
-
# List of HTML elements where whitespace is semantically significant
|
|
142
|
-
whitespace_sensitive_tags = %w[pre code textarea script style]
|
|
143
|
-
|
|
144
|
-
# Check if this node is whitespace-sensitive
|
|
145
|
-
if node.is_a?(TreeNode)
|
|
146
|
-
label = node.label.to_s.downcase
|
|
147
|
-
return true if whitespace_sensitive_tags.include?(label)
|
|
148
|
-
end
|
|
149
|
-
|
|
150
|
-
false
|
|
151
|
-
end
|
|
152
|
-
|
|
153
114
|
# Compute signature string from path
|
|
154
115
|
#
|
|
155
116
|
# @return [String]
|
|
@@ -50,6 +50,22 @@ module Canon
|
|
|
50
50
|
@weight = nil
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
# Signature path component (see NodeSignature): the label plus
|
|
54
|
+
# sorted attributes (and whitespace-sensitive text value) when
|
|
55
|
+
# +include_attributes+. Memoized per variant — signatures
|
|
56
|
+
# rebuild ancestor components for every node they cover, which
|
|
57
|
+
# is quadratic over the tree without it.
|
|
58
|
+
#
|
|
59
|
+
# @param include_attributes [Boolean]
|
|
60
|
+
# @return [String]
|
|
61
|
+
def signature_component(include_attributes: true)
|
|
62
|
+
if include_attributes
|
|
63
|
+
@signature_component_attrs ||= build_signature_component(true)
|
|
64
|
+
else
|
|
65
|
+
@signature_component ||= build_signature_component(false)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
53
69
|
# Check if this is a leaf node (no children)
|
|
54
70
|
#
|
|
55
71
|
# @return [Boolean]
|
|
@@ -57,6 +73,30 @@ module Canon
|
|
|
57
73
|
children.empty?
|
|
58
74
|
end
|
|
59
75
|
|
|
76
|
+
# Elements where whitespace is semantically significant; their
|
|
77
|
+
# text value participates in the signature (see NodeSignature).
|
|
78
|
+
WHITESPACE_SENSITIVE_TAGS = %w[pre code textarea script style].freeze
|
|
79
|
+
|
|
80
|
+
def build_signature_component(include_attributes)
|
|
81
|
+
component = label.to_s
|
|
82
|
+
|
|
83
|
+
# Sorted attributes distinguish same-label nodes while
|
|
84
|
+
# ignoring attribute order.
|
|
85
|
+
if include_attributes && !attributes.empty?
|
|
86
|
+
component += "{#{attributes.sort.map { |k, v| "#{k}=#{v}" }.join(',')}}" # rubocop:disable Style/StringConcatenation
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
if include_attributes &&
|
|
90
|
+
WHITESPACE_SENSITIVE_TAGS.include?(label.to_s.downcase) && value
|
|
91
|
+
# inspect makes whitespace visible and handles special
|
|
92
|
+
# characters.
|
|
93
|
+
component += "[text=#{value.inspect}]"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
component
|
|
97
|
+
end
|
|
98
|
+
private :build_signature_component
|
|
99
|
+
|
|
60
100
|
# Check if this is a text node (leaf with value)
|
|
61
101
|
#
|
|
62
102
|
# @return [Boolean]
|
data/lib/canon/version.rb
CHANGED