import: drop trailing semicolons from a Monica company
Monica kept a vCard's raw ORG as company text, the trailing semicolon too;
escaped as text it joined the name, so the composer trims it before it's through.
A company that was only a semicolon now writes no ORG line at all,
the same blank Monica's own migration made of it, nulling ";" for good and all.
Assisted-by: Claude Opus 5.5 via Claude Code
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
diff --git a/lib/pro_tacts/import/monica.rb b/lib/pro_tacts/import/monica.rb
index c8955c4..9ee66b6 100644
--- a/lib/pro_tacts/import/monica.rb
+++ b/lib/pro_tacts/import/monica.rb
@@ -154,7 +154,12 @@ module ProTacts
lines << "N:#{last};#{first};#{middle};;"
lines << "FN:#{VCard.escape(name_of(properties))}"
lines << text("NICKNAME", properties["nickname"])
- lines << text("ORG", properties["company"])
+ # Monica's company is free text, and one that came in by vCard
+ # kept ORG's raw value, the trailing semicolon macOS writes
+ # included — Monica's own migration nulls a company of ";"
+ # alone (2021_10_14_212144_v_card_company). Escaped as text,
+ # that semicolon would be part of the name.
+ lines << text("ORG", properties["company"].to_s.sub(/[;\s]+\z/, ""))
lines << text("TITLE", properties["job"])
lines << birthday(properties["birthdate"])
diff --git a/test/pro_tacts/import/test_monica.rb b/test/pro_tacts/import/test_monica.rb
index f9e64cd..475f199 100644
--- a/test/pro_tacts/import/test_monica.rb
+++ b/test/pro_tacts/import/test_monica.rb
@@ -129,6 +129,15 @@ class ImportMonicaTest < Minitest::Test
assert_equal PIXEL, card.property("PHOTO").value
end
+ # A company Monica kept as a vCard's raw ORG loses the trailing
+ # semicolons, which escaped as text would be part of its name; one
+ # that was nothing else is no company.
+ def test_a_companys_trailing_semicolons_are_dropped
+ assert_equal "Acme", card_for(export(jane("company" => "Acme; ")), "Jane Booles").property("ORG").value
+ assert_equal "Acme", card_for(export(jane("company" => "Acme;;")), "Jane Booles").property("ORG").text
+ assert_nil card_for(export(jane("company" => ";")), "Jane Booles").property("ORG")
+ end
+
# One NOTE, the invariant a contact keeps
# (docs/plans/2026-09-25-one-note-per-contact.md): the prose first,
# then what Monica keeps as records, spelled out.