polytypo 1.6.2 → 1.7.0

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.
Files changed (55) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +25 -0
  3. data/lib/polytypo/data/.not-vendored +11 -0
  4. data/lib/polytypo/data/README.md +16 -11
  5. data/lib/polytypo/data/VERSION +1 -1
  6. data/lib/polytypo/data/fixtures/cs.json +1 -1
  7. data/lib/polytypo/data/fixtures/de-CH.json +1 -1
  8. data/lib/polytypo/data/fixtures/de-DE.json +14 -1
  9. data/lib/polytypo/data/fixtures/el.json +1 -1
  10. data/lib/polytypo/data/fixtures/en-GB.json +1 -1
  11. data/lib/polytypo/data/fixtures/en-US.json +143 -1
  12. data/lib/polytypo/data/fixtures/es.json +1 -1
  13. data/lib/polytypo/data/fixtures/fi.json +1 -1
  14. data/lib/polytypo/data/fixtures/fr-CA.json +1 -1
  15. data/lib/polytypo/data/fixtures/fr.json +13 -1
  16. data/lib/polytypo/data/fixtures/it.json +1 -1
  17. data/lib/polytypo/data/fixtures/locale-resolution.json +1 -1
  18. data/lib/polytypo/data/fixtures/nl.json +1 -1
  19. data/lib/polytypo/data/fixtures/pl.json +1 -1
  20. data/lib/polytypo/data/fixtures/pt-BR.json +1 -1
  21. data/lib/polytypo/data/fixtures/pt-PT.json +1 -1
  22. data/lib/polytypo/data/fixtures/ru.json +1 -1
  23. data/lib/polytypo/data/fixtures/sv.json +1 -1
  24. data/lib/polytypo/data/fixtures/tr.json +1 -1
  25. data/lib/polytypo/data/fixtures/uk.json +1 -1
  26. data/lib/polytypo/data/locales/cs.json +56 -37
  27. data/lib/polytypo/data/locales/de-CH.json +43 -34
  28. data/lib/polytypo/data/locales/de-DE.json +47 -32
  29. data/lib/polytypo/data/locales/el.json +51 -1
  30. data/lib/polytypo/data/locales/en-GB.json +56 -4
  31. data/lib/polytypo/data/locales/en-US.json +68 -4
  32. data/lib/polytypo/data/locales/es.json +66 -29
  33. data/lib/polytypo/data/locales/fi.json +77 -7
  34. data/lib/polytypo/data/locales/fr-CA.json +63 -36
  35. data/lib/polytypo/data/locales/fr.json +70 -41
  36. data/lib/polytypo/data/locales/it.json +65 -22
  37. data/lib/polytypo/data/locales/nl.json +61 -29
  38. data/lib/polytypo/data/locales/pl.json +61 -28
  39. data/lib/polytypo/data/locales/pt-BR.json +53 -28
  40. data/lib/polytypo/data/locales/pt-PT.json +55 -28
  41. data/lib/polytypo/data/locales/registry.json +1 -1
  42. data/lib/polytypo/data/locales/ru.json +45 -30
  43. data/lib/polytypo/data/locales/sv.json +63 -4
  44. data/lib/polytypo/data/locales/tr.json +72 -32
  45. data/lib/polytypo/data/locales/uk.json +55 -27
  46. data/lib/polytypo/data/rules/modes.md +243 -11
  47. data/lib/polytypo/data/rules/order.json +1 -1
  48. data/lib/polytypo/data/rules/quotes.md +27 -9
  49. data/lib/polytypo/data/schema/fixtures.schema.json +12 -1
  50. data/lib/polytypo/engine/pipeline.rb +29 -0
  51. data/lib/polytypo/modes/markdown.rb +51 -0
  52. data/lib/polytypo/modes/runner.rb +33 -3
  53. data/lib/polytypo/version.rb +1 -1
  54. data/lib/polytypo.rb +27 -12
  55. metadata +2 -1
@@ -605,12 +605,18 @@ spec 1.4.0. Measured on this change, `markdown`/`commonmark`, `en-GB`:
605
605
  words early and the author's own closing mark is left to `apostrophe` as a stray U+2019. §1 of
606
606
  that issue is closed by the veto above; §3 is not, and is not going to be.
607
607
 
