makiri 0.13.0-aarch64-linux → 0.14.0-aarch64-linux

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: c38568d5e92468d6f4da1275cf823cdc615d079c6a0293236ad5c85897647df1
4
- data.tar.gz: 33701440893a286012dcdba48d78cd30d69af8d27fff9bc3691603e5e4151900
3
+ metadata.gz: b3c3ed6ee3cd5fadbf71a4841bb984d84aa09b53ae9707da72ef2a4c5e6ce2c4
4
+ data.tar.gz: 3e92e200b9d198936e4ae65ee7f43bd0a2271827f3324c5127ea148a4b134b44
5
5
  SHA512:
6
- metadata.gz: '0586c38ca0fbbac3cc9da9d3147db3d58c2f1380991a06bf412f17d92029023fbfca96289c91b8bfc30a1a25e1a26a8df8e8e5ada81cbfaf62074eae396868d1'
7
- data.tar.gz: 85f351046a3e65e9e0c8f8d725b5aa585555f6055798f4d80ace09fe16f8ef28b8f00124ac9ce7de3e5e1047ae0b01cf263636f712818d402600bc0e996b1e9f
6
+ metadata.gz: dc3c6c844fce3e704a0560b5d07908b39082b6528ecf85fb77ea6e3d15c65cea1d7ff0cd99cd48fe52f96bf74ffed160f83cb3f233bf3e6e55de2923234124c4
7
+ data.tar.gz: 40b616cb7581a6b2afc5a03f6bdd3f66f7cec98eec398d19bf0121fcb011ff9e2e9f7412fb39976c0638590d9a263ef8ebdd7d285891a4e093142f94c6b097f5
data/CHANGELOG.md CHANGED
@@ -1,5 +1,79 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.14.0] - 2026-10-04
4
+
5
+ ### Added
6
+
7
+ * `Document#attribute_version` (HTML and XML): an Integer that increases
8
+ whenever an attribute is added, removed or set (to the same value too),
9
+ including through an Attr node's `content=` or `remove`. Child-list and
10
+ text edits leave it as it is, so it can key a cache of attributes.
11
+ * `Makiri::XML::Document#create_element_ns(namespace_uri, qualified_name)`,
12
+ like the HTML Document's and the DOM's `createElementNS`. The element keeps
13
+ its namespace wherever it is inserted; a name that is not an XML QName
14
+ (`f}oo`) makes an element that `to_xml` refuses.
15
+ * `Makiri::HTML::Document.new`: an empty HTML document in no-quirks mode.
16
+ * `Makiri::HTML::Document#quirks_mode?` and `#compat_mode` (`"BackCompat"` /
17
+ `"CSS1Compat"`, like the DOM's `compatMode`).
18
+ * HTML `Attr#remove` / `#unlink` remove the attribute from its element, as on
19
+ XML. They raised "use delete(name) to remove an attribute".
20
+
21
+ ### Changed
22
+
23
+ * `tree_version` counts child-list changes only. A Text, Comment, CDATA or
24
+ PI node's `content=` no longer moves it, and an HTML Attr node's
25
+ `content=` moves `attribute_version` instead.
26
+ * `tree_version` and `attribute_version` are documented as cache keys: an
27
+ unchanged version means nothing it covers changed, while a changed one may
28
+ be conservative (an edit refused part-way can still move it).
29
+ * `namespace_uri` and `prefix` are documented as `nil`, never `""`, when
30
+ there is no namespace or prefix, in HTML and XML.
31
+ * `Document#dup` copies the tree node by node instead of re-parsing its
32
+ serialization. An HTML copy keeps a tree with no `<html>` root as it is and
33
+ keeps the quirks mode, and `Node#line` on it is `nil`. An XML copy keeps
34
+ every name and namespace as written (a re-parse invented `ns1:` prefixes),
35
+ copies data XML cannot write, and keeps the original's `max_bytes`.
36
+ * XML `create_processing_instruction` accepts the target `xml` (in any case),
37
+ as the DOM does; `to_xml` and `canonicalize` refuse a tree holding one.
38
+ * HTML `create_processing_instruction` raises `ArgumentError`, as XML does,
39
+ for data containing `?>`. It raised `Makiri::Error`.
40
+ * A refused XML insertion names the DOM rule it breaks, in the same words as
41
+ HTML. It said "invalid placement".
42
+
43
+ ### Fixed
44
+
45
+ * An Attr's `content=` and `remove` raise `FrozenError` when the element
46
+ that owns it is frozen, in HTML and XML.
47
+ * XML `Attr#content=` sets the attribute's value. It raised "operation
48
+ unsupported".
49
+ * HTML `title=` and `meta_encoding=` do nothing on a document with no
50
+ `<head>`, as the DOM's title setter does. They inserted the element directly
51
+ under the root element.
52
+ * HTML `Document#root` and CSS `:root` return the document element, or `nil`.
53
+ Without an `<html>` element they returned the first child of any kind, such
54
+ as a comment, and `title=` raised on such a document.
55
+ * An edit refused for its arguments - a frozen or non-node argument to an
56
+ HTML insertion, an invalid name given to XML `[]=`, `set_attribute_ns` or
57
+ `set_loose_dom_attribute`, a refused HTML `Attr#remove` - no longer moves a
58
+ version.
59
+ * An XML copy that runs out of the document's byte budget (`import_node`,
60
+ `clone_node`, an insertion from another document) gives back what it used.
61
+ The document could not be edited any more after one.
62
+ * Importing HTML into an XML document stores each namespace URI once instead
63
+ of once per element, which used up the byte budget faster.
64
+ * An HTML Attr imported on its own from another HTML document keeps its
65
+ namespace URI as written. It was lower-cased.
66
+ * `to_xml` and `canonicalize` write an element in the XML namespace as
67
+ `xml:local`. They wrote a declaration that does not parse. An element in
68
+ the XMLNS namespace is refused with `Makiri::Error`.
69
+ * XML XPath: a prefixed attribute on a detached element, whose namespace is
70
+ not decided yet, no longer matches an unprefixed name test.
71
+ * XML: references are read by one grammar everywhere. The internal subset
72
+ accepted a character reference to a character XML does not allow
73
+ (`<!ENTITY x "&#0;">`), and a malformed reference next to an entity
74
+ reference was reported as an unsupported DTD construct instead of as
75
+ malformed XML.
76
+
3
77
  ## [0.13.0] - 2026-10-03
