canon 0.3.77 → 0.3.78
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/pretty_printer/xml.rb +21 -2
- data/lib/canon/version.rb +1 -1
- data/lib/canon/xml_backend.rb +5 -2
- data/lib/canon/xml_parsing.rb +51 -0
- metadata +8 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 031d0a1ecb48c26cb773e79d791d7ae090fa1231eb3132fbdf3d9138b0afcab6
|
|
4
|
+
data.tar.gz: 63dd55aa45a123cc1c39e6072033363def2bd0f6b6fc8de9ab88edd8a7f16ae4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a77a02d18d89482275d8e288951b7bda5f4bb144fea76e08e21ce484df42ee4928d666cb45b7cba0f63d025b3bbda59f4e2550ed81e6190f7154cbe4c2c79931
|
|
7
|
+
data.tar.gz: 4bb93c91e98b9f04ff0513a17559a4eed805c5f7d8a3385dfd3f11e5af929c31d327eab1228c616b5712ace68cdcd8fdabcd49dbb25e5af14b3fb2160c40cc0f
|
|
@@ -28,6 +28,21 @@ module Canon
|
|
|
28
28
|
def nokogiri_format(xml_string)
|
|
29
29
|
Canon::NokogiriLoader.require!("Nokogiri-engine XML pretty-printing")
|
|
30
30
|
doc = Nokogiri::XML(xml_string, &:noblanks)
|
|
31
|
+
|
|
32
|
+
# The loud/tolerant contract, Nokogiri-lane edition: the
|
|
33
|
+
# non-strict parse recovers malformed input and records the
|
|
34
|
+
# errors — non-HTML malformed input stays loud, HTML-shaped
|
|
35
|
+
# input falls back to the HTML parser (mirrors
|
|
36
|
+
# XmlParsing.parse_with_html_fallback).
|
|
37
|
+
if doc.errors.any?
|
|
38
|
+
unless Canon::XmlParsing.html_shaped?(xml_string)
|
|
39
|
+
raise Moxml::ParseError,
|
|
40
|
+
doc.errors.map(&:message).join("; ")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
doc = Nokogiri::HTML4(xml_string, &:noblanks)
|
|
44
|
+
end
|
|
45
|
+
|
|
31
46
|
if @indent_type == "tab"
|
|
32
47
|
doc.to_xml(indent: 1, indent_text: "\t", encoding: "UTF-8")
|
|
33
48
|
else
|
|
@@ -37,8 +52,12 @@ module Canon
|
|
|
37
52
|
|
|
38
53
|
def moxml_format(xml_string)
|
|
39
54
|
# noblanks mutates the tree (strips whitespace-only text), so
|
|
40
|
-
# the document cannot be readonly.
|
|
41
|
-
|
|
55
|
+
# the document cannot be readonly. HTML producers' output
|
|
56
|
+
# (Asciidoctor cover pages) routes through the tolerant HTML
|
|
57
|
+
# mode instead of failing the comparison (leptris#1564).
|
|
58
|
+
doc = Canon::XmlParsing.parse_with_html_fallback(
|
|
59
|
+
xml_string, noblanks: true
|
|
60
|
+
)
|
|
42
61
|
if @indent_type == "tab"
|
|
43
62
|
doc.to_xml(declaration: true, encoding: "UTF-8",
|
|
44
63
|
indent: 1, indent_text: "\t", expand_empty: false)
|
data/lib/canon/version.rb
CHANGED
data/lib/canon/xml_backend.rb
CHANGED
|
@@ -6,8 +6,11 @@ module Canon
|
|
|
6
6
|
# Two independent concerns, deliberately separated (MECE):
|
|
7
7
|
# - XML engine — :nokogiri (raw) or :moxml (adapter-mediated). Drives DOM
|
|
8
8
|
# parsing and serialization of XML (see Canon::XmlParsing).
|
|
9
|
-
# - HTML support —
|
|
10
|
-
#
|
|
9
|
+
# - HTML support — the dedicated HTML pipeline stays on Nokogiri
|
|
10
|
+
# (see Canon::Html::NokogiriSupport); the XML lane additionally
|
|
11
|
+
# accepts HTML-shaped content through moxml's Context#parse_html
|
|
12
|
+
# (engine HTML modes: leptris >= 1.9.80, nokogiri) — see
|
|
13
|
+
# XmlParsing.parse_with_html_fallback (leptris#1564).
|
|
11
14
|
#
|
|
12
15
|
# SSOT: moxml owns adapter preference (Moxml::Config prefers leptris
|
|
13
16
|
# when installed; see XmlParsing.moxml_adapter_name). Both engines
|
data/lib/canon/xml_parsing.rb
CHANGED
|
@@ -44,6 +44,36 @@ module Canon
|
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# leptris#1564: HTML producers' output (void elements, unclosed
|
|
48
|
+
# tags, inline JS with bare <) is not well-formed XML, but the
|
|
49
|
+
# comparison pretty-printer still needs a tree. HTML-SHAPED
|
|
50
|
+
# content — a <!DOCTYPE html> declaration or an <html> root —
|
|
51
|
+
# parses through the engine's tolerant HTML mode (moxml
|
|
52
|
+
# Context#parse_html; adapters with an engine HTML mode, leptris
|
|
53
|
+
# >= 1.9.80 and nokogiri alike). Anything else re-raises:
|
|
54
|
+
# malformed XML stays loud.
|
|
55
|
+
def parse_with_html_fallback(xml_string, options = {})
|
|
56
|
+
doc = moxml_context.parse(xml_string, options)
|
|
57
|
+
|
|
58
|
+
# Engines differ in how strict:false treats malformed input —
|
|
59
|
+
# some raise, some recover and record. The loud/tolerant
|
|
60
|
+
# contract keys off the RECORD, not the raise: non-HTML
|
|
61
|
+
# malformed input stays loud; HTML-shaped input falls back to
|
|
62
|
+
# the HTML parser. Engine-independent by construction.
|
|
63
|
+
recorded = doc.respond_to?(:parse_errors) ? doc.parse_errors : []
|
|
64
|
+
if recorded.any?
|
|
65
|
+
raise Moxml::ParseError, recorded.join("; ") unless html_shaped?(xml_string)
|
|
66
|
+
|
|
67
|
+
return moxml_context.parse_html(xml_string)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
doc
|
|
71
|
+
rescue Moxml::ParseError
|
|
72
|
+
raise unless html_shaped?(xml_string)
|
|
73
|
+
|
|
74
|
+
moxml_context.parse_html(xml_string)
|
|
75
|
+
end
|
|
76
|
+
|
|
47
77
|
def parse_fragment(xml_string)
|
|
48
78
|
if XmlBackend.nokogiri?
|
|
49
79
|
Nokogiri::XML.fragment(xml_string).children.to_a
|
|
@@ -53,6 +83,27 @@ module Canon
|
|
|
53
83
|
end
|
|
54
84
|
end
|
|
55
85
|
|
|
86
|
+
# Conservative HTML sniff on the document head: the fallback
|
|
87
|
+
# must never swallow a genuinely malformed XML comparison —
|
|
88
|
+
# only content that declares itself HTML. Index-based scan,
|
|
89
|
+
# no regex: the previous regex form was polynomial on
|
|
90
|
+
# uncontrolled data (CodeQL).
|
|
91
|
+
def html_shaped?(xml_string)
|
|
92
|
+
head = xml_string.to_s.slice(0, 2048).downcase
|
|
93
|
+
return true if head.include?("<!doctype html")
|
|
94
|
+
|
|
95
|
+
root = head.lstrip
|
|
96
|
+
return false unless root.start_with?("<?xml")
|
|
97
|
+
|
|
98
|
+
close = root.index("?>")
|
|
99
|
+
return false unless close
|
|
100
|
+
|
|
101
|
+
root = root[(close + 2)..].lstrip
|
|
102
|
+
delimiter = root[5]
|
|
103
|
+
root.start_with?("<html") &&
|
|
104
|
+
(delimiter.nil? || " \t\n\r\f>/'\"".include?(delimiter))
|
|
105
|
+
end
|
|
106
|
+
|
|
56
107
|
# --- Serialization ---
|
|
57
108
|
|
|
58
109
|
def serialize(node)
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: canon
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.78
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-10-
|
|
11
|
+
date: 2026-10-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: diff-lcs
|
|
@@ -44,28 +44,28 @@ dependencies:
|
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: 1.9.
|
|
47
|
+
version: 1.9.314
|
|
48
48
|
type: :runtime
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: 1.9.
|
|
54
|
+
version: 1.9.314
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: moxml
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: 0.5.
|
|
61
|
+
version: 0.5.116
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: 0.5.
|
|
68
|
+
version: 0.5.116
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: paint
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -142,14 +142,14 @@ dependencies:
|
|
|
142
142
|
requirements:
|
|
143
143
|
- - "~>"
|
|
144
144
|
- !ruby/object:Gem::Version
|
|
145
|
-
version: 0.6.
|
|
145
|
+
version: 0.6.29
|
|
146
146
|
type: :runtime
|
|
147
147
|
prerelease: false
|
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
|
149
149
|
requirements:
|
|
150
150
|
- - "~>"
|
|
151
151
|
- !ruby/object:Gem::Version
|
|
152
|
-
version: 0.6.
|
|
152
|
+
version: 0.6.29
|
|
153
153
|
description: |-
|
|
154
154
|
Canon provides canonicalization and pretty-printing for various serialization
|
|
155
155
|
formats (XML, HTML, JSON, YAML), producing standardized forms suitable for
|