canon 0.3.98 → 0.3.99

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07c9d8c96426b670ad088e3b96e662b45283c4868e99c27a5afb5a6ecb537780
4
- data.tar.gz: 5e8bc5ee7aa5b1e1b75b158d1afc68f3035e1c58bcd3da4624fdebbbbc83b4a6
3
+ metadata.gz: 4e993fe0bac445ec82e1a02983bfa2f297c1b7d9d112bcb7c724f3f010a1b353
4
+ data.tar.gz: 869324e74378af4f4cb9493fbfdc04ac1ba8e76c0378159547bc7e23ebf66084
5
5
  SHA512:
6
- metadata.gz: 813b81bd8fe090e71c9729d18326e864b0af54129e422ae4d624676ed8e191f6b2b278e5dab5e00c1827fccaed9658e5bd85a9ef6ac908c9e0cc4ff97d33839e
7
- data.tar.gz: 6819b9252b0e6f27efec816241b1444d1ff92456562996ddc0c89a8f07b04eb41d48302025fda8776581437fb793da24db3ed21fec2b1589522c0680739bd99c
6
+ metadata.gz: 70c6dcb6bb9da7ef764f9aed9e1e8d02fb95193c446102df62496a10dbe33010d29b5d0e90293d929cf3adc267b5128ad1dd7e9666dff38b892d221bc681f20c
7
+ data.tar.gz: dc45835bdab2c58479e8413eb87aee5c8615237ebf6bd2c435ae725b58b7df247c3740c25a3ab192fb0aaf86c6776d3634c5a66170ea6834a3f3bedf5582fd27
@@ -295,8 +295,8 @@ module Canon
295
295
  Canon::Xml::C14n.canonicalize(html_string,
296
296
  with_comments: false)
297
297
  when :format
298
- # Pretty format
299
- Canon.format(html_string, :html)
298
+ # Engine single-line structural normalizer
299
+ Canon::Html::DataModel.engine_html_format(html_string)
300
300
  else
301
301
  # :none or unrecognized
302
302
  html_string
@@ -375,8 +375,8 @@ module Canon
375
375
  Canon::Xml::C14n.canonicalize(node,
376
376
  with_comments: false)
377
377
  when :format
378
- # Pretty format the HTML
379
- Canon.format(node, :html)
378
+ # Engine single-line structural normalizer
379
+ Canon::Html::DataModel.engine_html_format(node)
380
380
  else
381
381
  # :none, :rendered or unrecognized - use as-is
382
382
  node
@@ -60,29 +60,10 @@ module Canon
60
60
  end
61
61
 
62
62
  # Parse an HTML string through the engine's WHATWG fragment
63
- # parsing and build a Canon tree from the fragment children.
64
- # Whitespace text nodes are preserved unconditionally — HTML
65
- # whitespace significance is the comparison profile's decision
66
- # (#112/#137 ride on stray whitespace surviving the parse),
67
- # unlike the XML DOM lane's parse-time policy. Top-level
68
- # element children convert through the materialize-records
69
- # fast path; the wrapper walk serves the rare non-element
70
- # top-level nodes (text, comments).
63
+ # parsing and build a Canon tree. Canon::Html::DataModel owns
64
+ # the conversion (the single home for HTML→Canon-tree building).
71
65
  def engine_fragment(html)
72
- frag = Canon::XmlParsing.moxml_context.parse_html_fragment(html)
73
- root = Canon::Xml::Nodes::RootNode.new
74
- frag.children.each do |child|
75
- node =
76
- if child.is_a?(Moxml::Element)
77
- Canon::Xml::DataModel.build_moxml_subtree_from_records(
78
- child, preserve_whitespace: true
79
- )
80
- else
81
- Canon::Xml::DataModel.walk_moxml(child, preserve_whitespace: true)
82
- end
83
- root.add_child(node) if node
84
- end
85
- root
66
+ Canon::Html::DataModel.engine_fragment(html)
86
67
  end
87
68
 
88
69
  # Engine HTML fragments are served by adapters with an engine
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Canon::NokogiriLoader.require!("HTML support")
4
-
5
3
  module Canon
6
4
  module Html
7
5
  # Builds XPath data model from HTML
@@ -10,58 +8,53 @@ module Canon
10
8
  class DataModel < Canon::DataModel
11
9
  # Build XPath data model from HTML string
12
10
  #
11
+ # The engine lane: moxml Context#parse_html_fragment (WHATWG
12
+ # fragment parsing) → Canon tree. The +version:+ parameter is
13
+ # accepted for API compatibility — the engine serves every input
14
+ # through one WHATWG parse (the #118 html4/html5 unification).
15
+ # Full documents keep their head content at the fragment top
16
+ # level (the in-body rules ignore the html/body start tags but
17
+ # preserve every other node); the former Nokogiri body-extraction
18
+ # dropped head content entirely.
19
+ #
13
20
  # @param html_string [String] HTML content to parse
14
- # @param version [Symbol] HTML version (:html4 or :html5)
21
+ # @param version [Symbol] accepted for compatibility; unused
15
22
  # @return [Canon::Xml::Nodes::RootNode] Root of the data model tree
23
+ # rubocop:disable-next Lint/UnusedMethodArgument -- API compatibility
16
24
  def self.from_html(html_string, version: :html4)
