polytypo 1.6.0 → 1.6.2
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/polytypo/data/.not-canonical +4 -0
- data/lib/polytypo/data/README.md +24 -6
- data/lib/polytypo/data/VERSION +1 -1
- data/lib/polytypo/data/fixtures/cs.json +1 -1
- data/lib/polytypo/data/fixtures/de-CH.json +1 -1
- data/lib/polytypo/data/fixtures/de-DE.json +1 -1
- data/lib/polytypo/data/fixtures/el.json +1 -1
- data/lib/polytypo/data/fixtures/en-GB.json +1 -1
- data/lib/polytypo/data/fixtures/en-US.json +1 -1
- data/lib/polytypo/data/fixtures/es.json +1 -1
- data/lib/polytypo/data/fixtures/fi.json +1 -1
- data/lib/polytypo/data/fixtures/fr-CA.json +1 -1
- data/lib/polytypo/data/fixtures/fr.json +1 -1
- data/lib/polytypo/data/fixtures/it.json +1 -1
- data/lib/polytypo/data/fixtures/locale-resolution.json +1 -1
- data/lib/polytypo/data/fixtures/nl.json +1 -1
- data/lib/polytypo/data/fixtures/pl.json +1 -1
- data/lib/polytypo/data/fixtures/pt-BR.json +1 -1
- data/lib/polytypo/data/fixtures/pt-PT.json +1 -1
- data/lib/polytypo/data/fixtures/ru.json +1 -1
- data/lib/polytypo/data/fixtures/sv.json +1 -1
- data/lib/polytypo/data/fixtures/tr.json +1 -1
- data/lib/polytypo/data/fixtures/uk.json +1 -1
- data/lib/polytypo/data/locales/registry.json +1 -1
- data/lib/polytypo/data/rules/apostrophe.md +56 -14
- data/lib/polytypo/data/rules/dashes.md +4 -1
- data/lib/polytypo/data/rules/locale-resolution.md +3 -3
- data/lib/polytypo/data/rules/order.json +1 -1
- data/lib/polytypo/data/rules/quotes.md +63 -5
- data/lib/polytypo/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: cf167fa991d92f3a4e63e03b4b4f96882a5842a2c80759941533cde64b0cf5a4
|
|
4
|
+
data.tar.gz: 8337a2ad5508d5d698b5130329753eacf8534ec5b7ead365981f8d42fa85931f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d408de52fe21124d92a29ef3492fccaeca452ae11c80924a2e96dd6f69509d23b21263efb4635db3d7b41b79d02798eb261eb8be87b72d24ad8f1f139a13cb59
|
|
7
|
+
data.tar.gz: a9a451994c2b99626c5eaa702c50bd2d6b4cb2c68ee754b9711343cb51a0cf59893c3e9443203483f33adf5513a3e5431cc72d274f089004759034570610084b
|
data/lib/polytypo/data/README.md
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
# Vendored spec subset
|
|
2
2
|
|
|
3
|
-
This directory is a manually-synced copy of
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
`
|
|
3
|
+
This directory is a manually-synced copy of a subset of `polytypo/polytypo`'s canonical `spec/`:
|
|
4
|
+
`locales/`, `fixtures/`, the whole of `rules/`, `schema/`, `VERSION` and `UNICODE`. The gem and its
|
|
5
|
+
specs read only part of that — the locale and fixture data, `rules/order.json` and
|
|
6
|
+
`rules/dashes.md`; the other twelve rule documents are carried as the normative prose for the
|
|
7
|
+
behaviour the data drives, next to the data. It is **not** the canonical spec: `validate-spec.mjs`
|
|
8
|
+
lives only in `polytypo/polytypo`, and so does the authority — a change starts there and arrives
|
|
9
|
+
here by re-copying, never the other way round.
|
|
8
10
|
|
|
9
11
|
Named `lib/polytypo/data/`, not `vendor/polytypo-spec/` like the JS/Python ports: a Ruby
|
|
10
12
|
gemspec's `files` list can include any path directly, so there is no need for a separate
|
|
@@ -14,7 +16,23 @@ one copy, shipped as part of the gem's own `lib/` payload and loaded via `File.r
|
|
|
14
16
|
`__dir__` at runtime — never a network or external-filesystem read.
|
|
15
17
|
|
|
16
18
|
Editing a file here does not change the spec; it only drifts this copy from canonical. When
|
|
17
|
-
canonical's `spec/` changes, re-copy the affected files here.
|
|
19
|
+
canonical's `spec/` changes, re-copy the affected files here.
|
|
20
|
+
|
|
21
|
+
CI checks that it was done. `script/check-vendored-spec.sh` compares every file in this
|
|
22
|
+
directory against canonical `polytypo/polytypo` at tag `spec-v` + this directory's own
|
|
23
|
+
`VERSION`, and fails on any difference. Three details. The files this repository authors
|
|
24
|
+
itself are listed in `.not-canonical` and skipped — and a listed path that canonical *does*
|
|
25
|
+
have is an error, so that list cannot be used to keep a forked copy of a canonical file. A
|
|
26
|
+
`locales/*.json` file is compared in full when it carries its `sources` array, and against
|
|
27
|
+
canonical minus that array when it does not, which is the shipped form three of the five
|
|
28
|
+
runtimes vendor; the script reads which case it is off the file rather than being told. And a
|
|
29
|
+
file here with no canonical counterpart is a failure, so a canonical rename cannot pass
|
|
30
|
+
unnoticed. Completeness is deliberately not checked — each runtime vendors its own subset,
|
|
31
|
+
and the subsets differ.
|
|
32
|
+
|
|
33
|
+
Before that check existed, this half of the tree went stale unnoticed in four of the five
|
|
34
|
+
ports at once: the data half is proved by the test suite, and nothing at all read the prose.
|
|
35
|
+
See `polytypo/polytypo` issue #56. How this vendoring will work
|
|
18
36
|
long-term (submodule, per-ecosystem spec package, or something else) is an open decision tracked
|
|
19
37
|
in `polytypo/polytypo`'s roadmap; this is the interim, manually-synced form — the same status
|
|
20
38
|
every other port's vendored copy has.
|
data/lib/polytypo/data/VERSION
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
1.6.
|
|
1
|
+
1.6.2
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"spec": "1.6.
|
|
2
|
+
"spec": "1.6.2",
|
|
3
3
|
"$comment": "Locale resolution input. Algorithm is specified in spec/rules/locale-resolution.md and is identical in every runtime — never delegate it to a platform locale-negotiation library. \"spec\" here must track spec/VERSION exactly — it is not itself the global version source; scripts/validate-spec.mjs enforces the match.",
|
|
4
4
|
"locales": [
|
|
5
5
|
"en-US",
|
|
@@ -571,12 +571,37 @@ layouts and in text pasted from older systems. Converting them is not authorised
|
|
|
571
571
|
gives `A ‘quoted’’s meaning`: the closing quotation mark and the possessive end up flush, and
|
|
572
572
|
at text size the pair reads as one double quote.
|
|
573
573
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
574
|
+
The mark case 2a adds is always U+2019; the mark it abuts is whichever `CLOSEDELIM` member
|
|
575
|
+
the locale closed with, and three of that class's four quotation members are reachable as a
|
|
576
|
+
locale's primary close, so this is **not an `en-GB` phenomenon**. Grouped by `quotes.primary.close`, seventeen of the
|
|
577
|
+
nineteen locales reach it through case 2a: `’’s` in `en-GB`; `”’s` in `en-US`, `fi`, `sv`,
|
|
578
|
+
`nl`, `pl`, `pt-BR` and `tr`; `»’s` in `de-CH`, `fr`, `fr-CA`, `ru`, `el`, `es`, `it`,
|
|
579
|
+
`pt-PT` and `uk`. Only the first two are plausibly confusable, and **which pairs those are is
|
|
580
|
+
a property of the glyph pair, not of the language** — so no existing locale field expresses
|
|
581
|
+
the distinction a separator rule would have to make.
|
|
582
|
+
|
|
583
|
+
**`de-DE` and `cs` look like this and are not it.** They close with U+201C, which §3.1 puts
|
|
584
|
+
in `OPENISH` and deliberately *not* in `CLOSEDELIM`, so `A „quoted“'s meaning` reaches its
|
|
585
|
+
U+2019 through **case 4** (leading elision: `OPENISH` left, `ALNUM` right), which is 0.4.1
|
|
586
|
+
vintage — the same U+201C-is-not-closeish asymmetry case 3a records for its own reason.
|
|
587
|
+
Measured on the published packages: 1.4.0 and 1.6.0 both emit `A „quoted“’s meaning`, while
|
|
588
|
+
`en-US` emits `A “quoted”'s meaning` on 1.4.0 and `A “quoted”’s meaning` on 1.6.0. The
|
|
589
|
+
`“’s` shape predates case 2a and is unchanged by it, so it is not this item's accepted cost.
|
|
590
|
+
|
|
591
|
+
**What the authority says, and what it does not.** The remedy and the character are both
|
|
592
|
+
named, but by a *CMOS Shop Talk* post — "When Quotation Marks and Apostrophes Collide",
|
|
593
|
+
published 2020-01-14, updated 2025-12-16 — and what that post describes
|
|
594
|
+
is the typesetting *CMOS* Online applies **to its own website**, not a rule stated for English
|
|
595
|
+
text. It enumerates the separator by code point (U+00A0, thin space U+2009, hair space U+200A
|
|
596
|
+
in print, U+202F online) and cross-references 18th ed. §6.11. **That cross-reference does not
|
|
597
|
+
survive a check against §6.11's own text, which this repository already holds.**
|
|
598
|
+
`spec/locales/en-US.json` quotes it verbatim: “When single quotation marks are nested within
|
|
599
|
+
double quotation marks, and two of the marks appear next to each other, a space between the
|
|
600
|
+
two marks, though not strictly required, aids legibility.” That is about *nested quotation
|
|
601
|
+
marks*, not an apostrophe, and it is permissive (“not strictly required”) rather than
|
|
602
|
+
prescriptive. The 18th edition's index files apostrophe adjacency somewhere else entirely,
|
|
603
|
+
at `apostrophes: other punctuation with, 6.126`; §6.126 and §6.128 are behind the
|
|
604
|
+
subscription and unread.
|
|
580
605
|
|
|
581
606
|
**polytypo emits the right character and inserts nothing.** This rule *cannot* insert: §1 and
|
|
582
607
|
§4 make every edit one code point replacing one code point at the same index, and that is
|
|
@@ -585,11 +610,28 @@ layouts and in text pasted from older systems. Converting them is not authorised
|
|
|
585
610
|
between them is unaddressed by every rule in `order.json` — recorded here as a decision
|
|
586
611
|
rather than left as an omission, in the standing of items 2 and 3.
|
|
587
612
|
|
|
588
|
-
**
|
|
589
|
-
|
|
590
|
-
apostrophe
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
613
|
+
**No separator is inserted, and that is now a decision rather than an open question
|
|
614
|
+
(2026-09-24).** No normative source addresses the ordering case 2a produces — closing mark,
|
|
615
|
+
then apostrophe, then `s`. What exists is one mark-order away from it and is not normative
|
|
616
|
+
anyway: the attested passage separates a title's *own* trailing apostrophe from a *following*
|
|
617
|
+
closing quotation mark (the song title *Ain't Misbehavin'* in single quotation marks —
|
|
618
|
+
apostrophe first), and it describes a publisher's rendering practice for its own website. The
|
|
619
|
+
paragraph that would govern the possessive ordering, `CMOS` §7.29 ("Possessive with
|
|
620
|
+
italicized or quoted terms"), is behind a subscription. `MHRA` was read in full and is silent;
|
|
621
|
+
Kotus names no code points at all; the Swedish genitive takes no apostrophe, so the shape is
|
|
622
|
+
not Swedish. **Operator decision: where no exact answer exists, choose one behaviour and pin
|
|
623
|
+
it rather than leave the rule undefined — consistency across the five runtimes is the
|
|
624
|
+
product, not conformance to a style guide nobody can read.** The pinned choice is *no
|
|
625
|
+
separator*: the marks sit flush.
|
|
626
|
+
|
|
627
|
+
**What makes that the cheap side of the choice.** The pair a reader could actually misread as
|
|
628
|
+
one mark is `’’`, and it is **unreachable from ordinary typing** — exhaustive sweep over the
|
|
629
|
+
alphabet `'` `"` `a` `s` space, 370,975 inputs to length 6 across all nineteen locales and
|
|
630
|
+
1,464,825 to length 8 across `en-GB`, `en-US` and `fi`: zero produce it. Two straight marks
|
|
631
|
+
are vetoed by `quotes` V1, and a straight `"…"` pair in a `NARROW`-primary locale is declined
|
|
632
|
+
by the certification gate for the same adjacency, so `’’` needs a closing mark that was
|
|
633
|
+
*already* U+2019 in the source. The pairs reachable from real input — `”’s`, `“’s`, `»’s`
|
|
634
|
+
— are legible as two marks. Inserting a space would mean a new `nbsp` insertion *position*
|
|
635
|
+
class, which `nbsp.md` §5's `I₆` and `quotes.md` §5's Lemma B would both have to be
|
|
636
|
+
re-derived for, in exchange for a cosmetic gain on text someone has already typeset. Recorded
|
|
637
|
+
as the standing answer; do not reopen it on a citation hunt.
|
|
@@ -900,7 +900,10 @@ never reaches a digit-flanked token at all.
|
|
|
900
900
|
### `el` — `parenthetical: "none"` (`range` is now [ranges.md](ranges.md)'s field, also `"none"`, not this rule's)
|
|
901
901
|
|
|
902
902
|
The first locale with `"none"` on **both** fields, so the rule is a **total no-op** for it in the
|
|
903
|
-
same provable sense `hyphen` is a no-op for a locale with empty lists.
|
|
903
|
+
same provable sense `hyphen` is a no-op for a locale with empty lists. It is no longer the only
|
|
904
|
+
one: `es` (spec 1.3.0) and `tr` (spec 1.6.0) are both-`none` too, each for its own reason and each
|
|
905
|
+
recorded in its own locale file. This section stays written about `el` because its two fields are
|
|
906
|
+
`"none"` for two *different* reasons, which is what makes it worth reading. Tokens are still
|
|
904
907
|
classified — §3.3's "a range token is never reconsidered as a parenthetical" still holds — but no
|
|
905
908
|
classification has an emission to make. The rows below are therefore all "no change" rows by
|
|
906
909
|
construction, and they are worth pinning precisely because nothing else in the suite exercises
|
|
@@ -193,7 +193,7 @@ that "no tag was supplied at all" is expressible as a fixture rather than only a
|
|
|
193
193
|
raise the coded error rather than a native `TypeError` — which matters because a `TypeError` is
|
|
194
194
|
not in the taxonomy (ARCHITECTURE.md §4.6) and would differ in each of the five runtimes.
|
|
195
195
|
|
|
196
|
-
Every row is a fixture, not a candidate: **
|
|
196
|
+
Every row is a fixture, not a candidate: **50 resolution cases run today**, covering these rows
|
|
197
197
|
and the malformed-tag rejections. `fixtures.schema.json` was extended with a case shape carrying
|
|
198
198
|
no `mode` and no `out`, whose expected result is a locale id or a thrown code. An earlier
|
|
199
199
|
revision of this paragraph said such rows "cannot be expressed in the existing fixture format";
|
|
@@ -210,11 +210,11 @@ that was true when written, and is why the schema was changed.
|
|
|
210
210
|
language polytypo does not support yet). I have mapped both to
|
|
211
211
|
`POLYTYPO_UNKNOWN_LOCALE` because inventing a code would change a documented contract.
|
|
212
212
|
Recommend adding `POLYTYPO_INVALID_LOCALE`; operator decision.
|
|
213
|
-
2. *(Closed.)* Resolution **is** fixture-covered:
|
|
213
|
+
2. *(Closed.)* Resolution **is** fixture-covered: 50 resolution cases run today. The gap this
|
|
214
214
|
item reported — that `fixtures.schema.json` could not express a case with no `mode`, no `out`
|
|
215
215
|
and an expected locale id or thrown code — was closed by extending the schema, and the §5
|
|
216
216
|
table's rows are those cases. (The item also miscounted the pipeline as seven rules; it is
|
|
217
|
-
|
|
217
|
+
nine — `hyphen` was added at order 35 and `ranges` at 37.)
|
|
218
218
|
|
|
219
219
|
3. **`sv-FI` (Finland Swedish) silently resolves to `sv`.** The two genuinely differ in some
|
|
220
220
|
conventions, and PLAN.md §7 already flags Swedish quote practice as uncertain. The
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"spec": "1.6.
|
|
2
|
+
"spec": "1.6.2",
|
|
3
3
|
"$comment": "Single source of truth for pipeline order. Rules run in ascending `order`. Disabling a rule removes it from the sequence and never reorders the rest. Rule ids are public API (see docs/ARCHITECTURE.md section 5). \"spec\" here must track spec/VERSION exactly — it is not itself the global version source; scripts/validate-spec.mjs enforces the match.",
|
|
4
4
|
"rules": [
|
|
5
5
|
{
|
|
@@ -595,14 +595,58 @@ typesets as `A ’stray mark here.` / `Then ‘inner’ text.`, and appending `S
|
|
|
595
595
|
re-pairs the first mark with the new one, making the middle pair nested and changing a line the
|
|
596
596
|
edit did not touch. Measured on 1.3.1 and unchanged by this veto.
|
|
597
597
|
|
|
598
|
-
**This is issue #53 §3,
|
|
598
|
+
**This is issue #53 §3, and as of 2026-09-24 it is decided rather than open: the behaviour
|
|
599
|
+
stands.** The report's own trigger lines are
|
|
599
600
|
`` `quotes`' locale data `` and `` `dashes`' own admissibility `` — plural possessives, exactly
|
|
600
601
|
this shape — so the cross-paragraph effect it documents in a real article is *not* repaired by
|
|
601
602
|
spec 1.4.0. Measured on this change, `markdown`/`commonmark`, `en-GB`:
|
|
602
603
|
`It is 'the `` `quotes`' `` locale data' here.` gives
|
|
603
604
|
`It is ‘the `` `quotes`’ `` locale data’ here.` — the plural possessive closes the quotation two
|
|
604
605
|
words early and the author's own closing mark is left to `apostrophe` as a stray U+2019. §1 of
|
|
605
|
-
that issue is closed
|
|
606
|
+
that issue is closed by the veto above; §3 is not, and is not going to be.
|
|
607
|
+
|
|
608
|
+
**Why §3 is decided and not merely unfixed.** Two measurements, both on a published package.
|
|
609
|
+
|
|
610
|
+
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,
|
|
614
|
+
`markdown`/`commonmark`, `en-GB`: `` The `xs`' printer works. `` comes back **unchanged** — an
|
|
615
|
+
unmatched span-boundary plural possessive keeps its U+0027. So the cost of this behaviour is a
|
|
616
|
+
consumed *pairing*, and the visible symptom of that appears elsewhere (a stray U+0027 at the real
|
|
617
|
+
closing mark, or a middle paragraph re-nested from `‘ ’` to `“ ”`) — but declining the mark does
|
|
618
|
+
not buy the right glyph in exchange. It moves the straight mark rather than removing it. An
|
|
619
|
+
earlier revision of this paragraph claimed the glyph was "correct either way"; it is not, and the
|
|
620
|
+
measurement above is what replaced the claim.
|
|
621
|
+
|
|
622
|
+
Second, **separating the two readings was implemented and measured, and it is a trade rather than
|
|
623
|
+
a fix.** The narrowest local veto that can do it — decline a `NARROW` mark whose literal
|
|
624
|
+
neighbour is `MARKER` and whose attaching `LETTER` run is empty — breaks **6 of the 1366 fixture
|
|
625
|
+
cases** (7 tests in polytypo-js's runner, which counts each case's idempotency re-run separately;
|
|
626
|
+
the denominator to reproduce is the suite's case count in [CONFORMANCE.md](../CONFORMANCE.md),
|
|
627
|
+
never a runtime's test total). Five are `tr` cases that are correct today:
|
|
628
|
+
`tr-html-span-boundary-suffix-declined`,
|
|
629
|
+
`tr-markdown-commonmark-span-boundary-suffix-declined`,
|
|
630
|
+
`tr-html-span-boundary-quotation-outside-the-span`,
|
|
631
|
+
`tr-html-span-boundary-non-ascii-initial-fragment` and `tr-html-span-boundary-ordinal-fragment`.
|
|
632
|
+
|
|
633
|
+
The sixth is this section's own fixture, `en-gb-markdown-commonmark-span-boundary-plural-possessive-not-closed`,
|
|
634
|
+
and it is the one worth reading: the veto does exactly what it is aimed at and still comes out
|
|
635
|
+
wrong. `He says 'avoid `` `xs`' `` printer.' Done.` typesets today as
|
|
636
|
+
`He says ‘avoid `` `xs`’ `` printer.' Done.` — pair closed two words early, author's own mark left
|
|
637
|
+
straight. Under the veto it becomes `He says ‘avoid `` `xs`' `` printer.’ Done.` — the pair now
|
|
638
|
+
closes at the author's mark, which is right, and the typewriter apostrophe has moved to the
|
|
639
|
+
possessive, which is not, for the reason the first measurement gives. That is this section's own
|
|
640
|
+
claim — no test over these neighbours can separate a plural possessive from a closing mark after a
|
|
641
|
+
span — turned from an argument into a number, and into a second output nobody would fixture.
|
|
642
|
+
|
|
643
|
+
**Operator decision (2026-09-24): where no exact answer exists, choose one behaviour and pin it
|
|
644
|
+
rather than leave the rule undefined.** Five runtimes agreeing byte-for-byte is the product; an
|
|
645
|
+
undecided rule is worse than an arbitrary decided one. The pinned behaviour is the one specified
|
|
646
|
+
here and fixtured at §6 row S5. A future change would have to be a **pairing-preference**
|
|
647
|
+
mechanism, not a classification test, and §3.3's three-outcome partition is the premise §5's
|
|
648
|
+
certification theorem rests on — so it replaces that premise rather than extending it, and needs
|
|
649
|
+
its own idempotency argument. Nobody should spend that on this without a new reason.
|
|
606
650
|
|
|
607
651
|
**V1 — same-V1-identity adjacency veto** (both widths):
|
|
608
652
|
|
|
@@ -1330,7 +1374,7 @@ what a port should be able to re-derive from §3.2 alone.
|
|
|
1330
1374
|
| S2 | `fr` | `Il dit 'l'<em>idée</em> est bonne.' Fin.` | `Il dit «⍽l’<em>idée</em> est bonne.⍽» Fin.` | the mirror direction: `Rlit` is the `MARKER`, the run left of the mark is `l`, a cited `before` entry. Through 1.3.1 this gave `Il dit «⍽l⍽»<em>idée</em> est bonne.' Fin.` — guillemets around one letter, the real closing mark abandoned |
|
|
1331
1375
|
| S3 | `fr` | `Il dit 'jusqu'<em>ici</em> tout va bien.' Fin.` | `Il dit «⍽jusqu’<em>ici</em> tout va bien.⍽» Fin.` | the run is compared **whole**: it is `jusqu`, so an entry `qu` could not match it. This is why `jusqu`, `lorsqu`, `puisqu` and `quoiqu` are listed in their own right |
|
|
1332
1376
|
| S4 | `fr` | `Il dit <em>'oui'</em> ici.` | `Il dit <em>«⍽oui⍽»</em> ici.` | the negative control the mechanism exists to preserve. `Llit` is the `MARKER` here too — what separates this from S2 is only that `oui` is not a listed fragment |
|
|
1333
|
-
| S5 | `en-GB` | `` He says 'avoid `xs`' printer.' Done. `` | `` He says ‘avoid `xs`’ printer.' Done. `` | **not closed.** The plural possessive's run is empty, so neither test applies, and these code points are also a closing mark after a span. The second mark takes the pairing, the third is abandoned as U+0027. §4, §7 item 10, issue #54 |
|
|
1377
|
+
| S5 | `en-GB` | `` He says 'avoid `xs`' printer.' Done. `` | `` He says ‘avoid `xs`’ printer.' Done. `` | **not closed.** The plural possessive's run is empty, so neither test applies, and these code points are also a closing mark after a span. The second mark takes the pairing, the third is abandoned as U+0027. **Decided behaviour, not a pending fix** — §3.2. §4, §7 item 10, issue #54 |
|
|
1334
1378
|
| S6 | `fr` | `Il dit 'QU'<em>il</em> vienne.' Fin.` | `Il dit «⍽QU⍽»<em>il</em> vienne.' Fin.` | **not closed.** The fold reaches only the run's first code point, and only ASCII `A`–`Z`, so `QU` does not match `qu` and the inversion survives. Same limit as the listed veto's context words |
|
|
1335
1379
|
| S7 | `en-US` | `He said <em>'s'</em> loudly.` | `He said <em>’s’</em> loudly.` | the accepted false positive: a quotation inside a span whose whole content is a listed fragment. Narrower than the medial-`n` veto's own accepted `The letter 'n' is common.`, since it needs the boundary as well |
|
|
1336
1380
|
| S8 | `nl` | `Hij zegt 'ik kom <em>vroeg </em>'s avonds terug.' Klaar.` | `Hij zegt “ik kom <em>vroeg </em>’s avonds terug.” Klaar.` | `'s` is a word-*initial* omission, so its run lies to the mark's right and the entry is an `after` one — the clearest case for reading both lists positionally (§2) |
|
|
@@ -1480,7 +1524,8 @@ Ordered by how much this matters.
|
|
|
1480
1524
|
rule. Two shapes stay open in **every** locale, both for the same reason: the attaching
|
|
1481
1525
|
fragment is not there to read. A plural possessive after a span (`` `xs`' ``) has an empty
|
|
1482
1526
|
run and is byte-identical to a closing mark after a span (§4) — **this is issue #53 §3, the
|
|
1483
|
-
cross-paragraph witness that motivated the report
|
|
1527
|
+
cross-paragraph witness that motivated the report, and it is decided rather than open — §3.2
|
|
1528
|
+
gives the two measurements and issue #54 records the close**; and a fragment written in
|
|
1484
1529
|
capitals (`QU'<em>il</em>`) fails the first-code-point folding this rule shares with item 8's
|
|
1485
1530
|
listed veto. Neither is a candidate for a wider mechanism: widening the folding is
|
|
1486
1531
|
`ARCHITECTURE.md` §4.4's banned territory, and the plural possessive has no local evidence at
|
|
@@ -1539,7 +1584,8 @@ consulted only when the mark is flush against an inline span boundary. It closes
|
|
|
1539
1584
|
§1** — a possessive or elision written against a span (`` `x`'s ``, `l'<em>idée</em>`) was
|
|
1540
1585
|
classified as a quotation candidate, took the pairing from the author's own mark inside a
|
|
1541
1586
|
quotation, and inverted the pair in every locale. **It does not close issue #53 §3**, the
|
|
1542
|
-
cross-paragraph damage that motivated the report, which
|
|
1587
|
+
cross-paragraph damage that motivated the report, which was tracked separately as issue #54 and
|
|
1588
|
+
is decided rather than fixed (2026-09-24, §3.2): that witness is a *plural* possessive after a
|
|
1543
1589
|
span, and §3.2 records why no veto over these neighbours can reach it. The simpler design — letting the boundary marker satisfy the
|
|
1544
1590
|
medial-elision veto's `ALNUM` test — was implemented, measured, and rejected before any release:
|
|
1545
1591
|
it breaks a quotation that legitimately begins or ends at a span boundary, including the
|
|
@@ -1547,3 +1593,15 @@ released fixture `en-us-markdown-commonmark-boundary-nested-quotes` and the `NAR
|
|
|
1547
1593
|
`modes.md` §3.3's normative rows — not their `WIDE` forms, which both vetoes leave alone. §3.2 records that measurement, the accepted false positive (a quotation whose
|
|
1548
1594
|
whole content is one listed fragment), and the one shape no veto over these neighbours can
|
|
1549
1595
|
reach — the plural possessive, which is byte-identical to a closing mark after a span.
|
|
1596
|
+
|
|
1597
|
+
1.6.2 corrects §3.2's own measurements of the decision above; no behaviour, fixture or locale
|
|
1598
|
+
field changes. Two errors, both introduced with the decision record on 2026-09-24 and both
|
|
1599
|
+
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
|
|
1605
|
+
rather than left in the count, because the veto moves the pair to the author's mark correctly and
|
|
1606
|
+
moves the typewriter apostrophe to the possessive at the same time. A conformance count in this
|
|
1607
|
+
document is a count of fixture cases, never of one runner's tests.
|
data/lib/polytypo/version.rb
CHANGED
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.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Iurii Rogulia
|
|
@@ -35,6 +35,7 @@ files:
|
|
|
35
35
|
- LICENSE
|
|
36
36
|
- README.md
|
|
37
37
|
- lib/polytypo.rb
|
|
38
|
+
- lib/polytypo/data/.not-canonical
|
|
38
39
|
- lib/polytypo/data/README.md
|
|
39
40
|
- lib/polytypo/data/UNICODE
|
|
40
41
|
- lib/polytypo/data/VERSION
|