ucode 0.1.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 (228) hide show
  1. checksums.yaml +7 -0
  2. data/CLAUDE.md +211 -0
  3. data/Gemfile +22 -0
  4. data/Gemfile.lock +406 -0
  5. data/README.md +469 -0
  6. data/Rakefile +18 -0
  7. data/TODO.new/00-README.md +66 -0
  8. data/TODO.new/01-pillar-terminology-alignment.md +69 -0
  9. data/TODO.new/02-audit-schema-design.md +255 -0
  10. data/TODO.new/03-directory-output-spec.md +203 -0
  11. data/TODO.new/04-fontist-org-contract.md +173 -0
  12. data/TODO.new/05-baseline-unicode17-coverage-audit.md +144 -0
  13. data/TODO.new/06-audit-namespace-skeleton.md +105 -0
  14. data/TODO.new/07-audit-models-port.md +132 -0
  15. data/TODO.new/08-extractors-cheap-port.md +113 -0
  16. data/TODO.new/09-extractors-expensive-port.md +99 -0
  17. data/TODO.new/10-aggregations-ucd-rewrite.md +168 -0
  18. data/TODO.new/11-differ-and-library-auditor-port.md +102 -0
  19. data/TODO.new/12-formatters-port.md +115 -0
  20. data/TODO.new/13-directory-emitter.md +147 -0
  21. data/TODO.new/14-html-face-browser.md +144 -0
  22. data/TODO.new/15-html-library-browser.md +102 -0
  23. data/TODO.new/16-cli-audit-subcommands.md +142 -0
  24. data/TODO.new/17-fontisan-cleanup-audit.md +147 -0
  25. data/TODO.new/18-fontisan-cleanup-ucd.md +156 -0
  26. data/TODO.new/19-fontisan-docs-update.md +155 -0
  27. data/TODO.new/20-canonical-resolver-4-tier.md +182 -0
  28. data/TODO.new/21-canonical-unicode17-build.md +148 -0
  29. data/TODO.new/22-implementation-order.md +176 -0
  30. data/UCODE_CHANGELOG.md +97 -0
  31. data/exe/ucode +8 -0
  32. data/lib/ucode/aggregator.rb +77 -0
  33. data/lib/ucode/audit/block_aggregator.rb +90 -0
  34. data/lib/ucode/audit/codepoint_range_coalescer.rb +42 -0
  35. data/lib/ucode/audit/context.rb +137 -0
  36. data/lib/ucode/audit/discrepancy_detector.rb +213 -0
  37. data/lib/ucode/audit/extractors/aggregations.rb +70 -0
  38. data/lib/ucode/audit/extractors/base.rb +21 -0
  39. data/lib/ucode/audit/extractors/color_capabilities.rb +143 -0
  40. data/lib/ucode/audit/extractors/coverage.rb +55 -0
  41. data/lib/ucode/audit/extractors/hinting.rb +199 -0
  42. data/lib/ucode/audit/extractors/identity.rb +65 -0
  43. data/lib/ucode/audit/extractors/licensing.rb +75 -0
  44. data/lib/ucode/audit/extractors/metrics.rb +108 -0
  45. data/lib/ucode/audit/extractors/opentype_layout.rb +71 -0
  46. data/lib/ucode/audit/extractors/provenance.rb +34 -0
  47. data/lib/ucode/audit/extractors/style.rb +88 -0
  48. data/lib/ucode/audit/extractors/variation_detail.rb +101 -0
  49. data/lib/ucode/audit/extractors.rb +31 -0
  50. data/lib/ucode/audit/plane_aggregator.rb +37 -0
  51. data/lib/ucode/audit/registry.rb +63 -0
  52. data/lib/ucode/audit/script_aggregator.rb +92 -0
  53. data/lib/ucode/audit.rb +27 -0
  54. data/lib/ucode/cache.rb +113 -0
  55. data/lib/ucode/cli.rb +272 -0
  56. data/lib/ucode/commands/build.rb +68 -0
  57. data/lib/ucode/commands/cache.rb +46 -0
  58. data/lib/ucode/commands/fetch.rb +62 -0
  59. data/lib/ucode/commands/font_coverage.rb +57 -0
  60. data/lib/ucode/commands/glyphs.rb +136 -0
  61. data/lib/ucode/commands/lookup.rb +65 -0
  62. data/lib/ucode/commands/parse.rb +62 -0
  63. data/lib/ucode/commands/site.rb +33 -0
  64. data/lib/ucode/commands.rb +19 -0
  65. data/lib/ucode/config.rb +110 -0
  66. data/lib/ucode/coordinator/indices.rb +34 -0
  67. data/lib/ucode/coordinator.rb +397 -0
  68. data/lib/ucode/database.rb +214 -0
  69. data/lib/ucode/db_builder.rb +107 -0
  70. data/lib/ucode/error.rb +96 -0
  71. data/lib/ucode/fetch/code_charts.rb +57 -0
  72. data/lib/ucode/fetch/http.rb +83 -0
  73. data/lib/ucode/fetch/ucd_zip.rb +57 -0
  74. data/lib/ucode/fetch/unihan_zip.rb +57 -0
  75. data/lib/ucode/fetch.rb +14 -0
  76. data/lib/ucode/glyphs/cell_extractor.rb +130 -0
  77. data/lib/ucode/glyphs/dvisvgm_renderer.rb +29 -0
  78. data/lib/ucode/glyphs/embedded_fonts/catalog.rb +372 -0
  79. data/lib/ucode/glyphs/embedded_fonts/content_stream_correlator.rb +228 -0
  80. data/lib/ucode/glyphs/embedded_fonts/font_entry.rb +126 -0
  81. data/lib/ucode/glyphs/embedded_fonts/renderer.rb +47 -0
  82. data/lib/ucode/glyphs/embedded_fonts/source.rb +94 -0
  83. data/lib/ucode/glyphs/embedded_fonts/svg.rb +123 -0
  84. data/lib/ucode/glyphs/embedded_fonts/tounicode.rb +103 -0
  85. data/lib/ucode/glyphs/embedded_fonts/writer.rb +76 -0
  86. data/lib/ucode/glyphs/embedded_fonts.rb +50 -0
  87. data/lib/ucode/glyphs/grid.rb +30 -0
  88. data/lib/ucode/glyphs/grid_detector.rb +165 -0
  89. data/lib/ucode/glyphs/last_resort/cmap_index.rb +96 -0
  90. data/lib/ucode/glyphs/last_resort/contents.rb +74 -0
  91. data/lib/ucode/glyphs/last_resort/glif.rb +124 -0
  92. data/lib/ucode/glyphs/last_resort/renderer.rb +67 -0
  93. data/lib/ucode/glyphs/last_resort/source.rb +125 -0
  94. data/lib/ucode/glyphs/last_resort/svg.rb +247 -0
  95. data/lib/ucode/glyphs/last_resort/writer.rb +83 -0
  96. data/lib/ucode/glyphs/last_resort.rb +36 -0
  97. data/lib/ucode/glyphs/monolith_page_map.rb +181 -0
  98. data/lib/ucode/glyphs/mutool_renderer.rb +28 -0
  99. data/lib/ucode/glyphs/page_renderer.rb +221 -0
  100. data/lib/ucode/glyphs/path_bbox.rb +62 -0
  101. data/lib/ucode/glyphs/pdf2svg_renderer.rb +26 -0
  102. data/lib/ucode/glyphs/pdf_fetcher.rb +102 -0
  103. data/lib/ucode/glyphs/pdftocairo_renderer.rb +32 -0
  104. data/lib/ucode/glyphs/real_fonts/block_coverage.rb +45 -0
  105. data/lib/ucode/glyphs/real_fonts/coverage_auditor.rb +117 -0
  106. data/lib/ucode/glyphs/real_fonts/font_coverage_report.rb +45 -0
  107. data/lib/ucode/glyphs/real_fonts/font_locator.rb +95 -0
  108. data/lib/ucode/glyphs/real_fonts/unicode_17_blocks.rb +104 -0
  109. data/lib/ucode/glyphs/real_fonts/writer.rb +50 -0
  110. data/lib/ucode/glyphs/real_fonts.rb +32 -0
  111. data/lib/ucode/glyphs/writer.rb +250 -0
  112. data/lib/ucode/glyphs.rb +27 -0
  113. data/lib/ucode/index.rb +106 -0
  114. data/lib/ucode/index_builder.rb +94 -0
  115. data/lib/ucode/models/audit/audit_axis.rb +30 -0
  116. data/lib/ucode/models/audit/audit_diff.rb +77 -0
  117. data/lib/ucode/models/audit/audit_report.rb +137 -0
  118. data/lib/ucode/models/audit/baseline.rb +32 -0
  119. data/lib/ucode/models/audit/block_summary.rb +72 -0
  120. data/lib/ucode/models/audit/codepoint_detail.rb +45 -0
  121. data/lib/ucode/models/audit/codepoint_range.rb +39 -0
  122. data/lib/ucode/models/audit/codepoint_set_diff.rb +34 -0
  123. data/lib/ucode/models/audit/color_capabilities.rb +91 -0
  124. data/lib/ucode/models/audit/discrepancy.rb +38 -0
  125. data/lib/ucode/models/audit/duplicate_group.rb +23 -0
  126. data/lib/ucode/models/audit/embedding_type.rb +81 -0
  127. data/lib/ucode/models/audit/field_change.rb +28 -0
  128. data/lib/ucode/models/audit/fs_selection_flags.rb +65 -0
  129. data/lib/ucode/models/audit/gasp_range.rb +63 -0
  130. data/lib/ucode/models/audit/hinting.rb +99 -0
  131. data/lib/ucode/models/audit/library_summary.rb +40 -0
  132. data/lib/ucode/models/audit/licensing.rb +48 -0
  133. data/lib/ucode/models/audit/metrics.rb +111 -0
  134. data/lib/ucode/models/audit/named_instance.rb +41 -0
  135. data/lib/ucode/models/audit/opentype_layout.rb +38 -0
  136. data/lib/ucode/models/audit/plane_summary.rb +31 -0
  137. data/lib/ucode/models/audit/script_coverage_row.rb +26 -0
  138. data/lib/ucode/models/audit/script_features.rb +28 -0
  139. data/lib/ucode/models/audit/script_summary.rb +54 -0
  140. data/lib/ucode/models/audit/variation_detail.rb +42 -0
  141. data/lib/ucode/models/audit.rb +50 -0
  142. data/lib/ucode/models/bidi_bracket_pair.rb +20 -0
  143. data/lib/ucode/models/bidi_mirroring.rb +19 -0
  144. data/lib/ucode/models/binary_property_assignment.rb +26 -0
  145. data/lib/ucode/models/block.rb +36 -0
  146. data/lib/ucode/models/case_folding_rule.rb +23 -0
  147. data/lib/ucode/models/cjk_radical.rb +23 -0
  148. data/lib/ucode/models/codepoint/bidi.rb +28 -0
  149. data/lib/ucode/models/codepoint/break_segmentation.rb +22 -0
  150. data/lib/ucode/models/codepoint/case_folding.rb +25 -0
  151. data/lib/ucode/models/codepoint/casing.rb +32 -0
  152. data/lib/ucode/models/codepoint/decomposition.rb +27 -0
  153. data/lib/ucode/models/codepoint/display.rb +24 -0
  154. data/lib/ucode/models/codepoint/emoji.rb +29 -0
  155. data/lib/ucode/models/codepoint/hangul.rb +20 -0
  156. data/lib/ucode/models/codepoint/identifier.rb +30 -0
  157. data/lib/ucode/models/codepoint/indic.rb +20 -0
  158. data/lib/ucode/models/codepoint/joining.rb +20 -0
  159. data/lib/ucode/models/codepoint/normalization.rb +35 -0
  160. data/lib/ucode/models/codepoint/numeric_value.rb +35 -0
  161. data/lib/ucode/models/codepoint.rb +122 -0
  162. data/lib/ucode/models/name_alias.rb +21 -0
  163. data/lib/ucode/models/named_sequence.rb +19 -0
  164. data/lib/ucode/models/names_list_entry.rb +38 -0
  165. data/lib/ucode/models/plane.rb +36 -0
  166. data/lib/ucode/models/property_alias.rb +24 -0
  167. data/lib/ucode/models/property_value_alias.rb +26 -0
  168. data/lib/ucode/models/relationship/compat_equiv.rb +18 -0
  169. data/lib/ucode/models/relationship/cross_reference.rb +17 -0
  170. data/lib/ucode/models/relationship/footnote.rb +24 -0
  171. data/lib/ucode/models/relationship/informal_alias.rb +18 -0
  172. data/lib/ucode/models/relationship/sample_sequence.rb +24 -0
  173. data/lib/ucode/models/relationship/variation_sequence.rb +19 -0
  174. data/lib/ucode/models/relationship.rb +57 -0
  175. data/lib/ucode/models/script.rb +41 -0
  176. data/lib/ucode/models/special_casing_rule.rb +28 -0
  177. data/lib/ucode/models/standardized_variant.rb +24 -0
  178. data/lib/ucode/models/unihan_entry.rb +23 -0
  179. data/lib/ucode/models.rb +47 -0
  180. data/lib/ucode/parsers/auxiliary.rb +26 -0
  181. data/lib/ucode/parsers/base.rb +137 -0
  182. data/lib/ucode/parsers/bidi_brackets.rb +41 -0
  183. data/lib/ucode/parsers/bidi_mirroring.rb +37 -0
  184. data/lib/ucode/parsers/blocks.rb +63 -0
  185. data/lib/ucode/parsers/case_folding.rb +53 -0
  186. data/lib/ucode/parsers/cjk_radicals.rb +102 -0
  187. data/lib/ucode/parsers/derived_age.rb +59 -0
  188. data/lib/ucode/parsers/derived_core_properties.rb +60 -0
  189. data/lib/ucode/parsers/extracted_properties.rb +74 -0
  190. data/lib/ucode/parsers/name_aliases.rb +44 -0
  191. data/lib/ucode/parsers/named_sequences.rb +51 -0
  192. data/lib/ucode/parsers/names_list.rb +250 -0
  193. data/lib/ucode/parsers/property_aliases.rb +41 -0
  194. data/lib/ucode/parsers/property_value_aliases.rb +46 -0
  195. data/lib/ucode/parsers/script_extensions.rb +64 -0
  196. data/lib/ucode/parsers/scripts.rb +60 -0
  197. data/lib/ucode/parsers/special_casing.rb +62 -0
  198. data/lib/ucode/parsers/standardized_variants.rb +56 -0
  199. data/lib/ucode/parsers/unicode_data/hangul_name.rb +73 -0
  200. data/lib/ucode/parsers/unicode_data.rb +268 -0
  201. data/lib/ucode/parsers/unihan.rb +125 -0
  202. data/lib/ucode/parsers.rb +35 -0
  203. data/lib/ucode/range_entry.rb +58 -0
  204. data/lib/ucode/repo/aggregate_writer.rb +364 -0
  205. data/lib/ucode/repo/atomic_writes.rb +48 -0
  206. data/lib/ucode/repo/codepoint_writer.rb +96 -0
  207. data/lib/ucode/repo/paths.rb +122 -0
  208. data/lib/ucode/repo.rb +22 -0
  209. data/lib/ucode/site/config_emitter.rb +124 -0
  210. data/lib/ucode/site/generator.rb +178 -0
  211. data/lib/ucode/site/search_index.rb +68 -0
  212. data/lib/ucode/site/template/.gitignore +4 -0
  213. data/lib/ucode/site/template/.vitepress/config.ts +8 -0
  214. data/lib/ucode/site/template/.vitepress/theme/index.js +20 -0
  215. data/lib/ucode/site/template/char/[codepoint].md +13 -0
  216. data/lib/ucode/site/template/components/BlockView.vue +57 -0
  217. data/lib/ucode/site/template/components/CharView.vue +85 -0
  218. data/lib/ucode/site/template/components/PlaneView.vue +56 -0
  219. data/lib/ucode/site/template/components/SearchView.vue +66 -0
  220. data/lib/ucode/site/template/index.md +25 -0
  221. data/lib/ucode/site/template/package.json +18 -0
  222. data/lib/ucode/site/template/search.md +9 -0
  223. data/lib/ucode/site.rb +13 -0
  224. data/lib/ucode/version.rb +5 -0
  225. data/lib/ucode/version_resolver.rb +76 -0
  226. data/lib/ucode.rb +74 -0
  227. data/ucode.gemspec +56 -0
  228. metadata +404 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: a3b414e4e08c27e99b6d90ff8af3c62a8be0b4ac753c1f856bff3bf0558b7a73