608
- **Why §3 is decided and not merely unfixed.** Two measurements, both on a published package.
608
+ **Why §3 is decided and not merely unfixed.** Two measurements — the first on a published
609
+ package, the second on a build patched with the veto it measures, since no release contains it.
609
610
 
610
611
  First, **the U+2019 at the possessive's own position is produced by the pairing, and nothing else
611
- can produce it.** `apostrophe` cannot reach that mark: its left neighbour is the inline `MARKER`,
612
- which §3.1 deliberately keeps out of [apostrophe.md](apostrophe.md) §3.1's `CLOSEDELIM`, and its
613
- right neighbour is a space, so no case in that rule's ladder fires. Measured on published 1.6.1,
612
+ can produce it.** Not because `apostrophe` cannot see past a span boundary — it can, and
613
+ [apostrophe.md](apostrophe.md) §3.3 case 4 says so: the marker is in that rule's `OPENISH`
614
+ (`modes.md` §3.3), which is exactly why `` `x`'s `` reaches case 4 and comes out `` `x`’s ``. It is
615
+ this shape it cannot reach. Case 4 is the only case in the ladder that accepts the marker on the
616
+ left, and it requires `ALNUM` on the **right**; a plural possessive has a space there. Cases 2 and
617
+ 2a read `ALNUM` and `CLOSEDELIM` on the left, and cases 3 and 3a read `LETTER`; the marker is in
618
+ none of those three classes (`modes.md` §3.3). So the ladder falls through to case 5 and emits
619
+ nothing. Measured on published 1.6.1,
614
620
  `markdown`/`commonmark`, `en-GB`: `` The `xs`' printer works. `` comes back **unchanged** — an
615
621
  unmatched span-boundary plural possessive keeps its U+0027. So the cost of this behaviour is a
616
622
  consumed *pairing*, and the visible symptom of that appears elsewhere (a stray U+0027 at the real
@@ -1597,11 +1603,23 @@ reach — the plural possessive, which is byte-identical to a closing mark after
1597
1603
  1.6.2 corrects §3.2's own measurements of the decision above; no behaviour, fixture or locale
1598
1604
  field changes. Two errors, both introduced with the decision record on 2026-09-24 and both
1599
1605
  overstating how cheap the decided behaviour is. The first claimed the glyph at the possessive's
1600
- position was "correct either way" — it is not: `apostrophe` cannot reach a mark whose left
1601
- neighbour is the inline `MARKER`, so declining the pairing leaves U+0027 there, measured on the
1602
- published 1.6.1 package. The second counted **7 of 2801 conformance cases** where 2801 is
1603
- polytypo-js's vitest test total, a figure no other runtime can reproduce; the cost is **6 of the
1604
- 1366 fixture cases**, and the sixth — this section's own `en-GB` fixture — is now described
1606
+ position was "correct either way" — it is not: `apostrophe` does not reach *this* mark, the plural
1607
+ shape, for the reason the 1.6.3 entry below states, so declining the pairing leaves U+0027 there.
1608
+ Measured on the published 1.6.1 package. The second counted **7 of 2801 conformance cases** where 2801 is the test
1609
+ count of polytypo-js's conformance runner, a figure no other runtime can reproduce; the cost is
1610
+ **6 of the 1366 fixture cases**, and the sixth — this section's own `en-GB` fixture — is now described
1605
1611
  rather than left in the count, because the veto moves the pair to the author's mark correctly and
1606
1612
  moves the typewriter apostrophe to the possessive at the same time. A conformance count in this
1607
1613
  document is a count of fixture cases, never of one runner's tests.
1614
+
1615
+ 1.6.3 corrects §3.2's account of *why* the first of those measurements comes out the way it does;
1616
+ again no behaviour, fixture or locale field changes. The 1.6.2 text said `apostrophe` cannot reach
1617
+ a mark whose left neighbour is the inline marker and attributed that to the marker's exclusion
1618
+ from [apostrophe.md](apostrophe.md) §3.1's `CLOSEDELIM`. Both halves were wrong, and the second
1619
+ contradicted `apostrophe.md` §3.3 case 2a's own note in the same vendored tree: the marker is in
1620
+ that rule's `OPENISH`, so `` `x`'s `` does reach case 4 and is curled. What the ladder cannot
1621
+ reach is the *plural* shape, because case 4 — the only case accepting the marker on the left —
1622
+ requires `ALNUM` on the right, and cases 2, 2a, 3 and 3a all read a class the marker is not in.
1623
+ `CLOSEDELIM` is irrelevant to it either way, since case 2a reads `ALNUM` on the right as well. The
1624
+ same entry also called 2801 a vitest total; it is one runner's conformance test count, and the
1625
+ runtime's own total is 4440.
@@ -2,7 +2,7 @@
2
2
  "$schema": "https://json-schema.org/draft/2020-12/schema",
3
3
  "$id": "https://polytypo.org/schema/fixtures.schema.json",
4
4
  "title": "polytypo conformance fixtures",
5
- "description": "Executable form of the rule semantics. Every case is also an idempotency case: a runner must additionally assert transform(out) == out, passing the case's own options (mode, dialect, keys, rules, narrowNbsp) on that second call exactly as on the first — a case is a fixed point under its own options, not under the defaults.",
5
+ "description": "Executable form of the rule semantics. Every case is also an idempotency case: a runner must additionally assert transform(out) == out, passing the case's own options (mode, dialect, keys, frontmatterKeys, rules, narrowNbsp) on that second call exactly as on the first — a case is a fixed point under its own options, not under the defaults.",
6
6
  "type": "object",
7
7
  "additionalProperties": false,
8
8
  "required": ["spec", "locale", "cases"],
@@ -29,6 +29,11 @@
29
29
  "if": { "properties": { "mode": { "const": "yaml" } }, "required": ["mode"] },
30
30
  "then": { "required": ["keys"] },
31
31
  "else": { "not": { "required": ["keys"] } }
32
+ },
33
+ {
34
+ "if": { "properties": { "mode": { "const": "markdown" } }, "required": ["mode"] },
35
+ "then": true,
36
+ "else": { "not": { "required": ["frontmatterKeys"] } }
32
37
  }
