canon 0.3.45 → 0.3.47
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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 8180f10b0965070c408985ca44868fc14ae2256f24dac607492470aea7e5d076
|
|
4
|
+
data.tar.gz: e50498b713b972237a67af3b3f5c2cd5fb0cf1cbc3fef0dbb57f628810ce2341
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 52c5eb3fcb8ab3e09c7de5b8b7120f2baad191467aeccab6154254cd0007128f76ae2f5dbd26102abf19c3cf9f289f3c0445db88917562d7b7edafe9aef7ae5b
|
|
7
|
+
data.tar.gz: 373032bcba62f9685c41f09bb0d3dce294c50fa8785252e3737231a67f9a0fdfdb5372c85f3b28da5983faf39d4cdf89723dfae8397969511d2688afecaf3418
|
|
@@ -21,19 +21,22 @@ module Canon
|
|
|
21
21
|
# @param text1 [String] The first document (preprocessed)
|
|
22
22
|
# @param text2 [String] The second document (preprocessed)
|
|
23
23
|
# @return [Array<DiffLine>] The assembled diff lines
|
|
24
|
-
def self.build(diff_nodes, text1, text2)
|
|
24
|
+
def self.build(diff_nodes, text1, text2, lines1: nil, lines2: nil)
|
|
25
25
|
return [] if diff_nodes.nil? || diff_nodes.empty?
|
|
26
26
|
return [] if text1.nil? || text2.nil?
|
|
27
27
|
|
|
28
|
-
new(diff_nodes, text1, text2).build
|
|
28
|
+
new(diff_nodes, text1, text2, lines1, lines2).build
|
|
29
29
|
end
|
|
30
30
|
|
|
31
|
-
def initialize(diff_nodes, text1, text2)
|
|
31
|
+
def initialize(diff_nodes, text1, text2, lines1 = nil, lines2 = nil)
|
|
32
32
|
@diff_nodes = diff_nodes
|
|
33
33
|
@text1 = text1
|
|
34
34
|
@text2 = text2
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
# The caller may hand in the already-split lines (the
|
|
36
|
+
# formatter splits these documents too); re-splitting both
|
|
37
|
+
# documents per pipeline stage was ~2x the line strings.
|
|
38
|
+
@lines1 = lines1 || text1.split("\n")
|
|
39
|
+
@lines2 = lines2 || text2.split("\n")
|
|
37
40
|
# Build reverse indices for efficient content lookup in gap handling.
|
|
38
41
|
# Maps content string to array of line indices where that content appears.
|
|
39
42
|
@line_to_indices1 = build_line_index(@lines1)
|
|
@@ -22,21 +22,22 @@ module Canon
|
|
|
22
22
|
# @param text1 [String] The first document (preprocessed)
|
|
23
23
|
# @param text2 [String] The second document (preprocessed)
|
|
24
24
|
# @return [Array<DiffNode>] The same DiffNodes, enriched in place
|
|
25
|
-
def self.build(diff_nodes, text1, text2)
|
|
25
|
+
def self.build(diff_nodes, text1, text2, lines1: nil, lines2: nil)
|
|
26
26
|
return diff_nodes if diff_nodes.nil? || diff_nodes.empty?
|
|
27
27
|
return diff_nodes if text1.nil? || text2.nil?
|
|
28
28
|
|
|
29
|
-
new(diff_nodes, text1, text2).enrich
|
|
29
|
+
new(diff_nodes, text1, text2, lines1, lines2).enrich
|
|
30
30
|
end
|
|
31
31
|
|
|
32
|
-
def initialize(diff_nodes, text1, text2)
|
|
32
|
+
def initialize(diff_nodes, text1, text2, lines1 = nil, lines2 = nil)
|
|
33
33
|
@diff_nodes = diff_nodes
|
|
34
34
|
@text1 = text1
|
|
35
35
|
@text2 = text2
|
|
36
36
|
@line_map1 = SourceLocator.build_line_map(text1)
|
|
37
37
|
@line_map2 = SourceLocator.build_line_map(text2)
|
|
38
|
-
|
|
39
|
-
@
|
|
38
|
+
# Shared split — see DiffLineBuilder's note.
|
|
39
|
+
@lines1 = lines1 || text1.split("\n")
|
|
40
|
+
@lines2 = lines2 || text2.split("\n")
|
|
40
41
|
# Track occurrences for text_content dimension to find correct element instance
|
|
41
42
|
@text_occurrence1 = Hash.new(0)
|
|
42
43
|
@text_occurrence2 = Hash.new(0)
|
|
@@ -44,12 +44,22 @@ module Canon
|
|
|
44
44
|
# Compute line number width BEFORE formatting
|
|
45
45
|
compute_line_num_width(doc1, doc2)
|
|
46
46
|
|
|
47
|
+
# The pipeline splits both documents once here; every stage
|
|
48
|
+
# downstream reuses the arrays (three redundant full-doc
|
|
49
|
+
# splits per render before).
|
|
50
|
+
@pipeline_lines1 = doc1.split("\n")
|
|
51
|
+
@pipeline_lines2 = doc2.split("\n")
|
|
52
|
+
|
|
47
53
|
# Phase 1: Enrich DiffNodes with character positions
|
|
48
|
-
Canon::Diff::DiffNodeEnricher.build(@differences, doc1, doc2
|
|
54
|
+
Canon::Diff::DiffNodeEnricher.build(@differences, doc1, doc2,
|
|
55
|
+
lines1: @pipeline_lines1,
|
|
56
|
+
lines2: @pipeline_lines2)
|
|
49
57
|
|
|
50
58
|
# Phase 2: Assemble DiffLines from enriched DiffNodes
|
|
51
59
|
diff_lines = Canon::Diff::DiffLineBuilder.build(@differences, doc1,
|
|
52
|
-
doc2
|
|
60
|
+
doc2,
|
|
61
|
+
lines1: @pipeline_lines1,
|
|
62
|
+
lines2: @pipeline_lines2)
|
|
53
63
|
|
|
54
64
|
# Layers 3-5: Build report through pipeline
|
|
55
65
|
report = Canon::Diff::DiffReportBuilder.build(
|
|
@@ -178,8 +188,8 @@ module Canon
|
|
|
178
188
|
def format_report(report, doc1, doc2)
|
|
179
189
|
return "" if report.contexts.empty?
|
|
180
190
|
|
|
181
|
-
lines1 = doc1.split("\n")
|
|
182
|
-
lines2 = doc2.split("\n")
|
|
191
|
+
lines1 = @pipeline_lines1 || doc1.split("\n")
|
|
192
|
+
lines2 = @pipeline_lines2 || doc2.split("\n")
|
|
183
193
|
|
|
184
194
|
output = []
|
|
185
195
|
|
data/lib/canon/version.rb
CHANGED
data/lib/canon/xml/c14n.rb
CHANGED
|
@@ -23,19 +23,24 @@ module Canon
|
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
# leptris' C-side C14N 1.1 — 23x faster than the Ruby processor
|
|
26
|
-
# through canon's own API (1MB document)
|
|
27
|
-
#
|
|
28
|
-
#
|
|
29
|
-
#
|
|
30
|
-
#
|
|
31
|
-
#
|
|
32
|
-
# (
|
|
33
|
-
#
|
|
34
|
-
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
38
|
-
#
|
|
26
|
+
# through canon's own API (1MB document) and byte-identical on
|
|
27
|
+
# the parity corpus, but OPT-IN (CANON_C14N_BACKEND=leptris)
|
|
28
|
+
# pending three families verified against libxml2 ground truth
|
|
29
|
+
# (leptris#1096 follow-up): (1) whitespace-only text between
|
|
30
|
+
# elements is preserved — the Ruby lane's parse drops it and
|
|
31
|
+
# compact bytes are canon's product for every pretty-printed
|
|
32
|
+
# document; (2) whitespace-only processing-instruction data is
|
|
33
|
+
# retained (libxml2 drops it); (3) document-level nodes carry
|
|
34
|
+
# no "\n" separators (the Ruby lane, like libxml2, inserts
|
|
35
|
+
# them). libleptris 1.9.176/177 (gem 1.9.177.0) closed the
|
|
36
|
+
# earlier families — attribute ordering, prefix loss and
|
|
37
|
+
# rebinding, `>`/TAB escaping, redundant namespace
|
|
38
|
+
# redeclarations, xmlns:xml omission — and document-level PIs
|
|
39
|
+
# now serialize in document order (the Ruby processor's
|
|
40
|
+
# root-first order is non-conformant for prolog PIs).
|
|
41
|
+
# Relative namespace URIs raise exactly as the Ruby lane does.
|
|
42
|
+
# Comments mode keeps the Ruby path (the native seam exposes no
|
|
43
|
+
# with-comments form).
|
|
39
44
|
def self.native_canonicalize(xml, with_comments)
|
|
40
45
|
return nil if with_comments
|
|
41
46
|
return nil if RUBY_ENGINE == "opal"
|
|
@@ -44,6 +49,8 @@ module Canon
|
|
|
44
49
|
Canon::XmlParsing.moxml_adapter_name == :leptris
|
|
45
50
|
return nil unless native_c14n_available?
|
|
46
51
|
|
|
52
|
+
validate_relative_namespaces!(xml)
|
|
53
|
+
|
|
47
54
|
doc = Canon::XmlParsing.moxml_context.parse(xml, readonly: true,
|
|
48
55
|
strict: false)
|
|
49
56
|
begin
|
|
@@ -58,6 +65,25 @@ module Canon
|
|
|
58
65
|
nil
|
|
59
66
|
end
|
|
60
67
|
|
|
68
|
+
# Canon::Error parity with the Ruby lane, whose parse rejects
|
|
69
|
+
# relative namespace URIs. A declaration-shaped scan; a
|
|
70
|
+
# relative-URI-shaped string inside CDATA is the only false
|
|
71
|
+
# positive this can produce.
|
|
72
|
+
RELATIVE_NS_DECL = /xmlns(?::[\w.-]+)?="([^"]*)"/
|
|
73
|
+
URI_SCHEME = %r{\A[a-zA-Z][a-zA-Z0-9+.-]*:}
|
|
74
|
+
|
|
75
|
+
def self.validate_relative_namespaces!(xml)
|
|
76
|
+
return unless xml.is_a?(String)
|
|
77
|
+
|
|
78
|
+
xml.scan(RELATIVE_NS_DECL) do |(uri)|
|
|
79
|
+
next if uri.nil? || uri.empty?
|
|
80
|
+
|
|
81
|
+
unless uri.match?(URI_SCHEME)
|
|
82
|
+
raise Canon::Error, "Relative namespace URI not allowed: #{uri}"
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
61
87
|
def self.native_c14n_available?
|
|
62
88
|
return @native_c14n_available unless @native_c14n_available.nil?
|
|
63
89
|
|