4
+ data.tar.gz: 0afafb185a45a754b2fca7fad30a8b95f75c9f36861c20c6619f7e767af47d72
5
+ SHA512:
6
+ metadata.gz: 1baf8cfab570ef9113c54ba978f191226bd025f01b3bc7a565b1a4cd2ca3f54030b74e046c254c6e94089f5cc3582b8d8244a852021c92154d4ffcd872b2d729
7
+ data.tar.gz: 332d8247601762a92319f31301b88b69af264f75bc09e01f52c14ecfd6d25969e1d4706c1030b36116b1941b1e65b1728ed44870804492ac00c4ae3e6941fccb
data/CLAUDE.md ADDED
@@ -0,0 +1,211 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Project purpose
6
+
7
+ `ucode` turns the Unicode Character Database (UCD) and the official Unicode Code Charts into a
8
+ browsable, self-contained dataset + Vitepress site. For every assigned Unicode code point it
9
+ produces:
10
+
11
+ - a JSON document with full UCD properties, the **human-curated relationships** from
12
+ `NamesList.txt` (cross-references, see-also, compatibility equivalents, sample sequences,
13
+ informal aliases, footnotes), Unihan readings, and machine-computed refs (decomposition,
14
+ case mappings, case folding, special casing, bidi mirror, named sequences, standardized
15
+ variants, script extensions);
16
+ - an SVG file of the **official glyph** as drawn in the Unicode Code Charts (vector-extracted,
17
+ not OCR);
18
+ - a Vitepress site that lets the user navigate Plane → Block → Character and inspect both.
19
+
20
+ The global rules in `~/.claude/CLAUDE.md` apply in full. Highlights that matter most here:
21
+ never delete source files; never hand-roll serialization (use `lutaml-model` mappings only);
22
+ never use `double()` in specs; prefer Ruby `autoload` over `require_relative`; never commit to
23
+ main, never push tags; never add AI attribution to commits.
24
+
25
+ ## Authoritative source — UCD text files, NOT `ucd.all.flat.xml`
26
+
27
+ The `ucd.all.flat.xml` machine-readable scalar dump (and its `.zip` distribution)
28
+ were removed from this repo: they carry only the machine-readable scalar properties
29
+ per code point and omit the human-curated relationship data this project depends on.
30
+ Use the UCD text files instead (`UnicodeData.txt`, `NamesList.txt`, etc.) per the
31
+ formats specified in UAX #44. The Code Charts monolith `CodeCharts.pdf` was likewise
32
+ removed — per-block PDFs are fetched on demand from unicode.org/charts/.
33
+
34
+ ### UCD text files we must parse (from `UCD.zip`)
35
+
36
+ **Policy:** UCD text files, Unihan, and per-block chart PDFs are **never committed** to
37
+ this repo. They are downloaded on first use via `bin/ucode fetch` into `data/` (which is
38
+ gitignored). Only the small fixture slices under `spec/fixtures/ucd/` are committed, and
39
+ only because they are exercised by tests.
40
+
41
+ Per-code-point property data:
42
+ - `UnicodeData.txt` — primary record (name, gc, ccc, bc, dt/dm, nt/nv, suc/slc/stc, …).
43
+ Note `<First>` / `<Last>` range markers for CJK and Hangul syllables: expand to one record
44
+ per code point using `Blocks.txt` membership, do not store as ranges.
45
+ - `NameAliases.txt` — `(cp, alias, type)` triples, type ∈ `correction|control|alternate|figment|abbreviation`.
46
+ - `NameSequences.txt` / `NamedSequences.txt` — multi-code-point sequences with a name.
47
+ - `JSN.txt` — JSON-style names (Unicode 16+) for identifiers.
48
+ - `SpecialCasing.txt` — context-sensitive case mappings (the plain mappings in
49
+ `UnicodeData.txt` are *simple*; this is the full rule set).
50
+ - `CaseFolding.txt` — case folding for comparison (`C`, `F`, `S`, `T` statuses).
51
+ - `BidiBrackets.txt` — paired bracket mapping (complements `Bidi_M` in `UnicodeData.txt`).
52
+ - `BidiMirroring.txt` — bidi mirroring glyph partner per code point.
53
+ - `CJKRadicals.txt` — CJK radical ↔ KangXi radical number ↔ ideograph mapping.
54
+ - `StandardizedVariants.txt` — variation-selector pairs with description and context.
55
+ - `USourceData.txt` — UTC source identifier-status tracking for unihan/identifier chars.
56
+ - `Index.txt` — name → code point index (used for search and disambiguation).
57
+
58
+ Property enumerations (apply to all code points):
59
+ - `PropertyAliases.txt` — property short ↔ long name.
60
+ - `PropertyValueAliases.txt` — property value short ↔ long name (e.g. `gc=Lu` ↔ `Uppercase_Letter`).
61
+
62
+ Range property files (`XXXX..YYYY; value` form):
63
+ - `Blocks.txt` — block name per range. **Use original block names verbatim as folder names**
64
+ (e.g. `ASCII`, `CJK_Ext_A`, `Greek_And_Coptic`, `Currency_Symbols`). Do not slugify.
65
+ - `Scripts.txt` — primary script per range.
66
+ - `ScriptExtensions.txt` — additional scripts per range (a codepoint can have many).
67
+ - `DerivedAge.txt` — Unicode version when introduced.
68
+ - `DerivedGeneralCategory.txt`, `DerivedCoreProperties.txt`, `DerivedName.txt`, etc.
69
+ (everything in `extracted/`).
70
+ - `auxiliary/GraphemeBreakProperty.txt`, `auxiliary/WordBreakProperty.txt`,
71
+ `auxiliary/SentenceBreakProperty.txt`, `LineBreak.txt`, `EastAsianWidth.txt`,
72
+ `auxiliary/VerticalOrientation.txt`, `auxiliary/IndicPositionalCategory.txt`,
73
+ `auxiliary/IndicSyllabicCategory.txt`, `auxiliary/IdentifierStatus.txt`,
74
+ `auxiliary/IdentifierType.txt`.
75
+
76
+ Human-curated relationship file (the one that makes this project valuable):
77
+ - `NamesList.txt` — the **annotated names list** Unicode uses to produce the Code Charts'
78
+ name pages. Each entry is `cp; Name` followed by indented annotations. Markers we must
79
+ model:
80
+ - `→ U+XXXX …` — cross-reference / "see also".
81
+ - `× U+XXXX …` — typical usage sequence (sample combination).
82
+ - `≡ U+XXXX …` — compatibility equivalent.
83
+ - `= …` — alias / informal name.
84
+ - `* …` — footnote / explanatory note.
85
+ - `% …` — instructional line (always dropped from output).
86
+ - `~ …` — X-ref heading line.
87
+ - `# …` — comment header.
88
+ Each annotation line has scope: it belongs to the most recent codepoint header above it.
89
+
90
+ ### Unihan (from `Unihan.zip`, separate download)
91
+
92
+ `Unihan.zip` contains `Unihan_IRGSources.txt`, `Unihan_NumericValues.txt`,
93
+ `Unihan_RadicalStrokeCounts.txt`, `Unihan_Readings.txt`, `Unihan_DictionaryIndices.txt`,
94
+ `Unihan_DictionaryLikeData.txt`, `Unhan_Variants.txt`, `Unihan_OtherMappings.txt`. Parse all
95
+ of them. Unihan field set is much larger than what a flat XML dump would inline — that is the
96
+ second reason we cannot rely on a flat dump.
97
+
98
+ ### Glyphs (per-block PDFs from unicode.org/charts/)
99
+
100
+ Default source: per-block PDFs at `https://www.unicode.org/charts/PDF/U<XXXX>.pdf` (the first
101
+ codepoint of each block, zero-padded to 4 digits where possible). One PDF per block — small,
102
+ incremental, easy to re-run. The monolithic `CodeCharts.pdf` (3,156 pages) was removed from
103
+ the repo — per-block PDFs are sufficient for the pipeline.
104
+
105
+ ## Architecture (target shape)
106
+
107
+ Five concerns, each isolated:
108
+
109
+ 1. **`Ucode::Models`** — `lutaml-model` classes. One per UCD aggregate:
110
+ `Plane`, `Block`, `Script`, `CodePoint`, `NameAlias`, `NamesListEntry` (carries the parsed
111
+ annotations: cross_refs, see_also, compatibility_equivs, sample_sequences, aliases,
112
+ footnotes), `NamedSequence`, `StandardizedVariant`, `CjkRadical`, `SpecialCasingRule`,
113
+ `CaseFoldingRule`, `BidiBracketPair`, `UnihanField`, `PropertyAlias`,
114
+ `PropertyValueAlias`. All JSON output is `model.to_hash` / `Model.from_hash` produced by
115
+ `lutaml-model` from `attribute` declarations + `mapping do … end` blocks. Never write
116
+ `def to_h` / `from_h`.
117
+
118
+ 2. **`Ucode::Parsers`** — one parser class per UCD text file. Common base
119
+ `Ucode::Parsers::Base` handles the shared format: skip blanks and `#`-comment lines,
120
+ split fields on `;`, strip whitespace, parse `XXXX..YYYY` range into an inclusive
121
+ `Range<Integer>`, yield one model instance per codepoint (expanding ranges). Each subclass
122
+ knows its file's specific column layout. **All parsers stream** — read line by line,
123
+ never load whole files into memory.
124
+
125
+ 3. **`Ucode::Glyphs`** — produces an SVG glyph per codepoint via the
126
+ **4-tier sourcing strategy** (see `docs/architecture.md` for the full
127
+ reference; lower tiers are fallbacks):
128
+ - **Tier 1** — `RealFonts::*`: real-font cmap via `fontist` (discovery)
129
+ + `fontisan` (parsing). Highest fidelity.
130
+ - **Pillar 1** — `EmbeddedFonts::Catalog`: PDF-embedded CIDFont +
131
+ `/ToUnicode` CMap. Walks the Type0 → CIDFont → FontDescriptor →
132
+ FontFile2/3 object graph.
133
+ - **Pillar 2** — `EmbeddedFonts::ContentStreamCorrelator`: PDF
134
+ content-stream positional correlation for CIDFonts without
135
+ `/ToUnicode` (renders page to SVG, partitions labels from specimens,
136
+ matches positionally).
137
+ - **Pillar 3** — `LastResort::*`: Last Resort UFO `.glif` outlines for
138
+ placeholders (unassigned, PUA, noncharacter) and any codepoint no
139
+ higher tier produced a glyph for.
140
+ The v0.1 cell extractor (`GridDetector` + `CellExtractor`) is the
141
+ retired path: it rendered each page to SVG via `mutool draw -F svg` /
142
+ `dvisvgm` / `pdf2svg` and lifted the path inside a chart grid cell, but
143
+ compositing made the output unusable. The 4-tier pipeline bypasses the
144
+ renderer entirely. This is **vector extraction, not OCR** — never run
145
+ OCR.
146
+
147
+ 4. **`Ucode::Repo`** — writes the output tree under `output/`. **One folder per codepoint,
148
+ no exceptions** (CJK included — ~45 k ideograph folders):
149
+ ```
150
+ output/planes/<0..16>.json
151
+ output/blocks/<ORIGINAL_NAME>.json # block metadata + member list
152
+ output/blocks/<ORIGINAL_NAME>/<U+XXXX>/index.json
153
+ output/blocks/<ORIGINAL_NAME>/<U+XXXX>/glyph.svg
154
+ output/scripts/<ScriptCode>.json
155
+ output/index/names.json # cp → name, for client-side search
156
+ output/index/labels.json # cp → {name, gc, sc} for grids
157
+ ```
158
+ Plane (17) and block (~346) pages are static; per-character pages are loaded client-side
159
+ by fetch — generating ~160 k static HTML pages is not viable. Planes 3–13 (mostly
160
+ unassigned) and Plane 14 (Tags) are included; only the few assigned codepoints there
161
+ become folders.
162
+
163
+ 5. **`Ucode::Site`** — Vitepress app under `site/`. Generates the Vitepress config
164
+ (`config.ts`, sidebar, search index) from `output/`. Character detail is a single dynamic
165
+ route that fetches `index.json` + `glyph.svg` by codepoint. Plane and block pages are
166
+ pre-rendered.
167
+
168
+ CLI entry point: `bin/ucode` → `Ucode::CLI` (Thor or similar). Subcommands: `ucode fetch`
169
+ (`ucd`, `unihan`, `charts`), `ucode parse`, `ucode glyphs`, `ucode site`, `ucode build`
170
+ (= parse + glyphs + site).
171
+
172
+ ## Build / test commands
173
+
174
+ To be filled in once the gem skeleton exists. Expected shape:
175
+
176
+ - `bundle install`
177
+ - `bundle exec rake spec` (or `bundle exec rspec`)
178
+ - `bundle exec rspec spec/parsers/names_list_spec.rb` for a single spec
179
+ - `bundle exec rubocop`
180
+ - `bin/ucode fetch ucd` → downloads `UCD.zip`, unzips into `data/ucd/`
181
+ - `bin/ucode fetch unihan` → downloads `Unihan.zip`, unzips into `data/unihan/`
182
+ - `bin/ucode fetch charts` → downloads per-block PDFs into `data/pdfs/`
183
+ - `bin/ucode parse` → writes `output/`
184
+ - `bin/ucode glyphs` → writes per-codepoint SVGs
185
+ - `(cd site && npm run dev)` → Vitepress dev server
186
+ - `(cd site && npm run build)` → static site
187
+
188
+ ## Things that are easy to get wrong here
189
+
190
+ - **`NamesList.txt` line scoping.** Annotations are indented under a codepoint header. A
191
+ new codepoint header (column 0) ends the previous codepoint's annotation block. Build the
192
+ parser as a small state machine, not a regex.
193
+ - **`UnicodeData.txt` range markers.** Lines with `na` of `<First>` / `<Last>` are range
194
+ endpoints — expand to one record per codepoint using the range bounds. Do not store as
195
+ ranges. Final codepoint count should be ~160 k for Unicode 17.
196
+ - **CID ↔ Unicode mapping in PDFs.** Code Charts fonts are subsetted with custom encodings.
197
+ The reliable mapping is "the codepoint label printed next to the row/column" — i.e. use
198
+ the chart's grid geometry, not the font's ToUnicode CMap, to attribute a glyph to a code
199
+ point.
200
+ - **CJK scale.** ~45 k ideographs each get a directory + `index.json` + `glyph.svg`. That's
201
+ the explicit requirement — do not collapse to sprites. Build/idempotency must handle this
202
+ scale without re-writing unchanged files.
203
+ - **Original block names.** Use the exact `blk` attribute from `Blocks.txt`
204
+ (e.g. `CJK_Ext_A`, `Greek_And_Coptic`) as the folder name and as the block identifier in
205
+ JSON. Do not slugify.
206
+ - **Per-block PDFs only.** Per-block PDFs are fetched on demand from
207
+ unicode.org/charts/PDF/ — no monolithic chart is committed. Each block
208
+ PDF is small and incremental, supporting clean re-runs.
209
+ - **Idempotency.** All build steps must be resumable: re-running `ucode glyphs` should skip
210
+ codepoints whose `glyph.svg` is already on disk and is newer than the source PDF; same for
211
+ `index.json` vs `data/ucd/`.
data/Gemfile ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gemspec
6
+
7
+ group :development do
8
+ gem "rake"
9
+ gem "rspec"
10
+ gem "rubocop"
11
+ gem "rubocop-performance"
12
+ gem "rubocop-rake"
13
+ gem "rubocop-rspec"
14
+ gem "simplecov"
15
+ gem "yard"
16
+ end
17
+
18
+ # Default to the published fontisan from rubygems. To develop against a
19
+ # local sibling checkout, set FONTISAN_PATH before running bundle.
20
+ # FONTISAN_PATH=../fontisan bundle install
21
+ gem "fontisan", path: ENV["FONTISAN_PATH"] if ENV["FONTISAN_PATH"]
22
+ gem "fontisan", "~> 0.2" unless ENV["FONTISAN_PATH"]
data/Gemfile.lock ADDED
@@ -0,0 +1,406 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ ucode (0.1.0)
5
+ base64
6
+ fontisan (~> 0.2)
7
+ fontist (~> 3.0)
8
+ logger
9
+ lutaml-model (~> 0.8)
10
+ nokogiri (~> 1.16)
11
+ rubyzip (~> 2.3)
12
+ sqlite3 (~> 2.0)
13
+ thor (~> 1.3)
14
+
15
+ GEM
16
+ remote: https://rubygems.org/
17
+ specs:
18
+ activesupport (8.1.3)
19
+ base64
20
+ bigdecimal
21
+ concurrent-ruby (~> 1.0, >= 1.3.1)
22
+ connection_pool (>= 2.2.5)
23
+ drb
24
+ i18n (>= 1.6, < 2)
25
+ json
26
+ logger (>= 1.4.2)
27
+ minitest (>= 5.1)
28
+ securerandom (>= 0.3)
29
+ tzinfo (~> 2.0, >= 2.0.5)
30
+ uri (>= 0.13.1)
31
+ addressable (2.9.0)
32
+ public_suffix (>= 2.0.2, < 8.0)
33
+ ast (2.4.3)
34
+ base64 (0.3.0)
35
+ benchmark (0.5.0)
36
+ bigdecimal (4.1.2)
37
+ bindata (2.5.1)
38
+ brotli (0.8.0)
39
+ cabriolet (0.2.4)
40
+ bindata (~> 2.5)
41
+ fractor (~> 0.1)
42
+ thor (~> 1.3)
43
+ canon (0.2.12)
44
+ diff-lcs
45
+ json
46
+ moxml (~> 0.1.22)
47
+ nokogiri
48
+ paint
49
+ rainbow
50
+ table_tennis
51
+ thor
52
+ unicode-name
53
+ concurrent-ruby (1.3.7)
54
+ connection_pool (3.0.2)
55
+ csv (3.3.5)
56
+ diff-lcs (1.6.2)
57
+ docile (1.4.1)
58
+ down (5.6.0)
59
+ addressable (~> 2.8)
60
+ base64 (~> 0.3)
61
+ drb (2.2.3)
62
+ excavate (1.1.0)
63
+ cabriolet (~> 0.2.4)
64
+ omnizip (~> 0.3.9)
65
+ thor (~> 1.0)
66
+ faraday (2.14.3)
67
+ faraday-net_http (>= 2.0, < 3.5)
68
+ json
69
+ logger
70
+ faraday-net_http (3.4.4)
71
+ net-http (~> 0.5)
72
+ ffi (1.17.4-aarch64-linux-gnu)
73
+ ffi (1.17.4-aarch64-linux-musl)
74
+ ffi (1.17.4-arm-linux-gnu)
75
+ ffi (1.17.4-arm-linux-musl)
76
+ ffi (1.17.4-arm64-darwin)
77
+ ffi (1.17.4-x86_64-darwin)
78
+ ffi (1.17.4-x86_64-linux-gnu)
79
+ ffi (1.17.4-x86_64-linux-musl)
80
+ fontisan (0.2.22)
81
+ base64
82
+ bindata (~> 2.5)
83
+ brotli (~> 0.5)
84
+ logger
85
+ lutaml-model (~> 0.8)
86
+ nokogiri (~> 1.16)
87
+ thor (~> 1.3)
88
+ fontist (3.0.8)
89
+ down (~> 5.0)
90
+ excavate (~> 1.0, >= 1.0.3)
91
+ fontisan (~> 0.2, >= 0.2.17)
92
+ fuzzy_match (~> 2.1)
93
+ git (> 1.0)
94
+ json (~> 2.0)
95
+ lutaml-model (~> 0.8.0)
96
+ marcel (~> 1.0)
97
+ nokogiri (~> 1.0)
98
+ octokit (~> 4.0)
99
+ paint (~> 2.3)
100
+ parallel (~> 1.24)
101
+ plist (~> 3.0)
102
+ socksify (~> 1.7)
103
+ thor (~> 1.4)
104
+ unibuf (~> 0.1)
105
+ fractor (0.1.10)
106
+ benchmark
107
+ logger
108
+ fuzzy_match (2.1.0)
109
+ git (4.3.2)
110
+ activesupport (>= 5.0)
111
+ addressable (~> 2.8)
112
+ process_executer (~> 4.0)
113
+ rchardet (~> 1.9)
114
+ i18n (1.15.2)
115
+ concurrent-ruby (~> 1.0)
116
+ json (2.20.0)
117
+ language_server-protocol (3.17.0.5)
118
+ lint_roller (1.1.0)
119
+ liquid (5.12.0)
120
+ bigdecimal
121
+ strscan (>= 3.1.1)
122
+ logger (1.7.0)
123
+ lutaml-model (0.8.16)
124
+ base64
125
+ bigdecimal
126
+ canon
127
+ concurrent-ruby
128
+ liquid (>= 4.0, < 6.0)
129
+ moxml (~> 0.1.23)
130
+ ostruct
131
+ rubyzip (~> 2.3)
132
+ thor
133
+ marcel (1.2.1)
134
+ memo_wise (1.13.0)
135
+ minitest (6.0.6)
136
+ drb (~> 2.0)
137
+ prism (~> 1.5)
138
+ moxml (0.1.25)
139
+ net-http (0.9.1)
140
+ uri (>= 0.11.1)
141
+ nokogiri (1.19.4-aarch64-linux-gnu)
142
+ racc (~> 1.4)
143
+ nokogiri (1.19.4-aarch64-linux-musl)
144
+ racc (~> 1.4)
145
+ nokogiri (1.19.4-arm-linux-gnu)
146
+ racc (~> 1.4)
147
+ nokogiri (1.19.4-arm-linux-musl)
148
+ racc (~> 1.4)
149
+ nokogiri (1.19.4-arm64-darwin)
150
+ racc (~> 1.4)
151
+ nokogiri (1.19.4-x86_64-darwin)
152
+ racc (~> 1.4)
153
+ nokogiri (1.19.4-x86_64-linux-gnu)
154
+ racc (~> 1.4)
155
+ nokogiri (1.19.4-x86_64-linux-musl)
156
+ racc (~> 1.4)
157
+ octokit (4.25.1)
158
+ faraday (>= 1, < 3)
159
+ sawyer (~> 0.9)
160
+ omnizip (0.3.9)
161
+ base64 (~> 0.2)
162
+ bindata (~> 2.4)
163
+ cabriolet (~> 0.2, >= 0.2.4)
164
+ lutaml-model (~> 0.7)
165
+ marcel (~> 1.0)
166
+ rexml (~> 3.3)
167
+ ostruct (0.6.3)
168
+ paint (2.3.0)
169
+ parallel (1.28.0)
170
+ parser (3.3.11.1)
171
+ ast (~> 2.4.1)
172
+ racc
173
+ parslet (2.0.0)
174
+ plist (3.7.2)
175
+ prism (1.9.0)
176
+ process_executer (4.0.4)
177
+ track_open_instances (~> 0.1)
178
+ public_suffix (7.0.5)
179
+ racc (1.8.1)
180
+ rainbow (3.1.1)
181
+ rake (13.4.2)
182
+ rchardet (1.10.2)
183
+ regexp_parser (2.12.0)
184
+ rexml (3.4.4)
185
+ rspec (3.13.2)
186
+ rspec-core (~> 3.13.0)
187
+ rspec-expectations (~> 3.13.0)
188
+ rspec-mocks (~> 3.13.0)
189
+ rspec-core (3.13.6)
190
+ rspec-support (~> 3.13.0)
191
+ rspec-expectations (3.13.5)
192
+ diff-lcs (>= 1.2.0, < 2.0)
193
+ rspec-support (~> 3.13.0)
194
+ rspec-mocks (3.13.8)
195
+ diff-lcs (>= 1.2.0, < 2.0)
196
+ rspec-support (~> 3.13.0)
197
+ rspec-support (3.13.7)
198
+ rubocop (1.88.0)
199
+ json (~> 2.3)
200
+ language_server-protocol (~> 3.17.0.2)
201
+ lint_roller (~> 1.1.0)
202
+ parallel (>= 1.10)
203
+ parser (>= 3.3.0.2)
204
+ rainbow (>= 2.2.2, < 4.0)
205
+ regexp_parser (>= 2.9.3, < 3.0)
206
+ rubocop-ast (>= 1.49.0, < 2.0)
207
+ ruby-progressbar (~> 1.7)
208
+ unicode-display_width (>= 2.4.0, < 4.0)
209
+ rubocop-ast (1.49.1)
210
+ parser (>= 3.3.7.2)
211
+ prism (~> 1.7)
212
+ rubocop-performance (1.26.1)
213
+ lint_roller (~> 1.1)
214
+ rubocop (>= 1.75.0, < 2.0)
215
+ rubocop-ast (>= 1.47.1, < 2.0)
216
+ rubocop-rake (0.7.1)
217
+ lint_roller (~> 1.1)
218
+ rubocop (>= 1.72.1)
219
+ rubocop-rspec (3.10.2)
220
+ lint_roller (~> 1.1)
221
+ regexp_parser (>= 2.0)
222
+ rubocop (~> 1.86, >= 1.86.2)
223
+ ruby-progressbar (1.13.0)
224
+ rubyzip (2.4.1)
225
+ sawyer (0.9.3)
226
+ addressable (>= 2.3.5)
227
+ faraday (>= 0.17.3, < 3)
228
+ securerandom (0.4.1)
229
+ simplecov (0.22.0)
230
+ docile (~> 1.1)
231
+ simplecov-html (~> 0.11)
232
+ simplecov_json_formatter (~> 0.1)
233
+ simplecov-html (0.13.2)
234
+ simplecov_json_formatter (0.1.4)
235
+ socksify (1.8.1)
236
+ sqlite3 (2.9.5-aarch64-linux-gnu)
237
+ sqlite3 (2.9.5-aarch64-linux-musl)
238
+ sqlite3 (2.9.5-arm-linux-gnu)
239
+ sqlite3 (2.9.5-arm-linux-musl)
240
+ sqlite3 (2.9.5-arm64-darwin)
241
+ sqlite3 (2.9.5-x86_64-darwin)
242
+ sqlite3 (2.9.5-x86_64-linux-gnu)
243
+ sqlite3 (2.9.5-x86_64-linux-musl)
244
+ strscan (3.1.8)
245
+ table_tennis (0.0.7)
246
+ csv (~> 3.3)
247
+ ffi (~> 1.17)
248
+ memo_wise (~> 1.11)
249
+ paint (~> 2.3)
250
+ unicode-display_width (~> 3.1)
251
+ thor (1.5.0)
252
+ track_open_instances (0.1.15)
253
+ tzinfo (2.0.6)
254
+ concurrent-ruby (~> 1.0)
255
+ unibuf (0.1.2)
256
+ bindata (~> 2.5)
257
+ lutaml-model (~> 0.7)
258
+ parslet (~> 2.0)
259
+ thor (~> 1.4)
260
+ unicode-display_width (3.2.0)
261
+ unicode-emoji (~> 4.1)
262
+ unicode-emoji (4.2.0)
263
+ unicode-name (1.14.0)
264
+ unicode-types (~> 1.11)
265
+ unicode-types (1.11.0)
266
+ uri (1.1.1)
267
+ yard (0.9.44)
268
+
269
+ PLATFORMS
270
+ aarch64-linux
271
+ aarch64-linux-gnu
272
+ aarch64-linux-musl
273
+ arm-linux-gnu
274
+ arm-linux-musl
275
+ arm64-darwin
276
+ x86_64-darwin
277
+ x86_64-linux
278
+ x86_64-linux-gnu
279
+ x86_64-linux-musl
280
+
281
+ DEPENDENCIES
282
+ fontisan (~> 0.2)
283
+ rake
284
+ rspec
285
+ rubocop
286
+ rubocop-performance
287
+ rubocop-rake
288
+ rubocop-rspec
289
+ simplecov
290
+ ucode!
291
+ yard
292
+
293
+ CHECKSUMS
294
+ activesupport (8.1.3) sha256=21a5e0dfbd4c3ddd9e1317ec6a4d782fa226e7867dc70b0743acda81a1dca20e
295
+ addressable (2.9.0) sha256=7fdf6ac3660f7f4e867a0838be3f6cf722ace541dd97767fa42bc6cfa980c7af
296
+ ast (2.4.3) sha256=954615157c1d6a382bc27d690d973195e79db7f55e9765ac7c481c60bdb4d383
297
+ base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b
298
+ benchmark (0.5.0) sha256=465df122341aedcb81a2a24b4d3bd19b6c67c1530713fd533f3ff034e419236c
299
+ bigdecimal (4.1.2) sha256=53d217666027eab4280346fba98e7d5b66baaae1b9c3c1c0ffe89d48188a3fbd
300
+ bindata (2.5.1) sha256=53186a1ec2da943d4cb413583d680644eb810aacbf8902497aac8f191fad9e58
301
+ brotli (0.8.0) sha256=0c5a42046b3b603fb109656881147fd76064c034b7d19c1b4fcc32a093a4d55d
302
+ bundler (4.0.14) sha256=d09a0a965cf772266a7e49e83610be7c2f4e49e61134c42a56804bb383cc24b8
303
+ cabriolet (0.2.4) sha256=fde76321a5b7ee5506581c01aeac44e4476332bc64fe7ae1a07a72227a318e9b
304
+ canon (0.2.12) sha256=9b87514fbf6c0f9f28d1e2746ea5837b08e24e50c30751dba27a89f86e8709af
305
+ concurrent-ruby (1.3.7) sha256=4412caec3a5ea2e5fdc52076724c071a81f2c0593d83b2ac8cbb8ca63b3151b0
306
+ connection_pool (3.0.2) sha256=33fff5ba71a12d2aa26cb72b1db8bba2a1a01823559fb01d29eb74c286e62e0a
307
+ csv (3.3.5) sha256=6e5134ac3383ef728b7f02725d9872934f523cb40b961479f69cf3afa6c8e73f
308
+ diff-lcs (1.6.2) sha256=9ae0d2cba7d4df3075fe8cd8602a8604993efc0dfa934cff568969efb1909962
309
+ docile (1.4.1) sha256=96159be799bfa73cdb721b840e9802126e4e03dfc26863db73647204c727f21e
310
+ down (5.6.0) sha256=48ec6ddb078cbf3b425d02596bb388303316f976143c6e94a7b3169d6712b593
311
+ drb (2.2.3) sha256=0b00d6fdb50995fe4a45dea13663493c841112e4068656854646f418fda13373
312
+ excavate (1.1.0) sha256=9e394785e23dc1bdba38fd1a82700da1f7c700b50067f60dd2226c273d95808d
313
+ faraday (2.14.3) sha256=1882247e6766615c8220b4392bf1d27f6ebb63d8e28267587cef1fb0bf37f278
314
+ faraday-net_http (3.4.4) sha256=0e78af151747ed1b00f33e25973b4bc220d7f16c00c39676817c8b12331eb588
315
+ ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
316
+ ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
317
+ ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564
318
+ ffi (1.17.4-arm-linux-musl) sha256=9d4838ded0465bef6e2426935f6bcc93134b6616785a84ffd2a3d82bc3cf6f95
319
+ ffi (1.17.4-arm64-darwin) sha256=19071aaf1419251b0a46852abf960e77330a3b334d13a4ab51d58b31a937001b
320
+ ffi (1.17.4-x86_64-darwin) sha256=aa70390523cf3235096cf64962b709b4cfbd5c082a2cb2ae714eb0fe2ccda496
321
+ ffi (1.17.4-x86_64-linux-gnu) sha256=9d3db14c2eae074b382fa9c083fe95aec6e0a1451da249eab096c34002bc752d
322
+ ffi (1.17.4-x86_64-linux-musl) sha256=3fdf9888483de005f8ef8d1cf2d3b20d86626af206cbf780f6a6a12439a9c49e
323
+ fontisan (0.2.22) sha256=de2805ba52348f7ee5d19ed2b23a84c6d6ece455d753182482d6198e35026d99
324
+ fontist (3.0.8) sha256=fc40263c72f3776c4d0b3e56a930c70639c261758c785f86b0577a2a7b09d726
325
+ fractor (0.1.10) sha256=a1b5d6de7265bbcb02d3e0606962e581c3456a04d51130976c80ea8c45b6820f
326
+ fuzzy_match (2.1.0) sha256=e97e25d0eaee48a5f77ed970d007c7b6ff3c6a6858303fead2d1986859204dfc
327
+ git (4.3.2) sha256=a3b0706573bb8cdd9edc630c33e2611ca5cbdece086f7c142bef73bc38522907
328
+ i18n (1.15.2) sha256=00f9eb62412fe593b2a65a97daa75300d37abb8f7202ec748e94b6d46a9dd1b5
329
+ json (2.20.0) sha256=9362bc6e55a952b056abf9167cf053358181c904cb70cd6eee0808ea830fc32b
330
+ language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
331
+ lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
332
+ liquid (5.12.0) sha256=5a3c2c2430cd925d21c53e4ed9abea52cd0a9da53b541422f81dee79aca2a673
333
+ logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
334
+ lutaml-model (0.8.16) sha256=9c3a112d7356e57b9c30b84b8cdf751aa23b1a068275e497ee6b9cd8fbfe11ab
335
+ marcel (1.2.1) sha256=1678e9360e32f9eafa917c80029e2f6d10b2715c66a4b87b6d0da9b9cd1f859f
336
+ memo_wise (1.13.0) sha256=30220c38c4cef410849bc73553c58664dc2c91c6379e4a1df22aea02358b716b
337
+ minitest (6.0.6) sha256=153ea36d1d987a62942382b61075745042a2b3123b1cd48f4c3675af9cc7d6f1
338
+ moxml (0.1.25) sha256=9cec15d56fc0e82d21f5a612cbd29d4e9812fbf2823f68de0b474548d6567afc
339
+ net-http (0.9.1) sha256=25ba0b67c63e89df626ed8fac771d0ad24ad151a858af2cc8e6a716ca4336996
340
+ nokogiri (1.19.4-aarch64-linux-gnu) sha256=1269fb644a6de405057a53dd5c762b1209b43ca7424f839454d3dbc677c31a8f
341
+ nokogiri (1.19.4-aarch64-linux-musl) sha256=35c65b9ce72b3bb03207bdbe7067915019dc18c1b9b59139684bd6690fdd01af
342
+ nokogiri (1.19.4-arm-linux-gnu) sha256=a301313e38bb065d68239e79734bcd6f56fb6efaacebde29e9abf2a4735340ca
343
+ nokogiri (1.19.4-arm-linux-musl) sha256=588923c101bcfa78869734d247d25b598674323e7f22474fc468f6e5647311eb
344
+ nokogiri (1.19.4-arm64-darwin) sha256=a46db9853286e6597b36ebc6953817d15acf3a299583eb3f89fdc6f91dd63527
345
+ nokogiri (1.19.4-x86_64-darwin) sha256=7fd17057d3e1f00e9954a74b3cd76595d3d4a5ef233b7ed9599047c204f70551
346
+ nokogiri (1.19.4-x86_64-linux-gnu) sha256=379fae440b28915e3f19d752ce2dcf8465ed2b2fbefd2a7ca0dd497bc981a06a
347
+ nokogiri (1.19.4-x86_64-linux-musl) sha256=17dfb7c1fa194ae02fbf7c51a7afc8d278045ab3fdacfd86f91d02d7b274470b
348
+ octokit (4.25.1) sha256=c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96
349
+ omnizip (0.3.9) sha256=bf46605a4fc69b43343980f2b676212079a64c212b94eff6323989fdf763c7e6
350
+ ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
351
+ paint (2.3.0) sha256=327d623e4038619d5bd99ae5db07973859cd78400c7f0329eea283cef8e83be5
352
+ parallel (1.28.0) sha256=33e6de1484baf2524792d178b0913fc8eb94c628d6cfe45599ad4458c638c970
353
+ parser (3.3.11.1) sha256=d17ace7aabe3e72c3cc94043714be27cc6f852f104d81aa284c2281aecc65d54
354
+ parslet (2.0.0) sha256=d45130695d39b43d7e6a91f4d2ec66b388a8d822bae38de9b4de9a5fbde1f606
355
+ plist (3.7.2) sha256=d37a4527cc1116064393df4b40e1dbbc94c65fa9ca2eec52edf9a13616718a42
356
+ prism (1.9.0) sha256=7b530c6a9f92c24300014919c9dcbc055bf4cdf51ec30aed099b06cd6674ef85
357
+ process_executer (4.0.4) sha256=6c179bd31b876e220e7a1ed30c8f8ee7333b9b5b4b8c301474b947b707c3ba6f
358
+ public_suffix (7.0.5) sha256=1a8bb08f1bbea19228d3bed6e5ed908d1cb4f7c2726d18bd9cadf60bc676f623
359
+ racc (1.8.1) sha256=4a7f6929691dbec8b5209a0b373bc2614882b55fc5d2e447a21aaa691303d62f
360
+ rainbow (3.1.1) sha256=039491aa3a89f42efa1d6dec2fc4e62ede96eb6acd95e52f1ad581182b79bc6a
361
+ rake (13.4.2) sha256=cb825b2bd5f1f8e91ca37bddb4b9aaf345551b4731da62949be002fa89283701
362
+ rchardet (1.10.2) sha256=e041cb195f464dc10e49ab130f78c8b5956cd9a4f4f6df84e0c183b87c135f33
363
+ regexp_parser (2.12.0) sha256=35a916a1d63190ab5c9009457136ae5f3c0c7512d60291d0d1378ba18ce08ebb
364
+ rexml (3.4.4) sha256=19e0a2c3425dfbf2d4fc1189747bdb2f849b6c5e74180401b15734bc97b5d142
365
+ rspec (3.13.2) sha256=206284a08ad798e61f86d7ca3e376718d52c0bc944626b2349266f239f820587
366
+ rspec-core (3.13.6) sha256=a8823c6411667b60a8bca135364351dda34cd55e44ff94c4be4633b37d828b2d
367
+ rspec-expectations (3.13.5) sha256=33a4d3a1d95060aea4c94e9f237030a8f9eae5615e9bd85718fe3a09e4b58836
368
+ rspec-mocks (3.13.8) sha256=086ad3d3d17533f4237643de0b5c42f04b66348c28bf6b9c2d3f4a3b01af1d47
369
+ rspec-support (3.13.7) sha256=0640e5570872aafefd79867901deeeeb40b0c9875a36b983d85f54fb7381c47c
370
+ rubocop (1.88.0) sha256=e420ddf1662d0ef34bc8a2910ac4b396a7ddda0b51a708264405241734b08e0b
371
+ rubocop-ast (1.49.1) sha256=4412f3ee70f6fe4546cc489548e0f6fcf76cafcfa80fa03af67098ffed755035
372
+ rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
373
+ rubocop-rake (0.7.1) sha256=3797f2b6810c3e9df7376c26d5f44f3475eda59eb1adc38e6f62ecf027cbae4d
374
+ rubocop-rspec (3.10.2) sha256=0b3e2ecc592cd10ecbf0095bb58d1e357905276e069643523cc19eb7495f65e2
375
+ ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
376
+ rubyzip (2.4.1) sha256=8577c88edc1fde8935eb91064c5cb1aef9ad5494b940cf19c775ee833e075615
377
+ sawyer (0.9.3) sha256=0d0f19298408047037638639fe62f4794483fb04320269169bd41af2bdcf5e41
378
+ securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
379
+ simplecov (0.22.0) sha256=fe2622c7834ff23b98066bb0a854284b2729a569ac659f82621fc22ef36213a5
380
+ simplecov-html (0.13.2) sha256=bd0b8e54e7c2d7685927e8d6286466359b6f16b18cb0df47b508e8d73c777246
381
+ simplecov_json_formatter (0.1.4) sha256=529418fbe8de1713ac2b2d612aa3daa56d316975d307244399fa4838c601b428
382
+ socksify (1.8.1) sha256=cf2a01720cc32490cc657b3233730620a03b92e98281726872ebebedfea9a856
383
+ sqlite3 (2.9.5-aarch64-linux-gnu) sha256=78075b6337d3d182c6d2b4691049ed45cd220826160c9ea18946bf6a1de200dc
384
+ sqlite3 (2.9.5-aarch64-linux-musl) sha256=18c801185deb4adc01ddb281e8f672a39e3d1729979ca91e39439cd3eac0402d
385
+ sqlite3 (2.9.5-arm-linux-gnu) sha256=1bdfca0c7d63998c60b0f4a8e3c8df2d33800ccc4abd2d612eddbbbc92a4c48b
386
+ sqlite3 (2.9.5-arm-linux-musl) sha256=bae1109d12b2e9f588455967729b008e1ff4feb7761749df695019c9079913c6
387
+ sqlite3 (2.9.5-arm64-darwin) sha256=d0cf444a70fc9395d513cfbcc1e6719e224aa645314e3824cb0474c721425aa2
388
+ sqlite3 (2.9.5-x86_64-darwin) sha256=8e9caae38bd7ebb29cbeee3e7ab1d12dc2327d9a1b92c7fcf0dda05589627a81
389
+ sqlite3 (2.9.5-x86_64-linux-gnu) sha256=233dbcb6714148dd23bc5aeb33e8efd6eac974969564ddd5794c23d5f52b231e
390
+ sqlite3 (2.9.5-x86_64-linux-musl) sha256=e7d3a7474e8af0f96150c21abc203fbab5437206bfcdf11deab7741c0ca516f2
391
+ strscan (3.1.8) sha256=aae2db611a225559f21ffbb71765c9a4e60fd262534a9ea84f4f11c7f32f679e
392
+ table_tennis (0.0.7) sha256=b45b50dc7714e3bea5b31d2ad2b7d6bdc2995fc7a686976017c17424e1094a28
393
+ thor (1.5.0) sha256=e3a9e55fe857e44859ce104a84675ab6e8cd59c650a49106a05f55f136425e73
394
+ track_open_instances (0.1.15) sha256=7f0e48821e6b4c881daaa40fb1583e308937c22a9c84883c150b399c3b5c3029
395
+ tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
396
+ ucode (0.1.0)
397
+ unibuf (0.1.2) sha256=2453cb9ff97b4a80ebb6ed4fec88669da847decf23f4f2b2d2490dcb270fc061
398
+ unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
399
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
400
+ unicode-name (1.14.0) sha256=b350dcdeb503748c8ad05c472e8078570fbf3231a73be53431c15db10bbedbdd
401
+ unicode-types (1.11.0) sha256=81d1201273260fa89b85471e7eebb93a51bb4e5f078a525508dcae7835d176f9
402
+ uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
403
+ yard (0.9.44) sha256=eb087e9b631ccd887b049f303d489963945452d5e2a7eb49a5a74a7cf6887f28
404
+
405
+ BUNDLED WITH
406
+ 4.0.14