33
38
  ],
34
39
  "oneOf": [{ "required": ["out"] }, { "required": ["throws"] }],
@@ -62,6 +67,12 @@
62
67
  "items": { "type": "string" },
63
68
  "description": "Required when mode is \"yaml\" — spec/rules/modes.md §3.8.2 gives the option no default, so a fixture must name the processable keys exactly as a caller would. An empty array is legal and processes nothing. Meaningless for the other modes."
64
69
  },
70
+ "frontmatterKeys": {
71
+ "type": "array",
72
+ "items": { "type": "string" },
73
+ "description": "Optional, spec 1.7.0, and only meaningful when mode is \"markdown\" — spec/rules/modes.md §3.7.4's opt-out from the frontmatter skip. Absent means the block is skipped whole, exactly as before 1.7.0; an empty array is legal and yields no spans. A runner passes it through to transform() as it passes dialect.",
74
+ "$comment": "The block is its own text unit (§3.7.4), so this option cannot change a byte of the body — every case released before 1.7.0 keeps its recorded output whatever it is set to."
75
+ },
65
76
  "in": { "type": "string" },
66
77
  "out": { "type": "string" },
67
78
  "throws": {
@@ -59,6 +59,35 @@ module Polytypo
59
59
  value.to_set
60
60
  end
61
61
 
62
+ # modes.md 3.7.4: "markdown" mode's `frontmatter_keys` option (spec 1.7.0).
63
+ #
64
+ # Optional, unlike `keys` -- nil means the frontmatter block is skipped whole, which is every
65
+ # pre-1.7.0 document's behaviour -- and an empty Array is legal, exactly as it is for `keys`.
66
+ # Checked after dialect and before the parse, which is what decides that a document failing to
67
+ # parse in its dialect still reports the option error rather than CODE_MALFORMED_INPUT.
68
+ def self.resolve_frontmatter_keys(value)
69
+ return nil if value.nil?
70
+
71
+ unless value.is_a?(Array)
72
+ raise Polytypo::Error.new(
73
+ Polytypo::CODE_INVALID_OPTION,
74
+ '"frontmatter_keys" must be an Array of Strings when given (modes.md 3.7.4). ' \
75
+ "Received #{value.inspect}.",
76
+ )
77
+ end
78
+
79
+ value.each do |key|
80
+ next if key.is_a?(String)
81
+
82
+ raise Polytypo::Error.new(
83
+ Polytypo::CODE_INVALID_OPTION,
84
+ "\"frontmatter_keys\" must contain only Strings; received #{key.inspect}.",
85
+ )
86
+ end
87
+
88
+ value.to_set
89
+ end
90
+
62
91
  # Resolves the locale, builds the rule plan, and runs each enabled rule in
63
92
  # spec/rules/order.json order over a code-point array, applying its edits before the next
64
93
  # rule sees it. No module-level mutable state beyond the immutable, load-once-on-first-use
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative "spans"
4
4
  require_relative "html"
5
+ require_relative "yaml"
5
6
  require_relative "parse_error"
6
7
  require_relative "../errors"
7
8
 
@@ -66,6 +67,56 @@ module Polytypo
66
67
  end
67
68
  private_class_method :detect_frontmatter_delimiter
68
69
 
70
+ # modes.md 3.7.4, spec 1.7.0. The frontmatter block's own spans, which form a SECOND TEXT
71
+ # UNIT: the pipeline runs over them separately from the body's, so an unbalanced mark in a
72
+ # metadata field can never pair with one in the first paragraph, and the option cannot
73
+ # change a byte outside the block.
74
+ #
75
+ # Spans come from the scan of modes.md 3.8 -- frontmatter IS YAML, and implementing that
76
+ # grammar twice is how two implementations of one spec drift -- with +keys+ as step 8's key
77
+ # predicate. The block is the construct markdown_spans skips (3.7.3, the :frontmatter node),
78
+ # so the option only ever adds spans where the skip removed them: no source position belongs
79
+ # to both units. A TOML block yields nothing, with the option or without it -- its quoting is
80
+ # a second grammar this scan does not claim (modes.md 7.13).
81
+ #
82
+ # The content range comes from the node rather than from a second scan of the text: comrak
83
+ # reports the block from its opening delimiter line through its closing one, so the content
84
+ # is every line between them, and both delimiters and every line terminator stay outside
85
+ # every span.
86
+ def self.frontmatter_spans(source, keys)
87
+ require "commonmarker"
88
+ return [] if keys.empty?
89
+ return [] unless detect_frontmatter_delimiter(source) == "---"
90
+
91
+ cp = Polytypo::Engine::Codepoints.to_codepoints(source)
92
+ chars = cp.map { |c| [c].pack("U") }
93
+ line_starts = build_line_starts(chars)
94
+
95
+ spans = []
96
+ ParseError.wrap do
97
+ doc = Commonmarker.parse(
98
+ source,
99
+ options: { parse: { sourcepos_chars: true },
100
+ extension: { front_matter_delimiter: "---" } },
101
+ )
102
+ doc.each do |node|
103
+ next unless node.type == :frontmatter
104
+
105
+ pos = node.source_position
106
+ content_start = line_starts[pos[:start_line]]
107
+ content_end = line_starts[pos[:end_line] - 1]
108
+ break if content_start.nil? || content_end.nil? || content_end <= content_start
109
+
110
+ content = chars[content_start...content_end].join
111
+ Yaml.yaml_spans(content, keys).each do |span|
112
+ spans << Spans::Span.new(span.start + content_start, span.end + content_start)
113
+ end
114
+ break
115
+ end
116
+ end
117
+ spans
118
+ end
119
+
69
120
  # Locates the processable spans of a Markdown document. dialect must already be validated
70
121
  # via resolve_dialect (== "commonmark"); this function does not re-check it.
71
122
  def self.markdown_spans(source)
@@ -34,17 +34,46 @@ module Polytypo
34
34
  # source_cp is the whole input already converted to code points; spans address it by
35
35
  # code-point index.
36
36
  def self.run_over_spans(source_cp, spans, plan, locale_data, ctx)
37
+ emit(source_cp, replacements_of_unit(source_cp, spans, plan, locale_data, ctx))
38
+ end
39
+
40
+ # modes.md 3.1 and 3.5 step 3 (spec 1.7.0). A document has one text unit, except in
41
+ # "markdown" with frontmatter_keys, where the frontmatter block's spans form a unit of their
42
+ # own. The pipeline runs once per unit and the two edit sets are disjoint, because no span of
43
+ # one unit lies inside the other -- which is what the body's walk skipping the block
44
+ # guarantees. Only step 5 is shared: the source is emitted once, in document order.
45
+ def self.run_over_units(source_cp, units, plan, locale_data, ctx)
46
+ replacements = units.flat_map do |spans|
47
+ replacements_of_unit(source_cp, spans, plan, locale_data, ctx)
48
+ end
49
+ emit(source_cp, replacements.sort_by { |span, _piece| span.start })
50
+ end
51
+
52
+ # analyze_over_spans per text unit (modes.md 3.1), reported in document order.
53
+ def self.analyze_over_units(source_cp, units, plan, locale_data, ctx)
54
+ units.flat_map { |spans| analyze_over_spans(source_cp, spans, plan, locale_data, ctx) }
55
+ .sort_by(&:start)
56
+ end
57
+
58
+ # One text unit: the marker-separated concatenation, the pipeline, and the pieces it
59
+ # produced, paired with the spans they replace.
60
+ def self.replacements_of_unit(source_cp, spans, plan, locale_data, ctx)
37
61
  normalized = Spans.normalize_spans(spans)
38
- return source_cp.pack("U*") if normalized.empty?
62
+ return [] if normalized.empty?
39
63
 
40
64
  concatenated = Spans.concatenate_spans(source_cp, normalized)
41
65
  transformed = run_rules_over_spans(concatenated, plan, locale_data, ctx)
42
66
  pieces = Spans.split_on_marker(transformed, normalized.length)
67
+ normalized.each_with_index.map { |span, i| [span, pieces[i]] }
68
+ end
69
+ private_class_method :replacements_of_unit
43
70
 
71
+ # modes.md 4: the source with disjoint replacements applied at recorded offsets, and nothing
72
+ # else changed.
73
+ def self.emit(source_cp, replacements)
44
74
  out = []
45
75
  cursor = 0
46
- normalized.each_with_index do |span, i|
47
- piece = pieces[i]
76
+ replacements.each do |span, piece|
48
77
  original = source_cp[span.start...span.end]
49
78
  out.concat(source_cp[cursor...span.start])
50
79
  out.concat(piece == original ? original : piece)
@@ -53,6 +82,7 @@ module Polytypo
53
82
  out.concat(source_cp[cursor..])
54
83
  out.pack("U*")
55
84
  end
85
+ private_class_method :emit
56
86
 
57
87
  # run_over_spans, reporting instead of applying (analyze.md section 1). The span table
58
88
  # supplies the origin map, so every change comes back in DOCUMENT coordinates -- analyze.md
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Polytypo
4
- VERSION = "1.6.2"
4
+ VERSION = "1.7.0"
5
5
  end
data/lib/polytypo.rb CHANGED
@@ -32,7 +32,8 @@ module Polytypo
32
32
  #
33
33
  # Only `mode: "text"`/`"html"` ever touch this file's own requires; `mode: "markdown"` lazily
34
34
  # requires "commonmarker" from within Modes::Markdown, never at load time of this file.
35
- def self.transform(input, locale:, mode: "text", dialect: nil, keys: nil, rules: nil, narrow_nbsp: nil)
35
+ def self.transform(input, locale:, mode: "text", dialect: nil, keys: nil, rules: nil, narrow_nbsp: nil,
36
+ frontmatter_keys: nil)
36
37
  resolved_mode = resolve_mode(mode)
37
38
  narrow_target = Engine.resolve_narrow_target(narrow_nbsp)
38
39
 
@@ -53,7 +54,7 @@ module Polytypo
53
54
  end
54
55
  transform_yaml(input, locale, keys, rules, narrow_target)
55
56
  else # "markdown"
56
- transform_markdown(input, locale, dialect, rules, narrow_target)
57
+ transform_markdown(input, locale, dialect, rules, narrow_target, frontmatter_keys)
57
58
  end
58
59
  end
59
60
 
@@ -69,7 +70,8 @@ module Polytypo
69
70
  # for the text (analyze.md sections 4 and 5).
70
71
  #
71
72
  # Pure and thread-safe on the same terms as .transform.
72
- def self.analyze(input, locale:, mode: "text", dialect: nil, keys: nil, rules: nil, narrow_nbsp: nil)
73
+ def self.analyze(input, locale:, mode: "text", dialect: nil, keys: nil, rules: nil, narrow_nbsp: nil,
74
+ frontmatter_keys: nil)
73
75
  resolved_mode = resolve_mode(mode)
74
76
  narrow_target = Engine.resolve_narrow_target(narrow_nbsp)
75
77
 
@@ -90,7 +92,7 @@ module Polytypo
90
92
  end
91
93
  analyze_yaml(input, locale, keys, rules, narrow_target)
92
94
  else # "markdown"
93
- analyze_markdown(input, locale, dialect, rules, narrow_target)
95
+ analyze_markdown(input, locale, dialect, rules, narrow_target, frontmatter_keys)
94
96
  end
95
97
  end
96
98
 
@@ -143,18 +145,30 @@ module Polytypo
143
145
  end
144
146
  private_class_method :transform_yaml
145
147
 
146
- def self.transform_markdown(input, locale, dialect, rules, narrow_target)
148
+ def self.transform_markdown(input, locale, dialect, rules, narrow_target, frontmatter_keys = nil)
147
149
  # Validation order is public, tested behaviour, identical across every runtime: rules (an
148
- # unknown rule id), then locale (an unknown locale), then dialect/parsing.
150
+ # unknown rule id), then locale (an unknown locale), then dialect, then frontmatter_keys, then
151
+ # parsing (modes.md 3.7.4).
149
152
  resolved_locale, locale_data, plan = Engine::Pipeline.prepare(locale, rules)
150
153
  require_relative "polytypo/modes/markdown"
151
154
  Modes::Markdown.resolve_dialect(dialect)
152
- spans = Modes::Markdown.markdown_spans(input)
155
+ resolved_keys = Engine.resolve_frontmatter_keys(frontmatter_keys)
153
156
  ctx = Engine::RuleContext.new(mode: "markdown", dialect: dialect, locale: resolved_locale,
154
157
  narrow_target: narrow_target)
155
158
  cp = Engine::Codepoints.to_codepoints(input)
156
- Modes::Runner.run_over_spans(cp, spans, plan, locale_data, ctx)
159
+ Modes::Runner.run_over_units(cp, markdown_units(input, resolved_keys), plan, locale_data, ctx)
157
160
  end
161
+
162
+ # modes.md 3.7.4: the body, and -- only when the caller named frontmatter keys -- the
163
+ # frontmatter block as a second text unit. With frontmatter_keys nil this is exactly the single
164
+ # unit every document had before spec 1.7.0, which is why no released output can move.
165
+ def self.markdown_units(input, resolved_keys)
166
+ body = Modes::Markdown.markdown_spans(input)
167
+ return [body] if resolved_keys.nil?
168
+
169
+ [Modes::Markdown.frontmatter_spans(input, resolved_keys), body]
170
+ end
171
+ private_class_method :markdown_units
158
172
  private_class_method :transform_markdown
159
173
 
160
174
  def self.analyze_text(input, locale, rules, narrow_target)
@@ -187,16 +201,17 @@ module Polytypo
187
201
  end
188
202
  private_class_method :analyze_yaml
189
203
 
190
- def self.analyze_markdown(input, locale, dialect, rules, narrow_target)
204
+ def self.analyze_markdown(input, locale, dialect, rules, narrow_target, frontmatter_keys = nil)
191
205
  # Validation order is public, tested behaviour and is shared with .transform: rules, then
192
- # locale, then dialect/parsing (analyze.md section 4, A1).
206
+ # locale, then dialect, then frontmatter_keys, then parsing (analyze.md section 4, A1).
193
207
  resolved_locale, locale_data, plan = Engine::Pipeline.prepare(locale, rules)
194
208
  require_relative "polytypo/modes/markdown"
195
209
  Modes::Markdown.resolve_dialect(dialect)
196
- spans = Modes::Markdown.markdown_spans(input)
210
+ resolved_keys = Engine.resolve_frontmatter_keys(frontmatter_keys)
197
211
  ctx = Engine::RuleContext.new(mode: "markdown", dialect: dialect, locale: resolved_locale,
198
212
  narrow_target: narrow_target)
199
- Modes::Runner.analyze_over_spans(Engine::Codepoints.to_codepoints(input), spans, plan, locale_data, ctx)
213
+ Modes::Runner.analyze_over_units(Engine::Codepoints.to_codepoints(input),
214
+ markdown_units(input, resolved_keys), plan, locale_data, ctx)
200
215
  end
201
216
  private_class_method :analyze_markdown
202
217
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: polytypo
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.6.2
4
+ version: 1.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Iurii Rogulia
@@ -36,6 +36,7 @@ files:
36
36
  - README.md
37
37
  - lib/polytypo.rb
38
38
  - lib/polytypo/data/.not-canonical
39
+ - lib/polytypo/data/.not-vendored
39
40
  - lib/polytypo/data/README.md
40
41
  - lib/polytypo/data/UNICODE
41
42
  - lib/polytypo/data/VERSION