17
- # Detect if this is a full document (has <html> tag) or fragment
18
- # Full documents should use document parser to preserve structure
19
- # Fragments should use fragment parser to avoid adding implicit wrappers
20
- is_full_document = html_string.match?(%r{<html[\s>]}i)
21
-
22
- # Parse with Nokogiri using appropriate parser
23
- doc = if is_full_document
24
- # CRITICAL FIX: For full HTML documents, parse as document first
25
- # and extract the body element. This avoids Nokogiri::HTML.fragment()
26
- # incorrectly moving head elements (like meta) to the body.
27
- # Parse as full document to get proper structure
28
- full_doc = if version == :html5
29
- Nokogiri::HTML5(html_string)
30
- else
31
- Nokogiri::HTML4(html_string)
32
- end
33
- # Extract body element and create fragment from it
34
- body = full_doc.at_css("body")
35
- if body
36
- # Create a fragment and copy body children to it
37
- # This preserves the body structure without head elements
38
- frag = if version == :html5
39
- Nokogiri::HTML5::DocumentFragment.new(full_doc)
40
- else
41
- Nokogiri::HTML4::DocumentFragment.new(full_doc)
42
- end
43
- body.children.each do |child|
44
- frag.add_child(child.dup)
45
- end
46
- frag
47
- elsif version == :html5
48
- # No body found, fall back to fragment parsing
49
- Nokogiri::HTML5.fragment(html_string)
50
- else
51
- Nokogiri::HTML4.fragment(html_string)
52
- end
53
- elsif version == :html5
54
- # Fragment - use fragment parser to avoid implicit wrappers
55
- Nokogiri::HTML5.fragment(html_string)
56
- else
57
- Nokogiri::HTML4.fragment(html_string)
58
- end
25
+ engine_fragment(html_string)
26
+ end
59
27
 
60
- # HTML doesn't have strict namespace requirements like XML,
61
- # so skip the relative namespace URI check
28
+ # Parse an HTML string through the engine's WHATWG fragment
29
+ # parsing and build a Canon tree from the fragment children.
30
+ # Whitespace text nodes are preserved unconditionally — HTML
31
+ # whitespace significance is the comparison profile's decision
32
+ # (#112/#137), unlike the XML DOM lane's parse-time policy.
33
+ # Top-level element children convert through the
34
+ # materialize-records fast path; the wrapper walk serves the
35
+ # rare non-element top-level nodes (text, comments).
36
+ def self.engine_fragment(html)
37
+ frag = Canon::XmlParsing.moxml_context.parse_html_fragment(html)
38
+ root = Canon::Xml::Nodes::RootNode.new
39
+ frag.children.each do |child|
40
+ node =
41
+ if child.is_a?(Moxml::Element)
42
+ Canon::Xml::DataModel.build_moxml_subtree_from_records(
43
+ child, preserve_whitespace: true
44
+ )
45
+ else
46
+ Canon::Xml::DataModel.walk_moxml(child, preserve_whitespace: true)
47
+ end
48
+ root.add_child(node) if node
49
+ end
50
+ root
51
+ end
62
52
 
63
- # Convert to XPath data model (reuse XML infrastructure)
64
- build_from_nokogiri(doc)
53
+ # Deterministic single-line engine formatting for the :format
54
+ # string preprocessor — parse + re-serialize as a pure function
55
+ # of the parsed tree.
56
+ def self.engine_html_format(html)
57
+ Canon::XmlParsing.moxml_context.parse_html(html).to_html
65
58
  end
66
59
 
67
60
  # Alias for compatibility
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- Canon::NokogiriLoader.require!("HTML tree diffing")
4
-
5
3
  module Canon
6
4
  module TreeDiff
7
5
  module Adapters
@@ -46,17 +44,22 @@ module Canon
46
44
  return to_tree_from_canon_comment(node)
47
45
  end
48
46
 
49
- # Fallback to Nokogiri (legacy support)
50
- case node
51
- when Nokogiri::HTML::Document, Nokogiri::HTML4::Document, Nokogiri::HTML5::Document
52
- # Start from html element or root element
53
- root = node.at_css("html") || node.root
54
- root ? to_tree(root) : nil
55
- when Nokogiri::HTML4::DocumentFragment, Nokogiri::HTML5::DocumentFragment, Nokogiri::XML::DocumentFragment
56
- # For DocumentFragment, create a wrapper root node and add all fragment children
57
- convert_fragment(node)
58
- when Nokogiri::XML::Element
59
- convert_element(node)
47
+ # Fallback to Nokogiri (legacy support for user-supplied
48
+ # nodes) — the Canon tree branches above run nokogiri-less.
49
+ if defined?(Nokogiri)
50
+ case node
51
+ when Nokogiri::HTML::Document, Nokogiri::HTML4::Document, Nokogiri::HTML5::Document
52
+ # Start from html element or root element
53
+ root = node.at_css("html") || node.root
54
+ root ? to_tree(root) : nil
55
+ when Nokogiri::HTML4::DocumentFragment, Nokogiri::HTML5::DocumentFragment, Nokogiri::XML::DocumentFragment
56
+ # For DocumentFragment, create a wrapper root node and add all fragment children
57
+ convert_fragment(node)
58
+ when Nokogiri::XML::Element
59
+ convert_element(node)
60
+ else
61
+ raise ArgumentError, "Unsupported node type: #{node.class}"
62
+ end
60
63
  else
61
64
  raise ArgumentError, "Unsupported node type: #{node.class}"
62
65
  end
@@ -68,7 +71,10 @@ module Canon
68
71
  # @param doc [Nokogiri::HTML::Document] Optional document to use
69
72
  # @return [Nokogiri::HTML::Document, Nokogiri::XML::Element]
70
73
  def from_tree(tree_node, doc = nil)
71
- doc ||= Nokogiri::HTML::Document.new
74
+ unless doc
75
+ Canon::NokogiriLoader.require!("HTML tree reconstruction")
76
+ doc = Nokogiri::HTML::Document.new
77
+ end
72
78
 
73
79
  element = build_element(tree_node, doc)
74
80
 
data/lib/canon/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Canon
4
- VERSION = "0.3.98"
4
+ VERSION = "0.3.99"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.98
4
+ version: 0.3.99
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.