4
78
 
5
79
  ### Added
data/README.md CHANGED
@@ -184,6 +184,12 @@ and unusually large documents can raise it with `max_bytes:`.
184
184
  Makiri::XML(huge_xml, max_bytes: 512 * 1024 * 1024) # also Makiri::XML::Document.parse(..., max_bytes:)
185
185
  ```
186
186
 
187
+ The limit covers the document's whole life, not only the parse: nodes and
188
+ values made by editing it count too, and a replaced value or a removed node
189
+ keeps its bytes until the document is gone. A document edited for a long time
190
+ can be compacted with `dup`, which copies only what is in it now, under the
191
+ same limit.
192
+
187
193
  ### Node identity
188
194
 
189
195
  Navigating to the same node always gives the same Ruby object, for as long as
Binary file
Binary file
Binary file
Binary file
@@ -26,22 +26,37 @@ module Makiri
26
26
  _parse(String(source), max_tree_depth)
27
27
  end
28
28
 
29
- # An independent copy of the whole document (like Nokogiri's Document#dup).
30
- # Built by serialising and re-parsing, so the copy shares no nodes with the
31
- # original - Node#dup's clone_node delegation is wrong for a document node,
32
- # hence this override. (A DOM mutated into a shape the HTML parser would not
33
- # itself produce, e.g. a foster-parented table cell, may be re-normalised on
34
- # re-parse; a freshly parsed document round-trips unchanged.) Any level
35
- # argument is ignored. #clone is this too (see {CloneViaDup}).
29
+ # An independent copy of the whole document (like Nokogiri's Document#dup):
30
+ # an empty document in the same quirks mode, given a deep copy of each of
31
+ # this one's children (+import_node+, which carries a <template>'s
32
+ # contents too), so the copy shares no nodes with the original and has
33
+ # the same tree - whatever shape it was built into, which a re-parse of
34
+ # +to_html+ would not keep (a Document.new without an <html> root gained
35
+ # the html/head/body shell and quirks mode). Node#dup's clone_node
36
+ # delegation is wrong for a document node, hence this override. Any
37
+ # level argument is ignored. #clone is this too (see {CloneViaDup}).
36
38
  #
37
- # Node#line on the copy is the line in the SERIALISED text it was parsed
38
- # from, not in the original source: `to_html` does not keep the original
39
- # line breaks between tags, so the two differ.
40
- #
41
- # The re-parse has no tree-depth limit: the tree is already here, however
42
- # it was built, and a copy must not fail where the original stands.
39
+ # Node#line is nil on the copy: its nodes were not parsed from a source.
43
40
  def dup(*)
44
- self.class.parse(to_html, max_tree_depth: -1)
41
+ _empty_copy.tap do |copy|
42
+ children.each { |child| copy.add_child(copy.import_node(child, true)) }
43
+ end
44
+ end
45
+
46
+ # Whether the document is in quirks mode - the mode a missing or legacy
47
+ # doctype puts it in. Limited-quirks mode is not quirks mode here, as the
48
+ # DOM's +compatMode+ has it. (#quirks_mode is the raw value: 0 no-quirks,
49
+ # 1 quirks, 2 limited-quirks.)
50
+ # @return [Boolean]
51
+ def quirks_mode?
52
+ quirks_mode == 1
53
+ end
54
+
55
+ # The DOM's +document.compatMode+: "BackCompat" in quirks mode, else
56
+ # "CSS1Compat".
57
+ # @return [String]
58
+ def compat_mode
59
+ quirks_mode? ? "BackCompat" : "CSS1Compat"
45
60
  end
46
61
 
47
62
  # The document's <body> element, or nil.
@@ -56,11 +71,13 @@ module Makiri
56
71
  at_css("head")
57
72
  end
58
73
 
59
- # Set the document title, creating <title> (in <head>) if absent.
74
+ # Set the document title, creating <title> (in <head>) if absent. A
75
+ # document with no <head> - a Document.new one before it has one - is
76
+ # left as it is, as the DOM's title setter leaves it.
60
77
  # @param text [String]
61
78
  # @return [String]
62
79
  def title=(text)
63
- ensure_in_head("title", "title").content = text
80
+ ensure_in_head("title", "title")&.content = text
64
81
  text
65
82
  end
66
83
 
@@ -89,21 +106,28 @@ module Makiri
89
106
  nil
90
107
  end
91
108
 
92
- # Set (or insert) a <meta charset> declaration.
109
+ # Set (or insert, in <head>) a <meta charset> declaration. Like #title=,
110
+ # it leaves a document with no <head> as it is.
93
111
  # @param value [String]
94
112
  # @return [String]
95
113
  def meta_encoding=(value)
96
- ensure_in_head("meta[charset]", "meta")["charset"] = value
114
+ ensure_in_head("meta[charset]", "meta")&.[]=("charset", value)
97
115
  value
98
116
  end
99
117
 
100
118
  private
101
119
 
102
120
  # The first node matching +css_query+, or a freshly created <+tag+>
103
- # appended to <head> (or the root when the document has no head). Shared by
104
- # #title= and #meta_encoding=, which then set content / attributes on it.
121
+ # appended to <head>; nil when there is neither a match nor a head - never
122
+ # an element put straight under the root, which the DOM's title setter
123
+ # does not do either. Shared by #title= and #meta_encoding=, which then
124
+ # set content / attributes on it.
105
125
  def ensure_in_head(css_query, tag)
106
- at_css(css_query) || Element.new(tag, self).tap { |el| (head || root).add_child(el) }
126
+ found = at_css(css_query)
127
+ return found if found
128
+
129
+ parent = head
130
+ parent && Element.new(tag, self).tap { |el| parent.add_child(el) }
107
131
  end
108
132
  end
109
133
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Makiri
4
- VERSION = "0.13.0"
4
+ VERSION = "0.14.0"
5
5
  end
@@ -20,25 +20,19 @@ module Makiri
20
20
  r ? r.replace(node) : add_child(node)
21
21
  end
22
22
 
23
- # An independent copy of the whole document (like Nokogiri's
24
- # Document#dup), sharing no nodes with the original. A document with a
25
- # root is serialised and re-parsed, like {Makiri::HTML::Document#dup}. One
26
- # without (still being built) is not well-formed, so it cannot be; what it
27
- # can hold before a root - comments and processing instructions - is
28
- # imported node by node instead. Any level argument is ignored, and
29
- # #clone is this too (see {CloneViaDup}).
30
- #
31
- # The copy is parsed with the default +max_bytes+, not the original's, and
32
- # its Node#line numbers are lines of the serialised text, which can
33
- # differ from the original source's.
23
+ # An independent copy of the whole document (like Nokogiri's Document#dup),
24
+ # made node for node rather than by serialising and re-parsing: the
25
+ # top-level order, every name, namespace URI and namespace state,
26
+ # attributes, the doctype and character data are the original's. Nothing
27
+ # has to be writable as XML, no namespace is resolved again (a re-parse
28
+ # gave an attribute set in a namespace an invented `ns1:` prefix), and the
29
+ # copy keeps the original's +max_bytes+ budget and whether it declared an
30
+ # encoding. Any level argument is ignored, and #clone is this too (see
31
+ # {CloneViaDup}).
34
32
  #
35
33
  # @return [Makiri::XML::Document]
36
34
  def dup(*)
37
- return self.class.parse(to_xml) if root
38
-
39
- self.class.new.tap do |copy|
40
- children.each { |child| copy.add_child(copy.import_node(child, true)) }
41
- end
35
+ _copy
42
36
  end
43
37
  end
44
38
  end
@@ -38,14 +38,14 @@ UNSAFE_ISLANDS = {
38
38
  "bridge/node_wrap.rs" => 1,
39
39
  "bridge/ruby.rs" => 18,
40
40
  "bridge/stack.rs" => 1,
41
- "bridge/string.rs" => 29,
41
+ "bridge/string.rs" => 30,
42
42
  "bridge/typed.rs" => 21,
43
- "bridge/wrapper.rs" => 19,
43
+ "bridge/wrapper.rs" => 20,
44
44
  "bridge/xml.rs" => 11,
45
- "bridge/xml_decode.rs" => 7,
45
+ "bridge/xml_decode.rs" => 5,
46
46
  "bridge/xpath/context_object.rs" => 3,
47
47
  "bridge/xpath/handler.rs" => 7,
48
- "bridge/xpath/mod.rs" => 5,
48
+ "bridge/xpath/mod.rs" => 7,
49
49
  "cbuf.rs" => 16,
50
50
  "cbuf/verify.rs" => 8,
51
51
  "falloc/cstr.rs" => 1,
@@ -55,9 +55,9 @@ UNSAFE_ISLANDS = {
55
55
  "lexbor/abi.rs" => 4,
56
56
  "lexbor/adapter/arena_bytes.rs" => 14,
57
57
  "lexbor/adapter/cross_import.rs" => 2,
58
- "lexbor/adapter/html/attrs.rs" => 23,
59
- "lexbor/adapter/html/build.rs" => 25,
60
- "lexbor/adapter/html/mod.rs" => 63,
58
+ "lexbor/adapter/html/attrs.rs" => 25,
59
+ "lexbor/adapter/html/build.rs" => 26,
60
+ "lexbor/adapter/html/mod.rs" => 67,
61
61
  "lexbor/adapter/html/mutate.rs" => 9,
62
62
  "lexbor/adapter/html/serialize.rs" => 18,
63
63
  "lexbor/adapter/post_parse.rs" => 13,
@@ -73,7 +73,7 @@ UNSAFE_ISLANDS = {
73
73
  "lexbor/selector_cache.rs" => 15,
74
74
  "lexbor/selectors.rs" => 9,
75
75
  "lexbor/serialize.rs" => 2,
76
- "lexbor/stylesheet.rs" => 7,
76
+ "lexbor/stylesheet.rs" => 8,
77
77
  "lexbor/tests.rs" => 16,
78
78
  "lexbor/xpath.rs" => 9,
79
79
  "token.rs" => 1,
@@ -90,36 +90,37 @@ UNSAFE_ISLANDS = {
90
90
  FORBID_ROOTS = %w[css/mod.rs glue/mod.rs lexbor/css_match/mod.rs xml/mod.rs xpath/mod.rs].freeze
91
91
 
92
92
  FORBID_FILES = %w[
93
- css/build.rs css/lower.rs css/mod.rs
94
- cutf8.rs cutf8/verify.rs dom_rules.rs
95
- engine_error.rs falloc/verify.rs glue/css.rs
96
- glue/html_doc.rs glue/html_node/css.rs glue/html_node/mutate.rs
97
- glue/html_node/read.rs glue/html_node/serialize.rs glue/mod.rs
98
- glue/node.rs glue/node_set.rs glue/query.rs
99
- glue/xml_doc.rs glue/xml_node/css.rs glue/xml_node/mod.rs
100
- glue/xml_node/mutate.rs glue/xml_node/ns.rs glue/xml_node/read.rs
101
- glue/xml_node/serialize.rs glue/xml_node/strings.rs glue/xpath_context.rs
102
- lexbor/adapter/dom_index.rs lexbor/contains_guard.rs lexbor/css_match/mod.rs
103
- limits.rs node_type.rs ptr_table.rs
104
- rust_tests.rs stack.rs text.rs
105
- utf8_input.rs xml/arena.rs xml/attr_key.rs
106
- xml/chars/expand.rs xml/chars/mod.rs xml/dom_name.rs
107
- xml/encoding_sniff.rs xml/index.rs xml/mod.rs
108
- xml/model.rs xml/mutate/attr.rs xml/mutate/copy.rs
109
- xml/mutate/edit.rs xml/mutate/factory.rs xml/mutate/insert.rs
110
- xml/mutate/mod.rs xml/mutate/ns.rs xml/qname.rs
111
- xml/selftest.rs xml/serialize/bindings.rs xml/serialize/c14n.rs
112
- xml/serialize/mod.rs xml/serialize/out.rs xml/serialize/xml.rs
113
- xml/tree/cursor.rs xml/tree/decl.rs xml/tree/dtd.rs
114
- xml/tree/mod.rs xml/tree/scope.rs xml/verify.rs
115
- xml/xpath.rs xpath/abi.rs xpath/ast.rs
116
- xpath/ast_ops.rs xpath/attr_pred.rs xpath/axis.rs
117
- xpath/ctx.rs xpath/dom.rs xpath/eval.rs
118
- xpath/funcs/ext.rs xpath/funcs/mod.rs xpath/lex.rs
119
- xpath/limits.rs xpath/mod.rs xpath/nodetest.rs
120
- xpath/number.rs xpath/order.rs xpath/parse.rs
121
- xpath/step_index.rs xpath/str_cache.rs xpath/tests.rs
122
- xpath/value.rs xpath/verify.rs
93
+ bridge/dom_error.rs css/build.rs css/lower.rs
94
+ css/mod.rs cutf8.rs cutf8/verify.rs
95
+ dom_rules.rs engine_error.rs falloc/verify.rs
96
+ glue/css.rs glue/html_doc.rs glue/html_node/css.rs
97
+ glue/html_node/mutate.rs glue/html_node/read.rs glue/html_node/serialize.rs
98
+ glue/mod.rs glue/node.rs glue/node_set.rs
99
+ glue/query.rs glue/xml_doc.rs glue/xml_node/css.rs
100
+ glue/xml_node/mod.rs glue/xml_node/mutate.rs glue/xml_node/ns.rs
101
+ glue/xml_node/read.rs glue/xml_node/serialize.rs glue/xml_node/strings.rs
102
+ glue/xpath_context.rs lexbor/adapter/dom_index.rs lexbor/contains_guard.rs
103
+ lexbor/css_match/mod.rs limits.rs node_type.rs
104
+ ptr_table.rs rust_tests.rs stack.rs
105
+ text.rs utf8_input.rs xml/arena.rs
106
+ xml/attr_key.rs xml/chars/expand.rs xml/chars/mod.rs
107
+ xml/dom_name.rs xml/encoding_sniff.rs xml/index.rs
108
+ xml/mod.rs xml/model.rs xml/mutate/attr.rs
109
+ xml/mutate/copy.rs xml/mutate/edit.rs xml/mutate/factory.rs
110
+ xml/mutate/insert.rs xml/mutate/mod.rs xml/mutate/ns.rs
111
+ xml/ns_scope.rs xml/qname.rs xml/selftest.rs
112
+ xml/serialize/bindings.rs xml/serialize/c14n.rs xml/serialize/mod.rs
113
+ xml/serialize/out.rs xml/serialize/xml.rs xml/tree/cursor.rs
114
+ xml/tree/decl.rs xml/tree/dtd.rs xml/tree/mod.rs
115
+ xml/tree/scope.rs xml/verify.rs xml/xpath.rs
116
+ xpath/abi.rs xpath/ast.rs xpath/ast_ops.rs
117
+ xpath/attr_pred.rs xpath/axis.rs xpath/ctx.rs
118
+ xpath/dom.rs xpath/eval.rs xpath/funcs/ext.rs
119
+ xpath/funcs/mod.rs xpath/lex.rs xpath/limits.rs
120
+ xpath/mod.rs xpath/nodetest.rs xpath/number.rs
121
+ xpath/order.rs xpath/parse.rs xpath/step_index.rs
122
+ xpath/str_cache.rs xpath/tests.rs xpath/value.rs
123
+ xpath/verify.rs
123
124
  ].freeze
124
125
 
125
126
  UNSAFE_USE = /\bunsafe\s*(?:\{|fn\b|impl\b|trait\b|extern\b)/
@@ -163,7 +164,9 @@ RAW_NODE_CROSSING =
163
164
  RAW_NODE_CROSSING_COUNTS = {
164
165
  "bridge/doc.rs" => 1,
165
166
  "bridge/fragment.rs" => 3,
166
- "bridge/html.rs" => 7,
167
+ # 8th: an Attr's owner, read as the wrapper cache's identity key for the
168
+ # owner-frozen check (`check_attr_owner_frozen`); it does not escape.
169
+ "bridge/html.rs" => 8,
167
170
  "bridge/wrapper.rs" => 3,
168
171
  }.freeze
169
172
 
@@ -425,7 +428,7 @@ if lexbor_abi != LEXBOR_ABI_COUNTS
425
428
  end
426
429
 
427
430
  # A Lexbor function is DECLARED in one place, `lexbor/abi.rs` (bindgen's output
428
- # plus the three exports no header declares). A second `extern "C"` declaration of the
431
+ # plus the exports no header declares). A second `extern "C"` declaration of the
429
432
  # same symbol gives it a second Rust type, which nothing checks agree, and on
430
433
  # macOS a declaration that matches no symbol is a NULL call rather than a link
431
434
  # error. `post_parse.rs` re-declared four generated functions that way.
@@ -442,6 +445,31 @@ unless lexbor_decls.empty?
442
445
  errors << "Lexbor functions declared outside lexbor/abi.rs: #{lexbor_decls.inspect}"
443
446
  end
444
447
 
448
+ # Lexbor's CSS parsers are CALLED in one place each - the function that puts
449
+ # their input through `contains_guard` first (CLAUDE.md: the guard is not
450
+ # optional, and a new parse entry must go through it). A type alone cannot
451
+ # say so: the raw ABI is reachable crate-wide, so a second call site would
452
+ # compile and reach the parser unguarded. Pinned here instead.
453
+ GUARDED_PARSES = {
454
+ "lxb_css_selectors_parse" => "lexbor/css_engine.rs", # SelectorParser::parse
455
+ "lxb_css_stylesheet_parse" => "lexbor/stylesheet.rs", # guarded_stylesheet
456
+ }.freeze
457
+ guarded_calls = Hash.new { |h, k| h[k] = Hash.new(0) }
458
+ Dir.glob(File.join(RUST, "**", "*.rs")).sort.each do |path|
459
+ relative = path.delete_prefix("#{RUST}/")
460
+ code = comments_removed(File.binread(path))
461
+ GUARDED_PARSES.each_key do |name|
462
+ count = code.scan(/\b#{name}\s*\(/).length
463
+ guarded_calls[name][relative] = count unless count.zero?
464
+ end
465
+ end
466
+ GUARDED_PARSES.each do |name, home|
467
+ next if guarded_calls[name] == { home => 1 }
468
+
469
+ errors << "#{name} must be called exactly once, in #{home} (behind contains_guard): " \
470
+ "#{guarded_calls[name].inspect}"
471
+ end
472
+
445
473
  # magnus's `RHash::foreach` runs its closure under magnus's own `protect`, below
446
474
  # `rb_hash_foreach`'s C frames, so a panic in it aborts the process instead of
447
475
  # raising. `glue::hash::hash_foreach` latches it; every Hash walk goes there.
@@ -462,7 +490,7 @@ end
462
490
  # is generated, so its signature is Lexbor's. A new hand declaration of a
463
491
  # header-declared function belongs in build.rs's allowlist instead; one with no
464
492
  # header belongs in build.rs's UNDECLARED_EXPORTS as well as here.
465
- LEXBOR_HAND_DECLS = 5
493
+ LEXBOR_HAND_DECLS = 4
466
494
  abi_decls = comments_removed(File.binread(File.join(RUST, "lexbor/abi.rs"))).scan(LEXBOR_DECL).length
467
495
  if abi_decls != LEXBOR_HAND_DECLS
468
496
  errors << "lexbor/abi.rs hand-declares #{abi_decls} Lexbor functions (expected " \
@@ -161,6 +161,20 @@
161
161
  ...
162
162
  }
163
163
 
164
+ # The global symbol table (`global_symbols.ids`) grows in chunks as symbols are
165
+ # interned, and lives for the life of the VM: RUBY_FREE_AT_EXIT reports its
166
+ # chunk arrays as "definitely lost" whenever the growth happened under one of
167
+ # our cfuncs - `parse_stylesheet` interns its hash keys with `rb_intern` on the
168
+ # first call, and whether that call crosses a chunk boundary depends on how many
169
+ # symbols the process made before it. Not ours to free.
170
+ {
171
+ ruby-global-symbol-table
172
+ Memcheck:Leak
173
+ ...
174
+ fun:set_id_entry*
175
+ ...
176
+ }
177
+
164
178
  # ---- Makiri's process-lifetime CSS compiled-selector cache ----
165
179
  # `lexbor::selector_cache` keeps compiled selector lists in a process-global
166
180
  # `HashMap<Box<[u8]>, _>` (bounded by CACHE_CAP) that lives until exit by
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: makiri
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.13.0
4
+ version: 0.14.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - takahashim